Merge branch 'upstream_libresoc' into libresoc_master
[c4m-jtag.git] / c4m / nmigen / jtag / tap.py
1 #!/usr/bin/env python3
2 import os, textwrap
3 from enum import Enum, auto
4
5 from nmigen import (Elaboratable, Signal, Module, ClockDomain, Cat, Record,
6 Const, Mux)
7 from nmigen.hdl.rec import Direction, Layout
8 from nmigen.tracer import get_var_name
9
10 from nmigen_soc.wishbone import Interface as WishboneInterface
11
12 from .bus import Interface, DMIInterface
13
14 __all__ = [
15 "TAP", "ShiftReg", "IOType", "IOConn",
16 ]
17
18
19 class _FSM(Elaboratable):
20 """TAP subblock for the FSM"""
21 def __init__(self, *, bus):
22 self.isir = Signal()
23 self.isdr = Signal()
24 self.capture = Signal()
25 self.shift = Signal()
26 self.update = Signal()
27
28 # JTAG uses both edges of the incoming clock (TCK). set them up here
29 self.posjtag = ClockDomain("posjtag", local=True)
30 self.negjtag = ClockDomain("negjtag", local=True, clk_edge="neg")
31
32 self._bus = bus
33
34 def elaborate(self, platform):
35 m = Module()
36
37 rst = Signal()
38 m.d.comb += [
39 self.posjtag.clk.eq(self._bus.tck),
40 self.posjtag.rst.eq(rst),
41 self.negjtag.clk.eq(self._bus.tck),
42 self.negjtag.rst.eq(rst),
43 ]
44
45 # Make local clock domain optionally using trst of JTAG bus as reset
46 if hasattr(self._bus, "trst"):
47 m.domains.local = local = ClockDomain(local=True)
48 m.d.comb += local.rst.eq(self._bus.trst)
49 else:
50 m.domains.local = local = ClockDomain(local=True, reset_less=True)
51 m.d.comb += local.clk.eq(self._bus.tck)
52
53 with m.FSM(domain="local") as fsm:
54 with m.State("TestLogicReset"):
55 # Be sure to reset isir, isdr
56 m.d.local += [
57 self.isir.eq(0),
58 self.isdr.eq(0),
59 ]
60 with m.If(self._bus.tms == 0):
61 m.next = "RunTestIdle"
62 with m.State("RunTestIdle"):
63 # Be sure to reset isir, isdr
64 m.d.local += [
65 self.isir.eq(0),
66 self.isdr.eq(0),
67 ]
68 with m.If(self._bus.tms == 1):
69 m.next = "SelectDRScan"
70 with m.State("SelectDRScan"):
71 with m.If(self._bus.tms == 0):
72 m.d.local += self.isdr.eq(1)
73 m.next = "CaptureState"
74 with m.Else():
75 m.next = "SelectIRScan"
76 with m.State("SelectIRScan"):
77 with m.If(self._bus.tms == 0):
78 m.d.local += self.isir.eq(1)
79 m.next = "CaptureState"
80 with m.Else():
81 m.next = "TestLogicReset"
82 with m.State("CaptureState"):
83 with m.If(self._bus.tms == 0):
84 m.next = "ShiftState"
85 with m.Else():
86 m.next = "Exit1"
87 with m.State("ShiftState"):
88 with m.If(self._bus.tms == 1):
89 m.next = "Exit1"
90 with m.State("Exit1"):
91 with m.If(self._bus.tms == 0):
92 m.next = "Pause"
93 with m.Else():
94 m.next = "UpdateState"
95 with m.State("Pause"):
96 with m.If(self._bus.tms == 1):
97 m.next = "Exit2"
98 with m.State("Exit2"):
99 with m.If(self._bus.tms == 0):
100 m.next = "ShiftState"
101 with m.Else():
102 m.next = "UpdateState"
103 with m.State("UpdateState"):
104 m.d.local += [
105 self.isir.eq(0),
106 self.isdr.eq(0),
107 ]
108 with m.If(self._bus.tms == 0):
109 m.next = "RunTestIdle"
110 with m.Else():
111 m.next = "SelectDRScan"
112
113 m.d.comb += [
114 rst.eq(fsm.ongoing("TestLogicReset")),
115 self.capture.eq(fsm.ongoing("CaptureState")),
116 self.shift.eq(fsm.ongoing("ShiftState")),
117 self.update.eq(fsm.ongoing("UpdateState")),
118 ]
119
120 return m
121
122
123 class _IRBlock(Elaboratable):
124 """TAP subblock for handling the IR shift register"""
125 def __init__(self, *, ir_width, cmd_idcode,
126 tdi, capture, shift, update,
127 name):
128 self.name = name
129 self.ir = Signal(ir_width, reset=cmd_idcode)
130 self.tdo = Signal()
131
132 self._tdi = tdi
133 self._capture = capture
134 self._shift = shift
135 self._update = update
136
137 def elaborate(self, platform):
138 m = Module()
139
140 shift_ir = Signal(len(self.ir), reset_less=True)
141
142 m.d.comb += self.tdo.eq(self.ir[0])
143 with m.If(self._capture):
144 m.d.posjtag += shift_ir.eq(self.ir)
145 with m.Elif(self._shift):
146 m.d.posjtag += shift_ir.eq(Cat(shift_ir[1:], self._tdi))
147 with m.Elif(self._update):
148 # For ir we only update it on the rising edge of clock
149 # to avoid that we already have the new ir value when still in
150 # Update state
151 m.d.posjtag += self.ir.eq(shift_ir)
152
153 return m
154
155
156 class IOType(Enum):
157 In = auto()
158 Out = auto()
159 TriOut = auto()
160 InTriOut = auto()
161
162
163 class IOConn(Record):
164 lengths = {
165 IOType.In: 1,
166 IOType.Out: 1,
167 IOType.TriOut: 2,
168 IOType.InTriOut: 3,
169 }
170
171 """TAP subblock representing the interface for an JTAG IO cell.
172 It contains signal to connect to the core and to the pad
173
174 This object is normally only allocated and returned from ``TAP.add_io``
175 It is a Record subclass.
176
177 Attributes
178 ----------
179 core: subrecord with signals for the core
180 i: Signal(1), present only for IOType.In and IOType.InTriOut.
181 Signal input to core with pad input value.
182 o: Signal(1), present only for IOType.Out, IOType.TriOut and
183 IOType.InTriOut.
184 Signal output from core with the pad output value.
185 oe: Signal(1), present only for IOType.TriOut and IOType.InTriOut.
186 Signal output from core with the pad output enable value.
187 pad: subrecord with for the pad
188 i: Signal(1), present only for IOType.In and IOType.InTriOut
189 Output from pad with pad input value for core.
190 o: Signal(1), present only for IOType.Out, IOType.TriOut and
191 IOType.InTriOut.
192 Input to pad with pad output value.
193 oe: Signal(1), present only for IOType.TriOut and IOType.InTriOut.
194 Input to pad with pad output enable value.
195 """
196 @staticmethod
197 def layout(iotype):
198 sigs = []
199 if iotype in (IOType.In, IOType.InTriOut):
200 sigs.append(("i", 1))
201 if iotype in (IOType.Out, IOType.TriOut, IOType.InTriOut):
202 sigs.append(("o", 1))
203 if iotype in (IOType.TriOut, IOType.InTriOut):
204 sigs.append(("oe", 1))
205
206 return Layout((("core", sigs), ("pad", sigs)))
207
208 def __init__(self, *, iotype, name=None, src_loc_at=0):
209 super().__init__(self.__class__.layout(iotype), name=name,
210 src_loc_at=src_loc_at+1)
211
212 self._iotype = iotype
213
214
215 class _IDBypassBlock(Elaboratable):
216 """TAP subblock for the ID shift register"""
217 def __init__(self, *, manufacturer_id, part_number, version,
218 tdi, capture, shift, update, bypass,
219 name):
220 self.name = name
221 if (not isinstance(manufacturer_id, Const) and
222 len(manufacturer_id) != 11):
223 raise ValueError("manufacturer_id has to be Const of length 11")
224 if not isinstance(part_number, Const) and len(manufacturer_id) != 16:
225 raise ValueError("part_number has to be Const of length 16")
226 if not isinstance(version, Const) and len(version) != 4:
227 raise ValueError("version has to be Const of length 4")
228 self._id = Cat(Const(1,1), manufacturer_id, part_number, version)
229
230 self.tdo = Signal(name=name+"_tdo")
231
232 self._tdi = tdi
233 self._capture = capture
234 self._shift = shift
235 self._update = update
236 self._bypass = bypass
237
238 def elaborate(self, platform):
239 m = Module()
240
241 sr = Signal(32, reset_less=True, name=self.name+"_sr")
242
243 # Local signals for the module
244 _tdi = Signal()
245 _capture = Signal()
246 _shift = Signal()
247 _update = Signal()
248 _bypass = Signal()
249
250 m.d.comb += [
251 _tdi.eq(self._tdi),
252 _capture.eq(self._capture),
253 _shift.eq(self._shift),
254 _update.eq(self._update),
255 _bypass.eq(self._bypass),
256 self.tdo.eq(sr[0]),
257 ]
258
259 with m.If(_capture):
260 m.d.posjtag += sr.eq(self._id)
261 with m.Elif(_shift):
262 with m.If(_bypass):
263 m.d.posjtag += sr[0].eq(_tdi)
264 with m.Else():
265 m.d.posjtag += sr.eq(Cat(sr[1:], _tdi))
266
267 return m
268
269
270 class ShiftReg(Record):
271 """Object with interface for extra shift registers on a TAP.
272
273 Parameters
274 ----------
275 sr_length : int
276 cmds : int, default=1
277 The number of corresponding JTAG instructions
278
279 This object is normally only allocated and returned from ``TAP.add_shiftreg``
280 It is a Record subclass.
281
282 Attributes
283 ----------
284 i: length=sr_length, FANIN
285 The input data sampled during capture state of the TAP
286 ie: length=cmds, FANOUT
287 Indicates that data is to be sampled by the JTAG TAP and
288 should be held stable. The bit indicates the corresponding
289 instruction for which data is asked.
290 This signal is kept high for a whole JTAG TAP clock cycle
291 and may thus be kept higher for more than one clock cycle
292 on the domain where ShiftReg is used.
293 The JTAG protocol does not allow insertion of wait states
294 so data need to be provided before ie goes down. The speed
295 of the response will determine the max. frequency for the
296 JTAG interface.
297 o: length=sr_length, FANOUT
298 The value of the shift register.
299 oe: length=cmds, FANOUT
300 Indicates that output is stable and can be sampled downstream because
301 JTAG TAP is in the Update state. The bit indicates the corresponding
302 instruction. The bit is only kept high for one clock cycle.
303 """
304 def __init__(self, *, sr_length, cmds=1, name=None, src_loc_at=0):
305 layout = [
306 ("i", sr_length, Direction.FANIN),
307 ("ie", cmds, Direction.FANOUT),
308 ("o", sr_length, Direction.FANOUT),
309 ("oe", cmds, Direction.FANOUT),
310 ]
311 super().__init__(layout, name=name, src_loc_at=src_loc_at+1)
312
313
314 class TAP(Elaboratable):
315 #TODO: Document TAP
316 def __init__(self, *, with_reset=False, ir_width=None,
317 manufacturer_id=Const(0b10001111111, 11),
318 part_number=Const(1, 16),
319 version=Const(0, 4),
320 name=None, src_loc_at=0):
321 assert((ir_width is None) or (isinstance(ir_width, int) and
322 ir_width >= 2))
323 assert(len(version) == 4)
324
325 if name is None:
326 name = get_var_name(depth=src_loc_at+2, default="TAP")
327 self.name = name
328 self.bus = Interface(with_reset=with_reset, name=self.name+"_bus",
329 src_loc_at=src_loc_at+1)
330
331 ##
332
333 self._ir_width = ir_width
334 self._manufacturer_id = manufacturer_id
335 self._part_number = part_number
336 self._version = version
337
338 self._ircodes = [0, 1, 2] # Already taken codes, all ones added at end
339
340 self._ios = []
341 self._srs = []
342 self._wbs = []
343 self._dmis = []
344
345 def elaborate(self, platform):
346 m = Module()
347
348 # Determine ir_width if not fixed.
349 ir_max = max(self._ircodes) + 1 # One extra code needed with all ones
350 ir_width = len("{:b}".format(ir_max))
351 if self._ir_width is not None:
352 assert self._ir_width >= ir_width, "Specified JTAG IR width " \
353 "not big enough for allocated shiift registers"
354 ir_width = self._ir_width
355
356 # TODO: Make commands numbers configurable
357 cmd_extest = 0
358 cmd_intest = 0
359 cmd_idcode = 1
360 cmd_sample = 2
361 cmd_preload = 2
362 cmd_bypass = 2**ir_width - 1 # All ones
363
364 m.submodules.fsm = fsm = _FSM(bus=self.bus)
365 m.domains.posjtag = fsm.posjtag
366 m.domains.negjtag = fsm.negjtag
367
368 # IR block
369 select_ir = fsm.isir
370 m.submodules.irblock = irblock = _IRBlock(
371 ir_width=ir_width, cmd_idcode=cmd_idcode, tdi=self.bus.tdi,
372 capture=(fsm.isir & fsm.capture),
373 shift=(fsm.isir & fsm.shift),
374 update=(fsm.isir & fsm.update),
375 name=self.name+"_ir",
376 )
377 ir = irblock.ir
378
379 # ID block
380 select_id = Signal()
381 id_bypass = Signal()
382 m.d.comb += select_id.eq(fsm.isdr &
383 ((ir == cmd_idcode) | (ir == cmd_bypass)))
384 m.d.comb += id_bypass.eq(ir == cmd_bypass)
385 m.submodules.idblock = idblock = _IDBypassBlock(
386 manufacturer_id=self._manufacturer_id,
387 part_number=self._part_number,
388 version=self._version, tdi=self.bus.tdi,
389 capture=(select_id & fsm.capture),
390 shift=(select_id & fsm.shift),
391 update=(select_id & fsm.update),
392 bypass=id_bypass,
393 name=self.name+"_id",
394 )
395
396 # IO (Boundary scan) block
397 io_capture = Signal()
398 io_shift = Signal()
399 io_update = Signal()
400 io_bd2io = Signal()
401 io_bd2core = Signal()
402 sample = (ir == cmd_extest) | (ir == cmd_sample)
403 preload = (ir == cmd_preload)
404 select_io = fsm.isdr & (sample | preload)
405 m.d.comb += [
406 io_capture.eq(sample & fsm.capture), # Don't capture if not sample
407 # (like for PRELOAD)
408 io_shift.eq(select_io & fsm.shift),
409 io_update.eq(select_io & fsm.update),
410 io_bd2io.eq(ir == cmd_extest),
411 io_bd2core.eq(ir == cmd_intest),
412 ]
413 io_tdo = self._elaborate_ios(
414 m=m,
415 capture=io_capture, shift=io_shift, update=io_update,
416 bd2io=io_bd2io, bd2core=io_bd2core,
417 )
418
419 # chain tdo: select as appropriate, to go into into shiftregs
420 tdo = Signal(name=self.name+"_tdo")
421 with m.If(select_ir):
422 m.d.comb += tdo.eq(irblock.tdo)
423 with m.Elif(select_id):
424 m.d.comb += tdo.eq(idblock.tdo)
425 with m.Elif(select_io):
426 m.d.comb += tdo.eq(io_tdo)
427
428 # shiftregs block
429 self._elaborate_shiftregs(
430 m, capture=fsm.capture, shift=fsm.shift, update=fsm.update,
431 ir=irblock.ir, tdo_jtag=tdo
432 )
433
434 # wishbone
435 self._elaborate_wishbones(m)
436
437 # DMI (Debug Memory Interface)
438 self._elaborate_dmis(m)
439
440 return m
441
442 def add_dmi(self, *, ircodes, address_width=8, data_width=64,
443 domain="sync", name=None):
444 """Add a DMI interface
445
446 * writing to DMIADDR will automatically trigger a DMI READ.
447 the DMI address does not alter (so writes can be done at that addr)
448 * reading from DMIREAD triggers a DMI READ at the current DMI addr
449 the address is automatically incremented by 1 after.
450 * writing to DMIWRITE triggers a DMI WRITE at the current DMI addr
451 the address is automatically incremented by 1 after.
452
453 Parameters:
454 -----------
455 ircodes: sequence of three integer for the JTAG IR codes;
456 they represent resp. DMIADDR, DMIREAD and DMIWRITE.
457 First code has a shift register of length 'address_width',
458 the two other codes share a shift register of length
459 data_width.
460
461 address_width: width of the address
462 data_width: width of the data
463
464 Returns:
465 dmi: soc.debug.dmi.DMIInterface
466 The DMI interface
467 """
468 if len(ircodes) != 3:
469 raise ValueError("3 IR Codes have to be provided")
470
471 if name is None:
472 name = "dmi" + str(len(self._dmis))
473
474 # add 2 shift registers: one for addr, one for data.
475 sr_addr = self.add_shiftreg(ircode=ircodes[0], length=address_width,
476 domain=domain, name=name+"_addrsr")
477 sr_data = self.add_shiftreg(ircode=ircodes[1:], length=data_width,
478 domain=domain, name=name+"_datasr")
479
480 dmi = DMIInterface(name=name)
481 self._dmis.append((sr_addr, sr_data, dmi, domain))
482
483 return dmi
484
485 def _elaborate_dmis(self, m):
486 for sr_addr, sr_data, dmi, domain in self._dmis:
487 cd = m.d[domain]
488 m.d.comb += sr_addr.i.eq(dmi.addr_i)
489
490 with m.FSM(domain=domain) as ds:
491
492 # detect mode based on whether jtag addr or data read/written
493 with m.State("IDLE"):
494 with m.If(sr_addr.oe): # DMIADDR code
495 cd += dmi.addr_i.eq(sr_addr.o)
496 m.next = "READ"
497 with m.Elif(sr_data.oe[0]): # DMIREAD code
498 # If data is
499 cd += dmi.addr_i.eq(dmi.addr_i + 1)
500 m.next = "READ"
501 with m.Elif(sr_data.oe[1]): # DMIWRITE code
502 cd += dmi.din.eq(sr_data.o)
503 m.next = "WRRD"
504
505 # req_i raises for 1 clock
506 with m.State("READ"):
507 m.next = "READACK"
508
509 # wait for read ack
510 with m.State("READACK"):
511 with m.If(dmi.ack_o):
512 # Store read data in sr_data.i hold till next read
513 cd += sr_data.i.eq(dmi.dout)
514 m.next = "IDLE"
515
516 # req_i raises for 1 clock
517 with m.State("WRRD"):
518 m.next = "WRRDACK"
519
520 # wait for write ack
521 with m.State("WRRDACK"):
522 with m.If(dmi.ack_o):
523 cd += dmi.addr_i.eq(dmi.addr_i + 1)
524 m.next = "READ" # for readwrite
525
526 # set DMI req and write-enable based on ongoing FSM states
527 m.d.comb += [
528 dmi.req_i.eq(ds.ongoing("READ") | ds.ongoing("WRRD")),
529 dmi.we_i.eq(ds.ongoing("WRRD")),
530 ]
531
532 def add_io(self, *, iotype, name=None, src_loc_at=0):
533 """Add a io cell to the boundary scan chain
534
535 Parameters:
536 - iotype: :class:`IOType` enum.
537
538 Returns:
539 - :class:`IOConn`
540 """
541 if name is None:
542 name = "ioconn" + str(len(self._ios))
543
544 ioconn = IOConn(iotype=iotype, name=name, src_loc_at=src_loc_at+1)
545 self._ios.append(ioconn)
546 return ioconn
547
548 def _elaborate_ios(self, *, m, capture, shift, update, bd2io, bd2core):
549 length = sum(IOConn.lengths[conn._iotype] for conn in self._ios)
550 if length == 0:
551 return self.bus.tdi
552
553 io_sr = Signal(length)
554 io_bd = Signal(length)
555
556 # Boundary scan "capture" mode. makes I/O status available via SR
557 with m.If(capture):
558 iol = []
559 idx = 0
560 for conn in self._ios:
561 # in appropriate sequence: In/TriOut has pad.i,
562 # Out.InTriOut has everything, Out and TriOut have core.o
563 if conn._iotype in [IOType.In, IOType.InTriOut]:
564 iol.append(conn.pad.i)
565 if conn._iotype in [IOType.Out, IOType.InTriOut]:
566 iol.append(conn.core.o)
567 if conn._iotype in [IOType.TriOut, IOType.InTriOut]:
568 iol.append(conn.core.oe)
569 # length double-check
570 idx += IOConn.lengths[conn._iotype] # fails if wrong type
571 assert idx == length, "Internal error"
572 m.d.posjtag += io_sr.eq(Cat(*iol)) # assigns all io_sr in one hit
573
574 # "Shift" mode (sends out captured data on tdo, sets incoming from tdi)
575 with m.Elif(shift):
576 m.d.posjtag += io_sr.eq(Cat(self.bus.tdi, io_sr[:-1]))
577
578 # "Update" mode
579 with m.Elif(update):
580 m.d.negjtag += io_bd.eq(io_sr)
581
582 # sets up IO (pad<->core) or in testing mode depending on requested
583 # mode, via Muxes controlled by bd2core and bd2io
584 idx = 0
585 for conn in self._ios:
586 if conn._iotype == IOType.In:
587 m.d.comb += conn.core.i.eq(Mux(bd2core, io_bd[idx], conn.pad.i))
588 idx += 1
589 elif conn._iotype == IOType.Out:
590 m.d.comb += conn.pad.o.eq(Mux(bd2io, io_bd[idx], conn.core.o))
591 idx += 1
592 elif conn._iotype == IOType.TriOut:
593 m.d.comb += [
594 conn.pad.o.eq(Mux(bd2io, io_bd[idx], conn.core.o)),
595 conn.pad.oe.eq(Mux(bd2io, io_bd[idx+1], conn.core.oe)),
596 ]
597 idx += 2
598 elif conn._iotype == IOType.InTriOut:
599 m.d.comb += [
600 conn.core.i.eq(Mux(bd2core, io_bd[idx], conn.pad.i)),
601 conn.pad.o.eq(Mux(bd2io, io_bd[idx+1], conn.core.o)),
602 conn.pad.oe.eq(Mux(bd2io, io_bd[idx+2], conn.core.oe)),
603 ]
604 idx += 3
605 else:
606 raise("Internal error")
607 assert idx == length, "Internal error"
608
609 return io_sr[-1]
610
611 def add_shiftreg(self, *, ircode, length, domain="sync", name=None,
612 src_loc_at=0):
613 """Add a shift register to the JTAG interface
614
615 Parameters:
616 - ircode: code(s) for the IR; int or sequence of ints. In the latter
617 case this shiftreg is shared between different IR codes.
618 - length: the length of the shift register
619 - domain: the domain on which the signal will be used"""
620
621 try:
622 ir_it = iter(ircode)
623 ircodes = ircode
624 except TypeError:
625 ir_it = ircodes = (ircode,)
626 for _ircode in ir_it:
627 if not isinstance(_ircode, int) or _ircode <= 0:
628 raise ValueError("IR code '{}' is not an int "
629 "greater than 0".format(_ircode))
630 if _ircode in self._ircodes:
631 raise ValueError("IR code '{}' already taken".format(_ircode))
632
633 self._ircodes.extend(ircodes)
634
635 if name is None:
636 name = "sr{}".format(len(self._srs))
637 sr = ShiftReg(sr_length=length, cmds=len(ircodes), name=name,
638 src_loc_at=src_loc_at+1)
639 self._srs.append((ircodes, domain, sr))
640
641 return sr
642
643 def _elaborate_shiftregs(self, m, capture, shift, update, ir, tdo_jtag):
644 # tdos is tuple of (tdo, tdo_en) for each shiftreg
645 tdos = []
646 for ircodes, domain, sr in self._srs:
647 reg = Signal(len(sr.o), name=sr.name+"_reg")
648 m.d.comb += sr.o.eq(reg)
649
650 isir = Signal(len(ircodes), name=sr.name+"_isir")
651 sr_capture = Signal(name=sr.name+"_capture")
652 sr_shift = Signal(name=sr.name+"_shift")
653 sr_update = Signal(name=sr.name+"_update")
654 m.d.comb += [
655 isir.eq(Cat(ir == ircode for ircode in ircodes)),
656 sr_capture.eq((isir != 0) & capture),
657 sr_shift.eq((isir != 0) & shift),
658 sr_update.eq((isir != 0) & update),
659 ]
660
661 # update signal is on the JTAG clockdomain, sr.oe is on `domain`
662 # clockdomain latch update in `domain` clockdomain and see when
663 # it has falling edge.
664 # At that edge put isir in sr.oe for one `domain` clockdomain
665 # Using this custom sync <> JTAG domain synchronization avoids
666 # the use of more generic but also higher latency CDC solutions
667 # like FFSynchronizer.
668 update_core = Signal(name=sr.name+"_update_core")
669 update_core_prev = Signal(name=sr.name+"_update_core_prev")
670 m.d[domain] += [
671 update_core.eq(sr_update), # This is CDC from JTAG domain
672 # to given domain
673 update_core_prev.eq(update_core)
674 ]
675 with m.If(update_core_prev & ~update_core):
676 # Falling edge of update
677 m.d[domain] += sr.oe.eq(isir)
678 with m.Else():
679 m.d[domain] += sr.oe.eq(0)
680
681 with m.If(sr_shift):
682 m.d.posjtag += reg.eq(Cat(reg[1:], self.bus.tdi))
683 with m.If(sr_capture):
684 m.d.posjtag += reg.eq(sr.i)
685
686 # tdo = reg[0], tdo_en = shift
687 tdos.append((reg[0], sr_shift))
688
689
690 # Assign the right tdo to the bus tdo
691 for i, (tdo, tdo_en) in enumerate(tdos):
692 if i == 0:
693 with m.If(tdo_en):
694 m.d.comb += self.bus.tdo.eq(tdo)
695 else:
696 with m.Elif(tdo_en):
697 m.d.comb += self.bus.tdo.eq(tdo)
698
699 if len(tdos) > 0:
700 with m.Else():
701 m.d.comb += self.bus.tdo.eq(tdo_jtag)
702 else:
703 # Always connect tdo_jtag to
704 m.d.comb += self.bus.tdo.eq(tdo_jtag)
705
706
707 def add_wishbone(self, *, ircodes, address_width, data_width,
708 granularity=None, domain="sync", features=None,
709 name=None, src_loc_at=0):
710 """Add a wishbone interface
711
712 In order to allow high JTAG clock speed, data will be cached.
713 This means that if data is output the value of the next address
714 will be read automatically.
715
716 Parameters:
717 -----------
718 ircodes: sequence of three integer for the JTAG IR codes;
719 they represent resp. WBADDR, WBREAD and WBREADWRITE. First code
720 has a shift register of length 'address_width', the two other codes
721 share a shift register of length data_width.
722 address_width: width of the address
723 data_width: width of the data
724 features: features required. defaults to stall, lock, err, rty
725
726 Returns:
727 wb: nmigen_soc.wishbone.bus.Interface
728 The Wishbone interface, is pipelined and has stall field.
729 """
730 if len(ircodes) != 3:
731 raise ValueError("3 IR Codes have to be provided")
732
733 if features is None:
734 features={"stall", "lock", "err", "rty"}
735 if name is None:
736 name = "wb" + str(len(self._wbs))
737 sr_addr = self.add_shiftreg(
738 ircode=ircodes[0], length=address_width, domain=domain,
739 name=name+"_addrsr"
740 )
741 sr_data = self.add_shiftreg(
742 ircode=ircodes[1:], length=data_width, domain=domain,
743 name=name+"_datasr"
744 )
745
746 wb = WishboneInterface(data_width=data_width, addr_width=address_width,
747 granularity=granularity, features=features,
748 name=name, src_loc_at=src_loc_at+1)
749
750 self._wbs.append((sr_addr, sr_data, wb, domain))
751
752 return wb
753
754 def _elaborate_wishbones(self, m):
755 for sr_addr, sr_data, wb, domain in self._wbs:
756 m.d.comb += sr_addr.i.eq(wb.adr)
757
758 if hasattr(wb, "sel"):
759 # Always selected
760 m.d.comb += [s.eq(1) for s in wb.sel]
761
762 with m.FSM(domain=domain) as fsm:
763 with m.State("IDLE"):
764 with m.If(sr_addr.oe): # WBADDR code
765 m.d[domain] += wb.adr.eq(sr_addr.o)
766 m.next = "READ"
767 with m.Elif(sr_data.oe[0]): # WBREAD code
768 # If data is
769 m.d[domain] += wb.adr.eq(wb.adr + 1)
770 m.next = "READ"
771 with m.Elif(sr_data.oe[1]): # WBWRITE code
772 m.d[domain] += wb.dat_w.eq(sr_data.o)
773 m.next = "WRITEREAD"
774 with m.State("READ"):
775 if not hasattr(wb, "stall"):
776 m.next = "READACK"
777 else:
778 with m.If(~wb.stall):
779 m.next = "READACK"
780 with m.State("READACK"):
781 with m.If(wb.ack):
782 # Store read data in sr_data.i
783 # and keep it there til next read.
784 # This is enough to synchronize between sync and JTAG
785 # clock domain and no higher latency solutions like
786 # FFSynchronizer is needed.
787 m.d[domain] += sr_data.i.eq(wb.dat_r)
788 m.next = "IDLE"
789 with m.State("WRITEREAD"):
790 if not hasattr(wb, "stall"):
791 m.next = "WRITEREADACK"
792 else:
793 with m.If(~wb.stall):
794 m.next = "WRITEREADACK"
795 with m.State("WRITEREADACK"):
796 with m.If(wb.ack):
797 m.d[domain] += wb.adr.eq(wb.adr + 1)
798 m.next = "READ"
799
800 if hasattr(wb, "stall"):
801 m.d.comb += wb.stb.eq(fsm.ongoing("READ") |
802 fsm.ongoing("WRITEREAD"))
803 m.d.comb += wb.we.eq(fsm.ongoing("WRITEREAD"))
804 else:
805 # non-stall is single-cycle (litex), must assert stb
806 # until ack is sent
807 m.d.comb += wb.stb.eq(fsm.ongoing("READ") |
808 fsm.ongoing("WRITEREAD") |
809 fsm.ongoing("READACK") |
810 fsm.ongoing("WRITEREADACK"))
811 m.d.comb += wb.we.eq(fsm.ongoing("WRITEREAD") |
812 fsm.ongoing("WRITEREADACK"))
813 m.d.comb += wb.cyc.eq(~fsm.ongoing("IDLE"))