Compare commits
No commits in common. "cd8abae83994eb567e49a097255dadf2486b0cdd" and "875bc74df938f3aac9b5d520a488f3fa4272aef7" have entirely different histories.
cd8abae839
...
875bc74df9
|
@ -12,7 +12,7 @@
|
||||||
"emit-debug-gdb-scripts": false,
|
"emit-debug-gdb-scripts": false,
|
||||||
"env": "",
|
"env": "",
|
||||||
"executables": true,
|
"executables": true,
|
||||||
"features": "+v7,+vfp3,-d32,+thumb2,-neon,+strict-align",
|
"features": "+v7,+vfp3,-d32,+thumb2,-neon",
|
||||||
"is-builtin": false,
|
"is-builtin": false,
|
||||||
"linker": "rust-lld",
|
"linker": "rust-lld",
|
||||||
"linker-flavor": "ld.lld",
|
"linker-flavor": "ld.lld",
|
||||||
|
|
|
@ -15,7 +15,6 @@ use libboard_zynq::{
|
||||||
clocks::source::{ArmPll, ClockSource, IoPll},
|
clocks::source::{ArmPll, ClockSource, IoPll},
|
||||||
clocks::Clocks,
|
clocks::Clocks,
|
||||||
print, println,
|
print, println,
|
||||||
setup_l2cache,
|
|
||||||
sdio::sd_card::SdCard,
|
sdio::sd_card::SdCard,
|
||||||
smoltcp::{
|
smoltcp::{
|
||||||
self,
|
self,
|
||||||
|
@ -33,7 +32,7 @@ use libregister::RegisterR;
|
||||||
use libsupport_zynq::{
|
use libsupport_zynq::{
|
||||||
boot, ram,
|
boot, ram,
|
||||||
};
|
};
|
||||||
use log::{info, warn};
|
use log::info;
|
||||||
|
|
||||||
mod ps7_init;
|
mod ps7_init;
|
||||||
|
|
||||||
|
@ -82,11 +81,7 @@ pub fn main_core0() {
|
||||||
clocks.cpu_2x(),
|
clocks.cpu_2x(),
|
||||||
clocks.cpu_1x()
|
clocks.cpu_1x()
|
||||||
);
|
);
|
||||||
info!("Setup L2Cache");
|
|
||||||
setup_l2cache();
|
|
||||||
info!("L2Cache done");
|
|
||||||
|
|
||||||
if false {
|
|
||||||
let sd = libboard_zynq::sdio::SDIO::sdio0(true);
|
let sd = libboard_zynq::sdio::SDIO::sdio0(true);
|
||||||
// only test SD card if it is inserted
|
// only test SD card if it is inserted
|
||||||
if sd.is_card_inserted() {
|
if sd.is_card_inserted() {
|
||||||
|
@ -119,7 +114,6 @@ if false {
|
||||||
println!("");
|
println!("");
|
||||||
}
|
}
|
||||||
let mut flash = flash.stop();
|
let mut flash = flash.stop();
|
||||||
}
|
|
||||||
|
|
||||||
let timer = libboard_zynq::timer::GlobalTimer::start();
|
let timer = libboard_zynq::timer::GlobalTimer::start();
|
||||||
|
|
||||||
|
@ -128,7 +122,6 @@ if false {
|
||||||
ddr.memtest();
|
ddr.memtest();
|
||||||
ram::init_alloc_ddr(&mut ddr);
|
ram::init_alloc_ddr(&mut ddr);
|
||||||
|
|
||||||
if false {
|
|
||||||
#[cfg(dev)]
|
#[cfg(dev)]
|
||||||
for i in 0..=1 {
|
for i in 0..=1 {
|
||||||
let mut flash_io = flash.manual_mode(i);
|
let mut flash_io = flash.manual_mode(i);
|
||||||
|
@ -182,15 +175,14 @@ if false {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
core1.disable();
|
core1.disable();
|
||||||
}
|
|
||||||
|
|
||||||
let eth = zynq::eth::Eth::default(HWADDR.clone());
|
let eth = zynq::eth::Eth::default(HWADDR.clone());
|
||||||
println!("Eth on");
|
println!("Eth on");
|
||||||
|
|
||||||
const RX_LEN: usize = 4096;
|
const RX_LEN: usize = 8;
|
||||||
// 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 = 4096;
|
const TX_LEN: usize = 8;
|
||||||
let eth = eth.start_rx(RX_LEN);
|
let eth = eth.start_rx(RX_LEN);
|
||||||
let mut eth = eth.start_tx(TX_LEN);
|
let mut eth = eth.start_tx(TX_LEN);
|
||||||
|
|
||||||
|
@ -245,42 +237,18 @@ if false {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
// (rx, tx)
|
let counter = alloc::rc::Rc::new(core::cell::RefCell::new(0));
|
||||||
let stats = alloc::rc::Rc::new(core::cell::RefCell::new((0, 0)));
|
|
||||||
let stats_tx = stats.clone();
|
|
||||||
task::spawn(async move {
|
task::spawn(async move {
|
||||||
while let Ok(stream) = TcpStream::accept(TCP_PORT, 0x10_0000, 0x10_0000).await {
|
while let Ok(stream) = TcpStream::accept(TCP_PORT, 2048, 2408).await {
|
||||||
let stats_tx = stats_tx.clone();
|
let counter = counter.clone();
|
||||||
task::spawn(async move {
|
task::spawn(async move {
|
||||||
let tx_data = (0..=255).take(65536).collect::<alloc::vec::Vec<u8>>();
|
*counter.borrow_mut() += 1;
|
||||||
loop {
|
println!("Serving {} connections", *counter.borrow());
|
||||||
// const CHUNK_SIZE: usize = 65536;
|
handle_connection(stream)
|
||||||
// match stream.send((0..=255).cycle().take(CHUNK_SIZE)).await {
|
.await
|
||||||
match stream.send_slice(&tx_data[..]).await {
|
.unwrap_or_else(|e| println!("Connection: {:?}", e));
|
||||||
Ok(len) => stats_tx.borrow_mut().1 += tx_data.len(), //CHUNK_SIZE,
|
*counter.borrow_mut() -= 1;
|
||||||
Err(e) => {
|
println!("Now serving {} connections", *counter.borrow());
|
||||||
warn!("tx: {:?}", e);
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
let stats_rx = stats.clone();
|
|
||||||
task::spawn(async move {
|
|
||||||
while let Ok(stream) = TcpStream::accept(TCP_PORT+1, 0x10_0000, 0x10_0000).await {
|
|
||||||
let stats_rx = stats_rx.clone();
|
|
||||||
task::spawn(async move {
|
|
||||||
loop {
|
|
||||||
match stream.recv(|buf| Poll::Ready((buf.len(), buf.len()))).await {
|
|
||||||
Ok(len) => stats_rx.borrow_mut().0 += len,
|
|
||||||
Err(e) => {
|
|
||||||
warn!("rx: {:?}", e);
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -293,13 +261,7 @@ if false {
|
||||||
let timestamp = timer.get_us();
|
let timestamp = timer.get_us();
|
||||||
let seconds = timestamp / 1_000_000;
|
let seconds = timestamp / 1_000_000;
|
||||||
let micros = timestamp % 1_000_000;
|
let micros = timestamp % 1_000_000;
|
||||||
let (rx, tx) = {
|
info!("time: {:6}.{:06}s", seconds, micros);
|
||||||
let mut stats = stats.borrow_mut();
|
|
||||||
let result = *stats;
|
|
||||||
*stats = (0, 0);
|
|
||||||
result
|
|
||||||
};
|
|
||||||
info!("time: {:6}.{:06}s, rx: {}k/s, tx: {}k/s", seconds, micros, rx / 1024, tx / 1024);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,5 @@ libcortex_a9 = { path = "../libcortex_a9" }
|
||||||
|
|
||||||
[dependencies.smoltcp]
|
[dependencies.smoltcp]
|
||||||
version = "0.6"
|
version = "0.6"
|
||||||
# features = ["ethernet", "proto-ipv4", "socket-tcp", "log"]
|
|
||||||
features = ["ethernet", "proto-ipv4", "socket-tcp"]
|
features = ["ethernet", "proto-ipv4", "socket-tcp"]
|
||||||
default-features = false
|
default-features = false
|
||||||
|
|
|
@ -2,8 +2,6 @@ use core::ops::Deref;
|
||||||
use alloc::{vec, vec::Vec};
|
use alloc::{vec, vec::Vec};
|
||||||
use libcortex_a9::{asm::*, cache::*, UncachedSlice};
|
use libcortex_a9::{asm::*, cache::*, UncachedSlice};
|
||||||
use libregister::*;
|
use libregister::*;
|
||||||
use log::debug;
|
|
||||||
use crate::l2cache;
|
|
||||||
use super::Buffer;
|
use super::Buffer;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -83,6 +81,9 @@ impl DescList {
|
||||||
entry.word1.write(
|
entry.word1.write(
|
||||||
DescWord1::zeroed()
|
DescWord1::zeroed()
|
||||||
);
|
);
|
||||||
|
// Flush buffer from cache, to be filled by the peripheral
|
||||||
|
// before next read
|
||||||
|
dcci_slice(&buffer[..]);
|
||||||
}
|
}
|
||||||
|
|
||||||
DescList {
|
DescList {
|
||||||
|
@ -104,9 +105,6 @@ impl DescList {
|
||||||
let word1 = entry.word1.read();
|
let word1 = entry.word1.read();
|
||||||
let len = word1.frame_length_lsbs().into();
|
let len = word1.frame_length_lsbs().into();
|
||||||
let buffer = &mut self.buffers[self.next][0..len];
|
let buffer = &mut self.buffers[self.next][0..len];
|
||||||
// Invalidate caches for packet buffer
|
|
||||||
l2cache().invalidate_slice(&mut buffer[..]);
|
|
||||||
dcci_slice(&buffer[..]);
|
|
||||||
|
|
||||||
self.next += 1;
|
self.next += 1;
|
||||||
if self.next >= list_len {
|
if self.next >= list_len {
|
||||||
|
@ -115,10 +113,8 @@ impl DescList {
|
||||||
|
|
||||||
let pkt = PktRef { entry, buffer };
|
let pkt = PktRef { entry, buffer };
|
||||||
if word1.start_of_frame() && word1.end_of_frame() {
|
if word1.start_of_frame() && word1.end_of_frame() {
|
||||||
// debug!("pkt {}: {:08X}..{:08X}", len, &pkt.buffer[0] as *const _ as usize, &pkt.buffer[pkt.len()-1] as *const _ as usize);
|
|
||||||
Ok(Some(pkt))
|
Ok(Some(pkt))
|
||||||
} else {
|
} else {
|
||||||
debug!("pkt trunc");
|
|
||||||
Err(Error::Truncated)
|
Err(Error::Truncated)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -135,6 +131,9 @@ pub struct PktRef<'a> {
|
||||||
|
|
||||||
impl<'a> Drop for PktRef<'a> {
|
impl<'a> Drop for PktRef<'a> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
|
// Flush buffer from cache, to be filled by the peripheral
|
||||||
|
// before next read
|
||||||
|
dcci_slice(self.buffer);
|
||||||
|
|
||||||
self.entry.word0.modify(|_, w| w.used(false));
|
self.entry.word0.modify(|_, w| w.used(false));
|
||||||
dmb();
|
dmb();
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
use core::ops::{Deref, DerefMut};
|
use core::ops::{Deref, DerefMut};
|
||||||
use alloc::{vec, vec::Vec};
|
use alloc::{vec, vec::Vec};
|
||||||
use libcortex_a9::{asm::dmb, cache::dcc_slice, UncachedSlice};
|
use libcortex_a9::{cache::dcc_slice, UncachedSlice};
|
||||||
use libregister::*;
|
use libregister::*;
|
||||||
use log::{debug, warn};
|
|
||||||
use crate::l2cache;
|
|
||||||
use super::{Buffer, regs};
|
use super::{Buffer, regs};
|
||||||
|
|
||||||
/// Descriptor entry
|
/// Descriptor entry
|
||||||
|
@ -92,10 +90,8 @@ impl DescList {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send<'s: 'p, 'p>(&'s mut self, regs: &'s mut regs::RegisterBlock, length: usize) -> Option<PktRef<'p>> {
|
pub fn send<'s: 'p, 'p>(&'s mut self, regs: &'s mut regs::RegisterBlock, length: usize) -> Option<PktRef<'p>> {
|
||||||
// debug!("send {}", length);
|
|
||||||
let list_len = self.list.len();
|
let list_len = self.list.len();
|
||||||
let entry = &mut self.list[self.next];
|
let entry = &mut self.list[self.next];
|
||||||
dmb();
|
|
||||||
if entry.word1.read().used() {
|
if entry.word1.read().used() {
|
||||||
let buffer = &mut self.buffers[self.next][0..length];
|
let buffer = &mut self.buffers[self.next][0..length];
|
||||||
entry.word1.write(DescWord1::zeroed()
|
entry.word1.write(DescWord1::zeroed()
|
||||||
|
@ -113,7 +109,6 @@ impl DescList {
|
||||||
Some(PktRef { entry, buffer, regs })
|
Some(PktRef { entry, buffer, regs })
|
||||||
} else {
|
} else {
|
||||||
// Still in use by HW (sending too fast, ring exceeded)
|
// Still in use by HW (sending too fast, ring exceeded)
|
||||||
warn!("tx ring overflow");
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -129,13 +124,10 @@ pub struct PktRef<'a> {
|
||||||
|
|
||||||
impl<'a> Drop for PktRef<'a> {
|
impl<'a> Drop for PktRef<'a> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
// Write back all dirty cachelines of packet buffer
|
// Write back all dirty cachelines of this buffer
|
||||||
dcc_slice(self.buffer);
|
dcc_slice(self.buffer);
|
||||||
l2cache().clean_slice(self.buffer);
|
|
||||||
|
|
||||||
self.entry.word1.modify(|_, w| w.used(false));
|
self.entry.word1.modify(|_, w| w.used(false));
|
||||||
dmb();
|
|
||||||
// dsb();
|
|
||||||
if ! self.regs.tx_status.read().tx_go() {
|
if ! self.regs.tx_status.read().tx_go() {
|
||||||
// Start TX if not already running
|
// Start TX if not already running
|
||||||
self.regs.net_ctrl.modify(|_, w| w.start_tx(true));
|
self.regs.net_ctrl.modify(|_, w| w.start_tx(true));
|
||||||
|
|
|
@ -36,8 +36,6 @@ pub fn setup_l2cache() {
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut l2 = l2cache();
|
let mut l2 = l2cache();
|
||||||
use log::info;
|
|
||||||
info!("l2 aux={:08X}", l2.regs.aux_control.read());
|
|
||||||
// TODO: set prefetch
|
// TODO: set prefetch
|
||||||
|
|
||||||
// Configure ZYNQ-specific latency
|
// Configure ZYNQ-specific latency
|
||||||
|
|
|
@ -44,15 +44,6 @@ pub fn dcisw(setway: u32) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Data cache clean by set/way
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn dccisw(setway: u32) {
|
|
||||||
unsafe {
|
|
||||||
llvm_asm!("mcr p15, 0, $0, c7, c14, 2" :: "r" (setway) :: "volatile");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// A made-up "instruction": invalidate all of the L1 D-Cache
|
/// A made-up "instruction": invalidate all of the L1 D-Cache
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn dciall() {
|
pub fn dciall() {
|
||||||
|
@ -80,33 +71,6 @@ pub fn dciall() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A made-up "instruction": flush and invalidate all of the L1 D-Cache
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn dcciall() {
|
|
||||||
// the cache associativity could be read from a register, but will
|
|
||||||
// always be 4 in L1 data cache of a cortex a9
|
|
||||||
let ways = 4;
|
|
||||||
let bit_pos_of_way = 30; // 32 - log2(ways)
|
|
||||||
|
|
||||||
// the cache sets could be read from a register, but are always
|
|
||||||
// 256 for the cores in the zync-7000; in general, 128 or 512 are
|
|
||||||
// also possible.
|
|
||||||
let sets = 256;
|
|
||||||
let bit_pos_of_set = 5; // for a line size of 8 words = 2^5 bytes
|
|
||||||
|
|
||||||
// select L1 data cache
|
|
||||||
unsafe {
|
|
||||||
llvm_asm!("mcr p15, 2, $0, c0, c0, 0" :: "r" (0) :: "volatile");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Invalidate entire D-Cache by iterating every set and every way
|
|
||||||
for set in 0..sets {
|
|
||||||
for way in 0..ways {
|
|
||||||
dccisw((set << bit_pos_of_set) | (way << bit_pos_of_way));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const CACHE_LINE: usize = 0x20;
|
const CACHE_LINE: usize = 0x20;
|
||||||
const CACHE_LINE_MASK: usize = CACHE_LINE - 1;
|
const CACHE_LINE_MASK: usize = CACHE_LINE - 1;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use bit_field::BitField;
|
use bit_field::BitField;
|
||||||
use super::{regs::*, asm::*, cache::*};
|
use super::{regs::*, asm, cache};
|
||||||
use libregister::RegisterW;
|
use libregister::RegisterW;
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
|
@ -158,7 +158,7 @@ impl L1Table {
|
||||||
global: true,
|
global: true,
|
||||||
shareable: true,
|
shareable: true,
|
||||||
access: AccessPermissions::FullAccess,
|
access: AccessPermissions::FullAccess,
|
||||||
tex: 0b111,
|
tex: 0b101,
|
||||||
domain: 0b1111,
|
domain: 0b1111,
|
||||||
exec: true,
|
exec: true,
|
||||||
cacheable: true,
|
cacheable: true,
|
||||||
|
@ -368,19 +368,10 @@ impl L1Table {
|
||||||
let result = f(&mut section);
|
let result = f(&mut section);
|
||||||
entry.set_section(section);
|
entry.set_section(section);
|
||||||
|
|
||||||
// Flush L1Dcache
|
asm::dmb();
|
||||||
dcciall();
|
cache::tlbiall();
|
||||||
// // TODO: L2?
|
asm::dsb();
|
||||||
|
asm::isb();
|
||||||
// Invalidate TLB
|
|
||||||
tlbiall();
|
|
||||||
// Invalidate all branch predictors
|
|
||||||
bpiall();
|
|
||||||
|
|
||||||
// ensure completion of the BP and TLB invalidation
|
|
||||||
dsb();
|
|
||||||
// synchronize context on this processor
|
|
||||||
isb();
|
|
||||||
|
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
@ -415,9 +406,9 @@ pub fn with_mmu<F: FnMut() -> !>(l1table: &L1Table, mut f: F) -> ! {
|
||||||
|
|
||||||
// Synchronization barriers
|
// Synchronization barriers
|
||||||
// Allows MMU to start
|
// Allows MMU to start
|
||||||
dsb();
|
asm::dsb();
|
||||||
// Flushes pre-fetch buffer
|
// Flushes pre-fetch buffer
|
||||||
isb();
|
asm::isb();
|
||||||
|
|
||||||
f();
|
f();
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,10 +25,8 @@ impl<T> UncachedSlice<T> {
|
||||||
for page_start in (start..(start + size)).step_by(L1_PAGE_SIZE) {
|
for page_start in (start..(start + size)).step_by(L1_PAGE_SIZE) {
|
||||||
L1Table::get()
|
L1Table::get()
|
||||||
.update(page_start as *const (), |l1_section| {
|
.update(page_start as *const (), |l1_section| {
|
||||||
// Shareable Device
|
|
||||||
l1_section.tex = 0b000;
|
|
||||||
l1_section.cacheable = false;
|
l1_section.cacheable = false;
|
||||||
l1_section.bufferable = true;
|
l1_section.bufferable = false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
use libregister::RegisterR;
|
|
||||||
use libcortex_a9::regs::DFSR;
|
|
||||||
use libboard_zynq::{println, slcr, stdio};
|
use libboard_zynq::{println, slcr, stdio};
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
|
@ -17,7 +15,6 @@ pub unsafe extern "C" fn DataAbort() {
|
||||||
stdio::drop_uart();
|
stdio::drop_uart();
|
||||||
|
|
||||||
println!("DataAbort");
|
println!("DataAbort");
|
||||||
println!("DFSR: {:03X}", DFSR.read());
|
|
||||||
|
|
||||||
slcr::RegisterBlock::unlocked(|slcr| slcr.soft_reset());
|
slcr::RegisterBlock::unlocked(|slcr| slcr.soft_reset());
|
||||||
loop {}
|
loop {}
|
||||||
|
|
Loading…
Reference in New Issue