#![no_std]
#![feature(start)]
extern crate alloc;
extern crate mos_alloc;
use core::panic::PanicInfo;
use mos_hardware::screen_codes;
use mos_hardware::sid::SidTune;
use mos_hardware::{c64, vic2};
use vic2::*;
struct SmoothScroll {
text_index: usize,
displacement: u8,
}
impl SmoothScroll {
const YPOSITION: u16 = 8;
const LEFTMOST_CHAR: *mut u8 = (0x0400 + (40 * SmoothScroll::YPOSITION as u16)) as *mut u8;
const RIGHTMOST_CHAR: *mut u8 =
(0x0400 + (40 * SmoothScroll::YPOSITION + 39 as u16)) as *mut u8;
const SCROLL_TEXT: [u8; 262] = screen_codes!(
"Hello from RUST! This is a tiny demo written \
in rust using the llvm-mos backend for 6502 code generation. \
The top color flickering reflects time spent in the raster interrupt, i.e. \
scroll (green) and sprite movement (red), while SID music playback is not shown. "
);
const fn new() -> Self {
Self {
text_index: 0,
displacement: 7,
}
}
pub fn init(&self) {
let mut mask = c64::vic2().control_x.read();
mask.set(ControlXFlags::COLUMN_SELECT, false);
unsafe {
c64::vic2().control_x.write(mask);
}
}
#[inline]
fn move_pixel(&mut self) {
self.displacement = match self.displacement.checked_sub(1) {
Some(x) => x,
None => 7,
};
let mut mask = c64::vic2().control_x.read();
mask.set(ControlXFlags::XSCROLL, false);
mask = ControlXFlags::from_bits(mask.bits() + self.displacement).unwrap();
unsafe {
c64::vic2().control_x.write(mask);
}
}
#[inline]
fn leftcopy_chars(&self) {
for i in 0..39 {
unsafe {
let character = SmoothScroll::LEFTMOST_CHAR.offset(i + 1).read_volatile();
SmoothScroll::LEFTMOST_CHAR
.offset(i)
.write_volatile(character);
}
}
}
#[inline]
fn update_chars(&mut self) {
if self.text_index == SmoothScroll::SCROLL_TEXT.len() {
self.text_index = 0;
}
unsafe {
SmoothScroll::RIGHTMOST_CHAR.write_volatile(SmoothScroll::SCROLL_TEXT[self.text_index]);
}
self.leftcopy_chars();
self.text_index += 1;
}
fn update(&mut self) {
self.move_pixel();
if self.displacement == 7 {
self.update_chars();
}
}
}
struct SpriteMove {
counter_x: u8,
counter_y: u8,
}
impl SpriteMove {
const SPRITE_ADDRESS: u16 = 0x2000;
const SPRITE_PTR: u8 = vic2::to_sprite_pointer(SpriteMove::SPRITE_ADDRESS);
const OFFSET: u8 = 30;
const MSB_THRESHOLD: u8 = 255 - SpriteMove::OFFSET;
const fn new() -> Self {
SpriteMove {
counter_x: 0,
counter_y: 0,
}
}
pub fn init(&self) {
unsafe {
*(SpriteMove::SPRITE_ADDRESS as *mut [u8; 63]) = RUST_LOGO;
c64::DEFAULT_SPRITE_PTR[0].write_volatile(SpriteMove::SPRITE_PTR);
c64::vic2().sprite_expand_x.write(Sprites::SPRITE0);
c64::vic2().sprite_expand_y.write(Sprites::SPRITE0);
c64::vic2().sprite_enable.write(Sprites::SPRITE0);
}
c64::vic2().set_sprite_color(0, GREEN);
}
fn update(&mut self) {
static XSINE: [u8; 256] = mos_hardware::make_sine(1, 0);
static YSINE: [u8; 256] = mos_hardware::make_sine(4, 70);
let x = XSINE[self.counter_x as usize];
let y = YSINE[self.counter_y as usize];
let (offset, msb) = match x > SpriteMove::MSB_THRESHOLD {
true => (SpriteMove::OFFSET.wrapping_sub(255), Sprites::SPRITE0),
false => (SpriteMove::OFFSET, Sprites::empty()),
};
unsafe {
c64::vic2()
.sprite_positions_most_significant_bit_of_x
.write(msb);
}
c64::vic2().set_sprite_pos(0, x + offset, y);
self.counter_x += 2;
self.counter_y += 1;
}
}
static mut SCROLL: SmoothScroll = SmoothScroll::new();
static mut SPRITE_MOVE: SpriteMove = SpriteMove::new();
struct SidFile;
impl SidTune for SidFile {
const BYTES: &'static [u8] = core::include_bytes!("../assets/last_hero.sid");
}
static MUSIC: SidFile = SidFile;
#[no_mangle]
pub extern "C" fn called_every_frame() {
let mut cnt: u8 = 0;
unsafe {
c64::vic2().border_color.write(vic2::RED);
SPRITE_MOVE.update();
c64::vic2().border_color.write(vic2::LIGHT_GREEN);
cnt += 2;
if cnt % 2 == 0 {
SCROLL.update();
}
c64::vic2().border_color.write(vic2::BLACK);
}
MUSIC.play(); }
#[start]
fn _main(_argc: isize, _argv: *const *const u8) -> isize {
c64::clear_screen();
c64::set_lower_case();
unsafe {
SCROLL.init();
SPRITE_MOVE.init();
MUSIC.to_memory();
}
MUSIC.init(0);
c64::hardware_raster_irq(20);
loop {} }
const RUST_LOGO: [u8; 63] = [
0, 90, 0, 1, 255, 128, 7, 239, 224, 15, 24, 240, 28, 0, 56, 63, 255, 28, 127, 255, 158, 127,
255, 222, 235, 195, 215, 115, 255, 142, 227, 255, 135, 99, 199, 142, 247, 195, 223, 127, 243,
254, 127, 241, 254, 62, 0, 60, 29, 0, 184, 15, 129, 240, 7, 255, 224, 1, 255, 128, 0, 90, 0,
];
#[panic_handler]
fn panic(_: &PanicInfo) -> ! {
loop {
unsafe {
c64::vic2().border_color.write(RED);
c64::vic2().border_color.write(BLACK);
}
}
}