use bitflags::bitflags;
use core::mem::size_of;
use static_assertions::const_assert;
use volatile_register::{RO, RW};
pub const BLACK: u8 = 0;
pub const WHITE: u8 = 1;
pub const RED: u8 = 2;
pub const CYAN: u8 = 3;
pub const PURPLE: u8 = 4;
pub const GREEN: u8 = 5;
pub const BLUE: u8 = 6;
pub const YELLOW: u8 = 7;
pub const ORANGE: u8 = 8;
pub const BROWN: u8 = 9;
pub const LIGHT_RED: u8 = 10;
pub const GRAY1: u8 = 11;
pub const GRAY2: u8 = 12;
pub const LIGHT_GREEN: u8 = 13;
pub const LIGHT_BLUE: u8 = 14;
pub const GRAY3: u8 = 15;
bitflags! {
pub struct Sprites: u8 {
const SPRITE0 = 0b00000001;
const SPRITE1 = 0b00000010;
const SPRITE2 = 0b00000100;
const SPRITE3 = 0b00001000;
const SPRITE4 = 0b00010000;
const SPRITE5 = 0b00100000;
const SPRITE6 = 0b01000000;
const SPRITE7 = 0b10000000;
}
}
impl Sprites {
pub const fn new(index: u8) -> Self {
assert!(index < 8);
match index {
0 => Self::SPRITE0,
1 => Self::SPRITE1,
2 => Self::SPRITE2,
3 => Self::SPRITE3,
4 => Self::SPRITE4,
5 => Self::SPRITE5,
6 => Self::SPRITE6,
7 => Self::SPRITE7,
_ => panic!(),
}
}
}
bitflags! {
pub struct ControlYFlags: u8 {
const YSCROLL = 0b0000_0111;
const ROW_SELECT = 0b0000_1000;
const BLANK_SCREEN = 0b0001_0000;
const BITMAP_MODE = 0b0010_0000;
const EXTENDED_COLOR_MODE = 0b0100_0000;
const RASTER_COMPARE = 0b1000_0000;
}
}
bitflags! {
pub struct ControlXFlags: u8 {
const XSCROLL = 0b0000_0111;
const COLUMN_SELECT = 0b0000_1000;
const MULTICOLOR = 0b0001_0000;
const ALWAYS_ZERO = 0b0010_0000;
const UNUSED = 0b1100_0000;
}
}
bitflags! {
pub struct InterruptFlags: u8 {
const RASTER_COMPARE_IRQ = 0b00000001;
const SPRITE_BACKGROUND_COLLISION = 0b00000010;
const SPRITE_SPRITE_COLLISION = 0b00000100;
const LIGHPEN_TRIGGERED = 0b00001000;
const ANY_IRQ = 0b10000000;
}
}
bitflags! {
pub struct IRQEnableFlags: u8 {
const RASTER_COMPARE = 0b0000_0001; const SPRITE_BACKGROUND_COLLISION = 0b0000_0010; const ENSPRITE_SPRITE_COLLISION = 0b0000_0100; const LIGHT_PEN = 0b0000_1000; }
}
bitflags! {
pub struct CharsetBank: u8 {
const AT_0000 = 0b0000_0000;
const AT_0800 = 0b0000_0010;
const AT_1000 = 0b0000_0100;
const AT_1800 = 0b0000_0110;
const AT_2000 = 0b0000_1000;
const AT_2800 = 0b0000_1010;
const AT_3000 = 0b0000_1100;
const AT_3800 = 0b0000_1110;
const DEFAULT = Self::AT_1000.bits;
}
}
impl CharsetBank {
pub const fn from(charset: u16) -> Self {
let bank = ((charset >> 10) & 0x0e) as u8;
Self::from_bits(bank).unwrap()
}
}
bitflags! {
pub struct ScreenBank: u8 {
const AT_0000 = 0b0000_0000;
const AT_0400 = 0b0001_0000;
const AT_0800 = 0b0010_0000;
const AT_0C00 = 0b0011_0000;
const AT_1000 = 0b0100_0000;
const AT_1400 = 0b0101_0000;
const AT_1800 = 0b0110_0000;
const AT_1C00 = 0b0111_0000;
const AT_2000 = 0b1000_0000;
const AT_2400 = 0b1001_0000;
const AT_2800 = 0b1010_0000;
const AT_2C00 = 0b1011_0000;
const AT_3000 = 0b1100_0000;
const AT_3400 = 0b1101_0000;
const AT_3800 = 0b1110_0000;
const AT_3C00 = 0b1111_0000;
const DEFAULT = Self::AT_0800.bits;
}
}
impl ScreenBank {
pub const fn from_address(screen: u16) -> Self {
let bank = (screen >> 6) as u8;
Self::from_bits(bank).unwrap()
}
}
pub struct XYcoordinate {
pub x: RW<u8>,
pub y: RW<u8>,
}
#[repr(C, packed)]
pub struct MOSVideoInterfaceControllerII {
pub sprite_positions: [XYcoordinate; 8],
pub sprite_positions_most_significant_bit_of_x: RW<Sprites>,
pub control_y: RW<ControlYFlags>,
pub raster_counter: RW<u8>,
pub lightpen_x: RW<u8>,
pub lightpen_y: RW<u8>,
pub sprite_enable: RW<Sprites>,
pub control_x: RW<ControlXFlags>,
pub sprite_expand_y: RW<Sprites>,
pub screen_and_charset_bank: RW<u8>,
pub irq_status: RW<InterruptFlags>,
pub irq_enable: RW<IRQEnableFlags>,
pub sprite_background_priority: RW<Sprites>,
pub sprite_multicolor_mode: RW<Sprites>,
pub sprite_expand_x: RW<Sprites>,
pub sprite_sprite_collision: RO<Sprites>,
pub sprite_background_collision: RO<Sprites>,
pub border_color: RW<u8>,
pub background_color0: RW<u8>,
pub background_color1: RW<u8>,
pub background_color2: RW<u8>,
pub background_color3: RW<u8>,
pub sprite_multicolor0: RW<u8>,
pub sprite_multicolor1: RW<u8>,
pub sprite_colors: [RW<u8>; 8],
}
const_assert!(size_of::<MOSVideoInterfaceControllerII>() == 0x2f);
impl MOSVideoInterfaceControllerII {
pub fn set_sprite_pos(&self, index: u8, xpos: u8, ypos: u8) {
unsafe {
self.sprite_positions[index as usize].x.write(xpos);
self.sprite_positions[index as usize].y.write(ypos);
}
}
pub fn set_sprite_color(&self, index: u8, color: u8) {
unsafe {
self.sprite_colors[index as usize].write(color);
}
}
}
pub const fn to_sprite_pointer(address: u16) -> u8 {
assert!(address % 64 == 0);
assert!(address / 64 < 256);
(address / 64) as u8
}