Skip to content

Commit dbc0d5c

Browse files
committed
Add Simulate instance for AXI4Lite
1 parent dbe4634 commit dbc0d5c

File tree

3 files changed

+170
-78
lines changed

3 files changed

+170
-78
lines changed

src/Protocols/Axi4/Lite/Axi4Lite.hs

Lines changed: 169 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
11
{-# LANGUAGE FlexibleContexts #-}
22
{-# LANGUAGE FlexibleInstances #-}
33
{-# LANGUAGE UndecidableInstances #-}
4-
<<<<<<< HEAD
54
{-# LANGUAGE RecordWildCards #-}
6-
=======
7-
>>>>>>> cc790e6... Add AXI4 Lite types
85
{-|
96
Defines datatypes for all five channels of the AXI4 Lite protocol. For more
107
information on AXI4 Lite, see chapter B of the AMBA AXI specification.
@@ -15,15 +12,17 @@ module Protocols.Axi4.Lite.Axi4Lite where
1512
import Protocols
1613
import Protocols.Axi4.Common
1714
import Clash.Prelude as C
15+
import Clash.Signal.Internal
16+
import Data.List ((\\))
1817

1918
import Control.DeepSeq
2019

20+
import qualified Data.Bifunctor as B
21+
22+
23+
2124
-- | AXI4 Lite busses are always either 32 bit or 64 bit.
22-
<<<<<<< HEAD
2325
data BusWidth = Width32 | Width64 deriving (Show, Eq, Generic, NFDataX)
24-
=======
25-
data BusWidth = Width32 | Width64 deriving (Show, Eq)
26-
>>>>>>> cc790e6... Add AXI4 Lite types
2726

2827
type instance Width 'Width32 = 32
2928
type instance Width 'Width64 = 64
@@ -40,10 +39,6 @@ type family ReadBusWidthType (bw :: BusWidth) where
4039
ReadBusWidthType 'Width32 = C.Vec 4 (C.BitVector 8)
4140
ReadBusWidthType 'Width64 = C.Vec 8 (C.BitVector 8)
4241

43-
<<<<<<< HEAD
44-
=======
45-
46-
>>>>>>> cc790e6... Add AXI4 Lite types
4742
---------------------------
4843
--- Write address types ---
4944
---------------------------
@@ -158,16 +153,12 @@ data S2M_ReadAddress
158153
--- Read data types ---
159154
-----------------------
160155

161-
-- | Acknowledges data from the slave component. This data type needs the 'bw' type
162-
-- to fullfil the injectivity requirement of 'Fwd' in 'Protocol', even though it only
163-
-- contains a ready signal of type 'Bool'.
156+
-- | Acknowledges data from the slave component.
164157
data M2S_ReadData
165-
(bw :: BusWidth)
166158
= M2S_ReadData {
167159
_rready :: Bool
168-
} deriving (Generic, NFDataX)
160+
} deriving (Generic, NFDataX, Show)
169161

170-
deriving instance (Show (ReadBusWidthType bw)) => Show (M2S_ReadData bw)
171162

172163
-- | Data type for the data sent over the read data channel from the slave to the master.
173164
data S2M_ReadData
@@ -191,7 +182,7 @@ data M2S_Axi4Lite
191182
m2s_wd :: M2S_WriteData bw,
192183
m2s_wr :: M2S_WriteResponse,
193184
m2s_ra :: M2S_ReadAddress aw,
194-
m2s_rd :: M2S_ReadData bw
185+
m2s_rd :: M2S_ReadData
195186
}
196187
deriving (Generic)
197188

@@ -252,6 +243,164 @@ instance (C.KnownDomain dom, NFDataX (S2M_Axi4Lite aw bw)) => Simulate (Axi4Lite
252243
sigToSimFwd _ = C.sample_lazy
253244
sigToSimBwd _ = C.sample_lazy
254245

255-
stallC SimulationConfig{..} (waStalls:>wdStalls:>wrStalls:>raStalls:>rdStalls:>Nil) = Circuit go
246+
stallC conf stallAckVector = Circuit go
256247
where
257-
go (fwd, bwd) = (bwd, fwd)
248+
(waStalls:>wdStalls:>wrStalls:>raStalls:>rdStalls:>Nil) = stallAckVector
249+
SimulationConfig{..} = conf
250+
go :: (Signal dom (M2S_Axi4Lite aw bw),
251+
Signal dom (S2M_Axi4Lite aw bw)) ->
252+
(Signal dom (S2M_Axi4Lite aw bw),
253+
Signal dom (M2S_Axi4Lite aw bw))
254+
go (fwd, bwd) = (bwd', fwd')
255+
where
256+
bwd' = S2M_Axi4Lite <$> waBwdOut <*> wdBwdOut <*> wrBwdOut <*> raBwdOut <*> rdBwdOut
257+
fwd' = M2S_Axi4Lite <$> waFwdOut <*> wdFwdOut <*> wrFwdOut <*> raFwdOut <*> rdFwdOut
258+
259+
(waFwd, wdFwd, wrFwd, raFwd, rdFwd) = dissectM2S fwd
260+
(waBwd, wdBwd, wrBwd, raBwd, rdBwd) = dissectS2M bwd
261+
262+
(waStallAck, waStallNs) = waStalls
263+
(waBwdOut, waFwdOut) = stallM2S (stallAcks waStallAck) waStallNs resetCycles waFwd waBwd
264+
265+
(wdStallAck, wdStallNs) = wdStalls
266+
(wdBwdOut, wdFwdOut) = stallM2S (stallAcks wdStallAck) wdStallNs resetCycles wdFwd wdBwd
267+
268+
(wrStallAck, wrStallNs) = wrStalls
269+
(wrBwdOut, wrFwdOut) = stallS2M (stallAcks wrStallAck) wrStallNs resetCycles wrFwd wrBwd
270+
271+
(raStallAck, raStallNs) = raStalls
272+
(raBwdOut, raFwdOut) = stallM2S (stallAcks raStallAck) raStallNs resetCycles raFwd raBwd
273+
274+
(rdStallAck, rdStallNs) = rdStalls
275+
(rdBwdOut, rdFwdOut) = stallS2M (stallAcks rdStallAck) rdStallNs resetCycles rdFwd rdBwd
276+
277+
dissectM2S (m :- m2s) =
278+
( m2s_wa m :- waSig
279+
, m2s_wd m :- wdSig
280+
, m2s_wr m :- wrSig
281+
, m2s_ra m :- raSig
282+
, m2s_rd m :- rdSig )
283+
where
284+
(waSig, wdSig, wrSig, raSig, rdSig) = dissectM2S m2s
285+
286+
dissectS2M (s :- s2m) =
287+
( s2m_wa s :- waSig
288+
, s2m_wd s :- wdSig
289+
, s2m_wr s :- wrSig
290+
, s2m_ra s :- raSig
291+
, s2m_rd s :- rdSig )
292+
where
293+
(waSig, wdSig, wrSig, raSig, rdSig) = dissectS2M s2m
294+
295+
296+
stallAcks stallAck = cycle saList
297+
where
298+
saList | stallAck == StallCycle = [minBound..maxBound] \\ [StallCycle]
299+
| otherwise = [stallAck]
300+
301+
302+
stallM2S :: (Source src, Destination dst) =>
303+
[StallAck] -> [Int] -> Int ->
304+
Signal dom src -> Signal dom dst ->
305+
(Signal dom dst, Signal dom src)
306+
stallM2S [] _ _ _ _ = error "finite stallAck list"
307+
stallM2S sas stalls resetN (f :- fwd) (b :- bwd) | resetN > 0 =
308+
B.bimap (b :-) (f :-) (stallM2S sas stalls (resetN - 1) fwd bwd)
309+
stallM2S (sa:sas) [] _ (f :- fwd) ~(b :- bwd) =
310+
B.bimap (toStallAck (maybePayload f) (isReady b) sa :-) (f :-) (stallM2S sas [] 0 fwd bwd)
311+
stallM2S (sa:sas) stalls _ ((maybePayload -> Nothing) :- fwd) ~(b :- bwd) =
312+
B.bimap (b' :-) (noData :-) (stallM2S sas stalls 0 fwd bwd)
313+
where b' = toStallAck (Nothing :: Maybe (M2S_WriteAddress aw)) (isReady b) sa
314+
stallM2S (_:sas) (stall:stalls) _ (f0 :- fwd) ~(b0 :- bwd) =
315+
let
316+
(f1, b1, stalls') = case compare 0 stall of
317+
LT -> (noData, ready False, (stall - 1):stalls)
318+
EQ -> (f0, b0, if isReady b0 then stalls else stall:stalls)
319+
GT -> error ("Unexpected negative stall: " <> show stall)
320+
in
321+
B.bimap (b1 :-) (f1 :-) (stallM2S sas stalls' 0 fwd bwd)
322+
323+
stallS2M :: (Destination dst, Source src) =>
324+
[StallAck] -> [Int] -> Int ->
325+
Signal dom dst -> Signal dom src ->
326+
(Signal dom src, Signal dom dst)
327+
stallS2M sas stalls resetN fwd bwd = (src, dst)
328+
where (dst, src) = stallM2S sas stalls resetN bwd fwd
329+
330+
toStallAck :: (Source src, Destination dst) => Maybe src -> Bool -> StallAck -> dst
331+
toStallAck (Just _) ack = const (ready ack)
332+
toStallAck Nothing ack = \case
333+
StallWithNack -> ready False
334+
StallWithAck -> ready True
335+
StallWithErrorX -> C.errorX "No defined ack"
336+
StallTransparently -> ready ack
337+
StallCycle -> ready False -- shouldn't happen..
338+
339+
-- | Every data-carrying direction in a channel in AXI4 has a @<Channel>@ and @No<Channel>@
340+
-- constructor. In some functions (like "stallC") it is useful to write functions that
341+
-- use this fact such that these can be applied to every channel of AXI4. This typeclass
342+
-- provides functions to convert a value in a channel to @Maybe@, where the @No<Channel>@ is
343+
-- converted to @Nothing@, and any other value to @Just value@.
344+
--
345+
-- This class is called @Source@ because a source of useful data is the sender of the type
346+
-- for which this class is relevant.
347+
class Source src where
348+
-- | Converts a channel type to a @Maybe@
349+
maybePayload :: src -> Maybe src
350+
-- | The value of type "src" that is mapped to @Nothing@ by "maybePayload"
351+
noData :: src
352+
353+
-- | Typeclass to convert Booleans to channel-specific acknowledgement types.
354+
class Destination dst where
355+
ready :: Bool -> dst
356+
isReady :: dst -> Bool
357+
358+
instance Source (M2S_WriteAddress aw) where
359+
maybePayload M2S_NoWriteAddress = Nothing
360+
maybePayload m2s_wa = Just m2s_wa
361+
362+
noData = M2S_NoWriteAddress
363+
364+
instance Destination S2M_WriteAddress where
365+
ready b = S2M_WriteAddress b
366+
isReady (S2M_WriteAddress b) = b
367+
368+
instance Source (M2S_WriteData bw) where
369+
maybePayload M2S_NoWriteData = Nothing
370+
maybePayload m2s_wd = Just m2s_wd
371+
372+
noData = M2S_NoWriteData
373+
374+
instance Destination S2M_WriteData where
375+
ready b = S2M_WriteData b
376+
isReady (S2M_WriteData b) = b
377+
378+
instance Source (S2M_WriteResponse) where
379+
maybePayload S2M_NoWriteResponse = Nothing
380+
maybePayload s2m_wr = Just s2m_wr
381+
382+
noData = S2M_NoWriteResponse
383+
384+
instance Destination (M2S_WriteResponse) where
385+
ready b = M2S_WriteResponse b
386+
isReady (M2S_WriteResponse b) = b
387+
388+
instance Source (M2S_ReadAddress aw) where
389+
maybePayload M2S_NoReadAddress = Nothing
390+
maybePayload m2s_ra = Just m2s_ra
391+
392+
noData = M2S_NoReadAddress
393+
394+
instance Destination S2M_ReadAddress where
395+
ready b = S2M_ReadAddress b
396+
isReady (S2M_ReadAddress b) = b
397+
398+
instance Source (S2M_ReadData bw) where
399+
maybePayload S2M_NoReadData = Nothing
400+
maybePayload s2m_rd = Just s2m_rd
401+
402+
noData = S2M_NoReadData
403+
404+
instance Destination M2S_ReadData where
405+
ready b = M2S_ReadData b
406+
isReady (M2S_ReadData b) = b

src/Protocols/Df.hs

Lines changed: 0 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -75,17 +75,12 @@ import qualified Prelude as P
7575
import Clash.Prelude (type (<=))
7676
import Clash.Signal.Internal (Signal)
7777
import qualified Clash.Prelude as C
78-
import qualified Clash.Explicit.Prelude as CE
7978

8079
-- me
8180
import Protocols.Internal
8281
import Protocols.DfLike (DfLike)
8382
import qualified Protocols.DfLike as DfLike
8483

85-
<<<<<<< HEAD
86-
=======
87-
import Debug.Trace
88-
>>>>>>> cc790e6... Add AXI4 Lite types
8984

9085
-- $setup
9186
-- >>> import Protocols
@@ -165,52 +160,6 @@ instance (C.KnownDomain dom, C.NFDataX a, C.ShowX a, Show a) => Drivable (Df dom
165160
sampleC = sample
166161

167162

168-
simulateRight SimulationConfig{..} acks circ =
169-
P.take timeoutAfter $
170-
CE.sample_lazy $
171-
P.snd $
172-
toSignals circ ((), resetAndAcks)
173-
where
174-
resetAndAcks = C.fromList $ (P.map Ack (replicate resetCycles False) <> acks)
175-
176-
simulateLeft SimulationConfig{..} fwds circ = CE.sample_lazy ackSig
177-
where
178-
(ackSig, ()) = toSignals circ (dataSig, ())
179-
dataSig = C.fromList_lazy (ackedData resetCycles fwds (C.sample ackSig))
180-
181-
ackedData resetN _ (_:acks) | resetN > 0 =
182-
NoData : ackedData (resetN - 1) fwds acks
183-
ackedData _ _ [] = C.errorX "Empty acks list."
184-
ackedData _ [] (_:acks) = NoData : ackedData 0 [] acks
185-
ackedData _ (dat:datas) (ack:acks) = case ack of
186-
Ack True -> dat : ackedData 0 (datas) acks
187-
Ack False -> dat : ackedData 0 (dat:datas) acks
188-
189-
190-
191-
simulateManager SimulationConfig{..} acks circ =
192-
P.take timeoutAfter $
193-
CE.sample_lazy $
194-
P.snd $
195-
toSignals circ ((), resetAndAcks)
196-
where
197-
resetAndAcks = C.fromList $ (P.map Ack (replicate resetCycles False) <> acks)
198-
199-
-- TODO: apply simulation config
200-
simulateSubordinate SimulationConfig{..} fwds circ = CE.sample_lazy ackSig
201-
where
202-
(ackSig, ()) = toSignals circ (dataSig, ())
203-
dataSig = C.fromList_lazy (ackedData resetCycles fwds (C.sample ackSig))
204-
205-
ackedData resetN _ (_:acks) | resetN > 0 =
206-
NoData : ackedData (resetN - 1) fwds acks
207-
ackedData _ [] (_:acks) = NoData : ackedData 0 [] acks
208-
ackedData _ (dat:datas) (ack:acks) = case ack of
209-
Ack True -> dat : ackedData 0 (datas) acks
210-
Ack False -> dat : ackedData 0 (dat:datas) acks
211-
212-
213-
214163
instance DfLike dom (Df dom) a where
215164
type Data (Df dom) a = Data a
216165
type Payload a = a

src/Protocols/Internal.hs

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -492,13 +492,6 @@ instance Drivable () where
492492
sampleC _ _ = ()
493493

494494

495-
simulateRight _ _ _ = ()
496-
simulateLeft _ _ _ = ()
497-
498-
simulateManager _ _ _ = ()
499-
simulateSubordinate _ _ _ = ()
500-
501-
502495
instance (Simulate a, Simulate b) => Simulate (a, b) where
503496
type SimulateFwdType (a, b) = (SimulateFwdType a, SimulateFwdType b)
504497
type SimulateBwdType (a, b) = (SimulateBwdType a, SimulateBwdType b)
@@ -689,6 +682,7 @@ simulateCSE c = simulateCS (c clk rst ena)
689682
-- | Applies conversion functions defined in the 'Simulate' instance of @a@ and @b@ to
690683
-- the given simulation types, and applies the results to the internal function of the
691684
-- given 'Circuit'. The resulting internal types are converted to the simulation types.
685+
-- TODO: implement SimulationConfig
692686
simulateCircuit :: forall a b . (Simulate a, Simulate b) =>
693687
SimulateFwdType a -> SimulateBwdType b ->
694688
Circuit a b ->

0 commit comments

Comments
 (0)