MIPS多周期CPU设计(Verilog)

来源:互联网 发布:图像处理经典算法 编辑:程序博客网 时间:2024/05/08 00:10

请勿转载,本人对该文章保留有所有权利,如果需要转载请联系gavingog@qq.com,经本人同意后才可转载

2016/05/12最新更改:RAM模块有错误,不需要乘四,因为ALU计算的结果直接就是地址了。
2016/05/13最新更改:更改了RegFile模块的触发条件,不用CLK上升沿信号触发,因为与CtrlUnit共享CLK会发生延迟,导致下一个时钟上升沿才做相应动作,因此在这里我使用地址和输入数据的更改作为触发条件,这样更加便于模块化思想,因为这不需要在WB阶段的上一个阶段就发出相应信号,而我们只需考虑当前阶段的信号问题就可以了。


前言:设计完了单周期CPU之后,接下来很自然地需要设计多周期CPU,如果以后有机会的话,我非常希望可以再写一篇关于MIPS流水线CPU的设计博客。因为最近这几周忙着考公选以及写论文所以blog更新的略慢,对此造成的困扰十分抱歉。那么话不多说,接下来就跟着我开始多周期CPU设计的历程吧!如果你之前有看了我的单周期CPU设计博客并且理解了其中的思想,那么接下来的设计肯定也不会难倒你的。


  • 该文仅供参考,其中也许很多bug,请注意
  • 仅供复习,学习用,若有问题或者建议请在评论区留言,我会尽快回复
  • 这个设计增加了一个功能,就是在初始化的时候可以通过外部的pc来确定代码段的存放地址,例如在我的测试代码中设置的outside_pc为4,所以ROM会在地址为4的地方开始放置代码以及reset的时候会从地址为4的地方开始执行。
  • 在实验过程中发现多周期一个很重大的问题就是延迟的问题,必须合理设计才不会掉坑,请注意。

多周期CPU概念

多周期CPU指的是将整个CPU的执行过程分成几个阶段,每个阶段用一个时钟去完成,然后开始下一条指令的执行,而每种指令执行时所用的时钟数不尽相同,这就是所谓的多周期CPU。CPU在处理指令时,一般需要经过以下几个阶段:
(1) 取指令(IF):根据程序计数器pc中的指令地址,从存储器中取出一条指令,同时,pc根据指令字长度自动递增产生下一条指令所需要的指令地址,但遇到“地址转移”指令时,则控制器把“转移地址”送入pc,当然得到的“地址”需要做些变换才送入pc。
(2) 指令译码(ID):对取指令操作中得到的指令进行分析并译码,确定这条指令需要完成的操作,从而产生相应的操作控制信号,用于驱动执行状态中的各种操作。
(3) 指令执行(EXE):根据指令译码得到的操作控制信号,具体地执行指令动作,然后转移到结果写回状态。
(4) 存储器访问(MEM):所有需要访问存储器的操作都将在这个步骤中执行,该步骤给出存储器的数据地址,把数据写入到存储器中数据地址所指定的存储单元或者从存储器中得到数据地址单元中的数据。
(5) 结果写回(WB):指令执行的结果或者访问存储器中得到的数据写回相应的目的寄存器中。
实验中就按照这五个阶段进行设计,这样一条指令的执行最长需要五个(小)时钟周期才能完成,但具体情况怎样?要根据该条指令的情况而定,有些指令不需要五个时钟周期的,这就是多周期的CPU。

这里写图片描述

系统概述

