Skip to content

Commit

Permalink
SPC700: implement AND1, EOR1, OR1, NOT1, MOV1
Browse files Browse the repository at this point in the history
  • Loading branch information
twvd committed Nov 25, 2023
1 parent 5e5a6e2 commit 5dc793a
Show file tree
Hide file tree
Showing 2 changed files with 105 additions and 8 deletions.
97 changes: 97 additions & 0 deletions src/snes/cpu_spc700/cpu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,11 @@ where
InstructionType::BVS => self.op_branch(instr, self.regs.test_flag(Flag::V)),
InstructionType::BRA => self.op_branch(instr, true),
InstructionType::ADDW => self.op_addw(instr),
InstructionType::AND1 => self.op_and1(instr),
InstructionType::EOR1 => self.op_eor1(instr),
InstructionType::OR1 => self.op_or1(instr),
InstructionType::MOV1 => self.op_mov1(instr),
InstructionType::NOT1 => self.op_not1(instr),
_ => todo!(),
}
}
Expand Down Expand Up @@ -382,10 +387,31 @@ where
.wrapping_add(self.regs.read(Register::Y));
Ok((imm_idx + 1, self.read_tick(addr), Some(addr)))
}
Operand::AbsoluteBooleanBit | Operand::AbsoluteNotBooleanBit => unreachable!(),

_ => todo!(),
}
}

/// Resolve an address for the m.b addressing modes
fn resolve_address_mb(&mut self, instr: &Instruction) -> (SpcAddress, u8) {
let i = instr.imm16();
let bit = (i >> 13) as u8;
(i & 0x1FFF, bit)
}

/// Resolve bit for the m.b addressing modes
fn resolve_value_mb(&mut self, instr: &Instruction, opidx: usize) -> bool {
let (addr, bit) = self.resolve_address_mb(instr);
let val = self.read_tick(addr);

match instr.def.operands[opidx] {
Operand::AbsoluteBooleanBit => (val & (1 << bit)) != 0,
Operand::AbsoluteNotBooleanBit => (val & (1 << bit)) == 0,
_ => unreachable!(),
}
}

/// Translate 8-bit relative address from operands
/// to a full address (P flag).
fn map_pageflag<T: Into<SpcAddress>>(&self, addr: T) -> SpcAddress {
Expand Down Expand Up @@ -903,4 +929,75 @@ where

Ok(())
}

/// AND1
fn op_and1(&mut self, instr: &Instruction) -> Result<()> {
let val = self.resolve_value_mb(instr, 1);
let result = self.regs.test_flag(Flag::C) & val;
self.regs.write_flags(&[(Flag::C, result)]);

Ok(())
}

/// EOR1
fn op_eor1(&mut self, instr: &Instruction) -> Result<()> {
let val = self.resolve_value_mb(instr, 1);
let result = self.regs.test_flag(Flag::C) ^ val;
self.regs.write_flags(&[(Flag::C, result)]);

// Internal cycle
self.tick_bus(1)?;

Ok(())
}

/// OR1
fn op_or1(&mut self, instr: &Instruction) -> Result<()> {
let val = self.resolve_value_mb(instr, 1);
let result = self.regs.test_flag(Flag::C) | val;
self.regs.write_flags(&[(Flag::C, result)]);

// Internal cycle
self.tick_bus(1)?;

Ok(())
}

/// MOV1
fn op_mov1(&mut self, instr: &Instruction) -> Result<()> {
match instr.def.operands[0] {
Operand::AbsoluteBooleanBit => {
// MOV1 m.b, C
let (addr, bit) = self.resolve_address_mb(instr);
let val = self.read_tick(addr);
let result = if self.regs.test_flag(Flag::C) {
val | (1 << bit)
} else {
val & !(1 << bit)
};

// Internal cycle
self.tick_bus(1)?;

self.write_tick(addr, result);
}
Operand::None => {
// MOV1 C, m.b
let result = self.resolve_value_mb(instr, 1);
self.regs.write_flags(&[(Flag::C, result)]);
}
_ => unreachable!(),
}

Ok(())
}

