drtio: add infrastructure for reporting busy/collision errors

This commit is contained in:
Sebastien Bourdeauducq 2017-04-02 23:45:55 +08:00
parent 0a687b7902
commit 008678b741
6 changed files with 126 additions and 75 deletions

View File

@ -20,6 +20,12 @@ use proto::*;
pub enum Packet { pub enum Packet {
EchoRequest, EchoRequest,
EchoReply, EchoReply,
RtioErrorRequest,
RtioNoErrorReply,
RtioErrorCollisionReply,
RtioErrorBusyReply,
MonitorRequest { channel: u16, probe: u8 }, MonitorRequest { channel: u16, probe: u8 },
MonitorReply { value: u32 }, MonitorReply { value: u32 },
InjectionRequest { channel: u16, overrd: u8, value: u8 }, InjectionRequest { channel: u16, overrd: u8, value: u8 },
@ -30,25 +36,31 @@ pub enum Packet {
impl Packet { impl Packet {
pub fn read_from(reader: &mut Read) -> io::Result<Packet> { pub fn read_from(reader: &mut Read) -> io::Result<Packet> {
Ok(match read_u8(reader)? { Ok(match read_u8(reader)? {
0 => Packet::EchoRequest, 0x00 => Packet::EchoRequest,
1 => Packet::EchoReply, 0x01 => Packet::EchoReply,
2 => Packet::MonitorRequest {
0x20 => Packet::RtioErrorRequest,
0x21 => Packet::RtioNoErrorReply,
0x22 => Packet::RtioErrorCollisionReply,
0x23 => Packet::RtioErrorBusyReply,
0x40 => Packet::MonitorRequest {
channel: read_u16(reader)?, channel: read_u16(reader)?,
probe: read_u8(reader)? probe: read_u8(reader)?
}, },
3 => Packet::MonitorReply { 0x41 => Packet::MonitorReply {
value: read_u32(reader)? value: read_u32(reader)?
}, },
4 => Packet::InjectionRequest { 0x50 => Packet::InjectionRequest {
channel: read_u16(reader)?, channel: read_u16(reader)?,
overrd: read_u8(reader)?, overrd: read_u8(reader)?,
value: read_u8(reader)? value: read_u8(reader)?
}, },
5 => Packet::InjectionStatusRequest { 0x51 => Packet::InjectionStatusRequest {
channel: read_u16(reader)?, channel: read_u16(reader)?,
overrd: read_u8(reader)? overrd: read_u8(reader)?
}, },
6 => Packet::InjectionStatusReply { 0x52 => Packet::InjectionStatusReply {
value: read_u8(reader)? value: read_u8(reader)?
}, },
_ => return Err(io::Error::new(io::ErrorKind::InvalidData, "unknown packet type")) _ => return Err(io::Error::new(io::ErrorKind::InvalidData, "unknown packet type"))
@ -57,30 +69,36 @@ impl Packet {
pub fn write_to(&self, writer: &mut Write) -> io::Result<()> { pub fn write_to(&self, writer: &mut Write) -> io::Result<()> {
match *self { match *self {
Packet::EchoRequest => write_u8(writer, 0)?, Packet::EchoRequest => write_u8(writer, 0x00)?,
Packet::EchoReply => write_u8(writer, 1)?, Packet::EchoReply => write_u8(writer, 0x01)?,
Packet::RtioErrorRequest => write_u8(writer, 0x20)?,
Packet::RtioNoErrorReply => write_u8(writer, 0x21)?,
Packet::RtioErrorCollisionReply => write_u8(writer, 0x22)?,
Packet::RtioErrorBusyReply => write_u8(writer, 0x23)?,
Packet::MonitorRequest { channel, probe } => { Packet::MonitorRequest { channel, probe } => {
write_u8(writer, 2)?; write_u8(writer, 0x40)?;
write_u16(writer, channel)?; write_u16(writer, channel)?;
write_u8(writer, probe)?; write_u8(writer, probe)?;
}, },
Packet::MonitorReply { value } => { Packet::MonitorReply { value } => {
write_u8(writer, 3)?; write_u8(writer, 0x41)?;
write_u32(writer, value)?; write_u32(writer, value)?;
}, },
Packet::InjectionRequest { channel, overrd, value } => { Packet::InjectionRequest { channel, overrd, value } => {
write_u8(writer, 4)?; write_u8(writer, 0x50)?;
write_u16(writer, channel)?; write_u16(writer, channel)?;
write_u8(writer, overrd)?; write_u8(writer, overrd)?;
write_u8(writer, value)?; write_u8(writer, value)?;
}, },
Packet::InjectionStatusRequest { channel, overrd } => { Packet::InjectionStatusRequest { channel, overrd } => {
write_u8(writer, 5)?; write_u8(writer, 0x51)?;
write_u16(writer, channel)?; write_u16(writer, channel)?;
write_u8(writer, overrd)?; write_u8(writer, overrd)?;
}, },
Packet::InjectionStatusReply { value } => { Packet::InjectionStatusReply { value } => {
write_u8(writer, 6)?; write_u8(writer, 0x52)?;
write_u8(writer, value)?; write_u8(writer, value)?;
} }
} }
@ -161,6 +179,18 @@ pub mod hw {
} }
} }
pub fn recv_timeout(timeout_ms: u64) -> io::Result<Packet> {
let limit = board::clock::get_ms() + timeout_ms;
while board::clock::get_ms() < limit {
match recv() {
Ok(None) => (),
Ok(Some(packet)) => return Ok(packet),
Err(e) => return Err(e)
}
}
return Err(io::Error::new(io::ErrorKind::TimedOut, "timed out waiting for data"))
}
fn tx_get_buffer() -> &'static mut [u8] { fn tx_get_buffer() -> &'static mut [u8] {
unsafe { unsafe {
while board::csr::drtio::aux_tx_read() != 0 {} while board::csr::drtio::aux_tx_read() != 0 {}

View File

@ -35,32 +35,22 @@ fn read_probe_local(channel: u16, probe: u8) -> u32 {
} }
#[cfg(has_drtio)] #[cfg(has_drtio)]
fn read_probe_drtio(io: &Io, channel: u16, probe: u8) -> u32 { fn read_probe_drtio(channel: u16, probe: u8) -> u32 {
if rtio_mgt::drtio::link_is_running() { if rtio_mgt::drtio::link_is_running() {
let request = drtioaux::Packet::MonitorRequest { channel: channel, probe: probe }; let request = drtioaux::Packet::MonitorRequest { channel: channel, probe: probe };
drtioaux::hw::send(&request).unwrap(); drtioaux::hw::send(&request).unwrap();
match drtioaux::hw::recv_timeout(10) {
let timeout = clock::get_ms() + 20; Ok(drtioaux::Packet::MonitorReply { value }) => return value,
while clock::get_ms() < timeout { Ok(_) => error!("received unexpected aux packet"),
if !rtio_mgt::drtio::link_is_running() { Err(e) => error!("aux packet error ({})", e)
return 0
}
match drtioaux::hw::recv() {
Ok(None) => (),
Ok(Some(drtioaux::Packet::MonitorReply { value })) => return value,
Ok(Some(_)) => warn!("received unexpected aux packet"),
Err(e) => warn!("aux packet error ({})", e)
}
io.relinquish().unwrap();
} }
warn!("aux packet timeout");
0 0
} else { } else {
0 0
} }
} }
fn read_probe(_io: &Io, channel: u32, probe: u8) -> u32 { fn read_probe(channel: u32, probe: u8) -> u32 {
#[cfg(has_rtio_moninj)] #[cfg(has_rtio_moninj)]
{ {
if channel & 0xff0000 == 0 { if channel & 0xff0000 == 0 {
@ -70,7 +60,7 @@ fn read_probe(_io: &Io, channel: u32, probe: u8) -> u32 {
#[cfg(has_drtio)] #[cfg(has_drtio)]
{ {
if channel & 0xff0000 != 0 { if channel & 0xff0000 != 0 {
return read_probe_drtio(_io, channel as u16, probe) return read_probe_drtio(channel as u16, probe)
} }
} }
error!("read_probe: unrecognized channel number {}", channel); error!("read_probe: unrecognized channel number {}", channel);
@ -126,35 +116,25 @@ fn read_injection_status_local(channel: u16, overrd: u8) -> u8 {
} }
#[cfg(has_drtio)] #[cfg(has_drtio)]
fn read_injection_status_drtio(io: &Io, channel: u16, overrd: u8) -> u8 { fn read_injection_status_drtio(channel: u16, overrd: u8) -> u8 {
if rtio_mgt::drtio::link_is_running() { if rtio_mgt::drtio::link_is_running() {
let request = drtioaux::Packet::InjectionStatusRequest { let request = drtioaux::Packet::InjectionStatusRequest {
channel: channel, channel: channel,
overrd: overrd overrd: overrd
}; };
drtioaux::hw::send(&request).unwrap(); drtioaux::hw::send(&request).unwrap();
match drtioaux::hw::recv_timeout(10) {
let timeout = clock::get_ms() + 20; Ok(drtioaux::Packet::InjectionStatusReply { value }) => return value,
while clock::get_ms() < timeout { Ok(_) => error!("received unexpected aux packet"),
if !rtio_mgt::drtio::link_is_running() { Err(e) => error!("aux packet error ({})", e)
return 0
}
match drtioaux::hw::recv() {
Ok(None) => (),
Ok(Some(drtioaux::Packet::InjectionStatusReply { value })) => return value,
Ok(Some(_)) => warn!("received unexpected aux packet"),
Err(e) => warn!("aux packet error ({})", e)
}
io.relinquish().unwrap();
} }
warn!("aux packet timeout");
0 0
} else { } else {
0 0
} }
} }
fn read_injection_status(_io: &Io, channel: u32, probe: u8) -> u8 { fn read_injection_status(channel: u32, probe: u8) -> u8 {
#[cfg(has_rtio_moninj)] #[cfg(has_rtio_moninj)]
{ {
if channel & 0xff0000 == 0 { if channel & 0xff0000 == 0 {
@ -164,7 +144,7 @@ fn read_injection_status(_io: &Io, channel: u32, probe: u8) -> u8 {
#[cfg(has_drtio)] #[cfg(has_drtio)]
{ {
if channel & 0xff0000 != 0 { if channel & 0xff0000 != 0 {
return read_injection_status_drtio(_io, channel as u16, probe) return read_injection_status_drtio(channel as u16, probe)
} }
} }
error!("read_injection_status: unrecognized channel number {}", channel); error!("read_injection_status: unrecognized channel number {}", channel);
@ -191,7 +171,7 @@ fn connection_worker(io: &Io, mut stream: &mut TcpStream) -> io::Result<()> {
}, },
HostMessage::Inject { channel, overrd, value } => inject(channel, overrd, value), HostMessage::Inject { channel, overrd, value } => inject(channel, overrd, value),
HostMessage::GetInjectionStatus { channel, overrd } => { HostMessage::GetInjectionStatus { channel, overrd } => {
let value = read_injection_status(io, channel, overrd); let value = read_injection_status(channel, overrd);
let reply = DeviceMessage::InjectionStatus { let reply = DeviceMessage::InjectionStatus {
channel: channel, channel: channel,
overrd: overrd, overrd: overrd,
@ -206,7 +186,7 @@ fn connection_worker(io: &Io, mut stream: &mut TcpStream) -> io::Result<()> {
if clock::get_ms() > next_check { if clock::get_ms() > next_check {
for (&(channel, probe), previous) in watch_list.iter_mut() { for (&(channel, probe), previous) in watch_list.iter_mut() {
let current = read_probe(io, channel, probe); let current = read_probe(channel, probe);
if previous.is_none() || (previous.unwrap() != current) { if previous.is_none() || (previous.unwrap() != current) {
let message = DeviceMessage::MonitorStatus { let message = DeviceMessage::MonitorStatus {
channel: channel, channel: channel,

View File

@ -43,7 +43,8 @@ pub mod drtio {
pub fn startup(io: &Io) { pub fn startup(io: &Io) {
io.spawn(4096, link_thread); io.spawn(4096, link_thread);
io.spawn(4096, error_thread); io.spawn(4096, local_error_thread);
io.spawn(4096, aux_error_thread);
} }
static mut LINK_RUNNING: bool = false; static mut LINK_RUNNING: bool = false;
@ -144,7 +145,7 @@ pub mod drtio {
} }
} }
pub fn error_thread(io: Io) { pub fn local_error_thread(io: Io) {
loop { loop {
unsafe { unsafe {
io.until(|| csr::drtio::protocol_error_read() != 0).unwrap(); io.until(|| csr::drtio::protocol_error_read() != 0).unwrap();
@ -162,6 +163,22 @@ pub mod drtio {
} }
} }
} }
pub fn aux_error_thread(io: Io) {
loop {
io.sleep(200).unwrap();
if link_is_running() {
drtioaux::hw::send(&drtioaux::Packet::RtioErrorRequest).unwrap();
match drtioaux::hw::recv_timeout(10) {
Ok(drtioaux::Packet::RtioNoErrorReply) => (),
Ok(drtioaux::Packet::RtioErrorCollisionReply) => error!("RTIO collision (in satellite)"),
Ok(drtioaux::Packet::RtioErrorBusyReply) => error!("RTIO busy (in satellite)"),
Ok(_) => error!("received unexpected aux packet"),
Err(e) => error!("aux packet error ({})", e)
}
}
}
}
} }
#[cfg(not(has_drtio))] #[cfg(not(has_drtio))]

View File

@ -16,6 +16,27 @@ fn process_aux_packet(p: &drtioaux::Packet) {
// and u16 otherwise; hence the `as _` conversion. // and u16 otherwise; hence the `as _` conversion.
match *p { match *p {
drtioaux::Packet::EchoRequest => drtioaux::hw::send(&drtioaux::Packet::EchoReply).unwrap(), drtioaux::Packet::EchoRequest => drtioaux::hw::send(&drtioaux::Packet::EchoReply).unwrap(),
drtioaux::Packet::RtioErrorRequest => {
let errors;
unsafe {
errors = board::csr::drtio::rtio_error_read();
}
if errors & 1 != 0 {
unsafe {
board::csr::drtio::rtio_error_write(1);
}
drtioaux::hw::send(&drtioaux::Packet::RtioErrorCollisionReply).unwrap();
} else if errors & 2 != 0 {
unsafe {
board::csr::drtio::rtio_error_write(2);
}
drtioaux::hw::send(&drtioaux::Packet::RtioErrorBusyReply).unwrap();
} else {
drtioaux::hw::send(&drtioaux::Packet::RtioNoErrorReply).unwrap();
}
}
drtioaux::Packet::MonitorRequest { channel, probe } => { drtioaux::Packet::MonitorRequest { channel, probe } => {
let value; let value;
#[cfg(has_rtio_moninj)] #[cfg(has_rtio_moninj)]

View File

@ -8,29 +8,28 @@ from misoc.interconnect.csr import *
class RTErrorsSatellite(Module, AutoCSR): class RTErrorsSatellite(Module, AutoCSR):
def __init__(self, rt_packet, ios): def __init__(self, rt_packet, ios):
self.protocol_error = CSR(4) self.protocol_error = CSR(4)
self.rtio_error = CSR(2)
def error_csr(csr, *sources):
for n, source in enumerate(sources):
pending = Signal(related=source)
ps = PulseSynchronizer("rtio", "sys")
self.submodules += ps
self.comb += ps.i.eq(source)
self.sync += [
If(csr.re & csr.r[n], pending.eq(0)),
If(ps.o, pending.eq(1))
]
self.comb += csr.w[n].eq(pending)
# The master is normally responsible for avoiding output overflows and # The master is normally responsible for avoiding output overflows and
# output underflows. # output underflows.
# Error reports here are only for diagnosing internal ARTIQ bugs. # Error reports here are only for diagnosing internal ARTIQ bugs.
error_csr(self.protocol_error,
unknown_packet_type = Signal() rt_packet.unknown_packet_type,
packet_truncated = Signal() rt_packet.packet_truncated,
write_overflow = Signal() ios.write_underflow,
write_underflow = Signal() ios.write_overflow)
self.comb += self.protocol_error.w.eq( error_csr(self.rtio_error,
Cat(unknown_packet_type, packet_truncated, ios.collision,
write_underflow, write_overflow)) ios.busy)
for n, (target, source) in enumerate([
(unknown_packet_type, rt_packet.unknown_packet_type),
(packet_truncated, rt_packet.packet_truncated),
(write_underflow, ios.write_underflow),
(write_overflow, ios.write_overflow)]):
ps = PulseSynchronizer("rtio", "sys")
self.submodules += ps
self.comb += ps.i.eq(source)
self.sync += [
If(self.protocol_error.re & self.protocol_error.r[n], target.eq(0)),
If(ps.o, target.eq(1))
]

View File

@ -11,6 +11,8 @@ class IOS(Module):
def __init__(self, rt_packet, channels, max_fine_ts_width, full_ts_width): def __init__(self, rt_packet, channels, max_fine_ts_width, full_ts_width):
self.write_underflow = Signal() self.write_underflow = Signal()
self.write_overflow = Signal() self.write_overflow = Signal()
self.collision = Signal()
self.busy = Signal()
self.rt_packet = rt_packet self.rt_packet = rt_packet
self.max_fine_ts_width = max_fine_ts_width self.max_fine_ts_width = max_fine_ts_width
@ -26,7 +28,9 @@ class IOS(Module):
self.sync.rio += [ self.sync.rio += [
self.write_underflow.eq(0), self.write_underflow.eq(0),
self.write_overflow.eq(0) self.write_overflow.eq(0),
self.collision.eq(0),
self.busy.eq(0)
] ]
for n, channel in enumerate(channels): for n, channel in enumerate(channels):
self.add_output(n, channel) self.add_output(n, channel)