Skip to content

Commit 1c9ce6b

Browse files
committed
[ot_transport] add fpga_ops and make bitstream methods part of it
This eliminates the special `dispatch` mechanism for FPGA programming. Signed-off-by: Gary Guo <[email protected]>
1 parent df6dd7f commit 1c9ce6b

File tree

12 files changed

+96
-75
lines changed

12 files changed

+96
-75
lines changed

sw/host/opentitanlib/src/app/mod.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ use crate::io::jtag::{JtagChain, JtagParams};
1919
use crate::io::spi::{Target, TransferMode};
2020
use crate::io::uart::Uart;
2121
use crate::transport::{
22-
Capability, ProgressIndicator, ProxyOps, Transport, TransportError, TransportInterfaceType,
23-
ioexpander,
22+
Capability, FpgaOps, ProgressIndicator, ProxyOps, Transport, TransportError,
23+
TransportInterfaceType, ioexpander,
2424
};
2525

2626
use anyhow::{Result, bail, ensure};
@@ -998,6 +998,11 @@ impl TransportWrapper {
998998
self.transport.emulator()
999999
}
10001000

1001+
/// Methods available only on FPGA implementations.
1002+
pub fn fpga_ops(&self) -> Result<&dyn FpgaOps> {
1003+
self.transport.fpga_ops()
1004+
}
1005+
10011006
/// Methods available only on Proxy implementation.
10021007
pub fn proxy_ops(&self) -> Result<&dyn ProxyOps> {
10031008
self.transport.proxy_ops()

sw/host/opentitanlib/src/test_utils/init.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,10 @@ impl InitializeTest {
144144
let _uart = self.bootstrap.options.uart_params.create(&transport)?;
145145

146146
// Load a bitstream.
147-
Self::print_result("load_bitstream", self.load_bitstream.init(&transport))?;
147+
Self::print_result(
148+
"load_bitstream",
149+
self.load_bitstream.init(&transport).map(|_| None),
150+
)?;
148151

149152
// Bootstrap an rv32 test program.
150153
Self::print_result("bootstrap", self.bootstrap.init(&transport))?;

sw/host/opentitanlib/src/test_utils/load_bitstream.rs

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use std::path::{Path, PathBuf};
88
use std::time::Duration;
99

1010
use crate::app::{StagedProgressBar, TransportWrapper};
11-
use crate::transport::common::fpga::{ClearBitstream, FpgaProgram};
11+
use crate::transport::common::fpga::FpgaProgram;
1212

1313
/// Load a bitstream into the FPGA.
1414
#[derive(Debug, Args)]
@@ -31,28 +31,21 @@ pub struct LoadBitstream {
3131
}
3232

3333
impl LoadBitstream {
34-
pub fn init(
35-
&self,
36-
transport: &TransportWrapper,
37-
) -> Result<Option<Box<dyn erased_serde::Serialize>>> {
34+
pub fn init(&self, transport: &TransportWrapper) -> Result<()> {
3835
// Clear out existing bitstream, if requested.
3936
if self.clear_bitstream {
4037
log::info!("Clearing bitstream.");
41-
transport.dispatch(&ClearBitstream)?;
38+
transport.fpga_ops()?.clear_bitstream()?;
4239
}
4340
// Load the specified bitstream, if provided.
4441
if let Some(bitstream) = &self.bitstream {
45-
self.load(transport, bitstream)
46-
} else {
47-
Ok(None)
42+
self.load(transport, bitstream)?;
4843
}
44+
45+
Ok(())
4946
}
5047

51-
pub fn load(
52-
&self,
53-
transport: &TransportWrapper,
54-
file: &Path,
55-
) -> Result<Option<Box<dyn erased_serde::Serialize>>> {
48+
pub fn load(&self, transport: &TransportWrapper, file: &Path) -> Result<()> {
5649
log::info!("Loading bitstream: {:?}", file);
5750
let payload = std::fs::read(file)?;
5851
let progress = StagedProgressBar::new();
@@ -64,8 +57,11 @@ impl LoadBitstream {
6457
};
6558

6659
if operation.should_skip(transport)? {
67-
return Ok(None);
60+
return Ok(());
6861
}
69-
transport.dispatch(&operation)
62+
63+
transport
64+
.fpga_ops()?
65+
.load_bitstream(&operation.bitstream, &*operation.progress)
7066
}
7167
}

sw/host/opentitanlib/src/transport/common/fpga.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,3 @@ impl FpgaProgram {
6565
Ok(false)
6666
}
6767
}
68-
69-
/// Command for Transport::dispatch().
70-
pub struct ClearBitstream;

sw/host/opentitanlib/src/transport/errors.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ pub enum TransportInterfaceType {
8383
I2c,
8484
Jtag,
8585
Emulator,
86+
FpgaOps,
8687
ProxyOps,
8788
GpioMonitoring,
8889
GpioBitbanging,

sw/host/opentitanlib/src/transport/mod.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,11 @@ pub trait Transport {
138138
Err(TransportError::InvalidInterface(TransportInterfaceType::Emulator).into())
139139
}
140140

141+
/// Methods available only on FPGA implementations.
142+
fn fpga_ops(&self) -> Result<&dyn FpgaOps> {
143+
Err(TransportError::InvalidInterface(TransportInterfaceType::FpgaOps).into())
144+
}
145+
141146
/// Methods available only on Proxy implementation.
142147
fn proxy_ops(&self) -> Result<&dyn ProxyOps> {
143148
Err(TransportError::InvalidInterface(TransportInterfaceType::ProxyOps).into())
@@ -162,6 +167,13 @@ pub trait Transport {
162167
}
163168
}
164169

170+
/// Methods available only on FPGA transports.
171+
pub trait FpgaOps {
172+
fn load_bitstream(&self, bitstream: &[u8], progress: &dyn ProgressIndicator) -> Result<()>;
173+
174+
fn clear_bitstream(&self) -> Result<()>;
175+
}
176+
165177
/// Methods available only on the Proxy implementation of the Transport trait.
166178
pub trait ProxyOps {
167179
/// Returns a string->string map containing user-defined aspects "provided" by the testbed

sw/host/opentitantool/src/command/clear_bitstream.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ use std::any::Any;
88

99
use opentitanlib::app::TransportWrapper;
1010
use opentitanlib::app::command::CommandDispatch;
11-
use opentitanlib::transport::common::fpga;
1211

1312
/// Clear the bitstream of the FPGA
1413
#[derive(Debug, Args)]
@@ -20,6 +19,7 @@ impl CommandDispatch for ClearBitstream {
2019
_context: &dyn Any,
2120
transport: &TransportWrapper,
2221
) -> Result<Option<Box<dyn erased_serde::Serialize>>> {
23-
transport.dispatch(&fpga::ClearBitstream)
22+
transport.fpga_ops()?.clear_bitstream()?;
23+
Ok(None)
2424
}
2525
}

sw/host/opentitantool/src/command/load_bitstream.rs

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,11 @@
55
use anyhow::Result;
66
use clap::Args;
77
use std::any::Any;
8-
use std::fs;
98
use std::path::PathBuf;
109
use std::time::Duration;
1110

11+
use opentitanlib::app::TransportWrapper;
1212
use opentitanlib::app::command::CommandDispatch;
13-
use opentitanlib::app::{StagedProgressBar, TransportWrapper};
14-
use opentitanlib::transport::common::fpga::FpgaProgram;
1513

1614
/// Load a bitstream into the FPGA.
1715
#[derive(Debug, Args)]
@@ -33,19 +31,14 @@ impl CommandDispatch for LoadBitstream {
3331
_context: &dyn Any,
3432
transport: &TransportWrapper,
3533
) -> Result<Option<Box<dyn erased_serde::Serialize>>> {
36-
log::info!("Loading bitstream: {:?}", self.filename);
37-
let bitstream = fs::read(&self.filename)?;
38-
let progress = StagedProgressBar::new();
39-
let operation = FpgaProgram {
40-
bitstream,
34+
opentitanlib::test_utils::load_bitstream::LoadBitstream {
35+
clear_bitstream: false,
36+
bitstream: Some(self.filename.clone()),
4137
rom_reset_pulse: self.rom_reset_pulse,
4238
rom_timeout: self.rom_timeout,
43-
progress: Box::new(progress),
44-
};
45-
46-
if operation.should_skip(transport)? {
47-
return Ok(None);
4839
}
49-
transport.dispatch(&operation)
40+
.init(transport)?;
41+
42+
Ok(None)
5043
}
5144
}

sw/host/ot_transports/chipwhisperer/src/lib.rs

Lines changed: 24 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@ use opentitanlib::io::spi::Target;
1818
use opentitanlib::io::uart::flow::SoftwareFlowControl;
1919
use opentitanlib::io::uart::serial::SerialPortUart;
2020
use opentitanlib::io::uart::{Uart, UartError};
21-
use opentitanlib::transport::common::fpga::{ClearBitstream, FpgaProgram};
2221
use opentitanlib::transport::{
23-
Capabilities, Capability, Transport, TransportError, TransportInterfaceType,
22+
Capabilities, Capability, FpgaOps, ProgressIndicator, Transport, TransportError,
23+
TransportInterfaceType,
2424
};
2525
use opentitanlib::util::fs::builtin_file;
2626
use opentitanlib::util::parse_int::ParseInt;
@@ -100,22 +100,6 @@ impl<B: Board> ChipWhisperer<B> {
100100
)?))
101101
}
102102
}
103-
104-
pub fn load_bitstream(&self, fpga_program: &FpgaProgram) -> Result<()> {
105-
// Program the FPGA bitstream.
106-
log::info!("Programming the FPGA bitstream.");
107-
let usb = self.device.borrow();
108-
usb.spi1_enable(false)?;
109-
usb.fpga_program(&fpga_program.bitstream, fpga_program.progress.as_ref())?;
110-
Ok(())
111-
}
112-
113-
pub fn clear_bitstream(&self) -> Result<()> {
114-
let usb = self.device.borrow();
115-
usb.spi1_enable(false)?;
116-
usb.clear_bitstream()?;
117-
Ok(())
118-
}
119103
}
120104

