firmware: create and apply rustfmt policy

Co-authored-by: Egor Savkin <es@m-labs.hk>
Co-committed-by: Egor Savkin <es@m-labs.hk>
master
Egor Savkin 2023-02-22 11:02:43 +08:00 committed by sb10q
parent dce37a52aa
commit a519d24074
48 changed files with 2452 additions and 1728 deletions

View File

@ -253,6 +253,23 @@
''; '';
}; };
fmt-check = pkgs.stdenv.mkDerivation {
name = "fmt-check";
nativeBuildInputs = [
rustPlatform.rust.cargo
];
phases = [ "buildPhase" ];
buildPhase =
''
cd ${self}/src
cargo fmt -- --check
touch $out
'';
};
# for hitl-tests # for hitl-tests
zc706-nist_qc2 = (build { target = "zc706"; variant = "nist_qc2"; }); zc706-nist_qc2 = (build { target = "zc706"; variant = "nist_qc2"; });
zc706-hitl-tests = pkgs.stdenv.mkDerivation { zc706-hitl-tests = pkgs.stdenv.mkDerivation {
@ -341,7 +358,7 @@
(build { target = "kasli_soc"; variant = "master"; json = ./kasli-soc-master.json; }) // (build { target = "kasli_soc"; variant = "master"; json = ./kasli-soc-master.json; }) //
(build { target = "kasli_soc"; variant = "satellite"; json = ./kasli-soc-satellite.json; }); (build { target = "kasli_soc"; variant = "satellite"; json = ./kasli-soc-satellite.json; });
hydraJobs = packages.x86_64-linux // { inherit zc706-hitl-tests; inherit gateware-sim; }; hydraJobs = packages.x86_64-linux // { inherit zc706-hitl-tests; inherit gateware-sim; inherit fmt-check; };
devShell.x86_64-linux = pkgs.mkShell { devShell.x86_64-linux = pkgs.mkShell {
name = "artiq-zynq-dev-shell"; name = "artiq-zynq-dev-shell";

View File

@ -1,9 +1,10 @@
use libconfig::Config;
#[cfg(has_drtio_routing)]
use crate::pl::csr;
use core::fmt; use core::fmt;
use log::{warn, info}; use libconfig::Config;
use log::{info, warn};
#[cfg(has_drtio_routing)]
use crate::pl::csr;
#[cfg(has_drtio_routing)] #[cfg(has_drtio_routing)]
pub const DEST_COUNT: usize = 256; pub const DEST_COUNT: usize = 256;
@ -18,7 +19,7 @@ impl RoutingTable {
// default routing table is for star topology with no repeaters // default routing table is for star topology with no repeaters
pub fn default_master(default_n_links: usize) -> RoutingTable { pub fn default_master(default_n_links: usize) -> RoutingTable {
let mut ret = RoutingTable([[INVALID_HOP; MAX_HOPS]; DEST_COUNT]); let mut ret = RoutingTable([[INVALID_HOP; MAX_HOPS]; DEST_COUNT]);
let n_entries = default_n_links + 1; // include local RTIO let n_entries = default_n_links + 1; // include local RTIO
for i in 0..n_entries { for i in 0..n_entries {
ret.0[i][0] = i as u8; ret.0[i][0] = i as u8;
} }
@ -58,10 +59,10 @@ impl fmt::Display for RoutingTable {
pub fn config_routing_table(default_n_links: usize, cfg: &Config) -> RoutingTable { pub fn config_routing_table(default_n_links: usize, cfg: &Config) -> RoutingTable {
let mut ret = RoutingTable::default_master(default_n_links); let mut ret = RoutingTable::default_master(default_n_links);
if let Ok(data) = cfg.read("routing_table") { if let Ok(data) = cfg.read("routing_table") {
if data.len() == DEST_COUNT*MAX_HOPS { if data.len() == DEST_COUNT * MAX_HOPS {
for i in 0..DEST_COUNT { for i in 0..DEST_COUNT {
for j in 0..MAX_HOPS { for j in 0..MAX_HOPS {
ret.0[i][j] = data[i*MAX_HOPS+j]; ret.0[i][j] = data[i * MAX_HOPS + j];
} }
} }
} else { } else {

View File

@ -1,14 +1,12 @@
use core_io::{Error as IoError, ErrorKind as IoErrorKind};
use crc; use crc;
use io::{proto::{ProtoRead, ProtoWrite},
use core_io::{ErrorKind as IoErrorKind, Error as IoError}; Cursor};
use io::{proto::ProtoRead, proto::ProtoWrite, Cursor}; use libboard_zynq::{time::Milliseconds, timer::GlobalTimer};
use libboard_zynq::{timer::GlobalTimer, time::Milliseconds};
use libcortex_a9::asm::dmb; use libcortex_a9::asm::dmb;
use crate::mem::mem::DRTIOAUX_MEM;
use crate::pl::csr::DRTIOAUX;
use crate::drtioaux_proto::Error as ProtocolError;
pub use crate::drtioaux_proto::Packet; pub use crate::drtioaux_proto::Packet;
use crate::{drtioaux_proto::Error as ProtocolError, mem::mem::DRTIOAUX_MEM, pl::csr::DRTIOAUX};
#[derive(Debug)] #[derive(Debug)]
pub enum Error { pub enum Error {
@ -21,7 +19,7 @@ pub enum Error {
RoutingError, RoutingError,
Protocol(ProtocolError) Protocol(ProtocolError),
} }
impl From<ProtocolError> for Error { impl From<ProtocolError> for Error {
@ -63,7 +61,7 @@ pub fn copy_work_buffer(src: *mut u32, dst: *mut u32, len: isize) {
// and AXI burst reads/writes are not implemented yet in gateware // and AXI burst reads/writes are not implemented yet in gateware
// thus the need for a work buffer for transmitting and copying it over // thus the need for a work buffer for transmitting and copying it over
unsafe { unsafe {
for i in 0..(len/4) { for i in 0..(len / 4) {
*dst.offset(i) = *src.offset(i); *dst.offset(i) = *src.offset(i);
//data memory barrier to prevent bursts //data memory barrier to prevent bursts
dmb(); dmb();
@ -72,8 +70,7 @@ pub fn copy_work_buffer(src: *mut u32, dst: *mut u32, len: isize) {
} }
fn receive<F, T>(linkno: u8, f: F) -> Result<Option<T>, Error> fn receive<F, T>(linkno: u8, f: F) -> Result<Option<T>, Error>
where F: FnOnce(&[u8]) -> Result<T, Error> where F: FnOnce(&[u8]) -> Result<T, Error> {
{
let linkidx = linkno as usize; let linkidx = linkno as usize;
unsafe { unsafe {
if (DRTIOAUX[linkidx].aux_rx_present_read)() == 1 { if (DRTIOAUX[linkidx].aux_rx_present_read)() == 1 {
@ -93,12 +90,12 @@ fn receive<F, T>(linkno: u8, f: F) -> Result<Option<T>, Error>
pub fn recv(linkno: u8) -> Result<Option<Packet>, Error> { pub fn recv(linkno: u8) -> Result<Option<Packet>, Error> {
if has_rx_error(linkno) { if has_rx_error(linkno) {
return Err(Error::GatewareError) return Err(Error::GatewareError);
} }
receive(linkno, |buffer| { receive(linkno, |buffer| {
if buffer.len() < 8 { if buffer.len() < 8 {
return Err(IoError::new(IoErrorKind::UnexpectedEof, "Unexpected end").into()) return Err(IoError::new(IoErrorKind::UnexpectedEof, "Unexpected end").into());
} }
let mut reader = Cursor::new(buffer); let mut reader = Cursor::new(buffer);
@ -107,7 +104,7 @@ pub fn recv(linkno: u8) -> Result<Option<Packet>, Error> {
let checksum = crc::crc32::checksum_ieee(&reader.get_ref()[0..checksum_at]); let checksum = crc::crc32::checksum_ieee(&reader.get_ref()[0..checksum_at]);
reader.set_position(checksum_at); reader.set_position(checksum_at);
if reader.read_u32()? != checksum { if reader.read_u32()? != checksum {
return Err(Error::CorruptedPacket) return Err(Error::CorruptedPacket);
} }
reader.set_position(0); reader.set_position(0);
@ -115,9 +112,7 @@ pub fn recv(linkno: u8) -> Result<Option<Packet>, Error> {
}) })
} }
pub fn recv_timeout(linkno: u8, timeout_ms: Option<u64>, pub fn recv_timeout(linkno: u8, timeout_ms: Option<u64>, timer: GlobalTimer) -> Result<Packet, Error> {
timer: GlobalTimer) -> Result<Packet, Error>
{
let timeout_ms = Milliseconds(timeout_ms.unwrap_or(10)); let timeout_ms = Milliseconds(timeout_ms.unwrap_or(10));
let limit = timer.get_time() + timeout_ms; let limit = timer.get_time() + timeout_ms;
while timer.get_time() < limit { while timer.get_time() < limit {
@ -130,15 +125,14 @@ pub fn recv_timeout(linkno: u8, timeout_ms: Option<u64>,
} }
fn transmit<F>(linkno: u8, f: F) -> Result<(), Error> fn transmit<F>(linkno: u8, f: F) -> Result<(), Error>
where F: FnOnce(&mut [u8]) -> Result<usize, Error> where F: FnOnce(&mut [u8]) -> Result<usize, Error> {
{
let linkno = linkno as usize; let linkno = linkno as usize;
unsafe { unsafe {
while (DRTIOAUX[linkno].aux_tx_read)() != 0 {} while (DRTIOAUX[linkno].aux_tx_read)() != 0 {}
let ptr = DRTIOAUX_MEM[linkno].base as *mut u32; let ptr = DRTIOAUX_MEM[linkno].base as *mut u32;
let len = DRTIOAUX_MEM[linkno].size / 2; let len = DRTIOAUX_MEM[linkno].size / 2;
// work buffer, works with unaligned mem access // work buffer, works with unaligned mem access
let mut buf: [u8; 1024] = [0; 1024]; let mut buf: [u8; 1024] = [0; 1024];
let len = f(&mut buf[0..len])?; let len = f(&mut buf[0..len])?;
copy_work_buffer(buf.as_mut_ptr() as *mut u32, ptr, len as isize); copy_work_buffer(buf.as_mut_ptr() as *mut u32, ptr, len as isize);
(DRTIOAUX[linkno].aux_tx_length_write)(len as u16); (DRTIOAUX[linkno].aux_tx_length_write)(len as u16);
@ -152,7 +146,7 @@ pub fn send(linkno: u8, packet: &Packet) -> Result<(), Error> {
let mut writer = Cursor::new(buffer); let mut writer = Cursor::new(buffer);
packet.write_to(&mut writer)?; packet.write_to(&mut writer)?;
// Pad till offset 4, insert checksum there // Pad till offset 4, insert checksum there
let padding = (12 - (writer.position() % 8)) % 8; let padding = (12 - (writer.position() % 8)) % 8;
for _ in 0..padding { for _ in 0..padding {

View File

@ -1,18 +1,16 @@
use core_io::{Error as IoError, ErrorKind as IoErrorKind};
use crc; use crc;
use io::{proto::{ProtoRead, ProtoWrite},
use core_io::{ErrorKind as IoErrorKind, Error as IoError}; Cursor};
use void::Void; use libasync::{block_async, task};
use libboard_zynq::{time::Milliseconds, timer::GlobalTimer};
use nb; use nb;
use void::Void;
use libboard_zynq::{timer::GlobalTimer, time::Milliseconds};
use libasync::{task, block_async};
use io::{proto::ProtoRead, proto::ProtoWrite, Cursor};
use crate::mem::mem::DRTIOAUX_MEM;
use crate::pl::csr::DRTIOAUX;
use crate::drtioaux::{Error, has_rx_error, copy_work_buffer};
pub use crate::drtioaux_proto::Packet; pub use crate::drtioaux_proto::Packet;
use crate::{drtioaux::{copy_work_buffer, has_rx_error, Error},
mem::mem::DRTIOAUX_MEM,
pl::csr::DRTIOAUX};
pub async fn reset(linkno: u8) { pub async fn reset(linkno: u8) {
let linkno = linkno as usize; let linkno = linkno as usize;
@ -29,16 +27,14 @@ fn tx_ready(linkno: usize) -> nb::Result<(), Void> {
unsafe { unsafe {
if (DRTIOAUX[linkno].aux_tx_read)() != 0 { if (DRTIOAUX[linkno].aux_tx_read)() != 0 {
Err(nb::Error::WouldBlock) Err(nb::Error::WouldBlock)
} } else {
else {
Ok(()) Ok(())
} }
} }
} }
async fn receive<F, T>(linkno: u8, f: F) -> Result<Option<T>, Error> async fn receive<F, T>(linkno: u8, f: F) -> Result<Option<T>, Error>
where F: FnOnce(&[u8]) -> Result<T, Error> where F: FnOnce(&[u8]) -> Result<T, Error> {
{
let linkidx = linkno as usize; let linkidx = linkno as usize;
unsafe { unsafe {
if (DRTIOAUX[linkidx].aux_rx_present_read)() == 1 { if (DRTIOAUX[linkidx].aux_rx_present_read)() == 1 {
@ -58,12 +54,12 @@ async fn receive<F, T>(linkno: u8, f: F) -> Result<Option<T>, Error>
pub async fn recv(linkno: u8) -> Result<Option<Packet>, Error> { pub async fn recv(linkno: u8) -> Result<Option<Packet>, Error> {
if has_rx_error(linkno) { if has_rx_error(linkno) {
return Err(Error::GatewareError) return Err(Error::GatewareError);
} }
receive(linkno, |buffer| { receive(linkno, |buffer| {
if buffer.len() < 8 { if buffer.len() < 8 {
return Err(IoError::new(IoErrorKind::UnexpectedEof, "Unexpected end").into()) return Err(IoError::new(IoErrorKind::UnexpectedEof, "Unexpected end").into());
} }
let mut reader = Cursor::new(buffer); let mut reader = Cursor::new(buffer);
@ -72,17 +68,16 @@ pub async fn recv(linkno: u8) -> Result<Option<Packet>, Error> {
let checksum = crc::crc32::checksum_ieee(&reader.get_ref()[0..checksum_at]); let checksum = crc::crc32::checksum_ieee(&reader.get_ref()[0..checksum_at]);
reader.set_position(checksum_at); reader.set_position(checksum_at);
if reader.read_u32()? != checksum { if reader.read_u32()? != checksum {
return Err(Error::CorruptedPacket) return Err(Error::CorruptedPacket);
} }
reader.set_position(0); reader.set_position(0);
Ok(Packet::read_from(&mut reader)?) Ok(Packet::read_from(&mut reader)?)
}).await })
.await
} }
pub async fn recv_timeout(linkno: u8, timeout_ms: Option<u64>, pub async fn recv_timeout(linkno: u8, timeout_ms: Option<u64>, timer: GlobalTimer) -> Result<Packet, Error> {
timer: GlobalTimer) -> Result<Packet, Error>
{
let timeout_ms = Milliseconds(timeout_ms.unwrap_or(10)); let timeout_ms = Milliseconds(timeout_ms.unwrap_or(10));
let limit = timer.get_time() + timeout_ms; let limit = timer.get_time() + timeout_ms;
let mut would_block = false; let mut would_block = false;
@ -93,7 +88,9 @@ pub async fn recv_timeout(linkno: u8, timeout_ms: Option<u64>,
task::r#yield().await; task::r#yield().await;
} }
match recv(linkno).await? { match recv(linkno).await? {
None => { would_block = true; }, None => {
would_block = true;
}
Some(packet) => return Ok(packet), Some(packet) => return Ok(packet),
} }
} }
@ -101,15 +98,14 @@ pub async fn recv_timeout(linkno: u8, timeout_ms: Option<u64>,
} }
async fn transmit<F>(linkno: u8, f: F) -> Result<(), Error> async fn transmit<F>(linkno: u8, f: F) -> Result<(), Error>
where F: FnOnce(&mut [u8]) -> Result<usize, Error> where F: FnOnce(&mut [u8]) -> Result<usize, Error> {
{
let linkno = linkno as usize; let linkno = linkno as usize;
unsafe { unsafe {
let _ = block_async!(tx_ready(linkno)).await; let _ = block_async!(tx_ready(linkno)).await;
let ptr = DRTIOAUX_MEM[linkno].base as *mut u32; let ptr = DRTIOAUX_MEM[linkno].base as *mut u32;
let len = DRTIOAUX_MEM[linkno].size / 2; let len = DRTIOAUX_MEM[linkno].size / 2;
// work buffer, works with unaligned mem access // work buffer, works with unaligned mem access
let mut buf: [u8; 1024] = [0; 1024]; let mut buf: [u8; 1024] = [0; 1024];
let len = f(&mut buf[0..len])?; let len = f(&mut buf[0..len])?;
copy_work_buffer(buf.as_mut_ptr() as *mut u32, ptr, len as isize); copy_work_buffer(buf.as_mut_ptr() as *mut u32, ptr, len as isize);
(DRTIOAUX[linkno].aux_tx_length_write)(len as u16); (DRTIOAUX[linkno].aux_tx_length_write)(len as u16);
@ -123,7 +119,7 @@ pub async fn send(linkno: u8, packet: &Packet) -> Result<(), Error> {
let mut writer = Cursor::new(buffer); let mut writer = Cursor::new(buffer);
packet.write_to(&mut writer)?; packet.write_to(&mut writer)?;
// Pad till offset 4, insert checksum there // Pad till offset 4, insert checksum there
let padding = (12 - (writer.position() % 8)) % 8; let padding = (12 - (writer.position() % 8)) % 8;
for _ in 0..padding { for _ in 0..padding {
@ -134,5 +130,6 @@ pub async fn send(linkno: u8, packet: &Packet) -> Result<(), Error> {
writer.write_u32(checksum)?; writer.write_u32(checksum)?;
Ok(writer.position()) Ok(writer.position())
}).await })
.await
} }

View File

@ -1,11 +1,10 @@
use core_io::{Write, Read, Error as IoError}; use core_io::{Error as IoError, Read, Write};
use io::proto::{ProtoRead, ProtoWrite};
use io::proto::{ProtoWrite, ProtoRead};
#[derive(Debug)] #[derive(Debug)]
pub enum Error { pub enum Error {
UnknownPacket(u8), UnknownPacket(u8),
Io(IoError) Io(IoError),
} }
impl From<IoError> for Error { impl From<IoError> for Error {
@ -22,45 +21,122 @@ pub enum Packet {
ResetAck, ResetAck,
TSCAck, TSCAck,
DestinationStatusRequest { destination: u8 }, DestinationStatusRequest {
destination: u8,
},
DestinationDownReply, DestinationDownReply,
DestinationOkReply, DestinationOkReply,
DestinationSequenceErrorReply { channel: u16 }, DestinationSequenceErrorReply {
DestinationCollisionReply { channel: u16 }, channel: u16,
DestinationBusyReply { channel: u16 }, },
DestinationCollisionReply {
channel: u16,
},
DestinationBusyReply {
channel: u16,
},
RoutingSetPath { destination: u8, hops: [u8; 32] }, RoutingSetPath {
RoutingSetRank { rank: u8 }, destination: u8,
hops: [u8; 32],
},
RoutingSetRank {
rank: u8,
},
RoutingAck, RoutingAck,
MonitorRequest { destination: u8, channel: u16, probe: u8 }, MonitorRequest {
MonitorReply { value: u64 }, destination: u8,
InjectionRequest { destination: u8, channel: u16, overrd: u8, value: u8 }, channel: u16,
InjectionStatusRequest { destination: u8, channel: u16, overrd: u8 }, probe: u8,
InjectionStatusReply { value: u8 }, },
MonitorReply {
value: u64,
},
InjectionRequest {
destination: u8,
channel: u16,
overrd: u8,
value: u8,
},
InjectionStatusRequest {
destination: u8,
channel: u16,
overrd: u8,
},
InjectionStatusReply {
value: u8,
},
I2cStartRequest { destination: u8, busno: u8 }, I2cStartRequest {
I2cRestartRequest { destination: u8, busno: u8 }, destination: u8,
I2cStopRequest { destination: u8, busno: u8 }, busno: u8,
I2cWriteRequest { destination: u8, busno: u8, data: u8 }, },
I2cWriteReply { succeeded: bool, ack: bool }, I2cRestartRequest {
I2cReadRequest { destination: u8, busno: u8, ack: bool }, destination: u8,
I2cReadReply { succeeded: bool, data: u8 }, busno: u8,
I2cBasicReply { succeeded: bool }, },
I2cSwitchSelectRequest { destination: u8, busno: u8, address: u8, mask: u8 }, I2cStopRequest {
destination: u8,
SpiSetConfigRequest { destination: u8, busno: u8, flags: u8, length: u8, div: u8, cs: u8 }, busno: u8,
SpiWriteRequest { destination: u8, busno: u8, data: u32 }, },
SpiReadRequest { destination: u8, busno: u8 }, I2cWriteRequest {
SpiReadReply { succeeded: bool, data: u32 }, destination: u8,
SpiBasicReply { succeeded: bool }, busno: u8,
data: u8,
},
I2cWriteReply {
succeeded: bool,
ack: bool,
},
I2cReadRequest {
destination: u8,
busno: u8,
ack: bool,
},
I2cReadReply {
succeeded: bool,
data: u8,
},
I2cBasicReply {
succeeded: bool,
},
I2cSwitchSelectRequest {
destination: u8,
busno: u8,
address: u8,
mask: u8,
},
SpiSetConfigRequest {
destination: u8,
busno: u8,
flags: u8,
length: u8,
div: u8,
cs: u8,
},
SpiWriteRequest {
destination: u8,
busno: u8,
data: u32,
},
SpiReadRequest {
destination: u8,
busno: u8,
},
SpiReadReply {
succeeded: bool,
data: u32,
},
SpiBasicReply {
succeeded: bool,
},
} }
impl Packet { impl Packet {
pub fn read_from<R>(reader: &mut R) -> Result<Self, Error> pub fn read_from<R>(reader: &mut R) -> Result<Self, Error>
where R: Read + ?Sized where R: Read + ?Sized {
{
Ok(match reader.read_u8()? { Ok(match reader.read_u8()? {
0x00 => Packet::EchoRequest, 0x00 => Packet::EchoRequest,
0x01 => Packet::EchoReply, 0x01 => Packet::EchoReply,
@ -69,18 +145,18 @@ impl Packet {
0x04 => Packet::TSCAck, 0x04 => Packet::TSCAck,
0x20 => Packet::DestinationStatusRequest { 0x20 => Packet::DestinationStatusRequest {
destination: reader.read_u8()? destination: reader.read_u8()?,
}, },
0x21 => Packet::DestinationDownReply, 0x21 => Packet::DestinationDownReply,
0x22 => Packet::DestinationOkReply, 0x22 => Packet::DestinationOkReply,
0x23 => Packet::DestinationSequenceErrorReply { 0x23 => Packet::DestinationSequenceErrorReply {
channel: reader.read_u16()? channel: reader.read_u16()?,
}, },
0x24 => Packet::DestinationCollisionReply { 0x24 => Packet::DestinationCollisionReply {
channel: reader.read_u16()? channel: reader.read_u16()?,
}, },
0x25 => Packet::DestinationBusyReply { 0x25 => Packet::DestinationBusyReply {
channel: reader.read_u16()? channel: reader.read_u16()?,
}, },
0x30 => { 0x30 => {
@ -89,75 +165,75 @@ impl Packet {
reader.read_exact(&mut hops)?; reader.read_exact(&mut hops)?;
Packet::RoutingSetPath { Packet::RoutingSetPath {
destination: destination, destination: destination,
hops: hops hops: hops,
} }
}, }
0x31 => Packet::RoutingSetRank { 0x31 => Packet::RoutingSetRank {
rank: reader.read_u8()? rank: reader.read_u8()?,
}, },
0x32 => Packet::RoutingAck, 0x32 => Packet::RoutingAck,
0x40 => Packet::MonitorRequest { 0x40 => Packet::MonitorRequest {
destination: reader.read_u8()?, destination: reader.read_u8()?,
channel: reader.read_u16()?, channel: reader.read_u16()?,
probe: reader.read_u8()? probe: reader.read_u8()?,
}, },
0x41 => Packet::MonitorReply { 0x41 => Packet::MonitorReply {
value: reader.read_u64()? value: reader.read_u64()?,
}, },
0x50 => Packet::InjectionRequest { 0x50 => Packet::InjectionRequest {
destination: reader.read_u8()?, destination: reader.read_u8()?,
channel: reader.read_u16()?, channel: reader.read_u16()?,
overrd: reader.read_u8()?, overrd: reader.read_u8()?,
value: reader.read_u8()? value: reader.read_u8()?,
}, },
0x51 => Packet::InjectionStatusRequest { 0x51 => Packet::InjectionStatusRequest {
destination: reader.read_u8()?, destination: reader.read_u8()?,
channel: reader.read_u16()?, channel: reader.read_u16()?,
overrd: reader.read_u8()? overrd: reader.read_u8()?,
}, },
0x52 => Packet::InjectionStatusReply { 0x52 => Packet::InjectionStatusReply {
value: reader.read_u8()? value: reader.read_u8()?,
}, },
0x80 => Packet::I2cStartRequest { 0x80 => Packet::I2cStartRequest {
destination: reader.read_u8()?, destination: reader.read_u8()?,
busno: reader.read_u8()? busno: reader.read_u8()?,
}, },
0x81 => Packet::I2cRestartRequest { 0x81 => Packet::I2cRestartRequest {
destination: reader.read_u8()?, destination: reader.read_u8()?,
busno: reader.read_u8()? busno: reader.read_u8()?,
}, },
0x82 => Packet::I2cStopRequest { 0x82 => Packet::I2cStopRequest {
destination: reader.read_u8()?, destination: reader.read_u8()?,
busno: reader.read_u8()? busno: reader.read_u8()?,
}, },
0x83 => Packet::I2cWriteRequest { 0x83 => Packet::I2cWriteRequest {
destination: reader.read_u8()?, destination: reader.read_u8()?,
busno: reader.read_u8()?, busno: reader.read_u8()?,
data: reader.read_u8()? data: reader.read_u8()?,
}, },
0x84 => Packet::I2cWriteReply { 0x84 => Packet::I2cWriteReply {
succeeded: reader.read_bool()?, succeeded: reader.read_bool()?,
ack: reader.read_bool()? ack: reader.read_bool()?,
}, },
0x85 => Packet::I2cReadRequest { 0x85 => Packet::I2cReadRequest {
destination: reader.read_u8()?, destination: reader.read_u8()?,
busno: reader.read_u8()?, busno: reader.read_u8()?,
ack: reader.read_bool()? ack: reader.read_bool()?,
}, },
0x86 => Packet::I2cReadReply { 0x86 => Packet::I2cReadReply {
succeeded: reader.read_bool()?, succeeded: reader.read_bool()?,
data: reader.read_u8()? data: reader.read_u8()?,
}, },
0x87 => Packet::I2cBasicReply { 0x87 => Packet::I2cBasicReply {
succeeded: reader.read_bool()? succeeded: reader.read_bool()?,
}, },
0x88 => Packet::I2cSwitchSelectRequest { 0x88 => Packet::I2cSwitchSelectRequest {
destination: reader.read_u8()?, destination: reader.read_u8()?,
busno: reader.read_u8()?, busno: reader.read_u8()?,
address: reader.read_u8()?, address: reader.read_u8()?,
mask: reader.read_u8()? mask: reader.read_u8()?,
}, },
0x90 => Packet::SpiSetConfigRequest { 0x90 => Packet::SpiSetConfigRequest {
@ -166,157 +242,180 @@ impl Packet {
flags: reader.read_u8()?, flags: reader.read_u8()?,
length: reader.read_u8()?, length: reader.read_u8()?,
div: reader.read_u8()?, div: reader.read_u8()?,
cs: reader.read_u8()? cs: reader.read_u8()?,
}, },
/* 0x91: was Packet::SpiSetXferRequest */ /* 0x91: was Packet::SpiSetXferRequest */
0x92 => Packet::SpiWriteRequest { 0x92 => Packet::SpiWriteRequest {
destination: reader.read_u8()?, destination: reader.read_u8()?,
busno: reader.read_u8()?, busno: reader.read_u8()?,
data: reader.read_u32()? data: reader.read_u32()?,
}, },
0x93 => Packet::SpiReadRequest { 0x93 => Packet::SpiReadRequest {
destination: reader.read_u8()?, destination: reader.read_u8()?,
busno: reader.read_u8()? busno: reader.read_u8()?,
}, },
0x94 => Packet::SpiReadReply { 0x94 => Packet::SpiReadReply {
succeeded: reader.read_bool()?, succeeded: reader.read_bool()?,
data: reader.read_u32()? data: reader.read_u32()?,
}, },
0x95 => Packet::SpiBasicReply { 0x95 => Packet::SpiBasicReply {
succeeded: reader.read_bool()? succeeded: reader.read_bool()?,
}, },
ty => return Err(Error::UnknownPacket(ty)) ty => return Err(Error::UnknownPacket(ty)),
}) })
} }
pub fn write_to<W>(&self, writer: &mut W) -> Result<(), IoError> pub fn write_to<W>(&self, writer: &mut W) -> Result<(), IoError>
where W: Write + ?Sized where W: Write + ?Sized {
{
match *self { match *self {
Packet::EchoRequest => Packet::EchoRequest => writer.write_u8(0x00)?,
writer.write_u8(0x00)?, Packet::EchoReply => writer.write_u8(0x01)?,
Packet::EchoReply => Packet::ResetRequest => writer.write_u8(0x02)?,
writer.write_u8(0x01)?, Packet::ResetAck => writer.write_u8(0x03)?,
Packet::ResetRequest => Packet::TSCAck => writer.write_u8(0x04)?,
writer.write_u8(0x02)?,
Packet::ResetAck =>
writer.write_u8(0x03)?,
Packet::TSCAck =>
writer.write_u8(0x04)?,
Packet::DestinationStatusRequest { destination } => { Packet::DestinationStatusRequest { destination } => {
writer.write_u8(0x20)?; writer.write_u8(0x20)?;
writer.write_u8(destination)?; writer.write_u8(destination)?;
}, }
Packet::DestinationDownReply => Packet::DestinationDownReply => writer.write_u8(0x21)?,
writer.write_u8(0x21)?, Packet::DestinationOkReply => writer.write_u8(0x22)?,
Packet::DestinationOkReply =>
writer.write_u8(0x22)?,
Packet::DestinationSequenceErrorReply { channel } => { Packet::DestinationSequenceErrorReply { channel } => {
writer.write_u8(0x23)?; writer.write_u8(0x23)?;
writer.write_u16(channel)?; writer.write_u16(channel)?;
}, }
Packet::DestinationCollisionReply { channel } => { Packet::DestinationCollisionReply { channel } => {
writer.write_u8(0x24)?; writer.write_u8(0x24)?;
writer.write_u16(channel)?; writer.write_u16(channel)?;
}, }
Packet::DestinationBusyReply { channel } => { Packet::DestinationBusyReply { channel } => {
writer.write_u8(0x25)?; writer.write_u8(0x25)?;
writer.write_u16(channel)?; writer.write_u16(channel)?;
}, }
Packet::RoutingSetPath { destination, hops } => { Packet::RoutingSetPath { destination, hops } => {
writer.write_u8(0x30)?; writer.write_u8(0x30)?;
writer.write_u8(destination)?; writer.write_u8(destination)?;
writer.write_all(&hops)?; writer.write_all(&hops)?;
}, }
Packet::RoutingSetRank { rank } => { Packet::RoutingSetRank { rank } => {
writer.write_u8(0x31)?; writer.write_u8(0x31)?;
writer.write_u8(rank)?; writer.write_u8(rank)?;
}, }
Packet::RoutingAck => Packet::RoutingAck => writer.write_u8(0x32)?,
writer.write_u8(0x32)?,
Packet::MonitorRequest { destination, channel, probe } => { Packet::MonitorRequest {
destination,
channel,
probe,
} => {
writer.write_u8(0x40)?; writer.write_u8(0x40)?;
writer.write_u8(destination)?; writer.write_u8(destination)?;
writer.write_u16(channel)?; writer.write_u16(channel)?;
writer.write_u8(probe)?; writer.write_u8(probe)?;
}, }
Packet::MonitorReply { value } => { Packet::MonitorReply { value } => {
writer.write_u8(0x41)?; writer.write_u8(0x41)?;
writer.write_u64(value)?; writer.write_u64(value)?;
}, }
Packet::InjectionRequest { destination, channel, overrd, value } => { Packet::InjectionRequest {
destination,
channel,
overrd,
value,
} => {
writer.write_u8(0x50)?; writer.write_u8(0x50)?;
writer.write_u8(destination)?; writer.write_u8(destination)?;
writer.write_u16(channel)?; writer.write_u16(channel)?;
writer.write_u8(overrd)?; writer.write_u8(overrd)?;
writer.write_u8(value)?; writer.write_u8(value)?;
}, }
Packet::InjectionStatusRequest { destination, channel, overrd } => { Packet::InjectionStatusRequest {
destination,
channel,
overrd,
} => {
writer.write_u8(0x51)?; writer.write_u8(0x51)?;
writer.write_u8(destination)?; writer.write_u8(destination)?;
writer.write_u16(channel)?; writer.write_u16(channel)?;
writer.write_u8(overrd)?; writer.write_u8(overrd)?;
}, }
Packet::InjectionStatusReply { value } => { Packet::InjectionStatusReply { value } => {
writer.write_u8(0x52)?; writer.write_u8(0x52)?;
writer.write_u8(value)?; writer.write_u8(value)?;
}, }
Packet::I2cStartRequest { destination, busno } => { Packet::I2cStartRequest { destination, busno } => {
writer.write_u8(0x80)?; writer.write_u8(0x80)?;
writer.write_u8(destination)?; writer.write_u8(destination)?;
writer.write_u8(busno)?; writer.write_u8(busno)?;
}, }
Packet::I2cRestartRequest { destination, busno } => { Packet::I2cRestartRequest { destination, busno } => {
writer.write_u8(0x81)?; writer.write_u8(0x81)?;
writer.write_u8(destination)?; writer.write_u8(destination)?;
writer.write_u8(busno)?; writer.write_u8(busno)?;
}, }
Packet::I2cStopRequest { destination, busno } => { Packet::I2cStopRequest { destination, busno } => {
writer.write_u8(0x82)?; writer.write_u8(0x82)?;
writer.write_u8(destination)?; writer.write_u8(destination)?;
writer.write_u8(busno)?; writer.write_u8(busno)?;
}, }
Packet::I2cWriteRequest { destination, busno, data } => { Packet::I2cWriteRequest {
destination,
busno,
data,
} => {
writer.write_u8(0x83)?; writer.write_u8(0x83)?;
writer.write_u8(destination)?; writer.write_u8(destination)?;
writer.write_u8(busno)?; writer.write_u8(busno)?;
writer.write_u8(data)?; writer.write_u8(data)?;
}, }
Packet::I2cWriteReply { succeeded, ack } => { Packet::I2cWriteReply { succeeded, ack } => {
writer.write_u8(0x84)?; writer.write_u8(0x84)?;
writer.write_bool(succeeded)?; writer.write_bool(succeeded)?;
writer.write_bool(ack)?; writer.write_bool(ack)?;
}, }
Packet::I2cReadRequest { destination, busno, ack } => { Packet::I2cReadRequest {
destination,
busno,
ack,
} => {
writer.write_u8(0x85)?; writer.write_u8(0x85)?;
writer.write_u8(destination)?; writer.write_u8(destination)?;
writer.write_u8(busno)?; writer.write_u8(busno)?;
writer.write_bool(ack)?; writer.write_bool(ack)?;
}, }
Packet::I2cReadReply { succeeded, data } => { Packet::I2cReadReply { succeeded, data } => {
writer.write_u8(0x86)?; writer.write_u8(0x86)?;
writer.write_bool(succeeded)?; writer.write_bool(succeeded)?;
writer.write_u8(data)?; writer.write_u8(data)?;
}, }
Packet::I2cBasicReply { succeeded } => { Packet::I2cBasicReply { succeeded } => {
writer.write_u8(0x87)?; writer.write_u8(0x87)?;
writer.write_bool(succeeded)?; writer.write_bool(succeeded)?;
}, }
Packet::I2cSwitchSelectRequest { destination, busno, address, mask } => { Packet::I2cSwitchSelectRequest {
destination,
busno,
address,
mask,
} => {
writer.write_u8(0x88)?; writer.write_u8(0x88)?;
writer.write_u8(destination)?; writer.write_u8(destination)?;
writer.write_u8(busno)?; writer.write_u8(busno)?;
writer.write_u8(address)?; writer.write_u8(address)?;
writer.write_u8(mask)?; writer.write_u8(mask)?;
}, }
Packet::SpiSetConfigRequest { destination, busno, flags, length, div, cs } => { Packet::SpiSetConfigRequest {
destination,
busno,
flags,
length,
div,
cs,
} => {
writer.write_u8(0x90)?; writer.write_u8(0x90)?;
writer.write_u8(destination)?; writer.write_u8(destination)?;
writer.write_u8(busno)?; writer.write_u8(busno)?;
@ -324,30 +423,32 @@ impl Packet {
writer.write_u8(length)?; writer.write_u8(length)?;
writer.write_u8(div)?; writer.write_u8(div)?;
writer.write_u8(cs)?; writer.write_u8(cs)?;
}, }
Packet::SpiWriteRequest { destination, busno, data } => { Packet::SpiWriteRequest {
destination,
busno,
data,
} => {
writer.write_u8(0x92)?; writer.write_u8(0x92)?;
writer.write_u8(destination)?; writer.write_u8(destination)?;
writer.write_u8(busno)?; writer.write_u8(busno)?;
writer.write_u32(data)?; writer.write_u32(data)?;
}, }
Packet::SpiReadRequest { destination, busno } => { Packet::SpiReadRequest { destination, busno } => {
writer.write_u8(0x93)?; writer.write_u8(0x93)?;
writer.write_u8(destination)?; writer.write_u8(destination)?;
writer.write_u8(busno)?; writer.write_u8(busno)?;
}, }
Packet::SpiReadReply { succeeded, data } => { Packet::SpiReadReply { succeeded, data } => {
writer.write_u8(0x94)?; writer.write_u8(0x94)?;
writer.write_bool(succeeded)?; writer.write_bool(succeeded)?;
writer.write_u32(data)?; writer.write_u32(data)?;
}, }
Packet::SpiBasicReply { succeeded } => { Packet::SpiBasicReply { succeeded } => {
writer.write_u8(0x95)?; writer.write_u8(0x95)?;
writer.write_bool(succeeded)?; writer.write_bool(succeeded)?;
}, }
} }
Ok(()) Ok(())
} }
} }

View File

@ -19,10 +19,8 @@ pub struct IoExpander<'a> {
registers: Registers, registers: Registers,
} }
impl<'a> IoExpander<'a> { impl<'a> IoExpander<'a> {
pub fn new(i2c: &'a mut i2c::I2c, index: u8) -> Result<Self, &'static str> { pub fn new(i2c: &'a mut i2c::I2c, index: u8) -> Result<Self, &'static str> {
// Both expanders on SHARED I2C bus // Both expanders on SHARED I2C bus
let mut io_expander = match index { let mut io_expander = match index {
0 => IoExpander { 0 => IoExpander {
@ -54,10 +52,7 @@ impl<'a> IoExpander<'a> {
_ => return Err("incorrect I/O expander index"), _ => return Err("incorrect I/O expander index"),
}; };
if !io_expander.check_ack()? { if !io_expander.check_ack()? {
info!( info!("MCP23017 io expander {} not found. Checking for PCA9539.", index);
"MCP23017 io expander {} not found. Checking for PCA9539.",
index
);
io_expander.address += 0xa8; // translate to PCA9539 addresses (see schematic) io_expander.address += 0xa8; // translate to PCA9539 addresses (see schematic)
io_expander.registers = Registers { io_expander.registers = Registers {
iodira: 0x06, iodira: 0x06,

View File

@ -1,34 +1,36 @@
#![no_std] #![no_std]
#![feature(never_type)] #![feature(never_type)]
extern crate log; extern crate core_io;
extern crate crc; extern crate crc;
extern crate embedded_hal; extern crate embedded_hal;
extern crate core_io;
extern crate io; extern crate io;
extern crate libasync;
extern crate libboard_zynq; extern crate libboard_zynq;
extern crate libregister;
extern crate libconfig; extern crate libconfig;
extern crate libcortex_a9; extern crate libcortex_a9;
extern crate libasync; extern crate libregister;
extern crate log;
extern crate log_buffer; extern crate log_buffer;
#[path = "../../../build/pl.rs"]
pub mod pl;
pub mod drtioaux_proto;
pub mod drtio_routing; pub mod drtio_routing;
pub mod logger;
#[cfg(has_si5324)]
pub mod si5324;
#[cfg(has_drtio)] #[cfg(has_drtio)]
pub mod drtioaux; pub mod drtioaux;
#[cfg(has_drtio)] #[cfg(has_drtio)]
pub mod drtioaux_async; pub mod drtioaux_async;
#[cfg(has_drtio)] pub mod drtioaux_proto;
#[path = "../../../build/mem.rs"]
pub mod mem;
#[cfg(feature = "target_kasli_soc")] #[cfg(feature = "target_kasli_soc")]
pub mod io_expander; pub mod io_expander;
pub mod logger;
#[cfg(has_drtio)]
#[rustfmt::skip]
#[path = "../../../build/mem.rs"]
pub mod mem;
#[rustfmt::skip]
#[path = "../../../build/pl.rs"]
pub mod pl;
#[cfg(has_si5324)]
pub mod si5324;
use core::{cmp, str}; use core::{cmp, str};

View File

@ -1,13 +1,13 @@
use core::cell::Cell; use core::{cell::Cell, fmt::Write};
use core::fmt::Write;
use log::{Log, LevelFilter};
use log_buffer::LogBuffer;
use libcortex_a9::mutex::{Mutex, MutexGuard};
use libboard_zynq::{println, timer::GlobalTimer}; use libboard_zynq::{println, timer::GlobalTimer};
use libcortex_a9::mutex::{Mutex, MutexGuard};
use log::{LevelFilter, Log};
use log_buffer::LogBuffer;
pub struct LogBufferRef<'a> { pub struct LogBufferRef<'a> {
buffer: MutexGuard<'a, LogBuffer<&'static mut [u8]>>, buffer: MutexGuard<'a, LogBuffer<&'static mut [u8]>>,
old_log_level: LevelFilter old_log_level: LevelFilter,
} }
impl<'a> LogBufferRef<'a> { impl<'a> LogBufferRef<'a> {
@ -37,7 +37,7 @@ impl<'a> Drop for LogBufferRef<'a> {
} }
pub struct BufferLogger { pub struct BufferLogger {
buffer: Mutex<LogBuffer<&'static mut [u8]>>, buffer: Mutex<LogBuffer<&'static mut [u8]>>,
uart_filter: Cell<LevelFilter>, uart_filter: Cell<LevelFilter>,
buffer_filter: Cell<LevelFilter>, buffer_filter: Cell<LevelFilter>,
} }
@ -56,8 +56,7 @@ impl BufferLogger {
pub fn register(self) { pub fn register(self) {
unsafe { unsafe {
LOGGER = Some(self); LOGGER = Some(self);
log::set_logger(LOGGER.as_ref().unwrap()) log::set_logger(LOGGER.as_ref().unwrap()).expect("global logger can only be initialized once");
.expect("global logger can only be initialized once");
} }
} }
@ -66,9 +65,7 @@ impl BufferLogger {
} }
pub fn buffer<'a>(&'a self) -> Option<LogBufferRef<'a>> { pub fn buffer<'a>(&'a self) -> Option<LogBufferRef<'a>> {
self.buffer self.buffer.try_lock().map(LogBufferRef::new)
.try_lock()
.map(LogBufferRef::new)
} }
pub fn uart_log_level(&self) -> LevelFilter { pub fn uart_log_level(&self) -> LevelFilter {
@ -99,25 +96,36 @@ impl Log for BufferLogger {
fn log(&self, record: &log::Record) { fn log(&self, record: &log::Record) {
if self.enabled(record.metadata()) { if self.enabled(record.metadata()) {
let timestamp = unsafe { let timestamp = unsafe { GlobalTimer::get() }.get_us().0;
GlobalTimer::get() let seconds = timestamp / 1_000_000;
}.get_us().0; let micros = timestamp % 1_000_000;
let seconds = timestamp / 1_000_000;
let micros = timestamp % 1_000_000;
if record.level() <= self.buffer_log_level() { if record.level() <= self.buffer_log_level() {
let mut buffer = self.buffer.lock(); let mut buffer = self.buffer.lock();
writeln!(buffer, "[{:6}.{:06}s] {:>5}({}): {}", seconds, micros, writeln!(
record.level(), record.target(), record.args()).unwrap(); buffer,
"[{:6}.{:06}s] {:>5}({}): {}",
seconds,
micros,
record.level(),
record.target(),
record.args()
)
.unwrap();
} }
if record.level() <= self.uart_log_level() { if record.level() <= self.uart_log_level() {
println!("[{:6}.{:06}s] {:>5}({}): {}", seconds, micros, println!(
record.level(), record.target(), record.args()); "[{:6}.{:06}s] {:>5}({}): {}",
seconds,
micros,
record.level(),
record.target(),
record.args()
);
} }
} }
} }
fn flush(&self) { fn flush(&self) {}
}
} }

View File

@ -1,7 +1,9 @@
use core::result; use core::result;
use log::info;
use libboard_zynq::{i2c::I2c, timer::GlobalTimer, time::Milliseconds};
use embedded_hal::blocking::delay::DelayUs; use embedded_hal::blocking::delay::DelayUs;
use libboard_zynq::{i2c::I2c, time::Milliseconds, timer::GlobalTimer};
use log::info;
#[cfg(not(si5324_soft_reset))] #[cfg(not(si5324_soft_reset))]
use crate::pl::csr; use crate::pl::csr;
@ -11,9 +13,13 @@ const ADDRESS: u8 = 0x68;
#[cfg(not(si5324_soft_reset))] #[cfg(not(si5324_soft_reset))]
fn hard_reset(timer: &mut GlobalTimer) { fn hard_reset(timer: &mut GlobalTimer) {
unsafe { csr::si5324_rst_n::out_write(0); } unsafe {
csr::si5324_rst_n::out_write(0);
}
timer.delay_us(1_000); timer.delay_us(1_000);
unsafe { csr::si5324_rst_n::out_write(1); } unsafe {
csr::si5324_rst_n::out_write(1);
}
timer.delay_us(10_000); timer.delay_us(10_000);
} }
@ -29,7 +35,7 @@ pub struct FrequencySettings {
pub n31: u32, pub n31: u32,
pub n32: u32, pub n32: u32,
pub bwsel: u8, pub bwsel: u8,
pub crystal_as_ckin2: bool pub crystal_as_ckin2: bool,
} }
pub enum Input { pub enum Input {
@ -39,52 +45,52 @@ pub enum Input {
fn map_frequency_settings(settings: &FrequencySettings) -> Result<FrequencySettings> { fn map_frequency_settings(settings: &FrequencySettings) -> Result<FrequencySettings> {
if settings.nc1_ls != 0 && (settings.nc1_ls % 2) == 1 { if settings.nc1_ls != 0 && (settings.nc1_ls % 2) == 1 {
return Err("NC1_LS must be 0 or even") return Err("NC1_LS must be 0 or even");
} }
if settings.nc1_ls > (1 << 20) { if settings.nc1_ls > (1 << 20) {
return Err("NC1_LS is too high") return Err("NC1_LS is too high");
} }
if (settings.n2_ls % 2) == 1 { if (settings.n2_ls % 2) == 1 {
return Err("N2_LS must be even") return Err("N2_LS must be even");
} }
if settings.n2_ls > (1 << 20) { if settings.n2_ls > (1 << 20) {
return Err("N2_LS is too high") return Err("N2_LS is too high");
} }
if settings.n31 > (1 << 19) { if settings.n31 > (1 << 19) {
return Err("N31 is too high") return Err("N31 is too high");
} }
if settings.n32 > (1 << 19) { if settings.n32 > (1 << 19) {
return Err("N32 is too high") return Err("N32 is too high");
} }
let r = FrequencySettings { let r = FrequencySettings {
n1_hs: match settings.n1_hs { n1_hs: match settings.n1_hs {
4 => 0b000, 4 => 0b000,
5 => 0b001, 5 => 0b001,
6 => 0b010, 6 => 0b010,
7 => 0b011, 7 => 0b011,
8 => 0b100, 8 => 0b100,
9 => 0b101, 9 => 0b101,
10 => 0b110, 10 => 0b110,
11 => 0b111, 11 => 0b111,
_ => return Err("N1_HS has an invalid value") _ => return Err("N1_HS has an invalid value"),
}, },
nc1_ls: settings.nc1_ls - 1, nc1_ls: settings.nc1_ls - 1,
n2_hs: match settings.n2_hs { n2_hs: match settings.n2_hs {
4 => 0b000, 4 => 0b000,
5 => 0b001, 5 => 0b001,
6 => 0b010, 6 => 0b010,
7 => 0b011, 7 => 0b011,
8 => 0b100, 8 => 0b100,
9 => 0b101, 9 => 0b101,
10 => 0b110, 10 => 0b110,
11 => 0b111, 11 => 0b111,
_ => return Err("N2_HS has an invalid value") _ => return Err("N2_HS has an invalid value"),
}, },
n2_ls: settings.n2_ls - 1, n2_ls: settings.n2_ls - 1,
n31: settings.n31 - 1, n31: settings.n31 - 1,
n32: settings.n32 - 1, n32: settings.n32 - 1,
bwsel: settings.bwsel, bwsel: settings.bwsel,
crystal_as_ckin2: settings.crystal_as_ckin2 crystal_as_ckin2: settings.crystal_as_ckin2,
}; };
Ok(r) Ok(r)
} }
@ -92,13 +98,13 @@ fn map_frequency_settings(settings: &FrequencySettings) -> Result<FrequencySetti
fn write(i2c: &mut I2c, reg: u8, val: u8) -> Result<()> { fn write(i2c: &mut I2c, reg: u8, val: u8) -> Result<()> {
i2c.start().unwrap(); i2c.start().unwrap();
if !i2c.write(ADDRESS << 1).unwrap() { if !i2c.write(ADDRESS << 1).unwrap() {
return Err("Si5324 failed to ack write address") return Err("Si5324 failed to ack write address");
} }
if !i2c.write(reg).unwrap() { if !i2c.write(reg).unwrap() {
return Err("Si5324 failed to ack register") return Err("Si5324 failed to ack register");
} }
if !i2c.write(val).unwrap() { if !i2c.write(val).unwrap() {
return Err("Si5324 failed to ack value") return Err("Si5324 failed to ack value");
} }
i2c.stop().unwrap(); i2c.stop().unwrap();
Ok(()) Ok(())
@ -108,10 +114,10 @@ fn write(i2c: &mut I2c, reg: u8, val: u8) -> Result<()> {
fn write_no_ack_value(i2c: &mut I2c, reg: u8, val: u8) -> Result<()> { fn write_no_ack_value(i2c: &mut I2c, reg: u8, val: u8) -> Result<()> {
i2c.start().unwrap(); i2c.start().unwrap();
if !i2c.write(ADDRESS << 1).unwrap() { if !i2c.write(ADDRESS << 1).unwrap() {
return Err("Si5324 failed to ack write address") return Err("Si5324 failed to ack write address");
} }
if !i2c.write(reg).unwrap() { if !i2c.write(reg).unwrap() {
return Err("Si5324 failed to ack register") return Err("Si5324 failed to ack register");
} }
i2c.write(val).unwrap(); i2c.write(val).unwrap();
i2c.stop().unwrap(); i2c.stop().unwrap();
@ -121,22 +127,22 @@ fn write_no_ack_value(i2c: &mut I2c, reg: u8, val: u8) -> Result<()> {
fn read(i2c: &mut I2c, reg: u8) -> Result<u8> { fn read(i2c: &mut I2c, reg: u8) -> Result<u8> {
i2c.start().unwrap(); i2c.start().unwrap();
if !i2c.write(ADDRESS << 1).unwrap() { if !i2c.write(ADDRESS << 1).unwrap() {
return Err("Si5324 failed to ack write address") return Err("Si5324 failed to ack write address");
} }
if !i2c.write(reg).unwrap() { if !i2c.write(reg).unwrap() {
return Err("Si5324 failed to ack register") return Err("Si5324 failed to ack register");
} }
i2c.restart().unwrap(); i2c.restart().unwrap();
if !i2c.write((ADDRESS << 1) | 1).unwrap() { if !i2c.write((ADDRESS << 1) | 1).unwrap() {
return Err("Si5324 failed to ack read address") return Err("Si5324 failed to ack read address");
} }
let val = i2c.read(false).unwrap(); let val = i2c.read(false).unwrap();
i2c.stop().unwrap(); i2c.stop().unwrap();
Ok(val) Ok(val)
} }
fn rmw<F>(i2c: &mut I2c, reg: u8, f: F) -> Result<()> where fn rmw<F>(i2c: &mut I2c, reg: u8, f: F) -> Result<()>
F: Fn(u8) -> u8 { where F: Fn(u8) -> u8 {
let value = read(i2c, reg)?; let value = read(i2c, reg)?;
write(i2c, reg, f(value))?; write(i2c, reg, f(value))?;
Ok(()) Ok(())
@ -155,18 +161,18 @@ fn soft_reset(i2c: &mut I2c, timer: &mut GlobalTimer) -> Result<()> {
} }
fn has_xtal(i2c: &mut I2c) -> Result<bool> { fn has_xtal(i2c: &mut I2c) -> Result<bool> {
Ok((read(i2c, 129)? & 0x01) == 0) // LOSX_INT=0 Ok((read(i2c, 129)? & 0x01) == 0) // LOSX_INT=0
} }
fn has_ckin(i2c: &mut I2c, input: Input) -> Result<bool> { fn has_ckin(i2c: &mut I2c, input: Input) -> Result<bool> {
match input { match input {
Input::Ckin1 => Ok((read(i2c, 129)? & 0x02) == 0), // LOS1_INT=0 Input::Ckin1 => Ok((read(i2c, 129)? & 0x02) == 0), // LOS1_INT=0
Input::Ckin2 => Ok((read(i2c, 129)? & 0x04) == 0), // LOS2_INT=0 Input::Ckin2 => Ok((read(i2c, 129)? & 0x04) == 0), // LOS2_INT=0
} }
} }
fn locked(i2c: &mut I2c) -> Result<bool> { fn locked(i2c: &mut I2c) -> Result<bool> {
Ok((read(i2c, 130)? & 0x01) == 0) // LOL_INT=0 Ok((read(i2c, 130)? & 0x01) == 0) // LOL_INT=0
} }
fn monitor_lock(i2c: &mut I2c, timer: &mut GlobalTimer) -> Result<()> { fn monitor_lock(i2c: &mut I2c, timer: &mut GlobalTimer) -> Result<()> {
@ -211,11 +217,11 @@ pub fn bypass(i2c: &mut I2c, input: Input, timer: &mut GlobalTimer) -> Result<()
Input::Ckin2 => 0b01, Input::Ckin2 => 0b01,
}; };
init(i2c, timer)?; init(i2c, timer)?;
rmw(i2c, 21, |v| v & 0xfe)?; // CKSEL_PIN=0 rmw(i2c, 21, |v| v & 0xfe)?; // CKSEL_PIN=0
rmw(i2c, 3, |v| (v & 0x3f) | (cksel_reg << 6))?; // CKSEL_REG rmw(i2c, 3, |v| (v & 0x3f) | (cksel_reg << 6))?; // CKSEL_REG
rmw(i2c, 4, |v| (v & 0x3f) | (0b00 << 6))?; // AUTOSEL_REG=b00 rmw(i2c, 4, |v| (v & 0x3f) | (0b00 << 6))?; // AUTOSEL_REG=b00
rmw(i2c, 6, |v| (v & 0xc0) | 0b111111)?; // SFOUT2_REG=b111 SFOUT1_REG=b111 rmw(i2c, 6, |v| (v & 0xc0) | 0b111111)?; // SFOUT2_REG=b111 SFOUT1_REG=b111
rmw(i2c, 0, |v| (v & 0xfd) | 0x02)?; // BYPASS_REG=1 rmw(i2c, 0, |v| (v & 0xfd) | 0x02)?; // BYPASS_REG=1
Ok(()) Ok(())
} }
@ -228,31 +234,31 @@ pub fn setup(i2c: &mut I2c, settings: &FrequencySettings, input: Input, timer: &
init(i2c, timer)?; init(i2c, timer)?;
if settings.crystal_as_ckin2 { if settings.crystal_as_ckin2 {
rmw(i2c, 0, |v| v | 0x40)?; // FREE_RUN=1 rmw(i2c, 0, |v| v | 0x40)?; // FREE_RUN=1
} }
rmw(i2c, 2, |v| (v & 0x0f) | (s.bwsel << 4))?; rmw(i2c, 2, |v| (v & 0x0f) | (s.bwsel << 4))?;
rmw(i2c, 21, |v| v & 0xfe)?; // CKSEL_PIN=0 rmw(i2c, 21, |v| v & 0xfe)?; // CKSEL_PIN=0
rmw(i2c, 3, |v| (v & 0x2f) | (cksel_reg << 6) | 0x10)?; // CKSEL_REG, SQ_ICAL=1 rmw(i2c, 3, |v| (v & 0x2f) | (cksel_reg << 6) | 0x10)?; // CKSEL_REG, SQ_ICAL=1
rmw(i2c, 4, |v| (v & 0x3f) | (0b00 << 6))?; // AUTOSEL_REG=b00 rmw(i2c, 4, |v| (v & 0x3f) | (0b00 << 6))?; // AUTOSEL_REG=b00
rmw(i2c, 6, |v| (v & 0xc0) | 0b111111)?; // SFOUT2_REG=b111 SFOUT1_REG=b111 rmw(i2c, 6, |v| (v & 0xc0) | 0b111111)?; // SFOUT2_REG=b111 SFOUT1_REG=b111
write(i2c, 25, (s.n1_hs << 5 ) as u8)?; write(i2c, 25, (s.n1_hs << 5) as u8)?;
write(i2c, 31, (s.nc1_ls >> 16) as u8)?; write(i2c, 31, (s.nc1_ls >> 16) as u8)?;
write(i2c, 32, (s.nc1_ls >> 8 ) as u8)?; write(i2c, 32, (s.nc1_ls >> 8) as u8)?;
write(i2c, 33, (s.nc1_ls) as u8)?; write(i2c, 33, (s.nc1_ls) as u8)?;
write(i2c, 34, (s.nc1_ls >> 16) as u8)?; // write to NC2_LS as well write(i2c, 34, (s.nc1_ls >> 16) as u8)?; // write to NC2_LS as well
write(i2c, 35, (s.nc1_ls >> 8 ) as u8)?; write(i2c, 35, (s.nc1_ls >> 8) as u8)?;
write(i2c, 36, (s.nc1_ls) as u8)?; write(i2c, 36, (s.nc1_ls) as u8)?;
write(i2c, 40, (s.n2_hs << 5 ) as u8 | (s.n2_ls >> 16) as u8)?; write(i2c, 40, (s.n2_hs << 5) as u8 | (s.n2_ls >> 16) as u8)?;
write(i2c, 41, (s.n2_ls >> 8 ) as u8)?; write(i2c, 41, (s.n2_ls >> 8) as u8)?;
write(i2c, 42, (s.n2_ls) as u8)?; write(i2c, 42, (s.n2_ls) as u8)?;
write(i2c, 43, (s.n31 >> 16) as u8)?; write(i2c, 43, (s.n31 >> 16) as u8)?;
write(i2c, 44, (s.n31 >> 8) as u8)?; write(i2c, 44, (s.n31 >> 8) as u8)?;
write(i2c, 45, (s.n31) as u8)?; write(i2c, 45, (s.n31) as u8)?;
write(i2c, 46, (s.n32 >> 16) as u8)?; write(i2c, 46, (s.n32 >> 16) as u8)?;
write(i2c, 47, (s.n32 >> 8) as u8)?; write(i2c, 47, (s.n32 >> 8) as u8)?;
write(i2c, 48, (s.n32) as u8)?; write(i2c, 48, (s.n32) as u8)?;
rmw(i2c, 137, |v| v | 0x01)?; // FASTLOCK=1 rmw(i2c, 137, |v| v | 0x01)?; // FASTLOCK=1
rmw(i2c, 136, |v| v | 0x40)?; // ICAL=1 rmw(i2c, 136, |v| v | 0x40)?; // ICAL=1
if !has_xtal(i2c)? { if !has_xtal(i2c)? {
return Err("Si5324 misses XA/XB signal"); return Err("Si5324 misses XA/XB signal");
@ -270,7 +276,7 @@ pub fn select_input(i2c: &mut I2c, input: Input, timer: &mut GlobalTimer) -> Res
Input::Ckin1 => 0b00, Input::Ckin1 => 0b00,
Input::Ckin2 => 0b01, Input::Ckin2 => 0b01,
}; };
rmw(i2c, 3, |v| (v & 0x3f) | (cksel_reg << 6))?; rmw(i2c, 3, |v| (v & 0x3f) | (cksel_reg << 6))?;
if !has_ckin(i2c, input)? { if !has_ckin(i2c, input)? {
return Err("Si5324 misses clock input signal"); return Err("Si5324 misses clock input signal");
} }
@ -285,12 +291,12 @@ pub mod siphaser {
pub fn select_recovered_clock(i2c: &mut I2c, rc: bool, timer: &mut GlobalTimer) -> Result<()> { pub fn select_recovered_clock(i2c: &mut I2c, rc: bool, timer: &mut GlobalTimer) -> Result<()> {
let val = read(i2c, 3)?; let val = read(i2c, 3)?;
write(i2c, 3, (val & 0xdf) | (1 << 5))?; // DHOLD=1 write(i2c, 3, (val & 0xdf) | (1 << 5))?; // DHOLD=1
unsafe { unsafe {
csr::siphaser::switch_clocks_write(if rc { 1 } else { 0 }); csr::siphaser::switch_clocks_write(if rc { 1 } else { 0 });
} }
let val = read(i2c, 3)?; let val = read(i2c, 3)?;
write(i2c, 3, (val & 0xdf) | (0 << 5))?; // DHOLD=0 write(i2c, 3, (val & 0xdf) | (0 << 5))?; // DHOLD=0
monitor_lock(i2c, timer)?; monitor_lock(i2c, timer)?;
Ok(()) Ok(())
} }
@ -309,9 +315,7 @@ pub mod siphaser {
csr::siphaser::error_write(1); csr::siphaser::error_write(1);
} }
timer.delay_us(5_000); timer.delay_us(5_000);
unsafe { unsafe { csr::siphaser::error_read() != 0 }
csr::siphaser::error_read() != 0
}
} }
fn find_edge(target: bool, timer: &mut GlobalTimer) -> Result<u32> { fn find_edge(target: bool, timer: &mut GlobalTimer) -> Result<u32> {
@ -340,14 +344,19 @@ pub mod siphaser {
} }
let width = find_edge(true, timer)? + jitter_margin; let width = find_edge(true, timer)? + jitter_margin;
// width is 360 degrees (one full rotation of the phase between s/h limits) minus jitter // width is 360 degrees (one full rotation of the phase between s/h limits) minus jitter
info!("calibration successful, lead: {}, width: {} ({}deg)", lead, width, width*360/(56*8)); info!(
"calibration successful, lead: {}, width: {} ({}deg)",
lead,
width,
width * 360 / (56 * 8)
);
// Apply reverse phase shift for half the width to get into the // Apply reverse phase shift for half the width to get into the
// middle of the working region. // middle of the working region.
for _ in 0..width/2 { for _ in 0..width / 2 {
phase_shift(0, timer); phase_shift(0, timer);
} }
Ok(()) Ok(())
} }
} }

View File

@ -1,8 +1,7 @@
use std::env; use std::{env,
use std::fs::File; fs::File,
use std::io::{BufRead, BufReader, Write}; io::{BufRead, BufReader, Write},
use std::path::PathBuf; path::PathBuf};
pub fn add_linker_script() { pub fn add_linker_script() {
// Put the linker script somewhere the linker can find it // Put the linker script somewhere the linker can find it

View File

@ -4,8 +4,7 @@ fn main() {
} }
mod libc { mod libc {
use std::path::Path; use std::{env, path::Path};
use std::env;
pub fn compile() { pub fn compile() {
let cfg = &mut cc::Build::new(); let cfg = &mut cc::Build::new();
@ -32,9 +31,7 @@ mod libc {
cfg.flag("-U_FORTIFY_SOURCE"); cfg.flag("-U_FORTIFY_SOURCE");
cfg.define("_FORTIFY_SOURCE", Some("0")); cfg.define("_FORTIFY_SOURCE", Some("0"));
let sources = vec![ let sources = vec!["printf.c"];
"printf.c"
];
let root = Path::new("./"); let root = Path::new("./");
for src in sources { for src in sources {

View File

@ -11,10 +11,12 @@
#![allow(non_upper_case_globals)] #![allow(non_upper_case_globals)]
#![allow(unused)] #![allow(unused)]
use crate::DwarfReader;
use core::mem; use core::mem;
use cslice::CSlice; use cslice::CSlice;
use crate::DwarfReader;
pub const DW_EH_PE_omit: u8 = 0xFF; pub const DW_EH_PE_omit: u8 = 0xFF;
pub const DW_EH_PE_absptr: u8 = 0x00; pub const DW_EH_PE_absptr: u8 = 0x00;
@ -160,15 +162,11 @@ pub unsafe fn find_eh_action(
if ar_filter == 0 { if ar_filter == 0 {
saw_cleanup = true; saw_cleanup = true;
} else if ar_filter > 0 { } else if ar_filter > 0 {
let catch_type = get_ttype_entry( let catch_type =
ar_filter as usize, get_ttype_entry(ar_filter as usize, ttype_encoding, ttype_base, ttype_table)?;
ttype_encoding,
ttype_base,
ttype_table,
)?;
match catch_type { match catch_type {
Some(clause_ptr) if *(clause_ptr as *const u32) == id => { Some(clause_ptr) if *(clause_ptr as *const u32) == id => {
return Ok(EHAction::Catch(lpad)) return Ok(EHAction::Catch(lpad));
} }
None => return Ok(EHAction::Catch(lpad)), None => return Ok(EHAction::Catch(lpad)),
_ => {} _ => {}
@ -251,19 +249,11 @@ fn get_base(encoding: u8, context: &EHContext<'_>) -> Result<usize, ()> {
} }
} }
unsafe fn read_encoded_pointer( unsafe fn read_encoded_pointer(reader: &mut DwarfReader, context: &EHContext<'_>, encoding: u8) -> Result<usize, ()> {
reader: &mut DwarfReader,
context: &EHContext<'_>,
encoding: u8,
) -> Result<usize, ()> {
read_encoded_pointer_with_base(reader, encoding, get_base(encoding, context)?) read_encoded_pointer_with_base(reader, encoding, get_base(encoding, context)?)
} }
unsafe fn read_encoded_pointer_with_base( unsafe fn read_encoded_pointer_with_base(reader: &mut DwarfReader, encoding: u8, base: usize) -> Result<usize, ()> {
reader: &mut DwarfReader,
encoding: u8,
base: usize,
) -> Result<usize, ()> {
if encoding == DW_EH_PE_omit { if encoding == DW_EH_PE_omit {
return Err(()); return Err(());
} }

View File

@ -1451,8 +1451,7 @@ pub const R_AARCH64_TLSDESC_CALL: usize = 569;
pub const R_AARCH64_TLSLE_LDST128_TPREL_LO12: usize = 570; pub const R_AARCH64_TLSLE_LDST128_TPREL_LO12: usize = 570;
pub const R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC: usize = 571; pub const R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC: usize = 571;
pub const R_AARCH64_TLSLD_LDST128_DTPREL_LO12: usize = 572; pub const R_AARCH64_TLSLD_LDST128_DTPREL_LO12: usize = 572;
pub const R_AARCH64_TLSLD_LDST128_DTPREL_LO12_NC: usize = pub const R_AARCH64_TLSLD_LDST128_DTPREL_LO12_NC: usize = 573;
573;
pub const R_AARCH64_COPY: usize = 1024; pub const R_AARCH64_COPY: usize = 1024;
pub const R_AARCH64_GLOB_DAT: usize = 1025; pub const R_AARCH64_GLOB_DAT: usize = 1025;
pub const R_AARCH64_JUMP_SLOT: usize = 1026; pub const R_AARCH64_JUMP_SLOT: usize = 1026;
@ -2267,7 +2266,9 @@ pub struct Elf32_Ehdr {
pub e_shstrndx: Elf32_Half, pub e_shstrndx: Elf32_Half,
} }
impl Clone for Elf32_Ehdr { impl Clone for Elf32_Ehdr {
fn clone(&self) -> Self { *self } fn clone(&self) -> Self {
*self
}
} }
#[repr(C)] #[repr(C)]
#[derive(Debug, Copy)] #[derive(Debug, Copy)]
@ -2288,7 +2289,9 @@ pub struct Elf64_Ehdr {
pub e_shstrndx: Elf64_Half, pub e_shstrndx: Elf64_Half,
} }
impl Clone for Elf64_Ehdr { impl Clone for Elf64_Ehdr {
fn clone(&self) -> Self { *self } fn clone(&self) -> Self {
*self
}
} }
#[repr(C)] #[repr(C)]
#[derive(Debug, Copy)] #[derive(Debug, Copy)]
@ -2305,7 +2308,9 @@ pub struct Elf32_Shdr {
pub sh_entsize: Elf32_Word, pub sh_entsize: Elf32_Word,
} }
impl Clone for Elf32_Shdr { impl Clone for Elf32_Shdr {
fn clone(&self) -> Self { *self } fn clone(&self) -> Self {
*self
}
} }
#[repr(C)] #[repr(C)]
#[derive(Debug, Copy)] #[derive(Debug, Copy)]
@ -2322,7 +2327,9 @@ pub struct Elf64_Shdr {
pub sh_entsize: Elf64_Xword, pub sh_entsize: Elf64_Xword,
} }
impl Clone for Elf64_Shdr { impl Clone for Elf64_Shdr {
fn clone(&self) -> Self { *self } fn clone(&self) -> Self {
*self
}
} }
#[repr(C)] #[repr(C)]
#[derive(Debug, Copy)] #[derive(Debug, Copy)]
@ -2335,7 +2342,9 @@ pub struct Elf32_Sym {
pub st_shndx: Elf32_Section, pub st_shndx: Elf32_Section,
} }
impl Clone for Elf32_Sym { impl Clone for Elf32_Sym {
fn clone(&self) -> Self { *self } fn clone(&self) -> Self {
*self
}
} }
#[repr(C)] #[repr(C)]
#[derive(Debug, Copy)] #[derive(Debug, Copy)]
@ -2348,7 +2357,9 @@ pub struct Elf64_Sym {
pub st_size: Elf64_Xword, pub st_size: Elf64_Xword,
} }
impl Clone for Elf64_Sym { impl Clone for Elf64_Sym {
fn clone(&self) -> Self { *self } fn clone(&self) -> Self {
*self
}
} }
#[repr(C)] #[repr(C)]
#[derive(Debug, Copy)] #[derive(Debug, Copy)]
@ -2357,7 +2368,9 @@ pub struct Elf32_Syminfo {
pub si_flags: Elf32_Half, pub si_flags: Elf32_Half,
} }
impl Clone for Elf32_Syminfo { impl Clone for Elf32_Syminfo {
fn clone(&self) -> Self { *self } fn clone(&self) -> Self {
*self
}
} }
#[repr(C)] #[repr(C)]
#[derive(Debug, Copy)] #[derive(Debug, Copy)]
@ -2366,7 +2379,9 @@ pub struct Elf64_Syminfo {
pub si_flags: Elf64_Half, pub si_flags: Elf64_Half,
} }
impl Clone for Elf64_Syminfo { impl Clone for Elf64_Syminfo {
fn clone(&self) -> Self { *self } fn clone(&self) -> Self {
*self
}
} }
#[repr(C)] #[repr(C)]
#[derive(Debug, Copy)] #[derive(Debug, Copy)]
@ -2375,7 +2390,9 @@ pub struct Elf32_Rel {
pub r_info: Elf32_Word, pub r_info: Elf32_Word,
} }
impl Clone for Elf32_Rel { impl Clone for Elf32_Rel {
fn clone(&self) -> Self { *self } fn clone(&self) -> Self {
*self
}
} }
#[repr(C)] #[repr(C)]
#[derive(Debug, Copy)] #[derive(Debug, Copy)]
@ -2384,7 +2401,9 @@ pub struct Elf64_Rel {
pub r_info: Elf64_Xword, pub r_info: Elf64_Xword,
} }
impl Clone for Elf64_Rel { impl Clone for Elf64_Rel {
fn clone(&self) -> Self { *self } fn clone(&self) -> Self {
*self
}
} }
#[repr(C)] #[repr(C)]
#[derive(Debug, Copy)] #[derive(Debug, Copy)]
@ -2394,7 +2413,9 @@ pub struct Elf32_Rela {
pub r_addend: Elf32_Sword, pub r_addend: Elf32_Sword,
} }
impl Clone for Elf32_Rela { impl Clone for Elf32_Rela {
fn clone(&self) -> Self { *self } fn clone(&self) -> Self {
*self
}
} }
#[repr(C)] #[repr(C)]
#[derive(Debug, Copy)] #[derive(Debug, Copy)]
@ -2404,7 +2425,9 @@ pub struct Elf64_Rela {
pub r_addend: Elf64_Sxword, pub r_addend: Elf64_Sxword,
} }
impl Clone for Elf64_Rela { impl Clone for Elf64_Rela {
fn clone(&self) -> Self { *self } fn clone(&self) -> Self {
*self
}
} }
#[repr(C)] #[repr(C)]
#[derive(Debug, Copy)] #[derive(Debug, Copy)]
@ -2419,7 +2442,9 @@ pub struct Elf32_Phdr {
pub p_align: Elf32_Word, pub p_align: Elf32_Word,
} }
impl Clone for Elf32_Phdr { impl Clone for Elf32_Phdr {
fn clone(&self) -> Self { *self } fn clone(&self) -> Self {
*self
}
} }
#[repr(C)] #[repr(C)]
#[derive(Debug, Copy)] #[derive(Debug, Copy)]
@ -2434,7 +2459,9 @@ pub struct Elf64_Phdr {
pub p_align: Elf64_Xword, pub p_align: Elf64_Xword,
} }
impl Clone for Elf64_Phdr { impl Clone for Elf64_Phdr {
fn clone(&self) -> Self { *self } fn clone(&self) -> Self {
*self
}
} }
#[repr(C)] #[repr(C)]
#[derive(Copy)] #[derive(Copy)]
@ -2449,10 +2476,14 @@ pub union Elf32_Dyn__bindgen_ty_1 {
pub d_ptr: Elf32_Addr, pub d_ptr: Elf32_Addr,
} }
impl Clone for Elf32_Dyn__bindgen_ty_1 { impl Clone for Elf32_Dyn__bindgen_ty_1 {
fn clone(&self) -> Self { *self } fn clone(&self) -> Self {
*self
}
} }
impl Clone for Elf32_Dyn { impl Clone for Elf32_Dyn {
fn clone(&self) -> Self { *self } fn clone(&self) -> Self {
*self
}
} }
#[repr(C)] #[repr(C)]
#[derive(Copy)] #[derive(Copy)]
@ -2467,10 +2498,14 @@ pub union Elf64_Dyn__bindgen_ty_1 {
pub d_ptr: Elf64_Addr, pub d_ptr: Elf64_Addr,
} }
impl Clone for Elf64_Dyn__bindgen_ty_1 { impl Clone for Elf64_Dyn__bindgen_ty_1 {
fn clone(&self) -> Self { *self } fn clone(&self) -> Self {
*self
}
} }
impl Clone for Elf64_Dyn { impl Clone for Elf64_Dyn {
fn clone(&self) -> Self { *self } fn clone(&self) -> Self {
*self
}
} }
#[repr(C)] #[repr(C)]
#[derive(Debug, Copy)] #[derive(Debug, Copy)]
@ -2484,7 +2519,9 @@ pub struct Elf32_Verdef {
pub vd_next: Elf32_Word, pub vd_next: Elf32_Word,
} }
impl Clone for Elf32_Verdef { impl Clone for Elf32_Verdef {
fn clone(&self) -> Self { *self } fn clone(&self) -> Self {
*self
}
} }
#[repr(C)] #[repr(C)]
#[derive(Debug, Copy)] #[derive(Debug, Copy)]
@ -2498,7 +2535,9 @@ pub struct Elf64_Verdef {
pub vd_next: Elf64_Word, pub vd_next: Elf64_Word,
} }
impl Clone for Elf64_Verdef { impl Clone for Elf64_Verdef {
fn clone(&self) -> Self { *self } fn clone(&self) -> Self {
*self
}
} }
#[repr(C)] #[repr(C)]
#[derive(Debug, Copy)] #[derive(Debug, Copy)]
@ -2507,7 +2546,9 @@ pub struct Elf32_Verdaux {
pub vda_next: Elf32_Word, pub vda_next: Elf32_Word,
} }
impl Clone for Elf32_Verdaux { impl Clone for Elf32_Verdaux {
fn clone(&self) -> Self { *self } fn clone(&self) -> Self {
*self
}
} }
#[repr(C)] #[repr(C)]
#[derive(Debug, Copy)] #[derive(Debug, Copy)]
@ -2516,7 +2557,9 @@ pub struct Elf64_Verdaux {
pub vda_next: Elf64_Word, pub vda_next: Elf64_Word,
} }
impl Clone for Elf64_Verdaux { impl Clone for Elf64_Verdaux {
fn clone(&self) -> Self { *self } fn clone(&self) -> Self {
*self
}
} }
#[repr(C)] #[repr(C)]
#[derive(Debug, Copy)] #[derive(Debug, Copy)]
@ -2528,7 +2571,9 @@ pub struct Elf32_Verneed {
pub vn_next: Elf32_Word, pub vn_next: Elf32_Word,
} }
impl Clone for Elf32_Verneed { impl Clone for Elf32_Verneed {
fn clone(&self) -> Self { *self } fn clone(&self) -> Self {
*self
}
} }
#[repr(C)] #[repr(C)]
#[derive(Debug, Copy)] #[derive(Debug, Copy)]
@ -2540,7 +2585,9 @@ pub struct Elf64_Verneed {
pub vn_next: Elf64_Word, pub vn_next: Elf64_Word,
} }
impl Clone for Elf64_Verneed { impl Clone for Elf64_Verneed {
fn clone(&self) -> Self { *self } fn clone(&self) -> Self {
*self
}
} }
#[repr(C)] #[repr(C)]
#[derive(Debug, Copy)] #[derive(Debug, Copy)]
@ -2552,7 +2599,9 @@ pub struct Elf32_Vernaux {
pub vna_next: Elf32_Word, pub vna_next: Elf32_Word,
} }
impl Clone for Elf32_Vernaux { impl Clone for Elf32_Vernaux {
fn clone(&self) -> Self { *self } fn clone(&self) -> Self {
*self
}
} }
#[repr(C)] #[repr(C)]
#[derive(Debug, Copy)] #[derive(Debug, Copy)]
@ -2564,7 +2613,9 @@ pub struct Elf64_Vernaux {
pub vna_next: Elf64_Word, pub vna_next: Elf64_Word,
} }
impl Clone for Elf64_Vernaux { impl Clone for Elf64_Vernaux {
fn clone(&self) -> Self { *self } fn clone(&self) -> Self {
*self
}
} }
#[repr(C)] #[repr(C)]
#[derive(Copy)] #[derive(Copy)]
@ -2578,10 +2629,14 @@ pub union Elf32_auxv_t__bindgen_ty_1 {
pub a_val: u32, pub a_val: u32,
} }
impl Clone for Elf32_auxv_t__bindgen_ty_1 { impl Clone for Elf32_auxv_t__bindgen_ty_1 {
fn clone(&self) -> Self { *self } fn clone(&self) -> Self {
*self
}
} }
impl Clone for Elf32_auxv_t { impl Clone for Elf32_auxv_t {
fn clone(&self) -> Self { *self } fn clone(&self) -> Self {
*self
}
} }
#[repr(C)] #[repr(C)]
#[derive(Copy)] #[derive(Copy)]
@ -2595,10 +2650,14 @@ pub union Elf64_auxv_t__bindgen_ty_1 {
pub a_val: u64, pub a_val: u64,
} }
impl Clone for Elf64_auxv_t__bindgen_ty_1 { impl Clone for Elf64_auxv_t__bindgen_ty_1 {
fn clone(&self) -> Self { *self } fn clone(&self) -> Self {
*self
}
} }
impl Clone for Elf64_auxv_t { impl Clone for Elf64_auxv_t {
fn clone(&self) -> Self { *self } fn clone(&self) -> Self {
*self
}
} }
#[repr(C)] #[repr(C)]
#[derive(Debug, Copy)] #[derive(Debug, Copy)]
@ -2608,7 +2667,9 @@ pub struct Elf32_Nhdr {
pub n_type: Elf32_Word, pub n_type: Elf32_Word,
} }
impl Clone for Elf32_Nhdr { impl Clone for Elf32_Nhdr {
fn clone(&self) -> Self { *self } fn clone(&self) -> Self {
*self
}
} }
#[repr(C)] #[repr(C)]
#[derive(Debug, Copy)] #[derive(Debug, Copy)]
@ -2618,7 +2679,9 @@ pub struct Elf64_Nhdr {
pub n_type: Elf64_Word, pub n_type: Elf64_Word,
} }
impl Clone for Elf64_Nhdr { impl Clone for Elf64_Nhdr {
fn clone(&self) -> Self { *self } fn clone(&self) -> Self {
*self
}
} }
#[repr(C)] #[repr(C)]
#[derive(Debug, Copy)] #[derive(Debug, Copy)]
@ -2630,7 +2693,9 @@ pub struct Elf32_Move {
pub m_stride: Elf32_Half, pub m_stride: Elf32_Half,
} }
impl Clone for Elf32_Move { impl Clone for Elf32_Move {
fn clone(&self) -> Self { *self } fn clone(&self) -> Self {
*self
}
} }
#[repr(C)] #[repr(C)]
#[derive(Debug, Copy)] #[derive(Debug, Copy)]
@ -2642,7 +2707,9 @@ pub struct Elf64_Move {
pub m_stride: Elf64_Half, pub m_stride: Elf64_Half,
} }
impl Clone for Elf64_Move { impl Clone for Elf64_Move {
fn clone(&self) -> Self { *self } fn clone(&self) -> Self {
*self
}
} }
#[repr(C)] #[repr(C)]
#[derive(Copy)] #[derive(Copy)]
@ -2657,7 +2724,9 @@ pub struct Elf32_gptab__bindgen_ty_1 {
pub gt_unused: Elf32_Word, pub gt_unused: Elf32_Word,
} }
impl Clone for Elf32_gptab__bindgen_ty_1 { impl Clone for Elf32_gptab__bindgen_ty_1 {
fn clone(&self) -> Self { *self } fn clone(&self) -> Self {
*self
}
} }
#[repr(C)] #[repr(C)]
#[derive(Debug, Copy)] #[derive(Debug, Copy)]
@ -2666,10 +2735,14 @@ pub struct Elf32_gptab__bindgen_ty_2 {
pub gt_bytes: Elf32_Word, pub gt_bytes: Elf32_Word,
} }
impl Clone for Elf32_gptab__bindgen_ty_2 { impl Clone for Elf32_gptab__bindgen_ty_2 {
fn clone(&self) -> Self { *self } fn clone(&self) -> Self {
*self
}
} }
impl Clone for Elf32_gptab { impl Clone for Elf32_gptab {
fn clone(&self) -> Self { *self } fn clone(&self) -> Self {
*self
}
} }
#[repr(C)] #[repr(C)]
#[derive(Debug, Copy)] #[derive(Debug, Copy)]
@ -2679,7 +2752,9 @@ pub struct Elf32_RegInfo {
pub ri_gp_value: Elf32_Sword, pub ri_gp_value: Elf32_Sword,
} }
impl Clone for Elf32_RegInfo { impl Clone for Elf32_RegInfo {
fn clone(&self) -> Self { *self } fn clone(&self) -> Self {
*self
}
} }
#[repr(C)] #[repr(C)]
#[derive(Debug, Copy)] #[derive(Debug, Copy)]
@ -2690,7 +2765,9 @@ pub struct Elf_Options {
pub info: Elf32_Word, pub info: Elf32_Word,
} }
impl Clone for Elf_Options { impl Clone for Elf_Options {
fn clone(&self) -> Self { *self } fn clone(&self) -> Self {
*self
}
} }
#[repr(C)] #[repr(C)]
#[derive(Debug, Copy)] #[derive(Debug, Copy)]
@ -2699,7 +2776,9 @@ pub struct Elf_Options_Hw {
pub hwp_flags2: Elf32_Word, pub hwp_flags2: Elf32_Word,
} }
impl Clone for Elf_Options_Hw { impl Clone for Elf_Options_Hw {
fn clone(&self) -> Self { *self } fn clone(&self) -> Self {
*self
}
} }
#[repr(C)] #[repr(C)]
#[derive(Debug, Copy)] #[derive(Debug, Copy)]
@ -2711,7 +2790,9 @@ pub struct Elf32_Lib {
pub l_flags: Elf32_Word, pub l_flags: Elf32_Word,
} }
impl Clone for Elf32_Lib { impl Clone for Elf32_Lib {
fn clone(&self) -> Self { *self } fn clone(&self) -> Self {
*self
}
} }
#[repr(C)] #[repr(C)]
#[derive(Debug, Copy)] #[derive(Debug, Copy)]
@ -2723,17 +2804,31 @@ pub struct Elf64_Lib {
pub l_flags: Elf64_Word, pub l_flags: Elf64_Word,
} }
impl Clone for Elf64_Lib { impl Clone for Elf64_Lib {
fn clone(&self) -> Self { *self } fn clone(&self) -> Self {
*self
}
} }
pub type Elf32_Conflict = Elf32_Addr; pub type Elf32_Conflict = Elf32_Addr;
#[repr(C)] #[repr(C)]
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub struct EXIDX_Entry(u32, u32); pub struct EXIDX_Entry(u32, u32);
pub fn ELF32_R_SYM(info: Elf32_Word) -> Elf32_Word { info >> 8 } pub fn ELF32_R_SYM(info: Elf32_Word) -> Elf32_Word {
pub fn ELF32_R_TYPE(info: Elf32_Word) -> u8 { info as u8 } info >> 8
pub fn ELF32_R_INFO(sym: Elf32_Word, ty: u8) -> Elf32_Word { sym << 8 | ty as Elf32_Word } }
pub fn ELF32_R_TYPE(info: Elf32_Word) -> u8 {
info as u8
}
pub fn ELF32_R_INFO(sym: Elf32_Word, ty: u8) -> Elf32_Word {
sym << 8 | ty as Elf32_Word
}
pub fn ELF32_ST_BIND(info: u8) -> u8 { info >> 4 } pub fn ELF32_ST_BIND(info: u8) -> u8 {
pub fn ELF32_ST_TYPE(info: u8) -> u8 { info & 0xf } info >> 4
pub fn ELF32_ST_INFO(bind: u8, ty: u8) -> u8 { (bind << 4) | (ty & 0xf) } }
pub fn ELF32_ST_TYPE(info: u8) -> u8 {
info & 0xf
}
pub fn ELF32_ST_INFO(bind: u8, ty: u8) -> u8 {
(bind << 4) | (ty & 0xf)
}

View File

@ -1,8 +1,8 @@
use core::{mem, ptr, ops::{Deref, Range}}; use core::{mem,
use super::{ ops::{Deref, Range},
Arch, ptr};
elf::*,
}; use super::{elf::*, Arch};
fn read_unaligned<T: Copy>(data: &[u8], offset: usize) -> Option<T> { fn read_unaligned<T: Copy>(data: &[u8], offset: usize) -> Option<T> {
if data.len() < offset + mem::size_of::<T>() { if data.len() < offset + mem::size_of::<T>() {
@ -31,14 +31,40 @@ impl<'a> File<'a> {
pub fn arch(&self) -> Option<Arch> { pub fn arch(&self) -> Option<Arch> {
const IDENT_OPENRISC: [u8; EI_NIDENT] = [ const IDENT_OPENRISC: [u8; EI_NIDENT] = [
ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3, ELFMAG0,
ELFCLASS32, ELFDATA2MSB, EV_CURRENT, ELFOSABI_NONE, ELFMAG1,
/* ABI version */ 0, /* padding */ 0, 0, 0, 0, 0, 0, 0 ELFMAG2,
ELFMAG3,
ELFCLASS32,
ELFDATA2MSB,
EV_CURRENT,
ELFOSABI_NONE,
/* ABI version */ 0,
/* padding */ 0,
0,
0,
0,
0,
0,
0,
]; ];
const IDENT_ARM: [u8; EI_NIDENT] = [ const IDENT_ARM: [u8; EI_NIDENT] = [
ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3, ELFMAG0,
ELFCLASS32, ELFDATA2LSB, EV_CURRENT, ELFOSABI_NONE, ELFMAG1,
/* ABI version */ 0, /* padding */ 0, 0, 0, 0, 0, 0, 0 ELFMAG2,
ELFMAG3,
ELFCLASS32,
ELFDATA2LSB,
EV_CURRENT,
ELFOSABI_NONE,
/* ABI version */ 0,
/* padding */ 0,
0,
0,
0,
0,
0,
0,
]; ];
match (self.ehdr.e_ident, self.ehdr.e_machine) { match (self.ehdr.e_ident, self.ehdr.e_machine) {
@ -48,16 +74,14 @@ impl<'a> File<'a> {
} }
} }
pub fn program_headers<'b>(&'b self) -> impl Iterator<Item = Option<Elf32_Phdr>> + 'b pub fn program_headers<'b>(&'b self) -> impl Iterator<Item = Option<Elf32_Phdr>> + 'b {
{
(0..self.ehdr.e_phnum).map(move |i| { (0..self.ehdr.e_phnum).map(move |i| {
let phdr_off = self.ehdr.e_phoff as usize + mem::size_of::<Elf32_Phdr>() * i as usize; let phdr_off = self.ehdr.e_phoff as usize + mem::size_of::<Elf32_Phdr>() * i as usize;
self.read_unaligned::<Elf32_Phdr>(phdr_off) self.read_unaligned::<Elf32_Phdr>(phdr_off)
}) })
} }
pub fn section_headers<'b>(&'b self) -> impl Iterator<Item = Option<Elf32_Shdr>> + 'b pub fn section_headers<'b>(&'b self) -> impl Iterator<Item = Option<Elf32_Shdr>> + 'b {
{
(0..self.ehdr.e_shnum).map(move |i| { (0..self.ehdr.e_shnum).map(move |i| {
let shdr_off = self.ehdr.e_shoff as usize + mem::size_of::<Elf32_Shdr>() * i as usize; let shdr_off = self.ehdr.e_shoff as usize + mem::size_of::<Elf32_Shdr>() * i as usize;
self.read_unaligned::<Elf32_Shdr>(shdr_off) self.read_unaligned::<Elf32_Shdr>(shdr_off)

View File

@ -1,13 +1,9 @@
use core::{
ops::{Deref, DerefMut, Range},
mem,
slice,
};
use alloc::alloc::{alloc_zeroed, dealloc, Layout, LayoutError}; use alloc::alloc::{alloc_zeroed, dealloc, Layout, LayoutError};
use super::{ use core::{mem,
elf::*, ops::{Deref, DerefMut, Range},
Error, slice};
};
use super::{elf::*, Error};
pub struct DynamicSection { pub struct DynamicSection {
pub strtab: Range<usize>, pub strtab: Range<usize>,
@ -34,17 +30,12 @@ impl Image {
slice::from_raw_parts_mut(ptr, size) slice::from_raw_parts_mut(ptr, size)
}; };
Ok(Image { Ok(Image { layout, data })
layout,
data,
})
} }
/// assumes that self.data is properly aligned /// assumes that self.data is properly aligned
pub(crate) fn get_ref<T>(&self, offset: usize) -> Option<&T> pub(crate) fn get_ref<T>(&self, offset: usize) -> Option<&T>
where where T: Copy {
T: Copy,
{
if self.data.len() < offset + mem::size_of::<T>() { if self.data.len() < offset + mem::size_of::<T>() {
None None
} else if (self.data.as_ptr() as usize + offset) & (mem::align_of::<T>() - 1) != 0 { } else if (self.data.as_ptr() as usize + offset) & (mem::align_of::<T>() - 1) != 0 {
@ -66,55 +57,53 @@ impl Image {
unsafe { slice::from_raw_parts(ptr, len) } unsafe { slice::from_raw_parts(ptr, len) }
} }
fn dyn_headers<'a>(&'a self, range: Range<usize>) -> fn dyn_headers<'a>(&'a self, range: Range<usize>) -> impl Iterator<Item = &'a Elf32_Dyn> + 'a {
impl Iterator<Item = &'a Elf32_Dyn> + 'a
{
range range
.step_by(mem::size_of::<Elf32_Dyn>()) .step_by(mem::size_of::<Elf32_Dyn>())
.filter_map(move |offset| { .filter_map(move |offset| self.get_ref::<Elf32_Dyn>(offset))
self.get_ref::<Elf32_Dyn>(offset)
})
.take_while(|d| unsafe { d.d_un.d_val } as i32 != DT_NULL) .take_while(|d| unsafe { d.d_un.d_val } as i32 != DT_NULL)
} }
pub fn dyn_section(&self, range: Range<usize>) -> Result<DynamicSection, Error> { pub fn dyn_section(&self, range: Range<usize>) -> Result<DynamicSection, Error> {
let (mut strtab_off, mut strtab_sz) = (0, 0); let (mut strtab_off, mut strtab_sz) = (0, 0);
let (mut rel_off, mut rel_sz) = (0, 0); let (mut rel_off, mut rel_sz) = (0, 0);
let (mut rela_off, mut rela_sz) = (0, 0); let (mut rela_off, mut rela_sz) = (0, 0);
let (mut pltrel_off, mut pltrel_sz) = (0, 0); let (mut pltrel_off, mut pltrel_sz) = (0, 0);
let (mut hash_off, mut hash_sz) = (0, 0); let (mut hash_off, mut hash_sz) = (0, 0);
let mut symtab_off = 0; let mut symtab_off = 0;
let mut sym_ent = 0; let mut sym_ent = 0;
let mut rel_ent = 0; let mut rel_ent = 0;
let mut rela_ent = 0; let mut rela_ent = 0;
let mut nbucket = 0; let mut nbucket = 0;
let mut nchain = 0; let mut nchain = 0;
for dyn_header in self.dyn_headers(range) { for dyn_header in self.dyn_headers(range) {
let val = unsafe { dyn_header.d_un.d_val } as usize; let val = unsafe { dyn_header.d_un.d_val } as usize;
match dyn_header.d_tag { match dyn_header.d_tag {
DT_NULL => break, DT_NULL => break,
DT_STRTAB => strtab_off = val, DT_STRTAB => strtab_off = val,
DT_STRSZ => strtab_sz = val, DT_STRSZ => strtab_sz = val,
DT_SYMTAB => symtab_off = val, DT_SYMTAB => symtab_off = val,
DT_SYMENT => sym_ent = val, DT_SYMENT => sym_ent = val,
DT_REL => rel_off = val, DT_REL => rel_off = val,
DT_RELSZ => rel_sz = val, DT_RELSZ => rel_sz = val,
DT_RELENT => rel_ent = val, DT_RELENT => rel_ent = val,
DT_RELA => rela_off = val, DT_RELA => rela_off = val,
DT_RELASZ => rela_sz = val, DT_RELASZ => rela_sz = val,
DT_RELAENT => rela_ent = val, DT_RELAENT => rela_ent = val,
DT_JMPREL => pltrel_off = val, DT_JMPREL => pltrel_off = val,
DT_PLTRELSZ => pltrel_sz = val, DT_PLTRELSZ => pltrel_sz = val,
DT_HASH => { DT_HASH => {
nbucket = *self.get_ref::<Elf32_Word>(val + 0) nbucket = *self
.get_ref::<Elf32_Word>(val + 0)
.ok_or("cannot read hash bucket count")? as usize; .ok_or("cannot read hash bucket count")? as usize;
nchain = *self.get_ref::<Elf32_Word>(val + 4) nchain = *self
.get_ref::<Elf32_Word>(val + 4)
.ok_or("cannot read hash chain count")? as usize; .ok_or("cannot read hash chain count")? as usize;
hash_off = val + 8; hash_off = val + 8;
hash_sz = (nbucket + nchain) * mem::size_of::<Elf32_Word>(); hash_sz = (nbucket + nchain) * mem::size_of::<Elf32_Word>();
} }
_ => () _ => (),
} }
} }
@ -123,28 +112,28 @@ impl Image {
let symtab_sz = nchain * mem::size_of::<Elf32_Sym>(); let symtab_sz = nchain * mem::size_of::<Elf32_Sym>();
if strtab_off + strtab_sz > self.data.len() { if strtab_off + strtab_sz > self.data.len() {
return Err("invalid strtab offset/size")? return Err("invalid strtab offset/size")?;
} }
if symtab_off + symtab_sz > self.data.len() { if symtab_off + symtab_sz > self.data.len() {
return Err("invalid symtab offset/size")? return Err("invalid symtab offset/size")?;
} }
if sym_ent != mem::size_of::<Elf32_Sym>() { if sym_ent != mem::size_of::<Elf32_Sym>() {
return Err("incorrect symbol entry size")? return Err("incorrect symbol entry size")?;
} }
if rel_off + rel_sz > self.data.len() { if rel_off + rel_sz > self.data.len() {
return Err("invalid rel offset/size")? return Err("invalid rel offset/size")?;
} }
if rel_ent != 0 && rel_ent != mem::size_of::<Elf32_Rel>() { if rel_ent != 0 && rel_ent != mem::size_of::<Elf32_Rel>() {
return Err("incorrect relocation entry size")? return Err("incorrect relocation entry size")?;
} }
if rela_off + rela_sz > self.data.len() { if rela_off + rela_sz > self.data.len() {
return Err("invalid rela offset/size")? return Err("invalid rela offset/size")?;
} }
if rela_ent != 0 && rela_ent != mem::size_of::<Elf32_Rela>() { if rela_ent != 0 && rela_ent != mem::size_of::<Elf32_Rela>() {
return Err("incorrect relocation entry size")? return Err("incorrect relocation entry size")?;
} }
if pltrel_off + pltrel_sz > self.data.len() { if pltrel_off + pltrel_sz > self.data.len() {
return Err("invalid pltrel offset/size")? return Err("invalid pltrel offset/size")?;
} }
Ok(DynamicSection { Ok(DynamicSection {
@ -165,7 +154,7 @@ impl Image {
pub fn write(&self, offset: usize, value: Elf32_Word) -> Result<(), Error> { pub fn write(&self, offset: usize, value: Elf32_Word) -> Result<(), Error> {
if offset + mem::size_of::<Elf32_Addr>() > self.data.len() { if offset + mem::size_of::<Elf32_Addr>() > self.data.len() {
return Err("relocation out of image bounds")? return Err("relocation out of image bounds")?;
} }
let ptr = (self.data.as_ptr() as usize + offset) as *mut Elf32_Addr; let ptr = (self.data.as_ptr() as usize + offset) as *mut Elf32_Addr;

View File

@ -1,13 +1,14 @@
#![no_std] #![no_std]
extern crate alloc; extern crate alloc;
extern crate log;
extern crate libcortex_a9; extern crate libcortex_a9;
extern crate log;
use core::{convert, fmt, ops::Range, str};
use alloc::string::String; use alloc::string::String;
use log::{debug, trace}; use core::{convert, fmt, ops::Range, str};
use elf::*; use elf::*;
use log::{debug, trace};
pub mod elf; pub mod elf;
mod file; mod file;
@ -21,11 +22,10 @@ pub enum Arch {
OpenRisc, OpenRisc,
} }
#[derive(Debug)] #[derive(Debug)]
pub enum Error { pub enum Error {
Parsing(&'static str), Parsing(&'static str),
Lookup(String) Lookup(String),
} }
impl convert::From<&'static str> for Error { impl convert::From<&'static str> for Error {
@ -37,10 +37,8 @@ impl convert::From<&'static str> for Error {
impl fmt::Display for Error { impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self { match self {
&Error::Parsing(desc) => &Error::Parsing(desc) => write!(f, "parse error: {}", desc),
write!(f, "parse error: {}", desc), &Error::Lookup(ref sym) => write!(f, "symbol lookup error: {}", sym),
&Error::Lookup(ref sym) =>
write!(f, "symbol lookup error: {}", sym),
} }
} }
} }
@ -103,20 +101,22 @@ impl Library {
let mut index = self.hash_bucket()[hash as usize % self.hash_bucket().len()] as usize; let mut index = self.hash_bucket()[hash as usize % self.hash_bucket().len()] as usize;
loop { loop {
if index == STN_UNDEF { return None } if index == STN_UNDEF {
return None;
}
let sym = &self.symtab()[index]; let sym = &self.symtab()[index];
let sym_name_off = sym.st_name as usize; let sym_name_off = sym.st_name as usize;
match self.strtab().get(sym_name_off..sym_name_off + name.len()) { match self.strtab().get(sym_name_off..sym_name_off + name.len()) {
Some(sym_name) if sym_name == name => { Some(sym_name) if sym_name == name => {
if ELF32_ST_BIND(sym.st_info) & STB_GLOBAL == 0 { if ELF32_ST_BIND(sym.st_info) & STB_GLOBAL == 0 {
return None return None;
} }
match sym.st_shndx { match sym.st_shndx {
SHN_UNDEF => return None, SHN_UNDEF => return None,
SHN_ABS => return Some(self.image.ptr() as u32 + sym.st_value), SHN_ABS => return Some(self.image.ptr() as u32 + sym.st_value),
_ => return Some(self.image.ptr() as u32 + sym.st_value) _ => return Some(self.image.ptr() as u32 + sym.st_value),
} }
} }
_ => (), _ => (),
@ -127,10 +127,16 @@ impl Library {
} }
pub fn name_starting_at(&self, offset: usize) -> Result<&[u8], Error> { pub fn name_starting_at(&self, offset: usize) -> Result<&[u8], Error> {
let size = self.strtab().iter().skip(offset).position(|&x| x == 0) let size = self
.ok_or("symbol in symbol table not null-terminated")?; .strtab()
Ok(self.strtab().get(offset..offset + size) .iter()
.ok_or("cannot read symbol name")?) .skip(offset)
.position(|&x| x == 0)
.ok_or("symbol in symbol table not null-terminated")?;
Ok(self
.strtab()
.get(offset..offset + size)
.ok_or("cannot read symbol name")?)
} }
/// Rebind Rela by `name` to a new `addr` /// Rebind Rela by `name` to a new `addr`
@ -143,53 +149,59 @@ impl Library {
} }
} }
pub fn load( pub fn load(data: &[u8], resolve: &dyn Fn(&[u8]) -> Option<Elf32_Word>) -> Result<Library, Error> {
data: &[u8],
resolve: &dyn Fn(&[u8]) -> Option<Elf32_Word>
) -> Result<Library, Error> {
// validate ELF file // validate ELF file
let file = file::File::new(data) let file = file::File::new(data).ok_or("cannot read ELF header")?;
.ok_or("cannot read ELF header")?;
if file.ehdr.e_type != ET_DYN { if file.ehdr.e_type != ET_DYN {
return Err("not a shared library")? return Err("not a shared library")?;
} }
let arch = file.arch() let arch = file.arch().ok_or("not for a supported architecture")?;
.ok_or("not for a supported architecture")?;
// prepare target memory // prepare target memory
let image_size = file.program_headers() let image_size = file
.program_headers()
.filter_map(|phdr| phdr.map(|phdr| phdr.p_vaddr + phdr.p_memsz)) .filter_map(|phdr| phdr.map(|phdr| phdr.p_vaddr + phdr.p_memsz))
.max() .max()
.unwrap_or(0) as usize; .unwrap_or(0) as usize;
let image_align = file.program_headers() let image_align = file
.filter_map(|phdr| phdr.and_then(|phdr| { .program_headers()
if phdr.p_type == PT_LOAD { .filter_map(|phdr| {
Some(phdr.p_align) phdr.and_then(|phdr| {
} else { if phdr.p_type == PT_LOAD {
None Some(phdr.p_align)
} } else {
})) None
}
})
})
.max() .max()
.unwrap_or(4) as usize; .unwrap_or(4) as usize;
// 1 image for all segments // 1 image for all segments
let mut image = image::Image::new(image_size, image_align) let mut image = image::Image::new(image_size, image_align).map_err(|_| "cannot allocate target image")?;
.map_err(|_| "cannot allocate target image")?; debug!(
debug!("ELF target: {} bytes, align to {:X}, allocated at {:08X}", image_size, image_align, image.ptr() as usize); "ELF target: {} bytes, align to {:X}, allocated at {:08X}",
image_size,
image_align,
image.ptr() as usize
);
// LOAD // LOAD
for phdr in file.program_headers() { for phdr in file.program_headers() {
let phdr = phdr.ok_or("cannot read program header")?; let phdr = phdr.ok_or("cannot read program header")?;
trace!("Program header: {:08X}+{:08X} to {:08X}", trace!(
phdr.p_offset, phdr.p_filesz, "Program header: {:08X}+{:08X} to {:08X}",
image.ptr() as u32 phdr.p_offset,
phdr.p_filesz,
image.ptr() as u32
); );
let file_range = phdr.p_offset as usize..(phdr.p_offset + phdr.p_filesz) as usize; let file_range = phdr.p_offset as usize..(phdr.p_offset + phdr.p_filesz) as usize;
match phdr.p_type { match phdr.p_type {
PT_LOAD => { PT_LOAD => {
let src = file.get(file_range) let src = file
.get(file_range)
.ok_or("program header requests an out of bounds load (in file)")?; .ok_or("program header requests an out of bounds load (in file)")?;
let dst = image.get_mut(phdr.p_vaddr as usize.. let dst = image
(phdr.p_vaddr + phdr.p_filesz) as usize) .get_mut(phdr.p_vaddr as usize..(phdr.p_vaddr + phdr.p_filesz) as usize)
.ok_or("program header requests an out of bounds load (in target)")?; .ok_or("program header requests an out of bounds load (in target)")?;
dst.copy_from_slice(src); dst.copy_from_slice(src);
} }
@ -203,9 +215,9 @@ pub fn load(
let shdr = shdr.ok_or("cannot read section header")?; let shdr = shdr.ok_or("cannot read section header")?;
match shdr.sh_type as usize { match shdr.sh_type as usize {
SHT_ARM_EXIDX => { SHT_ARM_EXIDX => {
let range = shdr.sh_addr as usize.. let range = shdr.sh_addr as usize..(shdr.sh_addr + shdr.sh_size) as usize;
(shdr.sh_addr + shdr.sh_size) as usize; let _ = image
let _ = image.get(range.clone()) .get(range.clone())
.ok_or("section header specifies EXIDX outside of image (in target)")?; .ok_or("section header specifies EXIDX outside of image (in target)")?;
exidx = Some(range); exidx = Some(range);
} }
@ -214,11 +226,14 @@ pub fn load(
} }
// relocate DYNAMIC // relocate DYNAMIC
let dyn_range = file.dyn_header_vaddr() let dyn_range = file.dyn_header_vaddr().ok_or("cannot find a dynamic header")?;
.ok_or("cannot find a dynamic header")?;
let dyn_section = image.dyn_section(dyn_range.clone())?; let dyn_section = image.dyn_section(dyn_range.clone())?;
debug!("Relocating {} rela, {} rel, {} pltrel", debug!(
dyn_section.rela.len(), dyn_section.rel.len(), dyn_section.pltrel.len()); "Relocating {} rela, {} rel, {} pltrel",
dyn_section.rela.len(),
dyn_section.rel.len(),
dyn_section.pltrel.len()
);
let lib = Library { let lib = Library {
arch, arch,
image, image,

View File

@ -1,16 +1,10 @@
use alloc::string::String; use alloc::string::String;
use libcortex_a9::{asm::{dsb, isb},
cache::{bpiall, dcci_slice, iciallu}};
use log::trace; use log::trace;
use super::{
Arch, use super::{elf::*, image::Image, Arch, Error, Library};
elf::*,
Error,
image::Image,
Library,
};
use libcortex_a9::{
cache::{dcci_slice, iciallu, bpiall},
asm::{dsb, isb},
};
pub trait Relocatable { pub trait Relocatable {
fn offset(&self) -> usize; fn offset(&self) -> usize;
@ -66,25 +60,18 @@ enum RelType {
impl RelType { impl RelType {
pub fn new(arch: Arch, type_info: u8) -> Option<Self> { pub fn new(arch: Arch, type_info: u8) -> Option<Self> {
match type_info { match type_info {
R_OR1K_NONE if arch == Arch::OpenRisc => R_OR1K_NONE if arch == Arch::OpenRisc => Some(RelType::None),
Some(RelType::None), R_ARM_NONE if arch == Arch::Arm => Some(RelType::None),
R_ARM_NONE if arch == Arch::Arm =>
Some(RelType::None),
R_OR1K_RELATIVE if arch == Arch::OpenRisc => R_OR1K_RELATIVE if arch == Arch::OpenRisc => Some(RelType::Relative),
Some(RelType::Relative), R_ARM_RELATIVE if arch == Arch::Arm => Some(RelType::Relative),
R_ARM_RELATIVE if arch == Arch::Arm =>
Some(RelType::Relative),
R_OR1K_32 | R_OR1K_GLOB_DAT | R_OR1K_JMP_SLOT R_OR1K_32 | R_OR1K_GLOB_DAT | R_OR1K_JMP_SLOT if arch == Arch::OpenRisc => Some(RelType::LookupAbs),
if arch == Arch::OpenRisc => Some(RelType::LookupAbs), R_ARM_GLOB_DAT | R_ARM_JUMP_SLOT | R_ARM_ABS32 if arch == Arch::Arm => Some(RelType::LookupAbs),
R_ARM_GLOB_DAT | R_ARM_JUMP_SLOT | R_ARM_ABS32
if arch == Arch::Arm => Some(RelType::LookupAbs),
R_ARM_PREL31 if arch == Arch::Arm => Some(RelType::LookupRel), R_ARM_PREL31 if arch == Arch::Arm => Some(RelType::LookupRel),
_ => _ => None,
None
} }
} }
} }
@ -96,22 +83,25 @@ fn format_sym_name(sym_name: &[u8]) -> String {
} }
pub fn relocate<R: Relocatable>( pub fn relocate<R: Relocatable>(
arch: Arch, lib: &Library, arch: Arch,
rel: &R, resolve: &dyn Fn(&[u8]) -> Option<Elf32_Word> lib: &Library,
rel: &R,
resolve: &dyn Fn(&[u8]) -> Option<Elf32_Word>,
) -> Result<(), Error> { ) -> Result<(), Error> {
let sym; let sym;
if rel.sym_info() == 0 { if rel.sym_info() == 0 {
sym = None; sym = None;
} else { } else {
sym = Some(lib.symtab().get(rel.sym_info() as usize) sym = Some(
.ok_or("symbol out of bounds of symbol table")?) lib.symtab()
.get(rel.sym_info() as usize)
.ok_or("symbol out of bounds of symbol table")?,
)
} }
let rel_type = RelType::new(arch, rel.type_info()) let rel_type = RelType::new(arch, rel.type_info()).ok_or("unsupported relocation type")?;
.ok_or("unsupported relocation type")?;
let value = match rel_type { let value = match rel_type {
RelType::None => RelType::None => return Ok(()),
return Ok(()),
RelType::Relative => { RelType::Relative => {
let addend = rel.addend(&lib.image); let addend = rel.addend(&lib.image);
@ -132,42 +122,48 @@ pub fn relocate<R: Relocatable>(
addr addr
} else { } else {
// We couldn't find it anywhere. // We couldn't find it anywhere.
return Err(Error::Lookup(format_sym_name(sym_name))) return Err(Error::Lookup(format_sym_name(sym_name)));
}; };
match rel_type { match rel_type {
RelType::LookupAbs => sym_addr, RelType::LookupAbs => sym_addr,
RelType::LookupRel => RelType::LookupRel => {
sym_addr.wrapping_sub( sym_addr.wrapping_sub(lib.image.ptr().wrapping_offset(rel.offset() as isize) as Elf32_Addr)
lib.image.ptr().wrapping_offset(rel.offset() as isize) as Elf32_Addr), }
_ => unreachable!() _ => unreachable!(),
} }
} }
}; };
match rel.type_info() { match rel.type_info() {
R_ARM_PREL31 => { R_ARM_PREL31 => {
let reloc_word = lib.image.get_ref::<Elf32_Word>(rel.offset()) let reloc_word = lib
.ok_or("relocation offset cannot be read")?; .image
lib.image.write(rel.offset(), (reloc_word & 0x80000000) | (value & 0x7FFFFFFF)) .get_ref::<Elf32_Word>(rel.offset())
}, .ok_or("relocation offset cannot be read")?;
lib.image
.write(rel.offset(), (reloc_word & 0x80000000) | (value & 0x7FFFFFFF))
}
_ => lib.image.write(rel.offset(), value), _ => lib.image.write(rel.offset(), value),
} }
} }
pub fn rebind( pub fn rebind(arch: Arch, lib: &Library, name: &[u8], value: Elf32_Word) -> Result<(), Error> {
arch: Arch, lib: &Library, name: &[u8], value: Elf32_Word
) -> Result<(), Error> {
fn rebind_symbol_to_value<R: Relocatable>( fn rebind_symbol_to_value<R: Relocatable>(
arch: Arch, lib: &Library,name: &[u8], value: Elf32_Word, relocs: &[R] arch: Arch,
lib: &Library,
name: &[u8],
value: Elf32_Word,
relocs: &[R],
) -> Result<(), Error> { ) -> Result<(), Error> {
for reloc in relocs { for reloc in relocs {
let rel_type = RelType::new(arch, reloc.type_info()) let rel_type = RelType::new(arch, reloc.type_info()).ok_or("unsupported relocation type")?;
.ok_or("unsupported relocation type")?;
match rel_type { match rel_type {
RelType::LookupAbs => { RelType::LookupAbs => {
let sym = lib.symtab().get(reloc.sym_info() as usize) let sym = lib
.symtab()
.get(reloc.sym_info() as usize)
.ok_or("symbol out of bounds of symbol table")?; .ok_or("symbol out of bounds of symbol table")?;
let sym_name = lib.name_starting_at(sym.st_name as usize)?; let sym_name = lib.name_starting_at(sym.st_name as usize)?;

View File

@ -1,9 +1,9 @@
use core_io::{Read, Write, Error as IoError}; use core_io::{Error as IoError, Read, Write};
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Cursor<T> { pub struct Cursor<T> {
inner: T, inner: T,
pos: usize pos: usize,
} }
impl<T> Cursor<T> { impl<T> Cursor<T> {
@ -39,7 +39,6 @@ impl<T> Cursor<T> {
} }
impl<T: AsRef<[u8]>> Read for Cursor<T> { impl<T: AsRef<[u8]>> Read for Cursor<T> {
fn read(&mut self, buf: &mut [u8]) -> Result<usize, IoError> { fn read(&mut self, buf: &mut [u8]) -> Result<usize, IoError> {
let data = &self.inner.as_ref()[self.pos..]; let data = &self.inner.as_ref()[self.pos..];
let len = buf.len().min(data.len()); let len = buf.len().min(data.len());
@ -50,10 +49,9 @@ impl<T: AsRef<[u8]>> Read for Cursor<T> {
} }
impl Write for Cursor<&mut [u8]> { impl Write for Cursor<&mut [u8]> {
fn write(&mut self, buf: &[u8]) -> Result<usize, IoError> { fn write(&mut self, buf: &[u8]) -> Result<usize, IoError> {
let data = &mut self.inner[self.pos..]; let data = &mut self.inner[self.pos..];
let len = buf.len().min(data.len()); let len = buf.len().min(data.len());
data[..len].copy_from_slice(&buf[..len]); data[..len].copy_from_slice(&buf[..len]);
self.pos += len; self.pos += len;
Ok(len) Ok(len)
@ -67,7 +65,6 @@ impl Write for Cursor<&mut [u8]> {
#[cfg(feature = "alloc")] #[cfg(feature = "alloc")]
impl Write for Cursor<::alloc::Vec<u8>> { impl Write for Cursor<::alloc::Vec<u8>> {
#[inline] #[inline]
fn write(&mut self, buf: &[u8]) -> Result<usize, IoError> { fn write(&mut self, buf: &[u8]) -> Result<usize, IoError> {
self.inner.extend_from_slice(buf); self.inner.extend_from_slice(buf);

View File

@ -16,7 +16,7 @@ pub mod cursor;
pub mod proto; pub mod proto;
pub use cursor::Cursor; pub use cursor::Cursor;
#[cfg(all(feature = "byteorder", feature = "alloc"))]
pub use proto::ReadStringError;
#[cfg(feature = "byteorder")] #[cfg(feature = "byteorder")]
pub use proto::{ProtoRead, ProtoWrite}; pub use proto::{ProtoRead, ProtoWrite};
#[cfg(all(feature = "byteorder", feature = "alloc"))]
pub use proto::ReadStringError;

View File

@ -1,15 +1,14 @@
use alloc::{string::String, vec};
use core::str::Utf8Error; use core::str::Utf8Error;
use byteorder::{ByteOrder, NativeEndian};
use alloc::vec;
use alloc::string::String;
use core_io::{Read, Write, Error as IoError}; use byteorder::{ByteOrder, NativeEndian};
use core_io::{Error as IoError, Read, Write};
#[allow(dead_code)] #[allow(dead_code)]
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub enum ReadStringError<T> { pub enum ReadStringError<T> {
Utf8(Utf8Error), Utf8(Utf8Error),
Other(T) Other(T),
} }
pub trait ProtoRead { pub trait ProtoRead {
@ -141,7 +140,9 @@ pub trait ProtoWrite {
} }
} }
impl<T> ProtoRead for T where T: Read + ?Sized { impl<T> ProtoRead for T
where T: Read + ?Sized
{
type ReadError = IoError; type ReadError = IoError;
fn read_exact(&mut self, buf: &mut [u8]) -> Result<(), Self::ReadError> { fn read_exact(&mut self, buf: &mut [u8]) -> Result<(), Self::ReadError> {
@ -149,7 +150,9 @@ impl<T> ProtoRead for T where T: Read + ?Sized {
} }
} }
impl<T> ProtoWrite for T where T: Write + ?Sized { impl<T> ProtoWrite for T
where T: Write + ?Sized
{
type WriteError = IoError; type WriteError = IoError;
fn write_all(&mut self, buf: &[u8]) -> Result<(), Self::WriteError> { fn write_all(&mut self, buf: &[u8]) -> Result<(), Self::WriteError> {

View File

@ -1,27 +1,25 @@
use libc::{c_void, c_int}; use libc::{c_int, c_void};
use crate::libunwind as uw; use crate::libunwind as uw;
const UW_REG_SP: c_int = 13; const UW_REG_SP: c_int = 13;
pub fn backtrace<F>(f: F) -> Result<(), uw::_Unwind_Reason_Code> pub fn backtrace<F>(f: F) -> Result<(), uw::_Unwind_Reason_Code>
where F: FnMut(usize) -> () where F: FnMut(usize) -> () {
{
struct TraceContext<F> { struct TraceContext<F> {
step_fn: F, step_fn: F,
prev_sp: uw::_Unwind_Word prev_sp: uw::_Unwind_Word,
} }
extern fn trace<F>(context: *mut uw::_Unwind_Context, arg: *mut c_void) extern "C" fn trace<F>(context: *mut uw::_Unwind_Context, arg: *mut c_void) -> uw::_Unwind_Reason_Code
-> uw::_Unwind_Reason_Code where F: FnMut(usize) -> () {
where F: FnMut(usize) -> ()
{
unsafe { unsafe {
let trace_context = &mut *(arg as *mut TraceContext<F>); let trace_context = &mut *(arg as *mut TraceContext<F>);
// Detect the root of a libfringe thread // Detect the root of a libfringe thread
let cur_sp = uw::_Unwind_GetGR(context, UW_REG_SP); let cur_sp = uw::_Unwind_GetGR(context, UW_REG_SP);
if cur_sp == trace_context.prev_sp { if cur_sp == trace_context.prev_sp {
return uw::_URC_END_OF_STACK return uw::_URC_END_OF_STACK;
} else { } else {
trace_context.prev_sp = cur_sp; trace_context.prev_sp = cur_sp;
} }
@ -35,7 +33,7 @@ pub fn backtrace<F>(f: F) -> Result<(), uw::_Unwind_Reason_Code>
let mut trace_context = TraceContext { step_fn: f, prev_sp: 0 }; let mut trace_context = TraceContext { step_fn: f, prev_sp: 0 };
match uw::_Unwind_Backtrace(trace::<F>, &mut trace_context as *mut _ as *mut c_void) { match uw::_Unwind_Backtrace(trace::<F>, &mut trace_context as *mut _ as *mut c_void) {
uw::_URC_NO_REASON => Ok(()), uw::_URC_NO_REASON => Ok(()),
err => Err(err) err => Err(err),
} }
} }
} }

View File

@ -5,8 +5,7 @@ fn main() {
} }
mod llvm_libunwind { mod llvm_libunwind {
use std::path::Path; use std::{env, path::Path};
use std::env;
fn setup_options(cfg: &mut cc::Build) { fn setup_options(cfg: &mut cc::Build) {
cfg.no_default_flags(true); cfg.no_default_flags(true);
@ -82,11 +81,7 @@ mod llvm_libunwind {
cfg.flag("-fvisibility=hidden"); cfg.flag("-fvisibility=hidden");
cfg.flag_if_supported("-fvisibility-global-new-delete-hidden"); cfg.flag_if_supported("-fvisibility-global-new-delete-hidden");
let unwind_sources = vec![ let unwind_sources = vec!["Unwind-EHABI.cpp", "Unwind-seh.cpp", "libunwind.cpp"];
"Unwind-EHABI.cpp",
"Unwind-seh.cpp",
"libunwind.cpp"
];
let root = Path::new("../llvm_libunwind"); let root = Path::new("../llvm_libunwind");
cfg.include(root.join("include")); cfg.include(root.join("include"));

View File

@ -21,8 +21,7 @@ pub use _Unwind_Reason_Code::*;
pub type _Unwind_Exception_Class = u64; pub type _Unwind_Exception_Class = u64;
pub type _Unwind_Word = uintptr_t; pub type _Unwind_Word = uintptr_t;
pub type _Unwind_Ptr = uintptr_t; pub type _Unwind_Ptr = uintptr_t;
pub type _Unwind_Trace_Fn = pub type _Unwind_Trace_Fn = extern "C" fn(ctx: *mut _Unwind_Context, arg: *mut c_void) -> _Unwind_Reason_Code;
extern "C" fn(ctx: *mut _Unwind_Context, arg: *mut c_void) -> _Unwind_Reason_Code;
#[cfg(target_arch = "x86")] #[cfg(target_arch = "x86")]
pub const unwinder_private_data_size: usize = 5; pub const unwinder_private_data_size: usize = 5;
@ -279,7 +278,6 @@ if #[cfg(all(windows, target_arch = "x86_64", target_env = "gnu"))] {
} // cfg_if! } // cfg_if!
#[no_mangle] #[no_mangle]
extern fn abort() { extern "C" fn abort() {
panic!("Abort!"); panic!("Abort!");
} }

View File

@ -3,8 +3,7 @@ use libboard_zynq::smoltcp::Error;
use libcortex_a9::cache; use libcortex_a9::cache;
use log::{debug, info, warn}; use log::{debug, info, warn};
use crate::proto_async::*; use crate::{pl, proto_async::*};
use crate::pl;
const BUFFER_SIZE: usize = 512 * 1024; const BUFFER_SIZE: usize = 512 * 1024;
@ -13,9 +12,7 @@ struct Buffer {
data: [u8; BUFFER_SIZE], data: [u8; BUFFER_SIZE],
} }
static mut BUFFER: Buffer = Buffer { static mut BUFFER: Buffer = Buffer { data: [0; BUFFER_SIZE] };
data: [0; BUFFER_SIZE]
};
fn arm() { fn arm() {
debug!("arming RTIO analyzer"); debug!("arming RTIO analyzer");
@ -46,7 +43,7 @@ struct Header {
total_byte_count: u64, total_byte_count: u64,
error_occurred: bool, error_occurred: bool,
log_channel: u8, log_channel: u8,
dds_onehot_sel: bool dds_onehot_sel: bool,
} }
async fn write_header(stream: &mut TcpStream, header: &Header) -> Result<(), Error> { async fn write_header(stream: &mut TcpStream, header: &Header) -> Result<(), Error> {
@ -78,10 +75,14 @@ async fn handle_connection(stream: &mut TcpStream) -> Result<(), Error> {
let header = Header { let header = Header {
total_byte_count: total_byte_count, total_byte_count: total_byte_count,
sent_bytes: if wraparound { BUFFER_SIZE as u32 } else { total_byte_count as u32 }, sent_bytes: if wraparound {
BUFFER_SIZE as u32
} else {
total_byte_count as u32
},
error_occurred: overflow_occurred | bus_error_occurred, error_occurred: overflow_occurred | bus_error_occurred,
log_channel: pl::csr::CONFIG_RTIO_LOG_CHANNEL as u8, log_channel: pl::csr::CONFIG_RTIO_LOG_CHANNEL as u8,
dds_onehot_sel: true // kept for backward compatibility of analyzer dumps dds_onehot_sel: true, // kept for backward compatibility of analyzer dumps
}; };
debug!("{:?}", header); debug!("{:?}", header);

View File

@ -1,39 +1,33 @@
use core::{fmt, slice, str}; use alloc::{collections::BTreeMap, rc::Rc, string::String, vec, vec::Vec};
use core::cell::RefCell; use core::{cell::RefCell, fmt, slice, str};
use alloc::{vec, vec::Vec, string::String, collections::BTreeMap, rc::Rc};
use log::{info, warn, error};
use cslice::CSlice; use cslice::CSlice;
use futures::{future::FutureExt, select_biased};
use num_derive::{FromPrimitive, ToPrimitive}; use libasync::{smoltcp::{Sockets, TcpStream},
use num_traits::{FromPrimitive, ToPrimitive}; task};
use libboard_zynq::{
self as zynq,
smoltcp::{
self,
wire::IpCidr,
iface::{NeighborCache, EthernetInterfaceBuilder},
time::Instant,
},
timer::GlobalTimer,
};
use libcortex_a9::{semaphore::Semaphore, mutex::Mutex, sync_channel::{Sender, Receiver}};
use futures::{select_biased, future::FutureExt};
use libasync::{smoltcp::{Sockets, TcpStream}, task};
use libconfig::{Config, net_settings};
use libboard_artiq::drtio_routing; use libboard_artiq::drtio_routing;
#[cfg(feature = "target_kasli_soc")] #[cfg(feature = "target_kasli_soc")]
use libboard_zynq::error_led::ErrorLED; use libboard_zynq::error_led::ErrorLED;
use libboard_zynq::{self as zynq,
smoltcp::{self,
iface::{EthernetInterfaceBuilder, NeighborCache},
time::Instant,
wire::IpCidr},
timer::GlobalTimer};
use libconfig::{net_settings, Config};
use libcortex_a9::{mutex::Mutex,
semaphore::Semaphore,
sync_channel::{Receiver, Sender}};
use log::{error, info, warn};
use num_derive::{FromPrimitive, ToPrimitive};
use num_traits::{FromPrimitive, ToPrimitive};
use crate::proto_async::*;
use crate::kernel;
use crate::rpc;
use crate::moninj;
use crate::mgmt;
use crate::analyzer;
use crate::rtio_mgt::{self, resolve_channel_name};
#[cfg(has_drtio)] #[cfg(has_drtio)]
use crate::pl; use crate::pl;
use crate::{analyzer, kernel, mgmt, moninj,
proto_async::*,
rpc,
rtio_mgt::{self, resolve_channel_name}};
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Error { pub enum Error {
@ -49,9 +43,9 @@ impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self { match self {
Error::NetworkError(error) => write!(f, "network error: {}", error), Error::NetworkError(error) => write!(f, "network error: {}", error),
Error::UnexpectedPattern => write!(f, "unexpected pattern"), Error::UnexpectedPattern => write!(f, "unexpected pattern"),
Error::UnrecognizedPacket => write!(f, "unrecognized packet"), Error::UnrecognizedPacket => write!(f, "unrecognized packet"),
Error::BufferExhausted => write!(f, "buffer exhausted"), Error::BufferExhausted => write!(f, "buffer exhausted"),
} }
} }
} }
@ -88,15 +82,16 @@ static CACHE_STORE: Mutex<BTreeMap<String, Vec<i32>>> = Mutex::new(BTreeMap::new
static DMA_RECORD_STORE: Mutex<BTreeMap<String, (Vec<u8>, i64)>> = Mutex::new(BTreeMap::new()); static DMA_RECORD_STORE: Mutex<BTreeMap<String, (Vec<u8>, i64)>> = Mutex::new(BTreeMap::new());
async fn write_header(stream: &TcpStream, reply: Reply) -> Result<()> { async fn write_header(stream: &TcpStream, reply: Reply) -> Result<()> {
stream.send_slice(&[0x5a, 0x5a, 0x5a, 0x5a, reply.to_u8().unwrap()]).await?; stream
.send_slice(&[0x5a, 0x5a, 0x5a, 0x5a, reply.to_u8().unwrap()])
.await?;
Ok(()) Ok(())
} }
async fn read_request(stream: &TcpStream, allow_close: bool) -> Result<Option<Request>> { async fn read_request(stream: &TcpStream, allow_close: bool) -> Result<Option<Request>> {
match expect(stream, &[0x5a, 0x5a, 0x5a, 0x5a]).await { match expect(stream, &[0x5a, 0x5a, 0x5a, 0x5a]).await {
Ok(true) => {} Ok(true) => {}
Ok(false) => Ok(false) => return Err(Error::UnexpectedPattern),
return Err(Error::UnexpectedPattern),
Err(smoltcp::Error::Finished) => { Err(smoltcp::Error::Finished) => {
if allow_close { if allow_close {
info!("peer closed connection"); info!("peer closed connection");
@ -105,11 +100,12 @@ async fn read_request(stream: &TcpStream, allow_close: bool) -> Result<Option<Re
error!("peer unexpectedly closed connection"); error!("peer unexpectedly closed connection");
return Err(smoltcp::Error::Finished)?; return Err(smoltcp::Error::Finished)?;
} }
}, }
Err(e) => Err(e) => return Err(e)?,
return Err(e)?,
} }
Ok(Some(FromPrimitive::from_i8(read_i8(&stream).await?).ok_or(Error::UnrecognizedPacket)?)) Ok(Some(
FromPrimitive::from_i8(read_i8(&stream).await?).ok_or(Error::UnrecognizedPacket)?,
))
} }
async fn read_bytes(stream: &TcpStream, max_length: usize) -> Result<Vec<u8>> { async fn read_bytes(stream: &TcpStream, max_length: usize) -> Result<Vec<u8>> {
@ -128,9 +124,7 @@ async fn fast_send(sender: &mut Sender<'_, kernel::Message>, content: kernel::Me
let mut content = content; let mut content = content;
for _ in 0..RETRY_LIMIT { for _ in 0..RETRY_LIMIT {
match sender.try_send(content) { match sender.try_send(content) {
Ok(()) => { Ok(()) => return,
return
},
Err(v) => { Err(v) => {
content = v; content = v;
} }
@ -142,10 +136,8 @@ async fn fast_send(sender: &mut Sender<'_, kernel::Message>, content: kernel::Me
async fn fast_recv(receiver: &mut Receiver<'_, kernel::Message>) -> kernel::Message { async fn fast_recv(receiver: &mut Receiver<'_, kernel::Message>) -> kernel::Message {
for _ in 0..RETRY_LIMIT { for _ in 0..RETRY_LIMIT {
match receiver.try_recv() { match receiver.try_recv() {
Ok(v) => { Ok(v) => return v,
return v; Err(()) => (),
},
Err(()) => ()
} }
} }
receiver.async_recv().await receiver.async_recv().await
@ -161,7 +153,11 @@ async fn write_exception_string(stream: &TcpStream, s: CSlice<'static, u8>) -> R
Ok(()) Ok(())
} }
async fn handle_run_kernel(stream: Option<&TcpStream>, control: &Rc<RefCell<kernel::Control>>, _up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>) -> Result<()> { async fn handle_run_kernel(
stream: Option<&TcpStream>,
control: &Rc<RefCell<kernel::Control>>,
_up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>,
) -> Result<()> {
control.borrow_mut().tx.async_send(kernel::Message::StartRequest).await; control.borrow_mut().tx.async_send(kernel::Message::StartRequest).await;
loop { loop {
let reply = control.borrow_mut().rx.async_recv().await; let reply = control.borrow_mut().rx.async_recv().await;
@ -169,7 +165,7 @@ async fn handle_run_kernel(stream: Option<&TcpStream>, control: &Rc<RefCell<kern
kernel::Message::RpcSend { is_async, data } => { kernel::Message::RpcSend { is_async, data } => {
if stream.is_none() { if stream.is_none() {
error!("Unexpected RPC from startup/idle kernel!"); error!("Unexpected RPC from startup/idle kernel!");
break break;
} }
let stream = stream.unwrap(); let stream = stream.unwrap();
write_header(stream, Reply::RPCRequest).await?; write_header(stream, Reply::RPCRequest).await?;
@ -196,46 +192,64 @@ async fn handle_run_kernel(stream: Option<&TcpStream>, control: &Rc<RefCell<kern
fast_send(&mut control.tx, kernel::Message::RpcRecvReply(Ok(size))).await; fast_send(&mut control.tx, kernel::Message::RpcRecvReply(Ok(size))).await;
match fast_recv(&mut control.rx).await { match fast_recv(&mut control.rx).await {
kernel::Message::RpcRecvRequest(slot) => slot, kernel::Message::RpcRecvRequest(slot) => slot,
other => panic!("expected nested value slot from kernel CPU, not {:?}", other), other => {
panic!("expected nested value slot from kernel CPU, not {:?}", other)
}
} }
} }
} }
}).await?; })
control.borrow_mut().tx.async_send(kernel::Message::RpcRecvReply(Ok(0))).await; .await?;
}, control
.borrow_mut()
.tx
.async_send(kernel::Message::RpcRecvReply(Ok(0)))
.await;
}
Request::RPCException => { Request::RPCException => {
let mut control = control.borrow_mut(); let mut control = control.borrow_mut();
match control.rx.async_recv().await { match control.rx.async_recv().await {
kernel::Message::RpcRecvRequest(_) => (), kernel::Message::RpcRecvRequest(_) => (),
other => panic!("expected (ignored) root value slot from kernel CPU, not {:?}", other), other => panic!("expected (ignored) root value slot from kernel CPU, not {:?}", other),
} }
let id = read_i32(stream).await? as u32; let id = read_i32(stream).await? as u32;
let message = read_i32(stream).await? as u32; let message = read_i32(stream).await? as u32;
let param = [read_i64(stream).await?, let param = [
read_i64(stream).await?, read_i64(stream).await?,
read_i64(stream).await?]; read_i64(stream).await?,
let file = read_i32(stream).await? as u32; read_i64(stream).await?,
let line = read_i32(stream).await?; ];
let column = read_i32(stream).await?; let file = read_i32(stream).await? as u32;
let line = read_i32(stream).await?;
let column = read_i32(stream).await?;
let function = read_i32(stream).await? as u32; let function = read_i32(stream).await? as u32;
control.tx.async_send(kernel::Message::RpcRecvReply(Err(kernel::RPCException { control
id, message, param, file, line, column, function .tx
}))).await; .async_send(kernel::Message::RpcRecvReply(Err(kernel::RPCException {
}, id,
message,
param,
file,
line,
column,
function,
})))
.await;
}
_ => { _ => {
error!("unexpected RPC request from host: {:?}", host_request); error!("unexpected RPC request from host: {:?}", host_request);
return Err(Error::UnrecognizedPacket) return Err(Error::UnrecognizedPacket);
} }
} }
} }
}, }
kernel::Message::KernelFinished(async_errors) => { kernel::Message::KernelFinished(async_errors) => {
if let Some(stream) = stream { if let Some(stream) = stream {
write_header(stream, Reply::KernelFinished).await?; write_header(stream, Reply::KernelFinished).await?;
write_i8(stream, async_errors as i8).await?; write_i8(stream, async_errors as i8).await?;
} }
break; break;
}, }
kernel::Message::KernelException(exceptions, stack_pointers, backtrace, async_errors) => { kernel::Message::KernelException(exceptions, stack_pointers, backtrace, async_errors) => {
match stream { match stream {
Some(stream) => { Some(stream) => {
@ -247,12 +261,22 @@ async fn handle_run_kernel(stream: Option<&TcpStream>, control: &Rc<RefCell<kern
let exception = exception.as_ref().unwrap(); let exception = exception.as_ref().unwrap();
write_i32(stream, exception.id as i32).await?; write_i32(stream, exception.id as i32).await?;
if exception.message.len() == usize::MAX { // exception with host string if exception.message.len() == usize::MAX {
// exception with host string
write_exception_string(stream, exception.message).await?; write_exception_string(stream, exception.message).await?;
} else { } else {
let msg = str::from_utf8(unsafe { slice::from_raw_parts(exception.message.as_ptr(), exception.message.len()) }) let msg = str::from_utf8(unsafe {
.unwrap() slice::from_raw_parts(exception.message.as_ptr(), exception.message.len())
.replace("{rtio_channel_info:0}", &format!("0x{:04x}:{}", exception.param[0], resolve_channel_name(exception.param[0] as u32))); })
.unwrap()
.replace(
"{rtio_channel_info:0}",
&format!(
"0x{:04x}:{}",
exception.param[0],
resolve_channel_name(exception.param[0] as u32)
),
);
write_exception_string(stream, unsafe { CSlice::new(msg.as_ptr(), msg.len()) }).await?; write_exception_string(stream, unsafe { CSlice::new(msg.as_ptr(), msg.len()) }).await?;
} }
@ -275,7 +299,7 @@ async fn handle_run_kernel(stream: Option<&TcpStream>, control: &Rc<RefCell<kern
write_i32(stream, sp as i32).await?; write_i32(stream, sp as i32).await?;
} }
write_i8(stream, async_errors as i8).await?; write_i8(stream, async_errors as i8).await?;
}, }
None => { None => {
error!("Uncaught kernel exceptions: {:?}", exceptions); error!("Uncaught kernel exceptions: {:?}", exceptions);
} }
@ -284,27 +308,41 @@ async fn handle_run_kernel(stream: Option<&TcpStream>, control: &Rc<RefCell<kern
} }
kernel::Message::CachePutRequest(key, value) => { kernel::Message::CachePutRequest(key, value) => {
CACHE_STORE.lock().insert(key, value); CACHE_STORE.lock().insert(key, value);
}, }
kernel::Message::CacheGetRequest(key) => { kernel::Message::CacheGetRequest(key) => {
const DEFAULT: Vec<i32> = Vec::new(); const DEFAULT: Vec<i32> = Vec::new();
let value = CACHE_STORE.lock().get(&key).unwrap_or(&DEFAULT).clone(); let value = CACHE_STORE.lock().get(&key).unwrap_or(&DEFAULT).clone();
control.borrow_mut().tx.async_send(kernel::Message::CacheGetReply(value)).await; control
}, .borrow_mut()
.tx
.async_send(kernel::Message::CacheGetReply(value))
.await;
}
kernel::Message::DmaPutRequest(recorder) => { kernel::Message::DmaPutRequest(recorder) => {
DMA_RECORD_STORE.lock().insert(recorder.name, (recorder.buffer, recorder.duration)); DMA_RECORD_STORE
}, .lock()
.insert(recorder.name, (recorder.buffer, recorder.duration));
}
kernel::Message::DmaEraseRequest(name) => { kernel::Message::DmaEraseRequest(name) => {
// prevent possible OOM when we have large DMA record replacement. // prevent possible OOM when we have large DMA record replacement.
DMA_RECORD_STORE.lock().remove(&name); DMA_RECORD_STORE.lock().remove(&name);
}, }
kernel::Message::DmaGetRequest(name) => { kernel::Message::DmaGetRequest(name) => {
let result = DMA_RECORD_STORE.lock().get(&name).map(|v| v.clone()); let result = DMA_RECORD_STORE.lock().get(&name).map(|v| v.clone());
control.borrow_mut().tx.async_send(kernel::Message::DmaGetReply(result)).await; control
}, .borrow_mut()
.tx
.async_send(kernel::Message::DmaGetReply(result))
.await;
}
#[cfg(has_drtio)] #[cfg(has_drtio)]
kernel::Message::UpDestinationsRequest(destination) => { kernel::Message::UpDestinationsRequest(destination) => {
let result = _up_destinations.borrow()[destination as usize]; let result = _up_destinations.borrow()[destination as usize];
control.borrow_mut().tx.async_send(kernel::Message::UpDestinationsReply(result)).await; control
.borrow_mut()
.tx
.async_send(kernel::Message::UpDestinationsReply(result))
.await;
} }
_ => { _ => {
panic!("unexpected message from core1 while kernel was running: {:?}", reply); panic!("unexpected message from core1 while kernel was running: {:?}", reply);
@ -314,11 +352,17 @@ async fn handle_run_kernel(stream: Option<&TcpStream>, control: &Rc<RefCell<kern
Ok(()) Ok(())
} }
async fn load_kernel(
async fn load_kernel(buffer: &Vec<u8>, control: &Rc<RefCell<kernel::Control>>, stream: Option<&TcpStream>) -> Result<()> { buffer: &Vec<u8>,
control: &Rc<RefCell<kernel::Control>>,
stream: Option<&TcpStream>,
) -> Result<()> {
let mut control = control.borrow_mut(); let mut control = control.borrow_mut();
control.restart(); control.restart();
control.tx.async_send(kernel::Message::LoadRequest(buffer.to_vec())).await; control
.tx
.async_send(kernel::Message::LoadRequest(buffer.to_vec()))
.await;
let reply = control.rx.async_recv().await; let reply = control.rx.async_recv().await;
match reply { match reply {
kernel::Message::LoadCompleted => { kernel::Message::LoadCompleted => {
@ -326,7 +370,7 @@ async fn load_kernel(buffer: &Vec<u8>, control: &Rc<RefCell<kernel::Control>>, s
write_header(stream, Reply::LoadCompleted).await?; write_header(stream, Reply::LoadCompleted).await?;
} }
Ok(()) Ok(())
}, }
kernel::Message::LoadFailed => { kernel::Message::LoadFailed => {
if let Some(stream) = stream { if let Some(stream) = stream {
write_header(stream, Reply::LoadFailed).await?; write_header(stream, Reply::LoadFailed).await?;
@ -335,7 +379,7 @@ async fn load_kernel(buffer: &Vec<u8>, control: &Rc<RefCell<kernel::Control>>, s
error!("Kernel load failed"); error!("Kernel load failed");
} }
Err(Error::UnexpectedPattern) Err(Error::UnexpectedPattern)
}, }
_ => { _ => {
error!("unexpected message from core1: {:?}", reply); error!("unexpected message from core1: {:?}", reply);
if let Some(stream) = stream { if let Some(stream) = stream {
@ -347,7 +391,11 @@ async fn load_kernel(buffer: &Vec<u8>, control: &Rc<RefCell<kernel::Control>>, s
} }
} }
async fn handle_connection(stream: &mut TcpStream, control: Rc<RefCell<kernel::Control>>, up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>) -> Result<()> { async fn handle_connection(
stream: &mut TcpStream,
control: Rc<RefCell<kernel::Control>>,
up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>,
) -> Result<()> {
stream.set_ack_delay(None); stream.set_ack_delay(None);
if !expect(stream, b"ARTIQ coredev\n").await? { if !expect(stream, b"ARTIQ coredev\n").await? {
@ -364,17 +412,17 @@ async fn handle_connection(stream: &mut TcpStream, control: Rc<RefCell<kernel::C
Request::SystemInfo => { Request::SystemInfo => {
write_header(stream, Reply::SystemInfo).await?; write_header(stream, Reply::SystemInfo).await?;
stream.send_slice("ARZQ".as_bytes()).await?; stream.send_slice("ARZQ".as_bytes()).await?;
}, }
Request::LoadKernel => { Request::LoadKernel => {
let buffer = read_bytes(stream, 1024*1024).await?; let buffer = read_bytes(stream, 1024 * 1024).await?;
load_kernel(&buffer, &control, Some(stream)).await?; load_kernel(&buffer, &control, Some(stream)).await?;
}, }
Request::RunKernel => { Request::RunKernel => {
handle_run_kernel(Some(stream), &control, &up_destinations).await?; handle_run_kernel(Some(stream), &control, &up_destinations).await?;
}, }
_ => { _ => {
error!("unexpected request from host: {:?}", request); error!("unexpected request from host: {:?}", request);
return Err(Error::UnrecognizedPacket) return Err(Error::UnrecognizedPacket);
} }
} }
} }
@ -398,24 +446,24 @@ pub fn main(timer: GlobalTimer, cfg: Config) {
let ip_addrs = [ let ip_addrs = [
IpCidr::new(net_addresses.ipv4_addr, 0), IpCidr::new(net_addresses.ipv4_addr, 0),
IpCidr::new(net_addresses.ipv6_ll_addr, 0), IpCidr::new(net_addresses.ipv6_ll_addr, 0),
IpCidr::new(addr, 0) IpCidr::new(addr, 0),
]; ];
EthernetInterfaceBuilder::new(&mut eth) EthernetInterfaceBuilder::new(&mut eth)
.ethernet_addr(net_addresses.hardware_addr) .ethernet_addr(net_addresses.hardware_addr)
.ip_addrs(ip_addrs) .ip_addrs(ip_addrs)
.neighbor_cache(neighbor_cache) .neighbor_cache(neighbor_cache)
.finalize() .finalize()
} }
None => { None => {
let ip_addrs = [ let ip_addrs = [
IpCidr::new(net_addresses.ipv4_addr, 0), IpCidr::new(net_addresses.ipv4_addr, 0),
IpCidr::new(net_addresses.ipv6_ll_addr, 0) IpCidr::new(net_addresses.ipv6_ll_addr, 0),
]; ];
EthernetInterfaceBuilder::new(&mut eth) EthernetInterfaceBuilder::new(&mut eth)
.ethernet_addr(net_addresses.hardware_addr) .ethernet_addr(net_addresses.hardware_addr)
.ip_addrs(ip_addrs) .ip_addrs(ip_addrs)
.neighbor_cache(neighbor_cache) .neighbor_cache(neighbor_cache)
.finalize() .finalize()
} }
}; };
@ -424,8 +472,10 @@ pub fn main(timer: GlobalTimer, cfg: Config) {
// before, mutex was on io, but now that io isn't used...? // before, mutex was on io, but now that io isn't used...?
let aux_mutex: Rc<Mutex<bool>> = Rc::new(Mutex::new(false)); let aux_mutex: Rc<Mutex<bool>> = Rc::new(Mutex::new(false));
#[cfg(has_drtio)] #[cfg(has_drtio)]
let drtio_routing_table = Rc::new(RefCell::new( let drtio_routing_table = Rc::new(RefCell::new(drtio_routing::config_routing_table(
drtio_routing::config_routing_table(pl::csr::DRTIO.len(), &cfg))); pl::csr::DRTIO.len(),
&cfg,
)));
#[cfg(not(has_drtio))] #[cfg(not(has_drtio))]
let drtio_routing_table = Rc::new(RefCell::new(drtio_routing::RoutingTable::default_empty())); let drtio_routing_table = Rc::new(RefCell::new(drtio_routing::RoutingTable::default_empty()));
let up_destinations = Rc::new(RefCell::new([false; drtio_routing::DEST_COUNT])); let up_destinations = Rc::new(RefCell::new([false; drtio_routing::DEST_COUNT]));
@ -497,14 +547,10 @@ pub fn main(timer: GlobalTimer, cfg: Config) {
} }
}); });
Sockets::run(&mut iface, || { Sockets::run(&mut iface, || Instant::from_millis(timer.get_time().0 as i32));
Instant::from_millis(timer.get_time().0 as i32)
});
} }
pub fn soft_panic_main(timer: GlobalTimer, cfg: Config) -> ! { pub fn soft_panic_main(timer: GlobalTimer, cfg: Config) -> ! {
let net_addresses = net_settings::get_addresses(&cfg); let net_addresses = net_settings::get_addresses(&cfg);
info!("network addresses: {}", net_addresses); info!("network addresses: {}", net_addresses);
@ -522,24 +568,24 @@ pub fn soft_panic_main(timer: GlobalTimer, cfg: Config) -> ! {
let ip_addrs = [ let ip_addrs = [
IpCidr::new(net_addresses.ipv4_addr, 0), IpCidr::new(net_addresses.ipv4_addr, 0),
IpCidr::new(net_addresses.ipv6_ll_addr, 0), IpCidr::new(net_addresses.ipv6_ll_addr, 0),
IpCidr::new(addr, 0) IpCidr::new(addr, 0),
]; ];
EthernetInterfaceBuilder::new(&mut eth) EthernetInterfaceBuilder::new(&mut eth)
.ethernet_addr(net_addresses.hardware_addr) .ethernet_addr(net_addresses.hardware_addr)
.ip_addrs(ip_addrs) .ip_addrs(ip_addrs)
.neighbor_cache(neighbor_cache) .neighbor_cache(neighbor_cache)
.finalize() .finalize()
} }
None => { None => {
let ip_addrs = [ let ip_addrs = [
IpCidr::new(net_addresses.ipv4_addr, 0), IpCidr::new(net_addresses.ipv4_addr, 0),
IpCidr::new(net_addresses.ipv6_ll_addr, 0) IpCidr::new(net_addresses.ipv6_ll_addr, 0),
]; ];
EthernetInterfaceBuilder::new(&mut eth) EthernetInterfaceBuilder::new(&mut eth)
.ethernet_addr(net_addresses.hardware_addr) .ethernet_addr(net_addresses.hardware_addr)
.ip_addrs(ip_addrs) .ip_addrs(ip_addrs)
.neighbor_cache(neighbor_cache) .neighbor_cache(neighbor_cache)
.finalize() .finalize()
} }
}; };
@ -555,7 +601,5 @@ pub fn soft_panic_main(timer: GlobalTimer, cfg: Config) -> ! {
err_led.toggle(true); err_led.toggle(true);
} }
Sockets::run(&mut iface, || { Sockets::run(&mut iface, || Instant::from_millis(timer.get_time().0 as i32));
Instant::from_millis(timer.get_time().0 as i32) }
});
}

View File

@ -13,14 +13,14 @@
#![allow(non_camel_case_types)] #![allow(non_camel_case_types)]
use core::mem; use core::mem;
use cslice::CSlice; use cslice::CSlice;
use unwind as uw;
use libc::{c_int, c_void, uintptr_t};
use log::{trace, error};
use crate::kernel::KERNEL_IMAGE;
use dwarf::eh::{self, EHAction, EHContext}; use dwarf::eh::{self, EHAction, EHContext};
use libc::{c_int, c_void, uintptr_t};
use log::{error, trace};
use unwind as uw;
use crate::kernel::KERNEL_IMAGE;
const EXCEPTION_CLASS: uw::_Unwind_Exception_Class = 0x4d_4c_42_53_41_52_54_51; /* 'MLBSARTQ' */ const EXCEPTION_CLASS: uw::_Unwind_Exception_Class = 0x4d_4c_42_53_41_52_54_51; /* 'MLBSARTQ' */
@ -32,13 +32,13 @@ const UNWIND_DATA_REG: (i32, i32) = (0, 1); // R0, R1
#[repr(C)] #[repr(C)]
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub struct Exception<'a> { pub struct Exception<'a> {
pub id: u32, pub id: u32,
pub file: CSlice<'a, u8>, pub file: CSlice<'a, u8>,
pub line: u32, pub line: u32,
pub column: u32, pub column: u32,
pub function: CSlice<'a, u8>, pub function: CSlice<'a, u8>,
pub message: CSlice<'a, u8>, pub message: CSlice<'a, u8>,
pub param: [i64; 3] pub param: [i64; 3],
} }
fn str_err(_: core::str::Utf8Error) -> core::fmt::Error { fn str_err(_: core::str::Utf8Error) -> core::fmt::Error {
@ -55,12 +55,16 @@ fn exception_str<'a>(s: &'a CSlice<'a, u8>) -> Result<&'a str, core::str::Utf8Er
impl<'a> core::fmt::Debug for Exception<'a> { impl<'a> core::fmt::Debug for Exception<'a> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "Exception {} from {} in {}:{}:{}, message: {}", write!(
f,
"Exception {} from {} in {}:{}:{}, message: {}",
self.id, self.id,
exception_str(&self.function).map_err(str_err)?, exception_str(&self.function).map_err(str_err)?,
exception_str(&self.file).map_err(str_err)?, exception_str(&self.file).map_err(str_err)?,
self.line, self.column, self.line,
exception_str(&self.message).map_err(str_err)?) self.column,
exception_str(&self.message).map_err(str_err)?
)
} }
} }
@ -91,9 +95,9 @@ struct ExceptionBuffer {
static mut EXCEPTION_BUFFER: ExceptionBuffer = ExceptionBuffer { static mut EXCEPTION_BUFFER: ExceptionBuffer = ExceptionBuffer {
uw_exceptions: [uw::_Unwind_Exception { uw_exceptions: [uw::_Unwind_Exception {
exception_class: EXCEPTION_CLASS, exception_class: EXCEPTION_CLASS,
exception_cleanup: cleanup, exception_cleanup: cleanup,
private: [0; uw::unwinder_private_data_size], private: [0; uw::unwinder_private_data_size],
}; MAX_INFLIGHT_EXCEPTIONS], }; MAX_INFLIGHT_EXCEPTIONS],
exceptions: [None; MAX_INFLIGHT_EXCEPTIONS + 1], exceptions: [None; MAX_INFLIGHT_EXCEPTIONS + 1],
exception_stack: [-1; MAX_INFLIGHT_EXCEPTIONS + 1], exception_stack: [-1; MAX_INFLIGHT_EXCEPTIONS + 1],
@ -102,17 +106,17 @@ static mut EXCEPTION_BUFFER: ExceptionBuffer = ExceptionBuffer {
stack_pointers: [StackPointerBacktrace { stack_pointers: [StackPointerBacktrace {
stack_pointer: 0, stack_pointer: 0,
initial_backtrace_size: 0, initial_backtrace_size: 0,
current_backtrace_size: 0 current_backtrace_size: 0,
}; MAX_INFLIGHT_EXCEPTIONS + 1], }; MAX_INFLIGHT_EXCEPTIONS + 1],
exception_count: 0 exception_count: 0,
}; };
pub unsafe extern fn reset_exception_buffer() { pub unsafe extern "C" fn reset_exception_buffer() {
trace!("reset exception buffer"); trace!("reset exception buffer");
EXCEPTION_BUFFER.uw_exceptions = [uw::_Unwind_Exception { EXCEPTION_BUFFER.uw_exceptions = [uw::_Unwind_Exception {
exception_class: EXCEPTION_CLASS, exception_class: EXCEPTION_CLASS,
exception_cleanup: cleanup, exception_cleanup: cleanup,
private: [0; uw::unwinder_private_data_size], private: [0; uw::unwinder_private_data_size],
}; MAX_INFLIGHT_EXCEPTIONS]; }; MAX_INFLIGHT_EXCEPTIONS];
EXCEPTION_BUFFER.exceptions = [None; MAX_INFLIGHT_EXCEPTIONS + 1]; EXCEPTION_BUFFER.exceptions = [None; MAX_INFLIGHT_EXCEPTIONS + 1];
EXCEPTION_BUFFER.exception_stack = [-1; MAX_INFLIGHT_EXCEPTIONS + 1]; EXCEPTION_BUFFER.exception_stack = [-1; MAX_INFLIGHT_EXCEPTIONS + 1];
@ -120,26 +124,25 @@ pub unsafe extern fn reset_exception_buffer() {
EXCEPTION_BUFFER.exception_count = 0; EXCEPTION_BUFFER.exception_count = 0;
} }
type _Unwind_Stop_Fn = extern "C" fn(version: c_int, type _Unwind_Stop_Fn = extern "C" fn(
actions: i32, version: c_int,
exception_class: uw::_Unwind_Exception_Class, actions: i32,
exception_object: *mut uw::_Unwind_Exception, exception_class: uw::_Unwind_Exception_Class,
context: *mut uw::_Unwind_Context, exception_object: *mut uw::_Unwind_Exception,
stop_parameter: *mut c_void) context: *mut uw::_Unwind_Context,
-> uw::_Unwind_Reason_Code; stop_parameter: *mut c_void,
) -> uw::_Unwind_Reason_Code;
extern { extern "C" {
// not defined in EHABI, but LLVM added it and is useful to us // not defined in EHABI, but LLVM added it and is useful to us
fn _Unwind_ForcedUnwind(exception: *mut uw::_Unwind_Exception, fn _Unwind_ForcedUnwind(
stop_fn: _Unwind_Stop_Fn, exception: *mut uw::_Unwind_Exception,
stop_parameter: *mut c_void) -> uw::_Unwind_Reason_Code; stop_fn: _Unwind_Stop_Fn,
stop_parameter: *mut c_void,
) -> uw::_Unwind_Reason_Code;
} }
unsafe fn find_eh_action( unsafe fn find_eh_action(context: *mut uw::_Unwind_Context, foreign_exception: bool, id: u32) -> Result<EHAction, ()> {
context: *mut uw::_Unwind_Context,
foreign_exception: bool,
id: u32,
) -> Result<EHAction, ()> {
let lsda = uw::_Unwind_GetLanguageSpecificData(context) as *const u8; let lsda = uw::_Unwind_GetLanguageSpecificData(context) as *const u8;
let mut ip_before_instr: c_int = 0; let mut ip_before_instr: c_int = 0;
let ip = uw::_Unwind_GetIPInfo(context, &mut ip_before_instr); let ip = uw::_Unwind_GetIPInfo(context, &mut ip_before_instr);
@ -154,10 +157,11 @@ unsafe fn find_eh_action(
eh::find_eh_action(lsda, &eh_context, foreign_exception, id) eh::find_eh_action(lsda, &eh_context, foreign_exception, id)
} }
pub unsafe fn artiq_personality(_state: uw::_Unwind_State, pub unsafe fn artiq_personality(
exception_object: *mut uw::_Unwind_Exception, _state: uw::_Unwind_State,
context: *mut uw::_Unwind_Context) exception_object: *mut uw::_Unwind_Exception,
-> uw::_Unwind_Reason_Code { context: *mut uw::_Unwind_Context,
) -> uw::_Unwind_Reason_Code {
// we will only do phase 2 forced unwinding now // we will only do phase 2 forced unwinding now
// The DWARF unwinder assumes that _Unwind_Context holds things like the function // The DWARF unwinder assumes that _Unwind_Context holds things like the function
// and LSDA pointers, however ARM EHABI places them into the exception object. // and LSDA pointers, however ARM EHABI places them into the exception object.
@ -165,9 +169,7 @@ pub unsafe fn artiq_personality(_state: uw::_Unwind_State,
// take only the context pointer, GCC personality routines stash a pointer to // take only the context pointer, GCC personality routines stash a pointer to
// exception_object in the context, using location reserved for ARM's // exception_object in the context, using location reserved for ARM's
// "scratch register" (r12). // "scratch register" (r12).
uw::_Unwind_SetGR(context, uw::_Unwind_SetGR(context, uw::UNWIND_POINTER_REG, exception_object as uw::_Unwind_Ptr);
uw::UNWIND_POINTER_REG,
exception_object as uw::_Unwind_Ptr);
// ...A more principled approach would be to provide the full definition of ARM's // ...A more principled approach would be to provide the full definition of ARM's
// _Unwind_Context in our libunwind bindings and fetch the required data from there // _Unwind_Context in our libunwind bindings and fetch the required data from there
// directly, bypassing DWARF compatibility functions. // directly, bypassing DWARF compatibility functions.
@ -186,10 +188,8 @@ pub unsafe fn artiq_personality(_state: uw::_Unwind_State,
}; };
match eh_action { match eh_action {
EHAction::None => return continue_unwind(exception_object, context), EHAction::None => return continue_unwind(exception_object, context),
EHAction::Cleanup(lpad) | EHAction::Cleanup(lpad) | EHAction::Catch(lpad) => {
EHAction::Catch(lpad) => { uw::_Unwind_SetGR(context, UNWIND_DATA_REG.0, exception_object as uintptr_t);
uw::_Unwind_SetGR(context, UNWIND_DATA_REG.0,
exception_object as uintptr_t);
uw::_Unwind_SetGR(context, UNWIND_DATA_REG.1, exception as *const _ as uw::_Unwind_Word); uw::_Unwind_SetGR(context, UNWIND_DATA_REG.1, exception as *const _ as uw::_Unwind_Word);
uw::_Unwind_SetIP(context, lpad); uw::_Unwind_SetIP(context, lpad);
return uw::_URC_INSTALL_CONTEXT; return uw::_URC_INSTALL_CONTEXT;
@ -199,9 +199,10 @@ pub unsafe fn artiq_personality(_state: uw::_Unwind_State,
// On ARM EHABI the personality routine is responsible for actually // On ARM EHABI the personality routine is responsible for actually
// unwinding a single stack frame before returning (ARM EHABI Sec. 6.1). // unwinding a single stack frame before returning (ARM EHABI Sec. 6.1).
unsafe fn continue_unwind(exception_object: *mut uw::_Unwind_Exception, unsafe fn continue_unwind(
context: *mut uw::_Unwind_Context) exception_object: *mut uw::_Unwind_Exception,
-> uw::_Unwind_Reason_Code { context: *mut uw::_Unwind_Context,
) -> uw::_Unwind_Reason_Code {
let reason = __gnu_unwind_frame(exception_object, context); let reason = __gnu_unwind_frame(exception_object, context);
if reason == uw::_URC_NO_REASON { if reason == uw::_URC_NO_REASON {
uw::_URC_CONTINUE_UNWIND uw::_URC_CONTINUE_UNWIND
@ -211,13 +212,14 @@ pub unsafe fn artiq_personality(_state: uw::_Unwind_State,
} }
// defined in libgcc // defined in libgcc
extern "C" { extern "C" {
fn __gnu_unwind_frame(exception_object: *mut uw::_Unwind_Exception, fn __gnu_unwind_frame(
context: *mut uw::_Unwind_Context) exception_object: *mut uw::_Unwind_Exception,
-> uw::_Unwind_Reason_Code; context: *mut uw::_Unwind_Context,
) -> uw::_Unwind_Reason_Code;
} }
} }
pub unsafe extern fn raise(exception: *const Exception) -> ! { pub unsafe extern "C" fn raise(exception: *const Exception) -> ! {
use cslice::AsCSlice; use cslice::AsCSlice;
let count = EXCEPTION_BUFFER.exception_count; let count = EXCEPTION_BUFFER.exception_count;
@ -244,8 +246,11 @@ pub unsafe extern fn raise(exception: *const Exception) -> ! {
} }
} }
assert!(found); assert!(found);
let _result = _Unwind_ForcedUnwind(&mut EXCEPTION_BUFFER.uw_exceptions[stack[count - 1] as usize], let _result = _Unwind_ForcedUnwind(
stop_fn, core::ptr::null_mut()); &mut EXCEPTION_BUFFER.uw_exceptions[stack[count - 1] as usize],
stop_fn,
core::ptr::null_mut(),
);
} else { } else {
if count < MAX_INFLIGHT_EXCEPTIONS { if count < MAX_INFLIGHT_EXCEPTIONS {
trace!("raising exception at level {}", count); trace!("raising exception at level {}", count);
@ -253,34 +258,33 @@ pub unsafe extern fn raise(exception: *const Exception) -> ! {
for (i, slot) in EXCEPTION_BUFFER.exceptions.iter_mut().enumerate() { for (i, slot) in EXCEPTION_BUFFER.exceptions.iter_mut().enumerate() {
// we should always be able to find a slot // we should always be able to find a slot
if slot.is_none() { if slot.is_none() {
*slot = Some( *slot = Some(*mem::transmute::<*const Exception, *const Exception<'static>>(
*mem::transmute::<*const Exception, *const Exception<'static>> exception,
(exception)); ));
EXCEPTION_BUFFER.exception_stack[count] = i as isize; EXCEPTION_BUFFER.exception_stack[count] = i as isize;
EXCEPTION_BUFFER.uw_exceptions[i].private = EXCEPTION_BUFFER.uw_exceptions[i].private = [0; uw::unwinder_private_data_size];
[0; uw::unwinder_private_data_size];
EXCEPTION_BUFFER.stack_pointers[i] = StackPointerBacktrace { EXCEPTION_BUFFER.stack_pointers[i] = StackPointerBacktrace {
stack_pointer: 0, stack_pointer: 0,
initial_backtrace_size: EXCEPTION_BUFFER.backtrace_size, initial_backtrace_size: EXCEPTION_BUFFER.backtrace_size,
current_backtrace_size: 0, current_backtrace_size: 0,
}; };
EXCEPTION_BUFFER.exception_count += 1; EXCEPTION_BUFFER.exception_count += 1;
let _result = _Unwind_ForcedUnwind(&mut EXCEPTION_BUFFER.uw_exceptions[i], let _result =
stop_fn, core::ptr::null_mut()); _Unwind_ForcedUnwind(&mut EXCEPTION_BUFFER.uw_exceptions[i], stop_fn, core::ptr::null_mut());
} }
} }
} else { } else {
error!("too many nested exceptions"); error!("too many nested exceptions");
// TODO: better reporting? // TODO: better reporting?
let exception = Exception { let exception = Exception {
id: get_exception_id("RuntimeError"), id: get_exception_id("RuntimeError"),
file: file!().as_c_slice(), file: file!().as_c_slice(),
line: line!(), line: line!(),
column: column!(), column: column!(),
// https://github.com/rust-lang/rfcs/pull/1719 // https://github.com/rust-lang/rfcs/pull/1719
function: "__artiq_raise".as_c_slice(), function: "__artiq_raise".as_c_slice(),
message: "too many nested exceptions".as_c_slice(), message: "too many nested exceptions".as_c_slice(),
param: [0, 0, 0] param: [0, 0, 0],
}; };
EXCEPTION_BUFFER.exceptions[MAX_INFLIGHT_EXCEPTIONS] = Some(mem::transmute(exception)); EXCEPTION_BUFFER.exceptions[MAX_INFLIGHT_EXCEPTIONS] = Some(mem::transmute(exception));
EXCEPTION_BUFFER.stack_pointers[MAX_INFLIGHT_EXCEPTIONS] = Default::default(); EXCEPTION_BUFFER.stack_pointers[MAX_INFLIGHT_EXCEPTIONS] = Default::default();
@ -291,17 +295,20 @@ pub unsafe extern fn raise(exception: *const Exception) -> ! {
unreachable!(); unreachable!();
} }
pub unsafe extern fn resume() -> ! { pub unsafe extern "C" fn resume() -> ! {
trace!("resume"); trace!("resume");
assert!(EXCEPTION_BUFFER.exception_count != 0); assert!(EXCEPTION_BUFFER.exception_count != 0);
let i = EXCEPTION_BUFFER.exception_stack[EXCEPTION_BUFFER.exception_count - 1]; let i = EXCEPTION_BUFFER.exception_stack[EXCEPTION_BUFFER.exception_count - 1];
assert!(i != -1); assert!(i != -1);
let _result = _Unwind_ForcedUnwind(&mut EXCEPTION_BUFFER.uw_exceptions[i as usize], let _result = _Unwind_ForcedUnwind(
stop_fn, core::ptr::null_mut()); &mut EXCEPTION_BUFFER.uw_exceptions[i as usize],
stop_fn,
core::ptr::null_mut(),
);
unreachable!() unreachable!()
} }
pub unsafe extern fn end_catch() { pub unsafe extern "C" fn end_catch() {
let mut count = EXCEPTION_BUFFER.exception_count; let mut count = EXCEPTION_BUFFER.exception_count;
assert!(count != 0); assert!(count != 0);
// we remove all exceptions with SP <= current exception SP // we remove all exceptions with SP <= current exception SP
@ -309,8 +316,7 @@ pub unsafe extern fn end_catch() {
let index = EXCEPTION_BUFFER.exception_stack[count - 1] as usize; let index = EXCEPTION_BUFFER.exception_stack[count - 1] as usize;
EXCEPTION_BUFFER.exception_stack[count - 1] = -1; EXCEPTION_BUFFER.exception_stack[count - 1] = -1;
EXCEPTION_BUFFER.exceptions[index] = None; EXCEPTION_BUFFER.exceptions[index] = None;
let outer_sp = EXCEPTION_BUFFER.stack_pointers let outer_sp = EXCEPTION_BUFFER.stack_pointers[index].stack_pointer;
[index].stack_pointer;
count -= 1; count -= 1;
for i in (0..count).rev() { for i in (0..count).rev() {
let index = EXCEPTION_BUFFER.exception_stack[i]; let index = EXCEPTION_BUFFER.exception_stack[i];
@ -334,8 +340,7 @@ pub unsafe extern fn end_catch() {
}; };
} }
extern fn cleanup(_unwind_code: uw::_Unwind_Reason_Code, extern "C" fn cleanup(_unwind_code: uw::_Unwind_Reason_Code, _uw_exception: *mut uw::_Unwind_Exception) {
_uw_exception: *mut uw::_Unwind_Exception) {
unimplemented!() unimplemented!()
} }
@ -345,18 +350,26 @@ fn uncaught_exception() -> ! {
for i in 0..EXCEPTION_BUFFER.exception_count { for i in 0..EXCEPTION_BUFFER.exception_count {
if EXCEPTION_BUFFER.exception_stack[i] != i as isize { if EXCEPTION_BUFFER.exception_stack[i] != i as isize {
// find the correct index // find the correct index
let index = EXCEPTION_BUFFER.exception_stack let index = EXCEPTION_BUFFER
.exception_stack
.iter() .iter()
.position(|v| *v == i as isize).unwrap(); .position(|v| *v == i as isize)
.unwrap();
let a = EXCEPTION_BUFFER.exception_stack[index]; let a = EXCEPTION_BUFFER.exception_stack[index];
let b = EXCEPTION_BUFFER.exception_stack[i]; let b = EXCEPTION_BUFFER.exception_stack[i];
assert!(a != -1 && b != -1); assert!(a != -1 && b != -1);
core::mem::swap(&mut EXCEPTION_BUFFER.exception_stack[index], core::mem::swap(
&mut EXCEPTION_BUFFER.exception_stack[i]); &mut EXCEPTION_BUFFER.exception_stack[index],
core::mem::swap(&mut EXCEPTION_BUFFER.exceptions[a as usize], &mut EXCEPTION_BUFFER.exception_stack[i],
&mut EXCEPTION_BUFFER.exceptions[b as usize]); );
core::mem::swap(&mut EXCEPTION_BUFFER.stack_pointers[a as usize], core::mem::swap(
&mut EXCEPTION_BUFFER.stack_pointers[b as usize]); &mut EXCEPTION_BUFFER.exceptions[a as usize],
&mut EXCEPTION_BUFFER.exceptions[b as usize],
);
core::mem::swap(
&mut EXCEPTION_BUFFER.stack_pointers[a as usize],
&mut EXCEPTION_BUFFER.stack_pointers[b as usize],
);
} }
} }
} }
@ -364,17 +377,20 @@ fn uncaught_exception() -> ! {
crate::kernel::core1::terminate( crate::kernel::core1::terminate(
EXCEPTION_BUFFER.exceptions[..EXCEPTION_BUFFER.exception_count].as_ref(), EXCEPTION_BUFFER.exceptions[..EXCEPTION_BUFFER.exception_count].as_ref(),
EXCEPTION_BUFFER.stack_pointers[..EXCEPTION_BUFFER.exception_count].as_ref(), EXCEPTION_BUFFER.stack_pointers[..EXCEPTION_BUFFER.exception_count].as_ref(),
EXCEPTION_BUFFER.backtrace[..EXCEPTION_BUFFER.backtrace_size].as_mut()) EXCEPTION_BUFFER.backtrace[..EXCEPTION_BUFFER.backtrace_size].as_mut(),
)
} }
} }
// stop function which would be executed when we unwind each frame // stop function which would be executed when we unwind each frame
extern fn stop_fn(_version: c_int, extern "C" fn stop_fn(
actions: i32, _version: c_int,
_uw_exception_class: uw::_Unwind_Exception_Class, actions: i32,
_uw_exception: *mut uw::_Unwind_Exception, _uw_exception_class: uw::_Unwind_Exception_Class,
context: *mut uw::_Unwind_Context, _uw_exception: *mut uw::_Unwind_Exception,
_stop_parameter: *mut c_void) -> uw::_Unwind_Reason_Code { context: *mut uw::_Unwind_Context,
_stop_parameter: *mut c_void,
) -> uw::_Unwind_Reason_Code {
unsafe { unsafe {
let load_addr = KERNEL_IMAGE.as_ref().unwrap().get_load_addr(); let load_addr = KERNEL_IMAGE.as_ref().unwrap().get_load_addr();
let backtrace_size = EXCEPTION_BUFFER.backtrace_size; let backtrace_size = EXCEPTION_BUFFER.backtrace_size;
@ -423,7 +439,7 @@ static EXCEPTION_ID_LOOKUP: [(&str, u32); 11] = [
pub fn get_exception_id(name: &str) -> u32 { pub fn get_exception_id(name: &str) -> u32 {
for (n, id) in EXCEPTION_ID_LOOKUP.iter() { for (n, id) in EXCEPTION_ID_LOOKUP.iter() {
if *n == name { if *n == name {
return *id return *id;
} }
} }
unimplemented!("unallocated internal exception id") unimplemented!("unallocated internal exception id")
@ -431,26 +447,24 @@ pub fn get_exception_id(name: &str) -> u32 {
#[macro_export] #[macro_export]
macro_rules! artiq_raise { macro_rules! artiq_raise {
($name:expr, $message:expr, $param0:expr, $param1:expr, $param2:expr) => ({ ($name:expr, $message:expr, $param0:expr, $param1:expr, $param2:expr) => {{
use cslice::AsCSlice; use cslice::AsCSlice;
let name_id = $crate::eh_artiq::get_exception_id($name); let name_id = $crate::eh_artiq::get_exception_id($name);
let message_cl = $message.clone(); let message_cl = $message.clone();
let exn = $crate::eh_artiq::Exception { let exn = $crate::eh_artiq::Exception {
id: name_id, id: name_id,
file: file!().as_c_slice(), file: file!().as_c_slice(),
line: line!(), line: line!(),
column: column!(), column: column!(),
// https://github.com/rust-lang/rfcs/pull/1719 // https://github.com/rust-lang/rfcs/pull/1719
function: "(Rust function)".as_c_slice(), function: "(Rust function)".as_c_slice(),
message: message_cl.as_c_slice(), message: message_cl.as_c_slice(),
param: [$param0, $param1, $param2] param: [$param0, $param1, $param2],
}; };
#[allow(unused_unsafe)] #[allow(unused_unsafe)]
unsafe { unsafe {
$crate::eh_artiq::raise(&exn) $crate::eh_artiq::raise(&exn)
} }
}); }};
($name:expr, $message:expr) => ({ ($name:expr, $message:expr) => {{ artiq_raise!($name, $message, 0, 0, 0) }};
artiq_raise!($name, $message, 0, 0, 0)
});
} }

View File

@ -1,9 +1,10 @@
use libboard_zynq; use libboard_zynq;
use crate::artiq_raise; use crate::artiq_raise;
pub static mut I2C_BUS: Option<libboard_zynq::i2c::I2c> = None; pub static mut I2C_BUS: Option<libboard_zynq::i2c::I2c> = None;
pub extern fn start(busno: i32) { pub extern "C" fn start(busno: i32) {
if busno > 0 { if busno > 0 {
artiq_raise!("I2CError", "I2C bus could not be accessed"); artiq_raise!("I2CError", "I2C bus could not be accessed");
} }
@ -14,7 +15,7 @@ pub extern fn start(busno: i32) {
} }
} }
pub extern fn restart(busno: i32) { pub extern "C" fn restart(busno: i32) {
if busno > 0 { if busno > 0 {
artiq_raise!("I2CError", "I2C bus could not be accessed"); artiq_raise!("I2CError", "I2C bus could not be accessed");
} }
@ -25,7 +26,7 @@ pub extern fn restart(busno: i32) {
} }
} }
pub extern fn stop(busno: i32) { pub extern "C" fn stop(busno: i32) {
if busno > 0 { if busno > 0 {
artiq_raise!("I2CError", "I2C bus could not be accessed"); artiq_raise!("I2CError", "I2C bus could not be accessed");
} }
@ -36,7 +37,7 @@ pub extern fn stop(busno: i32) {
} }
} }
pub extern fn write(busno: i32, data: i32) -> bool { pub extern "C" fn write(busno: i32, data: i32) -> bool {
if busno > 0 { if busno > 0 {
artiq_raise!("I2CError", "I2C bus could not be accessed"); artiq_raise!("I2CError", "I2C bus could not be accessed");
} }
@ -48,7 +49,7 @@ pub extern fn write(busno: i32, data: i32) -> bool {
} }
} }
pub extern fn read(busno: i32, ack: bool) -> i32 { pub extern "C" fn read(busno: i32, ack: bool) -> i32 {
if busno > 0 { if busno > 0 {
artiq_raise!("I2CError", "I2C bus could not be accessed"); artiq_raise!("I2CError", "I2C bus could not be accessed");
} }
@ -60,11 +61,12 @@ pub extern fn read(busno: i32, ack: bool) -> i32 {
} }
} }
pub extern fn switch_select(busno: i32, address: i32, mask: i32) { pub extern "C" fn switch_select(busno: i32, address: i32, mask: i32) {
if busno > 0 { if busno > 0 {
artiq_raise!("I2CError", "I2C bus could not be accessed"); artiq_raise!("I2CError", "I2C bus could not be accessed");
} }
let ch = match mask { //decode from mainline, PCA9548-centric API let ch = match mask {
//decode from mainline, PCA9548-centric API
0x00 => None, 0x00 => None,
0x01 => Some(0), 0x01 => Some(0),
0x02 => Some(1), 0x02 => Some(1),
@ -74,10 +76,15 @@ pub extern fn switch_select(busno: i32, address: i32, mask: i32) {
0x20 => Some(5), 0x20 => Some(5),
0x40 => Some(6), 0x40 => Some(6),
0x80 => Some(7), 0x80 => Some(7),
_ => artiq_raise!("I2CError", "switch select supports only one channel") _ => artiq_raise!("I2CError", "switch select supports only one channel"),
}; };
unsafe { unsafe {
if (&mut I2C_BUS).as_mut().unwrap().pca954x_select(address as u8, ch).is_err() { if (&mut I2C_BUS)
.as_mut()
.unwrap()
.pca954x_select(address as u8, ch)
.is_err()
{
artiq_raise!("I2CError", "switch select failed"); artiq_raise!("I2CError", "switch select failed");
} }
} }

View File

@ -1,12 +1,9 @@
use libboard_zynq::{gic, mpcore, println, stdio};
use libcortex_a9::{
asm, interrupt_handler,
regs::MPIDR,
spin_lock_yield, notify_spin_lock
};
use libregister::RegisterR;
use core::sync::atomic::{AtomicBool, Ordering}; use core::sync::atomic::{AtomicBool, Ordering};
use libboard_zynq::{gic, mpcore, println, stdio};
use libcortex_a9::{asm, interrupt_handler, notify_spin_lock, regs::MPIDR, spin_lock_yield};
use libregister::RegisterR;
extern "C" { extern "C" {
static mut __stack1_start: u32; static mut __stack1_start: u32;
fn main_core1() -> !; fn main_core1() -> !;

View File

@ -1,29 +1,25 @@
use core::ffi::VaList; use alloc::vec;
use core::ptr; use core::{ffi::VaList, ptr, str};
use core::str;
use libc::{c_char, c_int, size_t}; use libc::{c_char, c_int, size_t};
use libm; use libm;
use log::{info, warn}; use log::{info, warn};
use alloc::vec; use super::{cache,
core1::rtio_get_destination_status,
use crate::eh_artiq; dma,
use crate::rtio; rpc::{rpc_recv, rpc_send, rpc_send_async}};
use crate::i2c; use crate::{eh_artiq, i2c, rtio};
use super::rpc::{rpc_send, rpc_send_async, rpc_recv};
use super::dma;
use super::cache;
use super::core1::rtio_get_destination_status;
extern "C" { extern "C" {
fn vsnprintf_(buffer: *mut c_char, count: size_t, format: *const c_char, va: VaList) -> c_int; fn vsnprintf_(buffer: *mut c_char, count: size_t, format: *const c_char, va: VaList) -> c_int;
} }
unsafe extern fn core_log(fmt: *const c_char, mut args: ...) { unsafe extern "C" fn core_log(fmt: *const c_char, mut args: ...) {
let size = vsnprintf_(ptr::null_mut(), 0, fmt, args.as_va_list()) as usize; let size = vsnprintf_(ptr::null_mut(), 0, fmt, args.as_va_list()) as usize;
let mut buf = vec![0; size + 1]; let mut buf = vec![0; size + 1];
vsnprintf_(buf.as_mut_ptr() as *mut i8, size + 1, fmt, args.as_va_list()); vsnprintf_(buf.as_mut_ptr() as *mut i8, size + 1, fmt, args.as_va_list());
let buf: &[u8] = &buf.as_slice()[..size-1]; // strip \n and NUL let buf: &[u8] = &buf.as_slice()[..size - 1]; // strip \n and NUL
match str::from_utf8(buf) { match str::from_utf8(buf) {
Ok(s) => info!("kernel: {}", s), Ok(s) => info!("kernel: {}", s),
Err(e) => { Err(e) => {
@ -33,14 +29,13 @@ unsafe extern fn core_log(fmt: *const c_char, mut args: ...) {
} }
} }
unsafe extern fn rtio_log(fmt: *const c_char, mut args: ...) { unsafe extern "C" fn rtio_log(fmt: *const c_char, mut args: ...) {
let size = vsnprintf_(ptr::null_mut(), 0, fmt, args.as_va_list()) as usize; let size = vsnprintf_(ptr::null_mut(), 0, fmt, args.as_va_list()) as usize;
let mut buf = vec![0; size + 1]; let mut buf = vec![0; size + 1];
vsnprintf_(buf.as_mut_ptr(), size + 1, fmt, args.as_va_list()); vsnprintf_(buf.as_mut_ptr(), size + 1, fmt, args.as_va_list());
rtio::write_log(buf.as_slice()); rtio::write_log(buf.as_slice());
} }
macro_rules! api { macro_rules! api {
($i:ident) => ({ ($i:ident) => ({
extern { static $i: u8; } extern { static $i: u8; }
@ -56,24 +51,25 @@ macro_rules! api {
} }
macro_rules! api_libm_f64f64 { macro_rules! api_libm_f64f64 {
($i:ident) => ({ ($i:ident) => {{
extern fn $i(x: f64) -> f64 { extern "C" fn $i(x: f64) -> f64 {
libm::$i(x) libm::$i(x)
} }
api!($i = $i) api!($i = $i)
}) }};
} }
macro_rules! api_libm_f64f64f64 { macro_rules! api_libm_f64f64f64 {
($i:ident) => ({ ($i:ident) => {{
extern fn $i(x: f64, y: f64) -> f64 { extern "C" fn $i(x: f64, y: f64) -> f64 {
libm::$i(x, y) libm::$i(x, y)
} }
api!($i = $i) api!($i = $i)
}) }};
} }
pub fn resolve(required: &[u8]) -> Option<u32> { pub fn resolve(required: &[u8]) -> Option<u32> {
#[rustfmt::skip]
let api = &[ let api = &[
// timing // timing
api!(now_mu = rtio::now_mu), api!(now_mu = rtio::now_mu),
@ -124,6 +120,7 @@ pub fn resolve(required: &[u8]) -> Option<u32> {
api!(__aeabi_ddiv), api!(__aeabi_ddiv),
api!(__aeabi_dmul), api!(__aeabi_dmul),
api!(__aeabi_dsub), api!(__aeabi_dsub),
// Double-precision floating-point comparison helper functions // Double-precision floating-point comparison helper functions
// RTABI chapter 4.1.2, Table 3 // RTABI chapter 4.1.2, Table 3
api!(__aeabi_dcmpeq), api!(__aeabi_dcmpeq),
@ -133,12 +130,14 @@ pub fn resolve(required: &[u8]) -> Option<u32> {
api!(__aeabi_dcmpge), api!(__aeabi_dcmpge),
api!(__aeabi_dcmpgt), api!(__aeabi_dcmpgt),
api!(__aeabi_dcmpun), api!(__aeabi_dcmpun),
// Single-precision floating-point arithmetic helper functions // Single-precision floating-point arithmetic helper functions
// RTABI chapter 4.1.2, Table 4 // RTABI chapter 4.1.2, Table 4
api!(__aeabi_fadd), api!(__aeabi_fadd),
api!(__aeabi_fdiv), api!(__aeabi_fdiv),
api!(__aeabi_fmul), api!(__aeabi_fmul),
api!(__aeabi_fsub), api!(__aeabi_fsub),
// Single-precision floating-point comparison helper functions // Single-precision floating-point comparison helper functions
// RTABI chapter 4.1.2, Table 5 // RTABI chapter 4.1.2, Table 5
api!(__aeabi_fcmpeq), api!(__aeabi_fcmpeq),
@ -148,6 +147,7 @@ pub fn resolve(required: &[u8]) -> Option<u32> {
api!(__aeabi_fcmpge), api!(__aeabi_fcmpge),
api!(__aeabi_fcmpgt), api!(__aeabi_fcmpgt),
api!(__aeabi_fcmpun), api!(__aeabi_fcmpun),
// Floating-point to integer conversions. // Floating-point to integer conversions.
// RTABI chapter 4.1.2, Table 6 // RTABI chapter 4.1.2, Table 6
api!(__aeabi_d2iz), api!(__aeabi_d2iz),
@ -158,9 +158,11 @@ pub fn resolve(required: &[u8]) -> Option<u32> {
api!(__aeabi_f2uiz), api!(__aeabi_f2uiz),
api!(__aeabi_f2lz), api!(__aeabi_f2lz),
api!(__aeabi_f2ulz), api!(__aeabi_f2ulz),
// Conversions between floating types. // Conversions between floating types.
// RTABI chapter 4.1.2, Table 7 // RTABI chapter 4.1.2, Table 7
api!(__aeabi_f2d), api!(__aeabi_f2d),
// Integer to floating-point conversions. // Integer to floating-point conversions.
// RTABI chapter 4.1.2, Table 8 // RTABI chapter 4.1.2, Table 8
api!(__aeabi_i2d), api!(__aeabi_i2d),
@ -171,12 +173,14 @@ pub fn resolve(required: &[u8]) -> Option<u32> {
api!(__aeabi_ui2f), api!(__aeabi_ui2f),
api!(__aeabi_l2f), api!(__aeabi_l2f),
api!(__aeabi_ul2f), api!(__aeabi_ul2f),
// Long long helper functions // Long long helper functions
// RTABI chapter 4.2, Table 9 // RTABI chapter 4.2, Table 9
api!(__aeabi_lmul), api!(__aeabi_lmul),
api!(__aeabi_llsl), api!(__aeabi_llsl),
api!(__aeabi_llsr), api!(__aeabi_llsr),
api!(__aeabi_lasr), api!(__aeabi_lasr),
// Integer division functions // Integer division functions
// RTABI chapter 4.3.1 // RTABI chapter 4.3.1
api!(__aeabi_idiv), api!(__aeabi_idiv),
@ -184,6 +188,7 @@ pub fn resolve(required: &[u8]) -> Option<u32> {
api!(__aeabi_idivmod), api!(__aeabi_idivmod),
api!(__aeabi_uidiv), api!(__aeabi_uidiv),
api!(__aeabi_uldivmod), api!(__aeabi_uldivmod),
// 4.3.4 Memory copying, clearing, and setting // 4.3.4 Memory copying, clearing, and setting
api!(__aeabi_memcpy8), api!(__aeabi_memcpy8),
api!(__aeabi_memcpy4), api!(__aeabi_memcpy4),
@ -199,10 +204,30 @@ pub fn resolve(required: &[u8]) -> Option<u32> {
api!(__aeabi_memclr), api!(__aeabi_memclr),
// libc // libc
api!(memcpy, extern { fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8; }), api!(
api!(memmove, extern { fn memmove(dest: *mut u8, src: *const u8, n: usize) -> *mut u8; }), memcpy,
api!(memset, extern { fn memset(s: *mut u8, c: i32, n: usize) -> *mut u8; }), extern "C" {
api!(memcmp, extern { fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32; }), fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8;
}
),
api!(
memmove,
extern "C" {
fn memmove(dest: *mut u8, src: *const u8, n: usize) -> *mut u8;
}
),
api!(
memset,
extern "C" {
fn memset(s: *mut u8, c: i32, n: usize) -> *mut u8;
}
),
api!(
memcmp,
extern "C" {
fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32;
}
),
// exceptions // exceptions
api!(_Unwind_Resume = unwind::_Unwind_Resume), api!(_Unwind_Resume = unwind::_Unwind_Resume),
@ -210,6 +235,7 @@ pub fn resolve(required: &[u8]) -> Option<u32> {
api!(__nac3_raise = eh_artiq::raise), api!(__nac3_raise = eh_artiq::raise),
api!(__nac3_resume = eh_artiq::resume), api!(__nac3_resume = eh_artiq::resume),
api!(__nac3_end_catch = eh_artiq::end_catch), api!(__nac3_end_catch = eh_artiq::end_catch),
// legacy exception symbols // legacy exception symbols
api!(__artiq_personality = eh_artiq::artiq_personality), api!(__artiq_personality = eh_artiq::artiq_personality),
api!(__artiq_raise = eh_artiq::raise), api!(__artiq_raise = eh_artiq::raise),
@ -241,7 +267,7 @@ pub fn resolve(required: &[u8]) -> Option<u32> {
api_libm_f64f64!(fabs), api_libm_f64f64!(fabs),
api_libm_f64f64!(floor), api_libm_f64f64!(floor),
{ {
extern fn fma(x: f64, y: f64, z: f64) -> f64 { extern "C" fn fma(x: f64, y: f64, z: f64) -> f64 {
libm::fma(x, y, z) libm::fma(x, y, z)
} }
api!(fma = fma) api!(fma = fma)
@ -253,7 +279,7 @@ pub fn resolve(required: &[u8]) -> Option<u32> {
api_libm_f64f64!(j0), api_libm_f64f64!(j0),
api_libm_f64f64!(j1), api_libm_f64f64!(j1),
{ {
extern fn jn(n: i32, x: f64) -> f64 { extern "C" fn jn(n: i32, x: f64) -> f64 {
libm::jn(n, x) libm::jn(n, x)
} }
api!(jn = jn) api!(jn = jn)
@ -275,13 +301,13 @@ pub fn resolve(required: &[u8]) -> Option<u32> {
api_libm_f64f64!(y0), api_libm_f64f64!(y0),
api_libm_f64f64!(y1), api_libm_f64f64!(y1),
{ {
extern fn yn(n: i32, x: f64) -> f64 { extern "C" fn yn(n: i32, x: f64) -> f64 {
libm::yn(n, x) libm::yn(n, x)
} }
api!(yn = yn) api!(yn = yn)
}, },
]; ];
api.iter() api.iter()
.find(|&&(exported, _)| exported.as_bytes() == required) .find(|&&(exported, _)| exported.as_bytes() == required)
.map(|&(_, ptr)| ptr as u32) .map(|&(_, ptr)| ptr as u32)
} }

View File

@ -1,12 +1,17 @@
use alloc::{string::String, boxed::Box}; use alloc::{boxed::Box, string::String};
use cslice::{CSlice, AsCSlice}; use core::mem::{forget, transmute};
use core::mem::{transmute, forget};
use super::{KERNEL_CHANNEL_0TO1, KERNEL_CHANNEL_1TO0, Message};
pub extern fn get(key: CSlice<u8>) -> &CSlice<'static, i32> { use cslice::{AsCSlice, CSlice};
use super::{Message, KERNEL_CHANNEL_0TO1, KERNEL_CHANNEL_1TO0};
pub extern "C" fn get(key: CSlice<u8>) -> &CSlice<'static, i32> {
let key = String::from_utf8(key.as_ref().to_vec()).unwrap(); let key = String::from_utf8(key.as_ref().to_vec()).unwrap();
unsafe { unsafe {
KERNEL_CHANNEL_1TO0.as_mut().unwrap().send(Message::CacheGetRequest(key)); KERNEL_CHANNEL_1TO0
.as_mut()
.unwrap()
.send(Message::CacheGetRequest(key));
let msg = KERNEL_CHANNEL_0TO1.as_mut().unwrap().recv(); let msg = KERNEL_CHANNEL_0TO1.as_mut().unwrap().recv();
if let Message::CacheGetReply(v) = msg { if let Message::CacheGetReply(v) = msg {
let leaked = Box::new(v.as_c_slice()); let leaked = Box::new(v.as_c_slice());
@ -20,11 +25,13 @@ pub extern fn get(key: CSlice<u8>) -> &CSlice<'static, i32> {
} }
} }
pub extern fn put(key: CSlice<u8>, list: &CSlice<i32>) { pub extern "C" fn put(key: CSlice<u8>, list: &CSlice<i32>) {
let key = String::from_utf8(key.as_ref().to_vec()).unwrap(); let key = String::from_utf8(key.as_ref().to_vec()).unwrap();
let value = list.as_ref().to_vec(); let value = list.as_ref().to_vec();
unsafe { unsafe {
KERNEL_CHANNEL_1TO0.as_mut().unwrap().send(Message::CachePutRequest(key, value)); KERNEL_CHANNEL_1TO0
.as_mut()
.unwrap()
.send(Message::CachePutRequest(key, value));
} }
} }

View File

@ -1,11 +1,11 @@
use libcortex_a9::sync_channel::{Sender, Receiver}; use core::mem::{forget, replace};
use libcortex_a9::sync_channel::{Receiver, Sender};
use libsupport_zynq::boot::Core1; use libsupport_zynq::boot::Core1;
use super::{CHANNEL_0TO1, CHANNEL_1TO0, CHANNEL_SEM, INIT_LOCK, Message}; use super::{Message, CHANNEL_0TO1, CHANNEL_1TO0, CHANNEL_SEM, INIT_LOCK};
use crate::irq::restart_core1; use crate::irq::restart_core1;
use core::mem::{forget, replace};
pub struct Control { pub struct Control {
pub tx: Sender<'static, Message>, pub tx: Sender<'static, Message>,
pub rx: Receiver<'static, Message>, pub rx: Receiver<'static, Message>,
@ -53,4 +53,3 @@ impl Control {
forget(replace(&mut self.rx, core0_rx)); forget(replace(&mut self.rx, core0_rx));
} }
} }

View File

@ -1,31 +1,20 @@
//! Kernel prologue/epilogue that runs on the 2nd CPU core //! Kernel prologue/epilogue that runs on the 2nd CPU core
use core::{mem, ptr, cell::UnsafeCell};
use alloc::borrow::ToOwned; use alloc::borrow::ToOwned;
use log::{debug, info, error}; use core::{cell::UnsafeCell, mem, ptr};
use cslice::CSlice;
use libcortex_a9::{ use cslice::CSlice;
enable_fpu, use dyld::{self, elf::EXIDX_Entry, Library};
cache::{dcci_slice, iciallu, bpiall}, use libboard_zynq::{gic, mpcore};
asm::{dsb, isb}, use libcortex_a9::{asm::{dsb, isb},
sync_channel, cache::{bpiall, dcci_slice, iciallu},
}; enable_fpu, sync_channel};
use libboard_zynq::{mpcore, gic};
use libsupport_zynq::ram; use libsupport_zynq::ram;
use dyld::{self, Library, elf::EXIDX_Entry}; use log::{debug, error, info};
use super::{api::resolve, dma, rpc::rpc_send_async, Message, CHANNEL_0TO1, CHANNEL_1TO0, CHANNEL_SEM, INIT_LOCK,
KERNEL_CHANNEL_0TO1, KERNEL_CHANNEL_1TO0, KERNEL_IMAGE};
use crate::{eh_artiq, get_async_errors, rtio}; use crate::{eh_artiq, get_async_errors, rtio};
use super::{
api::resolve,
rpc::rpc_send_async,
INIT_LOCK,
CHANNEL_0TO1, CHANNEL_1TO0,
CHANNEL_SEM,
KERNEL_CHANNEL_0TO1, KERNEL_CHANNEL_1TO0,
KERNEL_IMAGE,
Message,
dma,
};
// linker symbols // linker symbols
extern "C" { extern "C" {
@ -38,13 +27,13 @@ extern "C" {
unsafe fn attribute_writeback(typeinfo: *const ()) { unsafe fn attribute_writeback(typeinfo: *const ()) {
struct Attr { struct Attr {
offset: usize, offset: usize,
tag: CSlice<'static, u8>, tag: CSlice<'static, u8>,
name: CSlice<'static, u8> name: CSlice<'static, u8>,
} }
struct Type { struct Type {
attributes: *const *const Attr, attributes: *const *const Attr,
objects: *const *const () objects: *const *const (),
} }
let mut tys = typeinfo as *const *const Type; let mut tys = typeinfo as *const *const Type;
@ -63,11 +52,16 @@ unsafe fn attribute_writeback(typeinfo: *const ()) {
attributes = attributes.offset(1); attributes = attributes.offset(1);
if (*attribute).tag.len() > 0 { if (*attribute).tag.len() > 0 {
rpc_send_async(0, &(*attribute).tag, [ rpc_send_async(
&object as *const _ as *const (), 0,
&(*attribute).name as *const _ as *const (), &(*attribute).tag,
(object as usize + (*attribute).offset) as *const () [
].as_ptr()); &object as *const _ as *const (),
&(*attribute).name as *const _ as *const (),
(object as usize + (*attribute).offset) as *const (),
]
.as_ptr(),
);
} }
} }
} }
@ -82,7 +76,8 @@ pub struct KernelImage {
impl KernelImage { impl KernelImage {
pub fn new(library: Library) -> Result<Self, dyld::Error> { pub fn new(library: Library) -> Result<Self, dyld::Error> {
let __modinit__ = library.lookup(b"__modinit__") let __modinit__ = library
.lookup(b"__modinit__")
.ok_or(dyld::Error::Lookup("__modinit__".to_owned()))?; .ok_or(dyld::Error::Lookup("__modinit__".to_owned()))?;
let typeinfo = library.lookup(b"typeinfo"); let typeinfo = library.lookup(b"typeinfo");
@ -90,8 +85,7 @@ impl KernelImage {
let bss_start = library.lookup(b"__bss_start"); let bss_start = library.lookup(b"__bss_start");
let end = library.lookup(b"_end"); let end = library.lookup(b"_end");
if let Some(bss_start) = bss_start { if let Some(bss_start) = bss_start {
let end = end let end = end.ok_or(dyld::Error::Lookup("_end".to_owned()))?;
.ok_or(dyld::Error::Lookup("_end".to_owned()))?;
unsafe { unsafe {
ptr::write_bytes(bss_start as *mut u8, 0, (end - bss_start) as usize); ptr::write_bytes(bss_start as *mut u8, 0, (end - bss_start) as usize);
} }
@ -126,9 +120,7 @@ impl KernelImage {
} }
pub fn get_load_addr(&self) -> usize { pub fn get_load_addr(&self) -> usize {
unsafe { unsafe { self.library.get().as_ref().unwrap().image.as_ptr() as usize }
self.library.get().as_ref().unwrap().image.as_ptr() as usize
}
} }
} }
@ -164,20 +156,19 @@ pub extern "C" fn main_core1() {
let message = core1_rx.recv(); let message = core1_rx.recv();
match message { match message {
Message::LoadRequest(data) => { Message::LoadRequest(data) => {
let result = dyld::load(&data, &resolve) let result = dyld::load(&data, &resolve).and_then(KernelImage::new);
.and_then(KernelImage::new);
match result { match result {
Ok(kernel) => { Ok(kernel) => {
loaded_kernel = Some(kernel); loaded_kernel = Some(kernel);
debug!("kernel loaded"); debug!("kernel loaded");
core1_tx.send(Message::LoadCompleted); core1_tx.send(Message::LoadCompleted);
}, }
Err(error) => { Err(error) => {
error!("failed to load shared library: {}", error); error!("failed to load shared library: {}", error);
core1_tx.send(Message::LoadFailed); core1_tx.send(Message::LoadFailed);
} }
} }
}, }
Message::StartRequest => { Message::StartRequest => {
info!("kernel starting"); info!("kernel starting");
if let Some(kernel) = loaded_kernel.take() { if let Some(kernel) = loaded_kernel.take() {
@ -202,9 +193,11 @@ pub extern "C" fn main_core1() {
} }
/// Called by eh_artiq /// Called by eh_artiq
pub fn terminate(exceptions: &'static [Option<eh_artiq::Exception<'static>>], pub fn terminate(
stack_pointers: &'static [eh_artiq::StackPointerBacktrace], exceptions: &'static [Option<eh_artiq::Exception<'static>>],
backtrace: &'static mut [(usize, usize)]) -> ! { stack_pointers: &'static [eh_artiq::StackPointerBacktrace],
backtrace: &'static mut [(usize, usize)],
) -> ! {
{ {
let core1_tx = unsafe { KERNEL_CHANNEL_1TO0.as_mut().unwrap() }; let core1_tx = unsafe { KERNEL_CHANNEL_1TO0.as_mut().unwrap() };
let errors = unsafe { get_async_errors() }; let errors = unsafe { get_async_errors() };
@ -215,7 +208,7 @@ pub fn terminate(exceptions: &'static [Option<eh_artiq::Exception<'static>>],
/// Called by llvm_libunwind /// Called by llvm_libunwind
#[no_mangle] #[no_mangle]
extern fn dl_unwind_find_exidx(pc: *const u32, len_ptr: *mut u32) -> *const u32 { extern "C" fn dl_unwind_find_exidx(pc: *const u32, len_ptr: *mut u32) -> *const u32 {
let length; let length;
let start: *const EXIDX_Entry; let start: *const EXIDX_Entry;
unsafe { unsafe {
@ -223,9 +216,14 @@ extern fn dl_unwind_find_exidx(pc: *const u32, len_ptr: *mut u32) -> *const u32
length = (&__exidx_end as *const EXIDX_Entry).offset_from(&__exidx_start) as u32; length = (&__exidx_end as *const EXIDX_Entry).offset_from(&__exidx_start) as u32;
start = &__exidx_start; start = &__exidx_start;
} else if KERNEL_IMAGE != ptr::null() { } else if KERNEL_IMAGE != ptr::null() {
let exidx = KERNEL_IMAGE.as_ref() let exidx = KERNEL_IMAGE
.as_ref()
.expect("dl_unwind_find_exidx kernel image") .expect("dl_unwind_find_exidx kernel image")
.library.get().as_ref().unwrap().exidx(); .library
.get()
.as_ref()
.unwrap()
.exidx();
length = exidx.len() as u32; length = exidx.len() as u32;
start = exidx.as_ptr(); start = exidx.as_ptr();
} else { } else {
@ -237,7 +235,7 @@ extern fn dl_unwind_find_exidx(pc: *const u32, len_ptr: *mut u32) -> *const u32
start as *const u32 start as *const u32
} }
pub extern fn rtio_get_destination_status(destination: i32) -> bool { pub extern "C" fn rtio_get_destination_status(destination: i32) -> bool {
#[cfg(has_drtio)] #[cfg(has_drtio)]
if destination > 0 && destination < 255 { if destination > 0 && destination < 255 {
let reply = unsafe { let reply = unsafe {
@ -248,9 +246,9 @@ pub extern fn rtio_get_destination_status(destination: i32) -> bool {
}; };
return match reply { return match reply {
Message::UpDestinationsReply(x) => x, Message::UpDestinationsReply(x) => x,
_ => panic!("received unexpected reply to UpDestinationsRequest: {:?}", reply) _ => panic!("received unexpected reply to UpDestinationsRequest: {:?}", reply),
}; };
} }
destination == 0 destination == 0
} }

View File

@ -1,21 +1,18 @@
use crate::{ use alloc::{boxed::Box, string::String, vec::Vec};
pl::csr,
artiq_raise,
rtio,
};
use alloc::{vec::Vec, string::String, boxed::Box};
use cslice::CSlice;
use super::{KERNEL_IMAGE, KERNEL_CHANNEL_0TO1, KERNEL_CHANNEL_1TO0, Message};
use core::mem; use core::mem;
use cslice::CSlice;
use libcortex_a9::cache::dcci_slice; use libcortex_a9::cache::dcci_slice;
use super::{Message, KERNEL_CHANNEL_0TO1, KERNEL_CHANNEL_1TO0, KERNEL_IMAGE};
use crate::{artiq_raise, pl::csr, rtio};
const ALIGNMENT: usize = 16 * 8; const ALIGNMENT: usize = 16 * 8;
#[repr(C)] #[repr(C)]
pub struct DmaTrace { pub struct DmaTrace {
duration: i64, duration: i64,
address: i32, address: i32,
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@ -33,10 +30,13 @@ pub unsafe fn init_dma_recorder() {
mem::forget(mem::replace(&mut RECORDER, None)); mem::forget(mem::replace(&mut RECORDER, None));
} }
pub extern fn dma_record_start(name: CSlice<u8>) { pub extern "C" fn dma_record_start(name: CSlice<u8>) {
let name = String::from_utf8(name.as_ref().to_vec()).unwrap(); let name = String::from_utf8(name.as_ref().to_vec()).unwrap();
unsafe { unsafe {
KERNEL_CHANNEL_1TO0.as_mut().unwrap().send(Message::DmaEraseRequest(name.clone())); KERNEL_CHANNEL_1TO0
.as_mut()
.unwrap()
.send(Message::DmaEraseRequest(name.clone()));
} }
unsafe { unsafe {
if RECORDER.is_some() { if RECORDER.is_some() {
@ -44,10 +44,10 @@ pub extern fn dma_record_start(name: CSlice<u8>) {
} }
let library = KERNEL_IMAGE.as_ref().unwrap(); let library = KERNEL_IMAGE.as_ref().unwrap();
library.rebind(b"rtio_output", library.rebind(b"rtio_output", dma_record_output as *const ()).unwrap();
dma_record_output as *const ()).unwrap(); library
library.rebind(b"rtio_output_wide", .rebind(b"rtio_output_wide", dma_record_output_wide as *const ())
dma_record_output_wide as *const ()).unwrap(); .unwrap();
RECORDER = Some(DmaRecorder { RECORDER = Some(DmaRecorder {
name, name,
@ -57,29 +57,29 @@ pub extern fn dma_record_start(name: CSlice<u8>) {
} }
} }
pub extern fn dma_record_stop(duration: i64) { pub extern "C" fn dma_record_stop(duration: i64) {
unsafe { unsafe {
if RECORDER.is_none() { if RECORDER.is_none() {
artiq_raise!("DMAError", "DMA is not recording") artiq_raise!("DMAError", "DMA is not recording")
} }
let library = KERNEL_IMAGE.as_ref().unwrap(); let library = KERNEL_IMAGE.as_ref().unwrap();
library.rebind(b"rtio_output", library.rebind(b"rtio_output", rtio::output as *const ()).unwrap();
rtio::output as *const ()).unwrap(); library
library.rebind(b"rtio_output_wide", .rebind(b"rtio_output_wide", rtio::output_wide as *const ())
rtio::output_wide as *const ()).unwrap(); .unwrap();
let mut recorder = RECORDER.take().unwrap(); let mut recorder = RECORDER.take().unwrap();
recorder.duration = duration; recorder.duration = duration;
KERNEL_CHANNEL_1TO0.as_mut().unwrap().send( KERNEL_CHANNEL_1TO0
Message::DmaPutRequest(recorder) .as_mut()
); .unwrap()
.send(Message::DmaPutRequest(recorder));
} }
} }
#[inline(always)] #[inline(always)]
unsafe fn dma_record_output_prepare(timestamp: i64, target: i32, unsafe fn dma_record_output_prepare(timestamp: i64, target: i32, words: usize) {
words: usize) {
// See gateware/rtio/dma.py. // See gateware/rtio/dma.py.
const HEADER_LENGTH: usize = /*length*/1 + /*channel*/3 + /*timestamp*/8 + /*address*/1; const HEADER_LENGTH: usize = /*length*/1 + /*channel*/3 + /*timestamp*/8 + /*address*/1;
let length = HEADER_LENGTH + /*data*/words * 4; let length = HEADER_LENGTH + /*data*/words * 4;
@ -87,36 +87,36 @@ unsafe fn dma_record_output_prepare(timestamp: i64, target: i32,
let buffer = &mut RECORDER.as_mut().unwrap().buffer; let buffer = &mut RECORDER.as_mut().unwrap().buffer;
buffer.reserve(length); buffer.reserve(length);
buffer.extend_from_slice(&[ buffer.extend_from_slice(&[
(length >> 0) as u8, (length >> 0) as u8,
(target >> 8) as u8, (target >> 8) as u8,
(target >> 16) as u8, (target >> 16) as u8,
(target >> 24) as u8, (target >> 24) as u8,
(timestamp >> 0) as u8, (timestamp >> 0) as u8,
(timestamp >> 8) as u8, (timestamp >> 8) as u8,
(timestamp >> 16) as u8, (timestamp >> 16) as u8,
(timestamp >> 24) as u8, (timestamp >> 24) as u8,
(timestamp >> 32) as u8, (timestamp >> 32) as u8,
(timestamp >> 40) as u8, (timestamp >> 40) as u8,
(timestamp >> 48) as u8, (timestamp >> 48) as u8,
(timestamp >> 56) as u8, (timestamp >> 56) as u8,
(target >> 0) as u8, (target >> 0) as u8,
]); ]);
} }
pub extern fn dma_record_output(target: i32, word: i32) { pub extern "C" fn dma_record_output(target: i32, word: i32) {
unsafe { unsafe {
let timestamp = rtio::now_mu(); let timestamp = rtio::now_mu();
dma_record_output_prepare(timestamp, target, 1); dma_record_output_prepare(timestamp, target, 1);
RECORDER.as_mut().unwrap().buffer.extend_from_slice(&[ RECORDER.as_mut().unwrap().buffer.extend_from_slice(&[
(word >> 0) as u8, (word >> 0) as u8,
(word >> 8) as u8, (word >> 8) as u8,
(word >> 16) as u8, (word >> 16) as u8,
(word >> 24) as u8, (word >> 24) as u8,
]); ]);
} }
} }
pub extern fn dma_record_output_wide(target: i32, words: CSlice<i32>) { pub extern "C" fn dma_record_output_wide(target: i32, words: CSlice<i32>) {
assert!(words.len() <= 16); // enforce the hardware limit assert!(words.len() <= 16); // enforce the hardware limit
unsafe { unsafe {
@ -125,8 +125,8 @@ pub extern fn dma_record_output_wide(target: i32, words: CSlice<i32>) {
let buffer = &mut RECORDER.as_mut().unwrap().buffer; let buffer = &mut RECORDER.as_mut().unwrap().buffer;
for word in words.as_ref().iter() { for word in words.as_ref().iter() {
buffer.extend_from_slice(&[ buffer.extend_from_slice(&[
(word >> 0) as u8, (word >> 0) as u8,
(word >> 8) as u8, (word >> 8) as u8,
(word >> 16) as u8, (word >> 16) as u8,
(word >> 24) as u8, (word >> 24) as u8,
]); ]);
@ -134,19 +134,22 @@ pub extern fn dma_record_output_wide(target: i32, words: CSlice<i32>) {
} }
} }
pub extern fn dma_erase(name: CSlice<u8>) { pub extern "C" fn dma_erase(name: CSlice<u8>) {
let name = String::from_utf8(name.as_ref().to_vec()).unwrap(); let name = String::from_utf8(name.as_ref().to_vec()).unwrap();
unsafe { unsafe {
KERNEL_CHANNEL_1TO0.as_mut().unwrap().send(Message::DmaEraseRequest(name)); KERNEL_CHANNEL_1TO0
.as_mut()
.unwrap()
.send(Message::DmaEraseRequest(name));
} }
} }
pub extern fn dma_retrieve(name: CSlice<u8>) -> DmaTrace { pub extern "C" fn dma_retrieve(name: CSlice<u8>) -> DmaTrace {
let name = String::from_utf8(name.as_ref().to_vec()).unwrap(); let name = String::from_utf8(name.as_ref().to_vec()).unwrap();
unsafe { unsafe {
KERNEL_CHANNEL_1TO0.as_mut().unwrap().send(Message::DmaGetRequest(name)); KERNEL_CHANNEL_1TO0.as_mut().unwrap().send(Message::DmaGetRequest(name));
} }
match unsafe {KERNEL_CHANNEL_0TO1.as_mut().unwrap()}.recv() { match unsafe { KERNEL_CHANNEL_0TO1.as_mut().unwrap() }.recv() {
Message::DmaGetReply(None) => (), Message::DmaGetReply(None) => (),
Message::DmaGetReply(Some((mut v, duration))) => { Message::DmaGetReply(Some((mut v, duration))) => {
v.reserve(ALIGNMENT - 1); v.reserve(ALIGNMENT - 1);
@ -162,18 +165,15 @@ pub extern fn dma_retrieve(name: CSlice<u8>) -> DmaTrace {
dcci_slice(&v); dcci_slice(&v);
let v = Box::new(v); let v = Box::new(v);
let address = Box::into_raw(v) as *mut Vec<u8> as i32; let address = Box::into_raw(v) as *mut Vec<u8> as i32;
return DmaTrace { return DmaTrace { address, duration };
address, }
duration,
};
},
_ => panic!("Expected DmaGetReply after DmaGetRequest!"), _ => panic!("Expected DmaGetReply after DmaGetRequest!"),
} }
// we have to defer raising error as we have to drop the message first... // we have to defer raising error as we have to drop the message first...
artiq_raise!("DMAError", "DMA trace not found"); artiq_raise!("DMAError", "DMA trace not found");
} }
pub extern fn dma_playback(timestamp: i64, ptr: i32) { pub extern "C" fn dma_playback(timestamp: i64, ptr: i32) {
unsafe { unsafe {
let v = Box::from_raw(ptr as *mut Vec<u8>); let v = Box::from_raw(ptr as *mut Vec<u8>);
let padding = ALIGNMENT - v.as_ptr() as usize % ALIGNMENT; let padding = ALIGNMENT - v.as_ptr() as usize % ALIGNMENT;
@ -197,16 +197,23 @@ pub extern fn dma_playback(timestamp: i64, ptr: i32) {
let channel = csr::rtio_dma::error_channel_read(); let channel = csr::rtio_dma::error_channel_read();
csr::rtio_dma::error_write(1); csr::rtio_dma::error_write(1);
if error & 1 != 0 { if error & 1 != 0 {
artiq_raise!("RTIOUnderflow", artiq_raise!(
"RTIOUnderflow",
"RTIO underflow at {1} mu, channel {rtio_channel_info:0}", "RTIO underflow at {1} mu, channel {rtio_channel_info:0}",
channel as i64, timestamp as i64, 0); channel as i64,
timestamp as i64,
0
);
} }
if error & 2 != 0 { if error & 2 != 0 {
artiq_raise!("RTIODestinationUnreachable", artiq_raise!(
"RTIODestinationUnreachable",
"RTIO destination unreachable, output, at {1} mu, channel {rtio_channel_info:0}", "RTIO destination unreachable, output, at {1} mu, channel {rtio_channel_info:0}",
channel as i64, timestamp as i64, 0); channel as i64,
timestamp as i64,
0
);
} }
} }
} }
} }

View File

@ -1,15 +1,16 @@
use alloc::{string::String, vec::Vec};
use core::ptr; use core::ptr;
use alloc::{vec::Vec, string::String};
use libcortex_a9::{mutex::Mutex, sync_channel, semaphore::Semaphore}; use libcortex_a9::{mutex::Mutex, semaphore::Semaphore, sync_channel};
use crate::eh_artiq; use crate::eh_artiq;
mod control; mod control;
pub use control::Control; pub use control::Control;
pub mod core1;
mod api; mod api;
mod rpc; pub mod core1;
mod dma; mod dma;
mod rpc;
pub use dma::DmaRecorder; pub use dma::DmaRecorder;
mod cache; mod cache;
@ -21,7 +22,7 @@ pub struct RPCException {
pub file: u32, pub file: u32,
pub line: i32, pub line: i32,
pub column: i32, pub column: i32,
pub function: u32 pub function: u32,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -31,11 +32,16 @@ pub enum Message {
LoadFailed, LoadFailed,
StartRequest, StartRequest,
KernelFinished(u8), KernelFinished(u8),
KernelException(&'static [Option<eh_artiq::Exception<'static>>], KernelException(
&'static [eh_artiq::StackPointerBacktrace], &'static [Option<eh_artiq::Exception<'static>>],
&'static [(usize, usize)], &'static [eh_artiq::StackPointerBacktrace],
u8), &'static [(usize, usize)],
RpcSend { is_async: bool, data: Vec<u8> }, u8,
),
RpcSend {
is_async: bool,
data: Vec<u8>,
},
RpcRecvRequest(*mut ()), RpcRecvRequest(*mut ()),
RpcRecvReply(Result<usize, RPCException>), RpcRecvReply(Result<usize, RPCException>),
@ -64,4 +70,3 @@ static mut KERNEL_CHANNEL_1TO0: Option<sync_channel::Sender<'static, Message>> =
pub static mut KERNEL_IMAGE: *const core1::KernelImage = ptr::null(); pub static mut KERNEL_IMAGE: *const core1::KernelImage = ptr::null();
static INIT_LOCK: Mutex<()> = Mutex::new(()); static INIT_LOCK: Mutex<()> = Mutex::new(());

View File

@ -1,14 +1,11 @@
//! Kernel-side RPC API //! Kernel-side RPC API
use alloc::vec::Vec; use alloc::vec::Vec;
use cslice::CSlice; use cslice::CSlice;
use crate::eh_artiq; use super::{Message, KERNEL_CHANNEL_0TO1, KERNEL_CHANNEL_1TO0};
use crate::rpc::send_args; use crate::{eh_artiq, rpc::send_args};
use super::{
KERNEL_CHANNEL_0TO1, KERNEL_CHANNEL_1TO0,
Message,
};
fn rpc_send_common(is_async: bool, service: u32, tag: &CSlice<u8>, data: *const *const ()) { fn rpc_send_common(is_async: bool, service: u32, tag: &CSlice<u8>, data: *const *const ()) {
let core1_tx = unsafe { KERNEL_CHANNEL_1TO0.as_mut().unwrap() }; let core1_tx = unsafe { KERNEL_CHANNEL_1TO0.as_mut().unwrap() };
@ -17,15 +14,15 @@ fn rpc_send_common(is_async: bool, service: u32, tag: &CSlice<u8>, data: *const
core1_tx.send(Message::RpcSend { is_async, data: buffer }); core1_tx.send(Message::RpcSend { is_async, data: buffer });
} }
pub extern fn rpc_send(service: u32, tag: &CSlice<u8>, data: *const *const ()) { pub extern "C" fn rpc_send(service: u32, tag: &CSlice<u8>, data: *const *const ()) {
rpc_send_common(false, service, tag, data); rpc_send_common(false, service, tag, data);
} }
pub extern fn rpc_send_async(service: u32, tag: &CSlice<u8>, data: *const *const ()) { pub extern "C" fn rpc_send_async(service: u32, tag: &CSlice<u8>, data: *const *const ()) {
rpc_send_common(true, service, tag, data); rpc_send_common(true, service, tag, data);
} }
pub extern fn rpc_recv(slot: *mut ()) -> usize { pub extern "C" fn rpc_recv(slot: *mut ()) -> usize {
let reply = unsafe { let reply = unsafe {
let core1_rx = KERNEL_CHANNEL_0TO1.as_mut().unwrap(); let core1_rx = KERNEL_CHANNEL_0TO1.as_mut().unwrap();
let core1_tx = KERNEL_CHANNEL_1TO0.as_mut().unwrap(); let core1_tx = KERNEL_CHANNEL_1TO0.as_mut().unwrap();
@ -36,15 +33,15 @@ pub extern fn rpc_recv(slot: *mut ()) -> usize {
Message::RpcRecvReply(Ok(alloc_size)) => alloc_size, Message::RpcRecvReply(Ok(alloc_size)) => alloc_size,
Message::RpcRecvReply(Err(exception)) => unsafe { Message::RpcRecvReply(Err(exception)) => unsafe {
eh_artiq::raise(&eh_artiq::Exception { eh_artiq::raise(&eh_artiq::Exception {
id: exception.id, id: exception.id,
file: CSlice::new(exception.file as *const u8, usize::MAX), file: CSlice::new(exception.file as *const u8, usize::MAX),
line: exception.line as u32, line: exception.line as u32,
column: exception.column as u32, column: exception.column as u32,
function: CSlice::new(exception.function as *const u8, usize::MAX), function: CSlice::new(exception.function as *const u8, usize::MAX),
message: CSlice::new(exception.message as *const u8, usize::MAX), message: CSlice::new(exception.message as *const u8, usize::MAX),
param: exception.param param: exception.param,
}) })
}, },
_ => panic!("received unexpected reply to RpcRecvRequest: {:?}", reply) _ => panic!("received unexpected reply to RpcRecvRequest: {:?}", reply),
} }
} }

View File

@ -1,6 +1,6 @@
#![no_std] #![no_std]
#![no_main] #![no_main]
#![recursion_limit="1024"] // for futures_util::select! #![recursion_limit = "1024"] // for futures_util::select!
#![feature(alloc_error_handler)] #![feature(alloc_error_handler)]
#![feature(panic_info_message)] #![feature(panic_info_message)]
#![feature(c_variadic)] #![feature(c_variadic)]
@ -12,25 +12,32 @@
#[macro_use] #[macro_use]
extern crate alloc; extern crate alloc;
use log::{info, warn, error}; use libasync::{block_async, task};
use libboard_zynq::{timer::GlobalTimer, mpcore, gic};
use libasync::{task, block_async};
use libsupport_zynq::ram;
use nb;
use void::Void;
use libconfig::Config;
use libcortex_a9::l2c::enable_l2_cache;
use libboard_artiq::{logger, identifier_read, pl};
#[cfg(feature = "target_kasli_soc")] #[cfg(feature = "target_kasli_soc")]
use libboard_artiq::io_expander; use libboard_artiq::io_expander;
use libboard_artiq::{identifier_read, logger, pl};
use libboard_zynq::{gic, mpcore, timer::GlobalTimer};
use libconfig::Config;
use libcortex_a9::l2c::enable_l2_cache;
use libsupport_zynq::ram;
use log::{error, info, warn};
use nb;
use void::Void;
const ASYNC_ERROR_COLLISION: u8 = 1 << 0; const ASYNC_ERROR_COLLISION: u8 = 1 << 0;
const ASYNC_ERROR_BUSY: u8 = 1 << 1; const ASYNC_ERROR_BUSY: u8 = 1 << 1;
const ASYNC_ERROR_SEQUENCE_ERROR: u8 = 1 << 2; const ASYNC_ERROR_SEQUENCE_ERROR: u8 = 1 << 2;
mod proto_async; mod analyzer;
mod comms; mod comms;
mod eh_artiq;
mod i2c;
mod irq;
mod kernel;
mod mgmt;
mod moninj;
mod panic;
mod proto_async;
mod rpc; mod rpc;
#[cfg(ki_impl = "csr")] #[cfg(ki_impl = "csr")]
#[path = "rtio_csr.rs"] #[path = "rtio_csr.rs"]
@ -38,16 +45,8 @@ mod rtio;
#[cfg(ki_impl = "acp")] #[cfg(ki_impl = "acp")]
#[path = "rtio_acp.rs"] #[path = "rtio_acp.rs"]
mod rtio; mod rtio;
mod rtio_mgt;
mod rtio_clocking; mod rtio_clocking;
mod kernel; mod rtio_mgt;
mod moninj;
mod eh_artiq;
mod panic;
mod mgmt;
mod analyzer;
mod irq;
mod i2c;
static mut SEEN_ASYNC_ERRORS: u8 = 0; static mut SEEN_ASYNC_ERRORS: u8 = 0;
@ -74,15 +73,27 @@ async fn report_async_rtio_errors() {
let errors = pl::csr::rtio_core::async_error_read(); let errors = pl::csr::rtio_core::async_error_read();
if errors & ASYNC_ERROR_COLLISION != 0 { if errors & ASYNC_ERROR_COLLISION != 0 {
let channel = pl::csr::rtio_core::collision_channel_read(); let channel = pl::csr::rtio_core::collision_channel_read();
error!("RTIO collision involving channel 0x{:04x}:{}", channel, rtio_mgt::resolve_channel_name(channel as u32)); error!(
"RTIO collision involving channel 0x{:04x}:{}",
channel,
rtio_mgt::resolve_channel_name(channel as u32)
);
} }
if errors & ASYNC_ERROR_BUSY != 0 { if errors & ASYNC_ERROR_BUSY != 0 {
let channel = pl::csr::rtio_core::busy_channel_read(); let channel = pl::csr::rtio_core::busy_channel_read();
error!("RTIO busy error involving channel 0x{:04x}:{}", channel, rtio_mgt::resolve_channel_name(channel as u32)); error!(
"RTIO busy error involving channel 0x{:04x}:{}",
channel,
rtio_mgt::resolve_channel_name(channel as u32)
);
} }
if errors & ASYNC_ERROR_SEQUENCE_ERROR != 0 { if errors & ASYNC_ERROR_SEQUENCE_ERROR != 0 {
let channel = pl::csr::rtio_core::sequence_error_channel_read(); let channel = pl::csr::rtio_core::sequence_error_channel_read();
error!("RTIO sequence error involving channel 0x{:04x}:{}", channel, rtio_mgt::resolve_channel_name(channel as u32)); error!(
"RTIO sequence error involving channel 0x{:04x}:{}",
channel,
rtio_mgt::resolve_channel_name(channel as u32)
);
} }
SEEN_ASYNC_ERRORS = errors; SEEN_ASYNC_ERRORS = errors;
pl::csr::rtio_core::async_error_write(errors); pl::csr::rtio_core::async_error_write(errors);
@ -90,18 +101,14 @@ async fn report_async_rtio_errors() {
} }
} }
static mut LOG_BUFFER: [u8; 1 << 17] = [0; 1 << 17];
static mut LOG_BUFFER: [u8; 1<<17] = [0; 1<<17];
#[no_mangle] #[no_mangle]
pub fn main_core0() { pub fn main_core0() {
enable_l2_cache(0x8); enable_l2_cache(0x8);
let mut timer = GlobalTimer::start(); let mut timer = GlobalTimer::start();
let buffer_logger = unsafe { let buffer_logger = unsafe { logger::BufferLogger::new(&mut LOG_BUFFER[..]) };
logger::BufferLogger::new(&mut LOG_BUFFER[..])
};
buffer_logger.set_uart_log_level(log::LevelFilter::Info); buffer_logger.set_uart_log_level(log::LevelFilter::Info);
buffer_logger.register(); buffer_logger.register();
log::set_max_level(log::LevelFilter::Info); log::set_max_level(log::LevelFilter::Info);
@ -137,7 +144,7 @@ pub fn main_core0() {
Config::new_dummy() Config::new_dummy()
} }
}; };
rtio_clocking::init(&mut timer, &cfg); rtio_clocking::init(&mut timer, &cfg);
task::spawn(report_async_rtio_errors()); task::spawn(report_async_rtio_errors());

View File

@ -1,16 +1,17 @@
use alloc::{rc::Rc, string::String, vec::Vec};
use core::cell::RefCell;
use futures::{future::poll_fn, task::Poll}; use futures::{future::poll_fn, task::Poll};
use libasync::{smoltcp::TcpStream, task}; use libasync::{smoltcp::TcpStream, task};
use libboard_zynq::{smoltcp, slcr};
use libconfig::Config;
use core::cell::RefCell;
use alloc::{rc::Rc, vec::Vec, string::String};
use log::{self, info, debug, warn, error, LevelFilter};
use libboard_artiq::logger::{BufferLogger, LogBufferRef}; use libboard_artiq::logger::{BufferLogger, LogBufferRef};
use crate::proto_async::*; use libboard_zynq::{slcr, smoltcp};
use libconfig::Config;
use log::{self, debug, error, info, warn, LevelFilter};
use num_derive::FromPrimitive; use num_derive::FromPrimitive;
use num_traits::FromPrimitive; use num_traits::FromPrimitive;
use crate::proto_async::*;
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Error { pub enum Error {
NetworkError(smoltcp::Error), NetworkError(smoltcp::Error),
@ -24,10 +25,10 @@ type Result<T> = core::result::Result<T, Error>;
impl core::fmt::Display for Error { impl core::fmt::Display for Error {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
match self { match self {
&Error::NetworkError(error) => write!(f, "network error: {}", error), &Error::NetworkError(error) => write!(f, "network error: {}", error),
&Error::UnknownLogLevel(lvl) => write!(f, "unknown log level {}", lvl), &Error::UnknownLogLevel(lvl) => write!(f, "unknown log level {}", lvl),
&Error::UnexpectedPattern => write!(f, "unexpected pattern"), &Error::UnexpectedPattern => write!(f, "unexpected pattern"),
&Error::UnrecognizedPacket => write!(f, "unrecognized packet"), &Error::UnrecognizedPacket => write!(f, "unrecognized packet"),
} }
} }
} }
@ -74,9 +75,7 @@ async fn read_log_level_filter(stream: &mut TcpStream) -> Result<log::LevelFilte
} }
async fn get_logger_buffer_pred<F>(f: F) -> LogBufferRef<'static> async fn get_logger_buffer_pred<F>(f: F) -> LogBufferRef<'static>
where where F: Fn(&LogBufferRef) -> bool {
F: Fn(&LogBufferRef) -> bool,
{
poll_fn(|ctx| { poll_fn(|ctx| {
let logger = unsafe { BufferLogger::get_logger().as_mut().unwrap() }; let logger = unsafe { BufferLogger::get_logger().as_mut().unwrap() };
match logger.buffer() { match logger.buffer() {
@ -112,10 +111,7 @@ async fn read_key(stream: &mut TcpStream) -> Result<String> {
Ok(String::from_utf8(buffer).unwrap()) Ok(String::from_utf8(buffer).unwrap())
} }
async fn handle_connection( async fn handle_connection(stream: &mut TcpStream, pull_id: Rc<RefCell<u32>>, cfg: Rc<Config>) -> Result<()> {
stream: &mut TcpStream,
pull_id: Rc<RefCell<u32>>,
cfg: Rc<Config>) -> Result<()> {
if !expect(&stream, b"ARTIQ management\n").await? { if !expect(&stream, b"ARTIQ management\n").await? {
return Err(Error::UnexpectedPattern); return Err(Error::UnexpectedPattern);
} }
@ -163,7 +159,7 @@ async fn handle_connection(
logger.set_buffer_log_level(LevelFilter::Trace); logger.set_buffer_log_level(LevelFilter::Trace);
} }
} }
}, }
Request::SetLogFilter => { Request::SetLogFilter => {
let lvl = read_log_level_filter(stream).await?; let lvl = read_log_level_filter(stream).await?;
info!("Changing log level to {}", lvl); info!("Changing log level to {}", lvl);
@ -174,10 +170,7 @@ async fn handle_connection(
let lvl = read_log_level_filter(stream).await?; let lvl = read_log_level_filter(stream).await?;
info!("Changing UART log level to {}", lvl); info!("Changing UART log level to {}", lvl);
unsafe { unsafe {
BufferLogger::get_logger() BufferLogger::get_logger().as_ref().unwrap().set_uart_log_level(lvl);
.as_ref()
.unwrap()
.set_uart_log_level(lvl);
} }
write_i8(stream, Reply::Success as i8).await?; write_i8(stream, Reply::Success as i8).await?;
} }
@ -193,16 +186,12 @@ async fn handle_connection(
warn!("read error: no such key"); warn!("read error: no such key");
write_i8(stream, Reply::Error as i8).await?; write_i8(stream, Reply::Error as i8).await?;
} }
}, }
Request::ConfigWrite => { Request::ConfigWrite => {
let key = read_key(stream).await?; let key = read_key(stream).await?;
debug!("write key: {}", key); debug!("write key: {}", key);
let len = read_i32(stream).await?; let len = read_i32(stream).await?;
let len = if len <= 0 { let len = if len <= 0 { 0 } else { len as usize };
0
} else {
len as usize
};
let mut buffer = Vec::with_capacity(len); let mut buffer = Vec::with_capacity(len);
unsafe { unsafe {
buffer.set_len(len); buffer.set_len(len);
@ -217,7 +206,7 @@ async fn handle_connection(
error!("failed to write: {:?}", value); error!("failed to write: {:?}", value);
write_i8(stream, Reply::Error as i8).await?; write_i8(stream, Reply::Error as i8).await?;
} }
}, }
Request::ConfigRemove => { Request::ConfigRemove => {
let key = read_key(stream).await?; let key = read_key(stream).await?;
debug!("erase key: {}", key); debug!("erase key: {}", key);
@ -229,7 +218,7 @@ async fn handle_connection(
warn!("erase failed"); warn!("erase failed");
write_i8(stream, Reply::Error as i8).await?; write_i8(stream, Reply::Error as i8).await?;
} }
}, }
Request::Reboot => { Request::Reboot => {
info!("rebooting"); info!("rebooting");
write_i8(stream, Reply::RebootImminent as i8).await?; write_i8(stream, Reply::RebootImminent as i8).await?;

View File

@ -1,26 +1,23 @@
use core::{fmt, cell::RefCell};
use alloc::{collections::BTreeMap, rc::Rc}; use alloc::{collections::BTreeMap, rc::Rc};
use log::{debug, info, warn}; use core::{cell::RefCell, fmt};
use void::Void;
use futures::{pin_mut, select_biased, FutureExt};
use libasync::{block_async, nb, smoltcp::TcpStream, task};
use libboard_artiq::drtio_routing; use libboard_artiq::drtio_routing;
use libboard_zynq::{smoltcp, time::Milliseconds, timer::GlobalTimer};
use libboard_zynq::{smoltcp, timer::GlobalTimer, time::Milliseconds};
use libasync::{task, smoltcp::TcpStream, block_async, nb};
use libcortex_a9::mutex::Mutex; use libcortex_a9::mutex::Mutex;
use log::{debug, info, warn};
use num_derive::{FromPrimitive, ToPrimitive}; use num_derive::{FromPrimitive, ToPrimitive};
use num_traits::{FromPrimitive, ToPrimitive}; use num_traits::{FromPrimitive, ToPrimitive};
use futures::{pin_mut, select_biased, FutureExt}; use void::Void;
use crate::proto_async::*; use crate::proto_async::*;
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Error { pub enum Error {
NetworkError(smoltcp::Error), NetworkError(smoltcp::Error),
UnexpectedPattern, UnexpectedPattern,
UnrecognizedPacket UnrecognizedPacket,
} }
pub type Result<T> = core::result::Result<T, Error>; pub type Result<T> = core::result::Result<T, Error>;
@ -29,8 +26,8 @@ impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self { match self {
&Error::NetworkError(error) => write!(f, "network error: {}", error), &Error::NetworkError(error) => write!(f, "network error: {}", error),
&Error::UnexpectedPattern => write!(f, "unexpected pattern"), &Error::UnexpectedPattern => write!(f, "unexpected pattern"),
&Error::UnrecognizedPacket => write!(f, "unrecognized packet"), &Error::UnrecognizedPacket => write!(f, "unrecognized packet"),
} }
} }
} }
@ -46,60 +43,102 @@ enum HostMessage {
MonitorProbe = 0, MonitorProbe = 0,
MonitorInjection = 3, MonitorInjection = 3,
Inject = 1, Inject = 1,
GetInjectionStatus = 2 GetInjectionStatus = 2,
} }
#[derive(Debug, FromPrimitive, ToPrimitive)] #[derive(Debug, FromPrimitive, ToPrimitive)]
enum DeviceMessage { enum DeviceMessage {
MonitorStatus = 0, MonitorStatus = 0,
InjectionStatus = 1 InjectionStatus = 1,
} }
#[cfg(has_drtio)] #[cfg(has_drtio)]
mod remote_moninj { mod remote_moninj {
use super::*;
use libboard_artiq::drtioaux_async; use libboard_artiq::drtioaux_async;
use crate::rtio_mgt::drtio;
use log::error; use log::error;
pub async fn read_probe(aux_mutex: &Rc<Mutex<bool>>, timer: GlobalTimer, linkno: u8, destination: u8, channel: i32, probe: i8) -> i64 { use super::*;
let reply = drtio::aux_transact(aux_mutex, linkno, &drtioaux_async::Packet::MonitorRequest { use crate::rtio_mgt::drtio;
destination: destination,
channel: channel as _, pub async fn read_probe(
probe: probe as _}, aux_mutex: &Rc<Mutex<bool>>,
timer).await; timer: GlobalTimer,
linkno: u8,
destination: u8,
channel: i32,
probe: i8,
) -> i64 {
let reply = drtio::aux_transact(
aux_mutex,
linkno,
&drtioaux_async::Packet::MonitorRequest {
destination: destination,
channel: channel as _,
probe: probe as _,
},
timer,
)
.await;
match reply { match reply {
Ok(drtioaux_async::Packet::MonitorReply { value }) => return value as i64, Ok(drtioaux_async::Packet::MonitorReply { value }) => return value as i64,
Ok(packet) => error!("received unexpected aux packet: {:?}", packet), Ok(packet) => error!("received unexpected aux packet: {:?}", packet),
Err("link went down") => { debug!("link is down"); }, Err("link went down") => {
Err(e) => error!("aux packet error ({})", e) debug!("link is down");
}
Err(e) => error!("aux packet error ({})", e),
} }
0 0
} }
pub async fn inject(aux_mutex: &Rc<Mutex<bool>>, _timer: GlobalTimer, linkno: u8, destination: u8, channel: i32, overrd: i8, value: i8) { pub async fn inject(
aux_mutex: &Rc<Mutex<bool>>,
_timer: GlobalTimer,
linkno: u8,
destination: u8,
channel: i32,
overrd: i8,
value: i8,
) {
let _lock = aux_mutex.lock(); let _lock = aux_mutex.lock();
drtioaux_async::send(linkno, &drtioaux_async::Packet::InjectionRequest { drtioaux_async::send(
destination: destination, linkno,
channel: channel as _, &drtioaux_async::Packet::InjectionRequest {
overrd: overrd as _, destination: destination,
value: value as _ channel: channel as _,
}).await.unwrap(); overrd: overrd as _,
value: value as _,
},
)
.await
.unwrap();
} }
pub async fn read_injection_status(aux_mutex: &Rc<Mutex<bool>>, timer: GlobalTimer, linkno: u8, destination: u8, channel: i32, overrd: i8) -> i8 { pub async fn read_injection_status(
let reply = drtio::aux_transact(aux_mutex, aux_mutex: &Rc<Mutex<bool>>,
linkno, timer: GlobalTimer,
linkno: u8,
destination: u8,
channel: i32,
overrd: i8,
) -> i8 {
let reply = drtio::aux_transact(
aux_mutex,
linkno,
&drtioaux_async::Packet::InjectionStatusRequest { &drtioaux_async::Packet::InjectionStatusRequest {
destination: destination, destination: destination,
channel: channel as _, channel: channel as _,
overrd: overrd as _}, overrd: overrd as _,
timer).await; },
timer,
)
.await;
match reply { match reply {
Ok(drtioaux_async::Packet::InjectionStatusReply { value }) => return value as i8, Ok(drtioaux_async::Packet::InjectionStatusReply { value }) => return value as i8,
Ok(packet) => error!("received unexpected aux packet: {:?}", packet), Ok(packet) => error!("received unexpected aux packet: {:?}", packet),
Err("link went down") => { debug!("link is down"); }, Err("link went down") => {
Err(e) => error!("aux packet error ({})", e) debug!("link is down");
}
Err(e) => error!("aux packet error ({})", e),
} }
0 0
} }
@ -157,8 +196,12 @@ macro_rules! dispatch {
}} }}
} }
async fn handle_connection(stream: &TcpStream, timer: GlobalTimer, async fn handle_connection(
_aux_mutex: &Rc<Mutex<bool>>, _routing_table: &drtio_routing::RoutingTable) -> Result<()> { stream: &TcpStream,
timer: GlobalTimer,
_aux_mutex: &Rc<Mutex<bool>>,
_routing_table: &drtio_routing::RoutingTable,
) -> Result<()> {
if !expect(&stream, b"ARTIQ moninj\n").await? { if !expect(&stream, b"ARTIQ moninj\n").await? {
return Err(Error::UnexpectedPattern); return Err(Error::UnexpectedPattern);
} }

View File

@ -1,14 +1,13 @@
use libboard_zynq::{print, println};
use libregister::RegisterR;
use libcortex_a9::regs::MPIDR;
use unwind::backtrace;
#[cfg(feature = "target_kasli_soc")] #[cfg(feature = "target_kasli_soc")]
use libboard_zynq::error_led::ErrorLED; use libboard_zynq::error_led::ErrorLED;
use crate::comms::soft_panic_main; use libboard_zynq::{print, println, timer::GlobalTimer};
use log::error;
use libboard_zynq::timer::GlobalTimer;
use libconfig::Config; use libconfig::Config;
use libcortex_a9::regs::MPIDR;
use libregister::RegisterR;
use log::error;
use unwind::backtrace;
use crate::comms::soft_panic_main;
static mut PANICKED: [bool; 2] = [false; 2]; static mut PANICKED: [bool; 2] = [false; 2];
static mut SOFT_PANICKED: bool = false; static mut SOFT_PANICKED: bool = false;
@ -68,9 +67,7 @@ fn soft_panic(info: &core::panic::PanicInfo) -> ! {
let timer = GlobalTimer::start(); let timer = GlobalTimer::start();
let cfg = match Config::new() { let cfg = match Config::new() {
Ok(cfg) => cfg, Ok(cfg) => cfg,
Err(_) => { Err(_) => Config::new_dummy(),
Config::new_dummy()
}
}; };
soft_panic_main(timer, cfg); soft_panic_main(timer, cfg);
} }

View File

@ -1,8 +1,7 @@
use core::cmp::min; use core::{cell::RefCell, cmp::min};
use core::cell::RefCell;
use libboard_zynq::smoltcp;
use libasync::smoltcp::TcpStream; use libasync::smoltcp::TcpStream;
use libboard_zynq::smoltcp;
type Result<T> = core::result::Result<T, smoltcp::Error>; type Result<T> = core::result::Result<T, smoltcp::Error>;
@ -14,25 +13,27 @@ enum RecvState<T> {
pub async fn expect(stream: &TcpStream, pattern: &[u8]) -> Result<bool> { pub async fn expect(stream: &TcpStream, pattern: &[u8]) -> Result<bool> {
let mut state = RecvState::NeedsMore(0, true); let mut state = RecvState::NeedsMore(0, true);
loop { loop {
state = stream.recv(|buf| { state = stream
let mut consumed = 0; .recv(|buf| {
if let RecvState::NeedsMore(mut cur_index, _) = state { let mut consumed = 0;
for b in buf.iter() { if let RecvState::NeedsMore(mut cur_index, _) = state {
consumed += 1; for b in buf.iter() {
if *b == pattern[cur_index] { consumed += 1;
if cur_index + 1 == pattern.len() { if *b == pattern[cur_index] {
return (consumed, RecvState::Completed(true)); if cur_index + 1 == pattern.len() {
return (consumed, RecvState::Completed(true));
}
} else {
return (consumed, RecvState::Completed(false));
} }
} else { cur_index += 1;
return (consumed, RecvState::Completed(false));
} }
cur_index += 1; (consumed, RecvState::NeedsMore(cur_index, true))
} else {
unreachable!();
} }
(consumed, RecvState::NeedsMore(cur_index, true)) })
} else { .await?;
unreachable!();
}
}).await?;
if let RecvState::Completed(result) = state { if let RecvState::Completed(result) = state {
return Ok(result); return Ok(result);
} }
@ -40,15 +41,11 @@ pub async fn expect(stream: &TcpStream, pattern: &[u8]) -> Result<bool> {
} }
pub async fn read_bool(stream: &TcpStream) -> Result<bool> { pub async fn read_bool(stream: &TcpStream) -> Result<bool> {
Ok(stream.recv(|buf| { Ok(stream.recv(|buf| (1, buf[0] != 0)).await?)
(1, buf[0] != 0)
}).await?)
} }
pub async fn read_i8(stream: &TcpStream) -> Result<i8> { pub async fn read_i8(stream: &TcpStream) -> Result<i8> {
Ok(stream.recv(|buf| { Ok(stream.recv(|buf| (1, buf[0] as i8)).await?)
(1, buf[0] as i8)
}).await?)
} }
pub async fn read_i32(stream: &TcpStream) -> Result<i32> { pub async fn read_i32(stream: &TcpStream) -> Result<i32> {
@ -68,12 +65,14 @@ pub async fn read_chunk(stream: &TcpStream, destination: &mut [u8]) -> Result<()
let destination = RefCell::new(destination); let destination = RefCell::new(destination);
let mut done = 0; let mut done = 0;
while done < total { while done < total {
let count = stream.recv(|buf| { let count = stream
let mut destination = destination.borrow_mut(); .recv(|buf| {
let count = min(total - done, buf.len()); let mut destination = destination.borrow_mut();
destination[done..done + count].copy_from_slice(&buf[..count]); let count = min(total - done, buf.len());
(count, count) destination[done..done + count].copy_from_slice(&buf[..count]);
}).await?; (count, count)
})
.await?;
done += count; done += count;
} }
Ok(()) Ok(())

View File

@ -1,18 +1,17 @@
use core::str;
use core::future::Future;
use cslice::{CSlice, CMutSlice};
use log::trace;
use byteorder::{NativeEndian, ByteOrder};
use core_io::{Write, Error};
use libboard_zynq::smoltcp;
use libasync::smoltcp::TcpStream;
use alloc::boxed::Box; use alloc::boxed::Box;
use async_recursion::async_recursion; use core::{future::Future, str};
use async_recursion::async_recursion;
use byteorder::{ByteOrder, NativeEndian};
use core_io::{Error, Write};
use cslice::{CMutSlice, CSlice};
use io::proto::ProtoWrite; use io::proto::ProtoWrite;
use libasync::smoltcp::TcpStream;
use libboard_zynq::smoltcp;
use log::trace;
use self::tag::{split_tag, Tag, TagIterator};
use crate::proto_async; use crate::proto_async;
use self::tag::{Tag, TagIterator, split_tag};
#[inline] #[inline]
fn round_up(val: usize, power_of_two: usize) -> usize { fn round_up(val: usize, power_of_two: usize) -> usize {
@ -52,17 +51,17 @@ async unsafe fn recv_elements<F>(
elt_tag: Tag<'async_recursion>, elt_tag: Tag<'async_recursion>,
length: usize, length: usize,
storage: *mut (), storage: *mut (),
alloc: &(impl Fn(usize) -> F + 'async_recursion) alloc: &(impl Fn(usize) -> F + 'async_recursion),
) -> Result<(), smoltcp::Error> ) -> Result<(), smoltcp::Error>
where where
F: Future<Output=*mut ()>, F: Future<Output = *mut ()>,
{ {
// List of simple types are special-cased in the protocol for performance. // List of simple types are special-cased in the protocol for performance.
match elt_tag { match elt_tag {
Tag::Bool => { Tag::Bool => {
let dest = core::slice::from_raw_parts_mut(storage as *mut u8, length); let dest = core::slice::from_raw_parts_mut(storage as *mut u8, length);
proto_async::read_chunk(stream, dest).await?; proto_async::read_chunk(stream, dest).await?;
}, }
Tag::Int32 => { Tag::Int32 => {
let ptr = storage as *mut u32; let ptr = storage as *mut u32;
let dest = core::slice::from_raw_parts_mut(ptr as *mut u8, length * 4); let dest = core::slice::from_raw_parts_mut(ptr as *mut u8, length * 4);
@ -70,7 +69,7 @@ where
drop(dest); drop(dest);
let dest = core::slice::from_raw_parts_mut(ptr, length); let dest = core::slice::from_raw_parts_mut(ptr, length);
NativeEndian::from_slice_u32(dest); NativeEndian::from_slice_u32(dest);
}, }
Tag::Int64 | Tag::Float64 => { Tag::Int64 | Tag::Float64 => {
let ptr = storage as *mut u64; let ptr = storage as *mut u64;
let dest = core::slice::from_raw_parts_mut(ptr as *mut u8, length * 8); let dest = core::slice::from_raw_parts_mut(ptr as *mut u8, length * 8);
@ -78,7 +77,7 @@ where
drop(dest); drop(dest);
let dest = core::slice::from_raw_parts_mut(ptr, length); let dest = core::slice::from_raw_parts_mut(ptr, length);
NativeEndian::from_slice_u64(dest); NativeEndian::from_slice_u64(dest);
}, }
_ => { _ => {
let mut data = storage; let mut data = storage;
for _ in 0..length { for _ in 0..length {
@ -95,36 +94,37 @@ where
/// invoked any number of times with the size of the required allocation as a parameter /// invoked any number of times with the size of the required allocation as a parameter
/// (which is assumed to be correctly aligned for all payload types). /// (which is assumed to be correctly aligned for all payload types).
#[async_recursion(?Send)] #[async_recursion(?Send)]
async unsafe fn recv_value<F>(stream: &TcpStream, tag: Tag<'async_recursion>, data: &mut *mut (), async unsafe fn recv_value<F>(
alloc: &(impl Fn(usize) -> F + 'async_recursion)) stream: &TcpStream,
-> Result<(), smoltcp::Error> tag: Tag<'async_recursion>,
where F: Future<Output=*mut ()> data: &mut *mut (),
alloc: &(impl Fn(usize) -> F + 'async_recursion),
) -> Result<(), smoltcp::Error>
where
F: Future<Output = *mut ()>,
{ {
macro_rules! consume_value { macro_rules! consume_value {
($ty:ty, |$ptr:ident| $map:expr) => ({ ($ty:ty, | $ptr:ident | $map:expr) => {{
let $ptr = align_ptr_mut::<$ty>(*data); let $ptr = align_ptr_mut::<$ty>(*data);
*data = $ptr.offset(1) as *mut (); *data = $ptr.offset(1) as *mut ();
$map $map
}) }};
} }
match tag { match tag {
Tag::None => Ok(()), Tag::None => Ok(()),
Tag::Bool => Tag::Bool => consume_value!(i8, |ptr| {
consume_value!(i8, |ptr| { *ptr = proto_async::read_i8(stream).await?;
*ptr = proto_async::read_i8(stream).await?; Ok(())
Ok(()) }),
}), Tag::Int32 => consume_value!(i32, |ptr| {
Tag::Int32 => *ptr = proto_async::read_i32(stream).await?;
consume_value!(i32, |ptr| { Ok(())
*ptr = proto_async::read_i32(stream).await?; }),
Ok(()) Tag::Int64 | Tag::Float64 => consume_value!(i64, |ptr| {
}), *ptr = proto_async::read_i64(stream).await?;
Tag::Int64 | Tag::Float64 => Ok(())
consume_value!(i64, |ptr| { }),
*ptr = proto_async::read_i64(stream).await?;
Ok(())
}),
Tag::String | Tag::Bytes | Tag::ByteArray => { Tag::String | Tag::Bytes | Tag::ByteArray => {
consume_value!(CMutSlice<u8>, |ptr| { consume_value!(CMutSlice<u8>, |ptr| {
let length = proto_async::read_i32(stream).await? as usize; let length = proto_async::read_i32(stream).await? as usize;
@ -148,7 +148,10 @@ async unsafe fn recv_value<F>(stream: &TcpStream, tag: Tag<'async_recursion>, da
} }
Tag::List(it) => { Tag::List(it) => {
#[repr(C)] #[repr(C)]
struct List { elements: *mut (), length: usize } struct List {
elements: *mut (),
length: usize,
}
consume_value!(*mut List, |ptr_to_list| { consume_value!(*mut List, |ptr_to_list| {
let tag = it.clone().next().expect("truncated tag"); let tag = it.clone().next().expect("truncated tag");
let length = proto_async::read_i32(stream).await? as usize; let length = proto_async::read_i32(stream).await? as usize;
@ -180,7 +183,7 @@ async unsafe fn recv_value<F>(stream: &TcpStream, tag: Tag<'async_recursion>, da
for _ in 0..num_dims { for _ in 0..num_dims {
let len = proto_async::read_i32(stream).await? as usize; let len = proto_async::read_i32(stream).await? as usize;
total_len *= len; total_len *= len;
consume_value!(usize, |ptr| *ptr = len ) consume_value!(usize, |ptr| *ptr = len)
} }
// Allocate backing storage for elements; deserialize them. // Allocate backing storage for elements; deserialize them.
@ -198,14 +201,18 @@ async unsafe fn recv_value<F>(stream: &TcpStream, tag: Tag<'async_recursion>, da
Ok(()) Ok(())
} }
Tag::Keyword(_) => unreachable!(), Tag::Keyword(_) => unreachable!(),
Tag::Object => unreachable!() Tag::Object => unreachable!(),
} }
} }
pub async fn recv_return<F>(stream: &TcpStream, tag_bytes: &[u8], data: *mut (), pub async fn recv_return<F>(
alloc: &impl Fn(usize) -> F) stream: &TcpStream,
-> Result<(), smoltcp::Error> tag_bytes: &[u8],
where F: Future<Output=*mut ()> data: *mut (),
alloc: &impl Fn(usize) -> F,
) -> Result<(), smoltcp::Error>
where
F: Future<Output = *mut ()>,
{ {
let mut it = TagIterator::new(tag_bytes); let mut it = TagIterator::new(tag_bytes);
trace!("recv ...->{}", it); trace!("recv ...->{}", it);
@ -217,10 +224,8 @@ pub async fn recv_return<F>(stream: &TcpStream, tag_bytes: &[u8], data: *mut (),
Ok(()) Ok(())
} }
unsafe fn send_elements<W>(writer: &mut W, elt_tag: Tag, length: usize, data: *const ()) unsafe fn send_elements<W>(writer: &mut W, elt_tag: Tag, length: usize, data: *const ()) -> Result<(), Error>
-> Result<(), Error> where W: Write + ?Sized {
where W: Write + ?Sized
{
writer.write_u8(elt_tag.as_u8())?; writer.write_u8(elt_tag.as_u8())?;
match elt_tag { match elt_tag {
// we cannot use NativeEndian::from_slice_i32 as the data is not mutable, // we cannot use NativeEndian::from_slice_i32 as the data is not mutable,
@ -228,15 +233,15 @@ unsafe fn send_elements<W>(writer: &mut W, elt_tag: Tag, length: usize, data: *c
Tag::Bool => { Tag::Bool => {
let slice = core::slice::from_raw_parts(data as *const u8, length); let slice = core::slice::from_raw_parts(data as *const u8, length);
writer.write_all(slice)?; writer.write_all(slice)?;
}, }
Tag::Int32 => { Tag::Int32 => {
let slice = core::slice::from_raw_parts(data as *const u8, length * 4); let slice = core::slice::from_raw_parts(data as *const u8, length * 4);
writer.write_all(slice)?; writer.write_all(slice)?;
}, }
Tag::Int64 | Tag::Float64 => { Tag::Int64 | Tag::Float64 => {
let slice = core::slice::from_raw_parts(data as *const u8, length * 8); let slice = core::slice::from_raw_parts(data as *const u8, length * 8);
writer.write_all(slice)?; writer.write_all(slice)?;
}, }
_ => { _ => {
let mut data = data; let mut data = data;
for _ in 0..length { for _ in 0..length {
@ -247,36 +252,26 @@ unsafe fn send_elements<W>(writer: &mut W, elt_tag: Tag, length: usize, data: *c
Ok(()) Ok(())
} }
unsafe fn send_value<W>(writer: &mut W, tag: Tag, data: &mut *const ()) unsafe fn send_value<W>(writer: &mut W, tag: Tag, data: &mut *const ()) -> Result<(), Error>
-> Result<(), Error> where W: Write + ?Sized {
where W: Write + ?Sized
{
macro_rules! consume_value { macro_rules! consume_value {
($ty:ty, |$ptr:ident| $map:expr) => ({ ($ty:ty, | $ptr:ident | $map:expr) => {{
let $ptr = align_ptr::<$ty>(*data); let $ptr = align_ptr::<$ty>(*data);
*data = $ptr.offset(1) as *const (); *data = $ptr.offset(1) as *const ();
$map $map
}) }};
} }
writer.write_u8(tag.as_u8())?; writer.write_u8(tag.as_u8())?;
match tag { match tag {
Tag::None => Ok(()), Tag::None => Ok(()),
Tag::Bool => Tag::Bool => consume_value!(u8, |ptr| writer.write_u8(*ptr)),
consume_value!(u8, |ptr| Tag::Int32 => consume_value!(u32, |ptr| writer.write_u32(*ptr)),
writer.write_u8(*ptr)), Tag::Int64 | Tag::Float64 => consume_value!(u64, |ptr| writer.write_u64(*ptr)),
Tag::Int32 => Tag::String => consume_value!(CSlice<u8>, |ptr| {
consume_value!(u32, |ptr| writer.write_string(str::from_utf8((*ptr).as_ref()).unwrap())
writer.write_u32(*ptr)), }),
Tag::Int64 | Tag::Float64 => Tag::Bytes | Tag::ByteArray => consume_value!(CSlice<u8>, |ptr| writer.write_bytes((*ptr).as_ref())),
consume_value!(u64, |ptr|
writer.write_u64(*ptr)),
Tag::String =>
consume_value!(CSlice<u8>, |ptr|
writer.write_string(str::from_utf8((*ptr).as_ref()).unwrap())),
Tag::Bytes | Tag::ByteArray =>
consume_value!(CSlice<u8>, |ptr|
writer.write_bytes((*ptr).as_ref())),
Tag::Tuple(it, arity) => { Tag::Tuple(it, arity) => {
let mut it = it.clone(); let mut it = it.clone();
writer.write_u8(arity)?; writer.write_u8(arity)?;
@ -291,7 +286,10 @@ unsafe fn send_value<W>(writer: &mut W, tag: Tag, data: &mut *const ())
} }
Tag::List(it) => { Tag::List(it) => {
#[repr(C)] #[repr(C)]
struct List { elements: *const (), length: u32 } struct List {
elements: *const (),
length: u32,
}
consume_value!(&List, |ptr| { consume_value!(&List, |ptr| {
let length = (**ptr).length as usize; let length = (**ptr).length as usize;
writer.write_u32((*ptr).length)?; writer.write_u32((*ptr).length)?;
@ -301,7 +299,7 @@ unsafe fn send_value<W>(writer: &mut W, tag: Tag, data: &mut *const ())
} }
Tag::Array(it, num_dims) => { Tag::Array(it, num_dims) => {
writer.write_u8(num_dims)?; writer.write_u8(num_dims)?;
consume_value!(*const(), |buffer| { consume_value!(*const (), |buffer| {
let elt_tag = it.clone().next().expect("truncated tag"); let elt_tag = it.clone().next().expect("truncated tag");
let mut total_len = 1; let mut total_len = 1;
@ -324,7 +322,9 @@ unsafe fn send_value<W>(writer: &mut W, tag: Tag, data: &mut *const ())
} }
Tag::Keyword(it) => { Tag::Keyword(it) => {
#[repr(C)] #[repr(C)]
struct Keyword<'a> { name: CSlice<'a, u8> } struct Keyword<'a> {
name: CSlice<'a, u8>,
}
consume_value!(Keyword, |ptr| { consume_value!(Keyword, |ptr| {
writer.write_string(str::from_utf8((*ptr).name.as_ref()).unwrap())?; writer.write_string(str::from_utf8((*ptr).name.as_ref()).unwrap())?;
let tag = it.clone().next().expect("truncated tag"); let tag = it.clone().next().expect("truncated tag");
@ -336,17 +336,16 @@ unsafe fn send_value<W>(writer: &mut W, tag: Tag, data: &mut *const ())
} }
Tag::Object => { Tag::Object => {
#[repr(C)] #[repr(C)]
struct Object { id: u32 } struct Object {
consume_value!(*const Object, |ptr| id: u32,
writer.write_u32((**ptr).id)) }
consume_value!(*const Object, |ptr| writer.write_u32((**ptr).id))
} }
} }
} }
pub fn send_args<W>(writer: &mut W, service: u32, tag_bytes: &[u8], data: *const *const ()) pub fn send_args<W>(writer: &mut W, service: u32, tag_bytes: &[u8], data: *const *const ()) -> Result<(), Error>
-> Result<(), Error> where W: Write + ?Sized {
where W: Write + ?Sized
{
let (arg_tags_bytes, return_tag_bytes) = split_tag(tag_bytes); let (arg_tags_bytes, return_tag_bytes) = split_tag(tag_bytes);
let mut args_it = TagIterator::new(arg_tags_bytes); let mut args_it = TagIterator::new(arg_tags_bytes);
@ -359,7 +358,7 @@ pub fn send_args<W>(writer: &mut W, service: u32, tag_bytes: &[u8], data: *const
let mut data = unsafe { *data.offset(index) }; let mut data = unsafe { *data.offset(index) };
unsafe { send_value(writer, arg_tag, &mut data)? }; unsafe { send_value(writer, arg_tag, &mut data)? };
} else { } else {
break break;
} }
} }
writer.write_u8(0)?; writer.write_u8(0)?;
@ -372,10 +371,10 @@ mod tag {
use core::fmt; use core::fmt;
pub fn split_tag(tag_bytes: &[u8]) -> (&[u8], &[u8]) { pub fn split_tag(tag_bytes: &[u8]) -> (&[u8], &[u8]) {
let tag_separator = let tag_separator = tag_bytes
tag_bytes.iter() .iter()
.position(|&b| b == b':') .position(|&b| b == b':')
.expect("tag without a return separator"); .expect("tag without a return separator");
let (arg_tags_bytes, rest) = tag_bytes.split_at(tag_separator); let (arg_tags_bytes, rest) = tag_bytes.split_at(tag_separator);
let return_tag_bytes = &rest[1..]; let return_tag_bytes = &rest[1..];
(arg_tags_bytes, return_tag_bytes) (arg_tags_bytes, return_tag_bytes)
@ -396,7 +395,7 @@ mod tag {
Array(TagIterator<'a>, u8), Array(TagIterator<'a>, u8),
Range(TagIterator<'a>), Range(TagIterator<'a>),
Keyword(TagIterator<'a>), Keyword(TagIterator<'a>),
Object Object,
} }
impl<'a> Tag<'a> { impl<'a> Tag<'a> {
@ -431,14 +430,15 @@ mod tag {
Tag::Tuple(it, arity) => { Tag::Tuple(it, arity) => {
let it = it.clone(); let it = it.clone();
it.take(arity.into()).map(|t| t.alignment()).max().unwrap() it.take(arity.into()).map(|t| t.alignment()).max().unwrap()
}, }
Tag::Range(it) => { Tag::Range(it) => {
let it = it.clone(); let it = it.clone();
it.take(3).map(|t| t.alignment()).max().unwrap() it.take(3).map(|t| t.alignment()).max().unwrap()
} }
// the ptr/length(s) pair is basically CSlice // the ptr/length(s) pair is basically CSlice
Tag::Bytes | Tag::String | Tag::ByteArray | Tag::List(_) | Tag::Array(_, _) => Tag::Bytes | Tag::String | Tag::ByteArray | Tag::List(_) | Tag::Array(_, _) => {
core::mem::align_of::<CSlice<()>>(), core::mem::align_of::<CSlice<()>>()
}
Tag::Keyword(_) => unreachable!("Tag::Keyword should not appear in composite types"), Tag::Keyword(_) => unreachable!("Tag::Keyword should not appear in composite types"),
Tag::Object => core::mem::align_of::<u32>(), Tag::Object => core::mem::align_of::<u32>(),
} }
@ -484,7 +484,7 @@ mod tag {
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub struct TagIterator<'a> { pub struct TagIterator<'a> {
data: &'a [u8] data: &'a [u8],
} }
impl<'a> TagIterator<'a> { impl<'a> TagIterator<'a> {
@ -492,13 +492,14 @@ mod tag {
TagIterator { data } TagIterator { data }
} }
fn sub(&mut self, count: u8) -> TagIterator<'a> { fn sub(&mut self, count: u8) -> TagIterator<'a> {
let data = self.data; let data = self.data;
for _ in 0..count { for _ in 0..count {
self.next().expect("truncated tag"); self.next().expect("truncated tag");
} }
TagIterator { data: &data[..(data.len() - self.data.len())] } TagIterator {
data: &data[..(data.len() - self.data.len())],
}
} }
} }
@ -507,7 +508,7 @@ mod tag {
fn next(&mut self) -> Option<Tag<'a>> { fn next(&mut self) -> Option<Tag<'a>> {
if self.data.len() == 0 { if self.data.len() == 0 {
return None return None;
} }
let tag_byte = self.data[0]; let tag_byte = self.data[0];
@ -535,7 +536,7 @@ mod tag {
b'r' => Tag::Range(self.sub(1)), b'r' => Tag::Range(self.sub(1)),
b'k' => Tag::Keyword(self.sub(1)), b'k' => Tag::Keyword(self.sub(1)),
b'O' => Tag::Object, b'O' => Tag::Object,
_ => unreachable!() _ => unreachable!(),
}) })
} }
} }
@ -552,22 +553,14 @@ mod tag {
} }
match tag { match tag {
Tag::None => Tag::None => write!(f, "None")?,
write!(f, "None")?, Tag::Bool => write!(f, "Bool")?,
Tag::Bool => Tag::Int32 => write!(f, "Int32")?,
write!(f, "Bool")?, Tag::Int64 => write!(f, "Int64")?,
Tag::Int32 => Tag::Float64 => write!(f, "Float64")?,
write!(f, "Int32")?, Tag::String => write!(f, "String")?,
Tag::Int64 => Tag::Bytes => write!(f, "Bytes")?,
write!(f, "Int64")?, Tag::ByteArray => write!(f, "ByteArray")?,
Tag::Float64 =>
write!(f, "Float64")?,
Tag::String =>
write!(f, "String")?,
Tag::Bytes =>
write!(f, "Bytes")?,
Tag::ByteArray =>
write!(f, "ByteArray")?,
Tag::Tuple(it, _) => { Tag::Tuple(it, _) => {
write!(f, "Tuple(")?; write!(f, "Tuple(")?;
it.fmt(f)?; it.fmt(f)?;
@ -593,8 +586,7 @@ mod tag {
it.fmt(f)?; it.fmt(f)?;
write!(f, ")")?; write!(f, ")")?;
} }
Tag::Object => Tag::Object => write!(f, "Object")?,
write!(f, "Object")?,
} }
} }

View File

@ -1,19 +1,18 @@
use cslice::CSlice;
use vcell::VolatileCell;
use libcortex_a9::asm;
use crate::artiq_raise;
use core::sync::atomic::{fence, Ordering}; use core::sync::atomic::{fence, Ordering};
use crate::pl::csr; use cslice::CSlice;
use crate::rtio_mgt::resolve_channel_name; use libcortex_a9::asm;
use vcell::VolatileCell;
pub const RTIO_O_STATUS_WAIT: i32 = 1; use crate::{artiq_raise, pl::csr, rtio_mgt::resolve_channel_name};
pub const RTIO_O_STATUS_UNDERFLOW: i32 = 2;
pub const RTIO_O_STATUS_DESTINATION_UNREACHABLE: i32 = 4; pub const RTIO_O_STATUS_WAIT: i32 = 1;
pub const RTIO_I_STATUS_WAIT_EVENT: i32 = 1; pub const RTIO_O_STATUS_UNDERFLOW: i32 = 2;
pub const RTIO_I_STATUS_OVERFLOW: i32 = 2; pub const RTIO_O_STATUS_DESTINATION_UNREACHABLE: i32 = 4;
pub const RTIO_I_STATUS_WAIT_STATUS: i32 = 4; // TODO pub const RTIO_I_STATUS_WAIT_EVENT: i32 = 1;
pub const RTIO_I_STATUS_DESTINATION_UNREACHABLE: i32 = 8; pub const RTIO_I_STATUS_OVERFLOW: i32 = 2;
pub const RTIO_I_STATUS_WAIT_STATUS: i32 = 4; // TODO
pub const RTIO_I_STATUS_DESTINATION_UNREACHABLE: i32 = 8;
#[repr(C)] #[repr(C)]
pub struct TimestampedData { pub struct TimestampedData {
@ -47,10 +46,10 @@ static mut TRANSACTION_BUFFER: Transaction = Transaction {
reply_timestamp: VolatileCell::new(0), reply_timestamp: VolatileCell::new(0),
padding0: [0; 2], padding0: [0; 2],
padding1: [0; 2], padding1: [0; 2],
padding2: [0; 2] padding2: [0; 2],
}; };
pub extern fn init() { pub extern "C" fn init() {
unsafe { unsafe {
csr::rtio_core::reset_write(1); csr::rtio_core::reset_write(1);
csr::rtio::engine_addr_base_write(&TRANSACTION_BUFFER as *const Transaction as u32); csr::rtio::engine_addr_base_write(&TRANSACTION_BUFFER as *const Transaction as u32);
@ -58,7 +57,7 @@ pub extern fn init() {
} }
} }
pub extern fn get_counter() -> i64 { pub extern "C" fn get_counter() -> i64 {
unsafe { unsafe {
csr::rtio::counter_update_write(1); csr::rtio::counter_update_write(1);
csr::rtio::counter_read() as i64 csr::rtio::counter_read() as i64
@ -67,15 +66,15 @@ pub extern fn get_counter() -> i64 {
static mut NOW: i64 = 0; static mut NOW: i64 = 0;
pub extern fn now_mu() -> i64 { pub extern "C" fn now_mu() -> i64 {
unsafe { NOW } unsafe { NOW }
} }
pub extern fn at_mu(t: i64) { pub extern "C" fn at_mu(t: i64) {
unsafe { NOW = t } unsafe { NOW = t }
} }
pub extern fn delay_mu(dt: i64) { pub extern "C" fn delay_mu(dt: i64) {
unsafe { NOW += dt } unsafe { NOW += dt }
} }
@ -87,18 +86,34 @@ unsafe fn process_exceptional_status(channel: i32, status: i32) {
while csr::rtio::o_status_read() as i32 & RTIO_O_STATUS_WAIT != 0 {} while csr::rtio::o_status_read() as i32 & RTIO_O_STATUS_WAIT != 0 {}
} }
if status & RTIO_O_STATUS_UNDERFLOW != 0 { if status & RTIO_O_STATUS_UNDERFLOW != 0 {
artiq_raise!("RTIOUnderflow", artiq_raise!(
format!("RTIO underflow at {{1}} mu, channel 0x{:04x}:{}, slack {{2}} mu", channel, resolve_channel_name(channel as u32)), "RTIOUnderflow",
channel as i64, timestamp, timestamp - get_counter()); format!(
"RTIO underflow at {{1}} mu, channel 0x{:04x}:{}, slack {{2}} mu",
channel,
resolve_channel_name(channel as u32)
),
channel as i64,
timestamp,
timestamp - get_counter()
);
} }
if status & RTIO_O_STATUS_DESTINATION_UNREACHABLE != 0 { if status & RTIO_O_STATUS_DESTINATION_UNREACHABLE != 0 {
artiq_raise!("RTIODestinationUnreachable", artiq_raise!(
format!("RTIO destination unreachable, output, at {{0}} mu, channel 0x{:04x}:{}", channel, resolve_channel_name(channel as u32)), "RTIODestinationUnreachable",
timestamp, channel as i64, 0); format!(
"RTIO destination unreachable, output, at {{0}} mu, channel 0x{:04x}:{}",
channel,
resolve_channel_name(channel as u32)
),
timestamp,
channel as i64,
0
);
} }
} }
pub extern fn output(target: i32, data: i32) { pub extern "C" fn output(target: i32, data: i32) {
unsafe { unsafe {
// Clear status so we can observe response // Clear status so we can observe response
TRANSACTION_BUFFER.reply_status.set(0); TRANSACTION_BUFFER.reply_status.set(0);
@ -126,7 +141,7 @@ pub extern fn output(target: i32, data: i32) {
} }
} }
pub extern fn output_wide(target: i32, data: CSlice<i32>) { pub extern "C" fn output_wide(target: i32, data: CSlice<i32>) {
unsafe { unsafe {
// Clear status so we can observe response // Clear status so we can observe response
TRANSACTION_BUFFER.reply_status.set(0); TRANSACTION_BUFFER.reply_status.set(0);
@ -143,7 +158,7 @@ pub extern fn output_wide(target: i32, data: CSlice<i32>) {
loop { loop {
status = TRANSACTION_BUFFER.reply_status.get(); status = TRANSACTION_BUFFER.reply_status.get();
if status != 0 { if status != 0 {
break break;
} }
} }
@ -154,8 +169,8 @@ pub extern fn output_wide(target: i32, data: CSlice<i32>) {
} }
} }
pub extern fn input_timestamp(timeout: i64, channel: i32) -> i64 { pub extern "C" fn input_timestamp(timeout: i64, channel: i32) -> i64 {
unsafe { unsafe {
// Clear status so we can observe response // Clear status so we can observe response
TRANSACTION_BUFFER.reply_status.set(0); TRANSACTION_BUFFER.reply_status.set(0);
@ -171,29 +186,45 @@ pub extern fn input_timestamp(timeout: i64, channel: i32) -> i64 {
loop { loop {
status = TRANSACTION_BUFFER.reply_status.get(); status = TRANSACTION_BUFFER.reply_status.get();
if status != 0 { if status != 0 {
break break;
} }
} }
if status & RTIO_I_STATUS_OVERFLOW != 0 { if status & RTIO_I_STATUS_OVERFLOW != 0 {
artiq_raise!("RTIOOverflow", artiq_raise!(
format!("RTIO input overflow on channel 0x{:04x}:{}", channel, resolve_channel_name(channel as u32)), "RTIOOverflow",
channel as i64, 0, 0); format!(
"RTIO input overflow on channel 0x{:04x}:{}",
channel,
resolve_channel_name(channel as u32)
),
channel as i64,
0,
0
);
} }
if status & RTIO_I_STATUS_WAIT_EVENT != 0 { if status & RTIO_I_STATUS_WAIT_EVENT != 0 {
return -1 return -1;
} }
if status & RTIO_I_STATUS_DESTINATION_UNREACHABLE != 0 { if status & RTIO_I_STATUS_DESTINATION_UNREACHABLE != 0 {
artiq_raise!("RTIODestinationUnreachable", artiq_raise!(
format!("RTIO destination unreachable, input, on channel 0x{:04x}:{}", channel, resolve_channel_name(channel as u32)), "RTIODestinationUnreachable",
channel as i64, 0, 0); format!(
"RTIO destination unreachable, input, on channel 0x{:04x}:{}",
channel,
resolve_channel_name(channel as u32)
),
channel as i64,
0,
0
);
} }
TRANSACTION_BUFFER.reply_timestamp.get() TRANSACTION_BUFFER.reply_timestamp.get()
} }
} }
pub extern fn input_data(channel: i32) -> i32 { pub extern "C" fn input_data(channel: i32) -> i32 {
unsafe { unsafe {
TRANSACTION_BUFFER.reply_status.set(0); TRANSACTION_BUFFER.reply_status.set(0);
@ -209,26 +240,42 @@ pub extern fn input_data(channel: i32) -> i32 {
loop { loop {
status = TRANSACTION_BUFFER.reply_status.get(); status = TRANSACTION_BUFFER.reply_status.get();
if status != 0 { if status != 0 {
break break;
} }
} }
if status & RTIO_I_STATUS_OVERFLOW != 0 { if status & RTIO_I_STATUS_OVERFLOW != 0 {
artiq_raise!("RTIOOverflow", artiq_raise!(
format!("RTIO input overflow on channel 0x{:04x}:{}", channel, resolve_channel_name(channel as u32)), "RTIOOverflow",
channel as i64, 0, 0); format!(
"RTIO input overflow on channel 0x{:04x}:{}",
channel,
resolve_channel_name(channel as u32)
),
channel as i64,
0,
0
);
} }
if status & RTIO_I_STATUS_DESTINATION_UNREACHABLE != 0 { if status & RTIO_I_STATUS_DESTINATION_UNREACHABLE != 0 {
artiq_raise!("RTIODestinationUnreachable", artiq_raise!(
format!("RTIO destination unreachable, input, on channel 0x{:04x}:{}", channel, resolve_channel_name(channel as u32)), "RTIODestinationUnreachable",
channel as i64, 0, 0); format!(
"RTIO destination unreachable, input, on channel 0x{:04x}:{}",
channel,
resolve_channel_name(channel as u32)
),
channel as i64,
0,
0
);
} }
TRANSACTION_BUFFER.reply_data.get() TRANSACTION_BUFFER.reply_data.get()
} }
} }
pub extern fn input_timestamped_data(timeout: i64, channel: i32) -> TimestampedData { pub extern "C" fn input_timestamped_data(timeout: i64, channel: i32) -> TimestampedData {
unsafe { unsafe {
TRANSACTION_BUFFER.reply_status.set(0); TRANSACTION_BUFFER.reply_status.set(0);
@ -244,19 +291,35 @@ pub extern fn input_timestamped_data(timeout: i64, channel: i32) -> TimestampedD
loop { loop {
status = TRANSACTION_BUFFER.reply_status.get(); status = TRANSACTION_BUFFER.reply_status.get();
if status != 0 { if status != 0 {
break break;
} }
} }
if status & RTIO_I_STATUS_OVERFLOW != 0 { if status & RTIO_I_STATUS_OVERFLOW != 0 {
artiq_raise!("RTIOOverflow", artiq_raise!(
format!("RTIO input overflow on channel 0x{:04x}:{}", channel, resolve_channel_name(channel as u32)), "RTIOOverflow",
channel as i64, 0, 0); format!(
"RTIO input overflow on channel 0x{:04x}:{}",
channel,
resolve_channel_name(channel as u32)
),
channel as i64,
0,
0
);
} }
if status & RTIO_I_STATUS_DESTINATION_UNREACHABLE != 0 { if status & RTIO_I_STATUS_DESTINATION_UNREACHABLE != 0 {
artiq_raise!("RTIODestinationUnreachable", artiq_raise!(
format!("RTIO destination unreachable, input, on channel 0x{:04x}:{}", channel, resolve_channel_name(channel as u32)), "RTIODestinationUnreachable",
channel as i64, 0, 0); format!(
"RTIO destination unreachable, input, on channel 0x{:04x}:{}",
channel,
resolve_channel_name(channel as u32)
),
channel as i64,
0,
0
);
} }
TimestampedData { TimestampedData {

View File

@ -1,14 +1,15 @@
use log::{info, warn};
use libboard_zynq::timer::GlobalTimer;
use embedded_hal::blocking::delay::DelayMs; use embedded_hal::blocking::delay::DelayMs;
use libconfig::Config;
use libboard_artiq::pl; use libboard_artiq::pl;
#[cfg(has_si5324)] #[cfg(has_si5324)]
use libboard_artiq::si5324;
#[cfg(has_si5324)]
use libboard_zynq::i2c::I2c; use libboard_zynq::i2c::I2c;
use libboard_zynq::timer::GlobalTimer;
use libconfig::Config;
use log::{info, warn};
#[cfg(has_si5324)] #[cfg(has_si5324)]
use crate::i2c; use crate::i2c;
#[cfg(has_si5324)]
use libboard_artiq::si5324;
#[derive(Debug, PartialEq, Copy, Clone)] #[derive(Debug, PartialEq, Copy, Clone)]
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
@ -37,22 +38,21 @@ fn get_rtio_clock_cfg(cfg: &Config) -> RtioClock {
"ext0_synth0_10to125" => RtioClock::Ext0_Synth0_10to125, "ext0_synth0_10to125" => RtioClock::Ext0_Synth0_10to125,
"ext0_synth0_100to125" => RtioClock::Ext0_Synth0_100to125, "ext0_synth0_100to125" => RtioClock::Ext0_Synth0_100to125,
"ext0_synth0_125to125" => RtioClock::Ext0_Synth0_125to125, "ext0_synth0_125to125" => RtioClock::Ext0_Synth0_125to125,
_ => { _ => {
warn!("Unrecognised rtio_clock setting. Falling back to default."); warn!("Unrecognised rtio_clock setting. Falling back to default.");
RtioClock::Default RtioClock::Default
} }
}; };
} } else {
else {
warn!("error reading configuration. Falling back to default."); warn!("error reading configuration. Falling back to default.");
} }
if res == RtioClock::Default { if res == RtioClock::Default {
#[cfg(rtio_frequency="100.0")] #[cfg(rtio_frequency = "100.0")]
{ {
warn!("Using default configuration - internal 100MHz RTIO clock."); warn!("Using default configuration - internal 100MHz RTIO clock.");
return RtioClock::Int_100; return RtioClock::Int_100;
} }
#[cfg(rtio_frequency="125.0")] #[cfg(rtio_frequency = "125.0")]
{ {
warn!("Using default configuration - internal 125MHz RTIO clock."); warn!("Using default configuration - internal 125MHz RTIO clock.");
return RtioClock::Int_125; return RtioClock::Int_125;
@ -85,16 +85,14 @@ fn init_rtio(timer: &mut GlobalTimer) {
pl::csr::rtio_core::reset_phy_write(1); pl::csr::rtio_core::reset_phy_write(1);
} }
info!("SYS PLL locked"); info!("SYS PLL locked");
} }
#[cfg(has_drtio)] #[cfg(has_drtio)]
fn init_drtio(timer: &mut GlobalTimer) fn init_drtio(timer: &mut GlobalTimer) {
{
unsafe { unsafe {
pl::csr::drtio_transceiver::stable_clkin_write(1); pl::csr::drtio_transceiver::stable_clkin_write(1);
} }
timer.delay_ms(20); // wait for CPLL/QPLL/SYS PLL lock timer.delay_ms(20); // wait for CPLL/QPLL/SYS PLL lock
let clk = unsafe { pl::csr::sys_crg::current_clock_read() }; let clk = unsafe { pl::csr::sys_crg::current_clock_read() };
if clk == 1 { if clk == 1 {
@ -115,116 +113,126 @@ const SI5324_EXT_INPUT: si5324::Input = si5324::Input::Ckin1;
#[cfg(has_si5324)] #[cfg(has_si5324)]
fn setup_si5324(i2c: &mut I2c, timer: &mut GlobalTimer, clk: RtioClock) { fn setup_si5324(i2c: &mut I2c, timer: &mut GlobalTimer, clk: RtioClock) {
let (si5324_settings, si5324_ref_input) = match clk { let (si5324_settings, si5324_ref_input) = match clk {
RtioClock::Ext0_Synth0_10to125 => { // 125 MHz output from 10 MHz CLKINx reference, 504 Hz BW RtioClock::Ext0_Synth0_10to125 => {
// 125 MHz output from 10 MHz CLKINx reference, 504 Hz BW
info!("using 10MHz reference to make 125MHz RTIO clock with PLL"); info!("using 10MHz reference to make 125MHz RTIO clock with PLL");
( (
si5324::FrequencySettings { si5324::FrequencySettings {
n1_hs : 10, n1_hs: 10,
nc1_ls : 4, nc1_ls: 4,
n2_hs : 10, n2_hs: 10,
n2_ls : 300, n2_ls: 300,
n31 : 6, n31: 6,
n32 : 6, n32: 6,
bwsel : 4, bwsel: 4,
crystal_as_ckin2: false crystal_as_ckin2: false,
}, },
SI5324_EXT_INPUT SI5324_EXT_INPUT,
) )
}, }
RtioClock::Ext0_Synth0_100to125 => { // 125MHz output, from 100MHz CLKINx reference, 586 Hz loop bandwidth RtioClock::Ext0_Synth0_100to125 => {
// 125MHz output, from 100MHz CLKINx reference, 586 Hz loop bandwidth
info!("using 100MHz reference to make 125MHz RTIO clock with PLL"); info!("using 100MHz reference to make 125MHz RTIO clock with PLL");
( (
si5324::FrequencySettings { si5324::FrequencySettings {
n1_hs : 10, n1_hs: 10,
nc1_ls : 4, nc1_ls: 4,
n2_hs : 10, n2_hs: 10,
n2_ls : 260, n2_ls: 260,
n31 : 52, n31: 52,
n32 : 52, n32: 52,
bwsel : 4, bwsel: 4,
crystal_as_ckin2: false crystal_as_ckin2: false,
}, },
SI5324_EXT_INPUT SI5324_EXT_INPUT,
) )
}, }
RtioClock::Ext0_Synth0_125to125 => { // 125MHz output, from 125MHz CLKINx reference, 606 Hz loop bandwidth RtioClock::Ext0_Synth0_125to125 => {
// 125MHz output, from 125MHz CLKINx reference, 606 Hz loop bandwidth
info!("using 125MHz reference to make 125MHz RTIO clock with PLL"); info!("using 125MHz reference to make 125MHz RTIO clock with PLL");
( (
si5324::FrequencySettings { si5324::FrequencySettings {
n1_hs : 5, n1_hs: 5,
nc1_ls : 8, nc1_ls: 8,
n2_hs : 7, n2_hs: 7,
n2_ls : 360, n2_ls: 360,
n31 : 63, n31: 63,
n32 : 63, n32: 63,
bwsel : 4, bwsel: 4,
crystal_as_ckin2: false crystal_as_ckin2: false,
}, },
SI5324_EXT_INPUT SI5324_EXT_INPUT,
) )
}, }
RtioClock::Int_150 => { // 150MHz output, from crystal RtioClock::Int_150 => {
// 150MHz output, from crystal
info!("using internal 150MHz RTIO clock"); info!("using internal 150MHz RTIO clock");
( (
si5324::FrequencySettings { si5324::FrequencySettings {
n1_hs : 9, n1_hs: 9,
nc1_ls : 4, nc1_ls: 4,
n2_hs : 10, n2_hs: 10,
n2_ls : 33732, n2_ls: 33732,
n31 : 7139, n31: 7139,
n32 : 7139, n32: 7139,
bwsel : 3, bwsel: 3,
crystal_as_ckin2: true crystal_as_ckin2: true,
}, },
si5324::Input::Ckin2 si5324::Input::Ckin2,
) )
}, }
RtioClock::Int_100 => { // 100MHz output, from crystal RtioClock::Int_100 => {
// 100MHz output, from crystal
info!("using internal 100MHz RTIO clock"); info!("using internal 100MHz RTIO clock");
( (
si5324::FrequencySettings { si5324::FrequencySettings {
n1_hs : 9, n1_hs: 9,
nc1_ls : 6, nc1_ls: 6,
n2_hs : 10, n2_hs: 10,
n2_ls : 33732, n2_ls: 33732,
n31 : 7139, n31: 7139,
n32 : 7139, n32: 7139,
bwsel : 3, bwsel: 3,
crystal_as_ckin2: true crystal_as_ckin2: true,
}, },
si5324::Input::Ckin2 si5324::Input::Ckin2,
) )
}, }
RtioClock::Int_125 => { // 125MHz output, from crystal, 7 Hz RtioClock::Int_125 => {
// 125MHz output, from crystal, 7 Hz
info!("using internal 125MHz RTIO clock"); info!("using internal 125MHz RTIO clock");
( (
si5324::FrequencySettings { si5324::FrequencySettings {
n1_hs : 10, n1_hs: 10,
nc1_ls : 4, nc1_ls: 4,
n2_hs : 10, n2_hs: 10,
n2_ls : 19972, n2_ls: 19972,
n31 : 4565, n31: 4565,
n32 : 4565, n32: 4565,
bwsel : 4, bwsel: 4,
crystal_as_ckin2: true crystal_as_ckin2: true,
}, },
si5324::Input::Ckin2 si5324::Input::Ckin2,
) )
}, }
_ => { // same setting as Int_125, but fallback to default _ => {
warn!("rtio_clock setting '{:?}' is unsupported. Falling back to default internal 125MHz RTIO clock.", clk); // same setting as Int_125, but fallback to default
warn!(
"rtio_clock setting '{:?}' is unsupported. Falling back to default internal 125MHz RTIO clock.",
clk
);
( (
si5324::FrequencySettings { si5324::FrequencySettings {
n1_hs : 10, n1_hs: 10,
nc1_ls : 4, nc1_ls: 4,
n2_hs : 10, n2_hs: 10,
n2_ls : 19972, n2_ls: 19972,
n31 : 4565, n31: 4565,
n32 : 4565, n32: 4565,
bwsel : 4, bwsel: 4,
crystal_as_ckin2: true crystal_as_ckin2: true,
}, },
si5324::Input::Ckin2 si5324::Input::Ckin2,
) )
} }
}; };
@ -232,7 +240,6 @@ fn setup_si5324(i2c: &mut I2c, timer: &mut GlobalTimer, clk: RtioClock) {
} }
pub fn init(timer: &mut GlobalTimer, cfg: &Config) { pub fn init(timer: &mut GlobalTimer, cfg: &Config) {
let clk = get_rtio_clock_cfg(cfg); let clk = get_rtio_clock_cfg(cfg);
#[cfg(has_si5324)] #[cfg(has_si5324)]
{ {
@ -248,4 +255,4 @@ pub fn init(timer: &mut GlobalTimer, cfg: &Config) {
#[cfg(not(has_drtio))] #[cfg(not(has_drtio))]
init_rtio(timer); init_rtio(timer);
} }

View File

@ -1,18 +1,16 @@
use core::ptr::{read_volatile, write_volatile}; use core::ptr::{read_volatile, write_volatile};
use cslice::CSlice; use cslice::CSlice;
use crate::artiq_raise; use crate::{artiq_raise, pl::csr, rtio_mgt::resolve_channel_name};
use crate::pl::csr; pub const RTIO_O_STATUS_WAIT: u8 = 1;
use crate::rtio_mgt::resolve_channel_name; pub const RTIO_O_STATUS_UNDERFLOW: u8 = 2;
pub const RTIO_O_STATUS_DESTINATION_UNREACHABLE: u8 = 4;
pub const RTIO_O_STATUS_WAIT: u8 = 1; pub const RTIO_I_STATUS_WAIT_EVENT: u8 = 1;
pub const RTIO_O_STATUS_UNDERFLOW: u8 = 2; pub const RTIO_I_STATUS_OVERFLOW: u8 = 2;
pub const RTIO_O_STATUS_DESTINATION_UNREACHABLE: u8 = 4; pub const RTIO_I_STATUS_WAIT_STATUS: u8 = 4;
pub const RTIO_I_STATUS_WAIT_EVENT: u8 = 1; pub const RTIO_I_STATUS_DESTINATION_UNREACHABLE: u8 = 8;
pub const RTIO_I_STATUS_OVERFLOW: u8 = 2;
pub const RTIO_I_STATUS_WAIT_STATUS: u8 = 4;
pub const RTIO_I_STATUS_DESTINATION_UNREACHABLE: u8 = 8;
#[repr(C)] #[repr(C)]
pub struct TimestampedData { pub struct TimestampedData {
@ -20,32 +18,30 @@ pub struct TimestampedData {
data: i32, data: i32,
} }
pub extern fn init() { pub extern "C" fn init() {
unsafe { unsafe {
csr::rtio_core::reset_write(1); csr::rtio_core::reset_write(1);
} }
} }
pub extern fn get_counter() -> i64 { pub extern "C" fn get_counter() -> i64 {
unsafe { unsafe {
csr::rtio::counter_update_write(1); csr::rtio::counter_update_write(1);
csr::rtio::counter_read() as i64 csr::rtio::counter_read() as i64
} }
} }
pub extern fn now_mu() -> i64 { pub extern "C" fn now_mu() -> i64 {
unsafe { unsafe { csr::rtio::now_read() as i64 }
csr::rtio::now_read() as i64
}
} }
pub extern fn at_mu(t: i64) { pub extern "C" fn at_mu(t: i64) {
unsafe { unsafe {
csr::rtio::now_write(t as u64); csr::rtio::now_write(t as u64);
} }
} }
pub extern fn delay_mu(dt: i64) { pub extern "C" fn delay_mu(dt: i64) {
unsafe { unsafe {
csr::rtio::now_write(csr::rtio::now_read() + dt as u64); csr::rtio::now_write(csr::rtio::now_read() + dt as u64);
} }
@ -56,13 +52,13 @@ pub extern fn delay_mu(dt: i64) {
pub unsafe fn rtio_o_data_write(offset: usize, data: u32) { pub unsafe fn rtio_o_data_write(offset: usize, data: u32) {
write_volatile( write_volatile(
csr::rtio::O_DATA_ADDR.offset((csr::rtio::O_DATA_SIZE - 1 - offset) as isize), csr::rtio::O_DATA_ADDR.offset((csr::rtio::O_DATA_SIZE - 1 - offset) as isize),
data); data,
);
} }
#[inline(always)] #[inline(always)]
pub unsafe fn rtio_i_data_read(offset: usize) -> u32 { pub unsafe fn rtio_i_data_read(offset: usize) -> u32 {
read_volatile( read_volatile(csr::rtio::I_DATA_ADDR.offset((csr::rtio::I_DATA_SIZE - 1 - offset) as isize))
csr::rtio::I_DATA_ADDR.offset((csr::rtio::I_DATA_SIZE - 1 - offset) as isize))
} }
#[inline(never)] #[inline(never)]
@ -72,18 +68,34 @@ unsafe fn process_exceptional_status(channel: i32, status: u8) {
while csr::rtio::o_status_read() & RTIO_O_STATUS_WAIT != 0 {} while csr::rtio::o_status_read() & RTIO_O_STATUS_WAIT != 0 {}
} }
if status & RTIO_O_STATUS_UNDERFLOW != 0 { if status & RTIO_O_STATUS_UNDERFLOW != 0 {
artiq_raise!("RTIOUnderflow", artiq_raise!(
format!("RTIO underflow at {{1}} mu, channel 0x{:04x}:{}, slack {{2}} mu", channel, resolve_channel_name(channel as u32)), "RTIOUnderflow",
channel as i64, timestamp, timestamp - get_counter()); format!(
"RTIO underflow at {{1}} mu, channel 0x{:04x}:{}, slack {{2}} mu",
channel,
resolve_channel_name(channel as u32)
),
channel as i64,
timestamp,
timestamp - get_counter()
);
} }
if status & RTIO_O_STATUS_DESTINATION_UNREACHABLE != 0 { if status & RTIO_O_STATUS_DESTINATION_UNREACHABLE != 0 {
artiq_raise!("RTIODestinationUnreachable", artiq_raise!(
format!("RTIO destination unreachable, output, at {{0}} mu, channel 0x{:04x}:{}", channel, resolve_channel_name(channel as u32)), "RTIODestinationUnreachable",
timestamp, channel as i64, 0); format!(
"RTIO destination unreachable, output, at {{0}} mu, channel 0x{:04x}:{}",
channel,
resolve_channel_name(channel as u32)
),
timestamp,
channel as i64,
0
);
} }
} }
pub extern fn output(target: i32, data: i32) { pub extern "C" fn output(target: i32, data: i32) {
unsafe { unsafe {
csr::rtio::target_write(target as u32); csr::rtio::target_write(target as u32);
// writing target clears o_data // writing target clears o_data
@ -95,7 +107,7 @@ pub extern fn output(target: i32, data: i32) {
} }
} }
pub extern fn output_wide(target: i32, data: CSlice<i32>) { pub extern "C" fn output_wide(target: i32, data: CSlice<i32>) {
unsafe { unsafe {
csr::rtio::target_write(target as u32); csr::rtio::target_write(target as u32);
// writing target clears o_data // writing target clears o_data
@ -109,7 +121,7 @@ pub extern fn output_wide(target: i32, data: CSlice<i32>) {
} }
} }
pub extern fn input_timestamp(timeout: i64, channel: i32) -> i64 { pub extern "C" fn input_timestamp(timeout: i64, channel: i32) -> i64 {
unsafe { unsafe {
csr::rtio::target_write((channel as u32) << 8); csr::rtio::target_write((channel as u32) << 8);
csr::rtio::i_timeout_write(timeout as u64); csr::rtio::i_timeout_write(timeout as u64);
@ -120,24 +132,40 @@ pub extern fn input_timestamp(timeout: i64, channel: i32) -> i64 {
} }
if status & RTIO_I_STATUS_OVERFLOW != 0 { if status & RTIO_I_STATUS_OVERFLOW != 0 {
artiq_raise!("RTIOOverflow", artiq_raise!(
format!("RTIO input overflow on channel 0x{:04x}:{}", channel, resolve_channel_name(channel as u32)), "RTIOOverflow",
channel as i64, 0, 0); format!(
"RTIO input overflow on channel 0x{:04x}:{}",
channel,
resolve_channel_name(channel as u32)
),
channel as i64,
0,
0
);
} }
if status & RTIO_I_STATUS_WAIT_EVENT != 0 { if status & RTIO_I_STATUS_WAIT_EVENT != 0 {
return -1 return -1;
} }
if status & RTIO_I_STATUS_DESTINATION_UNREACHABLE != 0 { if status & RTIO_I_STATUS_DESTINATION_UNREACHABLE != 0 {
artiq_raise!("RTIODestinationUnreachable", artiq_raise!(
format!("RTIO destination unreachable, input, on channel 0x{:04x}:{}", channel, resolve_channel_name(channel as u32)), "RTIODestinationUnreachable",
channel as i64, 0, 0); format!(
"RTIO destination unreachable, input, on channel 0x{:04x}:{}",
channel,
resolve_channel_name(channel as u32)
),
channel as i64,
0,
0
);
} }
csr::rtio::i_timestamp_read() as i64 csr::rtio::i_timestamp_read() as i64
} }
} }
pub extern fn input_data(channel: i32) -> i32 { pub extern "C" fn input_data(channel: i32) -> i32 {
unsafe { unsafe {
csr::rtio::target_write((channel as u32) << 8); csr::rtio::target_write((channel as u32) << 8);
csr::rtio::i_timeout_write(0xffffffff_ffffffff); csr::rtio::i_timeout_write(0xffffffff_ffffffff);
@ -148,21 +176,37 @@ pub extern fn input_data(channel: i32) -> i32 {
} }
if status & RTIO_I_STATUS_OVERFLOW != 0 { if status & RTIO_I_STATUS_OVERFLOW != 0 {
artiq_raise!("RTIOOverflow", artiq_raise!(
format!("RTIO input overflow on channel 0x{:04x}:{}", channel, resolve_channel_name(channel as u32)), "RTIOOverflow",
channel as i64, 0, 0); format!(
"RTIO input overflow on channel 0x{:04x}:{}",
channel,
resolve_channel_name(channel as u32)
),
channel as i64,
0,
0
);
} }
if status & RTIO_I_STATUS_DESTINATION_UNREACHABLE != 0 { if status & RTIO_I_STATUS_DESTINATION_UNREACHABLE != 0 {
artiq_raise!("RTIODestinationUnreachable", artiq_raise!(
format!("RTIO destination unreachable, input, on channel 0x{:04x}:{}", channel, resolve_channel_name(channel as u32)), "RTIODestinationUnreachable",
channel as i64, 0, 0); format!(
"RTIO destination unreachable, input, on channel 0x{:04x}:{}",
channel,
resolve_channel_name(channel as u32)
),
channel as i64,
0,
0
);
} }
rtio_i_data_read(0) as i32 rtio_i_data_read(0) as i32
} }
} }
pub extern fn input_timestamped_data(timeout: i64, channel: i32) -> TimestampedData { pub extern "C" fn input_timestamped_data(timeout: i64, channel: i32) -> TimestampedData {
unsafe { unsafe {
csr::rtio::target_write((channel as u32) << 8); csr::rtio::target_write((channel as u32) << 8);
csr::rtio::i_timeout_write(timeout as u64); csr::rtio::i_timeout_write(timeout as u64);
@ -173,22 +217,38 @@ pub extern fn input_timestamped_data(timeout: i64, channel: i32) -> TimestampedD
} }
if status & RTIO_I_STATUS_OVERFLOW != 0 { if status & RTIO_I_STATUS_OVERFLOW != 0 {
artiq_raise!("RTIOOverflow", artiq_raise!(
format!("RTIO input overflow on channel 0x{:04x}:{}", channel, resolve_channel_name(channel as u32)), "RTIOOverflow",
channel as i64, 0, 0); format!(
"RTIO input overflow on channel 0x{:04x}:{}",
channel,
resolve_channel_name(channel as u32)
),
channel as i64,
0,
0
);
} }
if status & RTIO_I_STATUS_WAIT_EVENT != 0 { if status & RTIO_I_STATUS_WAIT_EVENT != 0 {
return TimestampedData { timestamp: -1, data: 0 } return TimestampedData { timestamp: -1, data: 0 };
} }
if status & RTIO_I_STATUS_DESTINATION_UNREACHABLE != 0 { if status & RTIO_I_STATUS_DESTINATION_UNREACHABLE != 0 {
artiq_raise!("RTIODestinationUnreachable", artiq_raise!(
format!("RTIO destination unreachable, input, on channel 0x{:04x}:{}", channel, resolve_channel_name(channel as u32)), "RTIODestinationUnreachable",
channel as i64, 0, 0); format!(
"RTIO destination unreachable, input, on channel 0x{:04x}:{}",
channel,
resolve_channel_name(channel as u32)
),
channel as i64,
0,
0
);
} }
TimestampedData { TimestampedData {
timestamp: csr::rtio::i_timestamp_read() as i64, timestamp: csr::rtio::i_timestamp_read() as i64,
data: rtio_i_data_read(0) as i32 data: rtio_i_data_read(0) as i32,
} }
} }
} }

View File

@ -1,33 +1,32 @@
use alloc::{collections::BTreeMap, rc::Rc, string::String};
use core::cell::RefCell; use core::cell::RefCell;
use alloc::rc::Rc;
use alloc::collections::BTreeMap;
use alloc::string::String;
use libboard_zynq::timer::GlobalTimer;
use libboard_artiq::{pl::csr, drtio_routing};
use libcortex_a9::mutex::Mutex;
use libconfig::Config;
use io::{Cursor, ProtoRead}; use io::{Cursor, ProtoRead};
use libboard_artiq::{drtio_routing, pl::csr};
use libboard_zynq::timer::GlobalTimer;
use libconfig::Config;
use libcortex_a9::mutex::Mutex;
use log::error; use log::error;
static mut RTIO_DEVICE_MAP: BTreeMap<u32, String> = BTreeMap::new(); static mut RTIO_DEVICE_MAP: BTreeMap<u32, String> = BTreeMap::new();
#[cfg(has_drtio)] #[cfg(has_drtio)]
pub mod drtio { pub mod drtio {
use super::*;
use crate::{SEEN_ASYNC_ERRORS, ASYNC_ERROR_BUSY, ASYNC_ERROR_SEQUENCE_ERROR, ASYNC_ERROR_COLLISION};
use libboard_artiq::drtioaux_async;
use libboard_artiq::drtioaux_async::Packet;
use libboard_artiq::drtioaux::Error;
use log::{warn, error, info};
use embedded_hal::blocking::delay::DelayMs; use embedded_hal::blocking::delay::DelayMs;
use libasync::{task, delay}; use libasync::{delay, task};
use libboard_artiq::{drtioaux::Error, drtioaux_async, drtioaux_async::Packet};
use libboard_zynq::time::Milliseconds; use libboard_zynq::time::Milliseconds;
use log::{error, info, warn};
pub fn startup(aux_mutex: &Rc<Mutex<bool>>, use super::*;
routing_table: &Rc<RefCell<drtio_routing::RoutingTable>>, use crate::{ASYNC_ERROR_BUSY, ASYNC_ERROR_COLLISION, ASYNC_ERROR_SEQUENCE_ERROR, SEEN_ASYNC_ERRORS};
up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>,
timer: GlobalTimer) { pub fn startup(
aux_mutex: &Rc<Mutex<bool>>,
routing_table: &Rc<RefCell<drtio_routing::RoutingTable>>,
up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>,
timer: GlobalTimer,
) {
let aux_mutex = aux_mutex.clone(); let aux_mutex = aux_mutex.clone();
let routing_table = routing_table.clone(); let routing_table = routing_table.clone();
let up_destinations = up_destinations.clone(); let up_destinations = up_destinations.clone();
@ -39,9 +38,7 @@ pub mod drtio {
async fn link_rx_up(linkno: u8) -> bool { async fn link_rx_up(linkno: u8) -> bool {
let linkno = linkno as usize; let linkno = linkno as usize;
unsafe { unsafe { (csr::DRTIO[linkno].rx_up_read)() == 1 }
(csr::DRTIO[linkno].rx_up_read)() == 1
}
} }
async fn recv_aux_timeout(linkno: u8, timeout: u64, timer: GlobalTimer) -> Result<Packet, &'static str> { async fn recv_aux_timeout(linkno: u8, timeout: u64, timer: GlobalTimer) -> Result<Packet, &'static str> {
@ -55,8 +52,12 @@ pub mod drtio {
} }
} }
pub async fn aux_transact(aux_mutex: &Mutex<bool>, linkno: u8, request: &Packet, pub async fn aux_transact(
timer: GlobalTimer) -> Result<Packet, &'static str> { aux_mutex: &Mutex<bool>,
linkno: u8,
request: &Packet,
timer: GlobalTimer,
) -> Result<Packet, &'static str> {
if !link_rx_up(linkno).await { if !link_rx_up(linkno).await {
return Err("link went down"); return Err("link went down");
} }
@ -79,7 +80,7 @@ pub mod drtio {
let mut count = 0; let mut count = 0;
loop { loop {
if !link_rx_up(linkno).await { if !link_rx_up(linkno).await {
return 0 return 0;
} }
count += 1; count += 1;
if count > 100 { if count > 100 {
@ -115,13 +116,23 @@ pub mod drtio {
} }
} }
async fn load_routing_table(aux_mutex: &Rc<Mutex<bool>>, linkno: u8, routing_table: &drtio_routing::RoutingTable, async fn load_routing_table(
timer: GlobalTimer) -> Result<(), &'static str> { aux_mutex: &Rc<Mutex<bool>>,
linkno: u8,
routing_table: &drtio_routing::RoutingTable,
timer: GlobalTimer,
) -> Result<(), &'static str> {
for i in 0..drtio_routing::DEST_COUNT { for i in 0..drtio_routing::DEST_COUNT {
let reply = aux_transact(aux_mutex, linkno, &Packet::RoutingSetPath { let reply = aux_transact(
destination: i as u8, aux_mutex,
hops: routing_table.0[i] linkno,
}, timer).await?; &Packet::RoutingSetPath {
destination: i as u8,
hops: routing_table.0[i],
},
timer,
)
.await?;
if reply != Packet::RoutingAck { if reply != Packet::RoutingAck {
return Err("unexpected reply"); return Err("unexpected reply");
} }
@ -129,10 +140,13 @@ pub mod drtio {
Ok(()) Ok(())
} }
async fn set_rank(aux_mutex: &Rc<Mutex<bool>>, linkno: u8, rank: u8, timer: GlobalTimer) -> Result<(), &'static str> { async fn set_rank(
let reply = aux_transact(aux_mutex, linkno, &Packet::RoutingSetRank { aux_mutex: &Rc<Mutex<bool>>,
rank: rank linkno: u8,
}, timer).await?; rank: u8,
timer: GlobalTimer,
) -> Result<(), &'static str> {
let reply = aux_transact(aux_mutex, linkno, &Packet::RoutingSetRank { rank: rank }, timer).await?;
if reply != Packet::RoutingAck { if reply != Packet::RoutingAck {
return Err("unexpected reply"); return Err("unexpected reply");
} }
@ -146,8 +160,11 @@ pub mod drtio {
(csr::DRTIO[linkno].force_destination_write)(1); (csr::DRTIO[linkno].force_destination_write)(1);
(csr::DRTIO[linkno].o_get_buffer_space_write)(1); (csr::DRTIO[linkno].o_get_buffer_space_write)(1);
while (csr::DRTIO[linkno].o_wait_read)() == 1 {} while (csr::DRTIO[linkno].o_wait_read)() == 1 {}
info!("[DEST#{}] buffer space is {}", info!(
destination, (csr::DRTIO[linkno].o_dbg_buffer_space_read)()); "[DEST#{}] buffer space is {}",
destination,
(csr::DRTIO[linkno].o_dbg_buffer_space_read)()
);
(csr::DRTIO[linkno].force_destination_write)(0); (csr::DRTIO[linkno].force_destination_write)(0);
} }
} }
@ -157,7 +174,7 @@ pub mod drtio {
match drtioaux_async::recv(linkno).await { match drtioaux_async::recv(linkno).await {
Ok(Some(packet)) => warn!("[LINK#{}] unsolicited aux packet: {:?}", linkno, packet), Ok(Some(packet)) => warn!("[LINK#{}] unsolicited aux packet: {:?}", linkno, packet),
Ok(None) => (), Ok(None) => (),
Err(_) => warn!("[LINK#{}] aux packet error", linkno) Err(_) => warn!("[LINK#{}] aux packet error", linkno),
} }
} }
@ -182,9 +199,12 @@ pub mod drtio {
} }
} }
async fn destination_set_up(routing_table: &drtio_routing::RoutingTable, async fn destination_set_up(
up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>, routing_table: &drtio_routing::RoutingTable,
destination: u8, up: bool) { up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>,
destination: u8,
up: bool,
) {
let mut up_destinations = up_destinations.borrow_mut(); let mut up_destinations = up_destinations.borrow_mut();
up_destinations[destination as usize] = up; up_destinations[destination as usize] = up;
if up { if up {
@ -201,10 +221,13 @@ pub mod drtio {
up_destinations[destination as usize] up_destinations[destination as usize]
} }
async fn destination_survey(aux_mutex: &Rc<Mutex<bool>>, routing_table: &drtio_routing::RoutingTable, async fn destination_survey(
up_links: &[bool], aux_mutex: &Rc<Mutex<bool>>,
up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>, routing_table: &drtio_routing::RoutingTable,
timer: GlobalTimer) { up_links: &[bool],
up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>,
timer: GlobalTimer,
) {
for destination in 0..drtio_routing::DEST_COUNT { for destination in 0..drtio_routing::DEST_COUNT {
let hop = routing_table.0[destination][0]; let hop = routing_table.0[destination][0];
let destination = destination as u8; let destination = destination as u8;
@ -218,44 +241,72 @@ pub mod drtio {
let linkno = hop - 1; let linkno = hop - 1;
if destination_up(up_destinations, destination).await { if destination_up(up_destinations, destination).await {
if up_links[linkno as usize] { if up_links[linkno as usize] {
let reply = aux_transact(aux_mutex, linkno, &Packet::DestinationStatusRequest { let reply = aux_transact(
destination: destination aux_mutex,
}, timer).await; linkno,
&Packet::DestinationStatusRequest {
destination: destination,
},
timer,
)
.await;
match reply { match reply {
Ok(Packet::DestinationDownReply) => Ok(Packet::DestinationDownReply) => {
destination_set_up(routing_table, up_destinations, destination, false).await, destination_set_up(routing_table, up_destinations, destination, false).await
}
Ok(Packet::DestinationOkReply) => (), Ok(Packet::DestinationOkReply) => (),
Ok(Packet::DestinationSequenceErrorReply { channel }) =>{ Ok(Packet::DestinationSequenceErrorReply { channel }) => {
error!("[DEST#{}] RTIO sequence error involving channel 0x{:04x}:{}", destination, channel, resolve_channel_name(channel as u32)); error!(
"[DEST#{}] RTIO sequence error involving channel 0x{:04x}:{}",
destination,
channel,
resolve_channel_name(channel as u32)
);
unsafe { SEEN_ASYNC_ERRORS |= ASYNC_ERROR_SEQUENCE_ERROR }; unsafe { SEEN_ASYNC_ERRORS |= ASYNC_ERROR_SEQUENCE_ERROR };
} }
Ok(Packet::DestinationCollisionReply { channel }) =>{ Ok(Packet::DestinationCollisionReply { channel }) => {
error!("[DEST#{}] RTIO collision involving channel 0x{:04x}:{}", destination, channel, resolve_channel_name(channel as u32)); error!(
"[DEST#{}] RTIO collision involving channel 0x{:04x}:{}",
destination,
channel,
resolve_channel_name(channel as u32)
);
unsafe { SEEN_ASYNC_ERRORS |= ASYNC_ERROR_COLLISION }; unsafe { SEEN_ASYNC_ERRORS |= ASYNC_ERROR_COLLISION };
} }
Ok(Packet::DestinationBusyReply { channel }) =>{ Ok(Packet::DestinationBusyReply { channel }) => {
error!("[DEST#{}] RTIO busy error involving channel 0x{:04x}:{}", destination, channel, resolve_channel_name(channel as u32)); error!(
"[DEST#{}] RTIO busy error involving channel 0x{:04x}:{}",
destination,
channel,
resolve_channel_name(channel as u32)
);
unsafe { SEEN_ASYNC_ERRORS |= ASYNC_ERROR_BUSY }; unsafe { SEEN_ASYNC_ERRORS |= ASYNC_ERROR_BUSY };
} }
Ok(packet) => error!("[DEST#{}] received unexpected aux packet: {:?}", destination, packet), Ok(packet) => error!("[DEST#{}] received unexpected aux packet: {:?}", destination, packet),
Err(e) => error!("[DEST#{}] communication failed ({})", destination, e) Err(e) => error!("[DEST#{}] communication failed ({})", destination, e),
} }
} else { } else {
destination_set_up(routing_table, up_destinations, destination, false).await; destination_set_up(routing_table, up_destinations, destination, false).await;
} }
} else { } else {
if up_links[linkno as usize] { if up_links[linkno as usize] {
let reply = aux_transact(aux_mutex, linkno, &Packet::DestinationStatusRequest { let reply = aux_transact(
destination: destination aux_mutex,
}, timer).await; linkno,
&Packet::DestinationStatusRequest {
destination: destination,
},
timer,
)
.await;
match reply { match reply {
Ok(Packet::DestinationDownReply) => (), Ok(Packet::DestinationDownReply) => (),
Ok(Packet::DestinationOkReply) => { Ok(Packet::DestinationOkReply) => {
destination_set_up(routing_table, up_destinations, destination, true).await; destination_set_up(routing_table, up_destinations, destination, true).await;
init_buffer_space(destination as u8, linkno).await; init_buffer_space(destination as u8, linkno).await;
}, }
Ok(packet) => error!("[DEST#{}] received unexpected aux packet: {:?}", destination, packet), Ok(packet) => error!("[DEST#{}] received unexpected aux packet: {:?}", destination, packet),
Err(e) => error!("[DEST#{}] communication failed ({})", destination, e) Err(e) => error!("[DEST#{}] communication failed ({})", destination, e),
} }
} }
} }
@ -263,10 +314,12 @@ pub mod drtio {
} }
} }
pub async fn link_task(aux_mutex: &Rc<Mutex<bool>>, pub async fn link_task(
routing_table: &drtio_routing::RoutingTable, aux_mutex: &Rc<Mutex<bool>>,
up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>, routing_table: &drtio_routing::RoutingTable,
timer: GlobalTimer) { up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>,
timer: GlobalTimer,
) {
let mut up_links = [false; csr::DRTIO.len()]; let mut up_links = [false; csr::DRTIO.len()];
loop { loop {
for linkno in 0..csr::DRTIO.len() { for linkno in 0..csr::DRTIO.len() {
@ -327,12 +380,11 @@ pub mod drtio {
for linkno in 0..csr::DRTIO.len() { for linkno in 0..csr::DRTIO.len() {
let linkno = linkno as u8; let linkno = linkno as u8;
if task::block_on(link_rx_up(linkno)) { if task::block_on(link_rx_up(linkno)) {
let reply = task::block_on(aux_transact(&aux_mutex, linkno, let reply = task::block_on(aux_transact(&aux_mutex, linkno, &Packet::ResetRequest, timer));
&Packet::ResetRequest, timer));
match reply { match reply {
Ok(Packet::ResetAck) => (), Ok(Packet::ResetAck) => (),
Ok(_) => error!("[LINK#{}] reset failed, received unexpected aux packet", linkno), Ok(_) => error!("[LINK#{}] reset failed, received unexpected aux packet", linkno),
Err(e) => error!("[LINK#{}] reset failed, aux packet error ({})", linkno, e) Err(e) => error!("[LINK#{}] reset failed, aux packet error ({})", linkno, e),
} }
} }
} }
@ -341,53 +393,67 @@ pub mod drtio {
fn read_device_map(cfg: &Config) -> BTreeMap<u32, String> { fn read_device_map(cfg: &Config) -> BTreeMap<u32, String> {
let mut device_map: BTreeMap<u32, String> = BTreeMap::new(); let mut device_map: BTreeMap<u32, String> = BTreeMap::new();
let _ = cfg.read("device_map").and_then(|raw_bytes| { let _ = cfg
let mut bytes_cr = Cursor::new(raw_bytes); .read("device_map")
let size = bytes_cr.read_u32().unwrap(); .and_then(|raw_bytes| {
for _ in 0..size { let mut bytes_cr = Cursor::new(raw_bytes);
let channel = bytes_cr.read_u32().unwrap(); let size = bytes_cr.read_u32().unwrap();
let device_name = bytes_cr.read_string().unwrap(); for _ in 0..size {
if let Some(old_entry) = device_map.insert(channel, device_name.clone()) { let channel = bytes_cr.read_u32().unwrap();
error!("read_device_map: conflicting entries for channel {}: `{}` and `{}`", let device_name = bytes_cr.read_string().unwrap();
channel, old_entry, device_name); if let Some(old_entry) = device_map.insert(channel, device_name.clone()) {
error!(
"read_device_map: conflicting entries for channel {}: `{}` and `{}`",
channel, old_entry, device_name
);
}
} }
} Ok(())
Ok(()) })
} ).or_else(|err| { .or_else(|err| {
error!("read_device_map: error reading `device_map` from config: {}", err); error!("read_device_map: error reading `device_map` from config: {}", err);
Err(err) Err(err)
}); });
device_map device_map
} }
fn _resolve_channel_name(channel: u32, device_map: &BTreeMap<u32, String>) -> String { fn _resolve_channel_name(channel: u32, device_map: &BTreeMap<u32, String>) -> String {
match device_map.get(&channel) { match device_map.get(&channel) {
Some(val) => val.clone(), Some(val) => val.clone(),
None => String::from("unknown") None => String::from("unknown"),
} }
} }
pub fn resolve_channel_name(channel: u32) -> String { pub fn resolve_channel_name(channel: u32) -> String {
_resolve_channel_name(channel, unsafe{&RTIO_DEVICE_MAP}) _resolve_channel_name(channel, unsafe { &RTIO_DEVICE_MAP })
} }
#[cfg(not(has_drtio))] #[cfg(not(has_drtio))]
pub mod drtio { pub mod drtio {
use super::*; use super::*;
pub fn startup(_aux_mutex: &Rc<Mutex<bool>>, _routing_table: &Rc<RefCell<drtio_routing::RoutingTable>>, pub fn startup(
_up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>, _timer: GlobalTimer) {} _aux_mutex: &Rc<Mutex<bool>>,
_routing_table: &Rc<RefCell<drtio_routing::RoutingTable>>,
_up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>,
_timer: GlobalTimer,
) {
}
#[allow(dead_code)] #[allow(dead_code)]
pub fn reset(_aux_mutex: Rc<Mutex<bool>>, mut _timer: GlobalTimer) {} pub fn reset(_aux_mutex: Rc<Mutex<bool>>, mut _timer: GlobalTimer) {}
} }
pub fn startup(aux_mutex: &Rc<Mutex<bool>>, pub fn startup(
routing_table: &Rc<RefCell<drtio_routing::RoutingTable>>, aux_mutex: &Rc<Mutex<bool>>,
up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>, routing_table: &Rc<RefCell<drtio_routing::RoutingTable>>,
timer: GlobalTimer, up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>,
cfg: &Config) { timer: GlobalTimer,
unsafe { RTIO_DEVICE_MAP = read_device_map(cfg); } cfg: &Config,
) {
unsafe {
RTIO_DEVICE_MAP = read_device_map(cfg);
}
drtio::startup(aux_mutex, routing_table, up_destinations, timer); drtio::startup(aux_mutex, routing_table, up_destinations, timer);
unsafe { unsafe {
csr::rtio_core::reset_phy_write(1); csr::rtio_core::reset_phy_write(1);

68
src/rustfmt.toml Normal file
View File

@ -0,0 +1,68 @@
max_width = 120
hard_tabs = false
tab_spaces = 4
newline_style = "Auto"
use_small_heuristics = "Default"
indent_style = "Block"
wrap_comments = false
format_code_in_doc_comments = false
comment_width = 100
normalize_comments = false
normalize_doc_attributes = false
license_template_path = ""
format_strings = true
format_macro_matchers = true
format_macro_bodies = true
empty_item_single_line = true
struct_lit_single_line = true
fn_single_line = false
where_single_line = true
imports_indent = "Visual"
imports_layout = "Mixed"
merge_imports = true
group_imports = "StdExternalCrate"
reorder_imports = true
reorder_modules = true
reorder_impl_items = false
type_punctuation_density = "Wide"
space_before_colon = false
space_after_colon = true
spaces_around_ranges = false
binop_separator = "Front"
remove_nested_parens = true
combine_control_expr = true
overflow_delimited_expr = false
struct_field_align_threshold = 0
enum_discrim_align_threshold = 0
match_arm_blocks = true
match_arm_leading_pipes = "Never"
force_multiline_blocks = false
fn_args_layout = "Tall"
brace_style = "SameLineWhere"
control_brace_style = "AlwaysSameLine"
trailing_semicolon = true
trailing_comma = "Vertical"
match_block_trailing_comma = false
blank_lines_upper_bound = 1
blank_lines_lower_bound = 0
edition = "2018"
version = "Two"
inline_attribute_width = 0
merge_derives = true
use_try_shorthand = false
use_field_init_shorthand = false
force_explicit_abi = true
condense_wildcard_suffixes = false
color = "Auto"
required_version = "1.4.32"
unstable_features = false
disable_all_formatting = false
skip_children = false
hide_parse_errors = false
error_on_line_overflow = false
error_on_unformatted = false
report_todo = "Never"
report_fixme = "Never"
ignore = []
emit_mode = "Files"
make_backup = false

View File

@ -8,30 +8,34 @@ extern crate log;
extern crate embedded_hal; extern crate embedded_hal;
extern crate libboard_zynq;
extern crate libboard_artiq; extern crate libboard_artiq;
extern crate libsupport_zynq; extern crate libboard_zynq;
extern crate libcortex_a9; extern crate libcortex_a9;
extern crate libregister; extern crate libregister;
extern crate libsupport_zynq;
extern crate unwind; extern crate unwind;
extern crate alloc; extern crate alloc;
use libboard_zynq::{i2c::I2c, timer::GlobalTimer, time::Milliseconds, print, println, mpcore, gic, stdio}; use core::sync::atomic::{AtomicBool, Ordering};
use libsupport_zynq::ram;
#[cfg(has_si5324)]
use libboard_artiq::si5324;
#[cfg(feature = "target_kasli_soc")]
use libboard_artiq::io_expander;
use libboard_artiq::{pl::csr, drtio_routing, drtioaux, logger, identifier_read};
use libcortex_a9::{spin_lock_yield, interrupt_handler, regs::{MPIDR, SP}, notify_spin_lock, asm, l2c::enable_l2_cache};
use libregister::{RegisterW, RegisterR};
#[cfg(feature = "target_kasli_soc")]
use libboard_zynq::error_led::ErrorLED;
use embedded_hal::blocking::delay::DelayUs; use embedded_hal::blocking::delay::DelayUs;
use core::sync::atomic::{AtomicBool, Ordering}; #[cfg(feature = "target_kasli_soc")]
use libboard_artiq::io_expander;
#[cfg(has_si5324)]
use libboard_artiq::si5324;
use libboard_artiq::{drtio_routing, drtioaux, identifier_read, logger, pl::csr};
#[cfg(feature = "target_kasli_soc")]
use libboard_zynq::error_led::ErrorLED;
use libboard_zynq::{gic, i2c::I2c, mpcore, print, println, stdio, time::Milliseconds, timer::GlobalTimer};
use libcortex_a9::{asm, interrupt_handler,
l2c::enable_l2_cache,
notify_spin_lock,
regs::{MPIDR, SP},
spin_lock_yield};
use libregister::{RegisterR, RegisterW};
use libsupport_zynq::ram;
mod repeater; mod repeater;
@ -48,9 +52,7 @@ fn drtiosat_reset_phy(reset: bool) {
} }
fn drtiosat_link_rx_up() -> bool { fn drtiosat_link_rx_up() -> bool {
unsafe { unsafe { csr::drtiosat::rx_up_read() == 1 }
csr::drtiosat::rx_up_read() == 1
}
} }
fn drtiosat_tsc_loaded() -> bool { fn drtiosat_tsc_loaded() -> bool {
@ -63,7 +65,6 @@ fn drtiosat_tsc_loaded() -> bool {
} }
} }
#[cfg(has_drtio_routing)] #[cfg(has_drtio_routing)]
macro_rules! forward { macro_rules! forward {
($routing_table:expr, $destination:expr, $rank:expr, $repeaters:expr, $packet:expr, $timer:expr) => {{ ($routing_table:expr, $destination:expr, $rank:expr, $repeaters:expr, $packet:expr, $timer:expr) => {{
@ -76,22 +77,26 @@ macro_rules! forward {
return Err(drtioaux::Error::RoutingError); return Err(drtioaux::Error::RoutingError);
} }
} }
}} }};
} }
#[cfg(not(has_drtio_routing))] #[cfg(not(has_drtio_routing))]
macro_rules! forward { macro_rules! forward {
($routing_table:expr, $destination:expr, $rank:expr, $repeaters:expr, $packet:expr, $timer:expr) => {} ($routing_table:expr, $destination:expr, $rank:expr, $repeaters:expr, $packet:expr, $timer:expr) => {};
} }
fn process_aux_packet(_repeaters: &mut [repeater::Repeater], fn process_aux_packet(
_routing_table: &mut drtio_routing::RoutingTable, _rank: &mut u8, _repeaters: &mut [repeater::Repeater],
packet: drtioaux::Packet, timer: &mut GlobalTimer, i2c: &mut I2c) -> Result<(), drtioaux::Error> { _routing_table: &mut drtio_routing::RoutingTable,
_rank: &mut u8,
packet: drtioaux::Packet,
timer: &mut GlobalTimer,
i2c: &mut I2c,
) -> Result<(), drtioaux::Error> {
// In the code below, *_chan_sel_write takes an u8 if there are fewer than 256 channels, // In the code below, *_chan_sel_write takes an u8 if there are fewer than 256 channels,
// and u16 otherwise; hence the `as _` conversion. // and u16 otherwise; hence the `as _` conversion.
match packet { match packet {
drtioaux::Packet::EchoRequest => drtioaux::Packet::EchoRequest => drtioaux::send(0, &drtioaux::Packet::EchoReply),
drtioaux::send(0, &drtioaux::Packet::EchoReply),
drtioaux::Packet::ResetRequest => { drtioaux::Packet::ResetRequest => {
info!("resetting RTIO"); info!("resetting RTIO");
drtiosat_reset(true); drtiosat_reset(true);
@ -103,9 +108,11 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater],
} }
} }
drtioaux::send(0, &drtioaux::Packet::ResetAck) drtioaux::send(0, &drtioaux::Packet::ResetAck)
}, }
drtioaux::Packet::DestinationStatusRequest { destination: _destination } => { drtioaux::Packet::DestinationStatusRequest {
destination: _destination,
} => {
#[cfg(has_drtio_routing)] #[cfg(has_drtio_routing)]
let hop = _routing_table.0[_destination as usize][*_rank as usize]; let hop = _routing_table.0[_destination as usize][*_rank as usize];
#[cfg(not(has_drtio_routing))] #[cfg(not(has_drtio_routing))]
@ -122,26 +129,22 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater],
channel = csr::drtiosat::sequence_error_channel_read(); channel = csr::drtiosat::sequence_error_channel_read();
csr::drtiosat::rtio_error_write(1); csr::drtiosat::rtio_error_write(1);
} }
drtioaux::send(0, drtioaux::send(0, &drtioaux::Packet::DestinationSequenceErrorReply { channel })?;
&drtioaux::Packet::DestinationSequenceErrorReply { channel })?;
} else if errors & 2 != 0 { } else if errors & 2 != 0 {
let channel; let channel;
unsafe { unsafe {
channel = csr::drtiosat::collision_channel_read(); channel = csr::drtiosat::collision_channel_read();
csr::drtiosat::rtio_error_write(2); csr::drtiosat::rtio_error_write(2);
} }
drtioaux::send(0, drtioaux::send(0, &drtioaux::Packet::DestinationCollisionReply { channel })?;
&drtioaux::Packet::DestinationCollisionReply { channel })?;
} else if errors & 4 != 0 { } else if errors & 4 != 0 {
let channel; let channel;
unsafe { unsafe {
channel = csr::drtiosat::busy_channel_read(); channel = csr::drtiosat::busy_channel_read();
csr::drtiosat::rtio_error_write(4); csr::drtiosat::rtio_error_write(4);
} }
drtioaux::send(0, drtioaux::send(0, &drtioaux::Packet::DestinationBusyReply { channel })?;
&drtioaux::Packet::DestinationBusyReply { channel })?; } else {
}
else {
drtioaux::send(0, &drtioaux::Packet::DestinationOkReply)?; drtioaux::send(0, &drtioaux::Packet::DestinationOkReply)?;
} }
} }
@ -152,15 +155,20 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater],
let hop = hop as usize; let hop = hop as usize;
if hop <= csr::DRTIOREP.len() { if hop <= csr::DRTIOREP.len() {
let repno = hop - 1; let repno = hop - 1;
match _repeaters[repno].aux_forward(&drtioaux::Packet::DestinationStatusRequest { match _repeaters[repno].aux_forward(
destination: _destination &drtioaux::Packet::DestinationStatusRequest {
}, timer) { destination: _destination,
},
timer,
) {
Ok(()) => (), Ok(()) => (),
Err(drtioaux::Error::LinkDown) => drtioaux::send(0, &drtioaux::Packet::DestinationDownReply)?, Err(drtioaux::Error::LinkDown) => {
drtioaux::send(0, &drtioaux::Packet::DestinationDownReply)?
}
Err(e) => { Err(e) => {
drtioaux::send(0, &drtioaux::Packet::DestinationDownReply)?; drtioaux::send(0, &drtioaux::Packet::DestinationDownReply)?;
error!("aux error when handling destination status request: {:?}", e); error!("aux error when handling destination status request: {:?}", e);
}, }
} }
} else { } else {
drtioaux::send(0, &drtioaux::Packet::DestinationDownReply)?; drtioaux::send(0, &drtioaux::Packet::DestinationDownReply)?;
@ -200,15 +208,18 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater],
} }
#[cfg(not(has_drtio_routing))] #[cfg(not(has_drtio_routing))]
drtioaux::Packet::RoutingSetPath { destination: _, hops: _ } => { drtioaux::Packet::RoutingSetPath {
drtioaux::send(0, &drtioaux::Packet::RoutingAck) destination: _,
} hops: _,
} => drtioaux::send(0, &drtioaux::Packet::RoutingAck),
#[cfg(not(has_drtio_routing))] #[cfg(not(has_drtio_routing))]
drtioaux::Packet::RoutingSetRank { rank: _ } => { drtioaux::Packet::RoutingSetRank { rank: _ } => drtioaux::send(0, &drtioaux::Packet::RoutingAck),
drtioaux::send(0, &drtioaux::Packet::RoutingAck)
}
drtioaux::Packet::MonitorRequest { destination: _destination, channel: _channel, probe: _probe } => { drtioaux::Packet::MonitorRequest {
destination: _destination,
channel: _channel,
probe: _probe,
} => {
forward!(_routing_table, _destination, *_rank, _repeaters, &packet, timer); forward!(_routing_table, _destination, *_rank, _repeaters, &packet, timer);
let value; let value;
#[cfg(has_rtio_moninj)] #[cfg(has_rtio_moninj)]
@ -224,9 +235,13 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater],
} }
let reply = drtioaux::Packet::MonitorReply { value: value }; let reply = drtioaux::Packet::MonitorReply { value: value };
drtioaux::send(0, &reply) drtioaux::send(0, &reply)
}, }
drtioaux::Packet::InjectionRequest { destination: _destination, channel: _channel, drtioaux::Packet::InjectionRequest {
overrd: _overrd, value: _value } => { destination: _destination,
channel: _channel,
overrd: _overrd,
value: _value,
} => {
forward!(_routing_table, _destination, *_rank, _repeaters, &packet, timer); forward!(_routing_table, _destination, *_rank, _repeaters, &packet, timer);
#[cfg(has_rtio_moninj)] #[cfg(has_rtio_moninj)]
unsafe { unsafe {
@ -235,9 +250,12 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater],
csr::rtio_moninj::inj_value_write(value); csr::rtio_moninj::inj_value_write(value);
} }
Ok(()) Ok(())
}, }
drtioaux::Packet::InjectionStatusRequest { destination: _destination, drtioaux::Packet::InjectionStatusRequest {
channel: _channel, overrd: _overrd } => { destination: _destination,
channel: _channel,
overrd: _overrd,
} => {
forward!(_routing_table, _destination, *_rank, _repeaters, &packet, timer); forward!(_routing_table, _destination, *_rank, _repeaters, &packet, timer);
let value; let value;
#[cfg(has_rtio_moninj)] #[cfg(has_rtio_moninj)]
@ -251,44 +269,87 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater],
value = 0; value = 0;
} }
drtioaux::send(0, &drtioaux::Packet::InjectionStatusReply { value: value }) drtioaux::send(0, &drtioaux::Packet::InjectionStatusReply { value: value })
}, }
drtioaux::Packet::I2cStartRequest { destination: _destination, busno: _busno } => { drtioaux::Packet::I2cStartRequest {
destination: _destination,
busno: _busno,
} => {
forward!(_routing_table, _destination, *_rank, _repeaters, &packet, timer); forward!(_routing_table, _destination, *_rank, _repeaters, &packet, timer);
let succeeded = i2c.start().is_ok(); let succeeded = i2c.start().is_ok();
drtioaux::send(0, &drtioaux::Packet::I2cBasicReply { succeeded: succeeded }) drtioaux::send(0, &drtioaux::Packet::I2cBasicReply { succeeded: succeeded })
} }
drtioaux::Packet::I2cRestartRequest { destination: _destination, busno: _busno } => { drtioaux::Packet::I2cRestartRequest {
destination: _destination,
busno: _busno,
} => {
forward!(_routing_table, _destination, *_rank, _repeaters, &packet, timer); forward!(_routing_table, _destination, *_rank, _repeaters, &packet, timer);
let succeeded = i2c.restart().is_ok(); let succeeded = i2c.restart().is_ok();
drtioaux::send(0, &drtioaux::Packet::I2cBasicReply { succeeded: succeeded }) drtioaux::send(0, &drtioaux::Packet::I2cBasicReply { succeeded: succeeded })
} }
drtioaux::Packet::I2cStopRequest { destination: _destination, busno: _busno } => { drtioaux::Packet::I2cStopRequest {
destination: _destination,
busno: _busno,
} => {
forward!(_routing_table, _destination, *_rank, _repeaters, &packet, timer); forward!(_routing_table, _destination, *_rank, _repeaters, &packet, timer);
let succeeded = i2c.stop().is_ok(); let succeeded = i2c.stop().is_ok();
drtioaux::send(0, &drtioaux::Packet::I2cBasicReply { succeeded: succeeded }) drtioaux::send(0, &drtioaux::Packet::I2cBasicReply { succeeded: succeeded })
} }
drtioaux::Packet::I2cWriteRequest { destination: _destination, busno: _busno, data } => { drtioaux::Packet::I2cWriteRequest {
destination: _destination,
busno: _busno,
data,
} => {
forward!(_routing_table, _destination, *_rank, _repeaters, &packet, timer); forward!(_routing_table, _destination, *_rank, _repeaters, &packet, timer);
match i2c.write(data) { match i2c.write(data) {
Ok(ack) => drtioaux::send(0, Ok(ack) => drtioaux::send(
&drtioaux::Packet::I2cWriteReply { succeeded: true, ack: ack }), 0,
Err(_) => drtioaux::send(0, &drtioaux::Packet::I2cWriteReply {
&drtioaux::Packet::I2cWriteReply { succeeded: false, ack: false }) succeeded: true,
ack: ack,
},
),
Err(_) => drtioaux::send(
0,
&drtioaux::Packet::I2cWriteReply {
succeeded: false,
ack: false,
},
),
} }
} }
drtioaux::Packet::I2cReadRequest { destination: _destination, busno: _busno, ack } => { drtioaux::Packet::I2cReadRequest {
destination: _destination,
busno: _busno,
ack,
} => {
forward!(_routing_table, _destination, *_rank, _repeaters, &packet, timer); forward!(_routing_table, _destination, *_rank, _repeaters, &packet, timer);
match i2c.read(ack) { match i2c.read(ack) {
Ok(data) => drtioaux::send(0, Ok(data) => drtioaux::send(
&drtioaux::Packet::I2cReadReply { succeeded: true, data: data }), 0,
Err(_) => drtioaux::send(0, &drtioaux::Packet::I2cReadReply {
&drtioaux::Packet::I2cReadReply { succeeded: false, data: 0xff }) succeeded: true,
data: data,
},
),
Err(_) => drtioaux::send(
0,
&drtioaux::Packet::I2cReadReply {
succeeded: false,
data: 0xff,
},
),
} }
} }
drtioaux::Packet::I2cSwitchSelectRequest { destination: _destination, busno: _busno, address, mask } => { drtioaux::Packet::I2cSwitchSelectRequest {
destination: _destination,
busno: _busno,
address,
mask,
} => {
forward!(_routing_table, _destination, *_rank, _repeaters, &packet, timer); forward!(_routing_table, _destination, *_rank, _repeaters, &packet, timer);
let ch = match mask { //decode from mainline, PCA9548-centric API let ch = match mask {
//decode from mainline, PCA9548-centric API
0x00 => None, 0x00 => None,
0x01 => Some(0), 0x01 => Some(0),
0x02 => Some(1), 0x02 => Some(1),
@ -298,28 +359,39 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater],
0x20 => Some(5), 0x20 => Some(5),
0x40 => Some(6), 0x40 => Some(6),
0x80 => Some(7), 0x80 => Some(7),
_ => { return drtioaux::send(0, &drtioaux::Packet::I2cBasicReply { succeeded: false }); } _ => return drtioaux::send(0, &drtioaux::Packet::I2cBasicReply { succeeded: false }),
}; };
let succeeded = i2c.pca954x_select(address, ch).is_ok(); let succeeded = i2c.pca954x_select(address, ch).is_ok();
drtioaux::send(0, &drtioaux::Packet::I2cBasicReply { succeeded: succeeded }) drtioaux::send(0, &drtioaux::Packet::I2cBasicReply { succeeded: succeeded })
} }
drtioaux::Packet::SpiSetConfigRequest { destination: _destination, busno: _busno, drtioaux::Packet::SpiSetConfigRequest {
flags: _flags, length: _length, div: _div, cs: _cs } => { destination: _destination,
busno: _busno,
flags: _flags,
length: _length,
div: _div,
cs: _cs,
} => {
forward!(_routing_table, _destination, *_rank, _repeaters, &packet, timer); forward!(_routing_table, _destination, *_rank, _repeaters, &packet, timer);
// todo: reimplement when/if SPI is available // todo: reimplement when/if SPI is available
//let succeeded = spi::set_config(busno, flags, length, div, cs).is_ok(); //let succeeded = spi::set_config(busno, flags, length, div, cs).is_ok();
drtioaux::send(0, drtioaux::send(0, &drtioaux::Packet::SpiBasicReply { succeeded: false })
&drtioaux::Packet::SpiBasicReply { succeeded: false }) }
}, drtioaux::Packet::SpiWriteRequest {
drtioaux::Packet::SpiWriteRequest { destination: _destination, busno: _busno, data: _data } => { destination: _destination,
busno: _busno,
data: _data,
} => {
forward!(_routing_table, _destination, *_rank, _repeaters, &packet, timer); forward!(_routing_table, _destination, *_rank, _repeaters, &packet, timer);
// todo: reimplement when/if SPI is available // todo: reimplement when/if SPI is available
//let succeeded = spi::write(busno, data).is_ok(); //let succeeded = spi::write(busno, data).is_ok();
drtioaux::send(0, drtioaux::send(0, &drtioaux::Packet::SpiBasicReply { succeeded: false })
&drtioaux::Packet::SpiBasicReply { succeeded: false })
} }
drtioaux::Packet::SpiReadRequest { destination: _destination, busno: _busno } => { drtioaux::Packet::SpiReadRequest {
destination: _destination,
busno: _busno,
} => {
forward!(_routing_table, _destination, *_rank, _repeaters, &packet, timer); forward!(_routing_table, _destination, *_rank, _repeaters, &packet, timer);
// todo: reimplement when/if SPI is available // todo: reimplement when/if SPI is available
// match spi::read(busno) { // match spi::read(busno) {
@ -328,8 +400,13 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater],
// Err(_) => drtioaux::send(0, // Err(_) => drtioaux::send(0,
// &drtioaux::Packet::SpiReadReply { succeeded: false, data: 0 }) // &drtioaux::Packet::SpiReadReply { succeeded: false, data: 0 })
// } // }
drtioaux::send(0, drtioaux::send(
&drtioaux::Packet::SpiReadReply { succeeded: false, data: 0 }) 0,
&drtioaux::Packet::SpiReadReply {
succeeded: false,
data: 0,
},
)
} }
_ => { _ => {
@ -339,20 +416,23 @@ fn process_aux_packet(_repeaters: &mut [repeater::Repeater],
} }
} }
fn process_aux_packets(repeaters: &mut [repeater::Repeater], fn process_aux_packets(
routing_table: &mut drtio_routing::RoutingTable, rank: &mut u8, repeaters: &mut [repeater::Repeater],
timer: &mut GlobalTimer, i2c: &mut I2c) { routing_table: &mut drtio_routing::RoutingTable,
let result = rank: &mut u8,
drtioaux::recv(0).and_then(|packet| { timer: &mut GlobalTimer,
if let Some(packet) = packet { i2c: &mut I2c,
process_aux_packet(repeaters, routing_table, rank, packet, timer, i2c) ) {
} else { let result = drtioaux::recv(0).and_then(|packet| {
Ok(()) if let Some(packet) = packet {
} process_aux_packet(repeaters, routing_table, rank, packet, timer, i2c)
}); } else {
Ok(())
}
});
match result { match result {
Ok(()) => (), Ok(()) => (),
Err(e) => warn!("aux packet error ({:?})", e) Err(e) => warn!("aux packet error ({:?})", e),
} }
} }
@ -372,7 +452,10 @@ fn drtiosat_process_errors() {
unsafe { unsafe {
destination = csr::drtiosat::buffer_space_timeout_dest_read(); destination = csr::drtiosat::buffer_space_timeout_dest_read();
} }
error!("timeout attempting to get buffer space from CRI, destination=0x{:02x}", destination) error!(
"timeout attempting to get buffer space from CRI, destination=0x{:02x}",
destination
)
} }
if errors & 8 != 0 { if errors & 8 != 0 {
let channel; let channel;
@ -383,8 +466,13 @@ fn drtiosat_process_errors() {
timestamp_event = csr::drtiosat::underflow_timestamp_event_read() as i64; timestamp_event = csr::drtiosat::underflow_timestamp_event_read() as i64;
timestamp_counter = csr::drtiosat::underflow_timestamp_counter_read() as i64; timestamp_counter = csr::drtiosat::underflow_timestamp_counter_read() as i64;
} }
error!("write underflow, channel={}, timestamp={}, counter={}, slack={}", error!(
channel, timestamp_event, timestamp_counter, timestamp_event-timestamp_counter); "write underflow, channel={}, timestamp={}, counter={}, slack={}",
channel,
timestamp_event,
timestamp_counter,
timestamp_event - timestamp_counter
);
} }
if errors & 16 != 0 { if errors & 16 != 0 {
error!("write overflow"); error!("write overflow");
@ -404,42 +492,38 @@ fn hardware_tick(ts: &mut u64, timer: &mut GlobalTimer) {
} }
#[cfg(all(has_si5324, rtio_frequency = "125.0"))] #[cfg(all(has_si5324, rtio_frequency = "125.0"))]
const SI5324_SETTINGS: si5324::FrequencySettings const SI5324_SETTINGS: si5324::FrequencySettings = si5324::FrequencySettings {
= si5324::FrequencySettings { n1_hs: 5,
n1_hs : 5, nc1_ls: 8,
nc1_ls : 8, n2_hs: 7,
n2_hs : 7, n2_ls: 360,
n2_ls : 360, n31: 63,
n31 : 63, n32: 63,
n32 : 63, bwsel: 4,
bwsel : 4, crystal_as_ckin2: true,
crystal_as_ckin2: true
}; };
#[cfg(all(has_si5324, rtio_frequency = "100.0"))] #[cfg(all(has_si5324, rtio_frequency = "100.0"))]
const SI5324_SETTINGS: si5324::FrequencySettings const SI5324_SETTINGS: si5324::FrequencySettings = si5324::FrequencySettings {
= si5324::FrequencySettings { n1_hs: 5,
n1_hs : 5, nc1_ls: 10,
nc1_ls : 10, n2_hs: 10,
n2_hs : 10, n2_ls: 250,
n2_ls : 250, n31: 50,
n31 : 50, n32: 50,
n32 : 50, bwsel: 4,
bwsel : 4, crystal_as_ckin2: true,
crystal_as_ckin2: true
}; };
static mut LOG_BUFFER: [u8; 1<<17] = [0; 1<<17]; static mut LOG_BUFFER: [u8; 1 << 17] = [0; 1 << 17];
#[no_mangle] #[no_mangle]
pub extern fn main_core0() -> i32 { pub extern "C" fn main_core0() -> i32 {
enable_l2_cache(0x8); enable_l2_cache(0x8);
let mut timer = GlobalTimer::start(); let mut timer = GlobalTimer::start();
let buffer_logger = unsafe { let buffer_logger = unsafe { logger::BufferLogger::new(&mut LOG_BUFFER[..]) };
logger::BufferLogger::new(&mut LOG_BUFFER[..])
};
buffer_logger.set_uart_log_level(log::LevelFilter::Info); buffer_logger.set_uart_log_level(log::LevelFilter::Info);
buffer_logger.register(); buffer_logger.register();
log::set_max_level(log::LevelFilter::Info); log::set_max_level(log::LevelFilter::Info);
@ -491,7 +575,7 @@ pub extern fn main_core0() -> i32 {
let mut repeaters = [repeater::Repeater::default(); 0]; let mut repeaters = [repeater::Repeater::default(); 0];
for i in 0..repeaters.len() { for i in 0..repeaters.len() {
repeaters[i] = repeater::Repeater::new(i as u8); repeaters[i] = repeater::Repeater::new(i as u8);
} }
let mut routing_table = drtio_routing::RoutingTable::default_empty(); let mut routing_table = drtio_routing::RoutingTable::default_empty();
let mut rank = 1; let mut rank = 1;
@ -553,7 +637,7 @@ extern "C" {
} }
interrupt_handler!(IRQ, irq, __irq_stack0_start, __irq_stack1_start, { interrupt_handler!(IRQ, irq, __irq_stack0_start, __irq_stack1_start, {
if MPIDR.read().cpu_id() == 1{ if MPIDR.read().cpu_id() == 1 {
let mpcore = mpcore::RegisterBlock::mpcore(); let mpcore = mpcore::RegisterBlock::mpcore();
let mut gic = gic::InterruptController::gic(mpcore); let mut gic = gic::InterruptController::gic(mpcore);
let id = gic.get_interrupt_id(); let id = gic.get_interrupt_id();
@ -566,7 +650,7 @@ interrupt_handler!(IRQ, irq, __irq_stack0_start, __irq_stack1_start, {
notify_spin_lock(); notify_spin_lock();
main_core1(); main_core1();
} }
stdio::drop_uart(); stdio::drop_uart();
} }
loop {} loop {}
}); });
@ -593,18 +677,21 @@ pub fn main_core1() {
} }
#[no_mangle] #[no_mangle]
pub extern fn exception(_vect: u32, _regs: *const u32, pc: u32, ea: u32) { pub extern "C" fn exception(_vect: u32, _regs: *const u32, pc: u32, ea: u32) {
fn hexdump(addr: u32) { fn hexdump(addr: u32) {
let addr = (addr - addr % 4) as *const u32; let addr = (addr - addr % 4) as *const u32;
let mut ptr = addr; let mut ptr = addr;
println!("@ {:08p}", ptr); println!("@ {:08p}", ptr);
for _ in 0..4 { for _ in 0..4 {
print!("+{:04x}: ", ptr as usize - addr as usize); print!("+{:04x}: ", ptr as usize - addr as usize);
print!("{:08x} ", unsafe { *ptr }); ptr = ptr.wrapping_offset(1); print!("{:08x} ", unsafe { *ptr });
print!("{:08x} ", unsafe { *ptr }); ptr = ptr.wrapping_offset(1); ptr = ptr.wrapping_offset(1);
print!("{:08x} ", unsafe { *ptr }); ptr = ptr.wrapping_offset(1); print!("{:08x} ", unsafe { *ptr });
print!("{:08x}\n", unsafe { *ptr }); ptr = ptr.wrapping_offset(1); ptr = ptr.wrapping_offset(1);
print!("{:08x} ", unsafe { *ptr });
ptr = ptr.wrapping_offset(1);
print!("{:08x}\n", unsafe { *ptr });
ptr = ptr.wrapping_offset(1);
} }
} }
@ -654,7 +741,7 @@ extern "C" {
} }
#[no_mangle] #[no_mangle]
extern fn dl_unwind_find_exidx(_pc: *const u32, len_ptr: *mut u32) -> *const u32 { extern "C" fn dl_unwind_find_exidx(_pc: *const u32, len_ptr: *mut u32) -> *const u32 {
let length; let length;
let start: *const u32; let start: *const u32;
unsafe { unsafe {

View File

@ -1,19 +1,16 @@
use libboard_artiq::{drtioaux, drtio_routing};
use libboard_zynq::timer::GlobalTimer;
#[cfg(has_drtio_routing)]
use libboard_artiq::{pl::csr};
#[cfg(has_drtio_routing)]
use libboard_zynq::time::Milliseconds;
#[cfg(has_drtio_routing)] #[cfg(has_drtio_routing)]
use embedded_hal::prelude::_embedded_hal_blocking_delay_DelayUs; use embedded_hal::prelude::_embedded_hal_blocking_delay_DelayUs;
#[cfg(has_drtio_routing)]
use libboard_artiq::pl::csr;
use libboard_artiq::{drtio_routing, drtioaux};
#[cfg(has_drtio_routing)]
use libboard_zynq::time::Milliseconds;
use libboard_zynq::timer::GlobalTimer;
#[cfg(has_drtio_routing)] #[cfg(has_drtio_routing)]
fn rep_link_rx_up(repno: u8) -> bool { fn rep_link_rx_up(repno: u8) -> bool {
let repno = repno as usize; let repno = repno as usize;
unsafe { unsafe { (csr::DRTIOREP[repno].rx_up_read)() == 1 }
(csr::DRTIOREP[repno].rx_up_read)() == 1
}
} }
#[cfg(has_drtio_routing)] #[cfg(has_drtio_routing)]
@ -23,12 +20,14 @@ enum RepeaterState {
SendPing { ping_count: u16 }, SendPing { ping_count: u16 },
WaitPingReply { ping_count: u16, timeout: Milliseconds }, WaitPingReply { ping_count: u16, timeout: Milliseconds },
Up, Up,
Failed Failed,
} }
#[cfg(has_drtio_routing)] #[cfg(has_drtio_routing)]
impl Default for RepeaterState { impl Default for RepeaterState {
fn default() -> RepeaterState { RepeaterState::Down } fn default() -> RepeaterState {
RepeaterState::Down
}
} }
#[cfg(has_drtio_routing)] #[cfg(has_drtio_routing)]
@ -36,7 +35,7 @@ impl Default for RepeaterState {
pub struct Repeater { pub struct Repeater {
repno: u8, repno: u8,
auxno: u8, auxno: u8,
state: RepeaterState state: RepeaterState,
} }
#[cfg(has_drtio_routing)] #[cfg(has_drtio_routing)]
@ -45,7 +44,7 @@ impl Repeater {
Repeater { Repeater {
repno: repno, repno: repno,
auxno: repno + 1, auxno: repno + 1,
state: RepeaterState::Down state: RepeaterState::Down,
} }
} }
@ -54,8 +53,7 @@ impl Repeater {
self.state == RepeaterState::Up self.state == RepeaterState::Up
} }
pub fn service(&mut self, routing_table: &drtio_routing::RoutingTable, rank: u8, pub fn service(&mut self, routing_table: &drtio_routing::RoutingTable, rank: u8, timer: &mut GlobalTimer) {
timer: &mut GlobalTimer) {
self.process_local_errors(); self.process_local_errors();
match self.state { match self.state {
@ -70,7 +68,7 @@ impl Repeater {
drtioaux::send(self.auxno, &drtioaux::Packet::EchoRequest).unwrap(); drtioaux::send(self.auxno, &drtioaux::Packet::EchoRequest).unwrap();
self.state = RepeaterState::WaitPingReply { self.state = RepeaterState::WaitPingReply {
ping_count: ping_count + 1, ping_count: ping_count + 1,
timeout: timer.get_time() + Milliseconds(100) timeout: timer.get_time() + Milliseconds(100),
} }
} else { } else {
error!("[REP#{}] link RX went down during ping", self.repno); error!("[REP#{}] link RX went down during ping", self.repno);
@ -132,7 +130,7 @@ impl Repeater {
match drtioaux::recv(self.auxno) { match drtioaux::recv(self.auxno) {
Ok(Some(packet)) => warn!("[REP#{}] unsolicited aux packet: {:?}", self.repno, packet), Ok(Some(packet)) => warn!("[REP#{}] unsolicited aux packet: {:?}", self.repno, packet),
Ok(None) => (), Ok(None) => (),
Err(_) => warn!("[REP#{}] aux packet error", self.repno) Err(_) => warn!("[REP#{}] aux packet error", self.repno),
} }
} }
@ -155,14 +153,20 @@ impl Repeater {
cmd = (csr::DRTIOREP[repno].command_missed_cmd_read)(); cmd = (csr::DRTIOREP[repno].command_missed_cmd_read)();
chan_sel = (csr::DRTIOREP[repno].command_missed_chan_sel_read)(); chan_sel = (csr::DRTIOREP[repno].command_missed_chan_sel_read)();
} }
error!("[REP#{}] CRI command missed, cmd={}, chan_sel=0x{:06x}", repno, cmd, chan_sel) error!(
"[REP#{}] CRI command missed, cmd={}, chan_sel=0x{:06x}",
repno, cmd, chan_sel
)
} }
if errors & 8 != 0 { if errors & 8 != 0 {
let destination; let destination;
unsafe { unsafe {
destination = (csr::DRTIOREP[repno].buffer_space_timeout_dest_read)(); destination = (csr::DRTIOREP[repno].buffer_space_timeout_dest_read)();
} }
error!("[REP#{}] timeout attempting to get remote buffer space, destination=0x{:02x}", repno, destination); error!(
"[REP#{}] timeout attempting to get remote buffer space, destination=0x{:02x}",
repno, destination
);
} }
unsafe { unsafe {
(csr::DRTIOREP[repno].protocol_error_write)(errors); (csr::DRTIOREP[repno].protocol_error_write)(errors);
@ -181,7 +185,7 @@ impl Repeater {
match drtioaux::recv(self.auxno) { match drtioaux::recv(self.auxno) {
Ok(Some(packet)) => return Ok(packet), Ok(Some(packet)) => return Ok(packet),
Ok(None) => (), Ok(None) => (),
Err(e) => return Err(e) Err(e) => return Err(e),
} }
} }
} }
@ -217,15 +221,24 @@ impl Repeater {
} }
} }
pub fn set_path(&self, destination: u8, hops: &[u8; drtio_routing::MAX_HOPS], timer: &mut GlobalTimer) -> Result<(), drtioaux::Error> { pub fn set_path(
&self,
destination: u8,
hops: &[u8; drtio_routing::MAX_HOPS],
timer: &mut GlobalTimer,
) -> Result<(), drtioaux::Error> {
if self.state != RepeaterState::Up { if self.state != RepeaterState::Up {
return Ok(()); return Ok(());
} }
drtioaux::send(self.auxno, &drtioaux::Packet::RoutingSetPath { drtioaux::send(
destination: destination, self.auxno,
hops: *hops &drtioaux::Packet::RoutingSetPath {
}).unwrap(); destination: destination,
hops: *hops,
},
)
.unwrap();
let reply = self.recv_aux_timeout(200, timer)?; let reply = self.recv_aux_timeout(200, timer)?;
if reply != drtioaux::Packet::RoutingAck { if reply != drtioaux::Packet::RoutingAck {
return Err(drtioaux::Error::UnexpectedReply); return Err(drtioaux::Error::UnexpectedReply);
@ -233,7 +246,11 @@ impl Repeater {
Ok(()) Ok(())
} }
pub fn load_routing_table(&self, routing_table: &drtio_routing::RoutingTable, timer: &mut GlobalTimer) -> Result<(), drtioaux::Error> { pub fn load_routing_table(
&self,
routing_table: &drtio_routing::RoutingTable,
timer: &mut GlobalTimer,
) -> Result<(), drtioaux::Error> {
for i in 0..drtio_routing::DEST_COUNT { for i in 0..drtio_routing::DEST_COUNT {
self.set_path(i as u8, &routing_table.0[i], timer)?; self.set_path(i as u8, &routing_table.0[i], timer)?;
} }
@ -244,9 +261,7 @@ impl Repeater {
if self.state != RepeaterState::Up { if self.state != RepeaterState::Up {
return Ok(()); return Ok(());
} }
drtioaux::send(self.auxno, &drtioaux::Packet::RoutingSetRank { drtioaux::send(self.auxno, &drtioaux::Packet::RoutingSetRank { rank: rank }).unwrap();
rank: rank
}).unwrap();
let reply = self.recv_aux_timeout(200, timer)?; let reply = self.recv_aux_timeout(200, timer)?;
if reply != drtioaux::Packet::RoutingAck { if reply != drtioaux::Packet::RoutingAck {
return Err(drtioaux::Error::UnexpectedReply); return Err(drtioaux::Error::UnexpectedReply);
@ -256,9 +271,13 @@ impl Repeater {
pub fn rtio_reset(&self, timer: &mut GlobalTimer) -> Result<(), drtioaux::Error> { pub fn rtio_reset(&self, timer: &mut GlobalTimer) -> Result<(), drtioaux::Error> {
let repno = self.repno as usize; let repno = self.repno as usize;
unsafe { (csr::DRTIOREP[repno].reset_write)(1); } unsafe {
(csr::DRTIOREP[repno].reset_write)(1);
}
timer.delay_us(100); timer.delay_us(100);
unsafe { (csr::DRTIOREP[repno].reset_write)(0); } unsafe {
(csr::DRTIOREP[repno].reset_write)(0);
}
if self.state != RepeaterState::Up { if self.state != RepeaterState::Up {
return Ok(()); return Ok(());
@ -275,16 +294,21 @@ impl Repeater {
#[cfg(not(has_drtio_routing))] #[cfg(not(has_drtio_routing))]
#[derive(Clone, Copy, Default)] #[derive(Clone, Copy, Default)]
pub struct Repeater { pub struct Repeater {}
}
#[cfg(not(has_drtio_routing))] #[cfg(not(has_drtio_routing))]
impl Repeater { impl Repeater {
pub fn new(_repno: u8) -> Repeater { Repeater::default() } pub fn new(_repno: u8) -> Repeater {
Repeater::default()
}
pub fn service(&self, _routing_table: &drtio_routing::RoutingTable, _rank: u8, _timer: &mut GlobalTimer) { } pub fn service(&self, _routing_table: &drtio_routing::RoutingTable, _rank: u8, _timer: &mut GlobalTimer) {}
pub fn sync_tsc(&self, _timer: &mut GlobalTimer) -> Result<(), drtioaux::Error> { Ok(()) } pub fn sync_tsc(&self, _timer: &mut GlobalTimer) -> Result<(), drtioaux::Error> {
Ok(())
}
pub fn rtio_reset(&self, _timer: &mut GlobalTimer) -> Result<(), drtioaux::Error> { Ok(()) } pub fn rtio_reset(&self, _timer: &mut GlobalTimer) -> Result<(), drtioaux::Error> {
Ok(())
}
} }