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