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

这篇具有很好参考价值的文章主要介绍了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

                机器中存储:

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

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

         I型指令:

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

                机器中存储:

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

                含义:[rs]+imm16  [rt] 

        J型指令:  

                汇编代码格式:op imm26

                机器中存储:

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

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

                来看下MIPS指令集:

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

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

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

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


3.代码实现        

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

            1)符号扩展单元Extender

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

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

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

                   

              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学习 扩展器完成!

           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学习

                         这时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学习                                                                                      

               注:第一条指令是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学习

         6)运算单元模块(ALU)

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

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

         虽然有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<in1;i=i+1)  res[31-i] = 1;
                end
                else begin
                    for(i=0;i<in1;i=i+1)  res[31-i] = 0;
                end
            end
            //判断相等
            4'b1000: begin
                zero = in1==in2 ? 1'b1 : 1'b0;
            end
            //lui指令:设置rt的高16位
            4'b1001: begin
                res = {in2[31],in2[14:0],{16{0}}};
            end
        endcase
    end
    
endmodule

                测试一下算术右移功能(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学习

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

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

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

        测试过后,将顶层写成一个模块,然后将程序烧入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学习MIPS指令集单周期CPU兼Verilog学习MIPS指令集单周期CPU兼Verilog学习

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

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

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

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

 3.CPU烧板

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

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

         七段数码管

                为了在数码管上显示,要写一个七段数码管显示的模块,通过当前的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学习   

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

        修改过后按键运行正常。

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

  项目源代码:https://download.csdn.net/download/wuyzh39/87244971文章来源地址https://www.toymoban.com/news/detail-423327.html

到了这里,关于MIPS指令集单周期CPU兼Verilog学习的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 实验九 单周期MIPS CPU设计实验(基于Logisim)

    一、实验目的 学生掌握控制器设计的基本原理,能利用硬布线控制器的设计原理在Logisim平台中设计实现MIPS单周期CPU。 二、实验内容 利用运算器实验,存储系统实验中构建的运算器、寄存器文件、存储系统等部件以及Logisim中其它功能部件构建一个32位MIPS CPU单周期处理器。数

    2024年02月05日
    浏览(87)
  • 计算机组成原理32位MIPS CPU设计实验(指令译码器电路设计 、时序发生器状态机设计、时序发生器输出函数、硬布线控制器)

    这次实验是32位MIPS CPU设计实验(单总线CPU-定长指令周期-3级时序),在头歌当中一共需要我们进行六道题的测试,分别为MIPS指令译码器设计,定长指令周期(时序发生FSM设计,时序发生器输出函数设计,硬布线控制器,单总线CPU设计),硬布线控制器组合逻辑单元。其中由于

    2024年02月02日
    浏览(42)
  • MIPS指令集-mars-cpu

    MIPS通用寄存器 MIPS有32个通用寄存器($0-$31),各寄存器的功能及汇编程序中使用约定如下: 下表描述32个通用寄存器的别名和用途 REGISTER NAME USAGE $0 $zero 常量0(constant value 0) $1 $at 保留给汇编器(Reserved for assembler) $2-$3 $v0-$v1 函数调用返回值(values for results and expression evaluation)

    2024年02月08日
    浏览(51)
  • 【计算机硬件系统设计(华科)——单周期MIPS CPU(Logisim 实现)】

    本章继续讲述计算机硬件系统设计的内容,之前已经大概说明了 ALU 和存储系统的设计,本文讲述CPU的设计。对应的有单周期、多周期 CPU 设计,以及流水线设计,中断处理会在后文中详细说明,本文不进行讲述。 即定长指令周期,机器性能取决于最慢的指令,导致时钟周期

    2024年02月02日
    浏览(53)
  • 【计组实验】基于Verilog的多周期非流水线MIPS处理器设计

    设计多周期非流水线MIPS处理器,包括: 完成多周期MIPS处理器的Verilog代码; 在Vivado软件上进行仿真; 编写MIPS代码验证MIPS处理器; 相关代码及资源的下载地址如下: 本实验的Vivado工程文件和实验文档:Multi-Cycle MIPS Processor.zip(272KB) QtSpim 9.1.23和Vivado 2019.2的安装包:QtSpim Viv

    2024年02月11日
    浏览(48)
  • FPGA纯verilog代码实现8位精简指令集CPU,一学期的微机原理不如看懂这套代码,提供工程源码和技术支持

    本文章主要针对大学本科阶段学生; 读文章之前先来几个灵魂拷问: 1、你是否学过《微机原理》、《单片机》、《汇编语言》之类有关微型计算机的课程? 2、上这些课时你的老师是否只是机械的讲着PPT,你听着无聊,听不懂,逐渐对计算机专业产生了畏惧? 3、这些计算机

    2024年02月11日
    浏览(54)
  • 单总线CPU设计(变长指令周期3级时序)(HUST)(头歌实验)

      利用比较器等功能模块将32位MIPS 指令字译码生成LW、SW、BEQ、SLT、ADDI、OtherInstr信号也就是利用比较器将指令字转换为译码信号,OP与不同信号对应(查询MIPS手册得知)  16 进制 :23 是 2进制: 00100011 ,把获得的OP,Func,和常数比对,相同输出1. 按照题目要求填写表格,使

    2024年02月07日
    浏览(34)
  • 计组高分笔记:【05】中央处理器 「CPU细节 | 取指周期 | 间址周期 | 执行周期 | 中断周期 | 数据通路 | 硬布线控制器 | 微程序控制器 | 指令流水线 | LOAD | STORE」

    CPU由 运算器 和 控制器 组成。 注意:n位CPU,指机器字长为n,表示一次能够处理的二进制位数。自然与数据总线相等 1.1.1 运算器的基本组成 功能:对数据进行加工 通用寄存器组 :如AX、BX、CX、DX、SP等,用于存放操作数(包括源操作数、目的操作数及中间结果)和各种地址

    2024年02月11日
    浏览(43)
  • 计算机组成原理实验——五、单周期CPU设计

    掌握指令执行过程的5个阶段 掌握每条指令的数据通路选择 掌握译码器和控制器的功能和实现 掌握数据输入输出处理的方法 实现risc-v中RV32I指令的单周期CPU 利用实现的risc-v CPU实现平方数 实现risc-v中37条RV32I指令的单周期 cpu; 完成1后在该cpu上实现斐波那契数。 rom dataRAM ins文

    2024年02月11日
    浏览(43)
  • 计算机组成原理 CPU的功能和基本结构和指令执行过程

    CPU的功能 指令控制: 完成取指令、分析指令和执行指令的操作,即程序的顺序控制。 操作控制:一条指令的功能往往是由若干操作信号的组合来实现的。CPU管理并产生由内存取出的每条指令的操作信号,把各种操作信号送往相应的部件,从而控制这些部件按指令的要求进行动

    2024年01月20日
    浏览(50)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包