connect up Platform resources to pads
authorLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Sun, 28 Nov 2021 16:30:22 +0000 (16:30 +0000)
committerLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Sun, 28 Nov 2021 16:30:22 +0000 (16:30 +0000)
src/spec/testing_stage1.py

index 1c747a33a410a42d1532286faedad33c6cc07da4..464a9cf36e69680f1dfeeb6298c82e1112ae3d91 100644 (file)
@@ -2,6 +2,7 @@
 from nmigen.build.dsl import Resource, Subsignal, Pins
 from nmigen.build.plat import TemplatedPlatform
 from nmigen.build.res import ResourceManager, ResourceError
 from nmigen.build.dsl import Resource, Subsignal, Pins
 from nmigen.build.plat import TemplatedPlatform
 from nmigen.build.res import ResourceManager, ResourceError
+from nmigen.hdl.rec import Layout
 from nmigen import Elaboratable, Signal, Module, Instance
 from collections import OrderedDict
 from jtag import JTAG, resiotypes
 from nmigen import Elaboratable, Signal, Module, Instance
 from collections import OrderedDict
 from jtag import JTAG, resiotypes
@@ -115,11 +116,29 @@ def UARTResource(*args, rx, tx):
 
 def I2CResource(*args, scl, sda):
     io = []
 
 def I2CResource(*args, scl, sda):
     io = []
-    io.append(Subsignal("scl", Pins(scl, dir="io", assert_width=1)))
-    io.append(Subsignal("sda", Pins(sda, dir="io", assert_width=1)))
+    fmt = "%s_i %s_o %s_oe"
+    scl = fmt % (scl, scl, scl)
+    sda = fmt % (sda, sda, sda)
+    io.append(Subsignal("scl", Pins(scl, dir="io", assert_width=3)))
+    io.append(Subsignal("sda", Pins(sda, dir="io", assert_width=3)))
     return Resource.family(*args, default_name="i2c", ios=io)
 
 
     return Resource.family(*args, default_name="i2c", ios=io)
 
 
+def recurse_down(asicpad, jtagpad):
+    eqs = []
+    for asiclayout, jtaglayout in zip(asicpad.layout, jtagpad.layout):
+        apad = getattr(asicpad, asiclayout[0])
+        jpad = getattr(jtagpad, jtaglayout[0])
+        print ("recurse_down", asiclayout, jtaglayout, apad, jpad)
+        if isinstance(asiclayout[1], Layout):
+            eqs += recurse_down(apad, jpad)
+        elif asiclayout[0] == 'i':
+            eqs.append(jpad.eq(apad))
+        elif asiclayout[0] in ['o', 'oe']:
+            eqs.append(apad.eq(jpad))
+    return eqs
+
+
 # ridiculously-simple top-level module.  doesn't even have a sync domain
 # and can't have one until a clock has been established by ASICPlatform.
 class Blinker(Elaboratable):
 # ridiculously-simple top-level module.  doesn't even have a sync domain
 # and can't have one until a clock has been established by ASICPlatform.
 class Blinker(Elaboratable):
@@ -133,9 +152,18 @@ class Blinker(Elaboratable):
         self.jtag.padlookup = {}
         self.jtag.requests_made = []
         self.jtag.boundary_scan_pads = []
         self.jtag.padlookup = {}
         self.jtag.requests_made = []
         self.jtag.boundary_scan_pads = []
+        self.jtag.resource_table = {}
+        self.jtag.resource_table_pads = {}
+        self.jtag.eqs = []
         memory = Memory(width=32, depth=16)
         self.sram = SRAM(memory=memory, bus=self.jtag.wb)
 
         memory = Memory(width=32, depth=16)
         self.sram = SRAM(memory=memory, bus=self.jtag.wb)
 
+        for resource in resources:
+            print ("JTAG resource", resource)
+            if resource.name in ['clk', 'rst']: # hack
+                continue
+            self.add_jtag_request(resource.name, resource.number)
+
     def elaborate(self, platform):
         jtag_resources = self.jtag.pad_mgr.resources
         core_resources = self.jtag.core_mgr.resources
     def elaborate(self, platform):
         jtag_resources = self.jtag.pad_mgr.resources
         core_resources = self.jtag.core_mgr.resources
