From a7e05afe1ccca74e6c98ac8d1d4fca9df85e1788 Mon Sep 17 00:00:00 2001 From: Romain Dolbeau Date: Sun, 13 Jun 2021 04:07:04 -0400 Subject: [PATCH] PoC for Migen version of the SBus slave FSM; is recognized by PROM --- sbus-to-ztex-gateware-migen/sbus-to-fpga.py | 127 +++++++++ .../sbus_to_fpga_slave.py | 265 ++++++++++++++++++ 2 files changed, 392 insertions(+) create mode 100644 sbus-to-ztex-gateware-migen/sbus-to-fpga.py create mode 100644 sbus-to-ztex-gateware-migen/sbus_to_fpga_slave.py diff --git a/sbus-to-ztex-gateware-migen/sbus-to-fpga.py b/sbus-to-ztex-gateware-migen/sbus-to-fpga.py new file mode 100644 index 0000000..3fdc22b --- /dev/null +++ b/sbus-to-ztex-gateware-migen/sbus-to-fpga.py @@ -0,0 +1,127 @@ +import os +import argparse +from migen import * +import litex +from litex.build.generic_platform import * +from litex.build.xilinx.vivado import vivado_build_args, vivado_build_argdict +from litex.soc.integration.soc import * +from litex.soc.integration.soc_core import * +from litex.soc.integration.builder import * +from litex.soc.cores.clock import * +from litex_boards.platforms import ztex213 + +from sbus_to_fpga_slave import *; + +_sbus_sbus = [ + ("SBUS_3V3_CLK", 0, Pins("D15"), IOStandard("lvttl")), + ("SBUS_3V3_ASs", 0, Pins("T4"), IOStandard("lvttl")), + ("SBUS_3V3_BGs", 0, Pins("T6"), IOStandard("lvttl")), + ("SBUS_3V3_BRs", 0, Pins("R6"), IOStandard("lvttl")), + ("SBUS_3V3_ERRs", 0, Pins("V2"), IOStandard("lvttl")), + ("SBUS_DATA_OE_LED", 0, Pins("U1"), IOStandard("lvttl")), + ("SBUS_DATA_OE_LED_2", 0, Pins("T3"), IOStandard("lvttl")), + ("SBUS_3V3_RSTs", 0, Pins("U2"), IOStandard("lvttl")), + ("SBUS_3V3_SELs", 0, Pins("K6"), IOStandard("lvttl")), + ("SBUS_3V3_INT1s", 0, Pins("R3"), IOStandard("lvttl")), + ("SBUS_3V3_INT7s", 0, Pins("N5"), IOStandard("lvttl")), + ("SBUS_3V3_PPRD", 0, Pins("N6"), IOStandard("lvttl")), + ("SBUS_OE", 0, Pins("P5"), IOStandard("lvttl")), + ("SBUS_3V3_ACKs", 0, Pins("M6 L6 N4"), IOStandard("lvttl")), + ("SBUS_3V3_SIZ", 0, Pins("R7 U3 V1"), IOStandard("lvttl")), + ("SBUS_3V3_D", 0, Pins("J18 K16 J17 K15 K13 J15 J13 J14 H14 H17 G14 G17 G16 G18 H16 F18 F16 E18 F15 D18 E17 G13 D17 F13 F14 E16 E15 C17 C16 A18 B18 C15"), IOStandard("lvttl")), + ("SBUS_3V3_PA", 0, Pins(" B16 B17 D14 C14 D12 A16 A15 B14 B13 B12 C12 A14 A13 B11 A11 M4 R2 M3 P2 M2 N2 K5 N1 L4 M1 L3 L1 K3"), IOStandard("lvttl")), +] +# CRG ---------------------------------------------------------------------------------------------- + +class _CRG(Module): + def __init__(self, platform, sys_clk_freq): + self.clock_domains.cd_sys = ClockDomain() + self.clock_domains.cd_native = ClockDomain(reset_less=True) + self.clock_domains.cd_sbus = ClockDomain() + self.clock_domains.cd_por = ClockDomain() + + # # # + clk48 = platform.request("clk48") + clk_sbus = platform.request("SBUS_3V3_CLK") + + self.submodules.pll = pll = S7MMCM(speedgrade=-1) + pll.register_clkin(clk48, 48e6) + pll.create_clkout(self.cd_sys, sys_clk_freq) + + self.comb += self.cd_sbus.clk.eq(clk_sbus) + self.comb += self.cd_sbus.rst.eq(~platform.request("SBUS_3V3_RSTs")) + + self.comb += self.cd_native.clk.eq(clk48) + + platform.add_false_path_constraints(self.cd_native.clk, self.cd_sbus.clk) + + # FIXME: add SBUS_3V3_RSTs + + # Power on reset, 20 seconds + por_count = Signal(30, reset=20*48*1000000) + por_done = Signal() + self.comb += self.cd_por.clk.eq(clk48) + self.comb += por_done.eq(por_count == 0) + self.sync.por += If(~por_done, por_count.eq(por_count - 1)) + self.comb += pll.reset.eq(~por_done) + +class SBusFPGA(SoCCore): + def __init__(self, **kwargs): + + kwargs["cpu_type"] = "None" + kwargs["integrated_sram_size"] = 0 + kwargs["with_uart"] = True + kwargs["with_timer"] = False + + self.sys_clk_freq = sys_clk_freq = 100e6 + + self.platform = platform = ztex213.Platform(variant="ztex2.13a", expansion="sbus") + self.platform.add_extension(_sbus_sbus) + SoCCore.__init__(self, platform=platform, sys_clk_freq=sys_clk_freq, clk_freq=sys_clk_freq, **kwargs) + self.submodules.crg = _CRG(platform=platform, sys_clk_freq=sys_clk_freq) + self.platform.add_period_constraint(self.platform.lookup_request("SBUS_3V3_CLK", loose=True), 1e9/25e6) + + prom_file = "prom_mini.fc" + prom_data = soc_core.get_mem_data(prom_file, "big") + prom = Array(prom_data) + #print("\n****************************************\n") + #for i in range(len(prom)): + # print(hex(prom[i])) + #print("\n****************************************\n") + #self.add_ram("prom", origin=0x0, size=2**14, contents=prom_data, mode="r") + #getattr(self,"prom").mem.init = prom_data + #getattr(self,"prom").mem.depth = 2**14 + + hold_reset_ctr = Signal(30, reset=960000000) + self.sync.native += If(hold_reset_ctr>0, hold_reset_ctr.eq(hold_reset_ctr - 1)) + hold_reset = Signal(reset=1) + self.comb += hold_reset.eq(~(hold_reset_ctr == 0)) + self.submodules.slave = ClockDomainsRenamer("sbus")(SBusFPGASlave(platform=self.platform, soc=self, prom=prom, hold_reset=hold_reset)) + + # self.soc = Module() + # self.soc.mem_regions = self.mem_regions = {} + # region = litex.soc.integration.soc.SoCRegion(origin=0x0, size=0x0) + # region.length = 0 + # self.mem_regions['csr'] = region + # self.soc.constants = self.constants = {} + # self.soc.csr_regions = self.csr_regions = {} + # self.soc.cpu_type = self.cpu_type = None + +# def do_finalize(self): +# self.platform.add_period_constraint(self.platform.lookup_request("SBUS_3V3_CLK", loose=True), 1e9/25e6) + +def main(): + parser = argparse.ArgumentParser(description="SbusFPGA") + parser.add_argument("--build", action="store_true", help="Build bitstream") + builder_args(parser) + vivado_build_args(parser) + args = parser.parse_args() + + soc = SBusFPGA(**soc_core_argdict(args)) + #soc.add_uart(name="uart", baudrate=115200, fifo_depth=16) + + builder = Builder(soc, **builder_argdict(args)) + builder.build(**vivado_build_argdict(args), run=args.build) + +if __name__ == "__main__": + main() diff --git a/sbus-to-ztex-gateware-migen/sbus_to_fpga_slave.py b/sbus-to-ztex-gateware-migen/sbus_to_fpga_slave.py new file mode 100644 index 0000000..5cd19ad --- /dev/null +++ b/sbus-to-ztex-gateware-migen/sbus_to_fpga_slave.py @@ -0,0 +1,265 @@ + +from migen import * +from migen.genlib.fifo import SyncFIFOBuffered +from migen.fhdl.specials import Tristate + +SIZ_WORD = 0x0 +SIZ_BYTE = 0x1 +SIZ_HWORD = 0x2 +SIZ_EXT = 0x3 +SIZ_BURST4 = 0x4 +SIZ_BURST8 = 0x5 +SIZ_BURST16 = 0x6 +SIZ_BURST2 = 0x7 + +ACK_IDLE = 0x7 +ACK_ERR = 0x6 +ACK_BYTE = 0x5 +ACK_RERUN = 0x4 +ACK_WORD = 0x3 +ACK_DWORD = 0x2 +ACK_HWORD = 0x1 +ACK_RECV = 0x0 + +def siz_is_word(siz): + return (SIZ_WORD == siz) or (SIZ_BURST2 == siz) or (SIZ_BURST4 == siz) or (SIZ_BURST8 == siz) or (SIZ_BURST16 == siz) + +def index_with_wrap(counter, limit_m1, value): + if (limit_m1 == 0): + return value[0:4] + elif (limit_m1 == 1): + return Cat((value + counter)[0:1], value[1:4]) + elif (limit_m1 == 3): + return Cat((value + counter)[0:2], value[2:4]) + elif (limit_m1 == 7): + return Cat((value + counter)[0:3], value[3:4]) + elif (limit_m1 == 15): + return (value + counter)[0:4] + return value[0:4] + +def siz_to_burst_size_m1(siz): + if (SIZ_WORD == siz): + return 0 + elif (SIZ_BURST2 == siz): + return 1 + elif (SIZ_BURST4 == siz): + return 3 + elif (SIZ_BURST8 == siz): + return 7 + elif (SIZ_BURST16 == siz): + return 15 + return 1 + +# siz_to_burst_size_m1 = { +# SIZ_WORD: 0, +# SIZ_BURST2: 1, +# SIZ_BURST4: 3, +# SIZ_BURST8: 7, +# SIZ_BURST16: 15 +# }; + +class SBusFPGASlave(Module): + def __init__(self, platform, soc, prom, hold_reset): + + self.hold_reset = hold_reset + + #pad_SBUS_3V3_CLK = platform.request("SBUS_3V3_CLK") + pad_SBUS_3V3_ASs = platform.request("SBUS_3V3_ASs") + pad_SBUS_3V3_BGs = platform.request("SBUS_3V3_BGs") + pad_SBUS_3V3_BRs = platform.request("SBUS_3V3_BRs") + pad_SBUS_3V3_ERRs = platform.request("SBUS_3V3_ERRs") + pad_SBUS_DATA_OE_LED = platform.request("SBUS_DATA_OE_LED") + pad_SBUS_DATA_OE_LED_2 = platform.request("SBUS_DATA_OE_LED_2") + #pad_SBUS_3V3_RSTs = platform.request("SBUS_3V3_RSTs") + pad_SBUS_3V3_SELs = platform.request("SBUS_3V3_SELs") + pad_SBUS_3V3_INT1s = platform.request("SBUS_3V3_INT1s") + pad_SBUS_3V3_INT7s = platform.request("SBUS_3V3_INT7s") + pad_SBUS_3V3_PPRD = platform.request("SBUS_3V3_PPRD") + pad_SBUS_OE = platform.request("SBUS_OE") + pad_SBUS_3V3_ACKs = platform.request("SBUS_3V3_ACKs") + pad_SBUS_3V3_SIZ = platform.request("SBUS_3V3_SIZ") + pad_SBUS_3V3_D = platform.request("SBUS_3V3_D") + pad_SBUS_3V3_PA = platform.request("SBUS_3V3_PA") + + leds = Signal(8, reset=0xF0) + self.comb += platform.request("user_led", 0).eq(leds[0]) + self.comb += platform.request("user_led", 1).eq(leds[1]) + self.comb += platform.request("user_led", 2).eq(leds[2]) + self.comb += platform.request("user_led", 3).eq(leds[3]) + self.comb += platform.request("user_led", 4).eq(leds[4]) + self.comb += platform.request("user_led", 5).eq(leds[5]) + self.comb += platform.request("user_led", 6).eq(leds[6]) + self.comb += platform.request("user_led", 7).eq(leds[7]) + + sbus_oe_data = Signal(reset=0) + sbus_oe_slave_in = Signal(reset=0) + sbus_oe_master_in = Signal(reset=0) + sbus_oe_int1 = Signal(reset=0) + sbus_oe_int7 = Signal(reset=0) + sbus_oe_master_br = Signal(reset=0) + + sbus_last_pa = Signal(28) + burst_index = Signal(4) + burst_counter = Signal(4) + burst_limit_m1 = Signal(4) + + #SBUS_3V3_CLK = Signal() + SBUS_3V3_ASs_i = Signal() + self.comb += SBUS_3V3_ASs_i.eq(pad_SBUS_3V3_ASs) + SBUS_3V3_BGs_i = Signal() + self.comb += SBUS_3V3_BGs_i.eq(pad_SBUS_3V3_BGs) + SBUS_3V3_BRs_o = Signal(reset=1) + self.specials += Tristate(pad_SBUS_3V3_BRs, SBUS_3V3_BRs_o, sbus_oe_master_br, None) + SBUS_3V3_ERRs_i = Signal() + SBUS_3V3_ERRs_o = Signal() + self.specials += Tristate(pad_SBUS_3V3_ERRs, SBUS_3V3_ERRs_o, sbus_oe_master_in, SBUS_3V3_ERRs_i) + SBUS_DATA_OE_LED_o = Signal() + self.comb += pad_SBUS_DATA_OE_LED.eq(SBUS_DATA_OE_LED_o) + SBUS_DATA_OE_LED_2_o = Signal() + self.comb += pad_SBUS_DATA_OE_LED_2.eq(SBUS_DATA_OE_LED_2_o) + #SBUS_3V3_RSTs = Signal() + SBUS_3V3_SELs_i = Signal() + self.comb += SBUS_3V3_SELs_i.eq(pad_SBUS_3V3_SELs) + SBUS_3V3_INT1s_o = Signal(reset=1) + self.specials += Tristate(pad_SBUS_3V3_INT1s, SBUS_3V3_INT1s_o, sbus_oe_int1, None) + SBUS_3V3_INT7s_o = Signal(reset=1) + self.specials += Tristate(pad_SBUS_3V3_INT7s, SBUS_3V3_INT7s_o, sbus_oe_int7, None) + SBUS_3V3_PPRD_i = Signal() + SBUS_3V3_PPRD_o = Signal() + self.specials += Tristate(pad_SBUS_3V3_PPRD, SBUS_3V3_PPRD_o, sbus_oe_slave_in, SBUS_3V3_PPRD_i) + #SBUS_OE_o = Signal() + self.comb += pad_SBUS_OE.eq(self.hold_reset) + SBUS_3V3_ACKs_i = Signal(3) + SBUS_3V3_ACKs_o = Signal(3) + self.specials += Tristate(pad_SBUS_3V3_ACKs, SBUS_3V3_ACKs_o, sbus_oe_master_in, SBUS_3V3_ACKs_i) + SBUS_3V3_SIZ_i = Signal(3) + SBUS_3V3_SIZ_o = Signal(3) + self.specials += Tristate(pad_SBUS_3V3_SIZ, SBUS_3V3_SIZ_o, sbus_oe_slave_in, SBUS_3V3_SIZ_i) + SBUS_3V3_D_i = Signal(32) + SBUS_3V3_D_o = Signal(32) + self.specials += Tristate(pad_SBUS_3V3_D, SBUS_3V3_D_o, sbus_oe_data, SBUS_3V3_D_i) + SBUS_3V3_PA_i = Signal(28) + self.comb += SBUS_3V3_PA_i.eq(pad_SBUS_3V3_PA) + + self.submodules.slave_fsm = slave_fsm = FSM(reset_state="Reset") + + p_data = Signal(32) # prom data + + slave_fsm.act("Reset", + NextValue(SBUS_DATA_OE_LED_o, 0), + NextValue(SBUS_DATA_OE_LED_2_o, 0), + NextValue(sbus_oe_int1, 0), + NextValue(sbus_oe_int7, 0), + NextValue(sbus_oe_data, 0), + NextValue(sbus_oe_slave_in, 0), + NextValue(sbus_oe_master_in, 0), + NextValue(sbus_oe_master_br, 0), + NextValue(p_data, 0), + NextValue(leds, 0x0F), + NextState("Start") + ) + slave_fsm.act("Start", + NextValue(SBUS_DATA_OE_LED_o, 0), + NextValue(SBUS_DATA_OE_LED_2_o, 0), + NextValue(sbus_oe_int1, 0), + NextValue(sbus_oe_int7, 0), + NextValue(sbus_oe_data, 0), + NextValue(sbus_oe_slave_in, 0), + NextValue(sbus_oe_master_in, 0), + NextValue(sbus_oe_master_br, 0), + NextValue(p_data, 0), + NextValue(leds, 0x01), + If((self.hold_reset == 0), NextState("Idle")) + ) + slave_fsm.act("Idle", + #NextValue(leds, 0x11), + If(((SBUS_3V3_SELs_i == 0) and + (SBUS_3V3_ASs_i == 0) and + (siz_is_word(SBUS_3V3_SIZ_i)) and + (SBUS_3V3_PPRD_i == 1)), + NextValue(SBUS_DATA_OE_LED_o, 1), + NextValue(sbus_oe_master_in, 1), + NextValue(sbus_last_pa, SBUS_3V3_PA_i), + NextValue(burst_counter, 0), + NextValue(burst_limit_m1, siz_to_burst_size_m1(SBUS_3V3_SIZ_i)), + If((SBUS_3V3_PA_i[16:28] == 0x000), + NextValue(SBUS_3V3_ACKs_o, ACK_WORD), + NextValue(SBUS_3V3_ERRs_o, 1), + NextValue(p_data, prom[SBUS_3V3_PA_i[2:16]]), + NextState("Slave_Ack_Read_Prom_Burst") + ).Else( + NextValue(SBUS_3V3_ACKs_o, ACK_ERR), + NextValue(SBUS_3V3_ERRs_o, 1), + NextState("Slave_Error") + ) + ).Elif(((SBUS_3V3_SELs_i == 0) and + (SBUS_3V3_ASs_i == 0) and + (SIZ_BYTE == SBUS_3V3_SIZ_i) and + (SBUS_3V3_PPRD_i == 1)), + NextValue(SBUS_DATA_OE_LED_2_o, 1), + NextValue(sbus_oe_master_in, 1), + NextValue(sbus_last_pa, SBUS_3V3_PA_i), + If((SBUS_3V3_PA_i[16:28] == 0x000), + NextValue(SBUS_3V3_ACKs_o, ACK_BYTE), + NextValue(SBUS_3V3_ERRs_o, 1), + NextValue(p_data, prom[SBUS_3V3_PA_i[2:16]]), + NextState("Slave_Ack_Read_Prom_Byte") + ).Else( + NextValue(SBUS_3V3_ACKs_o, ACK_ERR), + NextValue(SBUS_3V3_ERRs_o, 1), + NextState("Slave_Error") + ) + ) + ) + slave_fsm.act("Slave_Ack_Read_Prom_Burst", + NextValue(leds, 0x03), + NextValue(sbus_oe_data, 1), + NextValue(SBUS_3V3_D_o, p_data), + #NextValue(burst_index, index_with_wrap((burst_counter+1), burst_limit_m1, sbus_last_pa[2:6])), + NextValue(p_data, prom[Cat(index_with_wrap((burst_counter+1), burst_limit_m1, sbus_last_pa[2:6]), sbus_last_pa[6:16])]), + If((burst_counter == burst_limit_m1), + NextValue(SBUS_3V3_ACKs_o, ACK_IDLE), + NextState("Slave_Do_Read") + ).Else( + NextValue(SBUS_3V3_ACKs_o, ACK_WORD), + NextValue(burst_counter, burst_counter + 1) + ) + ) + slave_fsm.act("Slave_Ack_Read_Prom_Byte", + NextValue(leds, 0x0c), + NextValue(sbus_oe_data, 1), + If((sbus_last_pa[0:2] == 0x0), + NextValue(SBUS_3V3_D_o, Cat(C(0)[0:24], p_data[24:32])) + ).Elif((sbus_last_pa[0:2] == 0x1), + NextValue(SBUS_3V3_D_o, Cat(C(0)[0:24], p_data[16:24])) + ).Elif((sbus_last_pa[0:2] == 0x2), + NextValue(SBUS_3V3_D_o, Cat(C(0)[0:24], p_data[8:16])) + ).Elif((sbus_last_pa[0:2] == 0x3), + NextValue(SBUS_3V3_D_o, Cat(C(0)[0:24], p_data[0:8])) + ), + NextState("Slave_Do_Read") + ) + slave_fsm.act("Slave_Do_Read", + NextValue(leds, 0x30), + NextValue(sbus_oe_int1, 0), + NextValue(sbus_oe_int7, 0), + NextValue(sbus_oe_data, 0), + NextValue(sbus_oe_slave_in, 0), + NextValue(sbus_oe_master_in, 0), + NextValue(sbus_oe_master_br, 0), + If((SBUS_3V3_ASs_i == 1), + NextState("Idle") + ) + ) + slave_fsm.act("Slave_Error", + NextValue(leds, 0xc0), + NextValue(sbus_oe_int1, 0), + NextValue(sbus_oe_int7, 0), + NextValue(sbus_oe_data, 0), + NextValue(sbus_oe_slave_in, 0), + NextValue(sbus_oe_master_in, 0), + NextValue(sbus_oe_master_br, 0), + If((SBUS_3V3_ASs_i == 1), + NextState("Idle") + ) + )