Dan McArdle | 411c774 | 2022-08-02 18:26:40 -0400 | [diff] [blame] | 1 | # Copyright lowRISC contributors. |
| 2 | # Licensed under the Apache License, Version 2.0, see LICENSE for details. |
| 3 | # SPDX-License-Identifier: Apache-2.0 |
| 4 | |
| 5 | load("@lowrisc_opentitan//rules:rv.bzl", "rv_rule") |
| 6 | |
| 7 | def _opentitan_gdb_fpga_cw310_test(ctx): |
| 8 | test_script = '''#!/usr/bin/env bash |
| 9 | set -e |
| 10 | |
| 11 | # Do not mask failures in the left-hand side of pipelines. |
| 12 | set -o pipefail |
| 13 | |
| 14 | COLOR_RED='\\x1b[0;31m' |
| 15 | COLOR_GREEN='\\x1b[0;32m' |
| 16 | COLOR_PURPLE='\\x1b[0;35m' |
| 17 | |
| 18 | function prefix_lines() {{ |
| 19 | LABEL="$1" |
| 20 | COLOR="$2" |
| 21 | COLOR_RESET='\\x1b[m' |
| 22 | sed -Eu "s/(.*)/$COLOR[$LABEL]$COLOR_RESET \\1/" |
| 23 | }} |
| 24 | |
| 25 | set -x |
| 26 | |
| 27 | ./opentitantool load-bitstream --rom-kind=TestRom rom.bit |
| 28 | |
| 29 | (openocd -f /usr/share/openocd/scripts/interface/ftdi/olimex-arm-usb-tiny-h.cfg \\ |
| 30 | -c "adapter speed 500; transport select jtag; reset_config trst_and_srst" \\ |
| 31 | -f {openocd_earlgrey_config} \\ |
| 32 | |& prefix_lines OPENOCD "$COLOR_PURPLE") & |
| 33 | OPENOCD_PID=$! |
| 34 | |
| 35 | # For debugging, it may be useful to use `--init-command`, which causes |
| 36 | # GDB to drop to the interactive prompt when the script ends rather than |
| 37 | # exiting. |
| 38 | (/tools/riscv/bin/riscv32-unknown-elf-gdb --command=script.gdb \\ |
| 39 | |& prefix_lines GDB "$COLOR_GREEN") & |
| 40 | |
| 41 | ./opentitantool console \\ |
| 42 | --timeout 15s \\ |
| 43 | --exit-success='{exit_success_pattern}' \\ |
| 44 | |& prefix_lines CONSOLE "$COLOR_RED" |
| 45 | |
| 46 | # Send TERM signal to OpenOCD and wait for all background jobs to complete. Note |
| 47 | # that GDB will exit naturally at the end of its script. |
| 48 | kill $OPENOCD_PID |
| 49 | wait |
| 50 | '''.format( |
| 51 | openocd_earlgrey_config = ctx.file._openocd_earlgrey_config.path, |
| 52 | exit_success_pattern = ctx.attr.exit_success_pattern, |
| 53 | ) |
| 54 | |
| 55 | # Write the GDB script to disk and load it with GDB's `--command` argument. |
| 56 | # This enables us to separate lines with whitespace, whereas if we piped the |
| 57 | # string into GDB's stdin, each newline would cause it to repeat the |
| 58 | # previous command. |
| 59 | gdb_script_file = ctx.actions.declare_file("{}.gdb".format(ctx.label.name)) |
| 60 | test_script_file = ctx.actions.declare_file("{}.sh".format(ctx.label.name)) |
| 61 | |
| 62 | ctx.actions.write(output = gdb_script_file, content = ctx.attr.gdb_script) |
| 63 | ctx.actions.write(output = test_script_file, content = test_script) |
| 64 | |
| 65 | # Construct a dict that we can pass to `ctx.runfiles()`, mapping symlink |
| 66 | # names to real file paths. |
| 67 | gdb_script_symlinks_flipped = {} |
| 68 | for label in ctx.attr.gdb_script_symlinks: |
| 69 | label_files = label.files.to_list() |
| 70 | if len(label_files) != 1: |
| 71 | fail("gdb_script_symlinks labels must have exactly one file, but", label, "has these files:", label_files) |
| 72 | gdb_script_symlinks_flipped[ctx.attr.gdb_script_symlinks[label]] = label_files[0] |
| 73 | |
| 74 | gdb_script_runfiles = ctx.runfiles( |
| 75 | symlinks = gdb_script_symlinks_flipped, |
| 76 | files = gdb_script_symlinks_flipped.values(), |
| 77 | ) |
| 78 | test_script_runfiles = ctx.runfiles( |
| 79 | # Relative paths provided by `File.path` seem to not work |
| 80 | # for generated files. Symlinking the runtime files wherever |
| 81 | # Bazel will run `test_script_file` sidesteps the issue. |
| 82 | symlinks = { |
| 83 | "opentitantool": ctx.file._opentitantool, |
| 84 | "rom.bit": ctx.file.rom_bitstream, |
| 85 | "script.gdb": gdb_script_file, |
| 86 | }, |
| 87 | files = [ |
| 88 | ctx.file._openocd_earlgrey_config, |
| 89 | ctx.file._opentitantool, |
| 90 | ctx.file.rom_bitstream, |
| 91 | gdb_script_file, |
| 92 | ], |
| 93 | ) |
| 94 | runfiles = test_script_runfiles.merge(gdb_script_runfiles) |
| 95 | |
| 96 | return [DefaultInfo( |
| 97 | executable = test_script_file, |
| 98 | runfiles = runfiles, |
| 99 | )] |
| 100 | |
| 101 | # Orchestrate opentitantool, OpenOCD, and GDB to load the given program into |
| 102 | # SRAM and execute it in-place. This rule assumes that a CW310 FPGA and an |
| 103 | # ARM-USB-TINY-H JTAG debugger are attached to the host. |
| 104 | opentitan_gdb_fpga_cw310_test = rv_rule( |
| 105 | implementation = _opentitan_gdb_fpga_cw310_test, |
| 106 | attrs = { |
| 107 | "exit_success_pattern": attr.string(mandatory = True), |
| 108 | "gdb_script": attr.string(mandatory = True), |
| 109 | "gdb_script_symlinks": attr.label_keyed_string_dict(allow_files = True), |
| 110 | "rom_bitstream": attr.label( |
| 111 | mandatory = True, |
| 112 | allow_single_file = True, |
| 113 | ), |
| 114 | "_opentitantool": attr.label( |
| 115 | default = "//sw/host/opentitantool", |
| 116 | allow_single_file = True, |
| 117 | cfg = "exec", |
| 118 | ), |
| 119 | "_openocd_earlgrey_config": attr.label( |
| 120 | default = "//util/openocd/target:lowrisc-earlgrey.cfg", |
| 121 | allow_single_file = True, |
| 122 | ), |
| 123 | }, |
| 124 | test = True, |
| 125 | ) |