MIPS指令集单周期CPU兼Verilog学习

1.单周期CPU原理(单个时钟周期内的操作):

        (1)取指,PC+4

        (2)译码

        (3)取操作数,ALU运算

        (4)访存(MEM)

        (5)写回(RegWr)

        将每一级操作抽象为CPU中的若干个模块:

                (1)指令读取模块(指令存储器)

                (2)指令寄存器(IR)

                (3)数据寄存器(rs,rt,rd)

                (4)逻辑运算器件(ALU)

                (5)数据存储器

                (6)控制单元

2.实验要求

        MIPS指令集三种指令:

        R型指令

                汇编代码格式:op rd,rs,rt

                机器中存储:

                

                含义:[rs]+[rt]  \rightarrow [rd]

         I型指令:

                汇编代码格式:op rt,rs,imm16

                机器中存储:

                

                含义:[rs]+imm16 \rightarrow [rt] 

        J型指令:  

                汇编代码格式:op imm26

                机器中存储:

                

                需要注意的是,这里的跳转地址为: PC高四位+imm26+00   ,构成了32的地址

                来看下MIPS指令集:

MIPS指令集单周期CPU兼Verilog学习_第1张图片

        来看一下整体的数据通路:

MIPS指令集单周期CPU兼Verilog学习_第2张图片

MIPS指令集单周期CPU兼Verilog学习_第3张图片


