-#!/bin/env python3
+#!/usr/bin/env python3
import os, textwrap
from enum import Enum, auto
-from nmigen import *
-from nmigen.build import *
-from nmigen.lib.io import *
+from nmigen import (Elaboratable, Signal, Module, ClockDomain, Cat, Record,
+ Const, Mux)
from nmigen.hdl.rec import Direction, Layout
from nmigen.tracer import get_var_name
self.shift = Signal()
self.update = Signal()
+ # JTAG uses both edges of the incoming clock (TCK). set them up here
self.posjtag = ClockDomain("posjtag", local=True)
self.negjtag = ClockDomain("negjtag", local=True, clk_edge="neg")
return m
+
class _IRBlock(Elaboratable):
"""TAP subblock for handling the IR shift register"""
def __init__(self, *, ir_width, cmd_idcode,
return m
+
class IOType(Enum):
In = auto()
Out = auto()
TriOut = auto()
InTriOut = auto()
+
class IOConn(Record):
"""TAP subblock representing the interface for an JTAG IO cell.
It contains signal to connect to the core and to the pad
self._iotype = iotype
+
class _IDBypassBlock(Elaboratable):
"""TAP subblock for the ID shift register"""
def __init__(self, *, manufacturer_id, part_number, version,
self._srs = []
self._wbs = []
-
def elaborate(self, platform):
m = Module()
m.domains.posjtag = fsm.posjtag
m.domains.negjtag = fsm.negjtag
+ # IR block
select_ir = fsm.isir
m.submodules._irblock = irblock = _IRBlock(
ir_width=ir_width, cmd_idcode=cmd_idcode, tdi=self.bus.tdi,
)
ir = irblock.ir
+ # ID block
select_id = fsm.isdr & ((ir == cmd_idcode) | (ir == cmd_bypass))
m.submodules._idblock = idblock = _IDBypassBlock(
manufacturer_id=self._manufacturer_id, part_number=self._part_number,
name=self.name+"_id",
)
+ # IO (Boundary scan) block
io_capture = Signal()
io_shift = Signal()
io_update = Signal()
bd2io=io_bd2io, bd2core=io_bd2core,
)
+ # chain tdo: select as appropriate, to go into into shiftregs
tdo = Signal(name=self.name+"_tdo")
with m.If(select_ir):
m.d.comb += tdo.eq(irblock.tdo)
with m.Elif(select_io):
m.d.comb += tdo.eq(io_tdo)
+ # shiftregs block
self._elaborate_shiftregs(
m, capture=fsm.capture, shift=fsm.shift, update=fsm.update,
ir=irblock.ir, tdo_jtag=tdo
)
+
+ # wishbone
self._elaborate_wishbones(m)
return m
IOType.InTriOut: 3,
}
length = sum(connlength[conn._iotype] for conn in self._ios)
+ if length == 0:
+ return self.bus.tdi
io_sr = Signal(length)
io_bd = Signal(length)
+ # Boundary scan "capture" mode. makes I/O status available via SR
with m.If(capture):
idx = 0
for conn in self._ios:
else:
raise("Internal error")
assert idx == length, "Internal error"
+
+ # "Shift" mode (sends out captured data on tdo, sets incoming from tdi)
with m.Elif(shift):
m.d.posjtag += io_sr.eq(Cat(self.bus.tdi, io_sr[:-1]))
+
+ # "Update" mode
with m.Elif(update):
m.d.negjtag += io_bd.eq(io_sr)
+ # sets up IO (pad<->core) or in testing mode depending on requested
+ # mode, via Muxes controlled by bd2core and bd2io
idx = 0
for conn in self._ios:
if conn._iotype == IOType.In:
return io_sr[-1]
-
def add_shiftreg(self, *, ircode, length, domain="sync", name=None, src_loc_at=0):
"""Add a shift register to the JTAG interface