本博客内容基于《自己动手写CPU》这本书

上一篇文章介绍了一下流水线思想、设计流程等,下面我们可以实操一下实现第一条ori指令。

其实实现一条ori指令不难,我目前对这一条指令的理解简单来说就是,先看图对应每一个接口连线。

ori指令说明

ori是进行逻辑“或”运算的指令,指令格式如下图所示

指令用法为:ori rs,rt,immediate,将指令中的16位立即数immediate进行无符号拓展至32位,然后与地址为rs的通用寄存器进行逻辑“或”运算,将运算结果保存至地址为rt的通用寄存器中。

原始OpenMIPS五级流水线结构

首先看图,在上一篇文章介绍了五级流水线,这里就不在赘述了。下图是实现一条ori指令的五级流水线结构,在后续的学习中我们会在每个阶段增加一点,到最后形成一个OpenMIPS32五级流水线。

下图是原始OpenMIPS五级流水线系统结构图

然后就是将你现在看到的线通过各个模块连接起来。(我把宏定义放在最后了)

取指阶段

用于给出指令地址,其 I/O 端口如下

PC模块代码:

`include "defines.v"module pc_reg(input wire                clk,input wire                rst,output reg[`InstAddrBus]  pc,output reg                ce
);always @(posedge clk) beginif(rst == `RstEnable) begince <= `ChipDisable;   //复位时指令存储器禁用endelse begince <= `ChipEnable;    //复位结束后使能指令存储器endendalways @(posedge clk) beginif(ce == `ChipDisable) beginpc <= 32'h00000000;   //指令存储器禁用时,PC为0endelse beginpc <= pc + 4'h4;      //指令存储器使能时,PC的值每时钟周期加4end endendmodule

取指/译码模块

用于暂时保存取指得到的指令,以及地址,在下一个时钟周期送给译码阶段,其 I/O 端口如下

if_id 模块代码:

`include "defines.v"module if_id(input wire              rst,input wire              clk,//来自取值阶段的信号,InstBus表示指令宽度为32input wire [`InstBus]   if_inst,//对应的译码阶段的信号output reg [`InstBus]   id_inst
);always @(posedge clk) beginif(rst == `RstEnable) beginid_inst <= `ZeroWord;endelse beginid_inst <= if_inst;endendendmodule

译码模块

将得到的指令1.给出运算类型 2.给出参与运算的操作数

Regfile模块

实现了32个32位通用整数寄存器,可以同时进行两个寄存器的读操作和一个寄存器的写操作,其 I/O 端口如下

模块代码:

`include "defines.v"module regfile(input wire                clk,input wire                rst,//写端口input wire we,input wire[`RegAddrBus]   waddr,input wire[`RegBus]       wdata,//读端口1input wire                re1,input wire[`RegAddrBus]   raddr1,output reg[`RegBus]       rdata1,//读端口2input wire                re2,input wire[`RegAddrBus]   raddr2,output reg[`RegBus]       rdata2
);//定义32个位宽为32的通用寄存器
reg [`RegBus] regs[0:`RegNum-1];//写操作
always @(posedge clk) beginif(rst == `RstDisable) beginif((we == `WriteEnable) && (waddr != `RegNumLog2'h0)) begin   //寄存器0不可写regs[waddr] <= wdata;endend
end
//MIPS32架构规定$0的值只能为0//读操作1,组合逻辑
always @(*) beginif(rst == `RstEnable) beginrdata1 <= `ZeroWord;endelse if(raddr1 == `RegNumLog2'h0) beginrdata1 <= `ZeroWord;endelse if((re1 == `ReadEnable) && (we == `WriteEnable) && (waddr == raddr1)) beginrdata1 <= wdata;endelse if(re1 == `ReadEnable) beginrdata1 <= regs[raddr1];endelse beginrdata1 <= `ZeroWord;end
end//读操作2
always @(*) beginif(rst == `RstEnable) beginrdata2 <= `ZeroWord;endelse if(raddr2 == `RegNumLog2'h0) beginrdata2 <= `ZeroWord;endelse if((re2 == `ReadEnable) && (we == `WriteEnable) && (waddr == raddr2)) beginrdata2 <= wdata;endelse if(re2 == `ReadEnable) beginrdata2 <= regs[raddr2];endelse beginrdata2 <= `ZeroWord;end
endendmodule

ID模块

对指令进行译码,得到最终的运算类型、子类型、源操作数1 2、要写入的目的寄存器等,其 I/O 端口如下

模块代码:

`include "defines.v"module id(input wire                rst,input wire [`InstBus]     inst_i,//读取的Regfile的值input wire[`RegBus]       reg1_data_i,input wire[`RegBus]       reg2_data_i,//输出到Regfile的信息output reg                reg1_read_o,output reg                reg2_read_o,output reg [`RegAddrBus]  reg1_addr_o,output reg [`RegAddrBus]  reg2_addr_o,//送到执行阶段的信息output reg[`AluSelBus]    alusel_o,output reg[`AluOpBus]     aluop_o,output reg[`RegBus]       reg1_o,output reg[`RegBus]       reg2_o,output reg[`RegAddrBus]   wd_o,       //译码阶段的指令要写入的目的寄存器地址output reg                wreg_o      //译码阶段的指令是否有要写入的目的寄存器
);//取得指令的指令码与功能码wire [5:0] op = inst_i[31:26];wire [4:0] op2 = inst_i[10:6];wire [5:0] op3 = inst_i[5:0];wire [4:0] op4 = inst_i[20:16];//保存指令执行需要的立即数reg[`RegBus] imm;//指示指令是否有效reg instvalid;//第一段:对指令进行译码always @(*) beginif(rst == `RstEnable) beginaluop_o = `EXE_NOP_OP;alusel_o = `EXE_RES_NOP;wd_o = `NOPRegAddr;wreg_o = `WriteDisable;instvalid = `InstInvalid;reg1_read_o = `ReadDisable;reg2_read_o = `ReadDisable;reg1_addr_o = `NOPRegAddr;reg2_addr_o = `NOPRegAddr;imm = `ZeroWord;endelse begincase(op)`EXE_ORI:beginaluop_o = `EXE_OR_OP;alusel_o = `EXE_RES_LOGIC;wd_o = inst_i[20:16];wreg_o = `WriteEnable;instvalid = `InstValid;reg1_read_o = `ReadEnable;reg2_read_o = `ReadDisable;reg1_addr_o = inst_i[25:21];reg2_addr_o = inst_i[20:16];imm = {16'h0,inst_i[15:0]};enddefault:beginaluop_o = `EXE_NOP_OP;alusel_o = `EXE_RES_NOP;wd_o = inst_i[15:11];wreg_o = `WriteDisable;instvalid = `InstInvalid;reg1_read_o = `ReadDisable;reg2_read_o = `ReadDisable;reg1_addr_o = inst_i[25:21];reg2_addr_o = inst_i[20:16];imm = `ZeroWord;endendcaseendend//确定进行运算的操作数1
always @(*) beginif(rst == `RstEnable) beginreg1_o = `ZeroWord;endelse if(reg1_read_o == 1'b1) beginreg1_o = reg1_data_i;endelse if(reg1_read_o == 1'b0) beginreg1_o = imm;endelse beginreg1_o = `ZeroWord;end
end//确定进行运算的操作数2
always @(*) beginif(rst == `RstEnable) beginreg2_o = `ZeroWord;endelse if(reg2_read_o == 1'b1) beginreg2_o = reg2_data_i;endelse if(reg2_read_o == 1'b0) beginreg2_o = imm;endelse beginreg2_o = `ZeroWord;end
endendmodule

译码/执行模块

将译码阶段信息在下一个时钟周期给执行阶段,其 I/O 端口如下

模块代码:

`include "defines.v"module id_ex(input wire              clk,input wire              rst,//从译码阶段传递过来的信息input wire[`AluSelBus]  id_alusel,input wire[`AluOpBus]   id_aluop,input wire[`RegBus]     id_reg1,input wire[`RegBus]     id_reg2,input wire[`RegAddrBus] id_wd,  //执行阶段的指令要写入的目的寄存器的地址input wire              id_wreg,//执行阶段的指令是否有要写入的目的寄存器//传递到执行阶段的信息output reg[`AluSelBus]  ex_alusel,output reg[`AluOpBus]   ex_aluop,output reg[`RegBus]     ex_reg1,output reg[`RegBus]     ex_reg2,output reg[`RegAddrBus] ex_wd,output reg              ex_wreg
);always @(posedge clk) beginif(rst == `RstEnable) beginex_alusel <= `EXE_RES_NOP;ex_aluop <= `EXE_NOP_OP;ex_reg1 <= `ZeroWord;ex_reg2 <= `ZeroWord;ex_wd <= `NOPRegAddr;ex_wreg <= `WriteDisable;endelse beginex_alusel <= id_alusel;ex_aluop <= id_aluop;ex_reg1 <= id_reg1;ex_reg2 <= id_reg2;ex_wd <= id_wd;ex_wreg <= id_wreg;endendendmodule

执行模块

根据 ID/EX 得到的数据进行运算,其 I/O 端口如下

模块代码:

`include "defines.v"module ex(input wire              rst,//译码阶段送到执行阶段的信息input wire[`AluSelBus]  alusel_i,input wire[`AluOpBus]   aluop_i,input wire[`RegBus]     reg1_i,input wire[`RegBus]     reg2_i,input wire[`RegAddrBus] wd_i,input wire              wreg_i,//执行的结果output reg[`RegAddrBus] wd_o,       //执行阶段的结果最终要写入的目的寄存器的地址output reg wreg_o,output reg[`RegBus] wdata_o         //执行阶段最终要写入目的寄存器的值
);//保存逻辑运算的结果reg [`RegBus] logicout;//根据aluop指示的运算子类型进行运算,此处只有逻辑或运算always @(*) beginif(rst == `RstEnable) beginlogicout = `ZeroWord;endelse begincase(aluop_i)`EXE_OR_OP:  logicout = reg1_i | reg2_i;default:    logicout = `ZeroWord;endcaseend  end//根据alusel指示的运算类型,选择一个运算结果作为最终结果//此时只有逻辑运算结果always @(*) beginwd_o = wd_i;wreg_o = wreg_i;case(alusel_i)`EXE_RES_LOGIC:     wdata_o = logicout;default:            wdata_o = `ZeroWord;endcaseendendmodule

执行/访存模块

将执行阶段得到的结果在下一个时钟周期传到访存阶段,其 I/O 端口如下

模块代码:

`include "defines.v"module ex_mem(input wire              clk,input wire              rst,//来自执行阶段的信息input wire[`RegAddrBus] ex_wd,input wire              ex_wreg,input wire[`RegBus]     ex_wdata,//送到访存阶段的信息output reg[`RegAddrBus] mem_wd,output reg              mem_wreg,output reg[`RegBus]     mem_wdata
);always @(posedge clk) beginif(rst == `RstEnable) beginmem_wd <= `NOPRegAddr;mem_wreg <= `WriteDisable;mem_wdata <= `ZeroWord;endelse beginmem_wd <= ex_wd;mem_wreg <= ex_wreg;mem_wdata <= ex_wdata;endendendmodule

访存模块

由于ori指令在访存阶段不需要访问数据寄存器,所以在访存阶段不做任何事,只是简单传递数据到回写阶段,其 I/O 端口如下

模块代码:

`include "defines.v"module mem(input wire                  rst,//来自执行阶段的信息input wire[`RegAddrBus]     wd_i,input wire                  wreg_i,input wire[`RegBus]         wdata_i,//访存阶段的结果output reg[`RegAddrBus]     wd_o,output reg                  wreg_o,output reg[`RegBus]         wdata_o
);always @(*) beginif(rst == `RstEnable) beginwd_o = `NOPRegAddr;wreg_o = `WriteDisable;wdata_o = `ZeroWord;endelse beginwd_o = wd_i;wreg_o = wreg_i;wdata_o = wdata_i;endendendmodule

访存/回写阶段

将访存阶段的结果在下一时钟周期传到回写阶段,其 I/O 端口如下

模块代码:

`include "defines.v"module mem_wb(input wire                  clk,input wire                  rst,//访存阶段的结果input wire[`RegAddrBus]     mem_wd,input wire                  mem_wreg,input wire[`RegBus]         mem_wdata,//送到回写阶段的信息output reg[`RegAddrBus]     wb_wd,output reg                  wb_wreg,output reg[`RegBus]         wb_wdata
);always @(posedge clk) beginif(rst == `RstEnable) beginwb_wd <= `NOPRegAddr;wb_wreg <= `WriteDisable;wb_wdata <= `ZeroWord;endelse beginwb_wd <= mem_wd;wb_wreg <= mem_wreg;wb_wdata <= mem_wdata;endendendmodule

回写阶段

参考上面五级流水线,此时这个阶段实际上是在Regfile模块中实现的,将上一模块得到的值传到Regfile。

顶层模块

每个模块都完成后,我们现在需要将各个模块进行例化、连接,连接的关系还是看上面的图。

例化其实也就相当于面向对象语言中实例化一个对象出来,然后将各个对象连接起来就可以得到我们的顶层模块

下面我们看看顶层模块的端口

当然,我们现在只是实现一条简单的ori指令,所以顶层模块会比较简单,等到后期指令增加、增加协处理器、中断处理的时候顶层模块就会复杂很多,不过还是像上面说的一样--看图,连线

模块代码:

`include "defines.v"module openmips(input wire                  clk,input wire                  rst,input wire[`InstBus]        rom_data_i,output wire[`InstAddrBus]   rom_addr_o,output wire                 rom_ce_o
);//连接IF/ID模块与译码阶段ID模块的变量wire[`InstBus]  id_inst_i;//连接译码阶段ID模块与通用寄存器Regfile模块的变量wire reg1_read;wire reg2_read;wire [`RegBus] reg1_data;wire [`RegBus] reg2_data;wire [`RegAddrBus] reg1_addr;wire [`RegAddrBus] reg2_addr;//连接译码阶段ID模块输出与ID/EX模块的输入的变量wire [`AluOpBus] id_aluop_o;wire [`AluSelBus] id_alusel_o;wire [`RegBus] id_reg1_o;wire [`RegBus] id_reg2_o;wire id_wreg_o;wire [`RegAddrBus] id_wd_o;//连接ID/EX模块输出与执行阶段EX模块输入的变量wire [`AluOpBus] ex_aluop_i;wire [`AluSelBus] ex_alusel_i;wire [`RegBus] ex_reg1_i;wire [`RegBus] ex_reg2_i;wire [`RegAddrBus] ex_wd_i;wire ex_wreg_i;//连接执行阶段EX模块输出与EX/MEM模块的输入的变量wire [`RegBus] ex_wdata_o;wire [`RegAddrBus] ex_wd_o;wire ex_wreg_o;//连接EX/MEM模块输出与访存MEM模块输入的变量wire [`RegBus] mem_wdata_i;wire [`RegAddrBus] mem_wd_i;wire mem_wreg_i;//连接MEM模块输出与MEM/WB模块输入的变量wire [`RegBus] mem_wdata_o;wire [`RegAddrBus] mem_wd_o;wire mem_wreg_o;//连接MEM/WB模块输出与寄存器堆模块输入的变量wire [`RegBus] wb_wdata_o;wire [`RegAddrBus] wb_wd_o;wire wb_wreg_o;//pc_reg例化pc_reg pc_reg0(.clk(clk),    .rst(rst),    .pc(rom_addr_o),    .ce(rom_ce_o));//IF/ID模块例化if_id if_id0(.rst(rst),    .clk(clk),    .if_inst(rom_data_i),    .id_inst(id_inst_i));//译码阶段ID模块例化id id0(.rst(rst),    .inst_i(id_inst_i),.reg1_data_i(reg1_data),    .reg2_data_i(reg2_data),.reg1_read_o(reg1_read),    .reg2_read_o(reg2_read),.reg1_addr_o(reg1_addr),    .reg2_addr_o(reg2_addr),.alusel_o(id_alusel_o),    .aluop_o(id_aluop_o),.reg1_o(id_reg1_o),    .reg2_o(id_reg2_o),.wd_o(id_wd_o),    .wreg_o(id_wreg_o)      );//通用寄存器Regfile模块例化regfile regfile0(.clk(clk),    .rst(rst),.we(wb_wreg_o),    .waddr(wb_wd_o),    .wdata(wb_wdata_o),.re1(reg1_read),    .raddr1(reg1_addr),    .rdata1(reg1_data),.re2(reg2_read),    .raddr2(reg2_addr),    .rdata2(reg2_data));//ID/EX模块例化id_ex id_ex0(.clk(clk),    .rst(rst),.id_alusel(id_alusel_o),    .id_aluop(id_aluop_o),.id_reg1(id_reg1_o),    .id_reg2(id_reg2_o),.id_wd(id_wd_o),      .id_wreg(id_wreg_o),.ex_alusel(ex_alusel_i),    .ex_aluop(ex_aluop_i),.ex_reg1(ex_reg1_i),    .ex_reg2(ex_reg2_i),.ex_wd(ex_wd_i),    .ex_wreg(ex_wreg_i));//EX模块例化ex ex0(.rst(rst),.alusel_i(ex_alusel_i),    .aluop_i(ex_aluop_i),.reg1_i(ex_reg1_i),    .reg2_i(ex_reg2_i),.wd_i(ex_wd_i),    .wreg_i(ex_wreg_i),.wd_o(ex_wd_o),    .wreg_o(ex_wreg_o),    .wdata_o(ex_wdata_o));//EX/MEM模块例化ex_mem ex_mem0(.clk(clk),    .rst(rst),.ex_wd(ex_wd_o),    .ex_wreg(ex_wreg_o),    .ex_wdata(ex_wdata_o),.mem_wd(mem_wd_i),    .mem_wreg(mem_wreg_i),    .mem_wdata(mem_wdata_i));//MEM模块例化mem mem0(.rst(rst),.wd_i(mem_wd_i),    .wreg_i(mem_wreg_i),    .wdata_i(mem_wdata_i),.wd_o(mem_wd_o),    .wreg_o(mem_wreg_o),    .wdata_o(mem_wdata_o));//MEM/WB模块例化mem_wb mem_wb0(.clk(clk),    .rst(rst),.mem_wd(mem_wd_o),    .mem_wreg(mem_wreg_o),    .mem_wdata(mem_wdata_o),.wb_wd(wb_wd_o),    .wb_wreg(wb_wreg_o),    .wb_wdata(wb_wdata_o));endmodule

代码看着比较长,但实际其本质都是一样的,懂了一块其他模块都懂了(不要放弃,加油!)

指令存储器ROM的实现

顾名思义,只读存储器,与openMIPS相连再构成最小SOPC

模块代码:

`include "defines.v"module inst_rom(input wire                  ce,input wire[`InstAddrBus]    addr,output reg[`InstBus]        inst
);//定义一个数组,大小是InstMemNum,元素宽度是InstBusreg [`InstBus] inst_mem[0:`InstMemNum-1];//使用文件inst_rom.data初始化寄存器,依据自己的路径给data文件改成绝对路径initial $readmemh ("D:/inst_rom.data",inst_mem);//当复位信号无效时,依据输入的地址,给出指令存储器ROM中对应的元素always @(*) beginif(ce == `ChipDisable) begininst <= `ZeroWord;endelse begin//指令寄存器的每个地址是32bit的字,所以要将OpenMips给出的指令地址除以4再使用inst <= inst_mem[addr[`InstMemNumLog2+1:2]];endendendmodule

⚠️注意注意!

这个读取文件的路径一定要用绝对路径!!!!

最小SOPC的实现

上面说过,将openMIPS与inst_rom连接成为一个最小SOPC

建立Test Bench文件

在上一篇文章讲过Test Bench文件

将各个模块设计完成后,通过test Bench文件,test Bench文件为测试或仿真一个Verilog HDL程序搭建了一个平台,我们被测试的模块施加激励信号,通过观察被测试模块的输出响应,从而判断逻辑是否正确。

模块代码:

//时间单位是1ns,精度是1ps
`timescale 1ns/1ps
`include "defines.v"module openmips_min_sopc_tb();reg CLOCK_50;reg rst;//每隔10ns,CLOCK_50信号翻转一次,所以一个周期是20ns,对应50MHzinitial beginCLOCK_50 = 1'b0;forever #10 CLOCK_50 = ~CLOCK_50;end//最初时刻,复位信号有效,在第195ns,复位信号无效,最小SOPC开始运行//运行1000ns后,暂停仿真initial beginrst = `RstEnable;#195 rst = `RstDisable;#1000 $stop;end//例化最小SOPCopenmips_min_sopc openmips_min_sopc0(.clk(CLOCK_50),.rst(rst));endmodule

之后将所有文件放在一起仿真就可以得到结果啦!

总结

·看图将各个模块根据图的描述写出来,再将各个模块例化连接起来(顶层模块),将顶层模块与存储器连接后建立最小SOPC,最后给SOPC激励信号进行仿真。

·交叉编译环境在这里还没有提到,其实就是通过GNU工具链对你的源代码(汇编代码)进行编译、链接、得到bin文件 最后将格式转化就可以得到我们需要的存储器文件inst_rom.data

宏定义代码

//全局宏定义
`define RstEnable 1'b1          //复位信号有效
`define RstDisable 1'b0         //复位信号无效
`define ChipEnable 1'b1         //芯片使能
`define ChipDisable 1'b0        //芯片禁止
`define ZeroWord 32'h00000000   //32位的数值0
`define WriteEnable 1'b1        //使能写
`define WriteDisable 1'b0       //禁止写
`define ReadEnable 1'b1         //使能读
`define ReadDisable 1'b0        //禁止读
`define AluSelBus 2:0           //译码阶段的输出alusel_o的宽度
`define AluOpBus 7:0            //译码阶段的输出aluop_o的宽度
`define InstValid 1'b1          //指令有效
`define InstInvalid 1'b0        //指令无效//与指令存储器相关的定义
`define InstAddrBus     31:0    //ROM的地址总线宽度
`define InstBus     31:0        //ROM的数据总线宽度
`define InstMemNum 131071       //ROM的实际大小为128KB
`define InstMemNumLog2  17      //ROM实际使用的地址线宽度//与通用寄存器Regfile有关的宏定义
`define RegAddrBus 4:0          //Regfile模块的地址线宽度
`define RegBus 31:0             //Regfile模块的数据线宽度
`define RegNum 32               //通用寄存器的数量
`define RegNumLog2 5            //寻址通用寄存器所用的地址位数
`define NOPRegAddr  5'b00000//与具体指令相关的宏定义
`define EXE_ORI     6'b001101   //指令ori的指令码
`define EXE_NOP     6'b000000//AluOp
`define EXE_OR_OP   8'b00100101
`define EXE_NOP_OP  8'b00000000//AluSel
`define EXE_RES_LOGIC   3'b001
`define EXE_RES_NOP     3'b000

自己动手写CPU(2)第一条ori指令相关推荐

  1. 【自己动手写CPU】第一条指令ori的实现

    验证过程 实现ori指令->建立最小SOPC->验证ori指令是否正确 ori指令说明 ori是进行逻辑"或"的运算指令 ori指令的指令码是6'b001101.处理器 ...

  2. 自己动手写CPU(8)加载存储指令的实现

    自己动手写CPU(8)加载存储指令的实现 好久没更新blog了,暑假提前放了.现在收假也该收收心了,继续捡起之前的CPU,自己开的坑不管咋样把它填完吧. 指令介绍 1.加载指令 2.存储指令 修改系统 ...

  3. 【自己动手写CPU】加载存储指令的实现

    目标 修改之前一直做测试的sopc,为其添加数据RAM,测试一般加载指令的实现,加入特殊加载存储指令. 探讨由于加载指令引起的load相关问题,给出OpenMIPS的解决方法,验证解决效果. 加载存储 ...

  4. 自己动手写CPU(5)——移动指令说明

    移动指令说明 移动操作指令 特殊寄存器HI.LO 移动指令确定过程 移动操作指令 不涉及特殊寄存器LO.HI: movn:判断地址为rt的通用寄存器的值,如果不为零,将地址为rs的通用寄存器的值赋给地 ...

  5. 自己动手写CPU(5)简单算术操作指令实现_1

    自己动手写CPU(5)简单算数操作指令实现_1 指令介绍 MIPS32指令集架构定义的所有算术操作指令,共有21条 共有三类,分别是: 简单算术指令 乘累加.乘累减指令 除法指令 算术指令操作介绍 一 ...

  6. 《自己动手写CPU》第五章--逻辑、移位操作与空指令的实现

    5.1流水线数据相关问题 流水线中经常有一些被称为"相关"的情况发生,它使得指令序列中下一条指令无法按照设计的时钟周期执行,这些"相关"会降低流水线的性能.流水 ...

  7. 自己动手写CPU(1)五级流水线及CPU第一条指令ori

    自己动手写CPU(1)五级流水线及CPU第一条指令ori 动机 不知为何研一的自由时间突然多起来,可能人一闲下来就容易焦虑吧,hhhhhh.正好之前看到一本<自己动手写CPU>,就按照此书 ...

  8. 自己动手写CPU(6)流水线暂停、乘累加减与除法器的实现

    自己动手写CPU(6)流水线暂停.乘累加减与除法器的实现 流水线暂停 因为OpenMIPS设计乘累加.乘累减.除法指令在流水线执行阶段占用多个时钟周期,因此需要暂停流水线,以等待这些多周期指令执行完毕 ...

  9. 自己动手写CPU(2)流水线数据相关问题

    自己动手写CPU(2)流水线数据相关问题 问题定义 流水线中经常有一些被称为"相关"的情况发生,它使得指令序列中下一条指令无法按照设计的时钟周期执行,这些"相关" ...

最新文章

  1. 用一个栈实现另一个栈的排序
  2. Nginx初学第一步
  3. Matlab中下标、斜体及希腊字母的使用方法
  4. Intel CPU内存屏障
  5. 第一次冲刺个人博客07
  6. 第七周linux内核分析
  7. FreeMarker_模板引擎_代码自动生成器_源码下载
  8. Linux下安装MySQL数据库、禅道
  9. c#划分目录和文件(小白的一点经验)
  10. solr学习笔记-linux下配置solr
  11. SQL常用语句(普通查询+条件查询)
  12. chrom浏览器flash_flash插件
  13. SEGGER Embedded Studio 搭建开发环境
  14. Mac解决Error: No such file or directory @ rb_sysopen报错问题
  15. cesium模型爆炸案例
  16. vue中改变v-html元素样式
  17. 浅谈 Java 中的排序
  18. C语言fscanf函数的理解
  19. 【软考系统架构设计师】计算机网络章节习题集
  20. C#批量修改文件后缀

热门文章

  1. 【通俗易懂】关系模式范式分解教程 3NF与BCNF口诀!小白也能看懂
  2. 2021.06.03合并石子+能量项链
  3. Ubuntu 18.04 安装ROS遇到的问题
  4. 每日一题/001/微积分/递推公式求定积分
  5. CentOS 7 安装天文学工具presto
  6. PayPal case系统
  7. 励志英文演讲--------Dream(梦想)
  8. ios10 关于app info.plist权限设置
  9. deep features for text spotting 在windows上使用
  10. C#项目中没有App.config文件,手动添加方法