Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/synthesis/all.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@

{"top": "vexRiscvTcpTest", "stage": "bitstream", "cc_report": false},

{"top": "asyncCommsDemoTest", "stage": "test", "cc_report": true},
{"top": "boardTestExtended", "stage": "test", "cc_report": false},
{"top": "boardTestSimple", "stage": "test", "cc_report": false},
{"top": "ddr4Test", "stage": "test", "cc_report": false},
Expand Down
1 change: 1 addition & 0 deletions .github/synthesis/main.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
[
{"top": "receiveRingBufferPnr", "stage": "pnr", "cc_report": false},
{"top": "safeDffSynchronizer", "stage": "hdl" , "cc_report": false},
{"top": "asyncCommsDemoTest", "stage": "test", "cc_report": true},
{"top": "transmitRingBufferPnr", "stage": "pnr", "cc_report": false},
{"top": "vexRiscvTest", "stage": "test", "cc_report": false},
{"top": "wireDemoTest", "stage": "test", "cc_report": true}
Expand Down
4 changes: 4 additions & 0 deletions bittide-instances/bittide-instances.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,10 @@ library
Bittide.Instances.Common
Bittide.Instances.Domains
Bittide.Instances.Hacks
Bittide.Instances.Hitl.AsyncCommsDemo.Driver
Bittide.Instances.Hitl.AsyncCommsDemo.MemoryMaps
Bittide.Instances.Hitl.AsyncCommsDemo.TopEntity
Bittide.Instances.Hitl.AsyncCommsDemo.UserCore
Bittide.Instances.Hitl.BoardTest
Bittide.Instances.Hitl.Ddr4
Bittide.Instances.Hitl.DnaOverSerial
Expand Down
126 changes: 126 additions & 0 deletions bittide-instances/src/Bittide/Instances/Hitl/AsyncCommsDemo/Driver.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
-- SPDX-FileCopyrightText: 2026 Google LLC
--
-- SPDX-License-Identifier: Apache-2.0
{-# LANGUAGE PackageImports #-}

module Bittide.Instances.Hitl.AsyncCommsDemo.Driver where

import Clash.Prelude

import Bittide.ClockControl.Config (defCcConf)
import Bittide.Hitl
import Bittide.Instances.Hitl.Setup (FpgaCount)
import Bittide.Instances.Hitl.Utils.Driver
import Bittide.Instances.Hitl.Utils.Gdb (initGdb)
import Bittide.Instances.Hitl.Utils.OpenOcd (parseBootTapInfo, parseTapInfo)
import Bittide.Instances.Hitl.Utils.Serial (initSerial)
import Bittide.Instances.Hitl.Utils.Usb (resetUsbDeviceByLocation)
import Bittide.Instances.Hitl.Utils.Utils (dumpCcSamples)
import Control.Concurrent.Async (forConcurrently_, mapConcurrently_)
import Control.Concurrent.Async.Extra (zipWithConcurrently3_)
import Control.Monad (forM_)
import Control.Monad.IO.Class
import Data.Vector.Internal.Check (HasCallStack)
import Project.Chan
import Project.FilePath
import Project.Handle (assertEither)
import System.Exit
import System.FilePath
import Vivado.Tcl (HwTarget)
import Vivado.VivadoM (VivadoM)
import "bittide-extra" Control.Exception.Extra (brackets)

import qualified Bittide.Instances.Hitl.AsyncCommsDemo.MemoryMaps as MemoryMaps
import qualified Bittide.Instances.Hitl.Utils.OpenOcd as Ocd
import qualified Data.List as L
import qualified Gdb
import qualified System.Timeout.Extra as T

driver ::
(HasCallStack) =>
String ->
[(HwTarget, DeviceInfo)] ->
VivadoM ExitCode
driver testName targets = do
let (_hwTargets, deviceInfos) = L.unzip targets
liftIO
. putStrLn
$ "Running driver function for targets "
<> show ((.deviceId) <$> deviceInfos)

projectDir <- liftIO $ findParentContaining "cabal.project"
let hitlDir = projectDir </> "_build/hitl" </> testName

forM_ targets (assertProbe "probe_test_start")

-- Reset USB adapter, see documentation of "Bittide.Instances.Hitl.Utils.Usb"
liftIO $ forM_ deviceInfos $ \d -> resetUsbDeviceByLocation d.usbAdapterLocation

let
expectedJtagIds = [0x0514C001, 0x1514C001, 0x2514C001]
toInitArgs deviceInfo targetIndex =
Ocd.InitOpenOcdArgs{deviceInfo, expectedJtagIds, hitlDir, targetIndex}
initArgs = L.zipWith toInitArgs deviceInfos [0 ..]
optionalBootInitArgs = L.repeat def{Ocd.logPrefix = "boot-", Ocd.initTcl = "vexriscv_boot_init.tcl"}
openOcdBootStarts = liftIO <$> L.zipWith Ocd.initOpenOcd initArgs optionalBootInitArgs

let serialStarts = liftIO <$> L.zipWith (initSerial hitlDir) targets [0 ..]
brackets serialStarts (liftIO . snd) $ \(L.map fst -> serials) -> do
brackets openOcdBootStarts (liftIO . (.cleanup)) $ \initOcdsData -> do
let bootTapInfos = parseBootTapInfo <$> initOcdsData

Gdb.withGdbs (L.length targets) $ \bootGdbs -> do
liftIO
$ zipWithConcurrently3_ (initGdb hitlDir "async-comms-demo-boot") bootGdbs bootTapInfos targets
liftIO $ mapConcurrently_ ((assertEither =<<) . Gdb.loadBinary) bootGdbs
liftIO $ mapConcurrently_ Gdb.continue bootGdbs
liftIO
$ T.tryWithTimeout T.PrintActionTime "Waiting for done" 60_000_000
$ forConcurrently_ serials
$ \pico ->
waitForLine pico "[BT] Going into infinite loop.."

let
optionalInitArgs = L.repeat def
openOcdStarts = liftIO <$> L.zipWith Ocd.initOpenOcd initArgs optionalInitArgs

brackets openOcdStarts (liftIO . (.cleanup)) $ \initOcdsData -> do
let
allTapInfos = parseTapInfo expectedJtagIds <$> initOcdsData

_bootTapInfos, muTapInfos, ccTapInfos :: [Ocd.TapInfo]
(_bootTapInfos, muTapInfos, ccTapInfos)
| all (== L.length expectedJtagIds) (L.length <$> allTapInfos)
, [boots, mus, ccs] <- L.transpose allTapInfos =
(boots, mus, ccs)
| otherwise =
error
$ "Unexpected number of OpenOCD taps initialized. Expected: "
<> show (L.length expectedJtagIds)
<> ", but got: "
<> show (L.length <$> allTapInfos)

Gdb.withGdbs (L.length targets) $ \ccGdbs -> do
liftIO
$ zipWithConcurrently3_ (initGdb hitlDir "async-comms-demo-clock-control") ccGdbs ccTapInfos targets
Gdb.withGdbs (L.length targets) $ \muGdbs -> do
liftIO
$ zipWithConcurrently3_ (initGdb hitlDir "async-comms-demo-management-unit") muGdbs muTapInfos targets
brackets serialStarts (liftIO . snd) $ \(L.map fst -> serials) -> do
let goDumpCcSamples = dumpCcSamples MemoryMaps.clockControl hitlDir (defCcConf (natToNum @FpgaCount)) ccGdbs
liftIO $ mapConcurrently_ ((assertEither =<<) . Gdb.loadBinary) ccGdbs
liftIO $ mapConcurrently_ ((assertEither =<<) . Gdb.loadBinary) muGdbs
liftIO $ mapConcurrently_ Gdb.continue (ccGdbs <> muGdbs)
liftIO
$ T.tryWithTimeoutOn
T.PrintActionTime
"Waiting for CPU test status"
(60_000_000)
goDumpCcSamples
$ forConcurrently_ serials
$ \pico ->
waitForLine pico "[MU] Demo complete."

liftIO goDumpCcSamples

pure ExitSuccess
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
-- SPDX-FileCopyrightText: 2026 Google LLC
--
-- SPDX-License-Identifier: Apache-2.0

module Bittide.Instances.Hitl.AsyncCommsDemo.MemoryMaps where

import Bittide.Instances.Hitl.AsyncCommsDemo.UserCore (mkUserCore, muConfig, ringBufferDepth)
import Bittide.Instances.Hitl.GenericDemo.MemoryMaps (extractMemoryMaps)
import Protocols.MemoryMap (MemoryMap)

boot, managementUnit, clockControl :: MemoryMap
(boot, managementUnit, clockControl) = extractMemoryMaps ringBufferDepth muConfig mkUserCore
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
-- SPDX-FileCopyrightText: 2026 Google LLC
--
-- SPDX-License-Identifier: Apache-2.0
-- Defined in GenericDemo
{-# OPTIONS_GHC -Wno-missing-signatures #-}

module Bittide.Instances.Hitl.AsyncCommsDemo.TopEntity where

import Bittide.Hitl (HitlTestGroup)
import Bittide.Instances.Hitl.AsyncCommsDemo.UserCore (mkUserCore, muConfig, ringBufferDepth)
import Bittide.Instances.Hitl.GenericDemo.TopEntity (demoTest, mkTests)
import Clash.Annotations.TH (makeTopEntity)

import qualified Bittide.Instances.Hitl.AsyncCommsDemo.Driver as Driver

asyncCommsDemoTest = demoTest ringBufferDepth muConfig mkUserCore
{-# OPAQUE asyncCommsDemoTest #-}
makeTopEntity 'asyncCommsDemoTest

tests :: HitlTestGroup
tests = mkTests 'asyncCommsDemoTest Driver.driver
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
-- SPDX-FileCopyrightText: 2026 Google LLC
--
-- SPDX-License-Identifier: Apache-2.0

-- | User core for the async-comms demo: essentially an empty circuit.
module Bittide.Instances.Hitl.AsyncCommsDemo.UserCore (
UserCoreBusses,
RingBufferDepth,
ringBufferDepth,
mkUserCore,
muConfig,
) where

import Clash.Explicit.Prelude
import Protocols

import Bittide.Instances.Hitl.GenericDemo.BringUp (NmuRemBusWidth, UserCoreCircuit)
import Bittide.Instances.Hitl.GenericDemo.Core (NmuInternalBusses)
import Bittide.ProcessingElement (PeConfig (..), PrefixWidth)

import qualified Bittide.Cpus.Riscv32imc as Riscv32imc

type UserCoreBusses = 0

type RingBufferDepth = 128

ringBufferDepth :: SNat RingBufferDepth
ringBufferDepth = SNat

{- | Management unit configuration for the async comms demo. Its firmware is
much larger than that of the other demos (it links in smoltcp), so it needs
more memory than the default 'Bittide.Instances.Hitl.GenericDemo.Core.muConfig'
provides.
-}
muConfig ::
( KnownNat n
, PrefixWidth (n + NmuInternalBusses) <= 30
) =>
PeConfig (n + NmuInternalBusses)
muConfig =
PeConfig
{ cpu = Riscv32imc.vexRiscv1
, depthI = SNat @(Div (10 * 16 * 1024) 4) -- One RAMB18E2 is 16KB, this uses 10 of them.
, depthD = SNat @(Div (10 * 16 * 1024) 4) -- One RAMB18E2 is 16KB, this uses 10 of them.
, initI = Nothing
, initD = Nothing
, iBusTimeout = d0
, dBusTimeout = d0
, includeIlaWb = False
}

mkUserCore :: UserCoreCircuit UserCoreBusses (NmuRemBusWidth UserCoreBusses)
mkUserCore _bitClk _bitRst _bitEna _localCounter _maybeDna =
circuit $ \(muBusses, _rxs2Raw, rxLinks) -> do
[] <- idC -< muBusses
idC -< rxLinks
Original file line number Diff line number Diff line change
Expand Up @@ -36,22 +36,22 @@ dnaOverSerialDriver ::
VivadoM ExitCode
dnaOverSerialDriver _name targets = do
-- Reset USB adapter, see documentation of "Bittide.Instances.Hitl.Utils.Usb"
liftIO $ forM_ targets $ \(_, d) -> resetUsbDeviceByLocation d.usbAdapterLocation
liftIO $ forM_ deviceInfos $ \d -> resetUsbDeviceByLocation d.usbAdapterLocation

results <- brackets (liftIO <$> initSerials) (liftIO . snd) $ \initSerialsData -> do
let targetSerials = fst <$> initSerialsData

liftIO $ putStrLn "Starting all targets to read DNA values"
-- start all targets
forM_ targets $ \(hwT, _) -> do
forM_ hwTargets $ \hwT -> do
openHardwareTarget hwT
updateVio "vioHitlt" [("probe_test_start", "1")]

liftIO $ putStrLn "Expecting specific DNAs for all serial ports"
liftIO $ putStrLn "Serial ports:"
mapM_ (liftIO . putStrLn) [d.serial | (_, d) <- targets]
mapM_ (liftIO . putStrLn) [d.serial | d <- deviceInfos]

forM (L.zip targets targetSerials) $ \((_, d), serialHandle) -> do
forM (L.zip deviceInfos targetSerials) $ \(d, serialHandle) -> do
liftIO $ putStrLn $ "Waiting for output on port: " <> d.serial
res <- liftIO $ checkDna d serialHandle
pure res
Expand All @@ -65,9 +65,9 @@ dnaOverSerialDriver _name targets = do
where
-- Must match the gateware's UART baud rate (`dnaOverSerial` uses @SNat \@9600@).
baud = 9600

(hwTargets, deviceInfos) = L.unzip targets
initSerials :: [IO (Serial.SerialHandle, IO ())]
initSerials = flip L.map targets $ \(_hwT, dI) -> do
initSerials = flip L.map deviceInfos $ \dI -> do
(serialHandle, serialClean) <- Serial.start dI.serial baud

hSetBuffering serialHandle.handle LineBuffering
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,8 @@ bringUp ::
, NmuRemBusWidth userCoreBusses <= 27
) =>
SNat ringBufferDepth ->
-- | Management unit processing element configuration
PeConfig (NmuExternalBusses userCoreBusses + NmuInternalBusses) ->
UserCoreCircuit userCoreBusses (NmuRemBusWidth userCoreBusses) ->
"REFCLK" ::: Clock Basic125 ->
"TEST_RST" ::: Reset Basic125 ->
Expand All @@ -113,7 +115,7 @@ bringUp ::
, "UART_TX" ::: CSignal Basic125 Bit
, "FINC_FDEC" ::: CSignal Bittide (FINC, FDEC)
)
bringUp bufferDepth mkUserCore refClk refRst =
bringUp bufferDepth muConfig mkUserCore refClk refRst =
withLittleEndian $ circuit $ \(memoryMaps, jtag, gths) -> do
([bootMm], coreMemoryMaps) <- Vec.split -< memoryMaps

Expand Down Expand Up @@ -158,6 +160,7 @@ bringUp bufferDepth mkUserCore refClk refRst =
) <-
core
bufferDepth
muConfig
mkUserCore
(refClk, refRst)
(bittideClk, bittideRst, enableGen)
Expand Down
13 changes: 9 additions & 4 deletions bittide-instances/src/Bittide/Instances/Hitl/GenericDemo/Core.hs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ module Bittide.Instances.Hitl.GenericDemo.Core (
NmuRemBusWidth,
UserCoreCircuit,
core,
muConfig,
) where

import Clash.Explicit.Prelude
Expand Down Expand Up @@ -194,6 +195,8 @@ managementUnit ::
, KnownNat userCoreBusses
, PrefixWidth (NmuExternalBusses userCoreBusses + NmuInternalBusses) <= 30
) =>
-- | Processing element configuration
PeConfig (NmuExternalBusses userCoreBusses + NmuInternalBusses) ->
-- | External counter
Signal dom (Unsigned 64) ->
-- | DNA value
Expand All @@ -207,10 +210,10 @@ managementUnit ::
, Bitbone dom (NmuRemBusWidth userCoreBusses)
)
)
managementUnit externalCounter maybeDna =
managementUnit peConfig externalCounter maybeDna =
circuit $ \(mm, jtag) -> do
-- Core and interconnect
allBusses <- processingElement NoDumpVcd muConfig -< (mm, jtag)
allBusses <- processingElement NoDumpVcd peConfig -< (mm, jtag)
([timeBus, uartBus, dnaBus], restBusses) <- Vec.split -< allBusses