下图是多周期CPU的数据通路图,可以看到这个数据通路和单周期CPU数据通路图基本一致,但是不一样的地方有以下几点:(1) ControlUnit增加了Reset信号和时钟,这是因为需要在内部实现状态的转移和控制信号的重置;(2)增加了IR寄存器以及ADR,BDR,ALUout,ALUM2DR –>IR指令寄存器,目的是使指令代码保持稳定,还有pc增加写使能控制信号pcWre,也是确保pc适时修改,原因都是和多周期工作的CPU有关。ADR、BDR、ALUout、ALUM2DR四个寄存器不需要写使能信号,其作用是切分数据通路,将大组合逻辑切分为若干个小组合逻辑,大延时变为多个分段小延时;举个例子:假设在我们在ALU计算出来数据打算写到RAM里面,那么在EXE阶段过后我们需要进入到MEM阶段,在MEM阶段这个计算的结果在ALUout这个小的延迟能够很好地保持数据的稳定,就算是ALU在这个阶段中产生了其他的计算结果对存入的数据也没有影响。(3)左下角增加了一个小部件,这个部件的作用是用于计算 j 和 jal 跳转指令产生的跳转地址(4)右上角的PC选择端多了几个数据接口,这是因为需要满足j 、jal、jr 跳转指令的需求进而增加的(5) 数据扩展器多了一位选择,这是因为需要满足移位指令扩展(用于sll指令),零扩展(用于ori指令),符号扩展(用于addi等指令);(6) 寄存器写数据端多了一个PC4的输入,这是因为需要满足jal指令的需求;(7)写寄存器地址多了一个$31,这是因为需要满足jal指令的需求。

多周期CPU数据通路图

下图是ALU计算功能表,接下来的ALU模块会根据这个表进行编写。

这里写图片描述

需要实现的指令如下

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

控制模块是最复杂的,接下来请仔细看这个实现的代码,下面是它的状态转移图和控制模块的逻辑原理结构图,当然最重要的还是具体的控制信号表,都在下面,棒棒哒!!!

这里写图片描述

这里写图片描述

这里写图片描述

代码实现区

主要的实现思想:

(1)和单周期CPU相同,我们这次也一样分成很多的小模块,这样实现起来debug很快,因为代码分离了,所以更改起来也会更加方面,可以看到模块化的思想很重要;

(2)我们需要一个主模块将所有的子模块通过连线囊括起来,这个主模块有两个输入<1.CLK时钟,2.Reset重置信号>,在整个系统中,这个主模块起到一个提供数据通路(也就是图中所看到的一些线路)的角色。


Main.v 模块