3.代码实现        

         看上去非常复杂,我们把每个元件单拎出来看输入和输出:

            1)符号扩展单元Extender

                   符号扩展单元看起来比较简单,它的作用:

                            (1)将imm16符号扩展至32位后送至ALU

                MIPS指令集单周期CPU兼Verilog学习_第4张图片               

                   ExtOp=\left\{\begin{matrix} 0 &,ZeroExt& \\ 1&,SignExt \end{matrix}\right.

              input1:[15:0] imm16,           input2:ExtOp

              output:[31:0] imm32

        扩展器模块代码如下(extender.v)         

module extender(
    input [15:0] imm16,
    input ExtOp,
    output [31:0] imm32
    );

    //ExtOp 为 0 做零扩展,为 1 做符号扩展
    //imm16是以补码储存在机器中的
 
    assign imm32 = {imm16[15],{16{1'b0}},imm16[14:0]}; 

    
endmodule

     进行一下简单的仿真(extender_tb.v)

module extender_tb();
    reg [15:0] imm16;
    reg ExtOp;
    wire [31:0] imm32;
    
    initial begin
        imm16 = 16'b1111111111111111;
        ExtOp = 1;
    end
    
    extender test(imm16,ExtOp,imm32);
    
endmodule

          11...11经过符号扩展后变成了10...0011...111,观察仿真波形:

MIPS指令集单周期CPU兼Verilog学习_第5张图片 扩展器完成!

           2)pc模块

                  pc的输入输出:input1:pc_new(经过+4的pc 或者 跳转地址)

                                            input2:clk(在板子上是手动的按键/上升沿触发)

                                            input3:reset(pc复位信号,由板子上的SW0给出)

                                            output1:pc_out(输出到InsMem中)

                                            output2:pc_plus(经过+4的pc,这样可以节省一个专门pc+4器件)  

                   pc模块参考代码(pc.v): 注:这里的pc_out设置一个初始值0

`timescale 1ns / 1ps

module pc(
    input [31:0] pc_in,
    input clk,
    input reset,
    output reg[31:0] pc_out,   //输出到mem进行取指
    output [31:0] pc_plus   //经过+4的pc
    );
    
    initial begin
        pc_out = 0;
    end
    
    always @(posedge clk) begin
        if(reset == 0) begin
            pc_out=pc_in;
       end 
       else begin
            pc_out=0;
       end
    end
    
    assign pc_plus = pc_out + 4;
    
endmodule

         pc模块测试用的仿真文件(pc_tb.v):

module pc_tb();
    reg clk;
    reg[31:0] pc_in;
    reg reset;
    wire[31:0] pc_out;
    wire[31:0] pc_plus;
    
    initial begin
        clk=0;
        pc_in=0;
        reset=0;
    end
    
    always @(*) begin
            #5 clk <= ~clk;
        end
    
    pc pc_test(pc_in,clk,reset,pc_out,pc_plus);

endmodule

               pc和自增模块完成!

       3)指令存储器模块(InsMem)

                功能:根据输入的pc,在存储器中找到pc所指向的那条指令后,将其发送给各个部件。

                输入:input1:pc

                           output:经过拆解过的指令

                注:(1)存储器的指令写入要在模块中实现而不是在仿真中实现

                       (2)将存储器设计为32位的寄存器组而不是8位的寄存器组有一个好处:当读入16进制的文件时,8位的寄存器会两个两个数据读,因此在读入单条(正常顺序)                            的指令时,顺序会错乱。比如:

                           MIPS指令集单周期CPU兼Verilog学习_第6张图片

                         这时8位寄存器组的存储内容会为:0111_1000_0101_0110_0011_0100_ 0001_0010

                         这样做指令分割的时候会非常麻烦。

                下面来看下InsMem模块的代码(InsMem.v):


module InsMem(
    input [31:0]addr,   //即pc值
    output [5:0]op,     //31:26
    output [4:0]rs,     //25:21
    output [4:0]rt,     //20:16
    output [4:0]rd,     //15:11
    output [4:0]shamt,  //10:6
    output [5:0]func    //5:0
    
    );
    
    reg [31:0] mem [63:0];  //最多可存64条指令
    initial begin
        $readmemh("D:/meiyong/testdata.txt",mem);
    end
    
    assign op = mem[addr >> 2][31:26];      //这里用的是32位的指令寄存器组,因此pc要除以4
    assign rs = mem[addr >> 2][25:21];
    assign rt = mem[addr >> 2][20:16];
    assign rd = mem[addr >> 2][15:11];
    assign shamt = mem[addr >> 2][10:6];
    assign func = mem[addr >> 2][5:0];
    
    
endmodule

                写个仿真测试一下(test_insmem_tb.v):

module test_insmem_tb( );
    reg [31:0] addr;
    wire [5:0]op;     //31:26
    wire [4:0]rs;     //25:21
    wire [4:0]rt;     //20:16
    wire [4:0]rd;     //15:11
    wire [4:0]shamt;  //10:6
    wire [5:0]func;
    
    InsMem tset_insmem(addr,op,rs,rt,rd,shamt,func);
    
    initial begin
        addr = 0;
    end
    
endmodule

                  检验一下输出波形:

MIPS指令集单周期CPU兼Verilog学习_第7张图片                                                                                      

               注:第一条指令是12345678

        4)数据存储器模块(dataMem)

                数据存储器也跟指令存储器一样采用32位的寄存器组来实现。

                输入:访问/写入地址,写入的数据,写使能信号Wr。

                输出:读出的数据

                数据存储器模块代码(dataMem.v):

`timescale 1ns / 1ps

module dataMem(
    input clk,
    input [31:0] dataAdd,
    input [31:0] dataIn,
    input dataWr,
    output reg[31:0] dataOut
    );
    
    integer i;
    reg [31:0] mem [511:0];
    
    initial begin 
        for(i=0;i<512;i=i+1) begin
            mem[i] <= 0;
        end
    end
    
    always @(posedge clk) begin 
        if(dataWr == 1) begin
            mem[dataAdd>>2] <= dataIn; 
        end
    end
    
    always @(*) begin
        dataOut <= mem[dataAdd>>2]; 
    end
endmodule

        

          5)数据寄存器组模块(Register)

                寄存器组内有32个32位的通用寄存器,通过rs、rt、rd来指定访问的是哪个寄存器。

                输入:input1:clk        input2:rs,rt,rd        input3:distSel(写哪个寄存器,rt还是rd)        input4:RegWr        input5:将写入rd的dataIn

                输出:两条线out1和out2

                数据寄存器模块源代码(Register.v):

module Register(
    input clk,
    input [4:0]rs,
    input [4:0]rt,
    input [4:0]rd,
    input distSel,  //写入rt还是rd,0写rt,1写rd
    input RegWr,
    input [31:0]dataIn,
    output reg[31:0]out1,
    output reg[31:0]out2
    );
    
    reg [31:0] Reg[31:0];   //32个通用寄存器
    
    integer i;
    //对寄存器初始化
    initial begin
        for (i = 0; i < 32; i = i+ 1) Reg[i] <= 0;  
    end
    
    always @(posedge clk) begin
        if(RegWr == 1) begin 
              case(distSel) 
                0: Reg[rt] = dataIn;  //写rt
                1: Reg[rd] = dataIn; //写rd
              endcase       
        end
    end
    
    always @(*) begin
        out1 <= Reg[rs];
        out2 <= Reg[rt];
    end
    
endmodule

                测试用的仿真代码(Reg_test_tb.v): //这里把Register中Reg的初始化改成了 Reg[i] = i ;

module Reg_test_tb( );
    reg clk;
    reg [4:0]rs;
    reg [4:0]rt;
    reg [4:0]rd;
    reg distSel;
    reg RegWr;
    reg [31:0]dataIn;
    wire [31:0]out1;
    wire [31:0]out2;
    
    Register myReg(clk,rs,rt,rd,distSel,RegWr,dataIn,out1,out2);
    
    initial begin
        clk=0;
        rs=5'b00101;
        rt=5'b00110;
        rd=5'b00111;
        distSel=1;   
        RegWr=0;
        dataIn=0;
    end
    
    always @(*)  begin
        #5 clk <= ~clk;
    end
    
endmodule

                out1和out2的波形如下:

MIPS指令集单周期CPU兼Verilog学习_第8张图片

         6)运算单元模块(ALU)

                这是和控制单元一样最为复杂的模块,先来看看需要实现多少个函数:

MIPS指令集单周期CPU兼Verilog学习_第9张图片MIPS指令集单周期CPU兼Verilog学习_第10张图片

         虽然有20(21)个函数,但是总结起来,ALU部件要用的也就9种操作,因此ALUop码只需要四位(0000~1000)。

ALUop 功能 涉及到的指令

0000

两数相加 add,addi
0001 两数相减 sub,subi
0010 按位与 and,andi
0011 按位或 or,ori
0100 按位异或 xor,xori
0101 逻辑右移(直接移) srl
0110 逻辑左移(直接移) sll
0111 算术右移(补符号位) sra
1000 比较是否相等 beq,bne
1001 设置高位 lui

               注意区分算术移位和逻辑移位。

                逻辑移位:直接移位,空的地方补0。

                算术右移:空出的位全部补符号位。

                运算器模块代码(ALU.v):

`timescale 1ns / 1ps



module ALU(
        input [3:0]ALUop,
        input [31:0]in1,    //可能是rs或者shamt
        input [31:0]in2,    //可能是rt或者imm16
        output reg zero,    //用来指示beq是否相等,1相等,0不相等
        output reg[31:0] res
    );
    
     integer i;
     
    
    always @(*) begin 
        case (ALUop)
            //求和
            4'b0000: begin 
                res = in1 + in2;  
                zero = 0; 
            end
            //求差
            4'b0001: begin
                res = in1 - in2;
            end
            //按位与
            4'b0010: begin
                res = in1 & in2;
            end
            //按位或
            4'b0011: begin 
                res = in1 | in2;
            end
            //按位异或
            4'b0100: begin
                res = in1 ^ in2;
            end
            //直接右移,in1是shamt,in2是rt
            4'b0101: begin
                res = in2 >> in1[4:0]; 
            end
            //直接左移
            4'b0110:begin
                res = in2 << in1[4:0];
            end
            //补符号位右移
            4'b0111: begin
                res = in2 >> in1[4:0];
                if(in2[31]==1'b1) begin
                    for(i=0;i

                测试一下算术右移功能(ALU_test_tb.v):

module ALU_test_tb();
    reg[3:0] ALUop;
    reg[31:0] in1;
    reg[31:0] in2;
    wire zero;
    wire[31:0] res;
    
    initial begin
        ALUop = 4'b0111;
        in1 = 5'b00100;
        in2 = 32'hf1234567;
    end
    
    ALU testALU(ALUop,in1,in2,zero,res);
    
endmodule

      7)pc选择(PCselect)

               该模块用一个四选一的数据选择器来实现,输出的是pc的下一个值,即下一步要运行指的令的地址

               输入的四个信号分别为:

序号 功能 所服务的指令
0 正常进行下一条指令 正常指令

1

beq或bne指令生效所跳转到的指令地址 beq,bne
2 无条件跳转 j
3 跳转到rs内的值 jr

                jr指令:jr rs        含义:rs寄存器中存有下条指令的地址,pc改为rs内存的值。

                PC选择器模块代码(PCselect.v):

`timescale 1ns / 1ps

//本模块用来选择最后的pc
module PCselect(
    input [31:0]addedPC,    //加过4的PC
    input [31:0]ex_imm32,
    input [25:0]jAddr,
    input [31:0]jr_rs,
    input [1:0]sel,
    output reg[31:0]finalPC
);

    always@(*) begin
        case (sel) 
            0: finalPC <= addedPC;  //正常执行下一条指令
            1: finalPC <= addedPC+(ex_imm32<<2); //beq或者bne跳转指令生效
            2: finalPC <= {addedPC[31:28],jAddr[25:0],0,0}; //无条件跳转指令
            3: finalPC <= jr_rs;
        endcase
    end
    
endmodule

      8)控制单元(control)

                输入:指令的op和funct码,ALU的zero(判断rs、rt,0不相等,1相等)

                输出:(1)PC的reset         (2)PCsel的选择信号,选择下条指令地址                                                                                                                                                                                     (3)ALU要进行的操作ALUop         (4)reg的写信号RegWr;选择哪个寄存器reg_distSel;进入寄存器的是ALUresult还是从数据存储器来的信号:regIn_sel                                 (5)ALU的两个输入ALUin1_sel, ALUin2_sel:第一个选rs还是shamt , 第二个选rt还是imm32.                                                                                                                               (6)dataMem的写信号memWr.

                控制模块源代码(control.v):

