drtio: implement destination state checks on operations

This commit is contained in:
Sebastien Bourdeauducq 2018-09-15 15:55:45 +08:00
parent 1990ab35d3
commit d38755feff
10 changed files with 63 additions and 44 deletions

View File

@ -91,7 +91,7 @@ class RTIOOverflow(Exception):
artiq_builtin = True artiq_builtin = True
class RTIOLinkError(Exception): class RTIODestinationUnreachable(Exception):
"""Raised with a RTIO operation could not be completed due to a DRTIO link """Raised with a RTIO operation could not be completed due to a DRTIO link
being down. being down.
""" """

View File

@ -428,8 +428,8 @@ extern fn dma_playback(timestamp: i64, ptr: i32) {
timestamp as i64, channel as i64, 0); timestamp as i64, channel as i64, 0);
} }
if error & 2 != 0 { if error & 2 != 0 {
raise!("RTIOLinkError", raise!("RTIODestinationUnreachable",
"RTIO output link error at {0} mu, channel {1}", "RTIO destination unreachable, output, at {0} mu, channel {1}",
timestamp as i64, channel as i64, 0); timestamp as i64, channel as i64, 0);
} }
} }

View File

@ -7,13 +7,13 @@ mod imp {
use ::send; use ::send;
use kernel_proto::*; use kernel_proto::*;
pub const RTIO_O_STATUS_WAIT: u8 = 1; pub const RTIO_O_STATUS_WAIT: u8 = 1;
pub const RTIO_O_STATUS_UNDERFLOW: u8 = 2; pub const RTIO_O_STATUS_UNDERFLOW: u8 = 2;
pub const RTIO_O_STATUS_LINK_ERROR: u8 = 4; pub const RTIO_O_STATUS_DESTINATION_UNREACHABLE: u8 = 4;
pub const RTIO_I_STATUS_WAIT_EVENT: u8 = 1; pub const RTIO_I_STATUS_WAIT_EVENT: u8 = 1;
pub const RTIO_I_STATUS_OVERFLOW: u8 = 2; pub const RTIO_I_STATUS_OVERFLOW: u8 = 2;
pub const RTIO_I_STATUS_WAIT_STATUS: u8 = 4; pub const RTIO_I_STATUS_WAIT_STATUS: u8 = 4;
pub const RTIO_I_STATUS_LINK_ERROR: u8 = 8; pub const RTIO_I_STATUS_DESTINATION_UNREACHABLE: u8 = 8;
pub extern fn init() { pub extern fn init() {
send(&RtioInitRequest); send(&RtioInitRequest);
@ -49,9 +49,9 @@ mod imp {
"RTIO underflow at {0} mu, channel {1}, slack {2} mu", "RTIO underflow at {0} mu, channel {1}, slack {2} mu",
timestamp, channel as i64, timestamp - get_counter()); timestamp, channel as i64, timestamp - get_counter());
} }
if status & RTIO_O_STATUS_LINK_ERROR != 0 { if status & RTIO_O_STATUS_DESTINATION_UNREACHABLE != 0 {
raise!("RTIOLinkError", raise!("RTIODestinationUnreachable",
"RTIO output link error at {0} mu, channel {1}", "RTIO destination unreachable, output, at {0} mu, channel {1}",
timestamp, channel as i64, 0); timestamp, channel as i64, 0);
} }
} }
@ -108,9 +108,9 @@ mod imp {
if status & RTIO_I_STATUS_WAIT_EVENT != 0 { if status & RTIO_I_STATUS_WAIT_EVENT != 0 {
return !0 return !0
} }
if status & RTIO_I_STATUS_LINK_ERROR != 0 { if status & RTIO_I_STATUS_DESTINATION_UNREACHABLE != 0 {
raise!("RTIOLinkError", raise!("RTIODestinationUnreachable",
"RTIO input link error on channel {0}", "RTIO destination unreachable, input, on channel {0}",
channel as i64, 0, 0); channel as i64, 0, 0);
} }
@ -135,9 +135,9 @@ mod imp {
"RTIO input overflow on channel {0}", "RTIO input overflow on channel {0}",
channel as i64, 0, 0); channel as i64, 0, 0);
} }
if status & RTIO_I_STATUS_LINK_ERROR != 0 { if status & RTIO_I_STATUS_DESTINATION_UNREACHABLE != 0 {
raise!("RTIOLinkError", raise!("RTIODestinationUnreachable",
"RTIO input link error on channel {0}", "RTIO destination unreachable, input, on channel {0}",
channel as i64, 0, 0); channel as i64, 0, 0);
} }

View File

