From c023f6ec5a536f3c0b369a4e3935c97ae44dbb38 Mon Sep 17 00:00:00 2001 From: pca006132 Date: Wed, 10 Jun 2020 16:42:22 +0800 Subject: [PATCH 1/7] started sd reader --- src/Cargo.lock | 10 +- src/runtime/src/main.rs | 6 +- src/runtime/src/sd_reader.rs | 234 +++++++++++++++++++++++++++++++++++ 3 files changed, 243 insertions(+), 7 deletions(-) create mode 100644 src/runtime/src/sd_reader.rs diff --git a/src/Cargo.lock b/src/Cargo.lock index 8a96b87..7b21c08 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -172,7 +172,7 @@ dependencies = [ [[package]] name = "libasync" version = "0.0.0" -source = "git+https://git.m-labs.hk/M-Labs/zc706.git#40d5eb8232de1bec19e8bb81ad09351537926a06" +source = "git+https://git.m-labs.hk/M-Labs/zc706.git#cf17a1c60a667bcc68772224d2fa98f1cf3fceee" dependencies = [ "embedded-hal", "libcortex_a9", @@ -184,7 +184,7 @@ dependencies = [ [[package]] name = "libboard_zynq" version = "0.0.0" -source = "git+https://git.m-labs.hk/M-Labs/zc706.git#40d5eb8232de1bec19e8bb81ad09351537926a06" +source = "git+https://git.m-labs.hk/M-Labs/zc706.git#cf17a1c60a667bcc68772224d2fa98f1cf3fceee" dependencies = [ "bit_field", "embedded-hal", @@ -200,7 +200,7 @@ dependencies = [ [[package]] name = "libcortex_a9" version = "0.0.0" -source = "git+https://git.m-labs.hk/M-Labs/zc706.git#40d5eb8232de1bec19e8bb81ad09351537926a06" +source = "git+https://git.m-labs.hk/M-Labs/zc706.git#cf17a1c60a667bcc68772224d2fa98f1cf3fceee" dependencies = [ "bit_field", "libregister", @@ -209,7 +209,7 @@ dependencies = [ [[package]] name = "libregister" version = "0.0.0" -source = "git+https://git.m-labs.hk/M-Labs/zc706.git#40d5eb8232de1bec19e8bb81ad09351537926a06" +source = "git+https://git.m-labs.hk/M-Labs/zc706.git#cf17a1c60a667bcc68772224d2fa98f1cf3fceee" dependencies = [ "bit_field", "vcell", @@ -219,7 +219,7 @@ dependencies = [ [[package]] name = "libsupport_zynq" version = "0.0.0" -source = "git+https://git.m-labs.hk/M-Labs/zc706.git#40d5eb8232de1bec19e8bb81ad09351537926a06" +source = "git+https://git.m-labs.hk/M-Labs/zc706.git#cf17a1c60a667bcc68772224d2fa98f1cf3fceee" dependencies = [ "compiler_builtins", "libboard_zynq", diff --git a/src/runtime/src/main.rs b/src/runtime/src/main.rs index 48522df..88c409c 100644 --- a/src/runtime/src/main.rs +++ b/src/runtime/src/main.rs @@ -8,7 +8,7 @@ extern crate alloc; use core::{cmp, str}; use log::info; -use libboard_zynq::{timer::GlobalTimer, logger, devc}; +use libboard_zynq::{timer::GlobalTimer, logger, devc, ddr}; use libsupport_zynq::ram; mod proto_core_io; @@ -20,7 +20,7 @@ mod pl; mod rtio; mod kernel; mod moninj; - +mod sd_reader; fn identifier_read(buf: &mut [u8]) -> &str { unsafe { @@ -42,7 +42,9 @@ pub fn main_core0() { log::set_max_level(log::LevelFilter::Debug); info!("NAR3/Zynq7000 starting..."); + let mut ddr_ram = ddr::DdrRam::new(); ram::init_alloc_linker(); + ram::init_alloc_ddr(&mut ddr_ram); let devc = devc::DevC::new(); if devc.is_done() { diff --git a/src/runtime/src/sd_reader.rs b/src/runtime/src/sd_reader.rs new file mode 100644 index 0000000..c23b88e --- /dev/null +++ b/src/runtime/src/sd_reader.rs @@ -0,0 +1,234 @@ +use core_io::{BufRead, Error, ErrorKind, Read, Result as IoResult, Seek, SeekFrom, Write}; +use libboard_zynq::sdio::{sd_card::SdCard, CmdTransferError}; + +fn cmd_error_to_io_error(_: CmdTransferError) -> Error { + Error::new(ErrorKind::Other, "Command transfer error") +} + +const BLOCK_SIZE: usize = 512; + +struct SdReader<'a> { + /// Internal SdCard handle. + sd: &'a mut SdCard, + /// Read buffer with the size of 1 block. + buffer: [u8; BLOCK_SIZE], + /// Address for the next byte. + byte_addr: u32, + /// Internal index for the next byte. + /// Normally in range `[0, BLOCK_SIZE - 1]`. + /// + /// `index = BLOCK_SIZE` means that the `buffer` is invalid for the current `byte_addr`, + /// the next `fill_buf` call would fill the buffer. + index: usize, + /// Dirty flag indicating the content has to be flushed. + dirty: bool, +} + +impl<'a> SdReader<'a> { + pub fn new(sd: &'a mut SdCard) -> SdReader<'a> { + SdReader { + sd, + buffer: [0; BLOCK_SIZE], + byte_addr: 0, + index: BLOCK_SIZE, + dirty: false, + } + } +} + +impl<'a> Read for SdReader<'a> { + fn read(&mut self, buf: &mut [u8]) -> IoResult { + let mut remaining_length = buf.len(); + if self.byte_addr % (BLOCK_SIZE as u32) == 0 && remaining_length >= BLOCK_SIZE { + // block aligned and the buffer can store at least 1 block + // write directly into the target buffer + self.sd + .read_block( + self.byte_addr / (BLOCK_SIZE as u32), + (remaining_length / BLOCK_SIZE) as u16, + buf, + ) + .map_err(cmd_error_to_io_error)?; + self.byte_addr += (remaining_length - remaining_length % BLOCK_SIZE) as u32; + // invalidate the read_buffer + self.index = BLOCK_SIZE; + remaining_length %= BLOCK_SIZE; + } else { + // Not block aligned or not enough for 1 block + // fill the internal buffer first and copy into the target buffer + let filled_buffer = self.fill_buf()?; + // It is possible for the target buffer to be smaller than the filled buffer, + // in this case the target buffer did not reach the block boundary. + // If so, the zip would short-circuit, so it should be safe. + let end_length = core::cmp::min(buf.len(), filled_buffer.len()); + for (target, src) in buf[..end_length].iter_mut().zip(filled_buffer.iter()) { + *target = *src; + } + remaining_length -= end_length; + self.consume(end_length); + + if remaining_length >= BLOCK_SIZE { + // block aligned read now + self.sd + .read_block( + self.byte_addr / (BLOCK_SIZE as u32), + (remaining_length / BLOCK_SIZE) as u16, + &mut buf[end_length..], + ) + .map_err(cmd_error_to_io_error)?; + remaining_length %= BLOCK_SIZE; + // invalidate the read buffer + self.index = BLOCK_SIZE; + } + } + assert!(remaining_length < BLOCK_SIZE); + if remaining_length > 0 { + let buf_len = buf.len(); + let filled_buffer = self.fill_buf()?; + for (target, src) in buf[buf_len - remaining_length..] + .iter_mut() + .zip(filled_buffer.iter()) + { + *target = *src; + } + self.consume(remaining_length); + } + Ok(buf.len()) + } +} + +impl<'a> BufRead for SdReader<'a> { + fn fill_buf(&mut self) -> IoResult<&[u8]> { + assert!(self.index <= BLOCK_SIZE, "Invalid index!"); + + if self.index == BLOCK_SIZE { + // flush the buffer if it is dirty before overwriting it with new data + if self.dirty { + self.flush()?; + } + // reload buffer + self.sd + .read_block(self.byte_addr / (BLOCK_SIZE as u32), 1, &mut self.buffer) + .map_err(cmd_error_to_io_error)?; + self.index = (self.byte_addr as usize) % BLOCK_SIZE; + } + Ok(&self.buffer[self.index..]) + } + + fn consume(&mut self, amt: usize) { + assert!(self.index + amt <= BLOCK_SIZE, "Invalid amt!"); + + self.index += amt; + self.byte_addr += amt as u32; + } +} + +impl<'a> Write for SdReader<'a> { + fn write(&mut self, buf: &[u8]) -> IoResult { + let mut remaining_length = buf.len(); + if self.byte_addr % (BLOCK_SIZE as u32) == 0 && buf.len() >= BLOCK_SIZE { + // block aligned and the buffer contains at least 1 block + // write directly into the SD card + self.sd + .write_block( + self.byte_addr / (BLOCK_SIZE as u32), + (remaining_length / BLOCK_SIZE) as u16, + buf, + ) + .map_err(cmd_error_to_io_error)?; + self.byte_addr += (remaining_length - remaining_length % BLOCK_SIZE) as u32; + // invalidate the read_buffer + self.index = BLOCK_SIZE; + remaining_length %= BLOCK_SIZE; + } else { + // update the read_buffer first, we will write into it + let filled_buffer_len = self.fill_buf()?.len(); + let end_index = core::cmp::min(buf.len(), filled_buffer_len); + for (src, target) in buf[..end_index] + .iter() + .zip(self.buffer[self.index..].iter_mut()) + { + *target = *src; + } + remaining_length -= end_index; + self.dirty = true; + self.consume(end_index); + if remaining_length > BLOCK_SIZE { + // flush the content first + self.flush()?; + // now write directly... + self.sd + .write_block( + self.byte_addr / (BLOCK_SIZE as u32), + (remaining_length / BLOCK_SIZE) as u16, + &buf[end_index..], + ) + .map_err(cmd_error_to_io_error)?; + remaining_length %= BLOCK_SIZE; + // invalidate the read buffer + self.index = BLOCK_SIZE; + } + } + assert!(remaining_length < BLOCK_SIZE); + if remaining_length > 0 { + let buf_len = buf.len(); + // fill the read buffer + self.fill_buf()?; + for (src, target) in buf[buf_len - remaining_length..] + .iter() + .zip(self.buffer[self.index..].iter_mut()) + { + *target = *src; + } + self.dirty = true; + self.consume(remaining_length); + } + Ok(buf.len()) + } + + fn flush(&mut self) -> IoResult<()> { + if self.dirty { + let block_addr = (self.byte_addr - self.index as u32) / (BLOCK_SIZE as u32); + self.sd + .write_block(block_addr, 1, &self.buffer) + .map_err(cmd_error_to_io_error)?; + self.dirty = false; + } + Ok(()) + } +} + +impl<'a> Seek for SdReader<'a> { + fn seek(&mut self, pos: SeekFrom) -> IoResult { + let raw_target = match pos { + SeekFrom::Start(x) => x as i64, + SeekFrom::Current(x) => self.byte_addr as i64 + x, + SeekFrom::End(_) => panic!("SD card does not support seek from end"), + }; + if raw_target < 0 || raw_target > core::u32::MAX as i64 { + return Err(Error::new(ErrorKind::InvalidInput, "Invalid address")); + } + let target_byte_addr = raw_target as u32; + let same_block = self.byte_addr / (BLOCK_SIZE as u32) + == target_byte_addr / (BLOCK_SIZE as u32) + && self.index != BLOCK_SIZE; + if !same_block { + self.flush()?; + } + self.byte_addr = target_byte_addr; + self.index = if same_block { + target_byte_addr as usize % BLOCK_SIZE + } else { + BLOCK_SIZE + }; + Ok(self.byte_addr as u64) + } +} + +impl<'a> Drop for SdReader<'a> { + fn drop(&mut self) { + // just try to flush it, ignore error if any + self.flush().unwrap_or(()); + } +} + -- 2.44.1 From a93cdef5439b9f93ab1c8579e9ebb96f5374881d Mon Sep 17 00:00:00 2001 From: pca006132 Date: Thu, 11 Jun 2020 11:12:48 +0800 Subject: [PATCH 2/7] refactoring sd read --- src/Cargo.lock | 10 ++-- src/runtime/src/sd_reader.rs | 104 +++++++++++++++++------------------ 2 files changed, 57 insertions(+), 57 deletions(-) diff --git a/src/Cargo.lock b/src/Cargo.lock index 7b21c08..fa4f8bf 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -172,7 +172,7 @@ dependencies = [ [[package]] name = "libasync" version = "0.0.0" -source = "git+https://git.m-labs.hk/M-Labs/zc706.git#cf17a1c60a667bcc68772224d2fa98f1cf3fceee" +source = "git+https://git.m-labs.hk/M-Labs/zc706.git#074b3547de2754279a7df9de3b13a8757c9272ef" dependencies = [ "embedded-hal", "libcortex_a9", @@ -184,7 +184,7 @@ dependencies = [ [[package]] name = "libboard_zynq" version = "0.0.0" -source = "git+https://git.m-labs.hk/M-Labs/zc706.git#cf17a1c60a667bcc68772224d2fa98f1cf3fceee" +source = "git+https://git.m-labs.hk/M-Labs/zc706.git#074b3547de2754279a7df9de3b13a8757c9272ef" dependencies = [ "bit_field", "embedded-hal", @@ -200,7 +200,7 @@ dependencies = [ [[package]] name = "libcortex_a9" version = "0.0.0" -source = "git+https://git.m-labs.hk/M-Labs/zc706.git#cf17a1c60a667bcc68772224d2fa98f1cf3fceee" +source = "git+https://git.m-labs.hk/M-Labs/zc706.git#074b3547de2754279a7df9de3b13a8757c9272ef" dependencies = [ "bit_field", "libregister", @@ -209,7 +209,7 @@ dependencies = [ [[package]] name = "libregister" version = "0.0.0" -source = "git+https://git.m-labs.hk/M-Labs/zc706.git#cf17a1c60a667bcc68772224d2fa98f1cf3fceee" +source = "git+https://git.m-labs.hk/M-Labs/zc706.git#074b3547de2754279a7df9de3b13a8757c9272ef" dependencies = [ "bit_field", "vcell", @@ -219,7 +219,7 @@ dependencies = [ [[package]] name = "libsupport_zynq" version = "0.0.0" -source = "git+https://git.m-labs.hk/M-Labs/zc706.git#cf17a1c60a667bcc68772224d2fa98f1cf3fceee" +source = "git+https://git.m-labs.hk/M-Labs/zc706.git#074b3547de2754279a7df9de3b13a8757c9272ef" dependencies = [ "compiler_builtins", "libboard_zynq", diff --git a/src/runtime/src/sd_reader.rs b/src/runtime/src/sd_reader.rs index c23b88e..5b3e281 100644 --- a/src/runtime/src/sd_reader.rs +++ b/src/runtime/src/sd_reader.rs @@ -34,66 +34,67 @@ impl<'a> SdReader<'a> { dirty: false, } } + + /// Internal read function for not block aligned read. + /// The read must not cross block boundary. + fn read_unaligned(&mut self, buf: &mut [u8]) -> IoResult { + if buf.len() == 0 { + return Ok(0); + } + let filled_buffer = self.fill_buf()?; + for (dest, src) in buf.iter_mut().zip(filled_buffer.iter()) { + *dest = *src; + } + self.consume(buf.len()); + Ok(buf.len()) + } + + /// Internal write function for not block aligned write. + /// The write must not cross block boundary. + fn write_unaligned(&mut self, buf: &[u8]) -> IoResult { + if buf.len() == 0 { + return Ok(0); + } + // update buffer + self.fill_buf()?; + self.dirty = true; + let dest_buffer = &mut self.buffer[self.index..]; + for (src, dest) in buf.iter().zip(dest_buffer.iter_mut()) { + *dest = *src; + } + self.consume(buf.len()); + Ok(buf.len()) + } } impl<'a> Read for SdReader<'a> { fn read(&mut self, buf: &mut [u8]) -> IoResult { - let mut remaining_length = buf.len(); - if self.byte_addr % (BLOCK_SIZE as u32) == 0 && remaining_length >= BLOCK_SIZE { - // block aligned and the buffer can store at least 1 block - // write directly into the target buffer + let total_length = buf.len(); + let boundary1 = self.byte_addr as usize % BLOCK_SIZE; + let (a, b, c) = if boundary1 > buf.len() { + (buf, &mut [] as &mut [u8], &mut [] as &mut [u8]) + } else { + let boundary2 = buf.len() - (buf.len() + self.byte_addr as usize) % BLOCK_SIZE; + let (head, remaining) = buf.split_at_mut(boundary1); + if boundary1 != boundary2 { + let (mid, last) = remaining.split_at_mut(boundary2); + (head, mid, last) + } else { + (head, &mut [] as &mut [u8], remaining) + } + }; + self.read_unaligned(a)?; + if b.len() > 0 { self.sd .read_block( - self.byte_addr / (BLOCK_SIZE as u32), - (remaining_length / BLOCK_SIZE) as u16, - buf, + self.byte_addr / BLOCK_SIZE as u32, + (b.len() / BLOCK_SIZE) as u16, + b, ) .map_err(cmd_error_to_io_error)?; - self.byte_addr += (remaining_length - remaining_length % BLOCK_SIZE) as u32; - // invalidate the read_buffer - self.index = BLOCK_SIZE; - remaining_length %= BLOCK_SIZE; - } else { - // Not block aligned or not enough for 1 block - // fill the internal buffer first and copy into the target buffer - let filled_buffer = self.fill_buf()?; - // It is possible for the target buffer to be smaller than the filled buffer, - // in this case the target buffer did not reach the block boundary. - // If so, the zip would short-circuit, so it should be safe. - let end_length = core::cmp::min(buf.len(), filled_buffer.len()); - for (target, src) in buf[..end_length].iter_mut().zip(filled_buffer.iter()) { - *target = *src; - } - remaining_length -= end_length; - self.consume(end_length); - - if remaining_length >= BLOCK_SIZE { - // block aligned read now - self.sd - .read_block( - self.byte_addr / (BLOCK_SIZE as u32), - (remaining_length / BLOCK_SIZE) as u16, - &mut buf[end_length..], - ) - .map_err(cmd_error_to_io_error)?; - remaining_length %= BLOCK_SIZE; - // invalidate the read buffer - self.index = BLOCK_SIZE; - } } - assert!(remaining_length < BLOCK_SIZE); - if remaining_length > 0 { - let buf_len = buf.len(); - let filled_buffer = self.fill_buf()?; - for (target, src) in buf[buf_len - remaining_length..] - .iter_mut() - .zip(filled_buffer.iter()) - { - *target = *src; - } - self.consume(remaining_length); - } - Ok(buf.len()) + self.read_unaligned(c)?; + Ok(total_length) } } @@ -231,4 +232,3 @@ impl<'a> Drop for SdReader<'a> { self.flush().unwrap_or(()); } } - -- 2.44.1 From d539597f567920a53c956a3e33d1c31ca12e03a2 Mon Sep 17 00:00:00 2001 From: pca006132 Date: Thu, 11 Jun 2020 12:55:17 +0800 Subject: [PATCH 3/7] seems working --- src/runtime/src/main.rs | 34 ++++++++-- src/runtime/src/sd_reader.rs | 124 ++++++++++++++--------------------- 2 files changed, 77 insertions(+), 81 deletions(-) diff --git a/src/runtime/src/main.rs b/src/runtime/src/main.rs index 88c409c..faf18df 100644 --- a/src/runtime/src/main.rs +++ b/src/runtime/src/main.rs @@ -7,13 +7,14 @@ extern crate alloc; use core::{cmp, str}; use log::info; - -use libboard_zynq::{timer::GlobalTimer, logger, devc, ddr}; +use libboard_zynq::{timer::GlobalTimer, logger, devc, ddr, sdio}; use libsupport_zynq::ram; +use core_io::{Seek, Read, Write, SeekFrom}; + mod proto_core_io; mod proto_async; -mod comms; +// mod comms; mod rpc; #[path = "../../../build/pl.rs"] mod pl; @@ -42,9 +43,28 @@ pub fn main_core0() { log::set_max_level(log::LevelFilter::Debug); info!("NAR3/Zynq7000 starting..."); - let mut ddr_ram = ddr::DdrRam::new(); - ram::init_alloc_linker(); - ram::init_alloc_ddr(&mut ddr_ram); + // let mut ddr_ram = ddr::DdrRam::new(); + // ram::init_alloc_linker(); + // ram::init_alloc_ddr(&mut ddr_ram); + + let mut sdio0 = sdio::SDIO::sdio0(true); + if sdio0.is_card_inserted() { + info!("Card inserted. Getting SD Card data."); + let mut sd = sdio::sd_card::SdCard::from_sdio(sdio0).unwrap(); + let mut reader = sd_reader::SdReader::new(&mut sd); + // let mut buffer: alloc::vec::Vec = alloc::vec::Vec::with_capacity(128); + // unsafe { + // buffer.set_len(128); + // } + let mut buffer: [u8; 1000] = [0; 1000]; + reader.seek(SeekFrom::Start(1000)); + reader.read(&mut buffer).unwrap(); + for i in 0..buffer.len() { + info!("buffer[{}] = {:0X}", i, buffer[i]); + } + } else { + info!("Card not inserted") + } let devc = devc::DevC::new(); if devc.is_done() { @@ -62,5 +82,5 @@ pub fn main_core0() { pl::csr::rtio_core::reset_phy_write(1); } - comms::main(timer); + // comms::main(timer); } diff --git a/src/runtime/src/sd_reader.rs b/src/runtime/src/sd_reader.rs index 5b3e281..ded0644 100644 --- a/src/runtime/src/sd_reader.rs +++ b/src/runtime/src/sd_reader.rs @@ -1,5 +1,6 @@ use core_io::{BufRead, Error, ErrorKind, Read, Result as IoResult, Seek, SeekFrom, Write}; use libboard_zynq::sdio::{sd_card::SdCard, CmdTransferError}; +use log::debug; fn cmd_error_to_io_error(_: CmdTransferError) -> Error { Error::new(ErrorKind::Other, "Command transfer error") @@ -7,7 +8,7 @@ fn cmd_error_to_io_error(_: CmdTransferError) -> Error { const BLOCK_SIZE: usize = 512; -struct SdReader<'a> { +pub struct SdReader<'a> { /// Internal SdCard handle. sd: &'a mut SdCard, /// Read buffer with the size of 1 block. @@ -65,26 +66,47 @@ impl<'a> SdReader<'a> { self.consume(buf.len()); Ok(buf.len()) } + + fn block_align<'b>(&self, buf: &'b [u8]) -> (&'b [u8], &'b [u8], &'b [u8]) { + let head_len = BLOCK_SIZE - (self.byte_addr as usize % BLOCK_SIZE); + if head_len > buf.len() { + (buf, &[], &[]) + } else { + let remaining_length = buf.len() - head_len; + let mid_length = remaining_length - remaining_length % BLOCK_SIZE; + let (head, remaining) = buf.split_at(head_len); + let (mid, tail) = remaining.split_at(mid_length); + (head, mid, tail) + } + } + + fn block_align_mut<'b>(&self, buf: &'b mut [u8]) -> (&'b mut [u8], &'b mut [u8], &'b mut [u8]) { + let head_len = BLOCK_SIZE - (self.byte_addr as usize % BLOCK_SIZE); + if head_len > buf.len() { + (buf, &mut [], &mut []) + } else { + let remaining_length = buf.len() - head_len; + let mid_length = remaining_length - remaining_length % BLOCK_SIZE; + let (head, remaining) = buf.split_at_mut(head_len); + let (mid, tail) = remaining.split_at_mut(mid_length); + (head, mid, tail) + } + } + + fn invalidate_buffer(&mut self) { + self.index = BLOCK_SIZE; + } } impl<'a> Read for SdReader<'a> { fn read(&mut self, buf: &mut [u8]) -> IoResult { let total_length = buf.len(); - let boundary1 = self.byte_addr as usize % BLOCK_SIZE; - let (a, b, c) = if boundary1 > buf.len() { - (buf, &mut [] as &mut [u8], &mut [] as &mut [u8]) - } else { - let boundary2 = buf.len() - (buf.len() + self.byte_addr as usize) % BLOCK_SIZE; - let (head, remaining) = buf.split_at_mut(boundary1); - if boundary1 != boundary2 { - let (mid, last) = remaining.split_at_mut(boundary2); - (head, mid, last) - } else { - (head, &mut [] as &mut [u8], remaining) - } - }; + let (a, b, c) = self.block_align_mut(buf); + debug!("{}, {}, {}", a.len(), b.len(), c.len()); self.read_unaligned(a)?; if b.len() > 0 { + // invalidate internal buffer + self.invalidate_buffer(); self.sd .read_block( self.byte_addr / BLOCK_SIZE as u32, @@ -126,64 +148,17 @@ impl<'a> BufRead for SdReader<'a> { impl<'a> Write for SdReader<'a> { fn write(&mut self, buf: &[u8]) -> IoResult { - let mut remaining_length = buf.len(); - if self.byte_addr % (BLOCK_SIZE as u32) == 0 && buf.len() >= BLOCK_SIZE { - // block aligned and the buffer contains at least 1 block - // write directly into the SD card - self.sd - .write_block( - self.byte_addr / (BLOCK_SIZE as u32), - (remaining_length / BLOCK_SIZE) as u16, - buf, - ) - .map_err(cmd_error_to_io_error)?; - self.byte_addr += (remaining_length - remaining_length % BLOCK_SIZE) as u32; - // invalidate the read_buffer - self.index = BLOCK_SIZE; - remaining_length %= BLOCK_SIZE; - } else { - // update the read_buffer first, we will write into it - let filled_buffer_len = self.fill_buf()?.len(); - let end_index = core::cmp::min(buf.len(), filled_buffer_len); - for (src, target) in buf[..end_index] - .iter() - .zip(self.buffer[self.index..].iter_mut()) - { - *target = *src; - } - remaining_length -= end_index; - self.dirty = true; - self.consume(end_index); - if remaining_length > BLOCK_SIZE { - // flush the content first - self.flush()?; - // now write directly... - self.sd - .write_block( - self.byte_addr / (BLOCK_SIZE as u32), - (remaining_length / BLOCK_SIZE) as u16, - &buf[end_index..], - ) - .map_err(cmd_error_to_io_error)?; - remaining_length %= BLOCK_SIZE; - // invalidate the read buffer - self.index = BLOCK_SIZE; - } - } - assert!(remaining_length < BLOCK_SIZE); - if remaining_length > 0 { - let buf_len = buf.len(); - // fill the read buffer - self.fill_buf()?; - for (src, target) in buf[buf_len - remaining_length..] - .iter() - .zip(self.buffer[self.index..].iter_mut()) - { - *target = *src; - } - self.dirty = true; - self.consume(remaining_length); + let (a, b, c) = self.block_align(buf); + self.write_unaligned(a)?; + if b.len() > 0 { + self.invalidate_buffer(); + self.sd.write_block( + self.byte_addr / BLOCK_SIZE as u32, + (b.len() / BLOCK_SIZE) as u16, + b, + ); } + self.write_unaligned(c)?; Ok(buf.len()) } @@ -210,9 +185,9 @@ impl<'a> Seek for SdReader<'a> { return Err(Error::new(ErrorKind::InvalidInput, "Invalid address")); } let target_byte_addr = raw_target as u32; - let same_block = self.byte_addr / (BLOCK_SIZE as u32) - == target_byte_addr / (BLOCK_SIZE as u32) - && self.index != BLOCK_SIZE; + let address_same_block = self.byte_addr / (BLOCK_SIZE as u32) == target_byte_addr / (BLOCK_SIZE as u32); + // if the buffer was invalidated, we consider seek as different block + let same_block = address_same_block && self.index != BLOCK_SIZE; if !same_block { self.flush()?; } @@ -220,6 +195,7 @@ impl<'a> Seek for SdReader<'a> { self.index = if same_block { target_byte_addr as usize % BLOCK_SIZE } else { + // invalidate the buffer as we moved to a different block BLOCK_SIZE }; Ok(self.byte_addr as u64) -- 2.44.1 From 38e5162ee08dbeaba866e48821ce2a53ac648416 Mon Sep 17 00:00:00 2001 From: pca006132 Date: Thu, 11 Jun 2020 13:03:53 +0800 Subject: [PATCH 4/7] SD reader seems working (actually Read+Write+Seek) --- src/runtime/src/main.rs | 7 ++++++- src/runtime/src/sd_reader.rs | 4 +--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/runtime/src/main.rs b/src/runtime/src/main.rs index faf18df..c5d9523 100644 --- a/src/runtime/src/main.rs +++ b/src/runtime/src/main.rs @@ -57,7 +57,12 @@ pub fn main_core0() { // buffer.set_len(128); // } let mut buffer: [u8; 1000] = [0; 1000]; - reader.seek(SeekFrom::Start(1000)); + for i in 0..buffer.len() { + buffer[i] = (i % 64) as u8; + } + // just trying randomly access some portion of the memory... + reader.write(&buffer[0..800]).unwrap(); + reader.seek(SeekFrom::Start(30)).unwrap(); reader.read(&mut buffer).unwrap(); for i in 0..buffer.len() { info!("buffer[{}] = {:0X}", i, buffer[i]); diff --git a/src/runtime/src/sd_reader.rs b/src/runtime/src/sd_reader.rs index ded0644..ab45d4e 100644 --- a/src/runtime/src/sd_reader.rs +++ b/src/runtime/src/sd_reader.rs @@ -1,6 +1,5 @@ use core_io::{BufRead, Error, ErrorKind, Read, Result as IoResult, Seek, SeekFrom, Write}; use libboard_zynq::sdio::{sd_card::SdCard, CmdTransferError}; -use log::debug; fn cmd_error_to_io_error(_: CmdTransferError) -> Error { Error::new(ErrorKind::Other, "Command transfer error") @@ -102,7 +101,6 @@ impl<'a> Read for SdReader<'a> { fn read(&mut self, buf: &mut [u8]) -> IoResult { let total_length = buf.len(); let (a, b, c) = self.block_align_mut(buf); - debug!("{}, {}, {}", a.len(), b.len(), c.len()); self.read_unaligned(a)?; if b.len() > 0 { // invalidate internal buffer @@ -156,7 +154,7 @@ impl<'a> Write for SdReader<'a> { self.byte_addr / BLOCK_SIZE as u32, (b.len() / BLOCK_SIZE) as u16, b, - ); + ).map_err(cmd_error_to_io_error)?; } self.write_unaligned(c)?; Ok(buf.len()) -- 2.44.1 From 7238e69f10ffa464ec7adcb5158aade9e2f56a36 Mon Sep 17 00:00:00 2001 From: pca006132 Date: Thu, 11 Jun 2020 15:55:14 +0800 Subject: [PATCH 5/7] fatfs working --- src/Cargo.lock | 13 +++++++++++ src/runtime/Cargo.toml | 3 ++- src/runtime/src/main.rs | 43 ++++++++++++++++++++++++------------ src/runtime/src/sd_reader.rs | 26 ++++++++++++++++------ 4 files changed, 63 insertions(+), 22 deletions(-) diff --git a/src/Cargo.lock b/src/Cargo.lock index fa4f8bf..95a8e85 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -93,6 +93,18 @@ dependencies = [ "void", ] +[[package]] +name = "fatfs" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6d1df9e4503954f60504a5ee4fc435cd65cc42e98b2081f7f421be5f2e68e7d" +dependencies = [ + "bitflags", + "byteorder", + "core_io", + "log", +] + [[package]] name = "futures" version = "0.3.5" @@ -353,6 +365,7 @@ dependencies = [ "core_io", "cslice", "dyld", + "fatfs", "futures", "libasync", "libboard_zynq", diff --git a/src/runtime/Cargo.toml b/src/runtime/Cargo.toml index 624fc16..f03acb1 100644 --- a/src/runtime/Cargo.toml +++ b/src/runtime/Cargo.toml @@ -14,7 +14,7 @@ num-traits = { version = "0.2", default-features = false } num-derive = "0.3" cslice = "0.3" log = "0.4" -core_io = { version = "0.1", features = ["alloc", "collections"] } +core_io = { version = "0.1", features = ["collections"] } byteorder = { version = "1.3", default-features = false } void = { version = "1", default-features = false } futures = { version = "0.3", default-features = false, features = ["async-await"] } @@ -24,3 +24,4 @@ libsupport_zynq = { git = "https://git.m-labs.hk/M-Labs/zc706.git" } libcortex_a9 = { git = "https://git.m-labs.hk/M-Labs/zc706.git" } libasync = { git = "https://git.m-labs.hk/M-Labs/zc706.git" } dyld = { path = "../libdyld" } +fatfs = { version = "0.3.3", features = ["core_io"], default-features = false } diff --git a/src/runtime/src/main.rs b/src/runtime/src/main.rs index c5d9523..1002cc5 100644 --- a/src/runtime/src/main.rs +++ b/src/runtime/src/main.rs @@ -12,6 +12,8 @@ use libsupport_zynq::ram; use core_io::{Seek, Read, Write, SeekFrom}; +use fatfs; + mod proto_core_io; mod proto_async; // mod comms; @@ -43,8 +45,10 @@ pub fn main_core0() { log::set_max_level(log::LevelFilter::Debug); info!("NAR3/Zynq7000 starting..."); + info!("Init alloc linker"); + ram::init_alloc_linker(); // let mut ddr_ram = ddr::DdrRam::new(); - // ram::init_alloc_linker(); + // info!("Init alloc ddr"); // ram::init_alloc_ddr(&mut ddr_ram); let mut sdio0 = sdio::SDIO::sdio0(true); @@ -52,21 +56,32 @@ pub fn main_core0() { info!("Card inserted. Getting SD Card data."); let mut sd = sdio::sd_card::SdCard::from_sdio(sdio0).unwrap(); let mut reader = sd_reader::SdReader::new(&mut sd); - // let mut buffer: alloc::vec::Vec = alloc::vec::Vec::with_capacity(128); - // unsafe { - // buffer.set_len(128); - // } - let mut buffer: [u8; 1000] = [0; 1000]; - for i in 0..buffer.len() { - buffer[i] = (i % 64) as u8; + + let mut lba_buffer: [u8; 4] = [0; 4]; + reader.seek(SeekFrom::Start(0x1BE + 0x8)); + reader.read(&mut lba_buffer).unwrap(); + // read MBR and get first partition LBA, hopefully it is FAT32 + let mut lba: u32 = 0; + for i in 0..4 { + lba |= (lba_buffer[i] as u32) << (i * 8); } - // just trying randomly access some portion of the memory... - reader.write(&buffer[0..800]).unwrap(); - reader.seek(SeekFrom::Start(30)).unwrap(); - reader.read(&mut buffer).unwrap(); - for i in 0..buffer.len() { - info!("buffer[{}] = {:0X}", i, buffer[i]); + info!("LBA = 0x{:0X}", lba); + reader.seek(SeekFrom::Start(0)).unwrap(); + reader.set_base_offset(lba * 0x200); + + let fs = fatfs::FileSystem::new(reader, fatfs::FsOptions::new()).unwrap(); + let root_dir = fs.root_dir(); + for entry in root_dir.iter() { + if let Ok(entry) = entry { + let bytes = entry.short_file_name_as_bytes(); + info!(""); + for b in bytes { + info!("{}", *b as char); + } + // info!("- {}", entry.short_file_name_as_bytes()); + } } + } else { info!("Card not inserted") } diff --git a/src/runtime/src/sd_reader.rs b/src/runtime/src/sd_reader.rs index ab45d4e..ff6d671 100644 --- a/src/runtime/src/sd_reader.rs +++ b/src/runtime/src/sd_reader.rs @@ -22,6 +22,8 @@ pub struct SdReader<'a> { index: usize, /// Dirty flag indicating the content has to be flushed. dirty: bool, + /// Base offset for upcoming read/writes + offset: u32, } impl<'a> SdReader<'a> { @@ -32,6 +34,7 @@ impl<'a> SdReader<'a> { byte_addr: 0, index: BLOCK_SIZE, dirty: false, + offset: 0, } } @@ -95,6 +98,12 @@ impl<'a> SdReader<'a> { fn invalidate_buffer(&mut self) { self.index = BLOCK_SIZE; } + + pub fn set_base_offset(&mut self, offset: u32) { + self.offset = offset; + self.byte_addr += offset; + self.invalidate_buffer(); + } } impl<'a> Read for SdReader<'a> { @@ -150,11 +159,13 @@ impl<'a> Write for SdReader<'a> { self.write_unaligned(a)?; if b.len() > 0 { self.invalidate_buffer(); - self.sd.write_block( - self.byte_addr / BLOCK_SIZE as u32, - (b.len() / BLOCK_SIZE) as u16, - b, - ).map_err(cmd_error_to_io_error)?; + self.sd + .write_block( + self.byte_addr / BLOCK_SIZE as u32, + (b.len() / BLOCK_SIZE) as u16, + b, + ) + .map_err(cmd_error_to_io_error)?; } self.write_unaligned(c)?; Ok(buf.len()) @@ -178,12 +189,13 @@ impl<'a> Seek for SdReader<'a> { SeekFrom::Start(x) => x as i64, SeekFrom::Current(x) => self.byte_addr as i64 + x, SeekFrom::End(_) => panic!("SD card does not support seek from end"), - }; + } + self.offset as i64; if raw_target < 0 || raw_target > core::u32::MAX as i64 { return Err(Error::new(ErrorKind::InvalidInput, "Invalid address")); } let target_byte_addr = raw_target as u32; - let address_same_block = self.byte_addr / (BLOCK_SIZE as u32) == target_byte_addr / (BLOCK_SIZE as u32); + let address_same_block = + self.byte_addr / (BLOCK_SIZE as u32) == target_byte_addr / (BLOCK_SIZE as u32); // if the buffer was invalidated, we consider seek as different block let same_block = address_same_block && self.index != BLOCK_SIZE; if !same_block { -- 2.44.1 From 5bb051d1f0ecedc619441fb1c116c184e00c4e31 Mon Sep 17 00:00:00 2001 From: pca006132 Date: Fri, 12 Jun 2020 10:32:14 +0800 Subject: [PATCH 6/7] Documentation and added mounting function --- src/runtime/src/main.rs | 20 +----- src/runtime/src/sd_reader.rs | 128 ++++++++++++++++++++++++++--------- 2 files changed, 98 insertions(+), 50 deletions(-) diff --git a/src/runtime/src/main.rs b/src/runtime/src/main.rs index 1002cc5..02b1fc4 100644 --- a/src/runtime/src/main.rs +++ b/src/runtime/src/main.rs @@ -10,10 +10,6 @@ use log::info; use libboard_zynq::{timer::GlobalTimer, logger, devc, ddr, sdio}; use libsupport_zynq::ram; -use core_io::{Seek, Read, Write, SeekFrom}; - -use fatfs; - mod proto_core_io; mod proto_async; // mod comms; @@ -57,19 +53,7 @@ pub fn main_core0() { let mut sd = sdio::sd_card::SdCard::from_sdio(sdio0).unwrap(); let mut reader = sd_reader::SdReader::new(&mut sd); - let mut lba_buffer: [u8; 4] = [0; 4]; - reader.seek(SeekFrom::Start(0x1BE + 0x8)); - reader.read(&mut lba_buffer).unwrap(); - // read MBR and get first partition LBA, hopefully it is FAT32 - let mut lba: u32 = 0; - for i in 0..4 { - lba |= (lba_buffer[i] as u32) << (i * 8); - } - info!("LBA = 0x{:0X}", lba); - reader.seek(SeekFrom::Start(0)).unwrap(); - reader.set_base_offset(lba * 0x200); - - let fs = fatfs::FileSystem::new(reader, fatfs::FsOptions::new()).unwrap(); + let fs = reader.mount_fatfs(sd_reader::PartitionEntry::Entry1).unwrap(); let root_dir = fs.root_dir(); for entry in root_dir.iter() { if let Ok(entry) = entry { @@ -78,10 +62,8 @@ pub fn main_core0() { for b in bytes { info!("{}", *b as char); } - // info!("- {}", entry.short_file_name_as_bytes()); } } - } else { info!("Card not inserted") } diff --git a/src/runtime/src/sd_reader.rs b/src/runtime/src/sd_reader.rs index ff6d671..f810405 100644 --- a/src/runtime/src/sd_reader.rs +++ b/src/runtime/src/sd_reader.rs @@ -1,4 +1,5 @@ use core_io::{BufRead, Error, ErrorKind, Read, Result as IoResult, Seek, SeekFrom, Write}; +use fatfs; use libboard_zynq::sdio::{sd_card::SdCard, CmdTransferError}; fn cmd_error_to_io_error(_: CmdTransferError) -> Error { @@ -7,6 +8,12 @@ fn cmd_error_to_io_error(_: CmdTransferError) -> Error { const BLOCK_SIZE: usize = 512; +/// SdReader struct implementing `Read + BufRead + Write + Seek` traits for `core_io`. +/// Used as an adaptor for fatfs crate, but could be used directly for raw data access. +/// +/// Implementation: all read/writes would be split into unaligned and block-aligned parts, +/// unaligned read/writes would do a buffered read/write using a block-sized internal buffer, +/// while aligned transactions would be sent to the SD card directly for performance reason. pub struct SdReader<'a> { /// Internal SdCard handle. sd: &'a mut SdCard, @@ -22,11 +29,22 @@ pub struct SdReader<'a> { index: usize, /// Dirty flag indicating the content has to be flushed. dirty: bool, - /// Base offset for upcoming read/writes + /// Base offset for translation from logical address to physical address. offset: u32, } +#[derive(Copy, Clone)] +#[allow(unused)] +// Partition entry enum, normally we would use entry1. +pub enum PartitionEntry { + Entry1 = 0x1BE, + Entry2 = 0x1CE, + Entry3 = 0x1DE, + Entry4 = 0x1EE, +} + impl<'a> SdReader<'a> { + /// Create SdReader from SdCard pub fn new(sd: &'a mut SdCard) -> SdReader<'a> { SdReader { sd, @@ -38,7 +56,7 @@ impl<'a> SdReader<'a> { } } - /// Internal read function for not block aligned read. + /// Internal read function for unaligned read. /// The read must not cross block boundary. fn read_unaligned(&mut self, buf: &mut [u8]) -> IoResult { if buf.len() == 0 { @@ -52,13 +70,13 @@ impl<'a> SdReader<'a> { Ok(buf.len()) } - /// Internal write function for not block aligned write. + /// Internal write function for unaligned write. /// The write must not cross block boundary. fn write_unaligned(&mut self, buf: &[u8]) -> IoResult { if buf.len() == 0 { return Ok(0); } - // update buffer + // update buffer if needed, as we will flush the entire block later. self.fill_buf()?; self.dirty = true; let dest_buffer = &mut self.buffer[self.index..]; @@ -69,6 +87,8 @@ impl<'a> SdReader<'a> { Ok(buf.len()) } + /// Split the slice into three segments, with the middle block-aligned. + /// Alignment depends on the current `self.byte_addr` instead of the slice pointer address fn block_align<'b>(&self, buf: &'b [u8]) -> (&'b [u8], &'b [u8], &'b [u8]) { let head_len = BLOCK_SIZE - (self.byte_addr as usize % BLOCK_SIZE); if head_len > buf.len() { @@ -82,6 +102,8 @@ impl<'a> SdReader<'a> { } } + /// Split the mutable slice into three segments, with the middle block-aligned. + /// Alignment depends on the current `self.byte_addr` instead of the slice pointer address fn block_align_mut<'b>(&self, buf: &'b mut [u8]) -> (&'b mut [u8], &'b mut [u8], &'b mut [u8]) { let head_len = BLOCK_SIZE - (self.byte_addr as usize % BLOCK_SIZE); if head_len > buf.len() { @@ -95,14 +117,55 @@ impl<'a> SdReader<'a> { } } + /// Invalidate the buffer, so later unaligned read/write would reload the buffer from SD card. fn invalidate_buffer(&mut self) { self.index = BLOCK_SIZE; } - pub fn set_base_offset(&mut self, offset: u32) { + /// Set the base offset of the SD card, to transform from physical address to logical address. + fn set_base_offset(&mut self, offset: u32) -> IoResult { self.offset = offset; - self.byte_addr += offset; - self.invalidate_buffer(); + self.seek(SeekFrom::Start(0)) + } + + /// Mount fatfs from partition entry, and return the fatfs object if success. + /// This takes the ownership of self, so currently there is no way to recover from an error, + /// except creating a new SD card instance. + pub fn mount_fatfs(mut self, entry: PartitionEntry) -> IoResult> { + let mut buffer: [u8; 4] = [0; 4]; + self.seek(SeekFrom::Start(0x1FE))?; + self.read_exact(&mut buffer[..2])?; + // check MBR signature + if buffer[0] != 0x55 || buffer[1] != 0xAA { + return Err(Error::new( + ErrorKind::InvalidData, + "Incorrect signature for MBR sector.", + )); + } + // Read partition ID. + self.seek(SeekFrom::Start(entry as u64 + 0x4))?; + self.read_exact(&mut buffer[..1])?; + match buffer[0] { + 0x01 | 0x04 | 0x06 | 0x0B => (), + _ => { + return Err(Error::new( + ErrorKind::InvalidData, + "No FAT partition found for the specified entry.", + )) + } + }; + // Read LBA + self.seek(SeekFrom::Current(0x3))?; + self.read_exact(&mut buffer)?; + let mut lba: u32 = 0; + // Little endian + for i in 0..4 { + lba |= (buffer[i] as u32) << (i * 8); + } + // Set to logical address + self.set_base_offset(lba * BLOCK_SIZE as u32)?; + // setup fatfs + fatfs::FileSystem::new(self, fatfs::FsOptions::new()) } } @@ -114,23 +177,25 @@ impl<'a> Read for SdReader<'a> { if b.len() > 0 { // invalidate internal buffer self.invalidate_buffer(); - self.sd - .read_block( - self.byte_addr / BLOCK_SIZE as u32, - (b.len() / BLOCK_SIZE) as u16, - b, - ) - .map_err(cmd_error_to_io_error)?; + if let Err(_) = self.sd.read_block( + self.byte_addr / BLOCK_SIZE as u32, + (b.len() / BLOCK_SIZE) as u16, + b, + ) { + // we have to allow partial read, as per the trait required + return Ok(a.len()); + } + } + if let Err(_) = self.read_unaligned(c) { + // we have to allow partial read, as per the trait required + return Ok(a.len() + b.len()); } - self.read_unaligned(c)?; Ok(total_length) } } impl<'a> BufRead for SdReader<'a> { fn fill_buf(&mut self) -> IoResult<&[u8]> { - assert!(self.index <= BLOCK_SIZE, "Invalid index!"); - if self.index == BLOCK_SIZE { // flush the buffer if it is dirty before overwriting it with new data if self.dirty { @@ -146,8 +211,6 @@ impl<'a> BufRead for SdReader<'a> { } fn consume(&mut self, amt: usize) { - assert!(self.index + amt <= BLOCK_SIZE, "Invalid amt!"); - self.index += amt; self.byte_addr += amt as u32; } @@ -159,15 +222,17 @@ impl<'a> Write for SdReader<'a> { self.write_unaligned(a)?; if b.len() > 0 { self.invalidate_buffer(); - self.sd - .write_block( - self.byte_addr / BLOCK_SIZE as u32, - (b.len() / BLOCK_SIZE) as u16, - b, - ) - .map_err(cmd_error_to_io_error)?; + if let Err(_) = self.sd.write_block( + self.byte_addr / BLOCK_SIZE as u32, + (b.len() / BLOCK_SIZE) as u16, + b, + ) { + return Ok(a.len()); + } + } + if let Err(_) = self.write_unaligned(c) { + return Ok(a.len() + b.len()); } - self.write_unaligned(c)?; Ok(buf.len()) } @@ -186,11 +251,11 @@ impl<'a> Write for SdReader<'a> { impl<'a> Seek for SdReader<'a> { fn seek(&mut self, pos: SeekFrom) -> IoResult { let raw_target = match pos { - SeekFrom::Start(x) => x as i64, + SeekFrom::Start(x) => self.offset as i64 + x as i64, SeekFrom::Current(x) => self.byte_addr as i64 + x, SeekFrom::End(_) => panic!("SD card does not support seek from end"), - } + self.offset as i64; - if raw_target < 0 || raw_target > core::u32::MAX as i64 { + }; + if raw_target < self.offset as i64 || raw_target > core::u32::MAX as i64 { return Err(Error::new(ErrorKind::InvalidInput, "Invalid address")); } let target_byte_addr = raw_target as u32; @@ -208,7 +273,7 @@ impl<'a> Seek for SdReader<'a> { // invalidate the buffer as we moved to a different block BLOCK_SIZE }; - Ok(self.byte_addr as u64) + Ok((self.byte_addr - self.offset) as u64) } } @@ -218,3 +283,4 @@ impl<'a> Drop for SdReader<'a> { self.flush().unwrap_or(()); } } + -- 2.44.1 From b4db766560632788831e11819aa649ac1a031938 Mon Sep 17 00:00:00 2001 From: pca006132 Date: Fri, 12 Jun 2020 10:37:39 +0800 Subject: [PATCH 7/7] uncommented comm --- src/runtime/src/main.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/runtime/src/main.rs b/src/runtime/src/main.rs index 02b1fc4..ecbef65 100644 --- a/src/runtime/src/main.rs +++ b/src/runtime/src/main.rs @@ -12,7 +12,7 @@ use libsupport_zynq::ram; mod proto_core_io; mod proto_async; -// mod comms; +mod comms; mod rpc; #[path = "../../../build/pl.rs"] mod pl; @@ -84,5 +84,5 @@ pub fn main_core0() { pl::csr::rtio_core::reset_phy_write(1); } - // comms::main(timer); + comms::main(timer); } -- 2.44.1