Add a FIFO for CDC between SBus (in cd_sbus) and Wishbone (in a 100 MHz cd_sys)
This commit is contained in:
@@ -10,8 +10,10 @@ from litex.soc.integration.builder import *
|
||||
from litex.soc.cores.clock import *
|
||||
from litex.soc.cores.led import LedChaser
|
||||
from litex_boards.platforms import ztex213
|
||||
from migen.genlib.fifo import *
|
||||
|
||||
from sbus_to_fpga_slave import *;
|
||||
from sbus_to_fpga_wishbone import *;
|
||||
|
||||
_sbus_sbus = [
|
||||
("SBUS_3V3_CLK", 0, Pins("D15"), IOStandard("lvttl")),
|
||||
@@ -38,39 +40,34 @@ 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_sbus = ClockDomain()
|
||||
self.clock_domains.cd_por = ClockDomain()
|
||||
|
||||
# # #
|
||||
clk48 = platform.request("clk48")
|
||||
self.cd_native.clk = clk48
|
||||
clk_sbus = platform.request("SBUS_3V3_CLK")
|
||||
self.cd_sys.clk = clk_sbus
|
||||
self.cd_sbus.clk = clk_sbus
|
||||
rst_sbus = platform.request("SBUS_3V3_RSTs")
|
||||
|
||||
#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.rst.eq(~rst_sbus)
|
||||
|
||||
#self.comb += self.cd_sbus.clk.eq(clk_sbus)
|
||||
#self.comb += self.cd_sbus.rst.eq(~rst_sbus)
|
||||
self.submodules.pll = pll = S7MMCM(speedgrade=-1)
|
||||
pll.register_clkin(clk48, 48e6)
|
||||
pll.create_clkout(self.cd_sys, sys_clk_freq)
|
||||
|
||||
platform.add_false_path_constraints(self.cd_native.clk, self.cd_sbus.clk)
|
||||
platform.add_false_path_constraints(self.cd_sys.clk, self.cd_sbus.clk)
|
||||
platform.add_false_path_constraints(self.cd_sbus.clk, self.cd_native.clk)
|
||||
platform.add_false_path_constraints(self.cd_sbus.clk, self.cd_sys.clk)
|
||||
|
||||
#self.comb += self.cd_sys.clk.eq(clk_sbus)
|
||||
self.comb += self.cd_sys.rst.eq(~rst_sbus)
|
||||
|
||||
#self.comb += self.cd_native.clk.eq(clk48)
|
||||
|
||||
#platform.add_false_path_constraints(self.cd_native.clk, self.cd_sbus.clk)
|
||||
platform.add_false_path_constraints(self.cd_native.clk, self.cd_sys.clk)
|
||||
platform.add_false_path_constraints(self.cd_sys.clk, self.cd_native.clk)
|
||||
|
||||
# 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)
|
||||
# Power on reset, reset propagate from SBus to SYS
|
||||
por_count = Signal(16, reset=2**16-1)
|
||||
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 | ~rst_sbus)
|
||||
|
||||
class SBusFPGA(SoCCore):
|
||||
def __init__(self, **kwargs):
|
||||
@@ -80,7 +77,7 @@ class SBusFPGA(SoCCore):
|
||||
kwargs["with_uart"] = True
|
||||
kwargs["with_timer"] = False
|
||||
|
||||
self.sys_clk_freq = sys_clk_freq = 25e6 # SBus max
|
||||
self.sys_clk_freq = sys_clk_freq = 100e6
|
||||
|
||||
self.platform = platform = ztex213.Platform(variant="ztex2.13a", expansion="sbus")
|
||||
self.platform.add_extension(_sbus_sbus)
|
||||
@@ -91,7 +88,7 @@ class SBusFPGA(SoCCore):
|
||||
}
|
||||
self.mem_map.update(wb_mem_map)
|
||||
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)
|
||||
self.platform.add_period_constraint(self.platform.lookup_request("SBUS_3V3_CLK", loose=True), 1e9/25e6) # SBus max
|
||||
|
||||
self.submodules.leds = LedChaser(
|
||||
pads = platform.request_all("user_led"),
|
||||
@@ -113,19 +110,27 @@ class SBusFPGA(SoCCore):
|
||||
# this avoids FPGA initialization messing with the cold boot process
|
||||
# requires us to reset the SPARCstation afterward so the FPGA board
|
||||
# is properly identified
|
||||
# This is in the 'native' ClockDomain that is never reset
|
||||
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.sbus_slave = ClockDomainsRenamer("sbus")(SBusFPGASlave(platform=self.platform, soc=self, prom=prom, hold_reset=hold_reset))
|
||||
self.submodules.sbus_slave = SBusFPGASlave(platform=self.platform,
|
||||
prom=prom,
|
||||
hold_reset=hold_reset,
|
||||
wishbone=wishbone.Interface(data_width=self.bus.data_width),
|
||||
chaser=self.leds)
|
||||
|
||||
self.bus.add_master(name="SBusBridgeToWishbone", master=self.sbus_slave.wishbone)
|
||||
|
||||
|
||||
|
||||
sbus_to_wishbone_fifo = AsyncFIFOBuffered(width=32+30, depth=8)
|
||||
sbus_to_wishbone_fifo = ClockDomainsRenamer({"write": "sbus", "read": "sys"})(sbus_to_wishbone_fifo)
|
||||
self.submodules += sbus_to_wishbone_fifo
|
||||
self.submodules.sbus_to_wishbone = SBusToWishbone(fifo=sbus_to_wishbone_fifo, wishbone=wishbone.Interface(data_width=self.bus.data_width))
|
||||
|
||||
_sbus_slave = SBusFPGASlave(platform=self.platform,
|
||||
prom=prom,
|
||||
hold_reset=hold_reset,
|
||||
write_fifo=sbus_to_wishbone_fifo)
|
||||
self.submodules.sbus_slave = ClockDomainsRenamer("sbus")(_sbus_slave)
|
||||
|
||||
self.bus.add_master(name="SBusBridgeToWishbone", master=self.sbus_to_wishbone.wishbone)
|
||||
|
||||
# self.soc = Module()
|
||||
# self.soc.mem_regions = self.mem_regions = {}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
|
||||
from migen import *
|
||||
from migen.genlib.fifo import SyncFIFOBuffered
|
||||
from migen.fhdl.specials import Tristate
|
||||
from litex.soc.interconnect import wishbone
|
||||
|
||||
SIZ_WORD = 0x0
|
||||
SIZ_BYTE = 0x1
|
||||
@@ -33,7 +31,7 @@ WISHBONE_CSR_ADDR_PFX = Signal(12, reset = 4)
|
||||
def siz_is_word(siz):
|
||||
return (SIZ_WORD == siz) | (SIZ_BURST2 == siz) | (SIZ_BURST4 == siz) | (SIZ_BURST8 == siz) | (SIZ_BURST16 == siz)
|
||||
|
||||
# FIXME: this doesn't work. Verilog aways use 1
|
||||
# FIXME: this doesn't work. Verilog aways use value[0:4]
|
||||
def index_with_wrap(counter, limit_m1, value):
|
||||
if (limit_m1 == 0):
|
||||
return value[0:4]
|
||||
@@ -146,11 +144,10 @@ class LedDisplay(Module):
|
||||
)
|
||||
|
||||
class SBusFPGASlave(Module):
|
||||
def __init__(self, platform, prom, hold_reset, wishbone, chaser):
|
||||
def __init__(self, platform, prom, hold_reset, write_fifo):
|
||||
self.platform = platform
|
||||
self.hold_reset = hold_reset
|
||||
self.wishbone = wishbone
|
||||
self.chaser = chaser
|
||||
self.write_fifo = write_fifo
|
||||
|
||||
#self.submodules.led_display = LedDisplay(pads=platform.request_all("user_led"))
|
||||
|
||||
@@ -238,9 +235,9 @@ class SBusFPGASlave(Module):
|
||||
|
||||
p_data = Signal(32) # prom data to read
|
||||
|
||||
csr_data_w_data = Signal(32) # csr data to write
|
||||
csr_data_w_addr = Signal(32) # address thereof
|
||||
csr_data_w_we = Signal(reset = 0) # write enable
|
||||
#csr_data_w_data = Signal(32) # csr data to write
|
||||
#csr_data_w_addr = Signal(32) # address thereof
|
||||
#csr_data_w_we = Signal(reset = 0) # write enable
|
||||
|
||||
slave_fsm.act("Reset",
|
||||
#NextValue(SBUS_DATA_OE_LED_o, 0),
|
||||
@@ -326,7 +323,8 @@ class SBusFPGASlave(Module):
|
||||
(SBUS_3V3_ASs_i == 0) &
|
||||
(siz_is_word(SBUS_3V3_SIZ_i)) &
|
||||
(SBUS_3V3_PPRD_i == 0) &
|
||||
(SBUS_3V3_PA_i[0:2] == 0)),
|
||||
(SBUS_3V3_PA_i[0:2] == 0) &
|
||||
(self.write_fifo.writable)), # maybe we should check for enough space? not that we'll encounter write burst...
|
||||
#NextValue(SBUS_DATA_OE_LED_o, 1),
|
||||
#NextValue(SBUS_DATA_OE_LED_2_o, 1),
|
||||
NextValue(sbus_oe_master_in, 1),
|
||||
@@ -418,13 +416,19 @@ class SBusFPGASlave(Module):
|
||||
#NextValue(SBUS_DATA_OE_LED_2_o, 1),
|
||||
#NextValue(leds, 0x03),
|
||||
#NextValue(burst_index, index_with_wrap((burst_counter+1), burst_limit_m1, sbus_last_pa[ADDR_PHYS_LOW+2:ADDR_PHYS_LOW+6])),
|
||||
NextValue(csr_data_w_data, SBUS_3V3_D_i),
|
||||
#NextValue(csr_data_w_addr, Cat(Signal(2, reset = 0),
|
||||
# index_with_wrap(burst_counter, burst_limit_m1, sbus_last_pa[ADDR_PHYS_LOW+2:ADDR_PHYS_LOW+6]),
|
||||
# sbus_last_pa[ADDR_PHYS_LOW+6:ADDR_PFX_LOW],
|
||||
# WISHBONE_CSR_ADDR_PFX)),
|
||||
NextValue(csr_data_w_addr, 0x00040000),
|
||||
NextValue(csr_data_w_we, 1),
|
||||
#NextValue(csr_data_w_data, SBUS_3V3_D_i),
|
||||
#NextValue(csr_data_w_addr, 0x00040000),
|
||||
#NextValue(csr_data_w_we, 1),
|
||||
self.write_fifo.din.eq(Cat(index_with_wrap(burst_counter, burst_limit_m1, sbus_last_pa[ADDR_PHYS_LOW+2:ADDR_PHYS_LOW+6]), # 4 bits, adr FIXME
|
||||
sbus_last_pa[ADDR_PHYS_LOW+6:ADDR_PFX_LOW], # 10 bits, adr
|
||||
WISHBONE_CSR_ADDR_PFX, # 12 bits, adr
|
||||
Signal(4, reset = 0), # 4 bits, adr (could be removed)
|
||||
SBUS_3V3_D_i)), # 32 bits, data
|
||||
self.write_fifo.we.eq(1),
|
||||
If((burst_counter == burst_limit_m1),
|
||||
NextValue(SBUS_3V3_ACKs_o, ACK_IDLE),
|
||||
NextState("Slave_Ack_Reg_Write_Final")
|
||||
@@ -461,35 +465,3 @@ class SBusFPGASlave(Module):
|
||||
NextState("Idle")
|
||||
)
|
||||
)
|
||||
|
||||
# ##### Iface to WB #####
|
||||
self.submodules.wb_fsm = wb_fsm = FSM(reset_state="Reset")
|
||||
wb_fsm.act("Reset",
|
||||
self.wishbone.we.eq(0),
|
||||
self.wishbone.cyc.eq(0),
|
||||
self.wishbone.stb.eq(0),
|
||||
NextState("Idle")
|
||||
)
|
||||
wb_fsm.act("Idle",
|
||||
If(csr_data_w_we == 1,
|
||||
#NextValue(SBUS_DATA_OE_LED_o, 0),
|
||||
NextValue(SBUS_DATA_OE_LED_2_o, 1),
|
||||
NextValue(csr_data_w_we, 0),
|
||||
NextState("Write")
|
||||
)
|
||||
)
|
||||
wb_fsm.act("Write",
|
||||
self.wishbone.adr.eq(csr_data_w_addr[2:32]),
|
||||
self.wishbone.dat_w.eq(csr_data_w_data),
|
||||
self.wishbone.we.eq(1),
|
||||
self.wishbone.cyc.eq(1),
|
||||
self.wishbone.stb.eq(1),
|
||||
self.wishbone.sel.eq(2**len(self.wishbone.sel)-1),
|
||||
If(self.wishbone.ack == 1,
|
||||
NextValue(SBUS_DATA_OE_LED_o, 1),
|
||||
self.wishbone.we.eq(0),
|
||||
self.wishbone.cyc.eq(0),
|
||||
self.wishbone.stb.eq(0),
|
||||
NextState("Idle")
|
||||
)
|
||||
)
|
||||
|
||||
42
sbus-to-ztex-gateware-migen/sbus_to_fpga_wishbone.py
Normal file
42
sbus-to-ztex-gateware-migen/sbus_to_fpga_wishbone.py
Normal file
@@ -0,0 +1,42 @@
|
||||
|
||||
from migen import *
|
||||
from litex.soc.interconnect import wishbone
|
||||
|
||||
class SBusToWishbone(Module):
|
||||
def __init__(self, fifo, wishbone):
|
||||
self.fifo = fifo
|
||||
self.wishbone = wishbone
|
||||
|
||||
data = Signal(32)
|
||||
adr = Signal(30)
|
||||
|
||||
# ##### Iface to WB #####
|
||||
self.submodules.wb_fsm = wb_fsm = FSM(reset_state="Reset")
|
||||
wb_fsm.act("Reset",
|
||||
self.wishbone.we.eq(0),
|
||||
self.wishbone.cyc.eq(0),
|
||||
self.wishbone.stb.eq(0),
|
||||
NextState("Idle")
|
||||
)
|
||||
wb_fsm.act("Idle",
|
||||
If(fifo.readable & ~self.wishbone.cyc,
|
||||
fifo.re.eq(1),
|
||||
NextValue(adr, fifo.dout[0:30]),
|
||||
NextValue(data, fifo.dout[30:62]),
|
||||
NextState("Write")
|
||||
)
|
||||
)
|
||||
wb_fsm.act("Write",
|
||||
self.wishbone.adr.eq(adr),
|
||||
self.wishbone.dat_w.eq(data),
|
||||
self.wishbone.we.eq(1),
|
||||
self.wishbone.cyc.eq(1),
|
||||
self.wishbone.stb.eq(1),
|
||||
self.wishbone.sel.eq(2**len(self.wishbone.sel)-1),
|
||||
If(self.wishbone.ack == 1,
|
||||
self.wishbone.we.eq(0),
|
||||
self.wishbone.cyc.eq(0),
|
||||
self.wishbone.stb.eq(0),
|
||||
NextState("Idle")
|
||||
)
|
||||
)
|
||||
Reference in New Issue
Block a user