add swapbank + test
Some checks failed
Verilator Unit Tests / Test (push) Failing after 3m51s

This commit is contained in:
saji 2024-09-09 17:46:50 -05:00
parent 7a4de2e02d
commit 386403bd12
2 changed files with 147 additions and 29 deletions

View file

@ -1,8 +1,10 @@
from amaranth import Array, Module, Cat, Signal, Assert, unsigned
from amaranth import Array, Module, Cat, Mux, ShapeLike, Signal, Assert, unsigned
from amaranth.build import Platform
from amaranth.lib import wiring, data
from amaranth.lib.wiring import In, Out
from amaranth.lib.memory import Memory, WritePort
from amaranth.lib.memory import Memory, ReadPort, WritePort
from amaranth.sim import Simulator
from amaranth.utils import ceil_log2
class RGBLayout(data.StructLayout):
@ -16,9 +18,9 @@ class RGBLayout(data.StructLayout):
)
rgb888_layout = RGBLayout(8, 8, 8)
Rgb888Layout = RGBLayout(8, 8, 8)
rgb111_hub75 = RGBLayout(1, 1, 1)
Rgb111Layout = RGBLayout(1, 1, 1)
class Hub75Stream(wiring.Signature):
@ -63,16 +65,79 @@ class Hub75Data(wiring.Signature):
def __init__(self):
super().__init__(
{
"rgb0": Out(rgb111_hub75),
"rgb1": Out(rgb111_hub75),
"rgb0": Out(Rgb111Layout),
"rgb1": Out(Rgb111Layout),
}
)
class SwapBuffer(wiring.Component):
"""A pair of BRAMs for holdling line data that are swapped between using an external signal.
Contains one write port, and one read port. They are attached to separate BRAMs to allow for
one to be read at the same time another is being updated.
def get_lineram() -> Memory:
return Memory(shape=rgb888_layout, depth=512, init=[])
Parameters:
depth: i32, depth of each memory buffer
shape: ShapeLike, the underlying shape of the memory.
Signals:
write_port: WritePort.Signature(width, shape)
read_port: ReadPort.Signature(width, shape)
selector: In(1)
"""
def __init__(self, shape: ShapeLike, depth: int):
super().__init__(
{
"selector": In(1),
"read_port": In(
ReadPort.Signature(addr_width=ceil_log2(depth), shape=shape)
),
"write_port": In(
WritePort.Signature(addr_width=ceil_log2(depth), shape=shape)
),
}
)
self.data_shape = shape
self.depth = depth
def elaborate(self, platform: Platform) -> Module:
m = Module()
m.submodules.bram0 = self.bram0 = Memory(
shape=self.data_shape, depth=self.depth, init=[]
)
m.submodules.bram1 = self.bram1 = Memory(
shape=self.data_shape, depth=self.depth, init=[]
)
read0 = self.bram0.read_port()
write0 = self.bram0.write_port()
read1 = self.bram1.read_port()
write1 = self.bram1.write_port()
# for name, member in self.write_port.signature.members.items():
# m.d.comb += self.write_port.members[name].eq(Mux(self.selector, write0[name], write1[name]))
#
m.d.comb += [
write0.addr.eq(self.write_port.addr),
write1.addr.eq(self.write_port.addr),
write0.en.eq(~self.selector),
write1.en.eq(self.selector),
# self.write_port.data.eq(Mux(self.selector, write0.data, write1.data)),
write0.data.eq(self.write_port.data),
write1.data.eq(self.write_port.data),
read0.addr.eq(self.read_port.addr),
read1.addr.eq(self.read_port.addr),
read0.en.eq(~self.selector),
read1.en.eq(self.selector),
self.read_port.data.eq(Mux(self.selector, read1.data, read0.data)),
]
return m
class Hub75StringDriver(wiring.Component):
@ -81,36 +146,42 @@ class Hub75StringDriver(wiring.Component):
bcm_select: In(3)
done: Out(1)
start: In(1)
active_bank: In(1) # the bank to use
bram_port: WritePort.Signature(addr_width=9, shape=rgb888_layout)
out: Out(Hub75Data())
active_bank: In(1) # the bank to use
bram_port: Out(WritePort.Signature(
addr_width=9, shape=Rgb888Layout
)) # the other line to be swapped to.
display_out: Out(Hub75Data()) # data signal output.
def elaborate(self, platform: Platform) -> Module:
m = Module()
# add two memories
m.submodules.bram0 = bram0 = Memory(shape=rgb888_layout, depth=512, init=[])
m.submodules.bram1 = bram1 = Memory(shape=rgb888_layout, depth=512, init=[])
m.submodules.bram0 = bram0 = Memory(shape=Rgb888Layout, depth=512, init=[])
m.submodules.bram1 = bram1 = Memory(shape=Rgb888Layout, depth=512, init=[])
# We use two brams here so we can swap between each - that way we can update the data
# while displaying the other line. Switching is controlled by the coordinator.
readports = Array([bram0.read_port(), bram1.read_port()])
readports = Mux([bram0.read_port(), bram1.read_port()])
active_readport = readports[self.active_bank]
m.d.comb += self.active_readport.eq(readports[self.active_bank])
m.d.comb += active_readport.eq(readports[self.active_bank])
writeports = Array([bram0.write_port(), bram1.write_port()])
m.d.comb += self.bram_port.eq(writeports[~self.active_bank])
# We want to set up the bram ports
port0 = bram0.read_port()
port1 = bram1.read_port()
# the enable for these ports is based on active bank.
m.d.comb += port0.en.eq(self.active_bank)
m.d.comb += port1.en.eq(~self.active_bank)
counter = Signal(32)
m.d.sync += counter.eq(counter + 1)
ram_rgb_slice = Cat(
active_readport.data['red'].bit_select(self.bcm_shift, 1),
active_readport.data['blue'].bit_select(self.bcm_shift, 1),
active_readport.data['green'].bit_select(self.bcm_shift, 1),
active_readport.data["red"].bit_select(self.bcm_shift, 1),
active_readport.data["blue"].bit_select(self.bcm_shift, 1),
active_readport.data["green"].bit_select(self.bcm_shift, 1),
)
pixnum = Signal(8, reset=127)
@ -120,29 +191,41 @@ class Hub75StringDriver(wiring.Component):
with m.FSM():
with m.State("init"):
m.d.sync += [
self.done.eq(0),
counter.eq(0),
pixnum.eq(127),
pixrow.eq(0),
self.done.eq(0),
counter.eq(0),
pixnum.eq(127),
pixrow.eq(0),
]
with m.If(self.start == 1):
m.d.sync += active_readport.en.eq(1)
m.next = "prefetch"
with m.State("prefetch"):
with m.State("prefetch"):
with m.If(counter == 0):
m.d.sync += pixrow.eq(0)
with m.Elif(counter == 1):
m.d.sync += pixrow.eq(1)
with m.Elif(counter == 2):
m.d.sync += self.out.rgb0.eq(ram_rgb_slice)
m.d.sync += self.display_out.rgb0.eq(ram_rgb_slice)
with m.Elif(counter == 3):
m.d.sync += [self.out.rgb1.eq(ram_rgb_slice), counter.eq(0)]
m.d.sync += [self.display_out.rgb1.eq(ram_rgb_slice), counter.eq(0)]
m.next = "writerow"
return m
def test_stringdriver():
dut = Hub75StringDriver()
sim = Simulator(dut)
sim.add_clock(1e-6)
async def testbench(ctx):
pass
sim.add_testbench(testbench)
with sim.write_vcd("output.vcd"):
sim.run_until(1e-6 * 1000)
class Hub75Coordinator(wiring.Component):
"""A shared-control hub75 driver"""
@ -271,7 +354,9 @@ class Hub75EDriver(wiring.Component):
return m
if __name__ == "__main__":
m = Hub75EDriver()
from amaranth.cli import main
main(m)

