Initial commit

This commit is contained in:
muellerlu
2026-05-29 10:19:13 +02:00
commit fedfd92270
726 changed files with 542654 additions and 0 deletions
+112
View File
@@ -0,0 +1,112 @@
// *********************************************************************************************
// 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 Bomin Kim
// Last Modified : 23.Oct.2025 by Bomin Kim [commit 2f8f03d]
// -----
// HISTORY : Date By Comments
// ----------- --------- -------------------------------------------------
// *********************************************************************************************
`timescale 1ns/1ns
module alu_tb();
// Local Signals
logic[2:0] aluOp;
logic aluNegAr;
logic aluBypass;
logic[31:0] op1;
logic[31:0] op2;
logic[31:0] result;
logic eqFlag;
// Toplevel instance (DUT)
alu u_alu (
.aluOp(aluOp),
.aluNegAr(aluNegAr),
.aluBypass(aluBypass),
.op1(op1),
.op2(op2),
.result(result),
.eqFlag(eqFlag)
);
// list of aluOp
localparam logic[2:0] f3add = 3'b000;
localparam logic[2:0] f3sl = 3'b001;
localparam logic[2:0] f3slt = 3'b010;
localparam logic[2:0] f3sltU = 3'b011;
localparam logic[2:0] f3xor = 3'b100;
localparam logic[2:0] f3sr = 3'b101;
localparam logic[2:0] f3or = 3'b110;
localparam logic[2:0] f3and = 3'b111;
// Initialize and run simulation
initial begin
dumpWave("wave.vcd");
// Initialize inputs
aluOp = 0;
aluNegAr = 0;
aluBypass = 0;
op1 = 0;
op2 = 0;
#10
// Set op1 and op2
op1 = 32'hDEAD_BEEF; op2 = 32'h0000_0001; #70
$display("\nTime = %0dns \t : op1 = %h, op2 = %h", $time, op1, op2);
$display("\nTime = %0dns \t : Is op1 and op2 equal?; eqFlag = %d", $time, eqFlag);
aluBypass = 1; #70
$display("\nTime = %0dns \t : AluBypass is set; result = %h", $time, result);
aluBypass = 0; aluOp = f3add; #70
$display("\nTime = %0dns \t : Alu operates addition; result = %h", $time, result);
aluNegAr = 1; #70
$display("\nTime = %0dns \t : Alu operates subtraction; result = %h", $time, result);
aluNegAr = 0; aluOp = f3sl; #70
$display("\nTime = %0dns \t : Alu operates shift left; result = %h", $time, result);
aluOp = f3slt; #70
$display("\nTime = %0dns \t : Alu operates set less than; result = %h", $time, result);
aluOp = f3sltU; #70
$display("\nTime = %0dns \t : Alu operates set less than (unsigned); result = %h", $time, result);
aluOp = f3xor; #70
$display("\nTime = %0dns \t : Alu operates bit-wise XOR; result = %h", $time, result);
aluOp = f3sr; aluNegAr = 1; #70
$display("\nTime = %0dns \t : Alu operates arithmetic right shift; result = %h", $time, result);
aluNegAr = 0; #70
$display("\nTime = %0dns \t : Alu operates logical right shift; result = %h", $time, result);
aluOp = f3or; #70
$display("\nTime = %0dns \t : Alu operates bit-wise OR; result = %h", $time, result);
aluOp = f3and; #70
$display("\nTime = %0dns \t : Alu operates bit-wise AND; result = %h", $time, result);
$finish;
end
// 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, "alu_tb");
$dumpvars(0, alu_tb);
endtask: dumpWave
endmodule
+164
View File
@@ -0,0 +1,164 @@
// *********************************************************************************************
// 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
// ----------- --------- -------------------------------------------------
// 15.Oct.2025 H.Elzomor Renamed file and module from soc_tb to cpu_tb
// *********************************************************************************************
// `define fibonacci
// `define helloWorld
// `define primeFactors
`timescale 1ns/1ns
module cpu_tb ();
// local signals
logic[7:0] led;
logic[6:0] btn;
logic reset;
logic clk;
// Toplevel instance (DUT)
cpu u_cpu (
.led(led),
.btn(btn),
.clk_25mhz(clk)
);
// Tie reset signal to the reset button
assign btn[0] = reset;
// Clock generation
always #20 clk = ~clk;
// Initialize and run simulation
initial begin
dumpWave("wave.vcd");
`ifdef fibonacci
loadMem("fibonacci.hex");
`elsif helloWorld
loadMem("helloWorld.hex");
`elsif primeFactors
loadMem("primeFactors.hex");
`endif
clk = 0;
$display("\nTime = %0dns \t : Resetting the CPU", $time);
reset = 0; #100;
$display("\nTime = %0dns \t : Reset released", $time);
reset = 1; #500000;
$finish;
end
// Fibonacci Program Monitor
`ifdef fibonacci
localparam int fibonacciStartLoc = 2027;
localparam int fibonacciLengthInWords = 10;
always_comb begin: Monitor_Fibonacci_Series_Calculation
$display("\nTime =%5dns\t\t\t Hex \t Dec", $time);
$display("Value at RAM[%0d]: 0x%h : %0d",fibonacciStartLoc+0, u_cpu.theMem.RAM[fibonacciStartLoc+0], u_cpu.theMem.RAM[fibonacciStartLoc+0]);
$display("Value at RAM[%0d]: 0x%h : %0d",fibonacciStartLoc+1, u_cpu.theMem.RAM[fibonacciStartLoc+1], u_cpu.theMem.RAM[fibonacciStartLoc+1]);
$display("Value at RAM[%0d]: 0x%h : %0d",fibonacciStartLoc+2, u_cpu.theMem.RAM[fibonacciStartLoc+2], u_cpu.theMem.RAM[fibonacciStartLoc+2]);
$display("Value at RAM[%0d]: 0x%h : %0d",fibonacciStartLoc+3, u_cpu.theMem.RAM[fibonacciStartLoc+3], u_cpu.theMem.RAM[fibonacciStartLoc+3]);
$display("Value at RAM[%0d]: 0x%h : %0d",fibonacciStartLoc+4, u_cpu.theMem.RAM[fibonacciStartLoc+4], u_cpu.theMem.RAM[fibonacciStartLoc+4]);
$display("Value at RAM[%0d]: 0x%h : %0d",fibonacciStartLoc+5, u_cpu.theMem.RAM[fibonacciStartLoc+5], u_cpu.theMem.RAM[fibonacciStartLoc+5]);
$display("Value at RAM[%0d]: 0x%h : %0d",fibonacciStartLoc+6, u_cpu.theMem.RAM[fibonacciStartLoc+6], u_cpu.theMem.RAM[fibonacciStartLoc+6]);
$display("Value at RAM[%0d]: 0x%h : %0d",fibonacciStartLoc+7, u_cpu.theMem.RAM[fibonacciStartLoc+7], u_cpu.theMem.RAM[fibonacciStartLoc+7]);
$display("Value at RAM[%0d]: 0x%h : %0d",fibonacciStartLoc+8, u_cpu.theMem.RAM[fibonacciStartLoc+8], u_cpu.theMem.RAM[fibonacciStartLoc+8]);
$display("Value at RAM[%0d]: 0x%h : %0d",fibonacciStartLoc+9, u_cpu.theMem.RAM[fibonacciStartLoc+9], u_cpu.theMem.RAM[fibonacciStartLoc+9]);
$display("");
end
// Hello World Program Monitor
`elsif helloWorld
localparam int helloWorldStartLoc = 1024;
localparam int helloWorldLengthInWords = 4;
always_comb begin: Monitor_Hello_World_Printing
$display("\nTime =%5dns\t\t Hex \t\t ASCII", $time);
$display("Value at RAM[%0d]: 0x%h : %0s", helloWorldStartLoc+0, u_cpu.theMem.RAM[helloWorldStartLoc+0], u_cpu.theMem.RAM[helloWorldStartLoc+0]);
$display("Value at RAM[%0d]: 0x%h : %0s", helloWorldStartLoc+1, u_cpu.theMem.RAM[helloWorldStartLoc+1], u_cpu.theMem.RAM[helloWorldStartLoc+1]);
$display("Value at RAM[%0d]: 0x%h : %0s", helloWorldStartLoc+2, u_cpu.theMem.RAM[helloWorldStartLoc+2], u_cpu.theMem.RAM[helloWorldStartLoc+2]);
$display("Value at RAM[%0d]: 0x%h : %0s", helloWorldStartLoc+3, u_cpu.theMem.RAM[helloWorldStartLoc+3], u_cpu.theMem.RAM[helloWorldStartLoc+3]);
$display("");
end
// Prime Factors Program Monitor
`elsif primeFactors
localparam int primeNumberReg = 16;
always_comb begin: Monitor_Factorization_Number
if(u_cpu.theRegisters.registers[primeNumberReg] > 1)
$display("\nTime =%5dns \t : Register [%0d] updated - Finding the prime factors of %0d", $time,primeNumberReg, u_cpu.theRegisters.registers[primeNumberReg]);
end
localparam int primeFactorsReg = 17;
always_comb begin: Monitor_Prime_Number
if(u_cpu.theRegisters.registers[primeFactorsReg] > 1)
$display("Time =%5dns \t : Register [%0d] updated - %0d is a prime factor", $time,primeFactorsReg, u_cpu.theRegisters.registers[primeFactorsReg]);
end
`endif
// Wave Dump Helper Task
int i;
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, "cpu_tb");
$dumpvars(0, cpu_tb);
// Dump Memory in wave file
$display("\nTime = %0dns \t : Dumping Memory in wave file", $time);
for (i = 0; i < 100; i++) begin $dumpvars(0, cpu_tb.u_cpu.theMem.RAM[i]); end // A part of the Instruction Memory
for (i = 1024; i < 1124; i++) begin $dumpvars(0, cpu_tb.u_cpu.theMem.RAM[i]); end // A part of the Data Memory
for (i = 1968; i < 2048; i++) begin $dumpvars(0, cpu_tb.u_cpu.theMem.RAM[i]); end // A part of the Stack
// Dump registers in wave file
$display("\nTime = %0dns \t : Dumping Registers in wave file", $time);
$dumpvars(0, cpu_tb.u_cpu.theRegisters.registers[1]);
$dumpvars(0, cpu_tb.u_cpu.theRegisters.registers[2]);
$dumpvars(0, cpu_tb.u_cpu.theRegisters.registers[3]);
$dumpvars(0, cpu_tb.u_cpu.theRegisters.registers[4]);
$dumpvars(0, cpu_tb.u_cpu.theRegisters.registers[5]);
$dumpvars(0, cpu_tb.u_cpu.theRegisters.registers[6]);
$dumpvars(0, cpu_tb.u_cpu.theRegisters.registers[7]);
$dumpvars(0, cpu_tb.u_cpu.theRegisters.registers[8]);
$dumpvars(0, cpu_tb.u_cpu.theRegisters.registers[9]);
$dumpvars(0, cpu_tb.u_cpu.theRegisters.registers[10]);
$dumpvars(0, cpu_tb.u_cpu.theRegisters.registers[11]);
$dumpvars(0, cpu_tb.u_cpu.theRegisters.registers[12]);
$dumpvars(0, cpu_tb.u_cpu.theRegisters.registers[13]);
$dumpvars(0, cpu_tb.u_cpu.theRegisters.registers[14]);
$dumpvars(0, cpu_tb.u_cpu.theRegisters.registers[15]);
$dumpvars(0, cpu_tb.u_cpu.theRegisters.registers[16]);
$dumpvars(0, cpu_tb.u_cpu.theRegisters.registers[17]);
$dumpvars(0, cpu_tb.u_cpu.theRegisters.registers[18]);
$dumpvars(0, cpu_tb.u_cpu.theRegisters.registers[19]);
$dumpvars(0, cpu_tb.u_cpu.theRegisters.registers[20]);
$dumpvars(0, cpu_tb.u_cpu.theRegisters.registers[21]);
$dumpvars(0, cpu_tb.u_cpu.theRegisters.registers[22]);
$dumpvars(0, cpu_tb.u_cpu.theRegisters.registers[23]);
$dumpvars(0, cpu_tb.u_cpu.theRegisters.registers[24]);
$dumpvars(0, cpu_tb.u_cpu.theRegisters.registers[25]);
$dumpvars(0, cpu_tb.u_cpu.theRegisters.registers[26]);
$dumpvars(0, cpu_tb.u_cpu.theRegisters.registers[27]);
$dumpvars(0, cpu_tb.u_cpu.theRegisters.registers[28]);
$dumpvars(0, cpu_tb.u_cpu.theRegisters.registers[29]);
$dumpvars(0, cpu_tb.u_cpu.theRegisters.registers[30]);
$dumpvars(0, cpu_tb.u_cpu.theRegisters.registers[31]);
endtask: dumpWave
// Load hex file into memory
task loadMem (string fileName);
$display("\nTime = %0dns \t : Loading '%s' into Memory", $time, fileName);
$readmemh(fileName, cpu_tb.u_cpu.theMem.RAM);
endtask: loadMem
endmodule
+150
View File
@@ -0,0 +1,150 @@
// *********************************************************************************************
// 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
+238
View File
@@ -0,0 +1,238 @@
// *********************************************************************************************
// Project Version : v1.0
// Project : [BCDC] Microtec Academy Course: Building a RISC-V CPU with SystemVerilog
// -----
// Copyright (c) : 2025 Fraunhofer IIS, Department IDS
// Created : 20.Oct.2025 by Aliakbar Merchant
// Last Modified : 24.Oct.2025 by Aliakbar Merchant [commit 89a5087]
// -----
// HISTORY : Date By Comments
// ----------- --------- -------------------------------------------------
// *********************************************************************************************
`timescale 1ns/1ns
module main_mem_tb ();
// local Parameters
localparam string MEM_INIT_FILE = "main_mem.hex";
// Helpers for addressing width
localparam logic[1:0] _byte = 2'b00; // byte: 8 bits
localparam logic[1:0] _half = 2'b01; // half: 16 bits
localparam logic[1:0] _word = 2'b10; // word: 32 bits
// Local Signals
// clk and reset
logic clk;
logic reset;
// Memory
logic[31:0] DAddr;
logic[31:0] IAddr;
logic[31:0] DWData;
logic[31:0] DRData;
logic[31:0] IRData;
logic DWE;
logic[1:0] DWidth;
// Helpers for display results purpose
logic[31:0] value_at_0;
logic[31:0] value_at_1;
logic[31:0] value_at_2;
logic[31:0] value_at_3;
logic[31:0] value_at_1024;
logic[31:0] value_at_1025;
logic[31:0] value_at_1026;
logic[31:0] value_at_1027;
// Toplevel instance (DUT)
main_mem u_main_mem (
.clk (clk ),
.reset (reset ),
.DAddr (DAddr ),
.IAddr (IAddr ),
.DWData (DWData ),
.DRData (DRData ),
.IRData (IRData ),
.DWE (DWE ),
.DWidth (DWidth )
);
// Clock generation
always #1 clk = ~clk;
// Initialize and run simulation
initial begin
loadMem(MEM_INIT_FILE);
value_at_0 = main_mem_tb.u_main_mem.RAM[0];
value_at_1 = main_mem_tb.u_main_mem.RAM[1];
value_at_2 = main_mem_tb.u_main_mem.RAM[2];
value_at_3 = main_mem_tb.u_main_mem.RAM[3];
value_at_1024 = main_mem_tb.u_main_mem.RAM[1024];
value_at_1025 = main_mem_tb.u_main_mem.RAM[1025];
value_at_1026 = main_mem_tb.u_main_mem.RAM[1026];
value_at_1027 = main_mem_tb.u_main_mem.RAM[1027];
clk = 0;
DAddr = 32'd4096;
IAddr = 0;
DWData = 0;
DWidth = 0;
reset = 1; DWE=1; #7;
DWE = 0;
reset = 0; #2;
test_scenario1(); #30;
$finish;
end
// Test scenario 1
task test_scenario1();
fork
read_inst_mem(15);
display_inst_read_results();
write_data_mem(4096);
join
display_write_results();
fork
display_read_results();
read_data_mem(4096);
join
endtask: test_scenario1
// Intruction memory read transactions and results display
task read_inst_mem(int unsigned n = 1);
repeat(n) begin
cycles_pe(1);
IAddr = IAddr+4;
end
endtask:read_inst_mem
task display_inst_read_results();
$display("\n----------------------------------------------------------------------------------" );
$display("Instruction MEMORY READ RESULTS" );
$display("15 instruction are read by testbench starting at adrress 0x0000 i.e at (RAM[0]) but only 4 displyed for simplicity" );
$display("----------------------------------------------------------------------------------" );
cycles_pe(2);
$display("Time = %0dns \t : IAddr = 0x0000(RAM[0]): Expected value = 0x%h Actual Value at IRData: 0x%h" , $time, value_at_0, IRData );
cycles_pe(1);
$display("Time = %0dns \t : IAddr = 0x0004(RAM[1]): Expected value = 0x%h Actual Value at IRData: 0x%h" , $time, value_at_1, IRData );
cycles_pe(1);
$display("Time = %0dns \t : IAddr = 0x0008(RAM[2]): Expected value = 0x%h Actual Value at IRData: 0x%h" , $time, value_at_2, IRData );
cycles_pe(1);
$display("Time = %0dns \t : IAddr = 0x000c(RAM[3]): Expected value = 0x%h Actual Value at IRData: 0x%h" , $time, value_at_3, IRData );
endtask:display_inst_read_results
// Data memory write transaction and results display
task write_data_mem(logic [31:0] daddr_init=32'd4096);
cycles_pe(1);
DWE = 1;
DWidth = 0;
DAddr = daddr_init+0;
DWData = 32'hDEADBEEF;
cycles_pe(1);
DWE = 1;
DWidth = 1;
DAddr = daddr_init+4;
DWData = 32'hDEADBEEF;
cycles_pe(1);
DWE = 1;
DWidth = 2;
DAddr = daddr_init+8;
DWData = 32'hDEADBEEF;
cycles_pe(1);
DWE = 1;
DWidth = 3;
DAddr = daddr_init+12;
DWData = 32'hDEADBEEF;
cycles_pe(1);
DWE = 0;
endtask:write_data_mem
task display_write_results();
$display("\n----------------------------------------------------------------------------------" );
$display("DATA MEMORY WRITE RESULTS" );
$display("4 Write transaction are being done by testbench starting at adrress 0x1000 i.e at (RAM[1024]) with all 4 combination of DWidth" );
$display("Data written is always 0xDEADBEEF i.e DWData = DEADBEEF" );
$display("----------------------------------------------------------------------------------" );
$display("Time = %0dns \t : DWidth = 0 DAddr = 0x1000(RAM[1024]): Start value at RAM[1024] = 0x%h Expected value at RAM[1024]= 0xef%h Actual Value at RAM[1024]: 0x%h" , $time, value_at_1024,value_at_1024[23:0], getMem(1024) );
$display("Time = %0dns \t : DWidth = 1 DAddr = 0x1004(RAM[1025]): Start value at RAM[1025] = 0x%h Expected value at RAM[1025]= 0xbeef%h Actual Value at RAM[1025]: 0x%h" , $time, value_at_1025,value_at_1025[15:0], getMem(1025) );
$display("Time = %0dns \t : DWidth = 2 DAddr = 0x1008(RAM[1026]): Start value at RAM[1026] = 0x%h Expected value at RAM[1026]= 0xdeadbeef Actual Value at RAM[1026]: 0x%h" , $time, value_at_1026, getMem(1026) );
$display("Time = %0dns \t : DWidth = 3 DAddr = 0x100c(RAM[1027]): Start value at RAM[1027] = 0x%h Expected value at RAM[1027]= 0x%h Actual Value at RAM[1027]: 0x%h" , $time, value_at_1027,value_at_1027, getMem(1027) );
endtask:display_write_results
// Data Memory read transaction and results display
task read_data_mem(logic [31:0] daddr_init=32'd4096);
cycles_pe(1);
DWidth = 0;
DAddr = daddr_init+0;
cycles_pe(1);
DWidth = 1;
DAddr = daddr_init+4;
cycles_pe(1);
DWidth = 2;
DAddr = daddr_init+8;
cycles_pe(1);
DWidth = 3;
DAddr = daddr_init+12;
cycles_pe(1);
DWidth = 2;
DAddr = daddr_init+0;
cycles_pe(1);
DWidth = 2;
DAddr = daddr_init+4;
cycles_pe(1);
DWidth = 2;
DAddr = daddr_init+8;
cycles_pe(1);
DWidth = 2;
DAddr = daddr_init+12;
endtask:read_data_mem
task display_read_results();
$display("\n----------------------------------------------------------------------------------" );
$display("DATA MEMORY READ RESULTS" );
$display("8 Read transaction are being done by testbench starting at adrress 0x1000 i.e at (RAM[1024])" );
$display("----------------------------------------------------------------------------------" );
cycles_pe(2);
$display("Time = %0dns \t : DWidth = 0 DAddr = 0x1000(RAM[1024]): Expected value = 0x000000ef Actual Value at DRData: 0x%h" , $time, DRData );
cycles_pe(1);
$display("Time = %0dns \t : DWidth = 1 DAddr = 0x1004(RAM[1025]): Expected value = 0x0000beef Actual Value at DRData: 0x%h" , $time, DRData );
cycles_pe(1);
$display("Time = %0dns \t : DWidth = 2 DAddr = 0x1008(RAM[1026]): Expected value = 0xdeadbeef Actual Value at DRData: 0x%h" , $time, DRData );
cycles_pe(1);
$display("Time = %0dns \t : DWidth = 3 DAddr = 0x100c(RAM[1027]): Expected value = 0xdeadbeef Actual Value at DRData: 0x%h" , $time, DRData );
cycles_pe(1);
$display("Time = %0dns \t : DWidth = 2 DAddr = 0x1000(RAM[1024]): Expected value = 0xef%h Actual Value at DRData: 0x%h" , $time, value_at_1024[23:0], DRData );
cycles_pe(1);
$display("Time = %0dns \t : DWidth = 2 DAddr = 0x1004(RAM[1025]): Expected value = 0xbeef%h Actual Value at DRData: 0x%h" , $time, value_at_1025[15:0], DRData );
cycles_pe(1);
$display("Time = %0dns \t : DWidth = 2 DAddr = 0x1008(RAM[1026]): Expected value = 0xdeadbeef Actual Value at DRData: 0x%h" , $time, DRData );
cycles_pe(1);
$display("Time = %0dns \t : DWidth = 2 DAddr = 0x100c(RAM[1027]): Expected value = 0x%h Actual Value at DRData: 0x%h" , $time, value_at_1027, DRData );
endtask:display_read_results
// Helper tasks
// Memory
function int getMem(int location);
getMem = u_main_mem.RAM[location];
endfunction: getMem
task cycles_pe(int unsigned N = 1);
repeat(N) @(posedge clk);
endtask: cycles_pe
task cycles_ne(int unsigned N = 1);
repeat(N) @(negedge clk);
endtask: cycles_ne
// Load hex file into memory
task loadMem (string fileName);
$display("\nTime = %0dns \t : Loading '%s' into Memory", $time, fileName);
$readmemh(fileName, main_mem_tb.u_main_mem.RAM);
endtask: loadMem
endmodule
+68
View File
@@ -0,0 +1,68 @@
// *********************************************************************************************
// 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 Bomin Kim
// Last Modified : 23.Oct.2025 by Bomin Kim [commit 2f8f03d]
// -----
// HISTORY : Date By Comments
// ----------- --------- -------------------------------------------------
// *********************************************************************************************
`timescale 1ns/1ns
module pc_tb ();
// Local Signals
logic[31:0] CurrentPC;
logic[31:0] JumpOrBranchPC;
logic JumpOrBranch;
logic[31:0] NextPC;
logic reset;
logic clk;
// Toplevel instance (DUT)
pc u_pc (
.CurrentPC(CurrentPC),
.JumpOrBranchPC(JumpOrBranchPC),
.JumpOrBranch(JumpOrBranch),
.NextPC(NextPC),
.reset(reset),
.clk(clk)
);
// Clock generation
always #20 clk = ~clk;
// Initialization and run simulation
initial begin
dumpWave("wave.vcd");
clk = 0;
JumpOrBranchPC = 32'h8;
JumpOrBranch = 0;
reset = 0; #100;
reset = 1; #100;
reset = 0; #490;
JumpOrBranch = 1; #60;
JumpOrBranch = 0; #500;
$finish;
end
// NextPC Monitor
initial begin
$monitor("time=%0t clk=%b reset=%b JumpOrBranch=%0h CurrentPC=%0h NextPC=%0h", $time, clk, reset, JumpOrBranch, CurrentPC, NextPC);
end
// 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, "pc_tb");
$dumpvars(0, pc_tb);
endtask: dumpWave
endmodule
+137
View File
@@ -0,0 +1,137 @@
// *********************************************************************************************
// 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 Bomin Kim
// Last Modified : 23.Oct.2025 by Bomin Kim [commit 2f8f03d]
// -----
// HISTORY : Date By Comments
// ----------- --------- -------------------------------------------------
// *********************************************************************************************
`timescale 1ns/1ns
module reg_file_tb ();
// Local Signals
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;
logic reset;
logic clk;
// Toplevel instance (DUT)
reg_file u_reg_file (
.Rs1(Rs1),
.Rs2(Rs2),
.Rd(Rd),
.RRs1(RRs1),
.RRs2(RRs2),
.WRd(WRd),
.WrReg(WrReg),
.reset(reset),
.clk(clk)
);
// Clock generation
always #20 clk = ~clk;
// Initialization and run simulation
initial begin
dumpWave("wave.vcd");
// Initialize inputs
clk = 0;
Rs1 = 0; Rs2 = 0; Rd = 0;
WRd = 0; WrReg = 0; // Read
reset = 1;
#50
reset = 0;
#50 // Write 0xDEADBEEF to reg21
Rd = 5'd21;
WrReg = 1; // Write
WRd = 32'hDEADBEEF;
#50; WrReg = 0;
#50
Rs1 = 5'd21; // read reg21 into RRs1
Rs2 = 5'd0;
#50 // Write 0x12345678 to reg5
Rd = 5'd5;
WrReg = 1; // Write
WRd = 32'h12345678;
#50; WrReg = 0;
#50
Rs1 = 5'd5; // read reg10 into RRs1
#50
Rs1 = 5'd0; // read zero register
#50
Rd = 5'd0; // attempt to write 0xCAFEBABE to zero register
WRd = 32'hCAFEBABE;
WrReg = 1; // Write
#50; WrReg = 0;
#50
Rs1 = 5'd5; // Read from reg5
#200
$finish;
end
// 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, "reg_file_tb");
$dumpvars(0, reg_file_tb);
// Dump registers in wave file
$display("\nTime = %0dns \t : Dumping Registers in wave file", $time);
$dumpvars(0, reg_file_tb.u_reg_file.registers[1]);
$dumpvars(0, reg_file_tb.u_reg_file.registers[2]);
$dumpvars(0, reg_file_tb.u_reg_file.registers[3]);
$dumpvars(0, reg_file_tb.u_reg_file.registers[4]);
$dumpvars(0, reg_file_tb.u_reg_file.registers[5]);
$dumpvars(0, reg_file_tb.u_reg_file.registers[6]);
$dumpvars(0, reg_file_tb.u_reg_file.registers[7]);
$dumpvars(0, reg_file_tb.u_reg_file.registers[8]);
$dumpvars(0, reg_file_tb.u_reg_file.registers[9]);
$dumpvars(0, reg_file_tb.u_reg_file.registers[10]);
$dumpvars(0, reg_file_tb.u_reg_file.registers[11]);
$dumpvars(0, reg_file_tb.u_reg_file.registers[12]);
$dumpvars(0, reg_file_tb.u_reg_file.registers[13]);
$dumpvars(0, reg_file_tb.u_reg_file.registers[14]);
$dumpvars(0, reg_file_tb.u_reg_file.registers[15]);
$dumpvars(0, reg_file_tb.u_reg_file.registers[16]);
$dumpvars(0, reg_file_tb.u_reg_file.registers[17]);
$dumpvars(0, reg_file_tb.u_reg_file.registers[18]);
$dumpvars(0, reg_file_tb.u_reg_file.registers[19]);
$dumpvars(0, reg_file_tb.u_reg_file.registers[20]);
$dumpvars(0, reg_file_tb.u_reg_file.registers[21]);
$dumpvars(0, reg_file_tb.u_reg_file.registers[22]);
$dumpvars(0, reg_file_tb.u_reg_file.registers[23]);
$dumpvars(0, reg_file_tb.u_reg_file.registers[24]);
$dumpvars(0, reg_file_tb.u_reg_file.registers[25]);
$dumpvars(0, reg_file_tb.u_reg_file.registers[26]);
$dumpvars(0, reg_file_tb.u_reg_file.registers[27]);
$dumpvars(0, reg_file_tb.u_reg_file.registers[28]);
$dumpvars(0, reg_file_tb.u_reg_file.registers[29]);
$dumpvars(0, reg_file_tb.u_reg_file.registers[30]);
$dumpvars(0, reg_file_tb.u_reg_file.registers[31]);
endtask: dumpWave
endmodule
+79
View File
@@ -0,0 +1,79 @@
# OpenFile ./cpu_tb.sv
ls
# alu_tb.sv decoder_tb.sv pc_tb.sv transcript
# cpu_tb.sv main_mem_tb.sv reg_file_tb.sv work
vsim compile.tcl
# vsim compile.tcl
# Start time: 11:01:25 on Nov 28,2025
# ** Error (suppressible): (vsim-19) Failed to access library 'compile' at "compile".
# No such file or directory. (errno = ENOENT)
# Error loading design
# End time: 11:01:25 on Nov 28,2025, Elapsed time: 0:00:00
# Errors: 1, Warnings: 0
ls
# alu_tb.sv decoder_tb.sv pc_tb.sv transcript
# cpu_tb.sv main_mem_tb.sv reg_file_tb.sv work
cd ..
ls
# rtl verilator wave_configs
cd ..
pwd
# C:/PhD/RISC-V Design Course Material/RISC-V Desgin Course - Complete Source Code/riscv_in3days-public/hw
cd ..
ls
# README.md doc hw sw
cd ..
ls
# riscv_in3days-public
cd ..
ls
# Course Introduction & Closing - Public.pdf
# Day 1
# Day 2
# Day 3
# Day 4
# RISC-V Desgin Course - Complete Source Code
# References
cd ..
cd ..
la
# ambiguous command name "la": label labelframe langOf lappend lassign lattice_edition layout
ls
# Drivers Program Files (x86) inetpub
# DumpStack.log Steam_Community_Markt intelFPGA
# Lukas Users intelFPGA_lite
# PhD Windows vfcompat.dll
# ProcLogs appverifUI.dll
# Program Files flexlm
pwd
# C:/
ls
# Drivers Program Files (x86) inetpub
# DumpStack.log Steam_Community_Markt intelFPGA
# Lukas Users intelFPGA_lite
# PhD Windows vfcompat.dll
# ProcLogs appverifUI.dll
# Program Files flexlm
cd PhD
ls
# Code compile.tcl
# RISC-V Design Course Material
cd RISC-V Design Course Material
# wrong # args: should be "cd ?dirName?"
ls
# Code compile.tcl
# RISC-V Design Course Material
ls
# Code compile.tcl
# RISC-V Design Course Material
cd RISC-V Design Course Material
# wrong # args: should be "cd ?dirName?"
ls
# Code compile.tcl
# RISC-V Design Course Material
run compile.tcl
# No Design Loaded!
compile.tcl
# couldn't execute ".\compile.tcl": no such file or directory
run compile.tcl
# No Design Loaded!
+10
View File
@@ -0,0 +1,10 @@
m255
K4
z2
13
!s112 1.1
!i10d 8192
!i10e 25
!i10f 100
cModel Technology
dC:/PhD/RISC-V Design Course Material/RISC-V Desgin Course - Complete Source Code/riscv_in3days-public/hw/dv/rtl
Binary file not shown.
Binary file not shown.
Binary file not shown.
+78
View File
@@ -0,0 +1,78 @@
export PRJ_ROOT = ../../..
# directroy containig syrinx application programs
SWDIR = $(PRJ_ROOT)/sw/risc-v
DVDIR = $(PRJ_ROOT)/hw/dv
# toplevel syrinx file list
RTL_FLIST = $(PRJ_ROOT)/hw/file_lists/rtl_flist.f
TB_FLIST = $(PRJ_ROOT)/hw/file_lists/tb_flist.f
# if we have multiple file list, we combine them here
FLIST = -f $(RTL_FLIST) -f $(TB_FLIST)
# Default number of simulation cycles
NCYCLES ?= 500
# Standard boot loader and dummy application to be used if nothing else is specified
PROG ?= $(SWDIR)/hello_world/helloWorld.hex
# top module name
TOPMODULE = cpu_harness
# NUmber of GCC parallel threads
COMPILE_THREADS = 32
# Verilator CPU usage, should be adapated to simulation host
SIM_THREADS = 4
TRACE_THREADS = 1
EXTRA_ARGS += --trace-fst --trace-structs --trace-max-array 2048 --trace-threads $(TRACE_THREADS) --threads $(SIM_THREADS)
EXTRA_ARGS += --clk clk --no-timing
# EXTRA_ARGS += -O2
# Used by some code constructs
VDEFS = +define+SIMULATION
all: ./obj_dir/V$(TOPMODULE)
wave: wavedump.fst
@echo
@echo "*** Starting waveform viewer..."
$(WAVE_VIEWER) wavedump.fst -s $(DVDIR)/wave_configs/verilator_wave.surf.ron
run:
@echo
@echo "*** Running simulation..."
@./obj_dir/V$(TOPMODULE) $(NCYCLES) $(PROG)
./obj_dir/V$(TOPMODULE): .stamp.verilate
@echo
@echo "*** Building simulator..."
make -C obj_dir -f V$(TOPMODULE).mk V$(TOPMODULE) -j $(COMPILE_THREADS)
.stamp.verilate: src/tb_$(TOPMODULE).cpp
@echo "*** Generating C++ model..."
$(VERILATOR) --trace $(EXTRA_ARGS) $(VDEFS) -cc $(FLIST) --top-module $(TOPMODULE) --exe src/tb_$(TOPMODULE).cpp
@touch .stamp.verilate
lint:$(VERILOG_SOURCES)
$(VERILATOR) --lint-only $(INCLUDES) $(VERILOG_SOURCES) --top-module $(TOPMODULE)
paths:
@echo $(PRJ_ROOT)/$(APB)
clean:
rm -rf .stamp.*;
rm -rf ./obj_dir
rm -rf wavedump.fst*
rm -rf *.dasm
@@ -0,0 +1,148 @@
// *********************************************************************************************
// Description : Verilator simulation harness
// Project Version : v1.0
// Project : [BCDC] Microtec Academy Course: Building a RISC-V CPU with SystemVerilog
// -----
// Copyright (c) : 2025 Fraunhofer IIS, Department IDS
// Created : 12.Aug.2025 by Marcus Bednara
// Last Modified : 15.Oct.2025 by Hussein Elzomor [commit d0452cd]
// -----
// HISTORY : Date By Comments
// ----------- --------- -------------------------------------------------
// 15.Oct.2025 H.Elzomor Renamed file and module from soc_harness to cpu_harness
// 15.Oct.2025 H.Elzomor Added getMem function, setMem task and printMem task
// *********************************************************************************************
timeunit 1ps;
timeprecision 1ps;
module cpu_harness;
// local signals
logic clk,
rst;
logic [7:0] led;
logic [6:0] btn;
// toplevel instance (DUT)
cpu u_cpu (
.led (led),
.btn ({btn[6:1], rst}),
.clk_25mhz (clk)
); // u_cpu
`ifdef VERILATOR
// Declare all functions with DPI-C interface to make them accessible from the C++ testbench
export "DPI-C" task setClk;
export "DPI-C" task enable;
export "DPI-C" task loadRAM;
// export "DPI-C" task dumpSRAM;
export "DPI-C" task setInitial;
export "DPI-C" function getLed;
export "DPI-C" task setBtn;
export "DPI-C" task setReset;
export "DPI-C" function getMem;
export "DPI-C" task setMem;
export "DPI-C" task printMem;
export "DPI-C" function getReg;
export "DPI-C" task printReg;
// Clocking is controlled from C++ testbench
task setClk (input logic val);
clk = val;
endtask: setClk
`else
// If not using verilator, generate clock here
const realtime clk_PERIOD = 1.0ns;
initial begin: clock_driver
clk = '1;
forever begin
#(clk_PERIOD/2.0);
clk <= ~clk;
end
end: clock_driver
task wait_clk_cycles(int unsigned n);
repeat(n) @(posedge clk);
endtask
`endif
// Remaining tasks are identical for Verilator and other simulators
task loadRAM (input string fileName);
$display ("Initializing SRAM memory from %s", fileName);
$readmemh(fileName, u_cpu.theMem.RAM);
endtask: loadRAM
/* Some helper stuff */
task enable(int val);
// nothing to do, we have no fetch enable in this design
endtask: enable
task setInitial();
btn = 7'b0;
rst = 'b0;
endtask: setInitial
function int getLed;
getLed = {24'b0, led};
endfunction: getLed
task setBtn(int val);
btn[6:1] = val[5:0];
endtask: setBtn
task setReset (input int val);
rst = (val==1);
endtask: setReset
function int getMem(int location);
getMem = u_cpu.theMem.RAM[location];
endfunction: getMem
task setMem(int location, int value);
u_cpu.theMem.RAM[location] = value;
endtask: setMem
task printMem (int location, string prog);
case (prog)
"fibonacci" :$display("Value at RAM[%0d]: 0x%h : %0d", location, getMem(location), getMem(location));
"helloWorld" :$display("Value at RAM[%0d]: 0x%h : %s" , location, getMem(location), getMem(location));
default :$display("Value at RAM[%0d]: 0x%h : %0d", location, getMem(location), getMem(location));
endcase
endtask: printMem
function int getReg(int location);
getReg = u_cpu.theRegisters.registers[location];
endfunction: getReg
task printReg (int location, string prog);
case (prog)
"primeNumber" :$display("Time =%5dns \t : Register [%0d] updated - Finding the prime factors of %0d", $time, location, getReg(location));
"primeFactors":$display("Time =%5dns \t : Register [%0d] updated - %0d is a prime factor", $time, location, getReg(location));
default :$display("Time =%5dns \t : Value at Reg[%0d]: 0x%h", $time, location, getReg(location));
endcase
endtask: printReg
endmodule: cpu_harness
@@ -0,0 +1,173 @@
// *********************************************************************************************
// Description : Verilator simulation harness
// 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 : 15.Oct.2025 by Hussein Elzomor
// -----
// HISTORY : Date By Comments
// ----------- --------- -------------------------------------------------
// *********************************************************************************************
timeunit 1ps;
timeprecision 1ps;
module decoder_harness;
// 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)
); // u_decoder
// Special Verilator specific tasks
`ifdef VERILATOR
// Declare all functions with DPI-C interface to make them accessible from the C++ testbench
// Setters
export "DPI-C" task setClk;
export "DPI-C" task enable;
export "DPI-C" task loadRAM;
export "DPI-C" task setInitial;
export "DPI-C" task printInfo;
// Clocking is controlled from C++ testbench
task setClk (input logic val);
clk = val;
endtask: setClk
`else
// If not using verilator, generate clock here
const realtime clk_PERIOD = 1.0ns;
initial begin: clock_driver
clk = '1;
forever begin
#(clk_PERIOD/2.0);
clk <= ~clk;
end
end: clock_driver
task wait_clk_cycles(int unsigned n);
repeat(n) @(posedge clk);
endtask
`endif
// 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
// Remaining tasks are identical for Verilator and other simulators
task enable(int val);
// nothing to do, we have no fetch enable in this design
endtask: enable
// Load data into memory
task loadRAM (input string fileName);
$display ("Initializing SRAM memory from %s", fileName);
$readmemh(fileName, mem);
endtask: loadRAM
// Set initial values
task setInitial();
Instruction = mem[0];
counter = 0;
CurrentPC = 32'hdeadbeef;
RData = 32'hbeefdead;
for(int i=0; i<REG_FILE_SIZE; i++) begin
regFile[i] = i;
end
endtask: setInitial
// Print decoder signals
task printInfo();
$displayh("(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 );
$displayh("");
endtask: printInfo
endmodule: decoder_harness
@@ -0,0 +1,328 @@
// *********************************************************************************************
// Description : Verilator tb
// Project Version : v1.0
// Project : [BCDC] Microtec Academy Course: Building a RISC-V CPU with SystemVerilog
// -----
// Copyright (c) : 2025 Fraunhofer IIS, Department IDS
// Created : 12.Aug.2025 by Marcus Bednara
// Last Modified : 15.Oct.2025 by Hussein Elzomor [commit d0452cd]
// -----
// HISTORY : Date By Comments
// ----------- --------- -------------------------------------------------
// 15.Oct.2025 H.Elzomor Renamed modules from *soc* to *cpu*
// 15.Oct.2025 H.Elzomor Added evalText function
// *********************************************************************************************
using namespace std;
#include <stdlib.h>
#include <iostream>
#include <verilated.h>
#include <verilated_fst_c.h>
#include "Vcpu_harness.h"
#include "Vcpu_harness__Dpi.h"
// only required for accessing model internal memory ressources via the rootp pointer.
// Bad style, better use systemverilog harness with tasks and functions to do that.
// #include "Vcpu_harness___024root.h"
// #include "svdpi.h"
#define SOC_CLK_PERIOD 40
//--------------------------------------------------------------
/// @brief Simulation environment class for the cpu model.
/// Contains a set of high level methods for controlling the model from test environment.
class cpu
{
private:
Vcpu_harness *dut;
VerilatedFstC *mTrace;
vluint64_t T;
uint32_t cpuClkState;
bool running;
string program;
public:
//--------------------------------------------------------------
/// @brief Constructor
cpu (int argc, char** argv)
{
// setup verilator stuff
T = 0;
dut = new Vcpu_harness();
Verilated::commandArgs(argc, argv);
Verilated::traceEverOn(true);
mTrace = new VerilatedFstC;
dut->trace(mTrace, 5);
mTrace->open("wavedump.fst");
cout << "Registered DPI-C functions:\n";
Verilated::scopesDump();
const svScope scope = svGetScopeFromName("TOP.cpu_harness");
assert(scope); // Check for nullptr if scope not found
svSetScope(scope);
running = false;
// initialize all input signals
initSignals();
} // swirl()
//--------------------------------------------------------------
/// @brief simulation tick, advances the simulation time and calls the eval() function of the model on every active clock edge
void tick ()
{
int do_eval;
if (T%SOC_CLK_PERIOD==0) {
dut->setClk(cpuClkState);
cpuClkState = 1-cpuClkState;
do_eval = 1;
}
// Other clock domains must be generated the same way
// if (T%OTHER_CLK_PERIOD==0) {
// dut->setOtherClk(otherClkState);
// otherClkState = 1-otherClkState;
// do_eval = 1;
// }
if (do_eval) {
dut->eval();
// evaluate the LED status in each clock cycle if the CPU is running (i.e., after reset)
if (running && program == "unknown") evalLed();
// evaluate the Fibonacci Series location in stack (starting at 2027) and print value if it has changed
if (running && program == "fibonacci") evalFibonacci();
// evaluate the 'hello world!' location in the DataMem in each clock cycle if the CPU is running (i.e., after reset)
if (running && program == "helloWorld") evalHelloWorld();
// evaluate the Prime Factors location in RegFile (x17) and print value if it has changed
if (running && program == "primeFactors") evalPrimeFactors();
mTrace->dump(T);
do_eval = 0;
}
T++;
} // tick()
//--------------------------------------------------------------
/// @brief Initialize all input signals of the hardware model to a defined value
void initSignals()
{
dut->setInitial();
} // initSignals()
//--------------------------------------------------------------
/// @brief Wait for a number of active edges of clk signal
/// @param numEdges number of rising edges
/// @param active active 1=rising 0=falling edge
void waitClocks (int numEdges=1, int activeEdge=1)
{
int clk_d;
for (int j=0; j<numEdges; ++j) {
while (1) {
clk_d = cpuClkState;
tick();
if (clk_d==1-activeEdge && cpuClkState==activeEdge) break;
}
} // for
} // waitClocks()
//--------------------------------------------------------------
/// @brief Toggle the reset signal active (low)
/// @param numEdges number of clock cyles keeping the reset active
void reset (int numEdges=1)
{
dut->setReset(0); // reset is active low
waitClocks (numEdges);
dut->setReset(1);
} // reset();
//--------------------------------------------------------------
/// @brief load the cpu memory from vmem formatted file
void loadRAM (char* vmemFile)
{
dut->loadRAM(vmemFile);
} // loadRAM()
/// @brief check the LED status and print value if it has change
void evalLed ()
{
static uint8_t oldLedStatus=0xff;
uint8_t currentLedStatus;
currentLedStatus=dut->getLed();
if (currentLedStatus!=oldLedStatus) {
cout << "T=" << T << ": LED=" << std::bitset<8>(currentLedStatus) << endl;
oldLedStatus = currentLedStatus;
}
} // evalLed()
/// @brief check Fibonacci Series location in stack (starting at 2027) and print value if it has changed
void evalFibonacci()
{
int memStartLoc = 2027;
const int memLengthInBytes = 40;
const int memLengthInWords = ceil(memLengthInBytes / 4.0);
static uint32_t oldValue[memLengthInWords];
uint32_t vlaue[memLengthInWords];
bool update = 0;
for (int i = 0; i < memLengthInWords; i++)
{
vlaue[i] = dut->getMem(memStartLoc + i);
if (oldValue[i] != vlaue[i])
update = 1;
}
if (update)
{
cout << endl
<< "T=" << T << ": \t Hex \t Dec" << endl;
for (int i = 0; i < memLengthInWords; i++)
{
dut->printMem(memStartLoc + i, "fibonacci");
oldValue[i] = vlaue[i];
}
cout << endl;
}
} // evalFibonacci()
/// @brief check 'hello world' location in DataMem (starting at 1024) and print value if it has changed
void evalHelloWorld()
{
int memStartLoc = 1024;
const int memLengthInBytes = 13;
const int memLengthInWords = ceil(memLengthInBytes / 4.0);
static uint32_t oldValue[memLengthInWords];
uint32_t vlaue[memLengthInWords];
bool update = 0;
for (int i = 0; i < memLengthInWords; i++)
{
vlaue[i] = dut->getMem(memStartLoc + i);
if (oldValue[i] != vlaue[i])
update = 1;
}
if (update)
{
cout << endl
<< "T=" << T << ": \t Hex \t ASCII" << endl;
for (int i = 0; i < memLengthInWords; i++)
{
dut->printMem(memStartLoc + i, "helloWorld");
oldValue[i] = vlaue[i];
}
cout << endl;
}
} // evalHelloWorld()
/// @brief check Prime Factors location in RegFile (x17) and print value if it has changed
void evalPrimeFactors()
{
// Number to be factorised
int regLoc_Number = 16;
static uint32_t oldValue_Number;
uint32_t value_Number;
value_Number = dut->getReg(regLoc_Number);
if (oldValue_Number != value_Number & value_Number > 1) dut->printReg(regLoc_Number, "primeNumber");
oldValue_Number = value_Number;
// Prime Factors
int regLoc_PrimeFactor = 17;
static uint32_t oldValue_PrimeFactor;
uint32_t value_PrimeFactor;
value_PrimeFactor = dut->getReg(regLoc_PrimeFactor);
if (oldValue_PrimeFactor != value_PrimeFactor & value_PrimeFactor > 1) dut->printReg(regLoc_PrimeFactor, "primeFactors");
oldValue_PrimeFactor = value_PrimeFactor;
} // evalPrimeFactors()
//--------------------------------------------------------------
/// @brief start the DUT
void start()
{
running = true;
dut->enable(1);
} // start()
//--------------------------------------------------------------
/// @brief close the trace file and delete the Verilator object
void stop()
{
dut->enable(0);
mTrace->close();
delete dut;
} // stop()
//--------------------------------------------------------------
/// @brief Set the program name
void setProgram(string prog)
{
if (prog.find("fibonacci") != string::npos) program = "fibonacci";
else if (prog.find("helloWorld") != string::npos) program = "helloWorld";
else if (prog.find("primeFactors") != string::npos) program = "primeFactors";
else program = "unknown";
cout << "program set to " << program << endl;
} // setProgram()
//--------------------------------------------------------------
/// @brief Get the program name
string getProgram()
{
return program;
} // getProgram()
}; // class cpu
int main (int argc, char** argv)
{
uint32_t nCycles;
char* program_path = new char[strlen(argv[2])]();
// Get number of simulation cycles
nCycles = atoi(argv[1]);
// Get the program
program_path = argv[2];
string program_path_str = program_path;
cout << "\nCreating model...\n";
cpu *m = new cpu(argc, argv);
m->loadRAM(program_path);
m->setProgram(program_path_str);
cout << "\nStarting model...\n";
cout << "\nResetting...\n";
m->reset(10);
cout << "Starting CPU...\n" << std::flush;
m->start();
cout << "Running for " << nCycles << " clock cycles...\n\n" << std::flush;
cout << "Printing evaluation for " << m->getProgram() << " program!\n" << std::flush;
m->waitClocks(nCycles);
cout << "\nDone, closing simulation.\n\n\n" << std::flush;
m->stop();
delete m;
exit(EXIT_SUCCESS);
}
@@ -0,0 +1,185 @@
// *********************************************************************************************
// Description : Verilator tb
// 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 : 15.Oct.2025 by Hussein Elzomor
// -----
// HISTORY : Date By Comments
// ----------- --------- -------------------------------------------------
// *********************************************************************************************
using namespace std;
#include <stdlib.h>
#include <iostream>
#include <verilated.h>
#include <verilated_fst_c.h>
#include "Vdecoder_harness.h"
#include "Vdecoder_harness__Dpi.h"
// only required for accessing model internal memory ressources via the rootp pointer.
// Bad style, better use systemverilog harness with tasks and functions to do that.
// #include "Vdecoder_harness___024root.h"
// #include "svdpi.h"
#define DECODER_CLK_PERIOD 40
//--------------------------------------------------------------
/// @brief Simulation environment class for the decoder model.
/// Contains a set of high level methods for controlling the model from test environment.
class decoder
{
private:
Vdecoder_harness *dut;
VerilatedFstC *mTrace;
vluint64_t T;
uint32_t decoderClkState;
bool running;
public:
//--------------------------------------------------------------
/// @brief Constructor
decoder (int argc, char** argv)
{
// setup verilator stuff
T = 0;
dut = new Vdecoder_harness();
Verilated::commandArgs(argc, argv);
Verilated::traceEverOn(true);
mTrace = new VerilatedFstC;
dut->trace(mTrace, 5);
mTrace->open("wavedump.fst");
cout << "Registered DPI-C functions:\n";
Verilated::scopesDump();
const svScope scope = svGetScopeFromName("TOP.decoder_harness");
assert(scope); // Check for nullptr if scope not found
svSetScope(scope);
running = false;
// initialize all input signals
initSignals();
} // swirl()
//--------------------------------------------------------------
/// @brief simulation tick, advances the simulation time and calls the eval() function of the model on every active clock edge
void tick ()
{
int do_eval;
if (T%DECODER_CLK_PERIOD==0) {
dut->setClk(decoderClkState);
decoderClkState = 1-decoderClkState;
do_eval = 1;
}
if (do_eval) {
dut->eval();
mTrace->dump(T);
do_eval = 0;
}
T++;
} // tick()
//--------------------------------------------------------------
/// @brief Initialize all input signals of the hardware model to a defined value
void initSignals()
{
dut->setInitial();
} // initSignals()
//--------------------------------------------------------------
/// @brief Wait for a number of active edges of clk signal
/// @param numEdges number of rising edges
/// @param active active 1=rising 0=falling edge
void waitClocks (int numEdges=1, int activeEdge=1)
{
int clk_d;
for (int j=0; j<numEdges; ++j) {
while (1) {
clk_d = decoderClkState;
tick();
if (clk_d==1-activeEdge && decoderClkState==activeEdge) break;
}
} // for
} // waitClocks()
//--------------------------------------------------------------
/// @brief load the decoder memory from vmem formatted file
void loadRAM(char *vmemFile)
{
dut->loadRAM(vmemFile);
} // loadRAM()
//--------------------------------------------------------------
/// @brief start the DUT
void start()
{
running = true;
dut->enable(1);
} // start()
//--------------------------------------------------------------
/// @brief close the trace file and delete the Verilator object
void stop()
{
dut->enable(0);
mTrace->close();
delete dut;
} // stop()
//--------------------------------------------------------------
/// @brief print signal info
void printInfo()
{
dut->printInfo();
}
}; // class decoder
int main (int argc, char** argv)
{
uint32_t nCycles;
int r;
// Get number of simulation cycles
nCycles = atoi(argv[1]);
cout << "\nCreating model...\n";
decoder *m = new decoder(argc, argv);
m->loadRAM(argv[2]);
cout << "Starting DECODER simulation...\n" << std::flush;
m->start();
cout << "Running for " << nCycles << " clock cycles...\n" << std::flush;
m->waitClocks(nCycles);
m->printInfo();
cout << "\nDone, closing simulation.\n\n\n" << std::flush;
m->stop();
delete m;
exit(EXIT_SUCCESS);
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+19
View File
@@ -0,0 +1,19 @@
// *********************************************************************************************
// Project Version : v1.0
// Project : [BCDC] Microtec Academy Course: Building a RISC-V CPU with SystemVerilog
// -----
// Copyright (c) : 2025 Fraunhofer IIS, Department IDS
// Created : 12.Aug.2025 by Marcus Bednara
// Last Modified : 01.Nov.2025 by Hussein Elzomor
// ------
// Notes : All ${}-variables must be provided by shell or Makefile {using export}
// *********************************************************************************************
${PRJ_ROOT}/hw/rtl/pc.sv
${PRJ_ROOT}/hw/rtl/reg_file.sv
${PRJ_ROOT}/hw/rtl/alu.sv
${PRJ_ROOT}/hw/rtl/main_mem.sv
${PRJ_ROOT}/hw/rtl/decoder.sv
${PRJ_ROOT}/hw/rtl/cpu.sv
+24
View File
@@ -0,0 +1,24 @@
// *********************************************************************************************
// Project Version : v1.0
// Project : [BCDC] Microtec Academy Course: Building a RISC-V CPU with SystemVerilog
// -----
// Copyright (c) : 2025 Fraunhofer IIS, Department IDS
// Created : 12.Aug.2025 by Marcus Bednara
// Last Modified : 01.Nov.2025 by Hussein Elzomor
// ------
// Notes : All ${}-variables must be provided by shell or Makefile {using export}
// *********************************************************************************************
// Used with verilator
${PRJ_ROOT}/hw/dv/verilator/rtl/decoder_harness.sv
${PRJ_ROOT}/hw/dv/verilator/rtl/cpu_harness.sv
// Used with other compilers and simulators (eg. Icarus)
// ${PRJ_ROOT}/hw/dv/rtl/pc_tb.sv
// ${PRJ_ROOT}/hw/dv/rtl/reg_file_tb.sv
// ${PRJ_ROOT}/hw/dv/rtl/alu_tb.sv
// ${PRJ_ROOT}/hw/dv/rtl/main_mem_tb.sv
// ${PRJ_ROOT}/hw/dv/rtl/decoder_tb.sv
// ${PRJ_ROOT}/hw/dv/rtl/cpu_tb.sv
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+60
View File
@@ -0,0 +1,60 @@
module MemGen_32_11 #(
parameter data_width = 32,
parameter addr_width = 11,
parameter mem_depth = 2048
)(
input chip_en,
input clock,
input [addr_width-1:0]addr,
output reg [data_width-1:0]rd_data,
input rd_en,
input wr_en,
input [data_width-1:0]wr_data
);
// Bank selection: 1 bit selects one of 2 banks
reg [1:0] mem_sel ;
wire [31:0] mem_data_out [1:0];
// Address decoder and output multiplexer
always @(*)
begin
if ( chip_en == 1'b1 )
case (addr[10])
1'b0 : begin mem_sel = 2'b01; rd_data = mem_data_out[0]; end
1'b1 : begin mem_sel = 2'b10; rd_data = mem_data_out[1]; end
endcase
else
begin
mem_sel = 2'b00;
rd_data = 32'h00000000;
end
end
genvar i;
// Instantiate 2 banks, each with 2 halves (low + high 16 bits)
generate
for (i = 0; i < 2; i = i + 1) begin
MemGen_16_10 U_lo (
.chip_en(mem_sel[i]),
.clock(clock),
.addr(addr[9:0]),
.rd_en(rd_en),
.rd_data(mem_data_out[i][15:0]),
.wr_en(wr_en),
.wr_data(wr_data[15:0])
);
MemGen_16_10 U_hi (
.chip_en(mem_sel[i]),
.clock(clock),
.addr(addr[9:0]),
.rd_en(rd_en),
.rd_data(mem_data_out[i][31:16]),
.wr_en(wr_en),
.wr_data(wr_data[31:16])
);
end
endgenerate
endmodule
+52
View File
@@ -0,0 +1,52 @@
// *********************************************************************************************
// Project Version : v1.0
// Project : [BCDC] Microtec Academy Course: Building a RISC-V CPU with SystemVerilog
// -----
// Copyright (c) : 2025 Fraunhofer IIS, Department IDS
// Created : 12.Jun.2025 by Lund University [commit 5b1e415]
// Last Modified : 23.Oct.2025 by Bomin Kim [commit 2f8f03d]
// -----
// HISTORY : Date By Comments
// ----------- --------- -------------------------------------------------
// 15.Oct.2025 Bomin Kim Refactored ALU logic from decoder into this file
// *********************************************************************************************
module alu (
input logic[2:0] aluOp,
input logic aluNegAr,
input logic aluBypass,
input logic[31:0] op1,
input logic[31:0] op2,
output logic[31:0] result,
output logic eqFlag
);
// Local parameters; list of aluOp
localparam logic[2:0] f3add = 3'b000;
localparam logic[2:0] f3sl = 3'b001;
localparam logic[2:0] f3slt = 3'b010;
localparam logic[2:0] f3sltU = 3'b011;
localparam logic[2:0] f3xor = 3'b100;
localparam logic[2:0] f3sr = 3'b101;
localparam logic[2:0] f3or = 3'b110;
localparam logic[2:0] f3and = 3'b111;
// ALU logic
always_comb begin : ALU
eqFlag = op1 == op2;
if (aluBypass) result = op1;
else case(aluOp)
f3add: result = aluNegAr ? op1 - op2 : op1 + op2;
f3sl: result = op1 << op2[4:0];
f3slt: result = {31'b0, $signed(op1) < $signed(op2)};
f3sltU: result = {31'b0, $unsigned(op1) < $unsigned(op2)};
f3xor: result = op1 ^ op2;
f3sr: result = aluNegAr ? $signed(op1) >>> op2[4:0] : $signed(op1) >> op2[4:0];
f3or: result = op1 | op2;
f3and: result = op1 & op2;
endcase
end
endmodule
+135
View File
@@ -0,0 +1,135 @@
// *********************************************************************************************
// Project Version : v1.0
// Project : [BCDC] Microtec Academy Course: Building a RISC-V CPU with SystemVerilog
// -----
// Copyright (c) : 2025 Fraunhofer IIS, Department IDS
// Created : 12.Jun.2025 by Lund University [commit 5b1e415]
// Last Modified : 23.Oct.2025 by Hussein Elzomor [commit 2f8f03d]
// -----
// HISTORY : Date By Comments
// ----------- --------- -------------------------------------------------
// 15.Oct.2025 H.Elzomor Renamed file and module from soc to cpu
// 15.Oct.2025 H.Elzomor Added an initial condition for clk_12p5
// *********************************************************************************************
module cpu (
output logic[7:0] led,
input logic[6:0] btn,
input logic clk_25mhz
//input logic scan_en
);
// Local Signals
// Clock & Reset
logic clk;
// logic clk12p5;
logic reset;
// 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;
// Logic
assign clk = clk_25mhz;
// Clock (12.5MHz)
//assign clk = scan_en ? clk_25mhz : clk12p5;
//assign clk = clk12p5;
// always_ff @(posedge clk_25mhz) begin
// if (reset)
// clk12p5 <= 1'b0;
// else if (!scan_en)
// clk12p5 <= ~clk12p5;
// end
// Reset
assign reset = ~btn[0];
// LED
assign led[0] = Illegal;
assign led[1] = WrMem;
assign led[7:2] = NextPC[7:2];
// Module Instantiation
// Decoder
decoder theDecoder (
// 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)
);
// Register File
reg_file theRegisters (
.Rs1(Rs1),
.Rs2(Rs2),
.Rd(Rd),
.RRs1(RRs1),
.RRs2(RRs2),
.WRd(WRd),
.WrReg(WrReg),
.reset(reset),
.clk(clk)
);
// PC
pc thePC (
.CurrentPC(CurrentPC),
.JumpOrBranchPC(JumpOrBranchPC),
.JumpOrBranch(JumpOrBranch),
.NextPC(NextPC),
.reset(reset),
.clk(clk)
);
// Main Memory
main_mem #(
) theMem (
.DAddr(DAddr),
.IAddr(NextPC),
.DWData(WData),
.DRData(RData),
.IRData(Instruction),
.DWE(WrMem),
.DWidth(DWidth),
.reset(reset),
.clk(clk)
);
endmodule
+231
View File
@@ -0,0 +1,231 @@
// *********************************************************************************************
// Project Version : v1.0
// Project : [BCDC] Microtec Academy Course: Building a RISC-V CPU with SystemVerilog
// -----
// Copyright (c) : 2025 Fraunhofer IIS, Department IDS
// Created : 12.Jun.2025 by Lund University [commit 5b1e415]
// Last Modified : 23.Oct.2025 by Hussein Elzomor [commit 2f8f03d]
// -----
// HISTORY : Date By Comments
// ----------- --------- -------------------------------------------------
// 15.Oct.2025 H.Elzomor Moved PC and ALU logic to their respective files
// 15.Oct.2025 H.Elzomor Absorbed the branching logic into the decoder logic
// *********************************************************************************************
module decoder (
// PC
input logic[31:0] CurrentPC,
output logic[31:0] JumpOrBranchPC,
output logic JumpOrBranch,
// Memory
output logic[31:0] DAddr,
output logic[31:0] WData,
input logic[31:0] RData,
input logic[31:0] Instruction,
output logic WrMem,
output logic[1:0] DWidth,
// Register File
output logic[4:0] Rs1,
output logic[4:0] Rs2,
output logic[4:0] Rd,
input logic[31:0] RRs1,
input logic[31:0] RRs2,
output logic[31:0] WRd,
output logic WrReg,
// Protection
output logic Illegal
);
// Local Parameters
// OpCode: set a local parameter for each operation
localparam logic[6:0] opLd = 7'b0000011;
localparam logic[6:0] opAluImm = 7'b0010011;
localparam logic[6:0] opUpPC = 7'b0010111;
localparam logic[6:0] opSt = 7'b0100011;
localparam logic[6:0] opAlu = 7'b0110011;
localparam logic[6:0] opUpImm = 7'b0110111;
localparam logic[6:0] opBranch = 7'b1100011;
localparam logic[6:0] opJALR = 7'b1100111;
localparam logic[6:0] opJAL = 7'b1101111;
// Func7: set a local parameter for each function 7
localparam logic[6:0] f7neg = 7'b0100000;
// Func3: set a local parameter for each function 3
// Load/Store
localparam logic[2:0] f3byte = 3'b000;
localparam logic[2:0] f3half = 3'b001;
localparam logic[2:0] f3word = 3'b010;
localparam logic[2:0] f3byteU = 3'b100;
localparam logic[2:0] f3halfU = 3'b101;
// ALU
localparam logic[2:0] f3add = 3'b000;
localparam logic[2:0] f3sl = 3'b001;
localparam logic[2:0] f3slt = 3'b010;
localparam logic[2:0] f3sltU = 3'b011;
localparam logic[2:0] f3xor = 3'b100;
localparam logic[2:0] f3sr = 3'b101;
localparam logic[2:0] f3or = 3'b110;
localparam logic[2:0] f3and = 3'b111;
// Branch
localparam logic[2:0] f3beq = 3'b000;
localparam logic[2:0] f3bne = 3'b001;
localparam logic[2:0] f3blt = 3'b100;
localparam logic[2:0] f3bge = 3'b101;
localparam logic[2:0] f3bltU = 3'b110;
localparam logic[2:0] f3bgeU = 3'b111;
// Local Signals
// Instruction breakdown (excluding I/O)
logic[6:0] theOp;
logic[2:0] theFunct3;
logic[6:0] theFunct7;
logic[31:0] i_imm;
logic[31:0] s_imm;
logic[31:0] b_imm;
logic[31:0] u_imm;
logic[31:0] j_imm;
// ALU
logic[2:0] aluOp;
logic aluNegAr;
logic aluBypass;
logic[31:0] op1;
logic[31:0] op2;
logic[31:0] result;
logic eqFlag;
// Instruction breakdown: assign values
// OpCode and functions 3/7
assign theOp = Instruction[6:0];
assign theFunct3 = Instruction[14:12];
assign theFunct7 = Instruction[31:25];
// Registers
assign Rs1 = Instruction[19:15];
assign Rs2 = Instruction[24:20];
assign Rd = Instruction[11:7];
// Immediates
always_comb begin : Immediate_Generator
i_imm = {{21{Instruction[31]}}, Instruction[30:20]};
s_imm = {{21{Instruction[31]}}, Instruction[30:25], Instruction[11:7]};
b_imm = {{20{Instruction[31]}}, Instruction[7], Instruction[30:25], Instruction[11:8], 1'b0};
u_imm = {Instruction[31:12], 12'b0};
j_imm = {{12{Instruction[31]}}, Instruction[19:12], Instruction[20], Instruction[30:21], 1'b0};
end
// Decoder Logic
always_comb begin : Main_Decoder
// Factored port/signal values
JumpOrBranch = '0;
JumpOrBranchPC = '0;
DAddr = '0;
WData = RRs2;
WrMem = '0;
DWidth = f3word[1:0];
WrReg = '1;
Illegal = '0;
aluOp = theFunct3;
aluNegAr = '0;
aluBypass = '0;
op1 = RRs1;
op2 = RRs2;
// OpCode Cases
case(theOp)
opLd: begin
DAddr = RRs1 + i_imm;
DWidth = theFunct3[1:0];
aluBypass = '1;
op1 = RData;
case(theFunct3)
f3byte: op1[31:8] = {24{RData[7]}};
f3byteU: op1[31:8] = {24{1'b0}};
f3half: op1[31:16] = {16{RData[15]}};
f3halfU: op1[31:16] = {16{1'b0}};
f3word: ;
default: begin
Illegal = '1;
WrReg = '0;
JumpOrBranch = '1;
JumpOrBranchPC = CurrentPC;
end
endcase
end
opAluImm: begin
op2 = i_imm;
aluOp = theFunct3;
aluNegAr = (theFunct7 == f7neg) & (theFunct3 == f3sr);
end
opUpPC: begin
op1 = u_imm;
op2 = CurrentPC;
aluOp = f3add;
end
opSt: begin
WrReg = '0;
WrMem = '1;
DAddr = RRs1 + s_imm;
DWidth = theFunct3[1:0];
end
opAlu: begin
aluOp = theFunct3;
aluNegAr = (theFunct7 == f7neg) & ((theFunct3 == f3add) | (theFunct3 == f3sr));
end
opUpImm: begin
op1 = u_imm;
aluBypass = '1;
end
opBranch: begin
WrReg = '0;
JumpOrBranchPC = CurrentPC + b_imm;
aluOp = f3slt;
case(theFunct3)
f3beq : begin JumpOrBranch = ( eqFlag)? '1 : '0; end
f3bne : begin JumpOrBranch = (~eqFlag)? '1 : '0; end
f3blt : begin JumpOrBranch = ( result[0])? '1 : '0; end
f3bge : begin JumpOrBranch = (~result[0])? '1 : '0; end
f3bltU: begin aluOp = f3sltU; JumpOrBranch = ( result[0])? '1 : '0; end
f3bgeU: begin aluOp = f3sltU; JumpOrBranch = (~result[0])? '1 : '0; end
default: begin
Illegal = '1;
JumpOrBranch = '1;
JumpOrBranchPC = CurrentPC;
end
endcase
end
opJALR: begin
JumpOrBranch = '1;
JumpOrBranchPC = (RRs1 + i_imm) & 32'hFFFFFFFE;
op1 = CurrentPC;
op2 = 4;
aluOp = f3add;
end
opJAL: begin
JumpOrBranch = '1;
JumpOrBranchPC = CurrentPC + j_imm;
op1 = CurrentPC;
op2 = 4;
aluOp = f3add;
end
default: begin
Illegal = '1;
WrReg = '0;
JumpOrBranch = '1;
JumpOrBranchPC = CurrentPC;
end
endcase
end
// ALU module instantiation
alu theALU (
.aluOp(aluOp),
.aluNegAr(aluNegAr),
.aluBypass(aluBypass),
.op1(op1),
.op2(op2),
.result(result),
.eqFlag(eqFlag)
);
assign WRd = result;
endmodule
+120
View File
@@ -0,0 +1,120 @@
// *********************************************************************************************
// main_mem.sv - Macro-based implementation using MemGen_32_11
// *********************************************************************************************
// Replaces the behavioral flip-flop RAM with an SRAM macro wrapper.
//
// Key differences from the original:
// - Uses MemGen_32_11 (2048 words x 32 bits, single-port SRAM macro)
// - Time-multiplexed using the 25 MHz clock for two accesses per CPU cycle:
// clk12p5=0 -> instruction fetch (IAddr)
// clk12p5=1 -> data access (DAddr read/write)
// - Word-only writes; SB/SH instructions will be dropped (TODO: add RMW later)
// - MEM_INIT_FILE parameter kept for interface compatibility (not functional)
// *********************************************************************************************
module main_mem #(
parameter int ABits = 13
//parameter string MEM_INIT_FILE = ""
)(
input logic clk, // 12.5 MHz CPU clock (= clk12p5)
// input logic clk_25mhz, // NEW: 25 MHz memory clock
input logic reset,
input logic[31:0] DAddr,
input logic[31:0] IAddr,
input logic[31:0] DWData,
output logic[31:0] DRData,
output logic[31:0] IRData,
input logic DWE,
input logic[1:0] DWidth
);
//---------------------------------------------------------------------------
// Localparam
//---------------------------------------------------------------------------
localparam logic[1:0] _byte = 2'b00;
localparam logic[1:0] _half = 2'b01;
localparam logic[1:0] _word = 2'b10;
//---------------------------------------------------------------------------
// Time-multiplexing logic
//
// The CPU runs on clk12p5 (half of clk_25mhz).
// We use clk_25mhz to drive the memory; within one CPU cycle:
// - During clk12p5 LOW: present instruction address
// - During clk12p5 HIGH: present data address
//
// The macro latches the address on the rising edge of its own clock (clk_25mhz),
// so we select which address to send based on the current phase.
//---------------------------------------------------------------------------
logic [10:0] mem_addr; // 11-bit word address for MemGen_32_11
logic [31:0] mem_wr_data;
logic mem_wr_en;
logic mem_rd_en;
logic [31:0] mem_rd_data;
// Phase: 0 = instruction fetch, 1 = data access
// Since clk12p5 rises on clk_25mhz rising edge, clk12p5 itself tells us the phase
wire phase_is_data = clk; // clk = clk12p5
always_comb begin
if (phase_is_data) begin
// Data phase
mem_addr = DAddr[12:2];
mem_wr_data = DWData;
mem_wr_en = DWE && !reset && (DWidth == _word);
mem_rd_en = !DWE;
end else begin
// Instruction phase
mem_addr = IAddr[12:2];
mem_wr_data = 32'h0;
mem_wr_en = 1'b0;
mem_rd_en = 1'b1;
end
end
//---------------------------------------------------------------------------
// Single memory macro - time-multiplexed
//---------------------------------------------------------------------------
MemGen_32_11 u_mem (
.chip_en (1'b1),
.clock (clk_25mhz), // 2x CPU clock - enables dual access per CPU cycle
.addr (mem_addr),
.rd_en (mem_rd_en),
.rd_data (mem_rd_data),
.wr_en (mem_wr_en),
.wr_data (mem_wr_dat)
);
//---------------------------------------------------------------------------
// Output capture
//
// On each CPU cycle, we capture:
// - IRData: the instruction read during instruction phase
// - DRData: the data read during data phase
//
// The macro delivers rd_data one clk_25mhz cycle after the address.
//---------------------------------------------------------------------------
// Capture IRData at the end of the instruction phase (when data phase starts)
always_ff @(posedge clk_25mhz) begin
if (reset) begin
IRData <= 32'h0;
end else if (!phase_is_data) begin
// We just presented the data address; the read of the previous
// instruction address is now available on mem_rd_data
// (Note: timing requires verification against macro characteristics)
IRData <= mem_rd_data;
end
end
// Capture DRData at the end of the data phase (when instruction phase starts)
always_ff @(posedge clk_25mhz) begin
if (reset) begin
DRData <= 32'h0;
end else if (phase_is_data) begin
DRData <= mem_rd_data;
end
end
endmodule
+142
View File
@@ -0,0 +1,142 @@
// *********************************************************************************************
// Project Version : v1.0
// Project : [BCDC] Microtec Academy Course: Building a RISC-V CPU with SystemVerilog
// -----
// Copyright (c) : 2025 Fraunhofer IIS, Department IDS
// Created : 12.Jun.2025 by Lund University [commit 5b1e415]
// Last Modified : 23.Oct.2025 by Aliakbar Merchant [commit 2f8f03d]
// -----
// HISTORY : Date By Comments
// ----------- ---------- -------------------------------------------------
// 22.Oct.2025 A.Merchant Added reset handling condition for Instr. read logic
// 22.Oct.2025 A.Merchant Added reset handling condition for data write logic
// *********************************************************************************************
`default_nettype wire
module main_mem #(
parameter int ABits = 13 // Number of address bits
//parameter string MEM_INIT_FILE = "" // Optional memory initializations file
) (
input logic clk, // Clock
input logic reset, // Active high sync reset
input logic[31:0] DAddr, // Data Address
input logic[31:0] IAddr, // Instruction Address
input logic[31:0] DWData, // Data to write
output logic[31:0] DRData, // Data read
output logic[31:0] IRData, // Instruction read
input logic DWE, // Data write enable, 1=Write
input logic [1:0] DWidth // Access width (byte, half word, word)
);
// Local Parameter
localparam logic[1:0] _byte = 2'b00; // byte: 8 bits
localparam logic[1:0] _half = 2'b01; // half: 16 bits
localparam logic[1:0] _word = 2'b10; // word: 32 bits
// Local Signals
//logic[31:0] RAM[2**(ABits-2)-1:0]; // Memory array 8KB(8192): ignores lowest 2 bits as 32bit-word
logic [31:0] irTmp;
logic[31:0] drTmp; // Temporary register to hold the data read from RAM.
logic [10:0] mem_addr; // 11-bit word address for MemGen_32_11
logic [31:0] mem_wdata; // 32-bit data bus for MemGen_32_11
logic [31:0] mem_rdata; // 32-bit data bus for MemGen_32_11
MemGen_32_11 RAM (
.chip_en (1'b1),
.clock (clk),
.addr (mem_addr),
.rd_en (!DWE),
.rd_data (mem_rdata),
.wr_en (DWE),
.wr_data (mem_wdata)
);
// memory initilizations
// initial begin
//if (MEM_INIT_FILE != "") begin
// $readmemh(MEM_INIT_FILE, RAM);
// end
// end
//---------------------------------------------------------------------------//
//--------------------------- DATA WRITE LOGIC ---------------------------//
//---------------------------------------------------------------------------//
always_ff @(negedge clk) begin
if (reset) begin
mem_addr <= 0;
end else begin
if (DWE) begin
mem_addr <= DAddr[(ABits-1):2];
// RAM[DAddr[(ABits-1):2]] <= DWData;
case (DWidth)
_word:
mem_wdata <= DWData;
_half:
case (DAddr[1])
1'b0: mem_wdata [31:16] <= DWData[15:0];
1'b1: mem_wdata [15: 0] <= DWData[15:0];
endcase
_byte:
case (DAddr[1:0])
2'b00: mem_wdata [31:24] <= DWData[7:0];
2'b01: mem_wdata [23:16] <= DWData[7:0];
2'b10: mem_wdata [15: 8] <= DWData[7:0];
2'b11: mem_wdata [ 7: 0] <= DWData[7:0];
endcase
default: ;
endcase
end else begin
mem_addr <= IAddr[(ABits-1):2];
end
end
end
//---------------------------------------------------------------------------//
//--------------------------- DATA READ LOGIC ----------------------------//
//---------------------------------------------------------------------------//
always_ff @(negedge clk) begin
drTmp <= mem_rdata;
end
always_comb begin
case (DWidth)
_word:
DRData = drTmp;
_half:
case (DAddr[1])
1'b0: DRData = {16'b0, drTmp[31:16]};
1'b1: DRData = {16'b0, drTmp[15: 0]};
endcase
_byte:
case (DAddr[1:0])
2'b00: DRData = {24'b0, drTmp[31:24]};
2'b01: DRData = {24'b0, drTmp[23:16]};
2'b10: DRData = {24'b0, drTmp[15: 8]};
2'b11: DRData = {24'b0, drTmp[ 7: 0]};
endcase
default: ;
endcase
end
//---------------------------------------------------------------------------//
//----------------------- INSTRUCTION READ LOGIC -------------------------//
//---------------------------------------------------------------------------//
//
//fetch intrcution from memory into IRData
always_ff @(posedge clk) begin
if (reset) begin
IRData <= mem_rdata;
end
else begin
IRData <= mem_rdata;
end
end
endmodule
+15
View File
@@ -0,0 +1,15 @@
#--------------------------------------------------------------------
# date : Thu May 28 12:01:37 CEST 2026
# ppid/pid : 2439771/2439781
# hostname : efiapps0.ads1.fh-nuernberg.de
# arch/os : x86_64/Linux-4.18.0-553.123.1.el8_10.x86_64
# install : /applications/SiemensEDA/siemenseda2023/Oasys-RTL-2022.2.R1
# currdir : /users/projekte/projekt01/RISC-V_w_RAM-Macros/riscv_rtl/hw/rtl
# logfile : /users/projekte/projekt01/RISC-V_w_RAM-Macros/riscv_rtl/hw/rtl/oasys.log.00
# tmpdir : /tmp/oasys.2439771/
#--------------------------------------------------------------------
# Starting Interactive Session
exit
#--------------------------------------------------------------------
# End Session at Thu May 28 13:20:20 CEST 2026
#--------------------------------------------------------------------
+23
View File
@@ -0,0 +1,23 @@
#--------------------------------------------------------------------
# date : Thu May 28 13:29:15 CEST 2026
# ppid/pid : 2451524/2451534
# hostname : efiapps0.ads1.fh-nuernberg.de
# arch/os : x86_64/Linux-4.18.0-553.123.1.el8_10.x86_64
# install : /applications/SiemensEDA/siemenseda2023/Oasys-RTL-2022.2.R1
# currdir : /users/projekte/projekt01/RISC-V_w_RAM-Macros/riscv_rtl/hw/rtl
# logfile : /users/projekte/projekt01/RISC-V_w_RAM-Macros/riscv_rtl/hw/rtl/oasys.log.01
# tmpdir : /tmp/oasys.2451524/
#--------------------------------------------------------------------
# Starting Interactive Session
ls
cd ..
ls
cd ..
cd ..
ls
source scripts_risc_v/1_read_design.tcl
source scripts_risc_v/2_synthesize_optimize.tcl
exit
#--------------------------------------------------------------------
# End Session at Thu May 28 13:42:47 CEST 2026
#--------------------------------------------------------------------
View File
+317
View File
@@ -0,0 +1,317 @@
@/users/projekte/projekt01/RISC-V_w_RAM-Macros/riscv_rtl/hw/rtl/oasys.log.02:1093
libc: 2.28-stable
Timestamp: 1779968572.056193725
---
PID=2457562 0.129170598 0.075018 0.054153 program start
Complete list of environment variables at program start
_ /applications/SiemensEDA/siemenseda2023/Oasys-RTL-2022.2.R1/bin/Linux-x86_64-O/oasysGui
BASH_FUNC_which%% {() { ( alias;
eval ${which_declare} ) | /usr/bin/which --tty-only --read-alias --read-functions --show-tilde --show-dot $@
}}
CALIBRE_HOME /applications/SiemensEDA/siemenseda2023/calibre/aok_cal_2023.4_39.23
CDS_DDIEXPORT /applications/Cadence/cadence2022/DDIEXPORT2233
CDS_GENUS /applications/Cadence/cadence2022/DDIEXPORT2233/GENUS*
CDS_INNOVUS /applications/Cadence/cadence2022/DDIEXPORT2233/INNOVUS*
CDS_JLS /applications/Cadence/cadence2022/DDIEXPORT2233/JLS*
CDS_LIC_FILE 1816@141.75.245.12
CDS_SSV /applications/Cadence/cadence2022/SSV2213
COLORTERM truecolor
DBUS_SESSION_BUS_ADDRESS unix:path=/run/user/1083946113/bus,guid=02a4782d1dbcb9e9f51311946a16bc26
DBUS_STARTER_ADDRESS unix:path=/run/user/1083946113/bus,guid=02a4782d1dbcb9e9f51311946a16bc26
DBUS_STARTER_BUS_TYPE session
DESKTOP_SESSION gnome-classic
DISPLAY :10
ENV_VER 1
FORMALITY /applications/Synopsys/synopsys2022/fm/U-2022.12-SP4
GNOME_DESKTOP_SESSION_ID this-is-deprecated
GNOME_SHELL_SESSION_MODE classic
GNOME_TERMINAL_SCREEN /org/gnome/Terminal/screen/46eff583_4eec_45e6_973b_99403434080c
GNOME_TERMINAL_SERVICE :1.207
HISTCONTROL ignoredups
HISTSIZE 1000
HOME /users/ads1/charapallivenkatsaja/linux
HOSTNAME efiapps0.ads1.fh-nuernberg.de
INVOCATION_ID ad18f9577c3a4ac89ac41411f6a6e0c9
JOURNAL_STREAM 9:20654617
KRB5CCNAME /var/opt/thinlinc/sessions/charapallivenkatsaja/10/krb5cc
LANG en_US.UTF-8
LANGUAGE en_US
LATTICE /applications/Lattice
LC_NUMERIC en_US.UTF-8
LD_LIBRARY_PATH /applications/SiemensEDA/siemenseda2023/Oasys-RTL-2022.2.R1/lib/Linux-x86_64-O:/opt/thinlinc/lib64:/opt/thinlinc/lib
LESSOPEN {||/usr/bin/lesspipe.sh %s}
LM_LICENSE_FILE 1818@141.75.245.12:1812@141.75.245.10:1810@141.75.245.10
LOGNAME charapallivenkatsaja
LS_COLORS {rs=0:di=38;5;33:ln=38;5;51:mh=00:pi=40;38;5;11:so=38;5;13:do=38;5;5:bd=48;5;232;38;5;11:cd=48;5;232;38;5;3:or=48;5;232;38;5;9:mi=01;05;37;41:su=48;5;196;38;5;15:sg=48;5;11;38;5;16:ca=48;5;196;38;5;226:tw=48;5;10;38;5;16:ow=48;5;10;38;5;21:st=48;5;21;38;5;15:ex=38;5;40:*.tar=38;5;9:*.tgz=38;5;9:*.arc=38;5;9:*.arj=38;5;9:*.taz=38;5;9:*.lha=38;5;9:*.lz4=38;5;9:*.lzh=38;5;9:*.lzma=38;5;9:*.tlz=38;5;9:*.txz=38;5;9:*.tzo=38;5;9:*.t7z=38;5;9:*.zip=38;5;9:*.z=38;5;9:*.dz=38;5;9:*.gz=38;5;9:*.lrz=38;5;9:*.lz=38;5;9:*.lzo=38;5;9:*.xz=38;5;9:*.zst=38;5;9:*.tzst=38;5;9:*.bz2=38;5;9:*.bz=38;5;9:*.tbz=38;5;9:*.tbz2=38;5;9:*.tz=38;5;9:*.deb=38;5;9:*.rpm=38;5;9:*.jar=38;5;9:*.war=38;5;9:*.ear=38;5;9:*.sar=38;5;9:*.rar=38;5;9:*.alz=38;5;9:*.ace=38;5;9:*.zoo=38;5;9:*.cpio=38;5;9:*.7z=38;5;9:*.rz=38;5;9:*.cab=38;5;9:*.wim=38;5;9:*.swm=38;5;9:*.dwm=38;5;9:*.esd=38;5;9:*.jpg=38;5;13:*.jpeg=38;5;13:*.mjpg=38;5;13:*.mjpeg=38;5;13:*.gif=38;5;13:*.bmp=38;5;13:*.pbm=38;5;13:*.pgm=38;5;13:*.ppm=38;5;13:*.tga=38;5;13:*.xbm=38;5;13:*.xpm=38;5;13:*.tif=38;5;13:*.tiff=38;5;13:*.png=38;5;13:*.svg=38;5;13:*.svgz=38;5;13:*.mng=38;5;13:*.pcx=38;5;13:*.mov=38;5;13:*.mpg=38;5;13:*.mpeg=38;5;13:*.m2v=38;5;13:*.mkv=38;5;13:*.webm=38;5;13:*.ogm=38;5;13:*.mp4=38;5;13:*.m4v=38;5;13:*.mp4v=38;5;13:*.vob=38;5;13:*.qt=38;5;13:*.nuv=38;5;13:*.wmv=38;5;13:*.asf=38;5;13:*.rm=38;5;13:*.rmvb=38;5;13:*.flc=38;5;13:*.avi=38;5;13:*.fli=38;5;13:*.flv=38;5;13:*.gl=38;5;13:*.dl=38;5;13:*.xcf=38;5;13:*.xwd=38;5;13:*.yuv=38;5;13:*.cgm=38;5;13:*.emf=38;5;13:*.ogv=38;5;13:*.ogx=38;5;13:*.aac=38;5;45:*.au=38;5;45:*.flac=38;5;45:*.m4a=38;5;45:*.mid=38;5;45:*.midi=38;5;45:*.mka=38;5;45:*.mp3=38;5;45:*.mpc=38;5;45:*.ogg=38;5;45:*.ra=38;5;45:*.wav=38;5;45:*.oga=38;5;45:*.opus=38;5;45:*.spx=38;5;45:*.xspf=38;5;45:}
MAIL /var/spool/mail/charapallivenkatsaja
MANAGERPID 2391729
MANPATH /applications/SiemensEDA/siemenseda2023/Oasys-RTL-2022.2.R1/doc/man:
MGC_AMS_HOME /applications/SiemensEDA/siemenseda2023/amsv
MGC_HOME /applications/SiemensEDA/siemenseda2023
MGLS_HOME /applications/SiemensEDA/siemenseda2023/questasim/linux_x86_64/mgls
MGLS_LICENSE_FILE 1810@141.75.245.10
MODELTECH /applications/SiemensEDA/siemenseda2023/questasim
MTI_VCO_MODE 64
NIOS2_ROOTDIR /applications/intelFPGA/22.1/nios2eds
OASYSLD_LICENSE_FILE /applications/SiemensEDA/siemenseda2023/Oasys-RTL-2022.2.R1/license.lic
PATH /applications/SiemensEDA/siemenseda2023/Oasys-RTL-2022.2.R1/bin:/applications/SiemensEDA/siemenseda2023/Oasys-RTL-2022.2.R1/bin/Linux-x86_64-O:/applications/SiemensEDA/siemenseda2023/Oasys-RTL-2022.2.R1/lib/share/formalpro:/applications/SiemensEDA/siemenseda2023/Oasys-RTL-2022.2.R1/lib/share/onespin:/applications/SiemensEDA/siemenseda2023/Oasys-RTL-2022.2.R1/lib/share/slec:/applications/th_tools/scripts:/applications/intelFPGA/22.1/quartus/bin:/applications/intelFPGA/22.1/quartus/qsys/bin:/applications/intelFPGA/22.1/nios2eds:/applications/Lattice/radiant/2023.1/bin/lin64:/applications/Synopsys/synopsys2022/syn/U-2022.12-SP4/amd64/syn/bin:/applications/Synopsys/synopsys2022/scl/2022.12/linux64/bin:/applications/Synopsys/synopsys2022/fm/U-2022.12-SP4/bin:/applications/Synopsys/synopsys2022/txs/U-2022.12-SP4/bin:/applications/Synopsys/synopsys2022/lc/V-2023.12/bin:/applications/th_tools/scripts:/applications/intelFPGA/22.1/quartus/bin:/applications/intelFPGA/22.1/quartus/qsys/bin:/applications/intelFPGA/22.1/nios2eds:/applications/Lattice/radiant/2023.1/bin/lin64:/applications/Synopsys/synopsys2022/syn/U-2022.12-SP4/amd64/syn/bin:/applications/Synopsys/synopsys2022/scl/2022.12/linux64/bin:/applications/Synopsys/synopsys2022/fm/U-2022.12-SP4/bin:/applications/Synopsys/synopsys2022/txs/U-2022.12-SP4/bin:/applications/Synopsys/synopsys2022/lc/V-2023.12/bin:/users/ads1/charapallivenkatsaja/linux/.local/bin:/users/ads1/charapallivenkatsaja/linux/bin:/bin:/usr/bin:/opt/thinlinc/bin:/usr/local/bin:/usr/bin/X11:/sbin:/usr/sbin:/usr/local/sbin:/applications/Cadence/cadence2022/DDIEXPORT2233/bin:/applications/Cadence/cadence2022/SSV2213/bin:/applications/SiemensEDA/siemenseda2023/questasim/bin:/applications/SiemensEDA/siemenseda2023/questasim/linux_x86_64:/applications/SiemensEDA/siemenseda2023/questasim/vco:/applications/SiemensEDA/siemenseda2023/questasim/linux_x86_64/mgls/bin:/applications/SiemensEDA/siemenseda2023/amsv/bin:/applications/SiemensEDA/siemenseda2023/amsv/modeltech/bin:/applications/SiemensEDA/siemenseda2023/calibre/aok_cal_2023.4_39.23/bin:/applications/SiemensEDA/siemenseda2023/tessent/bin:/applications/SiemensEDA/siemenseda2023/oasys/bin:/applications/SiemensEDA/siemenseda2023/precision/bin:/applications/Cadence/cadence2022/DDIEXPORT2233/bin:/applications/Cadence/cadence2022/SSV2213/bin:/applications/SiemensEDA/siemenseda2023/questasim/bin:/applications/SiemensEDA/siemenseda2023/questasim/linux_x86_64:/applications/SiemensEDA/siemenseda2023/questasim/vco:/applications/SiemensEDA/siemenseda2023/questasim/linux_x86_64/mgls/bin:/applications/SiemensEDA/siemenseda2023/amsv/bin:/applications/SiemensEDA/siemenseda2023/amsv/modeltech/bin:/applications/SiemensEDA/siemenseda2023/calibre/aok_cal_2023.4_39.23/bin:/applications/SiemensEDA/siemenseda2023/tessent/bin:/applications/SiemensEDA/siemenseda2023/oasys/bin:/applications/SiemensEDA/siemenseda2023/precision/bin
PCSCTUN_COOKIE /var/opt/thinlinc/sessions/charapallivenkatsaja/10/pcsctun-cookie
PCSCTUN_SERVER 127.0.0.1:5006
PULSE_COOKIE /var/opt/thinlinc/sessions/charapallivenkatsaja/10/pulse-cookie
PULSE_RUNTIME_PATH /var/opt/thinlinc/sessions/charapallivenkatsaja/10/pulse
PULSE_SERVER {/var/opt/thinlinc/sessions/charapallivenkatsaja/10/pulse/native 127.0.0.1:5005}
PWD /users/projekte/projekt01/RISC-V_w_RAM-Macros/riscv_rtl/hw/rtl
QSYS_ROOTDIR /applications/intelFPGA/22.1/quartus/qsys/bin
QT_IM_MODULE ibus
QUARTUS /applications/intelFPGA
QUARTUS_ROOTDIR /applications/intelFPGA/22.1/quartus
RT_CMD {/applications/SiemensEDA/siemenseda2023/oasys/bin/oasys }
RT_HOME /applications/SiemensEDA/siemenseda2023/Oasys-RTL-2022.2.R1
RT_LIBPATH /applications/SiemensEDA/siemenseda2023/Oasys-RTL-2022.2.R1/lib
RT_MANPATH /applications/SiemensEDA/siemenseda2023/Oasys-RTL-2022.2.R1/doc/man
RT_PID 2457552
RT_SIGSTKSZ 16
RT_TCL_PATH /applications/SiemensEDA/siemenseda2023/Oasys-RTL-2022.2.R1/tcl
RT_TMP /tmp/oasys.2457552
RT_WRAPPER_SCRIPT /applications/SiemensEDA/siemenseda2023/oasys/bin/oasys
SCRIPTS /applications/th_tools/scripts
SESSION_MANAGER local/unix:@/tmp/.ICE-unix/2434259,unix/unix:/tmp/.ICE-unix/2434259
SHELL /bin/bash
SHLVL 4
SNPSLMD_LICENSE_FILE 1806@141.75.245.10
SSH_ASKPASS /usr/libexec/openssh/gnome-ssh-askpass
SSH_AUTH_SOCK /run/user/1083946113/keyring/ssh
SYNOPSYS /applications/Synopsys/synopsys2022/syn/U-2022.12-SP4
SYNOPSYS_TMAX /applications/Synopsys/synopsys2022/txs/U-2022.12-SP4
TCL_LIBRARY /applications/SiemensEDA/siemenseda2023/Oasys-RTL-2022.2.R1/tcl/library
TERM xterm-256color
TLPREFIX /opt/thinlinc
TLPROFILE gnome-classic
TLSESSIONDATA /var/opt/thinlinc/sessions/charapallivenkatsaja/10
TOWN Springfield
USER charapallivenkatsaja
USERNAME charapallivenkatsaja
VTE_VERSION 5204
which_declare {declare -f}
XAUTHORITY /var/opt/thinlinc/sessions/charapallivenkatsaja/10/Xauthority
XDG_CURRENT_DESKTOP GNOME-Classic:GNOME
XDG_DATA_DIRS /users/ads1/charapallivenkatsaja/linux/.local/share/flatpak/exports/share:/var/lib/flatpak/exports/share:/usr/local/share:/usr/share
XDG_MENU_PREFIX gnome-
XDG_RUNTIME_DIR /run/user/1083946113
XDG_SESSION_CLASS user
XDG_SESSION_DESKTOP gnome-classic
XDG_SESSION_ID 6060
XDG_SESSION_TYPE x11
XMODIFIERS @im=ibus
---
Timestamp: 1779968572.059144838
---
Soft resource limits:
Executing: /bin/bash -f -c {ulimit -a -S}
core file size (blocks, -c) 0
data seg size (kbytes, -d) unlimited
scheduling priority (-e) 0
file size (blocks, -f) unlimited
pending signals (-i) 191837
max locked memory (kbytes, -l) 64
max memory size (kbytes, -m) unlimited
open files (-n) 1024
pipe size (512 bytes, -p) 8
POSIX message queues (bytes, -q) 819200
real-time priority (-r) 0
stack size (kbytes, -s) 81920
cpu time (seconds, -t) unlimited
max user processes (-u) 191837
virtual memory (kbytes, -v) unlimited
file locks (-x) unlimited
---
Timestamp: 1779968572.060768504
---
Hard resource limits:
Executing: /bin/bash -f -c {ulimit -a -H}
core file size (blocks, -c) unlimited
data seg size (kbytes, -d) unlimited
scheduling priority (-e) 0
file size (blocks, -f) unlimited
pending signals (-i) 191837
max locked memory (kbytes, -l) 64
max memory size (kbytes, -m) unlimited
open files (-n) 262144
pipe size (512 bytes, -p) 8
POSIX message queues (bytes, -q) 819200
real-time priority (-r) 0
stack size (kbytes, -s) unlimited
cpu time (seconds, -t) unlimited
max user processes (-u) 191837
virtual memory (kbytes, -v) unlimited
file locks (-x) unlimited
---
Timestamp: 1779968572.061645115
---
CPU Information
processor : 0
vendor_id : AuthenticAMD
cpu family : 25
model : 1
model name : AMD EPYC 73F3 16-Core Processor
stepping : 1
microcode : 0xa0011d3
cpu MHz : 3499.999
cache size : 512 KB
physical id : 0
siblings : 1
core id : 0
cpu cores : 1
apicid : 0
initial apicid : 0
fpu : yes
fpu_exception : yes
cpuid level : 16
wp : yes
flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 syscall nx mmxext fxsr_opt pdpe1gb rdtscp lm constant_tsc rep_good nopl tsc_reliable nonstop_tsc cpuid extd_apicid pni pclmulqdq ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt aes xsave avx f16c rdrand hypervisor lahf_lm extapic cr8_legacy abm sse4a misalignsse 3dnowprefetch osvw topoext invpcid_single ibpb vmmcall fsgsbase bmi1 avx2 smep bmi2 erms invpcid rdseed adx smap clflushopt clwb sha_ni xsaveopt xsavec xgetbv1 xsaves clzero wbnoinvd arat umip pku ospke vaes vpclmulqdq rdpid overflow_recov succor fsrm
bugs : fxsave_leak sysret_ss_attrs null_seg spectre_v1 spectre_v2 spec_store_bypass srso
bogomips : 6999.99
TLB size : 2560 4K pages
clflush size : 64
cache_alignment : 64
address sizes : 45 bits physical, 48 bits virtual
power management:
processor : 1
physical id : 2
apicid : 2
initial apicid : 2
processor : 2
physical id : 4
apicid : 4
initial apicid : 4
processor : 3
physical id : 6
apicid : 6
initial apicid : 6
processor : 4
physical id : 8
apicid : 8
initial apicid : 8
processor : 5
physical id : 10
apicid : 10
initial apicid : 10
processor : 6
physical id : 12
apicid : 12
initial apicid : 12
processor : 7
physical id : 14
apicid : 14
initial apicid : 14
processor : 8
physical id : 16
apicid : 16
initial apicid : 16
processor : 9
physical id : 18
apicid : 18
initial apicid : 18
processor : 10
physical id : 20
apicid : 20
initial apicid : 20
processor : 11
physical id : 22
apicid : 22
initial apicid : 22
This host has 12 processors, with most parameters identical to the first one, except as noted above.
---
Timestamp: 1779968572.161364465
---
Miscellaneous system info for process PID=2457562
Recorded at Thu May 28 13:42:52 CEST 2026
Executing: uptime
13:42:52 up 20 days, 1:11, 5 users, load average: 1.99, 2.79, 2.57
Executing: uname -a
Linux efiapps0.ads1.fh-nuernberg.de 4.18.0-553.123.1.el8_10.x86_64 #1 SMP Mon May 4 13:45:48 EDT 2026 x86_64 x86_64 x86_64 GNU/Linux
Executing: free
total used free shared buff/cache available
Mem: 49166924 12854332 9280556 826488 27032036 34721076
Swap: 25165820 8312 25157508
Executing: ps u 2457562
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
charapa+ 2457562 13.0 0.1 438180 69168 pts/2 S+ 13:42 0:00 /applications/SiemensEDA/siemenseda2023/Oasys-RTL-2022.2.R1/bin/Linux-x86_64-O/oasysGui --
Executing: cat /etc/redhat-release
Red Hat Enterprise Linux release 8.9 (Ootpa)
Executing: ldd /applications/SiemensEDA/siemenseda2023/Oasys-RTL-2022.2.R1/bin/Linux-x86_64-O/oasysGui
linux-vdso.so.1 (0x00007fff5a525000)
libQt5PrintSupport.so.5 => /applications/SiemensEDA/siemenseda2023/Oasys-RTL-2022.2.R1/bin/Linux-x86_64-O/../../lib/Linux-x86_64-O/libQt5PrintSupport.so.5 (0x00007f7623103000)
libQt5Widgets.so.5 => /applications/SiemensEDA/siemenseda2023/Oasys-RTL-2022.2.R1/bin/Linux-x86_64-O/../../lib/Linux-x86_64-O/libQt5Widgets.so.5 (0x00007f76226ab000)
libQt5Gui.so.5 => /applications/SiemensEDA/siemenseda2023/Oasys-RTL-2022.2.R1/bin/Linux-x86_64-O/../../lib/Linux-x86_64-O/libQt5Gui.so.5 (0x00007f7621d0f000)
libQt5Core.so.5 => /applications/SiemensEDA/siemenseda2023/Oasys-RTL-2022.2.R1/bin/Linux-x86_64-O/../../lib/Linux-x86_64-O/libQt5Core.so.5 (0x00007f7621178000)
libmemsh-102.so => /applications/SiemensEDA/siemenseda2023/Oasys-RTL-2022.2.R1/bin/Linux-x86_64-O/../../lib/Linux-x86_64-O/libmemsh-102.so (0x00007f76235b0000)
libncurses.so.5 => /lib64/libncurses.so.5 (0x00007f7620f51000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f7620d31000)
libdl.so.2 => /lib64/libdl.so.2 (0x00007f7620b2d000)
librt.so.1 => /lib64/librt.so.1 (0x00007f7620925000)
libX11.so.6 => /lib64/libX11.so.6 (0x00007f76205e1000)
libz.so.1 => /lib64/libz.so.1 (0x00007f76203c9000)
libm.so.6 => /lib64/libm.so.6 (0x00007f7620047000)
libc.so.6 => /lib64/libc.so.6 (0x00007f761fc71000)
libgthread-2.0.so.0 => /lib64/libgthread-2.0.so.0 (0x00007f761fa6f000)
libglib-2.0.so.0 => /lib64/libglib-2.0.so.0 (0x00007f761f755000)
/lib64/ld-linux-x86-64.so.2 (0x00007f76233a4000)
libtinfo.so.5 => /lib64/libtinfo.so.5 (0x00007f761f52a000)
libxcb.so.1 => /applications/SiemensEDA/siemenseda2023/Oasys-RTL-2022.2.R1/bin/Linux-x86_64-O/../../lib/Linux-x86_64-O/libxcb.so.1 (0x00007f761f2f5000)
libgnutls.so.30 => /lib64/libgnutls.so.30 (0x00007f761ef04000)
libpcre.so.1 => /lib64/libpcre.so.1 (0x00007f761ec93000)
libXau.so.6 => /lib64/libXau.so.6 (0x00007f761ea8f000)
libXdmcp.so.6 => /lib64/libXdmcp.so.6 (0x00007f761e889000)
libp11-kit.so.0 => /lib64/libp11-kit.so.0 (0x00007f761e55f000)
libidn2.so.0 => /lib64/libidn2.so.0 (0x00007f761e341000)
libunistring.so.2 => /lib64/libunistring.so.2 (0x00007f761dfc0000)
libtasn1.so.6 => /lib64/libtasn1.so.6 (0x00007f761ddad000)
libnettle.so.6 => /lib64/libnettle.so.6 (0x00007f761db73000)
libhogweed.so.4 => /lib64/libhogweed.so.4 (0x00007f761d943000)
libgmp.so.10 => /lib64/libgmp.so.10 (0x00007f761d6ab000)
libffi.so.6 => /lib64/libffi.so.6 (0x00007f761d4a2000)
Examining disk space in the following directories:
Current directory: /users/projekte/projekt01/RISC-V_w_RAM-Macros/riscv_rtl/hw/rtl
Oasys' temp directory: /tmp/oasys.2457552/ (normalized path: /tmp/oasys.2457552)
RT_TMP directory: /tmp/oasys.2457552
Executing: df /users/projekte/projekt01/RISC-V_w_RAM-Macros/riscv_rtl/hw/rtl /tmp/oasys.2457552 /tmp/oasys.2457552
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/sdc1 10485760 2530136 7955624 25% /users
/dev/sda3 25582384 9713924 15868460 38% /
/dev/sda3 25582384 9713924 15868460 38% /
---
+29
View File
@@ -0,0 +1,29 @@
*******************************************************************
* Oasys-RTL™ - release 2022.2.R1 *
* *
* This material contains trade secrets or otherwise confidential *
* information owned by Siemens Industry Software Inc. or its *
* affiliates (collectively, "SISW"), or its licensors. Access to *
* and use of this information is strictly limited as set forth *
* in the Customer’s applicable agreements with SISW. *
* *
* Unpublished work. © 2023 Siemens *
* *
* Program : ../bin/Linux-x86_64-O/oasysGui *
* Version : 22.2-p002 *
* Date : Mon Jan 16 21:36:23 PST 2023 *
* Build : releases/22.2-54756.0-CentOS_6.5-O *
*******************************************************************
config sdc-v1.7-cpd cli cmd explore mxdb o2n fp rta mpg-m-w dft
loading: oa2tessent-d ctl verify edit bt upf-c aos conc ipc-l vcd o2pp prot int oa2ap
checked out license: psyncore
date : Thu May 28 12:01:37 CEST 2026
ppid/pid : 2439771/2439781
hostname : efiapps0.ads1.fh-nuernberg.de
arch/os : x86_64/Linux-4.18.0-553.123.1.el8_10.x86_64
install : /applications/SiemensEDA/siemenseda2023/Oasys-RTL-2022.2.R1
currdir : /users/projekte/projekt01/RISC-V_w_RAM-Macros/riscv_rtl/hw/rtl
logfile : /users/projekte/projekt01/RISC-V_w_RAM-Macros/riscv_rtl/hw/rtl/oasys.log.00
tmpdir : /tmp/oasys.2439771/
> source /applications/SiemensEDA/siemenseda2023/Oasys-RTL-2022.2.R1/tcl/library/history.tcl
File diff suppressed because one or more lines are too long
+16
View File
@@ -0,0 +1,16 @@
*******************************************************************
* Oasys-RTL™ - release 2022.2.R1 *
* *
* This material contains trade secrets or otherwise confidential *
* information owned by Siemens Industry Software Inc. or its *
* affiliates (collectively, "SISW"), or its licensors. Access to *
* and use of this information is strictly limited as set forth *
* in the Customer’s applicable agreements with SISW. *
* *
* Unpublished work. © 2023 Siemens *
* *
* Program : ../bin/Linux-x86_64-O/oasysGui *
* Version : 22.2-p002 *
* Date : Mon Jan 16 21:36:23 PST 2023 *
* Build : releases/22.2-54756.0-CentOS_6.5-O *
*******************************************************************
+37
View File
@@ -0,0 +1,37 @@
// *********************************************************************************************
// Project Version : v1.0
// Project : [BCDC] Microtec Academy Course: Building a RISC-V CPU with SystemVerilog
// -----
// Copyright (c) : 2025 Fraunhofer IIS, Department IDS
// Created : 12.Jun.2025 by Lund University [commit 5b1e415]
// Last Modified : 23.Oct.2025 by Bomin Kim [commit 2f8f03d]
// -----
// HISTORY : Date By Comments
// ----------- --------- -------------------------------------------------
// 15.Oct.2025 Bomin Kim Moved NextPC logic from decoder into PC
// 15.Oct.2025 Bomin Kim Removed reset condition from combinational logic
// *********************************************************************************************
module pc (
output logic[31:0] CurrentPC,
input logic[31:0] JumpOrBranchPC,
input logic JumpOrBranch,
output logic[31:0] NextPC,
input logic reset,
input logic clk
);
// NextPC logic; next-state function
always_comb begin : Next_PC
if (JumpOrBranch) NextPC = JumpOrBranchPC;
else NextPC = CurrentPC + 4;
end
// CurrentPC logic; state register
always_ff @(posedge clk) begin
if (reset) CurrentPC <= '0;
else CurrentPC <= NextPC;
end
endmodule
+44
View File
@@ -0,0 +1,44 @@
// *********************************************************************************************
// Project Version : v1.0
// Project : [BCDC] Microtec Academy Course: Building a RISC-V CPU with SystemVerilog
// -----
// Copyright (c) : 2025 Fraunhofer IIS, Department IDS
// Created : 12.Jun.2025 by Lund University [commit 5b1e415]
// Last Modified : 23.Oct.2025 by Bomin Kim [commit 2f8f03d]
// -----
// HISTORY : Date By Comments
// ----------- --------- -------------------------------------------------
// 15.Oct.2025 Bomin Kim Added reset handling condition
// *********************************************************************************************
module reg_file (
input logic[4:0] Rs1,
input logic[4:0] Rs2,
input logic[4:0] Rd,
output logic[31:0] RRs1,
output logic[31:0] RRs2,
input logic[31:0] WRd,
input logic WrReg,
input logic reset,
input logic clk
);
// Define the registers array
logic[31:0] registers[31:1];
// Register file reading
assign RRs1 = Rs1 == 0 ? '0 : registers[Rs1];
assign RRs2 = Rs2 == 0 ? '0 : registers[Rs2];
// Register file writing
always_ff @(posedge clk) begin
if (reset) begin
for (int i=1; i<32; i++)
registers[i] <= '0;
end else begin
if (WrReg & Rd != 0) registers[Rd] <= WRd;
end
end
endmodule