-
Notifications
You must be signed in to change notification settings - Fork 3
/
Uart.hs
161 lines (143 loc) · 3.52 KB
/
Uart.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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
module Veldt.Uart
( Rx(Rx)
, unRx
, Tx(Tx)
, unTx
, Byte
, Uart
, mkUart
, read
, write
) where
import Clash.Prelude hiding (read)
import Control.Monad
import Control.Monad.RWS
import Control.Lens hiding ((:>))
import qualified Veldt.Counter as C
import qualified Veldt.Serial as S
type Byte = BitVector 8
newtype Rx = Rx { unRx :: Bit }
newtype Tx = Tx { unTx :: Bit }
instance Semigroup Tx where
Tx tx <> Tx tx' = Tx $ tx .&. tx'
instance Monoid Tx where
mempty = Tx 1
-----------------
-- Transmitter --
-----------------
data TxFsm = TxStart | TxSend
deriving (NFDataX, Generic)
data Transmitter = Transmitter
{ _txSer :: S.Serializer 10 Bit
, _txBaud :: Unsigned 16
, _txCtr :: Unsigned 16
, _txFsm :: TxFsm
}
deriving (NFDataX, Generic)
makeLenses ''Transmitter
mkTransmitter :: Unsigned 16 -> Transmitter
mkTransmitter b = Transmitter
{ _txSer = S.mkSerializer 0 S.R
, _txBaud = b
, _txCtr = 0
, _txFsm = TxStart
}
transmit :: Byte -> RWS r Tx Transmitter Bool
transmit byte = use txFsm >>= \case
TxStart -> do
zoom txSer $ S.give $ bv2v $ frame byte
txCtr .= 0
txFsm .= TxSend
return False
TxSend -> do
zoom txSer S.peek >>= tell . Tx
baud <- use txBaud
ctrDone <- uses txCtr (== baud)
txCtr %= C.incrementUnless (== baud)
if ctrDone
then do
zoom txSer S.serialize
serEmpty <- zoom txSer S.empty
when serEmpty $ txFsm .= TxStart
return serEmpty
else return False
frame :: Byte -> BitVector 10
frame b = (1 :: BitVector 1) ++# b ++# (0 :: BitVector 1)
--------------
-- Receiver --
--------------
data RxFsm = RxIdle | RxStart | RxRecv | RxStop
deriving (NFDataX, Generic)
data Receiver = Receiver
{ _rxDes :: S.Deserializer 8 Bit
, _rxBaud :: Unsigned 16
, _rxCtr :: Unsigned 16
, _rxFsm :: RxFsm
}
deriving (NFDataX, Generic)
makeLenses ''Receiver
mkReceiver :: Unsigned 16 -> Receiver
mkReceiver b = Receiver
{ _rxDes = S.mkDeserializer 0 S.L
, _rxBaud = b
, _rxCtr = 0
, _rxFsm = RxIdle
}
receive :: Monoid w => RWS Rx w Receiver (Maybe Byte)
receive = use rxFsm >>= \case
RxIdle -> do
rxLow <- asks $ (== low) . unRx
when rxLow $ do
rxCtr %= C.increment
rxFsm .= RxStart
return Nothing
RxStart -> do
rxLow <- asks $ (== low) . unRx
baudHalf <- uses rxBaud (`shiftR` 1)
ctrDone <- uses rxCtr (== baudHalf)
rxCtr %= C.incrementUnless (== baudHalf)
when ctrDone $ if rxLow
then rxFsm .= RxRecv
else rxFsm .= RxIdle
return Nothing
RxRecv -> do
ctrDone <- countBaud
when ctrDone $ do
i <- asks unRx
zoom rxDes $ S.deserialize i
full <- zoom rxDes S.full
when full $ rxFsm .= RxStop
return Nothing
RxStop -> do
ctrDone <- countBaud
if ctrDone
then do
byte <- v2bv <$> zoom rxDes S.get
zoom rxDes S.clear
rxFsm .= RxIdle
return $ Just byte
else return Nothing
where
countBaud = do
baud <- use rxBaud
ctrDone <- uses rxCtr (== baud)
rxCtr %= C.incrementUnless (== baud)
return ctrDone
----------
-- Uart --
----------
data Uart = Uart
{ _receiver :: Receiver
, _transmitter :: Transmitter
}
deriving (NFDataX, Generic)
makeLenses ''Uart
mkUart :: Unsigned 16 -> Uart
mkUart baud = Uart
{ _receiver = mkReceiver baud
, _transmitter = mkTransmitter baud
}
read :: Monoid w => RWS Rx w Uart (Maybe Byte)
read = zoom receiver receive
write :: Byte -> RWS r Tx Uart Bool
write = zoom transmitter . transmit