Compare commits

..

6 Commits

Author SHA1 Message Date
Astro d2f91eac25 libasync: start smoltcp support 2020-03-31 01:16:58 +02:00
Astro 48257e989c libasync: pin tasks to memory 2020-03-31 01:13:01 +02:00
Astro 965a00801e libcortex_a9: set DDR pages non-bufferable to fix eth dma 2020-03-31 01:09:28 +02:00
Astro 46af38906e libboard_zynq: wrap eth Buffer for alignment 2020-03-29 00:08:43 +01:00
Astro ed52ead914 cora ddr attempts 2020-03-28 21:50:06 +01:00
Astro ea765fc529 libasync: replace executor Mutexes with RefCells
this will not run on multi-core.
2020-03-26 20:29:36 +01:00
13 changed files with 373 additions and 110 deletions

21
Cargo.lock generated
View File

@ -15,6 +15,11 @@ name = "byteorder"
version = "1.3.4" version = "1.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "cfg-if"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "compiler_builtins" name = "compiler_builtins"
version = "0.1.26" version = "0.1.26"
@ -38,6 +43,7 @@ dependencies = [
"libboard_zynq 0.0.0", "libboard_zynq 0.0.0",
"libcortex_a9 0.0.0", "libcortex_a9 0.0.0",
"pin-utils 0.1.0-alpha.4 (registry+https://github.com/rust-lang/crates.io-index)", "pin-utils 0.1.0-alpha.4 (registry+https://github.com/rust-lang/crates.io-index)",
"smoltcp 0.6.0",
] ]
[[package]] [[package]]
@ -47,7 +53,8 @@ dependencies = [
"bit_field 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "bit_field 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libcortex_a9 0.0.0", "libcortex_a9 0.0.0",
"libregister 0.0.0", "libregister 0.0.0",
"smoltcp 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"smoltcp 0.6.0",
"volatile-register 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "volatile-register 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@ -85,6 +92,14 @@ name = "linked_list_allocator"
version = "0.8.1" version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "log"
version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "managed" name = "managed"
version = "0.7.1" version = "0.7.1"
@ -103,7 +118,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "smoltcp" name = "smoltcp"
version = "0.6.0" version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
@ -127,11 +141,12 @@ dependencies = [
"checksum bit_field 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a165d606cf084741d4ac3a28fb6e9b1eb0bd31f6cd999098cfddb0b2ab381dc0" "checksum bit_field 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a165d606cf084741d4ac3a28fb6e9b1eb0bd31f6cd999098cfddb0b2ab381dc0"
"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" "checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
"checksum byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" "checksum byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"
"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
"checksum compiler_builtins 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)" = "036b035e9ebcd705affece16319223d19f229e2358be6e3b7b094e57193312e6" "checksum compiler_builtins 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)" = "036b035e9ebcd705affece16319223d19f229e2358be6e3b7b094e57193312e6"
"checksum linked_list_allocator 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5825aea823c659d0fdcdbe8c9b78baf56f3a10365d783db874f6d360df72626f" "checksum linked_list_allocator 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5825aea823c659d0fdcdbe8c9b78baf56f3a10365d783db874f6d360df72626f"
"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
"checksum managed 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fdcec5e97041c7f0f1c5b7d93f12e57293c831c646f4cc7a5db59460c7ea8de6" "checksum managed 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fdcec5e97041c7f0f1c5b7d93f12e57293c831c646f4cc7a5db59460c7ea8de6"
"checksum pin-utils 0.1.0-alpha.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5894c618ce612a3fa23881b152b608bafb8c56cfc22f434a3ba3120b40f7b587" "checksum pin-utils 0.1.0-alpha.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5894c618ce612a3fa23881b152b608bafb8c56cfc22f434a3ba3120b40f7b587"
"checksum r0 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bd7a31eed1591dcbc95d92ad7161908e72f4677f8fabf2a32ca49b4237cbf211" "checksum r0 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bd7a31eed1591dcbc95d92ad7161908e72f4677f8fabf2a32ca49b4237cbf211"
"checksum smoltcp 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0fe46639fd2ec79eadf8fe719f237a7a0bd4dac5d957f1ca5bbdbc1c3c39e53a"
"checksum vcell 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "876e32dcadfe563a4289e994f7cb391197f362b6315dc45e8ba4aa6f564a4b3c" "checksum vcell 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "876e32dcadfe563a4289e994f7cb391197f362b6315dc45e8ba4aa6f564a4b3c"
"checksum volatile-register 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0d67cb4616d99b940db1d6bd28844ff97108b498a6ca850e5b6191a532063286" "checksum volatile-register 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0d67cb4616d99b940db1d6bd28844ff97108b498a6ca850e5b6191a532063286"

View File

@ -1,14 +1,17 @@
#![no_std] #![no_std]
#![no_main] #![no_main]
extern crate alloc;
use core::mem::transmute; use core::mem::transmute;
use alloc::collections::BTreeMap;
use libcortex_a9::mutex::Mutex; use libcortex_a9::mutex::Mutex;
use libboard_zynq::{ use libboard_zynq::{
print, println, print, println,
self as zynq, clocks::Clocks, clocks::source::{ClockSource, ArmPll, IoPll}, self as zynq, clocks::Clocks, clocks::source::{ClockSource, ArmPll, IoPll},
smoltcp::{ smoltcp::{
wire::{EthernetAddress, IpAddress, IpCidr}, wire::{EthernetAddress, IpAddress, IpCidr},
iface::{NeighborCache, EthernetInterfaceBuilder}, iface::{NeighborCache, EthernetInterfaceBuilder, Routes},
time::Instant, time::Instant,
socket::SocketSet, socket::SocketSet,
socket::{TcpSocket, TcpSocketBuffer}, socket::{TcpSocket, TcpSocketBuffer},
@ -18,7 +21,7 @@ use libsupport_zynq::{
ram, alloc::{vec, vec::Vec}, ram, alloc::{vec, vec::Vec},
boot, boot,
}; };
use libasync::task; use libasync::{smoltcp::{Sockets, TcpStream}, task};
const HWADDR: [u8; 6] = [0, 0x23, 0xde, 0xea, 0xbe, 0xef]; const HWADDR: [u8; 6] = [0, 0x23, 0xde, 0xea, 0xbe, 0xef];
@ -152,14 +155,14 @@ pub fn main_core0() {
let mut rx_descs = (0..RX_LEN) let mut rx_descs = (0..RX_LEN)
.map(|_| zynq::eth::rx::DescEntry::zeroed()) .map(|_| zynq::eth::rx::DescEntry::zeroed())
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let mut rx_buffers = vec![[0u8; zynq::eth::MTU]; RX_LEN]; let mut rx_buffers = vec![zynq::eth::Buffer::new(); RX_LEN];
// Number of transmission buffers (minimum is two because with // Number of transmission buffers (minimum is two because with
// one, duplicate packet transmission occurs) // one, duplicate packet transmission occurs)
const TX_LEN: usize = 8; const TX_LEN: usize = 8;
let mut tx_descs = (0..TX_LEN) let mut tx_descs = (0..TX_LEN)
.map(|_| zynq::eth::tx::DescEntry::zeroed()) .map(|_| zynq::eth::tx::DescEntry::zeroed())
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let mut tx_buffers = vec![[0u8; zynq::eth::MTU]; TX_LEN]; let mut tx_buffers = vec![zynq::eth::Buffer::new(); TX_LEN];
let eth = eth.start_rx(&mut rx_descs, &mut rx_buffers); let eth = eth.start_rx(&mut rx_descs, &mut rx_buffers);
// let mut eth = eth.start_tx(&mut tx_descs, &mut tx_buffers); // let mut eth = eth.start_tx(&mut tx_descs, &mut tx_buffers);
let mut eth = eth.start_tx( let mut eth = eth.start_tx(
@ -167,63 +170,79 @@ pub fn main_core0() {
unsafe { transmute(tx_descs.as_mut_slice()) }, unsafe { transmute(tx_descs.as_mut_slice()) },
unsafe { transmute(tx_buffers.as_mut_slice()) }, unsafe { transmute(tx_buffers.as_mut_slice()) },
); );
// loop {
// match eth.recv_next() {
// Ok(None) => {},
// Ok(Some(pkt)) => println!("received {} bytes", pkt.len()),
// Err(e) => println!("e: {:?}", e),
// }
// }
println!("iface...");
let ethernet_addr = EthernetAddress(HWADDR); let ethernet_addr = EthernetAddress(HWADDR);
// IP stack // IP stack
let local_addr = IpAddress::v4(192, 168, 1, 51); let local_addr = IpAddress::v4(192, 168, 1, 51);
let mut ip_addrs = [IpCidr::new(local_addr, 24)]; let mut ip_addrs = [IpCidr::new(local_addr, 24)];
let mut routes_storage = vec![None; 4];
let routes = Routes::new(/*BTreeMap::new()*/ &mut routes_storage[..]);
let mut neighbor_storage = vec![None; 256]; let mut neighbor_storage = vec![None; 256];
let neighbor_cache = NeighborCache::new(&mut neighbor_storage[..]); let neighbor_cache = NeighborCache::new(&mut neighbor_storage[..]);
let mut iface = EthernetInterfaceBuilder::new(&mut eth) let mut iface = EthernetInterfaceBuilder::new(&mut eth)
.ethernet_addr(ethernet_addr) .ethernet_addr(ethernet_addr)
.ip_addrs(&mut ip_addrs[..]) .ip_addrs(&mut ip_addrs[..])
.routes(routes)
.neighbor_cache(neighbor_cache) .neighbor_cache(neighbor_cache)
.finalize(); .finalize();
let mut sockets_storage = [
None, None, None, None,
None, None, None, None
];
let mut sockets = SocketSet::new(&mut sockets_storage[..]);
// taken from example code for smoltcp // TODO: compare with ps7_init
let mut tcp_server_rx_data = vec![0; 512 * 1024];
let mut tcp_server_tx_data = vec![0; 512 * 1024]; println!("Sockets init...");
let tcp_rx_buffer = TcpSocketBuffer::new(&mut tcp_server_rx_data[..]); Sockets::init(32);
let tcp_tx_buffer = TcpSocketBuffer::new(&mut tcp_server_tx_data[..]);
let tcp_socket = TcpSocket::new(tcp_rx_buffer, tcp_tx_buffer);
let tcp_handle = sockets.add(tcp_socket);
/// `chargen` /// `chargen`
const TCP_PORT: u16 = 19; const TCP_PORT: u16 = 19;
task::spawn(async {
println!("listening");
while let socket = TcpStream::listen(TCP_PORT, 2048, 2048).await {
println!("got connection");
task::spawn(async {
println!("spawned for connection");
// while l
drop(socket);
});
}
println!("done?");
});
let mut time = 0u32; Sockets::run(&mut iface);
loop { // let mut time = 0u32;
time += 1; // loop {
let timestamp = Instant::from_millis(time); // time += 1;
// let timestamp = Instant::from_millis(time);
match iface.poll(&mut sockets, timestamp) { // match iface.poll(&mut sockets, timestamp) {
Ok(_) => {}, // Ok(_) => {},
Err(e) => { // Err(e) => {
println!("poll error: {}", e); // println!("poll error: {}", e);
} // }
} // }
// (mostly) taken from smoltcp example: TCP echo server // // (mostly) taken from smoltcp example: TCP echo server
let mut socket = sockets.get::<TcpSocket>(tcp_handle); // let mut socket = sockets.get::<TcpSocket>(tcp_handle);
if !socket.is_open() { // if !socket.is_open() {
socket.listen(TCP_PORT).unwrap() // socket.listen(TCP_PORT).unwrap()
} // }
if socket.may_recv() && socket.can_send() { // if socket.may_recv() && socket.can_send() {
socket.recv(|buf| { // socket.recv(|buf| {
let len = buf.len().min(4096); // let len = buf.len().min(4096);
let buffer = buf[..len].iter().cloned().collect::<Vec<_>>(); // let buffer = buf[..len].iter().cloned().collect::<Vec<_>>();
(len, buffer) // (len, buffer)
}) // })
.and_then(|buffer| socket.send_slice(&buffer[..])) // .and_then(|buffer| socket.send_slice(&buffer[..]))
.map(|_| {}) // .map(|_| {})
.unwrap_or_else(|e| println!("tcp: {:?}", e)); // .unwrap_or_else(|e| println!("tcp: {:?}", e));
} // }
} // }
// #[allow(unreachable_code)] // #[allow(unreachable_code)]
// drop(tx_descs); // drop(tx_descs);

View File

@ -11,3 +11,8 @@ pin-utils = "0.1.0-alpha.4"
libcortex_a9 = { path = "../libcortex_a9" } libcortex_a9 = { path = "../libcortex_a9" }
# TODO: delete # TODO: delete
libboard_zynq = { path = "../libboard_zynq" } libboard_zynq = { path = "../libboard_zynq" }
[dependencies.smoltcp]
version = "0.6"
default-features = false
features = ["alloc"]

View File

@ -1,17 +1,16 @@
use core::{ use core::{
cell::{Cell, UnsafeCell}, cell::{RefCell, UnsafeCell},
future::Future, future::Future,
mem::MaybeUninit, mem::MaybeUninit,
pin::Pin, pin::Pin,
sync::atomic::{self, AtomicBool, Ordering}, sync::atomic::{AtomicBool, Ordering},
task::{Context, Poll, RawWaker, RawWakerVTable, Waker}, task::{Context, Poll, RawWaker, RawWakerVTable, Waker},
}; };
use alloc::{boxed::Box, collections::VecDeque as Deque}; use alloc::{boxed::Box, collections::VecDeque as Deque};
//use futures::future::FutureExt; //use futures::future::FutureExt;
use pin_utils::pin_mut; use pin_utils::pin_mut;
use libcortex_a9::mutex::Mutex;
// TODO: delete // TODO: delete
use libboard_zynq::println; //use libboard_zynq::println;
// NOTE `*const ()` is &AtomicBool // NOTE `*const ()` is &AtomicBool
static VTABLE: RawWakerVTable = { static VTABLE: RawWakerVTable = {
@ -35,16 +34,21 @@ static VTABLE: RawWakerVTable = {
/// ///
/// This is a singleton /// This is a singleton
pub struct Executor { pub struct Executor {
in_block_on: Mutex<bool>, // Entered block_on() already?
tasks: Mutex<Deque<Task>>, in_block_on: RefCell<bool>,
/// Tasks reside on the heap, so that we just queue pointers. They
/// must also be pinned in memory because our RawWaker is a pointer
/// to their `ready` field.
tasks: RefCell<Deque<Pin<Box<Task>>>>,
} }
impl Executor { impl Executor {
/// Creates a new instance of the executor /// Creates a new instance of the executor
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
in_block_on: Mutex::new(false), in_block_on: RefCell::new(false),
tasks: Mutex::new(Deque::new()), tasks: RefCell::new(Deque::new()),
} }
} }
@ -54,7 +58,7 @@ impl Executor {
// application will only call `block_on` once on an infinite task // application will only call `block_on` once on an infinite task
// (`Future<Output = !>`) // (`Future<Output = !>`)
{ {
let mut in_block_on = self.in_block_on.lock(); let mut in_block_on = self.in_block_on.borrow_mut();
if *in_block_on { if *in_block_on {
panic!("nested `block_on`"); panic!("nested `block_on`");
} }
@ -70,14 +74,17 @@ impl Executor {
if ready.load(Ordering::Relaxed) { if ready.load(Ordering::Relaxed) {
ready.store(false, Ordering::Relaxed); ready.store(false, Ordering::Relaxed);
// println!("run block_on");
let mut cx = Context::from_waker(&waker); let mut cx = Context::from_waker(&waker);
if let Poll::Ready(val) = f.as_mut().poll(&mut cx) { if let Poll::Ready(val) = f.as_mut().poll(&mut cx) {
break val; break val;
} }
// println!("ran block_on");
} }
// println!("tasks: {}", self.tasks.borrow().len());
// advance other tasks // advance other tasks
let next_task = self.tasks.lock().pop_front(); let next_task = self.tasks.borrow_mut().pop_front();
if let Some(mut task) = next_task { if let Some(mut task) = next_task {
// NOTE we don't need a CAS operation here because `wake` invocations that come from // NOTE we don't need a CAS operation here because `wake` invocations that come from
// interrupt handlers (the only source of 'race conditions' (!= data races)) are // interrupt handlers (the only source of 'race conditions' (!= data races)) are
@ -94,46 +101,41 @@ impl Executor {
}; };
let mut cx = Context::from_waker(&waker); let mut cx = Context::from_waker(&waker);
// this points into a `static` memory so it's already pinned // this points into a `static` memory so it's already pinned
let r = unsafe { // println!("run task");
Pin::new_unchecked(&mut *task.f) let ready = task.f.as_mut().poll(&mut cx).is_ready();
.poll(&mut cx) if ready {
.is_ready() // Task is finished, do not requeue
}; continue;
if !r {
// Task is not finished, requeue
self.tasks.lock().push_back(task);
} }
} }
// Requeue
self.tasks.borrow_mut().push_back(task);
} }
// // try to sleep; this will be a no-op if any of the previous tasks generated a SEV or an // // try to sleep; this will be a no-op if any of the previous tasks generated a SEV or an
// // interrupt ran (regardless of whether it generated a wake-up or not) // // interrupt ran (regardless of whether it generated a wake-up or not)
// asm::wfe(); // asm::wfe();
}; };
*self.in_block_on.lock() = false; self.in_block_on.replace(false);
val val
} }
// NOTE CAREFUL! this method can overlap with `block_on`
// FIXME we want to use `Future<Output = !>` here but the never type (`!`) is unstable; so as a
// workaround we'll "abort" if the task / future terminates (see `Task::new`)
pub fn spawn(&self, f: impl Future + 'static) { pub fn spawn(&self, f: impl Future + 'static) {
// NOTE(unsafe) only safe as long as `spawn` is never re-entered and this does not overlap let task = Box::pin(Task::new(f));
// with operation `(A)` (see `Task::block_on`) self.tasks.borrow_mut().push_back(task);
self.tasks.lock().push_back(Task::new(f));
} }
} }
pub struct Task { pub struct Task {
ready: AtomicBool, ready: AtomicBool,
f: Box<Future<Output = ()>>, f: Pin<Box<dyn Future<Output = ()>>>,
} }
impl Task { impl Task {
fn new(f: impl Future + 'static) -> Self { fn new(f: impl Future + 'static) -> Self {
Task { Task {
ready: AtomicBool::new(true), ready: AtomicBool::new(true),
f: Box::new(async { f.await; }), f: Box::pin(async { f.await; }),
} }
} }
} }

View File

@ -4,3 +4,5 @@ extern crate alloc;
pub mod task; pub mod task;
pub mod executor; pub mod executor;
pub mod smoltcp;

View File

@ -0,0 +1,90 @@
use core::{
cell::RefCell,
task::Waker,
};
use alloc::{vec, vec::Vec};
use smoltcp::{
iface::EthernetInterface,
phy::Device,
socket::{
SocketSet, SocketHandle,
TcpSocketBuffer, TcpSocket,
},
time::Instant,
};
use libboard_zynq::println;
use crate::task;
mod tcp_stream;
pub use tcp_stream::TcpStream;
static mut SOCKETS: Option<Sockets> = None;
pub struct Sockets {
sockets: RefCell<SocketSet<'static, 'static, 'static>>,
wakers: RefCell<Vec<Waker>>,
}
impl Sockets {
pub fn init(max_sockets: usize) {
println!("initializing {} sockets", max_sockets);
let mut sockets_storage = Vec::with_capacity(max_sockets);
for _ in 0..max_sockets {
sockets_storage.push(None);
}
let sockets = RefCell::new(SocketSet::new(sockets_storage));
let wakers = RefCell::new(Vec::new());
let instance = Sockets {
sockets,
wakers,
};
println!("sockets initialized");
unsafe { SOCKETS = Some(instance); }
}
/// Block and run executor indefinitely while polling the smoltcp
/// iface
pub fn run<'b, 'c, 'e, D: for<'d> Device<'d>>(iface: &mut EthernetInterface<'b, 'c, 'e, D>) {
task::block_on(async {
loop {
Self::instance().poll(iface);
task::r#yield().await;
}
});
}
pub(crate) fn instance() -> &'static Self {
unsafe { SOCKETS.as_ref().expect("Sockets") }
}
fn poll<'b, 'c, 'e, D: for<'d> Device<'d>>(&self, iface: &mut EthernetInterface<'b, 'c, 'e, D>) {
// TODO:
let instant = Instant::from_millis(0);
let processed = {
let mut sockets = self.sockets.borrow_mut();
let r = iface.poll(&mut sockets, instant);
if r != Ok(false) { println!("poll: {:?}", r); }
match r {
Ok(processed) => processed,
Err(_) => true,
}
};
if processed {
let mut wakers = self.wakers.borrow_mut();
println!("wakeup of {}", wakers.len());
for waker in wakers.drain(..) {
waker.wake();
}
}
}
/// TODO: this was called through eg. TcpStream, another poll()
/// might want to send packets before sleeping for an interrupt.
pub(crate) fn register_waker(waker: Waker) {
println!("register_waker");
Self::instance().wakers.borrow_mut()
.push(waker);
}
}

