1
0
mirror of https://github.com/mre/mos6502.git synced 2024-06-04 03:29:27 +00:00

Variant with no decimal mode

This commit is contained in:
Sam M W 2023-08-28 16:46:18 +01:00
parent 877f83a6d1
commit 030e6c1d0a
2 changed files with 172 additions and 56 deletions

View File

@ -196,6 +196,15 @@ impl<M: Bus, V: Variant> CPU<M, V> {
debug!("add with carry. address: {:?}. value: {}", addr, val);
self.add_with_carry(val);
}
(Instruction::ADCnd, OpInput::UseImmediate(val)) => {
debug!("add with carry immediate: {}", val);
self.add_with_no_decimal(val);
}
(Instruction::ADCnd, OpInput::UseAddress(addr)) => {
let val = self.memory.get_byte(addr);
debug!("add with carry. address: {:?}. value: {}", addr, val);
self.add_with_no_decimal(val);
}
(Instruction::AND, OpInput::UseImmediate(val)) => {
self.and(val);
@ -509,6 +518,16 @@ impl<M: Bus, V: Variant> CPU<M, V> {
self.subtract_with_carry(val);
}
(Instruction::SBCnd, OpInput::UseImmediate(val)) => {
debug!("subtract with carry immediate: {}", val);
self.subtract_with_no_decimal(val);
}
(Instruction::SBCnd, OpInput::UseAddress(addr)) => {
let val = self.memory.get_byte(addr);
debug!("subtract with carry. address: {:?}. value: {}", addr, val);
self.subtract_with_no_decimal(val);
}
(Instruction::SEC, OpInput::UseImplied) => {
self.registers.status.or(Status::PS_CARRY);
}
@ -700,7 +719,6 @@ impl<M: Bus, V: Variant> CPU<M, V> {
}
fn add_with_carry(&mut self, value: u8) {
#[cfg(feature = "decimal_mode")]
fn decimal_adjust(result: u8) -> u8 {
let bcd1: u8 = if (result & 0x0f) > 0x09 { 0x06 } else { 0x00 };
@ -719,15 +737,43 @@ impl<M: Bus, V: Variant> CPU<M, V> {
debug_assert_eq!(a_after, a_before.wrapping_add(c_before).wrapping_add(value));
#[cfg(feature = "decimal_mode")]
let result: u8 = if self.registers.status.contains(Status::PS_DECIMAL_MODE) {
decimal_adjust(a_after)
} else {
a_after
};
#[cfg(not(feature = "decimal_mode"))]
let result: u8 = a_after;
let did_carry = (result) < (a_before)
|| (a_after == 0 && c_before == 0x01)
|| (value == 0xff && c_before == 0x01);
let did_overflow = (a_before > 127 && value > 127 && a_after < 128)
|| (a_before < 128 && value < 128 && a_after > 127);
let mask = Status::PS_CARRY | Status::PS_OVERFLOW;
self.registers.status.set_with_mask(
mask,
Status::new(StatusArgs {
carry: did_carry,
overflow: did_overflow,
..StatusArgs::none()
}),
);
self.load_accumulator(result);
debug!("accumulator: {}", self.registers.accumulator);
}
fn add_with_no_decimal(&mut self, value: u8) {
let a_before: u8 = self.registers.accumulator;
let c_before: u8 = u8::from(self.registers.status.contains(Status::PS_CARRY));
let a_after: u8 = a_before.wrapping_add(c_before).wrapping_add(value);
debug_assert_eq!(a_after, a_before.wrapping_add(c_before).wrapping_add(value));
let result = a_after;
let did_carry = (result) < (a_before)
|| (a_after == 0 && c_before == 0x01)
@ -757,6 +803,52 @@ impl<M: Bus, V: Variant> CPU<M, V> {
self.load_accumulator(a_after);
}
fn subtract_with_no_decimal(&mut self, value: u8) {
// A - M - (1 - C)
// nc -- 'not carry'
let nc: u8 = if self.registers.status.contains(Status::PS_CARRY) {
0
} else {
1
};
let a_before = self.registers.accumulator;
let a_after = a_before.wrapping_sub(value).wrapping_sub(nc);
// The overflow flag is set on two's-complement overflow.
//
// range of A is -128 to 127
// range of - M - (1 - C) is -128 to 128
// -(127 + 1) to -(-128 + 0)
//
let over = (nc == 0 && value > 127) && a_before < 128 && a_after > 127;
let under =
(a_before > 127) && (0u8.wrapping_sub(value).wrapping_sub(nc) > 127) && a_after < 128;
let did_overflow = over || under;
let mask = Status::PS_CARRY | Status::PS_OVERFLOW;
let result = a_after;
// The carry flag is set on unsigned overflow.
let did_carry = (result) > (a_before);
self.registers.status.set_with_mask(
mask,
Status::new(StatusArgs {
carry: did_carry,
overflow: did_overflow,
..StatusArgs::none()
}),
);
self.load_accumulator(result);
}
fn subtract_with_carry(&mut self, value: u8) {
// A - M - (1 - C)
@ -798,16 +890,12 @@ impl<M: Bus, V: Variant> CPU<M, V> {
0x00
};
#[cfg(feature = "decimal_mode")]
let result: u8 = if self.registers.status.contains(Status::PS_DECIMAL_MODE) {
a_after.wrapping_sub(bcd1).wrapping_sub(bcd2)
} else {
a_after
};
#[cfg(not(feature = "decimal_mode"))]
let result = a_after;
// The carry flag is set on unsigned overflow.
let did_carry = (result) > (a_before);

View File

@ -44,39 +44,40 @@
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum Instruction {
ADC, // ADd with Carry................ | NV ...ZC A = A + M + C
AND, // logical AND (bitwise)......... | N. ...Z. A = A && M
ASL, // Arithmetic Shift Left......... | N. ...ZC A = M << 1
BCC, // Branch if Carry Clear......... | .. ..... PC = !C
BCS, // Branch if Carry Set........... | .. ..... PC = C
BEQ, // Branch if Equal (to zero?).... | .. ..... PC = Z
BIT, // BIT test...................... | NV ...Z. = A & M
BMI, // Branch if Minus............... | .. ..... PC = N
BNE, // Branch if Not Equal........... | .. ..... PC = !Z
BPL, // Branch if Positive............ | .. ..... PC = Z
BRK, // BReaK......................... | .. B.... S PC =
BVC, // Branch if oVerflow Clear...... | .. ..... PC = !V
BVS, // Branch if oVerflow Set........ | .. ..... PC = V
CLC, // CLear Carry flag.............. | .. ....C = 0
CLD, // Clear Decimal Mode............ | .. .D... = 0
CLI, // Clear Interrupt Disable....... | .. ..I.. = 0
CLV, // Clear oVerflow flag........... | .V ..... = 0
CMP, // Compare....................... | N. ...ZC = A - M
CPX, // Compare X register............ | N. ...ZC = X - M
CPY, // Compare Y register............ | N. ...ZC = Y - M
DEC, // DECrement memory.............. | N. ...Z. M = M - 1
DEX, // DEcrement X register.......... | N. ...Z. X = X - 1
DEY, // DEcrement Y register.......... | N. ...Z. Y = Y - 1
EOR, // Exclusive OR (bitwise)........ | N. ...Z. A = A ^ M
INC, // INCrement memory.............. | N. ...Z. M = M + 1
INX, // INcrement X register.......... | N. ...Z. X = X + 1
INY, // INcrement Y register.......... | N. ...Z. Y = Y + 1
JMP, // JuMP.......................... | .. ..... S PC =
JSR, // Jump to SubRoutine............ | .. ..... S PC =
LDA, // LoaD Accumulator.............. | N. ...Z. A = M
LDX, // LoaD X register............... | N. ...Z. X = M
LDY, // LoaD Y register............... | N. ...Z. Y = M
LSR, // Logical Shift Right........... | N. ...ZC A = A/2
ADC, // ADd with Carry................ | NV ...ZC A = A + M + C
ADCnd, // ADd with Carry................ | NV ...ZC A = A + M + C
AND, // logical AND (bitwise)......... | N. ...Z. A = A && M
ASL, // Arithmetic Shift Left......... | N. ...ZC A = M << 1
BCC, // Branch if Carry Clear......... | .. ..... PC = !C
BCS, // Branch if Carry Set........... | .. ..... PC = C
BEQ, // Branch if Equal (to zero?).... | .. ..... PC = Z
BIT, // BIT test...................... | NV ...Z. = A & M
BMI, // Branch if Minus............... | .. ..... PC = N
BNE, // Branch if Not Equal........... | .. ..... PC = !Z
BPL, // Branch if Positive............ | .. ..... PC = Z
BRK, // BReaK......................... | .. B.... S PC =
BVC, // Branch if oVerflow Clear...... | .. ..... PC = !V
BVS, // Branch if oVerflow Set........ | .. ..... PC = V
CLC, // CLear Carry flag.............. | .. ....C = 0
CLD, // Clear Decimal Mode............ | .. .D... = 0
CLI, // Clear Interrupt Disable....... | .. ..I.. = 0
CLV, // Clear oVerflow flag........... | .V ..... = 0
CMP, // Compare....................... | N. ...ZC = A - M
CPX, // Compare X register............ | N. ...ZC = X - M
CPY, // Compare Y register............ | N. ...ZC = Y - M
DEC, // DECrement memory.............. | N. ...Z. M = M - 1
DEX, // DEcrement X register.......... | N. ...Z. X = X - 1
DEY, // DEcrement Y register.......... | N. ...Z. Y = Y - 1
EOR, // Exclusive OR (bitwise)........ | N. ...Z. A = A ^ M
INC, // INCrement memory.............. | N. ...Z. M = M + 1
INX, // INcrement X register.......... | N. ...Z. X = X + 1
INY, // INcrement Y register.......... | N. ...Z. Y = Y + 1
JMP, // JuMP.......................... | .. ..... S PC =
JSR, // Jump to SubRoutine............ | .. ..... S PC =
LDA, // LoaD Accumulator.............. | N. ...Z. A = M
LDX, // LoaD X register............... | N. ...Z. X = M
LDY, // LoaD Y register............... | N. ...Z. Y = M
LSR, // Logical Shift Right........... | N. ...ZC A = A/2
// or N. ...ZC M = M/2
NOP, // No OPeration.................. | .. ..... =
ORA, // inclusive OR (bitwise)........ | N. ...Z. A = A | M
@ -88,21 +89,22 @@ pub enum Instruction {
// or N. ...ZC M = C M rotated
ROR, // ROtate Right.................. | N. ...ZC A = C A rotated
// or N. ...ZC M = C M rotated
RTI, // ReTurn from Interrupt......... | NV BDIZC PC = M (stack)
RTS, // ReTurn from Subroutine........ | .. ..... PC = M (stack)
SBC, // SuBtract with Carry........... | NV ...ZC A = A-M-(1-C)
SEC, // SEt Carry flag................ | .. ....C = 1
SED, // SEt Decimal flag.............. | .. .D... = 1
SEI, // SEt Interrupt disable......... | .. ..I.. = 1
STA, // STore Accumulator............. | .. ..... M = A
STX, // STore X register.............. | .. ..... M = X
STY, // STore Y register.............. | .. ..... M = Y
TAX, // Transfer Accumulator to X..... | N. ...Z. X = A
TAY, // Transfer Accumulator to Y..... | N. ...Z. Y = A
TSX, // Transfer Stack pointer to X... | N. ...Z. X = S
TXA, // Transfer X to Accumulator..... | N. ...Z. A = X
TXS, // Transfer X to Stack pointer... | .. ..... S = X
TYA, // Transfer Y to Accumulator..... | N. ...Z. A = Y
RTI, // ReTurn from Interrupt......... | NV BDIZC PC = M (stack)
RTS, // ReTurn from Subroutine........ | .. ..... PC = M (stack)
SBC, // SuBtract with Carry........... | NV ...ZC A = A-M-(1-C)
SBCnd, // SuBtract with Carry........... | NV ...ZC A = A-M-(1-C)
SEC, // SEt Carry flag................ | .. ....C = 1
SED, // SEt Decimal flag.............. | .. .D... = 1
SEI, // SEt Interrupt disable......... | .. ..I.. = 1
STA, // STore Accumulator............. | .. ..... M = A
STX, // STore X register.............. | .. ..... M = X
STY, // STore Y register.............. | .. ..... M = Y
TAX, // Transfer Accumulator to X..... | N. ...Z. X = A
TAY, // Transfer Accumulator to Y..... | N. ...Z. Y = A
TSX, // Transfer Stack pointer to X... | N. ...Z. X = S
TXA, // Transfer X to Accumulator..... | N. ...Z. A = X
TXS, // Transfer X to Stack pointer... | .. ..... S = X
TYA, // Transfer Y to Accumulator..... | N. ...Z. A = Y
}
#[derive(Copy, Clone)]
@ -418,6 +420,32 @@ impl crate::Variant for Nmos6502 {
}
}
}
pub struct Ricoh2a03;
impl crate::Variant for Ricoh2a03 {
fn decode(opcode: u8) -> Option<(Instruction, AddressingMode)> {
match opcode {
0x61 => Some((Instruction::ADCnd, AddressingMode::IndexedIndirectX)),
0x65 => Some((Instruction::ADCnd, AddressingMode::ZeroPage)),
0x69 => Some((Instruction::ADCnd, AddressingMode::Immediate)),
0x6d => Some((Instruction::ADCnd, AddressingMode::Absolute)),
0x71 => Some((Instruction::ADCnd, AddressingMode::IndirectIndexedY)),
0x75 => Some((Instruction::ADCnd, AddressingMode::ZeroPageX)),
0x79 => Some((Instruction::ADCnd, AddressingMode::AbsoluteY)),
0x7d => Some((Instruction::ADCnd, AddressingMode::AbsoluteX)),
0xe1 => Some((Instruction::SBCnd, AddressingMode::IndexedIndirectX)),
0xe5 => Some((Instruction::SBCnd, AddressingMode::ZeroPage)),
0xe9 => Some((Instruction::SBCnd, AddressingMode::Immediate)),
0xed => Some((Instruction::SBCnd, AddressingMode::Absolute)),
0xf1 => Some((Instruction::SBCnd, AddressingMode::IndirectIndexedY)),
0xf5 => Some((Instruction::SBCnd, AddressingMode::ZeroPageX)),
0xf9 => Some((Instruction::SBCnd, AddressingMode::AbsoluteY)),
0xfd => Some((Instruction::SBCnd, AddressingMode::AbsoluteX)),
_ => Nmos6502::decode(opcode),
}
}
}
pub struct RevisionA;
impl crate::Variant for RevisionA {