diff --git a/examples/bg_demo.rs b/examples/bg_demo.rs index d4b3bd2..7477aa2 100644 --- a/examples/bg_demo.rs +++ b/examples/bg_demo.rs @@ -7,9 +7,10 @@ use gba::{ display::{DisplayControlSetting, DISPCNT}, }, palram::index_palram_bg_4bpp, - video::tiled::{TextScreenblockEntry, Tile4bpp, VRAM_CHARBLOCKS, VRAM_TEXT_SCREENBLOCKS}, + vram::text::{TextScreenblockEntry}, Color, }; +use gba::vram::{Tile4bpp, CHAR_BASE_BLOCKS, SCREEN_BASE_BLOCKS}; #[panic_handler] fn panic(_info: &core::panic::PanicInfo) -> ! { @@ -52,11 +53,11 @@ pub const ALL_THREES: Tile4bpp = Tile4bpp([ pub fn set_bg_tile_4bpp(charblock: usize, index: usize, tile: Tile4bpp) { assert!(charblock < 4); assert!(index < 512); - unsafe { VRAM_CHARBLOCKS.index(charblock).cast::().offset(index as isize).write(tile) } + unsafe { CHAR_BASE_BLOCKS.index(charblock).cast::().offset(index as isize).write(tile) } } pub fn checker_screenblock(slot: usize, a_entry: TextScreenblockEntry, b_entry: TextScreenblockEntry) { - let mut p = unsafe { VRAM_TEXT_SCREENBLOCKS.index(slot).cast::() }; + let mut p = unsafe { SCREEN_BASE_BLOCKS.index(slot).cast::() }; let mut checker = true; for _row in 0..32 { for _col in 0..32 { diff --git a/examples/hello_world.rs b/examples/hello_world.rs index f1e5336..b126ee9 100644 --- a/examples/hello_world.rs +++ b/examples/hello_world.rs @@ -4,7 +4,7 @@ use gba::{ io::display::{DisplayControlSetting, DisplayMode, DISPCNT}, - video::bitmap::Mode3, + vram::bitmap::Mode3, Color, }; diff --git a/examples/light_cycle.rs b/examples/light_cycle.rs index 29ad8b6..3514998 100644 --- a/examples/light_cycle.rs +++ b/examples/light_cycle.rs @@ -7,7 +7,7 @@ use gba::{ display::{spin_until_vblank, spin_until_vdraw, DisplayControlSetting, DisplayMode, DISPCNT}, keypad::read_key_input, }, - video::bitmap::Mode3, + vram::bitmap::Mode3, Color, }; diff --git a/examples/mgba_panic_handler.rs b/examples/mgba_panic_handler.rs index a51c0c9..5a9914e 100644 --- a/examples/mgba_panic_handler.rs +++ b/examples/mgba_panic_handler.rs @@ -4,7 +4,7 @@ use gba::{ io::display::{DisplayControlSetting, DisplayMode, DISPCNT}, - video::bitmap::Mode3, + vram::bitmap::Mode3, Color, }; diff --git a/src/base/volatile.rs b/src/base/volatile.rs index 5e12e28..7f74f69 100644 --- a/src/base/volatile.rs +++ b/src/base/volatile.rs @@ -2,6 +2,8 @@ use core::{cmp::Ordering, iter::FusedIterator, marker::PhantomData, num::NonZeroUsize}; +// TODO: striding block/iter + /// Abstracts the use of a volatile hardware address. /// /// If you're trying to do anything other than abstract a volatile hardware diff --git a/src/io/background.rs b/src/io/background.rs index dad56f1..d86f033 100644 --- a/src/io/background.rs +++ b/src/io/background.rs @@ -2,13 +2,13 @@ use super::*; -// BG0 Control. Read/Write. +// BG0 Control. Read/Write. Display Mode 0/1 only. pub const BG0CNT: VolAddress = unsafe { VolAddress::new_unchecked(0x400_0008) }; -// BG1 Control. Read/Write. +// BG1 Control. Read/Write. Display Mode 0/1 only. pub const BG1CNT: VolAddress = unsafe { VolAddress::new_unchecked(0x400_000A) }; -// BG2 Control. Read/Write. +// BG2 Control. Read/Write. Display Mode 0/1/2 only. pub const BG2CNT: VolAddress = unsafe { VolAddress::new_unchecked(0x400_000C) }; -// BG3 Control. Read/Write. +// BG3 Control. Read/Write. Display Mode 0/2 only. pub const BG3CNT: VolAddress = unsafe { VolAddress::new_unchecked(0x400_000E) }; newtype! { @@ -19,7 +19,7 @@ newtype! { /// Bit 6: Mosaic mode /// Bit 7: is 8bpp /// Bit 8-12: Screen Base Block (0 through 31, 2k each) - /// Bit 13: Display area overflow wraps (otherwise transparent, affine only) + /// Bit 13: Display area overflow wraps (otherwise transparent, affine BG only) /// Bit 14-15: Screen Size #[derive(Debug, Copy, Clone, Default, PartialEq, Eq)] BackgroundControlSetting, u16 @@ -93,7 +93,7 @@ pub const BG3HOFS: VolAddress = unsafe { VolAddress::new_unchecked(0x400_00 // BG3 Y-Offset. Write only. Text mode only. 9 bits. pub const BG3VOFS: VolAddress = unsafe { VolAddress::new_unchecked(0x400_001E) }; -// TODO: affine registers: +// TODO: affine backgrounds // BG2X_L // BG2X_H // BG2Y_L @@ -115,40 +115,6 @@ pub const BG3VOFS: VolAddress = unsafe { VolAddress::new_unchecked(0x400_00 // pub const WININ: VolAddress = unsafe { VolAddress::new_unchecked(0x400_0048) }; // pub const WINOUT: VolAddress = unsafe { VolAddress::new_unchecked(0x400_004A) }; -/// Global mosaic effect control. Write-only. -pub const MOSAIC: VolAddress = unsafe { VolAddress::new_unchecked(0x400_004C) }; - -newtype! { - /// Allows control of the Mosaic effect. - /// - /// Values are the _increase_ for each top-left pixel to be duplicated in the - /// final result. If you want to duplicate some other pixel than the top-left, - /// you can offset the background or object by an appropriate amount. - /// - /// 0) No effect (1+0) - /// 1) Each pixel becomes 2 pixels (1+1) - /// 2) Each pixel becomes 3 pixels (1+2) - /// 3) Each pixel becomes 4 pixels (1+3) - /// - /// * Bits 0-3: BG mosaic horizontal increase - /// * Bits 4-7: BG mosaic vertical increase - /// * Bits 8-11: Object mosaic horizontal increase - /// * Bits 12-15: Object mosaic vertical increase - #[derive(Debug, Copy, Clone, Default, PartialEq, Eq)] - MosaicSetting, u16 -} -impl MosaicSetting { - multi_bits!( - u16, - [ - (0, 4, bg_horizontal_inc), - (4, 4, bg_vertical_inc), - (8, 4, obj_horizontal_inc), - (12, 4, obj_vertical_inc), - ] - ); -} - // pub const BLDCNT: VolAddress = unsafe { VolAddress::new_unchecked(0x400_0050) }; // pub const BLDALPHA: VolAddress = unsafe { VolAddress::new_unchecked(0x400_0052) }; // pub const BLDY: VolAddress = unsafe { VolAddress::new_unchecked(0x400_0054) }; diff --git a/src/io/display.rs b/src/io/display.rs index 353dffa..6badf90 100644 --- a/src/io/display.rs +++ b/src/io/display.rs @@ -4,7 +4,7 @@ use super::*; /// LCD Control. Read/Write. /// -/// The "force vblank" bit is always set when your rust code first executes. +/// The "force vblank" bit is always set when your Rust code first executes. pub const DISPCNT: VolAddress = unsafe { VolAddress::new_unchecked(0x400_0000) }; newtype!( @@ -101,7 +101,7 @@ pub fn display_control() -> DisplayControlSetting { DISPCNT.read() } -/// Display Status and IRQ Control. +/// Display Status and IRQ Control. Read/Write. pub const DISPSTAT: VolAddress = unsafe { VolAddress::new_unchecked(0x400_0004) }; newtype!( @@ -154,3 +154,37 @@ pub fn spin_until_vdraw() { // TODO: make this the better version with BIOS and interrupts and such. while vcount() >= VBLANK_SCANLINE {} } + +/// Global mosaic effect control. Write-only. +pub const MOSAIC: VolAddress = unsafe { VolAddress::new_unchecked(0x400_004C) }; + +newtype! { + /// Allows control of the Mosaic effect. + /// + /// Values are the _increase_ for each top-left pixel to be duplicated in the + /// final result. If you want to duplicate some other pixel than the top-left, + /// you can offset the background or object by an appropriate amount. + /// + /// 0) No effect (1+0) + /// 1) Each pixel becomes 2 pixels (1+1) + /// 2) Each pixel becomes 3 pixels (1+2) + /// 3) Each pixel becomes 4 pixels (1+3) + /// + /// * Bits 0-3: BG mosaic horizontal increase + /// * Bits 4-7: BG mosaic vertical increase + /// * Bits 8-11: Object mosaic horizontal increase + /// * Bits 12-15: Object mosaic vertical increase + #[derive(Debug, Copy, Clone, Default, PartialEq, Eq)] + MosaicSetting, u16 +} +impl MosaicSetting { + multi_bits!( + u16, + [ + (0, 4, bg_horizontal_inc), + (4, 4, bg_vertical_inc), + (8, 4, obj_horizontal_inc), + (12, 4, obj_vertical_inc), + ] + ); +} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 7b5b198..a65fc07 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -66,7 +66,7 @@ pub mod bios; pub mod io; pub mod mgba; pub mod palram; -pub mod video; +pub mod vram; newtype! { /// A color on the GBA is an RGB 5.5.5 within a `u16` diff --git a/src/video/tiled.rs b/src/video/tiled.rs deleted file mode 100644 index 40bb383..0000000 --- a/src/video/tiled.rs +++ /dev/null @@ -1,86 +0,0 @@ -//! Module for tiled mode types and operations. - -use super::*; - -// Note(Lokathor): We've got several newtypes here that don't use the `newtype!` -// macro because it's insufficient at parsing array types being wrapped. - -newtype! { - /// An 8x8 tile with 4bpp, packed as `u32` values for proper alignment. - #[derive(Debug, Clone, Copy, Default)] - Tile4bpp, pub [u32; 8], no frills -} - -newtype! { - /// An 8x8 tile with 8bpp, packed as `u32` values for proper alignment. - #[derive(Debug, Clone, Copy, Default)] - Tile8bpp, pub [u32; 16], no frills -} - -newtype! { - /// A 4bpp charblock has 512 tiles in it - #[derive(Clone, Copy)] - Charblock4bpp, pub [Tile4bpp; 512], no frills -} - -newtype! { - /// An 8bpp charblock has 256 tiles in it - #[derive(Clone, Copy)] - Charblock8bpp, pub [Tile4bpp; 256], no frills -} - -newtype! { - /// A screenblock entry for use in Text mode. - #[derive(Debug, Clone, Copy, Default)] - TextScreenblockEntry, u16 -} -impl TextScreenblockEntry { - pub const fn from_tile_index(index: u16) -> Self { - TextScreenblockEntry(index & Self::TILE_ID_MASK) - } - - bool_bits!(u16, [(10, hflip), (11, vflip)]); - - multi_bits!(u16, [(0, 10, tile_id), (12, 4, palbank)]); -} - -newtype! { - /// A screenblock for use in Text mode. - #[derive(Clone, Copy)] - TextScreenblock, [TextScreenblockEntry; 32 * 32], no frills -} - -newtype! { - /// A screenblock entry for use in Affine mode. - #[derive(Debug, Clone, Copy, Default)] - AffineScreenblockEntry, u8 -} - -newtype! { - /// A screenblock for use in Affine mode. - #[derive(Clone, Copy)] - AffineScreenblock16x16, [AffineScreenblockEntry; 16*16], no frills -} - -newtype! { - /// A screenblock for use in Affine mode. - #[derive(Clone, Copy)] - AffineScreenblock32x32, [AffineScreenblockEntry; 32*32], no frills -} - -newtype! { - /// A screenblock for use in Affine mode. - #[derive(Clone, Copy)] - AffineScreenblock64x64, [AffineScreenblockEntry; 64*64], no frills -} - -newtype! { - /// A screenblock for use in Affine mode. - #[derive(Clone, Copy)] - AffineScreenblock128x128, [AffineScreenblockEntry; 128*128], no frills -} - -pub const VRAM_CHARBLOCKS: VolAddressBlock = unsafe { VolAddressBlock::new_unchecked(VolAddress::new_unchecked(VRAM_BASE_USIZE), 6) }; - -pub const VRAM_TEXT_SCREENBLOCKS: VolAddressBlock = - unsafe { VolAddressBlock::new_unchecked(VolAddress::new_unchecked(VRAM_BASE_USIZE), 32) }; diff --git a/src/video.rs b/src/vram.rs similarity index 53% rename from src/video.rs rename to src/vram.rs index 54c52f1..efb0825 100644 --- a/src/video.rs +++ b/src/vram.rs @@ -15,8 +15,9 @@ pub(crate) use super::*; +pub mod affine; pub mod bitmap; -pub mod tiled; +pub mod text; /// The start of VRAM. /// @@ -25,3 +26,34 @@ pub mod tiled; /// value as just being a `usize`. Specific video mode types then wrap this as /// being the correct thing. pub const VRAM_BASE_USIZE: usize = 0x600_0000; + +pub const CHAR_BASE_BLOCKS: VolAddressBlock<[u8; 0x4000]> = unsafe { VolAddressBlock::new_unchecked(VolAddress::new_unchecked(VRAM_BASE_USIZE), 6) }; + +pub const SCREEN_BASE_BLOCKS: VolAddressBlock<[u8; 0x800]> = + unsafe { VolAddressBlock::new_unchecked(VolAddress::new_unchecked(VRAM_BASE_USIZE), 32) }; + +newtype! { + /// An 8x8 tile with 4bpp, packed as `u32` values for proper alignment. + #[derive(Debug, Clone, Copy, Default)] + Tile4bpp, pub [u32; 8], no frills +} + +newtype! { + /// An 8x8 tile with 8bpp, packed as `u32` values for proper alignment. + #[derive(Debug, Clone, Copy, Default)] + Tile8bpp, pub [u32; 16], no frills +} + +/* +newtype! { + /// A 4bpp charblock has 512 tiles in it + #[derive(Clone, Copy)] + Charblock4bpp, pub [Tile4bpp; 512], no frills +} + +newtype! { + /// An 8bpp charblock has 256 tiles in it + #[derive(Clone, Copy)] + Charblock8bpp, pub [Tile4bpp; 256], no frills +} +*/ diff --git a/src/vram/affine.rs b/src/vram/affine.rs new file mode 100644 index 0000000..a29ccf1 --- /dev/null +++ b/src/vram/affine.rs @@ -0,0 +1,31 @@ +use super::*; + +newtype! { + /// A screenblock entry for use in Affine mode. + #[derive(Debug, Clone, Copy, Default)] + AffineScreenblockEntry, u8 +} + +newtype! { + /// A 16x16 screenblock for use in Affine mode. + #[derive(Clone, Copy)] + AffineScreenblock16x16, [AffineScreenblockEntry; 16*16], no frills +} + +newtype! { + /// A 32x32 screenblock for use in Affine mode. + #[derive(Clone, Copy)] + AffineScreenblock32x32, [AffineScreenblockEntry; 32*32], no frills +} + +newtype! { + /// A 64x64 screenblock for use in Affine mode. + #[derive(Clone, Copy)] + AffineScreenblock64x64, [AffineScreenblockEntry; 64*64], no frills +} + +newtype! { + /// A 128x128 screenblock for use in Affine mode. + #[derive(Clone, Copy)] + AffineScreenblock128x128, [AffineScreenblockEntry; 128*128], no frills +} diff --git a/src/video/bitmap.rs b/src/vram/bitmap.rs similarity index 100% rename from src/video/bitmap.rs rename to src/vram/bitmap.rs diff --git a/src/vram/text.rs b/src/vram/text.rs new file mode 100644 index 0000000..58f5aa4 --- /dev/null +++ b/src/vram/text.rs @@ -0,0 +1,29 @@ +//! Module for tiled mode types and operations. + +use super::*; + +newtype! { + /// A screenblock entry for use in Text mode. + #[derive(Debug, Clone, Copy, Default)] + TextScreenblockEntry, u16 +} +impl TextScreenblockEntry { + pub const fn from_tile_index(index: u16) -> Self { + TextScreenblockEntry(index & Self::TILE_ID_MASK) + } + + bool_bits!(u16, [(10, hflip), (11, vflip)]); + + multi_bits!(u16, [(0, 10, tile_id), (12, 4, palbank)]); +} + +newtype! { + /// A screenblock for use in Text mode. + #[derive(Clone, Copy)] + TextScreenblock, [TextScreenblockEntry; 32 * 32], no frills +} + +#[test] +pub fn test_text_screen_block_size() { + assert_eq!(core::mem::size_of::(), 0x800); +}