mirror of
https://github.com/saymrwulf/xous-core.git
synced 2026-11-08 04:56:43 +00:00
more unit tests
fifo input/output from host with back-pressure works gpio loopback input testing works framework for automated assertion testing is in place; all tests from this point forward will endeavor to include some asserts that will cause the test to fail, so we don't require manual inspection to check test results.
This commit is contained in:
parent
ca3a3bba19
commit
0844cfbc52
3 changed files with 144 additions and 48 deletions
|
|
@ -1,5 +1,14 @@
|
|||
pub mod units;
|
||||
|
||||
// masks for utra::main::WDATA, which is abused to control GPIO register states for testing this module
|
||||
// these signals are "pulled through" the hierarchy and only exist in the test configuration, thus
|
||||
// they don't have a utralib entry
|
||||
pub const TEST_I2C_MASK: u32 = 0b00001;
|
||||
pub const TEST_FORCE_MASK: u32 = 0b00010;
|
||||
pub const TEST_LOOP_OE_MASK: u32 = 0b00100;
|
||||
pub const TEST_INVERT_MASK: u32 = 0b01000;
|
||||
pub const TEST_FORCE_OFFSET: usize = 16; // top 16 bits
|
||||
|
||||
#[cfg(not(any(target_os = "xous")))]
|
||||
mod duart {
|
||||
pub const UART_DOUT: utralib::Register = utralib::Register::new(0, 0xff);
|
||||
|
|
@ -81,22 +90,23 @@ pub fn bio_tests() {
|
|||
units::hello_world();
|
||||
units::hello_multiverse();
|
||||
units::fifo_basic();
|
||||
units::host_fifo_tests();
|
||||
}
|
||||
|
||||
// Test plan:
|
||||
// Unit tests:
|
||||
// -[x] Basic FIFO stall test. Two cores writing to each other to unlock.
|
||||
// -[ ] Host FIFO stall on empty test. Core stalls until host provides data.
|
||||
// -[ ] Host FIFO stall on full test. Core stall until host reads data.
|
||||
// -[ ] GPIO input path test
|
||||
// -[x] Host FIFO stall on empty test. Core stalls until host provides data.
|
||||
// -[x] Host FIFO stall on full test. Core stall until host reads data.
|
||||
// -[x] GPIO input path test
|
||||
// -[ ] Extclk as x20 stall source
|
||||
// -[ ] Check Extclk:gpio pin mapping (make sure bit ordering is not swapped)
|
||||
// -[ ] GPIO direction control test
|
||||
// -[ ] FIFO level trigger test - eq, gt, lt on various channels, at various fullness levels
|
||||
// -[ ] Stall on event - register bit test, between cores
|
||||
// -[ ] Stall on event - register bit test, to host
|
||||
// -[ ] Stall on event - FIFO level test
|
||||
// -[ ] Host IRQ generation test - some combination with event tests above to confirm IRQ generation
|
||||
// -[ ] Extclk as x20 stall source
|
||||
// -[ ] Check Extclk:gpio pin mapping (make sure bit ordering is not swapped)
|
||||
// -[ ] Core ID read test
|
||||
// -[ ] Core aclk counter test
|
||||
// Application tests:
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
use super::report_api;
|
||||
use super::{report_api, TEST_INVERT_MASK};
|
||||
use crate::*;
|
||||
|
||||
pub fn hello_world() {
|
||||
report_api(0x1310_0000);
|
||||
let mut bio_ss = BioSharedState::new();
|
||||
let simple_test_code = fn_to_slice(simple_test, simple_test_endcap);
|
||||
let simple_test_code = hello_world_code();
|
||||
// copy code to reset vector for 0th machine
|
||||
bio_ss.load_code(simple_test_code, 0);
|
||||
|
||||
|
|
@ -16,24 +16,15 @@ pub fn hello_world() {
|
|||
report_api(0x1310_00FF);
|
||||
}
|
||||
|
||||
pub unsafe fn simple_test() {
|
||||
core::arch::asm!(
|
||||
"add x1, zero, 0x10",
|
||||
"0:",
|
||||
"add x1, x1, 0x1",
|
||||
"mv x21, x1",
|
||||
"mv x20, zero",
|
||||
"j 0b",
|
||||
"nop"
|
||||
);
|
||||
}
|
||||
// this marks the "end address" of simple_test
|
||||
pub unsafe fn simple_test_endcap() {
|
||||
core::arch::asm!(
|
||||
"nop"
|
||||
);
|
||||
|
||||
}
|
||||
bio_code!(hello_world_code, HELLO_START, HELLO_END,
|
||||
"add x1, zero, 0x10",
|
||||
"0:",
|
||||
"add x1, x1, 0x1",
|
||||
"mv x21, x1",
|
||||
"mv x20, zero",
|
||||
"j 0b",
|
||||
"nop"
|
||||
);
|
||||
|
||||
pub fn hello_multiverse() {
|
||||
report_api(0x1310_1000);
|
||||
|
|
@ -51,8 +42,8 @@ pub fn hello_multiverse() {
|
|||
bio_ss.bio.wo(utra::bio::SFR_QDIV3, 0x20_0000);
|
||||
// snap GPIO outputs to the quantum
|
||||
bio_ss.bio.wo(utra::bio::SFR_CONFIG,
|
||||
bio_ss.bio.ms(utra::bio::SFR_CONFIG_SNAP_TO_QUANTUM, 1)
|
||||
| bio_ss.bio.ms(utra::bio::SFR_CONFIG_SNAP_TO_QUANTUM, 2) // arbitrary choice, they should all be the same
|
||||
bio_ss.bio.ms(utra::bio::SFR_CONFIG_SNAP_OUTPUT_TO_QUANTUM, 1)
|
||||
| bio_ss.bio.ms(utra::bio::SFR_CONFIG_SNAP_OUTPUT_TO_QUANTUM, 2) // arbitrary choice, they should all be the same
|
||||
);
|
||||
// start all the machines, all at once
|
||||
bio_ss.bio.wo(utra::bio::SFR_CTRL, 0xfff);
|
||||
|
|
@ -130,6 +121,9 @@ bio_code!(multiverse_code, MULTIVERSE_START, MULTIVERSE_END,
|
|||
pub fn fifo_basic() {
|
||||
report_api(0x1310_2000);
|
||||
report_api(0xf1f0_0000);
|
||||
// clear any prior test config state
|
||||
let mut test_cfg = CSR::new(utra::main::HW_MAIN_BASE as *mut u32);
|
||||
test_cfg.wo(utra::main::WDATA, 0);
|
||||
|
||||
let mut bio_ss = BioSharedState::new();
|
||||
// stop all the machines, so that code can be loaded
|
||||
|
|
@ -140,12 +134,11 @@ pub fn fifo_basic() {
|
|||
// configure & run the 0th machine
|
||||
// / 16. clock
|
||||
bio_ss.bio.wo(utra::bio::SFR_QDIV0, 0x23_BE00);
|
||||
bio_ss.bio.wo(utra::bio::SFR_QDIV3, 0x23_BE00);
|
||||
bio_ss.bio.wo(utra::bio::SFR_QDIV1, 0x33_1200);
|
||||
// snap GPIO outputs to the quantum
|
||||
bio_ss.bio.wo(utra::bio::SFR_CONFIG,
|
||||
bio_ss.bio.ms(utra::bio::SFR_CONFIG_SNAP_TO_QUANTUM, 1)
|
||||
| bio_ss.bio.ms(utra::bio::SFR_CONFIG_SNAP_TO_QUANTUM, 2) // arbitrary choice, they should all be the same
|
||||
);
|
||||
bio_ss.bio.wo(utra::bio::SFR_QDIV2, 0x33_1200);
|
||||
// don't snap GPIO outputs
|
||||
bio_ss.bio.wo(utra::bio::SFR_CONFIG, 0);
|
||||
// start all the machines, all at once
|
||||
bio_ss.bio.wo(utra::bio::SFR_CTRL, 0xfff);
|
||||
|
||||
|
|
@ -166,12 +159,13 @@ bio_code!(fifo_basic_code, FIFO_BASIC_START, FIFO_BASIC_END,
|
|||
"li x2, 0xFFFF",
|
||||
"mv x26, x2",
|
||||
"li x1, 0x10000000",
|
||||
"li x2, 0x10000",
|
||||
"11:",
|
||||
"mv x16, x1",
|
||||
"mv x21, x17",
|
||||
"add x1, x1, x2",
|
||||
// pass to mach 3 to update the loop counter
|
||||
"mv x19, x1",
|
||||
"mv x20, zero",
|
||||
"mv x1, x19",
|
||||
"j 11b",
|
||||
// mach 1 code
|
||||
"91:",
|
||||
|
|
@ -181,14 +175,89 @@ bio_code!(fifo_basic_code, FIFO_BASIC_START, FIFO_BASIC_END,
|
|||
"21:",
|
||||
"mv x17, x1",
|
||||
"mv x21, x16",
|
||||
"addi x1, x1, 1",
|
||||
// pass to mach 2 to update the loop counter
|
||||
"mv x18, x1",
|
||||
"mv x20, zero",
|
||||
"mv x1, x18",
|
||||
"j 21b",
|
||||
// mach 2 code
|
||||
"92:",
|
||||
"addi x18, x18, 2", // increment the value in fifo by 2
|
||||
"mv x20, zero",
|
||||
"j 92b",
|
||||
// mach 3 code
|
||||
"93:",
|
||||
"j 93b",
|
||||
"li x2, 0x40000",
|
||||
"23:",
|
||||
"add x19, x19, x2", // increment the value in fifo by 0x4_0000
|
||||
"mv x20, zero",
|
||||
"j 23b",
|
||||
"nop"
|
||||
);
|
||||
|
||||
pub fn host_fifo_tests() {
|
||||
report_api(0x1310_3000);
|
||||
report_api(0xf1f0_0001);
|
||||
// clear prior test config state
|
||||
let mut test_cfg = CSR::new(utra::main::HW_MAIN_BASE as *mut u32);
|
||||
test_cfg.wo(utra::main::WDATA, 0);
|
||||
|
||||
let mut bio_ss = BioSharedState::new();
|
||||
// stop all the machines, so that code can be loaded
|
||||
bio_ss.bio.wo(utra::bio::SFR_CTRL, 0x0);
|
||||
let code = fifo_host_bitbang();
|
||||
bio_ss.load_code(code, 0);
|
||||
|
||||
// configure & run the 0th machine
|
||||
// clock it slowly, so the fifo builds up back pressure
|
||||
bio_ss.bio.wo(utra::bio::SFR_QDIV0, 0x400_0000);
|
||||
bio_ss.bio.wo(utra::bio::SFR_QDIV1, 0x400_0000);
|
||||
// don't snap GPIO outputs
|
||||
bio_ss.bio.wo(utra::bio::SFR_CONFIG, 0);
|
||||
|
||||
// invert readbacks via I/O
|
||||
test_cfg.wo(utra::main::WDATA, TEST_INVERT_MASK);
|
||||
|
||||
// start cores 1 & 2
|
||||
bio_ss.bio.wo(utra::bio::SFR_CTRL, 0x333);
|
||||
|
||||
// clock some values into the bitbang fifo
|
||||
for i in 0..16 {
|
||||
bio_ss.bio.wo(utra::bio::SFR_TXF0, i + 0xF1F0_0000);
|
||||
while bio_ss.bio.rf(utra::bio::SFR_FLEVEL_PCLK_REGFIFO_LEVEL0) >= 8 {}
|
||||
}
|
||||
// wait for the write FIFO to drain
|
||||
while bio_ss.bio.rf(utra::bio::SFR_FLEVEL_PCLK_REGFIFO_LEVEL0) != 0 {}
|
||||
|
||||
// read back some fifo values, and check that back-pressure worked
|
||||
for i in 0..16 {
|
||||
let rbk = bio_ss.bio.r(utra::bio::SFR_RXF1);
|
||||
// we get indices 0-9: we can capture up to 8+1 entries before backpressure stops captures
|
||||
// and there is 1 extra value stuck in the CPU itself at the time of the stall.
|
||||
//
|
||||
// finally, we're pegged at 15, because, backpressure caused us to miss the rest of
|
||||
// the entries, and we are stuck at the final written value of the output test
|
||||
if i <= 9 {
|
||||
assert!(rbk == !(0xF1F0_0000 + i));
|
||||
} else {
|
||||
assert!(rbk == !(0xF1F0_0000 + 15));
|
||||
}
|
||||
report_api(rbk);
|
||||
}
|
||||
report_api(0x1310_30FF);
|
||||
}
|
||||
|
||||
bio_code!(fifo_host_bitbang, FIFO_HOST_BITBANG_START, FIFO_HOST_BITBANG_END,
|
||||
"j 90f",
|
||||
"nop",
|
||||
"j 91f",
|
||||
"nop",
|
||||
"90:",
|
||||
"mv x21, x16",
|
||||
"mv x20, zero",
|
||||
"j 90b",
|
||||
"91:",
|
||||
"mv x20, zero",
|
||||
"mv x17, x21",
|
||||
"j 91b"
|
||||
);
|
||||
|
|
@ -1,9 +1,38 @@
|
|||
//! FIFO - 8-deep fifo head/tail access. Cores halt on overflow/underflow.
|
||||
//! - x16 r/w fifo[0]
|
||||
//! - x17 r/w fifo[1]
|
||||
//! - x18 r/w fifo[2]
|
||||
//! - x19 r/w fifo[3]
|
||||
//!
|
||||
//! Quantum - core will halt until host-configured clock divider pules occurs,
|
||||
//! or an external event comes in on a host-specified GPIO pin.
|
||||
//! - x20 -/w halt to quantum
|
||||
//!
|
||||
//! GPIO - note clear-on-0 semantics for bit-clear ops
|
||||
//! - x21 r/w write: (x26 & x21) -> gpio pins; read: gpio pins -> x21
|
||||
//! - x22 -/w (x26 & x22) -> `1` will set corresponding pin on gpio
|
||||
//! - x23 -/w (x26 & x23) -> `0` will clear corresponding pin on gpio
|
||||
//! - x24 -/w (x26 & x24) -> `1` will make corresponding gpio pin an output
|
||||
//! - x25 -/w (x26 & x25) -> `0` will make corresponding gpio pin an input
|
||||
//! - x26 r/w mask GPIO action outputs
|
||||
//!
|
||||
//! Events - operate on a shared event register. Bits [7:0] are hard-wired to FIFO
|
||||
//! level flags, configured by the host; writes to bits [7:0] are ignored.
|
||||
//! - x27 -/w mask event sensitivity bits
|
||||
//! - x28 -/w `1` will set the corresponding event bit. Only [31:8] are wired up.
|
||||
//! - x29 -/w `1` will clear the corresponding event bit Only [31:8] are wired up.
|
||||
//! - x30 r/- halt until ((x27 & events) == x27), and return unmasked `events` value
|
||||
//!
|
||||
//! Core ID & debug:
|
||||
//! - x31 r/- [31:30] -> core ID; [29:0] -> cpu clocks since reset
|
||||
|
||||
#![cfg_attr(feature = "baremetal", no_std)]
|
||||
use utralib::generated::*;
|
||||
|
||||
#[cfg(feature = "tests")]
|
||||
pub mod bio_tests;
|
||||
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum BioError {
|
||||
/// specified state machine is not valid
|
||||
|
|
@ -29,18 +58,6 @@ pub fn lfsr_next(state: u16) -> u16 {
|
|||
|
||||
((state << 1) + bit) & 0x1_FF
|
||||
}
|
||||
|
||||
type BioRustFn = unsafe fn();
|
||||
|
||||
pub fn fn_to_slice(target_fn: BioRustFn, endcap_fn: BioRustFn) -> &'static [u8] {
|
||||
let start_ptr = target_fn as *const u8;
|
||||
unsafe {
|
||||
core::slice::from_raw_parts(start_ptr,
|
||||
(endcap_fn as *const u8) as usize - start_ptr as usize
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct BioSharedState {
|
||||
pub bio: CSR<u32>,
|
||||
pub imem_slice: &'static mut [u32],
|
||||
|
|
|
|||
Loading…
Reference in a new issue