- Disk read acceleration

- Source code organization 1
This commit is contained in:
Tamas Rudnai 2020-02-16 20:38:38 -08:00
parent e33c1dc34b
commit 7e2d93f043
13 changed files with 699 additions and 451 deletions

View File

@ -9,6 +9,9 @@
/* Begin PBXBuildFile section */
32439F8722ECD8AD0077AAE0 /* 6502.c in Sources */ = {isa = PBXBuildFile; fileRef = 32439F7422ECD8AD0077AAE0 /* 6502.c */; };
32439F8822ECD8AD0077AAE0 /* apple.rom in Resources */ = {isa = PBXBuildFile; fileRef = 32439F8422ECD8AD0077AAE0 /* apple.rom */; };
325EB62F23F8856F00C6B4A4 /* woz.c in Sources */ = {isa = PBXBuildFile; fileRef = 325EB62E23F8856F00C6B4A4 /* woz.c */; };
325EB63623F8F78300C6B4A4 /* disk.c in Sources */ = {isa = PBXBuildFile; fileRef = 325EB63523F8F78300C6B4A4 /* disk.c */; };
325EB63923F9E48100C6B4A4 /* common.c in Sources */ = {isa = PBXBuildFile; fileRef = 325EB63823F9E48100C6B4A4 /* common.c */; };
3262F37623E169F8008BDB95 /* spk_dn.wav in Resources */ = {isa = PBXBuildFile; fileRef = 3262F37423E169F8008BDB95 /* spk_dn.wav */; };
3262F37723E169F8008BDB95 /* spk_up.wav in Resources */ = {isa = PBXBuildFile; fileRef = 3262F37523E169F8008BDB95 /* spk_up.wav */; };
326ED2EF232D7A0000A41337 /* 6502_functional_test.bin in Resources */ = {isa = PBXBuildFile; fileRef = 326ED2EE232D7A0000A41337 /* 6502_functional_test.bin */; };
@ -84,11 +87,15 @@
32439F8422ECD8AD0077AAE0 /* apple.rom */ = {isa = PBXFileReference; lastKnownFileType = file; path = apple.rom; sourceTree = "<group>"; };
32439F8522ECD8AD0077AAE0 /* 6502.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = 6502.h; sourceTree = "<group>"; };
32439F8622ECD8AD0077AAE0 /* common.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = common.h; sourceTree = "<group>"; };
325EB62D23F8856F00C6B4A4 /* woz.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = woz.h; sourceTree = "<group>"; };
325EB62E23F8856F00C6B4A4 /* woz.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = woz.c; sourceTree = "<group>"; };
325EB63423F8F78300C6B4A4 /* disk.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = disk.h; sourceTree = "<group>"; };
325EB63523F8F78300C6B4A4 /* disk.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = disk.c; sourceTree = "<group>"; };
325EB63823F9E48100C6B4A4 /* common.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = common.c; sourceTree = "<group>"; };
3262F37423E169F8008BDB95 /* spk_dn.wav */ = {isa = PBXFileReference; lastKnownFileType = audio.wav; path = spk_dn.wav; sourceTree = "<group>"; };
3262F37523E169F8008BDB95 /* spk_up.wav */ = {isa = PBXFileReference; lastKnownFileType = audio.wav; path = spk_up.wav; 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>"; };
@ -177,6 +184,43 @@
path = instructions;
sourceTree = "<group>";
};
325EB63123F8861A00C6B4A4 /* src */ = {
isa = PBXGroup;
children = (
325EB63723F9492200C6B4A4 /* util */,
325EB63223F8862A00C6B4A4 /* dev */,
);
path = src;
sourceTree = "<group>";
};
325EB63223F8862A00C6B4A4 /* dev */ = {
isa = PBXGroup;
children = (
325EB63323F8863100C6B4A4 /* disk */,
);
path = dev;
sourceTree = "<group>";
};
325EB63323F8863100C6B4A4 /* disk */ = {
isa = PBXGroup;
children = (
325EB62D23F8856F00C6B4A4 /* woz.h */,
325EB62E23F8856F00C6B4A4 /* woz.c */,
325EB63423F8F78300C6B4A4 /* disk.h */,
325EB63523F8F78300C6B4A4 /* disk.c */,
);
path = disk;
sourceTree = "<group>";
};
325EB63723F9492200C6B4A4 /* util */ = {
isa = PBXGroup;
children = (
32439F8622ECD8AD0077AAE0 /* common.h */,
325EB63823F9E48100C6B4A4 /* common.c */,
);
path = util;
sourceTree = "<group>";
};
3262F37823E17013008BDB95 /* Resources */ = {
isa = PBXGroup;
children = (
@ -214,6 +258,7 @@
32BFFB5922EACC630003B53F /* A2Mac */ = {
isa = PBXGroup;
children = (
325EB63123F8861A00C6B4A4 /* src */,
3262F37823E17013008BDB95 /* Resources */,
32439F7522ECD8AD0077AAE0 /* instructions */,
32439F8522ECD8AD0077AAE0 /* 6502.h */,
@ -224,7 +269,6 @@
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 */,
@ -238,7 +282,6 @@
32BFFB6322EACC660003B53F /* Info.plist */,
32BFFB6422EACC660003B53F /* A2Mac.entitlements */,
32439F7222ECD8AC0077AAE0 /* A2Mac-Bridging-Header.h */,
326C50802383CC0B00A05420 /* woz.h */,
);
path = A2Mac;
sourceTree = "<group>";
@ -459,8 +502,11 @@
files = (
32439F8722ECD8AD0077AAE0 /* 6502.c in Sources */,
32DBF7642334657900DD50E7 /* HiRes.swift in Sources */,
325EB63623F8F78300C6B4A4 /* disk.c in Sources */,
325EB63923F9E48100C6B4A4 /* common.c in Sources */,
32BFFB5D22EACC630003B53F /* ViewController.swift in Sources */,
32C4532E233345430000EBA1 /* MonitorView.swift in Sources */,
325EB62F23F8856F00C6B4A4 /* woz.c in Sources */,
32BFFB5B22EACC630003B53F /* AppDelegate.swift in Sources */,
32C45306232E3EEF0000EBA1 /* RepeatingTimer.swift in Sources */,
);

View File

@ -13,37 +13,14 @@
#include <unistd.h>
#include <string.h>
#include <time.h>
#include "6502.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;
uint64_t clklast = 0;
uint64_t clkelpased = 0;
uint16_t trackOffset = 0;
uint8_t bitOffset = 0;
FILE * outdev = NULL;
void ViewController_spk_up_play(void);
void ViewController_spk_dn_play(void);
#ifdef DEBUG
#define INLINE
#else
#define INLINE static __attribute__((always_inline))
#endif
#include "common.h"
@ -80,9 +57,9 @@ m6502_t m6502 = {
0, // PC
0, // SP
// 0, // clk
0, // clktime
0, // clklast
0, // trace
0, // step
0, // brk
@ -91,7 +68,8 @@ m6502_t m6502 = {
0, // bra_true
0, // bra_false
0, // compile
HLT // IF
HLT, // IF
};
disassembly_t disassembly;
@ -791,7 +769,7 @@ void m6502_Run() {
// mhz = clktime / (execution_time * M);
}
void read_rom( const char * filename, const uint8_t * rom, const uint16_t addr ) {
void read_rom( const char * filename, uint8_t * rom, const uint16_t addr ) {
FILE * f = fopen(filename, "rb");
if (f == NULL) {
perror("Failed: ");
@ -808,64 +786,6 @@ void read_rom( const char * filename, const uint8_t * rom, const uint16_t addr )
}
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;
@ -906,12 +826,12 @@ void m6502_ColdReset() {
read_rom("/Users/trudnai/Library/Containers/com.gamealloy.A2Mac/Data/DISK_II_C600.ROM", Apple2_64K_RAM, 0xC600);
// 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");
// woz_loadFile("/Users/trudnai/Library/Containers/com.gamealloy.A2Mac/Data/DOS 3.3 System Master.woz");
// woz_loadFile("/Users/trudnai/Library/Containers/com.gamealloy.A2Mac/Data/Hard Hat Mack - Disk 1, Side A.woz");
// read_woz("/Users/trudnai/Library/Containers/com.gamealloy.A2Mac/Data/Merlin-8 v2.48 (DOS 3.3).woz");
// read_woz("/Users/trudnai/Library/Containers/com.gamealloy.A2Mac/Data/DOS3.3.Launcher.2.2.woz");
read_woz("/Users/trudnai/Library/Containers/com.gamealloy.A2Mac/Data/Apple DOS 3.3 January 1983.woz");
// woz_loadFile("/Users/trudnai/Library/Containers/com.gamealloy.A2Mac/Data/Merlin-8 v2.48 (DOS 3.3).woz");
// woz_loadFile("/Users/trudnai/Library/Containers/com.gamealloy.A2Mac/Data/DOS3.3.Launcher.2.2.woz");
woz_loadFile("/Users/trudnai/Library/Containers/com.gamealloy.A2Mac/Data/Apple DOS 3.3 January 1983.woz");
m6502.A = m6502.X = m6502.Y = 0xFF;
// reset vector

View File

@ -9,21 +9,14 @@
#ifndef __6502_H__
#define __6502_H__
#import <stdint.h>
#include <stdint.h>
#include "common.h"
extern unsigned long long MHz_6502;
extern unsigned long long clk_6502_per_frm;
#ifdef DEBUG
//#define dbgPrintf(format, ...) printf (format, ## __VA_ARGS__)
#define dbgPrintf(format, ...)
#define dbgPrintf2(format, ...) if(outdev) fprintf(outdev, format, ## __VA_ARGS__)
#else
#define dbgPrintf(format, ...)
#define dbgPrintf2(format, ...)
#endif
typedef enum {
NO_INT,
HLT,
@ -33,6 +26,7 @@ typedef enum {
SOFTRESET,
} interrupt_t;
typedef struct debugLevel_s {
uint8_t trace : 1;
uint8_t step : 1;
@ -44,6 +38,7 @@ typedef struct debugLevel_s {
uint8_t compile : 1;
} debugLevel_t;
typedef struct m6502_s {
uint8_t A; // Accumulator
uint8_t X; // X index register
@ -74,6 +69,7 @@ typedef struct m6502_s {
// unsigned clk; // Clock Counter
uint64_t clktime;
uint64_t clklast;
debugLevel_t dbgLevel; // 0: No Debug, 1: Disassembly Only, 2: Run till BRK, 3: StepByStep
@ -110,4 +106,47 @@ extern void m6502_ColdReset(void);
extern void m6502_Run(void);
extern void kbdInput ( uint8_t code );
INLINE void set_flags_N( const uint8_t test ) {
m6502.N = BITTEST(test, 7);
}
INLINE void set_flags_V( const uint8_t test ) {
m6502.V = BITTEST(test, 6);
}
INLINE void set_flags_Z( const uint8_t test ) {
m6502.Z = test == 0;
}
INLINE void set_flags_C( const int16_t test ) {
m6502.C = test >= 0;
}
INLINE void set_flags_NZ( const uint8_t test ) {
set_flags_N(test);
set_flags_Z(test);
}
INLINE void set_flags_NV( const uint8_t test ) {
set_flags_N(test);
set_flags_V(test);
}
INLINE void set_flags_NVZ( const uint8_t test ) {
set_flags_NZ(test);
set_flags_V(test);
}
INLINE void set_flags_NZC( const int16_t test ) {
set_flags_NZ(test);
set_flags_C(test);
}
//INLINE void set_flags_NZCV( int test ) {
// set_flags_NZC(test);
// set_flags_V(test);
//}
#endif /* __6502_H__ */

View File

@ -11,20 +11,8 @@
#include "common.h"
#include "6502.h"
typedef union {
struct {
uint8_t latch;
uint8_t shift;
};
struct {
uint16_t lower15 : 15;
uint16_t valid : 1;
};
uint16_t shift16;
} WOZread_t;
WOZread_t WOZread = {0};
#include "disk.h"
#include "woz.h"
typedef union address16_u {
@ -226,202 +214,12 @@ enum mmio {
#define PAGESIZE 256
#define PAGES 16
//uint8_t ram_0[PAGESIZE];
//uint8_t ram_1[PAGESIZE];
//uint8_t ram_2[PAGESIZE];
//uint8_t ram_3[PAGESIZE];
//uint8_t ram_4[PAGESIZE];
//uint8_t ram_5[PAGESIZE];
//uint8_t ram_6[PAGESIZE];
//uint8_t ram_7[PAGESIZE];
//uint8_t ram_8[PAGESIZE];
//uint8_t ram_9[PAGESIZE];
//uint8_t ram_A[PAGESIZE];
//uint8_t ram_B[PAGESIZE];
//uint8_t aui_C[PAGESIZE];
//uint8_t rom_D[PAGESIZE];
//uint8_t rom_E[PAGESIZE];
//uint8_t rom_F[PAGESIZE];
//
//uint8_t * ram[PAGES] = {
// ram_0,
// ram_1,
// ram_2,
// ram_3,
// ram_4,
// ram_5,
// ram_6,
// ram_7,
// ram_8,
// ram_9,
// ram_A,
// ram_B,
// aui_C,
// rom_D,
// rom_E,
// rom_F,
//};
//uint8_t ( * mmio_read [ 64 * KB ] )( uint16_t addr );
#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 int minDiskTrackNum = 0;
static const int maxDiskTrackNum = 39;
static const int minDiskPhaseStates = 8; // 4 quarters * 2 because of two neighbouring magnets can be activated at the same time which gets you a half quarter movement
static const int minDiskPhaseNum = 0;
static const int maxDiskPhaseNum = minDiskPhaseStates * maxDiskTrackNum;
struct phase_t {
uint8_t lastMagnet : 4;
uint8_t magnet : 4;
int count;
} phase = { 0, 0, 0 };
//static const int8_t phaseTransition[4][4] = {
// { 0, -1, 0, +1 },
// { +1, 0, -1, 0 },
// { 0, +1, 0, -1 },
// { -1, 0, +1, 0 },
//};
//static const int phaseTransition[16][16] = {
//// 0000 0001 0010 0011 0100 0101 0110 0111 1000 1001 1010 1011 1100 1101 1110 1111
// { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // 0000
// { 0, 0, -2, -1, 0, 0, 0, 0, +2, +1, 0, 0, 0, 0, 0, 0 }, // 0001
// { 0, +2, 0, +1, -2, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // 0010
// { 0, +1, -1, 0, 0, 0, -2, 0, 0, +2, 0, 0, 0, 0, 0, 0 }, // 0011
// { 0, 0, +2, 0, 0, 0, +1, 0, -2, 0, 0, 0, -1, 0, 0, 0 }, // 0100
// { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // 0101
// { 0, 0, +1, +2, -1, 0, 0, 0, 0, 0, 0, 0, -2, 0, 0, 0 }, // 0110
// { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // 0111
// { 0, -2, 0, 0, +2, 0, 0, 0, 0, -1, 0, 0, +1, 0, 0, 0 }, // 1000
// { 0, -1, 0, -2, 0, 0, 0, 0, +1, 0, 0, 0, +2, 0, 0, 0 }, // 1001
// { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // 1010
// { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // 1011
// { 0, 0, 0, 0, +1, 0, +2, 0, -1, -2, 0, 0, 0, 0, 0, 0 }, // 1100
// { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // 1101
// { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // 1110
// { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // 1111
//};
// Magnet States --> Stepper Motor Position
//
// N
// 0001
// NW | NE
// 1001 | 0011
// |
// W 1000 ------- o ------- 0010 E
// |
// 1100 | 0110
// SW | SE
// 0100
// S
// motor position from the magnet state
// -1 means invalid, not supported
static const int magnet_to_Poistion[16] = {
// 0000 0001 0010 0011 0100 0101 0110 0111 1000 1001 1010 1011 1100 1101 1110 1111
-1, 0, 2, 1, 4, -1, 3, -1, 6, 7, -1, -1, 5, -1, -1, -1
};
static const int position_to_direction[8][8] = {
// N NE E SE S SW W NW
// 0 1 2 3 4 5 6 7
{ 0, 1, 2, 3, 0, -3, -2, -1 }, // 0 N
{ -1, 0, 1, 2, 3, 0, -3, -2 }, // 1 NE
{ -2, -1, 0, 1, 2, 3, 0, -3 }, // 2 E
{ -3, -2, -1, 0, 1, 2, 3, 0 }, // 3 SE
{ 0, -3, -2, -1, 0, 1, 2, 3 }, // 4 S
{ 3, 0, -3, -2, -1, 0, 1, 2 }, // 5 SW
{ 2, 3, 0, -3, -2, -1, 0, 1 }, // 6 W
{ 1, 2, 3, 0, -3, -2, -1, 0 }, // 7 NW
};
INLINE void diskII_phase() {
int position = magnet_to_Poistion[phase.magnet];
if ( position >= 0 ) {
int lastPosition = phase.count & 7;
int direction = position_to_direction[lastPosition][position];
phase.count += direction;
if ( phase.count < minDiskPhaseNum ) {
phase.count = minDiskPhaseNum;
}
else if ( phase.count > maxDiskPhaseNum ) {
phase.count = maxDiskPhaseNum;
}
printf(", p:%d d:%d l:%d: ph:%u trk:%u)", position, direction, lastPosition, phase.count, woz_tmap.phase[phase.count]);
}
else {
// invalid magnet config
}
printf("\n");
}
INLINE uint8_t ioRead( uint16_t addr ) {
dbgPrintf("mmio read:%04X\n", addr);
uint8_t currentMagnet = 0;
int clk = 0;
switch (addr) {
case io_KBD:
@ -441,8 +239,6 @@ INLINE uint8_t ioRead( uint16_t addr ) {
return RAM[io_SPKR];
// CASE_DISKII(6)
case io_MEM_RDRAM_NOWR_2:
case io_MEM_RDROM_WRAM_2:
case io_MEM_RDROM_NOWR_2:
@ -523,10 +319,10 @@ INLINE uint8_t ioRead( uint16_t addr ) {
case io_DISK_PHASE2_OFF + SLOT6:
case io_DISK_PHASE3_OFF + SLOT6:
currentMagnet = (addr - io_DISK_PHASE0_OFF - SLOT6) / 2;
phase.magnet &= ~(1 << currentMagnet);
printf("io_DISK_PHASE%u_OFF (S%u, ps:%X) ", currentMagnet, 6, phase.magnet);
disk.phase.magnet &= ~(1 << currentMagnet);
printf("io_DISK_PHASE%u_OFF (S%u, ps:%X) ", currentMagnet, 6, disk.phase.magnet);
diskII_phase();
disk_phase();
return 0;
case io_DISK_PHASE0_ON + SLOT6:
@ -534,10 +330,10 @@ INLINE uint8_t ioRead( uint16_t addr ) {
case io_DISK_PHASE2_ON + SLOT6:
case io_DISK_PHASE3_ON + SLOT6: {
currentMagnet = (addr - io_DISK_PHASE0_ON - SLOT6) / 2;
phase.magnet |= 1 << currentMagnet;
printf("io_DISK_PHASE%u_ON (S%u, ps:%X) ", currentMagnet, 6, phase.magnet);
disk.phase.magnet |= 1 << currentMagnet;
printf("io_DISK_PHASE%u_ON (S%u, ps:%X) ", currentMagnet, 6, disk.phase.magnet);
diskII_phase();
disk_phase();
return 0;
}
@ -558,49 +354,9 @@ INLINE uint8_t ioRead( uint16_t addr ) {
return 0;
case io_DISK_READ + SLOT6:
dbgPrintf("io_DISK_READ (S%u)\n", 6);
int track = woz_tmap.phase[phase.count];
if (outdev) fprintf(outdev, "track: %d (%d) ", track, phase.count);
if ( track >= 40 ) {
dbgPrintf("TRCK TOO HIGH!\n");
return rand();
}
return disk_read();
clkelpased = m6502.clktime - clklast;
clklast = m6502.clktime;
if ( clkelpased > 100 ) {
bitOffset = (clkelpased % 32) / 4;
trackOffset += (clkelpased / 32) % WOZ_TRACK_BYTE_COUNT;
WOZread.latch = woz_trks[track].data[trackOffset];
}
// to avoid infinite loop and to search for bit 7 high
for ( int i = 0; i < WOZ_TRACK_BYTE_COUNT * 8; i++ ) {
if ( ++bitOffset >= 8 ) {
bitOffset = 0;
// if ( ++trackOffset >= WOZ_TRACK_BYTE_COUNT ) {
// trackOffset = 0;
// }
trackOffset++;
trackOffset %= WOZ_TRACK_BYTE_COUNT;
// printf("offs:%u\n", trackOffset);
WOZread.latch = 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();
case io_DISK_WRITE + SLOT6:
dbgPrintf2("io_DISK_WRITE (S%u)\n", 6);
return 0;

View File

@ -1,89 +0,0 @@
//
// common.h
// 6502
//
// Created by Tamas Rudnai on 7/14/19.
// Copyright © 2019 GameAlloy. All rights reserved.
//
#ifndef __COMMON_H__
#define __COMMON_H__
#include "6502.h"
#define K 1000ULL
#define M (K * K)
#define G (M * K)
#define T (G * K)
#define PG 256ULL
#define KB 1024ULL
#define MB (KB * KB)
#define GB (MB * KB)
#define TB (GB * KB)
typedef
union {
uint8_t bits;
struct {
uint8_t b0:1;
uint8_t b1:1;
uint8_t b2:1;
uint8_t b3:1;
uint8_t b4:1;
uint8_t b5:1;
uint8_t b6:1;
uint8_t b7:1;
};
} bits_t;
#define BITTEST(n,x) ((bits_t)(n)).b##x
INLINE void set_flags_N( const uint8_t test ) {
m6502.N = BITTEST(test, 7);
}
INLINE void set_flags_V( const uint8_t test ) {
m6502.V = BITTEST(test, 6);
}
INLINE void set_flags_Z( const uint8_t test ) {
m6502.Z = test == 0;
}
INLINE void set_flags_C( const int16_t test ) {
m6502.C = test >= 0;
}
INLINE void set_flags_NZ( const uint8_t test ) {
set_flags_N(test);
set_flags_Z(test);
}
INLINE void set_flags_NV( const uint8_t test ) {
set_flags_N(test);
set_flags_V(test);
}
INLINE void set_flags_NVZ( const uint8_t test ) {
set_flags_NZ(test);
set_flags_V(test);
}
INLINE void set_flags_NZC( const int16_t test ) {
set_flags_NZ(test);
set_flags_C(test);
}
//INLINE void set_flags_NZCV( int test ) {
// set_flags_NZC(test);
// set_flags_V(test);
//}
#endif // __COMMON_H__

View File

@ -11,6 +11,7 @@
INLINE void BRA( int8_t reladdr ) {
m6502.PC += reladdr;
m6502.clktime++;
#ifdef DEBUG
if ( reladdr == -2 ) {
dbgPrintf2("Infinite Loop at %04X!\n", m6502.PC);

View File

@ -20,7 +20,7 @@
--------------------------------------------
implied BRK 00 1 7
**/
INLINE void BRK() {
INLINE int BRK() {
dbgPrintf("BRK ");
disPrintf(disassembly.inst, "BRK");
PUSH_addr(m6502.PC +1); // PC +2, however, fetch already incremented it by 1
@ -29,6 +29,8 @@ INLINE void BRK() {
PUSH(m6502.SR);
m6502.I = 1;
m6502.PC = memread16(IRQ_VECTOR);
return 7;
}
/**

73
A2Mac/src/dev/disk/disk.c Normal file
View File

@ -0,0 +1,73 @@
//
// disk.c
// A2Mac
//
// Created by Tamas Rudnai on 2/15/20.
// Copyright © 2020 GameAlloy. All rights reserved.
//
#include "disk.h"
#include "6502.h"
#include "common.h"
#include "woz.h"
disk_t disk = {
{ 0, 0, 0 }, // phase
};
// motor position from the magnet state
// -1 means invalid, not supported
const int magnet_to_Poistion[16] = {
// 0000 0001 0010 0011 0100 0101 0110 0111 1000 1001 1010 1011 1100 1101 1110 1111
-1, 0, 2, 1, 4, -1, 3, -1, 6, 7, -1, -1, 5, -1, -1, -1
};
const int position_to_direction[8][8] = {
// N NE E SE S SW W NW
// 0 1 2 3 4 5 6 7
{ 0, 1, 2, 3, 0, -3, -2, -1 }, // 0 N
{ -1, 0, 1, 2, 3, 0, -3, -2 }, // 1 NE
{ -2, -1, 0, 1, 2, 3, 0, -3 }, // 2 E
{ -3, -2, -1, 0, 1, 2, 3, 0 }, // 3 SE
{ 0, -3, -2, -1, 0, 1, 2, 3 }, // 4 S
{ 3, 0, -3, -2, -1, 0, 1, 2 }, // 5 SW
{ 2, 3, 0, -3, -2, -1, 0, 1 }, // 6 W
{ 1, 2, 3, 0, -3, -2, -1, 0 }, // 7 NW
};
void disk_phase() {
int position = magnet_to_Poistion[disk.phase.magnet];
if ( position >= 0 ) {
int lastPosition = disk.phase.count & 7;
int direction = position_to_direction[lastPosition][position];
disk.phase.count += direction;
if( disk.phase.count < minDiskPhaseNum ) {
disk.phase.count = minDiskPhaseNum;
}
else
if( disk.phase.count > maxDiskPhaseNum ) {
disk.phase.count = maxDiskPhaseNum;
}
// printf(", p:%d d:%d l:%d: ph:%u trk:%u)", position, direction, lastPosition, phase.count, woz_tmap.phase[phase.count]);
}
else {
// invalid magnet config
}
printf("\n");
}
uint8_t disk_read() {
dbgPrintf("io_DISK_READ (S%u)\n", 6);
return woz_read();
}

55
A2Mac/src/dev/disk/disk.h Normal file
View File

@ -0,0 +1,55 @@
//
// disk.h
// A2Mac
//
// Created by Tamas Rudnai on 2/15/20.
// Copyright © 2020 GameAlloy. All rights reserved.
//
#ifndef disk_h
#define disk_h
#include "common.h"
#define minDiskTrackNum 0
#define maxDiskTrackNum 39
#define minDiskPhaseStates 8 // 4 quarters * 2 because of two neighbouring magnets can be activated at the same time which leaves motor in a half quarter movement
#define minDiskPhaseNum 0
#define maxDiskPhaseNum (minDiskPhaseStates * maxDiskTrackNum)
typedef struct phase_s {
uint8_t lastMagnet : 4;
uint8_t magnet : 4;
int count;
} phase_t;
typedef struct disk_s {
phase_t phase;
} disk_t;
extern disk_t disk;
// Magnet States --> Stepper Motor Position
//
// N
// 0001
// NW | NE
// 1001 | 0011
// |
// W 1000 ------- o ------- 0010 E
// |
// 1100 | 0110
// SW | SE
// 0100
// S
extern const int magnet_to_Poistion[16];
extern const int position_to_direction[8][8];
extern void disk_phase();
extern uint8_t disk_read();
#endif /* disk_h */

303
A2Mac/src/dev/disk/woz.c Normal file
View File

@ -0,0 +1,303 @@
//
// woz.c
// A2Mac
//
// Created by Tamas Rudnai on 2/15/20.
// Copyright © 2020 GameAlloy. All rights reserved.
//
#include <stdlib.h>
#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;
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
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 - clklast;
clklast = m6502.clktime & ~3;
bitOffset = (clkelpased >> 2) & 7;
trackOffset += (clkelpased >> 5) % WOZ_TRACK_BYTE_COUNT;
WOZread.data = woz_trks[track].data[trackOffset];
// to avoid infinite loop and to search for bit 7 high
for ( int i = 0; i < WOZ_TRACK_BYTE_COUNT * 8; i++ ) {
if ( ++bitOffset >= 8 ) {
bitOffset = 0;
// if ( ++trackOffset >= WOZ_TRACK_BYTE_COUNT ) {
// trackOffset = 0;
// }
trackOffset++;
trackOffset %= WOZ_TRACK_BYTE_COUNT;
// 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
clkelpased = m6502.clktime - m6502.clklast;
m6502.clklast = m6502.clktime;
if ( clkelpased > 100 ) {
// printf("NEED SYNC : %llu\n", clkelpased);
bitOffset = (clkelpased >> 2) & 7;
trackOffset += ((clkelpased >> 5) +64) % WOZ_TRACK_BYTE_COUNT;
WOZread.data = woz_trks[track].data[trackOffset];
}
// to avoid infinite loop and to search for bit 7 high
for ( int i = 0; i < WOZ_TRACK_BYTE_COUNT * 8; i++ ) {
if ( ++bitOffset >= 8 ) {
bitOffset = 0;
// if ( ++trackOffset >= WOZ_TRACK_BYTE_COUNT ) {
// trackOffset = 0;
// }
trackOffset++;
trackOffset %= WOZ_TRACK_BYTE_COUNT;
// 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();
#endif // WOZ_REAL_SPIN
}
void woz_loadFile( 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);
}

View File

@ -1,17 +1,28 @@
//
// woz1.h
// woz.h
// A2Mac
//
// Created by Tamas Rudnai on 11/18/19.
// Copyright © 2019 GameAlloy. All rights reserved.
// Created by Tamas Rudnai on 2/15/20.
// Copyright © 2020 GameAlloy. All rights reserved.
//
#ifndef woz_h
#define woz_h
#include <stdio.h>
#include "common.h"
#define DISKII_MAXTRACKS 80
#define DISKII_PHASES 4
#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
#pragma pack(push)
#pragma pack(1)
@ -62,4 +73,53 @@ typedef woz_track_t woz_trks_t[DISKII_MAXTRACKS];
#pragma pack(pop)
#define __NO__WOZ_REAL_SPIN2
#ifdef WOZ_REAL_SPIN
typedef union {
struct {
uint8_t next;
uint8_t data;
uint8_t prev;
uint8_t shift;
};
struct {
uint32_t lower : 31;
uint32_t valid : 1;
};
uint32_t shift32;
} WOZread_t;
#else // WOZ_REAL_SPIN
typedef union {
struct {
uint8_t data;
uint8_t shift;
};
struct {
uint16_t lower15 : 15;
uint16_t valid : 1;
};
uint16_t shift16;
} WOZread_t;
#endif // WOZ_REAL_SPIN
extern WOZread_t WOZread;
extern uint8_t WOZlatch;
//extern woz_header_t woz_header;
//extern woz_chunk_header_t woz_chunk_header;
//extern woz_tmap_t woz_tmap;
//extern woz_trks_t woz_trks;
extern uint8_t woz_read();
extern void woz_loadFile( const char * filename );
#endif /* woz_h */

15
A2Mac/src/util/common.c Normal file
View File

@ -0,0 +1,15 @@
//
// common.c
// A2Mac
//
// Created by Tamas Rudnai on 2/16/20.
// Copyright © 2020 GameAlloy. All rights reserved.
//
#include <stdio.h>
#include "common.h"
FILE * outdev = NULL;

67
A2Mac/src/util/common.h Normal file
View File

@ -0,0 +1,67 @@
//
// common.h
// 6502
//
// Created by Tamas Rudnai on 7/14/19.
// Copyright © 2019 GameAlloy. All rights reserved.
//
#ifndef __COMMON_H__
#define __COMMON_H__
#include <stdio.h>
#include <unistd.h>
#ifdef DEBUG
#define INLINE
#else
#define INLINE static __attribute__((always_inline))
#endif
#ifdef DEBUG
//#define dbgPrintf(format, ...) printf (format, ## __VA_ARGS__)
#define dbgPrintf(format, ...)
#define dbgPrintf2(format, ...) if(outdev) fprintf(outdev, format, ## __VA_ARGS__)
#else
#define dbgPrintf(format, ...)
#define dbgPrintf2(format, ...)
#endif
#define K 1000ULL
#define M (K * K)
#define G (M * K)
#define T (G * K)
#define PG 256ULL
#define KB 1024ULL
#define MB (KB * KB)
#define GB (MB * KB)
#define TB (GB * KB)
typedef
union {
uint8_t bits;
struct {
uint8_t b0:1;
uint8_t b1:1;
uint8_t b2:1;
uint8_t b3:1;
uint8_t b4:1;
uint8_t b5:1;
uint8_t b6:1;
uint8_t b7:1;
};
} bits_t;
#define BITTEST(n,x) ((bits_t)(n)).b##x
extern FILE * outdev;
#endif // __COMMON_H__