Added reverse arg fix, tests working
[pinmux.git] / src / spec / testing_stage1.py
1 #!/usr/bin/env python3
2 """
3 pinmux documented here https://libre-soc.org/docs/pinmux/
4 """
5 from nmigen.build.dsl import Resource, Subsignal, Pins
6 from nmigen.build.plat import TemplatedPlatform
7 from nmigen.build.res import ResourceManager, ResourceError
8 from nmigen.hdl.rec import Layout
9 from nmigen import Elaboratable, Signal, Module, Instance
10 from collections import OrderedDict
11 from jtag import JTAG, resiotypes
12 from copy import deepcopy
13 from nmigen.cli import rtlil
14 import sys
15
16 # extra dependencies for jtag testing (?)
17 #from soc.bus.sram import SRAM
18
19 #from nmigen import Memory
20 from nmigen.sim import Simulator, Delay, Settle, Tick, Passive
21
22 from nmutil.util import wrap
23
24 # from soc.debug.jtagutils import (jtag_read_write_reg,
25 # jtag_srv, jtag_set_reset,
26 # jtag_set_ir, jtag_set_get_dr)
27
28 from soc.debug.test.test_jtag_tap import (jtag_read_write_reg,
29 jtag_set_reset,
30 jtag_set_shift_ir,
31 jtag_set_shift_dr,
32 jtag_set_run,
33 jtag_set_idle,
34 tms_data_getset)
35
36 from c4m.nmigen.jtag.tap import TAP, IOType
37 from c4m.nmigen.jtag.bus import Interface as JTAGInterface
38 from soc.debug.dmi import DMIInterface, DBGCore
39 #from soc.debug.test.dmi_sim import dmi_sim
40 #from soc.debug.test.jtagremote import JTAGServer, JTAGClient
41 from nmigen.build.res import ResourceError
42
43 # Was thinking of using these functions, but skipped for simplicity for now
44 # XXX nope. the output from JSON file.
45 # from pinfunctions import (i2s, lpc, emmc, sdmmc, mspi, mquadspi, spi,
46 # quadspi, i2c, mi2c, jtag, uart, uartfull, rgbttl, ulpi, rgmii, flexbus1,
47 # flexbus2, sdram1, sdram2, sdram3, vss, vdd, sys, eint, pwm, gpio)
48
49 # File for stage 1 pinmux tested proposed by Luke,
50 # https://bugs.libre-soc.org/show_bug.cgi?id=50#c10
51
52
53 def dummy_pinset():
54 # sigh this needs to come from pinmux.
55 gpios = []
56 for i in range(4):
57 gpios.append("%d*" % i)
58 return {'uart': ['tx+', 'rx-'],
59 'gpio': gpios,
60 # 'jtag': ['tms-', 'tdi-', 'tdo+', 'tck+'],
61 'i2c': ['sda*', 'scl+']}
62
63
64 """
65 a function is needed which turns the results of dummy_pinset()
66 into:
67
68 [UARTResource("uart", 0, tx=..., rx=..),
69 I2CResource("i2c", 0, scl=..., sda=...),
70 Resource("gpio", 0, Subsignal("i"...), Subsignal("o"...)
71 Resource("gpio", 1, Subsignal("i"...), Subsignal("o"...)
72 ...
73 ]
74 """
75
76
77 def create_resources(pinset):
78 resources = []
79 for periph, pins in pinset.items():
80 print(periph, pins)
81 if periph == 'i2c':
82 #print("I2C required!")
83 resources.append(I2CResource('i2c', 0, sda='sda', scl='scl'))
84 elif periph == 'uart':
85 #print("UART required!")
86 resources.append(UARTResource('uart', 0, tx='tx', rx='rx'))
87 elif periph == 'gpio':
88 #print("GPIO required!")
89 print("GPIO is defined as '*' type, meaning i, o and oe needed")
90 ios = []
91 for pin in pins:
92 pname = "gpio"+pin[:-1] # strip "*" on end
93 # urrrr... tristsate and io assume a single pin which is
94 # of course exactly what we don't want in an ASIC: we want
95 # *all three* pins but the damn port is not outputted
96 # as a triplet, it's a single Record named "io". sigh.
97 # therefore the only way to get a triplet of i/o/oe
98 # is to *actually* create explicit triple pins
99 # XXX ARRRGH, doesn't work
100 # pad = Subsignal("io",
101 # Pins("%s_i %s_o %s_oe" % (pname, pname, pname),
102 # dir="io", assert_width=3))
103 #ios.append(Resource(pname, 0, pad))
104 pads = []
105 pads.append(Subsignal("i",
106 Pins(pname+"_i", dir="i", assert_width=1)))
107 pads.append(Subsignal("o",
108 Pins(pname+"_o", dir="o", assert_width=1)))
109 pads.append(Subsignal("oe",
110 Pins(pname+"_oe", dir="o", assert_width=1)))
111 ios.append(Resource.family(pname, 0, default_name=pname,
112 ios=pads))
113 resources.append(Resource.family(periph, 0, default_name="gpio",
114 ios=ios))
115
116 # add clock and reset
117 clk = Resource("clk", 0, Pins("sys_clk", dir="i"))
118 rst = Resource("rst", 0, Pins("sys_rst", dir="i"))
119 resources.append(clk)
120 resources.append(rst)
121 return resources
122
123
124 def JTAGResource(*args):
125 io = []
126 io.append(Subsignal("tms", Pins("tms", dir="i", assert_width=1)))
127 io.append(Subsignal("tdi", Pins("tdi", dir="i", assert_width=1)))
128 io.append(Subsignal("tck", Pins("tck", dir="i", assert_width=1)))
129 io.append(Subsignal("tdo", Pins("tdo", dir="o", assert_width=1)))
130 return Resource.family(*args, default_name="jtag", ios=io)
131
132
133 def UARTResource(*args, rx, tx):
134 io = []
135 io.append(Subsignal("rx", Pins(rx, dir="i", assert_width=1)))
136 io.append(Subsignal("tx", Pins(tx, dir="o", assert_width=1)))
137 return Resource.family(*args, default_name="uart", ios=io)
138
139
140 def I2CResource(*args, scl, sda):
141 ios = []
142 pads = []
143 pads.append(Subsignal("i", Pins(sda+"_i", dir="i", assert_width=1)))
144 pads.append(Subsignal("o", Pins(sda+"_o", dir="o", assert_width=1)))
145 pads.append(Subsignal("oe", Pins(sda+"_oe", dir="o", assert_width=1)))
146 ios.append(Resource.family(sda, 0, default_name=sda, ios=pads))
147 pads = []
148 pads.append(Subsignal("i", Pins(scl+"_i", dir="i", assert_width=1)))
149 pads.append(Subsignal("o", Pins(scl+"_o", dir="o", assert_width=1)))
150 pads.append(Subsignal("oe", Pins(scl+"_oe", dir="o", assert_width=1)))
151 ios.append(Resource.family(scl, 0, default_name=scl, ios=pads))
152 return Resource.family(*args, default_name="i2c", ios=ios)
153
154
155 # top-level demo module.
156 class Blinker(Elaboratable):
157 def __init__(self, pinset, resources, no_jtag_connect=False):
158 self.no_jtag_connect = no_jtag_connect
159 self.jtag = JTAG({}, "sync", resources=resources)
160 #memory = Memory(width=32, depth=16)
161 #self.sram = SRAM(memory=memory, bus=self.jtag.wb)
162
163 def elaborate(self, platform):
164 jtag_resources = self.jtag.pad_mgr.resources
165 m = Module()
166 m.submodules.jtag = self.jtag
167 #m.submodules.sram = self.sram
168
169 #count = Signal(5)
170 #m.d.sync += count.eq(count+1)
171 print("resources", platform, jtag_resources.items())
172 gpio = self.jtag.request('gpio')
173 print(gpio, gpio.layout, gpio.fields)
174 # get the GPIO bank, mess about with some of the pins
175 #m.d.comb += gpio.gpio0.o.eq(1)
176 #m.d.comb += gpio.gpio1.o.eq(gpio.gpio2.i)
177 #m.d.comb += gpio.gpio1.oe.eq(count[4])
178 #m.d.sync += count[0].eq(gpio.gpio1.i)
179
180 num_gpios = 4
181 gpio_i_ro = Signal(num_gpios)
182 gpio_o_test = Signal(num_gpios)
183 gpio_oe_test = Signal(num_gpios)
184
185 # Create a read-only copy of core-side GPIO input signals
186 # for Simulation asserts
187 m.d.comb += gpio_i_ro[0].eq(gpio.gpio0.i)
188 m.d.comb += gpio_i_ro[1].eq(gpio.gpio1.i)
189 m.d.comb += gpio_i_ro[2].eq(gpio.gpio2.i)
190 m.d.comb += gpio_i_ro[3].eq(gpio.gpio3.i)
191
192 # Wire up the output signal of each gpio by XOR'ing each bit of
193 # gpio_o_test with gpio's input
194 # Wire up each bit of gpio_oe_test signal to oe signal of each gpio.
195 # Turn into a loop at some point, probably a way without
196 # using get_attr()
197 m.d.comb += gpio.gpio0.o.eq(gpio_o_test[0] ^ gpio.gpio0.i)
198 m.d.comb += gpio.gpio1.o.eq(gpio_o_test[1] ^ gpio.gpio1.i)
199 m.d.comb += gpio.gpio2.o.eq(gpio_o_test[2] ^ gpio.gpio2.i)
200 m.d.comb += gpio.gpio3.o.eq(gpio_o_test[3] ^ gpio.gpio3.i)
201
202 m.d.comb += gpio.gpio0.oe.eq(gpio_oe_test[0])# ^ gpio.gpio0.i)
203 m.d.comb += gpio.gpio1.oe.eq(gpio_oe_test[1])# ^ gpio.gpio1.i)
204 m.d.comb += gpio.gpio2.oe.eq(gpio_oe_test[2])# ^ gpio.gpio2.i)
205 m.d.comb += gpio.gpio3.oe.eq(gpio_oe_test[3])# ^ gpio.gpio3.i)
206
207 # get the UART resource, mess with the output tx
208 uart = self.jtag.request('uart')
209 print("uart fields", uart, uart.fields)
210 self.uart_tx_test = Signal()
211 #self.intermediary = Signal()
212 #m.d.comb += uart.tx.eq(self.intermediary)
213 #m.d.comb += self.intermediary.eq(uart.rx)
214 # Allow tx to be controlled externally
215 m.d.comb += uart.tx.eq(self.uart_tx_test ^ uart.rx)
216
217 # I2C
218 num_i2c = 1
219 i2c_sda_oe_test = Signal(num_i2c)
220 i2c_scl_oe_test = Signal(num_i2c)
221 i2c = self.jtag.request('i2c')
222 print("i2c fields", i2c, i2c.fields)
223 # Connect in loopback
224 m.d.comb += i2c.sda.o.eq(i2c.sda.i)
225 m.d.comb += i2c.scl.o.eq(i2c.scl.i)
226 # Connect output enable to test port for sim
227 m.d.comb += i2c.sda.oe.eq(i2c_sda_oe_test)# ^ i2c.sda.i)
228 m.d.comb += i2c.scl.oe.eq(i2c_scl_oe_test)# ^ i2c.scl.i)
229
230 # to even be able to get at objects, you first have to make them
231 # available - i.e. not as local variables
232 # Public attributes are equivalent to input/output ports in hdl's
233 self.gpio = gpio
234 self.uart = uart
235 self.uart_tx_test
236 self.i2c = i2c
237 self.i2c_sda_oe_test = i2c_sda_oe_test
238 self.i2c_scl_oe_test = i2c_scl_oe_test
239 self.gpio_i_ro = gpio_i_ro
240 self.gpio_o_test = gpio_o_test
241 self.gpio_oe_test = gpio_oe_test
242
243 # sigh these wire up to the pads so you cannot set Signals
244 # that are already wired
245 if self.no_jtag_connect: # bypass jtag pad connect for testing purposes
246 return m
247 return self.jtag.boundary_elaborate(m, platform)
248
249 def ports(self):
250 return list(self)
251
252 def __iter__(self):
253 yield from self.jtag.iter_ports()
254
255
256 '''
257 _trellis_command_templates = [
258 r"""
259 {{invoke_tool("yosys")}}
260 {{quiet("-q")}}
261 {{get_override("yosys_opts")|options}}
262 -l {{name}}.rpt
263 {{name}}.ys
264 """,
265 ]
266 '''
267
268 # sigh, have to create a dummy platform for now.
269 # TODO: investigate how the heck to get it to output ilang. or verilog.
270 # or, anything, really. but at least it doesn't barf
271
272
273 class ASICPlatform(TemplatedPlatform):
274 connectors = []
275 resources = OrderedDict()
276 required_tools = []
277 command_templates = ['/bin/true'] # no command needed: stops barfing
278 file_templates = {
279 **TemplatedPlatform.build_script_templates,
280 "{{name}}.il": r"""
281 # {{autogenerated}}
282 {{emit_rtlil()}}
283 """,
284 "{{name}}.debug.v": r"""
285 /* {{autogenerated}} */
286 {{emit_debug_verilog()}}
287 """,
288 }
289 toolchain = None
290 default_clk = "clk" # should be picked up / overridden by platform sys.clk
291 default_rst = "rst" # should be picked up / overridden by platform sys.rst
292
293 def __init__(self, resources, jtag):
294 self.jtag = jtag
295 super().__init__()
296
297 # create set of pin resources based on the pinset, this is for the core
298 #jtag_resources = self.jtag.pad_mgr.resources
299 self.add_resources(resources)
300
301 # add JTAG without scan
302 self.add_resources([JTAGResource('jtag', 0)], no_boundary_scan=True)
303
304 def add_resources(self, resources, no_boundary_scan=False):
305 print("ASICPlatform add_resources", resources)
306 return super().add_resources(resources)
307
308 # def iter_ports(self):
309 # yield from super().iter_ports()
310 # for io in self.jtag.ios.values():
311 # print ("iter ports", io.layout, io)
312 # for field in io.core.fields:
313 # yield getattr(io.core, field)
314 # for field in io.pad.fields:
315 # yield getattr(io.pad, field)
316
317 # XXX these aren't strictly necessary right now but the next
318 # phase is to add JTAG Boundary Scan so it maaay be worth adding?
319 # at least for the print statements
320 def get_input(self, pin, port, attrs, invert):
321 self._check_feature("single-ended input", pin, attrs,
322 valid_xdrs=(0,), valid_attrs=None)
323
324 m = Module()
325 print(" get_input", pin, "port", port, port.layout)
326 m.d.comb += pin.i.eq(self._invert_if(invert, port))
327 return m
328
329 def get_output(self, pin, port, attrs, invert):
330 self._check_feature("single-ended output", pin, attrs,
331 valid_xdrs=(0,), valid_attrs=None)
332
333 m = Module()
334 print(" get_output", pin, "port", port, port.layout)
335 m.d.comb += port.eq(self._invert_if(invert, pin.o))
336 return m
337
338 def get_tristate(self, pin, port, attrs, invert):
339 self._check_feature("single-ended tristate", pin, attrs,
340 valid_xdrs=(0,), valid_attrs=None)
341
342 print(" get_tristate", pin, "port", port, port.layout)
343 m = Module()
344 print(" pad", pin, port, attrs)
345 print(" pin", pin.layout)
346 return m
347 # m.submodules += Instance("$tribuf",
348 # p_WIDTH=pin.width,
349 # i_EN=pin.oe,
350 # i_A=self._invert_if(invert, pin.o),
351 # o_Y=port,
352 # )
353 m.d.comb += io.core.o.eq(pin.o)
354 m.d.comb += io.core.oe.eq(pin.oe)
355 m.d.comb += pin.i.eq(io.core.i)
356 m.d.comb += io.pad.i.eq(port.i)
357 m.d.comb += port.o.eq(io.pad.o)
358 m.d.comb += port.oe.eq(io.pad.oe)
359 return m
360
361 def get_input_output(self, pin, port, attrs, invert):
362 self._check_feature("single-ended input/output", pin, attrs,
363 valid_xdrs=(0,), valid_attrs=None)
364
365 print(" get_input_output", pin, "port", port, port.layout)
366 m = Module()
367 print(" port layout", port.layout)
368 print(" pin", pin)
369 print(" layout", pin.layout)
370 # m.submodules += Instance("$tribuf",
371 # p_WIDTH=pin.width,
372 # i_EN=io.pad.oe,
373 # i_A=self._invert_if(invert, io.pad.o),
374 # o_Y=port,
375 # )
376 # Create aliases for the port sub-signals
377 port_i = port.io[0]
378 port_o = port.io[1]
379 port_oe = port.io[2]
380
381 m.d.comb += pin.i.eq(self._invert_if(invert, port_i))
382 m.d.comb += port_o.eq(self._invert_if(invert, pin.o))
383 m.d.comb += port_oe.eq(pin.oe)
384
385 return m
386
387 def toolchain_prepare(self, fragment, name, **kwargs):
388 """override toolchain_prepare in order to grab the fragment
389 """
390 self.fragment = fragment
391 return super().toolchain_prepare(fragment, name, **kwargs)
392
393
394 def test_case0():
395 print("Starting sanity test case!")
396 print("printing out list of stuff in top")
397 print("JTAG IOs", top.jtag.ios)
398 # ok top now has a variable named "gpio", let's enumerate that too
399 print("printing out list of stuff in top.gpio and its type")
400 print(top.gpio.__class__.__name__, dir(top.gpio))
401 # ok, it's a nmigen Record, therefore it has a layout. let's print
402 # that too
403 print("top.gpio is a Record therefore has fields and a layout")
404 print(" layout:", top.gpio.layout)
405 print(" fields:", top.gpio.fields)
406 print("Fun never ends...")
407 print(" layout, gpio2:", top.gpio.layout['gpio2'])
408 print(" fields, gpio2:", top.gpio.fields['gpio2'])
409 print(top.jtag.__class__.__name__, dir(top.jtag))
410 print("Pads:")
411 print(top.jtag.resource_table_pads[('gpio', 0)])
412
413 # etc etc. you get the general idea
414 delayVal = 0.2e-6
415 yield top.uart.rx.eq(0)
416 yield Delay(delayVal)
417 yield Settle()
418 yield top.gpio.gpio2.o.eq(0)
419 yield top.gpio.gpio3.o.eq(1)
420 yield
421 yield top.gpio.gpio3.oe.eq(1)
422 yield
423 yield top.gpio.gpio3.oe.eq(0)
424 # grab the JTAG resource pad
425 gpios_pad = top.jtag.resource_table_pads[('gpio', 0)]
426 yield gpios_pad.gpio3.i.eq(1)
427 yield Delay(delayVal)
428 yield Settle()
429 yield top.gpio.gpio2.oe.eq(1)
430 yield top.gpio.gpio3.oe.eq(1)
431 yield gpios_pad.gpio3.i.eq(0)
432 yield top.jtag.gpio.gpio2.i.eq(1)
433 yield Delay(delayVal)
434 yield Settle()
435 gpio_o2 = 0
436 for _ in range(20):
437 # get a value first (as an integer). you were trying to set
438 # it to the actual Signal. this is not going to work. or if
439 # it does, it's very scary.
440 gpio_o2 = not gpio_o2
441 yield top.gpio.gpio2.o.eq(gpio_o2)
442
443 # ditto: here you are trying to set to an AST expression
444 # which is inadviseable (likely to fail)
445 gpio_o3 = not gpio_o2
446 yield top.gpio.gpio3.o.eq(gpio_o3)
447 yield Delay(delayVal)
448 yield Settle()
449 # grab the JTAG resource pad
450 uart_pad = top.jtag.resource_table_pads[('uart', 0)]
451 yield uart_pad.rx.i.eq(gpio_o2)
452 yield Delay(delayVal)
453 yield Settle()
454 yield # one clock cycle
455 tx_val = yield uart_pad.tx.o
456 print("xmit uart", tx_val, gpio_o2)
457
458 print("jtag pad table keys")
459 print(top.jtag.resource_table_pads.keys())
460 uart_pad = top.jtag.resource_table_pads[('uart', 0)]
461 print("uart pad", uart_pad)
462 print("uart pad", uart_pad.layout)
463
464 yield top.gpio.gpio2.oe.eq(0)
465 yield top.gpio.gpio3.oe.eq(0)
466 yield top.jtag.gpio.gpio2.i.eq(0)
467 yield Delay(delayVal)
468 yield Settle()
469
470
471 def test_gpios(dut):
472 print("Starting GPIO test case!")
473 # TODO: make pad access parametrisable to cope with more than 4 GPIOs
474 num_gpios = dut.gpio_o_test.width
475 # Grab GPIO outpud pad resource from JTAG BS - end of chain
476 print(dut.jtag.boundary_scan_pads.keys())
477 gpio0_o = dut.jtag.boundary_scan_pads['gpio_0__gpio0__o']['o']
478 gpio1_o = dut.jtag.boundary_scan_pads['gpio_0__gpio1__o']['o']
479 gpio2_o = dut.jtag.boundary_scan_pads['gpio_0__gpio2__o']['o']
480 gpio3_o = dut.jtag.boundary_scan_pads['gpio_0__gpio3__o']['o']
481 gpio_pad_out = [gpio0_o, gpio1_o, gpio2_o, gpio3_o]
482
483 # Grab GPIO output enable pad resource from JTAG BS - end of chain
484 gpio0_oe = dut.jtag.boundary_scan_pads['gpio_0__gpio0__oe']['o']
485 gpio1_oe = dut.jtag.boundary_scan_pads['gpio_0__gpio1__oe']['o']
486 gpio2_oe = dut.jtag.boundary_scan_pads['gpio_0__gpio2__oe']['o']
487 gpio3_oe = dut.jtag.boundary_scan_pads['gpio_0__gpio3__oe']['o']
488 gpio_pad_oe = [gpio0_oe, gpio1_oe, gpio2_oe, gpio3_oe]
489
490 # Grab GPIO input pad resource from JTAG BS - start of chain
491 gpio0_pad_in = dut.jtag.boundary_scan_pads['gpio_0__gpio0__i']['i']
492 gpio1_pad_in = dut.jtag.boundary_scan_pads['gpio_0__gpio1__i']['i']
493 gpio2_pad_in = dut.jtag.boundary_scan_pads['gpio_0__gpio2__i']['i']
494 gpio3_pad_in = dut.jtag.boundary_scan_pads['gpio_0__gpio3__i']['i']
495 gpio_pad_in = [gpio0_pad_in, gpio1_pad_in, gpio2_pad_in, gpio3_pad_in]
496
497 # Have the sim run through a for-loop where the gpio_o_test is
498 # incremented like a counter (0000, 0001...)
499 # At each iteration of the for-loop, assert:
500 # + output set at core matches output seen at pad
501 # TODO + input set at pad matches input seen at core
502 # TODO + if gpio_o_test bit is cleared, output seen at pad matches
503 # input seen at pad
504 num_gpio_o_states = num_gpios**2
505 pad_out = [0] * num_gpios
506 pad_oe = [0] * num_gpios
507 #print("Num of permutations of gpio_o_test record: ", num_gpio_o_states)
508 for gpio_o_val in range(0, num_gpio_o_states):
509 yield dut.gpio_o_test.eq(gpio_o_val)
510 # yield Settle()
511 yield # Move to the next clk cycle
512
513 # Cycle through all input combinations
514 for gpio_i_val in range(0, num_gpio_o_states):
515 # Set each gpio input at pad to test value
516 for gpio_bit in range(0, num_gpios):
517 yield gpio_pad_in[gpio_bit].eq((gpio_i_val >> gpio_bit) & 0x1)
518 yield
519 # After changing the gpio0/1/2/3 inputs,
520 # the output is also going to change.
521 # *therefore it must be read again* to get the
522 # snapshot (as a python value)
523 for gpio_bit in range(0, num_gpios):
524 pad_out[gpio_bit] = yield gpio_pad_out[gpio_bit]
525 yield
526 for gpio_bit in range(0, num_gpios):
527 # check core and pad in
528 gpio_i_ro = yield dut.gpio_i_ro[gpio_bit]
529 out_test_bit = ((gpio_o_val & (1 << gpio_bit)) != 0)
530 in_bit = ((gpio_i_val & (1 << gpio_bit)) != 0)
531 # Check that the core end input matches pad
532 assert in_bit == gpio_i_ro
533 # Test that the output at pad matches:
534 # Pad output == given test output XOR test input
535 assert (out_test_bit ^ in_bit) == pad_out[gpio_bit]
536
537 # For debugging - VERY verbose
538 # print("---------------------")
539 #print("Test Out: ", bin(gpio_o_val))
540 #print("Test Input: ", bin(gpio_i_val))
541 # Print MSB first
542 #print("Pad Output: ", list(reversed(pad_out)))
543 # print("---------------------")
544
545 # For-loop for testing output enable signals
546 for gpio_o_val in range(0, num_gpio_o_states):
547 yield dut.gpio_oe_test.eq(gpio_o_val)
548 yield # Move to the next clk cycle
549
550 for gpio_bit in range(0, num_gpios):
551 pad_oe[gpio_bit] = yield gpio_pad_oe[gpio_bit]
552 yield
553
554 for gpio_bit in range(0, num_gpios):
555 oe_test_bit = ((gpio_o_val & (1 << gpio_bit)) != 0)
556 # oe set at core matches oe seen at pad:
557 assert oe_test_bit == pad_oe[gpio_bit]
558 # For debugging - VERY verbose
559 # print("---------------------")
560 #print("Test Output Enable: ", bin(gpio_o_val))
561 # Print MSB first
562 #print("Pad Output Enable: ", list(reversed(pad_oe)))
563 # print("---------------------")
564
565 # Reset test ouput register
566 yield dut.gpio_o_test.eq(0)
567 print("GPIO Test PASSED!")
568
569
570 def test_uart(dut):
571 # grab the JTAG resource pad
572 print()
573 print("bs pad keys", dut.jtag.boundary_scan_pads.keys())
574 print()
575 uart_rx_pad = dut.jtag.boundary_scan_pads['uart_0__rx']['i']
576 uart_tx_pad = dut.jtag.boundary_scan_pads['uart_0__tx']['o']
577
578 print("uart rx pad", uart_rx_pad)
579 print("uart tx pad", uart_tx_pad)
580
581 # Test UART by writing 0 and 1 to RX
582 # Internally TX connected to RX,
583 # so match pad TX with RX
584 for i in range(0, 2):
585 yield uart_rx_pad.eq(i)
586 # yield uart_rx_pad.eq(i)
587 yield Settle()
588 yield # one clock cycle
589 tx_val = yield uart_tx_pad
590 print("xmit uart", tx_val, 1)
591 assert tx_val == i
592
593 print("UART Test PASSED!")
594
595
596 def test_i2c(dut):
597 i2c_sda_i_pad = dut.jtag.boundary_scan_pads['i2c_0__sda__i']['i']
598 i2c_sda_o_pad = dut.jtag.boundary_scan_pads['i2c_0__sda__o']['o']
599 i2c_sda_oe_pad = dut.jtag.boundary_scan_pads['i2c_0__sda__oe']['o']
600
601 i2c_scl_i_pad = dut.jtag.boundary_scan_pads['i2c_0__scl__i']['i']
602 i2c_scl_o_pad = dut.jtag.boundary_scan_pads['i2c_0__scl__o']['o']
603 i2c_scl_oe_pad = dut.jtag.boundary_scan_pads['i2c_0__scl__oe']['o']
604
605 #i2c_pad = dut.jtag.resource_table_pads[('i2c', 0)]
606 #print ("i2c pad", i2c_pad)
607 #print ("i2c pad", i2c_pad.layout)
608
609 for i in range(0, 2):
610 yield i2c_sda_i_pad.eq(i) # i2c_pad.sda.i.eq(i)
611 yield i2c_scl_i_pad.eq(i) # i2c_pad.scl.i.eq(i)
612 yield dut.i2c_sda_oe_test.eq(i)
613 yield dut.i2c_scl_oe_test.eq(i)
614 yield Settle()
615 yield # one clock cycle
616 sda_o_val = yield i2c_sda_o_pad
617 scl_o_val = yield i2c_scl_o_pad
618 sda_oe_val = yield i2c_sda_oe_pad
619 scl_oe_val = yield i2c_scl_oe_pad
620 print("Test input: ", i, " SDA/SCL out: ", sda_o_val, scl_o_val,
621 " SDA/SCL oe: ", sda_oe_val, scl_oe_val)
622 assert sda_o_val == i
623 assert scl_o_val == i
624 assert sda_oe_val == i
625 assert scl_oe_val == i
626
627 print("I2C Test PASSED!")
628
629 # JTAG boundary scan reg addresses - See c4m/nmigen/jtag/tap.py line #357
630 BS_EXTEST = 0
631 BS_INTEST = 0
632 BS_SAMPLE = 2
633 BS_PRELOAD = 2
634
635 def test_jtag_bs_chain(dut):
636 # print(dir(dut.jtag))
637 # print(dir(dut))
638 # print(dut.jtag._ir_width)
639 # print("JTAG I/O dictionary of core/pad signals:")
640 # print(dut.jtag.ios.keys())
641
642 print("JTAG BS Reset")
643 yield from jtag_set_reset(dut.jtag)
644
645 # TODO: cleanup!
646 # Based on number of ios entries, produce a test shift reg pattern
647 bslen = len(dut.jtag.ios)
648 bsdata = 2**bslen - 1 # Fill with all 1s for now
649 fulldata = bsdata # for testing
650 emptydata = 0 # for testing
651
652 mask_i = produce_ios_mask(dut, is_i=True, is_o=False, is_oe=False)
653 mask_i_oe = produce_ios_mask(dut, is_i=True, is_o=False, is_oe=True)
654 mask_o = produce_ios_mask(dut, is_i=False, is_o=True, is_oe=False)
655 mask_oe = produce_ios_mask(dut, is_i=False, is_o=False, is_oe=True)
656 mask_o_oe = produce_ios_mask(dut, is_i=False, is_o=True, is_oe=True)
657 mask_low = 0
658 mask_all = 2**bslen - 1
659
660 num_bit_format = "{:0" + str(bslen) + "b}"
661 print("Masks (LSB corresponds to bit0 of the BS chain register!)")
662 print("Input only :", num_bit_format.format(mask_i))
663 print("Input and oe:", num_bit_format.format(mask_o_oe))
664 print("Output only :", num_bit_format.format(mask_o))
665 print("Out en only :", num_bit_format.format(mask_oe))
666 print("Output and oe:", num_bit_format.format(mask_o_oe))
667
668 yield from jtag_unit_test(dut, BS_EXTEST, False, bsdata, mask_o_oe, mask_o)
669 yield from jtag_unit_test(dut, BS_SAMPLE, False, bsdata, mask_low, mask_low)
670
671 # Run through GPIO, UART, and I2C tests so that all signals are asserted
672 yield from test_gpios(dut)
673 yield from test_uart(dut)
674 yield from test_i2c(dut)
675
676 bsdata = emptydata
677 yield from jtag_unit_test(dut, BS_EXTEST, True, bsdata, mask_i, mask_i_oe)
678 yield from jtag_unit_test(dut, BS_SAMPLE, True, bsdata, mask_all, mask_all)
679
680 print("JTAG Boundary Scan Chain Test PASSED!")
681
682 # ONLY NEEDED FOR DEBUG - MAKE SURE TAP DRIVER FUNCTIONS CORRECT FIRST!
683 def swap_bit_order(word, wordlen):
684 rev_word = 0
685 for i in range(wordlen):
686 rev_word += ((word >> i) & 0x1) << (wordlen-1-i)
687
688 num_bit_format = "{:0" + str(wordlen) + "b}"
689 print_str = "Orig:" + num_bit_format + " | Bit Swapped:" + num_bit_format
690 print(print_str.format(word, rev_word))
691
692 return rev_word
693
694 def jtag_unit_test(dut, bs_type, is_io_set, bsdata, exp_pads, exp_tdo):
695 bslen = len(dut.jtag.ios) #* 2
696 print("Chain len based on jtag.ios: {}".format(bslen))
697 if bs_type == BS_EXTEST:
698 print("Sending TDI data with core/pads disconnected")
699 elif bs_type == BS_SAMPLE:
700 print("Sending TDI data with core/pads connected")
701 else:
702 raise Exception("Unsupported BS chain mode!")
703
704 if is_io_set:
705 print("All pad inputs/core outputs set, bs data: {0:b}"
706 .format(bsdata))
707 else:
708 print("All pad inputs/core outputs reset, bs data: {0:b}"
709 .format(bsdata))
710
711 result = yield from jtag_read_write_reg(dut.jtag, bs_type, bslen, bsdata,
712 reverse=True)
713 if bs_type == BS_EXTEST:
714 # TDO is only outputting previous BS chain data, must configure to
715 # output BS chain to the main shift register
716 yield from jtag_set_shift_dr(dut.jtag)
717 result = yield from tms_data_getset(dut.jtag, bs_type, bslen, bsdata,
718 reverse=True)
719 yield from jtag_set_idle(dut.jtag)
720
721 # TODO: make format based on bslen, not a magic number 20-bits wide
722 print("TDI BS Data: {0:020b}, Data Length (bits): {1}"
723 .format(bsdata, bslen))
724 print("TDO BS Data: {0:020b}".format(result))
725 yield from check_ios_keys(dut, result, exp_pads, exp_tdo)
726
727 #yield # testing extra clock
728 # Reset shift register between tests
729 yield from jtag_set_reset(dut.jtag)
730
731 def check_ios_keys(dut, tdo_data, test_vector, exp_tdo):
732 print("Checking ios signals with TDO and given test vectors")
733 bslen = len(dut.jtag.ios)
734 ios_keys = list(dut.jtag.ios.keys())
735 print(" ios Signals | From TDO | --- | ----")
736 print("Side|Exp|Seen | Side|Exp|Seen | I/O | Name")
737 for i in range(0, bslen):
738 signal = ios_keys[i]
739 exp_pad_val = (test_vector >> i) & 0b1
740 exp_tdo_val = (exp_tdo >> i) & 0b1
741 tdo_value = (tdo_data >> i) & 0b1
742 # Only observed signals so far are outputs...
743 # TODO: Cleanup!
744 if check_if_signal_output(ios_keys[i]):
745 temp_result = yield dut.jtag.boundary_scan_pads[signal]['o']
746 print("Pad |{0:3b}|{1:4b} | Core|{2:3b}|{3:4b} | o | {4}"
747 .format(exp_pad_val, temp_result, exp_tdo_val, tdo_value, signal))
748 # ...or inputs
749 elif check_if_signal_input(ios_keys[i]):
750 temp_result = yield dut.jtag.boundary_scan_pads[signal]['i']
751 print("Pad |{0:3b}|{1:4b} | Pad |{2:3b}|{3:4b} | i | {4}"
752 .format(exp_pad_val, temp_result, exp_tdo_val, tdo_value, signal))
753 else:
754 raise Exception("Signal in JTAG ios dict: " + signal
755 + " cannot be determined as input or output!")
756 assert temp_result == exp_pad_val
757 assert tdo_value == exp_tdo_val
758
759 # TODO: may need to expand to support further signals contained in the
760 # JTAG module ios dictionary!
761
762
763 def check_if_signal_output(signal_str):
764 if ('__o' in signal_str) or ('__tx' in signal_str):
765 return True
766 else:
767 return False
768
769
770 def check_if_signal_input(signal_str):
771 if ('__i' in signal_str) or ('__rx' in signal_str):
772 return True
773 else:
774 return False
775
776
777 def produce_ios_mask(dut, is_i=False, is_o=True, is_oe=False):
778 if is_i and not(is_o) and not(is_oe):
779 mask_type = "input"
780 elif not(is_i) and is_o:
781 mask_type = "output"
782 else:
783 mask_type = "i={:b} | o={:b} | oe={:b} ".format(is_i, is_o, is_oe)
784 print("Determine the", mask_type, "mask")
785 bslen = len(dut.jtag.ios)
786 ios_keys = list(dut.jtag.ios.keys())
787 mask = 0
788 for i in range(0, bslen):
789 signal = ios_keys[i]
790 if (('__o' in ios_keys[i]) or ('__tx' in ios_keys[i])):
791 if ('__oe' in ios_keys[i]):
792 if is_oe:
793 mask += (1 << i)
794 else:
795 if is_o:
796 mask += (1 << i)
797 else:
798 if is_i:
799 mask += (1 << i)
800 return mask
801
802
803 def print_all_ios_keys(dut):
804 print("Print all ios keys")
805 bslen = len(dut.jtag.ios)
806 ios_keys = list(dut.jtag.ios.keys())
807 for i in range(0, bslen):
808 signal = ios_keys[i]
809 # Check if outputs are asserted
810 if ('__o' in ios_keys[i]) or ('__tx' in ios_keys[i]):
811 print("Pad Output | Name: ", signal)
812 else:
813 print("Pad Input | Name: ", signal)
814
815
816 # Copied from test_jtag_tap.py
817 # JTAG-ircodes for accessing DMI
818 DMI_ADDR = 5
819 DMI_READ = 6
820 DMI_WRRD = 7
821
822 # JTAG-ircodes for accessing Wishbone
823 WB_ADDR = 8
824 WB_READ = 9
825 WB_WRRD = 10
826
827
828 def test_jtag_dmi_wb():
829 print(dir(top.jtag))
830 print(dir(top))
831 print("JTAG BS Reset")
832 yield from jtag_set_reset(top.jtag)
833
834 print("JTAG I/O dictionary of core/pad signals:")
835 print(top.jtag.ios.keys())
836
837 # Copied from test_jtag_tap
838 # Don't know if the ID is the same for all JTAG instances
839 ####### JTAGy stuff (IDCODE) ######
840
841 # read idcode
842 idcode = yield from jtag_read_write_reg(top.jtag, 0b1, 32)
843 print("idcode", hex(idcode))
844 assert idcode == 0x18ff
845
846 ####### JTAG to DMI ######
847
848 # write DMI address
849 yield from jtag_read_write_reg(top.jtag, DMI_ADDR, 8, DBGCore.CTRL)
850
851 # read DMI CTRL register
852 status = yield from jtag_read_write_reg(top.jtag, DMI_READ, 64)
853 print("dmi ctrl status", hex(status))
854 #assert status == 4
855
856 # write DMI address
857 yield from jtag_read_write_reg(top.jtag, DMI_ADDR, 8, 0)
858
859 # write DMI CTRL register
860 status = yield from jtag_read_write_reg(top.jtag, DMI_WRRD, 64, 0b101)
861 print("dmi ctrl status", hex(status))
862 # assert status == 4 # returned old value (nice! cool feature!)
863
864 # write DMI address
865 yield from jtag_read_write_reg(top.jtag, DMI_ADDR, 8, DBGCore.CTRL)
866
867 # read DMI CTRL register
868 status = yield from jtag_read_write_reg(top.jtag, DMI_READ, 64)
869 print("dmi ctrl status", hex(status))
870 #assert status == 6
871
872 # write DMI MSR address
873 yield from jtag_read_write_reg(top.jtag, DMI_ADDR, 8, DBGCore.MSR)
874
875 # read DMI MSR register
876 msr = yield from jtag_read_write_reg(top.jtag, DMI_READ, 64)
877 print("dmi msr", hex(msr))
878 #assert msr == 0xdeadbeef
879
880 ####### JTAG to Wishbone ######
881
882 # write Wishbone address
883 yield from jtag_read_write_reg(top.jtag, WB_ADDR, 16, 0x18)
884
885 # write/read wishbone data
886 data = yield from jtag_read_write_reg(top.jtag, WB_WRRD, 16, 0xfeef)
887 print("wb write", hex(data))
888
889 # write Wishbone address
890 yield from jtag_read_write_reg(top.jtag, WB_ADDR, 16, 0x18)
891
892 # write/read wishbone data
893 data = yield from jtag_read_write_reg(top.jtag, WB_READ, 16, 0)
894 print("wb read", hex(data))
895
896 ####### done - tell dmi_sim to stop (otherwise it won't) ########
897
898 top.jtag.stop = True
899
900
901 def test_debug_print(dut):
902 print("Test used for getting object methods/information")
903 print("Moved here to clear clutter of gpio test")
904
905 print("printing out info about the resource gpio0")
906 print(dut.gpio['gpio0']['i'])
907 print("this is a PIN resource", type(dut.gpio['gpio0']['i']))
908 # yield can only be done on SIGNALS or RECORDS,
909 # NOT Pins/Resources gpio0_core_in = yield top.gpio['gpio0']['i']
910 #print("Test gpio0 core in: ", gpio0_core_in)
911
912 print("JTAG")
913 print(dut.jtag.__class__.__name__, dir(dut.jtag))
914 print("TOP")
915 print(dut.__class__.__name__, dir(dut))
916 print("PORT")
917 print(dut.ports.__class__.__name__, dir(dut.ports))
918 print("GPIO")
919 print(dut.gpio.__class__.__name__, dir(dut.gpio))
920
921 print("UART")
922 print(dir(dut.jtag.boundary_scan_pads['uart_0__rx__pad__i']))
923 print(dut.jtag.boundary_scan_pads['uart_0__rx__pad__i'].keys())
924 print(dut.jtag.boundary_scan_pads['uart_0__tx__pad__o'])
925 # print(type(dut.jtag.boundary_scan_pads['uart_0__rx__pad__i']['rx']))
926 print("jtag pad table keys")
927 print(dut.jtag.resource_table_pads.keys())
928 print(type(dut.jtag.resource_table_pads[('uart', 0)].rx.i))
929 print(dut.jtag.boundary_scan_pads['uart_0__rx__i'])
930
931 print("I2C")
932 print(dut.jtag.boundary_scan_pads['i2c_0__sda__i'])
933 print(type(dut.jtag.boundary_scan_pads['i2c_0__sda__i']['i']))
934
935 print(dut.jtag.resource_table_pads)
936 print(dut.jtag.boundary_scan_pads)
937
938 # Trying to read input from core side, looks like might be a pin...
939 # XXX don't "look like" - don't guess - *print it out*
940 #print ("don't guess, CHECK", type(top.gpio.gpio0.i))
941
942 print() # extra print to divide the output
943 yield
944
945
946 def setup_blinker(build_blinker=False):
947 """
948 and to create a Platform instance with that list, and build
949 something random
950
951 p=Platform()
952 p.resources=listofstuff
953 p.build(Blinker())
954 """
955
956 pinset = dummy_pinset()
957 print(pinset)
958 resources = create_resources(pinset)
959 top = Blinker(pinset, resources, no_jtag_connect=False) # True)
960
961 vl = rtlil.convert(top, ports=top.ports())
962 with open("test_jtag_blinker.il", "w") as f:
963 f.write(vl)
964
965 if build_blinker:
966 # XXX these modules are all being added *AFTER* the build process links
967 # everything together. the expectation that this would work is...
968 # unrealistic. ordering, clearly, is important.
969
970 # This JTAG code copied from test, probably not needed
971 # dut = JTAG(test_pinset(), wb_data_wid=64, domain="sync")
972 top.jtag.stop = False
973 # rather than the client access the JTAG bus directly
974 # create an alternative that the client sets
975
976 class Dummy:
977 pass
978 cdut = Dummy()
979 cdut.cbus = JTAGInterface()
980
981 # set up client-server on port 44843-something
982 top.jtag.s = JTAGServer()
983 cdut.c = JTAGClient()
984 top.jtag.s.get_connection()
985 # else:
986 # print ("running server only as requested,
987 # use openocd remote to test")
988 # sys.stdout.flush()
989 # top.jtag.s.get_connection(None) # block waiting for connection
990
991 # take copy of ir_width and scan_len
992 cdut._ir_width = top.jtag._ir_width
993 cdut.scan_len = top.jtag.scan_len
994
995 p = ASICPlatform(resources, top.jtag)
996 p.build(top)
997 # this is what needs to gets treated as "top", after "main module" top
998 # is augmented with IO pads with JTAG tacked on. the expectation that
999 # the get_input() etc functions will be called magically by some other
1000 # function is unrealistic.
1001 top_fragment = p.fragment
1002
1003 return top
1004
1005
1006 def test_jtag():
1007 dut = setup_blinker(build_blinker=False)
1008
1009 # XXX simulating top (the module that does not itself contain IO pads
1010 # because that's covered by build) cannot possibly be expected to work
1011 # particularly when modules have been added *after* the platform build()
1012 # function has been called.
1013
1014 sim = Simulator(dut)
1015 sim.add_clock(1e-6, domain="sync") # standard clock
1016
1017 # sim.add_sync_process(wrap(jtag_srv(top))) #? jtag server
1018 # if len(sys.argv) != 2 or sys.argv[1] != 'server':
1019 # actual jtag tester
1020 #sim.add_sync_process(wrap(jtag_sim(cdut, top.jtag)))
1021 # handles (pretends to be) DMI
1022 # sim.add_sync_process(wrap(dmi_sim(top.jtag)))
1023
1024 # sim.add_sync_process(wrap(test_gpios(top)))
1025 # sim.add_sync_process(wrap(test_uart(top)))
1026 # sim.add_sync_process(wrap(test_i2c(top)))
1027 # sim.add_sync_process(wrap(test_debug_print()))
1028
1029 sim.add_sync_process(wrap(test_jtag_bs_chain(dut)))
1030
1031 with sim.write_vcd("blinker_test.vcd"):
1032 sim.run()
1033
1034
1035 if __name__ == '__main__':
1036 test_jtag()