| # Copyright lowRISC contributors. |
| # Licensed under the Apache License, Version 2.0, see LICENSE for details. |
| # SPDX-License-Identifier: Apache-2.0 |
| |
| load("@lowrisc_opentitan//rules:rv.bzl", "rv_rule") |
| |
| def _opentitan_gdb_fpga_cw310_test(ctx): |
| test_script = '''#!/usr/bin/env bash |
| set -e |
| |
| # Do not mask failures in the left-hand side of pipelines. |
| set -o pipefail |
| |
| COLOR_RED='\\x1b[0;31m' |
| COLOR_GREEN='\\x1b[0;32m' |
| COLOR_PURPLE='\\x1b[0;35m' |
| |
| function prefix_lines() {{ |
| LABEL="$1" |
| COLOR="$2" |
| COLOR_RESET='\\x1b[m' |
| sed -Eu "s/(.*)/$COLOR[$LABEL]$COLOR_RESET \\1/" |
| }} |
| |
| set -x |
| |
| ./opentitantool fpga load-bitstream --rom-kind=TestRom rom.bit |
| |
| (openocd -f /usr/share/openocd/scripts/interface/ftdi/olimex-arm-usb-tiny-h.cfg \\ |
| -c "adapter speed 500; transport select jtag; reset_config trst_and_srst" \\ |
| -f {openocd_earlgrey_config} \\ |
| |& prefix_lines OPENOCD "$COLOR_PURPLE") & |
| OPENOCD_PID=$! |
| |
| # For debugging, it may be useful to use `--init-command`, which causes |
| # GDB to drop to the interactive prompt when the script ends rather than |
| # exiting. |
| (/tools/riscv/bin/riscv32-unknown-elf-gdb --command=script.gdb \\ |
| |& prefix_lines GDB "$COLOR_GREEN") & |
| |
| ./opentitantool console \\ |
| --timeout 15s \\ |
| --exit-success='{exit_success_pattern}' \\ |
| |& prefix_lines CONSOLE "$COLOR_RED" |
| |
| # Send TERM signal to OpenOCD and wait for all background jobs to complete. Note |
| # that GDB will exit naturally at the end of its script. |
| kill $OPENOCD_PID |
| wait |
| '''.format( |
| openocd_earlgrey_config = ctx.file._openocd_earlgrey_config.path, |
| exit_success_pattern = ctx.attr.exit_success_pattern, |
| ) |
| |
| # Write the GDB script to disk and load it with GDB's `--command` argument. |
| # This enables us to separate lines with whitespace, whereas if we piped the |
| # string into GDB's stdin, each newline would cause it to repeat the |
| # previous command. |
| gdb_script_file = ctx.actions.declare_file("{}.gdb".format(ctx.label.name)) |
| test_script_file = ctx.actions.declare_file("{}.sh".format(ctx.label.name)) |
| |
| ctx.actions.write(output = gdb_script_file, content = ctx.attr.gdb_script) |
| ctx.actions.write(output = test_script_file, content = test_script) |
| |
| # Construct a dict that we can pass to `ctx.runfiles()`, mapping symlink |
| # names to real file paths. |
| gdb_script_symlinks_flipped = {} |
| for label in ctx.attr.gdb_script_symlinks: |
| label_files = label.files.to_list() |
| if len(label_files) != 1: |
| fail("gdb_script_symlinks labels must have exactly one file, but", label, "has these files:", label_files) |
| gdb_script_symlinks_flipped[ctx.attr.gdb_script_symlinks[label]] = label_files[0] |
| |
| gdb_script_runfiles = ctx.runfiles( |
| symlinks = gdb_script_symlinks_flipped, |
| files = gdb_script_symlinks_flipped.values(), |
| ) |
| test_script_runfiles = ctx.runfiles( |
| # Relative paths provided by `File.path` seem to not work |
| # for generated files. Symlinking the runtime files wherever |
| # Bazel will run `test_script_file` sidesteps the issue. |
| symlinks = { |
| "opentitantool": ctx.file._opentitantool, |
| "rom.bit": ctx.file.rom_bitstream, |
| "script.gdb": gdb_script_file, |
| }, |
| files = [ |
| ctx.file._openocd_earlgrey_config, |
| ctx.file._opentitantool, |
| ctx.file.rom_bitstream, |
| gdb_script_file, |
| ], |
| ) |
| runfiles = test_script_runfiles.merge(gdb_script_runfiles) |
| |
| return [DefaultInfo( |
| executable = test_script_file, |
| runfiles = runfiles, |
| )] |
| |
| # Orchestrate opentitantool, OpenOCD, and GDB to load the given program into |
| # SRAM and execute it in-place. This rule assumes that a CW310 FPGA and an |
| # ARM-USB-TINY-H JTAG debugger are attached to the host. |
| opentitan_gdb_fpga_cw310_test = rv_rule( |
| implementation = _opentitan_gdb_fpga_cw310_test, |
| attrs = { |
| "exit_success_pattern": attr.string(mandatory = True), |
| "gdb_script": attr.string(mandatory = True), |
| "gdb_script_symlinks": attr.label_keyed_string_dict(allow_files = True), |
| "rom_bitstream": attr.label( |
| mandatory = True, |
| allow_single_file = True, |
| ), |
| "_opentitantool": attr.label( |
| default = "//sw/host/opentitantool", |
| allow_single_file = True, |
| cfg = "exec", |
| ), |
| "_openocd_earlgrey_config": attr.label( |
| default = "//util/openocd/target:lowrisc-earlgrey.cfg", |
| allow_single_file = True, |
| ), |
| }, |
| test = True, |
| ) |