get access to jtag boundary scan pads for uart_0_tx/rx
[pinmux.git] / src / spec / testing_stage1.py
index e07601f9201b3c39975db41a439234ff51262824..fe5143179b3139b50e199b76b980116486ca3408 100644 (file)
@@ -168,9 +168,19 @@ class Blinker(Elaboratable):
         #m.d.sync += count[0].eq(gpio.gpio1.i)
        
         num_gpios = 4
+        gpio_i_ro = Signal(num_gpios)
         gpio_o_test = Signal(num_gpios)
         gpio_oe_test = Signal(num_gpios)
-        # Wire up the output signal of each gpio by XOR'ing each bit of gpio_o_test with gpio's input
+
+        # Create a read-only copy of core-side GPIO input signals 
+        # for Simulation asserts
+        m.d.comb += gpio_i_ro[0].eq(gpio.gpio0.i)
+        m.d.comb += gpio_i_ro[1].eq(gpio.gpio1.i)
+        m.d.comb += gpio_i_ro[2].eq(gpio.gpio2.i)
+        m.d.comb += gpio_i_ro[3].eq(gpio.gpio3.i)
+
+        # Wire up the output signal of each gpio by XOR'ing each bit of 
+        # gpio_o_test with gpio's input
         # Wire up each bit of gpio_oe_test signal to oe signal of each gpio. 
         # Turn into a loop at some point, probably a way without
         # using get_attr()
@@ -191,10 +201,28 @@ class Blinker(Elaboratable):
         m.d.comb += uart.tx.eq(self.intermediary)
         m.d.comb += self.intermediary.eq(uart.rx)
 
+        # I2C
+        num_i2c = 1
+        i2c_sda_oe_test = Signal(num_i2c)
+        i2c_scl_oe_test = Signal(num_i2c)
+        i2c = self.jtag.request('i2c')
+        print ("i2c fields", i2c, i2c.fields)
+        # Connect in loopback
+        m.d.comb += i2c.scl.o.eq(i2c.scl.i)
+        m.d.comb += i2c.sda.o.eq(i2c.sda.i)
+        # Connect output enable to test port for sim
+        m.d.comb += i2c.sda.oe.eq(i2c_sda_oe_test)
+        m.d.comb += i2c.scl.oe.eq(i2c_scl_oe_test)
+
         # to even be able to get at objects, you first have to make them
         # available - i.e. not as local variables
+        # Public attributes are equivalent to input/output ports in hdl's
         self.gpio = gpio
         self.uart = uart
+        self.i2c = i2c
+        self.i2c_sda_oe_test = i2c_sda_oe_test
+        self.i2c_scl_oe_test = i2c_scl_oe_test
+        self.gpio_i_ro = gpio_i_ro
         self.gpio_o_test = gpio_o_test
         self.gpio_oe_test = gpio_oe_test
 
@@ -345,61 +373,7 @@ class ASICPlatform(TemplatedPlatform):
         self.fragment = fragment
         return super().toolchain_prepare(fragment, name, **kwargs)
 
