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