Merge at opentitan f243e680
Change-Id: I5c447581944309d63f2d58ec95647815f462bae0
diff --git a/hw/dv/BUILD b/hw/dv/BUILD
new file mode 100644
index 0000000..29144e4
--- /dev/null
+++ b/hw/dv/BUILD
@@ -0,0 +1,11 @@
+# Copyright 2022 Google contributors.
+
+package(default_visibility = ["//visibility:public"])
+
+# For matcha to get the directory of this folder and run fusesoc.
+exports_files(["BUILD"])
+
+filegroup(
+ name ="all_files",
+ srcs = glob(["**"]),
+)
diff --git a/hw/dv/dpi/spidpi/spidpi.c b/hw/dv/dpi/spidpi/spidpi.c
index 3827635..a6d9314 100644
--- a/hw/dv/dpi/spidpi/spidpi.c
+++ b/hw/dv/dpi/spidpi/spidpi.c
@@ -51,7 +51,12 @@
ctx->driving = P2D_CSB | ((ctx->cpol) ? P2D_SCK : 0);
char cwd[PATH_MAX];
char *cwd_rv;
- cwd_rv = getcwd(cwd, sizeof(cwd));
+ const char *test_out_dir = getenv("TEST_UNDECLARED_OUTPUTS_DIR");
+ if (test_out_dir) {
+ cwd_rv = strncpy(cwd, test_out_dir, sizeof(cwd));
+ } else {
+ cwd_rv = getcwd(cwd, sizeof(cwd));
+ }
assert(cwd_rv != NULL);
int rv;
diff --git a/hw/dv/dpi/uartdpi/uartdpi.c b/hw/dv/dpi/uartdpi/uartdpi.c
index fa69858..479162f 100644
--- a/hw/dv/dpi/uartdpi/uartdpi.c
+++ b/hw/dv/dpi/uartdpi/uartdpi.c
@@ -57,10 +57,20 @@
} else {
FILE *log_file;
- log_file = fopen(log_file_path, "w");
+ const char *test_out_dir = getenv("TEST_UNDECLARED_OUTPUTS_DIR");
+ const int kMaxPathLen = 512;
+ char test_out_log_file[kMaxPathLen] = {0};
+ if (test_out_dir) {
+ snprintf(test_out_log_file, kMaxPathLen, "%s/%s", test_out_dir,
+ log_file_path),
+ log_file = fopen(test_out_log_file, "w");
+ } else {
+ log_file = fopen(log_file_path, "w");
+ }
if (!log_file) {
fprintf(stderr, "UART: Unable to open log file at %s: %s\n",
- log_file_path, strerror(errno));
+ test_out_dir ? test_out_log_file : log_file_path,
+ strerror(errno));
} else {
// Switch log file output to line buffering to ensure lines written to
// the UART device show up in the log file as soon as a newline
@@ -70,7 +80,7 @@
ctx->log_file = log_file;
printf("UART: Additionally writing all UART output to '%s'.\n",
- log_file_path);
+ test_out_dir ? test_out_log_file : log_file_path);
}
}
}
diff --git a/hw/dv/dpi/usbdpi/usbdpi.c b/hw/dv/dpi/usbdpi/usbdpi.c
index 8c3c9c5..3ccfcb3 100644
--- a/hw/dv/dpi/usbdpi/usbdpi.c
+++ b/hw/dv/dpi/usbdpi/usbdpi.c
@@ -112,7 +112,12 @@
char cwd[FILENAME_MAX];
char *cwd_rv;
- cwd_rv = getcwd(cwd, sizeof(cwd));
+ const char *test_out_dir = getenv("TEST_UNDECLARED_OUTPUTS_DIR");
+ if (test_out_dir) {
+ cwd_rv = strncpy(cwd, test_out_dir, sizeof(cwd));
+ } else {
+ cwd_rv = getcwd(cwd, sizeof(cwd));
+ }
assert(cwd_rv != NULL);
// Monitor log file
diff --git a/hw/dv/verilator/simutil_verilator/cpp/verilator_sim_ctrl.cc b/hw/dv/verilator/simutil_verilator/cpp/verilator_sim_ctrl.cc
index 3c8ddea..53589d9 100644
--- a/hw/dv/verilator/simutil_verilator/cpp/verilator_sim_ctrl.cc
+++ b/hw/dv/verilator/simutil_verilator/cpp/verilator_sim_ctrl.cc
@@ -319,11 +319,23 @@
}
const char *VerilatorSimCtrl::GetTraceFileName() const {
+ const char *test_output_dir = getenv("TEST_UNDECLARED_OUTPUTS_DIR");
+ constexpr int kMaxPathLen = 512;
+ static char trace_file[kMaxPathLen];
#ifdef VM_TRACE_FMT_FST
- return "sim.fst";
+ if (test_output_dir) {
+ snprintf(trace_file, kMaxPathLen, "%s/sim.fst", test_output_dir);
+ } else {
+ return "sim.fst";
+ }
#else
- return "sim.vcd";
+ if (test_output_dir) {
+ snprintf(trace_file, kMaxPathLen, "%s/sim.fst", test_output_dir);
+ } else {
+ return "sim.vcd";
+ }
#endif
+ return trace_file;
}
void VerilatorSimCtrl::Run() {
diff --git a/hw/ip/otbn/BUILD b/hw/ip/otbn/BUILD
index ba54a6a..67d0bb7 100644
--- a/hw/ip/otbn/BUILD
+++ b/hw/ip/otbn/BUILD
@@ -10,3 +10,39 @@
"//hw/ip/otbn/data:all_files",
],
)
+
+genrule(
+ name = "otbn_simple_smoke_test_obj",
+ srcs = [
+ "dv/smoke/smoke_test.s",
+ ],
+ outs = [
+ "otbn_simple_smoke_test.o",
+ ],
+ cmd = """
+ export RV32_TOOL_AS=$(location @lowrisc_rv32imcb_files//:bin/riscv32-unknown-elf-as)
+ $(location //hw/ip/otbn/util:otbn_as) -o $@ $<
+ """,
+ tools = [
+ "//hw/ip/otbn/util:otbn_as",
+ "@lowrisc_rv32imcb_files//:bin/riscv32-unknown-elf-as",
+ ],
+)
+
+genrule(
+ name = "otbn_simple_smoke_test_elf",
+ srcs = [
+ ":otbn_simple_smoke_test.o",
+ ],
+ outs = [
+ "otbn_simple_smoke_test.elf",
+ ],
+ cmd = """
+ export RV32_TOOL_LD=$(location @lowrisc_rv32imcb_files//:bin/riscv32-unknown-elf-ld)
+ $(location //hw/ip/otbn/util:otbn_ld) -o $@ $<
+ """,
+ tools = [
+ "//hw/ip/otbn/util:otbn_ld",
+ "@lowrisc_rv32imcb_files//:bin/riscv32-unknown-elf-ld",
+ ],
+)
diff --git a/hw/ip/rv_dm/data/rv_dm.hjson b/hw/ip/rv_dm/data/rv_dm.hjson
index 5151e59..0c8407f 100644
--- a/hw/ip/rv_dm/data/rv_dm.hjson
+++ b/hw/ip/rv_dm/data/rv_dm.hjson
@@ -31,7 +31,8 @@
param_list: [
{ name: "NrHarts",
type: "int",
- default: "1",
+ // TODO(b/271173103).
+ default: "2",
desc: "Number of hardware threads in the system."
local: "true"
},
@@ -110,11 +111,13 @@
power down of the core and bus-attached peripherals.
'''
},
- { struct: "logic [rv_dm_reg_pkg::NrHarts-1:0]"
+ { struct: "logic"
type: "uni"
name: "debug_req"
act: "req"
desc: "This is the debug request interrupt going to the main processor."
+ // TODO(b/271173103).
+ width: "2"
},
]
countermeasures: [
diff --git a/hw/ip/rv_dm/rtl/rv_dm_reg_pkg.sv b/hw/ip/rv_dm/rtl/rv_dm_reg_pkg.sv
index eb2c96c..f7791ca 100644
--- a/hw/ip/rv_dm/rtl/rv_dm_reg_pkg.sv
+++ b/hw/ip/rv_dm/rtl/rv_dm_reg_pkg.sv
@@ -7,7 +7,7 @@
package rv_dm_reg_pkg;
// Param list
- parameter int NrHarts = 1;
+ parameter int NrHarts = 2;
parameter int NumAlerts = 1;
// Address widths within the block
diff --git a/hw/ip/tlul/rtl/tlul_pkg.sv b/hw/ip/tlul/rtl/tlul_pkg.sv
index 4e9401f..34f601d 100644
--- a/hw/ip/tlul/rtl/tlul_pkg.sv
+++ b/hw/ip/tlul/rtl/tlul_pkg.sv
@@ -13,17 +13,43 @@
// both in terms of area and timing.
parameter ArbiterImpl = "PPC";
+ // TODO(hoangm): Below enums have been modified to support TL-UH. Eventually
+ // we'll want to upstream these changes to OT.
typedef enum logic [2:0] {
PutFullData = 3'h 0,
PutPartialData = 3'h 1,
- Get = 3'h 4
+ ArithmeticData = 3'h 2,
+ LogicalData = 3'h 3,
+ Get = 3'h 4,
+ Intent = 3'h 5
} tl_a_op_e;
typedef enum logic [2:0] {
AccessAck = 3'h 0,
- AccessAckData = 3'h 1
+ AccessAckData = 3'h 1,
+ HintAck = 3'h 2
} tl_d_op_e;
+ typedef enum logic [2:0] {
+ Min = 3'h 0,
+ Max = 3'h 1,
+ MinU = 3'h 2,
+ MaxU = 3'h 3,
+ Add = 3'h 4
+ } tl_a_arith_param_e;
+
+ typedef enum logic [2:0] {
+ Xor = 3'h 0,
+ Or = 3'h 1,
+ And = 3'h 2,
+ Swap = 3'h 3
+ } tl_a_logical_param_e;
+
+ typedef enum logic [2:0] {
+ PrefetchRead = 3'h 0,
+ PrefetchWrite = 3'h 1
+ } tl_a_intent_param_e;
+
parameter int H2DCmdMaxWidth = 57;
parameter int H2DCmdIntgWidth = 7;
parameter int H2DCmdFullWidth = H2DCmdMaxWidth + H2DCmdIntgWidth;
diff --git a/hw/lint/BUILD b/hw/lint/BUILD
new file mode 100644
index 0000000..2f3e391
--- /dev/null
+++ b/hw/lint/BUILD
@@ -0,0 +1,6 @@
+# Copyright 2022 Google contributors.
+
+package(default_visibility = ["//visibility:public"])
+
+# For matcha to get the directory of this folder and run fusesoc.
+exports_files(["BUILD"])
diff --git a/hw/vendor/BUILD b/hw/vendor/BUILD
new file mode 100644
index 0000000..2f3e391
--- /dev/null
+++ b/hw/vendor/BUILD
@@ -0,0 +1,6 @@
+# Copyright 2022 Google contributors.
+
+package(default_visibility = ["//visibility:public"])
+
+# For matcha to get the directory of this folder and run fusesoc.
+exports_files(["BUILD"])
diff --git a/python-requirements.txt b/python-requirements.txt
index 700f56d..bb655f6 100644
--- a/python-requirements.txt
+++ b/python-requirements.txt
@@ -5,7 +5,8 @@
# Keep sorted.
hjson==3.1.0
jsonschema==4.17.3; python_version >= "3.7"
-libcst==0.4.1
+# Need to pin to 0.4.9 to be compatible with python3.11
+libcst==0.4.9
mako==1.1.6
pluralizer==1.2.0
pycryptodome==3.15.0
@@ -50,12 +51,22 @@
anytree==2.8.0
# Development version with OT-specific changes
-git+https://github.com/lowRISC/fusesoc.git@ot-0.3
+# The version is different from upstream OT because ot-0.3 builds HW twice
+# somehow and doubles the build time.
+git+https://github.com/lowRISC/fusesoc.git@ot-0.1
# Development version with OT-specific changes
-git+https://github.com/lowRISC/edalize.git@v0.4.0
+# The version is different from upstream OT because v0.4.0 builds HW twice
+# somehow and doubles the build time.
+git+https://github.com/lowRISC/edalize.git@ot-0.1
# Development version of minimal ChipWhisperer toolchain with latest features
# and bug fixes. We fix the version for improved stability and manually update
# if necessary.
git+https://github.com/newaetech/chipwhisperer-minimal.git@2643131b71e528791446ee1bab7359120288f4ab#egg=chipwhisperer
+
+# Dependencies: @matcha//util/image_to_c.py
+Pillow == 9.3.0
+
+# Dependencies: @matcha//util/run_live_cam.py
+pyserial == 3.5
diff --git a/rules/fusesoc.bzl b/rules/fusesoc.bzl
index dbb7e02..242bad3 100644
--- a/rules/fusesoc.bzl
+++ b/rules/fusesoc.bzl
@@ -67,14 +67,24 @@
args.add_all(ctx.attr.systems)
args.add_all(flags)
+ _inputs = ctx.files.srcs + ctx.files.cores
+
+ # For some reason, the sanboxed fusesoc would call vivado twice. Add an
+ # option to use the system installed fusesoc.
+ if ctx.attr.use_system_fusesoc:
+ _exec = "fusesoc"
+ else:
+ _exec = ctx.executable._fusesoc
+ _inputs += ctx.files._fusesoc
+
# Note: the `fileset_top` flag used above is specific to the OpenTitan
# project to select the correct RTL fileset.
ctx.actions.run(
mnemonic = "FuseSoC",
outputs = outputs,
- inputs = ctx.files.srcs + ctx.files.cores + ctx.files._fusesoc,
+ inputs = _inputs,
arguments = [args],
- executable = ctx.executable._fusesoc,
+ executable = _exec,
use_default_shell_env = False,
execution_requirements = {
"no-sandbox": "",
@@ -104,6 +114,10 @@
),
"verilator_options": attr.label(),
"make_options": attr.label(),
+ "use_system_fusesoc": attr.bool(
+ default = False,
+ doc = "Use non-sanboxed fusesoc (for FPGA vivado build)",
+ ),
"_fusesoc": attr.label(
default = entry_point("fusesoc"),
executable = True,
diff --git a/rules/opentitan.bzl b/rules/opentitan.bzl
index 9a68c64..7d96cfd 100644
--- a/rules/opentitan.bzl
+++ b/rules/opentitan.bzl
@@ -326,7 +326,7 @@
"platform": attr.string(default = OPENTITAN_PLATFORM),
"_cleanup_script": attr.label(
allow_single_file = True,
- default = Label("@//rules/scripts:expand_tabs.sh"),
+ default = Label("@lowrisc_opentitan//rules/scripts:expand_tabs.sh"),
),
"_cc_toolchain": attr.label(default = Label("@bazel_tools//tools/cpp:current_cc_toolchain")),
},
@@ -481,7 +481,7 @@
"otp": attr.label(allow_single_file = True),
"vmem": attr.label(allow_single_file = True),
"_tool": attr.label(
- default = "@//util/design:gen-flash-img",
+ default = "@lowrisc_opentitan//util/design:gen-flash-img",
executable = True,
cfg = "exec",
),
@@ -529,7 +529,7 @@
"srcs": attr.label_list(allow_files = True),
"platform": attr.string(default = OPENTITAN_PLATFORM),
"_tool": attr.label(
- default = "@//util/device_sw_utils:extract_sw_logs_db",
+ default = "@lowrisc_opentitan//util/device_sw_utils:extract_sw_logs_db",
cfg = "exec",
executable = True,
),
diff --git a/rules/opentitan_test.bzl b/rules/opentitan_test.bzl
index 03870ed..455e371 100644
--- a/rules/opentitan_test.bzl
+++ b/rules/opentitan_test.bzl
@@ -2,7 +2,7 @@
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
# SPDX-License-Identifier: Apache-2.0
-load("@//rules:opentitan.bzl", "opentitan_flash_binary", "opentitan_rom_binary")
+load("@lowrisc_opentitan//rules:opentitan.bzl", "opentitan_flash_binary", "opentitan_rom_binary")
load("@bazel_skylib//lib:shell.bzl", "shell")
load("@bazel_skylib//lib:collections.bzl", "collections")
diff --git a/rules/ujson.bzl b/rules/ujson.bzl
index c7f922a..649510b 100644
--- a/rules/ujson.bzl
+++ b/rules/ujson.bzl
@@ -11,6 +11,9 @@
module = ctx.actions.declare_file("{}.rs".format(ctx.label.name))
ujson_lib = ctx.attr.ujson_lib[CcInfo].compilation_context.headers.to_list()
+ # Get the include search path for ujson.
+ ujson_lib_root = ctx.attr.ujson_lib[CcInfo].compilation_context.quote_includes.to_list()
+
srcs = []
includes = []
for src in ctx.attr.srcs:
@@ -29,7 +32,8 @@
# 3. Substitute all `rust_attr` for `#`, thus creating rust attributes.
# 4. Format it with `rustfmt` so it looks nice and can be inspected.
command = """
- {preprocessor} -nostdinc -I. -DRUST_PREPROCESSOR_EMIT=1 -DNOSTDINC=1 {defines} $@ \
+ {preprocessor} -nostdinc -I{ujson_lib_root_includes} \
+ -DRUST_PREPROCESSOR_EMIT=1 -DNOSTDINC=1 {defines} $@ \
| grep -v '#' \
| sed -e "s/rust_attr/#/g" \
| {rustfmt} > {module}""".format(
@@ -37,6 +41,7 @@
defines = " ".join(defines),
module = module.path,
rustfmt = rustfmt.path,
+ ujson_lib_root_includes = " -I".join(ujson_lib_root),
)
ctx.actions.run_shell(
diff --git a/sw/device/lib/dif/dif_rstmgr.c b/sw/device/lib/dif/dif_rstmgr.c
index d3daf35..4379653 100644
--- a/sw/device/lib/dif/dif_rstmgr.c
+++ b/sw/device/lib/dif/dif_rstmgr.c
@@ -32,9 +32,10 @@
<< RSTMGR_RESET_INFO_HW_REQ_OFFSET),
"kDifRstmgrResetInfoHwReq must match the register definition!");
-static_assert(
- RSTMGR_PARAM_NUM_SW_RESETS == 8,
- "Number of software resets has changed, please update this file!");
+// Turn off the static_assert to enable non-earlgrey top run
+// static_assert(
+// RSTMGR_PARAM_NUM_SW_RESETS == 8,
+// "Number of software resets has changed, please update this file!");
// The Reset Manager implementation will have to be updated if the number
// of software resets grows, as it would span across multiple registers, so
diff --git a/sw/device/lib/runtime/ibex.h b/sw/device/lib/runtime/ibex.h
index abe608b..634c972 100644
--- a/sw/device/lib/runtime/ibex.h
+++ b/sw/device/lib/runtime/ibex.h
@@ -35,6 +35,7 @@
kIbexExcLoadAccessFault = 5,
kIbexExcStoreAccessFault = 7,
kIbexExcUserECall = 8,
+ kIbexExcSupervisorECall = 9,
kIbexExcMachineECall = 11,
kIbexExcMax = 31
} ibex_exc_t;
diff --git a/sw/device/tests/BUILD b/sw/device/tests/BUILD
index 6153b52..95eb3ed 100644
--- a/sw/device/tests/BUILD
+++ b/sw/device/tests/BUILD
@@ -1117,6 +1117,10 @@
],
test_harness = "//sw/host/tests/chip/gpio",
verilator = verilator_params(
+ tags = [
+ # TODO(opentitan/#17812): Verilator test is broken
+ "broken",
+ ],
timeout = "eternal",
test_cmds = [],
),
@@ -1883,6 +1887,10 @@
timeout = "eternal",
exit_failure = ROM_BOOT_FAILURE_MSG,
rom = "//sw/device/silicon_creator/rom:rom_with_fake_keys",
+ tags = [
+ # TODO(opentitan/#17813): The test is broken
+ "broken",
+ ],
),
deps = [
"//hw/top_earlgrey/sw/autogen:top_earlgrey",
diff --git a/sw/device/tests/autogen/BUILD b/sw/device/tests/autogen/BUILD
index d139bea..efb602a 100644
--- a/sw/device/tests/autogen/BUILD
+++ b/sw/device/tests/autogen/BUILD
@@ -102,3 +102,52 @@
"//sw/device/lib/testing/test_framework:ottf_main",
],
)
+
+opentitan_functest(
+ name = "alert_renode_test",
+ srcs = ["alert_test.c"],
+ deps = [
+ "//hw/top_earlgrey/sw/autogen:top_earlgrey",
+ "//sw/device/lib/base:memory",
+ "//sw/device/lib/base:mmio",
+ "//sw/device/lib/dif:adc_ctrl",
+ "//sw/device/lib/dif:aes",
+ "//sw/device/lib/dif:alert_handler",
+ "//sw/device/lib/dif:aon_timer",
+ "//sw/device/lib/dif:clkmgr",
+ "//sw/device/lib/dif:csrng",
+ "//sw/device/lib/dif:edn",
+ "//sw/device/lib/dif:entropy_src",
+ "//sw/device/lib/dif:flash_ctrl",
+ "//sw/device/lib/dif:gpio",
+ "//sw/device/lib/dif:hmac",
+ "//sw/device/lib/dif:i2c",
+ "//sw/device/lib/dif:keymgr",
+ "//sw/device/lib/dif:kmac",
+ "//sw/device/lib/dif:lc_ctrl",
+ "//sw/device/lib/dif:otbn",
+ "//sw/device/lib/dif:otp_ctrl",
+ "//sw/device/lib/dif:pattgen",
+ "//sw/device/lib/dif:pinmux",
+ "//sw/device/lib/dif:pwm",
+ "//sw/device/lib/dif:pwrmgr",
+ "//sw/device/lib/dif:rom_ctrl",
+ "//sw/device/lib/dif:rstmgr",
+ "//sw/device/lib/dif:rv_core_ibex",
+ "//sw/device/lib/dif:rv_plic",
+ "//sw/device/lib/dif:rv_timer",
+ "//sw/device/lib/dif:sensor_ctrl",
+ "//sw/device/lib/dif:spi_device",
+ "//sw/device/lib/dif:spi_host",
+ "//sw/device/lib/dif:sram_ctrl",
+ "//sw/device/lib/dif:sysrst_ctrl",
+ "//sw/device/lib/dif:uart",
+ "//sw/device/lib/dif:usbdev",
+ "//sw/device/lib/runtime:log",
+ "//sw/device/lib/testing:alert_handler_testutils",
+ "//sw/device/lib/testing/test_framework:ottf_main",
+ ],
+ copts = [
+ "-DDISABLE_RENODE_TEST",
+ ],
+)
diff --git a/sw/device/tests/autogen/alert_test.c b/sw/device/tests/autogen/alert_test.c
index 0a8413c..3aeec02 100644
--- a/sw/device/tests/autogen/alert_test.c
+++ b/sw/device/tests/autogen/alert_test.c
@@ -280,6 +280,7 @@
bool is_cause;
dif_alert_handler_alert_t exp_alert;
+#ifndef DISABLE_RENODE_TEST
// Write adc_ctrl's alert_test reg and check alert_cause.
for (int i = 0; i < 1; ++i) {
CHECK_DIF_OK(dif_adc_ctrl_alert_force(&adc_ctrl_aon, kDifAdcCtrlAlertFatalFault + i));
@@ -294,6 +295,7 @@
CHECK_DIF_OK(dif_alert_handler_alert_acknowledge(
&alert_handler, exp_alert));
}
+#endif
// Write aes's alert_test reg and check alert_cause.
for (int i = 0; i < 2; ++i) {
@@ -325,6 +327,7 @@
&alert_handler, exp_alert));
}
+#ifndef DISABLE_RENODE_TEST
// Write clkmgr's alert_test reg and check alert_cause.
for (int i = 0; i < 2; ++i) {
CHECK_DIF_OK(dif_clkmgr_alert_force(&clkmgr_aon, kDifClkmgrAlertRecovFault + i));
@@ -339,6 +342,7 @@
CHECK_DIF_OK(dif_alert_handler_alert_acknowledge(
&alert_handler, exp_alert));
}
+#endif
// Write csrng's alert_test reg and check alert_cause.
for (int i = 0; i < 2; ++i) {
@@ -355,6 +359,7 @@
&alert_handler, exp_alert));
}
+#ifndef DISABLE_RENODE_TEST
// Write edn's alert_test reg and check alert_cause.
for (int i = 0; i < 2; ++i) {
CHECK_DIF_OK(dif_edn_alert_force(&edn0, kDifEdnAlertRecovAlert + i));
@@ -369,7 +374,9 @@
CHECK_DIF_OK(dif_alert_handler_alert_acknowledge(
&alert_handler, exp_alert));
}
+#endif
+#ifndef DISABLE_RENODE_TEST
// Write edn's alert_test reg and check alert_cause.
for (int i = 0; i < 2; ++i) {
CHECK_DIF_OK(dif_edn_alert_force(&edn1, kDifEdnAlertRecovAlert + i));
@@ -384,7 +391,9 @@
CHECK_DIF_OK(dif_alert_handler_alert_acknowledge(
&alert_handler, exp_alert));
}
+#endif
+#ifndef DISABLE_RENODE_TEST
// Write entropy_src's alert_test reg and check alert_cause.
for (int i = 0; i < 2; ++i) {
CHECK_DIF_OK(dif_entropy_src_alert_force(&entropy_src, kDifEntropySrcAlertRecovAlert + i));
@@ -399,6 +408,7 @@
CHECK_DIF_OK(dif_alert_handler_alert_acknowledge(
&alert_handler, exp_alert));
}
+#endif
// Write flash_ctrl's alert_test reg and check alert_cause.
for (int i = 0; i < 5; ++i) {
@@ -490,6 +500,7 @@
&alert_handler, exp_alert));
}
+#ifndef DISABLE_RENODE_TEST
// Write keymgr's alert_test reg and check alert_cause.
for (int i = 0; i < 2; ++i) {
CHECK_DIF_OK(dif_keymgr_alert_force(&keymgr, kDifKeymgrAlertRecovOperationErr + i));
@@ -504,6 +515,7 @@
CHECK_DIF_OK(dif_alert_handler_alert_acknowledge(
&alert_handler, exp_alert));
}
+#endif
// Write kmac's alert_test reg and check alert_cause.
for (int i = 0; i < 2; ++i) {
@@ -565,6 +577,7 @@
&alert_handler, exp_alert));
}
+#ifndef DISABLE_RENODE_TEST
// Write pattgen's alert_test reg and check alert_cause.
for (int i = 0; i < 1; ++i) {
CHECK_DIF_OK(dif_pattgen_alert_force(&pattgen, kDifPattgenAlertFatalFault + i));
@@ -579,7 +592,9 @@
CHECK_DIF_OK(dif_alert_handler_alert_acknowledge(
&alert_handler, exp_alert));
}
+#endif
+#ifndef DISABLE_RENODE_TEST
// Write pinmux's alert_test reg and check alert_cause.
for (int i = 0; i < 1; ++i) {
CHECK_DIF_OK(dif_pinmux_alert_force(&pinmux_aon, kDifPinmuxAlertFatalFault + i));
@@ -594,7 +609,9 @@
CHECK_DIF_OK(dif_alert_handler_alert_acknowledge(
&alert_handler, exp_alert));
}
+#endif
+#ifndef DISABLE_RENODE_TEST
// Write pwm's alert_test reg and check alert_cause.
for (int i = 0; i < 1; ++i) {
CHECK_DIF_OK(dif_pwm_alert_force(&pwm_aon, kDifPwmAlertFatalFault + i));
@@ -609,6 +626,7 @@
CHECK_DIF_OK(dif_alert_handler_alert_acknowledge(
&alert_handler, exp_alert));
}
+#endif
// Write pwrmgr's alert_test reg and check alert_cause.
for (int i = 0; i < 1; ++i) {
@@ -670,6 +688,7 @@
&alert_handler, exp_alert));
}
+#ifndef DISABLE_RENODE_TEST
// Write rv_plic's alert_test reg and check alert_cause.
for (int i = 0; i < 1; ++i) {
CHECK_DIF_OK(dif_rv_plic_alert_force(&rv_plic, kDifRvPlicAlertFatalFault + i));
@@ -684,6 +703,7 @@
CHECK_DIF_OK(dif_alert_handler_alert_acknowledge(
&alert_handler, exp_alert));
}
+#endif
// Write rv_timer's alert_test reg and check alert_cause.
for (int i = 0; i < 1; ++i) {
@@ -700,6 +720,7 @@
&alert_handler, exp_alert));
}
+#ifndef DISABLE_RENODE_TEST
// Write sensor_ctrl's alert_test reg and check alert_cause.
for (int i = 0; i < 2; ++i) {
CHECK_DIF_OK(dif_sensor_ctrl_alert_force(&sensor_ctrl, kDifSensorCtrlAlertRecovAlert + i));
@@ -714,7 +735,9 @@
CHECK_DIF_OK(dif_alert_handler_alert_acknowledge(
&alert_handler, exp_alert));
}
+#endif
+#ifndef DISABLE_RENODE_TEST
// Write spi_device's alert_test reg and check alert_cause.
for (int i = 0; i < 1; ++i) {
CHECK_DIF_OK(dif_spi_device_alert_force(&spi_device, kDifSpiDeviceAlertFatalFault + i));
@@ -729,6 +752,7 @@
CHECK_DIF_OK(dif_alert_handler_alert_acknowledge(
&alert_handler, exp_alert));
}
+#endif
// Write spi_host's alert_test reg and check alert_cause.
for (int i = 0; i < 1; ++i) {
@@ -760,6 +784,7 @@
&alert_handler, exp_alert));
}
+#ifndef DISABLE_RENODE_TEST
// Write sram_ctrl's alert_test reg and check alert_cause.
for (int i = 0; i < 1; ++i) {
CHECK_DIF_OK(dif_sram_ctrl_alert_force(&sram_ctrl_main, kDifSramCtrlAlertFatalError + i));
@@ -774,7 +799,9 @@
CHECK_DIF_OK(dif_alert_handler_alert_acknowledge(
&alert_handler, exp_alert));
}
+#endif
+#ifndef DISABLE_RENODE_TEST
// Write sram_ctrl's alert_test reg and check alert_cause.
for (int i = 0; i < 1; ++i) {
CHECK_DIF_OK(dif_sram_ctrl_alert_force(&sram_ctrl_ret_aon, kDifSramCtrlAlertFatalError + i));
@@ -789,7 +816,9 @@
CHECK_DIF_OK(dif_alert_handler_alert_acknowledge(
&alert_handler, exp_alert));
}
+#endif
+#ifndef DISABLE_RENODE_TEST
// Write sysrst_ctrl's alert_test reg and check alert_cause.
for (int i = 0; i < 1; ++i) {
CHECK_DIF_OK(dif_sysrst_ctrl_alert_force(&sysrst_ctrl_aon, kDifSysrstCtrlAlertFatalFault + i));
@@ -804,6 +833,7 @@
CHECK_DIF_OK(dif_alert_handler_alert_acknowledge(
&alert_handler, exp_alert));
}
+#endif
// Write uart's alert_test reg and check alert_cause.
for (int i = 0; i < 1; ++i) {
@@ -865,6 +895,7 @@
&alert_handler, exp_alert));
}
+#ifndef DISABLE_RENODE_TEST
// Write usbdev's alert_test reg and check alert_cause.
for (int i = 0; i < 1; ++i) {
CHECK_DIF_OK(dif_usbdev_alert_force(&usbdev, kDifUsbdevAlertFatalFault + i));
@@ -879,6 +910,7 @@
CHECK_DIF_OK(dif_alert_handler_alert_acknowledge(
&alert_handler, exp_alert));
}
+#endif
}
bool test_main(void) {
diff --git a/sw/device/tests/sim_dv/i2c_host_tx_rx_test.c b/sw/device/tests/sim_dv/i2c_host_tx_rx_test.c
index a0a5649..03c8333 100644
--- a/sw/device/tests/sim_dv/i2c_host_tx_rx_test.c
+++ b/sw/device/tests/sim_dv/i2c_host_tx_rx_test.c
@@ -9,8 +9,8 @@
#include "sw/device/lib/dif/dif_pinmux.h"
#include "sw/device/lib/dif/dif_rv_plic.h"
#include "sw/device/lib/runtime/hart.h"
-#include "sw/device/lib/runtime/irq.h"
#include "sw/device/lib/runtime/log.h"
+#include "sw/device/lib/runtime/irq.h"
#include "sw/device/lib/testing/i2c_testutils.h"
#include "sw/device/lib/testing/rand_testutils.h"
#include "sw/device/lib/testing/test_framework/check.h"
diff --git a/sw/host/opentitanlib/BUILD b/sw/host/opentitanlib/BUILD
index d7ab74a..6eeb38f 100644
--- a/sw/host/opentitanlib/BUILD
+++ b/sw/host/opentitanlib/BUILD
@@ -46,6 +46,7 @@
"src/backend/cw310.rs",
"src/backend/hyperdebug.rs",
"src/backend/mod.rs",
+ "src/backend/nexus.rs",
"src/backend/proxy.rs",
"src/backend/ti50emulator.rs",
"src/backend/ultradebug.rs",
@@ -118,6 +119,9 @@
"src/transport/hyperdebug/mod.rs",
"src/transport/hyperdebug/spi.rs",
"src/transport/mod.rs",
+ "src/transport/nexus/gpio.rs",
+ "src/transport/nexus/mod.rs",
+ "src/transport/nexus/spi.rs",
"src/transport/proxy/emu.rs",
"src/transport/proxy/gpio.rs",
"src/transport/proxy/i2c.rs",
diff --git a/sw/host/opentitanlib/src/app/config/mod.rs b/sw/host/opentitanlib/src/app/config/mod.rs
index 7913363..36669e0 100644
--- a/sw/host/opentitanlib/src/app/config/mod.rs
+++ b/sw/host/opentitanlib/src/app/config/mod.rs
@@ -67,5 +67,6 @@
"/__builtin__/hyperdebug_cw310.json" => include_str!("hyperdebug_cw310.json"),
"/__builtin__/opentitan_ultradebug.json" => include_str!("opentitan_ultradebug.json"),
"/__builtin__/opentitan_verilator.json" => include_str!("opentitan_verilator.json"),
+ "/__builtin__/nexus.json" => include_str!("nexus.json"),
};
}
diff --git a/sw/host/opentitanlib/src/app/config/nexus.json b/sw/host/opentitanlib/src/app/config/nexus.json
new file mode 100644
index 0000000..e34a640
--- /dev/null
+++ b/sw/host/opentitanlib/src/app/config/nexus.json
@@ -0,0 +1,64 @@
+{
+ "interface": "nexus",
+ "pins": [
+ {
+ "name": "RESET",
+ "alias_of": "RESET_B",
+ "mode": "PushPull",
+ "level": true,
+ "pull_mode": "None"
+ },
+ {
+ "name": "SW_STRAP0",
+ "mode": "PushPull",
+ "level": false,
+ "pull_mode": "None"
+ },
+ {
+ "name": "SW_STRAP1",
+ "mode": "PushPull",
+ "level": false,
+ "pull_mode": "None"
+ },
+ {
+ "name": "SW_STRAP2",
+ "mode": "PushPull",
+ "level": false,
+ "pull_mode": "None"
+ }
+ ],
+ "strappings": [
+ {
+ "name": "ROM_BOOTSTRAP",
+ "pins": [
+ {
+ "name": "SW_STRAP0",
+ "level": true
+ },
+ {
+ "name": "SW_STRAP1",
+ "level": true
+ },
+ {
+ "name": "SW_STRAP2",
+ "level": true
+ }
+ ]
+ },
+ {
+ "name": "RESET",
+ "pins": [
+ {
+ "name": "RESET",
+ "level": false
+ }
+ ]
+ }
+ ],
+ "spi": [
+ {
+ "name": "BOOTSTRAP",
+ "alias_of": "0"
+ }
+ ]
+}
diff --git a/sw/host/opentitanlib/src/backend/mod.rs b/sw/host/opentitanlib/src/backend/mod.rs
index cca0d56..0570fe3 100644
--- a/sw/host/opentitanlib/src/backend/mod.rs
+++ b/sw/host/opentitanlib/src/backend/mod.rs
@@ -16,6 +16,7 @@
mod cw310;
mod hyperdebug;
+mod nexus;
mod proxy;
mod ti50emulator;
mod ultradebug;
@@ -89,6 +90,10 @@
cw310::create(args)?,
Some(Path::new("/__builtin__/opentitan_cw310.json")),
),
+ "nexus" => (
+ nexus::create(args)?,
+ Some(Path::new("/__builtin__/nexus.json")),
+ ),
_ => return Err(Error::UnknownInterface(interface.to_string()).into()),
};
let mut env = TransportWrapperBuilder::new(backend);
diff --git a/sw/host/opentitanlib/src/backend/nexus.rs b/sw/host/opentitanlib/src/backend/nexus.rs
new file mode 100644
index 0000000..5e7292c
--- /dev/null
+++ b/sw/host/opentitanlib/src/backend/nexus.rs
@@ -0,0 +1,17 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+use crate::transport::nexus::Nexus;
+use crate::transport::Transport;
+use anyhow::Result;
+
+use crate::backend::BackendOpts;
+
+pub fn create(args: &BackendOpts) -> Result<Box<dyn Transport>> {
+ Ok(Box::new(Nexus::new(
+ args.usb_vid,
+ args.usb_pid,
+ args.usb_serial.clone(),
+ )))
+}
diff --git a/sw/host/opentitanlib/src/spiflash/flash.rs b/sw/host/opentitanlib/src/spiflash/flash.rs
index 615be32..0012797 100644
--- a/sw/host/opentitanlib/src/spiflash/flash.rs
+++ b/sw/host/opentitanlib/src/spiflash/flash.rs
@@ -55,8 +55,11 @@
impl SpiFlash {
// Well known SPI Flash opcodes.
pub const READ: u8 = 0x03;
+ pub const READ4: u8 = 0x13;
pub const PAGE_PROGRAM: u8 = 0x02;
pub const SECTOR_ERASE: u8 = 0x20;
+ pub const BLOCK_ERASE_3B: u8 = 0xd8;
+ pub const BLOCK_ERASE_4B: u8 = 0xdc;
pub const CHIP_ERASE: u8 = 0xc7;
pub const WRITE_ENABLE: u8 = 0x06;
pub const WRITE_DISABLE: u8 = 0x04;
@@ -230,8 +233,12 @@
) -> Result<&Self> {
// Break the read up according to the maximum chunksize the backend can handle.
for chunk in buffer.chunks_mut(spi.max_chunk_size()?) {
+ let opcode = match self.address_mode {
+ AddressMode::Mode3b => SpiFlash::READ,
+ AddressMode::Mode4b => SpiFlash::READ4,
+ };
spi.run_eeprom_transactions(&mut [Transaction::Read(
- MODE_111.cmd_addr(SpiFlash::READ, address, self.address_mode),
+ MODE_111.cmd_addr(opcode, address, self.address_mode),
chunk,
)])?;
address += chunk.len() as u32;
@@ -250,12 +257,49 @@
Ok(self)
}
+ // Erase in 256kB blocks.
+ pub fn block_erase(&self, spi: &dyn Target, address: u32, length: u32) -> Result<()> {
+ self.block_erase_with_progress(spi, address, length, |_, _| {})
+ }
+
/// Erase a segment of the SPI flash starting at `address` for `length` bytes.
/// The address and length must be sector aligned.
pub fn erase(&self, spi: &dyn Target, address: u32, length: u32) -> Result<&Self> {
self.erase_with_progress(spi, address, length, |_, _| {})
}
+ /// Block erase, and a progress bar.
+ pub fn block_erase_with_progress(
+ &self,
+ spi: &dyn Target,
+ address: u32,
+ length: u32,
+ progress: impl Fn(u32, u32),
+ ) -> Result<()> {
+ // 256kB sectors
+ let sector_size = 256 * 1024;
+ if address % sector_size != 0 {
+ return Err(Error::BadEraseAddress(address, sector_size).into());
+ }
+ if length % sector_size != 0 {
+ return Err(Error::BadEraseAddress(length, sector_size).into());
+ }
+ let end = address + length;
+ for addr in (address..end).step_by(sector_size as usize) {
+ let opcode = match self.address_mode {
+ AddressMode::Mode3b => SpiFlash::BLOCK_ERASE_3B,
+ AddressMode::Mode4b => SpiFlash::BLOCK_ERASE_4B,
+ };
+ spi.run_eeprom_transactions(&mut [
+ Transaction::Command(MODE_111.cmd(SpiFlash::WRITE_ENABLE)),
+ Transaction::Command(MODE_111.cmd_addr(opcode, address, self.address_mode)),
+ Transaction::WaitForBusyClear,
+ ])?;
+ progress(addr, sector_size);
+ }
+ Ok(())
+ }
+
/// Erase a segment of the SPI flash starting at `address` for `length` bytes.
/// The address and length must be sector aligned.
/// The `progress` callback will be invoked after each chunk of the erase operation.
diff --git a/sw/host/opentitanlib/src/spiflash/sfdp.rs b/sw/host/opentitanlib/src/spiflash/sfdp.rs
index 0a109c5..4b83a1a 100644
--- a/sw/host/opentitanlib/src/spiflash/sfdp.rs
+++ b/sw/host/opentitanlib/src/spiflash/sfdp.rs
@@ -941,7 +941,7 @@
let start = (8 + i * 8) as usize;
let end = start + 8;
let phdr = SfdpPhdr::try_from(&buf[start..end])?;
- len = std::cmp::max(len, phdr.offset + (phdr.dwords * 4) as u32);
+ len = std::cmp::max(len, phdr.offset + ((phdr.dwords as u32) * 4) as u32);
log::debug!("computed sfdp len = {}", len);
}
Ok(len as usize)
diff --git a/sw/host/opentitanlib/src/transport/mod.rs b/sw/host/opentitanlib/src/transport/mod.rs
index cd484d6..cef1824 100644
--- a/sw/host/opentitanlib/src/transport/mod.rs
+++ b/sw/host/opentitanlib/src/transport/mod.rs
@@ -19,6 +19,7 @@
pub mod common;
pub mod cw310;
pub mod hyperdebug;
+pub mod nexus;
pub mod proxy;
pub mod ti50emulator;
pub mod ultradebug;
diff --git a/sw/host/opentitanlib/src/transport/nexus/gpio.rs b/sw/host/opentitanlib/src/transport/nexus/gpio.rs
new file mode 100644
index 0000000..91350f8
--- /dev/null
+++ b/sw/host/opentitanlib/src/transport/nexus/gpio.rs
@@ -0,0 +1,113 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+use anyhow::{ensure, Context, Result};
+use lazy_static::lazy_static;
+use safe_ftdi as ftdi;
+use std::cell::RefCell;
+use std::collections::HashMap;
+use std::rc::Rc;
+
+use crate::collection;
+use crate::io::gpio::{GpioError, GpioPin, PinMode, PullMode};
+use crate::transport::nexus::Nexus;
+use crate::transport::ultradebug::mpsse;
+use crate::util::parse_int::ParseInt;
+
+/// Represents the Nexus GPIO pins.
+pub struct NexusGpio {
+ pub device: Rc<RefCell<mpsse::Context>>,
+}
+
+impl NexusGpio {
+ pub const PIN_SW_STRAP0: u8 = 4;
+ pub const PIN_SW_STRAP1: u8 = 5;
+ pub const PIN_SW_STRAP2: u8 = 6;
+ pub const PIN_RESET_B: u8 = 7;
+ const LAST_PIN_NUM: u8 = 7;
+
+ pub fn open(nexus: &Nexus) -> Result<Self> {
+ Ok(NexusGpio {
+ device: nexus.mpsse(ftdi::Interface::A)?,
+ })
+ }
+
+ pub fn pin(&self, pinname: &str) -> Result<NexusGpioPin> {
+ Ok(NexusGpioPin {
+ device: self.device.clone(),
+ pin_id: self.pin_name_to_number(pinname)?,
+ })
+ }
+
+ /// Given an nexus pin name, return its pin number.
+ pub fn pin_name_to_number(&self, pinname: &str) -> Result<u8> {
+ // If the pinname is an integer, use it; otherwise try to see if it
+ // is a symbolic name of a pin.
+ if let Ok(pinnum) = u8::from_str(pinname) {
+ ensure!(
+ pinnum <= NexusGpio::LAST_PIN_NUM,
+ GpioError::InvalidPinNumber(pinnum)
+ );
+ return Ok(pinnum);
+ }
+ let pinname = pinname.to_uppercase();
+ let pn = pinname.as_str();
+ PIN_NAMES
+ .get(pn)
+ .copied()
+ .ok_or_else(|| GpioError::InvalidPinName(pinname).into())
+ }
+}
+
+pub struct NexusGpioPin {
+ device: Rc<RefCell<mpsse::Context>>,
+ pin_id: u8,
+}
+
+impl GpioPin for NexusGpioPin {
+ /// Reads the value of the the GPIO pin `id`.
+ fn read(&self) -> Result<bool> {
+ let bits = self.device.borrow_mut().gpio_get().context("FTDI error")?;
+ Ok(bits & (1 << self.pin_id) != 0)
+ }
+
+ /// Sets the value of the GPIO pin `id` to `value`.
+ fn write(&self, value: bool) -> Result<()> {
+ self.device
+ .borrow_mut()
+ .gpio_set(self.pin_id, value)
+ .context("FTDI error")?;
+ Ok(())
+ }
+
+ /// Sets the `direction` of GPIO `id` as input or output.
+ fn set_mode(&self, mode: PinMode) -> Result<()> {
+ let direction = match mode {
+ PinMode::Input => false,
+ PinMode::PushPull => true,
+ PinMode::OpenDrain => return Err(GpioError::UnsupportedPinMode(mode).into()),
+ PinMode::AnalogInput |
+ PinMode::AnalogOutput |
+ PinMode::Alternate => todo!(),
+ };
+ self.device
+ .borrow_mut()
+ .gpio_set_direction(self.pin_id, direction)
+ .context("FTDI error")?;
+ Ok(())
+ }
+
+ fn set_pull_mode(&self, _mode: PullMode) -> Result<()> {
+ Ok(())
+ }
+}
+
+lazy_static! {
+ static ref PIN_NAMES: HashMap<&'static str, u8> = collection! {
+ "SW_STRAP0" => 4,
+ "SW_STRAP1" => 5,
+ "SW_STRAP2" => 6,
+ "RESET_B" => 7,
+ };
+}
diff --git a/sw/host/opentitanlib/src/transport/nexus/mod.rs b/sw/host/opentitanlib/src/transport/nexus/mod.rs
new file mode 100644
index 0000000..40db0a5
--- /dev/null
+++ b/sw/host/opentitanlib/src/transport/nexus/mod.rs
@@ -0,0 +1,119 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+use anyhow::{bail, ensure, Context, Result};
+use safe_ftdi as ftdi;
+use std::cell::RefCell;
+use std::rc::Rc;
+
+use crate::io::gpio::GpioPin;
+use crate::io::spi::Target;
+use crate::transport::{
+ Capabilities, Capability, Transport, TransportError, TransportInterfaceType,
+};
+use crate::transport::ultradebug::mpsse;
+
+pub mod gpio;
+pub mod spi;
+
+#[derive(Default)]
+pub struct Nexus {
+ pub usb_vid: Option<u16>,
+ pub usb_pid: Option<u16>,
+ pub usb_serial: Option<String>,
+ mpsse_a: RefCell<Option<Rc<RefCell<mpsse::Context>>>>,
+ inner: RefCell<Inner>,
+}
+
+#[derive(Default)]
+struct Inner {
+ gpio: Option<Rc<gpio::NexusGpio>>,
+ spi: Option<Rc<dyn Target>>,
+}
+
+impl Nexus {
+ /// Create a new `Nexus` struct, optionally specifying the USB vid/pid/serial number.
+ pub fn new(usb_vid: Option<u16>, usb_pid: Option<u16>, usb_serial: Option<String>) -> Self {
+ Nexus {
+ usb_vid,
+ usb_pid,
+ usb_serial,
+ ..Default::default()
+ }
+ }
+
+ /// Construct an `ftdi::Device` for the specified `interface` on the Nexus device.
+ pub fn from_interface(&self, interface: ftdi::Interface) -> Result<ftdi::Device> {
+ Ok(ftdi::Device::from_description_serial(
+ interface,
+ self.usb_vid.unwrap_or(0x0403),
+ self.usb_pid.unwrap_or(0x6011),
+ None,
+ self.usb_serial.clone(),
+ )
+ .context("FTDI error")?)
+ }
+
+ fn mpsse_interface_a(&self) -> Result<Rc<RefCell<mpsse::Context>>> {
+ let mut mpsse_a = self.mpsse_a.borrow_mut();
+ if mpsse_a.is_none() {
+ let device = self.from_interface(ftdi::Interface::A)?;
+ device.set_timeouts(5000, 5000);
+ let mut mpdev = mpsse::Context::new(device).context("FTDI error")?;
+ mpdev.gpio_direction.insert(
+ mpsse::GpioDirection::OUT_0 |
+ mpsse::GpioDirection::OUT_1 |
+ mpsse::GpioDirection::OUT_3 |
+ mpsse::GpioDirection::OUT_4 |
+ mpsse::GpioDirection::OUT_5 |
+ mpsse::GpioDirection::OUT_6 |
+ mpsse::GpioDirection::OUT_7);
+ let _ = mpdev.gpio_get().context("FTDI error")?;
+ mpdev.gpio_value &= 0xF8;
+ *mpsse_a = Some(Rc::new(RefCell::new(mpdev)));
+ }
+ Ok(Rc::clone(mpsse_a.as_ref().unwrap()))
+ }
+
+ /// Construct an `mpsse::Context` for the requested interface.
+ pub fn mpsse(&self, interface: ftdi::Interface) -> Result<Rc<RefCell<mpsse::Context>>> {
+ match interface {
+ ftdi::Interface::A => self.mpsse_interface_a(),
+ _ => {
+ bail!(TransportError::UsbOpenError(format!(
+ "I don't know how to create an MPSSE context for interface {:?}",
+ interface
+ )));
+ }
+ }
+ }
+}
+
+impl Transport for Nexus {
+ fn capabilities(&self) -> Result<Capabilities> {
+ Ok(Capabilities::new(
+ Capability::GPIO | Capability::SPI,
+ ))
+ }
+
+ fn gpio_pin(&self, instance: &str) -> Result<Rc<dyn GpioPin>> {
+ let mut inner = self.inner.borrow_mut();
+ if inner.gpio.is_none() {
+ inner.gpio = Some(Rc::new(gpio::NexusGpio::open(self)?));
+ }
+ Ok(Rc::new(inner.gpio.as_ref().unwrap().pin(instance)?))
+ }
+
+ fn spi(&self, instance: &str) -> Result<Rc<dyn Target>> {
+ ensure!(
+ instance == "0",
+ TransportError::InvalidInstance(TransportInterfaceType::Spi, instance.to_string())
+ );
+ let mut inner = self.inner.borrow_mut();
+ if inner.spi.is_none() {
+ inner.spi = Some(Rc::new(spi::NexusSpi::open(self)?));
+ }
+ Ok(Rc::clone(inner.spi.as_ref().unwrap()))
+ }
+}
diff --git a/sw/host/opentitanlib/src/transport/nexus/spi.rs b/sw/host/opentitanlib/src/transport/nexus/spi.rs
new file mode 100644
index 0000000..96c8522
--- /dev/null
+++ b/sw/host/opentitanlib/src/transport/nexus/spi.rs
@@ -0,0 +1,198 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+use anyhow::{Context, Result};
+use safe_ftdi as ftdi;
+use std::cell::RefCell;
+use std::rc::Rc;
+
+use crate::io::spi::{
+ AssertChipSelect, ClockPolarity, SpiError, Target, TargetChipDeassert, Transfer, TransferMode,
+};
+use crate::transport::nexus::Nexus;
+use crate::transport::ultradebug::mpsse;
+
+struct Inner {
+ mode: TransferMode,
+ cs_asserted_count: u32,
+}
+
+/// Represents the Nexus SPI device.
+pub struct NexusSpi {
+ pub device: Rc<RefCell<mpsse::Context>>,
+ inner: RefCell<Inner>,
+}
+
+impl NexusSpi {
+ pub const PIN_CLOCK: u8 = 0;
+ pub const PIN_MOSI: u8 = 1;
+ pub const PIN_MISO: u8 = 2;
+ pub const PIN_CHIP_SELECT: u8 = 3;
+ pub const MASK_CHIP_SELECT: u8 = 1u8 << Self::PIN_CHIP_SELECT;
+ pub const PIN_SPI_ZB: u8 = 4;
+ pub fn open(ultradebug: &Nexus) -> Result<Self> {
+ // let mpsse = ultradebug.mpsse(ftdi::Interface::B)?;
+ let mpsse = ultradebug.mpsse(ftdi::Interface::A)?;
+ // Note: platforms ultradebugs tristate their SPI lines
+ // unless SPI_ZB is driven low. Non-platforms ultradebugs
+ // don't use SPI_ZB, so this is safe for both types of devices.
+ // log::debug!("Setting SPI_ZB");
+ // mpsse
+ // .borrow_mut()
+ // .gpio_set(NexusSpi::PIN_SPI_ZB, false)
+ // .context("FTDI error f")?;
+
+ Ok(NexusSpi {
+ device: mpsse,
+ inner: RefCell::new(Inner {
+ mode: TransferMode::Mode0,
+ cs_asserted_count: 0,
+ }),
+ })
+ }
+
+ fn do_assert_cs(&self, assert: bool) -> Result<()> {
+ let device = self.device.borrow();
+ // Assert or deassert CS#
+ device
+ .execute(&mut [mpsse::Command::SetLowGpio(
+ device.gpio_direction,
+ if assert {
+ device.gpio_value & !Self::MASK_CHIP_SELECT
+ } else {
+ device.gpio_value | Self::MASK_CHIP_SELECT
+ },
+ )])
+ .context("FTDI error g")?;
+ Ok(())
+ }
+}
+
+impl Target for NexusSpi {
+ fn get_transfer_mode(&self) -> Result<TransferMode> {
+ Ok(self.inner.borrow().mode)
+ }
+ fn set_transfer_mode(&self, mode: TransferMode) -> Result<()> {
+ self.inner.borrow_mut().mode = mode;
+ Ok(())
+ }
+
+ fn get_bits_per_word(&self) -> Result<u32> {
+ Ok(8)
+ }
+ fn set_bits_per_word(&self, bits_per_word: u32) -> Result<()> {
+ match bits_per_word {
+ 8 => Ok(()),
+ _ => Err(SpiError::InvalidWordSize(bits_per_word).into()),
+ }
+ }
+
+ fn get_max_speed(&self) -> Result<u32> {
+ Ok(self.device.borrow().max_clock_frequency)
+ }
+ fn set_max_speed(&self, frequency: u32) -> Result<()> {
+ let mut device = self.device.borrow_mut();
+ device
+ .set_clock_frequency(frequency)
+ .context("FTDI errorh ")?;
+ Ok(())
+ }
+
+ fn get_max_transfer_count(&self) -> Result<usize> {
+ // Arbitrary value: number of `Transfers` that can be in a single transaction.
+ Ok(42)
+ }
+
+ fn max_chunk_size(&self) -> Result<usize> {
+ // Size of the FTDI read buffer. We can't perform a read larger than this;
+ // the FTDI device simply won't read any more.
+ Ok(65536)
+ }
+
+ fn run_transaction(&self, transaction: &mut [Transfer]) -> Result<()> {
+ let (rdedge, wredge) = match self.inner.borrow().mode.polarity() {
+ ClockPolarity::IdleLow => (mpsse::ClockEdge::Rising, mpsse::ClockEdge::Falling),
+ ClockPolarity::IdleHigh => (mpsse::ClockEdge::Falling, mpsse::ClockEdge::Rising),
+ };
+
+ let mut command = Vec::new();
+ let device = self.device.borrow();
+ let cs_not_already_asserted = self.inner.borrow().cs_asserted_count == 0;
+ if cs_not_already_asserted {
+ // Assert CS# (drive low).
+ command.push(mpsse::Command::SetLowGpio(
+ device.gpio_direction,
+ device.gpio_value & !Self::MASK_CHIP_SELECT,
+ ));
+ }
+ // Translate SPI Read/Write Transactions into MPSSE Commands.
+ for transfer in transaction.iter_mut() {
+ command.push(match transfer {
+ Transfer::Read(buf) => mpsse::Command::ReadData(
+ mpsse::DataShiftOptions {
+ read_clock_edge: rdedge,
+ read_data: true,
+ ..Default::default()
+ },
+ buf,
+ ),
+ Transfer::Write(buf) => mpsse::Command::WriteData(
+ mpsse::DataShiftOptions {
+ write_clock_edge: wredge,
+ write_data: true,
+ ..Default::default()
+ },
+ buf,
+ ),
+ Transfer::Both(wbuf, rbuf) => mpsse::Command::TransactData(
+ mpsse::DataShiftOptions {
+ write_clock_edge: wredge,
+ write_data: true,
+ ..Default::default()
+ },
+ wbuf,
+ mpsse::DataShiftOptions {
+ read_clock_edge: rdedge,
+ read_data: true,
+ ..Default::default()
+ },
+ rbuf,
+ ),
+ });
+ }
+ if cs_not_already_asserted {
+ // Release CS# (allow to float high).
+ command.push(mpsse::Command::SetLowGpio(
+ device.gpio_direction,
+ device.gpio_value | Self::MASK_CHIP_SELECT,
+ ));
+ }
+ device.execute(&mut command).context("FTDI error i")?;
+ Ok(())
+ }
+
+ fn assert_cs(self: Rc<Self>) -> Result<AssertChipSelect> {
+ {
+ let mut inner = self.inner.borrow_mut();
+ if inner.cs_asserted_count == 0 {
+ self.do_assert_cs(true)?;
+ }
+ inner.cs_asserted_count += 1;
+ }
+ Ok(AssertChipSelect::new(self))
+ }
+}
+
+impl TargetChipDeassert for NexusSpi {
+ fn deassert_cs(&self) {
+ let mut inner = self.inner.borrow_mut();
+ inner.cs_asserted_count -= 1;
+ if inner.cs_asserted_count == 0 {
+ // We cannot propagate errors through `Drop::drop()`, so panic on any error. (Logging
+ // would be another option.)
+ self.do_assert_cs(false)
+ .expect("Error while deasserting CS");
+ }
+ }
+}
diff --git a/sw/host/opentitantool/src/command/spi.rs b/sw/host/opentitantool/src/command/spi.rs
index 97d8734..935da52 100644
--- a/sw/host/opentitantool/src/command/spi.rs
+++ b/sw/host/opentitantool/src/command/spi.rs
@@ -8,11 +8,13 @@
use std::fs::{self, File};
use std::io::{self, Write};
use std::path::PathBuf;
-use std::time::Instant;
+use std::time::{Duration, Instant};
use structopt::StructOpt;
use opentitanlib::app::command::CommandDispatch;
use opentitanlib::app::{self, TransportWrapper};
+// Use PinMode if gpio is enabled
+// use opentitanlib::io::gpio::PinMode;
use opentitanlib::io::spi::{SpiParams, Transfer};
use opentitanlib::spiflash::SpiFlash;
use opentitanlib::tpm;
@@ -215,6 +217,25 @@
bytes_per_second: f64,
}
+#[derive(Debug, StructOpt)]
+pub struct SpiBlockErase {
+ #[structopt(short, long, help = "Start offset.")]
+ start: u32,
+ #[structopt(short = "n", long, help = "Number of bytes to erase.")]
+ length: u32,
+}
+
+#[derive(Debug, serde::Serialize)]
+pub struct SpiBlockEraseResponse {
+ length: u32,
+ bytes_per_second: f64,
+}
+
+#[derive(Debug, StructOpt)]
+pub struct SpiChipErase {}
+#[derive(Debug, serde::Serialize)]
+pub struct SpiChipEraseResponse {}
+
impl CommandDispatch for SpiErase {
fn run(
&self,
@@ -242,6 +263,49 @@
}
}
+impl CommandDispatch for SpiBlockErase {
+ fn run(
+ &self,
+ context: &dyn Any,
+ transport: &TransportWrapper,
+ ) -> Result<Option<Box<dyn Annotate>>> {
+ transport.capabilities()?.request(Capability::SPI).ok()?;
+ let context = context.downcast_ref::<SpiCommand>().unwrap();
+ let spi = context.params.create(transport, "BOOTSTRAP")?;
+ let mut flash = SpiFlash::from_spi(&*spi)?;
+ flash.set_address_mode_auto(&*spi)?;
+
+ let progress = app::progress_bar(self.length as u64);
+ let t0 = Instant::now();
+ flash.block_erase_with_progress(&*spi, self.start, self.length, |_, chunk| {
+ progress.inc(chunk as u64);
+ })?;
+ progress.finish();
+ let duration = t0.elapsed().as_secs_f64();
+
+ Ok(Some(Box::new(SpiBlockEraseResponse {
+ length: self.length,
+ bytes_per_second: self.length as f64 / duration,
+ })))
+ }
+}
+
+impl CommandDispatch for SpiChipErase {
+ fn run(
+ &self,
+ context: &dyn Any,
+ transport: &TransportWrapper,
+ ) -> Result<Option<Box<dyn Annotate>>> {
+ transport.capabilities()?.request(Capability::SPI).ok()?;
+ let context = context.downcast_ref::<SpiCommand>().unwrap();
+ let spi = context.params.create(transport, "BOOTSTRAP")?;
+ let mut flash = SpiFlash::from_spi(&*spi)?;
+ flash.set_address_mode_auto(&*spi)?;
+ flash.chip_erase(&*spi)?;
+ Ok(Some(Box::new(SpiChipEraseResponse {})))
+ }
+}
+
/// Program data into a SPI EEPROM.
#[derive(Debug, StructOpt)]
pub struct SpiProgram {
@@ -257,6 +321,7 @@
bytes_per_second: f64,
}
+/// Program data into a SPI EEPROM.
impl CommandDispatch for SpiProgram {
fn run(
&self,
@@ -286,6 +351,93 @@
}
#[derive(Debug, StructOpt)]
+pub struct SpiReadMemory {
+ #[structopt(short, long, default_value = "0", help = "Start offset.")]
+ start: u32,
+ #[structopt(short, long, help = "Length to readback.")]
+ length: u32,
+ #[structopt(short, long, help = "Hexdump the data.")]
+ hexdump: bool,
+ #[structopt(name = "FILE", default_value = "-")]
+ filename: PathBuf,
+}
+
+#[derive(Debug, serde::Serialize)]
+pub struct SpiReadMemoryResponse {
+ length: usize,
+ bytes_per_second: f64,
+}
+
+impl SpiReadMemory {
+ fn write_file(&self, mut writer: impl Write, buffer: &[u8]) -> Result<()> {
+ if self.hexdump {
+ hexdump(writer, buffer)?;
+ } else {
+ writer.write_all(buffer)?;
+ }
+ Ok(())
+ }
+}
+
+impl CommandDispatch for SpiReadMemory {
+ fn run(
+ &self,
+ context: &dyn Any,
+ transport: &TransportWrapper,
+ ) -> Result<Option<Box<dyn Annotate>>> {
+ transport.capabilities()?.request(Capability::SPI).ok()?;
+ transport.capabilities()?.request(Capability::GPIO).ok()?;
+ let context = context.downcast_ref::<SpiCommand>().unwrap();
+ let spi = context.params.create(transport, "BOOTSTRAP")?;
+ // Rename to gpio if the gpio loop is used
+ let _gpio = transport.gpio_pin("SW_STRAP0")?;
+ spi.set_max_speed(1_000_000)?;
+
+ let mut buffer = vec![0u8; self.length as usize];
+ let mut write_buffer = Vec::with_capacity(8);
+ write_buffer.extend(self.start.to_be_bytes());
+ write_buffer.extend(self.length.to_be_bytes());
+ spi.run_transaction(&mut [Transfer::Write(&write_buffer)])?;
+ // TODO(atv): For some reason, the GPIO does not
+ // read back a changed value in this context (but does, if you try to read it separately)
+ // If we can resolve this, uncomment out this polling block. For now, however, wait 50ms.
+ // gpio.set_mode(PinMode::Input)?;
+ // loop {
+ // let val = gpio.read()?;
+ // if val {
+ // break;
+ // }
+ // std::thread::sleep(Duration::from_millis(50));
+ // }
+ // gpio.set_mode(PinMode::PushPull)?;
+ std::thread::sleep(Duration::from_millis(50));
+ let t0 = Instant::now();
+ let chunk_size = spi.max_chunk_size()?;
+ let mut remaining = buffer.len();
+ for i in 0..=(buffer.len() / chunk_size) {
+ let chunk_len = std::cmp::min(chunk_size, remaining);
+ let start = i * chunk_size;
+ let end = start + chunk_len;
+ spi.run_transaction(&mut [Transfer::Read(&mut buffer[start..end])])?;
+ remaining -= chunk_len;
+ }
+ let duration = t0.elapsed().as_secs_f64();
+
+ if self.filename.to_str() == Some("-") {
+ self.write_file(io::stdout(), &buffer)?;
+ Ok(None)
+ } else {
+ let file = File::create(&self.filename)?;
+ self.write_file(file, &buffer)?;
+ Ok(Some(Box::new(SpiReadMemoryResponse {
+ length: buffer.len(),
+ bytes_per_second: buffer.len() as f64 / duration,
+ })))
+ }
+ }
+}
+
+#[derive(Debug, StructOpt)]
pub struct SpiTpm {
#[structopt(subcommand)]
command: super::tpm::TpmSubCommand,
@@ -312,7 +464,10 @@
ReadId(SpiReadId),
Read(SpiRead),
Erase(SpiErase),
+ BlockErase(SpiBlockErase),
+ ChipErase(SpiChipErase),
Program(SpiProgram),
+ ReadMemory(SpiReadMemory),
Tpm(SpiTpm),
}
diff --git a/third_party/rust/BUILD b/third_party/rust/BUILD
index 220a746..96ae281 100644
--- a/third_party/rust/BUILD
+++ b/third_party/rust/BUILD
@@ -8,7 +8,7 @@
annotations = {
"libudev-sys": [crate.annotation(
patch_args = ["-p1"],
- patches = ["@//third_party/rust/patches:libudev-sys-0.1.4.patch"],
+ patches = ["@lowrisc_opentitan//third_party/rust/patches:libudev-sys-0.1.4.patch"],
)],
},
cargo_lockfile = "//third_party/rust:Cargo.lock",
diff --git a/third_party/rust/crates/defs.bzl b/third_party/rust/crates/defs.bzl
index 87101ce..90c0520 100644
--- a/third_party/rust/crates/defs.bzl
+++ b/third_party/rust/crates/defs.bzl
@@ -1206,7 +1206,7 @@
"-p1",
],
patches = [
- "@//third_party/rust/patches:libudev-sys-0.1.4.patch",
+ "@lowrisc_opentitan//third_party/rust/patches:libudev-sys-0.1.4.patch",
],
sha256 = "3c8469b4a23b962c1396b9b451dda50ef5b283e8dd309d69033475fa9b334324",
type = "tar.gz",
diff --git a/third_party/rust/repos.bzl b/third_party/rust/repos.bzl
index d3c3f6a..7c848db 100644
--- a/third_party/rust/repos.bzl
+++ b/third_party/rust/repos.bzl
@@ -2,7 +2,7 @@
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
# SPDX-License-Identifier: Apache-2.0
-load("@//rules:repo.bzl", "http_archive_or_local")
+load("@lowrisc_opentitan//rules:repo.bzl", "http_archive_or_local")
def rust_repos(rules_rust = None, safe_ftdi = None, serde_annotate = None):
# We use forked/patched Rust Bazel rules to enable caching repository rules
diff --git a/util/prep-bazel-airgapped-build.sh b/util/prep-bazel-airgapped-build.sh
index 6b28ecc..be07ba6 100755
--- a/util/prep-bazel-airgapped-build.sh
+++ b/util/prep-bazel-airgapped-build.sh
@@ -164,7 +164,7 @@
readonly LATEST_BISTREAM_HASH_FILE="${SYSTEM_BITSTREAM_CACHE}/latest.txt"
# The revision named in latest.txt is not necessarily on disk. Induce the
# cache backend to fetch the latest bitstreams.
- BITSTREAM=latest ${BAZELISK} fetch @bitstreams//...
+ BITSTREAM=--offline ${BAZELISK} fetch @bitstreams//...
cp "${LATEST_BISTREAM_HASH_FILE}" \
"${BAZEL_AIRGAPPED_DIR}/${BAZEL_BITSTREAMS_CACHE}/"
LATEST_BISTREAM_HASH=$(cat "${LATEST_BISTREAM_HASH_FILE}")
diff --git a/util/reggen/bus_interfaces.py b/util/reggen/bus_interfaces.py
index fbeb99c..c699ea4 100644
--- a/util/reggen/bus_interfaces.py
+++ b/util/reggen/bus_interfaces.py
@@ -50,7 +50,8 @@
protocol = check_str(ed['protocol'],
'protocol field of ' + entry_what)
- if protocol != 'tlul':
+ # TODO(hoangm): Investigate TLUH OT upstream support.
+ if protocol != 'tlul' and protocol != 'tluh' :
raise ValueError('Unknown protocol {!r} at {}'
.format(protocol, entry_what))
diff --git a/util/regtool/Cargo.toml b/util/regtool/Cargo.toml
new file mode 100644
index 0000000..ed409cc
--- /dev/null
+++ b/util/regtool/Cargo.toml
@@ -0,0 +1,6 @@
+[package]
+name = "regtool"
+version = "0.1.0"
+edition = "2018"
+
+[dependencies]
diff --git a/util/regtool/src/lib.rs b/util/regtool/src/lib.rs
new file mode 100644
index 0000000..3584abc
--- /dev/null
+++ b/util/regtool/src/lib.rs
@@ -0,0 +1,124 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+#![allow(clippy::needless_doctest_main)]
+
+//! A library for build scripts to generate `.rs` files using `regtool.py`.
+//!
+//! This library is intended to be used as a `build-dependencies` entry in
+//! `Cargo.toml`:
+//!
+//! ```toml
+//! [build-dependencies]
+//! regtool = { path = "path/to/regtool" }
+//! ```
+//!
+//! By default, the library expects the environment variable `REGTOOL` to point
+//! to `regtool.py`. Either set the variable before running cargo, or use
+//! `Build::regtool(...)` from `build.rs` to set the path to the script
+//! explicitly.
+//!
+//! # Examples
+//!
+//! Use the `Build` struct to process `hw/ip/uart/data/uart.hjson`:
+//!
+//! build.rs:
+//!
+//! ```no_run
+//! fn main() {
+//! regtool::Build::new()
+//! .in_file_path("hw/ip/uart/data/uart.hjson")
+//! .generate("uart.rs");
+//! }
+//! ```
+//!
+//! src/main.rs:
+//!
+//! ```no_run
+//! include!(concat!(env!("OUT_DIR"), "/uart.rs"));
+//! ```
+
+use std::env;
+use std::path::Path;
+use std::path::PathBuf;
+use std::process::Command;
+
+#[derive(Clone, Debug)]
+pub struct Build {
+ in_file_path: Option<PathBuf>, // Must be set; no default
+ out_dir: Option<PathBuf>, // default: $OUT_DIR
+
+ python: Option<PathBuf>,
+ regtool: Option<PathBuf>, // Default: $REGTOOL
+}
+
+macro_rules! option_path_setter {
+ ($name:ident) => {
+ pub fn $name<P: AsRef<Path>>(&mut self, $name: P) -> &mut Build {
+ self.$name = Some($name.as_ref().to_owned());
+ self
+ }
+ };
+}
+
+impl Build {
+ pub fn new() -> Self {
+ Self {
+ in_file_path: None,
+ out_dir: None,
+
+ python: None,
+ regtool: None,
+ }
+ }
+
+ // Generate setter functions for Option<PathBuf> fields:
+ option_path_setter!(in_file_path);
+ option_path_setter!(out_dir);
+ option_path_setter!(python);
+ option_path_setter!(regtool);
+
+ // Run regtool. If out_file is an absolute path, write output to out_file,
+ // otherwise write output to out_dir/out_file.
+ pub fn generate(&self, out_file: &str) {
+ let regtool = if let Some(regtool) = &self.regtool {
+ regtool.to_owned()
+ } else {
+ println!("cargo:rerun-if-env-changed=REGTOOL");
+ PathBuf::from(env::var("REGTOOL").expect("missing environment variable 'REGTOOL'"))
+ };
+ println!("cargo:rerun-if-changed={}", regtool.display());
+
+ let mut out_file_path = if let Some(out_dir) = &self.out_dir {
+ out_dir.to_owned()
+ } else {
+ PathBuf::from(env::var("OUT_DIR").unwrap())
+ };
+ // NB: If out_file is absolute, it replaces the current path.
+ out_file_path.push(out_file);
+
+ let in_file_path: &Path = self
+ .in_file_path
+ .as_ref()
+ .expect("'in_file_path' is not set");
+ println!("cargo:rerun-if-changed={}", in_file_path.display());
+
+ let mut cmd;
+ if let Some(python) = &self.python {
+ cmd = Command::new(python);
+ cmd.arg(regtool);
+ } else {
+ cmd = Command::new(regtool);
+ }
+ cmd.arg("-R").arg("-o").arg(out_file_path).arg(in_file_path);
+ println!("Running: {:?}", cmd);
+ assert!(cmd.status().unwrap().success());
+ }
+}
+
+impl Default for Build {
+ fn default() -> Self {
+ Self::new()
+ }
+}
diff --git a/util/tlgen/xbar.sim_cfg.hjson.tpl b/util/tlgen/xbar.sim_cfg.hjson.tpl
index 681945f..627c05b 100644
--- a/util/tlgen/xbar.sim_cfg.hjson.tpl
+++ b/util/tlgen/xbar.sim_cfg.hjson.tpl
@@ -16,13 +16,13 @@
testplan: "{proj_root}/hw/ip/tlul/data/tlul_testplan.hjson"
// Add xbar_main specific exclusion files.
- vcs_cov_excl_files: ["{proj_root}/hw/top_earlgrey/ip/{dut}/dv/autogen/xbar_cov_excl.el"]
+ vcs_cov_excl_files: ["{proj_root}/${xbar.ip_path}/dv/autogen/xbar_cov_excl.el"]
// replace common cover.cfg with a generated one, which includes xbar toggle exclusions
overrides: [
{
name: default_vcs_cov_cfg_file
- value: "-cm_hier {proj_root}/hw/top_earlgrey/ip/{dut}/dv/autogen/xbar_cover.cfg"
+ value: "-cm_hier {proj_root}/${xbar.ip_path}/dv/autogen/xbar_cover.cfg"
}
]
// Import additional common sim cfg files.
diff --git a/util/topgen/BUILD b/util/topgen/BUILD
index fa87f82..cc73719 100644
--- a/util/topgen/BUILD
+++ b/util/topgen/BUILD
@@ -11,7 +11,9 @@
name = "topgen",
srcs = [
"__init__.py",
+ "entropy_buffer_generator.py",
"gen_top_docs.py",
+ "strong_random.py",
"validate.py",
],
deps = [
diff --git a/util/topgen/templates/BUILD.tpl b/util/topgen/templates/BUILD.tpl
index 858d019..e659f12 100644
--- a/util/topgen/templates/BUILD.tpl
+++ b/util/topgen/templates/BUILD.tpl
@@ -51,3 +51,22 @@
"//sw/device/lib/testing/test_framework:ottf_main",
],
)
+
+opentitan_functest(
+ name = "alert_renode_test",
+ srcs = ["alert_test.c"],
+ deps = [
+ "//hw/top_earlgrey/sw/autogen:top_earlgrey",
+ "//sw/device/lib/base:memory",
+ "//sw/device/lib/base:mmio",
+% for n in sorted(alert_peripheral_names + ["alert_handler"]):
+ "//sw/device/lib/dif:${n}",
+% endfor
+ "//sw/device/lib/runtime:log",
+ "//sw/device/lib/testing:alert_handler_testutils",
+ "//sw/device/lib/testing/test_framework:ottf_main",
+ ],
+ copts = [
+ "-DDISABLE_RENODE_TEST",
+ ],
+)
diff --git a/util/topgen/templates/alert_test.c.tpl b/util/topgen/templates/alert_test.c.tpl
index 98a1c16..c098eef 100644
--- a/util/topgen/templates/alert_test.c.tpl
+++ b/util/topgen/templates/alert_test.c.tpl
@@ -5,6 +5,12 @@
${gencmd}
<%
+## list renode unsupported peripherals
+unsupported_peripherals = [
+ "adc_ctrl", "clkmgr", "edn", "entropy_src", "keymgr", "pattgen",
+ "pinmux", "pwm", "rv_plic", "sensor_ctrl", "spi_device", "sram_ctrl",
+ "sysrst_ctrl", "usbdev"
+]
alert_peripheral_names = sorted({p.name for p in helper.alert_peripherals})
%>\
#include "sw/device/lib/base/mmio.h"
@@ -98,6 +104,9 @@
dif_alert_handler_alert_t exp_alert;
% for p in helper.alert_peripherals:
+ % if p.name in unsupported_peripherals:
+#ifndef DISABLE_RENODE_TEST
+ % endif
// Write ${p.name}'s alert_test reg and check alert_cause.
for (int i = 0; i < ${p.num_alerts}; ++i) {
CHECK_DIF_OK(dif_${p.name}_alert_force(&${p.inst_name}, ${p.dif_alert_name} + i));
@@ -112,6 +121,9 @@
CHECK_DIF_OK(dif_alert_handler_alert_acknowledge(
&alert_handler, exp_alert));
}
+ % if p.name in unsupported_peripherals:
+#endif
+ % endif
% endfor
}
diff --git a/util/topgen/templates/xbar_env_pkg__params.sv.tpl b/util/topgen/templates/xbar_env_pkg__params.sv.tpl
index 996511f..805b06a 100644
--- a/util/topgen/templates/xbar_env_pkg__params.sv.tpl
+++ b/util/topgen/templates/xbar_env_pkg__params.sv.tpl
@@ -21,7 +21,7 @@
for host, devices in xbar["connections"].items():
for dev_name in devices:
if is_device_a_xbar(dev_name):
- edge_devices.extend(get_xbar_edge_nodes())
+ edge_devices.extend(get_xbar_edge_nodes(dev_name))
else:
edge_devices.append(dev_name)