Skip to content

Commit

Permalink
65816: implement STZ
Browse files Browse the repository at this point in the history
  • Loading branch information
twvd committed Oct 14, 2023
1 parent 28f7bdc commit 8b38511
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 8 deletions.
80 changes: 76 additions & 4 deletions src/snes/cpu_65816/cpu.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use anyhow::Result;

use crate::snes::bus::{Address, Bus, BusIterator};
use crate::snes::bus::{Address, Bus, BusIterator, ADDRESS_MASK};
use crate::tickable::Ticks;

use super::instruction::{Instruction, InstructionType};
use super::instruction::{AddressingMode, Instruction, InstructionType};
use super::regs::{Flag, Register, RegisterFile};

/// Main SNES CPU (65816)
Expand Down Expand Up @@ -70,8 +70,6 @@ where
let instr = self.fetch_next_instr()?;

let _cycles = self.execute_instruction(&instr)?;

// TODO program bank?
self.regs.pc = self.regs.pc.wrapping_add(instr.len as u16);

Ok(())
Expand All @@ -95,6 +93,24 @@ where
v
}

/// Writes a memory location while ticking peripherals
/// for the access time.
fn write_tick(&mut self, addr: Address, val: u8) {
self.bus.write(addr, val);
self.tick_bus(1).unwrap();
}

/// Writes 16-bit to a memory location while ticking
/// peripherals for the access time.
/// 16-bit address wrap.
fn write16_tick_a16(&mut self, addr: Address, val: u16) {
self.bus.write(addr, (val & 0xFF) as u8);
self.tick_bus(1).unwrap();
let hi_addr = addr & 0xFFFF0000 | Address::from((addr as u16).wrapping_add(1));
self.bus.write(hi_addr, (val >> 8) as u8);
self.tick_bus(1).unwrap();
}

fn execute_instruction(&mut self, instr: &Instruction) -> Result<()> {
match instr.def.instr_type {
InstructionType::NOP => self.tick_bus(1),
Expand All @@ -120,6 +136,8 @@ where
InstructionType::TXY => self.op_txx(Register::X, Register::Y, Flag::X),
InstructionType::TYA => self.op_txx(Register::Y, Register::C, Flag::M),
InstructionType::TYX => self.op_txx(Register::Y, Register::X, Flag::X),
InstructionType::STZ => self.op_stz(&instr),

_ => todo!(),
}
}
Expand Down Expand Up @@ -192,4 +210,58 @@ where
}
self.tick_bus(1)
}

/// STZ - Store zero
fn op_stz(&mut self, instr: &Instruction) -> Result<()> {
let addr = self.resolve_address(instr)?;

// Extra internal cycles
if (instr.def.mode == AddressingMode::Direct || instr.def.mode == AddressingMode::DirectX)
&& self.regs.read(Register::DL) != 0
{
self.tick_bus(1)?;
}
if instr.def.mode == AddressingMode::DirectX || instr.def.mode == AddressingMode::AbsoluteX
{
self.tick_bus(1)?;
}

if self.regs.test_flag(Flag::M) {
self.write_tick(addr, 0);
} else {
self.write16_tick_a16(addr, 0);
}

Ok(())
}

/// Resolves an address from instruction data, registers, etc.
/// based on the addressing mode.
fn resolve_address(&self, instr: &Instruction) -> Result<Address> {
Ok(match instr.def.mode {
AddressingMode::Direct => Address::from(
self.regs
.read(Register::D)
.wrapping_add(instr.imm::<u16>()?),
),
AddressingMode::DirectX => Address::from(
self.regs
.read(Register::D)
.wrapping_add(instr.imm::<u16>()?)
.wrapping_add(self.regs.read(Register::X)),
),
AddressingMode::Absolute => {
Address::from(self.regs.read(Register::DBR)) << 16
| Address::from(instr.imm::<u16>()?)
}
AddressingMode::AbsoluteX => {
(Address::from(self.regs.read(Register::DBR)) << 16
| Address::from(instr.imm::<u16>()?))
.wrapping_add(Address::from(self.regs.read(Register::X)))
& ADDRESS_MASK
}

_ => todo!(),
})
}
}
12 changes: 12 additions & 0 deletions src/snes/cpu_65816/instruction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use thiserror::Error;
use super::instruction_table::INSTRUCTION_TABLE;

/// Instruction addressing mode
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum AddressingMode {
/// Absolute
/// 3 bytes, $OP $LL $HH
Expand Down Expand Up @@ -294,6 +295,17 @@ impl Instruction {
len,
})
}

/// Reads the immediate value for addressing modes that
/// have one immediate value.
pub fn imm<T: std::convert::TryFrom<u32>>(&self) -> Result<T>
where
anyhow::Error: From<T::Error>,
{
assert_ne!(self.def.mode, AddressingMode::SrcDest);
assert_ne!(self.def.mode, AddressingMode::Implied);
Ok(self.immediate[0].try_into()?)
}
}

impl fmt::Display for Instruction {
Expand Down
8 changes: 4 additions & 4 deletions src/test/processortests_65816.rs
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ cpu_test!(instr_5b, 0x5b);
//cpu_test!(instr_61, 0x61);
//cpu_test!(instr_62, 0x62);
//cpu_test!(instr_63, 0x63);
//cpu_test!(instr_64, 0x64);
cpu_test!(instr_64, 0x64);
//cpu_test!(instr_65, 0x65);
//cpu_test!(instr_66, 0x66);
//cpu_test!(instr_67, 0x67);
Expand All @@ -252,7 +252,7 @@ cpu_test!(instr_5b, 0x5b);
//cpu_test!(instr_71, 0x71);
//cpu_test!(instr_72, 0x72);
//cpu_test!(instr_73, 0x73);
//cpu_test!(instr_74, 0x74);
cpu_test!(instr_74, 0x74);
//cpu_test!(instr_75, 0x75);
//cpu_test!(instr_76, 0x76);
//cpu_test!(instr_77, 0x77);
Expand Down Expand Up @@ -292,9 +292,9 @@ cpu_test!(instr_98, 0x98);
//cpu_test!(instr_99, 0x99);
cpu_test!(instr_9a, 0x9a);
cpu_test!(instr_9b, 0x9b);
//cpu_test!(instr_9c, 0x9c);
cpu_test!(instr_9c, 0x9c);
//cpu_test!(instr_9d, 0x9d);
//cpu_test!(instr_9e, 0x9e);
cpu_test!(instr_9e, 0x9e);
//cpu_test!(instr_9f, 0x9f);
//cpu_test!(instr_a0, 0xa0);
//cpu_test!(instr_a1, 0xa1);
Expand Down

0 comments on commit 8b38511

Please sign in to comment.