View file

@ -0,0 +1,33 @@
from amaranth import Array, Module, Cat, Signal, Assert, unsigned
from amaranth.build import Platform
from amaranth.lib import wiring, data
from amaranth.lib.wiring import In, Out
from amaranth.lib.memory import Memory, WritePort
from amaranth.sim import Simulator
from .bitslicer import Hub75StringDriver, Rgb888Layout, SwapBuffer
def test_swapbuffer():
dut = SwapBuffer(Rgb888Layout, 512)
sim = Simulator(dut)
sim.add_clock(1e-6)
async def testbench(ctx):
init_color = {"red": 0, "green": 0, "blue": 0}
test_color = {"red": 8, "green": 8, "blue": 8}
ctx.set(dut.selector, 0)
ctx.set(dut.write_port.addr, 1)
ctx.set(dut.read_port.addr, 1)
ctx.set(dut.write_port.data, test_color)
await ctx.tick()
# assert that the read port addr 1 = 0
assert ctx.get(dut.read_port.data) == init_color
# swap buffer
ctx.set(dut.selector, 1)
await ctx.tick().repeat(2) # takes two clocks after switching selector to output data.
assert ctx.get(dut.read_port.data) == test_color
sim.add_testbench(testbench)
with sim.write_vcd("output.vcd"):
sim.run_until(1e-6 * 1000)