mirror of
				https://github.com/openhwgroup/cvw
				synced 2025-02-11 06:05:49 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			400 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Systemverilog
		
	
	
	
	
	
			
		
		
	
	
			400 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Systemverilog
		
	
	
	
	
	
| ///////////////////////////////////////////
 | |
| // riscvsingle.sv
 | |
| //
 | |
| // Written: David_Harris@hmc.edu 9 January 2021
 | |
| // Modified: 
 | |
| //
 | |
| // Purpose: Simplified Single Cycle RISC-V Processor
 | |
| //          Adapted from DDCA RISC-V Edition
 | |
| //          Modified to match partitioning in RISC-V SoC Design
 | |
| // 
 | |
| // A component of the Wally configurable RISC-V project.
 | |
| // 
 | |
| // Copyright (C) 2021 Harvey Mudd College & Oklahoma State University
 | |
| //
 | |
| // MIT LICENSE
 | |
| // Permission is hereby granted, free of charge, to any person obtaining a copy of this 
 | |
| // software and associated documentation files (the "Software"), to deal in the Software 
 | |
| // without restriction, including without limitation the rights to use, copy, modify, merge, 
 | |
| // publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons 
 | |
| // to whom the Software is furnished to do so, subject to the following conditions:
 | |
| //
 | |
| //   The above copyright notice and this permission notice shall be included in all copies or 
 | |
| //   substantial portions of the Software.
 | |
| //
 | |
| //   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 
 | |
| //   INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 
 | |
| //   PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 
 | |
| //   BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 
 | |
| //   TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE 
 | |
| //   OR OTHER DEALINGS IN THE SOFTWARE.
 | |
| ////////////////////////////////////////////////////////////////////////////////////////////////
 | |
| 
 | |
| 
 | |
| // run 210
 | |
| // Expect simulator to print "Simulation succeeded"
 | |
| // when the value 25 (0x19) is written to address 100 (0x64)
 | |
| 
 | |
| // Single-cycle implementation of RISC-V (RV32I)
 | |
| // User-level Instruction Set Architecture V2.2 
 | |
| // Implements a subset of the base integer instructions:
 | |
| //    lw, sw
 | |
| //    add, sub, and, or, slt
 | |
| //    addi, andi, ori, slti
 | |
| //    beq
 | |
| //    jal
 | |
| // Exceptions, traps, and interrupts not implemented
 | |
| // little-endian memory
 | |
| 
 | |
| // 31 32-bit registers x1-x31, x0 hardwired to 0
 | |
| // R-Type instructions
 | |
| //   add, sub, and, or, slt
 | |
| //   INSTR rd, rs1, rs2
 | |
| //   Instr[31:25] = funct7 (funct7b5 & opb5 = 1 for sub, 0 for others)
 | |
| //   Instr[24:20] = rs2
 | |
| //   Instr[19:15] = rs1
 | |
| //   Instr[14:12] = funct3
 | |
| //   Instr[11:7]  = rd
 | |
| //   Instr[6:0]   = opcode
 | |
| // I-Type Instructions
 | |
| //   lw, I-type ALU (addi, andi, ori, slti)
 | |
| //   lw:         INSTR rd, imm(rs1)
 | |
| //   I-type ALU: INSTR rd, rs1, imm (12-bit signed)
 | |
| //   Instr[31:20] = imm[11:0]
 | |
| //   Instr[24:20] = rs2
 | |
| //   Instr[19:15] = rs1
 | |
| //   Instr[14:12] = funct3
 | |
| //   Instr[11:7]  = rd
 | |
| //   Instr[6:0]   = opcode
 | |
| // S-Type Instruction
 | |
| //   sw rs2, imm(rs1) (store rs2 into address specified by rs1 + immm)
 | |
| //   Instr[31:25] = imm[11:5] (offset[11:5])
 | |
| //   Instr[24:20] = rs2 (src)
 | |
| //   Instr[19:15] = rs1 (base)
 | |
| //   Instr[14:12] = funct3
 | |
| //   Instr[11:7]  = imm[4:0]  (offset[4:0])
 | |
| //   Instr[6:0]   = opcode
 | |
| // B-Type Instruction
 | |
