acpki: implement input interface

This commit is contained in:
Sebastien Bourdeauducq 2020-08-06 18:15:34 +08:00
parent 0354699ae3
commit 1eeee43d64
1 changed files with 108 additions and 8 deletions

View File

@ -11,7 +11,7 @@ pub const RTIO_O_STATUS_UNDERFLOW: i32 = 2;
pub const RTIO_O_STATUS_DESTINATION_UNREACHABLE: i32 = 4; pub const RTIO_O_STATUS_DESTINATION_UNREACHABLE: i32 = 4;
pub const RTIO_I_STATUS_WAIT_EVENT: i32 = 1; pub const RTIO_I_STATUS_WAIT_EVENT: i32 = 1;
pub const RTIO_I_STATUS_OVERFLOW: i32 = 2; pub const RTIO_I_STATUS_OVERFLOW: i32 = 2;
pub const RTIO_I_STATUS_WAIT_STATUS: i32 = 4; pub const RTIO_I_STATUS_WAIT_STATUS: i32 = 4; // TODO
pub const RTIO_I_STATUS_DESTINATION_UNREACHABLE: i32 = 8; pub const RTIO_I_STATUS_DESTINATION_UNREACHABLE: i32 = 8;
#[repr(C)] #[repr(C)]
@ -32,7 +32,7 @@ struct Transaction {
padding: i64, padding: i64,
reply_status: VolatileCell<i32>, reply_status: VolatileCell<i32>,
reply_data: VolatileCell<i32>, reply_data: VolatileCell<i32>,
reply_timestamp: VolatileCell<u64> reply_timestamp: VolatileCell<i64>
} }
static mut TRANSACTION_BUFFER: Transaction = Transaction { static mut TRANSACTION_BUFFER: Transaction = Transaction {
@ -69,16 +69,18 @@ pub extern fn get_counter() -> i64 {
} }
} }
static mut NOW: i64 = 0;
pub extern fn now_mu() -> i64 { pub extern fn now_mu() -> i64 {
unsafe { TRANSACTION_BUFFER.request_timestamp } unsafe { NOW }
} }
pub extern fn at_mu(t: i64) { pub extern fn at_mu(t: i64) {
unsafe { TRANSACTION_BUFFER.request_timestamp = t } unsafe { NOW = t }
} }
pub extern fn delay_mu(dt: i64) { pub extern fn delay_mu(dt: i64) {
unsafe { TRANSACTION_BUFFER.request_timestamp += dt } unsafe { NOW += dt }
} }
#[inline(never)] #[inline(never)]
@ -107,6 +109,7 @@ pub extern fn output(target: i32, data: i32) {
TRANSACTION_BUFFER.request_cmd = 0; TRANSACTION_BUFFER.request_cmd = 0;
TRANSACTION_BUFFER.request_target = target; TRANSACTION_BUFFER.request_target = target;
TRANSACTION_BUFFER.request_timestamp = NOW;
TRANSACTION_BUFFER.request_data = data as i64; TRANSACTION_BUFFER.request_data = data as i64;
asm::dmb(); asm::dmb();
@ -133,15 +136,112 @@ pub extern fn output_wide(target: i32, data: CSlice<i32>) {
} }
pub extern fn input_timestamp(timeout: i64, channel: i32) -> i64 { pub extern fn input_timestamp(timeout: i64, channel: i32) -> i64 {
unimplemented!(); unsafe {
// Clear status so we can observe response
TRANSACTION_BUFFER.reply_status.set(0);
TRANSACTION_BUFFER.request_cmd = 1;
TRANSACTION_BUFFER.request_timestamp = NOW;
TRANSACTION_BUFFER.request_target = channel << 8;
asm::dmb();
asm::sev();
let mut status;
loop {
status = TRANSACTION_BUFFER.reply_status.get();
if status != 0 {
break
}
}
if status & RTIO_I_STATUS_OVERFLOW != 0 {
artiq_raise!("RTIOOverflow",
"RTIO input overflow on channel {0}",
channel as i64, 0, 0);
}
if status & RTIO_I_STATUS_WAIT_EVENT != 0 {
return -1
}
if status & RTIO_I_STATUS_DESTINATION_UNREACHABLE != 0 {
artiq_raise!("RTIODestinationUnreachable",
"RTIO destination unreachable, input, on channel {0}",
channel as i64, 0, 0);
}
TRANSACTION_BUFFER.reply_timestamp.get()
}
} }
pub extern fn input_data(channel: i32) -> i32 { pub extern fn input_data(channel: i32) -> i32 {
unimplemented!(); unsafe {
TRANSACTION_BUFFER.reply_status.set(0);
TRANSACTION_BUFFER.request_cmd = 1;
TRANSACTION_BUFFER.request_timestamp = -1;
TRANSACTION_BUFFER.request_target = channel << 8;
asm::dmb();
asm::sev();
let mut status;
loop {
status = TRANSACTION_BUFFER.reply_status.get();
if status != 0 {
break
}
}
if status & RTIO_I_STATUS_OVERFLOW != 0 {
artiq_raise!("RTIOOverflow",
"RTIO input overflow on channel {0}",
channel as i64, 0, 0);
}
if status & RTIO_I_STATUS_DESTINATION_UNREACHABLE != 0 {
artiq_raise!("RTIODestinationUnreachable",
"RTIO destination unreachable, input, on channel {0}",
channel as i64, 0, 0);
}
TRANSACTION_BUFFER.reply_data.get()
}
} }
pub extern fn input_timestamped_data(timeout: i64, channel: i32) -> TimestampedData { pub extern fn input_timestamped_data(timeout: i64, channel: i32) -> TimestampedData {
unimplemented!(); unsafe {
TRANSACTION_BUFFER.reply_status.set(0);
TRANSACTION_BUFFER.request_cmd = 1;
TRANSACTION_BUFFER.request_timestamp = timeout;
TRANSACTION_BUFFER.request_target = channel << 8;
asm::dmb();
asm::sev();
let mut status;
loop {
status = TRANSACTION_BUFFER.reply_status.get();
if status != 0 {
break
}
}
if status & RTIO_I_STATUS_OVERFLOW != 0 {
artiq_raise!("RTIOOverflow",
"RTIO input overflow on channel {0}",
channel as i64, 0, 0);
}
if status & RTIO_I_STATUS_DESTINATION_UNREACHABLE != 0 {
artiq_raise!("RTIODestinationUnreachable",
"RTIO destination unreachable, input, on channel {0}",
channel as i64, 0, 0);
}
TimestampedData {
timestamp: TRANSACTION_BUFFER.reply_timestamp.get(),
data: TRANSACTION_BUFFER.reply_data.get(),
}
}
} }
pub fn write_log(data: &[i8]) { pub fn write_log(data: &[i8]) {