Compare commits

..

2 Commits

Author SHA1 Message Date
a7dbfe506e firmware: add unit tests for exception sync 2024-08-21 17:18:31 +08:00
c0ab42d52d firmware: sync exception names and ids 2024-08-21 17:17:39 +08:00
2 changed files with 54 additions and 15 deletions

View File

@ -13,7 +13,7 @@
#![allow(non_camel_case_types)] #![allow(non_camel_case_types)]
use core::mem; use core::mem;
use cslice::CSlice; use cslice::{AsCSlice, CSlice};
use unwind as uw; use unwind as uw;
use libc::{c_int, c_void, uintptr_t}; use libc::{c_int, c_void, uintptr_t};
use log::{trace, error}; use log::{trace, error};
@ -218,8 +218,6 @@ pub unsafe fn artiq_personality(_state: uw::_Unwind_State,
} }
pub unsafe extern fn raise(exception: *const Exception) -> ! { pub unsafe extern fn raise(exception: *const Exception) -> ! {
use cslice::AsCSlice;
let count = EXCEPTION_BUFFER.exception_count; let count = EXCEPTION_BUFFER.exception_count;
let stack = &mut EXCEPTION_BUFFER.exception_stack; let stack = &mut EXCEPTION_BUFFER.exception_stack;
let diff = exception as isize - EXCEPTION_BUFFER.exceptions.as_ptr() as isize; let diff = exception as isize - EXCEPTION_BUFFER.exceptions.as_ptr() as isize;
@ -405,19 +403,27 @@ extern fn stop_fn(_version: c_int,
} }
} }
// Must be kept in sync with preallocate_runtime_exception_names() in artiq/language/embedding_map.py // Must be kept in sync with preallocate_runtime_exception_names() in `artiq.compiler.embedding`
static EXCEPTION_ID_LOOKUP: [(&str, u32); 11] = [ static EXCEPTION_ID_LOOKUP: [(&str, u32); 19] = [
("RuntimeError", 0), ("RTIOUnderflow", 0),
("RTIOUnderflow", 1), ("RTIOOverflow", 1),
("RTIOOverflow", 2), ("RTIODestinationUnreachable", 2),
("RTIODestinationUnreachable", 3), ("DMAError", 3),
("DMAError", 4), ("I2CError", 4),
("I2CError", 5), ("CacheError", 5),
("CacheError", 6), ("SPIError", 6),
("SPIError", 7), ("AssertionError", 7),
("ZeroDivisionError", 8), ("AttributeError", 8),
("IndexError", 9), ("IndexError", 9),
("UnwrapNoneError", 10), ("IOError", 10),
("KeyError", 11),
("NotImplementedError", 12),
("OverflowError", 13),
("RuntimeError", 14),
("TimeoutError", 15),
("TypeError", 16),
("ValueError", 17),
("ZeroDivisionError", 18),
]; ];
pub fn get_exception_id(name: &str) -> u32 { pub fn get_exception_id(name: &str) -> u32 {
@ -453,3 +459,29 @@ macro_rules! artiq_raise {
artiq_raise!($name, $message, 0, 0, 0) artiq_raise!($name, $message, 0, 0, 0)
}); });
} }
/// Takes as input exception id from host
/// Generates a new exception with:
/// * `id` set to `exn_id`
/// * `message` set to corresponding exception name from `EXCEPTION_ID_LOOKUP`
///
/// The message is matched on host to ensure correct exception is being referred
/// This test checks the synchronization of exception ids for runtime errors
#[no_mangle]
pub extern "C" fn test_exception_id_sync(exn_id: u32) {
let message = EXCEPTION_ID_LOOKUP
.iter()
.find_map(|&(name, id)| if id == exn_id { Some(name) } else { None })
.unwrap_or("unallocated internal exception id");
let exn = Exception {
id: exn_id,
file: file!().as_c_slice(),
line: 0,
column: 0,
function: "test_exception_id_sync".as_c_slice(),
message: message.as_c_slice(),
param: [0, 0, 0],
};
unsafe { raise(&exn) };
}

View File

@ -280,6 +280,13 @@ pub fn resolve(required: &[u8]) -> Option<u32> {
} }
api!(yn = yn) api!(yn = yn)
}, },
/*
* syscall for unit tests
* Used in `artiq.tests.coredevice.test_exceptions.ExceptionTest.test_raise_exceptions_kernel`
* This syscall checks that the exception IDs used in the Python `EmbeddingMap` (in `artiq.language.embedding`)
* match the `EXCEPTION_ID_LOOKUP` defined in the firmware (`libksupport::src::eh_artiq`)
*/
api!(test_exception_id_sync = eh_artiq::test_exception_id_sync)
]; ];
api.iter() api.iter()
.find(|&&(exported, _)| exported.as_bytes() == required) .find(|&&(exported, _)| exported.as_bytes() == required)