mirror of
https://github.com/trudnai/Steve2.git
synced 2025-02-01 01:33: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
|
||||
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
|
||||
|
||||
|
||||
}
|
||||
|
@ -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
34
A2Mac/Shaders.metal
Normal 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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
);
|
||||
}
|
||||
|
@ -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 );
|
||||
}
|
||||
|
@ -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
1036
A2Mac/verticies.swift
Normal file
File diff suppressed because it is too large
Load Diff
56
A2Mac/woz.h
Normal file
56
A2Mac/woz.h
Normal 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 */
|
Loading…
x
Reference in New Issue
Block a user