mirror of
https://github.com/FranLMSP/snes.git
synced 2026-10-03 16:05:18 -04:00
LSR instruction
This commit is contained in:
@@ -299,6 +299,26 @@ impl CPU {
|
|||||||
self.increment_cycles_shift(addressing_mode);
|
self.increment_cycles_shift(addressing_mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn lsr(&mut self, bus: &mut Bus, addressing_mode: AddressingMode) {
|
||||||
|
let target = match addressing_mode {
|
||||||
|
AddressingMode::Accumulator => self.registers.a,
|
||||||
|
_ => match self.registers.is_16bit_mode() {
|
||||||
|
true => self.get_16bit_from_address(bus, addressing_mode),
|
||||||
|
false => self.get_8bit_from_address(bus, addressing_mode) as u16,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if self.registers.is_16bit_mode() {
|
||||||
|
let (result, affected_flags) = alu::lsr(target);
|
||||||
|
self.set_16bit_to_address(bus, addressing_mode, result);
|
||||||
|
self.registers.set_flags(&affected_flags);
|
||||||
|
} else {
|
||||||
|
let (result, affected_flags) = alu::lsr(target as u8);
|
||||||
|
self.set_8bit_to_address(bus, addressing_mode, result);
|
||||||
|
self.registers.set_flags(&affected_flags);
|
||||||
|
}
|
||||||
|
self.increment_cycles_shift(addressing_mode);
|
||||||
|
}
|
||||||
|
|
||||||
fn do_bit<T: SnesNum>(&mut self, accumulator: T, value: T, addressing_mode: AddressingMode) {
|
fn do_bit<T: SnesNum>(&mut self, accumulator: T, value: T, addressing_mode: AddressingMode) {
|
||||||
let (result, _) = alu::and(accumulator, value);
|
let (result, _) = alu::and(accumulator, value);
|
||||||
// Immediate addressing affects only the zero flag
|
// Immediate addressing affects only the zero flag
|
||||||
@@ -597,6 +617,12 @@ impl CPU {
|
|||||||
0xE8 => self.inx(),
|
0xE8 => self.inx(),
|
||||||
// INY
|
// INY
|
||||||
0xC8 => self.iny(),
|
0xC8 => self.iny(),
|
||||||
|
// LSR
|
||||||
|
0x4A => self.lsr(bus, A::Accumulator),
|
||||||
|
0x4E => self.lsr(bus, A::Absolute),
|
||||||
|
0x46 => self.lsr(bus, A::DirectPage),
|
||||||
|
0x5E => self.lsr(bus, A::AbsoluteIndexed(I::X)),
|
||||||
|
0x56 => self.lsr(bus, A::DirectPageIndexed(I::X)),
|
||||||
_ => println!("Invalid opcode: {:02X}", opcode),
|
_ => println!("Invalid opcode: {:02X}", opcode),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -691,6 +717,25 @@ mod cpu_instructions_tests {
|
|||||||
assert!(cpu.registers.get_negative_flag());
|
assert!(cpu.registers.get_negative_flag());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_lsr() {
|
||||||
|
let mut cpu = CPU::new();
|
||||||
|
let mut bus = Bus::new();
|
||||||
|
cpu.registers.a = 0b00000000_00000011;
|
||||||
|
cpu.registers.pbr = 0x00;
|
||||||
|
cpu.registers.pc = 0x0000;
|
||||||
|
cpu.registers.set_memory_select_flag(false);
|
||||||
|
cpu.registers.set_negative_flag(true);
|
||||||
|
cpu.registers.set_carry_flag(false);
|
||||||
|
cpu.lsr(&mut bus, AddressingMode::Accumulator);
|
||||||
|
assert_eq!(cpu.registers.a, 0b00000000_00000001);
|
||||||
|
assert_eq!(cpu.registers.pc, 0x01);
|
||||||
|
assert_eq!(cpu.cycles, 4);
|
||||||
|
assert!(cpu.registers.get_carry_flag());
|
||||||
|
assert!(!cpu.registers.get_zero_flag());
|
||||||
|
assert!(!cpu.registers.get_negative_flag());
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_bit() {
|
fn test_bit() {
|
||||||
let mut cpu = CPU::new();
|
let mut cpu = CPU::new();
|
||||||
@@ -1262,4 +1307,13 @@ 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_nop() {
|
||||||
|
let mut cpu = CPU::new();
|
||||||
|
cpu.registers.pc = 0x0000;
|
||||||
|
cpu.nop();
|
||||||
|
assert_eq!(cpu.registers.pc, 0x01);
|
||||||
|
assert_eq!(cpu.cycles, 2);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -109,6 +109,15 @@ pub fn asl<T: SnesNum>(target: T) -> (T, [Flags; 3]) {
|
|||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn lsr<T: SnesNum>(target: T) -> (T, [Flags; 3]) {
|
||||||
|
let result = target.lsr();
|
||||||
|
(result, [
|
||||||
|
Negative(false),
|
||||||
|
Zero(result.is_zero()),
|
||||||
|
Carry(result.to_u32() & 1 == 1), // High bit becomes carry
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
pub fn eor<T: SnesNum>(target: T, value: T) -> (T, [Flags; 2]) {
|
pub fn eor<T: SnesNum>(target: T, value: T) -> (T, [Flags; 2]) {
|
||||||
let result = target.xor(value);
|
let result = target.xor(value);
|
||||||
(result, [
|
(result, [
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ pub trait SnesNum: Copy + Clone + Sized + Eq + PartialEq {
|
|||||||
fn sbc_snes(&self, v: Self, carry: bool) -> Self;
|
fn sbc_snes(&self, v: Self, carry: bool) -> Self;
|
||||||
fn and(&self, v: Self) -> Self;
|
fn and(&self, v: Self) -> Self;
|
||||||
fn asl(&self) -> Self;
|
fn asl(&self) -> Self;
|
||||||
|
fn lsr(&self) -> Self;
|
||||||
fn xor(&self, v: Self) -> Self;
|
fn xor(&self, v: Self) -> Self;
|
||||||
fn is_negative(&self) -> bool;
|
fn is_negative(&self) -> bool;
|
||||||
fn is_zero(&self) -> bool;
|
fn is_zero(&self) -> bool;
|
||||||
@@ -68,6 +69,10 @@ macro_rules! define_impl {
|
|||||||
(* self) << 1
|
(* self) << 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn lsr(&self) -> $t {
|
||||||
|
(* self) >> 1
|
||||||
|
}
|
||||||
|
|
||||||
fn xor(&self, v: $t) -> $t {
|
fn xor(&self, v: $t) -> $t {
|
||||||
(* self) ^ v
|
(* self) ^ v
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user