121105
impl<B: Board + 'static> Transport for ChipWhisperer<B> {
@@ -162,11 +146,12 @@ impl<B: Board + 'static> Transport for ChipWhisperer<B> {
162146
Ok(inner.spi.as_ref().unwrap().clone())
163147
}
164148

149+
fn fpga_ops(&self) -> Result<&dyn FpgaOps> {
150+
Ok(self)
151+
}
152+
165153
fn dispatch(&self, action: &dyn Any) -> Result<Option<Box<dyn erased_serde::Serialize>>> {
166-
if let Some(fpga_program) = action.downcast_ref::<FpgaProgram>() {
167-
self.load_bitstream(fpga_program)?;
168-
Ok(None)
169-
} else if action.downcast_ref::<ResetSam3x>().is_some() {
154+
if action.downcast_ref::<ResetSam3x>().is_some() {
170155
self.device.borrow().reset_sam3x()?;
171156
Ok(None)
172157
} else if action.downcast_ref::<SetPll>().is_some() {
@@ -180,9 +165,6 @@ impl<B: Board + 'static> Transport for ChipWhisperer<B> {
180165
usb.pll_out_enable(2, false)?;
181166
usb.pll_write_defaults()?;
182167
Ok(None)
183-
} else if action.downcast_ref::<ClearBitstream>().is_some() {
184-
self.clear_bitstream()?;
185-
Ok(None)
186168
} else if action.downcast_ref::<GetSam3xFwVersion>().is_some() {
187169
let usb = self.device.borrow();
188170
Ok(Some(Box::new(usb.get_firmware_version()?)))
@@ -192,6 +174,23 @@ impl<B: Board + 'static> Transport for ChipWhisperer<B> {
192174
}
193175
}
194176

177+
impl<B: Board> FpgaOps for ChipWhisperer<B> {
178+
fn load_bitstream(&self, bitstream: &[u8], progress: &dyn ProgressIndicator) -> Result<()> {
179+
// Program the FPGA bitstream.
180+
log::info!("Programming the FPGA bitstream.");
181+
let usb = self.device.borrow();
182+
usb.spi1_enable(false)?;
183+
usb.fpga_program(bitstream, progress)?;
184+
Ok(())
185+
}
186+
187+
fn clear_bitstream(&self) -> Result<()> {
188+
let usb = self.device.borrow();
189+
usb.spi1_enable(false)?;
190+
usb.clear_bitstream()?;
191+
Ok(())
192+
}
193+
}
195194
/// Command for Transport::dispatch().
196195
pub struct SetPll {}
197196

sw/host/ot_transports/hyperdebug/src/lib.rs

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,9 @@ use opentitanlib::io::jtag::{JtagChain, JtagParams};
2626
use opentitanlib::io::spi::Target;
2727
use opentitanlib::io::uart::Uart;
2828
use opentitanlib::io::uart::serial::flock_serial;
29-
use opentitanlib::transport::common::fpga::{ClearBitstream, FpgaProgram};
3029
use opentitanlib::transport::{
31-
Capabilities, Capability, SetJtagPins, Transport, TransportError, TransportInterfaceType,
32-
UpdateFirmware,
30+
Capabilities, Capability, FpgaOps, ProgressIndicator, SetJtagPins, Transport, TransportError,
31+
TransportInterfaceType, UpdateFirmware,
3332
};
3433
use opentitanlib::util::fs::builtin_file;
3534
use opentitanlib::util::usb::UsbBackend;
@@ -83,7 +82,7 @@ pub trait Flavor {
8382
}
8483
fn get_default_usb_vid() -> u16;
8584
fn get_default_usb_pid() -> u16;
86-
fn load_bitstream(_fpga_program: &FpgaProgram) -> Result<()> {
85+
fn load_bitstream(_bitstream: &[u8], _progress: &dyn ProgressIndicator) -> Result<()> {
8786
Err(TransportError::UnsupportedOperation.into())
8887
}
8988
fn clear_bitstream() -> Result<()> {
@@ -817,6 +816,10 @@ impl<T: Flavor> Transport for Hyperdebug<T> {
817816
)?))
818817
}
819818

