Made progress in figuring out JTAG. Getting TDO, still need more testing
[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])
203 m.d.comb += gpio.gpio1.oe.eq(gpio_oe_test[1])
204 m.d.comb += gpio.gpio2.oe.eq(gpio_oe_test[2])
205 m.d.comb += gpio.gpio3.oe.eq(gpio_oe_test[3])
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.scl.o.eq(i2c.scl.i)
225 m.d.comb += i2c.sda.o.eq(i2c.sda.i)
226 # Connect output enable to test port for sim
227 m.d.comb += i2c.sda.oe.eq(i2c_sda_oe_test)
228 m.d.comb += i2c.scl.oe.eq(i2c_scl_oe_test)
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
630 # JTAG boundary scan reg addresses - See c4m/nmigen/jtag/tap.py line #357
631 BS_EXTEST = 0
632 BS_INTEST = 0
633 BS_SAMPLE = 2
634 BS_PRELOAD = 2
635
636
637 def test_jtag_bs_chain(dut):
638 print(dir(dut.jtag))
639 print(dir(dut))
640
641 print("JTAG BS Reset")
642 yield from jtag_set_reset(dut.jtag)
643
644 #print("JTAG I/O dictionary of core/pad signals:")
645 # print(dut.jtag.ios.keys())
646
647 # Based on number of ios entries, produce a test shift reg pattern
648 bslen = len(dut.jtag.ios)
649 bsdata = 2**bslen - 1 # Fill with all 1s for now
650 fulldata = bsdata # for testing
651 emptydata = 0 # for testing
652
653 mask_inputs = produce_ios_io_mask(dut, is_input=True)
654 mask_outputs = produce_ios_io_mask(dut, is_input=False)
655 mask_low = 0
656 mask_high = bsdata
657
658 # TODO: make format based on bslen, not a magic number 20-bits wide
659 print("Input Mask: {0:020b}".format(mask_inputs))
660 print("Output Mask: {0:020b}".format(mask_outputs))
661
662 print(dut.jtag._ir_width)
663 #bsdata = 0xA3659
664 #bsdata = 0x20000
665 #bsdata = 0x00000
666 #uart_rx_pad = dut.jtag.boundary_scan_pads['uart_0__rx']['i']
667 #yield uart_rx_pad.eq(1)
668
669 for i in range(0, 1):
670 print("Data Reg Address: {}".format(i))
671 d_len=20
672 #d_in=0xFFFFF
673 d_in=0xB1EA5
674 """
675 yield from jtag_set_reset(dut.jtag)
676 yield from jtag_set_run(dut.jtag)
677 yield from jtag_set_shift_ir(dut.jtag)
678 yield from tms_data_getset(dut.jtag, 0, dut.jtag._ir_width, BS_EXTEST)
679 yield from jtag_set_idle(dut.jtag)
680
681 yield from jtag_set_shift_dr(dut.jtag)
682 result = yield from tms_data_getset(dut.jtag, 0, d_len, d_in)
683 yield from jtag_set_idle(dut.jtag)
684 print("TDI BS Data: {0:020b}, TDO Data: {1:020b}".format(d_in, result))
685 print("TDI BS Data: {0:05x}, TDO Data: {1:05x}".format(d_in, result))
686 """
687 """
688 #d_in=0xDBEEF
689 yield from jtag_set_reset(dut.jtag)
690 yield from jtag_set_run(dut.jtag)
691 yield from jtag_set_shift_ir(dut.jtag)
692 yield from tms_data_getset(dut.jtag, 0, dut.jtag._ir_width, 0)
693 yield from jtag_set_idle(dut.jtag)
694
695 yield from jtag_set_shift_dr(dut.jtag)
696 result = yield from tms_data_getset(dut.jtag, 0, d_len, d_in)
697 yield from jtag_set_idle(dut.jtag)
698 print("TDI BS Data: {0:020b}, TDO Data: {1:020b}".format(d_in, result))
699 print("TDI BS Data: {0:05x}, TDO Data: {1:05x}".format(d_in, result))
700 #print("TDI BS Data: {0:05x}, TDO Shift: {1:05x}".format(d_in, result>>2))
701 #yield from jtag_set_reset(dut.jtag)
702 #yield from jtag_set_run(dut.jtag)
703 yield from jtag_set_shift_ir(dut.jtag)
704 yield from tms_data_getset(dut.jtag, 0, dut.jtag._ir_width, BS_EXTEST)
705 yield from jtag_set_idle(dut.jtag)
706 """
707
708
709
710 yield from jtag_unit_test(dut, BS_EXTEST, False, bsdata, mask_outputs)
711 #yield from jtag_unit_test(dut, BS_SAMPLE, False, bsdata, mask_low)
712
713 # Run through GPIO, UART, and I2C tests so that all signals are asserted
714 #yield from test_gpios(dut)
715 #yield from test_uart(dut)
716 #yield from test_i2c(dut)
717
718 #yield from jtag_unit_test(dut, BS_EXTEST, True, emptydata, mask_inputs)
719 #yield from jtag_unit_test(dut, BS_SAMPLE, True, emptydata, mask_high)
720
721 print("JTAG Boundary Scan Chain Test PASSED!")
722
723
724 def jtag_unit_test(dut, bs_type, is_io_set, bsdata, expected):
725 bslen = len(dut.jtag.ios) #* 2
726 print("Chain len based on jtag.ios: {}".format(bslen))
727 if bs_type == BS_EXTEST:
728 print("Sending TDI data with core/pads disconnected")
729 elif bs_type == BS_SAMPLE:
730 print("Sending TDI data with core/pads connected")
731 else:
732 raise Exception("Unsupported BS chain mode!")
733
734 if is_io_set:
735 print("All pad inputs/core outputs set, bs data: {0:b}"
736 .format(bsdata))
737 else:
738 print("All pad inputs/core outputs reset, bs data: {0:b}"
739 .format(bsdata))
740
741 result = yield from jtag_read_write_reg(dut.jtag, bs_type, bslen, bsdata)
742
743 yield from jtag_set_shift_ir(dut.jtag)
744 yield from tms_data_getset(dut.jtag, 0, dut.jtag._ir_width, BS_EXTEST)
745 yield from jtag_set_idle(dut.jtag)
746 yield from jtag_set_shift_dr(dut.jtag)
747 result = yield from tms_data_getset(dut.jtag, bs_type, bslen, bsdata)
748 yield from jtag_set_idle(dut.jtag)
749
750
751
752 # TODO: TDO data does not always match the signal states, maybe JTAG reset?
753 # TODO: make format based on bslen, not a magic number 20-bits wide
754 print("TDI BS Data: {0:020b}, Data Length (bits): {1}"
755 .format(bsdata, bslen))
756 print("TDO BS Data: {0:020b}".format(result))
757 yield from check_ios_keys(dut, expected)
758
759 yield # testing extra clock
760 # Reset shift register between tests
761 yield from jtag_set_reset(dut.jtag)
762
763
764 def check_ios_keys(dut, test_vector):
765 print("Checking ios signals with given test vector")
766 bslen = len(dut.jtag.ios)
767 ios_keys = list(dut.jtag.ios.keys())
768 for i in range(0, bslen):
769 signal = ios_keys[i]
770 test_value = (test_vector >> i) & 0b1
771 # Only observed signals so far are outputs...
772 if check_if_signal_output(ios_keys[i]):
773 temp_result = yield dut.jtag.boundary_scan_pads[signal]['o']
774 print("Core Output | Name: ", signal, " Value: ", temp_result)
775 # ...or inputs
776 elif check_if_signal_input(ios_keys[i]):
777 temp_result = yield dut.jtag.boundary_scan_pads[signal]['i']
778 print("Pad Input | Name: ", signal, " Value: ", temp_result)
779 else:
780 raise Exception("Signal in JTAG ios dict: " + signal
781 + " cannot be determined as input or output!")
782 #assert temp_result == test_value
783
784 # TODO: may need to expand to support further signals contained in the
785 # JTAG module ios dictionary!
786
787
788 def check_if_signal_output(signal_str):
789 if ('__o' in signal_str) or ('__tx' in signal_str):
790 return True
791 else:
792 return False
793
794
795 def check_if_signal_input(signal_str):
796 if ('__i' in signal_str) or ('__rx' in signal_str):
797 return True
798 else:
799 return False
800
801
802 def produce_ios_io_mask(dut, is_input=False):
803 if is_input:
804 mask_type = "input"
805 else:
806 mask_type = "output"
807 print("Determine the", mask_type, "mask")
808 bslen = len(dut.jtag.ios)
809 ios_keys = list(dut.jtag.ios.keys())
810 mask = 0
811 for i in range(0, bslen):
812 signal = ios_keys[i]
813 if (('__o' in ios_keys[i]) or ('__tx' in ios_keys[i])):
814 if is_input == False:
815 mask += (1 << i)
816 else:
817 if is_input == True:
818 mask += (1 << i)
819 return mask
820
821
822 def print_all_ios_keys(dut):
823 print("Print all ios keys")
824 bslen = len(dut.jtag.ios)
825 ios_keys = list(dut.jtag.ios.keys())
826 for i in range(0, bslen):
827 signal = ios_keys[i]
828 # Check if outputs are asserted
829 if ('__o' in ios_keys[i]) or ('__tx' in ios_keys[i]):
830 print("Core Output | Name: ", signal)
831 else:
832 print("Pad Input | Name: ", signal)
833
834
835 # Copied from test_jtag_tap.py
836 # JTAG-ircodes for accessing DMI
837 DMI_ADDR = 5
838 DMI_READ = 6
839 DMI_WRRD = 7
840
841 # JTAG-ircodes for accessing Wishbone
842 WB_ADDR = 8
843 WB_READ = 9
844 WB_WRRD = 10
845
846
847 def test_jtag_dmi_wb():
848 print(dir(top.jtag))
849 print(dir(top))
850 print("JTAG BS Reset")
851 yield from jtag_set_reset(top.jtag)
852
853 print("JTAG I/O dictionary of core/pad signals:")
854 print(top.jtag.ios.keys())
855
856 # Copied from test_jtag_tap
857 # Don't know if the ID is the same for all JTAG instances
858 ####### JTAGy stuff (IDCODE) ######
859
860 # read idcode
861 idcode = yield from jtag_read_write_reg(top.jtag, 0b1, 32)
862 print("idcode", hex(idcode))
863 assert idcode == 0x18ff
864
865 ####### JTAG to DMI ######
866
867 # write DMI address
868 yield from jtag_read_write_reg(top.jtag, DMI_ADDR, 8, DBGCore.CTRL)
869
870 # read DMI CTRL register
871 status = yield from jtag_read_write_reg(top.jtag, DMI_READ, 64)
872 print("dmi ctrl status", hex(status))
873 #assert status == 4
874
875 # write DMI address
876 yield from jtag_read_write_reg(top.jtag, DMI_ADDR, 8, 0)
877
878 # write DMI CTRL register
879 status = yield from jtag_read_write_reg(top.jtag, DMI_WRRD, 64, 0b101)
880 print("dmi ctrl status", hex(status))
881 # assert status == 4 # returned old value (nice! cool feature!)
882
883 # write DMI address
884 yield from jtag_read_write_reg(top.jtag, DMI_ADDR, 8, DBGCore.CTRL)
885
886 # read DMI CTRL register
887 status = yield from jtag_read_write_reg(top.jtag, DMI_READ, 64)
888 print("dmi ctrl status", hex(status))
889 #assert status == 6
890
891 # write DMI MSR address
892 yield from jtag_read_write_reg(top.jtag, DMI_ADDR, 8, DBGCore.MSR)
893
894 # read DMI MSR register
895 msr = yield from jtag_read_write_reg(top.jtag, DMI_READ, 64)
896 print("dmi msr", hex(msr))
897 #assert msr == 0xdeadbeef
898
899 ####### JTAG to Wishbone ######
900
901 # write Wishbone address
902 yield from jtag_read_write_reg(top.jtag, WB_ADDR, 16, 0x18)
903
904 # write/read wishbone data
905 data = yield from jtag_read_write_reg(top.jtag, WB_WRRD, 16, 0xfeef)
906 print("wb write", hex(data))
907
908 # write Wishbone address
909 yield from jtag_read_write_reg(top.jtag, WB_ADDR, 16, 0x18)
910
911 # write/read wishbone data
912 data = yield from jtag_read_write_reg(top.jtag, WB_READ, 16, 0)
913 print("wb read", hex(data))
914
915 ####### done - tell dmi_sim to stop (otherwise it won't) ########
916
917 top.jtag.stop = True
918
919
920 def test_debug_print(dut):
921 print("Test used for getting object methods/information")
922 print("Moved here to clear clutter of gpio test")
923
924 print("printing out info about the resource gpio0")
925 print(dut.gpio['gpio0']['i'])
926 print("this is a PIN resource", type(dut.gpio['gpio0']['i']))
927 # yield can only be done on SIGNALS or RECORDS,
928 # NOT Pins/Resources gpio0_core_in = yield top.gpio['gpio0']['i']
929 #print("Test gpio0 core in: ", gpio0_core_in)
930
931 print("JTAG")
932 print(dut.jtag.__class__.__name__, dir(dut.jtag))
933 print("TOP")
934 print(dut.__class__.__name__, dir(dut))
935 print("PORT")
936 print(dut.ports.__class__.__name__, dir(dut.ports))
937 print("GPIO")
938 print(dut.gpio.__class__.__name__, dir(dut.gpio))
939
940 print("UART")
941 print(dir(dut.jtag.boundary_scan_pads['uart_0__rx__pad__i']))
942 print(dut.jtag.boundary_scan_pads['uart_0__rx__pad__i'].keys())
943 print(dut.jtag.boundary_scan_pads['uart_0__tx__pad__o'])
944 # print(type(dut.jtag.boundary_scan_pads['uart_0__rx__pad__i']['rx']))
945 print("jtag pad table keys")
946 print(dut.jtag.resource_table_pads.keys())
947 print(type(dut.jtag.resource_table_pads[('uart', 0)].rx.i))
948 print(dut.jtag.boundary_scan_pads['uart_0__rx__i'])
949
950 print("I2C")
951 print(dut.jtag.boundary_scan_pads['i2c_0__sda__i'])
952 print(type(dut.jtag.boundary_scan_pads['i2c_0__sda__i']['i']))
953
954 print(dut.jtag.resource_table_pads)
955 print(dut.jtag.boundary_scan_pads)
956
957 # Trying to read input from core side, looks like might be a pin...
958 # XXX don't "look like" - don't guess - *print it out*
959 #print ("don't guess, CHECK", type(top.gpio.gpio0.i))
960
961 print() # extra print to divide the output
962 yield
963
964
965 def setup_blinker(build_blinker=False):
966 """
967 and to create a Platform instance with that list, and build
968 something random
969
970 p=Platform()
971 p.resources=listofstuff
972 p.build(Blinker())
973 """
974
975 pinset = dummy_pinset()
976 print(pinset)
977 resources = create_resources(pinset)
978 top = Blinker(pinset, resources, no_jtag_connect=False) # True)
979
980 vl = rtlil.convert(top, ports=top.ports())
981 with open("test_jtag_blinker.il", "w") as f:
982 f.write(vl)
983
984 if build_blinker:
985 # XXX these modules are all being added *AFTER* the build process links
986 # everything together. the expectation that this would work is...
987 # unrealistic. ordering, clearly, is important.
988
989 # This JTAG code copied from test, probably not needed
990 # dut = JTAG(test_pinset(), wb_data_wid=64, domain="sync")
991 top.jtag.stop = False
992 # rather than the client access the JTAG bus directly
993 # create an alternative that the client sets
994
995 class Dummy:
996 pass
997 cdut = Dummy()
998 cdut.cbus = JTAGInterface()
999
1000 # set up client-server on port 44843-something
1001 top.jtag.s = JTAGServer()
1002 cdut.c = JTAGClient()
1003 top.jtag.s.get_connection()
1004 # else:
1005 # print ("running server only as requested,
1006 # use openocd remote to test")
1007 # sys.stdout.flush()
1008 # top.jtag.s.get_connection(None) # block waiting for connection
1009
1010 # take copy of ir_width and scan_len
1011 cdut._ir_width = top.jtag._ir_width
1012 cdut.scan_len = top.jtag.scan_len
1013
1014 p = ASICPlatform(resources, top.jtag)
1015 p.build(top)
1016 # this is what needs to gets treated as "top", after "main module" top
1017 # is augmented with IO pads with JTAG tacked on. the expectation that
1018 # the get_input() etc functions will be called magically by some other
1019 # function is unrealistic.
1020 top_fragment = p.fragment
1021
1022 return top
1023
1024
1025 def test_jtag():
1026 dut = setup_blinker(build_blinker=False)
1027
1028 # XXX simulating top (the module that does not itself contain IO pads
1029 # because that's covered by build) cannot possibly be expected to work
1030 # particularly when modules have been added *after* the platform build()
1031 # function has been called.
1032
1033 sim = Simulator(dut)
1034 sim.add_clock(1e-6, domain="sync") # standard clock
1035
1036 # sim.add_sync_process(wrap(jtag_srv(top))) #? jtag server
1037 # if len(sys.argv) != 2 or sys.argv[1] != 'server':
1038 # actual jtag tester
1039 #sim.add_sync_process(wrap(jtag_sim(cdut, top.jtag)))
1040 # handles (pretends to be) DMI
1041 # sim.add_sync_process(wrap(dmi_sim(top.jtag)))
1042
1043 # sim.add_sync_process(wrap(test_gpios(top)))
1044 # sim.add_sync_process(wrap(test_uart(top)))
1045 # sim.add_sync_process(wrap(test_i2c(top)))
1046 # sim.add_sync_process(wrap(test_debug_print()))
1047
1048 sim.add_sync_process(wrap(test_jtag_bs_chain(dut)))
1049
1050 with sim.write_vcd("blinker_test.vcd"):
1051 sim.run()
1052
1053
1054 if __name__ == '__main__':
1055 test_jtag()