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