计算机组成实验-第5章_R指令设计实现

/*主要问题,result=AopB,如果所有的always都是posedge clk触发,则会出现不同步的问题,因为A和B的值从寄存器取出进行运算得到结果之后,结果需要等到下一个时钟周期才能写入result:
     第一个时钟周期的操作是解析指令,将A和B的值从寄存器堆中取出,并且计算得到ALUoper的值。
     第二个时钟周期:计算result的值。
这样result会比A和B晚一个时钟周期。
因此,将ALUnit中的always改成*触发,这样:
     第一个时钟周期的操作是解析指令,将A和B的值从寄存器堆中取出,并且计算得到ALUoper的值,一旦三个值得到,计算结果会立刻写入result(得益于ALUnit中的always循环没有停顿)。
*/
//住模块代码
module Rtype(clk, rst, instru, Adat, Bdat, result);
     input clk;
     input rst;
     input [31:0] instru;
     output[31:0] result, Adat, Bdat;//Adat, Bdat为对应的两个操作数寄存器rs和rt,result对应rd
     wire [31:0] result;
    
     wire [31:0] Wdat, Adat, Bdat, ALUout;
     wire [2:0] ALUoper;
    
     RegFile s1(clk, instru[25:21], instru[20:16], instru[15:11],result, Adat, Bdat, 1);//生成子模块实例
     ALUctr s2(clk, 2'b10,instru[5:0],ALUoper);
     ALUnit s3(clk, Adat, Bdat, ALUoper, result, zero);

endmodule
module RegFile(clk, rs, rt, rd, result, A, B, RegWrite);//构建寄存器堆,并存取。
     input clk;
     input [4:0] rs, rt, rd;
     input [31:0] result;
     input RegWrite;
     output [31:0] A, B;
     reg [31:0] A, B;
    
     //下边是对应寄存器堆
     reg[31:0] Szero, Sat, Sv0, Sv1, Sa0, Sa1, Sa2, Sa3;//0-7
     reg[31:0] St0, St1, St2, St3, St4, St5, St6, St7;//8-15, Temp
     reg[31:0] Ss0, Ss1, Ss2, Ss3, Ss4, Ss5, Ss6, Ss7;//16-23, Saved
     reg[31:0] St8, St9, Sk0, Sk1, Sgp, Ssp, Sfp, Sra;//24-31
    
     //以下初值仅用于测试
     initial begin
          Szero = 0; Sat=1; Sv0=2; Sv1=3; Sa0=4; Sa1=5; Sa2=6; Sa3=7;
          St0=8; St1=9; St2=10; St3=11; St4=12; St5=13; St6=14; St7=15;
          Ss0=16; Ss1=17; Ss2=18; Ss3=19; Ss4=20; Ss5=21; Ss6=22; Ss7=23;
          St8=24; St9=25; Sk0=26; Sk1=27; Sgp=28; Ssp=29; Sfp=30; Sra=31;
     end
    
     //根据寄存器号取对应寄存器值(rs和rt)
     always @(posedge clk) begin
          case (rs)
               0:A=0; //$zero
               1:A=Sat;
               2:A=Sv0;
               3:A=Sv1;
               4:A=Sa0;
               5:A=Sa1;
               6:A=Sa2;
               7:A=Sa3;
               8:A=St0;
               9:A=St1;
               10:A=St2;
               11:A=St3;
               12:A=St4;
               13:A=St5;
               14:A=St6;
               15:A=St7;
               16:A=Ss0;
               17:A=Ss1;
               18:A=Ss2;
               19:A=Ss3;
               20:A=Ss4;
               21:A=Ss5;
               22:A=Ss6;
               23:A=Ss7;
               24:A=St8;
               25:A=St9;
               26:A=Sk0;
               27:A=Sk1;
               28:A=Sgp;
               29:A=Ssp;
               30:A=Sfp;
               31:A=Sra;         
          endcase
         
          case (rt)
               0:B=0;//$zero
               1:B=Sat;
               2:B=Sv0;
               3:B=Sv1;
               4:B=Sa0;
               5:B=Sa1;
               6:B=Sa2;
               7:B=Sa3;
               8:B=St0;
               9:B=St1;
               10:B=St2;
               11:B=St3;
               12:B=St4;
               13:B=St5;
               14:B=St6;
               15:B=St7;
               16:B=Ss0;
               17:B=Ss1;
               18:B=Ss2;
               19:B=Ss3;
               20:B=Ss4;
               21:B=Ss5;
               22:B=Ss6;
               23:B=Ss7;
               24:B=St8;
               25:B=St9;
               26:B=Sk0;
               27:B=Sk1;
               28:B=Sgp;
               29:B=Ssp;
               30:B=Sfp;
               31:B=Sra;
          endcase
         
          //write reg rd
          if (RegWrite == 1)
          case (rd)
               0:Szero=0;
               1:Sat=result;
               2:Sv0=result;
               3:Sv1=result;
               4:Sa0=result;
               5:Sa1=result;
               6:Sa2=result;
               7:Sa3=result;
               8:St0=result;
               9:St1=result;
               10:St2=result;
               11:St3=result;
               12:St4=result;
               13:St5=result;
               14:St6=result;
               15:St7=result;
               16:Ss0=result;
               17:Ss1=result;
               18:Ss2=result;
               19:Ss3=result;
               20:Ss4=result;
               21:Ss5=result;
               22:Ss6=result;
               23:Ss7=result;
               24:St8=result;
               25:St9=result;
               26:Sk0=result;
               27:Sk1=result;
               28:Sgp=result;
               29:Ssp=result;
               30:Sfp=result;
               31:Sra=result;
          endcase
     end
endmodule
//根据function field的值进行计算
module ALUnit(clk, A, B, ALUoper, result, zero);
     input clk;
     input [31:0] A, B;
     input [2:0] ALUoper;
    
     output zero;
     reg zero;
     output [31:0] result;
     reg [31:0] result;
    
     always @(*) begin/*always @(posedge clk) begin 会有延迟,计算结果不能立刻写入result,也不能立刻写入寄存器堆。*/
          case (ALUoper)
               3'b000: result = A & B;
               3'b001: result = A | B;
               3'b010: result = A + B;
               3'b110: result = A - B;
               3'b111: result = (A<B)?1:0;
               default: result = A + B;//Add
          endcase
          zero = (A==B)?1:0;
     end
endmodule
 //为什么有些地方always @ (*)会出问题。。
 
 
module ALUctr(clk, ALUop, Func, op);
     input clk;
     input [1:0] ALUop;
     input [5:0] Func;
     output [2:0] op;
     reg[2:0] op;
    
     always @(posedge clk) begin// 如果改成always @(*) begin会出现不同步的问题。
          case (ALUop[1])
               1'b0:case (ALUop[0])
                    1'b0:op<=3'b010;
                    1'b1:op<=3'b110;
                    endcase
               1'b1:case (Func)
                    6'b100000:op<=3'b010;
                    6'b100010:op<=3'b110;
                    6'b100100:op<=3'b000;
                    6'b100101:op<=3'b001;
                    6'b101010:op<=3'b111;
                    endcase
          endcase
     end
endmodule


//测试代码,可以再仿真中修改数字显示的格式(二进制、十进制等),还可以修改时间窗口的长短。
module test;
  reg clk = 1'b0;
    reg rst = 1'b0;
    reg [31:0] I = 32'b00000000000000000000000000000000;
    wire [31:0] A;
    wire [31:0] B;
    wire [31:0] result;
    parameter PERIOD = 20;//时钟周期长短
    parameter real DUTY_CYCLE = 0.5;
    parameter OFFSET = 0;
    initial    // Clock process for clk
    begin
        #OFFSET;
        forever//10ns,clk会翻转一次
        begin
            clk = 1'b0;
            #(PERIOD-(PERIOD*DUTY_CYCLE)) clk = 1'b1;
            #(PERIOD*DUTY_CYCLE);
        end
    end
    Rtype UUT (
        .clk(clk),
        .rst(rst),
        .instru(I),
        .Adat(A),
        .Bdat(B),
        .result(result));//将A作为子模块输入,对应子模块里边的Adat
    initial begin
        // -------------  Current Time:  105ns
        #105;
        rst = 1'b1;
        // -------------------------------------
        // -------------  Current Time:  405ns
        #300;
        I = 32'b00000001101010001000000000100000;
        // -------------------------------------
        // -------------  Current Time:  1405ns
        #1000;
        I = 32'b00000001110010011000100000100010;
        // -------------------------------------
        // -------------  Current Time:  2405ns
        #1000;
        I = 32'b00000001111010101001000000100100;
        // -------------------------------------
        // -------------  Current Time:  3405ns
        #1000;
        I = 32'b00000011000010111001100000100101;
        // -------------------------------------
        // -------------  Current Time:  4405ns
        #1000;
        I = 32'b00000011001011001010000000101010;
        // -------------------------------------
    end
      
endmodule
 


  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值