Skip to content

Commit 9b12c63

Browse files
authored
Merge pull request #184 from clash-lang/specialize-wishbone
Specialize payload of `Wishbone` to be `BitVector (w * 8)`.
2 parents 77e9f91 + 84bca4d commit 9b12c63

File tree

6 files changed

+231
-279
lines changed

6 files changed

+231
-279
lines changed

clash-protocols/src/Data/Constraint/Nat/Extra.hs

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,6 @@ import Clash.Prelude
1212
import Data.Constraint
1313
import Unsafe.Coerce (unsafeCoerce)
1414

15-
{- | Postulates that multiplying some number /a/ by some constant /b/, and
16-
subsequently dividing that result by /b/ equals /a/.
17-
-}
18-
cancelMulDiv :: forall a b. (1 <= b) => Dict (DivRU (a * b) b ~ a)
19-
cancelMulDiv = unsafeCoerce (Dict :: Dict (0 ~ 0))
20-
2115
-- | if (1 <= b) then (Mod a b + 1 <= b)
2216
leModulusDivisor :: forall a b. (1 <= b) => Dict (Mod a b + 1 <= b)
2317
leModulusDivisor = unsafeCoerce (Dict :: Dict (0 <= 0))

clash-protocols/src/Protocols/Wishbone.hs

Lines changed: 34 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ Types modelling the Wishbone bus protocol.
88
-}
99
module Protocols.Wishbone where
1010

11-
import Clash.Prelude (DivRU, Nat, Type, (:::))
11+
import Clash.Prelude (Nat, (:::))
1212
import Prelude hiding (head, not, (&&))
1313

1414
import Clash.Signal.Internal (Signal (..))
@@ -19,17 +19,17 @@ import Protocols.Idle
1919
import Clash.Prelude qualified as C
2020

