add more bugs to find later

This commit is contained in:
ash lea 2023-09-16 19:03:32 -04:00
parent b7acc63225
commit f9192b1d32
7 changed files with 191 additions and 10 deletions

23
Cargo.lock generated
View File

@ -24,6 +24,12 @@ dependencies = [
"num_enum",
]
[[package]]
name = "bit_field"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61"
[[package]]
name = "bitflags"
version = "1.3.2"
@ -98,7 +104,9 @@ dependencies = [
"embedded-io",
"gba",
"gpt-parser",
"itoa",
"log",
"ucs2",
]
[[package]]
@ -122,6 +130,12 @@ dependencies = [
"explicit-endian",
]
[[package]]
name = "itoa"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38"
[[package]]
name = "log"
version = "0.4.19"
@ -177,6 +191,15 @@ dependencies = [
"unicode-ident",
]
[[package]]
name = "ucs2"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bad643914094137d475641b6bab89462505316ec2ce70907ad20102d28a79ab8"
dependencies = [
"bit_field",
]
[[package]]
name = "unicode-ident"
version = "1.0.12"

View File

@ -5,12 +5,14 @@ authors = ["ashkitten"]
edition = "2021"
[dependencies]
ape-fatfs = { version = "0.2.0", default-features = false }
ape-fatfs = { version = "0.2.0", default-features = false, features = ["unicode", "lfn"] }
ape-mbr = "0.1.1"
embedded-io = "0.4.0"
gba = "0.11.2"
gpt-parser = { version = "0.0.9", features = ["no_std"] }
itoa = "1.0.9"
log = "=0.4.19"
ucs2 = "0.3.2"
[profile.dev]
opt-level = 3

View File