| //   beq rs1, rs2, imm (PCTarget = PC + (signed imm x 2))
 | |
| //   Instr[31:25] = imm[12], imm[10:5]
 | |
| //   Instr[24:20] = rs2
 | |
| //   Instr[19:15] = rs1
 | |
| //   Instr[14:12] = funct3
 | |
| //   Instr[11:7]  = imm[4:1], imm[11]
 | |
| //   Instr[6:0]   = opcode
 | |
| // J-Type Instruction
 | |
| //   jal rd, imm  (signed imm is multiplied by 2 and added to PC, rd = PC+4)
 | |
| //   Instr[31:12] = imm[20], imm[10:1], imm[11], imm[19:12]
 | |
| //   Instr[11:7]  = rd
 | |
| //   Instr[6:0]   = opcode
 | |
| 
 | |
| //   Instruction  opcode    funct3    funct7
 | |
| //   add          0110011   000       0000000
 | |
| //   sub          0110011   000       0100000
 | |
| //   and          0110011   111       0000000
 | |
| //   or           0110011   110       0000000
 | |
| //   slt          0110011   010       0000000
 | |
| //   addi         0010011   000       immediate
 | |
| //   andi         0010011   111       immediate
 | |
| //   ori          0010011   110       immediate
 | |
| //   slti         0010011   010       immediate
 | |
| //   beq          1100011   000       immediate
 | |
| //   lw	          0000011   010       immediate
 | |
| //   sw           0100011   010       immediate
 | |
| //   jal          1101111   immediate immediate
 | |
| 
 | |
| 
 | |
| /* verilator lint_on UNUSED */
 | |
| 
 | |
| /* verilator lint_off COMBDLY */ 
 | |
| /* verilator lint_off INITIALDLY */ 
 | |
| /* verilator lint_off STMTDLY */ 
 | |
| 
 | |
| module testbench();
 | |
|   logic        clk;
 | |
|   logic        reset;
 | |
|   logic [31:0] WriteData, IEUAdr;
 | |
|   logic        MemWrite;
 | |
| 
 | |
|   // instantiate device to be tested
 | |
|   riscvsinglecore dut(clk, reset, WriteData, IEUAdr, MemWrite);
 | |
|   
 | |
|   // initialize test
 | |
|   initial begin
 | |
|       reset <= 1; # 22; reset <= 0;
 | |
|   end
 | |
| 
 | |
|   // generate clock to sequence tests
 | |
|   always begin
 | |
|       clk <= 1; # 5; clk <= 0; # 5;
 | |
|   end
 | |
| 
 | |
|   // check results
 | |
|   always @(negedge clk) begin
 | |
|       if(MemWrite) begin
 | |
|         if(IEUAdr === 100 & WriteData === 25) begin
 | |
|           $display("Simulation succeeded");
 | |
|           $stop;
 | |
|         end else if (IEUAdr !== 96) begin
 | |
|           $display("Simulation failed");
 | |
|           $stop;
 | |
|         end
 | |
|       end
 | |
|   end
 | |
| endmodule
 | |
| 
 | |
| module riscvsinglecore(
 | |
|   input  logic        clk, reset, 
 | |
|   output logic [31:0] WriteData, IEUAdr, 
 | |
|   output logic        MemWrite);
 | |
| 
 | |
|   logic [31:0] PC, PCPlus4, Instr, ReadData;
 | |
|   logic        PCSrc;
 | |
| 
 | |
|   ifu ifu(.clk, .reset, .PCSrc, .IEUAdr, .Instr, .PC, .PCPlus4);
 | |
|   ieu ieu(.clk, .reset, .Instr, .PC, .PCPlus4, .PCSrc, .MemWrite, .IEUAdr, .WriteData, .ReadData);
 | |
|   lsu lsu(.clk, .MemWrite, .IEUAdr, .WriteData, .ReadData);
 | |
| endmodule
 | |
| 
 | |
| module ifu(
 | |
|   input  logic        clk, reset,
 | |
|   input  logic        PCSrc,
 | |
|   input  logic [31:0] IEUAdr, 
 | |
|   output logic [31:0] Instr, PC, PCPlus4);
 | |
| 
 | |
|   logic [31:0] PCNext;
 | |