`timescale 1ns / 1ps
 
module control(
    input [5:0] op,
    input [5:0] funct,
    input zero,
 //   input PC_reset,
    output reg[3:0]ALUop,
    output reg[1:0]PCsel,
    output reg reg_distSel,
    output reg regWr,
    output reg dataWr,
    output reg ALUin1_sel,  //选rs还是shamt,0是rs,1是shamt
    output reg ALUin2_sel,   //选rt还是imm,0是rt,1是imm
    output reg regIn_sel    //选ALUout还是dataMem_out,0是ALUout,1是dataMem_out
    );
    
    
    always @(*) begin
        case(op)
             //r型指令
            6'b000000:begin     
                case(funct)
                    //add
                    6'b100000:begin
     //                   PC_reset <= 0;
                        ALUop <= 4'b0000;
                        PCsel <= 2'b00;
                        reg_distSel <= 1;
                        regWr <= 1;
                        dataWr <= 0;
                        ALUin1_sel <= 0;
                        ALUin2_sel <= 0;
                        regIn_sel <= 0;
                    end 
                    //sub
                    6'b100010:begin
             //           PC_reset <= 0;
                        ALUop <= 4'b0001;
                        PCsel <= 2'b00;
                        reg_distSel <= 1;
                        regWr <= 1;
                        dataWr <= 0;
                        ALUin1_sel <= 0;
                        ALUin2_sel <= 0;
                        regIn_sel <= 0;
                    end
                    //and
                    6'b100100:begin
              //          PC_reset <= 0;
                        ALUop <= 4'b0010;
                        PCsel <= 2'b00;
                        reg_distSel <= 1;
                        regWr <= 1;
                        dataWr <= 0;
                        ALUin1_sel <= 0;
                        ALUin2_sel <= 0;
                        regIn_sel <= 0;
                    end
                    //or
                    6'b100101:begin
         //               PC_reset <= 0;
                        ALUop <= 4'b0011;
                        PCsel <= 2'b00;
                        reg_distSel <= 1;
                        regWr <= 1;
                        dataWr <= 0;
                        ALUin1_sel <= 0;
                        ALUin2_sel <= 0;
                        regIn_sel <= 0;
                    end
                    //xor
                    6'b100110:begin
            //            PC_reset <= 0;
                        ALUop <= 4'b0100;
                        PCsel <= 2'b00;
                        reg_distSel <= 1;
                        regWr <= 1;
                        dataWr <= 0;
                        ALUin1_sel <= 0;
                        ALUin2_sel <= 0;
                        regIn_sel <= 0;
                    end
                    //sll
                    6'b000000:begin
             //           PC_reset <= 0;
                        ALUop <= 4'b0110;
                        PCsel <= 2'b00;
                        reg_distSel <= 1;
                        regWr <= 1;
                        dataWr <= 0;
                        ALUin1_sel <= 1;
                        ALUin2_sel <= 0;
                        regIn_sel <= 0;
                    end
                    //srl
                    6'b000010:begin
          //              PC_reset <= 0;
                        ALUop <= 4'b0101;
                        PCsel <= 2'b00;
                        reg_distSel <= 1;
                        regWr <= 1;
                        dataWr <= 0;
                        ALUin1_sel <= 1;
                        ALUin2_sel <= 0;
                        regIn_sel <= 0;
                    end
                    //sra
                    6'b000011:begin
               //         PC_reset <= 0;
                        ALUop <= 4'b0111;
                        PCsel <= 2'b00;
                        reg_distSel <= 1;
                        regWr <= 1;
                        dataWr <= 0;
                        ALUin1_sel <= 1;
                        ALUin2_sel <= 0;
                        regIn_sel <= 0;
                    end
                    //jr
                    6'b001000:begin
                //        PC_reset <= 0;
                        ALUop <= 4'b0111;   //无所谓
                        PCsel <= 2'b11; //PC选择rs的内容
                        reg_distSel <= 0;
                        regWr <= 0;
                        dataWr <= 0;
                        ALUin1_sel <= 0;
                        ALUin2_sel <= 0;
                        regIn_sel <= 0;
                    end
                endcase
            end
            //下面是I型指令  
            //addi
            6'b001000:begin
     //           PC_reset <= 0;
                ALUop <= 4'b0000;
                PCsel <= 2'b00;
                reg_distSel <= 0;
                regWr <= 1;
                dataWr <= 0;
                ALUin1_sel <= 0;
                ALUin2_sel <= 1;
                regIn_sel <= 0;
            end
            //andi
            6'b001100:begin
     //           PC_reset <= 0;
                ALUop <= 4'b0001;
                PCsel <= 2'b00;
                reg_distSel <= 0;
                regWr <= 1;
                dataWr <= 0;
                ALUin1_sel <= 0;
                ALUin2_sel <= 1;
                regIn_sel <= 0;
            end
            //ori
            6'b001101:begin
          //      PC_reset <= 0;
                ALUop <= 4'b0011;
                PCsel <= 2'b00;
                reg_distSel <= 0;
                regWr <= 1;
                dataWr <= 0;
                ALUin1_sel <= 0;
                ALUin2_sel <= 1;
                regIn_sel <= 0;
            end
            //xori
            6'b001110:begin
       //         PC_reset <= 0;
                ALUop <= 4'b0100;
                PCsel <= 2'b00;
                reg_distSel <= 0;
                regWr <= 1;
                dataWr <= 0;
                ALUin1_sel <= 0;
                ALUin2_sel <= 1;
                regIn_sel <= 0;
            end
            //lw
            6'b100011:begin
       //         PC_reset <= 0;
                ALUop <= 4'b0000;
                PCsel <= 2'b00;
                reg_distSel <= 0;
                regWr <= 1;
                dataWr <= 0;
                ALUin1_sel <= 0;
                ALUin2_sel <= 1;
                regIn_sel <= 1;
            end
            //sw
            6'b101011:begin
       //         PC_reset <= 0;
                ALUop <= 4'b0000;
                PCsel <= 2'b00;
                reg_distSel <= 0;
                regWr <= 0;
                dataWr <= 1;
                ALUin1_sel <= 0;
                ALUin2_sel <= 1;
                regIn_sel <= 0;
            end
            //beq
            6'b000100:begin
         //       PC_reset <= 0;
                ALUop <= 4'b1000;
                reg_distSel <= 0;
                regWr <= 0;
                dataWr <= 0;
                ALUin1_sel <= 0;
                ALUin2_sel <= 1;
                regIn_sel <= 0;
                if(zero == 1) //1表示相等,要跳转
                    PCsel <= 2'b01;
                else 
                    PCsel <= 2'b00;
            end
            //bne
            6'b000101:begin
        //        PC_reset <= 0;
                ALUop <= 4'b1000;
                reg_distSel <= 0;
                regWr <= 0;
                dataWr <= 0;
                ALUin1_sel <= 0;
                ALUin2_sel <= 1;
                regIn_sel <= 0;
                if(zero == 0)
                    PCsel <= 2'b01;
                else 
                    PCsel <= 2'b00;
            end
            //lui,设置rt寄存器的高十六位,后面是16个0
            6'b001111: begin
     //           PC_reset <= 0;
                ALUop <= 4'b1001; 
                PCsel <= 2'b00;  
                reg_distSel <= 0;
                regWr <= 1;
                dataWr <= 0;
                ALUin1_sel <= 0;
                ALUin2_sel <= 1;
                regIn_sel <= 0;
            end
            //j
            6'b000010: begin
      //          PC_reset <= 0;
                ALUop <= 4'b1001;   //无所谓
                reg_distSel <= 0;   //无所谓
                PCsel <= 2'b10;
                regWr <= 0;
                dataWr <= 0;
                ALUin1_sel <= 0;    //无所谓
                ALUin2_sel <= 1;    //无所谓
                regIn_sel <= 0;     //无所谓
            end
        endcase
    end
    
endmodule

            这个模块不设置仿真,因为要需要调用很多其他模块。

        9)顶层仿真

                这个仿真文件是用来统筹所有其他的模块并且进行运行MIPS指令。这里还未写顶层模块

                下面直接贴上仿真代码(main_tb.v):

`timescale 1ns / 1ps