@ -25,7 +25,6 @@ SECTIONS {
.data : {
__iwram_start = ABSOLUTE(.);
*(.text .text.*);
*(.data .data.*);
*(.iwram .iwram.*);
. = ALIGN(4);
@ -38,6 +37,7 @@ SECTIONS {
.ewram : {
__ewram_start = ABSOLUTE(.);
*(.text .text.*);
*(.ewram .ewram.*);
. = ALIGN(4);

View File

@ -6,3 +6,12 @@ pub unsafe fn set_rompage(page: u16) {
(0x9880000 as *mut u16).write_volatile(page); //C4
(0x9fc0000 as *mut u16).write_volatile(0x1500);
}
pub unsafe fn set_led_control(status: u16) {
(0x9fe0000 as *mut u16).write_volatile(0xd200);
(0x8000000 as *mut u16).write_volatile(0x1500);
(0x8020000 as *mut u16).write_volatile(0xd200);
(0x8040000 as *mut u16).write_volatile(0x1500);
(0x96E0000 as *mut u16).write_volatile(status);
(0x9fc0000 as *mut u16).write_volatile(0x1500);
}

View File

@ -22,7 +22,8 @@ impl<E> From<ReadExactError<E>> for ErrorKind {
}
/// BS: Block Size, PS: Page Size
// optimally PS would be in terms of BS, but const generics don't allow that yet
/// optimally PS would be in terms of BS, but const generics don't allow that yet
/// BS and PS must be powers of two, and PS must be as large or larger than BS
pub struct BufferedIo<const BS: usize, const PS: usize, IO: BlockIo<BS>> {
io: IO,
/// current stream position
@ -39,6 +40,11 @@ impl<const BS: usize, const PS: usize, IO: BlockIo<BS>> BufferedIo<BS, PS, IO> {
page: None,
}
}
fn lba(&self) -> Lba {
// floor to PS, but in terms of BS
(self.pos / PS * PS / BS) as Lba
}
}
impl<const BS: usize, const PS: usize, IO: BlockIo<BS>> Io for BufferedIo<BS, PS, IO> {
@ -50,9 +56,9 @@ impl<const BS: usize, const PS: usize, IO: BlockIo<BS>> Read for BufferedIo<BS,
// ensure the page at self.pos is loaded
let (lba, page) = self
.page
.filter(|(lba, _)| *lba as usize == self.pos / BS)
.filter(|(lba, _)| *lba == self.lba())
.unwrap_or_else(|| {
let lba = (self.pos / BS) as Lba;
let lba = self.lba();
let mut buf = [0; PS];
self.io.read_blocks(lba, &mut buf).unwrap();
(lba, buf)
@ -73,11 +79,12 @@ impl<const BS: usize, const PS: usize, IO: BlockIo<BS>> Read for BufferedIo<BS,
impl<const BS: usize, const PS: usize, IO: BlockIo<BS>> Write for BufferedIo<BS, PS, IO> {
fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
todo!()
self.pos += buf.len();
Ok(buf.len())
}
fn flush(&mut self) -> Result<(), Self::Error> {
todo!()
Ok(())
}
}

View File

@ -3,10 +3,14 @@
#![no_std]
#![no_main]
use core::str::from_utf8_unchecked;
use ape_fatfs::fs::{FileSystem, FsOptions};
use ape_mbr::{PartitionId, MBR};
use ezflash::set_led_control;
use fs::BufferedIo;
use gba::prelude::*;
use log::Log;
use sd::SdCard;
mod dma;
@ -15,21 +19,144 @@ mod fs;
mod sd;
#[panic_handler]
fn panic_handler(_: &core::panic::PanicInfo) -> ! {
fn panic_handler(info: &core::panic::PanicInfo) -> ! {
unsafe {
// red+green
set_led_control(0b10100000);
}
BACKDROP_COLOR.write(Color::RED);
let mut itoa = itoa::Buffer::new();
let mut pos = 0;
let mut bytes = [0u8; 512];
let mut write = |str: &str| {
// truncate silently
let end = bytes.len().min(pos + str.len());
let len = end - pos;
bytes[pos..end].copy_from_slice(&str.as_bytes()[..len]);
pos = end;
};
write("panic at ");
if let Some(location) = info.location() {
write(location.file().rsplit_terminator('/').next().unwrap());
write(" line ");
write(itoa.format(location.line()));
} else {
write("unknown location");
};
draw_text(unsafe { core::str::from_utf8_unchecked(&bytes) });
loop {}
}
// static LOGGER: ScreenLogger = ScreenLogger::new();
// struct ScreenLogger {
// buf: GbaCell<[u8; 1024]>,
// len: GbaCell<u16>,
// pos: GbaCell<u16>,
// }
// impl ScreenLogger {
// fn new() -> Self {
// Self {
// buf: GbaCell::new([0; 1024]),
// len: GbaCell::new(0),
// pos: GbaCell::new(0),
// }
// }
// }
// impl Log for ScreenLogger {
// fn enabled(&self, metadata: &log::Metadata) -> bool {
// true
// }
// fn log(&self, record: &log::Record) {}
// fn flush(&self) {
// todo!()
// }
// }
extern "C" fn irq_handler(_: IrqBits) {}
fn draw_text(text: &str) {
Cga8x8Thick.bitunpack_4bpp(CHARBLOCK0_4BPP.as_region(), 0);
BG0CNT.write(BackgroundControl::new().with_screenblock(8));
let screenblock = TEXT_SCREENBLOCKS.get_frame(8).unwrap();
for x in 0..32 {
for y in 0..32 {
screenblock
.get(x, y)
.unwrap()
.write(TextEntry::new().with_tile(0));
}
}
for (y, line) in text.split_terminator("\n").take(32).enumerate() {
let row = screenblock.get_row(y).unwrap();
for (x, byte) in line.bytes().take(32).enumerate() {
let text_entry = TextEntry::new().with_tile(byte as u16);
row.get(x).unwrap().write(text_entry);
}
}
DISPCNT.write(DisplayControl::new().with_show_bg0(true));
}
#[no_mangle]
extern "C" fn main() -> ! {
RUST_IRQ_HANDLER.write(Some(irq_handler));
DISPSTAT.write(DisplayStatus::new().with_irq_vblank(true));
IE.write(IrqBits::VBLANK);
IME.write(true);
DISPCNT.write(DisplayControl::new().with_show_bg0(true));
BACKDROP_COLOR.write(Color::YELLOW);
unsafe {
// red+green + blue sd indicator
set_led_control(0b10110001);
}
draw_text("hello world!");
let mut mbr = MBR::new(BufferedIo::<512, 2048, _>::new(SdCard)).unwrap();
let partition = mbr.get_partition(PartitionId::One).unwrap();
let fs = FileSystem::new(partition, FsOptions::new()).unwrap();
BACKDROP_COLOR.write(Color::GREEN);
unsafe {
// green + blue sd indicator
set_led_control(0b10010001);
}
{
let mut pos = 0;
let mut bytes = [0u8; 512];
for entry in fs.root_dir().iter() {
let entry = entry.unwrap();
if let Some(name) = entry.long_file_name_as_ucs2_units() {
pos += ucs2::decode(name, &mut bytes[pos..]).unwrap()
} else {
let name = entry.short_file_name_as_bytes();
bytes[pos..pos + name.len()].copy_from_slice(&name);
pos += name.len();
}
if entry.is_dir() {
bytes[pos..pos + 1].copy_from_slice("/".as_bytes());
pos += 1;
}
bytes[pos..pos + 1].copy_from_slice("\n".as_bytes());
pos += 1;
}
draw_text(unsafe { from_utf8_unchecked(&bytes) });
}
loop {}
}

View File

@ -1,6 +1,9 @@
use core::ffi::c_void;
use core::fmt;
use gba::prelude::BACKDROP_COLOR;
use gba::video::Color;
use crate::delay;
use crate::dma::dma_copy;
use crate::ezflash::set_rompage;
@ -12,6 +15,7 @@ pub enum SdControl {
ReadState = 3,
}
#[link_section = ".iwram"]
pub unsafe fn set_sd_control(control: SdControl) {
(0x9fe0000 as *mut u16).write_volatile(0xd200);
(0x8000000 as *mut u16).write_volatile(0x1500);
@ -21,22 +25,27 @@ pub unsafe fn set_sd_control(control: SdControl) {
(0x9fc0000 as *mut u16).write_volatile(0x1500);
}
#[link_section = ".iwram"]
pub unsafe fn sd_enable() {
set_sd_control(SdControl::Enable);
}
#[link_section = ".iwram"]
pub unsafe fn sd_disable() {
set_sd_control(SdControl::Disable);
}
#[link_section = ".iwram"]
pub unsafe fn sd_read_state() {
set_sd_control(SdControl::ReadState);
}
#[link_section = ".iwram"]
pub unsafe fn sd_response() -> u16 {
(0x9e00000 as *mut u16).read_volatile()
}
#[link_section = ".iwram"]
pub unsafe fn wait_sd_response() -> Result<(), ()> {
for _ in 0..0x100000 {
if sd_response() != 0xeee1 {
@ -77,6 +86,7 @@ impl SdCard {
impl BlockIo<512> for SdCard {
type Error = BlockIoError;
#[link_section = ".iwram"]
fn read_blocks(&mut self, start_lba: Lba, buffer: &mut [u8]) -> Result<(), Self::Error> {
unsafe {
set_rompage(0x8000); // OS mode
@ -94,6 +104,8 @@ impl BlockIo<512> for SdCard {
// try three times to read
for _ in 0..2 {
sd_enable();
(0x9fe0000 as *mut u16).write_volatile(0xd200);
(0x8000000 as *mut u16).write_volatile(0x1500);
(0x8020000 as *mut u16).write_volatile(0xd200);
@ -105,6 +117,7 @@ impl BlockIo<512> for SdCard {
sd_read_state();
if wait_sd_response().is_ok() {
sd_enable();
// successful read!
let src = 0x9e00000 as *mut c_void;
let dst = &mut buffer[i as usize * 512] as *mut u8 as *mut c_void;
@ -114,13 +127,13 @@ impl BlockIo<512> for SdCard {
continue 'chunks;
} else {
// read timed out, try again
sd_enable();
delay(5000);
}
}
// oh no! we couldn't read!
panic!();
BACKDROP_COLOR.write(Color::BLUE);
loop {}
}
sd_disable();