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 {
EchoRequest,
EchoReply,
RtioErrorRequest,
RtioNoErrorReply,
RtioErrorCollisionReply,
RtioErrorBusyReply,
MonitorRequest { channel: u16, probe: u8 },
MonitorReply { value: u32 },
InjectionRequest { channel: u16, overrd: u8, value: u8 },
@ -30,25 +36,31 @@ pub enum Packet {
impl Packet {
pub fn read_from(reader: &mut Read) -> io::Result<Packet> {
Ok(match read_u8(reader)? {
0 => Packet::EchoRequest,
1 => Packet::EchoReply,
2 => Packet::MonitorRequest {
0x00 => Packet::EchoRequest,
0x01 => Packet::EchoReply,
0x20 => Packet::RtioErrorRequest,
0x21 => Packet::RtioNoErrorReply,
0x22 => Packet::RtioErrorCollisionReply,
0x23 => Packet::RtioErrorBusyReply,
0x40 => Packet::MonitorRequest {
channel: read_u16(reader)?,
probe: read_u8(reader)?
},
3 => Packet::MonitorReply {
0x41 => Packet::MonitorReply {
value: read_u32(reader)?
},
4 => Packet::InjectionRequest {
0x50 => Packet::InjectionRequest {
channel: read_u16(reader)?,
overrd: read_u8(reader)?,
value: read_u8(reader)?
},
5 => Packet::InjectionStatusRequest {
0x51 => Packet::InjectionStatusRequest {
channel: read_u16(reader)?,
overrd: read_u8(reader)?
},
6 => Packet::InjectionStatusReply {
0x52 => Packet::InjectionStatusReply {
value: read_u8(reader)?
},
_ => 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<()> {
match *self {
Packet::EchoRequest => write_u8(writer, 0)?,
Packet::EchoReply => write_u8(writer, 1)?,
Packet::EchoRequest => write_u8(writer, 0x00)?,
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 } => {
write_u8(writer, 2)?;
write_u8(writer, 0x40)?;
write_u16(writer, channel)?;
write_u8(writer, probe)?;
},
Packet::MonitorReply { value } => {
write_u8(writer, 3)?;
write_u8(writer, 0x41)?;
write_u32(writer, value)?;
},
Packet::InjectionRequest { channel, overrd, value } => {
write_u8(writer, 4)?;
write_u8(writer, 0x50)?;
write_u16(writer, channel)?;
write_u8(writer, overrd)?;
write_u8(writer, value)?;
},
Packet::InjectionStatusRequest { channel, overrd } => {
write_u8(writer, 5)?;
write_u8(writer, 0x51)?;
write_u16(writer, channel)?;
write_u8(writer, overrd)?;
},
Packet::InjectionStatusReply { value } => {
write_u8(writer, 6)?;
write_u8(writer, 0x52)?;
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] {
unsafe {
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)]
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() {
let request = drtioaux::Packet::MonitorRequest { channel: channel, probe: probe };
drtioaux::hw::send(&request).unwrap();
let timeout = clock::get_ms() + 20;
while clock::get_ms() < timeout {
if !rtio_mgt::drtio::link_is_running() {
return 0
match drtioaux::hw::recv_timeout(10) {
Ok(drtioaux::Packet::MonitorReply { value }) => return value,
Ok(_) => error!("received unexpected aux packet"),
Err(e) => error!("aux packet error ({})", e)
}
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
} else {
0
}
}
fn read_probe(_io: &Io, channel: u32, probe: u8) -> u32 {
fn read_probe(channel: u32, probe: u8) -> u32 {
#[cfg(has_rtio_moninj)]
{
if channel & 0xff0000 == 0 {
@ -70,7 +60,7 @@ fn read_probe(_io: &Io, channel: u32, probe: u8) -> u32 {
#[cfg(has_drtio)]
{
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);
@ -126,35 +116,25 @@ fn read_injection_status_local(channel: u16, overrd: u8) -> u8 {
}
#[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() {
let request = drtioaux::Packet::InjectionStatusRequest {
channel: channel,
overrd: overrd
};
drtioaux::hw::send(&request).unwrap();
let timeout = clock::get_ms() + 20;
while clock::get_ms() < timeout {
if !rtio_mgt::drtio::link_is_running() {
return 0
match drtioaux::hw::recv_timeout(10) {
Ok(drtioaux::Packet::InjectionStatusReply { value }) => return value,
Ok(_) => error!("received unexpected aux packet"),
Err(e) => error!("aux packet error ({})", e)
}
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
} else {
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)]
{
if channel & 0xff0000 == 0 {
@ -164,7 +144,7 @@ fn read_injection_status(_io: &Io, channel: u32, probe: u8) -> u8 {
#[cfg(has_drtio)]
{
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);
@ -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::GetInjectionStatus { channel, overrd } => {
let value = read_injection_status(io, channel, overrd);
let value = read_injection_status(channel, overrd);
let reply = DeviceMessage::InjectionStatus {
channel: channel,
overrd: overrd,
@ -206,7 +186,7 @@ fn connection_worker(io: &Io, mut stream: &mut TcpStream) -> io::Result<()> {
if clock::get_ms() > next_check {
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) {
let message = DeviceMessage::MonitorStatus {
channel: channel,

View File

@ -43,7 +43,8 @@ pub mod drtio {
pub fn startup(io: &Io) {
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;
@ -144,7 +145,7 @@ pub mod drtio {
}
}
pub fn error_thread(io: Io) {
pub fn local_error_thread(io: Io) {
loop {
unsafe {
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))]

View File

@ -16,6 +16,27 @@ fn process_aux_packet(p: &drtioaux::Packet) {
// and u16 otherwise; hence the `as _` conversion.
match *p {
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 } => {
let value;
#[cfg(has_rtio_moninj)]

View File

@ -8,29 +8,28 @@ from misoc.interconnect.csr import *
class RTErrorsSatellite(Module, AutoCSR):
def __init__(self, rt_packet, ios):
self.protocol_error = CSR(4)
self.rtio_error = CSR(2)
# The master is normally responsible for avoiding output overflows and
# output underflows.
# Error reports here are only for diagnosing internal ARTIQ bugs.
unknown_packet_type = Signal()
packet_truncated = Signal()
write_overflow = Signal()
write_underflow = Signal()
self.comb += self.protocol_error.w.eq(
Cat(unknown_packet_type, packet_truncated,
write_underflow, write_overflow))
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)]):
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(self.protocol_error.re & self.protocol_error.r[n], target.eq(0)),
If(ps.o, target.eq(1))
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
# output underflows.
# Error reports here are only for diagnosing internal ARTIQ bugs.
error_csr(self.protocol_error,
rt_packet.unknown_packet_type,
rt_packet.packet_truncated,
ios.write_underflow,
ios.write_overflow)
error_csr(self.rtio_error,
ios.collision,
ios.busy)

View File

@ -11,6 +11,8 @@ class IOS(Module):
def __init__(self, rt_packet, channels, max_fine_ts_width, full_ts_width):
self.write_underflow = Signal()
self.write_overflow = Signal()
self.collision = Signal()
self.busy = Signal()
self.rt_packet = rt_packet
self.max_fine_ts_width = max_fine_ts_width
@ -26,7 +28,9 @@ class IOS(Module):
self.sync.rio += [
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):
self.add_output(n, channel)