天天看點

CPU實驗-risc-v37條實驗

PC:
module PC(
    input rst,
    input clk,
    input [31:0] next,
    output reg [31:0] addr
    );
    always @(posedge clk)
        if(rst)
            addr<=32'h0
        else
            addr <=next;
    initial
        $monitor($time ,,"=====================================pc:addr=%h",addr);
    initial
        $monitor($time ,,"pc:next=%h",next);
endmodule
ROM:

module rom(
    input[31:0] addr,
    output reg [31:0] ins
    );
     
    always @(*)
    begin
        case(addr)
        //立即數測試(I類指令,除了load,jalr指令)
           32'h0:ins=32'h00100093;//addi x1,x0,1;
           32'h4:ins=32'h00100093;//addi x2,x0,1;
           32'h8:ins=32'h00100113;//slti x3,x2,3;
           32'hc:ins=32'h00312193;//sltiu x4,x1,3;
           32'h10:ins=32'h0030b213;//xori x5 ,x0,1;
           32'h14:ins=32'h00104293;//ori x6,x1,0x789;
           32'h18:ins=32'h7890e313;//andi x7,x1,10;
           32'h1c:ins=32'h00a0f393;//slli x6,x1,1;
           32'h20:ins=32'h00109313;//srli x7,x1,1;
           32'h24:ins=32'h0010d393;//srai x8,x2,1;
           32'h28:ins=32'h40115413;//lw x10,1(x0);
           32'h2c:ins=32'h00102503;//lb x11,1(x0);
           //R類測試
           32'h30:ins=32'h00100583;//lbu x12,1(x0);
           32'h34:ins=32'h00104603;// lh x13,1(x0);
           32'h38:ins=32'h00101683;//lhu x14,1(x0);
           32'h3c:ins=32'h00105703;// sw x4,4(x0);
           32'h40:ins=32'h00402223;//sb x1,8(x0);
           32'h44:ins=32'h00100423;// sh x3,12(x0);
           32'h48:ins=32'h00301623;// beq x3,x4,4;
           32'h4c:ins=32'h00418263;//  bne x3,x4,4;
           32'h50:ins=32'h00419263;// blt x3,x4,4;
           32'h54:ins=32'h0041c263;//bltu x2,x4,4;
           //store指令
           32'h58:ins=32'h00416263;//bge x2,x4,4;
           32'h5c:ins=32'h00415263;// bgeu x2,x4,4;
           32'h60:ins=32'h00417263;// lui x3,10;
           //load
           32'h64:ins=32'h0000a1b7;//auipc x15,4,;
           32'h68:ins=32'h00004797;//jal x10,4;
           32'h6c:ins=32'h0040056f;// jalr x11,x3,4
           32'h70:ins=32'h004185e7;// add x3,x2,x1;
           32'h74:ins=32'h001101b3;//sub x10,x4,x3
           //auipc
           32'h78:ins=32'h40320533;//sll x11,x4,x3;
           //B類指令
           32'h7c:ins=32'h003215b3 ;//slt x12,x4,x3;
           32'h80:ins=32'h00322633;//sltu x13,x2,x3;
           32'h84:ins=32'h003136b3;//  xor x14,x3,x4;
           32'h88:ins=32'h0041c733;// srl x15,x4,x3;
           32'h8c:ins=32'h003257b3;//  bge x2,x4,12  下一條
           32'h90:ins=32'h40325833;//sra x16,x4,x3;
           //jalr
           32'h94:ins=32'h0041e8b3;// or x17,x3,x4;
           //jal
           32'h98:ins=32'h0041f5b3;//and x11,x3,x4;
        endcase 
    end
    initial
             $monitor($time ,,"rom:addr=%h,ins=%h",addr,ins);     
