From 766262385b9c212501a04918c321ae2b7c81bb62 Mon Sep 17 00:00:00 2001 From: qwe-q Date: Sat, 18 Nov 2023 00:02:57 -0600 Subject: [PATCH 1/3] huge blob of everything from the last like, three weeks --- name-emu/Cargo.toml | 3 +- name-emu/src/exception.rs | 5 +++ name-emu/src/main.rs | 41 ++++++++++++++---- name-emu/src/mips.rs | 90 +++++++++++++++++++++++++++++++++------ name-emu/src/syscall.rs | 36 ++++++++++++++++ 5 files changed, 153 insertions(+), 22 deletions(-) create mode 100644 name-emu/src/syscall.rs diff --git a/name-emu/Cargo.toml b/name-emu/Cargo.toml index 381ed452..62a589e3 100644 --- a/name-emu/Cargo.toml +++ b/name-emu/Cargo.toml @@ -12,4 +12,5 @@ base64 = "0.21.4" byteorder = "1.4.3" serde_json = "1.0.107" serde = { version = "1.0.188", features = ["derive"] } -toml = "0.7.6" \ No newline at end of file +toml = "0.7.6" +elf = "0.7.3" \ No newline at end of file diff --git a/name-emu/src/exception.rs b/name-emu/src/exception.rs index 3c04051e..0e07cab4 100644 --- a/name-emu/src/exception.rs +++ b/name-emu/src/exception.rs @@ -19,6 +19,10 @@ pub enum ExecutionErrors { // Can also refer to underflow IntegerOverflow { rt: usize, rs: usize, value1: u32, value2: u32 }, + SyscallInvalidArugment, + + SyscallInvalidSyscallNumber, + Event { event: ExecutionEvents } } @@ -97,6 +101,7 @@ pub fn exception_pretty_print(reason: Result<(), ExecutionErrors>) -> ExceptionI type_name: None, full_type_name: None, evaluate_name: None, stack_trace: None, inner_exception: None }) }, + _ => unimplemented!("adf"), } } diff --git a/name-emu/src/main.rs b/name-emu/src/main.rs index 26e2971e..9fff8116 100644 --- a/name-emu/src/main.rs +++ b/name-emu/src/main.rs @@ -1,9 +1,12 @@ +use std::collections::HashMap; use std::fs::File; use std::io::{BufReader, BufWriter, Write}; use dap::events::{StoppedEventBody, ExitedEventBody, TerminatedEventBody}; use dap::responses::{ReadMemoryResponse, SetExceptionBreakpointsResponse, ThreadsResponse, StackTraceResponse, ScopesResponse, VariablesResponse, ContinueResponse}; use dap::types::{StoppedEventReason, Thread, StackFrame, Scope, Source, Variable}; +use elf::endian::{AnyEndian, LittleEndian}; +use elf::section::SectionHeader; use thiserror::Error; use dap::prelude::*; @@ -17,10 +20,16 @@ use exception::{ExecutionErrors, exception_pretty_print, ExecutionEvents}; mod lineinfo; use lineinfo::{LineInfo, lineinfo_import}; +mod syscall; + use base64::{Engine as _, engine::general_purpose}; use std::env; use std::net::TcpListener; +use elf::ElfBytes; +use elf::segment::ProgramHeader; +use elf::abi::PT_LOAD; + #[derive(Error, Debug)] enum MyAdapterError { #[error("Unhandled command")] @@ -72,20 +81,34 @@ type DynResult = std::result::Result>; // } // } -fn reset_mips(program_data: &[u8]) -> Mips { +fn reset_mips(elf_file: &Vec, elf_parsed: &ElfBytes<'_, LittleEndian>, segments: &Vec) -> Mips { // Reset execution and begin again. - let mut mips: Mips = Default::default(); + let mut mips: Mips = Default::default(); + mips.pc = elf_parsed.ehdr.e_entry as usize; - for (i, byte) in program_data.iter().enumerate() { - mips.write_b(mips::DOT_TEXT_START_ADDRESS + i as u32, *byte).unwrap(); + for phdr in segments { + mips.memories.push((elf_file[phdr.p_offset as usize .. (phdr.p_offset + phdr.p_filesz) as usize].to_vec(), phdr.p_vaddr as u32, phdr.p_filesz as u32)); + + // WARNING: BROKEN + if elf_parsed.ehdr.e_entry == phdr.p_vaddr { + mips.stop_address = (phdr.p_vaddr + phdr.p_filesz) as usize; + } } - mips.stop_address = mips::DOT_TEXT_START_ADDRESS as usize + program_data.len(); mips } fn main() -> DynResult<()> { + + let elf_file_data = std::fs::read("/home/qwe/Documents/CS4485/Fibonacci_linked").unwrap(); + let elf_file = ElfBytes::::minimal_parse(elf_file_data.as_slice()).unwrap(); + let elf_all_load_phdrs: Vec = elf_file.segments().unwrap() + .iter() + .filter(|phdr|{phdr.p_type == PT_LOAD}) + .collect(); + + let args_strings: Vec = env::args().collect(); if args_strings.len() != 5 { @@ -199,7 +222,7 @@ loop { server.send_event(Event::Initialized)?; - mips = reset_mips(&program_data); + mips = reset_mips(&elf_file_data, &elf_file, &elf_all_load_phdrs); } @@ -461,7 +484,7 @@ loop { } Command::Restart(_) => { - mips = reset_mips(&program_data); + mips = reset_mips(&elf_file_data, &elf_file, &elf_all_load_phdrs); let rsp = req.success( ResponseBody::Restart @@ -504,7 +527,9 @@ loop { } // OK, what happened? let stopped_event_body = match mips.prev_ins_result { - Ok(()) => unreachable!(), // It's unreachable. + Ok(()) => { + unreachable!()// It's unreachable. + } Err(what_happened) => match what_happened { ExecutionErrors::Event{event} => match event { ExecutionEvents::ProgramComplete => { diff --git a/name-emu/src/mips.rs b/name-emu/src/mips.rs index 5231a781..8d0b7a34 100644 --- a/name-emu/src/mips.rs +++ b/name-emu/src/mips.rs @@ -4,14 +4,12 @@ use std::io::Cursor; use std::fs::File; use std::io::Write; -use crate::exception::{ExecutionErrors, ExecutionEvents}; -pub const DOT_TEXT_START_ADDRESS: u32 = 0x00400000; -const DOT_TEXT_MAX_LENGTH: u32 = 0x1000; -const LEN_TEXT_INITIAL: usize = 200; +use crate::{exception::{ExecutionErrors, ExecutionEvents}, syscall::syscall}; + const MIPS_INSTRUCTION_LENGTH: usize = 4; -pub const REGISTER_NAMES: [&str; 32] = [ +pub const REGISTER_NAMES: [&str; 33] = [ "$zero", "$at", "$v0", @@ -43,9 +41,12 @@ pub const REGISTER_NAMES: [&str; 32] = [ "$gp", "$sp", "$fp", - "$ra" + "$ra", + // See below constant. Used for exception printing + "Immediate" ]; pub const PC_NAME: &str = "$pc"; +pub const IMMEDIATE_PRETTY_PRINT: usize = 32; #[derive(Debug)] enum BranchDelays { @@ -91,13 +92,11 @@ impl Default for Mips { floats: [0f32; 32], mult_hi: 0, mult_lo: 0, - pc: DOT_TEXT_START_ADDRESS as usize, + pc: 0, branch_delay_target: 0, branch_delay_status: BranchDelays::NotActive, - memories: vec![ - (vec![0; LEN_TEXT_INITIAL], DOT_TEXT_START_ADDRESS, DOT_TEXT_MAX_LENGTH) - ], - stop_address: DOT_TEXT_START_ADDRESS as usize, + memories: vec![], + stop_address: 0, prev_ins_result: Ok(()) } } @@ -150,6 +149,10 @@ impl Mips { 0x2 => { self.regs[ins.rd] = self.regs[ins.rt] >> ins.shamt; } + // Jump Register + 0x8 => { + self.pc = self.regs[ins.rs] as usize; + } // Add 0x20 => { let result = self.regs[ins.rt].checked_add(self.regs[ins.rs]); @@ -206,9 +209,45 @@ impl Mips { } fn dispatch_i(&mut self, ins: Itype, opcode: u32) -> Result<(), ExecutionErrors> { - let memory_address = (ins.rt as i64 + (ins.imm as i64)) as u32; + let memory_address = self.regs[ins.rs].wrapping_add(ins.imm as u32); match ins.opcode { + // Branch on Less than Zero + // MIPS manual says: If the contents of GPR rs are less than zero (sign bit is 1) + 0x6 => { + if self.regs[ins.rs] as i32 <= 0 { + self.branch_delay_target = (ins.imm as u32) << 2; + self.branch_delay_status = BranchDelays::Set; + } + } + // Branch on Greater than Zero + // MIPS manual says: If the contents of GPR rs + // are greater than zero (sign bit is 0 but value not zero) + 0x7 => { + if self.regs[ins.rs] > 0 { + self.branch_delay_target = (ins.imm as u32) << 2; + self.branch_delay_status = BranchDelays::Set; + } + } + // Add Immediate + 0x8 => { + let result = self.regs[ins.rs].checked_add(ins.imm as u32); + match result { + Some(value) => {self.regs[ins.rt] = value;} + None => { + return Err(ExecutionErrors::IntegerOverflow { + rt: IMMEDIATE_PRETTY_PRINT, + rs: ins.rs, + value1: ins.imm as u32, + value2: self.regs[ins.rs] + }); + } + } + } + // Add Immediate Unsigned + 0x9 => { + self.regs[ins.rt] = self.regs[ins.rs].wrapping_add(ins.imm as u32); + } // Set on Less Than Immediate (signed) // If rs is less than sign-extended 16 bit immediate using signed comparison, then set rt to 1 // Casting on imm is to sign extend. See load byte casts @@ -221,6 +260,12 @@ impl Mips { 0xB => { self.regs[ins.rt] = if self.regs[ins.rs] < (ins.imm as i16 as i32 as u32) { 1 } else { 0 }; } + // System Call + 0xC => { + // Grab 20-bit code field + let code = (opcode >> 6) & 0xFFFFF; + syscall(self, code)?; + } // Or Immediate 0xD => { // Rust zero-extends unsigned values when up-casting @@ -316,7 +361,7 @@ impl Mips { fn decode(&self, instruction: u32) -> Instructions { let opcode = instruction >> 26 & 0b111111; - match opcode { + match opcode { // R-type 0 => { Instructions::R(Rtype { @@ -392,6 +437,15 @@ impl Mips { self.read_b(address + 2)?, self.read_b(address + 3)?]; Ok(Cursor::new(bytes).read_u32::().unwrap()) } + // Returns a reference to a block of memory, if it exists. + pub fn read_block(&mut self, address: u32, len: u32) -> Result<&[u8], ExecutionErrors> { + if let Some((memory, offset)) = self.map_memory(address) { + if memory.len() <= (len + offset) as usize { + return Ok(&memory[offset as usize .. (offset + len) as usize]); + } + } + Err(ExecutionErrors::MemoryIllegalAccess { load_address: address }) + } // Writes one byte @@ -426,6 +480,16 @@ impl Mips { self.write_b(address, bytes[3])?; Ok(()) } + // Writes a block of memory, if it exists + pub fn write_block(&mut self, address: u32, len: u32, data: &[u8]) -> Result<(), ExecutionErrors> { + if let Some((memory, offset)) = self.map_memory(address) { + if memory.len() <= (len + offset) as usize { + memory[offset as usize .. (offset + len) as usize].copy_from_slice(data); + return Ok(()) + } + } + Err(ExecutionErrors::MemoryIllegalAccess { load_address: address }) + } pub fn step_one(&mut self, mut f :&mut File) -> Result<(), ExecutionErrors> { let opcode = self.read_w(self.pc as u32)?; diff --git a/name-emu/src/syscall.rs b/name-emu/src/syscall.rs new file mode 100644 index 00000000..7003a69f --- /dev/null +++ b/name-emu/src/syscall.rs @@ -0,0 +1,36 @@ +// This file implements the system calls used by MARS. +// The system call number is stored in $v0, which is register 2. + +use crate::mips::Mips; +use crate::exception::{ExecutionErrors, ExecutionEvents}; +use std::io::Stdin; + +pub(crate) fn syscall(mips: &mut Mips, code: u32) -> Result<(), ExecutionErrors> { + match mips.regs[2] { + + // Exit. Immediately raise a ProgramComplete error + 0 => { + Err(ExecutionErrors::Event { event: ExecutionEvents::ProgramComplete }) + } + // Print integer. Writes the value in $a0 to the screen + 1 => { + print!("{}", mips.regs[4]); + Ok(()) + } + // Print string. Writes null-terminated string pointed to by $a0 to the screen + 4 => { + let mut i = 0; + loop { + let read_char = mips.read_b(mips.regs[4] + i)?; + if read_char == 0 { + break; + } + print!("{}", read_char); + i += 1; + }; + Ok(()) + } + + _ => Err(ExecutionErrors::SyscallInvalidSyscallNumber) + } +} \ No newline at end of file From aa38cdf6b47eb7cda3b806bfdcfcdee3d5914a65 Mon Sep 17 00:00:00 2001 From: qwe-q Date: Mon, 27 Nov 2023 17:36:29 -0600 Subject: [PATCH 2/3] Assorted emulator bug fixes --- name-emu/src/mips.rs | 58 ++++++++++++++++++++++++++++++-------------- 1 file changed, 40 insertions(+), 18 deletions(-) diff --git a/name-emu/src/mips.rs b/name-emu/src/mips.rs index 8d0b7a34..922433fc 100644 --- a/name-emu/src/mips.rs +++ b/name-emu/src/mips.rs @@ -52,7 +52,15 @@ pub const IMMEDIATE_PRETTY_PRINT: usize = 32; enum BranchDelays { NotActive, Set, - Ready + SetAbsolute, + Ready, + ReadyAbsolute +} + +// https://www.reddit.com/r/rust/comments/6175al/arbitrary_width_sign_extension_in_rust/ +fn sign_extend(x: i32, nbits: u32) -> i32 { + let notherbits = std::mem::size_of_val(&x) as u32 * 8 - nbits; + x.wrapping_shl(notherbits).wrapping_shr(notherbits) } #[derive(Debug)] @@ -65,7 +73,8 @@ pub(crate) struct Mips { // Branch delay slots are implemented by filling this buffer with the // branch target, which will be triggered after the following instruction - branch_delay_target: u32, + branch_delay_target: i32, + branch_delay_target_abs: u32, branch_delay_status: BranchDelays, @@ -94,6 +103,7 @@ impl Default for Mips { mult_lo: 0, pc: 0, branch_delay_target: 0, + branch_delay_target_abs: 0, branch_delay_status: BranchDelays::NotActive, memories: vec![], stop_address: 0, @@ -153,6 +163,12 @@ impl Mips { 0x8 => { self.pc = self.regs[ins.rs] as usize; } + // System Call + 0xC => { + // Grab 20-bit code field + let code = (opcode >> 6) & 0xFFFFF; + syscall(self, code)?; + } // Add 0x20 => { let result = self.regs[ins.rt].checked_add(self.regs[ins.rs]); @@ -216,7 +232,9 @@ impl Mips { // MIPS manual says: If the contents of GPR rs are less than zero (sign bit is 1) 0x6 => { if self.regs[ins.rs] as i32 <= 0 { - self.branch_delay_target = (ins.imm as u32) << 2; + // Ugh. How do I handle this? + // This is an 18-bit signed integer. How do I even make that in Rust + self.branch_delay_target = sign_extend(ins.imm as u32 as i32, 18); self.branch_delay_status = BranchDelays::Set; } } @@ -225,13 +243,13 @@ impl Mips { // are greater than zero (sign bit is 0 but value not zero) 0x7 => { if self.regs[ins.rs] > 0 { - self.branch_delay_target = (ins.imm as u32) << 2; + self.branch_delay_target = sign_extend(((ins.imm as u32) << 2) as i32, 18); self.branch_delay_status = BranchDelays::Set; } } // Add Immediate 0x8 => { - let result = self.regs[ins.rs].checked_add(ins.imm as u32); + let result = self.regs[ins.rs].checked_add_signed(ins.imm as i16 as i32); match result { Some(value) => {self.regs[ins.rt] = value;} None => { @@ -260,12 +278,6 @@ impl Mips { 0xB => { self.regs[ins.rt] = if self.regs[ins.rs] < (ins.imm as i16 as i32 as u32) { 1 } else { 0 }; } - // System Call - 0xC => { - // Grab 20-bit code field - let code = (opcode >> 6) & 0xFFFFF; - syscall(self, code)?; - } // Or Immediate 0xD => { // Rust zero-extends unsigned values when up-casting @@ -319,14 +331,14 @@ impl Mips { // Branch if Equal 0x4 => { if self.regs[ins.rt] == self.regs[ins.rs] { - self.branch_delay_target = (ins.imm as u32) << 2; + self.branch_delay_target = sign_extend(ins.imm as u32 as i32, 18); self.branch_delay_status = BranchDelays::Set; } } // Branch if Not Equal 0x5 => { if self.regs[ins.rt] != self.regs[ins.rs] { - self.branch_delay_target = (ins.imm as u32) << 2; + self.branch_delay_target = sign_extend(ins.imm as u32 as i32, 18); self.branch_delay_status = BranchDelays::Set; } } @@ -343,13 +355,13 @@ impl Mips { match ins.opcode { // Jump absolute 2 => { - self.branch_delay_status = BranchDelays::Set; - self.branch_delay_target = self.pc as u32 & 0xF0000000 | (ins.dest << 2); + self.branch_delay_status = BranchDelays::SetAbsolute; + self.branch_delay_target_abs = self.pc as u32 & 0xF0000000 | (ins.dest << 2); } // Jump And Link 3 => { - self.branch_delay_status = BranchDelays::Set; - self.branch_delay_target = self.pc as u32 & 0xF0000000 | (ins.dest << 2); + self.branch_delay_status = BranchDelays::SetAbsolute; + self.branch_delay_target_abs = self.pc as u32 & 0xF0000000 | (ins.dest << 2); // $ra = register 31 self.regs[31] = self.pc as u32 + 8; } @@ -522,8 +534,18 @@ impl Mips { match self.branch_delay_status { BranchDelays::NotActive => (), BranchDelays::Set => self.branch_delay_status = BranchDelays::Ready, + BranchDelays::SetAbsolute => self.branch_delay_status = BranchDelays::ReadyAbsolute, BranchDelays::Ready => { - self.pc = self.branch_delay_target as usize; + // https://stackoverflow.com/questions/54035728/how-to-add-a-negative-i32-number-to-an-usize-variable + if self.branch_delay_target.is_negative() { + self.pc = self.pc.wrapping_sub(self.branch_delay_target.wrapping_abs() as u32 as usize); + } else { + self.pc = self.pc.wrapping_add(self.branch_delay_target as usize); + } + self.branch_delay_status = BranchDelays::NotActive; + } + BranchDelays::ReadyAbsolute => { + self.pc = self.branch_delay_target_abs as usize; self.branch_delay_status = BranchDelays::NotActive; } } From 67d0f7132aee034d7900c23ddaa0bbfcc4e8a8ac Mon Sep 17 00:00:00 2001 From: qwe-q Date: Tue, 5 Dec 2023 18:12:02 -0600 Subject: [PATCH 3/3] =?UTF-8?q?Many=20emulation=20bug=20fixes=E2=80=94=20F?= =?UTF-8?q?ibonacci=20now=20runs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- name-emu/src/mips.rs | 61 +++++++++++++++++------------------------ name-emu/src/syscall.rs | 12 ++++---- 2 files changed, 32 insertions(+), 41 deletions(-) diff --git a/name-emu/src/mips.rs b/name-emu/src/mips.rs index 922433fc..16f8de85 100644 --- a/name-emu/src/mips.rs +++ b/name-emu/src/mips.rs @@ -52,9 +52,7 @@ pub const IMMEDIATE_PRETTY_PRINT: usize = 32; enum BranchDelays { NotActive, Set, - SetAbsolute, - Ready, - ReadyAbsolute + Ready } // https://www.reddit.com/r/rust/comments/6175al/arbitrary_width_sign_extension_in_rust/ @@ -73,8 +71,7 @@ pub(crate) struct Mips { // Branch delay slots are implemented by filling this buffer with the // branch target, which will be triggered after the following instruction - branch_delay_target: i32, - branch_delay_target_abs: u32, + branch_delay_target: usize, branch_delay_status: BranchDelays, @@ -103,7 +100,6 @@ impl Default for Mips { mult_lo: 0, pc: 0, branch_delay_target: 0, - branch_delay_target_abs: 0, branch_delay_status: BranchDelays::NotActive, memories: vec![], stop_address: 0, @@ -223,6 +219,13 @@ impl Mips { } Ok(()) } + + // This is a helper function for doing branches + fn configure_branch(&mut self, ins: Itype) { + self.branch_delay_target = self.pc.wrapping_add_signed(sign_extend(((ins.imm as u32) << 2) as i32, 18) as isize); + self.branch_delay_status = BranchDelays::Set; + } + fn dispatch_i(&mut self, ins: Itype, opcode: u32) -> Result<(), ExecutionErrors> { let memory_address = self.regs[ins.rs].wrapping_add(ins.imm as u32); @@ -232,10 +235,7 @@ impl Mips { // MIPS manual says: If the contents of GPR rs are less than zero (sign bit is 1) 0x6 => { if self.regs[ins.rs] as i32 <= 0 { - // Ugh. How do I handle this? - // This is an 18-bit signed integer. How do I even make that in Rust - self.branch_delay_target = sign_extend(ins.imm as u32 as i32, 18); - self.branch_delay_status = BranchDelays::Set; + self.configure_branch(ins); } } // Branch on Greater than Zero @@ -243,8 +243,7 @@ impl Mips { // are greater than zero (sign bit is 0 but value not zero) 0x7 => { if self.regs[ins.rs] > 0 { - self.branch_delay_target = sign_extend(((ins.imm as u32) << 2) as i32, 18); - self.branch_delay_status = BranchDelays::Set; + self.configure_branch(ins); } } // Add Immediate @@ -331,15 +330,13 @@ impl Mips { // Branch if Equal 0x4 => { if self.regs[ins.rt] == self.regs[ins.rs] { - self.branch_delay_target = sign_extend(ins.imm as u32 as i32, 18); - self.branch_delay_status = BranchDelays::Set; + self.configure_branch(ins); } } // Branch if Not Equal 0x5 => { if self.regs[ins.rt] != self.regs[ins.rs] { - self.branch_delay_target = sign_extend(ins.imm as u32 as i32, 18); - self.branch_delay_status = BranchDelays::Set; + self.configure_branch(ins); } } @@ -355,15 +352,17 @@ impl Mips { match ins.opcode { // Jump absolute 2 => { - self.branch_delay_status = BranchDelays::SetAbsolute; - self.branch_delay_target_abs = self.pc as u32 & 0xF0000000 | (ins.dest << 2); + self.branch_delay_status = BranchDelays::Set; + self.branch_delay_target = (self.pc as u32 & 0xF0000000 | (ins.dest << 2)) as usize; } // Jump And Link 3 => { - self.branch_delay_status = BranchDelays::SetAbsolute; - self.branch_delay_target_abs = self.pc as u32 & 0xF0000000 | (ins.dest << 2); + self.branch_delay_status = BranchDelays::Set; + self.branch_delay_target = (self.pc as u32 & 0xF0000000 | (ins.dest << 2)) as usize; // $ra = register 31 - self.regs[31] = self.pc as u32 + 8; + + // CODE SMELL— This has to be adjusted when branch delays are turned off!! + self.regs[31] = self.pc as u32 + 4; } _ => return Err(ExecutionErrors::UndefinedInstruction {instruction: opcode}) } @@ -479,7 +478,7 @@ impl Mips { let mut bytes = vec![]; bytes.write_u16::(value).unwrap(); self.write_b(address, bytes[0])?; - self.write_b(address, bytes[1])?; + self.write_b(address + 1, bytes[1])?; Ok(()) } // Writes a word in little endian form @@ -487,9 +486,9 @@ impl Mips { let mut bytes = vec![]; bytes.write_u32::(value).unwrap(); self.write_b(address, bytes[0])?; - self.write_b(address, bytes[1])?; - self.write_b(address, bytes[2])?; - self.write_b(address, bytes[3])?; + self.write_b(address + 1, bytes[1])?; + self.write_b(address + 2, bytes[2])?; + self.write_b(address + 3, bytes[3])?; Ok(()) } // Writes a block of memory, if it exists @@ -534,18 +533,8 @@ impl Mips { match self.branch_delay_status { BranchDelays::NotActive => (), BranchDelays::Set => self.branch_delay_status = BranchDelays::Ready, - BranchDelays::SetAbsolute => self.branch_delay_status = BranchDelays::ReadyAbsolute, BranchDelays::Ready => { - // https://stackoverflow.com/questions/54035728/how-to-add-a-negative-i32-number-to-an-usize-variable - if self.branch_delay_target.is_negative() { - self.pc = self.pc.wrapping_sub(self.branch_delay_target.wrapping_abs() as u32 as usize); - } else { - self.pc = self.pc.wrapping_add(self.branch_delay_target as usize); - } - self.branch_delay_status = BranchDelays::NotActive; - } - BranchDelays::ReadyAbsolute => { - self.pc = self.branch_delay_target_abs as usize; + self.pc = self.branch_delay_target; self.branch_delay_status = BranchDelays::NotActive; } } diff --git a/name-emu/src/syscall.rs b/name-emu/src/syscall.rs index 7003a69f..757b4355 100644 --- a/name-emu/src/syscall.rs +++ b/name-emu/src/syscall.rs @@ -8,10 +8,6 @@ use std::io::Stdin; pub(crate) fn syscall(mips: &mut Mips, code: u32) -> Result<(), ExecutionErrors> { match mips.regs[2] { - // Exit. Immediately raise a ProgramComplete error - 0 => { - Err(ExecutionErrors::Event { event: ExecutionEvents::ProgramComplete }) - } // Print integer. Writes the value in $a0 to the screen 1 => { print!("{}", mips.regs[4]); @@ -19,17 +15,23 @@ pub(crate) fn syscall(mips: &mut Mips, code: u32) -> Result<(), ExecutionErrors> } // Print string. Writes null-terminated string pointed to by $a0 to the screen 4 => { + let mut str_vec = vec![]; let mut i = 0; loop { let read_char = mips.read_b(mips.regs[4] + i)?; if read_char == 0 { break; } - print!("{}", read_char); + str_vec.push(read_char as char); i += 1; }; + print!("{}", str_vec.iter().collect::()); Ok(()) } + // Exit. Immediately raise a ProgramComplete error + 10 => { + Err(ExecutionErrors::Event { event: ExecutionEvents::ProgramComplete }) + } _ => Err(ExecutionErrors::SyscallInvalidSyscallNumber) }