From: git Date: Sat, 11 Apr 2026 16:34:39 +0000 (-0400) Subject: initial public commit X-Git-Url: https://git.datadissipation.net/?a=commitdiff_plain;h=3856064e3206d9dbe3c6d2e647a1594b15524b6d;p=smh-ac440b-litex.git initial public commit --- 3856064e3206d9dbe3c6d2e647a1594b15524b6d diff --git a/README.md b/README.md new file mode 100644 index 0000000..2bf4dc4 --- /dev/null +++ b/README.md @@ -0,0 +1,6 @@ +Litex target for [SiMiaoHub AC440B](http://doc.simiaohub.com/p/ac440b/index.html) - a small EP4CE40 devboard. + +Features: +- Asynchronous SoC reset button +- Power-On Reset +- Board LEDs and buttons accessible as CSR diff --git a/smh_ac440b_board.py b/smh_ac440b_board.py new file mode 100644 index 0000000..7904dea --- /dev/null +++ b/smh_ac440b_board.py @@ -0,0 +1,53 @@ +from litex.build.generic_platform import * +from litex.build.altera import AlteraPlatform +from litex.build.altera.programmer import USBBlaster + +# I/O -------------------------------------------------------------------------- + +_io = [ + + # Persistent I/O - fixed on the AC440B itself ------------------------------ + + # Clk + ("clk50", 0, Pins("T2"), IOStandard("3.3-V LVTTL")), + + # D1-D4 + ("u_led_n", 0, Pins("V22"), IOStandard("3.3-V LVTTL")), + ("u_led_n", 1, Pins("V21"), IOStandard("3.3-V LVTTL")), + ("u_led_n", 2, Pins("U22"), IOStandard("3.3-V LVTTL")), + ("u_led_n", 3, Pins("U21"), IOStandard("3.3-V LVTTL")), + + # RST, K1-K2 + ("rst_n", 0, Pins("D2"), IOStandard("3.3-V LVTTL")), + ("u_key_n", 0, Pins("W1"), IOStandard("3.3-V LVTTL")), + ("u_key_n", 1, Pins("V1"), IOStandard("3.3-V LVTTL")), + + # Persistent I/O end ------------------------------------------------------- + + ("serial", 0, + Subsignal("tx", Pins("Y22"), IOStandard("3.3-V LVTTL")), + Subsignal("rx", Pins("W22"), IOStandard("3.3-V LVTTL")) + ), + + ] + +_connectors = [ + +] + +# Platform --------------------------------------------------------------------- + +class Platform(AlteraPlatform): + default_clk_name = "clk50" + default_clk_period = 1e9/50e6 + + def __init__(self, toolchain="quartus"): + AlteraPlatform.__init__(self, "EP4CE40F23C8", _io, _connectors, toolchain=toolchain) + self.add_platform_command("set_global_assignment -name CYCLONEII_RESERVE_NCEO_AFTER_CONFIGURATION \"USE AS REGULAR IO\"") + + def create_programmer(self): + return USBBlaster() + + def do_finalize(self, fragment): + AlteraPlatform.do_finalize(self, fragment) + self.add_period_constraint(self.lookup_request("clk50", loose=True), 1e9/50e6) diff --git a/smh_ac440b_target.py b/smh_ac440b_target.py new file mode 100755 index 0000000..5b605b9 --- /dev/null +++ b/smh_ac440b_target.py @@ -0,0 +1,107 @@ +#!/usr/bin/env python3 + +from migen import * + +from litex.gen import * + +from litex.soc.cores.clock import CycloneIVPLL +from litex.soc.integration.soc_core import * +from litex.soc.integration.builder import * +from litex.soc.interconnect.csr import * +from migen.genlib.resetsync import AsyncResetSynchronizer + +import mmuless_board + +# CRG -------------------------------------------------------------------------- + +class _CRG(LiteXModule): + def __init__(self, platform, sys_clk_freq): + self.rst = Signal() + self.cd_por = ClockDomain(reset_less=True) + self.cd_sys = ClockDomain() + # clock domain used only for reset button sync + self.cd_sync = ClockDomain() + + clk50 = platform.request("clk50") + rst_n = platform.request("rst_n") + + # POR + por_count = Signal(16, reset=2**16 - 1) + por_done = Signal() + self.comb += self.cd_por.clk.eq(clk50) + self.comb += por_done.eq(por_count == 0) + self.sync.por += If(~por_done, por_count.eq(por_count - 1)) + + # PLL + self.pll = pll = CycloneIVPLL(speedgrade="-6") + self.comb += pll.reset.eq(~por_done | self.rst) + pll.register_clkin(clk50, 50e6) + pll.create_clkout(self.cd_sys, sys_clk_freq, margin=0, with_reset=False) + + # Sys CD + sys_rst = Signal() + self.comb += sys_rst.eq(~pll.locked) + self.specials += AsyncResetSynchronizer(self.cd_sys, sys_rst) + + # Sync Cd + self.comb += self.cd_sync.clk.eq(self.cd_sys.clk) + self.specials += AsyncResetSynchronizer(self.cd_sync, ~rst_n) + + +# BaseSoC ---------------------------------------------------------------------- + +class BaseSoC(SoCCore): + def __init__(self, sys_clk_freq=50e6, + **kwargs): + + platform = mmuless_board.Platform() + + # CRG ------------------------------------------------------------------ + self.crg = _CRG(platform, sys_clk_freq) + + # SoCCore -------------------------------------------------------------- + if kwargs["with_jtagbone"]: + if kwargs.get("uart_name", "serial") == "serial": kwargs["uart_name"] = "crossover" + + SoCCore.__init__(self, platform, sys_clk_freq, + ident = "LiteX SoC on SiMiaoHub AC440B", + **kwargs + ) + + # Leds ----------------------------------------------------------------- + leds = Cat(*[platform.request("u_led_n", i) for i in range(4)]) + self.submodules.leds = CSRStorage(len(leds), description="Board LEDs") + self.comb += leds.eq(~self.leds.storage) + + # Buttons -------------------------------------------------------------- + keys = Cat(*[platform.request("u_key_n", i) for i in range(2)]) + self.submodules.btns = CSRStatus(len(keys), description="Board buttons") + self.comb += self.btns.status.eq(~keys) + # Reset button hook + self.comb += If(self.crg.cd_sync.rst, self.cpu.reset.eq(1)) + + + +# Build ------------------------------------------------------------------------ + +def main(): + from litex.build.parser import LiteXArgumentParser + parser = LiteXArgumentParser(platform=mmuless_board.Platform, description="LiteX SoC on SiMiaoHub AC440B") + parser.add_target_argument("--sys-clk-freq", default=50e6, type=float, help="System clock frequency.") + args = parser.parse_args() + + soc = BaseSoC( + sys_clk_freq = args.sys_clk_freq, + **parser.soc_argdict + ) + + builder = Builder(soc, **parser.builder_argdict) + if args.build: + builder.build(**parser.toolchain_argdict) + + if args.load: + prog = soc.platform.create_programmer() + prog.load_bitstream(builder.get_bitstream_filename(mode="sram")) + +if __name__ == "__main__": + main()