-"""
-and to create a Platform instance with that list, and build
-something random
 
-   p=Platform()
-   p.resources=listofstuff
-   p.build(Blinker())
-"""
-pinset = dummy_pinset()
-print(pinset)
-resources = create_resources(pinset)
-top = Blinker(pinset, resources, no_jtag_connect=False)#True)
-
-vl = rtlil.convert(top, ports=top.ports())
-with open("test_jtag_blinker.il", "w") as f:
-    f.write(vl)
-
-if False:
-    # 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.
-
-    # dut = JTAG(test_pinset(), wb_data_wid=64, domain="sync")
-    top.jtag.stop = False
-    # rather than the client access the JTAG bus directly
-    # create an alternative that the client sets
-    class Dummy: pass
-    cdut = Dummy()
-    cdut.cbus = JTAGInterface()
-
-    # set up client-server on port 44843-something
-    top.jtag.s = JTAGServer()
-    cdut.c = JTAGClient()
-    top.jtag.s.get_connection()
-    #else:
-    #    print ("running server only as requested, use openocd remote to test")
-    #    sys.stdout.flush()
-    #    top.jtag.s.get_connection(None) # block waiting for connection
-
-    # take copy of ir_width and scan_len
-    cdut._ir_width = top.jtag._ir_width
-    cdut.scan_len = top.jtag.scan_len
-
-    p = ASICPlatform (resources, top.jtag)
-    p.build(top)
-    # this is what needs to gets treated as "top", after "main module" top
-    # is augmented with IO pads with JTAG tacked on.  the expectation that
-    # the get_input() etc functions will be called magically by some other
-    # function is unrealistic.
-    top_fragment = p.fragment
-
-# XXX simulating top (the module that does not itself contain IO pads
-# because that's covered by build) cannot possibly be expected to work
-# particularly when modules have been added *after* the platform build()
-# function has been called.
 
 def test_case0():
     print("Starting sanity test case!")
@@ -510,8 +484,29 @@ def test_case1():
 
 def test_gpios():
     print("Starting GPIO test case!")
-    # Grab GPIO pad resource from JTAG BS
-    gpios_pad = top.jtag.resource_table_pads[('gpio', 0)]
+    
+    num_gpios = top.gpio_o_test.width
+    # Grab GPIO outpud pad resource from JTAG BS - end of chain
+    print (top.jtag.boundary_scan_pads.keys())
+    gpio0_o = top.jtag.boundary_scan_pads['gpio_0__gpio0__o']['o']
+    gpio1_o = top.jtag.boundary_scan_pads['gpio_0__gpio1__o']['o']
+    gpio2_o = top.jtag.boundary_scan_pads['gpio_0__gpio2__o']['o']
+    gpio3_o = top.jtag.boundary_scan_pads['gpio_0__gpio3__o']['o']
+    gpio_pad_out = [ gpio0_o, gpio1_o, gpio2_o, gpio3_o]
+
+    # Grab GPIO output enable pad resource from JTAG BS - end of chain
+    gpio0_oe = top.jtag.boundary_scan_pads['gpio_0__gpio0__oe']['o']
+    gpio1_oe = top.jtag.boundary_scan_pads['gpio_0__gpio1__oe']['o']
+    gpio2_oe = top.jtag.boundary_scan_pads['gpio_0__gpio2__oe']['o']
+    gpio3_oe = top.jtag.boundary_scan_pads['gpio_0__gpio3__oe']['o']
+    gpio_pad_oe = [gpio0_oe, gpio1_oe, gpio2_oe, gpio3_oe]
+
+    # Grab GPIO input pad resource from JTAG BS - start of chain
+    gpio0_pad_in = top.jtag.boundary_scan_pads['gpio_0__gpio0__i']['i']
+    gpio1_pad_in = top.jtag.boundary_scan_pads['gpio_0__gpio1__i']['i']
+    gpio2_pad_in = top.jtag.boundary_scan_pads['gpio_0__gpio2__i']['i']
+    gpio3_pad_in = top.jtag.boundary_scan_pads['gpio_0__gpio3__i']['i']
+    gpio_pad_in = [gpio0_pad_in, gpio1_pad_in, gpio2_pad_in, gpio3_pad_in]
     
     # Have the sim run through a for-loop where the gpio_o_test is 
     # incremented like a counter (0000, 0001...)
@@ -520,35 +515,248 @@ def test_gpios():
     # TODO + input set at pad matches input seen at core
     # TODO + if gpio_o_test bit is cleared, output seen at pad matches 
     # input seen at pad
-    num_gpio_o_states = top.gpio_o_test.width**2
-    print("Num of permutations of gpio_o_test record: ", num_gpio_o_states)
+    num_gpio_o_states = num_gpios**2
+    pad_out = [0] * num_gpios
+    pad_oe = [0] * num_gpios
+    #print("Num of permutations of gpio_o_test record: ", num_gpio_o_states)
     for gpio_o_val in range(0, num_gpio_o_states):
         yield top.gpio_o_test.eq(gpio_o_val) 