View File

@ -0,0 +1,91 @@
use core::{
cell::{RefCell, UnsafeCell},
future::Future,
mem::MaybeUninit,
pin::Pin,
sync::atomic::{AtomicBool, Ordering},
task::{Context, Poll},
};
use alloc::vec;
use smoltcp::{
iface::EthernetInterface,
phy::Device,
socket::{
SocketSet, SocketHandle, SocketRef,
TcpSocketBuffer, TcpSocket,
},
time::Instant,
};
use libboard_zynq::println;
use super::Sockets;
pub struct TcpStream {
handle: SocketHandle,
}
impl TcpStream {
fn new(rx_bufsize: usize, tx_bufsize: usize) -> Self {
let rx_buffer = TcpSocketBuffer::new(vec![0u8; rx_bufsize]);
let tx_buffer = TcpSocketBuffer::new(vec![0u8; tx_bufsize]);
let socket = TcpSocket::new(rx_buffer, tx_buffer);
let handle = Sockets::instance().sockets.borrow_mut()
.add(socket);
TcpStream { handle }
}
fn with_socket<F, R>(&self, f: F) -> R
where
F: FnOnce(SocketRef<TcpSocket>) -> R,
{
println!("with_socket");
let mut sockets = Sockets::instance().sockets.borrow_mut();
let socket_ref = sockets.get::<TcpSocket>(self.handle);
f(socket_ref)
}
pub async fn listen(port: u16, rx_bufsize: usize, tx_bufsize: usize) -> Self {
struct Accept {
stream: Option<TcpStream>,
}
impl Future for Accept {
type Output = TcpStream;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let is_active = self.stream.as_ref()
.map(|s| s.with_socket(|s| s.is_active()))
.unwrap_or(true);
println!("is_active={:?}", is_active);
if is_active {
Poll::Ready(self.stream.take().unwrap())
} else {
println!("register_waker");
Sockets::register_waker(cx.waker().clone());
//asm::sev();
Poll::Pending
}
}
}
let stream = Self::new(rx_bufsize, tx_bufsize);
stream.with_socket(|mut s| s.listen(port)).expect("listen");
println!("listening on {}", port);
Accept {
stream: Some(stream),
}.await
}
pub async fn recv(&self) {
// self.socket();
}
}
impl Drop for TcpStream {
fn drop(&mut self) {
// TODO: verify
println!("tcpstream drop");
Sockets::instance().sockets.borrow_mut()
.remove(self.handle);
}
}

