move display modes to own file

This commit is contained in:
Corwin Kuiper 2021-03-06 22:46:55 +00:00
parent 9b0bdb17e5
commit cc48605f4a
4 changed files with 207 additions and 192 deletions

View file

@ -1,192 +0,0 @@
use crate::{
memory_mapped::{MemoryMapped, MemoryMapped1DArray, MemoryMapped2DArray},
single::{Single, SingleToken},
};
use bitflags::bitflags;
use core::convert::TryInto;
const DISPLAY_CONTROL: MemoryMapped<u16> = unsafe { MemoryMapped::new(0x0400_0000) };
const DISPLAY_STATUS: MemoryMapped<u16> = unsafe { MemoryMapped::new(0x0400_0004) };
const VCOUNT: MemoryMapped<u16> = unsafe { MemoryMapped::new(0x0400_0006) };
const PALETTE_BACKGROUND: MemoryMapped1DArray<u16, 256> =
unsafe { MemoryMapped1DArray::new(0x0500_0000) };
const PALETTE_SPRITE: MemoryMapped1DArray<u16, 256> =
unsafe { MemoryMapped1DArray::new(0x0500_0200) };
const BITMAP_MODE_3: MemoryMapped2DArray<u16, { WIDTH as usize }, { HEIGHT as usize }> =
unsafe { MemoryMapped2DArray::new(0x600_0000) };
const BITMAP_PAGE_FRONT_MODE_4: MemoryMapped2DArray<
u16,
{ (WIDTH / 2) as usize },
{ HEIGHT as usize },
> = unsafe { MemoryMapped2DArray::new(0x600_0000) };
const BITMAP_PAGE_BACK_MODE_4: MemoryMapped2DArray<
u16,
{ (WIDTH / 2) as usize },
{ HEIGHT as usize },
> = unsafe { MemoryMapped2DArray::new(0x600_A000) };
pub const WIDTH: i32 = 240;
pub const HEIGHT: i32 = 160;
pub enum DisplayMode {
Tiled0 = 0,
Tiled1 = 1,
Tiled2 = 2,
Bitmap3 = 3,
Bitmap4 = 4,
Bitmap5 = 5,
}
pub enum Page {
Front = 0,
Back = 1,
}
bitflags! {
pub struct GraphicsSettings: u16 {
const PAGE_SELECT = 1 << 0x4;
const OAM_HBLANK = 1 << 0x5;
const SPRITE1_D = 1 << 0x6;
const SCREEN_BLANK = 1 << 0x7;
const LAYER_BG0 = 1 << 0x8;
const LAYER_BG1 = 1 << 0x9;
const LAYER_BG2 = 1 << 0xA;
const LAYER_BG3 = 1 << 0xB;
const LAYER_OBJ = 1 << 0xC;
const WINDOW0 = 1 << 0xD;
const WINDOW1 = 1 << 0xE;
const WINDOW_OBJECT = 1 << 0xF;
}
}
pub struct Display {
in_mode: Single,
}
impl Display {
pub(crate) const unsafe fn new() -> Self {
Display {
in_mode: Single::new(),
}
}
pub fn bitmap3(&self) -> Bitmap3 {
Bitmap3::new(
self.in_mode
.take()
.expect("Cannot create new mode as mode already taken"),
)
}
pub fn bitmap4(&self) -> Bitmap4 {
Bitmap4::new(
self.in_mode
.take()
.expect("Cannot create new mode as mode already taken"),
)
}
}
pub struct Bitmap3<'a> {
_in_mode: SingleToken<'a>,
}
impl<'a> Bitmap3<'a> {
fn new(in_mode: SingleToken<'a>) -> Self {
set_graphics_mode(DisplayMode::Bitmap3);
set_graphics_settings(GraphicsSettings::LAYER_BG2);
Bitmap3 { _in_mode: in_mode }
}
pub fn draw_point(&self, x: i32, y: i32, colour: u16) {
let x = x.try_into().unwrap();
let y = y.try_into().unwrap();
BITMAP_MODE_3.set(x, y, colour)
}
}
pub struct Bitmap4<'a> {
_in_mode: SingleToken<'a>,
}
impl<'a> Bitmap4<'a> {
fn new(in_mode: SingleToken<'a>) -> Self {
set_graphics_mode(DisplayMode::Bitmap4);
set_graphics_settings(GraphicsSettings::LAYER_BG2);
Bitmap4 { _in_mode: in_mode }
}
pub fn draw_point_page(&self, x: i32, y: i32, colour: u8, page: Page) {
let addr = match page {
Page::Front => BITMAP_PAGE_FRONT_MODE_4,
Page::Back => BITMAP_PAGE_BACK_MODE_4,
};
let x_in_screen = (x / 2) as usize;
let y_in_screen = y as usize;
let c = addr.get(x_in_screen, y_in_screen);
if x & 0b1 != 0 {
addr.set(x_in_screen, y_in_screen, c | (colour as u16) << 8);
} else {
addr.set(x_in_screen, y_in_screen, c | colour as u16);
}
}
pub fn draw_point(&self, x: i32, y: i32, colour: u8) {
let disp = DISPLAY_CONTROL.get();
let page = if disp & GraphicsSettings::PAGE_SELECT.bits() != 0 {
Page::Back
} else {
Page::Front
};
self.draw_point_page(x, y, colour, page)
}
pub fn set_palette_entry(&self, entry: u32, colour: u16) {
PALETTE_BACKGROUND.set(entry as usize, colour);
}
pub fn flip_page(&self) {
let disp = DISPLAY_CONTROL.get();
let swapped = disp ^ GraphicsSettings::PAGE_SELECT.bits();
DISPLAY_CONTROL.set(swapped);
}
}
fn set_graphics_mode(mode: DisplayMode) {
let current = DISPLAY_CONTROL.get();
let current = current & (!0b111);
let s = current | (mode as u16 & 0b111);
DISPLAY_CONTROL.set(s);
}
pub fn set_graphics_settings(settings: GraphicsSettings) {
let current = DISPLAY_CONTROL.get();
// preserve display mode
let current = current & 0b111;
let s = settings.bits() | current;
DISPLAY_CONTROL.set(s);
}
#[allow(non_snake_case)]
pub fn busy_wait_for_VBlank() {
while VCOUNT.get() >= 160 {}
while VCOUNT.get() < 160 {}
}
#[allow(non_snake_case)]
pub fn enable_VBlank_interrupt() {
let status = DISPLAY_STATUS.get() | (1 << 3);
DISPLAY_STATUS.set(status);
}
#[allow(non_snake_case)]
pub fn wait_for_VBlank() {
crate::syscall::wait_for_VBlank();
}

