diff --git a/flake.nix b/flake.nix index 5cebaeb..6f7a6f4 100644 --- a/flake.nix +++ b/flake.nix @@ -49,6 +49,7 @@ nextpnr pkgsCross.riscv64.buildPackages.gcc gnumake + wishbone-tool # simulators verilog verilator diff --git a/groovylight/hub75.py b/groovylight/hub75.py index 5990f34..64c62c3 100644 --- a/groovylight/hub75.py +++ b/groovylight/hub75.py @@ -2,25 +2,92 @@ # r0 g0 b0 gnd r1 g1 b1 e a b c d clk stb oe gnd from litex.build.generic_platform import Signal, Subsignal, Pins -from litex.build.io import Module +from litex.build.io import FSM, Module +from litex.gen import If, NextState, NextValue def make_hub75_iodevice(index, basename): b = basename signals = ("hub75_iodev", index, - Subsignal("r0", Pins(f"{b}:1")), - Subsignal("g0", Pins(f"{b}:2")), - Subsignal("b0", Pins(f"{b}:3")), - Subsignal("r1", Pins(f"{b}:5")), - Subsignal("g1", Pins(f"{b}:6")), - Subsignal("b1", Pins(f"{b}:7")), - Subsignal("addr", Pins(f"{b}:9 {b}:10 {b}:11 {b}:12 {b}:8")), - Subsignal("clk", Pins(f"{b}:13")), - Subsignal("stb", Pins(f"{b}:14")), - Subsignal("oe", Pins(f"{b}:15")), + Subsignal("r0", Pins(f"{b}:0")), + Subsignal("g0", Pins(f"{b}:1")), + Subsignal("b0", Pins(f"{b}:2")), + Subsignal("r1", Pins(f"{b}:4")), + Subsignal("g1", Pins(f"{b}:5")), + Subsignal("b1", Pins(f"{b}:6")), + Subsignal("addr", Pins(f"{b}:8 {b}:9 {b}:10 {b}:11 {b}:7")), + Subsignal("clk", Pins(f"{b}:12")), + Subsignal("stb", Pins(f"{b}:13")), + Subsignal("oe", Pins(f"{b}:14")), ) return [signals] class Hub75Driver(Module): - count = Signal(8) # fsm counter - + def __init__(self, base_freq=60e6, linedepth=128): + if base_freq // 2 > 30e6: + raise RuntimeError("hi") + + self.phase = Signal() # divider/counter + self.addr = Signal(5) + self.latch = Signal() + self.output_en = Signal() + self.rgb = Signal(6) + + + # clk-en acts as a gate. + clock_en = Signal() + + self.clock_out = Signal() + # self.comb += self.clock_out.eq(self.phase & clock_en) + # clock counter increments. + self.sync += self.phase.eq(self.phase + 1) + + # self.sync += If(self.phase == 1, If(clock_en, self.clock_out.eq(self.phase)).Else(self.clock_out.eq(0))) + self.sync += If(clock_en, self.clock_out.eq(self.phase)).Else(self.clock_out.eq(0)) + + self.fsm = fsm = FSM() + self.submodules += self.fsm + + self.comb += self.rgb.eq(0b111010) + + counter = Signal(8) + + fsm.act("ready", + NextValue(self.output_en, 1), + NextValue(self.pixnum, linedepth - 1), + NextValue(self.latch, 0), + If(self.phase == 1, + NextValue(self.addr, self.addr + 1), + NextValue(clock_en, 1), + NextState("transmit"), + ), + # If((self.state_count == 7), NextValue(clock_en, ~clock_en)), + ) + fsm.act("transmit", + If(self.phase == 1, + NextValue(self.pixnum, self.pixnum - 1), + If(self.pixnum == 0, + NextState("latch_delay"), + ) + ) + ) + fsm.act("latch_delay", + NextValue(clock_en, 0), + If(self.phase == 1, + NextState("latchout") + ) + ) + fsm.act("latchout", + If(self.phase == 1, + NextValue(self.latch, 1), + NextValue(counter, 0), + NextState("done") + ) + ) + fsm.act("done", + NextValue(self.output_en, 0), + NextValue(self.latch, 0), + NextValue(counter, counter + 1), + If(counter == 255, NextState("ready")) + ) + diff --git a/groovylight/platform/colorlight_5a_75b_8_0.py b/groovylight/platform/colorlight_5a_75b_8_0.py index 85f9e53..e8874c9 100644 --- a/groovylight/platform/colorlight_5a_75b_8_0.py +++ b/groovylight/platform/colorlight_5a_75b_8_0.py @@ -93,6 +93,7 @@ _connectors = [ class _CRG(LiteXModule): def __init__(self, platform, sys_clk_freq, with_reset = False): self.cd_sys = ClockDomain("sys") + self.cd_hub = ClockDomain("hub") # self.cd_sdram = ClockDomain("sdram") self.cd_sys2x = ClockDomain() self.cd_sys2x_ps = ClockDomain() @@ -105,13 +106,14 @@ class _CRG(LiteXModule): self.pll = pll = ECP5PLL() rst_n = platform.request("user_btn_n", 0) if with_reset else 1 - self.comb += [pll.reset.eq(~rst_n)] + self.comb += pll.reset.eq(~rst_n) pll.register_clkin(clk25, 25e6) pll.create_clkout(self.cd_sys, sys_clk_freq) # for the sdram # pll.create_clkout(self.cd_sdram, sys_clk_freq, phase=180) pll.create_clkout(self.cd_sys2x, 2*sys_clk_freq) pll.create_clkout(self.cd_sys2x_ps, 2*sys_clk_freq, phase=180) + pll.create_clkout(self.cd_hub, 30e6) sdram_clk = ClockSignal("sys2x_ps") diff --git a/groovylight/soc.py b/groovylight/soc.py index 3e766d9..dd3ad0a 100644 --- a/groovylight/soc.py +++ b/groovylight/soc.py @@ -13,7 +13,7 @@ from litedram.phy import GENSDRPHY, HalfRateGENSDRPHY from liteeth.phy.ecp5rgmii import LiteEthPHYRGMII from platform.colorlight_5a_75b_8_0 import Groovy1Platform - +from hub75 import Hub75Driver, make_hub75_iodevice class GroovySoC(SoCCore): def __init__(self, platform, sys_clk_freq, @@ -49,6 +49,24 @@ class GroovySoC(SoCCore): self.mem_map["spiflash"] = 0x20000000 mod = SpiFlashModule(SpiNorFlashOpCodes.READ_1_1_1) self.add_spi_flash(mode="1x", module=SpiFlashModule, with_master=False) + self.platform.add_extension(make_hub75_iodevice(0, "j4")) + hub_io = self.platform.request("hub75_iodev", 0) + self.submodules.hub75 = hub75 = ClockDomainsRenamer("hub")(Hub75Driver()) + self.comb += [ + hub_io.r0.eq(hub75.rgb[0]), + hub_io.r1.eq(hub75.rgb[3]), + hub_io.g0.eq(hub75.rgb[1]), + hub_io.g1.eq(hub75.rgb[4]), + hub_io.b0.eq(hub75.rgb[2]), + hub_io.b1.eq(hub75.rgb[5]), + hub_io.clk.eq(hub75.clock_out), + hub_io.addr.eq(hub75.addr), + hub_io.oe.eq(hub75.output_en), + hub_io.stb.eq(hub75.latch), + + ] + + diff --git a/litex/default.nix b/litex/default.nix index 3e9ed12..4ae6aa5 100644 --- a/litex/default.nix +++ b/litex/default.nix @@ -2,6 +2,7 @@ let tag = "2023.12"; in final: prev: { + wishbone-tool = prev.callPackage(import ./wishbone-tool.nix) { }; pythonPackagesExtensions = prev.pythonPackagesExtensions ++ [ (python-final: python-prev: { litex = python-final.callPackage(import ./litex.nix tag) { }; diff --git a/litex/wishbone-tool.nix b/litex/wishbone-tool.nix new file mode 100644 index 0000000..8099892 --- /dev/null +++ b/litex/wishbone-tool.nix @@ -0,0 +1,17 @@ +{ lib, fetchFromGitHub, rustPlatform }: + +rustPlatform.buildRustPackage rec { + pname = "wishbone-tool"; + version = "0.7.9-git"; + + src = fetchFromGitHub { + owner = "litex-hub"; + repo = "wishbone-utils"; + rev = "master"; + hash = "sha256-ZEJ3hd5G/zziCMqG1yvRzrt3JX6PtJupenq+xM8AKO0="; + }; + sourceRoot = "${src.name}/wishbone-tool"; + + + cargoHash = "sha256-kWvtZEXtb5bZ7/hd8jsr41UGSDOuDU4tyKWAL0kDoIg="; +}