gte_w65c02s/lib.rs
1#![allow(unused)]
2
3//! This crate is a cycle-accurate simulator for the WDC W65C02S, the most
4//! advanced direct descendent of that catalyst of the home computer
5//! revolution, the 6502.
6//!
7//! This crate accurately simulates all bus signals of the W65C02S except RDY,
8//! SOB, and BE, which can all be simulated by outside code. It is written in
9//! such a way that the unused bus logic usually gets optimized out. Make sure
10//! LTO is enabled in your `Cargo.toml` for a tremendous speedup:
11//!
12//! ```toml
13//! [profile.release]
14//! lto = true
15//! ```
16//!
17//! This crate does not depend on any other libraries, including the standard
18//! library.
19//!
20//! The W65C02S instruction set includes the original NMOS 6502 instructions,
21//! the additional instructions supported by all CMOS 6502s, the "Rockwell bit
22//! extensions" (`BBRx`/`BBSx`/`RMBx`/`SMBx`), and the `WAI` and `STP`
23//! instructions.
24//!
25//! The accuracy of this simulation has been tested on the [`65test` test
26//! suite](https://github.com/SolraBizna/65test), which contains over 4500
27//! tests. In every single test, the simulator's bus traffic is *exactly* the
28//! same as the real hardware—even down to the timing of IRQ and NMI responses.
29//! This means that this simulator is suitable for prototyping and simulation
30//! of real systems using the W65C02S processor, including systems based on the
31//! W65C134S MCU.
32//!
33//! To use it, you will need an instance of [`W65C02S`](struct.W65C02S.html)
34//! and an implementation of [`System`](trait.System.html). `W65C02S` simulates
35//! the CPU; `System` must simulate the hardware attached to the bus (memory,
36//! IO devices, et cetera).
37//!
38//! ```rust
39//! use w65c02s::*;
40//!
41//! pub fn main() {
42//! let mut system = HelloWorldSystem::new();
43//! let mut cpu = W65C02S::new();
44//! while cpu.get_state() != State::Stopped { cpu.step(&mut system); }
45//! }
46//!
47//! /// A simple system with 64K of RAM, along with an output-only "serial
48//! /// port" mapped to $0000.
49//! struct HelloWorldSystem {
50//! ram: [u8; 65536],
51//! }
52//!
53//! impl HelloWorldSystem {
54//! pub fn new() -> HelloWorldSystem {
55//! // initialize RAM with all 0xFFs
56//! let mut ram = [0xFF; 65536];
57//! // initialize the message
58//! ram[0x0001..0x000F].copy_from_slice(b"Hello World!\n\0");
59//! // initialize the program
60//! ram[0x0200..0x020C].copy_from_slice(&[
61//! op::LDX_IMM, 0, // LDX #0
62//! // loop:
63//! op::LDA_ZPX, 1, // LDA $01, X
64//! op::BNE, 1, // BNE +
65//! op::STP, // STP
66//! op::STA_ZP, 0, // + STA $00
67//! op::INC_X, // INX
68//! op::BRA, 0xF6, // BRA loop
69//! ]);
70//! // initialize the reset vector to point to $0200
71//! ram[0xFFFC..0xFFFE].copy_from_slice(&[0x00, 0x02]);
72//! HelloWorldSystem { ram }
73//! }
74//! }
75//!
76//! impl System for HelloWorldSystem {
77//! fn read(&mut self, _cpu: &mut W65C02S, addr: u16) -> u8 {
78//! // all reads return RAM values directly
79//! self.ram[addr as usize]
80//! }
81//! fn write(&mut self, _cpu: &mut W65C02S, addr: u16, value: u8) {
82//! if addr == 0 {
83//! // writing address $0000 outputs on an ASCII-only "serial port"
84//! print!("{}", String::from_utf8_lossy(&[value]));
85//! }
86//! else {
87//! // all other writes write to RAM
88//! self.ram[addr as usize] = value
89//! }
90//! }
91//! }
92//! ```
93//!
94//! This simulator is based on the simulator in the original [ARS
95//! Emulator](https://github.com/SolraBizna/ars-emu).
96//!
97//! # License
98//!
99//! w65c02s is distributed under the zlib license. The complete text is as
100//! follows:
101//!
102//! > Copyright (c) 2019, Solra Bizna
103//! >
104//! > This software is provided "as-is", without any express or implied
105//! > warranty. In no event will the author be held liable for any damages
106//! > arising from the use of this software.
107//! >
108//! > Permission is granted to anyone to use this software for any purpose,
109//! > including commercial applications, and to alter it and redistribute it
110//! > freely, subject to the following restrictions:
111//! >
112//! > 1. The origin of this software must not be misrepresented; you must not
113//! > claim that you wrote the original software. If you use this software in a
114//! > product, an acknowledgement in the product documentation would be
115//! > appreciated but is not required.
116//! > 2. Altered source versions must be plainly marked as such, and must not
117//! > be misrepresented as being the original software.
118//! > 3. This notice may not be removed or altered from any source
119//! > distribution.
120
121pub mod op;
122mod addressing_modes;
123mod instructions;
124
125use addressing_modes::*;
126
127pub static OPCODE_CYCLES: [i32; 256]= [ // was this worst case or...? who knows, who cares
128 7, 6, 2, 0, 5, 3, 5, 5, 2, 3, 4, 0, 7, 5, 7, 7,
129 3, 5, 5, 0, 5, 4, 6, 5, 1, 5, 4, 0, 7, 5, 7, 7,
130 6, 6, 2, 0, 3, 3, 5, 5, 3, 3, 4, 0, 5, 5, 7, 7,
131 2, 5, 5, 0, 4, 4, 6, 5, 1, 5, 4, 0, 5, 5, 7, 7,
132 5, 6, 2, 0, 2, 3, 5, 5, 2, 3, 4, 0, 4, 5, 7, 7,
133 3, 5, 5, 0, 3, 4, 6, 5, 1, 5, 2, 0, 9, 5, 7, 7,
134 5, 6, 2, 0, 3, 3, 5, 5, 3, 3, 4, 0, 7, 5, 7, 7,
135 2, 5, 5, 0, 4, 4, 6, 5, 1, 5, 2, 0, 7, 5, 7, 7,
136 3, 5, 2, 0, 3, 2, 3, 5, 4, 3, 1, 0, 5, 5, 5, 6,
137 3, 5, 4, 0, 4, 3, 4, 5, 1, 5, 1, 0, 5, 5, 6, 6,
138 3, 6, 3, 0, 3, 3, 3, 5, 1, 2, 1, 0, 5, 5, 5, 6,
139 2, 5, 5, 0, 4, 4, 4, 5, 1, 5, 1, 0, 5, 5, 5, 6,
140 3, 6, 2, 0, 3, 3, 5, 5, 4, 3, 4, 0, 5, 5, 7, 6,
141 3, 5, 5, 0, 3, 4, 6, 5, 1, 5, 2, 1, 4, 5, 8, 6,
142 3, 6, 2, 0, 3, 3, 5, 5, 4, 3, 1, 0, 5, 5, 7, 6,
143 2, 5, 5, 0, 3, 4, 6, 5, 1, 6, 3, 0, 4, 6, 8, 6,
144];
145
146/// Implements a system connected to a W65C02S's bus. Only `read` and `write`
147/// need be implemented for a simple system, but other systems may be more
148/// complicated; for instance, many 65C02-based microcontrollers have advanced
149/// interrupt vectoring logic that would require implementing `read_vector`.
150pub trait System {
151 /// Read an instruction opcode from the given address. VPB, MLB, and SYNC
152 /// are all HIGH.
153 fn read_opcode(&mut self, cpu: &mut W65C02S, addr: u16) -> u8 { self.read(cpu, addr) }
154 /// Read a byte of data from the given address. SYNC is LOW and VPB and MLB
155 /// are HIGH.
156 fn read(&mut self, cpu: &mut W65C02S, addr: u16) -> u8;
157 /// Read data from the given address as part of a Read-Modify-Write
158 /// instruction. SYNC and MLB are LOW, VPB is HIGH.
159 fn read_locked(&mut self, cpu: &mut W65C02S, addr: u16) -> u8 { self.read(cpu, addr) }
160 /// Second data read from the given address as part of a Read-Modify-Write
161 /// instruction. This data is ignored; this is an "idle cycle". SYNC and
162 /// MLB are LOW, VPB is HIGH. Indistinguishable from a locked data read on
163 /// real hardware, but the distinction may be useful for simulation.
164 fn read_locked_spurious(&mut self, cpu: &mut W65C02S, addr: u16) { self.read_locked(cpu, addr); }
165 /// Read part of an interrupt vector from the given address. VPB is LOW,
166 /// and SYNC and MLB are HIGH.
167 fn read_vector(&mut self, cpu: &mut W65C02S, addr: u16) -> u8 { self.read(cpu, addr) }
168 /// Write a byte of data to the given address. SYNC is LOW and VPB and MLB
169 /// are HIGH.
170 fn write(&mut self, cpu: &mut W65C02S, addr: u16, data: u8);
171 /// Push a byte of data onto the stack at the given address. SYNC is LOW
172 /// and VPB and MLB are HIGH. Indistinguishable from a normal data write
173 /// on real hardware, but the distinction may be useful for simulation.
174 fn write_stack(&mut self, cpu: &mut W65C02S, addr: u16, data: u8) { self.write(cpu, addr, data) }
175 /// Write a byte of data to the given address as the conclusion of a Read-
176 /// Modify-Write instruction. SYNC and MLB are LOW, VPB is HIGH.
177 fn write_locked(&mut self, cpu: &mut W65C02S, addr: u16, data: u8) { self.write(cpu, addr, data) }
178 /// Read an instruction opcode whose execution will be preempted by an
179 /// interrupt or a reset, or which follows a WAI or STP instruction that
180 /// has not yet been broken out of. VPB, MLB, and SYNC are all HIGH.
181 /// Indistinguishable from a normal opcode fetch on real hardware, but
182 /// the distinction may be useful for simulation.
183 fn read_opcode_spurious(&mut self, cpu: &mut W65C02S, addr: u16) { self.read_opcode(cpu, addr); }
184 /// Read an instruction operand from the given address. SYNC is LOW and VPB
185 /// and MLB are HIGH. Indistinguishable from an ordinary data read on real
186 /// hardware, but the distinction may be useful for simulation.
187 fn read_operand(&mut self, cpu: &mut W65C02S, addr: u16) -> u8 { self.read(cpu, addr) }
188 /// Read an instruction operand from the given address, except that the
189 /// instruction had an implied operand or was preempted by a reset. SYNC
190 /// is LOW and VPB and MLB are HIGH. Indistinguishable from an ordinary
191 /// data read on real hardware, but the distinction may be useful for
192 /// simulation.
193 fn read_operand_spurious(&mut self, cpu: &mut W65C02S, addr: u16) { self.read(cpu, addr); }
194 /// Read part of a pointer from the given address. SYNC is LOW and VPB and
195 /// MLB are HIGH. Indistinguishable from an ordinary data read on real
196 /// hardware, but the distinction may be useful for simulation.
197 fn read_pointer(&mut self, cpu: &mut W65C02S, addr: u16) -> u8 { self.read(cpu, addr) }
198 /// Pop a value from the stack at the given address. SYNC is LOW and VPB
199 /// and MLB are HIGH. Indistinguishable from an ordinary data read on real
200 /// hardware, but the distinction may be useful for simulation.
201 fn read_stack(&mut self, cpu: &mut W65C02S, addr: u16) -> u8 { self.read(cpu, addr) }
202 /// Spurious stack "read" that occurs during reset. SYNC is LOW and VPB
203 /// and MLB are HIGH. Indistinguishable from an ordinary data read on real
204 /// hardware, but the distinction may be useful for simulation.
205 fn read_stack_spurious(&mut self, cpu: &mut W65C02S, addr: u16) { self.read_stack(cpu, addr); }
206 /// Read a byte of data from the given address during an "internal
207 /// operation" cycle. SYNC is LOW and VPB and MLB are HIGH.
208 /// Indistinguishable from an ordinary data read on real hardware, but the
209 /// distinction may be useful for simulation.
210 fn read_spurious(&mut self, cpu: &mut W65C02S, addr: u16) { self.read(cpu, addr); }
211}
212
213/// Status register flag corresponding to the **C**arry bit.
214pub const P_C: u8 = 0x01;
215/// Status register flag corresponding to the **Z**ero bit.
216pub const P_Z: u8 = 0x02;
217/// Status register flag corresponding to the **I**nterrupt mask bit.
218pub const P_I: u8 = 0x04;
219/// Status register flag corresponding to the **D**ecimal mode bit.
220pub const P_D: u8 = 0x08;
221/// Status register flag corresponding to the **B**reak bit.
222pub const P_B: u8 = 0x10;
223/// Status register flag that is hardwired to 1, in spite of what the datasheet
224/// says.
225pub const P_1: u8 = 0x20;
226/// Status register flag corresponding to the o**V**erflow bit.
227pub const P_V: u8 = 0x40;
228/// Status register flag corresponding to the **N**egative bit.
229pub const P_N: u8 = 0x80;
230
231/// Address of the IRQ/BRK interrupt vector.
232pub const IRQ_VECTOR: u16 = 0xfffe;
233/// Address of the Reset interrupt vector.
234pub const RESET_VECTOR: u16 = 0xfffc;
235/// Address of the NMI interrupt vector.
236pub const NMI_VECTOR: u16 = 0xfffa;
237
238/// The CPU is in one of the given states between `step`s.
239#[derive(Clone,Copy,Debug,PartialEq,Eq)]
240pub enum State {
241 /// The CPU has just been reset. It will execute the reset sequence at the
242 /// next step. RDY is HIGH.
243 HasBeenReset,
244 /// The CPU is in its normal operating state. It will fetch an instruction
245 /// at the next step, and possibly handle an interrupt. RDY is HIGH.
246 Running,
247 /// The CPU has executed a `WAI` instruction and has not yet detected an
248 /// interrupt. RDY is LOW.
249 AwaitingInterrupt,
250 /// The CPU has executed a `STP` instruction. Only a reset will return it
251 /// to an executing state. RDY is LOW.
252 Stopped,
253}
254
255/// An instance of a W65C02S, encapsulating the entire runtime state of the
256/// processor itself. Not very useful without a `System` to go with it.
257#[derive(Copy,Clone,Debug,PartialEq,Eq)]
258pub struct W65C02S {
259 state: State, pc: u16,
260 a: u8, x: u8, y: u8, s: u8, p: u8,
261 irq: bool, irq_pending: bool,
262 nmi: bool, nmi_edge: bool, nmi_pending: bool,
263}
264
265impl W65C02S {
266 /// Creates a new `W65C02S` instance, initialized in a newly-reset state.
267 /// (Unlike a real W65C02S, most registers will be in the all-ones state at
268 /// this point.)
269 pub fn new() -> W65C02S {
270 W65C02S {
271 state: State::HasBeenReset,
272 pc: 0xFFFF,
273 a: 0xFF,
274 x: 0xFF,
275 y: 0xFF,
276 s: 0xFF,
277 p: P_1|P_I,
278 irq: false, irq_pending: false,
279 nmi: false, nmi_edge: false, nmi_pending: false,
280 }
281 }
282 /// Resets the CPU. Execution will flounder for a few cycles, then fetch
283 /// the reset vector and "start over".
284 #[inline(always)]
285 pub fn reset(&mut self) {
286 self.state = State::HasBeenReset;
287 self.s = 0;
288 self.p = P_1|P_I;
289 }
290 /// Get the current value of the **P**rogram **C**ounter, i.e. the next
291 /// instruction that will (probably) be executed.
292 #[inline(always)]
293 pub fn get_pc(&self) -> u16 { self.pc }
294 /// Internal function. Get the current value of the **P**rogram
295 /// **C**ounter. Increment the underlying value by one *after* reading it.
296 #[inline(always)]
297 fn read_pc_postincrement(&mut self) -> u16 {
298 let ret = self.pc;
299 self.pc = self.pc.wrapping_add(1);
300 ret
301 }
302 /// Overwrite the current value of the **P**rogram **C**ounter.
303 #[inline(always)]
304 pub fn set_pc(&mut self, pc: u16) { self.pc = pc }
305 /// Get the current value of the **A**ccumulator.
306 #[inline(always)]
307 pub fn get_a(&self) -> u8 { self.a }
308 /// Overwrite the current value of the **A**ccumulator.
309 #[inline(always)]
310 pub fn set_a(&mut self, a: u8) { self.a = a }
311 /// Get the current value of index register **X**.
312 #[inline(always)]
313 pub fn get_x(&self) -> u8 { self.x }
314 /// Overwrite the current value of index register **X**.
315 #[inline(always)]
316 pub fn set_x(&mut self, x: u8) { self.x = x }
317 /// Get the current value of index register **Y**.
318 #[inline(always)]
319 pub fn get_y(&self) -> u8 { self.y }
320 /// Overwrite the current value of index register **Y**.
321 #[inline(always)]
322 pub fn set_y(&mut self, y: u8) { self.y = y }
323 /// Get the current value of the **S**tack pointer. The next byte pushed
324 /// onto the stack will go into address `$01xx` where `xx` is this value.
325 #[inline(always)]
326 pub fn get_s(&self) -> u8 { self.s }
327 /// Overwrite the current value of the **S**tack pointer.
328 #[inline(always)]
329 pub fn set_s(&mut self, s: u8) { self.s = s }
330 /// Get the current value of the **P**rocessor status register. Use the
331 /// `P_*` constants to interpret the value.
332 #[inline(always)]
333 pub fn get_p(&self) -> u8 { self.p }
334 /// Overwrite the current value of the **P**rocessor status register.
335 /// Can't be used to change the hardwired 1 bit. You can use this to
336 /// implement SOB logic; when the SOB pin should transition to active, do
337 /// something like:
338 ///
339 /// ```rust
340 /// # use w65c02s::*;
341 /// # let mut cpu = W65C02S::new();
342 /// cpu.set_p(cpu.get_p() | P_V);
343 /// ```
344 #[inline(always)]
345 pub fn set_p(&mut self, p: u8) { self.p = p | P_1 }
346 /// Get the current operating state of the CPU. May return a stale value if
347 /// called during a `step`.
348 #[inline(always)]
349 pub fn get_state(&self) -> State { self.state }
350 /// Push a value onto the stack using the given `System`.
351 #[inline(always)]
352 pub fn push<S: System>(&mut self, system: &mut S, value: u8) {
353 system.write_stack(self, 0x100 | self.s as u16, value);
354 self.s = self.s.wrapping_sub(1);
355 }
356 /// Spurious push during reset.
357 #[inline(always)]
358 pub fn spurious_push<S: System>(&mut self, system: &mut S) {
359 // system.read_stack_spurious(self, 0x100 | self.s as u16);
360 self.s = self.s.wrapping_sub(1);
361 }
362 /// Pop a value from the stack using the given `System`.
363 #[inline(always)]
364 pub fn pop<S: System>(&mut self, system: &mut S) -> u8 {
365 self.s = self.s.wrapping_add(1);
366 system.read_stack(self, 0x100 | self.s as u16)
367 }
368 /// Spuriously read a value from the next stack slot, like happens during
369 /// a JSR or RTS or most pulls.
370 #[inline(always)]
371 pub fn spurious_stack_read<S: System>(&mut self, system: &mut S) {
372 // system.read_spurious(self, 0x100 | (self.s as u16));
373 }
374 /// Change the input on the `IRQB` pin. `false` means no interrupt pending.
375 /// `true` means some interrupt is pending. Note that `IRQB` is an active-
376 /// low pin and that the value you pass to this function is the *logical*
377 /// value and not the *electrical* one.
378 #[inline(always)]
379 pub fn set_irq(&mut self, irq: bool) { self.irq = irq }
380 /// Change the input on the NMIB pin. `false` means no NMI pending. A
381 /// transition from `false` to `true` triggers an NMI at the next `step`.
382 /// Note that `NMIB` is an active-low pin and that the value you pass to
383 /// this function is the *logical* value and not the *electrical* one.
384 ///
385 /// This crate does not accurately simulate extremely short NMI pulses, or
386 /// extremely rapid ones. If these conditions arise on real hardware, chaos
387 /// will ensue anyway.
388 #[inline(always)]
389 pub fn set_nmi(&mut self, nmi: bool) {
390 self.nmi_edge = self.nmi_edge || (!self.nmi_edge && nmi);
391 self.nmi = nmi;
392 }
393 /// Internal function. Updates the IRQ and NMI edge flags.
394 #[inline(always)]
395 fn check_irq_edge(&mut self) {
396 self.irq_pending = self.irq && (self.p & P_I) == 0;
397 self.nmi_pending = self.nmi_edge;
398 }
399 /// Set N and Z flags according to the argument value.
400 #[inline(always)]
401 fn nz_p(&mut self, v: u8) {
402 self.p = (self.p & 0x7F) | (v & 0x80);
403 if v == 0 { self.p |= P_Z; }
404 else { self.p &= !P_Z; }
405 }
406 /// Set N and Z flags according to the argument value, and the C flag
407 /// according to the argument.
408 #[inline(always)]
409 fn cnz_p(&mut self, c: bool, v: u8) {
410 self.p = (self.p & 0x7F) | (v & 0x80);
411 if v == 0 { self.p |= P_Z; }
412 else { self.p &= !P_Z; }
413 if c { self.p |= P_C; }
414 else { self.p &= !P_C; }
415 }
416 /// Step the processor once. This means executing an interrupt sequence,
417 /// fetching an instruction, or doing a spurious read, depending on the
418 /// current state of the processor. Returns the new state.
419 ///
420 /// Always executes at least one bus cycle. May execute more.
421 pub fn step<S: System>(&mut self, system: &mut S) -> i32 {
422 match self.state {
423 State::Stopped => /*system.read_operand_spurious(self, self.pc),*/return 1,
424 State::AwaitingInterrupt => {
425 if self.irq || self.nmi_edge {
426 self.state = State::Running;
427 // system.read_operand_spurious(self, self.pc);
428 }
429 self.check_irq_edge();
430 // system.read_operand_spurious(self, self.pc);
431
432 return 2;
433 },
434 State::HasBeenReset => {
435 // first, we spuriously read an opcode
436 // system.read_opcode_spurious(self, self.pc);
437 // second, we read ... the same byte, but with SYNC low
438 // system.read_operand_spurious(self, self.pc);
439 // three spurious pushes...
440 self.spurious_push(system);
441 self.spurious_push(system);
442 self.spurious_push(system);
443 // clear the D flag, set the I flag
444 self.p &= !P_D;
445 self.p |= P_I;
446 // read the reset vector, non-spuriously
447 self.pc = (self.pc & 0xFF00) | (system.read_vector(self, RESET_VECTOR) as u16);
448 self.pc = (self.pc & 0x00FF) | (system.read_vector(self, RESET_VECTOR+1) as u16) << 8;
449 // we are ready to be actually running!
450 self.state = State::Running;
451
452 return 7
453 },
454 State::Running => {
455 if self.nmi_pending {
456 self.nmi_pending = false;
457 self.nmi_edge = false;
458 let opcode_addr = self.get_pc();
459 // system.read_opcode_spurious(self, opcode_addr);
460 // system.read_spurious(self, opcode_addr);
461 self.push(system, (opcode_addr >> 8) as u8);
462 self.push(system, opcode_addr as u8);
463 self.push(system, self.p & !P_B);
464 self.p &= !P_D;
465 self.p |= P_I;
466 self.pc = (self.pc & 0xFF00) | (system.read_vector(self, NMI_VECTOR) as u16);
467 self.pc = (self.pc & 0x00FF) | (system.read_vector(self, NMI_VECTOR+1) as u16) << 8;
468 return 7
469 }
470 else if self.irq_pending {
471 self.irq_pending = false;
472 let opcode_addr = self.get_pc();
473 // system.read_opcode_spurious(self, opcode_addr);
474 // system.read_spurious(self, opcode_addr);
475 self.push(system, (opcode_addr >> 8) as u8);
476 self.push(system, opcode_addr as u8);
477 self.push(system, self.p);
478 self.p &= !P_D;
479 self.p |= P_I;
480 self.pc = (self.pc & 0xFF00) | (system.read_vector(self, IRQ_VECTOR) as u16);
481 self.pc = (self.pc & 0x00FF) | (system.read_vector(self, IRQ_VECTOR+1) as u16) << 8;
482 return 7
483 }
484 else {
485 // oh boy, we're running! oh boy oh boy!
486 let opcode_addr = self.read_pc_postincrement();
487 let opcode = system.read_opcode(self, opcode_addr);
488 // oh boy OH JEEZ
489 match opcode {
490 0x00 => self.brk(system),
491 0x01 => self.ora::<_, ZeroPageXIndirect, S>(system),
492 0x02 => self.nop::<_, Immediate, S>(system),
493 0x03 => self.nop::<_, FastImplied, S>(system),
494 0x04 => self.tsb::<_, ZeroPage, S>(system),
495 0x05 => self.ora::<_, ZeroPage, S>(system),
496 0x06 => self.asl::<_, ZeroPage, S>(system),
497 0x07 => self.rmb::<_, ZeroPage, S>(system, !0x01),
498 0x08 => self.php(system),
499 0x09 => self.ora::<_, Immediate, S>(system),
500 0x0A => self.asl::<_, ImpliedA, S>(system),
501 0x0B => self.nop::<_, FastImplied, S>(system),
502 0x0C => self.tsb::<_, Absolute, S>(system),
503 0x0D => self.ora::<_, Absolute, S>(system),
504 0x0E => self.asl::<_, Absolute, S>(system),
505 0x0F => self.bbr::<_, RelativeBitBranch, S>(system, 0x01),
506 0x10 => self.branch::<_, Relative, S>(system, self.p & P_N == 0),
507 0x11 => self.ora::<_, ZeroPageIndirectY, S>(system),
508 0x12 => self.ora::<_, ZeroPageIndirect, S>(system),
509 0x13 => self.nop::<_, FastImplied, S>(system),
510 0x14 => self.trb::<_, ZeroPage, S>(system),
511 0x15 => self.ora::<_, ZeroPageX, S>(system),
512 0x16 => self.asl::<_, ZeroPageX, S>(system),
513 0x17 => self.rmb::<_, ZeroPage, S>(system, !0x02),
514 0x18 => self.clc(system),
515 0x19 => self.ora::<_, AbsoluteY, S>(system),
516 0x1A => self.inc::<_, ImpliedA, S>(system),
517 0x1B => self.nop::<_, FastImplied, S>(system),
518 0x1C => self.trb::<_, Absolute, S>(system),
519 0x1D => self.ora::<_, AbsoluteX, S>(system),
520 0x1E => self.asl::<_, AbsoluteX, S>(system),
521 0x1F => self.bbr::<_, RelativeBitBranch, S>(system, 0x02),
522 0x20 => self.jsr(system),
523 0x21 => self.and::<_, ZeroPageXIndirect, S>(system),
524 0x22 => self.nop::<_, Immediate, S>(system),
525 0x23 => self.nop::<_, FastImplied, S>(system),
526 0x24 => self.bit::<_, ZeroPage, S>(system),
527 0x25 => self.and::<_, ZeroPage, S>(system),
528 0x26 => self.rol::<_, ZeroPage, S>(system),
529 0x27 => self.rmb::<_, ZeroPage, S>(system, !0x04),
530 0x28 => self.plp(system),
531 0x29 => self.and::<_, Immediate, S>(system),
532 0x2A => self.rol::<_, ImpliedA, S>(system),
533 0x2B => self.nop::<_, FastImplied, S>(system),
534 0x2C => self.bit::<_, Absolute, S>(system),
535 0x2D => self.and::<_, Absolute, S>(system),
536 0x2E => self.rol::<_, Absolute, S>(system),
537 0x2F => self.bbr::<_, RelativeBitBranch, S>(system, 0x04),
538 0x30 => self.branch::<_, Relative, S>(system, self.p & P_N == P_N),
539 0x31 => self.and::<_, ZeroPageIndirectY, S>(system),
540 0x32 => self.and::<_, ZeroPageIndirect, S>(system),
541 0x33 => self.nop::<_, FastImplied, S>(system),
542 0x34 => self.bit::<_, ZeroPageX, S>(system),
543 0x35 => self.and::<_, ZeroPageX, S>(system),
544 0x36 => self.rol::<_, ZeroPageX, S>(system),
545 0x37 => self.rmb::<_, ZeroPage, S>(system, !0x08),
546 0x38 => self.sec(system),
547 0x39 => self.and::<_, AbsoluteY, S>(system),
548 0x3A => self.dec::<_, ImpliedA, S>(system),
549 0x3B => self.nop::<_, FastImplied, S>(system),
550 0x3C => self.bit::<_, AbsoluteX, S>(system),
551 0x3D => self.and::<_, AbsoluteX, S>(system),
552 0x3E => self.rol::<_, AbsoluteX, S>(system),
553 0x3F => self.bbr::<_, RelativeBitBranch, S>(system, 0x08),
554 0x40 => self.rti(system),
555 0x41 => self.eor::<_, ZeroPageXIndirect, S>(system),
556 0x42 => self.nop::<_, Immediate, S>(system),
557 0x43 => self.nop::<_, FastImplied, S>(system),
558 0x44 => self.nop::<_, ZeroPage, S>(system),
559 0x45 => self.eor::<_, ZeroPage, S>(system),
560 0x46 => self.lsr::<_, ZeroPage, S>(system),
561 0x47 => self.rmb::<_, ZeroPage, S>(system, !0x10),
562 0x48 => self.pha(system),
563 0x49 => self.eor::<_, Immediate, S>(system),
564 0x4A => self.lsr::<_, ImpliedA, S>(system),
565 0x4B => self.nop::<_, FastImplied, S>(system),
566 0x4C => self.jmp::<_, Absolute, S>(system),
567 0x4D => self.eor::<_, Absolute, S>(system),
568 0x4E => self.lsr::<_, Absolute, S>(system),
569 0x4F => self.bbr::<_, RelativeBitBranch, S>(system, 0x10),
570 0x50 => self.branch::<_, Relative, S>(system, self.p & P_V == 0),
571 0x51 => self.eor::<_, ZeroPageIndirectY, S>(system),
572 0x52 => self.eor::<_, ZeroPageIndirect, S>(system),
573 0x53 => self.nop::<_, FastImplied, S>(system),
574 0x54 => self.nop::<_, ZeroPageX, S>(system),
575 0x55 => self.eor::<_, ZeroPageX, S>(system),
576 0x56 => self.lsr::<_, ZeroPageX, S>(system),
577 0x57 => self.rmb::<_, ZeroPage, S>(system, !0x20),
578 0x58 => self.cli(system),
579 0x59 => self.eor::<_, AbsoluteY, S>(system),
580 0x5A => self.phy(system),
581 0x5B => self.nop::<_, FastImplied, S>(system),
582 0x5C => self.nop_5c::<_, Absolute, S>(system),
583 0x5D => self.eor::<_, AbsoluteX, S>(system),
584 0x5E => self.lsr::<_, AbsoluteX, S>(system),
585 0x5F => self.bbr::<_, RelativeBitBranch, S>(system, 0x20),
586 0x60 => self.rts(system),
587 0x61 => self.adc::<_, ZeroPageXIndirect, S>(system),
588 0x62 => self.nop::<_, Immediate, S>(system),
589 0x63 => self.nop::<_, FastImplied, S>(system),
590 0x64 => self.stz::<_, ZeroPage, S>(system),
591 0x65 => self.adc::<_, ZeroPage, S>(system),
592 0x66 => self.ror::<_, ZeroPage, S>(system),
593 0x67 => self.rmb::<_, ZeroPage, S>(system, !0x40),
594 0x68 => self.pla(system),
595 0x69 => self.adc::<_, Immediate, S>(system),
596 0x6A => self.ror::<_, ImpliedA, S>(system),
597 0x6B => self.nop::<_, FastImplied, S>(system),
598 0x6C => self.jmp::<_, AbsoluteIndirect, S>(system),
599 0x6D => self.adc::<_, Absolute, S>(system),
600 0x6E => self.ror::<_, Absolute, S>(system),
601 0x6F => self.bbr::<_, RelativeBitBranch, S>(system, 0x40),
602 0x70 => self.branch::<_, Relative, S>(system, self.p & P_V == P_V),
603 0x71 => self.adc::<_, ZeroPageIndirectY, S>(system),
604 0x72 => self.adc::<_, ZeroPageIndirect, S>(system),
605 0x73 => self.nop::<_, FastImplied, S>(system),
606 0x74 => self.stz::<_, ZeroPageX, S>(system),
607 0x75 => self.adc::<_, ZeroPageX, S>(system),
608 0x76 => self.ror::<_, ZeroPageX, S>(system),
609 0x77 => self.rmb::<_, ZeroPage, S>(system, !0x80),
610 0x78 => self.sei(system),
611 0x79 => self.adc::<_, AbsoluteY, S>(system),
612 0x7A => self.ply(system),
613 0x7B => self.nop::<_, FastImplied, S>(system),
614 0x7C => self.jmp::<_, AbsoluteXIndirect, S>(system),
615 0x7D => self.adc::<_, AbsoluteX, S>(system),
616 0x7E => self.ror::<_, AbsoluteX, S>(system),
617 0x7F => self.bbr::<_, RelativeBitBranch, S>(system, 0x80),
618 0x80 => self.branch::<_, Relative, S>(system, true),
619 0x81 => self.sta::<_, ZeroPageXIndirect, S>(system),
620 0x82 => self.nop::<_, Immediate, S>(system),
621 0x83 => self.nop::<_, FastImplied, S>(system),
622 0x84 => self.sty::<_, ZeroPage, S>(system),
623 0x85 => self.sta::<_, ZeroPage, S>(system),
624 0x86 => self.stx::<_, ZeroPage, S>(system),
625 0x87 => self.smb::<_, ZeroPage, S>(system, 0x01),
626 0x88 => self.dec::<_, ImpliedY, S>(system),
627 0x89 => self.bit_i::<_, Immediate, S>(system),
628 0x8A => self.txa(system),
629 0x8B => self.nop::<_, FastImplied, S>(system),
630 0x8C => self.sty::<_, Absolute, S>(system),
631 0x8D => self.sta::<_, Absolute, S>(system),
632 0x8E => self.stx::<_, Absolute, S>(system),
633 0x8F => self.bbs::<_, RelativeBitBranch, S>(system, 0x01),
634 0x90 => self.branch::<_, Relative, S>(system, self.p & P_C == 0),
635 0x91 => self.sta::<_, ZeroPageIndirectYSlower, S>(system),
636 0x92 => self.sta::<_, ZeroPageIndirect, S>(system),
637 0x93 => self.nop::<_, FastImplied, S>(system),
638 0x94 => self.sty::<_, ZeroPageX, S>(system),
639 0x95 => self.sta::<_, ZeroPageX, S>(system),
640 0x96 => self.stx::<_, ZeroPageY, S>(system),
641 0x97 => self.smb::<_, ZeroPage, S>(system, 0x02),
642 0x98 => self.tya(system),
643 0x99 => self.sta::<_, AbsoluteYSlower, S>(system),
644 0x9A => self.txs(system),
645 0x9B => self.nop::<_, FastImplied, S>(system),
646 0x9C => self.stz::<_, Absolute, S>(system),
647 0x9D => self.sta::<_, AbsoluteXSlower, S>(system),
648 0x9E => self.stz::<_, AbsoluteXSlower, S>(system),
649 0x9F => self.bbs::<_, RelativeBitBranch, S>(system, 0x02),
650 0xA0 => self.ldy::<_, Immediate, S>(system),
651 0xA1 => self.lda::<_, ZeroPageXIndirect, S>(system),
652 0xA2 => self.ldx::<_, Immediate, S>(system),
653 0xA3 => self.nop::<_, FastImplied, S>(system),
654 0xA4 => self.ldy::<_, ZeroPage, S>(system),
655 0xA5 => self.lda::<_, ZeroPage, S>(system),
656 0xA6 => self.ldx::<_, ZeroPage, S>(system),
657 0xA7 => self.smb::<_, ZeroPage, S>(system, 0x04),
658 0xA8 => self.tay(system),
659 0xA9 => self.lda::<_, Immediate, S>(system),
660 0xAA => self.tax(system),
661 0xAB => self.nop::<_, FastImplied, S>(system),
662 0xAC => self.ldy::<_, Absolute, S>(system),
663 0xAD => self.lda::<_, Absolute, S>(system),
664 0xAE => self.ldx::<_, Absolute, S>(system),
665 0xAF => self.bbs::<_, RelativeBitBranch, S>(system, 0x04),
666 0xB0 => self.branch::<_, Relative, S>(system, self.p & P_C == P_C),
667 0xB1 => self.lda::<_, ZeroPageIndirectY, S>(system),
668 0xB2 => self.lda::<_, ZeroPageIndirect, S>(system),
669 0xB3 => self.nop::<_, FastImplied, S>(system),
670 0xB4 => self.ldy::<_, ZeroPageX, S>(system),
671 0xB5 => self.lda::<_, ZeroPageX, S>(system),
672 0xB6 => self.ldx::<_, ZeroPageY, S>(system),
673 0xB7 => self.smb::<_, ZeroPage, S>(system, 0x08),
674 0xB8 => self.clv(system),
675 0xB9 => self.lda::<_, AbsoluteY, S>(system),
676 0xBA => self.tsx(system),
677 0xBB => self.nop::<_, FastImplied, S>(system),
678 0xBC => self.ldy::<_, AbsoluteX, S>(system),
679 0xBD => self.lda::<_, AbsoluteX, S>(system),
680 0xBE => self.ldx::<_, AbsoluteY, S>(system),
681 0xBF => self.bbs::<_, RelativeBitBranch, S>(system, 0x08),
682 0xC0 => self.cpy::<_, Immediate, S>(system),
683 0xC1 => self.cmp::<_, ZeroPageXIndirect, S>(system),
684 0xC2 => self.nop::<_, Immediate, S>(system),
685 0xC3 => self.nop::<_, FastImplied, S>(system),
686 0xC4 => self.cpy::<_, ZeroPage, S>(system),
687 0xC5 => self.cmp::<_, ZeroPage, S>(system),
688 0xC6 => self.dec::<_, ZeroPage, S>(system),
689 0xC7 => self.smb::<_, ZeroPage, S>(system, 0x10),
690 0xC8 => self.inc::<_, ImpliedY, S>(system),
691 0xC9 => self.cmp::<_, Immediate, S>(system),
692 0xCA => self.dec::<_, ImpliedX, S>(system),
693 0xCB => self.wai(system),
694 0xCC => self.cpy::<_, Absolute, S>(system),
695 0xCD => self.cmp::<_, Absolute, S>(system),
696 0xCE => self.dec::<_, Absolute, S>(system),
697 0xCF => self.bbs::<_, RelativeBitBranch, S>(system, 0x10),
698 0xD0 => self.branch::<_, Relative, S>(system, self.p & P_Z == 0),
699 0xD1 => self.cmp::<_, ZeroPageIndirectY, S>(system),
700 0xD2 => self.cmp::<_, ZeroPageIndirect, S>(system),
701 0xD3 => self.nop::<_, FastImplied, S>(system),
702 0xD4 => self.nop::<_, ZeroPageX, S>(system),
703 0xD5 => self.cmp::<_, ZeroPageX, S>(system),
704 0xD6 => self.dec::<_, ZeroPageX, S>(system),
705 0xD7 => self.smb::<_, ZeroPage, S>(system, 0x20),
706 0xD8 => self.cld(system),
707 0xD9 => self.cmp::<_, AbsoluteY, S>(system),
708 0xDA => self.phx(system),
709 0xDB => self.stp(system),
710 0xDC => self.nop::<_, Absolute, S>(system),
711 0xDD => self.cmp::<_, AbsoluteX, S>(system),
712 0xDE => self.dec::<_, AbsoluteXSlower, S>(system),
713 0xDF => self.bbs::<_, RelativeBitBranch, S>(system, 0x20),
714 0xE0 => self.cpx::<_, Immediate, S>(system),
715 0xE1 => self.sbc::<_, ZeroPageXIndirect, S>(system),
716 0xE2 => self.nop::<_, Immediate, S>(system),
717 0xE3 => self.nop::<_, FastImplied, S>(system),
718 0xE4 => self.cpx::<_, ZeroPage, S>(system),
719 0xE5 => self.sbc::<_, ZeroPage, S>(system),
720 0xE6 => self.inc::<_, ZeroPage, S>(system),
721 0xE7 => self.smb::<_, ZeroPage, S>(system, 0x40),
722 0xE8 => self.inc::<_, ImpliedX, S>(system),
723 0xE9 => self.sbc::<_, Immediate, S>(system),
724 0xEA => self.nop::<_, Implied, S>(system),
725 0xEB => self.nop::<_, FastImplied, S>(system),
726 0xEC => self.cpx::<_, Absolute, S>(system),
727 0xED => self.sbc::<_, Absolute, S>(system),
728 0xEE => self.inc::<_, Absolute, S>(system),
729 0xEF => self.bbs::<_, RelativeBitBranch, S>(system, 0x40),
730 0xF0 => self.branch::<_, Relative, S>(system, self.p & P_Z == P_Z),
731 0xF1 => self.sbc::<_, ZeroPageIndirectY, S>(system),
732 0xF2 => self.sbc::<_, ZeroPageIndirect, S>(system),
733 0xF3 => self.nop::<_, FastImplied, S>(system),
734 0xF4 => self.nop::<_, ZeroPageX, S>(system),
735 0xF5 => self.sbc::<_, ZeroPageX, S>(system),
736 0xF6 => self.inc::<_, ZeroPageX, S>(system),
737 0xF7 => self.smb::<_, ZeroPage, S>(system, 0x80),
738 0xF8 => self.sed(system),
739 0xF9 => self.sbc::<_, AbsoluteY, S>(system),
740 0xFA => self.plx(system),
741 0xFB => self.nop::<_, FastImplied, S>(system),
742 0xFC => self.nop::<_, Absolute, S>(system),
743 0xFD => self.sbc::<_, AbsoluteX, S>(system),
744 0xFE => self.inc::<_, AbsoluteXSlower, S>(system),
745 0xFF => self.bbs::<_, RelativeBitBranch, S>(system, 0x80),
746 }
747
748 return OPCODE_CYCLES[opcode as usize];
749 }
750 },
751 }
752 1
753 }
754}
755