X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fspec%2Fsimple_gpio.py;h=08ca522e244d15b30709e6474dbcd3d2f0df416d;hb=523336e5e6fb60185c4e0e3cdb6ce4d192db858c;hp=57cfeffa3503f80ac5526ab75d4199fdd28371be;hpb=1752fc41a7e1648f8a765199ed5903c925db8e0a;p=pinmux.git diff --git a/src/spec/simple_gpio.py b/src/spec/simple_gpio.py index 57cfeff..08ca522 100644 --- a/src/spec/simple_gpio.py +++ b/src/spec/simple_gpio.py @@ -45,19 +45,27 @@ gpio_layout = (("i", 1), class SimpleGPIO(Elaboratable): def __init__(self, wordsize=4, n_gpio=16): - print("SimpleGPIO: WB Data # of bytes: {0}, # of GPIOs: {1}" - .format(wordsize, n_gpio)) self.wordsize = wordsize self.n_gpio = n_gpio + self.n_rows = ceil(self.n_gpio / self.wordsize) + print("SimpleGPIO: WB Data # of bytes: {0}, #GPIOs: {1}, Rows: {2}" + .format(self.wordsize, self.n_gpio, self.n_rows)) class Spec: pass spec = Spec() spec.addr_wid = 30 spec.mask_wid = 4 spec.reg_wid = wordsize*8 # 32 self.bus = Record(make_wb_layout(spec), name="gpio_wb") + self.wb_rd_data_reg = Signal(self.wordsize*8) # same len as WB bus #print("CSRBUS layout: ", csrbus_layout) - # create array - probably a cleaner way to do this... + # MultiCSR read and write buses + temp = [] + for i in range(self.wordsize): + temp_str = "rd_word{}".format(i) + temp.append(Record(name=temp_str, layout=csrbus_layout)) + self.rd_multicsr = Array(temp) + temp = [] for i in range(self.wordsize): temp_str = "word{}".format(i) @@ -77,80 +85,117 @@ class SimpleGPIO(Elaboratable): bus = self.bus wb_rd_data = bus.dat_r wb_wr_data = bus.dat_w + wb_rd_data_reg = self.wb_rd_data_reg wb_ack = bus.ack gpio_ports = self.gpio_ports multi = self.multicsrbus - - comb += wb_ack.eq(0) - - # log2_int(1) will give 0, which wouldn't work? - if (self.n_gpio == 1): - row_start = Signal(1) - else: - row_start = Signal(log2_int(self.n_gpio)) + rd_multi = self.rd_multicsr # Flag for indicating rd/wr transactions new_transaction = Signal(1) - #print("Types:") - #print("gpio_addr: ", type(gpio_addr)) - # One address used to configure CSR, set output, read input with m.If(bus.cyc & bus.stb): - comb += wb_ack.eq(1) # always ack - # Probably wasteful - sync += row_start.eq(bus.adr * self.wordsize) + sync += wb_ack.eq(1) # always ack, always delayed + # TODO: is this needed anymore? sync += new_transaction.eq(1) + # Concatinate the GPIO configs that are on the same "row" or + # address and send + multi_cat = [] + for i in range(0, self.wordsize): + multi_cat.append(rd_multi[i]) + sync += wb_rd_data_reg.eq(Cat(multi_cat)) with m.If(bus.we): # write # Configure CSR for byte in range(0, self.wordsize): + # TODO: wasteful... convert to Cat(), somehow sync += multi[byte].eq(wb_wr_data[byte*8:8+byte*8]) - with m.Else(): # read - # Concatinate the GPIO configs that are on the same "row" or - # address and send - multi_cat = [] - for i in range(0, self.wordsize): - multi_cat.append(multi[i]) - comb += wb_rd_data.eq(Cat(multi_cat)) with m.Else(): sync += new_transaction.eq(0) + sync += wb_ack.eq(0) + + with m.If(wb_ack): # read (and acked) + comb += wb_rd_data.eq(wb_rd_data_reg) + + self.connect_gpio_to_rd_bus(m, sync, bus.adr, gpio_ports, rd_multi) # Only update GPIOs config if a new transaction happened last cycle # (read or write). Always lags from multi csrbus by 1 clk cycle, most # sane way I could think of while using Record(). with m.If(new_transaction): - # This is a complex case, not needed atm - if self.n_gpio > self.wordsize: + self.connect_wr_bus_to_gpio(m, sync, bus.adr, gpio_ports, multi) + + return m + + def connect_wr_bus_to_gpio(self, module, domain, addr, gp, multi): + if self.n_gpio > self.wordsize: + print("#GPIOs is greater than, and is a multiple of WB wordsize") + # Case where all gpios fit within full words + if self.n_gpio % self.wordsize == 0: + for byte in range(self.wordsize): + with module.If(addr[0]): + self.wr_connect_one_byte(module, domain, gp, multi, + byte, self.wordsize) + with module.Else(): + self.wr_connect_one_byte(module, domain, gp, multi, + byte, 0) + else: + # TODO: This is a complex case, not needed atm + print("#GPIOs is greater than WB wordsize") + print("But not fully fitting in words...") print("NOT IMPLEMENTED THIS CASE") - """ - for byte in range(0, self.wordsize): - if ((row_start+byte) < Const(self.n_gpio)): - sync += gpio_ports[row+byte].oe.eq(multi[byte].oe) - sync += gpio_ports[row+byte].puen.eq(multi[byte].puen) - sync += gpio_ports[row+byte].pden.eq(multi[byte].pden) - # prevent output being set if GPIO configured as i - # TODO: No checking is done if ie/oe high together - with m.If(gpio_ports[row+byte].oe): - sync += gpio_ports[row+byte].o.eq(multi[byte].io) - with m.Else(): - sync += multi[byte].io.eq(gpio_ports[row+byte].i) - sync += gpio_ports[row+byte].bank.eq(multi[byte].bank) - """ raise + else: + print("#GPIOs is less or equal to WB wordsize (in bytes)") + for byte in range(self.n_gpio): + self.wr_connect_one_byte(module, domain, gp, multi, byte, 0) + + def connect_gpio_to_rd_bus(self, module, domain, addr, gp, multi): + if self.n_gpio > self.wordsize: + print("#GPIOs is greater than, and is a multiple of WB wordsize") + # Case where all gpios fit within full words + if self.n_gpio % self.wordsize == 0: + for byte in range(self.wordsize): + with module.If(addr[0]): + self.rd_connect_one_byte(module, domain, gp, multi, byte, self.wordsize) + with module.Else(): + self.rd_connect_one_byte(module, domain, gp, multi, byte, 0) else: - for byte in range(self.n_gpio): - sync += gpio_ports[byte].oe.eq(multi[byte].oe) - sync += gpio_ports[byte].puen.eq(multi[byte].puen) - sync += gpio_ports[byte].pden.eq(multi[byte].pden) - # Check to prevent output being set if GPIO configured as i - # TODO: No checking is done if ie/oe high together - with m.If(multi[byte].oe): # gpio_ports[byte].oe): - sync += gpio_ports[byte].o.eq(multi[byte].io) - with m.Else(): - sync += multi[byte].io.eq(gpio_ports[byte].i) - sync += gpio_ports[byte].bank.eq(multi[byte].bank) - return m + # TODO: This is a complex case, not needed atm + print("#GPIOs is greater than WB wordsize") + print("NOT IMPLEMENTED THIS CASE") + raise + else: + print("#GPIOs is less or equal to WB wordsize (in bytes)") + for byte in range(self.n_gpio): + self.rd_connect_one_byte(module, domain, gp, multi, byte, 0) + + def rd_connect_one_byte(self, module, domain, gp, multi, byte, offset): + domain += multi[byte].oe.eq(gp[byte+offset].oe) + domain += multi[byte].puen.eq(gp[byte+offset].puen) + domain += multi[byte].pden.eq(gp[byte+offset].pden) + with module.If(gp[byte+offset].oe): + domain += multi[byte].ie.eq(0) + domain += multi[byte].io.eq(gp[byte+offset].o) + with module.Else(): + domain += multi[byte].ie.eq(1) # Return GPIO as i by default + domain += multi[byte].io.eq(gp[byte+offset].i) + + domain += multi[byte].bank.eq(gp[byte+offset].bank) + + def wr_connect_one_byte(self, module, domain, gp, multi, byte, offset): + domain += gp[byte+offset].oe.eq(multi[byte].oe) + domain += gp[byte+offset].puen.eq(multi[byte].puen) + domain += gp[byte+offset].pden.eq(multi[byte].pden) + # prevent output being set if GPIO configured as i + # TODO: No checking is done if ie/oe high together + with module.If(multi[byte].oe): + domain += gp[byte+offset].o.eq(multi[byte].io) + with module.Else(): + domain += gp[byte+offset].o.eq(0) + domain += gp[byte+offset].bank.eq(multi[byte].bank) + def __iter__(self): for field in self.bus.fields.values(): @@ -162,13 +207,14 @@ class SimpleGPIO(Elaboratable): def ports(self): return list(self) +""" def gpio_test_in_pattern(dut, pattern): num_gpios = len(dut.gpio_ports) print("Test pattern:") print(pattern) for pat in range(0, len(pattern)): for gpio in range(0, num_gpios): - yield from gpio_set_in_pad(dut, gpio, pattern[pat]) + yield gpio_set_in_pad(dut, gpio, pattern[pat]) yield temp = yield from gpio_rd_input(dut, gpio) print("Pattern: {0}, Reading {1}".format(pattern[pat], temp)) @@ -176,6 +222,7 @@ def gpio_test_in_pattern(dut, pattern): pat += 1 if pat == len(pattern): break +""" def test_gpio_single(dut, gpio, use_random=True): oe = 1 @@ -472,6 +519,7 @@ def gen_gtkw_doc(n_gpios, wordsize, filename): ('gpio_wb__we', 'in'), ('gpio_wb__adr[27:0]', 'in'), ('gpio_wb__dat_w[{}:0]'.format(wb_data_width-1), 'in'), + ('wb_rd_data_reg[{}:0]'.format(wb_data_width-1), ''), ('gpio_wb__dat_r[{}:0]'.format(wb_data_width-1), 'out'), ('gpio_wb__ack', 'out'), ]) @@ -480,11 +528,25 @@ def gen_gtkw_doc(n_gpios, wordsize, filename): gpio_internal_traces = ('Internal', [ ('clk', 'in'), ('new_transaction'), - ('row_start[2:0]'), ('rst', 'in') ]) traces.append(gpio_internal_traces) + traces.append({'comment': 'Multi-byte GPIO config read bus'}) + for word in range(0, wordsize): + prefix = "rd_word{}__".format(word) + single_word = [] + word_signals = [] + single_word.append('Word{}'.format(word)) + word_signals.append((prefix+'bank[{}:0]'.format(NUMBANKBITS-1))) + word_signals.append((prefix+'ie')) + word_signals.append((prefix+'io')) + word_signals.append((prefix+'oe')) + word_signals.append((prefix+'pden')) + word_signals.append((prefix+'puen')) + single_word.append(word_signals) + traces.append(tuple(single_word)) + traces.append({'comment': 'Multi-byte GPIO config bus'}) for word in range(0, wordsize): prefix = "word{}__".format(word) @@ -548,7 +610,7 @@ def test_gpioman(dut): gpios.print_info() #gpios._parse_gpio_arg("all") #gpios._parse_gpio_arg("0") - gpios._parse_gpio_arg("1-3") + #gpios._parse_gpio_arg("1-3") #gpios._parse_gpio_arg("20") oe = 1 @@ -559,7 +621,7 @@ def test_gpioman(dut): bank = 3 yield from gpios.config("0-3", oe=1, ie=0, puen=0, pden=1, outval=0, bank=2) ie = 1 - yield from gpios.config("4-7", oe=0, ie=1, puen=0, pden=1, outval=0, bank=2) + yield from gpios.config("4-7", oe=0, ie=1, puen=0, pden=1, outval=0, bank=6) yield from gpios.set_out("0-3", outval=1) #yield from gpios.rd_all()