-
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 7 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 |
|---|---|---|
|
|
@@ -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) | ||
|
|
@@ -105,8 +107,10 @@ type FifoSize = 5 -- = 2^5 = 32 | |
| - `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: | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,140 @@ | ||||||||||||||||||||||||
| -- SPDX-FileCopyrightText: 2026 Google LLC | ||||||||||||||||||||||||
| -- | ||||||||||||||||||||||||
| -- SPDX-License-Identifier: Apache-2.0 | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| {- | | ||||||||||||||||||||||||
| The application-facing UGN grooming layer for HITL: it adapts the generic grooming | ||||||||||||||||||||||||
| algorithm ("Bittide.ClockControl.Ugn.Grooming", on "Bittide.Graph.Weighted") to the HITL | ||||||||||||||||||||||||
| 'UgnEdge' type and turns its result into a directly-applyable 'RelabelPlan'. | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| Nodes are identified by their DNA-derived 'BitVector' 32 id (the @srcNode@ / @dstNode@ | ||||||||||||||||||||||||
| fields of a 'UgnEdge'), so the graph is keyed directly on those ids. Edges are matched | ||||||||||||||||||||||||
| between the measured @λ@ and stored @λ^safe@ snapshots by their @(srcNode, dstNode)@ pair | ||||||||||||||||||||||||
| — unique because the demo topology is a complete graph (one link per ordered node pair). | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| @Signed 64@ UGN values are widened to 'Integer' for the (overflow-prone) relaxation, and | ||||||||||||||||||||||||
| the resulting reset offsets / frame counts are narrowed back with a bounds check. | ||||||||||||||||||||||||
|
Comment on lines
+6
to
+16
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. He talked a lot, but said nothing. |
||||||||||||||||||||||||
| -} | ||||||||||||||||||||||||
| module Bittide.Instances.Hitl.Utils.UgnGrooming ( | ||||||||||||||||||||||||
|
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. Alright. After reading through this whole commit, I feel that There is also a bunch of duplication, though I feel that that will solve itself if you just move everything to |
||||||||||||||||||||||||
| ugnGraph, | ||||||||||||||||||||||||
| safeMargin, | ||||||||||||||||||||||||
| canonicalizeUgn, | ||||||||||||||||||||||||
| RelabelPlan (..), | ||||||||||||||||||||||||
| computeRelabel, | ||||||||||||||||||||||||
| ) where | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| import Prelude | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| import Clash.Prelude (BitVector, Signed, Vec, checkedFromIntegral) | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| import Bittide.ClockControl.Ugn.Grooming (GroomResult (..), groomCorrection) | ||||||||||||||||||||||||
| import Bittide.Graph.Weighted (Graph) | ||||||||||||||||||||||||
| import Bittide.Instances.Hitl.Setup (FpgaCount, LinkCount, knownLinkConfigs) | ||||||||||||||||||||||||
| import Bittide.Instances.Hitl.Utils.Ugn (UgnEdge (..), indexToNodeId) | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| import qualified Bittide.Graph.Weighted as G | ||||||||||||||||||||||||
| import qualified Clash.Prelude as CP | ||||||||||||||||||||||||
| import qualified Data.Map.Strict as Map | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| {- | Build a weighted graph from UGN edges, keyed on the DNA-derived node ids with | ||||||||||||||||||||||||
| the (signed) UGN as the 'Integer' edge weight. | ||||||||||||||||||||||||
|
Comment on lines
+39
to
+40
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.
Suggested change
|
||||||||||||||||||||||||
| -} | ||||||||||||||||||||||||
| ugnGraph :: [UgnEdge] -> Graph (BitVector 32) Integer | ||||||||||||||||||||||||
| ugnGraph es = G.fromEdges [(e.srcNode, e.dstNode, toInteger e.ugn) | e <- es] | ||||||||||||||||||||||||
|
Comment on lines
+42
to
+43
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. Can this function move to |
||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| {- | Add a safety margin @ε@ to every edge: @λ^safe = λ + ε@. Mirrors the | ||||||||||||||||||||||||
| record-update style of 'Bittide.Instances.Hitl.Utils.Ugn.addLatencyEdge'. | ||||||||||||||||||||||||
| -} | ||||||||||||||||||||||||
| safeMargin :: Signed 64 -> [UgnEdge] -> [UgnEdge] | ||||||||||||||||||||||||
| safeMargin eps = map (\e -> e{ugn = e.ugn + eps}) | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
|
Comment on lines
+45
to
+50
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.
|
||||||||||||||||||||||||
| {- | Relabel UGN edges to their minimal non-negative form: the Bellman-Ford reduced | ||||||||||||||||||||||||
| costs @λ_{i->j} + q_i - q_j@ (potentials @q@ from the super-source), which are all | ||||||||||||||||||||||||
| @>= 0@ and leave every round-trip / cycle sum unchanged. | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| This is a pure gauge change (a relabeling), so it represents the /same/ physical | ||||||||||||||||||||||||
| system, but in a gauge where the UGNs are small and non-negative. Storing | ||||||||||||||||||||||||
| @λ^safe@ in this gauge keeps the application's per-link UGNs (and hence its fixed | ||||||||||||||||||||||||
| schedule) inside the working range a depth-bounded mux/elastic-buffer needs, while | ||||||||||||||||||||||||
| still honouring the true /asymmetric/ cycle constraints (unlike a symmetric | ||||||||||||||||||||||||
| midpoint, which is only a valid relabeling on an acyclic graph). | ||||||||||||||||||||||||
|
Comment on lines
+51
to
+60
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.
Suggested change
|
||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| If the edges are not physically allowed (a negative cycle), they are returned | ||||||||||||||||||||||||
| unchanged. | ||||||||||||||||||||||||
|
Comment on lines
+62
to
+63
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. Make it return an martijn@volthe:~$ python3 -c "import this" | head -n 12 | tail -n 1
Errors should never pass silently. |
||||||||||||||||||||||||
| -} | ||||||||||||||||||||||||
| canonicalizeUgn :: [UgnEdge] -> [UgnEdge] | ||||||||||||||||||||||||
| canonicalizeUgn es = | ||||||||||||||||||||||||
|
Comment on lines
+65
to
+66
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. It's not clear to me whether this is here because of your work on Manticore, or whether it's fundamentally needed for the demo in this PR. Could you clarify? |
||||||||||||||||||||||||
| case G.potentials (ugnGraph es) of | ||||||||||||||||||||||||
| Nothing -> es | ||||||||||||||||||||||||
| Just q -> | ||||||||||||||||||||||||
| [ e{ugn = checkedFromIntegral (toInteger e.ugn + qOf e.srcNode - qOf e.dstNode)} | ||||||||||||||||||||||||
| | e <- es | ||||||||||||||||||||||||
| ] | ||||||||||||||||||||||||
| where | ||||||||||||||||||||||||
| qOf n = Map.findWithDefault 0 n q | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| {- | The result of grooming a measured boot onto a target: per-node reset offsets and | ||||||||||||||||||||||||
| per-node, per-link frame corrections, both FPGA-/link-indexed and ready to apply. | ||||||||||||||||||||||||
| -} | ||||||||||||||||||||||||
| data RelabelPlan = RelabelPlan | ||||||||||||||||||||||||
| { resetOffsets :: Vec FpgaCount (Signed 64) | ||||||||||||||||||||||||
|
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. Why isn't this just an absolute clock cycle? What's this all about a shared base all of a sudden? |
||||||||||||||||||||||||
| {- ^ Per-node offset to add to the shared base to get its reset-release cycle. This | ||||||||||||||||||||||||
| realises the relabel @q@: every node's application counter leaves reset in the | ||||||||||||||||||||||||
| relabeled domain. Gauged so node 0's offset is 0. | ||||||||||||||||||||||||
|
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 seems to relate to the canonicalization step, but that's not clear to me. |
||||||||||||||||||||||||
| -} | ||||||||||||||||||||||||
| , corrections :: Vec FpgaCount (Vec LinkCount (Signed 64)) | ||||||||||||||||||||||||
|
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 is derived from
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. Why is this a |
||||||||||||||||||||||||
| {- ^ Per-node, per-link frame corrections: the frames the management unit inserts | ||||||||||||||||||||||||
|
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. Overly complex. |
||||||||||||||||||||||||
| (@> 0@) or removes (@< 0@) on each receiving link to reach @λ^safe@ after relabeling. | ||||||||||||||||||||||||
| -} | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
| deriving (Show) | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| {- | Groom this boot's measured UGNs onto the target @λ^safe@ and produce an applyable | ||||||||||||||||||||||||
| 'RelabelPlan': per-node reset offsets (the relabel @q@) and per-link frame corrections. | ||||||||||||||||||||||||
| Returns 'Left' (with the witnessing node ids) if the UGNs changed too much to fit under | ||||||||||||||||||||||||
| @λ^safe@ (a negative cycle in the slack graph). | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| Calls 'groomCorrection' (Bellman-Ford, per the UGN grooming slides) directly on the | ||||||||||||||||||||||||
| measured / target 'ugnGraph's. The relabel @q@ is the per-node potential that fits this | ||||||||||||||||||||||||
| boot's @λ@ under the stored @λ^safe@ (@λ + B^T q <= λ^safe@); the residual | ||||||||||||||||||||||||
| @frames = λ^safe - (λ + B^T q)@ are the small, non-negative per-link corrections the | ||||||||||||||||||||||||
| elastic buffers insert. So: | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| * @resetOffsets_i = -(q_i - q_0)@ — the reset release that applies the relabel | ||||||||||||||||||||||||
| (gauged so node 0 is 0); and | ||||||||||||||||||||||||
| * @corrections@ — the per-receiving-link frames. Since 'groomCorrection' returns frames | ||||||||||||||||||||||||
| keyed by @(srcNode, dstNode)@, the receiving @(fpga, port)@ is reconstructed via | ||||||||||||||||||||||||
| 'knownLinkConfigs' (the same link map 'Bittide.Instances.Hitl.Utils.Ugn.ugnEdges' | ||||||||||||||||||||||||
| uses). | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| When @λ^safe@ is stored in a small non-negative gauge (see 'canonicalizeUgn'), the relabel | ||||||||||||||||||||||||
| absorbs this boot's counter offsets so the groomed app-frame UGNs land back on @λ^safe@ — | ||||||||||||||||||||||||
| small, non-negative, and identical every run, which is what makes a single fixed schedule | ||||||||||||||||||||||||
| reusable. | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| Edges are matched by @(srcNode, dstNode)@; pass the full measured + target graphs to | ||||||||||||||||||||||||
| groom every link. | ||||||||||||||||||||||||
|
Comment on lines
+92
to
+116
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. Okay...
In general it's a lot of prose which only achieves confusion. Just call it what it is: a call to |
||||||||||||||||||||||||
| -} | ||||||||||||||||||||||||
| computeRelabel :: | ||||||||||||||||||||||||
| -- | Measured UGNs @λ@ | ||||||||||||||||||||||||
| [UgnEdge] -> | ||||||||||||||||||||||||
| -- | Target UGNs @λ^safe@ | ||||||||||||||||||||||||
| [UgnEdge] -> | ||||||||||||||||||||||||
| Either [BitVector 32] RelabelPlan | ||||||||||||||||||||||||
| computeRelabel measured target = | ||||||||||||||||||||||||
| case groomCorrection (ugnGraph measured) (ugnGraph target) of | ||||||||||||||||||||||||
| Infeasible ns -> Left ns | ||||||||||||||||||||||||
| Feasible{correction = q, framesToInsert} -> | ||||||||||||||||||||||||
| Right | ||||||||||||||||||||||||
| RelabelPlan | ||||||||||||||||||||||||
| { resetOffsets = (\idx -> negate (qOf idx - qOf 0)) <$> CP.indicesI | ||||||||||||||||||||||||
| , corrections = (\idx -> (\port -> frameOf idx port) <$> CP.indicesI) <$> CP.indicesI | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
| where | ||||||||||||||||||||||||
| qOf idx = checkedFromIntegral (Map.findWithDefault 0 (indexToNodeId idx) q) | ||||||||||||||||||||||||
| frameByEdge = Map.fromList [((i, j), f) | (i, j, f) <- framesToInsert] | ||||||||||||||||||||||||
| frameOf dstIdx port = | ||||||||||||||||||||||||
| checkedFromIntegral (Map.findWithDefault 0 (srcNode, dstNode) frameByEdge) | ||||||||||||||||||||||||
| where | ||||||||||||||||||||||||
| srcNode = indexToNodeId ((knownLinkConfigs CP.!! dstIdx) CP.!! port) | ||||||||||||||||||||||||
| dstNode = indexToNodeId dstIdx | ||||||||||||||||||||||||
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.