Lab6 V3.0
版本控制
版本 | 描述 |
---|---|
V0 | Lab3 |
V1.0 | Lab3 相对V0变化: 修改了文件名,各阶段以_stage结尾(因为if是关键词,所以module名不能叫if,遂改为if_stage,为了统一命名,将所有module后缀加上_stage) 删除了imm_sign信号(默认对立即数进行有符号数扩展) 由于对sw指令进行了重新理解:无论如何都是需要将rt_data传递给EXE阶段,故将部分译码逻辑进行后移至EXE阶段,避免id_to_exe_data总线过于庞大 将ins_shmat剔除出id_to_exe_data,因为imm包括ins_shamt 对信号进行重命名(例如在ID阶段有个信号叫rf_we,最终要传递给WB阶段,那么在EXE阶段,该信号叫作exe_rf_we,同理mem_rf_we,wb_rf_we),不然都叫rf_we,Debug的时候太痛苦了。 |
V2.0 | Lab4 相对V1.0的变化 引入`ifdef-`else-`endif来实现相对V1.0的代码增量 增加了旁路控制,减少流水线阻塞(因为增加了旁路,所以修改了ID、EXE、MEM的接口) 修改了ready_go命令,用于控制流水线的阻塞 |
V3.0 | Lab6(加载的是func_lab6的.coe文件,而不是func_lab5的,因为没有func_lab5这个东西) 相对V2.0的变化:电路细节变化详见:“CPU设计实战电路图”,图中Lab6的变化均以红色背景的方框框起来,并以黄色背景的“Lab6复用/新增信号”标注。本lab6.docx中,新增及修改的信号以红色标注。 删掉了ALU.v的接口,将alu_shamt合并至data_1,方便对新加指令sllv、srlv、srav的数据通路的复用 增加了ID.v中的alu_add的“或门”的输入 扩充了id_to_exe_data总线数据, 因为alu_op扩充了新的指令 添加了imm_zero_ext信号 修改了ins_R、ins_J、ins_I,因为增加了新的指令 乘法器和除法器调用vivado的IP,其周期参数化可配置设计 乘法和除法结果存放的寄存器HI/LO放在WB.v中 增加了sfr.v,用于特殊寄存器的存储 增加了mul_div.v,用于处理乘法和除法。增加了mul.v用于处理乘法,增加了divu.v用于处理无符号除法,增加了divs.v用于处理有符号除法 修改了id_to_exe_data,添加了新信号:imm_zero_ext_en 修改了id_to_exe_data,扩充了alu_op的位宽,并将alu_op调整至id_to_exe_data的最高位,方便未来扩充指令 |
Top顶层
接口信号
MYCPU_TOP.v(TOP)
名称 | 宽度 | 方向 | 描述 |
---|---|---|---|
时钟与复位 | |||
clk | 1 | I | 时钟信号,来自clk_pll的输出时钟 |
resetn | 1 | I | 复位信号,低电平同步复位 |
取指端访存接口 | |||
inst_sram_en | 1 | O | 指令RAM使能信号,高电平有效 |
inst_sram_wen | 4 | O | 指令RAM字节写使能信号,高电平有效 |
inst_sram_addr | 32 | O | 指令RMA读写地址,字节寻址 |
inst_sram_wdata | 32 | O | 指令RAM写数据 |
inst_sram_rdata | 32 | I | 指令RAM读数据 |
数据端访存接口 | |||
data_sram_en | 1 | O | 数据RAM使能信号,高电平有效 |
data_sram_wen | 4 | O | 数据RAM字节写使能信号,高电平有效 |
data_sram_addr | 32 | O | 数据RAM读写地址,字节寻址 |
data_sram_wdata | 32 | O | 数据RAM写数据 |
data_sram_rdata | 32 | I | 数据RAM读数据 |
debug信号,供验证平台使用 | |||
debug_wb_pc | 32 | O | 写回级(多周期最后一级)的PC,需要myCPU里将PC一路传递到写回级 |
debug_wb_rf_wen | 4 | O | 写回级写寄存器堆(regfiles)的写使能,为字节使能,如果myCPU写regfiles为单字节写使能,则将写使能扩展成4位即可 |
debug_wb_rf_wnum | 5 | O | 写回级写regfiles的目的寄存器号 |
debug_wb_rf_wdata | 32 | O | 写回级写regfiles的写数据 |
接口时序
略(MIPS经典五级流水线)
代码结构
MYCPU_TOP.v
|____IF.v
|____ID.v
|____RF.v(2个读端口,1个写端口)
|____SFR.v(1个读端口,2个写端口)
|____EXE.v
|____ALU.v
|____MUL_DIV.v(专门处理乘法和除法)
|____MUL.v
|____DIVU.v
|____DIVS.v
|____MEM.v
|____WB.v
|____MYCPU.h
DATA_RAM.v
IF.v(修改为IF_STAGE,因为会与关键词if冲突)
接口信号
名称 | 宽度 | 方向 | 描述 |
---|---|---|---|
时钟与复位 | |||
clk | 1 | I | 时钟信号,来自clk_pll的输出时钟 |
resetn | 1 | I | 复位信号,低电平同步复位 |
与TOP | |||
inst_sram_en | 1 | O | RAM使能信号,高电平有效 |
inst_sram_wen | 4 | O | RAM字节写使能信号,高电平有效 |
inst_sram_addr | 32 | O | RMA读写地址,字节寻址 |
inst_sram_wdata | 32 | O | RAM写数据 |
inst_sram_rdata | 32 | I | RAM读数据 |
与ID | |||
id_to_if_allowin | 1 | I | pipe allowin |
if_to_id_vld | 1 | O | pipe valid |
if_to_id_data | 64 | O | pipe data(instruction 32-bits, pc 32-bits) |
jump_bus | 33 | I | branch instructions(enable 1bit,address 32-bits) |
接口时序
ID.v
接口信号
名称 | 宽度 | 方向 | 描述 |
---|---|---|---|
时钟与复位 | |||
clk | 1 | I | 时钟信号,来自clk_pll的输出时钟 |
resetn | 1 | I | 复位信号,低电平同步复位 |
与IF | |||
id_to_if_allowin | 1 | O | pipe allowin |
if_to_id_vld | 1 | I | pipe valid |
if_to_id_data | 64 | I | pipe data(instruction 32-bits, pc 32-bits) |
jump_bus | 33 | O | branch instructions(enable 1bit,address 32-bits) |
与EXE | |||
exe_to_id_allowin | 1 | I | pipe allowin |
id_to_exe_vld | 1 | O | pipe valid |
id_to_exe_data | 145 | O | {alu_op:21, shamt_is_shamt:1, imm_zero_ext_en:1, ins_R:1, ins_I:1, imm:16, mem_rd:1, mem_we:1, rf_we:1, rf_dst_addr:5, rt_data:32, rs_sfr_data_2:32, pc:32} |
exe_bypass_bus | 38 | I | {exe_rf_we:1, exe_rf_dst_addr:5, exe_rf_data:32} |
exe_to_id_sfr_bus | 76 | I | [75] exe_sfr_we1 [74:70] exe_sfr_w_addr1 [69:38] exe_sfr_data1 [37] exe_sfr_we2 [36:32] exe_sfr_w_addr2 [31:0] exe_sfr_data2 |
csr_mul_div_bus | 40(参数化) | O | csr_mul_hi参数化4,循环移位计数器——乘法hi csr_mul_lo参数化4,循环移位计数器——乘法lo csr_div_s_hi参数化8,循环移位计数器——有符号除法hi csr_div_s_lo参数化8,循环移位计数器——有符号除法lo csr_div_u_hi参数化8,循环移位计数器——无符号除法hi csr_div_u_lo参数化8,循环移位计数器——无符号除法lo |
mul_div_busy | 1 | I | 正在进行乘法或除法运算 |
与MEM | |||
mem_bypass_bus | 38 | I | {mem_rf_we:1, mem_rf_dst_addr:5, mem_rf_data:32} |
与WB | |||
wb_to_rf_bus | 38 | I | {rf_we:1, rf_addr:5, rf_data:32} |
接口信号(RF.v)
名称 | 宽度 | 方向 | 描述 |
---|---|---|---|
时钟与复位 | |||
clk | 1 | I | 时钟信号,来自clk_pll的输出时钟 |
与ID内部信号 | |||
rf_r_addr1 | 5 | I | RF读地址1 |
rf_r_data1 | 32 | O | RF读数据1 |
rf_r_addr2 | 5 | I | RF读地址2 |
rf_r_data2 | 32 | O | RF读数据2 |
rf_wen1 | 1 | I | RF写使能1 |
rf_w_addr1 | 5 | I | RF写地址1 |
rf_w_data1 | 32 | O | RF写数据1 |
接口信号(SFR)
当写入同一地址时,以sfr_we_1优先
名称 | 宽度 | 方向 | 描述 |
---|---|---|---|
时钟与复位 | |||
clk | 1 | I | 时钟信号,来自clk_pll的输出时钟 |
resetn | 1 | I | 复位信号,低电平同步复位 |
与ID内部信号 | |||
sfr_r_addr1 | 5 | I | SFR读地址1 |
sfr_r_data1 | 32 | O | SFR读数据1 |
sfr_we_1 | 1 | I | SFR写使能1 |
sfr_w_addr1 | 5 | I | SFR写地址1 |
sfr_w_data1 | 32 | I | SFR写数据1 |
sfr_we_2 | 1 | I | SFR写使能2 |
sfr_w_addr2 | 5 | I | SFR写地址2 |
sfr_w_data2 | 32 | I | SFR写数据2 |
接口时序
电路设计
图3-4-1 译码电路分组(注:黄线少画了两条)
根据附录——MIPS指令。由于跳转指令不传递给EXE阶段,直接传递给IF阶段,且为纯组合逻辑输出,有可能成为关键路径,故对跳转指令单独处理。除了跳转指令外,涉及加法(减法归为加法)的指令如图3-4-1所示,即ins_addu、ins_addiu、ins_subu、ins_lw、ins_sw。
对于图3-4-1的拼接运算,可以当作移位运算执行。
EXE.v
接口信号
名称 | 宽度 | 方向 | 描述 |
---|---|---|---|
时钟与复位 | |||
clk | 1 | I | 时钟信号,来自clk_pll的输出时钟 |
resetn | 1 | I | 复位信号,低电平同步复位 |
与TOP(外接的DATA_RAM) | |||
data_sram_en | 1 | O | 数据RAM使能信号,高电平有效 |
data_sram_wen | 4 | O | 数据RAM字节写使能信号,高电平有效(4个比特,应该代表32 = 4 bytes) |
data_sram_addr | 32 | O | 数据RAM读写地址,字节寻址 |
data_sram_wdata | 32 | O | 数据RAM写数据 |
与ID | |||
exe_to_id_allowin | 1 | O | pipe allowin |
id_to_exe_vld | 1 | I | pipe valid |
id_to_exe_data | 145 | I | {alu_op:21, shamt_is_shamt:1, imm_zero_ext_en:1, ins_R:1, ins_I:1, imm:16, mem_rd:1, mem_we:1, rf_we:1, rf_dst_addr:5, rt_data:32, rs_sfr_data_2:32, pc:32} |
exe_bypass_bus | 38 | O | {exe_rf_we:1, exe_rf_dst_addr:5, exe_rf_data:32} |
exe_to_id_sfr_bus | 76 | O | [75] exe_sfr_we1 [74:70] exe_sfr_w_addr1 [69:38] exe_sfr_data1 [37] exe_sfr_we2 [36:32] exe_sfr_w_addr2 [31:0] exe_sfr_data2 |
csr_mul_div_bus | 40(参数化) | I | csr_mul_hi参数化4,循环移位计数器——乘法hi csr_mul_lo参数化4,循环移位计数器——乘法lo csr_div_s_hi参数化8,循环移位计数器——有符号除法hi csr_div_s_lo参数化8,循环移位计数器——有符号除法lo csr_div_u_hi参数化8,循环移位计数器——无符号除法hi csr_div_u_lo参数化8,循环移位计数器——无符号除法lo |
mul_div_busy | 1 | O | 正在进行乘法或除法运算 |
与MEM | |||
mem_to_id_allowin | 1 | I | pipe allowin |
exe_to_mem_vld | 1 | O | pipe valid |
exe_to_mem_data | 71 | O | {mem_rd:1, rf_we:1, rf_dst_addr:5, pc:32(其实可以删掉pc,这里是debug显示用的,可以叫debug_pc), exe_result:32 |
接口信号(ALU.v)
暂时不需要时钟和复位,纯组合逻辑
名称 | 宽度 | 方向 | 描述 |
---|---|---|---|
时钟与复位 | |||
clk | 1 | I | 时钟信号,来自clk_pll的输出时钟 |
resetn | 1 | I | 复位信号,低电平同步复位 |
与ID内部信号 | |||
alu_shamt | 6 | I | ALU移位(R-指令的shamt部分) |
alu_op | 19 | I | ALU操作(加、减、乘除、位运算) |
alu_din1 | 32 | I | ALU输入1 |
alu_din2 | 32 | I | ALU输入2 |
alu_out | 32 | O | ALU输出 |
csr_mul_div_bus | 40(参数化) | I | csr_mul_hi参数化4,循环移位计数器——乘法hi csr_mul_lo参数化4,循环移位计数器——乘法lo csr_div_s_hi参数化8,循环移位计数器——有符号除法hi csr_div_s_lo参数化8,循环移位计数器——有符号除法lo csr_div_u_hi参数化8,循环移位计数器——无符号除法hi csr_div_u_lo参数化8,循环移位计数器——无符号除法lo |
mul_div_busy | 1 | O | 正在进行乘法或除法运算 |
接口信号(MUL_DIV.v)
名称 | 宽度 | 方向 | 描述 |
---|---|---|---|
时钟与复位 | |||
clk | 1 | I | 时钟信号,来自clk_pll的输出时钟 |
resetn | 1 | I | 复位信号,低电平同步复位 |
与ALU内部信号 | |||
alu_mult | 1 | I | 有符号乘 |
alu_multu | 1 | I | 无符号乘 |
alu_div | 1 | I | 有符号除 |
alu_divu | 1 | I | 无符号除 |
alu_mthi | 1 | I | 将寄存器 rs 的值写入到 HI 寄存器中 |
alu_mtlo | 1 | I | 将寄存器 rs 的值写入到LO寄存器中 |
alu_din1 | 32 | I | ALU输入1 |
alu_din2 | 32 | I | ALU输入2 |
exe_to_id_sfr_bus | 76 | O | [75] exe_sfr_we1 [74:70] exe_sfr_w_addr1 [69:38] exe_sfr_data1 [37] exe_sfr_we2 [36:32] exe_sfr_w_addr2 [31:0] exe_sfr_data2 |
csr_mul_div_bus | 40(参数化) | I | csr_mul_hi参数化4,循环移位计数器——乘法hi csr_mul_lo参数化4,循环移位计数器——乘法lo csr_div_s_hi参数化8,循环移位计数器——有符号除法hi csr_div_s_lo参数化8,循环移位计数器——有符号除法lo csr_div_u_hi参数化8,循环移位计数器——无符号除法hi csr_div_u_lo参数化8,循环移位计数器——无符号除法lo |
mul_div_busy | 1 | O | 正在进行乘法或除法运算 |
接口信号MUL.v
名称 | 宽度 | 方向 | 描述 |
---|---|---|---|
时钟与复位 | |||
clk | 1 | I | 时钟信号,来自clk_pll的输出时钟 |
resetn | 1 | I | 复位信号,低电平同步复位 |
与ALU内部信号 | |||
mul_din_vld | 1 | I | 数据有效信号 |
mul_din1 | 33 | I | 乘数1 |
mul_din2 | 33 | I | 乘数2 |
mul_result_hi | 32 | O | 乘法高32位 |
mul_result_lo | 32 | O | 乘法低32位 |
接口信号DIVU.v
名称 | 宽度 | 方向 | 描述 |
---|---|---|---|
时钟与复位 | |||
clk | 1 | I | 时钟信号,来自clk_pll的输出时钟 |
resetn | 1 | I | 复位信号,低电平同步复位 |
与ALU内部信号 | |||
divu_din_vld | 1 | I | 数据有效信号 |
divu_din1 | 33 | I | 被除数 |
divu_din2 | 33 | I | 除数 |
divu_hi | 32 | O | 结果高32位 |
divu_lo | 32 | O | 结果低32位 |
接口信号DIVS.v
名称 | 宽度 | 方向 | 描述 |
---|---|---|---|
时钟与复位 | |||
clk | 1 | I | 时钟信号,来自clk_pll的输出时钟 |
resetn | 1 | I | 复位信号,低电平同步复位 |
与ALU内部信号 | |||
divs_din_vld | 1 | I | 数据有效信号 |
divs_din1 | 33 | I | 被除数 |
divs_din2 | 33 | I | 除数 |
divs_hi | 32 | O | 结果高32位 |
divs_lo | 32 | O | 结果低32位 |
接口时序
MEM.v
接口信号
名称 | 宽度 | 方向 | 描述 |
---|---|---|---|
时钟与复位 | |||
clk | 1 | I | 时钟信号,来自clk_pll的输出时钟 |
resetn | 1 | I | 复位信号,低电平同步复位 |
与TOP(外接的DATA_RAM) | |||
data_sram_rdata | 32 | I | 数据RAM读数据 |
与EXE | |||
mem_to_exe_allowin | 1 | O | pipe allowin |
exe_to_mem_vld | 1 | I | pipe valid |
exe_to_mem_data | 71 | I | {mem_rd:1, rf_we:1, rf_dst_addr:5, pc:32(其实可以删掉pc,这里是debug显示用的,可以叫debug_pc), exe_result:32} |
与WB | |||
wb_to_mem_allowin | 1 | I | pipe allowin |
mem_to_wb_vld | 1 | O | pipe valid |
mem_to_wb_data | 70 | O | { rf_we:1, rf_dst_addr:5, mem_result:32, pc:32(其实可以删掉pc,这里是debug显示用的,可以叫debug_pc)} |
与ID | |||
mem_bypass_bus | 38 | O | {mem_rf_we:1, mem_rf_dst_addr:5, mem_rf_data:32} |
WB.v
接口信号
名称 | 宽度 | 方向 | 描述 |
---|---|---|---|
时钟与复位 | |||
clk | 1 | I | 时钟信号,来自clk_pll的输出时钟 |
resetn | 1 | I | 复位信号,低电平同步复位 |
与TOP | |||
debug_wb_pc | 32 | O | 写回级(多周期最后一级)的PC,需要myCPU里将PC一路传递到写回级(与原书保持一致) |
debug_wb_rf_wen | 4 | O | 写回级写寄存器堆(regfiles)的写使能,为字节使能,如果myCPU写regfiles为单字节写使能,则将写使能扩展成4位即可(与原书保持一致) |
debug_wb_rf_wnum | 5 | O | 写回级写regfiles的目的寄存器号(与原书保持一致) |
debug_wb_rf_wdata | 32 | O | 写回级写regfiles的写数据(与原书保持一致) |
与MEM | |||
wb_to_mem_allowin | 1 | O | pipe allowin |
mem_to_wb_vld | 1 | I | pipe valid |
mem_to_wb_data | 70 | I | { rf_we:1, rf_dst_addr:5, mem_result:32, pc:32(其实可以删掉pc,这里是debug显示用的,可以叫debug_pc)} |
与ID | |||
wb_to_rf_bus | 38 | O | {rf_we:1, rf_addr:5, rf_data:32} |
接口时序
附录——参考
附录——原书指令
指令 | sel_nextpc | inst_ram_wen | inst_ram_wen | sel_alu_src1 | sel_alu_src2 | alu_op | data_ram_en | data_ram_wen | rf_we | sel_rf_dst | sel_rf_res |
---|---|---|---|---|---|---|---|---|---|---|---|
ADDU | 0001 | 1 | 0 | 001 | 001 | 000000000001 | 0 | 0 | 1 | 001 | 0 |
ADDIU | 0001 | 1 | 0 | 001 | 010 | 000000000001 | 0 | 0 | 1 | 010 | 0 |
SUBU | 0001 | 1 | 0 | 001 | 001 | 000000000010 | 0 | 0 | 1 | 001 | 0 |
LW | 0001 | 1 | 0 | 001 | 010 | 000000000001 | 1 | 0 | 1 | 010 | 1 |
SW | 0001 | 1 | 0 | 001 | 010 | 000000000001 | 1 | 1 | 0 | 000 | 0 |
BEQ | 0010 | 1 | 0 | 000 | 000 | 000000000000 | 0 | 0 | 0 | 000 | 0 |
BNE | 0010 | 1 | 0 | 000 | 000 | 000000000000 | 0 | 0 | 0 | 000 | 0 |
JAL | 0100 | 1 | 0 | 010 | 100 | 000000000001 | 0 | 0 | 1 | 100 | 0 |
JR | 1000 | 1 | 0 | 000 | 000 | 000000000000 | 0 | 0 | 0 | 000 | 0 |
SLT | 0001 | 1 | 0 | 001 | 001 | 000000000100 | 0 | 0 | 1 | 001 | 0 |
SLTU | 0001 | 1 | 0 | 001 | 001 | 000000001000 | 0 | 0 | 1 | 001 | 0 |
SLL | 0001 | 1 | 0 | 100 | 001 | 000100000000 | 0 | 0 | 1 | 001 | 0 |
SRL | 0001 | 1 | 0 | 100 | 001 | 001000000000 | 0 | 0 | 1 | 001 | 0 |
SRA | 0001 | 1 | 0 | 100 | 001 | 010000000000 | 0 | 0 | 1 | 001 | 0 |
LUI | 0001 | 1 | 0 | 000 | 010 | 100000000000 | 0 | 0 | 1 | 010 | 0 |
AND | 0001 | 1 | 0 | 001 | 001 | 000000010000 | 0 | 0 | 1 | 001 | 0 |
OR | 0001 | 1 | 0 | 001 | 001 | 000001000000 | 0 | 0 | 1 | 001 | 0 |
XOR | 0001 | 1 | 0 | 001 | 001 | 000010000000 | 0 | 0 | 1 | 001 | 0 |
NOR | 0001 | 1 | 0 | 001 | 001 | 000000100000 | 0 | 0 | 1 | 001 | 0 |
Lab6完结
Lab6 后记
乘除法器
Lab6新添加的指令中,其他指令其实很简单,唯一需要思考的就是乘除法器。本人决定乘除法器调用vivado的IP,而且乘除法器的参数参数化设计。经过反复权衡,针对乘除法器,本人做了以下设计:
- 乘除法器的数据及控制,只参与IF-ID-EXE阶段,不参与MEM-WB阶段
- 乘除法器不影响数据rf_we,因为乘除法器只影响HI、LO这两个特殊功能寄存器。
- 乘法器只使用1个乘法器(有符号和无符号合并为一个33x33的有符号乘法器),除法器使用2个除法器,分别是有符号的和无符号的。
- 乘除法器的流水控制由3个cnt控制,cnt_mul、cnt_div_s、cnt_div_u。由计数器控制流水。
- 关于流水线的阻塞。仅当本条指令是乘/除,后面指令出现MFHI、MFLO的时候才判断是否阻塞
- 当乘/除指令后,出现MTHI、MTLO指令时,对乘/除进行清零处理
- 当乘/除指令后,出现乘/除指令时,刷新乘法器和除法器的输入值同时将计数器重置,并以后面的乘/除指令为目标指令
- 乘法器只使用1个乘法器(有符号和无符号合并为一个33x33的有符号乘法器),除法器使用2个除法器,分别是有符号的和无符号的。
- 乘除法器不影响数据rf_we,因为乘除法器只影响HI、LO这两个特殊功能寄存器。
乘除法器设计
- 刚开始我是打算将计数器放置在ID.v里,把乘法器IP和除法器的IP也放在ID.v里,但是发现,不利于Lab4设计的旁路电路,遂将乘法器和除法器的IP放在ALU.v中
- 针对流水线阻塞,本人刚开始打算将乘、除法都设计为纯组合逻辑,先实现一遍,之后再增加乘、除法的级数,但是发现就算实现了,增加级数也不好控制,遂放弃该计划,改为直接参数化设计,放弃先实现纯组合逻辑的乘除法器
- 可以自己设计或调用vivado的IP
- 针对流水线阻塞,本人刚开始打算将乘、除法都设计为纯组合逻辑,先实现一遍,之后再增加乘、除法的级数,但是发现就算实现了,增加级数也不好控制,遂放弃该计划,改为直接参数化设计,放弃先实现纯组合逻辑的乘除法器
- 如果自己设计乘/除法器IP:通过cnt计数器来控制数据的,是固定周期出结果,故不需要握手。(本次暂时仅实现乘法器的计数器,因为乘法器IP没有握手信号)
- 由于vivado的除法器的IP都带有AXI接口,需要握手,故除法器使用握手信号进行控制。
- 本来我是想扩展rf_we信号的,因为方便旁路设计,后来想了想还是放弃了,决定再创建一个sfr_we信号,即“特殊功能寄存器”,同时也创建一个sfr.v,里面包括HI、LO寄存器
- 原书P138:我们不用勾选8处的除0检测,因为MIPS指令规范中规定除法指令自身是不需要对除数为0进行处理的,这项工作交给软件去做。
- 本来我是想扩展rf_we信号的,因为方便旁路设计,后来想了想还是放弃了,决定再创建一个sfr_we信号,即“特殊功能寄存器”,同时也创建一个sfr.v,里面包括HI、LO寄存器
MFHI/MFLO/MTHI/MTLO
- MFHI/MFLO/MTHI/MTLO都是R型指令,其目的寄存器也与R型指令一样,是rd寄存器,所以需要扩充ins_R的输入,不需要因为op_code==6’h0即是R型指令
- MFHI/MFLO这2条指令要参与rf_we,并参与sfr_r_addr1、sfr_r_data1
- /MTHI/MTLO这2条指令不参与rf_we,只参与sfr_we1、sfr_addr1
- MFHI/MFLO这2条指令要参与rf_we,并参与sfr_r_addr1、sfr_r_data1
流水线阻塞问题
本人已放弃使用计数器来进行乘除法器的流水计数,而是改为移位寄存器来判断。原因就是精简控制与判断,毕竟乘除法器本人也就打算最多流水4或8个周期,没必要用计数器,用移位寄存器够了,采用循环移位寄存器,即cycle shift registers。
- 考虑这样一种情况,乘法指令之后,有一条MTHI指令。乘法指令要写HI寄存器,MTHI指令也要写HI寄存器。MTHI指令在后面,所以最终肯定是MTHI要写入,但是若执行MTHI时,乘法指令尚在执行中,所以怎么处理呢?正常地,最终结果应该是MTHI指令修改了HI寄存器,乘法指令只修改了LO寄存器。但是乘法器的控制我是用计数器cnt达到计数值判断是否写入HI、LO寄存器来控制的,当cnt达到计数值时,MTHI早就执行了,所以怎么办呢?但是乘法器的控制我是用移位寄存器判断是否写入HI、LO寄存器来控制的,当移位寄存器的最高位为1时,MTHI早就执行了,所以怎么办呢?
- 本人想还只使用一个计数器移位寄存器来计数,然后增加新的逻辑进行控制,但是发现这样逻辑耦合较为严重。
- 于是决定增加计数器,即计数器cnt加倍,分别控制LO、HI寄存器的写使能。于是决定增加移位寄存器,即移位寄存器的个数加倍,分别控制LO、HI寄存器的写使能。
- 为了避免流水线阻塞,乘除法器的计数器复位值为MUL/DIVCYCLE移位寄存器的位宽为MUL/DIVCYCLE复位值为全0,移位寄存器最高位为1时终止移位。而乘除法器是否结束,即乘除法结果vld信号有效的值是判断第MUL/DIVCYCLE-2位(从0计数)是否为1,这样就只会判断一次,并且当MFHI/MFHO检测流水线不阻塞时,由于是检测移位寄存器的第MUL/DIVCYCLE-2位,因此可以确保此时乘除法结果已经写入sfr.v中
- 旁路的增加:MTHI/MTLO指令之后如果马上遇到MFHI/MFLO指令呢?这个时候就需要增加旁路,因为MTHI/MTLO在EXE阶段就完成了,因此,只需要增加EXEID的旁路。
- 为了避免流水线阻塞,乘除法器的计数器复位值为MUL/DIVCYCLE移位寄存器的位宽为MUL/DIVCYCLE复位值为全0,移位寄存器最高位为1时终止移位。而乘除法器是否结束,即乘除法结果vld信号有效的值是判断第MUL/DIVCYCLE-2位(从0计数)是否为1,这样就只会判断一次,并且当MFHI/MFHO检测流水线不阻塞时,由于是检测移位寄存器的第MUL/DIVCYCLE-2位,因此可以确保此时乘除法结果已经写入sfr.v中
SFR.v结构
- 最初我是将SFR.v放在ID阶段,即像RF.v一样,这样直接依照RF.v的结构对SFR.v的接口进行安排即可,但是实际绘制电路的时候发现,当MTHI、MTLO将rs寄存器的值写入到HI/LO寄存器时,需要先从RF中读出rs的数据,然后再向HI/LO寄存器写数据,这中间就必定会差了一个周期,但是SFR又像RF一样既需要读、又需要写,于是需要将EXE阶段的写SRF数据当作SFR的写回阶段。不需要像RF一样等到WB阶段再写回。
- 粗暴地讲,把写MTHI、MTLO的写回,当作执行(EXE)处理。
- 再向SFR中写数据时,可以发现MTHI、MTLO的优先级是高于乘除法器的,因为假如遇到乘除法指令需要写HI/LO,同时MTHI/MTLO也要写HI/LO,由于乘除法指令是多周期,说明MTHI、MTLO指令在乘除法指令之后,因此其优先级更高,在设计电路时,是在优先级的。
- 因为MTHI、MTLO的优先级是高于乘除法器的(流水线的角度考虑优先级),但是还有一种情况是乘除法指令之后紧跟着MTHI/MTLO指令,这时候还需要中止当前的乘除法器,防止后续乘除法过了若干个周期后完成后将乘除的结果写了进去。
- 再向SFR中写数据时,可以发现MTHI、MTLO的优先级是高于乘除法器的,因为假如遇到乘除法指令需要写HI/LO,同时MTHI/MTLO也要写HI/LO,由于乘除法指令是多周期,说明MTHI、MTLO指令在乘除法指令之后,因此其优先级更高,在设计电路时,是在优先级的。
- 粗暴地讲,把写MTHI、MTLO的写回,当作执行(EXE)处理。
移位寄存器问题
本来我是打算将6个移位寄存器放在ID阶段的,如下:
然而我意识到一个问题,这部分与ID基本没有关系,完全可以放在ALU中,而且还避免了又从ID向EXE引一条移位寄存器总线。于是将其添加到EXE阶段,由于这是我设计电路没有考虑清楚的,为记住该教训,绘图工具中将修改前保存为“Lab6(old)”,修改后的保存为“Lab6”。
Lab6——Debug
addi符号问题
ins_addi中的立即数是有符号扩展,不应该参与id_imm_zero_ext_en的或运算,应该是ins_andi。
add译码出错
function code出错
assign ins_add = op_ext[6’h00] & sa_ext[5’h00] & fun_ext[6’h21] ;
更改为:
assign ins_add = op_ext[6’h00] & sa_ext[5’h00] & fun_ext[6’h20] ;
div执行出错
- 时序差了一拍,已修改
- vivado2019.2的div的IP商在高位,余数在低位,而MIPS指令集中商在LO寄存器,余数在HI寄存器中。本人写反了,已修正。(确实理解上容易出错,毕竟看见HI就认为在高位,HI存的是余数)
mfhi译码出错
function code出错了
assign ins_mfhi = op_ext[6’h00] & sa_ext[5’h00] & rs_ext[5’h00] & rt_ext[5’h00] & fun_ext[6’h00] ;
改为:
assign ins_mfhi = op_ext[6’h00] & sa_ext[5’h00] & rs_ext[5’h00] & rt_ext[5’h00] & fun_ext[6’h10] ;
mult报错
后发现是alu_op的位宽少了一位,导致信号没有正确地从ID阶段传给EXE阶段
multu报错
从wb_rf_wdata的对比结果可以看到,应当是multu的执行结果的符号位出了问题。已处理如下:
修改为:
旁路出错
mthimfhi出错,经发现是旁路rs_data有问题,后来对信号进行了解耦,创建了sfr_bypass_data信号,专门处理lo、hi寄存器的旁路。该旁路的生成与rs的旁路无关。