+class _FSM(Elaboratable):
+ """TAP subblock for the FSM"""
+ def __init__(self, *, bus):
+ self.isir = Signal()
+ self.isdr = Signal()
+ self.capture = Signal()
+ self.shift = Signal()
+ self.update = Signal()
+
+ self.posjtag = ClockDomain("posjtag", local=True)
+ self.negjtag = ClockDomain("negjtag", local=True, clk_edge="neg")
+
+ self._bus = bus
+
+ def elaborate(self, platform):
+ m = Module()
+
+ rst = Signal()
+ m.d.comb += [
+ self.posjtag.clk.eq(self._bus.tck),
+ self.posjtag.rst.eq(rst),
+ self.negjtag.clk.eq(self._bus.tck),
+ self.negjtag.rst.eq(rst),
+ ]
+
+ # Make local clock domain optionally using trst of JTAG bus as reset
+ if hasattr(self._bus, "trst"):
+ m.domains.local = local = ClockDomain(local=True)
+ m.d.comb += local.rst.eq(self._bus.trst)
+ else:
+ m.domains.local = local = ClockDomain(local=True, reset_less=True)
+ m.d.comb += local.clk.eq(self._bus.tck)
+
+ with m.FSM(domain="local") as fsm:
+ with m.State("TestLogicReset"):
+ # Be sure to reset isir, isdr
+ m.d.local += [
+ self.isir.eq(0),
+ self.isdr.eq(0),
+ ]
+ with m.If(self._bus.tms == 0):
+ m.next = "RunTestIdle"
+ with m.State("RunTestIdle"):
+ # Be sure to reset isir, isdr
+ m.d.local += [
+ self.isir.eq(0),
+ self.isdr.eq(0),
+ ]
+ with m.If(self._bus.tms == 1):
+ m.next = "SelectDRScan"
+ with m.State("SelectDRScan"):
+ with m.If(self._bus.tms == 0):
+ m.d.local += self.isdr.eq(1)
+ m.next = "CaptureState"
+ with m.Else():
+ m.next = "SelectIRScan"
+ with m.State("SelectIRScan"):
+ with m.If(self._bus.tms == 0):
+ m.d.local += self.isir.eq(1)
+ m.next = "CaptureState"
+ with m.Else():
+ m.next = "TestLogicReset"
+ with m.State("CaptureState"):
+ with m.If(self._bus.tms == 0):
+ m.next = "ShiftState"
+ with m.Else():
+ m.next = "Exit1"
+ with m.State("ShiftState"):
+ with m.If(self._bus.tms == 1):
+ m.next = "Exit1"
+ with m.State("Exit1"):
+ with m.If(self._bus.tms == 0):
+ m.next = "Pause"
+ with m.Else():
+ m.next = "UpdateState"
+ with m.State("Pause"):
+ with m.If(self._bus.tms == 1):
+ m.next = "Exit2"
+ with m.State("Exit2"):
+ with m.If(self._bus.tms == 0):
+ m.next = "ShiftState"
+ with m.Else():
+ m.next = "UpdateState"
+ with m.State("UpdateState"):
+ m.d.local += [
+ self.isir.eq(0),
+ self.isdr.eq(0),
+ ]
+ with m.If(self._bus.tms == 0):
+ m.next = "RunTestIdle"
+ with m.Else():
+ m.next = "SelectDRScan"
+
+ m.d.comb += [
+ rst.eq(fsm.ongoing("TestLogicReset")),
+ self.capture.eq(fsm.ongoing("CaptureState")),
+ self.shift.eq(fsm.ongoing("ShiftState")),
+ self.update.eq(fsm.ongoing("UpdateState")),
+ ]
+
+ return m
+
+class _IRBlock(Elaboratable):
+ """TAP subblock for handling the IR shift register"""
+ def __init__(self, *, ir_width, cmd_idcode,
+ tdi, capture, shift, update,
+ name):
+ self.name = name
+ self.ir = Signal(ir_width, reset=cmd_idcode)
+ self.tdo = Signal()
+
+ self._tdi = tdi
+ self._capture = capture
+ self._shift = shift
+ self._update = update
+
+ def elaborate(self, platform):
+ m = Module()
+
+ shift_ir = Signal(len(self.ir), reset_less=True)
+
+ m.d.comb += self.tdo.eq(self.ir[0])
+ with m.If(self._capture):
+ m.d.posjtag += shift_ir.eq(self.ir)
+ with m.Elif(self._shift):
+ m.d.posjtag += shift_ir.eq(Cat(shift_ir[1:], self._tdi))
+ with m.Elif(self._update):
+ # For ir we only update it on the rising edge of clock
+ # to avoid that we already have the new ir value when still in
+ # Update state
+ m.d.posjtag += self.ir.eq(shift_ir)
+
+ 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
+
+ This object is normally only allocated and returned from ``TAP.add_io``
+ It is a Record subclass.
+
+ Attributes
+ ----------
+ core: subrecord with signals for the core
+ i: Signal(1), present only for IOType.In and IOType.InTriOut.
+ Signal input to core with pad input value.
+ o: Signal(1), present only for IOType.Out, IOType.TriOut and IOType.InTriOut.
+ Signal output from core with the pad output value.
+ oe: Signal(1), present only for IOType.TriOut and IOType.InTriOut.
+ Signal output from core with the pad output enable value.
+ pad: subrecord with for the pad
+ i: Signal(1), present only for IOType.In and IOType.InTriOut
+ Output from pad with pad input value for core.
+ o: Signal(1), present only for IOType.Out, IOType.TriOut and IOType.InTriOut.
+ Input to pad with pad output value.
+ oe: Signal(1), present only for IOType.TriOut and IOType.InTriOut.
+ Input to pad with pad output enable value.
+ """
+ @staticmethod
+ def layout(iotype):
+ sigs = []
+ if iotype in (IOType.In, IOType.InTriOut):
+ sigs.append(("i", 1))
+ if iotype in (IOType.Out, IOType.TriOut, IOType.InTriOut):
+ sigs.append(("o", 1))
+ if iotype in (IOType.TriOut, IOType.InTriOut):
+ sigs.append(("oe", 1))
+
+ return Layout((("core", sigs), ("pad", sigs)))
+
+ def __init__(self, *, iotype, name=None, src_loc_at=0):
+ super().__init__(self.__class__.layout(iotype), name=name, src_loc_at=src_loc_at+1)
+
+ self._iotype = iotype
+
+class _IDBypassBlock(Elaboratable):
+ """TAP subblock for the ID shift register"""
+ def __init__(self, *, manufacturer_id, part_number, version,
+ tdi, capture, shift, update, bypass,
+ name):
+ self.name = name
+ if not isinstance(manufacturer_id, Const) and len(manufacturer_id) != 11:
+ raise ValueError("manufacturer_id has to be Const of length 11")
+ if not isinstance(part_number, Const) and len(manufacturer_id) != 16:
+ raise ValueError("part_number has to be Const of length 16")
+ if not isinstance(version, Const) and len(version) != 4:
+ raise ValueError("version has to be Const of length 4")
+ self._id = Cat(Const(1,1), manufacturer_id, part_number, version)
+
+ self.tdo = Signal(name=name+"_tdo")
+
+ self._tdi = tdi
+ self._capture = capture
+ self._shift = shift
+ self._update = update
+ self._bypass = bypass
+
+ def elaborate(self, platform):
+ m = Module()
+
+ sr = Signal(32, reset_less=True, name=self.name+"_sr")
+
+ # Local signals for the module
+ _tdi = Signal()
+ _capture = Signal()
+ _shift = Signal()
+ _update = Signal()
+ _bypass = Signal()
+
+ m.d.comb += [
+ _tdi.eq(self._tdi),
+ _capture.eq(self._capture),
+ _shift.eq(self._shift),
+ _update.eq(self._update),
+ _bypass.eq(self._bypass),
+ self.tdo.eq(sr[0]),
+ ]
+
+ with m.If(_capture):
+ m.d.posjtag += sr.eq(self._id)
+ with m.Elif(_shift):
+ with m.If(_bypass):
+ m.d.posjtag += sr[0].eq(_tdi)
+ with m.Else():
+ m.d.posjtag += sr.eq(Cat(sr[1:], _tdi))
+
+ return m
+
+