diff options
-rw-r--r-- | CHANGELOG.txt | 13 | ||||
-rw-r--r-- | Cargo.toml | 9 | ||||
-rw-r--r-- | README.txt | 10 | ||||
-rw-r--r-- | src/luma.rs | 14 | ||||
-rw-r--r-- | src/luma/application.rs | 2 | ||||
-rw-r--r-- | src/luma/application/decode.rs | 22 | ||||
-rw-r--r-- | src/luma/application/drop.rs | 4 | ||||
-rw-r--r-- | src/luma/application/end.rs | 17 | ||||
-rw-r--r-- | src/luma/application/initialise.rs | 2 | ||||
-rw-r--r-- | src/luma/application/log.rs | 30 | ||||
-rw-r--r-- | src/luma/application/run.rs | 6 | ||||
-rw-r--r-- | src/luma/application/trap.rs | 41 | ||||
-rw-r--r-- | src/luma/configuration.rs | 1 | ||||
-rw-r--r-- | src/luma/configuration/create.rs | 28 | ||||
-rw-r--r-- | src/luma/configuration/load.rs | 108 | ||||
-rw-r--r-- | src/luma/configuration/path.rs | 2 |
16 files changed, 156 insertions, 153 deletions
diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 26fded1..ba07ef5 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -1,3 +1,16 @@ +# 0.24 + +* Bump dependency versions; +* Optimise b{cond}{l}.w decoder; +* Update messages; +* Remove Application::end method; +* Add comments; +* Add function for logging; +* Use TOML for configuration; +* Depend on Serde; +* Update readme; +* Remove unused Configuration::create; + # 0.23 * Update manifest; @@ -1,6 +1,6 @@ [package] name = "luma" -version = "0.35.0" +version = "0.36.0" authors = ["Gabriel Jensen"] edition = "2021" description = "AGB emulator." @@ -20,6 +20,7 @@ overflow-checks = false lto = true [dependencies] -configparser = "3.0.2" -libc = "0.2.146" -sdl2 = "0.35.2" +toml = "0.7.5" +libc = "0.2.147" +sdl2 = "0.35.2" +serde = { version = "1.0.164", features = ["derive"] } @@ -12,18 +12,18 @@ Invoke the emulator via the 'luma' command. CONFIGURATION -The emulator tries to read the configuration file at '${HOME}/.luma.ini'. If +The emulator tries to read the configuration file at '${HOME}/.luma.toml'. If this file is found, the following fields are read (if present): luma: - - version: (Uint) The version of the configuration file (0) + - version: (Integer) The version of the configuration file (0) device: - - bootloader: (String) The path to the bootloader file (home-relative) - - image: (String) The path to the image file (home-relative) + - bootloader: (String) The path to the bootloader file (home-relative) + - image: (String) The path to the image file (home-relative) video: - - scale: (Uint) The scale modifier applied to the screen (min 1; max (2^32-1)) + - scale: (Integer) The scale modifier applied to the screen (min 1; max (2^32-1)) These settings are overwritten by terminal parameters (see USAGE). diff --git a/src/luma.rs b/src/luma.rs index 88eb255..222e97e 100644 --- a/src/luma.rs +++ b/src/luma.rs @@ -10,9 +10,21 @@ pub struct VersionType<T> { pub const VERSION: VersionType::<u32> = VersionType::<u32> { major: 0x0, - minor: 0x23, + minor: 0x24, }; +#[allow(dead_code)] +pub enum LogType { + Branch( i32, u32), + Continue( u32), + Link( u32), + Load( u8, u32), + MoveRegister( u8, u8), + MoveImmediate(u8, u32), + Store( u32, u8), +} + +#[allow(dead_code)] pub enum TrapKind { BadAlignment( u32, u32), InvalidOpcode(u32, u32), diff --git a/src/luma/application.rs b/src/luma/application.rs index efb4beb..4c34c9d 100644 --- a/src/luma/application.rs +++ b/src/luma/application.rs @@ -11,10 +11,10 @@ use std::sync::atomic::AtomicBool; pub mod bootloader; pub mod decode; pub mod drop; -pub mod end; pub mod image; pub mod initialise; pub mod load; +pub mod log; pub mod read; pub mod run; pub mod trap; diff --git a/src/luma/application/decode.rs b/src/luma/application/decode.rs index fb57e44..bfb7765 100644 --- a/src/luma/application/decode.rs +++ b/src/luma/application/decode.rs @@ -1,7 +1,7 @@ // Copyright 2021-2023 Gabriel Jensen. use crate::luma::application::Application; -use crate::luma::TrapKind; +use crate::luma::{LogType, TrapKind}; impl Application { pub fn decode(&mut self, opcode: u32) { @@ -21,25 +21,25 @@ impl Application { 0b11000000000000000000000000000 => self.psr & 0b01000000000000000000000000000000 == 0x00 && self.psr & 0b00010000000000000000000000000000 >> 0x1C == self.psr & 0b10000000000000000000000000000000 >> 0x1F, 0b11010000000000000000000000000 => self.psr & 0b01000000000000000000000000000000 != 0x00 || self.psr & 0b00010000000000000000000000000000 >> 0x1C != self.psr & 0b10000000000000000000000000000000 >> 0x1F, 0b11100000000000000000000000000 => true, - _ => { self.trap(TrapKind::InvalidOpcode(self.registers[0xF] - 0x8, opcode)); false }, + _ => return self.trap(TrapKind::InvalidOpcode(self.registers[0xF] - 0x8, opcode)), }; if !condition { return } if opcode & 0b00001110000000000000000000000000 == 0b00001010000000000000000000000000 { - let off = opcode & 0b00000000111111111111111111111111; // Offset from pc. - let inv = !(opcode - 0x1) & 0b00000000111111111111111111111111; // Inverted offset. - - if opcode & 0b00000001000000000000000000000000 != 0x0 { + if opcode & 0b00000001000000000000000000000000 != 0x0 { // Check the L flag. self.registers[0xE] = self.registers[0xF] - 0x4; - eprintln!("link: lr => {}", self.registers[0xE]); + + self.log(LogType::Link(self.registers[0xE])); } - self.registers[0xF] = match (off & 0b00000000100000000000000000000000) != 0x0 { // If negative... - false => self.registers[0xF] + off * 0x4 + 0x8, - true => self.registers[0xF] - inv * 0x4 + 0x8, + let offset = match opcode & 0b00000000100000000000000000000000 != 0x0 { + false => (opcode & 0b00000000111111111111111111111111) as i32, + true => 0x0 - (!(opcode - 0x1) & 0b00000000111111111111111111111111) as i32, // Inverted (absolute) offset. }; - eprintln!("branch: {off:024b} => {:08X}", self.registers[0xF] - 0x8); + (self.registers[0xF], _) = self.registers[0xF].overflowing_add_signed(offset * 0x4 + 0x8); + + self.log(LogType::Branch(offset, self.registers[0xF] - 0x8)); return; } diff --git a/src/luma/application/drop.rs b/src/luma/application/drop.rs index 711e994..5652610 100644 --- a/src/luma/application/drop.rs +++ b/src/luma/application/drop.rs @@ -8,8 +8,8 @@ use std::mem::size_of; impl Drop for Application { fn drop(&mut self) { - unsafe { dealloc(self.memory, Layout::new::<[u32; MEMORY_SIZE / size_of::<u32>()]>()) }; + eprintln!("ending"); - self.end(0x0,None); + unsafe { dealloc(self.memory, Layout::new::<[u32; MEMORY_SIZE / size_of::<u32>()]>()) }; } } diff --git a/src/luma/application/end.rs b/src/luma/application/end.rs deleted file mode 100644 index 4e6f4fa..0000000 --- a/src/luma/application/end.rs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2021-2023 Gabriel Jensen. - -use crate::luma::application::Application; - -use std::process::exit; - -impl Application { - pub fn end(&mut self, cod: u8, msg: Option<&str>) { - if cod != 0x0 { - eprintln!("error: {}", msg.unwrap()); - } - - eprintln!("ending"); - - exit(cod as i32); - } -} diff --git a/src/luma/application/initialise.rs b/src/luma/application/initialise.rs index 67b0133..4777e51 100644 --- a/src/luma/application/initialise.rs +++ b/src/luma/application/initialise.rs @@ -37,7 +37,7 @@ impl Application { let memory = unsafe { alloc_zeroed(Layout::new::<[u32; MEMORY_SIZE / size_of::<u32>()]>()) }; if memory.is_null() { panic!("unable to allocate memory buffer") } - eprintln!("allocated memory buffer at 0x{:0X}", memory as usize); + eprintln!("allocated memory buffer at {:#0X}", memory as usize); return Application { configuration: configuration.clone(), diff --git a/src/luma/application/log.rs b/src/luma/application/log.rs new file mode 100644 index 0000000..4e0eb88 --- /dev/null +++ b/src/luma/application/log.rs @@ -0,0 +1,30 @@ +// Copyright 2021-2023 Gabriel Jensen. + +use crate::luma::LogType; +use crate::luma::application::Application; + +impl Application { + pub fn log(&mut self, log_type: LogType) { + let type_string = match log_type { + LogType::Branch( _, _) => "branch ", + LogType::Continue( _) => "continue", + LogType::Link( _) => "link ", + LogType::Load( _, _) => "load ", + LogType::MoveRegister( _, _) => "move ", + LogType::MoveImmediate(_, _) => "move ", + LogType::Store( _, _) => "store ", + }; + + let message = match log_type { + LogType::Branch( offset, address) => format!("pc{offset:+} => {address:#010X}"), + LogType::Continue( address) => format!("pc => {address:#010X}"), + LogType::Link( address) => format!("lr => {address:#010X}"), + LogType::Load( register, address) => format!("r{register} => {address:#010X}"), + LogType::MoveRegister( destination, source) => format!("r{destination} => r{source}"), + LogType::MoveImmediate(register, immediate) => format!("r{register} => {immediate:#X}"), + LogType::Store( address, register) => format!("{address:#010X} => r{register}"), + }; + + eprintln!("{type_string} : {message}"); + } +} diff --git a/src/luma/application/run.rs b/src/luma/application/run.rs index 59f2144..8f7368a 100644 --- a/src/luma/application/run.rs +++ b/src/luma/application/run.rs @@ -1,6 +1,6 @@ // Copyright 2021-2023 Gabriel Jensen. -use crate::luma::VERSION; +use crate::luma::{LogType, VERSION}; use crate::luma::application::{Application, GOT_SIGNAL}; use sdl2::event::Event; @@ -19,7 +19,7 @@ impl Application { let mut event_pump = self.sdl.event_pump().expect("unable to get event pump"); - eprintln!("starting emulation at 0x{:08X}",self.registers[0xF] - 0x8); + eprintln!("starting emulation at {:#010X}",self.registers[0xF] - 0x8); 'main_loop: loop { // Check if we have recieved a signal: @@ -42,7 +42,7 @@ impl Application { // Continue: self.registers[0xF] += 0x4; - eprintln!("continue: pc => {:08X}", self.registers[0xF]); + self.log(LogType::Continue(self.registers[0xF])); sleep(Duration::from_secs(0x1)); } diff --git a/src/luma/application/trap.rs b/src/luma/application/trap.rs index 1d38610..f96ccbc 100644 --- a/src/luma/application/trap.rs +++ b/src/luma/application/trap.rs @@ -6,29 +6,28 @@ use crate::luma::application::Application; impl Application { pub fn trap(&mut self, kind: TrapKind) { let message = match kind { - TrapKind::BadAlignment( address, alignment) => format!("bad alignment of address 0x{address:08X} (should be {alignment}-byte aligned)"), - TrapKind::InvalidOpcode(address, opcode) => format!("invalid opcode 0x{opcode:08X} at 0x{address:08X}"), - TrapKind::OutOfBounds( address) => format!("out-of-bounds address 0x{address:08X} (limit is 0x{MEMORY_SIZE:08X})"), + TrapKind::BadAlignment( address, alignment) => format!("bad alignment of address {address:#010X} (should be {alignment}-byte aligned)"), + TrapKind::InvalidOpcode(address, opcode) => format!("invalid opcode {opcode:#010X} at {address:#010X}"), + TrapKind::OutOfBounds( address) => format!("out-of-bounds address {address:#010X} (limit is {MEMORY_SIZE:#010X})"), }; eprintln!("trap - {message}"); - eprintln!(); - eprintln!("\tr0: {:08X}", self.registers[0x0]); - eprintln!("\tr1: {:08X}", self.registers[0x1]); - eprintln!("\tr2: {:08X}", self.registers[0x2]); - eprintln!("\tr3: {:08X}", self.registers[0x3]); - eprintln!("\tr4: {:08X}", self.registers[0x4]); - eprintln!("\tr5: {:08X}", self.registers[0x5]); - eprintln!("\tr6: {:08X}", self.registers[0x6]); - eprintln!("\tr7: {:08X}", self.registers[0x7]); - eprintln!("\tr8: {:08X}", self.registers[0x8]); - eprintln!("\tr9: {:08X}", self.registers[0x9]); - eprintln!("\tr10: {:08X}", self.registers[0xA]); - eprintln!("\tr11: {:08X}", self.registers[0xB]); - eprintln!("\tr12: {:08X}", self.registers[0xC]); - eprintln!("\tsp: {:08X}", self.registers[0xD]); - eprintln!("\tlr: {:08X}", self.registers[0xE]); - eprintln!("\tpc: {:08X}", self.registers[0xF]); - eprintln!("\tcpsr: {:032b}", self.psr); + eprintln!("\tr0: {:#010X}", self.registers[0x0]); + eprintln!("\tr1: {:#010X}", self.registers[0x1]); + eprintln!("\tr2: {:#010X}", self.registers[0x2]); + eprintln!("\tr3: {:#010X}", self.registers[0x3]); + eprintln!("\tr4: {:#010X}", self.registers[0x4]); + eprintln!("\tr5: {:#010X}", self.registers[0x5]); + eprintln!("\tr6: {:#010X}", self.registers[0x6]); + eprintln!("\tr7: {:#010X}", self.registers[0x7]); + eprintln!("\tr8: {:#010X}", self.registers[0x8]); + eprintln!("\tr9: {:#010X}", self.registers[0x9]); + eprintln!("\tr10: {:#010X}", self.registers[0xA]); + eprintln!("\tr11: {:#010X}", self.registers[0xB]); + eprintln!("\tr12: {:#010X}", self.registers[0xC]); + eprintln!("\tsp: {:#010X}", self.registers[0xD]); + eprintln!("\tlr: {:#010X}", self.registers[0xE]); + eprintln!("\tpc: {:#010X}", self.registers[0xF]); + eprintln!("\tcpsr: {:#034b}", self.psr); } } diff --git a/src/luma/configuration.rs b/src/luma/configuration.rs index 045e897..efad017 100644 --- a/src/luma/configuration.rs +++ b/src/luma/configuration.rs @@ -1,6 +1,5 @@ // Copyright 2021-2023 Gabriel Jensen. -pub mod create; pub mod load; pub mod new; pub mod overwrite; diff --git a/src/luma/configuration/create.rs b/src/luma/configuration/create.rs deleted file mode 100644 index b5f2312..0000000 --- a/src/luma/configuration/create.rs +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2021-2023 Gabriel Jensen. - -use crate::luma::CONFIGURATION_VERSION; -use crate::luma::configuration::Configuration; - -use std::fs::write; - -impl Configuration { - pub(super) fn create(&mut self) { - let configuration_path = Configuration::path(); - - eprintln!("creating configuration at {configuration_path}"); - - let default_configuration = format!( - "[luma]\n\ - version = {CONFIGURATION_VERSION}\n\ - \n\ - [device]\n\ - #bootloader = \n\ - #image = \n\ - \n\ - [video]\n\ - scale = 1\n" - ); - - write(configuration_path, default_configuration).unwrap(); - } -} diff --git a/src/luma/configuration/load.rs b/src/luma/configuration/load.rs index a3fe455..fd425d4 100644 --- a/src/luma/configuration/load.rs +++ b/src/luma/configuration/load.rs @@ -3,8 +3,35 @@ use crate::luma::CONFIGURATION_VERSION; use crate::luma::configuration::Configuration; -use configparser::ini::Ini; +extern crate serde; +extern crate toml; + use std::env::var; +use std::fs::read_to_string; +use serde::Deserialize; + +#[derive(Deserialize)] +struct Container { + luma: Luma, + device: Device, + video: Video, +} + +#[derive(Deserialize)] +struct Luma { + version: Option<u32>, +} + +#[derive(Deserialize)] +struct Device { + bootloader: Option<String>, + image: Option<String>, +} + +#[derive(Deserialize)] +struct Video { + scale: Option<u32>, +} impl Configuration { pub(super) fn load(&mut self) { @@ -12,69 +39,36 @@ impl Configuration { eprintln!("loading configuration \"{configuration_path}\""); - let mut configuration = Ini::new(); + let contents = read_to_string(configuration_path).expect("unable to read configuration file"); - match configuration.load(configuration_path) { - Ok( _) => {}, - Err(_) => { - eprintln!("unable to read configuration"); + let configuration: Container = toml::from_str(contents.as_str()).expect("unable to parse configuration file"); - return self.create(); - }, - } + let version = configuration.luma.version.expect("missing value 'version' under 'luma'"); + if version < CONFIGURATION_VERSION { panic!("ancient version: downgrade configuration") } + if version > CONFIGURATION_VERSION { panic!("out-of-date version: upgrade configuration") } - let get_path = |configuration: &mut Ini, section: &str, entry: &str| -> Option<String> { - match configuration.get(section, entry) { + let get_path = |output_path: &mut String, input_path: Option<String>| { + match input_path { Some(path) => { - if path.chars().nth(0x0).unwrap() != '/' { - let home_directory = match var("HOME") { - Ok( path) => path, - Err(_) => { eprintln!("unable to get home directory"); "".to_string() }, - }; - - return Some(home_directory + "/" + &path) - } - - return Some(path); - }, - None => None, - } + *output_path = if path.chars().nth(0x0).unwrap() != '/' { + let home_directory = match var("HOME") { + Ok( path) => path, + Err(_) => { eprintln!("unable to get home directory"); "".to_string() }, + }; + + home_directory + "/" + &path + } else { path } + }, + None => {}, + }; }; - let get_unsigned = |configuration: &mut Ini, section: &str, entry: &str| -> Option<u64> { - match configuration.getuint(section, entry) { - Ok( optional) => optional, - Err(_) => panic!("invalid format of '{entry}' in configuration under '{section}"), - } - }; - - let version = get_unsigned(&mut configuration, "luma", "version").expect("'version' field not defined in configuration under 'luma'") as u32; - - if version < CONFIGURATION_VERSION { panic!("out-of-date configuration - please upgrade") }; - if version > CONFIGURATION_VERSION { panic!("future configuration - please downgrade") }; - - match get_path(&mut configuration, "device", "bootloader") { - Some(path) => { - self.bootloader = path; - }, - None => {}, - } - - match get_path(&mut configuration, "device", "image") { - Some(path) => { - self.image = path; - }, - None => {}, - } - - match get_unsigned(&mut configuration, "video", "scale") { - Some(value) => { - assert!(value >= 0x1); - assert!(value <= 0xFFFFFFFF); + get_path(&mut self.bootloader, configuration.device.bootloader); + get_path(&mut self.image, configuration.device.image); - self.scale = value as u32; - }, - None => {}, + if configuration.video.scale.is_some() { + self.scale = configuration.video.scale.unwrap(); + assert!(self.scale >= 0x1); } } } diff --git a/src/luma/configuration/path.rs b/src/luma/configuration/path.rs index 0db3d98..a1ff3fd 100644 --- a/src/luma/configuration/path.rs +++ b/src/luma/configuration/path.rs @@ -9,6 +9,6 @@ impl Configuration { return match var("HOME") { Ok( path) => path, Err(_) => panic!("unable to get home directory"), - } + "/.luma.ini"; + } + "/.luma.toml"; } } |