@@ -146,7 +174,7 @@ class Blinker(Elaboratable):
         count = Signal(5)
         m.d.sync += count.eq(count+1)
         print ("resources", platform, jtag_resources.items())
         count = Signal(5)
         m.d.sync += count.eq(count+1)
         print ("resources", platform, jtag_resources.items())
-        gpio = self.jtag_request(m, 'gpio')
+        gpio = self.jtag_request('gpio')
         print (gpio, gpio.layout, gpio.fields)
         # get the GPIO bank, mess about with some of the pins
         m.d.comb += gpio.gpio0.io.o.eq(1)
         print (gpio, gpio.layout, gpio.fields)
         # get the GPIO bank, mess about with some of the pins
         m.d.comb += gpio.gpio0.io.o.eq(1)
@@ -154,7 +182,7 @@ class Blinker(Elaboratable):
         m.d.comb += gpio.gpio1.io.oe.eq(count[4])
         m.d.sync += count[0].eq(gpio.gpio1.io.i)
         # get the UART resource, mess with the output tx
         m.d.comb += gpio.gpio1.io.oe.eq(count[4])
         m.d.sync += count[0].eq(gpio.gpio1.io.i)
         # get the UART resource, mess with the output tx
-        uart = self.jtag_request(m, 'uart')
+        uart = self.jtag_request('uart')
         print (uart, uart.fields)
         intermediary = Signal()
         m.d.comb += uart.tx.eq(intermediary)
         print (uart, uart.fields)
         intermediary = Signal()
         m.d.comb += uart.tx.eq(intermediary)
@@ -164,7 +192,10 @@ class Blinker(Elaboratable):
         # then add JTAG afterwards
         if platform is not None:
             for (name, number, dir, xdr) in self.jtag.requests_made:
         # then add JTAG afterwards
         if platform is not None:
             for (name, number, dir, xdr) in self.jtag.requests_made:
-                platform.request(name, number, dir=dir, xdr=xdr)
+                asicpad = platform.request(name, number, dir=dir, xdr=xdr)
+                jtagpad = self.jtag.resource_table_pads[(name, number)]
+                print ("jtagpad", jtagpad, jtagpad.layout)
+                m.d.comb += recurse_down(asicpad, jtagpad)
 
             # wire up JTAG otherwise we are in trouble (no clock)
             jtag = platform.request('jtag')
 
             # wire up JTAG otherwise we are in trouble (no clock)
             jtag = platform.request('jtag')
@@ -173,6 +204,8 @@ class Blinker(Elaboratable):
             m.d.comb += self.jtag.bus.tms.eq(jtag.tms)
             m.d.comb += jtag.tdo.eq(self.jtag.bus.tdo)
 
             m.d.comb += self.jtag.bus.tms.eq(jtag.tms)
             m.d.comb += jtag.tdo.eq(self.jtag.bus.tdo)
 
+        # add the eq assignments connecting up JTAG boundary scan to core
+        m.d.comb += self.jtag.eqs
         return m
 
     def ports(self):
         return m
 
     def ports(self):
@@ -185,7 +218,10 @@ class Blinker(Elaboratable):
         yield self.jtag.bus.tms
         yield from self.jtag.boundary_scan_pads
 
         yield self.jtag.bus.tms
         yield from self.jtag.boundary_scan_pads
 
-    def jtag_request(self, m, name, number=0, *, dir=None, xdr=None):
+    def jtag_request(self, name, number=0, *, dir=None, xdr=None):
+        return self.jtag.resource_table[(name, number)]
+
+    def add_jtag_request(self, name, number=0, *, dir=None, xdr=None):
         """request a Resource (e.g. name="uart", number=0) which will
         return a data structure containing Records of all the pins.
 
         """request a Resource (e.g. name="uart", number=0) which will
         return a data structure containing Records of all the pins.
 
