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