源文件收敛到 pipelined-cpu/ 一份:删除根目录 rtl/board/testbench/tools,补充回归脚本
- 现在只有一份源文件,就在 pipelined-cpu/ 下:
srcs/rtl(13 个处理器 RTL)、srcs/board、srcs/constrs、srcs/tb、srcs/rom、
tools/(rv_asm.py、hex2vh.py、run_regress.ps1)、programs/(汇编源码与期望值)。
仓库根目录的 rtl/、board/、testbench/、tools/ 已删除(删除前逐个文件比对过 MD5,
与工程目录里的副本完全一致),说明文档仍放在最外层
cpu21_riscv_redirect_int_bpb说明.md。
- .gitignore 改为:忽略 pipelined-cpu/ 下的工程生成物(*.xpr、*.runs、*.sim、*.cache…),
只跟踪 srcs/、tools/、programs/、create_project.tcl;_tmp/、_vivado/ 等本地临时目录
继续忽略。
- 新增 tools/run_regress.ps1:一键回归脚本。编译 srcs/rtl/ → 跑 muldiv/isa/lui/mmio
四个指令测试并与 programs/*.expected 逐值比对 → 跑两个流水基线 → 跑板级顶层
(-d BOARD_ROM_FAST)检查跑马灯,最后汇总 PASS/FAIL 并返回失败数作为退出码。
编译与仿真的中间文件写在 %TEMP%\cpu21_regress,不污染工程目录。实测全部通过。
- 新增 programs/board_demo_fast.asm:快速版演示程序(延时初值 64,约 2.6 µs/步),
对应 srcs/board/cpu21_board_rom_fast.vh;仿真时用 -d BOARD_ROM_FAST 才会选到它。
- 两个测试平台增加 srcs/rom 探测路径,工程目录内直接 Run Simulation 即可加载镜像。
- 文档:目录结构一节按新布局重写;新增“回归测试”一节(脚本用法 + 期望基线数字);
上板章节的生成/仿真命令改为相对工程目录(python tools/rv_asm.py programs/…、
xvlog -d BOARD_ROM_FAST srcs/rtl/*.v …);tools 里的用法示例同步更新;
“工程分享”一节去掉已不存在的副本同步说明。
- 清理:删除本地 _tmp/(约 57 MB)、_vivado/、.Xil/ 临时目录。
This commit is contained in:
@@ -0,0 +1,169 @@
|
||||
`timescale 1ns / 1ps
|
||||
`default_nettype none
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// 多周期乘除法单元(时序逻辑,32 拍迭代)
|
||||
//
|
||||
// 原来乘除法直接写在 ALU 里(组合的 a*b / a%b):综合后关键路径约 94 ns
|
||||
// (325 级逻辑、286 个 CARRY4),100 MHz 下无法收敛,只能把板上 100 MHz 分频
|
||||
// 到 6.25 MHz 再跑。这里改成移位迭代:
|
||||
// * 乘法:32 拍移位加法得到 64 位乘积;有符号变体先取操作数绝对值,
|
||||
// 迭代结束后按符号对 64 位乘积取负。
|
||||
// * 除法:32 拍恢复余数法得到商与余数;除零按 RISC-V 约定处理
|
||||
// (商为全 1、余数为被除数)。DIVU/REMU 都是无符号运算,不需要符号修正。
|
||||
//
|
||||
// 顶层的 EX 级会停留若干拍(往 EX/MEM 插气泡)等待 done_o 有效,然后照常写回。
|
||||
// 迭代期间顶层会屏蔽中断,避免在结果未定型时提前推进流水线。
|
||||
//
|
||||
// op_i 编码(由 cpu21_riscv_decoder 给出,MD_NONE 表示不是乘除法指令):
|
||||
// MD_MUL mul :无符号乘积低 32 位(有符号乘法的低 32 位与之相同)
|
||||
// MD_MULH mulh :有符号 x 有符号,取高 32 位
|
||||
// MD_MULHSU mulhsu :有符号 x 无符号,取高 32 位
|
||||
// MD_MULHU mulhu :无符号 x 无符号,取高 32 位
|
||||
// MD_DIVU divu :无符号商
|
||||
// MD_REMU remu :无符号余数
|
||||
//
|
||||
// result_o / result2_o 的含义与原来的 ALU 保持一致:乘法时 result_o 为低 32 位、
|
||||
// result2_o 为高 32 位;除法时 result_o 为商、result2_o 为余数。译码器用 wb_sel
|
||||
// 决定写回哪一个(mulhu、remu 用 wb_sel=3 取 result2),因此顶层只需把这一对
|
||||
// 结果接到原来的 EX 结果总线上,其余流水逻辑不用改。
|
||||
// -----------------------------------------------------------------------------
|
||||
module cpu21_riscv_muldiv (
|
||||
input wire clk,
|
||||
input wire reset, // 异步复位,高有效(与顶层一致)
|
||||
input wire start_i, // 指令在 EX 级且是乘除法(电平,模块内部只在空闲时响应)
|
||||
input wire [2:0] op_i, // 乘除法操作类型
|
||||
input wire [31:0] a_i, // EX 级 src1
|
||||
input wire [31:0] b_i, // EX 级 src2(ALU 的 B 端)
|
||||
output wire busy_o, // 迭代中(不含结果定型那一拍)
|
||||
output wire done_o, // 结果有效(单拍,此时顶层推进流水线)
|
||||
output wire [31:0] result_o, // 主结果
|
||||
output wire [31:0] result2_o // 第二结果(乘法高 32 位 / 除法余数)
|
||||
);
|
||||
localparam [2:0] MD_NONE = 3'd0;
|
||||
localparam [2:0] MD_MUL = 3'd1;
|
||||
localparam [2:0] MD_MULH = 3'd2;
|
||||
localparam [2:0] MD_MULHSU = 3'd3;
|
||||
localparam [2:0] MD_MULHU = 3'd4;
|
||||
localparam [2:0] MD_DIVU = 3'd5;
|
||||
localparam [2:0] MD_REMU = 3'd6;
|
||||
|
||||
localparam [1:0] S_IDLE = 2'd0;
|
||||
localparam [1:0] S_RUN = 2'd1;
|
||||
localparam [1:0] S_DONE = 2'd2;
|
||||
|
||||
reg [ 1:0] state_q;
|
||||
reg [ 5:0] cnt_q; // 0..32:0..31 为迭代,32 为结果定型
|
||||
reg [ 2:0] op_q;
|
||||
reg is_div_q;
|
||||
|
||||
// 乘法数据通路:64 位被乘数(每拍左移)、32 位乘数(每拍右移)、64 位累加器。
|
||||
reg [63:0] mcand_q;
|
||||
reg [31:0] mplier_q;
|
||||
reg [63:0] prod_q;
|
||||
reg sign_q;
|
||||
|
||||
// 除法数据通路:32 位除数、32 位商/被除数移位寄存器、33 位余数。
|
||||
reg [31:0] dvsr_q;
|
||||
reg [31:0] quo_q;
|
||||
reg [32:0] rem_q;
|
||||
reg [31:0] dvd_q; // 原始被除数(除零时原样返回)
|
||||
reg div_zero_q;
|
||||
|
||||
// 结果寄存器。
|
||||
reg [31:0] res_q;
|
||||
reg [31:0] res2_q;
|
||||
|
||||
assign busy_o = (state_q == S_RUN);
|
||||
assign done_o = (state_q == S_DONE);
|
||||
assign result_o = res_q;
|
||||
assign result2_o = res2_q;
|
||||
|
||||
// 乘法操作数准备:按操作类型决定是否取绝对值,并给出结果符号。
|
||||
wire a_signed = (op_i == MD_MULH) || (op_i == MD_MULHSU);
|
||||
wire b_signed = (op_i == MD_MULH);
|
||||
wire [31:0] a_mag = (a_signed && a_i[31]) ? (~a_i + 32'd1) : a_i;
|
||||
wire [31:0] b_mag = (b_signed && b_i[31]) ? (~b_i + 32'd1) : b_i;
|
||||
wire sign_in = ((op_i == MD_MULH) && (a_i[31] ^ b_i[31])) || ((op_i == MD_MULHSU) && a_i[31]);
|
||||
|
||||
// 除法的一步(恢复余数法):把被除数最高位移进余数,够减则减并把商位置 1。
|
||||
wire [32:0] rem_shift = {rem_q[31:0], quo_q[31]};
|
||||
wire rem_ge = (rem_shift >= {1'b0, dvsr_q});
|
||||
wire [32:0] rem_next = rem_ge ? (rem_shift - {1'b0, dvsr_q}) : rem_shift;
|
||||
wire [31:0] quo_next = {quo_q[30:0], rem_ge};
|
||||
|
||||
// 迭代结束时的符号修正:prod_mag 为无符号乘积,sign_q 为 1 时取负。
|
||||
wire [63:0] prod_fix = sign_q ? (~prod_q + 64'd1) : prod_q;
|
||||
|
||||
always @(posedge clk or posedge reset) begin
|
||||
if (reset) begin
|
||||
state_q <= S_IDLE;
|
||||
cnt_q <= 6'd0;
|
||||
op_q <= MD_NONE;
|
||||
is_div_q <= 1'b0;
|
||||
mcand_q <= 64'd0;
|
||||
mplier_q <= 32'd0;
|
||||
prod_q <= 64'd0;
|
||||
sign_q <= 1'b0;
|
||||
dvsr_q <= 32'd0;
|
||||
quo_q <= 32'd0;
|
||||
rem_q <= 33'd0;
|
||||
dvd_q <= 32'd0;
|
||||
div_zero_q <= 1'b0;
|
||||
res_q <= 32'd0;
|
||||
res2_q <= 32'd0;
|
||||
end else begin
|
||||
case (state_q)
|
||||
// 空闲:指令进入 EX 且是乘除法时装载操作数,下一拍开始迭代。
|
||||
S_IDLE: begin
|
||||
if (start_i) begin
|
||||
state_q <= S_RUN;
|
||||
cnt_q <= 6'd0;
|
||||
op_q <= op_i;
|
||||
is_div_q <= (op_i == MD_DIVU) || (op_i == MD_REMU);
|
||||
// 乘法初始化(先取绝对值,符号留到最后修正)。
|
||||
mcand_q <= {32'b0, a_mag};
|
||||
mplier_q <= b_mag;
|
||||
prod_q <= 64'd0;
|
||||
sign_q <= sign_in;
|
||||
// 除法初始化(无符号)。
|
||||
dvsr_q <= b_i;
|
||||
quo_q <= a_i;
|
||||
rem_q <= 33'd0;
|
||||
dvd_q <= a_i;
|
||||
div_zero_q <= (b_i == 32'd0);
|
||||
end
|
||||
end
|
||||
|
||||
// 迭代:cnt 0..31 各走一步,32 拍后把结果定型。
|
||||
S_RUN: begin
|
||||
if (cnt_q == 6'd32) begin
|
||||
state_q <= S_DONE;
|
||||
if (is_div_q) begin
|
||||
res_q <= div_zero_q ? 32'hffff_ffff : quo_q;
|
||||
res2_q <= div_zero_q ? dvd_q : rem_q[31:0];
|
||||
end else begin
|
||||
res_q <= (op_q == MD_MULHU || op_q == MD_MUL) ? prod_fix[31:0] : prod_fix[63:32];
|
||||
res2_q <= prod_fix[63:32];
|
||||
end
|
||||
end else begin
|
||||
cnt_q <= cnt_q + 6'd1;
|
||||
if (is_div_q) begin
|
||||
rem_q <= rem_next;
|
||||
quo_q <= quo_next;
|
||||
end else begin
|
||||
prod_q <= mplier_q[0] ? (prod_q + mcand_q) : prod_q;
|
||||
mcand_q <= {mcand_q[62:0], 1'b0};
|
||||
mplier_q <= {1'b0, mplier_q[31:1]};
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// 结果有效一拍,顶层据此推进流水线;随后回到空闲。
|
||||
default: state_q <= S_IDLE;
|
||||
endcase
|
||||
end
|
||||
end
|
||||
endmodule
|
||||
|
||||
`default_nettype wire
|
||||
Reference in New Issue
Block a user