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
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
// 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::{ensure, Context, Result};
use once_cell::sync::Lazy;
use regex::Regex;
use serde_annotate::Annotate;
use std::any::Any;
use std::cell::RefCell;
use std::rc::Rc;
use std::time::{Duration, Instant};

use crate::io::gpio::{GpioError, GpioPin};
use crate::io::uart::Uart;
use crate::transport::common::uart::SerialPortUart;
use crate::transport::verilator::gpio::{GpioInner, VerilatorGpioPin};
use crate::transport::verilator::subprocess::{Options, Subprocess};
use crate::transport::{
    Capabilities, Capability, Transport, TransportError, TransportInterfaceType,
};
use crate::util::parse_int::ParseInt;

const UART_BAUD: u32 = 40;

pub(crate) struct Inner {
    uart: Option<Rc<dyn Uart>>,
    pub gpio: GpioInner,
}

/// Represents the verilator transport object.
pub struct Verilator {
    subprocess: Option<Subprocess>,
    pub uart_tty: String,
    pub spi_file: String,
    pub gpio_read_file: String,
    pub gpio_write_file: String,

    inner: Rc<RefCell<Inner>>,
}

impl Verilator {
    /// Creates a verilator subprocess-hosting transport from `options`.
    pub fn from_options(options: Options) -> Result<Self> {
        static UART: Lazy<Regex> =
            Lazy::new(|| Regex::new("UART: Created ([^ ]+) for uart0").unwrap());
        static SPI: Lazy<Regex> =
            Lazy::new(|| Regex::new("SPI: Created ([^ ]+) for spi0").unwrap());
        static GPIO_RD: Lazy<Regex> = Lazy::new(|| {
            Regex::new(r"GPIO: FIFO pipes created at ([^ ]+) \(read\) and [^ ]+ \(write\) for 32-bit wide GPIO.").unwrap()
        });
        static GPIO_WR: Lazy<Regex> = Lazy::new(|| {
            Regex::new(r"GPIO: FIFO pipes created at [^ ]+ \(read\) and ([^ ]+) \(write\) for 32-bit wide GPIO.").unwrap()
        });

        let deadline = Instant::now() + options.timeout;
        let subprocess = Subprocess::from_options(options)?;
        let gpio_rd = subprocess.find(&GPIO_RD, deadline)?;
        let gpio_wr = subprocess.find(&GPIO_WR, deadline)?;
        let uart = subprocess.find(&UART, deadline)?;
        let spi = subprocess.find(&SPI, deadline)?;

        log::info!("Verilator started with the following interfaces:");
        log::info!("gpio_read = {}", gpio_rd);
        log::info!("gpio_write = {}", gpio_wr);
        let gpio = GpioInner::new(&gpio_rd, &gpio_wr)?;
        log::info!("uart = {}", uart);
        log::info!("spi = {}", spi);

        Ok(Verilator {
            subprocess: Some(subprocess),
            uart_tty: uart,
            spi_file: spi,
            gpio_read_file: gpio_rd,
            gpio_write_file: gpio_wr,
            inner: Rc::new(RefCell::new(Inner { uart: None, gpio })),
        })
    }

    /// Shuts down the verilator subprocess.
    pub fn shutdown(&mut self) -> Result<()> {
        if let Some(mut subprocess) = self.subprocess.take() {
            subprocess.kill()
        } else {
            Ok(())
        }
    }
}

impl Drop for Verilator {
    fn drop(&mut self) {
        self.shutdown().expect("Kill verilator subprocess");
    }
}

impl Transport for Verilator {
    fn capabilities(&self) -> Result<Capabilities> {
        Ok(Capabilities::new(Capability::UART | Capability::GPIO))
    }

    fn uart(&self, instance: &str) -> Result<Rc<dyn Uart>> {
        ensure!(
            instance == "0",
            TransportError::InvalidInstance(TransportInterfaceType::Uart, instance.to_string())
        );
        let mut inner = self.inner.borrow_mut();
        if inner.uart.is_none() {
            inner.uart = Some(Rc::new(SerialPortUart::open_pseudo(
                &self.uart_tty,
                UART_BAUD,
            )?));
        }
        Ok(Rc::clone(inner.uart.as_ref().unwrap()))
    }

    fn gpio_pin(&self, instance: &str) -> Result<Rc<dyn GpioPin>> {
        let pin = u8::from_str(instance).with_context(|| format!("can't convert {instance:?}"))?;
        ensure!(pin < 32 || pin == 255, GpioError::InvalidPinNumber(pin));
        let mut inner = self.inner.borrow_mut();
        Ok(Rc::clone(inner.gpio.pins.entry(pin).or_insert_with(|| {
            VerilatorGpioPin::new(Rc::clone(&self.inner), pin)
        })))
    }

    fn dispatch(&self, action: &dyn Any) -> Result<Option<Box<dyn Annotate>>> {
        if let Some(watch) = action.downcast_ref::<Watch>() {
            let subprocess = self.subprocess.as_ref().unwrap();
            let deadline = Instant::now() + watch.timeout.unwrap_or(Watch::FOREVER);
            let result = subprocess.find(&watch.regex, deadline)?;
            Ok(Some(Box::new(WatchResponse { result })))
        } else {
            Err(TransportError::UnsupportedOperation.into())
        }
    }
}

/// Watch verilator's stdout for a expression or timeout.
pub struct Watch {
    pub regex: Regex,
    pub timeout: Option<Duration>,
}

impl Watch {
    // Using Duration::MAX causes an overflow when calculating a deadline.
    // We use 100 years -- although it isn't "forever", it is longer than
    // any invocation of opentitantool.
    pub const FOREVER: Duration = Duration::from_secs(100 * 365 * 86400);
}

#[derive(serde::Serialize, Debug)]
pub struct WatchResponse {
    pub result: String,
}