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 :