module main_tb( );
    reg clk;  
    wire pc_reset;  wire push;  wire [31:0]pc_out;  wire [31:0]pc_in;  wire[31:0] plused_pc;
    pc my_pc(pc_in,clk,pc_reset,pc_out,plused_pc);
    
    wire [5:0]op;  wire [4:0]rs; wire [4:0]rt;  wire [4:0]rd;  wire [4:0]shamt;  wire [5:0]funct;  wire [31:0]imm32;
    InsMem my_Insmem(pc_out,op,rs,rt,rd,shamt,funct);   extender my_extender({rd,shamt,funct},imm32);
    
    wire ctrl_distReg; wire [31:0]reg_dataIn;  wire RegWr;  wire [31:0]reg_out1;  wire [31:0]reg_out2;
    Register my_Register(clk, rs, rt, rd, ctrl_distReg, RegWr, reg_dataIn, reg_out1, reg_out2);
    
    wire [31:0]ALU_in1;  wire[31:0]ALU_in2;  wire ALUsel_in1;  wire ALUsel_in2;
    dataSel_2 ALU1(reg_out1,shamt,ALUsel_in1,ALU_in1);  dataSel_2 ALU2(reg_out2,imm32,ALUsel_in2,ALU_in2);
    
    wire [3:0]ALUctrl;  wire ALU_zero;  wire [31:0]ALU_out;
    ALU my_ALU(ALUctrl,ALU_in1,ALU_in2,ALU_zero,ALU_out);
    
    wire dataWr;  wire [31:0]dataOut;
    dataMem mt_dataMem(clk,ALU_out,reg_out2,dataWr,dataOut);
    wire regIn_sel_wire;
    dataSel_2 regIn_sel(ALU_out,dataOut,regIn_sel_wire,reg_dataIn);
    
    wire [1:0]pcSel;
    PCselect my_PCselect(plused_pc,imm32,{rs,rt,rd,shamt,funct},reg_out1,pcSel,pc_in);
    
    control my_control(op,funct,ALU_zero,pc_reset,ALUctrl,pcSel,ctrl_distReg,RegWr,dataWr,ALUsel_in1,ALUsel_in2,regIn_sel_wire);
    
   initial begin
        clk=0;

   end


    always @(*) begin
        #5 clk <= ~clk;
    end
       
endmodule

        在testdata.txt中写入几行指令来测试CPU是否能正常工作。

MIPS指令集单周期CPU兼Verilog学习_第11张图片

                经过测试后观察波形,这些指令都能够正常运行。

MIPS指令集单周期CPU兼Verilog学习_第12张图片

MIPS指令集单周期CPU兼Verilog学习_第13张图片

        测试过后,将顶层写成一个模块,然后将程序烧入CPU中。

        顶层模块代码(top.v):

