158 lines
5.7 KiB
Rust
158 lines
5.7 KiB
Rust
pub mod cpu;
|
|
pub mod opcodes;
|
|
|
|
#[macro_use]
|
|
extern crate lazy_static;
|
|
|
|
#[macro_use]
|
|
extern crate bitflags;
|
|
|
|
use cpu::Mem;
|
|
use cpu::CPU;
|
|
|
|
use sdl2::event::Event;
|
|
use sdl2::keyboard::Keycode;
|
|
use sdl2::pixels::Color;
|
|
use sdl2::pixels::PixelFormatEnum;
|
|
use sdl2::EventPump;
|
|
|
|
use rand::Rng;
|
|
|
|
fn main() {
|
|
let game_code = vec![
|
|
0x20, 0x06, 0x06, 0x20, 0x38, 0x06, 0x20, 0x0d, 0x06, 0x20, 0x2a, 0x06, 0x60, 0xa9, 0x02,
|
|
0x85, 0x02, 0xa9, 0x04, 0x85, 0x03, 0xa9, 0x11, 0x85, 0x10, 0xa9, 0x10, 0x85, 0x12, 0xa9,
|
|
0x0f, 0x85, 0x14, 0xa9, 0x04, 0x85, 0x11, 0x85, 0x13, 0x85, 0x15, 0x60, 0xa5, 0xfe, 0x85,
|
|
0x00, 0xa5, 0xfe, 0x29, 0x03, 0x18, 0x69, 0x02, 0x85, 0x01, 0x60, 0x20, 0x4d, 0x06, 0x20,
|
|
0x8d, 0x06, 0x20, 0xc3, 0x06, 0x20, 0x19, 0x07, 0x20, 0x20, 0x07, 0x20, 0x2d, 0x07, 0x4c,
|
|
0x38, 0x06, 0xa5, 0xff, 0xc9, 0x77, 0xf0, 0x0d, 0xc9, 0x64, 0xf0, 0x14, 0xc9, 0x73, 0xf0,
|
|
0x1b, 0xc9, 0x61, 0xf0, 0x22, 0x60, 0xa9, 0x04, 0x24, 0x02, 0xd0, 0x26, 0xa9, 0x01, 0x85,
|
|
0x02, 0x60, 0xa9, 0x08, 0x24, 0x02, 0xd0, 0x1b, 0xa9, 0x02, 0x85, 0x02, 0x60, 0xa9, 0x01,
|
|
0x24, 0x02, 0xd0, 0x10, 0xa9, 0x04, 0x85, 0x02, 0x60, 0xa9, 0x02, 0x24, 0x02, 0xd0, 0x05,
|
|
0xa9, 0x08, 0x85, 0x02, 0x60, 0x60, 0x20, 0x94, 0x06, 0x20, 0xa8, 0x06, 0x60, 0xa5, 0x00,
|
|
0xc5, 0x10, 0xd0, 0x0d, 0xa5, 0x01, 0xc5, 0x11, 0xd0, 0x07, 0xe6, 0x03, 0xe6, 0x03, 0x20,
|
|
0x2a, 0x06, 0x60, 0xa2, 0x02, 0xb5, 0x10, 0xc5, 0x10, 0xd0, 0x06, 0xb5, 0x11, 0xc5, 0x11,
|
|
0xf0, 0x09, 0xe8, 0xe8, 0xe4, 0x03, 0xf0, 0x06, 0x4c, 0xaa, 0x06, 0x4c, 0x35, 0x07, 0x60,
|
|
0xa6, 0x03, 0xca, 0x8a, 0xb5, 0x10, 0x95, 0x12, 0xca, 0x10, 0xf9, 0xa5, 0x02, 0x4a, 0xb0,
|
|
0x09, 0x4a, 0xb0, 0x19, 0x4a, 0xb0, 0x1f, 0x4a, 0xb0, 0x2f, 0xa5, 0x10, 0x38, 0xe9, 0x20,
|
|
0x85, 0x10, 0x90, 0x01, 0x60, 0xc6, 0x11, 0xa9, 0x01, 0xc5, 0x11, 0xf0, 0x28, 0x60, 0xe6,
|
|
0x10, 0xa9, 0x1f, 0x24, 0x10, 0xf0, 0x1f, 0x60, 0xa5, 0x10, 0x18, 0x69, 0x20, 0x85, 0x10,
|
|
0xb0, 0x01, 0x60, 0xe6, 0x11, 0xa9, 0x06, 0xc5, 0x11, 0xf0, 0x0c, 0x60, 0xc6, 0x10, 0xa5,
|
|
0x10, 0x29, 0x1f, 0xc9, 0x1f, 0xf0, 0x01, 0x60, 0x4c, 0x35, 0x07, 0xa0, 0x00, 0xa5, 0xfe,
|
|
0x91, 0x00, 0x60, 0xa6, 0x03, 0xa9, 0x00, 0x81, 0x10, 0xa2, 0x00, 0xa9, 0x01, 0x81, 0x10,
|
|
0x60, 0xa2, 0x00, 0xea, 0xea, 0xca, 0xd0, 0xfb, 0x60,
|
|
];
|
|
|
|
// init sdl2
|
|
let sdl_context = sdl2::init().unwrap();
|
|
let video_subsystem = sdl_context.video().unwrap();
|
|
let window = video_subsystem
|
|
.window("Snake game", (32.0 * 10.0) as u32, (32.0 * 10.0) as u32)
|
|
.position_centered()
|
|
.build()
|
|
.unwrap();
|
|
|
|
let mut canvas = window.into_canvas().present_vsync().build().unwrap();
|
|
let mut event_pump = sdl_context.event_pump().unwrap();
|
|
canvas.set_scale(10.0, 10.0).unwrap();
|
|
|
|
let creator = canvas.texture_creator();
|
|
let mut texture = creator
|
|
.create_texture_target(PixelFormatEnum::RGB24, 32, 32)
|
|
.unwrap();
|
|
|
|
// init cpu
|
|
let mut cpu = cpu::CPU::new();
|
|
cpu.load_sneak(game_code);
|
|
cpu.reset();
|
|
|
|
let mut screen_state = [0_u8; 32 * 3 * 32];
|
|
let mut rng = rand::thread_rng();
|
|
|
|
cpu.run_with_callback(move |cpu| {
|
|
// TODO:
|
|
// read user input and write it to mem[0xFF]
|
|
// update mem[0xFE] with new Random Number
|
|
// read mem mapped screen state
|
|
// render screen state
|
|
handle_user_input(cpu, &mut event_pump);
|
|
cpu.mem_write(0xfe, rng.gen_range(1..16));
|
|
|
|
if read_screen_state(cpu, &mut screen_state) {
|
|
texture.update(None, &screen_state, 32 * 3).unwrap();
|
|
canvas.copy(&texture, None, None).unwrap();
|
|
canvas.present();
|
|
}
|
|
|
|
::std::thread::sleep(std::time::Duration::new(0, 70_000));
|
|
});
|
|
}
|
|
|
|
fn handle_user_input(cpu: &mut CPU, event_pump: &mut EventPump) {
|
|
for event in event_pump.poll_iter() {
|
|
match event {
|
|
Event::Quit { .. }
|
|
| Event::KeyDown {
|
|
keycode: Some(Keycode::Escape),
|
|
..
|
|
} => std::process::exit(0),
|
|
Event::KeyDown {
|
|
keycode: Some(Keycode::W),
|
|
..
|
|
} => {
|
|
cpu.mem_write(0xff, 0x77);
|
|
}
|
|
Event::KeyDown {
|
|
keycode: Some(Keycode::S),
|
|
..
|
|
} => {
|
|
cpu.mem_write(0xff, 0x73);
|
|
}
|
|
Event::KeyDown {
|
|
keycode: Some(Keycode::A),
|
|
..
|
|
} => {
|
|
cpu.mem_write(0xff, 0x61);
|
|
}
|
|
Event::KeyDown {
|
|
keycode: Some(Keycode::D),
|
|
..
|
|
} => {
|
|
cpu.mem_write(0xff, 0x64);
|
|
}
|
|
_ => { /* do nothing */ }
|
|
}
|
|
}
|
|
}
|
|
|
|
fn color(byte: u8) -> Color {
|
|
match byte {
|
|
0 => sdl2::pixels::Color::BLACK,
|
|
1 => sdl2::pixels::Color::WHITE,
|
|
2 | 9 => sdl2::pixels::Color::GREY,
|
|
3 | 10 => sdl2::pixels::Color::RED,
|
|
4 | 11 => sdl2::pixels::Color::GREEN,
|
|
5 | 12 => sdl2::pixels::Color::BLUE,
|
|
6 | 13 => sdl2::pixels::Color::MAGENTA,
|
|
7 | 14 => sdl2::pixels::Color::YELLOW,
|
|
_ => sdl2::pixels::Color::CYAN,
|
|
}
|
|
}
|
|
|
|
fn read_screen_state(cpu: &CPU, frame: &mut [u8; 32 * 3 * 32]) -> bool {
|
|
let mut frame_idx = 0;
|
|
let mut update = false;
|
|
for i in 0x0200..0x600 {
|
|
let color_idx = cpu.mem_read(i as u16);
|
|
let (b1, b2, b3) = color(color_idx).rgb();
|
|
if frame[frame_idx] != b1 || frame[frame_idx + 1] != b2 || frame[frame_idx + 2] != b3 {
|
|
frame[frame_idx] = b1;
|
|
frame[frame_idx + 1] = b2;
|
|
frame[frame_idx + 2] = b3;
|
|
update = true;
|
|
}
|
|
frame_idx += 3;
|
|
}
|
|
update
|
|
}
|