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