mirror of
https://github.com/trudnai/Steve2.git
synced 2025-01-21 21:32:51 +00:00
- WOZ Disk initial Try
- HiRes support - Reset Vector fixes - ROM read from file - Better MMIO Handling - BugFixes - Shader Metal try
This commit is contained in:
parent
1e455a011e
commit
fddb1d9642
@ -84,7 +84,10 @@
|
||||
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>"; };
|
||||
326C50802383CC0B00A05420 /* woz.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = woz.h; sourceTree = "<group>"; };
|
||||
326ED2EE232D7A0000A41337 /* 6502_functional_test.bin */ = {isa = PBXFileReference; lastKnownFileType = archive.macbinary; path = 6502_functional_test.bin; sourceTree = SOURCE_ROOT; };
|
||||
32B18435233F10BC00DBB4AB /* Shaders.metal */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.metal; path = Shaders.metal; sourceTree = "<group>"; };
|
||||
32B18438233FAB3900DBB4AB /* verticies.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = verticies.swift; sourceTree = "<group>"; };
|
||||
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>"; };
|
||||
@ -204,11 +207,13 @@
|
||||
32DBF76723373FB400DD50E7 /* disassembler.h */,
|
||||
32439F8422ECD8AD0077AAE0 /* apple.rom */,
|
||||
326ED2EE232D7A0000A41337 /* 6502_functional_test.bin */,
|
||||
32B18438233FAB3900DBB4AB /* verticies.swift */,
|
||||
32439F7322ECD8AD0077AAE0 /* Apple2_mmio.h */,
|
||||
3264261023284F6F008B615F /* Apple2_mmio_8bit_ioaddr.h */,
|
||||
32439F8622ECD8AD0077AAE0 /* common.h */,
|
||||
32BFFB5A22EACC630003B53F /* AppDelegate.swift */,
|
||||
32BFFB5C22EACC630003B53F /* ViewController.swift */,
|
||||
32B18435233F10BC00DBB4AB /* Shaders.metal */,
|
||||
32C4532D233345420000EBA1 /* MonitorView.swift */,
|
||||
32DBF7632334657900DD50E7 /* HiRes.swift */,
|
||||
32C453072331C0910000EBA1 /* NSLayoutManager-Extension.swift */,
|
||||
@ -219,6 +224,7 @@
|
||||
32BFFB6322EACC660003B53F /* Info.plist */,
|
||||
32BFFB6422EACC660003B53F /* A2Mac.entitlements */,
|
||||
32439F7222ECD8AC0077AAE0 /* A2Mac-Bridging-Header.h */,
|
||||
326C50802383CC0B00A05420 /* woz.h */,
|
||||
);
|
||||
path = A2Mac;
|
||||
sourceTree = "<group>";
|
||||
@ -338,7 +344,7 @@
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastSwiftUpdateCheck = 1020;
|
||||
LastUpgradeCheck = 1020;
|
||||
LastUpgradeCheck = 1100;
|
||||
ORGANIZATIONNAME = GameAlloy;
|
||||
TargetAttributes = {
|
||||
32BFFB5622EACC630003B53F = {
|
||||
@ -634,6 +640,7 @@
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = A2Mac/A2Mac.entitlements;
|
||||
CODE_SIGN_IDENTITY = "-";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
DEVELOPMENT_TEAM = W6TFQTZ4DA;
|
||||
@ -643,8 +650,11 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
OTHER_CFLAGS = "";
|
||||
OTHER_SWIFT_FLAGS = "";
|
||||
OTHER_CFLAGS = (
|
||||
"-DDISASSEMBLER",
|
||||
"-DINTERRUPR_CHECK_PER_STEP",
|
||||
);
|
||||
OTHER_SWIFT_FLAGS = "-D_NO_HIRES -D_NO_HIRESDRAW -D_NO_HIRESLOW";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.gamealloy.A2Mac;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||
@ -660,6 +670,7 @@
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = A2Mac/A2Mac.entitlements;
|
||||
CODE_SIGN_IDENTITY = "-";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
DEVELOPMENT_TEAM = W6TFQTZ4DA;
|
||||
@ -670,7 +681,11 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
OTHER_CFLAGS = "";
|
||||
OTHER_CFLAGS = (
|
||||
"-DDISASSEMBLER",
|
||||
"-DINTERRUPR_CHECK_PER_STEP",
|
||||
);
|
||||
OTHER_SWIFT_FLAGS = "-D_NO_HIRES -D_NO_HIRESDRAW -D_NO_HIRESLOW";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.gamealloy.A2Mac;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "A2Mac/A2Mac-Bridging-Header.h";
|
||||
@ -766,6 +781,7 @@
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = A2Mac/A2Mac.entitlements;
|
||||
CODE_SIGN_IDENTITY = "-";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
DEVELOPMENT_TEAM = W6TFQTZ4DA;
|
||||
@ -792,6 +808,7 @@
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = A2Mac/A2Mac.entitlements;
|
||||
CODE_SIGN_IDENTITY = "-";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
DEVELOPMENT_TEAM = W6TFQTZ4DA;
|
||||
@ -817,6 +834,7 @@
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = A2Mac/A2Mac.entitlements;
|
||||
CODE_SIGN_IDENTITY = "-";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
DEVELOPMENT_TEAM = W6TFQTZ4DA;
|
||||
@ -843,6 +861,7 @@
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = A2Mac/A2Mac.entitlements;
|
||||
CODE_SIGN_IDENTITY = "-";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
DEVELOPMENT_TEAM = W6TFQTZ4DA;
|
||||
|
264
A2Mac/6502.c
264
A2Mac/6502.c
@ -12,6 +12,21 @@
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include "woz.h"
|
||||
|
||||
#define WOZ1_MAGIC 0x315A4F57
|
||||
#define WOZ2_MAGIC 0x325A4F57
|
||||
#define WOZ_INFO_CHUNK_ID 0x4F464E49
|
||||
#define WOZ_TMAP_CHUNK_ID 0x50414D54
|
||||
#define WOZ_TRKS_CHUNK_ID 0x534B5254
|
||||
#define WOZ_META_CHUNK_ID 0x4154454D
|
||||
|
||||
woz_header_t woz_header;
|
||||
woz_chunk_header_t woz_chunk_header;
|
||||
woz_tmap_t woz_tmap;
|
||||
woz_trks_t woz_trks;
|
||||
|
||||
uint16_t trackOffset = 0;
|
||||
|
||||
#ifdef DEBUG
|
||||
#define INLINE
|
||||
@ -28,7 +43,7 @@
|
||||
#define RESET_VECTOR 0xFFFC
|
||||
#define IRQ_VECTOR 0xFFFE
|
||||
|
||||
const unsigned long long int iterations = 100*G;
|
||||
const unsigned long long int iterations = G;
|
||||
unsigned long long int inst_cnt = 0;
|
||||
|
||||
const unsigned int fps = 30;
|
||||
@ -46,7 +61,24 @@ INLINE unsigned long long rdtsc(void)
|
||||
}
|
||||
|
||||
|
||||
m6502_t m6502 = { 0, 0, 0, 0, 0, 0, 0, NO_DEBUG, HLT };
|
||||
m6502_t m6502 = {
|
||||
0, // A
|
||||
0, // X
|
||||
0, // Y
|
||||
0, // SR
|
||||
0, // PC
|
||||
0, // SP
|
||||
0, // clk
|
||||
0, // trace
|
||||
0, // step
|
||||
0, // brk
|
||||
0, // rts
|
||||
0, // bra
|
||||
0, // bra_true
|
||||
0, // bra_false
|
||||
0, // compile
|
||||
HLT // IF
|
||||
};
|
||||
|
||||
disassembly_t disassembly;
|
||||
|
||||
@ -54,6 +86,62 @@ disassembly_t disassembly;
|
||||
#include "Apple2_mmio.h"
|
||||
|
||||
|
||||
uint16_t videoShadow [0x1000];
|
||||
uint32_t videoMem [0x2000];
|
||||
uint32_t * videoMemPtr = videoMem;
|
||||
|
||||
uint16_t HiResLineAddrTbl [0x2000];
|
||||
|
||||
void initHiResLineAddresses() {
|
||||
uint16_t i = 0;
|
||||
for ( uint16_t x = 0; x <= 0x50; x+= 0x28 ) {
|
||||
for ( uint16_t y = 0; y <= 0x380; y += 0x80 ) {
|
||||
for ( uint16_t z = 0; z <= 0x1C00; z += 0x400) {
|
||||
HiResLineAddrTbl[i++] = x + y + z;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
typedef struct {
|
||||
uint8_t L;
|
||||
uint8_t H;
|
||||
} bytes_t;
|
||||
|
||||
void hires_Update () {
|
||||
// lines
|
||||
int videoMemIndex = 0;
|
||||
for( int y = 0; y < 192; y++ ) {
|
||||
// 16 bit blocks of columns
|
||||
for ( int x = 0; x < 20; x++ ) {
|
||||
// odd
|
||||
bytes_t block = * (bytes_t*)(& RAM[ HiResLineAddrTbl[y * 20] + x * 2 ]);
|
||||
for ( uint8_t bit = 0; bit < 7; bit++ ) {
|
||||
uint8_t bitMask = 1 << bit;
|
||||
|
||||
if (block.L & bitMask) {
|
||||
videoMem[videoMemIndex++] = 0x7F12A208;
|
||||
}
|
||||
else { // 28CD41
|
||||
videoMem[videoMemIndex++] = 0x00000000;
|
||||
}
|
||||
}
|
||||
// even
|
||||
for ( uint8_t bit = 0; bit < 7; bit++ ) {
|
||||
uint8_t bitMask = 1 << bit;
|
||||
|
||||
if (block.H & bitMask) {
|
||||
videoMem[videoMemIndex++] = 0x7F12A208;
|
||||
}
|
||||
else { // 28CD41
|
||||
videoMem[videoMemIndex++] = 0x00000000;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Instruction Implementations
|
||||
!!!! `his has to be here!!!
|
||||
@ -63,12 +151,28 @@ disassembly_t disassembly;
|
||||
#include "6502_instructions.h"
|
||||
|
||||
/////
|
||||
#ifdef SPEEDTEST
|
||||
unsigned long long int clktime = 0;
|
||||
|
||||
#endif
|
||||
|
||||
INLINE int m6502_Step() {
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
#ifdef DEBUG___
|
||||
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");
|
||||
@ -539,7 +643,7 @@ INLINE int m6502_Step() {
|
||||
// case 0xFF:
|
||||
|
||||
default:
|
||||
printf("%04X: Unimplemented Instruction 0x%02X\n", m6502.PC -1, memread( m6502.PC -1 ));
|
||||
dbgPrintf("%04X: Unimplemented Instruction 0x%02X\n", m6502.PC -1, memread( m6502.PC -1 ));
|
||||
return 2;
|
||||
}
|
||||
// } // fetch16
|
||||
@ -558,8 +662,8 @@ double mhz = 0;
|
||||
unsigned long long epoch = 0;
|
||||
|
||||
void m6502_Run() {
|
||||
unsigned int clk = 0;
|
||||
unsigned int clkfrm = 0;
|
||||
static unsigned int clk = 0;
|
||||
static unsigned int clkfrm = 0;
|
||||
|
||||
// init time
|
||||
//#ifdef CLK_WAIT
|
||||
@ -567,28 +671,52 @@ void m6502_Run() {
|
||||
//#endif
|
||||
|
||||
#ifdef SPEEDTEST
|
||||
for ( unsigned long long int i = 0; i < iterations ; i++ )
|
||||
for ( inst_cnt = 0; inst_cnt < iterations ; inst_cnt++ )
|
||||
#elif defined( CLK_WAIT )
|
||||
for ( clkfrm = 0; clkfrm < clk_6502_per_frm ; clkfrm += clk )
|
||||
for ( clkfrm = 0; clkfrm < clk_6502_per_frm ; clkfrm += clk )
|
||||
#else
|
||||
// for ( ; m6502.pc ; )
|
||||
for ( ; ; )
|
||||
#endif
|
||||
{
|
||||
|
||||
#ifdef INTERRUPR_CHECK_PER_STEP
|
||||
if ( m6502.IF ) {
|
||||
switch (m6502.interrupt) {
|
||||
case HLT:
|
||||
// CPU is haletd, nothing to do here...
|
||||
return;
|
||||
|
||||
case IRQ:
|
||||
m6502.PC = memread16(IRQ_VECTOR);
|
||||
// TODO: PUSH things onto stack?
|
||||
break;
|
||||
|
||||
case NMI:
|
||||
m6502.PC = memread16(NMI_VECTOR);
|
||||
// TODO: PUSH things onto stack?
|
||||
break;
|
||||
|
||||
case 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
|
||||
m6502.SR = 0x25;
|
||||
|
||||
break;
|
||||
|
||||
case SOFTRESET:
|
||||
m6502.PC = memread16(SOFTRESET_VECTOR);
|
||||
// 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
|
||||
m6502.SR = 0x25;
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -597,12 +725,16 @@ void m6502_Run() {
|
||||
|
||||
m6502.IF = 0;
|
||||
}
|
||||
|
||||
dbgPrintf("%llu %04X: ", clktime, m6502.PC);
|
||||
clktime += clk = m6502_Step();
|
||||
#endif // INTERRUPR_CHECK_PER_STEP
|
||||
|
||||
// dbgPrintf("%llu %04X: ", clktime, m6502.PC);
|
||||
#ifdef SPEEDTEST
|
||||
clktime +=
|
||||
#endif
|
||||
clk = m6502_Step();
|
||||
printDisassembly();
|
||||
|
||||
dbgPrintf("\nA:%02X X:%02X Y:%02X SP:%02X %c%c%c%c%c%c%c%c\n",
|
||||
dbgPrintf2("A:%02X X:%02X Y:%02X SP:%02X %c%c%c%c%c%c%c%c\n\n",
|
||||
m6502.A,
|
||||
m6502.X,
|
||||
m6502.Y,
|
||||
@ -651,7 +783,82 @@ void m6502_Run() {
|
||||
// mhz = clktime / (execution_time * M);
|
||||
}
|
||||
|
||||
void m6502_Reset() {
|
||||
void read_rom( const char * filename, const uint16_t addr ) {
|
||||
FILE * f = fopen(filename, "rb");
|
||||
if (f == NULL) {
|
||||
perror("Failed: ");
|
||||
return;
|
||||
}
|
||||
|
||||
fseek(f, 0L, SEEK_END);
|
||||
uint16_t flen = ftell(f);
|
||||
fseek(f, 0L, SEEK_SET);
|
||||
|
||||
fread( RAM + addr, 1, flen, f);
|
||||
fclose(f);
|
||||
|
||||
}
|
||||
|
||||
|
||||
void read_woz( const char * filename ) {
|
||||
FILE * f = fopen(filename, "rb");
|
||||
if (f == NULL) {
|
||||
perror("Failed: ");
|
||||
return;
|
||||
}
|
||||
|
||||
fread( &woz_header, 1, sizeof(woz_header_t), f);
|
||||
if ( woz_header.magic != WOZ1_MAGIC ) {
|
||||
return;
|
||||
}
|
||||
|
||||
while ( ! feof(f) ) {
|
||||
// beginning of the chunk, so we can skip it later
|
||||
|
||||
long r = fread( &woz_chunk_header, 1, sizeof(woz_chunk_header_t), f);
|
||||
if ( r != sizeof(woz_chunk_header_t) ) {
|
||||
break;
|
||||
}
|
||||
long foffs = ftell(f);
|
||||
|
||||
void * buf = NULL;
|
||||
|
||||
switch ( woz_chunk_header.magic ) {
|
||||
case WOZ_INFO_CHUNK_ID:
|
||||
break;
|
||||
|
||||
case WOZ_TMAP_CHUNK_ID:
|
||||
buf = &woz_tmap;
|
||||
break;
|
||||
|
||||
case WOZ_TRKS_CHUNK_ID:
|
||||
buf = woz_trks;
|
||||
break;
|
||||
|
||||
case WOZ_META_CHUNK_ID:
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (buf) {
|
||||
r = fread( buf, 1, woz_chunk_header.size, f);
|
||||
if ( r != woz_chunk_header.size ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// make sure we are skipping unhandled chunks correctly
|
||||
fseek(f, foffs + woz_chunk_header.size, SEEK_SET);
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
|
||||
|
||||
}
|
||||
|
||||
void m6502_ColdReset() {
|
||||
inst_cnt = 0;
|
||||
mhz = (double)MHz_6502 / M;
|
||||
|
||||
@ -661,12 +868,12 @@ void m6502_Reset() {
|
||||
tick_per_sec = e - epoch;
|
||||
tick_6502_per_sec = tick_per_sec / MHz_6502;
|
||||
|
||||
memset( RAM, 0xFF, sizeof(RAM) );
|
||||
memset( RAM, 0xFF, sizeof(Apple2_64K_RAM) );
|
||||
memset( RAM + 0xC000, 0, 0x1000 ); // I/O area should be 0
|
||||
|
||||
m6502.A = m6502.X = m6502.Y = 0xFF;
|
||||
// reset vector
|
||||
m6502.SP = 0xFF -3;
|
||||
m6502.SP = 0xFF; //-3;
|
||||
|
||||
// N V - B D I Z C
|
||||
// 0 0 1 1 0 1 0 0
|
||||
@ -690,15 +897,16 @@ void m6502_Reset() {
|
||||
m6502.PC = 0x400;
|
||||
|
||||
#else
|
||||
FILE * f = fopen("/Users/trudnai/Library/Containers/com.gamealloy.A2Mac/Data/Apple2Plus.rom", "rb");
|
||||
if (f == NULL) {
|
||||
perror("Failed: ");
|
||||
return;
|
||||
}
|
||||
// Apple ][e ROM
|
||||
read_rom("/Users/trudnai/Library/Containers/com.gamealloy.A2Mac/Data/Apple2Plus.rom", 0xD000);
|
||||
// Disk ][ ROM in Slot 6
|
||||
// read_rom("/Users/trudnai/Library/Containers/com.gamealloy.A2Mac/Data/DISK_II_C600.ROM", 0xC600);
|
||||
|
||||
fread( RAM + 0xD000, 1, 0x3000, f);
|
||||
fclose(f);
|
||||
// WOZ DISK
|
||||
// read_woz("/Users/trudnai/Library/Containers/com.gamealloy.A2Mac/Data/DOS 3.3 System Master.woz");
|
||||
// read_woz("/Users/trudnai/Library/Containers/com.gamealloy.A2Mac/Data/Hard Hat Mack - Disk 1, Side A.woz");
|
||||
|
||||
|
||||
m6502.PC = memread16( RESET_VECTOR );
|
||||
#endif
|
||||
|
||||
@ -812,22 +1020,24 @@ void tst6502() {
|
||||
// insert code here...
|
||||
printf("6502\n");
|
||||
|
||||
m6502_Reset();
|
||||
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 = clktime / (execution_time * M);
|
||||
printf("clk:%llu Elpased time: (%llu / %u / %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 / %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[]) {
|
||||
|
40
A2Mac/6502.h
40
A2Mac/6502.h
@ -9,7 +9,7 @@
|
||||
#ifndef __6502_H__
|
||||
#define __6502_H__
|
||||
|
||||
#import "stdint.h"
|
||||
#import <stdint.h>
|
||||
|
||||
#ifdef DEBUG
|
||||
//#define dbgPrintf(format, ...) printf (format, ## __VA_ARGS__)
|
||||
@ -23,16 +23,21 @@
|
||||
typedef enum {
|
||||
NO_INT,
|
||||
HLT,
|
||||
IRQ,
|
||||
NMI,
|
||||
HARDRESET,
|
||||
SOFTRESET,
|
||||
} interrupt_t;
|
||||
|
||||
typedef enum {
|
||||
NO_DEBUG,
|
||||
DISASSEMBLY,
|
||||
DEBUGBRK,
|
||||
STEPBYSTEP,
|
||||
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 struct m6502_s {
|
||||
@ -73,25 +78,28 @@ typedef struct m6502_s {
|
||||
|
||||
|
||||
typedef struct disassembly_s {
|
||||
char codeAddr[5]; // 4 digits + \0
|
||||
char hex[4 * 3 + 1]; // max 4 bytes * (2 digits + 1 space) + \0
|
||||
char * pHex;
|
||||
char inst[6 + 1]; // 3 char (unknown instr? -- give it 6 chars) + \0
|
||||
char addr[4 + 2 + 1 + 1 + 1]; // 4 digits + 2 brackets + 1 comma + 1 index + \0
|
||||
char comment[256]; // to be able to add some comments
|
||||
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;
|
||||
|
||||
|
||||
extern m6502_t m6502;
|
||||
extern uint8_t RAM[ 64 * 1024 ];
|
||||
extern uint8_t * RAM;
|
||||
extern uint32_t * videoMemPtr;
|
||||
|
||||
extern void hires_Update(void);
|
||||
|
||||
extern double mips;
|
||||
extern double mhz;
|
||||
extern const unsigned int fps;
|
||||
|
||||
extern void tst6502();
|
||||
extern void m6502_Reset();
|
||||
extern void m6502_Run();
|
||||
extern void tst6502(void);
|
||||
extern void m6502_ColdReset(void);
|
||||
extern void m6502_Run(void);
|
||||
extern void kbdInput ( uint8_t code );
|
||||
|
||||
#endif /* __6502_H__ */
|
||||
|
@ -13,13 +13,44 @@
|
||||
#include "6502.h"
|
||||
|
||||
|
||||
enum mmio {
|
||||
io_KBD = 0xC000,
|
||||
io_KBDSTRB = 0xC010,
|
||||
uint8_t Apple2_64K_RAM[ 64 * KB ] = {0};
|
||||
uint8_t * RAM = Apple2_64K_RAM;
|
||||
|
||||
enum slot {
|
||||
SLOT0 = 0x00,
|
||||
SLOT1 = 0x10,
|
||||
SLOT2 = 0x20,
|
||||
SLOT3 = 0x30,
|
||||
SLOT4 = 0x40,
|
||||
SLOT5 = 0x50,
|
||||
SLOT6 = 0x60,
|
||||
SLOT7 = 0x70,
|
||||
};
|
||||
|
||||
|
||||
uint8_t RAM[ 64 * KB ] = {0};
|
||||
enum mmio {
|
||||
io_KBD = 0xC000,
|
||||
io_KBDSTRB = 0xC010,
|
||||
|
||||
io_DISK_PHASE0_OFF = 0xC080,
|
||||
io_DISK_PHASE0_ON = 0xC081,
|
||||
io_DISK_PHASE1_OFF = 0xC082,
|
||||
io_DISK_PHASE1_ON = 0xC083,
|
||||
io_DISK_PHASE2_OFF = 0xC084,
|
||||
io_DISK_PHASE2_ON = 0xC085,
|
||||
io_DISK_PHASE3_OFF = 0xC086,
|
||||
io_DISK_PHASE3_ON = 0xC087,
|
||||
io_DISK_POWER_OFF = 0xC088,
|
||||
io_DISK_POWER_ON = 0xC089,
|
||||
io_DISK_SELECT_1 = 0xC08A,
|
||||
io_DISK_SELECT_2 = 0xC08B,
|
||||
io_DISK_READ = 0xC08C,
|
||||
io_DISK_WRITE = 0xC08D,
|
||||
io_DISK_CLEAR = 0xC08E,
|
||||
io_DISK_SHIFT = 0xC08F,
|
||||
|
||||
};
|
||||
|
||||
|
||||
#define PAGESIZE 256
|
||||
#define PAGES 16
|
||||
@ -71,8 +102,79 @@ typedef union address16_u {
|
||||
} address16_t;
|
||||
|
||||
|
||||
#define CASE_DISKII(x) \
|
||||
case io_DISK_PHASE0_OFF + SLOT##x: \
|
||||
printf("io_DISK_PHASE0_OFF (S%u)\n", x); \
|
||||
return 0; \
|
||||
case io_DISK_PHASE0_ON + SLOT##x: \
|
||||
printf("io_DISK_PHASE0_ON (S%u)\n", x); \
|
||||
return 0; \
|
||||
case io_DISK_PHASE1_OFF + SLOT##x: \
|
||||
printf("io_DISK_PHASE1_OFF (S%u)\n", x); \
|
||||
return 0; \
|
||||
case io_DISK_PHASE1_ON + SLOT##x: \
|
||||
printf("io_DISK_PHASE1_ON (S%u)\n", x); \
|
||||
return 0; \
|
||||
case io_DISK_PHASE2_OFF + SLOT##x: \
|
||||
printf("io_DISK_PHASE2_OFF (S%u)\n", x); \
|
||||
return 0; \
|
||||
case io_DISK_PHASE2_ON + SLOT##x: \
|
||||
printf("io_DISK_PHASE2_ON (S%u)\n", x); \
|
||||
return 0; \
|
||||
case io_DISK_PHASE3_OFF + SLOT##x: \
|
||||
printf("io_DISK_PHASE3_OFF (S%u)\n", x); \
|
||||
return 0; \
|
||||
case io_DISK_PHASE3_ON + SLOT##x: \
|
||||
printf("io_DISK_PHASE3_ON (S%u)\n", x); \
|
||||
return 0; \
|
||||
case io_DISK_POWER_OFF + SLOT##x: \
|
||||
printf("io_DISK_POWER_OFF (S%u)\n", x); \
|
||||
return 0; \
|
||||
case io_DISK_POWER_ON + SLOT##x: \
|
||||
printf("io_DISK_POWER_ON (S%u)\n", x); \
|
||||
return 0; \
|
||||
case io_DISK_SELECT_1 + SLOT##x: \
|
||||
printf("io_DISK_SELECT_1 (S%u)\n", x); \
|
||||
return 0; \
|
||||
case io_DISK_SELECT_2 + SLOT##x: \
|
||||
printf("io_DISK_SELECT_2 (S%u)\n", x); \
|
||||
return 0; \
|
||||
case io_DISK_READ + SLOT##x: \
|
||||
printf("io_DISK_READ (S%u)\n", x); \
|
||||
return 0; \
|
||||
case io_DISK_WRITE + SLOT##x: \
|
||||
printf("io_DISK_WRITE (S%u)\n", x); \
|
||||
return 0; \
|
||||
case io_DISK_CLEAR + SLOT##x: \
|
||||
printf("io_DISK_CLEAR (S%u)\n", x); \
|
||||
return 0; \
|
||||
case io_DISK_SHIFT + SLOT##x: \
|
||||
printf("io_DISK_SHIFT (S%u)\n", x); \
|
||||
return 0;
|
||||
|
||||
|
||||
static const minDiskPhaseNum = 0;
|
||||
static const maxDiskPhaseNum = 80;
|
||||
static int trackPhase = maxDiskPhaseNum;
|
||||
|
||||
struct phase_t {
|
||||
uint8_t current : 2;
|
||||
uint8_t last : 2;
|
||||
} phase = {0};
|
||||
|
||||
static const int8_t phaseTransition[4][4] = {
|
||||
{ 0, -1, 0, +1 },
|
||||
{ +1, 0, -1, 0 },
|
||||
{ 0, +1, 0, -1 },
|
||||
{ -1, 0, +1, 0 },
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
INLINE uint8_t ioRead( uint16_t addr ) {
|
||||
// printf("mmio read:%04X\n", addr);
|
||||
dbgPrintf("mmio read:%04X\n", addr);
|
||||
|
||||
switch (addr) {
|
||||
case io_KBD:
|
||||
// if ( RAM[io_KBD] > 0x7F ) printf("io_KBD:%04X\n", addr);
|
||||
@ -83,10 +185,68 @@ INLINE uint8_t ioRead( uint16_t addr ) {
|
||||
// printf("io_KBDSTRB\n");
|
||||
return RAM[io_KBD] &= 0x7F;
|
||||
|
||||
// CASE_DISKII(6)
|
||||
|
||||
// TODO: Make code "card insertable to slot" / aka slot independent and dynamically add/remove
|
||||
case io_DISK_PHASE0_OFF + SLOT6:
|
||||
case io_DISK_PHASE1_OFF + SLOT6:
|
||||
case io_DISK_PHASE2_OFF + SLOT6:
|
||||
case io_DISK_PHASE3_OFF + SLOT6:
|
||||
dbgPrintf2("io_DISK_PHASE%u_OFF (S%u)\n", phase.current, 6);
|
||||
phase.last = phase.current;
|
||||
return 0;
|
||||
|
||||
case io_DISK_PHASE0_ON + SLOT6:
|
||||
case io_DISK_PHASE1_ON + SLOT6:
|
||||
case io_DISK_PHASE2_ON + SLOT6:
|
||||
case io_DISK_PHASE3_ON + SLOT6: {
|
||||
phase.current = (addr - io_DISK_PHASE0_ON - SLOT6) / 2;
|
||||
trackPhase += phaseTransition[phase.current][phase.last];
|
||||
if ( trackPhase < minDiskPhaseNum ) {
|
||||
trackPhase = minDiskPhaseNum;
|
||||
}
|
||||
if ( trackPhase > maxDiskPhaseNum ) {
|
||||
trackPhase = maxDiskPhaseNum;
|
||||
}
|
||||
dbgPrintf2("io_DISK_PHASE%u_ON (S%u, trk:%u)\n", phase.current, 6, trackPhase);
|
||||
return 0;
|
||||
}
|
||||
case io_DISK_POWER_OFF + SLOT6:
|
||||
dbgPrintf2("io_DISK_POWER_OFF (S%u)\n", 6);
|
||||
return 0;
|
||||
case io_DISK_POWER_ON + SLOT6:
|
||||
dbgPrintf2("io_DISK_POWER_ON (S%u)\n", 6);
|
||||
return 0;
|
||||
case io_DISK_SELECT_1 + SLOT6:
|
||||
dbgPrintf2("io_DISK_SELECT_1 (S%u)\n", 6);
|
||||
return 0;
|
||||
case io_DISK_SELECT_2 + SLOT6:
|
||||
dbgPrintf2("io_DISK_SELECT_2 (S%u)\n", 6);
|
||||
return 0;
|
||||
case io_DISK_READ + SLOT6:
|
||||
dbgPrintf("io_DISK_READ (S%u)\n", 6);
|
||||
int track = woz_tmap.phase[trackPhase];
|
||||
if (trackOffset >= WOZ_TRACK_BYTE_COUNT ) {
|
||||
trackOffset = 0;
|
||||
}
|
||||
printf("offs:%u\n", trackOffset);
|
||||
return woz_trks[track].data[trackOffset++];
|
||||
case io_DISK_WRITE + SLOT6:
|
||||
dbgPrintf2("io_DISK_WRITE (S%u)\n", 6);
|
||||
return 0;
|
||||
case io_DISK_CLEAR + SLOT6:
|
||||
dbgPrintf2("io_DISK_CLEAR (S%u)\n", 6);
|
||||
return 0;
|
||||
case io_DISK_SHIFT + SLOT6:
|
||||
dbgPrintf2("io_DISK_SHIFT (S%u)\n", 6);
|
||||
return 0;
|
||||
|
||||
|
||||
|
||||
default:
|
||||
break;
|
||||
return RAM[addr];
|
||||
}
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -135,6 +295,24 @@ INLINE uint8_t memread_zp( uint8_t addr ) {
|
||||
return RAM[ addr ];
|
||||
}
|
||||
|
||||
/**
|
||||
Naive implementation of RAM read from address
|
||||
**/
|
||||
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
|
||||
**/
|
||||
INLINE uint16_t memread16( uint16_t addr ) {
|
||||
return * (uint16_t*) (& RAM[ addr ]);
|
||||
}
|
||||
|
||||
INLINE uint8_t memread( uint16_t addr ) {
|
||||
// switch ( ((address16_t)addr).page ) {
|
||||
// case 0xC0:
|
||||
@ -159,29 +337,11 @@ INLINE uint8_t memread( uint16_t addr ) {
|
||||
// break;
|
||||
// }
|
||||
|
||||
if ( (addr >= 0xC000) && (addr < 0xD000) ) {
|
||||
if ( (addr >= 0xC000) && (addr < 0xC0FF) ) {
|
||||
return ioRead(addr);
|
||||
}
|
||||
|
||||
return RAM[ addr ];
|
||||
}
|
||||
|
||||
/**
|
||||
Naive implementation of RAM read from address
|
||||
**/
|
||||
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
|
||||
**/
|
||||
INLINE uint16_t memread16( uint16_t addr ) {
|
||||
return * (uint16_t*) (& RAM[ addr ]);
|
||||
return memread8(addr);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -222,7 +382,7 @@ static void memwrite( uint16_t addr, uint8_t byte ) {
|
||||
increase pc by one
|
||||
**/
|
||||
INLINE uint8_t fetch() {
|
||||
disHexB( disassembly.pHex, RAM[m6502.PC] );
|
||||
disHexB( disassembly.pOpcode, RAM[m6502.PC] );
|
||||
return memread( m6502.PC++ );
|
||||
}
|
||||
|
||||
@ -233,7 +393,7 @@ INLINE uint8_t fetch() {
|
||||
INLINE uint16_t fetch16() {
|
||||
uint16_t word = memread16( m6502.PC );
|
||||
m6502.PC += 2;
|
||||
disHexW( disassembly.pHex, word );
|
||||
disHexW( disassembly.pOpcode, word );
|
||||
return word;
|
||||
}
|
||||
|
||||
@ -243,7 +403,7 @@ INLINE uint16_t fetch16() {
|
||||
**/
|
||||
INLINE uint16_t addr_abs() {
|
||||
dbgPrintf("abs:%04X(%02X) ", *((uint16_t*)&RAM[m6502.PC]), RAM[*((uint16_t*)&RAM[m6502.PC])]);
|
||||
disPrintf(disassembly.addr, "$%04X", memread16(m6502.PC))
|
||||
disPrintf(disassembly.oper, "$%04X", memread16(m6502.PC))
|
||||
return fetch16();
|
||||
}
|
||||
INLINE uint8_t src_abs() {
|
||||
@ -255,15 +415,15 @@ INLINE uint8_t * dest_abs() {
|
||||
|
||||
|
||||
INLINE int8_t rel_addr() {
|
||||
disPrintf(disassembly.addr, "$%04X", m6502.PC + 1 + (int)memread8(m6502.PC))
|
||||
disPrintf(disassembly.oper, "$%04X", m6502.PC + 1 + (int8_t)memread8(m6502.PC))
|
||||
return fetch();
|
||||
}
|
||||
INLINE uint16_t abs_addr() {
|
||||
disPrintf(disassembly.addr, "$%04X", memread16(m6502.PC))
|
||||
disPrintf(disassembly.oper, "$%04X", memread16(m6502.PC))
|
||||
return fetch16();
|
||||
}
|
||||
INLINE uint16_t ind_addr() {
|
||||
disPrintf(disassembly.addr, "($%04X)", memread16(m6502.PC))
|
||||
disPrintf(disassembly.oper, "($%04X)", memread16(m6502.PC))
|
||||
return memread16( fetch16() );
|
||||
}
|
||||
|
||||
@ -273,11 +433,11 @@ INLINE uint16_t ind_addr() {
|
||||
**/
|
||||
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]);
|
||||
disPrintf(disassembly.addr, "$%04X,X", memread16(m6502.PC))
|
||||
disPrintf(disassembly.oper, "$%04X,X", memread16(m6502.PC))
|
||||
return fetch16() + m6502.X;
|
||||
}
|
||||
INLINE uint8_t src_abs_X() {
|
||||
return memread8( addr_abs_X() );
|
||||
return memread( addr_abs_X() );
|
||||
}
|
||||
INLINE uint8_t * dest_abs_X() {
|
||||
return & RAM[ addr_abs_X() ];
|
||||
@ -290,18 +450,18 @@ INLINE uint8_t * dest_abs_X() {
|
||||
**/
|
||||
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]);
|
||||
disPrintf(disassembly.addr, "$%04X,Y", memread16(m6502.PC))
|
||||
return abs_addr() + m6502.Y;
|
||||
disPrintf(disassembly.oper, "$%04X,Y", memread16(m6502.PC))
|
||||
return fetch16() + m6502.Y;
|
||||
}
|
||||
INLINE uint8_t src_abs_Y() {
|
||||
return memread8(addr_abs_Y());
|
||||
return memread(addr_abs_Y());
|
||||
}
|
||||
INLINE uint8_t * dest_abs_Y() {
|
||||
return & RAM[ addr_abs_Y() ];
|
||||
}
|
||||
|
||||
INLINE uint16_t imm() {
|
||||
disPrintf(disassembly.addr, "#$%02X", memread8(m6502.PC))
|
||||
disPrintf(disassembly.oper, "#$%02X", memread8(m6502.PC))
|
||||
return fetch();
|
||||
}
|
||||
|
||||
@ -312,7 +472,7 @@ INLINE uint16_t imm() {
|
||||
**/
|
||||
INLINE uint8_t addr_zp() {
|
||||
dbgPrintf("zp:%02X(%02X) ", RAM[m6502.PC], RAM[ RAM[m6502.PC]] );
|
||||
disPrintf(disassembly.addr, "$%02X", memread8(m6502.PC))
|
||||
disPrintf(disassembly.oper, "$%02X", memread8(m6502.PC))
|
||||
return fetch();
|
||||
}
|
||||
INLINE uint8_t src_zp() {
|
||||
@ -327,7 +487,7 @@ INLINE uint8_t * dest_zp() {
|
||||
**/
|
||||
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])]);
|
||||
disPrintf(disassembly.addr, "($%02X)", memread8(m6502.PC))
|
||||
disPrintf(disassembly.oper, "($%02X) {$%04X}", memread8(m6502.PC), memread16( memread8(m6502.PC) ) )
|
||||
return memread16(addr);
|
||||
}
|
||||
|
||||
@ -338,11 +498,11 @@ INLINE uint16_t addr_zp_ind( uint8_t addr ) {
|
||||
**/
|
||||
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]);
|
||||
disPrintf(disassembly.addr, "($%02X,X)", memread8(m6502.PC))
|
||||
return addr_zp_ind( fetch() + m6502.X );
|
||||
disPrintf(disassembly.oper, "($%02X,X) {$%04X}", memread8(m6502.PC), memread16( memread8(m6502.PC) + m6502.X) )
|
||||
return memread16( fetch() + m6502.X );
|
||||
}
|
||||
INLINE uint8_t src_X_ind() {
|
||||
return memread8( addr_X_ind() );
|
||||
return memread( addr_X_ind() );
|
||||
}
|
||||
INLINE uint8_t * dest_X_ind() {
|
||||
return & RAM[ addr_X_ind() ];
|
||||
@ -356,17 +516,17 @@ INLINE uint8_t * dest_X_ind() {
|
||||
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);
|
||||
disPrintf(disassembly.addr, "($%02X),Y", memread8(m6502.PC))
|
||||
return addr_zp_ind( fetch() ) + m6502.Y;
|
||||
disPrintf(disassembly.oper, "($%02X),Y {$%04X}", memread8(m6502.PC), memread16( memread8(m6502.PC) ) + m6502.Y)
|
||||
return memread16( fetch() ) + m6502.Y;
|
||||
}
|
||||
INLINE uint8_t src_ind_Y() {
|
||||
return memread8( addr_ind_Y() );
|
||||
return memread( addr_ind_Y() );
|
||||
}
|
||||
INLINE uint8_t * dest_ind_Y() {
|
||||
uint16_t addr = addr_ind_Y();
|
||||
if ( (addr >= 0xC000) && (addr <= 0xC0FF) ) {
|
||||
addr = 0xC111;
|
||||
}
|
||||
// if ( (addr >= 0xC000) && (addr <= 0xC0FF) ) {
|
||||
// addr = 0xC111;
|
||||
// }
|
||||
// return & RAM[ addr_abs_Y() ];
|
||||
return & RAM[ addr ];
|
||||
// return & RAM[ addr_ind_Y() ];
|
||||
@ -378,7 +538,7 @@ INLINE uint8_t * dest_ind_Y() {
|
||||
effective address is address incremented by X without carry **
|
||||
**/
|
||||
INLINE uint8_t addr_zp_X() {
|
||||
disPrintf(disassembly.addr, "$%02X,X", memread8(m6502.PC))
|
||||
disPrintf(disassembly.oper, "$%02X,X", memread8(m6502.PC))
|
||||
return fetch() + m6502.X;
|
||||
}
|
||||
INLINE uint8_t src_zp_X() {
|
||||
@ -394,7 +554,7 @@ INLINE uint8_t * dest_zp_X() {
|
||||
effective address is address incremented by Y without carry **
|
||||
**/
|
||||
INLINE uint8_t addr_zp_Y() {
|
||||
disPrintf(disassembly.addr, "$%02X,Y", memread8(m6502.PC))
|
||||
disPrintf(disassembly.oper, "$%02X,Y", memread8(m6502.PC))
|
||||
return fetch() + m6502.Y;
|
||||
}
|
||||
INLINE uint8_t src_zp_Y() {
|
||||
|
@ -1,8 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="14490.70" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" initialViewController="B8D-0N-5wS">
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="14868" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" initialViewController="B8D-0N-5wS">
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14490.70"/>
|
||||
<capability name="System colors introduced in macOS 10.14" minToolsVersion="10.0"/>
|
||||
<deployment identifier="macosx"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14868"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
@ -705,7 +705,7 @@
|
||||
<scene sceneID="hIz-AP-VOD">
|
||||
<objects>
|
||||
<viewController id="XfG-lQ-9wD" customClass="ViewController" customModule="A2Mac" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<view key="view" id="m2S-Jp-Qdl" customClass="QuietView" customModule="A2Mac" customModuleProvider="target">
|
||||
<view key="view" id="m2S-Jp-Qdl" customClass="MonitorView" customModule="A2Mac" customModuleProvider="target">
|
||||
<rect key="frame" x="0.0" y="0.0" width="680" height="400"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
||||
<subviews>
|
||||
@ -720,13 +720,13 @@
|
||||
</allowedInputSourceLocales>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" mirrorLayoutDirectionWhenInternationalizing="never" textCompletion="NO" translatesAutoresizingMaskIntoConstraints="NO" id="SEL-hl-0c0">
|
||||
<textField canDrawConcurrently="YES" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" mirrorLayoutDirectionWhenInternationalizing="never" textCompletion="NO" translatesAutoresizingMaskIntoConstraints="NO" id="SEL-hl-0c0">
|
||||
<rect key="frame" x="14" y="8" width="572" height="384"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="568" id="uez-Mi-0Sh"/>
|
||||
<constraint firstAttribute="height" constant="384" id="zl6-au-oZj"/>
|
||||
</constraints>
|
||||
<textFieldCell key="cell" lineBreakMode="truncatingTail" selectable="YES" allowsUndo="NO" sendsActionOnEndEditing="YES" state="on" baseWritingDirection="leftToRight" id="pIk-RC-s5g">
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" refusesFirstResponder="YES" allowsUndo="NO" sendsActionOnEndEditing="YES" state="on" baseWritingDirection="leftToRight" id="pIk-RC-s5g">
|
||||
<font key="font" size="16" name="PrintChar21"/>
|
||||
<string key="title">1234567890123456789012345678901234567890
|
||||
@@@@@@@@@1@@@@@@@@@2@@@@@@@@@3@@@@@@@@@4
|
||||
@ -753,10 +753,7 @@
|
||||
@@@@@@@@@@@@@@@@@@23@@@@@@@@@@@@@@@@@@@@
|
||||
@@@@@@@@@@@@@@@@@@24@@@@@@@@@@@@@@@@@@@@</string>
|
||||
<color key="textColor" name="systemGreenColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="alternatingContentBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
<allowedInputSourceLocales>
|
||||
<string>NSAllRomanInputSourcesLocaleIdentifier</string>
|
||||
</allowedInputSourceLocales>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="mfd-12-bcR">
|
||||
@ -796,7 +793,7 @@
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<customView hidden="YES" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="LlM-EV-ruZ" customClass="HiRes" customModule="A2Mac" customModuleProvider="target">
|
||||
<customView fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="LlM-EV-ruZ" customClass="HiRes" customModule="A2Mac" customModuleProvider="target">
|
||||
<rect key="frame" x="16" y="8" width="568" height="384"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
</customView>
|
||||
@ -820,9 +817,9 @@
|
||||
</constraints>
|
||||
</view>
|
||||
<connections>
|
||||
<outlet property="HiRes" destination="LlM-EV-ruZ" id="E60-pA-HM1"/>
|
||||
<outlet property="display" destination="pIk-RC-s5g" id="Hvd-DI-h6z"/>
|
||||
<outlet property="displayField" destination="SEL-hl-0c0" id="4Pc-hG-qQf"/>
|
||||
<outlet property="hires" destination="LlM-EV-ruZ" id="E60-pA-HM1"/>
|
||||
<outlet property="speedometer" destination="FBZ-dh-6Fs" id="L0v-RY-xwB"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
|
@ -18,18 +18,42 @@ class HiRes: NSView {
|
||||
static let PixelWidth = 280
|
||||
static let PixelMixedHeight = 160
|
||||
static let PixelHeight = 192
|
||||
static let LineBlocks = 40
|
||||
static let blockRows = 24
|
||||
static let blockCols = 40
|
||||
static let blockWidth = PixelWidth / blockCols
|
||||
static let blockHeight = PixelHeight / blockRows
|
||||
|
||||
let HiResBufferPointer = UnsafeRawBufferPointer(start: &RAM + Page1Addr, count: PageSize * 2)
|
||||
let HiResBufferPointer = UnsafeRawBufferPointer(start: RAM + Page1Addr, count: PageSize * 2)
|
||||
let HiResRawPointer = UnsafeRawPointer(RAM + Page1Addr)
|
||||
|
||||
#if METAL_YES
|
||||
var device: MTLDevice!
|
||||
var metalLayer: CAMetalLayer!
|
||||
var vertexBuffer: MTLBuffer!
|
||||
var renderPipelineState: MTLRenderPipelineState!
|
||||
var computePipelineState: MTLComputePipelineState!
|
||||
var commandQueue: MTLCommandQueue!
|
||||
// var timer: CADisplayLink! // iOS only!
|
||||
var timer: CVDisplayLink! // MacOS only!
|
||||
var defaultLibrary : MTLLibrary!
|
||||
var addFunction : MTLFunction!
|
||||
var mtlBufferA : MTLBuffer!
|
||||
var mtlBufferB : MTLBuffer!
|
||||
var mtlBufferC : MTLBuffer!
|
||||
|
||||
let vertexData: [Float] = [
|
||||
0.0, 1.0, 0.0, -1.0, -1.0, 0.0, 1.0, -1.0, 0.0
|
||||
]
|
||||
#endif // METAL_YES
|
||||
|
||||
// holds the starting addresses for each lines minus the screen page starting address
|
||||
var HiResLineAddrTbl = [UInt16](repeating: 0, count: PixelHeight)
|
||||
var HiResLineAddrTbl = [Int](repeating: 0, count: PixelHeight)
|
||||
|
||||
func initHiResLineAddresses() {
|
||||
var i = 0
|
||||
for x : UInt16 in stride(from: 0, through: 0x50, by: 0x28) {
|
||||
for y : UInt16 in stride(from: 0, through: 0x380, by: 0x80) {
|
||||
for z : UInt16 in stride(from: 0, through: 0x1C00, by: 0x400) {
|
||||
for x in stride(from: 0, through: 0x50, by: 0x28) {
|
||||
for y in stride(from: 0, through: 0x380, by: 0x80) {
|
||||
for z in stride(from: 0, through: 0x1C00, by: 0x400) {
|
||||
HiResLineAddrTbl[i] = x + y + z
|
||||
i += 1
|
||||
}
|
||||
@ -37,16 +61,87 @@ class HiRes: NSView {
|
||||
}
|
||||
}
|
||||
|
||||
#if METAL_YES
|
||||
func initMetal() {
|
||||
device = MTLCreateSystemDefaultDevice()
|
||||
metalLayer = CAMetalLayer() // 1
|
||||
metalLayer.device = device // 2
|
||||
metalLayer.pixelFormat = .bgra8Unorm // 3
|
||||
metalLayer.framebufferOnly = true // 4
|
||||
metalLayer.frame = frame // 5
|
||||
// hires.layer = metalLayer // 6
|
||||
|
||||
// let dataSize = vertexData.count * MemoryLayout.size(ofValue: vertexData[0]) // 1
|
||||
// vertexBuffer = device.makeBuffer(bytes: vertexData, length: dataSize, options: []) // 2
|
||||
|
||||
// 1
|
||||
defaultLibrary = device.makeDefaultLibrary()!
|
||||
addFunction = defaultLibrary.makeFunction(name: "add_arrays")
|
||||
|
||||
computePipelineState = try! device.makeComputePipelineState(function: addFunction)
|
||||
|
||||
// let fragmentProgram = defaultLibrary.makeFunction(name: "basic_fragment")
|
||||
// let vertexProgram = defaultLibrary.makeFunction(name: "basic_vertex")
|
||||
|
||||
// 2
|
||||
// let pipelineState
|
||||
// let pipelineStateDescriptor = MTLRenderPipelineDescriptor()
|
||||
// pipelineStateDescriptor.vertexFunction = vertexProgram
|
||||
// pipelineStateDescriptor.fragmentFunction = fragmentProgram
|
||||
// pipelineStateDescriptor.colorAttachments[0].pixelFormat = .bgra8Unorm
|
||||
|
||||
// 3
|
||||
// pipelineState = try! device.makeRenderPipelineState(descriptor: pipelineStateDescriptor)
|
||||
|
||||
commandQueue = device.makeCommandQueue()
|
||||
|
||||
mtlBufferA = device.makeBuffer(bytes: HiResRawPointer, length: HiRes.PageSize, options: .storageModeShared)
|
||||
mtlBufferB = device.makeBuffer(bytes: HiResRawPointer, length: HiRes.PageSize, options: .storageModeShared)
|
||||
mtlBufferC = device.makeBuffer(length: HiRes.PageSize * 4, options: .storageModeShared)
|
||||
|
||||
var displayLink : CVDisplayLink!
|
||||
let displayID = CGMainDisplayID()
|
||||
let error = CVDisplayLinkCreateWithCGDisplay(displayID, &displayLink)
|
||||
|
||||
// timer = CVDisplayLink( (target: self, selector: #selector(gameloop))
|
||||
// timer.add(to: RunLoop.main, forMode: .default)
|
||||
|
||||
// CVDisplayLinkSetOutputCallback(displayLink!, renderCallback as? CVDisplayLinkOutputCallback, UnsafeMutableRawPointer( Unmanaged.passUnretained(self).toOpaque() ))
|
||||
// CVDisplayLinkStart(displayLink!)
|
||||
|
||||
}
|
||||
#endif // METAL_YES
|
||||
|
||||
var HiResSubView = [[NSView]]()
|
||||
|
||||
func createHiRes() {
|
||||
for y in 0 ..< HiRes.blockRows {
|
||||
HiResSubView.append([NSView]())
|
||||
for x in 0 ..< HiRes.blockCols {
|
||||
let blockView = NSView(frame: NSRect(x: x * HiRes.blockWidth, y: y * 8, width: HiRes.blockWidth, height: 8))
|
||||
HiResSubView[y].append(blockView)
|
||||
self.addSubview(blockView)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
required init?(coder aDecoder: NSCoder) {
|
||||
super.init(coder: aDecoder)
|
||||
initHiResLineAddresses()
|
||||
|
||||
|
||||
let scaleSizeW = Double((frame.size).width) / Double(HiRes.PixelWidth)
|
||||
let scaleSizeH = Double((frame.size).height) / Double(HiRes.PixelHeight)
|
||||
// let scaleSizeW = Double((frame.size).width) / Double(HiRes.PixelWidth)
|
||||
// let scaleSizeH = Double((frame.size).height) / Double(HiRes.PixelHeight)
|
||||
let scaleSizeW = 2
|
||||
let scaleSizeH = 2
|
||||
scaleUnitSquare(to: NSSize(width: scaleSizeW, height: scaleSizeH))
|
||||
|
||||
// create smaller box views for draw optimization
|
||||
// createHiRes()
|
||||
|
||||
#if METAL_YES
|
||||
initMetal()
|
||||
#endif
|
||||
}
|
||||
|
||||
override init(frame: CGRect) {
|
||||
@ -54,20 +149,198 @@ class HiRes: NSView {
|
||||
}
|
||||
|
||||
|
||||
#if METAL_YES
|
||||
func compute() {
|
||||
let commandBuffer = commandQueue.makeCommandBuffer()!
|
||||
let computeEncoder = commandBuffer.makeComputeCommandEncoder()
|
||||
|
||||
computeEncoder?.setComputePipelineState(computePipelineState)
|
||||
computeEncoder?.setBuffer(mtlBufferA, offset: 0, index: 0)
|
||||
computeEncoder?.setBuffer(mtlBufferA, offset: 0, index: 1)
|
||||
computeEncoder?.setBuffer(mtlBufferC, offset: 0, index: 2)
|
||||
|
||||
let gridSize = MTLSizeMake(HiRes.PageSize, 1, 1)
|
||||
let threadGroupSize = min( computePipelineState.maxTotalThreadsPerThreadgroup, HiRes.PageSize )
|
||||
let threadgroupSize = MTLSizeMake(threadGroupSize, 1, 1)
|
||||
// Encode the Compute Command to Execute the Threads
|
||||
computeEncoder?.dispatchThreadgroups(gridSize, threadsPerThreadgroup: threadgroupSize)
|
||||
// no more compute passes
|
||||
computeEncoder?.endEncoding()
|
||||
// Commit the Command Buffer to Execute Its Commands
|
||||
commandBuffer.commit()
|
||||
// Wait for the Calculation to Complete
|
||||
commandBuffer.waitUntilCompleted()
|
||||
// Alternatively, to be notified when Metal has processed all of the commands,
|
||||
// add a completion handler to the command buffer (addCompletedHandler(_:)),
|
||||
// or check the status of a command buffer by reading its status property
|
||||
|
||||
let result = UnsafeRawBufferPointer(start: mtlBufferC.contents(), count: HiRes.PageSize)
|
||||
}
|
||||
|
||||
|
||||
func render() {
|
||||
guard let drawable = metalLayer?.nextDrawable() else { return }
|
||||
let renderPassDescriptor = MTLRenderPassDescriptor()
|
||||
renderPassDescriptor.colorAttachments[0].texture = drawable.texture
|
||||
renderPassDescriptor.colorAttachments[0].loadAction = .clear
|
||||
renderPassDescriptor.colorAttachments[0].clearColor = MTLClearColor(
|
||||
red: 0.0,
|
||||
green: 104.0/255.0,
|
||||
blue: 55.0/255.0,
|
||||
alpha: 1.0)
|
||||
|
||||
let commandBuffer = commandQueue.makeCommandBuffer()!
|
||||
|
||||
let renderEncoder = commandBuffer.makeRenderCommandEncoder(descriptor: renderPassDescriptor)!
|
||||
renderEncoder.setRenderPipelineState(renderPipelineState)
|
||||
renderEncoder.setVertexBuffer(vertexBuffer, offset: 0, index: 0)
|
||||
renderEncoder.drawPrimitives(type: .triangle, vertexStart: 0, vertexCount: 3, instanceCount: 1)
|
||||
renderEncoder.endEncoding()
|
||||
|
||||
// committing buffer
|
||||
commandBuffer.present(drawable)
|
||||
commandBuffer.commit()
|
||||
}
|
||||
#endif // METAL_YES
|
||||
|
||||
// @objc func gameloop() {
|
||||
// autoreleasepool {
|
||||
// self.render()
|
||||
// }
|
||||
// }
|
||||
|
||||
func renderCallback(displayLink : CVDisplayLink,
|
||||
const inNow : UnsafePointer<CVTimeStamp>,
|
||||
const inOutputTime : UnsafePointer<CVTimeStamp>,
|
||||
flagsIn : CVOptionFlags,
|
||||
flagsOut : UnsafeMutablePointer<CVOptionFlags>,
|
||||
displayLinkContext : UnsafeMutableRawPointer) -> CVReturn
|
||||
{
|
||||
/* It's prudent to also have a brief discussion about the CVTimeStamp.
|
||||
CVTimeStamp has five properties. Three of the five are very useful
|
||||
for keeping track of the current time, calculating delta time, the
|
||||
frame number, and the number of frames per second. The utility of
|
||||
each property is not terribly obvious from just reading the names
|
||||
or the descriptions in the Developer dcumentation and has been a
|
||||
mystery to many a developer. Thankfully, CaptainRedmuff on
|
||||
StackOverflow asked a question that provided the equation that
|
||||
calculates frames per second. From that equation, we can
|
||||
extrapolate the value of each field.
|
||||
|
||||
@hostTime = current time in Units of the "root". Yeah, I don't know.
|
||||
The key to this field is to understand that it is in nanoseconds
|
||||
(e.g. 1/1_000_000_000 of a second) not units. To convert it to
|
||||
seconds divide by 1_000_000_000. Dividing by videoRefreshPeriod
|
||||
and videoTimeScale in a calculation for frames per second yields
|
||||
the appropriate number of frames. This works as a result of
|
||||
proportionality--dividing seconds by seconds. Note that dividing
|
||||
by videoTimeScale to get the time in seconds does not work like it
|
||||