aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNathan Ringo <nathan@remexre.com>2024-10-08 14:27:19 -0500
committerNathan Ringo <nathan@remexre.com>2024-10-08 14:27:19 -0500
commit08d727e9886cde6a367906999e96a33f7ba37f33 (patch)
tree919da00f9d4bdc451be53f558c4b42bef7c487fd
parented3e96b5eaae71d035e14569b107040c3538f849 (diff)
Reorganization and rewiring.
-rw-r--r--README.md9
-rw-r--r--fpga/src/Clock.bs19
-rw-r--r--fpga/src/HyperBus.bs31
-rw-r--r--fpga/src/I2C.bs3
-rw-r--r--fpga/src/Numini.bs77
-rw-r--r--fpga/src/Top.bs225
-rw-r--r--fpga/src/Uart.bs65
7 files changed, 298 insertions, 131 deletions
diff --git a/README.md b/README.md
index 82fec48..3fa4e22 100644
--- a/README.md
+++ b/README.md
@@ -7,16 +7,18 @@ A small CPU and a computer built around it.
Currently, the planned hardware is based around an [iCEBreaker] and an [Inkplate 6].
The [original Inkplate 6 case]'s top is used (since the Inkplate came glued to it), but the bottom is replaced by a 3D-printed custom case that leaves room for the remainder of the components and ports on the bottom.
The Inkplate provides power via a lithium battery, and access to its display, its microSD card, and its Wi-Fi and Bluetooth connectivity.
-The iCEBreaker is connected to the Inkplate over both I²C and UART.
+The iCEBreaker is connected to the Inkplate over UART.
The iCEBreaker is augmented with a [quad HyperRAM PMOD] module, which it uses for main memory.
A [CH559] is used to provide support for USB keyboards.
It connects to the iCEBreaker over UART, essentially acting as a PS/2 keyboard would.
+Finally, a variety of devices connect to the iCEBreaker over I²C, including several [MCP23017]
[iCEBreaker]: https://docs.icebreaker-fpga.org/
[Inkplate 6]: https://soldered.com/product/soldered-inkplate-6-6-e-paper-board/
[original Inkplate 6 case]: https://github.com/SolderedElectronics/Inkplate-6-hardware/blob/master/3D%20printable%20case/Original%20case
[quad HyperRAM PMOD]: https://1bitsquared.com/products/pmod-hyperram
[CH559]: https://www.wch-ic.com/products/CH559.html
+[MCP23017]: https://www.microchip.com/en-us/product/mcp23017
The different components are in the following subdirectories:
@@ -28,3 +30,8 @@ The different components are in the following subdirectories:
[Bluespec]: https://github.com/B-Lang-org/bsc
[OpenSCAD]: https://openscad.org/
+
+## Inkplate
+
+The Inkplate 6 provides 800x600 pixels with 3 bits of greyscale color depth.
+It quotes a 1.26s update time; in order to update at faster than the refresh rate, we need to run the UART at 2MHz, which gives a 900ms access time to send the whole framebuffer, or 1.2s if we send 4 bits per pixel.
diff --git a/fpga/src/Clock.bs b/fpga/src/Clock.bs
new file mode 100644
index 0000000..c908502
--- /dev/null
+++ b/fpga/src/Clock.bs
@@ -0,0 +1,19 @@
+-- | A simple clock package.
+package Clock where
+
+interface Clock =
+ clk :: Bool
+
+-- TODO: Make a multiclock that uses one count for all the sub-clocks in the
+-- design.
+
+mkClock :: Bit n -> Module Clock
+mkClock divisor =
+ module
+ count :: Reg (Bit n) <- mkReg 0
+ rules
+ when True ==> count := if count == divisor - 1 then 0 else count + 1
+ interface Clock
+ clk = count == 0
+
+-- vim: set ft=haskell :
diff --git a/fpga/src/HyperBus.bs b/fpga/src/HyperBus.bs
new file mode 100644
index 0000000..41d1703
--- /dev/null
+++ b/fpga/src/HyperBus.bs
@@ -0,0 +1,31 @@
+-- | A controller for a HyperBus interface, allowing for I/O to four chips.
+package HyperBus where
+
+import Clock
+
+-- | The HyperBus output pins.
+interface HyperBusOut =
+ ck :: Bit 1
+ ck_n :: Bit 1
+ cs0_n :: Bit 1
+ cs1_n :: Bit 1
+ cs2_n :: Bit 1
+ cs3_n :: Bit 1
+ reset_n :: Bit 1
+ rwds_out :: Maybe (Bit 1)
+ dq_out :: Maybe (Bit 8)
+
+mkHyperBus :: Wire (Bit 1) -> Wire (Bit 8) -> Clock -> Module HyperBusOut
+mkHyperBus rwds_in dq_in clock = module
+ interface HyperBusOut
+ ck = if clock.clk then 1 else 0
+ ck_n = if clock.clk then 0 else 1
+ cs0_n = 1
+ cs1_n = 1
+ cs2_n = 1
+ cs3_n = 1
+ reset_n = 1
+ rwds_out = Nothing
+ dq_out = Nothing
+
+-- vim: set ft=haskell :
diff --git a/fpga/src/I2C.bs b/fpga/src/I2C.bs
new file mode 100644
index 0000000..f3cd760
--- /dev/null
+++ b/fpga/src/I2C.bs
@@ -0,0 +1,3 @@
+package I2C where
+
+-- vim: set ft=haskell :
diff --git a/fpga/src/Numini.bs b/fpga/src/Numini.bs
new file mode 100644
index 0000000..58c2c38
--- /dev/null
+++ b/fpga/src/Numini.bs
@@ -0,0 +1,77 @@
+-- | The main board, set up to be wired to either the Inkplate's top-level or
+-- the simulator's. This insulates us from Bluesim's lack of Inout support.
+package Numini where
+
+import Clock
+import HyperBus
+import Uart
+
+-- | The output pins.
+interface NuminiOut =
+ ch559_uart_tx :: Bit 1
+ inkplate_uart_tx :: Bit 1
+ usb_uart_tx :: Bit 1
+
+ led_r_n :: Bit 1
+ led_g_n :: Bit 1
+
+ rgb_r_n :: Bit 1
+ rgb_g_n :: Bit 1
+ rgb_b_n :: Bit 1
+
+ hyperbus_ck :: Bit 1
+ hyperbus_ck_n :: Bit 1
+ hyperbus_cs0_n :: Bit 1
+ hyperbus_cs1_n :: Bit 1
+ hyperbus_cs2_n :: Bit 1
+ hyperbus_cs3_n :: Bit 1
+ hyperbus_reset_n :: Bit 1
+ hyperbus_rwds_out :: Maybe (Bit 1)
+ hyperbus_dq_out :: Maybe (Bit 8)
+
+ i2c_scl :: Bit 1
+ i2c_sda_out :: Maybe (Bit 1)
+
+clockFreqHz :: Bit 24
+clockFreqHz = 12_000_000
+
+mkNumini :: Wire (Bit 1) -> Wire (Bit 1) -> Wire (Bit 1) -> Wire (Bit 1) ->
+ Wire (Bit 8) -> Wire (Bit 1) -> Module NuminiOut
+mkNumini ch559_uart_rx inkplate_uart_rx usb_uart_rx hyperbus_rwds_in
+ hyperbus_dq_in i2c_sda_in = module
+ clk9600 <- mkClock (clockFreqHz / 9600)
+ clk2M <- mkClock (clockFreqHz / 2_000_000)
+ clk3M <- mkClock (clockFreqHz / 3_000_000)
+
+ ch559_uart <- mkUart ch559_uart_rx clk9600
+ inkplate_uart <- mkUart inkplate_uart_rx clk2M
+ usb_uart <- mkUart usb_uart_rx clk9600
+
+ hyperbus <- mkHyperBus hyperbus_rwds_in hyperbus_dq_in clk3M
+
+ interface NuminiOut
+ ch559_uart_tx = ch559_uart.tx
+ inkplate_uart_tx = inkplate_uart.tx
+ usb_uart_tx = usb_uart.tx
+
+ led_r_n = 1
+ led_g_n = 1
+
+ rgb_r_n = 1
+ rgb_g_n = 1
+ rgb_b_n = 1
+
+ hyperbus_ck = hyperbus.ck
+ hyperbus_ck_n = hyperbus.ck_n
+ hyperbus_cs0_n = hyperbus.cs0_n
+ hyperbus_cs1_n = hyperbus.cs1_n
+ hyperbus_cs2_n = hyperbus.cs2_n
+ hyperbus_cs3_n = hyperbus.cs3_n
+ hyperbus_reset_n = hyperbus.reset_n
+ hyperbus_rwds_out = hyperbus.rwds_out
+ hyperbus_dq_out = hyperbus.dq_out
+
+ i2c_scl = 1
+ i2c_sda_out = Nothing
+
+-- vim: set ft=haskell :
diff --git a/fpga/src/Top.bs b/fpga/src/Top.bs
index 29558d4..df79387 100644
--- a/fpga/src/Top.bs
+++ b/fpga/src/Top.bs
@@ -4,108 +4,165 @@ package Top where
import Connectable
import CPU
import GetPut
+import Numini
import TriState
import Uart
-- | The interface to the iCEBreaker.
interface Top =
-- RS232
- rx :: Bit 1 -> Action {-# always_enabled, always_ready, prefix = "", arg_names = [RX] #-}
- tx :: Bit 1 {-# always_ready, result = TX #-}
+ usb_uart_rx :: Bit 1 -> Action {-# always_enabled, always_ready, prefix = "", arg_names = [RX] #-}
+ usb_uart_tx :: Bit 1 {-# always_ready, result = TX #-}
-- Onboard LEDs
- ledR_N :: Bit 1 {-# always_ready, result = LEDR_N #-}
- ledG_N :: Bit 1 {-# always_ready, result = LEDG_N #-}
+ led_r_n :: Bit 1 {-# always_ready, result = LEDR_N #-}
+ led_g_n :: Bit 1 {-# always_ready, result = LEDG_N #-}
-- RGB LED driver
- ledRed_N :: Bit 1 {-# always_ready, result = LED_RED_N #-}
- ledGrn_N :: Bit 1 {-# always_ready, result = LED_GRN_N #-}
- ledBlu_N :: Bit 1 {-# always_ready, result = LED_BLU_N #-}
+ rgb_r_n :: Bit 1 {-# always_ready, result = LED_RED_N #-}
+ rgb_g_n :: Bit 1 {-# always_ready, result = LED_GRN_N #-}
+ rgb_b_n :: Bit 1 {-# always_ready, result = LED_BLU_N #-}
-- HyperBus 1 (PMOD 1A)
- hyperBus_CS2_N :: Bit 1 {-# always_ready, result = P1A1 #-}
- hyperBus_CS0_N :: Bit 1 {-# always_ready, result = P1A2 #-}
- hyperBus_CK :: Bit 1 {-# always_ready, result = P1A3 #-}
- hyperBus_CK_N :: Bit 1 {-# always_ready, result = P1A4 #-}
- hyperBus_CS3_N :: Bit 1 {-# always_ready, result = P1A7 #-}
- hyperBus_CS1_N :: Bit 1 {-# always_ready, result = P1A8 #-}
- hyperBus_RESET_N :: Bit 1 {-# always_ready, result = P1A9 #-}
- hyperBus_RWDS :: Bit 1 -> Action {-# always_enabled, always_ready, prefix = "", arg_names = [P1A10] #-}
+ hyperbus_cs2_n :: Bit 1 {-# always_ready, result = P1A1 #-}
+ hyperbus_cs0_n :: Bit 1 {-# always_ready, result = P1A2 #-}
+ hyperbus_ck :: Bit 1 {-# always_ready, result = P1A3 #-}
+ hyperbus_ck_n :: Bit 1 {-# always_ready, result = P1A4 #-}
+ hyperbus_cs3_n :: Bit 1 {-# always_ready, result = P1A7 #-}
+ hyperbus_cs1_n :: Bit 1 {-# always_ready, result = P1A8 #-}
+ hyperbus_reset_n :: Bit 1 {-# always_ready, result = P1A9 #-}
+ hyperbus_rwds :: Inout (Bit 1) {-# prefix = "P1A10" #-}
-- HyperBus 2 (PMOD 1B)
- hyperBus_DQ0 :: Inout (Bit 1) {-# prefix = "P1B1" #-}
- hyperBus_DQ1 :: Inout (Bit 1) {-# prefix = "P1B2" #-}
- hyperBus_DQ2 :: Inout (Bit 1) {-# prefix = "P1B3" #-}
- hyperBus_DQ3 :: Inout (Bit 1) {-# prefix = "P1B4" #-}
- hyperBus_DQ7 :: Inout (Bit 1) {-# prefix = "P1B7" #-}
- hyperBus_DQ6 :: Inout (Bit 1) {-# prefix = "P1B8" #-}
- hyperBus_DQ5 :: Inout (Bit 1) {-# prefix = "P1B9" #-}
- hyperBus_DQ4 :: Inout (Bit 1) {-# prefix = "P1B10" #-}
- -- LEDs and buttons (PMOD 2)
- led1 :: Bit 1 {-# always_ready, result = P2_7 #-}
- led2 :: Bit 1 {-# always_ready, result = P2_1 #-}
- led3 :: Bit 1 {-# always_ready, result = P2_2 #-}
- led4 :: Bit 1 {-# always_ready, result = P2_8 #-}
- led5 :: Bit 1 {-# always_ready, result = P2_3 #-}
- btn1 :: Bit 1 -> Action {-# always_enabled, always_ready, prefix = "", arg_names = [P2_9] #-}
- btn2 :: Bit 1 -> Action {-# always_enabled, always_ready, prefix = "", arg_names = [P2_4] #-}
- btn3 :: Bit 1 -> Action {-# always_enabled, always_ready, prefix = "", arg_names = [P2_10] #-}
+ hyperbus_dq0 :: Inout (Bit 1) {-# prefix = "P1B1" #-}
+ hyperbus_dq1 :: Inout (Bit 1) {-# prefix = "P1B2" #-}
+ hyperbus_dq2 :: Inout (Bit 1) {-# prefix = "P1B3" #-}
+ hyperbus_dq3 :: Inout (Bit 1) {-# prefix = "P1B4" #-}
+ hyperbus_dq7 :: Inout (Bit 1) {-# prefix = "P1B7" #-}
+ hyperbus_dq6 :: Inout (Bit 1) {-# prefix = "P1B8" #-}
+ hyperbus_dq5 :: Inout (Bit 1) {-# prefix = "P1B9" #-}
+ hyperbus_dq4 :: Inout (Bit 1) {-# prefix = "P1B10" #-}
+ -- Serial buses (PMOD 2)
+ ch559_uart_rx :: Bit 1 -> Action {-# always_enabled, always_ready, prefix = "", arg_names = [P2_1] #-}
+ ch559_uart_tx :: Bit 1 {-# always_ready, result = P2_2 #-}
+ inkplate_uart_rx :: Bit 1 -> Action {-# always_enabled, always_ready, prefix = "", arg_names = [P2_3] #-}
+ inkplate_uart_tx :: Bit 1 {-# always_ready, result = P2_4 #-}
+ i2c_scl :: Bit 1 {-# always_ready, result = P2_7 #-}
+ i2c_sda :: Inout (Bit 1) {-# prefix = "P2_8" #-}
+ todo_btn :: Bit 1 -> Action {-# always_enabled, always_ready, prefix = "", arg_names = [P2_9] #-}
+ todo_led :: Bit 1 {-# always_ready, result = P2_10 #-}
clockFreqHz :: Integer
clockFreqHz = 12_000_000
mkTop :: Module Top
-mkTop =
- module
- cpu <- mkCPU
+mkTop = module
+ ch559_uart_rx <- mkWire
+ inkplate_uart_rx <- mkWire
+ usb_uart_rx <- mkWire
- uart <- mkUart (clockFreqHz / 9600)
- mkConnection cpu.uart_tx uart.send
- mkConnection cpu.uart_rx uart.recv
+ -- Make tristates for the HyperBus inouts.
+ hyperbus_rwds_enable :: Reg Bool <- mkReg False
+ hyperbus_rwds_out :: Reg (Bit 1) <- mkReg 0
+ hyperbus_dq_enable :: Reg Bool <- mkReg False
+ hyperbus_dq_out :: Reg (Bit 8) <- mkReg 0
+ hyperbus_rwds <- mkTriState hyperbus_rwds_enable hyperbus_rwds_out
+ hyperbus_dq0 <- mkTriState hyperbus_dq_enable hyperbus_dq_out[0:0]
+ hyperbus_dq1 <- mkTriState hyperbus_dq_enable hyperbus_dq_out[1:1]
+ hyperbus_dq2 <- mkTriState hyperbus_dq_enable hyperbus_dq_out[2:2]
+ hyperbus_dq3 <- mkTriState hyperbus_dq_enable hyperbus_dq_out[3:3]
+ hyperbus_dq4 <- mkTriState hyperbus_dq_enable hyperbus_dq_out[4:4]
+ hyperbus_dq5 <- mkTriState hyperbus_dq_enable hyperbus_dq_out[5:5]
+ hyperbus_dq6 <- mkTriState hyperbus_dq_enable hyperbus_dq_out[6:6]
+ hyperbus_dq7 <- mkTriState hyperbus_dq_enable hyperbus_dq_out[7:7]
- hyperBus_data0 <- mkTriState True 1
- hyperBus_data1 <- mkTriState True 1
- hyperBus_data2 <- mkTriState True 1
- hyperBus_data3 <- mkTriState True 1
- hyperBus_data4 <- mkTriState True 1
- hyperBus_data5 <- mkTriState True 1
- hyperBus_data6 <- mkTriState True 1
- hyperBus_data7 <- mkTriState True 1
+ -- Make a tristate for the I2C inout.
+ i2c_sda_enable <- mkReg False
+ i2c_sda_out <- mkReg 0
+ i2c_sda <- mkTriState i2c_sda_enable i2c_sda_out
- interface Top
- -- RS232
- rx = uart.rxPin
- tx = uart.txPin
- -- Onboard LEDs
- ledR_N = uart.txPin
- ledG_N = 1
- -- RGB LED driver
- ledRed_N = 1
- ledGrn_N = 1
- ledBlu_N = 1
- -- HyperBus 1 (PMOD 1A)
- hyperBus_CS2_N = 1
- hyperBus_CS0_N = 1
- hyperBus_CK = 0
- hyperBus_CK_N = 1
- hyperBus_CS3_N = 1
- hyperBus_CS1_N = 1
- hyperBus_RESET_N = 1
- hyperBus_RWDS _ = noAction
- -- HyperBus 2 (PMOD 1B)
- hyperBus_DQ0 = hyperBus_data0.io
- hyperBus_DQ1 = hyperBus_data1.io
- hyperBus_DQ2 = hyperBus_data2.io
- hyperBus_DQ3 = hyperBus_data3.io
- hyperBus_DQ4 = hyperBus_data4.io
- hyperBus_DQ5 = hyperBus_data5.io
- hyperBus_DQ6 = hyperBus_data6.io
- hyperBus_DQ7 = hyperBus_data7.io
- -- LEDs and buttons (PMOD 2)
- led1 = 0
- led2 = 0
- led3 = 0
- led4 = 0
- led5 = 0
- btn1 _ = noAction
- btn2 _ = noAction
- btn3 _ = noAction
+ -- Make wires for all the inout inputs.
+ hyperbus_rwds_in :: Wire (Bit 1) <- mkWire
+ hyperbus_dq_in :: Wire (Bit 8) <- mkWire
+ i2c_sda_in :: Wire (Bit 1) <- mkWire
+
+ numini <- mkNumini ch559_uart_rx inkplate_uart_rx usb_uart_rx
+ hyperbus_rwds_in hyperbus_dq_in i2c_sda_in
+
+ -- Wire up the tristates.
+ rules
+ "update_hyperbus_rwds_out": when True ==> do
+ case numini.hyperbus_rwds_out of
+ Just bits -> do
+ hyperbus_rwds_enable := True
+ hyperbus_rwds_out := bits
+ Nothing -> do
+ hyperbus_rwds_enable := False
+ hyperbus_rwds_out := 0
+ "update_hyperbus_rwds_in": when True ==> do
+ hyperbus_rwds_in := hyperbus_rwds._read
+ "update_hyperbus_dq_out": when True ==> do
+ case numini.hyperbus_dq_out of
+ Just bits -> do
+ hyperbus_dq_enable := True
+ hyperbus_dq_out := bits
+ Nothing -> do
+ hyperbus_dq_enable := False
+ hyperbus_dq_out := 0
+ "update_hyperbus_dq_in": when True ==> do
+ hyperbus_dq_in := hyperbus_dq7._read
+ ++ hyperbus_dq6._read
+ ++ hyperbus_dq5._read
+ ++ hyperbus_dq4._read
+ ++ hyperbus_dq3._read
+ ++ hyperbus_dq2._read
+ ++ hyperbus_dq1._read
+ ++ hyperbus_dq0._read
+ "update_i2c_sda_out": when True ==> do
+ case numini.i2c_sda_out of
+ Just bits -> do
+ i2c_sda_enable := True
+ i2c_sda_out := bits
+ Nothing -> do
+ i2c_sda_enable := False
+ i2c_sda_out := 0
+ "update_i2c_sda_in": when True ==> do
+ i2c_sda_in := i2c_sda._read
+
+ interface Top
+ -- RS232
+ usb_uart_rx bit = usb_uart_rx := bit
+ usb_uart_tx = numini.usb_uart_tx
+ -- Onboard LEDs
+ led_r_n = numini.led_r_n
+ led_g_n = numini.led_g_n
+ -- RGB LED driver
+ rgb_r_n = numini.rgb_r_n
+ rgb_g_n = numini.rgb_g_n
+ rgb_b_n = numini.rgb_b_n
+ -- HyperBus 1 (PMOD 1A)
+ hyperbus_cs2_n = numini.hyperbus_cs2_n
+ hyperbus_cs0_n = numini.hyperbus_cs0_n
+ hyperbus_ck = numini.hyperbus_ck
+ hyperbus_ck_n = numini.hyperbus_ck_n
+ hyperbus_cs3_n = numini.hyperbus_cs3_n
+ hyperbus_cs1_n = numini.hyperbus_cs1_n
+ hyperbus_reset_n = numini.hyperbus_reset_n
+ hyperbus_rwds = hyperbus_rwds.io
+ -- HyperBus 2 (PMOD 1B)
+ hyperbus_dq0 = hyperbus_dq0.io
+ hyperbus_dq1 = hyperbus_dq1.io
+ hyperbus_dq2 = hyperbus_dq2.io
+ hyperbus_dq3 = hyperbus_dq3.io
+ hyperbus_dq4 = hyperbus_dq4.io
+ hyperbus_dq5 = hyperbus_dq5.io
+ hyperbus_dq6 = hyperbus_dq6.io
+ hyperbus_dq7 = hyperbus_dq7.io
+ -- LEDs and buttons (PMOD 2)
+ ch559_uart_rx bit = ch559_uart_rx := bit
+ ch559_uart_tx = numini.ch559_uart_tx
+ inkplate_uart_rx bit = inkplate_uart_rx := bit
+ inkplate_uart_tx = numini.inkplate_uart_tx
+ i2c_scl = numini.i2c_scl
+ i2c_sda = i2c_sda.io
+ todo_btn _ = noAction
+ todo_led = 0
{-# verilog mkTop #-}
{-# properties mkTop = { RSTN = BTN_N } #-}
diff --git a/fpga/src/Uart.bs b/fpga/src/Uart.bs
index b54cfb8..7298083 100644
--- a/fpga/src/Uart.bs
+++ b/fpga/src/Uart.bs
@@ -1,26 +1,9 @@
package Uart where
+import Clock
import FIFOF
import GetPut
-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
@@ -44,14 +27,14 @@ interface TxUart =
send :: Put (Bit 8)
mkTxUart :: Clock -> Integer -> Module TxUart
-mkTxUart baudClock bufferSize =
+mkTxUart clock 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
+ "uart_tx": when clock.clk
rules
"uart_tx_idle": when Idle <- state, not fifo.notEmpty ==> do
pin := 1
@@ -90,58 +73,48 @@ data RxState
-- | 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 =
+mkRxUart :: Wire (Bit 1) -> Clock -> Integer -> Module RxUart
+mkRxUart rx clock 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
+ "uart_rx": when clock.clk
rules
- "uart_rx_idle_to_start": when Idle <- state, pin == 0 ==> do
+ "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 (pin ++ bits[7:1]) (n + 1)
+ state := Data (rx ++ 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
+ state := Stop (rx ++ bits[7:1])
+ "uart_rx_stop_to_idle": when Stop bits <- state, rx == 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
+ 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 :: 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
+mkUart :: Wire (Bit 1) -> Clock -> Module Uart
+mkUart rx clock = module
+ uart_rx <- mkRxUart rx clock 8
+ uart_tx <- mkTxUart clock 8
+ interface Uart
+ tx = uart_tx.pin
+ recv = uart_rx.recv
+ send = uart_tx.send
-- vim: set ft=haskell :