-        yield Settle()
+        #yield Settle()
         yield # Move to the next clk cycle
+        
+        # Cycle through all input combinations
+        for gpio_i_val in range(0, num_gpio_o_states):
+            # Set each gpio input at pad to test value
+            for gpio_bit in range(0, num_gpios):
+                yield gpio_pad_in[gpio_bit].eq((gpio_i_val >> gpio_bit) & 0x1)
+            yield
+            # After changing the gpio0/1/2/3 inputs,
+            # the output is also going to change.
+            # *therefore it must be read again* to get the
+            # snapshot (as a python value)
+            for gpio_bit in range(0, num_gpios):
+                pad_out[gpio_bit] = yield gpio_pad_out[gpio_bit]
+            yield
+            for gpio_bit in range(0, num_gpios):
+                # check core and pad in
+                gpio_i_ro = yield top.gpio_i_ro[gpio_bit]
+                out_test_bit = ((gpio_o_val & (1 << gpio_bit)) != 0)
+                in_bit = ((gpio_i_val & (1 << gpio_bit)) != 0)
+                # Check that the core end input matches pad 
+                assert in_bit == gpio_i_ro
+                # Test that the output at pad matches:
+                # Pad output == given test output XOR test input
+                assert (out_test_bit ^ in_bit) == pad_out[gpio_bit]
+            
+            # For debugging - VERY verbose
+            #print("---------------------")
+            #print("Test Out: ", bin(gpio_o_val))
+            #print("Test Input: ", bin(gpio_i_val)) 
+            # Print MSB first
+            #print("Pad Output: ", list(reversed(pad_out)))
+            #print("---------------------")
+        
+    # For-loop for testing output enable signals
+    for gpio_o_val in range(0, num_gpio_o_states):
+        yield top.gpio_oe_test.eq(gpio_o_val) 
+        yield # Move to the next clk cycle
+        
+        for gpio_bit in range(0, num_gpios):
+            pad_oe[gpio_bit] = yield gpio_pad_oe[gpio_bit]
+        yield 
+
+        for gpio_bit in range(0, num_gpios):
+            oe_test_bit = ((gpio_o_val & (1 << gpio_bit)) != 0)
+            # oe set at core matches oe seen at pad:
+            assert oe_test_bit == pad_oe[gpio_bit]
+        # For debugging - VERY verbose
+        #print("---------------------")
+        #print("Test Output Enable: ", bin(gpio_o_val))
+        # Print MSB first
+        #print("Pad Output Enable: ", list(reversed(pad_oe)))
+        #print("---------------------") 
+    print("GPIO Test PASSED!")
+
+def test_uart():
+    # grab the JTAG resource pad
+    print ()
+    print ("bs pad keys", top.jtag.boundary_scan_pads.keys())
+    print ()
+    uart_rx_pad = top.jtag.boundary_scan_pads['uart_0__rx']['i']
+    uart_tx_pad = top.jtag.boundary_scan_pads['uart_0__tx']['o']
+
+    print ("uart rx pad", uart_rx_pad)
+    print ("uart tx pad", uart_tx_pad)
+
+    # Test UART by writing 0 and 1 to RX
+    # Internally TX connected to RX,
+    # so match pad TX with RX
+    for i in range(0, 2):
+        yield uart_rx_pad.eq(i)
+        #yield uart_rx_pad.eq(i)
+        yield Settle()
+        yield # one clock cycle
+        tx_val = yield uart_tx_pad
+        print ("xmit uart", tx_val, 1)
+        assert tx_val == i
+
+    print("UART Test PASSED!")
+
+def test_i2c():
+    i2c_sda_i_pad = top.jtag.boundary_scan_pads['i2c_0__sda__i']['i']
+    i2c_sda_o_pad = top.jtag.boundary_scan_pads['i2c_0__sda__o']['o']
+    i2c_sda_oe_pad = top.jtag.boundary_scan_pads['i2c_0__sda__oe']['o']
+
+    i2c_scl_i_pad = top.jtag.boundary_scan_pads['i2c_0__scl__i']['i']
+    i2c_scl_o_pad = top.jtag.boundary_scan_pads['i2c_0__scl__o']['o']
+    i2c_scl_oe_pad = top.jtag.boundary_scan_pads['i2c_0__scl__oe']['o']
+
+    #i2c_pad = top.jtag.resource_table_pads[('i2c', 0)]
+    #print ("i2c pad", i2c_pad)
+    #print ("i2c pad", i2c_pad.layout)
+
+    for i in range(0, 2):
+        yield i2c_sda_i_pad.eq(i) #i2c_pad.sda.i.eq(i)
+        yield i2c_scl_i_pad.eq(i) #i2c_pad.scl.i.eq(i)
+        yield top.i2c_sda_oe_test.eq(i)
+        yield top.i2c_scl_oe_test.eq(i)
+        yield Settle()
+        yield # one clock cycle
+        sda_o_val = yield i2c_sda_o_pad
+        scl_o_val = yield i2c_scl_o_pad
+        sda_oe_val = yield i2c_sda_oe_pad
+        scl_oe_val = yield i2c_scl_oe_pad
+        print ("Test input: ", i, " SDA/SCL out: ", sda_o_val, scl_o_val,
+               " SDA/SCL oe: ", sda_oe_val, scl_oe_val)
+        assert sda_o_val == i
+        assert scl_o_val == i
+        assert sda_oe_val == i
+        assert scl_oe_val == i
+
+    print("I2C Test PASSED!")
 
