Skip to content

Commit 14583fb

Browse files
committed
Test addressableBytesWb HAL
1 parent cd7d0ea commit 14583fb

13 files changed

Lines changed: 604 additions & 38 deletions

File tree

bittide-instances/bittide-instances.cabal

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,7 @@ library
222222
Bittide.Instances.Pnr.Si539xSpi
223223
Bittide.Instances.Pnr.Switch
224224
Bittide.Instances.Pnr.Synchronizer
225+
Bittide.Instances.Tests.AddressableBytesWb
225226
Bittide.Instances.Tests.ElasticBufferWb
226227
Bittide.Instances.Tests.NestedInterconnect
227228
Bittide.Instances.Tests.RegisterWb
@@ -314,6 +315,7 @@ test-suite unittests
314315
Tests.Bittide.Instances.Hitl.Utils.OpenOcd
315316
Tests.Bittide.Instances.Hitl.Utils.Picocom
316317
Tests.ClockControlWb
318+
Wishbone.AddressableBytesWb
317319
Wishbone.Axi
318320
Wishbone.CaptureUgn
319321
Wishbone.DnaPortE2

bittide-instances/src/Bittide/Instances/MemoryMaps.hs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import qualified Bittide.Instances.Hitl.Si539xConfiguration as Si539xConfigurati
2525
import qualified Bittide.Instances.Hitl.SoftUgnDemo.MemoryMaps as SoftUgnDemo
2626
import qualified Bittide.Instances.Hitl.SwitchDemo.MemoryMaps as SwitchDemo
2727
import qualified Bittide.Instances.Hitl.SwitchDemoGppe.MemoryMaps as SwitchDemoGppe
28+
import qualified Bittide.Instances.Tests.AddressableBytesWb as AddressableBytesWb
2829
import qualified Bittide.Instances.Tests.ElasticBufferWb as ElasticBufferWb
2930
import qualified Bittide.Instances.Tests.NestedInterconnect as NestedInterconnect
3031
import qualified Bittide.Instances.Tests.RegisterWb as RegisterWb
@@ -42,7 +43,8 @@ $( do
4243
-- Add new memory maps here --
4344
-------------------------------
4445
let memoryMaps =
45-
[ ("Ethernet", vexRiscvEthernetMM)
46+
[ ("AddressableBytesWb", AddressableBytesWb.memoryMap)
47+
, ("Ethernet", vexRiscvEthernetMM)
4648
, ("ElasticBufferWbTest", ElasticBufferWb.dutMM)
4749
, ("Freeze", freezeMM)
4850
, ("NestedInterconnect", NestedInterconnect.nestedInterconnectMm)
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
-- SPDX-FileCopyrightText: 2025 Google LLC
2+
--
3+
-- SPDX-License-Identifier: Apache-2.0
4+
5+
module Bittide.Instances.Tests.AddressableBytesWb where
6+
7+
import Clash.Prelude
8+
9+
-- Local
10+
import Bittide.Cpus.Riscv32imc (vexRiscv0)
11+
import Bittide.DoubleBufferedRam (
12+
ContentType (Vec),
13+
wbStorage,
14+
)
15+
import Bittide.Instances.Domains (Basic50)
16+
import Bittide.ProcessingElement (
17+
PeConfig (..),
18+
processingElement,
19+
)
20+
import Bittide.ProcessingElement.Util (
21+
vecFromElfData,
22+
vecFromElfInstr,
23+
)
24+
import Bittide.SharedTypes (withBittideByteOrder)
25+
import Bittide.Wishbone (uartBytes, uartInterfaceWb)
26+
import Project.FilePath (
27+
CargoBuildType (Release),
28+
findParentContaining,
29+
firmwareBinariesDir,
30+
)
31+
32+
import Clash.Class.BitPackC (ByteOrder (BigEndian))
33+
import Data.Char (chr)
34+
import Data.Maybe (catMaybes)
35+
import Protocols
36+
import Protocols.Idle (idleSource)
37+
import Protocols.MemoryMap (MemoryMap, Mm, getMMAny)
38+
import System.Environment (lookupEnv)
39+
import System.FilePath ((</>))
40+
import System.IO.Unsafe (unsafePerformIO)
41+
import Test.Tasty.HUnit (HasCallStack)
42+
import VexRiscv (DumpVcd (DumpVcd, NoDumpVcd))
43+
44+
sim :: IO ()
45+
sim = do
46+
-- Print the UART output to terminal for debugging
47+
putStrLn "=== UART Output ==="
48+
putStrLn simResult
49+
putStrLn "=================="
50+
51+
simResult :: String
52+
simResult = chr . fromIntegral <$> catMaybes uartStream
53+
where
54+
uartStream = sampleC def{timeoutAfter = 1000000} dut0
55+
56+
dut0 :: Circuit () (Df Basic50 (BitVector 8))
57+
dut0 = Circuit $ ((),) . snd . toSignals dut . ((),) . snd
58+
59+
{- | An instance connecting a VexRiscv to a UART and an addressable buffer device.
60+
Uses the Rust test binary.
61+
-}
62+
dut :: Circuit (ToConstBwd Mm) (Df Basic50 (BitVector 8))
63+
dut = dutWithBinary "addressable_bytes_wb_test"
64+
65+
-- | Parameterized DUT that loads a specific firmware binary.
66+
dutWithBinary ::
67+
(HasCallStack) =>
68+
String ->
69+
Circuit (ToConstBwd Mm) (Df Basic50 (BitVector 8))
70+
dutWithBinary binaryName =
71+
withBittideByteOrder
72+
$ withClockResetEnable clockGen (resetGenN d2) enableGen
73+
$ circuit
74+
$ \mm -> do
75+
(uartRx, jtag) <- idleSource
76+
[uartBus, addressableBus] <- processingElement dumpVcd (peConfig binaryName) -< (mm, jtag)
77+
(uartTx, _uartStatus) <- uartInterfaceWb d2 d2 uartBytes -< (uartBus, uartRx)
78+
wbStorage "AddressableBuffer" d8 Nothing -< addressableBus
79+
idC -< uartTx
80+
where
81+
dumpVcd =
82+
unsafePerformIO $ do
83+
mVal <- lookupEnv "ADDRESSABLE_BYTES_WB_DUMP_VCD"
84+
case mVal of
85+
Just s -> pure (DumpVcd s)
86+
_ -> pure NoDumpVcd
87+
88+
peConfig binary = unsafePerformIO $ do
89+
root <- findParentContaining "cabal.project"
90+
let elfPath = root </> firmwareBinariesDir "riscv32imc" Release </> binary
91+
pure
92+
PeConfig
93+
{ cpu = vexRiscv0
94+
, depthI = SNat @IMemWords
95+
, depthD = SNat @DMemWords
96+
, initI =
97+
Just
98+
$ Vec
99+
$ unsafePerformIO
100+
$ vecFromElfInstr BigEndian elfPath
101+
, initD =
102+
Just
103+
$ Vec
104+
$ unsafePerformIO
105+
$ vecFromElfData BigEndian elfPath
106+
, iBusTimeout = d0 -- No timeouts on the instruction bus
107+
, dBusTimeout = d0 -- No timeouts on the data bus
108+
, includeIlaWb = False
109+
}
110+
{-# OPAQUE dutWithBinary #-}
111+
112+
memoryMap :: MemoryMap
113+
memoryMap = getMMAny dut0
114+
where
115+
dut0 :: Circuit (ToConstBwd Mm, Df System ()) ()
116+
dut0 = circuit $ \(mm, _df) -> do
117+
_uart <- dut -< mm
118+
idC
119+
120+
type IMemWords = DivRU (256 * 1024) 4
121+
type DMemWords = DivRU (256 * 1024) 4
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
-- SPDX-FileCopyrightText: 2025 Google LLC
2+
--
3+
-- SPDX-License-Identifier: Apache-2.0
4+
5+
module Wishbone.AddressableBytesWb where
6+
7+
import Clash.Prelude
8+
9+
import Data.List (isInfixOf)
10+
import Test.Tasty (TestTree)
11+
import Test.Tasty.HUnit (Assertion, assertBool, testCase)
12+
import Test.Tasty.TH (testGroupGenerator)
13+
14+
import Bittide.Instances.Tests.AddressableBytesWb (simResult)
15+
16+
case_sim :: Assertion
17+
case_sim = assertBool msg ("RESULT: OK" `isInfixOf` simResult)
18+
where
19+
msg = "Received the following from the CPU over UART:\n" <> simResult
20+
21+
tests :: TestTree
22+
tests = $(testGroupGenerator)

bittide-instances/tests/unittests.hs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import qualified Tests.Bittide.Instances.Hitl.Utils.MemoryMap as MemoryMap
2121
import qualified Tests.Bittide.Instances.Hitl.Utils.OpenOcd as OpenOcd
2222
import qualified Tests.Bittide.Instances.Hitl.Utils.Picocom as Picocom
2323
import qualified Tests.ClockControlWb as ClockControlWb
24+
import qualified Wishbone.AddressableBytesWb as AddressableBytesWb
2425
import qualified Wishbone.Axi as Axi
2526
import qualified Wishbone.CaptureUgn as CaptureUgn
2627
import qualified Wishbone.DnaPortE2 as DnaPortE2
@@ -69,7 +70,8 @@ tests =
6970
]
7071
, testGroup
7172
"Unittests"
72-
[ Axi.tests
73+
[ AddressableBytesWb.tests
74+
, Axi.tests
7375
, CaptureUgn.tests
7476
, ClockControlWb.tests
7577
, DnaPortE2.tests

bittide/src/Bittide/DoubleBufferedRam.hs

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ module Bittide.DoubleBufferedRam where
88
import Clash.Prelude
99

1010
import Data.Maybe
11-
import Protocols (Ack (Ack), CSignal, Circuit (Circuit), Df, toSignals)
11+
import Protocols (Ack (Ack), CSignal, Circuit (Circuit), Df, toSignals, (<|))
1212
import Protocols.Wishbone
1313

1414
import Bittide.Extra.Maybe
@@ -18,12 +18,14 @@ import Data.Typeable
1818
import GHC.Stack (HasCallStack)
1919
import Protocols.MemoryMap (unMemmap)
2020
import Protocols.MemoryMap.Registers.WishboneStandard (
21+
addressableBytesWb,
2122
deviceWb,
2223
matchEndianness,
23-
memoryWb,
2424
registerConfig,
2525
)
2626

27+
import qualified Protocols.ReqResp as ReqResp
28+
2729
data ContentType n a
2830
= Vec (Vec n a)
2931
| Blob (MemBlob n (BitSize a))
@@ -82,26 +84,31 @@ wbStorage ::
8284
( HasCallStack
8385
, HiddenClockResetEnable dom
8486
, KnownNat aw
85-
, KnownNat depth
8687
, 1 <= depth
8788
, ?busByteOrder :: ByteOrder
8889
) =>
8990
String ->
9091
SNat depth ->
9192
Maybe (ContentType depth (Bytes 4)) ->
9293
Circuit (BitboneMm dom aw) ()
93-
wbStorage memoryName depth initContent =
94+
wbStorage memoryName SNat initContent =
9495
let ?regByteOrder = BigEndian
9596
in circuit $ \(mm, wbMaster0) -> do
9697
wbMaster1 <- matchEndianness -< wbMaster0
9798
[wb0] <- deviceWb memoryName -< (mm, wbMaster1)
98-
memoryWb hasClock hasReset (registerConfig "data") ram depth -< wb0
99+
reqresp <- addressableBytesWb regConfig -< wb0
100+
(reads, writes0) <- ReqResp.partitionEithers -< reqresp
101+
writes1 <- ReqResp.requests <| ReqResp.dropResponse 0 -< writes0
102+
_vecUnit <- ram -< (reads, writes1)
103+
idC -< ()
99104
where
100-
ram = case initContent of
101-
Nothing ->
102-
blockRamByteAddressableU
103-
Just content ->
104-
blockRamByteAddressable @_ @depth content
105+
regConfig = registerConfig "data"
106+
ram = ReqResp.fromBlockRamWithMask
107+
$ case initContent of
108+
Nothing ->
109+
blockRamByteAddressableU
110+
Just content ->
111+
blockRamByteAddressable @_ @depth content
105112
{-# OPAQUE wbStorage #-}
106113

107114
-- | Storage element with a single wishbone port. Allows for word-aligned addresses.

0 commit comments

Comments
 (0)