手搓单周期、流水线CPU
实验指导书连接实验概述 - 计算机设计与实践(2022夏季) | 哈工大(深圳) (gitee.io)
实现的18条指令如下: 【注释:(r)表示寄存器r的值,Mem[addr]表示地址为addr的存储单元的值,sext(a)表示a的符号扩展】
加(rd)ß(rs1)+(rs2)
减(rd)ß(rs1)-(rs2)
与(rd)ß(rs1)&(rs2)
或(rd)ß(rs1)|(rs2)
异或(rd)ß(rs1)^(rs2)
左移(rd)ß(rs1)<<(rs2)
逻辑右移(rd)ß(rs1)>>(rs2)
算术右移(rd)ß($signed(rs1))>>(rs2)
加立即数(rd)ß(rs1)+sext(imm)
与立即数(rd)ß(rs1)&sext(imm)
或立即数(rd)ß(rs1)|sext(imm)
异或立即数(rd)ß(rs1)^sext(imm)
左移立即数位(rd)ß(rs1)<<shamt
逻辑右移立即数位(rd)ß(rs1)>>shamt
算数右移立即数(rd)ß ($signed(rs1))>>shamt
取数(rd)ßsext(Mem[(rs1)+sext(offset)][31:0]
跳转tß(pc)+4;(pc)ß((rs1)+sext(offset))&~1;(rd)ßt(将原来的pc+4的值写入寄存器rd,将pc设置为(rs1)+sext(offset),把计算出的地址的最低位设为0)
存数Mem[(rs1)+sext(offset)]ß(rs2)[31:0]
相等则跳转if((rs1)==(rs2))(pc)ß(pc)+sext(offset)
不等则跳转if((rs1)≠(rs2))(pc)ß(pc)+sext(offset)
小于则跳转if((rs1)<(rs2))(pc)ß(pc)+sext(offset)(有符号数)
大于等于则跳转if((rs1)≥(rs2))(pc)ß(pc)+sext(offset)(有符号数)
取长立即数(rd)ßsext(imm[31:12]<<12)
跳转(rd)ß(pc)+4; (pc)ß(pc)+sext(offset) 按照指导书,单周期时钟频率使用25mhz,流水线频率使用50mhz皆成功。单周期未做更高频率的尝试,流水线cpu频率成功上板最高为180mhz。 |
设计的主要特色(除基本要求以外的设计) |
流水线CPU设计中,对于不涉及访存的数据冒险,RAW冒险的三种情形均采用前递的方式解决,提高执行效率;对于涉及访存的数据冒险,采用先停顿后续指令一个时钟周期,再前递的方式解决;对于控制冒险,采用静态预测的方式解决,预测分支指令总是不跳转,若在分支指令到达执行阶段时发现预测错误,则将后续已传入错误指令的流水级清空,以在下一个时钟周期传入正确的指令。 |
资源使用、功耗数据截图(Post Implementation;含单周期、流水线2个截图) |
以下是示例,请贴自己的图。 单周期25mhz 流水线50mhz 流水线100mhz 流水线180mhz |
1 单周期CPU设计与实现
1.1 单周期CPU整体框图
要求:无需画出模块内的具体逻辑,但要标出模块的接口信号名、模块之间信号线的信号名和位宽,以及说明每个模块的功能含义。 |
各个模块功能: pc:更新pc 指令IM:指令寄存器 寄存器堆regfile:从此获取32个寄存器存储内容 控制单元control:给出控制信号 比较器BranchComp:获取相应比较结果 计算器ALU:获取相应计算结果 数据寄存器DM:根据所给地址获得内存内容 MUX_WB:选择写回数据寄存器的内容 |
1.2 单周期CPU模块详细设计
要求:画出各个模块的详细设计图,包含内部的子模块,以及关键性逻辑;标出子模块接口信号名、各信号线的信号名和位宽,并有详细的解释说明。 |
next_pc的赋值采用组合逻辑,当pcSel为0时表示跳转,被赋为计算出来的地址from_alu;当pcSel为1时表示不跳转,被赋为pc4(恒为pc+4)。复位信号rst无效一个时钟周期后的时钟上升沿信号rst_p无效。current_pc的赋值采用时序逻辑,在每个时钟上升沿,当rst_p有效时,被赋值为0;无效时,被赋值为next_pc。以实现pc的更新。 控制信号的赋值均采用组合逻辑。 pcSel:根据opcode判断指令类型,当指令为R型指令、I型指令、LW指令、S型指令、U型指令时,指令不跳转,pcSel设为1;当指令为B型指令时,由比较器结果判断指令跳转与否,pcSel设为brAns;当指令为J型指令或jalr指令,指令跳转,pcSel设为0;其余情况默认指令不跳转,pcSel设为1。 regWEn:当指令为S型指令或B型指令时,不写寄存器,regWEn设为0,否则设为1。 immSel:根据opcode判断指令类型选择如何对立即数进行扩展。当指令为I型指令、LW指令、jalr指令时,immSel设为`I_SEXT;当指令为S型指令时,immSel设为`S_SEXT ;当指令为B型指令时,immSel设为`B_SEXT;当指令为U型指令时,immSel设为`U_SEXT;当指令为J型指令时,immSel设为`J_SEXT;其余情况默认immSel设为3’b111。 brOp:当指令类型为B型指令时,比较器做何比较由funct3决定,直接将brOp设为funct3;其余情况默认brOp设为3’b111。 aSel:根据指令类型判断ALU第一个操作数。当指令类型为B型指令或J型指令时, aSel设为0;否则aSel设为1。 bSel:根据指令类型判断ALU第二个操作数。当指令类型为R型指令时, bSel设为0;否则bSel设为1。 aluSel:当指令类型为R型指令时,根据funct3和funct7判断计算器进行的操作类型,分别将aluSel设为`SUB、`ADD、`AND、`OR、`XOR、`SLL、`SRL、`SRA,其它情况默认为`NOOP;当指令类型为I型指令时,根据funct3和funct7判断计算器进行的操作类型,分别将aluSel设为`ADD、`AND、`OR、`XOR、`SLL、`SRL、`SRA,其它情况默认为`NOOP;当指令为LW指令、jalr指令、S型指令、B型指令、J型指令时,aluSel设为`ADD;当指令为U型指令时,aluSel设为`LUI;其余情况默认aluSel设为`NOOP。 memRW:根据指令类型判断读写内存。当指令类型为S型指令时需要写内存,memRW设为1;其余情况默认不写内存,设为0。 wbSel:根据指令类型选择写回寄存器的内容。当指令类型为J型指令、jalr指令时, wbSel设为`PC4;当指令为LW指令时, wbSel设为`FROM_DM;其余情况默认wbSel设为`FROM_ALU。 读寄存器采用时序逻辑,每个时钟下降沿来临时,若rR1不是0号寄存器,将其中存储的内容赋给rD1,否则将rD1设为0;若rR2不是0号寄存器,将其中存储的内容赋给rD2,否则将rD2设为0。 写寄存器采用时序逻辑,每个时钟上升沿来临时,0号寄存器reg_array[0]恒设为0,复位信号有效时,所有寄存器设为0。不复位时,若写寄存器堆信号有效,即wE为1时,且目标寄存器不是0号寄存器,则将reg_array[wR]设为wD。 根据控制信号对25位的数ins进行相应立即数扩展为32位的sext_imm。当sext_op为`I_SEXT时,进行I型立即数扩展;当sext_op为`S_SEXT 时,进行S型立即数扩展;当sext_op为`B_SEXT,进行B型立即数扩展;当sext_op为`U_SEXT 时,进行U型立即数扩展;当sext_op为`J_SEXT 时,进行J型立即数扩展;其余情况默认设置sext_imm为0。 brOp为`BEQ时,data1==data2则将brAns设为0,否则为1;为`BNE时,与`BEQ 相反;为`BLT时,data1<data2则将brAns设为0,否则为1;为`BGE时,与`BLT相反。 运算器采用组合逻辑。 aSel为0时,ALU第一个操作数a选择pc,为1时选择reg1存储的数。bSel为0时,ALU第二个操作数b选择reg2存储的数,为1时选择扩展后的立即数。当aluSel为`ADD时,ALU对两操作数进行加法操作(result=a+b);当为`SUB时,做减法操作(result=a-b);当为`AND时,做与操作(result=a&b);当为`OR时,做或操作(result=a|b);当为`XOR时,做异或操作(result=a^b);当为`SLL时,做左移操作(result=a<<b[4:0]);当为`SRL时,做逻辑右移操作(result=a>>b[4:0]);当为`SRA时,做算数右移操作(result=($signed(a))>>>b[4:0]);当为`LUI时,直接将b赋值给result(result=b);其他情况默认将result直接赋值为0。 寄存器堆写回值dataW的赋值采用组合逻辑。当wbSel=`PC4时,选择pc+4;当wbSel=`FROM_ALU时,选择ALU的计算结果;当wbSel=`FROM_DM时,选择从DM中取出的结果。 数码管显示逻辑。Top模块获取数码管所需显示的数字data和进行时钟分频得到时钟信号clk_1khz,传入shumaguan模块,由shumaguan模块计算出每个分频后时钟周期显示的数字num和数码管使能信号。 |
1.3 单周期CPU仿真及结果分析
要求:包含逻辑运算、访存、分支跳转三类指令的仿真截图以及波形分析;每类指令的截图和分析中,至少包含1条具体指令;截图需包含信号名和关键信号。 |
4: 02500413 addi x8,x0,37 在时钟上升沿获得当前pc后,从IM取出指令instruction,分析指令。从寄存器堆中取出寄存器rR1,即0号寄存器的内容作为ALU的第一个操作数,即a=0;同时由sext_op=0,判断将指令后25位做I型立即数扩展,得到32位的立即数sext_imm作为ALU的第二个操作数,即b=0x25。两操作数在ALU中做加法操作得到结果,即from_alu=0x25,并将该结果写回8号寄存器。 b00: 0000a703 lw x14,0(x1) 在时钟上升沿获得当前pc后,从IM取出指令instruction,分析指令。从寄存器堆中取出寄存器rR1,即1号寄存器的内容作为ALU的第一个操作数,即a=0x4000;同时由sext_op=0,判断将指令后25位做I型立即数扩展,得到32位的立即数sext_imm作为ALU的第二个操作数,即b=0。两操作数在ALU中做加法操作得到结果,即from_alu=0x4000。该结果作为内存地址,取出该地址中存储的内容0xff00ff写入14号寄存器。 2a4: fc7716e3 bne x14,x7,270 <fail> 在时钟上升沿获得当前pc后,从IM取出指令instruction,分析指令。从寄存器堆中取出寄存器rR1,即14号寄存器的内容作为比较器的第一个操作数,即data1=0;从寄存器堆中取出寄存器rR2,即7号寄存器的内容作为比较器的第一个操作数,即data2=0;由brOp=1,判断两操作数是否相等,得判断结果相等,即brAns=1 ,说明指令顺序执行,不跳转,所以将pc4作为下条pc,即next_pc=0x2a8,而非ALU得到的跳转地址0x270。 |
2 流水线CPU设计与实现
2.1 流水线的划分
要求:画出流水线如何划分,说明每个流水级具备什么功能、需要完成哪些操作。 |
经典五级流水结构: 》取指 阶段(Instruction Fetch,IF):是指将指令从指令存储器中读取出来的过程。 》译码 阶段(Instruction Decode,ID):是指将取指阶段取出的指令进行翻译的过程。译码阶段将得到指令的操作码、功能码、操作数寄存器号等信息,然后从寄存器堆(Register File)取出操作数,同时产生指令执行所需的控制信号。 》执行 阶段(instruction EXecute,EX):是指根据指令的操作码和功能码,对指令操作数进行运算的过程。如果指令是一条加法运算指令,则对操作数进行加法操作;如果是减法运算指令,则进行减法操作。CPU中的算术逻辑单元(Arithmetic Logical Unit,ALU)是实施具体运算的硬件功能单元,是执行阶段的核心部件。 》访存 阶段(MEMory access,MEM):是指访存指令从存储器读出数据,或将数据写入存储器的过程。 》写回 阶段(Write Back,WB):是指将指令执行结果写回到目标寄存器的过程。运算类指令的执行结果是执行阶段的输出,而访存指令的执行结果则是访存阶段从存储器读取出的数据。 |
2.2 流水线CPU整体框图
要求:无需画出模块内的具体逻辑,但要标出模块的接口信号名、模块之间信号线的信号名和位宽,以及说明每个模块的功能含义。 |
各个模块功能: pc:更新pc 指令IM:指令寄存器 寄存器堆regfile:从此获取32个寄存器存储内容 控制单元control:给出控制信号 比较器BranchComp:获取相应比较结果 计算器ALU:获取相应计算结果 数据寄存器DM:根据所给地址获得内存内容 MUX_WB:选择写回数据寄存器的内容 IF/ID流水级、ID/EX流水级、EX/MEM流水级、MEM/WB流水级:4个用于暂存指令执行的中间结果的流水线寄存器 停顿判断逻辑:判断载入使用型数据冒险,并通过暂停和前递解决冒险 前递判断逻辑:判断不涉及LW指令的数据冒险,并通过前递解决冒险 |
2.3 流水线CPU模块详细设计
要求:画出各个模块的详细设计图,包含内部的子模块,以及关键性逻辑;标出子模块接口信号名、各信号线的信号名和位宽,并有详细的解释说明;此外,必须结合模块图,详细说明数据冒险、控制冒险的解决方法。 |
当EX阶段正在执行取数指令(opcode_2==`LW_TYPE),EX阶段的写回寄存器与ID阶段要读取的寄存器reg1/reg2相同(wreg_2==reg1/reg2且rr1_1/rr2_1,其中rr1_1/rr2_1表示ID阶段要读取寄存器reg1/reg2)时,说明此时EX阶段和ID阶段的两条指令发生载入-使用型数据冒险,采用组合逻辑,赋stop1/stop2=1,而停顿信号stop=stop1|stop2,得知此时得停顿。pre11和pre21的赋值采用时序逻辑,复位信号无效时,在每个时钟上升沿将pre11<=stop1、pre21<=stop2。停顿一个时钟周期后,利用pre11或pre21的改变将stop变回0,以实现只停顿一个时钟周期。同时采用组合逻辑,赋停顿后续前递信号pre1\pre2为pre11\pre21,或着当MEM阶段正在执行取数指令(opcode_3==`LW_TYPE),MEM阶段的写回寄存器与ID阶段要读取的寄存器reg1/reg2相同(wreg_3==reg1/reg2且rr1_1/rr2_1,其中rr1_1/rr2_1表示ID阶段要读取寄存器reg1/reg2)时,将pre1\pre2赋为1。停顿操作在部分部件设计中说明。 代码如下: 当ID阶段正在读寄存器reg1/reg2(即rr1_1/rr2_1)时,若EX阶段的指令要写寄存器wreg_2(即regWEn_2),同时两寄存器是同一个(即reg1== wreg_2/reg2== wreg_2),则检测到RAW情形A,设rs1_id_ex_hazard=1/ rs2_id_ex_hazard=1;若MEM阶段的指令要写寄存器wreg_3(即regWEn_3),同时两寄存器是同一个(即reg1== wreg_3/reg2== wreg_3),则检测到RAW情形B,设rs1_id_mem_hazard=1/ rs2_id_mem_hazard=1;若WB阶段的指令要写寄存器wreg_4(即regWEn_4),同时两寄存器是同一个(即reg1== wreg_4/reg2== wreg_4),则检测到RAW情形C,设rs1_id_wb_hazard=1/ rs2_id_wb_hazard=1。都需要前递。 前递的具体操作: pre1=1:将MEM阶段从DM中取来的数(from_dm_3)赋给data1_1 pre2=1:将MEM阶段从DM中取来的数(from_dm_3)赋给data2_1 rs1_id_ex_hazard=1:将EX阶段ALU计算出的结果(from_alu_2)赋给data1_1 rs2_id_ex_hazard=1:将EX阶段ALU计算出的结果(from_alu_2)赋给data2_1 rs1_id_mem_hazard=1:将MEM阶段ALU计算出的结果(from_alu_3)赋给data1_1 rs2_id_mem_hazard=1:将MEM阶段ALU计算出的结果(from_alu_3)赋给data2_1 rs1_id_wb_hazard=1:将WB阶段ALU计算出的结果(from_alu_4)赋给data1_1 rs2_id_wb_hazard=1:将WB阶段ALU计算出的结果(from_alu_4)赋给data2_1 next_pc的赋值采用组合逻辑,当EX阶段传来的pcSel_2为0时表示跳转,被赋为EX阶段计算出来的地址from_alu_2;当pcSel_2为1时表示不跳转,被赋为pc4(恒为pc+4)。复位信号rst无效一个时钟周期后的时钟上升沿信号rst_p无效。current_pc的赋值采用时序逻辑,在每个时钟上升沿,当rst_p有效时,被赋值为0;其它当停顿检测逻辑传来的信号有效,即stop=1时,保持;其他情况默认赋值为next_pc。以实现pc的更新。 控制信号的赋值均采用组合逻辑。 》regWEn:当指令为S型指令或B型指令时,不写寄存器,regWEn设为0,否则设为1。 》immSel:根据opcode判断指令类型选择如何对立即数进行扩展。当指令为I型指令、LW指令、jalr指令时,immSel设为`I_SEXT;当指令为S型指令时,immSel设为`S_SEXT ;当指令为B型指令时,immSel设为`B_SEXT;当指令为U型指令时,immSel设为`U_SEXT;当指令为J型指令时,immSel设为`J_SEXT;其余情况默认immSel设为3’b111。 》brOp:当指令类型为B型指令时,比较器做何比较由funct3决定,直接将brOp设为funct3;其余情况默认brOp设为3’b111。 》aSel:根据指令类型判断ALU第一个操作数。当指令类型为B型指令或J型指令时, aSel设为0;否则aSel设为1。 》bSel:根据指令类型判断ALU第二个操作数。当指令类型为R型指令时, bSel设为0;否则bSel设为1。 》aluSel:当指令类型为R型指令时,根据funct3和funct7判断计算器进行的操作类型,分别将aluSel设为`SUB、`ADD、`AND、`OR、`XOR、`SLL、`SRL、`SRA,其它情况默认为`NOOP;当指令类型为I型指令时,根据funct3和funct7判断计算器进行的操作类型,分别将aluSel设为`ADD、`AND、`OR、`XOR、`SLL、`SRL、`SRA,其它情况默认为`NOOP;当指令为LW指令、jalr指令、S型指令、B型指令、J型指令时,aluSel设为`ADD;当指令为U型指令时,aluSel设为`LUI;其余情况默认aluSel设为`NOOP。 》memRW:根据指令类型判断读写内存。当指令类型为S型指令时需要写内存,memRW设为1;其余情况默认不写内存,设为0。 》wbSel:根据指令类型选择写回寄存器的内容。当指令类型为J型指令、jalr指令时, wbSel设为`PC4;当指令为LW指令时, wbSel设为`FROM_DM;其余情况默认wbSel设为`FROM_ALU。 》rr1:根据指令类型判断是否需要读取寄存器reg1中的内容。当指令为R型指令、I型指令、LW型指令、jalr指令、S型指令、B型指令时,rr1设为1;当指令为U型指令、J型指令时,rr1设为0;其他情况默认设为0。 》rr2:根据指令类型判断是否需要读取寄存器reg2中的内容。当指令为R型指令、S型指令、B型指令时,rr2设为1;当指令为I型指令、LW型指令、jalr指令、U型指令、J型指令时,rr2设为0;其他情况默认设为0。 所有输出信号的更新均采用时序逻辑,在时钟上升沿来临时: 当复位信号有效,即rst=1时,或要清空流水级,即flush(EX阶段得到的pcSel)=0时,要将相应的寄存器清零,useful_1设为’b0;pc_1设为32'b0;reg1设为5'b0;reg2设为5'b0;wreg_1设为5'b0;imm设为25'b0;opcode_1设为7'b0;regWEn_1设为1;immSel_1设为'b111;brOp_1设为'b111;aSel_1设为1;bSel_1设为1;aluSel_1设为`NOOP;memRW_1设为0;wbSel_1设为`FROM_ALU;rr1_1设为0;rr2_1设为0。 当来自停顿判断逻辑的停顿信号有效,即stop=1时,所有输出信号保持。 其它情况默认,useful_1设为’b1;pc_1设为pc;reg1设为instruction[19:15];reg2设为instruction[24:20];wreg_1设为instruction[11:7];imm设为instruction[31:7];opcode_1设为instruction[6:0];regWEn_1设为regWEn;immSel_1设为immSel;brOp_1设为brOp;aSel_1设为aSel;bSel_1设为bSel;aluSel_1设为aluSel;memRW_1设为memRW;wbSel_1设为wbSel;rr1_1设为rr1;rr2_1设为rr2。 读寄存器采用组合逻辑,若rR1不是0号寄存器,将其中存储的内容赋给rD1,否则将rD1设为0;若rR2不是0号寄存器,将其中存储的内容赋给rD2,否则将rD2设为0。 写寄存器采用时序逻辑,每个时钟上升沿来临时,0号寄存器reg_array[0]恒设为0,复位信号有效时,所有寄存器设为0。不复位时,若写寄存器堆信号有效,即wE为1时,且目标寄存器不是0号寄存器,则将reg_array[wR]设为wD。 根据控制信号对25位的数imm进行相应立即数扩展为32位的sext_imm_1。当immSel_1为`I_SEXT时,进行I型立即数扩展;当immSel_1为`S_SEXT 时,进行S型立即数扩展;当immSel_1为`B_SEXT,进行B型立即数扩展;当immSel_1为`U_SEXT 时,进行U型立即数扩展;当immSel_1为`J_SEXT 时,进行J型立即数扩展;其余情况默认设置sext_imm_1为0。(与单周期设计相同) 所有输出信号的更新均采用时序逻辑,在时钟上升沿来临时: 当复位信号有效,即rst=1时,或要清空流水级,即flush(EX阶段得到的pcSel)=0时,要将相应的寄存器清零,useful_2设为’b0;pc_2设为32'b0; wreg_2设为5'b0;sext_imm_2设为32'b0;data1_2设为32'b0;data2_2设为32'b0;opcode_2设为7'b0;regWEn_2设为0;brOp_2设为'b111;aSel_2设为1;bSel_2设为1;aluSel_2设为`NOOP;memRW_2设为0;wbSel_2设为`FROM_ALU。 当来自停顿判断逻辑的停顿信号有效,即stop=1时,useful_2设为’b0;pc_2设为pc_1; wreg_2设为wreg_1;sext_imm_2设为sext_imm_1;data1_2设为data1_1;data2_2设为data2_1;opcode_2设为opcode_1;regWEn_2设为0;brOp_2设为brOp_1;aSel_2设为aSel_1;bSel_2设为bSel_1;aluSel_2设为aluSel_1;memRW_2设为0;wbSel_2设为wbSel_1。 其余情况默认将useful_2设为useful_1;pc_2设为pc_1; wreg_2设为wreg_1;sext_imm_2设为sext_imm_1;data1_2设为data1_1;data2_2设为data2_1;opcode_2设为opcode_1;regWEn_2设为regWEn_1;brOp_2设为brOp_1;aSel_2设为aSel_1;bSel_2设为bSel_1;aluSel_2设为aluSel_1;memRW_2设为memRW_1;wbSel_2设为wbSel_1。 brOp_2为`BEQ时,data1_2==data2_2则将brAns设为0,否则为1;为`BNE时,与`BEQ 相反;为`BLT时,data1_2<data2_2则将brAns设为0,否则为1;为`BGE时,与`BLT相反。 同时根据EX阶段所执行的指令类型,即opcode_2判断pcSel,当指令为R型指令、I型指令、LW指令、S型指令、U型指令时,指令不跳转,pcSel_2设为1;当指令为B型指令时,由比较结果判断指令跳转与否,pcSel_2设为brAns;当指令为J型指令或jalr指令,指令跳转,pcSel_2设为0;其余情况默认指令不跳转,pcSel_2设为1。 运算器采用组合逻辑。 aSel为0时,ALU第一个操作数a选择pc,为1时选择reg1存储的数。bSel为0时,ALU第二个操作数b选择reg2存储的数,为1时选择扩展后的立即数。当aluSel为`ADD时,ALU对两操作数进行加法操作(result=a+b);当为`SUB时,做减法操作(result=a-b);当为`AND时,做与操作(result=a&b);当为`OR时,做或操作(result=a|b);当为`XOR时,做异或操作(result=a^b);当为`SLL时,做左移操作(result=a<<b[4:0]);当为`SRL时,做逻辑右移操作(result=a>>b[4:0]);当为`SRA时,做算数右移操作(result=($signed(a))>>>b[4:0]);当为`LUI时,直接将b赋值给result(result=b);其他情况默认将result直接赋值为0。(与单周期设计相同) 所有输出信号的更新均采用时序逻辑,在时钟上升沿来临时: 当复位信号有效,即rst=1时,useful_3设为’b0;pc_3设为32'b0;from_alu_3设为32’b0;wreg_3设为5'b0;data2_3设为32'b0;opcode_3设为7'b0;regWEn_3设为0;memRW_3设为0;wbSel_3设为`FROM_ALU。 其余情况默认将useful_3设为useful_2;pc_3设为pc_2;from_alu_3设为from_alu_2;wreg_3设为wreg_2;data2_3设为data2_2;opcode_3设为opcode_2;regWEn_3设为regWEn_2;memRW_3设为memRW_2;wbSel_3设为wbSel_2。 所有输出信号的更新均采用时序逻辑,在时钟上升沿来临时: 当复位信号有效,即rst=1时,useful_4设为’b0;pc_4设为32'b0;from_alu_4设为32’b0;from_dm_4设为32’b0;wreg_4设为5'b0;regWEn_4设为0; wbSel_4设为`FROM_ALU。 其余情况默认将useful_4设为useful_3;pc_4设为pc_3;from_alu_4设为from_alu_3;from_dm_4设为from_dm_3;wreg_4设为wreg_3;regWEn_4设为regWEn_3;wbSel_4设为wbSel_3。 寄存器堆写回值dataW的赋值采用组合逻辑。当wbSel=`PC4时,选择pc+4;当wbSel=`FROM_ALU时,选择ALU的计算结果;当wbSel=`FROM_DM时,选择从DM中取出的结果。(与单周期设计相同) 数码管显示逻辑。Top模块获取数码管所需显示的数字data和进行时钟分频得到时钟信号clk_1khz,传入shumaguan模块,由shumaguan模块计算出每个分频后时钟周期显示的数字num和数码管使能信号。(与单周期设计相同) |
2.4 流水线CPU仿真及结果分析
要求:包含控制冒险和数据冒险三种情形的仿真截图,以及波形分析。若仅实现了理想流水,则此处贴上理想流水的仿真截图及详细的波形分析。 |
控制冒险: 0: 0040006f jal x0,4 <reset_vector> 4: 02500413 addi x8,x0,37 我采用静态预测解决控制冒险,总是预测跳转。图中当第一条指令到达EX阶段(pc_2=0x0)时,得知下条指令该跳转(pcSel=0),跳转目的地址为from_alu_2=0x4,预测错误,一个时钟周期后,pc=0x4,清空IF/ID流水级(pc_1=0)、ID/EX流水级(pc_2=0),ID、EX阶段的指令设为无效(useful_1=0、useful_2=0)。在经过四个时钟周期后,第二条指令执行完成,又一个时钟周期后将其计算结果0x25写入寄存器reg8。 RAW情形A: 4: 02500413 addi x8,x0,37 8: 01841413 slli x8,x8,0x18 我采用前递解决该数据冒险。当第一条指令进入EX阶段、第二条指令在ID阶段时,检测到RAW情形A(rs1_id_ex_hazard=1),于是采用组合逻辑直接将EX阶段ALU计算结果from_alu_2前递给data1_1,在下一个时钟周期直接作为ALU的第一个操作数,以保证第二条指令计算结果的正确。故又过三个时钟周期后将两条指令正确执行所得结果0x25000000写回寄存器reg8。 8: 01841413 slli x8,x8,0x18 c: fffff0b7 lui x1,0xfffff 10: 0080a023 sw x8,0(x1) # fffff000 <_end+0xffffaf90> RAW情形B: 我采用前递解决该数据冒险。当第一条指令进入MEM阶段、第三条指令在ID阶段时,检测到RAW情形B(rs2_id_mem_hazard=1) ,于是采用组合逻辑直接将MEM阶段ALU计算结果from_alu_3前递给data2_1,在下一个时钟周期直接作为ALU的第二个操作数,以保证第三条指令计算结果的正确。故又过两个时钟周期后将要写入内存中的正确内容data2_3=0x25000000写入内存地址from_alu_3=0xfffff000。 298: 00208733 add x14,x1,x2 29c: 00000393 addi x7,x0,0 2a0: 06600193 addi x3,x0,102 2a4: fc7716e3 bne x14,x7,270 <fail> RAW情形C: 我采用前递解决该数据冒险。当第一条指令进入WB阶段、第四条指令在ID阶段时,检测到RAW情形C(rs1_id_wb_hazard=1) ,于是采用组合逻辑直接将WB阶段ALU计算结果from_alu_4前递给data1_1,在下一个时钟周期直接作为BranchComp的第一个操作数,以保证第四条指令比较结果的正确。故一个时钟周期后,BranchComp中两操作数data1=data2,指令不跳转(pcSel=1)。 |
3 设计过程中遇到的问题及解决方法
要求:包括设计过程中遇到的有价值的错误,或测试过程中遇到的有价值的问题。所谓有价值,指的是解决该错误或问题后,能够学到新的知识和技巧,或加深对已有知识的理解和运用。 |
|
(流水线比单周期复杂很多有木有?菜鸡参考《计算机组成原理》课程画的) 代码链接自取
Men200/test at master (github.com)
手搓单周期、流水线CPU相关推荐
- 【计算机硬件系统设计(华科)——单周期MIPS CPU(Logisim 实现)】
计算机硬件系统设计(华科)--单周期MIPS CPU 设计(单周期.流水线)(Logisim 实现) 前言 单周期 CPU 设计 数据通路 控制器设计 MIPS 指令流水线设计 理想流水线 流水接口部 ...
- 实验九 单周期MIPS CPU设计实验(基于Logisim)
一.实验目的 学生掌握控制器设计的基本原理,能利用硬布线控制器的设计原理在Logisim平台中设计实现MIPS单周期CPU. 二.实验内容 利用运算器实验,存储系统实验中构建的运算器.寄存器文件.存储 ...
- 单周期MIPS CPU设计
一.实验内容 实验过程 1.设计的24条指令 R型指令详细: I型指令详细: J型指令详细: 分析每条指令的控制信号 逻辑左移指令 SLL rd, Rt,shamt 通过指令译码器,解析出Func字段 ...
- verilog搭建单周期CPU与流水线CPU
目录 实现功能与搭建环境介绍 单周期CPU 整体框图 具体代码 顶层模块 取值 译码 执行 访存 写回 流水线CPU 整体框图 前置知识及思路探讨 如何让流水线流起来~ Hazard_detect模块 ...
- [华中科技计组实验]logisim完成单周期5级流水MIPS CPU
自己动手画cpu系列 建设中ing 仅供参考! 在这首推华中科技大学计算机组成原理实验课mooc连接 初衷:在mooc上看见了本课觉得超赞,本人已完成了课中所有的实验,在做实验的过程中有时候实验会没有 ...
- 西工大计组实验——流水线CPU并处理数据冒险
流水线CPU实验报告 最近看到不少学弟学妹浏览了我的两篇博客 流水线 单周期 此处加个声明,只提供参考,严禁报告直接抄袭! 老师会查重的,不要有侥幸心理,这个实验难度可能有点大,但是很锻炼个人能力,还 ...
- 基于RISC-V指令集架构的单周期CPU与五级流水线的实现(一)——分析
本文是为完全不了解CPU的朋友所写的入门级教程,对于较为精通的朋友,多数章节均为赘述,完整代码在下一篇博客中,请见谅哈 一.实现功能 实现了部分RV32I指令集中的部分指令类型,如下表 具体指令如下( ...
- 使用logisim搭建单周期CPU与添加指令
使用logisim搭建单周期CPU与添加指令 搭建 总设计 借用高老板的图,我们只需要分别做出PC.NPC.IM.RF.EXT.ALU.DM.Controller模块即可,再按图连线,最后进行控制信号 ...
- 单周期31条指令CPU设计---bug总结
单周期31条指令CPU设计bug-总结 vivado 2016.2 verilog modelsim Mars标准 -声明:该篇总结的bug是在编写代码,并进行测试过程中遇到问题,并及时记录.并不具有 ...
最新文章
- 自定义预览_为什么NVR预览画面数量少于已经添加的通道数
- List和DataTable的Limit
- php模拟远程提交get 、post 实例函数
- 我在项目中对 MySQL 做的优化
- 如何为Kafka挑选合适的分区数
- c语言k歌4.0编程,一次在线K歌玩法的尝试
- 一次redis集群连接数占满问题的排查
- H3C设备之 EASY NAT
- 怎样用python把数据分开_python使用pandas实现数据分割实例代码
- 圆周率π前百万位,完整版显示
- cad2018安装教程_安装CAD后,我首先干了这些事!
- Pseudo-terminal will not be allocated because stdin is not a terminal
- python中import 模块的路径问题
- lua table是否为空的判断
- 2020新版软件自动化测试自学全套教程——中级程序员学习路线
- 一些比较好用的域名信息查询网站
- java输出hello java_eclipse输出Hello World的实现方法
- STEP标准执行方法-ISO-10303-21
- 租用香港服务器机房机柜,费用由哪些部分组成
- 微观经济学知识点(七)
热门文章
- 阴阳师服务器维护到了9点半,阴阳师服务器维护结束 SSR式神抽取概率明显提升...
- 基于Python的在线办公系统的设计和实现
- 本地网站的策划与营运
- Aspose.CAD for .NET 22.11.0 cRACK
- TFT LCD使用心得
- html中编辑器制作goole图标,TinyMCE 编辑器添加 FontAwesome 自定义图标按钮
- JPA Hibernate 注解
- 如何在react中使用OrgChart?
- 天地伟业tiandy如何连手机_如何帮助孩子树立正确的人生理想
- 【JokerのZYNQ7020】PS_LWIP_POLL。