- 新增 rtl/cpu21_riscv_muldiv.v:移位迭代的多周期乘除法单元。
* 乘法:32 拍移位加法得到 64 位乘积;有符号变体先取操作数绝对值,迭代结束后
按符号对 64 位乘积取负。
* 除法:32 拍恢复余数法得到商与余数;除零按 RISC-V 约定(商全 1、余数为被除数)。
* 一次乘/除独占 EX 共 34 拍(1 拍装载 + 32 拍迭代 + 1 拍定型):期间 ID/EX 保持、
EX/MEM 插气泡、取指/译码冻结,并屏蔽中断(避免结果未定型就写回 rd)。
- rtl/cpu21_riscv_alu.v:删除组合的 32x32 乘法与除法/取余(原来关键路径约 94 ns、
325 级逻辑、286 个 CARRY4,是 100 MHz 无法收敛的根因)。ALU_MUL/ALU_DIVU 现在
只作为“这是乘除法指令”的标识,结果由顶层从 muldiv 选取(wb_sel=3 取 result2 的
约定保持不变,译码器与写回选择都不用改)。
- rtl/cpu21_riscv_decoder.v:新增 md_op_o(乘除法操作类型),并补上课程真值表里的
divu(funct3=101)——之前这一项译码缺失,会导致 divu 不写 rd。
- rtl/cpu21_riscv_redirect_int_bpb.v:ID/EX 增加 md_op;EX 级停留、结果选择与中断
屏蔽。另外为时序做了三处行为等价的重构(100 MHz 下 WNS 从 -3.54 ns 改善到
-1.10 ns):
* JAL/JALR 的链接地址 PC+4 改在 EX 级预先算好并随流水寄存器传递,去掉
“写回值/前递 → 停机判定 → 流水控制”路径上的两个 32 位加法器;
* ID/EX 的 payload 时钟使能不再依赖冲刷(只有 valid 位受冲刷控制),把
“EX 级组合判决 → 流水寄存器时钟使能”这条最长路径缩到只剩 1 位;
* ex_block_irq 不再包含 ex_redirect_valid / ex_halt_event(它们本身就会让
flush_younger 有效,中断优先时返回地址由 irq_save_pc 正确给出),切断
“分支判决 → 中断控制器 → flush”的绕行路径。
- rtl/cpu21_riscv_hazard_unit.v:停顿条件去掉 flush_younger(冲刷由 valid 位与
PC/IF-ID 的冲刷分支处理,同时发生停顿只会多保持一拍 payload),避免把长路径
引到 payload 的时钟使能上。
- board/cpu21_board_top.v / .xdc:乘除法已不在关键路径上,分频比从 16 降到 2
(50 MHz,周期 20 ns)。实测(xc7a100tcsg324-1):CLK_DIV=1(100 MHz)下
WNS=-1.1 ns,剩余违例路径是 EX 级“分支判决/中断保存 → BPB 更新”,与乘除法无关
(逻辑只占约 3 ns,其余 ~8 ns 是布线);CLK_DIV=2 时 WNS=+5.109 ns,余量约 25%。
- 上板 ROM 按 50 MHz 重新生成(延时计数 0x7A000 ≈ 20 ms/步,快速版 64 次循环),
CPU 时钟比改造前快 8 倍。
- tools/rv_asm.py:支持 divu / remu 助记符。新增 testbench/programs/muldiv_test.asm
与 muldiv_test.expected(13 个用例:mul/mulh/mulhsu/mulhu/divu/remu、负数、
0xffffffff、除零、0x12345678 大数)。
- 验证:muldiv_test 13/13、isa_test 24/24、lui_test 4/4、mmio_test 5/5 全部 PASS;
两个基线(5560 / 6003 周期)与改造前的流水统计一致(差异只来自多周期乘除法带来的
停顿/气泡计数);中断测试仍能正常进入 0x30ac / 0x31e0 / 0x3300 三层嵌套处理程序;
板级仿真:默认 ROM 首次写入 LED=0001、快速 ROM 跑马灯 0001..8000 循环正常。
- 实现结果:synth_design / route_design / write_bitstream 全部完成,
LUT 5400 → 3420(5.39%)、DSP 12 → 0、IOB 23,时钟 6.25 MHz → 50 MHz,
bit 文件已更新。
96 lines
2.6 KiB
NASM
96 lines
2.6 KiB
NASM
# 乘除法(多周期单元)测试:每个结果都写给 MMIO 的 LED 寄存器,供测试平台比对。
|
||
# 期望输出顺序见同目录 muldiv_test.expected(共 13 个值)。
|
||
#
|
||
# ① mul 7 * 6 = 42 -> 0000002a
|
||
# ② mul -5 * 4 = -20 -> ffffffec
|
||
# ③ mulh 0x40000000 * 4 高 32 位 -> 00000001
|
||
# ④ mulhu 0xffffffff * 2 高 32 位 -> 00000001
|
||
# ⑤ mulhsu -1 * 0xffffffff 高 32 位 -> ffffffff
|
||
# ⑥ divu 100 / 7 = 14 -> 0000000e
|
||
# ⑦ remu 100 % 7 = 2 -> 00000002
|
||
# ⑧ divu 0xffffffff / 2 = 2147483647 -> 7fffffff
|
||
# ⑨ divu 12345 / 0 除零约定 -> ffffffff
|
||
# ⑩ remu 12345 % 0 除零约定 -> 00003039
|
||
# ⑪ remu 0xffffffff % 16 = 15 -> 0000000f
|
||
# ⑫ mul 0x12345678 * 16 低 32 位 -> 23456780
|
||
# ⑬ mulh 0x12345678 * 0x1000 高 32 位 -> 00000123
|
||
#
|
||
# 用法:python tools/rv_asm.py testbench/programs/muldiv_test.asm testbench/rom/muldiv_test.hex
|
||
|
||
# ① mul:有符号乘法的低 32 位
|
||
addi t1, zero, 7
|
||
addi t2, zero, 6
|
||
mul a0, t1, t2
|
||
print
|
||
|
||
# ② mul:负乘数(低 32 位)
|
||
addi t1, zero, -5
|
||
addi t2, zero, 4
|
||
mul a0, t1, t2
|
||
print
|
||
|
||
# ③ mulh:正数相乘,高 32 位不为 0
|
||
lui t1, 0x40000
|
||
addi t2, zero, 4
|
||
mulh a0, t1, t2
|
||
print
|
||
|
||
# ④ mulhu:无符号高位(0xffffffff * 2 = 0x1_fffffffe)
|
||
addi t1, zero, -1
|
||
addi t2, zero, 2
|
||
mulhu a0, t1, t2
|
||
print
|
||
|
||
# ⑤ mulhsu:有符号 x 无符号(-1 * 4294967295 = 0xffffffff_00000001)
|
||
addi t1, zero, -1
|
||
addi t2, zero, -1
|
||
mulhsu a0, t1, t2
|
||
print
|
||
|
||
# ⑥ divu:普通除法
|
||
addi t1, zero, 100
|
||
addi t2, zero, 7
|
||
divu a0, t1, t2
|
||
print
|
||
|
||
# ⑦ remu:普通取余
|
||
remu a0, t1, t2
|
||
print
|
||
|
||
# ⑧ divu:无符号大数
|
||
addi t1, zero, -1
|
||
addi t2, zero, 2
|
||
divu a0, t1, t2
|
||
print
|
||
|
||
# ⑨ divu:除零(商为全 1)
|
||
lui t1, 0x3
|
||
addi t1, t1, 0x39 # t1 = 12345
|
||
addi t2, zero, 0
|
||
divu a0, t1, t2
|
||
print
|
||
|
||
# ⑩ remu:除零(余数为被除数)
|
||
remu a0, t1, t2
|
||
print
|
||
|
||
# ⑪ remu:0xffffffff % 16
|
||
addi t1, zero, -1
|
||
addi t2, zero, 16
|
||
remu a0, t1, t2
|
||
print
|
||
|
||
# ⑫ mul:0x12345678 * 16 的低 32 位
|
||
lui t1, 0x12345
|
||
addi t1, t1, 0x678
|
||
addi t2, zero, 16
|
||
mul a0, t1, t2
|
||
print
|
||
|
||
# ⑬ mulh:0x12345678 * 0x1000 的高 32 位
|
||
lui t2, 0x1
|
||
mulh a0, t1, t2
|
||
print
|
||
|
||
halt
|