convert debug script to TCL interface, remove telnetlib dependency

This commit is contained in:
Matthew 2024-06-09 11:25:28 -05:00
parent c3243caacf
commit 7f63daa49c
4 changed files with 473 additions and 512 deletions

View File

@ -1,429 +0,0 @@
#!/usr/bin/env python3
#########################################################################################
# hw_interface.py
#
# Written: matthew.n.otto@okstate.edu
# Created: 19 April 2024
#
# Purpose: Send debugging commands to OpenOCD via local telnet connection
#
# A component of the CORE-V-WALLY configurable RISC-V project.
# https:#github.com/openhwgroup/cvw
#
# Copyright (C) 2021-24 Harvey Mudd College & Oklahoma State University
#
# SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1
#
# Licensed under the Solderpad Hardware License v 2.1 (the “License”); you may not use this file
# except in compliance with the License, or, at your option, the Apache License version 2.0. You
# may obtain a copy of the License at
#
# https:#solderpad.org/licenses/SHL-2.1/
#
# Unless required by applicable law or agreed to in writing, any work 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.
#########################################################################################
# This script uses python to send text commands to OpenOCD via telnet
# OpenOCD also supports tcl commands directly
import atexit
import re
import time
from telnetlib import Telnet
debug = False
# TODO: if JTAG clk is fast enough, need to check for busy between absract commands
def dump_GPR():
gpr = {}
for i in range(1,32):
addr = f"X{i}"
gpr[addr] = read_data(addr)
# DM will assert Abstract Command Err if GPR X16-X31 isn't implemented (CMDERR_EXCEPTION)
# This will clear that error and return early.
if i == 16:
abstractcs = int(read_dmi("0x16"), 16)
cmderr = (abstractcs & 0x700) >> 8
if cmderr == 3:
clear_abstrcmd_err()
break
return gpr
def write_data(register, data):
"""Writes data of width XLEN to specified register"""
# Translate register alias to DM regno
regno = int(register_translations[register], 16)
# Write data to 32 bit message registers
data = int(data, 16)
write_dmi("0x4", hex(data & 0xffffffff))
if XLEN == 64:
write_dmi("0x5", hex((data >> 32) & 0xffffffff))
if XLEN == 128:
write_dmi("0x6", hex((data >> 64) & 0xffffffff))
write_dmi("0x7", hex((data >> 96) & 0xffffffff))
# Transfer data from msg registers to target register
access_register(write=True, regno=regno, addr_size=XLEN)
# Check that operations completed without error
if acerr := check_absrtcmderr():
raise Exception(acerr)
def read_data(register):
"""Read data of width XLEN from specified register"""
# Translate register alias to DM regno
regno = int(register_translations[register], 16)
# Transfer data from target register to msg registers
access_register(write=False, regno=regno, addr_size=XLEN)
# Read data from 32 bit message registers
data = ""
data = read_dmi("0x4").replace("0x", "").zfill(8)
if XLEN >= 64:
data = read_dmi("0x5").replace("0x", "").zfill(8) + data
if XLEN == 128:
data = read_dmi("0x6").replace("0x", "").zfill(8) + data
data = read_dmi("0x7").replace("0x", "").zfill(8) + data
# Check that operations completed without error
if acerr := check_absrtcmderr():
raise Exception(acerr)
return f"0x{data}"
def access_register(write, regno, addr_size):
"""3.7.1.1
Before starting an abstract command, a debugger must ensure that haltreq, resumereq, and
ackhavereset are all 0."""
addr = "0x17"
data = 1 << 17 # transfer bit always set
if addr_size == 32:
data += 2 << 20
elif addr_size == 64:
data += 3 << 20
elif addr_size == 128:
data += 4 << 20
else:
raise Exception("must provide valid register access size (32, 64, 128). See: 3.7.1.1 aarsize")
if write:
data += 1<<16
data += regno
data = hex(data)
write_dmi(addr, data)
def halt():
write_dmi("0x10", "0x80000001")
check_errors()
def resume():
write_dmi("0x10", "0x40000001")
check_errors()
def step():
write_dmi("0x10", "0xC0000001")
check_errors()
def set_haltonreset():
write_dmi("0x10", "0x9")
def clear_haltonreset():
write_dmi("0x10", "0x5")
def reset_hart():
write_dmi("0x10", "0x3")
write_dmi("0x10", "0x1")
def status():
dmstatus = int(read_dmi("0x11"), 16)
print("Core status:::")
print(f"Running: {bool((dmstatus >> 11) & 0x1)}")
print(f"Halted: {bool((dmstatus >> 9) & 0x1)}")
def check_errors():
# TODO: update this
"""Checks various status bits and reports any potential errors
Returns true if any errors are found"""
# check dtmcs
dtmcs = int(read_dtmcs(), 16)
errinfo = (dtmcs & 0x1C0000) >> 18
dmistat = (dtmcs & 0xC00) >> 10
if errinfo > 0 and errinfo < 4:
print(f"DTM Error: {errinfo_translations[errinfo]}")
return True
if dmistat:
print(f"DMI status error: {op_translations[dmistat]}")
return True
# check if DM is inactive
dm_active = int(read_dmi("0x10"), 16) & 0x1
if not dm_active:
print("DMControl Error: Debug module is not active")
return True
# check abstract command error
abstractcs = int(read_dmi("0x16"), 16)
busy = (abstractcs & 0x1000) >> 12
cmderr = (abstractcs & 0x700) >> 8
if not busy and cmderr:
print(f"Abstract Command Error: {cmderr_translations[cmderr]}")
return True
def check_busy():
"""If an Abstract Command OP is attempted while busy, an abstrcmderr will be asserted"""
abstractcs = int(read_dmi("0x16"), 16)
return bool((abstractcs & 0x1000) >> 12)
def check_absrtcmderr():
"""These errors must be cleared using clear_abstrcmd_err() before another OP can be executed"""
abstractcs = int(read_dmi("0x16"), 16)
# CmdErr is only valid if Busy is 0
busy = bool((abstractcs & 0x1000) >> 12)
while busy:
time.sleep(0.05)
abstractcs = int(read_dmi("0x16"), 16)
busy = bool((abstractcs & 0x1000) >> 12)
return cmderr_translations[(abstractcs & 0x700) >> 8]
def clear_abstrcmd_err():
write_dmi("0x16", "0x700")
def reset_dm():
deactivate_dm()
activate_dm()
def activate_dm():
write_dmi("0x10", "0x1")
return int(read_dmi("0x10"), 16) & 0x1
def deactivate_dm():
write_dmi("0x10", "0x0")
return not int(read_dmi("0x10"), 16) & 0x1
def dmi_reset():
"""Reset sticky dmi error status in DTM"""
write_dtmcs(dmireset=True)
check_errors()
def write_dmi(address, data):
cmd = f"riscv dmi_write {address} {data}"
rsp = execute(cmd)
if "Failed" in rsp:
print(rsp)
def read_dmi(address):
cmd = f"riscv dmi_read {address}"
return execute(cmd)
def write_dtmcs(dtmhardreset=False, dmireset=False):
data = 0
if dtmhardreset:
data += 0x1 << 17
if dmireset:
data += 0x1 << 16
execute(f"irscan {tapname} 0x10") # dtmcs instruction
execute(f"drscan {tapname} 32 {hex(data)}")
def read_dtmcs():
execute(f"irscan {tapname} 0x10") # dtmcs instruction
dtmcs = execute(f"drscan {tapname} 32 0x0")
return dtmcs
def trst():
execute("pathmove RESET IDLE")
def execute(cmd):
write(cmd)
return read()
def write(cmd):
if debug:
print(f"Executing command: '{cmd}'")
tn.write(cmd.encode('ascii') + b"\n")
tn.read_until(b"\n")
def read():
data = b""
data = tn.read_until(b"> ").decode('ascii')
data = data.replace("\r", "").replace("\n", "").replace("> ", "")
if debug:
print(data)
return data
def interrogate():
global XLEN
global tapname
write("scan_chain")
raw = tn.read_until(b"> ").decode('ascii')
scan_chain = raw.replace("\r", "").replace("> ", "")
scan_chain = [tap for tap in scan_chain.split("\n")[2:] if tap]
if len(scan_chain) > 1:
print(f"Found multiple taps. Selecting tap #0\n{raw}")
scan_chain = scan_chain[0]
tapname = re.search("\d\s+(.+?)\s+", scan_chain).group(1)
print(f"DM tapname: {tapname}")
write("riscv info")
info = tn.read_until(b"> ").decode('ascii').replace("\r", "").replace("> ", "").split("\n")
for line in info:
if XLEN := re.search("hart.xlen\s+(\d+)", line).group(1):
XLEN = int(XLEN)
break
print(f"XLEN: {XLEN}")
def init():
global tn
tn = Telnet("127.0.0.1", 4444)
atexit.register(cleanup)
read() # clear welcome message from read buffer
interrogate()
activate_dm()
# TODO: query gpr count
def cleanup():
tn.close()
# 6.1.4 dtmcs errinfo translation table
errinfo_translations = {
0 : "not implemented",
1 : "dmi error",
2 : "communication error",
3 : "device error",
4 : "unknown",
}
# 6.1.5 DMI op translation table
op_translations = {
0 : "success",
1 : "reserved",
2 : "failed",
3 : "busy",
}
# 3.14.6 Abstract command CmdErr value translation table
cmderr_translations = {
0 : None,
1 : "busy",
2 : "not supported",
3 : "exception",
4 : "halt/resume",
5 : "bus",
6 : "reserved",
7 : "other",
}
# Register alias to regno translation table
register_translations = {
"MISA" : "0x0301",
"TRAPM" : "0xC000",
"PCM" : "0xC001",
"INSTRM" : "0xC002",
"MEMRWM" : "0xC003",
"INSTRVALIDM" : "0xC004",
"WRITEDATAM" : "0xC005",
"IEUADRM" : "0xC006",
"READDATAM" : "0xC007",
"x0 (zero)" : "0x1000",
"x1 (ra)" : "0x1001",
"x2 (sp)" : "0x1002",
"x3 (gp)" : "0x1003",
"x4 (tp)" : "0x1004",
"x5 (t0)" : "0x1005",
"x6 (t1)" : "0x1006",
"x7 (t2)" : "0x1007",
"x8 (s0/fp)" : "0x1008",
"x9 (s1)" : "0x1009",
"x10 (a0)" : "0x100A",
"x11 (a1)" : "0x100B",
"x12 (a2)" : "0x100C",
"x13 (a3)" : "0x100D",
"x14 (a4)" : "0x100E",
"x15 (a5)" : "0x100F",
"x16 (a6)" : "0x1010",
"x17 (a7)" : "0x1011",
"x18 (s2)" : "0x1012",
"x19 (s3)" : "0x1013",
"x20 (s4)" : "0x1014",
"x21 (s5)" : "0x1015",
"x22 (s6)" : "0x1016",
"x23 (s7)" : "0x1017",
"x24 (s8)" : "0x1018",
"x25 (s9)" : "0x1019",
"x26 (s10)" : "0x101A",
"x27 (s11)" : "0x101B",
"x28 (t3)" : "0x101C",
"x29 (t4)" : "0x101D",
"x30 (t5)" : "0x101E",
"x31 (t6)" : "0x101F",
"f0 (ft0)" : "0x1020",
"f1 (ft1)" : "0x1021",
"f2 (ft2)" : "0x1022",
"f3 (ft3)" : "0x1023",
"f4 (ft4)" : "0x1024",
"f5 (ft5)" : "0x1025",
"f6 (ft6)" : "0x1026",
"f7 (ft7)" : "0x1027",
"f8 (fs0)" : "0x1028",
"f9 (fs1)" : "0x1029",
"f10 (fa0)" : "0x102A",
"f11 (fa1)" : "0x102B",
"f12 (fa2)" : "0x102C",
"f13 (fa3)" : "0x102D",
"f14 (fa4)" : "0x102E",
"f15 (fa5)" : "0x102F",
"f16 (fa6)" : "0x1030",
"f17 (fa7)" : "0x1031",
"f18 (fs2)" : "0x1032",
"f19 (fs3)" : "0x1033",
"f20 (fs4)" : "0x1034",
"f21 (fs5)" : "0x1035",
"f22 (fs6)" : "0x1036",
"f23 (fs7)" : "0x1037",
"f24 (fs8)" : "0x1038",
"f25 (fs9)" : "0x1039",
"f26 (fs10)" : "0x103A",
"f27 (fs11)" : "0x103B",
"f28 (ft8)" : "0x103C",
"f29 (ft9)" : "0x103D",
"f30 (ft10)" : "0x103E",
"f31 (ft11)" : "0x103F",
}
nonstandard_register_lengths = {
"TRAPM" : 1,
"INSTRM" : 32,
"MEMRWM" : 2,
"INSTRVALIDM" : 1,
"READDATAM" : 64
}

