mirror of
https://github.com/FranLMSP/snes.git
synced 2026-10-02 07:25:19 -04:00
PEA and PEI instructions
This commit is contained in:
@@ -267,6 +267,19 @@ impl CPU {
|
|||||||
let (bytes, cycles) = self.common_conditions(addressing_mode, &LD_INDEX_CONDITIONS);
|
let (bytes, cycles) = self.common_conditions(addressing_mode, &LD_INDEX_CONDITIONS);
|
||||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn increment_cycles_pea(&mut self) {
|
||||||
|
self.registers.increment_pc(3); self.cycles += 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn increment_cycles_pei(&mut self) {
|
||||||
|
self.registers.increment_pc(2); self.cycles += 6;
|
||||||
|
let (bytes, cycles) = self.common_conditions(
|
||||||
|
AddressingMode::DirectPageIndirect,
|
||||||
|
&[Condition::DirectPageIsZero],
|
||||||
|
);
|
||||||
|
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|||||||
@@ -369,7 +369,7 @@ impl CPU {
|
|||||||
self.increment_cycles_bit(addressing_mode);
|
self.increment_cycles_bit(addressing_mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn do_branch(&mut self, bus: &Bus) -> bool {
|
fn do_branch(&mut self, bus: &Bus) -> bool {
|
||||||
let nearlabel = bus.read(self.registers.get_pc_address());
|
let nearlabel = bus.read(self.registers.get_pc_address());
|
||||||
let is_negative = (nearlabel >> 7) != 0;
|
let is_negative = (nearlabel >> 7) != 0;
|
||||||
let old_pc = self.registers.get_pc_address();
|
let old_pc = self.registers.get_pc_address();
|
||||||
@@ -384,7 +384,7 @@ impl CPU {
|
|||||||
return page_boundary_crossed
|
return page_boundary_crossed
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn bcc(&mut self, bus: &Bus) {
|
fn bcc(&mut self, bus: &Bus) {
|
||||||
self.increment_cycles_branch();
|
self.increment_cycles_branch();
|
||||||
if !self.registers.get_carry_flag() {
|
if !self.registers.get_carry_flag() {
|
||||||
let page_boundary_crossed = self.do_branch(bus);
|
let page_boundary_crossed = self.do_branch(bus);
|
||||||
@@ -392,7 +392,7 @@ impl CPU {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn bcs(&mut self, bus: &Bus) {
|
fn bcs(&mut self, bus: &Bus) {
|
||||||
self.increment_cycles_branch();
|
self.increment_cycles_branch();
|
||||||
if self.registers.get_carry_flag() {
|
if self.registers.get_carry_flag() {
|
||||||
let page_boundary_crossed = self.do_branch(bus);
|
let page_boundary_crossed = self.do_branch(bus);
|
||||||
@@ -400,7 +400,7 @@ impl CPU {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn beq(&mut self, bus: &Bus) {
|
fn beq(&mut self, bus: &Bus) {
|
||||||
self.increment_cycles_branch();
|
self.increment_cycles_branch();
|
||||||
if self.registers.get_zero_flag() {
|
if self.registers.get_zero_flag() {
|
||||||
let page_boundary_crossed = self.do_branch(bus);
|
let page_boundary_crossed = self.do_branch(bus);
|
||||||
@@ -408,7 +408,7 @@ impl CPU {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn bne(&mut self, bus: &Bus) {
|
fn bne(&mut self, bus: &Bus) {
|
||||||
self.increment_cycles_branch();
|
self.increment_cycles_branch();
|
||||||
if !self.registers.get_zero_flag() {
|
if !self.registers.get_zero_flag() {
|
||||||
let page_boundary_crossed = self.do_branch(bus);
|
let page_boundary_crossed = self.do_branch(bus);
|
||||||
@@ -416,7 +416,7 @@ impl CPU {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn bmi(&mut self, bus: &Bus) {
|
fn bmi(&mut self, bus: &Bus) {
|
||||||
self.increment_cycles_branch();
|
self.increment_cycles_branch();
|
||||||
if self.registers.get_negative_flag() {
|
if self.registers.get_negative_flag() {
|
||||||
let page_boundary_crossed = self.do_branch(bus);
|
let page_boundary_crossed = self.do_branch(bus);
|
||||||
@@ -424,7 +424,7 @@ impl CPU {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn bpl(&mut self, bus: &Bus) {
|
fn bpl(&mut self, bus: &Bus) {
|
||||||
self.increment_cycles_branch();
|
self.increment_cycles_branch();
|
||||||
if !self.registers.get_negative_flag() {
|
if !self.registers.get_negative_flag() {
|
||||||
let page_boundary_crossed = self.do_branch(bus);
|
let page_boundary_crossed = self.do_branch(bus);
|
||||||
@@ -432,13 +432,13 @@ impl CPU {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn bra(&mut self, bus: &Bus) {
|
fn bra(&mut self, bus: &Bus) {
|
||||||
self.increment_cycles_branch();
|
self.increment_cycles_branch();
|
||||||
let page_boundary_crossed = self.do_branch(bus);
|
let page_boundary_crossed = self.do_branch(bus);
|
||||||
self.increment_cycles_branch_taken(page_boundary_crossed);
|
self.increment_cycles_branch_taken(page_boundary_crossed);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn brl(&mut self, bus: &Bus) {
|
fn brl(&mut self, bus: &Bus) {
|
||||||
let label = bus.read(self.registers.get_pc_address()) as u16 |
|
let label = bus.read(self.registers.get_pc_address()) as u16 |
|
||||||
((bus.read(self.registers.get_pc_address() + 1) as u16) << 8);
|
((bus.read(self.registers.get_pc_address() + 1) as u16) << 8);
|
||||||
let is_negative = (label >> 15) != 0;
|
let is_negative = (label >> 15) != 0;
|
||||||
@@ -451,7 +451,7 @@ impl CPU {
|
|||||||
self.increment_cycles_branch_long();
|
self.increment_cycles_branch_long();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn bvc(&mut self, bus: &Bus) {
|
fn bvc(&mut self, bus: &Bus) {
|
||||||
self.increment_cycles_branch();
|
self.increment_cycles_branch();
|
||||||
if !self.registers.get_overflow_flag() {
|
if !self.registers.get_overflow_flag() {
|
||||||
let page_boundary_crossed = self.do_branch(bus);
|
let page_boundary_crossed = self.do_branch(bus);
|
||||||
@@ -459,7 +459,7 @@ impl CPU {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn bvs(&mut self, bus: &Bus) {
|
fn bvs(&mut self, bus: &Bus) {
|
||||||
self.increment_cycles_branch();
|
self.increment_cycles_branch();
|
||||||
if self.registers.get_overflow_flag() {
|
if self.registers.get_overflow_flag() {
|
||||||
let page_boundary_crossed = self.do_branch(bus);
|
let page_boundary_crossed = self.do_branch(bus);
|
||||||
@@ -467,31 +467,31 @@ impl CPU {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clc(&mut self) {
|
fn clc(&mut self) {
|
||||||
self.registers.set_carry_flag(false);
|
self.registers.set_carry_flag(false);
|
||||||
self.increment_cycles_clear();
|
self.increment_cycles_clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cld(&mut self) {
|
fn cld(&mut self) {
|
||||||
self.registers.set_decimal_mode_flag(false);
|
self.registers.set_decimal_mode_flag(false);
|
||||||
self.increment_cycles_clear();
|
self.increment_cycles_clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cli(&mut self) {
|
fn cli(&mut self) {
|
||||||
self.registers.set_irq_disable_flag(false);
|
self.registers.set_irq_disable_flag(false);
|
||||||
self.increment_cycles_clear();
|
self.increment_cycles_clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clv(&mut self) {
|
fn clv(&mut self) {
|
||||||
self.registers.set_overflow_flag(false);
|
self.registers.set_overflow_flag(false);
|
||||||
self.increment_cycles_clear();
|
self.increment_cycles_clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn nop(&mut self) {
|
fn nop(&mut self) {
|
||||||
self.increment_cycles_nop();
|
self.increment_cycles_nop();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn jmp(&mut self, bus: &Bus, addressing_mode: AddressingMode) {
|
fn jmp(&mut self, bus: &Bus, addressing_mode: AddressingMode) {
|
||||||
let effective_address = self.get_effective_address(bus, addressing_mode);
|
let effective_address = self.get_effective_address(bus, addressing_mode);
|
||||||
let is_long = match addressing_mode {
|
let is_long = match addressing_mode {
|
||||||
AddressingMode::AbsoluteLong |
|
AddressingMode::AbsoluteLong |
|
||||||
@@ -505,7 +505,7 @@ impl CPU {
|
|||||||
self.increment_cycles_jmp(addressing_mode);
|
self.increment_cycles_jmp(addressing_mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn do_push(&mut self, bus: &mut Bus, bytes: &[u8]) {
|
fn do_push(&mut self, bus: &mut Bus, bytes: &[u8]) {
|
||||||
for byte in bytes {
|
for byte in bytes {
|
||||||
let address = self.registers.sp as u32;
|
let address = self.registers.sp as u32;
|
||||||
bus.write(address, *byte);
|
bus.write(address, *byte);
|
||||||
@@ -513,7 +513,19 @@ impl CPU {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn jsr(&mut self, bus: &mut Bus, addressing_mode: AddressingMode) {
|
fn pea(&mut self, bus: &mut Bus) {
|
||||||
|
let address = self.get_effective_address(bus, AddressingMode::Absolute);
|
||||||
|
self.do_push(bus, &[(address >> 8) as u8, address as u8]);
|
||||||
|
self.increment_cycles_pea();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pei(&mut self, bus: &mut Bus) {
|
||||||
|
let address = self.get_effective_address(bus, AddressingMode::DirectPageIndirect);
|
||||||
|
self.do_push(bus, &[(address >> 8) as u8, address as u8]);
|
||||||
|
self.increment_cycles_pei();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn jsr(&mut self, bus: &mut Bus, addressing_mode: AddressingMode) {
|
||||||
let effective_address = self.get_effective_address(bus, addressing_mode);
|
let effective_address = self.get_effective_address(bus, addressing_mode);
|
||||||
let is_long = match addressing_mode {
|
let is_long = match addressing_mode {
|
||||||
AddressingMode::AbsoluteLong |
|
AddressingMode::AbsoluteLong |
|
||||||
@@ -816,6 +828,10 @@ impl CPU {
|
|||||||
0x17 => self.ora(bus, A::DirectPageIndirectLongIndexed(I::Y)),
|
0x17 => self.ora(bus, A::DirectPageIndirectLongIndexed(I::Y)),
|
||||||
0x03 => self.ora(bus, A::StackRelative),
|
0x03 => self.ora(bus, A::StackRelative),
|
||||||
0x13 => self.ora(bus, A::StackRelativeIndirectIndexed(I::Y)),
|
0x13 => self.ora(bus, A::StackRelativeIndirectIndexed(I::Y)),
|
||||||
|
// PEA
|
||||||
|
0xF4 => self.pea(bus),
|
||||||
|
// PEI
|
||||||
|
0xD4 => self.pei(bus),
|
||||||
_ => println!("Invalid opcode: {:02X}", opcode),
|
_ => println!("Invalid opcode: {:02X}", opcode),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1630,4 +1646,19 @@ mod cpu_instructions_tests {
|
|||||||
assert!(cpu.registers.get_negative_flag());
|
assert!(cpu.registers.get_negative_flag());
|
||||||
assert!(!cpu.registers.get_zero_flag());
|
assert!(!cpu.registers.get_zero_flag());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_push_instructions() {
|
||||||
|
let mut cpu = CPU::new();
|
||||||
|
let mut bus = Bus::new();
|
||||||
|
cpu.registers.pc = 0x0000;
|
||||||
|
cpu.registers.sp = 0x1FC;
|
||||||
|
bus.write(0x000002, 0xAA);
|
||||||
|
bus.write(0x000001, 0xBB);
|
||||||
|
cpu.pea(&mut bus);
|
||||||
|
assert_eq!(bus.read(0x1FC), 0xAA);
|
||||||
|
assert_eq!(bus.read(0x1FB), 0xBB);
|
||||||
|
assert_eq!(cpu.registers.pc, 0x0003);
|
||||||
|
assert_eq!(cpu.cycles, 5);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user