mirror of
https://github.com/italicsjenga/gba.git
synced 2025-01-11 03:21:30 +11:00
CLOSE to another release
This commit is contained in:
parent
298d45ccfb
commit
d6a6301815
|
@ -13,7 +13,7 @@ publish = false
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
typenum = "1.10"
|
typenum = "1.10"
|
||||||
gba-proc-macro = "0.3"
|
gba-proc-macro = "0.4"
|
||||||
|
|
||||||
#[dev-dependencies]
|
#[dev-dependencies]
|
||||||
#quickcheck="0.7"
|
#quickcheck="0.7"
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
use gba::{
|
use gba::{
|
||||||
io::{
|
io::{
|
||||||
background::{BackgroundControlSetting, BG0},
|
background::{BackgroundControlSetting, BG0CNT},
|
||||||
display::{DisplayControlSetting, DISPCNT},
|
display::{DisplayControlSetting, DISPCNT},
|
||||||
},
|
},
|
||||||
palram::index_palram_bg_4bpp,
|
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);
|
let dark_entry = TextScreenblockEntry::from_tile_index(1);
|
||||||
checker_screenblock(8, light_entry, dark_entry);
|
checker_screenblock(8, light_entry, dark_entry);
|
||||||
// bg0 control
|
// bg0 control
|
||||||
BG0::BG0CNT.write(BackgroundControlSetting::from_screen_base_block(8));
|
BG0CNT.write(BackgroundControlSetting::from_screen_base_block(8));
|
||||||
// Display Control
|
// Display Control
|
||||||
DISPCNT.write(DisplayControlSetting::new().with_display_bg0(true));
|
DISPCNT.write(DisplayControlSetting::new().with_bg0(true));
|
||||||
loop {
|
loop {
|
||||||
// TODO the whole thing
|
// TODO the whole thing
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
#![forbid(unsafe_code)]
|
#![forbid(unsafe_code)]
|
||||||
|
|
||||||
use gba::{
|
use gba::{
|
||||||
io::display::{DisplayControlMode, DisplayControlSetting, DISPCNT},
|
io::display::{DisplayControlSetting, DisplayMode, DISPCNT},
|
||||||
video::bitmap::Mode3,
|
video::bitmap::Mode3,
|
||||||
Color,
|
Color,
|
||||||
};
|
};
|
||||||
|
@ -15,7 +15,7 @@ fn panic(_info: &core::panic::PanicInfo) -> ! {
|
||||||
|
|
||||||
#[start]
|
#[start]
|
||||||
fn main(_argc: isize, _argv: *const *const u8) -> isize {
|
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);
|
DISPCNT.write(SETTING);
|
||||||
Mode3::write_pixel(120, 80, Color::from_rgb(31, 0, 0));
|
Mode3::write_pixel(120, 80, Color::from_rgb(31, 0, 0));
|
||||||
Mode3::write_pixel(136, 80, Color::from_rgb(0, 31, 0));
|
Mode3::write_pixel(136, 80, Color::from_rgb(0, 31, 0));
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
use gba::{
|
use gba::{
|
||||||
io::{
|
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,
|
keypad::read_key_input,
|
||||||
},
|
},
|
||||||
video::bitmap::Mode3,
|
video::bitmap::Mode3,
|
||||||
|
@ -18,7 +18,7 @@ fn panic(_info: &core::panic::PanicInfo) -> ! {
|
||||||
|
|
||||||
#[start]
|
#[start]
|
||||||
fn main(_argc: isize, _argv: *const *const u8) -> isize {
|
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);
|
DISPCNT.write(SETTING);
|
||||||
|
|
||||||
let mut px = Mode3::SCREEN_WIDTH / 2;
|
let mut px = Mode3::SCREEN_WIDTH / 2;
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
#![forbid(unsafe_code)]
|
#![forbid(unsafe_code)]
|
||||||
|
|
||||||
use gba::{
|
use gba::{
|
||||||
io::display::{DisplayControlMode, DisplayControlSetting, DISPCNT},
|
io::display::{DisplayControlSetting, DisplayMode, DISPCNT},
|
||||||
video::bitmap::Mode3,
|
video::bitmap::Mode3,
|
||||||
Color,
|
Color,
|
||||||
};
|
};
|
||||||
|
@ -22,7 +22,7 @@ fn panic(info: &core::panic::PanicInfo) -> ! {
|
||||||
|
|
||||||
#[start]
|
#[start]
|
||||||
fn main(_argc: isize, _argv: *const *const u8) -> isize {
|
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);
|
DISPCNT.write(SETTING);
|
||||||
Mode3::write_pixel(120, 80, Color::from_rgb(31, 0, 0));
|
Mode3::write_pixel(120, 80, Color::from_rgb(31, 0, 0));
|
||||||
Mode3::write_pixel(136, 80, Color::from_rgb(0, 31, 0));
|
Mode3::write_pixel(136, 80, Color::from_rgb(0, 31, 0));
|
||||||
|
|
23
src/bios.rs
23
src/bios.rs
|
@ -8,7 +8,7 @@
|
||||||
//! whatever value is necessary for that function). Some functions also perform
|
//! whatever value is necessary for that function). Some functions also perform
|
||||||
//! necessary checks to save you from yourself, such as not dividing by zero.
|
//! 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
|
//TODO: ALL functions in this module should have `if cfg!(test)` blocks. The
|
||||||
//functions that never return must panic, the functions that return nothing
|
//functions that never return must panic, the functions that return nothing
|
||||||
|
@ -109,14 +109,19 @@ newtype! {
|
||||||
}
|
}
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
impl RegisterRAMResetFlags {
|
impl RegisterRAMResetFlags {
|
||||||
register_bit!(EWRAM, u8, 0, ewram);
|
bool_bits!(
|
||||||
register_bit!(IWRAM, u8, 1 << 1, iwram);
|
u8,
|
||||||
register_bit!(PALRAM, u8, 1 << 2, palram);
|
[
|
||||||
register_bit!(VRAM, u8, 1 << 3, vram);
|
(0, ewram),
|
||||||
register_bit!(OAM, u8, 1 << 4, oam);
|
(1, iwram),
|
||||||
register_bit!(SIO, u8, 1 << 5, sio);
|
(2, palram),
|
||||||
register_bit!(SOUND, u8, 1 << 6, sound);
|
(3, vram),
|
||||||
register_bit!(OTHER_IO, u8, 1 << 7, other_io);
|
(4, oam),
|
||||||
|
(5, sio),
|
||||||
|
(6, sound),
|
||||||
|
(7, other_io),
|
||||||
|
]
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// (`swi 0x02`) Halts the CPU until an interrupt occurs.
|
/// (`swi 0x02`) Halts the CPU until an interrupt occurs.
|
||||||
|
|
|
@ -3,15 +3,35 @@
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
newtype! {
|
newtype! {
|
||||||
|
/// A newtype over the various display control options that you have on a GBA.
|
||||||
|
#[derive(Debug, Copy, Clone, Default, PartialEq, Eq)]
|
||||||
BackgroundControlSetting, u16
|
BackgroundControlSetting, u16
|
||||||
}
|
}
|
||||||
impl BackgroundControlSetting {
|
impl BackgroundControlSetting {
|
||||||
pub const fn from_screen_base_block(screen_base_block: u16) -> Self {
|
pub const fn from_screen_base_block(screen_base_block: u16) -> Self {
|
||||||
BackgroundControlSetting(screen_base_block << 8) // TODO: mask this for correctness
|
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;
|
pub const BG0CNT: VolAddress<BackgroundControlSetting> = unsafe { VolAddress::new_unchecked(0x400_0008) };
|
||||||
impl BG0 {
|
pub const BG1CNT: VolAddress<BackgroundControlSetting> = unsafe { VolAddress::new_unchecked(0x400_000A) };
|
||||||
pub const BG0CNT: VolAddress<BackgroundControlSetting> = unsafe { VolAddress::new_unchecked(0x400_0008) };
|
pub const BG2CNT: VolAddress<BackgroundControlSetting> = unsafe { VolAddress::new_unchecked(0x400_000C) };
|
||||||
}
|
pub const BG3CNT: VolAddress<BackgroundControlSetting> = unsafe { VolAddress::new_unchecked(0x400_000E) };
|
||||||
|
|
|
@ -15,43 +15,36 @@ newtype!(
|
||||||
|
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
impl DisplayControlSetting {
|
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 {
|
multi_bits!(
|
||||||
// TODO: constify
|
u16,
|
||||||
match self.0 & Self::BG_MODE_MASK {
|
[
|
||||||
0 => DisplayControlMode::Tiled0,
|
(0, 3, mode, DisplayMode, Tiled0, Tiled1, Tiled2, Bitmap3, Bitmap4, Bitmap5 )
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The six display modes available on the GBA.
|
/// The six display modes available on the GBA.
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
#[repr(u16)]
|
#[repr(u16)]
|
||||||
pub enum DisplayControlMode {
|
pub enum DisplayMode {
|
||||||
/// This basically allows for the most different things at once (all layers,
|
/// This basically allows for the most different things at once (all layers,
|
||||||
/// 1024 tiles, two palette modes, etc), but you can't do affine
|
/// 1024 tiles, two palette modes, etc), but you can't do affine
|
||||||
/// transformations.
|
/// transformations.
|
||||||
|
|
|
@ -68,56 +68,25 @@ newtype! {
|
||||||
}
|
}
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
impl DMAControlSetting {
|
impl DMAControlSetting {
|
||||||
pub const DEST_ADDR_CONTROL_MASK: u16 = 0b11 << 5;
|
bool_bits!(u16, [(9, dma_repeat), (10, use_32bit), (14, irq_when_done), (15, enabled)]);
|
||||||
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))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const SRC_ADDR_CONTROL_MASK: u16 = 0b11 << 7;
|
multi_bits!(
|
||||||
pub fn src_address_control(self) -> DMASrcAddressControl {
|
u16,
|
||||||
// TODO: constify
|
[
|
||||||
match (self.0 & Self::SRC_ADDR_CONTROL_MASK) >> 7 {
|
(
|
||||||
0 => DMASrcAddressControl::Increment,
|
5,
|
||||||
1 => DMASrcAddressControl::Decrement,
|
2,
|
||||||
2 => DMASrcAddressControl::Fixed,
|
dest_address_control,
|
||||||
_ => unreachable!(), // TODO: custom error message?
|
DMADestAddressControl,
|
||||||
}
|
Increment,
|
||||||
}
|
Decrement,
|
||||||
pub const fn with_src_address_control(self, new_control: DMASrcAddressControl) -> Self {
|
Fixed,
|
||||||
Self((self.0 & !Self::SRC_ADDR_CONTROL_MASK) | ((new_control as u16) << 7))
|
IncrementReload
|
||||||
}
|
),
|
||||||
|
(7, 2, source_address_control, DMASrcAddressControl, Increment, Decrement, Fixed),
|
||||||
register_bit!(REPEAT, u16, 1 << 9, repeat);
|
(12, 2, start_time, DMAStartTiming, Immediate, VBlank, HBlank, Special)
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets how the destination address should be adjusted per data transfer.
|
/// Sets how the destination address should be adjusted per data transfer.
|
||||||
|
@ -234,9 +203,9 @@ impl DMA3 {
|
||||||
/// must be valid for writing.
|
/// must be valid for writing.
|
||||||
pub unsafe fn fill32(src: *const u32, dest: *mut u32, count: u16) {
|
pub unsafe fn fill32(src: *const u32, dest: *mut u32, count: u16) {
|
||||||
const FILL_CONTROL: DMAControlSetting = DMAControlSetting::new()
|
const FILL_CONTROL: DMAControlSetting = DMAControlSetting::new()
|
||||||
.with_src_address_control(DMASrcAddressControl::Fixed)
|
.with_source_address_control(DMASrcAddressControl::Fixed)
|
||||||
.with_transfer_u32(true)
|
.with_use_32bit(true)
|
||||||
.with_enable(true);
|
.with_enabled(true);
|
||||||
// TODO: destination checking against SRAM
|
// TODO: destination checking against SRAM
|
||||||
Self::DMA3SAD.write(src);
|
Self::DMA3SAD.write(src);
|
||||||
Self::DMA3DAD.write(dest);
|
Self::DMA3DAD.write(dest);
|
||||||
|
|
|
@ -31,16 +31,21 @@ newtype! {
|
||||||
|
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
impl KeyInput {
|
impl KeyInput {
|
||||||
register_bit!(A_BIT, u16, 1, a_pressed);
|
bool_bits!(
|
||||||
register_bit!(B_BIT, u16, 1 << 1, b_pressed);
|
u16,
|
||||||
register_bit!(SELECT_BIT, u16, 1 << 2, select_pressed);
|
[
|
||||||
register_bit!(START_BIT, u16, 1 << 3, start_pressed);
|
(0, a),
|
||||||
register_bit!(RIGHT_BIT, u16, 1 << 4, right_pressed);
|
(1, b),
|
||||||
register_bit!(LEFT_BIT, u16, 1 << 5, left_pressed);
|
(2, select),
|
||||||
register_bit!(UP_BIT, u16, 1 << 6, up_pressed);
|
(3, start),
|
||||||
register_bit!(DOWN_BIT, u16, 1 << 7, down_pressed);
|
(4, right),
|
||||||
register_bit!(R_BIT, u16, 1 << 8, r_pressed);
|
(5, left),
|
||||||
register_bit!(L_BIT, u16, 1 << 9, l_pressed);
|
(6, up),
|
||||||
|
(7, down),
|
||||||
|
(8, r),
|
||||||
|
(9, l)
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
/// Takes the set difference between these keys and another set of keys.
|
/// Takes the set difference between these keys and another set of keys.
|
||||||
pub fn difference(self, other: Self) -> Self {
|
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
|
/// Gives the arrow pad value as a tribool, with Plus being increased column
|
||||||
/// value (right).
|
/// value (right).
|
||||||
pub fn column_direction(self) -> TriBool {
|
pub fn column_direction(self) -> TriBool {
|
||||||
if self.right_pressed() {
|
if self.right() {
|
||||||
TriBool::Plus
|
TriBool::Plus
|
||||||
} else if self.left_pressed() {
|
} else if self.left() {
|
||||||
TriBool::Minus
|
TriBool::Minus
|
||||||
} else {
|
} else {
|
||||||
TriBool::Neutral
|
TriBool::Neutral
|
||||||
|
@ -62,9 +67,9 @@ impl KeyInput {
|
||||||
/// Gives the arrow pad value as a tribool, with Plus being increased row
|
/// Gives the arrow pad value as a tribool, with Plus being increased row
|
||||||
/// value (down).
|
/// value (down).
|
||||||
pub fn row_direction(self) -> TriBool {
|
pub fn row_direction(self) -> TriBool {
|
||||||
if self.down_pressed() {
|
if self.down() {
|
||||||
TriBool::Plus
|
TriBool::Plus
|
||||||
} else if self.up_pressed() {
|
} else if self.up() {
|
||||||
TriBool::Minus
|
TriBool::Minus
|
||||||
} else {
|
} else {
|
||||||
TriBool::Neutral
|
TriBool::Neutral
|
||||||
|
@ -100,19 +105,23 @@ newtype! {
|
||||||
}
|
}
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
impl KeyInterruptSetting {
|
impl KeyInterruptSetting {
|
||||||
register_bit!(A_BIT, u16, 1, a_pressed);
|
bool_bits!(
|
||||||
register_bit!(B_BIT, u16, 1 << 1, b_pressed);
|
u16,
|
||||||
register_bit!(SELECT_BIT, u16, 1 << 2, select_pressed);
|
[
|
||||||
register_bit!(START_BIT, u16, 1 << 3, start_pressed);
|
(0, a),
|
||||||
register_bit!(RIGHT_BIT, u16, 1 << 4, right_pressed);
|
(1, b),
|
||||||
register_bit!(LEFT_BIT, u16, 1 << 5, left_pressed);
|
(2, select),
|
||||||
register_bit!(UP_BIT, u16, 1 << 6, up_pressed);
|
(3, start),
|
||||||
register_bit!(DOWN_BIT, u16, 1 << 7, down_pressed);
|
(4, right),
|
||||||
register_bit!(R_BIT, u16, 1 << 8, r_pressed);
|
(5, left),
|
||||||
register_bit!(L_BIT, u16, 1 << 9, l_pressed);
|
(6, up),
|
||||||
//
|
(7, down),
|
||||||
register_bit!(IRQ_ENABLE_BIT, u16, 1 << 14, irq_enabled);
|
(8, r),
|
||||||
register_bit!(IRQ_AND_BIT, u16, 1 << 15, irq_logical_and);
|
(9, l),
|
||||||
|
(14, irq_enabled),
|
||||||
|
(15, irq_logical_and)
|
||||||
|
]
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Use this to configure when a keypad interrupt happens.
|
/// Use this to configure when a keypad interrupt happens.
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
#![feature(const_int_wrapping)]
|
#![feature(const_int_wrapping)]
|
||||||
#![feature(const_int_rotate)]
|
#![feature(const_int_rotate)]
|
||||||
#![feature(min_const_unsafe_fn)]
|
#![feature(min_const_unsafe_fn)]
|
||||||
#![warn(missing_docs)]
|
//#![warn(missing_docs)]
|
||||||
#![allow(clippy::cast_lossless)]
|
#![allow(clippy::cast_lossless)]
|
||||||
#![deny(clippy::float_arithmetic)]
|
#![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 not** use this crate in programs that aren't running on the GBA. If you
|
||||||
//! do, it's a giant bag of Undefined Behavior.
|
//! 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.
|
/// Assists in defining a newtype wrapper over some base type.
|
||||||
///
|
///
|
||||||
|
|
|
@ -36,29 +36,12 @@ newtype! {
|
||||||
}
|
}
|
||||||
impl TextScreenblockEntry {
|
impl TextScreenblockEntry {
|
||||||
pub const fn from_tile_index(index: u16) -> Self {
|
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;
|
multi_bits!(u16, [(0, 10, tile_id), (12, 4, palbank)]);
|
||||||
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))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
newtype! {
|
newtype! {
|
||||||
|
|
Loading…
Reference in a new issue