sourcelibs/Uart/src/Uart.xtl

1⍝# Uart: a serial port (UART: 8 data bits, no parity, 1 stop bit) as X_eTaL step functions: a transmitter, a receiver, and the two looped back 2⍝# Import it with an alias of your choice: "ua:" u_se< "Uart". 3⍝# Put libs/Uart/src on XETAL_PATH ("just path"); the reference is libs/Uart/docs. 4⍝# Names with l: are exported; the others are private to this file. 5⍝# 6⍝# A line idles at 1. A byte is sent as a frame of ten bits, each held 7⍝# for d clocks: a start bit (0), the eight data bits, least significant 8⍝# first, and a stop bit (1). d, the clocks per bit, is the clock rate 9⍝# over the baud rate: 234 for a 27 MHz Tang Nano at 115200 baud, 3 in 10⍝# the tests. It is the first argument of every step, bound once: 11⍝# u:t_x := ua:t_x 3, then s0 'u:t_x ck:r_un commands (Clocked's harness). 12⍝# Each step is pure, one clock's input in, the next state out. 13 14⍝## The transmitter 15 16⍝# Its state, four registers: busy (0 or 1), clocks left in this bit, 17⍝# bits left in the frame, the frame (bit 0 on the line). 18⍝# >> "ua:" u_se< "Uart" 19⍝# >> ua:TxIdle 20⍝# 0 0 0 0 21ˡTxIdle ← 0 0 0 0 22 23⍝# d t_x s c: the transmitter after one clock. A command c of 0 to 255 24⍝# starts sending that byte when it is idle; -1 is no command (a 25⍝# command while busy is ignored). 26⍝# >> "ua:" u_se< "Uart" 27⍝# >> u:t_x := ua:t_x 3 28⍝# >> ua:TxIdle u:t_x 65 29⍝# 1 2 10 642 30ˡt̲x ← { d s c → 31 b ← f̲irst s 32 n ← 2 s̲elect s 33 k ← 3 s̲elect s 34 f ← 4 s̲elect s 35 (b = 0) ∧ c ≥ 0 ? 1 c̲at (d − 1) c̲at 10 c̲at 512 + 2 × c m̲od 256 36 b = 0 ? 0 0 0 0 37 n > 0 ? 1 c̲at (n − 1) c̲at k c̲at f 38 k = 1 ? 0 0 0 0 39 1 c̲at (d − 1) c̲at (k − 1) c̲at f d̲iv 2 40} 41 42⍝# l_ine s: the transmitter's line: 1 when idle, else the frame's bit 0. 43⍝# >> "ua:" u_se< "Uart" 44⍝# >> ua:l_ine 1 2 10 642 45⍝# 0 46ˡl̲ine ← { s → (1 − f̲irst s) + (f̲irst s) × (4 s̲elect s) m̲od 2 } 47 48⍝## The receiver 49 50⍝# Its state, six registers: phase (0 idle, 1 receiving, 2 waiting for 51⍝# the stop bit), clocks to the next sample, bits left, the bits so 52⍝# far, the last byte received, and valid (1 for the one clock after a 53⍝# byte arrives). 54⍝# >> "ua:" u_se< "Uart" 55⍝# >> ua:RxIdle 56⍝# 0 0 0 0 0 0 57ˡRxIdle ← 0 0 0 0 0 0 58 59⍝# d r_x s l: the receiver after one clock of the line l. A fall to 0 60⍝# while idle is a start bit; each data bit is sampled in its middle 61⍝# (d + d/2 clocks after the fall, then every d clocks), least 62⍝# significant first. 63⍝# >> "ua:" u_se< "Uart" 64⍝# >> u:r_x := ua:r_x 3 65⍝# >> ua:RxIdle u:r_x 0 66⍝# 1 3 8 0 0 0 67ˡr̲x ← { d s l → 68 p ← f̲irst s 69 n ← 2 s̲elect s 70 k ← 3 s̲elect s 71 sh ← 4 s̲elect s 72 da ← 5 s̲elect s 73 (p = 0) ∧ l = 0 ? 1 c̲at (d + (d d̲iv 2) − 1) c̲at 8 c̲at 0 c̲at da c̲at 0 74 p = 0 ? 0 0 0 0 c̲at da c̲at 0 75 p = 2 ? (2 × 1 − l) c̲at 0 0 0 c̲at da c̲at 0 76 n > 0 ? 1 c̲at (n − 1) c̲at k c̲at sh c̲at da c̲at 0 77 s2 ← (sh d̲iv 2) + 128 × l 78 k = 1 ? 2 0 0 0 c̲at s2 c̲at 1 79 1 c̲at (d − 1) c̲at (k − 1) c̲at s2 c̲at da c̲at 0 80} 81 82⍝# r_eceived s: the last byte received. 83⍝# >> "ua:" u_se< "Uart" 84⍝# >> ua:r_eceived 0 0 0 0 72 1 85⍝# 72 86ˡr̲eceived ← { s → 5 s̲elect s } 87 88⍝# v_alid? s: whether the last byte arrived on the last clock. 89⍝# >> "ua:" u_se< "Uart" 90⍝# >> ua:v_alid? 0 0 0 0 72 1 91⍝# 1 92ˡv̲alid? ← { s → 1 = 6 s̲elect s } 93 94⍝## Looped back 95 96⍝# The transmitter's line wired to the receiver, and a log of the first 97⍝# four bytes received with their count: fifteen registers, the 98⍝# transmitter's four, the receiver's six, the log's four, the count. 99⍝# >> "ua:" u_se< "Uart" 100⍝# >> ua:LoopIdle 101⍝# 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 102ˡLoopIdle ← 15 r̲eshape 0 103 104⍝# d l_oopback s c: one clock: the receiver samples the line as the 105⍝# transmitter drives it now, then both step, and a byte that arrives 106⍝# goes into the log at the count. 107⍝# >> "ua:" u_se< "Uart" 108⍝# >> "ck:" u_se< "Clocked" 109⍝# >> u:l_oop := ua:l_oopback 3 110⍝# >> ua:l_og ua:LoopIdle 'u:l_oop ck:r_un 3 ua:c_ommands 65 111⍝# 65 112ˡl̲oopback ← { d s c → 113 tx ← 4 t̲ake s 114 rx ← 6 t̲ake 4 d̲rop s 115 lg ← 4 t̲ake 10 d̲rop s 116 ct ← 15 s̲elect s 117 rx2 ← (d ˡr̲x rx)_ ˡl̲ine tx 118 v ← 6 s̲elect rx2 119 lg2 ← lg + v × ((o̲ffsets 4) = ct) × (5 s̲elect rx2) − lg 120 ((d ˡt̲x tx)_ c) c̲at rx2 c̲at lg2 c̲at ct + v 121} 122 123⍝# l_ines t: the transmitter's line for every row of a trace (of the 124⍝# transmitter, or of the looped-back pair: both start with its four 125⍝# registers). 126⍝# >> "ua:" u_se< "Uart" 127⍝# >> ua:l_ines 2 4 r_eshape 0 0 0 0 1 0 10 640 128⍝# 1 0 129ˡl̲ines ← { t → 130 b ← 1 s̲elect₂ t 131 (1 − b) + b × (4 s̲elect₂ t) m̲od 2 132} 133 134⍝# l_og s: the bytes received so far, from a looped-back state. 135⍝# >> "ua:" u_se< "Uart" 136⍝# >> ua:l_og 0 0 0 0 0 0 0 0 0 0 72 105 0 0 2 137⍝# 72 105 138ˡl̲og ← { s → (4 m̲in 15 s̲elect s) t̲ake 4 t̲ake 10 d̲rop s } 139 140⍝# The commands that send bytes (0 to 255), each when the transmitter 141⍝# is free: d c_ommands bytes gives one command per clock, the byte at 142⍝# the start of each frame of 10 d + 1 clocks, -1 elsewhere, with d 143⍝# more clocks at the end for the last stop bit. 144⍝# >> "ua:" u_se< "Uart" 145⍝# >> 2 ua:c_ommands 65 146⍝# 65 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 147ˡc̲ommands ← { d bytes → 148 per ← 1 + 10 × d 149 at ← per × o̲ffsets t̲ally bytes 150 all ← ((per × t̲ally bytes) + d) r̲eshape -1 151 all + ((o̲ffsets t̲ally all) '= t̲able at) '+ '× i̲nner bytes + 1 152}