3 # Copyright (C) 2019,2020,2021 Staf Verhaegen <staf@fibraservi.eu>
4 # Copyright (C) 2021,2022 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
5 # Funded by NLnet and NGI POINTER under EU Grants 871528 and 957073
8 from enum
import Enum
, auto
10 from nmigen
import (Elaboratable
, Signal
, Module
, ClockDomain
, Cat
, Record
,
12 from nmigen
.hdl
.rec
import Direction
, Layout
13 from nmigen
.tracer
import get_var_name
15 from nmigen_soc
.wishbone
import Interface
as WishboneInterface
17 from .bus
import Interface
, DMIInterface
20 "TAP", "ShiftReg", "IOType", "IOConn",
24 class _FSM(Elaboratable
):
25 """TAP subblock for the FSM"""
26 def __init__(self
, *, bus
):
29 self
.capture
= Signal()
31 self
.update
= Signal()
33 # JTAG uses both edges of the incoming clock (TCK). set them up here
34 self
.posjtag
= ClockDomain("posjtag", local
=True)
35 self
.negjtag
= ClockDomain("negjtag", local
=True, clk_edge
="neg")
39 def elaborate(self
, platform
):
44 self
.posjtag
.clk
.eq(self
._bus
.tck
),
45 self
.posjtag
.rst
.eq(rst
),
46 self
.negjtag
.clk
.eq(self
._bus
.tck
),
47 self
.negjtag
.rst
.eq(rst
),
50 # Make local clock domain optionally using trst of JTAG bus as reset
51 if hasattr(self
._bus
, "trst"):
52 m
.domains
.local
= local
= ClockDomain(local
=True)
53 m
.d
.comb
+= local
.rst
.eq(self
._bus
.trst
)
55 m
.domains
.local
= local
= ClockDomain(local
=True, reset_less
=True)
56 m
.d
.comb
+= local
.clk
.eq(self
._bus
.tck
)
58 with m
.FSM(domain
="local") as fsm
:
59 with m
.State("TestLogicReset"):
60 # Be sure to reset isir, isdr
65 with m
.If(self
._bus
.tms
== 0):
66 m
.next
= "RunTestIdle"
67 with m
.State("RunTestIdle"):
68 # Be sure to reset isir, isdr
73 with m
.If(self
._bus
.tms
== 1):
74 m
.next
= "SelectDRScan"
75 with m
.State("SelectDRScan"):
76 with m
.If(self
._bus
.tms
== 0):
77 m
.d
.local
+= self
.isdr
.eq(1)
78 m
.next
= "CaptureState"
80 m
.next
= "SelectIRScan"
81 with m
.State("SelectIRScan"):
82 with m
.If(self
._bus
.tms
== 0):
83 m
.d
.local
+= self
.isir
.eq(1)
84 m
.next
= "CaptureState"
86 m
.next
= "TestLogicReset"
87 with m
.State("CaptureState"):
88 with m
.If(self
._bus
.tms
== 0):
92 with m
.State("ShiftState"):
93 with m
.If(self
._bus
.tms
== 1):
95 with m
.State("Exit1"):
96 with m
.If(self
._bus
.tms
== 0):
99 m
.next
= "UpdateState"
100 with m
.State("Pause"):
101 with m
.If(self
._bus
.tms
== 1):
103 with m
.State("Exit2"):
104 with m
.If(self
._bus
.tms
== 0):
105 m
.next
= "ShiftState"
107 m
.next
= "UpdateState"
108 with m
.State("UpdateState"):
113 with m
.If(self
._bus
.tms
== 0):
114 m
.next
= "RunTestIdle"
116 m
.next
= "SelectDRScan"
119 rst
.eq(fsm
.ongoing("TestLogicReset")),
120 self
.capture
.eq(fsm
.ongoing("CaptureState")),
121 self
.shift
.eq(fsm
.ongoing("ShiftState")),
122 self
.update
.eq(fsm
.ongoing("UpdateState")),
128 class _IRBlock(Elaboratable
):
129 """TAP subblock for handling the IR shift register"""
130 def __init__(self
, *, ir_width
, cmd_idcode
,
131 tdi
, capture
, shift
, update
,
134 self
.ir
= Signal(ir_width
, reset
=cmd_idcode
)
138 self
._capture
= capture
140 self
._update
= update
142 def elaborate(self
, platform
):
145 shift_ir
= Signal(len(self
.ir
), reset_less
=True)
147 m
.d
.comb
+= self
.tdo
.eq(self
.ir
[0])
148 with m
.If(self
._capture
):
149 m
.d
.posjtag
+= shift_ir
.eq(self
.ir
)
150 with m
.Elif(self
._shift
):
151 m
.d
.posjtag
+= shift_ir
.eq(Cat(shift_ir
[1:], self
._tdi
))
152 with m
.Elif(self
._update
):
153 # For ir we only update it on the rising edge of clock
154 # to avoid that we already have the new ir value when still in
156 m
.d
.posjtag
+= self
.ir
.eq(shift_ir
)
168 class IOConn(Record
):
176 """TAP subblock representing the interface for an JTAG IO cell.
177 It contains signals to connect to the core and to the pad
179 This object is normally only allocated and returned from ``TAP.add_io``
180 It is a Record subclass.
184 core: subrecord with signals for the core
185 i: Signal(1), present only for IOType.In and IOType.InTriOut.
186 Signal input to core with pad input value.
187 o: Signal(1), present only for IOType.Out, IOType.TriOut and
189 Signal output from core with the pad output value.
190 oe: Signal(1), present only for IOType.TriOut and IOType.InTriOut.
191 Signal output from core with the pad output enable value.
192 pad: subrecord with for the pad
193 i: Signal(1), present only for IOType.In and IOType.InTriOut
194 Output from pad with pad input value for core.
195 o: Signal(1), present only for IOType.Out, IOType.TriOut and
197 Input to pad with pad output value.
198 oe: Signal(1), present only for IOType.TriOut and IOType.InTriOut.
199 Input to pad with pad output enable value.
201 bank select, pullup and pulldown may also be optionally added
204 def layout(iotype
, banksel
=0, pullup
=False, pulldown
=False):
206 if iotype
in (IOType
.In
, IOType
.InTriOut
):
207 sigs
.append(("i", 1))
208 if iotype
in (IOType
.Out
, IOType
.TriOut
, IOType
.InTriOut
):
209 sigs
.append(("o", 1))
210 if iotype
in (IOType
.TriOut
, IOType
.InTriOut
):
211 sigs
.append(("oe", 1))
213 sigs
.append(("sel", banksel
))
215 sigs
.append(("pu", 1))
217 sigs
.append(("pd", 1))
219 return Layout((("core", sigs
), ("pad", sigs
)))
221 def __init__(self
, *, iotype
, name
=None, banksel
=0,
222 pullup
=False, pulldown
=False,
224 layout
= self
.__class
__.layout(iotype
, banksel
, pullup
, pulldown
)
225 super().__init
__(layout
, name
=name
, src_loc_at
=src_loc_at
+1)
227 self
._iotype
= iotype
228 self
._banksel
= banksel
229 self
._pullup
= pullup
230 self
._pulldown
= pulldown
233 class _IDBypassBlock(Elaboratable
):
234 """TAP subblock for the ID shift register"""
235 def __init__(self
, *, manufacturer_id
, part_number
, version
,
236 tdi
, capture
, shift
, update
, bypass
,
239 if (not isinstance(manufacturer_id
, Const
) and
240 len(manufacturer_id
) != 11):
241 raise ValueError("manufacturer_id has to be Const of length 11")
242 if not isinstance(part_number
, Const
) and len(manufacturer_id
) != 16:
243 raise ValueError("part_number has to be Const of length 16")
244 if not isinstance(version
, Const
) and len(version
) != 4:
245 raise ValueError("version has to be Const of length 4")
246 self
._id
= Cat(Const(1,1), manufacturer_id
, part_number
, version
)
248 self
.tdo
= Signal(name
=name
+"_tdo")
251 self
._capture
= capture
253 self
._update
= update
254 self
._bypass
= bypass
256 def elaborate(self
, platform
):
259 sr
= Signal(32, reset_less
=True, name
=self
.name
+"_sr")
261 # Local signals for the module
270 _capture
.eq(self
._capture
),
271 _shift
.eq(self
._shift
),
272 _update
.eq(self
._update
),
273 _bypass
.eq(self
._bypass
),
278 m
.d
.posjtag
+= sr
.eq(self
._id
)
281 m
.d
.posjtag
+= sr
[0].eq(_tdi
)
283 m
.d
.posjtag
+= sr
.eq(Cat(sr
[1:], _tdi
))
288 class ShiftReg(Record
):
289 """Object with interface for extra shift registers on a TAP.
294 cmds : int, default=1
295 The number of corresponding JTAG instructions
297 This object is normally only allocated and returned from ``TAP.add_shiftreg``
298 It is a Record subclass.
302 i: length=sr_length, FANIN
303 The input data sampled during capture state of the TAP
304 ie: length=cmds, FANOUT
305 Indicates that data is to be sampled by the JTAG TAP and
306 should be held stable. The bit indicates the corresponding
307 instruction for which data is asked.
308 This signal is kept high for a whole JTAG TAP clock cycle
309 and may thus be kept higher for more than one clock cycle
310 on the domain where ShiftReg is used.
311 The JTAG protocol does not allow insertion of wait states
312 so data need to be provided before ie goes down. The speed
313 of the response will determine the max. frequency for the
315 o: length=sr_length, FANOUT
316 The value of the shift register.
317 oe: length=cmds, FANOUT
318 Indicates that output is stable and can be sampled downstream because
319 JTAG TAP is in the Update state. The bit indicates the corresponding
320 instruction. The bit is only kept high for one clock cycle.
322 def __init__(self
, *, sr_length
, cmds
=1, name
=None, src_loc_at
=0):
324 ("i", sr_length
, Direction
.FANIN
),
325 ("ie", cmds
, Direction
.FANOUT
),
326 ("o", sr_length
, Direction
.FANOUT
),
327 ("oe", cmds
, Direction
.FANOUT
),
329 super().__init
__(layout
, name
=name
, src_loc_at
=src_loc_at
+1)
332 class TAP(Elaboratable
):
334 def __init__(self
, *, with_reset
=False, ir_width
=None,
335 manufacturer_id
=Const(0b10001111111, 11),
336 part_number
=Const(1, 16),
338 name
=None, src_loc_at
=0):
339 assert((ir_width
is None) or (isinstance(ir_width
, int) and
341 assert(len(version
) == 4)
344 name
= get_var_name(depth
=src_loc_at
+2, default
="TAP")
346 self
.bus
= Interface(with_reset
=with_reset
, name
=self
.name
+"_bus",
347 src_loc_at
=src_loc_at
+1)
351 self
._ir
_width
= ir_width
352 self
._manufacturer
_id
= manufacturer_id
353 self
._part
_number
= part_number
354 self
._version
= version
356 self
._ircodes
= [0, 1, 2] # Already taken codes, all ones added at end
363 def elaborate(self
, platform
):
366 # Determine ir_width if not fixed.
367 ir_max
= max(self
._ircodes
) + 1 # One extra code needed with all ones
368 ir_width
= len("{:b}".format(ir_max
))
369 if self
._ir
_width
is not None:
370 assert self
._ir
_width
>= ir_width
, "Specified JTAG IR width " \
371 "not big enough for allocated shiift registers"
372 ir_width
= self
._ir
_width
374 # TODO: Make commands numbers configurable
380 cmd_bypass
= 2**ir_width
- 1 # All ones
382 m
.submodules
.fsm
= fsm
= _FSM(bus
=self
.bus
)
383 m
.domains
.posjtag
= fsm
.posjtag
384 m
.domains
.negjtag
= fsm
.negjtag
388 m
.submodules
.irblock
= irblock
= _IRBlock(
389 ir_width
=ir_width
, cmd_idcode
=cmd_idcode
, tdi
=self
.bus
.tdi
,
390 capture
=(fsm
.isir
& fsm
.capture
),
391 shift
=(fsm
.isir
& fsm
.shift
),
392 update
=(fsm
.isir
& fsm
.update
),
393 name
=self
.name
+"_ir",
400 m
.d
.comb
+= select_id
.eq(fsm
.isdr
&
401 ((ir
== cmd_idcode
) |
(ir
== cmd_bypass
)))
402 m
.d
.comb
+= id_bypass
.eq(ir
== cmd_bypass
)
403 m
.submodules
.idblock
= idblock
= _IDBypassBlock(
404 manufacturer_id
=self
._manufacturer
_id
,
405 part_number
=self
._part
_number
,
406 version
=self
._version
, tdi
=self
.bus
.tdi
,
407 capture
=(select_id
& fsm
.capture
),
408 shift
=(select_id
& fsm
.shift
),
409 update
=(select_id
& fsm
.update
),
411 name
=self
.name
+"_id",
414 # IO (Boundary scan) block
415 io_capture
= Signal()
419 io_bd2core
= Signal()
420 sample
= (ir
== cmd_extest
) |
(ir
== cmd_sample
)
421 preload
= (ir
== cmd_preload
)
422 select_io
= fsm
.isdr
& (sample | preload
)
424 io_capture
.eq(sample
& fsm
.capture
), # Don't capture if not sample
426 io_shift
.eq(select_io
& fsm
.shift
),
427 io_update
.eq(select_io
& fsm
.update
),
428 io_bd2io
.eq(ir
== cmd_extest
),
429 io_bd2core
.eq(ir
== cmd_intest
),
431 io_tdo
= self
._elaborate
_ios
(
433 capture
=io_capture
, shift
=io_shift
, update
=io_update
,
434 bd2io
=io_bd2io
, bd2core
=io_bd2core
,
437 # chain tdo: select as appropriate, to go into into shiftregs
438 tdo
= Signal(name
=self
.name
+"_tdo")
439 with m
.If(select_ir
):
440 m
.d
.comb
+= tdo
.eq(irblock
.tdo
)
441 with m
.Elif(select_id
):
442 m
.d
.comb
+= tdo
.eq(idblock
.tdo
)
443 with m
.Elif(select_io
):
444 m
.d
.comb
+= tdo
.eq(io_tdo
)
447 self
._elaborate
_shiftregs
(
448 m
, capture
=fsm
.capture
, shift
=fsm
.shift
, update
=fsm
.update
,
449 ir
=irblock
.ir
, tdo_jtag
=tdo
453 self
._elaborate
_wishbones
(m
)
455 # DMI (Debug Memory Interface)
456 self
._elaborate
_dmis
(m
)
460 def add_dmi(self
, *, ircodes
, address_width
=8, data_width
=64,
461 domain
="sync", name
=None):
462 """Add a DMI interface
464 * writing to DMIADDR will automatically trigger a DMI READ.
465 the DMI address does not alter (so writes can be done at that addr)
466 * reading from DMIREAD triggers a DMI READ at the current DMI addr
467 the address is automatically incremented by 1 after.
468 * writing to DMIWRITE triggers a DMI WRITE at the current DMI addr
469 the address is automatically incremented by 1 after.
473 ircodes: sequence of three integer for the JTAG IR codes;
474 they represent resp. DMIADDR, DMIREAD and DMIWRITE.
475 First code has a shift register of length 'address_width',
476 the two other codes share a shift register of length
479 address_width: width of the address
480 data_width: width of the data
483 dmi: soc.debug.dmi.DMIInterface
486 if len(ircodes
) != 3:
487 raise ValueError("3 IR Codes have to be provided")
490 name
= "dmi" + str(len(self
._dmis
))
492 # add 2 shift registers: one for addr, one for data.
493 sr_addr
= self
.add_shiftreg(ircode
=ircodes
[0], length
=address_width
,
494 domain
=domain
, name
=name
+"_addrsr")
495 sr_data
= self
.add_shiftreg(ircode
=ircodes
[1:], length
=data_width
,
496 domain
=domain
, name
=name
+"_datasr")
498 dmi
= DMIInterface(name
=name
)
499 self
._dmis
.append((sr_addr
, sr_data
, dmi
, domain
))
503 def _elaborate_dmis(self
, m
):
504 for sr_addr
, sr_data
, dmi
, domain
in self
._dmis
:
506 m
.d
.comb
+= sr_addr
.i
.eq(dmi
.addr_i
)
508 with m
.FSM(domain
=domain
) as ds
:
510 # detect mode based on whether jtag addr or data read/written
511 with m
.State("IDLE"):
512 with m
.If(sr_addr
.oe
): # DMIADDR code
513 cd
+= dmi
.addr_i
.eq(sr_addr
.o
)
515 with m
.Elif(sr_data
.oe
[0]): # DMIREAD code
517 cd
+= dmi
.addr_i
.eq(dmi
.addr_i
+ 1)
519 with m
.Elif(sr_data
.oe
[1]): # DMIWRITE code
520 cd
+= dmi
.din
.eq(sr_data
.o
)
523 # req_i raises for 1 clock
524 with m
.State("READ"):
528 with m
.State("READACK"):
529 with m
.If(dmi
.ack_o
):
530 # Store read data in sr_data.i hold till next read
531 cd
+= sr_data
.i
.eq(dmi
.dout
)
534 # req_i raises for 1 clock
535 with m
.State("WRRD"):
539 with m
.State("WRRDACK"):
540 with m
.If(dmi
.ack_o
):
541 cd
+= dmi
.addr_i
.eq(dmi
.addr_i
+ 1)
542 m
.next
= "READ" # for readwrite
544 # set DMI req and write-enable based on ongoing FSM states
546 dmi
.req_i
.eq(ds
.ongoing("READ") | ds
.ongoing("WRRD")),
547 dmi
.we_i
.eq(ds
.ongoing("WRRD")),
550 def add_io(self
, *, iotype
, name
=None, src_loc_at
=0,
551 banksel
=0, pullup
=False, pulldown
=False):
552 """Add a io cell to the boundary scan chain
555 - iotype: :class:`IOType` enum.
561 name
= "ioconn" + str(len(self
._ios
))
563 ioconn
= IOConn(iotype
=iotype
, banksel
=banksel
,
564 pullup
=pullup
, pulldown
=pulldown
,
565 name
=name
, src_loc_at
=src_loc_at
+1)
566 self
._ios
.append(ioconn
)
569 def _elaborate_ios(self
, *, m
, capture
, shift
, update
, bd2io
, bd2core
):
570 length
= sum(IOConn
.lengths
[conn
._iotype
] for conn
in self
._ios
)
571 # note: the starting points where each IOConn is placed into
572 # the Shift Register depends *specifically* on the type (parameters)
573 # of each IOConn, and therefore on all IOConn(s) that came before it
574 # [prior calls to add_io]. this function consistently follows
575 # the exact same pattern in the exact same sequence every time,
576 # to compute consistent offsets. developers must do the same:
577 # note that each length depends on *all* parameters:
578 # IOtype, banksel, pullup *and* pulldown.
580 # pre-compute the length of the IO shift registers needed.
581 # relies on Record.len() returning the total bit-width including
583 length
= sum(len(conn
) for conn
in self
._ios
)
587 io_sr
= Signal(length
)
588 io_bd
= Signal(length
)
590 # Boundary scan "capture" mode. makes I/O status available via SR
594 for conn
in self
._ios
:
595 # in appropriate sequence: In/TriOut has pad.i,
596 # Out.InTriOut has everything, Out and TriOut have core.o
597 if conn
._iotype
in [IOType
.In
, IOType
.InTriOut
]:
598 iol
.append(conn
.pad
.i
)
599 if conn
._iotype
in [IOType
.Out
, IOType
.InTriOut
]:
600 iol
.append(conn
.core
.o
)
601 if conn
._iotype
in [IOType
.TriOut
, IOType
.InTriOut
]:
602 iol
.append(conn
.core
.oe
)
603 # now also banksel, pullup and pulldown from core are added
604 if conn
._banksel
!= 0:
605 iol
.append(conn
.core
.sel
)
608 iol
.append(conn
.core
.pu
)
611 iol
.append(conn
.core
.pd
)
613 # help with length double-check
614 idx
+= IOConn
.lengths
[conn
._iotype
] # fails if wrong type
615 assert idx
== length
, "Internal error, length mismatch"
616 m
.d
.posjtag
+= io_sr
.eq(Cat(*iol
)) # assigns all io_sr in one hit
618 # "Shift" mode (sends out captured data on tdo, sets incoming from tdi)
620 m
.d
.posjtag
+= io_sr
.eq(Cat(self
.bus
.tdi
, io_sr
[:-1]))
624 m
.d
.negjtag
+= io_bd
.eq(io_sr
)
626 # sets up IO (pad<->core) or in testing mode depending on requested
627 # mode, via Muxes controlled by bd2core and bd2io
628 # for each IOConn, the number of bits needed from io_bd will vary
629 # and is computed on-the-fly, here. it is up to the developer to
630 # keep track of where each IO pad configuration starts and ends
631 # in the Shift Register (TODO: provide a dictionary of starting points)
633 for conn
in self
._ios
:
634 # mux the I/O/OE depending on IOType
635 if conn
._iotype
== IOType
.In
:
636 m
.d
.comb
+= conn
.core
.i
.eq(Mux(bd2core
, io_bd
[idx
], conn
.pad
.i
))
638 elif conn
._iotype
== IOType
.Out
:
639 m
.d
.comb
+= conn
.pad
.o
.eq(Mux(bd2io
, io_bd
[idx
], conn
.core
.o
))
641 elif conn
._iotype
== IOType
.TriOut
:
643 conn
.pad
.o
.eq(Mux(bd2io
, io_bd
[idx
], conn
.core
.o
)),
644 conn
.pad
.oe
.eq(Mux(bd2io
, io_bd
[idx
+1], conn
.core
.oe
)),
647 elif conn
._iotype
== IOType
.InTriOut
:
649 conn
.core
.i
.eq(Mux(bd2core
, io_bd
[idx
], conn
.pad
.i
)),
650 conn
.pad
.o
.eq(Mux(bd2io
, io_bd
[idx
+1], conn
.core
.o
)),
651 conn
.pad
.oe
.eq(Mux(bd2io
, io_bd
[idx
+2], conn
.core
.oe
)),
655 raise("Internal error")
656 # optional mux of banksel, pullup and pulldown. note that idx
657 # advances each time, so that io_bd[idx] comes from the right point
659 if conn
._banksel
!= 0:
660 s
, e
= (idx
, idx
+conn
._banksel
) # banksel can be multi-bit
661 comb
+= conn
.pad
.sel
.eq(Mux(bd2io
, io_bd
[s
:e
], conn
.core
.sel
))
664 comb
+= conn
.pad
.pu
.eq(Mux(bd2io
, io_bd
[idx
], conn
.core
.pu
))
667 comb
+= conn
.pad
.pd
.eq(Mux(bd2io
, io_bd
[idx
], conn
.core
.pd
))
669 assert idx
== length
, "Internal error"
671 # return the last bit of the shift register, for output on tdo
674 def add_shiftreg(self
, *, ircode
, length
, domain
="sync", name
=None,
676 """Add a shift register to the JTAG interface
679 - ircode: code(s) for the IR; int or sequence of ints. In the latter
680 case this shiftreg is shared between different IR codes.
681 - length: the length of the shift register
682 - domain: the domain on which the signal will be used"""
688 ir_it
= ircodes
= (ircode
,)
689 for _ircode
in ir_it
:
690 if not isinstance(_ircode
, int) or _ircode
<= 0:
691 raise ValueError("IR code '{}' is not an int "
692 "greater than 0".format(_ircode
))
693 if _ircode
in self
._ircodes
:
694 raise ValueError("IR code '{}' already taken".format(_ircode
))
696 self
._ircodes
.extend(ircodes
)
699 name
= "sr{}".format(len(self
._srs
))
700 sr
= ShiftReg(sr_length
=length
, cmds
=len(ircodes
), name
=name
,
701 src_loc_at
=src_loc_at
+1)
702 self
._srs
.append((ircodes
, domain
, sr
))
706 def _elaborate_shiftregs(self
, m
, capture
, shift
, update
, ir
, tdo_jtag
):
707 # tdos is tuple of (tdo, tdo_en) for each shiftreg
709 for ircodes
, domain
, sr
in self
._srs
:
710 reg
= Signal(len(sr
.o
), name
=sr
.name
+"_reg")
711 m
.d
.comb
+= sr
.o
.eq(reg
)
713 isir
= Signal(len(ircodes
), name
=sr
.name
+"_isir")
714 sr_capture
= Signal(name
=sr
.name
+"_capture")
715 sr_shift
= Signal(name
=sr
.name
+"_shift")
716 sr_update
= Signal(name
=sr
.name
+"_update")
718 isir
.eq(Cat(ir
== ircode
for ircode
in ircodes
)),
719 sr_capture
.eq((isir
!= 0) & capture
),
720 sr_shift
.eq((isir
!= 0) & shift
),
721 sr_update
.eq((isir
!= 0) & update
),
724 # update signal is on the JTAG clockdomain, sr.oe is on `domain`
725 # clockdomain latch update in `domain` clockdomain and see when
726 # it has falling edge.
727 # At that edge put isir in sr.oe for one `domain` clockdomain
728 # Using this custom sync <> JTAG domain synchronization avoids
729 # the use of more generic but also higher latency CDC solutions
730 # like FFSynchronizer.
731 update_core
= Signal(name
=sr
.name
+"_update_core")
732 update_core_prev
= Signal(name
=sr
.name
+"_update_core_prev")
734 update_core
.eq(sr_update
), # This is CDC from JTAG domain
736 update_core_prev
.eq(update_core
)
738 with m
.If(update_core_prev
& ~update_core
):
739 # Falling edge of update
740 m
.d
[domain
] += sr
.oe
.eq(isir
)
742 m
.d
[domain
] += sr
.oe
.eq(0)
745 m
.d
.posjtag
+= reg
.eq(Cat(reg
[1:], self
.bus
.tdi
))
746 with m
.If(sr_capture
):
747 m
.d
.posjtag
+= reg
.eq(sr
.i
)
749 # tdo = reg[0], tdo_en = shift
750 tdos
.append((reg
[0], sr_shift
))
753 # Assign the right tdo to the bus tdo
754 for i
, (tdo
, tdo_en
) in enumerate(tdos
):
757 m
.d
.comb
+= self
.bus
.tdo
.eq(tdo
)
760 m
.d
.comb
+= self
.bus
.tdo
.eq(tdo
)
764 m
.d
.comb
+= self
.bus
.tdo
.eq(tdo_jtag
)
766 # Always connect tdo_jtag to
767 m
.d
.comb
+= self
.bus
.tdo
.eq(tdo_jtag
)
770 def add_wishbone(self
, *, ircodes
, address_width
, data_width
,
771 granularity
=None, domain
="sync", features
=None,
772 name
=None, src_loc_at
=0):
773 """Add a wishbone interface
775 In order to allow high JTAG clock speed, data will be cached.
776 This means that if data is output the value of the next address
777 will be read automatically.
781 ircodes: sequence of three integer for the JTAG IR codes;
782 they represent resp. WBADDR, WBREAD and WBREADWRITE. First code
783 has a shift register of length 'address_width', the two other codes
784 share a shift register of length data_width.
785 address_width: width of the address
786 data_width: width of the data
787 features: features required. defaults to stall, lock, err, rty
790 wb: nmigen_soc.wishbone.bus.Interface
791 The Wishbone interface, is pipelined and has stall field.
793 if len(ircodes
) != 3:
794 raise ValueError("3 IR Codes have to be provided")
797 features
={"stall", "lock", "err", "rty"}
799 name
= "wb" + str(len(self
._wbs
))
800 sr_addr
= self
.add_shiftreg(
801 ircode
=ircodes
[0], length
=address_width
, domain
=domain
,
804 sr_data
= self
.add_shiftreg(
805 ircode
=ircodes
[1:], length
=data_width
, domain
=domain
,
809 wb
= WishboneInterface(data_width
=data_width
, addr_width
=address_width
,
810 granularity
=granularity
, features
=features
,
811 name
=name
, src_loc_at
=src_loc_at
+1)
813 self
._wbs
.append((sr_addr
, sr_data
, wb
, domain
))
817 def _elaborate_wishbones(self
, m
):
818 for sr_addr
, sr_data
, wb
, domain
in self
._wbs
:
819 m
.d
.comb
+= sr_addr
.i
.eq(wb
.adr
)
821 if hasattr(wb
, "sel"):
823 m
.d
.comb
+= [s
.eq(1) for s
in wb
.sel
]
825 with m
.FSM(domain
=domain
) as fsm
:
826 with m
.State("IDLE"):
827 with m
.If(sr_addr
.oe
): # WBADDR code
828 m
.d
[domain
] += wb
.adr
.eq(sr_addr
.o
)
830 with m
.Elif(sr_data
.oe
[0]): # WBREAD code
832 m
.d
[domain
] += wb
.adr
.eq(wb
.adr
+ 1)
834 with m
.Elif(sr_data
.oe
[1]): # WBWRITE code
835 m
.d
[domain
] += wb
.dat_w
.eq(sr_data
.o
)
837 with m
.State("READ"):
838 if not hasattr(wb
, "stall"):
841 with m
.If(~wb
.stall
):
843 with m
.State("READACK"):
845 # Store read data in sr_data.i
846 # and keep it there til next read.
847 # This is enough to synchronize between sync and JTAG
848 # clock domain and no higher latency solutions like
849 # FFSynchronizer is needed.
850 m
.d
[domain
] += sr_data
.i
.eq(wb
.dat_r
)
852 with m
.State("WRITEREAD"):
853 if not hasattr(wb
, "stall"):
854 m
.next
= "WRITEREADACK"
856 with m
.If(~wb
.stall
):
857 m
.next
= "WRITEREADACK"
858 with m
.State("WRITEREADACK"):
860 m
.d
[domain
] += wb
.adr
.eq(wb
.adr
+ 1)
863 if hasattr(wb
, "stall"):
864 m
.d
.comb
+= wb
.stb
.eq(fsm
.ongoing("READ") |
865 fsm
.ongoing("WRITEREAD"))
866 m
.d
.comb
+= wb
.we
.eq(fsm
.ongoing("WRITEREAD"))
868 # non-stall is single-cycle (litex), must assert stb
870 m
.d
.comb
+= wb
.stb
.eq(fsm
.ongoing("READ") |
871 fsm
.ongoing("WRITEREAD") |
872 fsm
.ongoing("READACK") |
873 fsm
.ongoing("WRITEREADACK"))
874 m
.d
.comb
+= wb
.we
.eq(fsm
.ongoing("WRITEREAD") |
875 fsm
.ongoing("WRITEREADACK"))
876 m
.d
.comb
+= wb
.cyc
.eq(~fsm
.ongoing("IDLE"))