[ref] format and use methods to get references
Plus, add setting keyboard support
This commit is contained in:
@@ -4,49 +4,49 @@ use crate::misc::endian::{read_big_endian_u24, write_big_endian_u24};
|
||||
use crate::misc::result::EmulatorResult;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum CpuState{
|
||||
pub enum CpuState {
|
||||
Running,
|
||||
Paused
|
||||
Paused,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Cpu<'a>{
|
||||
pub memory: &'a RamMemory,
|
||||
pub graphics_processor: &'a GraphicsProcessor<'a>
|
||||
pub struct Cpu<'a> {
|
||||
memory: &'a RamMemory,
|
||||
graphics_processor: &'a GraphicsProcessor<'a>,
|
||||
}
|
||||
|
||||
impl <'a> Cpu<'a>{
|
||||
const PC_START:usize = 2;
|
||||
const PC_LEN:usize = 3;
|
||||
const PC_ZERO:[u8;3] = [0;3];
|
||||
pub fn new(memory: &'a RamMemory, graphics_processor: &'a GraphicsProcessor<'a>) ->Cpu<'a>{
|
||||
Cpu{
|
||||
impl<'a> Cpu<'a> {
|
||||
const PC_START: usize = 2;
|
||||
const PC_LEN: usize = 3;
|
||||
const PC_ZERO: [u8; 3] = [0; 3];
|
||||
pub fn new(memory: &'a RamMemory, graphics_processor: &'a GraphicsProcessor<'a>) -> Cpu<'a> {
|
||||
Cpu {
|
||||
graphics_processor,
|
||||
memory
|
||||
memory,
|
||||
}
|
||||
}
|
||||
pub fn get_pc(&self)->u32{
|
||||
let memory_slice = self.memory.data.borrow();
|
||||
let data = memory_slice.get(Self::PC_START..(Self::PC_START+Self::PC_LEN)).unwrap();
|
||||
pub fn get_pc(&self) -> u32 {
|
||||
let memory_slice = self.memory.get_data_ref();
|
||||
let data = memory_slice.get(Self::PC_START..(Self::PC_START + Self::PC_LEN)).unwrap();
|
||||
read_big_endian_u24(data.try_into().unwrap())
|
||||
}
|
||||
pub fn set_pc(&self,address:u32){
|
||||
let mut memory_slice = self.memory.data.borrow_mut();
|
||||
pub fn set_pc(&self, address: u32) {
|
||||
let mut memory_slice = self.memory.get_data_ref_mut();
|
||||
|
||||
let mut pc_big_endian_slice = Self::PC_ZERO;
|
||||
write_big_endian_u24(address,&mut pc_big_endian_slice);
|
||||
write_big_endian_u24(address, &mut pc_big_endian_slice);
|
||||
|
||||
memory_slice[Self::PC_START..(Self::PC_START + Self::PC_LEN)].copy_from_slice(&pc_big_endian_slice);
|
||||
}
|
||||
|
||||
pub fn cycle(&self)->EmulatorResult<()>{
|
||||
for _i in 0..65536{
|
||||
pub fn cycle(&self) -> EmulatorResult<()> {
|
||||
for _i in 0..65536 {
|
||||
let address_to_execute = self.get_pc();
|
||||
|
||||
//execute p1
|
||||
self.copy_u24(address_to_execute)?;
|
||||
//execute p2
|
||||
let new_pc_location = address_to_execute+2*(Self::PC_LEN as u32) ;
|
||||
let new_pc_location = address_to_execute + 2 * (Self::PC_LEN as u32);
|
||||
|
||||
let new_pc = self.memory.try_get_u24(new_pc_location)?;
|
||||
|
||||
@@ -60,20 +60,20 @@ impl <'a> Cpu<'a>{
|
||||
|
||||
fn copy_u24(&self, address_to_execute: u32) -> EmulatorResult<()> {
|
||||
let aloc = self.memory.try_get_u24(address_to_execute)?;
|
||||
let bloc = self.memory.try_get_u24(address_to_execute+Self::PC_LEN as u32)?;
|
||||
let bloc = self.memory.try_get_u24(address_to_execute + Self::PC_LEN as u32)?;
|
||||
|
||||
self.memory.try_set_byte(bloc,self.memory.try_get_byte(aloc)?)
|
||||
self.memory.try_set_byte(bloc, self.memory.try_get_byte(aloc)?)
|
||||
}
|
||||
|
||||
|
||||
fn fetch_triplet(&self, address: u32) -> EmulatorResult<[u8;3]> {
|
||||
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];
|
||||
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<()> {
|
||||
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])?;
|
||||
@@ -82,13 +82,8 @@ impl <'a> Cpu<'a>{
|
||||
}
|
||||
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod test{
|
||||
|
||||
mod test {
|
||||
#[test]
|
||||
pub fn construct(){
|
||||
|
||||
}
|
||||
|
||||
pub fn construct() {}
|
||||
}
|
@@ -14,7 +14,7 @@ pub struct GraphicsProcessor<'a> {
|
||||
}
|
||||
|
||||
/// Abstracted graphics processor. Calls `[GraphicsAdapter]` with the associated framebuffer
|
||||
impl <'a> GraphicsProcessor<'a> {
|
||||
impl<'a> GraphicsProcessor<'a> {
|
||||
pub fn try_new(ram_memory: &'a RamMemory) -> EmulatorResult<GraphicsProcessor> {
|
||||
let framebuffer = vec![0; DEVICE_FRAMEBUFFER_SIZE].into_boxed_slice()
|
||||
.try_into()
|
||||
@@ -26,11 +26,11 @@ impl <'a> GraphicsProcessor<'a> {
|
||||
frame_buffer: RefCell::new(framebuffer),
|
||||
})
|
||||
}
|
||||
/// take a copy of FB and
|
||||
pub fn draw(&self)->EmulatorResult<()>{
|
||||
self.copy_indicated_pixel_data_block()?;
|
||||
let fb_immut = self.frame_buffer.borrow();
|
||||
Ok(())
|
||||
/// Draw the pixels.
|
||||
/// Since this is a VM, we just copy and store it in a buffer.
|
||||
/// take a copy of FB and store it
|
||||
pub fn draw(&self) -> EmulatorResult<()> {
|
||||
self.copy_indicated_pixel_data_block()
|
||||
}
|
||||
|
||||
fn copy_indicated_pixel_data_block(&self) -> Result<(), EmulatorError> {
|
||||
@@ -40,16 +40,14 @@ impl <'a> GraphicsProcessor<'a> {
|
||||
self.ram.get_block(fb_base_register, fb.as_mut())?;
|
||||
Ok(())
|
||||
}
|
||||
fn set_framebuffer(&self, memory_slice: &[u8;DEVICE_FRAMEBUFFER_SIZE]) {
|
||||
fn set_framebuffer(&self, memory_slice: &[u8; DEVICE_FRAMEBUFFER_SIZE]) {
|
||||
let mut fb = self.frame_buffer.borrow_mut();
|
||||
fb.copy_from_slice(memory_slice);
|
||||
}
|
||||
pub fn get_framebuffer(&self)->Ref<Box<[u8; DEVICE_FRAMEBUFFER_SIZE]>>{
|
||||
pub fn get_framebuffer(&self) -> Ref<Box<[u8; DEVICE_FRAMEBUFFER_SIZE]>> {
|
||||
self.frame_buffer.borrow()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test{
|
||||
|
||||
}
|
||||
mod test {}
|
@@ -1,8 +1,8 @@
|
||||
use std::cell::RefCell;
|
||||
use std::cell::{Ref, RefCell, RefMut};
|
||||
|
||||
use crate::misc::emulator_error::DeviceType::RAM;
|
||||
use crate::misc::emulator_error::EmulatorError;
|
||||
use crate::misc::endian::read_big_endian_u24;
|
||||
use crate::misc::endian::{read_big_endian_u24, write_big_endian_u16};
|
||||
use crate::misc::result::EmulatorResult;
|
||||
|
||||
pub const MEM_LENGTH: usize = 2 << 23;
|
||||
@@ -17,13 +17,13 @@ pub trait Memory {
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct RamMemory {
|
||||
pub data: RefCell<Box<[u8; MEM_LENGTH]>>,
|
||||
data: RefCell<Box<[u8; MEM_LENGTH]>>,
|
||||
}
|
||||
|
||||
impl RamMemory {
|
||||
pub fn try_new() -> EmulatorResult<RamMemory> {
|
||||
let alloc_result = vec![0; MEM_LENGTH].into_boxed_slice();
|
||||
let data = alloc_result.try_into().map_err(|err|{
|
||||
let data = alloc_result.try_into().map_err(|err| {
|
||||
EmulatorError::AllocationFailure(RAM, "Allocation failed")
|
||||
})?;
|
||||
let data_refcell = RefCell::new(data);
|
||||
@@ -31,35 +31,47 @@ impl RamMemory {
|
||||
data: data_refcell
|
||||
})
|
||||
}
|
||||
pub fn try_from(existing_data:&[u8]) -> EmulatorResult<RamMemory>{
|
||||
pub fn try_from(existing_data: &[u8]) -> EmulatorResult<RamMemory> {
|
||||
let alloc_result = vec![0u8; MEM_LENGTH].into_boxed_slice();
|
||||
// get box of fixed size
|
||||
let mut fixed_size_alloc_box:Box<[u8;MEM_LENGTH]> = alloc_result.try_into().unwrap();
|
||||
let mut fixed_size_alloc_box: Box<[u8; MEM_LENGTH]> = alloc_result.try_into().unwrap();
|
||||
fixed_size_alloc_box.copy_from_slice(&existing_data);
|
||||
|
||||
Ok(RamMemory{
|
||||
Ok(RamMemory {
|
||||
data: RefCell::new(fixed_size_alloc_box)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn try_get_u24(&self,index:u32)->EmulatorResult<u32>{
|
||||
const U24_LEN:usize = 3;
|
||||
pub fn try_get_u24(&self, index: u32) -> EmulatorResult<u32> {
|
||||
const U24_LEN: usize = 3;
|
||||
let index_usize = index as usize;
|
||||
let data = self.data.borrow();
|
||||
let a = data.get(index_usize..(index_usize +U24_LEN)).ok_or(EmulatorError::UnreachableMemory(RAM, index))?;
|
||||
let a = data.get(index_usize..(index_usize + U24_LEN)).ok_or(EmulatorError::UnreachableMemory(RAM, index))?;
|
||||
Ok(read_big_endian_u24(a.try_into()?))
|
||||
}
|
||||
|
||||
pub fn get_block(&self,address:u32,output:&mut [u8])->EmulatorResult<()>{
|
||||
pub fn get_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))?;
|
||||
let data_requested_slice = data.get(address..address + output.len()).ok_or(EmulatorError::UnreachableMemory(RAM, address as u32))?;
|
||||
output.copy_from_slice(data_requested_slice);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
pub fn get_data_ref(&self) -> Ref<Box<[u8; MEM_LENGTH]>> {
|
||||
self.data.borrow()
|
||||
}
|
||||
pub fn get_data_ref_mut(&self) -> RefMut<Box<[u8; MEM_LENGTH]>> {
|
||||
self.data.borrow_mut()
|
||||
}
|
||||
/// set keyboard bits
|
||||
pub fn set_keyboard(&self,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());
|
||||
}
|
||||
}
|
||||
|
||||
impl Memory for RamMemory {
|
||||
fn try_get_byte(&self, address: u32) -> EmulatorResult<u8> {
|
||||
log::trace!("Fetch RAM memory at address {}",address);
|
||||
@@ -69,8 +81,8 @@ impl Memory for RamMemory {
|
||||
}
|
||||
|
||||
fn try_set_byte(&self, address: u32, value: u8) -> EmulatorResult<()> {
|
||||
if address>= MEM_LENGTH as u32 {
|
||||
return Err(EmulatorError::UnreachableMemory(RAM, address))
|
||||
if address >= MEM_LENGTH as u32 {
|
||||
return Err(EmulatorError::UnreachableMemory(RAM, address));
|
||||
}
|
||||
let mut data = self.data.borrow_mut();
|
||||
data[address as usize] = value;
|
||||
@@ -79,28 +91,28 @@ impl Memory for RamMemory {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests{
|
||||
mod tests {
|
||||
use crate::emu::memory::RamMemory;
|
||||
use crate::emu::memory::Memory;
|
||||
const EXAMPLE_ADDRESS:u32=0x24;
|
||||
|
||||
const EXAMPLE_ADDRESS: u32 = 0x24;
|
||||
|
||||
#[test]
|
||||
pub fn get_mem(){
|
||||
pub fn get_mem() {
|
||||
let ram_result = RamMemory::try_new();
|
||||
assert!(ram_result.is_ok())
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn get_set_memory(){
|
||||
const EXAMPLE_DATA:u8 = 0xa5;
|
||||
pub fn get_set_memory() {
|
||||
const EXAMPLE_DATA: u8 = 0xa5;
|
||||
let mut ram = RamMemory::try_new().unwrap();
|
||||
let byte_before = ram.try_get_byte(EXAMPLE_ADDRESS).unwrap();
|
||||
ram.try_set_byte(EXAMPLE_ADDRESS, EXAMPLE_DATA).unwrap();
|
||||
let byte_after = ram.try_get_byte(EXAMPLE_ADDRESS).unwrap();
|
||||
assert_eq!(0,byte_before);
|
||||
assert_eq!(EXAMPLE_DATA,byte_after);
|
||||
assert_eq!(0, byte_before);
|
||||
assert_eq!(EXAMPLE_DATA, byte_after);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -9,7 +9,7 @@ use crate::misc::result::EmulatorResult;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct SDLGraphicsAdapter<'a> {
|
||||
pub graphics_processor: &'a GraphicsProcessor<'a>,
|
||||
graphics_processor: &'a GraphicsProcessor<'a>,
|
||||
}
|
||||
|
||||
impl<'a> Debug for SDLGraphicsAdapter<'a> {
|
||||
@@ -45,7 +45,7 @@ impl<'a> SDLGraphicsAdapter<'a> {
|
||||
|
||||
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))
|
||||
.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))
|
||||
}
|
||||
}
|
||||
|
@@ -18,16 +18,16 @@ pub enum EmulatorError {
|
||||
UnreachableMemory(DeviceType, u32),
|
||||
InvalidColor(u8),
|
||||
EmulatorIOError(Error),
|
||||
OtherError(String)
|
||||
OtherError(String),
|
||||
}
|
||||
|
||||
impl From<TryFromSliceError> for EmulatorError{
|
||||
fn from(value: TryFromSliceError) -> Self {
|
||||
EmulatorError::UnreachableMemory(DeviceType::RAM,0x5a5a)
|
||||
impl From<TryFromSliceError> for EmulatorError {
|
||||
fn from(_: TryFromSliceError) -> Self {
|
||||
EmulatorError::UnreachableMemory(DeviceType::RAM, 0x5a5a)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<std::io::Error> for EmulatorError{
|
||||
impl From<std::io::Error> for EmulatorError {
|
||||
fn from(value: Error) -> Self {
|
||||
EmulatorIOError(value)
|
||||
}
|
||||
|
@@ -11,3 +11,7 @@ pub fn read_big_endian_u16(input: &[u8; 2]) -> u16 {
|
||||
pub fn write_big_endian_u24(input: u32, output_slice: &mut [u8; 3]) {
|
||||
BigEndian::write_u24(output_slice, input);
|
||||
}
|
||||
|
||||
pub fn write_big_endian_u16(input: u16, output_slice: &mut [u8; 2]) {
|
||||
BigEndian::write_u16(output_slice, input);
|
||||
}
|
Reference in New Issue
Block a user