@@ -237,7 +273,7 @@ class Blinker(Elaboratable):
             print ("existing pads", padlookup.keys())
             assert padpin.name not in padlookup # no overwrites allowed!
             assert padpin.name == corepin.name       # has to be the same!
             print ("existing pads", padlookup.keys())
             assert padpin.name not in padlookup # no overwrites allowed!
             assert padpin.name == corepin.name       # has to be the same!
-            padlookup[padpin.name] = (core, pad)        # store pad by pin name
+            padlookup[padpin.name] = pad        # store pad by pin name
 
             # now add the IO Shift Register.  first identify the type
             # then request a JTAG IOConn. we can't wire it up (yet) because
 
             # now add the IO Shift Register.  first identify the type
             # then request a JTAG IOConn. we can't wire it up (yet) because
@@ -257,9 +293,9 @@ class Blinker(Elaboratable):
                 print ("   jtag io core", io.core)
                 print ("   jtag io pad", io.pad)
                 # corepin is to be returned, here. so, connect jtag corein to it
                 print ("   jtag io core", io.core)
                 print ("   jtag io pad", io.pad)
                 # corepin is to be returned, here. so, connect jtag corein to it
-                m.d.comb += corepin.i.eq(io.core.i)
+                self.jtag.eqs += [corepin.i.eq(io.core.i)]
                 # and padpin to JTAG pad
                 # and padpin to JTAG pad
-                m.d.comb += io.pad.i.eq(padpin.i)
+                self.jtag.eqs += [io.pad.i.eq(padpin.i)]
                 self.jtag.boundary_scan_pads.append(padpin.i)
             elif padpin.dir == 'o':
                 print ("jtag_request add output pin", padpin)
                 self.jtag.boundary_scan_pads.append(padpin.i)
             elif padpin.dir == 'o':
                 print ("jtag_request add output pin", padpin)
@@ -267,9 +303,9 @@ class Blinker(Elaboratable):
                 print ("   jtag io core", io.core)
                 print ("   jtag io pad", io.pad)
                 # corepin is to be returned, here. connect it to jtag core out
                 print ("   jtag io core", io.core)
                 print ("   jtag io pad", io.pad)
                 # corepin is to be returned, here. connect it to jtag core out
-                m.d.comb += io.core.o.eq(corepin.o)
+                self.jtag.eqs += [io.core.o.eq(corepin.o)]
                 # and JTAG pad to padpin
                 # and JTAG pad to padpin
-                m.d.comb += padpin.o.eq(io.pad.o)
+                self.jtag.eqs += [padpin.o.eq(io.pad.o)]
                 self.jtag.boundary_scan_pads.append(padpin.o)
             elif padpin.dir == 'io':
                 print ("jtag_request add io    pin", padpin)
                 self.jtag.boundary_scan_pads.append(padpin.o)
             elif padpin.dir == 'io':
                 print ("jtag_request add io    pin", padpin)
@@ -277,26 +313,28 @@ class Blinker(Elaboratable):
                 print ("   jtag io core", io.core)
                 print ("   jtag io pad", io.pad)
                 # corepin is to be returned, here. so, connect jtag corein to it
                 print ("   jtag io core", io.core)
                 print ("   jtag io pad", io.pad)
                 # corepin is to be returned, here. so, connect jtag corein to it
-                m.d.comb += corepin.i.eq(io.core.i)
+                self.jtag.eqs += [corepin.i.eq(io.core.i)]
                 # and padpin to JTAG pad
                 # and padpin to JTAG pad
-                m.d.comb += io.pad.i.eq(padpin.i)
+                self.jtag.eqs += [io.pad.i.eq(padpin.i)]
                 # corepin is to be returned, here. connect it to jtag core out
                 # corepin is to be returned, here. connect it to jtag core out
-                m.d.comb += io.core.o.eq(corepin.o)
+                self.jtag.eqs += [io.core.o.eq(corepin.o)]
                 # and JTAG pad to padpin
                 # and JTAG pad to padpin
-                m.d.comb += padpin.o.eq(io.pad.o)
+                self.jtag.eqs += [padpin.o.eq(io.pad.o)]
                 # corepin is to be returned, here. connect it to jtag core out
                 # corepin is to be returned, here. connect it to jtag core out
