草庐IT

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

相当乏善 2024-05-11 原文

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]   [rd]

         I型指令:

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

                机器中存储:

                

                含义:[rs]+imm16  [rt] 

        J型指令:  

                汇编代码格式:op imm26

                机器中存储:

                

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

                来看下MIPS指令集:

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


3.代码实现        

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

            1)符号扩展单元Extender

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

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

                               

                   

              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,观察仿真波形:

 扩展器完成!

           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位的寄存器会两个两个数据读,因此在读入单条(正常顺序)                            的指令时,顺序会错乱。比如:

                           

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

                  检验一下输出波形:

                                                                                      

               注:第一条指令是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的波形如下:

         6)运算单元模块(ALU)

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

         虽然有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是否能正常工作。

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

        测试过后,将顶层写成一个模块,然后将程序烧入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):

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

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

 3.CPU烧板

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

         七段数码管

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

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

   

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

        修改过后按键运行正常。

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

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

有关MIPS指令集单周期CPU兼Verilog学习的更多相关文章

  1. LC滤波器设计学习笔记(一)滤波电路入门 - 2

    目录前言滤波电路科普主要分类实际情况单位的概念常用评价参数函数型滤波器简单分析滤波电路构成低通滤波器RC低通滤波器RL低通滤波器高通滤波器RC高通滤波器RL高通滤波器部分摘自《LC滤波器设计与制作》,侵权删。前言最近需要学习放大电路和滤波电路,但是由于只在之前做音乐频谱分析仪的时候简单了解过一点点运放,所以也是相当从零开始学习了。滤波电路科普主要分类滤波器:主要是从不同频率的成分中提取出特定频率的信号。有源滤波器:由RC元件与运算放大器组成的滤波器。可滤除某一次或多次谐波,最普通易于采用的无源滤波器结构是将电感与电容串联,可对主要次谐波(3、5、7)构成低阻抗旁路。无源滤波器:无源滤波器,又称

  2. CAN协议的学习与理解 - 2

    最近在学习CAN,记录一下,也供大家参考交流。推荐几个我觉得很好的CAN学习,本文也是在看了他们的好文之后做的笔记首先是瑞萨的CAN入门,真的通透;秀!靠这篇我竟然2天理解了CAN协议!实战STM32F4CAN!原文链接:https://blog.csdn.net/XiaoXiaoPengBo/article/details/116206252CAN详解(小白教程)原文链接:https://blog.csdn.net/xwwwj/article/details/105372234一篇易懂的CAN通讯协议指南1一篇易懂的CAN通讯协议指南1-知乎(zhihu.com)视频推荐CAN总线个人知识总

  3. 深度学习部署:Windows安装pycocotools报错解决方法 - 2

    深度学习部署:Windows安装pycocotools报错解决方法1.pycocotools库的简介2.pycocotools安装的坑3.解决办法更多Ai资讯:公主号AiCharm本系列是作者在跑一些深度学习实例时,遇到的各种各样的问题及解决办法,希望能够帮助到大家。ERROR:Commanderroredoutwithexitstatus1:'D:\Anaconda3\python.exe'-u-c'importsys,setuptools,tokenize;sys.argv[0]='"'"'C:\\Users\\46653\\AppData\\Local\\Temp\\pip-instal

  4. ruby - 我正在学习编程并选择了 Ruby。我应该升级到 Ruby 1.9 吗? - 2

    我完全不是程序员,正在学习使用Ruby和Rails框架进行编程。我目前正在使用Ruby1.8.7和Rails3.0.3,但我想知道我是否应该升级到Ruby1.9,因为我真的没有任何升级的“遗留”成本。缺点是什么?我是否会遇到与普通gem的兼容性问题,或者甚至其他我不太了解甚至无法预料的问题? 最佳答案 你应该升级。不要坚持从1.8.7开始。如果您发现不支持1.9.2的gem,请避免使用它们(因为它们很可能不被维护)。如果您对gem是否兼容1.9.2有任何疑问,您可以在以下位置查看:http://www.railsplugins.or

  5. ruby - 我如何学习 ruby​​ 的正则表达式? - 2

    如何学习ruby​​的正则表达式?(对于假人) 最佳答案 http://www.rubular.com/在Ruby中使用正则表达式时是一个很棒的工具,因为它可以立即将结果可视化。 关于ruby-我如何学习ruby​​的正则表达式?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/1881231/

  6. 深度学习12. CNN经典网络 VGG16 - 2

    深度学习12.CNN经典网络VGG16一、简介1.VGG来源2.VGG分类3.不同模型的参数数量4.3x3卷积核的好处5.关于学习率调度6.批归一化二、VGG16层分析1.层划分2.参数展开过程图解3.参数传递示例4.VGG16各层参数数量三、代码分析1.VGG16模型定义2.训练3.测试一、简介1.VGG来源VGG(VisualGeometryGroup)是一个视觉几何组在2014年提出的深度卷积神经网络架构。VGG在2014年ImageNet图像分类竞赛亚军,定位竞赛冠军;VGG网络采用连续的小卷积核(3x3)和池化层构建深度神经网络,网络深度可以达到16层或19层,其中VGG16和VGG

  7. 机器学习——时间序列ARIMA模型(四):自相关函数ACF和偏自相关函数PACF用于判断ARIMA模型中p、q参数取值 - 2

    文章目录1、自相关函数ACF2、偏自相关函数PACF3、ARIMA(p,d,q)的阶数判断4、代码实现1、引入所需依赖2、数据读取与处理3、一阶差分与绘图4、ACF5、PACF1、自相关函数ACF自相关函数反映了同一序列在不同时序的取值之间的相关性。公式:ACF(k)=ρk=Cov(yt,yt−k)Var(yt)ACF(k)=\rho_{k}=\frac{Cov(y_{t},y_{t-k})}{Var(y_{t})}ACF(k)=ρk​=Var(yt​)Cov(yt​,yt−k​)​其中分子用于求协方差矩阵,分母用于计算样本方差。求出的ACF值为[-1,1]。但对于一个平稳的AR模型,求出其滞

  8. Unity Shader 学习笔记(5)Shader变体、Shader属性定义技巧、自定义材质面板 - 2

    写在之前Shader变体、Shader属性定义技巧、自定义材质面板,这三个知识点任何一个单拿出来都是一套知识体系,不能一概而论,本文章目的在于将学习和实际工作中遇见的问题进行总结,类似于网络笔记之用,方便后续回顾查看,如有以偏概全、不祥不尽之处,还望海涵。1、Shader变体先看一段代码......Properties{ [KeywordEnum(on,off)]USL_USE_COL("IsUseColorMixTex?",int)=0 [Toggle(IS_RED_ON)]_IsRed("IsRed?",int)=0}......//中间省略,后续会有完整代码 #pragmamulti_c

  9. Verilog使用inout信号的方法 - 2

    目录一、inout在设计文件中的使用方法1.1、inout的第一种使用方法1.2、inout实现的第二种使用方法1.3、inout使用总结 二、inout在仿真测试中的使用方法一、inout在设计文件中的使用方法在FPGA的设计过程中,有时候会遇到双向信号(既能作为输出,也能作为输入的信号叫双向信号)。比如,IIC总线中的SDA信号就是一个双向信号,QSPIFlash的四线操作的时候四根信号线均为双向信号。在Verilog中用关键字inout定义双向信号,这里总结一下双向信号的处理方法。1.1、inout的第一种使用方法  实际上,双向信号的本质是由一个三态门组成的,三态门可以输出高电平,低电

  10. ruby-on-rails - 这个 C 和 PHP 程序员如何学习 Ruby 和 Rails? - 2

    按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visitthehelpcenter指导。关闭9年前。我来自C、php和bash背景,很容易学习,因为它们都有相同的C结构,我可以将其与我已经知道的联系起来。然后2年前我学了Python并且学得很好,Python对我来说比Ruby更容易学。然后从去年开始,我一直在尝试学习Ruby,然后是Rails,我承认,直到现在我还是学不会,讽刺的是那些打着简单易学的烙印,但是对于我这样一个老练的程序员来说,我只是无法将它

随机推荐