| // Copyright lowRISC contributors. |
| // Licensed under the Apache License, Version 2.0, see LICENSE for details. |
| // SPDX-License-Identifier: Apache-2.0 |
| |
| use anyhow::Result; |
| use regex::Regex; |
| use serde_annotate::Annotate; |
| use std::any::Any; |
| use std::fs; |
| use std::path::PathBuf; |
| use std::time::Duration; |
| use structopt::StructOpt; |
| |
| use opentitanlib::app::command::CommandDispatch; |
| use opentitanlib::app::{StagedProgressBar, TransportWrapper}; |
| use opentitanlib::transport::verilator::transport::Watch; |
| use opentitanlib::transport::UpdateFirmware; |
| |
| /// Initialize state of a transport debugger device to fit the device under test. This |
| /// typically involves setting pins as input/output, open drain, etc. according to configuration |
| /// files. |
| #[derive(Debug, StructOpt)] |
| pub struct TransportInit {} |
| |
| impl CommandDispatch for TransportInit { |
| fn run( |
| &self, |
| _context: &dyn Any, |
| transport: &TransportWrapper, |
| ) -> Result<Option<Box<dyn Annotate>>> { |
| // Configure all GPIO pins to default direction and level, according to |
| // configuration files provided, and configures SPI port mode/speed, etc. |
| transport.apply_default_configuration()?; |
| Ok(None) |
| } |
| } |
| |
| /// Updates the firmware of the debugger/transport. If no argument is given, a suitable |
| /// "official" firmware will be used, if one such was compiled into the OpenTitanTool binary. For |
| /// instructions on how to build HyperDebug firmware locally, see |
| /// https://docs.google.com/document/d/1ZEH7L5j9-wMw4tkW28-xt6JU5B6hTX0RdZD4h4OZzDo . |
| #[derive(Debug, StructOpt)] |
| pub struct TransportUpdateFirmware { |
| #[structopt( |
| short, |
| long, |
| help = "Local firmware file to use instead of official release" |
| )] |
| filename: Option<PathBuf>, |
| } |
| |
| impl CommandDispatch for TransportUpdateFirmware { |
| fn run( |
| &self, |
| _context: &dyn Any, |
| transport: &TransportWrapper, |
| ) -> Result<Option<Box<dyn Annotate>>> { |
| let firmware = match self.filename.as_ref() { |
| Some(name) => Some(fs::read(name)?), |
| None => None, |
| }; |
| let progress = StagedProgressBar::new(); |
| let operation = UpdateFirmware { |
| firmware, |
| progress: Some(progress.pfunc()), |
| }; |
| transport.dispatch(&operation) |
| } |
| } |
| |
| /// Watch verilator's stdout for a regex or until a timeout is reached. |
| #[derive(Debug, StructOpt)] |
| pub struct VerilatorWatch { |
| #[structopt(help = "Regular expresion to watch for")] |
| regex: String, |
| #[structopt( |
| short, |
| long, parse(try_from_str=humantime::parse_duration), |
| help = "Duration to watch for the expresion", |
| )] |
| timeout: Option<Duration>, |
| } |
| |
| impl CommandDispatch for VerilatorWatch { |
| fn run( |
| &self, |
| _context: &dyn Any, |
| transport: &TransportWrapper, |
| ) -> Result<Option<Box<dyn Annotate>>> { |
| let watch = Watch { |
| regex: Regex::new(&self.regex)?, |
| timeout: self.timeout, |
| }; |
| transport.dispatch(&watch) |
| } |
| } |
| |
| /// Commands for interacting with the transport debugger device itself. |
| #[derive(Debug, StructOpt, CommandDispatch)] |
| pub enum TransportCommand { |
| Init(TransportInit), |
| VerilatorWatch(VerilatorWatch), |
| UpdateFirmware(TransportUpdateFirmware), |
| } |