151 lines
6.7 KiB
Systemverilog
151 lines
6.7 KiB
Systemverilog
// *********************************************************************************************
|
|
// Project Version : v1.0
|
|
// Project : [BCDC] Microtec Academy Course: Building a RISC-V CPU with SystemVerilog
|
|
// -----
|
|
// Copyright (c) : 2025 Fraunhofer IIS, Department IDS
|
|
// Created : 15.Oct.2025 by Hussein Elzomor
|
|
// Last Modified : 23.Oct.2025 by Hussein Elzomor [commit 2f8f03d]
|
|
// -----
|
|
// HISTORY : Date By Comments
|
|
// ----------- --------- -------------------------------------------------
|
|
// *********************************************************************************************
|
|
|
|
|
|
|
|
`timescale 1ns/1ns
|
|
|
|
module decoder_tb ();
|
|
|
|
// local Parameters
|
|
localparam MEM_SIZE = 37;
|
|
localparam REG_FILE_SIZE = 32;
|
|
|
|
// local signals
|
|
logic clk;
|
|
int counter;
|
|
logic[31:0] mem [MEM_SIZE-1:0];
|
|
logic[31:0] regFile [REG_FILE_SIZE-1:0];
|
|
// PC
|
|
logic[31:0] CurrentPC;
|
|
logic[31:0] JumpOrBranchPC;
|
|
logic JumpOrBranch;
|
|
logic[31:0] NextPC;
|
|
// Memory
|
|
logic[31:0] DAddr;
|
|
logic[31:0] WData;
|
|
logic[31:0] RData;
|
|
logic[31:0] Instruction;
|
|
logic WrMem;
|
|
logic[1:0] DWidth;
|
|
// Register File;
|
|
logic[4:0] Rs1;
|
|
logic[4:0] Rs2;
|
|
logic[4:0] Rd;
|
|
logic[31:0] RRs1;
|
|
logic[31:0] RRs2;
|
|
logic[31:0] WRd;
|
|
logic WrReg;
|
|
// Protection
|
|
logic Illegal;
|
|
|
|
// Toplevel instance (DUT)
|
|
decoder u_decoder (
|
|
// PC
|
|
.CurrentPC(CurrentPC),
|
|
.JumpOrBranchPC(JumpOrBranchPC),
|
|
.JumpOrBranch(JumpOrBranch),
|
|
// Memory
|
|
.DAddr(DAddr),
|
|
.WData(WData),
|
|
.RData(RData),
|
|
.Instruction(Instruction),
|
|
.WrMem(WrMem),
|
|
.DWidth(DWidth),
|
|
// Register File
|
|
.Rs1(Rs1),
|
|
.Rs2(Rs2),
|
|
.Rd(Rd),
|
|
.RRs1(RRs1),
|
|
.RRs2(RRs2),
|
|
.WRd(WRd),
|
|
.WrReg(WrReg),
|
|
// Protection
|
|
.Illegal(Illegal)
|
|
);
|
|
|
|
// Clock generation
|
|
always begin
|
|
clk = ~clk; #1;
|
|
end
|
|
|
|
// Load a new instruction every cycle
|
|
always_ff @(posedge clk) begin: increment_instruction_and_print_info
|
|
if (counter < MEM_SIZE) begin
|
|
if (counter > 0) printInfo();
|
|
Instruction = mem[counter++];
|
|
end
|
|
end
|
|
|
|
// Return the value of the RegFile
|
|
always_comb begin: reg_file_assignment
|
|
RRs1 = regFile[Rs1];
|
|
RRs2 = regFile[Rs2];
|
|
end
|
|
|
|
// Initialize and run simulation
|
|
initial begin
|
|
dumpWave("wave.vcd");
|
|
loadMem("decoder.hex");
|
|
clk = 1;
|
|
counter = 0;
|
|
CurrentPC = 32'hdeadbeef;
|
|
RData = 32'hbeefdead;
|
|
for(int i=0; i<REG_FILE_SIZE; i++) begin
|
|
regFile[i] = i;
|
|
end
|
|
while (counter < MEM_SIZE) #1;
|
|
printInfo();
|
|
#1 $finish;
|
|
end
|
|
|
|
// Functions
|
|
// Wave Dump Helper Task
|
|
task dumpWave(string fileName);
|
|
// Open wave file and dump all signals (2D arrays not included)
|
|
$display("\nTime = %0dns \t : Opening wave file '%s'", $time, fileName);
|
|
$dumpfile(fileName);
|
|
$display("Time = %0dns \t : Dumping all %s signals in wave file (2D arrays not included)", $time, "decoder_tb");
|
|
$dumpvars(0, decoder_tb);
|
|
endtask: dumpWave
|
|
|
|
// Load hex file into memory
|
|
task loadMem (string fileName);
|
|
$display("\nTime = %0dns \t : Loading '%s' into Memory", $time, fileName);
|
|
$readmemh(fileName, mem);
|
|
endtask: loadMem
|
|
|
|
// Print decoder signals
|
|
task printInfo();
|
|
$displayh("\n(cycle %0d) Decoder (I/O) \tDecoder (Internal Signals) \tALU" , counter );
|
|
$displayh(" -------------------------- \t--------------------------------------------- \t---------------------" );
|
|
$displayh(" CurrentPC : 0x%h OpCode : 0b%b aluOp : 0b%b" , CurrentPC , u_decoder.theOp , u_decoder.aluOp );
|
|
$displayh(" JumpOrBranchPC: 0x%h theFunct3: 0b%b aluNegAr : 0b%b" , JumpOrBranchPC, u_decoder.theFunct3, u_decoder.aluNegAr );
|
|
$displayh(" JumpOrBranch : 0b%b \ttheFunct7: 0b%b aluBypass: 0b%b", JumpOrBranch , u_decoder.theFunct7, u_decoder.aluBypass);
|
|
$displayh(" DAddr : 0x%h i_imm : 0b%b op1 : 0x%h" , DAddr , u_decoder.i_imm , u_decoder.op1 );
|
|
$displayh(" WData : 0x%h s_imm : 0b%b op2 : 0x%h" , WData , u_decoder.s_imm , u_decoder.op2 );
|
|
$displayh(" RData : 0x%h b_imm : 0b%b result : 0x%h" , RData , u_decoder.b_imm , u_decoder.result );
|
|
$displayh(" Instruction : 0x%h u_imm : 0b%b eqFlag : 0b%b" , Instruction , u_decoder.u_imm , u_decoder.eqFlag );
|
|
$displayh(" WrMem : 0b%b \tj_imm : 0b%b" , WrMem , u_decoder.j_imm );
|
|
$displayh(" DWidth : 0b%b" , DWidth );
|
|
$displayh(" Rs1 : %0d " , Rs1 );
|
|
$displayh(" Rs2 : %0d " , Rs2 );
|
|
$displayh(" Rd : 0x%h" , Rd );
|
|
$displayh(" RRs1 : %0d " , RRs1 );
|
|
$displayh(" RRs2 : %0d " , RRs2 );
|
|
$displayh(" WRd : 0x%h" , WRd );
|
|
$displayh(" WrReg : 0b%b" , WrReg );
|
|
$displayh(" Illegal : 0b%b" , Illegal );
|
|
endtask: printInfo
|
|
|
|
endmodule
|