# Manuel Eggimann <meggimann@iis.ee.ethz.ch>
#
# Copyright (C) 2020-2022 ETH Zürich
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from enum import Enum
from typing import List
import bitstring
from dumpling.Common.VectorBuilder import VectorBuilder
from dumpling.Drivers.JTAG import JTAGDriver, JTAGRegister, JTAGTap
from bitstring import BitArray
bitstring.lsb0 = True #Enables the experimental mode to index LSB with 0 instead of the MSB (see thread https://github.com/scott-griffiths/bitstring/issues/156)
[docs]class DMIOp(Enum):
NOP = '00'
READ = '01'
WRITE = '10'
[docs]class DMIResult(Enum):
OP_SUCCESS = '00'
OP_FAILED = '10'
OP_PENDING = '11'
[docs]class DMRegAddress(Enum):
NO_REG = f'{0x00:0>7b}'
DATAO = f'{0x04:0>7b}'
DATA11 = f'{0x0f:0>7b}'
DMCONTROL = f'{0x10:0>7b}'
DMSTATUS = f'{0x11:0>7b}'
HARTINFO = f'{0x12:0>7b}'
HALTSUM1 = f'{0x13:0>7b}'
HAWINDOWSEL = f'{0x14:0>7b}'
HAWINDOW = f'{0x15:0>7b}'
ABSTRACTCS = f'{0x16:0>7b}'
COMMAND = f'{0x17:0>7b}'
ABSTRACTAUTO = f'{0x18:0>7b}'
CONFSTRPTR0 = f'{0x19:0>7b}'
CONFSTRPTR1 = f'{0x1a:0>7b}'
CONFSTRPTR2 = f'{0x1b:0>7b}'
CONFSTRPTR3 = f'{0x1c:0>7b}'
NEXTDM = f'{0x1d:0>7b}'
PROGBUF0 = f'{0x20:0>7b}'
PROGBUF15 = f'{0x2f:0>7b}'
AUTHDATA = f'{0x30:0>7b}'
HALTSUM2 = f'{0x34:0>7b}'
HALTSUM3 = f'{0x35:0>7b}'
SBADDRESS3 = f'{0x37:0>7b}'
SBCS = f'{0x38:0>7b}'
SBADDRESS0 = f'{0x39:0>7b}'
SBADDRESS1 = f'{0x3a:0>7b}'
SBADDRESS2 = f'{0x3b:0>7b}'
SBDATA0 = f'{0x3c:0>7b}'
SBDATA1 = f'{0x3d:0>7b}'
SBDATA2 = f'{0x3e:0>7b}'
SBDATA3 = f'{0x3f:0>7b}'
HALTSUM0 = f'{0x40:0>7b}'
[docs]class RISCVReg(Enum):
# Floating-Point CSRs
CSR_FFLAGS = '0x001'
CSR_FRM = '0x002'
CSR_FCSR = '0x003'
CSR_FTRAN = '0x800'
# Supervisor Mode CSRs
CSR_SSTATUS = '0x100'
CSR_SIE = '0x104'
CSR_STVEC = '0x105'
CSR_SCOUNTEREN = '0x106'
CSR_SSCRATCH = '0x140'
CSR_SEPC = '0x141'
CSR_SCAUSE = '0x142'
CSR_STVAL = '0x143'
CSR_SIP = '0x144'
CSR_SATP = '0x180'
# Machine Mode CSRs
CSR_MSTATUS = '0x300'
CSR_MISA = '0x301'
CSR_MEDELEG = '0x302'
CSR_MIDELEG = '0x303'
CSR_MIE = '0x304'
CSR_MTVEC = '0x305'
CSR_MCOUNTEREN = '0x306'
CSR_MSCRATCH = '0x340'
CSR_MEPC = '0x341'
CSR_MCAUSE = '0x342'
CSR_MTVAL = '0x343'
CSR_MIP = '0x344'
CSR_PMPCFG0 = '0x3A0'
CSR_PMPADDR0 = '0x3B0'
CSR_MVENDORID = '0xF11'
CSR_MARCHID = '0xF12'
CSR_MIMPID = '0xF13'
CSR_MHARTID = '0xF14'
CSR_MCYCLE = '0xB00'
CSR_MINSTRET = '0xB02'
CSR_DCACHE = '0x701'
CSR_ICACHE = '0x700'
CSR_TSELECT = '0x7A0'
CSR_TDATA1 = '0x7A1'
CSR_TDATA2 = '0x7A2'
CSR_TDATA3 = '0x7A3'
CSR_TINFO = '0x7A4'
# Debug CSR
CSR_DCSR = '0x7b0'
CSR_DPC = '0x7b1'
CSR_DSCRATCH0 = '0x7b2' # optional
CSR_DSCRATCH1 = '0x7b3' # optional
# Counters and Timers
CSR_CYCLE = '0xC00'
CSR_TIME = '0xC01'
CSR_INSTRET = '0xC02'
# Performance counters
CSR_L1_ICACHE_MISS = '0xC03' # L1 Instr Cache Miss
CSR_L1_DCACHE_MISS = '0xC04' # L1 Data Cache Miss
CSR_ITLB_MISS = '0xC05' # ITLB Miss
CSR_DTLB_MISS = '0xC06' # DTLB Miss
CSR_LOAD = '0xC07' # Loads
CSR_STORE = '0xC08' # Stores
CSR_EXCEPTION = '0xC09' # Taken exceptions
CSR_EXCEPTION_RET = '0xC0A' # Exception return
CSR_BRANCH_JUMP = '0xC0B' # Software change of PC
CSR_CALL = '0xC0C' # Procedure call
CSR_RET = '0xC0D' # Procedure Return
CSR_MIS_PREDICT = '0xC0E' # Branch mis-predicted
CSR_SB_FULL = '0xC0F' # Scoreboard full
CSR_IF_EMPTY = '0xC10' # instruction fetch queue empty
[docs] def to_bits(self):
return bitstring.pack("0x0, hex:12", self.value)
[docs]class DMAbstractCmdType(Enum):
ACCESS_REG = 0
QUICK_ACCESS = 1
ACCESS_MEM = 2
[docs] def to_bits(self):
return BitArray(uint=self.value, length=8)
[docs]class DMAbstractCmd:
def __init__(self, cmd_type: 'DMAbstractCmdType', reg: 'RISCVReg', write: bool = False, transfer: bool = False, postexec: bool = False, aarpostinc: bool = False,
aarsize: int = 2):
# Validate Input
if aarsize not in [2, 3, 4]:
raise ValueError("Illegal aarsize: {}".format(aarsize))
self.reg = reg
self.write = write
self.transfer = transfer
self.postexec = postexec
self.aarpostinc = aarpostinc
self.aarsize = aarsize
self.cmd_type = cmd_type
[docs] def to_bits(self):
return bitstring.pack('bits, 0b0, uint:3, bool, bool, bool, bool, bits', self.cmd_type.to_bits(), self.aarsize, self.aarpostinc, self.postexec, self.transfer, self.write,
self.reg.to_bits())
[docs]class RISCVDebugTap(JTAGTap):
def __init__(self, driver: JTAGDriver, idcode: str = "0x249511C3"):
super().__init__("RISC-V debug module", 5, driver)
# Add JTAG registers
self.reg_soc_idcode = self._add_reg(JTAGRegister("SoC IDCODE", '00001', 32, BitArray(idcode).bin))
self.reg_soc_dtmcsr = self._add_reg(JTAGRegister("SoC DTMCSR", '10000', 32))
self.reg_soc_dmiaccess = self._add_reg(JTAGRegister("SoC DMIACCESS", "10001", 41))
[docs] def verify_idcode(self):
"""Selects the IDCODE register of this tap (all other TAPs are put into bypass mode) and verifies that IDCODE matches the expected value."""
return self.reg_soc_idcode.read(expected_value=self.reg_soc_idcode.default_value, comment="Verifying IDCODE of RISC-V Debug Unit")
[docs] def init_dmi(self):
return self.driver.jtag_set_ir(self, self.reg_soc_dmiaccess.IR_value, comment="Init DMIACCESS (set corresponding IR)")
[docs] def set_dmi(self, dm_op: DMIOp, dmi_addr: DMRegAddress, new_dm_data: str, expected_dm_status=None, expected_dm_data=None, comment=""):
comment += "/Start DMI access with OP {} to register {}.".format(dm_op, dmi_addr.name)
if expected_dm_status and expected_dm_data:
comment += " Expecting status {} and data 0b{}".format(expected_dm_status, expected_dm_data)
dr_value = dmi_addr.value + new_dm_data + dm_op.value
expected_dr_value = 8 * 'X'
expected_dr_value += expected_dm_data if expected_dm_data else 32 * 'X'
expected_dr_value += expected_dm_status.value if expected_dm_status else 'XX'
return self.driver.jtag_set_dr(self, dr_value, expected_dr_value, comment)
[docs] def wait_command(self, retries=1, comment=""):
comment += "/Wait for abstract command completion"
expected_abstractcs = BitArray(32)
mask = BitArray(32)
expected_abstractcs[12] = 0
mask[12] = 1
expected_abstractcs[8:11] = '0b000'
mask[8:11] = '0b111'
expected_abstractcs_value = ''
for bit, maskbit in zip(expected_abstractcs, mask):
if maskbit:
expected_abstractcs_value += str(int(bit))
else:
expected_abstractcs_value += 'X'
return self.read_debug_reg(DMRegAddress.ABSTRACTCS, expected_abstractcs_value, retries, comment=comment)
[docs] def set_command_no_loop(self, cmd: DMAbstractCmd, comment="", wait_cycles=10):
comment += "/Issue abstract command register"
# Write to command register
vectors = self.write_debug_reg(DMRegAddress.COMMAND, cmd.to_bits().bin, verify_completion=False, comment=comment)
# Wait for completion of the command
vectors += [self.driver.jtag_idle_vector(repeat=wait_cycles, comment="Waiting for command completion")]
return vectors
[docs] def set_command(self, cmd: DMAbstractCmd, comment="", retries=1):
comment += "/Issue abstract command register"
# Write to command register
vectors = self.write_debug_reg(DMRegAddress.COMMAND, cmd.to_bits().bin, verify_completion=False, comment=comment)
# Wait for completion of the command
vectors += self.wait_command(retries)
return vectors
[docs] def dmi_reset(self):
# Set the dmireset flag in DTMCS
dr_value = BitArray(32)
dr_value[16] = 1
dr_value = dr_value.bin
vectors = self.driver.write_reg(self, self.reg_soc_dtmcsr, dr_value, "Reset DMI")
vectors += self.init_dmi() # Change IR back to DMIACCESS register
return vectors
[docs] def dmi_hardreset(self):
dr_value = BitArray(32)
dr_value[17] = 1
dr_value = dr_value.bin
return self.driver.jtag_set_dr(self, dr_value, "Hardreset DMI")
[docs] def set_dmactive(self, dmactive: bool):
return self.set_dmi(DMIOp.WRITE, DMRegAddress.DMCONTROL, 31 * '0' + '1' if dmactive else '0', comment="Set DMACTIVE flag")
[docs] def read_debug_reg_no_loop(self, dmi_addr: DMRegAddress, expected_data: str, wait_cycles=0, comment=""):
comment += "/Verify debug reg {} to be 0b{}.".format(dmi_addr, expected_data)
# Generate vectors to start read operation from register
vectors = self.set_dmi(DMIOp.READ, dmi_addr, 32 * '0', comment=comment)
self.driver.set_jtag_default_values()
self.driver.vector_builder.tck = 1
vectors += [self.driver.vector_builder.vector(repeat=10, comment="Clock tck for a few cycles to let dmi complete operation")]
# Don't use a matched loop but wait for a couple of jtag cycles before trying to read the DMIACCESS register
vectors += [self.driver.jtag_idle_vector(repeat=wait_cycles, comment="Waiting for completion of DMI read OP.")]
vectors += self.set_dmi(DMIOp.NOP, DMRegAddress.NO_REG, 32 * '0', DMIResult.OP_SUCCESS, expected_data)
return vectors
[docs] def read_debug_reg(self, dmi_addr: DMRegAddress, expected_data: str, retries=1, comment=""):
comment += "/Verify debug reg {} to be 0b{}. Max retries = {}".format(dmi_addr, expected_data, retries)
# Generate vectors to start read operation from register
vectors = self.set_dmi(DMIOp.READ, dmi_addr, 32 * '0', comment=comment)
# Poll the DMIACCESS register and check the status & read register value
condition_vectors = self.set_dmi(DMIOp.NOP, DMRegAddress.NO_REG, 32 * '0', DMIResult.OP_SUCCESS, expected_data)
# Pad the condition vectors to be a multiple of 8
condition_vectors = VectorBuilder.pad_vectors(condition_vectors, self.driver.jtag_idle_vector())
idle_vectors = self.dmi_reset()
# Pad the idle vectors to be a multiple of 8
idle_vectors = VectorBuilder.pad_vectors(idle_vectors, self.driver.jtag_idle_vector())
# Create vectors for a matched loop that repeatedly polls the status register and resets the error bit on mismatch
vectors += self.driver.vector_builder.matched_loop(condition_vectors, idle_vectors, retries)
vectors += self.driver.jtag_idle_vectors(8) # Make sure there are at least 8 normal vectors before the next matched loop by insertion idle instructions
return vectors
[docs] def write_debug_reg(self, dmi_addr: DMRegAddress, data: str, verify_completion=True, retries=1, comment=""):
comment += "/Write 0x{} to debug reg {}.".format(BitArray(bin=data).hex, dmi_addr)
if verify_completion:
comment += "Max retries = {}".format(retries)
# Generate vectors to start write operation to register
vectors = self.set_dmi(DMIOp.WRITE, dmi_addr, data, comment=comment)
# Generate a few jtag clock edges while staying in idle state
self.driver.set_jtag_default_values()
self.driver.vector_builder.tck = 1
vectors += [self.driver.vector_builder.vector(repeat=5, comment="Clock tck for a few cycles to let dmi complete operation")]
if verify_completion:
# Check the status of the previous operation by reading the OP field of JTAG DMI Access register
condition_vectors = self.set_dmi(DMIOp.NOP, DMRegAddress.NO_REG, 32 * '0', DMIResult.OP_SUCCESS)
# Pad the condition vectors to be a multiple of 8
condition_vectors = VectorBuilder.pad_vectors(condition_vectors, self.driver.jtag_idle_vector())
idle_vectors = self.dmi_reset()
# Pad the idle vectors to be a multiple of 8
idle_vectors = VectorBuilder.pad_vectors(idle_vectors, self.driver.jtag_idle_vector())
# Create vectors for a matched loop that repeatedly polls the status register and resets the error bit on mismatch
vectors += self.driver.vector_builder.matched_loop(condition_vectors, idle_vectors, retries)
vectors += self.driver.jtag_idle_vectors(8) # Make sure there are at least 8 normal vectors before the next matched loop by insertion idle instructions
return vectors
[docs] def write_reg_abstract_cmd_no_loop(self, reg: RISCVReg, data: BitArray, comment=""):
comment += "/Write {} to registers {}".format(data, reg)
# Write data to data0 DM reg
vectors = self.write_debug_reg(DMRegAddress.DATAO, data.bin, verify_completion=False, comment=comment)
# Issue the write to register command
cmd = DMAbstractCmd(cmd_type=DMAbstractCmdType.ACCESS_REG, reg=RISCVReg.CSR_DPC, write=True, transfer=True, aarsize=2)
vectors += self.set_command_no_loop(cmd)
return vectors
[docs] def write_reg_abstract_cmd(self, reg: RISCVReg, data: BitArray, retries=1, comment=""):
comment += "/Write {} to registers {}".format(data, reg)
# Write data to data0 DM reg
vectors = self.write_debug_reg(DMRegAddress.DATAO, data.bin, retries=retries, comment=comment)
# Issue the write to register command
cmd = DMAbstractCmd(cmd_type=DMAbstractCmdType.ACCESS_REG, reg=RISCVReg.CSR_DPC, write=True, transfer=True, aarsize=2)
vectors += self.set_command(cmd, retries=retries)
return vectors
[docs] def read_reg_abstract_cmd(self, reg: RISCVReg, expected_data, retries=1, comment=""):
comment += "Verify register {} equals {}".format(reg, expected_data)
# Issue the read from register command
cmd = DMAbstractCmd(cmd_type=DMAbstractCmdType.ACCESS_REG, reg=RISCVReg.CSR_DPC, write=False, transfer=True, aarsize=2)
vectors = self.set_command(cmd, retries=retries)
# Read data from data0 DM reg
vectors += self.read_debug_reg(DMRegAddress.DATAO, expected_data, retries=retries, comment=comment)
return vectors
[docs] def read_reg_abstract_cmd_no_loop(self, reg: RISCVReg, expected_data, wait_cycles=10, comment=""):
comment += "Verify register {} equals {}".format(reg, expected_data)
# Issue the read from register command
cmd = DMAbstractCmd(cmd_type=DMAbstractCmdType.ACCESS_REG, reg=RISCVReg.CSR_DPC, write=False, transfer=True, aarsize=2)
vectors = self.set_command_no_loop(cmd, wait_cycles=wait_cycles)
# Read data from data0 DM reg
vectors += self.read_debug_reg_no_loop(DMRegAddress.DATAO, expected_data, wait_cycles=wait_cycles, comment=comment)
return vectors
[docs] def halt_hart(self, hartsel: BitArray, comment="", retries=1):
comment += "/Halting hart 0x{}".format(hartsel.hex)
new_dm_value = BitArray(32)
new_dm_value[31] = 1 # haltreq
new_dm_value[16:26] = hartsel[0:10] # hartsello
new_dm_value[6:16] = hartsel[10:20] # hartselhi
new_dm_value[0] = 1 # Dmactive, if we were to write a zero we would reset the dmi
vectors = self.write_debug_reg(DMRegAddress.DMCONTROL, new_dm_value.bin, retries=1, comment=comment)
# Poll the DMSTATUS reg
expected_dm_status = BitArray(32)
mask = BitArray(32)
expected_dm_status[9] = 1 # 1 #All halted
mask[9] = 1
expected_dm_status_value = ""
for bit, maskbit in zip(expected_dm_status, mask):
if maskbit:
expected_dm_status_value += str(int(bit))
else:
expected_dm_status_value += 'X'
vectors += self.read_debug_reg(DMRegAddress.DMSTATUS, expected_dm_status_value, retries, comment="Poll until allhalted flag is set")
# Clear halreq bit
new_dm_value[31] = 0
vectors += self.write_debug_reg(DMRegAddress.DMCONTROL, new_dm_value.bin, verify_completion=False, comment=comment)
return vectors
[docs] def halt_hart_no_loop(self, hartsel: BitArray, comment="", wait_cycles=10):
comment += "/Halting hart 0x{}".format(hartsel.hex)
new_dm_value = BitArray(32)
new_dm_value[31] = 1 # haltreq
new_dm_value[16:26] = hartsel[0:10] # hartsello
new_dm_value[6:16] = hartsel[10:20] # hartselhi
new_dm_value[0] = 1 # Dmactive, if we were to write a zero we would reset the dmi
vectors = self.write_debug_reg(DMRegAddress.DMCONTROL, new_dm_value.bin, verify_completion=False, comment=comment)
# Check the DMSTATUS reg after wait cycles
vectors += [self.driver.jtag_idle_vector(repeat=wait_cycles, comment="Waiting for core to halt")]
expected_dm_status = BitArray(32)
mask = BitArray(32)
expected_dm_status[9] = 1 # 1 #All halted
mask[9] = 1
expected_dm_status_value = ""
for bit, maskbit in zip(expected_dm_status, mask):
if maskbit:
expected_dm_status_value += str(int(bit))
else:
expected_dm_status_value += 'X'
vectors += self.read_debug_reg_no_loop(DMRegAddress.DMSTATUS, expected_dm_status_value, wait_cycles=wait_cycles, comment="Check if allhalted flag is set")
# Clear halreq bit
new_dm_value[31] = 0
vectors += self.write_debug_reg(DMRegAddress.DMCONTROL, new_dm_value.bin, verify_completion=False, comment=comment)
return vectors
[docs] def resume_harts(self, hartsel: BitArray, comment="", retries=1):
comment += "/Resume hart {}".format(hartsel)
new_dm_value = BitArray(32)
new_dm_value[30] = 1 # resumereq
new_dm_value[16:26] = hartsel[0:10] # hartsello
new_dm_value[6:16] = hartsel[10:20] # hartselhi
new_dm_value[0] = 1 # Dmactive, if we were to write a zero we would reset the dmi
vectors = self.write_debug_reg(DMRegAddress.DMCONTROL, new_dm_value.bin, retries=1, comment=comment)
# Poll the DMSTATUS reg
expected_dm_status = BitArray(32)
mask = BitArray(32)
expected_dm_status[17] = 1 # allresumeack
mask[17] = 1
mask[23:32] = 1
expected_dm_status_value = ""
for bit, maskbit in zip(expected_dm_status, mask):
if maskbit:
expected_dm_status_value += str(int(bit))
else:
expected_dm_status_value += 'X'
vectors += self.read_debug_reg(DMRegAddress.DMSTATUS, expected_dm_status_value, retries, comment="Poll until allresumeack flag is set")
# Clear resumereq bit
new_dm_value[30] = 0
vectors += self.write_debug_reg(DMRegAddress.DMCONTROL, new_dm_value.bin, verify_completion=False, comment=comment)
return vectors
[docs] def resume_harts_no_loop(self, hartsel: BitArray, comment="", wait_cycles=10):
comment += "/Resume hart {}".format(hartsel)
new_dm_value = BitArray(32)
new_dm_value[30] = 1 # resumereq
new_dm_value[16:26] = hartsel[0:10] # hartsello
new_dm_value[6:16] = hartsel[10:20] # hartselhi
new_dm_value[0] = 1 # Dmactive, if we were to write a zero we would reset the dmi
vectors = self.write_debug_reg(DMRegAddress.DMCONTROL, new_dm_value.bin, verify_completion=False, comment=comment)
# Check the DMSTATUS reg after wait cycles
vectors += [self.driver.jtag_idle_vector(repeat=wait_cycles, comment="Waiting for {} cycles before checking if core halted.".format(wait_cycles))]
expected_dm_status = BitArray(32)
mask = BitArray(32)
expected_dm_status[17] = 1 # allresumeack
mask[17] = 1
mask[23:32] = 1
expected_dm_status_value = ""
for bit, maskbit in zip(expected_dm_status, mask):
if maskbit:
expected_dm_status_value += str(int(bit))
else:
expected_dm_status_value += 'X'
vectors += self.read_debug_reg_no_loop(DMRegAddress.DMSTATUS, expected_dm_status_value, wait_cycles=wait_cycles, comment="Check if allresumeack flag is set")
# Clear resumereq bit
new_dm_value[30] = 0
vectors += self.write_debug_reg(DMRegAddress.DMCONTROL, new_dm_value.bin, verify_completion=False, comment=comment)
return vectors
[docs] def writeMem(self, addr: BitArray, data: BitArray, verify_completion=True, retries=1, comment=""):
comment += "/Writing {} to memory @0x{}".format(data.hex, addr.hex)
vectors = self.write_debug_reg(DMRegAddress.SBADDRESS0, addr.bin, verify_completion=verify_completion, retries=retries, comment=comment)
vectors += self.write_debug_reg(DMRegAddress.SBDATA0, data.bin, verify_completion=verify_completion, retries=retries, comment=comment)
return vectors
[docs] def readMem(self, addr: BitArray, expected_data: BitArray, retries=1, comment=""):
comment += "/Reading from systembus @0x{} expecting 0x".format(addr.hex, expected_data.hex)
vectors = self.write_debug_reg(DMRegAddress.SBADDRESS0, addr.bin, retries=retries, comment=comment)
vectors += self.read_debug_reg(DMRegAddress.SBDATA0, expected_data.bin, retries=retries)
return vectors
[docs] def readMem_no_loop(self, addr: BitArray, expected_data: BitArray, wait_cycles, comment=""):
comment += "/Reading from systembus @0x{} expecting 0x".format(addr.hex, expected_data.hex)
vectors = self.write_debug_reg(DMRegAddress.SBADDRESS0, addr.bin, verify_completion=False, comment=comment)
vectors += [self.driver.jtag_idle_vector(repeat=wait_cycles, comment="Wait for a few cylces to let the bus transaction complete")]
vectors += self.read_debug_reg_no_loop(DMRegAddress.SBDATA0, expected_data.bin, wait_cycles=wait_cycles)
return vectors
[docs] def enable_sbreadonaddr(self):
# Enable sbreadonaddr by writing appropriate values to SBCS register
sbcs_value = BitArray(32)
sbcs_value[29:32] = 1
sbcs_value[20] = 1
sbcs_value[17:20] = 2
return self.write_debug_reg(DMRegAddress.SBCS, sbcs_value.bin, verify_completion=False, comment="Enable sbreadonaddr flag in SBCS reg for "
"subsequent reads.")
[docs] def check_end_of_computation(self, expected_return_code: int, wait_cycles=10, eoc_reg_addr = '0x1a1040a0'):
vectors = self.enable_sbreadonaddr()
expected_eoc_value = BitArray(int=expected_return_code, length=32)
expected_eoc_value[31] = 1
vectors += self.readMem_no_loop(BitArray(eoc_reg_addr), expected_eoc_value, wait_cycles=wait_cycles, comment="Check for end of computation with expected return code {}".format(
expected_return_code))
return vectors
[docs] def wait_for_end_of_computation(self, expected_return_code: int, idle_vector_count=10, max_retries=10, eoc_reg_addr = '0x1a1040a0'):
vectors = self.enable_sbreadonaddr()
expected_eoc_value = BitArray(int=expected_return_code, length=32)
expected_eoc_value[31] = 1
condition_vectors = self.readMem(BitArray(eoc_reg_addr), expected_eoc_value, retries=max_retries, comment="Wait for end of computation with expected return code {}".format(
expected_return_code))
# Pad the condition vectors to be a multiple of 8
condition_vectors = VectorBuilder.pad_vectors(condition_vectors, self.driver.jtag_idle_vector())
idle_vectors = self.driver.jtag_idle_vectors(count=idle_vector_count)
idle_vectors = VectorBuilder.pad_vectors(idle_vectors, self.driver.jtag_idle_vector())
vectors += self.driver.vector_builder.matched_loop(condition_vectors, idle_vectors, max_retries)
vectors += self.driver.jtag_idle_vectors(8) # Make sure there are at least 8 normal vectors before the next matched loop by insertion idle instructions
return vectors