diff --git a/src/emu/audio.rs b/src/emu/audio.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/emu/cpu.rs b/src/emu/cpu.rs index 69d7274..00450fe 100644 --- a/src/emu/cpu.rs +++ b/src/emu/cpu.rs @@ -40,19 +40,20 @@ impl<'a> Cpu<'a> { } pub fn cycle(&self) -> EmulatorResult<()> { + + let mut program_counter = self.get_pc(); for _i in 0..65536 { - let address_to_execute = self.get_pc(); //execute p1 - self.copy_u24(address_to_execute)?; + self.copy_u24(program_counter)?; //execute p2 - let new_pc_location = address_to_execute + 2 * (Self::PC_LEN as u32); + let new_pc_location = program_counter + 2 * (Self::PC_LEN as u32); - let new_pc = self.memory.try_get_u24(new_pc_location)?; - - self.set_pc(new_pc); + program_counter = self.memory.try_get_u24(new_pc_location)?; } - log::debug!("Finished internal loop"); + + // self.set_pc(program_counter); + log::trace!("Finished internal loop"); self.graphics_processor.draw()?; // TODO send audio Ok(()) @@ -65,20 +66,6 @@ impl<'a> Cpu<'a> { self.memory.try_set_byte(bloc, self.memory.try_get_byte(aloc)?) } - - fn fetch_triplet(&self, address: u32) -> EmulatorResult<[u8; 3]> { - let first_byte = self.memory.try_get_byte(address)?; - let second_byte = self.memory.try_get_byte(address + 1)?; - let third_byte = self.memory.try_get_byte(address + 2)?; - let num = [first_byte, second_byte, third_byte]; - Ok(num) - } - fn set_triplet(&self, address: u32, val: &[u8; 3]) -> EmulatorResult<()> { - self.memory.try_set_byte(address, val[0])?; - self.memory.try_set_byte(address + 1, val[1])?; - self.memory.try_set_byte(address + 2, val[2])?; - Ok(()) - } } diff --git a/src/emu/graphics.rs b/src/emu/graphics.rs index 330dec7..5d1d720 100644 --- a/src/emu/graphics.rs +++ b/src/emu/graphics.rs @@ -37,7 +37,7 @@ impl<'a> GraphicsProcessor<'a> { let fb_base_register = (self.ram.try_get_byte(5)? as u32) << 16; let mut fb = self.frame_buffer.borrow_mut(); - self.ram.get_block(fb_base_register, fb.as_mut())?; + self.ram.try_copy_block(fb_base_register, fb.as_mut())?; Ok(()) } fn set_framebuffer(&self, memory_slice: &[u8; DEVICE_FRAMEBUFFER_SIZE]) { diff --git a/src/emu/memory.rs b/src/emu/memory.rs index f3e840f..8d36f24 100644 --- a/src/emu/memory.rs +++ b/src/emu/memory.rs @@ -13,6 +13,7 @@ pub trait Memory { fn try_get_byte(&self, address: u32) -> EmulatorResult; /// Set the value at the 24bit address fn try_set_byte(&self, address: u32, value: u8) -> EmulatorResult<()>; + fn try_set_u16(&self, address: u32, value: u16) -> EmulatorResult<()>; } #[derive(Clone, Debug)] @@ -50,7 +51,8 @@ impl RamMemory { Ok(read_big_endian_u24(a.try_into()?)) } - pub fn get_block(&self, address: u32, output: &mut [u8]) -> EmulatorResult<()> { + /// write a block of memory into an output slice + pub fn try_copy_block(&self, address: u32, output: &mut [u8]) -> EmulatorResult<()> { let address = address as usize; let data = self.data.borrow(); let data_requested_slice = data.get(address..address + output.len()).ok_or(EmulatorError::UnreachableMemory(RAM, address as u32))?; @@ -65,17 +67,17 @@ impl RamMemory { self.data.borrow_mut() } /// set keyboard bits - pub fn set_keyboard(&self,keyboard_bits: u16) { + pub fn set_u16(&self, address: u32, keyboard_bits: u16) { let mut keyboard_slice_ref = self.data.borrow_mut(); let keyboard_slice = keyboard_slice_ref.get_mut(0..2).unwrap(); - write_big_endian_u16(keyboard_bits,keyboard_slice.try_into().unwrap()); + write_big_endian_u16(keyboard_bits, keyboard_slice.try_into().unwrap()); } } impl Memory for RamMemory { fn try_get_byte(&self, address: u32) -> EmulatorResult { log::trace!("Fetch RAM memory at address {}",address); - let mut data = self.data.borrow_mut(); + let data = self.data.borrow(); let x = *data.get(address as usize).ok_or(EmulatorError::UnreachableMemory(RAM, address))?; Ok(x) } @@ -88,6 +90,15 @@ impl Memory for RamMemory { data[address as usize] = value; Ok(()) } + + fn try_set_u16(&self, address: u32, value: u16) -> EmulatorResult<()> { + let address = address as usize; + let mut data_ref = self.data.borrow_mut(); + let data = data_ref.get_mut(address..(address + 2)).ok_or(EmulatorError::UnreachableMemory(RAM, address as u32))?; + + write_big_endian_u16(value, data.try_into()?); + Ok(()) + } } diff --git a/src/emu/mod.rs b/src/emu/mod.rs index b40a4fb..7c72be7 100644 --- a/src/emu/mod.rs +++ b/src/emu/mod.rs @@ -1,3 +1,5 @@ pub mod cpu; pub mod memory; -pub mod graphics; \ No newline at end of file +pub mod graphics; +pub mod audio; +pub mod keyboard; \ No newline at end of file diff --git a/src/graphics/color.rs b/src/graphics/color.rs index a5db837..f66ac2b 100644 --- a/src/graphics/color.rs +++ b/src/graphics/color.rs @@ -48,6 +48,16 @@ impl Color { let b = gb_byte_remainder % Self::GREEN_MULT; (r * Self::COLOR_FACTOR_8_BIT, g * Self::COLOR_FACTOR_8_BIT, b * Self::COLOR_FACTOR_8_BIT) } + + pub fn to_rgb_555(&self)->u16{ + let r = (self.0 / Self::RED_MULT) as u16; + let gb_byte_remainder = self.0 % Self::RED_MULT; + let g = (gb_byte_remainder / Self::GREEN_MULT) as u16; + let b = gb_byte_remainder % Self::GREEN_MULT; + + (r*25)<<10 + (g*25)<<5 + b + } + } diff --git a/src/graphics/graphics_adapter.rs b/src/graphics/graphics_adapter.rs index b7696e6..8d26182 100644 --- a/src/graphics/graphics_adapter.rs +++ b/src/graphics/graphics_adapter.rs @@ -1,7 +1,10 @@ +use std::cell::Ref; use std::fmt::{Debug, Formatter}; +use std::mem::size_of; +use sdl2::pixels::PixelFormatEnum; use sdl2::rect::Rect; -use sdl2::render::WindowCanvas; -use crate::emu::graphics::GraphicsProcessor; +use sdl2::render::{TextureAccess, WindowCanvas}; +use crate::emu::graphics::{DEVICE_FRAMEBUFFER_SIZE, GraphicsProcessor}; use crate::graphics::color::Color; use crate::misc::error::EmulatorError; use crate::misc::result::EmulatorResult; @@ -9,6 +12,7 @@ use crate::misc::result::EmulatorResult; #[derive(Clone)] pub struct SDLGraphicsAdapter<'a> { + color_fb: Box<[u8; DEVICE_FRAMEBUFFER_SIZE * 3]>, graphics_processor: &'a GraphicsProcessor<'a>, } @@ -20,33 +24,36 @@ impl<'a> Debug for SDLGraphicsAdapter<'a> { impl<'a> SDLGraphicsAdapter<'a> { pub fn new(graphics_processor: &'a GraphicsProcessor) -> SDLGraphicsAdapter<'a> { + let color_fb_vec = vec![0u8; DEVICE_FRAMEBUFFER_SIZE * 3].into_boxed_slice().try_into().expect("???"); SDLGraphicsAdapter { - graphics_processor + color_fb: color_fb_vec, + graphics_processor, } } - pub fn draw(&self, canvas: &mut WindowCanvas, draw_factor: u32) -> EmulatorResult<()> { + pub fn draw(&mut self, canvas: &mut WindowCanvas) -> EmulatorResult<()> { let fb = self.graphics_processor.get_framebuffer(); + self.fill_my_texture(fb); + + + let texture_creator = canvas.texture_creator(); + + let mut texture = texture_creator.create_texture(PixelFormatEnum::RGB24, TextureAccess::Streaming, 256, 256).expect("Failed to make texture"); + texture.with_lock(None, |f, _i| { + f.copy_from_slice(self.color_fb.as_ref()) + }).expect("TODO: panic message"); + canvas.copy(&texture, None, None).expect("Failed to write texture"); - let xyc = fb.iter().enumerate().map(|(i, e)| { - let i = i as u32; - let y_coord = (i & 0xff00) >> 8; - let x_coord = i & 0x00ff; - let color = Color::new(*e); - (x_coord, y_coord, color) - }); - for (x, y, c) in xyc { - canvas.set_draw_color(c.get_rgb()); - let coordinates = (x as i32, y as i32); - let draw_result = Self::draw_scaled_point(canvas, coordinates, draw_factor); - draw_result?; - } Ok(()) } - - fn draw_scaled_point(canvas: &mut WindowCanvas, coordinates: (i32, i32), draw_factor: u32) -> Result<(), EmulatorError> { - canvas - .fill_rect(Rect::new(coordinates.0 * draw_factor as i32, coordinates.1 * draw_factor as i32, draw_factor, draw_factor)) - .map_err(|str| EmulatorError::OtherError(str)) + fn fill_my_texture(&mut self, dev_fb_ref: Ref>) { + for (i, e) in dev_fb_ref.iter().enumerate() { + let color = Color::new(*e).get_rgb(); + self.color_fb[3 * i] = color.0; + self.color_fb[3 * i + 1] = color.1; + self.color_fb[3 * i + 2] = color.2; + } } } + + diff --git a/src/main.rs b/src/main.rs index f19bd7b..356e9c8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,11 +5,12 @@ use sdl2::event::Event; use sdl2::EventPump; use sdl2::keyboard::Keycode; use sdl2::pixels::Color; -use sdl2::render::WindowCanvas; +use sdl2::render::{BlendMode, WindowCanvas}; use simple_logger::SimpleLogger; use crate::emu::cpu::Cpu; use crate::emu::graphics::GraphicsProcessor; -use crate::emu::memory::{MEM_LENGTH, RamMemory}; +use crate::emu::keyboard::Keyboard; +use crate::emu::memory::{MEM_LENGTH, Memory, RamMemory}; use crate::graphics::graphics_adapter::SDLGraphicsAdapter; use crate::misc::result::EmulatorResult; @@ -23,15 +24,20 @@ fn main() -> EmulatorResult<()> { let (file_bytes, x) = try_load_rom()?; assert!(x < MEM_LENGTH); SimpleLogger::new().env().init().unwrap(); - let ram = RamMemory::try_from(file_bytes.as_slice())?; let (mut canvas, mut event_pump, draw_factor) = initiate_sdl(); + + let ram = RamMemory::try_from(file_bytes.as_slice())?; let graphics_processor = GraphicsProcessor::try_new(&ram)?; - let sdl2_graphics_adapter = SDLGraphicsAdapter::new(&graphics_processor); + let mut keyboard = Keyboard::new(&ram); let cpu = Cpu::new(&ram, &graphics_processor); + let mut sdl2_graphics_adapter = SDLGraphicsAdapter::new(&graphics_processor); + + let mut i = 0; 'running: loop { + i = (i+1)%255; canvas.set_draw_color(Color::BLACK); canvas.clear(); for event in event_pump.poll_iter() { @@ -39,7 +45,17 @@ fn main() -> EmulatorResult<()> { Event::Quit { .. } | Event::KeyDown { keycode: Some(Keycode::Escape), .. } => { break 'running; + } + Event::KeyDown { keycode: Some(x),repeat:false,.. } => { + if let Some(key_val) = get_key_index(x) { + keyboard.key_down(key_val) + } }, + Event::KeyUp { keycode: Some(x), repeat:false, .. } => { + if let Some(key_val) = get_key_index(x) { + keyboard.key_up(key_val) + } + } event => { log::trace!("Received window event {:?}",event); @@ -47,10 +63,12 @@ fn main() -> EmulatorResult<()> { } } + keyboard.flush_keyboard()?; + // The rest of the game loop goes here... cpu.cycle()?; // draw graphics - sdl2_graphics_adapter.draw(&mut canvas, draw_factor)?; + sdl2_graphics_adapter.draw(&mut canvas)?; // TODO render audio canvas.present(); @@ -61,10 +79,33 @@ fn main() -> EmulatorResult<()> { Ok(()) } +/// get index of key pressed. 0..9+A..F provides a u8 +fn get_key_index(p0: Keycode) -> Option { + match p0 { + Keycode::Kp0 => Some(0x0), + Keycode::Kp1 => Some(0x1), + Keycode::Kp2 => Some(0x2), + Keycode::Kp3 => Some(0x3), + Keycode::Kp4 => Some(0x4), + Keycode::Kp5 => Some(0x5), + Keycode::Kp6 => Some(0x6), + Keycode::Kp7 => Some(0x7), + Keycode::Kp8 => Some(0x8), + Keycode::Kp9 => Some(0x9), + Keycode::A => Some(0xA), + Keycode::B => Some(0xB), + Keycode::C => Some(0xC), + Keycode::D => Some(0xD), + Keycode::E => Some(0xE), + Keycode::F => Some(0xF), + _ => None + } +} + fn try_load_rom() -> EmulatorResult<(Vec, usize)> { let mut file_bytes = vec![0u8; MEM_LENGTH]; - let mut file_handle = File::open("rom.BytePusher")?; + let mut file_handle = File::open("roms/Keyboard Test(1).BytePusher")?; let x = file_handle.read(&mut file_bytes)?; Ok((file_bytes, x)) @@ -83,9 +124,13 @@ fn initiate_sdl() -> (WindowCanvas, EventPump, u32) { .unwrap(); let mut canvas = window.into_canvas().build().unwrap(); - canvas.set_draw_color(Color::RGB(0, 255, 255)); + canvas.set_draw_color(Color::RGB(0x10, 0x10, 0x10)); + canvas.set_integer_scale(true).expect("Setting int scale"); + + canvas.set_scale(DRAW_FACTOR as f32,DRAW_FACTOR as f32).expect("Setting scale"); canvas.clear(); + canvas.set_blend_mode(BlendMode::None); canvas.present(); - let mut event_pump = sdl_context.event_pump().unwrap(); + let event_pump = sdl_context.event_pump().unwrap(); (canvas, event_pump, DRAW_FACTOR) } diff --git a/src/misc/endian.rs b/src/misc/endian.rs index 1d037f6..327283c 100644 --- a/src/misc/endian.rs +++ b/src/misc/endian.rs @@ -14,4 +14,4 @@ pub fn write_big_endian_u24(input: u32, output_slice: &mut [u8; 3]) { pub fn write_big_endian_u16(input: u16, output_slice: &mut [u8; 2]) { BigEndian::write_u16(output_slice, input); -} \ No newline at end of file +}