From d6a630181518fe214e220c4f5849b0399ccb470c Mon Sep 17 00:00:00 2001 From: Lokathor Date: Tue, 25 Dec 2018 23:19:16 -0700 Subject: [PATCH] CLOSE to another release --- Cargo.toml | 2 +- examples/bg_demo.rs | 6 +-- examples/hello_world.rs | 4 +- examples/light_cycle.rs | 4 +- examples/mgba_panic_handler.rs | 4 +- src/bios.rs | 23 ++++++----- src/io/background.rs | 28 +++++++++++-- src/io/display.rs | 55 +++++++++++-------------- src/io/dma.rs | 73 ++++++++++------------------------ src/io/keypad.rs | 63 ++++++++++++++++------------- src/lib.rs | 4 +- src/video/tiled.rs | 23 ++--------- 12 files changed, 134 insertions(+), 155 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index d3d18c9..e265cad 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,7 @@ publish = false [dependencies] typenum = "1.10" -gba-proc-macro = "0.3" +gba-proc-macro = "0.4" #[dev-dependencies] #quickcheck="0.7" diff --git a/examples/bg_demo.rs b/examples/bg_demo.rs index 553a15f..d4b3bd2 100644 --- a/examples/bg_demo.rs +++ b/examples/bg_demo.rs @@ -3,7 +3,7 @@ use gba::{ io::{ - background::{BackgroundControlSetting, BG0}, + background::{BackgroundControlSetting, BG0CNT}, display::{DisplayControlSetting, DISPCNT}, }, palram::index_palram_bg_4bpp, @@ -33,9 +33,9 @@ fn main(_argc: isize, _argv: *const *const u8) -> isize { let dark_entry = TextScreenblockEntry::from_tile_index(1); checker_screenblock(8, light_entry, dark_entry); // bg0 control - BG0::BG0CNT.write(BackgroundControlSetting::from_screen_base_block(8)); + BG0CNT.write(BackgroundControlSetting::from_screen_base_block(8)); // Display Control - DISPCNT.write(DisplayControlSetting::new().with_display_bg0(true)); + DISPCNT.write(DisplayControlSetting::new().with_bg0(true)); loop { // TODO the whole thing } diff --git a/examples/hello_world.rs b/examples/hello_world.rs index db402d8..202b23f 100644 --- a/examples/hello_world.rs +++ b/examples/hello_world.rs @@ -3,7 +3,7 @@ #![forbid(unsafe_code)] use gba::{ - io::display::{DisplayControlMode, DisplayControlSetting, DISPCNT}, + io::display::{DisplayControlSetting, DisplayMode, DISPCNT}, video::bitmap::Mode3, Color, }; @@ -15,7 +15,7 @@ fn panic(_info: &core::panic::PanicInfo) -> ! { #[start] fn main(_argc: isize, _argv: *const *const u8) -> isize { - const SETTING: DisplayControlSetting = DisplayControlSetting::new().with_mode(DisplayControlMode::Bitmap3).with_display_bg2(true); + const SETTING: DisplayControlSetting = DisplayControlSetting::new().with_mode(DisplayMode::Bitmap3).with_bg2(true); DISPCNT.write(SETTING); Mode3::write_pixel(120, 80, Color::from_rgb(31, 0, 0)); Mode3::write_pixel(136, 80, Color::from_rgb(0, 31, 0)); diff --git a/examples/light_cycle.rs b/examples/light_cycle.rs index 6c6ed71..4ba4698 100644 --- a/examples/light_cycle.rs +++ b/examples/light_cycle.rs @@ -4,7 +4,7 @@ use gba::{ io::{ - display::{spin_until_vblank, spin_until_vdraw, DisplayControlMode, DisplayControlSetting, DISPCNT}, + display::{spin_until_vblank, spin_until_vdraw, DisplayControlSetting, DisplayMode, DISPCNT}, keypad::read_key_input, }, video::bitmap::Mode3, @@ -18,7 +18,7 @@ fn panic(_info: &core::panic::PanicInfo) -> ! { #[start] fn main(_argc: isize, _argv: *const *const u8) -> isize { - const SETTING: DisplayControlSetting = DisplayControlSetting::new().with_mode(DisplayControlMode::Bitmap3).with_display_bg2(true); + const SETTING: DisplayControlSetting = DisplayControlSetting::new().with_mode(DisplayMode::Bitmap3).with_bg2(true); DISPCNT.write(SETTING); let mut px = Mode3::SCREEN_WIDTH / 2; diff --git a/examples/mgba_panic_handler.rs b/examples/mgba_panic_handler.rs index 214a56a..7711460 100644 --- a/examples/mgba_panic_handler.rs +++ b/examples/mgba_panic_handler.rs @@ -3,7 +3,7 @@ #![forbid(unsafe_code)] use gba::{ - io::display::{DisplayControlMode, DisplayControlSetting, DISPCNT}, + io::display::{DisplayControlSetting, DisplayMode, DISPCNT}, video::bitmap::Mode3, Color, }; @@ -22,7 +22,7 @@ fn panic(info: &core::panic::PanicInfo) -> ! { #[start] fn main(_argc: isize, _argv: *const *const u8) -> isize { - const SETTING: DisplayControlSetting = DisplayControlSetting::new().with_mode(DisplayControlMode::Bitmap3).with_display_bg2(true); + const SETTING: DisplayControlSetting = DisplayControlSetting::new().with_mode(DisplayMode::Bitmap3).with_bg2(true); DISPCNT.write(SETTING); Mode3::write_pixel(120, 80, Color::from_rgb(31, 0, 0)); Mode3::write_pixel(136, 80, Color::from_rgb(0, 31, 0)); diff --git a/src/bios.rs b/src/bios.rs index 4504f22..bfdf0da 100644 --- a/src/bios.rs +++ b/src/bios.rs @@ -8,7 +8,7 @@ //! whatever value is necessary for that function). Some functions also perform //! necessary checks to save you from yourself, such as not dividing by zero. -use super::register_bit; +use super::bool_bits; //TODO: ALL functions in this module should have `if cfg!(test)` blocks. The //functions that never return must panic, the functions that return nothing @@ -109,14 +109,19 @@ newtype! { } #[allow(missing_docs)] impl RegisterRAMResetFlags { - register_bit!(EWRAM, u8, 0, ewram); - register_bit!(IWRAM, u8, 1 << 1, iwram); - register_bit!(PALRAM, u8, 1 << 2, palram); - register_bit!(VRAM, u8, 1 << 3, vram); - register_bit!(OAM, u8, 1 << 4, oam); - register_bit!(SIO, u8, 1 << 5, sio); - register_bit!(SOUND, u8, 1 << 6, sound); - register_bit!(OTHER_IO, u8, 1 << 7, other_io); + bool_bits!( + u8, + [ + (0, ewram), + (1, iwram), + (2, palram), + (3, vram), + (4, oam), + (5, sio), + (6, sound), + (7, other_io), + ] + ); } /// (`swi 0x02`) Halts the CPU until an interrupt occurs. diff --git a/src/io/background.rs b/src/io/background.rs index 926ce06..1b38309 100644 --- a/src/io/background.rs +++ b/src/io/background.rs @@ -3,15 +3,35 @@ use super::*; newtype! { + /// A newtype over the various display control options that you have on a GBA. + #[derive(Debug, Copy, Clone, Default, PartialEq, Eq)] BackgroundControlSetting, u16 } impl BackgroundControlSetting { pub const fn from_screen_base_block(screen_base_block: u16) -> Self { BackgroundControlSetting(screen_base_block << 8) // TODO: mask this for correctness } + + // + + pub const PRIORITY_MASK: u16 = 0b11 << 0; + pub const fn priority(self) -> u16 { + self.0 & Self::PRIORITY_MASK + } + pub const fn with_priority(self, priority: u16) -> Self { + BackgroundControlSetting((self.0 & !Self::PRIORITY_MASK) | priority) + } + + pub const CHARACTER_BASE_BLOCK_MASK: u16 = 0b11 << 2; + pub const fn character_base_block(self) -> u16 { + (self.0 & Self::CHARACTER_BASE_BLOCK_MASK) >> 2 + } + pub const fn with_character_base_block(self, character_base_block: u16) -> Self { + BackgroundControlSetting((self.0 & !Self::CHARACTER_BASE_BLOCK_MASK) | ((character_base_block << 2) & Self::CHARACTER_BASE_BLOCK_MASK)) + } } -pub struct BG0; -impl BG0 { - pub const BG0CNT: VolAddress = unsafe { VolAddress::new_unchecked(0x400_0008) }; -} +pub const BG0CNT: VolAddress = unsafe { VolAddress::new_unchecked(0x400_0008) }; +pub const BG1CNT: VolAddress = unsafe { VolAddress::new_unchecked(0x400_000A) }; +pub const BG2CNT: VolAddress = unsafe { VolAddress::new_unchecked(0x400_000C) }; +pub const BG3CNT: VolAddress = unsafe { VolAddress::new_unchecked(0x400_000E) }; diff --git a/src/io/display.rs b/src/io/display.rs index 1711f43..831d315 100644 --- a/src/io/display.rs +++ b/src/io/display.rs @@ -15,43 +15,36 @@ newtype!( #[allow(missing_docs)] impl DisplayControlSetting { - pub const BG_MODE_MASK: u16 = 0b111; + bool_bits!(u16, + [ + (3, cgb_mode), + (4, frame1), + (5, hblank_interval_free), + (6, oam_memory_1d), + (7, force_vblank), + (8, bg0), + (9, bg1), + (10, bg2), + (11, bg3), + (12, obj), + (13, win0), + (14, win1), + (15, obj_window) + ] + ); - pub fn mode(self) -> DisplayControlMode { - // TODO: constify - match self.0 & Self::BG_MODE_MASK { - 0 => DisplayControlMode::Tiled0, - 1 => DisplayControlMode::Tiled1, - 2 => DisplayControlMode::Tiled2, - 3 => DisplayControlMode::Bitmap3, - 4 => DisplayControlMode::Bitmap4, - 5 => DisplayControlMode::Bitmap5, - _ => unreachable!(), - } - } - pub const fn with_mode(self, new_mode: DisplayControlMode) -> Self { - Self((self.0 & !Self::BG_MODE_MASK) | (new_mode as u16)) - } - - register_bit!(CGB_MODE_BIT, u16, 0b1000, cgb_mode); - register_bit!(PAGE_SELECT_BIT, u16, 0b1_0000, page1_enabled); - register_bit!(HBLANK_INTERVAL_FREE_BIT, u16, 0b10_0000, hblank_interval_free); - register_bit!(OBJECT_MEMORY_1D, u16, 0b100_0000, object_memory_1d); - register_bit!(FORCE_BLANK_BIT, u16, 0b1000_0000, force_blank); - register_bit!(DISPLAY_BG0_BIT, u16, 0b1_0000_0000, display_bg0); - register_bit!(DISPLAY_BG1_BIT, u16, 0b10_0000_0000, display_bg1); - register_bit!(DISPLAY_BG2_BIT, u16, 0b100_0000_0000, display_bg2); - register_bit!(DISPLAY_BG3_BIT, u16, 0b1000_0000_0000, display_bg3); - register_bit!(DISPLAY_OBJECT_BIT, u16, 0b1_0000_0000_0000, display_object); - register_bit!(DISPLAY_WINDOW0_BIT, u16, 0b10_0000_0000_0000, display_window0); - register_bit!(DISPLAY_WINDOW1_BIT, u16, 0b100_0000_0000_0000, display_window1); - register_bit!(OBJECT_WINDOW_BIT, u16, 0b1000_0000_0000_0000, display_object_window); + multi_bits!( + u16, + [ + (0, 3, mode, DisplayMode, Tiled0, Tiled1, Tiled2, Bitmap3, Bitmap4, Bitmap5 ) + ] + ); } /// The six display modes available on the GBA. #[derive(Debug, Clone, Copy, PartialEq, Eq)] #[repr(u16)] -pub enum DisplayControlMode { +pub enum DisplayMode { /// This basically allows for the most different things at once (all layers, /// 1024 tiles, two palette modes, etc), but you can't do affine /// transformations. diff --git a/src/io/dma.rs b/src/io/dma.rs index f796f8c..3ecd98e 100644 --- a/src/io/dma.rs +++ b/src/io/dma.rs @@ -68,56 +68,25 @@ newtype! { } #[allow(missing_docs)] impl DMAControlSetting { - pub const DEST_ADDR_CONTROL_MASK: u16 = 0b11 << 5; - pub fn dest_address_control(self) -> DMADestAddressControl { - // TODO: constify - match (self.0 & Self::DEST_ADDR_CONTROL_MASK) >> 5 { - 0 => DMADestAddressControl::Increment, - 1 => DMADestAddressControl::Decrement, - 2 => DMADestAddressControl::Fixed, - 3 => DMADestAddressControl::IncrementReload, - _ => unsafe { core::hint::unreachable_unchecked() }, - } - } - pub const fn with_dest_address_control(self, new_control: DMADestAddressControl) -> Self { - Self((self.0 & !Self::DEST_ADDR_CONTROL_MASK) | ((new_control as u16) << 5)) - } + bool_bits!(u16, [(9, dma_repeat), (10, use_32bit), (14, irq_when_done), (15, enabled)]); - pub const SRC_ADDR_CONTROL_MASK: u16 = 0b11 << 7; - pub fn src_address_control(self) -> DMASrcAddressControl { - // TODO: constify - match (self.0 & Self::SRC_ADDR_CONTROL_MASK) >> 7 { - 0 => DMASrcAddressControl::Increment, - 1 => DMASrcAddressControl::Decrement, - 2 => DMASrcAddressControl::Fixed, - _ => unreachable!(), // TODO: custom error message? - } - } - pub const fn with_src_address_control(self, new_control: DMASrcAddressControl) -> Self { - Self((self.0 & !Self::SRC_ADDR_CONTROL_MASK) | ((new_control as u16) << 7)) - } - - register_bit!(REPEAT, u16, 1 << 9, repeat); - register_bit!(TRANSFER_U32, u16, 1 << 10, transfer_u32); - // TODO: Game Pak DRQ? (bit 11) DMA3 only, and requires specific hardware - - pub const START_TIMING_MASK: u16 = 0b11 << 12; - pub fn start_timing(self) -> DMAStartTiming { - // TODO: constify - match (self.0 & Self::DEST_ADDR_CONTROL_MASK) >> 12 { - 0 => DMAStartTiming::Immediate, - 1 => DMAStartTiming::VBlank, - 2 => DMAStartTiming::HBlank, - 3 => DMAStartTiming::Special, - _ => unsafe { core::hint::unreachable_unchecked() }, - } - } - pub const fn with_start_timing(self, new_control: DMAStartTiming) -> Self { - Self((self.0 & !Self::START_TIMING_MASK) | ((new_control as u16) << 12)) - } - - register_bit!(IRQ_AT_END, u16, 1 << 14, irq_at_end); - register_bit!(ENABLE, u16, 1 << 15, enable); + multi_bits!( + u16, + [ + ( + 5, + 2, + dest_address_control, + DMADestAddressControl, + Increment, + Decrement, + Fixed, + IncrementReload + ), + (7, 2, source_address_control, DMASrcAddressControl, Increment, Decrement, Fixed), + (12, 2, start_time, DMAStartTiming, Immediate, VBlank, HBlank, Special) + ] + ); } /// Sets how the destination address should be adjusted per data transfer. @@ -234,9 +203,9 @@ impl DMA3 { /// must be valid for writing. pub unsafe fn fill32(src: *const u32, dest: *mut u32, count: u16) { const FILL_CONTROL: DMAControlSetting = DMAControlSetting::new() - .with_src_address_control(DMASrcAddressControl::Fixed) - .with_transfer_u32(true) - .with_enable(true); + .with_source_address_control(DMASrcAddressControl::Fixed) + .with_use_32bit(true) + .with_enabled(true); // TODO: destination checking against SRAM Self::DMA3SAD.write(src); Self::DMA3DAD.write(dest); diff --git a/src/io/keypad.rs b/src/io/keypad.rs index d03d242..f4fab87 100644 --- a/src/io/keypad.rs +++ b/src/io/keypad.rs @@ -31,16 +31,21 @@ newtype! { #[allow(missing_docs)] impl KeyInput { - register_bit!(A_BIT, u16, 1, a_pressed); - register_bit!(B_BIT, u16, 1 << 1, b_pressed); - register_bit!(SELECT_BIT, u16, 1 << 2, select_pressed); - register_bit!(START_BIT, u16, 1 << 3, start_pressed); - register_bit!(RIGHT_BIT, u16, 1 << 4, right_pressed); - register_bit!(LEFT_BIT, u16, 1 << 5, left_pressed); - register_bit!(UP_BIT, u16, 1 << 6, up_pressed); - register_bit!(DOWN_BIT, u16, 1 << 7, down_pressed); - register_bit!(R_BIT, u16, 1 << 8, r_pressed); - register_bit!(L_BIT, u16, 1 << 9, l_pressed); + bool_bits!( + u16, + [ + (0, a), + (1, b), + (2, select), + (3, start), + (4, right), + (5, left), + (6, up), + (7, down), + (8, r), + (9, l) + ] + ); /// Takes the set difference between these keys and another set of keys. pub fn difference(self, other: Self) -> Self { @@ -50,9 +55,9 @@ impl KeyInput { /// Gives the arrow pad value as a tribool, with Plus being increased column /// value (right). pub fn column_direction(self) -> TriBool { - if self.right_pressed() { + if self.right() { TriBool::Plus - } else if self.left_pressed() { + } else if self.left() { TriBool::Minus } else { TriBool::Neutral @@ -62,9 +67,9 @@ impl KeyInput { /// Gives the arrow pad value as a tribool, with Plus being increased row /// value (down). pub fn row_direction(self) -> TriBool { - if self.down_pressed() { + if self.down() { TriBool::Plus - } else if self.up_pressed() { + } else if self.up() { TriBool::Minus } else { TriBool::Neutral @@ -100,19 +105,23 @@ newtype! { } #[allow(missing_docs)] impl KeyInterruptSetting { - register_bit!(A_BIT, u16, 1, a_pressed); - register_bit!(B_BIT, u16, 1 << 1, b_pressed); - register_bit!(SELECT_BIT, u16, 1 << 2, select_pressed); - register_bit!(START_BIT, u16, 1 << 3, start_pressed); - register_bit!(RIGHT_BIT, u16, 1 << 4, right_pressed); - register_bit!(LEFT_BIT, u16, 1 << 5, left_pressed); - register_bit!(UP_BIT, u16, 1 << 6, up_pressed); - register_bit!(DOWN_BIT, u16, 1 << 7, down_pressed); - register_bit!(R_BIT, u16, 1 << 8, r_pressed); - register_bit!(L_BIT, u16, 1 << 9, l_pressed); - // - register_bit!(IRQ_ENABLE_BIT, u16, 1 << 14, irq_enabled); - register_bit!(IRQ_AND_BIT, u16, 1 << 15, irq_logical_and); + bool_bits!( + u16, + [ + (0, a), + (1, b), + (2, select), + (3, start), + (4, right), + (5, left), + (6, up), + (7, down), + (8, r), + (9, l), + (14, irq_enabled), + (15, irq_logical_and) + ] + ); } /// Use this to configure when a keypad interrupt happens. diff --git a/src/lib.rs b/src/lib.rs index 6b07a04..7b5b198 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,7 +3,7 @@ #![feature(const_int_wrapping)] #![feature(const_int_rotate)] #![feature(min_const_unsafe_fn)] -#![warn(missing_docs)] +//#![warn(missing_docs)] #![allow(clippy::cast_lossless)] #![deny(clippy::float_arithmetic)] @@ -20,7 +20,7 @@ //! **Do not** use this crate in programs that aren't running on the GBA. If you //! do, it's a giant bag of Undefined Behavior. -pub(crate) use gba_proc_macro::register_bit; +pub(crate) use gba_proc_macro::{bool_bits, multi_bits}; /// Assists in defining a newtype wrapper over some base type. /// diff --git a/src/video/tiled.rs b/src/video/tiled.rs index 9c10009..e91dcc1 100644 --- a/src/video/tiled.rs +++ b/src/video/tiled.rs @@ -36,29 +36,12 @@ newtype! { } impl TextScreenblockEntry { pub const fn from_tile_index(index: u16) -> Self { - TextScreenblockEntry(index & Self::TILE_INDEX_MASK) + TextScreenblockEntry(index & Self::TILE_ID_MASK) } - // + bool_bits!(u16, [(10, hflip), (11, vflip)]); - pub const TILE_INDEX_MASK: u16 = 0xA - 1; - pub const fn tile_index(self) -> u16 { - self.0 & Self::TILE_INDEX_MASK - } - pub const fn with_tile_index(self, index: u16) -> Self { - TextScreenblockEntry((self.0 & !Self::TILE_INDEX_MASK) | (index & Self::TILE_INDEX_MASK)) - } - - register_bit!(HFLIP_BIT, u16, 1 << 0xA, hflip); - register_bit!(VFLIP_BIT, u16, 1 << 0xB, vflip); - - pub const PALBANK_MASK: u16 = 0b1111 << 0xC; - pub const fn palbank(self) -> u16 { - (self.0 & Self::TILE_INDEX_MASK) >> 0xC - } - pub const fn with_palbank(self, palbank: u16) -> Self { - TextScreenblockEntry((self.0 & !Self::PALBANK_MASK) | (palbank << 0xC)) - } + multi_bits!(u16, [(0, 10, tile_id), (12, 4, palbank)]); } newtype! {