`timescale 1ns / 1ps
//结合所有CPU器件的模块,但还没有通过数码管进行输出
module top(
    input push,
    input clk_7seg,
    input [1:0]SW,
    output [11:0]display,
 //   input clk,
    input pc_reset
//    output  effective_clk
    
    );
    wire [31:0]pc_out;
    wire [31:0]pc_in;
    wire [31:0]plused_pc;
    wire [5:0]op;
    wire  [4:0]rs;
    wire [4:0]rt;
    wire [4:0]rd;
    wire [4:0]shamt;
    wire [5:0]funct;
    wire [31:0]imm32;
    wire  ctrl_distReg;
    wire [31:0]reg_dataIn;
    wire RegWr;
    wire [31:0]reg_out1;
    wire [31:0]reg_out2;
    wire   [31:0]ALU_in1;
    wire  [31:0]ALU_in2;
    wire   ALUsel_in1;
    wire  ALUsel_in2;
    wire [3:0]ALUctrl;
    wire  ALU_zero;
    wire  [31:0]ALU_out;
    wire  dataWr;
    wire [31:0]dataOut;
    wire regIn_sel_wire;
    wire  [1:0]pcSel;
   
    wire effective_clk;
    wire [31:0]extended_shamt;
    
    clk_dura my_clkdura(clk_7seg,push,effective_clk);
    
    extend5 shamt_ex(shamt,extended_shamt);
    
    pc my_pc(pc_in,effective_clk,pc_reset,pc_out,plused_pc);
    
    InsMem my_Insmem(pc_out,op,rs,rt,rd,shamt,funct);   extender my_extender({rd,shamt,funct},imm32);
    Register my_Register(effective_clk, rs, rt, rd, ctrl_distReg, RegWr, reg_dataIn, reg_out1, reg_out2);
    
    dataSel_2 ALU1(reg_out1,extended_shamt,ALUsel_in1,ALU_in1);  dataSel_2 ALU2(reg_out2,imm32,ALUsel_in2,ALU_in2);
    ALU my_ALU(ALUctrl,ALU_in1,ALU_in2,ALU_zero,ALU_out);
    dataMem mt_dataMem(effective_clk,ALU_out,reg_out2,dataWr,dataOut);
    dataSel_2 regIn_sel(ALU_out,dataOut,regIn_sel_wire,reg_dataIn);
    PCselect my_PCselect(plused_pc,imm32,{rs,rt,rd,shamt,funct},reg_out1,pcSel,pc_in);
        
    control my_control(op,funct,ALU_zero,ALUctrl,pcSel,ctrl_distReg,RegWr,dataWr,ALUsel_in1,ALUsel_in2,regIn_sel_wire);

    _7seg my_7seg(clk_7seg,SW,pc_out,pc_in,rs,reg_out1,rt,reg_out2,ALU_out,reg_dataIn,display);
endmodule

                之前顶层模块把所有参数都写进了模块的参数列表(即input,output)中,但在约束文件中并未将他们接至引脚上,因此会造成输出悬空的现象,在进行硬件implementation会报错如下:

        顶层模块仿真(top_test_tb.v):

`timescale 1ns / 1ps

module top_test_tb();
    reg push;
    reg clk_7seg;
    reg [1:0]SW;
    reg pc_reset;
    
    wire [11:0]display;
//    wire effective_clk;

    
    top test_top(push,clk_7seg,SW,display,pc_reset);
                 
    initial begin
        push = 0;
        clk_7seg = 0;
        SW = 0;
        pc_reset = 0;
    end
    
    always @(clk_7seg) begin
        #5 clk_7seg <=  ~clk_7seg;
    end
    
    always @(push) begin
        #80 push <= ~push;
    end
    
    
endmodule

        指令文件(test.txt):

20010008    //add $1,$0,8
34020002    //ori $2,$0,2
00411820    //add $3,$2,$1
00622822    //sub $5,$3,$2
00a22024    //and $4,$5,$2
00824025    //or $8,$4,$2
00084040    //sll $8,$8,1
ac080004    //sw $8,4($0)
8c090004    //lw $9,4($0)

        0~2条指令波形(pc:00~08):

MIPS指令集单周期CPU兼Verilog学习_第14张图片MIPS指令集单周期CPU兼Verilog学习_第15张图片MIPS指令集单周期CPU兼Verilog学习_第16张图片

         3~5条指令波形(pc:0C~14):

MIPS指令集单周期CPU兼Verilog学习_第17张图片MIPS指令集单周期CPU兼Verilog学习_第18张图片MIPS指令集单周期CPU兼Verilog学习_第19张图片

         6~8条指令(pc:18~20):

MIPS指令集单周期CPU兼Verilog学习_第20张图片MIPS指令集单周期CPU兼Verilog学习_第21张图片MIPS指令集单周期CPU兼Verilog学习_第22张图片

 3.CPU烧板

        本实验还有在basys3板子上展示的要求,要求如下:

MIPS指令集单周期CPU兼Verilog学习_第23张图片

         七段数码管

                为了在数码管上显示,要写一个七段数码管显示的模块,通过当前的pc,rs,rt,ALU_out值来进行显示。

                该模块代码(_7seg.v):

