计算机组成与结构课程设计 单周期CPU的译码模块设计(vivado)

1.框图

对指令进行分离,op为指令码,rs为要读的第一个寄存器的号,rt为要读的第二个寄存器的号或i-form指令要写的寄存器的号,rd为r-form指令要写的寄存器的号,immediate为指令中的立即数。

对寄存器组进行读操作。

目标寄存器的指定,其中Regdst和JAL都来自于控制单元,JAL说明该指令是否为JAL指令,rt为要读的第二个寄存器的号或i-form指令要写的寄存器的号,rd为r-form指令要写的寄存器的号,31为寄存器组的最大序号。

read_data为从 DATA RAM 取出的数据ALU_result为从执行单元来的运算的结果opcplus4来自取指单元,JAL 中用,Jal和MemtoReg来着控制单元,write_data用于储存要写寄存器的数据。

2.子模块设计

       对于分离指令变量的模块,只需简单的将从取指单元送来的指令Instruction按对应位数分配给不同的变量即可,包括31-26交给opcode即OP信号,25-21交给read_register_1_address即rs信号,20-16交给read_register_2_address即rt信号,15-11交给write_register_address_1即rd(r-form)信号,20-16交给write_register_address_0即rt(i-form)信号,15-0交给Instruction_immediate_value即立即数。

       定义寄存器组模块,只是定义,无需初始化,只需要简单的定义一个由32个32位寄存器组成的寄存器组。

       对于目标寄存器的指定模块则需要根据RegDst和Jal信号的不同来给write_register_address信号附上不同的值,若RegDst信号为1,Jal信号为0,则赋值为rd,若RegDst信号为0,Jal信号为1,则赋值为31(5’b11111),其他情况,即RegDst和Jal信号均为0时,则赋值为rt,由于RegDst和Jal不同时为1忽略其赋值。

       第四模块,即对需要写的数据进行准备,需根据MemtoReg和Jal信号的不同,对write_data写入不同的数据,若MemtoReg和Jal均为0则写入执行单元的运算结果,若MemtoReg为0,Jal为1,则写入pc+4,只要MemtoReg为1,则写入从DATA RAM or I/O port取出的数据。

第五模块实现对寄存器的写操作,在写入之前或者reset信号为1时需要对寄存器组进行初始化,这里是全赋值为0,当RegWrite信号为1时,根据write_register_address信号的值,即根据要写的寄存器的号,对寄存器组进行写入,其中需注意寄存器0恒等于0。

第六个模块实现的是16位立即数的32位扩展,首先取出立即数的最高位,即符号位,然后运用三目运算符,在andi,ori,xori,sltiu四个指令下执行无符号扩展,在不足的位数上补零,在其他指令下执行有符号位扩展,在不足的为位数上补符号位的值。

五、程序清单

1.设计文件

