68 lines
1.9 KiB
Rust
68 lines
1.9 KiB
Rust
use core::time::Duration;
|
|
|
|
use alloc::format;
|
|
use log::info;
|
|
|
|
use crate::{
|
|
process::ExecutionContext, scheduler::scheduler, set_csr, vga::{Color, FONT_WIDTH, Vga, WIDTH}
|
|
};
|
|
|
|
pub const IRQ_M_TIMER: u8 = 1 << 7;
|
|
pub const IRQ_S_TIMER: u8 = 1 << 5;
|
|
const CLINT_TIMER_CMP: *mut u64 = 0x02004000 as *mut u64;
|
|
const CLINT_TIMER: *const u64 = 0x0200bff8 as *const u64;
|
|
const TIMER_FREQUENCY: u64 = 10000000; // 10MHz
|
|
const INTERRUPT_FREQUENCY: u64 = 20; // 20Hz
|
|
|
|
static mut START_TIME: Instant = Instant(0);
|
|
|
|
pub fn setup_timer_interrupt() {
|
|
unsafe { START_TIME = Instant::now() };
|
|
set_csr!(sie, IRQ_S_TIMER);
|
|
setup_next_timer_interrupt();
|
|
}
|
|
|
|
pub fn setup_next_timer_interrupt() {
|
|
unsafe {
|
|
core::ptr::write_volatile(
|
|
CLINT_TIMER_CMP,
|
|
Instant::now().0 + TIMER_FREQUENCY / INTERRUPT_FREQUENCY,
|
|
);
|
|
}
|
|
}
|
|
pub fn timer_interrupt(interrupt_state: ExecutionContext) -> usize {
|
|
let current_time = elapsed_time_since_startup();
|
|
let seconds = current_time.as_secs();
|
|
let minutes = seconds / 60 % 60;
|
|
let hours = seconds / 3600 % 60;
|
|
let seconds = seconds % 60;
|
|
let formated_time = format!("{:02}:{:02}:{:02}", hours, minutes, seconds);
|
|
unsafe {
|
|
Vga::draw_string(
|
|
(WIDTH - formated_time.len() * FONT_WIDTH) as u16,
|
|
0,
|
|
formated_time,
|
|
Color::WHITE,
|
|
Color::BLACK,
|
|
)
|
|
};
|
|
scheduler(interrupt_state)
|
|
}
|
|
|
|
pub fn elapsed_time_since_startup() -> Duration {
|
|
unsafe { START_TIME.elapsed() }
|
|
}
|
|
|
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
|
pub struct Instant(u64);
|
|
|
|
impl Instant {
|
|
pub fn now() -> Self {
|
|
Instant(unsafe { core::ptr::read_volatile(CLINT_TIMER) })
|
|
}
|
|
pub fn elapsed(&self) -> Duration {
|
|
let now = Self::now();
|
|
Duration::from_nanos((now.0 - self.0) * (1_000_000_000 / TIMER_FREQUENCY))
|
|
}
|
|
}
|