#
# ------------------------------------------------------------
# Copyright (c) All rights reserved
# SiLab, Institute of Physics, University of Bonn
# ------------------------------------------------------------
#
import numpy as np
from bitarray import bitarray
from basil.HL.RegisterHardwareLayer import RegisterHardwareLayer
from basil.utils.BitLogic import BitLogic
[docs]
class JtagMaster(RegisterHardwareLayer):
"""
SPI based JTAG interface
"""
_registers = {
"RESET": {"descr": {"addr": 0, "size": 8, "properties": ["writeonly"]}},
"VERSION": {"descr": {"addr": 0, "size": 8, "properties": ["ro"]}},
"READY": {"descr": {"addr": 1, "size": 1, "properties": ["ro"]}},
"START": {"descr": {"addr": 1, "size": 8, "properties": ["writeonly"]}},
"SIZE": {"descr": {"addr": 3, "size": 16}},
"WAIT": {"descr": {"addr": 5, "size": 32}},
"WORD_COUNT": {"descr": {"addr": 9, "size": 16}},
"COMMAND": {"descr": {"addr": 11, "size": 16}},
"EN": {"descr": {"addr": 13, "size": 1}},
"MEM_BYTES": {"descr": {"addr": 14, "size": 16, "properties": ["ro"]}},
}
_require_version = "==1"
jtag_command = {"INSTRUCTION": 0, "DATA": 1}
def __init__(self, intf, conf):
super(JtagMaster, self).__init__(intf, conf)
self._mem_offset = 16 # in bytes
self._memout_offset = 0
self._memin_offset = 16
def init(self):
super(JtagMaster, self).init()
self._mem_bytes = self.MEM_BYTES
[docs]
def reset(self):
"""
Soft reset the module.
"""
self.RESET = 0
while not self.READY:
pass
[docs]
def start(self):
"""
Starts the shifting data
"""
self.START = 0
[docs]
def set_command(self, value):
"""
IR_SCAN or DR_SCAN
"""
self.COMMAND = self.jtag_command[value]
[docs]
def get_command(self):
"""
IR_SCAN or DR_SCAN
"""
return list(self.jtag_command.keys())[self.COMMAND]
[docs]
def set_data(self, data, addr=0):
"""
Sets data for outgoing stream
"""
if self._mem_bytes < len(data):
raise ValueError("Size of data (%d bytes) is too big for memory (%d bytes)" % (len(data), self._mem_bytes))
self._intf.write(self._conf["base_addr"] + self._mem_offset + addr, data)
# This needs to be changed to return written value
[docs]
def get_data(self, size=None, addr=None):
"""
Gets data for incoming stream
"""
# readback memory offset
if addr is None:
addr = self._mem_bytes
if size and self._mem_bytes < size:
raise ValueError("Size is too big")
if size is None:
return self._intf.read(self._conf["base_addr"] + self._mem_offset + addr, self._mem_bytes)
else:
return self._intf.read(self._conf["base_addr"] + self._mem_offset + addr, size)
[docs]
def scan_ir(self, data, readback=True):
"""
Data must be a list of BitLogic
"""
bit_number = self._test_input(data)
self.SIZE = bit_number
if isinstance(data[0], BitLogic):
data_byte = self._bitlogic2bytes(data)
else:
data_byte = self._raw_data2bytes(data)
self.set_data(data_byte)
self.WORD_COUNT = 1
self.set_command("INSTRUCTION")
self.start()
while not self.READY:
pass
if readback:
received_data = self.get_data(size=len(data_byte))
return self._bytes2bitlogic(received_data, bit_number, data)
[docs]
def scan_dr(self, data, readback=True, word_size=None):
"""
Data must be a list of BitLogic or string of raw data
"""
bit_number = self._test_input(data, word_size)
self.set_command("DATA")
if word_size is None:
self.SIZE = bit_number
self.WORD_COUNT = 1
else:
self.WORD_COUNT = bit_number // word_size
self.SIZE = word_size
if isinstance(data[0], BitLogic):
data_byte = self._bitlogic2bytes(data)
else:
data_byte = self._raw_data2bytes(data)
self.set_data(data_byte)
self.start()
while not self.READY:
pass
if readback:
received_data = self.get_data(size=len(data_byte))
return self._bytes2bitlogic(received_data, bit_number, data)
def _test_input(self, data, word_size=None):
"""
Test input data and return length in bits
"""
if not isinstance(data, list):
raise ValueError("Input data must be a list of BitLogic or str")
if type(data[0]) not in [BitLogic, str]:
raise TypeError("Type of data not supported: got", type(data[0]), " and support only str and Bitlogic")
bit_number = sum(len(x) for x in data)
if bit_number > self._mem_bytes * 8:
raise ValueError("Size is too big for memory: got %d and memory is: %d" % (bit_number, self._mem_bytes * 8))
if word_size is not None and bit_number % word_size != 0:
raise ValueError("Number of bits doesn't match word_size. %d bits remaining" % (bit_number % word_size))
return bit_number
def _bitlogic2bytes(self, data):
original_string = ""
for dev in range(len(data)):
device_string = data[dev].to01()
original_string += device_string[::-1] # We want the original string of the Bitlogic, not the reversed one
data_bitarray = bitarray(original_string)
return data_bitarray.tobytes()
def _bytes2bitlogic(self, data, bit_number, original_data):
data_byte = np.byte(data)
tmp = bitarray()
tmp.frombytes(data_byte.tobytes())
binary_string = tmp.to01()
rlist = []
last_data_len = 0
for i in original_data:
rlist.append(BitLogic(binary_string[last_data_len : len(i) + last_data_len]))
last_data_len += len(i)
return rlist
def _raw_data2bytes(self, data):
all_data = "".join(data)
# pad with zero if not a multiple of 8
if len(all_data) % 8 != 0:
all_data += "0" * (8 - (len(all_data) % 8))
# convert string to byte
return bytes(int(all_data[i : i + 8], 2) for i in range(0, len(all_data), 8))