diff --git a/nubus-to-ztex-gateware/nubus_full_sampling.py b/nubus-to-ztex-gateware/nubus_full_sampling.py index 5630386..ed78a54 100644 --- a/nubus-to-ztex-gateware/nubus_full_sampling.py +++ b/nubus-to-ztex-gateware/nubus_full_sampling.py @@ -7,12 +7,16 @@ import litex from litex.soc.interconnect import wishbone class NuBus(Module): - def __init__(self, platform, wb_read, wb_write, wb_dma, cd_nubus="nubus", cd_nubus90="nubus90"): + def __init__(self, soc, + burst_size, tosbus_fifo, fromsbus_fifo, fromsbus_req_fifo, + wb_read, wb_write, wb_dma, + cd_nubus="nubus", cd_nubus90="nubus90"): + platform = soc.platform self.add_sources(platform) - #led0 = platform.request("user_led", 0) - #led1 = platform.request("user_led", 1) + led0 = platform.request("user_led", 0) + led1 = platform.request("user_led", 1) nub_clk = ClockSignal(cd_nubus) nub_resetn = ~ResetSignal(cd_nubus) @@ -321,16 +325,56 @@ class NuBus(Module): ] self.submodules.dma_fsm = dma_fsm = ClockDomainsRenamer(cd_nubus)(FSM(reset_state="Reset")) + ctr = Signal(2) # burst counter + burst = Signal() + burst_we = Signal() + + data_width = burst_size * 4 + data_width_bits = burst_size * 32 + blk_addr_width = 32 - log2_int(data_width) # 27 for burst_size == 8, 28 for burst_size == 4 + fifo_addr = Signal(blk_addr_width) + fifo_blk_addr = Signal(blk_addr_width) + fifo_buffer = Signal(data_width_bits) + + tosbus_fifo_dout = Record(soc.tosbus_layout) + self.comb += tosbus_fifo_dout.raw_bits().eq(tosbus_fifo.dout) + + fromsbus_req_fifo_dout = Record(soc.fromsbus_req_layout) + self.comb += fromsbus_req_fifo_dout.raw_bits().eq(fromsbus_req_fifo.dout) + + fromsbus_fifo_din = Record(soc.fromsbus_layout) + self.comb += fromsbus_fifo.din.eq(fromsbus_fifo_din.raw_bits()) + dma_fsm.act("Reset", NextState("Idle") ) dma_fsm.act("Idle", If(wb_dma.cyc & wb_dma.stb & ~sampled_rqst, # we need the bus and it's not being requested + NextValue(burst, 0), If(owning_bus, # we own the bus, skip arbitration NextState("AdrCycle"), ).Else( # go for arbitration NextState("Arbitration"), ), + ).Elif(tosbus_fifo.readable & ~sampled_rqst, + NextValue(burst, 1), + NextValue(burst_we, 1), + NextValue(fifo_addr, tosbus_fifo_dout.address[(32-blk_addr_width):32]), + If(owning_bus, # we own the bus, skip arbitration + NextState("Burst4AdrCycle"), + ).Else( # go for arbitration + NextState("Arbitration"), + ) + ).Elif(fromsbus_req_fifo.readable & fromsbus_fifo.writable & ~sampled_rqst, + NextValue(burst, 1), + NextValue(burst_we, 0), + NextValue(fifo_addr, fromsbus_req_fifo_dout.dmaaddress[(32-blk_addr_width):32]), + NextValue(fifo_blk_addr, fromsbus_req_fifo_dout.blkaddress), + If(owning_bus, # we own the bus, skip arbitration + NextState("Burst4AdrCycle"), + ).Else( # go for arbitration + NextState("Arbitration"), + ) ) ) dma_fsm.act("Arbitration", @@ -345,7 +389,11 @@ class NuBus(Module): rqst_o_n.eq(0), If(grant & ~decoded_busy, # I'm now 'owner' NextValue(owning_bus, 1), - NextState("AdrCycle"), + If(burst, + NextState("Burst4AdrCycle"), + ).Else( + NextState("AdrCycle"), + ), ) ) dma_fsm.act("AdrCycle", @@ -374,6 +422,7 @@ class NuBus(Module): If(sampled_ack, wb_dma.ack.eq(1), # fixme: check status ??? (tm0 and tm1 should be active for no-error) + NextValue(led0, (~sampled_tm0 | ~sampled_tm1)), NextState("FinishCycle"), ) ) @@ -393,6 +442,101 @@ class NuBus(Module): If(sampled_ack, wb_dma.ack.eq(1), # fixme: check status ??? (tm0 and tm1 should be active for no-error) + NextValue(led0, (~sampled_tm0 | ~sampled_tm1)), + NextState("FinishCycle"), + ) + ) + + dma_fsm.act("Burst4AdrCycle", + start_arbitration.eq(0), + master_oe.eq(1), # for start + tmo_oe.eq(1), # for tm0, tm1, ack + ad_oe.eq(1), # for write address + start_o_n.eq(0), + tm0_o_n.eq(1), # burst + tm1_o_n.eq(~burst_we), + ad_o_n[0].eq(1), # burst + ad_o_n[1].eq(0), # burst + ad_o_n[2].eq(0), # burst == 4 + ad_o_n[3].eq(1), # burst == 4 + ad_o_n[4:32].eq(~fifo_addr), + ack_o_n.eq(1), + NextValue(ctr, 0), + If(burst_we, + NextState("Burst4DatCycleTM0"), + ).Else( + NextState("Burst4ReadWaitForTM0"), + ) + ) + dma_fsm.act("Burst4ReadWaitForTM0", + master_oe.eq(1), # for start + start_o_n.eq(1), # start finished, but still need to be driven + If(sampled_ack, # oups + fromsbus_req_fifo.re.eq(1), # remove request to avoid infinite repeat + NextValue(led0, 1), + NextValue(led1, 1), + NextState("FinishCycle"), + ).Elif(sampled_tm0, + Case(ctr, { + 0x0: NextValue(fifo_buffer[ 0: 32], sampled_ad), + 0x1: NextValue(fifo_buffer[32: 64], sampled_ad), + 0x2: NextValue(fifo_buffer[64: 96], sampled_ad), + #0x3: NextValue(fifo_buffer[96:128], sampled_ad), + }), + NextValue(ctr, ctr + 1), + If(ctr == 0x2, # burst next-to-last + NextState("Burst4ReadWaitForAck"), + ).Else( + NextState("Burst4ReadWaitForTM0"), + ) + ) + ) + dma_fsm.act("Burst4ReadWaitForAck", + master_oe.eq(1), # for start + start_o_n.eq(1), # start finished, but still need to be driven + If(sampled_ack, + fromsbus_req_fifo.re.eq(1), # remove request + fromsbus_fifo.we.eq(1), + fromsbus_fifo_din.blkaddress.eq(fifo_blk_addr), + fromsbus_fifo_din.data.eq(Cat(fifo_buffer[0:96], sampled_ad)), # we use sampled_ad directly for 96:128 + # fixme: check status ??? (tm0 and tm1 should be active for no-error) + NextValue(led0, (~sampled_tm0 | ~sampled_tm1)), + NextState("FinishCycle"), + ) + ) + dma_fsm.act("Burst4DatCycleTM0", + master_oe.eq(1), # for start + ad_oe.eq(1), # for write data + start_o_n.eq(1), # start finished, but still need to be driven + Case(ctr, { + 0x0: ad_o_n.eq(~tosbus_fifo_dout.data[ 0: 32]), + 0x1: ad_o_n.eq(~tosbus_fifo_dout.data[32: 64]), + 0x2: ad_o_n.eq(~tosbus_fifo_dout.data[64: 96]), + #0x3: ad_o_n.eq(~tosbus_fifo_dout.data[96:128]), + }), + If(sampled_ack, # oups + NextValue(led0, 1), + NextValue(led1, 1), + tosbus_fifo.re.eq(1), # remove FIFO entry to avoid infinite repeat + NextState("FinishCycle"), + ).Elif(sampled_tm0, + NextValue(ctr, ctr + 1), + If(ctr == 0x2, # burst next-to-last + NextState("Burst4DatCycleAck"), + ).Else( + NextState("Burst4DatCycleTM0"), + ) + ) + ) + dma_fsm.act("Burst4DatCycleAck", + master_oe.eq(1), # for start + ad_oe.eq(1), # for write data + start_o_n.eq(1), # start finished, but still need to be driven + ad_o_n.eq(~tosbus_fifo_dout.data[96:128]), # last word + If(sampled_ack, + tosbus_fifo.re.eq(1), # remove FIFO entry at last + # fixme: check status ??? (tm0 and tm1 should be active for no-error) + NextValue(led0, (~sampled_tm0 | ~sampled_tm1)), NextState("FinishCycle"), ) ) diff --git a/nubus-to-ztex-gateware/nubus_to_fpga_soc.py b/nubus-to-ztex-gateware/nubus_to_fpga_soc.py index 02e85df..e6ff81a 100644 --- a/nubus-to-ztex-gateware/nubus_to_fpga_soc.py +++ b/nubus-to-ztex-gateware/nubus_to_fpga_soc.py @@ -37,6 +37,7 @@ import goblin_accel # Wishbone stuff from sbus_wb import WishboneDomainCrossingMaster +from sbus_to_fpga_blk_dma import * from nubus_mem_wb import NuBus2Wishbone from nubus_memfifo_wb import NuBus2WishboneFIFO from nubus_cpu_wb import Wishbone2NuBus @@ -322,12 +323,56 @@ class NuBusFPGA(SoCCore): nubus_writemaster_sys = wishbone.Interface(data_width=self.bus.data_width) wishbone_slave_nubus = wishbone.Interface(data_width=self.bus.data_width) self.submodules.wishbone_slave_sys = WishboneDomainCrossingMaster(platform=self.platform, slave=wishbone_slave_nubus, cd_master="sys", cd_slave="nubus", force_delay=6) # force delay needed to avoid back-to-back transaction running into issue https://github.com/alexforencich/verilog-wishbone/issues/4 - self.submodules.nubus = nubus_full_sampling.NuBus(platform=platform, + + + burst_size=4 + + data_width = burst_size * 4 + data_width_bits = burst_size * 32 + blk_addr_width = 32 - log2_int(data_width) + + self.tosbus_layout = [ + ("address", 32), + ("data", data_width_bits), + ] + self.fromsbus_layout = [ + ("blkaddress", blk_addr_width), + ("data", data_width_bits), + ] + self.fromsbus_req_layout = [ + ("blkaddress", blk_addr_width), + ("dmaaddress", 32), + ] + + self.submodules.tosbus_fifo = ClockDomainsRenamer({"read": "nubus", "write": "sys"})(AsyncFIFOBuffered(width=layout_len(self.tosbus_layout), depth=burst_size)) + self.submodules.fromsbus_fifo = ClockDomainsRenamer({"write": "nubus", "read": "sys"})(AsyncFIFOBuffered(width=layout_len(self.fromsbus_layout), depth=burst_size)) + self.submodules.fromsbus_req_fifo = ClockDomainsRenamer({"read": "nubus", "write": "sys"})(AsyncFIFOBuffered(width=layout_len(self.fromsbus_req_layout), depth=burst_size)) + + self.submodules.exchange_with_mem = ExchangeWithMem(soc=self, + platform=platform, + tosbus_fifo=self.tosbus_fifo, + fromsbus_fifo=self.fromsbus_fifo, + fromsbus_req_fifo=self.fromsbus_req_fifo, + dram_native_r=self.sdram.crossbar.get_port(mode="read", data_width=data_width_bits), + dram_native_w=self.sdram.crossbar.get_port(mode="write", data_width=data_width_bits), + mem_size=avail_sdram//1048576, + burst_size=burst_size, + do_checksum = False) + + self.submodules.nubus = nubus_full_sampling.NuBus(soc=self, + burst_size=burst_size, + tosbus_fifo=self.tosbus_fifo, + fromsbus_fifo=self.fromsbus_fifo, + fromsbus_req_fifo=self.fromsbus_req_fifo, wb_read=wishbone_master_sys, wb_write=nubus_writemaster_sys, wb_dma=wishbone_slave_nubus, cd_nubus="nubus") - #self.submodules.nubus = nubus_full.NuBus(platform=platform, + #self.submodules.nubus = nubus_full.NuBus(soc=self, + # burst_size=burst_size, + # tosbus_fifo=self.tosbus_fifo, + # fromsbus_fifo=self.fromsbus_fifo, + # fromsbus_req_fifo=self.fromsbus_req_fifo, # wb_read=self.wishbone_master_nubus, # wb_write=nubus_writemaster_sys, # wb_dma=wishbone_slave_nubus, diff --git a/nubus-to-ztex-gateware/sdram_init.py b/nubus-to-ztex-gateware/sdram_init.py index 1c594c3..02374f9 100644 --- a/nubus-to-ztex-gateware/sdram_init.py +++ b/nubus-to-ztex-gateware/sdram_init.py @@ -18,7 +18,7 @@ dfii_command_wrdata = 0x10 dfii_command_rddata = 0x20 # /!\ keep up to date with csr /!\ -sdram_dfii_base = 0xf0a01000 +sdram_dfii_base = 0xf0a01800 sdram_dfii_control = sdram_dfii_base + 0x000 sdram_dfii_pi0_command = sdram_dfii_base + 0x004 sdram_dfii_pi0_command_issue = sdram_dfii_base + 0x008