mirror of
https://github.com/italicsjenga/gba.git
synced 2024-12-23 19:01:30 +11:00
update to voladdress-0.4 (#120)
* update to voladdress-0.4 (via git) * restore the imports rust-analyzer told me to break.
This commit is contained in:
parent
7b2a067aad
commit
3bcd64f28c
|
@ -16,8 +16,7 @@ default = []
|
||||||
serial = ["embedded-hal", "nb"]
|
serial = ["embedded-hal", "nb"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
typenum = "1.10"
|
voladdress = { version = "0.4.0-alpha.0", git = "https://github.com/rust-console/voladdress" }
|
||||||
voladdress = "0.2"
|
|
||||||
gba-proc-macro = "0.5"
|
gba-proc-macro = "0.5"
|
||||||
embedded-hal = { version = "0.2.4", optional = true }
|
embedded-hal = { version = "0.2.4", optional = true }
|
||||||
nb = { version = "1.0.0", optional = true }
|
nb = { version = "1.0.0", optional = true }
|
||||||
|
|
|
@ -44,7 +44,7 @@ fn main(_argc: isize, _argv: *const *const u8) -> isize {
|
||||||
irq::set_irq_handler(irq_handler);
|
irq::set_irq_handler(irq_handler);
|
||||||
|
|
||||||
// Enable all interrupts that are set in the IE register.
|
// Enable all interrupts that are set in the IE register.
|
||||||
IME.write(IrqEnableSetting::IRQ_YES);
|
unsafe { IME.write(IrqEnableSetting::IRQ_YES) };
|
||||||
|
|
||||||
// Request that VBlank, HBlank and VCount will generate IRQs.
|
// Request that VBlank, HBlank and VCount will generate IRQs.
|
||||||
const DISPLAY_SETTINGS: DisplayStatusSetting = DisplayStatusSetting::new()
|
const DISPLAY_SETTINGS: DisplayStatusSetting = DisplayStatusSetting::new()
|
||||||
|
@ -78,7 +78,7 @@ fn main(_argc: isize, _argv: *const *const u8) -> isize {
|
||||||
flags = flags.with_timer1(true);
|
flags = flags.with_timer1(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
IE.write(flags);
|
unsafe { IE.write(flags) };
|
||||||
|
|
||||||
// Puts the CPU into low power mode until a VBlank IRQ is received. This
|
// Puts the CPU into low power mode until a VBlank IRQ is received. This
|
||||||
// will yield considerably better power efficiency as opposed to spin
|
// will yield considerably better power efficiency as opposed to spin
|
||||||
|
@ -119,29 +119,29 @@ fn vblank_handler() {
|
||||||
|
|
||||||
// When using `interrupt_wait()` or `vblank_interrupt_wait()`, IRQ handlers must acknowledge
|
// When using `interrupt_wait()` or `vblank_interrupt_wait()`, IRQ handlers must acknowledge
|
||||||
// the IRQ on the BIOS Interrupt Flags register.
|
// the IRQ on the BIOS Interrupt Flags register.
|
||||||
BIOS_IF.write(BIOS_IF.read().with_vblank(true));
|
unsafe { BIOS_IF.write(BIOS_IF.read().with_vblank(true)) };
|
||||||
}
|
}
|
||||||
|
|
||||||
fn hblank_handler() {
|
fn hblank_handler() {
|
||||||
write_pixel(GREEN);
|
write_pixel(GREEN);
|
||||||
|
|
||||||
BIOS_IF.write(BIOS_IF.read().with_hblank(true));
|
unsafe { BIOS_IF.write(BIOS_IF.read().with_hblank(true)) };
|
||||||
}
|
}
|
||||||
|
|
||||||
fn vcounter_handler() {
|
fn vcounter_handler() {
|
||||||
write_pixel(RED);
|
write_pixel(RED);
|
||||||
|
|
||||||
BIOS_IF.write(BIOS_IF.read().with_vcounter(true));
|
unsafe { BIOS_IF.write(BIOS_IF.read().with_vcounter(true)) };
|
||||||
}
|
}
|
||||||
|
|
||||||
fn timer0_handler() {
|
fn timer0_handler() {
|
||||||
write_pixel(YELLOW);
|
write_pixel(YELLOW);
|
||||||
|
|
||||||
BIOS_IF.write(BIOS_IF.read().with_timer0(true));
|
unsafe { BIOS_IF.write(BIOS_IF.read().with_timer0(true)) };
|
||||||
}
|
}
|
||||||
|
|
||||||
fn timer1_handler() {
|
fn timer1_handler() {
|
||||||
write_pixel(PINK);
|
write_pixel(PINK);
|
||||||
|
|
||||||
BIOS_IF.write(BIOS_IF.read().with_timer1(true));
|
unsafe { BIOS_IF.write(BIOS_IF.read().with_timer1(true)) };
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,14 +4,14 @@
|
||||||
|
|
||||||
use core::cmp;
|
use core::cmp;
|
||||||
use gba::{
|
use gba::{
|
||||||
fatal, warn,
|
fatal,
|
||||||
io::{
|
io::{
|
||||||
display::{DisplayControlSetting, DisplayMode, DISPCNT},
|
display::{DisplayControlSetting, DisplayMode, DISPCNT},
|
||||||
timers::{TimerControlSetting, TimerTickRate, TM0CNT_H, TM0CNT_L, TM1CNT_H, TM1CNT_L},
|
timers::{TimerControlSetting, TimerTickRate, TM0CNT_H, TM0CNT_L, TM1CNT_H, TM1CNT_L},
|
||||||
},
|
},
|
||||||
save::*,
|
save::*,
|
||||||
vram::bitmap::Mode3,
|
vram::bitmap::Mode3,
|
||||||
Color,
|
warn, Color,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn set_screen_color(r: u16, g: u16, b: u16) {
|
fn set_screen_color(r: u16, g: u16, b: u16) {
|
||||||
|
@ -34,7 +34,6 @@ fn set_screen_progress(cur: usize, max: usize) {
|
||||||
fn panic(info: &core::panic::PanicInfo) -> ! {
|
fn panic(info: &core::panic::PanicInfo) -> ! {
|
||||||
set_screen_color(31, 0, 0);
|
set_screen_color(31, 0, 0);
|
||||||
fatal!("{}", info);
|
fatal!("{}", info);
|
||||||
loop {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
@ -90,7 +89,7 @@ fn do_test(seed: Rng, offset: usize, len: usize, block_size: usize) -> Result<()
|
||||||
let mut buffer = [0; MAX_BLOCK_SIZE];
|
let mut buffer = [0; MAX_BLOCK_SIZE];
|
||||||
|
|
||||||
output!(" - Clearing media...");
|
output!(" - Clearing media...");
|
||||||
access.prepare_write(offset..offset+len)?;
|
access.prepare_write(offset..offset + len)?;
|
||||||
|
|
||||||
output!(" - Writing media...");
|
output!(" - Writing media...");
|
||||||
let mut rng = seed.clone();
|
let mut rng = seed.clone();
|
||||||
|
@ -168,7 +167,9 @@ fn main(_argc: isize, _argv: *const *const u8) -> isize {
|
||||||
|
|
||||||
output!(
|
output!(
|
||||||
"[ Partial, offset = 0x{:06x}, len = {}, bs = {}]",
|
"[ Partial, offset = 0x{:06x}, len = {}, bs = {}]",
|
||||||
rand_offset, rand_length, block_size,
|
rand_offset,
|
||||||
|
rand_length,
|
||||||
|
block_size,
|
||||||
);
|
);
|
||||||
check_status(do_test(Rng(i * 10000), rand_offset, rand_length, block_size));
|
check_status(do_test(Rng(i * 10000), rand_offset, rand_length, block_size));
|
||||||
set_screen_progress(3 + i as usize, 10);
|
set_screen_progress(3 + i as usize, 10);
|
||||||
|
@ -176,5 +177,5 @@ fn main(_argc: isize, _argv: *const *const u8) -> isize {
|
||||||
|
|
||||||
// show a pattern so we know it worked
|
// show a pattern so we know it worked
|
||||||
set_screen_color(0, 31, 0);
|
set_screen_color(0, 31, 0);
|
||||||
loop { }
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,6 @@
|
||||||
|
|
||||||
#![cfg_attr(not(target_arch = "arm"), allow(unused_variables))]
|
#![cfg_attr(not(target_arch = "arm"), allow(unused_variables))]
|
||||||
|
|
||||||
use core::mem;
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use io::irq::IrqFlags;
|
use io::irq::IrqFlags;
|
||||||
|
|
||||||
|
@ -184,8 +183,8 @@ pub fn interrupt_wait(ignore_current_flags: bool, target_flags: IrqFlags) {
|
||||||
unsafe {
|
unsafe {
|
||||||
asm!(
|
asm!(
|
||||||
"swi 0x04",
|
"swi 0x04",
|
||||||
in("r0") mem::transmute::<bool, u8>(ignore_current_flags),
|
in("r0") ignore_current_flags as u8,
|
||||||
in("r1") mem::transmute::<IrqFlags, u16>(target_flags),
|
in("r1") target_flags.0,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
11
src/debug.rs
11
src/debug.rs
|
@ -3,15 +3,8 @@
|
||||||
//! This is the underlying implementation behind the various print macros in
|
//! This is the underlying implementation behind the various print macros in
|
||||||
//! the gba crate. It currently supports the latest versions of mGBA and NO$GBA.
|
//! the gba crate. It currently supports the latest versions of mGBA and NO$GBA.
|
||||||
|
|
||||||
use crate::{
|
use crate::sync::{InitOnce, RawMutex, Static};
|
||||||
io::{
|
|
||||||
dma::{DMAControlSetting, DMA0, DMA1, DMA2, DMA3},
|
|
||||||
irq::{IrqEnableSetting, IME},
|
|
||||||
},
|
|
||||||
sync::{InitOnce, RawMutex, Static},
|
|
||||||
};
|
|
||||||
use core::fmt::{Arguments, Error};
|
use core::fmt::{Arguments, Error};
|
||||||
use voladdress::VolAddress;
|
|
||||||
|
|
||||||
pub mod mgba;
|
pub mod mgba;
|
||||||
pub mod nocash;
|
pub mod nocash;
|
||||||
|
@ -127,5 +120,5 @@ pub fn crash() -> ! {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(all(target_vendor = "nintendo", target_env = "agb")))]
|
#[cfg(not(all(target_vendor = "nintendo", target_env = "agb")))]
|
||||||
loop { }
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
use super::{DebugInterface, DebugLevel};
|
use super::{DebugInterface, DebugLevel};
|
||||||
use crate::sync::InitOnce;
|
use crate::sync::InitOnce;
|
||||||
use core::fmt::{Arguments, Write};
|
use core::fmt::{Arguments, Write};
|
||||||
use voladdress::VolAddress;
|
use voladdress::*;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
#[repr(u16)]
|
#[repr(u16)]
|
||||||
|
@ -22,13 +22,13 @@ pub enum MGBADebugLevel {
|
||||||
}
|
}
|
||||||
|
|
||||||
// MGBADebug related addresses.
|
// MGBADebug related addresses.
|
||||||
const ENABLE_ADDRESS: VolAddress<u16> = unsafe { VolAddress::new(0x4fff780) };
|
const ENABLE_ADDRESS: VolAddress<u16, Safe, Safe> = unsafe { VolAddress::new(0x4fff780) };
|
||||||
const ENABLE_ADDRESS_INPUT: u16 = 0xC0DE;
|
const ENABLE_ADDRESS_INPUT: u16 = 0xC0DE;
|
||||||
const ENABLE_ADDRESS_OUTPUT: u16 = 0x1DEA;
|
const ENABLE_ADDRESS_OUTPUT: u16 = 0x1DEA;
|
||||||
|
|
||||||
const OUTPUT_BASE: VolAddress<u8> = unsafe { VolAddress::new(0x4fff600) };
|
const OUTPUT_BLOCK: VolBlock<u8, Safe, Safe, 256> = unsafe { VolBlock::new(0x4fff600) };
|
||||||
|
|
||||||
const SEND_ADDRESS: VolAddress<u16> = unsafe { VolAddress::new(0x4fff700) };
|
const SEND_ADDRESS: VolAddress<u16, Safe, Safe> = unsafe { VolAddress::new(0x4fff700) };
|
||||||
const SEND_FLAG: u16 = 0x100;
|
const SEND_FLAG: u16 = 0x100;
|
||||||
|
|
||||||
// Only enable MGBA debugging once.
|
// Only enable MGBA debugging once.
|
||||||
|
@ -82,7 +82,7 @@ impl MGBADebug {
|
||||||
impl core::fmt::Write for MGBADebug {
|
impl core::fmt::Write for MGBADebug {
|
||||||
fn write_str(&mut self, s: &str) -> Result<(), core::fmt::Error> {
|
fn write_str(&mut self, s: &str) -> Result<(), core::fmt::Error> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut current = OUTPUT_BASE.offset(self.bytes_written as isize);
|
let mut current = OUTPUT_BLOCK.index(self.bytes_written as usize);
|
||||||
let mut str_iter = s.bytes();
|
let mut str_iter = s.bytes();
|
||||||
while self.bytes_written < 255 {
|
while self.bytes_written < 255 {
|
||||||
match str_iter.next() {
|
match str_iter.next() {
|
||||||
|
|
|
@ -9,11 +9,10 @@ use crate::{
|
||||||
sync::InitOnce,
|
sync::InitOnce,
|
||||||
};
|
};
|
||||||
use core::fmt::{Arguments, Write};
|
use core::fmt::{Arguments, Write};
|
||||||
use typenum::consts::U16;
|
use voladdress::*;
|
||||||
use voladdress::{VolAddress, VolBlock};
|
|
||||||
|
|
||||||
const CHAR_OUT: VolAddress<u8> = unsafe { VolAddress::new(0x04FFFA1C) };
|
const CHAR_OUT: VolAddress<u8, Safe, Safe> = unsafe { VolAddress::new(0x04FFFA1C) };
|
||||||
const SIGNATURE_ADDR: VolBlock<u8, U16> = unsafe { VolBlock::new(0x04FFFA00) };
|
const SIGNATURE_ADDR: VolBlock<u8, Safe, Safe, 16> = unsafe { VolBlock::new(0x04FFFA00) };
|
||||||
|
|
||||||
const SIGNATURE: [u8; 7] = *b"no$gba ";
|
const SIGNATURE: [u8; 7] = *b"no$gba ";
|
||||||
static NO_CASH_DEBUGGING: InitOnce<bool> = InitOnce::new();
|
static NO_CASH_DEBUGGING: InitOnce<bool> = InitOnce::new();
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
#![allow(non_camel_case_types)]
|
#![allow(non_camel_case_types)]
|
||||||
|
// Note(Lokathor): NOT CURRENTLY USED.
|
||||||
|
//
|
||||||
|
// If we want this in the future we can convert it to const generics.
|
||||||
|
|
||||||
//! Module for fixed point math types and operations.
|
//! Module for fixed point math types and operations.
|
||||||
|
|
|
@ -3,13 +3,17 @@
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
/// BG0 Control. Read/Write. Display Mode 0/1 only.
|
/// BG0 Control. Read/Write. Display Mode 0/1 only.
|
||||||
pub const BG0CNT: VolAddress<BackgroundControlSetting> = unsafe { VolAddress::new(0x400_0008) };
|
pub const BG0CNT: VolAddress<BackgroundControlSetting, Safe, Safe> =
|
||||||
|
unsafe { VolAddress::new(0x400_0008) };
|
||||||
/// BG1 Control. Read/Write. Display Mode 0/1 only.
|
/// BG1 Control. Read/Write. Display Mode 0/1 only.
|
||||||
pub const BG1CNT: VolAddress<BackgroundControlSetting> = unsafe { VolAddress::new(0x400_000A) };
|
pub const BG1CNT: VolAddress<BackgroundControlSetting, Safe, Safe> =
|
||||||
|
unsafe { VolAddress::new(0x400_000A) };
|
||||||
/// BG2 Control. Read/Write. Display Mode 0/1/2 only.
|
/// BG2 Control. Read/Write. Display Mode 0/1/2 only.
|
||||||
pub const BG2CNT: VolAddress<BackgroundControlSetting> = unsafe { VolAddress::new(0x400_000C) };
|
pub const BG2CNT: VolAddress<BackgroundControlSetting, Safe, Safe> =
|
||||||
|
unsafe { VolAddress::new(0x400_000C) };
|
||||||
/// BG3 Control. Read/Write. Display Mode 0/2 only.
|
/// BG3 Control. Read/Write. Display Mode 0/2 only.
|
||||||
pub const BG3CNT: VolAddress<BackgroundControlSetting> = unsafe { VolAddress::new(0x400_000E) };
|
pub const BG3CNT: VolAddress<BackgroundControlSetting, Safe, Safe> =
|
||||||
|
unsafe { VolAddress::new(0x400_000E) };
|
||||||
|
|
||||||
newtype! {
|
newtype! {
|
||||||
/// Allows configuration of a background layer.
|
/// Allows configuration of a background layer.
|
||||||
|
@ -66,24 +70,24 @@ pub enum BGSize {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// BG0 X-Offset. Write only. Text mode only. 9 bits.
|
/// BG0 X-Offset. Write only. Text mode only. 9 bits.
|
||||||
pub const BG0HOFS: VolAddress<u16> = unsafe { VolAddress::new(0x400_0010) };
|
pub const BG0HOFS: VolAddress<u16, Safe, Safe> = unsafe { VolAddress::new(0x400_0010) };
|
||||||
/// BG0 Y-Offset. Write only. Text mode only. 9 bits.
|
/// BG0 Y-Offset. Write only. Text mode only. 9 bits.
|
||||||
pub const BG0VOFS: VolAddress<u16> = unsafe { VolAddress::new(0x400_0012) };
|
pub const BG0VOFS: VolAddress<u16, Safe, Safe> = unsafe { VolAddress::new(0x400_0012) };
|
||||||
|
|
||||||
/// BG1 X-Offset. Write only. Text mode only. 9 bits.
|
/// BG1 X-Offset. Write only. Text mode only. 9 bits.
|
||||||
pub const BG1HOFS: VolAddress<u16> = unsafe { VolAddress::new(0x400_0014) };
|
pub const BG1HOFS: VolAddress<u16, Safe, Safe> = unsafe { VolAddress::new(0x400_0014) };
|
||||||
/// BG1 Y-Offset. Write only. Text mode only. 9 bits.
|
/// BG1 Y-Offset. Write only. Text mode only. 9 bits.
|
||||||
pub const BG1VOFS: VolAddress<u16> = unsafe { VolAddress::new(0x400_0016) };
|
pub const BG1VOFS: VolAddress<u16, Safe, Safe> = unsafe { VolAddress::new(0x400_0016) };
|
||||||
|
|
||||||
/// BG2 X-Offset. Write only. Text mode only. 9 bits.
|
/// BG2 X-Offset. Write only. Text mode only. 9 bits.
|
||||||
pub const BG2HOFS: VolAddress<u16> = unsafe { VolAddress::new(0x400_0018) };
|
pub const BG2HOFS: VolAddress<u16, Safe, Safe> = unsafe { VolAddress::new(0x400_0018) };
|
||||||
/// BG2 Y-Offset. Write only. Text mode only. 9 bits.
|
/// BG2 Y-Offset. Write only. Text mode only. 9 bits.
|
||||||
pub const BG2VOFS: VolAddress<u16> = unsafe { VolAddress::new(0x400_001A) };
|
pub const BG2VOFS: VolAddress<u16, Safe, Safe> = unsafe { VolAddress::new(0x400_001A) };
|
||||||
|
|
||||||
/// BG3 X-Offset. Write only. Text mode only. 9 bits.
|
/// BG3 X-Offset. Write only. Text mode only. 9 bits.
|
||||||
pub const BG3HOFS: VolAddress<u16> = unsafe { VolAddress::new(0x400_001C) };
|
pub const BG3HOFS: VolAddress<u16, Safe, Safe> = unsafe { VolAddress::new(0x400_001C) };
|
||||||
/// BG3 Y-Offset. Write only. Text mode only. 9 bits.
|
/// BG3 Y-Offset. Write only. Text mode only. 9 bits.
|
||||||
pub const BG3VOFS: VolAddress<u16> = unsafe { VolAddress::new(0x400_001E) };
|
pub const BG3VOFS: VolAddress<u16, Safe, Safe> = unsafe { VolAddress::new(0x400_001E) };
|
||||||
|
|
||||||
// TODO: affine backgrounds
|
// TODO: affine backgrounds
|
||||||
// BG2X_L
|
// BG2X_L
|
||||||
|
|
|
@ -3,7 +3,8 @@
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
/// Color Special Effects Selection (R/W)
|
/// Color Special Effects Selection (R/W)
|
||||||
pub const BLDCNT: VolAddress<ColorEffectSetting> = unsafe { VolAddress::new(0x400_0050) };
|
pub const BLDCNT: VolAddress<ColorEffectSetting, Safe, Safe> =
|
||||||
|
unsafe { VolAddress::new(0x400_0050) };
|
||||||
|
|
||||||
newtype! {
|
newtype! {
|
||||||
/// TODO: docs
|
/// TODO: docs
|
||||||
|
@ -43,7 +44,8 @@ newtype_enum! {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Alpha Blending Coefficients (R/W) (not W)
|
/// Alpha Blending Coefficients (R/W) (not W)
|
||||||
pub const BLDALPHA: VolAddress<AlphaBlendingSetting> = unsafe { VolAddress::new(0x400_0052) };
|
pub const BLDALPHA: VolAddress<AlphaBlendingSetting, Safe, Safe> =
|
||||||
|
unsafe { VolAddress::new(0x400_0052) };
|
||||||
|
|
||||||
newtype! {
|
newtype! {
|
||||||
/// TODO: docs
|
/// TODO: docs
|
||||||
|
@ -59,7 +61,7 @@ impl AlphaBlendingSetting {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Brightness (Fade-In/Out) Coefficient (W) (not R/W)
|
/// Brightness (Fade-In/Out) Coefficient (W) (not R/W)
|
||||||
pub const BLDY: VolAddress<BrightnessSetting> = unsafe { VolAddress::new(0x400_0054) };
|
pub const BLDY: VolAddress<BrightnessSetting, Safe, Safe> = unsafe { VolAddress::new(0x400_0054) };
|
||||||
|
|
||||||
newtype! {
|
newtype! {
|
||||||
/// TODO: docs
|
/// TODO: docs
|
||||||
|
|
|
@ -5,7 +5,8 @@ use super::*;
|
||||||
/// LCD Control. Read/Write.
|
/// LCD Control. Read/Write.
|
||||||
///
|
///
|
||||||
/// The "force vblank" bit is always set when your Rust code first executes.
|
/// The "force vblank" bit is always set when your Rust code first executes.
|
||||||
pub const DISPCNT: VolAddress<DisplayControlSetting> = unsafe { VolAddress::new(0x400_0000) };
|
pub const DISPCNT: VolAddress<DisplayControlSetting, Safe, Safe> =
|
||||||
|
unsafe { VolAddress::new(0x400_0000) };
|
||||||
|
|
||||||
newtype!(
|
newtype!(
|
||||||
/// Setting for the display control register.
|
/// Setting for the display control register.
|
||||||
|
@ -96,7 +97,8 @@ pub fn display_control() -> DisplayControlSetting {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Display Status and IRQ Control. Read/Write.
|
/// Display Status and IRQ Control. Read/Write.
|
||||||
pub const DISPSTAT: VolAddress<DisplayStatusSetting> = unsafe { VolAddress::new(0x400_0004) };
|
pub const DISPSTAT: VolAddress<DisplayStatusSetting, Safe, Safe> =
|
||||||
|
unsafe { VolAddress::new(0x400_0004) };
|
||||||
|
|
||||||
newtype!(
|
newtype!(
|
||||||
/// A newtype over display status and interrupt control values.
|
/// A newtype over display status and interrupt control values.
|
||||||
|
@ -122,13 +124,13 @@ impl DisplayStatusSetting {
|
||||||
/// Gives the current scanline that the display controller is working on. If
|
/// Gives the current scanline that the display controller is working on. If
|
||||||
/// this is at or above the `VBLANK_SCANLINE` value then the display controller
|
/// this is at or above the `VBLANK_SCANLINE` value then the display controller
|
||||||
/// is in a "vertical blank" period.
|
/// is in a "vertical blank" period.
|
||||||
pub const VCOUNT: ROVolAddress<u16> = unsafe { ROVolAddress::new(0x400_0006) };
|
pub const VCOUNT: VolAddress<u16, Safe, ()> = unsafe { VolAddress::new(0x400_0006) };
|
||||||
|
|
||||||
/// If the `VCOUNT` register reads equal to or above this then you're in vblank.
|
/// If the `VCOUNT` register reads equal to or above this then you're in vblank.
|
||||||
pub const VBLANK_SCANLINE: u16 = 160;
|
pub const VBLANK_SCANLINE: u16 = 160;
|
||||||
|
|
||||||
/// Global mosaic effect control. Write-only.
|
/// Global mosaic effect control. Write-only.
|
||||||
pub const MOSAIC: VolAddress<MosaicSetting> = unsafe { VolAddress::new(0x400_004C) };
|
pub const MOSAIC: VolAddress<MosaicSetting, Safe, Safe> = unsafe { VolAddress::new(0x400_004C) };
|
||||||
|
|
||||||
newtype! {
|
newtype! {
|
||||||
/// Allows control of the Mosaic effect.
|
/// Allows control of the Mosaic effect.
|
||||||
|
|
|
@ -127,13 +127,14 @@ pub enum DMAStartTiming {
|
||||||
pub struct DMA0;
|
pub struct DMA0;
|
||||||
impl DMA0 {
|
impl DMA0 {
|
||||||
/// DMA 0 Source Address, read only.
|
/// DMA 0 Source Address, read only.
|
||||||
const DMA0SAD: VolAddress<*const u32> = unsafe { VolAddress::new(0x400_00B0) };
|
const DMA0SAD: VolAddress<*const u32, Safe, Unsafe> = unsafe { VolAddress::new(0x400_00B0) };
|
||||||
/// DMA 0 Destination Address, read only.
|
/// DMA 0 Destination Address, read only.
|
||||||
const DMA0DAD: VolAddress<*mut u32> = unsafe { VolAddress::new(0x400_00B4) };
|
const DMA0DAD: VolAddress<*mut u32, Safe, Unsafe> = unsafe { VolAddress::new(0x400_00B4) };
|
||||||
/// DMA 0 Word Count, read only.
|
/// DMA 0 Word Count, read only.
|
||||||
const DMA0CNT_L: VolAddress<u16> = unsafe { VolAddress::new(0x400_00B8) };
|
const DMA0CNT_L: VolAddress<u16, Safe, Unsafe> = unsafe { VolAddress::new(0x400_00B8) };
|
||||||
/// DMA 0 Control, read/write.
|
/// DMA 0 Control, read/write.
|
||||||
const DMA0CNT_H: VolAddress<DMAControlSetting> = unsafe { VolAddress::new(0x400_00BA) };
|
const DMA0CNT_H: VolAddress<DMAControlSetting, Safe, Unsafe> =
|
||||||
|
unsafe { VolAddress::new(0x400_00BA) };
|
||||||
|
|
||||||
/// Assigns the source register.
|
/// Assigns the source register.
|
||||||
///
|
///
|
||||||
|
@ -190,13 +191,14 @@ impl DMA0 {
|
||||||
pub struct DMA1;
|
pub struct DMA1;
|
||||||
impl DMA1 {
|
impl DMA1 {
|
||||||
/// DMA 1 Source Address, read only.
|
/// DMA 1 Source Address, read only.
|
||||||
const DMA1SAD: VolAddress<*const u32> = unsafe { VolAddress::new(0x400_00BC) };
|
const DMA1SAD: VolAddress<*const u32, Safe, Unsafe> = unsafe { VolAddress::new(0x400_00BC) };
|
||||||
/// DMA 1 Destination Address, read only.
|
/// DMA 1 Destination Address, read only.
|
||||||
const DMA1DAD: VolAddress<*mut u32> = unsafe { VolAddress::new(0x400_00C0) };
|
const DMA1DAD: VolAddress<*mut u32, Safe, Unsafe> = unsafe { VolAddress::new(0x400_00C0) };
|
||||||
/// DMA 1 Word Count, read only.
|
/// DMA 1 Word Count, read only.
|
||||||
const DMA1CNT_L: VolAddress<u16> = unsafe { VolAddress::new(0x400_00C4) };
|
const DMA1CNT_L: VolAddress<u16, Safe, Unsafe> = unsafe { VolAddress::new(0x400_00C4) };
|
||||||
/// DMA 1 Control, read/write.
|
/// DMA 1 Control, read/write.
|
||||||
const DMA1CNT_H: VolAddress<DMAControlSetting> = unsafe { VolAddress::new(0x400_00C6) };
|
const DMA1CNT_H: VolAddress<DMAControlSetting, Safe, Unsafe> =
|
||||||
|
unsafe { VolAddress::new(0x400_00C6) };
|
||||||
|
|
||||||
/// Assigns the source register.
|
/// Assigns the source register.
|
||||||
///
|
///
|
||||||
|
@ -253,13 +255,14 @@ impl DMA1 {
|
||||||
pub struct DMA2;
|
pub struct DMA2;
|
||||||
impl DMA2 {
|
impl DMA2 {
|
||||||
/// DMA 2 Source Address, read only.
|
/// DMA 2 Source Address, read only.
|
||||||
const DMA2SAD: VolAddress<*const u32> = unsafe { VolAddress::new(0x400_00C8) };
|
const DMA2SAD: VolAddress<*const u32, Safe, Unsafe> = unsafe { VolAddress::new(0x400_00C8) };
|
||||||
/// DMA 2 Destination Address, read only.
|
/// DMA 2 Destination Address, read only.
|
||||||
const DMA2DAD: VolAddress<*mut u32> = unsafe { VolAddress::new(0x400_00CC) };
|
const DMA2DAD: VolAddress<*mut u32, Safe, Unsafe> = unsafe { VolAddress::new(0x400_00CC) };
|
||||||
/// DMA 2 Word Count, read only.
|
/// DMA 2 Word Count, read only.
|
||||||
const DMA2CNT_L: VolAddress<u16> = unsafe { VolAddress::new(0x400_00D0) };
|
const DMA2CNT_L: VolAddress<u16, Safe, Unsafe> = unsafe { VolAddress::new(0x400_00D0) };
|
||||||
/// DMA 2 Control, read/write.
|
/// DMA 2 Control, read/write.
|
||||||
const DMA2CNT_H: VolAddress<DMAControlSetting> = unsafe { VolAddress::new(0x400_00D2) };
|
const DMA2CNT_H: VolAddress<DMAControlSetting, Safe, Unsafe> =
|
||||||
|
unsafe { VolAddress::new(0x400_00D2) };
|
||||||
|
|
||||||
/// Assigns the source register.
|
/// Assigns the source register.
|
||||||
///
|
///
|
||||||
|
@ -317,13 +320,14 @@ impl DMA2 {
|
||||||
pub struct DMA3;
|
pub struct DMA3;
|
||||||
impl DMA3 {
|
impl DMA3 {
|
||||||
/// DMA 3 Source Address, read only.
|
/// DMA 3 Source Address, read only.
|
||||||
const DMA3SAD: VolAddress<*const u32> = unsafe { VolAddress::new(0x400_00D4) };
|
const DMA3SAD: VolAddress<*const u32, Safe, Unsafe> = unsafe { VolAddress::new(0x400_00D4) };
|
||||||
/// DMA 3 Destination Address, read only.
|
/// DMA 3 Destination Address, read only.
|
||||||
const DMA3DAD: VolAddress<*mut u32> = unsafe { VolAddress::new(0x400_00D8) };
|
const DMA3DAD: VolAddress<*mut u32, Safe, Unsafe> = unsafe { VolAddress::new(0x400_00D8) };
|
||||||
/// DMA 3 Word Count, read only.
|
/// DMA 3 Word Count, read only.
|
||||||
const DMA3CNT_L: VolAddress<u16> = unsafe { VolAddress::new(0x400_00DC) };
|
const DMA3CNT_L: VolAddress<u16, Safe, Unsafe> = unsafe { VolAddress::new(0x400_00DC) };
|
||||||
/// DMA 3 Control, read/write.
|
/// DMA 3 Control, read/write.
|
||||||
const DMA3CNT_H: VolAddress<DMAControlSetting> = unsafe { VolAddress::new(0x400_00DE) };
|
const DMA3CNT_H: VolAddress<DMAControlSetting, Safe, Unsafe> =
|
||||||
|
unsafe { VolAddress::new(0x400_00DE) };
|
||||||
|
|
||||||
/// Assigns the source register.
|
/// Assigns the source register.
|
||||||
///
|
///
|
||||||
|
|
|
@ -103,7 +103,7 @@ use super::*;
|
||||||
newtype!(
|
newtype!(
|
||||||
/// A newtype over all interrupt flags.
|
/// A newtype over all interrupt flags.
|
||||||
IrqFlags,
|
IrqFlags,
|
||||||
u16
|
pub(crate) u16
|
||||||
);
|
);
|
||||||
|
|
||||||
impl IrqFlags {
|
impl IrqFlags {
|
||||||
|
@ -130,7 +130,7 @@ impl IrqFlags {
|
||||||
///
|
///
|
||||||
/// After setting up interrupt handlers, set the flags on this register type corresponding to the
|
/// After setting up interrupt handlers, set the flags on this register type corresponding to the
|
||||||
/// IRQs you want to handle.
|
/// IRQs you want to handle.
|
||||||
pub const IE: VolAddress<IrqFlags> = unsafe { VolAddress::new(0x400_0200) };
|
pub const IE: VolAddress<IrqFlags, Safe, Unsafe> = unsafe { VolAddress::new(0x400_0200) };
|
||||||
|
|
||||||
/// Interrupt Request Flags / IRQ Acknowledge. Read/Write.
|
/// Interrupt Request Flags / IRQ Acknowledge. Read/Write.
|
||||||
///
|
///
|
||||||
|
@ -139,7 +139,7 @@ pub const IE: VolAddress<IrqFlags> = unsafe { VolAddress::new(0x400_0200) };
|
||||||
/// However, if the main interrupt handler in `rsrt0.S` is changed, then the
|
/// However, if the main interrupt handler in `rsrt0.S` is changed, then the
|
||||||
/// handler must write a `1` bit to all bits that are enabled on this register
|
/// handler must write a `1` bit to all bits that are enabled on this register
|
||||||
/// when it is called.
|
/// when it is called.
|
||||||
pub const IF: VolAddress<IrqFlags> = unsafe { VolAddress::new(0x400_0202) };
|
pub const IF: VolAddress<IrqFlags, Safe, Unsafe> = unsafe { VolAddress::new(0x400_0202) };
|
||||||
|
|
||||||
newtype! {
|
newtype! {
|
||||||
/// Setting to control whether interrupts are enabled.
|
/// Setting to control whether interrupts are enabled.
|
||||||
|
@ -161,7 +161,7 @@ impl IrqEnableSetting {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Interrupt Master Enable Register. Read/Write.
|
/// Interrupt Master Enable Register. Read/Write.
|
||||||
pub const IME: VolAddress<IrqEnableSetting> = unsafe { VolAddress::new(0x400_0208) };
|
pub const IME: VolAddress<IrqEnableSetting, Safe, Unsafe> = unsafe { VolAddress::new(0x400_0208) };
|
||||||
|
|
||||||
/// BIOS Interrupt Flags. Read/Write.
|
/// BIOS Interrupt Flags. Read/Write.
|
||||||
///
|
///
|
||||||
|
@ -169,7 +169,7 @@ pub const IME: VolAddress<IrqEnableSetting> = unsafe { VolAddress::new(0x400_020
|
||||||
/// [`vblank_interrupt_wait`](bios::vblank_interrupt_wait), the corresponding
|
/// [`vblank_interrupt_wait`](bios::vblank_interrupt_wait), the corresponding
|
||||||
/// interrupt handler MUST set the flag of the interrupt it has handled on this
|
/// interrupt handler MUST set the flag of the interrupt it has handled on this
|
||||||
/// register in addition to the usual interrupt acknowledgement.
|
/// register in addition to the usual interrupt acknowledgement.
|
||||||
pub const BIOS_IF: VolAddress<IrqFlags> = unsafe { VolAddress::new(0x0300_7FF8) };
|
pub const BIOS_IF: VolAddress<IrqFlags, Safe, Unsafe> = unsafe { VolAddress::new(0x0300_7FF8) };
|
||||||
|
|
||||||
/// A function pointer for use as an interrupt handler.
|
/// A function pointer for use as an interrupt handler.
|
||||||
pub type IrqHandler = extern "C" fn(IrqFlags);
|
pub type IrqHandler = extern "C" fn(IrqFlags);
|
||||||
|
|
|
@ -8,7 +8,7 @@ use super::*;
|
||||||
/// follow the "high-active" convention (hint: you probably do, it's far easier
|
/// follow the "high-active" convention (hint: you probably do, it's far easier
|
||||||
/// to work with) then call `read_key_input()` rather than reading this register
|
/// to work with) then call `read_key_input()` rather than reading this register
|
||||||
/// directly. It will perform the necessary bit flip operation for you.
|
/// directly. It will perform the necessary bit flip operation for you.
|
||||||
pub const KEYINPUT: ROVolAddress<u16> = unsafe { ROVolAddress::new(0x400_0130) };
|
pub const KEYINPUT: VolAddress<u16, Safe, ()> = unsafe { VolAddress::new(0x400_0130) };
|
||||||
|
|
||||||
/// A "tribool" value helps us interpret the arrow pad.
|
/// A "tribool" value helps us interpret the arrow pad.
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
@ -88,7 +88,8 @@ pub fn read_key_input() -> KeyInput {
|
||||||
/// Use this to configure when a keypad interrupt happens.
|
/// Use this to configure when a keypad interrupt happens.
|
||||||
///
|
///
|
||||||
/// See the `KeyInterruptSetting` type for more.
|
/// See the `KeyInterruptSetting` type for more.
|
||||||
pub const KEYCNT: VolAddress<KeyInterruptSetting> = unsafe { VolAddress::new(0x400_0132) };
|
pub const KEYCNT: VolAddress<KeyInterruptSetting, Safe, Safe> =
|
||||||
|
unsafe { VolAddress::new(0x400_0132) };
|
||||||
|
|
||||||
newtype! {
|
newtype! {
|
||||||
/// Allows configuration of when a keypad interrupt fires.
|
/// Allows configuration of when a keypad interrupt fires.
|
||||||
|
|
|
@ -3,13 +3,14 @@
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
/// Serial IO Control. Read/Write.
|
/// Serial IO Control. Read/Write.
|
||||||
pub const SIOCNT: VolAddress<SioControlSetting> = unsafe { VolAddress::new(0x400_0128) };
|
pub const SIOCNT: VolAddress<SioControlSetting, Safe, Safe> =
|
||||||
|
unsafe { VolAddress::new(0x400_0128) };
|
||||||
|
|
||||||
/// Serial IO Data. Read/Write.
|
/// Serial IO Data. Read/Write.
|
||||||
pub const SIODATA8: VolAddress<u16> = unsafe { VolAddress::new(0x400_012A) };
|
pub const SIODATA8: VolAddress<u16, Safe, Safe> = unsafe { VolAddress::new(0x400_012A) };
|
||||||
|
|
||||||
/// General IO Control. Read/Write.
|
/// General IO Control. Read/Write.
|
||||||
pub const RCNT: VolAddress<IoControlSetting> = unsafe { VolAddress::new(0x400_0134) };
|
pub const RCNT: VolAddress<IoControlSetting, Safe, Safe> = unsafe { VolAddress::new(0x400_0134) };
|
||||||
|
|
||||||
newtype!(
|
newtype!(
|
||||||
/// Setting for the serial IO control register.
|
/// Setting for the serial IO control register.
|
||||||
|
@ -122,7 +123,7 @@ newtype_enum! {
|
||||||
JoyBus = 3,
|
JoyBus = 3,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Empty stuct that implements embedded_hal traits.
|
/// Empty struct that implements embedded_hal traits.
|
||||||
#[cfg(feature = "serial")]
|
#[cfg(feature = "serial")]
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct SioSerial;
|
pub struct SioSerial;
|
||||||
|
|
|
@ -5,7 +5,8 @@ use super::*;
|
||||||
//TODO within these "read/write" registers only some bits are actually read/write!
|
//TODO within these "read/write" registers only some bits are actually read/write!
|
||||||
|
|
||||||
/// Sound Channel 1 Sweep Register (`NR10`). Read/Write.
|
/// Sound Channel 1 Sweep Register (`NR10`). Read/Write.
|
||||||
pub const SOUND1CNT_L: VolAddress<SweepRegisterSetting> = unsafe { VolAddress::new(0x400_0060) };
|
pub const SOUND1CNT_L: VolAddress<SweepRegisterSetting, Safe, Safe> =
|
||||||
|
unsafe { VolAddress::new(0x400_0060) };
|
||||||
|
|
||||||
newtype! {
|
newtype! {
|
||||||
/// TODO: docs
|
/// TODO: docs
|
||||||
|
@ -22,7 +23,8 @@ impl SweepRegisterSetting {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sound Channel 1 Duty/Length/Envelope (`NR11`, `NR12`). Read/Write.
|
/// Sound Channel 1 Duty/Length/Envelope (`NR11`, `NR12`). Read/Write.
|
||||||
pub const SOUND1CNT_H: VolAddress<DutyLenEnvelopeSetting> = unsafe { VolAddress::new(0x400_0062) };
|
pub const SOUND1CNT_H: VolAddress<DutyLenEnvelopeSetting, Safe, Safe> =
|
||||||
|
unsafe { VolAddress::new(0x400_0062) };
|
||||||
|
|
||||||
newtype! {
|
newtype! {
|
||||||
/// TODO: docs
|
/// TODO: docs
|
||||||
|
@ -41,7 +43,8 @@ impl DutyLenEnvelopeSetting {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sound Channel 1 Frequency/Control (`NR13`, `NR14`). Read/Write.
|
/// Sound Channel 1 Frequency/Control (`NR13`, `NR14`). Read/Write.
|
||||||
pub const SOUND1CNT_X: VolAddress<FrequencyControlSetting> = unsafe { VolAddress::new(0x400_0064) };
|
pub const SOUND1CNT_X: VolAddress<FrequencyControlSetting, Safe, Safe> =
|
||||||
|
unsafe { VolAddress::new(0x400_0064) };
|
||||||
|
|
||||||
newtype! {
|
newtype! {
|
||||||
/// TODO: docs
|
/// TODO: docs
|
||||||
|
@ -58,13 +61,15 @@ impl FrequencyControlSetting {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sound Channel 2 Channel 2 Duty/Length/Envelope (`NR21`, `NR22`). Read/Write.
|
/// Sound Channel 2 Channel 2 Duty/Length/Envelope (`NR21`, `NR22`). Read/Write.
|
||||||
pub const SOUND2CNT_L: VolAddress<DutyLenEnvelopeSetting> = unsafe { VolAddress::new(0x400_0068) };
|
pub const SOUND2CNT_L: VolAddress<DutyLenEnvelopeSetting, Safe, Safe> =
|
||||||
|
unsafe { VolAddress::new(0x400_0068) };
|
||||||
|
|
||||||
/// Sound Channel 2 Frequency/Control (`NR23`, `NR24`). Read/Write.
|
/// Sound Channel 2 Frequency/Control (`NR23`, `NR24`). Read/Write.
|
||||||
pub const SOUND2CNT_H: VolAddress<FrequencyControlSetting> = unsafe { VolAddress::new(0x400_006C) };
|
pub const SOUND2CNT_H: VolAddress<FrequencyControlSetting, Safe, Safe> =
|
||||||
|
unsafe { VolAddress::new(0x400_006C) };
|
||||||
|
|
||||||
/// Sound Channel 3 Stop/Wave RAM select (`NR23`, `NR24`). Read/Write.
|
/// Sound Channel 3 Stop/Wave RAM select (`NR23`, `NR24`). Read/Write.
|
||||||
pub const SOUND3CNT_L: VolAddress<StopWaveRAMSelectSetting> =
|
pub const SOUND3CNT_L: VolAddress<StopWaveRAMSelectSetting, Safe, Safe> =
|
||||||
unsafe { VolAddress::new(0x400_0070) };
|
unsafe { VolAddress::new(0x400_0070) };
|
||||||
|
|
||||||
newtype! {
|
newtype! {
|
||||||
|
@ -82,7 +87,8 @@ impl StopWaveRAMSelectSetting {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sound Channel 3 Length/Volume (`NR23`, `NR24`). Read/Write.
|
/// Sound Channel 3 Length/Volume (`NR23`, `NR24`). Read/Write.
|
||||||
pub const SOUND3CNT_H: VolAddress<LengthVolumeSetting> = unsafe { VolAddress::new(0x400_0072) };
|
pub const SOUND3CNT_H: VolAddress<LengthVolumeSetting, Safe, Safe> =
|
||||||
|
unsafe { VolAddress::new(0x400_0072) };
|
||||||
|
|
||||||
newtype! {
|
newtype! {
|
||||||
/// TODO: docs
|
/// TODO: docs
|
||||||
|
@ -99,27 +105,29 @@ impl LengthVolumeSetting {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sound Channel 3 Frequency/Control (`NR33`, `NR34`). Read/Write.
|
/// Sound Channel 3 Frequency/Control (`NR33`, `NR34`). Read/Write.
|
||||||
pub const SOUND3CNT_X: VolAddress<FrequencyControlSetting> = unsafe { VolAddress::new(0x400_0074) };
|
pub const SOUND3CNT_X: VolAddress<FrequencyControlSetting, Safe, Safe> =
|
||||||
|
unsafe { VolAddress::new(0x400_0074) };
|
||||||
|
|
||||||
/// Channel 3 Wave Pattern RAM (W/R)
|
/// Channel 3 Wave Pattern RAM (W/R)
|
||||||
pub const WAVE_RAM0_L: VolAddress<u16> = unsafe { VolAddress::new(0x400_0090) };
|
pub const WAVE_RAM0_L: VolAddress<u16, Safe, Safe> = unsafe { VolAddress::new(0x400_0090) };
|
||||||
/// Channel 3 Wave Pattern RAM (W/R)
|
/// Channel 3 Wave Pattern RAM (W/R)
|
||||||
pub const WAVE_RAM0_H: VolAddress<u16> = unsafe { VolAddress::new(0x400_0092) };
|
pub const WAVE_RAM0_H: VolAddress<u16, Safe, Safe> = unsafe { VolAddress::new(0x400_0092) };
|
||||||
/// Channel 3 Wave Pattern RAM (W/R)
|
/// Channel 3 Wave Pattern RAM (W/R)
|
||||||
pub const WAVE_RAM1_L: VolAddress<u16> = unsafe { VolAddress::new(0x400_0094) };
|
pub const WAVE_RAM1_L: VolAddress<u16, Safe, Safe> = unsafe { VolAddress::new(0x400_0094) };
|
||||||
/// Channel 3 Wave Pattern RAM (W/R)
|
/// Channel 3 Wave Pattern RAM (W/R)
|
||||||
pub const WAVE_RAM1_H: VolAddress<u16> = unsafe { VolAddress::new(0x400_0096) };
|
pub const WAVE_RAM1_H: VolAddress<u16, Safe, Safe> = unsafe { VolAddress::new(0x400_0096) };
|
||||||
/// Channel 3 Wave Pattern RAM (W/R)
|
/// Channel 3 Wave Pattern RAM (W/R)
|
||||||
pub const WAVE_RAM2_L: VolAddress<u16> = unsafe { VolAddress::new(0x400_0098) };
|
pub const WAVE_RAM2_L: VolAddress<u16, Safe, Safe> = unsafe { VolAddress::new(0x400_0098) };
|
||||||
/// Channel 3 Wave Pattern RAM (W/R)
|
/// Channel 3 Wave Pattern RAM (W/R)
|
||||||
pub const WAVE_RAM2_H: VolAddress<u16> = unsafe { VolAddress::new(0x400_009A) };
|
pub const WAVE_RAM2_H: VolAddress<u16, Safe, Safe> = unsafe { VolAddress::new(0x400_009A) };
|
||||||
/// Channel 3 Wave Pattern RAM (W/R)
|
/// Channel 3 Wave Pattern RAM (W/R)
|
||||||
pub const WAVE_RAM3_L: VolAddress<u16> = unsafe { VolAddress::new(0x400_009C) };
|
pub const WAVE_RAM3_L: VolAddress<u16, Safe, Safe> = unsafe { VolAddress::new(0x400_009C) };
|
||||||
/// Channel 3 Wave Pattern RAM (W/R)
|
/// Channel 3 Wave Pattern RAM (W/R)
|
||||||
pub const WAVE_RAM3_H: VolAddress<u16> = unsafe { VolAddress::new(0x400_009E) };
|
pub const WAVE_RAM3_H: VolAddress<u16, Safe, Safe> = unsafe { VolAddress::new(0x400_009E) };
|
||||||
|
|
||||||
/// Sound Channel 4 Length/Envelope (`NR41`, `NR42`). Read/Write.
|
/// Sound Channel 4 Length/Envelope (`NR41`, `NR42`). Read/Write.
|
||||||
pub const SOUND4CNT_L: VolAddress<LengthEnvelopeSetting> = unsafe { VolAddress::new(0x400_0078) };
|
pub const SOUND4CNT_L: VolAddress<LengthEnvelopeSetting, Safe, Safe> =
|
||||||
|
unsafe { VolAddress::new(0x400_0078) };
|
||||||
|
|
||||||
newtype! {
|
newtype! {
|
||||||
/// TODO: docs
|
/// TODO: docs
|
||||||
|
@ -137,7 +145,8 @@ impl LengthEnvelopeSetting {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sound Channel 4 Frequency/Control (`NR43`, `NR44`). Read/Write.
|
/// Sound Channel 4 Frequency/Control (`NR43`, `NR44`). Read/Write.
|
||||||
pub const SOUND4CNT_H: VolAddress<NoiseFrequencySetting> = unsafe { VolAddress::new(0x400_007C) };
|
pub const SOUND4CNT_H: VolAddress<NoiseFrequencySetting, Safe, Safe> =
|
||||||
|
unsafe { VolAddress::new(0x400_007C) };
|
||||||
|
|
||||||
newtype! {
|
newtype! {
|
||||||
/// TODO: docs
|
/// TODO: docs
|
||||||
|
@ -158,16 +167,16 @@ impl NoiseFrequencySetting {
|
||||||
// TODO: unify FIFO as
|
// TODO: unify FIFO as
|
||||||
|
|
||||||
/// Sound A FIFO, Data 0 and Data 1 (W)
|
/// Sound A FIFO, Data 0 and Data 1 (W)
|
||||||
pub const FIFO_A_L: VolAddress<u16> = unsafe { VolAddress::new(0x400_00A0) };
|
pub const FIFO_A_L: VolAddress<u16, Safe, Safe> = unsafe { VolAddress::new(0x400_00A0) };
|
||||||
/// Sound A FIFO, Data 2 and Data 3 (W)
|
/// Sound A FIFO, Data 2 and Data 3 (W)
|
||||||
pub const FIFO_A_H: VolAddress<u16> = unsafe { VolAddress::new(0x400_00A2) };
|
pub const FIFO_A_H: VolAddress<u16, Safe, Safe> = unsafe { VolAddress::new(0x400_00A2) };
|
||||||
/// Sound B FIFO, Data 0 and Data 1 (W)
|
/// Sound B FIFO, Data 0 and Data 1 (W)
|
||||||
pub const FIFO_B_L: VolAddress<u16> = unsafe { VolAddress::new(0x400_00A4) };
|
pub const FIFO_B_L: VolAddress<u16, Safe, Safe> = unsafe { VolAddress::new(0x400_00A4) };
|
||||||
/// Sound B FIFO, Data 2 and Data 3 (W)
|
/// Sound B FIFO, Data 2 and Data 3 (W)
|
||||||
pub const FIFO_B_H: VolAddress<u16> = unsafe { VolAddress::new(0x400_00A6) };
|
pub const FIFO_B_H: VolAddress<u16, Safe, Safe> = unsafe { VolAddress::new(0x400_00A6) };
|
||||||
|
|
||||||
/// Channel L/R Volume/Enable (`NR50`, `NR51`). Read/Write.
|
/// Channel L/R Volume/Enable (`NR50`, `NR51`). Read/Write.
|
||||||
pub const SOUNDCNT_L: VolAddress<NonWaveVolumeEnableSetting> =
|
pub const SOUNDCNT_L: VolAddress<NonWaveVolumeEnableSetting, Safe, Safe> =
|
||||||
unsafe { VolAddress::new(0x400_0080) };
|
unsafe { VolAddress::new(0x400_0080) };
|
||||||
|
|
||||||
newtype! {
|
newtype! {
|
||||||
|
@ -186,7 +195,8 @@ impl NonWaveVolumeEnableSetting {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// DMA Sound Control/Mixing. Read/Write.
|
/// DMA Sound Control/Mixing. Read/Write.
|
||||||
pub const SOUNDCNT_H: VolAddress<WaveVolumeEnableSetting> = unsafe { VolAddress::new(0x400_0082) };
|
pub const SOUNDCNT_H: VolAddress<WaveVolumeEnableSetting, Safe, Safe> =
|
||||||
|
unsafe { VolAddress::new(0x400_0082) };
|
||||||
|
|
||||||
newtype! {
|
newtype! {
|
||||||
/// TODO: docs
|
/// TODO: docs
|
||||||
|
@ -222,7 +232,8 @@ newtype_enum! {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sound on/off (`NR52`). Read/Write.
|
/// Sound on/off (`NR52`). Read/Write.
|
||||||
pub const SOUNDCNT_X: VolAddress<SoundMasterSetting> = unsafe { VolAddress::new(0x400_0084) };
|
pub const SOUNDCNT_X: VolAddress<SoundMasterSetting, Safe, Safe> =
|
||||||
|
unsafe { VolAddress::new(0x400_0084) };
|
||||||
|
|
||||||
newtype! {
|
newtype! {
|
||||||
/// TODO: docs
|
/// TODO: docs
|
||||||
|
@ -241,7 +252,8 @@ impl SoundMasterSetting {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sound on/off (`NR52`). Read/Write.
|
/// Sound on/off (`NR52`). Read/Write.
|
||||||
pub const SOUNDBIAS: VolAddress<SoundPWMSetting> = unsafe { VolAddress::new(0x400_0088) };
|
pub const SOUNDBIAS: VolAddress<SoundPWMSetting, Safe, Safe> =
|
||||||
|
unsafe { VolAddress::new(0x400_0088) };
|
||||||
|
|
||||||
newtype! {
|
newtype! {
|
||||||
/// TODO: docs
|
/// TODO: docs
|
||||||
|
|
|
@ -28,28 +28,32 @@ use super::*;
|
||||||
// TODO: striding blocks?
|
// TODO: striding blocks?
|
||||||
|
|
||||||
/// Timer 0 Counter/Reload. Special (see module).
|
/// Timer 0 Counter/Reload. Special (see module).
|
||||||
pub const TM0CNT_L: VolAddress<u16> = unsafe { VolAddress::new(0x400_0100) };
|
pub const TM0CNT_L: VolAddress<u16, Safe, Safe> = unsafe { VolAddress::new(0x400_0100) };
|
||||||
|
|
||||||
/// Timer 1 Counter/Reload. Special (see module).
|
/// Timer 1 Counter/Reload. Special (see module).
|
||||||
pub const TM1CNT_L: VolAddress<u16> = unsafe { VolAddress::new(0x400_0104) };
|
pub const TM1CNT_L: VolAddress<u16, Safe, Safe> = unsafe { VolAddress::new(0x400_0104) };
|
||||||
|
|
||||||
/// Timer 2 Counter/Reload. Special (see module).
|
/// Timer 2 Counter/Reload. Special (see module).
|
||||||
pub const TM2CNT_L: VolAddress<u16> = unsafe { VolAddress::new(0x400_0108) };
|
pub const TM2CNT_L: VolAddress<u16, Safe, Safe> = unsafe { VolAddress::new(0x400_0108) };
|
||||||
|
|
||||||
/// Timer 3 Counter/Reload. Special (see module).
|
/// Timer 3 Counter/Reload. Special (see module).
|
||||||
pub const TM3CNT_L: VolAddress<u16> = unsafe { VolAddress::new(0x400_010C) };
|
pub const TM3CNT_L: VolAddress<u16, Safe, Safe> = unsafe { VolAddress::new(0x400_010C) };
|
||||||
|
|
||||||
/// Timer 0 Control. Read/Write.
|
/// Timer 0 Control. Read/Write.
|
||||||
pub const TM0CNT_H: VolAddress<TimerControlSetting> = unsafe { VolAddress::new(0x400_0102) };
|
pub const TM0CNT_H: VolAddress<TimerControlSetting, Safe, Safe> =
|
||||||
|
unsafe { VolAddress::new(0x400_0102) };
|
||||||
|
|
||||||
/// Timer 1 Control. Read/Write.
|
/// Timer 1 Control. Read/Write.
|
||||||
pub const TM1CNT_H: VolAddress<TimerControlSetting> = unsafe { VolAddress::new(0x400_0106) };
|
pub const TM1CNT_H: VolAddress<TimerControlSetting, Safe, Safe> =
|
||||||
|
unsafe { VolAddress::new(0x400_0106) };
|
||||||
|
|
||||||
/// Timer 2 Control. Read/Write.
|
/// Timer 2 Control. Read/Write.
|
||||||
pub const TM2CNT_H: VolAddress<TimerControlSetting> = unsafe { VolAddress::new(0x400_010A) };
|
pub const TM2CNT_H: VolAddress<TimerControlSetting, Safe, Safe> =
|
||||||
|
unsafe { VolAddress::new(0x400_010A) };
|
||||||
|
|
||||||
/// Timer 3 Control. Read/Write.
|
/// Timer 3 Control. Read/Write.
|
||||||
pub const TM3CNT_H: VolAddress<TimerControlSetting> = unsafe { VolAddress::new(0x400_010E) };
|
pub const TM3CNT_H: VolAddress<TimerControlSetting, Safe, Safe> =
|
||||||
|
unsafe { VolAddress::new(0x400_010E) };
|
||||||
|
|
||||||
newtype! {
|
newtype! {
|
||||||
/// Allows control of a timer unit.
|
/// Allows control of a timer unit.
|
||||||
|
|
|
@ -3,10 +3,12 @@
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
/// Window 0 Horizontal Dimensions (W)
|
/// Window 0 Horizontal Dimensions (W)
|
||||||
pub const WIN0H: VolAddress<HorizontalWindowSetting> = unsafe { VolAddress::new(0x400_0040) };
|
pub const WIN0H: VolAddress<HorizontalWindowSetting, Safe, Safe> =
|
||||||
|
unsafe { VolAddress::new(0x400_0040) };
|
||||||
|
|
||||||
/// Window 1 Horizontal Dimensions (W)
|
/// Window 1 Horizontal Dimensions (W)
|
||||||
pub const WIN1H: VolAddress<HorizontalWindowSetting> = unsafe { VolAddress::new(0x400_0042) };
|
pub const WIN1H: VolAddress<HorizontalWindowSetting, Safe, Safe> =
|
||||||
|
unsafe { VolAddress::new(0x400_0042) };
|
||||||
|
|
||||||
newtype! {
|
newtype! {
|
||||||
/// TODO: docs
|
/// TODO: docs
|
||||||
|
@ -22,10 +24,12 @@ impl HorizontalWindowSetting {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Window 0 Vertical Dimensions (W)
|
/// Window 0 Vertical Dimensions (W)
|
||||||
pub const WIN0V: VolAddress<VerticalWindowSetting> = unsafe { VolAddress::new(0x400_0044) };
|
pub const WIN0V: VolAddress<VerticalWindowSetting, Safe, Safe> =
|
||||||
|
unsafe { VolAddress::new(0x400_0044) };
|
||||||
|
|
||||||
/// Window 1 Vertical Dimensions (W)
|
/// Window 1 Vertical Dimensions (W)
|
||||||
pub const WIN1V: VolAddress<VerticalWindowSetting> = unsafe { VolAddress::new(0x400_0046) };
|
pub const WIN1V: VolAddress<VerticalWindowSetting, Safe, Safe> =
|
||||||
|
unsafe { VolAddress::new(0x400_0046) };
|
||||||
|
|
||||||
newtype! {
|
newtype! {
|
||||||
/// TODO: docs
|
/// TODO: docs
|
||||||
|
@ -41,7 +45,8 @@ impl VerticalWindowSetting {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Control of Inside of Window(s) (R/W)
|
/// Control of Inside of Window(s) (R/W)
|
||||||
pub const WININ: VolAddress<InsideWindowSetting> = unsafe { VolAddress::new(0x400_0048) };
|
pub const WININ: VolAddress<InsideWindowSetting, Safe, Safe> =
|
||||||
|
unsafe { VolAddress::new(0x400_0048) };
|
||||||
|
|
||||||
newtype! {
|
newtype! {
|
||||||
/// TODO: docs
|
/// TODO: docs
|
||||||
|
@ -67,7 +72,8 @@ impl InsideWindowSetting {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Control of Outside of Windows & Inside of OBJ Window (R/W)
|
/// Control of Outside of Windows & Inside of OBJ Window (R/W)
|
||||||
pub const WINOUT: VolAddress<OutsideWindowSetting> = unsafe { VolAddress::new(0x400_004A) };
|
pub const WINOUT: VolAddress<OutsideWindowSetting, Safe, Safe> =
|
||||||
|
unsafe { VolAddress::new(0x400_004A) };
|
||||||
|
|
||||||
newtype! {
|
newtype! {
|
||||||
/// TODO: docs
|
/// TODO: docs
|
||||||
|
|
10
src/lib.rs
10
src/lib.rs
|
@ -1,8 +1,7 @@
|
||||||
#![cfg_attr(not(test), no_std)]
|
#![cfg_attr(not(test), no_std)]
|
||||||
#![feature(asm, global_asm, isa_attribute)]
|
#![feature(asm, global_asm, isa_attribute)]
|
||||||
#![allow(clippy::cast_lossless)]
|
#![allow(unused_imports)]
|
||||||
#![deny(clippy::float_arithmetic)]
|
//#![warn(missing_docs)]
|
||||||
#![warn(missing_docs)]
|
|
||||||
|
|
||||||
//! This crate helps you write GBA ROMs.
|
//! This crate helps you write GBA ROMs.
|
||||||
//!
|
//!
|
||||||
|
@ -18,12 +17,11 @@
|
||||||
//! do, it's a giant bag of Undefined Behavior.
|
//! do, it's a giant bag of Undefined Behavior.
|
||||||
|
|
||||||
pub(crate) use gba_proc_macro::phantom_fields;
|
pub(crate) use gba_proc_macro::phantom_fields;
|
||||||
pub(crate) use voladdress::{read_only::ROVolAddress, VolAddress, VolBlock};
|
|
||||||
|
use voladdress::*;
|
||||||
|
|
||||||
pub mod macros;
|
pub mod macros;
|
||||||
|
|
||||||
pub mod base;
|
|
||||||
|
|
||||||
pub mod bios;
|
pub mod bios;
|
||||||
|
|
||||||
pub mod iwram;
|
pub mod iwram;
|
||||||
|
|
|
@ -2,8 +2,6 @@
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
use typenum::consts::{U128, U32};
|
|
||||||
|
|
||||||
newtype! {
|
newtype! {
|
||||||
/// 0th part of an object's attributes.
|
/// 0th part of an object's attributes.
|
||||||
///
|
///
|
||||||
|
@ -139,7 +137,7 @@ pub struct ObjectAttributes {
|
||||||
|
|
||||||
/// The object attributes, but there are gaps in the array, so we must not
|
/// The object attributes, but there are gaps in the array, so we must not
|
||||||
/// expose this directly.
|
/// expose this directly.
|
||||||
const OBJ_ATTR_APPROX: VolBlock<[u16; 4], U128> = unsafe { VolBlock::new(0x700_0000) };
|
const OBJ_ATTR_APPROX: VolBlock<[u16; 4], Safe, Safe, 128> = unsafe { VolBlock::new(0x700_0000) };
|
||||||
// TODO: VolSeries
|
// TODO: VolSeries
|
||||||
|
|
||||||
pub fn write_obj_attributes(slot: usize, attributes: ObjectAttributes) -> Option<()> {
|
pub fn write_obj_attributes(slot: usize, attributes: ObjectAttributes) -> Option<()> {
|
||||||
|
@ -172,7 +170,8 @@ pub struct AffineParameters {
|
||||||
|
|
||||||
/// The object attributes, but there are gaps in the array, so we must not
|
/// The object attributes, but there are gaps in the array, so we must not
|
||||||
/// expose this directly.
|
/// expose this directly.
|
||||||
const AFFINE_PARAMS_APPROX: VolBlock<[i16; 16], U32> = unsafe { VolBlock::new(0x700_0000) };
|
const AFFINE_PARAMS_APPROX: VolBlock<[i16; 16], Safe, Safe, 32> =
|
||||||
|
unsafe { VolBlock::new(0x700_0000) };
|
||||||
// TODO: VolSeries
|
// TODO: VolSeries
|
||||||
|
|
||||||
pub fn write_affine_parameters(slot: usize, params: AffineParameters) -> Option<()> {
|
pub fn write_affine_parameters(slot: usize, params: AffineParameters) -> Option<()> {
|
||||||
|
|
|
@ -25,42 +25,36 @@
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
use typenum::consts::U256;
|
|
||||||
|
|
||||||
// TODO: PalIndex newtypes?
|
// TODO: PalIndex newtypes?
|
||||||
|
|
||||||
/// The `PALRAM` for background colors, 256 slot view.
|
/// The `PALRAM` for background colors, 256 slot view.
|
||||||
pub const PALRAM_BG: VolBlock<Color, U256> = unsafe { VolBlock::new(0x500_0000) };
|
pub const PALRAM_BG: VolBlock<Color, Safe, Safe, 256> = unsafe { VolBlock::new(0x500_0000) };
|
||||||
|
|
||||||
/// The `PALRAM` for object colors, 256 slot view.
|
/// The `PALRAM` for object colors, 256 slot view.
|
||||||
pub const PALRAM_OBJ: VolBlock<Color, U256> = unsafe { VolBlock::new(0x500_0200) };
|
pub const PALRAM_OBJ: VolBlock<Color, Safe, Safe, 256> = unsafe { VolBlock::new(0x500_0200) };
|
||||||
|
|
||||||
/// Obtains the address of the specified 8bpp background palette slot.
|
/// Obtains the address of the specified 8bpp background palette slot.
|
||||||
pub const fn index_palram_bg_8bpp(slot: u8) -> VolAddress<Color> {
|
pub const fn index_palram_bg_8bpp(slot: u8) -> VolAddress<Color, Safe, Safe> {
|
||||||
// Note(Lokathor): because of the `u8` limit we can't go out of bounds here.
|
PALRAM_BG.index(slot as usize)
|
||||||
unsafe { PALRAM_BG.index_unchecked(slot as usize) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Obtains the address of the specified 8bpp object palette slot.
|
/// Obtains the address of the specified 8bpp object palette slot.
|
||||||
pub const fn index_palram_obj_8bpp(slot: u8) -> VolAddress<Color> {
|
pub const fn index_palram_obj_8bpp(slot: u8) -> VolAddress<Color, Safe, Safe> {
|
||||||
// Note(Lokathor): because of the `u8` limit we can't go out of bounds here.
|
PALRAM_OBJ.index(slot as usize)
|
||||||
unsafe { PALRAM_OBJ.index_unchecked(slot as usize) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Obtains the address of the specified 4bpp background palbank and palslot.
|
/// Obtains the address of the specified 4bpp background palbank and palslot.
|
||||||
///
|
///
|
||||||
/// Accesses `palbank * 16 + palslot`, if this is out of bounds the computation
|
/// Accesses `palbank * 16 + palslot`, if this is out of bounds the computation
|
||||||
/// will wrap.
|
/// will wrap.
|
||||||
pub const fn index_palram_bg_4bpp(palbank: u8, palslot: u8) -> VolAddress<Color> {
|
pub const fn index_palram_bg_4bpp(palbank: u8, palslot: u8) -> VolAddress<Color, Safe, Safe> {
|
||||||
// Note(Lokathor): because of the `u8` limit we can't go out of bounds here.
|
PALRAM_BG.index(palbank.wrapping_mul(16).wrapping_add(palslot) as usize)
|
||||||
unsafe { PALRAM_BG.index_unchecked(palbank.wrapping_mul(16).wrapping_add(palslot) as usize) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Obtains the address of the specified 4bpp object palbank and palslot.
|
/// Obtains the address of the specified 4bpp object palbank and palslot.
|
||||||
///
|
///
|
||||||
/// Accesses `palbank * 16 + palslot`, if this is out of bounds the computation
|
/// Accesses `palbank * 16 + palslot`, if this is out of bounds the computation
|
||||||
/// will wrap.
|
/// will wrap.
|
||||||
pub const fn index_palram_obj_4bpp(palbank: u8, palslot: u8) -> VolAddress<Color> {
|
pub const fn index_palram_obj_4bpp(palbank: u8, palslot: u8) -> VolAddress<Color, Safe, Safe> {
|
||||||
// Note(Lokathor): because of the `u8` limit we can't go out of bounds here.
|
PALRAM_OBJ.index(palbank.wrapping_mul(16).wrapping_add(palslot) as usize)
|
||||||
unsafe { PALRAM_OBJ.index_unchecked(palbank.wrapping_mul(16).wrapping_add(palslot) as usize) }
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,9 +9,9 @@ use crate::{
|
||||||
sync::with_irqs_disabled,
|
sync::with_irqs_disabled,
|
||||||
};
|
};
|
||||||
use core::cmp;
|
use core::cmp;
|
||||||
use voladdress::VolAddress;
|
use voladdress::*;
|
||||||
|
|
||||||
const PORT: VolAddress<u16> = unsafe { VolAddress::new(0x0DFFFF00) };
|
const PORT: VolAddress<u16, Safe, Safe> = unsafe { VolAddress::new(0x0DFFFF00) };
|
||||||
const SECTOR_SHIFT: usize = 3;
|
const SECTOR_SHIFT: usize = 3;
|
||||||
const SECTOR_LEN: usize = 1 << SECTOR_SHIFT;
|
const SECTOR_LEN: usize = 1 << SECTOR_SHIFT;
|
||||||
const SECTOR_MASK: usize = SECTOR_LEN - 1;
|
const SECTOR_MASK: usize = SECTOR_LEN - 1;
|
||||||
|
@ -156,32 +156,30 @@ impl EepromProperties {
|
||||||
|
|
||||||
/// Writes a sector directly.
|
/// Writes a sector directly.
|
||||||
fn write_sector_raw(&self, word: usize, block: &[u8]) -> Result<(), Error> {
|
fn write_sector_raw(&self, word: usize, block: &[u8]) -> Result<(), Error> {
|
||||||
unsafe {
|
// Write sector command. The command is a one bit, followed by a
|
||||||
// Write sector command. The command is a one bit, followed by a
|
// zero bit, followed by the address, followed by 64 bits of data.
|
||||||
// zero bit, followed by the address, followed by 64 bits of data.
|
//
|
||||||
//
|
// 512B Command: [1 0|n n n n n n|v v v v ...]
|
||||||
// 512B Command: [1 0|n n n n n n|v v v v ...]
|
// 8KiB Command: [1 0|n n n n n n n n n n n n n n|v v v v ...]
|
||||||
// 8KiB Command: [1 0|n n n n n n n n n n n n n n|v v v v ...]
|
let mut buf = BufferData::new();
|
||||||
let mut buf = BufferData::new();
|
buf.write_bit(1);
|
||||||
buf.write_bit(1);
|
buf.write_bit(0);
|
||||||
buf.write_bit(0);
|
buf.write_num(self.addr_bits, word as u32);
|
||||||
buf.write_num(self.addr_bits, word as u32);
|
for i in 0..8 {
|
||||||
for i in 0..8 {
|
buf.write_num(8, block[i] as u32);
|
||||||
buf.write_num(8, block[i] as u32);
|
|
||||||
}
|
|
||||||
buf.write_bit(0);
|
|
||||||
buf.submit();
|
|
||||||
|
|
||||||
// Wait for the sector to be written for 10 milliseconds.
|
|
||||||
let timeout = Timeout::new()?;
|
|
||||||
timeout.start();
|
|
||||||
while PORT.read() & 1 != 1 {
|
|
||||||
if timeout.is_timeout_met(10) {
|
|
||||||
return Err(Error::OperationTimedOut);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
buf.write_bit(0);
|
||||||
|
buf.submit();
|
||||||
|
|
||||||
|
// Wait for the sector to be written for 10 milliseconds.
|
||||||
|
let timeout = Timeout::new()?;
|
||||||
|
timeout.start();
|
||||||
|
while PORT.read() & 1 != 1 {
|
||||||
|
if timeout.is_timeout_met(10) {
|
||||||
|
return Err(Error::OperationTimedOut);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Writes a sector to the EEPROM, keeping any current contents outside the
|
/// Writes a sector to the EEPROM, keeping any current contents outside the
|
||||||
|
@ -218,7 +216,7 @@ impl EepromProperties {
|
||||||
let start = offset & SECTOR_MASK;
|
let start = offset & SECTOR_MASK;
|
||||||
let end_len = cmp::min(SECTOR_LEN - start, buf.len());
|
let end_len = cmp::min(SECTOR_LEN - start, buf.len());
|
||||||
let sector = self.read_sector(offset >> SECTOR_SHIFT);
|
let sector = self.read_sector(offset >> SECTOR_SHIFT);
|
||||||
buf[..end_len].copy_from_slice(§or[start..start+end_len]);
|
buf[..end_len].copy_from_slice(§or[start..start + end_len]);
|
||||||
buf = &mut buf[end_len..];
|
buf = &mut buf[end_len..];
|
||||||
offset += end_len;
|
offset += end_len;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,14 +9,13 @@ use super::{
|
||||||
};
|
};
|
||||||
use crate::sync::{with_irqs_disabled, InitOnce, Static};
|
use crate::sync::{with_irqs_disabled, InitOnce, Static};
|
||||||
use core::cmp;
|
use core::cmp;
|
||||||
use typenum::consts::U65536;
|
use voladdress::*;
|
||||||
use voladdress::{VolAddress, VolBlock};
|
|
||||||
|
|
||||||
// Volatile address ports for flash
|
// Volatile address ports for flash
|
||||||
const FLASH_PORT_BANK: VolAddress<u8> = unsafe { VolAddress::new(0x0E000000) };
|
const FLASH_PORT_BANK: VolAddress<u8, Safe, Safe> = unsafe { VolAddress::new(0x0E000000) };
|
||||||
const FLASH_PORT_A: VolAddress<u8> = unsafe { VolAddress::new(0x0E005555) };
|
const FLASH_PORT_A: VolAddress<u8, Safe, Safe> = unsafe { VolAddress::new(0x0E005555) };
|
||||||
const FLASH_PORT_B: VolAddress<u8> = unsafe { VolAddress::new(0x0E002AAA) };
|
const FLASH_PORT_B: VolAddress<u8, Safe, Safe> = unsafe { VolAddress::new(0x0E002AAA) };
|
||||||
const FLASH_DATA: VolBlock<u8, U65536> = unsafe { VolBlock::new(0x0E000000) };
|
const FLASH_DATA: VolBlock<u8, Safe, Safe, 65536> = unsafe { VolBlock::new(0x0E000000) };
|
||||||
|
|
||||||
// Various constants related to sector sizes
|
// Various constants related to sector sizes
|
||||||
const BANK_SHIFT: usize = 16; // 64 KiB
|
const BANK_SHIFT: usize = 16; // 64 KiB
|
||||||
|
@ -133,7 +132,7 @@ struct ChipInfo {
|
||||||
|
|
||||||
/// The timeout in milliseconds for writes to this chip.
|
/// The timeout in milliseconds for writes to this chip.
|
||||||
write_timeout: u16,
|
write_timeout: u16,
|
||||||
/// The timeout in mililseconds for erasing a sector in this chip.
|
/// The timeout in milliseconds for erasing a sector in this chip.
|
||||||
erase_sector_timeout: u16,
|
erase_sector_timeout: u16,
|
||||||
/// The timeout in milliseconds for erasing the entire chip.
|
/// The timeout in milliseconds for erasing the entire chip.
|
||||||
erase_chip_timeout: u16,
|
erase_chip_timeout: u16,
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
//! A package containing useful utilities for writing save accessors. This is
|
//! A package containing useful utilities for writing save accessors. This is
|
||||||
//! mainly used internally, although the types inside are exposed publically.
|
//! mainly used internally, although the types inside are exposed publicly.
|
||||||
|
|
||||||
use super::Error;
|
use super::Error;
|
||||||
use crate::{
|
use crate::{
|
||||||
io::timers::*,
|
io::timers::*,
|
||||||
sync::{RawMutex, RawMutexGuard, Static},
|
sync::{RawMutex, RawMutexGuard, Static},
|
||||||
};
|
};
|
||||||
use voladdress::VolAddress;
|
use voladdress::*;
|
||||||
|
|
||||||
/// Internal representation for our active timer.
|
/// Internal representation for our active timer.
|
||||||
#[derive(Copy, Clone, PartialEq)]
|
#[derive(Copy, Clone, PartialEq)]
|
||||||
|
@ -44,8 +44,8 @@ pub fn disable_timeout() {
|
||||||
pub struct Timeout {
|
pub struct Timeout {
|
||||||
_lock_guard: RawMutexGuard<'static>,
|
_lock_guard: RawMutexGuard<'static>,
|
||||||
active: bool,
|
active: bool,
|
||||||
timer_l: VolAddress<u16>,
|
timer_l: VolAddress<u16, Safe, Safe>,
|
||||||
timer_h: VolAddress<TimerControlSetting>,
|
timer_h: VolAddress<TimerControlSetting, Safe, Safe>,
|
||||||
}
|
}
|
||||||
impl Timeout {
|
impl Timeout {
|
||||||
/// Creates a new timeout from the timer passed to [`set_timer_for_timeout`].
|
/// Creates a new timeout from the timer passed to [`set_timer_for_timeout`].
|
||||||
|
|
16
src/sync.rs
16
src/sync.rs
|
@ -29,13 +29,19 @@ pub fn memory_write_hint<T>(val: *mut T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An internal function used as a temporary hack to get `compiler_fence`
|
/// An internal function used as a temporary hack to get `compiler_fence`
|
||||||
/// working. While this call is not properly inlined, working is better than
|
/// working. While this call is not properly inlined, working is better than not
|
||||||
/// not working at all.
|
/// working at all.
|
||||||
///
|
///
|
||||||
/// This seems to be a problem caused by Rust issue #62256:
|
/// This seems to be a problem caused by Rust issue #62256:
|
||||||
/// <https://github.com/rust-lang/rust/issues/62256>
|
/// <https://github.com/rust-lang/rust/issues/62256>
|
||||||
///
|
///
|
||||||
/// Not public API, obviously.
|
/// Not public API, obviously.
|
||||||
|
///
|
||||||
|
/// NOTE TO ANYONE WHO FINDS THIS: THIS FUNCTION SHOULD NOT NORMALLY BE BLANK.
|
||||||
|
/// Having a blank version of this function is *only* correct because the GBA is
|
||||||
|
/// so old that it doesn't actually have atomics to sync to begin with (just a
|
||||||
|
/// main thread + interrupts). On any modern CPU, having this function be blank
|
||||||
|
/// is extremely likely to be incorrect.
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
#[deprecated]
|
#[deprecated]
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
|
@ -49,15 +55,15 @@ pub unsafe extern "C" fn __sync_synchronize() {}
|
||||||
/// for game functionality.
|
/// for game functionality.
|
||||||
pub fn with_irqs_disabled<T>(mut func: impl FnOnce() -> T) -> T {
|
pub fn with_irqs_disabled<T>(mut func: impl FnOnce() -> T) -> T {
|
||||||
let current_ime = IME.read();
|
let current_ime = IME.read();
|
||||||
IME.write(IrqEnableSetting::IRQ_NO);
|
unsafe { IME.write(IrqEnableSetting::IRQ_NO) };
|
||||||
// prevents the contents of the function from being reordered before IME is disabled.
|
// prevents the contents of the function from being reordered before IME is disabled.
|
||||||
memory_write_hint(&mut func);
|
memory_write_hint(&mut func);
|
||||||
|
|
||||||
let mut result = func();
|
let mut result = func();
|
||||||
|
|
||||||
// prevents the contents of the function from being reordered after IME is reenabled.
|
// prevents the contents of the function from being reordered after IME is re-enabled.
|
||||||
memory_write_hint(&mut result);
|
memory_write_hint(&mut result);
|
||||||
IME.write(current_ime);
|
unsafe { IME.write(current_ime) };
|
||||||
|
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,19 @@
|
||||||
#![cfg_attr(not(target_arch = "arm"), allow(unused_variables))]
|
#![cfg_attr(not(target_arch = "arm"), allow(unused_variables))]
|
||||||
|
|
||||||
use super::*;
|
use crate::sync::with_irqs_disabled;
|
||||||
use core::{cell::UnsafeCell, mem, mem::MaybeUninit, ptr};
|
use core::{
|
||||||
|
cell::UnsafeCell,
|
||||||
|
mem::{align_of, size_of, MaybeUninit},
|
||||||
|
ptr,
|
||||||
|
};
|
||||||
|
|
||||||
/// The internal function for replacing a `Copy` (really `!Drop`) value in a
|
/// The internal function for replacing a `Copy` (really `!Drop`) value in a
|
||||||
/// [`Static`]. This uses assembly to use an `stmia` instruction to ensure
|
/// [`Static`]. This uses assembly to use an `stmia` instruction to ensure
|
||||||
/// an IRQ cannot occur during the write operation.
|
/// an IRQ cannot occur during the write operation.
|
||||||
#[cfg(target_arch = "arm")]
|
#[cfg(target_arch = "arm")]
|
||||||
unsafe fn transfer<T: Copy>(dst: *mut T, src: *const T) {
|
unsafe fn transfer<T: Copy>(dst: *mut T, src: *const T) {
|
||||||
let align = mem::align_of::<T>();
|
let align = align_of::<T>();
|
||||||
let size = mem::size_of::<T>();
|
let size = size_of::<T>();
|
||||||
if size == 0 {
|
if size == 0 {
|
||||||
// Do nothing with ZSTs. Obviously.
|
// Do nothing with ZSTs. Obviously.
|
||||||
} else if size <= 16 && align % 4 == 0 {
|
} else if size <= 16 && align % 4 == 0 {
|
||||||
|
@ -41,7 +45,7 @@ unsafe fn transfer<T: Copy>(dst: *mut T, src: *const T) {
|
||||||
#[cfg(target_arch = "arm")]
|
#[cfg(target_arch = "arm")]
|
||||||
#[allow(unused_assignments)]
|
#[allow(unused_assignments)]
|
||||||
unsafe fn transfer_align4_thumb<T: Copy>(mut dst: *mut T, mut src: *const T) {
|
unsafe fn transfer_align4_thumb<T: Copy>(mut dst: *mut T, mut src: *const T) {
|
||||||
let size = mem::size_of::<T>();
|
let size = size_of::<T>();
|
||||||
if size <= 4 {
|
if size <= 4 {
|
||||||
// We use assembly here regardless to just do the word aligned copy. This
|
// We use assembly here regardless to just do the word aligned copy. This
|
||||||
// ensures it's done with a single ldr/str instruction.
|
// ensures it's done with a single ldr/str instruction.
|
||||||
|
@ -82,7 +86,7 @@ unsafe fn transfer_align4_thumb<T: Copy>(mut dst: *mut T, mut src: *const T) {
|
||||||
#[instruction_set(arm::a32)]
|
#[instruction_set(arm::a32)]
|
||||||
#[allow(unused_assignments)]
|
#[allow(unused_assignments)]
|
||||||
unsafe fn transfer_align4_arm<T: Copy>(mut dst: *mut T, mut src: *const T) {
|
unsafe fn transfer_align4_arm<T: Copy>(mut dst: *mut T, mut src: *const T) {
|
||||||
let size = mem::size_of::<T>();
|
let size = size_of::<T>();
|
||||||
if size <= 16 {
|
if size <= 16 {
|
||||||
unimplemented!("This should be done via transfer_thumb.");
|
unimplemented!("This should be done via transfer_thumb.");
|
||||||
} else if size <= 20 {
|
} else if size <= 20 {
|
||||||
|
@ -134,8 +138,8 @@ unsafe fn transfer_align4_arm<T: Copy>(mut dst: *mut T, mut src: *const T) {
|
||||||
/// another value.
|
/// another value.
|
||||||
#[cfg(target_arch = "arm")]
|
#[cfg(target_arch = "arm")]
|
||||||
unsafe fn exchange<T>(dst: *mut T, src: *const T) -> T {
|
unsafe fn exchange<T>(dst: *mut T, src: *const T) -> T {
|
||||||
let align = mem::align_of::<T>();
|
let align = align_of::<T>();
|
||||||
let size = mem::size_of::<T>();
|
let size = size_of::<T>();
|
||||||
if size == 0 {
|
if size == 0 {
|
||||||
// Do nothing with ZSTs.
|
// Do nothing with ZSTs.
|
||||||
ptr::read(dst)
|
ptr::read(dst)
|
||||||
|
|
21
src/vram.rs
21
src/vram.rs
|
@ -15,8 +15,6 @@
|
||||||
|
|
||||||
pub(crate) use super::*;
|
pub(crate) use super::*;
|
||||||
|
|
||||||
use typenum::{U1024, consts::{U256, U32, U512, U6}};
|
|
||||||
|
|
||||||
pub mod affine;
|
pub mod affine;
|
||||||
pub mod bitmap;
|
pub mod bitmap;
|
||||||
pub mod text;
|
pub mod text;
|
||||||
|
@ -34,10 +32,11 @@ pub const VRAM_BASE_USIZE: usize = 0x600_0000;
|
||||||
pub const PAGE1_OFFSET: usize = 0xA000;
|
pub const PAGE1_OFFSET: usize = 0xA000;
|
||||||
|
|
||||||
/// The character base blocks.
|
/// The character base blocks.
|
||||||
pub const CHAR_BASE_BLOCKS: VolBlock<[u8; 0x4000], U6> = unsafe { VolBlock::new(VRAM_BASE_USIZE) };
|
pub const CHAR_BASE_BLOCKS: VolBlock<[u8; 0x4000], Safe, Safe, 6> =
|
||||||
|
unsafe { VolBlock::new(VRAM_BASE_USIZE) };
|
||||||
|
|
||||||
/// The screen entry base blocks.
|
/// The screen entry base blocks.
|
||||||
pub const SCREEN_BASE_BLOCKS: VolBlock<[u8; 0x800], U32> =
|
pub const SCREEN_BASE_BLOCKS: VolBlock<[u8; 0x800], Safe, Safe, 32> =
|
||||||
unsafe { VolBlock::new(VRAM_BASE_USIZE) };
|
unsafe { VolBlock::new(VRAM_BASE_USIZE) };
|
||||||
|
|
||||||
newtype! {
|
newtype! {
|
||||||
|
@ -53,15 +52,15 @@ newtype! {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gives the specified charblock in 4bpp view.
|
/// Gives the specified charblock in 4bpp view.
|
||||||
pub fn get_4bpp_character_block(slot: usize) -> VolBlock<Tile4bpp, U512> {
|
pub fn get_4bpp_character_block(slot: usize) -> VolBlock<Tile4bpp, Safe, Safe, 512> {
|
||||||
unsafe { VolBlock::new(CHAR_BASE_BLOCKS.index(slot).to_usize()) }
|
unsafe { VolBlock::new(CHAR_BASE_BLOCKS.index(slot).as_usize()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gives the specified charblock in 8bpp view.
|
/// Gives the specified charblock in 8bpp view.
|
||||||
pub fn get_8bpp_character_block(slot: usize) -> VolBlock<Tile8bpp, U256> {
|
pub fn get_8bpp_character_block(slot: usize) -> VolBlock<Tile8bpp, Safe, Safe, 256> {
|
||||||
unsafe { VolBlock::new(CHAR_BASE_BLOCKS.index(slot).to_usize()) }
|
unsafe { VolBlock::new(CHAR_BASE_BLOCKS.index(slot).as_usize()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_screen_block(slot: usize) -> VolBlock<TextScreenblockEntry, U1024> {
|
pub fn get_screen_block(slot: usize) -> VolBlock<TextScreenblockEntry, Safe, Safe, 1024> {
|
||||||
unsafe { VolBlock::new(SCREEN_BASE_BLOCKS.index(slot).to_usize()) }
|
unsafe { VolBlock::new(SCREEN_BASE_BLOCKS.index(slot).as_usize()) }
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
//! Module for the Bitmap video modes.
|
//! Module for the Bitmap video modes.
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use core::ops::{Div, Mul};
|
|
||||||
use typenum::consts::{U128, U160, U2, U256, U4};
|
|
||||||
|
|
||||||
/// A bitmap video mode with full color and full resolution.
|
/// A bitmap video mode with full color and full resolution.
|
||||||
///
|
///
|
||||||
|
@ -23,10 +21,10 @@ impl Mode3 {
|
||||||
/// The screen's height in this mode.
|
/// The screen's height in this mode.
|
||||||
pub const HEIGHT: usize = 160;
|
pub const HEIGHT: usize = 160;
|
||||||
|
|
||||||
const VRAM: VolBlock<Color, <U256 as Mul<U160>>::Output> =
|
const VRAM: VolBlock<Color, Safe, Safe, { 256 * 160 }> =
|
||||||
unsafe { VolBlock::new(VRAM_BASE_USIZE) };
|
unsafe { VolBlock::new(VRAM_BASE_USIZE) };
|
||||||
|
|
||||||
const WORDS_BLOCK: VolBlock<u32, <<U256 as Mul<U160>>::Output as Div<U2>>::Output> =
|
const WORDS_BLOCK: VolBlock<u32, Safe, Safe, { (256 * 160) / 2 }> =
|
||||||
unsafe { VolBlock::new(VRAM_BASE_USIZE) };
|
unsafe { VolBlock::new(VRAM_BASE_USIZE) };
|
||||||
|
|
||||||
/// Gets the address of the pixel specified.
|
/// Gets the address of the pixel specified.
|
||||||
|
@ -34,7 +32,7 @@ impl Mode3 {
|
||||||
/// ## Failure
|
/// ## Failure
|
||||||
///
|
///
|
||||||
/// Gives `None` if out of bounds
|
/// Gives `None` if out of bounds
|
||||||
fn get(col: usize, row: usize) -> Option<VolAddress<Color>> {
|
fn get(col: usize, row: usize) -> Option<VolAddress<Color, Safe, Safe>> {
|
||||||
Self::VRAM.get(col + row * Self::WIDTH)
|
Self::VRAM.get(col + row * Self::WIDTH)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,7 +42,7 @@ impl Mode3 {
|
||||||
///
|
///
|
||||||
/// Gives `None` if out of bounds
|
/// Gives `None` if out of bounds
|
||||||
pub fn read(col: usize, row: usize) -> Option<Color> {
|
pub fn read(col: usize, row: usize) -> Option<Color> {
|
||||||
Self::get(col, row).map(VolAddress::read)
|
Self::get(col, row).map(VolAddress::<Color, Safe, Safe>::read)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Writes a color to the pixel specified.
|
/// Writes a color to the pixel specified.
|
||||||
|
@ -164,16 +162,16 @@ impl Mode4 {
|
||||||
/// The screen's height in this mode.
|
/// The screen's height in this mode.
|
||||||
pub const HEIGHT: usize = 160;
|
pub const HEIGHT: usize = 160;
|
||||||
|
|
||||||
const PAGE0_INDEXES: VolBlock<u8, <U256 as Mul<U160>>::Output> =
|
const PAGE0_INDEXES: VolBlock<u8, Safe, Safe, { 256 * 160 }> =
|
||||||
unsafe { VolBlock::new(VRAM_BASE_USIZE) };
|
unsafe { VolBlock::new(VRAM_BASE_USIZE) };
|
||||||
|
|
||||||
const PAGE1_INDEXES: VolBlock<u8, <U256 as Mul<U160>>::Output> =
|
const PAGE1_INDEXES: VolBlock<u8, Safe, Safe, { 256 * 160 }> =
|
||||||
unsafe { VolBlock::new(VRAM_BASE_USIZE + PAGE1_OFFSET) };
|
unsafe { VolBlock::new(VRAM_BASE_USIZE + PAGE1_OFFSET) };
|
||||||
|
|
||||||
const PAGE0_WORDS: VolBlock<u32, <<U256 as Mul<U160>>::Output as Div<U4>>::Output> =
|
const PAGE0_WORDS: VolBlock<u32, Safe, Safe, { (256 * 160) / 4 }> =
|
||||||
unsafe { VolBlock::new(VRAM_BASE_USIZE) };
|
unsafe { VolBlock::new(VRAM_BASE_USIZE) };
|
||||||
|
|
||||||
const PAGE1_WORDS: VolBlock<u32, <<U256 as Mul<U160>>::Output as Div<U4>>::Output> =
|
const PAGE1_WORDS: VolBlock<u32, Safe, Safe, { (256 * 160) / 4 }> =
|
||||||
unsafe { VolBlock::new(VRAM_BASE_USIZE + PAGE1_OFFSET) };
|
unsafe { VolBlock::new(VRAM_BASE_USIZE + PAGE1_OFFSET) };
|
||||||
|
|
||||||
/// Reads the color of the pixel specified.
|
/// Reads the color of the pixel specified.
|
||||||
|
@ -187,7 +185,7 @@ impl Mode4 {
|
||||||
Page::One => Self::PAGE1_INDEXES,
|
Page::One => Self::PAGE1_INDEXES,
|
||||||
}
|
}
|
||||||
.get(col + row * Self::WIDTH)
|
.get(col + row * Self::WIDTH)
|
||||||
.map(VolAddress::read)
|
.map(VolAddress::<u8, Safe, Safe>::read)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Writes a color to the pixel specified.
|
/// Writes a color to the pixel specified.
|
||||||
|
@ -201,12 +199,12 @@ impl Mode4 {
|
||||||
if col < Self::WIDTH && row < Self::HEIGHT {
|
if col < Self::WIDTH && row < Self::HEIGHT {
|
||||||
let real_index = col + row * Self::WIDTH;
|
let real_index = col + row * Self::WIDTH;
|
||||||
let rounded_down_index = real_index & !1;
|
let rounded_down_index = real_index & !1;
|
||||||
let address: VolAddress<u16> = unsafe {
|
let address: VolAddress<u16, Safe, Safe> = unsafe {
|
||||||
match page {
|
match page {
|
||||||
Page::Zero => Self::PAGE0_INDEXES,
|
Page::Zero => Self::PAGE0_INDEXES,
|
||||||
Page::One => Self::PAGE1_INDEXES,
|
Page::One => Self::PAGE1_INDEXES,
|
||||||
}
|
}
|
||||||
.index_unchecked(rounded_down_index)
|
.index(rounded_down_index)
|
||||||
.cast::<u16>()
|
.cast::<u16>()
|
||||||
};
|
};
|
||||||
if real_index != rounded_down_index {
|
if real_index != rounded_down_index {
|
||||||
|
@ -247,11 +245,9 @@ impl Mode4 {
|
||||||
|
|
||||||
let pal8bpp_32 = pal8bpp as u32;
|
let pal8bpp_32 = pal8bpp as u32;
|
||||||
let bulk_color = (pal8bpp_32 << 24) | (pal8bpp_32 << 16) | (pal8bpp_32 << 8) | pal8bpp_32;
|
let bulk_color = (pal8bpp_32 << 24) | (pal8bpp_32 << 16) | (pal8bpp_32 << 8) | pal8bpp_32;
|
||||||
let words_address = unsafe {
|
let words_address = match page {
|
||||||
match page {
|
Page::Zero => Self::PAGE0_WORDS.index(0).as_usize(),
|
||||||
Page::Zero => Self::PAGE0_WORDS.index_unchecked(0).to_usize(),
|
Page::One => Self::PAGE1_WORDS.index(0).as_usize(),
|
||||||
Page::One => Self::PAGE1_WORDS.index_unchecked(0).to_usize(),
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
unsafe { DMA3::fill32(&bulk_color, words_address as *mut u32, Self::PAGE0_WORDS.len() as u16) };
|
unsafe { DMA3::fill32(&bulk_color, words_address as *mut u32, Self::PAGE0_WORDS.len() as u16) };
|
||||||
}
|
}
|
||||||
|
@ -331,16 +327,16 @@ impl Mode5 {
|
||||||
/// The screen's height in this mode.
|
/// The screen's height in this mode.
|
||||||
pub const HEIGHT: usize = 128;
|
pub const HEIGHT: usize = 128;
|
||||||
|
|
||||||
const PAGE0_PIXELS: VolBlock<Color, <U160 as Mul<U128>>::Output> =
|
const PAGE0_PIXELS: VolBlock<Color, Safe, Safe, { 160 * 128 }> =
|
||||||
unsafe { VolBlock::new(VRAM_BASE_USIZE) };
|
unsafe { VolBlock::new(VRAM_BASE_USIZE) };
|
||||||
|
|
||||||
const PAGE1_PIXELS: VolBlock<Color, <U160 as Mul<U128>>::Output> =
|
const PAGE1_PIXELS: VolBlock<Color, Safe, Safe, { 160 * 128 }> =
|
||||||
unsafe { VolBlock::new(VRAM_BASE_USIZE + PAGE1_OFFSET) };
|
unsafe { VolBlock::new(VRAM_BASE_USIZE + PAGE1_OFFSET) };
|
||||||
|
|
||||||
const PAGE0_WORDS: VolBlock<u32, <<U160 as Mul<U128>>::Output as Div<U2>>::Output> =
|
const PAGE0_WORDS: VolBlock<u32, Safe, Safe, { (160 * 128) / 2 }> =
|
||||||
unsafe { VolBlock::new(VRAM_BASE_USIZE) };
|
unsafe { VolBlock::new(VRAM_BASE_USIZE) };
|
||||||
|
|
||||||
const PAGE1_WORDS: VolBlock<u32, <<U160 as Mul<U128>>::Output as Div<U2>>::Output> =
|
const PAGE1_WORDS: VolBlock<u32, Safe, Safe, { (160 * 128) / 2 }> =
|
||||||
unsafe { VolBlock::new(VRAM_BASE_USIZE + PAGE1_OFFSET) };
|
unsafe { VolBlock::new(VRAM_BASE_USIZE + PAGE1_OFFSET) };
|
||||||
|
|
||||||
/// Reads the color of the pixel specified.
|
/// Reads the color of the pixel specified.
|
||||||
|
@ -354,7 +350,7 @@ impl Mode5 {
|
||||||
Page::One => Self::PAGE1_PIXELS,
|
Page::One => Self::PAGE1_PIXELS,
|
||||||
}
|
}
|
||||||
.get(col + row * Self::WIDTH)
|
.get(col + row * Self::WIDTH)
|
||||||
.map(VolAddress::read)
|
.map(VolAddress::<Color, Safe, Safe>::read)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Writes a color to the pixel specified.
|
/// Writes a color to the pixel specified.
|
||||||
|
@ -394,11 +390,9 @@ impl Mode5 {
|
||||||
|
|
||||||
let color32 = color.0 as u32;
|
let color32 = color.0 as u32;
|
||||||
let bulk_color = color32 << 16 | color32;
|
let bulk_color = color32 << 16 | color32;
|
||||||
let words_address = unsafe {
|
let words_address = match page {
|
||||||
match page {
|
Page::Zero => Self::PAGE0_WORDS.index(0).as_usize(),
|
||||||
Page::Zero => Self::PAGE0_WORDS.index_unchecked(0).to_usize(),
|
Page::One => Self::PAGE1_WORDS.index(0).as_usize(),
|
||||||
Page::One => Self::PAGE1_WORDS.index_unchecked(0).to_usize(),
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
unsafe { DMA3::fill32(&bulk_color, words_address as *mut u32, Self::PAGE0_WORDS.len() as u16) };
|
unsafe { DMA3::fill32(&bulk_color, words_address as *mut u32, Self::PAGE0_WORDS.len() as u16) };
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue