From 92817c240451c1d14d78bdf432afbe1b6756843d Mon Sep 17 00:00:00 2001 From: Jean THOMAS Date: Mon, 27 Jul 2020 14:02:04 +0200 Subject: [PATCH] Wire directly to the Wishbone bus, making simulations faster and reduce the chances of reading before ACK --- gram/simulation/simsoc.py | 42 +++-- gram/simulation/simsoctb.v | 123 +++++++------- gram/simulation/uartbridge.py | 305 ---------------------------------- 3 files changed, 90 insertions(+), 380 deletions(-) delete mode 100644 gram/simulation/uartbridge.py diff --git a/gram/simulation/simsoc.py b/gram/simulation/simsoc.py index abfded2..2379715 100644 --- a/gram/simulation/simsoc.py +++ b/gram/simulation/simsoc.py @@ -1,6 +1,7 @@ # This file is Copyright (c) 2020 LambdaConcept from nmigen import * +from nmigen.build import Resource, Pins, Attrs, Subsignal from nmigen_soc import wishbone, memory from lambdasoc.periph import Peripheral @@ -12,7 +13,6 @@ from gram.modules import MT41K256M16 from gram.frontend.wishbone import gramWishbone from icarusecpix5platform import IcarusECPIX5Platform -from uartbridge import UARTBridge from crg import * class DDR3SoC(SoC, Elaboratable): @@ -21,14 +21,9 @@ class DDR3SoC(SoC, Elaboratable): ddr_addr): self.crg = ECPIX5CRG() - self._arbiter = wishbone.Arbiter(addr_width=30, data_width=32, granularity=8, - features={"cti", "bte"}) self._decoder = wishbone.Decoder(addr_width=30, data_width=32, granularity=8, features={"cti", "bte"}) - self.ub = UARTBridge(divisor=5, pins=platform.request("uart", 0)) - self._arbiter.add(self.ub.bus) - ddr_pins = platform.request("ddr3", 0, dir={"dq":"-", "dqs":"-"}, xdr={"clk":4, "a":4, "ba":4, "clk_en":4, "we_n":4, "odt":4, "ras":4, "cas":4, "we":4}) self.ddrphy = DomainRenamer("dramsync")(ECP5DDRPHY(ddr_pins)) @@ -53,18 +48,45 @@ class DDR3SoC(SoC, Elaboratable): def elaborate(self, platform): m = Module() - m.submodules.sysclk = self.crg + resources = [ + Resource("wishbone", 0, + Subsignal("adr", Pins("ADDR0 ADDR1 ADDR2 ADDR3 ADDR4 ADDR5 ADDR6 ADDR7" + " ADDR8 ADDR9 ADDR10 ADDR11 ADDR12 ADDR13 ADDR14 ADDR15" + " ADDR16 ADDR17 ADDR18 ADDR19 ADDR20 ADDR21 ADDR22 ADDR23" + " ADDR24 ADDR25 ADDR26 ADDR27 ADDR28 ADDR29 ADDR30 ADDR31", dir="i")), + Subsignal("dat_r", Pins("DATR0 DATR1 DATR2 DATR3 DATR4 DATR5 DATR6 DATR7" + " DATR8 DATR9 DATR10 DATR11 DATR12 DATR13 DATR14 DATR15" + " DATR16 DATR17 DATR18 DATR19 DATR20 DATR21 DATR22 DATR23" + " DATR24 DATR25 DATR26 DATR27 DATR28 DATR29 DATR30 DATR31", dir="o")), + Subsignal("dat_w", Pins("DATW0 DATW1 DATW2 DATW3 DATW4 DATW5 DATW6 DATW7" + " DATW8 DATW9 DATW10 DATW11 DATW12 DATW13 DATW14 DATW15" + " DATW16 DATW17 DATW18 DATW19 DATW20 DATW21 DATW22 DATW23" + " DATW24 DATW25 DATW26 DATW27 DATW28 DATW29 DATW30 DATW31", dir="i")), + Subsignal("cyc", Pins("CYC", dir="i")), + Subsignal("stb", Pins("STB", dir="i")), + Subsignal("sel", Pins("SEL0 SEL1 SEL2 SEL3", dir="i")), + Subsignal("ack", Pins("ACK", dir="o")), + Subsignal("we", Pins("WE", dir="i"))), + ] + platform.add_resources(resources) - m.submodules.arbiter = self._arbiter - m.submodules.ub = self.ub + m.submodules.sysclk = self.crg m.submodules.decoder = self._decoder m.submodules.ddrphy = self.ddrphy m.submodules.dramcore = self.dramcore m.submodules.drambone = self.drambone + ext_bus = platform.request("wishbone", 0) m.d.comb += [ - self._arbiter.bus.connect(self._decoder.bus), + self._decoder.bus.adr.eq(ext_bus.adr.i), + self._decoder.bus.dat_w.eq(ext_bus.dat_w.i), + ext_bus.dat_r.o.eq(self._decoder.bus.dat_r), + self._decoder.bus.cyc.eq(ext_bus.cyc.i), + self._decoder.bus.stb.eq(ext_bus.stb.i), + self._decoder.bus.sel.eq(ext_bus.sel.i), + ext_bus.ack.o.eq(self._decoder.bus.ack), + self._decoder.bus.we.eq(ext_bus.we.i), ] return m diff --git a/gram/simulation/simsoctb.v b/gram/simulation/simsoctb.v index c9546c3..4d7ce64 100644 --- a/gram/simulation/simsoctb.v +++ b/gram/simulation/simsoctb.v @@ -29,10 +29,6 @@ module simsoctb; #5; end - // UART - reg uart_rx; - wire uart_tx; - // DDR3 init wire dram_ck; wire dram_cke; @@ -72,6 +68,16 @@ module simsoctb; assign dram_dqs_n = (dram_dqs != 2'hz) ? ~dram_dqs : 2'hz; + // Wishbone + reg [31:0] wishbone_adr = 0; + reg [31:0] wishbone_dat_w = 0; + wire [31:0] wishbone_dat_r; + reg [3:0] wishbone_sel = 0; + reg wishbone_cyc = 0; + reg wishbone_stb = 0; + reg wishbone_we = 0; + wire wishbone_ack; + //defparam ram_chip. top simsoctop ( @@ -86,10 +92,16 @@ module simsoctb; .ddr3_0__ba__io(dram_ba), .ddr3_0__dm__io(dram_dm), .ddr3_0__odt__io(dram_odt), + .wishbone_0__adr__io(wishbone_adr), + .wishbone_0__dat_r__io(wishbone_dat_r), + .wishbone_0__dat_w__io(wishbone_dat_w), + .wishbone_0__cyc__io(wishbone_cyc), + .wishbone_0__stb__io(wishbone_stb), + .wishbone_0__sel__io(wishbone_sel), + .wishbone_0__ack__io(wishbone_ack), + .wishbone_0__we__io(wishbone_we), .clk100_0__io(clkin), - .rst_0__io(1'b0), - .uart_0__rx__io(uart_rx), - .uart_0__tx__io(uart_tx) + .rst_0__io(1'b0) ); initial @@ -107,8 +119,14 @@ module simsoctb; $dumpvars(0, dram_ba); $dumpvars(0, dram_dm); $dumpvars(0, dram_odt); - $dumpvars(0, uart_rx); - $dumpvars(0, uart_tx); + $dumpvars(0, wishbone_adr); + $dumpvars(0, wishbone_dat_w); + $dumpvars(0, wishbone_dat_r); + $dumpvars(0, wishbone_ack); + $dumpvars(0, wishbone_stb); + $dumpvars(0, wishbone_cyc); + $dumpvars(0, wishbone_sel); + $dumpvars(0, wishbone_we); $dumpvars(0, simsoctop); $dumpvars(0, ram_chip); @@ -195,10 +213,10 @@ module simsoctb; assert_equal_32(tmp, 32'h12345678); // Write - wishbone_write(32'h10000000 >> 2, 32'h00BA0BAB); - #2000; - wishbone_write(32'h10000100 >> 2, 32'h00000000); - #2000; + wishbone_write(32'h1000000C >> 2, 32'h00BA0BAB); + wishbone_write(32'h10000008 >> 2, 32'h13374242); + wishbone_write(32'h10000004 >> 2, 32'hC0DEC0DE); + wishbone_write(32'h10000000 >> 2, 32'h01020304); wishbone_read(32'h10000000 >> 2, tmp); assert_equal_32(tmp, 32'h00BA0BAB); @@ -210,17 +228,22 @@ module simsoctb; input [31:0] value; begin - uart_send(8'h01); // Write command - uart_send(8'h01); // Length - uart_send(address[31:24]); // Address - uart_send(address[23:16]); - uart_send(address[15:8]); - uart_send(address[7:0]); - uart_send(value[31:24]); - uart_send(value[23:16]); - uart_send(value[15:8]); - uart_send(value[7:0]); - #100; + wishbone_adr = address; + wishbone_dat_w = value; + wishbone_cyc = 1; + wishbone_stb = 1; + wishbone_sel = 4'hF; + wishbone_we = 1; + + while (wishbone_ack == 0) + begin + #10; + end + + wishbone_cyc = 0; + wishbone_stb = 0; + + #10; end endtask @@ -229,52 +252,22 @@ module simsoctb; output [31:0] value; begin - uart_send(8'h02); // Read command - uart_send(8'h01); // Length - uart_send(address[31:24]); // Address - uart_send(address[23:16]); - uart_send(address[15:8]); - uart_send(address[7:0]); - uart_read(value[31:24]); - uart_read(value[23:16]); - uart_read(value[15:8]); - uart_read(value[7:0]); - end - endtask - - task uart_send; - input [7:0] data; - integer i; - - begin - uart_rx = 0; - #50; - for (i = 0; i < 8; i = i + 1) - begin - uart_rx <= data[i]; - #50; - end - uart_rx = 1; - #50; - end - endtask - - task uart_read; - output [7:0] data; - integer i; + wishbone_adr = address; + wishbone_we = 0; + wishbone_cyc = 1; + wishbone_stb = 1; + wishbone_sel = 4'hF; - begin - while (uart_tx) + while (wishbone_ack == 0) begin - #1; + #10; end - for (i = 0; i < 8; i = i+1) - begin - #50 data[i] = uart_tx; - end + value = wishbone_dat_r; + wishbone_cyc = 0; + wishbone_stb = 0; - #50; + #10; end endtask diff --git a/gram/simulation/uartbridge.py b/gram/simulation/uartbridge.py deleted file mode 100644 index d5a886e..0000000 --- a/gram/simulation/uartbridge.py +++ /dev/null @@ -1,305 +0,0 @@ -from nmigen import * -from nmigen.lib.io import pin_layout -from nmigen_soc import wishbone -from nmigen_stdio.serial import AsyncSerial, AsyncSerialTX -from nmigen.back.pysim import * - -import unittest - -__ALL__ = ["UARTBridge"] - -class UARTBridge(Elaboratable): - def __init__(self, divisor, pins): - self.bus = wishbone.Interface(addr_width=30, - data_width=32, granularity=8) - self._pins = pins - self._divisor = divisor - - def elaborate(self, platform): - m = Module() - - m.submodules.serial = serial = AsyncSerial(divisor=self._divisor, pins=self._pins) - - address_width = 32 - data_width = 32 - - cmd = Signal(8) - length = Signal(8) - address = Signal(address_width) - data = Signal(data_width) - bytes_count = Signal(range(data_width//8)) - words_count = Signal(8) - - m.d.comb += [ - self.bus.dat_w.eq(data), - self.bus.adr.eq(address), - ] - - with m.FSM(): - with m.State("Receive-Cmd"): - m.d.comb += serial.rx.ack.eq(1) - - # Reset registers - m.d.sync += [ - bytes_count.eq(data_width//8-1), - words_count.eq(0), - ] - - with m.If(serial.rx.rdy): - m.d.sync += cmd.eq(serial.rx.data) - m.next = "Receive-Length" - - with m.State("Receive-Length"): - m.d.comb += serial.rx.ack.eq(1) - - with m.If(serial.rx.rdy): - m.d.sync += length.eq(serial.rx.data) - m.next = "Receive-Address" - - with m.State("Receive-Address"): - m.d.comb += serial.rx.ack.eq(1) - - with m.If(serial.rx.rdy): - m.d.sync += [ - address.eq(Cat(serial.rx.data, address)), - bytes_count.eq(bytes_count-1), - ] - - with m.If(bytes_count == 0): - with m.Switch(cmd): - with m.Case(0x01): - m.next = "Handle-Write" - with m.Case(0x02): - m.next = "Handle-Read" - with m.Case(): - m.next = "Receive-Cmd" - - with m.State("Handle-Write"): - m.d.comb += serial.rx.ack.eq(1) - - with m.If(serial.rx.rdy): - m.d.sync += [ - data.eq(Cat(serial.rx.data, data)), - bytes_count.eq(bytes_count-1), - ] - with m.If(bytes_count == 0): - m.next = "Write-Data" - - with m.State("Write-Data"): - m.d.comb += [ - self.bus.stb.eq(1), - self.bus.we.eq(1), - self.bus.cyc.eq(1), - self.bus.sel.eq(0xF), - ] - - with m.If(self.bus.ack): - m.next = "Receive-Cmd" - - - with m.State("Handle-Read"): - m.d.comb += [ - self.bus.stb.eq(1), - self.bus.we.eq(0), - self.bus.cyc.eq(1), - self.bus.sel.eq(0xF), - ] - - with m.If(self.bus.ack): - m.d.sync += [ - bytes_count.eq(data_width//8-1), - data.eq(self.bus.dat_r), - ] - m.next = "Send-Data" - - with m.State("Send-Data"): - m.d.comb += serial.tx.ack.eq(1) - - with m.Switch(bytes_count): - for i in range(data_width//8): - with m.Case(i): - m.d.comb += serial.tx.data.eq(data[i*8:(i+1)*8]) - - with m.If(serial.tx.rdy): - m.next = "Send-Data-Wait" - - with m.State("Send-Data-Wait"): - with m.If(serial.tx.rdy): - m.d.sync += [ - bytes_count.eq(bytes_count-1), - ] - - with m.If(bytes_count == 0): - m.next = "Receive-Cmd" - with m.Else(): - m.next = "Send-Data" - - return m - -def serial_write(serial, val): - while not (yield serial.tx.rdy): - yield - - yield serial.tx.data.eq(val) - yield serial.tx.ack.eq(1) - yield - - while (yield serial.tx.rdy): - yield - - yield serial.tx.ack.eq(0) - - while not (yield serial.tx.rdy): - yield - - yield - -def serial_read(serial): - yield serial.rx.ack.eq(1) - - while not (yield serial.rx.rdy): - yield - - data = (yield serial.rx.data) - yield serial.rx.ack.eq(0) - - while (yield serial.rx.rdy): - yield - - return data - -class UARTBridgeTestCase(unittest.TestCase): - # Minimum 5, lowest makes the simulation faster - divisor = 5 - timeout = 10000 - - def test_read(self): - pins = Record([("rx", pin_layout(1, dir="i")), - ("tx", pin_layout(1, dir="o"))]) - dut = UARTBridge(divisor=self.divisor, pins=pins) - serial = AsyncSerial(divisor=self.divisor) - m = Module() - m.submodules.bridge = dut - m.submodules.serial = serial - m.d.comb += [ - pins.rx.i.eq(serial.tx.o), - serial.rx.i.eq(pins.tx.o), - ] - - def process(): - # Send read command - yield from serial_write(serial, 0x02) - yield - - # Length = 1 - yield from serial_write(serial, 0x01) - yield - - # Send 0x4000 as address - yield from serial_write(serial, 0x00) - yield - yield from serial_write(serial, 0x00) - yield - yield from serial_write(serial, 0x40) - yield - yield from serial_write(serial, 0x00) - yield - - # Handle wishbone request - timeout = 0 - while not (yield dut.bus.cyc): - yield - timeout += 1 - if timeout > self.timeout: - raise RuntimeError("Simulation timed out") - - # Ensure Wishbone address is the one we asked for - self.assertEqual((yield dut.bus.adr), 0x00004000) - self.assertFalse((yield dut.bus.we)) - - # Answer - yield dut.bus.dat_r.eq(0x0DEFACED) - yield dut.bus.ack.eq(1) - yield - - # Check response on UART - rx = yield from serial_read(serial) - self.assertEqual(rx, 0x0D) - rx = yield from serial_read(serial) - self.assertEqual(rx, 0xEF) - rx = yield from serial_read(serial) - self.assertEqual(rx, 0xAC) - rx = yield from serial_read(serial) - self.assertEqual(rx, 0xED) - - yield - - sim = Simulator(m) - with sim.write_vcd("test_uartbridge.vcd"): - sim.add_clock(1e-6) - sim.add_sync_process(process) - sim.run() - - def test_write(self): - pins = Record([("rx", pin_layout(1, dir="i")), - ("tx", pin_layout(1, dir="o"))]) - dut = UARTBridge(divisor=self.divisor, pins=pins) - serial = AsyncSerial(divisor=self.divisor) - m = Module() - m.submodules.bridge = dut - m.submodules.serial = serial - m.d.comb += [ - pins.rx.i.eq(serial.tx.o), - serial.rx.i.eq(pins.tx.o), - ] - - def process(): - # Send write command - yield from serial_write(serial, 0x01) - yield - - # Length = 1 - yield from serial_write(serial, 0x01) - yield - - # Send 0x4000 as address - yield from serial_write(serial, 0x00) - yield - yield from serial_write(serial, 0x00) - yield - yield from serial_write(serial, 0x40) - yield - yield from serial_write(serial, 0x00) - yield - - # Send 0xFEEDFACE as value - yield from serial_write(serial, 0xFE) - yield - yield from serial_write(serial, 0xED) - yield - yield from serial_write(serial, 0xFA) - yield - yield from serial_write(serial, 0xCE) - - # Handle wishbone request - timeout = 0 - while not (yield dut.bus.cyc): - yield - timeout += 1 - if timeout > self.timeout: - raise RuntimeError("Simulation timed out") - - # Ensure Wishbone address is the one we asked for - self.assertEqual((yield dut.bus.adr), 0x00004000) - self.assertEqual((yield dut.bus.dat_w), 0xFEEDFACE) - self.assertTrue((yield dut.bus.we)) - - # Answer - yield dut.bus.ack.eq(1) - yield - - sim = Simulator(m) - with sim.write_vcd("test_uartbridge.vcd"): - sim.add_clock(1e-6) - sim.add_sync_process(process) - sim.run() -- 2.30.2