fix affine stuff.

This commit is contained in:
Lokathor 2022-10-24 14:38:38 -06:00
parent ee925d5a4d
commit a7ac5d508a
5 changed files with 139 additions and 69 deletions

View file

@ -1,5 +1,9 @@
# Changelog # Changelog
* **0.10.0:**
* **Breaking:** Cleaned up the screenblock interface. Because they're in VRAM,
they can't use `u8` access like they were defined to use before. Now the
types use `u8x2`, similar to the Mode 4 bitmap.
* **0.9.3:** * **0.9.3:**
* Added `as_u32_slice` and `as_u16_slice` to `Align4`. * Added `as_u32_slice` and `as_u16_slice` to `Align4`.
* *Removed* the requirement for inputs to `include_aligned_bytes!` to be a * *Removed* the requirement for inputs to `include_aligned_bytes!` to be a

View file

@ -6,6 +6,10 @@ version = "0.9.3"
edition = "2021" edition = "2021"
license = "Zlib OR Apache-2.0 OR MIT" license = "Zlib OR Apache-2.0 OR MIT"
[features]
default = ["track_caller"]
track_caller = []
[dependencies] [dependencies]
bitfrob = "0.2.3" bitfrob = "0.2.3"
voladdress = { version = "1.2.1", features = ["experimental_volregion"] } voladdress = { version = "1.2.1", features = ["experimental_volregion"] }

View file

