Skip to content

Commit

Permalink
65816: implement shift and rotate instructions
Browse files Browse the repository at this point in the history
  • Loading branch information
twvd committed Oct 18, 2023
1 parent 5f1d2c5 commit c674079
Show file tree
Hide file tree
Showing 2 changed files with 259 additions and 20 deletions.
239 changes: 239 additions & 0 deletions src/snes/cpu_65816/cpu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,22 @@ where
InstructionType::BIT => self.op_bit(instr),
InstructionType::TRB => self.op_trb(instr),
InstructionType::TSB => self.op_tsb(instr),
InstructionType::ASL if instr.def.mode == AddressingMode::Accumulator => {
self.op_asl_acc()
}
InstructionType::ASL => self.op_asl(instr),
InstructionType::LSR if instr.def.mode == AddressingMode::Accumulator => {
self.op_lsr_acc()
}
InstructionType::LSR => self.op_lsr(instr),
InstructionType::ROL if instr.def.mode == AddressingMode::Accumulator => {
self.op_rol_acc()
}
InstructionType::ROL => self.op_rol(instr),
InstructionType::ROR if instr.def.mode == AddressingMode::Accumulator => {
self.op_ror_acc()
}
InstructionType::ROR => self.op_ror(instr),

_ => todo!(),
}
Expand Down Expand Up @@ -908,4 +924,227 @@ where

Ok(())
}

/// ASL - Arithmetic Shift Left (register variant)
fn op_asl_acc(&mut self) -> Result<()> {
let val = self.regs.read(Register::C);
if self.regs.test_flag(Flag::M) {
// 8-bit
let result = (val << 1) as u8;
self.regs.write(Register::A, result.into());
self.regs.write_flags(&[
(Flag::Z, result == 0),
(Flag::N, result & 0x80 != 0),
(Flag::C, val & 0x80 != 0),
]);
} else {
// 16-bit
let result = val << 1;
self.regs.write(Register::C, result);
self.regs.write_flags(&[
(Flag::Z, result == 0),
(Flag::N, result & 0x8000 != 0),
(Flag::C, val & 0x8000 != 0),
]);
}

self.tick_bus(1)
}

/// ASL - Arithmetic Shift Left (memory variant)
fn op_asl(&mut self, instr: &Instruction) -> Result<()> {
let (val, addr) = self.fetch_data(instr, true, false, Flag::M)?;

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

if self.regs.test_flag(Flag::M) {
let result = (val << 1) as u8;
self.write_tick(addr, result);
self.regs.write_flags(&[
(Flag::Z, result == 0),
(Flag::N, result & 0x80 != 0),
(Flag::C, val & 0x80 != 0),
]);
} else {
// 16-bit
let result = val << 1;
self.write16_tick_a_desc(instr, addr, result);
self.regs.write_flags(&[
(Flag::Z, result == 0),
(Flag::N, result & 0x8000 != 0),
(Flag::C, val & 0x8000 != 0),
]);
}

Ok(())
}

/// LSR - Logical Shift Right (register variant)
fn op_lsr_acc(&mut self) -> Result<()> {
let val = self.regs.read(Register::C);
if self.regs.test_flag(Flag::M) {
// 8-bit
let result = (val as u8 >> 1) as u8;
self.regs.write(Register::A, result.into());
self.regs.write_flags(&[
(Flag::Z, result == 0),
(Flag::N, false),
(Flag::C, val & 0x01 != 0),
]);
} else {
// 16-bit
let result = val >> 1;
self.regs.write(Register::C, result);
self.regs.write_flags(&[
(Flag::Z, result == 0),
(Flag::N, false),
(Flag::C, val & 0x01 != 0),
]);
}

self.tick_bus(1)
}

/// LSR - Logical Shift Right (memory variant)
fn op_lsr(&mut self, instr: &Instruction) -> Result<()> {
let (val, addr) = self.fetch_data(instr, true, false, Flag::M)?;
// Calculation cycle
self.tick_bus(1)?;

if self.regs.test_flag(Flag::M) {
let result = (val as u8 >> 1) as u8;
self.write_tick(addr, result);
self.regs.write_flags(&[
(Flag::Z, result == 0),
(Flag::N, false),
(Flag::C, val & 0x01 != 0),
]);
} else {
// 16-bit
let result = val >> 1;
self.write16_tick_a_desc(instr, addr, result);
self.regs.write_flags(&[
(Flag::Z, result == 0),
(Flag::N, false),
(Flag::C, val & 0x01 != 0),
]);
}

Ok(())
}

