verilog实现32位5级流水线简易cpu(可执行5条指令,带数据冲突、分支跳转)

这里写自定义目录标题


正在学习计算机组成原理,以下为计组大作业,借鉴了很多其他人的代码加入了自己的更改。仅供学习使用。这里实现的5条操作指令为:
ADD R1 R2 R3 :R3=R1+R2;加和赋值操作
XOR R1 R2 R3 :R3=R1^R2;异或赋值操作
LOAD R1 R2 VAl1:R2=MEM[R1+VAL1]从memory载入数据
STORE R1 R2 VAL2: MEM[R1+VAL2]=R1;向memory写入数据
beq R1 R2 VAL3 : if(R1==R2) PC=PC+1+VAL3;条件跳转

在这里插入图片描述
这个是简易CPU的5级流水线流程图。关于各个部分具体的内容介绍我就不赘述了,可以去网上查找资料。关于流水线操作的数据冲突以及操作冲突的内容也不做过多的介绍。主要是放代码。
在这里插入图片描述
上图为32位操作指令的结构,【31-25】位没用上全部置零。【24-22】为指令的标志位,用来区分指令。【21-19】,【18-16】为两个寄存器的地址位,用来指示被操作数的地址,在指令被读取之后会到对应的寄存器中提取数据,然后进行操作。第一个指令类型使用于ADD和XOR,LOAD、STORE、beq适用于第二个指令类型。

简易CPU的结构:
1 PCPU 主要模块:用从指令内存得到的指令进行运算处理,并从数据内存中写入或读取数据。这是最核心的部分,其他模块都很好设计。

2 Instruction_Mem 指令模块: 为PCPU模块提供指令,使得PCPU中通过指令寄存器中的值,找到指令的内存地址,从而读取指令。

3 Data_Mem 数据模块: PCPU从中读取数据或写入数据
在这里插入图片描述
上图借鉴博客:https://blog.csdn.net/august717/article/details/46120163,感觉这个写的比我好,大家可以去看看。
上代码:
头文件 headfile.v


`ifndef HEADFILE_H_

`define idle 1'b0
`define exec 1'b1
`define LOAD 3'b010
`define STORE 3'b011
`define ADD 3'b000
`define XOR 3'b001
`define beq 3'b100

`define gr0 3'b000
`define gr1 3'b001
`define gr2 3'b010
`define gr3 3'b011
`define gr4 3'b100
`define gr5 3'b101
`define gr6 3'b110
`define gr7 3'b111 
`endif

顶层cpu.v

module cpu( input wire clk, enable, reset, start); 

wire [31:0] d_datain; //data from memory 
wire [31:0] i_datain; //instruction
wire [7:0] d_addr;    //address for data memory
wire [31:0] d_dataout;//output data to data memory
wire d_we;            //write datamemory write enable 
wire [7:0] i_addr;    //pc
PCPU pcpu(
    .clock(clk),
    .enable(enable),
    .reset(reset),
    .start(start),
    .d_datain(d_datain),
    .i_datain(i_datain),
    .d_addr(d_addr),
    .d_dataout(d_dataout),
    .d_we(d_we),
    .i_addr(i_addr)
);
I_mem i_mem(
    .addra(i_addr),
    .douta(i_datain)
);
D_mem d_mem(
    .wea(d_we),
    .addra(d_addr),
    .dina(d_dataout),
    .douta(d_datain)
);
endmodule

底层:PCPU.v

`include "headfile.v"

module PCPU(input wire reset, enable, clock, start,
    input wire [31:0] d_datain,  //data from memory 
    i_datain,                    //instruction
    output wire [7:0] d_addr,    //address for data memory 
    output wire [7:0] i_addr,    //pc
    output wire [31:0] d_dataout,//output data to data memory 
    output wire d_we             //write enable 
    );
