自己动手写CPU - 4

自己动手写CPU - 1-优快云博客icon-default.png?t=O83Ahttps://blog.youkuaiyun.com/weixin_46766770/article/details/144933071自己动手写CPU - 2-优快云博客icon-default.png?t=O83Ahttps://blog.youkuaiyun.com/weixin_46766770/article/details/144935050自己动手写CPU - 3-优快云博客icon-default.png?t=O83Ahttps://blog.youkuaiyun.com/weixin_46766770/article/details/144935080

书接上文.

上一节中有一个问题未解决: 仔细看了下, 应该还无法完成从1加到10的任务. 没有条件跳转, 需要利用CMP的结果来控制跳转, 例如: 比较循环次数到了10了没? 小于10则继续循环.

这一节补上它, 只加了四五行代码吧. 直接上代码.

增加了两个指令, 相等则跳, 不相等则跳, 不满足条件时输出R7+1

新加了eq寄存器, 如果op是5则更新它, 用in1==in2是否成立

6/7两个新加的指令, 按代码的逻辑看, 也不一定只能作用于R7, 它也可以作用于R0-R6, 但它在不成立时返回的是in1+1, 操作R0/R6似乎没有明确的含义(没有使用场合), 写程序时只用来操作R7.

全部代码如下(仿真时发现没有rst无法仿真, 全部信号是xxxxx, 也加上了rst)

module cpu(
    input clk,rst,
    input [15:0]op,     //[15:11]指令 [10:8]目标Reg索引 [7:0]立即数或源Reg索引
    output reg eq,
    output reg[7:0]R[8] // R0-R7组织成寄存器组,  方便用寄存器索引 选择
);

reg [7:0] in1,in2, out1;
always @ (*) begin
    in1 = R[op[10:8]];
    in2 = !op[11]? R[op[2:0]] : op[7:0];
end

always @ (*) begin 
    case(op[15:12])
        0: out1 = in2;          // ldr
        1: out1 = in1 + in2;    // add
        2: out1 = in1 - in2;    // sub
        3: out1 = in1 & in2;    // and
        4: out1 = in1 | in2;    // or
        5: out1 = in1;          // cmp
        6: out1 =  eq ? in2:in1+1;// jeq
        7: out1 = !eq ? in2:in1+1;// jne
        default: out1 = 0;
    endcase
end

wire [7:0]sel;
decode38 decode38_inst1(
    .abc(op[10:8]),
    .out(sel)
);

always @(posedge clk or negedge rst) begin
    if (!rst) begin
        eq=0; R[0:7]={0,0,0,0,0,0,0,0};
    end else begin
    if(op[15:12]==5) eq=(in1==in2);
    if(sel[0]) R[0]=out1;
    if(sel[1]) R[1]=out1;
    if(sel[2]) R[2]=out1;
    if(sel[3]) R[3]=out1;
    if(sel[4]) R[4]=out1;
    if(sel[5]) R[5]=out1;
    if(sel[6]) R[6]=out1;
    if(sel[7]) 
        R[7]=out1;
    else  
        R[7]=R[7]+1;
    end
end

endmodule

生成的RTL变化也不大, 下图将增加的单元也标注了出来.

RTL逻辑电路图

直接使用vivado跑测试, 测试代码

//`timescale 1ns / 1ps
module tb_cpu();

reg clk,rst;
reg [15:0]op;
wire eq;
wire [7:0]R[8];

cpu cpu_inst1(
    .clk(clk),
    .rst(rst),
    .op(op),
    .eq(eq),
    .R(R)
);

initial begin
    clk = 0; 
    rst=0;
    #5  rst=1;
        op = 'h0001+'h0800; //ldr R0, #1
    #20 op = 'h0111+'h0800; //ldr R1, #11
    #20 op = 'h0222+'h0800; //ldr R2, #22
    #20 op = 'h0666+'h0800; //ldr R6, #66
    #20 op = 'h0602;        //mov R6, R2
    #20 op = 'h1022+'h0800; //add R0, #22
    #20 op = 'h1106;        //add R1, R6
    #20 op = 'h2100;        //sub R1, R0
    #20 op = 'h5101;        //cmp R1, R1
    #20 op = 'h6701+'h0800; //beq #01
    #20 op = 'h5102;        //cmp R1, R2
end

always #10 clk = ~clk;

endmodule

测试代码比较简单, 先例化一个cpu, 连上信号线. 设好时钟, 每20个时间单位给一条指令, 然后观察R0-R7以及eq状态的变化. 仿真图如下:

可以看到, ldr add sub 执行的都是对的, cmp可以影响到eq状态, beq也成功修改了R7的值.

一开始提出的目标可以实现.

(数了下, 一共53行代码. 周六下午开始写, 写到凌晨.
周日本来不写了, 天黑时又有了想法, 还是把它写完吧, 正好0点收工)

已更新: 

自己动手写CPU - 5-优快云博客icon-default.png?t=O83Ahttps://blog.youkuaiyun.com/weixin_46766770/article/details/145078234

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

qq85058522

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值