Optimize instructions with "register lists" (LDM_STM)
These instruction (probably) allocated a vector each time. Former-commit-id: 66f724e21e1e5d667d19c1f21d2cc4fa3944faac
This commit is contained in:
parent
7119ba2451
commit
0f73abaf98
|
@ -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) {
|
||||||
for reg in register_list {
|
if has_first {
|
||||||
write!(f, ", {}", reg_string(reg))?;
|
write!(f, ", {}", reg_string(i))?;
|
||||||
|
} else {
|
||||||
|
write!(f, "{}", reg_string(i))?;
|
||||||
|
has_first = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"}}{}",
|
"}}{}",
|
||||||
|
|
|
@ -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,54 +328,54 @@ 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 {
|
||||||
writeback = false;
|
let r = if ascending { r } else { 15 - r };
|
||||||
}
|
if rlist.bit(r) {
|
||||||
for r in rlist {
|
if r == rn {
|
||||||
if full {
|
writeback = false;
|
||||||
addr = addr.wrapping_add(step);
|
}
|
||||||
}
|
if full {
|
||||||
|
addr = addr.wrapping_add(step);
|
||||||
|
}
|
||||||
|
|
||||||
self.add_cycle();
|
self.add_cycle();
|
||||||
let val = self.load_32(addr as Addr, bus);
|
let val = self.load_32(addr as Addr, bus);
|
||||||
self.set_reg(r, val);
|
self.set_reg(r, val);
|
||||||
|
|
||||||
if r == REG_PC {
|
if r == REG_PC {
|
||||||
self.flush_pipeline();
|
self.flush_pipeline();
|
||||||
}
|
}
|
||||||
|
|
||||||
if !full {
|
if !full {
|
||||||
addr = addr.wrapping_add(step);
|
addr = addr.wrapping_add(step);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for r in rlist {
|
for r in 0..16 {
|
||||||
if full {
|
let r = if ascending { r } else { 15 - r };
|
||||||
addr = addr.wrapping_add(step);
|
if rlist.bit(r) {
|
||||||
}
|
if full {
|
||||||
|
addr = addr.wrapping_add(step);
|
||||||
|
}
|
||||||
|
|
||||||
let val = if r == REG_PC {
|
let val = if r == REG_PC {
|
||||||
insn.pc + 12
|
insn.pc + 12
|
||||||
} else {
|
} else {
|
||||||
self.get_reg(r)
|
self.get_reg(r)
|
||||||
};
|
};
|
||||||
self.store_32(addr as Addr, val, bus);
|
self.store_32(addr as Addr, val, bus);
|
||||||
|
|
||||||
if !full {
|
if !full {
|
||||||
addr = addr.wrapping_add(step);
|
addr = addr.wrapping_add(step);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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, "}}")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -313,14 +313,14 @@ 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 {
|
||||||
pop(self, bus, r);
|
if rlist.bit(r) {
|
||||||
|
pop(self, bus, r);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if pc_lr_flag {
|
if pc_lr_flag {
|
||||||
pop(self, bus, REG_PC);
|
pop(self, bus, REG_PC);
|
||||||
|
@ -332,8 +332,10 @@ 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() {
|
||||||
push(self, bus, r);
|
if rlist.bit(r) {
|
||||||
|
push(self, bus, r);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -349,16 +351,20 @@ 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 {
|
||||||
let val = self.load_32(addr, bus);
|
if rlist.bit(r) {
|
||||||
addr += 4;
|
let val = self.load_32(addr, bus);
|
||||||
self.add_cycle();
|
addr += 4;
|
||||||
self.set_reg(r, val);
|
self.add_cycle();
|
||||||
|
self.set_reg(r, val);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for r in rlist {
|
for r in 0..8 {
|
||||||
self.store_32(addr, self.gpr[r], bus);
|
if rlist.bit(r) {
|
||||||
addr += 4;
|
self.store_32(addr, self.gpr[r], bus);
|
||||||
|
addr += 4;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
Reference in a new issue