-- Peripherals
Expand All @@ -232,6 +235,8 @@ core ::
, 1 <= NmuRemBusWidth userCoreBusses
) =>
SNat ringBufferDepth ->
-- | Management unit processing element configuration
PeConfig (NmuExternalBusses userCoreBusses + NmuInternalBusses) ->
UserCoreCircuit userCoreBusses (NmuRemBusWidth userCoreBusses) ->
(Clock Basic125, Reset Basic125) ->
(Clock Bittide, Reset Bittide, Enable Bittide) ->
Expand All @@ -250,7 +255,7 @@ core ::
, "UARTS" ::: Vec InternalCpuCount (Df Bittide (BitVector 8))
, "MU_TRANSCEIVER" ::: BitboneMm Bittide (NmuRemBusWidth userCoreBusses)
)
core bufferDepth mkUserCore (refClk, refRst) (bitClk, bitRst, bitEna) rxClocks rxResets = withXilinx
core bufferDepth peConfig mkUserCore (refClk, refRst) (bitClk, bitRst, bitEna) rxClocks rxResets = withXilinx
$ circuit
$ \(memoryMaps, jtag, mask, linksSuitableForCc, Fwd rxs0) -> do
[muMm, ccMm] <- idC -< memoryMaps
Expand All @@ -263,7 +268,7 @@ core bufferDepth mkUserCore (refClk, refRst) (bitClk, bitRst, bitEna) rxClocks r

