/
Spram.hs
97 lines (92 loc) · 3.32 KB
/
Spram.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
{-|
Module : Ice40.Spram
Description : Ice40 single-port RAM hard IP primitive
Copyright : (c) David Cox, 2021-2024
License : BSD 3-Clause
Maintainer : standardsemiconductor@gmail.com
SPRAM hard IP primitive from [Lattice Ice Technology Library](https://github.com/standardsemiconductor/VELDT-info/blob/master/SBTICETechnologyLibrary201708.pdf)
-}
module Ice40.Spram ( spramPrim ) where
import Clash.Prelude
import Clash.Annotations.Primitive
import Data.String.Interpolate (i)
import Data.String.Interpolate.Util (unindent)
{-# ANN spramPrim (InlinePrimitive [Verilog] $ unindent [i|
[ { "BlackBox" :
{ "name" : "Ice40.Spram.spramPrim"
, "kind" : "Declaration"
, "type" :
"spramPrim
:: KnownDomain dom -- ARG[0]
=> Clock dom -- ARG[1] clock
-> Signal dom (BitVector 14) -- ARG[2] address
-> Signal dom (BitVector 16) -- ARG[3] dataIn
-> Signal dom (BitVector 4) -- ARG[4] maskWrEn
-> Signal dom Bit -- ARG[5] wrEN
-> Signal dom Bit -- ARG[6] chipSelect
-> Signal dom Bit -- ARG[7] standBy
-> Signal dom Bit -- ARG[8] sleep
-> Signal dom Bit -- ARG[9] powerOff
-> Signal dom (BitVector 16) -- dataOut"
, "template" :
"//SB_SPRAM begin
SB_SPRAM256KA ~GENSYM[sb_spram_inst][0] (
.ADDRESS (~ARG[2]),
.DATAIN (~ARG[3]),
.MASKWREN (~ARG[4]),
.WREN (~ARG[5]),
.CHIPSELECT(~ARG[6]),
.CLOCK (~ARG[1]),
.STANDBY (~ARG[7]),
.SLEEP (~ARG[8]),
.POWEROFF (~ARG[9]),
.DATAOUT (~RESULT)
);
//SB_SPRAM end"
}
}
]
|]) #-}
data Nyb = Nyb3 | Nyb2 | Nyb1 | Nyb0
-- | Single port RAM primitive
{-# NOINLINE spramPrim #-}
spramPrim
:: KnownDomain dom -- ARG[0]
=> Clock dom -- ^ clock
-> Signal dom (BitVector 14) -- ^ address
-> Signal dom (BitVector 16) -- ^ dataIn
-> Signal dom (BitVector 4) -- ^ maskWrEn
-> Signal dom Bit -- ^ wrEN
-> Signal dom Bit -- ^ chipSelect
-> Signal dom Bit -- ^ standBy
-> Signal dom Bit -- ^ sleep
-> Signal dom Bit -- ^ powerOff
-> Signal dom (BitVector 16) -- ^ dataOut
spramPrim clock address dataIn maskWrEn wrEn chipSelect !_ !_ !_
= concat4 <$> nyb3 <*> nyb2 <*> nyb1 <*> nyb0
where
addressU = unpack <$> address
concat4 a b c d = a ++# b ++# c ++# d
ramEn = toEnable $ bitToBool <$> chipSelect
nybRam = withClock clock $ withEnable ramEn (blockRamPow2 (repeat 0) addressU)
nyb3 = nybRam wrM3
nyb2 = nybRam wrM2
nyb1 = nybRam wrM1
nyb0 = nybRam wrM0
wrM3 = writeGuard Nyb3 <$> dataIn <*> addressU <*> wrEn <*> maskWrEn
wrM2 = writeGuard Nyb2 <$> dataIn <*> addressU <*> wrEn <*> maskWrEn
wrM1 = writeGuard Nyb1 <$> dataIn <*> addressU <*> wrEn <*> maskWrEn
wrM0 = writeGuard Nyb0 <$> dataIn <*> addressU <*> wrEn <*> maskWrEn
nybSlice = \case
Nyb3 -> slice d15 d12
Nyb2 -> slice d11 d8
Nyb1 -> slice d7 d4
Nyb0 -> slice d3 d0
nybMask = \case
Nyb3 -> (! (3 :: Index 4))
Nyb2 -> (! (2 :: Index 4))
Nyb1 -> (! (1 :: Index 4))
Nyb0 -> (! (0 :: Index 4))
writeGuard n dIn addr en mask
| bitToBool en && (not.bitToBool) (nybMask n mask) = Just (addr, nybSlice n dIn)
| otherwise = Nothing