blob: 39724e2a361febb44b20910338053fca933a18ca [file] [log] [blame]
// 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::{Deserialize, Serialize};
use std::convert::TryInto;
use std::str::FromStr;
use std::time::Duration;
use std::time::Instant;
use structopt::clap::arg_enum;
use thiserror::Error;
use crate::io::uart::Uart;
use crate::uart::console::{ExitStatus, UartConsole};
const REG_USR_ACCESS: [u8; 4] = [0x30, 0x01, 0xa0, 0x01];
#[derive(Error, Debug, Serialize, Deserialize)]
pub enum Error {
#[error("USR_ACCESS value not found in bitstream")]
UsrAccessNotFound,
}
arg_enum! {
#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq)]
pub enum RomKind {
TestRom,
Rom,
}
}
pub struct RomDetect {
kind: RomKind,
usr_access: u32,
console: UartConsole,
}
impl RomDetect {
pub fn new(kind: RomKind, bitstream: &[u8], timeout: Option<Duration>) -> Result<RomDetect> {
Ok(RomDetect {
kind: kind,
usr_access: Self::scan_usr_access(bitstream)?,
console: UartConsole {
timeout: timeout,
exit_success: Some(Regex::new(r"(\w+ROM):([^\r\n]+)[\r\n]").unwrap()),
..Default::default()
},
})
}
fn scan_usr_access(bitstream: &[u8]) -> Result<u32> {
let operand = bitstream
.chunks(4)
.skip_while(|op| **op != REG_USR_ACCESS)
.nth(1)
.ok_or(Error::UsrAccessNotFound)?;
let usr_access = u32::from_be_bytes(operand.try_into()?);
log::info!("Bitstream file USR_ACCESS value: {:#x}", usr_access);
Ok(usr_access)
}
pub fn detect(&mut self, uart: &dyn Uart) -> Result<bool> {
let t0 = Instant::now();
let rc = self.console.interact(uart, None, None)?;
let t1 = Instant::now();
log::debug!("detect exit={:?}, duration={:?}", rc, t1 - t0);
if let Some(cap) = self.console.captures(ExitStatus::ExitSuccess) {
log::info!("Current bitstream: {:?}", cap.get(0).unwrap().as_str());
let romkind = cap.get(1).unwrap().as_str();
let kind = match RomKind::from_str(romkind) {
Ok(k) => k,
Err(_) => {
log::error!("Could not identify ROM kind {:?}", romkind);
return Ok(false);
}
};
let fpga = cap
.get(2)
.map(|v| u32::from_str_radix(v.as_str(), 16))
.unwrap()?;
return Ok(kind == self.kind && fpga == self.usr_access);
}
log::info!("Did not detect the ROM identification message.");
Ok(false)
}
}