`timescale 1ns / 1ps//主模块,用于小模块连线作用module Main(CLK, RST, outside_pc, ins, now_pc);  input CLK, RST;  input [31:0] outside_pc;  output [31:0] ins, now_pc;  parameter endReg = 5'b11111;  // 数据通路  wire [31:0] pc, pc0, pc4, i_IR, instruction, pcChoose3, pcChoose1, extendData, ALUResult, WirteData, ReadData1, ReadData2, DataOut;  wire [31:0] o_ADR, o_BDR, o_ALUout, i_ALUM2DR, i_ALUData2;  wire zero;  // 控制信号  wire [2:0] ALUOp;  wire [1:0] ExtSel, RegOut, PCSrc;  wire PCWre, IRWre, InsMemRW, WrRegData, RegWre, ALUSrcB, DataMemRW, ALUM2Reg;  // 数据选择输出  wire [4:0] fiveChooseData;  wire [31:0] InputWriteData1;  // 引脚输出  assign ins = instruction;  assign now_pc = pc0;  PC PC(CLK, pc, PCWre, RST, pc0, outside_pc); // 添加了外部pc  PCAddFour PCAddFour(pc0, pc4);  ROM ROM(i_IR, pc0, InsMemRW, outside_pc); // 添加了外部pc  IR IR(i_IR, CLK, IRWre, instruction);  PCJump PCJump(pc0, instruction[25:0], pcChoose3);  DataSelect_5_Bit DataSelect_5_Bit(endReg, instruction[20:16], instruction[15:11], RegOut, fiveChooseData);  RegFile RegFile(instruction[25:21], instruction[20:16], fiveChooseData, WirteData, RegWre, CLK, ReadData1, ReadData2);  DataReg ADR(ReadData1, CLK, o_ADR);  DataReg BDR(ReadData2, CLK, o_BDR);  SignExtend SignExtend(instruction[15:0], ExtSel, extendData);  DataSelect_2To1_32Bit ALU_DATA2(o_BDR, extendData, ALUSrcB, i_ALUData2);  ALU ALU(o_ADR, i_ALUData2, ALUOp, zero, ALUResult);  DataReg ALUout(ALUResult, CLK, o_ALUout);  RAM RAM(o_BDR, o_ALUout, DataMemRW, DataOut);  DataSelect_2To1_32Bit Write_Data(ALUResult, DataOut, ALUM2Reg, i_ALUM2DR);  DataReg ALUM2DR(i_ALUM2DR, CLK, InputWriteData1);  DataSelect_2To1_32Bit WrRegDataChoose(pc4, InputWriteData1, WrRegData, WirteData);  PCAddImm PCAddImm(pc4, extendData, pcChoose1);  DataSelect_4To1_32Bit PCSelect(pc4, pcChoose1, ReadData1, pcChoose3, PCSrc, pc);  CtrlUnit CtrlUnit(instruction[31:26], CLK, RST, zero, PCWre, InsMemRW, IRWre, WrRegData, RegWre, ALUSrcB, DataMemRW, ALUM2Reg, ExtSel, RegOut, PCSrc, ALUOp);endmodule

接下来是控制模块,控制模块按照上面的原理结构图我们可以细分为三个小模块,这里我分别命名为DFlipFlop.v(触发器模块)、NextState.v(下一状态模块)、OutputFunc.v(输出函数模块)

`timescale 1ns / 1ps// 控制模块,包含了D触发器,状态转移,输出函数;module CtrlUnit(opcode, clk, reset, zero, PCWre, InsMemRW, IRWre, WrRegData, RegWre, ALUSrcB, DataMemRW, ALUM2Reg, ExtSel, RegOut, PCSrc, ALUOp);    input [5:0]opcode;    input zero, clk, reset;    output PCWre, InsMemRW, IRWre, WrRegData, RegWre, ALUSrcB, DataMemRW, ALUM2Reg;    output [1:0]ExtSel, RegOut, PCSrc;    output [2:0]ALUOp;    wire [2:0]i_state, o_state;    DFilpFlop DFilpFlop(i_state, reset, clk, o_state);    NextState NextState(o_state, opcode, i_state);    OutputFunc OutputFunc(o_state, opcode, zero, PCWre, InsMemRW, IRWre, WrRegData, RegWre, ALUSrcB, DataMemRW, ALUM2Reg, ExtSel, RegOut, PCSrc, ALUOp);endmodule

DFlipFlop.v 模块,这是CtrlUnit.v的一个子模块

`timescale 1ns / 1ps// D触发器模块module DFilpFlop(i_state, reset, clk, o_state);    input [2:0]i_state;    input reset, clk;    output reg[2:0]o_state;    always @(posedge clk) begin        if (reset) o_state = 3'b000;        else o_state = i_state;    endendmodule

NextState.v 模块,这是CtrlUnit.v的一个子模块

`timescale 1ns / 1ps// 下一个状态模块module NextState(i_state, opcode, next_state);    input [2:0]i_state;    input [5:0]opcode;    output reg[2:0]next_state;    parameter [2:0] IF = 3'b000, // IF状态                         ID = 3'b001, // ID状态                         aEXE = 3'b110, // add等指令的EXE状态                         bEXE = 3'b101, // beq指令的EXE状态                         cEXE = 3'b010, // sw,lw指令的EXE状态                         MEM = 3'b011, // MEM状态                         aWB = 3'b111, //add等指令的WB状态                         cWB = 3'b100; // lw指令的WB状态    always @(i_state or opcode) begin        case (i_state)            IF: next_state = ID;            ID: begin                case (opcode[5:3])                    3'b111: next_state = IF; // j, jal, jr, halt等指令                    3'b110: begin                        if (opcode == 6'b110100) next_state = bEXE; // beq指令                        else next_state = cEXE; // sw, lw指令                    end                    default: next_state = aEXE; // add, sub等指令                endcase            end            aEXE: next_state = aWB;            bEXE: next_state = IF;            cEXE: next_state = MEM;            MEM: begin                if (opcode == 6'b110001) next_state = cWB; // lw指令                else next_state = IF; // sw指令            end            aWB: next_state = IF;            cWB: next_state = IF;            default: next_state = IF;        endcase    endendmodule

