├── ADD4_32.v ├── ADDMulti4_32.v ├── ALU.v ├── CU.v ├── DM.v ├── EXT.v ├── IM.v ├── MUX2L_32.v ├── MUX4L_32.v ├── MUX4L_5.v ├── PC.v ├── PCJUMP.v ├── README.md ├── RF.v ├── multicycle_CPU_tb.v └── topFile.v /ADD4_32.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | // moduleName: ADD4_32 3 | // fileName: ADD4_32 4 | // Here is a module : ADD4_32 5 | // fuction : 专门为pc+4 6 | 7 | module ADD4_32( 8 | input [31:0] pc_before, 9 | // input [31:0] B, 10 | output [31:0] pc_new 11 | ); 12 | 13 | // pc_before + 4 14 | assign pc_new = pc_before + 4; 15 | 16 | endmodule -------------------------------------------------------------------------------- /ADDMulti4_32.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | // moduleName: ADDMulti4_32 3 | // fileName: ADDMulti4_32 4 | // Here is a module : 5 | // ADDMulti4_32 默认把B左移2位后再加,专为跳转的PC加法 6 | // fuction : + 7 | 8 | module ADDMulti4_32( 9 | input [31:0] A, 10 | input [31:0] B, 11 | output [31:0] out 12 | ); 13 | 14 | // A + B 15 | assign out = A + (B << 2); 16 | 17 | endmodule -------------------------------------------------------------------------------- /ALU.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | // moduleName: ALU 3 | // fileName: ALU 4 | // Here is a module : Arithmetic and Logic Unit 5 | // fuction : 6 | 7 | module ALU( 8 | input [3:0] op_ALU, // ALU操作码,决定操作类型 9 | input [31:0] src_A, // 源操作数A 10 | input [31:0] src_B, // 源操作数B 11 | output reg zero, // 0标志 12 | output reg[31:0] result // 结果 13 | ); 14 | 15 | // 初始化 0标志 16 | initial 17 | begin 18 | zero <= 0; 19 | end 20 | 21 | 22 | always@(*) 23 | begin 24 | case (op_ALU) 25 | 4'b0000 : result <= src_A + src_B; // 加 26 | 4'b0001 : result <= src_A - src_B; // - 27 | 4'b0010 : result <= (src_A < src_B) ? 1 : 0; // A < B ? 28 | 4'b0011 : result <= src_A >> src_B; // A 右移 B 位 29 | 4'b0100 : result <= src_A << src_B; // A 左移 B 位 30 | 4'b0101 : result <= src_A | src_B; // A 按位或 B 31 | 4'b0110 : result <= src_A & src_B; // A 按位与 B 32 | 4'b0111 : result <= src_A ^ src_B; // A 异或 B 33 | 4'b1000 : result <= src_B; // for movn, movz 34 | // rt 自然判是否为0 35 | 36 | 4'b1001 : result <= src_A + 4; // jal addr放到$31的地址值 37 | 38 | 39 | default: result <= result; // do nothing 40 | endcase 41 | 42 | // 0标志 43 | if (result) zero = 0; 44 | else zero = 1; 45 | end 46 | 47 | endmodule -------------------------------------------------------------------------------- /CU.v: -------------------------------------------------------------------------------- 1 | module CU( 2 | input CLK, // 时钟 3 | input reset, // 重置信号 4 | input [5:0] op_instruction, // 指令的op段 5 | input [5:0] func_instruction, // 指令的func段 6 | input zero, // ALU的zero输出 7 | 8 | // 一堆控制信号 9 | output reg w_pc, // PC 写信号 10 | output reg slc_ALUB, // 多路选择器: ALU源操作数B来源选择 11 | output reg slc_ALUA, // 多路选择器: ALU源操作数A来源选择 12 | output reg[1:0] slc_RFWriteData, // 多路选择器:RF写数据来源第一级(两级选择) 13 | output reg w_RF, // (RF)写使能信号,为1时,在时钟上升沿写入 14 | output reg w_dataMem, // (DM)数据存储器读写控制信号,为1写,为0读 15 | output reg[1:0] op_ext, // 立即数拓展: 00:移位指令下对sa的0拓展; 16 | // 01拓展一般0拓展 17 | // 11: 一般情况的符号拓展 18 | output reg[1:0] slc_pcSrc, // 新的PC值的来源选择 19 | output reg[1:0] slc_RFWriteAddr,// RF写地址的来源选择 20 | output reg[3:0] op_ALU // ALU操作码 21 | ); 22 | // 有限状态机宏定义 23 | parameter [2:0] 24 | IF = 3'b000, 25 | ID = 3'b001, 26 | EX_MEM = 3'b010, 27 | EX_NO_MEM = 3'b011, 28 | EX_NO_WB = 3'b100, 29 | MEM_NO_WB = 3'b101, 30 | MEM_WB = 3'b110, 31 | WB = 3'b111; 32 | 33 | // 指令的识别部分: func 或 op 34 | parameter [5:0] 35 | add_func = 6'b100000, 36 | sub_func = 6'b100001, 37 | and_func = 6'b100100, 38 | or_func = 6'b100101, 39 | movn_func = 6'b001011, 40 | movz_func = 6'b001010, 41 | sll_func = 6'b000000, 42 | slt_func = 6'b101010, 43 | jr_func = 6'b001000, 44 | addi_op = 6'b001100, 45 | ori_op = 6'b001101, 46 | sw_op = 6'b101011, 47 | lw_op = 6'b100011, 48 | beq_op = 6'b000100, 49 | j_op = 6'b000010, 50 | jal_op = 6'b000011 51 | // ,halt_op = 52 | ; 53 | // 状态 54 | reg [2:0] status; 55 | // 初始化 56 | initial 57 | begin 58 | w_pc <= 0; 59 | slc_ALUB <= 0; 60 | slc_ALUA <= 0; 61 | w_RF <= 0; 62 | w_dataMem <= 0; 63 | slc_pcSrc <= 0; 64 | slc_RFWriteData <= 0; 65 | slc_RFWriteAddr <= 0; 66 | op_ALU <= 0; 67 | status = IF; 68 | end 69 | 70 | always@(posedge CLK or posedge reset) 71 | begin 72 | // 重置 73 | if (reset) 74 | begin 75 | status = IF; 76 | w_pc = 0; 77 | w_RF = 0; 78 | end 79 | else 80 | begin 81 | case (status) 82 | // 根据所处的状态CU发出不同的控制信号 83 | 84 | IF: // 对所有指令都一样 85 | begin 86 | // 禁止写指令,寄存器,和内存 87 | w_pc = 0; // 读取指令期间,不许修改PC 88 | w_RF = 0; // 非流水: RF此阶段不写 89 | w_dataMem = 0; // 同理DM 不写 90 | // 其他为了不被遗留的状态影响的重置 91 | status <= ID; // 进入ID段 92 | end 93 | 94 | ID: 95 | begin 96 | case (op_instruction) 97 | 6'b000000 : // op = 0的指令通过func识别 98 | begin 99 | case (func_instruction) 100 | sll_func: 101 | begin 102 | op_ext = 2'b00; // 对sa进行0拓展 103 | status = EX_NO_MEM; 104 | end 105 | 106 | jr_func: status = EX_NO_WB; 107 | 108 | default: 109 | status = EX_NO_MEM; // 其他进入EX_NO_MEM,读寄存器即可 110 | // add_func, and_func, sub_func, or_func, 111 | // movn_func, movz_func, slt_func: 112 | endcase 113 | end // op = 0 终止 114 | // 以下op != 0, 通过op识别 115 | sw_op, lw_op: 116 | begin 117 | op_ext = 2'b10; // 地址符号拓展 118 | status = EX_MEM; 119 | end 120 | 121 | j_op : status = EX_NO_WB; 122 | jal_op : status = EX_NO_MEM; 123 | 124 | addi_op, beq_op : 125 | begin 126 | op_ext = 2'b10; // 进行符号拓展 127 | status = EX_NO_MEM; 128 | end 129 | 130 | ori_op : 131 | begin 132 | op_ext = 01; // 进行一般情况的 0拓展 133 | status = EX_NO_MEM; 134 | end 135 | endcase 136 | end // ID 终止 137 | 138 | EX_MEM: // sw, lw 139 | begin 140 | slc_ALUB = 1; // 141 | slc_ALUA = 1; // A来源rs 142 | op_ALU = 0000; // rs + imme ==> DM_addr 读写相同 143 | if (func_instruction == sw_op) status = MEM_NO_WB; // sw 144 | else status = MEM_WB; // lw 145 | end 146 | 147 | EX_NO_WB: // j, jr 148 | begin 149 | if (func_instruction == jr_func) slc_pcSrc = 2'b10; 150 | 151 | if (op_instruction == j_op) slc_pcSrc = 2'b11; 152 | 153 | w_pc = 1; 154 | status = IF; 155 | end 156 | 157 | EX_NO_MEM: // add, sub, and, or, movn,movz, slt,sll, 158 | // addi, ori, beq, jal 159 | begin 160 | if (op_instruction == 0) // op = 0, 看func 161 | begin 162 | slc_ALUB = 0; // B来源是rt 163 | slc_ALUA = 1; // A来源rs 164 | case(func_instruction) 165 | add_func : op_ALU = 4'b0000; 166 | sub_func : op_ALU = 4'b0001; 167 | and_func : op_ALU = 4'b0110; 168 | or_func : op_ALU = 4'b0101; 169 | movn_func: op_ALU = 4'b1000; 170 | movz_func: op_ALU = 4'b1000; 171 | slt_func : op_ALU = 4'b0010; 172 | sll_func : 173 | begin 174 | slc_ALUB = 1; // B来源imme 175 | op_ALU = 4'b0100; 176 | end 177 | default: ; // do nothing 178 | endcase 179 | end // if (op_instrcution == 0)-end 180 | else // op != 0 ????op 181 | begin 182 | slc_ALUB = 1; // B???ime 183 | slc_ALUA = 1; // A??rs 184 | case(op_instruction) 185 | addi_op : op_ALU = 4'b0000; 186 | ori_op : op_ALU = 4'b0101; 187 | beq_op : 188 | begin 189 | slc_ALUB = 0; // rt 190 | op_ALU = 4'b0001; 191 | end 192 | jal_op : 193 | begin 194 | slc_ALUA = 0; 195 | op_ALU = 4'b1001; 196 | end 197 | endcase 198 | 199 | end // else-end 200 | status = WB; // EX_NO_MEM ==> WB? 201 | end // EX_NO_MEM -end 202 | 203 | MEM_NO_WB : // sw 204 | begin 205 | w_dataMem = 1; // write DM 206 | w_pc = 1; // write pc 207 | status = IF; // no WB,????IF? 208 | end 209 | 210 | MEM_WB : // lw 211 | begin 212 | w_dataMem = 0; // read DM 213 | status = WB; // ==> WB 214 | end 215 | 216 | WB : // 对RF写回; 对PC进行更新(部分指令) 217 | // 写入rt:addi, ori,lw 218 | // 写入rd:add, sub, and, or, movn,movz, slt,sll, 219 | // 更新pc: beq, jal 220 | 221 | begin 222 | // 数据来源选择: ALU, DM 223 | slc_pcSrc = 0; 224 | if (op_instruction == lw_op) //只有lw是来自DM 225 | slc_RFWriteData = 2'b01; 226 | else if (op_instruction == 0 && func_instruction[5:1] == 5'b00101) 227 | slc_RFWriteData = 2'b10; // 00101 + 1/0:movn,movz 228 | else 229 | slc_RFWriteData = 2'b00; // RF的in_data来源:ALU-result 230 | // RF写入地址来源选择:rd, rt 231 | case (op_instruction) 232 | jal_op: 233 | begin 234 | slc_pcSrc = 2'b11; // out of PCJUMP 235 | slc_RFWriteAddr = 2'b00; // $31, 1F 236 | end 237 | 238 | addi_op, ori_op, lw_op: 239 | begin 240 | slc_RFWriteAddr = 2'b01; // from rt 241 | end 242 | 6'b000000: slc_RFWriteAddr = 2'b10; // 正好写入rd的命令都是op=0 243 | // select pc src 244 | beq_op: slc_pcSrc = zero ? 2'b01 : 2'b00; // pc+4+imme<<2:pc+4 245 | 246 | endcase 247 | 248 | // 是否给RF发送写信号 249 | if (func_instruction == movn_func && zero == 1) 250 | w_RF = 0; // movn 非0则写 251 | else if (func_instruction == movz_func && zero == 0) 252 | w_RF = 0; // movz 0则写 253 | else 254 | w_RF = 1; // 其他可以进入到WB的命令就是直接写 255 | 256 | w_pc = 1; // 更新pc,每条指令都要的 257 | status = IF; // ==》 IF 258 | end // WB-end 259 | endcase // case(status) 260 | end // if (reset) -else end 261 | end // always_end 262 | endmodule 263 | 264 | 265 | 266 | 267 | 268 | -------------------------------------------------------------------------------- /DM.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | // moduleName: 3 | // fileName: 4 | // Here is a module : 5 | // fuction : 6 | // 7 | module DM( 8 | input CLK, 9 | input w_dataMem, // 写信号 10 | input [31:0] rw_addr, // 读写地址 11 | input [31:0] in_data, 12 | output reg [31:0] out_data 13 | ); 14 | 15 | // 模拟内存 16 | reg [7:0] mem[0:63]; 17 | 18 | integer i; 19 | initial 20 | begin 21 | 22 | for (i = 0; i < 64; i = i + 1) mem[i] <= 0; 23 | end 24 | 25 | 26 | always@(negedge CLK) 27 | begin 28 | if (w_dataMem) // 大端模式、 逐个字节写 29 | begin 30 | mem[rw_addr] <= in_data[31:24]; 31 | mem[rw_addr + 1] <= in_data[23:16]; 32 | mem[rw_addr + 2] <= in_data[15:8]; 33 | mem[rw_addr + 3] <= in_data[7:0]; 34 | end 35 | else // 读 同理 36 | begin 37 | out_data[31:24] <= mem[rw_addr]; 38 | out_data[23:16] <= mem[rw_addr + 1]; 39 | out_data[15:8] <= mem[rw_addr + 2]; 40 | out_data[7:0] <= mem[rw_addr + 3]; 41 | end 42 | end 43 | 44 | endmodule -------------------------------------------------------------------------------- /EXT.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | // moduleName: EXT 3 | // fileName: EXT 4 | // Here is a module : EXT 5 | // fuction : 6 | // 7 | module EXT( 8 | input [1:0]op_ext, // 决定拓展类型的操作码 9 | input [15:0] src_immed, // 要拓展的原数据 10 | output [31:0] new_immed // 拓展后的数据 11 | ); 12 | // 低位 13 | // 00: zero-extend: sll: 移位的位数是指令中sa段([10:6])指定的 14 | // 所以是 [4:0] = [10:6], 其他补0 15 | // 除了是拓展sa段以外,其他的被拓展数都是在[15:0],所以保持低位即可 16 | assign new_immed[4:0] = (op_ext == 2'b00) ? src_immed[10:6] : src_immed[4:0]; 17 | assign new_immed[15:5] = (op_ext == 2'b00) ? 11'b00000000000 : src_immed[15:5]; 18 | 19 | // 高位: (零拓展)无符号补0, (符号拓展)有符号补符号 20 | assign new_immed[31:16] = (op_ext == 2'b10) ? (src_immed[15] ? 16'hffff : 16'h0000) : 16'h0000; 21 | 22 | endmodule -------------------------------------------------------------------------------- /IM.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | // moduleName: IM 3 | // fileName: IM 4 | // Here is a module : Instruction Memory 5 | // fuction : 根据给的地址,输出存储器上的 32位指令 6 | // 这里是使用reg来模拟存储器, 所以使用8位reg[7:0] 7 | // 8 | module IM( 9 | input [31:0] read_addr, // 读地址 10 | // 以下 IR = op,rs,rt,rd,sa,func 11 | // 为了方便,分成了几部分而不以一个IR整体存在 12 | // 由于指令类型的不同 13 | // I类型的: imediate = rd,sa,func 14 | // J类型的: address = rs,rt,rd,sa,func 15 | output reg[5:0] op, 16 | output reg[4:0] rs, 17 | output reg[4:0] rt, 18 | output reg[4:0] rd, 19 | output reg[4:0] sa, 20 | output reg[5:0] func 21 | ); 22 | 23 | reg[7:0] mem[0:63]; // 存储器模拟,64字节 24 | // wire [15:0] immediate; 25 | // assign immediate = {rs,sa,func}; 26 | initial 27 | begin 28 | {mem[0], mem[1], mem[2], mem[3]} = 32'h30010001; //1 29 | {mem[4], mem[5], mem[6], mem[7]} = 32'h00201020; //2 30 | {mem[8], mem[9], mem[10], mem[11]} = 32'h00401821; //3 31 | {mem[12], mem[13], mem[14], mem[15]} = 32'h00622024; //4 32 | {mem[16], mem[17], mem[18], mem[19]} = 32'h00832825; //5 33 | {mem[20], mem[21], mem[22], mem[23]} = 32'h00A4300B; //6 34 | {mem[24], mem[25], mem[26], mem[27]} = 32'h00A4380A; //7 35 | {mem[28], mem[29], mem[30], mem[31]} = 32'h00E6402A; //8 36 | {mem[32], mem[33], mem[34], mem[35]} = 32'h01004880; //9 37 | {mem[36], mem[37], mem[38], mem[39]} = 32'h350A0002; //10 38 | {mem[40], mem[41], mem[42], mem[43]} = 32'hAC020000; //11 39 | {mem[44], mem[45], mem[46], mem[47]} = 32'h8C0B0000; //12 40 | {mem[48], mem[49], mem[50], mem[51]} = 32'h10000001; //13 41 | {mem[52], mem[53], mem[54], mem[55]} = 32'h300C000C; //14 42 | {mem[56], mem[57], mem[58], mem[59]} = 32'h300C000F; //15 43 | {mem[60], mem[61], mem[62], mem[63]} = 32'h08000012; //16 44 | {mem[64], mem[65], mem[66], mem[67]} = 32'h300C0005; //17 45 | {mem[68], mem[69], mem[70], mem[71]} = 32'h03E00008; //18 46 | {mem[72], mem[73], mem[74], mem[75]} = 32'h0C000010; //19 47 | {mem[76], mem[77], mem[78], mem[79]} = 32'h300C0014; //20 48 | {mem[80], mem[81], mem[82], mem[83]} = 32'h300C0015; //21 49 | // 初始化为0 50 | op <= 0; 51 | rs <= 0; 52 | rt <= 0; 53 | rd <= 0; 54 | sa <= 0; 55 | func <= 0; 56 | // 读文件(测试使用的指令放在文件中) 57 | $readmemb("./test/test.txt", mem); 58 | end 59 | 60 | // fetch the instruction to IR 61 | always@(* ) 62 | begin 63 | begin 64 | // 一个字节一个字节的赋值 大端模式(高位在低地址) 65 | op <= mem[read_addr][7:2]; 66 | rs <= {mem[read_addr][1:0], mem[read_addr + 1][7:5]}; 67 | rt <= mem[read_addr+1][4:0]; 68 | rd <= mem[read_addr+2][7:3]; 69 | sa <= {mem[read_addr+2][2:0], mem[read_addr+3][7:6]}; 70 | func <= mem[read_addr+3][5:0]; 71 | end 72 | end 73 | 74 | endmodule 75 | 76 | -------------------------------------------------------------------------------- /MUX2L_32.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | // moduleName: MUX2L_32 3 | module MUX2L_32( 4 | input slc, 5 | input [31:0] in_0, 6 | input [31:0] in_1, 7 | output [31:0] out_0 8 | ); 9 | 10 | assign out_0 = slc ? in_1 : in_0; 11 | 12 | endmodule -------------------------------------------------------------------------------- /MUX4L_32.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | // moduleName: MUX4L_32 3 | module MUX4L_32( 4 | input [1:0] slc, 5 | input [31:0] in_0, 6 | input [31:0] in_1, 7 | input [31:0] in_2, 8 | input [31:0] in_3, 9 | output [31:0] out_0 10 | ); 11 | 12 | assign out_0 = slc[0] ? (slc[1] ? in_3 : in_1) : (slc[1] ? in_2 : in_0); 13 | endmodule -------------------------------------------------------------------------------- /MUX4L_5.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | // moduleName: MUX4L_5 3 | module MUX4L_5( 4 | input [1:0] slc, 5 | input [4:0] in_0, 6 | input [4:0] in_1, 7 | input [4:0] in_2, 8 | input [4:0] in_3, 9 | output [4:0] out_0 10 | ); 11 | 12 | assign out_0 = slc[0] ? (slc[1] ? in_3 : in_1) : (slc[1] ? in_2 : in_0); 13 | endmodule -------------------------------------------------------------------------------- /PC.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | // moduleName: PC 3 | // fileName: PC 4 | // Here is a module : program counter 5 | // fuction : 6 | // 1. w_pc == 1下, 在clk上沿更新pc 7 | // 2. reset == 1下,重置pc 为 0 8 | 9 | module PC( 10 | input CLK, // 11 | input reset, // 12 | input w_pc, // pc 写信号 13 | input [31:0] in_addr, // pc输入地址,新地址 14 | output reg[31:0] out_addr // pc输出地址,当前地址 15 | ); 16 | 17 | initial begin 18 | out_addr <= 0; // 初始为 0 19 | end 20 | 21 | always@(posedge CLK or posedge reset) 22 | begin 23 | if (reset == 1) 24 | out_addr <= 0; // 重置为 0 25 | else 26 | begin 27 | if (w_pc) 28 | out_addr <= in_addr; // 更新pc 29 | else 30 | out_addr <= out_addr; // 不变 31 | end 32 | end 33 | endmodule 34 | -------------------------------------------------------------------------------- /PCJUMP.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | // moduleName: ALU 3 | // fileName: ALU 4 | // Here is a module : Arithmetic and Logic Unit 5 | // fuction : 6 | 7 | // 26bit 字节address, 补全成32bit字节地址 8 | // << 2, 头部使用PC的头部 9 | // jar命令的含义: PC = (PC+4)[31:28]||target||'00' 10 | 11 | 12 | module PCJUMP( 13 | input [31:0] PC4, // 指令 14 | input [25:0] in_addr, // 输入地址 15 | output [31:0] out_addr // 输出地址(指令) 16 | ); 17 | 18 | // out_addr = PC[31:28] + in_addr + 00 19 | // 这里用<= 会不会好一点 20 | assign out_addr[31:28] = PC4[31:28]; 21 | assign out_addr[27:2] = in_addr; 22 | assign out_addr[1:0] = 2'b00; 23 | 24 | endmodule 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # muticycle-CPU 2 | MIPS多周期CPU 3 | 题目: 设计并实现一个多周期CPU 4 | 5 | 完成度: 6 | 1. 实现支持多周期的CPU 7 | 2. 支持不同的指令可以跳过不必要的阶段以提高效率 8 | 3. 实现三种类型的指令16条 9 | 4. 实现的指令有: 10 | a) 算术运算:add、sub、addi 11 | b) 逻辑运算:or、and、ori 12 | c) 移位运算:sll 13 | d) 传送指令:movn、movz 14 | e) 访存指令:sw、lw 15 | f) 比较指令:slt 16 | g) 分支指令:beq 17 | h) 跳转指令:j、jr 18 | i) 子程序调用: jal 19 | 5. 完成一个尽可能规范的CPU是我的主要目的 20 | a) 参照MIPS指令格式 21 | b) 采用相同的指令编码 22 | c) 可拓展:预留的指令编码空间可以后期拓展到更多指令 23 | 24 | 6. 全部通过测试 25 | 26 | 文档: https://www.yuque.com/docs/share/aacb1cec-74ac-4da2-93cb-69940e48b2b0?# 《系统硬件综合设计实验报告》 27 | 28 | 29 | -------------------------------------------------------------------------------- /RF.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | // moduleName: RF 3 | // fileName: RF 4 | // Here is a module : registereadReg_addrA file 5 | // fuction : 6 | // 1. 随时可读出指定寄存器编号的值 7 | // 2. 在写信号有效下,更新指定寄存器的值 8 | // 3. 不修改0号寄存器,使之保持为0 9 | // 10 | module RF( 11 | input CLK, 12 | input w_RF, // RF 写信号 13 | input [4:0] readReg_addrA, // reg_addr: readReg_addrA 14 | input [4:0] readReg_addrB, // reg_addr: readReg_addrB 15 | input [4:0] writeReg_addr, // reg_addr: 写地址(寄存器编号) 16 | input [31:0] writeData, // 写数据 17 | output [31:0] out_dataA, // 读数据A: readReg_addrA 18 | output [31:0] out_dataB // 读数据: readReg_addrB 19 | ); 20 | reg [31:0] register[0:31]; // 32个 32位寄存器 21 | 22 | integer i; // 辅助变量,用来遍历 23 | initial 24 | begin 25 | // 32个寄存器初始化为0 26 | for(i = 0; i < 32; i = i + 1) register[i] <= 0; 27 | end 28 | 29 | // A、B两个端口: 读寄存器 30 | assign out_dataA = register[readReg_addrA]; 31 | assign out_dataB = register[readReg_addrB]; 32 | 33 | // 写寄存器 34 | always@(posedge w_RF, negedge CLK) 35 | begin 36 | // 这里0号寄存器不使用,作为常数 0 37 | if (w_RF && writeReg_addr != 0) register[writeReg_addr] = writeData; 38 | end 39 | 40 | 41 | endmodule -------------------------------------------------------------------------------- /multicycle_CPU_tb.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns/1ps 2 | module multicycle_CPU_TB( 3 | ); 4 | 5 | reg clk; 6 | always #5 clk = ~clk; 7 | 8 | initial 9 | begin 10 | #5 11 | clk = 1; 12 | end 13 | 14 | multicycle_CPU cpu_tb( 15 | .CLK(clk), .reset(1'b0) 16 | ); 17 | 18 | endmodule 19 | 20 | 21 | -------------------------------------------------------------------------------- /topFile.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | module multicycle_CPU( 3 | input CLK, 4 | input reset 5 | ); 6 | 7 | wire[31:0] out_data; // DM 8 | wire[31:0] out_ADDMulti4_32; //ADDMulti4_32 9 | wire[31:0] out_pcSrc; // pcSrc 4路选择器输出 10 | wire [4:0] out_RFWriteAddr; // RFWriteAddr 11 | wire[31:0] result, out_RFWriteData; // ALU结果 12 | wire zero; // ALU结果 0标志 13 | // CU信号 14 | wire w_pc, slc_ALUB, slc_ALUA, w_RF, w_dataMem; 15 | wire[1:0] op_ext, slc_pcSrc, slc_RFWriteAddr, slc_RFWriteData; 16 | wire[3:0] op_ALU; 17 | wire[31:0] pc_new; // ADD4_32, out 18 | 19 | // 信号线的名字 = 信号来源名字 20 | 21 | 22 | /* 23 | module PC( 24 | input CLK, // 25 | input reset, // 26 | input w_pc, // pc 写信号 27 | input [31:0] in_addr, // pc输入地址,新地址 28 | output reg[31:0] out_addr // pc输出地址,当前地址 29 | ); 30 | */ 31 | // from PC 32 | wire[31:0] out_addr_pc; 33 | PC PC_case(.CLK(CLK), .reset(reset), .w_pc(w_pc), .in_addr(out_pcSrc), 34 | .out_addr(out_addr_pc) ); 35 | 36 | /* 37 | module IM( 38 | input [31:0] read_addr, // 读地址 39 | // I类型的: imediate = rd,sa,func 40 | // J类型的: address = rs,rt,rd,sa,func 41 | output reg[5:0] op, 42 | output reg[4:0] rs, rt, rd, sa, 43 | ouptut reg[5:0] func 44 | ); 45 | */ 46 | //from IM 47 | wire[5:0] op, func; 48 | wire[4:0] rs, rt, rd, sa; 49 | IM IM_case (.read_addr(out_addr_pc), 50 | .op(op), .rs(rs), .rt(rt), .rd(rd), .sa(sa), .func(func)); 51 | 52 | /* 53 | module RF( 54 | input CLK, 55 | input w_RF, // RF 写信号 56 | input [4:0] readReg_addrA, // reg_addr: readReg_addrA 57 | input [4:0] readReg_addrB, // reg_addr: readReg_addrB 58 | input [4:0] writeReg_addr, // reg_addr: 写地址(寄存器编号) 59 | input [31:0] writeData, // 写数据 60 | output [31:0] out_dataA, // 读数据A: readReg_addrA 61 | output [31:0] out_dataB // 读数据: readReg_addrB 62 | ); 63 | */ 64 | // from RF 65 | wire[31:0] out_dataA, out_dataB; 66 | 67 | RF RF_case (.CLK(CLK), .w_RF(w_RF), .readReg_addrA(rs), 68 | .readReg_addrB(rt),.writeReg_addr(out_RFWriteAddr),.writeData(out_RFWriteData), 69 | .out_dataA(out_dataA), .out_dataB(out_dataB)); 70 | 71 | 72 | /* 73 | module EXT( 74 | input [1:0]op_ext, // 决定拓展类型的操作码 75 | input [15:0] src_immed, // 要拓展的原数据 76 | output [31:0] new_immed // 拓展后的数据 77 | ); 78 | */ 79 | // from EXT 80 | wire[31:0] new_immed; 81 | EXT EXT_case (.op_ext(op_ext), .src_immed({rd,sa,func}), 82 | .new_immed(new_immed)); 83 | 84 | /* 85 | module PCJUMP( 86 | input [31:0] PC4, // 指令 87 | input [25:0] in_addr, // 输入地址 88 | output [31:0] out_addr // 输出地址(指令) 89 | ); 90 | */ 91 | // from PCJUMP (pc+4)[31:28],addr,00 92 | wire[31:0] out_addr; 93 | PCJUMP PCJUMP_case (.PC4(pc_new), .in_addr({rs,rt,rd,sa,func}), 94 | .out_addr(out_addr)); 95 | /* 96 | module ADD4_32( 97 | input [31:0] pc_before, 98 | // input [31:0] B, 99 | output [31:0] pc_new 100 | ); 101 | // 专为pc+4 102 | */ 103 | // from ADD4_32 104 | 105 | ADD4_32 ADD4_32_case (.pc_before(out_addr_pc), 106 | .pc_new(pc_new)); 107 | 108 | 109 | /* 110 | module MUX2L_32( 111 | input slc, 112 | input [31:0] in_0, 113 | input [31:0] in_1, 114 | output [31:0] out_0 115 | ); 116 | */ 117 | wire[31:0] out_slc_ALUA, out_slc_ALUB; 118 | MUX2L_32 MUX2L_32_ALUA (.slc(slc_ALUA), .in_0(pc_new), .in_1(out_dataA), 119 | .out_0(out_slc_ALUA)); 120 | MUX2L_32 MUX2L_32_ALUB (.slc(slc_ALUB), .in_0(out_dataB), .in_1(new_immed), 121 | .out_0(out_slc_ALUB)); 122 | MUX2L_32 MUX2L_32_RFWriteData (.slc(slc_RFWriteData), .in_0(result), .in_1(out_data), 123 | .out_0(out_RFWriteData)); 124 | 125 | /* 126 | module ALU( 127 | input [3:0] op_ALU, // ALU操作码,决定操作类型 128 | input [31:0] src_A, // 源操作数A 129 | input [31:0] src_B, // 源操作数B 130 | output reg zero, // 0标志 131 | output reg[31:0] result // 结果 132 | ); 133 | */ 134 | ALU ALU_case (.op_ALU(op_ALU), .src_A(out_slc_ALUA), 135 | .src_B(out_slc_ALUB), 136 | .zero(zero), .result(result)); 137 | 138 | /* 139 | module DM( 140 | input w_dataMem, // 写信号 141 | input [31:0] rw_addr, // 读写地址 142 | input [31:0] in_data, // 要写入的数据 143 | output reg [31:0] out_data // 读出的数据 144 | ); 145 | */ 146 | DM DM_case (.CLK(CLK), .w_dataMem(w_dataMem), .rw_addr(result), .in_data(out_dataB), 147 | .out_data(out_data)); 148 | 149 | /* 150 | module ADDMulti4_32( 151 | input [31:0] A, 152 | input [31:0] B, 153 | output [31:0] out 154 | ); 155 | // 专为地址跳转: (pc+4)+ imme << 2 156 | */ 157 | ADDMulti4_32 ADDMulti4_32_case (.A(pc_new), .B(new_immed), 158 | .out(out_ADDMulti4_32)); 159 | 160 | /* 161 | module MUX4L_32( 162 | input [1:0] slc, 163 | input [31:0] in_0, 164 | input [31:0] in_1, 165 | input [31:0] in_2, 166 | input [31:0] in_3, 167 | output [31:0] out_0 168 | ); 169 | */ 170 | MUX4L_32 MUX4L_32_pcSrc (.slc(slc_pcSrc), .in_0(pc_new), 171 | .in_1(out_ADDMulti4_32), 172 | .in_2(out_dataA), .in_3(out_addr), 173 | .out_0(out_pcSrc)); 174 | 175 | /* 176 | module MUX4L_5( 177 | input [1:0] slc, 178 | input [4:0] in_0, 179 | input [4:0] in_1, 180 | input [4:0] in_2, 181 | input [4:0] in_3, 182 | out_0put [4:0] out_0 183 | ); 184 | */ 185 | // 1F : $31 186 | MUX4L_5 MUX4L_5_RFWriteAddr (.slc(slc_RFWriteAddr), .in_0(5'h1F), 187 | .in_1(rt), .in_2(rd), 188 | .in_3(5'b00000), 189 | .out_0(out_RFWriteAddr)); 190 | // in_3 不使用 191 | 192 | /* 193 | module CU( 194 | input CLK, // 时钟 195 | input reset, // 重置信号 196 | input [5:0] op_instruction, // 指令的op段 197 | input [5:0] func_instruction, // 指令的func段 198 | input zero, // ALU的zero输出 199 | 200 | // 一堆控制信号 201 | output reg w_pc, // PC 写信号 202 | output reg slc_ALUB, // 多路选择器: ALU源操作数B来源选择 203 | output reg slc_ALUA, // 多路选择器: ALU源操作数A来源选择 204 | output reg[1:0] slc_RFWriteData, // 多路选择器:RF写数据来源第一级(两级选择) 205 | output reg w_RF, // (RF)写使能信号,为1时,在时钟上升沿写入 206 | output reg w_dataMem, // (DM)数据存储器读写控制信号,为1写,为0读 207 | output reg[1:0] op_ext, // 立即数拓展: 00:移位指令下对sa的0拓展; 208 | // 01拓展一般0拓展 209 | // 11: 一般情况的符号拓展 210 | output reg[1:0] slc_pcSrc, // 新的PC值的来源选择 211 | output reg[1:0] slc_RFWriteAddr,// RF写地址的来源选择 212 | output reg[3:0] op_ALU // ALU操作码 213 | ); 214 | */ 215 | 216 | CU CU_case (.CLK(CLK), .reset(reset), .op_instruction(op), 217 | .func_instruction(func), .zero(zero), 218 | .w_pc(w_pc), .slc_ALUB(slc_ALUB), .slc_ALUA(slc_ALUA), 219 | .slc_RFWriteData(slc_RFWriteData), .w_RF(w_RF), 220 | .w_dataMem(w_dataMem), .op_ext(op_ext), .slc_pcSrc(slc_pcSrc), 221 | .slc_RFWriteAddr(slc_RFWriteAddr), .op_ALU(op_ALU)); 222 | 223 | endmodule --------------------------------------------------------------------------------