From be6dccb9d79e7c25fe8a9bbc549636d85da555d1 Mon Sep 17 00:00:00 2001 From: Thomas Date: Sat, 16 Dec 2023 08:22:59 +0100 Subject: [PATCH] Remove allocations from instruction fetchers --- Cargo.lock | 7 +++++++ Cargo.toml | 1 + src/snes/cpu_65816/cpu.rs | 5 +++-- src/snes/cpu_65816/instruction.rs | 9 ++++++--- src/snes/cpu_spc700/cpu.rs | 5 +++-- src/snes/cpu_spc700/instruction.rs | 7 +++++-- 6 files changed, 25 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 498ee39..c25ff34 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -74,6 +74,12 @@ dependencies = [ "backtrace", ] +[[package]] +name = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" + [[package]] name = "autocfg" version = "1.1.0" @@ -558,6 +564,7 @@ name = "siena" version = "0.1.0" dependencies = [ "anyhow", + "arrayvec", "clap", "colored", "dbg_hex", diff --git a/Cargo.toml b/Cargo.toml index 1d51014..188653c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,6 +7,7 @@ default-run = "siena" [dependencies] anyhow = { version = "1.0.75", features = ["backtrace"] } +arrayvec = "0.7.4" clap = { version = "4.4.6", features = ["derive"] } colored = "2.0.4" dbg_hex = "0.1.1" diff --git a/src/snes/cpu_65816/cpu.rs b/src/snes/cpu_65816/cpu.rs index b22b120..a401893 100644 --- a/src/snes/cpu_65816/cpu.rs +++ b/src/snes/cpu_65816/cpu.rs @@ -1,4 +1,5 @@ use anyhow::Result; +use arrayvec::ArrayVec; use num_traits::ToPrimitive; use serde::{Deserialize, Serialize}; @@ -6,7 +7,7 @@ use crate::snes::bus::{Address, Bus, BusIterator, ADDRESS_MASK}; use crate::tickable::Ticks; use super::alu; -use super::instruction::{AddressingMode, Instruction, InstructionType}; +use super::instruction::{AddressingMode, Instruction, InstructionType, MAX_INSTRUCTION_LEN}; use super::regs::{Flag, Register, RegisterFile, RegisterWidth}; /// Main SNES CPU (65816) @@ -62,7 +63,7 @@ where /// Fetches and decodes the next instruction at PC pub fn fetch_next_instr(&mut self) -> Result { - let mut fetched: Vec = vec![]; + let mut fetched: ArrayVec = ArrayVec::new(); for p in 0.. { let pc = (self.regs.k as Address) << 16 | self.regs.pc.wrapping_add(p) as Address; diff --git a/src/snes/cpu_65816/instruction.rs b/src/snes/cpu_65816/instruction.rs index 31e6062..e6e4d5c 100644 --- a/src/snes/cpu_65816/instruction.rs +++ b/src/snes/cpu_65816/instruction.rs @@ -1,10 +1,13 @@ use std::fmt; use anyhow::Result; +use arrayvec::ArrayVec; use thiserror::Error; use super::instruction_table::INSTRUCTION_TABLE; +pub const MAX_INSTRUCTION_LEN: usize = 4; + /// Instruction addressing mode #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub enum AddressingMode { @@ -257,7 +260,7 @@ pub struct Instruction { pub immediate: [u32; 2], /// Raw bytes - pub raw: Vec, + pub raw: ArrayVec, /// Instruction length pub len: usize, @@ -266,7 +269,7 @@ pub struct Instruction { impl Instruction { /// Try to decode a single instruction from an iterator. pub fn decode(stream: &mut impl Iterator, m: bool, x: bool) -> Result { - let mut raw: Vec = vec![]; + let mut raw: ArrayVec = ArrayVec::new(); let mut rd = || -> Result { let b = stream.next().ok_or(DecodeErr::EndOfStream)?; raw.push(b); @@ -275,7 +278,7 @@ impl Instruction { let opcode = rd()?; let def = &INSTRUCTION_TABLE[opcode as usize]; - let mut args = [0; 4]; + let mut args = [0; MAX_INSTRUCTION_LEN]; let len = def.mode.get_fetch_len(m, x); for i in 0..(len - 1) { args[i] = rd()?; diff --git a/src/snes/cpu_spc700/cpu.rs b/src/snes/cpu_spc700/cpu.rs index 2a8b2b2..d1a7a43 100644 --- a/src/snes/cpu_spc700/cpu.rs +++ b/src/snes/cpu_spc700/cpu.rs @@ -1,10 +1,11 @@ use anyhow::Result; +use arrayvec::ArrayVec; use serde::{Deserialize, Serialize}; use crate::snes::bus::{Bus, BusIterator}; use crate::tickable::Ticks; -use super::instruction::{Instruction, InstructionType, Operand}; +use super::instruction::{Instruction, InstructionType, Operand, MAX_INSTRUCTION_LEN}; use super::regs::{Flag, Register, RegisterFile}; pub type SpcAddress = u16; @@ -47,7 +48,7 @@ where /// Fetches and decodes the next instruction at PC pub fn fetch_next_instr(&mut self) -> Result { - let mut fetched: Vec = vec![]; + let mut fetched: ArrayVec = ArrayVec::new(); for i in 0.. { let pc = self.regs.pc as SpcAddress; diff --git a/src/snes/cpu_spc700/instruction.rs b/src/snes/cpu_spc700/instruction.rs index f056ef3..9d57899 100644 --- a/src/snes/cpu_spc700/instruction.rs +++ b/src/snes/cpu_spc700/instruction.rs @@ -1,11 +1,14 @@ use std::fmt; use anyhow::Result; +use arrayvec::ArrayVec; use thiserror::Error; use super::instruction_table::INSTRUCTION_TABLE; use super::regs::Register; +pub const MAX_INSTRUCTION_LEN: usize = 3; + /// Instruction operands #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub enum Operand { @@ -135,7 +138,7 @@ pub struct Instruction { pub immediate: [u8; 2], /// Raw bytes - pub raw: Vec, + pub raw: ArrayVec, /// Instruction length pub len: usize, @@ -144,7 +147,7 @@ pub struct Instruction { impl Instruction { /// Try to decode a single instruction from an iterator. pub fn decode(stream: &mut impl Iterator) -> Result { - let mut raw: Vec = vec![]; + let mut raw: ArrayVec = ArrayVec::new(); let mut rd = || -> Result { let b = stream.next().ok_or(DecodeErr::EndOfStream)?; raw.push(b);