OutputFunc.v 模块,这是CtrlUnit.v的一个子模块,注意到这里的控制信号是根据上面那个表来定义的

`timescale 1ns / 1ps// 输出函数模块module OutputFunc(state, opcode, zero, PCWre, InsMemRW, IRWre, WrRegData, RegWre, ALUSrcB, DataMemRW, ALUM2Reg, ExtSel, RegOut, PCSrc, ALUOp);    input [2:0]state;    input [5:0]opcode;    input zero;    output reg PCWre, InsMemRW, IRWre, WrRegData, RegWre, ALUSrcB, DataMemRW, ALUM2Reg;    output reg[1:0]ExtSel, RegOut, PCSrc;    output reg[2:0]ALUOp;    parameter [2:0] IF = 3'b000, // IF状态                         ID = 3'b001, // ID状态                         aEXE = 3'b110, // add等指令的EXE状态                         bEXE = 3'b101, // beq指令的EXE状态                         cEXE = 3'b010, // sw,lw指令的EXE状态                         MEM = 3'b011, // MEM状态                         aWB = 3'b111, //add等指令的WB状态                         cWB = 3'b100; // lw指令的WB状态    parameter [5:0] addi = 6'b000010,                         ori = 6'b010010,                         sll = 6'b011000,                         add = 6'b000000,                         sub = 6'b000001,                         move = 6'b100000,                         slt = 6'b100111,                         sw = 6'b110000,                         lw = 6'b110001,                         beq = 6'b110100,                         j = 6'b111000,                         jr = 6'b111001,                         Or = 6'b010000,                         And = 6'b010001,                         jal = 6'b111010,                         halt = 6'b111111;    always @(state) begin        // 对PCWre定值        if (state == IF && opcode != halt) PCWre = 1;        else PCWre = 0;        // 对InsMemRW定值        InsMemRW = 1;        // 对IRWre定值        if (state == IF) IRWre = 1;        else IRWre = 0;        // 对WrRegData定值        if (state == aWB || state == cWB) WrRegData = 1;        else WrRegData = 0;        // 对RegWre定值        if (state == aWB || state == cWB || opcode == jal) RegWre = 1;        else RegWre = 0;        // 对ALUSrcB定值        if (opcode == addi || opcode == ori || opcode == sll || opcode == sw || opcode == lw) ALUSrcB = 1;        else ALUSrcB = 0;        // 对DataMemRW定值        if (state == MEM && opcode == sw) DataMemRW = 1;        else DataMemRW = 0;        // 对ALUM2Reg定值        if (state == cWB) ALUM2Reg = 1;        else ALUM2Reg = 0;        // 对ExtSel定值        if (opcode == ori) ExtSel = 2'b01;        else if (opcode == sll) ExtSel = 2'b00;        else ExtSel = 2'b10;        // 对RegOut定值        if (opcode == jal) RegOut = 2'b00;        else if (opcode == addi || opcode == ori || opcode == lw) RegOut = 2'b01;        else RegOut = 2'b10;        // 对PCSrc定值        case(opcode)            j: PCSrc = 2'b11;            jal: PCSrc = 2'b11;            jr: PCSrc = 2'b10;            beq: begin                if (zero) PCSrc = 2'b01;                else PCSrc = 2'b00;            end            default: PCSrc = 2'b00;        endcase        // 对ALUOp定值        case(opcode)            sub: ALUOp = 3'b001;            Or: ALUOp = 3'b101;            And: ALUOp = 3'b110;            ori: ALUOp = 3'b101;            slt: ALUOp = 3'b010;            sll: ALUOp = 3'b100;            beq: ALUOp = 3'b001;            default: ALUOp = 3'b000;        endcase        // 防止在IF阶段写数据        if (state == IF) begin            RegWre = 0;            DataMemRW = 0;        end    endendmodule

PC.v模块

`timescale 1ns / 1ps// PC模块module PC(clk, i_pc, pcWre, reset, o_pc, outside_pc);  input wire clk, pcWre, reset;  input wire [31:0] i_pc, outside_pc;  output reg [31:0] o_pc;  always @(pcWre or reset) begin // 这里和单周期不太一样,存在延迟的问题,只有当pcWre改变的时候或者reset改变的时候再检测    if (reset) begin      o_pc = outside_pc;    end else if (pcWre) begin      o_pc = i_pc;    end else if (!pcWre) begin //停机时候指令不变        o_pc = o_pc;     end  endendmodule