@ -82,7 +82,7 @@ extern "C" fn main() -> ! {
{ {
// get the the tilemap copied into place // get the the tilemap copied into place
let tsb = TextScreenblockAddress::new(31); let tsb = TextScreenblockAddress::new(31);
tsb.write_words(&TILE_LAYOUT); tsb.write_word_array(&TILE_LAYOUT);
} }
{ {

View file

@ -8,7 +8,8 @@ pub type i16fx8 = Fixed<i16, 8>;
/// `i16` with 14 bits of fixed-point fraction. /// `i16` with 14 bits of fixed-point fraction.
/// ///
/// This is used by the [`ArcTan`] and [`ArcTan2`] BIOS functions. /// This is used by the [`ArcTan`](crate::bios::ArcTan) and
/// [`ArcTan2`](crate::bios::ArcTan2) BIOS functions.
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
pub type i16fx14 = Fixed<i16, 14>; pub type i16fx14 = Fixed<i16, 14>;

View file

@ -214,6 +214,17 @@ def_mmio!(0x0500_2000 = OBJ_PALETTE: VolBlock<Color, Safe, Safe, 256>; "Object t
// Video RAM (VRAM) // Video RAM (VRAM)
/// The VRAM offset per screenblock index.
///
/// This is the same for all background types and sizes.
pub const SCREENBLOCK_INDEX_OFFSET: usize = 2 * 1_024;
/// The size of the background tile region of VRAM.
///
/// Background tile index use can cross between charblocks, but not past the end
/// of BG tile memory into OBJ tile memory.
pub const BG_TILE_REGION_SIZE: usize = 64 * 1_024;
def_mmio!(0x0600_0000 = CHARBLOCK0_4BPP: VolBlock<Tile4, Safe, Safe, 512>; "Charblock 0, 4bpp view (512 tiles)."); def_mmio!(0x0600_0000 = CHARBLOCK0_4BPP: VolBlock<Tile4, Safe, Safe, 512>; "Charblock 0, 4bpp view (512 tiles).");
def_mmio!(0x0600_4000 = CHARBLOCK1_4BPP: VolBlock<Tile4, Safe, Safe, 512>; "Charblock 1, 4bpp view (512 tiles)."); def_mmio!(0x0600_4000 = CHARBLOCK1_4BPP: VolBlock<Tile4, Safe, Safe, 512>; "Charblock 1, 4bpp view (512 tiles).");
def_mmio!(0x0600_8000 = CHARBLOCK2_4BPP: VolBlock<Tile4, Safe, Safe, 512>; "Charblock 2, 4bpp view (512 tiles)."); def_mmio!(0x0600_8000 = CHARBLOCK2_4BPP: VolBlock<Tile4, Safe, Safe, 512>; "Charblock 2, 4bpp view (512 tiles).");
@ -228,101 +239,151 @@ def_mmio!(0x0600_C000 = CHARBLOCK3_8BPP: VolBlock<Tile8, Safe, Safe, 256>; "Char
#[must_use] #[must_use]
const fn screenblock_addr(index: usize) -> usize { const fn screenblock_addr(index: usize) -> usize {
// The VRAM offset per screenblock isn't affected by the screenblock's size, it's always 2k // The VRAM offset per screenblock isn't affected by the screenblock's size, it's always 2k
0x0600_0000 + index * 2_048 0x0600_0000 + index * SCREENBLOCK_INDEX_OFFSET
} }
macro_rules! make_me_a_screenblock_addr { /// Text mode screenblock address.
( $(#[$name_meta:meta])* $name:ident($t:ty), $(#[$size_meta:meta])* size: $size:literal, $(#[$index_meta:meta])* max_index: $max_index:literal) => { #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] #[repr(transparent)]
#[repr(transparent)] pub struct TextScreenblockAddress {
$(#[$name_meta])* block: VolBlock<TextEntry, Safe, Safe, {32*32}>,
pub struct $name { }
block: VolBlock<$t, Safe, Safe, {$size*$size}>, impl TextScreenblockAddress {
} const WORD_COUNT: usize = (32 * 32 * size_of::<TextEntry>())/4;
impl $name {
#[inline] #[inline]
#[must_use] #[must_use]
$(#[$index_meta])* #[cfg_attr(feature="track_caller", track_caller)]
pub const fn new(index: usize) -> Self { pub const fn new(index: usize) -> Self {
assert!(index <= $max_index); assert!(index <= 31);
Self { block: unsafe { VolBlock::new(screenblock_addr(index)) } } Self { block: unsafe { VolBlock::new(screenblock_addr(index)) } }
} }
#[inline] #[inline]
#[must_use] #[must_use]
pub const fn as_usize(self) -> usize { pub const fn as_vol_block(self) -> VolBlock<TextEntry, Safe, Safe, {32*32}> {
self.block.as_usize() self.block
} }
#[inline] #[inline]
#[must_use] #[must_use]
$(#[$size_meta])* #[cfg_attr(feature="track_caller", track_caller)]
pub const fn row_col(self, row: usize, col: usize) -> VolAddress<$t, Safe, Safe> { pub const fn row_col(self, row: usize, col: usize) -> VolAddress<TextEntry, Safe, Safe> {
assert!(row < $size, concat!("`row` must be less than ", $size)); assert!(row < 32, "`row` must be less than 32");
assert!(col < $size, concat!("`col` must be less than ", $size)); assert!(col < 32, "`col` must be less than 32");
self.block.index(row * $size + col) self.block.index(row * 32 + col)
} }
const WORD_COUNT: usize = (size_of::<$t>() * $size * $size)/4; #[inline]
const _DEBUG_CHECK: () = { pub fn write_word_array(self, words: &[u32; Self::WORD_COUNT]) {
assert!((size_of::<$t>() * $size * $size) % 4 == 0);
()
};
/// Overwrites the entire screenblock with the data provided.
pub fn write_words(self, words: &[u32; Self::WORD_COUNT]) {
use crate::prelude::__aeabi_memcpy4; use crate::prelude::__aeabi_memcpy4;
let dest: *mut u32 = self.block.as_ptr() as *mut u32; let dest: *mut u32 = self.block.as_ptr() as *mut u32;
let src: *const u32 = words.as_ptr(); let src: *const u32 = words.as_ptr();
let byte_count = size_of::<[u32; Self::WORD_COUNT]>(); let byte_count = size_of::<[u32; Self::WORD_COUNT]>();
unsafe { __aeabi_memcpy4(dest.cast(), src.cast(), byte_count) }; unsafe { __aeabi_memcpy4(dest.cast(), src.cast(), byte_count) };
} }
}
#[inline]
#[cfg_attr(feature="track_caller", track_caller)]
pub fn write_word_slice(self, words: &[u32]) {
assert_eq!(words.len(), Self::WORD_COUNT);
self.write_word_array(unsafe { &*words.as_ptr().cast::<[u32; Self::WORD_COUNT]>() })
} }
} }
make_me_a_screenblock_addr!( macro_rules! make_affine_screenblock_address_type {
/// Screenblock address for text mode backgrounds (32x32). ($(#[$name_meta:meta])* $name:ident, size: $size:literal) => {
TextScreenblockAddress(TextEntry), $(#[$name_meta])*
/// Size: 32x32 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
size: 32, #[repr(transparent)]
/// Max Index: 31 pub struct $name {
max_index: 31 block: VolBlock<u8x2, Safe, Safe, {Self::HEIGHT*Self::WIDTH}>,
}
impl $name {
pub const BG_SIZE: usize = $size;
pub const WIDTH: usize = (16 << Self::BG_SIZE) / 2;
pub const HEIGHT: usize = 16 << Self::BG_SIZE;
pub const ENTRIES: usize = Self::WIDTH * Self::HEIGHT;
pub const BYTES: usize = Self::ENTRIES * size_of::<u8x2>();
pub const WORD_COUNT: usize = {
assert!(Self::BYTES % 4 == 0);
Self::BYTES/4
};
pub const MAX_INDEX: usize = {
let mut i = 0;
while ((i+1) * SCREENBLOCK_INDEX_OFFSET) + (Self::BYTES) <= BG_TILE_REGION_SIZE {
i += 1;
}
if i > 31 {
31
} else {
i
}
};
#[inline]
#[must_use]
#[cfg_attr(feature="track_caller", track_caller)]
pub const fn new(index: usize) -> Self {
assert!(index <= Self::MAX_INDEX);
Self { block: unsafe { VolBlock::new(screenblock_addr(index)) } }
}
#[inline]
#[must_use]
pub const fn as_vol_block(self) -> VolBlock<u8x2, Safe, Safe, {Self::HEIGHT*Self::WIDTH}> {
self.block
}
#[inline]
#[must_use]
#[cfg_attr(feature="track_caller", track_caller)]
pub const fn row_col(self, row: usize, col: usize) -> VolAddress<u8x2, Safe, Safe> {
assert!(row < Self::HEIGHT, "`row` out of bounds.");
assert!(col < Self::WIDTH, "`col` out of bounds.");
self.block.index(row * 32 + col)
}
#[inline]
pub fn write_word_array(self, words: &[u32; Self::WORD_COUNT]) {
use crate::prelude::__aeabi_memcpy4;
let dest: *mut u32 = self.block.as_ptr() as *mut u32;
let src: *const u32 = words.as_ptr();
let byte_count = size_of::<[u32; Self::WORD_COUNT]>();
unsafe { __aeabi_memcpy4(dest.cast(), src.cast(), byte_count) };
}
#[inline]
#[cfg_attr(feature="track_caller", track_caller)]
pub fn write_word_slice(self, words: &[u32]) {
assert_eq!(words.len(), Self::WORD_COUNT);
self.write_word_array(unsafe { &*words.as_ptr().cast::<[u32; Self::WORD_COUNT]>() })
}
}
}
}
make_affine_screenblock_address_type!(
/// Affine mode screenblock address for a size 0 background.
Affine0ScreenblockAddress,
size: 0
); );
make_me_a_screenblock_addr!( make_affine_screenblock_address_type!(
/// Screenblock address for size 0 affine mode backgrounds (16x16). /// Affine mode screenblock address for a size 1 background.
AffineScreenBlock0Address(u8), Affine1ScreenblockAddress,
/// Size: 16x16 size: 1
size: 16,
/// Max Index: 31
max_index: 31
); );
make_me_a_screenblock_addr!( make_affine_screenblock_address_type!(
/// Screenblock address for size 1 affine mode backgrounds (32x32). /// Affine mode screenblock address for a size 2 background.
AffineScreenBlock1Address(u8), Affine2ScreenblockAddress,
/// Size: 32x32 size: 2
size: 32,
/// Max Index: 31
max_index: 31
); );
make_me_a_screenblock_addr!( make_affine_screenblock_address_type!(
/// Screenblock address for size 2 affine mode backgrounds (64x64). /// Affine mode screenblock address for a size 3 background.
AffineScreenBlock2Address(u8), Affine3ScreenblockAddress,
/// Size: 64x64 size: 3
size: 64,
/// Max Index: 29
max_index: 29
);
make_me_a_screenblock_addr!(
/// Screenblock address for size 3 affine mode backgrounds (128x128).
AffineScreenBlock3Address(u8),
/// Size: 128x128
size: 128,
/// Max Index: 23
max_index: 23
); );
/// Video mode 3 has a single full resolution bitmap /// Accesses VRAM as the Video Mode 3 single bitmap.
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct VideoMode3Bitmap; pub struct VideoMode3Bitmap;
impl VideoMode3Bitmap { impl VideoMode3Bitmap {
@ -351,7 +412,7 @@ impl VideoMode3Bitmap {
} }
} }
/// Video mode 4 has two 8bpp indexmaps. /// Accesses VRAM as a Video Mode 4 bitmap frame.
/// ///
/// Because VRAM can't be written with less than 2 bytes at a time, the /// Because VRAM can't be written with less than 2 bytes at a time, the
/// scanlines here use `u8x2` to represent pixels pairs so that all the writes /// scanlines here use `u8x2` to represent pixels pairs so that all the writes
@ -374,7 +435,7 @@ impl VideoMode4Frame {
} }
} }
/// Video mode 5 has two reduced-resolution bitmaps. /// Accesses VRAM as a Video Mode 5 bitmap frame.
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct VideoMode5Frame(usize); pub struct VideoMode5Frame(usize);
impl VideoMode5Frame { impl VideoMode5Frame {