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 }