PCAddFour.v模块 PC加4模块

`timescale 1ns / 1ps// PC加4模块module PCAddFour(i_pc, o_pc);  input wire [31:0] i_pc;  output wire [31:0] o_pc;  assign o_pc[31:0] = i_pc[31:0] + 4;endmodule

ROM.v 模块 , 指令寄存器模块

`timescale 1ns / 1ps// 寄存器module ROM (instruction, addr, read_en_, outside_pc);    input read_en_;    input [31:0] addr, outside_pc;    output reg [31:0] instruction;    reg [7:0] mem [0:127]; //最大读取32条指令     initial begin        #1; // 延迟是为了让outside_pc的值能够安全地进来        $readmemb("my_rom_data.coe", mem, outside_pc);          instruction = 0;     end    always @( addr or read_en_)        if (read_en_) begin          instruction[31:24] = mem[addr];          instruction[23:16] = mem[addr+1];          instruction[15:8] = mem[addr+2];          instruction[7:0] = mem[addr+3];        endendmodule

IR.v 模块,IR指令寄存器模块

`timescale 1ns / 1ps// IR指令寄存器,目的是使指令代码保持稳定module IR(i_data, clk, IRWre, o_data);  input clk, IRWre;  input [31:0] i_data;  output reg[31:0] o_data;  always @(negedge clk) begin // 存在延迟的问题,所以用下降沿触发,对数据传输没有什么影响    if (IRWre) begin        o_data = i_data;     end  endendmodule

PCJump.v 模块,用于计算j,jal指令的跳转位置的模块

`timescale 1ns / 1ps// 计算PC直接跳转位置模块module PCJump(PC0, i_addr, o_addr);  input [31:0] PC0;  input [25:0] i_addr;  output reg[31:0] o_addr;  reg [27:0] mid;  always @(i_addr) begin     mid = i_addr << 2;     o_addr <= {PC0[31:28], mid[27:0]};  endendmodule

DataSelect_5_Bit.v 模块,这是用于选择寄存器输入端地址的

`timescale 1ns / 1ps// 数据选择器 (五位数据选择)module DataSelect_5_Bit(A, B, C, Ctrl, S);  input [4:0] A, B, C; // 三个数据  input [1:0]Ctrl; //控制信号  output reg[4:0] S;  always @(Ctrl or A or B or C) begin    case(Ctrl)       2'b00: S = A;        2'b01: S = B;        2'b10: S = C;        default: S = 0; // 给零号寄存器赋值不会有影响,因为寄存器模块不会修改零号寄存器的值     endcase  endendmodule

RegFile.v 模块,寄存器组模块

`timescale 1ns / 1ps// 寄存器组module RegFile (rs, rt, rd, i_data, we, clk, o_data_1, o_data_2);  input [4:0] rs, rt, rd;  input [31:0] i_data;  input we, clk;  output [31:0] o_data_1, o_data_2;  reg [31:0] register [0:31];  initial begin    register[0] = 0; // 只需要确定零号寄存器的值就好,$0恒等于0  end  assign o_data_1 = register[rs];  assign o_data_2 = register[rt];  always @(i_data or rd) begin // 这里有更改,不用CLK上升沿信号触发,因为与CtrlUnit共享CLK会发生延迟问题,导致下一个时钟上升沿才做相应动作    if ((rd != 0) && (we == 1)) begin // rd != 0 是确保零号寄存器不会改变的作用      register[rd] = i_data;    end  endendmodule

