From 276c0ab26906df33f6b554b15166785023277404 Mon Sep 17 00:00:00 2001 From: Lucas Bollen Date: Fri, 10 Jan 2025 13:52:51 +0100 Subject: [PATCH] Correcetly simulate passed time before first clock edge in verilator 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. --- clash-vexriscv/src/VexRiscv.hs | 15 +++++++++++---- clash-vexriscv/src/VexRiscv/FFI.hsc | 2 +- clash-vexriscv/src/ffi/impl.cpp | 17 ++++++++++------- 3 files changed, 22 insertions(+), 12 deletions(-) diff --git a/clash-vexriscv/src/VexRiscv.hs b/clash-vexriscv/src/VexRiscv.hs index 09e318c..97dab71 100644 --- a/clash-vexriscv/src/VexRiscv.hs +++ b/clash-vexriscv/src/VexRiscv.hs @@ -185,7 +185,8 @@ vexRiscv dumpVcd clk rst cpuInput jtagInput = vexRiscv# - :: KnownDomain dom + :: forall dom . + KnownDomain dom => DumpVcd -> String -> Clock dom @@ -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 @@ -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 @@ -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 @@ -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 #-} diff --git a/clash-vexriscv/src/VexRiscv/FFI.hsc b/clash-vexriscv/src/VexRiscv/FFI.hsc index c466c1f..74a1181 100644 --- a/clash-vexriscv/src/VexRiscv/FFI.hsc +++ b/clash-vexriscv/src/VexRiscv/FFI.hsc @@ -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 () diff --git a/clash-vexriscv/src/ffi/impl.cpp b/clash-vexriscv/src/ffi/impl.cpp index 3288345..ca098c7 100644 --- a/clash-vexriscv/src/ffi/impl.cpp +++ b/clash-vexriscv/src/ffi/impl.cpp @@ -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, @@ -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); @@ -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) {