Optimize instructions with "register lists" (LDM_STM)

These instruction (probably) allocated a vector each time.


Former-commit-id: 66f724e21e1e5d667d19c1f21d2cc4fa3944faac
This commit is contained in:
Michel Heily 2019-07-20 16:07:19 +03:00
parent 7119ba2451
commit 0f73abaf98
6 changed files with 90 additions and 95 deletions

View file

@ -1,5 +1,7 @@
use std::fmt; use std::fmt;
use crate::bit::BitIndex;
use super::{AluOpCode, ArmCond, ArmFormat, ArmHalfwordTransferType, ArmInstruction}; use super::{AluOpCode, ArmCond, ArmFormat, ArmHalfwordTransferType, ArmInstruction};
use crate::arm7tdmi::{ use crate::arm7tdmi::{
psr::RegPSR, reg_string, Addr, BarrelShiftOpCode, BarrelShifterValue, ShiftedRegister, REG_PC, psr::RegPSR, reg_string, Addr, BarrelShiftOpCode, BarrelShifterValue, ShiftedRegister, REG_PC,
@ -253,13 +255,19 @@ impl ArmInstruction {
auto_inc = if self.write_back_flag() { "!" } else { "" } auto_inc = if self.write_back_flag() { "!" } else { "" }
)?; )?;
let mut register_list = self.register_list().into_iter(); let register_list = self.register_list();
if let Some(reg) = register_list.next() { let mut has_first = false;
write!(f, "{}", reg_string(reg))?; for i in 0..16 {
if register_list.bit(i) {
if has_first {
write!(f, ", {}", reg_string(i))?;
} else {
write!(f, "{}", reg_string(i))?;
has_first = true;
} }
for reg in register_list {
write!(f, ", {}", reg_string(reg))?;
} }
}
write!( write!(
f, f,
"}}{}", "}}{}",

View file

@ -158,7 +158,6 @@ impl Core {
fn exec_data_processing(&mut self, _bus: &mut Bus, insn: ArmInstruction) -> CpuExecResult { fn exec_data_processing(&mut self, _bus: &mut Bus, insn: ArmInstruction) -> CpuExecResult {
// TODO handle carry flag // TODO handle carry flag
let op1 = if insn.rn() == REG_PC { let op1 = if insn.rn() == REG_PC {
self.pc as i32 // prefething self.pc as i32 // prefething
} else { } else {
@ -265,7 +264,6 @@ impl Core {
return Err(CpuError::IllegalInstruction); return Err(CpuError::IllegalInstruction);
} }
let mut addr = self.get_reg(insn.rn()); let mut addr = self.get_reg(insn.rn());
if insn.rn() == REG_PC { if insn.rn() == REG_PC {
addr = insn.pc + 8; // prefetching addr = insn.pc + 8; // prefetching
@ -330,23 +328,19 @@ impl Core {
let mut addr = self.gpr[rn] as i32; let mut addr = self.gpr[rn] as i32;
let step: i32 = if ascending { 4 } else { -4 }; let step: i32 = if ascending { 4 } else { -4 };
let rlist = if ascending { let rlist = insn.register_list();
insn.register_list()
} else {
let mut rlist = insn.register_list();
rlist.reverse();
rlist
};
if psr_user { if psr_user {
unimplemented!("Too tired to implement the mode enforcement"); unimplemented!("Too tired to implement the mode enforcement");
} }
if is_load { if is_load {
if rlist.contains(&rn) { for r in 0..16 {
let r = if ascending { r } else { 15 - r };
if rlist.bit(r) {
if r == rn {
writeback = false; writeback = false;
} }
for r in rlist {
if full { if full {
addr = addr.wrapping_add(step); addr = addr.wrapping_add(step);
} }
@ -363,8 +357,11 @@ impl Core {
addr = addr.wrapping_add(step); addr = addr.wrapping_add(step);
} }
} }
}
} else { } else {
for r in rlist { for r in 0..16 {
let r = if ascending { r } else { 15 - r };
if rlist.bit(r) {
if full { if full {
addr = addr.wrapping_add(step); addr = addr.wrapping_add(step);
} }
@ -381,6 +378,7 @@ impl Core {
} }
} }
} }
}
if writeback { if writeback {
self.set_reg(rn, addr as u32); self.set_reg(rn, addr as u32);

View file

@ -338,15 +338,8 @@ impl ArmInstruction {
} }
} }
pub fn register_list(&self) -> Vec<usize> { pub fn register_list(&self) -> u16 {
let list_bits = self.raw & 0xffff; (self.raw & 0xffff) as u16
let mut list = Vec::with_capacity(16);
for i in 0..16 {
if (list_bits & (1 << i)) != 0 {
list.push(i)
}
}
list
} }
pub fn swi_comment(&self) -> u32 { pub fn swi_comment(&self) -> u32 {

View file

@ -209,21 +209,27 @@ impl ThumbInstruction {
write!(f, "add\tsp, #{imm:x}", imm = self.sword7()) write!(f, "add\tsp, #{imm:x}", imm = self.sword7())
} }
fn fmt_register_list(&self, f: &mut fmt::Formatter, rlist: u8) -> fmt::Result {
let mut has_first = false;
for i in 0..8 {
if rlist.bit(i) {
if has_first {
write!(f, ", {}", reg_string(i))?;
} else {
write!(f, "{}", reg_string(i))?;
}
}
}
Ok(())
}
fn fmt_thumb_push_pop(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt_thumb_push_pop(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}\t{{", if self.is_load() { "pop" } else { "push" })?; write!(f, "{}\t{{", if self.is_load() { "pop" } else { "push" })?;
let mut register_list = self.register_list().into_iter(); let rlist = self.register_list();
let mut has_reg = false; self.fmt_register_list(f, rlist)?;
if let Some(reg) = register_list.next() {
write!(f, "{}", reg_string(reg))?;
has_reg = true;
}
for reg in register_list {
has_reg = true;
write!(f, ", {}", reg_string(reg))?;
}
if self.flag(ThumbInstruction::FLAG_R) { if self.flag(ThumbInstruction::FLAG_R) {
let r = if self.is_load() { "pc" } else { "lr" }; let r = if self.is_load() { "pc" } else { "lr" };
if has_reg { if rlist != 0 {
write!(f, ", {}", r)?; write!(f, ", {}", r)?;
} else { } else {
write!(f, "{}", r)?; write!(f, "{}", r)?;
@ -239,16 +245,7 @@ impl ThumbInstruction {
op = if self.is_load() { "ldm" } else { "stm" }, op = if self.is_load() { "ldm" } else { "stm" },
Rb = reg_string(self.rb()), Rb = reg_string(self.rb()),
)?; )?;
let mut register_list = self.register_list().into_iter(); self.fmt_register_list(f, self.register_list())?;
let mut has_reg = false;
if let Some(reg) = register_list.next() {
write!(f, "{}", reg_string(reg))?;
has_reg = true;
}
for reg in register_list {
has_reg = true;
write!(f, ", {}", reg_string(reg))?;
}
write!(f, "}}") write!(f, "}}")
} }

View file

@ -313,15 +313,15 @@ impl Core {
fn exec_thumb_push_pop(&mut self, bus: &mut Bus, insn: ThumbInstruction) -> CpuExecResult { fn exec_thumb_push_pop(&mut self, bus: &mut Bus, insn: ThumbInstruction) -> CpuExecResult {
// (From GBATEK) Execution Time: nS+1N+1I (POP), (n+1)S+2N+1I (POP PC), or (n-1)S+2N (PUSH). // (From GBATEK) Execution Time: nS+1N+1I (POP), (n+1)S+2N+1I (POP PC), or (n-1)S+2N (PUSH).
let is_pop = insn.is_load(); let is_pop = insn.is_load();
let pc_lr_flag = insn.flag(ThumbInstruction::FLAG_R); let pc_lr_flag = insn.flag(ThumbInstruction::FLAG_R);
let rlist = insn.register_list(); let rlist = insn.register_list();
if is_pop { if is_pop {
for r in rlist { for r in 0..8 {
if rlist.bit(r) {
pop(self, bus, r); pop(self, bus, r);
} }
}
if pc_lr_flag { if pc_lr_flag {
pop(self, bus, REG_PC); pop(self, bus, REG_PC);
self.pc = self.pc & !1; self.pc = self.pc & !1;
@ -332,10 +332,12 @@ impl Core {
if pc_lr_flag { if pc_lr_flag {
push(self, bus, REG_LR); push(self, bus, REG_LR);
} }
for r in rlist.into_iter().rev() { for r in (0..8).rev() {
if rlist.bit(r) {
push(self, bus, r); push(self, bus, r);
} }
} }
}
Ok(()) Ok(())
} }
@ -349,18 +351,22 @@ impl Core {
let mut addr = self.gpr[rb]; let mut addr = self.gpr[rb];
let rlist = insn.register_list(); let rlist = insn.register_list();
if is_load { if is_load {
for r in rlist { for r in 0..8 {
if rlist.bit(r) {
let val = self.load_32(addr, bus); let val = self.load_32(addr, bus);
addr += 4; addr += 4;
self.add_cycle(); self.add_cycle();
self.set_reg(r, val); self.set_reg(r, val);
} }
}
} else { } else {
for r in rlist { for r in 0..8 {
if rlist.bit(r) {
self.store_32(addr, self.gpr[r], bus); self.store_32(addr, self.gpr[r], bus);
addr += 4; addr += 4;
} }
} }
}
self.gpr[rb] = addr as u32; self.gpr[rb] = addr as u32;

View file

@ -330,15 +330,8 @@ impl ThumbInstruction {
self.raw.bit(bit) self.raw.bit(bit)
} }
pub fn register_list(&self) -> Vec<usize> { pub fn register_list(&self) -> u8 {
let list_bits = self.raw & 0xff; (self.raw & 0xff) as u8
let mut list = Vec::with_capacity(8);
for i in 0..8 {
if (list_bits & (1 << i)) != 0 {
list.push(i)
}
}
list
} }
pub fn sword7(&self) -> i32 { pub fn sword7(&self) -> i32 {