[cln] Code cleanup
This commit is contained in:
@@ -1,6 +1,8 @@
|
|||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
|
|
||||||
#[derive(Debug,Parser)]
|
#[derive(Debug,Parser)]
|
||||||
|
#[command(version, about, long_about = "Byte Pusher Emulator")]
|
||||||
pub struct BytePusherArgs{
|
pub struct BytePusherArgs{
|
||||||
|
#[arg(short,long)]
|
||||||
|
pub file_name:Option<String>
|
||||||
}
|
}
|
@@ -3,11 +3,6 @@ use crate::emu::memory::{Memory, RamMemory};
|
|||||||
use crate::misc::endian::{read_big_endian_u24, write_big_endian_u24};
|
use crate::misc::endian::{read_big_endian_u24, write_big_endian_u24};
|
||||||
use crate::misc::result::EmulatorResult;
|
use crate::misc::result::EmulatorResult;
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum CpuState {
|
|
||||||
Running,
|
|
||||||
Paused,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Cpu<'a> {
|
pub struct Cpu<'a> {
|
||||||
@@ -18,7 +13,6 @@ pub struct Cpu<'a> {
|
|||||||
impl<'a> Cpu<'a> {
|
impl<'a> Cpu<'a> {
|
||||||
const PC_START: usize = 2;
|
const PC_START: usize = 2;
|
||||||
const PC_LEN: usize = 3;
|
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> {
|
pub fn new(memory: &'a RamMemory, graphics_processor: &'a GraphicsProcessor<'a>) -> Cpu<'a> {
|
||||||
Cpu {
|
Cpu {
|
||||||
graphics_processor,
|
graphics_processor,
|
||||||
@@ -30,14 +24,6 @@ impl<'a> Cpu<'a> {
|
|||||||
let data = memory_slice.get(Self::PC_START..(Self::PC_START + Self::PC_LEN)).unwrap();
|
let data = memory_slice.get(Self::PC_START..(Self::PC_START + Self::PC_LEN)).unwrap();
|
||||||
read_big_endian_u24(data.try_into().unwrap())
|
read_big_endian_u24(data.try_into().unwrap())
|
||||||
}
|
}
|
||||||
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);
|
|
||||||
|
|
||||||
memory_slice[Self::PC_START..(Self::PC_START + Self::PC_LEN)].copy_from_slice(&pc_big_endian_slice);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn cycle(&self) -> EmulatorResult<()> {
|
pub fn cycle(&self) -> EmulatorResult<()> {
|
||||||
|
|
||||||
@@ -52,7 +38,6 @@ impl<'a> Cpu<'a> {
|
|||||||
program_counter = self.memory.try_get_u24(new_pc_location)?;
|
program_counter = self.memory.try_get_u24(new_pc_location)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// self.set_pc(program_counter);
|
|
||||||
log::trace!("Finished internal loop");
|
log::trace!("Finished internal loop");
|
||||||
self.graphics_processor.draw()?;
|
self.graphics_processor.draw()?;
|
||||||
// TODO send audio
|
// TODO send audio
|
||||||
|
@@ -40,10 +40,6 @@ impl<'a> GraphicsProcessor<'a> {
|
|||||||
self.ram.try_copy_block(fb_base_register, fb.as_mut())?;
|
self.ram.try_copy_block(fb_base_register, fb.as_mut())?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
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()
|
self.frame_buffer.borrow()
|
||||||
}
|
}
|
||||||
|
@@ -17,12 +17,6 @@ impl<'a> Keyboard<'a>{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clear_keyboard(&mut self){
|
|
||||||
log::debug!("Keyboard clear");
|
|
||||||
self.bitflags = 0;
|
|
||||||
self.dirty = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn key_down(&mut self,x:u8){
|
pub fn key_down(&mut self,x:u8){
|
||||||
self.bitflags |= 1<<x;
|
self.bitflags |= 1<<x;
|
||||||
log::debug!("Key Down, keyboard state {}",self.bitflags);
|
log::debug!("Key Down, keyboard state {}",self.bitflags);
|
||||||
|
@@ -22,16 +22,6 @@ pub struct RamMemory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl RamMemory {
|
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| {
|
|
||||||
EmulatorError::AllocationFailure(RAM, "Allocation failed")
|
|
||||||
})?;
|
|
||||||
let data_refcell = RefCell::new(data);
|
|
||||||
Ok(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();
|
let alloc_result = vec![0u8; MEM_LENGTH].into_boxed_slice();
|
||||||
// get box of fixed size
|
// get box of fixed size
|
||||||
@@ -66,17 +56,12 @@ impl RamMemory {
|
|||||||
pub fn get_data_ref_mut(&self) -> RefMut<Box<[u8; MEM_LENGTH]>> {
|
pub fn get_data_ref_mut(&self) -> RefMut<Box<[u8; MEM_LENGTH]>> {
|
||||||
self.data.borrow_mut()
|
self.data.borrow_mut()
|
||||||
}
|
}
|
||||||
/// set keyboard bits
|
|
||||||
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());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Memory for RamMemory {
|
impl Memory for RamMemory {
|
||||||
fn try_get_byte(&self, address: u32) -> EmulatorResult<u8> {
|
fn try_get_byte(&self, address: u32) -> EmulatorResult<u8> {
|
||||||
log::trace!("Fetch RAM memory at address {}",address);
|
// log::trace!("Fetch RAM memory at address {}",address);
|
||||||
let data = self.data.borrow();
|
let data = self.data.borrow();
|
||||||
let x = *data.get(address as usize).ok_or(EmulatorError::UnreachableMemory(RAM, address))?;
|
let x = *data.get(address as usize).ok_or(EmulatorError::UnreachableMemory(RAM, address))?;
|
||||||
Ok(x)
|
Ok(x)
|
||||||
|
@@ -1,5 +1,3 @@
|
|||||||
use crate::misc::error::EmulatorError;
|
|
||||||
use crate::misc::result::EmulatorResult;
|
|
||||||
|
|
||||||
/// A Color as represented in BytePusher.
|
/// A Color as represented in BytePusher.
|
||||||
/// It is a byte that contains a packed 6 digit red, green and blue
|
/// It is a byte that contains a packed 6 digit red, green and blue
|
||||||
@@ -15,31 +13,15 @@ impl Color {
|
|||||||
/// Only first 216 color indices are used.
|
/// Only first 216 color indices are used.
|
||||||
const COLOR_MAX: u8 = 215;
|
const COLOR_MAX: u8 = 215;
|
||||||
const COLOR_FACTOR_8_BIT: u8 = 0x33;
|
const COLOR_FACTOR_8_BIT: u8 = 0x33;
|
||||||
/// This constructs a valid color from rgb triplet
|
|
||||||
pub fn from_rgb(red: u8, green: u8, blue: u8) -> Color {
|
|
||||||
let red = red / Self::COLOR_FACTOR_8_BIT;
|
|
||||||
let green = green / Self::COLOR_FACTOR_8_BIT;
|
|
||||||
let blue = blue / Self::COLOR_FACTOR_8_BIT;
|
|
||||||
Color(red * Self::RED_MULT + green * Self::GREEN_MULT + blue)
|
|
||||||
}
|
|
||||||
pub fn try_new(in_mem_color: u8) -> EmulatorResult<Color> {
|
|
||||||
if in_mem_color > Self::COLOR_MAX {
|
|
||||||
return Err(EmulatorError::InvalidColor(in_mem_color));
|
|
||||||
}
|
|
||||||
Ok(Color(in_mem_color))
|
|
||||||
}
|
|
||||||
/// wrap to black if needed
|
/// wrap to black if needed
|
||||||
pub fn new(in_mem_color: u8) -> Color {
|
pub fn new(in_mem_color: u8) -> Color {
|
||||||
if in_mem_color > Self::COLOR_MAX {
|
if in_mem_color > Self::COLOR_MAX {
|
||||||
log::trace!("Invalid color {}, using 0", in_mem_color);
|
|
||||||
Color(0)
|
Color(0)
|
||||||
} else {
|
} else {
|
||||||
Color(in_mem_color)
|
Color(in_mem_color)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn get_mem_byte(&self) -> u8 {
|
|
||||||
self.0
|
|
||||||
}
|
|
||||||
/// This fetches the rgb triplet
|
/// This fetches the rgb triplet
|
||||||
pub fn get_rgb(self) -> (u8, u8, u8) {
|
pub fn get_rgb(self) -> (u8, u8, u8) {
|
||||||
let r = self.0 / Self::RED_MULT;
|
let r = self.0 / Self::RED_MULT;
|
||||||
@@ -48,16 +30,6 @@ impl Color {
|
|||||||
let b = gb_byte_remainder % Self::GREEN_MULT;
|
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)
|
(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
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -67,31 +39,20 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
pub fn test_from_mem_zero() {
|
pub fn test_from_mem_zero() {
|
||||||
let color = Color::try_new(0).unwrap();
|
let color = Color::new(0);
|
||||||
assert_eq!((0, 0, 0), color.get_rgb())
|
assert_eq!((0, 0, 0), color.get_rgb())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
pub fn test_from_mem_invalid() {
|
pub fn test_from_mem_invalid() {
|
||||||
let color = Color::try_new(0xff);
|
let color = Color::new(0xff);
|
||||||
assert!(color.is_err())
|
assert_eq!((0,0,0),color.get_rgb())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
pub fn test_from_mem_max() {
|
pub fn test_from_mem_max() {
|
||||||
let color = Color::try_new(Color::COLOR_MAX).unwrap();
|
let color = Color::new(Color::COLOR_MAX);
|
||||||
assert_eq!((255, 255, 255), color.get_rgb())
|
assert_eq!((255, 255, 255), color.get_rgb())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
pub fn from_rgb_zero() {
|
|
||||||
let color = Color::from_rgb(0, 0, 0);
|
|
||||||
assert_eq!(0, color.get_mem_byte())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
pub fn from_rgb_max() {
|
|
||||||
let color = Color::from_rgb(255, 255, 255);
|
|
||||||
assert_eq!(Color::COLOR_MAX, color.get_mem_byte())
|
|
||||||
}
|
|
||||||
}
|
}
|
@@ -1,12 +1,9 @@
|
|||||||
use std::cell::Ref;
|
use std::cell::Ref;
|
||||||
use std::fmt::{Debug, Formatter};
|
use std::fmt::{Debug, Formatter};
|
||||||
use std::mem::size_of;
|
|
||||||
use sdl2::pixels::PixelFormatEnum;
|
use sdl2::pixels::PixelFormatEnum;
|
||||||
use sdl2::rect::Rect;
|
|
||||||
use sdl2::render::{TextureAccess, WindowCanvas};
|
use sdl2::render::{TextureAccess, WindowCanvas};
|
||||||
use crate::emu::graphics::{DEVICE_FRAMEBUFFER_SIZE, GraphicsProcessor};
|
use crate::emu::graphics::{DEVICE_FRAMEBUFFER_SIZE, GraphicsProcessor};
|
||||||
use crate::graphics::color::Color;
|
use crate::graphics::color::Color;
|
||||||
use crate::misc::error::EmulatorError;
|
|
||||||
use crate::misc::result::EmulatorResult;
|
use crate::misc::result::EmulatorResult;
|
||||||
|
|
||||||
|
|
||||||
|
44
src/main.rs
44
src/main.rs
@@ -1,16 +1,18 @@
|
|||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
use clap::Parser;
|
||||||
use sdl2::event::Event;
|
use sdl2::event::Event;
|
||||||
use sdl2::EventPump;
|
use sdl2::EventPump;
|
||||||
use sdl2::keyboard::Keycode;
|
use sdl2::keyboard::Keycode;
|
||||||
use sdl2::pixels::Color;
|
use sdl2::pixels::Color;
|
||||||
use sdl2::render::{BlendMode, WindowCanvas};
|
use sdl2::render::{BlendMode, WindowCanvas};
|
||||||
use simple_logger::SimpleLogger;
|
use simple_logger::SimpleLogger;
|
||||||
|
use crate::args::BytePusherArgs;
|
||||||
use crate::emu::cpu::Cpu;
|
use crate::emu::cpu::Cpu;
|
||||||
use crate::emu::graphics::GraphicsProcessor;
|
use crate::emu::graphics::GraphicsProcessor;
|
||||||
use crate::emu::keyboard::Keyboard;
|
use crate::emu::keyboard::Keyboard;
|
||||||
use crate::emu::memory::{MEM_LENGTH, Memory, RamMemory};
|
use crate::emu::memory::{MEM_LENGTH, RamMemory};
|
||||||
use crate::graphics::graphics_adapter::SDLGraphicsAdapter;
|
use crate::graphics::graphics_adapter::SDLGraphicsAdapter;
|
||||||
|
|
||||||
use crate::misc::result::EmulatorResult;
|
use crate::misc::result::EmulatorResult;
|
||||||
@@ -21,11 +23,14 @@ mod misc;
|
|||||||
mod graphics;
|
mod graphics;
|
||||||
|
|
||||||
fn main() -> EmulatorResult<()> {
|
fn main() -> EmulatorResult<()> {
|
||||||
let (file_bytes, x) = try_load_rom()?;
|
let BytePusherArgs { file_name } = BytePusherArgs::parse();
|
||||||
assert!(x < MEM_LENGTH);
|
|
||||||
SimpleLogger::new().env().init().unwrap();
|
SimpleLogger::new().env().init().unwrap();
|
||||||
|
|
||||||
let (mut canvas, mut event_pump, draw_factor) = initiate_sdl();
|
|
||||||
|
let (file_bytes, x) = try_load_rom(&file_name)?;
|
||||||
|
assert!(x < MEM_LENGTH);
|
||||||
|
|
||||||
|
let (mut canvas, mut event_pump) = initiate_sdl();
|
||||||
|
|
||||||
|
|
||||||
let ram = RamMemory::try_from(file_bytes.as_slice())?;
|
let ram = RamMemory::try_from(file_bytes.as_slice())?;
|
||||||
@@ -35,9 +40,7 @@ fn main() -> EmulatorResult<()> {
|
|||||||
|
|
||||||
let mut sdl2_graphics_adapter = SDLGraphicsAdapter::new(&graphics_processor);
|
let mut sdl2_graphics_adapter = SDLGraphicsAdapter::new(&graphics_processor);
|
||||||
|
|
||||||
let mut i = 0;
|
|
||||||
'running: loop {
|
'running: loop {
|
||||||
i = (i+1)%255;
|
|
||||||
canvas.set_draw_color(Color::BLACK);
|
canvas.set_draw_color(Color::BLACK);
|
||||||
canvas.clear();
|
canvas.clear();
|
||||||
for event in event_pump.poll_iter() {
|
for event in event_pump.poll_iter() {
|
||||||
@@ -46,20 +49,17 @@ fn main() -> EmulatorResult<()> {
|
|||||||
Event::KeyDown { keycode: Some(Keycode::Escape), .. } => {
|
Event::KeyDown { keycode: Some(Keycode::Escape), .. } => {
|
||||||
break 'running;
|
break 'running;
|
||||||
}
|
}
|
||||||
Event::KeyDown { keycode: Some(x),repeat:false,.. } => {
|
Event::KeyDown { keycode: Some(x), repeat: false, .. } => {
|
||||||
if let Some(key_val) = get_key_index(x) {
|
if let Some(key_val) = get_key_index(x) {
|
||||||
keyboard.key_down(key_val)
|
keyboard.key_down(key_val)
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
Event::KeyUp { keycode: Some(x), repeat:false, .. } => {
|
Event::KeyUp { keycode: Some(x), repeat: false, .. } => {
|
||||||
if let Some(key_val) = get_key_index(x) {
|
if let Some(key_val) = get_key_index(x) {
|
||||||
keyboard.key_up(key_val)
|
keyboard.key_up(key_val)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
_ => {}
|
||||||
event => {
|
|
||||||
log::trace!("Received window event {:?}",event);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,16 +102,20 @@ fn get_key_index(p0: Keycode) -> Option<u8> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn try_load_rom() -> EmulatorResult<(Vec<u8>, usize)> {
|
fn try_load_rom(file_name_option: &Option<String>) -> EmulatorResult<(Vec<u8>, usize)> {
|
||||||
let mut file_bytes = vec![0u8; MEM_LENGTH];
|
let mut file_bytes = vec![0u8; MEM_LENGTH];
|
||||||
|
|
||||||
let mut file_handle = File::open("roms/Keyboard Test(1).BytePusher")?;
|
let bytes_read = if let Some(file_name) = file_name_option{
|
||||||
let x = file_handle.read(&mut file_bytes)?;
|
let mut file_handle = File::open(file_name.as_str())?;
|
||||||
|
file_handle.read(&mut file_bytes)?
|
||||||
|
}else{
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
Ok((file_bytes, x))
|
Ok((file_bytes, bytes_read))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn initiate_sdl() -> (WindowCanvas, EventPump, u32) {
|
fn initiate_sdl() -> (WindowCanvas, EventPump) {
|
||||||
const BASE_RESOLUTION: u32 = 256;
|
const BASE_RESOLUTION: u32 = 256;
|
||||||
const DRAW_FACTOR: u32 = 4;
|
const DRAW_FACTOR: u32 = 4;
|
||||||
const WINDOW_RESOLUTION: u32 = BASE_RESOLUTION * DRAW_FACTOR;
|
const WINDOW_RESOLUTION: u32 = BASE_RESOLUTION * DRAW_FACTOR;
|
||||||
@@ -127,10 +131,10 @@ fn initiate_sdl() -> (WindowCanvas, EventPump, u32) {
|
|||||||
canvas.set_draw_color(Color::RGB(0x10, 0x10, 0x10));
|
canvas.set_draw_color(Color::RGB(0x10, 0x10, 0x10));
|
||||||
canvas.set_integer_scale(true).expect("Setting int scale");
|
canvas.set_integer_scale(true).expect("Setting int scale");
|
||||||
|
|
||||||
canvas.set_scale(DRAW_FACTOR as f32,DRAW_FACTOR as f32).expect("Setting scale");
|
canvas.set_scale(DRAW_FACTOR as f32, DRAW_FACTOR as f32).expect("Setting scale");
|
||||||
canvas.clear();
|
canvas.clear();
|
||||||
canvas.set_blend_mode(BlendMode::None);
|
canvas.set_blend_mode(BlendMode::None);
|
||||||
canvas.present();
|
canvas.present();
|
||||||
let event_pump = sdl_context.event_pump().unwrap();
|
let event_pump = sdl_context.event_pump().unwrap();
|
||||||
(canvas, event_pump, DRAW_FACTOR)
|
(canvas, event_pump)
|
||||||
}
|
}
|
||||||
|
@@ -5,9 +5,7 @@ use crate::misc::error::EmulatorError::EmulatorIOError;
|
|||||||
|
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
pub enum DeviceType {
|
pub enum DeviceType {
|
||||||
CPU,
|
|
||||||
RAM,
|
RAM,
|
||||||
KEYBOARD,
|
|
||||||
AUDIO,
|
AUDIO,
|
||||||
GRAPHICS,
|
GRAPHICS,
|
||||||
}
|
}
|
||||||
@@ -16,9 +14,7 @@ pub enum DeviceType {
|
|||||||
pub enum EmulatorError {
|
pub enum EmulatorError {
|
||||||
AllocationFailure(DeviceType, &'static str),
|
AllocationFailure(DeviceType, &'static str),
|
||||||
UnreachableMemory(DeviceType, u32),
|
UnreachableMemory(DeviceType, u32),
|
||||||
InvalidColor(u8),
|
|
||||||
EmulatorIOError(Error),
|
EmulatorIOError(Error),
|
||||||
OtherError(String),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<TryFromSliceError> for EmulatorError {
|
impl From<TryFromSliceError> for EmulatorError {
|
||||||
|
Reference in New Issue
Block a user