endmodule
實驗二(實作斐波那契數):
`timescale 1ns / 1ps
module rom(
    input[31:0] addr,
    output reg [31:0] ins
    );
     
    always @(*)
    begin
        case(addr)
        32'h0:ins=32'h04002203;//lw x4,40h(x0);
        32'h4:ins=32'h00300293;//addi x5,x0,3
        32'h8:ins=32'h00100093;//addi x1,x0,1  
        32'hc:ins=32'h00100113;//addi x2,x0,1
        32'h10:ins=32'h001101b3;
        32'h14:ins=32'h000100b3;
        32'h18:ins=32'h00018133;
        32'h1c:ins=32'h001101b3;
        32'h20:ins=32'hfff20213;
        32'h24:ins=32'hfe42e8e3;
        32'h28:ins=32'h08302023;//sw
        endcase 
    end
    initial
             $monitor($time ,,"rom:addr=%h,ins=%h",addr,ins);     
endmodule

分析指令(ID)相關子產品代碼:
ID:
`timescale 1ns / 1ps
module ID(
    input [31:0] ins,
    output [4:0] rs1,
    output [4:0] rs2,
    output [4:0] rd,
    output [6:0] opcode,
    output [11:0] imm12,//12位立即數
    output [2:0] func,
    output [19:0] imm20,//20位立即數
    output dis//區分碼,指令的第30位
    );
    assign opcode =ins[6:0];
    assign rd =ins[11:7];
    assign func =ins[14:12];
    assign rs1 =ins[19:15];
    assign rs2 =ins[24:20];
    assign dis =ins[30];
    wire I_type ,S_type,B_type, J_type,U_type,R_type;
    //00x0011 I指令  ||1100111  jalr
    assign I_type =(~ins[6]&~ins[5]&~ins[3]&~ins[2]&ins[1]&ins[0])|
    ((&ins[6:5])&~(|ins[4:3])&(&ins[2:0]));
    //1100011 B指令  
    assign B_type =(&ins[6:5])&~(|ins[4:2])&(&ins[1:0]);
    //0100011 S指令  
    assign S_type =~ins[6]&ins[5]&~(|ins[4:2])&(&ins[1:0]); 
    //1101111 J指令    jal
    assign J_type =(&ins[6:5])&~ins[4]&(&ins[3:0]);
    //0x10111 U指令    
    assign U_type =~ins[6]&ins[4]&~ins[3]&(&ins[2:0]);
    //0110011 R指令
    assign R_type =~ins[6]&(&ins[5:4])&~(|ins[3:2])&(&ins[1:0]);
    assign imm12={12{I_type}}&ins[31:20]|
                    {12{B_type}}&{ins[31],ins[7],ins[30:25],ins[11:8]}|
                    {12{S_type}}&{ins[31:25],ins[11:7]};
    assign imm20={20{U_type}}&ins[31:12]|
                     {20{J_type}}&{ins[31],ins[19:12],ins[20],ins[30:21]};
    initial
         $monitor($time ,,"ID:rs1=%b,rs2=%b,rd=%b",rs1,rs2,rd);                    
endmodule

ControlUnit:

