2021-07-21 15:25:37 +08:00
|
|
|
#![feature(never_type, panic_implementation, panic_info_message, const_slice_len, try_from)]
|
|
|
|
#![no_std]
|
|
|
|
|
|
|
|
#[macro_use]
|
|
|
|
extern crate log;
|
|
|
|
|
|
|
|
use core::convert::TryFrom;
|
2021-07-23 20:45:48 +08:00
|
|
|
use libboard_zynq::i2c::I2c; // not using a wrapper like runtime
|
2021-07-23 17:00:48 +08:00
|
|
|
use libboard_zynq::timer::GlobalTimer;
|
2021-07-21 15:25:37 +08:00
|
|
|
#[cfg(has_si5324)]
|
2021-07-23 19:15:07 +08:00
|
|
|
use libboard_artiq::si5324;
|
2021-07-22 17:24:43 +08:00
|
|
|
use board_artiq::spi; // <- port?, use libboard_zynq (if spi available/necessary)
|
2021-07-23 20:11:05 +08:00
|
|
|
use libboard_artiq::{pl::csr, drtio_routing, drtioaux, logger};
|
2021-07-21 15:25:37 +08:00
|
|
|
|
|
|
|
mod repeater;
|
|
|
|
|
2021-07-23 20:14:07 +08:00
|
|
|
fn identifier_read(buf: &mut [u8]) -> &str {
|
|
|
|
unsafe {
|
|
|
|
pl::csr::identifier::address_write(0);
|
|
|
|
let len = pl::csr::identifier::data_read();
|
|
|
|
let len = cmp::min(len, buf.len() as u8);
|
|
|
|
for i in 0..len {
|
|
|
|
pl::csr::identifier::address_write(1 + i);
|
|
|
|
buf[i as usize] = pl::csr::identifier::data_read();
|
|
|
|
}
|
|
|
|
str::from_utf8_unchecked(&buf[..len as usize])
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-21 15:25:37 +08:00
|
|
|
fn drtiosat_reset(reset: bool) {
|
|
|
|
unsafe {
|
|
|
|
csr::drtiosat::reset_write(if reset { 1 } else { 0 });
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn drtiosat_reset_phy(reset: bool) {
|
|
|
|
unsafe {
|
|
|
|
csr::drtiosat::reset_phy_write(if reset { 1 } else { 0 });
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn drtiosat_link_rx_up() -> bool {
|
|
|
|
unsafe {
|
|
|
|
csr::drtiosat::rx_up_read() == 1
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn drtiosat_tsc_loaded() -> bool {
|
|
|
|
unsafe {
|
|
|
|
let tsc_loaded = csr::drtiosat::tsc_loaded_read() == 1;
|
|
|
|
if tsc_loaded {
|
|
|
|
csr::drtiosat::tsc_loaded_write(1);
|
|
|
|
}
|
|
|
|
tsc_loaded
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[cfg(has_drtio_routing)]
|
|
|
|
macro_rules! forward {
|
|
|
|
($routing_table:expr, $destination:expr, $rank:expr, $repeaters:expr, $packet:expr) => {{
|
|
|
|
let hop = $routing_table.0[$destination as usize][$rank as usize];
|
|
|
|
if hop != 0 {
|
|
|
|
let repno = (hop - 1) as usize;
|
|
|
|
if repno < $repeaters.len() {
|
|
|
|
return $repeaters[repno].aux_forward($packet);
|
|
|
|
} else {
|
|
|
|
return Err(drtioaux::Error::RoutingError);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(not(has_drtio_routing))]
|
|
|
|
macro_rules! forward {
|
|
|
|
($routing_table:expr, $destination:expr, $rank:expr, $repeaters:expr, $packet:expr) => {}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn process_aux_packet(_repeaters: &mut [repeater::Repeater],
|
|
|
|
_routing_table: &mut drtio_routing::RoutingTable, _rank: &mut u8,
|
2021-07-23 20:45:48 +08:00
|
|
|
packet: drtioaux::Packet, timer: GlobalTimer, i2c: I2c) -> Result<(), drtioaux::Error<!>> {
|
2021-07-21 15:25:37 +08:00
|
|
|
// In the code below, *_chan_sel_write takes an u8 if there are fewer than 256 channels,
|
|
|
|
// and u16 otherwise; hence the `as _` conversion.
|
|
|
|
match packet {
|
|
|
|
drtioaux::Packet::EchoRequest =>
|
|
|
|
drtioaux::send(0, &drtioaux::Packet::EchoReply),
|
|
|
|
drtioaux::Packet::ResetRequest => {
|
|
|
|
info!("resetting RTIO");
|
|
|
|
drtiosat_reset(true);
|
2021-07-23 20:45:48 +08:00
|
|
|
timer.delay_us(100);
|
2021-07-21 15:25:37 +08:00
|
|
|
drtiosat_reset(false);
|
|
|
|
for rep in _repeaters.iter() {
|
|
|
|
if let Err(e) = rep.rtio_reset() {
|
|
|
|
error!("failed to issue RTIO reset ({})", e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
drtioaux::send(0, &drtioaux::Packet::ResetAck)
|
|
|
|
},
|
|
|
|
|
|
|
|
drtioaux::Packet::DestinationStatusRequest { destination: _destination } => {
|
|
|
|
#[cfg(has_drtio_routing)]
|
|
|
|
let hop = _routing_table.0[_destination as usize][*_rank as usize];
|
|
|
|
#[cfg(not(has_drtio_routing))]
|
|
|
|
let hop = 0;
|
|
|
|
|
|
|
|
if hop == 0 {
|
|
|
|
let errors;
|
|
|
|
unsafe {
|
|
|
|
errors = csr::drtiosat::rtio_error_read();
|
|
|
|
}
|
|
|
|
if errors & 1 != 0 {
|
|
|
|
let channel;
|
|
|
|
unsafe {
|
|
|
|
channel = csr::drtiosat::sequence_error_channel_read();
|
|
|
|
csr::drtiosat::rtio_error_write(1);
|
|
|
|
}
|
|
|
|
drtioaux::send(0,
|
|
|
|
&drtioaux::Packet::DestinationSequenceErrorReply { channel })?;
|
|
|
|
} else if errors & 2 != 0 {
|
|
|
|
let channel;
|
|
|
|
unsafe {
|
|
|
|
channel = csr::drtiosat::collision_channel_read();
|
|
|
|
csr::drtiosat::rtio_error_write(2);
|
|
|
|
}
|
|
|
|
drtioaux::send(0,
|
|
|
|
&drtioaux::Packet::DestinationCollisionReply { channel })?;
|
|
|
|
} else if errors & 4 != 0 {
|
|
|
|
let channel;
|
|
|
|
unsafe {
|
|
|
|
channel = csr::drtiosat::busy_channel_read();
|
|
|
|
csr::drtiosat::rtio_error_write(4);
|
|
|
|
}
|
|
|
|
drtioaux::send(0,
|
|
|
|
&drtioaux::Packet::DestinationBusyReply { channel })?;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
drtioaux::send(0, &drtioaux::Packet::DestinationOkReply)?;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(has_drtio_routing)]
|
|
|
|
{
|
|
|
|
if hop != 0 {
|
|
|
|
let hop = hop as usize;
|
|
|
|
if hop <= csr::DRTIOREP.len() {
|
|
|
|
let repno = hop - 1;
|
|
|
|
match _repeaters[repno].aux_forward(&drtioaux::Packet::DestinationStatusRequest {
|
|
|
|
destination: _destination
|
|
|
|
}) {
|
|
|
|
Ok(()) => (),
|
|
|
|
Err(drtioaux::Error::LinkDown) => drtioaux::send(0, &drtioaux::Packet::DestinationDownReply)?,
|
|
|
|
Err(e) => {
|
|
|
|
drtioaux::send(0, &drtioaux::Packet::DestinationDownReply)?;
|
|
|
|
error!("aux error when handling destination status request: {}", e);
|
|
|
|
},
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
drtioaux::send(0, &drtioaux::Packet::DestinationDownReply)?;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(has_drtio_routing)]
|
|
|
|
drtioaux::Packet::RoutingSetPath { destination, hops } => {
|
|
|
|
_routing_table.0[destination as usize] = hops;
|
|
|
|
for rep in _repeaters.iter() {
|
|
|
|
if let Err(e) = rep.set_path(destination, &hops) {
|
|
|
|
error!("failed to set path ({})", e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
drtioaux::send(0, &drtioaux::Packet::RoutingAck)
|
|
|
|
}
|
|
|
|
#[cfg(has_drtio_routing)]
|
|
|
|
drtioaux::Packet::RoutingSetRank { rank } => {
|
|
|
|
*_rank = rank;
|
|
|
|
drtio_routing::interconnect_enable_all(_routing_table, rank);
|
|
|
|
|
|
|
|
let rep_rank = rank + 1;
|
|
|
|
for rep in _repeaters.iter() {
|
|
|
|
if let Err(e) = rep.set_rank(rep_rank) {
|
|
|
|
error!("failed to set rank ({})", e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
info!("rank: {}", rank);
|
|
|
|
info!("routing table: {}", _routing_table);
|
|
|
|
|
|
|
|
drtioaux::send(0, &drtioaux::Packet::RoutingAck)
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(not(has_drtio_routing))]
|
|
|
|
drtioaux::Packet::RoutingSetPath { destination: _, hops: _ } => {
|
|
|
|
drtioaux::send(0, &drtioaux::Packet::RoutingAck)
|
|
|
|
}
|
|
|
|
#[cfg(not(has_drtio_routing))]
|
|
|
|
drtioaux::Packet::RoutingSetRank { rank: _ } => {
|
|
|
|
drtioaux::send(0, &drtioaux::Packet::RoutingAck)
|
|
|
|
}
|
|
|
|
|
|
|
|
drtioaux::Packet::MonitorRequest { destination: _destination, channel, probe } => {
|
|
|
|
forward!(_routing_table, _destination, *_rank, _repeaters, &packet);
|
|
|
|
let value;
|
|
|
|
#[cfg(has_rtio_moninj)]
|
|
|
|
unsafe {
|
|
|
|
csr::rtio_moninj::mon_chan_sel_write(channel as _);
|
|
|
|
csr::rtio_moninj::mon_probe_sel_write(probe);
|
|
|
|
csr::rtio_moninj::mon_value_update_write(1);
|
|
|
|
value = csr::rtio_moninj::mon_value_read();
|
|
|
|
}
|
|
|
|
#[cfg(not(has_rtio_moninj))]
|
|
|
|
{
|
|
|
|
value = 0;
|
|
|
|
}
|
|
|
|
let reply = drtioaux::Packet::MonitorReply { value: value as u32 };
|
|
|
|
drtioaux::send(0, &reply)
|
|
|
|
},
|
|
|
|
drtioaux::Packet::InjectionRequest { destination: _destination, channel, overrd, value } => {
|
|
|
|
forward!(_routing_table, _destination, *_rank, _repeaters, &packet);
|
|
|
|
#[cfg(has_rtio_moninj)]
|
|
|
|
unsafe {
|
|
|
|
csr::rtio_moninj::inj_chan_sel_write(channel as _);
|
|
|
|
csr::rtio_moninj::inj_override_sel_write(overrd);
|
|
|
|
csr::rtio_moninj::inj_value_write(value);
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
},
|
|
|
|
drtioaux::Packet::InjectionStatusRequest { destination: _destination, channel, overrd } => {
|
|
|
|
forward!(_routing_table, _destination, *_rank, _repeaters, &packet);
|
|
|
|
let value;
|
|
|
|
#[cfg(has_rtio_moninj)]
|
|
|
|
unsafe {
|
|
|
|
csr::rtio_moninj::inj_chan_sel_write(channel as _);
|
|
|
|
csr::rtio_moninj::inj_override_sel_write(overrd);
|
|
|
|
value = csr::rtio_moninj::inj_value_read();
|
|
|
|
}
|
|
|
|
#[cfg(not(has_rtio_moninj))]
|
|
|
|
{
|
|
|
|
value = 0;
|
|
|
|
}
|
|
|
|
drtioaux::send(0, &drtioaux::Packet::InjectionStatusReply { value: value })
|
|
|
|
},
|
|
|
|
|
|
|
|
drtioaux::Packet::I2cStartRequest { destination: _destination, busno } => {
|
|
|
|
forward!(_routing_table, _destination, *_rank, _repeaters, &packet);
|
2021-07-23 20:45:48 +08:00
|
|
|
let succeeded = i2c.start(busno).is_ok();
|
2021-07-21 15:25:37 +08:00
|
|
|
drtioaux::send(0, &drtioaux::Packet::I2cBasicReply { succeeded: succeeded })
|
|
|
|
}
|
|
|
|
drtioaux::Packet::I2cRestartRequest { destination: _destination, busno } => {
|
|
|
|
forward!(_routing_table, _destination, *_rank, _repeaters, &packet);
|
2021-07-23 20:45:48 +08:00
|
|
|
let succeeded = i2c.restart(busno).is_ok();
|
2021-07-21 15:25:37 +08:00
|
|
|
drtioaux::send(0, &drtioaux::Packet::I2cBasicReply { succeeded: succeeded })
|
|
|
|
}
|
|
|
|
drtioaux::Packet::I2cStopRequest { destination: _destination, busno } => {
|
|
|
|
forward!(_routing_table, _destination, *_rank, _repeaters, &packet);
|
2021-07-23 20:45:48 +08:00
|
|
|
let succeeded = i2c.stop(busno).is_ok();
|
2021-07-21 15:25:37 +08:00
|
|
|
drtioaux::send(0, &drtioaux::Packet::I2cBasicReply { succeeded: succeeded })
|
|
|
|
}
|
|
|
|
drtioaux::Packet::I2cWriteRequest { destination: _destination, busno, data } => {
|
|
|
|
forward!(_routing_table, _destination, *_rank, _repeaters, &packet);
|
2021-07-23 20:45:48 +08:00
|
|
|
match i2c.write(busno, data) {
|
2021-07-21 15:25:37 +08:00
|
|
|
Ok(ack) => drtioaux::send(0,
|
|
|
|
&drtioaux::Packet::I2cWriteReply { succeeded: true, ack: ack }),
|
|
|
|
Err(_) => drtioaux::send(0,
|
|
|
|
&drtioaux::Packet::I2cWriteReply { succeeded: false, ack: false })
|
|
|
|
}
|
|
|
|
}
|
|
|
|
drtioaux::Packet::I2cReadRequest { destination: _destination, busno, ack } => {
|
|
|
|
forward!(_routing_table, _destination, *_rank, _repeaters, &packet);
|
2021-07-23 20:45:48 +08:00
|
|
|
match i2c.read(busno, ack) {
|
2021-07-21 15:25:37 +08:00
|
|
|
Ok(data) => drtioaux::send(0,
|
|
|
|
&drtioaux::Packet::I2cReadReply { succeeded: true, data: data }),
|
|
|
|
Err(_) => drtioaux::send(0,
|
|
|
|
&drtioaux::Packet::I2cReadReply { succeeded: false, data: 0xff })
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
drtioaux::Packet::SpiSetConfigRequest { destination: _destination, busno, flags, length, div, cs } => {
|
|
|
|
forward!(_routing_table, _destination, *_rank, _repeaters, &packet);
|
|
|
|
let succeeded = spi::set_config(busno, flags, length, div, cs).is_ok();
|
|
|
|
drtioaux::send(0,
|
|
|
|
&drtioaux::Packet::SpiBasicReply { succeeded: succeeded })
|
|
|
|
},
|
|
|
|
drtioaux::Packet::SpiWriteRequest { destination: _destination, busno, data } => {
|
|
|
|
forward!(_routing_table, _destination, *_rank, _repeaters, &packet);
|
|
|
|
let succeeded = spi::write(busno, data).is_ok();
|
|
|
|
drtioaux::send(0,
|
|
|
|
&drtioaux::Packet::SpiBasicReply { succeeded: succeeded })
|
|
|
|
}
|
|
|
|
drtioaux::Packet::SpiReadRequest { destination: _destination, busno } => {
|
|
|
|
forward!(_routing_table, _destination, *_rank, _repeaters, &packet);
|
|
|
|
match spi::read(busno) {
|
|
|
|
Ok(data) => drtioaux::send(0,
|
|
|
|
&drtioaux::Packet::SpiReadReply { succeeded: true, data: data }),
|
|
|
|
Err(_) => drtioaux::send(0,
|
|
|
|
&drtioaux::Packet::SpiReadReply { succeeded: false, data: 0 })
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
drtioaux::Packet::JdacBasicRequest { destination: _destination, dacno: _dacno,
|
|
|
|
reqno: _reqno, param: _param } => {
|
|
|
|
forward!(_routing_table, _destination, *_rank, _repeaters, &packet);
|
|
|
|
let (succeeded, retval) = (false, 0);
|
|
|
|
drtioaux::send(0,
|
|
|
|
&drtioaux::Packet::JdacBasicReply { succeeded: succeeded, retval: retval })
|
|
|
|
}
|
|
|
|
|
|
|
|
_ => {
|
|
|
|
warn!("received unexpected aux packet");
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn process_aux_packets(repeaters: &mut [repeater::Repeater],
|
2021-07-23 20:45:48 +08:00
|
|
|
routing_table: &mut drtio_routing::RoutingTable, rank: &mut u8,
|
|
|
|
timer::GlobalTimer, i2c: I2c) {
|
2021-07-21 15:25:37 +08:00
|
|
|
let result =
|
|
|
|
drtioaux::recv(0).and_then(|packet| {
|
|
|
|
if let Some(packet) = packet {
|
2021-07-23 20:45:48 +08:00
|
|
|
process_aux_packet(repeaters, routing_table, rank, packet, timer, i2c)
|
2021-07-21 15:25:37 +08:00
|
|
|
} else {
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
});
|
|
|
|
match result {
|
|
|
|
Ok(()) => (),
|
|
|
|
Err(e) => warn!("aux packet error ({})", e)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn drtiosat_process_errors() {
|
|
|
|
let errors;
|
|
|
|
unsafe {
|
|
|
|
errors = csr::drtiosat::protocol_error_read();
|
|
|
|
}
|
|
|
|
if errors & 1 != 0 {
|
|
|
|
error!("received packet of an unknown type");
|
|
|
|
}
|
|
|
|
if errors & 2 != 0 {
|
|
|
|
error!("received truncated packet");
|
|
|
|
}
|
|
|
|
if errors & 4 != 0 {
|
|
|
|
let destination;
|
|
|
|
unsafe {
|
|
|
|
destination = csr::drtiosat::buffer_space_timeout_dest_read();
|
|
|
|
}
|
|
|
|
error!("timeout attempting to get buffer space from CRI, destination=0x{:02x}", destination)
|
|
|
|
}
|
|
|
|
if errors & 8 != 0 {
|
|
|
|
let channel;
|
|
|
|
let timestamp_event;
|
|
|
|
let timestamp_counter;
|
|
|
|
unsafe {
|
|
|
|
channel = csr::drtiosat::underflow_channel_read();
|
|
|
|
timestamp_event = csr::drtiosat::underflow_timestamp_event_read() as i64;
|
|
|
|
timestamp_counter = csr::drtiosat::underflow_timestamp_counter_read() as i64;
|
|
|
|
}
|
|
|
|
error!("write underflow, channel={}, timestamp={}, counter={}, slack={}",
|
|
|
|
channel, timestamp_event, timestamp_counter, timestamp_event-timestamp_counter);
|
|
|
|
}
|
|
|
|
if errors & 16 != 0 {
|
|
|
|
error!("write overflow");
|
|
|
|
}
|
|
|
|
unsafe {
|
|
|
|
csr::drtiosat::protocol_error_write(errors);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[cfg(has_rtio_crg)]
|
2021-07-23 19:15:07 +08:00
|
|
|
fn init_rtio_crg(timer: GlobalTimer) {
|
2021-07-21 15:25:37 +08:00
|
|
|
unsafe {
|
|
|
|
csr::rtio_crg::pll_reset_write(0);
|
|
|
|
}
|
2021-07-23 19:15:07 +08:00
|
|
|
timer.delay_us(150);
|
2021-07-21 15:25:37 +08:00
|
|
|
let locked = unsafe { csr::rtio_crg::pll_locked_read() != 0 };
|
|
|
|
if !locked {
|
|
|
|
error!("RTIO clock failed");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(not(has_rtio_crg))]
|
2021-07-23 19:15:07 +08:00
|
|
|
fn init_rtio_crg(timer: GlobalTimer) { }
|
2021-07-21 15:25:37 +08:00
|
|
|
|
2021-07-23 19:15:07 +08:00
|
|
|
fn hardware_tick(ts: &mut u64, timer: GlobalTimer) {
|
|
|
|
let now = timer.get_time();
|
2021-07-21 15:25:37 +08:00
|
|
|
if now > *ts {
|
|
|
|
*ts = now + 200;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(all(has_si5324, rtio_frequency = "150.0"))]
|
|
|
|
const SI5324_SETTINGS: si5324::FrequencySettings
|
|
|
|
= si5324::FrequencySettings {
|
|
|
|
n1_hs : 6,
|
|
|
|
nc1_ls : 6,
|
|
|
|
n2_hs : 10,
|
|
|
|
n2_ls : 270,
|
|
|
|
n31 : 75,
|
|
|
|
n32 : 75,
|
|
|
|
bwsel : 4,
|
|
|
|
crystal_ref: true
|
|
|
|
};
|
|
|
|
|
|
|
|
#[cfg(all(has_si5324, rtio_frequency = "125.0"))]
|
|
|
|
const SI5324_SETTINGS: si5324::FrequencySettings
|
|
|
|
= si5324::FrequencySettings {
|
|
|
|
n1_hs : 5,
|
|
|
|
nc1_ls : 8,
|
|
|
|
n2_hs : 7,
|
|
|
|
n2_ls : 360,
|
|
|
|
n31 : 63,
|
|
|
|
n32 : 63,
|
|
|
|
bwsel : 4,
|
|
|
|
crystal_ref: true
|
|
|
|
};
|
|
|
|
|
|
|
|
#[no_mangle]
|
|
|
|
pub extern fn main() -> i32 {
|
2021-07-23 17:00:48 +08:00
|
|
|
let mut timer = GlobalTimer::start();
|
2021-07-21 15:25:37 +08:00
|
|
|
|
2021-07-22 17:24:43 +08:00
|
|
|
let buffer_logger = unsafe {
|
|
|
|
logger::BufferLogger::new(&mut LOG_BUFFER[..])
|
|
|
|
};
|
|
|
|
buffer_logger.set_uart_log_level(log::LevelFilter::Info);
|
|
|
|
buffer_logger.register();
|
|
|
|
|
2021-07-21 15:25:37 +08:00
|
|
|
info!("ARTIQ satellite manager starting...");
|
|
|
|
info!("software ident {}", csr::CONFIG_IDENTIFIER_STR);
|
2021-07-23 20:14:07 +08:00
|
|
|
info!("gateware ident {}", identifier_read(&mut [0; 64]));
|
2021-07-21 15:25:37 +08:00
|
|
|
|
2021-07-23 20:45:48 +08:00
|
|
|
let mut i2c = I2c::i2c0();
|
|
|
|
i2c.init().expect("I2C initialization failed");
|
|
|
|
|
2021-07-23 17:00:48 +08:00
|
|
|
//see if below is applicable (probably not - not kasli)
|
2021-07-21 15:25:37 +08:00
|
|
|
#[cfg(all(soc_platform = "kasli", hw_rev = "v2.0"))]
|
|
|
|
let (mut io_expander0, mut io_expander1);
|
|
|
|
#[cfg(all(soc_platform = "kasli", hw_rev = "v2.0"))]
|
|
|
|
{
|
|
|
|
io_expander0 = board_misoc::io_expander::IoExpander::new(0);
|
|
|
|
io_expander1 = board_misoc::io_expander::IoExpander::new(1);
|
|
|
|
io_expander0.init().expect("I2C I/O expander #0 initialization failed");
|
|
|
|
io_expander1.init().expect("I2C I/O expander #1 initialization failed");
|
|
|
|
|
|
|
|
// Actively drive TX_DISABLE to false on SFP0..3
|
|
|
|
io_expander0.set_oe(0, 1 << 1).unwrap();
|
|
|
|
io_expander0.set_oe(1, 1 << 1).unwrap();
|
|
|
|
io_expander1.set_oe(0, 1 << 1).unwrap();
|
|
|
|
io_expander1.set_oe(1, 1 << 1).unwrap();
|
|
|
|
io_expander0.set(0, 1, false);
|
|
|
|
io_expander0.set(1, 1, false);
|
|
|
|
io_expander1.set(0, 1, false);
|
|
|
|
io_expander1.set(1, 1, false);
|
|
|
|
io_expander0.service().unwrap();
|
|
|
|
io_expander1.service().unwrap();
|
|
|
|
}
|
|
|
|
|
2021-07-23 17:00:48 +08:00
|
|
|
//this part was commented in runtime
|
2021-07-21 15:25:37 +08:00
|
|
|
#[cfg(has_si5324)]
|
|
|
|
si5324::setup(&SI5324_SETTINGS, si5324::Input::Ckin1).expect("cannot initialize Si5324");
|
|
|
|
|
|
|
|
unsafe {
|
|
|
|
csr::drtio_transceiver::stable_clkin_write(1);
|
|
|
|
}
|
2021-07-23 17:00:48 +08:00
|
|
|
timer.delay_us(1500); // wait for CPLL/QPLL lock
|
|
|
|
|
|
|
|
// #[cfg(not(has_jdcg))]
|
2021-07-21 15:25:37 +08:00
|
|
|
unsafe {
|
|
|
|
csr::drtio_transceiver::txenable_write(0xffffffffu32 as _);
|
|
|
|
}
|
2021-07-23 20:45:48 +08:00
|
|
|
init_rtio_crg(timer);
|
2021-07-21 15:25:37 +08:00
|
|
|
|
|
|
|
#[cfg(has_drtio_routing)]
|
|
|
|
let mut repeaters = [repeater::Repeater::default(); csr::DRTIOREP.len()];
|
|
|
|
#[cfg(not(has_drtio_routing))]
|
|
|
|
let mut repeaters = [repeater::Repeater::default(); 0];
|
|
|
|
for i in 0..repeaters.len() {
|
|
|
|
repeaters[i] = repeater::Repeater::new(i as u8);
|
|
|
|
}
|
|
|
|
let mut routing_table = drtio_routing::RoutingTable::default_empty();
|
|
|
|
let mut rank = 1;
|
|
|
|
|
|
|
|
let mut hardware_tick_ts = 0;
|
|
|
|
|
|
|
|
loop {
|
|
|
|
while !drtiosat_link_rx_up() {
|
|
|
|
drtiosat_process_errors();
|
|
|
|
for mut rep in repeaters.iter_mut() {
|
2021-07-23 19:15:07 +08:00
|
|
|
rep.service(&routing_table, rank, timer);
|
2021-07-21 15:25:37 +08:00
|
|
|
}
|
|
|
|
#[cfg(all(soc_platform = "kasli", hw_rev = "v2.0"))]
|
|
|
|
{
|
|
|
|
io_expander0.service().expect("I2C I/O expander #0 service failed");
|
|
|
|
io_expander1.service().expect("I2C I/O expander #1 service failed");
|
|
|
|
}
|
|
|
|
hardware_tick(&mut hardware_tick_ts);
|
|
|
|
}
|
|
|
|
|
|
|
|
info!("uplink is up, switching to recovered clock");
|
|
|
|
#[cfg(has_si5324)]
|
|
|
|
{
|
|
|
|
si5324::siphaser::select_recovered_clock(true).expect("failed to switch clocks");
|
|
|
|
si5324::siphaser::calibrate_skew().expect("failed to calibrate skew");
|
|
|
|
}
|
|
|
|
|
|
|
|
drtioaux::reset(0);
|
|
|
|
drtiosat_reset(false);
|
|
|
|
drtiosat_reset_phy(false);
|
|
|
|
|
|
|
|
while drtiosat_link_rx_up() {
|
|
|
|
drtiosat_process_errors();
|
2021-07-23 20:45:48 +08:00
|
|
|
process_aux_packets(&mut repeaters, &mut routing_table, &mut rank, timer, i2c);
|
2021-07-21 15:25:37 +08:00
|
|
|
for mut rep in repeaters.iter_mut() {
|
2021-07-23 20:45:48 +08:00
|
|
|
rep.service(&routing_table, rank, timer);
|
2021-07-21 15:25:37 +08:00
|
|
|
}
|
|
|
|
#[cfg(all(soc_platform = "kasli", hw_rev = "v2.0"))]
|
|
|
|
{
|
|
|
|
io_expander0.service().expect("I2C I/O expander #0 service failed");
|
|
|
|
io_expander1.service().expect("I2C I/O expander #1 service failed");
|
|
|
|
}
|
2021-07-23 19:15:07 +08:00
|
|
|
hardware_tick(&mut hardware_tick_ts, timer);
|
2021-07-21 15:25:37 +08:00
|
|
|
if drtiosat_tsc_loaded() {
|
|
|
|
info!("TSC loaded from uplink");
|
|
|
|
for rep in repeaters.iter() {
|
2021-07-23 19:15:07 +08:00
|
|
|
if let Err(e) = rep.sync_tsc(timer) {
|
2021-07-21 15:25:37 +08:00
|
|
|
error!("failed to sync TSC ({})", e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if let Err(e) = drtioaux::send(0, &drtioaux::Packet::TSCAck) {
|
|
|
|
error!("aux packet error: {}", e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
drtiosat_reset_phy(true);
|
|
|
|
drtiosat_reset(true);
|
|
|
|
drtiosat_tsc_loaded();
|
|
|
|
info!("uplink is down, switching to local oscillator clock");
|
|
|
|
#[cfg(has_si5324)]
|
|
|
|
si5324::siphaser::select_recovered_clock(false).expect("failed to switch clocks");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[no_mangle]
|
|
|
|
pub extern fn exception(vect: u32, _regs: *const u32, pc: u32, ea: u32) {
|
|
|
|
|
|
|
|
fn hexdump(addr: u32) {
|
|
|
|
let addr = (addr - addr % 4) as *const u32;
|
|
|
|
let mut ptr = addr;
|
|
|
|
println!("@ {:08p}", ptr);
|
|
|
|
for _ in 0..4 {
|
|
|
|
print!("+{:04x}: ", ptr as usize - addr as usize);
|
|
|
|
print!("{:08x} ", unsafe { *ptr }); ptr = ptr.wrapping_offset(1);
|
|
|
|
print!("{:08x} ", unsafe { *ptr }); ptr = ptr.wrapping_offset(1);
|
|
|
|
print!("{:08x} ", unsafe { *ptr }); ptr = ptr.wrapping_offset(1);
|
|
|
|
print!("{:08x}\n", unsafe { *ptr }); ptr = ptr.wrapping_offset(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
hexdump(pc);
|
|
|
|
hexdump(ea);
|
2021-07-23 20:11:05 +08:00
|
|
|
panic!("exception at PC 0x{:x}, EA 0x{:x}", pc, ea)
|
2021-07-21 15:25:37 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
#[no_mangle]
|
|
|
|
pub extern fn abort() {
|
|
|
|
println!("aborted");
|
|
|
|
loop {}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[no_mangle] // https://github.com/rust-lang/rust/issues/{38281,51647}
|
|
|
|
#[panic_implementation]
|
|
|
|
pub fn panic_fmt(info: &core::panic::PanicInfo) -> ! {
|
|
|
|
#[cfg(has_error_led)]
|
|
|
|
unsafe {
|
|
|
|
csr::error_led::out_write(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if let Some(location) = info.location() {
|
|
|
|
print!("panic at {}:{}:{}", location.file(), location.line(), location.column());
|
|
|
|
} else {
|
|
|
|
print!("panic at unknown location");
|
|
|
|
}
|
|
|
|
if let Some(message) = info.message() {
|
|
|
|
println!(": {}", message);
|
|
|
|
} else {
|
|
|
|
println!("");
|
|
|
|
}
|
|
|
|
loop {}
|
|
|
|
}
|