819+
fn fpga_ops(&self) -> Result<&dyn FpgaOps> {
820+
Ok(self)
821+
}
822+
820823
fn dispatch(&self, action: &dyn Any) -> Result<Option<Box<dyn erased_serde::Serialize>>> {
821824
if let Some(update_firmware_action) = action.downcast_ref::<UpdateFirmware>() {
822825
let usb_vid = self.inner.usb_device.borrow().get_vendor_id();
@@ -856,10 +859,6 @@ impl<T: Flavor> Transport for Hyperdebug<T> {
856859
}
857860
_ => Err(TransportError::UnsupportedOperation.into()),
858861
}
859-
} else if let Some(fpga_program) = action.downcast_ref::<FpgaProgram>() {
860-
T::load_bitstream(fpga_program).map(|_| None)
861-
} else if action.downcast_ref::<ClearBitstream>().is_some() {
862-
T::clear_bitstream().map(|_| None)
863862
} else {
864863
Err(TransportError::UnsupportedOperation.into())
865864
}
@@ -893,6 +892,16 @@ impl<T: Flavor> Transport for Hyperdebug<T> {
893892
}
894893
}
895894

895+
impl<T: Flavor> FpgaOps for Hyperdebug<T> {
896+
fn load_bitstream(&self, bitstream: &[u8], progress: &dyn ProgressIndicator) -> Result<()> {
897+
T::load_bitstream(bitstream, progress)
898+
}
899+
900+
fn clear_bitstream(&self) -> Result<()> {
901+
T::clear_bitstream()
902+
}
903+
}
904+
896905
/// A `StandardFlavor` is a plain Hyperdebug board.
897906
pub struct StandardFlavor;
898907

@@ -980,11 +989,11 @@ impl<B: Board> Flavor for ChipWhispererFlavor<B> {
980989
fn get_default_usb_pid() -> u16 {
981990
StandardFlavor::get_default_usb_pid()
982991
}
983-
fn load_bitstream(fpga_program: &FpgaProgram) -> Result<()> {
992+
fn load_bitstream(bitstream: &[u8], progress: &dyn ProgressIndicator) -> Result<()> {
984993
// Try to establish a connection to the native Chip Whisperer interface
985994
// which we will use for bitstream loading.
986995
let board = ChipWhisperer::<B>::new(None, None, None, &[])?;
987-
board.load_bitstream(fpga_program)?;
996+
board.load_bitstream(bitstream, progress)?;
988997
Ok(())
989998
}
990999
fn clear_bitstream() -> Result<()> {

0 commit comments

Comments
 (0)