mos6502/lib.rs
1// Copyright (C) 2014 The 6502-rs Developers
2// All rights reserved.
3//
4// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions
6// are met:
7// 1. Redistributions of source code must retain the above copyright
8// notice, this list of conditions and the following disclaimer.
9// 2. Redistributions in binary form must reproduce the above copyright
10// notice, this list of conditions and the following disclaimer in the
11// documentation and/or other materials provided with the distribution.
12// 3. Neither the names of the copyright holders nor the names of any
13// contributors may be used to endorse or promote products derived from this
14// software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26// POSSIBILITY OF SUCH DAMAGE.
27
28//! An emulator for the MOS 6502 CPU and its variants.
29//!
30//! The 6502 was one of the most influential microprocessors in history, powering
31//! iconic systems like the Apple II, Commodore 64, Atari 2600, and Nintendo
32//! Entertainment System. Its low cost democratized computing and helped birth
33//! the personal computer industry.
34//!
35//! ## Variants
36//!
37//! This emulator supports multiple 6502 variants, each with subtle differences
38//! in behavior. Choose the [variant] that matches your target system:
39//!
40//! - **NMOS 6502**: Original MOS Technology processor
41//! - **65C02**: CMOS version with bug fixes and new instructions. Several
42//! historical 65C02 chips are available as named type aliases:
43//! - [`instruction::Cmos6502`] — WDC W65C02 original (WAI/STP only)
44//! - [`instruction::W65C02S`] - Modern W65C02S, with low-power and Rockwell extensions.
45//! - **Ricoh 2A03**: Nintendo's NES variant without decimal mode
46//! - **Revision A**: Very early variant missing the ROR instruction
47//!
48//! [variant]: crate::Variant
49
50#![warn(clippy::all, clippy::pedantic)]
51#![warn(
52 absolute_paths_not_starting_with_crate,
53 rustdoc::invalid_html_tags,
54 missing_copy_implementations,
55 missing_debug_implementations,
56 semicolon_in_expressions_from_macros,
57 unreachable_pub,
58 unused_crate_dependencies,
59 unused_extern_crates,
60 variant_size_differences,
61 clippy::missing_const_for_fn
62)]
63#![deny(anonymous_parameters, macro_use_extern_crate)]
64#![allow(clippy::module_name_repetitions, clippy::needless_doctest_main)]
65// Registers and ops follow the 6502 naming convention and have similar names at
66// times
67#![allow(clippy::similar_names)]
68#![allow(clippy::match_same_arms)]
69#![allow(clippy::too_many_lines)]
70#![no_std]
71
72#[doc = include_str!("../README.md")]
73pub mod cpu;
74pub mod instruction;
75pub mod memory;
76pub mod registers;
77
78/// Output of arithmetic instructions (ADC/SBC)
79#[derive(Copy, Clone, Debug, PartialEq, Eq)]
80#[allow(clippy::struct_excessive_bools)]
81pub struct ArithmeticOutput {
82 result: u8,
83 did_carry: bool,
84 overflow: bool,
85 negative: bool,
86 zero: bool,
87}
88
89/// Trait for different 6502 CPU variants with their historical differences.
90///
91/// The 6502 family evolved over decades with various manufacturers creating
92/// specialized versions for different applications:
93///
94/// - **Revision A (1975)**: Very early 6502 variant missing the ROR instruction
95/// entirely. Found in early KIM-1 systems and some Apple-1 computers. The ROR
96/// instruction was intentionally unimplemented due to design constraints, not
97/// a "bug" as commonly believed. Production ended around June 1976.
98///
99/// - **NMOS 6502 (1976)**: Complete MOS Technology processor with working ROR
100/// instruction, used in Apple II, Commodore 64, Atari 2600. Has unreliable
101/// decimal mode flags but full BCD support. This became the standard reference
102/// implementation.
103///
104/// - **65C02 (1983)**: WDC's CMOS version with bug fixes, additional instructions,
105/// and reliable decimal mode flags. Development began in 1981 with samples
106/// released in early 1983. Used in Apple IIc/IIe and many embedded systems.
107///
108/// - **Ricoh 2A03 (1983)**: Nintendo's cost-reduced variant for NES/Famicom
109/// (released July 15, 1983). Removed decimal mode entirely to avoid patent
110/// issues. Used as a core in their custom ASIC which also included sound
111/// generation and other features.
112///
113/// Choose the variant that matches your target system for accurate emulation.
114/// Note that software written for later variants may not run on earlier ones
115/// due to missing instructions (particularly ROR on Revision A).
116pub trait Variant {
117 fn decode(
118 opcode: u8,
119 ) -> Option<(
120 crate::instruction::Instruction,
121 crate::instruction::AddressingMode,
122 )>;
123
124 /// Returns the cycle penalty for ADC/SBC in decimal mode for this variant.
125 ///
126 /// - NMOS/Ricoh: 0 (no penalty)
127 /// - 65C02: 1 (decimal mode adds an extra cycle)
128 /// - Future variants may have different values
129 #[must_use]
130 fn penalty_cycles_for_decimal_mode() -> u8 {
131 0 // Default: no penalty
132 }
133
134 /// Returns the cycle penalty for JMP (indirect) for this variant.
135 ///
136 /// - NMOS/Ricoh: 0 (5 cycles total)
137 /// - 65C02: 1 (6 cycles total, also fixes page-crossing bug)
138 /// - Future HMOS 7501: 0 (5 cycles)
139 #[must_use]
140 fn penalty_cycles_for_indirect_jmp() -> u8 {
141 0 // Default: no penalty
142 }
143
144 /// Execute Add with Carry (ADC) in binary mode
145 ///
146 /// # Arguments
147 /// * `accumulator` - Current accumulator value
148 /// * `value` - Value to add
149 /// * `carry_set` - Carry flag set at the time of execution
150 ///
151 /// # Returns
152 /// Tuple of (result, `carry_out`, overflow, negative, zero)
153 fn adc_binary(accumulator: u8, value: u8, carry_set: bool) -> ArithmeticOutput;
154
155 /// Execute Add with Carry (ADC) in decimal mode (BCD)
156 ///
157 /// # Arguments
158 /// * `accumulator` - Current accumulator value
159 /// * `value` - Value to add
160 /// * `carry_set` - Carry flag set at the time of execution
161 ///
162 /// # Returns
163 /// Tuple of (result, `carry_out`, overflow, negative, zero)
164 fn adc_decimal(accumulator: u8, value: u8, carry_set: bool) -> ArithmeticOutput;
165
166 /// Execute Subtract with Carry (SBC) in binary mode
167 ///
168 /// # Arguments
169 /// * `accumulator` - Current accumulator value
170 /// * `value` - Value to subtract
171 /// * `carry_set` - Carry flag set at the time of execution
172 ///
173 /// # Returns
174 /// Tuple of (result, `carry_out`, overflow, negative, zero)
175 fn sbc_binary(accumulator: u8, value: u8, carry_set: bool) -> ArithmeticOutput;
176
177 /// Execute Subtract with Carry (SBC) in decimal mode (BCD)
178 ///
179 /// # Arguments
180 /// * `accumulator` - Current accumulator value
181 /// * `value` - Value to subtract
182 /// * `carry_set` - Carry flag set at the time of execution
183 ///
184 /// # Returns
185 /// Tuple of (result, `carry_out`, overflow, negative, zero)
186 fn sbc_decimal(accumulator: u8, value: u8, carry_set: bool) -> ArithmeticOutput;
187}