add gpio and start doing print-outs to find out what is in Blinker.gpio
[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 c4m.nmigen.jtag.tap import TAP, IOType
29 from c4m.nmigen.jtag.bus import Interface as JTAGInterface
30 #from soc.debug.dmi import DMIInterface, DBGCore
31 #from soc.debug.test.dmi_sim import dmi_sim
32 #from soc.debug.test.jtagremote import JTAGServer, JTAGClient
33 from nmigen.build.res import ResourceError
34
35 # Was thinking of using these functions, but skipped for simplicity for now
36 # XXX nope. the output from JSON file.
37 #from pinfunctions import (i2s, lpc, emmc, sdmmc, mspi, mquadspi, spi,
38 # quadspi, i2c, mi2c, jtag, uart, uartfull, rgbttl, ulpi, rgmii, flexbus1,
39 # flexbus2, sdram1, sdram2, sdram3, vss, vdd, sys, eint, pwm, gpio)
40
41 # File for stage 1 pinmux tested proposed by Luke,
42 # https://bugs.libre-soc.org/show_bug.cgi?id=50#c10
43
44
45 def dummy_pinset():
46 # sigh this needs to come from pinmux.
47 gpios = []
48 for i in range(4):
49 gpios.append("%d*" % i)
50 return {'uart': ['tx+', 'rx-'],
51 'gpio': gpios,
52 #'jtag': ['tms-', 'tdi-', 'tdo+', 'tck+'],
53 'i2c': ['sda*', 'scl+']}
54
55 """
56 a function is needed which turns the results of dummy_pinset()
57 into:
58
59 [UARTResource("uart", 0, tx=..., rx=..),
60 I2CResource("i2c", 0, scl=..., sda=...),
61 Resource("gpio", 0, Subsignal("i"...), Subsignal("o"...)
62 Resource("gpio", 1, Subsignal("i"...), Subsignal("o"...)
63 ...
64 ]
65 """
66
67
68 def create_resources(pinset):
69 resources = []
70 for periph, pins in pinset.items():
71 print(periph, pins)
72 if periph == 'i2c':
73 #print("I2C required!")
74 resources.append(I2CResource('i2c', 0, sda='sda', scl='scl'))
75 elif periph == 'uart':
76 #print("UART required!")
77 resources.append(UARTResource('uart', 0, tx='tx', rx='rx'))
78 elif periph == 'gpio':
79 #print("GPIO required!")
80 print ("GPIO is defined as '*' type, meaning i, o and oe needed")
81 ios = []
82 for pin in pins:
83 pname = "gpio"+pin[:-1] # strip "*" on end
84 # urrrr... tristsate and io assume a single pin which is
85 # of course exactly what we don't want in an ASIC: we want
86 # *all three* pins but the damn port is not outputted
87 # as a triplet, it's a single Record named "io". sigh.
88 # therefore the only way to get a triplet of i/o/oe
89 # is to *actually* create explicit triple pins
90 # XXX ARRRGH, doesn't work
91 #pad = Subsignal("io",
92 # Pins("%s_i %s_o %s_oe" % (pname, pname, pname),
93 # dir="io", assert_width=3))
94 #ios.append(Resource(pname, 0, pad))
95 pads = []
96 pads.append(Subsignal("i",
97 Pins(pname+"_i", dir="i", assert_width=1)))
98 pads.append(Subsignal("o",
99 Pins(pname+"_o", dir="o", assert_width=1)))
100 pads.append(Subsignal("oe",
101 Pins(pname+"_oe", dir="o", assert_width=1)))
102 ios.append(Resource.family(pname, 0, default_name=pname,
103 ios=pads))
104 resources.append(Resource.family(periph, 0, default_name="gpio",
105 ios=ios))
106
107 # add clock and reset
108 clk = Resource("clk", 0, Pins("sys_clk", dir="i"))
109 rst = Resource("rst", 0, Pins("sys_rst", dir="i"))
110 resources.append(clk)
111 resources.append(rst)
112 return resources
113
114
115 def JTAGResource(*args):
116 io = []
117 io.append(Subsignal("tms", Pins("tms", dir="i", assert_width=1)))
118 io.append(Subsignal("tdi", Pins("tdi", dir="i", assert_width=1)))
119 io.append(Subsignal("tck", Pins("tck", dir="i", assert_width=1)))
120 io.append(Subsignal("tdo", Pins("tdo", dir="o", assert_width=1)))
121 return Resource.family(*args, default_name="jtag", ios=io)
122
123 def UARTResource(*args, rx, tx):
124 io = []
125 io.append(Subsignal("rx", Pins(rx, dir="i", assert_width=1)))
126 io.append(Subsignal("tx", Pins(tx, dir="o", assert_width=1)))
127 return Resource.family(*args, default_name="uart", ios=io)
128
129
130 def I2CResource(*args, scl, sda):
131 ios = []
132 pads = []
133 pads.append(Subsignal("i", Pins(sda+"_i", dir="i", assert_width=1)))
134 pads.append(Subsignal("o", Pins(sda+"_o", dir="o", assert_width=1)))
135 pads.append(Subsignal("oe", Pins(sda+"_oe", dir="o", assert_width=1)))
136 ios.append(Resource.family(sda, 0, default_name=sda, ios=pads))
137 pads = []
138 pads.append(Subsignal("i", Pins(scl+"_i", dir="i", assert_width=1)))
139 pads.append(Subsignal("o", Pins(scl+"_o", dir="o", assert_width=1)))
140 pads.append(Subsignal("oe", Pins(scl+"_oe", dir="o", assert_width=1)))
141 ios.append(Resource.family(scl, 0, default_name=scl, ios=pads))
142 return Resource.family(*args, default_name="i2c", ios=ios)
143
144
145 # top-level demo module.
146 class Blinker(Elaboratable):
147 def __init__(self, pinset, resources):
148 self.jtag = JTAG({}, "sync", resources=resources)
149 #memory = Memory(width=32, depth=16)
150 #self.sram = SRAM(memory=memory, bus=self.jtag.wb)
151
152 def elaborate(self, platform):
153 jtag_resources = self.jtag.pad_mgr.resources
154 m = Module()
155 m.submodules.jtag = self.jtag
156 #m.submodules.sram = self.sram
157
158 count = Signal(5)
159 m.d.sync += count.eq(count+1)
160 print ("resources", platform, jtag_resources.items())
161 gpio = self.jtag.request('gpio')
162 print (gpio, gpio.layout, gpio.fields)
163 # get the GPIO bank, mess about with some of the pins
164 m.d.comb += gpio.gpio0.o.eq(1)
165 m.d.comb += gpio.gpio1.o.eq(gpio.gpio2.i)
166 m.d.comb += gpio.gpio1.oe.eq(count[4])
167 m.d.sync += count[0].eq(gpio.gpio1.i)
168 # get the UART resource, mess with the output tx
169 uart = self.jtag.request('uart')
170 print (uart, uart.fields)
171 intermediary = Signal()
172 m.d.comb += uart.tx.eq(intermediary)
173 m.d.comb += intermediary.eq(uart.rx)
174
175 # to even be able to get at objects, you first have to make them
176 # available - i.e. not as local variables
177 self.gpio = gpio
178
179 return self.jtag.boundary_elaborate(m, platform)
180
181 def ports(self):
182 return list(self)
183
184 def __iter__(self):
185 yield from self.jtag.iter_ports()
186
187 '''
188 _trellis_command_templates = [
189 r"""
190 {{invoke_tool("yosys")}}
191 {{quiet("-q")}}
192 {{get_override("yosys_opts")|options}}
193 -l {{name}}.rpt
194 {{name}}.ys
195 """,
196 ]
197 '''
198
199 # sigh, have to create a dummy platform for now.
200 # TODO: investigate how the heck to get it to output ilang. or verilog.
201 # or, anything, really. but at least it doesn't barf
202 class ASICPlatform(TemplatedPlatform):
203 connectors = []
204 resources = OrderedDict()
205 required_tools = []
206 command_templates = ['/bin/true'] # no command needed: stops barfing
207 file_templates = {
208 **TemplatedPlatform.build_script_templates,
209 "{{name}}.il": r"""
210 # {{autogenerated}}
211 {{emit_rtlil()}}
212 """,
213 "{{name}}.debug.v": r"""
214 /* {{autogenerated}} */
215 {{emit_debug_verilog()}}
216 """,
217 }
218 toolchain = None
219 default_clk = "clk" # should be picked up / overridden by platform sys.clk
220 default_rst = "rst" # should be picked up / overridden by platform sys.rst
221
222 def __init__(self, resources, jtag):
223 self.jtag = jtag
224 super().__init__()
225
226 # create set of pin resources based on the pinset, this is for the core
227 #jtag_resources = self.jtag.pad_mgr.resources
228 self.add_resources(resources)
229
230 # add JTAG without scan
231 self.add_resources([JTAGResource('jtag', 0)], no_boundary_scan=True)
232
233 def add_resources(self, resources, no_boundary_scan=False):
234 print ("ASICPlatform add_resources", resources)
235 return super().add_resources(resources)
236
237 #def iter_ports(self):
238 # yield from super().iter_ports()
239 # for io in self.jtag.ios.values():
240 # print ("iter ports", io.layout, io)
241 # for field in io.core.fields:
242 # yield getattr(io.core, field)
243 # for field in io.pad.fields:
244 # yield getattr(io.pad, field)
245
246 # XXX these aren't strictly necessary right now but the next
247 # phase is to add JTAG Boundary Scan so it maaay be worth adding?
248 # at least for the print statements
249 def get_input(self, pin, port, attrs, invert):
250 self._check_feature("single-ended input", pin, attrs,
251 valid_xdrs=(0,), valid_attrs=None)
252
253 m = Module()
254 print (" get_input", pin, "port", port, port.layout)
255 m.d.comb += pin.i.eq(self._invert_if(invert, port))
256 return m
257
258 def get_output(self, pin, port, attrs, invert):
259 self._check_feature("single-ended output", pin, attrs,
260 valid_xdrs=(0,), valid_attrs=None)
261
262 m = Module()
263 print (" get_output", pin, "port", port, port.layout)
264 m.d.comb += port.eq(self._invert_if(invert, pin.o))
265 return m
266
267 def get_tristate(self, pin, port, attrs, invert):
268 self._check_feature("single-ended tristate", pin, attrs,
269 valid_xdrs=(0,), valid_attrs=None)
270
271 print (" get_tristate", pin, "port", port, port.layout)
272 m = Module()
273 print (" pad", pin, port, attrs)
274 print (" pin", pin.layout)
275 return m
276 # m.submodules += Instance("$tribuf",
277 # p_WIDTH=pin.width,
278 # i_EN=pin.oe,
279 # i_A=self._invert_if(invert, pin.o),
280 # o_Y=port,
281 # )
282 m.d.comb += io.core.o.eq(pin.o)
283 m.d.comb += io.core.oe.eq(pin.oe)
284 m.d.comb += pin.i.eq(io.core.i)
285 m.d.comb += io.pad.i.eq(port.i)
286 m.d.comb += port.o.eq(io.pad.o)
287 m.d.comb += port.oe.eq(io.pad.oe)
288 return m
289
290 def get_input_output(self, pin, port, attrs, invert):
291 self._check_feature("single-ended input/output", pin, attrs,
292 valid_xdrs=(0,), valid_attrs=None)
293
294 print (" get_input_output", pin, "port", port, port.layout)
295 m = Module()
296 print (" port layout", port.layout)
297 print (" pin", pin)
298 print (" layout", pin.layout)
299 #m.submodules += Instance("$tribuf",
300 # p_WIDTH=pin.width,
301 # i_EN=io.pad.oe,
302 # i_A=self._invert_if(invert, io.pad.o),
303 # o_Y=port,
304 #)
305 # Create aliases for the port sub-signals
306 port_i = port.io[0]
307 port_o = port.io[1]
308 port_oe = port.io[2]
309
310 m.d.comb += pin.i.eq(self._invert_if(invert, port_i))
311 m.d.comb += port_o.eq(self._invert_if(invert, pin.o))
312 m.d.comb += port_oe.eq(pin.oe)
313
314 return m
315
316 def toolchain_prepare(self, fragment, name, **kwargs):
317 """override toolchain_prepare in order to grab the fragment
318 """
319 self.fragment = fragment
320 return super().toolchain_prepare(fragment, name, **kwargs)
321
322 """
323 and to create a Platform instance with that list, and build
324 something random
325
326 p=Platform()
327 p.resources=listofstuff
328 p.build(Blinker())
329 """
330 pinset = dummy_pinset()
331 print(pinset)
332 resources = create_resources(pinset)
333 top = Blinker(pinset, resources)
334
335 vl = rtlil.convert(top, ports=top.ports())
336 with open("test_jtag_blinker.il", "w") as f:
337 f.write(vl)
338
339 if False:
340 # XXX these modules are all being added *AFTER* the build process links
341 # everything together. the expectation that this would work is...
342 # unrealistic. ordering, clearly, is important.
343
344 # dut = JTAG(test_pinset(), wb_data_wid=64, domain="sync")
345 top.jtag.stop = False
346 # rather than the client access the JTAG bus directly
347 # create an alternative that the client sets
348 class Dummy: pass
349 cdut = Dummy()
350 cdut.cbus = JTAGInterface()
351
352 # set up client-server on port 44843-something
353 top.jtag.s = JTAGServer()
354 cdut.c = JTAGClient()
355 top.jtag.s.get_connection()
356 #else:
357 # print ("running server only as requested, use openocd remote to test")
358 # sys.stdout.flush()
359 # top.jtag.s.get_connection(None) # block waiting for connection
360
361 # take copy of ir_width and scan_len
362 cdut._ir_width = top.jtag._ir_width
363 cdut.scan_len = top.jtag.scan_len
364
365 p = ASICPlatform (resources, top.jtag)
366 p.build(top)
367 # this is what needs to gets treated as "top", after "main module" top
368 # is augmented with IO pads with JTAG tacked on. the expectation that
369 # the get_input() etc functions will be called magically by some other
370 # function is unrealistic.
371 top_fragment = p.fragment
372
373 # XXX simulating top (the module that does not itself contain IO pads
374 # because that's covered by build) cannot possibly be expected to work
375 # particularly when modules have been added *after* the platform build()
376 # function has been called.
377
378 def test_case0():
379 print("Starting sanity test case!")
380 print("printing out list of stuff in top")
381 print(dir(top))
382 # ok top now has a variable named "gpio", let's enumerate that too
383 print("printing out list of stuff in top.gpio and its type")
384 print(top.gpio.__class__.__name__, dir(top.gpio))
385 # ok, it's a nmigen Record, therefore it has a layout. let's print
386 # that too
387 print("top.gpio is a Record therefore has fields and a layout")
388 print(" layout:", top.gpio.layout)
389 print(" fields:", top.gpio.fields)
390 # etc etc. you get the general idea
391 yield top.gpio_0__gpio0__o__o.eq(0)
392 yield top.gpio_0__gpio0__o__core__o.eq(0)
393 yield top.gpio_0__gpio1__o.eq(0)
394 yield
395
396 # Code borrowed from cesar, runs, but shouldn't actually work because of
397 # self. statements and non-existent signal names.
398 def test_case1():
399 print("Example test case")
400 yield Passive()
401 while True:
402 # Settle() is needed to give a quick response to
403 # the zero delay case
404 yield Settle()
405 # wait for rel_o to become active
406 while not (yield self.rel_o):
407 yield
408 yield Settle()
409 # read the transaction parameters
410 assert self.expecting, "an unexpected result was produced"
411 delay = (yield self.delay)
412 expected = (yield self.expected)
413 # wait for `delay` cycles
414 for _ in range(delay):
415 yield
416 # activate go_i for one cycle
417 yield self.go_i.eq(1)
418 yield self.count.eq(self.count + 1)
419 yield
420 # check received data against the expected value
421 result = (yield self.port)
422 assert result == expected,\
423 f"expected {expected}, received {result}"
424 yield self.go_i.eq(0)
425 yield self.port.eq(0)
426
427 sim = Simulator(top)
428 sim.add_clock(1e-6, domain="sync") # standard clock
429
430 #sim.add_sync_process(wrap(jtag_srv(top))) #? jtag server
431 #if len(sys.argv) != 2 or sys.argv[1] != 'server':
432 #sim.add_sync_process(wrap(jtag_sim(cdut, top.jtag))) # actual jtag tester
433 #sim.add_sync_process(wrap(dmi_sim(top.jtag))) # handles (pretends to be) DMI
434
435 sim.add_sync_process(wrap(test_case1()))
436 sim.add_sync_process(wrap(test_case0()))
437
438 with sim.write_vcd("blinker_test.vcd"):
439 sim.run()