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

View file

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

View file

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

View file

@ -209,21 +209,27 @@ impl ThumbInstruction {
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 {
write!(f, "{}\t{{", if self.is_load() { "pop" } else { "push" })?;
let mut register_list = self.register_list().into_iter();
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))?;
}
let rlist = self.register_list();
self.fmt_register_list(f, rlist)?;
if self.flag(ThumbInstruction::FLAG_R) {
let r = if self.is_load() { "pc" } else { "lr" };
if has_reg {
if rlist != 0 {
write!(f, ", {}", r)?;
} else {
write!(f, "{}", r)?;
@ -239,16 +245,7 @@ impl ThumbInstruction {
op = if self.is_load() { "ldm" } else { "stm" },
Rb = reg_string(self.rb()),
)?;
let mut register_list = self.register_list().into_iter();
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))?;
}
self.fmt_register_list(f, self.register_list())?;
write!(f, "}}")
}

View file

@ -313,14 +313,14 @@ impl Core {
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).
let is_pop = insn.is_load();
let pc_lr_flag = insn.flag(ThumbInstruction::FLAG_R);
let rlist = insn.register_list();
if is_pop {
for r in rlist {
pop(self, bus, r);
for r in 0..8 {
if rlist.bit(r) {
pop(self, bus, r);
}
}
if pc_lr_flag {
pop(self, bus, REG_PC);
@ -332,8 +332,10 @@ impl Core {
if pc_lr_flag {
push(self, bus, REG_LR);
}
for r in rlist.into_iter().rev() {
push(self, bus, r);
for r in (0..8).rev() {
if rlist.bit(r) {
push(self, bus, r);
}
}
}
@ -349,16 +351,20 @@ impl Core {
let mut addr = self.gpr[rb];
let rlist = insn.register_list();
if is_load {
for r in rlist {
let val = self.load_32(addr, bus);
addr += 4;
self.add_cycle();
self.set_reg(r, val);
for r in 0..8 {
if rlist.bit(r) {
let val = self.load_32(addr, bus);
addr += 4;
self.add_cycle();
self.set_reg(r, val);
}
}
} else {
for r in rlist {
self.store_32(addr, self.gpr[r], bus);
addr += 4;
for r in 0..8 {
if rlist.bit(r) {
self.store_32(addr, self.gpr[r], bus);
addr += 4;
}
}
}

View file

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