diff --git a/bittide-instances/data/openocd/start.sh b/bittide-instances/data/openocd/start.sh index e6a2e204a..a25aa1bc4 100755 --- a/bittide-instances/data/openocd/start.sh +++ b/bittide-instances/data/openocd/start.sh @@ -17,6 +17,6 @@ mkdir -p "${stderr_dir}" OPENOCD_STDERR_LOG="$(realpath ${OPENOCD_STDERR_LOG})" cd $(dirname $0) -exec ${OPENOCD_BIN} -f ports.tcl -f sipeed.tcl -f vexriscv_init.tcl $@ \ +exec "${OPENOCD_BIN}" -f ports.tcl -f sipeed.tcl -f "${VEXRISCV_TCL_INIT}" $@ \ > >(tee "${OPENOCD_STDOUT_LOG}") \ 2> >(tee "${OPENOCD_STDERR_LOG}" >&2) diff --git a/bittide-instances/data/openocd/vexriscv_init_custom.tcl b/bittide-instances/data/openocd/vexriscv_init_custom.tcl new file mode 100644 index 000000000..10ac88f0d --- /dev/null +++ b/bittide-instances/data/openocd/vexriscv_init_custom.tcl @@ -0,0 +1,59 @@ +# SPDX-FileCopyrightText: 2024 Google LLC +# +# SPDX-License-Identifier: Apache-2.0 +set _ENDIAN little +set _TAP_TYPE 1234 + +if { [info exists CPUTAPID] } { + set _CPUTAPID $CPUTAPID +} else { + # set useful default + set _CPUTAPID 0x10002FFF +} + +set _CHIPNAME vexrisc_ocd + +# The JTAG TAP itself is given the name "bridge", because it refers to the +# JtagBridge that's part of the VexRiscv/SpinalHDL debug infrastructure. +# In the example design, there is the JtagBridge controls a single CPU, but +# the capability is there for 1 JTAG TAP + JtagBridge to control multiple +# VexRiscv CPUs. +jtag newtap $_CHIPNAME bridge -expected-id $_CPUTAPID -irlen 5 + +# There is 1 CPU controlled by the "bridge" JTAG TAP, "cpu0" +target create $_CHIPNAME.cpu0 vexriscv -endian $_ENDIAN -chain-position $_CHIPNAME.bridge + +# The JtagBridge/SystemDebugger receives commands in a serialized way. It gets synchronized into +# a parallel bus, and a response is received. Along the way, there may be various clock domain +# crossings or pipeline delays. +# readWaitCycles instructs OpenOCD to insert idle JTAG clock cycles before shifting out +# the response. +# There aren't many transactions where read-back throughput is important, so there's little +# points in lowballing this number. +vexriscv readWaitCycles 10 + +# When the Verilog of a SpinalHDL design with one or more VexRiscv CPUs is created, the system +# also creates a .yaml file with information that's sideband information that's important for +# OpenOCD to control the CPU correctly. +# A good example of this are the number of hardware breakpoints that are supported by the CPU. +set git_top_level [string trim [exec git rev-parse --show-toplevel]] +vexriscv cpuConfigFile [file join $git_top_level clash-vexriscv clash-vexriscv example-cpu ExampleCpu.yaml] + +# The rate at which OpenOCD polls active JTAG TAPs to check if there has been a notable +# event. (E.g. to check if the CPU has hit a breakpoint.) +# For some reason, making this number really low has an impact on the CPU while semihosting is +# enabled? +poll_period 50 + +# Initialize all JTAG TAPs and targets. +init + +echo "Halting processor" + +# Halts the CPU +halt + +# If you also want to reset the CPU, use: +# soft_reset_halt + +sleep 1000 diff --git a/bittide-instances/src/Bittide/Instances/Hitl/Driver/SwCcTopologies.hs b/bittide-instances/src/Bittide/Instances/Hitl/Driver/SwCcTopologies.hs index 2cc5c18b6..794ad624d 100644 --- a/bittide-instances/src/Bittide/Instances/Hitl/Driver/SwCcTopologies.hs +++ b/bittide-instances/src/Bittide/Instances/Hitl/Driver/SwCcTopologies.hs @@ -86,9 +86,9 @@ driverFunc testName targets = do putStrLn "Starting OpenOCD..." (ocd, ocdPh, ocdClean1) <- startOpenOcdWithEnv + OpenOcdVexRiscv [ ("OPENOCD_STDOUT_LOG", ocdStdout) , ("OPENOCD_STDERR_LOG", ocdStderr) - , ("OPENOCD_BIN", "openocd-vexriscv") ] d.usbAdapterLocation gdbPort diff --git a/bittide-instances/src/Bittide/Instances/Hitl/Driver/VexRiscv.hs b/bittide-instances/src/Bittide/Instances/Hitl/Driver/VexRiscv.hs index 9fd99ca8b..2e642ef54 100644 --- a/bittide-instances/src/Bittide/Instances/Hitl/Driver/VexRiscv.hs +++ b/bittide-instances/src/Bittide/Instances/Hitl/Driver/VexRiscv.hs @@ -78,7 +78,7 @@ driverFunc _name targets = do -- even though this is just pre-process step, the CPU is reset until -- the test_start signal is asserted and cannot be accessed via GDB otherwise updateVio "vioHitlt" [("probe_test_start", "1")] - liftIO $ withOpenOcdWithEnv openocdEnv deviceInfo.usbAdapterLocation gdbPort 6666 4444 $ \ocd -> do + liftIO $ withOpenOcdWithEnv OpenOcdRiscv openocdEnv deviceInfo.usbAdapterLocation gdbPort 6666 4444 $ \ocd -> do -- make sure OpenOCD is started properly hSetBuffering ocd.stderrHandle LineBuffering expectLine ocd.stderrHandle openOcdWaitForHalt diff --git a/bittide-instances/src/Bittide/Instances/Hitl/Driver/VexRiscvTcp.hs b/bittide-instances/src/Bittide/Instances/Hitl/Driver/VexRiscvTcp.hs index 36a333473..3d1862521 100644 --- a/bittide-instances/src/Bittide/Instances/Hitl/Driver/VexRiscvTcp.hs +++ b/bittide-instances/src/Bittide/Instances/Hitl/Driver/VexRiscvTcp.hs @@ -94,7 +94,7 @@ driverFunc _name [(hwT, dI)] = do initHwDevice - withOpenOcdWithEnv openocdEnv dI.usbAdapterLocation 3333 6666 4444 $ \ocd -> do + withOpenOcdWithEnv OpenOcdRiscv openocdEnv dI.usbAdapterLocation 3333 6666 4444 $ \ocd -> do liftIO $ do hSetBuffering ocd.stderrHandle LineBuffering putStr "Waiting for OpenOCD to halt..." diff --git a/bittide-instances/src/Bittide/Instances/Hitl/Utils/Program.hs b/bittide-instances/src/Bittide/Instances/Hitl/Utils/Program.hs index 2affd84c2..66c6fc4af 100644 --- a/bittide-instances/src/Bittide/Instances/Hitl/Utils/Program.hs +++ b/bittide-instances/src/Bittide/Instances/Hitl/Utils/Program.hs @@ -56,6 +56,8 @@ awaitProcessTermination name h (Just t) = do withOpenOcd :: (MonadMask m, MonadIO m) => + -- | Which OpenOcd to use + OpenOcdVersion -> -- | USB device location String -> -- | GDB port @@ -67,10 +69,12 @@ withOpenOcd :: -- | Action to run with OpenOCD (ProcessStdIoHandles -> m a) -> m a -withOpenOcd = withOpenOcdWithEnv [] +withOpenOcd ocdVersion = withOpenOcdWithEnv ocdVersion [] withOpenOcdWithEnv :: (MonadMask m, MonadIO m) => + -- | Which OpenOcd to use + OpenOcdVersion -> -- | Extra environment variables to pass to OpenOCD in form (name, value) [(String, String)] -> -- | USB device location @@ -84,12 +88,15 @@ withOpenOcdWithEnv :: -- | Action to run with OpenOCD (ProcessStdIoHandles -> m a) -> m a -withOpenOcdWithEnv extraEnv usbLoc gdbPort tclPort telnetPort action = do +withOpenOcdWithEnv ocdVersion extraEnv usbLoc gdbPort tclPort telnetPort action = do (ocd, _handle, clean) <- - liftIO $ startOpenOcdWithEnv extraEnv usbLoc gdbPort tclPort telnetPort + liftIO $ startOpenOcdWithEnv ocdVersion extraEnv usbLoc gdbPort tclPort telnetPort finally (action ocd) (liftIO clean) +data OpenOcdVersion = OpenOcdRiscv | OpenOcdVexRiscv startOpenOcdWithEnv :: + -- | Which OpenOcd to use + OpenOcdVersion -> -- | Extra environment variables to pass to OpenOCD in form (name, value) [(String, String)] -> -- | USB device location @@ -101,13 +108,10 @@ startOpenOcdWithEnv :: -- | Telnet port Int -> IO (ProcessStdIoHandles, ProcessHandle, IO ()) -startOpenOcdWithEnv extraEnv0 usbLoc gdbPort tclPort telnetPort = do - -- Check if OPENOCD_BIN is set. If not, append ("OPENOCD_BIN", "openocd") to the environment. - -- This is necessary because swCcTopologiesTest relies on the custom OpenOCD binary. - let extraEnv1 - | any ((== "OPENOCD_BIN") . fst) extraEnv0 = extraEnv0 - | otherwise = ("OPENOCD_BIN", "openocd") : extraEnv0 - +startOpenOcdWithEnv ocdVersion extraEnv usbLoc gdbPort tclPort telnetPort = do + let (openocdBin, vexriscvInit) = case ocdVersion of + OpenOcdRiscv -> ("openocd-riscv", "vexriscv_init.tcl") + OpenOcdVexRiscv -> ("openocd-vexriscv", "vexriscv_init_custom.tcl") startOpenOcdPath <- getOpenOcdStartPath currentEnv <- getEnvironment let @@ -119,11 +123,13 @@ startOpenOcdWithEnv extraEnv0 usbLoc gdbPort tclPort telnetPort = do , env = Just ( currentEnv - <> extraEnv1 + <> extraEnv <> [ ("USB_DEVICE", usbLoc) , ("GDB_PORT", show gdbPort) , ("TCL_PORT", show tclPort) , ("TELNET_PORT", show telnetPort) + , ("OPENOCD_BIN", openocdBin) + , ("VEXRISCV_TCL_INIT", vexriscvInit) ] ) }