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