/// ROL - ROtate Left (register variant)
fn op_rol_acc(&mut self) -> Result<()> {
let val = self.regs.read(Register::C);
let c = if self.regs.test_flag(Flag::C) { 1 } else { 0 };
if self.regs.test_flag(Flag::M) {
// 8-bit
let result = ((val << 1) | c) as u8;
self.regs.write(Register::A, result.into());
self.regs.write_flags(&[
(Flag::Z, result == 0),
(Flag::N, result & 0x80 != 0),
(Flag::C, val & 0x80 != 0),
]);
} else {
// 16-bit
let result = (val << 1) | c;
self.regs.write(Register::C, result);
self.regs.write_flags(&[
(Flag::Z, result == 0),
(Flag::N, result & 0x8000 != 0),
(Flag::C, val & 0x8000 != 0),
]);
}

self.tick_bus(1)
}

/// ROL - ROtate Left (memory variant)
fn op_rol(&mut self, instr: &Instruction) -> Result<()> {
let (val, addr) = self.fetch_data(instr, true, false, Flag::M)?;
let c = if self.regs.test_flag(Flag::C) { 1 } else { 0 };

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

if self.regs.test_flag(Flag::M) {
let result = ((val << 1) | c) as u8;
self.write_tick(addr, result);
self.regs.write_flags(&[
(Flag::Z, result == 0),
(Flag::N, result & 0x80 != 0),
(Flag::C, val & 0x80 != 0),
]);
} else {
// 16-bit
let result = (val << 1) | c;
self.write16_tick_a_desc(instr, addr, result);
self.regs.write_flags(&[
(Flag::Z, result == 0),
(Flag::N, result & 0x8000 != 0),
(Flag::C, val & 0x8000 != 0),
]);
}

Ok(())
}

/// ROR - ROtate Right (register variant)
fn op_ror_acc(&mut self) -> Result<()> {
let val = self.regs.read(Register::C);
let c = if self.regs.test_flag(Flag::C) { 1 } else { 0 };
if self.regs.test_flag(Flag::M) {
// 8-bit
let result = (((val & 0xFF) >> 1) | (c << 7)) as u8;
self.regs.write(Register::A, result.into());
self.regs.write_flags(&[
(Flag::Z, result == 0),
(Flag::N, result & 0x80 != 0),
(Flag::C, val & 0x01 != 0),
]);
} else {
// 16-bit
let result = (val >> 1) | (c << 15);
self.regs.write(Register::C, result);
self.regs.write_flags(&[
(Flag::Z, result == 0),
(Flag::N, result & 0x8000 != 0),
(Flag::C, val & 0x01 != 0),
]);
}

self.tick_bus(1)
}

