mirror of
https://github.com/italicsjenga/gba.git
synced 2024-12-23 10:51: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"]
|
||||
|
||||
[dependencies]
|
||||
typenum = "1.10"
|
||||
voladdress = "0.2"
|
||||
voladdress = { version = "0.4.0-alpha.0", git = "https://github.com/rust-console/voladdress" }
|
||||
gba-proc-macro = "0.5"
|
||||
embedded-hal = { version = "0.2.4", 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);
|
||||
|
||||
// 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.
|
||||
const DISPLAY_SETTINGS: DisplayStatusSetting = DisplayStatusSetting::new()
|
||||
|
@ -78,7 +78,7 @@ fn main(_argc: isize, _argv: *const *const u8) -> isize {
|
|||
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
|
||||
// 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
|
||||
// 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() {
|
||||
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() {
|
||||
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() {
|
||||
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() {
|
||||
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 gba::{
|
||||
fatal, warn,
|
||||
fatal,
|
||||
io::{
|
||||
display::{DisplayControlSetting, DisplayMode, DISPCNT},
|
||||
timers::{TimerControlSetting, TimerTickRate, TM0CNT_H, TM0CNT_L, TM1CNT_H, TM1CNT_L},
|
||||
},
|
||||
save::*,
|
||||
vram::bitmap::Mode3,
|
||||
Color,
|
||||
warn, Color,
|
||||
};
|
||||
|
||||
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) -> ! {
|
||||
set_screen_color(31, 0, 0);
|
||||
fatal!("{}", info);
|
||||
loop {}
|
||||
}
|
||||
|
||||
#[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];
|
||||
|
||||
output!(" - Clearing media...");
|
||||
access.prepare_write(offset..offset+len)?;
|
||||
access.prepare_write(offset..offset + len)?;
|
||||
|
||||
output!(" - Writing media...");
|
||||
let mut rng = seed.clone();
|
||||
|
@ -168,7 +167,9 @@ fn main(_argc: isize, _argv: *const *const u8) -> isize {
|
|||
|
||||
output!(
|
||||
"[ 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));
|
||||
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
|
||||
set_screen_color(0, 31, 0);
|
||||
loop { }
|
||||
loop {}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
|
||||
#![cfg_attr(not(target_arch = "arm"), allow(unused_variables))]
|
||||
|
||||
use core::mem;
|
||||
use super::*;
|
||||
use io::irq::IrqFlags;
|
||||
|
||||
|
@ -184,8 +183,8 @@ pub fn interrupt_wait(ignore_current_flags: bool, target_flags: IrqFlags) {
|
|||
unsafe {
|
||||
asm!(
|
||||
"swi 0x04",
|
||||
in("r0") mem::transmute::<bool, u8>(ignore_current_flags),
|
||||
in("r1") mem::transmute::<IrqFlags, u16>(target_flags),
|
||||
in("r0") ignore_current_flags as u8,
|
||||
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
|
||||
//! the gba crate. It currently supports the latest versions of mGBA and NO$GBA.
|
||||
|
||||
use crate::{
|
||||
io::{
|
||||
dma::{DMAControlSetting, DMA0, DMA1, DMA2, DMA3},
|
||||
irq::{IrqEnableSetting, IME},
|
||||
},
|
||||
sync::{InitOnce, RawMutex, Static},
|
||||
};
|
||||
use crate::sync::{InitOnce, RawMutex, Static};
|
||||
use core::fmt::{Arguments, Error};
|
||||
use voladdress::VolAddress;
|
||||
|
||||
pub mod mgba;
|
||||
pub mod nocash;
|
||||
|
@ -127,5 +120,5 @@ pub fn crash() -> ! {
|
|||
}
|
||||
|
||||
#[cfg(not(all(target_vendor = "nintendo", target_env = "agb")))]
|
||||
loop { }
|
||||
loop {}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
use super::{DebugInterface, DebugLevel};
|
||||
use crate::sync::InitOnce;
|
||||
use core::fmt::{Arguments, Write};
|
||||
use voladdress::VolAddress;
|
||||
use voladdress::*;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
#[repr(u16)]
|
||||
|
@ -22,13 +22,13 @@ pub enum MGBADebugLevel {
|
|||
}
|
||||
|
||||
// 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_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;
|
||||
|
||||
// Only enable MGBA debugging once.
|
||||
|
@ -82,7 +82,7 @@ impl MGBADebug {
|
|||
impl core::fmt::Write for MGBADebug {
|
||||
fn write_str(&mut self, s: &str) -> Result<(), core::fmt::Error> {
|
||||
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();
|
||||
while self.bytes_written < 255 {
|
||||
match str_iter.next() {
|
||||
|
|
|
@ -9,11 +9,10 @@ use crate::{
|
|||
sync::InitOnce,
|
||||
};
|
||||
use core::fmt::{Arguments, Write};
|
||||
use typenum::consts::U16;
|
||||
use voladdress::{VolAddress, VolBlock};
|
||||
use voladdress::*;
|
||||
|
||||
const CHAR_OUT: VolAddress<u8> = unsafe { VolAddress::new(0x04FFFA1C) };
|
||||
const SIGNATURE_ADDR: VolBlock<u8, U16> = unsafe { VolBlock::new(0x04FFFA00) };
|
||||
const CHAR_OUT: VolAddress<u8, Safe, Safe> = unsafe { VolAddress::new(0x04FFFA1C) };
|
||||
const SIGNATURE_ADDR: VolBlock<u8, Safe, Safe, 16> = unsafe { VolBlock::new(0x04FFFA00) };
|
||||
|
||||
const SIGNATURE: [u8; 7] = *b"no$gba ";
|
||||
static NO_CASH_DEBUGGING: InitOnce<bool> = InitOnce::new();
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
#![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.
|
||||
|
|
@ -3,13 +3,17 @@
|
|||
use super::*;
|
||||
|
||||
/// 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.
|
||||
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.
|
||||
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.
|
||||
pub const BG3CNT: VolAddress<BackgroundControlSetting> = unsafe { VolAddress::new(0x400_000E) };
|
||||
pub const BG3CNT: VolAddress<BackgroundControlSetting, Safe, Safe> =
|
||||
unsafe { VolAddress::new(0x400_000E) };
|
||||
|
||||
newtype! {
|
||||
/// Allows configuration of a background layer.
|
||||
|
@ -66,24 +70,24 @@ pub enum BGSize {
|
|||
}
|
||||
|
||||
/// 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.
|
||||
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.
|
||||
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.
|
||||
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.
|
||||
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.
|
||||
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.
|
||||
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.
|
||||
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
|
||||
// BG2X_L
|
||||
|
|
|
@ -3,7 +3,8 @@
|
|||
use super::*;
|
||||
|
||||
/// 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! {
|
||||
/// TODO: docs
|
||||
|
@ -43,7 +44,8 @@ newtype_enum! {
|
|||
}
|
||||
|
||||
/// 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! {
|
||||
/// TODO: docs
|
||||
|
@ -59,7 +61,7 @@ impl AlphaBlendingSetting {
|
|||
}
|
||||
|
||||
/// 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! {
|
||||
/// TODO: docs
|
||||
|
|
|
@ -5,7 +5,8 @@ use super::*;
|
|||
/// LCD Control. Read/Write.
|
||||
///
|
||||
/// 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!(
|
||||
/// Setting for the display control register.
|
||||
|
@ -96,7 +97,8 @@ pub fn display_control() -> DisplayControlSetting {
|
|||
}
|
||||
|
||||
/// 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!(
|
||||
/// 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
|
||||
/// this is at or above the `VBLANK_SCANLINE` value then the display controller
|
||||
/// 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.
|
||||
pub const VBLANK_SCANLINE: u16 = 160;
|
||||
|
||||
/// 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! {
|
||||
/// Allows control of the Mosaic effect.
|
||||
|
|
|
@ -127,13 +127,14 @@ pub enum DMAStartTiming {
|
|||
pub struct DMA0;
|
||||
impl DMA0 {
|
||||
/// 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.
|
||||
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.
|
||||
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.
|
||||
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.
|
||||
///
|
||||
|
@ -190,13 +191,14 @@ impl DMA0 {
|
|||
pub struct DMA1;
|
||||
impl DMA1 {
|
||||
/// 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.
|
||||
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.
|
||||
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.
|
||||
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.
|
||||
///
|
||||
|
@ -253,13 +255,14 @@ impl DMA1 {
|
|||
pub struct DMA2;
|
||||
impl DMA2 {
|
||||
/// 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.
|
||||
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.
|
||||
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.
|
||||
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.
|
||||
///
|
||||
|
@ -317,13 +320,14 @@ impl DMA2 {
|
|||
pub struct DMA3;
|
||||
impl DMA3 {
|
||||
/// 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.
|
||||
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.
|
||||
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.
|
||||
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.
|
||||
///
|
||||
|
|
|
@ -103,7 +103,7 @@ use super::*;
|
|||
newtype!(
|
||||
/// A newtype over all interrupt flags.
|
||||
IrqFlags,
|
||||
u16
|
||||
pub(crate) u16
|
||||
);
|
||||
|
||||
impl IrqFlags {
|
||||
|
@ -130,7 +130,7 @@ impl IrqFlags {
|
|||
///
|
||||
/// After setting up interrupt handlers, set the flags on this register type corresponding to the
|
||||
/// 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.
|
||||
///
|
||||
|
@ -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
|
||||
/// handler must write a `1` bit to all bits that are enabled on this register
|
||||
/// 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! {
|
||||
/// Setting to control whether interrupts are enabled.
|
||||
|
@ -161,7 +161,7 @@ impl IrqEnableSetting {
|
|||
}
|
||||
|
||||
/// 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.
|
||||
///
|
||||
|
@ -169,7 +169,7 @@ pub const IME: VolAddress<IrqEnableSetting> = unsafe { VolAddress::new(0x400_020
|
|||
/// [`vblank_interrupt_wait`](bios::vblank_interrupt_wait), the corresponding
|
||||
/// interrupt handler MUST set the flag of the interrupt it has handled on this
|
||||
/// 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.
|
||||
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
|
||||
/// to work with) then call `read_key_input()` rather than reading this register
|
||||
/// 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.
|
||||
#[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.
|
||||
///
|
||||
/// 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! {
|
||||
/// Allows configuration of when a keypad interrupt fires.
|
||||
|
|
|
@ -3,13 +3,14 @@
|
|||
use super::*;
|
||||
|
||||
/// 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.
|
||||
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.
|
||||
pub const RCNT: VolAddress<IoControlSetting> = unsafe { VolAddress::new(0x400_0134) };
|
||||
pub const RCNT: VolAddress<IoControlSetting, Safe, Safe> = unsafe { VolAddress::new(0x400_0134) };
|
||||
|
||||
newtype!(
|
||||
/// Setting for the serial IO control register.
|
||||
|
@ -122,7 +123,7 @@ newtype_enum! {
|
|||
JoyBus = 3,
|
||||
}
|
||||
|
||||
/// Empty stuct that implements embedded_hal traits.
|
||||
/// Empty struct that implements embedded_hal traits.
|
||||
#[cfg(feature = "serial")]
|
||||
#[derive(Clone)]
|
||||
pub struct SioSerial;
|
||||
|
|
|
@ -5,7 +5,8 @@ use super::*;
|
|||
//TODO within these "read/write" registers only some bits are actually 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! {
|
||||
/// TODO: docs
|
||||
|
@ -22,7 +23,8 @@ impl SweepRegisterSetting {
|
|||
}
|
||||
|
||||
/// 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! {
|
||||
/// TODO: docs
|
||||
|
@ -41,7 +43,8 @@ impl DutyLenEnvelopeSetting {
|
|||
}
|
||||
|
||||
/// 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! {
|
||||
/// TODO: docs
|
||||
|
@ -58,13 +61,15 @@ impl FrequencyControlSetting {
|
|||
}
|
||||
|
||||
/// 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.
|
||||
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.
|
||||
pub const SOUND3CNT_L: VolAddress<StopWaveRAMSelectSetting> =
|
||||
pub const SOUND3CNT_L: VolAddress<StopWaveRAMSelectSetting, Safe, Safe> =
|
||||
unsafe { VolAddress::new(0x400_0070) };
|
||||
|
||||
newtype! {
|
||||
|
@ -82,7 +87,8 @@ impl StopWaveRAMSelectSetting {
|
|||
}
|
||||
|
||||
/// 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! {
|
||||
/// TODO: docs
|
||||
|
@ -99,27 +105,29 @@ impl LengthVolumeSetting {
|
|||
}
|
||||
|
||||
/// 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)
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
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.
|
||||
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! {
|
||||
/// TODO: docs
|
||||
|
@ -137,7 +145,8 @@ impl LengthEnvelopeSetting {
|
|||
}
|
||||
|
||||
/// 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! {
|
||||
/// TODO: docs
|
||||
|
@ -158,16 +167,16 @@ impl NoiseFrequencySetting {
|
|||
// TODO: unify FIFO as
|
||||
|
||||
/// 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)
|
||||
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)
|
||||
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)
|
||||
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.
|
||||
pub const SOUNDCNT_L: VolAddress<NonWaveVolumeEnableSetting> =
|
||||
pub const SOUNDCNT_L: VolAddress<NonWaveVolumeEnableSetting, Safe, Safe> =
|
||||
unsafe { VolAddress::new(0x400_0080) };
|
||||
|
||||
newtype! {
|
||||
|
@ -186,7 +195,8 @@ impl NonWaveVolumeEnableSetting {
|
|||
}
|
||||
|
||||
/// 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! {
|
||||
/// TODO: docs
|
||||
|
@ -222,7 +232,8 @@ newtype_enum! {
|
|||
}
|
||||
|
||||
/// 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! {
|
||||
/// TODO: docs
|
||||
|
@ -241,7 +252,8 @@ impl SoundMasterSetting {
|
|||
}
|
||||
|
||||
/// 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! {
|
||||
/// TODO: docs
|
||||
|
|
|
@ -28,28 +28,32 @@ use super::*;
|
|||
// TODO: striding blocks?
|
||||
|
||||
/// 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).
|
||||
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).
|
||||
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).
|
||||
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.
|
||||
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.
|
||||
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.
|
||||
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.
|
||||
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! {
|
||||
/// Allows control of a timer unit.
|
||||
|
|
|
@ -3,10 +3,12 @@
|
|||
use super::*;
|
||||
|
||||
/// 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)
|
||||
pub const WIN1H: VolAddress<HorizontalWindowSetting> = unsafe { VolAddress::new(0x400_0042) };
|
||||
pub const WIN1H: VolAddress<HorizontalWindowSetting, Safe, Safe> =
|
||||
unsafe { VolAddress::new(0x400_0042) };
|
||||
|
||||
newtype! {
|
||||
/// TODO: docs
|
||||
|
@ -22,10 +24,12 @@ impl HorizontalWindowSetting {
|
|||
}
|
||||
|
||||
/// 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)
|
||||
pub const WIN1V: VolAddress<VerticalWindowSetting> = unsafe { VolAddress::new(0x400_0046) };
|
||||
pub const WIN1V: VolAddress<VerticalWindowSetting, Safe, Safe> =
|
||||
unsafe { VolAddress::new(0x400_0046) };
|
||||
|
||||
newtype! {
|
||||
/// TODO: docs
|
||||
|
@ -41,7 +45,8 @@ impl VerticalWindowSetting {
|
|||
}
|
||||
|
||||
/// 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! {
|
||||
/// TODO: docs
|
||||
|
@ -67,7 +72,8 @@ impl InsideWindowSetting {
|
|||
}
|
||||
|
||||
/// 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! {
|
||||
/// TODO: docs
|
||||
|
|
10
src/lib.rs
10
src/lib.rs
|
@ -1,8 +1,7 @@
|
|||
#![cfg_attr(not(test), no_std)]
|
||||
#![feature(asm, global_asm, isa_attribute)]
|
||||
#![allow(clippy::cast_lossless)]
|
||||
#![deny(clippy::float_arithmetic)]
|
||||
#![warn(missing_docs)]
|
||||
#![allow(unused_imports)]
|
||||
//#![warn(missing_docs)]
|
||||
|
||||
//! This crate helps you write GBA ROMs.
|
||||
//!
|
||||
|
@ -18,12 +17,11 @@
|
|||
//! do, it's a giant bag of Undefined Behavior.
|
||||
|
||||
pub(crate) use gba_proc_macro::phantom_fields;
|
||||
pub(crate) use voladdress::{read_only::ROVolAddress, VolAddress, VolBlock};
|
||||
|
||||
use voladdress::*;
|
||||
|
||||
pub mod macros;
|
||||
|
||||
pub mod base;
|
||||
|
||||
pub mod bios;
|
||||
|
||||
pub mod iwram;
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
|
||||
use super::*;
|
||||
|
||||
use typenum::consts::{U128, U32};
|
||||
|
||||
newtype! {
|
||||
/// 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
|
||||
/// 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
|
||||
|
||||
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
|
||||
/// 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
|
||||
|
||||
pub fn write_affine_parameters(slot: usize, params: AffineParameters) -> Option<()> {
|
||||
|
|
|
@ -25,42 +25,36 @@
|
|||
|
||||
use super::*;
|
||||
|
||||
use typenum::consts::U256;
|
||||
|
||||
// TODO: PalIndex newtypes?
|
||||
|
||||
/// 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.
|
||||
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.
|
||||
pub const fn index_palram_bg_8bpp(slot: u8) -> VolAddress<Color> {
|
||||
// Note(Lokathor): because of the `u8` limit we can't go out of bounds here.
|
||||
unsafe { PALRAM_BG.index_unchecked(slot as usize) }
|
||||
pub const fn index_palram_bg_8bpp(slot: u8) -> VolAddress<Color, Safe, Safe> {
|
||||
PALRAM_BG.index(slot as usize)
|
||||
}
|
||||
|
||||
/// Obtains the address of the specified 8bpp object palette slot.
|
||||
pub const fn index_palram_obj_8bpp(slot: u8) -> VolAddress<Color> {
|
||||
// Note(Lokathor): because of the `u8` limit we can't go out of bounds here.
|
||||
unsafe { PALRAM_OBJ.index_unchecked(slot as usize) }
|
||||
pub const fn index_palram_obj_8bpp(slot: u8) -> VolAddress<Color, Safe, Safe> {
|
||||
PALRAM_OBJ.index(slot as usize)
|
||||
}
|
||||
|
||||
/// Obtains the address of the specified 4bpp background palbank and palslot.
|
||||
///
|
||||
/// Accesses `palbank * 16 + palslot`, if this is out of bounds the computation
|
||||
/// will wrap.
|
||||
pub const fn index_palram_bg_4bpp(palbank: u8, palslot: u8) -> VolAddress<Color> {
|
||||
// Note(Lokathor): because of the `u8` limit we can't go out of bounds here.
|
||||
unsafe { PALRAM_BG.index_unchecked(palbank.wrapping_mul(16).wrapping_add(palslot) as usize) }
|
||||
pub const fn index_palram_bg_4bpp(palbank: u8, palslot: u8) -> VolAddress<Color, Safe, Safe> {
|
||||
PALRAM_BG.index(palbank.wrapping_mul(16).wrapping_add(palslot) as usize)
|
||||
}
|
||||
|
||||
/// Obtains the address of the specified 4bpp object palbank and palslot.
|
||||
///
|
||||
/// Accesses `palbank * 16 + palslot`, if this is out of bounds the computation
|
||||
/// will wrap.
|
||||
pub const fn index_palram_obj_4bpp(palbank: u8, palslot: u8) -> VolAddress<Color> {
|
||||
// Note(Lokathor): because of the `u8` limit we can't go out of bounds here.
|
||||
unsafe { PALRAM_OBJ.index_unchecked(palbank.wrapping_mul(16).wrapping_add(palslot) as usize) }
|
||||
pub const fn index_palram_obj_4bpp(palbank: u8, palslot: u8) -> VolAddress<Color, Safe, Safe> {
|
||||
PALRAM_OBJ.index(palbank.wrapping_mul(16).wrapping_add(palslot) as usize)
|
||||
}
|
||||
|
|
|
@ -9,9 +9,9 @@ use crate::{
|
|||
sync::with_irqs_disabled,
|
||||
};
|
||||
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_LEN: usize = 1 << SECTOR_SHIFT;
|
||||
const SECTOR_MASK: usize = SECTOR_LEN - 1;
|
||||
|
@ -156,32 +156,30 @@ impl EepromProperties {
|
|||
|
||||
/// Writes a sector directly.
|
||||
fn write_sector_raw(&self, word: usize, block: &[u8]) -> Result<(), Error> {
|
||||
unsafe {
|
||||
// Write sector command. The command is a one bit, followed by a
|
||||
// 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 ...]
|
||||
// 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();
|
||||
buf.write_bit(1);
|
||||
buf.write_bit(0);
|
||||
buf.write_num(self.addr_bits, word as u32);
|
||||
for i in 0..8 {
|
||||
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(())
|
||||
// Write sector command. The command is a one bit, followed by a
|
||||
// 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 ...]
|
||||
// 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();
|
||||
buf.write_bit(1);
|
||||
buf.write_bit(0);
|
||||
buf.write_num(self.addr_bits, word as u32);
|
||||
for i in 0..8 {
|
||||
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(())
|
||||
}
|
||||
|
||||
/// Writes a sector to the EEPROM, keeping any current contents outside the
|
||||
|
@ -218,7 +216,7 @@ impl EepromProperties {
|
|||
let start = offset & SECTOR_MASK;
|
||||
let end_len = cmp::min(SECTOR_LEN - start, buf.len());
|
||||
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..];
|
||||
offset += end_len;
|
||||
}
|
||||
|
|
|
@ -9,14 +9,13 @@ use super::{
|
|||
};
|
||||
use crate::sync::{with_irqs_disabled, InitOnce, Static};
|
||||
use core::cmp;
|
||||
use typenum::consts::U65536;
|
||||
use voladdress::{VolAddress, VolBlock};
|
||||
use voladdress::*;
|
||||
|
||||
// Volatile address ports for flash
|
||||
const FLASH_PORT_BANK: VolAddress<u8> = unsafe { VolAddress::new(0x0E000000) };
|
||||
const FLASH_PORT_A: VolAddress<u8> = unsafe { VolAddress::new(0x0E005555) };
|
||||
const FLASH_PORT_B: VolAddress<u8> = unsafe { VolAddress::new(0x0E002AAA) };
|
||||
const FLASH_DATA: VolBlock<u8, U65536> = unsafe { VolBlock::new(0x0E000000) };
|
||||
const FLASH_PORT_BANK: VolAddress<u8, Safe, Safe> = unsafe { VolAddress::new(0x0E000000) };
|
||||
const FLASH_PORT_A: VolAddress<u8, Safe, Safe> = unsafe { VolAddress::new(0x0E005555) };
|
||||
const FLASH_PORT_B: VolAddress<u8, Safe, Safe> = unsafe { VolAddress::new(0x0E002AAA) };
|
||||
const FLASH_DATA: VolBlock<u8, Safe, Safe, 65536> = unsafe { VolBlock::new(0x0E000000) };
|
||||
|
||||
// Various constants related to sector sizes
|
||||
const BANK_SHIFT: usize = 16; // 64 KiB
|
||||
|
@ -133,7 +132,7 @@ struct ChipInfo {
|
|||
|
||||
/// The timeout in milliseconds for writes to this chip.
|
||||
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,
|
||||
/// The timeout in milliseconds for erasing the entire chip.
|
||||
erase_chip_timeout: u16,
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
//! 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 crate::{
|
||||
io::timers::*,
|
||||
sync::{RawMutex, RawMutexGuard, Static},
|
||||
};
|
||||
use voladdress::VolAddress;
|
||||
use voladdress::*;
|
||||
|
||||
/// Internal representation for our active timer.
|
||||
#[derive(Copy, Clone, PartialEq)]
|
||||
|
@ -44,8 +44,8 @@ pub fn disable_timeout() {
|
|||
pub struct Timeout {
|
||||
_lock_guard: RawMutexGuard<'static>,
|
||||
active: bool,
|
||||
timer_l: VolAddress<u16>,
|
||||
timer_h: VolAddress<TimerControlSetting>,
|
||||
timer_l: VolAddress<u16, Safe, Safe>,
|
||||
timer_h: VolAddress<TimerControlSetting, Safe, Safe>,
|
||||
}
|
||||
impl 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`
|
||||
/// working. While this call is not properly inlined, working is better than
|
||||
/// not working at all.
|
||||
/// working. While this call is not properly inlined, working is better than not
|
||||
/// working at all.
|
||||
///
|
||||
/// This seems to be a problem caused by Rust issue #62256:
|
||||
/// <https://github.com/rust-lang/rust/issues/62256>
|
||||
///
|
||||
/// 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)]
|
||||
#[deprecated]
|
||||
#[allow(dead_code)]
|
||||
|
@ -49,15 +55,15 @@ pub unsafe extern "C" fn __sync_synchronize() {}
|
|||
/// for game functionality.
|
||||
pub fn with_irqs_disabled<T>(mut func: impl FnOnce() -> T) -> T {
|
||||
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.
|
||||
memory_write_hint(&mut 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);
|
||||
IME.write(current_ime);
|
||||
unsafe { IME.write(current_ime) };
|
||||
|
||||
result
|
||||
}
|
||||
|
|
|
@ -1,15 +1,19 @@
|
|||
#![cfg_attr(not(target_arch = "arm"), allow(unused_variables))]
|
||||
|
||||
use super::*;
|
||||
use core::{cell::UnsafeCell, mem, mem::MaybeUninit, ptr};
|
||||
use crate::sync::with_irqs_disabled;
|
||||
use core::{
|
||||
cell::UnsafeCell,
|
||||
mem::{align_of, size_of, MaybeUninit},
|
||||
ptr,
|
||||
};
|
||||
|
||||
/// The internal function for replacing a `Copy` (really `!Drop`) value in a
|
||||
/// [`Static`]. This uses assembly to use an `stmia` instruction to ensure
|
||||
/// an IRQ cannot occur during the write operation.
|
||||
#[cfg(target_arch = "arm")]
|
||||
unsafe fn transfer<T: Copy>(dst: *mut T, src: *const T) {
|
||||
let align = mem::align_of::<T>();
|
||||
let size = mem::size_of::<T>();
|
||||
let align = align_of::<T>();
|
||||
let size = size_of::<T>();
|
||||
if size == 0 {
|
||||
// Do nothing with ZSTs. Obviously.
|
||||
} 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")]
|
||||
#[allow(unused_assignments)]
|
||||
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 {
|
||||
// We use assembly here regardless to just do the word aligned copy. This
|
||||
// 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)]
|
||||
#[allow(unused_assignments)]
|
||||
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 {
|
||||
unimplemented!("This should be done via transfer_thumb.");
|
||||
} 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.
|
||||
#[cfg(target_arch = "arm")]
|
||||
unsafe fn exchange<T>(dst: *mut T, src: *const T) -> T {
|
||||
let align = mem::align_of::<T>();
|
||||
let size = mem::size_of::<T>();
|
||||
let align = align_of::<T>();
|
||||
let size = size_of::<T>();
|
||||
if size == 0 {
|
||||
// Do nothing with ZSTs.
|
||||
ptr::read(dst)
|
||||
|
|
21
src/vram.rs
21
src/vram.rs
|
@ -15,8 +15,6 @@
|
|||
|
||||
pub(crate) use super::*;
|
||||
|
||||
use typenum::{U1024, consts::{U256, U32, U512, U6}};
|
||||
|
||||
pub mod affine;
|
||||
pub mod bitmap;
|
||||
pub mod text;
|
||||
|
@ -34,10 +32,11 @@ pub const VRAM_BASE_USIZE: usize = 0x600_0000;
|
|||
pub const PAGE1_OFFSET: usize = 0xA000;
|
||||
|
||||
/// 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.
|
||||
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) };
|
||||
|
||||
newtype! {
|
||||
|
@ -53,15 +52,15 @@ newtype! {
|
|||
}
|
||||
|
||||
/// Gives the specified charblock in 4bpp view.
|
||||
pub fn get_4bpp_character_block(slot: usize) -> VolBlock<Tile4bpp, U512> {
|
||||
unsafe { VolBlock::new(CHAR_BASE_BLOCKS.index(slot).to_usize()) }
|
||||
pub fn get_4bpp_character_block(slot: usize) -> VolBlock<Tile4bpp, Safe, Safe, 512> {
|
||||
unsafe { VolBlock::new(CHAR_BASE_BLOCKS.index(slot).as_usize()) }
|
||||
}
|
||||
|
||||
/// Gives the specified charblock in 8bpp view.
|
||||
pub fn get_8bpp_character_block(slot: usize) -> VolBlock<Tile8bpp, U256> {
|
||||
unsafe { VolBlock::new(CHAR_BASE_BLOCKS.index(slot).to_usize()) }
|
||||
pub fn get_8bpp_character_block(slot: usize) -> VolBlock<Tile8bpp, Safe, Safe, 256> {
|
||||
unsafe { VolBlock::new(CHAR_BASE_BLOCKS.index(slot).as_usize()) }
|
||||
}
|
||||
|
||||
pub fn get_screen_block(slot: usize) -> VolBlock<TextScreenblockEntry, U1024> {
|
||||
unsafe { VolBlock::new(SCREEN_BASE_BLOCKS.index(slot).to_usize()) }
|
||||
}
|
||||
pub fn get_screen_block(slot: usize) -> VolBlock<TextScreenblockEntry, Safe, Safe, 1024> {
|
||||
unsafe { VolBlock::new(SCREEN_BASE_BLOCKS.index(slot).as_usize()) }
|
||||
}
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
//! Module for the Bitmap video modes.
|
||||
|
||||
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.
|
||||
///
|
||||
|
@ -23,10 +21,10 @@ impl Mode3 {
|
|||
/// The screen's height in this mode.
|
||||
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) };
|
||||
|
||||
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) };
|
||||
|
||||
/// Gets the address of the pixel specified.
|
||||
|
@ -34,7 +32,7 @@ impl Mode3 {
|
|||
/// ## Failure
|
||||
///
|
||||
/// 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)
|
||||
}
|
||||
|
||||
|
@ -44,7 +42,7 @@ impl Mode3 {
|
|||
///
|
||||
/// Gives `None` if out of bounds
|
||||
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.
|
||||
|
@ -164,16 +162,16 @@ impl Mode4 {
|
|||
/// The screen's height in this mode.
|
||||
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) };
|
||||
|
||||
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) };
|
||||
|
||||
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) };
|
||||
|
||||
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) };
|
||||
|
||||
/// Reads the color of the pixel specified.
|
||||
|
@ -187,7 +185,7 @@ impl Mode4 {
|
|||
Page::One => Self::PAGE1_INDEXES,
|
||||
}
|
||||
.get(col + row * Self::WIDTH)
|
||||
.map(VolAddress::read)
|
||||
.map(VolAddress::<u8, Safe, Safe>::read)
|
||||
}
|
||||
|
||||
/// Writes a color to the pixel specified.
|
||||
|
@ -201,12 +199,12 @@ impl Mode4 {
|
|||
if col < Self::WIDTH && row < Self::HEIGHT {
|
||||
let real_index = col + row * Self::WIDTH;
|
||||
let rounded_down_index = real_index & !1;
|
||||
let address: VolAddress<u16> = unsafe {
|
||||
let address: VolAddress<u16, Safe, Safe> = unsafe {
|
||||
match page {
|
||||
Page::Zero => Self::PAGE0_INDEXES,
|
||||
Page::One => Self::PAGE1_INDEXES,
|
||||
}
|
||||
.index_unchecked(rounded_down_index)
|
||||
.index(rounded_down_index)
|
||||
.cast::<u16>()
|
||||
};
|
||||
if real_index != rounded_down_index {
|
||||
|
@ -247,11 +245,9 @@ impl Mode4 {
|
|||
|
||||
let pal8bpp_32 = pal8bpp as u32;
|
||||
let bulk_color = (pal8bpp_32 << 24) | (pal8bpp_32 << 16) | (pal8bpp_32 << 8) | pal8bpp_32;
|
||||
let words_address = unsafe {
|
||||
match page {
|
||||
Page::Zero => Self::PAGE0_WORDS.index_unchecked(0).to_usize(),
|
||||
Page::One => Self::PAGE1_WORDS.index_unchecked(0).to_usize(),
|
||||
}
|
||||
let words_address = match page {
|
||||
Page::Zero => Self::PAGE0_WORDS.index(0).as_usize(),
|
||||
Page::One => Self::PAGE1_WORDS.index(0).as_usize(),
|
||||
};
|
||||
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.
|
||||
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) };
|
||||
|
||||
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) };
|
||||
|
||||
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) };
|
||||
|
||||
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) };
|
||||
|
||||
/// Reads the color of the pixel specified.
|
||||
|
@ -354,7 +350,7 @@ impl Mode5 {
|
|||
Page::One => Self::PAGE1_PIXELS,
|
||||
}
|
||||
.get(col + row * Self::WIDTH)
|
||||
.map(VolAddress::read)
|
||||
.map(VolAddress::<Color, Safe, Safe>::read)
|
||||
}
|
||||
|
||||
/// Writes a color to the pixel specified.
|
||||
|
@ -394,11 +390,9 @@ impl Mode5 {
|
|||
|
||||
let color32 = color.0 as u32;
|
||||
let bulk_color = color32 << 16 | color32;
|
||||
let words_address = unsafe {
|
||||
match page {
|
||||
Page::Zero => Self::PAGE0_WORDS.index_unchecked(0).to_usize(),
|
||||
Page::One => Self::PAGE1_WORDS.index_unchecked(0).to_usize(),
|
||||
}
|
||||
let words_address = match page {
|
||||
Page::Zero => Self::PAGE0_WORDS.index(0).as_usize(),
|
||||
Page::One => Self::PAGE1_WORDS.index(0).as_usize(),
|
||||
};
|
||||
unsafe { DMA3::fill32(&bulk_color, words_address as *mut u32, Self::PAGE0_WORDS.len() as u16) };
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue