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:
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);
|
||||
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);
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in New Issue
Block a user