Wire directly to the Wishbone bus, making simulations faster and reduce the chances...
authorJean THOMAS <git0@pub.jeanthomas.me>
Mon, 27 Jul 2020 12:02:04 +0000 (14:02 +0200)
committerJean THOMAS <git0@pub.jeanthomas.me>
Mon, 27 Jul 2020 12:02:04 +0000 (14:02 +0200)
gram/simulation/simsoc.py
gram/simulation/simsoctb.v
gram/simulation/uartbridge.py [deleted file]

index abfded248fc20d921a522ad3bb5358e78e523a83..2379715cbd7bf9f5e43001ed154a8e9700e94b64 100644 (file)
@@ -1,6 +1,7 @@
 # This file is Copyright (c) 2020 LambdaConcept <contact@lambdaconcept.com>
 
 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
index c9546c35f8d133be7d074350c9b72a3115126d4e..4d7ce64ef224659446bb5f9713bf8f2632a389fa 100644 (file)
@@ -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 (file)
index d5a886e..0000000
+++ /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()