欢迎光临
我们一直在努力

简单cpu搭建(增添3个新功能)

功能更新:立即数判断

采用指令的最后一位作为立即数判断的依据。0为寄存器型指令(R型指令),1为立即数型指令(I型指令)。

主要是在state_transition里进行立即数判断。修改ISA指令集,增添ALU的立即数版本。结果如下:

*********空操作**********
0000_00_00_00_00_0000
op/寄存器编号(对应第一个操作数)/第二个操作数/保存结果寄存器标号/常数/功能码
ALU******
0010_00_01_00_00_0001 ADD
0010_00_01_00_00_0010 SUB
0010_00_01_00_00_0011 自增1
0010_00_01_00_00_0100 清空
0010_00_01_00_00_0101 与
0010_00_01_00_00_0110 或
0010_00_01_00_00_0111 非
0010_00_01_00_00_1000 异或
/立即数型*/
1010_00_01_00_01_0001 ADD
1010_00_01_00_01_0010 SUB
1010_00_01_00_00_0011 自增1
1010_00_01_00_01_0100 清空
1010_00_01_00_01_0101 与
1010_00_01_00_00_0110 或
1010_00_01_00_01_0111 非
1010_00_01_00_01_1000 异或

在这个分支下增添imdata判断指令。其中imdata_en_in来源于指令集的最后一个数,也就是ir_out[15]。判断逻辑也很简单,如下:

if(alu_en_out==1'b1)begin
next_state=Write;
ir_en=1'b1;
end
else begin
next_state=current_state;
end
if(imdata_en_in==1)imdata_en=1'b1;//立即数判断
else imdata_en=1'b0;

        然后增添一行代码,用来给立即数做拓展,之前的拓展应该是在alu_mux里的,现在都挪到state_transition里了。

然后在顶层文件把相应的连接起来就好了。

功能更新:加一个Halt指令

逻辑是这样的,Halt指令读取的是opcode的位置,所以给他分配独立的op号,最后的指令如下:

0110_0000_0000_0000 Halt

既然有独立的op号了,所以我们只要判断这个op号就好。这里刚开始其实是用if语句在case语句的上层进行了一次选择。但是在后续添加别的功能的过程中,这种方法的拓展性不好,所以在Fetch状态下,采用了case语句用来筛选不同的opcode号。

case(opcode)
4'b1010:begin
next_state=Decode;
pc_en=1'b1;
pc_ctrl=3'b001;
end
4'b0010:begin
next_state=Decode;
pc_en=1'b1;
pc_ctrl=3'b001;
end
4'b0110:begin
next_state=Halt;
end

除此之外我选择了把ir_en_pulse信号直接置零来达到Halt也就是停机的目的。这样ir不会发出ir_en成功的模块,会卡在Fetch状态,不会进行pc更新和ir取指。具体代码如下:

assign ir_en_pulse={(~ir_en_reg)&ir_reg2}&halt_en;

功能更新:加两个跳转

跳转分很多种。先从绝对跳转和相对跳转里选一种。绝对跳转就是直接跳到指定的地址,而相对跳转就是在原有的地址上进行加减运算,这里选择的是相对跳转。

如何在pc上实现相对跳转呢,其实还是比较简单的,之前没有用上的pc_ctrl模块,可以利用上了。把pc_ctrl模块拓展一下,添加上可以加减offset(跳转的相对地址的数)的分支,然后在state_transition里对pc_ctrl的状态进行判断,就可以实现了,还需要更新ir,本次的ir直接写进去就好,原先的代码已经足够ir装载,返回状态Fetch,重新等待取指就好。除此之外,也需要对之前的计算模块中加入对pc_ctrl的限制。还需要对alu开始指令alu_en_start进行关断。也就是再原先的代码中,把pc_en_pulse后与一个(current_state==Fetch)。

alu_en_start<=pc_en_pulse&(current_state==Fetch);

下面是pc模块的改动:

module pc(
input wire clk,
input wire rst_n,
input wire pc_en_updata,
input wire [2:0] pc_ctrl,
input wire [7:0] offset,

output reg [7:0] pc_out
);

always@(posedge clk or negedge rst_n)begin
if(!rst_n)
pc_out<=8'b0;
else if(pc_en_updata==1'b1)
case(pc_ctrl)
3'b000:pc_out<=pc_out;
3'b001:pc_out<=pc_out+8'b01;
3'b010:pc_out<=8'b0;
3'b011:pc_out<=pc_out+offset;
3'b100:pc_out<=pc_out-offset;
default:pc_out<=8'b0;
endcase
end

endmodule

下面是state_transition模块的改动:

case(opcode)
4'b1010:begin
next_state=Decode;
pc_en=1'b1;
pc_ctrl=3'b001;
end
4'b0010:begin
next_state=Decode;
pc_en=1'b1;
pc_ctrl=3'b001;
end
4'b0110:begin
next_state=Halt;
end
4'b0111:begin
next_state=Jump;
end
default:begin
next_state=current_state;
end
endcase

Jump:begin
pc_offset_en=1'b1;
pc_offset=offset;
next_state=Fetch;
if(offset_sel==2'b10)begin
pc_ctrl=3'b100;
pc_en=1'b1;
ir_en=1'b1;
end
else if(offset_sel==2'b01)begin
pc_ctrl=3'b011;
pc_en=1'b1;
ir_en=1'b1;
end
else begin
pc_ctrl=3'b001;
pc_en=1'b1;
ir_en=1'b1;
end
end

赞(0)
未经允许不得转载:171主机测评 » 简单cpu搭建(增添3个新功能)
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址