X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fspec%2Fiomux.py;h=0351fbe064d0687bb9cc2adeb9dd6a4cc7ea65ec;hb=HEAD;hp=e310ed95d1fc2b40e4fd6772c3274f413eb36694;hpb=53b5fab0feaf518c6db9c404c4406c3116e707c3;p=pinmux.git diff --git a/src/spec/iomux.py b/src/spec/iomux.py index e310ed9..0351fbe 100644 --- a/src/spec/iomux.py +++ b/src/spec/iomux.py @@ -5,95 +5,176 @@ testing, however it could also be used as an actual GPIO peripheral Modified for use with pinmux, will probably change the class name later. """ -from random import randint -from math import ceil, floor +from random import randint, shuffle +#from math import ceil, floor from nmigen import Elaboratable, Module, Signal, Record, Array, Cat from nmigen.hdl.rec import Layout from nmigen.utils import log2_int from nmigen.cli import rtlil -from soc.minerva.wishbone import make_wb_layout +#from soc.minerva.wishbone import make_wb_layout from nmutil.util import wrap -from soc.bus.test.wb_rw import wb_read, wb_write +#from soc.bus.test.wb_rw import wb_read, wb_write from nmutil.gtkw import write_gtkw cxxsim = False if cxxsim: - from nmigen.sim.cxxsim import Simulator, Settle + from nmigen.sim.cxxsim import Simulator, Settle, Delay else: - from nmigen.sim import Simulator, Settle + from nmigen.sim import Simulator, Settle, Delay io_layout = (("i", 1), ("oe", 1), ("o", 1) ) -class IOMuxBlock(Elaboratable): +# This block produces an N-to-1 mux with N 3-bit periph ports and one pad port. +# The peripheral ports are intended to be wired to peripheral functions, +# while the pad port will connect to the I/O pad. +# Peripheral and output ports have o/oe/i signals, and the port signal is used +# to select between the peripheral ports. +class IOMuxBlockSingle(Elaboratable): - def __init__(self): - print("IO Mux Block") - self.n_banks = 4 - self.bank = Signal(log2_int(self.n_banks)) + def __init__(self, n_ports=4): + print("1-bit IO Mux Block") + self.n_ports = n_ports + portsize = n_ports.bit_length() + self.port = Signal(portsize) temp = [] - for i in range(self.n_banks): - temp_str = "bank{}".format(i) - temp.append(Record(name=temp_str, layout=io_layout)) - self.bank_ports = Array(temp) + for i in range(self.n_ports): + name = "port%d" % i + temp.append(Record(name=name, layout=io_layout)) + self.periph_ports = Array(temp) self.out_port = Record(name="IO", layout=io_layout) - #self.b0 = Record(name="b0", layout=io_layout) - #self.b1 = Record(name="b1", layout=io_layout) - def elaborate(self, platform): m = Module() comb, sync = m.d.comb, m.d.sync - bank = self.bank - bank_ports = self.bank_ports - #b0 = self.b0 - #b1 = self.b1 + port = self.port + periph_ports = self.periph_ports out_port = self.out_port - sync += out_port.o.eq(bank_ports[0].o) - sync += out_port.oe.eq(bank_ports[0].oe) - sync += bank_ports[0].i.eq(out_port.i) - # Connect IO Pad output port to one of the peripheral IOs # Connect peripheral inputs to the IO pad input + comb += self.out_port.o.eq(self.periph_ports[port].o) + comb += self.out_port.oe.eq(self.periph_ports[port].oe) - bank_range = range(self.n_banks) - - #with m.Switch(bank): - - for cur_bank in bank_range: - sync += out_port.o.eq(bank_ports[cur_bank].o) - sync += out_port.oe.eq(bank_ports[cur_bank].oe) - sync += bank_ports[cur_bank].i.eq(out_port.i) - - temp_list = list(bank_range) - temp_list.pop(temp_list.index(cur_bank)) - print("Banks with input hardwired to zero: {}".format(temp_list)) - for j in range(len(temp_list)): - unused_bank = temp_list[j] - sync += bank_ports[unused_bank].i.eq(0) + comb += self.periph_ports[port].i.eq(self.out_port.i) return m + def connect_port_to_io(self, domain, port_arg): + domain += self.out_port.o.eq(self.periph_ports[port_arg].o) + domain += self.out_port.oe.eq(self.periph_ports[port_arg].oe) + domain += self.periph_ports[port_arg].i.eq(self.out_port.i) + def __iter__(self): """ Get member signals for Verilog form. """ for field in self.out_port.fields.values(): yield field - for bank in range(len(self.bank_ports)): - for field in self.bank_ports[bank].fields.values(): + for port in range(self.n_ports): + for field in self.periph_ports[port].fields.values(): yield field - yield self.bank + yield self.port def ports(self): return list(self) -def gen_gtkw_doc(module_name, n_banks, filename): +# Method to test a particular peripheral port +# when rand_order is True, previous and consecutive ports are +# random (but NOT equal to given port) +def test_single_port(dut, port, rand_order=True, delay=1e-6): + if rand_order: + print("Randomising the prev and next ports") + prev_port=port + while(prev_port == port): + prev_port = randint(0, dut.n_ports-1) + next_port=port + while(next_port == port): + next_port = randint(0, dut.n_ports-1) + else: + # Set the prev and next ports as consecutive ports + if port == 0: + prev_port = dut.n_ports - 1 + else: + prev_port = port - 1 + + if port == dut.n_ports: + next_port = 0 + else: + next_port = port + 1 + + print("Prev=%d, Given=%d, Next=%d" % (prev_port, port, next_port)) + + # Clear o/oe, delay, set port i + # Set to previous port, delay + # Assert port i == 0 + # Set to desired port + # Assert port i == 1 + # Set o/oe, delay + # Assert o, oe == 1 + # Set to next port, delay + # Assert port i == 0 + yield dut.periph_ports[port].o.eq(0) + yield Delay(delay) + yield dut.periph_ports[port].oe.eq(0) + yield Delay(delay) + yield dut.out_port.i.eq(1) + yield Delay(delay) + + yield dut.port.eq(prev_port) + yield Delay(delay) + + test_i = yield dut.periph_ports[port].i + assert(test_i == 0) + + yield dut.port.eq(port) + yield Delay(delay) + + test_o = yield dut.out_port.o + test_oe = yield dut.out_port.oe + test_i = yield dut.periph_ports[port].i + assert(test_o == 0) + assert(test_oe == 0) + assert(test_i == 1) + + yield dut.periph_ports[port].o.eq(1) + yield Delay(delay) + yield dut.periph_ports[port].oe.eq(1) + yield Delay(delay) + + test_o = yield dut.out_port.o + test_oe = yield dut.out_port.oe + assert(test_o == 1) + assert(test_oe == 1) + + yield dut.port.eq(next_port) + yield Delay(delay) + + test_i = yield dut.periph_ports[port].i + assert(test_i == 0) + +def test_iomux(dut, rand_order=True): + print("------START----------------------") + #print(dir(dut.periph_ports[0])) + #print(dut.periph_ports[0].fields) + + # Produce a test list of port values + test_port_vec = list(range(0, dut.n_ports)) + #print(test_port_vec) + # Randomise for wider testing + if rand_order: + shuffle(test_port_vec) + #print(test_port_vec) + for i in range(dut.n_ports): + yield from test_single_port(dut, test_port_vec[i], rand_order) + + print("Finished the 1-bit IO mux block test!") + +def gen_gtkw_doc(module_name, n_ports, filename): # GTKWave doc generation style = { '': {'base': 'hex'}, @@ -104,21 +185,33 @@ def gen_gtkw_doc(module_name, n_banks, filename): # Create a trace list, each block expected to be a tuple() traces = [] - for bank in range(0, n_banks): - temp_traces = ('Bank{}'.format(bank), [ - ('bank{}__i'.format(bank), 'in'), - ('bank{}__o'.format(bank), 'out'), - ('bank{}__oe'.format(bank), 'out') + for port in range(0, n_ports): + temp_traces = ('Bank%d' % port, [ + ('port%d__i' % port, 'in'), + ('port%d__o' % port, 'out'), + ('port%d__oe' % port, 'out') ]) traces.append(temp_traces) + + temp_traces = ('Misc', [ + ('port[%d:0]' % ((n_ports-1).bit_length()-1), 'in') + ]) + traces.append(temp_traces) + temp_traces = ('IO port to pad', [ + ('IO__i', 'in'), + ('IO__o', 'out'), + ('IO__oe', 'out') + ]) + traces.append(temp_traces) #print(traces) write_gtkw(filename+".gtkw", filename+".vcd", traces, style, module=module_name) -def sim_iomux(): - filename = "test_pinmux" # Doesn't include extension - dut = IOMuxBlock() +def sim_iomux(rand_order=True): + filename = "test_iomux" # Doesn't include extension + n_ports = 8 + dut = IOMuxBlockSingle(n_ports) vl = rtlil.convert(dut, ports=dut.ports()) with open(filename+".il", "w") as f: f.write(vl) @@ -127,50 +220,16 @@ def sim_iomux(): m.submodules.pinmux = dut sim = Simulator(m) - sim.add_clock(1e-6) - sim.add_sync_process(wrap(test_iomux(dut))) + sim.add_process(wrap(test_iomux(dut, rand_order))) sim_writer = sim.write_vcd(filename+".vcd") with sim_writer: sim.run() - gen_gtkw_doc("top.pinmux", dut.n_banks, filename) + gen_gtkw_doc("top.pinmux", dut.n_ports, filename) + -def test_iomux(dut): - print("------START----------------------") - #print(dir(dut.bank_ports[0])) - #print(dut.bank_ports[0].fields) - #for (name, signal) in dut.b0.fields.items(): - # print(name, signal) - #print(dir(dut.bank_ports)) - #print(dut.bank_ports.__len__()) - #for bank in range(len(dut.bank_ports)): - # for values in dut.bank_ports[bank].fields.values(): - # print(values) - yield dut.bank_ports[0].o.eq(1) - yield dut.bank.eq(0) - yield - yield dut.bank_ports[0].o.eq(1) - yield - yield - yield dut.bank_ports[1].o.eq(1) - yield - yield dut.bank_ports[0].oe.eq(1) - yield - yield dut.bank.eq(1) - yield - - yield dut.bank_ports[0].o.eq(0) - yield - yield dut.bank_ports[1].o.eq(0) - yield - yield dut.bank_ports[1].oe.eq(1) - yield - yield dut.bank.eq(0) - yield - - print("Finished the IO mux block test!") if __name__ == '__main__': - sim_iomux() + sim_iomux(rand_order=True)