def shift_register(self, out, use_last=False): """Shift a BitSequence into the current register and retrieve the register output""" if not isinstance(out, BitSequence): return JtagError('Expect a BitSequence') length = len(out) if use_last: (out, self._last) = (out[:-1], int(out[-1])) byte_count = len(out)//8 pos = 8*byte_count bit_count = len(out)-pos if not byte_count and not bit_count: raise JtagError("Nothing to shift") if byte_count: blen = byte_count-1 #print "RW OUT %s" % out[:pos] cmd = Array('B', [Ftdi.RW_BYTES_PVE_NVE_LSB, blen, (blen>>8)&0xff]) cmd.extend(out[:pos].tobytes(msby=True)) self._stack_cmd(cmd) #print "push %d bytes" % byte_count if bit_count: #print "RW OUT %s" % out[pos:] cmd = Array('B', [Ftdi.RW_BITS_PVE_NVE_LSB, bit_count-1]) cmd.append(out[pos:].tobyte()) self._stack_cmd(cmd) #print "push %d bits" % bit_count self.sync() bs = BitSequence() byte_count = length//8 pos = 8*byte_count bit_count = length-pos if byte_count: data = self._ftdi.read_data_bytes(byte_count, 4) if not data: raise JtagError('Unable to read data from FTDI') byteseq = BitSequence(bytes_=data, length=8*byte_count) #print "RW IN %s" % byteseq bs.append(byteseq) #print "pop %d bytes" % byte_count if bit_count: data = self._ftdi.read_data_bytes(1, 4) if not data: raise JtagError('Unable to read data from FTDI') byte = data[0] # need to shift bits as they are shifted in from the MSB in FTDI byte >>= 8-bit_count bitseq = BitSequence(byte, length=bit_count) bs.append(bitseq) #print "pop %d bits" % bit_count if len(bs) != length: raise AssertionError("Internal error") #self._ftdi.validate_mpsse() return bs
def read(self, length): """Read out a sequence of bits from TDO""" byte_count = length//8 bit_count = length-8*byte_count bs = BitSequence() if byte_count: bytes = self._read_bytes(byte_count) bs.append(bytes) if bit_count: bits = self._read_bits(bit_count) bs.append(bits) return bs
def write(self, out, use_last=True): """Write a sequence of bits to TDI""" if isinstance(out, str): out = BitSequence(bytes_=out) elif not isinstance(out, BitSequence): out = BitSequence(out) if use_last: (out, self._last) = (out[:-1], bool(out[-1])) byte_count = len(out) // 8 pos = 8 * byte_count bit_count = len(out) - pos if byte_count: self._write_bytes(out[:pos]) if bit_count: self._write_bits(out[pos:])
def write_tms(self, tms): """Change the TAP controller state""" if not isinstance(tms, BitSequence): raise JtagError('Expect a BitSequence') length = len(tms) if not (0 < length < 8): raise JtagError('Invalid TMS length') out = BitSequence(tms, length=8) # apply the last TDO bit if self._last is not None: out[7] = self._last # print "TMS", tms, (self._last is not None) and 'w/ Last' or '' # reset last bit self._last = None cmd = Array('B', [Ftdi.WRITE_BITS_TMS_NVE, length-1, out.tobyte()]) self._stack_cmd(cmd) self.sync()
def shift_register(self, length): if not self._sm.state_of('shift'): raise JtagError("Invalid state: %s" % self._sm.state()) if self._sm.state_of('capture'): bs = BitSequence(False) self._ctrl.write_tms(bs) self._sm.handle_events(bs) return self._ctrl.shift_register(length)
def write_tms(self, tms): """Change the TAP controller state""" if not isinstance(tms, BitSequence): raise JtagError('Expect a BitSequence') length = len(tms) if not (0 < length < 8): raise JtagError('Invalid TMS length') out = BitSequence(tms, length=8) # apply the last TDO bit if self._last is not None: out[7] = self._last # print "TMS", tms, (self._last is not None) and 'w/ Last' or '' # reset last bit self._last = None cmd = Array('B', [Ftdi.WRITE_BITS_TMS_NVE, length - 1, out.tobyte()]) self._stack_cmd(cmd) self.sync()
def detect_register_size(self): # Freely inpired from UrJTAG # Need to contact authors, or to replace this code to comply with # the GPL license (GPL vs. LGPL with Python is a bit fuzzy for me) if not self._engine._sm.state_of('shift'): raise JtagError("Invalid state: %s" % self._engine._sm.state()) if self._engine._sm.state_of('capture'): bs = BitSequence(False) self._engine._ctrl.write_tms(bs) self._engine._sm.handle_events(bs) MAX_REG_LEN = 1024 PATTERN_LEN = 8 stuck = None for length in range(1, MAX_REG_LEN): print "Testing for length %d" % length if length > 5: return zero = BitSequence(length=length) inj = BitSequence(length=length+PATTERN_LEN) inj.inc() for p in range(1, 1<<PATTERN_LEN): ok = False self._engine.write(zero, False) rcv = self._engine.shift_register(inj) try: tdo = rcv.invariant() except ValueError: tdo = None if stuck is None: stuck = tdo if stuck != tdo: stuck = None rcv >>= length if rcv == inj: ok = True else: break inj.inc() if ok: print "Register detected length: %d" % length return length if stuck is not None: raise JtagError('TDO seems to be stuck') raise JtagError('Unable to detect register length')
def shift_register(self, out, use_last=False): """Shift a BitSequence into the current register and retrieve the register output""" if not isinstance(out, BitSequence): return JtagError('Expect a BitSequence') length = len(out) if use_last: (out, self._last) = (out[:-1], int(out[-1])) byte_count = len(out) // 8 pos = 8 * byte_count bit_count = len(out) - pos if not byte_count and not bit_count: raise JtagError("Nothing to shift") if byte_count: blen = byte_count - 1 #print "RW OUT %s" % out[:pos] cmd = Array('B', [Ftdi.RW_BYTES_PVE_NVE_LSB, blen, (blen >> 8) & 0xff]) cmd.extend(out[:pos].tobytes(msby=True)) self._stack_cmd(cmd) #print "push %d bytes" % byte_count if bit_count: #print "RW OUT %s" % out[pos:] cmd = Array('B', [Ftdi.RW_BITS_PVE_NVE_LSB, bit_count - 1]) cmd.append(out[pos:].tobyte()) self._stack_cmd(cmd) #print "push %d bits" % bit_count self.sync() bs = BitSequence() byte_count = length // 8 pos = 8 * byte_count bit_count = length - pos if byte_count: data = self._ftdi.read_data_bytes(byte_count, 4) if not data: raise JtagError('Unable to read data from FTDI') byteseq = BitSequence(bytes_=data, length=8 * byte_count) #print "RW IN %s" % byteseq bs.append(byteseq) #print "pop %d bytes" % byte_count if bit_count: data = self._ftdi.read_data_bytes(1, 4) if not data: raise JtagError('Unable to read data from FTDI') byte = data[0] # need to shift bits as they are shifted in from the MSB in FTDI byte >>= 8 - bit_count bitseq = BitSequence(byte, length=bit_count) bs.append(bitseq) #print "pop %d bits" % bit_count if len(bs) != length: raise AssertionError("Internal error") #self._ftdi.validate_mpsse() return bs
def get_events(self, path): """Build up an event sequence from a state sequence, so that the resulting event sequence allows the JTAG state machine to advance from the first state to the last one of the input sequence""" events = [] for s, d in zip(path[:-1], path[1:]): for e, x in enumerate(s.exits): if x == d: events.append(e) if len(events) != len(path) - 1: raise JtagError("Invalid path") return BitSequence(events)
def _read_bytes(self, length): """Read out bytes from TDO""" data = '' if length > JtagController.FTDI_PIPE_LEN: raise JtagError("Cannot fit into FTDI fifo") alen = length - 1 cmd = Array('B', [Ftdi.READ_BYTES_NVE_LSB, alen & 0xff, (alen >> 8) & 0xff]) self._stack_cmd(cmd) self.sync() data = self._ftdi.read_data_bytes(length, 4) bs = BitSequence(bytes_=data, length=8 * length) #print "READ BYTES %s" % bs return bs
def _read_bits(self, length): """Read out bits from TDO""" data = '' if length > 8: raise JtagError("Cannot fit into FTDI fifo") cmd = Array('B', [Ftdi.READ_BITS_NVE_LSB, length - 1]) self._stack_cmd(cmd) self.sync() data = self._ftdi.read_data_bytes(1, 4) # need to shift bits as they are shifted in from the MSB in FTDI byte = ord(data) >> 8 - bit_count bs = BitSequence(byte, length=length) #print "READ BITS %s" % (bs) return bs
def detect_register_size(self): # Freely inpired from UrJTAG # Need to contact authors, or to replace this code to comply with # the GPL license (GPL vs. LGPL with Python is a bit fuzzy for me) if not self._engine._sm.state_of('shift'): raise JtagError("Invalid state: %s" % self._engine._sm.state()) if self._engine._sm.state_of('capture'): bs = BitSequence(False) self._engine._ctrl.write_tms(bs) self._engine._sm.handle_events(bs) MAX_REG_LEN = 1024 PATTERN_LEN = 8 stuck = None for length in range(1, MAX_REG_LEN): print "Testing for length %d" % length if length > 5: return zero = BitSequence(length=length) inj = BitSequence(length=length + PATTERN_LEN) inj.inc() for p in range(1, 1 << PATTERN_LEN): ok = False self._engine.write(zero, False) rcv = self._engine.shift_register(inj) try: tdo = rcv.invariant() except ValueError: tdo = None if stuck is None: stuck = tdo if stuck != tdo: stuck = None rcv >>= length if rcv == inj: ok = True else: break inj.inc() if ok: print "Register detected length: %d" % length return length if stuck is not None: raise JtagError('TDO seems to be stuck') raise JtagError('Unable to detect register length')
def read(self, length): """Read out a sequence of bits from TDO""" byte_count = length // 8 bit_count = length - 8 * byte_count bs = BitSequence() if byte_count: bytes = self._read_bytes(byte_count) bs.append(bytes) if bit_count: bits = self._read_bits(bit_count) bs.append(bits) return bs
def reset(self, sync=False): """Reset the attached TAP controller. sync sends the command immediately (no caching) """ # we can either send a TRST HW signal or perform 5 cycles with TMS=1 # to move the remote TAP controller back to 'test_logic_reset' state # do both for now if not self._ftdi: raise JtagError("FTDI controller terminated") if self._trst: # nTRST value = 0 cmd = Array('B', [Ftdi.SET_BITS_LOW, value, self.direction]) self._ftdi.write_data(cmd) time.sleep(0.1) # nTRST should be left to the high state value = JtagController.TRST_BIT cmd = Array('B', [Ftdi.SET_BITS_LOW, value, self.direction]) self._ftdi.write_data(cmd) time.sleep(0.1) # TAP reset (even with HW reset, could be removed though) self.write_tms(BitSequence('11111')) if sync: self.sync()
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, # OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, # EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. import sys import time import unittest from pyftdi.pyftdi.jtag import JtagEngine, JtagTool from pyftdi.pyftdi.bits import BitSequence # Should match the tested device JTAG_INSTR = { 'SAMPLE': BitSequence('0001', msb=True, length=4), 'PRELOAD': BitSequence('0001', msb=True, length=4), 'IDCODE': BitSequence('0100', msb=True, length=4), 'BYPASS': BitSequence('1111', msb=True, length=4) } class JtagTestCase(unittest.TestCase): def setUp(self): self.jtag = JtagEngine(trst=True, frequency=3E6) self.jtag.configure(vendor=0x403, product=0x6011, interface=1) self.jtag.reset() self.tool = JtagTool(self.jtag) def tearDown(self): del self.jtag
# ARE DISCLAIMED. IN NO EVENT SHALL NEOTION BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, # OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, # EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. import sys import time from pyftdi.pyftdi.jtag import JtagEngine from pyftdi.pyftdi.bits import BitSequence # ARM 926 JTAG_INSTR = { 'EXTEST': BitSequence('0000', msb=True, length=4), 'SAMPLE': BitSequence('0011', msb=True, length=4), 'PRELOAD': BitSequence('0011', msb=True, length=4), 'SCAN_N': BitSequence('0010', msb=True, length=4), 'INTEST': BitSequence('1100', msb=True, length=4), 'IDCODE': BitSequence('1110', msb=True, length=4), 'BYPASS': BitSequence('1111', msb=True, length=4), 'RESTART': BitSequence('0100', msb=True, length=4) } class ArmJtag(object): """JTAG helper for ARM core""" def __init__(self, vendor, product, interface): self.jtag = JtagEngine() self.jtag.configure(vendor, product, interface)