8c2ea43bfc8c0ffc0213337254955c9a00fbe0d3
[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 lengths = {
161 IOType.In: 1,
162 IOType.Out: 1,
163 IOType.TriOut: 2,
164 IOType.InTriOut: 3,
165 }
166
167 """TAP subblock representing the interface for an JTAG IO cell.
168 It contains signal to connect to the core and to the pad
169
170 This object is normally only allocated and returned from ``TAP.add_io``
171 It is a Record subclass.
172
173 Attributes
174 ----------
175 core: subrecord with signals for the core
176 i: Signal(1), present only for IOType.In and IOType.InTriOut.
177 Signal input to core with pad input value.
178 o: Signal(1), present only for IOType.Out, IOType.TriOut and
179 IOType.InTriOut.
180 Signal output from core with the pad output value.
181 oe: Signal(1), present only for IOType.TriOut and IOType.InTriOut.
182 Signal output from core with the pad output enable value.
183 pad: subrecord with for the pad
184 i: Signal(1), present only for IOType.In and IOType.InTriOut
185 Output from pad with pad input value for core.
186 o: Signal(1), present only for IOType.Out, IOType.TriOut and
187 IOType.InTriOut.
188 Input to pad with pad output value.
189 oe: Signal(1), present only for IOType.TriOut and IOType.InTriOut.
190 Input to pad with pad output enable value.
191 """
192 @staticmethod
193 def layout(iotype):
194 sigs = []
195 if iotype in (IOType.In, IOType.InTriOut):
196 sigs.append(("i", 1))
197 if iotype in (IOType.Out, IOType.TriOut, IOType.InTriOut):
198 sigs.append(("o", 1))
199 if iotype in (IOType.TriOut, IOType.InTriOut):
200 sigs.append(("oe", 1))
201
202 return Layout((("core", sigs), ("pad", sigs)))
203
204 def __init__(self, *, iotype, name=None, src_loc_at=0):
205 super().__init__(self.__class__.layout(iotype), name=name,
206 src_loc_at=src_loc_at+1)
207
208 self._iotype = iotype
209
210 class _IDBypassBlock(Elaboratable):
211 """TAP subblock for the ID shift register"""
212 def __init__(self, *, manufacturer_id, part_number, version,
213 tdi, capture, shift, update, bypass,
214 name):
215 self.name = name
216 if (not isinstance(manufacturer_id, Const) and
217 len(manufacturer_id) != 11):
218 raise ValueError("manufacturer_id has to be Const of length 11")
219 if not isinstance(part_number, Const) and len(manufacturer_id) != 16:
220 raise ValueError("part_number has to be Const of length 16")
221 if not isinstance(version, Const) and len(version) != 4:
222 raise ValueError("version has to be Const of length 4")
223 self._id = Cat(Const(1,1), manufacturer_id, part_number, version)
224
225 self.tdo = Signal(name=name+"_tdo")
226
227 self._tdi = tdi
228 self._capture = capture
229 self._shift = shift
230 self._update = update
231 self._bypass = bypass
232
233 def elaborate(self, platform):
234 m = Module()
235
236 sr = Signal(32, reset_less=True, name=self.name+"_sr")
237
238 # Local signals for the module
239 _tdi = Signal()
240 _capture = Signal()
241 _shift = Signal()
242 _update = Signal()
243 _bypass = Signal()
244
245 m.d.comb += [
246 _tdi.eq(self._tdi),
247 _capture.eq(self._capture),
248 _shift.eq(self._shift),
249 _update.eq(self._update),
250 _bypass.eq(self._bypass),
251 self.tdo.eq(sr[0]),
252 ]
253
254 with m.If(_capture):
255 m.d.posjtag += sr.eq(self._id)
256 with m.Elif(_shift):
257 with m.If(_bypass):
258 m.d.posjtag += sr[0].eq(_tdi)
259 with m.Else():
260 m.d.posjtag += sr.eq(Cat(sr[1:], _tdi))
261
262 return m
263
264
265 class ShiftReg(Record):
266 """Object with interface for extra shift registers on a TAP.
267
268 Parameters
269 ----------
270 sr_length : int
271 cmds : int, default=1
272 The number of corresponding JTAG instructions
273
274 This object is normally only allocated and returned from ``TAP.add_shiftreg``
275 It is a Record subclass.
276
277 Attributes
278 ----------
279 i: length=sr_length, FANIN
280 The input data sampled during capture state of the TAP
281 ie: length=cmds, FANOUT
282 Indicates that data is to be sampled by the JTAG TAP and
283 should be held stable. The bit indicates the corresponding
284 instruction for which data is asked.
285 This signal is kept high for a whole JTAG TAP clock cycle
286 and may thus be kept higher for more than one clock cycle
287 on the domain where ShiftReg is used.
288 The JTAG protocol does not allow insertion of wait states
289 so data need to be provided before ie goes down. The speed
290 of the response will determine the max. frequency for the
291 JTAG interface.
292 o: length=sr_length, FANOUT
293 The value of the shift register.
294 oe: length=cmds, FANOUT
295 Indicates that output is stable and can be sampled downstream because
296 JTAG TAP is in the Update state. The bit indicates the corresponding
297 instruction. The bit is only kept high for one clock cycle.
298 """
299 def __init__(self, *, sr_length, cmds=1, name=None, src_loc_at=0):
300 layout = [
301 ("i", sr_length, Direction.FANIN),
302 ("ie", cmds, Direction.FANOUT),
303 ("o", sr_length, Direction.FANOUT),
304 ("oe", cmds, Direction.FANOUT),
305 ]
306 super().__init__(layout, name=name, src_loc_at=src_loc_at+1)
307
308 class TAP(Elaboratable):
309 #TODO: Document TAP
310 def __init__(self, *, with_reset=False, ir_width=None,
311 manufacturer_id=Const(0b10001111111, 11),
312 part_number=Const(1, 16),
313 version=Const(0, 4),
314 name=None, src_loc_at=0):
315 assert((ir_width is None) or (isinstance(ir_width, int) and
316 ir_width >= 2))
317 assert(len(version) == 4)
318
319 if name is None:
320 name = get_var_name(depth=src_loc_at+2, default="TAP")
321 self.name = name
322 self.bus = Interface(with_reset=with_reset, name=self.name+"_bus",
323 src_loc_at=src_loc_at+1)
324
325 ##
326
327 self._ir_width = ir_width
328 self._manufacturer_id = manufacturer_id
329 self._part_number = part_number
330 self._version = version
331
332 self._ircodes = [0, 1, 2] # Already taken codes, all ones added at end
333
334 self._ios = []
335 self._srs = []
336 self._wbs = []
337 self._dmis = []
338
339 def elaborate(self, platform):
340 m = Module()
341
342 # Determine ir_width if not fixed.
343 ir_max = max(self._ircodes) + 1 # One extra code needed with all ones
344 ir_width = len("{:b}".format(ir_max))
345 if self._ir_width is not None:
346 assert self._ir_width >= ir_width, "Specified JTAG IR width " \
347 "not big enough for allocated shiift registers"
348 ir_width = self._ir_width
349
350 # TODO: Make commands numbers configurable
351 cmd_extest = 0
352 cmd_intest = 0
353 cmd_idcode = 1
354 cmd_sample = 2
355 cmd_preload = 2
356 cmd_bypass = 2**ir_width - 1 # All ones
357
358 m.submodules._fsm = fsm = _FSM(bus=self.bus)
359 m.domains.posjtag = fsm.posjtag
360 m.domains.negjtag = fsm.negjtag
361
362 # IR block
363 select_ir = fsm.isir
364 m.submodules._irblock = irblock = _IRBlock(
365 ir_width=ir_width, cmd_idcode=cmd_idcode, tdi=self.bus.tdi,
366 capture=(fsm.isir & fsm.capture),
367 shift=(fsm.isir & fsm.shift),
368 update=(fsm.isir & fsm.update),
369 name=self.name+"_ir",
370 )
371 ir = irblock.ir
372
373 # ID block
374 select_id = fsm.isdr & ((ir == cmd_idcode) | (ir == cmd_bypass))
375 m.submodules._idblock = idblock = _IDBypassBlock(
376 manufacturer_id=self._manufacturer_id,
377 part_number=self._part_number,
378 version=self._version, tdi=self.bus.tdi,
379 capture=(select_id & fsm.capture),
380 shift=(select_id & fsm.shift),
381 update=(select_id & fsm.update),
382 bypass=(ir == cmd_bypass),
383 name=self.name+"_id",
384 )
385
386 # IO (Boundary scan) block
387 io_capture = Signal()
388 io_shift = Signal()
389 io_update = Signal()
390 io_bd2io = Signal()
391 io_bd2core = Signal()
392 sample = (ir == cmd_extest) | (ir == cmd_sample)
393 preload = (ir == cmd_preload)
394 select_io = fsm.isdr & (sample | preload)
395 m.d.comb += [
396 io_capture.eq(sample & fsm.capture), # Don't capture if not sample
397 # (like for PRELOAD)
398 io_shift.eq(select_io & fsm.shift),
399 io_update.eq(select_io & fsm.update),
400 io_bd2io.eq(ir == cmd_extest),
401 io_bd2core.eq(ir == cmd_intest),
402 ]
403 io_tdo = self._elaborate_ios(
404 m=m,
405 capture=io_capture, shift=io_shift, update=io_update,
406 bd2io=io_bd2io, bd2core=io_bd2core,
407 )
408
409 # chain tdo: select as appropriate, to go into into shiftregs
410 tdo = Signal(name=self.name+"_tdo")
411 with m.If(select_ir):
412 m.d.comb += tdo.eq(irblock.tdo)
413 with m.Elif(select_id):
414 m.d.comb += tdo.eq(idblock.tdo)
415 if io_tdo is not None:
416 with m.Elif(select_io):
417 m.d.comb += tdo.eq(io_tdo)
418
419 # shiftregs block
420 self._elaborate_shiftregs(
421 m, capture=fsm.capture, shift=fsm.shift, update=fsm.update,
422 ir=irblock.ir, tdo_jtag=tdo
423 )
424
425 # wishbone
426 self._elaborate_wishbones(m)
427
428 # DMI (Debug Memory Interface)
429 self._elaborate_dmis(m)
430
431 return m
432
433 def add_dmi(self, *, ircodes, address_width=8, data_width=64,
434 domain="sync", name=None):
435 """Add a DMI interface
436
437 * writing to DMIADDR will automatically trigger a DMI READ.
438 the DMI address does not alter (so writes can be done at that addr)
439 * reading from DMIREAD triggers a DMI READ at the current DMI addr
440 the address is automatically incremented by 1 after.
441 * writing to DMIWRITE triggers a DMI WRITE at the current DMI addr
442 the address is automatically incremented by 1 after.
443
444 Parameters:
445 -----------
446 ircodes: sequence of three integer for the JTAG IR codes;
447 they represent resp. DMIADDR, DMIREAD and DMIWRITE.
448 First code has a shift register of length 'address_width',
449 the two other codes share a shift register of length
450 data_width.
451
452 address_width: width of the address
453 data_width: width of the data
454
455 Returns:
456 dmi: soc.debug.dmi.DMIInterface
457 The DMI interface
458 """
459 if len(ircodes) != 3:
460 raise ValueError("3 IR Codes have to be provided")
461
462 if name is None:
463 name = "dmi" + str(len(self._dmis))
464
465 # add 2 shift registers: one for addr, one for data.
466 sr_addr = self.add_shiftreg(ircode=ircodes[0], length=address_width,
467 domain=domain, name=name+"_addrsr")
468 sr_data = self.add_shiftreg(ircode=ircodes[1:], length=data_width,
469 domain=domain, name=name+"_datasr")
470
471 dmi = DMIInterface(name=name)
472 self._dmis.append((sr_addr, sr_data, dmi, domain))
473
474 return dmi
475
476 def _elaborate_dmis(self, m):
477 for sr_addr, sr_data, dmi, domain in self._dmis:
478 cd = m.d[domain]
479 m.d.comb += sr_addr.i.eq(dmi.addr_i)
480
481 with m.FSM(domain=domain) as ds:
482
483 # detect mode based on whether jtag addr or data read/written
484 with m.State("IDLE"):
485 with m.If(sr_addr.oe): # DMIADDR code
486 cd += dmi.addr_i.eq(sr_addr.o)
487 m.next = "READ"
488 with m.Elif(sr_data.oe[0]): # DMIREAD code
489 # If data is
490 cd += dmi.addr_i.eq(dmi.addr_i + 1)
491 m.next = "READ"
492 with m.Elif(sr_data.oe[1]): # DMIWRITE code
493 cd += dmi.din.eq(sr_data.o)
494 m.next = "WRRD"
495
496 # req_i raises for 1 clock
497 with m.State("READ"):
498 m.next = "READACK"
499
500 # wait for read ack
501 with m.State("READACK"):
502 with m.If(dmi.ack_o):
503 # Store read data in sr_data.i hold till next read
504 cd += sr_data.i.eq(dmi.dout)
505 m.next = "IDLE"
506
507 # req_i raises for 1 clock
508 with m.State("WRRD"):
509 m.next = "WRRDACK"
510
511 # wait for write ack
512 with m.State("WRRDACK"):
513 with m.If(dmi.ack_o):
514 cd += dmi.addr_i.eq(dmi.addr_i + 1)
515 m.next = "READ" # for readwrite
516
517 # set DMI req and write-enable based on ongoing FSM states
518 m.d.comb += [
519 dmi.req_i.eq(ds.ongoing("READ") | ds.ongoing("WRRD")),
520 dmi.we_i.eq(ds.ongoing("WRRD")),
521 ]
522
523 def add_io(self, *, iotype, name=None, src_loc_at=0):
524 """Add a io cell to the boundary scan chain
525
526 Parameters:
527 - iotype: :class:`IOType` enum.
528
529 Returns:
530 - :class:`IOConn`
531 """
532 if name is None:
533 name = "ioconn" + str(len(self._ios))
534
535 ioconn = IOConn(iotype=iotype, name=name, src_loc_at=src_loc_at+1)
536 self._ios.append(ioconn)
537 return ioconn
538
539 def _elaborate_ios(self, *, m, capture, shift, update, bd2io, bd2core):
540 length = sum(IOConn.lengths[conn._iotype] for conn in self._ios)
541 if length == 0:
542 return None
543
544 io_sr = Signal(length)
545 io_bd = Signal(length)
546
547 # Boundary scan "capture" mode. makes I/O status available via SR
548 with m.If(capture):
549 iol = []
550 idx = 0
551 for conn in self._ios:
552 # in appropriate sequence: In/TriOut has pad.i,
553 # Out.InTriOut has everything, Out and TriOut have core.o
554 if conn._iotype in [IOType.In, IOType.InTriOut]:
555 iol.append(conn.pad.i)
556 if conn._iotype in [IOType.Out, IOType.InTriOut]:
557 iol.append(conn.core.o)
558 if conn._iotype in [IOType.TriOut, IOType.InTriOut]:
559 iol.append(conn.core.oe)
560 # length double-check
561 idx += IOConn.lengths[conn._iotype] # fails if wrong type
562 assert idx == length, "Internal error"
563 m.d.posjtag += io_sr.eq(Cat(*iol)) # assigns all io_sr in one hit
564
565 # "Shift" mode (sends out captured data on tdo, sets incoming from tdi)
566 with m.Elif(shift):
567 m.d.posjtag += io_sr.eq(Cat(self.bus.tdi, io_sr[:-1]))
568
569 # "Update" mode
570 with m.Elif(update):
571 m.d.negjtag += io_bd.eq(io_sr)
572
573 # sets up IO (pad<->core) or in testing mode depending on requested
574 # mode, via Muxes controlled by bd2core and bd2io
575 idx = 0
576 for conn in self._ios:
577 if conn._iotype == IOType.In:
578 m.d.comb += conn.core.i.eq(Mux(bd2core, io_bd[idx], conn.pad.i))
579 idx += 1
580 elif conn._iotype == IOType.Out:
581 m.d.comb += conn.pad.o.eq(Mux(bd2io, io_bd[idx], conn.core.o))
582 idx += 1
583 elif conn._iotype == IOType.TriOut:
584 m.d.comb += [
585 conn.pad.o.eq(Mux(bd2io, io_bd[idx], conn.core.o)),
586 conn.pad.oe.eq(Mux(bd2io, io_bd[idx+1], conn.core.oe)),
587 ]
588 idx += 2
589 elif conn._iotype == IOType.InTriOut:
590 m.d.comb += [
591 conn.core.i.eq(Mux(bd2core, io_bd[idx], conn.pad.i)),
592 conn.pad.o.eq(Mux(bd2io, io_bd[idx+1], conn.core.o)),
593 conn.pad.oe.eq(Mux(bd2io, io_bd[idx+2], conn.core.oe)),
594 ]
595 idx += 3
596 else:
597 raise("Internal error")
598 assert idx == length, "Internal error"
599
600 return io_sr[-1]
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 ]