View File

@ -17,10 +17,7 @@ pub fn block_on<T>(f: impl Future<Output = T>) -> T {
/// Spawns a task onto the executor /// Spawns a task onto the executor
/// ///
/// The spawned task will not make any progress until `block_on` is called. /// The spawned task will not make any progress until `block_on` is called.
/// pub fn spawn(f: impl Future + 'static) {
/// The future `f` must never terminate. The program will *abort* if `f` (the async code) returns.
/// The right signature here would be `f: impl Future<Output = !>` but that requires nightly
pub fn spawn<T>(f: impl Future<Output = T> + 'static) {
executor::current().spawn(f) executor::current().spawn(f)
} }

View File

@ -61,7 +61,7 @@ impl DdrRam {
fn calibrate_iob_impedance(clocks: &Clocks) { fn calibrate_iob_impedance(clocks: &Clocks) {
let divisor0 = ((DCI_FREQ - 1 + clocks.ddr) / DCI_FREQ) let divisor0 = ((DCI_FREQ - 1 + clocks.ddr) / DCI_FREQ)
.max(1).min(63) as u8; .max(1).min(63) as u8;
let divisor1 = (clocks.ddr / DCI_FREQ / u32::from(divisor0)) let divisor1 = ((DCI_FREQ - 1 + clocks.ddr) / DCI_FREQ / u32::from(divisor0))
.max(1).min(63) as u8; .max(1).min(63) as u8;
println!("DDR DCI clock: {} Hz", clocks.ddr / u32::from(divisor0) / u32::from(divisor1)); println!("DDR DCI clock: {} Hz", clocks.ddr / u32::from(divisor0) / u32::from(divisor1));
@ -111,21 +111,46 @@ impl DdrRam {
slcr.ddriob_addr0.write(addr_config.clone()); slcr.ddriob_addr0.write(addr_config.clone());
slcr.ddriob_addr1.write(addr_config); slcr.ddriob_addr1.write(addr_config);
let data_config = slcr::DdriobConfig::zeroed() #[cfg(feature = "target_zc706")]
let data0_config = slcr::DdriobConfig::zeroed()
.inp_type(slcr::DdriobInputType::VrefDifferential) .inp_type(slcr::DdriobInputType::VrefDifferential)
.term_en(true) .term_en(true)
.dci_type(slcr::DdriobDciType::Termination) .dci_type(slcr::DdriobDciType::Termination)
.output_en(slcr::DdriobOutputEn::Obuf); .output_en(slcr::DdriobOutputEn::Obuf);
slcr.ddriob_data0.write(data_config.clone()); #[cfg(feature = "target_zc706")]
slcr.ddriob_data1.write(data_config); let data1_config = data0_config.clone();
#[cfg(feature = "target_cora_z7_10")]
let data0_config = slcr::DdriobConfig::zeroed()
.inp_type(slcr::DdriobInputType::VrefDifferential)
.term_en(true)
.dci_type(slcr::DdriobDciType::Termination)
.output_en(slcr::DdriobOutputEn::Obuf);
#[cfg(feature = "target_cora_z7_10")]
let data1_config = slcr::DdriobConfig::zeroed()
.pullup_en(true);
slcr.ddriob_data0.write(data0_config);
slcr.ddriob_data1.write(data1_config);
let diff_config = slcr::DdriobConfig::zeroed() #[cfg(feature = "target_zc706")]
let diff0_config = slcr::DdriobConfig::zeroed()
.inp_type(slcr::DdriobInputType::Differential) .inp_type(slcr::DdriobInputType::Differential)
.term_en(true) .term_en(true)
.dci_type(slcr::DdriobDciType::Termination) .dci_type(slcr::DdriobDciType::Termination)
.output_en(slcr::DdriobOutputEn::Obuf); .output_en(slcr::DdriobOutputEn::Obuf);
slcr.ddriob_diff0.write(diff_config.clone()); #[cfg(feature = "target_zc706")]
slcr.ddriob_diff1.write(diff_config); let diff1_config = diff0_config.clone();
#[cfg(feature = "target_cora_z7_10")]
let diff0_config = slcr::DdriobConfig::zeroed()
.inp_type(slcr::DdriobInputType::Differential)
.term_en(true)
.dci_type(slcr::DdriobDciType::Termination)
.output_en(slcr::DdriobOutputEn::Obuf);
#[cfg(feature = "target_cora_z7_10")]
let diff1_config = slcr::DdriobConfig::zeroed()
.pullup_en(true);
slcr.ddriob_diff0.write(diff0_config);
slcr.ddriob_diff1.write(diff1_config);
slcr.ddriob_clock.write( slcr.ddriob_clock.write(
slcr::DdriobConfig::zeroed() slcr::DdriobConfig::zeroed()
@ -140,24 +165,17 @@ impl DdrRam {
slcr.ddriob_drive_slew_clock.write(0x00F9861C); slcr.ddriob_drive_slew_clock.write(0x00F9861C);
} }
#[cfg(feature = "target_zc706")]
let vref_sel = slcr::DdriobVrefSel::Vref0_75V;
#[cfg(feature = "target_cora_z7_10")]
let vref_sel = slcr::DdriobVrefSel::Vref0_675V;
// // Enable internal V[REF]
// slcr.ddriob_ddr_ctrl.modify(|_, w| w
// .vref_ext_en_lower(false)
// .vref_ext_en_upper(false)
// .vref_sel(vref_sel)
// .vref_int_en(true)
// );
// Enable external V[REF] // Enable external V[REF]
#[cfg(feature = "target_cora_z7_10")]
slcr.ddriob_ddr_ctrl.modify(|_, w| w
.vref_int_en(false)
.vref_ext_en_lower(true)
.vref_ext_en_upper(false)
);
#[cfg(feature = "target_zc706")]
slcr.ddriob_ddr_ctrl.modify(|_, w| w slcr.ddriob_ddr_ctrl.modify(|_, w| w
.vref_ext_en_lower(true) .vref_ext_en_lower(true)
.vref_ext_en_upper(true) .vref_ext_en_upper(true)
.vref_sel(vref_sel)
.vref_int_en(false)
); );
}); });
} }

