f5bfd8cc676e02f0e9e53b882a41c2cac25e6bf7
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, banksel
=0,
551 pullup
=False, pulldown
=False,
553 """Add a io cell to the boundary scan chain
556 - iotype: :class:`IOType` enum.
562 name
= "ioconn" + str(len(self
._ios
))
564 ioconn
= IOConn(iotype
=iotype
, banksel
=banksel
,
565 pullup
=pullup
, pulldown
=pulldown
,
566 name
=name
, src_loc_at
=src_loc_at
+1)
567 self
._ios
.append(ioconn
)
570 def _elaborate_ios(self
, *, m
, capture
, shift
, update
, bd2io
, bd2core
):
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.
582 for conn
in self
._ios
:
583 length
+= IOConn
.lengths
[conn
._iotype
] + conn
._banksel
591 io_sr
= Signal(length
)
592 io_bd
= Signal(length
)
594 # Boundary scan "capture" mode. makes I/O status available via SR
598 for conn
in self
._ios
:
599 # in appropriate sequence: In/TriOut has pad.i,
600 # Out.InTriOut has everything, Out and TriOut have core.o
601 if conn
._iotype
in [IOType
.In
, IOType
.InTriOut
]:
602 iol
.append(conn
.pad
.i
)
603 if conn
._iotype
in [IOType
.Out
, IOType
.InTriOut
]:
604 iol
.append(conn
.core
.o
)
605 if conn
._iotype
in [IOType
.TriOut
, IOType
.InTriOut
]:
606 iol
.append(conn
.core
.oe
)
607 # now also banksel, pullup and pulldown from core are added
608 if conn
._banksel
!= 0:
609 iol
.append(conn
.core
.sel
)
612 iol
.append(conn
.core
.pu
)
615 iol
.append(conn
.core
.pd
)
617 # help with length double-check
618 idx
+= IOConn
.lengths
[conn
._iotype
] # fails if wrong type
619 assert idx
== length
, "Internal error, length mismatch"
620 m
.d
.posjtag
+= io_sr
.eq(Cat(*iol
)) # assigns all io_sr in one hit
622 # "Shift" mode (sends out captured data on tdo, sets incoming from tdi)
624 m
.d
.posjtag
+= io_sr
.eq(Cat(self
.bus
.tdi
, io_sr
[:-1]))
628 m
.d
.negjtag
+= io_bd
.eq(io_sr
)
630 # sets up IO (pad<->core) or in testing mode depending on requested
631 # mode, via Muxes controlled by bd2core and bd2io
632 # for each IOConn, the number of bits needed from io_bd will vary
633 # and is computed on-the-fly, here. it is up to the developer to
634 # keep track of where each IO pad configuration starts and ends
635 # in the Shift Register (TODO: provide a dictionary of starting points)
637 for conn
in self
._ios
:
638 # mux the I/O/OE depending on IOType
639 if conn
._iotype
== IOType
.In
:
640 m
.d
.comb
+= conn
.core
.i
.eq(Mux(bd2core
, io_bd
[idx
], conn
.pad
.i
))
642 elif conn
._iotype
== IOType
.Out
:
643 m
.d
.comb
+= conn
.pad
.o
.eq(Mux(bd2io
, io_bd
[idx
], conn
.core
.o
))
645 elif conn
._iotype
== IOType
.TriOut
:
647 conn
.pad
.o
.eq(Mux(bd2io
, io_bd
[idx
], conn
.core
.o
)),
648 conn
.pad
.oe
.eq(Mux(bd2io
, io_bd
[idx
+1], conn
.core
.oe
)),
651 elif conn
._iotype
== IOType
.InTriOut
:
653 conn
.core
.i
.eq(Mux(bd2core
, io_bd
[idx
], conn
.pad
.i
)),
654 conn
.pad
.o
.eq(Mux(bd2io
, io_bd
[idx
+1], conn
.core
.o
)),
655 conn
.pad
.oe
.eq(Mux(bd2io
, io_bd
[idx
+2], conn
.core
.oe
)),
659 raise("Internal error")
660 # optional mux of banksel, pullup and pulldown. note that idx
661 # advances each time, so that io_bd[idx] comes from the right point
663 if conn
._banksel
!= 0:
664 s
, e
= (idx
, idx
+conn
._banksel
) # banksel can be multi-bit
665 comb
+= conn
.pad
.sel
.eq(Mux(bd2io
, io_bd
[s
:e
], conn
.core
.sel
))
668 comb
+= conn
.pad
.pu
.eq(Mux(bd2io
, io_bd
[idx
], conn
.core
.pu
))
671 comb
+= conn
.pad
.pd
.eq(Mux(bd2io
, io_bd
[idx
], conn
.core
.pd
))
673 assert idx
== length
, "Internal error"
675 # return the last bit of the shift register, for output on tdo
678 def add_shiftreg(self
, *, ircode
, length
, domain
="sync", name
=None,
680 """Add a shift register to the JTAG interface
683 - ircode: code(s) for the IR; int or sequence of ints. In the latter
684 case this shiftreg is shared between different IR codes.
685 - length: the length of the shift register
686 - domain: the domain on which the signal will be used"""
692 ir_it
= ircodes
= (ircode
,)
693 for _ircode
in ir_it
:
694 if not isinstance(_ircode
, int) or _ircode
<= 0:
695 raise ValueError("IR code '{}' is not an int "
696 "greater than 0".format(_ircode
))
697 if _ircode
in self
._ircodes
:
698 raise ValueError("IR code '{}' already taken".format(_ircode
))
700 self
._ircodes
.extend(ircodes
)
703 name
= "sr{}".format(len(self
._srs
))
704 sr
= ShiftReg(sr_length
=length
, cmds
=len(ircodes
), name
=name
,
705 src_loc_at
=src_loc_at
+1)
706 self
._srs
.append((ircodes
, domain
, sr
))
710 def _elaborate_shiftregs(self
, m
, capture
, shift
, update
, ir
, tdo_jtag
):
711 # tdos is tuple of (tdo, tdo_en) for each shiftreg
713 for ircodes
, domain
, sr
in self
._srs
:
714 reg
= Signal(len(sr
.o
), name
=sr
.name
+"_reg")
715 m
.d
.comb
+= sr
.o
.eq(reg
)
717 isir
= Signal(len(ircodes
), name
=sr
.name
+"_isir")
718 sr_capture
= Signal(name
=sr
.name
+"_capture")
719 sr_shift
= Signal(name
=sr
.name
+"_shift")
720 sr_update
= Signal(name
=sr
.name
+"_update")
722 isir
.eq(Cat(ir
== ircode
for ircode
in ircodes
)),
723 sr_capture
.eq((isir
!= 0) & capture
),
724 sr_shift
.eq((isir
!= 0) & shift
),
725 sr_update
.eq((isir
!= 0) & update
),
728 # update signal is on the JTAG clockdomain, sr.oe is on `domain`
729 # clockdomain latch update in `domain` clockdomain and see when
730 # it has falling edge.
731 # At that edge put isir in sr.oe for one `domain` clockdomain
732 # Using this custom sync <> JTAG domain synchronization avoids
733 # the use of more generic but also higher latency CDC solutions
734 # like FFSynchronizer.
735 update_core
= Signal(name
=sr
.name
+"_update_core")
736 update_core_prev
= Signal(name
=sr
.name
+"_update_core_prev")
738 update_core
.eq(sr_update
), # This is CDC from JTAG domain
740 update_core_prev
.eq(update_core
)
742 with m
.If(update_core_prev
& ~update_core
):
743 # Falling edge of update
744 m
.d
[domain
] += sr
.oe
.eq(isir
)
746 m
.d
[domain
] += sr
.oe
.eq(0)
749 m
.d
.posjtag
+= reg
.eq(Cat(reg
[1:], self
.bus
.tdi
))
750 with m
.If(sr_capture
):
751 m
.d
.posjtag
+= reg
.eq(sr
.i
)
753 # tdo = reg[0], tdo_en = shift
754 tdos
.append((reg
[0], sr_shift
))
756 # Assign the right tdo to the bus tdo
757 for i
, (tdo
, tdo_en
) in enumerate(tdos
):
760 m
.d
.comb
+= self
.bus
.tdo
.eq(tdo
)
763 m
.d
.comb
+= self
.bus
.tdo
.eq(tdo
)
767 m
.d
.comb
+= self
.bus
.tdo
.eq(tdo_jtag
)
769 # Always connect tdo_jtag to
770 m
.d
.comb
+= self
.bus
.tdo
.eq(tdo_jtag
)
772 def add_wishbone(self
, *, ircodes
, address_width
, data_width
,
773 granularity
=None, domain
="sync", features
=None,
774 name
=None, src_loc_at
=0):
775 """Add a wishbone interface
777 In order to allow high JTAG clock speed, data will be cached.
778 This means that if data is output the value of the next address
779 will be read automatically.
783 ircodes: sequence of three integer for the JTAG IR codes;
784 they represent resp. WBADDR, WBREAD and WBREADWRITE. First code
785 has a shift register of length 'address_width', the two other codes
786 share a shift register of length data_width.
787 address_width: width of the address
788 data_width: width of the data
789 features: features required. defaults to stall, lock, err, rty
792 wb: nmigen_soc.wishbone.bus.Interface
793 The Wishbone interface, is pipelined and has stall field.
795 if len(ircodes
) != 3:
796 raise ValueError("3 IR Codes have to be provided")
799 features
={"stall", "lock", "err", "rty"}
801 name
= "wb" + str(len(self
._wbs
))
802 sr_addr
= self
.add_shiftreg(
803 ircode
=ircodes
[0], length
=address_width
, domain
=domain
,
806 sr_data
= self
.add_shiftreg(
807 ircode
=ircodes
[1:], length
=data_width
, domain
=domain
,
811 wb
= WishboneInterface(data_width
=data_width
, addr_width
=address_width
,
812 granularity
=granularity
, features
=features
,
813 name
=name
, src_loc_at
=src_loc_at
+1)
815 self
._wbs
.append((sr_addr
, sr_data
, wb
, domain
))
819 def _elaborate_wishbones(self
, m
):
820 for sr_addr
, sr_data
, wb
, domain
in self
._wbs
:
821 m
.d
.comb
+= sr_addr
.i
.eq(wb
.adr
)
823 if hasattr(wb
, "sel"):
825 m
.d
.comb
+= [s
.eq(1) for s
in wb
.sel
]
827 with m
.FSM(domain
=domain
) as fsm
:
828 with m
.State("IDLE"):
829 with m
.If(sr_addr
.oe
): # WBADDR code
830 m
.d
[domain
] += wb
.adr
.eq(sr_addr
.o
)
832 with m
.Elif(sr_data
.oe
[0]): # WBREAD code
834 m
.d
[domain
] += wb
.adr
.eq(wb
.adr
+ 1)
836 with m
.Elif(sr_data
.oe
[1]): # WBWRITE code
837 m
.d
[domain
] += wb
.dat_w
.eq(sr_data
.o
)
839 with m
.State("READ"):
840 if not hasattr(wb
, "stall"):
843 with m
.If(~wb
.stall
):
845 with m
.State("READACK"):
847 # Store read data in sr_data.i
848 # and keep it there til next read.
849 # This is enough to synchronize between sync and JTAG
850 # clock domain and no higher latency solutions like
851 # FFSynchronizer is needed.
852 m
.d
[domain
] += sr_data
.i
.eq(wb
.dat_r
)
854 with m
.State("WRITEREAD"):
855 if not hasattr(wb
, "stall"):
856 m
.next
= "WRITEREADACK"
858 with m
.If(~wb
.stall
):
859 m
.next
= "WRITEREADACK"
860 with m
.State("WRITEREADACK"):
862 m
.d
[domain
] += wb
.adr
.eq(wb
.adr
+ 1)
865 if hasattr(wb
, "stall"):
866 m
.d
.comb
+= wb
.stb
.eq(fsm
.ongoing("READ") |
867 fsm
.ongoing("WRITEREAD"))
868 m
.d
.comb
+= wb
.we
.eq(fsm
.ongoing("WRITEREAD"))
870 # non-stall is single-cycle (litex), must assert stb
872 m
.d
.comb
+= wb
.stb
.eq(fsm
.ongoing("READ") |
873 fsm
.ongoing("WRITEREAD") |
874 fsm
.ongoing("READACK") |
875 fsm
.ongoing("WRITEREADACK"))
876 m
.d
.comb
+= wb
.we
.eq(fsm
.ongoing("WRITEREAD") |
877 fsm
.ongoing("WRITEREADACK"))
878 m
.d
.comb
+= wb
.cyc
.eq(~fsm
.ongoing("IDLE"))