| 
 | |
|   // next PC logic
 | |
|   flopr #(32) pcreg(clk, reset, PCNext, PC); 
 | |
|   adder       pcadd4(PC, 32'd4, PCPlus4);
 | |
|   mux2 #(32)  pcmux(PCPlus4, IEUAdr, PCSrc, PCNext);
 | |
|   irom        irom(PC, Instr);
 | |
| endmodule
 | |
| 
 | |
| module irom(input  logic [31:0] a,
 | |
|             output logic [31:0] rd);
 | |
| 
 | |
|   logic [31:0] RAM[63:0];
 | |
| 
 | |
|   initial
 | |
|       $readmemh("riscvtest.memfile",RAM);
 | |
| 
 | |
|   assign rd = RAM[a[7:2]]; // word aligned
 | |
| endmodule
 | |
| 
 | |
| module ieu(
 | |
|   input  logic        clk, reset,
 | |
|   input  logic [31:0] Instr,
 | |
|   input  logic [31:0] PC, PCPlus4,
 | |
|   output logic        PCSrc, MemWrite,
 | |
|   output logic [31:0] IEUAdr, WriteData,
 | |
|   input  logic [31:0] ReadData);
 | |
| 
 | |
|   logic       RegWrite, Jump, Eq, ALUResultSrc, ResultSrc;
 | |
|   logic [1:0] ALUSrc, ImmSrc;
 | |
|   logic [1:0] ALUControl;
 | |
| 
 | |
|   controller c(.Op(Instr[6:0]), .Funct3(Instr[14:12]), .Funct7b5(Instr[30]), .Eq,
 | |
|                .ALUResultSrc, .ResultSrc, .MemWrite, .PCSrc,
 | |
|                .ALUSrc, .RegWrite, .ImmSrc, .ALUControl);
 | |
|   datapath dp(.clk, .reset, .Funct3(Instr[14:12]),  
 | |
|               .ALUResultSrc, .ResultSrc, .ALUSrc, .RegWrite, .ImmSrc, .ALUControl, .Eq,
 | |
|               .PC, .PCPlus4, .Instr, .IEUAdr, .WriteData, .ReadData);
 | |
| endmodule
 | |
| 
 | |
| module controller(
 | |
|   input  logic [6:0] Op,
 | |
|   input  logic       Eq,
 | |
|   input  logic [2:0] Funct3,
 | |
|   input  logic       Funct7b5,
 | |
|   output logic       ALUResultSrc,
 | |
|   output logic       ResultSrc,
 | |
|   output logic       MemWrite,
 | |
|   output logic       PCSrc, 
 | |
|   output logic       RegWrite, 
 | |
|   output logic [1:0] ALUSrc, ImmSrc,
 | |
|   output logic [1:0] ALUControl); 
 | |
| 
 | |
|   logic       Branch, Jump;
 | |
|   logic       Sub, ALUOp;
 | |
| 
 | |
|   logic [10:0] controls;
 | |
| 
 | |
|   // Main decoder
 | |
|   always_comb
 | |
|     case(Op)
 | |
|     // RegWrite_ImmSrc_ALUSrc_ALUOp_ALUResultSrc_MemWrite_ResultSrc_Branch_Jump
 | |
|       7'b0000011: controls = 11'b1_00_01_0_0_0_1_0_0; // lw
 | |
|       7'b0100011: controls = 11'b0_01_01_0_0_1_0_0_0; // sw
 | |
|       7'b0110011: controls = 11'b1_xx_00_1_0_0_0_0_0; // R-type 
 | |
|       7'b0010011: controls = 11'b1_00_01_1_0_0_0_0_0; // I-type ALU
 | |
|       7'b1100011: controls = 11'b0_10_11_0_0_0_0_1_0; // beq
 | |
|       7'b1101111: controls = 11'b1_11_11_0_1_0_0_0_1; // jal
 | |
|       default:    controls = 11'bx_xx_xx_x_x_x_x_x_x; // non-implemented instruction
 | |
|     endcase
 | |
|   
 | |
|   assign {RegWrite, ImmSrc, ALUSrc, ALUOp, ALUResultSrc, MemWrite,
 | |
|           ResultSrc, Branch, Jump} = controls;
 | |
| 
 | |
|   // ALU Control Logic
 | |
|   assign Sub = ALUOp & ((Funct3 == 3'b000) & Funct7b5 & Op[5] | (Funct3 == 3'b010));  // subtract or SLT
 | |
|   assign ALUControl = {Sub, ALUOp};
 | |
| 
 | |
|   // PCSrc logic
 | |
|   assign PCSrc = Branch & Eq | Jump;
 | |
| endmodule
 | |
| 
 | |
| module datapath(
 | |
|   input  logic        clk, reset,
 | |
|   input  logic [2:0]  Funct3,
 | |
|   input  logic        ALUResultSrc, ResultSrc, 
 | |
|   input  logic [1:0]  ALUSrc,
 | |
|   input  logic        RegWrite,
 | |
|   input  logic [1:0]  ImmSrc,
 | |
|   input  logic [1:0]  ALUControl,
 | |
|   output logic        Eq,
 | |
|   input  logic [31:0] PC, PCPlus4,
 | |
|   input  logic [31:0] Instr,
 | |
|   output logic [31:0] IEUAdr, WriteData,
 | |
|   input  logic [31:0] ReadData);
 | |
| 
 | |
|   logic [31:0] ImmExt;
 | |
|   logic [31:0] R1, R2, SrcA, SrcB;
 | |
|   logic [31:0] ALUResult, IEUResult, Result;
 | |
| 
 | |
|   // register file logic
 | |
|   regfile     rf(.clk, .WE3(RegWrite), .A1(Instr[19:15]), .A2(Instr[24:20]), 
 | |
|                  .A3(Instr[11:7]), .WD3(Result), .RD1(R1), .RD2(R2));
 | |
|   extend      ext(.Instr(Instr[31:7]), .ImmSrc, .ImmExt);
 | |
| 
 | |
|   // ALU logic
 | |
|   cmp         cmp(.R1, .R2, .Eq);
 | |
|   mux2 #(32)  srcamux(R1, PC, ALUSrc[1], SrcA);
 | |
|   mux2 #(32)  srcbmux(R2, ImmExt, ALUSrc[0], SrcB);
 | |
|   alu         alu(.SrcA, .SrcB, .ALUControl, .Funct3, .ALUResult, .IEUAdr);
 | |
|   mux2 #(32)  ieuresultmux(ALUResult, PCPlus4, ALUResultSrc, IEUResult);
 | |
|   mux2 #(32)  resultmux(IEUResult, ReadData, ResultSrc, Result);
 | |
|   assign WriteData = R2;
 | |
| endmodule
 | |
| 
 | |
| module regfile(
 | |
|   input  logic        clk, 
 | |
|   input  logic        WE3, 
 | |
|   input  logic [ 4:0] A1, A2, A3, 
 | |
|   input  logic [31:0] WD3, 
 | |
|   output logic [31:0] RD1, RD2);
 | |
| 
 | |
|   logic [31:0] rf[31:1];
 | |
| 
 | |
|   // three ported register file
 | |
|   // read two ports combinationally (A1/RD1, A2/RD2)
 | |
|   // write third port on rising edge of clock (A3/WD3/WE3)
 | |
|   // register 0 hardwired to 0
 | |
| 
 | |
|   always_ff @(posedge clk)
 | |
|     if (WE3) rf[A3] <= WD3;	
 | |
| 
 | |
|   assign RD1 = (A1 != 0) ? rf[A1] : 0;
 | |
|   assign RD2 = (A2 != 0) ? rf[A2] : 0;
 | |
| endmodule
 | |
| 
 | |
| module extend(
 | |
|   input  logic [31:7] Instr,
 | |
|   input  logic [1:0]  ImmSrc,
 | |
|   output logic [31:0] ImmExt);
 | |
|  
 | |
|   always_comb
 | |
|     case(ImmSrc) 
 | |
|                // I-type 
 | |
|       2'b00:   ImmExt = {{20{Instr[31]}}, Instr[31:20]};  
 | |
|                // S-type (stores)
 | |
|       2'b01:   ImmExt = {{20{Instr[31]}}, Instr[31:25], Instr[11:7]}; 
 | |
|                // B-type (branches)
 | |
|       2'b10:   ImmExt = {{20{Instr[31]}}, Instr[7], Instr[30:25], Instr[11:8], 1'b0}; 
 | |
