2018-11-19 16:19:13 +11:00
|
|
|
#![feature(start)]
|
|
|
|
#![no_std]
|
|
|
|
|
|
|
|
#[panic_handler]
|
|
|
|
fn panic(_info: &core::panic::PanicInfo) -> ! {
|
|
|
|
loop {}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[start]
|
|
|
|
fn main(_argc: isize, _argv: *const *const u8) -> isize {
|
2018-12-06 15:56:39 +11:00
|
|
|
// bg palette
|
|
|
|
set_bg_palette_4bpp(0, 1, WHITE);
|
|
|
|
set_bg_palette_4bpp(0, 2, LIGHT_GRAY);
|
|
|
|
set_bg_palette_4bpp(0, 3, DARK_GRAY);
|
|
|
|
// bg tiles
|
|
|
|
set_bg_tile_4bpp(0, 0, ALL_TWOS);
|
|
|
|
set_bg_tile_4bpp(0, 1, ALL_THREES);
|
|
|
|
// screenblock
|
|
|
|
let light_entry = RegularScreenblockEntry::from_tile_id(0);
|
|
|
|
let dark_entry = RegularScreenblockEntry::from_tile_id(1);
|
|
|
|
checker_screenblock(8, light_entry, dark_entry);
|
|
|
|
// bg0 control
|
|
|
|
unsafe { BG0CNT.write(BackgroundControlSetting::from_base_block(8)) };
|
|
|
|
// Display Control
|
|
|
|
unsafe { DISPCNT.write(DisplayControlSetting::JUST_ENABLE_BG0) };
|
|
|
|
loop {
|
|
|
|
// TODO the whole thing
|
2018-11-19 16:19:13 +11:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-06 15:56:39 +11:00
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
2018-11-19 16:19:13 +11:00
|
|
|
#[repr(transparent)]
|
|
|
|
pub struct VolatilePtr<T>(pub *mut T);
|
|
|
|
impl<T> VolatilePtr<T> {
|
|
|
|
pub unsafe fn read(&self) -> T {
|
|
|
|
core::ptr::read_volatile(self.0)
|
|
|
|
}
|
|
|
|
pub unsafe fn write(&self, data: T) {
|
|
|
|
core::ptr::write_volatile(self.0, data);
|
|
|
|
}
|
2018-12-06 15:56:39 +11:00
|
|
|
pub fn offset(self, count: isize) -> Self {
|
2018-11-19 16:19:13 +11:00
|
|
|
VolatilePtr(self.0.wrapping_offset(count))
|
|
|
|
}
|
2018-12-06 15:56:39 +11:00
|
|
|
pub fn cast<Z>(self) -> VolatilePtr<Z> {
|
|
|
|
VolatilePtr(self.0 as *mut Z)
|
2018-11-19 16:19:13 +11:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-06 15:56:39 +11:00
|
|
|
pub const BACKGROUND_PALETTE: VolatilePtr<u16> = VolatilePtr(0x500_0000 as *mut u16);
|
2018-11-19 16:19:13 +11:00
|
|
|
|
2018-12-06 15:56:39 +11:00
|
|
|
pub fn set_bg_palette_4bpp(palbank: usize, slot: usize, color: u16) {
|
|
|
|
assert!(palbank < 16);
|
|
|
|
assert!(slot > 0 && slot < 16);
|
|
|
|
unsafe {
|
|
|
|
BACKGROUND_PALETTE
|
|
|
|
.cast::<[u16; 16]>()
|
|
|
|
.offset(palbank as isize)
|
|
|
|
.cast::<u16>()
|
|
|
|
.offset(slot as isize)
|
|
|
|
.write(color);
|
2018-11-19 16:19:13 +11:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-06 15:56:39 +11:00
|
|
|
pub const fn rgb16(red: u16, green: u16, blue: u16) -> u16 {
|
|
|
|
blue << 10 | green << 5 | red
|
2018-11-19 16:19:13 +11:00
|
|
|
}
|
|
|
|
|
2018-12-06 15:56:39 +11:00
|
|
|
pub const WHITE: u16 = rgb16(31, 31, 31);
|
|
|
|
pub const LIGHT_GRAY: u16 = rgb16(25, 25, 25);
|
|
|
|
pub const DARK_GRAY: u16 = rgb16(15, 15, 15);
|
2018-11-19 16:19:13 +11:00
|
|
|
|
2018-12-06 15:56:39 +11:00
|
|
|
#[derive(Debug, Clone, Copy, Default)]
|
2018-11-20 20:57:43 +11:00
|
|
|
#[repr(transparent)]
|
|
|
|
pub struct Tile4bpp {
|
2018-12-05 17:27:35 +11:00
|
|
|
pub data: [u32; 8],
|
2018-11-20 20:57:43 +11:00
|
|
|
}
|
|
|
|
|
2018-12-06 15:56:39 +11:00
|
|
|
pub const ALL_TWOS: Tile4bpp = Tile4bpp {
|
|
|
|
data: [
|
|
|
|
0x22222222, 0x22222222, 0x22222222, 0x22222222, 0x22222222, 0x22222222, 0x22222222, 0x22222222,
|
|
|
|
],
|
|
|
|
};
|
|
|
|
|
|
|
|
pub const ALL_THREES: Tile4bpp = Tile4bpp {
|
|
|
|
data: [
|
|
|
|
0x33333333, 0x33333333, 0x33333333, 0x33333333, 0x33333333, 0x33333333, 0x33333333, 0x33333333,
|
|
|
|
],
|
|
|
|
};
|
2018-11-20 20:57:43 +11:00
|
|
|
|
|
|
|
#[derive(Clone, Copy)]
|
|
|
|
#[repr(transparent)]
|
|
|
|
pub struct Charblock4bpp {
|
2018-12-05 17:27:35 +11:00
|
|
|
pub data: [Tile4bpp; 512],
|
2018-11-20 20:57:43 +11:00
|
|
|
}
|
|
|
|
|
2018-12-06 15:56:39 +11:00
|
|
|
pub const VRAM: VolatilePtr<Charblock4bpp> = VolatilePtr(0x0600_0000 as *mut Charblock4bpp);
|
2018-12-05 17:27:35 +11:00
|
|
|
|
2018-12-06 15:56:39 +11:00
|
|
|
pub fn set_bg_tile_4bpp(charblock: usize, index: usize, tile: Tile4bpp) {
|
|
|
|
assert!(charblock < 4);
|
|
|
|
assert!(index < 512);
|
|
|
|
unsafe { VRAM.offset(charblock as isize).cast::<Tile4bpp>().offset(index as isize).write(tile) }
|
2018-11-22 03:23:21 +11:00
|
|
|
}
|
|
|
|
|
2018-12-06 15:56:39 +11:00
|
|
|
#[derive(Debug, Clone, Copy, Default)]
|
2018-11-22 03:23:21 +11:00
|
|
|
#[repr(transparent)]
|
|
|
|
pub struct RegularScreenblockEntry(u16);
|
|
|
|
|
|
|
|
impl RegularScreenblockEntry {
|
2018-12-06 15:56:39 +11:00
|
|
|
pub const SCREENBLOCK_ENTRY_TILE_ID_MASK: u16 = 0b11_1111_1111;
|
2018-12-08 11:06:11 +11:00
|
|
|
pub const fn from_tile_id(id: u16) -> Self {
|
2018-12-06 15:56:39 +11:00
|
|
|
RegularScreenblockEntry(id & Self::SCREENBLOCK_ENTRY_TILE_ID_MASK)
|
2018-11-22 03:23:21 +11:00
|
|
|
}
|
2018-11-24 08:48:37 +11:00
|
|
|
}
|
|
|
|
|
2018-12-06 15:56:39 +11:00
|
|
|
#[derive(Clone, Copy)]
|
|
|
|
#[repr(transparent)]
|
|
|
|
pub struct RegularScreenblock {
|
|
|
|
pub data: [RegularScreenblockEntry; 32 * 32],
|
2018-11-24 08:48:37 +11:00
|
|
|
}
|
2018-11-26 19:35:30 +11:00
|
|
|
|
2018-12-06 15:56:39 +11:00
|
|
|
pub fn checker_screenblock(slot: usize, a_entry: RegularScreenblockEntry, b_entry: RegularScreenblockEntry) {
|
|
|
|
let mut p = VRAM.cast::<RegularScreenblock>().offset(slot as isize).cast::<RegularScreenblockEntry>();
|
|
|
|
let mut checker = true;
|
|
|
|
for _row in 0..32 {
|
|
|
|
for _col in 0..32 {
|
|
|
|
unsafe { p.write(if checker { a_entry } else { b_entry }) };
|
|
|
|
p = p.offset(1);
|
|
|
|
checker = !checker;
|
2018-11-26 19:35:30 +11:00
|
|
|
}
|
2018-12-06 15:56:39 +11:00
|
|
|
checker = !checker;
|
2018-11-26 19:35:30 +11:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-06 15:56:39 +11:00
|
|
|
#[derive(Clone, Copy, Default, PartialEq, Eq)]
|
|
|
|
#[repr(transparent)]
|
|
|
|
pub struct BackgroundControlSetting(u16);
|
2018-11-26 19:35:30 +11:00
|
|
|
|
2018-12-06 15:56:39 +11:00
|
|
|
impl BackgroundControlSetting {
|
2018-12-08 11:06:11 +11:00
|
|
|
pub const SCREEN_BASE_BLOCK_MASK: u16 = 0b1_1111;
|
|
|
|
pub const fn from_base_block(sbb: u16) -> Self {
|
|
|
|
BackgroundControlSetting((sbb & Self::SCREEN_BASE_BLOCK_MASK) << 8)
|
2018-11-26 19:35:30 +11:00
|
|
|
}
|
|
|
|
}
|
2018-11-29 12:18:23 +11:00
|
|
|
|
2018-12-06 15:56:39 +11:00
|
|
|
pub const BG0CNT: VolatilePtr<BackgroundControlSetting> = VolatilePtr(0x400_0008 as *mut BackgroundControlSetting);
|
2018-11-29 12:18:23 +11:00
|
|
|
|
2018-12-06 15:56:39 +11:00
|
|
|
#[derive(Clone, Copy, Default, PartialEq, Eq)]
|
2018-11-29 18:15:41 +11:00
|
|
|
#[repr(transparent)]
|
2018-12-06 15:56:39 +11:00
|
|
|
pub struct DisplayControlSetting(u16);
|
2018-11-29 18:15:41 +11:00
|
|
|
|
2018-12-06 15:56:39 +11:00
|
|
|
impl DisplayControlSetting {
|
|
|
|
pub const JUST_ENABLE_BG0: DisplayControlSetting = DisplayControlSetting(1 << 8);
|
2018-11-29 18:15:41 +11:00
|
|
|
}
|
|
|
|
|
2018-12-06 15:56:39 +11:00
|
|
|
pub const DISPCNT: VolatilePtr<DisplayControlSetting> = VolatilePtr(0x0400_0000 as *mut DisplayControlSetting);
|