generated from saji/ecp5-template
add wip sdram controller, start multistring hub75
Some checks failed
Verilator Unit Tests / Test (push) Failing after 3m28s
Some checks failed
Verilator Unit Tests / Test (push) Failing after 3m28s
This commit is contained in:
parent
bf35262640
commit
d42e227c4d
|
@ -1,7 +1,8 @@
|
|||
from amaranth import Module, Cat, Signal, Assert, unsigned
|
||||
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
|
||||
|
||||
|
||||
class RGBLayout(data.StructLayout):
|
||||
|
@ -55,9 +56,10 @@ class Hub75Ctrl(wiring.Signature):
|
|||
|
||||
|
||||
class Hub75Data(wiring.Signature):
|
||||
""" Data lines for HUB75 displays. When combined with Hub75Ctrl, this forms a complete HUB75 interface.
|
||||
"""Data lines for HUB75 displays. When combined with Hub75Ctrl, this forms a complete HUB75 interface.
|
||||
These are kept separate as some devices have a single set of control signals.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(
|
||||
{
|
||||
|
@ -65,31 +67,91 @@ class Hub75Data(wiring.Signature):
|
|||
"rgb1": Out(rgb111_hub75),
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
|
||||
def get_lineram() -> Memory:
|
||||
return Memory(shape=rgb888_layout, depth=512, init=[])
|
||||
|
||||
|
||||
|
||||
class Hub75StringDriver(wiring.Component):
|
||||
""" A data driver for Hub75 panels. This accesses the line memory and feeds out the data
|
||||
"""
|
||||
"""A data driver for Hub75 panels. This accesses the line memory and feeds out the data"""
|
||||
|
||||
bcm_select: In(3)
|
||||
|
||||
|
||||
class Hub75Coordinator(wiring.Component):
|
||||
""" A shared-control hub75 driver"""
|
||||
pass
|
||||
|
||||
class Bitslicer(wiring.Component):
|
||||
start_write: In(1)
|
||||
done: Out(1)
|
||||
bitplane_addr: Out(11)
|
||||
bitplane_wren: Out(1)
|
||||
bitplane_data: Out(6)
|
||||
start: In(1)
|
||||
active_bank: In(1) # the bank to use
|
||||
bram_port: WritePort.Signature(addr_width=9, shape=rgb888_layout)
|
||||
out: Out(Hub75Data())
|
||||
|
||||
|
||||
def elaborate(self, platform: Platform) -> Module:
|
||||
m = Module()
|
||||
|
||||
bitplane_bit = Signal(3)
|
||||
|
||||
# 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=[])
|
||||
|
||||
|
||||
# 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()])
|
||||
active_readport = readports[self.active_bank]
|
||||
m.d.comb += self.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])
|
||||
|
||||
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),
|
||||
)
|
||||
|
||||
pixnum = Signal(8, reset=127)
|
||||
pixrow = Signal(1, reset=0)
|
||||
m.d.comb += self.buf_addr.eq(Cat(pixrow, pixnum))
|
||||
|
||||
with m.FSM():
|
||||
with m.State("init"):
|
||||
m.d.sync += bitplane_bit.eq(0)
|
||||
m.d.sync += self.done.eq(0)
|
||||
m.d.sync += [
|
||||
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.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)
|
||||
with m.Elif(counter == 3):
|
||||
m.d.sync += [self.out.rgb1.eq(ram_rgb_slice), counter.eq(0)]
|
||||
m.next = "writerow"
|
||||
|
||||
|
||||
return m
|
||||
|
||||
|
||||
class Hub75Coordinator(wiring.Component):
|
||||
"""A shared-control hub75 driver"""
|
||||
|
||||
def __init__(self, n_strings=1):
|
||||
self.n_strings = n_strings
|
||||
super().__init__()
|
||||
|
||||
def elaborate(self, platform: Platform) -> Module:
|
||||
m = Module()
|
||||
|
||||
return m
|
||||
|
||||
|
@ -208,3 +270,8 @@ class Hub75EDriver(wiring.Component):
|
|||
m.next = "init"
|
||||
|
||||
return m
|
||||
|
||||
if __name__ == "__main__":
|
||||
m = Hub75EDriver()
|
||||
from amaranth.cli import main
|
||||
main(m)
|
||||
|
|
70
src/groovylight/sdram.py
Normal file
70
src/groovylight/sdram.py
Normal file
|
@ -0,0 +1,70 @@
|
|||
# SDRAM controller for the Colorlight 5a-75b
|
||||
|
||||
|
||||
from amaranth import Module, Cat, Signal, Assert, unsigned
|
||||
from amaranth.build import Platform
|
||||
from amaranth.lib import wiring, data, enum
|
||||
from amaranth.lib.wiring import In, Out
|
||||
|
||||
|
||||
# RAM Specs:
|
||||
# 4 banks, 2048 rows, 256 columns.
|
||||
# 11 row bits, 8 column bits.
|
||||
# word size = 32
|
||||
# 8 megabytes data.
|
||||
|
||||
|
||||
sdram_control_layout = data.StructLayout(
|
||||
{
|
||||
"nCS": 1,
|
||||
"nRAS": 1,
|
||||
"nCAS": 1,
|
||||
"nWE": 1,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
|
||||
class _WriteBurstLength(enum.Enum, shape=1):
|
||||
"""MRS field"""
|
||||
BURST = 0
|
||||
SINGLE_BIT = 1
|
||||
|
||||
class _TestMode(enum.Enum, shape=2):
|
||||
""" The "test mode" of the sdram. This is always zero pretty much"""
|
||||
MODE_REGISTER_SET = 0
|
||||
RESERVED0 = 1
|
||||
RESERVED1 = 2
|
||||
RESERVED2 = 3
|
||||
|
||||
class _CASLatency(enum.Enum, shape=3):
|
||||
""" How many cycles of latency for the column address select to complete """
|
||||
CYCL2 = 2
|
||||
CYCL3 = 3
|
||||
|
||||
class _BurstType(enum.Enum, shape=1):
|
||||
SEQUENTIAL = 0
|
||||
INTERLEAVED = 1
|
||||
|
||||
class _BurstLength(enum.IntEnum, shape=3):
|
||||
""" The size of the burst """
|
||||
SINGLE = 0
|
||||
DUAL = 1
|
||||
QUAD = 2
|
||||
OCT = 3
|
||||
FULL_PAGE = 7
|
||||
|
||||
|
||||
class _Command(enum.Enum):
|
||||
""" Command set for SDRAM """
|
||||
MRS_WRITE = 0
|
||||
ACTIVATE = 1
|
||||
PRECHARGE = 2
|
||||
WRITE = 3
|
||||
READ = 4
|
||||
CBR = 5 # auto refresh
|
||||
SELF_REFRESH = 6
|
||||
BRST_STOP = 7
|
||||
NOP = 8
|
||||
|
||||
|
Loading…
Reference in a new issue