|                // J-type (jal)
 | |
|       2'b11:   ImmExt = {{12{Instr[31]}}, Instr[19:12], Instr[20], Instr[30:21], 1'b0}; 
 | |
|       default: ImmExt = 32'bx; // undefined
 | |
|     endcase             
 | |
| endmodule
 | |
| 
 | |
| module cmp(
 | |
|   input  logic [31:0] R1, R2,
 | |
|   output logic        Eq
 | |
| );
 | |
|  
 | |
|    assign Eq = (R1 == R2);
 | |
| endmodule
 | |
|   
 | |
| 
 | |
| module alu(
 | |
|   input  logic [31:0] SrcA, SrcB,
 | |
|   input  logic [1:0]  ALUControl,
 | |
|   input  logic [2:0]  Funct3,
 | |
|   output logic [31:0] ALUResult, IEUAdr);
 | |
| 
 | |
|   logic [31:0] CondInvb, Sum, SLT;
 | |
|   logic        ALUOp, Sub, Overflow, Neg, LT;       
 | |
|   logic [2:0]  ALUFunct;
 | |
| 
 | |
|   assign {Sub, ALUOp} = ALUControl;
 | |
| 
 | |
|   // Add or subtract
 | |
|   assign CondInvb = Sub ? ~SrcB : SrcB;
 | |
