diff --git a/libs/xous-bio/src/bio_tests/mod.rs b/libs/xous-bio/src/bio_tests/mod.rs index 7210729d6..468abc82c 100644 --- a/libs/xous-bio/src/bio_tests/mod.rs +++ b/libs/xous-bio/src/bio_tests/mod.rs @@ -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: diff --git a/libs/xous-bio/src/bio_tests/units.rs b/libs/xous-bio/src/bio_tests/units.rs index c41cde76d..6065ddcc6 100644 --- a/libs/xous-bio/src/bio_tests/units.rs +++ b/libs/xous-bio/src/bio_tests/units.rs @@ -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" ); \ No newline at end of file diff --git a/libs/xous-bio/src/lib.rs b/libs/xous-bio/src/lib.rs index 58abed128..d03d623a3 100644 --- a/libs/xous-bio/src/lib.rs +++ b/libs/xous-bio/src/lib.rs @@ -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, pub imem_slice: &'static mut [u32],