1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
// Copyright lowRISC contributors (OpenTitan project).
// 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 std::time::Duration;
use std::time::Instant;

use crate::io::uart::Uart;
use crate::uart::console::{ExitStatus, UartConsole};
use crate::util::usr_access::usr_access_get;

pub struct RomDetect {
    usr_access: u32,
    console: UartConsole,
}

impl RomDetect {
    pub fn new(bitstream: &[u8], timeout: Option<Duration>) -> Result<RomDetect> {
        Ok(RomDetect {
            usr_access: usr_access_get(bitstream)?,
            console: UartConsole {
                timeout,
                exit_success: Some(Regex::new(r"(\w*ROM):([^\r\n]+)[\r\n]").unwrap()),
                ..Default::default()
            },
        })
    }

    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 fpga = cap
                .get(2)
                .map(|v| u32::from_str_radix(v.as_str(), 16))
                .unwrap()?;
            return Ok(fpga == self.usr_access);
        }
        log::info!("Did not detect the ROM identification message.");
        Ok(false)
    }
}