|   assign Sum = SrcA + CondInvb + Sub;
 | |
|   assign IEUAdr = Sum; // Send this out to IFU and LSU
 | |
| 
 | |
|   // Set less than based on subtraction result
 | |
|   assign Overflow = (SrcA[31] ^ SrcB[31]) & (SrcA[31] ^ Sum[31]);
 | |
|   assign Neg  = Sum[31];
 | |
|   assign LT = Neg ^ Overflow;
 | |
|   assign SLT = {31'b0, LT};
 | |
|  
 | |
|   assign ALUFunct = Funct3 & {3{ALUOp}}; // Force ALUFunct to 0 to Add when ALUOp = 0
 | |
|   always_comb
 | |
|     case (ALUFunct)
 | |
|       3'b000:  ALUResult = Sum;          // add or sub
 | |
|       3'b010:  ALUResult = SLT;          // slt
 | |
|       3'b110:  ALUResult = SrcA | SrcB;  // or 
 | |
|       3'b111:  ALUResult = SrcA & SrcB;  // and
 | |
|       default: ALUResult = 'x;
 | |
|     endcase
 | |
| endmodule
 | |
| 
 | |
| module lsu(
 | |
|   input  logic        clk, MemWrite,
 | |
|   input  logic [31:0] IEUAdr, WriteData,
 | |
|   output logic [31:0] ReadData);
 | |
| 
 | |
|   logic [31:0] RAM[63:0];
 | |
| 
 | |
|   assign ReadData = RAM[IEUAdr[7:2]]; // word aligned
 | |
| 
 | |
|   always_ff @(posedge clk)
 | |
|     if (MemWrite) RAM[IEUAdr[7:2]] <= WriteData;
 | |
| endmodule
 | |
| 
 | |
| module flopr #(parameter WIDTH = 8) (
 | |
|   input  logic             clk, reset,
 | |
|   input  logic [WIDTH-1:0] d, 
 | |
|   output logic [WIDTH-1:0] q);
 | |
| 
 | |
|   always_ff @(posedge clk, posedge reset)
 | |
|     if (reset) q <= 0;
 | |
|     else       q <= d;
 | |
| endmodule
 | |
| 
 | |
| module mux2 #(parameter WIDTH = 8) (
 | |
|   input  logic [WIDTH-1:0] d0, d1, 
 | |
|   input  logic             s, 
 | |
|   output logic [WIDTH-1:0] y);
 | |
| 
 | |
|   assign y = s ? d1 : d0; 
 | |
| endmodule
 | |
| 
 | |
| module adder(input  [31:0] a, b,
 | |
|              output [31:0] y);
 | |
| 
 | |
|   assign y = a + b;
 | |
| endmodule
 | |
| 
 |