# 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
from gram.frontend.wishbone import gramWishbone
from icarusecpix5platform import IcarusECPIX5Platform
-from uartbridge import UARTBridge
from crg import *
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))
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
#5;
end
- // UART
- reg uart_rx;
- wire uart_tx;
-
// DDR3 init
wire dram_ck;
wire dram_cke;
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 (
.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
$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);
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);
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
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
+++ /dev/null
-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()