DataReg.v 模块,用于上面介绍的ADR、BDR、ALUout、ALUM2DR这些数据延迟小模块

`timescale 1ns / 1ps// 切分数据通路模块module DataReg(i_data, clk, o_data);  input clk;  input [31:0] i_data;  output reg[31:0] o_data;  always @(posedge clk) begin    o_data = i_data;  endendmodule

SignExtend.v模块,数据扩展作用

`timescale 1ns / 1ps// 符号扩展、zero扩展模块module SignExtend(i_num, ExtSel, o_num);  input [15:0] i_num;  input [1:0] ExtSel;  output reg[31:0] o_num;  initial begin    o_num = 0;  end  always @(i_num or ExtSel) begin     case(ExtSel)        2'b00: o_num <= {{27{0}}, i_num[10:6]}; // 扩充 sa        2'b01: o_num <= {{16{0}}, i_num[15:0]}; // 扩充立即数, 如 ori指令        2'b10: o_num <= {{16{i_num[15]}}, i_num[15:0]}; // 符号扩充立即数,如addi、lw、sw、beq指令        default: o_num <= {{16{i_num[15]}}, i_num[15:0]}; // 默认符号扩展    endcase  endendmodule

两个类似的数据选择器,所用地方请看数据通路图

`timescale 1ns / 1psmodule DataSelect_2To1_32Bit(A, B, Ctrl, S);  input [31:0] A, B; //两个数据  input Ctrl; //控制信号  output [31:0] S;  assign S = (Ctrl == 1'b0 ? A : B);endmodule`timescale 1ns / 1psmodule DataSelect_4To1_32Bit(A, B, C, D, Ctrl, S);  input [31:0] A, B, C, D; // 四个数据  input [1:0]Ctrl; //控制信号  output reg[31:0] S;  always @(Ctrl or A or B or C or D) begin    case(Ctrl)       2'b00: S = A;        2'b01: S = B;        2'b10: S = C;        2'b11: S = D;        default: S = 0; // 给零号寄存器赋值不会有影响,因为寄存器模块不会修改零号寄存器的值     endcase  endendmodule

ALU.v 模块,算术逻辑单元

`timescale 1ns / 1ps// ALU模块 ,算术逻辑单元module ALU(A, B, ALUOp, zero, result);  input [31:0] A, B;  input [2:0] ALUOp;  output zero;  output reg [31:0] result;  initial begin        result = 0;  end  assign zero = (result? 0 : 1);  always @(A or B or ALUOp) begin    case(ALUOp)      3'b000: result = A + B;      3'b001: result = A - B;      3'b010: result = (A < B ? 1 : 0);      3'b011: result = A >> B;      3'b100: result = A << B;      3'b101: result = A | B;      3'b110: result = A & B;      3'b111: result = (~A & B) | (A & ~B);      default: result = 0;    endcase  endendmodule

RAM.v模块,注意这次使用对大端模式

`timescale 1ns / 1ps// 内存模块module RAM (i_data, addr, rw, o_data);    input [31:0] i_data;    input [31:0] addr;    input rw;    output reg [31:0] o_data;    reg [7:0] memory [0:63]; // 最多16个数据,因为好像模拟器上限好像是64个寄存器     initial begin        o_data = 0;     end    always @(addr or i_data or rw) begin // 使用大端方式储存,这里有更改(不需要乘4),请注意      if (rw) begin // 1 为 写        memory[addr] = i_data[31:24];          memory[addr+1] = i_data[23:16];          memory[addr+2] = i_data[15:8];          memory[addr+3] = i_data[7:0];      end else begin // 0 为 读        o_data[31:24] = memory[addr];          o_data[23:16] = memory[addr+1];          o_data[15:8] = memory[addr+2];          o_data[7:0] = memory[addr+3];      end    endendmodule 

