| #!/bin/bash |
| # |
| # Copyright 2020 Google LLC |
| # |
| # 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 |
| # |
| # https://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. |
| |
| export C_PREFIX="riscv32-unknown-elf-" |
| export IREE_PREFIX="riscv32-unknown-elf-" |
| export IREE_ARCH="rv32imf" |
| export RUST_PREFIX="riscv32-unknown-linux-gnu" |
| |
| # NB: $(CANTRIP_SRC_DIR)/apps/system/rust.cmake forces riscv32imac for |
| # the target when building Rust code |
| export CANTRIP_TARGET_ARCH="riscv32-unknown-elf" |
| |
| # Shodan's toolchains are setup specially, just setup the environment. |
| export RUSTDIR="${CACHE}/rust_toolchain" |
| export CARGO_HOME="${RUSTDIR}" |
| export RUSTUP_HOME="${RUSTDIR}" |
| export PATH="${RUSTDIR}/bin:${PATH}" |
| |
| export OPENTITAN_GEN_DIR="${CANTRIP_OUT_DIR}/opentitan-gen/include/opentitan" |
| export OPENTITAN_SOURCE="${ROOTDIR}/hw/opentitan-upstream" |
| |
| # Some build.rs files use the regtool crate which needs to know where to find |
| # regtool.py. |
| export REGTOOL="${OPENTITAN_SOURCE}/util/regtool.py" |
| # The following files are the input to regtool.py |
| export I2S_HJSON="${ROOTDIR}/hw/matcha/hw/top_matcha/ip/i2s/data/i2s.hjson" |
| export MBOX_HJSON="${ROOTDIR}/hw/matcha/hw/top_matcha/ip/tlul_mailbox/data/tlul_mailbox.hjson" |
| export ML_TOP_HJSON="${ROOTDIR}/hw/matcha/hw/top_matcha/ip/ml_top/data/ml_top.hjson" |
| export TIMER_HJSON="${OPENTITAN_GEN_DIR}/rv_timer.hjson" |
| export UART_HJSON="${OPENTITAN_SOURCE}/hw/ip/uart/data/uart.hjson" |
| export VC_TOP_HJSON="${ROOTDIR}/hw/matcha/hw/top_matcha/ip/vc_top/data/vc_top.hjson" |
| # Input for topgen_matcha.py to generate hw configuration |
| export TOP_MATCHA_HJSON="${ROOTDIR}/hw/matcha/hw/top_matcha/data/top_matcha.hjson" |
| |
| # Standard locations of Nexus configs and binaries |
| export OT_TOOL="${ROOTDIR}/out/opentitantool" |
| export NEXUS_JSON="${ROOTDIR}/out/nexus.json" |
| export NEXUS_SPI_PASSTHRU="${ROOTDIR}/out/spi_passthrough_fpga_nexus.bin" |
| |
| function parting_messages() { |
| if [[ ! -d "${RUSTDIR}" ]] || |
| [[ ! -d "${ROOTDIR}/cache/toolchain" ]] || |
| [[ ! -d "${ROOTDIR}/cache/toolchain_iree_rv32imf" ]] || |
| [[ ! -d "${ROOTDIR}/cache/renode" ]]; then |
| echo |
| echo '!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!' |
| echo You have missing tools. Please run \'m prereqs\' followed |
| echo by \'m tools\' to install them. |
| echo '!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!' |
| echo |
| [[ -d "${RUSTDIR}" ]] || echo "${RUSTDIR} is missing!" |
| [[ -d "${ROOTDIR}/cache/toolchain" ]] || echo "${ROOTDIR}/cache/toolchain is missing" |
| [[ -d "${ROOTDIR}/cache/toolchain_iree_rv32imf" ]] || echo "${ROOTDIR}/cache/toolchain_iree_rv32imf is missing!" |
| [[ -d "${ROOTDIR}/cache/renode" ]] || echo "${ROOTDIR}/cache/renode is missing!" |
| fi |
| echo Run \'set-nexus-id NN\' to set your Nexus board ID |
| } |
| |
| function sim_kelvin |
| { |
| # Run the ELF/Bin program with kelvin_sim |
| local bin_file="$(realpath $1)" |
| local magic_bytes="$(xxd -p -l 4 ${bin_file})" |
| local -a flags=() |
| local is_elf=false |
| if [[ ${magic_bytes} == "7f454c46" ]]; then |
| is_elf=true |
| else |
| flags+=("--entry_point 0 ") |
| fi |
| |
| if [[ "$2" == "debug" ]]; then |
| flags+=("-i") |
| if [[ "${is_elf}" == false ]]; then |
| echo "debug mode only works on ELF files" |
| return 1 |
| fi |
| fi |
| |
| ("${OUT}/kelvin/sim/kelvin_sim" "${bin_file}" ${flags[@]}) |
| } |
| |
| function sim_kelvin_renode |
| { |
| # Run the Bin program with renode |
| local bin_file="$(realpath $1)" |
| local command="start;" |
| |
| (cd "${ROOTDIR}" && renode -e "\$bin=@${bin_file}; i @sim/config/kelvin.resc; \ |
| ${command} sysbus.ml_top_controlblock WriteDoubleWord 0xc 0" \ |
| --disable-xwt --console) |
| |
| } |
| |
| function set-nexus-id |
| { |
| local nexus_id="${1}"; shift |
| |
| if [[ -z "${nexus_id}" ]]; then |
| ( |
| echo "Usage: set-nexus-id <NN>" |
| echo |
| echo "Sets the target Nexus board to run on. Must be a two digit number" |
| echo |
| ) | fmt |
| return 1 |
| fi |
| if [[ "${#nexus_id}" -ne 2 ]]; then |
| echo "Nexus number must be two digits" |
| return 1 |
| fi |
| |
| export NEXUS_ID="${nexus_id}" |
| # TODO(b/316200811) track down all the places we use a different variable name: |
| export NEXUS_BOARD="${nexus_id}" |
| export FPGA_BOARD_ID="${nexus_id}" |
| } |
| |
| function opentitantool |
| { |
| # Run built opentitantool with standard flags |
| if [[ -z "${NEXUS_ID}" ]]; then |
| echo "Run set-nexus-id first" |
| return 1 |
| fi |
| |
| "${OT_TOOL}" --conf "${NEXUS_JSON}" --interface nexus --usb-serial \ |
| "Nexus-FTDI-${NEXUS_ID}" "$@" |
| } |
| |
| function nexus_reset |
| { |
| # Reset nexus board |
| if [[ -z "${NEXUS_ID}" ]]; then |
| echo "Run set-nexus-id first" |
| return 1 |
| fi |
| |
| opentitantool gpio write RESET true |
| opentitantool gpio write RESET false |
| opentitantool gpio write RESET true |
| } |
| |
| function nexus_flash |
| { |
| # Write tar file to nexus SPI flash and verify |
| |
| local flash_tar="$(realpath $1)" |
| if [[ -z "${flash_tar}" ]]; then |
| ( |
| echo "Usage: nexus_flash path/to/file.tar" |
| echo |
| echo "Writes tar file to Nexus SPI flash for booting." |
| echo |
| ) | fmt |
| return 1 |
| fi |
| |
| if [[ -z "${NEXUS_ID}" ]]; then |
| echo "Run set-nexus-id first" |
| return 1 |
| fi |
| |
| if [[ ! -f "${NEXUS_SPI_PASSTHRU}" ]]; then |
| echo "INFO: spi_passthrough binary not found at ${NEXUS_SPI_PASSTHRU}" |
| echo "running `m spi_passthrough` to build it" |
| m spi_passthrough |
| if [[ "$?" -ne 0 ]]; then |
| echo "ERROR: Unable to find or build spi_passthrough!" |
| return 1 |
| fi |
| fi |
| |
| nexus_reset |
| |
| local read_size="$(du -b ${flash_tar} | awk '{print $1}')" |
| local erase_size="$(du -b ${flash_tar} \ |
| | awk '{ print $1 + (n - $1 % n) % n }' n=262144)" |
| |
| echo "Program SPI using ${NEXUS_SPI_PASSTHRU} on board ${NEXUS_ID}" |
| opentitantool bootstrap "${NEXUS_SPI_PASSTHRU}" |
| opentitantool spi block-erase --start 0 --length "${erase_size}" |
| opentitantool spi program --start 0 "${flash_tar}" |
| |
| local readback_file="$(mktemp -d)/$(basename ${flash_tar}).readback" |
| opentitantool spi read --start 0 --length "${read_size}" "${readback_file}" |
| diff "${flash_tar}" "${readback_file}" |
| if [[ "$?" -ne 0 ]]; then |
| echo "ERROR: Nexus flash verify failed!" |
| return 1 |
| fi |
| rm "${readback_file}" |
| |
| nexus_reset |
| } |
| |
| function nexus_clear_flash |
| { |
| # Clear the first page of the SPI flash to prevent restarting from the |
| # loaded program at the next reset. |
| if [[ -z "${NEXUS_ID}" ]]; then |
| echo "Run set-nexus-id first" |
| return 1 |
| fi |
| |
| echo "Clearing nexus SPI flash" |
| nexus_reset |
| opentitantool bootstrap "${NEXUS_SPI_PASSTHRU}" |
| opentitantool spi block-erase --start 0 --length 262144 |
| } |
| |
| function nexus_mcu_write() { |
| # Slowly send characters to the Nexus MCU |
| if [[ -z "${NEXUS_ID}" ]]; then |
| echo "Run set-nexus-id first" |
| return 1 |
| fi |
| |
| local string="$1" |
| local length="${#string}" |
| for ((i = 0; i < length; i++)); do |
| local char="${string:i:1}" |
| echo -n "$char" > "/dev/Nexus-FTDI-${NEXUS_ID}-MCU-UART" |
| sleep 0.5 |
| done |
| echo -e "\r" > "/dev/Nexus-FTDI-${NEXUS_ID}-MCU-UART" |
| } |
| |
| function nexus_load_bitstream |
| { |
| # Load bitstream file onto Nexus FPGA |
| local bitstream_path="$(realpath $1)" |
| if [[ -z "${bitstream_path}" ]]; then |
| ( |
| echo "Usage: nexus_load_bitstream path/to/file.bit" |
| echo |
| echo "Loads bitstream file onto Nexus FPGA" |
| echo "This command may ask you for the Nexus SOM root password" |
| echo |
| ) | fmt |
| return 1 |
| fi |
| |
| if [[ -z "${NEXUS_ID}" ]]; then |
| echo "Run set-nexus-id first" |
| return 1 |
| fi |
| |
| if [[ ! -f "${bitstream_path}" ]]; then |
| echo "ERROR: bitstream not found at ${bitstream_path}" |
| return 1 |
| fi |
| |
| # Issue a no-op command to flush the character buffer in case it isn't empty |
| nexus_mcu_write "help" |
| scp "${bitstream_path}" "root@nexus${NEXUS_ID}:/mnt/mmcp1/" |
| nexus_mcu_write "camera_powerdown" |
| sleep 5 |
| local bitstream_name="$(basename ${bitstream_path})" |
| ssh "root@nexus${NEXUS_ID}" "/mnt/mmcp1/zturn -d a /mnt/mmcp1/${bitstream_name}" |
| nexus_mcu_write "camera_powerup" |
| } |
| |
| function nexus_boot |
| { |
| # Boot the Nexus board. If flashed, will boot from flash |
| # This command is a synomym for `opentitantool boot` |
| opentitantool boot |
| } |
| |
| function nexus_bootstrap |
| { |
| # Bootstrap a binary on the Nexus board |
| |
| local binary="$(realpath $1)" |
| if [[ -z "${binary}" ]]; then |
| ( |
| echo "Usage: nexus_flash path/to/file.bin" |
| echo |
| echo "Run a binary on the nexus board." |
| echo |
| ) | fmt |
| return 1 |
| fi |
| opentitantool bootstrap "${binary}" |
| } |