`timescale 1ns / 1ps

module _7seg(
    input clk_7seg,
    input [1:0]SW,  //(sw15,sw14)
    input [31:0]pc_now, //当前pc值
    input [31:0]pc_next,    //下条pc值
    
    input [4:0]rs,  //rs寄存器的编号
    input [31:0]reg_out1,   //rs寄存器的内容
    
    input [4:0]rt,  //rt寄存器的编号
    input [31:0]reg_out2,   //rt寄存器的内容
    
    input [31:0]ALU_out,    //ALU结果
    input [31:0]dataOut,    //DB总线
    
    output reg[11:0] display
    
    );
    
    //count == T1MS 用来分频
    reg [19:0] count = 0;
    reg [2:0] sel = 0;
    parameter T1MS = 50000;
    always @(posedge clk_7seg) begin
        count <= count+1;
        if(count == T1MS) begin
            count <= 0;
            if(sel==3) sel<=0;
            else sel <= sel+1;
        end
    end
    
    always @(posedge clk_7seg) begin
        case(SW) 
            //pc
            0: begin
                case(sel)
                    0: begin
                        display[11:8] <= 4'b0111;
                        //第一位输出
                        case(pc_now[7:4])
                            4'b0000: display[7:0] <= 8'b1100_0000; 
                            4'b0001: display[7:0] <= 8'b1111_1001;
                            4'b0010: display[7:0] <= 8'b1010_0100;
                            4'b0011: display[7:0] <= 8'b1011_0000;
                            4'b0100: display[7:0] <= 8'b1001_1001;
                            4'b0101: display[7:0] <= 8'b1001_0010;
                            4'b0110: display[7:0] <= 8'b1000_0010;
                            4'b0111: display[7:0] <= 8'b1101_1000;
                            4'b1000: display[7:0] <= 8'b1000_0000;
                            4'b1001: display[7:0] <= 8'b1001_0000;
                            4'b1010: display[7:0] <= 8'b1000_1000;
                            4'b1011: display[7:0] <= 8'b1000_0011;
                            4'b1100: display[7:0] <= 8'b1100_0110;
                            4'b1101: display[7:0] <= 8'b1010_0001;
                            4'b1110: display[7:0] <= 8'b1000_0110;
                            4'b1111: display[7:0] <= 8'b1000_1110;
                            default : display[7:0] = 8'b1111_1111; //全灭
                         endcase
                    end
                    1: begin
                        display[11:8] <= 4'b1011;
                        //第二位输出
                        case(pc_now[3:0])
                            4'b0000: display[7:0] <= 8'b1100_0000; 
                            4'b0001: display[7:0] <= 8'b1111_1001;
                            4'b0010: display[7:0] <= 8'b1010_0100;
                            4'b0011: display[7:0] <= 8'b1011_0000;
                            4'b0100: display[7:0] <= 8'b1001_1001;
                            4'b0101: display[7:0] <= 8'b1001_0010;
                            4'b0110: display[7:0] <= 8'b1000_0010;
                            4'b0111: display[7:0] <= 8'b1101_1000;
                            4'b1000: display[7:0] <= 8'b1000_0000;
                            4'b1001: display[7:0] <= 8'b1001_0000;
                            4'b1010: display[7:0] <= 8'b1000_1000;
                            4'b1011: display[7:0] <= 8'b1000_0011;
                            4'b1100: display[7:0] <= 8'b1100_0110;
                            4'b1101: display[7:0] <= 8'b1010_0001;
                            4'b1110: display[7:0] <= 8'b1000_0110;
                            4'b1111: display[7:0] <= 8'b1000_1110;
                            default : display[7:0] = 8'b1111_1111; //全灭
                         endcase
                    end
                    2: begin
                        display[11:8] <= 4'b1101;
                        //第三位输出
                        case(pc_next[7:4])
                            4'b0000: display[7:0] <= 8'b1100_0000; 
                            4'b0001: display[7:0] <= 8'b1111_1001;
                            4'b0010: display[7:0] <= 8'b1010_0100;
                            4'b0011: display[7:0] <= 8'b1011_0000;
                            4'b0100: display[7:0] <= 8'b1001_1001;
                            4'b0101: display[7:0] <= 8'b1001_0010;
                            4'b0110: display[7:0] <= 8'b1000_0010;
                            4'b0111: display[7:0] <= 8'b1101_1000;
                            4'b1000: display[7:0] <= 8'b1000_0000;
                            4'b1001: display[7:0] <= 8'b1001_0000;
                            4'b1010: display[7:0] <= 8'b1000_1000;
                            4'b1011: display[7:0] <= 8'b1000_0011;
                            4'b1100: display[7:0] <= 8'b1100_0110;
                            4'b1101: display[7:0] <= 8'b1010_0001;
                            4'b1110: display[7:0] <= 8'b1000_0110;
                            4'b1111: display[7:0] <= 8'b1000_1110;
                            default : display[7:0] = 8'b1111_1111; //全灭
                         endcase
                    end
                    3: begin
                        display[11:8] <= 4'b1110;
                        //第四位输出
                        case(pc_next[3:0])
                            4'b0000: display[7:0] <= 8'b1100_0000; 
                            4'b0001: display[7:0] <= 8'b1111_1001;
                            4'b0010: display[7:0] <= 8'b1010_0100;
                            4'b0011: display[7:0] <= 8'b1011_0000;
                            4'b0100: display[7:0] <= 8'b1001_1001;
                            4'b0101: display[7:0] <= 8'b1001_0010;
                            4'b0110: display[7:0] <= 8'b1000_0010;
                            4'b0111: display[7:0] <= 8'b1101_1000;
                            4'b1000: display[7:0] <= 8'b1000_0000;
                            4'b1001: display[7:0] <= 8'b1001_0000;
                            4'b1010: display[7:0] <= 8'b1000_1000;
                            4'b1011: display[7:0] <= 8'b1000_0011;
                            4'b1100: display[7:0] <= 8'b1100_0110;
                            4'b1101: display[7:0] <= 8'b1010_0001;
                            4'b1110: display[7:0] <= 8'b1000_0110;
                            4'b1111: display[7:0] <= 8'b1000_1110;
                            default : display[7:0] = 8'b1111_1111; //全灭
                         endcase
                    end
                endcase
            end
            //rs
            1: begin
                  case(sel)
                      0: begin
                          display[11:8] <= 4'b0111;
                          //第一位输出
                          case(rs[4])
                              0: display[7:0] <= 8'b1100_0000; 
                              1: display[7:0] <= 8'b1111_1001;
                          
                              default : display[7:0] = 8'b1111_1111; //全灭
                           endcase
                      end
                      1: begin
                          display[11:8] <= 4'b1011;
                          //第二位输出
                          case(rs[3:0])
                              4'b0000: display[7:0] <= 8'b1100_0000; 
                              4'b0001: display[7:0] <= 8'b1111_1001;
                              4'b0010: display[7:0] <= 8'b1010_0100;
                              4'b0011: display[7:0] <= 8'b1011_0000;
                              4'b0100: display[7:0] <= 8'b1001_1001;
                              4'b0101: display[7:0] <= 8'b1001_0010;
                              4'b0110: display[7:0] <= 8'b1000_0010;
                              4'b0111: display[7:0] <= 8'b1101_1000;
                              4'b1000: display[7:0] <= 8'b1000_0000;
                              4'b1001: display[7:0] <= 8'b1001_0000;
                              4'b1010: display[7:0] <= 8'b1000_1000;
                              4'b1011: display[7:0] <= 8'b1000_0011;
                              4'b1100: display[7:0] <= 8'b1100_0110;
                              4'b1101: display[7:0] <= 8'b1010_0001;
                              4'b1110: display[7:0] <= 8'b1000_0110;
                              4'b1111: display[7:0] <= 8'b1000_1110;
                              default : display[7:0] = 8'b1111_1111; //全灭
                           endcase
                      end
                      2: begin
                          display[11:8] <= 4'b1101;
                          //第三位输出
                          case(reg_out1[7:4])
                              4'b0000: display[7:0] <= 8'b1100_0000; 
                              4'b0001: display[7:0] <= 8'b1111_1001;
                              4'b0010: display[7:0] <= 8'b1010_0100;
                              4'b0011: display[7:0] <= 8'b1011_0000;
                              4'b0100: display[7:0] <= 8'b1001_1001;
                              4'b0101: display[7:0] <= 8'b1001_0010;
                              4'b0110: display[7:0] <= 8'b1000_0010;
                              4'b0111: display[7:0] <= 8'b1101_1000;
                              4'b1000: display[7:0] <= 8'b1000_0000;
                              4'b1001: display[7:0] <= 8'b1001_0000;
                              4'b1010: display[7:0] <= 8'b1000_1000;
                              4'b1011: display[7:0] <= 8'b1000_0011;
                              4'b1100: display[7:0] <= 8'b1100_0110;
                              4'b1101: display[7:0] <= 8'b1010_0001;
                              4'b1110: display[7:0] <= 8'b1000_0110;
                              4'b1111: display[7:0] <= 8'b1000_1110;
                              default : display[7:0] = 8'b1111_1111; //全灭
                           endcase
                      end
                      3: begin
                          display[11:8] <= 4'b1110;
                          //第四位输出
                          case(reg_out1[3:0])
                              4'b0000: display[7:0] <= 8'b1100_0000; 
                              4'b0001: display[7:0] <= 8'b1111_1001;
                              4'b0010: display[7:0] <= 8'b1010_0100;
                              4'b0011: display[7:0] <= 8'b1011_0000;
                              4'b0100: display[7:0] <= 8'b1001_1001;
                              4'b0101: display[7:0] <= 8'b1001_0010;
                              4'b0110: display[7:0] <= 8'b1000_0010;
                              4'b0111: display[7:0] <= 8'b1101_1000;
                              4'b1000: display[7:0] <= 8'b1000_0000;
                              4'b1001: display[7:0] <= 8'b1001_0000;
                              4'b1010: display[7:0] <= 8'b1000_1000;
                              4'b1011: display[7:0] <= 8'b1000_0011;
                              4'b1100: display[7:0] <= 8'b1100_0110;
                              4'b1101: display[7:0] <= 8'b1010_0001;
                              4'b1110: display[7:0] <= 8'b1000_0110;
                              4'b1111: display[7:0] <= 8'b1000_1110;
                              default : display[7:0] = 8'b1111_1111; //全灭
                           endcase
                      end
                  endcase
            end
            //rt
            2: begin
                  case(sel)
                      0: begin
                          display[11:8] <= 4'b0111;
                          //第一位输出
                          case(rt[4])
                                0: display[7:0] <= 8'b1100_0000; 
                                1: display[7:0] <= 8'b1111_1001;
                            
                              default : display[7:0] = 8'b1111_1111; //全灭
                           endcase
                      end
                      1: begin
                          display[11:8] <= 4'b1011;
                          //第二位输出
                          case(rt[3:0])
                              4'b0000: display[7:0] <= 8'b1100_0000; 
                              4'b0001: display[7:0] <= 8'b1111_1001;
                              4'b0010: display[7:0] <= 8'b1010_0100;
                              4'b0011: display[7:0] <= 8'b1011_0000;
                              4'b0100: display[7:0] <= 8'b1001_1001;
                              4'b0101: display[7:0] <= 8'b1001_0010;
                              4'b0110: display[7:0] <= 8'b1000_0010;
                              4'b0111: display[7:0] <= 8'b1101_1000;
                              4'b1000: display[7:0] <= 8'b1000_0000;
                              4'b1001: display[7:0] <= 8'b1001_0000;
                              4'b1010: display[7:0] <= 8'b1000_1000;
                              4'b1011: display[7:0] <= 8'b1000_0011;
                              4'b1100: display[7:0] <= 8'b1100_0110;
                              4'b1101: display[7:0] <= 8'b1010_0001;
                              4'b1110: display[7:0] <= 8'b1000_0110;
                              4'b1111: display[7:0] <= 8'b1000_1110;
                              default : display[7:0] = 8'b1111_1111; //全灭
                           endcase
                      end
                      2: begin
                          display[11:8] <= 4'b1101;
                          //第三位输出
                          case(reg_out2[7:4])
                              4'b0000: display[7:0] <= 8'b1100_0000; 
                              4'b0001: display[7:0] <= 8'b1111_1001;
                              4'b0010: display[7:0] <= 8'b1010_0100;
                              4'b0011: display[7:0] <= 8'b1011_0000;
                              4'b0100: display[7:0] <= 8'b1001_1001;
                              4'b0101: display[7:0] <= 8'b1001_0010;
                              4'b0110: display[7:0] <= 8'b1000_0010;
                              4'b0111: display[7:0] <= 8'b1101_1000;
                              4'b1000: display[7:0] <= 8'b1000_0000;
                              4'b1001: display[7:0] <= 8'b1001_0000;
                              4'b1010: display[7:0] <= 8'b1000_1000;
                              4'b1011: display[7:0] <= 8'b1000_0011;
                              4'b1100: display[7:0] <= 8'b1100_0110;
                              4'b1101: display[7:0] <= 8'b1010_0001;
                              4'b1110: display[7:0] <= 8'b1000_0110;
                              4'b1111: display[7:0] <= 8'b1000_1110;
                              default : display[7:0] = 8'b1111_1111; //全灭
                           endcase
                      end
                      3: begin
                          display[11:8] <= 4'b1110;
                          //第四位输出
                          case(reg_out2[3:0])
                              4'b0000: display[7:0] <= 8'b1100_0000; 
                              4'b0001: display[7:0] <= 8'b1111_1001;
                              4'b0010: display[7:0] <= 8'b1010_0100;
                              4'b0011: display[7:0] <= 8'b1011_0000;
                              4'b0100: display[7:0] <= 8'b1001_1001;
                              4'b0101: display[7:0] <= 8'b1001_0010;
                              4'b0110: display[7:0] <= 8'b1000_0010;
                              4'b0111: display[7:0] <= 8'b1101_1000;
                              4'b1000: display[7:0] <= 8'b1000_0000;
                              4'b1001: display[7:0] <= 8'b1001_0000;
                              4'b1010: display[7:0] <= 8'b1000_1000;
                              4'b1011: display[7:0] <= 8'b1000_0011;
                              4'b1100: display[7:0] <= 8'b1100_0110;
                              4'b1101: display[7:0] <= 8'b1010_0001;
                              4'b1110: display[7:0] <= 8'b1000_0110;
                              4'b1111: display[7:0] <= 8'b1000_1110;
                              default : display[7:0] = 8'b1111_1111; //全灭
                           endcase
                      end
                  endcase
            end
            //ALUout:DB数据
            3: begin
                  case(sel)
                      0: begin
                          display[11:8] <= 4'b0111;
                          //第一位输出
                          case(ALU_out[7:4])
                              4'b0000: display[7:0] <= 8'b1100_0000; 
                              4'b0001: display[7:0] <= 8'b1111_1001;
                              4'b0010: display[7:0] <= 8'b1010_0100;
                              4'b0011: display[7:0] <= 8'b1011_0000;
                              4'b0100: display[7:0] <= 8'b1001_1001;
                              4'b0101: display[7:0] <= 8'b1001_0010;
                              4'b0110: display[7:0] <= 8'b1000_0010;
                              4'b0111: display[7:0] <= 8'b1101_1000;
                              4'b1000: display[7:0] <= 8'b1000_0000;
                              4'b1001: display[7:0] <= 8'b1001_0000;
                              4'b1010: display[7:0] <= 8'b1000_1000;
                              4'b1011: display[7:0] <= 8'b1000_0011;
                              4'b1100: display[7:0] <= 8'b1100_0110;
                              4'b1101: display[7:0] <= 8'b1010_0001;
                              4'b1110: display[7:0] <= 8'b1000_0110;
                              4'b1111: display[7:0] <= 8'b1000_1110;
                              default : display[7:0] = 8'b1111_1111; //全灭
                           endcase
                      end
                      1: begin
                          display[11:8] <= 4'b1011;
                          //第二位输出
                          case(ALU_out[3:0])
                              4'b0000: display[7:0] <= 8'b1100_0000; 
                              4'b0001: display[7:0] <= 8'b1111_1001;
                              4'b0010: display[7:0] <= 8'b1010_0100;
                              4'b0011: display[7:0] <= 8'b1011_0000;
                              4'b0100: display[7:0] <= 8'b1001_1001;
                              4'b0101: display[7:0] <= 8'b1001_0010;
                              4'b0110: display[7:0] <= 8'b1000_0010;
                              4'b0111: display[7:0] <= 8'b1101_1000;
                              4'b1000: display[7:0] <= 8'b1000_0000;
                              4'b1001: display[7:0] <= 8'b1001_0000;
                              4'b1010: display[7:0] <= 8'b1000_1000;
                              4'b1011: display[7:0] <= 8'b1000_0011;
                              4'b1100: display[7:0] <= 8'b1100_0110;
                              4'b1101: display[7:0] <= 8'b1010_0001;
                              4'b1110: display[7:0] <= 8'b1000_0110;
                              4'b1111: display[7:0] <= 8'b1000_1110;
                              default : display[7:0] = 8'b1111_1111; //全灭
                           endcase
                      end
                      2: begin
                          display[11:8] <= 4'b1101;
                          //第三位输出
                          case(dataOut[7:4])
                              4'b0000: display[7:0] <= 8'b1100_0000; 
                              4'b0001: display[7:0] <= 8'b1111_1001;
                              4'b0010: display[7:0] <= 8'b1010_0100;
                              4'b0011: display[7:0] <= 8'b1011_0000;
                              4'b0100: display[7:0] <= 8'b1001_1001;
                              4'b0101: display[7:0] <= 8'b1001_0010;
                              4'b0110: display[7:0] <= 8'b1000_0010;
                              4'b0111: display[7:0] <= 8'b1101_1000;
                              4'b1000: display[7:0] <= 8'b1000_0000;
                              4'b1001: display[7:0] <= 8'b1001_0000;
                              4'b1010: display[7:0] <= 8'b1000_1000;
                              4'b1011: display[7:0] <= 8'b1000_0011;
                              4'b1100: display[7:0] <= 8'b1100_0110;
                              4'b1101: display[7:0] <= 8'b1010_0001;
                              4'b1110: display[7:0] <= 8'b1000_0110;
                              4'b1111: display[7:0] <= 8'b1000_1110;
                              default : display[7:0] = 8'b1111_1111; //全灭
                           endcase
                      end
                      3: begin
                          display[11:8] <= 4'b1110;
                          //第四位输出
                          case(dataOut[3:0])
                              4'b0000: display[7:0] <= 8'b1100_0000; 
                              4'b0001: display[7:0] <= 8'b1111_1001;
                              4'b0010: display[7:0] <= 8'b1010_0100;
                              4'b0011: display[7:0] <= 8'b1011_0000;
                              4'b0100: display[7:0] <= 8'b1001_1001;
                              4'b0101: display[7:0] <= 8'b1001_0010;
                              4'b0110: display[7:0] <= 8'b1000_0010;
                              4'b0111: display[7:0] <= 8'b1101_1000;
                              4'b1000: display[7:0] <= 8'b1000_0000;
                              4'b1001: display[7:0] <= 8'b1001_0000;
                              4'b1010: display[7:0] <= 8'b1000_1000;
                              4'b1011: display[7:0] <= 8'b1000_0011;
                              4'b1100: display[7:0] <= 8'b1100_0110;
                              4'b1101: display[7:0] <= 8'b1010_0001;
                              4'b1110: display[7:0] <= 8'b1000_0110;
                              4'b1111: display[7:0] <= 8'b1000_1110;
                              default : display[7:0] = 8'b1111_1111; //全灭
                           endcase
                      end
                  endcase
            end
        endcase
    end
    
endmodule

            这里的display[0]~diplay[6]分别是数码管的A~G。

        按键消抖

                消抖原理:FPGA板子上的按键在按下时,由于弹性形变,因此会导致信号不稳定,在极短的时间内会产生多次高电平,因此要在信号保持稳定后再进行读取,这样              能避免按下一次按键后执行多条指令。

                脉冲信号为push,写一个模块消抖(clk_dura.v):

`timescale 1ns / 1ps

module clk_dura(
    input clk,
    input push,
    output reg effective_clk
    );
    
    reg [31:0] count;
    integer i;
    initial begin
     for(i=0;i<32;i=i+1) count[i] = 0; 
    end
    
    always @(posedge clk) begin
        if(push && count<=32'd30000000) count = count + 1;
        else if(!push) count = 0; 
    end
    
    always @(count) begin
        if(count == 32'd10000000) effective_clk = 1'b1;
        else effective_clk = 0;
    end
endmodule

        虽然加了延迟消除抖动,但是在上板子的时候会发现仍会出现按一下跳两条指令的情况,(猜测是板子问题)因此加入了简易的松手检测,如下图:

MIPS指令集单周期CPU兼Verilog学习_第24张图片   

        强行抹除了长按可能造成跳多条指令的影响(计数器到了30ms后不会再增加)。

        修改过后按键运行正常。

  需要全项目源代码的,链接已经贴在下面,需要自取。

  项目源代码:https://download.csdn.net/download/wuyzh39/87244971

你可能感兴趣的:(Verilog,学习,fpga开发)