b2bcf818f8a3a2bc5b9fe62bfa5dafd628b8321b
5 from nmigen
.build
import *
6 from nmigen
.lib
.io
import *
7 from nmigen
.hdl
.rec
import Direction
8 from nmigen
.tracer
import get_var_name
10 from nmigen_soc
.wishbone
import Interface
as WishboneInterface
12 from .bus
import Interface
19 class ShiftReg(Record
):
20 """Object with interface for extra shift registers on a TAP.
26 The number of corresponding JTAG instructions
28 This object is normally only allocated and returned from ``TAP.add_shiftreg``
29 It is a Record subclass.
33 i: length=sr_length, FANIN
34 The input data sampled during capture state of the TAP
35 ie: length=cmds, FANOUT
36 Indicates that data is to be sampled by the JTAG TAP and
37 should be held stable. The bit indicates the corresponding
38 instruction for which data is asked.
39 This signal is kept high for a whole JTAG TAP clock cycle
40 and may thus be kept higher for more than one clock cycle
41 on the domain where ShiftReg is used.
42 The JTAG protocol does not allow insertion of wait states
43 so data need to be provided before ie goes down. The speed
44 of the response will determine the max. frequency for the
46 o: length=sr_length, FANOUT
47 The value of the shift register.
48 oe: length=cmds, FANOUT
49 Indicates that output needs to be sampled downstream because
50 JTAG TAP in in the Update state. The bit indicated the corresponding
51 instruction. The bit is only kept high for one clock cycle.
53 def __init__(self
, *, sr_length
, cmds
=1, name
=None, src_loc_at
=0):
55 ("i", sr_length
, Direction
.FANIN
),
56 ("ie", cmds
, Direction
.FANOUT
),
57 ("o", sr_length
, Direction
.FANOUT
),
58 ("oe", cmds
, Direction
.FANOUT
),
60 super().__init
__(layout
, name
=name
, src_loc_at
=src_loc_at
+1)
63 class TAP(Elaboratable
):
66 def _add_files(platform
, prefix
):
67 d
= os
.path
.realpath("{dir}{sep}{par}{sep}{par}{sep}vhdl{sep}jtag".format(
68 dir=os
.path
.dirname(__file__
), sep
=os
.path
.sep
, par
=os
.path
.pardir
72 "c4m_jtag_idblock.vhdl",
73 "c4m_jtag_iocell.vhdl",
74 "c4m_jtag_ioblock.vhdl",
75 "c4m_jtag_irblock.vhdl",
76 "c4m_jtag_tap_fsm.vhdl",
77 "c4m_jtag_tap_controller.vhdl",
79 f
= open(d
+ fname
, "r")
80 platform
.add_file(prefix
+ fname
, f
)
83 _controller_templ
= textwrap
.dedent(r
"""
85 use ieee.std_logic_1164.ALL;
87 use work.c4m_jtag.ALL;
98 -- The FSM state indicators
100 CAPTURE: out std_logic;
101 SHIFT: out std_logic;
102 UPDATE: out std_logic;
104 -- The Instruction Register
105 IR: out std_logic_vector({ir_width}-1 downto 0);
107 -- The I/O access ports
108 CORE_IN: out std_logic_vector({ios}-1 downto 0);
109 CORE_EN: in std_logic_vector({ios}-1 downto 0);
110 CORE_OUT: in std_logic_vector({ios}-1 downto 0);
112 -- The pad connections
113 PAD_IN: in std_logic_vector({ios}-1 downto 0);
114 PAD_EN: out std_logic_vector({ios}-1 downto 0);
115 PAD_OUT: out std_logic_vector({ios}-1 downto 0)
119 architecture rtl of {name} is
121 jtag : c4m_jtag_tap_controller
124 IR_WIDTH => {ir_width},
126 MANUFACTURER => "{manufacturer:011b}",
127 PART_NUMBER => "{part:016b}",
128 VERSION => "{version:04b}"
143 CORE_OUT => CORE_OUT,
148 end architecture rtl;
152 def _add_instance(cls
, platform
, prefix
, *, ir_width
, ios
, manufacturer
, part
, version
):
153 name
= "jtag_controller_i{}".format(cls
._cell
_inst
)
157 "{}{}.vhdl".format(prefix
, name
),
158 cls
._controller
_templ
.format(
159 name
=name
, ir_width
=ir_width
, ios
=ios
,
160 manufacturer
=manufacturer
, part
=part
, version
=version
,
168 self
, io_count
, *, with_reset
=False, ir_width
=None,
169 manufacturer_id
=Const(0b10001111111, 11), part_number
=Const(1, 16),
171 name
=None, src_loc_at
=0
173 assert(isinstance(io_count
, int) and io_count
> 0)
174 assert((ir_width
is None) or (isinstance(ir_width
, int) and ir_width
>= 2))
175 assert(len(version
) == 4)
178 name
= get_var_name(depth
=src_loc_at
+2, default
="TAP")
180 self
.bus
= Interface(with_reset
=with_reset
, name
=self
.name
+"_bus",
181 src_loc_at
=src_loc_at
+1)
183 # TODO: Handle IOs with different directions
185 Pin(1, "io", name
=name
+"_coreio"+str(i
), src_loc_at
=src_loc_at
+1)
186 for i
in range(io_count
)
187 ) # Signals to use for core
189 Pin(1, "io", name
=name
+"_padio"+str(i
), src_loc_at
=src_loc_at
+1)
190 for i
in range(io_count
)
191 ) # Signals going to IO pads
195 self
._io
_count
= io_count
196 self
._ir
_width
= ir_width
197 self
._manufacturer
_id
= manufacturer_id
198 self
._part
_number
= part_number
199 self
._version
= version
201 self
._ircodes
= [0, 1, 2] # Already taken codes, all ones added at the end
207 def elaborate(self
, platform
):
208 self
.__class
__._add
_files
(platform
, "jtag" + os
.path
.sep
)
212 # Determine ir_width if not fixed.
213 ir_max
= max(self
._ircodes
) + 1 # One extra code needed with all ones
214 ir_width
= len("{:b}".format(ir_max
))
215 if self
._ir
_width
is not None:
216 assert self
._ir
_width
>= ir_width
, "Specified JTAG IR width not big enough for allocated shiift registers"
217 ir_width
= self
._ir
_width
219 cell
= self
.__class
__._add
_instance
(
220 platform
, "jtag" + os
.path
.sep
, ir_width
=ir_width
, ios
=self
._io
_count
,
221 manufacturer
=self
._manufacturer
_id
.value
, part
=self
._part
_number
.value
,
222 version
=self
._version
.value
,
236 m
.d
.comb
+= trst_n
.eq(~self
.bus
.trst
if hasattr(self
.bus
, "trst") else Const(1))
238 core_i
= Cat(pin
.i
for pin
in self
.core
)
239 core_o
= Cat(pin
.o
for pin
in self
.core
)
240 core_oe
= Cat(pin
.oe
for pin
in self
.core
)
241 pad_i
= Cat(pin
.i
for pin
in self
.pad
)
242 pad_o
= Cat(pin
.o
for pin
in self
.pad
)
243 pad_oe
= Cat(pin
.oe
for pin
in self
.pad
)
245 m
.submodules
.tap
= Instance(cell
,
252 o_CAPTURE
=sigs
.capture
,
254 o_UPDATE
=sigs
.update
,
264 # Own clock domain using TCK as clock signal
265 m
.domains
.jtag
= jtag_cd
= ClockDomain(name
="jtag", local
=True)
267 jtag_cd
.clk
.eq(self
.bus
.tck
),
268 jtag_cd
.rst
.eq(reset
),
271 self
._elaborate
_shiftregs
(m
, sigs
)
272 self
._elaborate
_wishbones
(m
)
277 def add_shiftreg(self
, *, ircode
, length
, domain
="sync", name
=None, src_loc_at
=0):
278 """Add a shift register to the JTAG interface
281 - ircode: code(s) for the IR; int or sequence of ints. In the latter case this
282 shiftreg is shared between different IR codes.
283 - length: the length of the shift register
284 - domain: the domain on which the signal will be used"""
290 ir_it
= ircodes
= (ircode
,)
291 for _ircode
in ir_it
:
292 if not isinstance(_ircode
, int) or _ircode
<= 0:
293 raise ValueError("IR code '{}' is not an int greater than 0".format(_ircode
))
294 if _ircode
in self
._ircodes
:
295 raise ValueError("IR code '{}' already taken".format(_ircode
))
297 self
._ircodes
.extend(ircodes
)
300 name
= self
.name
+ "_sr{}".format(len(self
._srs
))
301 sr
= ShiftReg(sr_length
=length
, cmds
=len(ircodes
), name
=name
, src_loc_at
=src_loc_at
+1)
302 self
._srs
.append((ircodes
, domain
, sr
))
306 def _elaborate_shiftregs(self
, m
, sigs
):
307 # tdos is tuple of (tdo, tdo_en) for each shiftreg
309 for ircodes
, domain
, sr
in self
._srs
:
310 reg
= Signal(len(sr
.o
), name
=sr
.name
+"_reg")
311 m
.d
.comb
+= sr
.o
.eq(reg
)
313 isir
= Signal(len(ircodes
), name
=sr
.name
+"_isir")
314 capture
= Signal(name
=sr
.name
+"_capture")
315 shift
= Signal(name
=sr
.name
+"_shift")
316 update
= Signal(name
=sr
.name
+"_update")
318 isir
.eq(Cat(sigs
.ir
== ircode
for ircode
in ircodes
)),
319 capture
.eq((isir
!= 0) & sigs
.capture
),
320 shift
.eq((isir
!= 0) & sigs
.shift
),
321 update
.eq((isir
!= 0) & sigs
.update
),
324 # update signal is on the JTAG clockdomain, sr.oe is on `domain` clockdomain
325 # latch update in `domain` clockdomain and see when it has falling edge.
326 # At that edge put isir in sr.oe for one `domain` clockdomain
327 update_core
= Signal(name
=sr
.name
+"_update_core")
328 update_core_prev
= Signal(name
=sr
.name
+"_update_core_prev")
330 update_core
.eq(update
), # This is CDC from JTAG domain to given domain
331 update_core_prev
.eq(update_core
)
333 with m
.If(update_core_prev
& ~update_core
== 0):
334 # Falling edge of update
335 m
.d
[domain
] += sr
.oe
.eq(isir
)
337 m
.d
[domain
] += sr
.oe
.eq(0)
340 m
.d
.jtag
+= reg
.eq(Cat(reg
[1:], self
.bus
.tdi
))
342 m
.d
.jtag
+= reg
.eq(sr
.i
)
344 # tdo = reg[0], tdo_en = shift
345 tdos
.append((reg
[0], shift
))
347 for i
, (tdo
, tdo_en
) in enumerate(tdos
):
350 m
.d
.comb
+= self
.bus
.tdo
.eq(tdo
)
353 m
.d
.comb
+= self
.bus
.tdo
.eq(tdo
)
357 m
.d
.comb
+= self
.bus
.tdo
.eq(sigs
.tdo_jtag
)
359 # Always connect tdo_jtag to
360 m
.d
.comb
+= self
.bus
.tdo
.eq(sigs
.tdo_jtag
)
363 def add_wishbone(self
, *, ircodes
, address_width
, data_width
, granularity
=None, domain
="sync"):
364 """Add a wishbone interface
366 In order to allow high JTAG clock speed, data will be cached. This means that if data is
367 output the value of the next address will be read automatically.
371 ircodes: sequence of three integer for the JTAG IR codes;
372 they represent resp. WBADDR, WBREAD and WBREADWRITE. First code
373 has a shift register of length 'address_width', the two other codes
374 share a shift register of length data_width.
375 address_width: width of the address
376 data_width: width of the data
379 wb: nmigen_soc.wishbone.bus.Interface
380 The Wishbone interface, is pipelined and has stall field.
382 if len(ircodes
) != 3:
383 raise ValueError("3 IR Codes have to be provided")
385 sr_addr
= self
.add_shiftreg(ircodes
[0], address_width
, domain
=domain
)
386 sr_data
= self
.add_shiftreg(ircodes
[1:], data_width
, domain
=domain
)
388 wb
= WishboneInterface(data_width
=data_width
, addr_width
=address_width
,
389 granularity
=granularity
, features
={"stall", "lock", "err", "rty"})
391 self
._wbs
.append((sr_addr
, sr_data
, wb
, domain
))
395 def _elaborate_wishbones(self
, m
):
396 for sr_addr
, sr_data
, wb
, domain
in self
._wbs
:
397 if hasattr(wb
, "sel"):
399 m
.d
.comb
+= [s
.eq(1) for s
in wb
.sel
]
401 with m
.FSM(domain
=domain
) as fsm
:
402 with m
.State("IDLE"):
403 with m
.If(sr_addr
.oe
): # WBADDR code
404 m
.d
[domain
] += wb
.adr
.eq(sr_addr
.o
)
406 with m
.Elif(sr_data
.oe
[0]): # WBREAD code
408 m
.d
[domain
] += wb
.adr
.eq(wb
.adr
+ 1)
410 with m
.Elif(sr_data
.oe
[1]): # WBWRITE code
411 m
.d
[domain
] += wb
.dat_w
.eq(sr_data
.o
)
413 with m
.State("READ"):
414 with m
.If(~wb
.stall
):
416 with m
.State("READACK"):
418 # Store read data in sr_data.i and keep it there til next read
419 m
.d
[domain
] += sr_data
.i
.eq(wb
.dat_r
)
421 with m
.State("WRITEREAD"):
422 with m
.If(~wb
.stall
):
423 m
.next
= "WRITEREADACK"
424 with m
.State("WRITEREADACK"):
426 m
.d
[domain
] += wb
.adr
.eq(wb
.adr
+ 1)
430 wb
.cyc
.eq(~fsm
.ongoing("IDLE")),
431 wb
.stb
.eq(fsm
.ongoing("READ") | fsm
.ongoing("WRITEREAD")),
432 wb
.we
.eq(fsm
.ongoing("WRITEREAD")),