diff --git a/sbus-to-ztex-gateware-migen/engine.py b/sbus-to-ztex-gateware-migen/engine.py index 43c0626..72a180f 100644 --- a/sbus-to-ztex-gateware-migen/engine.py +++ b/sbus-to-ztex-gateware-migen/engine.py @@ -1934,7 +1934,8 @@ Here are the currently implemented opcodes for The Engine: ##### TIMING CONSTRAINTS -- you want these. Trust me. clk50 = "clk50" - clk100 = "clk100" + #clk100 = "clk100" + clk100 = "sysclk" clk200 = "clk200" # registered exec units need this set of rules ### clk200->clk50 multi-cycle paths: diff --git a/sbus-to-ztex-gateware-migen/sbus_to_fpga_fsmstat.py b/sbus-to-ztex-gateware-migen/sbus_to_fpga_fsmstat.py new file mode 100644 index 0000000..6ae0230 --- /dev/null +++ b/sbus-to-ztex-gateware-migen/sbus_to_fpga_fsmstat.py @@ -0,0 +1,59 @@ +from migen import * +from migen.genlib.cdc import BusSynchronizer +from litex.soc.interconnect.csr import * +from litex.soc.interconnect import wishbone + +class SBusFPGABusStat(Module, AutoCSR): + def __init__(self, sbus_bus): + self.stat_ctrl = CSRStorage(fields = [CSRField("update", 1, description = "update")]) + self.submodules.sync_update = BusSynchronizer(width = 1, idomain="sys", odomain="sbus") + self.comb += self.sync_update.i.eq(self.stat_ctrl.fields.update) + self.comb += sbus_bus.stat_update.eq(self.sync_update.o) + + self.live_stat_cycle_counter = CSRStatus(32, description="live_stat_cycle_counter") + self.stat_cycle_counter = CSRStatus(32, description="stat_cycle_counter") + self.stat_slave_start_counter = CSRStatus(32, description="stat_slave_start_counter") + self.stat_slave_done_counter = CSRStatus(32, description="stat_slave_done_counter") + self.stat_slave_rerun_counter = CSRStatus(32, description="stat_slave_rerun_counter") + self.stat_slave_early_error_counter = CSRStatus(32, description="stat_slave_early_error_counter") + self.stat_master_start_counter = CSRStatus(32, description="stat_master_start_counter") + self.stat_master_done_counter = CSRStatus(32, description="stat_master_done_counter") + self.stat_master_error_counter = CSRStatus(32, description="stat_master_error_counter") + self.stat_master_rerun_counter = CSRStatus(32, description="stat_master_rerun_counter") + self.sbus_master_error_virtual = CSRStatus(32, description="sbus_master_error_virtual") + + self.submodules.sync_live_stat_cycle_counter = BusSynchronizer(width = 32, idomain="sbus", odomain="sys") + self.comb += self.sync_live_stat_cycle_counter.i.eq(sbus_bus.stat_cycle_counter) + self.comb += self.live_stat_cycle_counter.status.eq(self.sync_live_stat_cycle_counter.o) + + self.submodules.sync_stat_cycle_counter = BusSynchronizer(width = 32, idomain="sbus", odomain="sys") + self.comb += self.sync_stat_cycle_counter.i.eq(sbus_bus.buf_stat_cycle_counter) + self.comb += self.stat_cycle_counter.status.eq(self.sync_stat_cycle_counter.o) + + self.submodules.sync_stat_slave_start_counter = BusSynchronizer(width = 32, idomain="sbus", odomain="sys"); + self.comb += self.sync_stat_slave_start_counter.i.eq(sbus_bus.buf_stat_slave_start_counter) + self.comb += self.stat_slave_start_counter.status.eq(self.sync_stat_slave_start_counter.o) + self.submodules.sync_stat_slave_done_counter = BusSynchronizer(width = 32, idomain="sbus", odomain="sys"); + self.comb += self.sync_stat_slave_done_counter.i.eq(sbus_bus.buf_stat_slave_done_counter) + self.comb += self.stat_slave_done_counter.status.eq(self.sync_stat_slave_done_counter.o) + self.submodules.sync_stat_slave_rerun_counter = BusSynchronizer(width = 32, idomain="sbus", odomain="sys"); + self.comb += self.sync_stat_slave_rerun_counter.i.eq(sbus_bus.buf_stat_slave_rerun_counter) + self.comb += self.stat_slave_rerun_counter.status.eq(self.sync_stat_slave_rerun_counter.o) + self.submodules.sync_stat_slave_early_error_counter = BusSynchronizer(width = 32, idomain="sbus", odomain="sys"); + self.comb += self.sync_stat_slave_early_error_counter.i.eq(sbus_bus.buf_stat_slave_early_error_counter) + self.comb += self.stat_slave_early_error_counter.status.eq(self.sync_stat_slave_early_error_counter.o) + self.submodules.sync_stat_master_start_counter = BusSynchronizer(width = 32, idomain="sbus", odomain="sys"); + self.comb += self.sync_stat_master_start_counter.i.eq(sbus_bus.buf_stat_master_start_counter) + self.comb += self.stat_master_start_counter.status.eq(self.sync_stat_master_start_counter.o) + self.submodules.sync_stat_master_done_counter = BusSynchronizer(width = 32, idomain="sbus", odomain="sys"); + self.comb += self.sync_stat_master_done_counter.i.eq(sbus_bus.buf_stat_master_done_counter) + self.comb += self.stat_master_done_counter.status.eq(self.sync_stat_master_done_counter.o) + self.submodules.sync_stat_master_error_counter = BusSynchronizer(width = 32, idomain="sbus", odomain="sys"); + self.comb += self.sync_stat_master_error_counter.i.eq(sbus_bus.buf_stat_master_error_counter) + self.comb += self.stat_master_error_counter.status.eq(self.sync_stat_master_error_counter.o) + self.submodules.sync_stat_master_rerun_counter = BusSynchronizer(width = 32, idomain="sbus", odomain="sys"); + self.comb += self.sync_stat_master_rerun_counter.i.eq(sbus_bus.buf_stat_master_rerun_counter) + self.comb += self.stat_master_rerun_counter.status.eq(self.sync_stat_master_rerun_counter.o) + self.submodules.sync_sbus_master_error_virtual = BusSynchronizer(width = 32, idomain="sbus", odomain="sys"); + self.comb += self.sync_sbus_master_error_virtual.i.eq(sbus_bus.buf_sbus_master_error_virtual) + self.comb += self.sbus_master_error_virtual.status.eq(self.sync_sbus_master_error_virtual.o) diff --git a/sbus-to-ztex-gateware-migen/sbus_to_fpga_soc.py b/sbus-to-ztex-gateware-migen/sbus_to_fpga_soc.py index 777ae4d..ab48314 100644 --- a/sbus-to-ztex-gateware-migen/sbus_to_fpga_soc.py +++ b/sbus-to-ztex-gateware-migen/sbus_to_fpga_soc.py @@ -43,7 +43,7 @@ class _CRG(Module): # self.clock_domains.cd_por = ClockDomain() # 48 MHz native, reset'ed by SBus, power-on-reset timer self.clock_domains.cd_usb = ClockDomain() # 48 MHZ PLL, reset'ed by SBus (via pll), for USB controller self.clock_domains.cd_clk50 = ClockDomain() # 50 MHz (gated) for curve25519engine -> eng_clk - self.clock_domains.cd_clk100 = ClockDomain() # 100 MHz for curve25519engine -> sys_clk + #self.clock_domains.cd_clk100 = ClockDomain() # 100 MHz for curve25519engine -> sys_clk self.clock_domains.cd_clk100_gated = ClockDomain() # 100 MHz (gated) for curve25519engine -> mul_clk self.clock_domains.cd_clk200 = ClockDomain() # 200 MHz (gated) for curve25519engine -> rf_clk @@ -67,11 +67,13 @@ class _CRG(Module): self.comb += self.cd_sbus.rst.eq(~rst_sbus) ##self.cd_sys.clk = clk_sbus ##self.comb += self.cd_sys.rst.eq(~rst_sbus) + + self.curve25519_on = Signal() self.submodules.pll = pll = S7MMCM(speedgrade=-1) #pll.register_clkin(clk48, 48e6) pll.register_clkin(self.clk48_bufg, 48e6) - pll.create_clkout(self.cd_sys, sys_clk_freq) + pll.create_clkout(self.cd_sys, sys_clk_freq, gated_replicas={self.cd_clk100_gated : pll.locked & self.curve25519_on}) platform.add_platform_command("create_generated_clock -name sysclk [get_pins {{MMCME2_ADV/CLKOUT0}}]") pll.create_clkout(self.cd_sys4x, 4*sys_clk_freq) platform.add_platform_command("create_generated_clock -name sys4xclk [get_pins {{MMCME2_ADV/CLKOUT1}}]") @@ -84,25 +86,30 @@ class _CRG(Module): #platform.add_false_path_constraints(self.cd_sbus.clk, self.cd_sys.clk) ##platform.add_false_path_constraints(self.cd_native.clk, self.cd_sys.clk) - self.submodules.curve25519_pll = curve25519_pll = S7MMCM(speedgrade=-1) - curve25519_clk_freq = 90e6 - self.curve25519_on = Signal() - #curve25519_pll.register_clkin(clk48, 48e6) - curve25519_pll.register_clkin(self.clk48_bufg, 48e6) - curve25519_pll.create_clkout(self.cd_clk50, curve25519_clk_freq/2, margin=0, ce=curve25519_pll.locked & self.curve25519_on) - platform.add_platform_command("create_generated_clock -name clk50 [get_pins {{MMCME2_ADV_1/CLKOUT0}}]") - curve25519_pll.create_clkout(self.cd_clk100, curve25519_clk_freq, margin=0, ce=curve25519_pll.locked, - gated_replicas={self.cd_clk100_gated : curve25519_pll.locked & self.curve25519_on}) - platform.add_platform_command("create_generated_clock -name clk100 [get_pins {{MMCME2_ADV_1/CLKOUT1}}]") - curve25519_pll.create_clkout(self.cd_clk200, curve25519_clk_freq*2, margin=0, ce=curve25519_pll.locked & self.curve25519_on) - platform.add_platform_command("create_generated_clock -name clk200 [get_pins {{MMCME2_ADV_1/CLKOUT2}}]") - #self.comb += curve25519_pll.reset.eq(~rst_sbus) # | ~por_done - platform.add_false_path_constraints(self.cd_sys.clk, self.cd_clk50.clk) - platform.add_false_path_constraints(self.cd_sys.clk, self.cd_clk100.clk) - platform.add_false_path_constraints(self.cd_sys.clk, self.cd_clk200.clk) - platform.add_false_path_constraints(self.cd_clk50.clk, self.cd_sys.clk) - platform.add_false_path_constraints(self.cd_clk100.clk, self.cd_sys.clk) - platform.add_false_path_constraints(self.cd_clk200.clk, self.cd_sys.clk) + pll.create_clkout(self.cd_clk50, sys_clk_freq/2, ce=pll.locked & self.curve25519_on) + platform.add_platform_command("create_generated_clock -name clk50 [get_pins {{MMCME2_ADV/CLKOUT3}}]") + pll.create_clkout(self.cd_clk200, sys_clk_freq*2, ce=pll.locked & self.curve25519_on) + platform.add_platform_command("create_generated_clock -name clk200 [get_pins {{MMCME2_ADV/CLKOUT4}}]") + + #self.submodules.curve25519_pll = curve25519_pll = S7MMCM(speedgrade=-1) + #curve25519_clk_freq = 90e6 + ##self.curve25519_on = Signal() + ##curve25519_pll.register_clkin(clk48, 48e6) + #curve25519_pll.register_clkin(self.clk48_bufg, 48e6) + #curve25519_pll.create_clkout(self.cd_clk50, curve25519_clk_freq/2, margin=0, ce=curve25519_pll.locked & self.curve25519_on) + #platform.add_platform_command("create_generated_clock -name clk50 [get_pins {{MMCME2_ADV_1/CLKOUT0}}]") + #curve25519_pll.create_clkout(self.cd_clk100, curve25519_clk_freq, margin=0, ce=curve25519_pll.locked, + # gated_replicas={self.cd_clk100_gated : curve25519_pll.locked & self.curve25519_on}) + #platform.add_platform_command("create_generated_clock -name clk100 [get_pins {{MMCME2_ADV_1/CLKOUT1}}]") + #curve25519_pll.create_clkout(self.cd_clk200, curve25519_clk_freq*2, margin=0, ce=curve25519_pll.locked & self.curve25519_on) + #platform.add_platform_command("create_generated_clock -name clk200 [get_pins {{MMCME2_ADV_1/CLKOUT2}}]") + ##self.comb += curve25519_pll.reset.eq(~rst_sbus) # | ~por_done + #platform.add_false_path_constraints(self.cd_sys.clk, self.cd_clk50.clk) + #platform.add_false_path_constraints(self.cd_sys.clk, self.cd_clk100.clk) + #platform.add_false_path_constraints(self.cd_sys.clk, self.cd_clk200.clk) + #platform.add_false_path_constraints(self.cd_clk50.clk, self.cd_sys.clk) + #platform.add_false_path_constraints(self.cd_clk100.clk, self.cd_sys.clk) + #platform.add_false_path_constraints(self.cd_clk200.clk, self.cd_sys.clk) # Power on reset, reset propagate from SBus to SYS # por_count = Signal(16, reset=2**16-1) @@ -283,14 +290,15 @@ class SBusFPGA(SoCCore): # beware the naming, as 'clk50' 'sysclk' 'clk200' are used in the original platform constraints # the local engine.py was slightly modified to have configurable names, so we can have 'clk50', 'clk100', 'clk200' # Beware that Engine implicitely runs in 'sys' by default, need to rename that one as well - self.submodules.curve25519engine = ClockDomainsRenamer({"eng_clk":"clk50", "rf_clk":"clk200", "mul_clk":"clk100_gated", "sys":"clk100"})(Engine(platform=platform,prefix=self.mem_map.get("curve25519engine", None))) - self.submodules.curve25519engine_wishbone_cdc = wishbone.WishboneDomainCrossingMaster(platform=self.platform, slave=self.curve25519engine.bus, cd_master="sys", cd_slave="clk100") - self.bus.add_slave("curve25519engine", self.curve25519engine_wishbone_cdc, SoCRegion(origin=self.mem_map.get("curve25519engine", None), size=0x20000, cached=False)) - #self.bus.add_slave("curve25519engine", self.curve25519engine.bus, SoCRegion(origin=self.mem_map.get("curve25519engine", None), size=0x20000, cached=False)) - self.submodules.curve25519_on_sync = BusSynchronizer(width = 1, idomain = "clk100", odomain = "sys") - self.comb += self.curve25519_on_sync.i.eq(self.curve25519engine.power.fields.on) - self.comb += self.crg.curve25519_on.eq(self.curve25519_on_sync.o) - + self.submodules.curve25519engine = ClockDomainsRenamer({"eng_clk":"clk50", "rf_clk":"clk200", "mul_clk":"clk100_gated"})(Engine(platform=platform,prefix=self.mem_map.get("curve25519engine", None))) # , "sys":"clk100" + #self.submodules.curve25519engine_wishbone_cdc = wishbone.WishboneDomainCrossingMaster(platform=self.platform, slave=self.curve25519engine.bus, cd_master="sys", cd_slave="clk100") + #self.bus.add_slave("curve25519engine", self.curve25519engine_wishbone_cdc, SoCRegion(origin=self.mem_map.get("curve25519engine", None), size=0x20000, cached=False)) + self.bus.add_slave("curve25519engine", self.curve25519engine.bus, SoCRegion(origin=self.mem_map.get("curve25519engine", None), size=0x20000, cached=False)) + #self.submodules.curve25519_on_sync = BusSynchronizer(width = 1, idomain = "clk100", odomain = "sys") + #self.comb += self.curve25519_on_sync.i.eq(self.curve25519engine.power.fields.on) + #self.comb += self.crg.curve25519_on.eq(self.curve25519_on_sync.o) + self.comb += self.crg.curve25519_on.eq(self.curve25519engine.power.fields.on) + def main(): parser = argparse.ArgumentParser(description="SbusFPGA") parser.add_argument("--build", action="store_true", help="Build bitstream")