-
Notifications
You must be signed in to change notification settings - Fork 2
Ugn grooming #1318
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Ugn grooming #1318
Changes from all commits
168684a
3997a47
f53f3f6
019757e
089709d
f5299ca
5e6c996
9ef423d
7c0b4a0
9f65e93
6a701a8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -96,3 +96,4 @@ docs/mdbook-drawio | |
|
|
||
| # Scala | ||
| .metals | ||
| .scala-build | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -59,6 +59,7 @@ import Protocols | |
| import Bittide.CaptureUgn (captureUgns, sendUgn) | ||
| import Bittide.ClockControl (SpeedChange) | ||
| import Bittide.ClockControl.CallistoSw (SwcccInternalBusses, callistoSwClockControlC) | ||
| import Bittide.ClockControl.Ugn.Corrections (correctionsWb) | ||
| import Bittide.DoubleBufferedRam (wbStorage) | ||
| import Bittide.ElasticBuffer (fromData, xilinxElasticBufferWb) | ||
| import Bittide.Extra.Maybe (toMaybe) | ||
|
|
@@ -76,6 +77,7 @@ import Bittide.ProcessingElement ( | |
| import Bittide.RingBuffer (receiveRingBuffer, transmitRingBuffer) | ||
| import Bittide.SharedTypes (Bitbone, BitboneMm) | ||
| import Bittide.Sync (Sync) | ||
| import Bittide.TimedReset (timedResetWb) | ||
| import Bittide.Wishbone (readDnaPortE2WbWorker, timeWb, uartBytes, uartInterfaceWb) | ||
| import Clash.Class.BitPackC (ByteOrder) | ||
| import Clash.Cores.Xilinx (withXilinx) | ||
|
|
@@ -97,16 +99,18 @@ import qualified Protocols.Vec as Vec | |
| -- | The number of CPUs in 'core' | ||
| type InternalCpuCount = 2 | ||
|
|
||
| type FifoSize = 5 -- = 2^5 = 32 | ||
| type FifoSize = 6 -- = 2^6 = 64 | ||
|
|
||
| {- Internal busses: | ||
| - Instruction memory | ||
| - Data memory | ||
| - `timeWb` | ||
| - DNA | ||
| - UART | ||
| - UGN grooming corrections | ||
| - application reset (TimedReset) | ||
| -} | ||
| type NmuInternalBusses = 3 + PeInternalBusses | ||
| type NmuInternalBusses = 5 + PeInternalBusses | ||
|
|
||
| {- Busses per link: | ||
| - Elastic buffer | ||
|
|
@@ -144,6 +148,10 @@ type UserCoreCircuit userCoreBusses muRemBusWidth = | |
| Enable Bittide -> | ||
| Signal Bittide (Unsigned 64) -> | ||
| Signal Bittide (Maybe (BitVector 96)) -> | ||
| -- Application reset, released by the management unit's 'timedResetWb' at a | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Update documentation after switching to programmable mux. |
||
| -- chosen local-counter cycle (the UGN-grooming relabel). Demos that have an | ||
| -- application counter gate it on this reset; others may ignore it. | ||
| Reset Bittide -> | ||
| Circuit | ||
| ( Vec userCoreBusses (ToConstBwd Mm, Bitbone Bittide muRemBusWidth) | ||
| , "RXS2_RAW" ::: CSignal Bittide (Vec LinkCount (BitVector 64)) | ||
|
|
@@ -201,6 +209,7 @@ managementUnit :: | |
| Circuit | ||
| (ToConstBwd Mm.Mm, Jtag dom) | ||
| ( Df dom (BitVector 8) | ||
| , "APP_RESET" ::: Reset dom | ||
| , Vec | ||
| (NmuExternalBusses userCoreBusses) | ||
| ( ToConstBwd Mm.Mm | ||
|
|
@@ -211,16 +220,24 @@ managementUnit externalCounter maybeDna = | |
| circuit $ \(mm, jtag) -> do | ||
| -- Core and interconnect | ||
| allBusses <- processingElement NoDumpVcd muConfig -< (mm, jtag) | ||
| ([timeBus, uartBus, dnaBus], restBusses) <- Vec.split -< allBusses | ||
| ([timeBus, uartBus, dnaBus, correctionsBus, timedResetBus], restBusses) <- | ||
| Vec.split -< allBusses | ||
|
|
||
| -- Peripherals | ||
| _localCounter <- timeWb (Just externalCounter) -< timeBus | ||
| (uartOut, _uartStatus) <- | ||
| uartInterfaceWb d16 d16 uartBytes -< (uartBus, Fwd (pure Nothing)) | ||
| readDnaPortE2WbWorker maybeDna -< dnaBus | ||
| -- Host-written UGN grooming corrections, polled and applied by the MU CPU. | ||
| correctionsWb (SNat @LinkCount) -< correctionsBus | ||
| -- Application reset for the demo's user core: the management unit chooses the | ||
| -- local-counter cycle at which the application leaves reset (the UGN-grooming | ||
| -- relabel). The reset lives here, in the layer around the user core; the | ||
| -- application counter it gates lives in the user core itself. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The what now? |
||
| appReset <- timedResetWb externalCounter -< timedResetBus | ||
|
|
||
| -- Output | ||
| idC -< (uartOut, restBusses) | ||
| idC -< (uartOut, appReset, restBusses) | ||
|
|
||
| core :: | ||
| forall userCoreBusses ringBufferDepth. | ||
|
|
@@ -262,7 +279,7 @@ core bufferDepth mkUserCore (refClk, refRst) (bitClk, bitRst, bitEna) rxClocks r | |
| localCounter = register bitClk bitRst bitEna 0 (localCounter + 1) | ||
|
|
||
| -- Start management unit | ||
| (muUartBytesBittide, muWbAll) <- | ||
| (muUartBytesBittide, Fwd appReset, muWbAll) <- | ||
| withBittideClockResetEnable managementUnit localCounter maybeDna -< (muMm, muJtag) | ||
| (ebWbs, muWbs1) <- Vec.split -< muWbAll | ||
| (rxBufferBusses, muWbs2) <- Vec.split -< muWbs1 | ||
|
|
@@ -329,7 +346,7 @@ core bufferDepth mkUserCore (refClk, refRst) (bitClk, bitRst, bitEna) rxClocks r | |
|
|
||
| -- Start user core: post-handshake stage drives the GTH-TX wire. | ||
| Fwd txsOut <- | ||
| mkUserCore bitClk bitRst bitEna localCounter maybeDna | ||
| mkUserCore bitClk bitRst bitEna localCounter maybeDna appReset | ||
| -< ( extraMuBusses | ||
| , Fwd (bundle rxs2Raw) | ||
| , Fwd (bundle handshakesOut.toNeighbors) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,11 +6,20 @@ module Bittide.Instances.Hitl.Utils.Gdb where | |
|
|
||
| import Prelude | ||
|
|
||
| import Clash.Prelude (Signed, Unsigned, Vec, checkedFromIntegral, toList) | ||
|
|
||
| import Bittide.Hitl (DeviceInfo (..)) | ||
| import Bittide.Instances.Hitl.Setup (LinkCount) | ||
|
Comment on lines
+9
to
+12
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. See other comment in this module: this module shouldn't contain device-specific functions. |
||
| import Bittide.Instances.Hitl.Utils.Driver (getTargetIndex) | ||
| import Bittide.Instances.Hitl.Utils.MemoryMap (getPathAddress) | ||
| import Bittide.Instances.Hitl.Utils.OpenOcd (TapInfo (..)) | ||
| import Bittide.Wishbone (TimeCmd (Capture)) | ||
| import Control.Monad (forM_) | ||
| import GHC.Stack (HasCallStack) | ||
| import Gdb (Gdb) | ||
| import Project.FilePath | ||
| import Project.Handle (expectRight) | ||
| import Protocols.MemoryMap (MemoryMap) | ||
| import System.FilePath ((</>)) | ||
| import Vivado.Tcl (HwTarget) | ||
|
|
||
|
|
@@ -26,3 +35,75 @@ initGdb hitlDir binName gdb tapInfo (hwT, _d) = do | |
| Gdb.setTimeout gdb Nothing | ||
| Gdb.runCommand gdb "echo connected to target device" | ||
| pure () | ||
|
|
||
| -- * GDB-based component HAL accessors | ||
|
|
||
| -- | ||
| -- Read/write a component's registers over GDB, addressed through a 'MemoryMap'. Generic | ||
| -- across demos (the memory map is a parameter). All require the CPU to be halted. | ||
|
|
||
| -- | Read the current local-counter value from a device's @Timer@ peripheral. | ||
| readCurrentTime :: (HasCallStack) => MemoryMap -> (HwTarget, DeviceInfo) -> Gdb -> IO (Unsigned 64) | ||
| readCurrentTime mm (_, d) gdb = do | ||
| putStrLn $ "Getting current time from device " <> d.deviceId | ||
| commandAddress <- expectRight $ getPathAddress mm ["0", "Timer", "command"] | ||
| scratchAddress <- expectRight $ getPathAddress mm ["0", "Timer", "scratchpad"] | ||
| Gdb.writeLe gdb commandAddress Capture | ||
| Gdb.readLe gdb scratchAddress | ||
|
Comment on lines
+45
to
+52
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This function already exists in |
||
|
|
||
| {- | Write a node's reset-release cycle to its @TimedReset@ peripheral. Once the local | ||
| counter exceeds this value the node's application (and its application counter) leave | ||
| reset. | ||
| -} | ||
| writeReleaseCycle :: (HasCallStack) => MemoryMap -> Gdb -> Unsigned 64 -> IO () | ||
| writeReleaseCycle mm gdb releaseCycle = do | ||
| addr <- expectRight $ getPathAddress mm ["0", "TimedReset", "release_cycle"] | ||
| Gdb.writeLe gdb addr releaseCycle | ||
|
|
||
| {- | Write the per-link frame corrections and set the @valid@ flag on the | ||
| @UgnCorrections@ peripheral. Resuming the CPU makes the management unit apply the | ||
| corrections to its elastic buffers. | ||
| -} | ||
| writeCorrections :: (HasCallStack) => MemoryMap -> Gdb -> Vec LinkCount (Signed 64) -> IO () | ||
| writeCorrections mm gdb corrections = do | ||
| correctionsAddr <- expectRight $ getPathAddress mm ["0", "UgnCorrections", "corrections"] | ||
| validAddr <- expectRight $ getPathAddress mm ["0", "UgnCorrections", "valid"] | ||
| Gdb.writeLe gdb correctionsAddr corrections | ||
| Gdb.writeLe gdb validAddr True | ||
|
|
||
| {- | Read the per-link hardware UGN counter captures from the @CaptureUgns@ peripheral: | ||
| the @(localCounter, remoteCounter)@ pair per link, with @localCounter@ already adjusted | ||
| for the elastic-buffer frames added/removed since capture (@elastic_buffer_delta@). | ||
| -} | ||
| readHardwareUgns :: | ||
| (HasCallStack) => MemoryMap -> (HwTarget, DeviceInfo) -> Gdb -> IO [(Unsigned 64, Unsigned 64)] | ||
| readHardwareUgns mm (_, d) gdb = do | ||
| let | ||
| getUgnRegister reg = expectRight $ getPathAddress mm ["0", "CaptureUgns", reg] | ||
|
|
||
| -- Adjust the local counter for the frames added/removed from the elastic | ||
| -- buffer after capturing the UGN. Leaves the remote counter untouched. | ||
| adjustLocalCounter :: (Unsigned 64, Unsigned 64, Signed 32) -> (Unsigned 64, Unsigned 64) | ||
| adjustLocalCounter (localCounter, remoteCounter, delta) = | ||
| (addSigned localCounter delta, remoteCounter) | ||
| where | ||
| addSigned :: Unsigned 64 -> Signed 32 -> Unsigned 64 | ||
| addSigned u s = checkedFromIntegral (toInteger u + toInteger s) | ||
|
|
||
| putStrLn $ "Getting UGNs for device " <> d.deviceId | ||
| localCounters <- Gdb.readLe @(Vec LinkCount (Unsigned 64)) gdb =<< getUgnRegister "local_counter" | ||
| remoteCounters <- Gdb.readLe @(Vec LinkCount (Unsigned 64)) gdb =<< getUgnRegister "remote_counter" | ||
| deltas <- Gdb.readLe @(Vec LinkCount (Signed 32)) gdb =<< getUgnRegister "elastic_buffer_delta" | ||
| let ugnTriples = zip3 (toList localCounters) (toList remoteCounters) (toList deltas) | ||
| forM_ ugnTriples $ \triple -> putStrLn $ "Raw UGN triple: " <> show triple | ||
| pure $ adjustLocalCounter <$> ugnTriples | ||
|
|
||
| {- | Read the relabeled application counter exposed by the user core's | ||
| @AppCounterReadback@ peripheral. With the application running, @localCounter - | ||
| app_counter@ equals the node's reset-release cycle, letting the host verify the relabel | ||
| landed on hardware. | ||
| -} | ||
| readAppCounter :: (HasCallStack) => MemoryMap -> (HwTarget, DeviceInfo) -> Gdb -> IO (Unsigned 64) | ||
| readAppCounter mm (_, _) gdb = do | ||
| addr <- expectRight $ getPathAddress mm ["0", "AppCounterReadback", "app_counter"] | ||
| Gdb.readLe gdb addr | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -211,6 +211,31 @@ timingOracleToUgnEdge oracle = | |
| , ugn = bitCoerce oracle.dstCounter - bitCoerce oracle.srcCounter | ||
| } | ||
|
|
||
| {- | Turn a per-node, per-link table of UGN values (@λ@) into 'UgnEdge's keyed by DNA | ||
| node id. The outer vector is FPGA-indexed (the capturing / destination node); each | ||
| inner vector is link-indexed (matching 'knownLinkConfigs'). | ||
| -} | ||
| ugnEdges :: CP.Vec FpgaCount (CP.Vec LinkCount (Signed 64)) -> [UgnEdge] | ||
| ugnEdges lams = | ||
|
Comment on lines
+214
to
+219
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should probably take the map as an argument and move to |
||
| L.concat (CP.toList (CP.imap nodeEdges lams)) | ||
| where | ||
| nodeEdges dstIndex links = CP.toList (CP.imap (edge dstIndex) links) | ||
| edge dstIndex port lam = | ||
| UgnEdge | ||
| { srcNode = indexToNodeId ((knownLinkConfigs CP.!! dstIndex) CP.!! port) | ||
| , srcPort = port | ||
| , dstNode = indexToNodeId dstIndex | ||
| , dstPort = port | ||
| , ugn = lam | ||
| } | ||
|
|
||
| {- | As 'ugnEdges', but from raw @(localCounter, remoteCounter)@ captures: the UGN is | ||
| their signed difference @local - remote@. | ||
| -} | ||
| hardwareUgnEdges :: | ||
| CP.Vec FpgaCount (CP.Vec LinkCount (Unsigned 64, Unsigned 64)) -> [UgnEdge] | ||
| hardwareUgnEdges = ugnEdges . CP.map (CP.map (\(l, r) -> bitCoerce l - bitCoerce r)) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could you use |
||
|
|
||
| {- | Compare hardware and software UGN edges with detailed difference reporting. | ||
|
|
||
| Performs edge-by-edge comparison and reports: | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you have a look at the commit message? The general take is that it doesn't really convey information that's important.