Refactor bitstream loading
Refactor bitstream loading into common code and transport-specific code.
Signed-off-by: Chris Frantz <cfrantz@google.com>
diff --git a/sw/host/opentitanlib/BUILD b/sw/host/opentitanlib/BUILD
index c413d39..8dedb05 100644
--- a/sw/host/opentitanlib/BUILD
+++ b/sw/host/opentitanlib/BUILD
@@ -96,6 +96,7 @@
"src/tpm/mod.rs",
"src/tpm/status.rs",
"src/transport/common/mod.rs",
+ "src/transport/common/fpga.rs",
"src/transport/common/uart.rs",
"src/transport/cw310/gpio.rs",
"src/transport/cw310/mod.rs",
diff --git a/sw/host/opentitanlib/src/test_utils/load_bitstream.rs b/sw/host/opentitanlib/src/test_utils/load_bitstream.rs
index d69c8b8..5100c31 100644
--- a/sw/host/opentitanlib/src/test_utils/load_bitstream.rs
+++ b/sw/host/opentitanlib/src/test_utils/load_bitstream.rs
@@ -9,7 +9,7 @@
use structopt::StructOpt;
use crate::app::{self, TransportWrapper};
-use crate::transport::cw310;
+use crate::transport::common::fpga::FpgaProgram;
use crate::util::rom_detect::RomKind;
/// Load a bitstream into the FPGA.
@@ -51,7 +51,7 @@
let pfunc = Box::new(move |_, chunk| {
progress.inc(chunk as u64);
});
- let operation = cw310::FpgaProgram {
+ let operation = FpgaProgram {
bitstream: payload,
rom_kind: self.rom_kind,
rom_reset_pulse: self.rom_reset_pulse,
diff --git a/sw/host/opentitanlib/src/transport/common/fpga.rs b/sw/host/opentitanlib/src/transport/common/fpga.rs
new file mode 100644
index 0000000..c8fcbfa
--- /dev/null
+++ b/sw/host/opentitanlib/src/transport/common/fpga.rs
@@ -0,0 +1,57 @@
+// 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 std::time::Duration;
+
+use crate::io::gpio::GpioPin;
+use crate::io::uart::Uart;
+use crate::util::rom_detect::{RomDetect, RomKind};
+
+/// Command for Transport::dispatch().
+pub struct FpgaProgram<'a> {
+ /// The bitstream content to load into the FPGA.
+ pub bitstream: Vec<u8>,
+ /// What type of ROM to expect.
+ pub rom_kind: Option<RomKind>,
+ /// How long of a reset pulse to send to the device.
+ pub rom_reset_pulse: Duration,
+ /// How long to wait for the ROM to print its type and version.
+ pub rom_timeout: Duration,
+ /// A progress function to provide user feedback.
+ /// Will be called with the address and length of each chunk sent to the target device.
+ pub progress: Option<Box<dyn Fn(u32, u32) + 'a>>,
+}
+
+impl FpgaProgram<'_> {
+ pub fn check_correct_version(&self, uart: &dyn Uart, reset_pin: &dyn GpioPin) -> Result<bool> {
+ if let Some(rom_kind) = &self.rom_kind {
+ let mut rd = RomDetect::new(*rom_kind, &self.bitstream, Some(self.rom_timeout))?;
+
+ // Send a reset pulse so the ROM will print the FPGA version.
+ // Reset is active low, sleep, then drive high.
+ reset_pin.write(false)?;
+ std::thread::sleep(self.rom_reset_pulse);
+ // Also clear the UART RX buffer for improved robustness.
+ uart.clear_rx_buffer()?;
+ reset_pin.write(true)?;
+
+ // Now read the uart until the ROM prints it's version.
+ if rd.detect(&*uart)? {
+ log::info!("Already running the correct bitstream. Skip loading bitstream.");
+ // If we're already running the right ROM+bitstream,
+ // then we can skip bootstrap.
+ return Ok(true);
+ }
+ }
+ Ok(false)
+ }
+
+ pub fn skip(&self) -> bool {
+ self.bitstream.starts_with(b"__skip__")
+ }
+}
+
+/// Command for Transport::dispatch().
+pub struct ClearBitstream;
diff --git a/sw/host/opentitanlib/src/transport/common/mod.rs b/sw/host/opentitanlib/src/transport/common/mod.rs
index af23e89..36c135d 100644
--- a/sw/host/opentitanlib/src/transport/common/mod.rs
+++ b/sw/host/opentitanlib/src/transport/common/mod.rs
@@ -2,4 +2,5 @@
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
+pub mod fpga;
pub mod uart;
diff --git a/sw/host/opentitanlib/src/transport/cw310/mod.rs b/sw/host/opentitanlib/src/transport/cw310/mod.rs
index 3430f19..1f87b6e 100644
--- a/sw/host/opentitanlib/src/transport/cw310/mod.rs
+++ b/sw/host/opentitanlib/src/transport/cw310/mod.rs
@@ -10,17 +10,16 @@
use std::collections::hash_map::Entry;
use std::collections::HashMap;
use std::rc::Rc;
-use std::time::Duration;
use crate::io::gpio::GpioPin;
use crate::io::spi::Target;
use crate::io::uart::{Uart, UartError};
+use crate::transport::common::fpga::{ClearBitstream, FpgaProgram};
use crate::transport::common::uart::SerialPortUart;
use crate::transport::{
Capabilities, Capability, Transport, TransportError, TransportInterfaceType,
};
use crate::util::parse_int::ParseInt;
-use crate::util::rom_detect::{RomDetect, RomKind};
pub mod gpio;
pub mod spi;
@@ -185,34 +184,15 @@
// Open the console UART. We do this first so we get the receiver
// started and the uart buffering data for us.
let uart = self.uart("0")?;
- if fpga_program.bitstream.starts_with(b"__skip__") {
+ let reset_pin = self.gpio_pin(Self::PIN_SRST)?;
+ if fpga_program.skip() {
log::info!("Skip loading the __skip__ bitstream.");
return Ok(None);
}
- if let Some(rom_kind) = &fpga_program.rom_kind {
- let mut rd = RomDetect::new(
- *rom_kind,
- &fpga_program.bitstream,
- Some(fpga_program.rom_timeout),
- )?;
-
- // Send a reset pulse so the ROM will print the FPGA version.
- let reset_pin = self.gpio_pin(Self::PIN_SRST)?;
- // Reset is active low, sleep, then drive high.
- reset_pin.write(false)?;
- std::thread::sleep(fpga_program.rom_reset_pulse);
- // Also clear the UART RX buffer for improved robustness.
- uart.clear_rx_buffer()?;
- reset_pin.write(true)?;
-
- // Now read the uart until the ROM prints it's version.
- if rd.detect(&*uart)? {
- log::info!("Already running the correct bitstream. Skip loading bitstream.");
- // If we're already running the right ROM+bitstream,
- // then we can skip bootstrap.
- return Ok(None);
- }
+ if fpga_program.check_correct_version(&*uart, &*reset_pin)? {
+ return Ok(None);
}
+
// Program the FPGA bitstream.
log::info!("Programming the FPGA bitstream.");
let usb = self.device.borrow();
@@ -248,25 +228,7 @@
}
/// Command for Transport::dispatch().
-pub struct FpgaProgram<'a> {
- /// The bitstream content to load into the FPGA.
- pub bitstream: Vec<u8>,
- /// What type of ROM to expect.
- pub rom_kind: Option<RomKind>,
- /// How long of a reset pulse to send to the device.
- pub rom_reset_pulse: Duration,
- /// How long to wait for the ROM to print its type and version.
- pub rom_timeout: Duration,
- /// A progress function to provide user feedback.
- /// Will be called with the address and length of each chunk sent to the target device.
- pub progress: Option<Box<dyn Fn(u32, u32) + 'a>>,
-}
-
-/// Command for Transport::dispatch().
pub struct SetPll {}
/// Command for Transport::dispatch(). Resets the CW310's SAM3X chip.
pub struct ResetSam3x {}
-
-/// Command for Transport::dispatch().
-pub struct ClearBitstream {}
diff --git a/sw/host/opentitantool/src/command/clear_bitstream.rs b/sw/host/opentitantool/src/command/clear_bitstream.rs
index 7ed5f53..36b99a3 100644
--- a/sw/host/opentitantool/src/command/clear_bitstream.rs
+++ b/sw/host/opentitantool/src/command/clear_bitstream.rs
@@ -9,7 +9,7 @@
use opentitanlib::app::command::CommandDispatch;
use opentitanlib::app::TransportWrapper;
-use opentitanlib::transport::cw310;
+use opentitanlib::transport::common::fpga;
/// Clear the bitstream of the FPGA
#[derive(Debug, StructOpt)]
@@ -21,6 +21,6 @@
_context: &dyn Any,
transport: &TransportWrapper,
) -> Result<Option<Box<dyn Annotate>>> {
- transport.dispatch(&cw310::ClearBitstream {})
+ transport.dispatch(&fpga::ClearBitstream)
}
}
diff --git a/sw/host/opentitantool/src/command/load_bitstream.rs b/sw/host/opentitantool/src/command/load_bitstream.rs
index d3d991e..5985597 100644
--- a/sw/host/opentitantool/src/command/load_bitstream.rs
+++ b/sw/host/opentitantool/src/command/load_bitstream.rs
@@ -12,7 +12,7 @@
use opentitanlib::app::command::CommandDispatch;
use opentitanlib::app::{self, TransportWrapper};
-use opentitanlib::transport::cw310;
+use opentitanlib::transport::common::fpga::FpgaProgram;
use opentitanlib::util::rom_detect::RomKind;
/// Load a bitstream into the FPGA.
@@ -46,7 +46,7 @@
let pfunc = Box::new(move |_, chunk| {
progress.inc(chunk as u64);
});
- let operation = cw310::FpgaProgram {
+ let operation = FpgaProgram {
bitstream,
rom_kind: self.rom_kind,
rom_reset_pulse: self.rom_reset_pulse,