module Idecode32 (

       input                    reset,

    input                   clock,

    output   [31:0]    read_data_1, // 输出的第一操作数

    output   [31:0]    read_data_2, // 输出的第二操作数

    input     [31:0]    Instruction,   // 取指单元来的指令

    input     [31:0]    read_data,           // 从DATA RAM or I/O port取出的数据

input     [31:0]    ALU_result,        // 从执行单元来的运算的结果,需要扩展立即数到32位

    input                   Jal,                // 来自控制单元,说明是JAL指令

    input                   RegWrite,           // 来自控制单元

    input                   MemtoReg,         // 来自控制单元

    input                   RegDst,               // 来自控制单元

    output   [31:0]    Sign_extend,       // 译码单元输出的扩展后的32位立即数

    input     [31:0]    opcplus4              // 来自取指单元,JAL中用

);

    reg[31:0] register[0:31];                   //寄存器组共32个32位寄存器

    reg[4:0] write_register_address;        // 要写的寄存器的号

    reg[31:0] write_data;                   // 要写寄存器的数据放这里

    wire[4:0] read_register_1_address;    // 要读的第一个寄存器的号(rs)

    wire[4:0] read_register_2_address;     // 要读的第二个寄存器的号(rt)

    wire[4:0] write_register_address_1;   // r-form指令要写的寄存器的号(rd)

    wire[4:0] write_register_address_0;    // i-form指令要写的寄存器的号(rt)

    wire[15:0] Instruction_immediate_value;  // 指令中的立即数

    wire[5:0] opcode;                       // 指令码

   

    assign opcode = Instruction[31:26];     //OP

    assign read_register_1_address = Instruction[25:21];//rs

    assign read_register_2_address = Instruction[20:16];//rt

    assign write_register_address_1 = Instruction[15:11];// rd(r-form)

    assign write_register_address_0 = Instruction[20:16];//rt(i-form)

    assign Instruction_immediate_value = Instruction[15:0];//data,rladr(i-form)

    wire sign;                                          // 取符号位的值

    assign sign = Instruction_immediate_value[15];  

    assign Sign_extend[31:0] = ((opcode == 6'b001100) ||   //andi

                                (opcode == 6'b001101) ||    //ori

                                (opcode == 6'b001110) ||    //xori

                                (opcode == 6'b001011))?     //sltiu

                                {16'h0000,Instruction_immediate_value[15:0]}:       //无符号扩展,补零

                                {sign,sign,sign,sign,sign,sign,sign,sign,sign,sign,sign,sign,sign,sign,sign,sign,Instruction_immediate_value[15:0]};    //有符号位扩展,补符号位

   

    assign read_data_1 = register[read_register_1_address];     //取register[rs]

    assign read_data_2 = register[read_register_2_address];     //取register[rd]

   

    always @* begin                                            //这个进程指定不同指令下的目标寄存器

    if((RegDst == 1) && (Jal == 0))                             //r-form jal (pc+1 > sp[$Rlast])

        write_register_address = write_register_address_1;      //RD(15-11)

    else if((RegDst == 0) && (Jal == 1))

        write_register_address = 5'b11111;                     //JAL

    else write_register_address = write_register_address_0;    // rt(20-16)

    end

always @* begin 

//这个进程基本上是实现结构图中右下的多路选择器,准备要写的数据

        if((MemtoReg == 0) && (Jal == 0)) begin

            write_data = ALU_result[31:0];      //写入执行单元的运算结果

        end else if ((MemtoReg == 0) && (Jal == 1)) begin

            write_data = opcplus4;              //写入pc+4

        end else begin

        write_data = read_data;                 //写入从DATA RAM or I/O port取出的数据

        end

     end

   

    integer i;

    always @(posedge clock) begin       // 本进程写目标寄存器

        if(reset==1) begin              // 初始化寄存器组

            for(i=0;i<32;i=i+1) register[i] <= 0;

        end else if(RegWrite==1) begin          // 注意寄存器0恒等于0

            case(write_register_address[4:0])    //根据要写的寄存器的号,对寄存器组进行写入

                5'd0:register[0] <= 32'd0;       //寄存器0恒等于0

                5'd1:register[1] <= write_data;  //寄存器1赋值

                5'd2:register[2] <= write_data;  //寄存器2赋值

                5'd3:register[3] <= write_data;  //寄存器3赋值

                5'd4:register[4] <= write_data;  //寄存器4赋值

                5'd5:register[5] <= write_data;  //寄存器5赋值

                5'd6:register[6] <= write_data;  //寄存器6赋值

                5'd7:register[7] <= write_data;  //寄存器7赋值

                5'd8:register[8] <= write_data;  //寄存器8赋值

                5'd9:register[9] <= write_data;  //寄存器9赋值

                5'd10:register[10] <= write_data;//寄存器10赋值

                5'd11:register[11] <= write_data;//寄存器11赋值

                5'd12:register[12] <= write_data;//寄存器12赋值

                5'd13:register[13] <= write_data;//寄存器13赋值

                5'd14:register[14] <= write_data;//寄存器14赋值

                5'd15:register[15] <= write_data;//寄存器15赋值

                5'd16:register[16] <= write_data;//寄存器16赋值

                5'd17:register[17] <= write_data;//寄存器17赋值

                5'd18:register[18] <= write_data;//寄存器18赋值

                5'd19:register[19] <= write_data;//寄存器19赋值

                5'd20:register[20] <= write_data;//寄存器20赋值

                5'd21:register[21] <= write_data;//寄存器21赋值

                5'd22:register[22] <= write_data;//寄存器22赋值

                5'd23:register[23] <= write_data;//寄存器23赋值

                5'd24:register[24] <= write_data;//寄存器24赋值

                5'd25:register[25] <= write_data;//寄存器25赋值

                5'd26:register[26] <= write_data;//寄存器26赋值

                5'd27:register[27] <= write_data;//寄存器27赋值

                5'd28:register[28] <= write_data;//寄存器28赋值

                5'd29:register[29] <= write_data;//寄存器29赋值

                5'd30:register[30] <= write_data;//寄存器30赋值

                5'd31:register[31] <= write_data;//寄存器31赋值

                default:register[0] <= 32'd0;

            endcase

        end

    end

endmodule

2.仿真文件

`timescale 1ns / 1ps

module idcode32_sim ();

    // input

    reg[31:0]  Instruction = 32'b000000_00010_00011_00111_00000_100000; //add $7,$2,$3

    reg[31:0]  read_data = 32'h00000000;    //  从DATA RAM or I/O port取出的数据

    reg[31:0]  ALU_result = 32'h00000005;      //  需要扩展立即数到32位

    reg        Jal = 1'b0;

    reg        RegWrite = 1'b1;

    reg        MemtoReg = 1'b0;

    reg        RegDst = 1'b1;

    reg         clock = 1'b0 ,reset = 1'b1;

    reg[31:0]  opcplus4 = 32'h00000004;       // 来自取指单元,JAL中用

    // output

    wire[31:0] read_data_1;

    wire[31:0] read_data_2;

    wire[31:0] Sign_extend;

   

       Idecode32 Uid (

              .reset                   (reset),          // 复位(高电平有效)

              .clock                  (clock),         // CPU时钟

              .read_data_1 (read_data_1),     // 输出的第一操作数

              .read_data_2 (read_data_2),     // 输出的第二操作数

              .Instruction   (Instruction),       // 取指单元来的指令

              .read_data           (read_data),  // 从DATA RAM or I/O port取出的数据

              .ALU_result        (ALU_result),     // 从执行单元来的运算的结果,需要扩展立即数到32位

              .Jal                (Jal),                    // 来自控制单元,说明是JAL指令

              .RegWrite           (RegWrite),         // 来自控制单元

              .MemtoReg  (MemtoReg),             // 来自控制单元

              .RegDst               (RegDst),            // 来自控制单元

              .Sign_extend       (Sign_extend),    // 扩展后的32位立即数

              .opcplus4             (opcplus4)           // 来自取指单元,JAL中用

       );

    initial begin

        #200   reset = 1'b0;

        #200   begin Instruction = 32'b001000_00111_00011_1000000000110111;  //addi $3,$7,0X8037

        read_data = 32'h00000000;

        ALU_result = 32'hFFFF803C;

        Jal = 1'b0;

        RegWrite = 1'b1;

        MemtoReg = 1'b0;

        RegDst = 1'b0;

        opcplus4 = 32'h00000008;

               end

        #200   begin Instruction = 32'b001100_00010_00100_1000000010010111;  //andi $4,$2,0X8097

               read_data = 32'h00000000;

               ALU_result = 32'h00000002;

               Jal = 1'b0;

               RegWrite = 1'b1;

               MemtoReg = 1'b0;

               RegDst = 1'b0;

               opcplus4 = 32'h0000000c;

          end

        #200   begin Instruction = 32'b000000_00000_00001_00101_00010_000000;  //sll $5,$1,2

                       read_data = 32'h00000000;

                       ALU_result = 32'h00000004;

                       Jal = 1'b0;

                       RegWrite = 1'b1;

                       MemtoReg = 1'b0;

                         RegDst = 1'b1;

                         opcplus4 = 32'h00000010;

               end

        #200   begin Instruction = 32'b100011_00000_00110_0000000100000000;  //LW $6,0(0X100)

                         read_data = 32'h0000007B;

                         ALU_result = 32'h00000054;

                         Jal = 1'b0;

                         RegWrite = 1'b1;

                         MemtoReg = 1'b1;

                         RegDst = 1'b0;

                         opcplus4 = 32'h00000014;

               end

        #200   begin Instruction = 32'b000011_00000000000000000000000000;  //JAL 0000

                         read_data = 32'h00000000;

                         ALU_result = 32'h00000004;

                         Jal = 1'b1;

                         RegWrite = 1'b1;

                         MemtoReg = 1'b0;

                         RegDst = 1'b0;

                         opcplus4 = 32'h00000018;

               end

    end

    always #50 clock = ~clock;           

endmodule

六、时序仿真结果及分析和硬件测试结果及分析

1.程序仿真图:

2.管脚分配图:

  • 2
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: Vivado 单周期 CPU译码模块设计主要包括以下几个方面: 1. 指令译码:根据指令的操作码,译码模块可以确定所执行的操作类型,比如算术逻辑操作、存取数据等。译码模块还可以根据指令的格式和位数,对指令进行解析,提取出操作数、立即数等。 2. 控制信号生成:译码模块根据指令的操作类型,生成相应的控制信号,用于控制其他模块的工作。比如,对于算术逻辑操作,需要生成加法、减法、与、或等控制信号。对于数据存取,需要生成读、写控制信号等。 3. 寄存器读取:译码模块需要根据指令中的寄存器编号,读取相应的寄存器的值,并将其传递给执行模块使用。 4. 分支跳转判断:译码模块需要对分支和跳转指令进行解析,判断分支条件是否满足,并生成相应的控制信号,用于跳转到指定的地址或执行下一条指令。 5. 异常处理:译码模块还负责识别指令中可能出现的异常情况,比如除零错误、越界访问等,并生成相应的异常信号,用于进行异常处理。 综上所述,Vivado 单周期 CPU译码模块设计扮演着重要的角色,通过对指令的解析、生成控制信号、读取寄存器等操作,实现对指令的译码和执行的控制。译码模块设计需要考虑各种指令类型和格式,以及异常处理等方面的细节,以确保 CPU 的正确运行。 ### 回答2: Vivado单周期CPU译码模块设计是实现CPU的指令译码和控制逻辑的重要模块。该模块将从指令存储单元(Instruction Memory)中读取指令,进行解析和译码后生成相应的控制信号,以控制CPU的其他各个模块的工作。 译码模块设计中,需要首先解析指令的各个字段,如操作码(Opcode)、操作数(Operand)、寄存器编号等。针对不同的指令,需要根据操作码确定执行的操作,并生成相应的控制信号,如读写信号、数据通路选择信号等。 在译码模块中,还需要进行指令的操作数和结果的寄存器选择。通过解析指令的寄存器编号字段,可以确定需要读取的源操作数寄存器和写入的目标寄存器。并生成读写寄存器的控制信号,使得对应的寄存器能够正确地进行读取或写入操作。 此外,译码模块还需要生成分支、跳转和访存等指令对应的控制信号。通过对指令中的条件字段进行解析,可以确定是否满足分支或跳转的条件,并生成对应的控制信号。对于访存指令,需要解析指令中的地址字段,并生成访存操作的控制信号,以实现数据的读取或写入。 最后,译码模块还需要处理异常和中断的控制信号。通过解析指令中的异常和中断字段,可以确定是否需要触发相应的异常或中断操作,并生成相关的控制信号,以通知CPU的其他模块进行相应的处理。 总而言之,Vivado单周期CPU译码模块设计是根据指令的不同字段进行解析和译码,生成相应的控制信号,以实现对CPU工作的准确定义和控制。 ### 回答3: vivado单周期CPU译码模块设计主要包括指令译码、操作数选择和控制信号生成等方面。 首先,在指令译码部分,我们需要解析指令,获得指令类型、操作数以及操作码等信息。这个过程可以通过对指令进行位切割和逻辑运算来实现。根据不同的指令类型,我们可以识别出是算术逻辑指令、分支指令还是存储指令等。 其次,在操作数选择部分,我们根据指令需要的操作数个数和类型,从寄存器文件或者内存中读取相应的操作数。通过指令中的寄存器地址字段,我们可以选择正确的源操作数寄存器,并将其值传递给执行阶段。 最后,在控制信号生成部分,我们根据指令类型和操作数选择的结果,生成相应的控制信号,用于控制数据通路中的各个模块的工作。比如,我们需要生成ALU的操作控制信号,用于指示进行加法、减法、与操作等。 整个译码模块设计需要考虑各个信号之间的协调和逻辑关系,保证指令的执行顺序和正确性。此外,还需要与其他模块进行协同工作,如与寄存器文件和内存模块进行交互,以实现数据的读写操作。 综上所述,vivado单周期CPU译码模块设计是一个复杂且关键的环节,它直接影响到整个CPU的性能和功能。通过合理的设计和优化,能够提高CPU的运行效率和功能扩展性,满足各种应用需求。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值