/// NOT1
fn op_not1(&mut self, instr: &Instruction) -> Result<()> {
let (addr, bit) = self.resolve_address_mb(instr);
let val = self.read_tick(addr);
self.write_tick(addr, val ^ (1 << bit));

Ok(())
}
}
16 changes: 8 additions & 8 deletions src/test/processortests_spc700.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,8 +121,8 @@ fn run_testcase(testcase: &Value, check_trace: bool, multi_steps: bool) {
dbg!(testcase);
dbg_hex!(bus_trace);
panic!(
"Addr {:06X} - expected {:02X}, saw {:02X}",
addr, exp_val, val
"Addr {:06X} - expected {:02X}, saw {:02X} - registers: {}",
addr, exp_val, val, cpu.regs
);
}
}
Expand Down Expand Up @@ -259,7 +259,7 @@ cpu_test!(instr_48, 0x48);
// Decoder reads immediate values first but real CPU follows the
// first indirection first.
cpu_test_no_trace!(instr_49, 0x49);
//cpu_test!(instr_4a, 0x4a);
cpu_test!(instr_4a, 0x4a);
cpu_test!(instr_4b, 0x4b);
cpu_test!(instr_4c, 0x4c);
cpu_test!(instr_4d, 0x4d);
Expand Down Expand Up @@ -294,7 +294,7 @@ cpu_test!(instr_67, 0x67);
cpu_test!(instr_68, 0x68);
// Read indirection during fetch
cpu_test_no_trace!(instr_69, 0x69);
//cpu_test!(instr_6a, 0x6a);
cpu_test!(instr_6a, 0x6a);
//cpu_test!(instr_6b, 0x6b);
//cpu_test!(instr_6c, 0x6c);
cpu_test!(instr_6d, 0x6d);
Expand Down Expand Up @@ -328,7 +328,7 @@ cpu_test!(instr_87, 0x87);
cpu_test!(instr_88, 0x88);
// Read indirection during fetch
cpu_test_no_trace!(instr_89, 0x89);
//cpu_test!(instr_8a, 0x8a);
cpu_test!(instr_8a, 0x8a);
cpu_test!(instr_8b, 0x8b);
cpu_test!(instr_8c, 0x8c);
cpu_test!(instr_8d, 0x8d);
Expand Down Expand Up @@ -362,7 +362,7 @@ cpu_test!(instr_a7, 0xa7);
cpu_test!(instr_a8, 0xa8);
// Read indirection during fetch
cpu_test_no_trace!(instr_a9, 0xa9);
//cpu_test!(instr_aa, 0xaa);
cpu_test!(instr_aa, 0xaa);
cpu_test!(instr_ab, 0xab);
cpu_test!(instr_ac, 0xac);
cpu_test!(instr_ad, 0xad);
Expand Down Expand Up @@ -396,7 +396,7 @@ cpu_test!(instr_c6, 0xc6);
cpu_test!(instr_c7, 0xc7);
//cpu_test!(instr_c8, 0xc8);
cpu_test!(instr_c9, 0xc9);
//cpu_test!(instr_ca, 0xca);
cpu_test!(instr_ca, 0xca);
cpu_test!(instr_cb, 0xcb);
cpu_test!(instr_cc, 0xcc);
cpu_test!(instr_cd, 0xcd);
Expand Down Expand Up @@ -429,7 +429,7 @@ cpu_test!(instr_e6, 0xe6);
cpu_test!(instr_e7, 0xe7);
cpu_test!(instr_e8, 0xe8);
cpu_test!(instr_e9, 0xe9);
//cpu_test!(instr_ea, 0xea);
cpu_test!(instr_ea, 0xea);
cpu_test!(instr_eb, 0xeb);
cpu_test!(instr_ec, 0xec);
cpu_test!(instr_ed, 0xed);
Expand Down

0 comments on commit 5dc793a

Please sign in to comment.