From fc1959bd9887ecc4d4ceb62a53e87abc6f49ef00 Mon Sep 17 00:00:00 2001 From: Nathan Ringo Date: Mon, 23 Sep 2024 21:46:34 -0500 Subject: Adds README, moves fpga stuff to a subdirectory. --- fpga/src/Uart.bs | 148 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 148 insertions(+) create mode 100644 fpga/src/Uart.bs (limited to 'fpga/src/Uart.bs') diff --git a/fpga/src/Uart.bs b/fpga/src/Uart.bs new file mode 100644 index 0000000..1059a65 --- /dev/null +++ b/fpga/src/Uart.bs @@ -0,0 +1,148 @@ +package Uart where + +import FIFOF +import GetPut +import Util + +interface Clock = + clk :: Bool + +mkDivider :: Integer -> Module Clock +mkDivider divisor = + module + count :: Reg (Bit 32) <- mkReg 0 + + rules + "increment_divider": when True ==> do + if count == fromInteger (divisor - 1) then do + count := 0 + else + count := count + 1 + + interface Clock + clk = count == 0 + +-- | 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'. + 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 (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 :: Clock -> Integer -> Module TxUart +mkTxUart baudClock bufferSize = + module + fifo :: FIFOF (Bit 8) <- mkSizedFIFOF bufferSize + state :: Reg TxState <- mkReg Idle + pin :: Reg (Bit 1) <- mkReg 1 + + rules + "uart_tx": when baudClock.clk + 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_data": when Data b n <- state ==> do + pin := b[0:0] + if n == 0 then + state := Idle + else + state := Data (b >> 1) (n - 1) + interface TxUart + pin = pin + send = toPut fifo + +-- | 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) + +-- | The RX side of the UART. +interface RxUart = + -- | The RX pin. + pin :: Bit 1 -> Action + -- | Reads a byte from the UART's receive buffer. + recv :: Get (Bit 8) + +mkRxUart :: Clock -> Integer -> Module RxUart +mkRxUart baudClock bufferSize = + module + fifo :: FIFOF (Bit 8) <- mkGSizedFIFOF True False bufferSize + state :: Reg RxState <- mkReg Idle + pin :: Wire (Bit 1) <- mkWire + + rules + "uart_rx": when baudClock.clk + rules + "uart_rx_idle_to_start": when Idle <- state, pin == 0 ==> do + state := Data 0 0 + "uart_rx_data_to_data": when Data bits n <- state, n < 7 ==> do + state := Data (pin ++ bits[7:1]) (n + 1) + "uart_rx_data_to_stop": when Data bits 7 <- state ==> do + state := Stop (pin ++ bits[7:1]) + "uart_rx_stop_to_idle": when Stop bits <- state, pin == 1 ==> do + fifo.enq bits + state := Idle + + interface RxUart + pin bit = pin := bit + recv = toGet fifo + +-- | An 8n1 UART. +interface Uart = + -- | The RX pin. + rxPin :: Bit 1 -> Action + -- | The TX pin. + txPin :: 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 :: Integer -> Module Uart +mkUart baudDivisor = + module + baudClock <- mkDivider baudDivisor + rx <- mkRxUart baudClock 8 + tx <- mkTxUart baudClock 8 + + interface Uart + rxPin = rx.pin + txPin = tx.pin + recv = rx.recv + send = tx.send + +-- vim: set ft=haskell : -- cgit v1.2.3