27
src/display/bitmap3.rs Normal file
View file

@ -0,0 +1,27 @@
use crate::{memory_mapped::MemoryMapped2DArray, single::SingleToken};
use super::{
set_graphics_mode, set_graphics_settings, DisplayMode, GraphicsSettings, HEIGHT, WIDTH,
};
use core::convert::TryInto;
const BITMAP_MODE_3: MemoryMapped2DArray<u16, { WIDTH as usize }, { HEIGHT as usize }> =
unsafe { MemoryMapped2DArray::new(0x600_0000) };
pub struct Bitmap3<'a> {
_in_mode: SingleToken<'a>,
}
impl<'a> Bitmap3<'a> {
pub(crate) fn new(in_mode: SingleToken<'a>) -> Self {
set_graphics_mode(DisplayMode::Bitmap3);
set_graphics_settings(GraphicsSettings::LAYER_BG2);
Bitmap3 { _in_mode: in_mode }
}
pub fn draw_point(&self, x: i32, y: i32, colour: u16) {
let x = x.try_into().unwrap();
let y = y.try_into().unwrap();
BITMAP_MODE_3.set(x, y, colour)
}
}

78
src/display/bitmap4.rs Normal file
View file

@ -0,0 +1,78 @@
use crate::{
memory_mapped::{MemoryMapped1DArray, MemoryMapped2DArray},
single::SingleToken,
};
use super::{
set_graphics_mode, set_graphics_settings, DisplayMode, GraphicsSettings, DISPLAY_CONTROL,
HEIGHT, WIDTH,
};
const BITMAP_PAGE_FRONT_MODE_4: MemoryMapped2DArray<
u16,
{ (WIDTH / 2) as usize },
{ HEIGHT as usize },
> = unsafe { MemoryMapped2DArray::new(0x600_0000) };
const BITMAP_PAGE_BACK_MODE_4: MemoryMapped2DArray<
u16,
{ (WIDTH / 2) as usize },
{ HEIGHT as usize },
> = unsafe { MemoryMapped2DArray::new(0x600_A000) };
const PALETTE_BACKGROUND: MemoryMapped1DArray<u16, 256> =
unsafe { MemoryMapped1DArray::new(0x0500_0000) };
pub enum Page {
Front = 0,
Back = 1,
}
pub struct Bitmap4<'a> {
_in_mode: SingleToken<'a>,
}
impl<'a> Bitmap4<'a> {
pub(crate) fn new(in_mode: SingleToken<'a>) -> Self {
set_graphics_mode(DisplayMode::Bitmap4);
set_graphics_settings(GraphicsSettings::LAYER_BG2);
Bitmap4 { _in_mode: in_mode }
}
pub fn draw_point_page(&self, x: i32, y: i32, colour: u8, page: Page) {
let addr = match page {
Page::Front => BITMAP_PAGE_FRONT_MODE_4,
Page::Back => BITMAP_PAGE_BACK_MODE_4,
};
let x_in_screen = (x / 2) as usize;
let y_in_screen = y as usize;
let c = addr.get(x_in_screen, y_in_screen);
if x & 0b1 != 0 {
addr.set(x_in_screen, y_in_screen, c | (colour as u16) << 8);
} else {
addr.set(x_in_screen, y_in_screen, c | colour as u16);
}
}
pub fn draw_point(&self, x: i32, y: i32, colour: u8) {
let disp = DISPLAY_CONTROL.get();
let page = if disp & GraphicsSettings::PAGE_SELECT.bits() != 0 {
Page::Back
} else {
Page::Front
};
self.draw_point_page(x, y, colour, page)
}
pub fn set_palette_entry(&self, entry: u32, colour: u16) {
PALETTE_BACKGROUND.set(entry as usize, colour);
}
pub fn flip_page(&self) {
let disp = DISPLAY_CONTROL.get();
let swapped = disp ^ GraphicsSettings::PAGE_SELECT.bits();
DISPLAY_CONTROL.set(swapped);
}
}

