opentitanlib/test_utils/
load_bitstream.rs

1// Copyright lowRISC contributors (OpenTitan project).
2// Licensed under the Apache License, Version 2.0, see LICENSE for details.
3// SPDX-License-Identifier: Apache-2.0
4
5use anyhow::Result;
6use clap::Args;
7use std::path::{Path, PathBuf};
8use std::time::Duration;
9
10use crate::app::{StagedProgressBar, TransportWrapper};
11use crate::transport::common::fpga::FpgaProgram;
12
13/// Load a bitstream into the FPGA.
14#[derive(Debug, Args)]
15pub struct LoadBitstream {
16    /// Whether to clear out any existing bitstream.
17    #[arg(long)]
18    pub clear_bitstream: bool,
19
20    /// The bitstream to load for the test.
21    #[arg(long)]
22    pub bitstream: Option<PathBuf>,
23
24    /// Duration of the reset pulse.
25    #[arg(long, value_parser = humantime::parse_duration, default_value = "50ms")]
26    pub rom_reset_pulse: Duration,
27
28    /// Duration of ROM detection timeout.
29    #[arg(long, value_parser = humantime::parse_duration, default_value = "2s")]
30    pub rom_timeout: Duration,
31
32    /// Load the bitstream, regardless of a matching USR_ACCESS.
33    #[arg(long)]
34    pub force: bool,
35}
36
37impl LoadBitstream {
38    pub fn init(&self, transport: &TransportWrapper) -> Result<()> {
39        // Clear out existing bitstream, if requested.
40        if self.clear_bitstream {
41            log::info!("Clearing bitstream.");
42            transport.fpga_ops()?.clear_bitstream()?;
43        }
44        // Load the specified bitstream, if provided.
45        if let Some(bitstream) = &self.bitstream {
46            self.load(transport, bitstream)?;
47        }
48
49        Ok(())
50    }
51
52    pub fn load(&self, transport: &TransportWrapper, file: &Path) -> Result<()> {
53        log::info!("Loading bitstream: {:?}", file);
54        let payload = std::fs::read(file)?;
55        let progress = StagedProgressBar::new();
56        let operation = FpgaProgram {
57            bitstream: payload,
58            rom_reset_pulse: self.rom_reset_pulse,
59            rom_timeout: self.rom_timeout,
60            progress: Box::new(progress),
61        };
62
63        if !self.force && operation.should_skip(transport)? {
64            return Ok(());
65        }
66
67        transport
68            .fpga_ops()?
69            .load_bitstream(&operation.bitstream, &*operation.progress)
70    }
71}