mirror of
https://github.com/trudnai/Steve2.git
synced 2024-10-05 21:54:57 +00:00
- Unified inline
- "breakpoints" for debugging - BugFixes
This commit is contained in:
parent
f2e5b49a6e
commit
26c413df6b
@ -9,12 +9,14 @@
|
||||
/* Begin PBXBuildFile section */
|
||||
32439F8722ECD8AD0077AAE0 /* 6502.c in Sources */ = {isa = PBXBuildFile; fileRef = 32439F7422ECD8AD0077AAE0 /* 6502.c */; };
|
||||
32439F8822ECD8AD0077AAE0 /* apple.rom in Resources */ = {isa = PBXBuildFile; fileRef = 32439F8422ECD8AD0077AAE0 /* apple.rom */; };
|
||||
326ED2EF232D7A0000A41337 /* 6502_functional_test.bin in Resources */ = {isa = PBXBuildFile; fileRef = 326ED2EE232D7A0000A41337 /* 6502_functional_test.bin */; };
|
||||
32BFFB5B22EACC630003B53F /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32BFFB5A22EACC630003B53F /* AppDelegate.swift */; };
|
||||
32BFFB5D22EACC630003B53F /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32BFFB5C22EACC630003B53F /* ViewController.swift */; };
|
||||
32BFFB5F22EACC660003B53F /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 32BFFB5E22EACC660003B53F /* Assets.xcassets */; };
|
||||
32BFFB6222EACC660003B53F /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 32BFFB6022EACC660003B53F /* Main.storyboard */; };
|
||||
32BFFB6E22EACC660003B53F /* A2MacTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32BFFB6D22EACC660003B53F /* A2MacTests.swift */; };
|
||||
32BFFB7922EACC660003B53F /* A2MacUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32BFFB7822EACC660003B53F /* A2MacUITests.swift */; };
|
||||
32C45306232E3EEF0000EBA1 /* RepeatingTimer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32C45305232E3EEF0000EBA1 /* RepeatingTimer.swift */; };
|
||||
32EDB7A223272CA80073AF2D /* fail1.txt in Resources */ = {isa = PBXBuildFile; fileRef = 32EDB7A123272CA80073AF2D /* fail1.txt */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
@ -58,6 +60,7 @@
|
||||
32439F8622ECD8AD0077AAE0 /* common.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = common.h; sourceTree = "<group>"; };
|
||||
3264261023284F6F008B615F /* Apple2_mmio_8bit_ioaddr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Apple2_mmio_8bit_ioaddr.h; sourceTree = "<group>"; };
|
||||
326426112328ADF4008B615F /* Apple_II_ROM.s */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm; path = Apple_II_ROM.s; sourceTree = "<group>"; };
|
||||
326ED2EE232D7A0000A41337 /* 6502_functional_test.bin */ = {isa = PBXFileReference; lastKnownFileType = archive.macbinary; path = 6502_functional_test.bin; sourceTree = SOURCE_ROOT; };
|
||||
32BFFB5722EACC630003B53F /* A2Mac.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = A2Mac.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
32BFFB5A22EACC630003B53F /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
32BFFB5C22EACC630003B53F /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; };
|
||||
@ -71,6 +74,7 @@
|
||||
32BFFB7422EACC660003B53F /* A2MacUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = A2MacUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
32BFFB7822EACC660003B53F /* A2MacUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = A2MacUITests.swift; sourceTree = "<group>"; };
|
||||
32BFFB7A22EACC660003B53F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
32C45305232E3EEF0000EBA1 /* RepeatingTimer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RepeatingTimer.swift; sourceTree = "<group>"; };
|
||||
32EDB7A123272CA80073AF2D /* fail1.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = fail1.txt; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
@ -148,11 +152,13 @@
|
||||
32439F7422ECD8AD0077AAE0 /* 6502.c */,
|
||||
32439F8522ECD8AD0077AAE0 /* 6502.h */,
|
||||
32439F8422ECD8AD0077AAE0 /* apple.rom */,
|
||||
326ED2EE232D7A0000A41337 /* 6502_functional_test.bin */,
|
||||
32439F7322ECD8AD0077AAE0 /* Apple2_mmio.h */,
|
||||
3264261023284F6F008B615F /* Apple2_mmio_8bit_ioaddr.h */,
|
||||
32439F8622ECD8AD0077AAE0 /* common.h */,
|
||||
32BFFB5A22EACC630003B53F /* AppDelegate.swift */,
|
||||
32BFFB5C22EACC630003B53F /* ViewController.swift */,
|
||||
32C45305232E3EEF0000EBA1 /* RepeatingTimer.swift */,
|
||||
32EDB7A123272CA80073AF2D /* fail1.txt */,
|
||||
32BFFB5E22EACC660003B53F /* Assets.xcassets */,
|
||||
32BFFB6022EACC660003B53F /* Main.storyboard */,
|
||||
@ -290,6 +296,7 @@
|
||||
32BFFB5F22EACC660003B53F /* Assets.xcassets in Resources */,
|
||||
32439F8822ECD8AD0077AAE0 /* apple.rom in Resources */,
|
||||
32BFFB6222EACC660003B53F /* Main.storyboard in Resources */,
|
||||
326ED2EF232D7A0000A41337 /* 6502_functional_test.bin in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@ -317,6 +324,7 @@
|
||||
32439F8722ECD8AD0077AAE0 /* 6502.c in Sources */,
|
||||
32BFFB5D22EACC630003B53F /* ViewController.swift in Sources */,
|
||||
32BFFB5B22EACC630003B53F /* AppDelegate.swift in Sources */,
|
||||
32C45306232E3EEF0000EBA1 /* RepeatingTimer.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
204
A2Mac/6502.c
204
A2Mac/6502.c
@ -6,20 +6,35 @@
|
||||
// Copyright © 2019 GameAlloy. All rights reserved.
|
||||
//
|
||||
|
||||
#define CLK_WAIT
|
||||
#define NO_SPEED_TEST
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#ifdef DEBUG
|
||||
#define INLINE
|
||||
#else
|
||||
#define INLINE static __attribute__((always_inline))
|
||||
#endif
|
||||
|
||||
#include "common.h"
|
||||
#include "Apple2_mmio.h"
|
||||
|
||||
|
||||
#define SOFTRESET_VECTOR 0x3F2
|
||||
#define SOFTRESET_VECTOR 0x3F2
|
||||
|
||||
#define NMI_VECTOR 0xFFFA
|
||||
#define RESET_VECTOR 0xFFFC
|
||||
#define IRQ_VECTOR 0xFFFE
|
||||
|
||||
|
||||
/**
|
||||
Instruction Implementations
|
||||
!!!! `his has to be here!!!
|
||||
This idea is that "static inline" would work only if it is
|
||||
This idea is that "INLINE" would work only if it is
|
||||
located in the same source file -- hence the include...
|
||||
**/
|
||||
#include "6502_instructions.h"
|
||||
@ -31,7 +46,7 @@ unsigned long long int clktime = 0;
|
||||
m6502_t m6502 = {0};
|
||||
|
||||
|
||||
static inline int m6502_step() {
|
||||
INLINE int m6502_step() {
|
||||
|
||||
// switch ( fetch16() ) {
|
||||
// case 0xFCD0: // D0 FC BNE
|
||||
@ -43,6 +58,26 @@ static inline int m6502_step() {
|
||||
// default:
|
||||
// m6502.pc -= 2;
|
||||
//
|
||||
|
||||
#ifdef DEBUG
|
||||
switch ( m6502.PC ) {
|
||||
case 0x400:
|
||||
dbgPrintf("START...\n");
|
||||
break;
|
||||
|
||||
case 0x9D1:
|
||||
dbgPrintf("BREAK POINT...\n");
|
||||
break;
|
||||
|
||||
case 0x35BD:
|
||||
if ( ( m6502.A == 0x35 ) && ( m6502.C ) )
|
||||
dbgPrintf("BREAK POINT...\n");
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
switch ( fetch() ) {
|
||||
case 0x00: BRK(); return 2; // BRK
|
||||
case 0x01: ORA( src_X_ind() ); return 6; // ORA X,ind
|
||||
@ -78,84 +113,84 @@ static inline int m6502_step() {
|
||||
// case 0x1F: // SLO* (undocumented)
|
||||
case 0x20: JSR( abs_addr() ); return 6; // JSR abs
|
||||
case 0x21: AND( src_X_ind() ); return 6; // AND X,ind
|
||||
// case 0x22:
|
||||
// case 0x23:
|
||||
// case 0x22: KIL
|
||||
// case 0x23: RLA izx 8
|
||||
case 0x24: BIT( src_zp() ); return 3; // BIT zpg
|
||||
case 0x25: AND( src_zp() ); return 3; // AND zpg
|
||||
case 0x26: ROL( dest_zp() ); return 5; // ROL zpg
|
||||
// case 0x27:
|
||||
// case 0x27: RLA zp 5
|
||||
case 0x28: PLP(); return 4; // PLP
|
||||
case 0x29: AND( imm() ); return 2; // AND imm
|
||||
case 0x2A: ROLA(); return 2; // ROL A
|
||||
// case 0x2B:
|
||||
// case 0x2B: ANC imm 2
|
||||
case 0x2C: BIT( src_abs() ); return 4; // BIT abs
|
||||
case 0x2D: AND( src_abs() ); return 4; // AND abs
|
||||
case 0x2E: ROL( dest_abs() ); return 6; // ROL abs
|
||||
// case 0x2F:
|
||||
// case 0x2F: RLA abs 6
|
||||
case 0x30: BMI( rel_addr() ); return 2; // BMI rel
|
||||
case 0x31: AND( src_ind_Y() ); return 5; // AND ind,Y
|
||||
// case 0x32:
|
||||
// case 0x33:
|
||||
// case 0x34:
|
||||
// case 0x32: KIL
|
||||
// case 0x33: RLA izy 8
|
||||
// case 0x34: NOP zpx 4
|
||||
case 0x35: AND( src_zp_X() ); return 4; // AND zpg,X
|
||||
case 0x36: ROL( dest_zp_X() ); return 6; // ROL zpg,X
|
||||
// case 0x37:
|
||||
// case 0x37: RLA zpx 6
|
||||
case 0x38: SEC(); return 2; // SEC
|
||||
case 0x39: AND( src_abs_Y() ); return 4; // AND abs,Y
|
||||
// case 0x3A:
|
||||
// case 0x3B:
|
||||
// case 0x3C:
|
||||
// case 0x3A: NOP 2
|
||||
// case 0x3B: RLA aby 7
|
||||
// case 0x3C: NOP abx 4
|
||||
case 0x3D: AND( src_abs_X() ); return 4; // AND abs,X
|
||||
case 0x3E: ROL( dest_abs_X() ); return 7; // ROL abs,X
|
||||
// case 0x3F:
|
||||
// case 0x3F: RLA abx 7
|
||||
case 0x40: RTI(); return 6; // RTI
|
||||
case 0x41: EOR( src_X_ind() ); return 6; // EOR X,ind
|
||||
// case 0x42:
|
||||
// case 0x43:
|
||||
// case 0x44:
|
||||
// case 0x42: KIL
|
||||
// case 0x43: SRE izx 8
|
||||
// case 0x44: NOP zp 3
|
||||
case 0x45: EOR( src_zp() ); return 3; // EOR zpg
|
||||
case 0x46: LSR( dest_zp() ); return 5; // LSR zpg
|
||||
// case 0x47:
|
||||
// case 0x47: SRE zp 5
|
||||
case 0x48: PHA(); return 3; // PHA
|
||||
case 0x49: EOR( imm() ); return 2; // EOR imm
|
||||
case 0x4A: LSRA(); return 2; // LSR A
|
||||
// case 0x4B:
|
||||
// case 0x4B: ALR imm 2
|
||||
case 0x4C: JMP( abs_addr() ); return 3; // JMP abs
|
||||
case 0x4D: EOR( src_abs() ); return 4; // EOR abs
|
||||
case 0x4E: LSR( dest_abs() ); return 6; // LSR abs
|
||||
// case 0x4F:
|
||||
// case 0x4F: SRE abs 6
|
||||
case 0x50: BVC( rel_addr() ); return 2; // BVC rel
|
||||
case 0x51: EOR( src_ind_Y() ); return 5; // EOR ind,Y
|
||||
// case 0x52:
|
||||
// case 0x53:
|
||||
// case 0x54:
|
||||
// case 0x52: KIL
|
||||
// case 0x53: SRE izy 8
|
||||
// case 0x54: NOP zpx 4
|
||||
case 0x55: EOR( src_zp_X() ); return 4; // AND zpg,X
|
||||
case 0x56: LSR( dest_zp_X() ); return 6; // LSR zpg,X
|
||||
// case 0x57:
|
||||
// case 0x57: SRE zpx 6
|
||||
case 0x58: CLI(); return 2; // CLI
|
||||
case 0x59: EOR( src_abs_Y() ); return 4; // EOR abs,Y
|
||||
// case 0x5A:
|
||||
// case 0x5B:
|
||||
// case 0x5C:
|
||||
// case 0x5A: NOP 2
|
||||
// case 0x5B: SRE aby 7
|
||||
// case 0x5C: NOP abx 4
|
||||
case 0x5D: EOR( src_abs_X() ); return 4; // EOR abs,X
|
||||
case 0x5E: LSR( dest_abs_X() ); return 7; // LSR abs,X
|
||||
// case 0x5F:
|
||||
// case 0x5F: SRE abx 7
|
||||
case 0x60: RTS(); return 6; // RTS
|
||||
case 0x61: ADC( src_X_ind() ); return 6; // ADC X,ind
|
||||
// case 0x62:
|
||||
// case 0x63:
|
||||
// case 0x64:
|
||||
// case 0x62: KIL
|
||||
// case 0x63: RRA izx 8
|
||||
// case 0x64: NOP zp 3
|
||||
case 0x65: ADC( src_zp() ); return 3; // ADC zpg
|
||||
case 0x66: ROR( dest_zp() ); return 5; // ROR zpg
|
||||
// case 0x67:
|
||||
// case 0x67: RRA zp 5
|
||||
case 0x68: PLA(); break; // PLA
|
||||
case 0x69: ADC( imm() ); return 2; // ADC imm
|
||||
case 0x6A: RORA(); return 2; // ROR A
|
||||
// case 0x6B:
|
||||
// case 0x6B: ARR imm 2
|
||||
case 0x6C: JMP( ind_addr() ); return 5; // JMP ind
|
||||
case 0x6D: ADC( src_abs() ); return 4; // ADC abs
|
||||
case 0x6E: ROR( dest_abs() ); return 6; // ROR abs
|
||||
// case 0x6F:
|
||||
// case 0x6F: RRA abs 6
|
||||
case 0x70: BVS( rel_addr() ); break; // BVS rel
|
||||
case 0x71: ADC( src_ind_Y() ); return 5; // ADC ind,Y
|
||||
// case 0x72:
|
||||
@ -181,7 +216,7 @@ static inline int m6502_step() {
|
||||
case 0x86: STX( dest_zp() ); return 3; // STX zpg
|
||||
// case 0x87:
|
||||
case 0x88: DEY(); return 2; // DEY
|
||||
// case 0x89:
|
||||
// case 0x89: NOP(); imm(); return 4; // NOP imm
|
||||
case 0x8A: TXA(); return 2; // TXA
|
||||
// case 0x8B:
|
||||
case 0x8C: STY( dest_abs() ); return 4; // STY abs
|
||||
@ -194,7 +229,7 @@ static inline int m6502_step() {
|
||||
// case 0x93:
|
||||
case 0x94: STY( dest_zp_X() ); return 4; // STY zpg,X
|
||||
case 0x95: STA( dest_zp_X() ); return 4; // STA zpg,X
|
||||
case 0x96: STX( dest_zp_X() ); return 4; // STX zpg,Y
|
||||
case 0x96: STX( dest_zp_Y() ); return 4; // STX zpg,Y
|
||||
// case 0x97:
|
||||
case 0x98: TYA(); return 2; // TYA
|
||||
case 0x99: STA( dest_abs_Y() ); return 5; // STA abs,Y
|
||||
@ -302,7 +337,7 @@ static inline int m6502_step() {
|
||||
// case 0xFF:
|
||||
|
||||
default:
|
||||
printf("Unimplemented Instruction 0x%02X\n", memread( m6502.pc -1 ));
|
||||
printf("%04X: Unimplemented Instruction 0x%02X\n", m6502.PC -1, memread( m6502.PC -1 ));
|
||||
break;
|
||||
}
|
||||
// } // fetch16
|
||||
@ -312,28 +347,39 @@ static inline int m6502_step() {
|
||||
|
||||
const unsigned long long int iterations = G;
|
||||
|
||||
unsigned long long TICK_PER_SEC = G;
|
||||
unsigned long long TICK_6502_PER_SEC = 0;
|
||||
unsigned long long tick_per_sec = G;
|
||||
unsigned long long tick_6502_per_sec = 0;
|
||||
unsigned long long MHz_6502 = 1.023 * M;
|
||||
|
||||
static __inline__ unsigned long long rdtsc(void)
|
||||
static __attribute__((always_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 );
|
||||
}
|
||||
|
||||
// nanosec does not work very well for some reason
|
||||
struct timespec tim, tim2;
|
||||
|
||||
static inline void m6502_run() {
|
||||
uint8_t clk = 0;
|
||||
INLINE void m6502_run() {
|
||||
// init time
|
||||
// unsigned long long s = rdtsc();
|
||||
#ifdef CLK_WAIT
|
||||
unsigned long long s = rdtsc();
|
||||
unsigned long long e = (unsigned long long)-1LL;
|
||||
#endif
|
||||
|
||||
// for ( unsigned long long int i = 0; i < iterations ; i++ ) {
|
||||
// for ( ; m6502.pc ; ) {
|
||||
for ( ; ; ) {
|
||||
if ( m6502.interrupt_flag ) {
|
||||
#ifdef SPEED_TEST
|
||||
for ( unsigned long long int i = 0; i < iterations ; i++ )
|
||||
#else
|
||||
// for ( ; m6502.pc ; )
|
||||
|
||||
tim.tv_sec = 0;
|
||||
tim.tv_nsec = 500L;
|
||||
|
||||
for ( ; ; )
|
||||
#endif
|
||||
{
|
||||
if ( m6502.IF ) {
|
||||
switch (m6502.interrupt) {
|
||||
case NMI:
|
||||
break;
|
||||
@ -342,25 +388,31 @@ static inline void m6502_run() {
|
||||
break;
|
||||
|
||||
case SOFTRESET:
|
||||
m6502.pc = memread16(SOFTRESET_VECTOR);
|
||||
m6502.PC = memread16(SOFTRESET_VECTOR);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
m6502.interrupt_flag = 0;
|
||||
m6502.IF = 0;
|
||||
}
|
||||
|
||||
dbgPrintf("%04u %04X: ", clktime, m6502.pc);
|
||||
clk = m6502_step();
|
||||
clktime += clk;
|
||||
e = TICK_6502_PER_SEC * clktime;
|
||||
dbgPrintf("%llu %04X: ", clktime, m6502.PC);
|
||||
clktime += m6502_step();
|
||||
|
||||
#ifdef CLK_WAIT
|
||||
e = tick_6502_per_sec * clktime;
|
||||
// query time + wait
|
||||
// usleep(1);
|
||||
|
||||
// TODO: We should use nanosleep
|
||||
usleep(1); // this is good enough for debugging
|
||||
|
||||
// nanosleep(&tim, &tim2);
|
||||
|
||||
// tight loop gives us the most precise wait time
|
||||
// while ( rdtsc() - s < e ) {}
|
||||
#endif
|
||||
|
||||
dbgPrintf("\n");
|
||||
}
|
||||
@ -370,11 +422,11 @@ void init() {
|
||||
unsigned long long s = rdtsc();
|
||||
sleep(1);
|
||||
unsigned long long e = rdtsc();
|
||||
TICK_PER_SEC = e - s;
|
||||
TICK_6502_PER_SEC = TICK_PER_SEC / MHz_6502;
|
||||
tick_per_sec = e - s;
|
||||
tick_6502_per_sec = tick_per_sec / MHz_6502;
|
||||
|
||||
memset( RAM, 0, sizeof(RAM) );
|
||||
|
||||
|
||||
|
||||
// RAM[ 0 ] = 0x4C;
|
||||
// RAM[ 1 ] = 0;
|
||||
@ -384,6 +436,29 @@ void init() {
|
||||
// RAM[ 0xBFFE ] = 0;
|
||||
// RAM[ 0xBFFF ] = 0;
|
||||
|
||||
m6502.A = m6502.X = m6502.Y = 0xFF;
|
||||
// reset vector
|
||||
m6502.SP = 0xFF -3;
|
||||
m6502.SR = 0x30;
|
||||
|
||||
// memory size
|
||||
*((uint16_t*)(&RAM[0x73])) = 0xC000;
|
||||
|
||||
#define NO_FUNCTIONTEST
|
||||
|
||||
#ifdef FUNCTIONTEST
|
||||
FILE * f = fopen("/Users/trudnai/Library/Containers/com.gamealloy.A2Mac/Data/6502_functional_test.bin", "rb");
|
||||
if (f == NULL) {
|
||||
perror("Failed: ");
|
||||
return;
|
||||
}
|
||||
|
||||
fread( RAM, 1, 65536, f);
|
||||
fclose(f);
|
||||
|
||||
m6502.PC = 0x400;
|
||||
|
||||
#else
|
||||
FILE * f = fopen("/Users/trudnai/Library/Containers/com.gamealloy.A2Mac/Data/apple.rom", "rb");
|
||||
if (f == NULL) {
|
||||
perror("Failed: ");
|
||||
@ -392,10 +467,9 @@ void init() {
|
||||
|
||||
fread( RAM + 0xD000, 1, 0x3000, f);
|
||||
fclose(f);
|
||||
|
||||
// reset vector
|
||||
m6502.pc = memread16( 0xFFFC );
|
||||
m6502.sp = 0xFF;
|
||||
|
||||
m6502.PC = memread16( RESET_VECTOR );
|
||||
#endif
|
||||
|
||||
|
||||
uint8_t counter[] = {
|
||||
@ -517,11 +591,11 @@ void tst6502() {
|
||||
// double execution_time = ((double) (end - start)) / CLOCKS_PER_SEC;
|
||||
unsigned long long e = rdtsc();
|
||||
unsigned long long t = e - s;
|
||||
double execution_time = (double)t / TICK_PER_SEC;
|
||||
double execution_time = (double)t / tick_per_sec;
|
||||
|
||||
double mips = iterations / (execution_time * M);
|
||||
double mhz = clktime / (execution_time * M);
|
||||
printf("clk:%llu Elpased time: (%llu / %llu / %llu), %.3lfs (%.3lf MIPS, %.3lf MHz)\n", clktime, TICK_PER_SEC, MHz_6502, TICK_6502_PER_SEC, execution_time, mips, mhz);
|
||||
printf("clk:%llu Elpased time: (%llu / %llu / %llu), %.3lfs (%.3lf MIPS, %.3lf MHz)\n", clktime, tick_per_sec, MHz_6502, tick_6502_per_sec, execution_time, mips, mhz);
|
||||
}
|
||||
|
||||
int ___main(int argc, const char * argv[]) {
|
||||
|
39
A2Mac/6502.h
39
A2Mac/6502.h
@ -27,32 +27,33 @@ typedef struct m6502_s {
|
||||
uint8_t A; // Accumulator
|
||||
uint8_t X; // X index register
|
||||
uint8_t Y; // Y index register
|
||||
// union {
|
||||
// uint8_t instr; // Instruction
|
||||
// struct {
|
||||
// uint8_t cc:2;
|
||||
// uint8_t bbb:3;
|
||||
// uint8_t aaa:3;
|
||||
// };
|
||||
// };
|
||||
union {
|
||||
uint8_t instr; // Instruction
|
||||
uint8_t SR; // Status Register
|
||||
struct {
|
||||
uint8_t aaa:3;
|
||||
uint8_t bbb:3;
|
||||
uint8_t cc:2;
|
||||
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
|
||||
};
|
||||
};
|
||||
union {
|
||||
uint8_t sr; // Status Register as 1 byte
|
||||
struct {
|
||||
uint8_t N:1; // Negative Flag
|
||||
uint8_t V:1; // Overflow Flag ???
|
||||
uint8_t B:2; // B Flag
|
||||
uint8_t D:1; // Decimal Flag
|
||||
uint8_t I:1; // Interrupt Flag
|
||||
uint8_t Z:1; // Zero Flag
|
||||
uint8_t C:1; // Carry Flag
|
||||
} flags; // Status Register
|
||||
};
|
||||
uint16_t pc; // Program Counter
|
||||
uint8_t sp; // Stack Pointer ( stack addr = 0x01 + sp )
|
||||
uint16_t PC; // Program Counter
|
||||
uint8_t SP; // Stack Pointer ( stack addr = 0x01 + sp )
|
||||
unsigned clk; // Clock Counter
|
||||
|
||||
union {
|
||||
int interrupt_flag;
|
||||
int IF; // interrut flag
|
||||
interrupt_t interrupt;
|
||||
};
|
||||
} m6502_t;
|
||||
|
@ -71,8 +71,8 @@ typedef union address16_u {
|
||||
} address16_t;
|
||||
|
||||
|
||||
static inline uint8_t ioRead( uint16_t addr ) {
|
||||
// printf("mmio:%04X\n", addr);
|
||||
INLINE uint8_t ioRead( uint16_t addr ) {
|
||||
// printf("mmio read:%04X\n", addr);
|
||||
switch (addr) {
|
||||
case io_KBD:
|
||||
return RAM[io_KBD];
|
||||
@ -88,7 +88,7 @@ static inline uint8_t ioRead( uint16_t addr ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void ioWrite( uint16_t addr ) {
|
||||
INLINE void ioWrite( uint16_t addr ) {
|
||||
// printf("mmio:%04X\n", addr);
|
||||
switch (addr) {
|
||||
case io_KBD:
|
||||
@ -104,11 +104,11 @@ static inline void ioWrite( uint16_t addr ) {
|
||||
Naive implementation of RAM read from address
|
||||
**/
|
||||
|
||||
static inline uint8_t memread_zp( uint8_t addr ) {
|
||||
INLINE uint8_t memread_zp( uint8_t addr ) {
|
||||
return RAM[ addr ];
|
||||
}
|
||||
|
||||
static inline uint8_t memread( uint16_t addr ) {
|
||||
INLINE uint8_t memread( uint16_t addr ) {
|
||||
// switch ( ((address16_t)addr).page ) {
|
||||
// case 0xC0:
|
||||
// case 0xC1:
|
||||
@ -142,20 +142,25 @@ static inline uint8_t memread( uint16_t addr ) {
|
||||
/**
|
||||
Naive implementation of RAM read from address
|
||||
**/
|
||||
static inline uint8_t memread8( uint16_t addr ) {
|
||||
INLINE uint8_t memread8( uint16_t addr ) {
|
||||
// if ( addr == 0xD2AD ) {
|
||||
// dbgPrintf("OUT OF MEMORY!\n");
|
||||
// }
|
||||
|
||||
|
||||
return RAM[ addr ];
|
||||
}
|
||||
/**
|
||||
Naive implementation of RAM read from address
|
||||
**/
|
||||
static inline uint16_t memread16( uint16_t addr ) {
|
||||
INLINE uint16_t memread16( uint16_t addr ) {
|
||||
return * (uint16_t*) (& RAM[ addr ]);
|
||||
}
|
||||
|
||||
/**
|
||||
Naive implementation of RAM read from address
|
||||
**/
|
||||
//static inline uint16_t memioread16( uint16_t addr ) {
|
||||
//INLINE uint16_t memioread16( uint16_t addr ) {
|
||||
// return (uint16_t)mmio_read[ addr ](addr);
|
||||
//}
|
||||
|
||||
@ -189,19 +194,19 @@ static void memwrite( uint16_t addr, uint8_t byte ) {
|
||||
Fetching 1 byte from memory address pc (program counter)
|
||||
increase pc by one
|
||||
**/
|
||||
static inline uint8_t fetch() {
|
||||
dbgPrintf("%02X ", RAM[m6502.pc]);
|
||||
return memread( m6502.pc++ );
|
||||
INLINE uint8_t fetch() {
|
||||
dbgPrintf("%02X ", RAM[m6502.PC]);
|
||||
return memread( m6502.PC++ );
|
||||
}
|
||||
|
||||
/**
|
||||
Fetching 2 bytes as a 16 bit number from memory address pc (program counter)
|
||||
increase pc by one
|
||||
**/
|
||||
static inline uint16_t fetch16() {
|
||||
dbgPrintf("%04X ", memread16(m6502.pc));
|
||||
uint16_t word = memread16( m6502.pc );
|
||||
m6502.pc += 2;
|
||||
INLINE uint16_t fetch16() {
|
||||
dbgPrintf("%04X ", memread16(m6502.PC));
|
||||
uint16_t word = memread16( m6502.PC );
|
||||
m6502.PC += 2;
|
||||
return word;
|
||||
}
|
||||
|
||||
@ -209,24 +214,25 @@ static inline uint16_t fetch16() {
|
||||
abs .... absolute OPC $LLHH,X
|
||||
operand is address; effective address is address incremented by X with carry **
|
||||
**/
|
||||
static inline uint16_t addr_abs() {
|
||||
INLINE uint16_t addr_abs() {
|
||||
dbgPrintf("abs:%04X(%02X) ", *((uint16_t*)&RAM[m6502.PC]), RAM[*((uint16_t*)&RAM[m6502.PC])]);
|
||||
return fetch16();
|
||||
}
|
||||
static inline uint8_t src_abs() {
|
||||
INLINE uint8_t src_abs() {
|
||||
return memread( addr_abs() );
|
||||
}
|
||||
static inline uint8_t * dest_abs() {
|
||||
INLINE uint8_t * dest_abs() {
|
||||
return & RAM[ addr_abs() ];
|
||||
}
|
||||
|
||||
|
||||
static inline int8_t rel_addr() {
|
||||
INLINE int8_t rel_addr() {
|
||||
return fetch();
|
||||
}
|
||||
static inline uint16_t abs_addr() {
|
||||
INLINE uint16_t abs_addr() {
|
||||
return fetch16();
|
||||
}
|
||||
static inline uint16_t ind_addr() {
|
||||
INLINE uint16_t ind_addr() {
|
||||
return memread16( fetch16() );
|
||||
}
|
||||
|
||||
@ -234,13 +240,14 @@ static inline uint16_t ind_addr() {
|
||||
abs,X .... absolute, X-indexed OPC $LLHH,X
|
||||
operand is address; effective address is address incremented by X with carry **
|
||||
**/
|
||||
static inline uint16_t addr_abs_X() {
|
||||
INLINE uint16_t addr_abs_X() {
|
||||
dbgPrintf("abs,X:%04X(%02X) ", *((uint16_t*)&RAM[m6502.PC]) + m6502.X, RAM[*((uint16_t*)&RAM[m6502.PC]) + m6502.X]);
|
||||
return fetch16() + m6502.X;
|
||||
}
|
||||
static inline uint8_t src_abs_X() {
|
||||
INLINE uint8_t src_abs_X() {
|
||||
return memread8( addr_abs_X() );
|
||||
}
|
||||
static inline uint8_t * dest_abs_X() {
|
||||
INLINE uint8_t * dest_abs_X() {
|
||||
return & RAM[ addr_abs_X() ];
|
||||
}
|
||||
|
||||
@ -249,17 +256,18 @@ static inline uint8_t * dest_abs_X() {
|
||||
abs,Y .... absolute, Y-indexed OPC $LLHH,Y
|
||||
operand is address; effective address is address incremented by Y with carry **
|
||||
**/
|
||||
static inline uint16_t addr_abs_Y() {
|
||||
INLINE uint16_t addr_abs_Y() {
|
||||
dbgPrintf("abs,Y:%04X(%02X) ", *((uint16_t*)&RAM[m6502.PC]) + m6502.Y, RAM[*((uint16_t*)&RAM[m6502.PC]) + m6502.Y]);
|
||||
return abs_addr() + m6502.Y;
|
||||
}
|
||||
static inline uint8_t src_abs_Y() {
|
||||
INLINE uint8_t src_abs_Y() {
|
||||
return memread8(addr_abs_Y());
|
||||
}
|
||||
static inline uint8_t * dest_abs_Y() {
|
||||
INLINE uint8_t * dest_abs_Y() {
|
||||
return & RAM[ addr_abs_Y() ];
|
||||
}
|
||||
|
||||
static inline uint16_t imm() {
|
||||
INLINE uint16_t imm() {
|
||||
return fetch();
|
||||
}
|
||||
|
||||
@ -268,20 +276,22 @@ static inline uint16_t imm() {
|
||||
zpg .... zeropage OPC $LL
|
||||
operand is zeropage address (hi-byte is zero, address = $00LL)
|
||||
**/
|
||||
static inline uint8_t addr_zp() {
|
||||
INLINE uint8_t addr_zp() {
|
||||
dbgPrintf("zp:%02X(%02X) ", RAM[m6502.PC], RAM[ RAM[m6502.PC]] );
|
||||
return fetch();
|
||||
}
|
||||
static inline uint8_t src_zp() {
|
||||
INLINE uint8_t src_zp() {
|
||||
return memread_zp(addr_zp());
|
||||
}
|
||||
static inline uint8_t * dest_zp() {
|
||||
INLINE uint8_t * dest_zp() {
|
||||
return & RAM[ addr_zp() ];
|
||||
}
|
||||
|
||||
/**
|
||||
get a 16 bit address from the zp:zp+1
|
||||
**/
|
||||
static inline uint16_t addr_zp_ind( uint8_t addr ) {
|
||||
INLINE uint16_t addr_zp_ind( uint8_t addr ) {
|
||||
dbgPrintf("zpi:%02X:%04X(%02X) ", RAM[m6502.PC], *((uint16_t*)&RAM[m6502.PC]), RAM[*((uint16_t*)&RAM[m6502.PC])]);
|
||||
return memread16(addr);
|
||||
}
|
||||
|
||||
@ -290,13 +300,14 @@ static inline uint16_t addr_zp_ind( uint8_t addr ) {
|
||||
operand is zeropage address;
|
||||
effective address is word in (LL + X, LL + X + 1), inc. without carry: C.w($00LL + X)
|
||||
**/
|
||||
static inline uint16_t addr_X_ind() {
|
||||
INLINE uint16_t addr_X_ind() {
|
||||
dbgPrintf("zpXi:%02X:%04X(%02X) ", RAM[m6502.PC], *((uint16_t*)&RAM[m6502.PC]) + m6502.X, RAM[*((uint16_t*)&RAM[m6502.PC]) + m6502.X]);
|
||||
return addr_zp_ind( addr_zp() + m6502.X );
|
||||
}
|
||||
static inline uint8_t src_X_ind() {
|
||||
INLINE uint8_t src_X_ind() {
|
||||
return memread8( addr_X_ind() );
|
||||
}
|
||||
static inline uint8_t * dest_X_ind() {
|
||||
INLINE uint8_t * dest_X_ind() {
|
||||
return & RAM[ addr_X_ind() ];
|
||||
}
|
||||
|
||||
@ -305,15 +316,15 @@ static inline uint8_t * dest_X_ind() {
|
||||
operand is zeropage address;
|
||||
effective address is word in (LL, LL + 1) incremented by Y with carry: C.w($00LL) + Y
|
||||
**/
|
||||
static inline uint16_t addr_ind_Y() {
|
||||
INLINE uint16_t addr_ind_Y() {
|
||||
// uint8_t a = fetch();
|
||||
// dbgPrintf("addr_ind_Y: %04X + %02X = %04X ", addr_zpg_ind( a ), m6502.Y, addr_zpg_ind( a ) + m6502.Y);
|
||||
return addr_zp_ind( addr_zp() ) + m6502.Y;
|
||||
}
|
||||
static inline uint8_t src_ind_Y() {
|
||||
INLINE uint8_t src_ind_Y() {
|
||||
return memread8( addr_ind_Y() );
|
||||
}
|
||||
static inline uint8_t * dest_ind_Y() {
|
||||
INLINE uint8_t * dest_ind_Y() {
|
||||
return & RAM[ addr_ind_Y() ];
|
||||
}
|
||||
|
||||
@ -322,13 +333,13 @@ static inline uint8_t * dest_ind_Y() {
|
||||
operand is zeropage address;
|
||||
effective address is address incremented by X without carry **
|
||||
**/
|
||||
static inline uint8_t addr_zp_X() {
|
||||
INLINE uint8_t addr_zp_X() {
|
||||
return addr_zp() + m6502.X;
|
||||
}
|
||||
static inline uint8_t src_zp_X() {
|
||||
INLINE uint8_t src_zp_X() {
|
||||
return memread_zp(addr_zp_X());
|
||||
}
|
||||
static inline uint8_t * dest_zp_X() {
|
||||
INLINE uint8_t * dest_zp_X() {
|
||||
return & RAM[ addr_zp_X() ];
|
||||
}
|
||||
|
||||
@ -337,13 +348,13 @@ static inline uint8_t * dest_zp_X() {
|
||||
operand is zeropage address;
|
||||
effective address is address incremented by Y without carry **
|
||||
**/
|
||||
static inline uint8_t addr_zp_Y() {
|
||||
INLINE uint8_t addr_zp_Y() {
|
||||
return addr_zp() + m6502.Y;
|
||||
}
|
||||
static inline uint8_t src_zp_Y() {
|
||||
INLINE uint8_t src_zp_Y() {
|
||||
return memread_zp(addr_zp_Y());
|
||||
}
|
||||
static inline uint8_t * dest_zp_Y() {
|
||||
INLINE uint8_t * dest_zp_Y() {
|
||||
return & RAM[ addr_zp_Y() ];
|
||||
}
|
||||
|
||||
|
@ -71,7 +71,7 @@ typedef union address16_u {
|
||||
} address16_t;
|
||||
|
||||
|
||||
static inline uint8_t ioRead( uint16_t addr ) {
|
||||
INLINE uint8_t ioRead( uint16_t addr ) {
|
||||
// printf("mmio:%04X\n", addr);
|
||||
|
||||
// C0xx
|
||||
@ -362,7 +362,7 @@ static inline uint8_t ioRead( uint16_t addr ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void ioWrite( uint16_t addr ) {
|
||||
INLINE void ioWrite( uint16_t addr ) {
|
||||
// printf("mmio:%04X\n", addr);
|
||||
switch (addr) {
|
||||
case io_KBD:
|
||||
@ -378,11 +378,11 @@ static inline void ioWrite( uint16_t addr ) {
|
||||
Naive implementation of RAM read from address
|
||||
**/
|
||||
|
||||
static inline uint8_t memread_zp( uint8_t addr ) {
|
||||
INLINE uint8_t memread_zp( uint8_t addr ) {
|
||||
return RAM[ addr ];
|
||||
}
|
||||
|
||||
static inline uint8_t memread( uint16_t addr ) {
|
||||
INLINE uint8_t memread( uint16_t addr ) {
|
||||
// switch ( ((address16_t)addr).page ) {
|
||||
// case 0xC0:
|
||||
// case 0xC1:
|
||||
@ -416,7 +416,7 @@ static inline uint8_t memread( uint16_t addr ) {
|
||||
/**
|
||||
Naive implementation of RAM read from address
|
||||
**/
|
||||
static inline uint16_t memread16( uint16_t addr ) {
|
||||
INLINE uint16_t memread16( uint16_t addr ) {
|
||||
// if ( ( addr >= 0xC000 ) && ( addr < 0xD000 ) ) {
|
||||
// return mmioRead(addr);
|
||||
// }
|
||||
@ -428,7 +428,7 @@ static inline uint16_t memread16( uint16_t addr ) {
|
||||
/**
|
||||
Naive implementation of RAM read from address
|
||||
**/
|
||||
//static inline uint16_t memioread16( uint16_t addr ) {
|
||||
//INLINE uint16_t memioread16( uint16_t addr ) {
|
||||
// return (uint16_t)mmio_read[ addr ](addr);
|
||||
//}
|
||||
|
||||
@ -462,7 +462,7 @@ static void memwrite( uint16_t addr, uint8_t byte ) {
|
||||
Fetching 1 byte from memory address pc (program counter)
|
||||
increase pc by one
|
||||
**/
|
||||
static inline uint8_t fetch() {
|
||||
INLINE uint8_t fetch() {
|
||||
dbgPrintf("%02X ", RAM[m6502.pc]);
|
||||
return memread( m6502.pc++ );
|
||||
}
|
||||
@ -471,7 +471,7 @@ static inline uint8_t fetch() {
|
||||
Fetching 2 bytes as a 16 bit number from memory address pc (program counter)
|
||||
increase pc by one
|
||||
**/
|
||||
static inline uint16_t fetch16() {
|
||||
INLINE uint16_t fetch16() {
|
||||
dbgPrintf("%04X ", memread16(m6502.pc));
|
||||
uint16_t word = memread16( m6502.pc );
|
||||
m6502.pc += 2;
|
||||
@ -481,7 +481,7 @@ static inline uint16_t fetch16() {
|
||||
/**
|
||||
get a 16 bit address from the zp:zp+1
|
||||
**/
|
||||
static inline uint16_t addr_zp_ind( uint8_t addr ) {
|
||||
INLINE uint16_t addr_zp_ind( uint8_t addr ) {
|
||||
return memread16(addr);
|
||||
}
|
||||
|
||||
@ -490,13 +490,13 @@ static inline uint16_t addr_zp_ind( uint8_t addr ) {
|
||||
operand is zeropage address;
|
||||
effective address is word in (LL + X, LL + X + 1), inc. without carry: C.w($00LL + X)
|
||||
**/
|
||||
static inline uint16_t addr_X_ind() {
|
||||
INLINE uint16_t addr_X_ind() {
|
||||
return addr_zp_ind( fetch() + m6502.X );
|
||||
}
|
||||
static inline uint8_t src_X_ind() {
|
||||
INLINE uint8_t src_X_ind() {
|
||||
return memread( addr_X_ind() );
|
||||
}
|
||||
static inline uint8_t * dest_X_ind() {
|
||||
INLINE uint8_t * dest_X_ind() {
|
||||
return & RAM[ addr_X_ind() ];
|
||||
}
|
||||
|
||||
@ -505,7 +505,7 @@ static inline uint8_t * dest_X_ind() {
|
||||
operand is zeropage address;
|
||||
effective address is word in (LL, LL + 1) incremented by Y with carry: C.w($00LL) + Y
|
||||
**/
|
||||
static inline uint16_t addr_ind_Y() {
|
||||
INLINE uint16_t addr_ind_Y() {
|
||||
uint8_t a = fetch();
|
||||
// dbgPrintf("addr_ind_Y: %04X + %02X = %04X ", addr_zpg_ind( a ), m6502.Y, addr_zpg_ind( a ) + m6502.Y);
|
||||
return addr_zp_ind( a ) + m6502.Y;
|
||||
@ -515,18 +515,18 @@ static inline uint16_t addr_ind_Y() {
|
||||
abs,X .... absolute, X-indexed OPC $LLHH,X
|
||||
operand is address; effective address is address incremented by X with carry **
|
||||
**/
|
||||
static inline uint16_t addr_abs_X() {
|
||||
INLINE uint16_t addr_abs_X() {
|
||||
return fetch16() + m6502.X;
|
||||
}
|
||||
static inline uint8_t src_abs_X() {
|
||||
INLINE uint8_t src_abs_X() {
|
||||
return memread( addr_abs_X() );
|
||||
}
|
||||
static inline uint8_t * dest_abs_X() {
|
||||
INLINE uint8_t * dest_abs_X() {
|
||||
return & RAM[ addr_abs_X() ];
|
||||
}
|
||||
|
||||
|
||||
static inline uint16_t abs_addr() {
|
||||
INLINE uint16_t abs_addr() {
|
||||
return fetch16();
|
||||
}
|
||||
|
||||
@ -534,13 +534,13 @@ static inline uint16_t abs_addr() {
|
||||
abs,Y .... absolute, Y-indexed OPC $LLHH,Y
|
||||
operand is address; effective address is address incremented by Y with carry **
|
||||
**/
|
||||
static inline uint16_t addr_abs_Y() {
|
||||
INLINE uint16_t addr_abs_Y() {
|
||||
return fetch16() + m6502.Y;
|
||||
}
|
||||
static inline uint8_t src_abs_Y() {
|
||||
INLINE uint8_t src_abs_Y() {
|
||||
return memread(addr_abs_Y());
|
||||
}
|
||||
static inline uint8_t * dest_abs_Y() {
|
||||
INLINE uint8_t * dest_abs_Y() {
|
||||
return & RAM[ addr_abs_Y() ];
|
||||
}
|
||||
|
||||
@ -548,13 +548,13 @@ static inline uint8_t * dest_abs_Y() {
|
||||
zpg .... zeropage OPC $LL
|
||||
operand is zeropage address (hi-byte is zero, address = $00LL)
|
||||
**/
|
||||
static inline uint16_t addr_zp() {
|
||||
INLINE uint16_t addr_zp() {
|
||||
return fetch();
|
||||
}
|
||||
static inline uint8_t src_zp() {
|
||||
INLINE uint8_t src_zp() {
|
||||
return memread_zp(addr_zp());
|
||||
}
|
||||
static inline uint8_t * dest_zp() {
|
||||
INLINE uint8_t * dest_zp() {
|
||||
return & RAM[ addr_zp() ];
|
||||
}
|
||||
|
||||
@ -563,7 +563,7 @@ static inline uint8_t * dest_zp() {
|
||||
operand is zeropage address;
|
||||
effective address is address incremented by X without carry **
|
||||
**/
|
||||
static inline uint16_t addr_zp_X() {
|
||||
INLINE uint16_t addr_zp_X() {
|
||||
return addr_zp() + m6502.X;
|
||||
}
|
||||
|
||||
@ -572,7 +572,7 @@ static inline uint16_t addr_zp_X() {
|
||||
operand is zeropage address;
|
||||
effective address is address incremented by Y without carry **
|
||||
**/
|
||||
static inline uint16_t addr_zp_Y() {
|
||||
INLINE uint16_t addr_zp_Y() {
|
||||
return addr_zp() + m6502.Y;
|
||||
}
|
||||
|
||||
|
@ -714,7 +714,7 @@
|
||||
<constraint firstAttribute="width" constant="700" id="YGY-gy-pSn"/>
|
||||
<constraint firstAttribute="height" constant="420" id="dWL-EL-ab7"/>
|
||||
</constraints>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" enabled="NO" allowsUndo="NO" sendsActionOnEndEditing="YES" state="on" borderStyle="border" alignment="center" placeholderString="Apple ][ Emulator Virtual Monitor" drawsBackground="YES" id="5AO-Gd-Lzo">
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" enabled="NO" allowsUndo="NO" sendsActionOnEndEditing="YES" state="on" borderStyle="border" alignment="justified" placeholderString="Apple ][ Emulator Virtual Monitor" drawsBackground="YES" id="5AO-Gd-Lzo">
|
||||
<font key="font" size="14" name="Courier-Bold"/>
|
||||
<color key="textColor" name="systemGreenColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" red="0.12549019607843137" green="0.17933968321917809" blue="0.12549019607843137" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
|
66
A2Mac/RepeatingTimer.swift
Normal file
66
A2Mac/RepeatingTimer.swift
Normal file
@ -0,0 +1,66 @@
|
||||
//
|
||||
// RepeatingTimer.swift
|
||||
// A2Mac
|
||||
//
|
||||
// Created by Tamas Rudnai on 9/15/19.
|
||||
// Copyright © 2019 GameAlloy. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
/// RepeatingTimer mimics the API of DispatchSourceTimer but in a way that prevents
|
||||
/// crashes that occur from calling resume multiple times on a timer that is
|
||||
/// already resumed (noted by https://github.com/SiftScience/sift-ios/issues/52
|
||||
class RepeatingTimer {
|
||||
|
||||
let timeInterval: TimeInterval
|
||||
var eventHandler: (() -> Void)?
|
||||
|
||||
private enum State {
|
||||
case suspended
|
||||
case resumed
|
||||
}
|
||||
|
||||
private var state: State = .suspended
|
||||
|
||||
init(timeInterval: TimeInterval) {
|
||||
self.timeInterval = timeInterval
|
||||
}
|
||||
|
||||
private lazy var timer: DispatchSourceTimer = {
|
||||
let t = DispatchSource.makeTimerSource()
|
||||
t.schedule(deadline: .now() + self.timeInterval, repeating: self.timeInterval)
|
||||
t.setEventHandler(handler: { [weak self] in
|
||||
self?.eventHandler?()
|
||||
})
|
||||
return t
|
||||
}()
|
||||
|
||||
|
||||
deinit {
|
||||
timer.setEventHandler {}
|
||||
timer.cancel()
|
||||
/*
|
||||
If the timer is suspended, calling cancel without resuming
|
||||
triggers a crash. This is documented here https://forums.developer.apple.com/thread/15902
|
||||
*/
|
||||
resume()
|
||||
eventHandler = nil
|
||||
}
|
||||
|
||||
func resume() {
|
||||
if state == .resumed {
|
||||
return
|
||||
}
|
||||
state = .resumed
|
||||
timer.resume()
|
||||
}
|
||||
|
||||
func suspend() {
|
||||
if state == .suspended {
|
||||
return
|
||||
}
|
||||
state = .suspended
|
||||
timer.suspend()
|
||||
}
|
||||
}
|
@ -39,7 +39,9 @@ class ViewController: NSViewController {
|
||||
}
|
||||
else {
|
||||
workItem = DispatchWorkItem {
|
||||
DispatchQueue.global(qos: .userInitiated).async {
|
||||
// DispatchQueue.global(qos: .userInteractive).async {
|
||||
// DispatchQueue.global(qos: .userInitiated).async {
|
||||
DispatchQueue.global(qos: .background).async {
|
||||
tst6502()
|
||||
}
|
||||
}
|
||||
@ -62,75 +64,83 @@ class ViewController: NSViewController {
|
||||
|
||||
|
||||
override func keyDown(with event: NSEvent) {
|
||||
switch event.modifierFlags.intersection(.deviceIndependentFlagsMask) {
|
||||
case [.command] where event.characters == "l",
|
||||
[.command, .shift] where event.characters == "l":
|
||||
print("command-l or command-shift-l")
|
||||
default:
|
||||
break
|
||||
}
|
||||
print( "key = " + (event.charactersIgnoringModifiers ?? ""))
|
||||
print( "\ncharacter = " + (event.characters ?? ""))
|
||||
// switch event.modifierFlags.intersection(.deviceIndependentFlagsMask) {
|
||||
// case [.command] where event.characters == "l",
|
||||
// [.command, .shift] where event.characters == "l":
|
||||
// print("command-l or command-shift-l")
|
||||
// default:
|
||||
// break
|
||||
// }
|
||||
// print( "key = " + (event.charactersIgnoringModifiers ?? ""))
|
||||
// print( "\ncharacter = " + (event.characters ?? ""))
|
||||
|
||||
#if FUNCTIONTEST
|
||||
#else
|
||||
if let chars = event.characters {
|
||||
let char = chars.uppercased()[chars.startIndex]
|
||||
if let code = char.asciiValue {
|
||||
var A2code = code | 0x80
|
||||
|
||||
if ( code == 13 ) {
|
||||
switch ( code ) {
|
||||
case 13:
|
||||
A2code = 141
|
||||
break
|
||||
|
||||
default:
|
||||
break
|
||||
}
|
||||
print("keycode: \(code) --> \(A2code)")
|
||||
|
||||
let resetPointer = UnsafeMutableRawBufferPointer(start: &RAM + 0xC000, count: 1)
|
||||
resetPointer[0] = A2code
|
||||
let kbdPointer = UnsafeMutableRawBufferPointer(start: &RAM + 0xC000, count: 1)
|
||||
kbdPointer[0] = A2code
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
override func flagsChanged(with event: NSEvent) {
|
||||
switch event.modifierFlags.intersection(.deviceIndependentFlagsMask) {
|
||||
case [.shift]:
|
||||
print("shift key is pressed")
|
||||
case [.control]:
|
||||
print("control key is pressed")
|
||||
case [.option] :
|
||||
print("option key is pressed")
|
||||
case [.command]:
|
||||
print("Command key is pressed")
|
||||
case [.control, .shift]:
|
||||
print("control-shift keys are pressed")
|
||||
case [.option, .shift]:
|
||||
print("option-shift keys are pressed")
|
||||
case [.command, .shift]:
|
||||
print("command-shift keys are pressed")
|
||||
case [.control, .option]:
|
||||
print("control-option keys are pressed")
|
||||
case [.control, .command]:
|
||||
print("control-command keys are pressed")
|
||||
case [.option, .command]:
|
||||
print("option-command keys are pressed")
|
||||
case [.shift, .control, .option]:
|
||||
print("shift-control-option keys are pressed")
|
||||
case [.shift, .control, .command]:
|
||||
print("shift-control-command keys are pressed")
|
||||
case [.control, .option, .command]:
|
||||
print("control-option-command keys are pressed")
|
||||
case [.shift, .command, .option]:
|
||||
print("shift-command-option keys are pressed")
|
||||
case [.shift, .control, .option, .command]:
|
||||
print("shift-control-option-command keys are pressed")
|
||||
default:
|
||||
print("no modifier keys are pressed")
|
||||
}
|
||||
// switch event.modifierFlags.intersection(.deviceIndependentFlagsMask) {
|
||||
// case [.shift]:
|
||||
// print("shift key is pressed")
|
||||
// case [.control]:
|
||||
// print("control key is pressed")
|
||||
// case [.option] :
|
||||
// print("option key is pressed")
|
||||
// case [.command]:
|
||||
// print("Command key is pressed")
|
||||
// case [.control, .shift]:
|
||||
// print("control-shift keys are pressed")
|
||||
// case [.option, .shift]:
|
||||
// print("option-shift keys are pressed")
|
||||
// case [.command, .shift]:
|
||||
// print("command-shift keys are pressed")
|
||||
// case [.control, .option]:
|
||||
// print("control-option keys are pressed")
|
||||
// case [.control, .command]:
|
||||
// print("control-command keys are pressed")
|
||||
// case [.option, .command]:
|
||||
// print("option-command keys are pressed")
|
||||
// case [.shift, .control, .option]:
|
||||
// print("shift-control-option keys are pressed")
|
||||
// case [.shift, .control, .command]:
|
||||
// print("shift-control-command keys are pressed")
|
||||
// case [.control, .option, .command]:
|
||||
// print("control-option-command keys are pressed")
|
||||
// case [.shift, .command, .option]:
|
||||
// print("shift-command-option keys are pressed")
|
||||
// case [.shift, .control, .option, .command]:
|
||||
// print("shift-control-option-command keys are pressed")
|
||||
// default:
|
||||
// print("no modifier keys are pressed")
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
func update() {
|
||||
|
||||
while true {
|
||||
usleep(33333) // 1/30 sec
|
||||
// while true {
|
||||
// usleep(33333) // 1/30 sec
|
||||
|
||||
let textBaseAddr = 0x400
|
||||
let textLines = 24
|
||||
@ -142,28 +152,24 @@ class ViewController: NSViewController {
|
||||
let textAddr = textBaseAddr + textLineOfs[y]
|
||||
let textBufferPointer = UnsafeRawBufferPointer(start: &RAM + textAddr, count: textCols)
|
||||
|
||||
for (index, byte) in textBufferPointer.enumerated() {
|
||||
for (_, byte) in textBufferPointer.enumerated() {
|
||||
let idx = Int(byte);
|
||||
let chr = ViewController.charConvTbl[idx]
|
||||
// print("byte \(index): \(chr)")
|
||||
txt = txt + " \(chr)"
|
||||
txt = txt + "\(chr)"
|
||||
}
|
||||
|
||||
txt = txt + " |\n"
|
||||
txt = txt + "\n"
|
||||
}
|
||||
|
||||
|
||||
DispatchQueue.main.async {
|
||||
self.display.stringValue = txt;
|
||||
}
|
||||
}
|
||||
// }
|
||||
|
||||
// DispatchQueue.main.asyncAfter(deadline: .now() + 1/30, execute: {
|
||||
// self.update()
|
||||
// })
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
// func FromBuf(ptr: UnsafeMutablePointer<UInt8>, length len: Int) -> String? {
|
||||
// // convert the bytes using the UTF8 encoding
|
||||
@ -174,17 +180,27 @@ class ViewController: NSViewController {
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
let upd = RepeatingTimer(timeInterval: 1/30)
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
// DispatchQueue.main.asyncAfter(deadline: .now() + 1/30, execute: {
|
||||
// self.update()
|
||||
// })
|
||||
|
||||
#if FUNCTIONTEST
|
||||
#else
|
||||
// DispatchQueue.global(qos: .background).async {
|
||||
// self.update()
|
||||
// }
|
||||
|
||||
DispatchQueue.global(qos: .background).async {
|
||||
upd.eventHandler = {
|
||||
self.update()
|
||||
}
|
||||
|
||||
upd.resume()
|
||||
#endif
|
||||
}
|
||||
|
||||
override var representedObject: Any? {
|
||||
|
@ -41,50 +41,50 @@ union {
|
||||
|
||||
#define BITTEST(n,x) ((bits_t)(n)).b##x
|
||||
|
||||
static inline void set_flags_N( const uint8_t test ) {
|
||||
m6502.flags.N = BITTEST(test, 7);
|
||||
dbgPrintf("%c", m6502.flags.N ? 'N' : 'n');
|
||||
INLINE void set_flags_N( const uint8_t test ) {
|
||||
m6502.N = BITTEST(test, 7);
|
||||
dbgPrintf("%c", m6502.N ? 'N' : 'n');
|
||||
}
|
||||
|
||||
static inline void set_flags_V( const uint8_t test ) {
|
||||
m6502.flags.V = BITTEST(test, 6);
|
||||
dbgPrintf("%c", m6502.flags.V ? 'V' : 'v');
|
||||
INLINE void set_flags_V( const uint8_t test ) {
|
||||
m6502.V = BITTEST(test, 6);
|
||||
dbgPrintf( |