You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

295 lines
8.8 KiB

#![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);
}
}
}