]> datadissipation.net git - smh-ac440b-litex.git/commitdiff
initial public commit
authorgit <redacted>
Sat, 11 Apr 2026 16:34:39 +0000 (12:34 -0400)
committergit <redacted>
Sat, 11 Apr 2026 16:34:39 +0000 (12:34 -0400)
README.md [new file with mode: 0644]
smh_ac440b_board.py [new file with mode: 0644]
smh_ac440b_target.py [new file with mode: 0755]

diff --git a/README.md b/README.md
new file mode 100644 (file)
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 (file)
index 0000000..7904dea
--- /dev/null
@@ -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 (executable)
index 0000000..5b605b9
--- /dev/null
@@ -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()