View File

@ -6,7 +6,7 @@
# Written: matthew.n.otto@okstate.edu
# Created: 19 April 2024
#
# Purpose: Send test commands to OpenOCD via local telnet connection
# Purpose: script to automate testing of hardware debug interface
#
# A component of the CORE-V-WALLY configurable RISC-V project.
# https:#github.com/openhwgroup/cvw
@ -30,36 +30,37 @@
import random
import time
import hw_debug_interface
from hw_debug_interface import *
from openocd_tcl_wrapper import OpenOCD
random_stimulus = False
random_stimulus = True
def main():
registers = dict.fromkeys(register_translations.keys(),[])
with OpenOCD() as cvw:
registers = dict.fromkeys(cvw.register_translations.keys(),[])
reg_addrs = list(registers.keys())
init()
global XLEN
XLEN = hw_debug_interface.XLEN
reset_dm()
reset_hart()
XLEN = cvw.LLEN
global nonstandard_register_lengths
nonstandard_register_lengths = cvw.nonstandard_register_lengths
cvw.reset_dm()
cvw.reset_hart()
time.sleep(70) # wait for OpenSBI
halt()
status()
cvw.halt()
# dump data in all registers
for r in reg_addrs:
try:
data = read_data(r)
data = cvw.read_data(r)
registers[r] = data
print(f"{r}: {data}")
except Exception as e:
if e.args[0] == "exception": # Invalid register (not implemented)
del registers[r]
clear_abstrcmd_err()
cvw.clear_abstrcmd_err()
else:
raise e
input("Compare values to ILA, press any key to continue")
@ -72,20 +73,18 @@ def main():
for r in reg_addrs:
test_data = random_hex(r)
try:
write_data(r, test_data)
cvw.write_data(r, test_data)
test_reg_data[r] = test_data
print(f"Writing {test_data} to {r}")
except Exception as e:
if e.args[0] == "not supported": # Register is read only
del registers[r]
clear_abstrcmd_err()
cvw.clear_abstrcmd_err()
else:
raise e
check_errors()
# GPR X0 is always 0
test_reg_data["X0"] = "0x" + "0"*(XLEN//4)
test_reg_data["x0"] = "0x" + "0"*(cvw.LLEN//4)
# Confirm data was written correctly
reg_addrs = list(registers.keys())
@ -93,7 +92,7 @@ def main():
random.shuffle(reg_addrs)
for r in reg_addrs:
try:
rdata = read_data(r)
rdata = cvw.read_data(r)
except Exception as e:
raise e
if rdata != test_reg_data[r]:
@ -106,22 +105,21 @@ def main():
for r in reg_addrs:
print(f"Writing {registers[r]} to {r}")
try:
write_data(r, registers[r])
cvw.write_data(r, registers[r])
except Exception as e:
raise e
# Confirm data was written correctly
for r in reg_addrs:
try:
rdata = read_data(r)
rdata = cvw.read_data(r)
except Exception as e:
raise e
if rdata != registers[r]:
raise Exception(f"Register {r} read did not return correct data: {rdata} != {registers[r]}")
print("All writes successful")
resume()
status()
cvw.resume()
def random_hex(reg_name):

392
bin/openocd_tcl_wrapper.py Normal file
View File

@ -0,0 +1,392 @@
#########################################################################################
# openocd_tcl_wrapper.py
#
# Written: matthew.n.otto@okstate.edu
# Created: 8 June 2024
#
# Purpose: Python wrapper library used to send debug commands to OpenOCD
#
# A component of the CORE-V-WALLY configurable RISC-V project.
# https://github.com/openhwgroup/cvw
#
# Copyright (C) 2021-24 Harvey Mudd College & Oklahoma State University
#
# SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1
#
# Licensed under the Solderpad Hardware License v 2.1 (the “License”); you may not use this file
# except in compliance with the License, or, at your option, the Apache License version 2.0. You
# may obtain a copy of the License at
#
# https://solderpad.org/licenses/SHL-2.1/
#
# Unless required by applicable law or agreed to in writing, any work 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.
#########################################################################################
import math
import socket
import time
ENDMSG = b'\x1a'
class OpenOCD:
def __init__(self):
self.tcl = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
def __enter__(self):
self.tcl.connect(("127.0.0.1", 6666))
self.LLEN = 64 #TODO: find this
return self
def __exit__(self, type, value, traceback):
try:
self.send("exit")
finally:
self.tcl.close()
def capture(self, cmd):
return self.send(f"capture \"{cmd}\"")
def send(self, cmd):
data = cmd.encode("ascii") + ENDMSG
self.tcl.send(data)
return self.receive()
def receive(self):
data = bytes()
while True:
byte = self.tcl.recv(1)
if byte == ENDMSG:
break
else:
data += byte
data = data.decode("ascii").rstrip()
return data
def trst(self):
self.send("pathmove RESET IDLE")
def write_dtmcs(self, dtmhardreset=False, dmireset=False):
"""Send reset commands to DTMCS. Used to clear sticky DMI OP error status"""
data = 0
data |= dtmhardreset << 17
data |= dmireset << 16
if not data:
print("Warning: not writing DTMCS (dtmhardreset and dmireset are both false)")
return
tapname = "cvw.cpu"
self.send(f"irscan {tapname} 0x10") # dtmcs instruction
self.send(f"drscan {tapname} 32 {hex(data)}")
op = self.capture(f"drscan {tapname} 32 0x0")
if (int(op) >> 10) & 0x3:
raise Exception("Error: failed to reset DTMCS (nonzero dmistat)")
def write_dmi(self, address, data):
cmd = f"riscv dmi_write {address} {data}"
rsp = self.capture(cmd)
if "Failed" in rsp:
raise Exception(rsp)
def read_dmi(self, address):
cmd = f"riscv dmi_read {address}"
return self.capture(cmd)
def activate_dm(self):
self.write_dmi("0x10", "0x1")
dmstat = int(self.read_dmi("0x10"), 16)
if not dmstat & 0x1:
raise Exception("Error: failed to activate debug module")
def reset_dm(self):
self.write_dmi("0x10", "0x0")
dmstat = int(self.read_dmi("0x10"), 16)
if dmstat & 0x1:
raise Exception("Error: failed to deactivate debug module")
self.activate_dm()
def reset_hart(self):
self.write_dmi("0x10", "0x3")
self.write_dmi("0x10", "0x1")
dmstat = int(self.read_dmi("0x11"), 16) # check HaveReset
if not ((dmstat >> 18) & 0x3):
raise Exception("Error: Hart failed to reset")
self.write_dmi("0x10", "0x10000001") # ack HaveReset
def set_haltonreset(self):
self.write_dmi("0x10", "0x9")
def clear_haltonreset(self):
self.write_dmi("0x10", "0x5")
def halt(self):
self.write_dmi("0x10", "0x80000001")
dmstat = int(self.read_dmi("0x11"), 16) # Check halted bit
if not ((dmstat >> 8) & 0x3):
raise Exception("Error: Hart failed to halt")
def resume(self):
self.write_dmi("0x10", "0x40000001") # Send resume command
dmstat = int(self.read_dmi("0x11"), 16) # Check resumeack bit
if not ((dmstat >> 16) & 0x3):
raise Exception("Error: Hart failed to resume")
self.write_dmi("0x10", "0x40000001") # Clear resumeack bit
def step(self):
self.write_dmi("0x10", "0xC0000001")
# BOZO: checking resumeack after halt is pointless until sdext halt method is added
dmstat = int(self.read_dmi("0x11"), 16)
if not ((dmstat >> 16) & 0x3):
raise Exception("Error: Hart failed to resume")
def access_register(self, write, regno, addr_size=None):
data = 1 << 17 # transfer bit always set
if not addr_size:
addr_size = self.LLEN
elif addr_size not in (32, 64, 128):
raise Exception("must provide valid register access size (32, 64, 128). See: 3.7.1.1 aarsize")
data += int(math.log2(addr_size // 8)) << 20
data += write << 16
data += regno
self.write_dmi("0x17", hex(data))
def write_data(self, register, data):
"""Write data to specified register"""
# Write data to 32 bit message registers
data = int(data, 16)
self.write_dmi("0x4", hex(data & 0xffffffff))
if self.LLEN >= 64:
self.write_dmi("0x5", hex((data >> 32) & 0xffffffff))
if self.LLEN == 128:
self.write_dmi("0x6", hex((data >> 64) & 0xffffffff))
self.write_dmi("0x7", hex((data >> 96) & 0xffffffff))
# Translate register alias to DM regno
regno = self.translate_regno(register)
# Transfer data from msg registers to target register
self.access_register(write=True, regno=regno)
# Check that operations completed without error
if acerr := self.check_abstrcmderr():
raise Exception(acerr)
def read_data(self, register):
"""Read data from specified register"""
# Translate register alias to DM regno
regno = self.translate_regno(register)
# Transfer data from target register to msg registers
self.access_register(write=False, regno=regno)
# Read data from 32 bit message registers
data = ""
data = self.read_dmi("0x4").replace("0x", "").zfill(8)
if self.LLEN >= 64:
data = self.read_dmi("0x5").replace("0x", "").zfill(8) + data
if self.LLEN == 128:
data = self.read_dmi("0x6").replace("0x", "").zfill(8) + data
data = self.read_dmi("0x7").replace("0x", "").zfill(8) + data
# Check that operations completed without error
if acerr := self.check_abstrcmderr():
raise Exception(acerr)
return f"0x{data}"
def translate_regno(self, register):
if register not in self.register_translations:
register = self.abi_translations[register]
return int(self.register_translations[register], 16)
def check_abstrcmderr(self):
"""These errors must be cleared using clear_abstrcmd_err() before another OP can be executed"""
abstractcs = int(self.read_dmi("0x16"), 16)
# CmdErr is only valid if Busy is 0
while True:
if not bool((abstractcs & 0x1000) >> 12): # if not Busy
break
time.sleep(0.05)
abstractcs = int(self.read_dmi("0x16"), 16)
return self.cmderr_translations[(abstractcs & 0x700) >> 8]
def clear_abstrcmd_err(self):
self.write_dmi("0x16", "0x700")
if self.check_abstrcmderr():
raise Exception("Error: failed to clear AbstrCmdErr")
# 6.1.4 dtmcs errinfo translation table
errinfo_translations = {
0 : "not implemented",
1 : "dmi error",
2 : "communication error",
3 : "device error",
4 : "unknown",
}
# 6.1.5 DMI op translation table
op_translations = {
0 : "success",
1 : "reserved",
2 : "failed",
3 : "busy",
}
# 3.14.6 Abstract command CmdErr value translation table
cmderr_translations = {
0 : None,
1 : "busy",
2 : "not supported",
3 : "exception",
4 : "halt/resume",
5 : "bus",
6 : "reserved",
7 : "other",
}
# Register alias to regno translation table
register_translations = {
"MISA" : "0x0301",
"TRAPM" : "0xC000",
"PCM" : "0xC001",
"INSTRM" : "0xC002",
"MEMRWM" : "0xC003",
"INSTRVALIDM" : "0xC004",
"WRITEDATAM" : "0xC005",
"IEUADRM" : "0xC006",
"READDATAM" : "0xC007",
"x0" : "0x1000",
"x1" : "0x1001",
"x2" : "0x1002",
"x3" : "0x1003",
"x4" : "0x1004",
"x5" : "0x1005",
"x6" : "0x1006",
"x7" : "0x1007",
"x8" : "0x1008",
"x9" : "0x1009",
"x10" : "0x100A",
"x11" : "0x100B",
"x12" : "0x100C",
"x13" : "0x100D",
"x14" : "0x100E",
"x15" : "0x100F",
"x16" : "0x1010",
"x17" : "0x1011",
"x18" : "0x1012",
"x19" : "0x1013",
"x20" : "0x1014",
"x21" : "0x1015",
"x22" : "0x1016",
"x23" : "0x1017",
"x24" : "0x1018",
"x25" : "0x1019",
"x26" : "0x101A",
"x27" : "0x101B",
"x28" : "0x101C",
"x29" : "0x101D",
"x30" : "0x101E",
"x31" : "0x101F",
"f0" : "0x1020",
"f1" : "0x1021",
"f2" : "0x1022",
"f3" : "0x1023",
"f4" : "0x1024",
"f5" : "0x1025",
"f6" : "0x1026",
"f7" : "0x1027",
"f8" : "0x1028",
"f9" : "0x1029",
"f10" : "0x102A",
"f11" : "0x102B",
"f12" : "0x102C",
"f13" : "0x102D",
"f14" : "0x102E",
"f15" : "0x102F",
"f16" : "0x1030",
"f17" : "0x1031",
"f18" : "0x1032",
"f19" : "0x1033",
"f20" : "0x1034",
"f21" : "0x1035",
"f22" : "0x1036",
"f23" : "0x1037",
"f24" : "0x1038",
"f25" : "0x1039",
"f26" : "0x103A",
"f27" : "0x103B",
"f28" : "0x103C",
"f29" : "0x103D",
"f30" : "0x103E",
"f31" : "0x103F",
}
abi_translations = {
"x0" : "zero",
"x1" : "ra",
"x2" : "sp",
"x3" : "gp",
"x4" : "tp",
"x5" : "t0",
"x6" : "t1",
"x7" : "t2",
"x8" : "s0/fp",
"x9" : "s1",
"x10" : "a0",
"x11" : "a1",
"x12" : "a2",
"x13" : "a3",
"x14" : "a4",
"x15" : "a5",
"x16" : "a6",
"x17" : "a7",
"x18" : "s2",
"x19" : "s3",
"x20" : "s4",
"x21" : "s5",
"x22" : "s6",
"x23" : "s7",
"x24" : "s8",
"x25" : "s9",
"x26" : "s10",
"x27" : "s11",
"x28" : "t3",
"x29" : "t4",
"x30" : "t5",
"x31" : "t6",
"f0" : "ft0",
"f1" : "ft1",
"f2" : "ft2",
"f3" : "ft3",
"f4" : "ft4",
"f5" : "ft5",
"f6" : "ft6",
"f7" : "ft7",
"f8" : "fs0",
"f9" : "fs1",
"f10" : "fa0",
"f11" : "fa1",
"f12" : "fa2",
"f13" : "fa3",
"f14" : "fa4",
"f15" : "fa5",
"f16" : "fa6",
"f17" : "fa7",
"f18" : "fs2",
"f19" : "fs3",
"f20" : "fs4",
"f21" : "fs5",
"f22" : "fs6",
"f23" : "fs7",
"f24" : "fs8",
"f25" : "fs9",
"f26" : "fs10",
"f27" : "fs11",
"f28" : "ft8",
"f29" : "ft9",
"f30" : "ft10",
"f31" : "ft11",
}
abi_translations |= dict(map(reversed, abi_translations.items())) # two way translations
nonstandard_register_lengths = {
"TRAPM" : 1,
"INSTRM" : 32,
"MEMRWM" : 2,
"INSTRVALIDM" : 1,
"READDATAM" : 64
}

View File

@ -6,7 +6,7 @@ adapter driver ftdi
# when multiple adapters with the same vid_pid are connected (ex: arty-a7 and usb-jtag)
# need to specify which usb port to drive
# find numerical path using command "lsusb -t" (<bus>-<port>)
adapter usb location 1-3
adapter usb location 1-4
ftdi vid_pid 0x0403 0x6010
ftdi channel 0