2121
-- | Data communicated from a Wishbone Master to a Wishbone Slave
22-
data WishboneM2S addressWidth selWidth dat = WishboneM2S
23-
{ addr :: "ADR" ::: C.BitVector addressWidth
22+
data WishboneM2S addressBits dataBytes = WishboneM2S
23+
{ addr :: "ADR" ::: C.BitVector addressBits
2424
-- ^ The address output array [ADR_O()] is used to pass a binary address. The higher array
2525
-- boundary is specific to the address width of the core, and the lower array boundary is
2626
-- determined by the data port size and granularity. For example the array size on a 32-bit
2727
-- data port with BYTE granularity is [ADR_O(n..2)]. In some cases (such as FIFO
2828
-- interfaces) the array may not be present on the interface.
29-
, writeData :: "DAT_MOSI" ::: dat
29+
, writeData :: "DAT_MOSI" ::: C.BitVector (dataBytes C.* 8)
3030
-- ^ The data output array [DAT_O()] is used to pass binary data. The array boundaries are
3131
-- determined by the port size, with a maximum port size of 64-bits (e.g. [DAT_I(63..0)]).
32-
, busSelect :: "SEL" ::: C.BitVector selWidth
32+
, busSelect :: "SEL" ::: C.BitVector dataBytes
3333
-- ^ The select output array [SEL_O()] indicates where valid data is expected on the [DAT_I()]
3434
-- signal array during READ cycles, and where it is placed on the [DAT_O()] signal array
3535
-- during WRITE cycles. The array boundaries are determined by the granularity of a port.
@@ -69,16 +69,16 @@ data WishboneM2S addressWidth selWidth dat = WishboneM2S
6969
deriving (NFData, C.Generic, C.NFDataX, Eq, C.BitPack)
7070

7171
instance
72-
(C.ShowX dat, C.KnownNat addressWidth, C.KnownNat selWidth) =>
73-
C.ShowX (WishboneM2S addressWidth selWidth dat)
72+
(C.KnownNat addressBits, C.KnownNat dataBytes) =>
73+
C.ShowX (WishboneM2S addressBits dataBytes)
7474
where
7575
showX = show
7676

7777
-- Compact printing for M2S values. This handles undefined values in the
7878
-- structure too.
7979
instance
80-
(C.ShowX dat, C.KnownNat addressWidth, C.KnownNat selWidth) =>
81-
Show (WishboneM2S addressWidth selWidth dat)
80+
(C.KnownNat addressBits, C.KnownNat dataBytes) =>
81+
Show (WishboneM2S addressBits dataBytes)
8282
where
8383
show WishboneM2S{..} =
8484
"WishboneM2S [ "
@@ -121,8 +121,8 @@ instance
121121
CycleTypeIdentifier val -> "reserved (" <> C.showX val <> ")"
122122

123123
-- | Data communicated from a Wishbone Slave to a Wishbone Master
124-
data WishboneS2M dat = WishboneS2M
125-
{ readData :: "DAT_MISO" ::: dat
124+
data WishboneS2M dataBytes = WishboneS2M
125+
{ readData :: "DAT_MISO" ::: C.BitVector (dataBytes C.* 8)
126126
-- ^ The data output array [DAT_O()] is used to pass binary data. The array boundaries are
127127
-- determined by the port size, with a maximum port size of 64-bits (e.g. [DAT_I(63..0)]).
128128
, acknowledge :: "ACK" ::: Bool
@@ -143,12 +143,12 @@ data WishboneS2M dat = WishboneS2M
143143
}
144144
deriving (NFData, C.Generic, C.NFDataX, Eq, C.BitPack)
145145

146-
instance (C.ShowX dat) => C.ShowX (WishboneS2M dat) where
146+
instance (C.KnownNat dataBytes) => C.ShowX (WishboneS2M dataBytes) where
147147
showX = show
148148

149149
-- Compact printing for S2M values. This handles undefined values in the
150150
-- structure too.
151-
instance (C.ShowX dat) => Show (WishboneS2M dat) where
151+
instance (C.KnownNat dataBytes) => Show (WishboneS2M dataBytes) where
152152
show WishboneS2M{..} =
153153
"WishboneS2M [ "
154154
<> prefix acknowledge
@@ -217,27 +217,27 @@ data
217217
Wishbone
218218
(dom :: C.Domain)
219219
(mode :: WishboneMode)
220-
(addressWidth :: Nat)
221-
(userType :: Type)
220+
(addressBits :: Nat)
221+
(dataBytes :: Nat)
222222

223-
instance Protocol (Wishbone dom mode addressWidth dat) where
223+
instance Protocol (Wishbone dom mode addressBits dataBytes) where
224224
type
225-
Fwd (Wishbone dom mode addressWidth dat) =
226-
Signal dom (WishboneM2S addressWidth (C.BitSize dat `DivRU` 8) dat)
225+
Fwd (Wishbone dom mode addressBits dataBytes) =
226+
Signal dom (WishboneM2S addressBits dataBytes)
227227

228-
type Bwd (Wishbone dom mode addressWidth dat) = Signal dom (WishboneS2M dat)
228+
type Bwd (Wishbone dom mode addressBits dataBytes) = Signal dom (WishboneS2M dataBytes)
229229

230230
instance
231-
(C.KnownNat aw, C.KnownNat (C.BitSize dat), C.NFDataX dat) =>
232-
IdleCircuit (Wishbone dom mode aw dat)
231+
(C.KnownNat aw, C.KnownNat dw) =>
232+
IdleCircuit (Wishbone dom mode aw dw)
233233
where
234234
idleFwd _ = C.pure emptyWishboneM2S
235235
idleBwd _ = C.pure emptyWishboneS2M
236236

237237
-- | Construct "default" Wishbone M2S signals
238238
emptyWishboneM2S ::
239-
(C.KnownNat addressWidth, C.KnownNat (C.BitSize dat), C.NFDataX dat) =>
240-
WishboneM2S addressWidth (C.BitSize dat `DivRU` 8) dat
239+
(C.KnownNat addressBits, C.KnownNat dataBytes) =>
240+
WishboneM2S addressBits dataBytes
241241
emptyWishboneM2S =
242242
WishboneM2S
243243
{ addr = C.deepErrorX "M2S address not defined"
@@ -252,7 +252,7 @@ emptyWishboneM2S =
252252
}
253253

254254
-- | Construct "default" Wishbone S2M signals
255-
emptyWishboneS2M :: (C.NFDataX dat) => WishboneS2M dat
255+
emptyWishboneS2M :: (C.KnownNat dataBytes) => WishboneS2M dataBytes
256256
emptyWishboneS2M =
257257
WishboneS2M
258258
{ readData = C.deepErrorX "S2M readData not defined"
@@ -267,56 +267,55 @@ whether transactions are in progress(returns true for any 'hasTerminateFlag').
267267
This is useful to determine whether a Wishbone bus is active.
268268
269269
>>> :{
270-
let m2s = (emptyWishboneM2S @32 @()){busCycle = True, strobe = True}
270+
let m2s = (emptyWishboneM2S @32 @4){busCycle = True, strobe = True}
271271
s2m = emptyWishboneS2M{acknowledge = True}
272272
in hasBusActivity (m2s, s2m)
273273
:}
274274
True
275275
276276
>>> :{
277-
let m2s = (emptyWishboneM2S @32 @()){busCycle = True, strobe = True}
277+
let m2s = (emptyWishboneM2S @32 @4){busCycle = True, strobe = True}
278278
s2m = emptyWishboneS2M{retry = True}
279279
in hasBusActivity (m2s, s2m)
280280
:}
281281
True
282282
283283
>>> :{
284-
let m2s = (emptyWishboneM2S @32 @()){busCycle = True}
284+
let m2s = (emptyWishboneM2S @32 @4){busCycle = True}
285285
s2m = emptyWishboneS2M{acknowledge = True}
286286
in hasBusActivity (m2s, s2m)
287287
:}
288288
False
289289
290290
>>> :{
291-
let m2s = (emptyWishboneM2S @32 @()){busCycle = True, strobe = True}
291+
let m2s = (emptyWishboneM2S @32 @4){busCycle = True, strobe = True}
292292
s2m = emptyWishboneS2M
293293
in hasBusActivity (m2s, s2m)
294294
:}
295295
False
296296
297297
>>> :{
298-
let m2s = emptyWishboneM2S @32 @()
298+
let m2s = emptyWishboneM2S @32 @4
299299
s2m = emptyWishboneS2M{acknowledge = True}
300300
in hasBusActivity (m2s, s2m)
301301
:}
302302
False
303303
-}
304-
hasBusActivity :: (WishboneM2S addressWidth sel dat, WishboneS2M dat) -> Bool
304+
hasBusActivity :: (WishboneM2S addressBits dataBytes, WishboneS2M dataBytes) -> Bool
305305
hasBusActivity (m2s, s2m) = busCycle m2s C.&& strobe m2s C.&& hasTerminateFlag s2m
306306

307307
-- | Helper function to determine whether a Slave signals the termination of a cycle.
308-
hasTerminateFlag :: WishboneS2M dat -> Bool
308+
hasTerminateFlag :: WishboneS2M dataBytes -> Bool
309309
hasTerminateFlag s2m = acknowledge s2m || err s2m || retry s2m
310310

311311
{- | Force a /nack/ on the backward channel and /no data/ on the forward
312312
channel if reset is asserted.
313313
-}
314314
forceResetSanity ::
315-
forall dom mode aw a.
315+
forall dom mode aw dw.
316316
( C.HiddenClockResetEnable dom
317317
, C.KnownNat aw
318-
, C.KnownNat (C.BitSize a)
319-
, C.NFDataX a
318+
, C.KnownNat dw
320319
) =>
321-
Circuit (Wishbone dom mode aw a) (Wishbone dom mode aw a)
320+
Circuit (Wishbone dom mode aw dw) (Wishbone dom mode aw dw)
322321
forceResetSanity = forceResetSanityGeneric

clash-protocols/src/Protocols/Wishbone/Standard.hs

Lines changed: 27 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
{-# LANGUAGE ApplicativeDo #-}
2-
{-# LANGUAGE RecordWildCards #-}
32
{-# OPTIONS_GHC -fconstraint-solver-iterations=10 #-}
43

54
-- | Circuits and utils for working with Standard mode wishbone circuits.
@@ -13,17 +12,16 @@ import Prelude hiding (head, not, repeat, (!!), (&&), (||))
1312

1413
-- | Distribute requests amongst N slave circuits
1514
roundrobin ::
16-
forall n dom addressWidth a.
15+
forall n dom addressBits dataBytes.
1716
( KnownNat n
1817
, HiddenClockResetEnable dom
19-
, KnownNat addressWidth
20-
, KnownNat (BitSize a)
21-
, NFDataX a
18+
, KnownNat addressBits
19+
, KnownNat dataBytes
2220
, 1 <= n
2321
) =>
2422
Circuit
25-
(Wishbone dom 'Standard addressWidth a)
26-
(Vec n (Wishbone dom 'Standard addressWidth a))
23+
(Wishbone dom 'Standard addressBits dataBytes)
24+
(Vec n (Wishbone dom 'Standard addressBits dataBytes))
2725
roundrobin = Circuit $ \(m2s, s2ms) -> B.first head $ fn (singleton m2s, s2ms)
2826
where
2927
Circuit fn = sharedBus selectFn
@@ -35,26 +33,25 @@ roundrobin = Circuit $ \(m2s, s2ms) -> B.first head $ fn (singleton m2s, s2ms)
3533
A selector signal is used to compute the next M-S pair.
3634
-}
3735
sharedBus ::
38-
forall n m dom addressWidth a.
36+
forall n m dom addressBits dataBytes.
3937
( KnownNat n
4038
, KnownNat m
4139
, HiddenClockResetEnable dom
42-
, KnownNat addressWidth
43-
, KnownNat (BitSize a)
44-
, NFDataX a
40+
, KnownNat addressBits
41+
, KnownNat dataBytes
4542
) =>
4643
-- | Funcion to select which M-S pair should be connected next.
4744
( Signal
4845
dom
4946
( Index n
5047
, Index m
51-
, Vec n (WishboneM2S addressWidth (BitSize a `DivRU` 8) a)
48+
, Vec n (WishboneM2S addressBits dataBytes)
5249
) ->
5350
Signal dom (Index n, Index m)
5451
) ->
5552
Circuit
56-
(Vec n (Wishbone dom 'Standard addressWidth a))
57-
(Vec m (Wishbone dom 'Standard addressWidth a))
53+
(Vec n (Wishbone dom 'Standard addressBits dataBytes))
54+
(Vec m (Wishbone dom 'Standard addressBits dataBytes))
5855
sharedBus selectFn = Circuit go
5956
where
6057
go (bundle -> m2ss0, bundle -> s2ms0) = (unbundle s2ms1, unbundle m2ss1)
@@ -74,19 +71,18 @@ sharedBus selectFn = Circuit go
7471

7572
-- | Crossbar-Switch circuit, allowing to dynamically route N masters to N slaves
7673
crossbarSwitch ::
77-
forall n m dom addressWidth a.
74+
forall n m dom addressBits dataBytes.
7875
( KnownNat n
7976
, KnownNat m
8077
, KnownDomain dom
81-
, KnownNat addressWidth
82-
, NFDataX a
83-
, KnownNat (BitSize a)
78+
, KnownNat addressBits
79+
, KnownNat dataBytes
8480
) =>
8581
Circuit
8682
( CSignal dom (Vec n (Index m)) -- route
87-
, Vec n (Wishbone dom 'Standard addressWidth a) -- masters
83+
, Vec n (Wishbone dom 'Standard addressBits dataBytes) -- masters
8884
)
89-
(Vec m (Wishbone dom 'Standard addressWidth a)) -- slaves
85+
(Vec m (Wishbone dom 'Standard addressBits dataBytes)) -- slaves
9086
crossbarSwitch = Circuit go
9187
where
9288
go ((route, bundle -> m2ss0), bundle -> s2ms0) =
@@ -108,26 +104,24 @@ data MemoryDelayState = Wait | AckRead
108104
The data rate could be increased by using registered feedback cycles or
109105
by using a pipelined circuit which would eliminate one wait cycle.
110106
111-
Since the underlying block RAM operates on values of @a@ directly, the only
107+
Since the underlying block RAM operates on the whole bitvector, the only
112108
accepted bus selector value is 'maxBound'. All other bus selector values
113109
will cause an ERR response.
114110
115111
TODO create pipelined memory circuit
116112
-}
117113
memoryWb ::
118-
forall dom a addressWidth.
119-
( BitPack a
120-
, NFDataX a
121-
, KnownDomain dom
122-
, KnownNat addressWidth
114+
forall dom addressBits dataBytes.
115+
( KnownDomain dom
116+
, KnownNat addressBits
117+
, KnownNat dataBytes
123118
, HiddenClockResetEnable dom
124-
, Default a
125119
) =>
126-
( Signal dom (BitVector addressWidth) ->
127-
Signal dom (Maybe (BitVector addressWidth, a)) ->
128-
Signal dom a
120+
( Signal dom (BitVector addressBits) ->
121+
Signal dom (Maybe (BitVector addressBits, BitVector (dataBytes * 8))) ->
122+
Signal dom (BitVector (dataBytes * 8))
129123
) ->
130-
Circuit (Wishbone dom 'Standard addressWidth a) ()
124+
Circuit (Wishbone dom 'Standard addressBits dataBytes) ()
131125
memoryWb ram = Circuit go
132126
where
133127
go (m2s, ()) = (s2m1, ())
@@ -136,7 +130,7 @@ memoryWb ram = Circuit go
136130
s2m1 = (\s2m dat -> s2m{readData = dat}) <$> s2m0 <*> readValue
137131
readValue = ram readAddr write
138132

139-
fsm st m2s
133+
fsm st (m2s :: WishboneM2S addressBits dataBytes)
140134
-- Manager must be active if we're in this state
141135
| AckRead <- st = (Wait, (0, Nothing, noS2M{acknowledge = True}))
142136
-- Stay in Wait for invalid transactions
@@ -147,7 +141,7 @@ memoryWb ram = Circuit go
147141
| isRead = (AckRead, (m2s.addr, Nothing, noS2M))
148142
| otherwise = (Wait, (0, Nothing, noS2M))
149143
where
150-
noS2M = emptyWishboneS2M @()
144+
noS2M = emptyWishboneS2M :: WishboneS2M dataBytes
151145
managerActive = m2s.busCycle && m2s.strobe
152146
isError = managerActive && (m2s.busSelect /= maxBound)
153147
isWrite = managerActive && m2s.writeEnable

0 commit comments

Comments
 (0)