uart: implement stream (un)packing, tidy interfaces on COBS encoder

This commit is contained in:
Fischer Moseley 2026-02-10 18:13:01 -07:00
parent 62049bac84
commit ba8462968e
4 changed files with 70 additions and 10 deletions

View File

@ -23,17 +23,18 @@ class COBSDecode(Elaboratable):
# State Machine:
with m.FSM():
with m.State("WAIT_FOR_PACKET_START"):
with m.If((self.data_i == 0) & (self.valid_i)):
m.next = "START_OF_PACKET"
# TODO: determine if wait for packet logic should stay
# with m.State("WAIT_FOR_PACKET_START"):
# with m.If((self.data_i == 0) & (self.valid_i)):
# m.next = "START_OF_PACKET"
with m.State("START_OF_PACKET"):
with m.If(self.valid_i):
m.d.sync += counter.eq(self.data_i - 1)
m.next = "DECODING"
with m.Else():
m.next = "START_OF_PACKET"
# with m.Else():
# m.next = "START_OF_PACKET"
with m.State("DECODING"):
with m.If(self.valid_i):

View File

@ -5,13 +5,11 @@ from amaranth.lib.memory import Memory
class COBSEncode(Elaboratable):
def __init__(self):
# Top-Level IO
self.start = Signal()
self.done = Signal()
# Stream-like data input
self.data_i = Signal(8)
self.valid_i = Signal()
self.ready_o = Signal()
self.last_i = Signal()
# Stream-like data output
self.data_o = Signal(8)
@ -44,7 +42,7 @@ class COBSEncode(Elaboratable):
# State Machine:
with m.FSM() as fsm:
with m.State("IDLE"):
with m.If(self.start):
with m.If(self.last_i):
m.d.sync += head_pointer.eq(0)
m.d.sync += tail_pointer.eq(0)
m.d.sync += rd_port.addr.eq(0)
@ -108,4 +106,6 @@ class COBSEncode(Elaboratable):
m.d.comb += wr_port.data.eq(self.data_i)
m.d.sync += wr_port.addr.eq(wr_port.addr + wr_port.en)
m.d.comb += self.ready_o.eq(fsm.ongoing("IDLE"))
return m

View File

@ -5,6 +5,7 @@ class StreamPacker(Elaboratable):
def __init__(self):
self.data_i = Signal(8)
self.valid_i = Signal()
self.ready_o = Signal(init=1)
self.last_i = Signal()
self.data_o = Signal(32)
@ -14,4 +15,26 @@ class StreamPacker(Elaboratable):
def elaborate(self, platform):
m = Module()
count = Signal(range(4))
with m.If(self.ready_o):
with m.If(self.valid_i):
m.d.sync += self.data_o.eq(Cat(self.data_o[8:], self.data_i))
m.d.sync += count.eq(count + 1)
with m.If(count == 3):
m.d.sync += self.ready_o.eq(0)
m.d.sync += self.valid_o.eq(1)
m.d.sync += self.last_o.eq(self.last_i)
with m.Else():
with m.If(self.valid_o & self.ready_i):
m.d.sync += self.ready_o.eq(1)
m.d.sync += self.valid_o.eq(0)
# TODO: not necessary, but makes debugging much easier!
m.d.sync += self.data_o.eq(0)
m.d.sync += self.last_o.eq(0)
return m

View File

@ -5,7 +5,7 @@ class StreamUnpacker(Elaboratable):
def __init__(self):
self.data_i = Signal(32)
self.valid_i = Signal()
self.ready_o = Signal()
self.ready_o = Signal(init=1)
self.last_i = Signal()
self.data_o = Signal(8)
@ -15,4 +15,40 @@ class StreamUnpacker(Elaboratable):
def elaborate(self, platform):
m = Module()
# Turn a stream of 32-bit numbers into a stream of 8-bit numbers
buf = Signal(24)
last = Signal()
count = Signal(range(3))
with m.If(self.ready_o):
with m.If(self.valid_i):
m.d.sync += buf.eq(self.data_i[8:])
m.d.sync += last.eq(self.last_i)
m.d.sync += self.ready_o.eq(0)
m.d.sync += self.data_o.eq(self.data_i[:7])
m.d.sync += self.valid_o.eq(1)
m.d.sync += count.eq(0)
# Have some data in the buffer
with m.Else():
with m.If(self.valid_o & self.ready_i):
# if done, clean up and signal ready for next word
with m.If(count == 3):
m.d.sync += self.valid_o.eq(0)
m.d.sync += self.ready_o.eq(1)
# TODO: not necessary, but makes debugging much easier!
m.d.sync += self.data_o.eq(0)
m.d.sync += self.last_o.eq(0)
# if not done, clock out next byte
with m.Else():
m.d.sync += self.data_o.eq(buf[8:])
m.d.sync += buf.eq(buf >> 8)
m.d.sync += count.eq(count + 1)
m.d.sync += self.last_o.eq((last) & (count == 2))
return m