diff options
Diffstat (limited to 'riscvsingle.sv')
| -rw-r--r-- | riscvsingle.sv | 390 |
1 files changed, 390 insertions, 0 deletions
diff --git a/riscvsingle.sv b/riscvsingle.sv new file mode 100644 index 0000000..f536718 --- /dev/null +++ b/riscvsingle.sv | |||
| @@ -0,0 +1,390 @@ | |||
| 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 | endmodule | ||
| 104 | |||
| 105 | // ======================================================================= | ||
| 106 | // NEW STUFF ABOUT MEMORIES - MUST REVIEW FIRST | ||
| 107 | // ======================================================================= | ||
| 108 | |||
| 109 | module regfile(input logic clk, | ||
| 110 | input logic we3, | ||
| 111 | input logic [ 4:0] a1, a2, a3, | ||
| 112 | input logic [31:0] wd3, | ||
| 113 | output logic [31:0] rd1, rd2); | ||
| 114 | |||
| 115 | logic [31:0] rf[31:0]; | ||
| 116 | |||
| 117 | // three ported register file | ||
| 118 | // read two ports combinationally (A1/RD1, A2/RD2) | ||
| 119 | // write third port on rising edge of clock (A3/WD3/WE3) | ||
| 120 | // register 0 hardwired to 0 | ||
| 121 | |||
| 122 | always_ff @(posedge clk) | ||
| 123 | if (we3) rf[a3] <= wd3; | ||
| 124 | |||
| 125 | assign rd1 = (a1 != 0) ? rf[a1] : 0; | ||
| 126 | assign rd2 = (a2 != 0) ? rf[a2] : 0; | ||
| 127 | endmodule | ||
| 128 | |||
| 129 | module imem(input logic [31:0] a, | ||
| 130 | output logic [31:0] rd); | ||
| 131 | |||
| 132 | logic [31:0] ROM[63:0]; | ||
| 133 | |||
| 134 | // Initialize the program memory | ||
| 135 | // Simulator : ok | ||
| 136 | // Hardware : For FPGA ok, non-FPGA we need a 3rd party solution to program the FLASH memory (ROM) | ||
| 137 | initial | ||
| 138 | $readmemh("C:\\Users\\onur\\Desktop\\CE_Lab2\\CEL_PROJECT\\riscvtest_rom_image.txt", ROM); | ||
| 139 | |||
| 140 | assign rd = ROM[a[31:2]]; // word aligned | ||
| 141 | endmodule | ||
| 142 | |||
| 143 | // This part is modified by Dr. Toker | ||
| 144 | module dmem(input logic clk, we, | ||
| 145 | input logic [31:0] a, wd, | ||
| 146 | output logic [31:0] rd, | ||
| 147 | input logic [ 7:0] my_sw, | ||
| 148 | output logic [31:0] my_rd); | ||
| 149 | |||
| 150 | logic [31:0] RAM[127:0]; | ||
| 151 | |||
| 152 | assign rd = RAM[a[31:2]]; // word aligned | ||
| 153 | |||
| 154 | always_ff @(posedge clk) | ||
| 155 | begin | ||
| 156 | if (we) RAM[a[31:2]] <= wd; | ||
| 157 | |||
| 158 | // Used only for simulation, does not correspond to ANY hardware | ||
| 159 | if (we) | ||
| 160 | $display("Write RAM[%08x]=%08x at %t", a[31:2], wd, $time); | ||
| 161 | else | ||
| 162 | $display("Read RAM[%08x]=%08x at %t", a[31:2], rd, $time); | ||
| 163 | |||
| 164 | end | ||
| 165 | |||
| 166 | assign my_rd = RAM[my_sw[7:2]]; | ||
| 167 | |||
| 168 | // Initialize the program memory | ||
| 169 | // Simulator : ok | ||
| 170 | // Hardware : For FPGA ok, non-FPGA we need a 3rd party solution to program the DATA memory (RAM) | ||
| 171 | initial | ||
| 172 | $readmemh("C:\\Users\\onur\\Desktop\\CE_Lab2\\CEL_PROJECT\\riscvtest_ram_image.txt", RAM); | ||
| 173 | |||
| 174 | endmodule | ||
| 175 | |||
| 176 | module flopr #(parameter WIDTH = 8) | ||
| 177 | (input logic clk, reset, | ||
| 178 | input logic [WIDTH-1:0] d, | ||
| 179 | output logic [WIDTH-1:0] q); | ||
| 180 | |||
| 181 | always_ff @(posedge clk, posedge reset) | ||
| 182 | if (reset) q <= 0; | ||
| 183 | else q <= d; | ||
| 184 | endmodule | ||
| 185 | |||
| 186 | // ======================================================================= | ||
| 187 | // OLD STUFF - Component Instantiation or New Combinatorial Designs | ||
| 188 | // ======================================================================= | ||
| 189 | |||
| 190 | module riscvsingle(input logic clk, reset, | ||
| 191 | output logic [31:0] PC, | ||
| 192 | input logic [31:0] Instr, | ||
| 193 | output logic MemWrite, | ||
| 194 | output logic [31:0] ALUResult, WriteData, | ||
| 195 | input logic [31:0] ReadData); | ||
| 196 | |||
| 197 | logic ALUSrc, RegWrite, Jump, Zero; | ||
| 198 | logic [1:0] ResultSrc, ImmSrc; | ||
| 199 | logic [2:0] ALUControl; | ||
| 200 | |||
| 201 | controller c(Instr[6:0], Instr[14:12], Instr[30], Zero, | ||
| 202 | ResultSrc, MemWrite, PCSrc, | ||
| 203 | ALUSrc, RegWrite, Jump, | ||
| 204 | ImmSrc, ALUControl); | ||
| 205 | datapath dp(clk, reset, ResultSrc, PCSrc, | ||
| 206 | ALUSrc, RegWrite, | ||
| 207 | ImmSrc, ALUControl, | ||
| 208 | Zero, PC, Instr, | ||
| 209 | ALUResult, WriteData, ReadData); | ||
| 210 | endmodule | ||
| 211 | |||
| 212 | module controller(input logic [6:0] op, | ||
| 213 | input logic [2:0] funct3, | ||
| 214 | input logic funct7b5, | ||
| 215 | input logic Zero, | ||
| 216 | output logic [1:0] ResultSrc, | ||
| 217 | output logic MemWrite, | ||
| 218 | output logic PCSrc, ALUSrc, | ||
| 219 | output logic RegWrite, Jump, | ||
| 220 | output logic [1:0] ImmSrc, | ||
| 221 | output logic [2:0] ALUControl); | ||
| 222 | |||
| 223 | logic [1:0] ALUOp; | ||
| 224 | logic Branch; | ||
| 225 | |||
| 226 | maindec md(op, ResultSrc, MemWrite, Branch, | ||
| 227 | ALUSrc, RegWrite, Jump, ImmSrc, ALUOp); | ||
| 228 | aludec ad(op[5], funct3, funct7b5, ALUOp, ALUControl); | ||
| 229 | |||
| 230 | assign PCSrc = Branch & Zero | Jump; | ||
| 231 | endmodule | ||
| 232 | |||
| 233 | module maindec(input logic [6:0] op, | ||
| 234 | output logic [1:0] ResultSrc, | ||
| 235 | output logic MemWrite, | ||
| 236 | output logic Branch, ALUSrc, | ||
| 237 | output logic RegWrite, Jump, | ||
| 238 | output logic [1:0] ImmSrc, | ||
| 239 | output logic [1:0] ALUOp); | ||
| 240 | |||
| 241 | logic [10:0] controls; | ||
| 242 | |||
| 243 | assign {RegWrite, ImmSrc, ALUSrc, MemWrite, | ||
| 244 | ResultSrc, Branch, ALUOp, Jump} = controls; | ||
| 245 | |||
| 246 | always_comb | ||
| 247 | case(op) | ||
| 248 | // RegWrite_ImmSrc_ALUSrc_MemWrite_ResultSrc_Branch_ALUOp_Jump | ||
| 249 | 7'b0000011: controls = 11'b1_00_1_0_01_0_00_0; // lw | ||
| 250 | 7'b0100011: controls = 11'b0_01_1_1_00_0_00_0; // sw | ||
| 251 | 7'b0110011: controls = 11'b1_xx_0_0_00_0_10_0; // R-type | ||
| 252 | 7'b1100011: controls = 11'b0_10_0_0_00_1_01_0; // beq | ||
| 253 | 7'b0010011: controls = 11'b1_00_1_0_00_0_10_0; // I-type ALU | ||
| 254 | 7'b1101111: controls = 11'b1_11_0_0_10_0_00_1; // jal | ||
| 255 | default: controls = 11'bx_xx_x_x_xx_x_xx_x; // non-implemented instruction | ||
| 256 | endcase | ||
| 257 | endmodule | ||
| 258 | |||
| 259 | module aludec(input logic opb5, | ||
| 260 | input logic [2:0] funct3, | ||
| 261 | input logic funct7b5, | ||
| 262 | input logic [1:0] ALUOp, | ||
| 263 | output logic [2:0] ALUControl); | ||
| 264 | |||
| 265 | logic RtypeSub; | ||
| 266 | assign RtypeSub = funct7b5 & opb5; // TRUE for R-type subtract instruction | ||
| 267 | |||
| 268 | always_comb | ||
| 269 | case(ALUOp) | ||
| 270 | 2'b00: ALUControl = 3'b000; // addition | ||
| 271 | 2'b01: ALUControl = 3'b001; // subtraction | ||
| 272 | default: case(funct3) // R-type or I-type ALU | ||
| 273 | 3'b000: if (RtypeSub) | ||
| 274 | ALUControl = 3'b001; // sub | ||
| 275 | else | ||
| 276 | ALUControl = 3'b000; // add, addi | ||
| 277 | 3'b010: ALUControl = 3'b101; // slt, slti | ||
| 278 | 3'b110: ALUControl = 3'b011; // or, ori | ||
| 279 | 3'b111: ALUControl = 3'b010; // and, andi | ||
| 280 | default: ALUControl = 3'bxxx; // ??? | ||
| 281 | endcase | ||
| 282 | endcase | ||
| 283 | endmodule | ||
| 284 | |||
| 285 | module datapath(input logic clk, reset, | ||
| 286 | input logic [1:0] ResultSrc, | ||
| 287 | input logic PCSrc, ALUSrc, | ||
| 288 | input logic RegWrite, | ||
| 289 | input logic [1:0] ImmSrc, | ||
| 290 | input logic [2:0] ALUControl, | ||
| 291 | output logic Zero, | ||
| 292 | output logic [31:0] PC, | ||
| 293 | input logic [31:0] Instr, | ||
| 294 | output logic [31:0] ALUResult, WriteData, | ||
| 295 | input logic [31:0] ReadData); | ||
| 296 | |||
| 297 | logic [31:0] PCNext, PCPlus4, PCTarget; | ||
| 298 | logic [31:0] ImmExt; | ||
| 299 | logic [31:0] SrcA, SrcB; | ||
| 300 | logic [31:0] Result; | ||
| 301 | |||
| 302 | // next PC logic | ||
| 303 | flopr #(32) pcreg(clk, reset, PCNext, PC); | ||
| 304 | adder pcadd4(PC, 32'd4, PCPlus4); | ||
| 305 | adder pcaddbranch(PC, ImmExt, PCTarget); | ||
| 306 | mux2 #(32) pcmux(PCPlus4, PCTarget, PCSrc, PCNext); | ||
| 307 | |||
| 308 | // register file logic | ||
| 309 | regfile rf(clk, RegWrite, Instr[19:15], Instr[24:20], | ||
| 310 | Instr[11:7], Result, SrcA, WriteData); | ||
| 311 | extend ext(Instr[31:7], ImmSrc, ImmExt); | ||
| 312 | |||
| 313 | // ALU logic | ||
| 314 | mux2 #(32) srcbmux(WriteData, ImmExt, ALUSrc, SrcB); | ||
| 315 | alu alu(SrcA, SrcB, ALUControl, ALUResult, Zero); | ||
| 316 | mux3 #(32) resultmux(ALUResult, ReadData, PCPlus4, ResultSrc, Result); | ||
| 317 | endmodule | ||
| 318 | |||
| 319 | |||
| 320 | module adder(input [31:0] a, b, | ||
| 321 | output [31:0] y); | ||
| 322 | |||
| 323 | assign y = a + b; | ||
| 324 | endmodule | ||
| 325 | |||
| 326 | module extend(input logic [31:7] instr, | ||
| 327 | input logic [1:0] immsrc, | ||
| 328 | output logic [31:0] immext); | ||
| 329 | |||
| 330 | always_comb | ||
| 331 | case(immsrc) | ||
| 332 | // I-type | ||
| 333 | 2'b00: immext = {{20{instr[31]}}, instr[31:20]}; | ||
| 334 | // S-type (stores) | ||
| 335 | 2'b01: immext = {{20{instr[31]}}, instr[31:25], instr[11:7]}; | ||
| 336 | // B-type (branches) | ||
| 337 | 2'b10: immext = {{20{instr[31]}}, instr[7], instr[30:25], instr[11:8], 1'b0}; | ||
| 338 | // J-type (jal) | ||
| 339 | 2'b11: immext = {{12{instr[31]}}, instr[19:12], instr[20], instr[30:21], 1'b0}; | ||
| 340 | default: immext = 32'bx; // undefined | ||
| 341 | endcase | ||
| 342 | endmodule | ||
| 343 | |||
| 344 | module mux2 #(parameter WIDTH = 8) | ||
| 345 | (input logic [WIDTH-1:0] d0, d1, | ||
| 346 | input logic s, | ||
| 347 | output logic [WIDTH-1:0] y); | ||
| 348 | |||
| 349 | assign y = s ? d1 : d0; | ||
| 350 | endmodule | ||
| 351 | |||
| 352 | module mux3 #(parameter WIDTH = 8) | ||
| 353 | (input logic [WIDTH-1:0] d0, d1, d2, | ||
| 354 | input logic [1:0] s, | ||
| 355 | output logic [WIDTH-1:0] y); | ||
| 356 | |||
| 357 | assign y = s[1] ? d2 : (s[0] ? d1 : d0); | ||
| 358 | endmodule | ||
| 359 | |||
| 360 | module alu(input logic [31:0] a, b, | ||
| 361 | input logic [2:0] alucontrol, | ||
| 362 | output logic [31:0] result, | ||
| 363 | output logic zero); | ||
| 364 | |||
| 365 | logic [31:0] condinvb, sum; | ||
| 366 | logic v; // overflow | ||
| 367 | logic isAddSub; // true when is add or subtract operation | ||
| 368 | |||
| 369 | assign condinvb = alucontrol[0] ? ~b : b; | ||
| 370 | assign sum = a + condinvb + alucontrol[0]; | ||
| 371 | assign isAddSub = ~alucontrol[2] & ~alucontrol[1] | | ||
| 372 | ~alucontrol[1] & alucontrol[0]; | ||
| 373 | |||
| 374 | always_comb | ||
| 375 | case (alucontrol) | ||
| 376 | 3'b000: result = sum; // add | ||
| 377 | 3'b001: result = sum; // subtract | ||
| 378 | 3'b010: result = a & b; // and | ||
| 379 | 3'b011: result = a | b; // or | ||
| 380 | 3'b100: result = a ^ b; // xor | ||
| 381 | 3'b101: result = sum[31] ^ v; // slt | ||
| 382 | 3'b110: result = a << b[4:0]; // sll | ||
| 383 | 3'b111: result = a >> b[4:0]; // srl | ||
| 384 | default: result = 32'bx; | ||
| 385 | endcase | ||
| 386 | |||
| 387 | assign zero = (result == 32'b0); | ||
| 388 | assign v = ~(alucontrol[0] ^ a[31] ^ b[31]) & (a[31] ^ sum[31]) & isAddSub; | ||
| 389 | |||
| 390 | endmodule | ||
