自己动手写CPU(2)第一条ori指令
本博客内容基于《自己动手写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指令相关推荐
- 【自己动手写CPU】第一条指令ori的实现
验证过程 实现ori指令->建立最小SOPC->验证ori指令是否正确 ori指令说明 ori是进行逻辑"或"的运算指令 ori指令的指令码是6'b001101.处理器 ...
- 自己动手写CPU(8)加载存储指令的实现
自己动手写CPU(8)加载存储指令的实现 好久没更新blog了,暑假提前放了.现在收假也该收收心了,继续捡起之前的CPU,自己开的坑不管咋样把它填完吧. 指令介绍 1.加载指令 2.存储指令 修改系统 ...
- 【自己动手写CPU】加载存储指令的实现
目标 修改之前一直做测试的sopc,为其添加数据RAM,测试一般加载指令的实现,加入特殊加载存储指令. 探讨由于加载指令引起的load相关问题,给出OpenMIPS的解决方法,验证解决效果. 加载存储 ...
- 自己动手写CPU(5)——移动指令说明
移动指令说明 移动操作指令 特殊寄存器HI.LO 移动指令确定过程 移动操作指令 不涉及特殊寄存器LO.HI: movn:判断地址为rt的通用寄存器的值,如果不为零,将地址为rs的通用寄存器的值赋给地 ...
- 自己动手写CPU(5)简单算术操作指令实现_1
自己动手写CPU(5)简单算数操作指令实现_1 指令介绍 MIPS32指令集架构定义的所有算术操作指令,共有21条 共有三类,分别是: 简单算术指令 乘累加.乘累减指令 除法指令 算术指令操作介绍 一 ...
- 《自己动手写CPU》第五章--逻辑、移位操作与空指令的实现
5.1流水线数据相关问题 流水线中经常有一些被称为"相关"的情况发生,它使得指令序列中下一条指令无法按照设计的时钟周期执行,这些"相关"会降低流水线的性能.流水 ...
- 自己动手写CPU(1)五级流水线及CPU第一条指令ori
自己动手写CPU(1)五级流水线及CPU第一条指令ori 动机 不知为何研一的自由时间突然多起来,可能人一闲下来就容易焦虑吧,hhhhhh.正好之前看到一本<自己动手写CPU>,就按照此书 ...
- 自己动手写CPU(6)流水线暂停、乘累加减与除法器的实现
自己动手写CPU(6)流水线暂停.乘累加减与除法器的实现 流水线暂停 因为OpenMIPS设计乘累加.乘累减.除法指令在流水线执行阶段占用多个时钟周期,因此需要暂停流水线,以等待这些多周期指令执行完毕 ...
- 自己动手写CPU(2)流水线数据相关问题
自己动手写CPU(2)流水线数据相关问题 问题定义 流水线中经常有一些被称为"相关"的情况发生,它使得指令序列中下一条指令无法按照设计的时钟周期执行,这些"相关" ...
最新文章
- 用一个栈实现另一个栈的排序
- Nginx初学第一步
- Matlab中下标、斜体及希腊字母的使用方法
- Intel CPU内存屏障
- 第一次冲刺个人博客07
- 第七周linux内核分析
- FreeMarker_模板引擎_代码自动生成器_源码下载
- Linux下安装MySQL数据库、禅道
- c#划分目录和文件(小白的一点经验)
- solr学习笔记-linux下配置solr
- SQL常用语句(普通查询+条件查询)
- chrom浏览器flash_flash插件
- SEGGER Embedded Studio 搭建开发环境
- Mac解决Error: No such file or directory @ rb_sysopen报错问题
- cesium模型爆炸案例
- vue中改变v-html元素样式
- 浅谈 Java 中的排序
- C语言fscanf函数的理解
- 【软考系统架构设计师】计算机网络章节习题集
- C#批量修改文件后缀
热门文章
- 【通俗易懂】关系模式范式分解教程 3NF与BCNF口诀!小白也能看懂
- 2021.06.03合并石子+能量项链
- Ubuntu 18.04 安装ROS遇到的问题
- 每日一题/001/微积分/递推公式求定积分
- CentOS 7 安装天文学工具presto
- PayPal case系统
- 励志英文演讲--------Dream(梦想)
- ios10 关于app info.plist权限设置
- deep features for text spotting 在windows上使用
- C#项目中没有App.config文件,手动添加方法