@ -72,13 +72,25 @@ pub fn config_routing_table(default_n_links: usize) -> RoutingTable {
} }
#[cfg(has_drtio_routing)] #[cfg(has_drtio_routing)]
pub fn program_interconnect(rt: &RoutingTable, rank: u8) pub fn interconnect_enable(routing_table: &RoutingTable, rank: u8, destination: u8) {
{ let hop = routing_table.0[destination as usize][rank as usize];
for i in 0..DEST_COUNT { unsafe {
let hop = rt.0[i][rank as usize]; csr::routing_table::destination_write(destination);
unsafe { csr::routing_table::hop_write(hop);
csr::routing_table::destination_write(i as _); }
csr::routing_table::hop_write(hop); }
}
#[cfg(has_drtio_routing)]
pub fn interconnect_disable(destination: u8) {
unsafe {
csr::routing_table::destination_write(destination);
csr::routing_table::hop_write(INVALID_HOP);
}
}
#[cfg(has_drtio_routing)]
pub fn interconnect_enable_all(routing_table: &RoutingTable, rank: u8) {
for i in 0..DEST_COUNT {
interconnect_enable(routing_table, rank, i as u8);
} }
} }

View File

@ -216,6 +216,7 @@ pub mod drtio {
if !up_destinations[destination] { if !up_destinations[destination] {
info!("[DEST#{}] destination is up", destination); info!("[DEST#{}] destination is up", destination);
up_destinations[destination] = true; up_destinations[destination] = true;
drtio_routing::interconnect_enable(routing_table, 0, destination as u8);
} }
} else if hop as usize <= csr::DRTIO.len() { } else if hop as usize <= csr::DRTIO.len() {
let linkno = hop - 1; let linkno = hop - 1;
@ -228,6 +229,7 @@ pub mod drtio {
Ok(drtioaux::Packet::DestinationDownReply) => { Ok(drtioaux::Packet::DestinationDownReply) => {
info!("[DEST#{}] destination is down", destination); info!("[DEST#{}] destination is down", destination);
up_destinations[destination] = false; up_destinations[destination] = false;
drtio_routing::interconnect_disable(destination as u8);
}, },
Ok(drtioaux::Packet::DestinationOkReply) => (), Ok(drtioaux::Packet::DestinationOkReply) => (),
Ok(drtioaux::Packet::DestinationSequenceErrorReply { channel }) => Ok(drtioaux::Packet::DestinationSequenceErrorReply { channel }) =>
@ -242,6 +244,7 @@ pub mod drtio {
} else { } else {
info!("[DEST#{}] destination is down", destination); info!("[DEST#{}] destination is down", destination);
up_destinations[destination] = false; up_destinations[destination] = false;
drtio_routing::interconnect_disable(destination as u8);
} }
} else { } else {
if link_up(linkno) { if link_up(linkno) {
@ -253,6 +256,7 @@ pub mod drtio {
Ok(drtioaux::Packet::DestinationOkReply) => { Ok(drtioaux::Packet::DestinationOkReply) => {
info!("[DEST#{}] destination is up", destination); info!("[DEST#{}] destination is up", destination);
up_destinations[destination] = true; up_destinations[destination] = true;
drtio_routing::interconnect_enable(routing_table, 0, destination as u8);
init_buffer_space(destination as u8, linkno); init_buffer_space(destination as u8, linkno);
}, },
Ok(packet) => error!("[DEST#{}] received unexpected aux packet: {:?}", destination, packet), Ok(packet) => error!("[DEST#{}] received unexpected aux packet: {:?}", destination, packet),
@ -394,12 +398,6 @@ pub fn startup(io: &Io, routing_table: &Urc<RefCell<drtio_routing::RoutingTable>
} }
} }
#[cfg(has_drtio_routing)]
{
let routing_table = routing_table.clone();
drtio_routing::program_interconnect(&routing_table.borrow(), 0);
}
drtio::startup(io, &routing_table); drtio::startup(io, &routing_table);
init_core(true); init_core(true);
io.spawn(4096, async_error_thread); io.spawn(4096, async_error_thread);

View File

@ -171,7 +171,7 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater],
#[cfg(has_drtio_routing)] #[cfg(has_drtio_routing)]
drtioaux::Packet::RoutingSetRank { rank } => { drtioaux::Packet::RoutingSetRank { rank } => {
*_rank = rank; *_rank = rank;
drtio_routing::program_interconnect(_routing_table, rank); drtio_routing::interconnect_enable_all(_routing_table, rank);
let rep_rank = rank + 1; let rep_rank = rank + 1;
for rep in _repeaters.iter() { for rep in _repeaters.iter() {

View File

@ -102,8 +102,7 @@ class RTController(Module):
o_status_wait = Signal() o_status_wait = Signal()
o_status_underflow = Signal() o_status_underflow = Signal()
self.comb += [ self.comb += [
self.cri.o_status.eq(Cat( self.cri.o_status.eq(Cat(o_status_wait, o_status_underflow)),
o_status_wait, o_status_underflow, ~self.csrs.link_up.storage)),
self.csrs.o_wait.status.eq(o_status_wait) self.csrs.o_wait.status.eq(o_status_wait)
] ]
o_underflow_set = Signal() o_underflow_set = Signal()
@ -143,8 +142,7 @@ class RTController(Module):
i_status_overflow = Signal() i_status_overflow = Signal()
i_status_wait_status = Signal() i_status_wait_status = Signal()
self.comb += self.cri.i_status.eq(Cat( self.comb += self.cri.i_status.eq(Cat(
i_status_wait_event, i_status_overflow, i_status_wait_status, i_status_wait_event, i_status_overflow, i_status_wait_status))
~self.csrs.link_up.storage))
load_read_reply = Signal() load_read_reply = Signal()
self.sync.sys_with_rst += [ self.sync.sys_with_rst += [

View File

@ -34,7 +34,7 @@ layout = [
("o_data", 512, DIR_M_TO_S), ("o_data", 512, DIR_M_TO_S),
("o_address", 16, DIR_M_TO_S), ("o_address", 16, DIR_M_TO_S),
# o_status bits: # o_status bits:
# <0:wait> <1:underflow> <2:link error> # <0:wait> <1:underflow> <2:destination unreachable>
("o_status", 3, DIR_S_TO_M), ("o_status", 3, DIR_S_TO_M),
# pessimistic estimate of the number of outputs events that can be # pessimistic estimate of the number of outputs events that can be
@ -47,7 +47,7 @@ layout = [
("i_timestamp", 64, DIR_S_TO_M), ("i_timestamp", 64, DIR_S_TO_M),
# i_status bits: # i_status bits:
# <0:wait for event (command timeout)> <1:overflow> <2:wait for status> # <0:wait for event (command timeout)> <1:overflow> <2:wait for status>
# <3:link error> # <3:destination unreachable>
# <0> and <1> are mutually exclusive. <1> has higher priority. # <0> and <1> are mutually exclusive. <1> has higher priority.
("i_status", 4, DIR_S_TO_M), ("i_status", 4, DIR_S_TO_M),
] ]
@ -122,6 +122,17 @@ class CRIDecoder(Module, AutoCSR):
# # # # # #
# routing # routing
if enable_routing:
destination_unreachable = Interface()
self.comb += [
destination_unreachable.o_status.eq(4),
destination_unreachable.i_status.eq(8)
]
slaves = slaves[:]
slaves.append(destination_unreachable)
target_len = 2**(len(slaves) - 1).bit_length()
slaves += [destination_unreachable]*(target_len - len(slaves))
slave_bits = bits_for(len(slaves)-1) slave_bits = bits_for(len(slaves)-1)
selected = Signal(slave_bits) selected = Signal(slave_bits)

View File

@ -125,7 +125,7 @@ class OutputsTestbench:
if status & 0x2: if status & 0x2:
raise RTIOUnderflow raise RTIOUnderflow
if status & 0x4: if status & 0x4:
raise RTIOLinkError raise RTIODestinationUnreachable
yield yield
wlen += 1 wlen += 1
return wlen return wlen
@ -264,7 +264,7 @@ class TestFullStack(unittest.TestCase):
if status & 0x2: if status & 0x2:
return "overflow" return "overflow"
if status & 0x8: if status & 0x8:
return "link error" return "destination unreachable"
return ((yield from kcsrs.i_data.read()), return ((yield from kcsrs.i_data.read()),
(yield from kcsrs.i_timestamp.read())) (yield from kcsrs.i_timestamp.read()))

View File

@ -5,7 +5,7 @@ import itertools
from migen import * from migen import *
from misoc.interconnect import wishbone from misoc.interconnect import wishbone
from artiq.coredevice.exceptions import RTIOUnderflow, RTIOLinkError from artiq.coredevice.exceptions import RTIOUnderflow, RTIODestinationUnreachable
from artiq.gateware import rtio from artiq.gateware import rtio
from artiq.gateware.rtio import dma, cri from artiq.gateware.rtio import dma, cri
from artiq.gateware.rtio.phy import ttl_simple from artiq.gateware.rtio.phy import ttl_simple
@ -61,7 +61,7 @@ def do_dma(dut, address):
if error & 1: if error & 1:
raise RTIOUnderflow raise RTIOUnderflow
if error & 2: if error & 2:
raise RTIOLinkError raise RTIODestinationUnreachable
test_writes1 = [ test_writes1 = [