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