-                m.d.comb += io.core.oe.eq(corepin.oe)
+                self.jtag.eqs += [io.core.oe.eq(corepin.oe)]
                 # and JTAG pad to padpin
                 # and JTAG pad to padpin
-                m.d.comb += padpin.oe.eq(io.pad.oe)
-`
+                self.jtag.eqs += [padpin.oe.eq(io.pad.oe)]
+
                 self.jtag.boundary_scan_pads.append(padpin.i)
                 self.jtag.boundary_scan_pads.append(padpin.o)
                 self.jtag.boundary_scan_pads.append(padpin.oe)
 
                 self.jtag.boundary_scan_pads.append(padpin.i)
                 self.jtag.boundary_scan_pads.append(padpin.o)
                 self.jtag.boundary_scan_pads.append(padpin.oe)
 
-        # finally return the *CORE* value just like ResourceManager.request()
+        # finally record the *CORE* value just like ResourceManager.request()
         # so that the module using this can connect to *CORE* i/o to the
         # resource.  pads are taken care of
         # so that the module using this can connect to *CORE* i/o to the
         # resource.  pads are taken care of
-        return value
+        self.jtag.resource_table[(name, number)] = value
+        # and the *PAD* value so that it can be wired up externally
+        self.jtag.resource_table_pads[(name, number)] = pvalue
 
 
 '''
 
 
 '''
@@ -345,80 +383,9 @@ class ASICPlatform(TemplatedPlatform):
         # add JTAG without scan
         self.add_resources([JTAGResource('jtag', 0)], no_boundary_scan=True)
 
         # add JTAG without scan
         self.add_resources([JTAGResource('jtag', 0)], no_boundary_scan=True)
 
-    def _request(self, name, number=0, *, dir=None, xdr=None):
-        """request a Resource (e.g. name="uart", number=0) which will
-        return a data structure containing Records of all the pins.
-
-        this override will also - automatically - create a JTAG Boundary Scan
-        connection *without* any change to the actual Platform.request() API
-        """
-        pad_mgr = self.jtag.pad_mgr
-        pad_mgr = self.jtag.pad_mgr
-        padlookup = self.jtag.padlookup
-        # okaaaay, bit of shenanigens going on: the important data structure
-        # here is Resourcemanager._ports.  requests add to _ports, which is
-        # what needs redirecting.  therefore what has to happen is to
-        # capture the number of ports *before* the request. sigh.
-        start_ports = len(self._ports)
-        value = super().request(name, number, dir=dir, xdr=xdr)
-        end_ports = len(self._ports)
-
-        # now make a corresponding (duplicate) request to the pad manager
-        # BUT, if it doesn't exist, don't sweat it: all it means is, the
-        # application did not request Boundary Scan for that resource.
-        pad_start_ports = len(pad_mgr._ports)
-        try:
-            pvalue = pad_mgr.request(name, number, dir=dir, xdr=xdr)
-        except ResourceError:
-            return value
-        pad_end_ports = len(pad_mgr._ports)
-
-        # ok now we have the lengths: now create a lookup between the pad
-        # and the core, so that JTAG boundary scan can be inserted in between
-        core = self._ports[start_ports:end_ports]
-        pads = pad_mgr._ports[pad_start_ports:pad_end_ports]
-        # oops if not the same numbers added. it's a duplicate. shouldn't happen
-        assert len(core) == len(pads), "argh, resource manager error"
-        print ("core", core)
-        print ("pads", pads)
-
-        # pad/core each return a list of tuples of (res, pin, port, attrs)
-        for pad, core in zip(pads, core):
-            # create a lookup on pin name to get at the hidden pad instance
-            # this pin name will be handed to get_input, get_output etc.
-            # and without the padlookup you can't find the (duplicate) pad.
-            # note that self.padlookup and self.jtag.ios use the *exact* same
-            # pin.name per pin
-            pin = pad[1]
-            corepin = core[1]
-            if pin is None: continue # skip when pin is None
-            assert corepin is not None # if pad was None, core should be too
-            print ("iter", pad, pin.name)
-            print ("existing pads", padlookup.keys())
-            assert pin.name not in padlookup # no overwrites allowed!
-            assert pin.name == corepin.name       # has to be the same!
-            padlookup[pin.name] = pad        # store pad by pin name
-
-            # now add the IO Shift Register.  first identify the type
-            # then request a JTAG IOConn. we can't wire it up (yet) because
-            # we don't have a Module() instance. doh. that comes in get_input
-            # and get_output etc. etc.
-            iotype = resiotypes[pin.dir] # look up the C4M-JTAG IOType
-            io = self.jtag.add_io(iotype=iotype, name=pin.name) # create IOConn
-            self.jtag.ios[pin.name] = io # store IOConn Record by pin name
-
-        # finally return the value just like ResourceManager.request()
-        return value
-
     def add_resources(self, resources, no_boundary_scan=False):
         print ("ASICPlatform add_resources", resources)
     def add_resources(self, resources, no_boundary_scan=False):
         print ("ASICPlatform add_resources", resources)
-        super().add_resources(resources)
-        return
-        if no_boundary_scan:
-            return
-        # make a *second* - identical - set of pin resources for the IO ring
-        padres = deepcopy(resources)
-        self.jtag.pad_mgr.add_resources(padres)
+        return super().add_resources(resources)
 
     #def iter_ports(self):
     #    yield from super().iter_ports()
 
     #def iter_ports(self):
     #    yield from super().iter_ports()
@@ -433,92 +400,38 @@ class ASICPlatform(TemplatedPlatform):
     # phase is to add JTAG Boundary Scan so it maaay be worth adding?
     # at least for the print statements
     def get_input(self, pin, port, attrs, invert):
     # phase is to add JTAG Boundary Scan so it maaay be worth adding?
     # at least for the print statements
     def get_input(self, pin, port, attrs, invert):
-        padlookup = self.jtag.padlookup
         self._check_feature("single-ended input", pin, attrs,
                             valid_xdrs=(0,), valid_attrs=None)
 
         m = Module()
         print ("    get_input", pin, "port", port, port.layout)
         self._check_feature("single-ended input", pin, attrs,
                             valid_xdrs=(0,), valid_attrs=None)
 
         m = Module()
         print ("    get_input", pin, "port", port, port.layout)
-        if pin.name in ['clk_0', 'rst_0']: # sigh
-            # simple pass-through from port to pin
-            print("No JTAG chain in-between")
-            m.d.comb += pin.i.eq(self._invert_if(invert, port))
-            return m
-        if pin.name not in padlookup:
-            print("No pin named %s, not connecting to JTAG BS" % pin.name)
-            m.d.comb += pin.i.eq(self._invert_if(invert, port))
-            return m
-        (padres, padpin, padport, padattrs) = padlookup[pin.name]
-        io = self.jtag.ios[pin.name]
-        print ("       pad", padres, padpin, padport, attrs)
-        print ("       padpin", padpin.layout)
-        print ("      jtag", io.core.layout, io.pad.layout)
-        m.d.comb += pin.i.eq(io.core.i)
-        m.d.comb += padpin.i.eq(pin.i)
-        m.d.comb += padport.io.eq(self._invert_if(invert, port))
-        m.d.comb += io.pad.i.eq(padport.io)
-
-        print("+=+=+= pin: ", pin)
-        print("+=+=+= port: ", port.layout)
-        print("+=+=+= pad pin: ", padpin)
-        print("+=+=+= pad port: ", padport)
+        m.d.comb += pin.i.eq(self._invert_if(invert, port))
         return m
 
     def get_output(self, pin, port, attrs, invert):
         return m
 
     def get_output(self, pin, port, attrs, invert):
-        padlookup = self.jtag.padlookup
         self._check_feature("single-ended output", pin, attrs,
                             valid_xdrs=(0,), valid_attrs=None)
 
         m = Module()
         print ("    get_output", pin, "port", port, port.layout)
         self._check_feature("single-ended output", pin, attrs,
                             valid_xdrs=(0,), valid_attrs=None)
 
         m = Module()
         print ("    get_output", pin, "port", port, port.layout)
-        if pin.name in ['clk_0', 'rst_0']: # sigh
-            # simple pass-through from pin to port
-            print("No JTAG chain in-between")
-            m.d.comb += port.eq(self._invert_if(invert, pin.o))
-            return m
-        if pin.name not in padlookup:
-            print("No pin named %s, not connecting to JTAG BS" % pin.name)
-            m.d.comb += port.eq(self._invert_if(invert, pin.o))
-            return m
-        (padres, padpin, padport, padattrs) = padlookup[pin.name]
-        io = self.jtag.ios[pin.name]
-        print ("       pad", padres, padpin, padport, padattrs)
-        print ("       pin", padpin.layout)
-        print ("      jtag", io.core.layout, io.pad.layout)
-        m.d.comb += io.core.o.eq(self._invert_if(invert, pin.o))
-        m.d.comb += pin.o.eq(padpin.o)
-        m.d.comb += port.eq(padport.io)
-        m.d.comb += padport.io.eq(io.pad.o)
+        m.d.comb += port.eq(self._invert_if(invert, pin.o))
         return m
 
     def get_tristate(self, pin, port, attrs, invert):
         return m
 
     def get_tristate(self, pin, port, attrs, invert):
-        padlookup = self.jtag.padlookup
         self._check_feature("single-ended tristate", pin, attrs,
                             valid_xdrs=(0,), valid_attrs=None)
 
         print ("    get_tristate", pin, "port", port, port.layout)
         m = Module()
         self._check_feature("single-ended tristate", pin, attrs,
                             valid_xdrs=(0,), valid_attrs=None)
 
         print ("    get_tristate", pin, "port", port, port.layout)
         m = Module()
-        if pin.name in ['clk_0', 'rst_0']: # sigh
-            print("No JTAG chain in-between")
-            m.submodules += Instance("$tribuf",
-                p_WIDTH=pin.width,
-                i_EN=pin.oe,
-                i_A=self._invert_if(invert, pin.o),
-                o_Y=port,
-            )
-            return m
-        return m
-        (res, pin, port, attrs) = padlookup[pin.name]
-        io = self.jtag.ios[pin.name]
         print ("       pad", res, pin, port, attrs)
         print ("       pin", pin.layout)
         print ("       pad", res, pin, port, attrs)
         print ("       pin", pin.layout)
-        print ("      jtag", io.core.layout, io.pad.layout)
-        #m.submodules += Instance("$tribuf",
-        #    p_WIDTH=pin.width,
-        #    i_EN=io.pad.oe,
-        #    i_A=self._invert_if(invert, io.pad.o),
-        #    o_Y=port,
-        #)
+        return m
+        #    m.submodules += Instance("$tribuf",
+        #        p_WIDTH=pin.width,
+        #        i_EN=pin.oe,
+        #        i_A=self._invert_if(invert, pin.o),
+        #        o_Y=port,
+        #    )
         m.d.comb += io.core.o.eq(pin.o)
         m.d.comb += io.core.oe.eq(pin.oe)
         m.d.comb += pin.i.eq(io.core.i)
         m.d.comb += io.core.o.eq(pin.o)
         m.d.comb += io.core.oe.eq(pin.oe)
         m.d.comb += pin.i.eq(io.core.i)
@@ -528,35 +441,14 @@ class ASICPlatform(TemplatedPlatform):
         return m
 
     def get_input_output(self, pin, port, attrs, invert):
         return m
 
     def get_input_output(self, pin, port, attrs, invert):
-        padlookup = self.jtag.padlookup
         self._check_feature("single-ended input/output", pin, attrs,
                             valid_xdrs=(0,), valid_attrs=None)
 
         print ("    get_input_output", pin, "port", port, port.layout)
         m = Module()
         self._check_feature("single-ended input/output", pin, attrs,
                             valid_xdrs=(0,), valid_attrs=None)
 
         print ("    get_input_output", pin, "port", port, port.layout)
         m = Module()
-        if pin.name in ['clk_0', 'rst_0']: # sigh
-            print("No JTAG chain in-between")
-            m.submodules += Instance("$tribuf",
-                p_WIDTH=pin.width,
-                i_EN=pin.oe,
-                i_A=self._invert_if(invert, pin.o),
-                o_Y=port,
-            )
-            m.d.comb += pin.i.eq(self._invert_if(invert, port))
-            return m
-        (padres, padpin, padport, padattrs) = padlookup[pin.name]
-        io = self.jtag.ios[pin.name]
-        print ("       padres", padres)
-        print ("       padpin", padpin)
-        print ("            layout", padpin.layout)
-        print ("       padport", padport)
-        print ("            layout", padport.layout)
-        print ("       padattrs", padattrs)
         print ("       port layout", port.layout)
         print ("       pin", pin)
         print ("            layout", pin.layout)
         print ("       port layout", port.layout)
         print ("       pin", pin)
         print ("            layout", pin.layout)
-        print ("      jtag io.core", io.core.layout)
-        print ("      jtag io.pad", io.pad.layout)
         #m.submodules += Instance("$tribuf",
         #    p_WIDTH=pin.width,
         #    i_EN=io.pad.oe,
         #m.submodules += Instance("$tribuf",
         #    p_WIDTH=pin.width,
         #    i_EN=io.pad.oe,
@@ -568,27 +460,9 @@ class ASICPlatform(TemplatedPlatform):
         port_o = port.io[1]
         port_oe = port.io[2]
 
         port_o = port.io[1]
         port_oe = port.io[2]
 
-        padport_i = padport.io[0]
-        padport_o = padport.io[1]
-        padport_oe = padport.io[2]
-
-        # connect i 
-        m.d.comb += pin.i.eq(io.core.i)
-        m.d.comb += padpin.i.eq(pin.i)
-        m.d.comb += padport_i.eq(self._invert_if(invert, port_i))
-        m.d.comb += io.pad.i.eq(padport_i)
-
-        # connect o
-        m.d.comb += io.core.o.eq(self._invert_if(invert, pin.o))
-        m.d.comb += pin.o.eq(padpin.o)
-        m.d.comb += port_o.eq(padport_o)
-        m.d.comb += padport_o.eq(io.pad.o)
-
-        # connect oe
-        m.d.comb += io.core.oe.eq(self._invert_if(invert, pin.oe))
-        m.d.comb += pin.oe.eq(padpin.oe)
-        m.d.comb += port_oe.eq(padport_oe)
-        m.d.comb += padport_oe.eq(io.pad.oe)
+        m.d.comb += pin.i.eq(self._invert_if(invert, port_i))
+        m.d.comb += port_o.eq(self._invert_if(invert, pin.o))
+        m.d.comb += port_oe.eq(pin.oe)
 
         return m
 
 
         return m
 
@@ -611,13 +485,11 @@ print(pinset)
 resources = create_resources(pinset)
 top = Blinker(pinset, resources)
 
 resources = create_resources(pinset)
 top = Blinker(pinset, resources)
 
-vl = rtlil.convert(top, ports=top.ports())
-with open("test_jtag_blinker.il", "w") as f:
-    f.write(vl)
-
-sys.exit(0)
+#vl = rtlil.convert(top, ports=top.ports())
+#with open("test_jtag_blinker.il", "w") as f:
+#    f.write(vl)
 
 
-if False:
+if True:
     # XXX these modules are all being added *AFTER* the build process links
     # everything together.  the expectation that this would work is...
     # unrealistic.  ordering, clearly, is important.
     # XXX these modules are all being added *AFTER* the build process links
     # everything together.  the expectation that this would work is...
     # unrealistic.  ordering, clearly, is important.
@@ -656,7 +528,7 @@ if False:
 # particularly when modules have been added *after* the platform build()
 # function has been called.
 
 # particularly when modules have been added *after* the platform build()
 # function has been called.
 
-sim = Simulator(top)
+sim = Simulator(top_fragment)
 sim.add_clock(1e-6, domain="sync")      # standard clock
 
 sim.add_sync_process(wrap(jtag_srv(top))) #? jtag server
 sim.add_clock(1e-6, domain="sync")      # standard clock
 
 sim.add_sync_process(wrap(jtag_srv(top))) #? jtag server