Added JIT base

This commit is contained in:
tudnai 2021-06-09 22:12:23 -07:00
parent 14a1fb982b
commit 87325f3e2b
24 changed files with 4148 additions and 0 deletions

View File

@ -640,6 +640,22 @@
32A6AA97266187570023257A /* hires.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = hires.c; sourceTree = "<group>"; };
32A6AABF2669B5480023257A /* mmio.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mmio.c; sourceTree = "<group>"; };
32A6AB0E266AF5160023257A /* paddle.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = paddle.c; sourceTree = "<group>"; };
32A6AB372671D0560023257A /* 6502.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = 6502.h; sourceTree = "<group>"; };
32A6AB382671D0570023257A /* 6502.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = 6502.c; sourceTree = "<group>"; };
32A6AB462671D0660023257A /* 6502_instr_set_clr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = 6502_instr_set_clr.h; sourceTree = "<group>"; };
32A6AB472671D0660023257A /* 6502_instr_stack.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = 6502_instr_stack.h; sourceTree = "<group>"; };
32A6AB482671D0660023257A /* 6502_instr_logic.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = 6502_instr_logic.h; sourceTree = "<group>"; };
32A6AB492671D0660023257A /* 6502_instr_shift_rotate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = 6502_instr_shift_rotate.h; sourceTree = "<group>"; };
32A6AB4A2671D0660023257A /* 6502_instr_inc_dec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = 6502_instr_inc_dec.h; sourceTree = "<group>"; };
32A6AB4B2671D0660023257A /* 6502_instr_compare_test.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = 6502_instr_compare_test.h; sourceTree = "<group>"; };
32A6AB4C2671D0660023257A /* 6502_instr_branch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = 6502_instr_branch.h; sourceTree = "<group>"; };
32A6AB4D2671D0660023257A /* 6502_instr_misc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = 6502_instr_misc.h; sourceTree = "<group>"; };
32A6AB4E2671D0660023257A /* 6502_instr_arithmetic.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = 6502_instr_arithmetic.h; sourceTree = "<group>"; };
32A6AB4F2671D0660023257A /* 6502_instr_undoc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = 6502_instr_undoc.h; sourceTree = "<group>"; };
32A6AB502671D0660023257A /* 6502_instr_transfer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = 6502_instr_transfer.h; sourceTree = "<group>"; };
32A6AB512671D0660023257A /* 6502_instr_load_store.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = 6502_instr_load_store.h; sourceTree = "<group>"; };
32A6AB522671D0660023257A /* 6502_instr_call_ret_jump.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = 6502_instr_call_ret_jump.h; sourceTree = "<group>"; };
32A6AB532671D0660023257A /* 6502_instructions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = 6502_instructions.h; sourceTree = "<group>"; };
32A9F7482467B60B004902A1 /* speaker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = speaker.h; sourceTree = "<group>"; };
32A9F7492467B60B004902A1 /* speaker.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = speaker.c; sourceTree = "<group>"; };
32AF7C9624AD85E8002D82BF /* select_all.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = select_all.png; sourceTree = "<group>"; };
@ -903,6 +919,7 @@
325EB63A23FA572000C6B4A4 /* cpu */ = {
isa = PBXGroup;
children = (
32A6AB362671CED60023257A /* jit */,
32439F7522ECD8AD0077AAE0 /* instructions */,
32439F8522ECD8AD0077AAE0 /* 6502.h */,
32439F7422ECD8AD0077AAE0 /* 6502.c */,
@ -989,6 +1006,37 @@
path = video;
sourceTree = "<group>";
};
32A6AB362671CED60023257A /* jit */ = {
isa = PBXGroup;
children = (
32A6AB452671D0660023257A /* instructions */,
32A6AB382671D0570023257A /* 6502.c */,
32A6AB372671D0560023257A /* 6502.h */,
);
path = jit;
sourceTree = "<group>";
};
32A6AB452671D0660023257A /* instructions */ = {
isa = PBXGroup;
children = (
32A6AB462671D0660023257A /* 6502_instr_set_clr.h */,
32A6AB472671D0660023257A /* 6502_instr_stack.h */,
32A6AB482671D0660023257A /* 6502_instr_logic.h */,
32A6AB492671D0660023257A /* 6502_instr_shift_rotate.h */,
32A6AB4A2671D0660023257A /* 6502_instr_inc_dec.h */,
32A6AB4B2671D0660023257A /* 6502_instr_compare_test.h */,
32A6AB4C2671D0660023257A /* 6502_instr_branch.h */,
32A6AB4D2671D0660023257A /* 6502_instr_misc.h */,
32A6AB4E2671D0660023257A /* 6502_instr_arithmetic.h */,
32A6AB4F2671D0660023257A /* 6502_instr_undoc.h */,
32A6AB502671D0660023257A /* 6502_instr_transfer.h */,
32A6AB512671D0660023257A /* 6502_instr_load_store.h */,
32A6AB522671D0660023257A /* 6502_instr_call_ret_jump.h */,
32A6AB532671D0660023257A /* 6502_instructions.h */,
);
path = instructions;
sourceTree = "<group>";
};
32A9F7472467B5DF004902A1 /* audio */ = {
isa = PBXGroup;
children = (

54
A2Mac/DisplayView.swift Normal file
View File

@ -0,0 +1,54 @@
//
// DisplayView.swift
// Steve ][
//
// Created by Tamas Rudnai on 5/11/21.
// Copyright © 2021 GameAlloy. All rights reserved.
//
import Cocoa
class DisplayView: NSTextView {
// override var acceptsFirstResponder: Bool {
// get {
// return true
// }
// }
override func acceptsFirstMouse(for event: NSEvent?) -> Bool {
return true
}
override func mouseDown(with event: NSEvent) {
// print(#function + "DisplayView")
ViewController.current?.mouseDown(with: event)
}
override func mouseUp(with event: NSEvent) {
// print(#function + "DisplayView")
ViewController.current?.mouseUp(with: event)
}
override func rightMouseDown(with event: NSEvent) {
// print(#function + "DisplayView")
ViewController.current?.rightMouseDown(with: event)
}
override func rightMouseUp(with event: NSEvent) {
// print(#function + "DisplayView")
ViewController.current?.rightMouseUp(with: event)
}
override func otherMouseDown(with event: NSEvent) {
// print(#function + "DisplayView")
ViewController.current?.otherMouseDown(with: event)
}
override func otherMouseUp(with event: NSEvent) {
// print(#function + "DisplayView")
ViewController.current?.otherMouseUp(with: event)
}
}

BIN
A2Mac/Steve2Icon.icns Normal file

Binary file not shown.

BIN
A2Mac/Steve2Icon_.icns Normal file

Binary file not shown.

83
src/cpu/6502_C.h Normal file
View File

@ -0,0 +1,83 @@
//
// 6502_und.h
// A2Mac
//
// Created by Tamas Rudnai on 7/27/20.
// Copyright © 2019, 2020 Tamas Rudnai. All rights reserved.
//
// This file is part of Steve ][ -- The Apple ][ Emulator.
//
// Steve ][ is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Steve ][ is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Steve ][. If not, see <https://www.gnu.org/licenses/>.
//
// Documentations:
//
// http://nesdev.com/6502_cpu.txt
// http://www.oxyron.de/html/opcodes02.html
// https://macgui.com/kb/article/46
// https://www.masswerk.at/6502/6502_instruction_set.html
//
#ifndef _6502_C_h
#define _6502_C_h
// 6502 instructions with additional addressing modes
// ADC AND CMP EOR LDA ORA SBC STA - (zp) addressing mode
case 0x12: ORA( src_zp_0() ); return 5; // ORA (zpg)
case 0x32: AND( src_zp_0() ); return 5; // AND (zpg)
case 0x52: EOR( src_zp_0() ); return 5; // EOR (zpg)
case 0x72: ADC( src_zp_0() ); return 5; // ADC (zpg)
case 0x92: STA( src_zp_0() ); return 5; // STA (zpg)
case 0xB2: LDA( src_zp_0() ); return 5; // LDA (zpg)
case 0xD2: CMP( src_zp_0() ); return 5; // CMP (zpg)
case 0xF2: SBC( src_zp_0() ); return 5; // SBC (zpg)
// BIT - imm abs,X zp,X addressing modes
case 0x34: BIT( src_zp_X() ); return 4; // BIT zpg,X
case 0x3C: BIT( src_abs_X() ); return 4; // BIT abs,X
case 0x89: BIT( imm() ); return 2; // BIT imm
// DEC INC - acc addressing mode
case 0x1A: INA(); return 2; // INA imm (INC A)
case 0x3A: DEA(); return 2; // DEA imm (DEC A)
// JMP - (abs,X) addressing mode
case 0x7C: JMP( addr_abs_X() ); return 6; // JMP abs,X
// Additional instructions
// BRA - BRanch Always
case 0x80: BRA( rel_addr() ); return 3; // BRA reladdr
// PHX PHY PLX PLY - PusH or PulL X or Y register
case 0x5A: PHY(); return 3; // PHY
case 0x7A: PLY(); return 4; // PLY
case 0xDA: PHX(); return 3; // PHX
case 0xFA: PLX(); return 4; // PLX
// STZ - STore Zero
case 0x64: STZ( addr_zp() ); return 3; // STZ zpg
case 0x74: STZ( addr_zp_X() ); return 4; // STZ zpg,X
case 0x9C: STZ( addr_abs() ); return 4; // STZ abs
case 0x9E: STZ( addr_abs_X() ); return 5; // STZ abs,X
// TRB - Test and Reset Bits
case 0x04: TSB( addr_zp() ); return 5; // TSB zpg
case 0x0C: TSB( addr_abs() ); return 6; // TSB abs
case 0x14: TRB( addr_zp() ); return 5; // TRB zpg
case 0x1C: TRB( addr_abs() ); return 6; // TRB abs
#endif /* _6502_C_h */

78
src/cpu/6502_C_Rockwell.h Normal file
View File

@ -0,0 +1,78 @@
//
// 6502_und.h
// A2Mac
//
// Created by Tamas Rudnai on 7/27/20.
// Copyright © 2019, 2020 Tamas Rudnai. All rights reserved.
//
// This file is part of Steve ][ -- The Apple ][ Emulator.
//
// Steve ][ is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Steve ][ is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Steve ][. If not, see <https://www.gnu.org/licenses/>.
//
// Documentations:
//
// http://nesdev.com/6502_cpu.txt
// http://www.oxyron.de/html/opcodes02.html
// https://macgui.com/kb/article/46
// https://www.masswerk.at/6502/6502_instruction_set.html
//
#ifndef _6502_C_Rockwell_h
#define _6502_C_Rockwell_h
// Additional Rockwell 65C02 and WDC 65C02 instructions
// Four additional instructions and one additional addressing mode are available on 65C02s manufactured by Rockwell and WDC
// BBR BBS - Branch on Bit Reset or Set
case 0x0F: BBR0( src_zp(), rel_addr() ); return 5; // BBR0 zpg, rel
case 0x1F: BBR1( src_zp(), rel_addr() ); return 5; // BBR1 zpg, rel
case 0x2F: BBR2( src_zp(), rel_addr() ); return 5; // BBR2 zpg, rel
case 0x3F: BBR3( src_zp(), rel_addr() ); return 5; // BBR3 zpg, rel
case 0x4F: BBR4( src_zp(), rel_addr() ); return 5; // BBR4 zpg, rel
case 0x5F: BBR5( src_zp(), rel_addr() ); return 5; // BBR5 zpg, rel
case 0x6F: BBR6( src_zp(), rel_addr() ); return 5; // BBR6 zpg, rel
case 0x7F: BBR7( src_zp(), rel_addr() ); return 5; // BBR7 zpg, rel
case 0x8F: BBS0( src_zp(), rel_addr() ); return 5; // BBS0 zpg, rel
case 0x9F: BBS1( src_zp(), rel_addr() ); return 5; // BBS1 zpg, rel
case 0xAF: BBS2( src_zp(), rel_addr() ); return 5; // BBS2 zpg, rel
case 0xBF: BBS3( src_zp(), rel_addr() ); return 5; // BBS3 zpg, rel
case 0xCF: BBS4( src_zp(), rel_addr() ); return 5; // BBS4 zpg, rel
case 0xDF: BBS5( src_zp(), rel_addr() ); return 5; // BBS5 zpg, rel
case 0xEF: BBS6( src_zp(), rel_addr() ); return 5; // BBS6 zpg, rel
case 0xFF: BBS7( src_zp(), rel_addr() ); return 5; // BBS7 zpg, rel
// RMB SMB - Reset or Set Memory Bit
case 0x07: RMB0( src_zp() ); return 5; // RMB0 zpg, rel
case 0x17: RMB1( src_zp() ); return 5; // RMB1 zpg, rel
case 0x27: RMB2( src_zp() ); return 5; // RMB2 zpg, rel
case 0x37: RMB3( src_zp() ); return 5; // RMB3 zpg, rel
case 0x47: RMB4( src_zp() ); return 5; // RMB4 zpg, rel
case 0x57: RMB5( src_zp() ); return 5; // RMB5 zpg, rel
case 0x67: RMB6( src_zp() ); return 5; // RMB6 zpg, rel
case 0x77: RMB7( src_zp() ); return 5; // RMB7 zpg, rel
case 0x87: SMB0( src_zp() ); return 5; // SMB0 zpg, rel
case 0x97: SMB1( src_zp() ); return 5; // SMB1 zpg, rel
case 0xA7: SMB2( src_zp() ); return 5; // SMB2 zpg, rel
case 0xB7: SMB3( src_zp() ); return 5; // SMB3 zpg, rel
case 0xC7: SMB4( src_zp() ); return 5; // SMB4 zpg, rel
case 0xD7: SMB5( src_zp() ); return 5; // SMB5 zpg, rel
case 0xE7: SMB6( src_zp() ); return 5; // SMB6 zpg, rel
case 0xF7: SMB7( src_zp() ); return 5; // SMB7 zpg, rel
#endif /* _6502_C_Rockwell_h */

251
src/cpu/6502_std.h Normal file
View File

@ -0,0 +1,251 @@
//
// 6502_std.h
// A2Mac
//
// Created by Tamas Rudnai on 7/27/20.
// Copyright © 2019, 2020 Tamas Rudnai. All rights reserved.
//
// This file is part of Steve ][ -- The Apple ][ Emulator.
//
// Steve ][ is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Steve ][ is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Steve ][. If not, see <https://www.gnu.org/licenses/>.
//
// Documentations:
//
// http://nesdev.com/6502_cpu.txt
// http://www.oxyron.de/html/opcodes02.html
// https://macgui.com/kb/article/46
// https://www.masswerk.at/6502/6502_instruction_set.html
//
#ifndef _6502_std_h
#define _6502_std_h
case 0x00: BRK(); return 7; // BRK
case 0x01: ORA( src_X_ind() ); return 6; // ORA X,ind
case 0x05: ORA( src_zp() ); return 3; // ORA zpg
case 0x06: ASL( addr_zp() ); return 5; // ASL zpg
case 0x08: PHP(); return 3; // PHP
case 0x09: ORA( imm() ); return 2; // ORA imm
case 0x0A: ASLA(); return 2; // ASL A
case 0x0D: ORA( src_abs() ); return 4; // ORA abs
case 0x0E: ASL( addr_abs() ); return 6; // ASL abs
case 0x10: BPL( rel_addr() ); return 3; // BPL rel
case 0x11: ORA( src_ind_Y() ); return 5; // ORA ind,Y
case 0x15: ORA( src_zp_X() ); return 4; // ORA zpg,X
case 0x16: ASL( addr_zp_X() ); return 6; // ASL zpg,X
case 0x18: CLC(); return 2; // CLC
case 0x19: ORA( src_abs_Y() ); return 4+1; // ORA abs,Y
case 0x1D: ORA( src_abs_X() ); return 4+1; // ORA abs,X
case 0x1E: ASL( addr_abs_X() ); return 7; // ASL abs,X
case 0x20: JSR( abs_addr() ); return 6; // JSR abs
case 0x21: AND( src_X_ind() ); return 6; // AND X,ind
case 0x24: BIT( src_zp() ); return 3; // BIT zpg
case 0x25: AND( src_zp() ); return 3; // AND zpg
case 0x26: ROL( addr_zp() ); return 5; // ROL zpg
case 0x28: PLP(); return 4; // PLP
case 0x29: AND( imm() ); return 2; // AND imm
case 0x2A: ROLA(); return 2; // ROL A
case 0x2C: BIT( src_abs() ); return 4; // BIT abs
case 0x2D: AND( src_abs() ); return 4; // AND abs
case 0x2E: ROL( addr_abs() ); return 6; // ROL abs
case 0x30: BMI( rel_addr() ); return 3; // BMI rel
case 0x31: AND( src_ind_Y() ); return 5; // AND ind,Y
case 0x35: AND( src_zp_X() ); return 4; // AND zpg,X
case 0x36: ROL( addr_zp_X() ); return 6; // ROL zpg,X
case 0x38: SEC(); return 2; // SEC
case 0x39: AND( src_abs_Y() ); return 4+1; // AND abs,Y
case 0x3D: AND( src_abs_X() ); return 4+1; // AND abs,X
case 0x3E: ROL( addr_abs_X() ); return 7; // ROL abs,X
case 0x40: RTI(); return 6; // RTI
case 0x41: EOR( src_X_ind() ); return 6; // EOR X,ind
case 0x45: EOR( src_zp() ); return 3; // EOR zpg
case 0x46: LSR( addr_zp() ); return 5; // LSR zpg
case 0x48: PHA(); return 3; // PHA
case 0x49: EOR( imm() ); return 2; // EOR imm
case 0x4A: LSRA(); return 2; // LSR A
case 0x4C: JMP( abs_addr() ); return 3; // JMP abs
case 0x4D: EOR( src_abs() ); return 4; // EOR abs
case 0x4E: LSR( addr_abs() ); return 6; // LSR abs
case 0x50: BVC( rel_addr() ); return 3; // BVC rel
case 0x51: EOR( src_ind_Y() ); return 5; // EOR ind,Y
case 0x55: EOR( src_zp_X() ); return 4; // AND zpg,X
case 0x56: LSR( addr_zp_X() ); return 6; // LSR zpg,X
case 0x58: CLI(); return 2; // CLI
case 0x59: EOR( src_abs_Y() ); return 4+1; // EOR abs,Y
case 0x5D: EOR( src_abs_X() ); return 4+1; // EOR abs,X
case 0x5E: LSR( addr_abs_X() ); return 7; // LSR abs,X
case 0x60: RTS(); return 6; // RTS
case 0x61: ADC( src_X_ind() ); return 6; // ADC X,ind
case 0x65: ADC( src_zp() ); return 3; // ADC zpg
case 0x66: ROR( addr_zp() ); return 5; // ROR zpg
case 0x68: PLA(); return 4; // PLA
case 0x69: ADC( imm() ); return 2; // ADC imm
case 0x6A: RORA(); return 2; // ROR A
case 0x6C: JMP( ind_addr() ); return 5; // JMP ind
case 0x6D: ADC( src_abs() ); return 4; // ADC abs
case 0x6E: ROR( addr_abs() ); return 6; // ROR abs
case 0x70: BVS( rel_addr() ); return 3; // BVS rel
case 0x71: ADC( src_ind_Y() ); return 5; // ADC ind,Y
case 0x75: ADC( src_zp_X() ); return 4; // ADC zpg,X
case 0x76: ROR( addr_zp_X() ); return 6; // ROR zpg,X
case 0x78: SEI(); return 2; // SEI
case 0x79: ADC( src_abs_Y() ); return 4+1; // ADC abs,Y
case 0x7D: ADC( src_abs_X() ); return 4+1; // ADC abs,X
case 0x7E: ROR( addr_abs_X() ); return 7; // ROR abs,X
case 0x81: STA( addr_ind_X() ) ; return 6; // STA X,ind
case 0x84: STY( addr_zp() ); return 3; // STY zpg
case 0x85: STA( addr_zp() ); return 3; // STA zpg
case 0x86: STX( addr_zp() ); return 3; // STX zpg
case 0x88: DEY(); return 2; // DEY
case 0x8A: TXA(); return 2; // TXA
case 0x8C: STY( addr_abs() ); return 4; // STY abs
case 0x8D: STA( addr_abs() ); return 4; // STA abs
case 0x8E: STX( addr_abs() ); return 4; // STX abs
case 0x90: BCC( rel_addr() ); return 3; // BCC rel
case 0x91: STA( addr_ind_Y() ); return 6; // STA ind,Y
case 0x94: STY( addr_zp_X() ); return 4; // STY zpg,X
case 0x95: STA( addr_zp_X() ); return 4; // STA zpg,X
case 0x96: STX( addr_zp_Y() ); return 4; // STX zpg,Y
case 0x98: TYA(); return 2; // TYA
case 0x99: STA( addr_abs_Y() ); return 5; // STA abs,Y
case 0x9A: TXS(); return 2; // TXS
case 0x9D: STA( addr_abs_X() ); return 5; // STA abs,X
case 0xA0: LDY( imm() ); return 2; // LDY imm
case 0xA1: LDA( src_X_ind() ) ; return 6; // LDA X,ind
case 0xA2: LDX( imm() ); return 2; // LDX imm
case 0xA4: LDY( src_zp() ); return 3; // LDY zpg
case 0xA5: LDA( src_zp() ); return 3; // LDA zpg
case 0xA6: LDX( src_zp() ); return 3; // LDX zpg
case 0xA8: TAY(); return 2; // TAY
case 0xA9: LDA( imm() ); return 2; // LDA imm
case 0xAA: TAX(); return 2; // TAX
case 0xAC: LDY( src_abs() ); return 4; // LDY abs
case 0xAD: LDA( src_abs() ); return 4; // LDA abs
case 0xAE: LDX( src_abs() ); return 4; // LDX abs
case 0xB0: BCS( rel_addr() ); return 3; // BCS rel
case 0xB1: LDA( src_ind_Y() ); return 5; // LDA ind,Y
case 0xB4: LDY( src_zp_X() ); return 4+1; // LDY zpg,X
case 0xB5: LDA( src_zp_X() ); return 4+1; // LDA zpg,X
case 0xB6: LDX( src_zp_Y() ); return 4+1; // LDX zpg,Y
case 0xB8: CLV(); return 2; // CLV
case 0xB9: LDA( src_abs_Y() ); return 4; // LDA abs,Y
case 0xBA: TSX(); return 2; // TSX
case 0xBC: LDY( src_abs_X() ); return 4; // LDY abs,X
case 0xBD: LDA( src_abs_X() ); return 4; // LDA abs,X
case 0xBE: LDX( src_abs_Y() ); return 4;
// LDX abs,Y
case 0xC0: CPY( imm() ); return 2; // CPY imm
case 0xC1: CMP( src_X_ind() ) ; return 6; // LDA X,ind
case 0xC4: CPY( src_zp() ); return 3; // CPY zpg
case 0xC5: CMP( src_zp() ); return 3; // CMP zpg
case 0xC6: DEC( addr_zp() ); return 5; // DEC zpg
case 0xC8: INY(); return 2; // INY
case 0xC9: CMP( imm() ); return 2; // CMP imm
case 0xCA: DEX(); return 2; // DEX
case 0xCC: CPY( src_abs() ); return 4; // CPY abs
case 0xCD: CMP( src_abs() ); return 4; // CMP abs
case 0xCE: DEC( addr_abs() ); return 6; // DEC abs
case 0xD0: BNE( rel_addr() ); return 3; // BNE rel
case 0xD1: CMP( src_ind_Y() ); return 5; // CMP ind,Y
case 0xD5: CMP( src_zp_X() ); return 4; // CMP zpg,X
case 0xD6: DEC( addr_zp_X() ); return 6; // DEC zpg,X
case 0xD8: CLD(); return 2; // CLD
case 0xD9: CMP( src_abs_Y() ); return 4; // CMP abs,Y
case 0xDD: CMP( src_abs_X() ); return 4; // CMP abs,X
case 0xDE: DEC( addr_abs_X() ); return 7; // DEC abs,X
case 0xE0: CPX( imm() ); return 2; // CPX imm
case 0xE1: SBC( src_X_ind() ) ; return 6; // SBC (X,ind)
case 0xE4: CPX( src_zp() ); return 3; // CPX zpg
case 0xE5: SBC( src_zp() ); return 3; // SBC zpg
case 0xE6: INC( addr_zp() ); return 5; // INC zpg
case 0xE8: INX(); return 2; // INX
case 0xE9: SBC( imm() ); return 2; // SBC imm
case 0xEA: NOP(); return 2; // NOP
case 0xEC: CPX( src_abs() ); return 4; // CPX abs
case 0xED: SBC( src_abs() ); return 4; // SBC abs
case 0xEE: INC( addr_abs() ); return 6; // INC abs
case 0xF0: BEQ( rel_addr() ); return 3; // BEQ rel
case 0xF1: SBC( src_ind_Y() ); return 5; // SBC ind,Y
case 0xF5: SBC( src_zp_X() ); return 4; // SBC zpg,X
case 0xF6: INC( addr_zp_X() ); return 6; // INC zpg,X
case 0xF8: SED(); return 2; // SED
case 0xF9: SBC( src_abs_Y() ); return 4+1; // SBC abs,Y
case 0xFD: SBC( src_abs_X() ); return 4+1; // SBC abs,X
case 0xFE: INC( addr_abs_X() ); return 7; // INC abs,X
#endif /* _6502_std_h */

205
src/cpu/6502_und.h Normal file
View File

@ -0,0 +1,205 @@
//
// 6502_und.h
// A2Mac
//
// Created by Tamas Rudnai on 7/27/20.
// Copyright © 2019, 2020 Tamas Rudnai. All rights reserved.
//
// This file is part of Steve ][ -- The Apple ][ Emulator.
//
// Steve ][ is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Steve ][ is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Steve ][. If not, see <https://www.gnu.org/licenses/>.
//
// Documentations:
//
// http://nesdev.com/6502_cpu.txt
// http://www.oxyron.de/html/opcodes02.html
// https://macgui.com/kb/article/46
// https://www.masswerk.at/6502/6502_instruction_set.html
//
#ifndef _6502_und_h
#define _6502_und_h
case 0x02: HLT(); return 0; // HLT* - Halts / Hangs / Jams / Kills the CPU (undocumented)
case 0x03: SLO( addr_zp_X() ); return 8; // SLO* zpg,X (undocumented)
case 0x04: NOP(); src_zp(); return 3; // NOP* zpg (undocumented)
case 0x07: SLO( addr_zp() ); return 5; // SLO* zpg (undocumented)
case 0x0B: ANC( imm() ); return 2; // ANC** imm (undocumented)
case 0x0C: NOP(); src_abs(); return 4; // NOP* (undocumented)
case 0x0F: SLO( addr_abs() ); return 6; // SLO* (undocumented)
case 0x12: HLT(); return 0; // HLT* - Halts / Hangs / Jams / Kills the CPU (undocumented)
case 0x13: SLO( addr_zp_Y() ); return 8; // SLO* zpg,Y (undocumented)
case 0x14: NOP(); addr_zp_X(); return 4; // NOP* zpg,X (undocumented)
case 0x17: SLO( addr_zp_X() ); return 6; // SLO* zpg,X (undocumented)
case 0x1A: NOP(); return 2; // NOP* (undocumented)
case 0x1B: SLO( addr_abs_Y() ); return 7; // SLO* abs,Y (undocumented)
case 0x1C: NOP(); src_abs_X(); return 4; // NOP* (undocumented)
case 0x1F: SLO( addr_abs_X() ); return 7; // SLO* abs,X (undocumented)
case 0x22: HLT(); return 0; // HLT* - Halts / Hangs / Jams / Kills the CPU (undocumented)
case 0x23: RLA( addr_ind_X() ); return 8; // RLA* ind,X 8 (undocumented)
case 0x27: RLA( addr_zp() ); return 5; // RLA* zpg 5 (undocumented)
case 0x2B: ANC( imm() ); return 2; // ANC* imm 2 (undocumented)
case 0x2F: RLA( addr_abs() ); return 6; // RLA* abs 6 (undocumented)
case 0x32: HLT(); return 0; // HLT* - Halts / Hangs / Jams / Kills the CPU (undocumented)
case 0x33: RLA( addr_ind_Y() ); return 8; // RLA* izy 8 (undocumented)
case 0x34: NOP(); src_zp_X(); return 4; // NOP* zpx 4 (undocumented)
case 0x37: RLA( addr_zp_X() ); return 6; // RLA* zpx 6 (undocumented)
case 0x3A: NOP(); return 2; // NOP* 2 (undocumented)
case 0x3B: RLA( addr_abs_Y() ); return 7; // RLA* aby 7 (undocumented)
case 0x3C: NOP(); src_abs_X(); return 4; // NOP* abx 4 (undocumented)
case 0x3F: RLA( addr_abs_X() ); return 7; // RLA* abx 7 (undocumented)
case 0x42: HLT(); return 0; // HLT* - Halts / Hangs / Jams / Kills the CPU (undocumented)
case 0x43: SRE( addr_ind_X() ); return 8; // SRE* izx 8 (undocumented)
case 0x44: NOP(); return 3; // NOP* zp 3 (undocumented)
case 0x47: SRE( addr_zp() ); return 5; // SRE* zp 5 (undocumented)
case 0x4B: ASR( imm() ); return 2; // ASR* imm 2 (undocumented)
case 0x4F: SRE( abs_addr() ); return 6; // SRE* abs 6 (undocumented)
case 0x52: HLT(); return 0; // HLT* - Halts / Hangs / Jams / Kills the CPU (undocumented)
case 0x53: SRE( addr_ind_Y() ); return 8; // SRE* izy 8 (undocumented)
case 0x54: NOP(); src_zp_X(); return 4; // NOP* zpx 4 (undocumented)
case 0x57: SRE( addr_ind_X() ); return 6; // SRE* zpx 6 (undocumented)
case 0x5A: NOP(); return 2; // NOP* 2 (undocumented)
case 0x5B: SRE( addr_abs_Y() ); return 7; // SRE* aby 7 (undocumented)
case 0x5C: NOP(); src_abs_X(); return 4; // NOP* abx 4 (undocumented)
case 0x5F: SRE( addr_abs_X() ); return 7; // SRE* abx 7 (undocumented)
case 0x62: HLT(); return 0; // HLT* - Halts / Hangs / Jams / Kills the CPU (undocumented)
case 0x63: RRA( addr_ind_X() ); return 8; // RRA* izx 8 (undocumented)
case 0x64: NOP(); return 3; // NOP* zp 3 (undocumented)
case 0x67: RRA( addr_zp() ); return 5; // RRA* zp 5 (undocumented)
case 0x6B: ARC( imm() ); return 2; // ARR/ARC* imm 2 (undocumented)
case 0x6F: RRA( abs_addr() ); return 6; // RRA* abs 6 (undocumented)
case 0x72: HLT(); return 0; // HLT* - Halts / Hangs / Jams / Kills the CPU (undocumented)
case 0x73: RRA( addr_ind_Y() ); return 8; // RRA* izy 8 (undocumented)
case 0x74: NOP(); src_zp_X(); return 4; // NOP* zpx 4 (undocumented)
case 0x77: RRA( addr_zp_X() ); return 6; // RRA* zpx 6 (undocumented)
case 0x7A: NOP(); return 2; // NOP* 2 (undocumented)
case 0x7B: RRA( addr_abs_Y() ); return 7; // RRA* aby 7 (undocumented)
case 0x7C: NOP(); src_abs_X(); return 4; // NOP* abx 4 (undocumented)
case 0x7F: RRA( addr_abs_X() ); return 7; // RRA* abx 7 (undocumented)
case 0x80: NOP(); imm(); return 2; // NOP* imm 2 (undocumented)
case 0x82: NOP(); imm(); return 2; // NOP* imm 2 (undocumented)
case 0x83: SAX( addr_ind_X() ); return 6; // SAX* izx 6 (undocumented)
case 0x87: SAX( addr_zp() ); return 3; // SAX* izx 6 (undocumented)
case 0x89: NOP(); imm(); return 2; // NOP* imm (undocumented)
case 0x8B: XAA( imm() ); return 2; // XAA* imm 2 (undocumented, highly unstable!)
case 0x8F: SAX( addr_abs() ); return 4; // SAX* abs 4 (undocumented)
case 0x92: HLT(); return 0; // HLT* - Halts / Hangs / Jams / Kills the CPU (undocumented)
case 0x93: SHA( addr_ind_Y() ); return 6; // SHA* izy 6 (undocumented, unstable)
case 0x97: SAX( addr_zp_Y() ); return 4; // SAX* izy 4 (undocumented)
case 0x9B: SAS( addr_abs_Y() ); return 5; // SAS* aby 5 (undocumented, unstable)
case 0x9C: SHY( addr_abs_X() ); return 5; // SHY* abx 5 (undocumented, unstable)
case 0x9E: SHX( addr_abs_Y() ); return 5; // SHX* aby 5 (undocumented, unstable)
case 0x9F: SAX( addr_abs_Y() ); return 5; // SAX* aby 5 (undocumented, unstable)
case 0xA3: LAX( src_X_ind() ); return 6; // LAX* izx 6 (undocumented)
case 0xA7: LAX( src_zp() ); return 3; // LAX* zpg 3 (undocumented)
case 0xAB: LAX( imm() ); return 2; // LAX* imm 2 (undocumented, highly unstable)
case 0xAF: LAX( src_abs() ); return 4; // LAX* abs 4 (undocumented)
case 0xB2: HLT(); return 0; // HLT* - Halts / Hangs / Jams / Kills the CPU (undocumented)
case 0xB3: LAX( src_ind_Y() ); return 5; // LAX* izy 5 (undocumented)
case 0xB7: LAX( src_zp_Y() ); return 4+1; // LAX* zpy 4 (undocumented)
case 0xBB: LAS( src_abs_Y() ); return 4; // LAX* aby 4 (undocumented)
case 0xBF: LAX( src_abs_Y() ); return 4; // LAX* aby 4 (undocumented)
case 0xC2: NOP(); imm(); return 2; // NOP* imm 2 (undocumented)
case 0xC3: DCP( addr_ind_X() ); return 8; // DCP* izx 8 (undocumented)
case 0xC7: DCP( addr_zp() ); return 5; // DCP* zpg 5 (undocumented)
case 0xCB: SBX( imm() ); return 2; // SBX* imm 2 (undocumented)
case 0xCF: DCP( addr_abs() ); return 6; // DCP* abs 6 (undocumented)
case 0xD2: HLT(); return 0; // HLT* - Halts / Hangs / Jams / Kills the CPU (undocumented)
case 0xD3: DCP( addr_ind_Y() ); return 8; // DCP* izy 8 (undocumented)
case 0xD4: NOP(); src_zp_X(); return 4; // NOP* zpx 4 (undocumented)
case 0xD7: DCP( addr_zp_X() ); return 6; // DCP* zpx 6 (undocumented)
case 0xDA: NOP(); return 2; // NOP* 2 (undocumented)
case 0xDB: DCP( addr_abs_Y() ); return 7; // DCP* aby 7 (undocumented)
case 0xDC: NOP(); src_abs_X(); return 4; // NOP* abx 4 (undocumented)
case 0xDF: DCP( addr_abs_X() ); return 7; // DCP* abx 7 (undocumented)
case 0xE2: NOP(); imm(); return 2; // NOP* imm 2 (undocumented)
case 0xE3: ISB( addr_ind_X() ); return 8; // ISB* izx 8 (undocumented)
case 0xE7: ISB( addr_zp() ); return 5; // ISB* zpg 5 (undocumented)
case 0xEB: SBC( imm() ); return 2; // SBC* imm 2 (undocumented)
case 0xEF: ISB( addr_abs() ); return 6; // ISB* abs 6 (undocumented)
case 0xF2: HLT(); return 0; // HLT* - Halts / Hangs / Jams / Kills the CPU (undocumented)
case 0xF3: ISB( addr_ind_Y() ); return 8; // ISB* izy 8 (undocumented)
case 0xF4: NOP(); src_zp_X(); return 4; // NOP* zpx 4 (undocumented)
case 0xF7: ISB( addr_zp_X() ); return 6; // ISB* zpx 6 (undocumented)
case 0xFA: NOP(); return 2; // NOP (undocumented)
case 0xFB: ISB( addr_abs_Y() ); return 7; // ISB* aby 7 (undocumented)
case 0xFC: NOP(); src_abs_X(); return 4; // NOP* abx 4 (undocumented)
case 0xFF: ISB( addr_abs_X() ); return 7; // ISB* abx 7 (undocumented)
#endif /* _6502_und_h */

922
src/cpu/jit/6502.c Normal file
View File

@ -0,0 +1,922 @@
//
// main.c
// 6502
//
// Created by Tamas Rudnai on 7/14/19.
// Copyright © 2019, 2020 Tamas Rudnai. All rights reserved.
//
// This file is part of Steve ][ -- The Apple ][ Emulator.
//
// Steve ][ is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Steve ][ is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Steve ][. If not, see <https://www.gnu.org/licenses/>.
//
// Documentations:
//
// http://nesdev.com/6502_cpu.txt
// http://www.oxyron.de/html/opcodes02.html
// https://macgui.com/kb/article/46
// https://www.masswerk.at/6502/6502_instruction_set.html
//
#define CLK_WAIT
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <time.h>
#include "6502.h"
#include "speaker.h"
void ViewController_spk_up_play(void);
void ViewController_spk_dn_play(void);
volatile cpuMode_s cpuMode = cpuMode_normal;
volatile cpuState_s cpuState = cpuState_unknown;
#include "../util/common.h"
#define SOFTRESET_VECTOR 0x3F2
#define NMI_VECTOR 0xFFFA
#define RESET_VECTOR 0xFFFC
#define IRQ_VECTOR 0xFFFE
const unsigned long long int iterations = G;
unsigned long long int inst_cnt = 0;
unsigned int video_fps_divider = DEF_VIDEO_DIV;
unsigned int fps = DEFAULT_FPS;
const double default_crystal_MHz = 14.31818;
const double default_MHz_6502 = default_crystal_MHz / 14; // 1.023; // 2 * M; // 4 * M; // 8 * M; // 16 * M; // 128 * M; // 256 * M; // 512 * M;
const double iigs_MHz_6502 = 2.8;
const double iicplus_MHz_6502 = 4;
const double startup_MHz_6502 = 32;
double MHz_6502 = default_MHz_6502;
unsigned long long clk_6502_per_frm = FRAME_INIT( default_MHz_6502 );
unsigned long long clk_6502_per_frm_set = FRAME_INIT( default_MHz_6502 );
unsigned long long clk_6502_per_frm_max_sound = 4 * FRAME_INIT( default_MHz_6502 );
unsigned long long clk_6502_per_frm_max = 0;
unsigned long long tick_per_sec = G;
unsigned long long tick_6502_per_sec = 0;
//INLINE unsigned long long rdtsc(void)
//{
// unsigned hi, lo;
// __asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi) );
// return ( (unsigned long long)lo) | ( ((unsigned long long)hi) << 32 );
//}
m6502_t m6502 = {
0, // A
0, // X
0, // Y
0, // C
0, // Z
0, // I
0, // D
0, // B
0, // res
0, // V
0, // N
0, // PC
0, // SP
0, // clktime
0, // clklast
0, // clkfrm
0, // trace
0, // step
0, // brk
0, // rts
0, // bra
0, // bra_true
0, // bra_false
0, // compile
HALT, // IF
};
disassembly_t disassembly;
#include "../util/disassembler.h"
#include "../dev/mem/mmio.h"
INLINE void set_flags_N( const uint8_t test ) {
m6502.N = BITTEST(test, 7);
}
INLINE void set_flags_V( const uint8_t test ) {
m6502.V = BITTEST(test, 6);
}
INLINE void set_flags_Z( const uint8_t test ) {
m6502.Z = test == 0;
}
INLINE void set_flags_C( const int16_t test ) {
m6502.C = test >= 0;
}
INLINE void set_flags_NZ( const uint8_t test ) {
set_flags_N(test);
set_flags_Z(test);
}
INLINE void set_flags_NV( const uint8_t test ) {
set_flags_N(test);
set_flags_V(test);
}
INLINE void set_flags_NVZ( const uint8_t test ) {
set_flags_NZ(test);
set_flags_V(test);
}
INLINE void set_flags_NZC( const int16_t test ) {
set_flags_NZ(test);
set_flags_C(test);
}
typedef struct {
uint8_t L;
uint8_t H;
} bytes_t;
/**
Instruction Implementations
!!!! `his has to be here!!!
This idea is that "INLINE" would work only if it is
located in the same source file -- hence the include...
**/
INLINE flags_t getFlags() {
flags_t f = {
m6502.C != 0, // Carry Flag
m6502.Z != 0, // Zero Flag
m6502.I != 0, // Interrupt Flag
m6502.D != 0, // Decimal Flag
m6502.B != 0, // B Flag
m6502.res != 0, // reserved -- should be always 1
m6502.V != 0, // Overflow Flag ???
m6502.N != 0, // Negative Flag
};
return f;
}
INLINE void setFlags( uint8_t byte ) {
flags_t flags = { .SR = byte };
m6502.C = flags.C; // Carry Flag
m6502.Z = flags.Z; // Zero Flag
m6502.I = flags.I; // Interrupt Flag
m6502.D = flags.D; // Decimal Flag
m6502.B = flags.B; // B Flag
m6502.res = flags.res; // reserved -- should be always 1
m6502.V = flags.V; // Overflow Flag ???
m6502.N = flags.N; // Negative Flag
}
#include "6502_instructions.h"
INLINE int m6502_Step() {
#ifdef DEBUG___
switch ( m6502.PC ) {
case 0x1E60:
printf("Wavy Navy...\n");
break;
default:
break;
}
switch ( m6502.PC ) {
case 0xC600:
printf("DISK...\n");
break;
case 0xC62F:
printf("DISK IO...\n");
break;
default:
break;
}
switch ( m6502.PC ) {
case 0xE000:
dbgPrintf("START...\n");
break;
case 0xF168:
dbgPrintf("START...\n");
break;
case 0xF16B:
dbgPrintf("START...\n");
break;
case 0xF195: // RAM size init
dbgPrintf("START...\n");
break;
default:
break;
}
#endif
disNewInstruction();
switch ( fetch() ) {
case 0x00: BRK(); return 7; // BRK
case 0x01: ORA( src_X_ind() ); return 6; // ORA X,ind
case 0x02: HLT(); return 0; // JAM / KIL / HLT* - Halts / Hangs / Jams / Kills the CPU (undocumented)
case 0x03: SLO( addr_zp_X() ); return 8; // SLO* zpg,X (undocumented)
case 0x04: NOP(); src_zp(); return 3; // NOP* zpg (undocumented)
case 0x05: ORA( src_zp() ); return 3; // ORA zpg
case 0x06: ASL( addr_zp() ); return 5; // ASL zpg
case 0x07: SLO( addr_zp() ); return 5; // SLO* zpg (undocumented)
case 0x08: PHP(); return 3; // PHP
case 0x09: ORA( imm() ); return 2; // ORA imm
case 0x0A: ASLA(); return 2; // ASL A
case 0x0B: ANC( imm() ); return 2; // ANC** imm (undocumented)
case 0x0C: NOP(); src_abs(); return 4; // NOP* (undocumented)
case 0x0D: ORA( src_abs() ); return 4; // ORA abs
case 0x0E: ASL( addr_abs() ); return 6; // ASL abs
case 0x0F: SLO( addr_abs() ); return 6; // SLO* (undocumented)
case 0x10: BPL( rel_addr() ); return 2; // BPL rel
case 0x11: ORA( src_ind_Y() ); return 5; // ORA ind,Y
case 0x12: HLT(); return 0; // JAM / KIL / HLT* - Halts / Hangs / Jams / Kills the CPU (undocumented)
case 0x13: SLO( addr_zp_Y() ); return 8; // SLO* zpg,Y (undocumented)
case 0x14: NOP(); addr_zp_X(); return 4; // NOP* zpg,X (undocumented)
case 0x15: ORA( src_zp_X() ); return 4; // ORA zpg,X
case 0x16: ASL( addr_zp_X() ); return 6; // ASL zpg,X
case 0x17: SLO( addr_zp_X() ); return 6; // SLO* zpg,X (undocumented)
case 0x18: CLC(); return 2; // CLC
case 0x19: ORA( src_abs_Y() ); return 4+1; // ORA abs,Y
case 0x1A: NOP(); return 2; // NOP* (undocumented)
case 0x1B: SLO( addr_abs_Y() ); return 7; // SLO* abs,Y (undocumented)
case 0x1C: NOP(); src_abs_X(); return 4; // NOP* (undocumented)
case 0x1D: ORA( src_abs_X() ); return 4+1; // ORA abs,X
case 0x1E: ASL( addr_abs_X() ); return 7; // ASL abs,X
case 0x1F: SLO( addr_abs_X() ); return 7; // SLO* abs,X (undocumented)
case 0x20: JSR( abs_addr() ); return 6; // JSR abs
case 0x21: AND( src_X_ind() ); return 6; // AND X,ind
case 0x22: HLT(); return 0; // JAM / KIL / HLT* - Halts / Hangs / Jams / Kills the CPU (undocumented)
case 0x23: RLA( addr_ind_X() ); return 8; // RLA* ind,X 8 (undocumented)
case 0x24: BIT( src_zp() ); return 3; // BIT zpg
case 0x25: AND( src_zp() ); return 3; // AND zpg
case 0x26: ROL( addr_zp() ); return 5; // ROL zpg
case 0x27: RLA( addr_zp() ); return 5; // RLA* zpg 5 (undocumented)
case 0x28: PLP(); return 4; // PLP
case 0x29: AND( imm() ); return 2; // AND imm
case 0x2A: ROLA(); return 2; // ROL A
case 0x2B: ANC( imm() ); return 2; // ANC* imm 2 (undocumented)
case 0x2C: BIT( src_abs() ); return 4; // BIT abs
case 0x2D: AND( src_abs() ); return 4; // AND abs
case 0x2E: ROL( addr_abs() ); return 6; // ROL abs
case 0x2F: RLA( addr_abs() ); return 6; // RLA* abs 6 (undocumented)
case 0x30: BMI( rel_addr() ); return 2; // BMI rel
case 0x31: AND( src_ind_Y() ); return 5; // AND ind,Y
case 0x32: HLT(); return 0; // JAM / KIL / HLT* - Halts / Hangs / Jams / Kills the CPU (undocumented)
case 0x33: RLA( addr_ind_Y() ); return 8; // RLA* izy 8 (undocumented)
case 0x34: NOP(); src_zp_X(); return 4; // NOP* zpx 4 (undocumented)
case 0x35: AND( src_zp_X() ); return 4; // AND zpg,X
case 0x36: ROL( addr_zp_X() ); return 6; // ROL zpg,X
case 0x37: RLA( addr_zp_X() ); return 6; // RLA* zpx 6 (undocumented)
case 0x38: SEC(); return 2; // SEC
case 0x39: AND( src_abs_Y() ); return 4+1; // AND abs,Y
case 0x3A: NOP(); return 2; // NOP* 2 (undocumented)
case 0x3B: RLA( addr_abs_Y() ); return 7; // RLA* aby 7 (undocumented)
case 0x3C: NOP(); src_abs_X(); return 4; // NOP* abx 4 (undocumented)
case 0x3D: AND( src_abs_X() ); return 4+1; // AND abs,X
case 0x3E: ROL( addr_abs_X() ); return 7; // ROL abs,X
case 0x3F: RLA( addr_abs_X() ); return 7; // RLA* abx 7 (undocumented)
case 0x40: RTI(); return 6; // RTI
case 0x41: EOR( src_X_ind() ); return 6; // EOR X,ind
case 0x42: HLT(); return 0; // JAM / KIL / HLT* - Halts / Hangs / Jams / Kills the CPU (undocumented)
case 0x43: SRE( addr_ind_X() ); return 8; // SRE* izx 8 (undocumented)
case 0x44: NOP(); src_zp(); return 3; // NOP* zp 3 (undocumented)
case 0x45: EOR( src_zp() ); return 3; // EOR zpg
case 0x46: LSR( addr_zp() ); return 5; // LSR zpg
case 0x47: SRE( addr_zp() ); return 5; // SRE* zp 5 (undocumented)
case 0x48: PHA(); return 3; // PHA
case 0x49: EOR( imm() ); return 2; // EOR imm
case 0x4A: LSRA(); return 2; // LSR A
case 0x4B: ASR( imm() ); return 2; // TODO: ALR / ASR* imm 2 (undocumented)
case 0x4C: JMP( abs_addr() ); return 3; // JMP abs
case 0x4D: EOR( src_abs() ); return 4; // EOR abs
case 0x4E: LSR( addr_abs() ); return 6; // LSR abs
case 0x4F: SRE( abs_addr() ); return 6; // SRE* abs 6 (undocumented)
case 0x50: BVC( rel_addr() ); return 2; // BVC rel
case 0x51: EOR( src_ind_Y() ); return 5; // EOR ind,Y
case 0x52: HLT(); return 0; // JAM / KIL / HLT* - Halts / Hangs / Jams / Kills the CPU (undocumented)
case 0x53: SRE( addr_ind_Y() ); return 8; // SRE* izy 8 (undocumented)
case 0x54: NOP(); src_zp_X(); return 4; // NOP* zpx 4 (undocumented)
case 0x55: EOR( src_zp_X() ); return 4; // AND zpg,X
case 0x56: LSR( addr_zp_X() ); return 6; // LSR zpg,X
case 0x57: SRE( addr_ind_X() ); return 6; // SRE* zpx 6 (undocumented)
case 0x58: CLI(); return 2; // CLI
case 0x59: EOR( src_abs_Y() ); return 4+1; // EOR abs,Y
case 0x5A: NOP(); return 2; // NOP* 2 (undocumented)
case 0x5B: SRE( addr_abs_Y() ); return 7; // SRE* aby 7 (undocumented)
case 0x5C: NOP(); src_abs_X(); return 4; // NOP* abx 4 (undocumented)
case 0x5D: EOR( src_abs_X() ); return 4+1; // EOR abs,X
case 0x5E: LSR( addr_abs_X() ); return 7; // LSR abs,X
case 0x5F: SRE( addr_abs_X() ); return 7; // SRE* abx 7 (undocumented)
case 0x60: RTS(); return 6; // RTS
case 0x61: ADC( src_X_ind() ); return 6; // ADC X,ind
case 0x62: HLT(); return 0; // JAM / KIL / HLT* - Halts / Hangs / Jams / Kills the CPU (undocumented)
case 0x63: RRA( addr_ind_X() ); return 8; // RRA* izx 8 (undocumented)
case 0x64: NOP(); src_zp(); return 3; // NOP* zp 3 (undocumented)
case 0x65: ADC( src_zp() ); return 3; // ADC zpg
case 0x66: ROR( addr_zp() ); return 5; // ROR zpg
case 0x67: RRA( addr_zp() ); return 5; // RRA* zp 5 (undocumented)
case 0x68: PLA(); return 4; // PLA
case 0x69: ADC( imm() ); return 2; // ADC imm
case 0x6A: RORA(); return 2; // ROR A
case 0x6B: ARC( imm() ); return 2; // ARR/ARC* imm 2 (undocumented)
case 0x6C: JMP( ind_addr() ); return 5; // JMP ind
case 0x6D: ADC( src_abs() ); return 4; // ADC abs
case 0x6E: ROR( addr_abs() ); return 6; // ROR abs
case 0x6F: RRA( abs_addr() ); return 6; // RRA* abs 6 (undocumented)
case 0x70: BVS( rel_addr() ); return 2; // BVS rel
case 0x71: ADC( src_ind_Y() ); return 5; // ADC ind,Y
case 0x72: HLT(); return 0; // JAM / KIL / HLT* - Halts / Hangs / Jams / Kills the CPU (undocumented)
case 0x73: RRA( addr_ind_Y() ); return 8; // RRA* izy 8 (undocumented)
case 0x74: NOP(); src_zp_X(); return 4; // NOP* zpx 4 (undocumented)
case 0x75: ADC( src_zp_X() ); return 4; // ADC zpg,X
case 0x76: ROR( addr_zp_X() ); return 6; // ROR zpg,X
case 0x77: RRA( addr_zp_X() ); return 6; // RRA* zpx 6 (undocumented)
case 0x78: SEI(); return 2; // SEI
case 0x79: ADC( src_abs_Y() ); return 4+1; // ADC abs,Y
case 0x7A: NOP(); return 2; // NOP* 2 (undocumented)
case 0x7B: RRA( addr_abs_Y() ); return 7; // RRA* aby 7 (undocumented)
case 0x7C: NOP(); src_abs_X(); return 4; // NOP* abx 4 (undocumented)
case 0x7D: ADC( src_abs_X() ); return 4+1; // ADC abs,X
case 0x7E: ROR( addr_abs_X() ); return 7; // ROR abs,X
case 0x7F: RRA( addr_abs_X() ); return 7; // RRA* abx 7 (undocumented)
case 0x80: NOP(); imm(); return 2; // NOP* imm 2 (undocumented)
case 0x81: STA( addr_ind_X() ) ; return 6; // STA X,ind
case 0x82: NOP(); imm(); return 2; // NOP* imm 2 (undocumented)
case 0x83: SAX( addr_ind_X() ); return 6; // SAX* izx 6 (undocumented)
case 0x84: STY( addr_zp() ); return 3; // STY zpg
case 0x85: STA( addr_zp() ); return 3; // STA zpg
case 0x86: STX( addr_zp() ); return 3; // STX zpg
case 0x87: SAX( addr_zp() ); return 3; // SAX* izx 6 (undocumented)
case 0x88: DEY(); return 2; // DEY
case 0x89: NOP(); imm(); return 2; // NOP* imm (undocumented)
case 0x8A: TXA(); return 2; // TXA
case 0x8B: XAA( imm() ); return 2; // ANE / XAA* imm 2 (undocumented, highly unstable!)
case 0x8C: STY( addr_abs() ); return 4; // STY abs
case 0x8D: STA( addr_abs() ); return 4; // STA abs
case 0x8E: STX( addr_abs() ); return 4; // STX abs
case 0x8F: SAX( addr_abs() ); return 4; // SAX* abs 4 (undocumented)
case 0x90: BCC( rel_addr() ); return 2; // BCC rel
case 0x91: STA( addr_ind_Y() ); return 6; // STA ind,Y
case 0x92: HLT(); return 0; // JAM / KIL / HLT* - Halts / Hangs / Jams / Kills the CPU (undocumented)
case 0x93: SHA( addr_ind_Y() ); return 6; // SHA* izy 6 (undocumented, unstable)
case 0x94: STY( addr_zp_X() ); return 4; // STY zpg,X
case 0x95: STA( addr_zp_X() ); return 4; // STA zpg,X
case 0x96: STX( addr_zp_Y() ); return 4; // STX zpg,Y
case 0x97: SAX( addr_zp_Y() ); return 4; // SAX* izy 4 (undocumented)
case 0x98: TYA(); return 2; // TYA
case 0x99: STA( addr_abs_Y() ); return 5; // STA abs,Y
case 0x9A: TXS(); return 2; // TXS
case 0x9B: SAS( addr_abs_Y() ); return 5; // TAS / XAS / SHS / SAS* aby 5 (undocumented, unstable)
case 0x9C: SHY( addr_abs_X() ); return 5; // SHY* abx 5 (undocumented, unstable)
case 0x9D: STA( addr_abs_X() ); return 5; // STA abs,X
case 0x9E: SHX( addr_abs_Y() ); return 5; // SHX* aby 5 (undocumented, unstable)
case 0x9F: SAX( addr_abs_Y() ); return 5; // TODO: SHA / SAX* aby 5 (undocumented, unstable)
case 0xA0: LDY( imm() ); return 2; // LDY imm
case 0xA1: LDA( src_X_ind() ) ; return 6; // LDA X,ind
case 0xA2: LDX( imm() ); return 2; // LDX imm
case 0xA3: LAX( src_X_ind() ); return 6; // LAX* izx 6 (undocumented)
case 0xA4: LDY( src_zp() ); return 3; // LDY zpg
case 0xA5: LDA( src_zp() ); return 3; // LDA zpg
case 0xA6: LDX( src_zp() ); return 3; // LDX zpg
case 0xA7: LAX( src_zp() ); return 3; // LAX* zpg 3 (undocumented)
case 0xA8: TAY(); return 2; // TAY
case 0xA9: LDA( imm() ); return 2; // LDA imm
case 0xAA: TAX(); return 2; // TAX
case 0xAB: LAX( imm() ); return 2; // LAX* imm 2 (undocumented, highly unstable)
case 0xAC: LDY( src_abs() ); return 4; // LDY abs
case 0xAD: LDA( src_abs() ); return 4; // LDA abs
case 0xAE: LDX( src_abs() ); return 4; // LDX abs
case 0xAF: LAX( src_abs() ); return 4; // LAX* abs 4 (undocumented)
case 0xB0: BCS( rel_addr() ); return 2; // BCS rel
case 0xB1: LDA( src_ind_Y() ); return 5; // LDA ind,Y
case 0xB2: HLT(); return 0; // JAM / KIL / HLT* - Halts / Hangs / Jams / Kills the CPU (undocumented)
case 0xB3: LAX( src_ind_Y() ); return 5; // LAX* izy 5 (undocumented)
case 0xB4: LDY( src_zp_X() ); return 4+1; // LDY zpg,X
case 0xB5: LDA( src_zp_X() ); return 4+1; // LDA zpg,X
case 0xB6: LDX( src_zp_Y() ); return 4+1; // LDX zpg,Y
case 0xB7: LAX( src_zp_Y() ); return 4+1; // LAX* zpy 4 (undocumented)
case 0xB8: CLV(); return 2; // CLV
case 0xB9: LDA( src_abs_Y() ); return 4; // LDA abs,Y
case 0xBA: TSX(); return 2; // TSX
case 0xBB: LAS( src_abs_Y() ); return 4; // TODO: LAS / LAR / LAX* aby 4 (undocumented)
case 0xBC: LDY( src_abs_X() ); return 4; // LDY abs,X
case 0xBD: LDA( src_abs_X() ); return 4; // LDA abs,X
case 0xBE: LDX( src_abs_Y() ); return 4; // LDX abs,Y
case 0xBF: LAX( src_abs_Y() ); return 4; // LAX* aby 4 (undocumented)
case 0xC0: CPY( imm() ); return 2; // CPY imm
case 0xC1: CMP( src_X_ind() ) ; return 6; // LDA X,ind
case 0xC2: NOP(); imm(); return 2; // NOP* imm 2 (undocumented)
case 0xC3: DCP( addr_ind_X() ); return 8; // DCP* izx 8 (undocumented)
case 0xC4: CPY( src_zp() ); return 3; // CPY zpg
case 0xC5: CMP( src_zp() ); return 3; // CMP zpg
case 0xC6: DEC( addr_zp() ); return 5; // DEC zpg
case 0xC7: DCP( addr_zp() ); return 5; // DCP* zpg 5 (undocumented)
case 0xC8: INY(); return 2; // INY
case 0xC9: CMP( imm() ); return 2; // CMP imm
case 0xCA: DEX(); return 2; // DEX
case 0xCB: SBX( imm() ); return 2; // SBX* imm 2 (undocumented)
case 0xCC: CPY( src_abs() ); return 4; // CPY abs
case 0xCD: CMP( src_abs() ); return 4; // CMP abs
case 0xCE: DEC( addr_abs() ); return 6; // DEC abs
case 0xCF: DCP( addr_abs() ); return 6; // DCP* abs 6 (undocumented)
case 0xD0: BNE( rel_addr() ); return 2; // BNE rel
case 0xD1: CMP( src_ind_Y() ); return 5; // CMP ind,Y
case 0xD2: HLT(); return 0; // JAM / KIL / HLT* - Halts / Hangs / Jams / Kills the CPU (undocumented)
case 0xD3: DCP( addr_ind_Y() ); return 8; // DCP* izy 8 (undocumented)
case 0xD4: NOP(); src_zp_X(); return 4; // NOP* zpx 4 (undocumented)
case 0xD5: CMP( src_zp_X() ); return 4; // CMP zpg,X
case 0xD6: DEC( addr_zp_X() ); return 6; // DEC zpg,X
case 0xD7: DCP( addr_zp_X() ); return 6; // DCP* zpx 6 (undocumented)
case 0xD8: CLD(); return 2; // CLD
case 0xD9: CMP( src_abs_Y() ); return 4; // CMP abs,Y
case 0xDA: NOP(); return 2; // NOP* 2 (undocumented)
case 0xDB: DCP( addr_abs_Y() ); return 7; // DCP* aby 7 (undocumented)
case 0xDC: NOP(); src_abs_X(); return 4; // NOP* abx 4 (undocumented)
case 0xDD: CMP( src_abs_X() ); return 4; // CMP abs,X
case 0xDE: DEC( addr_abs_X() ); return 7; // DEC abs,X
case 0xDF: DCP( addr_abs_X() ); return 7; // DCP* abx 7 (undocumented)
case 0xE0: CPX( imm() ); return 2; // CPX imm
case 0xE1: SBC( src_X_ind() ) ; return 6; // SBC (X,ind)
case 0xE2: NOP(); imm(); return 2; // NOP* imm 2 (undocumented)
case 0xE3: ISB( addr_ind_X() ); return 8; // ISC / INS / ISB* izx 8 (undocumented)
case 0xE4: CPX( src_zp() ); return 3; // CPX zpg
case 0xE5: SBC( src_zp() ); return 3; // SBC zpg
case 0xE6: INC( addr_zp() ); return 5; // INC zpg
case 0xE7: ISB( addr_zp() ); return 5; // ISC / INS / ISB* zpg 5 (undocumented)
case 0xE8: INX(); return 2; // INX
case 0xE9: SBC( imm() ); return 2; // SBC imm
case 0xEA: NOP(); return 2; // NOP
case 0xEB: SBC( imm() ); return 2; // USBC / SBC* imm 2 (undocumented)
case 0xEC: CPX( src_abs() ); return 4; // CPX abs
case 0xED: SBC( src_abs() ); return 4; // SBC abs
case 0xEE: INC( addr_abs() ); return 6; // INC abs
case 0xEF: ISB( addr_abs() ); return 6; // ISC / INS / ISB* abs 6 (undocumented)
case 0xF0: BEQ( rel_addr() ); return 2; // BEQ rel
case 0xF1: SBC( src_ind_Y() ); return 5; // SBC ind,Y
case 0xF2: HLT(); return 0; // JAM / KIL / HLT* - Halts / Hangs / Jams / Kills the CPU (undocumented)
case 0xF3: ISB( addr_ind_Y() ); return 8; // ISC / INS / ISB* izy 8 (undocumented)
case 0xF4: NOP(); src_zp_X(); return 4; // NOP* zpx 4 (undocumented)
case 0xF5: SBC( src_zp_X() ); return 4; // SBC zpg,X
case 0xF6: INC( addr_zp_X() ); return 6; // INC zpg,X
case 0xF7: ISB( addr_zp_X() ); return 6; // ISC / INS / ISB* zpx 6 (undocumented)
case 0xF8: SED(); return 2; // SED
case 0xF9: SBC( src_abs_Y() ); return 4+1; // SBC abs,Y
case 0xFA: NOP(); return 2; // NOP (undocumented)
case 0xFB: ISB( addr_abs_Y() ); return 7; // ISB* aby 7 (undocumented)
case 0xFC: NOP(); src_abs_X(); return 4; // NOP* abx 4 (undocumented)
case 0xFD: SBC( src_abs_X() ); return 4+1; // SBC abs,X
case 0xFE: INC( addr_abs_X() ); return 7; // INC abs,X
case 0xFF: ISB( addr_abs_X() ); return 7; // ISC / INS / ISB* abx 7 (undocumented)
default:
dbgPrintf("%04X: Unimplemented Instruction 0x%02X\n", m6502.PC -1, memread( m6502.PC -1 ));
return 2;
}
// } // fetch16
return 2;
}
unsigned long long ee = 0;
unsigned long long dd = 0;
// nanosec does not work very well for some reason
struct timespec tim = { 0, 400L };
double mips = 0;
double mhz = 0;
unsigned long long epoch = 0;
void interrupt_IRQ() {
m6502.PC = memread16(IRQ_VECTOR);
// TODO: PUSH things onto stack?
}
void interrupt_NMI() {
m6502.PC = memread16(NMI_VECTOR);
// TODO: PUSH things onto stack?
}
void hardReset() {
m6502.PC = memread16(RESET_VECTOR);
// make sure it will be a cold reset...
memwrite(0x3F4, 0);
m6502.SP = 0xFF;
// N V - B D I Z C
// 0 0 1 0 0 1 0 1
setFlags(0x25);
}
void softReset() {
// m6502.PC = memread16(SOFTRESET_VECTOR);
m6502.PC = memread16( RESET_VECTOR );
m6502.SP = 0xFF;
// N V - B D I Z C
// 0 0 1 0 0 1 0 1
setFlags(0x25);
spkr_stopAll();
resetMemory();
}
void m6502_Run() {
// init time
//#ifdef CLK_WAIT
// unsigned long long elpased = (unsigned long long)-1LL;
//#endif
#ifdef SPEEDTEST
for ( inst_cnt = 0; inst_cnt < iterations ; inst_cnt++ )
#elif defined( CLK_WAIT )
// we clear the clkfrm from ViewController Update()
// we will also use this to pause the simulation if not finished by the end of the frame
for ( clk_6502_per_frm_max = clk_6502_per_frm; m6502.clkfrm < clk_6502_per_frm_max ; m6502.clkfrm += m6502_Step() )
#else
// this is for max speed only -- WARNING! It works only if simulation runs in a completely different thread from the Update()
for ( ; ; )
#endif
{
// TODO: clkfrm is already increamented!!!
printDisassembly(outdev);
#ifdef INTERRUPT_CHECK_PER_STEP
if ( m6502.IF ) {
switch (m6502.interrupt) {
case HALT:
// CPU is haletd, nothing to do here...
return;
case IRQ:
interrupt_IRQ();
break;
case NMI:
interrupt_NMI();
break;
case HARDRESET:
hardReset();
break;
case SOFTRESET:
softReset();
break;
default:
break;
}
m6502.IF = 0;
}
#endif // INTERRUPT_CHECK_PER_STEP
}
// TODO: What if we dynamically reduce or increace CPU speed?
m6502.clktime += clk_6502_per_frm;
if( diskAccelerator_count ) {
if( --diskAccelerator_count <= 0 ) {
// make sure we only adjust clock once to get back to normal
diskAccelerator_count = 0;
clk_6502_per_frm = clk_6502_per_frm_set;
}
}
// play the entire sound buffer for this frame
spkr_update();
// this will take care of turning off disk motor sound when time is up
spkr_update_disk_sfx();
}
void read_rom( const char * bundlePath, const char * filename, uint8_t * rom, const uint16_t addr ) {
char fullPath[256];
strcpy( fullPath, bundlePath );
strcat( fullPath, "/");
strcat( fullPath, filename );
FILE * f = fopen(fullPath, "rb");
if (f == NULL) {
perror("Failed to read ROM: ");
return;
}
fseek(f, 0L, SEEK_END);
uint16_t flen = ftell(f);
fseek(f, 0L, SEEK_SET);
fread( rom + addr, 1, flen, f);
fclose(f);
}
size_t getFileSize ( const char * fullPath ) {
FILE * f = fopen(fullPath, "rb");
if (f == NULL) {
perror("Failed to read ROM: ");
return 0;
}
fseek(f, 0L, SEEK_END);
size_t flen = ftell(f);
fseek(f, 0L, SEEK_SET);
fclose(f);
return flen;
}
void rom_loadFile( const char * bundlePath, const char * filename ) {
char fullPath[256];
strcpy( fullPath, bundlePath );
strcat( fullPath, "/");
strcat( fullPath, filename );
size_t flen = getFileSize(fullPath);
if ( flen == 0 ) {
return; // there was an error
}
else if ( flen == 16 * KB ) {
read_rom( bundlePath, filename, Apple2_64K_ROM + 0xC000, 0);
memcpy(Apple2_64K_MEM + 0xC000, Apple2_64K_ROM + 0xC000, 16 * KB);
}
else if ( flen == 12 * KB ) {
read_rom( bundlePath, filename, Apple2_64K_ROM + 0xD000, 0x1000);
memcpy(Apple2_64K_MEM + 0xD000, Apple2_64K_ROM + 0xD000, 12 * KB);
}
}
void openLog() {
#ifdef DISASSEMBLER
outdev = fopen("/Users/trudnai/Library/Containers/com.trudnai.steveii/Data/disassembly_new.log", "w+");
#endif
// for DEBUG ONLY!!! -- use stdout if could not create log file
// if (outdev == NULL) {
// outdev = stdout;
// }
}
void closeLog() {
if ( ( outdev ) && ( outdev != stdout ) && ( outdev != stderr ) ) {
fclose(outdev);
}
}
void m6502_ColdReset( const char * bundlePath, const char * romFileName ) {
inst_cnt = 0;
spkr_init();
clk_6502_per_frm =
clk_6502_per_frm_max =
clk_6502_per_frm_set = 0;
// wait 100ms to be sure simulation has been halted
usleep(100000);
// printf("Bundlepath: %s\n", bundlePath);
// epoch = rdtsc();
// sleep(1);
// unsigned long long e = rdtsc();
// tick_per_sec = e - epoch;
// tick_6502_per_sec = tick_per_sec / MHz_6502;
initMemory();
#ifdef FUNCTIONTEST
read_rom( bundlePath, "6502_functional_test.bin", Apple2_64K_RAM, 0);
memcpy(Apple2_64K_MEM, Apple2_64K_RAM, 65536);
m6502.PC = 0x400;
#else
// Apple ][+ ROM
rom_loadFile(bundlePath, romFileName);
// Disk ][ ROM in Slot 6
read_rom( bundlePath, "DISK_II_C600.ROM", Apple2_64K_ROM, 0xC600);
memcpy(Apple2_64K_MEM + 0xC600, Apple2_64K_ROM + 0xC600, 0x100);
m6502.A = m6502.X = m6502.Y = 0xFF;
// reset vector
m6502.SP = 0xFF; //-3;
// N V - B D I Z C
// 0 0 1 0 0 1 0 0
setFlags(0x24);
m6502.IF = 0;
// memory size
//*((uint16_t*)(&RAM[0x73])) = 0xC000;
m6502.PC = memread16( RESET_VECTOR );
#endif
uint8_t counter[] = {
// 1 * COUNTER2
// 2
// 3 ORG $1000
// 4 SCREEN EQU $400
// 5 HOME EQU $FC58
// 6 DIGITS EQU $06
// 7 ZERO EQU $B0
// 8 CARRY EQU $BA
// 9 RDKEY EQU $FD0C
//10
// I have placed NOP to keep addresses
0xA0, 0x09, 0xEA, //11 LDY #$09 ; NOP
0x84, 0x06, //12 STY #DIGITS
0xEA, 0xEA, //13 NOP NOP
0xEA, 0xEA, 0xEA, //14 NOP NOP NOP
0xA6, 0x06, //15 LDY DIGITS
0xA9, 0xB0, //16 CLEAR LDA #ZERO
0x99, 0x00, 0x04, //17 STA SCREEN,Y
0x88, //18 DEY
0x10, 0xF8, //19 BPL CLEAR
0xA4, 0x06, //20 START LDY DIGITS
0x20, 0x36, 0x10, //21 ONES JSR INC
0xB9, 0x00, 0x04, //22 LDA SCREEN,Y
0xC9, 0xBA, //23 CMP #CARRY
0xD0, 0xF6, //24 BNE ONES
0xA9, 0xB0, //25 NEXT LDA #ZERO
0x99, 0x00, 0x04, //26 STA SCREEN,Y
0x88, //27 DEY
0x30, 0x0D, //28 BMI END
0x20, 0x36, 0x10, //29 JSR INC
0xB9, 0x00, 0x04, //30 LDA SCREEN,Y
0xC9, 0xBA, //31 CMP #CARRY
0xD0, 0xE2, //32 BNE START
0x4C, 0x20, 0x10, //33 JMP NEXT
0x60, //34 END RTS
0xB9, 0x00, 0x04, //36 INC LDA SCREEN,Y
0xAA, //37 TAX
0xE8, //38 INX
0x8A, //39 TXA
0x99, 0x00, 0x04, //40 STA SCREEN,Y
0x60, //41 RTS
};
uint8_t counter_fast[] = {
// 1 * COUNTER2
// 2
// 3 ORG $1000
// 4 SCREEN EQU $400
// 5 HOME EQU $FC58
// 6 DIGITS EQU $06
// 7 ZERO EQU $B0
// 8 CARRY EQU $BA
// 9 RDKEY EQU $FD0C
//10
// I have placed NOP to keep addresses
0xA0, 0x06, // 00 LDY #$09
0x84, 0x06, // 02 STY #DIGITS
0xA6, 0x06, // 04 LDY DIGITS
0xA9, 0xB0, // 06 CLEAR LDA #ZERO
0x99, 0x00, 0x04, // 08 STA SCREEN,Y
0x88, // 0B DEY
0x10, 0xF8, // 0C BPL CLEAR
0xA6, 0x06, // 0E START LDX DIGITS
0xA9, 0xBA, // 10 LDA #CARRY
0xFE, 0x00, 0x04, // 12 ONES INC SCREEN,X
0xDD, 0x00, 0x04, // 15 CMP SCREEN,X
0xD0, 0xF8, // 18 BNE ONES
0xA9, 0xB0, // 1A NEXT LDA #ZERO
0x9D, 0x00, 0x04, // 1C STA SCREEN,X
0xCA, // 1F DEX
0x30, 0x0C, // 20 BMI END
0xFE, 0x00, 0x04, // 22 INC SCREEN,X
0xBD, 0x00, 0x04, // 25 LDA SCREEN,X
0xC9, 0xBA, // 28 CMP #CARRY
0xD0, 0xE2, // 2A BNE START
0xF0, 0xEC, // 2C BEQ NEXT
0x60, // 2E END RTS
};
// set the default speed
clk_6502_per_frm_set = clk_6502_per_frm = FRAME(default_MHz_6502);
// Initialize Paddle / Game Controller / Joystick / Mouse Buttons
setIO(0xC061, 0);
setIO(0xC062, 0);
setIO(0xC063, 1 << 7); // inverted (bit 7: not pressed)
}
void tst6502() {
// insert code here...
printf("6502\n");
m6502_ColdReset( "", "" );
// clock_t start = clock();
// epoch = rdtsc();
m6502_Run();
// clock_t end = clock();
// double execution_time = ((double) (end - start)) / CLOCKS_PER_SEC;
#ifdef SPEEDTEST
unsigned long long end = rdtsc();
unsigned long long elapsed = end - epoch;
double execution_time = (double)elapsed / tick_per_sec;
double mips = inst_cnt / (execution_time * M);
double mhz = m6502.clktime / (execution_time * M);
printf("clk:%llu Elpased time: (%llu / %u / %llu), %.3lfs (%.3lf MIPS, %.3lf MHz)\n", iterations *3, tick_per_sec, MHz_6502, tick_6502_per_sec, execution_time, mips, mhz);
// printf(" dd:%llu ee:%llu nn:%llu\n", dd, ee, ee - dd);
#endif
}
int ___main(int argc, const char * argv[]) {
tst6502();
return 0;
}

222
src/cpu/jit/6502.h Normal file
View File

@ -0,0 +1,222 @@
//
// 6502.h
// 6502
//
// Created by Tamas Rudnai on 7/22/19.
// Copyright © 2019, 2020 Tamas Rudnai. All rights reserved.
//
// This file is part of Steve ][ -- The Apple ][ Emulator.
//
// Steve ][ is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Steve ][ is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Steve ][. If not, see <https://www.gnu.org/licenses/>.
//
#ifndef __6502_H__
#define __6502_H__
#include <stdint.h>
#include "common.h"
#include "woz.h"
typedef enum cpuMode_e {
cpuMode_normal = 0,
cpuMode_eco,
cpuMode_game,
} cpuMode_s;
typedef enum cpuState_e {
cpuState_unknown = 0,
cpuState_inited,
cpuState_running,
cpuState_halting,
cpuState_halted,
} cpuState_s;
extern volatile cpuMode_s cpuMode;
extern volatile cpuState_s cpuState;
extern const double default_MHz_6502;
extern const double iigs_MHz_6502;
extern const double iicplus_MHz_6502;
extern double MHz_6502;
extern unsigned long long clk_6502_per_frm;
extern unsigned long long clk_6502_per_frm_set;
extern unsigned long long clk_6502_per_frm_max;
extern unsigned long long clk_6502_per_frm_max_sound;
typedef enum {
NO_INT,
HALT,
IRQ,
NMI,
HARDRESET,
SOFTRESET,
} interrupt_t;
typedef struct debugLevel_s {
uint8_t trace : 1;
uint8_t step : 1;
uint8_t brk : 1;
uint8_t rts : 1;
uint8_t bra : 1;
uint8_t bra_true : 1;
uint8_t bra_false : 1;
uint8_t compile : 1;
} debugLevel_t;
typedef union flags_u {
struct {
uint8_t C:1; // Carry Flag
uint8_t Z:1; // Zero Flag
uint8_t I:1; // Interrupt Flag
uint8_t D:1; // Decimal Flag
uint8_t B:1; // B Flag
uint8_t res:1; // reserved -- should be always 1
uint8_t V:1; // Overflow Flag ???
uint8_t N:1; // Negative Flag
};
uint8_t SR;
} flags_t;
//#pragma pack(1)
typedef struct m6502_s {
uint8_t A; // 0: Accumulator
uint8_t X; // 1: X index register
uint8_t Y; // 2: Y index register
// union {
// uint8_t instr; // Instruction
// struct {
// uint8_t cc:2;
// uint8_t bbb:3;
// uint8_t aaa:3;
// };
// };
struct { // no bitfield faster processing
uint8_t C; // 3: Carry Flag
uint8_t Z; // 4: Zero Flag
uint8_t I; // 5: Interrupt Flag
uint8_t D; // 6: Decimal Flag
uint8_t B; // 7: B Flag
uint8_t res; // 8: reserved -- should be always 1
uint8_t V; // 9: Overflow Flag ???
uint8_t N; // 10: Negative Flag
};
uint16_t PC; // 11: Program Counter
uint8_t SP; // 13: Stack Pointer ( stack addr = 0x01 + sp )
// unsigned clk; // Clock Counter
uint64_t clktime; // 14:
uint64_t clklast; // 22:
uint32_t clkfrm; // 30:
debugLevel_t dbgLevel; // 34: 0: No Debug, 1: Disassembly Only, 2: Run till BRK, 3: StepByStep
union {
unsigned int IF; // interrut flag
interrupt_t interrupt;
};
} m6502_t;
//#pragma pack()
typedef struct disassembly_s {
uint64_t clk; // clock time
char addr[5]; // 4 digits + \0
char opcode[4 * 3 + 1]; // max 4 bytes * (2 digits + 1 space) + \0
char * pOpcode; // pointer for opcode string builder
char inst[6 + 1]; // 3 char (unknown instr? -- give it 6 chars) + \0
char oper[14 + 2 + 1 + 1 + 1]; // 4 digits + 2 brackets + 1 comma + 1 index + \0
char comment[256]; // to be able to add some comments
} disassembly_t;
// Memory Config
typedef struct MEMcfg_s {
unsigned RAM_16K : 1;
unsigned RAM_128K : 1;
unsigned RD_INT_RAM : 1;
unsigned WR_RAM : 1;
unsigned RAM_BANK_2 : 1;
unsigned AUX_BANK : 1;
unsigned txt_page_2 : 1; // 0: page 1 1: page 2 (aux video memory)
unsigned int_Cx_ROM : 1; // 0: Slot Cx ROM 1: Internal Cx ROM
unsigned slot_C3_ROM : 1; // 0: Internal ROM 1: Slot 3 ROM
unsigned is_80STORE : 1;
unsigned RD_AUX_MEM : 1;
unsigned WR_AUX_MEM : 1;
unsigned ALT_ZP : 1;
} MEMcfg_t;
typedef union videoMode_u {
struct {
uint8_t text : 1; // 0: graphics 1: text
uint8_t col80 : 1; // 0: 40 col 1: 80 col
uint8_t altChr : 1; // 0: normal 1: alternate character set
uint8_t mixed : 1; // 0: no mix 1: mixed graphics and text when in graphics mode
uint8_t hires : 1; // 0: loRes 1: hiRes
};
uint8_t mode;
} videoMode_t;
extern MEMcfg_t MEMcfg;
extern m6502_t m6502;
extern uint8_t * const AUX; // Pointer to the auxiliary memory so we can use this from Swift
extern uint8_t * const RAM;
extern uint8_t * const MEM; // Pointer to the Shadow Memory Map so we can use this from Swift//extern uint8_t * AUX_VID_RAM;
extern uint32_t * videoMemPtr;
extern double * pdl_valarr;
extern double * pdl_prevarr;
extern double * pdl_diffarr;
//extern void hires_Update(void);
extern double mips;
extern double mhz;
#define DEFAULT_FPS 30U
#define DEF_VIDEO_DIV 1U
#define DEF_SPKR_DIV 1U
#define GAME_FPS 480U
#define GAME_VIDEO_DIV (GAME_FPS / 60U)
extern unsigned int video_fps_divider;
extern unsigned int fps;
extern void rom_loadFile( const char * bundlePath, const char * filename );
extern void tst6502(void);
extern void m6502_ColdReset( const char * bundlePath, const char * romFilePath );
extern void m6502_Run(void);
extern void interrupt_IRQ(void);
extern void interrupt_NMI(void);
extern void hardReset(void);
extern void softReset(void);
extern void openLog(void);
extern void closeLog(void);
#endif /* __6502_H__ */

View File

@ -0,0 +1,138 @@
//
// main.c
// 6502
//
// Created by Tamas Rudnai on 7/14/19.
// Copyright © 2019, 2020 Tamas Rudnai. All rights reserved.
//
// This file is part of Steve ][ -- The Apple ][ Emulator.
//
// Steve ][ is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Steve ][ is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Steve ][. If not, see <https://www.gnu.org/licenses/>.
//
#ifndef __6502_INSTR_ARITHMETIC_H__
#define __6502_INSTR_ARITHMETIC_H__
#include "common.h"
/**
ADC Add Memory to Accumulator with Carry
A + M + C -> A, C N Z C I D V
+ + + - - +
addressing assembler opc bytes cyles
--------------------------------------------
immidiate ADC #oper 69 2 2
zeropage ADC oper 65 2 3
zeropage,X ADC oper,X 75 2 4
absolute ADC oper 6D 3 4
absolute,X ADC oper,X 7D 3 4*
absolute,Y ADC oper,Y 79 3 4*
(indirect,X) ADC (oper,X) 61 2 6
(indirect),Y ADC (oper),Y 71 2 5*
**/
INLINE void _ADC( uint8_t src ) {
uint16_t tmp;
// V = C7 != C6
m6502.V = ((m6502.A & 0x7F) + (src & 0x7F) + (m6502.C != 0)) > 0x7F;
if ( m6502.D ) {
if ( (tmp = (m6502.A & 0x0F) + (src & 0x0F) + (m6502.C != 0)) > 0x09 ) {
tmp += 0x06;
}
if ( (tmp += (m6502.A & 0xF0) + (src & 0xF0)) > 0x99 ) {
tmp += 0x60;
}
}
else {
tmp = (uint16_t)m6502.A + src + (m6502.C != 0);
}
set_flags_NZ( m6502.A = tmp );
m6502.C = tmp > 0xFF;
m6502.V ^= m6502.C;
// // this is good but slow:
// uint16_t tmp = (uint16_t)m6502.A + src + m6502.C;
// m6502.V = ( !((m6502.A ^ src) & 0x80)) && ( (m6502.A ^ tmp) & 0x80);
// m6502.C = tmp > 0xFF;
// set_flags_NZ( m6502.A = tmp );
// // this is good but slow:
// uint16_t tmp = (uint16_t)m6502.A + src + m6502.C;
// m6502.V = ( ((m6502.A ^ src) ^ (m6502.A ^ tmp)) & 0x80 ) != 0;
// m6502.C = tmp > 0xFF;
// set_flags_NZ( m6502.A = tmp );
}
INLINE void ADC( uint8_t src ) {
dbgPrintf("ADC(%02X) ", src);
disPrintf(disassembly.inst, "ADC");
_ADC(src);
}
/**
SBC Subtract Memory from Accumulator with Borrow
A - M - C -> A N Z C I D V
+ + + - - +
addressing assembler opc bytes cyles
--------------------------------------------
immidiate SBC #oper E9 2 2
zeropage SBC oper E5 2 3
zeropage,X SBC oper,X F5 2 4
absolute SBC oper ED 3 4
absolute,X SBC oper,X FD 3 4*
absolute,Y SBC oper,Y F9 3 4*
(indirect,X) SBC (oper,X) E1 2 6
(indirect),Y SBC (oper),Y F1 2 5*
**/
INLINE void _SBC( uint8_t src ) {
uint16_t tmp;
if( m6502.D ) {
tmp = (m6502.A & 0x0F) - ( src & 0x0F ) - !m6502.C;
if( (tmp & 0x10) != 0) {
tmp = ( (tmp - 0x06 ) & 0x0F ) | ( (m6502.A & 0xF0) - (src & 0xF0) - 0x10 );
}
else {
tmp = (tmp & 0x0F) | ( (m6502.A & 0xF0) - (src & 0xF0) );
}
if(( tmp & 0x100 ) != 0) {
tmp -= 0x60;
}
}
else
{
tmp = m6502.A - src - !m6502.C;
}
m6502.C = tmp < 0x100;
m6502.V = ( (m6502.A ^ tmp) & 0x80 ) && ( (m6502.A ^ src) & 0x80 );
set_flags_NZ( m6502.A = tmp );
}
INLINE void SBC( uint8_t src ) {
dbgPrintf("SBC(%02X) ", src);
disPrintf(disassembly.inst, "SBC");
_SBC(src);
}
#endif // __6502_INSTR_ARITHMETIC_H__

View File

@ -0,0 +1,283 @@
//
// main.c
// 6502
//
// Created by Tamas Rudnai on 7/14/19.
// Copyright © 2019, 2020 Tamas Rudnai. All rights reserved.
//
// This file is part of Steve ][ -- The Apple ][ Emulator.
//
// Steve ][ is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Steve ][ is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Steve ][. If not, see <https://www.gnu.org/licenses/>.
//
#ifndef __6502_INSTR_BRANCH_H__
#define __6502_INSTR_BRANCH_H__
INLINE void BRA( int8_t reladdr ) {
uint8_t pg = m6502.PC >> 8;
m6502.PC += reladdr;
m6502.clkfrm += m6502.PC >> 8 == pg ? 1 : 2;
#ifdef DEBUG
if ( reladdr == -2 ) {
dbgPrintf2("Infinite Loop at %04X!\n", m6502.PC);
}
#endif
dbgPrintf("BRA %04X ", m6502.PC);
}
/**
BCC Branch on Carry Clear
branch on C = 0 N Z C I D V
- - - - - -
addressing assembler opc bytes cyles
--------------------------------------------
relative BCC oper 90 2 2**
**/
INLINE void BCC( int8_t reladdr ) {
dbgPrintf("BCC ");
disPrintf(disassembly.inst, "BCC");
if ( ! m6502.C ) {
BRA( reladdr );
}
else {
dbgPrintf("-no-");
}
}
/**
BCS Branch on Carry Set
branch on C = 1 N Z C I D V
- - - - - -
addressing assembler opc bytes cyles
--------------------------------------------
relative BCS oper B0 2 2**
**/
INLINE void BCS( int8_t reladdr ) {
dbgPrintf("BCS ");
disPrintf(disassembly.inst, "BCS");
if ( m6502.C ) {
BRA( reladdr );
}
else {
dbgPrintf("-no-");
}
}
/**
BNE Branch on Result not Zero
branch on Z = 0 N Z C I D V
- - - - - -
addressing assembler opc bytes cyles
--------------------------------------------
relative BNE oper D0 2 2**
**/
INLINE void BNE( int8_t reladdr ) {
dbgPrintf("BNE ");
disPrintf(disassembly.inst, "BNE");
if ( ! m6502.Z ) {
BRA( reladdr );
}
else {
dbgPrintf("-no-");
}
}
/**
BEQ Branch on Result Zero
branch on Z = 1 N Z C I D V
- - - - - -
addressing assembler opc bytes cyles
--------------------------------------------
relative BEQ oper F0 2 2**
**/
INLINE void BEQ( int8_t reladdr ) {
dbgPrintf("BEQ ");
disPrintf(disassembly.inst, "BEQ");
if ( m6502.Z ) {
BRA( reladdr );
}
else {
dbgPrintf("-no-");
}
}
/**
BPL Branch on Result Plus
branch on N = 0 N Z C I D V
- - - - - -
addressing assembler opc bytes cyles
--------------------------------------------
relative BPL oper 10 2 2**
**/
INLINE void BPL( int8_t reladdr ) {
dbgPrintf("BPL ");
disPrintf(disassembly.inst, "BPL");
if ( ! m6502.N ) {
BRA( reladdr );
}
else {
dbgPrintf("-no-");
}
}
/**
BMI Branch on Result Minus
branch on N = 1 N Z C I D V
- - - - - -
addressing assembler opc bytes cyles
--------------------------------------------
relative BMI oper 30 2 2**
**/
INLINE void BMI( int8_t reladdr ) {
dbgPrintf("BMI ");
disPrintf(disassembly.inst, "BMI");
if ( m6502.N ) {
BRA( reladdr );
}
else {
dbgPrintf("-no-");
}
}
/**
BVC Branch on Overflow Clear
branch on V = 0 N Z C I D V
- - - - - -
addressing assembler opc bytes cyles
--------------------------------------------
relative BVC oper 50 2 2**
**/
INLINE void BVC( int8_t reladdr ) {
dbgPrintf("BVC ");
disPrintf(disassembly.inst, "BVC");
if ( ! m6502.V ) {
BRA( reladdr );
}
else {
dbgPrintf("-no-");
}
}
/**
BVS Branch on Overflow Set
branch on V = 1 N Z C I D V
- - - - - -
addressing assembler opc bytes cyles
--------------------------------------------
relative BVC oper 70 2 2**
**/
INLINE void BVS( int8_t reladdr ) {
dbgPrintf("BVS ");
disPrintf(disassembly.inst, "BVS");
if ( m6502.V ) {
BRA( reladdr );
}
else {
dbgPrintf("-no-");
}
}
/**
BBR BBS - Branch on Bit Reset or Set
BBR and BBS test the specified zero page location and branch if the specified bit is clear (BBR) or set (BBS).
Note that as with TRB, the term reset in BBR is used to mean clear.
On the 6502 and 65C02, bit 7 is typically the most convenient bit to use for I/O and software flags because
it can be tested by several instructions, such as BIT and LDA. BBR and BBS can test any of the 8 bits without
affecting any flags or using any registers. Unlike other branch instructions, BBR and BBS always take the same
number of cycles (five) whether the branch is taken or not. It is often useful to test bit 0, for example, to test
whether a byte is even or odd. However, the usefulness of BBR and BBS is somewhat limited for a couple of reasons.
First, there is only a single addressing mode for these instructions -- no indexing by X or Y, for instance.
Second, they are restricted to zero page locations. For software flags this may be just fine, but it may not be very
convenient (or cost effective) to add any additional address decoding hardware that may be necessary to
map I/O locations to the zero page.
The addressing mode is a combination of zero page addressing and relative addressing -- really just a juxtaposition of the two.
The bit to test is typically specified as part of the instruction name rather than the operand, i.e.
Flags affected: none
OP LEN CYC MODE FLAGS SYNTAX
-- --- --- ---- ----- ------
0F 3 5 zp,rel ........ BBR0 $12,LABEL
1F 3 5 zp,rel ........ BBR1 $12,LABEL
2F 3 5 zp,rel ........ BBR2 $12,LABEL
3F 3 5 zp,rel ........ BBR3 $12,LABEL
4F 3 5 zp,rel ........ BBR4 $12,LABEL
5F 3 5 zp,rel ........ BBR5 $12,LABEL
6F 3 5 zp,rel ........ BBR6 $12,LABEL
7F 3 5 zp,rel ........ BBR7 $12,LABEL
8F 3 5 zp,rel ........ BBS0 $12,LABEL
9F 3 5 zp,rel ........ BBS1 $12,LABEL
AF 3 5 zp,rel ........ BBS2 $12,LABEL
BF 3 5 zp,rel ........ BBS3 $12,LABEL
CF 3 5 zp,rel ........ BBS4 $12,LABEL
DF 3 5 zp,rel ........ BBS5 $12,LABEL
EF 3 5 zp,rel ........ BBS6 $12,LABEL
FF 3 5 zp,rel ........ BBS7 $12,LABEL
**/
#define BBR(n) INLINE void BBR##n( uint8_t src, int8_t reladdr ) { \
dbgPrintf("BBR"#n" "); \
disPrintf(disassembly.inst, "BBR"#n); \
if ( ! (src & (1 << n) ) ) { \
BRA( reladdr ); \
} \
}
BBR(0)
BBR(1)
BBR(2)
BBR(3)
BBR(4)
BBR(5)
BBR(6)
BBR(7)
#define BBS(n) INLINE void BBS##n( uint8_t src, int8_t reladdr ) { \
dbgPrintf("BBS"#n" "); \
disPrintf(disassembly.inst, "BBS"#n); \
if ( (src & (1 << n) ) ) { \
BRA( reladdr ); \
} \
}
BBS(0)
BBS(1)
BBS(2)
BBS(3)
BBS(4)
BBS(5)
BBS(6)
BBS(7)
#endif // __6502_INSTR_BRANCH_H__

View File

@ -0,0 +1,123 @@
//
// main.c
// 6502
//
// Created by Tamas Rudnai on 7/14/19.
// Copyright © 2019, 2020 Tamas Rudnai. All rights reserved.
//
// This file is part of Steve ][ -- The Apple ][ Emulator.
//
// Steve ][ is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Steve ][ is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Steve ][. If not, see <https://www.gnu.org/licenses/>.
//
#ifndef __6502_INSTR_CALL_RET_JUMP_H__
#define __6502_INSTR_CALL_RET_JUMP_H__
/**
JMP Jump to New Location
(PC+1) -> PCL N Z C I D V
(PC+2) -> PCH - - - - - -
addressing assembler opc bytes cyles
--------------------------------------------
absolute JMP oper 4C 3 3
indirect JMP (oper) 6C 3 5
**/
INLINE void JMP( uint16_t addr ) {
dbgPrintf("JMP %04X ", addr);
disPrintf(disassembly.inst, "JMP");
// disPrintf(disassembly.comment, "to:%04X", addr)
#ifdef DEBUG
if ( addr == m6502.PC - 3 ) {
dbgPrintf("Infinite Loop at %04X!\n", m6502.PC);
}
#endif
if (m6502.PC >> 8 != addr >> 8) {
m6502.clkfrm += 1;
}
m6502.PC = addr;
}
// for patching game purposes -- it should not be inline!
void CALL( uint16_t addr ) {
dbgPrintf("CALL ");
disPrintf(disassembly.inst, "CALL");
PUSH_addr(m6502.PC -1);
m6502.PC = addr;
}
/**
JSR Jump to New Location Saving Return Address
push (PC+2), N Z C I D V
(PC+1) -> PCL - - - - - -
(PC+2) -> PCH
addressing assembler opc bytes cyles
--------------------------------------------
absolute JSR oper 20 3 6
**/
INLINE void JSR( uint16_t addr ) {
dbgPrintf("JSR ");
disPrintf(disassembly.inst, "JSR");
PUSH_addr(m6502.PC -1);
m6502.PC = addr;
}
/**
RTS Return from Subroutine
pull PC, PC+1 -> PC N Z C I D V
- - - - - -
addressing assembler opc bytes cyles
--------------------------------------------
implied RTS 60 1 6
**/
INLINE void RTS() {
dbgPrintf("RTS ");
disPrintf(disassembly.inst, "RTS");
m6502.PC = POP_addr() +1;
// disk accelerator would only work for a certain amount of time
// currently it is 200ms simulated times
// if ( m6502.clktime - disk.clk_last_access > clk_diskAcceleratorTimeout ) {
// clk_6502_per_frm = clk_6502_per_frm_set;
// }
}
/**
RTI Return from Interrupt
pull SR, pull PC N Z C I D V
from stack
addressing assembler opc bytes cyles
--------------------------------------------
implied RTI 40 1 6
**/
INLINE void RTI() {
dbgPrintf("RTI ");
disPrintf(disassembly.inst, "RTI");
setFlags( POP() );
// m6502.I = 0;
m6502.PC = POP_addr();
}
#endif // __6502_INSTR_CALL_RET_JUMP_H__

View File

@ -0,0 +1,168 @@
//
// main.c
// 6502
//
// Created by Tamas Rudnai on 7/14/19.
// Copyright © 2019, 2020 Tamas Rudnai. All rights reserved.
//
// This file is part of Steve ][ -- The Apple ][ Emulator.
//
// Steve ][ is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Steve ][ is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Steve ][. If not, see <https://www.gnu.org/licenses/>.
//
#ifndef __6502_INSTR_COMPARE_TEST_H__
#define __6502_INSTR_COMPARE_TEST_H__
/**
BIT Test Bits in Memory with Accumulator
bits 7 and 6 of operand are transfered to bit 7 and 6 of SR (N,V);
the zeroflag is set to the result of operand AND accumulator.
A AND M, M7 -> N, M6 -> V N Z C I D V
M7 + - - - M6
addressing assembler opc bytes cyles
--------------------------------------------
zeropage BIT oper 24 2 3
absolute BIT oper 2C 3 4
**/
INLINE void BIT( uint8_t src ) {
dbgPrintf("BIT(%02X) ", src);
disPrintf(disassembly.inst, "BIT");
set_flags_NV(src);
set_flags_Z(m6502.A & src);
}
/**
TRB - Test and Reset Bits
TRB can be one the more confusing instructions for a couple of reasons.
First, the term reset is used to refer to the clearing of a bit, whereas the term clear had been used consistently before, such as CLC
which stands for CLear Carry. Second, the effect on the Z flag is determined by a different function than the effect on memory.
TRB has the same effect on the Z flag that a BIT instruction does. Specifically, it is based on whether the result of a bitwise AND of the
accumulator with the contents of the memory location specified in the operand is zero. Also, like BIT, the accumulator is not affected.
The accumulator determines which bits in the memory location specified in the operand are cleared and which are not affected.
The bits in the accumulator that are ones are cleared (in memory), and the bits that are zeros (in the accumulator) are not affected (in memory).
This is the same as saying that the resulting memory contents are the bitwise AND of the memory contents with the complement of the
accumulator (i.e. the exclusive-or of the accululator with $FF).
OP LEN CYC MODE FLAGS SYNTAX
-- --- --- ---- ----- ------
14 2 5 zp ......Z. TRB $12
1C 3 6 abs ......Z. TRB $3456
**/
INLINE void TRB( uint16_t addr ) {
dbgPrintf("TRB(%02X) ", src);
disPrintf(disassembly.inst, "TRB");
set_flags_Z( WRLOMEM[addr] & m6502.A );
WRLOMEM[addr] &= ~m6502.A;
}
/**
TSB - Test and Set Bits
TSB, like TRB, can be confusing. For one, like TRB, the effect on the Z flag is determined by a different function than the effect on memory.
TSB, like TRB, has the same effect on the Z flag that a BIT instruction does. Specifically, it is based on whether the result of a bitwise AND
of the accumulator with the contents of the memory location specified in the operand is zero. Also, like BIT (and TRB), the accumulator is not affected.
The accumulator determines which bits in the memory location specified in the operand are set and which are not affected. The bits in the
accumulator that are ones are set to one (in memory), and the bits that are zeros (in the accumulator) are not affected (in memory).
This is the same as saying that the resulting memory contents are the bitwise OR of the memory contents with the accumulator.
Flags affected: Z
OP LEN CYC MODE FLAGS SYNTAX
-- --- --- ---- ----- ------
04 2 5 zp ......Z. TSB $12
0C 3 6 abs ......Z. TSB $3456
**/
INLINE void TSB( uint16_t addr ) {
dbgPrintf("TSB(%02X) ", src);
disPrintf(disassembly.inst, "TSB");
set_flags_Z( WRLOMEM[addr] & m6502.A );
WRLOMEM[addr] |= m6502.A;
}
/**
CMP Compare Memory with Accumulator
A - M N Z C I D V
+ + + - - -
addressing assembler opc bytes cyles
--------------------------------------------
immidiate CMP #oper C9 2 2
zeropage CMP oper C5 2 3
zeropage,X CMP oper,X D5 2 4
absolute CMP oper CD 3 4
absolute,X CMP oper,X DD 3 4*
absolute,Y CMP oper,Y D9 3 4*
(indirect,X) CMP (oper,X) C1 2 6
(indirect),Y CMP (oper),Y D1 2 5*
**/
INLINE void _CMP( uint8_t src ) {
set_flags_NZC( (int16_t)m6502.A - src );
}
INLINE void CMP( uint8_t src ) {
dbgPrintf("CMP(%02X) ", src);
disPrintf(disassembly.inst, "CMP");
_CMP(src);
}
/**
CPX Compare Memory and Index X
X - M N Z C I D V
+ + + - - -
addressing assembler opc bytes cyles
--------------------------------------------
immidiate CPX #oper E0 2 2
zeropage CPX oper E4 2 3
absolute CPX oper EC 3 4
**/
INLINE void CPX( uint8_t src ) {
dbgPrintf("CPX(%02X) ", src);
disPrintf(disassembly.inst, "CPX");
set_flags_NZC( (int16_t)m6502.X - src );
}
/**
CPY Compare Memory and Index Y
Y - M N Z C I D V
+ + + - - -
addressing assembler opc bytes cyles
--------------------------------------------
immidiate CPY #oper C0 2 2
zeropage CPY oper C4 2 3
absolute CPY oper CC 3 4
**/
INLINE void CPY( uint8_t src ) {
dbgPrintf("CPY(%02X) ", src);
disPrintf(disassembly.inst, "CPY");
set_flags_NZC( (int16_t)m6502.Y - src );
}
#endif // __6502_INSTR_COMPARE_TEST_H__

View File

@ -0,0 +1,173 @@
//
// main.c
// 6502
//
// Created by Tamas Rudnai on 7/14/19.
// Copyright © 2019, 2020 Tamas Rudnai. All rights reserved.
//
// This file is part of Steve ][ -- The Apple ][ Emulator.
//
// Steve ][ is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Steve ][ is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Steve ][. If not, see <https://www.gnu.org/licenses/>.
//
#ifndef __6502_INSTR_INC_DEC_H__
#define __6502_INSTR_INC_DEC_H__
/**
INC Increment Memory by One
M + 1 -> M N Z C I D V
+ + - - - -
addressing assembler opc bytes cyles
--------------------------------------------
zeropage INC oper E6 2 5
zeropage,X INC oper,X F6 2 6
absolute INC oper EE 3 6
absolute,X INC oper,X FE 3 7
**/
INLINE void _INC( uint16_t addr ) {
set_flags_NZ( ++(WRLOMEM[addr]) );
}
INLINE void INC( uint16_t addr ) {
disPrintf(disassembly.inst, "INC");
_INC(addr);
}
/**
INX Increment Index X by One
X + 1 -> X N Z C I D V
+ + - - - -
addressing assembler opc bytes cyles
--------------------------------------------
implied INX E8 1 2
**/
INLINE void INX() {
dbgPrintf("INX %02X -> ", m6502.X);
disPrintf(disassembly.inst, "INX");
set_flags_NZ( ++m6502.X );
dbgPrintf("%02X ", m6502.X);
}
/**
INY Increment Index Y by One
Y + 1 -> Y N Z C I D V
+ + - - - -
addressing assembler opc bytes cyles
--------------------------------------------
implied INY C8 1 2
**/
INLINE void INY() {
dbgPrintf("INY %02X -> ", m6502.Y);
disPrintf(disassembly.inst, "INY");
set_flags_NZ( ++m6502.Y );
dbgPrintf("%02X ", m6502.Y);
}
/**
INA Increment Accumulator by One
A + 1 -> A N Z C I D V
+ + - - - -
addressing assembler opc bytes cyles
--------------------------------------------
implied INA C8 1 2
**/
INLINE void INA() {
dbgPrintf("INA %02X -> ", m6502.A);
disPrintf(disassembly.inst, "INA");
set_flags_NZ( ++m6502.A );
dbgPrintf("%02X ", m6502.A);
}
/**
DEC Decrement Memory by One
M - 1 -> M N Z C I D V
+ + - - - -
addressing assembler opc bytes cyles
--------------------------------------------
zeropage DEC oper C6 2 5
zeropage,X DEC oper,X D6 2 6
absolute DEC oper CE 3 3
absolute,X DEC oper,X DE 3 7
**/
INLINE void _DEC( uint16_t addr ) {
set_flags_NZ( --(WRLOMEM[addr]) );
}
INLINE void DEC( uint16_t addr ) {
disPrintf(disassembly.inst, "DEC");
_DEC(addr);
}
/**
DEX Decrement Index X by One
X - 1 -> X N Z C I D V
+ + - - - -
addressing assembler opc bytes cyles
--------------------------------------------
implied DEC CA 1 2
**/
INLINE void DEX() {
dbgPrintf("DEX %02X -> ", m6502.X);
disPrintf(disassembly.inst, "DEX");
set_flags_NZ( --m6502.X );
dbgPrintf("%02X ", m6502.X);
}
/**
DEY Decrement Index Y by One
Y - 1 -> Y N Z C I D V
+ + - - - -
addressing assembler opc bytes cyles
--------------------------------------------
implied DEC 88 1 2
**/
INLINE void DEY() {
dbgPrintf("DEY %02X -> ", m6502.Y);
disPrintf(disassembly.inst, "DEY");
set_flags_NZ( --m6502.Y );
dbgPrintf("%02X ", m6502.Y);
}
/**
DEA Decrement Accumulator by One
A - 1 -> A N Z C I D V
+ + - - - -
addressing assembler opc bytes cyles
--------------------------------------------
implied DEC 88 1 2
**/
INLINE void DEA() {
dbgPrintf("DEA %02X -> ", m6502.A);
disPrintf(disassembly.inst, "DEA");
set_flags_NZ( --m6502.A );
dbgPrintf("%02X ", m6502.A);
}
#endif // __6502_INSTR_INC_DEC_H__

View File

@ -0,0 +1,191 @@
//
// main.c
// 6502
//
// Created by Tamas Rudnai on 7/14/19.
// Copyright © 2019 Tamas Rudnai. All rights reserved.
//
// This file is part of Steve ][ -- The Apple ][ Emulator.
//
// Steve ][ is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Steve ][ is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Steve ][. If not, see <https://www.gnu.org/licenses/>.
//
#ifndef __6502_INSTR_LOAD_STORE_H__
#define __6502_INSTR_LOAD_STORE_H__
#include <ctype.h>
#include "mmio.h"
/**
LDA Load Accumulator with Memory
M -> A N Z C I D V
+ + - - - -
addressing assembler opc bytes cyles
--------------------------------------------
immidiate LDA #oper A9 2 2
zeropage LDA oper A5 2 3
zeropage,X LDA oper,X B5 2 4
absolute LDA oper AD 3 4
absolute,X LDA oper,X BD 3 4*
absolute,Y LDA oper,Y B9 3 4*
(indirect,X) LDA (oper,X) A1 2 6
(indirect),Y LDA (oper),Y B1 2 5*
**/
INLINE void LDA( uint8_t src ) {
dbgPrintf("LDA(%02X) ", src);
disPrintf(disassembly.inst, "LDA");
set_flags_NZ(m6502.A = src);
}
/**
LDX Load Index X with Memory
M -> X N Z C I D V
+ + - - - -
addressing assembler opc bytes cyles
--------------------------------------------
immidiate LDX #oper A2 2 2
zeropage LDX oper A6 2 3
zeropage,Y LDX oper,Y B6 2 4
absolute LDX oper AE 3 4
absolute,Y LDX oper,Y BE 3 4*
**/
INLINE void LDX( uint8_t src ) {
dbgPrintf("LDX(%02X) ", src);
disPrintf(disassembly.inst, "LDX");
set_flags_NZ(m6502.X = src);
}
/**
LDY Load Index Y with Memory
M -> Y N Z C I D V
+ + - - - -
addressing assembler opc bytes cyles
--------------------------------------------
immidiate LDY #oper A0 2 2
zeropage LDY oper A4 2 3
zeropage,X LDY oper,X B4 2 4
absolute LDY oper AC 3 4
absolute,X LDY oper,X BC 3 4*
**/
INLINE void LDY( uint8_t src ) {
dbgPrintf("LDY(%02X) ", src);
disPrintf(disassembly.inst, "LDY");
set_flags_NZ(m6502.Y = src);
}
char * charConv =
"@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_ !\"#$%&'()*+,-./0123456789:;<=>?"
"@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_ !\"#$%&'()*+,-./0123456789:;<=>?"
"@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_ !\"#$%&'()*+,-./0123456789:;<=>?"
"@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~?"
;
/**
STR Store Data in Destination
(not a real instruction, only a helper function)
**/
INLINE void STR( uint16_t addr, uint8_t src ) {
dbgPrintf("STR [%04X], %02X ", addr, src );
memwrite(addr, src);
}
/**
STA Store Accumulator in Memory
A -> M N Z C I D V
- - - - - -
addressing assembler opc bytes cyles
--------------------------------------------
zeropage STA oper 85 2 3
zeropage,X STA oper,X 95 2 4
absolute STA oper 8D 3 4
absolute,X STA oper,X 9D 3 5
absolute,Y STA oper,Y 99 3 5
(indirect,X) STA (oper,X) 81 2 6
(indirect),Y STA (oper),Y 91 2 6
**/
INLINE void STA( uint16_t addr ) {
dbgPrintf("STA ");
disPrintf(disassembly.inst, "STA");
STR(addr, m6502.A);
}
/**
STX Store Index X in Memory
X -> M N Z C I D V
- - - - - -
addressing assembler opc bytes cyles
--------------------------------------------
zeropage STX oper 86 2 3
zeropage,Y STX oper,Y 96 2 4
absolute STX oper 8E 3 4
**/
INLINE void STX( uint16_t addr ) {
dbgPrintf("STX ");
disPrintf(disassembly.inst, "STX");
STR(addr, m6502.X);
}
/**
STY Sore Index Y in Memory
Y -> M N Z C I D V
- - - - - -
addressing assembler opc bytes cyles
--------------------------------------------
zeropage STY oper 84 2 3
zeropage,X STY oper,X 94 2 4
absolute STY oper 8C 3 4
**/
INLINE void STY( uint16_t addr ) {
dbgPrintf("STY ");
disPrintf(disassembly.inst, "STY");
STR(addr, m6502.Y);
}
/**
STZ Store Zero (0) in Memory
0 -> M N Z C I D V
- - - - - -
OP LEN CYC MODE FLAGS SYNTAX
-- --- --- ---- ----- ------
64 2 3 zp ........ STZ $12
74 2 4 zp,X ........ STZ $12,X
9C 3 4 abs ........ STZ $3456
9E 3 5 abs,X ........ STZ $3456,X
**/
INLINE void STZ( uint16_t addr ) {
dbgPrintf("STZ ");
disPrintf(disassembly.inst, "STZ");
STR(addr, 0);
}
#endif // __6502_INSTR_LOAD_STORE_H__

View File

@ -0,0 +1,104 @@
//
// main.c
// 6502
//
// Created by Tamas Rudnai on 7/14/19.
// Copyright © 2019, 2020 Tamas Rudnai. All rights reserved.
//
// This file is part of Steve ][ -- The Apple ][ Emulator.
//
// Steve ][ is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Steve ][ is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Steve ][. If not, see <https://www.gnu.org/licenses/>.
//
#ifndef __6502_INSTR_LOGIC_H__
#define __6502_INSTR_LOGIC_H__
/**
ORA OR Memory with Accumulator
A OR M -> A N Z C I D V
+ + - - - -
addressing assembler opc bytes cyles
--------------------------------------------
immidiate ORA #oper 09 2 2
zeropage ORA oper 05 2 3
zeropage,X ORA oper,X 15 2 4
absolute ORA oper 0D 3 4
absolute,X ORA oper,X 1D 3 4*
absolute,Y ORA oper,Y 19 3 4*
(indirect,X) ORA (oper,X) 01 2 6
(indirect),Y ORA (oper),Y 11 2 5*
**/
INLINE void _ORA( uint8_t src ) {
set_flags_NZ( m6502.A |= src );
}
INLINE void ORA( uint8_t src ) {
dbgPrintf("ORA(%02X) ", src);
disPrintf(disassembly.inst, "ORA");
_ORA(src);
}
/**
AND AND Memory with Accumulator
A AND M -> A N Z C I D V
+ + - - - -
addressing assembler opc bytes cyles
--------------------------------------------
immidiate AND #oper 29 2 2
zeropage AND oper 25 2 3
zeropage,X AND oper,X 35 2 4
absolute AND oper 2D 3 4
absolute,X AND oper,X 3D 3 4*
absolute,Y AND oper,Y 39 3 4*
(indirect,X) AND (oper,X) 21 2 6
(indirect),Y AND (oper),Y 31 2 5*
**/
INLINE void _AND( uint8_t src ) {
set_flags_NZ( m6502.A &= src );
}
INLINE void AND( uint8_t src ) {
dbgPrintf("AND(%02X) ", src);
disPrintf(disassembly.inst, "AND");
_AND(src);
}
/**
EOR Exclusive-OR Memory with Accumulator
A EOR M -> A N Z C I D V
+ + - - - -
addressing assembler opc bytes cyles
--------------------------------------------
immidiate EOR #oper 49 2 2
zeropage EOR oper 45 2 3
zeropage,X EOR oper,X 55 2 4
absolute EOR oper 4D 3 4
absolute,X EOR oper,X 5D 3 4*
absolute,Y EOR oper,Y 59 3 4*
(indirect,X) EOR (oper,X) 41 2 6
(indirect),Y EOR (oper),Y 51 2 5*
**/
INLINE void EOR( uint8_t src ) {
dbgPrintf("EOR(%02X) ", src);
disPrintf(disassembly.inst, "EOR");
set_flags_NZ( m6502.A ^= src );
}
#endif // __6502_INSTR_LOGIC_H__

View File

@ -0,0 +1,75 @@
//
// main.c
// 6502
//
// Created by Tamas Rudnai on 7/14/19.
// Copyright © 2019, 2020 Tamas Rudnai. All rights reserved.
//
// This file is part of Steve ][ -- The Apple ][ Emulator.
//
// Steve ][ is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Steve ][ is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Steve ][. If not, see <https://www.gnu.org/licenses/>.
//
#ifndef __6502_INSTR_MISC_H__
#define __6502_INSTR_MISC_H__
/**
BRK Force Break
interrupt, N Z C I D V
push PC+2, push SR - - - 1 - -
addressing assembler opc bytes cyles
--------------------------------------------
implied BRK 00 1 7
**/
INLINE int BRK() {
dbgPrintf("BRK ");
disPrintf(disassembly.inst, "BRK");
PUSH_addr(m6502.PC +1); // PC +2, however, fetch already incremented it by 1
// B flag should be set before pushing flags onto the stack
m6502.B = 1;
PUSH( getFlags().SR );
m6502.I = 1;
m6502.PC = memread16(IRQ_VECTOR);
return 7;
}
/**
HLT / JAM / KIL Halts (Hangs / Jams / Kills) the CPU - Well, it hangs it untill the next power cycle
**/
INLINE void HLT() {
disPrintf(disassembly.inst, "HLT");
m6502.interrupt = HALT;
}
/**
NOP No Operation
--- N Z C I D V
- - - - - -
addressing assembler opc bytes cyles
--------------------------------------------
implied NOP EA 1 2
**/
INLINE void NOP() {
dbgPrintf("NOP ");
disPrintf(disassembly.inst, "NOP");
}
#endif // __6502_INSTR_MISC_H__

View File

@ -0,0 +1,210 @@
//
// main.c
// 6502
//
// Created by Tamas Rudnai on 7/14/19.
// Copyright © 2019, 2020 Tamas Rudnai. All rights reserved.
//
// This file is part of Steve ][ -- The Apple ][ Emulator.
//
// Steve ][ is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Steve ][ is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Steve ][. If not, see <https://www.gnu.org/licenses/>.
//
#ifndef __6502_INSTR_SET_CLR_H__
#define __6502_INSTR_SET_CLR_H__
/**
CLC Clear Carry Flag
0 -> C N Z C I D V
- - 0 - - -
addressing assembler opc bytes cyles
--------------------------------------------
implied CLC 18 1 2
**/
INLINE void CLC() {
dbgPrintf("CLC ");
disPrintf(disassembly.inst, "CLC");
m6502.C = 0;
}
/**
CLD Clear Decimal Mode
0 -> D N Z C I D V
- - - - 0 -
addressing assembler opc bytes cyles
--------------------------------------------
implied CLD D8 1 2
**/
INLINE void CLD() {
dbgPrintf("CLD ");
disPrintf(disassembly.inst, "CLD");
m6502.D = 0;
}
/**
CLI Clear Interrupt Disable Bit
0 -> I N Z C I D V
- - - 0 - -
addressing assembler opc bytes cyles
--------------------------------------------
implied CLI 58 1 2
**/
INLINE void CLI() {
dbgPrintf("CLI ");
disPrintf(disassembly.inst, "CLI");
m6502.I = 0;
}
/**
CLV Clear Overflow Flag
0 -> V N Z C I D V
- - - - - 0
addressing assembler opc bytes cyles
--------------------------------------------
implied CLV B8 1 2
**/
INLINE void CLV() {
dbgPrintf("CLV ");
disPrintf(disassembly.inst, "CLV");
m6502.V = 0;
}
/**
SEC Set Carry Flag
1 -> C N Z C I D V
- - 1 - - -
addressing assembler opc bytes cyles
--------------------------------------------
implied SEC 38 1 2
**/
INLINE void SEC() {
dbgPrintf("SEC ");
disPrintf(disassembly.inst, "SEC");
m6502.C = 1;
}
/**
SED Set Decimal Flag
1 -> D N Z C I D V
- - - - 1 -
addressing assembler opc bytes cyles
--------------------------------------------
implied SED F8 1 2
**/
INLINE void SED() {
dbgPrintf("SED ");
disPrintf(disassembly.inst, "SED");
m6502.D = 1;
}
/**
SEI Set Interrupt Disable Status
1 -> I N Z C I D V
- - - 1 - -
addressing assembler opc bytes cyles
--------------------------------------------
implied SEI 78 1 2
**/
INLINE void SEI() {
dbgPrintf("SEI ");
disPrintf(disassembly.inst, "SEI");
m6502.I = 1;
}
/**
RMB SMB - Reset or Set Memory Bit
RMB and SMB clear (RMB) or set (SMB) the specified bit in the specified zero page location,
and can be used in conjuction with the BBR and BBS instructions. Again, note that as with BBR and TRB,
the term reset in RMB is used to mean clear.
The function of RMB and SMB is very similar to the function of TRB and TSB, except that RMB and SMB
can clear or set only one zero page bit, whereas TRB and TSB can clear or set any number of bits. Also,
only zero page addressing is available with RMB and SMB, whereas zero page and absolute addressing
are available for both TRB and TSB. As a result, RMB and SMB do not offer much that isn't already available
with TRB and TSB (which are available on 65C02s from all manufacturers). The main advantages are that
RMB and SMB, unlike TRB and TSB, do not use the accumulator, leaving it available, and do not affect any flags.
However, it is worth noting that it is rarely useful to preserve the value of the Z (zero) flag (the only flag affected by
TRB and TSB), unlike other flags (such as the carry).
Like BBR and BBS, the bit to test is typically specified as part of the instruction name rather than the operand, i.e.
Flags affected: none
OP LEN CYC MODE FLAGS SYNTAX
-- --- --- ---- ----- ------
07 2 5 zp ........ RMB0 $12
17 2 5 zp ........ RMB1 $12
27 2 5 zp ........ RMB2 $12
37 2 5 zp ........ RMB3 $12
47 2 5 zp ........ RMB4 $12
57 2 5 zp ........ RMB5 $12
67 2 5 zp ........ RMB6 $12
77 2 5 zp ........ RMB7 $12
87 2 5 zp ........ SMB0 $12
97 2 5 zp ........ SMB1 $12
A7 2 5 zp ........ SMB2 $12
B7 2 5 zp ........ SMB3 $12
C7 2 5 zp ........ SMB4 $12
D7 2 5 zp ........ SMB5 $12
E7 2 5 zp ........ SMB6 $12
F7 2 5 zp ........ SMB7 $12
**/
#define RMB(n) INLINE void RMB##n( uint8_t zpg ) { \
dbgPrintf("RMB"#n" "); \
disPrintf(disassembly.inst, "RMB"#n); \
WRLOMEM[zpg] &= ~(1 << n); \
}
RMB(0)
RMB(1)
RMB(2)
RMB(3)
RMB(4)
RMB(5)
RMB(6)
RMB(7)
#define SMB(n) INLINE void SMB##n( uint8_t zpg ) { \
dbgPrintf("SMB"#n" "); \
disPrintf(disassembly.inst, "SMB"#n); \
WRLOMEM[zpg] |= (1 << n); \
}
SMB(0)
SMB(1)
SMB(2)
SMB(3)
SMB(4)
SMB(5)
SMB(6)
SMB(7)
#endif // __6502_INSTR_SET_CLR_H__

View File

@ -0,0 +1,156 @@
//
// main.c
// 6502
//
// Created by Tamas Rudnai on 7/14/19.
// Copyright © 2019, 2020 Tamas Rudnai. All rights reserved.
//
// This file is part of Steve ][ -- The Apple ][ Emulator.
//
// Steve ][ is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Steve ][ is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Steve ][. If not, see <https://www.gnu.org/licenses/>.
//
#ifndef __6502_INSTR_SHIFT_ROTATE_H__
#define __6502_INSTR_SHIFT_ROTATE_H__
/**
ASL Shift Left One Bit (Memory or Accumulator)
C <- [76543210] <- 0 N Z C I D V
+ + + - - -
addressing assembler opc bytes cyles
--------------------------------------------
accumulator ASL A 0A 1 2
zeropage ASL oper 06 2 5
zeropage,X ASL oper,X 16 2 6
absolute ASL oper 0E 3 6
absolute,X ASL oper,X 1E 3 7
**/
INLINE void _ASL( uint16_t addr ) {
m6502.C = memread(addr) & 0x80;
set_flags_NZ( WRLOMEM[addr] <<= 1 );
}
INLINE void ASL( uint16_t addr ) {
dbgPrintf("ASL ");
disPrintf(disassembly.inst, "ASL");
_ASL(addr);
}
INLINE void ASLA() {
dbgPrintf("ASL ");
disPrintf(disassembly.inst, "ASL");
m6502.C = m6502.A & 0x80;
set_flags_NZ( m6502.A <<= 1 );
}
/**
LSR Shift One Bit Right (Memory or Accumulator)
0 -> [76543210] -> C N Z C I D V
0 + + - - -
addressing assembler opc bytes cyles
--------------------------------------------
accumulator LSR A 4A 1 2
zeropage LSR oper 46 2 5
zeropage,X LSR oper,X 56 2 6
absolute LSR oper 4E 3 6
absolute,X LSR oper,X 5E 3 7
**/
INLINE void LSR( uint16_t addr ) {
dbgPrintf("LSR ");
disPrintf(disassembly.inst, "LSR");
m6502.C = WRLOMEM[addr] & 1;
set_flags_NZ( WRLOMEM[addr] >>= 1 );
}
INLINE void LSRA() {
dbgPrintf("LSR ");
disPrintf(disassembly.inst, "LSR");
m6502.C = m6502.A & 1;
set_flags_NZ( m6502.A >>= 1 );
}
/**
ROL Rotate One Bit Left (Memory or Accumulator)
C <- [76543210] <- C N Z C I D V
+ + + - - -
addressing assembler opc bytes cyles
--------------------------------------------
accumulator ROL A 2A 1 2
zeropage ROL oper 26 2 5
zeropage,X ROL oper,X 36 2 6
absolute ROL oper 2E 3 6
absolute,X ROL oper,X 3E 3 7
**/
INLINE void _ROL( uint16_t addr ) {
uint8_t C = m6502.C != 0;
m6502.C = WRLOMEM[addr] & 0x80;
WRLOMEM[addr] <<= 1;
set_flags_NZ( WRLOMEM[addr] |= C );
}
INLINE void ROL( uint16_t addr ) {
dbgPrintf("ROL ");
disPrintf(disassembly.inst, "ROL");
_ROL(addr);
}
INLINE void ROLA() {
dbgPrintf("ROL ");
disPrintf(disassembly.inst, "ROL");
uint8_t C = m6502.C != 0;
m6502.C = m6502.A & 0x80;
m6502.A <<= 1;
set_flags_NZ( m6502.A |= C );
}
/**
ROR Rotate One Bit Right (Memory or Accumulator)
C -> [76543210] -> C N Z C I D V
+ + + - - -
addressing assembler opc bytes cyles
--------------------------------------------
accumulator ROR A 6A 1 2
zeropage ROR oper 66 2 5
zeropage,X ROR oper,X 76 2 6
absolute ROR oper 6E 3 6
absolute,X ROR oper,X 7E 3 7
**/
INLINE void _ROR( uint16_t addr ) {
uint8_t C = m6502.C != 0;
m6502.C = WRLOMEM[addr] & 1;
WRLOMEM[addr] >>= 1;
set_flags_NZ( WRLOMEM[addr] |= C << 7 );
}
INLINE void ROR( uint16_t addr ) {
dbgPrintf("ROR ");
disPrintf(disassembly.inst, "ROR");
_ROR(addr);
}
INLINE void RORA() {
dbgPrintf("ROR ");
disPrintf(disassembly.inst, "ROR");
uint8_t C = m6502.C != 0;
m6502.C = m6502.A & 1;
m6502.A >>= 1;
set_flags_NZ( m6502.A |= C << 7);
}
#endif // __6502_INSTR_SHIFT_ROTATE_H__

View File

@ -0,0 +1,182 @@
//
// main.c
// 6502
//
// Created by Tamas Rudnai on 7/14/19.
// Copyright © 2019, 2020 Tamas Rudnai. All rights reserved.
//
// This file is part of Steve ][ -- The Apple ][ Emulator.
//
// Steve ][ is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Steve ][ is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Steve ][. If not, see <https://www.gnu.org/licenses/>.
//
#ifndef __6502_INSTR_STACK_H__
#define __6502_INSTR_STACK_H__
static const uint16_t stack_base_addr = 0x100;
INLINE void PUSH( uint8_t src ) {
// DO NOT MAKE IT NICER! faster this way!
WRLOMEM[ stack_base_addr | m6502.SP-- ] = src;
}
INLINE uint8_t POP() {
return Apple2_64K_MEM[ stack_base_addr | ++m6502.SP ];
}
INLINE void PUSH_addr( uint16_t addr ) {
PUSH( (uint8_t)(addr >> 8) );
PUSH( (uint8_t)addr );
}
INLINE uint16_t POP_addr() {
return POP() + ( POP() << 8 );
}
/**
PHA Push Accumulator on Stack
push A N Z C I D V
- - - - - -
addressing assembler opc bytes cyles
--------------------------------------------
implied PHA 48 1 3
**/
INLINE void PHA() {
dbgPrintf("PHA %02X ", m6502.A);
disPrintf(disassembly.inst, "PHA");
PUSH( m6502.A );
}
/**
PHX Push index X on Stack
push X N Z C I D V
- - - - - -
addressing assembler opc bytes cyles
--------------------------------------------
implied PHX 48 1 3
**/
INLINE void PHX() {
dbgPrintf("PHX %02X ", m6502.X);
disPrintf(disassembly.inst, "PHX");
PUSH( m6502.X );
}
/**
PHY Push index Y on Stack
push Y N Z C I D V
- - - - - -
addressing assembler opc bytes cyles
--------------------------------------------
implied PHY 48 1 3
**/
INLINE void PHY() {
dbgPrintf("PHY %02X ", m6502.Y);
disPrintf(disassembly.inst, "PHY");
PUSH( m6502.Y );
}
/**
PLA Pull Accumulator from Stack
pull A N Z C I D V
+ + - - - -
addressing assembler opc bytes cyles
--------------------------------------------
implied PLA 68 1 4
**/
INLINE void PLA() {
m6502.A = POP();
dbgPrintf("PLA %02X ", m6502.A);
disPrintf(disassembly.inst, "PLA");
set_flags_NZ( m6502.A );
}
/**
PLX Pull index X from Stack
pull X N Z C I D V
+ + - - - -
addressing assembler opc bytes cyles
--------------------------------------------
implied PLX 68 1 4
**/
INLINE void PLX() {
m6502.X = POP();
dbgPrintf("PLX %02X ", m6502.X);
disPrintf(disassembly.inst, "PLX");
set_flags_NZ( m6502.X );
}
/**
PLY Pull index Y from Stack
pull Y N Z C I D V
+ + - - - -
addressing assembler opc bytes cyles
--------------------------------------------
implied PLY 68 1 4
**/
INLINE void PLY() {
m6502.Y = POP();
dbgPrintf("PLY %02X ", m6502.Y);
disPrintf(disassembly.inst, "PLY");
set_flags_NZ( m6502.Y );
}
/**
PHP Push Processor Status on Stack
push SR N Z C I D V
- - - - - -
addressing assembler opc bytes cyles
--------------------------------------------
implied PHP 08 1 3
**/
INLINE void PHP() {
dbgPrintf("PHP %02X ", m6502.SR);
disPrintf(disassembly.inst, "PHP");
PUSH( getFlags().SR ); // res and B flag should be set
}
/**
PLP Pull Processor Status from Stack
pull SR N Z C I D V
from stack
addressing assembler opc bytes cyles
--------------------------------------------
implied PLP 28 1 4
**/
INLINE void PLP() {
setFlags(POP() | 0x30); // res and B flag should be set
dbgPrintf("PLP %02X ", m6502.SR);
disPrintf(disassembly.inst, "PLP");
}
#endif // __6502_INSTR_STACK_H__

View File

@ -0,0 +1,126 @@
//
// main.c
// 6502
//
// Created by Tamas Rudnai on 7/14/19.
// Copyright © 2019, 2020 Tamas Rudnai. All rights reserved.
//
// This file is part of Steve ][ -- The Apple ][ Emulator.
//
// Steve ][ is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Steve ][ is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Steve ][. If not, see <https://www.gnu.org/licenses/>.
//
#ifndef __6502_INSTR_TRANSFER_H__
#define __6502_INSTR_TRANSFER_H__
/**
TAX Transfer Accumulator to Index X
A -> X N Z C I D V
+ + - - - -
addressing assembler opc bytes cyles
--------------------------------------------
implied TAX AA 1 2
**/
INLINE void TAX() {
dbgPrintf("TAX(%02X) ", m6502.A);
disPrintf(disassembly.inst, "TAX");
set_flags_NZ(m6502.X = m6502.A);
}
/**
TXA Transfer Index X to Accumulator
X -> A N Z C I D V
+ + - - - -
addressing assembler opc bytes cyles
--------------------------------------------
implied TXA 8A 1 2
**/
INLINE void TXA() {
dbgPrintf("TXA(%02X) ", m6502.X);
disPrintf(disassembly.inst, "TXA");
set_flags_NZ(m6502.A = m6502.X);
}
/**
TAY Transfer Accumulator to Index Y
A -> Y N Z C I D V
+ + - - - -
addressing assembler opc bytes cyles
--------------------------------------------
implied TAY A8 1 2
**/
INLINE void TAY() {
dbgPrintf("TAY ");
disPrintf(disassembly.inst, "TAY");
set_flags_NZ(m6502.Y = m6502.A);
}
/**
TYA Transfer Index Y to Accumulator
Y -> A N Z C I D V
+ + - - - -
addressing assembler opc bytes cyles
--------------------------------------------
implied TYA 98 1 2
**/
INLINE void TYA() {
dbgPrintf("TYA(%02X) ", m6502.Y);
disPrintf(disassembly.inst, "TYA");
set_flags_NZ(m6502.A = m6502.Y);
}
/**
TSX Transfer Stack Pointer to Index X
SP -> X N Z C I D V
+ + - - - -
addressing assembler opc bytes cyles
--------------------------------------------
implied TSX BA 1 2
**/
INLINE void TSX() {
dbgPrintf("TSX(%02X) ", m6502.SP);
disPrintf(disassembly.inst, "TSX");
set_flags_NZ(m6502.X = m6502.SP);
}
/**
TXS Transfer Index X to Stack Register
X -> SP N Z C I D V
- - - - - -
addressing assembler opc bytes cyles
--------------------------------------------
implied TXS 9A 1 2
**/
INLINE void TXS() {
dbgPrintf("TXS(%02X) ", m6502.X);
disPrintf(disassembly.inst, "TXS");
m6502.SP = m6502.X;
}
#endif // __6502_INSTR_TRANSFER_H__

View File

@ -0,0 +1,313 @@
//
// main.c
// 6502
//
// Created by Tamas Rudnai on 7/14/19.
// Copyright © 2019, 2020 Tamas Rudnai. All rights reserved.
//
// This file is part of Steve ][ -- The Apple ][ Emulator.
//
// Steve ][ is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Steve ][ is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Steve ][. If not, see <https://www.gnu.org/licenses/>.
//
#ifndef __6502_INSTR_UNDOC_H__
#define __6502_INSTR_UNDOC_H__
/**
ANC - "AND" Memory with Accumulator
THEN Copy Bit 7 of Result into Carry
(M "AND" A) -> A
THEN msb(A) -> C
**/
INLINE void ANC ( uint8_t src ) {
disPrintf(disassembly.inst, "ANC");
set_flags_NZ( m6502.A &= src );
m6502.C = m6502.A >> 7;
}
/**
ARC - "AND" Memory with Accumulator
THEN Copy Bit 7 of Result into Carry
THEN Rotate Accumulator One Bit Right
(Carry unaffected)
(M "AND" A) -> A
THEN msb(A) -> C
THEN ROR A
**/
INLINE void ARC ( uint8_t src ) {
disPrintf(disassembly.inst, "ARC");
_AND(src);
m6502.C = m6502.A >> 7;
// RORA -- Carry not affected
uint8_t C = m6502.C != 0;
m6502.A >>= 1;
set_flags_NZ( m6502.A |= C << 7);
}
/**
ASR - "AND" Memory with Accumulator
THEN Shift Accumulator One Bit Right
(M "AND" A) -> A
THEN LSR A
**/
INLINE void ASR ( uint8_t src ) {
disPrintf(disassembly.inst, "ASR");
// AND
m6502.A &= src;
// LSR A
m6502.C = m6502.A & 1;
set_flags_NZ( m6502.A >>= 1 );
}
/**
DCP - Decrement Memory by One
THEN Compare Memory with Accumulator
(M - 1) -> M
THEN CMP M
**/
INLINE void DCP ( uint16_t addr ) {
disPrintf(disassembly.inst, "DCP");
_DEC(addr);
_CMP(WRLOMEM[addr]);
}
/**
LAS - Stores {adr} & S into A, X and S
**/
INLINE void LAS ( uint8_t src ) {
disPrintf(disassembly.inst, "LAS");
set_flags_NZ( m6502.A = m6502.X = m6502.SP = m6502.SP & src );
}
/**
ISB / ISC / INS - Increment Memory by One
THEN Subtract Memory from Accumulator with Borrow
(M + 1) -> M
THEN (A - M - ~C) -> A
**/
INLINE void ISB ( uint16_t addr ) {
disPrintf(disassembly.inst, "ISB");
_INC(addr);
_SBC(WRLOMEM[addr]);
}
/**
LAX - Load Index X and Accumulator with Memory
M -> X,A
**/
INLINE void LAX ( uint8_t src ) {
disPrintf(disassembly.inst, "LAX");
set_flags_NZ(m6502.A = m6502.X = src);
}
/**
RLA - Rotate Memory One Bit Left
THEN "AND" Memory with Accumulator
ROL M
AND M
**/
INLINE void RLA ( uint16_t addr ) {
disPrintf(disassembly.inst, "RLA");
_ROL(addr);
_AND(WRLOMEM[addr]);
}
/**
RRA - Rotate Memory One Bit Right
THEN Add Memory to Accumulator with Carry
ROR M
ADC M
**/
INLINE void RRA ( uint16_t addr ) {
disPrintf(disassembly.inst, "RRA");
_ROR(addr);
_ADC(WRLOMEM[addr]);
}
/**
SAS - "AND" Accumulator with Index X into Stack Pointer
THEN Store Result "AND" (MSB(Address)+1) in Memory
(A "AND" X) -> SP
THEN (SP "AND" (MSB(adr)+1)) -> M
**/
INLINE void SAS ( uint16_t addr ) {
disPrintf(disassembly.inst, "SAS");
m6502.SP = m6502.A & m6502.X;
set_flags_NZ( WRLOMEM[addr] = m6502.SP & ((addr >> 8) + 1) );
}
/**
SBX - Store Index X "AND" Accumulator in Memory
Carry and Decimal flags are ignored but the
Carry flag will be set in substraction. This
is due to the CMP command, which is executed
instead of the real SBC.
(A & X) - Immediate -> X
The 'SBX' ($CB) may seem to be very complex operation, even though it
is a combination of the subtraction of accumulator and parameter, as
in the 'CMP' instruction, and the command 'DEX'. As a result, both A
and X are connected to ALU but only the subtraction takes place. Since
the comparison logic was used, the result of subtraction should be
normally ignored, but the 'DEX' now happily stores to X the value of
(A & X) - Immediate. That is why this instruction does not have any
decimal mode, and it does not affect the V flag. Also Carry flag will
be ignored in the subtraction but set according to the result.
**/
INLINE void SBX ( uint8_t src ) {
disPrintf(disassembly.inst, "SBX");
uint16_t tmp;
// Decimal flag is ignored
tmp = (m6502.A & m6502.X) - src;
m6502.C = tmp < 0x100;
m6502.V = ( (m6502.A ^ tmp) & 0x80 ) && ( (m6502.A ^ src) & 0x80 );
set_flags_NZ( m6502.X = tmp );
}
/**
SHA - Store Index X "AND" Accumulator in Memory
(X "AND" A "AND" addr.H) -> M
**/
INLINE void SHA ( uint16_t addr ) {
disPrintf(disassembly.inst, "SHA");
set_flags_NZ( WRLOMEM[addr] = m6502.X & m6502.A & ((addr >> 8) + 1) );
}
/**
SHY - Store (MSB(Address)+1) "AND" Index Y in Memory
((MSB(adr)+1) "AND" Y) -> M
**/
INLINE void SHY ( uint16_t addr ) {
disPrintf(disassembly.inst, "SHY");
set_flags_NZ( WRLOMEM[addr] = m6502.Y &((addr >> 8) + 1) );
}
/**
SHX - Store (MSB(Address)+1) "AND" Index Y in Memory
((MSB(adr)+1) "AND" X) -> M
**/
INLINE void SHX ( uint16_t addr ) {
disPrintf(disassembly.inst, "SHX");
set_flags_NZ( WRLOMEM[addr] = m6502.X &((addr >> 8) + 1) );
}
/**
SLO - Shift Memory One Bit Left
THEN "OR" Memory with Accumulator
into Accumulator and Memory
ASL M
ORA M
-> A,M
**/
INLINE void SLO ( uint16_t addr ) {
disPrintf(disassembly.inst, "SLO");
_ASL(addr);
_ORA( WRLOMEM[addr] );
set_flags_NZ( WRLOMEM[addr] = m6502.A ); // A -> M
}
/**
SAX - Store Accumulator "AND" Index X in Memory
(A "AND" X) -> M
**/
INLINE void SAX ( uint16_t addr ) {
disPrintf(disassembly.inst, "SAX");
set_flags_NZ( WRLOMEM[addr] = m6502.A & m6502.X );
}
/**
SRE - Shift Memory One Bit Right
THEN "OR" Memory with Accumulator
LSR M
ORA M
**/
INLINE void SRE ( uint16_t addr ) {
disPrintf(disassembly.inst, "SRE");
// LSR
m6502.C = WRLOMEM[addr] & 1;
set_flags_NZ( WRLOMEM[addr] >>= 1 );
// EOR M
set_flags_NZ( m6502.A |= WRLOMEM[addr] );
}
/**
XAA - "AND" Memory with Index X into Accumulator
(M "AND" X) -> A
**/
INLINE void XAA ( uint8_t src ) {
disPrintf(disassembly.inst, "XAA");
set_flags_NZ( m6502.A = m6502.X & src );
}
#endif // __6502_INSTR_UNDOC_H__

View File

@ -0,0 +1,43 @@
//
// main.c
// 6502
//
// Created by Tamas Rudnai on 7/14/19.
// Copyright © 2019, 2020 Tamas Rudnai. All rights reserved.
//
// This file is part of Steve ][ -- The Apple ][ Emulator.
//
// Steve ][ is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Steve ][ is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Steve ][. If not, see <https://www.gnu.org/licenses/>.
//
#ifndef __6502_INSTRUCTIONS_H__
#define __6502_INSTRUCTIONS_H__
#include "6502_instr_load_store.h"
#include "6502_instr_arithmetic.h"
#include "6502_instr_inc_dec.h"
#include "6502_instr_shift_rotate.h"
#include "6502_instr_logic.h"
#include "6502_instr_compare_test.h"
#include "6502_instr_branch.h"
#include "6502_instr_transfer.h"
#include "6502_instr_stack.h"
#include "6502_instr_call_ret_jump.h"
#include "6502_instr_set_clr.h"
#include "6502_instr_misc.h"
#include "6502_instr_undoc.h"
#endif // __6502_INSTRUCTIONS_H__