View File

@ -1,3 +1,4 @@
use core::ops::{Deref, DerefMut};
use libregister::*; use libregister::*;
use crate::println; use crate::println;
use super::slcr; use super::slcr;
@ -18,6 +19,29 @@ const TX_100: u32 = 25_000_000;
/// Clock for GbE /// Clock for GbE
const TX_1000: u32 = 125_000_000; const TX_1000: u32 = 125_000_000;
#[derive(Clone)]
#[repr(C, align(0x08))]
pub struct Buffer(pub [u8; MTU]);
impl Buffer {
pub fn new() -> Self {
Buffer([0; MTU])
}
}
impl Deref for Buffer {
type Target = [u8];
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for Buffer {
fn deref_mut(&mut self) -> &mut <Self as Deref>::Target {
&mut self.0
}
}
pub struct Eth<'r, RX, TX> { pub struct Eth<'r, RX, TX> {
rx: RX, rx: RX,
tx: TX, tx: TX,
@ -239,7 +263,7 @@ impl<'r, RX, TX> Eth<'r, RX, TX> {
}); });
} }
pub fn start_rx<'rx>(self, rx_list: &'rx mut [rx::DescEntry], rx_buffers: &'rx mut [[u8; MTU]]) -> Eth<'r, rx::DescList<'rx>, TX> { pub fn start_rx<'rx>(self, rx_list: &'rx mut [rx::DescEntry], rx_buffers: &'rx mut [Buffer]) -> Eth<'r, rx::DescList<'rx>, TX> {
let new_self = Eth { let new_self = Eth {
rx: rx::DescList::new(rx_list, rx_buffers), rx: rx::DescList::new(rx_list, rx_buffers),
tx: self.tx, tx: self.tx,
@ -258,7 +282,7 @@ impl<'r, RX, TX> Eth<'r, RX, TX> {
new_self new_self
} }
pub fn start_tx<'tx>(self, tx_list: &'tx mut [tx::DescEntry], tx_buffers: &'tx mut [[u8; MTU]]) -> Eth<'r, RX, tx::DescList<'tx>> { pub fn start_tx<'tx>(self, tx_list: &'tx mut [tx::DescEntry], tx_buffers: &'tx mut [Buffer]) -> Eth<'r, RX, tx::DescList<'tx>> {
let new_self = Eth { let new_self = Eth {
rx: self.rx, rx: self.rx,
tx: tx::DescList::new(tx_list, tx_buffers), tx: tx::DescList::new(tx_list, tx_buffers),

View File

@ -1,6 +1,6 @@
use core::ops::Deref; use core::ops::Deref;
use libregister::*; use libregister::*;
use super::MTU; use super::Buffer;
#[derive(Debug)] #[derive(Debug)]
pub enum Error { pub enum Error {
@ -55,16 +55,16 @@ register_bit!(desc_word1, global_broadcast, 31);
#[repr(C)] #[repr(C)]
pub struct DescList<'a> { pub struct DescList<'a> {
list: &'a mut [DescEntry], list: &'a mut [DescEntry],
buffers: &'a mut [[u8; MTU]], buffers: &'a mut [Buffer],
next: usize, next: usize,
} }
impl<'a> DescList<'a> { impl<'a> DescList<'a> {
pub fn new(list: &'a mut [DescEntry], buffers: &'a mut [[u8; MTU]]) -> Self { pub fn new(list: &'a mut [DescEntry], buffers: &'a mut [Buffer]) -> Self {
let last = list.len().min(buffers.len()) - 1; let last = list.len().min(buffers.len()) - 1;
for (i, (entry, buffer)) in list.iter_mut().zip(buffers.iter_mut()).enumerate() { for (i, (entry, buffer)) in list.iter_mut().zip(buffers.iter_mut()).enumerate() {
let is_last = i == last; let is_last = i == last;
let buffer_addr = &mut buffer[0] as *mut _ as u32; let buffer_addr = &mut buffer.0[0] as *mut _ as u32;
assert!(buffer_addr & 0b11 == 0); assert!(buffer_addr & 0b11 == 0);
entry.word0.write( entry.word0.write(
DescWord0::zeroed() DescWord0::zeroed()

View File

@ -1,6 +1,6 @@
use core::ops::{Deref, DerefMut}; use core::ops::{Deref, DerefMut};
use libregister::*; use libregister::*;
use super::{MTU, regs}; use super::{Buffer, regs};
/// Descriptor entry /// Descriptor entry
#[repr(C, align(0x08))] #[repr(C, align(0x08))]
@ -42,12 +42,12 @@ pub const DESCS: usize = 8;
#[repr(C)] #[repr(C)]
pub struct DescList<'a> { pub struct DescList<'a> {
list: &'a mut [DescEntry], list: &'a mut [DescEntry],
buffers: &'a mut [[u8; MTU]], buffers: &'a mut [Buffer],
next: usize, next: usize,
} }
impl<'a> DescList<'a> { impl<'a> DescList<'a> {
pub fn new(list: &'a mut [DescEntry], buffers: &'a mut [[u8; MTU]]) -> Self { pub fn new(list: &'a mut [DescEntry], buffers: &'a mut [Buffer]) -> Self {
let last = list.len().min(buffers.len()) - 1; let last = list.len().min(buffers.len()) - 1;
// Sending seems to not work properly with only one packet // Sending seems to not work properly with only one packet
// buffer (two duplicates get send with every packet), so // buffer (two duplicates get send with every packet), so
@ -57,7 +57,7 @@ impl<'a> DescList<'a> {
for (i, (entry, buffer)) in list.iter_mut().zip(buffers.iter_mut()).enumerate() { for (i, (entry, buffer)) in list.iter_mut().zip(buffers.iter_mut()).enumerate() {
let is_last = i == last; let is_last = i == last;
let buffer_addr = &mut buffer[0] as *mut _ as u32; let buffer_addr = &mut buffer.0[0] as *mut _ as u32;
assert!(buffer_addr & 0b11 == 0); assert!(buffer_addr & 0b11 == 0);
entry.word0.write( entry.word0.write(
DescWord0::zeroed() DescWord0::zeroed()

View File

@ -137,7 +137,7 @@ impl L1Table {
domain: 0b1111, domain: 0b1111,
exec: true, exec: true,
cacheable: true, cacheable: true,
bufferable: true, bufferable: false,
}); });
} }
/* (unassigned/reserved). */ /* (unassigned/reserved). */