From 7f6ade463b1e8e4a1302e0f1751ab9ee502cba4a Mon Sep 17 00:00:00 2001 From: tudnai Date: Thu, 18 Jun 2020 15:14:54 -0700 Subject: [PATCH] - Disk Write!!! - Some Debug code - Super low power ECO mode --- A2Mac.xcodeproj/project.pbxproj | 6 +- .../xcdebugger/Expressions.xcexplist | 101 +-- A2Mac/ViewController.swift | 5 + src/cpu/6502.c | 19 +- src/cpu/6502.h | 1 + src/dev/disk/woz.c | 205 ++++-- src/dev/disk/woz.h | 8 +- src/dev/disk/woz_backup.c | 628 ++++++++++++++++++ src/dev/mem/mmio.h | 16 +- src/util/disassembler.h | 12 +- 10 files changed, 863 insertions(+), 138 deletions(-) create mode 100644 src/dev/disk/woz_backup.c diff --git a/A2Mac.xcodeproj/project.pbxproj b/A2Mac.xcodeproj/project.pbxproj index 95ac1b0..3d0eb85 100644 --- a/A2Mac.xcodeproj/project.pbxproj +++ b/A2Mac.xcodeproj/project.pbxproj @@ -611,6 +611,7 @@ 32BFFB5922EACC630003B53F /* A2Mac */ = { isa = PBXGroup; children = ( + 32BFFB5E22EACC660003B53F /* Assets.xcassets */, 326ED2EE232D7A0000A41337 /* 6502_functional_test.bin */, 32B18438233FAB3900DBB4AB /* verticies.swift */, 32BFFB5A22EACC630003B53F /* AppDelegate.swift */, @@ -623,7 +624,6 @@ 32440BA22480D5C0000F9DA1 /* LoRes.swift */, 32DBF7632334657900DD50E7 /* HiRes.swift */, 32EDB7A123272CA80073AF2D /* fail1.txt */, - 32BFFB5E22EACC660003B53F /* Assets.xcassets */, 32BFFB6022EACC660003B53F /* Main.storyboard */, 323D042D248980600086A901 /* Preferences.storyboard */, 32BFFB6322EACC660003B53F /* Info.plist */, @@ -1410,7 +1410,7 @@ "@executable_path/../Frameworks", ); OTHER_CFLAGS = ( - "-D_NO_DISASSEMBLER", + "-DDISASSEMBLER", "-D_NO_INTERRUPT_CHECK_PER_STEP", "-D_NO_CLK_ABSOLUTE_PRECISE", ); @@ -1447,7 +1447,7 @@ ); LLVM_LTO = YES_THIN; OTHER_CFLAGS = ( - "-D_NO_DISASSEMBLER", + "-DDISASSEMBLER", "-D_NO_INTERRUPT_CHECK_PER_STEP", "-D_NO_CLK_ABSOLUTE_PRECISE", ); diff --git a/A2Mac.xcodeproj/project.xcworkspace/xcuserdata/trudnai.xcuserdatad/xcdebugger/Expressions.xcexplist b/A2Mac.xcodeproj/project.xcworkspace/xcuserdata/trudnai.xcuserdatad/xcdebugger/Expressions.xcexplist index 54242f7..9c1f43a 100644 --- a/A2Mac.xcodeproj/project.xcworkspace/xcuserdata/trudnai.xcuserdatad/xcdebugger/Expressions.xcexplist +++ b/A2Mac.xcodeproj/project.xcworkspace/xcuserdata/trudnai.xcuserdatad/xcdebugger/Expressions.xcexplist @@ -14,13 +14,10 @@ + contextName = "specialized closure #1 in ViewController.Update():ViewController.swift"> - - + value = "self.HiRes.frame"> @@ -67,7 +64,7 @@ contextName = "closure #1 in ViewController.Update():ViewController.swift"> + value = "txtArr"> @@ -76,10 +73,10 @@ value = "txt"> + value = "MEMcfg.is_80STORE"> + value = "MEMcfg.txt_page_2"> @@ -117,14 +114,6 @@ - - - - - - @@ -221,13 +210,13 @@ contextName = "spkr_update:speaker.c"> + value = "(uint8_t)spkr_samples[455]"> + value = "(uint8_t)spkr_samples[452]"> @@ -275,7 +264,7 @@ value = "pdl_value[pdl]"> + value = "normalized_time >= pdl_value[pdl] ? 255 : 0"> @@ -287,7 +276,7 @@ value = "1 * 512 * (1 - ( 3300 / 3300.0 ))"> + value = "normalized_time"> @@ -304,13 +293,13 @@ value = "textLines"> + value = "hires.layer"> + value = "hires.frame"> @@ -326,7 +315,7 @@ contextName = "LoRes.Update():LoRes.swift"> + value = "blockChanged[ screenIdx ]"> @@ -335,7 +324,7 @@ value = "UInt8(block & 4)"> + value = "UInt8( (block >> 4) & 0x0F )"> @@ -354,10 +343,10 @@ contextName = "set_flags_NZC:common.h"> + value = "(unsigned)test "> + value = "(unsigned)0xFF"> @@ -399,9 +388,6 @@ - - + value = "linAddr"> + value = "ctx?.bitsPerComponent"> @@ -522,6 +508,9 @@ + + @@ -532,10 +521,7 @@ value = "ctx?.height"> - - + value = "ctx?.data"> @@ -551,13 +537,13 @@ contextName = "HiRes.compute():HiRes.swift"> + value = "computePipelineState.maxTotalThreadsPerThreadgroup"> + value = "UnsafeRawBufferPointer(result)"> @@ -583,10 +569,10 @@ value = "mouseLocation"> + value = "clkfrm"> + value = "txtArr"> @@ -629,6 +615,32 @@ + + + + + + + + + + + + + + + + + + @@ -647,10 +659,10 @@ value = "Apple2_64K_AUX + 0xC600"> + value = "(void*)rom"> + value = "Apple2_64K_RAM + 0xC600"> @@ -675,10 +687,13 @@ + contextName = "BRA:6502_instr_branch.h"> + value = ""> + + diff --git a/A2Mac/ViewController.swift b/A2Mac/ViewController.swift index 7e68a78..64d757d 100644 --- a/A2Mac/ViewController.swift +++ b/A2Mac/ViewController.swift @@ -289,6 +289,7 @@ class ViewController: NSViewController { if ( cpuMode == cpuMode_eco ) { cpuState = cpuState_running; + upd.resume() } // print("keyDown") @@ -826,6 +827,10 @@ class ViewController: NSViewController { // #endif break + + case cpuState_halted: + upd.suspend() + break default: break diff --git a/src/cpu/6502.c b/src/cpu/6502.c index 3ee6747..309273f 100644 --- a/src/cpu/6502.c +++ b/src/cpu/6502.c @@ -286,11 +286,11 @@ INLINE int m6502_Step() { case 0x36: ROL( addr_zp_X() ); return 6; // ROL zpg,X case 0x37: RLA( addr_zp_X() ); return 6; // RLA* zpx 6 (undocumented) case 0x38: SEC(); return 2; // SEC - case 0x39: AND( src_abs_Y() ); return 4; // AND abs,Y + case 0x39: AND( src_abs_Y() ); return 4+1; // AND abs,Y case 0x3A: NOP(); return 2; // NOP* 2 (undocumented) case 0x3B: RLA( addr_abs_Y() ); return 7; // RLA* aby 7 (undocumented) case 0x3C: NOP(); src_abs_X(); return 4; // NOP* abx 4 (undocumented) - case 0x3D: AND( src_abs_X() ); return 4; // AND abs,X + case 0x3D: AND( src_abs_X() ); return 4+1; // AND abs,X case 0x3E: ROL( addr_abs_X() ); return 7; // ROL abs,X case 0x3F: RLA( addr_abs_X() ); return 7; // RLA* abx 7 (undocumented) case 0x40: RTI(); return 6; // RTI @@ -318,11 +318,11 @@ INLINE int m6502_Step() { case 0x56: LSR( addr_zp_X() ); return 6; // LSR zpg,X case 0x57: SRE( addr_ind_X() ); return 6; // SRE* zpx 6 (undocumented) case 0x58: CLI(); return 2; // CLI - case 0x59: EOR( src_abs_Y() ); return 4; // EOR abs,Y + case 0x59: EOR( src_abs_Y() ); return 4+1; // EOR abs,Y case 0x5A: NOP(); return 2; // NOP* 2 (undocumented) case 0x5B: SRE( addr_abs_Y() ); return 7; // SRE* aby 7 (undocumented) case 0x5C: NOP(); src_abs_X(); return 4; // NOP* abx 4 (undocumented) - case 0x5D: EOR( src_abs_X() ); return 4; // EOR abs,X + case 0x5D: EOR( src_abs_X() ); return 4+1; // EOR abs,X case 0x5E: LSR( addr_abs_X() ); return 7; // LSR abs,X case 0x5F: SRE( addr_abs_X() ); return 7; // SRE* abx 7 (undocumented) case 0x60: RTS(); return 6; // RTS @@ -333,7 +333,7 @@ INLINE int m6502_Step() { case 0x65: ADC( src_zp() ); return 3; // ADC zpg case 0x66: ROR( addr_zp() ); return 5; // ROR zpg case 0x67: RRA( addr_zp() ); return 5; // RRA* zp 5 (undocumented) - case 0x68: PLA(); break; // PLA + case 0x68: PLA(); return 4; // PLA case 0x69: ADC( imm() ); return 2; // ADC imm case 0x6A: RORA(); return 2; // ROR A case 0x6B: ARC( imm() ); return 2; // ARR/ARC* imm 2 (undocumented) @@ -350,11 +350,11 @@ INLINE int m6502_Step() { case 0x76: ROR( addr_zp_X() ); return 6; // ROR zpg,X case 0x77: RRA( addr_zp_X() ); return 6; // RRA* zpx 6 (undocumented) case 0x78: SEI(); return 2; // SEI - case 0x79: ADC( src_abs_Y() ); return 4; // ADC abs,Y + case 0x79: ADC( src_abs_Y() ); return 4+1; // ADC abs,Y case 0x7A: NOP(); return 2; // NOP* 2 (undocumented) case 0x7B: RRA( addr_abs_Y() ); return 7; // RRA* aby 7 (undocumented) case 0x7C: NOP(); src_abs_X(); return 4; // NOP* abx 4 (undocumented) - case 0x7D: ADC( src_abs_X() ); return 4; // ADC abs,X + case 0x7D: ADC( src_abs_X() ); return 4+1; // ADC abs,X case 0x7E: ROR( addr_abs_X() ); return 7; // ROR abs,X case 0x7F: RRA( addr_abs_X() ); return 7; // RRA* abx 7 (undocumented) case 0x80: NOP(); imm(); return 2; // NOP* imm 2 (undocumented) @@ -556,7 +556,8 @@ void m6502_Run() { for ( ; ; ) #endif { - + + // TODO: clkfrm is already increamented!!! printDisassembly(outdev); #ifdef INTERRUPT_CHECK_PER_STEP @@ -592,6 +593,7 @@ void m6502_Run() { } + // TODO: WHat if we dynamically reduce or increace CPU speed? m6502.clktime += clk_6502_per_frm; if( diskAccelerator_count ) { @@ -697,6 +699,7 @@ void m6502_ColdReset( const char * bundlePath, const char * romFileName ) { resetMemory(); + // for DEBUG ONLY!!! // outdev = fopen("/Users/trudnai/Library/Containers/com.gamealloy.A2Mac/Data/disassembly_new.log", "w+"); // if (outdev == NULL) { // outdev = stdout; diff --git a/src/cpu/6502.h b/src/cpu/6502.h index 9abe613..ed026ba 100644 --- a/src/cpu/6502.h +++ b/src/cpu/6502.h @@ -120,6 +120,7 @@ typedef struct m6502_s { typedef struct disassembly_s { + uint64_t clk; // clock time 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 diff --git a/src/dev/disk/woz.c b/src/dev/disk/woz.c index b039b10..8d4cd4e 100644 --- a/src/dev/disk/woz.c +++ b/src/dev/disk/woz.c @@ -16,8 +16,10 @@ WOZread_t WOZread = {0}; -uint8_t WOZlatch = 0; +WOZread_t WOZwrite = {0}; + +int trackWRoffset = 0; int trackOffset = 0; int bitOffset = 0; uint64_t clkelpased; @@ -88,6 +90,7 @@ typedef enum wozTrackState_e { wozTrackState_trk2, wozTrackState_sec1, wozTrackState_sec2, + wozTrackState_END, } wozTrackState_t; @@ -96,21 +99,17 @@ int vol = 0; int trk = 0; int sec = 0; - int bitOffs_D5_SecHdr = 0; // bit offset of D5 Sector Header +wozTrackState_t woz_decodeTrkSec( uint8_t data, uint64_t clkelapsed, int bitOffs ) { + static wozTrackState_t wozTrackState = wozTrackState_Start; - int bitOffs = 0; + if ( clkelpased > 40 ) { + // spent too much time on reading, we cannot reliably decode sector header + wozTrackState = wozTrackState_Start; + } - for ( int byteOffs = 0; byteOffs < WOZ_TRACK_BYTE_COUNT; byteOffs++ ) { - - reg.data = woz_trks[track].data[ byteOffs ]; - - for ( int i = 0; i < 8; i++ ) { - reg.shift16 <<= 1; - - if (reg.shift & 0x80) { switch (wozTrackState) { case wozTrackState_D5: - switch (reg.shift) { + switch (data) { case 0xAA: // printf("D5 AA at bitOffset:%d\n", bitOffs); wozTrackState = wozTrackState_D5_AA; @@ -124,7 +123,7 @@ int sec = 0; break; case wozTrackState_D5_AA: - switch (reg.shift) { + switch (data) { case 0x96: wozTrackState = wozTrackState_vol1; // printf("D5 AA 96 at bitOffset:%d\n", bitOffs); @@ -139,47 +138,72 @@ int sec = 0; break; case wozTrackState_vol1: - vol = (reg.shift << 1) | 1; + vol = (data << 1) | 1; wozTrackState = wozTrackState_vol2; break; case wozTrackState_vol2: - vol &= reg.shift; + vol &= data; wozTrackState = wozTrackState_trk1; break; case wozTrackState_trk1: - trk = (reg.shift << 1) | 1; + trk = (data << 1) | 1; wozTrackState = wozTrackState_trk2; break; case wozTrackState_trk2: - trk &= reg.shift; + trk &= data; wozTrackState = wozTrackState_sec1; break; case wozTrackState_sec1: - sec = (reg.shift << 1) | 1; + sec = (data << 1) | 1; wozTrackState = wozTrackState_sec2; break; case wozTrackState_sec2: - sec &= reg.shift; - wozTrackState = wozTrackState_Start; + sec &= data; + wozTrackState = wozTrackState_END; - printf("Vol:%d Track:%d Sector:%d at bitOffset:%d\n", vol, trk, sec, bitOffs_D5_SecHdr); +// printf("Vol:%d Track:%d Sector:%d at bitOffset:%d\n", vol, trk, sec, bitOffs_D5_SecHdr); break; default: - if ( reg.shift == 0xD5 ) { + if ( data == 0xD5 ) { // printf("D5 at bitOffset:%d\n", bitOffs); wozTrackState = wozTrackState_D5; bitOffs_D5_SecHdr = bitOffs; } + else { + wozTrackState = wozTrackState_Start; + } break; } + return wozTrackState; +} + + +void woz_loadTrack( int track ) { + trackEntry_t reg = {0}; + + reg.shift = 0; + reg.data = 0; + prepared_track[0] = reg; + + int bitOffs = 0; + + for ( int byteOffs = 0; byteOffs < WOZ_TRACK_BYTE_COUNT; byteOffs++ ) { + + reg.data = woz_trks[track].data[ byteOffs ]; + + for ( int i = 0; i < 8; i++ ) { + reg.shift16 <<= 1; + + if (reg.shift & 0x80) { + woz_decodeTrkSec( reg.shift, 0, bitOffs ); reg.shift = 0; } @@ -221,21 +245,25 @@ uint8_t woz_read() { trackOffset %= usedBytes; // preroll data stream - WOZread.shift16 = 0; + WOZread.shift = 0; WOZread.data = woz_trks[track].data[trackOffset++]; trackOffset %= usedBytes; + trackWRoffset = trackOffset; - WOZread.shift16 <<= bitOffset; + WOZread.shift <<= bitOffset; + WOZwrite = WOZread; for ( int i = 0; i < magicShiftOffset; i++ ) { for ( ; bitOffset < 8; bitOffset++ ) { - WOZread.shift16 <<= 1; + WOZread.shift <<= 1; + WOZwrite.shift <<= 1; if ( WOZread.valid ) { - WOZread.shift = 0; + WOZread.latch = 0; } } - WOZread.data = woz_trks[track].data[trackOffset++]; + trackWRoffset = trackOffset; + WOZwrite.data = WOZread.data = woz_trks[track].data[trackOffset++]; trackOffset %= usedBytes; bitOffset = 0; } @@ -247,17 +275,18 @@ uint8_t woz_read() { for ( uint64_t i = 0; i < bitForward; i++ ) { if ( ++bitOffset >= 8 ) { bitOffset = 0; + trackWRoffset = trackOffset; trackOffset++; trackOffset %= usedBytes; WOZwrite.data = WOZread.data = woz_trks[track].data[trackOffset]; } - WOZread.shift16 <<= 1; - WOZwrite.shift16 <<= 1; + WOZread.shift <<= 1; + WOZwrite.shift <<= 1; if ( WOZread.valid ) { - WOZread.shift = 0; + WOZread.latch = 0; } } } @@ -265,16 +294,16 @@ uint8_t woz_read() { // to avoid infinite loop and to search for bit 7 high for ( int i = 0; i < usedBytes * 8; i++ ) { if ( WOZread.valid ) { - WOZread.shift = 0; + WOZread.latch = 0; // if (outdev) fprintf(outdev, "byte: %02X\n", byte); - if ( woz_decodeTrkSec(WOZwrite.shift, clkelpased, trackOffset * 8 + bitOffset) == wozTrackState_END ) { - if (disk_sfx_enabled) printf("vol:%d trk:%d sec:%d\n", vol, trk, sec); + if ( woz_decodeTrkSec(WOZwrite.latch, clkelpased, trackOffset * 8 + bitOffset) == wozTrackState_END ) { + if (outdev) fprintf(outdev, "vol:%d trk:%d sec:%d\n", vol, trk, sec); } - if (disk_sfx_enabled) printf("elpased:%lld read: %02X\n", clkelpased, WOZwrite.shift); + if (outdev) fprintf(outdev, "elpased:%lld read: %02X\n", clkelpased, WOZwrite.latch); - return WOZwrite.shift; + return WOZwrite.latch; } if ( ++bitOffset >= 8 ) { @@ -286,8 +315,8 @@ uint8_t woz_read() { WOZwrite.data = WOZread.data = woz_trks[track].data[trackOffset]; } - WOZread.shift16 <<= 1; - WOZwrite.shift16 <<= 1; + WOZread.shift <<= 1; + WOZwrite.shift <<= 1; } // if (outdev) fprintf(outdev, "TIME OUT!\n"); } @@ -295,59 +324,90 @@ uint8_t woz_read() { return rand(); } +void printbits ( uint8_t byte ) { + fprintf(outdev, "%02X:", byte); + + for ( int bit = 7; bit >= 0; bit-- ) { + fprintf(outdev, "%d", byte & (1 << bit) ? 1 : 0 ); + } + fprintf(outdev, " "); +} + +void printWozBuffer (const char * s, int n, WOZread_t WOZbuf ) { + // for DEBUG ONLY!!! + if (outdev) { + fprintf(outdev, "%s (%d) ", s, n); + + for ( int i = 5; i >= 0; i-- ) { + printbits(WOZbuf.out[i]); + } + + printbits(WOZbuf.latch); + printbits(WOZbuf.data); + + fprintf(outdev, "\n"); + } +} void woz_write( uint8_t data ) { int track = woz_tmap.phase[disk.phase.count]; if (outdev) fprintf(outdev, "track: %d (%d) ", track, disk.phase.count); if ( track >= 40 ) { - dbgPrintf("TRCK TOO HIGH!\n"); + dbgPrintf("TRACK TOO HIGH!\n"); return; } - static int clkBeforeSync = 0; - clkelpased = m6502.clktime + clkfrm - m6502.clklast; m6502.clklast = m6502.clktime + clkfrm; - clkBeforeSync += clkelpased; - uint16_t usedBytes = woz_trks[track].bytes_used < WOZ_TRACK_BYTE_COUNT ? woz_trks[track].bytes_used : WOZ_TRACK_BYTE_COUNT; if ( usedBytes ) { - if ( disk_sfx_enabled ) printf("elpased:%llu data:$%02X\n", clkelpased, data); - if ( clkelpased > 40 ) { - if ( disk_sfx_enabled ) printf("I/O ERROR : %llu (clkBefRd:%d)\n", clkelpased, clkBeforeSync); - } + // for DEBUG ONLY!!! + if (outdev) fprintf(outdev, "elpased:%llu data:$%02X\n", clkelpased, data); + printWozBuffer("*start", 0, WOZwrite); - // sync data? - if ( WOZwrite.shift == 0xFF ) { - // yes, we have to push in extra 2 zeros - for ( int i = 0; i < 2; i++ ) { - WOZread.shift16 <<= 1; - WOZwrite.shift16 <<= 1; - + if ( clkelpased > 32 ) { +// if (outdev) fprintf(outdev, "I/O ERROR : %llu\n", clkelpased); + + uint64_t bitForward = (clkelpased - 32) >> 2; + + // simulate disk spin over time + while ( bitForward-- ) { if ( ++bitOffset >= 8 ) { bitOffset = 0; trackWRoffset = trackOffset; trackOffset++; trackOffset %= usedBytes; + +// WOZwrite.data = + WOZread.data = woz_trks[track].data[trackOffset]; + } + + WOZread.shift <<= 1; + WOZwrite.shift <<= 1; + + if ( WOZread.valid ) { + WOZread.latch = 0; } } } - - // now we can latch data -// uint8_t latch = data; + + // ok now we can latch data WOZwrite.data = WOZread.data = data; + printWozBuffer("datain", 0, WOZwrite); + int i = 8; // 8 bit to shift in + // shift in 8 bits of data and write it out - for ( int i = 0; i < 8; i++ ) { + while ( i-- ) { if ( ++bitOffset >= 8 ) { // write out first part - woz_trks[track].data[trackWRoffset] = WOZwrite.shift; + woz_trks[track].data[trackWRoffset] = WOZwrite.latch; bitOffset = 0; trackWRoffset = trackOffset; @@ -356,31 +416,38 @@ void woz_write( uint8_t data ) { // simulate shift in data (path of write latch is already loaded, we should not overwrite it!) uint8_t new = woz_trks[track].data[trackOffset]; - new &= (1 << i) - 1; + new >>= i + 1; WOZread.data |= new; - WOZwrite.data |= new; +// WOZwrite.data |= new; + printWozBuffer("shl1in", i, WOZwrite); + WOZread.shift <<= 1; + WOZwrite.shift <<= 1; break; } - WOZread.shift16 <<= 1; - WOZwrite.shift16 <<= 1; + WOZread.shift <<= 1; + WOZwrite.shift <<= 1; + printWozBuffer("shift1", i, WOZwrite); }; - + printWozBuffer("shift1", 9, WOZwrite); + // write the remaining bits without altering WOZ track offsets and indexes - WOZread_t WOZtmp = WOZwrite; - int bo = bitOffset; +// WOZread_t WOZtmp = WOZwrite; +// int bo = bitOffset; // second half - for ( int i = 8; i; i-- ) { - if ( ++bo >= 8 ) { + while ( i-- ) { + if ( ++bitOffset >= 8 ) { // write out first part - woz_trks[track].data[trackWRoffset] = WOZtmp.shift; + woz_trks[track].data[trackWRoffset] = WOZwrite.latch; break; } - WOZtmp.shift16 <<= 1; + WOZwrite.shift <<= 1; + printWozBuffer("shift2", i, WOZwrite); }; + printWozBuffer("shift2", 9, WOZwrite); } diff --git a/src/dev/disk/woz.h b/src/dev/disk/woz.h index 66f1774..0b9c366 100644 --- a/src/dev/disk/woz.h +++ b/src/dev/disk/woz.h @@ -104,13 +104,16 @@ typedef union { typedef union { struct { uint8_t data; - uint8_t shift; + uint8_t latch; + + // for debug and diag purposes + uint8_t out[6]; }; struct { uint16_t lower15 : 15; uint16_t valid : 1; }; - uint16_t shift16; + uint64_t shift; } WOZread_t; #endif // WOZ_REAL_SPIN @@ -126,6 +129,7 @@ extern uint8_t WOZlatch; extern uint8_t woz_read(void); +extern void woz_write( uint8_t data ); extern int woz_loadFile( const char * filename ); diff --git a/src/dev/disk/woz_backup.c b/src/dev/disk/woz_backup.c new file mode 100644 index 0000000..87c6b0b --- /dev/null +++ b/src/dev/disk/woz_backup.c @@ -0,0 +1,628 @@ +// +// woz.c +// A2Mac +// +// Created by Tamas Rudnai on 2/15/20. +// Copyright © 2020 GameAlloy. All rights reserved. +// + +#include +#include + +#include "woz.h" +#include "disk.h" +#include "6502.h" +#include "common.h" + + +WOZread_t WOZread = {0}; +uint8_t WOZlatch = 0; + +int trackOffset = 0; +int bitOffset = 0; +uint64_t clkelpased; + + +woz_header_t woz_header; +woz_chunk_header_t woz_chunk_header; +woz_tmap_t woz_tmap; +woz_trks_t woz_trks; +int track_loaded = -1; + + + +#pragma pack(push, 1) + +typedef union trackEntry_u { + struct { + uint8_t data; + uint8_t shift; + }; + uint16_t shift16; +} trackEntry_t; + +#pragma pack(pop) + +trackEntry_t prepared_track[WOZ_TRACK_BYTE_COUNT]; + +typedef enum readState_e { + readNormal = 0, + readHold, +} readState_t; + +readState_t readState = readNormal; +uint8_t readLatch; + + +void woz_loadTrack_old( int track ) { + trackEntry_t reg = {0}; + + reg.shift = woz_trks[track].data[0]; + reg.data = woz_trks[track].data[1]; + prepared_track[0] = reg; + + for ( int offs = 1; offs < WOZ_TRACK_BYTE_COUNT; offs++ ) { + + for ( int i = 0; i < 8; i++ ) { + if (reg.shift & 0x80) { + reg.shift = 0; + } + + reg.shift16 <<= 1; + } + + reg.data = woz_trks[track].data[ (offs + 1) % WOZ_TRACK_BYTE_COUNT ]; + prepared_track[offs] = reg; + } +} + + +typedef enum wozTrackState_e { + wozTrackState_Start = 0, + wozTrackState_D5, + wozTrackState_D5_AA, + wozTrackState_D5_AA_96, + wozTrackState_vol1, + wozTrackState_vol2, + wozTrackState_trk1, + wozTrackState_trk2, + wozTrackState_sec1, + wozTrackState_sec2, +} wozTrackState_t; + + +void woz_loadTrack( int track ) { + trackEntry_t reg = {0}; + wozTrackState_t wozTrackState = wozTrackState_Start; + + reg.shift = 0; + reg.data = 0; + prepared_track[0] = reg; + + int vol = 0; + int trk = 0; + int sec = 0; + + int bitOffs_D5_SecHdr = 0; // bit offset of D5 Sector Header + + int bitOffs = 0; + + for ( int byteOffs = 0; byteOffs < WOZ_TRACK_BYTE_COUNT; byteOffs++ ) { + + reg.data = woz_trks[track].data[ byteOffs ]; + + for ( int i = 0; i < 8; i++ ) { + reg.shift16 <<= 1; + + if (reg.shift & 0x80) { + switch (wozTrackState) { + case wozTrackState_D5: + switch (reg.shift) { + case 0xAA: +// printf("D5 AA at bitOffset:%d\n", bitOffs); + wozTrackState = wozTrackState_D5_AA; + break; + + default: + wozTrackState = wozTrackState_Start; + break; + } + + break; + + case wozTrackState_D5_AA: + switch (reg.shift) { + case 0x96: + wozTrackState = wozTrackState_vol1; +// printf("D5 AA 96 at bitOffset:%d\n", bitOffs); +// printf("Sector Header at bitOffset:%d\n", bitOffs_D5_SecHdr); + break; + + default: + wozTrackState = wozTrackState_Start; + break; + } + + break; + + case wozTrackState_vol1: + vol = (reg.shift << 1) | 1; + wozTrackState = wozTrackState_vol2; + break; + + case wozTrackState_vol2: + vol &= reg.shift; + wozTrackState = wozTrackState_trk1; + break; + + case wozTrackState_trk1: + trk = (reg.shift << 1) | 1; + wozTrackState = wozTrackState_trk2; + break; + + case wozTrackState_trk2: + trk &= reg.shift; + wozTrackState = wozTrackState_sec1; + break; + + case wozTrackState_sec1: + sec = (reg.shift << 1) | 1; + wozTrackState = wozTrackState_sec2; + break; + + case wozTrackState_sec2: + sec &= reg.shift; + wozTrackState = wozTrackState_Start; + + printf("Vol:%d Track:%d Sector:%d at bitOffset:%d\n", vol, trk, sec, bitOffs_D5_SecHdr); + + break; + + default: + if ( reg.shift == 0xD5 ) { +// printf("D5 at bitOffset:%d\n", bitOffs); + wozTrackState = wozTrackState_D5; + bitOffs_D5_SecHdr = bitOffs; + } + break; + } + + reg.shift = 0; + } + + bitOffs++; + } + } +} + + +uint8_t woz_read() { + + int track = woz_tmap.phase[disk.phase.count]; + if (outdev) fprintf(outdev, "track: %d (%d) ", track, disk.phase.count); + if ( track >= 40 ) { + dbgPrintf("TRCK TOO HIGH!\n"); + return rand(); + } + +#ifdef WOZ_REAL_SPIN + if ( track != track_loaded ) { + woz_loadTrack(track); + track_loaded = track; + } + + WOZread.shift32 = 0; + bitOffset = (m6502.clktime >> 2) & 7; + trackOffset = (m6502.clktime >> 5) % WOZ_TRACK_BYTE_COUNT; + WOZread.next = woz_trks[track].data[ (trackOffset +1) % WOZ_TRACK_BYTE_COUNT ]; + WOZread.data = woz_trks[track].data[ trackOffset ]; + WOZread.prev = woz_trks[track].data[ (trackOffset -1) % WOZ_TRACK_BYTE_COUNT ]; + WOZread.shift = woz_trks[track].data[ (trackOffset -2) % WOZ_TRACK_BYTE_COUNT ]; + + printf("clk:%llu bo:%u to:%u W:%08X\n", m6502.clktime, bitOffset, trackOffset, WOZread.shift32); + + uint8_t state = 0; + // simulating the continous shift register in Disk ][ + for (int i = bitOffset + 16; i; --i) { + + WOZread.shift32 <<= 1; + + switch (state) { + case 0: + WOZlatch = WOZread.shift; + if ( WOZread.valid ) { + state = 1; + WOZread.shift = 0; + } + break; + + case 1: + // we do not latch the shift register for one 4us cycle + state = 0; + break; + + default: + // this should not happen + state = 0; + break; + } + +// printf("shft1: W:%08X L:%02X\n", WOZread.shift32, WOZlatch); + + } + + printf("clk:%llu bo:%u to:%u W:%08X B:%02X\n", m6502.clktime, bitOffset, trackOffset, WOZread.shift32, WOZlatch); + if ( WOZlatch & 0x80 ) { + printf("WOZlatch: %02X\n", WOZlatch); + + static int readState = 0; + static int vol = 0; + static int trk = 0; + static int sec = 0; + + switch (readState) { + case 0: + if ( 0xD5 == WOZlatch ) readState = 1; + else readState = 0; + break; + + case 1: + if ( 0xAA == WOZlatch ) readState = 2; + else readState = 0; + break; + + case 2: + if ( 0x96 == WOZlatch ) { + readState = 3; + printf("sector header marker\n"); + } + else if ( 0xAD == WOZlatch ) { + readState = 10; + printf("sector data marker\n"); + } + else readState = 0; + break; + + case 3: // sector header, vol number 1 + readState++; + vol = (WOZlatch << 1) | 1; + break; + + case 4: // sector header, vol number 2 + readState++; + vol &= WOZlatch; + printf("vol:%u ", vol); + break; + + case 5: // sector header, trk number 1 + readState++; + trk = (WOZlatch << 1) | 1; + break; + + case 6: // sector header, trk number 2 + readState++; + trk &= WOZlatch; + printf("trk:%u ", trk); + break; + + case 7: // sector header, sec number 1 + readState++; + sec = (WOZlatch << 1) | 1; + break; + + case 8: // sector header, sec number 2 + readState = 0; + sec &= WOZlatch; + printf("sec:%u\n", sec); + break; + + + default: + readState = 0; + break; + } + } + +// switch ( WOZlatch ) { +// case 0xAA: +// case 0x96: +//// printf("%02X ", WOZlatch); +// printf("clk:%llu bo:%u to:%u B:%02X\n", m6502.clktime, bitOffset, trackOffset, WOZlatch); +// break; +// +// default: +// break; +// } + + return WOZlatch; + + +#elif defined( WOZ_REAL_SPIN2 ) +// clkelpased = m6502.clktime - disk.clk_last_read; +// disk.clk_last_read = m6502.clktime; + + bitOffset = (m6502.clktime >> 2) & 7; + trackOffset = (m6502.clktime >> 5) % WOZ_TRACK_BYTE_COUNT; + trackEntry_t reg = prepared_track[trackOffset]; + + do { + switch (readState) { + case readNormal: + readLatch = reg.shift; + break; + + case readHold: + default: + readState = readNormal; + break; + } + + if (reg.shift & 0x80) { + reg.shift = 0; + readState = readHold; + } + + reg.shift16 <<= 1; + } while ( --bitOffset > 0 ); + + printf("READ: clk:%llu to:%u bo:%llu B:%02X\n", m6502.clktime, trackOffset, (m6502.clktime >> 2) & 7, readLatch); + return readLatch; + + +#elif defined( WOZ_SEARCH_NEXTSECT ) + + static int clkBeforeSync = 0; + + clkelpased = m6502.clktime + clkfrm - m6502.clklast; + m6502.clklast = m6502.clktime + clkfrm; + + clkBeforeSync += clkelpased; + + const int clkBeforeAdjusting = 1024; + const int magicShiftOffset = 8192; + + uint16_t usedBytes = woz_trks[track].bytes_used < WOZ_TRACK_BYTE_COUNT ? woz_trks[track].bytes_used : WOZ_TRACK_BYTE_COUNT; + + if ( usedBytes ) { +// printf("elpased : %llu (clkBefRd:%d)\n", clkelpased, clkBeforeSync); + if ( clkelpased > clkBeforeAdjusting ) { +// printf("NEED SYNC : %llu (clkBefRd:%d)\n", clkelpased, clkBeforeSync); + clkBeforeSync = 0; +// bitOffset = (clkelpased >> 2) & 7; +// bitOffset = 0; +// trackOffset += clkelpased >> 5; +// trackOffset %= usedBytes; + +// preroll data stream +// WOZread.shift16 = 0; +// WOZread.data = woz_trks[track].data[trackOffset++]; +// trackOffset %= usedBytes; + +// WOZread.shift16 <<= bitOffset; + + int w = 2; // 2 x 0xD5 + + for ( int i = 0; i < usedBytes * 8; i++ ) { + if ( ++bitOffset >= 8 ) { + bitOffset = 0; + + trackOffset++; + trackOffset %= usedBytes; + + WOZread.data = woz_trks[track].data[trackOffset]; + } + + WOZread.shift16 <<= 1; + if ( WOZread.valid ) { + uint8_t byte = WOZread.shift; + WOZread.shift = 0; + + // find next sector or end of sector + if ( byte == 0xD5 ) { + // actually 2 sectors, because of DOS 3.3 interleaving algoritm + if ( --w <= 0 ) { + return byte; + } + } + } + } + + } + + // to avoid infinite loop and to search for bit 7 high + for ( int i = 0; i < usedBytes * 8; i++ ) { + if ( ++bitOffset >= 8 ) { + bitOffset = 0; +// if ( ++trackOffset >= WOZ_TRACK_BYTE_COUNT ) { +// trackOffset = 0; +// } + trackOffset++; + trackOffset %= usedBytes; + +// printf("offs:%u\n", trackOffset); + WOZread.data = woz_trks[track].data[trackOffset]; + } + + WOZread.shift16 <<= 1; + if ( WOZread.valid ) { + uint8_t byte = WOZread.shift; +// printf("%02X ", byte); + WOZread.shift = 0; + if (outdev) fprintf(outdev, "byte: %02X\n", byte); + + return byte; + } + } + if (outdev) fprintf(outdev, "TIME OUT!\n"); + } + + return rand(); + +#else // WOZ_REAL_SPIN + static int clkBeforeSync = 0; + + clkelpased = m6502.clktime + clkfrm - m6502.clklast; + m6502.clklast = m6502.clktime + clkfrm; + + clkBeforeSync += clkelpased; + + const int clkBeforeAdjusting = 512; + const int magicShiftOffset = 50; + + uint16_t usedBytes = woz_trks[track].bytes_used < WOZ_TRACK_BYTE_COUNT ? woz_trks[track].bytes_used : WOZ_TRACK_BYTE_COUNT; + + if ( usedBytes ) { +// printf("elpased : %llu (clkBefRd:%d)\n", clkelpased, clkBeforeSync); + + if ( clkelpased > clkBeforeAdjusting ) { +// printf("NEED SYNC : %llu (clkBefRd:%d)\n", clkelpased, clkBeforeSync); + clkBeforeSync = 0; + bitOffset = (clkelpased >> 2) & 7; + trackOffset += clkelpased >> 5; + trackOffset %= usedBytes; + + // preroll data stream + WOZread.shift16 = 0; + WOZread.data = woz_trks[track].data[trackOffset++]; + trackOffset %= usedBytes; + + WOZread.shift16 <<= bitOffset; + + for ( int i = 0; i < magicShiftOffset; i++ ) { + for ( ; bitOffset < 8; bitOffset++ ) { + WOZread.shift16 <<= 1; + + if ( WOZread.valid ) { + WOZread.shift = 0; + } + } + WOZread.data = woz_trks[track].data[trackOffset++]; + trackOffset %= usedBytes; + bitOffset = 0; + } + } + else { + uint64_t bitForward = (clkelpased >> 2); + + // to avoid infinite loop and to search for bit 7 high + for ( uint64_t i = 0; i < bitForward; i++ ) { + if ( ++bitOffset >= 8 ) { + bitOffset = 0; + trackOffset++; + trackOffset %= usedBytes; + + WOZread.data = woz_trks[track].data[trackOffset]; + } + + WOZread.shift16 <<= 1; + + if ( WOZread.valid ) { + WOZread.shift = 0; + } + } + } + + // to avoid infinite loop and to search for bit 7 high + for ( int i = 0; i < usedBytes * 8; i++ ) { + if ( WOZread.valid ) { + uint8_t byte = WOZread.shift; + WOZread.shift = 0; +// if (outdev) fprintf(outdev, "byte: %02X\n", byte); + + return byte; + } + + if ( ++bitOffset >= 8 ) { + bitOffset = 0; + trackOffset++; + trackOffset %= usedBytes; + + WOZread.data = woz_trks[track].data[trackOffset]; + } + + WOZread.shift16 <<= 1; + } +// if (outdev) fprintf(outdev, "TIME OUT!\n"); + } + + return rand(); + +#endif // WOZ_REAL_SPIN + +} + + +int woz_loadFile( const char * filename ) { + +// char fullpath[256]; +// +// strcpy(fullpath, resourcePath); +// strcat(fullpath, "/"); +// strcat(fullpath, filename); + + FILE * f = fopen(filename, "rb"); + if (f == NULL) { + perror("Failed to read WOZ: "); + return WOZ_ERR_FILE_NOT_FOUND; + } + + fread( &woz_header, 1, sizeof(woz_header_t), f); + if ( woz_header.magic != WOZ1_MAGIC ) { + return WOZ_ERR_NOT_WOZ_FILE; + } + + 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) ) { + if ( r ) { + return WOZ_ERR_BAD_CHUNK_HDR; + } + // ok we just reached the end of the file, we should exit properly, close file handle etc + 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 ) { + return WOZ_ERR_BAD_DATA; + } + } + + // make sure we are skipping unhandled chunks correctly + fseek(f, foffs + woz_chunk_header.size, SEEK_SET); + } + + fclose(f); + + + // DO NOT COMMIT THIS! ONLY FOR DEBUG!!! +// woz_loadTrack(0x11); + + return WOZ_ERR_OK; +} + + diff --git a/src/dev/mem/mmio.h b/src/dev/mem/mmio.h index 91f1975..8544929 100644 --- a/src/dev/mem/mmio.h +++ b/src/dev/mem/mmio.h @@ -564,7 +564,7 @@ INLINE uint8_t ioRead( uint16_t addr ) { if ( cpuMode == cpuMode_eco ) { // check if this is a busy keyboard poll (aka waiting for user input) if ( IOframe < 16 ) { - clk_6502_per_frm_max = 6502; // Absolute low mode + clk_6502_per_frm_max = 6502; // Let it run for a bit to display character -- nerd number :-) cpuState = cpuState_halting; } } @@ -1064,13 +1064,13 @@ INLINE uint8_t memread8_low( uint16_t addr ) { INLINE uint8_t memread8_high( uint16_t addr ) { return RDHIMEM[addr]; } -//INLINE uint8_t memread8( uint16_t addr ) { -// if (addr >= 0xC000) { -// return memread8_high(addr); -// } -// -// return memread8_low(addr); -//} +INLINE uint8_t memread8( uint16_t addr ) { + if (addr >= 0xC000) { + return memread8_high(addr); + } + + return memread8_low(addr); +} /** Naive implementation of RAM read from address **/ diff --git a/src/util/disassembler.h b/src/util/disassembler.h index 8f9d1da..0af7ae5 100644 --- a/src/util/disassembler.h +++ b/src/util/disassembler.h @@ -39,14 +39,16 @@ unsigned long long discnt = 0; } \ } +// TODO: We should add a new field for clk counter, so we can print that out _before_ execution, not after... #define disNewInstruction() { \ if ( m6502.dbgLevel.trace ) { \ + disassembly.clk = m6502.clktime + clkfrm; \ snprintf(disassembly.addr, 5, "%04X ", m6502.PC); \ - *disassembly.opcode = '\0'; \ + disassembly.opcode[0] = '\0'; \ disassembly.pOpcode = disassembly.opcode; \ - *disassembly.inst = '\0'; \ - *disassembly.oper = '\0'; \ - *disassembly.comment = '\0'; \ + disassembly.inst[0] = '\0'; \ + disassembly.oper[0] = '\0'; \ + disassembly.comment[0] = '\0'; \ } \ } @@ -108,7 +110,7 @@ INLINE void printDisassembly( FILE * f ) { // Virtual ][ Style fprintf( f, "%llu\t%llu\t%s: %-11s%-4s%s\t0x%02X\t0x%02X\t0x%02X\t0x%02X\t0x%02X\n", // Virtual ][ style ++discnt, - m6502.clktime + clkfrm, + disassembly.clk, disassembly.addr, disassembly.opcode, disassembly.inst,