module ControlUnit(
    input [6:0] opcode,
    input [2:0] func,
    input dis,
    input c,//滿足B類跳轉
    output reg [1:0]  pcs,//下一條指令位址來源
    output reg rwe,//寄存器寫使能端
    output reg mwe,//RAM寫使能端   
    output reg [2:0] mm,//RAM讀寫方式  
    output reg [3:0] aluOP,//運算類型
    output reg isimm,//b是否是立即數
    output reg is20,//b是否為20的立即數
    output reg isfpc,//a來源于pc
    output reg isfm,//rwdata是否來源于mem
    output reg ispc4//rwdata是否來源于pc+4
    );
    always @(*)
        begin 
            case(opcode)   
                7'b0110011://R類指令
                begin
                    rwe=1'b1;//控制器(CU)産生aluOP信号給ALU,産生rwe信号(1'b1)給寄存器堆,産生pcs信号(2'b00)給資料選擇器MUX。
                    pcs=2'b00;//R類指令不是跳轉指令, pcs的值是2'b00
                    mwe=1'b0;
                    isimm=1'b0;//通過PC從ROM中讀出R類指令
                    is20=1'b0;
                    isfpc=1'b0;
                    isfm=1'b0;
                    ispc4=1'b0;
                    if(dis)
                        begin
                            case(func)
                                3'b000:
                                    aluOP=4'b0010;//sub
                                3'b101:
                                    aluOP=4'b0110;//sra
                            endcase
                        end
                    else
                        begin
                            case(func)
                                3'b000:
                                    aluOP=4'b0001;//add
                                3'b111:
                                    aluOP=4'b0011;//and
                                3'b110:
                                    aluOP=4'b0100;//or
                                3'b100:
                                    aluOP=4'b0101;//xor
                                3'b001:
                                    aluOP=4'b0111;//sll
                                3'b101:
                                    aluOP=4'b1000;//srl
                                3'b010:
                                    aluOP=4'b1001;//slt
                                3'b011:
                                    aluOP=4'b1010;//sltu
                            endcase        
                        end
                end
                7'b0010011://I類指令,除了load,jalr指令
                    begin
                        rwe=1'b1;//産生rwe信号(1'b1)給寄存器堆,産生pcs信号(2'b00)給資料選擇器MUX
                        pcs=2'b00;//立即數指令不是跳轉指令, pcs的值是2`b00
                        mwe=1'b0;
                        isimm=1'b1;//從ROM中讀出立即數指令
                        is20=1'b0;
                        isfpc=1'b0;
                        isfm=1'b0;
                        ispc4=1'b0;
                        case(func)
                            3'b000:
                                aluOP=4'b0001;//addi
                            3'b111:
                                aluOP=4'b0011;//andi
                            3'b110:
                                aluOP=4'b0100;//ori
                            3'b100:
                                aluOP=4'b0101;//xori
                            3'b001:
                                aluOP=4'b0111;//slli
                            3'b101:
                                if(dis)
                                    aluOP=4'b0110;//srai
                                else
                                    aluOP=4'b1000;//srli
                            3'b010:
                                aluOP=4'b1001;//slti
                            3'b011:
                                aluOP=4'b1010;//sltui
                         endcase        
                     end    
                 7'b0000011://load指令
                     begin
                         rwe=1'b1;//産生rwe信号(1'b1)給寄存器堆,産生pcs信号(2'b00) 給資料選擇器MUX
                         pcs=2'b00;
                         mwe=1'b0;
                         isimm=1'b1;//産生mm信号給資料存儲器RAM
                         is20=1'b0;
                         isfpc=1'b0;
                         isfm=1'b1;
                         ispc4=1'b0;
                         case(func)
                             3'b000:
                                 begin
                                     mm=3'b000;
                                     aluOP=4'b0001;//lb
                                 end
                             3'b001:
                                 begin
                                     mm=3'b001;
                                     aluOP=4'b0001;//lh
                                 end
                             3'b010:
                                 begin
                                     aluOP=4'b0001;//lw
                                     mm=3'b010;
                                 end
                             3'b100:
                                 begin
                                     mm=3'b011;
                                     aluOP=4'b0001;//lbu
                                 end
                             3'b101:
                                 begin
                                     mm=3'b100;
                                    aluOP=4'b0001;//lhu
                                 end
                         endcase        
                     end    
                 7'b0100011://store指令
                     begin
                         rwe=1'b0;
                         pcs=2'b00;
                         mwe=1'b1;//産生mwe信号(1'b1)給RAM,産生pcs信号(2'b00)給資料選擇器MUX
                         isimm=1'b1;//産生mm信号給資料存儲器RAM
                         is20=1'b0;
                         isfpc=1'b0;
                         isfm=1'b0;
                         ispc4=1'b0;
                         case(func)
                             3'b000:
                                 begin
                                     mm=3'b101;
                                     aluOP=4'b0001;//sb
                                 end
                             3'b001:
                                 begin
                                     mm=3'b110;
                                     aluOP=4'b0001;//sh
                                 end
                             3'b010:
                                 begin
                                     aluOP=4'b0001;//sw
                                     mm=3'b111;
                                 end
                          endcase        
                      end   
                  7'b0110111://lui指令
                      begin
                          rwe=1'b1;//産生rwe信号(1'b1)給寄存器堆,産生pcs信号(2'b00)給資料選擇器MUX
                          pcs=2'b00;
                          mwe=1'b0;
                          isimm=1'b1;
                          is20=1'b1;//ID還産生了20位的立即數imm20
                          isfpc=1'b0;
                          isfm=1'b0;
                          ispc4=1'b0;
                          aluOP=4'b1011;//lui
                       end
                   7'b0010111://auipc指令
                       begin
                          rwe=1'b1;//産生rwe信号(1'b1)給寄存器堆,産生pcs信号(2'b00)給資料選擇器MUX
                          pcs=2'b00;
                          mwe=1'b0;
                          isimm=1'b1;
                          is20=1'b1;//ID還産生了20位的立即數imm20
                          isfpc=1'b1;//ALU有了a端資料(pc)
                          isfm=1'b0;
                          ispc4=1'b0;
                          aluOP=4'b1100;//auipc
                       end       
                   7'b1100011://B指令
                       begin
                           rwe=1'b0;
                           mwe=1'b0;
                           isimm=1'b0;
                           is20=1'b0;
                           isfpc=1'b0;
                           isfm=1'b0;
                           ispc4=1'b0;
                           if(c==0)//CU根據c的值産生pcs信号給MUX,MUX進行2選1,将結果next傳給PC
                               pcs=2'b00;
                           else
                               pcs=2'b01;   
                           case(func)
                               3'b000:
                                   begin
                                       aluOP=4'b0010;//beq
                                   end
                               3'b001:
                                   begin
                                       aluOP=4'b0101;//bne
                                   end
                               3'b100:
                                   begin
                                       aluOP=4'b1001;//blt
                                   end
                               3'b101:
                                   begin
                                       aluOP=4'b1101;//bge
                                   end
                               3'b110:
                                   begin
                                       aluOP=4'b1010;//bltu
                                   end
                               3'b111:
                                   begin
                                       aluOP=4'b1110;//bgeu
                                   end
                           endcase    
                       end    
                   7'b1101111://jal指令
                       begin
                           rwe=1'b1;
                           pcs=2'b10;
                           mwe=1'b0;
                           isimm=1'b0;
                           is20=1'b0;
                           isfpc=1'b0;
                           isfm=1'b0;
                           ispc4=1'b1;//産生rwe信号(1`b1)給寄存器堆,産生ispc4信号(1`b1) 用來選擇pc+4
                       end
                   7'b1100111://jalr指令
                       begin
                           rwe=1'b1;//控制器(CU)産生pcs信号(2`b11)給MUX,産生rwe信号(1`b1)給寄存器堆,産生ispc4信号(1`b1) 用來選擇pc+4,産生isimm(1`b1)、is20(1`b0)、isfpc(1`b0)。
                           pcs=2'b11;
                           mwe=1'b0;
                           isimm=1'b1;
                           is20=1'b0;
                           isfpc=1'b0;
                           isfm=1'b0;
                           ispc4=1'b1;
                           aluOP=4'b1111;//jalr
                       end
                   endcase
               end
endmodule

執行指令(EXE)相關子產品代碼:
REGS:

module REGS(
    input clk,
    input rwe,
    input[4:0] rs1,
    input[4:0] rs2,
    output[31:0] Rdata1,
    output[31:0] Rdata2,
    input[4:0] rd,
    input[31:0] rwdata
    );
    //31個 32位寬
reg[31:0] r[1:31];
assign Rdata1=(rs1==5'b00000)? 32'b0 : r[rs1];
assign Rdata2=(rs2==5'b00000)? 32'b0 : r[rs2];
always @(posedge clk)
if(rwe)//使能端為1,可寫
if(rd!=5'b00000)
r[rd]<=rwdata;
initial
$monitor($time ,,"regs:Rdata1=%h, Rdata2=%h,rwdata=%h",Rdata1,Rdata2,rwdata);
endmodule

ALU:
`timescale 1ns / 1ps
module ALU(
    input[3:0] aluOP,   
    input[31:0] a,   
    input[31:0] b,  
    output reg[31:0] f  ,
    output reg c
    );
   
    always @(*)   
        case(aluOP)       
            4'b0000: f=31'b0;       
            4'b0001: f=a+b;       //add
            4'b0010:
                begin
                    f=a-b;       //sub
                    c=~(|f);
                end
            4'b0011: f=a&b;       //and
            4'b0100: f=a|b;       //or
            4'b0101:
                begin
                    f=a^b;//xor
                    if(f==0)
                        c=0;
                    else 
                        c=1;
                end
            4'b0110: f=$signed(a)>>>b[4:0];//sra   
            4'b0111: f=a<<b[4:0];//sll
            4'b1000: f=a>>b[4:0];//srl
            4'b1001: 
                if($signed(a)<$signed(b))//slt
                    begin
                        f=32'b1;
                        c=1'b1;
                    end
                else 
                    begin
                        f=32'b0;
                        c=1'b0;
                    end
             4'b1010: 
                 if(a<b)//sltu
                     begin
                         f=32'b1;
                         c=1'b1;
                     end
                 else 
                     begin
                         f=32'b0;
                         c=1'b0;
                     end
             4'b1011: f=b<<12;//lui
             4'b1100: 
                 begin
                     f=b<<12;//auipc
                     f=f+a;
                 end
             4'b1101: 
                 if($signed(a)>=$signed(b))//bge
                     begin
                         c=1'b1;
                     end
                 else 
                     begin
                         c=1'b0;
                     end
             4'b1110: 
                 if(a>=b)//bgeu
                     begin
                         c=1'b1;
                     end
                 else 
                     begin
                         c=1'b0;
                     end
             4'b1111: //jalr
                     begin
                         f=a+b;     
                         f[0]=0;
                     end  
         endcase
    initial
    $monitor($time ,,"alu:a=%h, b=%h,f=%h",a,b,f);      
    initial
    $monitor($time ,,"alu:f=%h",f);         
     
endmodule

MUX:

module MUX(
    input [1:0]pcs,
    input [31:0] addr,
    input [31:0] imm12,
    input [31:0] imm20,
    input [31:0] f,
    output reg [31:0] next
    );
    always @(*)
        begin
            case(pcs)
                2'b00:next=addr+4;
                2'b01:next=(imm12<<1)+addr;
                2'b10:next=(imm20<<1)+addr;
                2'b11:next=f;
            endcase
         end
    initial
      $monitor($time ,,"MUX:next=%h",next);     
Endmodule

RAM:
`timescale 1ns / 1ps
module ram(
    input[5:0] addr,//2^6=64
    input[31:0] wdata,
    input clk,
    input we,
    output[31:0] rdata
    );
    
    //RAM
    reg[31:0] r[0:63];
    //讀資料
    assign rdata=r[addr];
    //寫入  
    always @(posedge clk)
    begin
        if(we)
            begin
                r[addr]<=wdata;
            end   
    end
endmodule

newram:

module newram(
    input[5:0] maddr,
    input[31:0] mwdata,
    input mwe,
    input clk,
    input[2:0] mm,
    output[31:0] mdata
    );
    //操作
    wire lb,lh,lw,lbu,lhu,sb,sh,sw;
    //輸入和輸出
    wire[31:0]temp_in;
    wire[31:0]temp_out;
    //用于輸出處理
    assign lb=~(|mm);    //000
    assign lh=~(|mm[2:1])&mm[0];//001
    assign lw=(~mm[2]&mm[1]&~mm[0]);//010
    assign lbu=(&mm[1:0])&~mm[2];//011
    assign lhu=mm[2]&~(|mm[1:0]);//100
    assign mdata = {32{lb}}&{{24{temp_out[7]}},temp_out[7:0]}|
                    {32{lh}}&{{16{temp_out[15]}},temp_out[15:0]}|
                    {32{lw}}&temp_out|
                    {32{lbu}}&{24'b0,temp_out[7:0]}|
                    {32{lhu}}&{16'b0,temp_out[15:0]};
    //用于輸入處理
    assign sb=mm[2]&~mm[1]&mm[0];//101
    assign sh=(&mm[2:1])&~mm[0];//110
    assign sw=&mm[2:0];//111
    assign temp_in=({{24'b0},{8{sb}}}|{{16'b0,{16{sh}}}}|{32{sw}})&mwdata;
    ram ram1(.addr(maddr),.wdata(temp_in),.we(mwe),.clk(clk),.rdata(temp_out));  
    
    initial     	$monitor($time,,"ram:mm=%b,mwe=%b,maddr=%h,mwdata=%h,mdata=%h",mm,mwe,maddr,mwdata,mdata); 
endmodule

IOManger:
`timescale 1ns / 1ps
module IOManger(
    input [7:0]maddr,
    input [2:0]mm,
    input clk,
    input we,
    input [31:0]wdata,
    input [5:0]n,
    output [31:0] data,
    output reg [31:0]result
    );
    wire [31:0] mwdata,mdata;
    wire memEnable,mwe;
    assign memEnable=~(|maddr[7:6]);
    assign mwe =memEnable&we;
    //執行個體化RAM
    newram newram1 (
    .maddr(maddr[5:0]),
    .mm(mm),
    .clk(clk),
    .mwe(mwe),
    .mdata(mdata),
    .mwdata(mwdata)
    );
    //data是lw指令的輸出結果,來源于兩個,
    assign data=maddr[6]?{26'h0,n}:mdata;
    assign mwdata=wdata;
    //當sw指令位址maddr[7]==1時,表示輸出結果
    always @(posedge clk)
        if(we&&maddr[7])
            result<=wdata;
    initial
              $monitor($time ,,"IOManger:maddr=%b,result=%h",maddr,result);      
    initial
              $monitor($time ,,"IOManger:wdata=%b,data=%h",wdata,data);  
endmodule

top:

module top(
    input rst,
    input clk,
    input [5:0] n,
    output [31:0]result
);
    wire [31:0] next,addr,ins;
    wire [4:0] rs1,rs2,rd;
    wire [6:0] opcode;
    wire [11:0] imm12;
    wire [2:0] func;
    wire [19:0] imm20; 
    wire [31:0] imm12_exp,imm20_exp,Rdata1,Rdata2,mwdata,mdata,f;
    wire [1:0] pcs;
    wire [2:0] mm;
    wire [3:0] aluOP;
    reg [31:0] rwdata,a,b;
    wire dis,c,rwe,mwe,isimm,is20,isfpc,isfm,ispc4;    
    wire [7:0]IOaddr;
    wire clk18;
    assign imm12_exp={{20{imm12[11]}},imm12};
    assign imm20_exp={{12{imm20[19]}},imm20};
    always @(*)
        begin
            if(isimm)
                if(is20)
                    b=imm20_exp;
                else
                    b=imm12_exp;
             else
                 b=Rdata2;
             if(isfpc)
                 a=addr;
             else
                 a=Rdata1;
             if(ispc4)
                 rwdata=addr+4;    
             else
                 if(isfm)
                     rwdata=mdata;
                 else
                     rwdata=f;
         end
     assign  mwdata=Rdata2;
     assign IOaddr = f[7:0];
     PC pc1(.rst(rst),. clk(clk),.next(next),.addr(addr));
     rom rom1(.addr(addr),.ins(ins));
     ID id1(.ins(ins),.rs1(rs1),.rs2(rs2),.rd(rd),.opcode(opcode),.imm12(imm12),.func(func),.imm20(imm20),.dis(dis));
     ControlUnit cu1(.opcode(opcode),.func(func),.dis(dis),.c(c),.pcs(pcs),.rwe(rwe),.mwe(mwe),.mm(mm),.aluOP(aluOP),.isimm(isimm),.is20(is20),.isfpc(isfpc),.isfm(isfm),.ispc4(ispc4));
     REGS regs1(.clk(clk),.rwe(rwe),.rs1(rs1),.rs2(rs2),.Rdata1(Rdata1),.Rdata2(Rdata2),.rd(rd),.rwdata(rwdata));
     ALU alu1(.aluOP(aluOP),.a(a),.b(b),.f(f),.c(c));
     IOManger iomanger1(.maddr(IOaddr),.mm(mm),.clk(clk),.we(mwe),.wdata(mwdata),.n(n),.data(mdata),.result(result));
     MUX mux1(.pcs(pcs),.addr(addr),. imm12(imm12_exp),.imm20(imm20_exp),.f(f),.next(next));
endmodule

仿真檔案:

module sim();
      reg [5:0] n=6'b000111; 
      reg clk = 1'b0;
      always #10
          clk = ~clk;
      reg rst = 1'b1;
      top t1(.clk(clk),.rst(rst),.n(n));
      initial
          #11 rst = 1'b0;
endmodule
           

繼續閱讀