#![no_std]
#![no_main]
use core::fmt::{self, Write};
use core::hint::spin_loop;
use core::ptr::{read_volatile, write_volatile};
use panic_halt as _;
use riscv_rt::entry;
const UART0_BASE: usize = 0x500C_A000;
const UART_FIFO_REG: *mut u32 = UART0_BASE as *mut u32;
const UART_STATUS_REG: *const u32 = (UART0_BASE + 0x1C) as *const u32;
const UART_TXFIFO_CNT_SHIFT: u32 = 16;
const UART_TXFIFO_CNT_MASK: u32 = 0xFF << UART_TXFIFO_CNT_SHIFT;
const UART_TXFIFO_CAPACITY: u32 = 128;
const SYSTIMER_BASE: usize = 0x500E_2000;
const SYSTIMER_CONF: *mut u32 = SYSTIMER_BASE as *mut u32;
const SYSTIMER_UNIT0_OP: *mut u32 = (SYSTIMER_BASE + 0x04) as *mut u32;
const SYSTIMER_UNIT0_VAL_HI: *const u32 = (SYSTIMER_BASE + 0x40) as *const u32;
const SYSTIMER_UNIT0_VAL_LO: *const u32 = (SYSTIMER_BASE + 0x44) as *const u32;
const SYSTIMER_DATE: *const u32 = (SYSTIMER_BASE + 0xFC) as *const u32;
const HP_CLKRST_SOC_CLK_CTRL2: *const u32 = 0x500E_601C as *const u32;
const HP_CLKRST_PERI_CLK_CTRL21: *const u32 = 0x500E_6098 as *const u32;
const HP_CLKRST_HP_RST_EN1: *const u32 = 0x500E_60C4 as *const u32;
const UNIT_OP_UPDATE_BIT: u32 = 1 << 30;
const UNIT_OP_VALID_BIT: u32 = 1 << 29;
struct Uart0;
impl Uart0 {
fn write_byte(&mut self, byte: u8) {
while txfifo_count() >= UART_TXFIFO_CAPACITY {
spin_loop();
}
unsafe {
write_volatile(UART_FIFO_REG, byte as u32);
}
}
}
impl Write for Uart0 {
fn write_str(&mut self, s: &str) -> fmt::Result {
for byte in s.bytes() {
if byte == b'\n' {
self.write_byte(b'\r');
}
self.write_byte(byte);
}
Ok(())
}
}
fn txfifo_count() -> u32 {
let status = unsafe { read_volatile(UART_STATUS_REG) };
(status & UART_TXFIFO_CNT_MASK) >> UART_TXFIFO_CNT_SHIFT
}
fn delay_cycles(spins: usize) {
for _ in 0..spins {
spin_loop();
}
}
fn flush_uart() {
while txfifo_count() != 0 {
spin_loop();
}
}
fn read_unit0() -> u64 {
unsafe {
write_volatile(SYSTIMER_UNIT0_OP, UNIT_OP_UPDATE_BIT);
while read_volatile(SYSTIMER_UNIT0_OP) & UNIT_OP_VALID_BIT == 0 {
spin_loop();
}
let hi = read_volatile(SYSTIMER_UNIT0_VAL_HI) as u64;
let lo = read_volatile(SYSTIMER_UNIT0_VAL_LO) as u64;
(hi << 32) | lo
}
}
#[entry]
fn main() -> ! {
let mut uart = Uart0;
let _ = writeln!(uart, "\n=== systimer_probe alive ===");
flush_uart();
let date = unsafe { read_volatile(SYSTIMER_DATE) };
let conf = unsafe { read_volatile(SYSTIMER_CONF) };
let soc_clk_ctrl2 = unsafe { read_volatile(HP_CLKRST_SOC_CLK_CTRL2) };
let peri_clk_ctrl21 = unsafe { read_volatile(HP_CLKRST_PERI_CLK_CTRL21) };
let hp_rst_en1 = unsafe { read_volatile(HP_CLKRST_HP_RST_EN1) };
let _ = writeln!(uart, "SYSTIMER_DATE = 0x{:08X}", date);
let _ = writeln!(uart, "SYSTIMER_CONF = 0x{:08X}", conf);
let _ = writeln!(
uart,
" decoded: clk_en={} unit0_work_en={} unit1_work_en={} target0_en={}",
(conf >> 31) & 1,
(conf >> 30) & 1,
(conf >> 29) & 1,
(conf >> 24) & 1,
);
let _ = writeln!(
uart,
"SOC_CLK_CTRL2 = 0x{:08X} (bit23 SYSTIMER_APB_CLK_EN={})",
soc_clk_ctrl2,
(soc_clk_ctrl2 >> 23) & 1,
);
let _ = writeln!(
uart,
"PERI_CLK_CTRL21 = 0x{:08X} (bit29 CLK_SRC_SEL={} 0=XTAL,1=RC_FAST)",
peri_clk_ctrl21,
(peri_clk_ctrl21 >> 29) & 1,
);
let _ = writeln!(
uart,
"HP_RST_EN1 = 0x{:08X} (bit5 RST_EN_STIMER={})",
hp_rst_en1,
(hp_rst_en1 >> 5) & 1,
);
flush_uart();
let _ = writeln!(uart, "--- 5 snapshots, ~5ms apart ---");
flush_uart();
let mut prev = 0u64;
for i in 0..5 {
let v = read_unit0();
let _ = writeln!(uart, " t[{}] = {:>14} (delta = {})", i, v, v - prev);
flush_uart();
prev = v;
delay_cycles(50_000);
}
for spins in [50_000usize, 200_000, 1_000_000] {
let t0 = read_unit0();
delay_cycles(spins);
let t1 = read_unit0();
let dt = t1 - t0;
let per_spin = dt / spins as u64;
let _ = writeln!(
uart,
" spins={:>8} delta_ticks={:>10} ticks/spin={}",
spins, dt, per_spin
);
flush_uart();
}
let _ = writeln!(
uart,
" expected systimer rate = XTAL 40 MHz / 2.5 = 16 MHz (62.5 ns/tick)"
);
flush_uart();
let _ = writeln!(uart, "=== systimer_probe done ===");
flush_uart();
loop {
spin_loop();
}
}