Loading files
6d2e42836This file is pinned to the selected release. Download the original to open it in your design tool.
// Copyright 2019- RSD contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
`timescale 1ns/1ps
import DumperTypes::*;
import BasicTypes::*;
import CacheSystemTypes::*;
import MemoryTypes::*;
import PipelineTypes::*;
import RenameLogicTypes::*;
import SchedulerTypes::*;
import ActiveListIndexTypes::*;
import MicroOpTypes::*;
import LoadStoreUnitTypes::*;
import MemoryMapTypes::*;
import IO_UnitTypes::*;
import DebugTypes::*;
parameter STEP = 8; // 62.5Mhz
parameter HOLD = 2;
parameter SETUP = 2;
parameter WAIT = STEP*2-HOLD-SETUP;
parameter HOLD_PLUS_WAIT = HOLD + WAIT;
module TestMain;
//
// Check compiler directives.
//
`ifdef RSD_SYNTHESIS
initial begin
$error("Wrong compiler directive: RSD_SYNTHESIS");
$finish;
end
`endif
`ifndef RSD_FUNCTIONAL_SIMULATION
`ifndef RSD_POST_SYNTHESIS_SIMULATION
initial begin
$error("Neither RSD_FUNCTIONAL_SIMULATION nor RSD_POST_SYNTHESIS_SIMULATION is defined as a compiler directive.");
$finish;
end
`endif
`endif
//
// Functions
//
`ifdef RSD_FUNCTIONAL_SIMULATION
`ifndef RSD_POST_SYNTHESIS_SIMULATION
// RetirementRMTからコミット済の論理レジスタの値を得る
task GetCommittedRegisterValue(
input int commitNumInThisCycle,
output DataPath regData[ LREG_NUM ]
);
int rollbackNum;
PScalarRegNumPath phyRegNum[ LREG_NUM ];
ActiveListIndexPath alHeadPtr;
ActiveListEntry alHead;
int tmpSelect;
DataPath tmpRegData [ ISSUE_WIDTH ];
// Copy RMT to local variable.
for( int i = 0; i < LREG_NUM; i++ ) begin
phyRegNum[i] = main.main.core.retirementRMT.regRMT.debugValue[i];
end
// Update RRMT
alHeadPtr = main.main.core.activeList.headPtr;
for( int i = 0; i < commitNumInThisCycle; i++ ) begin
alHead = main.main.core.activeList.activeList.debugValue[ alHeadPtr ];
if ( alHead.writeReg ) begin
phyRegNum[ alHead.logDstRegNum ] = alHead.phyDstRegNum.regNum;
end
alHeadPtr++;
end
// Get regData
for( int i = 0; i < LSCALAR_NUM; i++ ) begin
regData[i] = main.main.core.registerFile.phyReg.debugValue[ phyRegNum[i] ];
end
`ifdef RSD_MARCH_FP_PIPE
for( int i = LSCALAR_NUM; i < LSCALAR_NUM + LSCALAR_FP_NUM; i++) begin
regData[i] = main.main.core.registerFile.phyFPReg.debugValue[ phyRegNum[i] ];
end
`endif
endtask
`endif
`endif
// These parameters are passed as command line arguments.
int MAX_TEST_CYCLES;
int SHOW_SERIAL_OUT;
int ENABLE_PC_GOAL;
string TEST_CODE;
string RSD_LOG_FILE;
string REG_CSV_FILE;
string DUMMY_DATA_FILE;
string codeFileName;
string regOutFileName;
string serialDumpFileName;
integer cycle;
integer entry;
integer dumpFlush; // A flag used for avoiding to dump flush more than once.
integer count;
string str;
DataPath regData[ LREG_NUM ];
integer commitNumInLastCycle;
integer numCommittedRISCV_Op;
integer numCommittedMicroOp;
real realTmp;
//
// Source of clock and reset
//
logic clk, rst, rstOut;
TestBenchClockGenerator #(
.STEP(STEP)
) clkgen (
.clk( clk ),
.rst( rst ),
.rstOut( rstOut )
);
//
// Main module
//
LED_Path ledOut;
LED_Path lastCommittedPC;
DebugRegister debugRegister;
logic rxd, txd;
logic serialWE;
SerialDataPath serialWriteData;
Main_Zynq_Wrapper main(
.clk_p( clk ),
.clk_n ( ~clk ),
.negResetIn( ~rst ),
.posResetOut( rstOut ),
.*
);
`ifdef RSD_SYNTHESIS_VIVADO
always_comb begin
debugRegister = main.debugRegister;
end
`endif
//
// Dumpers
//
logic enableDumpKanata;
logic enableDumpRegCSV;
KanataDumper kanataDumper;
RegisterFileHexDumper registerFileHexDumper;
RegisterFileCSV_Dumper registerFileCSV_Dumper;
SerialDumper serialDumper;
//
// Test Bench
//
initial begin
// init variable
dumpFlush = FALSE;
numCommittedRISCV_Op = 0;
numCommittedMicroOp = 0;
// settings
if( !$value$plusargs( "MAX_TEST_CYCLES=%d", MAX_TEST_CYCLES ) ) begin
MAX_TEST_CYCLES = 100;
end
if( !$value$plusargs( "TEST_CODE=%s", TEST_CODE ) ) begin
TEST_CODE = "Verification/TestCode/Fibonacci";
end
if( !$value$plusargs( "DUMMY_DATA_FILE=%s", DUMMY_DATA_FILE ) ) begin
DUMMY_DATA_FILE = "Verification/DummyData.hex";
end
if( !$value$plusargs( "SHOW_SERIAL_OUT=%d", SHOW_SERIAL_OUT ) ) begin
SHOW_SERIAL_OUT = 0;
end
if( !$value$plusargs( "ENABLE_PC_GOAL=%d", ENABLE_PC_GOAL ) ) begin
ENABLE_PC_GOAL = 1;
end
enableDumpKanata = FALSE;
if( $value$plusargs( "RSD_LOG_FILE=%s", RSD_LOG_FILE ) ) begin
enableDumpKanata = TRUE;
kanataDumper = new;
kanataDumper.Open( RSD_LOG_FILE );
end
enableDumpRegCSV = FALSE;
if( $value$plusargs( "REG_CSV_FILE=%s", REG_CSV_FILE ) ) begin
enableDumpRegCSV = TRUE;
registerFileCSV_Dumper = new;
registerFileCSV_Dumper.Open( REG_CSV_FILE );
end
codeFileName = { TEST_CODE, "/", "code.hex" };
regOutFileName = { TEST_CODE, "/", "reg.out.hex" };
serialDumpFileName = { TEST_CODE, "/", "serial.out.txt" };
serialDumper = new;
serialDumper.Init();
// Initialize memory
#STEP;
`ifdef RSD_FUNCTIONAL_SIMULATION
`ifndef RSD_POST_SYNTHESIS_SIMULATION
// Fill memory with dummy data
// see InitializedBlockRAM module in Primitives/RAM.sv in details
main.main.memory.body.FillDummyData(DUMMY_DATA_FILE, DUMMY_HEX_ENTRY_NUM);
// ファイル内容は物理メモリ空間の先頭から連続して展開される
// ファイル先頭 64KB は ROM とみなされ,残りが RAM の空間に展開される
// Physical 0x0_0000 - 0x0_ffff -> Logical 0x0000_0000 - 0x0000_ffff: ROM (64KB)
// Physical 0x1_0000 - 0x4_ffff -> Logical 0x8000_0000 - 0x8003_ffff: RAM (256KB)
// たとえば 128KB のファイルの場合,
// 先頭 64KB は 論理空間の 0x0000_0000 - 0x0000_FFFF に,
// 後続 64KB は 論理空間の 0x8000_0000 - 0x8000_FFFF に展開されることになる
main.main.memory.body.InitializeMemory(codeFileName);
`endif
`endif
//
// Simulation body
//
@(negedge rstOut);
for( cycle = 0; cycle < MAX_TEST_CYCLES; cycle++ ) begin
if (SHOW_SERIAL_OUT == 0 && (clkgen.kanataCycle < 10000 || clkgen.kanataCycle % 10000 == 0)) begin
$display( "%d cycle %d KanataCycle %tps", clkgen.cycle, clkgen.kanataCycle, $time );
end
@(posedge clk);
#HOLD_PLUS_WAIT;
serialDumper.CheckSignal( serialWE, serialWriteData, SHOW_SERIAL_OUT );
// Dump RSD.log for Kanata
if ( enableDumpKanata ) begin
kanataDumper.DumpCycle( debugRegister );
end
// Dump values of logical register file to a CSV file.
`ifdef RSD_FUNCTIONAL_SIMULATION
`ifndef RSD_POST_SYNTHESIS_SIMULATION
if ( enableDumpRegCSV ) begin
registerFileCSV_Dumper.ProceedCycle();
for ( int i = 0; i < COMMIT_WIDTH; i++ ) begin
if ( main.main.core.cmStage.commit[i] ) begin
GetCommittedRegisterValue( i, regData );
registerFileCSV_Dumper.Dump( main.main.core.cmStage.alReadData[i].pc, regData );
end
end
end
`endif
`endif
// Count number of committed Ops.
for ( int i = 0; i < COMMIT_WIDTH; i++ ) begin
if ( debugRegister.cmReg[i].commit ) begin
numCommittedMicroOp += 1;
if ( debugRegister.cmReg[i].opId.mid == 0 ) begin
numCommittedRISCV_Op += 1;
end
end
end
// Check end of simulation.
lastCommittedPC = ledOut;
if ( ENABLE_PC_GOAL != 0 && lastCommittedPC == PC_GOAL[LED_WIDTH-1:0] ) begin
// lastCommittedPC は 16bit 分しか外に出てきていないので,下位で判定しておく
$display( "PC reached PC_GOAL: %08x", PC_GOAL );
break;
end
end
// Close Dumper
serialDumper.DumpToFile( serialDumpFileName );
if ( enableDumpKanata ) kanataDumper.Close();
if ( enableDumpRegCSV ) registerFileCSV_Dumper.Close();
// Simulation Result
$display("Num of I$ misses: %d", debugRegister.perfCounter.numIC_Miss);
$display("Num of D$ load misses: %d", debugRegister.perfCounter.numLoadMiss);
$display("Num of D$ store misses: %d", debugRegister.perfCounter.numStoreMiss);
$display("Num of memory dependency prediction misses: %d", debugRegister.perfCounter.numStoreLoadForwardingFail);
$display("Num of store-load-forwarding misses: %d", debugRegister.perfCounter.numMemDepPredMiss);
$display("Num of branch prediction misses: %d", debugRegister.perfCounter.numBranchPredMiss);
$display("Num of branch prediction misses detected on decode: %d", debugRegister.perfCounter.numBranchPredMissDetectedOnDecode);
$display( "Num of committed RISC-V-ops: %d", numCommittedRISCV_Op );
$display( "Num of committed micro-ops: %d", numCommittedMicroOp );
if ( cycle != 0 ) begin
realTmp = cycle;
$display( "IPC (RISC-V instruction): %f", numCommittedRISCV_Op / realTmp );
$display( "IPC (micro-op): %f", numCommittedMicroOp / realTmp );
end
$display("Elapsed cycles: %d", cycle);
`ifdef RSD_FUNCTIONAL_SIMULATION
`ifndef RSD_POST_SYNTHESIS_SIMULATION
// Count the number of commit in the last cycle.
for ( count = 0; count < COMMIT_WIDTH; count++ ) begin
if ( !main.main.core.cmStage.commit[count] )
break;
end
commitNumInLastCycle = count;
// Dump Register File
GetCommittedRegisterValue( commitNumInLastCycle, regData );
registerFileHexDumper = new;
registerFileHexDumper.Open( regOutFileName );
registerFileHexDumper.Dump( lastCommittedPC, regData );
registerFileHexDumper.Close();
`endif
`endif
$finish;
end
endmodule