计算机组成与结构课程设计 单周期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
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值