diff options
Diffstat (limited to 'fpga/src/Uart.bs')
-rw-r--r-- | fpga/src/Uart.bs | 117 |
1 files changed, 70 insertions, 47 deletions
diff --git a/fpga/src/Uart.bs b/fpga/src/Uart.bs index 82f8e06..954f96e 100644 --- a/fpga/src/Uart.bs +++ b/fpga/src/Uart.bs @@ -1,56 +1,39 @@ package Uart where -import FIFOF +import Clocks import GetPut -- | The state of the TX side of the UART. data TxState - = -- | The UART is not currently sending anything. May transition to - -- 'Start b' when ready to send 'b'. + = -- | 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 the start bit. 'Start b' transitions to - -- 'Data b 7' by sending the start bit. - Start (Bit 8) | -- | The UART is about to send a data bit. 'Data b n' transitions to - -- 'Data (b >> 1) (n - 1)' by sending a data bit. 'Data b 0' transitions to - -- 'Idle' by sending the last data bit. Being in the 'Idle' state for a - -- clock transmits the stop bit. + -- '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) --- | The TX side of the UART. -interface TxUart = - -- | The TX pin. - pin :: Bit 1 - -- | Writes a byte to the UART's transmit buffer. - send :: Put (Bit 8) - -mkTxUart :: Integer -> Module TxUart -mkTxUart bufferSize = module - fifo :: FIFOF (Bit 8) <- mkSizedFIFOF bufferSize +-- | 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 - pin :: Reg (Bit 1) <- mkReg 1 - rules - "uart_tx_idle": when Idle <- state, not fifo.notEmpty ==> do - pin := 1 - "uart_tx_idle_to_start": when Idle <- state, fifo.notEmpty ==> do - pin := 1 - b <- (toGet fifo).get - state := Start b - "uart_tx_start": when Start b <- state ==> do - pin := 0 - state := Data b 7 + "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 - pin := b[0:0] - if n == 0 then + tx._write b[n:n] + if n == 7 then state := Idle else - state := Data (b >> 1) (n - 1) - - interface TxUart - pin = pin - send = toPut fifo + state := Data b (n + 1) -- | The state of the RX side of the UART. data RxState @@ -68,11 +51,17 @@ data RxState 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 @@ -83,26 +72,60 @@ mkRxUart rx bufferSize = module "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) -mkUart :: Wire (Bit 1) -> Module Uart -mkUart rx = module - recv <- mkRxUart rx 8 - uart_tx <- mkTxUart 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 = uart_tx.pin - recv = recv - send = uart_tx.send + tx = txSync._read + recv = toGet recvFIFO + send = toPut sendFIFO -- vim: set ft=haskell : |