fetcher basic
All checks were successful
Unit Tests / Test (push) Successful in 2m8s

doesn't support variable functions
This commit is contained in:
saji 2024-10-23 15:14:53 -05:00
parent 6b63b17bb8
commit 5f54b8acd8
3 changed files with 70 additions and 18 deletions

View file

@ -3,17 +3,15 @@
# during operation, it is given a row index, and responds with the data. # during operation, it is given a row index, and responds with the data.
from amaranth import Module, Cat, Mux, ShapeLike, Signal, Assert, Array, unsigned from amaranth import Module, Signal, unsigned, Cat
from amaranth.build import Platform from amaranth.build import Platform
from amaranth.lib import wiring, data from amaranth.lib import wiring, data
from amaranth.lib.wiring import In, Out from amaranth.lib.wiring import In, Out
from amaranth.lib.memory import Memory, ReadPort, WritePort
from amaranth.lib import stream from amaranth.lib import stream
from amaranth.utils import ceil_log2
import logging import logging
from .common import Rgb666Layout, Hub75Stream, Hub75Ctrl, Hub75Data, Rgb888Layout from .common import Rgb888Layout
from .geom import DisplayRotation, DisplayString from .geom import DisplayString
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -91,7 +89,8 @@ class AddressGenerator(wiring.Component):
# stream data out as long as it's valid. # stream data out as long as it's valid.
with m.If( with m.If(
self.coordstream.ready & (counter == self.geom.dimensions.length - 1) self.coordstream.ready
& (counter == self.geom.dimensions.length - 1)
): ):
m.next = "done" m.next = "done"
with m.Elif(self.coordstream.ready): with m.Elif(self.coordstream.ready):
@ -107,17 +106,42 @@ class AddressGenerator(wiring.Component):
class BasicFetcher(wiring.Component): class BasicFetcher(wiring.Component):
"""A generic fetcher. Takes a function of the form f(x,y: int) -> RGB.""" """A generic function-based fetcher. Takes a function of the form f(x,y: int) -> RGB."""
def __init__( def __init__(
self, geom: DisplayString, dfunc, data_shape=Rgb888Layout, *, src_loc_at=0 self, geom: DisplayString, dfunc, data_shape=Rgb888Layout, *, src_loc_at=0
): ):
self.geom = geom
self.dfunc = dfunc self.dfunc = dfunc
super().__init__( super().__init__(
{ {
"pixstream": Out(stream.Signature(data.ArrayLayout(Rgb888Layout, 2))), "input": In(
"start": In(1), stream.Signature(data.ArrayLayout(CoordLayout, geom.dimensions.mux))
"addr": In(geom.dimensions.addr_bits), ),
"pixstream": Out(
stream.Signature(data.ArrayLayout(data_shape, geom.dimensions.mux))
),
}, },
src_loc_at=src_loc_at, src_loc_at=src_loc_at,
) )
def elaborate(self, platform: Platform) -> Module:
m = Module()
# test mode - pass through, r = x + y, g = x - y, b = {y,x}
colors = self.pixstream.payload
m.d.comb += [
self.input.valid.eq(self.pixstream.valid),
self.input.ready.eq(self.pixstream.ready),
]
for i in range(self.geom.dimensions.mux):
inp = self.input.payload[i]
m.d.comb += [
colors[i].red.eq(inp.x + inp.y),
colors[i].green.eq(inp.x - inp.y),
colors[i].blue.eq(inp.x ^ inp.y),
]
return m

View file

@ -4,7 +4,7 @@ import random
from random import randrange from random import randrange
import pytest import pytest
from groovylight.fetcher import AddressConverter, AddressGenerator from groovylight.fetcher import AddressConverter, AddressGenerator, BasicFetcher
from groovylight.geom import DisplayString, Coord, DisplayDimensions, DisplayRotation from groovylight.geom import DisplayString, Coord, DisplayDimensions, DisplayRotation
ds_testdata = [ ds_testdata = [
@ -54,9 +54,9 @@ generator_tests = [
(0, DisplayRotation.R0), (0, DisplayRotation.R0),
(0, DisplayRotation.R90), (0, DisplayRotation.R90),
(4, DisplayRotation.R90), (4, DisplayRotation.R90),
] ]
@pytest.mark.parametrize("addr, rot", generator_tests) @pytest.mark.parametrize("addr, rot", generator_tests)
def test_generator(addr, rot): def test_generator(addr, rot):
ds = DisplayString(Coord(3, 0), DisplayDimensions(128, 64), rot) ds = DisplayString(Coord(3, 0), DisplayDimensions(128, 64), rot)
@ -74,7 +74,8 @@ def test_generator(addr, rot):
await ctx.tick().until(dut.done == 1) await ctx.tick().until(dut.done == 1)
expected = [ expected = [
[ds.translate_coord(x, addr, 0), ds.translate_coord(x, addr, 1)] for x in range(128) [ds.translate_coord(x, addr, 0), ds.translate_coord(x, addr, 1)]
for x in range(128)
] ]
expected.reverse() expected.reverse()
@ -88,3 +89,31 @@ def test_generator(addr, rot):
sim.add_testbench(stream_checker) sim.add_testbench(stream_checker)
with sim.write_vcd("generator.vcd"): with sim.write_vcd("generator.vcd"):
sim.run() sim.run()
basicFetcher_tests = [
({"x": 0, "y": 0}, {"red": 0, "green": 0, "blue": 0}),
({"x": 1, "y": 1}, {"red": 2, "green": 0, "blue": 0}),
({"x": 9, "y": 1}, {"red": 10, "green": 8, "blue": 8}),
]
@pytest.mark.parametrize("inp, expected", basicFetcher_tests)
def test_basic_fetcher(inp, expected):
ds = DisplayString(
Coord(3, 0), DisplayDimensions(128, 64, mux=1), DisplayRotation.R0
)
dut = BasicFetcher(ds, None)
sim = Simulator(dut)
async def test(ctx):
ctx.set(dut.input.payload[0], inp)
res = ctx.get(dut.pixstream.payload)[0]
assert res["red"] == expected["red"]
assert res["green"] == expected["green"]
assert res["blue"] == expected["blue"]
sim.add_testbench(test)
with sim.write_vcd("fetcher.vcd"):
sim.run()

View file

@ -146,7 +146,6 @@ def test_datadriver_single(bcm):
with sim.write_vcd("output.vcd"): with sim.write_vcd("output.vcd"):
sim.run() sim.run()
@pytest.mark.skip() @pytest.mark.skip()
def test_hub75_coordinator(): def test_hub75_coordinator():
m = Module() m = Module()