PCAddImm.v 模块,是用来计算PC加立即数的

`timescale 1ns / 1ps// PC 加立即数模块module PCAddImm(now_pc, addNum, o_pc);  input [31:0] now_pc, addNum;  output [31:0] o_pc;  assign o_pc = now_pc + (addNum << 2);endmodule

测试代码区

test.v 模块,要添加什么观察的变量可以在main模块添加,或者在模拟器增加观察变量,这里就不赘述了,因为这是和单周期CPU类似的代码

`timescale 1ns / 1psmodule test;    // Inputs    reg CLK;    reg RST;    reg [31:0] outside_pc;    // Outputs    wire [31:0] ins, now_pc;    // Instantiate the Unit Under Test (UUT)    Main uut (        .CLK(CLK),         .RST(RST),         .outside_pc(outside_pc),         .ins(ins),        .now_pc(now_pc)    );    initial begin        // Initialize Inputs      CLK = 0;      RST = 1;      outside_pc = 4; // 这里设置外部pc      #50; // 刚开始设置pc为0          CLK = !CLK;      #50;          RST = 0;      forever #50 begin // 产生时钟信号          CLK = !CLK;      end    endendmodule

我测试的代码,可以自己写,仅供参考

// 注意,这里为了测试outside_pc的功能所以初始地址为4// j 3 这里直接跳到第三条指令也就是addi $1, $0, 4111000 00000000000000000000000011// jr  $31111001 11111 000000000000000000000//addi $1, $0, 4000010 00000 00001 0000000000000100//addi $2, $0, 8000010 00000 00010 0000000000001000//sw $2, 0($2)110000 00010 00010 0000000000000000//add $3, $2, $1000000 00010 00001 00011 00000000000//sub $3, $3, $1000001 00011 00001 00011 00000000000//beq $2, $3, -2110100 00010 00011 1111111111111110//ori $1, $1, 1010010 00001 00001 0000000000000001//or $3, $2, $1010000 00010 00001 00011 00000000000//move $3, $2100000 00010 00000 00011 00000000000//and $1, $3, $2010001 00011 00010 00001 00000000000 // sll  $1, $2, 2  ===> 这个时候 $1 = $2 = $3 = 1000, 得到结果是 $1 = 100000011000 00010 00000 00001 00010 000000// slt  $6, $1, $2  ===> 因为 $1 > $2 所以 $6 = 0100111 00001 00010 00110 00000000000// slt  $7, $2, $1  ===> 因为 $1 > $2 所以 $7 = 1100111 00010 00001 00111 00000000000//jal 2111010 00000000000000000000000010//lw $4, 0($2)110001 00010 00100 0000000000000000//halt111111 00000000000000000000000000

二进制文件(my_rom_data.coe)

111000000000000000000000000000111110011111100000000000000000000000001000000000010000000000000100000010000000001000000000000010001100000001000010000000000000000000000000010000010001100000000000000001000110000100011000000000001101000001000011111111111111111001001000001000010000000000000001010000000100000100011000000000001000000001000000000110000000000001000100011000100000100000000000011000000100000000001000100000001001110000100010001100000000000010011100010000010011100000000000111010000000000000000000000000101100010001000100000000000000000011111100000000000000000000000000

最后的一点体会

感觉和单周期CPU设计的思想是差不多的,最复杂的是控制模块,实现了这个模块基本上复杂的都完成了,继续加油!

2 0