reg state,next_state;  //to control the CPU  
reg [7:0] pc;
reg [31:0] id_ir,ex_ir,mem_ir,wb_ir;
reg [31:0] reg_A, reg_B, reg_C, reg_C1, smdr, smdr1, ALUo; 
reg dw, zf, nf, cf, cin,flag;
reg [31:0] gr[0:7];
assign d_dataout = smdr1;
assign d_we = dw;
assign d_addr = reg_C[7:0];//***** 
assign i_addr = pc;
//************* CPU control *************//
always @(posedge clock or negedge reset)
    begin
        if (!reset)
            state <= `idle;
        else
            state <= next_state;
    end
always @(*)
    begin
        case (state)
            `idle : 
                if ((enable == 1'b1) && (start == 1'b1)) // on
                    next_state <= `exec;
                else    
                    next_state <= `idle;
            `exec :
                if (enable == 1'b0)//pause
                    next_state <= `idle;
                else
                    next_state <= `exec;
        endcase
    end

//************* IF *************// 
always @(posedge clock or negedge reset)
    begin
        if (!reset)
            begin
                id_ir <= 32'b0000_0000_0000_0000_0000_0000_0000_0000;
                pc <= 8'b0000_0000;
            end

        else if (state ==`exec)
            begin   
  
            //Load hazard  Stall    
               if((id_ir[24:22] == `LOAD)&&(i_datain[24:22]!=`LOAD)) 
                 begin
   
                      //r2
                    if((id_ir[18:16]==i_datain[18:16])&&((i_datain[24:22]==`STORE)||(i_datain[24:22]==`ADD)||(i_datain[24:22]==`XOR)))
                       begin
                         pc <= pc;
                         id_ir <= 16'bx;
                       end
                      //r3
                   else if((id_ir[18:16]==i_datain[21:19])&&((i_datain[24:22]==`STORE)||(i_datain[24:22]==`ADD)||(i_datain[24:22]==`XOR)))

 
 
                       begin
                         pc <= pc;
                         id_ir <= 16'bx;
                       end
                      else
                         begin
                            pc <= pc + 1'b1;
                         id_ir <= i_datain;
                          end
                   end
               else if(id_ir[24:22] == `beq || ex_ir[24:22] == `beq)
                    begin
                         pc <= pc;
                         id_ir <= 16'bx;
                       end
               else if((mem_ir[24:22] == `beq)&& (flag == 1'b1)) 
                   begin
                    pc <= pc+mem_ir[7:0];
                    id_ir <= 16'bx;
                   end
               else
                   begin
                       pc <= pc + 1'b1;
                       id_ir <= i_datain;
                    end
            end
         else if(state==`idle)
                begin
                   id_ir <= id_ir;
                    pc <= pc;
                end         
    end
//************* ID *************//
always @(posedge clock or negedge reset)
    begin
        if (!reset)
            begin
                ex_ir <= 32'b0000_0000_0000_0000_0000_0000_0000_0000;
                reg_A <= 32'b0000_0000_0000_0000_0000_0000_0000_0000;
                reg_B <= 32'b0000_0000_0000_0000_0000_0000_0000_0000; 
                smdr <= 32'b0000_0000_0000_0000_0000_0000_0000_0000;
            end
        //flush
       // else if(state == `exec && (ex_ir[15:11]==`BZ && zf==1'b1))
       //       ex_ir <= 16'bx;

      else if (state == `exec)
            begin
                ex_ir <= id_ir;
               //regA
              
                //r1=r2#r3 or r1=r2#val 
                 if(id_ir[24:22] == `LOAD || id_ir[24:22] == `STORE || id_ir[24:22] == `ADD || id_ir[24:22] == `XOR) 
                    begin
                       //r2
                       if( (ex_ir[24:22] == `ADD || ex_ir[24:22] == `XOR||ex_ir[24:22] == `beq )&& ex_ir[2:0] == id_ir[21:19])
                            reg_A <= ALUo;
                       else if( (mem_ir[24:22] == `ADD || mem_ir[24:22] == `XOR ||mem_ir[24:22] == `beq )&& mem_ir[2:0] == id_ir[21:19])
                            reg_A <= reg_C;
                       else if( mem_ir[24:22] == `LOAD && mem_ir[18:16] == id_ir[21:19])
                            reg_A <= d_datain;
                       else if( (wb_ir[24:22] == `ADD || wb_ir[24:22] == `XOR ||wb_ir[24:22] == `beq)&& wb_ir[2:0] == id_ir[21:19])
                            reg_A <= reg_C1;
                       else if( wb_ir[24:22] == `LOAD && wb_ir[18:16] == id_ir[21:19]) 
                            reg_A <= reg_C1; 
                        else
                            reg_A <= gr[id_ir[21:19]];//gr2
                     end    
                 
               
                else
                    reg_A <= gr[id_ir[21:19]];//gr2
                //regB
                if (id_ir[24:22] == `LOAD || id_ir[24:22] == `STORE )
                    reg_B <= {28'b0000_0000_0000, id_ir[3:0]};//val3

                //r1=r2#r3
                else if(id_ir[24:22] == `ADD || id_ir[24:22] == `XOR||id_ir[24:22] == `beq)
                   begin
                       if( (ex_ir[24:22] == `ADD  || ex_ir[24:22] == `XOR ||ex_ir[24:22] == `beq )&& ex_ir[2:0] == id_ir[18:16])
                            reg_B <= ALUo;
                        else if( (mem_ir[24:22] == `ADD || mem_ir[24:22] == `XOR ||mem_ir[24:22] == `beq )&& mem_ir[2:0] == id_ir[18:16])
                             reg_B <= reg_C;
                        else if( mem_ir[24:22] == `LOAD && mem_ir[18:16] == id_ir[18:16])
                             reg_B <= d_datain;
                        else if( (wb_ir[24:22] == `ADD || wb_ir[24:22] == `XOR ||wb_ir[24:22] == `beq)&& wb_ir[2:0] == id_ir[18:16])
                             reg_B <= reg_C1;
                        else if( wb_ir[24:22] == `LOAD && wb_ir[18:16] == id_ir[18:16])
                             reg_B <= reg_C1;
                        else
                            reg_B <= gr[id_ir[18:16]];//gr2
                     end

                else
                    reg_B <= gr[id_ir[18:16]];//gr3
               //STORE  
               if (id_ir[24:22] == `STORE)
                   begin
                      //r1???
                      if(id_ir[18:16] == ex_ir[2:0] && (ex_ir[24:22] == `ADD || ex_ir[24:22] == `XOR ))
                           smdr <= ALUo;
                      else if(id_ir[18:16] == mem_ir[2:0] && (mem_ir[24:22] == `ADD || mem_ir[24:22] == `XOR))    
                           smdr <= reg_C;                  
                     else if(id_ir[18:16] == mem_ir[18:16] && mem_ir[24:22] == `LOAD)
                           smdr <= d_datain;
                      else if(id_ir[18:16] == wb_ir[2:0] && (wb_ir[24:22] == `ADD || wb_ir[24:22] == `XOR ))
                           smdr <= reg_C1;
                      else if(id_ir[18:16] == wb_ir[18:16] && wb_ir[24:22] == `LOAD  )
                           smdr <= reg_C1;
                      else
                          smdr <= gr[id_ir[18:16]]; 
                    end
                else
                    smdr <= gr[id_ir[18:16]];


            end
   end
//************* ALU *************//
reg signed [31:0] reg_A1;
always @(*)
begin
  reg_A1 <= reg_A;
end

always @(*)
    begin
      
      if(ex_ir[24:22] == `ADD ) 
         {cf, ALUo} <= reg_A + reg_B;

      else if(ex_ir[24:22] == `XOR)
         {cf, ALUo} <= reg_A ^ reg_B;

      
      else if(ex_ir[24:22] == `LOAD || ex_ir[24:22] == `STORE)
          {cf, ALUo} <= reg_A + reg_B;
      else if(ex_ir[24:22] == `beq)
          begin
            if(reg_A ^ reg_B ==0)
              flag = 1'b1;
            else
              flag =1'b0;
          end
      else 
         {cf, ALUo} <= 33'b0;
    end     
//************* EX *************//  
always @(posedge clock or negedge reset)
    begin
        if (!reset)
            begin
                mem_ir <= 32'b0000_0000_0000_0000_0000_0000_0000_0000;
                reg_C <= 32'b0000_0000_0000_0000_0000_0000_0000_0000;
                smdr1 <= 32'b0000_0000_0000_0000_0000_0000_0000_0000;
                zf <= 1'b0;
                nf <= 1'b0;
                cin <= 1'b0;
                dw <= 1'b0;
            end 
       else if (state == `exec)
            begin
                mem_ir <= ex_ir;
                reg_C <= ALUo;

                if (ex_ir[24:22] == `ADD)
                    begin
                        if (ALUo == 32'b0000_0000_0000_0000_0000_0000_0000_0000)
                            zf <= 1'b1;//if zero
                        else
                            zf <= 1'b0;
                        if (ALUo[31] == 1'b1)//if negative 
                            nf <= 1'b1;
                        else
                            nf <= 1'b0;
                    end
                else
                  begin
                     zf <= zf;
                      nf <= nf;
                  end
                //carry 
                if (ex_ir[24:22] == `ADD)                  
                      cin <= cf;
                else
                      cin <= cin; 
                //STORE   
                if (ex_ir[24:22] == `STORE)
                    begin
                        dw <= 1'b1;//data wire enable
                        smdr1 <= smdr;
                    end
                else
                   begin
                       dw <= 1'b0;
                        smdr1 <= 32'b0;
                    end

            end
   end    
//************* MEM *************//
always @(posedge clock or negedge reset)
    begin
        if (!reset)
            begin
                wb_ir <= 32'b0000_0000_0000_0000_0000_0000_0000_0000;
                reg_C1 <= 32'b0000_0000_0000_0000_0000_0000_0000_0000;
            end 
        else if (state == `exec)
            begin
                wb_ir <= mem_ir;
                if (mem_ir[24:22] == `LOAD)
                        reg_C1 <= d_datain;
                else
                        reg_C1 <= reg_C;
            end
   end      
//************* WB *************//
always @(posedge clock or negedge reset)
    begin
        if (!reset)
            begin
                gr[7] <= 32'h00000001;
                gr[6] <= 32'h00000001;
                gr[5] <= 32'h00000001;
                gr[4] <= 32'h00000002;
                gr[3] <= 32'h00000001;
                gr[2] <= 32'h00000001;
                gr[1] <= 32'h00000001;
                gr[0] <= 32'h00000001;
            end 
        else if (state == `exec)
            begin
                if (wb_ir[24:22] == `LOAD)  
                    gr[wb_ir[18:16]] <= reg_C1;//write back to gr1
                else if((wb_ir[24:22] == `ADD) ||(wb_ir[24:22] == `XOR))
                    gr[wb_ir[2:0]] <= reg_C1;//write back to gr1
                else
                   gr[wb_ir[18:16]] <= gr[wb_ir[18:16]];
            end
   end      

endmodule

底层2 instraction-mem.v

`include "headfile.v"
module I_mem(input wire [7:0] addra, output reg [31:0] douta);
reg [31:0] i_mem[20:0];
always @(*)
   begin
        douta <= i_mem[addra];
    end

initial begin

    //gcm
    i_mem[0] <= {7'b0000000, `ADD, `gr6, `gr1, 13'b0, `gr2}; //gr2=gr6+gr1
    i_mem[1] <= {7'b0000000, `XOR, `gr4, `gr5, 13'b0, `gr6}; //gr6=gr4^gr5
    i_mem[2] <= {7'b0000000,`LOAD, `gr3, `gr4, 16'h0001}; //gr4 = mem[gr3+1]
    i_mem[3] <= {7'b0000000, `ADD, `gr2, `gr5, 13'b0, `gr5}; //gr5=gr2+gr5
    i_mem[4] <= {7'b0000000,`STORE, `gr3, `gr7, 16'h0005}; //mem[gr3+5]=gr7
    
   //???? test
    i_mem[6] <= {7'b0000000, `ADD, `gr6, `gr1, 13'b0, `gr4}; //gr4=gr6+gr1
    i_mem[7] <= {7'b0000000, `ADD, `gr4, `gr5, 13'b0, `gr1}; //gr1=gr4+gr5
   
    //???? teat
    i_mem[9] <= {7'b0000000,`beq, `gr5, `gr6, 12'h000,4'b0010};//if gr6==gr5,pc=0001+1;
    i_mem[10] <= {7'b0000000, `ADD, `gr6, `gr1, 13'b0, `gr2}; //gr2=gr6+gr1
    i_mem[11] <= {7'b0000000, `ADD, `gr3, `gr5, 13'b0, `gr5}; //gr5=gr3+gr5
    i_mem[12] <= {7'b0000000, `ADD, `gr3, `gr5, 13'b0, `gr5}; //gr5=gr3+gr5
    
end

endmodule

底层3 data-mem.v

module D_mem(input wire wea, input wire [7:0] addra, input wire [31:0] dina, output wire [31:0] douta
    );
reg [31:0] d_mem[255:0];

assign  douta = d_mem[addra];
always @(*)
   begin
        if(wea == 1'b1)
             d_mem[addra] <= dina;
   end
initial begin
 //data
  d_mem[0] <= 32'h00000000;
  d_mem[1] <= 32'h00000001;  //1
  d_mem[2] <= 32'h00000005;   //5
  d_mem[3] <= 32'h00000008;//8
end
endmodule

测试代码:test.v

module test;
    // Inputs
    reg clk;
    reg enable;
    reg reset;
    reg start;

    // Instantiate the Unit Under Test (UUT)
    cpu uut (
        .clk(clk), 
        .enable(enable), 
        .reset(reset), 
        .start(start)
    );
   always #5 clk = ~clk;
    initial begin
        // Initialize Inputs
        clk = 0;
        enable = 0;
        reset = 0;
        start = 0;

      $monitor("%h:%b:%h:%h:%h:%h:%h:%h:%b:%h:%h:%h:%h:%h:%h:%h:%h:%b:%b:%b", 
         uut.pcpu.pc, uut.pcpu.id_ir, uut.pcpu.reg_A, uut.pcpu.reg_B, uut.pcpu.reg_C,
         uut.pcpu.d_addr, uut.pcpu.d_dataout, uut.pcpu.ALUo, uut.pcpu.d_we, uut.pcpu.reg_C1, uut.pcpu.gr[1], uut.pcpu.gr[2], uut.pcpu.gr[3],
          uut.pcpu.gr[4], uut.pcpu.gr[5], uut.pcpu.gr[6],
          uut.pcpu.gr[7], uut.pcpu.cin, uut.pcpu.nf, uut.pcpu.zf);

        // Wait 100 ns for global reset to finish
        #100;
      $display("pc:      id_ir:    regA:regB:regC:da:dout:ALUo:dwe:reC1: gr1:gr2:gr3: gr4: gr5: gr6: gr7: cf:nf:zf");        
        // Add stimulus here
        #10 reset <= 0;
      #10 reset <= 1; 
      #10 enable <= 1;
      #10 start <=1;
        #10 start <= 0;
        #100;   

    end

endmodule

可以安装modelsim来跑跑这个代码,欢迎大家来交流更好的想法。有啥不懂的可以私聊我,虽然我不一定能及时回复。

  • 6
    点赞
  • 55
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值