From 891c8706c53347b377bc2bcb3c7fd01a14ee7522 Mon Sep 17 00:00:00 2001 From: Luke Kenneth Casson Leighton Date: Thu, 20 Aug 2020 15:28:12 +0100 Subject: [PATCH] bugfix wishbone downconvert using wb sram 64-to-32 test --- src/soc/bus/test/test_sram_wb_downconvert.py | 132 ++++++++++++++++++ .../{wb_upconvert.py => wb_downconvert.py} | 20 +-- 2 files changed, 144 insertions(+), 8 deletions(-) create mode 100644 src/soc/bus/test/test_sram_wb_downconvert.py rename src/soc/bus/{wb_upconvert.py => wb_downconvert.py} (86%) diff --git a/src/soc/bus/test/test_sram_wb_downconvert.py b/src/soc/bus/test/test_sram_wb_downconvert.py new file mode 100644 index 00000000..fe87bf49 --- /dev/null +++ b/src/soc/bus/test/test_sram_wb_downconvert.py @@ -0,0 +1,132 @@ +"""demonstration of nmigen-soc SRAM behind a wishbone bus and a downconverter +""" +from nmigen_soc.wishbone.bus import Interface +from nmigen_soc.wishbone.sram import SRAM +from nmigen import Memory, Signal, Module +from nmigen.utils import log2_int +from soc.bus.wb_downconvert import WishboneDownConvert + +# memory +memory = Memory(width=32, depth=32) +sram = SRAM(memory=memory, granularity=16) + +# interface for converter +cvtbus = Interface(addr_width=log2_int(memory.depth//2, need_pow2=False), + data_width=memory.width*2, + features={'cti'}, + granularity=16) + +# actual converter +downcvt = WishboneDownConvert(cvtbus, sram.bus) +bus = cvtbus + +# valid wishbone signals include +# sram.bus.adr +# sram.bus.dat_w +# sram.bus.dat_r +# sram.bus.sel +# sram.bus.cyc +# sram.bus.stb +# sram.bus.we +# sram.bus.ack + +# setup simulation +from nmigen.back.pysim import Simulator, Delay, Settle +m = Module() +m.submodules.sram = sram +m.submodules.downcvt = downcvt +sim = Simulator(m) +sim.add_clock(1e-6) + +def print_sig(sig, format=None): + if format == None: + print(f"{sig.__repr__()} = {(yield sig)}") + if format == "h": + print(f"{sig.__repr__()} = {hex((yield sig))}") + +def process(): + + test_data = 0xdeadbeef12345678 + + # enable necessary signals for write + for en in range(4): + yield bus.sel[en].eq(1) + yield bus.we.eq(1) + yield bus.cyc.eq(1) + yield bus.stb.eq(1) + + # put data and address on bus + yield bus.adr.eq(0x4) + yield bus.dat_w.eq(test_data) + yield + + while True: + ack = yield bus.ack + if ack: + break + yield + yield bus.cyc.eq(0) + yield bus.stb.eq(0) + yield bus.adr.eq(0) + yield bus.dat_w.eq(0) + + + # set necessary signal to read bus + # at address 0 + yield bus.we.eq(0) + yield bus.adr.eq(0) + yield bus.cyc.eq(1) + yield bus.stb.eq(1) + yield + + while True: + ack = yield bus.ack + if ack: + break + yield + + # see sync_behaviors.py + # for why we need Settle() + # debug print the bus address/data + yield Settle() + yield from print_sig(bus.adr) + yield from print_sig(bus.dat_r, "h") + + # check the result + data = yield bus.dat_r + assert data == 0 + + # set necessary signal to read bus + # at address 4 + yield bus.we.eq(0) + yield bus.adr.eq(0x4) + yield bus.cyc.eq(1) + yield bus.stb.eq(1) + yield + + while True: + ack = yield bus.ack + if ack: + break + yield + + data = yield bus.dat_r + print ("data", hex(data)) + + yield from print_sig(bus.adr) + yield from print_sig(bus.dat_r, "h") + + # check the result + assert data == test_data, "data != %x %16x" % (test_data, data) + + # disable signals + yield bus.adr.eq(0) + yield bus.cyc.eq(0) + yield bus.stb.eq(0) + yield + +sim_writer = sim.write_vcd(f"{__file__[:-3]}.vcd") + +with sim_writer: + sim.add_sync_process(process) + sim.run() diff --git a/src/soc/bus/wb_upconvert.py b/src/soc/bus/wb_downconvert.py similarity index 86% rename from src/soc/bus/wb_upconvert.py rename to src/soc/bus/wb_downconvert.py index 666e488a..1e4389c2 100644 --- a/src/soc/bus/wb_upconvert.py +++ b/src/soc/bus/wb_downconvert.py @@ -44,7 +44,7 @@ class WishboneDownConvert(Elaboratable): cached_data = Signal(dw_from) shift_reg = Signal(dw_from) - counter = Signal(log2_int(ratio, False)+1) + counter = Signal(log2_int(ratio, False)) counter_reset = Signal() counter_ce = Signal() with m.If(counter_reset): @@ -59,7 +59,7 @@ class WishboneDownConvert(Elaboratable): with m.FSM() as fsm: with m.State("IDLE"): comb += counter_reset.eq(1) - sync += shift_reg.eq(0) + sync += cached_data.eq(0) with m.If(master.stb & master.cyc): with m.If(master.we): m.next = "WRITE" @@ -89,24 +89,27 @@ class WishboneDownConvert(Elaboratable): comb += counter_ce.eq(1) with m.If(counter_done): comb += master.ack.eq(1) - comb += master.dat_r.eq(cached_data) + comb += master.dat_r.eq(shift_reg) m.next = "IDLE" with m.Elif(~master.cyc): m.next = "IDLE" # Address - with m.If(counter_done): - comb += slave.cti.eq(7) # indicate end of burst - with m.Else(): - comb += slave.cti.eq(2) + if hasattr(slave, 'cti'): + with m.If(counter_done): + comb += slave.cti.eq(7) # indicate end of burst + with m.Else(): + comb += slave.cti.eq(2) comb += slave.adr.eq(Cat(counter, master.adr)) # write Datapath - select fragments of data, depending on "counter" with m.Switch(counter): + slen = slave.sel.width for i in range(ratio): with m.Case(i): # select fractions of dat_w and associated "sel" bits - comb += slave.sel.eq(master.sel[i*dw_to//8:(i+1)*dw_to//8]) + print ("sel", i, "from", i*slen, "to", (i+1)*slen) + comb += slave.sel.eq(master.sel[i*slen:(i+1)*slen]) comb += slave.dat_w.eq(master.dat_w[i*dw_to:(i+1)*dw_to]) # read Datapath - uses cached_data and master.dat_r as a shift-register. @@ -116,3 +119,4 @@ class WishboneDownConvert(Elaboratable): sync += cached_data.eq(shift_reg) + return m -- 2.30.2