-        print(type(top.gpio.gpio0.o), type(gpios_pad.gpio0.o))
-        print(top.gpio.gpio0.o, gpios_pad.gpio0.o)
-        core_out = yield top.gpio.gpio0.o
-        pad_out = yield gpios_pad.gpio0.o
-        assert core_out == pad_out
 
 
-    # Another for loop to run through gpio_oe_test. Assert:
-    # + oe set at core matches oe seen at pad.
-    # TODO
+def test_debug_print():
+    print("Test used for getting object methods/information")
+    print("Moved here to clear clutter of gpio test")
+    
+    print ("printing out info about the resource gpio0")
+    print (top.gpio['gpio0']['i'])
+    print ("this is a PIN resource", type(top.gpio['gpio0']['i']))
+    # yield can only be done on SIGNALS or RECORDS,
+    # NOT Pins/Resources gpio0_core_in = yield top.gpio['gpio0']['i']
+    #print("Test gpio0 core in: ", gpio0_core_in)
+    
+    print("JTAG")
+    print(top.jtag.__class__.__name__, dir(top.jtag))
+    print("TOP")
+    print(top.__class__.__name__, dir(top))
+    print("PORT")
+    print(top.ports.__class__.__name__, dir(top.ports))
+    print("GPIO")
+    print(top.gpio.__class__.__name__, dir(top.gpio))
+   
+    print("UART")
+    print(dir(top.jtag.boundary_scan_pads['uart_0__rx__pad__i']))
+    print(top.jtag.boundary_scan_pads['uart_0__rx__pad__i'].keys())
+    print(top.jtag.boundary_scan_pads['uart_0__tx__pad__o'])
+    #print(type(top.jtag.boundary_scan_pads['uart_0__rx__pad__i']['rx']))
+    print ("jtag pad table keys")
+    print (top.jtag.resource_table_pads.keys())
+    print(type(top.jtag.resource_table_pads[('uart', 0)].rx.i))
+    print(top.jtag.boundary_scan_pads['uart_0__rx__i'])
+
+    print("I2C")
+    print(top.jtag.boundary_scan_pads['i2c_0__sda__i'])
+    print(type(top.jtag.boundary_scan_pads['i2c_0__sda__i']['i']))
+
+    print(top.jtag.resource_table_pads)
+    print(top.jtag.boundary_scan_pads)
 