102
src/display/mod.rs Normal file
View file

@ -0,0 +1,102 @@
use crate::{memory_mapped::MemoryMapped, single::Single};
use bitflags::bitflags;
use bitmap3::Bitmap3;
use bitmap4::Bitmap4;
mod bitmap3;
mod bitmap4;
const DISPLAY_CONTROL: MemoryMapped<u16> = unsafe { MemoryMapped::new(0x0400_0000) };
const DISPLAY_STATUS: MemoryMapped<u16> = unsafe { MemoryMapped::new(0x0400_0004) };
const VCOUNT: MemoryMapped<u16> = unsafe { MemoryMapped::new(0x0400_0006) };
bitflags! {
pub struct GraphicsSettings: u16 {
const PAGE_SELECT = 1 << 0x4;
const OAM_HBLANK = 1 << 0x5;
const SPRITE1_D = 1 << 0x6;
const SCREEN_BLANK = 1 << 0x7;
const LAYER_BG0 = 1 << 0x8;
const LAYER_BG1 = 1 << 0x9;
const LAYER_BG2 = 1 << 0xA;
const LAYER_BG3 = 1 << 0xB;
const LAYER_OBJ = 1 << 0xC;
const WINDOW0 = 1 << 0xD;
const WINDOW1 = 1 << 0xE;
const WINDOW_OBJECT = 1 << 0xF;
}
}
pub const WIDTH: i32 = 240;
pub const HEIGHT: i32 = 160;
pub enum DisplayMode {
Tiled0 = 0,
Tiled1 = 1,
Tiled2 = 2,
Bitmap3 = 3,
Bitmap4 = 4,
Bitmap5 = 5,
}
pub struct Display {
in_mode: Single,
}
impl Display {
pub(crate) const unsafe fn new() -> Self {
Display {
in_mode: Single::new(),
}
}
pub fn bitmap3(&self) -> Bitmap3 {
Bitmap3::new(
self.in_mode
.take()
.expect("Cannot create new mode as mode already taken"),
)
}
pub fn bitmap4(&self) -> Bitmap4 {
bitmap4::Bitmap4::new(
self.in_mode
.take()
.expect("Cannot create new mode as mode already taken"),
)
}
}
fn set_graphics_mode(mode: DisplayMode) {
let current = DISPLAY_CONTROL.get();
let current = current & (!0b111);
let s = current | (mode as u16 & 0b111);
DISPLAY_CONTROL.set(s);
}
pub fn set_graphics_settings(settings: GraphicsSettings) {
let current = DISPLAY_CONTROL.get();
// preserve display mode
let current = current & 0b111;
let s = settings.bits() | current;
DISPLAY_CONTROL.set(s);
}
#[allow(non_snake_case)]
pub fn busy_wait_for_VBlank() {
while VCOUNT.get() >= 160 {}
while VCOUNT.get() < 160 {}
}
#[allow(non_snake_case)]
pub fn enable_VBlank_interrupt() {
let status = DISPLAY_STATUS.get() | (1 << 3);
DISPLAY_STATUS.set(status);
}
#[allow(non_snake_case)]
pub fn wait_for_VBlank() {
crate::syscall::wait_for_VBlank();
}