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