Compare commits

..

3 commits

Author SHA1 Message Date
Saji 6b034b0176 add wip fetcher
All checks were successful
Unit Tests / Test (push) Successful in 2m2s
2024-10-08 20:58:20 -05:00
Saji e945aa03f2 fix tests 2024-10-08 20:58:10 -05:00
saji 3187db40ae add displaystrobe, config/geom fixes 2024-10-08 20:57:39 -05:00
4 changed files with 89 additions and 6 deletions

View file

@ -24,9 +24,11 @@ Rgb111Layout = RGBLayout(1, 1, 1)
class RGBView(data.View):
def bit_depth(self) -> int:
return max(self.red.shape(), self.green.shape(), self.blue.shape())
return max(
self.red.shape().width, self.green.shape().width, self.blue.shape().width
)
def channel_slice(self, bit: int) -> Rgb111Layout:
"""Select bits from each channel and use it to form an Rgb111Layout.
This is useful for BCM stuff, since the bits are sliced to form a bitplane.

View file

@ -0,0 +1,82 @@
# Holds various implementations of a "fetcher", which is given a display string
# to know its location.
# 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.build import Platform
from amaranth.lib import wiring, data
from amaranth.lib.wiring import In, Out
from amaranth.lib.memory import Memory, ReadPort, WritePort
from amaranth.lib import stream
from amaranth.utils import ceil_log2
import logging
from .common import Rgb666Layout, Hub75Stream, Hub75Ctrl, Hub75Data, Rgb888Layout
from .geom import DisplayRotation, DisplayString
logger = logging.getLogger(__name__)
CoordLayout = data.StructLayout({"x": unsigned(32), "y": unsigned(32)})
class AddressGenerator(wiring.Component):
"""Generates (x,y) sequences corresponding to a display row."""
def __init__(self, geom: DisplayString, *, src_loc_at=0):
self.geom = geom
super().__init__(
{
"coordstream": Out(stream.Signature(CoordLayout)),
"start": In(1),
"done": Out(1),
"addr": In(geom.dimensions.addr_bits),
},
src_loc_at=src_loc_at,
)
def elaborate(self, platform: Platform) -> Module:
m = Module()
counter = Signal(self.geom.dimensions.length)
# based on the geometry we generate x,y pairs.
with m.FSM():
with m.State("init"):
m.d.comb += self.done.eq(0)
m.d.sync += counter.eq(0)
with m.If(self.start):
m.next = "run"
with m.State("run"):
if self.geom.rotation == DisplayRotation.LEFTRIGHT:
# default case, +x.
pass
elif self.geom.rotation == DisplayRotation.UPDOWN:
# r 90, +y
pass
with m.State("done"):
m.d.comb += self.done.eq(1)
m.next = "init"
return m
class BasicFetcher(wiring.Component):
"""A generic fetcher. Takes a function of the form f(x,y: int) -> RGB."""
def __init__(
self, geom: DisplayString, dfunc, data_shape=Rgb888Layout, *, src_loc_at=0
):
self.dfunc = dfunc
super().__init__(
{
"pixstream": Out(stream.Signature(Rgb888Layout)),
"start": In(1),
"addr": In(geom.dimensions.addr_bits),
},
src_loc_at=src_loc_at,
)

View file

@ -1,4 +1,4 @@
from amaranth import Module, Cat, Mux, Print, ShapeLike, Signal, Assert, Array
from amaranth import Module, Cat, Mux, ShapeLike, Signal, Assert, Array
from amaranth.build import Platform
from amaranth.lib import wiring, data
from amaranth.lib.wiring import In, Out
@ -313,7 +313,6 @@ class Hub75DataDriver(wiring.Component):
return m
class Hub75Coordinator(wiring.Component):
"""A shared-control hub75 driver"""

View file

@ -7,14 +7,14 @@ from groovylight.common import Rgb888Layout, Rgb666Layout, RGBView
def test_rgbview():
rgb = Rgb888Layout(0xAABBCC)
assert rgb.channel_size() == unsigned(8)
assert rgb.bit_depth() == 8
rgb18 = Rgb666Layout(0x2DEFD)
slice = rgb.channel_slice(1)
assert isinstance(slice, RGBView), "channel_slice should return another rgbview"
assert slice.channel_size() == unsigned(1), "channel_slice channel size should be 1"
assert slice.bit_depth() == 1, "channel_slice channel size should be 1"
assert isinstance(
rgb18.channel_slice(5), RGBView
), "channel_slice should return another rgbview"