2
0
mirror of https://github.com/m-labs/artiq.git synced 2024-12-25 03:08:27 +08:00

drtio: initial firmware support for multi-link

This commit is contained in:
Sebastien Bourdeauducq 2017-07-18 00:40:21 +08:00
parent 94ee48860a
commit 9045b4cc19
11 changed files with 407 additions and 329 deletions

View File

@ -1,3 +1,9 @@
"""
DRTIO debugging functions.
Those syscalls are intended for ARTIQ developers only.
"""
from artiq.language.core import syscall
from artiq.language.types import TTuple, TInt32, TInt64, TNone
@ -18,9 +24,9 @@ def drtio_get_fifo_space(channel: TInt32) -> TNone:
@syscall(flags={"nounwind", "nowrite"})
def drtio_get_packet_counts() -> TTuple([TInt32, TInt32]):
def drtio_get_packet_counts(linkno: TInt32) -> TTuple([TInt32, TInt32]):
raise NotImplementedError("syscall not simulated")
@syscall(flags={"nounwind", "nowrite"})
def drtio_get_fifo_space_req_count() -> TInt32:
def drtio_get_fifo_space_req_count(linkno: TInt32) -> TInt32:
raise NotImplementedError("syscall not simulated")

View File

@ -182,14 +182,14 @@ pub mod drtio_dbg {
#[repr(C)]
pub struct PacketCounts(i32, i32);
pub extern fn get_packet_counts() -> PacketCounts {
send(&DrtioPacketCountRequest);
pub extern fn get_packet_counts(linkno: i32) -> PacketCounts {
send(&DrtioPacketCountRequest { linkno: linkno as u8 });
recv!(&DrtioPacketCountReply { tx_cnt, rx_cnt }
=> PacketCounts(tx_cnt as i32, rx_cnt as i32))
}
pub extern fn get_fifo_space_req_count() -> i32 {
send(&DrtioFifoSpaceReqCountRequest);
pub extern fn get_fifo_space_req_count(linkno: i32) -> i32 {
send(&DrtioFifoSpaceReqCountRequest { linkno: linkno as u8 });
recv!(&DrtioFifoSpaceReqCountReply { cnt }
=> cnt as i32)
}

View File

@ -252,50 +252,49 @@ pub mod hw {
use super::*;
use std::io::Cursor;
const AUX_TX_BASE: usize = board::mem::DRTIO_AUX_BASE;
const AUX_TX_SIZE: usize = board::mem::DRTIO_AUX_SIZE/2;
const AUX_RX_BASE: usize = AUX_TX_BASE + AUX_TX_SIZE;
fn rx_has_error() -> bool {
fn rx_has_error(linkno: u8) -> bool {
let linkno = linkno as usize;
unsafe {
let error = board::csr::drtio::aux_rx_error_read() != 0;
let error = (board::csr::DRTIO[linkno].aux_rx_error_read)() != 0;
if error {
board::csr::drtio::aux_rx_error_write(1)
(board::csr::DRTIO[linkno].aux_rx_error_write)(1)
}
error
}
}
struct RxBuffer(&'static [u8]);
struct RxBuffer(u8, &'static [u8]);
impl Drop for RxBuffer {
fn drop(&mut self) {
unsafe {
board::csr::drtio::aux_rx_present_write(1);
(board::csr::DRTIO[self.0 as usize].aux_rx_present_write)(1);
}
}
}
fn rx_get_buffer() -> Option<RxBuffer> {
fn rx_get_buffer(linkno: u8) -> Option<RxBuffer> {
let linkidx = linkno as usize;
unsafe {
if board::csr::drtio::aux_rx_present_read() == 1 {
let length = board::csr::drtio::aux_rx_length_read();
let sl = slice::from_raw_parts(AUX_RX_BASE as *mut u8, length as usize);
Some(RxBuffer(sl))
if (board::csr::DRTIO[linkidx].aux_rx_present_read)() == 1 {
let length = (board::csr::DRTIO[linkidx].aux_rx_length_read)();
let base = board::mem::DRTIO_AUX[linkidx].base + board::mem::DRTIO_AUX[linkidx].size/2;
let sl = slice::from_raw_parts(base as *mut u8, length as usize);
Some(RxBuffer(linkno, sl))
} else {
None
}
}
}
pub fn recv() -> io::Result<Option<Packet>> {
if rx_has_error() {
pub fn recv_link(linkno: u8) -> io::Result<Option<Packet>> {
if rx_has_error(linkno) {
return Err(io::Error::new(io::ErrorKind::Other, "gateware reported error"))
}
let buffer = rx_get_buffer();
let buffer = rx_get_buffer(linkno);
match buffer {
Some(rxb) => {
let slice = rxb.0;
let slice = rxb.1;
let mut reader = Cursor::new(slice);
let len = slice.len();
@ -320,11 +319,11 @@ pub mod hw {
}
}
pub fn recv_timeout(timeout_ms: Option<u64>) -> io::Result<Packet> {
pub fn recv_timeout_link(linkno: u8, timeout_ms: Option<u64>) -> io::Result<Packet> {
let timeout_ms = timeout_ms.unwrap_or(10);
let limit = board::clock::get_ms() + timeout_ms;
while board::clock::get_ms() < limit {
match recv() {
match recv_link(linkno) {
Ok(None) => (),
Ok(Some(packet)) => return Ok(packet),
Err(e) => return Err(e)
@ -333,22 +332,26 @@ pub mod hw {
return Err(io::Error::new(io::ErrorKind::TimedOut, "timed out waiting for data"))
}
fn tx_get_buffer() -> &'static mut [u8] {
fn tx_get_buffer(linkno: u8) -> &'static mut [u8] {
let linkno = linkno as usize;
unsafe {
while board::csr::drtio::aux_tx_read() != 0 {}
slice::from_raw_parts_mut(AUX_TX_BASE as *mut u8, AUX_TX_SIZE)
while (board::csr::DRTIO[linkno].aux_tx_read)() != 0 {}
let base = board::mem::DRTIO_AUX[linkno].base;
let size = board::mem::DRTIO_AUX[linkno].size/2;
slice::from_raw_parts_mut(base as *mut u8, size)
}
}
fn tx_ack_buffer(length: u16) {
fn tx_ack_buffer(linkno: u8, length: u16) {
let linkno = linkno as usize;
unsafe {
board::csr::drtio::aux_tx_length_write(length);
board::csr::drtio::aux_tx_write(1)
(board::csr::DRTIO[linkno].aux_tx_length_write)(length);
(board::csr::DRTIO[linkno].aux_tx_write)(1)
}
}
pub fn send(packet: &Packet) -> io::Result<()> {
let sl = tx_get_buffer();
pub fn send_link(linkno: u8, packet: &Packet) -> io::Result<()> {
let sl = tx_get_buffer(linkno);
let mut writer = Cursor::new(sl);
packet.write_to(&mut writer)?;
@ -366,8 +369,31 @@ pub mod hw {
write_u32(&mut writer, crc)?;
len += 4;
tx_ack_buffer(len as u16);
tx_ack_buffer(linkno, len as u16);
Ok(())
}
// TODO: routing
fn get_linkno(nodeno: u8) -> io::Result<u8> {
if nodeno == 0 || nodeno as usize > board::csr::DRTIO.len() {
return Err(io::Error::new(io::ErrorKind::NotFound, "invalid node number"))
}
Ok(nodeno - 1)
}
pub fn recv(nodeno: u8) -> io::Result<Option<Packet>> {
let linkno = get_linkno(nodeno)?;
recv_link(linkno)
}
pub fn recv_timeout(nodeno: u8, timeout_ms: Option<u64>) -> io::Result<Packet> {
let linkno = get_linkno(nodeno)?;
recv_timeout_link(linkno, timeout_ms)
}
pub fn send(nodeno: u8, packet: &Packet) -> io::Result<()> {
let linkno = get_linkno(nodeno)?;
send_link(linkno, packet)
}
}

View File

@ -50,9 +50,9 @@ pub enum Message<'a> {
DrtioChannelStateReply { fifo_space: u16, last_timestamp: u64 },
DrtioResetChannelStateRequest { channel: u32 },
DrtioGetFifoSpaceRequest { channel: u32 },
DrtioPacketCountRequest,
DrtioPacketCountRequest { linkno: u8 },
DrtioPacketCountReply { tx_cnt: u32, rx_cnt: u32 },
DrtioFifoSpaceReqCountRequest,
DrtioFifoSpaceReqCountRequest { linkno: u8 },
DrtioFifoSpaceReqCountReply { cnt: u32 },
RunFinished,

View File

@ -8,8 +8,8 @@ use sched::Io;
mod drtio_i2c {
use drtioaux;
fn basic_reply() -> Result<(), ()> {
match drtioaux::hw::recv_timeout(None) {
fn basic_reply(nodeno: u8) -> Result<(), ()> {
match drtioaux::hw::recv_timeout(nodeno, None) {
Ok(drtioaux::Packet::I2cBasicReply { succeeded }) => {
if succeeded { Ok(()) } else { Err(()) }
}
@ -24,31 +24,39 @@ mod drtio_i2c {
}
}
pub fn start(busno: u32) -> Result<(), ()> {
let request = drtioaux::Packet::I2cStartRequest { busno: busno as u8 };
drtioaux::hw::send(&request).unwrap();
basic_reply()
pub fn start(nodeno: u8, busno: u8) -> Result<(), ()> {
let request = drtioaux::Packet::I2cStartRequest { busno: busno };
if drtioaux::hw::send(nodeno, &request).is_err() {
return Err(())
}
basic_reply(nodeno)
}
pub fn restart(busno: u32) -> Result<(), ()> {
let request = drtioaux::Packet::I2cRestartRequest { busno: busno as u8 };
drtioaux::hw::send(&request).unwrap();
basic_reply()
pub fn restart(nodeno: u8, busno: u8) -> Result<(), ()> {
let request = drtioaux::Packet::I2cRestartRequest { busno: busno };
if drtioaux::hw::send(nodeno, &request).is_err() {
return Err(())
}
basic_reply(nodeno)
}
pub fn stop(busno: u32) -> Result<(), ()> {
let request = drtioaux::Packet::I2cStopRequest { busno: busno as u8 };
drtioaux::hw::send(&request).unwrap();
basic_reply()
pub fn stop(nodeno: u8, busno: u8) -> Result<(), ()> {
let request = drtioaux::Packet::I2cStopRequest { busno: busno };
if drtioaux::hw::send(nodeno, &request).is_err() {
return Err(())
}
basic_reply(nodeno)
}
pub fn write(busno: u32, data: u8) -> Result<bool, ()> {
pub fn write(nodeno: u8, busno: u8, data: u8) -> Result<bool, ()> {
let request = drtioaux::Packet::I2cWriteRequest {
busno: busno as u8,
busno: busno,
data: data
};
drtioaux::hw::send(&request).unwrap();
match drtioaux::hw::recv_timeout(None) {
if drtioaux::hw::send(nodeno, &request).is_err() {
return Err(())
}
match drtioaux::hw::recv_timeout(nodeno, None) {
Ok(drtioaux::Packet::I2cWriteReply { succeeded, ack }) => {
if succeeded { Ok(ack) } else { Err(()) }
}
@ -63,13 +71,15 @@ mod drtio_i2c {
}
}
pub fn read(busno: u32, ack: bool) -> Result<u8, ()> {
pub fn read(nodeno: u8, busno: u8, ack: bool) -> Result<u8, ()> {
let request = drtioaux::Packet::I2cReadRequest {
busno: busno as u8,
busno: busno,
ack: ack
};
drtioaux::hw::send(&request).unwrap();
match drtioaux::hw::recv_timeout(None) {
if drtioaux::hw::send(nodeno, &request).is_err() {
return Err(())
}
match drtioaux::hw::recv_timeout(nodeno, None) {
Ok(drtioaux::Packet::I2cReadReply { succeeded, data }) => {
if succeeded { Ok(data) } else { Err(()) }
}
@ -87,23 +97,23 @@ mod drtio_i2c {
#[cfg(not(has_drtio))]
mod drtio_i2c {
pub fn start(_busno: u32) -> Result<(), ()> {
pub fn start(_nodeno: u8, _busno: u8) -> Result<(), ()> {
Err(())
}
pub fn restart(_busno: u32) -> Result<(), ()> {
pub fn restart(_nodeno: u8, _busno: u8) -> Result<(), ()> {
Err(())
}
pub fn stop(_busno: u32) -> Result<(), ()> {
pub fn stop(_nodeno: u8, _busno: u8) -> Result<(), ()> {
Err(())
}
pub fn write(_busno: u32, _data: u8) -> Result<bool, ()> {
pub fn write(_nodeno: u8, _busno: u8, _data: u8) -> Result<bool, ()> {
Err(())
}
pub fn read(_busno: u32, _ack: bool) -> Result<u8, ()> {
pub fn read(_nodeno: u8, _busno: u8, _ack: bool) -> Result<u8, ()> {
Err(())
}
}
@ -113,52 +123,52 @@ mod i2c {
use super::drtio_i2c;
pub fn start(busno: u32) -> Result<(), ()> {
let drtio = busno >> 16;
let dev_busno = busno as u8;
if drtio == 0 {
board::i2c::start(dev_busno)
let nodeno = (busno >> 16) as u8;
let node_busno = busno as u8;
if nodeno == 0 {
board::i2c::start(node_busno)
} else {
drtio_i2c::start(busno)
drtio_i2c::start(nodeno, node_busno)
}
}
pub fn restart(busno: u32) -> Result<(), ()> {
let drtio = busno >> 16;
let dev_busno = busno as u8;
if drtio == 0 {
board::i2c::restart(dev_busno)
let nodeno = (busno >> 16) as u8;
let node_busno = busno as u8;
if nodeno == 0 {
board::i2c::restart(node_busno)
} else {
drtio_i2c::restart(busno)
drtio_i2c::restart(nodeno, node_busno)
}
}
pub fn stop(busno: u32) -> Result<(), ()> {
let drtio = busno >> 16;
let dev_busno = busno as u8;
if drtio == 0 {
board::i2c::stop(dev_busno)
let nodeno = (busno >> 16) as u8;
let node_busno = busno as u8;
if nodeno == 0 {
board::i2c::stop(node_busno)
} else {
drtio_i2c::stop(busno)
drtio_i2c::stop(nodeno, node_busno)
}
}
pub fn write(busno: u32, data: u8) -> Result<bool, ()> {
let drtio = busno >> 16;
let dev_busno = busno as u8;
if drtio == 0 {
board::i2c::write(dev_busno, data)
let nodeno = (busno >> 16 )as u8;
let node_busno = busno as u8;
if nodeno == 0 {
board::i2c::write(node_busno, data)
} else {
drtio_i2c::write(busno, data)
drtio_i2c::write(nodeno, node_busno, data)
}
}
pub fn read(busno: u32, ack: bool) -> Result<u8, ()> {
let drtio = busno >> 16;
let dev_busno = busno as u8;
if drtio == 0 {
board::i2c::read(dev_busno, ack)
let nodeno = (busno >> 16) as u8;
let node_busno = busno as u8;
if nodeno == 0 {
board::i2c::read(node_busno, ack)
} else {
drtio_i2c::read(busno, ack)
drtio_i2c::read(nodeno, node_busno, ack)
}
}
}
@ -167,8 +177,8 @@ mod i2c {
mod drtio_spi {
use drtioaux;
fn basic_reply() -> Result<(), ()> {
match drtioaux::hw::recv_timeout(None) {
fn basic_reply(nodeno: u8) -> Result<(), ()> {
match drtioaux::hw::recv_timeout(nodeno, None) {
Ok(drtioaux::Packet::SpiBasicReply { succeeded }) => {
if succeeded { Ok(()) } else { Err(()) }
}
@ -183,41 +193,49 @@ mod drtio_spi {
}
}
pub fn set_config(busno: u32, flags: u8, write_div: u8, read_div: u8) -> Result<(), ()> {
pub fn set_config(nodeno: u8, busno: u8, flags: u8, write_div: u8, read_div: u8) -> Result<(), ()> {
let request = drtioaux::Packet::SpiSetConfigRequest {
busno: busno as u8,
busno: busno,
flags: flags,
write_div: write_div,
read_div: read_div
};
drtioaux::hw::send(&request).unwrap();
basic_reply()
if drtioaux::hw::send(nodeno, &request).is_err() {
return Err(())
}
basic_reply(nodeno)
}
pub fn set_xfer(busno: u32, chip_select: u16, write_length: u8, read_length: u8) -> Result<(), ()> {
pub fn set_xfer(nodeno: u8, busno: u8, chip_select: u16, write_length: u8, read_length: u8) -> Result<(), ()> {
let request = drtioaux::Packet::SpiSetXferRequest {
busno: busno as u8,
busno: busno,
chip_select: chip_select,
write_length: write_length,
read_length: read_length
};
drtioaux::hw::send(&request).unwrap();
basic_reply()
if drtioaux::hw::send(nodeno, &request).is_err() {
return Err(())
}
basic_reply(nodeno)
}
pub fn write(busno: u32, data: u32) -> Result<(), ()> {
pub fn write(nodeno: u8, busno: u8, data: u32) -> Result<(), ()> {
let request = drtioaux::Packet::SpiWriteRequest {
busno: busno as u8,
busno: busno,
data: data
};
drtioaux::hw::send(&request).unwrap();
basic_reply()
if drtioaux::hw::send(nodeno, &request).is_err() {
return Err(())
}
basic_reply(nodeno)
}
pub fn read(busno: u32) -> Result<u32, ()> {
let request = drtioaux::Packet::SpiReadRequest { busno: busno as u8 };
drtioaux::hw::send(&request).unwrap();
match drtioaux::hw::recv_timeout(None) {
pub fn read(nodeno: u8, busno: u8) -> Result<u32, ()> {
let request = drtioaux::Packet::SpiReadRequest { busno: busno };
if drtioaux::hw::send(nodeno, &request).is_err() {
return Err(())
}
match drtioaux::hw::recv_timeout(nodeno, None) {
Ok(drtioaux::Packet::SpiReadReply { succeeded, data }) => {
if succeeded { Ok(data) } else { Err(()) }
}
@ -235,19 +253,19 @@ mod drtio_spi {
#[cfg(not(has_drtio))]
mod drtio_spi {
pub fn set_config(_busno: u32, _flags: u8, _write_div: u8, _read_div: u8) -> Result<(), ()> {
pub fn set_config(_nodeno: u8, _busno: u8, _flags: u8, _write_div: u8, _read_div: u8) -> Result<(), ()> {
Err(())
}
pub fn set_xfer(_busno: u32, _chip_select: u16, _write_length: u8, _read_length: u8) -> Result<(), ()> {
pub fn set_xfer(_nodeno: u8, _busno: u8, _chip_select: u16, _write_length: u8, _read_length: u8) -> Result<(), ()> {
Err(())
}
pub fn write(_busno: u32, _data: u32) -> Result<(), ()> {
pub fn write(_nodeno: u8, _busno: u8, _data: u32) -> Result<(), ()> {
Err(())
}
pub fn read(_busno: u32) -> Result<u32, ()> {
pub fn read(_nodeno: u8, _busno: u8) -> Result<u32, ()> {
Err(())
}
}
@ -257,42 +275,42 @@ mod spi {
use super::drtio_spi;
pub fn set_config(busno: u32, flags: u8, write_div: u8, read_div: u8) -> Result<(), ()> {
let drtio = busno >> 16;
let dev_busno = busno as u8;
if drtio == 0 {
board::spi::set_config(dev_busno, flags, write_div, read_div)
let nodeno = (busno >> 16) as u8;
let node_busno = busno as u8;
if nodeno == 0 {
board::spi::set_config(node_busno, flags, write_div, read_div)
} else {
drtio_spi::set_config(busno, flags, write_div, read_div)
drtio_spi::set_config(nodeno, node_busno, flags, write_div, read_div)
}
}
pub fn set_xfer(busno: u32, chip_select: u16, write_length: u8, read_length: u8) -> Result<(), ()> {
let drtio = busno >> 16;
let dev_busno = busno as u8;
if drtio == 0 {
board::spi::set_xfer(dev_busno, chip_select, write_length, read_length)
let nodeno = (busno >> 16) as u8;
let node_busno = busno as u8;
if nodeno == 0 {
board::spi::set_xfer(node_busno, chip_select, write_length, read_length)
} else {
drtio_spi::set_xfer(busno, chip_select, write_length, read_length)
drtio_spi::set_xfer(nodeno, node_busno, chip_select, write_length, read_length)
}
}
pub fn write(busno: u32, data: u32) -> Result<(), ()> {
let drtio = busno >> 16;
let dev_busno = busno as u8;
if drtio == 0 {
board::spi::write(dev_busno, data)
let nodeno = (busno >> 16) as u8;
let node_busno = busno as u8;
if nodeno == 0 {
board::spi::write(node_busno, data)
} else {
drtio_spi::write(busno, data)
drtio_spi::write(nodeno, node_busno, data)
}
}
pub fn read(busno: u32) -> Result<u32, ()> {
let drtio = busno >> 16;
let dev_busno = busno as u8;
if drtio == 0 {
board::spi::read(dev_busno)
let nodeno = (busno >> 16) as u8;
let node_busno = busno as u8;
if nodeno == 0 {
board::spi::read(node_busno)
} else {
drtio_spi::read(busno)
drtio_spi::read(nodeno, node_busno)
}
}
}
@ -318,12 +336,12 @@ pub fn process_kern_hwreq(io: &Io, request: &kern::Message) -> io::Result<bool>
rtio_mgt::drtio_dbg::get_fifo_space(channel);
kern_acknowledge()
}
&kern::DrtioPacketCountRequest => {
let (tx_cnt, rx_cnt) = rtio_mgt::drtio_dbg::get_packet_counts();
&kern::DrtioPacketCountRequest { linkno } => {
let (tx_cnt, rx_cnt) = rtio_mgt::drtio_dbg::get_packet_counts(linkno);
kern_send(io, &kern::DrtioPacketCountReply { tx_cnt: tx_cnt, rx_cnt: rx_cnt })
}
&kern::DrtioFifoSpaceReqCountRequest => {
let cnt = rtio_mgt::drtio_dbg::get_fifo_space_req_count();
&kern::DrtioFifoSpaceReqCountRequest { linkno } => {
let cnt = rtio_mgt::drtio_dbg::get_fifo_space_req_count(linkno);
kern_send(io, &kern::DrtioFifoSpaceReqCountReply { cnt: cnt })
}

View File

@ -6,8 +6,6 @@ use sched::{TcpListener, TcpStream};
use board::{clock, csr};
#[cfg(has_drtio)]
use drtioaux;
#[cfg(has_drtio)]
use rtio_mgt;
use moninj_proto::*;
@ -35,32 +33,36 @@ fn read_probe_local(channel: u16, probe: u8) -> u32 {
}
#[cfg(has_drtio)]
fn read_probe_drtio(channel: u16, probe: u8) -> u32 {
if rtio_mgt::drtio::link_is_running() {
let request = drtioaux::Packet::MonitorRequest { channel: channel, probe: probe };
drtioaux::hw::send(&request).unwrap();
match drtioaux::hw::recv_timeout(None) {
Ok(drtioaux::Packet::MonitorReply { value }) => return value,
Ok(_) => error!("received unexpected aux packet"),
Err(e) => error!("aux packet error ({})", e)
fn read_probe_drtio(nodeno: u8, channel: u16, probe: u8) -> u32 {
let request = drtioaux::Packet::MonitorRequest { channel: channel, probe: probe };
match drtioaux::hw::send(nodeno, &request) {
Ok(_) => (),
Err(e) => {
error!("aux packet error ({})", e);
return 0;
}
0
} else {
0
}
match drtioaux::hw::recv_timeout(nodeno, None) {
Ok(drtioaux::Packet::MonitorReply { value }) => return value,
Ok(_) => error!("received unexpected aux packet"),
Err(e) => error!("aux packet error ({})", e)
}
0
}
fn read_probe(channel: u32, probe: u8) -> u32 {
let nodeno = (channel >> 16) as u8;
let node_channel = channel as u16;
#[cfg(has_rtio_moninj)]
{
if channel & 0xff0000 == 0 {
return read_probe_local(channel as u16, probe)
if nodeno == 0 {
return read_probe_local(node_channel, probe)
}
}
#[cfg(has_drtio)]
{
if channel & 0xff0000 != 0 {
return read_probe_drtio(channel as u16, probe)
if nodeno != 0 {
return read_probe_drtio(nodeno, node_channel, probe)
}
}
error!("read_probe: unrecognized channel number {}", channel);
@ -77,29 +79,32 @@ fn inject_local(channel: u16, overrd: u8, value: u8) {
}
#[cfg(has_drtio)]
fn inject_drtio(channel: u16, overrd: u8, value: u8) {
if rtio_mgt::drtio::link_is_running() {
let request = drtioaux::Packet::InjectionRequest {
channel: channel,
overrd: overrd,
value: value
};
drtioaux::hw::send(&request).unwrap();
fn inject_drtio(nodeno: u8, channel: u16, overrd: u8, value: u8) {
let request = drtioaux::Packet::InjectionRequest {
channel: channel,
overrd: overrd,
value: value
};
match drtioaux::hw::send(nodeno, &request) {
Ok(_) => (),
Err(e) => error!("aux packet error ({})", e)
}
}
fn inject(channel: u32, overrd: u8, value: u8) {
let nodeno = (channel >> 16) as u8;
let node_channel = channel as u16;
#[cfg(has_rtio_moninj)]
{
if channel & 0xff0000 == 0 {
inject_local(channel as u16, overrd, value);
if nodeno == 0 {
inject_local(node_channel, overrd, value);
return
}
}
#[cfg(has_drtio)]
{
if channel & 0xff0000 != 0 {
inject_drtio(channel as u16, overrd, value);
if nodeno != 0 {
inject_drtio(nodeno, node_channel, overrd, value);
return
}
}
@ -116,35 +121,39 @@ fn read_injection_status_local(channel: u16, overrd: u8) -> u8 {
}
#[cfg(has_drtio)]
fn read_injection_status_drtio(channel: u16, overrd: u8) -> u8 {
if rtio_mgt::drtio::link_is_running() {
let request = drtioaux::Packet::InjectionStatusRequest {
channel: channel,
overrd: overrd
};
drtioaux::hw::send(&request).unwrap();
match drtioaux::hw::recv_timeout(None) {
Ok(drtioaux::Packet::InjectionStatusReply { value }) => return value,
Ok(_) => error!("received unexpected aux packet"),
Err(e) => error!("aux packet error ({})", e)
fn read_injection_status_drtio(nodeno: u8, channel: u16, overrd: u8) -> u8 {
let request = drtioaux::Packet::InjectionStatusRequest {
channel: channel,
overrd: overrd
};
match drtioaux::hw::send(nodeno, &request) {
Ok(_) => (),
Err(e) => {
error!("aux packet error ({})", e);
return 0;
}
0
} else {
0
}
match drtioaux::hw::recv_timeout(nodeno, None) {
Ok(drtioaux::Packet::InjectionStatusReply { value }) => return value,
Ok(_) => error!("received unexpected aux packet"),
Err(e) => error!("aux packet error ({})", e)
}
0
}
fn read_injection_status(channel: u32, probe: u8) -> u8 {
let nodeno = (channel >> 16) as u8;
let node_channel = channel as u16;
#[cfg(has_rtio_moninj)]
{
if channel & 0xff0000 == 0 {
return read_injection_status_local(channel as u16, probe)
if nodeno == 0 {
return read_injection_status_local(node_channel, probe)
}
}
#[cfg(has_drtio)]
{
if channel & 0xff0000 != 0 {
return read_injection_status_drtio(channel as u16, probe)
if nodeno != 0 {
return read_injection_status_drtio(nodeno, node_channel, probe)
}
}
error!("read_injection_status: unrecognized channel number {}", channel);

View File

@ -43,80 +43,70 @@ pub mod drtio {
pub fn startup(io: &Io) {
io.spawn(4096, link_thread);
io.spawn(4096, local_error_thread);
io.spawn(4096, aux_error_thread);
}
static mut LINK_RUNNING: bool = false;
fn link_set_running(running: bool) {
fn link_rx_up(linkno: u8) -> bool {
let linkno = linkno as usize;
unsafe {
LINK_RUNNING = running
(csr::DRTIO[linkno].link_status_read)() == 1
}
}
pub fn link_is_running() -> bool {
fn reset_phy(linkno: u8) {
let linkno = linkno as usize;
unsafe {
LINK_RUNNING
(csr::DRTIO[linkno].reset_phy_write)(1);
while (csr::DRTIO[linkno].o_wait_read)() == 1 {}
}
}
fn link_is_up() -> bool {
fn sync_tsc(linkno: u8) {
let linkno = linkno as usize;
unsafe {
csr::drtio::link_status_read() == 1
(csr::DRTIO[linkno].set_time_write)(1);
while (csr::DRTIO[linkno].set_time_read)() == 1 {}
}
}
fn reset_phy() {
fn init_link(linkno: u8) {
let linkidx = linkno as usize;
unsafe {
csr::drtio::reset_phy_write(1);
while csr::drtio::o_wait_read() == 1 {}
(csr::DRTIO[linkidx].reset_write)(1);
while (csr::DRTIO[linkidx].o_wait_read)() == 1 {}
}
}
// TODO: determine actual number of remote FIFOs
for channel in 0..16 {
unsafe {
(csr::DRTIO[linkidx].chan_sel_override_write)(channel);
(csr::DRTIO[linkidx].chan_sel_override_en_write)(1);
fn sync_tsc() {
unsafe {
csr::drtio::set_time_write(1);
while csr::drtio::set_time_read() == 1 {}
}
}
(csr::DRTIO[linkidx].o_reset_channel_status_write)(1);
(csr::DRTIO[linkidx].o_get_fifo_space_write)(1);
while (csr::DRTIO[linkidx].o_wait_read)() == 1 {}
info!("[LINK#{}] FIFO space on channel {} is {}",
linkno, channel, (csr::DRTIO[linkidx].o_dbg_fifo_space_read)());
fn init_channel(channel: u16) {
unsafe {
csr::drtio::chan_sel_override_write(channel);
csr::drtio::chan_sel_override_en_write(1);
csr::drtio::o_reset_channel_status_write(1);
csr::drtio::o_get_fifo_space_write(1);
while csr::drtio::o_wait_read() == 1 {}
info!("FIFO space on channel {} is {}", channel, csr::drtio::o_dbg_fifo_space_read());
csr::drtio::chan_sel_override_en_write(0);
(csr::DRTIO[linkidx].chan_sel_override_en_write)(0);
}
}
}
pub fn init() {
if link_is_running() {
unsafe {
csr::drtio::reset_write(1);
while csr::drtio::o_wait_read() == 1 {}
}
for channel in 0..16 {
init_channel(channel);
}
for linkno in 0..csr::DRTIO.len() {
init_link(linkno as u8);
}
}
fn ping_remote(io: &Io) -> u32 {
fn ping_remote(linkno: u8, io: &Io) -> u32 {
let mut count = 0;
loop {
if !link_is_up() {
if !link_rx_up(linkno) {
return 0
}
count += 1;
drtioaux::hw::send(&drtioaux::Packet::EchoRequest).unwrap();
drtioaux::hw::send_link(linkno, &drtioaux::Packet::EchoRequest).unwrap();
io.sleep(100).unwrap();
let pr = drtioaux::hw::recv();
let pr = drtioaux::hw::recv_link(linkno);
match pr {
Ok(Some(drtioaux::Packet::EchoReply)) => return count,
_ => {}
@ -124,59 +114,72 @@ pub mod drtio {
}
}
fn process_local_errors(linkno: u8) {
let errors;
let linkidx = linkno as usize;
unsafe {
errors = (csr::DRTIO[linkidx].protocol_error_read)();
(csr::DRTIO[linkidx].protocol_error_write)(errors);
}
if errors != 0 {
error!("[LINK#{}] found error(s)", linkno);
if errors & 1 != 0 {
error!("[LINK#{}] received packet of an unknown type", linkno);
}
if errors & 2 != 0 {
error!("[LINK#{}] received truncated packet", linkno);
}
if errors & 4 != 0 {
error!("[LINK#{}] timeout attempting to get remote FIFO space", linkno);
}
}
}
fn process_aux_errors(linkno: u8) {
drtioaux::hw::send_link(linkno, &drtioaux::Packet::RtioErrorRequest).unwrap();
match drtioaux::hw::recv_timeout_link(linkno, None) {
Ok(drtioaux::Packet::RtioNoErrorReply) => (),
Ok(drtioaux::Packet::RtioErrorCollisionReply) =>
error!("[LINK#{}] RTIO collision", linkno),
Ok(drtioaux::Packet::RtioErrorBusyReply) =>
error!("[LINK#{}] RTIO busy", linkno),
Ok(_) => error!("[LINK#{}] received unexpected aux packet", linkno),
Err(e) => error!("[LINK#{}] aux packet error ({})", linkno, e)
}
}
pub fn link_thread(io: Io) {
loop {
io.until(link_is_up).unwrap();
info!("link RX is up, pinging");
let mut link_up = vec![false; csr::DRTIO.len()];
let ping_count = ping_remote(&io);
if ping_count > 0 {
info!("remote replied after {} packets", ping_count);
link_set_running(true);
init(); // clear all FIFOs first
reset_phy();
sync_tsc();
info!("link initialization completed");
loop {
for linkno in 0..csr::DRTIO.len() {
let linkno = linkno as u8;
if !link_up[linkno as usize] {
if link_rx_up(linkno) {
info!("[LINK#{}] link RX became up, pinging", linkno);
let ping_count = ping_remote(linkno, &io);
if ping_count > 0 {
info!("[LINK#{}] remote replied after {} packets", linkno, ping_count);
init_link(linkno); // clear all FIFOs first
reset_phy(linkno);
sync_tsc(linkno);
info!("[LINK#{}] link initialization completed", linkno);
link_up[linkno as usize] = true;
} else {
info!("[LINK#{}] ping failed", linkno);
}
} else {
if link_rx_up(linkno) {
process_local_errors(linkno);
process_aux_errors(linkno);
} else {
info!("[LINK#{}] link is down", linkno);
link_up[linkno as usize] = false;
}
}
}
}
io.until(|| !link_is_up()).unwrap();
link_set_running(false);
info!("link is down");
}
}
pub fn local_error_thread(io: Io) {
loop {
unsafe {
io.until(|| csr::drtio::protocol_error_read() != 0).unwrap();
let errors = csr::drtio::protocol_error_read();
if errors & 1 != 0 {
error!("received packet of an unknown type");
}
if errors & 2 != 0 {
error!("received truncated packet");
}
if errors & 4 != 0 {
error!("timeout attempting to get remote FIFO space");
}
csr::drtio::protocol_error_write(errors);
}
}
}
pub fn aux_error_thread(io: Io) {
loop {
io.sleep(200).unwrap();
if link_is_running() {
drtioaux::hw::send(&drtioaux::Packet::RtioErrorRequest).unwrap();
match drtioaux::hw::recv_timeout(None) {
Ok(drtioaux::Packet::RtioNoErrorReply) => (),
Ok(drtioaux::Packet::RtioErrorCollisionReply) => error!("RTIO collision (in satellite)"),
Ok(drtioaux::Packet::RtioErrorBusyReply) => error!("RTIO busy (in satellite)"),
Ok(_) => error!("received unexpected aux packet"),
Err(e) => error!("aux packet error ({})", e)
}
}
}
}
}
@ -248,45 +251,55 @@ pub fn init_core() {
pub mod drtio_dbg {
use board::csr;
// TODO: routing
pub fn get_channel_state(channel: u32) -> (u16, u64) {
let linkno = ((channel >> 16) - 1) as usize;
let node_channel = channel as u16;
unsafe {
csr::drtio::chan_sel_override_write(channel as u16);
csr::drtio::chan_sel_override_en_write(1);
let fifo_space = csr::drtio::o_dbg_fifo_space_read();
let last_timestamp = csr::drtio::o_dbg_last_timestamp_read();
csr::drtio::chan_sel_override_en_write(0);
(csr::DRTIO[linkno].chan_sel_override_write)(node_channel as u16);
(csr::DRTIO[linkno].chan_sel_override_en_write)(1);
let fifo_space = (csr::DRTIO[linkno].o_dbg_fifo_space_read)();
let last_timestamp = (csr::DRTIO[linkno].o_dbg_last_timestamp_read)();
(csr::DRTIO[linkno].chan_sel_override_en_write)(0);
(fifo_space, last_timestamp)
}
}
pub fn reset_channel_state(channel: u32) {
let linkno = ((channel >> 16) - 1) as usize;
let node_channel = channel as u16;
unsafe {
csr::drtio::chan_sel_override_write(channel as u16);
csr::drtio::chan_sel_override_en_write(1);
csr::drtio::o_reset_channel_status_write(1);
csr::drtio::chan_sel_override_en_write(0);
(csr::DRTIO[linkno].chan_sel_override_write)(node_channel);
(csr::DRTIO[linkno].chan_sel_override_en_write)(1);
(csr::DRTIO[linkno].o_reset_channel_status_write)(1);
(csr::DRTIO[linkno].chan_sel_override_en_write)(0);
}
}
pub fn get_fifo_space(channel: u32) {
let linkno = ((channel >> 16) - 1) as usize;
let node_channel = channel as u16;
unsafe {
csr::drtio::chan_sel_override_write(channel as u16);
csr::drtio::chan_sel_override_en_write(1);
csr::drtio::o_get_fifo_space_write(1);
csr::drtio::chan_sel_override_en_write(0);
(csr::DRTIO[linkno].chan_sel_override_write)(node_channel);
(csr::DRTIO[linkno].chan_sel_override_en_write)(1);
(csr::DRTIO[linkno].o_get_fifo_space_write)(1);
(csr::DRTIO[linkno].chan_sel_override_en_write)(0);
}
}
pub fn get_packet_counts() -> (u32, u32) {
pub fn get_packet_counts(linkno: u8) -> (u32, u32) {
let linkno = linkno as usize;
unsafe {
csr::drtio::update_packet_cnt_write(1);
(csr::drtio::packet_cnt_tx_read(), csr::drtio::packet_cnt_rx_read())
(csr::DRTIO[linkno].update_packet_cnt_write)(1);
((csr::DRTIO[linkno].packet_cnt_tx_read)(),
(csr::DRTIO[linkno].packet_cnt_rx_read)())
}
}
pub fn get_fifo_space_req_count() -> u32 {
pub fn get_fifo_space_req_count(linkno: u8) -> u32 {
let linkno = linkno as usize;
unsafe {
csr::drtio::o_dbg_fifo_space_req_cnt_read()
(csr::DRTIO[linkno].o_dbg_fifo_space_req_cnt_read)()
}
}
}
@ -299,7 +312,7 @@ pub mod drtio_dbg {
pub fn get_fifo_space(_channel: u32) {}
pub fn get_packet_counts() -> (u32, u32) { (0, 0) }
pub fn get_packet_counts(_linkno: u8) -> (u32, u32) { (0, 0) }
pub fn get_fifo_space_req_count() -> u32 { 0 }
pub fn get_fifo_space_req_count(_linkno: u8) -> u32 { 0 }
}

View File

@ -15,25 +15,25 @@ fn process_aux_packet(p: &drtioaux::Packet) {
// In the code below, *_chan_sel_write takes an u8 if there are fewer than 256 channels,
// and u16 otherwise; hence the `as _` conversion.
match *p {
drtioaux::Packet::EchoRequest => drtioaux::hw::send(&drtioaux::Packet::EchoReply).unwrap(),
drtioaux::Packet::EchoRequest => drtioaux::hw::send_link(0, &drtioaux::Packet::EchoReply).unwrap(),
drtioaux::Packet::RtioErrorRequest => {
let errors;
unsafe {
errors = board::csr::drtio::rtio_error_read();
errors = (board::csr::DRTIO[0].rtio_error_read)();
}
if errors & 1 != 0 {
unsafe {
board::csr::drtio::rtio_error_write(1);
(board::csr::DRTIO[0].rtio_error_write)(1);
}
drtioaux::hw::send(&drtioaux::Packet::RtioErrorCollisionReply).unwrap();
drtioaux::hw::send_link(0, &drtioaux::Packet::RtioErrorCollisionReply).unwrap();
} else if errors & 2 != 0 {
unsafe {
board::csr::drtio::rtio_error_write(2);
(board::csr::DRTIO[0].rtio_error_write)(2);
}
drtioaux::hw::send(&drtioaux::Packet::RtioErrorBusyReply).unwrap();
drtioaux::hw::send_link(0, &drtioaux::Packet::RtioErrorBusyReply).unwrap();
} else {
drtioaux::hw::send(&drtioaux::Packet::RtioNoErrorReply).unwrap();
drtioaux::hw::send_link(0, &drtioaux::Packet::RtioNoErrorReply).unwrap();
}
}
@ -51,7 +51,7 @@ fn process_aux_packet(p: &drtioaux::Packet) {
value = 0;
}
let reply = drtioaux::Packet::MonitorReply { value: value as u32 };
drtioaux::hw::send(&reply).unwrap();
drtioaux::hw::send_link(0, &reply).unwrap();
},
drtioaux::Packet::InjectionRequest { channel, overrd, value } => {
#[cfg(has_rtio_moninj)]
@ -74,50 +74,50 @@ fn process_aux_packet(p: &drtioaux::Packet) {
value = 0;
}
let reply = drtioaux::Packet::InjectionStatusReply { value: value };
drtioaux::hw::send(&reply).unwrap();
drtioaux::hw::send_link(0, &reply).unwrap();
},
drtioaux::Packet::I2cStartRequest { busno } => {
let succeeded = board::i2c::start(busno).is_ok();
drtioaux::hw::send(&drtioaux::Packet::I2cBasicReply { succeeded: succeeded }).unwrap();
drtioaux::hw::send_link(0, &drtioaux::Packet::I2cBasicReply { succeeded: succeeded }).unwrap();
}
drtioaux::Packet::I2cRestartRequest { busno } => {
let succeeded = board::i2c::restart(busno).is_ok();
drtioaux::hw::send(&drtioaux::Packet::I2cBasicReply { succeeded: succeeded }).unwrap();
drtioaux::hw::send_link(0, &drtioaux::Packet::I2cBasicReply { succeeded: succeeded }).unwrap();
}
drtioaux::Packet::I2cStopRequest { busno } => {
let succeeded = board::i2c::stop(busno).is_ok();
drtioaux::hw::send(&drtioaux::Packet::I2cBasicReply { succeeded: succeeded }).unwrap();
drtioaux::hw::send_link(0, &drtioaux::Packet::I2cBasicReply { succeeded: succeeded }).unwrap();
}
drtioaux::Packet::I2cWriteRequest { busno, data } => {
match board::i2c::write(busno, data) {
Ok(ack) => drtioaux::hw::send(&drtioaux::Packet::I2cWriteReply { succeeded: true, ack: ack }).unwrap(),
Err(_) => drtioaux::hw::send(&drtioaux::Packet::I2cWriteReply { succeeded: false, ack: false }).unwrap()
Ok(ack) => drtioaux::hw::send_link(0, &drtioaux::Packet::I2cWriteReply { succeeded: true, ack: ack }).unwrap(),
Err(_) => drtioaux::hw::send_link(0, &drtioaux::Packet::I2cWriteReply { succeeded: false, ack: false }).unwrap()
};
}
drtioaux::Packet::I2cReadRequest { busno, ack } => {
match board::i2c::read(busno, ack) {
Ok(data) => drtioaux::hw::send(&drtioaux::Packet::I2cReadReply { succeeded: true, data: data }).unwrap(),
Err(_) => drtioaux::hw::send(&drtioaux::Packet::I2cReadReply { succeeded: false, data: 0xff }).unwrap()
Ok(data) => drtioaux::hw::send_link(0, &drtioaux::Packet::I2cReadReply { succeeded: true, data: data }).unwrap(),
Err(_) => drtioaux::hw::send_link(0, &drtioaux::Packet::I2cReadReply { succeeded: false, data: 0xff }).unwrap()
};
}
drtioaux::Packet::SpiSetConfigRequest { busno, flags, write_div, read_div } => {
let succeeded = board::spi::set_config(busno, flags, write_div, read_div).is_ok();
drtioaux::hw::send(&drtioaux::Packet::SpiBasicReply { succeeded: succeeded }).unwrap();
drtioaux::hw::send_link(0, &drtioaux::Packet::SpiBasicReply { succeeded: succeeded }).unwrap();
},
drtioaux::Packet::SpiSetXferRequest { busno, chip_select, write_length, read_length } => {
let succeeded = board::spi::set_xfer(busno, chip_select, write_length, read_length).is_ok();
drtioaux::hw::send(&drtioaux::Packet::SpiBasicReply { succeeded: succeeded }).unwrap();
drtioaux::hw::send_link(0, &drtioaux::Packet::SpiBasicReply { succeeded: succeeded }).unwrap();
}
drtioaux::Packet::SpiWriteRequest { busno, data } => {
let succeeded = board::spi::write(busno, data).is_ok();
drtioaux::hw::send(&drtioaux::Packet::SpiBasicReply { succeeded: succeeded }).unwrap();
drtioaux::hw::send_link(0, &drtioaux::Packet::SpiBasicReply { succeeded: succeeded }).unwrap();
}
drtioaux::Packet::SpiReadRequest { busno } => {
match board::spi::read(busno) {
Ok(data) => drtioaux::hw::send(&drtioaux::Packet::SpiReadReply { succeeded: true, data: data }).unwrap(),
Err(_) => drtioaux::hw::send(&drtioaux::Packet::SpiReadReply { succeeded: false, data: 0 }).unwrap()
Ok(data) => drtioaux::hw::send_link(0, &drtioaux::Packet::SpiReadReply { succeeded: true, data: data }).unwrap(),
Err(_) => drtioaux::hw::send_link(0, &drtioaux::Packet::SpiReadReply { succeeded: false, data: 0 }).unwrap()
};
}
@ -126,7 +126,7 @@ fn process_aux_packet(p: &drtioaux::Packet) {
}
fn process_aux_packets() {
let pr = drtioaux::hw::recv();
let pr = drtioaux::hw::recv_link(0);
match pr {
Ok(None) => (),
Ok(Some(p)) => process_aux_packet(&p),
@ -138,8 +138,8 @@ fn process_aux_packets() {
fn process_errors() {
let errors;
unsafe {
errors = board::csr::drtio::protocol_error_read();
board::csr::drtio::protocol_error_write(errors);
errors = (board::csr::DRTIO[0].protocol_error_read)();
(board::csr::DRTIO[0].protocol_error_write)(errors);
}
if errors & 1 != 0 {
error!("received packet of an unknown type");
@ -185,7 +185,7 @@ const SI5324_SETTINGS: board::si5324::FrequencySettings
fn drtio_link_is_up() -> bool {
unsafe {
board::csr::drtio::link_status_read() == 1
(board::csr::DRTIO[0].link_status_read)() == 1
}
}

View File

@ -53,11 +53,14 @@ class Master(MiniSoC, AMPSoC):
sys_clk_freq=self.clk_freq,
clock_div2=True)
self.submodules.drtio = DRTIOMaster(self.transceiver)
self.csr_devices.append("drtio")
self.submodules.drtio0 = DRTIOMaster(self.transceiver)
self.csr_devices.append("drtio0")
self.add_wb_slave(self.mem_map["drtio_aux"], 0x800,
self.drtio.aux_controller.bus)
self.add_memory_region("drtio_aux", self.mem_map["drtio_aux"] | self.shadow_base, 0x800)
self.drtio0.aux_controller.bus)
self.add_memory_region("drtio0_aux", self.mem_map["drtio_aux"] | self.shadow_base, 0x800)
self.config["has_drtio"] = None
self.add_csr_group("drtio", ["drtio0"])
self.add_memory_group("drtio_aux", ["drtio0_aux"])
platform.add_extension(ad9154_fmc_ebz)
ad9154_spi = platform.request("ad9154_spi")
@ -100,7 +103,7 @@ class Master(MiniSoC, AMPSoC):
self.register_kernel_cpu_csrdevice("rtio_dma")
self.submodules.cri_con = rtio.CRIInterconnectShared(
[self.rtio.cri, self.rtio_dma.cri],
[self.rtio_core.cri, self.drtio.cri])
[self.rtio_core.cri, self.drtio0.cri])
self.register_kernel_cpu_csrdevice("cri_con")

View File

@ -56,13 +56,16 @@ class Satellite(BaseSoC):
sys_clk_freq=self.clk_freq)
self.submodules.rx_synchronizer = gtx_7series.RXSynchronizer(
self.transceiver.rtio_clk_freq, initial_phase=180.0)
self.submodules.drtio = DRTIOSatellite(
self.submodules.drtio0 = DRTIOSatellite(
self.transceiver, rtio_channels, self.rx_synchronizer)
self.csr_devices.append("rx_synchronizer")
self.csr_devices.append("drtio")
self.csr_devices.append("drtio0")
self.add_wb_slave(self.mem_map["drtio_aux"], 0x800,
self.drtio.aux_controller.bus)
self.add_memory_region("drtio_aux", self.mem_map["drtio_aux"] | self.shadow_base, 0x800)
self.drtio0.aux_controller.bus)
self.add_memory_region("drtio0_aux", self.mem_map["drtio_aux"] | self.shadow_base, 0x800)
self.config["has_drtio"] = None
self.add_csr_group("drtio", ["drtio0"])
self.add_memory_group("drtio_aux", ["drtio0_aux"])
self.config["RTIO_FREQUENCY"] = str(self.transceiver.rtio_clk_freq/1e6)
si5324_clkin = platform.request("si5324_clkin")

View File

@ -15,7 +15,7 @@ requirements:
- python >=3.5.3,<3.6
- setuptools 33.1.1
- migen 0.5.dev py_117+gite826cb9
- misoc 0.6.dev py_32+gitc49a361c
- misoc 0.6.dev py_35+gitd6f86c03
- jesd204b 0.3
- binutils-or1k-linux >=2.27
- llvm-or1k