+++ /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