Moved files without any changes to easily track later changes.
+++ /dev/null
--- reset JTAG interface and then IDCODE should be shifted out
-
-library ieee;
-use ieee.std_logic_1164.ALL;
-
-use work.c4m_jtag.ALL;
-
-entity bench_idcode is
-end bench_idcode;
-
-architecture rtl of bench_idcode is
- signal TCK: std_logic;
- signal TMS: std_logic;
- signal TDI: std_logic;
- signal TDO: std_logic;
- signal TRST_N: std_logic;
-
- constant CLK_PERIOD: time := 10 ns;
-
- procedure ClkCycle(
- signal CLK: out std_logic;
- CLK_PERIOD: time
- ) is
- begin
- CLK <= '0';
- wait for CLK_PERIOD/4;
- CLK <= '1';
- wait for CLK_PERIOD/2;
- CLK <= '0';
- wait for CLK_PERIOD/4;
- end ClkCycle;
-
- procedure ClkCycles(
- N: integer;
- signal CLK: out std_logic;
- CLK_PERIOD: time
- ) is
- begin
- for i in 1 to N loop
- ClkCycle(CLK, CLK_PERIOD);
- end loop;
- end ClkCycles;
-begin
- JTAG_BLOCK: c4m_jtag_tap_controller
- -- Use default values
- port map (
- TCK => TCK,
- TMS => TMS,
- TDI => TDI,
- TDO => TDO,
- TRST_N => TRST_N,
- RESET => open,
- DRCAPTURE => open,
- DRSHIFT => open,
- DRUPDATE => open,
- IR => open,
- CORE_OUT => "0",
- CORE_IN => open,
- CORE_EN => "0",
- PAD_OUT => open,
- PAD_IN => "0",
- PAD_EN => open
- );
-
- SIM: process
- begin
- -- Reset
- TCK <= '0';
- TMS <= '1';
- TDI <= '0';
- TRST_N <= '0';
- wait for 10*CLK_PERIOD;
-
- TRST_N <= '1';
- wait for CLK_PERIOD;
-
- -- Enter RunTestIdle
- TMS <= '0';
- ClkCycle(TCK, CLK_PERIOD);
- -- Enter SelectDRScan
- TMS <= '1';
- ClkCycle(TCK, CLK_PERIOD);
- -- Enter Capture
- TMS <= '0';
- ClkCycle(TCK, CLK_PERIOD);
- -- Enter Shift, run for 35 CLK cycles
- TMS <= '0';
- ClkCycles(35, TCK, CLK_PERIOD);
- -- Enter Exit1
- TMS <= '1';
- ClkCycle(TCK, CLK_PERIOD);
- -- Enter Update
- TMS <= '1';
- ClkCycle(TCK, CLK_PERIOD);
- -- To TestLogicReset
- TMS <= '1';
- ClkCycles(4, TCK, CLK_PERIOD);
-
- -- end simulation
- wait;
- end process;
-end rtl;
+++ /dev/null
--- Test JTAG in the following way:
--- * reset JTAG interface
--- * load samplepreload command
--- * shift in/out sampled inputs + wanted outputs
--- * load extest command
--- * execute
-
-
-library ieee;
-use ieee.std_logic_1164.ALL;
-
-use work.c4m_jtag.ALL;
-
-entity bench_sampleshift is
-end bench_sampleshift;
-
-architecture rtl of bench_sampleshift is
- signal TCK: std_logic;
- signal TMS: std_logic;
- signal TDI: std_logic;
- signal TDO: std_logic;
- signal TRST_N: std_logic;
-
- constant CLK_PERIOD: time := 10 ns;
-
- procedure ClkCycle(
- signal CLK: out std_logic;
- CLK_PERIOD: time
- ) is
- begin
- CLK <= '0';
- wait for CLK_PERIOD/4;
- CLK <= '1';
- wait for CLK_PERIOD/2;
- CLK <= '0';
- wait for CLK_PERIOD/4;
- end ClkCycle;
-
- procedure ClkCycles(
- N: integer;
- signal CLK: out std_logic;
- CLK_PERIOD: time
- ) is
- begin
- for i in 1 to N loop
- ClkCycle(CLK, CLK_PERIOD);
- end loop;
- end ClkCycles;
-
- procedure LoadIR(
--- /dev/null
+import cocotb
+from cocotb.triggers import Timer
+from cocotb.binary import BinaryValue
+
+class JTAGException(Exception):
+ pass
+
+class JTAG_Clock(object):
+ """
+ Class for the JTAG clock, run cycle by cycle
+ """
+ def __init__(self, signal, period):
+ self.signal = signal
+ self.t = Timer(period/4)
+
+ @cocotb.coroutine
+ def Cycle(self, cycles=1):
+ """
+ Do one or more cycles
+ Cycle start in middle of 0 pulse of the clock
+ """
+ for i in range(cycles):
+ self.signal <= 0
+ yield self.t
+ self.signal <= 1
+ yield self.t
+ yield self.t
+ self.signal <= 0
+ yield self.t
+
+class JTAG_Master(object):
+ """
+ Class that will run JTAG commands, shift in and out data
+ """
+ #TODO: Handle a JTAG chain with more than one device
+
+ def __init__(self, tck, tms, tdi, tdo, trst_n=None, clk_period=1000):
+ self.tck = tck
+ self.clkgen = JTAG_Clock(tck, clk_period)
+ tck <= 0
+ self.tms = tms
+ tms <= 1
+ self.tdi = tdi
+ tdi <= 0
+ self.tdo = tdo
+ self.trst_n = trst_n
+ if trst_n is not None:
+ trst_n <= 1
+ self.period = Timer(clk_period)
+
+ # Standard commands
+ # TODO: make IR length configurable; now 2 is assumed
+ self.BYPASS = [1, 1]
+ self.IDCODE = [0, 1]
+ self.SAMPLEPRELOAD = [1, 0]
+ self.EXTEST = [0, 0]
+
+ # After command we always leave the controller in reset or runidle state
+ # If value is None we will always reset the interface
+ self.state = None
+
+ # The methods of this class are coroutines. The results will be stored
+ # in the result field
+ self.result = None
+
+ @cocotb.coroutine
+ def cycle_clock(self, cycles=1):
+ if self.state == "Run" and self.tms == 1:
+ self.state = "Scan"
+ yield self.clkgen.Cycle(cycles)
+
+ @cocotb.coroutine
+ def reset(self):
+ if not self.trst_n is None:
+ # Enable reset signal for one clock period
+ self.trst_n <= 0
+ yield self.period
+ self.trst_n <= 1
+ else:
+ # 5 cycles with tms on 1 should reset the JTAG TAP controller
+ self.tms <= 1
+ yield self.cycle_clock(5)
+
+ self.state = "Reset"
+
+ self.result = None
+
+ @cocotb.coroutine
+ def change_state(self, tms_list):
+ """
+ Put TAP in other state by giving a TMS sequence
+ This function does not detect if one ends up in reset or run
+ state afterwards, self.state has to be updated by caller
+ if that is the case.
+ """
+ tms_copy = list(tms_list)
+ while tms_copy:
+ self.tms <= tms_copy.pop()
+ yield self.cycle_clock()
+ self.result = None
+
+ @cocotb.coroutine
+ def change_to_run(self):
+ """
+ Put TAP in RunTestIdle state
+ self.result is bool and true if TAP went through reset state
+ """
+ isreset = False
+ if self.state is None:
+ yield self.reset()
+ if self.state is "Reset":
+ isreset = True
+ self.tms <= 0
+ yield self.cycle_clock()
+ self.state = "Run"
+ assert(self.state == "Run")
+ self.result = isreset
+
+ @cocotb.coroutine
+ def load_ir(self, cmd):
+ cmd_copy = list(cmd)
+ result = BinaryValue(bits=len(cmd_copy))
+ l_result = list()
+
+ yield self.change_to_run()
+ # Go to Capture/IR
+ yield self.change_state([0, 1, 1])
+
+ # Shift the two
+ self.tms <= 0
+ while cmd_copy:
+ # In first iteration we enter SHIFT state and tdo is made active
+ yield self.cycle_clock()
+ # For the last iteration tdi will be shifted when entering next state
+ self.tdi <= cmd_copy.pop()
+ l_result.insert(0, str(self.tdo))
+
+ # Go to RunTestIdle
+ yield self.change_state([0, 1, 1])
+ self.state = "Run"
+
+ @cocotb.coroutine
+ def idcode(self):
+ """
+ Get the IDCODE from the device
+ result will contain the 32 bit IDCODE of the device
+ """
+
+ result = BinaryValue(bits=32)
+ l_result = list()
+
+ # Keep tdi 0 for the whole run
+ self.tdi <= 0
+
+ yield self.change_to_run()
+ if not self.result:
+ # If TAP was not reset we have to load IDCODE command
+ yield self.load_ir(self.IDCODE)
+
+ # Should be again in RUN state
+ assert(self.state == "Run")
+
+ # Go to Shift/DR
+ yield self.change_state([0, 0, 1])
+
+ # Enter Shift; run for 32 cycles
+ self.tms <= 0
+ for i in range(32):
+ l_result.insert(0, str(self.tdo))
+ yield self.cycle_clock()
+ result.binstr = "".join(l_result)
+
+ # Go to RunTestIdle
+ yield self.change_state([0, 1, 1])
+ self.state = "Run"
+
+ self.result = result
+
+ @cocotb.coroutine
+ def shift_data(self, data_in):
+ """
+ Shift data in through the JTAG and capture the output
+ Input can be of type BinaryValue or an iterable value of 0 and 1s.
+ Last bit will be shifted in first.
+ result will contain the sample TDO with the same number of bits as the input
+ """
+ if isinstance(data_in, BinaryValue):
+ data_copy = [int(c) for c in data_in.binstr]
+ else:
+ data_copy = list(data_in)
+ result = BinaryValue()
+ l_result = list()
+
+ yield self.change_to_run()
+ # Go to Capture/DR
+ yield self.change_state([0, 1])
+
+ # Shift data through
+ self.tms <= 0
+ while data_copy:
+ yield self.cycle_clock()
+ self.tdi <= data_copy.pop()
+ l_result.insert(0, str(self.tdo))
+ result.binstr = "".join(l_result)
+
+ # Go to RunTestIdle
+ yield self.change_state([0, 1, 1])
+ self.state = "Run"
+
+ self.result = result
--- /dev/null
+import c4m_jtag_svfgrammar
+import cocotb
+from cocotb.binary import BinaryValue
+from functools import singledispatch
+
+def decodescanspec(node):
+ length = int(str(node[2]))
+ fstr = "{:0"+str(node[2])+"b}"
+
+ g_tdi = node[4]
+ g_tdo = node[5]
+ g_mask = node[6]
+ g_smask = node[7]
+
+ if g_tdi is None:
+ tdi = None
+ else:
+ tdi = BinaryValue(fstr.format(int(str(g_tdi[2]),16)), length)
+
+ if g_tdo is None:
+ tdo = None
+ else:
+ tdo = BinaryValue(fstr.format(int(str(g_tdo[3]),16)), length)
+
+ if g_mask is None:
+ mask = None
+ else:
+ mask = BinaryValue(fstr.format(int(str(g_mask[3]),16)), length)
+
+ if g_smask is None:
+ smask = None
+ else:
+ smask = BinaryValue(fstr.format(int(str(g_smask[3]),16)), length)
+
+ return (length, tdi, tdo, mask, smask)
+
+
+class SVF_Executor(object):
+ @cocotb.coroutine
+ def execute(self, node):
+ """This is the generic method"""
+ self._p("generic")
+ if False: # Make coroutine work
+ yield PythonTrigger()
+
+ @cocotb.coroutine
+ def _execute_NOP(self, node):
+ if False: # Make coroutine work
+ yield PythonTrigger()
+
+ @cocotb.coroutine
+ def _execute_EndDR(self, node):
+ self._p("EndDR ignored")
+ if False: # Make coroutine work
+ yield PythonTrigger()
+
+ @cocotb.coroutine
+ def _execute_EndIR(self, node):
+ self._p("EndIR ignored")
+ if False: # Make coroutine work
+ yield PythonTrigger()
+
+ @cocotb.coroutine
+ def _execute_Frequency(self, node):
+ self._p("Frequency ignored")
+ if False: # Make coroutine work
+ yield PythonTrigger()
+
+ @cocotb.coroutine
+ def _execute_HDR(self, node):
+ self._p("HDR ignored")
+ if False: # Make coroutine work
+ yield PythonTrigger()
+
+ @cocotb.coroutine
+ def _execute_HIR(self, node):
+ self._p("HIR ignored")
+ if False: # Make coroutine work
+ yield PythonTrigger()
+
+ @cocotb.coroutine
+ def _execute_SDR(self, node):
+ self._p("Executing SDR")
+ (length, tdi, tdo, mask, smask) = decodescanspec(node)
+
+ samelength = length == self._d_length
+ self._d_length = length
+
+ if tdi is None:
+ if not samelength:
+ raise(JTAGException("TDI needs to be specified when length of data changes"))
+ else:
+ self._d_tdi = tdi
+
+ if mask is not None:
+ self._d_mask = mask
+ elif not samelength:
+ self._d_mask = None
+
+ if smask is not None:
+ self._d_smask = smask
+ elif not samelength:
+ self._d_smask = None
+
+ yield self.master.shift_data(self._d_tdi)
+ if tdo is not None:
+ if self._d_mask is not None:
+ raise(JTAGException("MASK not supported for SDR"))
+ assert(self.result == tdo)
+
+ @cocotb.coroutine
+ def _execute_SIR(self, node):
+ (length, tdi, tdo, mask, smask) = decodescanspec(node)
+
+ samelength = length == self._i_length
+ self._i_length = length
+
+ if tdi is None:
+ if not samelength:
+ raise(JTAGException("TDI needs to be specified when length of data changes"))
+ else:
+ self._i_tdi = tdi
+
+ if mask is not None:
+ self._i_mask = mask
+ elif not samelength:
+ self._i_mask = None
+
+ if smask is not None:
+ self._i_smask = smask
+ elif not samelength:
+ self._i_smask = None
+
+ self._p("Executing SIR ({})".format(self._i_tdi.integer))
+
+ yield self.master.load_ir(self._i_tdi)
+ if tdo is not None:
+ if self._i_mask is not None:
+ raise(JTAGException("MASK not supported for SIR"))
+ assert(self.result == tdo)
+
+
+ @cocotb.coroutine
+ def _execute_State(self, node):
+ self._p("State")
+ if False: # Make coroutine work
+ yield PythonTrigger()
+
+ @cocotb.coroutine
+ def _execute_TDR(self, node):
+ self._p("TDR")
+ if False: # Make coroutine work
+ yield PythonTrigger()
+
+ @cocotb.coroutine
+ def _execute_TIR(self, node):
+ self._p("TIR")
+ if False: # Make coroutine work
+ yield PythonTrigger()
+
+ @cocotb.coroutine
+ def _execute_Trst(self, node):
+ self._p("TRST ignored")
+ if False: # Make coroutine work
+ yield PythonTrigger()
+
+ @cocotb.coroutine
+ def _execute_Runtest(self, node):
+ if node[1] is not None:
+ raise(JTAGException("State specification for RUNTEST not supported"))
+ # TODO: cycle the right number of clocks or wait the right time
+ yield(self.master.change_state([0]))
+
+ @cocotb.coroutine
+ def _execute_SVFFile(self, node):
+ self._p("Executing SVFFile")
+ for statement in node.elements[0]:
+ yield self.execute(statement)
+
+ def __init__(self, master):
+ # master is assumed to be a JTAG_Master class
+ # it needs to support methods load_ir() and shift_data()
+ self.master = master
+
+ # Due to bug in Grammar definition all possible classes have to have
+ # a dispatch entry otherwise an error will be raised.
+ self.execute = singledispatch(self.execute)
+ self.execute.register(c4m_jtag_svfgrammar.EmptyLine, self._execute_NOP)
+ self.execute.register(c4m_jtag_svfgrammar.Comment, self._execute_NOP)
+ self.execute.register(c4m_jtag_svfgrammar.EndDR, self._execute_EndDR)
+ self.execute.register(c4m_jtag_svfgrammar.EndIR, self._execute_EndIR)
+ self.execute.register(c4m_jtag_svfgrammar.Frequency, self._execute_Frequency)
+ self.execute.register(c4m_jtag_svfgrammar.HDR, self._execute_HDR)
+ self.execute.register(c4m_jtag_svfgrammar.HIR, self._execute_HIR)
+ self.execute.register(c4m_jtag_svfgrammar.Runtest, self._execute_Runtest)
+ self.execute.register(c4m_jtag_svfgrammar.SDR, self._execute_SDR)
+ self.execute.register(c4m_jtag_svfgrammar.SIR, self._execute_SIR)
+ self.execute.register(c4m_jtag_svfgrammar.State, self._execute_State)
+ self.execute.register(c4m_jtag_svfgrammar.TDR, self._execute_TDR)
+ self.execute.register(c4m_jtag_svfgrammar.TIR, self._execute_TIR)
+ self.execute.register(c4m_jtag_svfgrammar.Trst, self._execute_Trst)
+ self.execute.register(c4m_jtag_svfgrammar.SVFFile, self._execute_SVFFile)
+
+ # Store the head and tail for the scan
+ self._d_tdi = self._d_tdi_h = self._d_tdi_t = None
+ self._d_tdo_h = self._d_tdo_t = None
+ self._i_tdi = self._i_tdi_h = self._i_tdi_t = None
+ self._i_tdo_h = self._i_tdo_t = None
+
+ # Remember the masks; smasks are ignored and bits always considered as care, e.g right
+ # value applied
+ self._d_length = self._d_length_h = self._d_length_t = None
+ self._d_mask = self._d_mask_h = self._d_mask_t = None
+ self._d_smask = self._d_smask_h = self._d_smask_t = None
+ self._i_length = self._i_length_h = self._i_length_t = None
+ self._i_mask = self._i_mask_h = self._i_mask_t = None
+ self._i_smask = self._i_smask_h = self._i_smask_t = None
+
+ @cocotb.coroutine
+ def run(self, cmds, p=print):
+ self._p = p
+ if isinstance(cmds, c4m_jtag_svfgrammar.SVFFile):
+ yield self.execute(cmds)
+ else:
+ p = c4m_jtag_svfgrammar.SVFFile.parser()
+ yield self.execute(p.parse_string(cmds))
--- /dev/null
+from modgrammar import *
+
+grammar_whitespace_mode = 'explicit'
+grammar_whitespace = WS_NOEOL
+
+class SVFEol(Grammar):
+ grammar = (OPTIONAL(SPACE), EOL)
+ grammar_collapse = True
+
+class SemicolonEol(Grammar):
+ grammar = (OPTIONAL(SPACE), L(";"), SVFEol)
+ grammar_collapse = True
+
+class Integer(Grammar):
+ grammar = WORD("0-9")
+ grammar_collapse = True
+
+class Float(Grammar):
+ grammar = (Integer, (L("."), OPTIONAL(Integer)), OPTIONAL(L("E"), Integer))
+
+class Hexadecimal(Grammar):
+ grammar = (L("("), WORD("0-9A-F"), L(")"))
+ grammar_collapse = True
+
+class StableState(Grammar):
+ grammar = (L("IRPAUSE") | L("DRPAUSE") | L("RESET") | L("IDLE"))
+ grammar_collapse = True
+
+
+class ScanSpec(Grammar):
+ """The specification of Scan In/Scan out data"""
+ grammar = (SPACE, Integer, SPACE,
+ OPTIONAL(L("TDI"), OPTIONAL(SPACE), Hexadecimal),
+ OPTIONAL(OPTIONAL(SPACE), L("TDO"), OPTIONAL(SPACE), Hexadecimal),
+ OPTIONAL(OPTIONAL(SPACE), L("MASK"), OPTIONAL(SPACE), Hexadecimal),
+ OPTIONAL(OPTIONAL(SPACE), L("SMASK"), OPTIONAL(SPACE), Hexadecimal)
+ )
+ grammar_collapse = True
+
+
+class EmptyLine(Grammar):
+ grammar = SVFEol
+
+class Comment(Grammar):
+ grammar = (L("!"), REST_OF_LINE, SVFEol)
+
+class EndDR(Grammar):
+ grammar = (L("ENDDR"), SPACE, StableState, SemicolonEol)
+
+class EndIR(Grammar):
+ grammar = (L("ENDIR"), SPACE, StableState, SemicolonEol)
+
+class Frequency(Grammar):
+ grammar = (L("FREQUENCY"), OPTIONAL(SPACE, Float, OPTIONAL(SPACE), L("HZ")), OPTIONAL(SPACE), SemicolonEol)
+
+class HDR(Grammar):
+ grammar = (L("HDR"), ScanSpec, SemicolonEol)
+
+class HIR(Grammar):
+ grammar = (L("HIR"), ScanSpec, SemicolonEol)
+
+#TODO: PIO, PIOMAP
+
+class Runtest(Grammar):
+ grammar = (
+ L("RUNTEST"),
+ OPTIONAL(SPACE, StableState),
+ OPTIONAL(SPACE, Integer, OPTIONAL(SPACE), (L("TCK") | L("SCK"))),
+ OPTIONAL(SPACE, Float, OPTIONAL(SPACE), L("SEC")),
+ OPTIONAL(SPACE, L("MAXIMUM"), SPACE, Float, OPTIONAL(SPACE), L("SEC")),
+ OPTIONAL(SPACE, L("ENDSTATE"), SPACE, StableState),
+ SemicolonEol
+ )
+
+class SDR(Grammar):
+ grammar = (L("SDR"), ScanSpec, SemicolonEol)
+
+class SIR(Grammar):
+ grammar = (L("SIR"), ScanSpec, SemicolonEol)
+
+class State(Grammar):
+ # TODO: Path to reach state
+ grammar = (L("STATE"), SPACE, StableState, SemicolonEol)
+
+class TDR(Grammar):
+ grammar = (L("TDR"), ScanSpec, SemicolonEol)
+
+class TIR(Grammar):
+ grammar = (L("TIR"), ScanSpec, SemicolonEol)
+
+class Trst(Grammar):
+ grammar = (L("TRST"), SPACE, (L("ON") | L("OFF") | L("Z") | L("ABSENT")), SemicolonEol)
+
+
+class SVFFile(Grammar):
+ grammar = ONE_OR_MORE(EmptyLine | Comment | Trst | EndDR | EndIR | SIR | SDR | Runtest | State)
--- /dev/null
+#!/bin/env python3
+import os
+
+from nmigen import *
+from nmigen.build import *
+from nmigen.lib.io import *
+
+from wishbone import Wishbone
+
+__all__ = [
+ "PmodJTAGMasterResource",
+ "PmodJTAGMasterAResource",
+ "PmodJTAGSlaveResource",
+ "PmodJTAGSlaveAResource",
+ "JTAG",
+]
+
+#TODO: Provide more documentation
+
+def PmodJTAGMasterResource(name, number, *, pmod, attrs=Attrs(IOSTANDARD="LVCMOS33")):
+ return Resource(name, number,
+ Subsignal("TCK", Pins("1", dir="o", conn=("pmod", pmod))),
+ Subsignal("TMS", Pins("2", dir="o", conn=("pmod", pmod))),
+ Subsignal("TDO", Pins("3", dir="o", conn=("pmod", pmod))),
+ Subsignal("TDI", Pins("4", dir="i", conn=("pmod", pmod))),
+ attrs,
+ )
+
+def PmodJTAGMasterAResource(name, number, *, pmod, attrs=Attrs(IOSTANDARD="LVCMOS33")):
+ return Resource(name, number,
+ Subsignal("TCK", Pins("1", dir="o", conn=("pmod", pmod))),
+ Subsignal("TMS", Pins("2", dir="o", conn=("pmod", pmod))),
+ Subsignal("TDO", Pins("3", dir="o", conn=("pmod", pmod))),
+ Subsignal("TDI", Pins("4", dir="i", conn=("pmod", pmod))),
+ Subsignal("TRST", PinsN("7", dir="o", conn=("pmod", pmod))),
+ attrs,
+ )
+
+def PmodJTAGSlaveResource(name, number, *, pmod, attrs=Attrs(IOSTANDARD="LVCMOS33")):
+ return Resource(name, number,
+ Subsignal("TCK", Pins("1", dir="i", conn=("pmod", pmod))),
+ Subsignal("TMS", Pins("2", dir="i", conn=("pmod", pmod))),
+ Subsignal("TDI", Pins("3", dir="i", conn=("pmod", pmod))),
+ Subsignal("TDO", Pins("4", dir="o", conn=("pmod", pmod))),
+ attrs,
+ )
+
+def PmodJTAGSlaveAResource(name, number, *, pmod, attrs=Attrs(IOSTANDARD="LVCMOS33")):
+ return Resource(name, number,
+ Subsignal("TCK", Pins("1", dir="i", conn=("pmod", pmod))),
+ Subsignal("TMS", Pins("2", dir="i", conn=("pmod", pmod))),
+ Subsignal("TDI", Pins("3", dir="i", conn=("pmod", pmod))),
+ Subsignal("TDO", Pins("4", dir="o", conn=("pmod", pmod))),
+ Subsignal("TRST", PinsN("7", dir="i", conn=("pmod", pmod))),
+ attrs,
+ )
+
+
+class ShiftReg(Elaboratable):
+ def __init__(self, ircodes, length, domain):
+ # The sr record will be returned to user code
+ self.sr = Record([("i", length), ("o", length), ("oe", len(ircodes)), ("ack", 1)])
+ # The next attributes are for JTAG class usage only
+ self.ir = None # made None as width is not known yet
+ self.tdi = Signal()
+ self.tdo = Signal()
+ self.tdo_en = Signal()
+ self.capture = Signal()
+ self.shift = Signal()
+ self.update = Signal()
+ self.jtag_cd = None # The JTAG clock domain
+
+ ##
+
+ self._ircodes = ircodes
+ self._domain = domain
+
+ def elaborate(self, platform):
+ length = len(self.sr.o)
+ domain = self._domain
+
+ m = Module()
+
+ m.domains.jtag = self.jtag_cd
+
+ sr_jtag = Signal(length)
+
+ assert isinstance(self.ir, Signal)
+ isir = Signal(len(self._ircodes))
+ capture = Signal()
+ shift = Signal()
+ update = Signal()
+ m.d.comb += [
+ isir.eq(Cat(self.ir == ircode for ircode in self._ircodes)),
+ capture.eq((isir != 0) & self.capture),
+ shift.eq((isir != 0) & self.shift),
+ update.eq((isir != 0) & self.update),
+ ]
+
+ # On update set o, oe and wait for ack
+ # update signal is on JTAG clockdomain, latch it
+ update_core = Signal()
+ m.d[domain] += update_core.eq(update) # This is CDC from JTAG domain to given domain
+ with m.FSM(domain=domain):
+ with m.State("IDLE"):
+ m.d.comb += self.sr.oe.eq(0)
+ with m.If(update_core):
+ # Latch sr_jtag cross domain but it should be stable due to latching of update_core
+ m.d[domain] += self.sr.o.eq(sr_jtag)
+ # Wait one cycle to raise oe so sr.o has one more cycle to stabilize
+ m.next = "WAIT4ACK"
+ with m.State("WAIT4ACK"):
+ m.d.comb += self.sr.oe.eq(isir)
+ with m.If(self.sr.ack):
+ m.next = "WAIT4END"
+ with m.State("WAIT4END"):
+ m.d.comb += self.sr.oe.eq(0)
+ with m.If(~update_core):
+ m.next = "IDLE"
+
+ m.d.comb += [
+ self.tdo.eq(sr_jtag[0]),
+ self.tdo_en.eq(shift),
+ ]
+
+ with m.If(shift):
+ m.d.jtag += sr_jtag.eq(Cat(sr_jtag[1:], self.tdi))
+ with m.If(capture):
+ m.d.jtag += sr_jtag.eq(self.sr.i)
+
+ return m
+
+class JTAGWishbone(Elaboratable):
+ def __init__(self, sr_addr, sr_data, wb, domain):
+ self._sr_addr = sr_addr
+ self._sr_data = sr_data
+ self._wb = wb
+ self._domain = domain
+
+ # To be set by JTAG
+ self._ir = None
+
+ def elaborate(self, platform):
+ sr_addr = self._sr_addr
+ sr_data = self._sr_data
+ wb = self._wb
+ domain = self._domain
+ ir = self._ir
+
+ m = Module()
+
+ if hasattr(wb, "sel"):
+ # Always selected
+ m.d.comb += [s.eq(1) for s in wb.sel]
+
+ # Immediately ack oe
+ m.d[domain] += [
+ sr_addr.ack.eq(sr_addr.oe),
+ sr_data.ack.eq(sr_data.oe != 0),
+ ]
+
+ with m.FSM(domain=domain) as fsm:
+ with m.State("IDLE"):
+ m.d.comb += [
+ wb.cyc.eq(0),
+ wb.stb.eq(0),
+ wb.we.eq(0),
+ ]
+ with m.If(sr_addr.oe): # WBADDR code
+ m.d[domain] += wb.addr.eq(sr_addr.o)
+ m.next = "READ"
+ with m.If(sr_data.oe[0]): # WBREAD code
+ m.d[domain] += wb.addr.eq(wb.addr + 1)
+ m.next = "READ"
+ with m.If(sr_data.oe[1]): # WBWRITE code
+ m.d[domain] += wb.dat_w.eq(sr_data.o)
+ m.next = "WRITEREAD"
+ with m.State("READ"):
+ m.d.comb += [
+ wb.cyc.eq(1),
+ wb.stb.eq(1),
+ wb.we.eq(0),
+ ]
+ with m.If(~wb.stall):
+ m.next = "READACK"
+ with m.State("READACK"):
+ m.d.comb += [
+ wb.cyc.eq(1),
+ wb.stb.eq(0),
+ wb.we.eq(0),
+ ]
+ with m.If(wb.ack):
+ m.d[domain] += sr_data.i.eq(wb.dat_r)
+ m.next = "IDLE"
+ with m.State("WRITEREAD"):
+ m.d.comb += [
+ wb.cyc.eq(1),
+ wb.stb.eq(1),
+ wb.we.eq(1),
+ ]
+ with m.If(~wb.stall):
+ m.next = "WRITEREADACK"
+ with m.State("WRITEREADACK"):
+ m.d.comb += [
+ wb.cyc.eq(1),
+ wb.stb.eq(0),
+ wb.we.eq(0),
+ ]
+ with m.If(wb.ack):
+ m.d[domain] += wb.addr.eq(wb.addr + 1)
+ m.next = "READ"
+
+ return m
+
+
+class JTAG(Elaboratable):
+ @staticmethod
+ def _add_files(platform, prefix):
+ d = os.path.realpath("{0}{1}{2}{1}vhdl".format(
+ os.path.dirname(__file__), os.path.sep, os.path.pardir
+ )) + os.path.sep
+ for fname in [
+ "c4m_jtag_pkg.vhdl",
+ "c4m_jtag_idblock.vhdl",
+ "c4m_jtag_iocell.vhdl",
+ "c4m_jtag_ioblock.vhdl",
+ "c4m_jtag_irblock.vhdl",
+ "c4m_jtag_tap_fsm.vhdl",
+ "c4m_jtag_tap_controller.vhdl",
+ ]:
+ f = open(d + fname, "r")
+ platform.add_file(prefix + fname, f)
+ f.close()
+
+
+ def __init__(self, io_count, *, ir_width=None, manufacturer_id=Const(0b10001111111, 11),
+ part_number=Const(1, 16), version=Const(0, 4)
+ ):
+ assert(isinstance(io_count, int) and io_count > 0)
+ assert((ir_width is None) or (isinstance(ir_width, int) and ir_width >= 2))
+ assert(len(version) == 4)
+
+ # TODO: Handle IOs with different directions
+ self.tck = Signal()
+ self.tms = Signal()
+ self.tdo = Signal()
+ self.tdi = Signal()
+ self.core = Array(Pin(1, "io") for _ in range(io_count)) # Signals to use for core
+ self.pad = Array(Pin(1, "io") for _ in range(io_count)) # Signals going to IO pads
+
+ self.jtag_cd = ClockDomain(name="jtag", local=True) # Own clock domain using TCK as clock signal
+
+ ##
+
+ self._io_count = io_count
+ self._ir_width = ir_width
+ self._manufacturer_id = manufacturer_id
+ self._part_number = part_number
+ self._version = version
+
+ self._ircodes = [0, 1, 2] # Already taken codes, all ones added at the end
+ self._srs = []
+
+ self._wbs = []
+
+ def elaborate(self, platform):
+ JTAG._add_files(platform, "jtag" + os.path.sep)
+
+ m = Module()
+
+ tdo_jtag = Signal()
+ reset = Signal()
+ capture = Signal()
+ shift = Signal()
+ update = Signal()
+
+
+ ir_max = max(self._ircodes) + 1 # One extra code needed with all ones
+ ir_width = len("{:b}".format(ir_max))
+ if self._ir_width is not None:
+ assert self._ir_width >= ir_width, "Specified JTAG IR width not big enough for allocated shiift registers"
+ ir_width = self._ir_width
+ ir = Signal(ir_width)
+
+ core_i = Cat(pin.i for pin in self.core)
+ core_o = Cat(pin.o for pin in self.core)
+ core_oe = Cat(pin.oe for pin in self.core)
+ pad_i = Cat(pin.i for pin in self.pad)
+ pad_o = Cat(pin.o for pin in self.pad)
+ pad_oe = Cat(pin.oe for pin in self.pad)
+
+ params = {
+ "p_IOS": self._io_count,
+ "p_IR_WIDTH": ir_width,
+ "p_MANUFACTURER": self._manufacturer_id,
+ "p_PART_NUMBER": self._part_number,
+ "p_VERSION": self._version,
+ "i_TCK": self.tck,
+ "i_TMS": self.tms,
+ "i_TDI": self.tdi,
+ "o_TDO": tdo_jtag,
+ "i_TRST_N": Const(1),
+ "o_RESET": reset,
+ "o_DRCAPTURE": capture,
+ "o_DRSHIFT": shift,
+ "o_DRUPDATE": update,
+ "o_IR": ir,
+ "o_CORE_IN": core_i,
+ "i_CORE_OUT": core_o,
+ "i_CORE_EN": core_oe,
+ "i_PAD_IN": pad_i,
+ "o_PAD_OUT": pad_o,
+ "o_PAD_EN": pad_oe,
+ }
+ m.submodules.tap = Instance("c4m_jtag_tap_controller", **params)
+
+ m.d.comb += [
+ self.jtag_cd.clk.eq(self.tck),
+ self.jtag_cd.rst.eq(reset),
+ ]
+
+ for i, sr in enumerate(self._srs):
+ m.submodules["sr{}".format(i)] = sr
+ sr.ir = ir
+ m.d.comb += [
+ sr.tdi.eq(self.tdi),
+ sr.capture.eq(capture),
+ sr.shift.eq(shift),
+ sr.update.eq(update),
+ ]
+
+ if len(self._srs) > 0:
+ first = True
+ for sr in self._srs:
+ if first:
+ first = False
+ with m.If(sr.tdo_en):
+ m.d.comb += self.tdo.eq(sr.tdo)
+ else:
+ with m.Elif(sr.tdo_en):
+ m.d.comb += self.tdo.eq(sr.tdo)
+ with m.Else():
+ m.d.comb += self.tdo.eq(tdo_jtag)
+ else:
+ m.d.comb += self.tdo.eq(tdo_jtag)
+
+ for i, wb in enumerate(self._wbs):
+ m.submodules["wb{}".format(i)] = wb
+ wb._ir = ir
+
+ return m
+
+
+ def add_shiftreg(self, ircode, length, domain="sync"):
+ """Add a shift register to the JTAG interface
+
+ Parameters:
+ - ircode: code(s) for the IR; int or sequence of ints. In the latter case this
+ shiftreg is shared between different IR codes.
+ - length: the length of the shift register
+ - domain: the domain on which the signal will be used"""
+
+ try:
+ ir_it = iter(ircode)
+ ircodes = ircode
+ except TypeError:
+ ir_it = ircodes = (ircode,)
+ for _ircode in ir_it:
+ assert(isinstance(_ircode, int) and _ircode > 0 and _ircode not in self._ircodes)
+
+ sr = ShiftReg(ircodes, length, domain)
+ sr.jtag_cd = self.jtag_cd
+ self._ircodes.extend(ircodes)
+ self._srs.append(sr)
+
+ return sr.sr
+
+
+ def add_wishbone(self, ircodes, address_width, data_width, sel_width=None, domain="sync"):
+ """Add a wishbone interface
+
+ Parameters:
+ - ircodes: sequence of three integer for the JTAG IR codes;
+ they represent resp. WBADDR, WBREAD and WBREADWRITE. First code
+ has a shift register of length 'address_width', the two other codes
+ share a shift register of length data_width.
+ - address_width: width of the address
+ - data_width: width of the data"""
+
+ assert len(ircodes) == 3
+
+ sr_addr = self.add_shiftreg(ircodes[0], address_width, domain=domain)
+ sr_data = self.add_shiftreg(ircodes[1:], data_width, domain=domain)
+
+ wb = Wishbone(data_width=data_width, address_width=address_width, sel_width=sel_width, master=True)
+
+ self._wbs.append(JTAGWishbone(sr_addr, sr_data, wb, domain))
+
+ return wb
--- /dev/null
+-- The JTAG id and bypass handling block
+
+library ieee;
+use ieee.std_logic_1164.ALL;
+
+use work.c4m_jtag.ALL;
+
+entity c4m_jtag_idblock is
+ generic (
+ IR_WIDTH: integer := 2;
+
+ MANUFACTURER: std_logic_vector(10 downto 0) := "10001111111";
+ PART_NUMBER: std_logic_vector(15 downto 0) := "0000000000000001";
+ VERSION: std_logic_vector(3 downto 0) := "0000"
+ );
+ port (
+ -- needed TAP signals
+ TCK: in std_logic;
+ TDI: in std_logic;
+ TDO: out std_logic;
+ TDO_EN: out std_logic := '0';
+
+ -- JTAG state
+ STATE: in TAPSTATE_TYPE;
+ NEXT_STATE: in TAPSTATE_TYPE;
+ DRSTATE: in std_logic;
+
+ -- The instruction
+ IR: in std_logic_vector(IR_WIDTH-1 downto 0)
+ );
+end c4m_jtag_idblock;
+
+architecture rtl of c4m_jtag_idblock is
+ constant IDCODE: std_logic_vector(31 downto 0) := VERSION & PART_NUMBER & MANUFACTURER & "1";
+
+ signal SR_ID: std_logic_vector(31 downto 0);
+ signal EN_TDO: boolean;
+
+ constant CMD_IDCODE: std_logic_vector(IR_WIDTH-1 downto 0) := c4m_jtag_cmd_idcode(IR_WIDTH);
+ constant CMD_BYPASS: std_logic_vector(IR_WIDTH-1 downto 0) := c4m_jtag_cmd_bypass(IR_WIDTH);
+begin
+ process (TCK)
+ begin
+ if rising_edge(TCK) then
+ if DRSTATE = '1' then
+ case STATE is
+ when Capture =>
+ SR_ID <= IDCODE;
+
+ when Shift =>
+ if IR = CMD_IDCODE then
+ SR_ID(30 downto 0) <= SR_ID(31 downto 1);
+ SR_ID(31) <= TDI;
+ elsif IR = CMD_BYPASS then
+ SR_ID(0) <= TDI;
+ else
+ null;
+ end if;
+
+ when others =>
+ null;
+ end case;
+ end if;
+ end if;
+ end process;
+
+ EN_TDO <= STATE = Shift and DRSTATE = '1' and (IR = CMD_IDCODE or IR = CMD_BYPASS);
+ TDO <= SR_ID(0) when EN_TDO else
+ '0';
+ TDO_EN <= '1' when EN_TDO else
+ '0';
+end rtl;
--- /dev/null
+-- The block of io cells with JTAG boundary scan support
+
+library ieee;
+use ieee.std_logic_1164.ALL;
+
+use work.c4m_jtag.ALL;
+
+entity c4m_jtag_ioblock is
+ generic (
+ IR_WIDTH: integer := 2;
+ IOS: integer := 1
+ );
+ port (
+ -- needed TAP signals
+ TCK: in std_logic;
+ TDI: in std_logic;
+ TDO: out std_logic;
+ TDO_EN: out std_logic := '0';
+
+ -- JTAG state
+ STATE: in TAPSTATE_TYPE;
+ NEXT_STATE: in TAPSTATE_TYPE;
+ DRSTATE: in std_logic;
+
+ -- The instruction
+ IR: in std_logic_vector(IR_WIDTH-1 downto 0);
+
+ -- The I/O access ports
+ CORE_OUT: in std_logic_vector(IOS-1 downto 0);
+ CORE_IN: out std_logic_vector(IOS-1 downto 0);
+ CORE_EN: in std_logic_vector(IOS-1 downto 0);
+
+ -- The pad connections
+ PAD_OUT: out std_logic_vector(IOS-1 downto 0);
+ PAD_IN: in std_logic_vector(IOS-1 downto 0);
+ PAD_EN: out std_logic_vector(IOS-1 downto 0)
+ );
+end c4m_jtag_ioblock;
+
+architecture rtl of c4m_jtag_ioblock is
+ signal IOMODE: SRIOMODE_TYPE;
+ signal SAMPLEMODE: SRSAMPLEMODE_TYPE;
+ signal ISSAMPLECMD: boolean;
+
+ signal BDSR_IN: std_logic_vector(IOS-1 downto 0);
+ signal BDSR_OUT: std_logic_vector(IOS-1 downto 0);
+
+ constant CMD_SAMPLEPRELOAD: std_logic_vector(IR_WIDTH-1 downto 0) := c4m_jtag_cmd_samplepreload(IR_WIDTH);
+ constant CMD_EXTEST: std_logic_vector(IR_WIDTH-1 downto 0) := c4m_jtag_cmd_extest(IR_WIDTH);
+begin
+ -- JTAG baundary scan IO cells
+ IOGEN: for i in 0 to IOS-1 generate
+ begin
+ IOCELL: c4m_jtag_iocell
+ port map (
+ CORE_IN => CORE_IN(i),
+ CORE_OUT => CORE_OUT(i),
+ CORE_EN => CORE_EN(i),
+ PAD_IN => PAD_IN(i),
+ PAD_OUT => PAD_OUT(i),
+ PAD_EN => PAD_EN(i),
+ BDSR_IN => BDSR_IN(i),
+ BDSR_OUT => BDSR_OUT(i),
+ IOMODE => IOMODE,
+ SAMPLEMODE => SAMPLEMODE,
+ TCK => TCK
+ );
+ end generate;
+ BDSRCONN: for i in 0 to IOS-2 generate
+ begin
+ BDSR_IN(i) <= BDSR_OUT(i+1);
+ end generate;
+ BDSR_IN(IOS-1) <= TDI;
+
+ -- Set IOMODE
+ -- Currently SR_2Core or SR_Z are not used
+ IOMODE <= SR_2Pad when IR = CMD_EXTEST else
+ SR_Through;
+
+ -- Set SAMPLEMODE
+ ISSAMPLECMD <= (IR = CMD_SAMPLEPRELOAD or IR = CMD_EXTEST) and DRSTATE = '1';
+ SAMPLEMODE <= SR_Sample when ISSAMPLECMD and STATE = Capture else
+ SR_Update when ISSAMPLECMD and STATE = Update else
+ SR_Shift when ISSAMPLECMD and STATE = Shift else
+ SR_Normal;
+
+ TDO <= BDSR_OUT(0) when ISSAMPLECMD and STATE = Shift else
+ '0';
+ TDO_EN <= '1' when ISSAMPLECMD and STATE = Shift else
+ '0';
+end rtl;
--- /dev/null
+-- An JTAG boundary scan for bidirectional I/O
+
+library ieee;
+use ieee.std_logic_1164.ALL;
+
+use work.c4m_jtag.ALL;
+
+entity c4m_jtag_iocell is
+ generic (
+ IR_WIDTH: integer := 2
+ );
+ port (
+ -- core connections
+ CORE_IN: out std_logic;
+ CORE_OUT: in std_logic;
+ CORE_EN: in std_logic;
+
+ -- pad connections
+ PAD_IN: in std_logic;
+ PAD_OUT: out std_logic;
+ PAD_EN: out std_logic;
+
+ -- BD shift register
+ BDSR_IN: in std_logic;
+ BDSR_OUT: out std_logic;
+
+ -- Mode of I/O cell
+ IOMODE: in SRIOMODE_TYPE;
+ SAMPLEMODE: in SRSAMPLEMODE_TYPE;
+ TCK: in std_logic
+ );
+end c4m_jtag_iocell;
+
+architecture rtl of c4m_jtag_iocell is
+ signal SR_IOIN: std_logic;
+ signal SR_IOOUT: std_logic;
+ signal SR_IOEN: std_logic;
+
+ signal CORE_IN_BD: std_logic;
+ signal PAD_OUT_BD: std_logic;
+ signal PAD_EN_BD: std_logic;
+begin
+ with IOMODE select
+ CORE_IN <=
+ PAD_IN when SR_Through | SR_Z,
+ PAD_IN when SR_2Pad,
+ CORE_IN_BD when SR_2Core,
+ 'X' when others;
+
+ with IOMODE select
+ PAD_OUT <=
+ CORE_OUT when SR_Through,
+ PAD_OUT_BD when SR_2Pad,
+ '0' when SR_2Core | SR_Z,
+ 'X' when others;
+
+ with IOMODE select
+ PAD_EN <=
+ CORE_EN when SR_Through,
+ PAD_EN_BD when SR_2Pad,
+ '0' when SR_2Core | SR_Z,
+ 'X' when others;
+
+ process (TCK)
+ begin
+ -- Sampling of inputs and shifting of boundary scan SR needs to be done on
+ -- rising edge of TCK
+ if rising_edge(TCK) then
+ case SAMPLEMODE is
+ when SR_Sample =>
+ SR_IOIN <= PAD_IN;
+ SR_IOOUT <= CORE_OUT;
+ SR_IOEN <= CORE_EN;
+
+ when SR_Shift =>
+ SR_IOIN <= BDSR_IN;
+ SR_IOOUT <= SR_IOIN;
+ SR_IOEN <= SR_IOOUT;
+
+ when others =>
+ null;
+ end case;
+ end if;
+
+ -- Update of output from boundary scan SR needs to be done on falling edge
+ -- of TCK
+ if falling_edge(TCK) then
+ case SAMPLEMODE is
+ when SR_Update =>
+ CORE_IN_BD <= SR_IOIN;
+ PAD_OUT_BD <= SR_IOOUT;
+ PAD_EN_BD <= SR_IOEN;
+
+ when others =>
+ null;
+ end case;
+ end if;
+ end process;
+
+ BDSR_OUT <= SR_IOEN;
+end rtl;
--- /dev/null
+-- Handle the instruction register for the JTAG controller
+
+library ieee;
+use ieee.std_logic_1164.ALL;
+
+use work.c4m_jtag.ALL;
+
+entity c4m_jtag_irblock is
+ generic (
+ IR_WIDTH: integer := 2
+ );
+ port (
+ -- needed TAP signals
+ TCK: in std_logic;
+ TDI: in std_logic;
+ TDO: out std_logic;
+ TDO_EN: out std_logic := '0';
+
+ -- JTAG state
+ STATE: in TAPSTATE_TYPE;
+ NEXT_STATE: in TAPSTATE_TYPE;
+ IRSTATE: in std_logic;
+
+ -- instruction register
+ IR: out std_logic_vector(IR_WIDTH-1 downto 0)
+ );
+end c4m_jtag_irblock;
+
+architecture rtl of c4m_jtag_irblock is
+ signal SHIFT_IR: std_logic_vector(IR_WIDTH-1 downto 0);
+
+ constant CMD_IDCODE: std_logic_vector(IR_WIDTH-1 downto 0) := c4m_jtag_cmd_idcode(IR_WIDTH);
+begin
+ process (TCK, STATE)
+ begin
+ if STATE = TestLogicReset then
+ SHIFT_IR <= (others => '0');
+ IR <= CMD_IDCODE;
+ elsif rising_edge(TCK) then
+ if IRSTATE = '1' then
+ case STATE is
+ when Capture =>
+ SHIFT_IR(1) <= '0';
+ SHIFT_IR(0) <= '1';
+
+ when Shift =>
+ SHIFT_IR(IR_WIDTH-2 downto 0) <= SHIFT_IR(IR_WIDTH-1 downto 1);
+ SHIFT_IR(IR_WIDTH-1) <= TDI;
+
+ when Update =>
+ IR <= SHIFT_IR;
+
+ when others =>
+ null;
+ end case;
+ end if;
+ end if;
+ end process;
+
+ TDO <= SHIFT_IR(0) when STATE = Shift and IRSTATE = '1' else
+ '0';
+ TDO_EN <= '1' when STATE = Shift and IRSTATE = '1' else
+ '0';
+end rtl;
--- /dev/null
+-- Package of jtag support code from the Chips4Makers project
+library ieee;
+use ieee.std_logic_1164.ALL;
+
+package c4m_jtag is
+ type TAPSTATE_TYPE is (
+ TestLogicReset,
+ RunTestIdle,
+ SelectDRScan,
+ SelectIRScan,
+ Capture,
+ Shift,
+ Exit1,
+ Pause,
+ Exit2,
+ Update
+ );
+ type SRIOMODE_TYPE is (
+ SR_Through, -- Connect core signal to pad signals
+ SR_2Pad, -- Connect BD to pad
+ SR_2Core, -- Connect BD to core
+ SR_Z -- pad is high impedance
+ );
+ type SRSAMPLEMODE_TYPE is (
+ SR_Normal, -- No sampling or shifting
+ SR_Sample, -- Sample IO state in BD SR on rising edge of TCK
+ SR_Update, -- Update BD from SR on falling edge of TCK
+ SR_Shift -- Shift the BD SR
+ );
+
+ component c4m_jtag_tap_fsm is
+ port (
+ -- The TAP signals
+ TCK: in std_logic;
+ TMS: in std_logic;
+ TRST_N: in std_logic;
+
+ -- The state outputs
+ STATE: out TAPSTATE_TYPE;
+ NEXT_STATE: out TAPSTATE_TYPE;
+ DRSTATE: out std_logic;
+ IRSTATE: out std_logic
+ );
+ end component c4m_jtag_tap_fsm;
+
+ component c4m_jtag_irblock is
+ generic (
+ IR_WIDTH: integer := 2
+ );
+ port (
+ -- needed TAP signals
+ TCK: in std_logic;
+ TDI: in std_logic;
+ TDO: out std_logic;
+ TDO_EN: out std_logic;
+
+ -- JTAG state
+ STATE: in TAPSTATE_TYPE;
+ NEXT_STATE: in TAPSTATE_TYPE;
+ IRSTATE: in std_logic;
+
+ -- instruction register
+ IR: out std_logic_vector(IR_WIDTH-1 downto 0)
+ );
+ end component c4m_jtag_irblock;
+
+ component c4m_jtag_idblock is
+ generic (
+ IR_WIDTH: integer := 2;
+
+ -- The default MANUFACTURING ID is not representing a valid
+ -- manufacturer according to the JTAG standard
+ MANUFACTURER: std_logic_vector(10 downto 0) := "10001111111";
+ PART_NUMBER: std_logic_vector(15 downto 0) := "0000000000000001";
+ VERSION: std_logic_vector(3 downto 0) := "0000"
+ );
+ port (
+ -- needed TAP signals
+ TCK: in std_logic;
+ TDI: in std_logic;
+ TDO: out std_logic;
+ TDO_EN: out std_logic;
+
+ -- JTAG state
+ STATE: in TAPSTATE_TYPE;
+ NEXT_STATE: in TAPSTATE_TYPE;
+ DRSTATE: in std_logic;
+
+ -- The instruction
+ IR: in std_logic_vector(IR_WIDTH-1 downto 0)
+ );
+ end component c4m_jtag_idblock;
+
+ component c4m_jtag_iocell is
+ port (
+ -- core connections
+ CORE_IN: out std_logic;
+ CORE_OUT: in std_logic;
+ CORE_EN: in std_logic;
+
+ -- pad connections
+ PAD_IN: in std_logic;
+ PAD_OUT: out std_logic;
+ PAD_EN: out std_logic;
+
+ -- BD shift register
+ BDSR_IN: in std_logic;
+ BDSR_OUT: out std_logic;
+
+ -- Mode of I/O cell
+ IOMODE: in SRIOMODE_TYPE;
+ SAMPLEMODE: in SRSAMPLEMODE_TYPE;
+ TCK: in std_logic
+ );
+ end component c4m_jtag_iocell;
+
+ component c4m_jtag_ioblock is
+ generic (
+ IR_WIDTH: integer := 2;
+ IOS: integer := 1
+ );
+ port (
+ -- needed TAP signals
+ TCK: in std_logic;
+ TDI: in std_logic;
+ TDO: out std_logic;
+ TDO_EN: out std_logic;
+
+ -- JTAG state
+ STATE: in TAPSTATE_TYPE;
+ NEXT_STATE: in TAPSTATE_TYPE;
+ DRSTATE: in std_logic;
+
+ -- The instruction
+ IR: in std_logic_vector(IR_WIDTH-1 downto 0);
+
+ -- The I/O access ports
+ CORE_OUT: in std_logic_vector(IOS-1 downto 0);
+ CORE_IN: out std_logic_vector(IOS-1 downto 0);
+ CORE_EN: in std_logic_vector(IOS-1 downto 0);
+
+ -- The pad connections
+ PAD_OUT: out std_logic_vector(IOS-1 downto 0);
+ PAD_IN: in std_logic_vector(IOS-1 downto 0);
+ PAD_EN: out std_logic_vector(IOS-1 downto 0)
+ );
+ end component c4m_jtag_ioblock;
+
+ component c4m_jtag_tap_controller is
+ generic (
+ DEBUG: boolean := false;
+
+ IR_WIDTH: integer := 2;
+ IOS: integer := 1;
+
+ -- The default MANUFACTURING ID is not representing a valid
+ -- manufacturer according to the JTAG standard
+ MANUFACTURER: std_logic_vector(10 downto 0) := "10001111111";
+ PART_NUMBER: std_logic_vector(15 downto 0) := "0000000000000001";
+ VERSION: std_logic_vector(3 downto 0) := "0000"
+ );
+ port (
+ -- The TAP signals
+ TCK: in std_logic;
+ TMS: in std_logic;
+ TDI: in std_logic;
+ TDO: out std_logic;
+ TRST_N: in std_logic;
+
+ -- The FSM state indicators
+ RESET: out std_logic; -- In reset state
+ DRCAPTURE: out std_logic; -- In DR_Capture state
+ DRSHIFT: out std_logic; -- In DR_Shift state
+ DRUPDATE: out std_logic; -- In DR_Update state
+
+ -- The Instruction Register
+ IR: out std_logic_vector(IR_WIDTH-1 downto 0);
+
+ -- The I/O access ports
+ CORE_IN: out std_logic_vector(IOS-1 downto 0);
+ CORE_EN: in std_logic_vector(IOS-1 downto 0);
+ CORE_OUT: in std_logic_vector(IOS-1 downto 0);
+
+ -- The pad connections
+ PAD_IN: in std_logic_vector(IOS-1 downto 0);
+ PAD_EN: out std_logic_vector(IOS-1 downto 0);
+ PAD_OUT: out std_logic_vector(IOS-1 downto 0)
+ );
+ end component c4m_jtag_tap_controller;
+
+ function c4m_jtag_cmd_idcode(width: integer) return std_logic_vector;
+ function c4m_jtag_cmd_bypass(width: integer) return std_logic_vector;
+ function c4m_jtag_cmd_samplepreload(width: integer) return std_logic_vector;
+ function c4m_jtag_cmd_extest(width: integer) return std_logic_vector;
+end c4m_jtag;
+
+package body c4m_jtag is
+ function c4m_jtag_cmd_bypass(width: integer) return std_logic_vector is
+ variable return_vector: std_logic_vector(width-1 downto 0);
+ begin
+ return_vector := (others => '1');
+ return return_vector;
+ end;
+
+ function c4m_jtag_cmd_idcode(width: integer) return std_logic_vector is
+ variable return_vector: std_logic_vector(width-1 downto 0);
+ begin
+ return_vector := (0 => '1', others => '0');
+ return return_vector;
+ end;
+
+ function c4m_jtag_cmd_samplepreload(width: integer) return std_logic_vector is
+ variable return_vector: std_logic_vector(width-1 downto 0);
+ begin
+ return_vector := (1 => '1', others => '0');
+ return return_vector;
+ end;
+
+ function c4m_jtag_cmd_extest(width: integer) return std_logic_vector is
+ variable return_vector: std_logic_vector(width-1 downto 0);
+ begin
+ return_vector := (others => '0');
+ return return_vector;
+ end;
+end package body;
--- /dev/null
+-- A JTAG complient tap controller implementation
+-- This is implemented based on the IEEE 1149.1 standard
+
+library ieee;
+use ieee.std_logic_1164.ALL;
+
+use work.c4m_jtag.ALL;
+
+entity c4m_jtag_tap_controller is
+ generic (
+ DEBUG: boolean := false;
+
+ IR_WIDTH: integer := 2;
+ IOS: integer := 1;
+
+ MANUFACTURER: std_logic_vector(10 downto 0) := "10001111111";
+ PART_NUMBER: std_logic_vector(15 downto 0) := "0000000000000001";
+ VERSION: std_logic_vector(3 downto 0) := "0000"
+ );
+ port (
+ -- The TAP signals
+ TCK: in std_logic;
+ TMS: in std_logic;
+ TDI: in std_logic;
+ TDO: out std_logic;
+ TRST_N: in std_logic;
+
+ -- The FSM state indicators
+ RESET: out std_logic;
+ DRCAPTURE: out std_logic;
+ DRSHIFT: out std_logic;
+ DRUPDATE: out std_logic;
+
+ -- The Instruction Register
+ IR: out std_logic_vector(IR_WIDTH-1 downto 0);
+
+ -- The I/O access ports
+ CORE_IN: out std_logic_vector(IOS-1 downto 0);
+ CORE_EN: in std_logic_vector(IOS-1 downto 0);
+ CORE_OUT: in std_logic_vector(IOS-1 downto 0);
+
+ -- The pad connections
+ PAD_IN: in std_logic_vector(IOS-1 downto 0);
+ PAD_EN: out std_logic_vector(IOS-1 downto 0);
+ PAD_OUT: out std_logic_vector(IOS-1 downto 0)
+ );
+end c4m_jtag_tap_controller;
+
+architecture rtl of c4m_jtag_tap_controller is
+ signal S_STATE: TAPSTATE_TYPE;
+ signal S_NEXT_STATE: TAPSTATE_TYPE;
+ signal S_IRSTATE: std_logic;
+ signal S_DRSTATE: std_logic;
+ signal S_IR: std_logic_vector(IR_WIDTH-1 downto 0);
+
+ signal IR_TDO: std_logic;
+ signal IR_TDO_EN: std_logic;
+ signal ID_TDO: std_logic;
+ signal ID_TDO_EN: std_logic;
+ signal IO_TDO: std_logic;
+ signal IO_TDO_EN: std_logic;
+begin
+ IR <= S_IR;
+
+ RESET <= '1' when S_STATE = TestLogicReset else '0';
+ DRCAPTURE <= '1' when S_STATE = Capture and S_DRSTATE = '1' else '0';
+ DRSHIFT <= '1' when S_STATE = Shift and S_DRSTATE = '1' else '0';
+ DRUPDATE <= '1' when S_STATE = Update and S_DRSTATE = '1' else '0';
+
+ -- JTAG state machine
+ FSM: c4m_jtag_tap_fsm
+ port map (
+ TCK => TCK,
+ TMS => TMS,
+ TRST_N => TRST_N,
+ STATE => S_STATE,
+ NEXT_STATE => S_NEXT_STATE,
+ DRSTATE => S_DRSTATE,
+ IRSTATE => S_IRSTATE
+ );
+
+ -- The instruction register
+ IRBLOCK: c4m_jtag_irblock
+ generic map (
+ IR_WIDTH => IR_WIDTH
+ )
+ port map (
+ TCK => TCK,
+ TDI => TDI,
+ TDO => IR_TDO,
+ TDO_EN => IR_TDO_EN,
+ STATE => S_STATE,
+ NEXT_STATE => S_NEXT_STATE,
+ IRSTATE => S_IRSTATE,
+ IR => S_IR
+ );
+
+ -- The ID
+ IDBLOCK: c4m_jtag_idblock
+ generic map (
+ IR_WIDTH => IR_WIDTH,
+ PART_NUMBER => PART_NUMBER,
+ MANUFACTURER => MANUFACTURER
+ )
+ port map (
+ TCK => TCK,
+ TDI => TDI,
+ TDO => ID_TDO,
+ TDO_EN => ID_TDO_EN,
+ STATE => S_STATE,
+ NEXT_STATE => S_NEXT_STATE,
+ DRSTATE => S_DRSTATE,
+ IR => S_IR
+ );
+
+ -- The IOS
+ IOBLOCK: c4m_jtag_ioblock
+ generic map (
+ IR_WIDTH => IR_WIDTH,
+ IOS => IOS
+ )
+ port map (
+ TCK => TCK,
+ TDI => TDI,
+ TDO => IO_TDO,
+ TDO_EN => IO_TDO_EN,
+ STATE => S_STATE,
+ NEXT_STATE => S_NEXT_STATE,
+ DRSTATE => S_DRSTATE,
+ IR => S_IR,
+ CORE_OUT => CORE_OUT,
+ CORE_IN => CORE_IN,
+ CORE_EN => CORE_EN,
+ PAD_OUT => PAD_OUT,
+ PAD_IN => PAD_IN,
+ PAD_EN => PAD_EN
+ );
+
+ TDO <= IR_TDO when IR_TDO_EN = '1' else
+ ID_TDO when ID_TDO_EN = '1' else
+ IO_TDO when IO_TDO_EN = '1' else
+ '0';
+
+ CHECK_EN: if DEBUG generate
+ signal EN: std_logic_vector(2 downto 0) := "000";
+ begin
+ EN <= IR_TDO_EN & ID_TDO_EN & IO_TDO_EN;
+ assert EN = "000" or EN = "100" or EN = "010" or EN = "001"
+ report "TDO conflict in c4m_jtag_tap_controller"
+ severity ERROR;
+ end generate CHECK_EN;
+end rtl;
+
+
--- /dev/null
+-- The JTAG state machine
+-- This is implemented based on the IEEE 1149.1 standard
+
+library ieee;
+use ieee.std_logic_1164.ALL;
+
+use work.c4m_jtag.ALL;
+
+entity c4m_jtag_tap_fsm is
+ port (
+ -- The TAP signals
+ TCK: in std_logic;
+ TMS: in std_logic;
+ TRST_N: in std_logic;
+
+ -- The state outputs
+ STATE: out TAPSTATE_TYPE;
+ NEXT_STATE: out TAPSTATE_TYPE;
+ DRSTATE: out std_logic;
+ IRSTATE: out std_logic
+ );
+end c4m_jtag_tap_fsm;
+
+architecture rtl of c4m_jtag_tap_fsm is
+ signal S_STATE: TAPSTATE_TYPE;
+ signal S_NEXT_STATE: TAPSTATE_TYPE;
+ signal S_DRSTATE: std_logic;
+ signal S_IRSTATE: std_logic;
+ signal NEXT_DRSTATE: std_logic;
+ signal NEXT_IRSTATE: std_logic;
+begin
+ STATE <= S_STATE;
+ NEXT_STATE <= S_NEXT_STATE;
+ DRSTATE <= S_DRSTATE;
+ IRSTATE <= S_IRSTATE;
+
+ process (TCK, TRST_N)
+ begin
+ if TRST_N = '0' then
+ S_DRSTATE <= '0';
+ S_IRSTATE <= '0';
+ S_STATE <= TestLogicReset;
+ elsif rising_edge(TCK) then
+ S_STATE <= S_NEXT_STATE;
+ S_DRSTATE <= NEXT_DRSTATE;
+ S_IRSTATE <= NEXT_IRSTATE;
+ end if;
+ end process;
+
+ NEXT_DRSTATE <=
+ '0' when S_NEXT_STATE = TestLogicReset else
+ '0' when S_NEXT_STATE = RunTestIdle else
+ '1' when S_NEXT_STATE = SelectDRScan else
+ '0' when S_NEXT_STATE = SelectIRScan else
+ S_DRSTATE;
+ NEXT_IRSTATE <=
+ '0' when S_NEXT_STATE = TestLogicReset else
+ '0' when S_NEXT_STATE = RunTestIdle else
+ '0' when S_NEXT_STATE = SelectDRScan else
+ '1' when S_NEXT_STATE = SelectIRScan else
+ S_IRSTATE;
+
+ process (S_STATE, TMS)
+ begin
+ case S_STATE is
+ when TestLogicReset =>
+ if (TMS = '0') then
+ S_NEXT_STATE <= RunTestIdle;
+ else
+ S_NEXT_STATE <= TestLogicReset;
+ end if;
+
+ when RunTestIdle =>
+ if (TMS = '0') then
+ S_NEXT_STATE <= RunTestIdle;
+ else
+ S_NEXT_STATE <= SelectDRScan;
+ end if;
+
+ when SelectDRScan =>
+ if (TMS = '0') then
+ S_NEXT_STATE <= Capture;
+ else
+ S_NEXT_STATE <= SelectIRScan;
+ end if;
+
+ when SelectIRScan =>
+ if (TMS = '0') then
+ S_NEXT_STATE <= Capture;
+ else
+ S_NEXT_STATE <= TestLogicReset;
+ end if;
+
+ when Capture =>
+ if (TMS = '0') then
+ S_NEXT_STATE <= Shift;
+ else
+ S_NEXT_STATE <= Exit1;
+ end if;
+
+ when Shift =>
+ if (TMS = '0') then
+ S_NEXT_STATE <= Shift;
+ else
+ S_NEXT_STATE <= Exit1;
+ end if;
+
+ when Exit1 =>
+ if (TMS = '0') then
+ S_NEXT_STATE <= Pause;
+ else
+ S_NEXT_STATE <= Update;
+ end if;
+
+ when Pause =>
+ if (TMS = '0') then
+ S_NEXT_STATE <= Pause;
+ else
+ S_NEXT_STATE <= Exit2;
+ end if;
+
+ when Exit2 =>
+ if (TMS = '0') then
+ S_NEXT_STATE <= Shift;
+ else
+ S_NEXT_STATE <= Update;
+ end if;
+
+ when Update =>
+ if (TMS = '0') then
+ S_NEXT_STATE <= RunTestIdle;
+ else
+ S_NEXT_STATE <= SelectDRScan;
+ end if;
+
+ when others =>
+ S_NEXT_STATE <= TestLogicReset;
+ end case;
+ end process;
+end rtl;
+++ /dev/null
-#!/bin/env python3
-import os
-
-from nmigen import *
-from nmigen.build import *
-from nmigen.lib.io import *
-
-from wishbone import Wishbone
-
-__all__ = [
- "PmodJTAGMasterResource",
- "PmodJTAGMasterAResource",
- "PmodJTAGSlaveResource",
- "PmodJTAGSlaveAResource",
- "JTAG",
-]
-
-#TODO: Provide more documentation
-
-def PmodJTAGMasterResource(name, number, *, pmod, attrs=Attrs(IOSTANDARD="LVCMOS33")):
- return Resource(name, number,
- Subsignal("TCK", Pins("1", dir="o", conn=("pmod", pmod))),
- Subsignal("TMS", Pins("2", dir="o", conn=("pmod", pmod))),
- Subsignal("TDO", Pins("3", dir="o", conn=("pmod", pmod))),
- Subsignal("TDI", Pins("4", dir="i", conn=("pmod", pmod))),
- attrs,
- )
-
-def PmodJTAGMasterAResource(name, number, *, pmod, attrs=Attrs(IOSTANDARD="LVCMOS33")):
- return Resource(name, number,
- Subsignal("TCK", Pins("1", dir="o", conn=("pmod", pmod))),
- Subsignal("TMS", Pins("2", dir="o", conn=("pmod", pmod))),
- Subsignal("TDO", Pins("3", dir="o", conn=("pmod", pmod))),
- Subsignal("TDI", Pins("4", dir="i", conn=("pmod", pmod))),
- Subsignal("TRST", PinsN("7", dir="o", conn=("pmod", pmod))),
- attrs,
- )
-
-def PmodJTAGSlaveResource(name, number, *, pmod, attrs=Attrs(IOSTANDARD="LVCMOS33")):
- return Resource(name, number,
- Subsignal("TCK", Pins("1", dir="i", conn=("pmod", pmod))),
- Subsignal("TMS", Pins("2", dir="i", conn=("pmod", pmod))),
- Subsignal("TDI", Pins("3", dir="i", conn=("pmod", pmod))),
- Subsignal("TDO", Pins("4", dir="o", conn=("pmod", pmod))),
- attrs,
- )
-
-def PmodJTAGSlaveAResource(name, number, *, pmod, attrs=Attrs(IOSTANDARD="LVCMOS33")):
- return Resource(name, number,
- Subsignal("TCK", Pins("1", dir="i", conn=("pmod", pmod))),
- Subsignal("TMS", Pins("2", dir="i", conn=("pmod", pmod))),
- Subsignal("TDI", Pins("3", dir="i", conn=("pmod", pmod))),
- Subsignal("TDO", Pins("4", dir="o", conn=("pmod", pmod))),
- Subsignal("TRST", PinsN("7", dir="i", conn=("pmod", pmod))),
- attrs,
- )
-
-
-class ShiftReg(Elaboratable):
- def __init__(self, ircodes, length, domain):
- # The sr record will be returned to user code
- self.sr = Record([("i", length), ("o", length), ("oe", len(ircodes)), ("ack", 1)])
- # The next attributes are for JTAG class usage only
- self.ir = None # made None as width is not known yet
- self.tdi = Signal()
- self.tdo = Signal()
- self.tdo_en = Signal()
- self.capture = Signal()
- self.shift = Signal()
- self.update = Signal()
- self.jtag_cd = None # The JTAG clock domain
-
- ##
-
- self._ircodes = ircodes
- self._domain = domain
-
- def elaborate(self, platform):
- length = len(self.sr.o)
- domain = self._domain
-
- m = Module()
-
- m.domains.jtag = self.jtag_cd
-
- sr_jtag = Signal(length)
-
- assert isinstance(self.ir, Signal)
- isir = Signal(len(self._ircodes))
- capture = Signal()
- shift = Signal()
- update = Signal()
- m.d.comb += [
- isir.eq(Cat(self.ir == ircode for ircode in self._ircodes)),
- capture.eq((isir != 0) & self.capture),
- shift.eq((isir != 0) & self.shift),
- update.eq((isir != 0) & self.update),
- ]
-
- # On update set o, oe and wait for ack
- # update signal is on JTAG clockdomain, latch it
- update_core = Signal()
- m.d[domain] += update_core.eq(update) # This is CDC from JTAG domain to given domain
- with m.FSM(domain=domain):
- with m.State("IDLE"):
- m.d.comb += self.sr.oe.eq(0)
- with m.If(update_core):
- # Latch sr_jtag cross domain but it should be stable due to latching of update_core
- m.d[domain] += self.sr.o.eq(sr_jtag)
- # Wait one cycle to raise oe so sr.o has one more cycle to stabilize
- m.next = "WAIT4ACK"
- with m.State("WAIT4ACK"):
- m.d.comb += self.sr.oe.eq(isir)
- with m.If(self.sr.ack):
- m.next = "WAIT4END"
- with m.State("WAIT4END"):
- m.d.comb += self.sr.oe.eq(0)
- with m.If(~update_core):
- m.next = "IDLE"
-
- m.d.comb += [
- self.tdo.eq(sr_jtag[0]),
- self.tdo_en.eq(shift),
- ]
-
- with m.If(shift):
- m.d.jtag += sr_jtag.eq(Cat(sr_jtag[1:], self.tdi))
- with m.If(capture):
- m.d.jtag += sr_jtag.eq(self.sr.i)
-
- return m
-
-class JTAGWishbone(Elaboratable):
- def __init__(self, sr_addr, sr_data, wb, domain):
- self._sr_addr = sr_addr
- self._sr_data = sr_data
- self._wb = wb
- self._domain = domain
-
- # To be set by JTAG
- self._ir = None
-
- def elaborate(self, platform):
- sr_addr = self._sr_addr
- sr_data = self._sr_data
- wb = self._wb
- domain = self._domain
- ir = self._ir
-
- m = Module()
-
- if hasattr(wb, "sel"):
- # Always selected
- m.d.comb += [s.eq(1) for s in wb.sel]
-
- # Immediately ack oe
- m.d[domain] += [
- sr_addr.ack.eq(sr_addr.oe),
- sr_data.ack.eq(sr_data.oe != 0),
- ]
-
- with m.FSM(domain=domain) as fsm:
- with m.State("IDLE"):
- m.d.comb += [
- wb.cyc.eq(0),
- wb.stb.eq(0),
- wb.we.eq(0),
- ]
- with m.If(sr_addr.oe): # WBADDR code
- m.d[domain] += wb.addr.eq(sr_addr.o)
- m.next = "READ"
- with m.If(sr_data.oe[0]): # WBREAD code
- m.d[domain] += wb.addr.eq(wb.addr + 1)
- m.next = "READ"
- with m.If(sr_data.oe[1]): # WBWRITE code
- m.d[domain] += wb.dat_w.eq(sr_data.o)
- m.next = "WRITEREAD"
- with m.State("READ"):
- m.d.comb += [
- wb.cyc.eq(1),
- wb.stb.eq(1),
- wb.we.eq(0),
- ]
- with m.If(~wb.stall):
- m.next = "READACK"
- with m.State("READACK"):
- m.d.comb += [
- wb.cyc.eq(1),
- wb.stb.eq(0),
- wb.we.eq(0),
- ]
- with m.If(wb.ack):
- m.d[domain] += sr_data.i.eq(wb.dat_r)
- m.next = "IDLE"
- with m.State("WRITEREAD"):
- m.d.comb += [
- wb.cyc.eq(1),
- wb.stb.eq(1),
- wb.we.eq(1),
- ]
- with m.If(~wb.stall):
- m.next = "WRITEREADACK"
- with m.State("WRITEREADACK"):
- m.d.comb += [
- wb.cyc.eq(1),
- wb.stb.eq(0),
- wb.we.eq(0),
- ]
- with m.If(wb.ack):
- m.d[domain] += wb.addr.eq(wb.addr + 1)
- m.next = "READ"
-
- return m
-
-
-class JTAG(Elaboratable):
- @staticmethod
- def _add_files(platform, prefix):
- d = os.path.realpath("{0}{1}{2}{1}vhdl".format(
- os.path.dirname(__file__), os.path.sep, os.path.pardir
- )) + os.path.sep
- for fname in [
- "c4m_jtag_pkg.vhdl",
- "c4m_jtag_idblock.vhdl",
- "c4m_jtag_iocell.vhdl",
- "c4m_jtag_ioblock.vhdl",
- "c4m_jtag_irblock.vhdl",
- "c4m_jtag_tap_fsm.vhdl",
- "c4m_jtag_tap_controller.vhdl",
- ]:
- f = open(d + fname, "r")
- platform.add_file(prefix + fname, f)
- f.close()
-
-
- def __init__(self, io_count, *, ir_width=None, manufacturer_id=Const(0b10001111111, 11),
- part_number=Const(1, 16), version=Const(0, 4)
- ):
- assert(isinstance(io_count, int) and io_count > 0)
- assert((ir_width is None) or (isinstance(ir_width, int) and ir_width >= 2))
- assert(len(version) == 4)
-
- # TODO: Handle IOs with different directions
- self.tck = Signal()
- self.tms = Signal()
- self.tdo = Signal()
- self.tdi = Signal()
- self.core = Array(Pin(1, "io") for _ in range(io_count)) # Signals to use for core
- self.pad = Array(Pin(1, "io") for _ in range(io_count)) # Signals going to IO pads
-
- self.jtag_cd = ClockDomain(name="jtag", local=True) # Own clock domain using TCK as clock signal
-
- ##
-
- self._io_count = io_count
- self._ir_width = ir_width
- self._manufacturer_id = manufacturer_id
- self._part_number = part_number
- self._version = version
-
- self._ircodes = [0, 1, 2] # Already taken codes, all ones added at the end
- self._srs = []
-
- self._wbs = []
-
- def elaborate(self, platform):
- JTAG._add_files(platform, "jtag" + os.path.sep)
-
- m = Module()
-
- tdo_jtag = Signal()
- reset = Signal()
- capture = Signal()
- shift = Signal()
- update = Signal()
-
-
- ir_max = max(self._ircodes) + 1 # One extra code needed with all ones
- ir_width = len("{:b}".format(ir_max))
- if self._ir_width is not None:
- assert self._ir_width >= ir_width, "Specified JTAG IR width not big enough for allocated shiift registers"
- ir_width = self._ir_width
- ir = Signal(ir_width)
-
- core_i = Cat(pin.i for pin in self.core)
- core_o = Cat(pin.o for pin in self.core)
- core_oe = Cat(pin.oe for pin in self.core)
- pad_i = Cat(pin.i for pin in self.pad)
- pad_o = Cat(pin.o for pin in self.pad)
- pad_oe = Cat(pin.oe for pin in self.pad)
-
- params = {
- "p_IOS": self._io_count,
- "p_IR_WIDTH": ir_width,
- "p_MANUFACTURER": self._manufacturer_id,
- "p_PART_NUMBER": self._part_number,
- "p_VERSION": self._version,
- "i_TCK": self.tck,
- "i_TMS": self.tms,
- "i_TDI": self.tdi,
- "o_TDO": tdo_jtag,
- "i_TRST_N": Const(1),
- "o_RESET": reset,
- "o_DRCAPTURE": capture,
- "o_DRSHIFT": shift,
- "o_DRUPDATE": update,
- "o_IR": ir,
- "o_CORE_IN": core_i,
- "i_CORE_OUT": core_o,
- "i_CORE_EN": core_oe,
- "i_PAD_IN": pad_i,
- "o_PAD_OUT": pad_o,
- "o_PAD_EN": pad_oe,
- }
- m.submodules.tap = Instance("c4m_jtag_tap_controller", **params)
-
- m.d.comb += [
- self.jtag_cd.clk.eq(self.tck),
- self.jtag_cd.rst.eq(reset),
- ]
-
- for i, sr in enumerate(self._srs):
- m.submodules["sr{}".format(i)] = sr
- sr.ir = ir
- m.d.comb += [
- sr.tdi.eq(self.tdi),
- sr.capture.eq(capture),
- sr.shift.eq(shift),
- sr.update.eq(update),
- ]
-
- if len(self._srs) > 0:
- first = True
- for sr in self._srs:
- if first:
- first = False
- with m.If(sr.tdo_en):
- m.d.comb += self.tdo.eq(sr.tdo)
- else:
- with m.Elif(sr.tdo_en):
- m.d.comb += self.tdo.eq(sr.tdo)
- with m.Else():
- m.d.comb += self.tdo.eq(tdo_jtag)
- else:
- m.d.comb += self.tdo.eq(tdo_jtag)
-
- for i, wb in enumerate(self._wbs):
- m.submodules["wb{}".format(i)] = wb
- wb._ir = ir
-
- return m
-
-
- def add_shiftreg(self, ircode, length, domain="sync"):
- """Add a shift register to the JTAG interface
-
- Parameters:
- - ircode: code(s) for the IR; int or sequence of ints. In the latter case this
- shiftreg is shared between different IR codes.
- - length: the length of the shift register
- - domain: the domain on which the signal will be used"""
-
- try:
- ir_it = iter(ircode)
- ircodes = ircode
- except TypeError:
- ir_it = ircodes = (ircode,)
- for _ircode in ir_it:
- assert(isinstance(_ircode, int) and _ircode > 0 and _ircode not in self._ircodes)
-
- sr = ShiftReg(ircodes, length, domain)
- sr.jtag_cd = self.jtag_cd
- self._ircodes.extend(ircodes)
- self._srs.append(sr)
-
- return sr.sr
-
-
- def add_wishbone(self, ircodes, address_width, data_width, sel_width=None, domain="sync"):
- """Add a wishbone interface
-
- Parameters:
- - ircodes: sequence of three integer for the JTAG IR codes;
- they represent resp. WBADDR, WBREAD and WBREADWRITE. First code
- has a shift register of length 'address_width', the two other codes
- share a shift register of length data_width.
- - address_width: width of the address
- - data_width: width of the data"""
-
- assert len(ircodes) == 3
-
- sr_addr = self.add_shiftreg(ircodes[0], address_width, domain=domain)
- sr_data = self.add_shiftreg(ircodes[1:], data_width, domain=domain)
-
- wb = Wishbone(data_width=data_width, address_width=address_width, sel_width=sel_width, master=True)
-
- self._wbs.append(JTAGWishbone(sr_addr, sr_data, wb, domain))
-
- return wb
+++ /dev/null
--- The JTAG id and bypass handling block
-
-library ieee;
-use ieee.std_logic_1164.ALL;
-
-use work.c4m_jtag.ALL;
-
-entity c4m_jtag_idblock is
- generic (
- IR_WIDTH: integer := 2;
-
- MANUFACTURER: std_logic_vector(10 downto 0) := "10001111111";
- PART_NUMBER: std_logic_vector(15 downto 0) := "0000000000000001";
- VERSION: std_logic_vector(3 downto 0) := "0000"
- );
- port (
- -- needed TAP signals
- TCK: in std_logic;
- TDI: in std_logic;
- TDO: out std_logic;
- TDO_EN: out std_logic := '0';
-
- -- JTAG state
- STATE: in TAPSTATE_TYPE;
- NEXT_STATE: in TAPSTATE_TYPE;
- DRSTATE: in std_logic;
-
- -- The instruction
- IR: in std_logic_vector(IR_WIDTH-1 downto 0)
- );
-end c4m_jtag_idblock;
-
-architecture rtl of c4m_jtag_idblock is
- constant IDCODE: std_logic_vector(31 downto 0) := VERSION & PART_NUMBER & MANUFACTURER & "1";
-
- signal SR_ID: std_logic_vector(31 downto 0);
- signal EN_TDO: boolean;
-
- constant CMD_IDCODE: std_logic_vector(IR_WIDTH-1 downto 0) := c4m_jtag_cmd_idcode(IR_WIDTH);
- constant CMD_BYPASS: std_logic_vector(IR_WIDTH-1 downto 0) := c4m_jtag_cmd_bypass(IR_WIDTH);
-begin
- process (TCK)
- begin
- if rising_edge(TCK) then
- if DRSTATE = '1' then
- case STATE is
- when Capture =>
- SR_ID <= IDCODE;
-
- when Shift =>
- if IR = CMD_IDCODE then
- SR_ID(30 downto 0) <= SR_ID(31 downto 1);
- SR_ID(31) <= TDI;
- elsif IR = CMD_BYPASS then
- SR_ID(0) <= TDI;
- else
- null;
- end if;
-
- when others =>
- null;
- end case;
- end if;
- end if;
- end process;
-
- EN_TDO <= STATE = Shift and DRSTATE = '1' and (IR = CMD_IDCODE or IR = CMD_BYPASS);
- TDO <= SR_ID(0) when EN_TDO else
- '0';
- TDO_EN <= '1' when EN_TDO else
- '0';
-end rtl;
+++ /dev/null
--- The block of io cells with JTAG boundary scan support
-
-library ieee;
-use ieee.std_logic_1164.ALL;
-
-use work.c4m_jtag.ALL;
-
-entity c4m_jtag_ioblock is
- generic (
- IR_WIDTH: integer := 2;
- IOS: integer := 1
- );
- port (
- -- needed TAP signals
- TCK: in std_logic;
- TDI: in std_logic;
- TDO: out std_logic;
- TDO_EN: out std_logic := '0';
-
- -- JTAG state
- STATE: in TAPSTATE_TYPE;
- NEXT_STATE: in TAPSTATE_TYPE;
- DRSTATE: in std_logic;
-
- -- The instruction
- IR: in std_logic_vector(IR_WIDTH-1 downto 0);
-
- -- The I/O access ports
- CORE_OUT: in std_logic_vector(IOS-1 downto 0);
- CORE_IN: out std_logic_vector(IOS-1 downto 0);
- CORE_EN: in std_logic_vector(IOS-1 downto 0);
-
- -- The pad connections
- PAD_OUT: out std_logic_vector(IOS-1 downto 0);
- PAD_IN: in std_logic_vector(IOS-1 downto 0);
- PAD_EN: out std_logic_vector(IOS-1 downto 0)
- );
-end c4m_jtag_ioblock;
-
-architecture rtl of c4m_jtag_ioblock is
- signal IOMODE: SRIOMODE_TYPE;
- signal SAMPLEMODE: SRSAMPLEMODE_TYPE;
- signal ISSAMPLECMD: boolean;
-
- signal BDSR_IN: std_logic_vector(IOS-1 downto 0);
- signal BDSR_OUT: std_logic_vector(IOS-1 downto 0);
-
- constant CMD_SAMPLEPRELOAD: std_logic_vector(IR_WIDTH-1 downto 0) := c4m_jtag_cmd_samplepreload(IR_WIDTH);
- constant CMD_EXTEST: std_logic_vector(IR_WIDTH-1 downto 0) := c4m_jtag_cmd_extest(IR_WIDTH);
-begin
- -- JTAG baundary scan IO cells
- IOGEN: for i in 0 to IOS-1 generate
- begin
- IOCELL: c4m_jtag_iocell
- port map (
- CORE_IN => CORE_IN(i),
- CORE_OUT => CORE_OUT(i),
- CORE_EN => CORE_EN(i),
- PAD_IN => PAD_IN(i),
- PAD_OUT => PAD_OUT(i),
- PAD_EN => PAD_EN(i),
- BDSR_IN => BDSR_IN(i),
- BDSR_OUT => BDSR_OUT(i),
- IOMODE => IOMODE,
- SAMPLEMODE => SAMPLEMODE,
- TCK => TCK
- );
- end generate;
- BDSRCONN: for i in 0 to IOS-2 generate
- begin
- BDSR_IN(i) <= BDSR_OUT(i+1);
- end generate;
- BDSR_IN(IOS-1) <= TDI;
-
- -- Set IOMODE
- -- Currently SR_2Core or SR_Z are not used
- IOMODE <= SR_2Pad when IR = CMD_EXTEST else
- SR_Through;
-
- -- Set SAMPLEMODE
- ISSAMPLECMD <= (IR = CMD_SAMPLEPRELOAD or IR = CMD_EXTEST) and DRSTATE = '1';
- SAMPLEMODE <= SR_Sample when ISSAMPLECMD and STATE = Capture else
- SR_Update when ISSAMPLECMD and STATE = Update else
- SR_Shift when ISSAMPLECMD and STATE = Shift else
- SR_Normal;
-
- TDO <= BDSR_OUT(0) when ISSAMPLECMD and STATE = Shift else
- '0';
- TDO_EN <= '1' when ISSAMPLECMD and STATE = Shift else
- '0';
-end rtl;
+++ /dev/null
--- An JTAG boundary scan for bidirectional I/O
-
-library ieee;
-use ieee.std_logic_1164.ALL;
-
-use work.c4m_jtag.ALL;
-
-entity c4m_jtag_iocell is
- generic (
- IR_WIDTH: integer := 2
- );
- port (
- -- core connections
- CORE_IN: out std_logic;
- CORE_OUT: in std_logic;
- CORE_EN: in std_logic;
-
- -- pad connections
- PAD_IN: in std_logic;
- PAD_OUT: out std_logic;
- PAD_EN: out std_logic;
-
- -- BD shift register
- BDSR_IN: in std_logic;
- BDSR_OUT: out std_logic;
-
- -- Mode of I/O cell
- IOMODE: in SRIOMODE_TYPE;
- SAMPLEMODE: in SRSAMPLEMODE_TYPE;
- TCK: in std_logic
- );
-end c4m_jtag_iocell;
-
-architecture rtl of c4m_jtag_iocell is
- signal SR_IOIN: std_logic;
- signal SR_IOOUT: std_logic;
- signal SR_IOEN: std_logic;
-
- signal CORE_IN_BD: std_logic;
- signal PAD_OUT_BD: std_logic;
- signal PAD_EN_BD: std_logic;
-begin
- with IOMODE select
- CORE_IN <=
- PAD_IN when SR_Through | SR_Z,
- PAD_IN when SR_2Pad,
- CORE_IN_BD when SR_2Core,
- 'X' when others;
-
- with IOMODE select
- PAD_OUT <=
- CORE_OUT when SR_Through,
- PAD_OUT_BD when SR_2Pad,
- '0' when SR_2Core | SR_Z,
- 'X' when others;
-
- with IOMODE select
- PAD_EN <=
- CORE_EN when SR_Through,
- PAD_EN_BD when SR_2Pad,
- '0' when SR_2Core | SR_Z,
- 'X' when others;
-
- process (TCK)
- begin
- -- Sampling of inputs and shifting of boundary scan SR needs to be done on
- -- rising edge of TCK
- if rising_edge(TCK) then
- case SAMPLEMODE is
- when SR_Sample =>
- SR_IOIN <= PAD_IN;
- SR_IOOUT <= CORE_OUT;
- SR_IOEN <= CORE_EN;
-
- when SR_Shift =>
- SR_IOIN <= BDSR_IN;
- SR_IOOUT <= SR_IOIN;
- SR_IOEN <= SR_IOOUT;
-
- when others =>
- null;
- end case;
- end if;
-
- -- Update of output from boundary scan SR needs to be done on falling edge
- -- of TCK
- if falling_edge(TCK) then
- case SAMPLEMODE is
- when SR_Update =>
- CORE_IN_BD <= SR_IOIN;
- PAD_OUT_BD <= SR_IOOUT;
- PAD_EN_BD <= SR_IOEN;
-
- when others =>
- null;
- end case;
- end if;
- end process;
-
- BDSR_OUT <= SR_IOEN;
-end rtl;
+++ /dev/null
--- Handle the instruction register for the JTAG controller
-
-library ieee;
-use ieee.std_logic_1164.ALL;
-
-use work.c4m_jtag.ALL;
-
-entity c4m_jtag_irblock is
- generic (
- IR_WIDTH: integer := 2
- );
- port (
- -- needed TAP signals
- TCK: in std_logic;
- TDI: in std_logic;
- TDO: out std_logic;
- TDO_EN: out std_logic := '0';
-
- -- JTAG state
- STATE: in TAPSTATE_TYPE;
- NEXT_STATE: in TAPSTATE_TYPE;
- IRSTATE: in std_logic;
-
- -- instruction register
- IR: out std_logic_vector(IR_WIDTH-1 downto 0)
- );
-end c4m_jtag_irblock;
-
-architecture rtl of c4m_jtag_irblock is
- signal SHIFT_IR: std_logic_vector(IR_WIDTH-1 downto 0);
-
- constant CMD_IDCODE: std_logic_vector(IR_WIDTH-1 downto 0) := c4m_jtag_cmd_idcode(IR_WIDTH);
-begin
- process (TCK, STATE)
- begin
- if STATE = TestLogicReset then
- SHIFT_IR <= (others => '0');
- IR <= CMD_IDCODE;
- elsif rising_edge(TCK) then
- if IRSTATE = '1' then
- case STATE is
- when Capture =>
- SHIFT_IR(1) <= '0';
- SHIFT_IR(0) <= '1';
-
- when Shift =>
- SHIFT_IR(IR_WIDTH-2 downto 0) <= SHIFT_IR(IR_WIDTH-1 downto 1);
- SHIFT_IR(IR_WIDTH-1) <= TDI;
-
- when Update =>
- IR <= SHIFT_IR;
-
- when others =>
- null;
- end case;
- end if;
- end if;
- end process;
-
- TDO <= SHIFT_IR(0) when STATE = Shift and IRSTATE = '1' else
- '0';
- TDO_EN <= '1' when STATE = Shift and IRSTATE = '1' else
- '0';
-end rtl;
+++ /dev/null
--- Package of jtag support code from the Chips4Makers project
-library ieee;
-use ieee.std_logic_1164.ALL;
-
-package c4m_jtag is
- type TAPSTATE_TYPE is (
- TestLogicReset,
- RunTestIdle,
- SelectDRScan,
- SelectIRScan,
- Capture,
- Shift,
- Exit1,
- Pause,
- Exit2,
- Update
- );
- type SRIOMODE_TYPE is (
- SR_Through, -- Connect core signal to pad signals
- SR_2Pad, -- Connect BD to pad
- SR_2Core, -- Connect BD to core
- SR_Z -- pad is high impedance
- );
- type SRSAMPLEMODE_TYPE is (
- SR_Normal, -- No sampling or shifting
- SR_Sample, -- Sample IO state in BD SR on rising edge of TCK
- SR_Update, -- Update BD from SR on falling edge of TCK
- SR_Shift -- Shift the BD SR
- );
-
- component c4m_jtag_tap_fsm is
- port (
- -- The TAP signals
- TCK: in std_logic;
- TMS: in std_logic;
- TRST_N: in std_logic;
-
- -- The state outputs
- STATE: out TAPSTATE_TYPE;
- NEXT_STATE: out TAPSTATE_TYPE;
- DRSTATE: out std_logic;
- IRSTATE: out std_logic
- );
- end component c4m_jtag_tap_fsm;
-
- component c4m_jtag_irblock is
- generic (
- IR_WIDTH: integer := 2
- );
- port (
- -- needed TAP signals
- TCK: in std_logic;
- TDI: in std_logic;
- TDO: out std_logic;
- TDO_EN: out std_logic;
-
- -- JTAG state
- STATE: in TAPSTATE_TYPE;
- NEXT_STATE: in TAPSTATE_TYPE;
- IRSTATE: in std_logic;
-
- -- instruction register
- IR: out std_logic_vector(IR_WIDTH-1 downto 0)
- );
- end component c4m_jtag_irblock;
-
- component c4m_jtag_idblock is
- generic (
- IR_WIDTH: integer := 2;
-
- -- The default MANUFACTURING ID is not representing a valid
- -- manufacturer according to the JTAG standard
- MANUFACTURER: std_logic_vector(10 downto 0) := "10001111111";
- PART_NUMBER: std_logic_vector(15 downto 0) := "0000000000000001";
- VERSION: std_logic_vector(3 downto 0) := "0000"
- );
- port (
- -- needed TAP signals
- TCK: in std_logic;
- TDI: in std_logic;
- TDO: out std_logic;
- TDO_EN: out std_logic;
-
- -- JTAG state
- STATE: in TAPSTATE_TYPE;
- NEXT_STATE: in TAPSTATE_TYPE;
- DRSTATE: in std_logic;
-
- -- The instruction
- IR: in std_logic_vector(IR_WIDTH-1 downto 0)
- );
- end component c4m_jtag_idblock;
-
- component c4m_jtag_iocell is
- port (
- -- core connections
- CORE_IN: out std_logic;
- CORE_OUT: in std_logic;
- CORE_EN: in std_logic;
-
- -- pad connections
- PAD_IN: in std_logic;
- PAD_OUT: out std_logic;
- PAD_EN: out std_logic;
-
- -- BD shift register
- BDSR_IN: in std_logic;
- BDSR_OUT: out std_logic;
-
- -- Mode of I/O cell
- IOMODE: in SRIOMODE_TYPE;
- SAMPLEMODE: in SRSAMPLEMODE_TYPE;
- TCK: in std_logic
- );
- end component c4m_jtag_iocell;
-
- component c4m_jtag_ioblock is
- generic (
- IR_WIDTH: integer := 2;
- IOS: integer := 1
- );
- port (
- -- needed TAP signals
- TCK: in std_logic;
- TDI: in std_logic;
- TDO: out std_logic;
- TDO_EN: out std_logic;
-
- -- JTAG state
- STATE: in TAPSTATE_TYPE;
- NEXT_STATE: in TAPSTATE_TYPE;
- DRSTATE: in std_logic;
-
- -- The instruction
- IR: in std_logic_vector(IR_WIDTH-1 downto 0);
-
- -- The I/O access ports
- CORE_OUT: in std_logic_vector(IOS-1 downto 0);
- CORE_IN: out std_logic_vector(IOS-1 downto 0);
- CORE_EN: in std_logic_vector(IOS-1 downto 0);
-
- -- The pad connections
- PAD_OUT: out std_logic_vector(IOS-1 downto 0);
- PAD_IN: in std_logic_vector(IOS-1 downto 0);
- PAD_EN: out std_logic_vector(IOS-1 downto 0)
- );
- end component c4m_jtag_ioblock;
-
- component c4m_jtag_tap_controller is
- generic (
- DEBUG: boolean := false;
-
- IR_WIDTH: integer := 2;
- IOS: integer := 1;
-
- -- The default MANUFACTURING ID is not representing a valid
- -- manufacturer according to the JTAG standard
- MANUFACTURER: std_logic_vector(10 downto 0) := "10001111111";
- PART_NUMBER: std_logic_vector(15 downto 0) := "0000000000000001";
- VERSION: std_logic_vector(3 downto 0) := "0000"
- );
- port (
- -- The TAP signals
- TCK: in std_logic;
- TMS: in std_logic;
- TDI: in std_logic;
- TDO: out std_logic;
- TRST_N: in std_logic;
-
- -- The FSM state indicators
- RESET: out std_logic; -- In reset state
- DRCAPTURE: out std_logic; -- In DR_Capture state
- DRSHIFT: out std_logic; -- In DR_Shift state
- DRUPDATE: out std_logic; -- In DR_Update state
-
- -- The Instruction Register
- IR: out std_logic_vector(IR_WIDTH-1 downto 0);
-
- -- The I/O access ports
- CORE_IN: out std_logic_vector(IOS-1 downto 0);
- CORE_EN: in std_logic_vector(IOS-1 downto 0);
- CORE_OUT: in std_logic_vector(IOS-1 downto 0);
-
- -- The pad connections
- PAD_IN: in std_logic_vector(IOS-1 downto 0);
- PAD_EN: out std_logic_vector(IOS-1 downto 0);
- PAD_OUT: out std_logic_vector(IOS-1 downto 0)
- );
- end component c4m_jtag_tap_controller;
-
- function c4m_jtag_cmd_idcode(width: integer) return std_logic_vector;
- function c4m_jtag_cmd_bypass(width: integer) return std_logic_vector;
- function c4m_jtag_cmd_samplepreload(width: integer) return std_logic_vector;
- function c4m_jtag_cmd_extest(width: integer) return std_logic_vector;
-end c4m_jtag;
-
-package body c4m_jtag is
- function c4m_jtag_cmd_bypass(width: integer) return std_logic_vector is
- variable return_vector: std_logic_vector(width-1 downto 0);
- begin
- return_vector := (others => '1');
- return return_vector;
- end;
-
- function c4m_jtag_cmd_idcode(width: integer) return std_logic_vector is
- variable return_vector: std_logic_vector(width-1 downto 0);
- begin
- return_vector := (0 => '1', others => '0');
- return return_vector;
- end;
-
- function c4m_jtag_cmd_samplepreload(width: integer) return std_logic_vector is
- variable return_vector: std_logic_vector(width-1 downto 0);
- begin
- return_vector := (1 => '1', others => '0');
- return return_vector;
- end;
-
- function c4m_jtag_cmd_extest(width: integer) return std_logic_vector is
- variable return_vector: std_logic_vector(width-1 downto 0);
- begin
- return_vector := (others => '0');
- return return_vector;
- end;
-end package body;
+++ /dev/null
--- A JTAG complient tap controller implementation
--- This is implemented based on the IEEE 1149.1 standard
-
-library ieee;
-use ieee.std_logic_1164.ALL;
-
-use work.c4m_jtag.ALL;
-
-entity c4m_jtag_tap_controller is
- generic (
- DEBUG: boolean := false;
-
- IR_WIDTH: integer := 2;
- IOS: integer := 1;
-
- MANUFACTURER: std_logic_vector(10 downto 0) := "10001111111";
- PART_NUMBER: std_logic_vector(15 downto 0) := "0000000000000001";
- VERSION: std_logic_vector(3 downto 0) := "0000"
- );
- port (
- -- The TAP signals
- TCK: in std_logic;
- TMS: in std_logic;
- TDI: in std_logic;
- TDO: out std_logic;
- TRST_N: in std_logic;
-
- -- The FSM state indicators
- RESET: out std_logic;
- DRCAPTURE: out std_logic;
- DRSHIFT: out std_logic;
- DRUPDATE: out std_logic;
-
- -- The Instruction Register
- IR: out std_logic_vector(IR_WIDTH-1 downto 0);
-
- -- The I/O access ports
- CORE_IN: out std_logic_vector(IOS-1 downto 0);
- CORE_EN: in std_logic_vector(IOS-1 downto 0);
- CORE_OUT: in std_logic_vector(IOS-1 downto 0);
-
- -- The pad connections
- PAD_IN: in std_logic_vector(IOS-1 downto 0);
- PAD_EN: out std_logic_vector(IOS-1 downto 0);
- PAD_OUT: out std_logic_vector(IOS-1 downto 0)
- );
-end c4m_jtag_tap_controller;
-
-architecture rtl of c4m_jtag_tap_controller is
- signal S_STATE: TAPSTATE_TYPE;
- signal S_NEXT_STATE: TAPSTATE_TYPE;
- signal S_IRSTATE: std_logic;
- signal S_DRSTATE: std_logic;
- signal S_IR: std_logic_vector(IR_WIDTH-1 downto 0);
-
- signal IR_TDO: std_logic;
- signal IR_TDO_EN: std_logic;
- signal ID_TDO: std_logic;
- signal ID_TDO_EN: std_logic;
- signal IO_TDO: std_logic;
- signal IO_TDO_EN: std_logic;
-begin
- IR <= S_IR;
-
- RESET <= '1' when S_STATE = TestLogicReset else '0';
- DRCAPTURE <= '1' when S_STATE = Capture and S_DRSTATE = '1' else '0';
- DRSHIFT <= '1' when S_STATE = Shift and S_DRSTATE = '1' else '0';
- DRUPDATE <= '1' when S_STATE = Update and S_DRSTATE = '1' else '0';
-
- -- JTAG state machine
- FSM: c4m_jtag_tap_fsm
- port map (
- TCK => TCK,
- TMS => TMS,
- TRST_N => TRST_N,
- STATE => S_STATE,
- NEXT_STATE => S_NEXT_STATE,
- DRSTATE => S_DRSTATE,
- IRSTATE => S_IRSTATE
- );
-
- -- The instruction register
- IRBLOCK: c4m_jtag_irblock
- generic map (
- IR_WIDTH => IR_WIDTH
- )
- port map (
- TCK => TCK,
- TDI => TDI,
- TDO => IR_TDO,
- TDO_EN => IR_TDO_EN,
- STATE => S_STATE,
- NEXT_STATE => S_NEXT_STATE,
- IRSTATE => S_IRSTATE,
- IR => S_IR
- );
-
- -- The ID
- IDBLOCK: c4m_jtag_idblock
- generic map (
- IR_WIDTH => IR_WIDTH,
- PART_NUMBER => PART_NUMBER,
- MANUFACTURER => MANUFACTURER
- )
- port map (
- TCK => TCK,
- TDI => TDI,
- TDO => ID_TDO,
- TDO_EN => ID_TDO_EN,
- STATE => S_STATE,
- NEXT_STATE => S_NEXT_STATE,
- DRSTATE => S_DRSTATE,
- IR => S_IR
- );
-
- -- The IOS
- IOBLOCK: c4m_jtag_ioblock
- generic map (
- IR_WIDTH => IR_WIDTH,
- IOS => IOS
- )
- port map (
- TCK => TCK,
- TDI => TDI,
- TDO => IO_TDO,
- TDO_EN => IO_TDO_EN,
- STATE => S_STATE,
- NEXT_STATE => S_NEXT_STATE,
- DRSTATE => S_DRSTATE,
- IR => S_IR,
- CORE_OUT => CORE_OUT,
- CORE_IN => CORE_IN,
- CORE_EN => CORE_EN,
- PAD_OUT => PAD_OUT,
- PAD_IN => PAD_IN,
- PAD_EN => PAD_EN
- );
-
- TDO <= IR_TDO when IR_TDO_EN = '1' else
- ID_TDO when ID_TDO_EN = '1' else
- IO_TDO when IO_TDO_EN = '1' else
- '0';
-
- CHECK_EN: if DEBUG generate
- signal EN: std_logic_vector(2 downto 0) := "000";
- begin
- EN <= IR_TDO_EN & ID_TDO_EN & IO_TDO_EN;
- assert EN = "000" or EN = "100" or EN = "010" or EN = "001"
- report "TDO conflict in c4m_jtag_tap_controller"
- severity ERROR;
- end generate CHECK_EN;
-end rtl;
-
-
+++ /dev/null
--- The JTAG state machine
--- This is implemented based on the IEEE 1149.1 standard
-
-library ieee;
-use ieee.std_logic_1164.ALL;
-
-use work.c4m_jtag.ALL;
-
-entity c4m_jtag_tap_fsm is
- port (
- -- The TAP signals
- TCK: in std_logic;
- TMS: in std_logic;
- TRST_N: in std_logic;
-
- -- The state outputs
- STATE: out TAPSTATE_TYPE;
- NEXT_STATE: out TAPSTATE_TYPE;
- DRSTATE: out std_logic;
- IRSTATE: out std_logic
- );
-end c4m_jtag_tap_fsm;
-
-architecture rtl of c4m_jtag_tap_fsm is
- signal S_STATE: TAPSTATE_TYPE;
- signal S_NEXT_STATE: TAPSTATE_TYPE;
- signal S_DRSTATE: std_logic;
- signal S_IRSTATE: std_logic;
- signal NEXT_DRSTATE: std_logic;
- signal NEXT_IRSTATE: std_logic;
-begin
- STATE <= S_STATE;
- NEXT_STATE <= S_NEXT_STATE;
- DRSTATE <= S_DRSTATE;
- IRSTATE <= S_IRSTATE;
-
- process (TCK, TRST_N)
- begin
- if TRST_N = '0' then
- S_DRSTATE <= '0';
- S_IRSTATE <= '0';
- S_STATE <= TestLogicReset;
- elsif rising_edge(TCK) then
- S_STATE <= S_NEXT_STATE;
- S_DRSTATE <= NEXT_DRSTATE;
- S_IRSTATE <= NEXT_IRSTATE;
- end if;
- end process;
-
- NEXT_DRSTATE <=
- '0' when S_NEXT_STATE = TestLogicReset else
- '0' when S_NEXT_STATE = RunTestIdle else
- '1' when S_NEXT_STATE = SelectDRScan else
- '0' when S_NEXT_STATE = SelectIRScan else
- S_DRSTATE;
- NEXT_IRSTATE <=
- '0' when S_NEXT_STATE = TestLogicReset else
- '0' when S_NEXT_STATE = RunTestIdle else
- '0' when S_NEXT_STATE = SelectDRScan else
- '1' when S_NEXT_STATE = SelectIRScan else
- S_IRSTATE;
-
- process (S_STATE, TMS)
- begin
- case S_STATE is
- when TestLogicReset =>
- if (TMS = '0') then
- S_NEXT_STATE <= RunTestIdle;
- else
- S_NEXT_STATE <= TestLogicReset;
- end if;
-
- when RunTestIdle =>
- if (TMS = '0') then
- S_NEXT_STATE <= RunTestIdle;
- else
- S_NEXT_STATE <= SelectDRScan;
- end if;
-
- when SelectDRScan =>
- if (TMS = '0') then
- S_NEXT_STATE <= Capture;
- else
- S_NEXT_STATE <= SelectIRScan;
- end if;
-
- when SelectIRScan =>
- if (TMS = '0') then
- S_NEXT_STATE <= Capture;
- else
- S_NEXT_STATE <= TestLogicReset;
- end if;
-
- when Capture =>
- if (TMS = '0') then
- S_NEXT_STATE <= Shift;
- else
- S_NEXT_STATE <= Exit1;
- end if;
-
- when Shift =>
- if (TMS = '0') then
- S_NEXT_STATE <= Shift;
- else
- S_NEXT_STATE <= Exit1;
- end if;
-
- when Exit1 =>
- if (TMS = '0') then
- S_NEXT_STATE <= Pause;
- else
- S_NEXT_STATE <= Update;
- end if;
-
- when Pause =>
- if (TMS = '0') then
- S_NEXT_STATE <= Pause;
- else
- S_NEXT_STATE <= Exit2;
- end if;
-
- when Exit2 =>
- if (TMS = '0') then
- S_NEXT_STATE <= Shift;
- else
- S_NEXT_STATE <= Update;
- end if;
-
- when Update =>
- if (TMS = '0') then
- S_NEXT_STATE <= RunTestIdle;
- else
- S_NEXT_STATE <= SelectDRScan;
- end if;
-
- when others =>
- S_NEXT_STATE <= TestLogicReset;
- end case;
- end process;
-end rtl;
+++ /dev/null
-import cocotb
-from cocotb.triggers import Timer
-from cocotb.binary import BinaryValue
-
-class JTAGException(Exception):
- pass
-
-class JTAG_Clock(object):
- """
- Class for the JTAG clock, run cycle by cycle
- """
- def __init__(self, signal, period):
- self.signal = signal
- self.t = Timer(period/4)
-
- @cocotb.coroutine
- def Cycle(self, cycles=1):
- """
- Do one or more cycles
- Cycle start in middle of 0 pulse of the clock
- """
- for i in range(cycles):
- self.signal <= 0
- yield self.t
- self.signal <= 1
- yield self.t
- yield self.t
- self.signal <= 0
- yield self.t
-
-class JTAG_Master(object):
- """
- Class that will run JTAG commands, shift in and out data
- """
- #TODO: Handle a JTAG chain with more than one device
-
- def __init__(self, tck, tms, tdi, tdo, trst_n=None, clk_period=1000):
- self.tck = tck
- self.clkgen = JTAG_Clock(tck, clk_period)
- tck <= 0
- self.tms = tms
- tms <= 1
- self.tdi = tdi
- tdi <= 0
- self.tdo = tdo
- self.trst_n = trst_n
- if trst_n is not None:
- trst_n <= 1
- self.period = Timer(clk_period)
-
- # Standard commands
- # TODO: make IR length configurable; now 2 is assumed
- self.BYPASS = [1, 1]
- self.IDCODE = [0, 1]
- self.SAMPLEPRELOAD = [1, 0]
- self.EXTEST = [0, 0]
-
- # After command we always leave the controller in reset or runidle state
- # If value is None we will always reset the interface
- self.state = None
-
- # The methods of this class are coroutines. The results will be stored
- # in the result field
- self.result = None
-
- @cocotb.coroutine
- def cycle_clock(self, cycles=1):
- if self.state == "Run" and self.tms == 1:
- self.state = "Scan"
- yield self.clkgen.Cycle(cycles)
-
- @cocotb.coroutine
- def reset(self):
- if not self.trst_n is None:
- # Enable reset signal for one clock period
- self.trst_n <= 0
- yield self.period
- self.trst_n <= 1
- else:
- # 5 cycles with tms on 1 should reset the JTAG TAP controller
- self.tms <= 1
- yield self.cycle_clock(5)
-
- self.state = "Reset"
-
- self.result = None
-
- @cocotb.coroutine
- def change_state(self, tms_list):
- """
- Put TAP in other state by giving a TMS sequence
- This function does not detect if one ends up in reset or run
- state afterwards, self.state has to be updated by caller
- if that is the case.
- """
- tms_copy = list(tms_list)
- while tms_copy:
- self.tms <= tms_copy.pop()
- yield self.cycle_clock()
- self.result = None
-
- @cocotb.coroutine
- def change_to_run(self):
- """
- Put TAP in RunTestIdle state
- self.result is bool and true if TAP went through reset state
- """
- isreset = False
- if self.state is None:
- yield self.reset()
- if self.state is "Reset":
- isreset = True
- self.tms <= 0
- yield self.cycle_clock()
- self.state = "Run"
- assert(self.state == "Run")
- self.result = isreset
-
- @cocotb.coroutine
- def load_ir(self, cmd):
- cmd_copy = list(cmd)
- result = BinaryValue(bits=len(cmd_copy))
- l_result = list()
-
- yield self.change_to_run()
- # Go to Capture/IR
- yield self.change_state([0, 1, 1])
-
- # Shift the two
- self.tms <= 0
- while cmd_copy:
- # In first iteration we enter SHIFT state and tdo is made active
- yield self.cycle_clock()
- # For the last iteration tdi will be shifted when entering next state
- self.tdi <= cmd_copy.pop()
- l_result.insert(0, str(self.tdo))
-
- # Go to RunTestIdle
- yield self.change_state([0, 1, 1])
- self.state = "Run"
-
- @cocotb.coroutine
- def idcode(self):
- """
- Get the IDCODE from the device
- result will contain the 32 bit IDCODE of the device
- """
-
- result = BinaryValue(bits=32)
- l_result = list()
-
- # Keep tdi 0 for the whole run
- self.tdi <= 0
-
- yield self.change_to_run()
- if not self.result:
- # If TAP was not reset we have to load IDCODE command
- yield self.load_ir(self.IDCODE)
-
- # Should be again in RUN state
- assert(self.state == "Run")
-
- # Go to Shift/DR
- yield self.change_state([0, 0, 1])
-
- # Enter Shift; run for 32 cycles
- self.tms <= 0
- for i in range(32):
- l_result.insert(0, str(self.tdo))
- yield self.cycle_clock()
- result.binstr = "".join(l_result)
-
- # Go to RunTestIdle
- yield self.change_state([0, 1, 1])
- self.state = "Run"
-
- self.result = result
-
- @cocotb.coroutine
- def shift_data(self, data_in):
- """
- Shift data in through the JTAG and capture the output
- Input can be of type BinaryValue or an iterable value of 0 and 1s.
- Last bit will be shifted in first.
- result will contain the sample TDO with the same number of bits as the input
- """
- if isinstance(data_in, BinaryValue):
- data_copy = [int(c) for c in data_in.binstr]
- else:
- data_copy = list(data_in)
- result = BinaryValue()
- l_result = list()
-
- yield self.change_to_run()
- # Go to Capture/DR
- yield self.change_state([0, 1])
-
- # Shift data through
- self.tms <= 0
- while data_copy:
- yield self.cycle_clock()
- self.tdi <= data_copy.pop()
- l_result.insert(0, str(self.tdo))
- result.binstr = "".join(l_result)
-
- # Go to RunTestIdle
- yield self.change_state([0, 1, 1])
- self.state = "Run"
-
- self.result = result
+++ /dev/null
-import c4m_jtag_svfgrammar
-import cocotb
-from cocotb.binary import BinaryValue
-from functools import singledispatch
-
-def decodescanspec(node):
- length = int(str(node[2]))
- fstr = "{:0"+str(node[2])+"b}"
-
- g_tdi = node[4]
- g_tdo = node[5]
- g_mask = node[6]
- g_smask = node[7]
-
- if g_tdi is None:
- tdi = None
- else:
- tdi = BinaryValue(fstr.format(int(str(g_tdi[2]),16)), length)
-
- if g_tdo is None:
- tdo = None
- else:
- tdo = BinaryValue(fstr.format(int(str(g_tdo[3]),16)), length)
-
- if g_mask is None:
- mask = None
- else:
- mask = BinaryValue(fstr.format(int(str(g_mask[3]),16)), length)
-
- if g_smask is None:
- smask = None
- else:
- smask = BinaryValue(fstr.format(int(str(g_smask[3]),16)), length)
-
- return (length, tdi, tdo, mask, smask)
-
-
-class SVF_Executor(object):
- @cocotb.coroutine
- def execute(self, node):
- """This is the generic method"""
- self._p("generic")
- if False: # Make coroutine work
- yield PythonTrigger()
-
- @cocotb.coroutine
- def _execute_NOP(self, node):
- if False: # Make coroutine work
- yield PythonTrigger()
-
- @cocotb.coroutine
- def _execute_EndDR(self, node):
- self._p("EndDR ignored")
- if False: # Make coroutine work
- yield PythonTrigger()
-
- @cocotb.coroutine
- def _execute_EndIR(self, node):
- self._p("EndIR ignored")
- if False: # Make coroutine work
- yield PythonTrigger()
-
- @cocotb.coroutine
- def _execute_Frequency(self, node):
- self._p("Frequency ignored")
- if False: # Make coroutine work
- yield PythonTrigger()
-
- @cocotb.coroutine
- def _execute_HDR(self, node):
- self._p("HDR ignored")
- if False: # Make coroutine work
- yield PythonTrigger()
-
- @cocotb.coroutine
- def _execute_HIR(self, node):
- self._p("HIR ignored")
- if False: # Make coroutine work
- yield PythonTrigger()
-
- @cocotb.coroutine
- def _execute_SDR(self, node):
- self._p("Executing SDR")
- (length, tdi, tdo, mask, smask) = decodescanspec(node)
-
- samelength = length == self._d_length
- self._d_length = length
-
- if tdi is None:
- if not samelength:
- raise(JTAGException("TDI needs to be specified when length of data changes"))
- else:
- self._d_tdi = tdi
-
- if mask is not None:
- self._d_mask = mask
- elif not samelength:
- self._d_mask = None
-
- if smask is not None:
- self._d_smask = smask
- elif not samelength:
- self._d_smask = None
-
- yield self.master.shift_data(self._d_tdi)
- if tdo is not None:
- if self._d_mask is not None:
- raise(JTAGException("MASK not supported for SDR"))
- assert(self.result == tdo)
-
- @cocotb.coroutine
- def _execute_SIR(self, node):
- (length, tdi, tdo, mask, smask) = decodescanspec(node)
-
- samelength = length == self._i_length
- self._i_length = length
-
- if tdi is None:
- if not samelength:
- raise(JTAGException("TDI needs to be specified when length of data changes"))
- else:
- self._i_tdi = tdi
-
- if mask is not None:
- self._i_mask = mask
- elif not samelength:
- self._i_mask = None
-
- if smask is not None:
- self._i_smask = smask
- elif not samelength:
- self._i_smask = None
-
- self._p("Executing SIR ({})".format(self._i_tdi.integer))
-
- yield self.master.load_ir(self._i_tdi)
- if tdo is not None:
- if self._i_mask is not None:
- raise(JTAGException("MASK not supported for SIR"))
- assert(self.result == tdo)
-
-
- @cocotb.coroutine
- def _execute_State(self, node):
- self._p("State")
- if False: # Make coroutine work
- yield PythonTrigger()
-
- @cocotb.coroutine
- def _execute_TDR(self, node):
- self._p("TDR")
- if False: # Make coroutine work
- yield PythonTrigger()
-
- @cocotb.coroutine
- def _execute_TIR(self, node):
- self._p("TIR")
- if False: # Make coroutine work
- yield PythonTrigger()
-
- @cocotb.coroutine
- def _execute_Trst(self, node):
- self._p("TRST ignored")
- if False: # Make coroutine work
- yield PythonTrigger()
-
- @cocotb.coroutine
- def _execute_Runtest(self, node):
- if node[1] is not None:
- raise(JTAGException("State specification for RUNTEST not supported"))
- # TODO: cycle the right number of clocks or wait the right time
- yield(self.master.change_state([0]))
-
- @cocotb.coroutine
- def _execute_SVFFile(self, node):
- self._p("Executing SVFFile")
- for statement in node.elements[0]:
- yield self.execute(statement)
-
- def __init__(self, master):
- # master is assumed to be a JTAG_Master class
- # it needs to support methods load_ir() and shift_data()
- self.master = master
-
- # Due to bug in Grammar definition all possible classes have to have
- # a dispatch entry otherwise an error will be raised.
- self.execute = singledispatch(self.execute)
- self.execute.register(c4m_jtag_svfgrammar.EmptyLine, self._execute_NOP)
- self.execute.register(c4m_jtag_svfgrammar.Comment, self._execute_NOP)
- self.execute.register(c4m_jtag_svfgrammar.EndDR, self._execute_EndDR)
- self.execute.register(c4m_jtag_svfgrammar.EndIR, self._execute_EndIR)
- self.execute.register(c4m_jtag_svfgrammar.Frequency, self._execute_Frequency)
- self.execute.register(c4m_jtag_svfgrammar.HDR, self._execute_HDR)
- self.execute.register(c4m_jtag_svfgrammar.HIR, self._execute_HIR)
- self.execute.register(c4m_jtag_svfgrammar.Runtest, self._execute_Runtest)
- self.execute.register(c4m_jtag_svfgrammar.SDR, self._execute_SDR)
- self.execute.register(c4m_jtag_svfgrammar.SIR, self._execute_SIR)
- self.execute.register(c4m_jtag_svfgrammar.State, self._execute_State)
- self.execute.register(c4m_jtag_svfgrammar.TDR, self._execute_TDR)
- self.execute.register(c4m_jtag_svfgrammar.TIR, self._execute_TIR)
- self.execute.register(c4m_jtag_svfgrammar.Trst, self._execute_Trst)
- self.execute.register(c4m_jtag_svfgrammar.SVFFile, self._execute_SVFFile)
-
- # Store the head and tail for the scan
- self._d_tdi = self._d_tdi_h = self._d_tdi_t = None
- self._d_tdo_h = self._d_tdo_t = None
- self._i_tdi = self._i_tdi_h = self._i_tdi_t = None
- self._i_tdo_h = self._i_tdo_t = None
-
- # Remember the masks; smasks are ignored and bits always considered as care, e.g right
- # value applied
- self._d_length = self._d_length_h = self._d_length_t = None
- self._d_mask = self._d_mask_h = self._d_mask_t = None
- self._d_smask = self._d_smask_h = self._d_smask_t = None
- self._i_length = self._i_length_h = self._i_length_t = None
- self._i_mask = self._i_mask_h = self._i_mask_t = None
- self._i_smask = self._i_smask_h = self._i_smask_t = None
-
- @cocotb.coroutine
- def run(self, cmds, p=print):
- self._p = p
- if isinstance(cmds, c4m_jtag_svfgrammar.SVFFile):
- yield self.execute(cmds)
- else:
- p = c4m_jtag_svfgrammar.SVFFile.parser()
- yield self.execute(p.parse_string(cmds))
+++ /dev/null
-from modgrammar import *
-
-grammar_whitespace_mode = 'explicit'
-grammar_whitespace = WS_NOEOL
-
-class SVFEol(Grammar):
- grammar = (OPTIONAL(SPACE), EOL)
- grammar_collapse = True
-
-class SemicolonEol(Grammar):
- grammar = (OPTIONAL(SPACE), L(";"), SVFEol)
- grammar_collapse = True
-
-class Integer(Grammar):
- grammar = WORD("0-9")
- grammar_collapse = True
-
-class Float(Grammar):
- grammar = (Integer, (L("."), OPTIONAL(Integer)), OPTIONAL(L("E"), Integer))
-
-class Hexadecimal(Grammar):
- grammar = (L("("), WORD("0-9A-F"), L(")"))
- grammar_collapse = True
-
-class StableState(Grammar):
- grammar = (L("IRPAUSE") | L("DRPAUSE") | L("RESET") | L("IDLE"))
- grammar_collapse = True
-
-
-class ScanSpec(Grammar):
- """The specification of Scan In/Scan out data"""
- grammar = (SPACE, Integer, SPACE,
- OPTIONAL(L("TDI"), OPTIONAL(SPACE), Hexadecimal),
- OPTIONAL(OPTIONAL(SPACE), L("TDO"), OPTIONAL(SPACE), Hexadecimal),
- OPTIONAL(OPTIONAL(SPACE), L("MASK"), OPTIONAL(SPACE), Hexadecimal),
- OPTIONAL(OPTIONAL(SPACE), L("SMASK"), OPTIONAL(SPACE), Hexadecimal)
- )
- grammar_collapse = True
-
-
-class EmptyLine(Grammar):
- grammar = SVFEol
-
-class Comment(Grammar):
- grammar = (L("!"), REST_OF_LINE, SVFEol)
-
-class EndDR(Grammar):
- grammar = (L("ENDDR"), SPACE, StableState, SemicolonEol)
-
-class EndIR(Grammar):
- grammar = (L("ENDIR"), SPACE, StableState, SemicolonEol)
-
-class Frequency(Grammar):
- grammar = (L("FREQUENCY"), OPTIONAL(SPACE, Float, OPTIONAL(SPACE), L("HZ")), OPTIONAL(SPACE), SemicolonEol)
-
-class HDR(Grammar):
- grammar = (L("HDR"), ScanSpec, SemicolonEol)
-
-class HIR(Grammar):
- grammar = (L("HIR"), ScanSpec, SemicolonEol)
-
-#TODO: PIO, PIOMAP
-
-class Runtest(Grammar):
- grammar = (
- L("RUNTEST"),
- OPTIONAL(SPACE, StableState),
- OPTIONAL(SPACE, Integer, OPTIONAL(SPACE), (L("TCK") | L("SCK"))),
- OPTIONAL(SPACE, Float, OPTIONAL(SPACE), L("SEC")),
- OPTIONAL(SPACE, L("MAXIMUM"), SPACE, Float, OPTIONAL(SPACE), L("SEC")),
- OPTIONAL(SPACE, L("ENDSTATE"), SPACE, StableState),
- SemicolonEol
- )
-
-class SDR(Grammar):
- grammar = (L("SDR"), ScanSpec, SemicolonEol)
-
-class SIR(Grammar):
- grammar = (L("SIR"), ScanSpec, SemicolonEol)
-
-class State(Grammar):
- # TODO: Path to reach state
- grammar = (L("STATE"), SPACE, StableState, SemicolonEol)
-
-class TDR(Grammar):
- grammar = (L("TDR"), ScanSpec, SemicolonEol)
-
-class TIR(Grammar):
- grammar = (L("TIR"), ScanSpec, SemicolonEol)
-
-class Trst(Grammar):
- grammar = (L("TRST"), SPACE, (L("ON") | L("OFF") | L("Z") | L("ABSENT")), SemicolonEol)
-
-
-class SVFFile(Grammar):
- grammar = ONE_OR_MORE(EmptyLine | Comment | Trst | EndDR | EndIR | SIR | SDR | Runtest | State)
+++ /dev/null
-PWD=$(realpath .)
-TOPDIR=$(realpath ../../..)
-VHDLDIR=$(TOPDIR)/rtl/vhdl
-VHDL_SOURCES = \
- $(VHDLDIR)/c4m_jtag_pkg.vhdl \
- $(VHDLDIR)/c4m_jtag_tap_fsm.vhdl \
- $(VHDLDIR)/c4m_jtag_irblock.vhdl \
- $(VHDLDIR)/c4m_jtag_iocell.vhdl \
- $(VHDLDIR)/c4m_jtag_ioblock.vhdl \
- $(VHDLDIR)/c4m_jtag_idblock.vhdl \
- $(VHDLDIR)/c4m_jtag_tap_controller.vhdl
-TOPLEVEL=c4m_jtag_tap_controller
-TOPLEVEL_LANG=vhdl
-MODULE=test
-SIM=ghdl
-GPI_IMPL=vhpi
-SIM_ARGS=--wave=test.ghw
-
-COCOTBDIR=$(shell cocotb-path)
-
-include $(COCOTBDIR)/makefiles/Makefile.inc
-include $(COCOTBDIR)/makefiles/Makefile.sim
+++ /dev/null
-../c4m_jtag.py
\ No newline at end of file
+++ /dev/null
-import cocotb
-from cocotb.utils import get_sim_steps
-from cocotb.binary import BinaryValue
-
-from c4m_jtag import JTAG_Master
-
-@cocotb.test()
-def test01_idcode(dut):
- """
- Test the IDCODE command
- """
-
- # Run @ 1MHz
- clk_period = get_sim_steps(1, "us")
- master = JTAG_Master(dut.tck, dut.tms, dut.tdi, dut.tdo, dut.trst_n, clk_period)
-
- dut._log.info("Trying to get IDCODE...")
-
- yield master.idcode()
- result1 = master.result
- dut._log.info("IDCODE1: {}".format(result1))
-
- yield master.idcode()
- result2 = master.result
- dut._log.info("IDCODE2: {}".format(result2))
-
- assert(result1 == result2)
-
-@cocotb.test()
-def test02_bypass(dut):
- """
- Test of BYPASS mode
- """
-
- # Run @ 1MHz
- clk_period = get_sim_steps(1, "us")
- master = JTAG_Master(dut.tck, dut.tms, dut.tdi, dut.tdo, dut.trst_n, clk_period)
-
- dut._log.info("Loading BYPASS command")
- yield master.load_ir(master.BYPASS)
-
- dut._log.info("Sending data")
-
- data_in = BinaryValue()
- data_in.binstr = "01001101"
- yield master.shift_data(data_in)
-
- dut._log.info("bypass out: {}".format(master.result.binstr))
- assert(master.result.binstr[:-1] == data_in.binstr[1:])
-
-@cocotb.test()
-def test03_sample(dut):
- """
- Test of SAMPLEPRELOAD and EXTEST
- """
- data_in = BinaryValue()
-
- # Run @ 1MHz
- clk_period = get_sim_steps(1, "us")
- master = JTAG_Master(dut.tck, dut.tms, dut.tdi, dut.tdo, dut.trst_n, clk_period)
-
-
- dut._log.info("Load SAMPLEPRELOAD command")
- yield master.load_ir(master.SAMPLEPRELOAD)
-
- data_in.binstr = "011"
- dut._log.info(" preloading data {}".format(data_in.binstr))
-
- # Set the ios pins
- dut.core_out = 0
- dut.core_en = 0
- dut.pad_in = 1
- yield master.shift_data(data_in)
- dut._log.info(" output: {}".format(master.result.binstr))
- assert(master.result.binstr == "100")
-
-
- dut._log.info("Load EXTEST command")
- yield master.load_ir(master.EXTEST)
-
- data_in.binstr = "100"
- dut._log.info(" input data {}".format(data_in.binstr))
-
- # Set the ios pins
- dut.core_out = 1
- dut.core_en = 1
- dut.pad_in = 0
- yield master.shift_data(data_in)
- dut._log.info(" output: {}".format(master.result.binstr))
- assert(master.result.binstr == "011")
-
- dut._log.info("Do a capture of the last loaded data")
- yield master.shift_data([])
-
+++ /dev/null
-PWD=$(realpath .)
-TOPDIR=$(realpath ../../..)
-VHDLDIR=$(TOPDIR)/rtl/vhdl
-VHDL_SOURCES = \
- $(VHDLDIR)/c4m_jtag_pkg.vhdl \
- $(VHDLDIR)/c4m_jtag_tap_fsm.vhdl \
- $(VHDLDIR)/c4m_jtag_irblock.vhdl \
- $(VHDLDIR)/c4m_jtag_iocell.vhdl \
- $(VHDLDIR)/c4m_jtag_ioblock.vhdl \
- $(VHDLDIR)/c4m_jtag_idblock.vhdl \
- $(VHDLDIR)/c4m_jtag_tap_controller.vhdl \
- $(PWD)/dual_parallel.vhdl
-TOPLEVEL=dual_parallel
-TOPLEVEL_LANG=vhdl
-MODULE=test
-SIM=ghdl
-GPI_IMPL=vhpi
-SIM_ARGS=--wave=test.ghw
-
-COCOTBDIR=$(shell cocotb-path)
-
-include $(COCOTBDIR)/makefiles/Makefile.inc
-include $(COCOTBDIR)/makefiles/Makefile.sim
+++ /dev/null
-../c4m_jtag.py
\ No newline at end of file
+++ /dev/null
--- Top cell with two instantiations of the tap_controller with parallel scan chains
-
-library ieee;
-use ieee.std_logic_1164.ALL;
-
-use work.c4m_jtag.ALL;
-
-entity dual_parallel is
- port (
- -- Instance 1
- -- ==========
- -- JTAG
- I1_TCK: in std_logic;
- I1_TMS: in std_logic;
- I1_TDI: in std_logic;
- I1_TDO: out std_logic;
- I1_TRST_N: in std_logic;
-
- -- Instance 2
- -- ==========
- -- JTAG
- I2_TCK: in std_logic;
- I2_TMS: in std_logic;
- I2_TDI: in std_logic;
- I2_TDO: out std_logic;
- I2_TRST_N: in std_logic
- );
-end dual_parallel;
-
-architecture rtl of dual_parallel is
- signal I1_PAD_IN: std_logic;
- signal I1_PAD_EN: std_logic;
- signal I1_PAD_OUT: std_logic;
- signal I2_PAD_IN: std_logic;
- signal I2_PAD_EN: std_logic;
- signal I2_PAD_OUT: std_logic;
-begin
- CTRL1: c4m_jtag_tap_controller
- port map (
- TCK => I1_TCK,
- TMS => I1_TMS,
- TDI => I1_TDI,
- TDO => I1_TDO,
- TRST_N => I1_TRST_N,
- RESET => open,
- DRCAPTURE => open,
- DRSHIFT => open,
- DRUPDATE => open,
- IR => open,
- CORE_IN => open,
- CORE_EN => "1",
- CORE_OUT => "1",
- PAD_IN(0) => I1_PAD_IN,
- PAD_EN(0) => I1_PAD_EN,
- PAD_OUT(0) => I1_PAD_OUT
- );
-
- CTRL2: c4m_jtag_tap_controller
- port map (
- TCK => I2_TCK,
- TMS => I2_TMS,
- TDI => I2_TDI,
- TDO => I2_TDO,
- TRST_N => I2_TRST_N,
- RESET => open,
- DRCAPTURE => open,
- DRSHIFT => open,
- DRUPDATE => open,
- IR => open,
- CORE_IN => open,
- CORE_EN => "1",
- CORE_OUT => "0",
- PAD_IN(0) => I2_PAD_IN,
- PAD_EN(0) => I2_PAD_EN,
- PAD_OUT(0) => I2_PAD_OUT
- );
-
- I1_PAD_IN <= I2_PAD_OUT when I2_PAD_EN = '1' else
- 'Z';
- I2_PAD_IN <= I1_PAD_OUT when I1_PAD_EN = '1' else
- 'Z';
-end rtl;
+++ /dev/null
-import cocotb
-from cocotb.utils import get_sim_steps
-
-from c4m_jtag import JTAG_Master
-
-@cocotb.test()
-def test01_dual(dut):
- """
- Test the IDCODE command
- """
-
- # TODO: Allow parallel operation of the JTAG chains
-
- # Run @ 1MHz
- clk_period = get_sim_steps(1, "us")
- master1 = JTAG_Master(dut.i1_tck, dut.i1_tms, dut.i1_tdi, dut.i1_tdo, dut.i1_trst_n, clk_period)
- master2 = JTAG_Master(dut.i2_tck, dut.i2_tms, dut.i2_tdi, dut.i2_tdo, dut.i2_trst_n, clk_period)
-
- dut._log.info("Set command to SAMPLEPRELOAD")
- yield master1.load_ir(master1.SAMPLEPRELOAD)
- yield master2.load_ir(master2.SAMPLEPRELOAD)
-
- dut._log.info("Load data, scan out first sample")
- yield master1.shift_data([0, 0, 0])
- dut._log.info(" master1 scan_out: {}".format(master1.result.binstr))
- assert(master1.result.binstr == "011")
- yield master2.shift_data([1, 1, 1])
- dut._log.info(" master2 scan_out: {}".format(master2.result.binstr))
- assert(master2.result.binstr == "101")
-
- dut._log.info("Set command to EXTEST")
- yield master1.load_ir(master1.EXTEST)
- yield master2.load_ir(master2.EXTEST)
-
- dut._log.info("Second scan")
- yield master1.shift_data([0, 0, 0])
- dut._log.info(" master1 scan_out: {}".format(master1.result.binstr))
- assert(master1.result.binstr == "111")
- yield master2.shift_data([1, 1, 1])
- dut._log.info(" master2 scan_out: {}".format(master2.result.binstr))
- assert(master2.result.binstr == "Z01")
+++ /dev/null
-#!/bin/sh
-ghdl -a --std=08 ../../rtl/vhdl/c4m_jtag_pkg.vhdl
-ghdl -a --std=08 ../../rtl/vhdl/c4m_jtag_tap_fsm.vhdl
-ghdl -a --std=08 ../../rtl/vhdl/c4m_jtag_irblock.vhdl
-ghdl -a --std=08 ../../rtl/vhdl/c4m_jtag_idblock.vhdl
-ghdl -a --std=08 ../../rtl/vhdl/c4m_jtag_iocell.vhdl
-ghdl -a --std=08 ../../rtl/vhdl/c4m_jtag_ioblock.vhdl
-ghdl -a --std=08 ../../rtl/vhdl/c4m_jtag_tap_controller.vhdl
-ghdl -a --std=08 ../../bench/vhdl/idcode.vhdl
-ghdl -r --std=08 bench_idcode --wave=bench_idcode.ghw
--- /dev/null
+PWD=$(realpath .)
+TOPDIR=$(realpath ../../..)
+VHDLDIR=$(TOPDIR)/rtl/vhdl
+VHDL_SOURCES = \
+ $(VHDLDIR)/c4m_jtag_pkg.vhdl \
+ $(VHDLDIR)/c4m_jtag_tap_fsm.vhdl \
+ $(VHDLDIR)/c4m_jtag_irblock.vhdl \
+ $(VHDLDIR)/c4m_jtag_iocell.vhdl \
+ $(VHDLDIR)/c4m_jtag_ioblock.vhdl \
+ $(VHDLDIR)/c4m_jtag_idblock.vhdl \
+ $(VHDLDIR)/c4m_jtag_tap_controller.vhdl
+TOPLEVEL=c4m_jtag_tap_controller
+TOPLEVEL_LANG=vhdl
+MODULE=test
+SIM=ghdl
+GPI_IMPL=vhpi
+SIM_ARGS=--wave=test.ghw
+
+COCOTBDIR=$(shell cocotb-path)
+
+include $(COCOTBDIR)/makefiles/Makefile.inc
+include $(COCOTBDIR)/makefiles/Makefile.sim
--- /dev/null
+../c4m_jtag.py
\ No newline at end of file
--- /dev/null
+import cocotb
+from cocotb.utils import get_sim_steps
+from cocotb.binary import BinaryValue
+
+from c4m_jtag import JTAG_Master
+
+@cocotb.test()
+def test01_idcode(dut):
+ """
+ Test the IDCODE command
+ """
+
+ # Run @ 1MHz
+ clk_period = get_sim_steps(1, "us")
+ master = JTAG_Master(dut.tck, dut.tms, dut.tdi, dut.tdo, dut.trst_n, clk_period)
+
+ dut._log.info("Trying to get IDCODE...")
+
+ yield master.idcode()
+ result1 = master.result
+ dut._log.info("IDCODE1: {}".format(result1))
+
+ yield master.idcode()
+ result2 = master.result
+ dut._log.info("IDCODE2: {}".format(result2))
+
+ assert(result1 == result2)
+
+@cocotb.test()
+def test02_bypass(dut):
+ """
+ Test of BYPASS mode
+ """
+
+ # Run @ 1MHz
+ clk_period = get_sim_steps(1, "us")
+ master = JTAG_Master(dut.tck, dut.tms, dut.tdi, dut.tdo, dut.trst_n, clk_period)
+
+ dut._log.info("Loading BYPASS command")
+ yield master.load_ir(master.BYPASS)
+
+ dut._log.info("Sending data")
+
+ data_in = BinaryValue()
+ data_in.binstr = "01001101"
+ yield master.shift_data(data_in)
+
+ dut._log.info("bypass out: {}".format(master.result.binstr))
+ assert(master.result.binstr[:-1] == data_in.binstr[1:])
+
+@cocotb.test()
+def test03_sample(dut):
+ """
+ Test of SAMPLEPRELOAD and EXTEST
+ """
+ data_in = BinaryValue()
+
+ # Run @ 1MHz
+ clk_period = get_sim_steps(1, "us")
+ master = JTAG_Master(dut.tck, dut.tms, dut.tdi, dut.tdo, dut.trst_n, clk_period)
+
+
+ dut._log.info("Load SAMPLEPRELOAD command")
+ yield master.load_ir(master.SAMPLEPRELOAD)
+
+ data_in.binstr = "011"
+ dut._log.info(" preloading data {}".format(data_in.binstr))
+
+ # Set the ios pins
+ dut.core_out = 0
+ dut.core_en = 0
+ dut.pad_in = 1
+ yield master.shift_data(data_in)
+ dut._log.info(" output: {}".format(master.result.binstr))
+ assert(master.result.binstr == "100")
+
+
+ dut._log.info("Load EXTEST command")
+ yield master.load_ir(master.EXTEST)
+
+ data_in.binstr = "100"
+ dut._log.info(" input data {}".format(data_in.binstr))
+
+ # Set the ios pins
+ dut.core_out = 1
+ dut.core_en = 1
+ dut.pad_in = 0
+ yield master.shift_data(data_in)
+ dut._log.info(" output: {}".format(master.result.binstr))
+ assert(master.result.binstr == "011")
+
+ dut._log.info("Do a capture of the last loaded data")
+ yield master.shift_data([])
+
--- /dev/null
+PWD=$(realpath .)
+TOPDIR=$(realpath ../../..)
+VHDLDIR=$(TOPDIR)/rtl/vhdl
+VHDL_SOURCES = \
+ $(VHDLDIR)/c4m_jtag_pkg.vhdl \
+ $(VHDLDIR)/c4m_jtag_tap_fsm.vhdl \
+ $(VHDLDIR)/c4m_jtag_irblock.vhdl \
+ $(VHDLDIR)/c4m_jtag_iocell.vhdl \
+ $(VHDLDIR)/c4m_jtag_ioblock.vhdl \
+ $(VHDLDIR)/c4m_jtag_idblock.vhdl \
+ $(VHDLDIR)/c4m_jtag_tap_controller.vhdl \
+ $(PWD)/dual_parallel.vhdl
+TOPLEVEL=dual_parallel
+TOPLEVEL_LANG=vhdl
+MODULE=test
+SIM=ghdl
+GPI_IMPL=vhpi
+SIM_ARGS=--wave=test.ghw
+
+COCOTBDIR=$(shell cocotb-path)
+
+include $(COCOTBDIR)/makefiles/Makefile.inc
+include $(COCOTBDIR)/makefiles/Makefile.sim
--- /dev/null
+../c4m_jtag.py
\ No newline at end of file
--- /dev/null
+-- Top cell with two instantiations of the tap_controller with parallel scan chains
+
+library ieee;
+use ieee.std_logic_1164.ALL;
+
+use work.c4m_jtag.ALL;
+
+entity dual_parallel is
+ port (
+ -- Instance 1
+ -- ==========
+ -- JTAG
+ I1_TCK: in std_logic;
+ I1_TMS: in std_logic;
+ I1_TDI: in std_logic;
+ I1_TDO: out std_logic;
+ I1_TRST_N: in std_logic;
+
+ -- Instance 2
+ -- ==========
+ -- JTAG
+ I2_TCK: in std_logic;
+ I2_TMS: in std_logic;
+ I2_TDI: in std_logic;
+ I2_TDO: out std_logic;
+ I2_TRST_N: in std_logic
+ );
+end dual_parallel;
+
+architecture rtl of dual_parallel is
+ signal I1_PAD_IN: std_logic;
+ signal I1_PAD_EN: std_logic;
+ signal I1_PAD_OUT: std_logic;
+ signal I2_PAD_IN: std_logic;
+ signal I2_PAD_EN: std_logic;
+ signal I2_PAD_OUT: std_logic;
+begin
+ CTRL1: c4m_jtag_tap_controller
+ port map (
+ TCK => I1_TCK,
+ TMS => I1_TMS,
+ TDI => I1_TDI,
+ TDO => I1_TDO,
+ TRST_N => I1_TRST_N,
+ RESET => open,
+ DRCAPTURE => open,
+ DRSHIFT => open,
+ DRUPDATE => open,
+ IR => open,
+ CORE_IN => open,
+ CORE_EN => "1",
+ CORE_OUT => "1",
+ PAD_IN(0) => I1_PAD_IN,
+ PAD_EN(0) => I1_PAD_EN,
+ PAD_OUT(0) => I1_PAD_OUT
+ );
+
+ CTRL2: c4m_jtag_tap_controller
+ port map (
+ TCK => I2_TCK,
+ TMS => I2_TMS,
+ TDI => I2_TDI,
+ TDO => I2_TDO,
+ TRST_N => I2_TRST_N,
+ RESET => open,
+ DRCAPTURE => open,
+ DRSHIFT => open,
+ DRUPDATE => open,
+ IR => open,
+ CORE_IN => open,
+ CORE_EN => "1",
+ CORE_OUT => "0",
+ PAD_IN(0) => I2_PAD_IN,
+ PAD_EN(0) => I2_PAD_EN,
+ PAD_OUT(0) => I2_PAD_OUT
+ );
+
+ I1_PAD_IN <= I2_PAD_OUT when I2_PAD_EN = '1' else
+ 'Z';
+ I2_PAD_IN <= I1_PAD_OUT when I1_PAD_EN = '1' else
+ 'Z';
+end rtl;
--- /dev/null
+import cocotb
+from cocotb.utils import get_sim_steps
+
+from c4m_jtag import JTAG_Master
+
+@cocotb.test()
+def test01_dual(dut):
+ """
+ Test the IDCODE command
+ """
+
+ # TODO: Allow parallel operation of the JTAG chains
+
+ # Run @ 1MHz
+ clk_period = get_sim_steps(1, "us")
+ master1 = JTAG_Master(dut.i1_tck, dut.i1_tms, dut.i1_tdi, dut.i1_tdo, dut.i1_trst_n, clk_period)
+ master2 = JTAG_Master(dut.i2_tck, dut.i2_tms, dut.i2_tdi, dut.i2_tdo, dut.i2_trst_n, clk_period)
+
+ dut._log.info("Set command to SAMPLEPRELOAD")
+ yield master1.load_ir(master1.SAMPLEPRELOAD)
+ yield master2.load_ir(master2.SAMPLEPRELOAD)
+
+ dut._log.info("Load data, scan out first sample")
+ yield master1.shift_data([0, 0, 0])
+ dut._log.info(" master1 scan_out: {}".format(master1.result.binstr))
+ assert(master1.result.binstr == "011")
+ yield master2.shift_data([1, 1, 1])
+ dut._log.info(" master2 scan_out: {}".format(master2.result.binstr))
+ assert(master2.result.binstr == "101")
+
+ dut._log.info("Set command to EXTEST")
+ yield master1.load_ir(master1.EXTEST)
+ yield master2.load_ir(master2.EXTEST)
+
+ dut._log.info("Second scan")
+ yield master1.shift_data([0, 0, 0])
+ dut._log.info(" master1 scan_out: {}".format(master1.result.binstr))
+ assert(master1.result.binstr == "111")
+ yield master2.shift_data([1, 1, 1])
+ dut._log.info(" master2 scan_out: {}".format(master2.result.binstr))
+ assert(master2.result.binstr == "Z01")
--- /dev/null
+#!/bin/sh
+ghdl -a --std=08 ../../rtl/vhdl/c4m_jtag_pkg.vhdl
+ghdl -a --std=08 ../../rtl/vhdl/c4m_jtag_tap_fsm.vhdl
+ghdl -a --std=08 ../../rtl/vhdl/c4m_jtag_irblock.vhdl
+ghdl -a --std=08 ../../rtl/vhdl/c4m_jtag_idblock.vhdl
+ghdl -a --std=08 ../../rtl/vhdl/c4m_jtag_iocell.vhdl
+ghdl -a --std=08 ../../rtl/vhdl/c4m_jtag_ioblock.vhdl
+ghdl -a --std=08 ../../rtl/vhdl/c4m_jtag_tap_controller.vhdl
+ghdl -a --std=08 ../../bench/vhdl/idcode.vhdl
+ghdl -r --std=08 bench_idcode --wave=bench_idcode.ghw
--- /dev/null
+-- reset JTAG interface and then IDCODE should be shifted out
+
+library ieee;
+use ieee.std_logic_1164.ALL;
+
+use work.c4m_jtag.ALL;
+
+entity bench_idcode is
+end bench_idcode;
+
+architecture rtl of bench_idcode is
+ signal TCK: std_logic;
+ signal TMS: std_logic;
+ signal TDI: std_logic;
+ signal TDO: std_logic;
+ signal TRST_N: std_logic;
+
+ constant CLK_PERIOD: time := 10 ns;
+
+ procedure ClkCycle(
+ signal CLK: out std_logic;
+ CLK_PERIOD: time
+ ) is
+ begin
+ CLK <= '0';
+ wait for CLK_PERIOD/4;
+ CLK <= '1';
+ wait for CLK_PERIOD/2;
+ CLK <= '0';
+ wait for CLK_PERIOD/4;
+ end ClkCycle;
+
+ procedure ClkCycles(
+ N: integer;
+ signal CLK: out std_logic;
+ CLK_PERIOD: time
+ ) is
+ begin
+ for i in 1 to N loop
+ ClkCycle(CLK, CLK_PERIOD);
+ end loop;
+ end ClkCycles;
+begin
+ JTAG_BLOCK: c4m_jtag_tap_controller
+ -- Use default values
+ port map (
+ TCK => TCK,
+ TMS => TMS,
+ TDI => TDI,
+ TDO => TDO,
+ TRST_N => TRST_N,
+ RESET => open,
+ DRCAPTURE => open,
+ DRSHIFT => open,
+ DRUPDATE => open,
+ IR => open,
+ CORE_OUT => "0",
+ CORE_IN => open,
+ CORE_EN => "0",
+ PAD_OUT => open,
+ PAD_IN => "0",
+ PAD_EN => open
+ );
+
+ SIM: process
+ begin
+ -- Reset
+ TCK <= '0';
+ TMS <= '1';
+ TDI <= '0';
+ TRST_N <= '0';
+ wait for 10*CLK_PERIOD;
+
+ TRST_N <= '1';
+ wait for CLK_PERIOD;
+
+ -- Enter RunTestIdle
+ TMS <= '0';
+ ClkCycle(TCK, CLK_PERIOD);
+ -- Enter SelectDRScan
+ TMS <= '1';
+ ClkCycle(TCK, CLK_PERIOD);
+ -- Enter Capture
+ TMS <= '0';
+ ClkCycle(TCK, CLK_PERIOD);
+ -- Enter Shift, run for 35 CLK cycles
+ TMS <= '0';
+ ClkCycles(35, TCK, CLK_PERIOD);
+ -- Enter Exit1
+ TMS <= '1';
+ ClkCycle(TCK, CLK_PERIOD);
+ -- Enter Update
+ TMS <= '1';
+ ClkCycle(TCK, CLK_PERIOD);
+ -- To TestLogicReset
+ TMS <= '1';
+ ClkCycles(4, TCK, CLK_PERIOD);
+
+ -- end simulation
+ wait;
+ end process;
+end rtl;
--- /dev/null
+-- Test JTAG in the following way:
+-- * reset JTAG interface
+-- * load samplepreload command
+-- * shift in/out sampled inputs + wanted outputs
+-- * load extest command
+-- * execute
+
+
+library ieee;
+use ieee.std_logic_1164.ALL;
+
+use work.c4m_jtag.ALL;
+
+entity bench_sampleshift is
+end bench_sampleshift;
+
+architecture rtl of bench_sampleshift is
+ signal TCK: std_logic;
+ signal TMS: std_logic;
+ signal TDI: std_logic;
+ signal TDO: std_logic;
+ signal TRST_N: std_logic;
+
+ constant CLK_PERIOD: time := 10 ns;
+
+ procedure ClkCycle(
+ signal CLK: out std_logic;
+ CLK_PERIOD: time
+ ) is
+ begin
+ CLK <= '0';
+ wait for CLK_PERIOD/4;
+ CLK <= '1';
+ wait for CLK_PERIOD/2;
+ CLK <= '0';
+ wait for CLK_PERIOD/4;
+ end ClkCycle;
+
+ procedure ClkCycles(
+ N: integer;
+ signal CLK: out std_logic;
+ CLK_PERIOD: time
+ ) is
+ begin
+ for i in 1 to N loop
+ ClkCycle(CLK, CLK_PERIOD);
+ end loop;
+ end ClkCycles;
+
+ procedure LoadIR(