@@ -2,23 +2,24 @@
` default_nettype none
// -----------------------------------------------------------------------------
// cpu21-riscv-4.circ -> synthesizable Verilog
// cpu21-riscv-4.circ -> 可综合 Verilog 实现
//
// This file keeps the instruction encodings used by the Logisim design. The
// processor is a five-stage IF/ID/EX/MEM/WB pipeline with:
// * EX-stage forwarding and load-use interlock;
// * EX-stage control-flow resolution and pipeline redirect;
// * an eight-entry fully-associative branch target buffer;
// * three sampled interrupt sources with priority and nested URET return;
// * the original ecall convention: a7==34 writes the LED value, otherwise
// the pipeline waits for go_i.
// 本文件保留 Logisim 原设计所使用的指令编码。处理器为五级流水线
// IF/ID/EX/MEM/WB,主要特性:
// * EX 级前递( forwarding)与 load-use 冒险互锁;
// * EX 级控制流裁决与流水线重定向;
// * 八表项全相联分支目标缓冲(BPB);
// * 三路采样的中断源,带优先级与可嵌套的 URET 返回;
// * 沿用原 ecall 约定:a7==34 时写出 LED 值,否则流水线等待 go_i。
//
// Memory interface convention:
// instr_addr_o and data_addr_o are byte addresses. data_wstrb_o is a byte
// write mask, so an external word RAM can use data_addr_o[11:2] as its word
// index and merge bytes according to data_wstrb_o.
// 存储器接口约定:
// instr_addr_o 与 data_addr_o 均为字节地址。 data_wstrb_o 是字节写掩码,
// 因此外部字宽 RAM 可用 data_addr_o[11:2] 作为字索引,再依据
// data_wstrb_o 完成字节合并。
// -----------------------------------------------------------------------------
// ALU:纯组合运算单元。result2 作为第二结果输出,用于 MUL 的高 32 位
// 以及 DIVU 的余数;除法则以 b==0 作为除零保护。
module cpu21_riscv_alu (
input wire [ 3 : 0 ] op ,
input wire [ 31 : 0 ] a ,
@@ -70,9 +71,9 @@ module cpu21_riscv_alu (
endmodule
// Eight-entry fully-associative branch target buffer.
// tag = PC[11:2], matching the ten-bit tag splitter in the Logisim BPB.
// count is a two-bit saturating predictor: 00/01 not-taken, 10/11 taken.
// 八表项全相联分支目标缓冲(BPB/BTB)。
// tag = PC[11:2],与 Logisim 版 BPB 中的十位 tag 拆分保持一致。
// count 为两位饱和计数器:00/01 表示不跳转,10/11 表示跳转。
module cpu21_bpb_8 (
input wire clk ,
input wire reset ,
@@ -103,6 +104,7 @@ module cpu21_bpb_8 (
integer k ;
integer selected_index ;
// 预测命中查找:按 tag 全相联匹配,命中则给出目标地址与方向预测。
always @ * begin
predict_hit = 1 ' b 0 ;
p r e d i c t _ t a k e n = 1 ' b0 ;
@@ -116,8 +118,8 @@ module cpu21_bpb_8 (
end
end
// Find a matching entry, otherwise use the first invalid entry, otherwise
// the oldest entry. The age update below implements an LRU-like policy.
// 更新时先找匹配表项;若无匹配则优先使用无效表项,否则淘汰最旧表项。
// 下方的 age 自增实现了类似 LRU 的替换策略。
always @ * begin
update_found = 1 ' b 0 ;
u p d a t e _ i n d e x = 3 ' d0 ;
@@ -142,6 +144,7 @@ module cpu21_bpb_8 (
e n d
e n d
/ / 表 项 状 态 更 新 ( 含 替 换 与 两 位 饱 和 计 数 器 更 新 ) 。
a l w a y s @ ( p o s e d g e c l k o r p o s e d g e r e s e t ) b e g i n
i f ( r e s e t ) b e g i n
f o r ( k = 0 ; k < 8 ; k = k + 1 ) b e g i n
@@ -160,11 +163,13 @@ module cpu21_bpb_8 (
a g e [ s e l e c t e d _ i n d e x ] < = 3 ' b0 ;
if ( ! update_found ) begin
// Weak initial state avoids an immediate false prediction.
// 新表项采用较弱的初始状态,避免立刻产生错误预测。
count [ selected_index ] <= update_taken ? 2 ' b 1 0 : 2 ' b01 ;
end else if ( update_taken ) begin
// 实际跳转:计数器加一(饱和到 11)。
if ( count [ selected_index ] != 2 ' b 1 1 ) c o u n t [ s e l e c t e d _ i n d e x ] < = c o u n t [ s e l e c t e d _ i n d e x ] + 2 ' b01 ;
end else begin
// 实际不跳转:计数器减一(饱和到 00)。
if ( count [ selected_index ] != 2 ' b 0 0 ) c o u n t [ s e l e c t e d _ i n d e x ] < = c o u n t [ s e l e c t e d _ i n d e x ] - 2 ' b01 ;
end
@@ -176,15 +181,16 @@ module cpu21_bpb_8 (
endmodule
// 顶层模块:五级流水线 RISC-V 处理器,内置分支预测与多级中断支持。
module cpu21_riscv_redirect_int_bpb # (
parameter RESET_PC = 32 ' h 0 0 0 0 _ 0 0 0 0 ,
p a r a m e t e r I R Q 1 _ V E C T O R = 3 2 ' h0000_30ac ,
parameter IRQ2_VECTOR = 32 ' h 0 0 0 0 _ 3 1 e 4 ,
p a r a m e t e r I R Q 3 _ V E C T O R = 3 2 ' h0000_3310 ,
parameter IRQ_STACK_DEPTH = 4 ,
// ustatus reset value. B it 0 is MIE. The course interrupt test program
// only sets MIE inside its interrupt handlers, so the mainline would never
// acknowledge the first interrupt unless MIE is enabled right after reset.
// ustatus 复位值。b it0 为 MIE。课程的中断测试程序只会在中断处理
// 程序中设置 MIE,若复位后不立即置位 MIE,主程序将永远无法响应
// 第一次中断,因此这里默认打开 MIE。
parameter [ 31 : 0 ] USTATUS_INIT = 32 ' h 0 0 0 0 _ 0 0 0 1
) (
i n p u t w i r e c l k ,
@@ -234,7 +240,7 @@ module cpu21_riscv_redirect_int_bpb #(
o u t p u t w i r e [ 1 5 : 0 ] p r e d i c t i o n _ s u c c e s s _ c o u n t _ o ,
o u t p u t w i r e [ 1 5 : 0 ] p r e d i c t i o n _ f a i l u r e _ c o u n t _ o
) ;
/ / C u s t o m C P U 2 1 o p c o d e s f r o m t h e s u p p l i e d t r u t h t a b l e .
/ / C P U 2 1 自 定 义 操 作 码 ( 取 自 所 提 供 的 真 值 表 ) 。
l o c a l p a r a m O P _ L O A D = 5 ' h00 ;
localparam OP_R = 5 ' h 0 c ;
l o c a l p a r a m O P _ I = 5 ' h04 ;
@@ -257,14 +263,17 @@ module cpu21_riscv_redirect_int_bpb #(
l o c a l p a r a m A L U _ S L T = 4 ' d11 ;
localparam ALU_SLTU = 4 ' d 1 2 ;
/ / 当 前 取 指 P C 。
r e g [ 3 1 : 0 ] p c _ q ;
/ / I F / I D 流 水 寄 存 器 ( 含 本 条 指 令 所 携 带 的 分 支 预 测 信 息 ) 。
r e g i f i d _ v a l i d _ q ;
r e g [ 3 1 : 0 ] i f i d _ p c _ q ;
r e g [ 3 1 : 0 ] i f i d _ i r _ q ;
r e g i f i d _ p r e d _ t a k e n _ q ;
r e g [ 3 1 : 0 ] i f i d _ p r e d _ t a r g e t _ q ;
/ / I D / E X 流 水 寄 存 器 : 保 存 译 码 结 果 与 操 作 数 。
r e g i d e x _ v a l i d _ q ;
r e g [ 3 1 : 0 ] i d e x _ p c _ q ;
r e g [ 3 1 : 0 ] i d e x _ i r _ q ;
@@ -296,6 +305,7 @@ module cpu21_riscv_redirect_int_bpb #(
r e g i d e x _ p r e d _ t a k e n _ q ;
r e g [ 3 1 : 0 ] i d e x _ p r e d _ t a r g e t _ q ;
/ / E X / M E M 流 水 寄 存 器 : 保 存 A L U / 存 储 结 果 与 写 回 控 制 。
r e g e x m e m _ v a l i d _ q ;
r e g [ 3 1 : 0 ] e x m e m _ p c _ q ;
r e g [ 3 1 : 0 ] e x m e m _ i r _ q ;
@@ -310,6 +320,7 @@ module cpu21_riscv_redirect_int_bpb #(
r e g [ 3 : 0 ] e x m e m _ w s t r b _ q ;
r e g [ 2 : 0 ] e x m e m _ w b _ s e l _ q ;
/ / M E M / W B 流 水 寄 存 器 : 保 存 访 存 数 据 与 最 终 写 回 信 息 。
r e g m e m w b _ v a l i d _ q ;
r e g [ 3 1 : 0 ] m e m w b _ p c _ q ;
r e g [ 3 1 : 0 ] m e m w b _ i r _ q ;
@@ -322,13 +333,14 @@ module cpu21_riscv_redirect_int_bpb #(
r e g m e m w b _ m e m _ t o _ r e g _ q ;
r e g [ 2 : 0 ] m e m w b _ w b _ s e l _ q ;
/ / 寄 存 器 堆 、 L E D 输 出 、 停 机 标 志 。
r e g [ 3 1 : 0 ] r e g f i l e [ 0 : 3 1 ] ;
r e g [ 3 1 : 0 ] l e d _ d a t a _ q ;
r e g l e d _ v a l i d _ q ;
r e g h a l t e d _ q ;
/ / I n t e r r u p t s t a t e . u s t a t u s [ 0 ] i s t h e c i r c u i t ' s MIE bit . A small stack
// keeps EPC/status/priority so nested interrupts can return correctly.
/ / 中 断 相 关 状 态 。 u s t a t u s [ 0 ] 即 电 路 中 的 M I E 位 。 用 一 个 小 的 硬 件 栈
/ / 保 存 E P C / 状 态 / 优 先 级 , 使 嵌 套 中 断 能 够 正 确 返 回 。
r e g [ 3 1 : 0 ] u s t a t u s _ q ;
r e g [ 3 1 : 0 ] u e p c _ q ;
r e g [ 1 : 0 ] i r q _ c u r r e n t _ q ;
@@ -341,6 +353,7 @@ module cpu21_riscv_redirect_int_bpb #(
r e g [ 1 : 0 ] p r i o r i t y _ s t a c k [ 0 : I R Q _ S T A C K _ D E P T H - 1 ] ;
r e g [ 2 : 0 ] i r q _ d e p t h _ q ;
/ / 性 能 计 数 器 , 用 于 统 计 周 期 数 、 停 顿 、 气 泡 与 分 支 预 测 效 果 。
r e g [ 1 5 : 0 ] c y c l e _ c o u n t _ q ;
r e g [ 1 5 : 0 ] s t a l l _ c o u n t _ q ;
r e g [ 1 5 : 0 ] b u b b l e _ c o u n t _ q ;
@@ -350,10 +363,10 @@ module cpu21_riscv_redirect_int_bpb #(
r e g [ 1 5 : 0 ] p r e d i c t i o n _ f a i l u r e _ c o u n t _ q ;
/ / - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Decode in ID.
/ / I D 级 译 码 。
/ / - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// The Logisim controller receives the standard RISC-V opcode field
// IR[6:2] (the table stores this five-bit field in hexadecimal).
/ / L o g i s i m 控 制 器 接 收 的 是 标 准 R I S C - V 操 作 码 字 段 I R [ 6 : 2 ] ( 真 值 表 中
/ / 以 十 六 进 制 形 式 存 储 该 五 位 字 段 ) 。
w i r e [ 4 : 0 ] d _ o p c o d e = i f i d _ i r _ q [ 6 : 2 ] ;
w i r e [ 2 : 0 ] d _ f u n c t 3 = i f i d _ i r _ q [ 1 4 : 1 2 ] ;
w i r e [ 6 : 0 ] d _ f u n c t 7 = i f i d _ i r _ q [ 3 1 : 2 5 ] ;
@@ -384,6 +397,7 @@ module cpu21_riscv_redirect_int_bpb #(
r e g [ 3 1 : 0 ] d _ i m m ;
w i r e [ 1 1 : 0 ] d _ c s r _ a d d r = i f i d _ i r _ q [ 3 1 : 2 0 ] ;
/ / 默 认 控 制 信 号 : 全 部 为 " 无 操 作 / 不 写 回 " , 再 由 下 面 的 c a s e 覆 盖 。
a l w a y s @ * b e g i n
d _ r e g _ w r i t e = 1 ' b0 ;
d_mem_to_reg = 1 ' b 0 ;
@@ -411,18 +425,20 @@ module cpu21_riscv_redirect_int_bpb #(
d_imm = { { 20 { ifid_ir_q [ 31 ] } } , ifid_ir_q [ 31 : 20 ] } ;
case ( d_opcode )
// R 型运算:由 funct3/funct7 决定具体操作。
OP_R : begin
d_uses_rs1 = 1 ' b 1 ;
d _ u s e s _ r s 2 = 1 ' b1 ;
d_reg_write = 1 ' b 1 ;
// The circuit's extra REMU control is the standard R-type
// funct7=1/funct3=111 form; ALU result2 is the remainder.
/ / 电 路 中 额 外 的 R E M U 控 制 对 应 标 准 R 型 的 f u n c t 7 = 1 / f u n c t 3 = 1 1 1
/ / 形 式 ; 此 时 A L U 的 r e s u l t 2 即 为 余 数 。
i f ( ( d _ f u n c t 7 = = 7 ' b0000001 ) && ( d_funct3 == 3 ' b 1 1 1 ) ) b e g i n
d _ a l u o p = A L U _ D I V U ;
d _ w b _ s e l = 3 ' d3 ;
end else if ( ( d_funct7 == 7 ' b 0 0 0 0 0 0 1 ) & & ( d _ f u n c t 3 = = 3 ' b000 ) ) begin
d_aluop = ALU_MUL ;
end else begin
// 标准 R 型 funct3 译码;add/sub 与 sra/srl 由 funct7[5] 区分。
case ( d_funct3 )
3 ' b 0 0 0 : d _ a l u o p = ( d _ f u n c t 7 [ 5 ] ? A L U _ S U B : A L U _ A D D ) ;
3 ' b001 : d_aluop = ALU_SLL ;
@@ -437,22 +453,25 @@ module cpu21_riscv_redirect_int_bpb #(
e n d
e n d
/ / I 型 运 算 ( a d d i / s l l i / s l t i / x o r i / s r a i / s r l i / o r i / a n d i ) 。
O P _ I : b e g i n
d _ u s e s _ r s 1 = 1 ' b1 ;
d_alu_src = 1 ' b 1 ;
d _ r e g _ w r i t e = 1 ' b1 ;
case ( d_funct3 )
3 ' b000 : d_aluop = ALU_ADD ; // addi
3 ' b 0 0 1 : d _ a l u o p = A L U _ S L L ; / / s l l i
3 ' b010 : d_aluop = ALU_SLT ; // slti
3 ' b 1 0 0 : d _ a l u o p = A L U _ X O R ; / / x o r i
3 ' b101 : d_aluop = ( d_funct7 [ 5 ] ? ALU_SRA : ALU_SRL ) ;
3 ' b 1 1 0 : d _ a l u o p = A L U _ O R ; / / o r i
3 ' b111 : d_aluop = ALU_AND ; // andi
3 ' b 0 0 0 : d _ a l u o p = A L U _ A D D ; / / a d d i : 立 即 数 加
3 ' b001 : d_aluop = ALU_SLL ; // slli:立即数逻辑左移
3 ' b 0 1 0 : d _ a l u o p = A L U _ S L T ; / / s l t i : 有 符 号 小 于 置 1
3 ' b100 : d_aluop = ALU_XOR ; // xori:立即数异或
3 ' b 1 0 1 :
d _ a l u o p = ( d _ f u n c t 7 [ 5 ] ? A L U _ S R A : A L U _ S R L ) ; / / s r a i / s r l i : 立 即 数 算 术 / 逻 辑 右 移
3 ' b110 : d_aluop = ALU_OR ; // ori:立即数或
3 ' b 1 1 1 : d _ a l u o p = A L U _ A N D ; / / a n d i : 立 即 数 与
d e f a u l t : d _ r e g _ w r i t e = 1 ' b0 ;
endcase
end
// 加载指令,当前仅支持 lw( funct3=010)。
OP_LOAD : begin
if ( d_funct3 == 3 ' b 0 1 0 ) b e g i n
d _ u s e s _ r s 1 = 1 ' b1 ;
@@ -464,6 +483,7 @@ module cpu21_riscv_redirect_int_bpb #(
end
end
// 存储指令:sw( funct3=010)与 sb( funct3=000)。
OP_STORE : begin
if ( ( d_funct3 == 3 ' b 0 1 0 ) | | ( d _ f u n c t 3 = = 3 ' b000 ) ) begin
d_uses_rs1 = 1 ' b 1 ;
@@ -471,11 +491,12 @@ module cpu21_riscv_redirect_int_bpb #(
d_alu_src = 1 ' b 1 ;
d _ a l u o p = A L U _ A D D ;
d _ m e m _ w r i t e = 1 ' b1 ;
d _ m e m _ b y t e = ( d _ f u n c t 3 = = 3 ' b000 ) ; // sb
d_mem_byte = ( d_funct3 == 3 ' b 0 0 0 ) ; / / s b : 字 节 存 储
d _ i m m = { { 2 0 { i f i d _ i r _ q [ 3 1 ] } } , i f i d _ i r _ q [ 3 1 : 2 5 ] , i f i d _ i r _ q [ 1 1 : 7 ] } ;
e n d
e n d
/ / 条 件 分 支 : b e q ( 0 0 0 ) / b n e ( 0 0 1 ) / b l t u ( 1 1 0 ) 。
O P _ B R A N C H : b e g i n
i f ( ( d _ f u n c t 3 = = 3 ' b000 ) || ( d_funct3 == 3 ' b 0 0 1 ) | | ( d _ f u n c t 3 = = 3 ' b110 ) ) begin
d_uses_rs1 = 1 ' b 1 ;
@@ -496,6 +517,7 @@ module cpu21_riscv_redirect_int_bpb #(
e n d
e n d
/ / 无 条 件 跳 转 并 链 接 : j a l ( 写 回 P C + 4 ) 。
O P _ J A L : b e g i n
d _ j a l = 1 ' b1 ;
d_reg_write = 1 ' b 1 ;
@@ -510,6 +532,7 @@ module cpu21_riscv_redirect_int_bpb #(
} ;
e n d
/ / 寄 存 器 间 接 跳 转 并 链 接 : j a l r 。
O P _ J A L R : b e g i n
i f ( d _ f u n c t 3 = = 3 ' b000 ) begin
d_jalr = 1 ' b 1 ;
@@ -521,33 +544,34 @@ module cpu21_riscv_redirect_int_bpb #(
e n d
e n d
/ / 系 统 指 令 : e c a l l / u r e t / C S R 读 写 。
O P _ S Y S : b e g i n
// The circuit uses IR[21] to distinguish URET from ecall.
/ / 电 路 用 I R [ 2 1 ] 区 分 U R E T 与 e c a l l 。
i f ( d _ f u n c t 3 = = 3 ' b000 ) begin
if ( ifid_ir_q [ 21 ] ) begin
d_uret = 1 ' b 1 ;
e n d e l s e b e g i n
d _ e c a l l = 1 ' b1 ;
/ / e c a l l r e a d s a 7 a n d a 0 , a s d o c u m e n t e d i n t h e s h e e t .
// 按文档说明,ecall 读取 a7(rs17) 与 a0(rs10)。
d_uses_rs1 = 1 ' b 1 ;
d _ u s e s _ r s 2 = 1 ' b1 ;
d_src1_idx = 5 ' d 1 7 ;
d _ s r c 2 _ i d x = 5 ' d10 ;
end
end else if ( d_funct3 == 3 ' b 0 0 1 ) b e g i n
d_csr_write = 1 ' b 1 ; / / C S R R W
d _ c s r _ w r i t e = 1 ' b1 ; // CSRRW:写 CSR,并把旧值写回 rd
d_uses_rs1 = 1 ' b 1 ;
d _ a l u _ s r c = 1 ' b1 ;
d_imm = { 27 ' b 0 , i f i d _ i r _ q [ 1 9 : 1 5 ] } ;
d _ r e g _ w r i t e = ( d _ r d ! = 5 ' d0 ) ;
d_wb_sel = 3 ' d 4 ;
e n d e l s e i f ( d _ f u n c t 3 = = 3 ' b110 ) begin
d _ c s r _ s e t = 1 ' b1 ; // CSRRSI
d_csr_set = 1 ' b 1 ; / / C S R R S I : 置 位 C S R 中 的 指 定 位
d _ i m m = { 2 7 ' b0 , ifid_ir_q [ 19 : 15 ] } ;
d_reg_write = ( d_rd != 5 ' d 0 ) ;
d _ w b _ s e l = 3 ' d4 ;
end else if ( d_funct3 == 3 ' b 1 1 1 ) b e g i n
d_csr_clear = 1 ' b 1 ; / / C S R R C I
d _ c s r _ c l e a r = 1 ' b1 ; // CSRRCI:清除 CSR 中的指定位
d_imm = { 27 ' b 0 , i f i d _ i r _ q [ 1 9 : 1 5 ] } ;
d _ r e g _ w r i t e = ( d _ r d ! = 5 ' d0 ) ;
d_wb_sel = 3 ' d 4 ;
@@ -559,13 +583,15 @@ module cpu21_riscv_redirect_int_bpb #(
e n d c a s e
e n d
// Register-file read with a write-first bypass for the same cycle's WB.
/ / 写 回 值 选 择 : w b _ s e l 0 = A L U 结 果 , 1 = 访 存 数 据 , 2 = P C + 4 , 3 = M U L 高 位 / 余 数 ,
/ / 4 = C S R 旧 值 。
w i r e [ 3 1 : 0 ] w b _ v a l u e ;
a s s i g n w b _ v a l u e = ( m e m w b _ w b _ s e l _ q = = 3 ' d1 ) ? memwb_mem_data_q :
( memwb_wb_sel_q == 3 ' d 2 ) ? ( m e m w b _ p c _ q + 3 2 ' d4 ) :
( memwb_wb_sel_q == 3 ' d 3 ) ? m e m w b _ a l u _ r e s u l t 2 _ q :
( m e m w b _ w b _ s e l _ q = = 3 ' d4 ) ? memwb_csr_old_q :
memwb_alu_result_q ;
// ID 级读寄存器:x0 恒为 0,并对同周期 WB 的结果做写优先旁路。
wire [ 31 : 0 ] d_rs1_value = ( d_src1_idx == 5 ' d 0 ) ? 3 2 ' b0 :
( ( memwb_valid_q && memwb_reg_write_q &&
( memwb_rd_q == d_src1_idx ) ) ? wb_value :
@@ -576,8 +602,8 @@ module cpu21_riscv_redirect_int_bpb #(
regfile [ d_src2_idx ] ) ;
// -------------------------------------------------------------------------
/ / I F b r a n c h p r e d i c t i o n . J A L / J A L R a r e r e s o l v e d i n E X , w h i l e c o n d i t i o n a l
/ / b r a n c h e s m a y r e d i r e c t t h e f e t c h P C i m m e d i a t e l y f r o m a B P B t a r g e t .
// IF 级分支预测。JAL/JALR 在 EX 级裁决,条件分支则可以直接依据 BPB
// 给出的目标地址重定向取指 PC。
// -------------------------------------------------------------------------
wire [ 4 : 0 ] f_opcode = instr_i [ 6 : 2 ] ;
wire [ 2 : 0 ] f_funct3 = instr_i [ 14 : 12 ] ;
@@ -589,10 +615,12 @@ module cpu21_riscv_redirect_int_bpb #(
w i r e b p b _ p r e d i c t _ t a k e n ;
w i r e e x _ b r a n c h _ t a k e n ;
w i r e [ 3 1 : 0 ] e x _ t a r g e t ;
/ / B P B 更 新 端 口 : 在 E X 级 用 条 件 分 支 的 实 际 结 果 训 练 预 测 器 。
w i r e b p b _ u p d a t e _ e n a b l e = i d e x _ v a l i d _ q & & i d e x _ b r a n c h _ q ;
w i r e b p b _ u p d a t e _ t a k e n = e x _ b r a n c h _ t a k e n ;
w i r e [ 3 1 : 0 ] b p b _ u p d a t e _ t a r g e t = e x _ t a r g e t ;
/ / 分 支 目 标 缓 冲 实 例 。
c p u 2 1 _ b p b _ 8 u _ b p b (
. c l k ( c l k ) ,
. r e s e t ( r e s e t ) ,
@@ -608,12 +636,13 @@ module cpu21_riscv_redirect_int_bpb #(
. update_taken ( bpb_update_taken )
) ;
// 下一取指 PC:预测跳转命中时使用 BPB 目标地址,否则顺序加 4。
wire [ 31 : 0 ] fetch_next_pc =
( f_is_branch && bpb_predict_hit && bpb_predict_taken ) ?
bpb_predict_target : ( pc_q + 32 ' d 4 ) ;
/ / - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// EX forwarding, ALU, and control-flow resolution.
/ / E X 级 : 前 递 网 络 、 A L U 运 算 与 控 制 流 裁 决 。
/ / - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
r e g [ 3 1 : 0 ] e x _ s r c 1 ;
r e g [ 3 1 : 0 ] e x _ s r c 2 ;
@@ -626,6 +655,8 @@ module cpu21_riscv_redirect_int_bpb #(
( exmem_wb_sel_q == 3 ' d 4 ) ? e x m e m _ c s r _ o l d _ q :
e x m e m _ a l u _ r e s u l t _ q ;
/ / 前 递 优 先 级 : E X / M E M 的 结 果 最 新 , 其 次 为 M E M / W B 写 回 值 , 最 后 才 是
/ / 译 码 时 读 到 的 寄 存 器 值 。
a l w a y s @ * b e g i n
e x _ s r c 1 = i d e x _ r s 1 _ v a l u e _ q ;
e x _ s r c 2 = i d e x _ r s 2 _ v a l u e _ q ;
@@ -636,12 +667,15 @@ module cpu21_riscv_redirect_int_bpb #(
e l s e i f ( w b _ f o r w a r d _ v a l i d & & ( m e m w b _ r d _ q = = i d e x _ r s 2 _ i d x _ q ) ) e x _ s r c 2 = w b _ v a l u e ;
e n d
/ / A L U 的 B 端 : 立 即 数 或 r s 2 。
w i r e [ 3 1 : 0 ] e x _ a l u _ b = i d e x _ a l u _ s r c _ q ? i d e x _ i m m _ q : e x _ s r c 2 ;
w i r e [ 3 1 : 0 ] e x _ a l u _ r e s u l t ;
w i r e [ 3 1 : 0 ] e x _ a l u _ r e s u l t 2 ;
/ / 读 取 C S R 旧 值 ( u s t a t u s = 0 x 0 0 4 、 u e p c = 0 x 0 4 1 ) , 供 C S R 指 令 回 写 r d 。
w i r e [ 3 1 : 0 ] e x _ c s r _ o l d _ v a l u e =
( i d e x _ c s r _ a d d r _ q = = 1 2 ' h004 ) ? ustatus_q :
( idex_csr_addr_q == 12 ' h 0 4 1 ) ? u e p c _ q : 3 2 ' b0 ;
// ALU 实例(纯组合逻辑)。
cpu21_riscv_alu u_ex_alu (
. op ( idex_aluop_q ) ,
. a ( ex_src1 ) ,
@@ -650,14 +684,19 @@ module cpu21_riscv_redirect_int_bpb #(
. result2 ( ex_alu_result2 )
) ;
// 条件分支裁决:beq 相等、bne 不等、bltu 无符号小于。
assign ex_branch_taken = idex_branch_q &&
( ( idex_beq_q && ( ex_src1 == ex_src2 ) ) ||
( idex_bne_q && ( ex_src1 != ex_src2 ) ) ||
( idex_bltu_q && ( ex_src1 < ex_src2 ) ) ) ;
// 跳转目标:jalr 为 (rs1+imm) 且最低位清零;jal 为 PC+imm。
assign ex_target = idex_jalr_q ?
( ( ex_src1 + idex_imm_q ) & 32 ' h f f f f _ f f f e ) :
( i d e x _ p c _ q + i d e x _ i m m _ q ) ;
/ / E X 级 存 在 需 要 裁 决 的 控 制 流 指 令 。
w i r e e x _ c o n t r o l f l o w = i d e x _ v a l i d _ q & & ( i d e x _ b r a n c h _ q | | i d e x _ j a l _ q | | i d e x _ j a l r _ q ) ;
/ / 需 要 重 定 向 的 条 件 : 条 件 分 支 的 预 测 方 向 / 目 标 与 实 际 不 符 ; J A L / J A L R 则
/ / 一 定 在 E X 级 才 解 析 出 目 标 , 因 此 总 是 需 要 重 定 向 。
w i r e e x _ r e d i r e c t _ v a l i d = e x _ c o n t r o l f l o w & &
( i d e x _ b r a n c h _ q ?
( ( i d e x _ p r e d _ t a k e n _ q ! = e x _ b r a n c h _ t a k e n ) | |
@@ -666,6 +705,7 @@ module cpu21_riscv_redirect_int_bpb #(
wire [ 31 : 0 ] ex_redirect_pc =
( idex_branch_q && ! ex_branch_taken ) ? ( idex_pc_q + 32 ' d 4 ) : e x _ t a r g e t ;
/ / 存 储 数 据 对 齐 : 依 据 字 节 地 址 低 两 位 生 成 写 数 据 与 字 节 写 掩 码 。
r e g [ 3 1 : 0 ] e x _ s t o r e _ d a t a ;
r e g [ 3 : 0 ] e x _ s t o r e _ w s t r b ;
a l w a y s @ * b e g i n
@@ -698,24 +738,27 @@ module cpu21_riscv_redirect_int_bpb #(
end
end
// ecall 约定:a7==34 时输出 LED;否则令处理器停机,等待 go_i 重新启动。
wire ex_led_event = idex_valid_q && idex_ecall_q && ( ex_src1 == 32 ' d 3 4 ) ;
w i r e e x _ h a l t _ e v e n t = i d e x _ v a l i d _ q & & i d e x _ e c a l l _ q & & ( e x _ s r c 1 ! = 3 2 ' d34 ) ;
/ / A l o a d i n E X f o l l o w e d b y a c o n s u m e r i n I D n e e d s o n e b u b b l e . A L U a n d
/ / b r a n c h d e p e n d e n c i e s a r e h a n d l e d b y t h e f o r w a r d i n g n e t w o r k a b o v e .
// EX 级为 load、而 ID 级指令立即使用其结果时,需要插入一个气泡。
// ALU 与分支的数据相关由上面的前递网络解决。
wire load_use_hazard = ifid_valid_q && idex_valid_q && idex_mem_to_reg_q &&
( idex_rd_q != 5 ' d 0 ) & &
( ( d _ u s e s _ r s 1 & & ( d _ s r c 1 _ i d x = = i d e x _ r d _ q ) ) | |
( d _ u s e s _ r s 2 & & ( d _ s r c 2 _ i d x = = i d e x _ r d _ q ) ) ) ;
/ / - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Interrupt sampling and priority selection.
// IRQ3 has the highest priority, then IRQ2, then IRQ1. A nested request
// is admitted only when its priority is higher than the current level.
/ / 中 断 采 样 与 优 先 级 选 择 。
/ / I R Q 3 优 先 级 最 高 , 其 次 I R Q 2 , 最 后 I R Q 1 。 嵌 套 请 求 只 有 在 优 先 级 高 于
/ / 当 前 级 别 时 才 会 被 接 纳 。
/ / - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
/ / 上 升 沿 检 测 : 只 在 i r q _ i 由 0 变 1 的 那 一 拍 产 生 中 断 事 件 。
w i r e [ 2 : 0 ] i r q _ e v e n t = i r q _ s y n c 2 _ q & ~ i r q _ p r e v _ q ;
r e g i r q _ s e l e c t e d _ v a l i d ;
r e g [ 1 : 0 ] i r q _ s e l e c t e d _ l e v e l ;
/ / 优 先 级 仲 裁 : 在 当 前 级 别 允 许 的 条 件 下 选 出 优 先 级 最 高 的 中 断 源 。
a l w a y s @ * b e g i n
i r q _ s e l e c t e d _ v a l i d = 1 ' b0 ;
irq_selected_level = 2 ' d 0 ;
@@ -732,20 +775,22 @@ module cpu21_riscv_redirect_int_bpb #(
end
wire ex_uret_redirect = idex_valid_q && idex_uret_q ;
/ / u e p c _ q i s t h e a c t i v e c o n t e x t ' s architectural return PC . The stack
// stores the interrupted outer contexts; using uepc_q here preserves the
// course-book sequence that saves/restores uepc with CSRRW.
// uepc_q 是当前运行上下文的架构返回 PC,栈中缓存的是被中断的外层
// 上下文。这里使用 uepc_q,与课程讲义中用 CSRRW 保存/恢复 uepc 的
// 流程保持一致。
wire [ 31 : 0 ] ex_return_pc = uepc_q ;
// 响应中断的条件:有已选中中断、MIE 使能、栈未溢出、未停机,且没有
// 正在处理的重定向/URET/停机事件。
wire take_irq = irq_selected_valid && ustatus_q [ 0 ] &&
( irq_depth_q < IRQ_STACK_DEPTH ) && ! halted_q &&
! ex_redirect_valid && ! ex_uret_redirect && ! ex_halt_event ;
// The EX instruction is allowed to complete when an interrupt is taken.
// Resume at the next architectural PC; if EX is a correctly predicted
// taken branch, that PC is its target. If EX is empty, IF/ID is the
// oldest instruction that has not executed yet.
// 响应中断时允许 EX 级指令正常完成。恢复地址取"下一个架构 PC":若
// EX 是一条预测正确且已跳转的分支,则该 PC 就是它的目标地址;若 EX
// 为空,则 IF/ID 中保存的就是尚未执行的最老指令。
wire [ 31 : 0 ] irq_save_pc = idex_valid_q ?
( ( idex_branch_q && ex_branch_taken ) ? ex_target : ( idex_pc_q + 32 ' d 4 ) ) :
( i f i d _ v a l i d _ q ? i f i d _ p c _ q : p c _ q ) ;
/ / 依 据 被 选 中 的 优 先 级 选 择 对 应 的 中 断 入 口 地 址 。
r e g [ 3 1 : 0 ] i r q _ v e c t o r ;
a l w a y s @ * b e g i n
c a s e ( i r q _ s e l e c t e d _ l e v e l )
@@ -756,6 +801,7 @@ module cpu21_riscv_redirect_int_bpb #(
endcase
end
// 组合逻辑计算下一拍的挂起位与 CSR(ustatus/uepc)取值。
reg [ 2 : 0 ] irq_pending_d ;
reg [ 31 : 0 ] ustatus_d ;
reg [ 31 : 0 ] uepc_d ;
@@ -792,14 +838,16 @@ module cpu21_riscv_redirect_int_bpb #(
e n d
/ / - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
/ / E x t e r n a l / d e b u g o u t p u t s .
/ / 对 外 输 出 与 调 试 信 号 。
/ / - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
/ / 存 储 器 接 口 : 指 令 地 址 来 自 取 指 P C ; 数 据 地 址 / 写 数 据 / 写 掩 码 来 自 M E M 级 。
a s s i g n i n s t r _ a d d r _ o = p c _ q ;
a s s i g n d a t a _ a d d r _ o = e x m e m _ a l u _ r e s u l t _ q ;
a s s i g n d a t a _ w d a t a _ o = e x m e m _ w r i t e _ d a t a _ q ;
a s s i g n d a t a _ w s t r b _ o = ( e x m e m _ v a l i d _ q & & e x m e m _ m e m _ w r i t e _ q ) ? e x m e m _ w s t r b _ q : 4 ' b0 ;
assign data_we_o = | data_wstrb_o ;
// LED 输出与流水线各级 PC/指令回显(用于调试与波形观察)。
assign led_data_o = led_data_q ;
assign led_valid_o = led_valid_q ;
assign if_pc_o = pc_q ;
@@ -832,15 +880,18 @@ module cpu21_riscv_redirect_int_bpb #(
assign prediction_success_count_o = prediction_success_count_q ;
assign prediction_failure_count_o = prediction_failure_count_q ;
// 需要冲刷年轻指令/气泡的情况:中断、URET、ecall 停机、分支重定向。
wire flush_younger = take_irq || ex_uret_redirect || ex_halt_event || ex_redirect_valid ;
// load-use 冒险且无需冲刷时,插入一个气泡(停顿一拍)。
wire pipeline_stall = load_use_hazard && ! flush_younger && ! halted_q ;
// -------------------------------------------------------------------------
// State update. Ordering follows the five-stage pipeline: WB commit,
// MEM/WB capture, EX/MEM capture, then ID/EX and IF/ID/PC control.
// 状态更新。顺序遵循五级流水线:先 WB 写回,再捕获 MEM/WB、EX/MEM,
// 最后处理 ID/EX 与 IF/ID/PC 的控制。
// -------------------------------------------------------------------------
integer r ;
integer s ;
// 复位时清空所有流水寄存器、寄存器堆、中断状态与性能计数器。
always @ ( posedge clk or posedge reset ) begin
if ( reset ) begin
pc_q <= RESET_PC ;
@@ -935,12 +986,12 @@ module cpu21_riscv_redirect_int_bpb #(
i f ( ! h a l t e d _ q ) c y c l e _ c o u n t _ q < = c y c l e _ c o u n t _ q + 1 6 ' d1 ;
led_valid_q <= 1 ' b 0 ;
/ / W B
/ / W B 级 : 写 回 寄 存 器 堆 ( x 0 恒 为 0 ) 。
i f ( m e m w b _ v a l i d _ q & & m e m w b _ r e g _ w r i t e _ q & & ( m e m w b _ r d _ q ! = 5 ' d0 ) )
regfile [ memwb_rd_q ] <= wb_value ;
regfile [ 0 ] <= 32 ' b 0 ;
/ / I n t e r r u p t s y n c h r o n i z e r s a n d p e n d i n g l a t c h e s .
/ / 中 断 输 入 打 两 拍 同 步 , 并 锁 存 挂 起 状 态 与 C S R 。
i r q _ s y n c 1 _ q < = i r q _ i ;
i r q _ s y n c 2 _ q < = i r q _ s y n c 1 _ q ;
i r q _ p r e v _ q < = i r q _ s y n c 2 _ q ;
@@ -970,7 +1021,7 @@ module cpu21_riscv_redirect_int_bpb #(
e n d
e n d
/ / M E M / W B
/ / M E M / W B 流 水 寄 存 器 捕 获 。
m e m w b _ v a l i d _ q < = e x m e m _ v a l i d _ q ;
m e m w b _ p c _ q < = e x m e m _ p c _ q ;
m e m w b _ i r _ q < = e x m e m _ i r _ q ;
@@ -983,7 +1034,7 @@ module cpu21_riscv_redirect_int_bpb #(
m e m w b _ m e m _ t o _ r e g _ q < = e x m e m _ m e m _ t o _ r e g _ q ;
m e m w b _ w b _ s e l _ q < = e x m e m _ w b _ s e l _ q ;
/ / E X / M E M
/ / E X / M E M 流 水 寄 存 器 捕 获 。
e x m e m _ v a l i d _ q < = i d e x _ v a l i d _ q ;
e x m e m _ p c _ q < = i d e x _ p c _ q ;
e x m e m _ i r _ q < = i d e x _ i r _ q ;
@@ -998,8 +1049,8 @@ module cpu21_riscv_redirect_int_bpb #(
e x m e m _ w s t r b _ q < = e x _ s t o r e _ w s t r b ;
e x m e m _ w b _ s e l _ q < = i d e x _ w b _ s e l _ q ;
/ / C o n t r o l p r i o r i t y : i n t e r r u p t , U R E T , e c a l l h a l t , b r a n c h r e d i r e c t ,
/ / t h e n l o a d - u s e s t a l l , t h e n o r d i n a r y p i p e l i n e a d v a n c e .
/ / 控 制 优 先 级 : 中 断 > U R E T > e c a l l 停 机 > 分 支 重 定 向 >
/ / l o a d - u s e 停 顿 > 正 常 流 水 推 进 。
i f ( f l u s h _ y o u n g e r | | p i p e l i n e _ s t a l l | | h a l t e d _ q ) b e g i n
i d e x _ v a l i d _ q < = 1 ' b0 ;
idex_pred_taken_q <= 1 ' b 0 ;
@@ -1076,6 +1127,8 @@ module cpu21_riscv_redirect_int_bpb #(
i f i d _ p r e d _ t a r g e t _ q < = b p b _ p r e d i c t _ t a r g e t ;
e n d
/ / 性 能 计 数 器 : 停 顿 / 气 泡 、 条 件 分 支 实 际 跳 转 数 、 无 条 件 跳 转 数 ,
/ / 以 及 分 支 预 测 的 成 功 / 失 败 次 数 。
i f ( p i p e l i n e _ s t a l l ) b e g i n
s t a l l _ c o u n t _ q < = s t a l l _ c o u n t _ q + 1 6 ' d1 ;
bubble_count_q <= bubble_count_q + 16 ' d 1 ;