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 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-02-29 11:55:14 +05:30
mod args ;
mod device ;
2024-03-03 11:48:07 +05:30
mod kb_map ;
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 11:48:07 +05:30
let frame_buffer = get_frame_buffer ( ) ;
let frame_buffer_for_display = Arc ::clone ( & frame_buffer ) ;
2024-03-02 13:00:57 +05:30
2024-03-03 14:12:54 +05:30
let ( 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 | | {
let mut device = Device ::new ( timer , frame_buffer ) ;
2024-03-03 11:48:07 +05:30
device . set_default_font ( ) ;
{
let rom = load_rom ( ) ;
device . load_rom ( & rom ) ;
}
loop {
let val = receiver . try_recv ( ) ;
2024-03-03 14:12:54 +05:30
if let Ok ( ( ) ) = val {
2024-03-03 11:48:07 +05:30
break ;
2024-03-03 14:12:54 +05:30
} else if let Err ( std ::sync ::mpsc ::TryRecvError ::Disconnected ) = val {
2024-03-03 11:48:07 +05:30
panic! ( " Disconnected " ) ;
}
device . cycle ( ) ;
2024-03-03 14:12:54 +05:30
// Put a bit of delay to slow down execution
thread ::sleep ( Duration ::from_nanos ( 500 ) )
2024-03-03 11:48:07 +05:30
}
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 ( 8 f32 ) ;
2024-03-03 14:12:54 +05:30
let mut fb_sdl = vec! [ 0 ; 3 * Device ::FRAME_BUFFER_SIZE ] ;
2024-03-03 11:48:07 +05:30
canvas . set_draw_color ( Color ::BLACK ) ;
canvas . clear ( ) ;
' running : loop {
for event in event_pump . poll_iter ( ) {
match event {
Event ::Quit { .. } |
Event ::KeyDown { keycode : Some ( Keycode ::Escape ) , .. } = > {
sender . send ( ( ) ) . expect ( " Could not send " ) ;
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 " ) ;
draw_screen ( lock , & mut canvas , & mut fb_sdl ) ;
2024-03-03 12:53:33 +05:30
// log::info!("Framebuffer status: {:?}",lock);
2024-03-03 11:48:07 +05:30
}
canvas . present ( ) ;
// 60fps - small offset to consider for cpu cycle time
std ::thread ::sleep ( Duration ::new ( 0 , 1_000_000_000 u32 / 60 - 2000_000 ) ) ;
}
compute_handle . join ( ) . unwrap ( ) ;
}
2024-03-03 12:53:33 +05:30
fn draw_screen ( frame_buffer : MutexGuard < Box < [ u8 ; 2048 ] > > , window_canvas : & mut WindowCanvas , x1 : & mut Vec < u8 > ) {
2024-03-03 14:12:54 +05:30
for ( i , pixel ) in frame_buffer . iter ( ) . enumerate ( ) {
x1 [ 3 * i ] = * pixel ;
x1 [ 3 * i + 1 ] = * pixel ;
x1 [ 3 * i + 2 ] = * pixel ;
2024-03-03 12:53:33 +05:30
}
drop ( frame_buffer ) ;
let tex_creator = window_canvas . texture_creator ( ) ;
let mut tex = tex_creator . create_texture ( PixelFormatEnum ::RGB24 , TextureAccess ::Streaming , Device ::FRAME_BUFFER_WIDTH as u32 , Device ::FRAME_BUFFER_HEIGHT as u32 ) . expect ( " Failed to create tex " ) ;
2024-03-03 14:12:54 +05:30
tex . with_lock ( None , | u , i | {
2024-03-03 12:53:33 +05:30
u . copy_from_slice ( x1 ) ;
} ) . expect ( " Unwrap tex " ) ;
2024-03-03 14:12:54 +05:30
window_canvas . copy ( & tex , None , None ) . expect ( " Failed to set texture " ) ;
2024-03-03 12:53:33 +05:30
}
2024-03-03 11:48:07 +05:30
fn get_frame_buffer ( ) -> Arc < Mutex < Box < [ u8 ; 2048 ] > > > {
Arc ::new ( Mutex ::new ( vec! [ 0 u8 ; 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 = [ 0 u8 ; 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