blob: 954f96e0717415ebe5c69b8b7db39b48447c6c6e (
plain)
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
|
package Uart where
import Clocks
import GetPut
-- | The state of the TX side of the UART.
data TxState
= -- | The UART is not currently sending anything. Transitions to 'Data b 0'
-- after sending the start bit once.
Idle
| -- | The UART is about to send a data bit. 'Data b n' transitions to
-- 'Data b (n + 1)' by sending a data bit. 'Data b 7' transitions to 'Idle'
-- by sending the last data bit. Being in the 'Idle' state for a clock
-- transmits the stop bit.
Data (Bit 8) (Bit 3)
deriving (Bits)
-- | Runs the TX side of the UART, receiving bytes from the 'Get' and writing
-- output bits to the 'Put'.
mkTxUart :: RWire (Bit 8) -> Wire (Bit 1) -> Module ()
mkTxUart fifo tx = module
state :: Reg TxState <- mkReg Idle
rules
"uart_tx_idle": when Idle <- state ==> do
case fifo.wget of
Just b -> do
state := Data b 7
tx._write 0
Nothing ->
tx._write 1
"uart_tx_data": when Data b n <- state ==> do
tx._write b[n:n]
if n == 7 then
state := Idle
else
state := Data b (n + 1)
-- | The state of the RX side of the UART.
data RxState
= -- | The initial state of the UART, and the state after receiving the stop
-- bit. May transition to 'Data 0 0' when the start bit is received.
Idle
| -- | In the 'Data _ n' state, the UART has received the start bit and 'n'
-- data bits, and is about to receive more data bits. 'Data _ n'
-- transitions to 'Data _ (n + 1)' by receiving a data bit. 'Data b 7'
-- transitions to 'Stop' by receving the last data bit.
Data (Bit 8) (Bit 3)
| -- | In the 'Stop' state, the UART has received the start and data bits,
-- and is waiting for the stop bit (which is ignored). Transitions to
-- 'Idle'.
Stop (Bit 8)
deriving (Bits, FShow)
-- | Runs the RX side of the UART, receiving input bits from the 'Get' and
-- writing bytes to the 'Put'.
mkRxUart :: Wire (Bit 8) -> Bit 1 -> Module ()
mkRxUart fifo rxBit = module
rules
{-
mkRxUart :: Wire (Bit 1) -> Integer -> Module (Get (Bit 8))
mkRxUart rx bufferSize = module
fifo :: FIFOF (Bit 8) <- mkGSizedFIFOF True False bufferSize
state :: Reg RxState <- mkReg Idle
rules
"uart_rx_idle_to_start": when Idle <- state, rx == 0 ==> do
state := Data 0 0
"uart_rx_data_to_data": when Data bits n <- state, n < 7 ==> do
state := Data (rx ++ bits[7:1]) (n + 1)
"uart_rx_data_to_stop": when Data bits 7 <- state ==> do
state := Stop (rx ++ bits[7:1])
"uart_rx_stop_to_idle": when Stop bits <- state, rx == 1 ==> do
fifo.enq bits
state := Idle
return (toGet fifo)
-}
-- | An 8n1 UART.
interface Uart =
-- | The TX pin.
tx :: Bit 1
-- | Reads a byte from the UART's receive buffer.
recv :: Get (Bit 8)
-- | Writes a byte to the UART's transmit buffer.
send :: Put (Bit 8)
-- | Returns a UART that does _not_ have FIFOs.
mkUart' :: Bit 1 -> Module Uart
mkUart' rx = module
recvFIFO :: Wire (Bit 8) <- mkWire
sendFIFO :: RWire (Bit 8) <- mkRWireSBR
tx :: Wire (Bit 1) <- mkWire
mkRxUart recvFIFO rx
mkTxUart sendFIFO tx
interface Uart
tx = tx._read
recv = toGet recvFIFO
send = toPut sendFIFO
mkDividedUart :: Integer -> Bit 1 -> Module Uart
mkDividedUart divisor rx = module
clock <- mkClockDivider divisor
reset <- mkAsyncResetFromCR divisor clock.slowClock
rxSync :: SyncBitIfc (Bit 1) <- mkSyncBitFromCC clock.slowClock
txSync :: Reg (Bit 1) <- mkSyncRegToCC 1 clock.slowClock reset
recvFIFO :: SyncFIFOIfc (Bit 8) <- mkSyncFIFOToCC 16 clock.slowClock reset
sendFIFO :: SyncFIFOIfc (Bit 8) <- mkSyncFIFOFromCC 16 clock.slowClock
rules
when True ==> rxSync.send rx
changeSpecialWires (Just clock.slowClock) (Just reset) Nothing $ module
uart <- mkUart' rxSync.read
rules
when True ==> txSync._write uart.tx
when True ==> do
byte <- uart.recv.get
recvFIFO.enq byte
when True ==> do
uart.send.put sendFIFO.first
sendFIFO.deq
return ()
interface Uart
tx = txSync._read
recv = toGet recvFIFO
send = toPut sendFIFO
-- vim: set ft=haskell :
|