- Unified inline

- "breakpoints" for debugging
- BugFixes
This commit is contained in:
Tamas Rudnai 2019-09-15 04:02:22 -07:00
parent f2e5b49a6e
commit 26c413df6b
21 changed files with 600 additions and 392 deletions

View File

@ -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;
};

View File

@ -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[]) {

View File

@ -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;

View File

@ -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() ];
}

View File

@ -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;
}

View File

@ -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"/>

View 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()
}
}

View File

@ -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? {

View File

@ -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(