├── README.md ├── lab1 ├── full-task │ ├── alu.v │ ├── conflict.v │ ├── cpu.v │ ├── extend.v │ ├── mux.v │ ├── regfile.v │ └── zero.v └── partial-task │ ├── alu.v │ ├── cpu.v │ ├── extend.v │ ├── mux.v │ ├── regfile.v │ └── zero.v ├── lab2 └── full-task │ ├── alu.v │ ├── conflict.v │ ├── cpu.v │ ├── extend.v │ ├── mux.v │ ├── predictor.v │ ├── regfile.v │ └── zero.v └── lab3 └── full-task └── cache.v /README.md: -------------------------------------------------------------------------------- 1 | ## 哈工大计算机体系结构实验(2024 年秋) 2 | 3 | 造 CPU,以及 Cache。 4 | 5 | 烈度显著强于前几周的处理器设计与实验,需要实现更进一步的优化比如流水线等,花了不少功夫。 6 | 7 | 挂在 Github 上留个纪念,供后人参考。只保留了源码,没有保留构建出来的程序以及测试环境。一般来说只要添加到 Vivado 项目的 Design Sources 下,就可以进行仿真测试了。因为是边学边写,所以加了很多注释,个人认为挺全的。如果有帮助的话,希望给个 Star) 8 | 9 | 目录(**每年实验课内容不完全一样**,注意查看): 10 | 11 | - 实验一:流水线处理器; 12 | - 实验二:分支预测; 13 | - 实验三:指令 Cache 的设计与实现。 14 | 15 | ## 施工进度 16 | 17 | - 实验一已完成,通过烧写测试,但是代码比较旧,谨慎使用; 18 | - 实验二已完成,通过烧写测试,不过分支预测的实现仍然可能有缺陷; 19 | - 实验三已完成,通过烧写测试。 20 | 21 | 因为已经通过验收,所以可能以后不太会主动修改这些代码了,如果还存在问题,可以提 issue,看情况修) 22 | 23 | ## 说明 24 | 25 | ### Lab 1 26 | 27 | 下有两个文件夹 partial-task 和 full-task,前者只完成了流水部分,但是没有加入暂停与定向;后者是完整实现。 28 | 29 | 说明:因为实验一的测试环境没有针对 BBT 和 J 指令的测试,同时这份代码的实现有缺陷,因此**对于分支跳转的实现有问题**。如果需要比较正确的实现可以看 Lab 2 的代码。 30 | 31 | ### Lab 2 32 | 33 | 下有文件夹 full-task,实现了分支预测功能。 34 | 35 | 代码里在从指令寄存器读取到指令的瞬间就会对 IR 进行基于组合逻辑的分析,并将预测结果立即写入到 PC 里,于是在下个时钟上边沿新的指令就能进入 IR 寄存器。代码实现的有点鬼畜,可能不是很标准的实现。 36 | 37 | 测试数据集 0: 38 | 39 | ```plain 40 | ------------------- 41 | HIT COA Lab2 42 | Branch Predictor 43 | ------------------- 44 | Run test case 0 45 | Your CPU is correct! It spent 415 cycles in total 46 | 47 | PASS! You have done well! 48 | ------------------- 49 | ``` 50 | 51 | 测试数据集 1: 52 | 53 | ```plain 54 | ------------------- 55 | HIT COA Lab2 56 | Branch Predictor 57 | ------------------- 58 | Run test case 1 59 | Your CPU is correct! It spent 716 cycles in total 60 | 61 | PASS! You have done well! 62 | ------------------- 63 | ``` 64 | 65 | 测试数据集 2: 66 | 67 | ```plain 68 | ------------------- 69 | HIT COA Lab2 70 | Branch Predictor 71 | ------------------- 72 | Run test case 2 73 | Your CPU is correct! It spent 987 cycles in total 74 | 75 | PASS! You have done well! 76 | ------------------- 77 | ``` 78 | 79 | 跑得还挺快。 80 | 81 | ### Lab 3 82 | 83 | 下有文件夹 full-task,实现的 Cache 具有如下参数: 84 | 85 | - 二路组相联,每路 128 行,每行 32 字节; 86 | - 二级流水; 87 | - 使用 LRU 替换策略。 88 | 89 | 测试数据集结果: 90 | 91 | ```plain 92 | ------------------- 93 | HIT COA Lab3 94 | Instruction Cache 95 | ------------------- 96 | Your cache is correct! In total 100011 requests: 97 | Total 439 misses (miss rate: 0.43%) 98 | Total 104842 cycles (1.04 cycles per request) 99 | 100 | PASS! You have done well! 101 | ------------------- 102 | ``` 103 | 104 | - 在一级流水(IF1 阶段)会将两路 RAM 对应的数据、tag 以及当前处理的 `cpu_addr` 存入寄存器文件; 105 | - 在二级流水(IF2 阶段)会根据是否发生 Cache Miss 来决定直接返回一级流水从 RAM 里得到的数据,还是向主存要一块数据。 106 | 107 | 使用组合逻辑实现了变量 stall,当发生了 Cache Miss,且二级流水还没从主存获取到期望的数据时设置为真,此时一级流水向二级流水泵来信息的过程会被暂停,同时 `cache_addr_ok` 也会被赋值为假,停止 CPU 向一级流水输送请求地址的过程。 108 | 109 | 当发生 Cache Miss,二级流水的内部状态会从 0 转变为 1,此时会向主存请求数据。一共要请求 8 个字,每次请求来一个字都会向 RAM 里写入。因此会延缓一个周期的时间用来完成 RAM 的写入,为了防止写地址和读地址相同产生错误,还要再延缓一个周期让一级流水有时间从 RAM 读取下一个信息。尽管减少这个周期的延迟,在仿真下也是能通过的(但是会报 Warning),但为了保险起见防止烧写不过,并且通过测试数据的限制比较宽松,所以还是延缓了这个周期。 110 | 111 | 整体而言这个实验还挺简单的。 -------------------------------------------------------------------------------- /lab1/full-task/alu.v: -------------------------------------------------------------------------------- 1 | `define ADD 6'b100000 // 加 2 | `define SUB 6'b100010 // 减 3 | `define AND 6'b100100 // 与 4 | `define OR 6'b100101 // 或 5 | `define XOR 6'b100110 // 异或 6 | `define MOVZ 6'b001010 // 条件移动 7 | `define SLL 6'b000000 // 移位 8 | `define CMP 6'b111110 // 比较 9 | 10 | module my_alu( 11 | input [31:0] A, // 输入 A 12 | input [31:0] B, // 输入 B 13 | input [5:0] Card, // 操作指令 14 | input [4:0] Shft, // 移位指令 15 | output [31:0] F // 输出 F 16 | ); 17 | 18 | wire [31:0] add_result = A + B; 19 | wire [31:0] sub_result = A - B; 20 | wire [31:0] and_result = A & B; 21 | wire [31:0] or_result = A | B; 22 | wire [31:0] xor_result = A ^ B; 23 | wire [31:0] movz_result = A; 24 | wire [31:0] sll_result = B << Shft; 25 | 26 | wire [31:0] cmp_result = { 27 | 22'b0, 28 | !(A <= B), 29 | !($signed(A) <= $signed(B)), 30 | !(A < B), 31 | !($signed(A) < $signed(B)), 32 | !(A == B), 33 | A <= B, 34 | $signed(A) <= $signed(B), 35 | A < B, 36 | $signed(A) < $signed(B), 37 | A == B 38 | }; 39 | // wire [31:0] cmp_result = { A[15:0], B[15:0] }; 40 | 41 | assign F = 42 | ({32{Card == `ADD}} & add_result) | 43 | ({32{Card == `SUB}} & sub_result) | 44 | ({32{Card == `AND}} & and_result) | 45 | ({32{Card == `OR}} & or_result) | 46 | ({32{Card == `XOR}} & xor_result) | 47 | ({32{Card == `MOVZ}} & movz_result) | 48 | ({32{Card == `SLL}} & sll_result) | 49 | ({32{Card == `CMP}} & cmp_result); 50 | endmodule 51 | -------------------------------------------------------------------------------- /lab1/full-task/conflict.v: -------------------------------------------------------------------------------- 1 | module conflict ( 2 | input[31:0] IR1, // 当前条指令,IF/ID 3 | input[31:0] IR2, // 上一条指令,ID/EX 4 | input[31:0] IR3, // 上二条指令,EX/MEM 5 | input[31:0] IR4, // 上三条指令,MEM/WB 6 | output stall, 7 | output sig1_ex_mem_rs, 8 | output sig1_mem_wb_rs, 9 | output sig1_mem_wb_mm, 10 | output sig2_ex_mem_rs, 11 | output sig2_mem_wb_rs, 12 | output sig2_mem_wb_mm 13 | ); 14 | // 暂停 15 | assign stall = 16 | (IR2[31:26] == 6'b100011 && (IR1[31:26] == 6'b000000 || IR1[31:26] == 6'b111110) && IR2[20:16] == IR1[25:21]) | 17 | (IR2[31:26] == 6'b100011 && (IR1[31:26] == 6'b000000 || IR1[31:26] == 6'b111110) && IR2[20:16] == IR1[20:16]) | 18 | (IR2[31:26] == 6'b100011 && IR2[20:16] == IR1[25:21]); 19 | 20 | // 从 EX/MEM.RS 定向替代 ID/EX.R1 21 | assign sig1_ex_mem_rs = (IR2[25:21] != 5'b00000) && 22 | (IR3[31:26] == 6'b000000 && IR2[25:21] == IR3[15:11]) | // 运算指令 23 | (IR3[31:26] == 6'b111110 && IR2[25:21] == IR3[15:11]); // 比较指令 24 | 25 | // 从 EX/MEM.RS 定向替代 ID/EX.R2 26 | assign sig2_ex_mem_rs = (IR2[20:16] != 5'b00000) && 27 | (IR3[31:26] == 6'b000000 && IR2[20:16] == IR3[15:11]) | // 运算指令 28 | (IR3[31:26] == 6'b111110 && IR2[20:16] == IR3[15:11]); // 比较指令 29 | 30 | // 从 EX/MEM.RS 定向替代 ID/EX.R1 31 | assign sig1_mem_wb_rs = (IR2[25:21] != 5'b00000) && 32 | (IR4[31:26] == 6'b000000 && IR2[25:21] == IR4[15:11]) | // 运算指令 33 | (IR4[31:26] == 6'b111110 && IR2[25:21] == IR4[15:11]); // 比较指令 34 | 35 | // 从 EX/MEM.RS 定向替代 ID/EX.R2 36 | assign sig2_mem_wb_rs = (IR2[20:16] != 5'b00000) && 37 | (IR4[31:26] == 6'b000000 && IR2[20:16] == IR4[15:11]) | // 运算指令 38 | (IR4[31:26] == 6'b111110 && IR2[20:16] == IR4[15:11]); // 比较指令 39 | 40 | // 从 EX/MEM.MM 定向替代 ID/EX.R1 41 | assign sig1_mem_wb_mm = (IR2[25:21] != 5'b00000) && 42 | (IR4[31:26] == 6'b100011 && IR2[25:21] == IR4[20:16]); // 取数指令 43 | 44 | // 从 EX/MEM.MM 定向替代 ID/EX.R2 45 | assign sig2_mem_wb_mm = (IR2[20:16] != 5'b00000) && 46 | (IR4[31:26] == 6'b100011 && IR2[20:16] == IR4[20:16]); // 取数指令 47 | endmodule -------------------------------------------------------------------------------- /lab1/full-task/cpu.v: -------------------------------------------------------------------------------- 1 | module cpu( 2 | input clk, // 时钟信号 3 | input resetn, // 低有效复位信号 4 | 5 | output inst_sram_en, // 指令存储器读使能 6 | output[31:0] inst_sram_addr, // 指令存储器读地址 7 | input[31:0] inst_sram_rdata, // 指令存储器读出的数据 8 | 9 | output data_sram_en, // 数据存储器端口读/写使能 10 | output[3:0] data_sram_wen, // 数据存储器写使能 11 | output[31:0] data_sram_addr, // 数据存储器读/写地址 12 | output[31:0] data_sram_wdata, // 写入数据存储器的数据 13 | input[31:0] data_sram_rdata, // 数据存储器读出的数据 14 | 15 | // 供自动测试环境进行CPU正确性检查 16 | output[31:0] debug_wb_pc, // 当前正在执行指令的PC 17 | output debug_wb_rf_wen, // 当前通用寄存器组的写使能信号 18 | output[4:0] debug_wb_rf_wnum, // 当前通用寄存器组写回的寄存器编号 19 | output[31:0] debug_wb_rf_wdata // 当前指令需要写回的数据 20 | ); 21 | 22 | // ========== 全局定义 ========== 23 | reg[31:0] PC; 24 | reg[31:0] IR; 25 | 26 | initial begin 27 | PC = 0; 28 | IR = 0; 29 | end 30 | // ============================== 31 | 32 | // ========== IF_ID ============= 33 | reg[31:0] IF_ID_PC; 34 | 35 | wire[31:0] IF_ID_IR; 36 | 37 | reg[31:0] debug_IF_ID_PC; // 测试用 38 | // ============================== 39 | 40 | // ========== ID_EX ============= 41 | reg[31:0] ID_EX_PC; 42 | reg[31:0] ID_EX_IR; 43 | reg[31:0] ID_EX_R1; 44 | reg[31:0] ID_EX_R2; 45 | reg[31:0] ID_EX_IM; 46 | 47 | reg[31:0] debug_ID_EX_PC; // 测试用 48 | // ============================== 49 | 50 | // ========== EX_MEM ============ 51 | reg[31:0] EX_MEM_RS; 52 | reg[31:0] EX_MEM_RG; 53 | reg[31:0] EX_MEM_IR; 54 | reg EX_MEM_JP; 55 | 56 | reg[31:0] debug_EX_MEM_PC; // 测试用 57 | // ============================== 58 | 59 | // ========== MEM_WB ============ 60 | reg[31:0] MEM_WB_RS; 61 | reg[31:0] MEM_WB_IR; 62 | wire[31:0] MEM_WB_MM; 63 | 64 | reg[31:0] debug_MEM_WB_PC; // 测试用 65 | // ============================== 66 | 67 | // ========== 解决冲突 =========== 68 | wire stall; 69 | wire sig1_ex_mem_rs; 70 | wire sig1_mem_wb_mm; 71 | wire sig1_mem_wb_rs; 72 | wire sig2_ex_mem_rs; 73 | wire sig2_mem_wb_mm; 74 | wire sig2_mem_wb_rs; 75 | 76 | // ============================== 77 | 78 | // ============ IF ============== 79 | assign inst_sram_en = !stall && resetn; 80 | assign inst_sram_addr = PC; 81 | 82 | wire[31:0] nPC; 83 | 84 | wire[31:0] mux0_result; 85 | 86 | my_mux IF_MUX( 87 | .d0 (PC + 4), 88 | .d1 (EX_MEM_RS), 89 | .select (EX_MEM_JP), 90 | .out (mux0_result) 91 | ); // EX_MEM.JP ? EX_MEM_RS : PC + 4 92 | 93 | assign nPC = mux0_result; 94 | 95 | assign IF_ID_IR = inst_sram_rdata; 96 | 97 | always @(posedge clk) begin 98 | if(!stall) begin 99 | PC <= {32{resetn}} & nPC; 100 | IF_ID_PC <= {32{resetn}} & nPC; 101 | 102 | debug_IF_ID_PC <= {32{resetn}} & PC; 103 | end 104 | end 105 | // ============================== 106 | 107 | // ============ ID ============== 108 | 109 | conflict conflict( // 组合逻辑检测是否有冲突信号 110 | .IR1( IF_ID_IR), 111 | .IR2( ID_EX_IR), 112 | .IR3(EX_MEM_IR), 113 | .IR4(MEM_WB_IR), 114 | .stall(stall), 115 | .sig1_ex_mem_rs(sig1_ex_mem_rs), 116 | .sig1_mem_wb_rs(sig1_mem_wb_rs), 117 | .sig1_mem_wb_mm(sig1_mem_wb_mm), 118 | .sig2_ex_mem_rs(sig2_ex_mem_rs), 119 | .sig2_mem_wb_rs(sig2_mem_wb_rs), 120 | .sig2_mem_wb_mm(sig2_mem_wb_mm) 121 | ); 122 | 123 | wire we; // 寄存器堆读使能(写回使能) 124 | wire[ 5:0] waddr; // 寄存器堆写地址 125 | wire[31:0] wdata; // 寄存器堆写数据 126 | 127 | wire[31:0] regfile_rdata1; 128 | wire[31:0] regfile_rdata2; 129 | 130 | my_regfile my_regfile( 131 | .clk (clk), 132 | .we (we), 133 | .raddr1(IF_ID_IR[25:21]), 134 | .raddr2(IF_ID_IR[20:16]), 135 | .waddr (waddr), 136 | .wdata (wdata), 137 | .rdata1(regfile_rdata1), 138 | .rdata2(regfile_rdata2) 139 | ); 140 | // 每个上升沿读入数据到 ID_EX.R1 和 ID_EX.R2 里 141 | 142 | wire[31:0] extend_imm; 143 | my_extend my_extend( 144 | .A (IF_ID_IR[15: 0]), // 低 16 位做符号扩展 145 | .B (extend_imm) 146 | ); 147 | 148 | always @(posedge clk) begin 149 | ID_EX_PC <= {32{resetn}} & IF_ID_PC; 150 | debug_ID_EX_PC <= {32{resetn}} & debug_IF_ID_PC; 151 | if (stall) begin 152 | ID_EX_IR <= 0; 153 | ID_EX_R1 <= 0; 154 | ID_EX_R2 <= 0; 155 | ID_EX_IM <= 0; 156 | end else begin 157 | ID_EX_R1 <= {32{resetn}} & regfile_rdata1; 158 | ID_EX_R2 <= {32{resetn}} & regfile_rdata2; 159 | ID_EX_IR <= {32{resetn}} & IF_ID_IR; 160 | ID_EX_IM <= {32{resetn}} & extend_imm; 161 | end 162 | end 163 | // ============================== 164 | 165 | // ============ EX ============== 166 | wire[31:0] alu_a, reg_a; 167 | wire[31:0] alu_b, reg_b; 168 | 169 | assign reg_a = // 检查是从 ID_EX.R1 里获取,还是定向获取 170 | sig1_ex_mem_rs ? EX_MEM_RS : 171 | sig1_mem_wb_rs ? MEM_WB_RS : 172 | sig1_mem_wb_mm ? MEM_WB_MM : 173 | ID_EX_R1; 174 | 175 | assign reg_b = // 检查是从 ID_EX.R2 里获取,还是定向获取 176 | sig2_ex_mem_rs ? EX_MEM_RS : 177 | sig2_mem_wb_rs ? MEM_WB_RS : 178 | sig2_mem_wb_mm ? MEM_WB_MM : 179 | ID_EX_R2; 180 | 181 | wire mux1_select, mux2_select; 182 | 183 | my_mux EX_MUX1( 184 | .d0(ID_EX_PC), 185 | .d1(reg_a), 186 | .select(mux1_select), 187 | .out(alu_a) 188 | ); // 从 PC 和 R1 里选一个 189 | assign mux1_select = 190 | (ID_EX_IR[31:26] == 6'b000000) | // 运算指令需要 R1 191 | (ID_EX_IR[31:26] == 6'b101011) | // 存数指令需要 R1 192 | (ID_EX_IR[31:26] == 6'b100011) | // 取数指令需要 R1 193 | (ID_EX_IR[31:26] == 6'b111110) | // 比较指令需要 R1 194 | (ID_EX_IR[31:26] == 6'b111111); // 条件指令需要 R1 195 | 196 | my_mux EX_MUX2( 197 | .d0(ID_EX_IM), 198 | .d1(reg_b), 199 | .select(mux2_select), 200 | .out(alu_b) 201 | ); // 从 R2 和 IM 里选一个 202 | assign mux2_select = 203 | (ID_EX_IR[31:26] == 6'b000000) | // 运算指令需要 R2 204 | (ID_EX_IR[31:26] == 6'b111110); // 比较指令需要 R2 205 | 206 | wire[31:0] alu_result; 207 | wire[ 5:0] alu_card = 208 | ({6{ID_EX_IR[31:26] == 6'b000000}} & ID_EX_IR[5:0]) | // 运算操作运算码为后五位 209 | ({6{ID_EX_IR[31:26] == 6'b111110}} & 6'b111110) | // 比较指令特殊指定操作码 210 | ({6{ID_EX_IR[31:26] == 6'b101011}} & 6'b100000) | // 存数指令做加法 211 | ({6{ID_EX_IR[31:26] == 6'b100011}} & 6'b100000); // 取数指令做加法 212 | my_alu EX_ALU( // 选出来的结果做运算 213 | .A(alu_a), 214 | .B(alu_b), 215 | .F(alu_result), 216 | .Shft(ID_EX_IR[10: 6]), 217 | .Card(alu_card) 218 | ); 219 | 220 | wire test_result; 221 | my_zero my_zero( // 位测试 222 | .R1(reg_a), 223 | .R2(reg_b), 224 | .IR(ID_EX_IR), 225 | .J(test_result) 226 | ); 227 | 228 | always @(posedge clk) begin 229 | EX_MEM_RG <= {32{resetn}} & reg_b; 230 | EX_MEM_IR <= {32{resetn}} & ( 231 | {32{!(ID_EX_IR[31:26] == 6'b000000 && ID_EX_IR[5:0] == 6'b001010 && reg_b != 0)}} 232 | ) & ID_EX_IR; 233 | // 如果是 MOVZ 指令并且 R2 为 0 就不继续执行 234 | EX_MEM_RS <= {32{resetn}} & ( 235 | ({32{ID_EX_IR[31:26] == 6'b000000}} & alu_result) | // 运算指令使用 ALU 236 | ({32{ID_EX_IR[31:26] == 6'b100011}} & alu_result) | // 取数指令使用 ALU 237 | ({32{ID_EX_IR[31:26] == 6'b101011}} & alu_result) | // 存数指令使用 ALU 238 | ({32{ID_EX_IR[31:26] == 6'b111110}} & alu_result) | // 比较指令使用 ALU 239 | ({32{ID_EX_IR[31:26] == 6'b000010}} & { ID_EX_PC[31:28], ID_EX_IR[25:0], 2'b00 }) // 无条件跳转指令 240 | ); 241 | EX_MEM_JP <= resetn & test_result; 242 | debug_EX_MEM_PC <= {32{resetn}} & debug_ID_EX_PC; 243 | end 244 | // ============================== 245 | 246 | // =========== MEM ============== 247 | assign data_sram_addr = EX_MEM_RS; // 写地址为运算结果 248 | assign data_sram_wdata = EX_MEM_RG; // 写数据为寄存器值 249 | assign data_sram_wen = EX_MEM_IR[31:26] == 6'b101011; // 只有存数指令写存 250 | assign data_sram_en = 251 | (EX_MEM_IR[31:26] == 6'b100011) | // 取数指令访存 252 | (EX_MEM_IR[31:26] == 6'b101011); // 存数指令访存 253 | 254 | assign MEM_WB_MM = {32{resetn}} & data_sram_rdata; 255 | // 在下个上升沿才能从 SRAM 里面读出数据 256 | 257 | always @(posedge clk) begin 258 | MEM_WB_IR <= {32{resetn}} & EX_MEM_IR; 259 | MEM_WB_RS <= {32{resetn}} & EX_MEM_RS; 260 | 261 | debug_MEM_WB_PC <= {32{resetn}} & debug_EX_MEM_PC; 262 | end 263 | // ============================== 264 | 265 | // ============ WB ============== 266 | wire mux3_select; 267 | 268 | my_mux WB_MUX( 269 | .d0(MEM_WB_RS), // 读结果 270 | .d1(MEM_WB_MM), // 读内存 271 | .select(mux3_select), 272 | .out(wdata) 273 | ); 274 | assign waddr = 275 | ({32{MEM_WB_IR[31:26] == 6'b100011}} & MEM_WB_IR[20:16]) | // 取数指令写回 IR[20:16] 276 | ({32{MEM_WB_IR[31:26] == 6'b000000}} & MEM_WB_IR[15:11]) | // 运算指令写回 IR[15:11] 277 | ({32{MEM_WB_IR[31:26] == 6'b111110}} & MEM_WB_IR[15:11]); // 比较指令写回 IR[15:11] 278 | assign mux3_select = 279 | (MEM_WB_IR[31:26] == 6'b100011); // 只有取数指令写回访存结果 280 | assign we = 281 | ((MEM_WB_IR[31:26] == 6'b000000) | // 运算指令要写回 282 | (MEM_WB_IR[31:26] == 6'b100011) | // 取数指令要写回 283 | (MEM_WB_IR[31:26] == 6'b111110) ) & // 比较指令要写回 284 | (waddr != 0); // 不能写入 r0 寄存器 285 | // ============================== 286 | 287 | assign debug_wb_pc = debug_MEM_WB_PC; // 写回的 PC 值 288 | assign debug_wb_rf_wen = we; // 写回使能 289 | assign debug_wb_rf_wnum = waddr; // 写回地址 290 | assign debug_wb_rf_wdata = wdata; // 写回数据 291 | 292 | endmodule -------------------------------------------------------------------------------- /lab1/full-task/extend.v: -------------------------------------------------------------------------------- 1 | module my_extend ( 2 | input [15:0] A, 3 | output [31:0] B 4 | ); 5 | assign B = {{16{A[15]}}, A[15:0] }; 6 | endmodule -------------------------------------------------------------------------------- /lab1/full-task/mux.v: -------------------------------------------------------------------------------- 1 | module my_mux( 2 | input[31:0] d0, 3 | input[31:0] d1, 4 | input select, 5 | output[31:0] out 6 | ); 7 | assign out = select ? d1 : d0; 8 | endmodule -------------------------------------------------------------------------------- /lab1/full-task/regfile.v: -------------------------------------------------------------------------------- 1 | module my_regfile ( 2 | input clk, 3 | input we, 4 | input [4:0] raddr1, 5 | input [4:0] raddr2, 6 | input [4:0] waddr , 7 | output [31:0] rdata1, 8 | output [31:0] rdata2, 9 | input [31:0] wdata 10 | ); 11 | reg [31:0] data[0:31]; 12 | 13 | integer i; 14 | 15 | initial begin 16 | for(i = 0;i < 32;i = i + 1) begin 17 | data[i] <= 0; 18 | end 19 | end 20 | 21 | always @(posedge clk) begin 22 | if(we) begin 23 | data[waddr] <= wdata; 24 | end 25 | end 26 | assign rdata1 = waddr == raddr1 ? wdata : data[raddr1]; 27 | assign rdata2 = waddr == raddr2 ? wdata : data[raddr2]; 28 | endmodule -------------------------------------------------------------------------------- /lab1/full-task/zero.v: -------------------------------------------------------------------------------- 1 | module my_zero ( 2 | input[31:0] R1, 3 | input[31:0] R2, 4 | input[31:0] IR, 5 | output J 6 | ); 7 | assign J = (IR[31:26] == 6'b111111 && R1[R2]) | (IR[31:26] == 6'b000010); 8 | // 位测试或者无条件 9 | endmodule -------------------------------------------------------------------------------- /lab1/partial-task/alu.v: -------------------------------------------------------------------------------- 1 | `define ADD 6'b100000 // 加 2 | `define SUB 6'b100010 // 减 3 | `define AND 6'b100100 // 与 4 | `define OR 6'b100101 // 或 5 | `define XOR 6'b100110 // 异或 6 | `define MOVZ 6'b001010 // 条件移动 7 | `define SLL 6'b000000 // 移位 8 | `define CMP 6'b111110 // 比较 9 | 10 | module my_alu( 11 | input [31:0] A, // 输入 A 12 | input [31:0] B, // 输入 B 13 | input [5:0] Card, // 操作指令 14 | input [4:0] Shft, // 移位指令 15 | output [31:0] F // 输出 F 16 | ); 17 | 18 | wire [31:0] add_result = A + B; 19 | wire [31:0] sub_result = A - B; 20 | wire [31:0] and_result = A & B; 21 | wire [31:0] or_result = A | B; 22 | wire [31:0] xor_result = A ^ B; 23 | wire [31:0] movz_result = A; 24 | wire [31:0] sll_result = B << Shft; 25 | 26 | wire [31:0] cmp_result = { 27 | 22'b0, 28 | !(A <= B), 29 | !($signed(A) <= $signed(B)), 30 | !(A < B), 31 | !($signed(A) < $signed(B)), 32 | !(A == B), 33 | A <= B, 34 | $signed(A) <= $signed(B), 35 | A < B, 36 | $signed(A) < $signed(B), 37 | A == B 38 | }; 39 | // wire [31:0] cmp_result = { A[15:0], B[15:0] }; 40 | 41 | assign F = 42 | ({32{Card == `ADD}} & add_result) | 43 | ({32{Card == `SUB}} & sub_result) | 44 | ({32{Card == `AND}} & and_result) | 45 | ({32{Card == `OR}} & or_result) | 46 | ({32{Card == `XOR}} & xor_result) | 47 | ({32{Card == `MOVZ}} & movz_result) | 48 | ({32{Card == `SLL}} & sll_result) | 49 | ({32{Card == `CMP}} & cmp_result); 50 | endmodule 51 | -------------------------------------------------------------------------------- /lab1/partial-task/cpu.v: -------------------------------------------------------------------------------- 1 | module cpu( 2 | input clk, // 时钟信号 3 | input resetn, // 低有效复位信号 4 | 5 | output inst_sram_en, // 指令存储器读使能 6 | output[31:0] inst_sram_addr, // 指令存储器读地址 7 | input[31:0] inst_sram_rdata, // 指令存储器读出的数据 8 | 9 | output data_sram_en, // 数据存储器端口读/写使能 10 | output[3:0] data_sram_wen, // 数据存储器写使能 11 | output[31:0] data_sram_addr, // 数据存储器读/写地址 12 | output[31:0] data_sram_wdata, // 写入数据存储器的数据 13 | input[31:0] data_sram_rdata, // 数据存储器读出的数据 14 | 15 | // 供自动测试环境进行CPU正确性检查 16 | output[31:0] debug_wb_pc, // 当前正在执行指令的PC 17 | output debug_wb_rf_wen, // 当前通用寄存器组的写使能信号 18 | output[4:0] debug_wb_rf_wnum, // 当前通用寄存器组写回的寄存器编号 19 | output[31:0] debug_wb_rf_wdata // 当前指令需要写回的数据 20 | ); 21 | 22 | // ========== 全局定义 ========== 23 | reg[31:0] PC; 24 | 25 | initial begin 26 | PC = 0; 27 | end 28 | // ============================== 29 | 30 | // ========== IF_ID ============= 31 | reg[31:0] IF_ID_PC; 32 | 33 | wire[31:0] IF_ID_IR; 34 | 35 | reg[31:0] debug_IF_ID_PC; // 测试用 36 | // ============================== 37 | 38 | // ========== ID_EX ============= 39 | reg[31:0] ID_EX_PC; 40 | reg[31:0] ID_EX_IR; 41 | reg[31:0] ID_EX_R1; 42 | reg[31:0] ID_EX_R2; 43 | reg[31:0] ID_EX_IM; 44 | 45 | reg[31:0] debug_ID_EX_PC; // 测试用 46 | // ============================== 47 | 48 | // ========== EX_MEM ============ 49 | reg[31:0] EX_MEM_RS; 50 | reg[31:0] EX_MEM_RG; 51 | reg[31:0] EX_MEM_IR; 52 | reg EX_MEM_JP; 53 | 54 | reg[31:0] debug_EX_MEM_PC; // 测试用 55 | // ============================== 56 | 57 | // ========== MEM_WB ============ 58 | reg[31:0] MEM_WB_RS; 59 | reg[31:0] MEM_WB_IR; 60 | wire[31:0] MEM_WB_MM; 61 | 62 | reg[31:0] debug_MEM_WB_PC; // 测试用 63 | // ============================== 64 | 65 | // ============ IF ============== 66 | assign inst_sram_en = resetn; 67 | assign inst_sram_addr = PC; 68 | 69 | wire[31:0] nPC; 70 | 71 | my_mux IF_MUX( 72 | .d0 (PC + 4), 73 | .d1 (EX_MEM_RS), 74 | .select (EX_MEM_JP), 75 | .out (nPC) 76 | ); // EX_MEM.JP ? EX_MEM_RS : PC + 4 77 | 78 | assign IF_ID_IR = {32{resetn}} & inst_sram_rdata; 79 | 80 | always @(posedge clk) begin 81 | PC <= {32{resetn}} & nPC; 82 | IF_ID_PC <= {32{resetn}} & nPC; 83 | 84 | debug_IF_ID_PC <= {32{resetn}} & PC; 85 | end 86 | // ============================== 87 | 88 | // ============ ID ============== 89 | wire we; // 寄存器堆读使能(写回使能) 90 | wire[ 5:0] waddr; // 寄存器堆写地址 91 | wire[31:0] wdata; // 寄存器堆写数据 92 | 93 | wire[31:0] regfile_rdata1; 94 | wire[31:0] regfile_rdata2; 95 | 96 | my_regfile my_regfile( 97 | .clk (clk), 98 | .we (we), 99 | .raddr1(IF_ID_IR[25:21]), 100 | .raddr2(IF_ID_IR[20:16]), 101 | .waddr (waddr), 102 | .wdata (wdata), 103 | .rdata1(regfile_rdata1), 104 | .rdata2(regfile_rdata2) 105 | ); 106 | // 每个上升沿读入数据到 ID_EX.R1 和 ID_EX.R2 里 107 | 108 | wire[31:0] extend_imm; 109 | my_extend my_extend( 110 | .A (IF_ID_IR[15: 0]), // 低 16 位做符号扩展 111 | .B (extend_imm) 112 | ); 113 | 114 | always @(posedge clk) begin 115 | ID_EX_R1 <= {32{resetn}} & regfile_rdata1; 116 | ID_EX_R2 <= {32{resetn}} & regfile_rdata2; 117 | ID_EX_IR <= {32{resetn}} & IF_ID_IR; 118 | ID_EX_PC <= {32{resetn}} & IF_ID_PC; 119 | ID_EX_IM <= {32{resetn}} & extend_imm; 120 | 121 | debug_ID_EX_PC <= {32{resetn}} & debug_IF_ID_PC; 122 | end 123 | // ============================== 124 | 125 | // ============ EX ============== 126 | wire[31:0] alu_a; 127 | wire[31:0] alu_b; 128 | 129 | wire mux1_select, mux2_select; 130 | 131 | my_mux EX_MUX1( 132 | .d0(ID_EX_PC), 133 | .d1(ID_EX_R1), 134 | .select(mux1_select), 135 | .out(alu_a) 136 | ); // 从 PC 和 R1 里选一个 137 | assign mux1_select = 138 | (ID_EX_IR[31:26] == 6'b000000) | // 运算指令需要 R1 139 | (ID_EX_IR[31:26] == 6'b101011) | // 存数指令需要 R1 140 | (ID_EX_IR[31:26] == 6'b100011) | // 取数指令需要 R1 141 | (ID_EX_IR[31:26] == 6'b111110) | // 比较指令需要 R1 142 | (ID_EX_IR[31:26] == 6'b111111); // 条件指令需要 R1 143 | 144 | my_mux EX_MUX2( 145 | .d0(ID_EX_R2), 146 | .d1(ID_EX_IM), 147 | .select(mux2_select), 148 | .out(alu_b) 149 | ); // 从 R2 和 IM 里选一个 150 | assign mux2_select = 151 | (ID_EX_IR[31:26] == 6'b101011) | // 存数指令需要 IM 152 | (ID_EX_IR[31:26] == 6'b100011) | // 取数指令需要 IM 153 | (ID_EX_IR[31:26] == 6'b111111); // 条件测试指令需要 IM 154 | 155 | wire[31:0] alu_result; 156 | wire[ 5:0] alu_card = 157 | ({6{ID_EX_IR[31:26] == 6'b000000}} & ID_EX_IR[5:0]) | // 运算操作运算码为后五位 158 | ({6{ID_EX_IR[31:26] == 6'b111110}} & 6'b111110) | // 比较指令特殊指定操作码 159 | ({6{ID_EX_IR[31:26] == 6'b101011}} & 6'b100000) | // 存数指令做加法 160 | ({6{ID_EX_IR[31:26] == 6'b100011}} & 6'b100000); // 取数指令做加法 161 | my_alu EX_ALU( // 选出来的结果做运算 162 | .A(alu_a), 163 | .B(alu_b), 164 | .F(alu_result), 165 | .Shft(ID_EX_IR[10: 6]), 166 | .Card(alu_card) 167 | ); 168 | 169 | wire test_result; 170 | my_zero my_zero( // 位测试 171 | .R1(ID_EX_R1), 172 | .R2(ID_EX_R2), 173 | .IR(ID_EX_IR), 174 | .J(test_result) 175 | ); 176 | 177 | always @(posedge clk) begin 178 | EX_MEM_RG <= {32{resetn}} & ID_EX_R2; 179 | EX_MEM_IR <= {32{resetn}} & ( 180 | {32{!(ID_EX_IR[31:26] == 6'b000000 && ID_EX_IR[5:0] == 6'b001010 && ID_EX_R2 != 0)}} 181 | ) & ID_EX_IR; 182 | // 如果是 MOVZ 指令并且 R2 为 0 就不继续执行 183 | EX_MEM_RS <= {32{resetn}} & ( 184 | ({32{ID_EX_IR[31:26] == 6'b000000}} & alu_result) | // 运算指令使用 ALU 185 | ({32{ID_EX_IR[31:26] == 6'b100011}} & alu_result) | // 取数指令使用 ALU 186 | ({32{ID_EX_IR[31:26] == 6'b101011}} & alu_result) | // 存数指令使用 ALU 187 | ({32{ID_EX_IR[31:26] == 6'b111110}} & alu_result) | // 比较指令使用 ALU 188 | ({32{ID_EX_IR[31:26] == 6'b000010}} & { ID_EX_PC[31:28], ID_EX_IR[25:0], 2'b00 }) // 无条件跳转指令 189 | ); 190 | EX_MEM_JP <= resetn & test_result; 191 | debug_EX_MEM_PC <= {32{resetn}} & debug_ID_EX_PC; 192 | end 193 | // ============================== 194 | 195 | // =========== MEM ============== 196 | assign data_sram_addr = EX_MEM_RS; // 写地址为运算结果 197 | assign data_sram_wdata = EX_MEM_RG; // 写数据为寄存器值 198 | assign data_sram_wen = EX_MEM_IR[31:26] == 6'b101011; // 只有存数指令写存 199 | assign data_sram_en = 200 | (EX_MEM_IR[31:26] == 6'b100011) | // 取数指令访存 201 | (EX_MEM_IR[31:26] == 6'b101011); // 存数指令访存 202 | 203 | assign MEM_WB_MM = {32{resetn}} & data_sram_rdata; 204 | // 在下个上升沿才能从 SRAM 里面读出数据 205 | 206 | always @(posedge clk) begin 207 | MEM_WB_IR <= {32{resetn}} & EX_MEM_IR; 208 | MEM_WB_RS <= {32{resetn}} & EX_MEM_RS; 209 | 210 | debug_MEM_WB_PC <= {32{resetn}} & debug_EX_MEM_PC; 211 | end 212 | // ============================== 213 | 214 | // ============ WB ============== 215 | wire mux3_select; 216 | 217 | my_mux WB_MUX( 218 | .d0(MEM_WB_RS), // 读结果 219 | .d1(MEM_WB_MM), // 读内存 220 | .select(mux3_select), 221 | .out(wdata) 222 | ); 223 | assign waddr = 224 | ({32{MEM_WB_IR[31:26] == 6'b100011}} & MEM_WB_IR[20:16]) | // 取数指令写回 IR[20:16] 225 | ({32{MEM_WB_IR[31:26] == 6'b000000}} & MEM_WB_IR[15:11]) | // 运算指令写回 IR[15:11] 226 | ({32{MEM_WB_IR[31:26] == 6'b111110}} & MEM_WB_IR[15:11]); // 比较指令写回 IR[15:11] 227 | assign mux3_select = 228 | (MEM_WB_IR[31:26] == 6'b100011); // 只有取数指令写回访存结果 229 | assign we = 230 | ((MEM_WB_IR[31:26] == 6'b000000) | // 运算指令要写回 231 | (MEM_WB_IR[31:26] == 6'b100011) | // 取数指令要写回 232 | (MEM_WB_IR[31:26] == 6'b111110) ) & // 比较指令要写回 233 | (waddr != 0); // 不能写入 r0 寄存器 234 | // ============================== 235 | 236 | assign debug_wb_pc = debug_MEM_WB_PC; // 写回的 PC 值 237 | assign debug_wb_rf_wen = we; // 写回使能 238 | assign debug_wb_rf_wnum = waddr; // 写回地址 239 | assign debug_wb_rf_wdata = wdata; // 写回数据 240 | 241 | endmodule -------------------------------------------------------------------------------- /lab1/partial-task/extend.v: -------------------------------------------------------------------------------- 1 | module my_extend ( 2 | input [15:0] A, 3 | output [31:0] B 4 | ); 5 | assign B = {{16{A[15]}}, A[15:0] }; 6 | endmodule -------------------------------------------------------------------------------- /lab1/partial-task/mux.v: -------------------------------------------------------------------------------- 1 | module my_mux( 2 | input[31:0] d0, 3 | input[31:0] d1, 4 | input select, 5 | output[31:0] out 6 | ); 7 | assign out = select ? d1 : d0; 8 | endmodule -------------------------------------------------------------------------------- /lab1/partial-task/regfile.v: -------------------------------------------------------------------------------- 1 | module my_regfile ( 2 | input clk, 3 | input we, 4 | input [4:0] raddr1, 5 | input [4:0] raddr2, 6 | input [4:0] waddr , 7 | output [31:0] rdata1, 8 | output [31:0] rdata2, 9 | input [31:0] wdata 10 | ); 11 | reg [31:0] data[0:31]; 12 | 13 | integer i; 14 | 15 | initial begin 16 | for(i = 0;i < 32;i = i + 1) begin 17 | data[i] <= 0; 18 | end 19 | end 20 | 21 | always @(posedge clk) begin 22 | if(we) begin 23 | data[waddr] <= wdata; 24 | end 25 | end 26 | assign rdata1 = waddr == raddr1 ? wdata : data[raddr1]; 27 | assign rdata2 = waddr == raddr2 ? wdata : data[raddr2]; 28 | endmodule -------------------------------------------------------------------------------- /lab1/partial-task/zero.v: -------------------------------------------------------------------------------- 1 | module my_zero ( 2 | input[31:0] R1, 3 | input[31:0] R2, 4 | input[31:0] IR, 5 | output J 6 | ); 7 | assign J = (IR[31:26] == 6'b111111 && R1[R2]) | (IR[31:26] == 6'b000010); 8 | // 位测试或者无条件 9 | endmodule -------------------------------------------------------------------------------- /lab2/full-task/alu.v: -------------------------------------------------------------------------------- 1 | `define ADD 6'b100000 // 加 2 | `define SUB 6'b100010 // 减 3 | `define AND 6'b100100 // 与 4 | `define OR 6'b100101 // 或 5 | `define XOR 6'b100110 // 异或 6 | `define MOVZ 6'b001010 // 条件移动 7 | `define SLL 6'b000000 // 移位 8 | `define CMP 6'b111110 // 比较 9 | 10 | module my_alu( 11 | input [31:0] A, // 输入 A 12 | input [31:0] B, // 输入 B 13 | input [5:0] Card, // 操作指令 14 | input [4:0] Shft, // 移位指令 15 | output [31:0] F // 输出 F 16 | ); 17 | 18 | wire [31:0] add_result = A + B; 19 | wire [31:0] sub_result = A - B; 20 | wire [31:0] and_result = A & B; 21 | wire [31:0] or_result = A | B; 22 | wire [31:0] xor_result = A ^ B; 23 | wire [31:0] movz_result = A; 24 | wire [31:0] sll_result = B << Shft; 25 | 26 | wire [31:0] cmp_result = { 27 | 22'b0, 28 | !(A <= B), 29 | !($signed(A) <= $signed(B)), 30 | !(A < B), 31 | !($signed(A) < $signed(B)), 32 | !(A == B), 33 | A <= B, 34 | $signed(A) <= $signed(B), 35 | A < B, 36 | $signed(A) < $signed(B), 37 | A == B 38 | }; 39 | // wire [31:0] cmp_result = { A[15:0], B[15:0] }; 40 | 41 | assign F = 42 | ({32{Card == `ADD}} & add_result) | 43 | ({32{Card == `SUB}} & sub_result) | 44 | ({32{Card == `AND}} & and_result) | 45 | ({32{Card == `OR}} & or_result) | 46 | ({32{Card == `XOR}} & xor_result) | 47 | ({32{Card == `MOVZ}} & movz_result) | 48 | ({32{Card == `SLL}} & sll_result) | 49 | ({32{Card == `CMP}} & cmp_result); 50 | endmodule 51 | -------------------------------------------------------------------------------- /lab2/full-task/conflict.v: -------------------------------------------------------------------------------- 1 | module conflict ( 2 | input[31:0] IR1, // 目前的指令,IF/ID 3 | input[31:0] IR2, // 上一条指令,ID/EX 4 | input[31:0] IR3, // 上二条指令,EX/MEM 5 | input[31:0] IR4, // 上三条指令,MEM/WB 6 | output stall, 7 | output sig1_ex_mem_rs, 8 | output sig1_mem_wb_rs, 9 | output sig1_mem_wb_mm, 10 | output sig2_ex_mem_rs, 11 | output sig2_mem_wb_rs, 12 | output sig2_mem_wb_mm 13 | ); 14 | wire ir1_need_r1 = ( 15 | IR1[31:26] == 6'b000000 || // 运算指令取 R1 16 | IR1[31:26] == 6'b111110 || // 比较指令取 R1 17 | IR1[31:26] == 6'b111111 || // 位测试需要 R1 18 | IR1[31:26] == 6'b101011 || // 存数指令取 R1 19 | IR1[31:26] == 6'b100011 // 取数指令取 R1 20 | ) && IR1[25:21] != 5'b00000; 21 | 22 | wire ir1_need_r2 = ( 23 | IR1[31:26] == 6'b000000 || // 运算指令取 R2 24 | IR1[31:26] == 6'b111110 || // 比较指令取 R2 25 | IR1[31:26] == 6'b101011 // 存数指令取 R2 26 | ) && IR1[20:16] != 5'b00000; 27 | 28 | wire ir2_need_r1 = ( 29 | IR2[31:26] == 6'b000000 || // 运算指令取 R1 30 | IR2[31:26] == 6'b111110 || // 比较指令取 R1 31 | IR2[31:26] == 6'b111111 || // 位测试需要 R1 32 | IR2[31:26] == 6'b101011 || // 存数指令取 R1 33 | IR2[31:26] == 6'b100011 // 取数指令取 R1 34 | ) && IR2[25:21] != 5'b00000; 35 | 36 | wire ir2_need_r2 = ( 37 | IR2[31:26] == 6'b000000 || // 运算指令取 R2 38 | IR2[31:26] == 6'b111110 || // 比较指令取 R2 39 | IR2[31:26] == 6'b101011 // 存数指令取 R2 40 | ) && IR2[20:16] != 5'b00000; 41 | 42 | // 暂停 43 | assign stall = ( 44 | (IR2[31:26] == 6'b100011 && ir1_need_r1 && IR2[20:16] == IR1[25:21]) | 45 | (IR2[31:26] == 6'b100011 && ir1_need_r2 && IR2[20:16] == IR1[20:16])); 46 | // 当前指令(IR1)需要取数指令 IR2 获取 47 | 48 | // 从 EX/MEM.RS 定向替代 ID/EX.R1 49 | assign sig1_ex_mem_rs = ir2_need_r1 && ( 50 | (IR3[31:26] == 6'b000000 && IR2[25:21] == IR3[15:11]) | // 运算指令 51 | (IR3[31:26] == 6'b111110 && IR2[25:21] == IR3[15:11])); // 比较指令 52 | 53 | // 从 EX/MEM.RS 定向替代 ID/EX.R2 54 | assign sig2_ex_mem_rs = ir2_need_r2 && ( 55 | (IR3[31:26] == 6'b000000 && IR2[20:16] == IR3[15:11]) | // 运算指令 56 | (IR3[31:26] == 6'b111110 && IR2[20:16] == IR3[15:11])); // 比较指令 57 | 58 | // 从 EX/MEM.RS 定向替代 ID/EX.R1 59 | assign sig1_mem_wb_rs = ir2_need_r1 && ( 60 | (IR4[31:26] == 6'b000000 && IR2[25:21] == IR4[15:11]) | // 运算指令 61 | (IR4[31:26] == 6'b111110 && IR2[25:21] == IR4[15:11])); // 比较指令 62 | 63 | // 从 EX/MEM.RS 定向替代 ID/EX.R2 64 | assign sig2_mem_wb_rs = ir2_need_r2 && ( 65 | (IR4[31:26] == 6'b000000 && IR2[20:16] == IR4[15:11]) | // 运算指令 66 | (IR4[31:26] == 6'b111110 && IR2[20:16] == IR4[15:11])); // 比较指令 67 | 68 | // 从 EX/MEM.MM 定向替代 ID/EX.R1 69 | assign sig1_mem_wb_mm = ir2_need_r1 && ( 70 | (IR4[31:26] == 6'b100011 && IR2[25:21] == IR4[20:16])); // 取数指令 71 | 72 | // 从 EX/MEM.MM 定向替代 ID/EX.R2 73 | assign sig2_mem_wb_mm = ir2_need_r2 && ( 74 | (IR4[31:26] == 6'b100011 && IR2[20:16] == IR4[20:16])); // 取数指令 75 | endmodule -------------------------------------------------------------------------------- /lab2/full-task/cpu.v: -------------------------------------------------------------------------------- 1 | module cpu( 2 | input clk, // 时钟信号 3 | input resetn, // 低有效复位信号 4 | 5 | output inst_sram_en, // 指令存储器读使能 6 | output[31:0] inst_sram_addr, // 指令存储器读地址 7 | input[31:0] inst_sram_rdata, // 指令存储器读出的数据 8 | 9 | output data_sram_en, // 数据存储器端口读/写使能 10 | output[3:0] data_sram_wen, // 数据存储器写使能 11 | output[31:0] data_sram_addr, // 数据存储器读/写地址 12 | output[31:0] data_sram_wdata, // 写入数据存储器的数据 13 | input[31:0] data_sram_rdata, // 数据存储器读出的数据 14 | 15 | // 供自动测试环境进行CPU正确性检查 16 | output[31:0] debug_wb_pc, // 当前正在执行指令的PC 17 | output debug_wb_rf_wen, // 当前通用寄存器组的写使能信号 18 | output[4:0] debug_wb_rf_wnum, // 当前通用寄存器组写回的寄存器编号 19 | output[31:0] debug_wb_rf_wdata // 当前指令需要写回的数据 20 | ); 21 | 22 | // ========== IF_ID ============= 23 | reg[31:0] IF_ID_PC; 24 | 25 | wire[31:0] IF_ID_IR; 26 | wire[31:0] IF_ID_NP; 27 | wire[31:0] IF_ID_JP; 28 | // ============================== 29 | 30 | // ========== ID_EX ============= 31 | reg[31:0] ID_EX_NP; 32 | reg[31:0] ID_EX_IR; 33 | reg[31:0] ID_EX_R1; 34 | reg[31:0] ID_EX_R2; 35 | reg[31:0] ID_EX_IM; 36 | reg[31:0] ID_EX_JP; 37 | reg[31:0] ID_EX_PC; 38 | // ============================== 39 | 40 | // ========== EX_MEM ============ 41 | reg[31:0] EX_MEM_RS; 42 | reg[31:0] EX_MEM_RG; 43 | reg[31:0] EX_MEM_IR; 44 | reg[31:0] EX_MEM_PC; 45 | // ============================== 46 | 47 | // ========== MEM_WB ============ 48 | reg[31:0] MEM_WB_RS; 49 | reg[31:0] MEM_WB_IR; 50 | wire[31:0] MEM_WB_MM; 51 | reg[31:0] MEM_WB_PC; 52 | // ============================== 53 | 54 | // ========== 解决冲突 =========== 55 | wire stall; 56 | wire sig1_ex_mem_rs; 57 | wire sig1_mem_wb_mm; 58 | wire sig1_mem_wb_rs; 59 | wire sig2_ex_mem_rs; 60 | wire sig2_mem_wb_mm; 61 | wire sig2_mem_wb_rs; 62 | 63 | wire jump_test; 64 | wire[31:0] jump_address; 65 | 66 | wire is_jump; 67 | wire do_jump; 68 | // ============================== 69 | 70 | // ========== 分支预测 =========== 71 | 72 | wire[31:0] nPC; 73 | reg[65:0] BBT[63:0]; 74 | // [31:00]: old PC 75 | // [63:32]: new PC 76 | // [65:64]: status (00 / 01 / 10 / 11) 77 | 78 | wire ID_jump_inst = (IF_ID_IR[31:26] == 6'b111111 || IF_ID_IR[31:26] == 6'b000010); // 是跳转指令 79 | wire EX_jump_inst = is_jump; // 是跳转指令 80 | 81 | wire[5:0] bbt_if_id = IF_ID_PC[7:2]; 82 | 83 | wire predict_success = 84 | ID_jump_inst && BBT[bbt_if_id][31: 0] == IF_ID_PC && ( 85 | BBT[bbt_if_id][65:64] == 2'b11 || 86 | BBT[bbt_if_id][65:64] == 2'b10 87 | ); 88 | 89 | assign nPC = jump_test ? jump_address : ( predict_success ? BBT[bbt_if_id][63:32] : IF_ID_PC + 4 ); 90 | 91 | // ============================== 92 | 93 | // ============ IF ============== 94 | 95 | assign inst_sram_en = !stall && resetn; 96 | assign inst_sram_addr = nPC; 97 | 98 | /* 99 | 根据当前处于 ID 阶段的 IR 和 PC 值,预测下一个 PC 值。 100 | */ 101 | 102 | assign IF_ID_IR = inst_sram_rdata; 103 | assign IF_ID_JP = nPC; 104 | assign IF_ID_NP = (IF_ID_PC + 4); 105 | 106 | // ============================== 107 | 108 | // ============ ID ============== 109 | 110 | conflict conflict( // 组合逻辑检测是否有冲突信号 111 | .IR1( IF_ID_IR), 112 | .IR2( ID_EX_IR), 113 | .IR3(EX_MEM_IR), 114 | .IR4(MEM_WB_IR), 115 | .stall(stall), 116 | .sig1_ex_mem_rs(sig1_ex_mem_rs), 117 | .sig1_mem_wb_rs(sig1_mem_wb_rs), 118 | .sig1_mem_wb_mm(sig1_mem_wb_mm), 119 | .sig2_ex_mem_rs(sig2_ex_mem_rs), 120 | .sig2_mem_wb_rs(sig2_mem_wb_rs), 121 | .sig2_mem_wb_mm(sig2_mem_wb_mm) 122 | ); 123 | 124 | wire we; // 寄存器堆读使能(写回使能) 125 | wire[ 5:0] waddr; // 寄存器堆写地址 126 | wire[31:0] wdata; // 寄存器堆写数据 127 | 128 | wire[31:0] regfile_rdata1; 129 | wire[31:0] regfile_rdata2; 130 | 131 | reg [31:0] data[0:31]; 132 | assign regfile_rdata1 = waddr == IF_ID_IR[25:21] ? wdata : data[IF_ID_IR[25:21]]; 133 | assign regfile_rdata2 = waddr == IF_ID_IR[20:16] ? wdata : data[IF_ID_IR[20:16]]; 134 | 135 | // 每个上升沿读入数据到 ID_EX.R1 和 ID_EX.R2 里 136 | 137 | wire[31:0] extend_imm; 138 | my_extend my_extend( 139 | .A (IF_ID_IR[15: 0]), // 低 16 位做符号扩展 140 | .B (extend_imm) 141 | ); 142 | 143 | // ============================== 144 | 145 | // ============ EX ============== 146 | wire[31:0] alu_a, reg_a; 147 | wire[31:0] alu_b, reg_b; 148 | 149 | assign reg_a = // 检查是从 ID_EX.R1 里获取,还是定向获取 150 | sig1_ex_mem_rs ? EX_MEM_RS : 151 | sig1_mem_wb_rs ? MEM_WB_RS : 152 | sig1_mem_wb_mm ? MEM_WB_MM : 153 | ID_EX_R1; 154 | 155 | assign reg_b = // 检查是从 ID_EX.R2 里获取,还是定向获取 156 | sig2_ex_mem_rs ? EX_MEM_RS : 157 | sig2_mem_wb_rs ? MEM_WB_RS : 158 | sig2_mem_wb_mm ? MEM_WB_MM : 159 | ID_EX_R2; 160 | 161 | wire mux1_select, mux2_select; 162 | 163 | assign alu_a = mux1_select ? reg_a : ID_EX_NP; 164 | 165 | assign mux1_select = 166 | (ID_EX_IR[31:26] == 6'b000000) | // 运算指令需要 R1 167 | (ID_EX_IR[31:26] == 6'b101011) | // 存数指令需要 R1 168 | (ID_EX_IR[31:26] == 6'b100011) | // 取数指令需要 R1 169 | (ID_EX_IR[31:26] == 6'b111110); 170 | 171 | assign alu_b = mux2_select ? reg_b : ID_EX_IM; 172 | 173 | assign mux2_select = 174 | (ID_EX_IR[31:26] == 6'b000000) | // 运算指令需要 R2 175 | (ID_EX_IR[31:26] == 6'b111110); // 比较指令需要 R2 176 | 177 | wire[31:0] alu_result; 178 | wire[ 5:0] alu_card = 179 | ({6{ID_EX_IR[31:26] == 6'b000000}} & ID_EX_IR[5:0]) | // 运算操作运算码为后五位 180 | ({6{ID_EX_IR[31:26] == 6'b111110}} & 6'b111110) | // 比较指令特殊指定操作码 181 | ({6{ID_EX_IR[31:26] == 6'b101011}} & 6'b100000) | // 存数指令做加法 182 | ({6{ID_EX_IR[31:26] == 6'b100011}} & 6'b100000); // 取数指令做加法 183 | my_alu EX_ALU( // 选出来的结果做运算 184 | .A(alu_a), 185 | .B(alu_b), 186 | .F(alu_result), 187 | .Shft(ID_EX_IR[10: 6]), 188 | .Card(alu_card) 189 | ); 190 | 191 | my_zero my_zero( 192 | .R1(reg_a), // 注意可能需要定向获取 193 | .R2(reg_b), 194 | .IR(ID_EX_IR), 195 | .is_jump(is_jump), 196 | .do_jump(do_jump) 197 | ); 198 | 199 | assign jump_address = 200 | do_jump ? ( 201 | ({32{ID_EX_IR[31:26] == 6'b000010}} & { ID_EX_NP[31:28], ID_EX_IR[25:0], 2'b00 }) | 202 | ({32{ID_EX_IR[31:26] == 6'b111111}} & ((ID_EX_IM << 2) + ID_EX_NP)) 203 | ) : ID_EX_NP; 204 | 205 | assign jump_test = is_jump && (jump_address != ID_EX_JP); 206 | // 如果跳转地址和实际地址不同,则预测不符,需要清空 ID 里的指令 207 | 208 | // ============================== 209 | 210 | // =========== MEM ============== 211 | assign data_sram_addr = EX_MEM_RS; // 写地址为运算结果 212 | assign data_sram_wdata = EX_MEM_RG; // 写数据为寄存器值 213 | assign data_sram_wen = EX_MEM_IR[31:26] == 6'b101011; // 只有存数指令写存 214 | assign data_sram_en = 215 | (EX_MEM_IR[31:26] == 6'b100011) | // 取数指令访存 216 | (EX_MEM_IR[31:26] == 6'b101011); // 存数指令访存 217 | 218 | assign MEM_WB_MM = data_sram_rdata; 219 | // 在下个上升沿才能从 SRAM 里面读出数据 220 | 221 | // ============================== 222 | 223 | // ============ WB ============== 224 | wire mux3_select; 225 | 226 | assign wdata = mux3_select ? MEM_WB_MM : MEM_WB_RS; 227 | 228 | assign waddr = 229 | ({32{MEM_WB_IR[31:26] == 6'b100011}} & MEM_WB_IR[20:16]) | // 取数指令写回 IR[20:16] 230 | ({32{MEM_WB_IR[31:26] == 6'b000000}} & MEM_WB_IR[15:11]) | // 运算指令写回 IR[15:11] 231 | ({32{MEM_WB_IR[31:26] == 6'b111110}} & MEM_WB_IR[15:11]); // 比较指令写回 IR[15:11] 232 | assign mux3_select = 233 | (MEM_WB_IR[31:26] == 6'b100011); // 只有取数指令写回访存结果 234 | assign we = 235 | ((MEM_WB_IR[31:26] == 6'b000000) | // 运算指令要写回 236 | (MEM_WB_IR[31:26] == 6'b100011) | // 取数指令要写回 237 | (MEM_WB_IR[31:26] == 6'b111110) ) & // 比较指令要写回 238 | (waddr != 0); // 不能写入 r0 寄存器 239 | // ============================== 240 | 241 | assign debug_wb_pc = MEM_WB_PC; // 写回的 PC 值 242 | assign debug_wb_rf_wen = we; // 写回使能 243 | assign debug_wb_rf_wnum = waddr; // 写回地址 244 | assign debug_wb_rf_wdata = wdata; // 写回数据 245 | 246 | wire[5:0] bbt_id_ex = ID_EX_PC[7:2]; 247 | 248 | // genvar i; 249 | // generate 250 | // for(i = 0;i < 64;i = i + 1) begin 251 | // always @(posedge clk) begin 252 | // if(~resetn) 253 | // BBT[i] <= 0; 254 | // end 255 | // end 256 | // for(i = 0;i < 32;i = i + 1) begin 257 | // always @(posedge clk) begin 258 | // if(~resetn) 259 | // data[i] <= 0; 260 | // end 261 | // end 262 | // endgenerate 263 | 264 | integer i; 265 | // ============================== 266 | always @(posedge clk) begin 267 | if(~resetn) begin 268 | IF_ID_PC <= -4; 269 | 270 | ID_EX_NP <= 0; 271 | ID_EX_IR <= 0; 272 | ID_EX_R1 <= 0; 273 | ID_EX_R2 <= 0; 274 | ID_EX_IM <= 0; 275 | ID_EX_JP <= 0; 276 | ID_EX_PC <= 0; 277 | 278 | EX_MEM_RS <= 0; 279 | EX_MEM_RG <= 0; 280 | EX_MEM_IR <= 0; 281 | EX_MEM_PC <= 0; 282 | 283 | MEM_WB_RS <= 0; 284 | MEM_WB_IR <= 0; 285 | MEM_WB_PC <= 0; 286 | 287 | for(i = 0;i < 32;i = i + 1) begin 288 | data[i] <= 0; 289 | end 290 | for(i = 0;i < 64;i = i + 1) begin 291 | BBT[i] <= 0; 292 | end 293 | end else begin 294 | if(we) begin 295 | data[waddr] <= wdata; 296 | end 297 | if(EX_jump_inst) begin // 根据 EX 内的指令更新表 298 | if(BBT[bbt_id_ex][31: 0] != ID_EX_PC) begin // 第一次碰到,初始化 299 | BBT[bbt_id_ex][31: 0] <= ID_EX_PC; 300 | BBT[bbt_id_ex][63:32] <= jump_address; 301 | BBT[bbt_id_ex][65:64] <= 2'b00; // 初始默认失败 302 | end else begin 303 | if(!do_jump) begin // 跳转失败 304 | case (BBT[bbt_id_ex][65:64]) 305 | // 2'b00: BBT[bbt_id_ex][65:64] <= 2'b00; 306 | 2'b01: BBT[bbt_id_ex][65:64] <= 2'b00; 307 | 2'b10: BBT[bbt_id_ex][65:64] <= 2'b01; 308 | 2'b11: BBT[bbt_id_ex][65:64] <= 2'b10; 309 | endcase 310 | BBT[bbt_id_ex][63:32] <= jump_address; 311 | // 更新正确的跳转地址 312 | end else begin // 跳转成功 313 | case (BBT[bbt_id_ex][65:64]) 314 | 2'b00: BBT[bbt_id_ex][65:64] <= 2'b01; 315 | 2'b01: BBT[bbt_id_ex][65:64] <= 2'b10; 316 | 2'b10: BBT[bbt_id_ex][65:64] <= 2'b11; 317 | // 2'b11: BBT[bbt_id_ex][65:64] <= 2'b11; 318 | endcase 319 | end 320 | end 321 | end 322 | 323 | ID_EX_NP <= IF_ID_NP; 324 | ID_EX_PC <= IF_ID_PC; 325 | 326 | // 如果有冲突信号,先往后传 NOP 327 | IF_ID_PC <= stall ? IF_ID_PC : nPC; 328 | ID_EX_R1 <= {32{!jump_test && !stall}} & regfile_rdata1; 329 | ID_EX_R2 <= {32{!jump_test && !stall}} & regfile_rdata2; 330 | ID_EX_IR <= {32{!jump_test && !stall}} & IF_ID_IR; 331 | ID_EX_JP <= {32{!jump_test && !stall}} & IF_ID_JP; 332 | ID_EX_IM <= {32{!jump_test && !stall}} & extend_imm; 333 | 334 | EX_MEM_RG <= reg_b; 335 | EX_MEM_IR <= ( 336 | {32{!(ID_EX_IR[31:26] == 6'b000000 && ID_EX_IR[5:0] == 6'b001010 && reg_b != 0)}} 337 | ) & ID_EX_IR; 338 | // 如果是 MOVZ 指令并且 R2 为 0 就不继续执行 339 | EX_MEM_RS <= ( 340 | ({32{ID_EX_IR[31:26] == 6'b000000}} & alu_result) | // 运算指令使用 ALU 341 | ({32{ID_EX_IR[31:26] == 6'b100011}} & alu_result) | // 取数指令使用 ALU 342 | ({32{ID_EX_IR[31:26] == 6'b101011}} & alu_result) | // 存数指令使用 ALU 343 | ({32{ID_EX_IR[31:26] == 6'b111110}} & alu_result) // 比较指令使用 ALU 344 | ); 345 | EX_MEM_PC <= ID_EX_PC; 346 | MEM_WB_IR <= EX_MEM_IR; 347 | MEM_WB_RS <= EX_MEM_RS; 348 | MEM_WB_PC <= EX_MEM_PC; 349 | end 350 | end 351 | 352 | endmodule -------------------------------------------------------------------------------- /lab2/full-task/extend.v: -------------------------------------------------------------------------------- 1 | module my_extend ( 2 | input [15:0] A, 3 | output [31:0] B 4 | ); 5 | assign B = {{16{A[15]}}, A[15:0] }; 6 | endmodule -------------------------------------------------------------------------------- /lab2/full-task/mux.v: -------------------------------------------------------------------------------- 1 | module my_mux( 2 | input[31:0] d0, 3 | input[31:0] d1, 4 | input select, 5 | output[31:0] out 6 | ); 7 | assign out = select ? d1 : d0; 8 | endmodule -------------------------------------------------------------------------------- /lab2/full-task/predictor.v: -------------------------------------------------------------------------------- 1 | module my_predictor ( 2 | input clk, 3 | input rst, 4 | 5 | input jump_test, 6 | input is_jump, 7 | input do_jump, 8 | input[31:0] jump_address, 9 | 10 | input[31:0] ID_IR, // 正在 ID 阶段的 IR 11 | input[31:0] EX_IR, // 正在 EX 阶段的 IR 12 | input[31:0] ID_PC, // 正在 ID 阶段的 PC 13 | input[31:0] EX_PC, // 正在 EX 阶段的 PC 14 | 15 | output[31:0] nPC 16 | ); 17 | reg[65:0] BBT[63:0]; 18 | // [31:00]: old PC 19 | // [63:32]: new PC 20 | // [65:64]: status (00 / 01 / 10 / 11) 21 | 22 | integer i; 23 | initial begin 24 | for(i = 0;i < 64;i = i + 1) begin 25 | BBT[i] = 0; 26 | end 27 | end 28 | 29 | wire ID_jump_inst = (ID_IR[31:26] == 6'b111111 || ID_IR[31:26] == 6'b000010); // 是跳转指令 30 | wire EX_jump_inst = is_jump; // 是跳转指令 31 | 32 | wire predict_success = 33 | ID_jump_inst && BBT[ID_PC[7:2]][31: 0] == ID_PC && ( 34 | BBT[ID_PC[7:2]][65:64] == 2'b11 || 35 | BBT[ID_PC[7:2]][65:64] == 2'b10 36 | ); 37 | 38 | always @(posedge clk) begin 39 | if(!rst) begin // 重置 40 | for(i = 0;i < 64;i = i + 1) begin 41 | BBT[i] <= 0; 42 | end 43 | end else 44 | if(EX_jump_inst) begin // 根据 EX 内的指令更新表 45 | 46 | if(BBT[EX_PC[7:2]][31: 0] != EX_PC) begin // 第一次碰到,初始化 47 | BBT[EX_PC[7:2]][31: 0] <= EX_PC; 48 | BBT[EX_PC[7:2]][63:32] <= jump_address; 49 | BBT[EX_PC[7:2]][65:64] <= 2'b00; // 初始默认失败 50 | end else begin 51 | if(!do_jump) begin // 跳转失败 52 | case (BBT[EX_PC[7:2]][65:64]) 53 | // 2'b00: BBT[EX_PC[7:2]][65:64] <= 2'b00; 54 | 2'b01: BBT[EX_PC[7:2]][65:64] <= 2'b00; 55 | 2'b10: BBT[EX_PC[7:2]][65:64] <= 2'b01; 56 | 2'b11: BBT[EX_PC[7:2]][65:64] <= 2'b10; 57 | endcase 58 | BBT[EX_PC[7:2]][63:32] <= jump_address; 59 | // 更新正确的跳转地址 60 | 61 | end else begin // 跳转成功 62 | case (BBT[EX_PC[7:2]][65:64]) 63 | 2'b00: BBT[EX_PC[7:2]][65:64] <= 2'b01; 64 | 2'b01: BBT[EX_PC[7:2]][65:64] <= 2'b10; 65 | 2'b10: BBT[EX_PC[7:2]][65:64] <= 2'b11; 66 | // 2'b11: BBT[EX_PC[7:2]][65:64] <= 2'b11; 67 | endcase 68 | end 69 | end 70 | end 71 | end 72 | 73 | assign nPC = jump_test ? jump_address : ( predict_success ? BBT[ID_PC[7:2]][63:32] : ID_PC + 4 ); 74 | endmodule -------------------------------------------------------------------------------- /lab2/full-task/regfile.v: -------------------------------------------------------------------------------- 1 | module my_regfile ( 2 | input clk, 3 | input we, 4 | input [4:0] raddr1, 5 | input [4:0] raddr2, 6 | input [4:0] waddr , 7 | output [31:0] rdata1, 8 | output [31:0] rdata2, 9 | input [31:0] wdata 10 | ); 11 | reg [31:0] data[0:31]; 12 | 13 | integer i; 14 | 15 | initial begin 16 | for(i = 0;i < 32;i = i + 1) begin 17 | data[i] <= 0; 18 | end 19 | end 20 | 21 | always @(posedge clk) begin 22 | if(we) begin 23 | data[waddr] <= wdata; 24 | end 25 | end 26 | assign rdata1 = waddr == raddr1 ? wdata : data[raddr1]; 27 | assign rdata2 = waddr == raddr2 ? wdata : data[raddr2]; 28 | endmodule -------------------------------------------------------------------------------- /lab2/full-task/zero.v: -------------------------------------------------------------------------------- 1 | module my_zero ( 2 | input[31:0] R1, 3 | input[31:0] R2, 4 | input[31:0] IR, 5 | output is_jump, 6 | output do_jump 7 | ); 8 | assign is_jump = (IR[31:26] == 6'b111111) || (IR[31:26] == 6'b000010); 9 | assign do_jump = (IR[31:26] == 6'b111111 && R1[IR[20:16]]) || (IR[31:26] == 6'b000010); 10 | // 位测试或者无条件 11 | endmodule -------------------------------------------------------------------------------- /lab3/full-task/cache.v: -------------------------------------------------------------------------------- 1 | module cache ( 2 | input clk , // 时钟 3 | input resetn , // 低有效复位信号 4 | 5 | // Sram-Like 接口信号,用于 CPU 访问 Cache 6 | input cpu_req , // 由 CPU 发送至 Cache 7 | input [31:0] cpu_addr , // 由 CPU 发送至 Cache 8 | output reg [31:0] cache_rdata , // 由 Cache 返回给 CPU 9 | output cache_addr_ok, // 由 Cache 返回给 CPU 10 | output reg cache_data_ok, // 由 Cache 返回给 CPU 11 | 12 | // AXI接口信号,用于Cache访问主存 13 | output reg [3 :0] arid , // Cache 向主存发起读请求时使用的 AXI 信道的 id 号 14 | output reg [31:0] araddr , // Cache 向主存发起读请求时所使用的地址 15 | output reg arvalid, // Cache 向主存发起读请求的请求信号 16 | input arready, // 读请求能否被接收的握手信号 17 | 18 | input [3 :0] rid , //主存向 Cache 返回数据时使用的 AXI 信道的 id 号 19 | input [31:0] rdata , //主存向 Cache 返回的数据 20 | input rlast , //是否是主存向 Cache 返回的最后一个数据 21 | input rvalid , //主存向 Cache 返回数据时的数据有效信号 22 | output reg rready //标识当前的 Cache 已经准备好可以接收主存返回的数据 23 | ); 24 | 25 | // ======= IF1/IF2 ========= 26 | 27 | wire[31:0] way0_rdata; 28 | wire[31:0] way1_rdata; 29 | reg[19:0] way0_tag; 30 | reg[19:0] way1_tag; 31 | reg way0_valid; 32 | reg way1_valid; 33 | reg way0_replace; 34 | reg way1_replace; 35 | reg[31:0] req_addr; 36 | reg flag, get; 37 | 38 | // ========================= 39 | 40 | // ======== BRAMs ========== 41 | 42 | wire[9:0] ram0_raddr; 43 | wire ram0_ren; 44 | reg[9:0] ram0_waddr; 45 | reg[31:0] ram0_wdata; 46 | reg[0:0] ram0_wen; 47 | 48 | wire[9:0] ram1_raddr; 49 | wire ram1_ren; 50 | reg[9:0] ram1_waddr; 51 | reg[31:0] ram1_wdata; 52 | reg[0:0] ram1_wen; 53 | 54 | blk_mem_gen_0 ram0( 55 | .clka(clk), 56 | .clkb(clk), 57 | .addra(ram0_waddr), 58 | .addrb(ram0_raddr), 59 | .wea(ram0_wen), 60 | .enb(ram0_ren), 61 | .dina(ram0_wdata), 62 | .doutb(way0_rdata) 63 | ); 64 | 65 | blk_mem_gen_0 ram1( 66 | .clka(clk), 67 | .clkb(clk), 68 | .addra(ram1_waddr), 69 | .addrb(ram1_raddr), 70 | .wea(ram1_wen), 71 | .enb(ram1_ren), 72 | .dina(ram1_wdata), 73 | .doutb(way1_rdata) 74 | ); 75 | 76 | // ========================= 77 | 78 | // CPU 发送数据请求时从 BRAM0 里面尝试获取 79 | assign ram0_ren = cpu_req && resetn && ~stall; 80 | assign ram1_ren = cpu_req && resetn && ~stall; 81 | 82 | // Tag 数组 83 | // [21] 是 replace 84 | // [20] 是 valid 85 | // [19:0] 是 tag 86 | reg[21:0] tags0[127:0]; 87 | reg[21:0] tags1[127:0]; 88 | 89 | genvar i; 90 | generate 91 | for(i = 0;i < 128;i = i + 1) begin 92 | initial begin 93 | tags0[i] <= 0; 94 | tags1[i] <= 0; 95 | end 96 | end 97 | endgenerate 98 | 99 | // 解析 CPU 传来的地址 100 | wire[19:0] tag; 101 | wire[ 6:0] ind; 102 | wire[ 4:0] off; 103 | 104 | assign tag = cpu_addr[31:12]; 105 | assign ind = cpu_addr[11: 5]; 106 | assign off = cpu_addr[ 4: 0]; 107 | 108 | assign ram0_raddr = { ind, off[ 4: 2] }; 109 | assign ram1_raddr = { ind, off[ 4: 2] }; 110 | 111 | wire hit0, hit1; 112 | reg finish; 113 | 114 | assign stall = flag && (~hit0 && ~hit1 && ~finish); 115 | 116 | // ========== IF1 ========== 117 | 118 | assign cache_addr_ok = ~stall && resetn; 119 | 120 | // ========================= 121 | 122 | // ========== IF2 ========== 123 | 124 | reg[2:0] state; // CPU 与主存数据通信时的状态 125 | 126 | wire[19:0] req_tag; 127 | wire[ 6:0] req_ind; 128 | wire[ 4:0] req_off; 129 | 130 | assign req_tag = req_addr[31:12]; 131 | assign req_ind = req_addr[11: 5]; 132 | assign req_off = req_addr[ 4: 0]; 133 | 134 | assign hit0 = (way0_valid && way0_tag == req_tag); 135 | assign hit1 = (way1_valid && way1_tag == req_tag); 136 | assign override = !way1_valid || way1_replace; 137 | 138 | wire[9:0] nram0_waddr = ram0_waddr + 1; 139 | wire[9:0] nram1_waddr = ram1_waddr + 1; 140 | 141 | always @(posedge clk) begin 142 | if(resetn) begin 143 | if(~stall) begin 144 | way0_tag <= tags0[ind][19:0]; 145 | way1_tag <= tags1[ind][19:0]; 146 | way0_valid <= tags0[ind][20]; 147 | way1_valid <= tags1[ind][20]; 148 | way0_replace <= tags0[ind][21]; 149 | way1_replace <= tags1[ind][21]; 150 | req_addr <= cpu_addr; 151 | flag <= 1; 152 | end 153 | if(flag) begin 154 | case (state) 155 | 0: begin // 开始向 AR 请求数据 156 | 157 | if(hit0 || hit1) begin // 命中 158 | cache_data_ok <= 1; 159 | cache_rdata <= hit0 ? way0_rdata : way1_rdata; 160 | 161 | // 更新替换标记位 162 | tags0[req_ind][21] = hit1; 163 | tags1[req_ind][21] = hit0; 164 | end else begin // 未命中 165 | arvalid <= 1; 166 | araddr <= { req_tag, req_ind, 5'b00000 }; 167 | arid <= 0; 168 | 169 | cache_data_ok <= 0; // 告诉 CPU 数据还没准备好 170 | 171 | if(override) begin // 写入 1 路 172 | ram1_waddr <= { req_ind, 3'b000 } - 1; 173 | tags1[req_ind] <= { 1'b0, 1'b1, req_tag }; 174 | end else begin // 写入 0 路 175 | ram0_waddr <= { req_ind, 3'b000 } - 1; 176 | tags0[req_ind] <= { 1'b0, 1'b1, req_tag }; 177 | end 178 | 179 | state <= 1; // 进入地址握手状态 180 | end 181 | end 182 | 1: begin 183 | if(arready) begin // 握手成功,进入数据握手状态 184 | arvalid <= 0; 185 | rready <= 1; 186 | state <= 2; 187 | end 188 | end 189 | 2: begin 190 | if(rvalid) begin 191 | if(override) begin // 替换 1 路 192 | ram1_wen <= 1; 193 | ram1_wdata <= rdata; 194 | ram1_waddr <= nram1_waddr; 195 | 196 | if(nram1_waddr == { req_ind, req_off[ 4: 2] } ) begin 197 | cache_rdata <= rdata; 198 | end 199 | end else begin // 替换 0 路 200 | ram0_wen <= 1; 201 | ram0_wdata <= rdata; 202 | ram0_waddr <= nram0_waddr; 203 | 204 | if(nram0_waddr == { req_ind, req_off[ 4: 2] } ) begin 205 | cache_rdata <= rdata; 206 | end 207 | end 208 | 209 | if(rlast) begin // 数据传输完毕 210 | rready <= 0; 211 | state <= 3; 212 | 213 | end 214 | end 215 | end 216 | 3: begin // 花一帧时间等待 RAM 写入完毕 217 | ram0_wen <= 0; 218 | ram1_wen <= 0; 219 | finish <= 1; 220 | 221 | state <= 4; 222 | end 223 | 4: begin // 花一帧时间等待 RAM 读取地址 224 | cache_data_ok <= 1; 225 | finish <= 0; 226 | 227 | state <= 0; 228 | end 229 | endcase 230 | end 231 | end else begin 232 | cache_data_ok <= 0; 233 | arvalid <= 0; 234 | rready <= 0; 235 | way0_tag <= 0; 236 | way1_tag <= 0; 237 | way0_valid <= 0; 238 | way1_valid <= 0; 239 | way0_replace <= 0; 240 | way1_replace <= 0; 241 | req_addr <= 0; 242 | flag <= 0; 243 | get <= 0; 244 | 245 | ram0_wen <= 0; 246 | ram1_wen <= 0; 247 | 248 | finish <= 0; 249 | state <= 0; 250 | end 251 | end 252 | // ========================= 253 | 254 | endmodule --------------------------------------------------------------------------------