#![no_std] use core::ptr::{read_volatile, write_volatile}; pub const BASE_POINTER : u32 = 0x1000_0000; pub const NUMBER_DISPLAY_OFFSET : u32 = 0x00; pub const RANDOM_NUMBER_OFFSET : u32 = 0x04; pub const BUTTONS_OFFSET : u32 = 0x08; pub const KEYBOARD_OFFSET : u32 = 0x10; pub const CHAR_CONTROL_OFFSET : u32 = 0x20; pub const SCREEN_CONTROL_OFFSET : u32 = 0x22; pub const CHAR_DISPLAY_OFFSET : u32 = 0x24; pub const TEXT_DISPLAY_OFFSET : u32 = 0x28; // cheeseutil modded display 64x64 characters pub const AUDIO_MAIN_OFFSET : u32 = 0x30; pub const SCREEN_OFFSET : u32 = 0x80; pub const NUMBER_DISPLAY_POINTER : *mut u32 = (BASE_POINTER + NUMBER_DISPLAY_OFFSET) as *mut u32; pub const RANDOM_NUMBER_POINTER : *mut u32 = (BASE_POINTER + RANDOM_NUMBER_OFFSET) as *mut u32; pub const BUTTONS_POINTER : *mut u8 = (BASE_POINTER + BUTTONS_OFFSET) as *mut u8; pub const CHAR_DISPLAY_POINTER : *mut u8 = (BASE_POINTER + CHAR_DISPLAY_OFFSET) as *mut u8; pub const KEYBOARD_POINTER : *mut u32 = (BASE_POINTER + KEYBOARD_OFFSET) as *mut u32; pub const SCREEN_CONTROL_POINTER : *mut u16 = (BASE_POINTER + SCREEN_CONTROL_OFFSET) as *mut u16; pub const CHAR_CONTROL_POINTER : *mut u16 = (BASE_POINTER + CHAR_CONTROL_OFFSET) as *mut u16; pub const TEXT_DISPLAY_POINTER : *mut u8 = (BASE_POINTER + TEXT_DISPLAY_OFFSET) as *mut u8; pub const AUDIO_MAIN_POINTER : *mut u32 = (BASE_POINTER + AUDIO_MAIN_OFFSET) as *mut u32; pub const SCREEN_POINTER : *mut u32 = (BASE_POINTER + SCREEN_OFFSET) as *mut u32; pub enum ScreenMode { AlwaysDisplay, Buffered, } pub struct Screen {} impl Screen { const CLEAR : u16 = 0x0001; const DISPLAY : u16 = 0x0100; #[inline] pub fn init(mode: ScreenMode) { unsafe { write_volatile(SCREEN_CONTROL_POINTER, Self::CLEAR | Self::DISPLAY); match mode { ScreenMode::AlwaysDisplay => { write_volatile(SCREEN_CONTROL_POINTER, Self::DISPLAY); }, ScreenMode::Buffered => { write_volatile(SCREEN_CONTROL_POINTER, 0); } } } } #[inline] pub fn clear() { unsafe { // Write a 1 to the screen clear byte write_volatile(SCREEN_CONTROL_POINTER as *mut u8, 1); write_volatile(SCREEN_CONTROL_POINTER as *mut u8, 0); } } #[inline] pub fn display() { unsafe { // Write a 1 to the screen display byte write_volatile((SCREEN_CONTROL_POINTER as *mut u8).byte_offset(1), 1); write_volatile((SCREEN_CONTROL_POINTER as *mut u8).byte_offset(1), 0); } } #[inline] pub fn change_mode(mode: ScreenMode) { match mode { ScreenMode::AlwaysDisplay => unsafe { write_volatile((SCREEN_CONTROL_POINTER as *mut u8).byte_offset(1), 1); }, ScreenMode::Buffered => unsafe { write_volatile((SCREEN_CONTROL_POINTER as *mut u8).byte_offset(1), 0); }, } } #[inline] pub fn turn_pixel_on(x: u8, y: u8) { unsafe { let mut row = read_volatile(SCREEN_POINTER.offset(y as isize)); row |= 1 << x; write_volatile(SCREEN_POINTER.offset(y as isize), row); } } #[inline] pub fn turn_pixel_off(x: u8, y: u8) { unsafe { let mut row = read_volatile(SCREEN_POINTER.offset(y as isize)); row &= !(1 << x); write_volatile(SCREEN_POINTER.offset(y as isize), row); } } #[inline] pub fn set_line(y: u8, value: u32) { unsafe { write_volatile(SCREEN_POINTER.offset(y as isize), value); } } } pub struct CharDisplay {} impl CharDisplay { const CLEAR : u16 = 0x0001; const DISPLAY : u16 = 0x0100; #[inline] pub fn init(&self) { unsafe { write_volatile(CHAR_CONTROL_POINTER, Self::CLEAR); // hide contents and clear write_volatile(CHAR_CONTROL_POINTER, Self::DISPLAY); // display contents } } #[inline] pub fn put_char(&self, ch: u8) { unsafe { write_volatile(CHAR_DISPLAY_POINTER, ch); } } #[inline] pub fn hide(&self) { unsafe { write_volatile((CHAR_CONTROL_POINTER as *mut u8).byte_offset(1), 0); } } #[inline] pub fn show(&self) { unsafe { write_volatile((CHAR_CONTROL_POINTER as *mut u8).byte_offset(1), 1); } } } impl core::fmt::Write for CharDisplay { #[inline] fn write_str(&mut self, s: &str) -> core::fmt::Result { for ch in s.bytes() { self.put_char(ch); } return Ok(()); } } pub struct TextDisplay { pos: u16 } impl TextDisplay { const CLEAR : u8 = 0b00000001; const SET_CHAR : u8 = 0b00000010; const SET_CURSOR : u8 = 0b00000100; const BLINK : u8 = 0b00001000; const SCROLL_UP : u8 = 0b00010000; // const SCROLL_DOWN : u8 = 0b00100000; // const SCROLL_LEFT : u8 = 0b01000000; // const SCROLL_RIGHT : u8 = 0b10000000; #[inline] pub fn clear(&mut self, blink: bool) { unsafe { let control_ptr = TEXT_DISPLAY_POINTER.offset(3); write_volatile(control_ptr, Self::CLEAR); match blink { true => { write_volatile(TEXT_DISPLAY_POINTER as *mut u16, self.pos); write_volatile(control_ptr, Self::SET_CURSOR); write_volatile(control_ptr, Self::BLINK); }, false => { write_volatile(control_ptr, 0); }, } } } #[inline] pub fn put_char(&mut self, ch: u8) { unsafe { let control_ptr = TEXT_DISPLAY_POINTER.offset(3); let control = read_volatile(control_ptr); if ch == b'\n' { if self.pos >= 63*64 { // last row write_volatile(control_ptr, Self::SCROLL_UP); write_volatile(control_ptr, control); } else { self.pos += 64; // increment row } self.pos &= !63u16; // set column to 0 } else { write_volatile(TEXT_DISPLAY_POINTER as *mut u16, self.pos); write_volatile(TEXT_DISPLAY_POINTER.offset(2), ch); write_volatile(control_ptr, Self::SET_CHAR); write_volatile(control_ptr, control); self.pos += 1; write_volatile(TEXT_DISPLAY_POINTER as *mut u16, self.pos); } write_volatile(control_ptr, Self::SET_CURSOR); write_volatile(control_ptr, control); } } } impl Default for TextDisplay { #[inline] fn default() -> Self { Self { pos: 0 } } } impl core::fmt::Write for TextDisplay { #[inline] fn write_str(&mut self, s: &str) -> core::fmt::Result { for ch in s.bytes() { self.put_char(ch); } return Ok(()); } } pub struct NumberDisplay {} impl NumberDisplay { #[inline] pub fn display_number(number: u32) { unsafe { write_volatile(NUMBER_DISPLAY_POINTER, number); } } #[inline] pub fn increment() { unsafe { let value = read_volatile(NUMBER_DISPLAY_POINTER); write_volatile(NUMBER_DISPLAY_POINTER, value + 1); } } } pub struct RNG {} impl RNG { #[inline] pub fn next() -> u32 { return unsafe { read_volatile(RANDOM_NUMBER_POINTER) }; } #[inline] pub fn next_range(min: u32, max: u32) -> u32 { return RNG::next() % (max - min) + min; } } pub struct Buttons {} impl Buttons { pub const A : u8 = 0b00000001; pub const B : u8 = 0b00000010; pub const X : u8 = 0b00000100; pub const Y : u8 = 0b00001000; pub const RIGHT : u8 = 0b00010000; pub const DOWN : u8 = 0b00100000; pub const LEFT : u8 = 0b01000000; pub const UP : u8 = 0b10000000; #[inline] pub fn read1() -> u8 { return unsafe { read_volatile(BUTTONS_POINTER) }; } #[inline] pub fn read2() -> u8 { return unsafe { read_volatile(BUTTONS_POINTER.byte_offset(3)) }; } } pub struct Audio {} impl Audio { #[inline] pub fn play_upper(notes: u32) { unsafe { write_volatile(AUDIO_MAIN_POINTER, notes); } } #[inline] pub fn play_lower(notes: u32) { unsafe { write_volatile(AUDIO_MAIN_POINTER.offset(1), notes); } } #[inline] pub fn stop() { unsafe { write_volatile(AUDIO_MAIN_POINTER.offset(0), 0); write_volatile(AUDIO_MAIN_POINTER.offset(1), 0); } } }