riscvsingle.sv (14127B)
1 // riscvsingle.sv 2 3 // RISC-V single-cycle processor 4 // From Section 7.6 of Digital Design & Computer Architecture 5 // 27 April 2020 6 // David_Harris@hmc.edu 7 // Sarah.Harris@unlv.edu 8 9 // run 210 10 // Expect simulator to print "Simulation succeeded" 11 // when the value 25 (0x19) is written to address 100 (0x64) 12 13 // Single-cycle implementation of RISC-V (RV32I) 14 // User-level Instruction Set Architecture V2.2 (May 7, 2017) 15 // Implements a subset of the base integer instructions: 16 // lw, sw 17 // add, sub, and, or, slt, 18 // addi, andi, ori, slti 19 // beq 20 // jal 21 // Exceptions, traps, and interrupts not implemented 22 // little-endian memory 23 24 // 31 32-bit registers x1-x31, x0 hardwired to 0 25 // R-Type instructions 26 // add, sub, and, or, slt 27 // INSTR rd, rs1, rs2 28 // Instr[31:25] = funct7 (funct7b5 & opb5 = 1 for sub, 0 for others) 29 // Instr[24:20] = rs2 30 // Instr[19:15] = rs1 31 // Instr[14:12] = funct3 32 // Instr[11:7] = rd 33 // Instr[6:0] = opcode 34 // I-Type Instructions 35 // lw, I-type ALU (addi, andi, ori, slti) 36 // lw: INSTR rd, imm(rs1) 37 // I-type ALU: INSTR rd, rs1, imm (12-bit signed) 38 // Instr[31:20] = imm[11:0] 39 // Instr[24:20] = rs2 40 // Instr[19:15] = rs1 41 // Instr[14:12] = funct3 42 // Instr[11:7] = rd 43 // Instr[6:0] = opcode 44 // S-Type Instruction 45 // sw rs2, imm(rs1) (store rs2 into address specified by rs1 + immm) 46 // Instr[31:25] = imm[11:5] (offset[11:5]) 47 // Instr[24:20] = rs2 (src) 48 // Instr[19:15] = rs1 (base) 49 // Instr[14:12] = funct3 50 // Instr[11:7] = imm[4:0] (offset[4:0]) 51 // Instr[6:0] = opcode 52 // B-Type Instruction 53 // beq rs1, rs2, imm (PCTarget = PC + (signed imm x 2)) 54 // Instr[31:25] = imm[12], imm[10:5] 55 // Instr[24:20] = rs2 56 // Instr[19:15] = rs1 57 // Instr[14:12] = funct3 58 // Instr[11:7] = imm[4:1], imm[11] 59 // Instr[6:0] = opcode 60 // J-Type Instruction 61 // jal rd, imm (signed imm is multiplied by 2 and added to PC, rd = PC+4) 62 // Instr[31:12] = imm[20], imm[10:1], imm[11], imm[19:12] 63 // Instr[11:7] = rd 64 // Instr[6:0] = opcode 65 66 // Instruction opcode funct3 funct7 67 // add 0110011 000 0000000 68 // sub 0110011 000 0100000 69 // and 0110011 111 0000000 70 // or 0110011 110 0000000 71 // slt 0110011 010 0000000 72 // addi 0010011 000 immediate 73 // andi 0010011 111 immediate 74 // ori 0010011 110 immediate 75 // slti 0010011 010 immediate 76 // beq 1100011 000 immediate 77 // lw 0000011 010 immediate 78 // sw 0100011 010 immediate 79 // jal 1101111 immediate immediate 80 81 82 // This part is modified by Dr.Toker 83 module my_computer(input logic clk, reset, 84 input logic[ 9:0] my_sw, 85 output logic[31:0] my_rd, 86 output logic[31:0] my_PC 87 ); 88 89 logic [31:0] PC, Instr, ReadData, WriteData, DataAddr; 90 logic MemWrite; 91 92 // instantiate processor 93 riscvsingle rvsingle(clk, reset, PC, Instr, MemWrite, DataAddr, 94 WriteData, ReadData); 95 // program memory - ROM 96 imem imem(PC, Instr); 97 98 // data memort - RAM 99 dmem dmem(clk, MemWrite, DataAddr, WriteData, ReadData, my_sw, my_rd); 100 101 assign my_PC = PC; 102 103 always_ff @(posedge clk) 104 $display("PC: %x", PC); 105 endmodule 106 107 // ======================================================================= 108 // NEW STUFF ABOUT MEMORIES - MUST REVIEW FIRST 109 // ======================================================================= 110 111 module regfile(input logic clk, 112 input logic we3, 113 input logic [ 4:0] a1, a2, a3, 114 input logic [31:0] wd3, 115 output logic [31:0] rd1, rd2); 116 117 logic [31:0] rf[31:0]; 118 119 // three ported register file 120 // read two ports combinationally (A1/RD1, A2/RD2) 121 // write third port on rising edge of clock (A3/WD3/WE3) 122 // register 0 hardwired to 0 123 124 always_ff @(posedge clk) 125 if (we3) rf[a3] <= wd3; 126 127 assign rd1 = (a1 != 0) ? rf[a1] : 0; 128 assign rd2 = (a2 != 0) ? rf[a2] : 0; 129 endmodule 130 131 module imem(input logic [31:0] a, 132 output logic [31:0] rd); 133 134 logic [31:0] ROM[127:0]; 135 136 // Initialize the program memory 137 // Simulator : ok 138 // Hardware : For FPGA ok, non-FPGA we need a 3rd party solution to program the FLASH memory (ROM) 139 initial 140 $readmemh("/home/vin/src/public/eel3792c_rv32i/riscvtest_rom_image.txt", ROM); 141 142 assign rd = ROM[a[31:2]]; // word aligned 143 endmodule 144 145 // This part is modified by Dr. Toker 146 module dmem(input logic clk, we, 147 input logic [31:0] a, wd, 148 output logic [31:0] rd, 149 input logic [ 7:0] my_sw, 150 output logic [31:0] my_rd); 151 152 logic [31:0] RAM[255:0]; 153 154 assign rd = RAM[a[31:2]]; // word aligned 155 156 always_ff @(posedge clk) 157 begin 158 if (we) RAM[a[31:2]] <= wd; 159 160 // Used only for simulation, does not correspond to ANY hardware 161 if (we) 162 $display("Write RAM[%08x]=%08x at %t", a[31:2], wd, $time); 163 else 164 $display("Read RAM[%08x]=%08x at %t", a[31:2], rd, $time); 165 166 end 167 168 assign my_rd = RAM[my_sw[7:2]]; 169 170 // Initialize the program memory 171 // Simulator : ok 172 // Hardware : For FPGA ok, non-FPGA we need a 3rd party solution to program the DATA memory (RAM) 173 initial 174 $readmemh("/home/vin/src/public/eel3792c_rv32i/riscvtest_ram_image.txt", RAM); 175 176 endmodule 177 178 module flopr #(parameter WIDTH = 8) 179 (input logic clk, reset, 180 input logic [WIDTH-1:0] d, 181 output logic [WIDTH-1:0] q); 182 183 always_ff @(posedge clk, posedge reset) 184 if (reset) q <= 0; 185 else q <= d; 186 endmodule 187 188 // ======================================================================= 189 // OLD STUFF - Component Instantiation or New Combinatorial Designs 190 // ======================================================================= 191 192 module riscvsingle(input logic clk, reset, 193 output logic [31:0] PC, 194 input logic [31:0] Instr, 195 output logic MemWrite, 196 output logic [31:0] ALUResult, WriteData, 197 input logic [31:0] ReadData); 198 199 logic ALUSrc, RegWrite, Jump, Zero; 200 logic [1:0] ResultSrc, ImmSrc; 201 logic [3:0] ALUControl; 202 203 controller c(Instr[6:0], Instr[14:12], Instr[30], Zero, 204 ResultSrc, MemWrite, PCSrc, 205 ALUSrc, RegWrite, Jump, 206 ImmSrc, ALUControl); 207 datapath dp(clk, reset, ResultSrc, PCSrc, 208 ALUSrc, RegWrite, 209 ImmSrc, ALUControl, 210 Zero, PC, Instr, 211 ALUResult, WriteData, ReadData); 212 endmodule 213 214 module controller(input logic [6:0] op, 215 input logic [2:0] funct3, 216 input logic funct7b5, 217 input logic Zero, 218 output logic [1:0] ResultSrc, 219 output logic MemWrite, 220 output logic PCSrc, ALUSrc, 221 output logic RegWrite, Jump, 222 output logic [1:0] ImmSrc, 223 output logic [3:0] ALUControl); 224 225 logic [1:0] ALUOp; 226 logic Branch; 227 228 maindec md(op, ResultSrc, MemWrite, Branch, 229 ALUSrc, RegWrite, Jump, ImmSrc, ALUOp); 230 aludec ad(op[5], funct3, funct7b5, ALUOp, ALUControl); 231 232 // assign PCSrc = Branch & Zero | Jump; 233 always_comb 234 if (Branch) 235 case (funct3) 236 3'b000: PCSrc = Zero; // beq 237 3'b001: PCSrc = ~Zero; // bne 238 3'b100: PCSrc = Zero; // blt 239 3'b101: PCSrc = ~Zero; // blt 240 default: PCSrc = 1'bx; 241 endcase 242 else 243 PCSrc = Jump; 244 endmodule 245 246 module maindec(input logic [6:0] op, 247 output logic [1:0] ResultSrc, 248 output logic MemWrite, 249 output logic Branch, ALUSrc, 250 output logic RegWrite, Jump, 251 output logic [1:0] ImmSrc, 252 output logic [1:0] ALUOp); 253 254 logic [10:0] controls; 255 256 assign {RegWrite, ImmSrc, ALUSrc, MemWrite, 257 ResultSrc, Branch, ALUOp, Jump} = controls; 258 259 always_comb 260 case(op) 261 // RegWrite_ImmSrc_ALUSrc_MemWrite_ResultSrc_Branch_ALUOp_Jump 262 7'b0000011: controls = 11'b1_00_1_0_01_0_00_0; // lw 263 7'b0100011: controls = 11'b0_01_1_1_00_0_00_0; // sw 264 7'b0110011: controls = 11'b1_xx_0_0_00_0_10_0; // R-type 265 7'b1100011: controls = 11'b0_10_0_0_00_1_01_0; // B-type 266 7'b0010011: controls = 11'b1_00_1_0_00_0_10_0; // I-type ALU 267 7'b1101111: controls = 11'b1_11_0_0_10_0_00_1; // jal 268 default: controls = 11'bx_xx_x_x_xx_x_xx_x; // non-implemented instruction 269 endcase 270 endmodule 271 272 module aludec(input logic opb5, 273 input logic [2:0] funct3, 274 input logic funct7b5, 275 input logic [1:0] ALUOp, 276 output logic [3:0] ALUControl); 277 278 logic RtypeSub; 279 assign RtypeSub = funct7b5 & opb5; // TRUE for R-type subtract instruction 280 281 always_comb 282 case(ALUOp) 283 2'b00: ALUControl = 4'b0000; // addition 284 2'b01: ALUControl = {funct3[2], 3'b001}; // branching 285 // (funct3[2] is used because it's set in blt/bge but not beq/bne 286 default: case(funct3) // R-type or I-type ALU 287 3'b000: if (RtypeSub) 288 ALUControl = 4'b0001; // sub 289 else 290 ALUControl = 4'b0000; // add, addi 291 3'b001: ALUControl = 4'b0110; // sll, slli 292 3'b010: ALUControl = 4'b0101; // slt, slti 293 3'b100: ALUControl = 4'b0100; // xor, xori 294 3'b101: if (RtypeSub) 295 ALUControl = 4'b1000; // sra, srai 296 else 297 ALUControl = 4'b0111; // srl, srli 298 3'b110: ALUControl = 4'b0011; // or, ori 299 3'b111: ALUControl = 4'b0010; // and, andi 300 default: ALUControl = 4'bxxxx; // ??? 301 endcase 302 endcase 303 endmodule 304 305 module datapath(input logic clk, reset, 306 input logic [1:0] ResultSrc, 307 input logic PCSrc, ALUSrc, 308 input logic RegWrite, 309 input logic [1:0] ImmSrc, 310 input logic [3:0] ALUControl, 311 output logic Zero, 312 output logic [31:0] PC, 313 input logic [31:0] Instr, 314 output logic [31:0] ALUResult, WriteData, 315 input logic [31:0] ReadData); 316 317 logic [31:0] PCNext, PCPlus4, PCTarget; 318 logic [31:0] ImmExt; 319 logic [31:0] SrcA, SrcB; 320 logic [31:0] Result; 321 322 // next PC logic 323 flopr #(32) pcreg(clk, reset, PCNext, PC); 324 adder pcadd4(PC, 32'd4, PCPlus4); 325 adder pcaddbranch(PC, ImmExt, PCTarget); 326 mux2 #(32) pcmux(PCPlus4, PCTarget, PCSrc, PCNext); 327 328 // register file logic 329 regfile rf(clk, RegWrite, Instr[19:15], Instr[24:20], 330 Instr[11:7], Result, SrcA, WriteData); 331 extend ext(Instr[31:7], ImmSrc, ImmExt); 332 333 // ALU logic 334 mux2 #(32) srcbmux(WriteData, ImmExt, ALUSrc, SrcB); 335 alu alu(SrcA, SrcB, ALUControl, ALUResult, Zero); 336 mux3 #(32) resultmux(ALUResult, ReadData, PCPlus4, ResultSrc, Result); 337 endmodule 338 339 340 module adder(input [31:0] a, b, 341 output [31:0] y); 342 343 assign y = a + b; 344 endmodule 345 346 module extend(input logic [31:7] instr, 347 input logic [1:0] immsrc, 348 output logic [31:0] immext); 349 350 always_comb 351 case(immsrc) 352 // I-type 353 2'b00: immext = {{20{instr[31]}}, instr[31:20]}; 354 // S-type (stores) 355 2'b01: immext = {{20{instr[31]}}, instr[31:25], instr[11:7]}; 356 // B-type (branches) 357 2'b10: immext = {{20{instr[31]}}, instr[7], instr[30:25], instr[11:8], 1'b0}; 358 // J-type (jal) 359 2'b11: immext = {{12{instr[31]}}, instr[19:12], instr[20], instr[30:21], 1'b0}; 360 default: immext = 32'bx; // undefined 361 endcase 362 endmodule 363 364 module mux2 #(parameter WIDTH = 8) 365 (input logic [WIDTH-1:0] d0, d1, 366 input logic s, 367 output logic [WIDTH-1:0] y); 368 369 assign y = s ? d1 : d0; 370 endmodule 371 372 module mux3 #(parameter WIDTH = 8) 373 (input logic [WIDTH-1:0] d0, d1, d2, 374 input logic [1:0] s, 375 output logic [WIDTH-1:0] y); 376 377 assign y = s[1] ? d2 : (s[0] ? d1 : d0); 378 endmodule 379 380 module alu(input logic [31:0] a, b, 381 input logic [3:0] alucontrol, 382 output logic [31:0] result, 383 output logic zero); 384 385 logic [31:0] condinvb, sum; 386 logic v; // overflow 387 logic isAddSub; // true when is add or subtract operation 388 389 assign condinvb = alucontrol[0] ? ~b : b; 390 assign sum = a + condinvb + alucontrol[0]; 391 assign isAddSub = ~alucontrol[2] & ~alucontrol[1] | 392 ~alucontrol[1] & alucontrol[0]; 393 394 always_comb 395 case (alucontrol) 396 4'b0000: result = sum; // add 397 4'b0001: result = sum; // subtract 398 4'b0010: result = a & b; // and 399 4'b0011: result = a | b; // or 400 4'b0100: result = a ^ b; // xor 401 4'b0101: result = sum[31] ^ v; // slt 402 4'b0110: result = a << b[4:0]; // sll 403 4'b0111: result = a >> b[4:0]; // srl 404 4'b1000: result = $signed(a) >>> b[4:0]; // srl 405 default: result = 32'bx; 406 endcase 407 408 always_comb 409 case (alucontrol) 410 4'b1001: zero = a < b; // blt and bge 411 default: zero = (result == 32'b0); // beq and bne 412 endcase 413 414 assign v = ~(alucontrol[0] ^ a[31] ^ b[31]) & (a[31] ^ sum[31]) & isAddSub; 415 endmodule