/// ROR - ROtate Right (memory variant)
fn op_ror(&mut self, instr: &Instruction) -> Result<()> {
let (val, addr) = self.fetch_data(instr, true, false, Flag::M)?;
let c = if self.regs.test_flag(Flag::C) { 1 } else { 0 };

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

if self.regs.test_flag(Flag::M) {
let result = (((val & 0xFF) >> 1) | (c << 7)) as u8;
self.write_tick(addr, result);
self.regs.write_flags(&[
(Flag::Z, result == 0),
(Flag::N, result & 0x80 != 0),
(Flag::C, val & 0x01 != 0),
]);
} else {
// 16-bit
let result = (val >> 1) | (c << 15);
self.write16_tick_a_desc(instr, addr, result);
self.regs.write_flags(&[
(Flag::Z, result == 0),
(Flag::N, result & 0x8000 != 0),
(Flag::C, val & 0x01 != 0),
]);
}

Ok(())
}
}
40 changes: 20 additions & 20 deletions src/test/processortests_65816.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,127 +145,127 @@ cpu_test!(instr_01, 0x01);
cpu_test!(instr_03, 0x03);
cpu_test!(instr_04, 0x04);
cpu_test!(instr_05, 0x05);
//cpu_test!(instr_06, 0x06);
cpu_test!(instr_06, 0x06);
cpu_test!(instr_07, 0x07);
//cpu_test!(instr_08, 0x08);
cpu_test!(instr_09, 0x09);
//cpu_test!(instr_0a, 0x0a);
cpu_test!(instr_0a, 0x0a);
//cpu_test!(instr_0b, 0x0b);
cpu_test!(instr_0c, 0x0c);
cpu_test!(instr_0d, 0x0d);
//cpu_test!(instr_0e, 0x0e);
cpu_test!(instr_0e, 0x0e);
cpu_test!(instr_0f, 0x0f);
//cpu_test!(instr_10, 0x10e);
cpu_test!(instr_11, 0x11);
cpu_test!(instr_12, 0x12);
cpu_test!(instr_13, 0x13);
cpu_test!(instr_14, 0x14);
cpu_test!(instr_15, 0x15);
//cpu_test!(instr_16, 0x16);
cpu_test!(instr_16, 0x16);
cpu_test!(instr_17, 0x17);
cpu_test!(instr_18, 0x18);
cpu_test!(instr_19, 0x19);
cpu_test!(instr_1a, 0x1a);
cpu_test!(instr_1b, 0x1b);
cpu_test!(instr_1c, 0x1c);
cpu_test!(instr_1d, 0x1d);
//cpu_test!(instr_1e, 0x1e);
cpu_test!(instr_1e, 0x1e);
cpu_test!(instr_1f, 0x1f);
//cpu_test!(instr_20, 0x20);
cpu_test!(instr_21, 0x21);
//cpu_test!(instr_22, 0x22);
cpu_test!(instr_23, 0x23);
cpu_test!(instr_24, 0x24);
cpu_test!(instr_25, 0x25);
//cpu_test!(instr_26, 0x26);
cpu_test!(instr_26, 0x26);
cpu_test!(instr_27, 0x27);
//cpu_test!(instr_28, 0x28);
cpu_test!(instr_29, 0x29);
//cpu_test!(instr_2a, 0x2a);
cpu_test!(instr_2a, 0x2a);
//cpu_test!(instr_2b, 0x2b);
cpu_test!(instr_2c, 0x2c);
cpu_test!(instr_2d, 0x2d);
//cpu_test!(instr_2e, 0x2e);
cpu_test!(instr_2e, 0x2e);
cpu_test!(instr_2f, 0x2f);
//cpu_test!(instr_30, 0x30);
cpu_test!(instr_31, 0x31);
cpu_test!(instr_32, 0x32);
cpu_test!(instr_33, 0x33);
cpu_test!(instr_34, 0x34);
cpu_test!(instr_35, 0x35);
//cpu_test!(instr_36, 0x36);
cpu_test!(instr_36, 0x36);
cpu_test!(instr_37, 0x37);
cpu_test!(instr_38, 0x38);
cpu_test!(instr_39, 0x39);
cpu_test!(instr_3a, 0x3a);
cpu_test!(instr_3b, 0x3b);
cpu_test!(instr_3c, 0x3c);
cpu_test!(instr_3d, 0x3d);
//cpu_test!(instr_3e, 0x3e);
cpu_test!(instr_3e, 0x3e);
cpu_test!(instr_3f, 0x3f);
//cpu_test!(instr_40, 0x40);
cpu_test!(instr_41, 0x41);
cpu_test!(instr_42, 0x42);
cpu_test!(instr_43, 0x43);
//cpu_test!(instr_44, 0x44);
cpu_test!(instr_45, 0x45);
//cpu_test!(instr_46, 0x46);
cpu_test!(instr_46, 0x46);
cpu_test!(instr_47, 0x47);
//cpu_test!(instr_48, 0x48);
cpu_test!(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);
//cpu_test!(instr_4e, 0x4e);
cpu_test!(instr_4e, 0x4e);
cpu_test!(instr_4f, 0x4f);
//cpu_test!(instr_50, 0x50);
cpu_test!(instr_51, 0x51);
cpu_test!(instr_52, 0x52);
cpu_test!(instr_53, 0x53);
//cpu_test!(instr_54, 0x54);
cpu_test!(instr_55, 0x55);
//cpu_test!(instr_56, 0x56);
cpu_test!(instr_56, 0x56);
cpu_test!(instr_57, 0x57);
cpu_test!(instr_58, 0x58);
cpu_test!(instr_59, 0x59);
//cpu_test!(instr_5a, 0x5a);
cpu_test!(instr_5b, 0x5b);
//cpu_test!(instr_5c, 0x5c);
cpu_test!(instr_5d, 0x5d);
//cpu_test!(instr_5e, 0x5e);
cpu_test!(instr_5e, 0x5e);
cpu_test!(instr_5f, 0x5f);
//cpu_test!(instr_60, 0x60);
cpu_test!(instr_61, 0x61);
//cpu_test!(instr_62, 0x62);
cpu_test!(instr_63, 0x63);
cpu_test!(instr_64, 0x64);
cpu_test!(instr_65, 0x65);
//cpu_test!(instr_66, 0x66);
cpu_test!(instr_66, 0x66);
cpu_test!(instr_67, 0x67);
//cpu_test!(instr_68, 0x68);
cpu_test!(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);
//cpu_test!(instr_6e, 0x6e);
cpu_test!(instr_6e, 0x6e);
cpu_test!(instr_6f, 0x6f);
//cpu_test!(instr_70, 0x70);
cpu_test!(instr_71, 0x71);
cpu_test!(instr_72, 0x72);
cpu_test!(instr_73, 0x73);
cpu_test!(instr_74, 0x74);
cpu_test!(instr_75, 0x75);
//cpu_test!(instr_76, 0x76);
cpu_test!(instr_76, 0x76);
cpu_test!(instr_77, 0x77);
cpu_test!(instr_78, 0x78);
//cpu_test!(instr_79, 0x79);
//cpu_test!(instr_7a, 0x7a);
cpu_test!(instr_7b, 0x7b);
//cpu_test!(instr_7c, 0x7c);
cpu_test!(instr_7d, 0x7d);
//cpu_test!(instr_7e, 0x7e);
cpu_test!(instr_7e, 0x7e);
cpu_test!(instr_7f, 0x7f);
//cpu_test!(instr_80, 0x80);
cpu_test!(instr_81, 0x81);
Expand Down

0 comments on commit c674079

Please sign in to comment.