mirror of
https://github.com/mre/mos6502.git
synced 2024-06-25 22:29:35 +00:00
Variant with no decimal mode
This commit is contained in:
parent
877f83a6d1
commit
030e6c1d0a
104
src/cpu.rs
104
src/cpu.rs
|
@ -196,6 +196,15 @@ impl<M: Bus, V: Variant> CPU<M, V> {
|
||||||
debug!("add with carry. address: {:?}. value: {}", addr, val);
|
debug!("add with carry. address: {:?}. value: {}", addr, val);
|
||||||
self.add_with_carry(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)) => {
|
(Instruction::AND, OpInput::UseImmediate(val)) => {
|
||||||
self.and(val);
|
self.and(val);
|
||||||
|
@ -509,6 +518,16 @@ impl<M: Bus, V: Variant> CPU<M, V> {
|
||||||
self.subtract_with_carry(val);
|
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) => {
|
(Instruction::SEC, OpInput::UseImplied) => {
|
||||||
self.registers.status.or(Status::PS_CARRY);
|
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) {
|
fn add_with_carry(&mut self, value: u8) {
|
||||||
#[cfg(feature = "decimal_mode")]
|
|
||||||
fn decimal_adjust(result: u8) -> u8 {
|
fn decimal_adjust(result: u8) -> u8 {
|
||||||
let bcd1: u8 = if (result & 0x0f) > 0x09 { 0x06 } else { 0x00 };
|
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));
|
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) {
|
let result: u8 = if self.registers.status.contains(Status::PS_DECIMAL_MODE) {
|
||||||
decimal_adjust(a_after)
|
decimal_adjust(a_after)
|
||||||
} else {
|
} else {
|
||||||
a_after
|
a_after
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(not(feature = "decimal_mode"))]
|
let did_carry = (result) < (a_before)
|
||||||
let result: u8 = a_after;
|
|| (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)
|
let did_carry = (result) < (a_before)
|
||||||
|| (a_after == 0 && c_before == 0x01)
|
|| (a_after == 0 && c_before == 0x01)
|
||||||
|
@ -757,6 +803,52 @@ impl<M: Bus, V: Variant> CPU<M, V> {
|
||||||
self.load_accumulator(a_after);
|
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) {
|
fn subtract_with_carry(&mut self, value: u8) {
|
||||||
// A - M - (1 - C)
|
// A - M - (1 - C)
|
||||||
|
|
||||||
|
@ -798,16 +890,12 @@ impl<M: Bus, V: Variant> CPU<M, V> {
|
||||||
0x00
|
0x00
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(feature = "decimal_mode")]
|
|
||||||
let result: u8 = if self.registers.status.contains(Status::PS_DECIMAL_MODE) {
|
let result: u8 = if self.registers.status.contains(Status::PS_DECIMAL_MODE) {
|
||||||
a_after.wrapping_sub(bcd1).wrapping_sub(bcd2)
|
a_after.wrapping_sub(bcd1).wrapping_sub(bcd2)
|
||||||
} else {
|
} else {
|
||||||
a_after
|
a_after
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(not(feature = "decimal_mode"))]
|
|
||||||
let result = a_after;
|
|
||||||
|
|
||||||
// The carry flag is set on unsigned overflow.
|
// The carry flag is set on unsigned overflow.
|
||||||
let did_carry = (result) > (a_before);
|
let did_carry = (result) > (a_before);
|
||||||
|
|
||||||
|
|
|
@ -44,39 +44,40 @@
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum Instruction {
|
pub enum Instruction {
|
||||||
ADC, // ADd with Carry................ | NV ...ZC A = A + M + C
|
ADC, // ADd with Carry................ | NV ...ZC A = A + M + C
|
||||||
AND, // logical AND (bitwise)......... | N. ...Z. A = A && M
|
ADCnd, // ADd with Carry................ | NV ...ZC A = A + M + C
|
||||||
ASL, // Arithmetic Shift Left......... | N. ...ZC A = M << 1
|
AND, // logical AND (bitwise)......... | N. ...Z. A = A && M
|
||||||
BCC, // Branch if Carry Clear......... | .. ..... PC = !C
|
ASL, // Arithmetic Shift Left......... | N. ...ZC A = M << 1
|
||||||
BCS, // Branch if Carry Set........... | .. ..... PC = C
|
BCC, // Branch if Carry Clear......... | .. ..... PC = !C
|
||||||
BEQ, // Branch if Equal (to zero?).... | .. ..... PC = Z
|
BCS, // Branch if Carry Set........... | .. ..... PC = C
|
||||||
BIT, // BIT test...................... | NV ...Z. = A & M
|
BEQ, // Branch if Equal (to zero?).... | .. ..... PC = Z
|
||||||
BMI, // Branch if Minus............... | .. ..... PC = N
|
BIT, // BIT test...................... | NV ...Z. = A & M
|
||||||
BNE, // Branch if Not Equal........... | .. ..... PC = !Z
|
BMI, // Branch if Minus............... | .. ..... PC = N
|
||||||
BPL, // Branch if Positive............ | .. ..... PC = Z
|
BNE, // Branch if Not Equal........... | .. ..... PC = !Z
|
||||||
BRK, // BReaK......................... | .. B.... S PC =
|
BPL, // Branch if Positive............ | .. ..... PC = Z
|
||||||
BVC, // Branch if oVerflow Clear...... | .. ..... PC = !V
|
BRK, // BReaK......................... | .. B.... S PC =
|
||||||
BVS, // Branch if oVerflow Set........ | .. ..... PC = V
|
BVC, // Branch if oVerflow Clear...... | .. ..... PC = !V
|
||||||
CLC, // CLear Carry flag.............. | .. ....C = 0
|
BVS, // Branch if oVerflow Set........ | .. ..... PC = V
|
||||||
CLD, // Clear Decimal Mode............ | .. .D... = 0
|
CLC, // CLear Carry flag.............. | .. ....C = 0
|
||||||
CLI, // Clear Interrupt Disable....... | .. ..I.. = 0
|
CLD, // Clear Decimal Mode............ | .. .D... = 0
|
||||||
CLV, // Clear oVerflow flag........... | .V ..... = 0
|
CLI, // Clear Interrupt Disable....... | .. ..I.. = 0
|
||||||
CMP, // Compare....................... | N. ...ZC = A - M
|
CLV, // Clear oVerflow flag........... | .V ..... = 0
|
||||||
CPX, // Compare X register............ | N. ...ZC = X - M
|
CMP, // Compare....................... | N. ...ZC = A - M
|
||||||
CPY, // Compare Y register............ | N. ...ZC = Y - M
|
CPX, // Compare X register............ | N. ...ZC = X - M
|
||||||
DEC, // DECrement memory.............. | N. ...Z. M = M - 1
|
CPY, // Compare Y register............ | N. ...ZC = Y - M
|
||||||
DEX, // DEcrement X register.......... | N. ...Z. X = X - 1
|
DEC, // DECrement memory.............. | N. ...Z. M = M - 1
|
||||||
DEY, // DEcrement Y register.......... | N. ...Z. Y = Y - 1
|
DEX, // DEcrement X register.......... | N. ...Z. X = X - 1
|
||||||
EOR, // Exclusive OR (bitwise)........ | N. ...Z. A = A ^ M
|
DEY, // DEcrement Y register.......... | N. ...Z. Y = Y - 1
|
||||||
INC, // INCrement memory.............. | N. ...Z. M = M + 1
|
EOR, // Exclusive OR (bitwise)........ | N. ...Z. A = A ^ M
|
||||||
INX, // INcrement X register.......... | N. ...Z. X = X + 1
|
INC, // INCrement memory.............. | N. ...Z. M = M + 1
|
||||||
INY, // INcrement Y register.......... | N. ...Z. Y = Y + 1
|
INX, // INcrement X register.......... | N. ...Z. X = X + 1
|
||||||
JMP, // JuMP.......................... | .. ..... S PC =
|
INY, // INcrement Y register.......... | N. ...Z. Y = Y + 1
|
||||||
JSR, // Jump to SubRoutine............ | .. ..... S PC =
|
JMP, // JuMP.......................... | .. ..... S PC =
|
||||||
LDA, // LoaD Accumulator.............. | N. ...Z. A = M
|
JSR, // Jump to SubRoutine............ | .. ..... S PC =
|
||||||
LDX, // LoaD X register............... | N. ...Z. X = M
|
LDA, // LoaD Accumulator.............. | N. ...Z. A = M
|
||||||
LDY, // LoaD Y register............... | N. ...Z. Y = M
|
LDX, // LoaD X register............... | N. ...Z. X = M
|
||||||
LSR, // Logical Shift Right........... | N. ...ZC A = A/2
|
LDY, // LoaD Y register............... | N. ...Z. Y = M
|
||||||
|
LSR, // Logical Shift Right........... | N. ...ZC A = A/2
|
||||||
// or N. ...ZC M = M/2
|
// or N. ...ZC M = M/2
|
||||||
NOP, // No OPeration.................. | .. ..... =
|
NOP, // No OPeration.................. | .. ..... =
|
||||||
ORA, // inclusive OR (bitwise)........ | N. ...Z. A = A | M
|
ORA, // inclusive OR (bitwise)........ | N. ...Z. A = A | M
|
||||||
|
@ -88,21 +89,22 @@ pub enum Instruction {
|
||||||
// or N. ...ZC M = C M rotated
|
// or N. ...ZC M = C M rotated
|
||||||
ROR, // ROtate Right.................. | N. ...ZC A = C A rotated
|
ROR, // ROtate Right.................. | N. ...ZC A = C A rotated
|
||||||
// or N. ...ZC M = C M rotated
|
// or N. ...ZC M = C M rotated
|
||||||
RTI, // ReTurn from Interrupt......... | NV BDIZC PC = M (stack)
|
RTI, // ReTurn from Interrupt......... | NV BDIZC PC = M (stack)
|
||||||
RTS, // ReTurn from Subroutine........ | .. ..... PC = M (stack)
|
RTS, // ReTurn from Subroutine........ | .. ..... PC = M (stack)
|
||||||
SBC, // SuBtract with Carry........... | NV ...ZC A = A-M-(1-C)
|
SBC, // SuBtract with Carry........... | NV ...ZC A = A-M-(1-C)
|
||||||
SEC, // SEt Carry flag................ | .. ....C = 1
|
SBCnd, // SuBtract with Carry........... | NV ...ZC A = A-M-(1-C)
|
||||||
SED, // SEt Decimal flag.............. | .. .D... = 1
|
SEC, // SEt Carry flag................ | .. ....C = 1
|
||||||
SEI, // SEt Interrupt disable......... | .. ..I.. = 1
|
SED, // SEt Decimal flag.............. | .. .D... = 1
|
||||||
STA, // STore Accumulator............. | .. ..... M = A
|
SEI, // SEt Interrupt disable......... | .. ..I.. = 1
|
||||||
STX, // STore X register.............. | .. ..... M = X
|
STA, // STore Accumulator............. | .. ..... M = A
|
||||||
STY, // STore Y register.............. | .. ..... M = Y
|
STX, // STore X register.............. | .. ..... M = X
|
||||||
TAX, // Transfer Accumulator to X..... | N. ...Z. X = A
|
STY, // STore Y register.............. | .. ..... M = Y
|
||||||
TAY, // Transfer Accumulator to Y..... | N. ...Z. Y = A
|
TAX, // Transfer Accumulator to X..... | N. ...Z. X = A
|
||||||
TSX, // Transfer Stack pointer to X... | N. ...Z. X = S
|
TAY, // Transfer Accumulator to Y..... | N. ...Z. Y = A
|
||||||
TXA, // Transfer X to Accumulator..... | N. ...Z. A = X
|
TSX, // Transfer Stack pointer to X... | N. ...Z. X = S
|
||||||
TXS, // Transfer X to Stack pointer... | .. ..... S = X
|
TXA, // Transfer X to Accumulator..... | N. ...Z. A = X
|
||||||
TYA, // Transfer Y to Accumulator..... | N. ...Z. A = Y
|
TXS, // Transfer X to Stack pointer... | .. ..... S = X
|
||||||
|
TYA, // Transfer Y to Accumulator..... | N. ...Z. A = Y
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[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;
|
pub struct RevisionA;
|
||||||
|
|
||||||
impl crate::Variant for RevisionA {
|
impl crate::Variant for RevisionA {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user