reworking IO, morphing to make JTAG independent of Platform.build()
[pinmux.git] / src / spec / testing_stage1.py
1 #!/usr/bin/env python3
2 from nmigen.build.dsl import Resource, Subsignal, Pins
3 from nmigen.build.plat import TemplatedPlatform
4 from nmigen.build.res import ResourceManager, ResourceError
5 from nmigen import Elaboratable, Signal, Module, Instance
6 from collections import OrderedDict
7 from jtag import JTAG, resiotypes
8 from copy import deepcopy
9
10 # extra dependencies for jtag testing (?)
11 from soc.bus.sram import SRAM
12
13 from nmigen import Memory
14 from nmigen.sim import Simulator, Delay, Settle, Tick
15
16 from nmutil.util import wrap
17
18 from soc.debug.jtagutils import (jtag_read_write_reg,
19 jtag_srv, jtag_set_reset,
20 jtag_set_ir, jtag_set_get_dr)
21
22 from c4m.nmigen.jtag.tap import TAP, IOType
23 from c4m.nmigen.jtag.bus import Interface as JTAGInterface
24 from soc.debug.dmi import DMIInterface, DBGCore
25 from soc.debug.test.dmi_sim import dmi_sim
26 from soc.debug.test.jtagremote import JTAGServer, JTAGClient
27 from nmigen.build.res import ResourceError
28
29 # Was thinking of using these functions, but skipped for simplicity for now
30 # XXX nope. the output from JSON file.
31 #from pinfunctions import (i2s, lpc, emmc, sdmmc, mspi, mquadspi, spi,
32 # quadspi, i2c, mi2c, jtag, uart, uartfull, rgbttl, ulpi, rgmii, flexbus1,
33 # flexbus2, sdram1, sdram2, sdram3, vss, vdd, sys, eint, pwm, gpio)
34
35 # File for stage 1 pinmux tested proposed by Luke,
36 # https://bugs.libre-soc.org/show_bug.cgi?id=50#c10
37
38
39 def dummy_pinset():
40 # sigh this needs to come from pinmux.
41 gpios = []
42 for i in range(4):
43 gpios.append("%d*" % i)
44 return {'uart': ['tx+', 'rx-'],
45 'gpio': gpios,
46 #'jtag': ['tms-', 'tdi-', 'tdo+', 'tck+'],
47 'i2c': ['sda*', 'scl+']}
48
49 """
50 a function is needed which turns the results of dummy_pinset()
51 into:
52
53 [UARTResource("uart", 0, tx=..., rx=..),
54 I2CResource("i2c", 0, scl=..., sda=...),
55 Resource("gpio", 0, Subsignal("i"...), Subsignal("o"...)
56 Resource("gpio", 1, Subsignal("i"...), Subsignal("o"...)
57 ...
58 ]
59 """
60
61
62 def create_resources(pinset):
63 resources = []
64 for periph, pins in pinset.items():
65 print(periph, pins)
66 if periph == 'i2c':
67 #print("I2C required!")
68 resources.append(I2CResource('i2c', 0, sda='sda', scl='scl'))
69 elif periph == 'uart':
70 #print("UART required!")
71 resources.append(UARTResource('uart', 0, tx='tx', rx='rx'))
72 elif periph == 'gpio':
73 #print("GPIO required!")
74 print ("GPIO is defined as '*' type, meaning i, o and oe needed")
75 ios = []
76 for pin in pins:
77 pname = "gpio"+pin[:-1] # strip "*" on end
78 # urrrr... tristsate and io assume a single pin which is
79 # of course exactly what we don't want in an ASIC: we want
80 # *all three* pins but the damn port is not outputted
81 # as a triplet, it's a single Record named "io". sigh.
82 # therefore the only way to get a triplet of i/o/oe
83 # is to *actually* create explicit triple pins
84 pad = Subsignal("io",
85 Pins("%s_i %s_o %s_oe" % (pname, pname, pname),
86 dir="io", assert_width=3))
87 ios.append(Resource(pname, 0, pad))
88 resources.append(Resource.family(periph, 0, default_name="gpio",
89 ios=ios))
90
91 # add clock and reset
92 clk = Resource("clk", 0, Pins("sys_clk", dir="i"))
93 rst = Resource("rst", 0, Pins("sys_rst", dir="i"))
94 resources.append(clk)
95 resources.append(rst)
96 return resources
97
98
99 def JTAGResource(*args):
100 io = []
101 io.append(Subsignal("tms", Pins("tms", dir="i", assert_width=1)))
102 io.append(Subsignal("tdi", Pins("tdi", dir="i", assert_width=1)))
103 io.append(Subsignal("tck", Pins("tck", dir="i", assert_width=1)))
104 io.append(Subsignal("tdo", Pins("tdo", dir="o", assert_width=1)))
105 return Resource.family(*args, default_name="jtag", ios=io)
106
107 def UARTResource(*args, rx, tx):
108 io = []
109 io.append(Subsignal("rx", Pins(rx, dir="i", assert_width=1)))
110 io.append(Subsignal("tx", Pins(tx, dir="o", assert_width=1)))
111 return Resource.family(*args, default_name="uart", ios=io)
112
113
114 def I2CResource(*args, scl, sda):
115 io = []
116 io.append(Subsignal("scl", Pins(scl, dir="io", assert_width=1)))
117 io.append(Subsignal("sda", Pins(sda, dir="io", assert_width=1)))
118 return Resource.family(*args, default_name="i2c", ios=io)
119
120
121 # ridiculously-simple top-level module. doesn't even have a sync domain
122 # and can't have one until a clock has been established by ASICPlatform.
123 class Blinker(Elaboratable):
124 def __init__(self, pinset, resources):
125 self.jtag = JTAG({}, "sync")
126 self.jtag.core_mgr = ResourceManager([], [])
127 self.jtag.core_mgr.add_resources(resources)
128 # record resource lookup between core IO names and pads
129 self.jtag.padlookup = {}
130 self.jtag.requests_made = []
131 memory = Memory(width=32, depth=16)
132 self.sram = SRAM(memory=memory, bus=self.jtag.wb)
133
134 def elaborate(self, platform):
135 jtag_resources = self.jtag.core_mgr.resources
136 m = Module()
137 m.submodules.jtag = self.jtag
138 m.submodules.sram = self.sram
139
140 count = Signal(5)
141 m.d.sync += count.eq(count+1)
142 print ("resources", jtag_resources.items())
143 gpio = self.jtag_request('gpio')
144 print (gpio, gpio.layout, gpio.fields)
145 # get the GPIO bank, mess about with some of the pins
146 m.d.comb += gpio.gpio0.io.o.eq(1)
147 m.d.comb += gpio.gpio1.io.o.eq(gpio.gpio2.io.i)
148 m.d.comb += gpio.gpio1.io.oe.eq(count[4])
149 m.d.sync += count[0].eq(gpio.gpio1.io.i)
150 # get the UART resource, mess with the output tx
151 uart = self.jtag_request('uart')
152 print (uart, uart.fields)
153 intermediary = Signal()
154 m.d.comb += uart.tx.eq(intermediary)
155 m.d.comb += intermediary.eq(uart.rx)
156
157 # platform requested: make the exact same requests,
158 # then add JTAG afterwards
159 if platform is not None:
160 for (name, number, dir, xdr) in self.jtag.requests_made:
161 platform.request(name, number, dir=dir, xdr=xdr)
162
163 # wire up JTAG otherwise we are in trouble (no clock)
164 jtag = platform.request('jtag')
165 m.d.comb += self.jtag.bus.tdi.eq(jtag.tdi)
166 m.d.comb += self.jtag.bus.tck.eq(jtag.tck)
167 m.d.comb += self.jtag.bus.tms.eq(jtag.tms)
168 m.d.comb += jtag.tdo.eq(self.jtag.bus.tdo)
169
170 return m
171
172 def jtag_request(self, name, number=0, *, dir=None, xdr=None):
173 """request a Resource (e.g. name="uart", number=0) which will
174 return a data structure containing Records of all the pins.
175
176 this override will also - automatically - create a JTAG Boundary Scan
177 connection *without* any change to the actual Platform.request() API
178 """
179 core_mgr = self.jtag.core_mgr
180 padlookup = self.jtag.padlookup
181 # okaaaay, bit of shenanigens going on: the important data structure
182 # here is Resourcemanager._ports. requests add to _ports, which is
183 # what needs redirecting. therefore what has to happen is to
184 # capture the number of ports *before* the request. sigh.
185 # start_ports = len(core_mgr._ports)
186 # value = core_mgr.request(name, number, dir=dir, xdr=xdr)
187 # end_ports = len(core_mgr._ports)
188
189 # take a copy of the requests made
190 self.jtag.requests_made.append((name, number, dir, xdr))
191
192 # now make a corresponding (duplicate) request to the pad manager
193 # BUT, if it doesn't exist, don't sweat it: all it means is, the
194 # application did not request Boundary Scan for that resource.
195 pad_start_ports = len(core_mgr._ports)
196 pvalue = core_mgr.request(name, number, dir=dir, xdr=xdr)
197 pad_end_ports = len(core_mgr._ports)
198
199 # ok now we have the lengths: now create a lookup between the pad
200 # and the core, so that JTAG boundary scan can be inserted in between
201 #core = self._ports[start_ports:end_ports]
202 pads = core_mgr._ports[pad_start_ports:pad_end_ports]
203 # oops if not the same numbers added. it's a duplicate. shouldn't happen
204 #assert len(core) == len(pads), "argh, resource manager error"
205 #print ("core", core)
206 print ("pads", pads)
207
208 # pad/core each return a list of tuples of (res, pin, port, attrs)
209 #for pad, core in zip(pads, core):
210 for pad in pads:
211 # create a lookup on pin name to get at the hidden pad instance
212 # this pin name will be handed to get_input, get_output etc.
213 # and without the padlookup you can't find the (duplicate) pad.
214 # note that self.padlookup and self.jtag.ios use the *exact* same
215 # pin.name per pin
216 pin = pad[1]
217 #corepin = core[1]
218 if pin is None: continue # skip when pin is None
219 #assert corepin is not None # if pad was None, core should be too
220 print ("iter", pad, pin.name)
221 print ("existing pads", padlookup.keys())
222 assert pin.name not in padlookup # no overwrites allowed!
223 #assert pin.name == corepin.name # has to be the same!
224 padlookup[pin.name] = pad # store pad by pin name
225
226 # now add the IO Shift Register. first identify the type
227 # then request a JTAG IOConn. we can't wire it up (yet) because
228 # we don't have a Module() instance. doh. that comes in get_input
229 # and get_output etc. etc.
230 iotype = resiotypes[pin.dir] # look up the C4M-JTAG IOType
231 io = self.jtag.add_io(iotype=iotype, name=pin.name) # create IOConn
232 self.jtag.ios[pin.name] = io # store IOConn Record by pin name
233
234 # finally return the value just like ResourceManager.request()
235 return pvalue
236
237
238 '''
239 _trellis_command_templates = [
240 r"""
241 {{invoke_tool("yosys")}}
242 {{quiet("-q")}}
243 {{get_override("yosys_opts")|options}}
244 -l {{name}}.rpt
245 {{name}}.ys
246 """,
247 ]
248 '''
249
250 # sigh, have to create a dummy platform for now.
251 # TODO: investigate how the heck to get it to output ilang. or verilog.
252 # or, anything, really. but at least it doesn't barf
253 class ASICPlatform(TemplatedPlatform):
254 connectors = []
255 resources = OrderedDict()
256 required_tools = []
257 command_templates = ['/bin/true'] # no command needed: stops barfing
258 file_templates = {
259 **TemplatedPlatform.build_script_templates,
260 "{{name}}.il": r"""
261 # {{autogenerated}}
262 {{emit_rtlil()}}
263 """,
264 "{{name}}.debug.v": r"""
265 /* {{autogenerated}} */
266 {{emit_debug_verilog()}}
267 """,
268 }
269 toolchain = None
270 default_clk = "clk" # should be picked up / overridden by platform sys.clk
271 default_rst = "rst" # should be picked up / overridden by platform sys.rst
272
273 def __init__(self, resources, jtag):
274 self.jtag = jtag
275 super().__init__()
276
277 # create set of pin resources based on the pinset, this is for the core
278 #jtag_resources = self.jtag.core_mgr.resources
279 self.add_resources(resources)
280
281 # add JTAG without scan
282 self.add_resources([JTAGResource('jtag', 0)], no_boundary_scan=True)
283
284 def _request(self, name, number=0, *, dir=None, xdr=None):
285 """request a Resource (e.g. name="uart", number=0) which will
286 return a data structure containing Records of all the pins.
287
288 this override will also - automatically - create a JTAG Boundary Scan
289 connection *without* any change to the actual Platform.request() API
290 """
291 core_mgr = self.jtag.core_mgr
292 padlookup = self.jtag.padlookup
293 # okaaaay, bit of shenanigens going on: the important data structure
294 # here is Resourcemanager._ports. requests add to _ports, which is
295 # what needs redirecting. therefore what has to happen is to
296 # capture the number of ports *before* the request. sigh.
297 start_ports = len(self._ports)
298 value = super().request(name, number, dir=dir, xdr=xdr)
299 end_ports = len(self._ports)
300
301 # now make a corresponding (duplicate) request to the pad manager
302 # BUT, if it doesn't exist, don't sweat it: all it means is, the
303 # application did not request Boundary Scan for that resource.
304 pad_start_ports = len(core_mgr._ports)
305 try:
306 pvalue = core_mgr.request(name, number, dir=dir, xdr=xdr)
307 except ResourceError:
308 return value
309 pad_end_ports = len(core_mgr._ports)
310
311 # ok now we have the lengths: now create a lookup between the pad
312 # and the core, so that JTAG boundary scan can be inserted in between
313 core = self._ports[start_ports:end_ports]
314 pads = core_mgr._ports[pad_start_ports:pad_end_ports]
315 # oops if not the same numbers added. it's a duplicate. shouldn't happen
316 assert len(core) == len(pads), "argh, resource manager error"
317 print ("core", core)
318 print ("pads", pads)
319
320 # pad/core each return a list of tuples of (res, pin, port, attrs)
321 for pad, core in zip(pads, core):
322 # create a lookup on pin name to get at the hidden pad instance
323 # this pin name will be handed to get_input, get_output etc.
324 # and without the padlookup you can't find the (duplicate) pad.
325 # note that self.padlookup and self.jtag.ios use the *exact* same
326 # pin.name per pin
327 pin = pad[1]
328 corepin = core[1]
329 if pin is None: continue # skip when pin is None
330 assert corepin is not None # if pad was None, core should be too
331 print ("iter", pad, pin.name)
332 print ("existing pads", padlookup.keys())
333 assert pin.name not in padlookup # no overwrites allowed!
334 assert pin.name == corepin.name # has to be the same!
335 padlookup[pin.name] = pad # store pad by pin name
336
337 # now add the IO Shift Register. first identify the type
338 # then request a JTAG IOConn. we can't wire it up (yet) because
339 # we don't have a Module() instance. doh. that comes in get_input
340 # and get_output etc. etc.
341 iotype = resiotypes[pin.dir] # look up the C4M-JTAG IOType
342 io = self.jtag.add_io(iotype=iotype, name=pin.name) # create IOConn
343 self.jtag.ios[pin.name] = io # store IOConn Record by pin name
344
345 # finally return the value just like ResourceManager.request()
346 return value
347
348 def add_resources(self, resources, no_boundary_scan=False):
349 print ("ASICPlatform add_resources", resources)
350 super().add_resources(resources)
351 return
352 if no_boundary_scan:
353 return
354 # make a *second* - identical - set of pin resources for the IO ring
355 padres = deepcopy(resources)
356 self.jtag.core_mgr.add_resources(padres)
357
358 #def iter_ports(self):
359 # yield from super().iter_ports()
360 # for io in self.jtag.ios.values():
361 # print ("iter ports", io.layout, io)
362 # for field in io.core.fields:
363 # yield getattr(io.core, field)
364 # for field in io.pad.fields:
365 # yield getattr(io.pad, field)
366
367 # XXX these aren't strictly necessary right now but the next
368 # phase is to add JTAG Boundary Scan so it maaay be worth adding?
369 # at least for the print statements
370 def get_input(self, pin, port, attrs, invert):
371 padlookup = self.jtag.padlookup
372 self._check_feature("single-ended input", pin, attrs,
373 valid_xdrs=(0,), valid_attrs=None)
374
375 m = Module()
376 print (" get_input", pin, "port", port, port.layout)
377 if pin.name in ['clk_0', 'rst_0']: # sigh
378 # simple pass-through from port to pin
379 print("No JTAG chain in-between")
380 m.d.comb += pin.i.eq(self._invert_if(invert, port))
381 return m
382 if pin.name not in padlookup:
383 print("No pin named %s, not connecting to JTAG BS" % pin.name)
384 m.d.comb += pin.i.eq(self._invert_if(invert, port))
385 return m
386 (padres, padpin, padport, padattrs) = padlookup[pin.name]
387 io = self.jtag.ios[pin.name]
388 print (" pad", padres, padpin, padport, attrs)
389 print (" padpin", padpin.layout)
390 print (" jtag", io.core.layout, io.pad.layout)
391 m.d.comb += pin.i.eq(io.core.i)
392 m.d.comb += padpin.i.eq(pin.i)
393 m.d.comb += padport.io.eq(self._invert_if(invert, port))
394 m.d.comb += io.pad.i.eq(padport.io)
395
396 print("+=+=+= pin: ", pin)
397 print("+=+=+= port: ", port.layout)
398 print("+=+=+= pad pin: ", padpin)
399 print("+=+=+= pad port: ", padport)
400 return m
401
402 def get_output(self, pin, port, attrs, invert):
403 padlookup = self.jtag.padlookup
404 self._check_feature("single-ended output", pin, attrs,
405 valid_xdrs=(0,), valid_attrs=None)
406
407 m = Module()
408 print (" get_output", pin, "port", port, port.layout)
409 if pin.name in ['clk_0', 'rst_0']: # sigh
410 # simple pass-through from pin to port
411 print("No JTAG chain in-between")
412 m.d.comb += port.eq(self._invert_if(invert, pin.o))
413 return m
414 if pin.name not in padlookup:
415 print("No pin named %s, not connecting to JTAG BS" % pin.name)
416 m.d.comb += port.eq(self._invert_if(invert, pin.o))
417 return m
418 (padres, padpin, padport, padattrs) = padlookup[pin.name]
419 io = self.jtag.ios[pin.name]
420 print (" pad", padres, padpin, padport, padattrs)
421 print (" pin", padpin.layout)
422 print (" jtag", io.core.layout, io.pad.layout)
423 m.d.comb += io.core.o.eq(self._invert_if(invert, pin.o))
424 m.d.comb += pin.o.eq(padpin.o)
425 m.d.comb += port.eq(padport.io)
426 m.d.comb += padport.io.eq(io.pad.o)
427 return m
428
429 def get_tristate(self, pin, port, attrs, invert):
430 padlookup = self.jtag.padlookup
431 self._check_feature("single-ended tristate", pin, attrs,
432 valid_xdrs=(0,), valid_attrs=None)
433
434 print (" get_tristate", pin, "port", port, port.layout)
435 m = Module()
436 if pin.name in ['clk_0', 'rst_0']: # sigh
437 print("No JTAG chain in-between")
438 m.submodules += Instance("$tribuf",
439 p_WIDTH=pin.width,
440 i_EN=pin.oe,
441 i_A=self._invert_if(invert, pin.o),
442 o_Y=port,
443 )
444 return m
445 return m
446 (res, pin, port, attrs) = padlookup[pin.name]
447 io = self.jtag.ios[pin.name]
448 print (" pad", res, pin, port, attrs)
449 print (" pin", pin.layout)
450 print (" jtag", io.core.layout, io.pad.layout)
451 #m.submodules += Instance("$tribuf",
452 # p_WIDTH=pin.width,
453 # i_EN=io.pad.oe,
454 # i_A=self._invert_if(invert, io.pad.o),
455 # o_Y=port,
456 #)
457 m.d.comb += io.core.o.eq(pin.o)
458 m.d.comb += io.core.oe.eq(pin.oe)
459 m.d.comb += pin.i.eq(io.core.i)
460 m.d.comb += io.pad.i.eq(port.i)
461 m.d.comb += port.o.eq(io.pad.o)
462 m.d.comb += port.oe.eq(io.pad.oe)
463 return m
464
465 def get_input_output(self, pin, port, attrs, invert):
466 padlookup = self.jtag.padlookup
467 self._check_feature("single-ended input/output", pin, attrs,
468 valid_xdrs=(0,), valid_attrs=None)
469
470 print (" get_input_output", pin, "port", port, port.layout)
471 m = Module()
472 if pin.name in ['clk_0', 'rst_0']: # sigh
473 print("No JTAG chain in-between")
474 m.submodules += Instance("$tribuf",
475 p_WIDTH=pin.width,
476 i_EN=pin.oe,
477 i_A=self._invert_if(invert, pin.o),
478 o_Y=port,
479 )
480 m.d.comb += pin.i.eq(self._invert_if(invert, port))
481 return m
482 (padres, padpin, padport, padattrs) = padlookup[pin.name]
483 io = self.jtag.ios[pin.name]
484 print (" padres", padres)
485 print (" padpin", padpin)
486 print (" layout", padpin.layout)
487 print (" padport", padport)
488 print (" layout", padport.layout)
489 print (" padattrs", padattrs)
490 print (" port layout", port.layout)
491 print (" pin", pin)
492 print (" layout", pin.layout)
493 print (" jtag io.core", io.core.layout)
494 print (" jtag io.pad", io.pad.layout)
495 #m.submodules += Instance("$tribuf",
496 # p_WIDTH=pin.width,
497 # i_EN=io.pad.oe,
498 # i_A=self._invert_if(invert, io.pad.o),
499 # o_Y=port,
500 #)
501 # Create aliases for the port sub-signals
502 port_i = port.io[0]
503 port_o = port.io[1]
504 port_oe = port.io[2]
505
506 padport_i = padport.io[0]
507 padport_o = padport.io[1]
508 padport_oe = padport.io[2]
509
510 # connect i
511 m.d.comb += pin.i[0].eq(io.core.i)
512 m.d.comb += padpin.i[0].eq(pin.i[0])
513 m.d.comb += padport_i.eq(self._invert_if(invert, port_i))
514 m.d.comb += io.pad.i.eq(padport_i)
515
516 # connect o
517 m.d.comb += io.core.o.eq(self._invert_if(invert, pin.o))
518 m.d.comb += pin.o.eq(padpin.o)
519 m.d.comb += port_o.eq(padport_o)
520 m.d.comb += padport_o.eq(io.pad.o)
521
522 # connect oe
523 m.d.comb += io.core.oe.eq(self._invert_if(invert, pin.oe))
524 m.d.comb += pin.oe.eq(padpin.oe)
525 m.d.comb += port_oe.eq(padport_oe)
526 m.d.comb += padport_oe.eq(io.pad.oe)
527
528 return m
529
530 def toolchain_prepare(self, fragment, name, **kwargs):
531 """override toolchain_prepare in order to grab the fragment
532 """
533 self.fragment = fragment
534 return super().toolchain_prepare(fragment, name, **kwargs)
535
536 """
537 and to create a Platform instance with that list, and build
538 something random
539
540 p=Platform()
541 p.resources=listofstuff
542 p.build(Blinker())
543 """
544 pinset = dummy_pinset()
545 print(pinset)
546 resources = create_resources(pinset)
547 top = Blinker(pinset, resources)
548
549
550 # XXX these modules are all being added *AFTER* the build process links
551 # everything together. the expectation that this would work is... unrealistic.
552 # ordering, clearly, is important.
553
554 # dut = JTAG(test_pinset(), wb_data_wid=64, domain="sync")
555 top.jtag.stop = False
556 # rather than the client access the JTAG bus directly
557 # create an alternative that the client sets
558 class Dummy: pass
559 cdut = Dummy()
560 cdut.cbus = JTAGInterface()
561
562 # set up client-server on port 44843-something
563 top.jtag.s = JTAGServer()
564 cdut.c = JTAGClient()
565 top.jtag.s.get_connection()
566 #else:
567 # print ("running server only as requested, use openocd remote to test")
568 # sys.stdout.flush()
569 # top.jtag.s.get_connection(None) # block waiting for connection
570
571 # take copy of ir_width and scan_len
572 cdut._ir_width = top.jtag._ir_width
573 cdut.scan_len = top.jtag.scan_len
574
575 p = ASICPlatform (resources, top.jtag)
576 p.build(top)
577 # this is what needs to gets treated as "top", after "main module" top
578 # is augmented with IO pads with JTAG tacked on. the expectation that
579 # the get_input() etc functions will be called magically by some other
580 # function is unrealistic.
581 top_fragment = p.fragment
582
583 # XXX simulating top (the module that does not itself contain IO pads
584 # because that's covered by build) cannot possibly be expected to work
585 # particularly when modules have been added *after* the platform build()
586 # function has been called.
587
588 sim = Simulator(top_fragment)
589 sim.add_clock(1e-6, domain="sync") # standard clock
590
591 sim.add_sync_process(wrap(jtag_srv(top))) #? jtag server
592 #if len(sys.argv) != 2 or sys.argv[1] != 'server':
593 sim.add_sync_process(wrap(jtag_sim(cdut, top.jtag))) # actual jtag tester
594 sim.add_sync_process(wrap(dmi_sim(top.jtag))) # handles (pretends to be) DMI
595
596 with sim.write_vcd("dmi2jtag_test_srv.vcd"):
597 sim.run()