From 74803da1f068568dcf7c42a589ed59e5620bc607 Mon Sep 17 00:00:00 2001 From: Sebastian Holzapfel Date: Wed, 10 Apr 2024 09:39:23 +0200 Subject: [PATCH] works on i5 --- deps/litex | 2 +- deps/litex_boards | 2 +- example-colorlight-i5.py | 92 +++++++++++++++++++++++++++++++++++ firmware/litex-fw/src/main.rs | 79 +++++------------------------- rtl/eurorack_pmod_wrapper.py | 2 +- 5 files changed, 106 insertions(+), 71 deletions(-) create mode 100755 example-colorlight-i5.py diff --git a/deps/litex b/deps/litex index 45db71b..abfcebe 160000 --- a/deps/litex +++ b/deps/litex @@ -1 +1 @@ -Subproject commit 45db71bf5eba10fda187f45790bda92c4d44577b +Subproject commit abfcebeb410d1fb74f5472d9ad5d334f9fea9539 diff --git a/deps/litex_boards b/deps/litex_boards index b8835e8..6c87d37 160000 --- a/deps/litex_boards +++ b/deps/litex_boards @@ -1 +1 @@ -Subproject commit b8835e805c0cbc7ec02d8c69ccb6be60e62f59ba +Subproject commit 6c87d377447fa6ebf425423be582f2cdac3a3bee diff --git a/example-colorlight-i5.py b/example-colorlight-i5.py new file mode 100755 index 0000000..e89a086 --- /dev/null +++ b/example-colorlight-i5.py @@ -0,0 +1,92 @@ +#!/usr/bin/env python3 + +# This variable defines all the external programs that this module +# relies on. lxbuildenv reads this variable in order to ensure +# the build will finish without exiting due to missing third-party +# programs. +LX_DEPENDENCIES = ["riscv", "nextpnr-ecp5", "yosys"] + +# Import lxbuildenv to integrate the deps/ directory +import lxbuildenv + +from litex.build.generic_platform import * +from litex.soc.cores.clock import * +from litex.soc.cores.dma import * +from litex.soc.interconnect import wishbone +from litex.soc.interconnect.stream import ClockDomainCrossing +from litex.soc.interconnect.csr_eventmanager import * +from litex.soc.integration.soc import SoCRegion + +from litex_boards.targets.colorlight_i5 import * + +from rtl.eurorack_pmod_wrapper import * + +_io_eurorack_pmod = [ + ("eurorack_pmod_p2b", 0, + Subsignal("mclk", Pins("N18")), + Subsignal("pdn", Pins("L20")), + Subsignal("i2c_sda", Pins("K20")), + Subsignal("i2c_scl", Pins("G20")), + Subsignal("sdin1", Pins("J20")), + Subsignal("sdout1", Pins("L18")), + Subsignal("lrck", Pins("M18")), + Subsignal("bick", Pins("N17")), + IOStandard("LVCMOS33") + ), + ("eurorack_pmod_p3b", 0, + Subsignal("mclk", Pins("A3")), + Subsignal("pdn", Pins("B1")), + Subsignal("i2c_sda", Pins("D2")), + Subsignal("i2c_scl", Pins("E2")), + Subsignal("sdin1", Pins("D1")), + Subsignal("sdout1", Pins("C1")), + Subsignal("lrck", Pins("C2")), + Subsignal("bick", Pins("E3")), + IOStandard("LVCMOS33") + ), +] + +def add_eurorack_pmod(soc, sample_rate=48000, dma_output_capable=True): + soc.platform.add_extension(_io_eurorack_pmod) + + # Create 256*Fs clock domain + soc.crg.cd_clk_256fs = ClockDomain() + soc.crg.pll.create_clkout(soc.crg.cd_clk_256fs, sample_rate * 256) + + # Create 1*Fs clock domain using a division register + soc.crg.cd_clk_fs = ClockDomain() + clkdiv_fs = Signal(8) + soc.sync.clk_256fs += clkdiv_fs.eq(clkdiv_fs+1) + soc.comb += soc.crg.cd_clk_fs.clk.eq(clkdiv_fs[-1]) + + # Now instantiate a EurorackPmod. + eurorack_pmod_pads = soc.platform.request("eurorack_pmod_p3b") + eurorack_pmod = EurorackPmod(soc.platform, eurorack_pmod_pads) + soc.add_module("eurorack_pmod0", eurorack_pmod) + soc.bus.add_slave("i2s", eurorack_pmod.bus, + SoCRegion(origin=0xb1000000, size=256*16, cached=False)) + soc.irq.add("eurorack_pmod0", use_loc_if_exists=True) + +def main(): + from litex.build.parser import LiteXArgumentParser + parser = LiteXArgumentParser(platform=colorlight_i5.Platform, description="LiteX SoC on Colorlight I5.") + parser.add_target_argument("--board", default="i5", help="Board type (i5).") + parser.add_target_argument("--revision", default="7.0", help="Board revision (7.0).") + parser.add_target_argument("--sys-clk-freq", default=60e6, type=float, help="System clock frequency.") + args = parser.parse_args() + + soc = BaseSoC( + sys_clk_freq = args.sys_clk_freq, + toolchain = args.toolchain, + with_video_framebuffer = True, + **parser.soc_argdict + ) + + add_eurorack_pmod(soc) + + builder = Builder(soc, **parser.builder_argdict) + if args.build: + builder.build(**parser.toolchain_argdict) + +if __name__ == "__main__": + main() diff --git a/firmware/litex-fw/src/main.rs b/firmware/litex-fw/src/main.rs index 3883cd7..7cd68ea 100644 --- a/firmware/litex-fw/src/main.rs +++ b/firmware/litex-fw/src/main.rs @@ -44,9 +44,7 @@ static mut LAST_IRQ: u32 = 0; static mut LAST_IRQ_LEN: u32 = 0; static mut LAST_IRQ_PERIOD: u32 = 0; -static mut LAST_IX: isize = 0; -static mut LAST_IY: isize = 0; -static mut LAST_RDAT: u32 = 0; +static mut RANDOM: u32 = 92; // Map the RISCV IRQ PLIC onto the fixed address present in the VexRISCV implementation. // TODO: ideally fetch this from the svf, its currently not exported by `svd2rust`! @@ -92,61 +90,26 @@ unsafe fn irq_handler() { let mut ch0raw = rdat as i16; let mut ch1raw = (rdat >> 16) as i16; - ch0raw <<= 3; - ch1raw <<= 3; + /* + RANDOM ^= RANDOM << 13; + RANDOM ^= RANDOM >> 17; + RANDOM ^= RANDOM << 5; + let ch0raw = RANDOM as i16; + let ch1raw = (RANDOM >> 16) as i16; + */ let ix: isize = (FB_SIZE_Y/2 - FB_XOFFS + ((ch0raw as i32 * (FB_SIZE_X) as i32) >> 16) as usize) as isize; let iy: isize = (FB_SIZE_X/2 + ((ch1raw as i32 * (FB_SIZE_Y) as i32) >> 16) as usize) as isize; if iy > 0 && iy < FB_SIZE_Y as isize { - let fb_ix = (FB_SIZE_Y*(iy as usize)) + (ix as usize); + FB[fb_ix] = 0xFF; + /* if FB[fb_ix] < (0xFF - 64) { FB[fb_ix] += 64; } - - let fb_ix2 = (FB_SIZE_Y*(((iy + LAST_IY)/2) as usize)) + (((ix + LAST_IX)/2) as usize); - - if FB[fb_ix2] < (0xFF - 64) { - FB[fb_ix2] += 64; - } - - LAST_IX = ix; - LAST_IY= iy; - } - - /* - if fb_ix > 0 && fb_ix < (FB_SIZE_X*(FB_SIZE_Y-2)) { - if FB[fb_ix] < (0xFF - 64) { - FB[fb_ix] += 64; - } - if FB[fb_ix+1] < (0xFF - 64) { - FB[fb_ix+1] += 64; - } - if FB[fb_ix-1] < (0xFF - 64) { - FB[fb_ix-1] += 64; - } - if FB[fb_ix+FB_SIZE_X] < (0xFF - 64) { - FB[fb_ix+FB_SIZE_X] += 64; - } - if FB[fb_ix-FB_SIZE_X] < (0xFF - 64) { - FB[fb_ix-FB_SIZE_X] += 64; - } + */ } - */ - /* - FB[((FB_SIZE_Y*(iy+FB_SIZE_Y/2+1)) + (ix+FB_SIZE_X/2-FB_XOFFS))] = 0xFF; - FB[((FB_SIZE_Y*(iy+FB_SIZE_Y/2-1)) + (ix+FB_SIZE_X/2-FB_XOFFS))] = 0xFF; - FB[((FB_SIZE_Y*(iy+FB_SIZE_Y/2)) + (ix+FB_SIZE_X/2-FB_XOFFS+1))] = 0xFF; - FB[((FB_SIZE_Y*(iy+FB_SIZE_Y/2)) + (ix+FB_SIZE_X/2-FB_XOFFS-1))] = 0xFF; - */ - - /* - FB[((FB_SIZE_Y*(iy+FB_SIZE_Y/2)+1) + (ix+FB_SIZE_X/2-FB_XOFFS+1))] = 0x7F; - FB[((FB_SIZE_Y*(iy+FB_SIZE_Y/2)+1) + (ix+FB_SIZE_X/2-FB_XOFFS-1))] = 0x7F; - FB[((FB_SIZE_Y*(iy+FB_SIZE_Y/2)-1) + (ix+FB_SIZE_X/2-FB_XOFFS+1))] = 0x7F; - FB[((FB_SIZE_Y*(iy+FB_SIZE_Y/2)-1) + (ix+FB_SIZE_X/2-FB_XOFFS-1))] = 0x7F; - */ } peripherals.EURORACK_PMOD0.ev_pending().write(|w| w.bits(pending_subtype)); @@ -197,27 +160,7 @@ fn main() -> ! { loop { unsafe { - /* - log::info!("rdat: {:x}", LAST_RDAT); - log::info!("ch0: {}", LAST_CH0); - log::info!("ch1: {}", LAST_CH1); - - // Print out some metrics as to how long our DSP operations are taking. - log::info!("irq_period: {}", LAST_IRQ_PERIOD); - log::info!("irq_len: {}", LAST_IRQ_LEN); - if LAST_IRQ_PERIOD != 0 { - log::info!("irq_load_percent: {}", (LAST_IRQ_LEN * 100) / LAST_IRQ_PERIOD); - } - */ - for p in 0..(FB_SIZE_X*FB_SIZE_Y) { - /* - if FB[p] > 32 { - FB[p] -= 32; - } else { - FB[p] = 0; - } - */ FB[p] >>= 1; } } diff --git a/rtl/eurorack_pmod_wrapper.py b/rtl/eurorack_pmod_wrapper.py index 4b9e0d5..ad7e500 100644 --- a/rtl/eurorack_pmod_wrapper.py +++ b/rtl/eurorack_pmod_wrapper.py @@ -18,7 +18,7 @@ ) class EurorackPmod(Module, AutoCSR): - def add_fifos(self, depth=512): + def add_fifos(self, depth=256): layout_rfifo = [("in0", 16), ("in1", 16),