-sim = Simulator(top)
-sim.add_clock(1e-6, domain="sync")      # standard clock
 
-#sim.add_sync_process(wrap(jtag_srv(top))) #? jtag server
-#if len(sys.argv) != 2 or sys.argv[1] != 'server':
-#sim.add_sync_process(wrap(jtag_sim(cdut, top.jtag))) # actual jtag tester
-#sim.add_sync_process(wrap(dmi_sim(top.jtag)))  # handles (pretends to be) DMI
+    # Trying to read input from core side, looks like might be a pin...
+    # XXX don't "look like" - don't guess - *print it out*
+    #print ("don't guess, CHECK", type(top.gpio.gpio0.i))
+    
+    print () # extra print to divide the output
+    yield
 
-#sim.add_sync_process(wrap(test_case1()))
-#sim.add_sync_process(wrap(test_case0()))
-sim.add_sync_process(wrap(test_gpios()))
+if __name__ == '__main__':
+    """
+    and to create a Platform instance with that list, and build
+    something random
+
+       p=Platform()
+       p.resources=listofstuff
+       p.build(Blinker())
+    """
+    pinset = dummy_pinset()
+    print(pinset)
+    resources = create_resources(pinset)
+    top = Blinker(pinset, resources, no_jtag_connect=False)#True)
+
+    vl = rtlil.convert(top, ports=top.ports())
+    with open("test_jtag_blinker.il", "w") as f:
+        f.write(vl)
+
+    if False:
+        # 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.
+
+        # dut = JTAG(test_pinset(), wb_data_wid=64, domain="sync")
+        top.jtag.stop = False
+        # rather than the client access the JTAG bus directly
+        # create an alternative that the client sets
+        class Dummy: pass
+        cdut = Dummy()
+        cdut.cbus = JTAGInterface()
+
+        # set up client-server on port 44843-something
+        top.jtag.s = JTAGServer()
+        cdut.c = JTAGClient()
+        top.jtag.s.get_connection()
+        #else:
+        #    print ("running server only as requested, 
+        #           use openocd remote to test")
+        #    sys.stdout.flush()
+        #    top.jtag.s.get_connection(None) # block waiting for connection
+
+        # take copy of ir_width and scan_len
+        cdut._ir_width = top.jtag._ir_width
+        cdut.scan_len = top.jtag.scan_len
+
+        p = ASICPlatform (resources, top.jtag)
+        p.build(top)
+        # this is what needs to gets treated as "top", after "main module" top
+        # is augmented with IO pads with JTAG tacked on.  the expectation that
+        # the get_input() etc functions will be called magically by some other
+        # function is unrealistic.
+        top_fragment = p.fragment
+
+    # XXX simulating top (the module that does not itself contain IO pads
+    # because that's covered by build) cannot possibly be expected to work
+    # particularly when modules have been added *after* the platform build()
+    # function has been called.
+
+    sim = Simulator(top)
+    sim.add_clock(1e-6, domain="sync")      # standard clock
+
+    #sim.add_sync_process(wrap(jtag_srv(top))) #? jtag server
+    #if len(sys.argv) != 2 or sys.argv[1] != 'server':
+    # actual jtag tester
+    #sim.add_sync_process(wrap(jtag_sim(cdut, top.jtag)))
+    # handles (pretends to be) DMI
+    #sim.add_sync_process(wrap(dmi_sim(top.jtag)))
+    
+    #sim.add_sync_process(wrap(test_case1()))
+    #sim.add_sync_process(wrap(test_case0()))
+    
+    #sim.add_sync_process(wrap(test_gpios()))
+    sim.add_sync_process(wrap(test_uart()))
+    sim.add_sync_process(wrap(test_i2c()))
+    #sim.add_sync_process(wrap(test_debug_print()))
 
-with sim.write_vcd("blinker_test.vcd"):
-    sim.run()
+    with sim.write_vcd("blinker_test.vcd"):
+        sim.run()