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
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);
|
|
}
|
|
}
|
|
|
|
}
|