From 06bff62901426d0289e0423341e23277f9ebc132 Mon Sep 17 00:00:00 2001 From: Romain Dolbeau Date: Sat, 30 Oct 2021 10:01:26 +0200 Subject: [PATCH] move the wishbone CDC locally ; speedgrade from part --- .../sbus_to_fpga_soc.py | 47 ++-- sbus-to-ztex-gateware-migen/sbus_wb.py | 53 +++++ sbus-to-ztex-gateware-migen/wb_async_reg.v | 225 ++++++++++++++++++ sbus-to-ztex-gateware-migen/ztex213_sbus.py | 3 + 4 files changed, 307 insertions(+), 21 deletions(-) create mode 100644 sbus-to-ztex-gateware-migen/sbus_wb.py create mode 100644 sbus-to-ztex-gateware-migen/wb_async_reg.v 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 d801b49..6ddd405 100644 --- a/sbus-to-ztex-gateware-migen/sbus_to_fpga_soc.py +++ b/sbus-to-ztex-gateware-migen/sbus_to_fpga_soc.py @@ -25,21 +25,24 @@ from sbus_to_fpga_trng import * from litedram.frontend.dma import * -from engine import Engine; +from engine import Engine from migen.genlib.cdc import BusSynchronizer -from migen.genlib.resetsync import AsyncResetSynchronizer; +from migen.genlib.resetsync import AsyncResetSynchronizer # betrusted-io/gateware -from gateware import i2c; +from gateware import i2c -import sbus_to_fpga_export; -import sbus_to_fpga_prom; +import sbus_to_fpga_export +import sbus_to_fpga_prom from litex.soc.cores.video import VideoVGAPHY -import cg3_fb; -import cg6_fb; -import cg6_accel; -#import cgtrois; +import cg3_fb +import cg6_fb +import cg6_accel +#import cgtrois + +# Wishbone stuff +from sbus_wb import WishboneDomainCrossingMaster # CRG ---------------------------------------------------------------------------------------------- @@ -101,7 +104,7 @@ class _CRG(Module): num_adv = 0 num_clk = 0 - self.submodules.pll = pll = S7MMCM(speedgrade=-1) + self.submodules.pll = pll = S7MMCM(speedgrade=platform.speedgrade) #pll.register_clkin(clk48, 48e6) pll.register_clkin(self.clk48_bufg, 48e6) pll.create_clkout(self.cd_sys, sys_clk_freq, gated_replicas={self.cd_clk100_gated : pll.locked & self.curve25519_on}) @@ -131,7 +134,7 @@ class _CRG(Module): num_adv = num_adv + 1 num_clk = 0 - #self.submodules.curve25519_pll = curve25519_pll = S7MMCM(speedgrade=-1) + #self.submodules.curve25519_pll = curve25519_pll = S7MMCM(speedgrade=platform.speedgrade) #curve25519_clk_freq = 90e6 ##self.curve25519_on = Signal() ##curve25519_pll.register_clkin(clk48, 48e6) @@ -162,7 +165,7 @@ class _CRG(Module): # USB if (usb): - self.submodules.usb_pll = usb_pll = S7MMCM(speedgrade=-1) + self.submodules.usb_pll = usb_pll = S7MMCM(speedgrade=platform.speedgrade) #usb_pll.register_clkin(clk48, 48e6) usb_pll.register_clkin(self.clk48_bufg, 48e6) usb_pll.create_clkout(self.cd_usb, usb_clk_freq, margin = 0) @@ -174,7 +177,7 @@ class _CRG(Module): num_clk = 0 if (sdram): - self.submodules.pll_idelay = pll_idelay = S7MMCM(speedgrade=-1) + self.submodules.pll_idelay = pll_idelay = S7MMCM(speedgrade=platform.speedgrade) #pll_idelay.register_clkin(clk48, 48e6) pll_idelay.register_clkin(self.clk48_bufg, 48e6) pll_idelay.create_clkout(self.cd_idelay, 200e6, margin = 0) @@ -186,7 +189,7 @@ class _CRG(Module): num_clk = 0 if (cg3): - self.submodules.video_pll = video_pll = S7MMCM(speedgrade=-1) + self.submodules.video_pll = video_pll = S7MMCM(speedgrade=platform.speedgrade) video_pll.register_clkin(self.clk48_bufg, 48e6) video_pll.create_clkout(self.cd_vga, pix_clk, margin = 0.0005) platform.add_platform_command("create_generated_clock -name vga_clk [get_pins {{{{MMCME2_ADV_{}/CLKOUT{}}}}}]".format(num_adv, num_clk)) @@ -211,7 +214,7 @@ class SBusFPGA(SoCCore): #if self.irq.enabled: #self.irq.add(name, use_loc_if_exists=True) - def __init__(self, version, sys_clk_freq, usb, sdram, engine, i2c, cg3, cg6, cg3_res, **kwargs): + def __init__(self, variant, version, sys_clk_freq, usb, sdram, engine, i2c, cg3, cg6, cg3_res, **kwargs): print(f"Building SBusFPGA for board version {version}") kwargs["cpu_type"] = "None" @@ -221,7 +224,7 @@ class SBusFPGA(SoCCore): self.sys_clk_freq = sys_clk_freq - self.platform = platform = ztex213_sbus.Platform(variant="ztex2.13a", version = version) + self.platform = platform = ztex213_sbus.Platform(variant = variant, version = version) if ((cg3 or cg6) and (version == "V1.2")): platform.add_extension(ztex213_sbus._vga_pmod_io_v1_2) @@ -365,8 +368,8 @@ class SBusFPGA(SoCCore): # we need to cross clock domains wishbone_slave_sbus = wishbone.Interface(data_width=self.bus.data_width) wishbone_master_sys = wishbone.Interface(data_width=self.bus.data_width) - self.submodules.wishbone_master_sbus = wishbone.WishboneDomainCrossingMaster(platform=self.platform, slave=wishbone_master_sys, cd_master="sbus", cd_slave="sys") - self.submodules.wishbone_slave_sys = wishbone.WishboneDomainCrossingMaster(platform=self.platform, slave=wishbone_slave_sbus, cd_master="sys", cd_slave="sbus") + self.submodules.wishbone_master_sbus = WishboneDomainCrossingMaster(platform=self.platform, slave=wishbone_master_sys, cd_master="sbus", cd_slave="sys") + self.submodules.wishbone_slave_sys = WishboneDomainCrossingMaster(platform=self.platform, slave=wishbone_slave_sbus, cd_master="sys", cd_slave="sbus") # SPARCstation 20 slave interface to the main memory are limited to 32-bytes burst (32-bits wide, 8 word long) # burst_size=16 should work on Ultra systems, but then they probably should go for 64-bits ET as well... @@ -411,7 +414,7 @@ class SBusFPGA(SoCCore): cg3_base=(self.wb_mem_map["main_ram"] + avail_sdram)) #self.submodules.sbus_bus = _sbus_bus self.submodules.sbus_bus = ClockDomainsRenamer("sbus")(_sbus_bus) - self.submodules.sbus_bus_stat = SBusFPGABusStat(sbus_bus = self.sbus_bus) + self.submodules.sbus_bus_stat = SBusFPGABusStat(soc = self, sbus_bus = self.sbus_bus) self.bus.add_master(name="SBusBridgeToWishbone", master=wishbone_master_sys) @@ -430,7 +433,7 @@ class SBusFPGA(SoCCore): # Actually renaming 'sys' doesn't work - unless we can CDC the CSRs as well if (engine): 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.submodules.curve25519engine_wishbone_cdc = 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.bus.add_master(name="curve25519engineLS", master=self.curve25519engine.busls) @@ -481,7 +484,8 @@ class SBusFPGA(SoCCore): def main(): parser = argparse.ArgumentParser(description="SbusFPGA") parser.add_argument("--build", action="store_true", help="Build bitstream") - parser.add_argument("--version", default="V1.0", help="SBusFPGA board version (default V1.0)") + parser.add_argument("--variant", default="ztex2.13a", help="ZTex board variant (default ztex2.13a)") + parser.add_argument("--version", default="V1.2", help="SBusFPGA board version (default V1.2)") parser.add_argument("--sys-clk-freq", default=100e6, help="SBusFPGA system clock (default 100e6 = 100 MHz)") parser.add_argument("--sdram", action="store_true", help="add a SDRAM controller (mandatory) [all]") parser.add_argument("--usb", action="store_true", help="add a USB OHCI controller [V1.2]") @@ -509,6 +513,7 @@ def main(): assert(False) soc = SBusFPGA(**soc_core_argdict(args), + variant=args.variant, version=args.version, sys_clk_freq=int(float(args.sys_clk_freq)), sdram=args.sdram, diff --git a/sbus-to-ztex-gateware-migen/sbus_wb.py b/sbus-to-ztex-gateware-migen/sbus_wb.py new file mode 100644 index 0000000..ab3bb20 --- /dev/null +++ b/sbus-to-ztex-gateware-migen/sbus_wb.py @@ -0,0 +1,53 @@ +from migen import * +from migen.genlib.fifo import * + +import litex +from litex.soc.interconnect import wishbone + +from migen.genlib.cdc import BusSynchronizer + +class WishboneDomainCrossingMaster(Module, wishbone.Interface): + """Wishbone Clock Domain Crossing [Master]""" + def __init__(self, platform, slave, cd_master="sys", cd_slave="sys"): + # Same Clock Domain, direct connection. + wishbone.Interface.__init__(self, data_width=slave.data_width, adr_width=slave.adr_width) + if cd_master == cd_slave: + raise NameError("Don't use domain crossing for the same domains.") + # Clock Domain Crossing. + else: + self.add_sources(platform) + + #fixme: parameters + self.specials += Instance(self.get_netlist_name(), + # master side + i_wbm_clk = ClockSignal(cd_master), + i_wbm_rst = ResetSignal(cd_master), + i_wbm_adr_i = self.adr, + i_wbm_dat_i = self.dat_w, + o_wbm_dat_o = self.dat_r, + i_wbm_we_i = self.we, + i_wbm_sel_i = self.sel, + i_wbm_stb_i = self.stb, + o_wbm_ack_o = self.ack, + o_wbm_err_o = self.err, + o_wbm_rty_o = Signal(), + i_wbm_cyc_i = self.cyc, + # slave side + i_wbs_clk = ClockSignal(cd_slave), + i_wbs_rst = ResetSignal(cd_slave), + o_wbs_adr_o = slave.adr, + o_wbs_dat_o = slave.dat_w, + i_wbs_dat_i = slave.dat_r, + o_wbs_we_o = slave.we, + o_wbs_sel_o = slave.sel, + o_wbs_stb_o = slave.stb, + i_wbs_ack_i = slave.ack, + i_wbs_err_i = slave.err, + i_wbs_rty_i = Signal(), + o_wbs_cyc_o = slave.cyc) + + def get_netlist_name(self): + return "wb_async_reg" + + def add_sources(self, platform): + platform.add_source("/home/dolbeau/SBusFPGA/sbus-to-ztex-gateware-migen/wb_async_reg.v", "verilog") diff --git a/sbus-to-ztex-gateware-migen/wb_async_reg.v b/sbus-to-ztex-gateware-migen/wb_async_reg.v new file mode 100644 index 0000000..8a888b6 --- /dev/null +++ b/sbus-to-ztex-gateware-migen/wb_async_reg.v @@ -0,0 +1,225 @@ +/* + +Copyright (c) 2015-2016 Alex Forencich + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +// Language: Verilog 2001 + +`timescale 1ns / 1ps + +/* + * Wishbone register + */ +module wb_async_reg # +( + parameter DATA_WIDTH = 32, // width of data bus in bits (8, 16, 32, or 64) + parameter ADDR_WIDTH = 30, // width of address bus in bits + parameter SELECT_WIDTH = (DATA_WIDTH/8) // width of word select bus (1, 2, 4, or 8) +) +( + // master side + input wire wbm_clk, + input wire wbm_rst, + input wire [ADDR_WIDTH-1:0] wbm_adr_i, // ADR_I() address + input wire [DATA_WIDTH-1:0] wbm_dat_i, // DAT_I() data in + output wire [DATA_WIDTH-1:0] wbm_dat_o, // DAT_O() data out + input wire wbm_we_i, // WE_I write enable input + input wire [SELECT_WIDTH-1:0] wbm_sel_i, // SEL_I() select input + input wire wbm_stb_i, // STB_I strobe input + output wire wbm_ack_o, // ACK_O acknowledge output + output wire wbm_err_o, // ERR_O error output + output wire wbm_rty_o, // RTY_O retry output + input wire wbm_cyc_i, // CYC_I cycle input + + // slave side + input wire wbs_clk, + input wire wbs_rst, + output wire [ADDR_WIDTH-1:0] wbs_adr_o, // ADR_O() address + input wire [DATA_WIDTH-1:0] wbs_dat_i, // DAT_I() data in + output wire [DATA_WIDTH-1:0] wbs_dat_o, // DAT_O() data out + output wire wbs_we_o, // WE_O write enable output + output wire [SELECT_WIDTH-1:0] wbs_sel_o, // SEL_O() select output + output wire wbs_stb_o, // STB_O strobe output + input wire wbs_ack_i, // ACK_I acknowledge input + input wire wbs_err_i, // ERR_I error input + input wire wbs_rty_i, // RTY_I retry input + output wire wbs_cyc_o // CYC_O cycle output +); + +reg [ADDR_WIDTH-1:0] wbm_adr_i_reg = 0; +reg [DATA_WIDTH-1:0] wbm_dat_i_reg = 0; +reg [DATA_WIDTH-1:0] wbm_dat_o_reg = 0; +reg wbm_we_i_reg = 0; +reg [SELECT_WIDTH-1:0] wbm_sel_i_reg = 0; +reg wbm_stb_i_reg = 0; +reg wbm_ack_o_reg = 0; +reg wbm_err_o_reg = 0; +reg wbm_rty_o_reg = 0; +reg wbm_cyc_i_reg = 0; + +reg wbm_done_sync1 = 0; +reg wbm_done_sync2 = 0; +reg wbm_done_sync3 = 0; + +reg [ADDR_WIDTH-1:0] wbs_adr_o_reg = 0; +reg [DATA_WIDTH-1:0] wbs_dat_i_reg = 0; +reg [DATA_WIDTH-1:0] wbs_dat_o_reg = 0; +reg wbs_we_o_reg = 0; +reg [SELECT_WIDTH-1:0] wbs_sel_o_reg = 0; +reg wbs_stb_o_reg = 0; +reg wbs_ack_i_reg = 0; +reg wbs_err_i_reg = 0; +reg wbs_rty_i_reg = 0; +reg wbs_cyc_o_reg = 0; + +reg wbs_cyc_o_sync1 = 0; +reg wbs_cyc_o_sync2 = 0; +reg wbs_cyc_o_sync3 = 0; + +reg wbs_stb_o_sync1 = 0; +reg wbs_stb_o_sync2 = 0; +reg wbs_stb_o_sync3 = 0; + +reg wbs_done_reg = 0; + +assign wbm_dat_o = wbm_dat_o_reg; +assign wbm_ack_o = wbm_ack_o_reg; +assign wbm_err_o = wbm_err_o_reg; +assign wbm_rty_o = wbm_rty_o_reg; + +assign wbs_adr_o = wbs_adr_o_reg; +assign wbs_dat_o = wbs_dat_o_reg; +assign wbs_we_o = wbs_we_o_reg; +assign wbs_sel_o = wbs_sel_o_reg; +assign wbs_stb_o = wbs_stb_o_reg; +assign wbs_cyc_o = wbs_cyc_o_reg; + +// master side logic +always @(posedge wbm_clk) begin + if (wbm_rst) begin + wbm_adr_i_reg <= 0; + wbm_dat_i_reg <= 0; + wbm_dat_o_reg <= 0; + wbm_we_i_reg <= 0; + wbm_sel_i_reg <= 0; + wbm_stb_i_reg <= 0; + wbm_ack_o_reg <= 0; + wbm_err_o_reg <= 0; + wbm_rty_o_reg <= 0; + wbm_cyc_i_reg <= 0; + end else begin + if (wbm_cyc_i_reg & wbm_stb_i_reg) begin + // cycle - hold master + if (wbm_done_sync2 & ~wbm_done_sync3) begin + // end of cycle - store slave + wbm_dat_o_reg <= wbs_dat_i_reg; + wbm_ack_o_reg <= wbs_ack_i_reg; + wbm_err_o_reg <= wbs_err_i_reg; + wbm_rty_o_reg <= wbs_rty_i_reg; + wbm_we_i_reg <= 0; + wbm_stb_i_reg <= 0; + end + end else begin + // idle - store master + wbm_adr_i_reg <= wbm_adr_i; + wbm_dat_i_reg <= wbm_dat_i; + wbm_dat_o_reg <= 0; + wbm_we_i_reg <= wbm_we_i & ~(wbm_ack_o | wbm_err_o | wbm_rty_o); + wbm_sel_i_reg <= wbm_sel_i; + wbm_stb_i_reg <= wbm_stb_i & ~(wbm_ack_o | wbm_err_o | wbm_rty_o); + wbm_ack_o_reg <= 0; + wbm_err_o_reg <= 0; + wbm_rty_o_reg <= 0; + wbm_cyc_i_reg <= wbm_cyc_i; + end + end + + // synchronize signals + wbm_done_sync1 <= wbs_done_reg; + wbm_done_sync2 <= wbm_done_sync1; + wbm_done_sync3 <= wbm_done_sync2; +end + +// slave side logic +always @(posedge wbs_clk) begin + if (wbs_rst) begin + wbs_adr_o_reg <= 0; + wbs_dat_i_reg <= 0; + wbs_dat_o_reg <= 0; + wbs_we_o_reg <= 0; + wbs_sel_o_reg <= 0; + wbs_stb_o_reg <= 0; + wbs_ack_i_reg <= 0; + wbs_err_i_reg <= 0; + wbs_rty_i_reg <= 0; + wbs_cyc_o_reg <= 0; + wbs_done_reg <= 0; + end else begin + if (wbs_ack_i | wbs_err_i | wbs_rty_i) begin + // end of cycle - store slave + wbs_dat_i_reg <= wbs_dat_i; + wbs_ack_i_reg <= wbs_ack_i; + wbs_err_i_reg <= wbs_err_i; + wbs_rty_i_reg <= wbs_rty_i; + wbs_we_o_reg <= 0; + wbs_stb_o_reg <= 0; + wbs_done_reg <= 1; + end else if (wbs_stb_o_sync2 & ~wbs_stb_o_sync3) begin + // beginning of cycle - store master + wbs_adr_o_reg <= wbm_adr_i_reg; + wbs_dat_i_reg <= 0; + wbs_dat_o_reg <= wbm_dat_i_reg; + wbs_we_o_reg <= wbm_we_i_reg; + wbs_sel_o_reg <= wbm_sel_i_reg; + wbs_stb_o_reg <= wbm_stb_i_reg; + wbs_ack_i_reg <= 0; + wbs_err_i_reg <= 0; + wbs_rty_i_reg <= 0; + wbs_cyc_o_reg <= wbm_cyc_i_reg; + wbs_done_reg <= 0; + end else if (~wbs_cyc_o_sync2 & wbs_cyc_o_sync3) begin + // cyc deassert + wbs_adr_o_reg <= 0; + wbs_dat_i_reg <= 0; + wbs_dat_o_reg <= 0; + wbs_we_o_reg <= 0; + wbs_sel_o_reg <= 0; + wbs_stb_o_reg <= 0; + wbs_ack_i_reg <= 0; + wbs_err_i_reg <= 0; + wbs_rty_i_reg <= 0; + wbs_cyc_o_reg <= 0; + wbs_done_reg <= 0; + end + end + + // synchronize signals + wbs_cyc_o_sync1 <= wbm_cyc_i_reg; + wbs_cyc_o_sync2 <= wbs_cyc_o_sync1; + wbs_cyc_o_sync3 <= wbs_cyc_o_sync2; + + wbs_stb_o_sync1 <= wbm_stb_i_reg; + wbs_stb_o_sync2 <= wbs_stb_o_sync1; + wbs_stb_o_sync3 <= wbs_stb_o_sync2; +end + +endmodule diff --git a/sbus-to-ztex-gateware-migen/ztex213_sbus.py b/sbus-to-ztex-gateware-migen/ztex213_sbus.py index 8019839..b1285d8 100644 --- a/sbus-to-ztex-gateware-migen/ztex213_sbus.py +++ b/sbus-to-ztex-gateware-migen/ztex213_sbus.py @@ -280,6 +280,9 @@ class Platform(XilinxPlatform): }[version] self.irq_device_map = dict() self.device_irq_map = dict() + self.speedgrade = -1 + if (device[-1] == '2'): + self.speedgrade = -2 XilinxPlatform.__init__(self, device, _io, connectors, toolchain="vivado") self.add_extension(sbus_io)