Skip to content

Commit

Permalink
Correcetly simulate passed time before first clock edge in verilator
Browse files Browse the repository at this point in the history
The FFI code used a default of 50 nanoseconds as time passed before the first clock edge.
This resulted in an unobservable reset pulse when used with `resetGenN d1` because  verilator's simulation time is off by a factor 1000.

Now derive the time before the clock edge as a single period of vexrisc clock domain.
  • Loading branch information
lmbollen committed Jan 10, 2025
1 parent 5123912 commit 276c0ab
Show file tree
Hide file tree
Showing 3 changed files with 22 additions and 12 deletions.
15 changes: 11 additions & 4 deletions clash-vexriscv/src/VexRiscv.hs
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,8 @@ vexRiscv dumpVcd clk rst cpuInput jtagInput =


vexRiscv#
:: KnownDomain dom
:: forall dom .
KnownDomain dom
=> DumpVcd
-> String
-> Clock dom
Expand Down Expand Up @@ -250,7 +251,12 @@ vexRiscv# dumpVcd !_sourcePath clk rst0
jtag_TCK0
jtag_TMS0
jtag_TDI0 = unsafePerformIO $ do
(v, initStage1, initStage2, stepRising, stepFalling, _shutDown) <- vexCPU dumpVcd
let
divRu a b = (a + b - 1) `div` b
domPeriodPs = natToNum @(DomainPeriod dom)
domPeriodHz = natToNum @(10^12) `divRu` domPeriodPs
domPeriodFs = hzToFs $ fromIntegral domPeriodHz
(v, initStage1, initStage2, stepRising, stepFalling, _shutDown) <- vexCPU dumpVcd domPeriodFs

-- Make sure all the inputs are defined
let
Expand Down Expand Up @@ -520,6 +526,7 @@ vexRiscv# dumpVcd !_sourcePath clk rst0
-- the internal CPU state
vexCPU ::
DumpVcd ->
Femtoseconds ->
IO
( Ptr VexRiscv
, Ptr VexRiscv -> NON_COMB_INPUT -> IO OUTPUT -- initStage1
Expand All @@ -528,7 +535,7 @@ vexCPU ::
, Ptr VexRiscv -> Word64 -> COMB_INPUT -> IO () -- falling
, Ptr VexRiscv -> IO ()
)
vexCPU dumpVcd = do
vexCPU dumpVcd (fromIntegral . unFemtoseconds -> domPeriodFs :: Word64) = do
v <- vexrInit
vcd <- case dumpVcd of
NoDumpVcd -> pure nullPtr
Expand All @@ -541,7 +548,7 @@ vexCPU dumpVcd = do
initStage1 vPtr nonCombInput =
alloca $ \nonCombInputFFI -> alloca $ \outputFFI -> do
poke nonCombInputFFI nonCombInput
vexrInitStage1 vcd vPtr nonCombInputFFI outputFFI
vexrInitStage1 vcd domPeriodFs vPtr nonCombInputFFI outputFFI
peek outputFFI

{-# NOINLINE initStage2 #-}
Expand Down
2 changes: 1 addition & 1 deletion clash-vexriscv/src/VexRiscv/FFI.hsc
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ foreign import ccall unsafe "vexr_init" vexrInit :: IO (Ptr VexRiscv)
foreign import ccall unsafe "vexr_init_vcd" vexrInitVcd :: Ptr VexRiscv -> CString -> IO (Ptr VerilatedVcdC)
foreign import ccall unsafe "vexr_shutdown" vexrShutdown :: Ptr VexRiscv -> IO ()

foreign import ccall unsafe "vexr_init_stage1" vexrInitStage1 :: Ptr VerilatedVcdC -> Ptr VexRiscv -> Ptr NON_COMB_INPUT -> Ptr OUTPUT -> IO ()
foreign import ccall unsafe "vexr_init_stage1" vexrInitStage1 :: Ptr VerilatedVcdC -> Word64 -> Ptr VexRiscv -> Ptr NON_COMB_INPUT -> Ptr OUTPUT -> IO ()
foreign import ccall unsafe "vexr_init_stage2" vexrInitStage2 :: Ptr VexRiscv -> Ptr COMB_INPUT -> IO ()
foreign import ccall unsafe "vexr_step_rising_edge" vexrStepRisingEdge :: Ptr VerilatedVcdC -> Ptr VexRiscv -> Word64 -> Ptr NON_COMB_INPUT -> Ptr OUTPUT -> IO ()
foreign import ccall unsafe "vexr_step_falling_edge" vexrStepFallingEdge :: Ptr VerilatedVcdC -> Ptr VexRiscv -> Word64 -> Ptr COMB_INPUT -> IO ()
Expand Down
17 changes: 10 additions & 7 deletions clash-vexriscv/src/ffi/impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,9 @@ VVexRiscv *vexr_init();
VerilatedVcdC *vexr_init_vcd(VVexRiscv *top, const char *path);
void vexr_shutdown(VVexRiscv *top);

void vexr_init_stage1(VerilatedVcdC *vcd, VVexRiscv *top,
const NON_COMB_INPUT *input, OUTPUT *output);
void vexr_init_stage1(VerilatedVcdC *vcd, uint64_t dom_period_fs,
VVexRiscv *top, const NON_COMB_INPUT *input,
OUTPUT *output);
void vexr_init_stage2(VVexRiscv *top, const COMB_INPUT *input);
void vexr_step_rising_edge(VerilatedVcdC *vcd, VVexRiscv *top,
uint64_t time_add, const NON_COMB_INPUT *input,
Expand Down Expand Up @@ -119,8 +120,9 @@ void set_outputs(VVexRiscv *top, OUTPUT *output) {
output->jtag_TDO = top->jtag_tdo;
}

void vexr_init_stage1(VerilatedVcdC *vcd, VVexRiscv *top,
const NON_COMB_INPUT *input, OUTPUT *output) {
void vexr_init_stage1(VerilatedVcdC *vcd, uint64_t dom_period_fs,
VVexRiscv *top, const NON_COMB_INPUT *input,
OUTPUT *output) {
// Set all inputs that cannot combinationaly depend on outputs. I.e., all
// inputs except the Wishbone buses.
set_non_comb_inputs(top, input);
Expand All @@ -132,9 +134,10 @@ void vexr_init_stage1(VerilatedVcdC *vcd, VVexRiscv *top,
}
set_outputs(top, output);

// Advance time by 50 nanoseconds. This is an arbitrary value. Ideally, we
// would do something similar to Clash's template tag "~LONGESTPERIOD".
contextp->timeInc(50000);
// Advance time by the period of the vexrisc clock in femtoseconds.
// Because verilator does not support femtosecond resolution, the simulation
// time is off by a factor of 1000.
contextp->timeInc(dom_period_fs);
}

void vexr_init_stage2(VVexRiscv *top, const COMB_INPUT *input) {
Expand Down

0 comments on commit 276c0ab

Please sign in to comment.