2024-03-03 11:48:07 +05:30
|
|
|
use std::fs::File;
|
|
|
|
use std::io::Read;
|
2024-03-03 12:53:33 +05:30
|
|
|
use std::sync::{Arc, Mutex, MutexGuard};
|
2024-03-03 21:50:56 +05:30
|
|
|
use std::sync::mpsc::Receiver;
|
2024-03-03 11:48:07 +05:30
|
|
|
use std::thread;
|
|
|
|
use std::time::Duration;
|
2024-02-29 11:55:14 +05:30
|
|
|
use log::LevelFilter;
|
2024-03-03 11:48:07 +05:30
|
|
|
use sdl2::audio::{AudioQueue, AudioSpecDesired};
|
|
|
|
use sdl2::event::Event;
|
|
|
|
use sdl2::EventPump;
|
|
|
|
use sdl2::keyboard::Keycode;
|
2024-03-03 12:53:33 +05:30
|
|
|
use sdl2::pixels::{Color, PixelFormatEnum};
|
|
|
|
use sdl2::render::{BlendMode, TextureAccess, WindowCanvas};
|
2024-02-29 11:55:14 +05:30
|
|
|
use simple_logger::SimpleLogger;
|
2024-03-02 13:00:57 +05:30
|
|
|
use device::timer::Timer;
|
|
|
|
use crate::device::Device;
|
2024-03-03 11:48:07 +05:30
|
|
|
use crate::kb_map::get_key_index;
|
2024-03-03 21:50:56 +05:30
|
|
|
use crate::sdl_graphics_adapter::SdlGraphicsAdapter;
|
2024-02-29 11:55:14 +05:30
|
|
|
|
|
|
|
mod args;
|
|
|
|
mod device;
|
2024-03-03 11:48:07 +05:30
|
|
|
mod kb_map;
|
2024-03-03 21:50:56 +05:30
|
|
|
mod sdl_graphics_adapter;
|
2024-02-29 11:55:14 +05:30
|
|
|
|
|
|
|
fn main() {
|
|
|
|
SimpleLogger::new().with_level(LevelFilter::Info).env().init().unwrap();
|
|
|
|
log::info!("Started emulator");
|
2024-03-02 13:00:57 +05:30
|
|
|
|
|
|
|
let mut timer = Timer::new();
|
|
|
|
timer.start();
|
|
|
|
|
2024-03-03 21:50:56 +05:30
|
|
|
let frame_buffer_for_display = get_frame_buffer();
|
|
|
|
let frame_buffer_for_device = Arc::clone(&frame_buffer_for_display);
|
2024-03-02 13:00:57 +05:30
|
|
|
|
2024-03-03 21:50:56 +05:30
|
|
|
let (termination_signal_sender, termination_signal_sender_receiver) = std::sync::mpsc::channel();
|
2024-03-03 11:48:07 +05:30
|
|
|
|
2024-03-03 14:12:54 +05:30
|
|
|
let compute_handle = thread::Builder::new().name("Compute".to_string()).spawn(move || {
|
2024-03-03 21:50:56 +05:30
|
|
|
do_device_loop(timer, frame_buffer_for_device, termination_signal_sender_receiver);
|
2024-03-03 14:12:54 +05:30
|
|
|
}).expect("Failed to launch thread");
|
2024-03-03 11:48:07 +05:30
|
|
|
|
2024-03-03 12:53:33 +05:30
|
|
|
let (mut canvas, mut event_pump) = initiate_sdl(8f32);
|
2024-03-03 21:50:56 +05:30
|
|
|
|
|
|
|
let mut sdl_graphics_adapter = SdlGraphicsAdapter::new();
|
2024-03-03 11:48:07 +05:30
|
|
|
|
|
|
|
canvas.set_draw_color(Color::BLACK);
|
|
|
|
canvas.clear();
|
2024-03-03 21:50:56 +05:30
|
|
|
|
2024-03-03 11:48:07 +05:30
|
|
|
'running: loop {
|
|
|
|
for event in event_pump.poll_iter() {
|
|
|
|
match event {
|
|
|
|
Event::Quit { .. } |
|
|
|
|
Event::KeyDown { keycode: Some(Keycode::Escape), .. } => {
|
2024-03-03 21:50:56 +05:30
|
|
|
termination_signal_sender.send(()).expect("Could not send");
|
2024-03-03 11:48:07 +05:30
|
|
|
break 'running;
|
|
|
|
}
|
|
|
|
Event::KeyDown { keycode: Some(x), repeat: false, .. } => {
|
|
|
|
if let Some(key_val) = get_key_index(x) {
|
|
|
|
log::info!("Key+ {}",key_val)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Event::KeyUp { keycode: Some(x), repeat: false, .. } => {
|
|
|
|
if let Some(key_val) = get_key_index(x) {
|
|
|
|
log::info!("Key- {}",key_val)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// The rest of the game loop goes here...
|
|
|
|
{
|
2024-03-03 14:12:54 +05:30
|
|
|
let lock = frame_buffer_for_display.lock().expect("Failed to get Display");
|
2024-03-03 21:50:56 +05:30
|
|
|
sdl_graphics_adapter.draw_screen(lock, &mut canvas);
|
2024-03-03 11:48:07 +05:30
|
|
|
}
|
|
|
|
canvas.present();
|
|
|
|
|
|
|
|
// 60fps - small offset to consider for cpu cycle time
|
2024-03-03 21:50:56 +05:30
|
|
|
thread::sleep(Duration::new(0, 1_000_000_000u32 / 60 ));
|
2024-03-03 11:48:07 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
compute_handle.join().unwrap();
|
|
|
|
}
|
|
|
|
|
2024-03-03 21:50:56 +05:30
|
|
|
fn do_device_loop(mut timer: Timer, frame_buffer: Arc<Mutex<Box<[u8; 2048]>>>, receiver: Receiver<()>) {
|
|
|
|
let mut device = Device::new(timer, frame_buffer);
|
|
|
|
device.set_default_font();
|
|
|
|
{
|
|
|
|
let rom = load_rom();
|
|
|
|
device.load_rom(&rom);
|
|
|
|
}
|
|
|
|
|
|
|
|
loop {
|
|
|
|
let val = receiver.try_recv();
|
|
|
|
if let Ok(()) = val {
|
|
|
|
break;
|
|
|
|
} else if let Err(std::sync::mpsc::TryRecvError::Disconnected) = val {
|
|
|
|
panic!("Disconnected");
|
|
|
|
}
|
|
|
|
device.cycle();
|
|
|
|
// Put a bit of delay to slow down execution
|
|
|
|
thread::sleep(Duration::from_nanos(500))
|
2024-03-03 12:53:33 +05:30
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-03-03 21:50:56 +05:30
|
|
|
|
2024-03-03 11:48:07 +05:30
|
|
|
fn get_frame_buffer() -> Arc<Mutex<Box<[u8; 2048]>>> {
|
|
|
|
Arc::new(Mutex::new(vec![0u8; Device::FRAME_BUFFER_SIZE].into_boxed_slice().try_into().unwrap()))
|
|
|
|
}
|
|
|
|
|
2024-03-03 14:12:54 +05:30
|
|
|
const ROM_SIZE: usize = 4096 - 0x200;
|
|
|
|
|
|
|
|
fn load_rom() -> [u8; ROM_SIZE] {
|
|
|
|
let mut rom_slice = [0u8; ROM_SIZE];
|
2024-03-03 11:48:07 +05:30
|
|
|
let mut file = File::open("roms/ibm_logo.ch8").expect("could not open");
|
|
|
|
file.read(&mut rom_slice).expect("Unwrap");
|
|
|
|
rom_slice
|
|
|
|
}
|
|
|
|
|
2024-03-03 14:12:54 +05:30
|
|
|
fn initiate_sdl(draw_scale: f32) -> (WindowCanvas, EventPump) {
|
2024-03-03 11:48:07 +05:30
|
|
|
let sdl_context = sdl2::init().unwrap();
|
|
|
|
let video_subsystem = sdl_context.video().unwrap();
|
|
|
|
// let audio_subsystem = sdl_context.audio().unwrap();
|
|
|
|
// let wanted_spec = AudioSpecDesired {
|
|
|
|
// channels: Some(1),
|
|
|
|
// samples: Some(256),
|
|
|
|
// freq: Some(15360),
|
|
|
|
// };
|
|
|
|
// let audio_queue = audio_subsystem.open_queue::<u8, _>(None, &wanted_spec).unwrap();
|
|
|
|
// audio_queue.resume();
|
|
|
|
let window_width = (Device::FRAME_BUFFER_WIDTH as f32 * draw_scale) as u32;
|
|
|
|
let window_height = (Device::FRAME_BUFFER_HEIGHT as f32 * draw_scale) as u32;
|
|
|
|
|
2024-03-03 14:12:54 +05:30
|
|
|
let window = video_subsystem.window("porcel8", window_width, window_height)
|
2024-03-03 11:48:07 +05:30
|
|
|
.position_centered()
|
|
|
|
.build()
|
|
|
|
.unwrap();
|
|
|
|
let mut canvas = window.into_canvas().build().unwrap();
|
|
|
|
|
|
|
|
canvas.set_scale(draw_scale, draw_scale).expect("Setting scale");
|
|
|
|
|
|
|
|
canvas.set_blend_mode(BlendMode::None);
|
|
|
|
canvas.clear();
|
|
|
|
canvas.present();
|
|
|
|
let event_pump = sdl_context.event_pump().unwrap();
|
|
|
|
(canvas, event_pump
|
|
|
|
// , audio_queue
|
|
|
|
)
|
2024-02-29 11:55:14 +05:30
|
|
|
}
|
2024-03-02 13:00:57 +05:30
|
|
|
|
|
|
|
|
|
|
|
|