X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fspec%2Fstage2.py;h=221961695b450609054ff1172ac7ee9fbbdbb0f8;hb=1e599e3a6ef092f5dd5d0c85e235bce0fd0b4e4a;hp=8eb1f92037ce4b1f9cb848ad63c27f95f7cd9801;hpb=ec0be6c8d3e83ddbd210c1c87babeae882c49cd0;p=pinmux.git diff --git a/src/spec/stage2.py b/src/spec/stage2.py index 8eb1f92..2219616 100644 --- a/src/spec/stage2.py +++ b/src/spec/stage2.py @@ -19,6 +19,8 @@ else: from nmigen.sim import Simulator, Settle, Delay from iomux import IOMuxBlockSingle +from base import PinSpec +from jtag import iotypes io_layout = (("i", 1), ("oe", 1), @@ -40,92 +42,73 @@ I2C_BANK = 2 Really basic example, uart tx/rx and i2c sda/scl pinmux """ class ManPinmux(Elaboratable): - def __init__(self, pad_names): + def __init__(self, requested): print("Test Manual Pinmux!") + + self.requested = requested self.n_banks = 4 - self.iomux1 = IOMuxBlockSingle(self.n_banks) - self.iomux2 = IOMuxBlockSingle(self.n_banks) - """ - self.pads = {} - for pad in pad_names: - self.pads[pad] = Record(name=pad, layout=io_layout) - self.gpio = {"0": Record(name="gp0", layout=io_layout), - "1": Record(name="gp1", layout=io_layout) - } - self.uart = Record(name="uart", layout=uart_layout) - self.i2c = {"sda": Record(name="sda", layout=io_layout), - "scl": Record(name="scl", layout=io_layout) - } - """ self.bank = Signal(log2_int(self.n_banks)) - self.pads = {pad_names[0]:{}, pad_names[1]:{}} - self.pads["N1"]["pad"] = Record(name=pad_names[0], layout=io_layout) - self.pads["N1"]["mux%d" % GPIO_BANK] = Record(name="gp0", - layout=io_layout) - self.pads["N1"]["mux%d" % UART_BANK] = Record(name="tx", - layout=uart_tx_layout) - self.pads["N1"]["mux%d" % I2C_BANK] = Record(name="sda", - layout=io_layout) - self.pads["N2"]["pad"] = Record(name=pad_names[1], layout=io_layout) - self.pads["N2"]["mux%d" % GPIO_BANK] = Record(name="gp1", - layout=io_layout) - self.pads["N2"]["mux%d" % UART_BANK] = Signal(name="rx") # One signal - self.pads["N2"]["mux%d" % I2C_BANK] = Record(name="scl", - layout=io_layout) + self.pads = {} + self.muxes = {} + # Automatically create the necessary periph/pad Records/Signals + # depending on the given dict specification + for pad in self.requested.keys(): + self.pads[pad] = {} + self.pads[pad]["pad"] = Record(name=pad, layout=io_layout) + self.muxes[pad] = IOMuxBlockSingle(self.n_banks) + for mux in self.requested[pad].keys(): + periph = self.requested[pad][mux][0] + unit = self.requested[pad][mux][1] + sig = self.requested[pad][mux][2][:-1] + sig_type = iotypes[self.requested[pad][mux][2][-1]] + #print(sig, sig_type) + if sig_type == iotypes['*']: + self.pads[pad][mux] = Record(name="%s%d" % (sig, unit), + layout=io_layout) + elif sig_type == iotypes['+']: + self.pads[pad][mux] = Signal(name="%s%d_o" % (sig, unit)) + elif sig_type == iotypes['-']: + self.pads[pad][mux] = Signal(name="%s%d_i" % (sig, unit)) + print(self.pads) def elaborate(self, platform): m = Module() comb, sync = m.d.comb, m.d.sync - iomux1 = self.iomux1 - iomux2 = self.iomux2 - m.submodules.iomux1 = iomux1 - m.submodules.iomux2 = iomux2 - - pads = self.pads - pad0 = self.pads["N1"]["pad"] - gp0 = self.pads["N1"]["mux%d" % GPIO_BANK] - gp1 = self.pads["N2"]["mux%d" % GPIO_BANK] - tx = self.pads["N1"]["mux%d" % UART_BANK] - rx = self.pads["N2"]["mux%d" % UART_BANK] - sda = self.pads["N1"]["mux%d" % I2C_BANK] - scl = self.pads["N2"]["mux%d" % I2C_BANK] + muxes = self.muxes bank = self.bank + pads = self.pads + for pad in pads.keys(): + m.submodules[pad+"_mux"] = muxes[pad] + # all muxes controlled by the same multi-bit signal + comb += muxes[pad].bank.eq(bank) - comb += iomux1.bank.eq(bank) - comb += iomux2.bank.eq(bank) + # print(self.requested) + # print(self.pads) # --------------------------- - # This section is muxing only - doesn'care about pad names + # This section connects the periphs to the assigned banks # --------------------------- - # gpio - gpio0 on Pad1, gpio1 on Pad2 - comb += iomux1.bank_ports[GPIO_BANK].o.eq(gp0.o) - comb += iomux1.bank_ports[GPIO_BANK].oe.eq(gp0.oe) - comb += gp0.i.eq(iomux1.bank_ports[GPIO_BANK].i) - comb += iomux2.bank_ports[GPIO_BANK].o.eq(gp1.o) - comb += iomux2.bank_ports[GPIO_BANK].oe.eq(gp1.oe) - comb += gp1.i.eq(iomux2.bank_ports[GPIO_BANK].i) - # uart Pad 1 tx, Pad 2 rx - comb += iomux1.bank_ports[UART_BANK].o.eq(tx.o) - comb += iomux1.bank_ports[UART_BANK].oe.eq(tx.oe) - comb += rx.eq(iomux2.bank_ports[UART_BANK].i) - # i2c Pad 1 sda, Pad 2 scl - comb += iomux1.bank_ports[I2C_BANK].o.eq(sda.o) - comb += iomux1.bank_ports[I2C_BANK].oe.eq(sda.oe) - comb += sda.i.eq(iomux1.bank_ports[I2C_BANK].i) - comb += iomux2.bank_ports[I2C_BANK].o.eq(scl.o) - comb += iomux2.bank_ports[I2C_BANK].oe.eq(scl.oe) - comb += scl.i.eq(iomux2.bank_ports[I2C_BANK].i) - + for pad in pads.keys(): + for mux in self.requested[pad].keys(): + periph = self.requested[pad][mux][0] + num = int(mux[3]) + sig = self.requested[pad][mux][2][:-1] + sig_type = iotypes[self.requested[pad][mux][2][-1]] + if sig_type == iotypes['*']: + comb += muxes[pad].bank_ports[num].o.eq(pads[pad][mux].o) + comb += muxes[pad].bank_ports[num].oe.eq(pads[pad][mux].oe) + comb += pads[pad][mux].i.eq(muxes[pad].bank_ports[num].i) + elif sig_type == iotypes['+']: + comb += muxes[pad].bank_ports[num].o.eq(pads[pad][mux]) + elif sig_type == iotypes['-']: + comb += pads[pad][mux].eq(muxes[pad].bank_ports[num].i) # --------------------------- # Here is where the muxes are assigned to the actual pads # --------------------------- - # TODO: for-loop to autoconnect muxes to pads (n_pads var?) - comb += pads['N1']["pad"].o.eq(iomux1.out_port.o) - comb += pads['N1']["pad"].oe.eq(iomux1.out_port.oe) - comb += iomux1.out_port.i.eq(pads['N1']["pad"].i) - comb += pads['N2']["pad"].o.eq(iomux2.out_port.o) - comb += pads['N2']["pad"].oe.eq(iomux2.out_port.oe) - comb += iomux2.out_port.i.eq(pads['N2']["pad"].i) + for pad in pads.keys(): + comb += pads[pad]["pad"].o.eq(muxes[pad].out_port.o) + comb += pads[pad]["pad"].oe.eq(muxes[pad].out_port.oe) + comb += muxes[pad].out_port.i.eq(pads[pad]["pad"].i) return m @@ -133,12 +116,12 @@ class ManPinmux(Elaboratable): for pad in list(self.pads.keys()): for field in self.pads[pad]["pad"].fields.values(): yield field - #for field in self.uart.fields.values(): - # yield field - #for field in self.i2c["sda"].fields.values(): - # yield field - #for field in self.i2c["scl"].fields.values(): - # yield field + for mux in self.pads[pad].keys(): + if type(self.pads[pad][mux]) == Signal: + yield self.pads[pad][mux] + else: + for field in self.pads[pad][mux].fields.values(): + yield field yield self.bank def ports(self): @@ -189,20 +172,21 @@ Input and output pads are different, so must specify both """ def uart_send(tx, rx, pad_tx, pad_rx, byte, delay=1e-6): # Drive uart tx - check the word seen at the Pad - yield tx.oe.eq(1) - yield tx.o.eq(1) + print(type(tx)) + #yield tx.oe.eq(1) + yield tx.eq(1) yield Delay(2*delay) - yield tx.o.eq(0) # start bit + yield tx.eq(0) # start bit yield Delay(delay) read = 0 # send one byte, lsb first for i in range(0, 8): bit = (byte >> i) & 0x1 - yield tx.o.eq(bit) + yield tx.eq(bit) yield Delay(delay) test_bit = yield pad_tx.o read |= (test_bit << i) - yield tx.o.eq(1) # stop bit + yield tx.eq(1) # stop bit yield Delay(delay) assert byte == read, f"UART Sent: %x | Pad Read: %x" % (byte, read) # Drive Pad i - check word at uart rx @@ -284,31 +268,136 @@ def i2c_send(sda, scl, sda_pad, byte, delay=1e-6): yield sda.o.eq(1) # 'release' the SDA line # Test the GPIO/UART/I2C connectivity -def test_man_pinmux(dut, pad_names): +def test_man_pinmux(dut, requested): + # TODO: Convert to automatic + # [{"pad":%s, "bank":%d}, {"pad":%s, "bank":%d},...] + #gpios = [{"padname":"N1", "bank":GPIO_BANK}, + # {"padname":"N2", "bank":GPIO_BANK}] + # [[txPAD, MUXx, rxPAD, MUXx],...] - diff banks not supported yet + uarts = [{"txpadname":"N1", "rxpadname":"N2", "bank":UART_BANK}] + # [[sdaPAD, MUXx, sclPAD, MUXx],...] - diff banks not supported yet + i2cs = [{"sdapadname":"N1", "sclpadname":"N2", "bank":I2C_BANK}] + + gpios = [] delay = 1e-6 + for pad in requested.keys(): + for mux in requested[pad].keys(): + periph = requested[pad][mux][0] + + if periph == "gpio": + # [{"padname":%s, "bank": %d}, ...] + gpios.append({"padname":pad, "bank": int(mux[3])}) + if periph == "uart": + # TODO: + pass + if periph == "i2c": + # TODO: + pass + print(gpios) # GPIO test - yield from set_bank(dut, GPIO_BANK) - yield from gpio(dut.pads["N1"]["mux%d" % GPIO_BANK], - dut.pads["N1"]["pad"], 0x5a5) - yield from gpio(dut.pads["N2"]["mux%d" % GPIO_BANK], - dut.pads["N2"]["pad"], 0x5a5) + for gpio_periph in gpios: + padname = gpio_periph["padname"] + gpio_bank = gpio_periph["bank"] + gp = dut.pads[padname]["mux%d" % gpio_bank] + pad = dut.pads[padname]["pad"] + yield from set_bank(dut, gpio_bank) + yield from gpio(gp, pad, 0x5a5) + # UART test - yield from set_bank(dut, UART_BANK) - yield from uart_send(dut.pads["N1"]["mux%d" % UART_BANK], - dut.pads["N2"]["mux%d" % UART_BANK], - dut.pads['N1']["pad"], dut.pads['N2']["pad"], 0x42) - #yield dut.pads['N2'].i.eq(0) - #yield Delay(delay) + for uart_periph in uarts: + txpadname = uart_periph["txpadname"] + rxpadname = uart_periph["rxpadname"] + uart_bank = uart_periph["bank"] + tx = dut.pads[txpadname]["mux%d" % uart_bank] + rx = dut.pads[rxpadname]["mux%d" % uart_bank] + txpad = dut.pads[txpadname]["pad"] + rxpad = dut.pads[rxpadname]["pad"] + yield from set_bank(dut, UART_BANK) + yield from uart_send(tx, rx, txpad, rxpad, 0x42) + # I2C test + for i2c_periph in i2cs: + sdapadname = i2c_periph["sdapadname"] + sclpadname = i2c_periph["sclpadname"] + i2c_bank = i2c_periph["bank"] + sda = dut.pads[sdapadname]["mux%d" % i2c_bank] + scl = dut.pads[sclpadname]["mux%d" % i2c_bank] + sdapad = dut.pads[sdapadname]["pad"] + yield from set_bank(dut, I2C_BANK) - yield from i2c_send(dut.pads["N1"]["mux%d" % I2C_BANK], - dut.pads["N2"]["mux%d" % I2C_BANK], - dut.pads['N1']["pad"], 0x67) + yield from i2c_send(sda, scl, sdapad, 0x67) + +def gen_gtkw_doc(module_name, requested, filename): + # GTKWave doc generation + style = { + '': {'base': 'hex'}, + 'in': {'color': 'orange'}, + 'out': {'color': 'yellow'}, + 'debug': {'module': 'top', 'color': 'red'} + } + # Create a trace list, each block expected to be a tuple() + traces = [] + temp = 0 + n_banks = 0 + for pad in requested.keys(): + temp = len(requested[pad].keys()) + if n_banks < temp: + n_banks = temp + temp_traces = ("Pad %s" % pad, []) + # Pad signals + temp_traces[1].append(('%s__i' % pad, 'in')) + temp_traces[1].append(('%s__o' % pad, 'out')) + temp_traces[1].append(('%s__oe' % pad, 'out')) + for mux in requested[pad].keys(): + periph = requested[pad][mux][0] + unit_num = requested[pad][mux][1] + if len(requested[pad][mux]) == 3: + pin = requested[pad][mux][2] + else: + pin = "io" + + if periph == "gpio": + temp_traces[1].append(('gp%d__i' % unit_num, 'in')) + temp_traces[1].append(('gp%d__o' % unit_num, 'out')) + temp_traces[1].append(('gp%d__oe' % unit_num, 'out')) + elif periph == "uart": + if pin == "tx": + temp_traces[1].append(('tx%d__o' % unit_num, 'out')) + temp_traces[1].append(('tx%d__oe' % unit_num, 'out')) + pass + elif pin == "rx": + temp_traces[1].append(('rx%d' % unit_num, 'in')) + pass + elif periph == "i2c": + temp_traces[1].append(('%s%d__i' % (pin, unit_num), 'in')) + temp_traces[1].append(('%s%d__o' % (pin, unit_num), 'out')) + temp_traces[1].append(('%s%d__oe' % (pin, unit_num), 'out')) + traces.append(temp_traces) + + # master bank signal + temp_traces = ('Misc', [ + ('bank[%d:0]' % ((n_banks-1).bit_length()-1), 'in') + ]) + traces.append(temp_traces) + + #print(traces) + + write_gtkw(filename+".gtkw", filename+".vcd", traces, style, + module=module_name) + def sim_man_pinmux(): filename = "test_man_pinmux" - pad_names = ["N1", "N2"] - dut = ManPinmux(pad_names) + requested = {"N1": {"mux%d" % GPIO_BANK: ["gpio", 0, '0*'], + "mux%d" % UART_BANK: ["uart", 0, 'tx+'], + "mux%d" % I2C_BANK: ["i2c", 0, 'sda*']}, + "N2": {"mux%d" % GPIO_BANK: ["gpio", 1, '*'], + "mux%d" % UART_BANK: ["uart", 0, 'rx-'], + "mux%d" % I2C_BANK: ["i2c", 0, 'scl*']}, + "N3": {"mux%d" % GPIO_BANK: ["gpio", 2, '0*']}, + "N4": {"mux%d" % GPIO_BANK: ["gpio", 3, '0*']} + } + dut = ManPinmux(requested) vl = rtlil.convert(dut, ports=dut.ports()) with open(filename+".il", "w") as f: f.write(vl) @@ -318,11 +407,72 @@ def sim_man_pinmux(): sim = Simulator(m) - sim.add_process(wrap(test_man_pinmux(dut, pad_names))) + sim.add_process(wrap(test_man_pinmux(dut, requested))) sim_writer = sim.write_vcd(filename+".vcd") with sim_writer: sim.run() - #gen_gtkw_doc("top.manpinmux", dut.n_banks, filename) + gen_gtkw_doc("top.manpinmux", dut.requested, filename) if __name__ == '__main__': - sim_man_pinmux() + sim_man_pinmux() + #pinbanks = [] + #fixedpins = [] + #function_names = [] + #testspec = PinSpec() + pinbanks = { + 'A': (4, 4), # (num of pads, num of banks)? + #'B': (18, 4), + #'C': (24, 1), + #'D': (93, 1), + } + fixedpins = { + 'POWER_GPIO': [ + 'VDD_GPIOB', + 'GND_GPIOB', + ]} + function_names = {'TWI0': 'I2C 0', + 'UART0': 'UART (TX/RX) 0', + } + ps = PinSpec(pinbanks, fixedpins, function_names) + # Unit number, (Bank, pin #), mux, start, num # pins + ps.gpio("", ('A', 0), 0, 0, 4) + ps.uart("0", ('A', 0), 1) + ps.i2c("0", ('A', 0), 2) + + print(dir(ps.gpio)) + #print(ps.gpio.pinouts, ps.gpio.bankspec, ps.gpio.pinfn, ps.gpio.fname) + """ + desc_dict_keys = ['UART0', 'TWI0', 'GPIOA_A0', 'GPIOA_A1', 'GPIOA_A2', 'GPIOA_A3'] + eint = [] + pwm = [] + desc = {'UART0': 'Basic serial TX/RX serial port', + 'TWI0': 'I2C interface', + 'GPIOA_A0': 'Test GPIO0', + 'GPIOA_A1': 'Test GPIO1', + 'GPIOA_A2': 'Test GPIO2', + 'GPIOA_A3': 'Test GPIO3'} + ps.add_scenario("Test Manual Pinmux", desc_dict_keys, eint, pwm, desc) + """ + print("---------------------------------") + #with open("test.mdwn", "w") as of: + # pinout, bankspec, pin_spec, fixedpins = ps.write(of) + #print("---------------------------------") + + bk = ps.pinbanks.keys() + for bank in bk: + muxwidth = ps.muxwidths[bank] + print(bank, muxwidth) + pinidx = sorted(ps.keys()) + for pin in pinidx: + print("---------------------------------") + print(pin) + pdata = ps.get(pin) + for mux in range(muxwidth): + if mux not in pdata: + print("Mux %d : NC" % mux) + else: + name, assigned_bank = pdata[mux] + print("Mux %d : %s" % (mux, name)) + + +