-- Start management unit
(muUartBytesBittide, muWbAll) <-
withBittideClockResetEnable managementUnit localCounter maybeDna -< (muMm, muJtag)
withBittideClockResetEnable managementUnit peConfig localCounter maybeDna -< (muMm, muJtag)
(ebWbs, muWbs1) <- Vec.split -< muWbAll
(rxBufferBusses, muWbs2) <- Vec.split -< muWbs1
(txBufferBusses, muWbs3) <- Vec.split -< muWbs2
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import Bittide.Instances.Hitl.GenericDemo.BringUp (
bringUp,
)
import Bittide.Instances.Hitl.GenericDemo.Core (NmuExternalBusses, NmuInternalBusses)
import Bittide.ProcessingElement (PrefixWidth)
import Bittide.ProcessingElement (PeConfig, PrefixWidth)
import Clash.Sized.Vector.ToTuple (vecToTuple)
import Protocols.MemoryMap (MemoryMap)
import VexRiscv (JtagIn (..))
Expand All @@ -35,12 +35,14 @@ extractMemoryMaps ::
, NmuRemBusWidth userCoreBusses <= 27
) =>
SNat ringBufferDepth ->
-- | Processing element configuration
PeConfig (NmuExternalBusses userCoreBusses + NmuInternalBusses) ->
UserCoreCircuit userCoreBusses (NmuRemBusWidth userCoreBusses) ->
-- | (boot, management unit, clock control)
(MemoryMap, MemoryMap, MemoryMap)
extractMemoryMaps bufferDepth mkUserCore = (bootMm, managementUnitMm, clockControlMm)
extractMemoryMaps bufferDepth muConfig mkUserCore = (bootMm, managementUnitMm, clockControlMm)
where
Circuit circuitFn = bringUp bufferDepth mkUserCore clockGen noReset
Circuit circuitFn = bringUp bufferDepth muConfig mkUserCore clockGen noReset

(SimOnly bootMm, SimOnly managementUnitMm, SimOnly clockControlMm) = vecToTuple memoryMaps

Expand Down
Loading