- 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:
Tamas Rudnai 2019-11-27 20:27:32 -08:00
parent 1e455a011e
commit fddb1d9642
14 changed files with 2127 additions and 184 deletions

View File

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

View File

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

View File

@ -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__ */

View File

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

View File

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

View File

@ -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
does for videoTime.
framesPerSecond:
(videoTime / videoRefreshPeriod) / (videoTime / videoTimeScale) = 59
and
(hostTime / videoRefreshPeriod) / (hostTime / videoTimeScale) = 59
but
hostTime * videoTimeScale seconds, but Units = seconds * (Units / seconds) = Units
@rateScalar = ratio of "rate of device in CVTimeStamp/unitOfTime" to
the "Nominal Rate". I think the "Nominal Rate" is
videoRefreshPeriod, but unfortunately, the documentation doesn't
just say videoRefreshPeriod is the Nominal rate and then define
what that means. Regardless, because this is a ratio, and the fact
that we know the value of one of the parts (e.g. Units/frame), we
then know that the "rate of the device" is frame/Units (the units of
measure need to cancel out for the ratio to be a ratio). This
makes sense in that rateScalar's definition tells us the rate is
"measured by timeStamps". Since there is a frame for every
timeStamp, the rate of the device equals CVTimeStamp/Unit or
frame/Unit. Thus,
rateScalar = frame/Units : Units/frame
@videoTime = the time the frame was created since computer started up.
If you turn your computer off and then turn it back on, this timer
returns to zero. The timer is paused when you put your computer to
sleep. This value is in Units not seconds. To get the number of
seconds this value represents, you have to apply videoTimeScale.
@videoRefreshPeriod = the number of Units per frame (i.e. Units/frame)
This is useful in calculating the frame number or frames per second.
The documentation calls this the "nominal update period" and I am
pretty sure that is quivalent to the aforementioned "nominal rate".
Unfortunately, the documetation mixes naming conventions and this
inconsistency creates confusion.
frame = videoTime / videoRefreshPeriod
@videoTimeScale = Units/second, used to convert videoTime into seconds
and may also be used with videoRefreshPeriod to calculate the expected
framesPerSecond. I say expected, because videoTimeScale and
videoRefreshPeriod don't change while videoTime does change. Thus,
to calculate fps in the case of system slow down, one would need to
use videoTime with videoTimeScale to calculate the actual fps value.
seconds = videoTime / videoTimeScale
framesPerSecondConstant = videoTimeScale / videoRefreshPeriod (this value does not change if their is system slowdown)
USE CASE 1: Time in DD:HH:mm:ss using hostTime
let rootTotalSeconds = inNow.pointee.hostTime
let rootDays = inNow.pointee.hostTime / (1_000_000_000 * 60 * 60 * 24) % 365
let rootHours = inNow.pointee.hostTime / (1_000_000_000 * 60 * 60) % 24
let rootMinutes = inNow.pointee.hostTime / (1_000_000_000 * 60) % 60
let rootSeconds = inNow.pointee.hostTime / 1_000_000_000 % 60
Swift.print("rootTotalSeconds: \(rootTotalSeconds) rootDays: \(rootDays) rootHours: \(rootHours) rootMinutes: \(rootMinutes) rootSeconds: \(rootSeconds)")
USE CASE 2: Time in DD:HH:mm:ss using videoTime
let totalSeconds = inNow.pointee.videoTime / Int64(inNow.pointee.videoTimeScale)
let days = (totalSeconds / (60 * 60 * 24)) % 365
let hours = (totalSeconds / (60 * 60)) % 24
let minutes = (totalSeconds / 60) % 60
let seconds = totalSeconds % 60
Swift.print("totalSeconds: \(totalSeconds) Days: \(days) Hours: \(hours) Minutes: \(minutes) Seconds: \(seconds)")
Swift.print("fps: \(Double(inNow.pointee.videoTimeScale) / Double(inNow.pointee.videoRefreshPeriod)) seconds: \(Double(inNow.pointee.videoTime) / Double(inNow.pointee.videoTimeScale))")
*/
/* The displayLinkContext in CVDisplayLinkOutputCallback's parameter list is the
view being driven by the CVDisplayLink. In order to use the context as an
instance of SwiftOpenGLView (which has our drawView() method) we need to use
unsafeBitCast() to cast this context to a SwiftOpenGLView.
*/
// let view = unsafeBitCast(displayLinkContext, to: SwiftOpenGLView.self)
// // Capture the current time in the currentTime property.
// view.currentTime = inNow.pointee.videoTime / Int64(inNow.pointee.videoTimeScale)
// view.drawView()
// self.render()
return kCVReturnSuccess
}
static func createBitmapContext(pixelsWide: Int, _ pixelsHigh: Int) -> CGContext? {
let bytesPerPixel = 4
let bytesPerRow = bytesPerPixel * pixelsWide
let bitsPerComponent = 8
let byteCount = (bytesPerRow * pixelsHigh)
guard let colorSpace = CGColorSpace(name: CGColorSpace.linearSRGB) else { return nil }
// guard let colorSpace = CGColorSpace(name: CGColorSpace.linearSRGB) else { return nil }
guard let colorSpace = CGColorSpace(name: CGColorSpace.genericRGBLinear) else { return nil }
let pixels = UnsafeMutablePointer<CUnsignedChar>.allocate(capacity: byteCount)
let bitmapInfo = CGImageAlphaInfo.premultipliedFirst.rawValue | CGBitmapInfo.byteOrder32Little.rawValue
let context = CGContext(data: pixels, width: pixelsWide, height: pixelsHigh, bitsPerComponent: bitsPerComponent, bytesPerRow: bytesPerRow, space: colorSpace, bitmapInfo: bitmapInfo)
let context = CGContext(
data: pixels,
width: pixelsWide,
height: pixelsHigh,
bitsPerComponent: 8,
bytesPerRow: bytesPerRow,
space: colorSpace,
bitmapInfo: bitmapInfo)
return context
}
@ -106,11 +379,12 @@ class HiRes: NSView {
}
}
#if HIRESLOW
static let ScreenBitmapSize = (PixelWidth * PixelHeight * 4)
static let context = createBitmapContext(pixelsWide: PixelWidth, PixelHeight)
static let pixels = UnsafeMutableRawBufferPointer(start: context?.data, count: ScreenBitmapSize) // UnsafeMutablePointer<CUnsignedChar>.allocate(capacity: byteCount)
#endif
static let byteCount = (HiRes.PixelWidth * HiRes.PixelHeight * 4)
static let context = createBitmapContext(pixelsWide: HiRes.PixelWidth, HiRes.PixelHeight)
static let pixels = UnsafeMutableRawBufferPointer(start: context?.data, count: byteCount) // UnsafeMutablePointer<CUnsignedChar>.allocate(capacity: byteCount)
let R = 2
let G = 1
let B = 0
@ -118,25 +392,35 @@ class HiRes: NSView {
var shadowScreen = [Int](repeating: 1, count: PageSize)
var was = 0;
#if HIRESLOW
override func draw(_ rect: CGRect) {
// print("HIRESSLOW\n")
// if was > 100 {
// return
// }
// was += 1
var pixelAddr = 0
var minX = 0
var minY = 0
var minX = 9999
var minY = 9999
var maxX = 0
var maxY = 0
var x = 0
var y = 0
for lineAddr in HiResLineAddrTbl {
for blockAddr in 0..<UInt16(HiRes.LineBlocks) {
for blockAddr in 0..<HiRes.blockCols {
let block = Int(HiResBufferPointer[ Int(lineAddr + blockAddr) ])
let screenIdx = y * HiRes.LineBlocks + x
let screenIdx = y * HiRes.blockCols + x
if ( shadowScreen[ screenIdx ] != block ) {
shadowScreen[ screenIdx ] = block
for bit in stride(from: 0, through: 6, by: 1) {
let bitMask = 1 << bit
if (block & bitMask) == 0 {
@ -149,14 +433,14 @@ class HiRes: NSView {
HiRes.pixels[pixelAddr + R] = 0x08;
HiRes.pixels[pixelAddr + G] = 0xA2;
HiRes.pixels[pixelAddr + B] = 0x12;
HiRes.pixels[pixelAddr + A] = 0xFF;
HiRes.pixels[pixelAddr + A] = 0x7F;
}
if ( minX == 0 ) { minX = x }
if ( minY == 0 ) { minY = y }
if ( minX > x ) { minX = x }
if ( minY > y ) { minY = y }
if ( maxX < x ) { maxX = x }
if ( maxY < y ) { maxY = y }
pixelAddr += 4
x += 1
}
@ -166,21 +450,133 @@ class HiRes: NSView {
x += 7
}
}
y += 1
x = 0
}
guard let image = HiRes.context?.makeImage() else { return }
if let currentContext: CGContext = currentContext {
// UIImagePNGRepresentation(UIImage(CGImage:image!))?.writeToFile("/Users/admin/Desktop/aaaaa.png", atomically: true)
// if ( maxX > minX ) && ( maxY > minY ) {
let boundingBox = CGRect(x: 0, y: 0, width: CGFloat(HiRes.PixelWidth), height: CGFloat(HiRes.PixelHeight))
// let boundingBox = CGRect(x: minX, y: minY, width: maxX - minX, height: maxY - minY)
currentContext.draw (image, in: boundingBox)
// }
}
let boundingBox = CGRect(x: 0, y: 0, width: CGFloat(HiRes.PixelWidth), height: CGFloat(HiRes.PixelHeight))
currentContext!.draw (image, in: boundingBox)
}
#elseif HIRESDRAW
override func draw(_ rect: CGRect) {
// NSColor.green.setFill()
NSColor(calibratedRed: 0.0314, green: 0.635, blue: 0.071, alpha: 0.5).setStroke()
let path = NSBezierPath()
path.lineWidth=1
path.move(to: NSPoint(x: 0, y: 0))
// path.appendRect(NSRect(x: 0, y: 0, width: 10, height: 10))
for y in 0 ..< HiRes.PixelHeight {
var inX = false
path.move(to: NSPoint(x: 0, y: y))
for blockX in 0 ..< HiRes.blockCols {
let lineAddr = HiResLineAddrTbl[y]
let block = Int(HiResBufferPointer[ Int(lineAddr + blockX) ])
// if( shadowScreen[ screenIdx ] != block ) {
// shadowScreen[ screenIdx ] = block
//
var x = blockX * HiRes.blockWidth
for bit in stride(from: 0, through: 6, by: 1) {
let bitMask = 1 << bit
if (block & bitMask) == 0 {
if inX {
inX = false
path.line(to: NSPoint(x: x, y: 192-y))
}
}
else { // 28CD41
if ( inX == false ) {
inX = true
path.move(to: NSPoint(x: x, y: 192-y))
}
}
x += 1
}
} // x
if inX {
inX = false
path.line(to: NSPoint(x: 279, y: 192-y))
}
}
// path.fill()
path.stroke()
}
#elseif HIRES
override func draw(_ rect: CGRect) {
// print("HIRESBLOCKS\n")
// if was > 100 {
// return
// }
// was += 1
for blockY in 0 ..< HiRes.blockRows {
for blockX in 0 ..< HiRes.blockCols {
let blockView = HiResSubView[blockY][blockX]
let bitmapSize = HiRes.blockWidth * HiRes.blockHeight * 4
let context = HiRes.createBitmapContext(pixelsWide: HiRes.blockWidth, HiRes.blockHeight)
let pixels = UnsafeMutableRawBufferPointer(start: context?.data, count: bitmapSize) // UnsafeMutablePointer<CUnsignedChar>.allocate(capacity: byteCount)
var blockNeedsDisplay = false
for line in 0 ... 7 {
let y = blockY + line
let screenIdx = y * HiRes.blockCols + blockX
let pixelAddr = line
let lineAddr = HiResLineAddrTbl[y]
let block = Int(HiResBufferPointer[ Int(lineAddr + blockX) ])
if( shadowScreen[ screenIdx ] != block ) {
shadowScreen[ screenIdx ] = block
blockNeedsDisplay = true
var x = blockX * HiRes.blockWidth
for bit in stride(from: 0, through: 6, by: 1) {
let bitMask = 1 << bit
if (block & bitMask) == 0 {
pixels[pixelAddr + R] = 0x00;
pixels[pixelAddr + G] = 0x00;
pixels[pixelAddr + B] = 0x00;
pixels[pixelAddr + A] = 0x00;
}
else { // 28CD41
pixels[pixelAddr + R] = 0x08;
pixels[pixelAddr + G] = 0xA2;
pixels[pixelAddr + B] = 0x12;
pixels[pixelAddr + A] = 0x7F;
}
x += 1
}
}
}
if blockNeedsDisplay {
blockView.needsDisplay = true
// print("block(\(blockX),\(blockY))")
guard let image = context?.makeImage() else { return }
let boundingBox = CGRect(x: 0, y: 0, width: CGFloat(HiRes.PixelWidth), height: CGFloat(HiRes.PixelHeight))
currentContext!.draw(image, in: boundingBox)
}
}
}
}
#endif
}

View File

@ -8,7 +8,7 @@
import Cocoa
class QuietView: NSView {
class MonitorView: NSView {
override func performKeyEquivalent(with event: NSEvent) -> Bool {
return true
}

34
A2Mac/Shaders.metal Normal file
View File

@ -0,0 +1,34 @@
//
// Shaders.metal
// A2Mac
//
// Created by Tamas Rudnai on 9/27/19.
// Copyright © 2019 GameAlloy. All rights reserved.
//
#include <metal_stdlib>
using namespace metal;
vertex float4 basic_vertex( // 1
const device packed_float3* vertex_array [[ buffer(0) ]], // 2
unsigned int vid [[ vertex_id ]]) { // 3
return float4(vertex_array[vid], 1.0); // 4
}
fragment half4 basic_fragment() { // 1
return half4(0.7); // 2
}
kernel void add_arrays(device const float* inA,
device const float* inB,
device float* result,
uint index [[thread_position_in_grid]])
{
// the for-loop is replaced with a collection of threads, each of which
// calls this function.
result[index] = inA[index] + inB[index] + 1;
}

View File

@ -8,12 +8,17 @@
import Cocoa
#if METAL_YES
import Metal
#endif
class ViewController: NSViewController {
@IBOutlet weak var displayField: NSTextField!
@IBOutlet weak var display: NSTextFieldCell!
@IBOutlet weak var speedometer: NSTextFieldCell!
@IBOutlet weak var HiRes: HiRes!
@IBOutlet weak var hires: HiRes!
// static let charConvStr : String =
// "@🄰🄱🄲🄳🄴🄵🄶🄷🄸🄹🄺🄻🄼🄽🄾🄿🅀🅁🅂🅃🅄🅅🅆🅇🅈🅉[\\]^_ !\"#$%&'()*+,-./0123456789:;<=>?" +
@ -73,7 +78,7 @@ class ViewController: NSViewController {
DispatchQueue.global().async(execute: workItem!);
}
#else
m6502_Reset()
m6502_ColdReset()
#endif
}
@ -171,7 +176,6 @@ class ViewController: NSViewController {
// }
// }
static let textBaseAddr = 0x400
static let textBufferSize = 0x400
let textLines = 24
@ -185,8 +189,8 @@ class ViewController: NSViewController {
let blockChar : Character = ""
var flashingSpace : Character = " "
let ramBufferPointer = UnsafeRawBufferPointer(start: &RAM, count: 64 * 1024)
let textBufferPointer = UnsafeRawBufferPointer(start: &RAM + textBaseAddr, count: textBufferSize)
let ramBufferPointer = UnsafeRawBufferPointer(start: RAM, count: 64 * 1024)
let textBufferPointer = UnsafeRawBufferPointer(start: RAM + textBaseAddr, count: textBufferSize)
var txtArr = [Character](repeating: " ", count: textBufferSize)
var s = String()
@ -210,6 +214,9 @@ class ViewController: NSViewController {
}
}
var was = 0;
func Update() {
#if SPEEDTEST
@ -217,6 +224,9 @@ class ViewController: NSViewController {
m6502_Run()
#endif
// render()
// hires.compute()
// HexDump()
// return
@ -273,16 +283,31 @@ class ViewController: NSViewController {
DispatchQueue.main.async {
self.display.stringValue = txt
// self.display.stringValue = "testing\nit\nout"
if ( mhz < 10 ) {
self.speedometer.stringValue = String(format: "%0.3lf MHz", mhz);
}
else {
self.speedometer.stringValue = String(format: "%.0lf MHz", mhz);
}
// self.HiRes.setNeedsDisplay(self.HiRes.frame)
// self.HiRes.setNeedsDisplay(CGRect(x: 0, y: 191-50, width: 50, height: 50))
// self.HiRes.needsDisplay = true
#if HIRES
// if ( self.was < 300 ) {
// self.was += 1
//
// for x in stride(from: 0, to: 280, by: 7) {
// for y in stride(from: 0, to: 192, by: 8) {
// self.hires.setNeedsDisplay( CGRect(x: x, y: y, width: 7, height: 8) )
// }
// }
// }
// self.HiRes.setNeedsDisplay(self.HiRes.frame)
// self.hires.setNeedsDisplay( CGRect(x: 0, y: 191-50, width: 50, height: 50) )
self.hires.needsDisplay = true
// }
#endif
}
}
@ -295,13 +320,17 @@ class ViewController: NSViewController {
// return nil // the bytes aren't valid UTF8
// }
// }
let upd = RepeatingTimer(timeInterval: 1/Double(fps))
override func viewDidLoad() {
super.viewDidLoad()
//view.frame = CGRect(origin: CGPoint(), size: NSScreen.main!.visibleFrame.size)
// createHiRes()
self.displayField.scaleUnitSquare(to: NSSize(width: 1, height: 1))
// NSEvent.removeMonitor(NSEvent.EventType.flagsChanged)
@ -309,12 +338,13 @@ class ViewController: NSViewController {
// self.flagsChanged(with: $0)
// return $0
// }
// NSEvent.removeMonitor(NSEvent.EventType.keyDown)
NSEvent.addLocalMonitorForEvents(matching: .keyDown) {
// print("keyDown event")
self.keyDown(with: $0)
return $0
}
// // NSEvent.removeMonitor(NSEvent.EventType.keyDown)
// NSEvent.addLocalMonitorForEvents(matching: .keyDown) {
//// print("keyDown event")
// self.keyDown(with: $0)
// return $0
// }
displayField.maximumNumberOfLines = textLines
displayField.preferredMaxLayoutWidth = displayField.frame.width

View File

@ -9,54 +9,51 @@
#ifndef disassembler_h
#define disassembler_h
#define NO_DISASSEMBLER
#ifdef DISASSEMBLER
#define disHexB( to, b ) \
if ( m6502.dbgLevel >= DISASSEMBLY ) { \
if ( m6502.dbgLevel.trace ) { \
snprintf((to), 4, "%02X ", (b)); \
to += 3; \
}
#define disHexW( to, w ) \
if ( m6502.dbgLevel >= DISASSEMBLY ) { \
if ( m6502.dbgLevel.trace ) { \
snprintf((to), 6, "%04X ", (w)); \
to += 5; \
}
#define disPuts( to, from ) { \
char * s = from; \
if ( m6502.dbgLevel >= DISASSEMBLY ) { \
if ( m6502.dbgLevel.trace ) { \
while ( (*(to)++ = *s++) ); \
} \
}
#define disPrintf( to, fmt, args... ) { \
if ( m6502.dbgLevel >= DISASSEMBLY ) { \
if ( m6502.dbgLevel.trace ) { \
snprintf( (to), sizeof(to), fmt, ##args ); \
} \
}
#define disNewInstruction() { \
if ( m6502.dbgLevel >= DISASSEMBLY ) { \
disassembly.pHex = disassembly.hex; \
*disassembly.hex = '\0'; \
if ( m6502.dbgLevel.trace ) { \
snprintf(disassembly.addr, 5, "%04X ", m6502.PC); \
*disassembly.opcode = '\0'; \
disassembly.pOpcode = disassembly.opcode; \
*disassembly.inst = '\0'; \
*disassembly.addr = '\0'; \
*disassembly.oper = '\0'; \
*disassembly.comment = '\0'; \
snprintf(disassembly.codeAddr, 5, "%04X ", m6502.PC); \
} \
}
INLINE void printDisassembly() {
if ( m6502.dbgLevel >= DISASSEMBLY ) {
if ( m6502.dbgLevel.trace ) {
printf("%s: %-14s%-6s%-14s%s\n",
disassembly.codeAddr,
disassembly.hex,
disassembly.inst,
disassembly.addr,
disassembly.opcode,
disassembly.inst,
disassembly.oper,
disassembly.comment
);
}

View File

@ -52,7 +52,7 @@ INLINE void BCC( int8_t reladdr ) {
**/
INLINE void BCS( int8_t reladdr ) {
dbgPrintf("BCS ");
disPrintf(disassembly.inst, "RCS");
disPrintf(disassembly.inst, "BCS");
if ( m6502.C == 1 ) {
BRA( reladdr );
}

View File

@ -28,7 +28,7 @@ INLINE void BRK() {
m6502.B = 1;
PUSH(m6502.SR);
m6502.I = 1;
JMP(memread16(IRQ_VECTOR));
m6502.PC = memread16(IRQ_VECTOR);
}
/**

1036
A2Mac/verticies.swift Normal file

File diff suppressed because it is too large Load Diff

56
A2Mac/woz.h Normal file
View File

@ -0,0 +1,56 @@
//
// woz1.h
// A2Mac
//
// Created by Tamas Rudnai on 11/18/19.
// Copyright © 2019 GameAlloy. All rights reserved.
//
#ifndef woz_h
#define woz_h
typedef struct woz_header_s {
uint32_t magic;
uint8_t no7;
char lineend [3];
uint32_t crc;
} woz_header_t;
typedef struct woz_chunk_header_s {
uint32_t magic;
uint32_t size;
} woz_chunk_header_t;
// chunk data only
typedef struct woz_info_s {
uint8_t version;
uint8_t disk_type; // 1 = 5.25, 2 = 3.5
uint8_t is_write_protected;
uint8_t sync; // 1 = Cross track sync
uint8_t cleaned; // 1 = MC3470 fake bits removed
char creator [32]; // Name of software created this file (UTF-8, 0x20 padded, NOT zero terminated)
} woz_info_t;
// chunk data only
typedef struct woz_tmap_s {
uint8_t phase [80 * 4];
} woz_tmap_t;
#define WOZ_TRACK_BYTE_COUNT 6646
// chunk data only
typedef struct woz_track_s {
uint8_t data [WOZ_TRACK_BYTE_COUNT];
uint16_t bytes_used;
uint16_t bit_count;
uint16_t splice_point;
uint8_t splice_nibble;
uint8_t splice_bit_count;
uint16_t reserved;
} woz_track_t;
// chunk data only
typedef woz_track_t woz_trks_t[80];
#endif /* woz_h */