Appalm/src/memio.c

1803 lines
61 KiB
C
Raw Normal View History

2019-04-21 13:53:32 +00:00
#include <PalmOS.h>
#include "Apple2.h"
extern UInt16 grMode;
UInt16 memIOU, vidIOU, kbdIOU, spkrIOU, btnIOU[3], pdlIOU[2], pdlResetIOU[2];
UInt8 kbdBuffer[16];
UInt8 kbdHead, kbdCount;
UInt8 *AppleMemory;
UInt8 *AuxMemory;
UInt8 *AppleROM;
UInt8 *BootROM;
READBYTE *ReadFunction;
WRITEBYTE *WriteFunction;
UInt8 auxDirty = 0;
void showDiskName(UInt16, Char *);
void showDriveState(UInt16, Boolean);
UInt8 RIOM(UInt16);
void WIOM(UInt16, UInt8);
UInt8 RC3M(UInt16);
void clrVidFuncs(UInt16);
void toggleVideoSoftSwitch(UInt8);
/*
* Function prototypes for sector nibblizing
*/
static void init_GCR_table(void);
static UInt8 gcr_read_nibble(void);
static void gcr_write_nibble( UInt8 );
static void decode62( UInt8* );
static void encode62( UInt8* );
static void FM_encode( UInt8 );
static UInt8 FM_decode(void);
static void write_sync( int );
static int read_address_field( int*, int*, int* );
static void write_address_field( int, int, int );
static int read_data_field(void);
static void write_data_field(void);
int NibblesToSectors(UInt8 *nibbles, UInt8 *sectors, int volume, int track);
void SectorsToNibbles(UInt8 *sectors, UInt8 *nibbles, int volume, int track);
void initMemory(void)
{
vidIOU = SS_TEXT;
memIOU =
kbdIOU =
spkrIOU =
btnIOU[0] =
btnIOU[1] =
btnIOU[2] =
pdlIOU[0] =
pdlIOU[1] = 0;
pdlResetIOU[0] =
pdlResetIOU[1] = 0x80;
kbdHead =
kbdCount = 0;
MemSet(AppleMemory, 65536, 0);
MemSet(AuxMemory, 16384+2048, 0);
MemSet(ReadFunction, 1024, 0);
MemSet(WriteFunction, 1024, 0);
loadROM();
MemMove(AppleMemory + 0xC100, AppleROM, 0x3F00);
setMemFuncs();
}
/*****************************************************************************\
* *
* ROM Access *
* *
\*****************************************************************************/
/* Apple ROM Paging */
void READONLY(UInt16, UInt8);
UInt8 RRMP(UInt16);
void awrap_ROMReadWrite(void)
{
asm(".global RRMP");
asm(".global READONLY");
asm("RRMP:");
asm("clr.l %d0");
asm("READONLY:");
asm("rts");
}
RDMEM_CWRAP(REXP, address)
{
if (!SS_ISSET(memIOU, SS_SLOTCXROM) && address == 0xCFFF)
{
MemMove(AppleMemory + 0xCE00, BootROM, 256);
SS_RESET(memIOU, SS_EXPNROM);
return (0x00);
}
else
{
return (AppleMemory[address]);
}
}
RDMEM_CWRAP(RC3M, address)
{
if (!SS_ISSET(memIOU, SS_SLOTC3ROM))
{
SS_SET(memIOU, SS_EXPNROM);
MemMove(AppleMemory + 0xC800, AppleROM + 0x700, 2048);
}
return (AppleMemory[address]);
}
void loadROM(void)
{
DmOpenRef romDB;
LocalID romID;
MemHandle romRec;
UInt8 *roms;
UInt32 romStart;
UInt16 count;
romID = DmFindDatabase(0, "apple2e.rom");
romDB = DmOpenDatabase(0, romID, dmModeReadOnly);
romRec = DmQueryRecord(romDB, 0);
roms = (UInt8 *) MemHandleLock(romRec);
romStart = 0x004100;
AppleROM = MemPtrNew(0x3F00);
MemMove(AppleROM, roms + romStart, 0x3F00);
MemHandleUnlock(romRec);
DmCloseDatabase(romDB);
romID = DmFindDatabase(0, "slot6.rom");
romDB = DmOpenDatabase(0, romID, dmModeReadOnly);
romRec = DmQueryRecord(romDB, 0);
roms = (UInt8 *) MemHandleLock(romRec);
BootROM = MemPtrNew(256);
MemMove(BootROM, roms, 256);
MemHandleUnlock(romRec);
DmCloseDatabase(romDB);
BootROM[0x004C] = 0xA9;
BootROM[0x004D] = 0x00;
BootROM[0x004E] = 0xEA;
}
void unloadROM(void)
{
MemPtrFree(AppleROM);
MemPtrFree(BootROM);
}
/*****************************************************************************\
* *
* Soft switches *
* *
\*****************************************************************************/
void AuxWriteBnk1(UInt16, UInt8);
void AuxWriteBnk2(UInt16, UInt8);
void AuxWrite(UInt16, UInt8);
void AuxMapWriteBnk1(UInt16, UInt8);
void AuxMapWriteBnk2(UInt16, UInt8);
void AuxMapWrite(UInt16, UInt8);
UInt8 AuxReadBnk1(UInt16);
UInt8 AuxReadBnk2(UInt16);
UInt8 AuxRead(UInt16);
UInt8 RomRead(UInt16);
void awrap_AuxMemReadWrite(void)
{
asm(".global AuxWriteBnk1");
asm(".global AuxWriteBnk2");
asm(".global AuxWrite");
asm(".global AuxMapWriteBnk1");
asm(".global AuxMapWriteBnk2");
asm(".global AuxMapWrite");
asm(".global AuxReadBnk1");
asm(".global AuxReadBnk2");
asm(".global AuxRead");
asm(".global RomRead");
asm("AuxWriteBnk1:");
asm("move.l AuxMemory@END.w(%a5), %a6");
asm("sub.l #0xD000, %a6");
asm("move.b %d0, (%a6, %d6.l)");
asm("rts");
asm("AuxWriteBnk2:");
asm("AuxWrite:");
asm("move.l AuxMemory@END.w(%a5), %a6");
asm("sub.l #0xC000, %a6");
asm("move.b %d0, (%a6, %d6.l)");
asm("rts");
asm("AuxMapWriteBnk1:");
asm("move.l AuxMemory@END.w(%a5), %a6");
asm("sub.l #0xD000, %a6");
asm("move.b %d0, (%a6, %d6.l)");
asm("move.b %d0, (%a2, %d6.l)");
asm("rts");
asm("AuxMapWriteBnk2:");
asm("AuxMapWrite:");
asm("move.l AuxMemory@END.w(%a5), %a6");
asm("sub.l #0xC000, %a6");
asm("move.b %d0, (%a6, %d6.l)");
asm("move.b %d0, (%a2, %d6.l)");
asm("rts");
asm("AuxReadBnk1:");
asm("move.l AuxMemory@END.w(%a5), %a6");
asm("sub.l #0xD000, %a6");
asm("clr.l %d0");
asm("move.b (%a6, %d6.l), %d0");
asm("rts");
asm("AuxReadBnk2:");
asm("AuxRead:");
asm("move.l AuxMemory@END.w(%a5), %a6");
asm("sub.l #0xC000, %a6");
asm("clr.l %d0");
asm("move.b (%a6, %d6.l), %d0");
asm("rts");
asm("RomRead:");
asm("move.l AppleROM@END.w(%a5), %a6");
asm("sub.l #0xC100, %a6");
asm("clr.l %d0");
asm("move.b (%a6, %d6.l), %d0");
asm("rts");
}
void WTXTM(UInt16, UInt8);
void WATXTM(UInt16, UInt8);
UInt8 RATXTM(UInt16 address);
void writeMemorySoftSwitch(UInt8 io)
{
UInt16 page;
UInt8 *tempPage;
switch (io)
{
case IO_OFFSET(CLR80STORE):
if (SS_ISSET(vidIOU, SS_80STORE))
{
clrVidFuncs(vidIOU);
SS_RESET(vidIOU, SS_80STORE);
if (SS_ISSET(vidIOU, SS_PAGE2))
{
WriteFunction[0x08] = WTXTM;
WriteFunction[0x09] = WTXTM;
WriteFunction[0x0A] = WTXTM;
WriteFunction[0x0B] = WTXTM;
}
else
{
WriteFunction[0x04] = WTXTM;
WriteFunction[0x05] = WTXTM;
WriteFunction[0x06] = WTXTM;
WriteFunction[0x07] = WTXTM;
}
}
break;
case IO_OFFSET(SET80STORE):
if (!SS_ISSET(vidIOU, SS_80STORE))
{
clrVidFuncs(vidIOU);
SS_SET(vidIOU, SS_80STORE);
if (SS_ISSET(vidIOU, SS_PAGE2))
{
if ((grMode > GRMODE_COLOR) && prefs.enable80Col)
{
WriteFunction[0x04] = WATXTM;
WriteFunction[0x05] = WATXTM;
WriteFunction[0x06] = WATXTM;
WriteFunction[0x07] = WATXTM;
ReadFunction[0x04] = RATXTM;
ReadFunction[0x05] = RATXTM;
ReadFunction[0x06] = RATXTM;
ReadFunction[0x07] = RATXTM;
}
else
{
WriteFunction[0x04] = READONLY;
WriteFunction[0x05] = READONLY;
WriteFunction[0x06] = READONLY;
WriteFunction[0x07] = READONLY;
}
}
else
{
WriteFunction[0x04] = WTXTM;
WriteFunction[0x05] = WTXTM;
WriteFunction[0x06] = WTXTM;
WriteFunction[0x07] = WTXTM;
}
}
break;
case IO_OFFSET(RDMAINRAM):
if (SS_ISSET(memIOU, SS_RAMRD))
{
SS_RESET(memIOU, SS_RAMRD);
for (page = 0x02; page < 0xC0; page++)
ReadFunction[page] = NULL;
setVideoFuncs(false);
}
break;
case IO_OFFSET(RDCARDRAM):
if (!SS_ISSET(memIOU, SS_RAMRD))
{
SS_SET(memIOU, SS_RAMRD);
for (page = 0x02; page < 0xC0; page++)
ReadFunction[page] = RRMP;
}
break;
case IO_OFFSET(WRMAINRAM):
if (SS_ISSET(memIOU, SS_RAMWRT))
{
SS_RESET(memIOU, SS_RAMWRT);
for (page = 0x02; page < 0xC0; page++)
WriteFunction[page] = NULL;
setVideoFuncs(false);
}
break;
case IO_OFFSET(WRCARDRAM):
if (!SS_ISSET(memIOU, SS_RAMWRT))
{
SS_SET(memIOU, SS_RAMWRT);
for (page = 0x02; page < 0xC0; page++)
WriteFunction[page] = READONLY;
}
break;
case IO_OFFSET(SETSLOTCXROM):
if (SS_ISSET(memIOU, SS_SLOTCXROM))
{
SS_RESET(memIOU, SS_SLOTCXROM);
ReadFunction[0xC1] = RRMP;
ReadFunction[0xC2] = RRMP;
ReadFunction[0xC4] = RRMP;
ReadFunction[0xC5] = RRMP;
ReadFunction[0xC6] = RRMP;
ReadFunction[0xC7] = RRMP;
MemSet(AppleMemory + 0xC100, 512, 0);
MemSet(AppleMemory + 0xC400, 1024, 0);
ReadFunction[0xC6] = NULL;
MemMove(AppleMemory + 0x00C600, BootROM, 256);
}
break;
case IO_OFFSET(SETINTCXROM):
if (!SS_ISSET(memIOU, SS_SLOTCXROM))
{
SS_SET(memIOU, SS_SLOTCXROM);
ReadFunction[0xC1] = NULL;
ReadFunction[0xC2] = NULL;
ReadFunction[0xC4] = NULL;
ReadFunction[0xC5] = NULL;
ReadFunction[0xC6] = NULL;
ReadFunction[0xC7] = NULL;
MemMove(AppleMemory + 0xC100, AppleROM, 512);
MemMove(AppleMemory + 0xC400, AppleROM + 0x300, 1024);
}
break;
case IO_OFFSET(SETINTC3ROM):
if (!SS_ISSET(memIOU, SS_SLOTC3ROM))
{
SS_SET(memIOU, SS_SLOTC3ROM);
MemMove(AppleMemory + 0xC300, AppleROM + 0x200, 256);
}
break;
case IO_OFFSET(SETSLOTC3ROM):
if (SS_ISSET(memIOU, SS_SLOTC3ROM))
{
SS_RESET(memIOU, SS_SLOTC3ROM);
MemSet(AppleMemory + 0xC300, 256, 0);
}
break;
case IO_OFFSET(CLR80VID):
SS_RESET(vidIOU, SS_80VID);
setVideoFuncs(true);
break;
case IO_OFFSET(SET80VID):
SS_SET(vidIOU, SS_80VID);
setVideoFuncs(true);
break;
}
}
void updateLanguageCardMapping(void)
{
READBYTE rfn;
WRITEBYTE wfn;
UInt16 page;
if (SS_ISSET(memIOU, SS_LCRAMMAP))
{
MemMove(AppleMemory + 0xD000, AuxMemory + (SS_ISSET(memIOU, SS_LCBNK2) ? 0x1000 : 0x0000), 4096);
MemMove(AppleMemory + 0xE000, AuxMemory + 0x2000, 8192);
}
else
{
MemMove(AppleMemory + 0xD000, AppleROM + 0xD000 - 0xC100, 4096+8192);
}
if (SS_ISSET(memIOU, SS_LCRAMWRT))
{
if (SS_ISSET(memIOU, SS_LCRAMMAP))
{
wfn = SS_ISSET(memIOU, SS_LCBNK2) ? AuxMapWriteBnk2 : AuxMapWriteBnk1;
WriteFunction[0xD0] = WriteFunction[0xD1] = wfn;
WriteFunction[0xD2] = WriteFunction[0xD3] = wfn;
WriteFunction[0xD4] = WriteFunction[0xD5] = wfn;
WriteFunction[0xD6] = WriteFunction[0xD7] = wfn;
WriteFunction[0xD8] = WriteFunction[0xD9] = wfn;
WriteFunction[0xDA] = WriteFunction[0xDB] = wfn;
WriteFunction[0xDC] = WriteFunction[0xDD] = wfn;
WriteFunction[0xDE] = WriteFunction[0xDF] = wfn;
for (page = 0xE0; page <= 0xFF; page++)
WriteFunction[page] = AuxMapWrite;
}
else
{
wfn = SS_ISSET(memIOU, SS_LCBNK2) ? AuxWriteBnk2 : AuxWriteBnk1;
WriteFunction[0xD0] = WriteFunction[0xD1] = wfn;
WriteFunction[0xD2] = WriteFunction[0xD3] = wfn;
WriteFunction[0xD4] = WriteFunction[0xD5] = wfn;
WriteFunction[0xD6] = WriteFunction[0xD7] = wfn;
WriteFunction[0xD8] = WriteFunction[0xD9] = wfn;
WriteFunction[0xDA] = WriteFunction[0xDB] = wfn;
WriteFunction[0xDC] = WriteFunction[0xDD] = wfn;
WriteFunction[0xDE] = WriteFunction[0xDF] = wfn;
for (page = 0xE0; page <= 0xFF; page++)
WriteFunction[page] = AuxWrite;
}
}
else
for (page = 0xD0; page <= 0xFF; page++)
WriteFunction[page] = READONLY;
for (page = 0xD0; page <= 0xFF; page++)
ReadFunction[page] = NULL;
clrPcCheckFuncs();
auxDirty = 0;
}
void toggleLanguageCard(UInt8 io)
{
READBYTE rfn;
WRITEBYTE wfn;
UInt16 page, dirty, pc6502;
/* set IOU soft switches */
dirty = memIOU;
switch (io)
{
case 0x00:
case 0x04:
SS_SET(memIOU, SS_LCBNK2);
SS_SET(memIOU, SS_LCRAMMAP);
SS_RESET(memIOU, SS_LCRAMWRT);
break;
case 0x01:
case 0x05:
SS_SET(memIOU, SS_LCBNK2);
SS_RESET(memIOU, SS_LCRAMMAP);
SS_SET(memIOU, SS_LCRAMWRT);
break;
case 0x02:
case 0x06:
SS_SET(memIOU, SS_LCBNK2);
SS_RESET(memIOU, SS_LCRAMMAP);
SS_RESET(memIOU, SS_LCRAMWRT);
break;
case 0x03:
case 0x07:
SS_SET(memIOU, SS_LCBNK2);
SS_SET(memIOU, SS_LCRAMMAP);
SS_SET(memIOU, SS_LCRAMWRT);
break;
case 0x08:
case 0x0C:
SS_RESET(memIOU, SS_LCBNK2);
SS_SET(memIOU, SS_LCRAMMAP);
SS_RESET(memIOU, SS_LCRAMWRT);
break;
case 0x09:
case 0x0D:
SS_RESET(memIOU, SS_LCBNK2);
SS_RESET(memIOU, SS_LCRAMMAP);
SS_SET(memIOU, SS_LCRAMWRT);
break;
case 0x0A:
case 0x0E:
SS_RESET(memIOU, SS_LCBNK2);
SS_RESET(memIOU, SS_LCRAMMAP);
SS_RESET(memIOU, SS_LCRAMWRT);
break;
case 0x0B:
case 0x0F:
SS_RESET(memIOU, SS_LCBNK2);
SS_SET(memIOU, SS_LCRAMMAP);
SS_SET(memIOU, SS_LCRAMWRT);
break;
}
/*
* Update only the changed state.
*/
if ((dirty ^= memIOU))
{
if (dirty & SS_LCRAMMAP)
{
updateLanguageCardMapping();
}
else
{
if (SS_ISSET(memIOU, SS_LCRAMMAP))
{
if (dirty & SS_LCBNK2)
{
pc6502 = state6502.LongRegs.PC-state6502.LongRegs.MEMBASE;
if ((pc6502 >= 0xD000) && (pc6502 < 0xE000))
{
updateLanguageCardMapping();
return;
}
if (!auxDirty)
{
/*
* Install special versions of JMP, JSR, BRK, RTI, and RTS that check for memory ranges.
*/
setPcCheckFuncs();
auxDirty = 1;
}
rfn = SS_ISSET(memIOU, SS_LCBNK2) ? AuxReadBnk2 : AuxReadBnk1;
ReadFunction[0xD0] = ReadFunction[0xD1] = rfn;
ReadFunction[0xD2] = ReadFunction[0xD3] = rfn;
ReadFunction[0xD4] = ReadFunction[0xD5] = rfn;
ReadFunction[0xD6] = ReadFunction[0xD7] = rfn;
ReadFunction[0xD8] = ReadFunction[0xD9] = rfn;
ReadFunction[0xDA] = ReadFunction[0xDB] = rfn;
ReadFunction[0xDC] = ReadFunction[0xDD] = rfn;
ReadFunction[0xDE] = ReadFunction[0xDF] = rfn;
}
if (SS_ISSET(memIOU, SS_LCRAMWRT))
{
wfn = SS_ISSET(memIOU, SS_LCBNK2) ? AuxMapWriteBnk2 : AuxMapWriteBnk1;
WriteFunction[0xD0] = WriteFunction[0xD1] = wfn;
WriteFunction[0xD2] = WriteFunction[0xD3] = wfn;
WriteFunction[0xD4] = WriteFunction[0xD5] = wfn;
WriteFunction[0xD6] = WriteFunction[0xD7] = wfn;
WriteFunction[0xD8] = WriteFunction[0xD9] = wfn;
WriteFunction[0xDA] = WriteFunction[0xDB] = wfn;
WriteFunction[0xDC] = WriteFunction[0xDD] = wfn;
WriteFunction[0xDE] = WriteFunction[0xDF] = wfn;
if (dirty & SS_LCRAMWRT)
for (page = 0xE0; page <= 0xFF; page++)
WriteFunction[page] = AuxMapWrite;
}
else if (dirty & SS_LCRAMWRT)
for (page = 0xD0; page <= 0xFF; page++)
WriteFunction[page] = READONLY;
}
else
{
if (SS_ISSET(memIOU, SS_LCRAMWRT))
{
wfn = SS_ISSET(memIOU, SS_LCBNK2) ? AuxWriteBnk2 : AuxWriteBnk1;
WriteFunction[0xD0] = WriteFunction[0xD1] = wfn;
WriteFunction[0xD2] = WriteFunction[0xD3] = wfn;
WriteFunction[0xD4] = WriteFunction[0xD5] = wfn;
WriteFunction[0xD6] = WriteFunction[0xD7] = wfn;
WriteFunction[0xD8] = WriteFunction[0xD9] = wfn;
WriteFunction[0xDA] = WriteFunction[0xDB] = wfn;
WriteFunction[0xDC] = WriteFunction[0xDD] = wfn;
WriteFunction[0xDE] = WriteFunction[0xDF] = wfn;
if (dirty & SS_LCRAMWRT)
for (page = 0xE0; page <= 0xFF; page++)
WriteFunction[page] = AuxWrite;
}
else if (dirty & SS_LCRAMWRT)
for (page = 0xD0; page <= 0xFF; page++)
WriteFunction[page] = READONLY;
}
}
}
}
void setMemFuncs(void)
{
UInt16 page;
updateLanguageCardMapping();
if (!SS_ISSET(memIOU, SS_SLOTCXROM))
{
ReadFunction[0xC1] = RRMP;
ReadFunction[0xC2] = RRMP;
ReadFunction[0xC4] = RRMP;
ReadFunction[0xC5] = RRMP;
ReadFunction[0xC6] = RRMP;
ReadFunction[0xC7] = RRMP;
}
if (SS_ISSET(memIOU, SS_RAMRD))
for (page = 0x02; page < 0xC0; page++)
ReadFunction[page] = RRMP;
if (SS_ISSET(memIOU, SS_RAMWRT))
for (page = 0x02; page < 0xC0; page++)
WriteFunction[page] = READONLY;
ReadFunction[0xC0] = RIOM;
ReadFunction[0xC3] = RC3M;
WriteFunction[0xC0] = WIOM;
}
/*****************************************************************************\
* *
* Disk access control *
* *
\*****************************************************************************/
#define RAW_TRACK_BYTES 6192
#define RAW_SECTOR_BYTES 387
#define DOS_TRACK_BYTES 4096
#define RAW_TRACK_BITS (RAW_TRACK_BYTES*8)
#define NO_OF_PHASES 8
#define MAX_PHYSICAL_TRACK_NO (40*NO_OF_PHASES)
#define MAX_DRIVE_NO 2
static Int8 stepper_movement_table[16][NO_OF_PHASES] =
{
{ 0, 0, 0, 0, 0, 0, 0, 0}, /* all electromagnets off */
{ 0, -1, -2, -3, 0, 3, 2, 1}, /* EM 1 on */
{ 2, 1, 0, -1, -2, -3, 0, 3}, /* EM 2 on */
{ 1, 0, -1, -2, -3, 0, 3, 2}, /* EMs 1 & 2 on */
{ 0, 3, 2, 1, 0, -1, -2, -3}, /* EM 3 on */
{ 0, -1, 0, 1, 0, -1, 0, 1}, /* EMs 1 & 3 on */
{ 3, 2, 1, 0, -1, -2, -3, 0}, /* EMs 2 & 3 on */
{ 2, 1, 0, -1, -2, -3, 0, 3}, /* EMs 1, 2 & 3 on */
{-2, -3, 0, 3, 2, 1, 0, -1}, /* EM 4 on */
{-1, -2, -3, 0, 3, 2, 1, 0}, /* EMs 1 & 4 on */
{ 0, 1, 0, -1, 0, 1, 0, -1}, /* EMs 2 & 4 */
{ 0, -1, -2, -3, 0, 3, 2, 1}, /* EMs 1, 2 & 4 on */
{-3, 0, 3, 2, 1, 0, -1, -2}, /* EMs 3 & 4 on */
{-2, -3, 0, 3, 2, 1, 0, -1}, /* EMs 1, 3 & 4 on */
{ 0, 3, 2, 1, 0, -1, -2, -3}, /* EMs 2, 3 & 4 on */
{ 0, 0, 0, 0, 0, 0, 0, 0}
}; /* all electromagnets on */
static Boolean track_buffer_valid;
static Int8 write_mode;
static UInt8 *nibble_buf;
static UInt16 track_buffer_pos;
static UInt16 track_buffer_size;
static UInt8 write_protect;
static UInt8 address_latch, data_latch;
static Boolean motor_state;
static UInt8 drive_no = 0;
struct stateDisk_t
{
char diskname[32];
LocalID diskdb;
DmOpenRef diskimage;
MemHandle track_buffer_handle;
Int16 physical_track_no;
Int16 stepper_status;
Boolean track_buffer_valid;
Boolean track_buffer_raw;
Boolean track_buffer_dirty;
Int8 track_count;
Int8 track_buffer_track;
Int8 write_mode;
Int16 last_track;
UInt8 *nibble_buf;
UInt16 track_buffer_pos;
UInt16 track_buffer_size;
UInt8 write_protect;
UInt8 logical_track;
UInt8 address_latch, data_latch;
} stateDisk[2] = {0};
UInt32 DskIoICountDiff = 0;
UInt32 LastDskIoICount = 0;
/*
* SLOT 6 IO read.
*/
RDMEM_CWRAP(SLT6, address)
{
return (BootROM[address & 0xFF]);
}
void setCurrentDisk(int drive)
{
if (drive != drive_no)
{
if (drive_no)
showDriveState(drive_no, false);
drive_no = drive;
showDiskName(drive_no, stateDisk[drive_no - 1].diskname);
showDriveState(drive_no, motor_state);
}
drive--;
track_buffer_valid = stateDisk[drive].track_buffer_valid;
write_mode = stateDisk[drive].write_mode;
nibble_buf = stateDisk[drive].nibble_buf;
track_buffer_pos = stateDisk[drive].track_buffer_pos;
track_buffer_size = stateDisk[drive].track_buffer_size;
write_protect = stateDisk[drive].write_protect;
address_latch = stateDisk[drive].address_latch;
data_latch = stateDisk[drive].data_latch;
}
int getCurrentDrive(void)
{
return (drive_no | (motor_state ? 0x80 : 0));
}
void updateCurrentDisk(int drive)
{
if (drive--)
{
stateDisk[drive].track_buffer_pos = track_buffer_pos;
stateDisk[drive].address_latch = address_latch;
stateDisk[drive].data_latch = data_latch;
}
}
void load_track_buffer(int drive)
{
UInt8 *values;
if (stateDisk[--drive].diskdb)
{
stateDisk[drive].logical_track = (stateDisk[drive].physical_track_no + 1) >> 2;
if (stateDisk[drive].logical_track >= stateDisk[drive].track_count)
stateDisk[drive].logical_track = stateDisk[drive].track_count - 1;
if ((stateDisk[drive].logical_track != stateDisk[drive].last_track) || !stateDisk[drive].track_buffer_valid)
{
if (stateDisk[drive].track_buffer_dirty && !stateDisk[drive].track_buffer_raw)
{
stateDisk[drive].track_buffer_handle = DmGetRecord(stateDisk[drive].diskimage, stateDisk[drive].last_track);
values = (UInt8 *) MemHandleLock(stateDisk[drive].track_buffer_handle);
NibblesToSectors(stateDisk[drive].nibble_buf, values, 254, stateDisk[drive].last_track);
MemHandleUnlock(stateDisk[drive].track_buffer_handle);
DmReleaseRecord(stateDisk[drive].diskimage, stateDisk[drive].last_track, true);
}
else if (stateDisk[drive].track_buffer_handle)
MemHandleUnlock(stateDisk[drive].track_buffer_handle);
stateDisk[drive].track_buffer_handle = DmQueryRecord(stateDisk[drive].diskimage, stateDisk[drive].logical_track);
values = (UInt8 *) MemHandleLock(stateDisk[drive].track_buffer_handle);
if (stateDisk[drive].track_buffer_raw)
stateDisk[drive].nibble_buf = values;
else
{
SectorsToNibbles(values, stateDisk[drive].nibble_buf, 254, stateDisk[drive].logical_track);
MemHandleUnlock(stateDisk[drive].track_buffer_handle);
stateDisk[drive].track_buffer_handle = 0;
}
stateDisk[drive].last_track = stateDisk[drive].logical_track;
stateDisk[drive].track_buffer_track = stateDisk[drive].physical_track_no;
stateDisk[drive].track_buffer_dirty = false;
stateDisk[drive].track_buffer_valid = true;
stateDisk[drive].track_buffer_pos = 0;
if (drive_no == (drive + 1))
setCurrentDisk(drive_no);
}
}
}
void write_nibble(UInt8 data)
{
if (!track_buffer_valid)
load_track_buffer(drive_no);
else if (DskIoICountDiff > 100)
{
if (DskIoICountDiff < 65536)
{
/*
* Advance position based on instruction count.
*/
track_buffer_pos += (DskIoICountDiff >> 12) * (track_buffer_size >> 4); /* divide by ~4096 instructions per sector */
if (track_buffer_pos >= track_buffer_size)
track_buffer_pos -= track_buffer_size;
}
if (track_buffer_size == RAW_TRACK_BYTES)
{
/*
* Round position up to a sector boundary.
*/
if (track_buffer_pos > RAW_SECTOR_BYTES*15)
track_buffer_pos = 0;
else if (track_buffer_pos > RAW_SECTOR_BYTES*14)
track_buffer_pos = RAW_SECTOR_BYTES*15;
else if (track_buffer_pos > RAW_SECTOR_BYTES*13)
track_buffer_pos = RAW_SECTOR_BYTES*14;
else if (track_buffer_pos > RAW_SECTOR_BYTES*12)
track_buffer_pos = RAW_SECTOR_BYTES*13;
else if (track_buffer_pos > RAW_SECTOR_BYTES*11)
track_buffer_pos = RAW_SECTOR_BYTES*12;
else if (track_buffer_pos > RAW_SECTOR_BYTES*10)
track_buffer_pos = RAW_SECTOR_BYTES*11;
else if (track_buffer_pos > RAW_SECTOR_BYTES*9)
track_buffer_pos = RAW_SECTOR_BYTES*10;
else if (track_buffer_pos > RAW_SECTOR_BYTES*8)
track_buffer_pos = RAW_SECTOR_BYTES*9;
else if (track_buffer_pos > RAW_SECTOR_BYTES*7)
track_buffer_pos = RAW_SECTOR_BYTES*8;
else if (track_buffer_pos > RAW_SECTOR_BYTES*6)
track_buffer_pos = RAW_SECTOR_BYTES*7;
else if (track_buffer_pos > RAW_SECTOR_BYTES*5)
track_buffer_pos = RAW_SECTOR_BYTES*6;
else if (track_buffer_pos > RAW_SECTOR_BYTES*4)
track_buffer_pos = RAW_SECTOR_BYTES*5;
else if (track_buffer_pos > RAW_SECTOR_BYTES*3)
track_buffer_pos = RAW_SECTOR_BYTES*4;
else if (track_buffer_pos > RAW_SECTOR_BYTES*2)
track_buffer_pos = RAW_SECTOR_BYTES*3;
else if (track_buffer_pos > RAW_SECTOR_BYTES*1)
track_buffer_pos = RAW_SECTOR_BYTES*2;
else if (track_buffer_pos > RAW_SECTOR_BYTES*0)
track_buffer_pos = RAW_SECTOR_BYTES*1;
}
}
nibble_buf[track_buffer_pos] = data;
if (++track_buffer_pos >= track_buffer_size)
track_buffer_pos = 0;
stateDisk[drive_no - 1].track_buffer_dirty = true;
}
UInt8 read_nibble()
{
UInt8 data;
if (!track_buffer_valid)
load_track_buffer(drive_no);
else if (DskIoICountDiff > 100)
{
if (DskIoICountDiff < 65536)
{
/*
* Advance position based on instruction count.
*/
track_buffer_pos += (DskIoICountDiff >> 12) * (track_buffer_size >> 4); /* divide by ~4096 instructions per sector */
if (track_buffer_pos >= track_buffer_size)
track_buffer_pos -= track_buffer_size;
}
if (track_buffer_size == RAW_TRACK_BYTES)
{
/*
* Round position up to a sector boundary.
*/
if (track_buffer_pos > RAW_SECTOR_BYTES*15)
track_buffer_pos = 0;
else if (track_buffer_pos > RAW_SECTOR_BYTES*14)
track_buffer_pos = RAW_SECTOR_BYTES*15;
else if (track_buffer_pos > RAW_SECTOR_BYTES*13)
track_buffer_pos = RAW_SECTOR_BYTES*14;
else if (track_buffer_pos > RAW_SECTOR_BYTES*12)
track_buffer_pos = RAW_SECTOR_BYTES*13;
else if (track_buffer_pos > RAW_SECTOR_BYTES*11)
track_buffer_pos = RAW_SECTOR_BYTES*12;
else if (track_buffer_pos > RAW_SECTOR_BYTES*10)
track_buffer_pos = RAW_SECTOR_BYTES*11;
else if (track_buffer_pos > RAW_SECTOR_BYTES*9)
track_buffer_pos = RAW_SECTOR_BYTES*10;
else if (track_buffer_pos > RAW_SECTOR_BYTES*8)
track_buffer_pos = RAW_SECTOR_BYTES*9;
else if (track_buffer_pos > RAW_SECTOR_BYTES*7)
track_buffer_pos = RAW_SECTOR_BYTES*8;
else if (track_buffer_pos > RAW_SECTOR_BYTES*6)
track_buffer_pos = RAW_SECTOR_BYTES*7;
else if (track_buffer_pos > RAW_SECTOR_BYTES*5)
track_buffer_pos = RAW_SECTOR_BYTES*6;
else if (track_buffer_pos > RAW_SECTOR_BYTES*4)
track_buffer_pos = RAW_SECTOR_BYTES*5;
else if (track_buffer_pos > RAW_SECTOR_BYTES*3)
track_buffer_pos = RAW_SECTOR_BYTES*4;
else if (track_buffer_pos > RAW_SECTOR_BYTES*2)
track_buffer_pos = RAW_SECTOR_BYTES*3;
else if (track_buffer_pos > RAW_SECTOR_BYTES*1)
track_buffer_pos = RAW_SECTOR_BYTES*2;
else if (track_buffer_pos > RAW_SECTOR_BYTES*0)
track_buffer_pos = RAW_SECTOR_BYTES*1;
}
}
data = nibble_buf[track_buffer_pos];
if (++track_buffer_pos >= track_buffer_size)
track_buffer_pos = 0;
return (data);
}
void toggleStepper(int drive, UInt8 magnet, UInt8 on)
{
if (drive--)
{
if (on)
stateDisk[drive].stepper_status |= (1 << magnet);
else
stateDisk[drive].stepper_status &= ~(1 << magnet);
if (motor_state)
{
stateDisk[drive].physical_track_no += stepper_movement_table[stateDisk[drive].stepper_status][stateDisk[drive].physical_track_no & 0x07];
if (stateDisk[drive].physical_track_no < 0)
stateDisk[drive].physical_track_no = 0;
else if (stateDisk[drive].physical_track_no >= MAX_PHYSICAL_TRACK_NO)
stateDisk[drive].physical_track_no = MAX_PHYSICAL_TRACK_NO - 1;
stateDisk[drive].track_buffer_valid = track_buffer_valid = false;
}
}
}
void toggleMotor(int drive, Boolean on_off)
{
if (drive--)
{
if (motor_state != on_off)
{
motor_state = on_off;
showDriveState(drive_no, motor_state);
}
}
}
void positionDisk(int drive, UInt16 new_track, UInt16 new_position)
{
drive--;
stateDisk[drive].physical_track_no = new_track << 2;
if (stateDisk[drive].physical_track_no >= MAX_PHYSICAL_TRACK_NO)
stateDisk[drive].physical_track_no = MAX_PHYSICAL_TRACK_NO - 1;
load_track_buffer(drive + 1);
stateDisk[drive].track_buffer_pos = new_position;
if (stateDisk[drive].track_buffer_pos >= stateDisk[drive].track_buffer_size)
stateDisk[drive].track_buffer_pos = 0;
if (drive_no == (drive + 1))
setCurrentDisk(drive_no);
}
void queryDisk(int drive, UInt16 *track, UInt16 *pos)
{
if (drive-- == drive_no)
updateCurrentDisk(drive_no);
*track = stateDisk[drive].physical_track_no >> 2;
*pos = stateDisk[drive].track_buffer_pos;
}
int mountDisk(int drive, char *file, Boolean writeable)
{
UInt16 attrs;
UInt32 type, numrecs, ttlbytes, recbytes;
umountDisk(drive--);
stateDisk[drive].track_buffer_pos = 0;
stateDisk[drive].track_buffer_dirty = false;
stateDisk[drive].diskdb = file ? DmFindDatabase(0, file) : 0;
if (stateDisk[drive].diskdb)
{
StrCopy(stateDisk[drive].diskname, file);
stateDisk[drive].diskimage = DmOpenDatabase(0, stateDisk[drive].diskdb, 0);
DmDatabaseInfo(0, stateDisk[drive].diskdb, NULL, &attrs, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &type, NULL);
stateDisk[drive].track_buffer_raw = (type == (UInt32)'RDSK') ? true : false;
stateDisk[drive].write_protect = attrs & dmHdrAttrReadOnly ? true : !writeable;
DmDatabaseSize(0, stateDisk[drive].diskdb, &numrecs, &ttlbytes, &recbytes);
stateDisk[drive].track_count = numrecs;
if (stateDisk[drive].track_buffer_raw)
{
stateDisk[drive].track_buffer_size = recbytes / stateDisk[drive].track_count;
}
else
{
stateDisk[drive].nibble_buf = MemPtrNew(RAW_TRACK_BYTES);
stateDisk[drive].track_buffer_size = RAW_TRACK_BYTES;
init_GCR_table();
}
stateDisk[drive].track_buffer_handle = 0;
stateDisk[drive].track_buffer_valid = false;
}
else
{
stateDisk[drive].diskname[0] = '\0';
stateDisk[drive].diskimage = 0;
stateDisk[drive].nibble_buf = MemPtrNew(RAW_TRACK_BYTES);
MemSet(stateDisk[drive].nibble_buf, RAW_TRACK_BYTES, 0xFF);
stateDisk[drive].track_buffer_handle = 0;
stateDisk[drive].track_buffer_size = RAW_TRACK_BYTES;
stateDisk[drive].track_buffer_valid = true;
stateDisk[drive].write_protect = true;
}
if (drive_no == (drive + 1))
{
drive_no = 0;
setCurrentDisk(drive + 1);
}
else
{
showDiskName(drive + 1, stateDisk[drive].diskname);
showDriveState(drive + 1, false);
}
return (stateDisk[drive].diskdb != 0);
}
void umountDisk(int drive)
{
UInt8 *values;
if (drive-- == drive_no)
updateCurrentDisk(drive_no);
if (stateDisk[drive].diskdb)
{
if (!stateDisk[drive].track_buffer_raw)
{
if (stateDisk[drive].track_buffer_dirty)
{
stateDisk[drive].track_buffer_handle = DmGetRecord(stateDisk[drive].diskimage, stateDisk[drive].last_track);
values = (UInt8 *) MemHandleLock(stateDisk[drive].track_buffer_handle);
NibblesToSectors(stateDisk[drive].nibble_buf, values, 254, stateDisk[drive].last_track);
MemHandleUnlock(stateDisk[drive].track_buffer_handle);
DmReleaseRecord(stateDisk[drive].diskimage, stateDisk[drive].last_track, true);
}
MemPtrFree(stateDisk[drive].nibble_buf);
}
else if (stateDisk[drive].track_buffer_handle)
{
MemHandleUnlock(stateDisk[drive].track_buffer_handle);
}
DmCloseDatabase(stateDisk[drive].diskimage);
stateDisk[drive].diskdb = 0;
}
else if (stateDisk[drive].nibble_buf)
MemPtrFree(stateDisk[drive].nibble_buf);
stateDisk[drive].nibble_buf = NULL;
stateDisk[drive].track_buffer_handle = 0;
stateDisk[drive].track_buffer_valid = false;
toggleMotor(drive + 1, 0);
}
void resetDisks(void)
{
#if 0
UInt8 drive, *values;
updateCurrentDisk(drive_no);
for (drive = 0; drive < 2; drive++)
{
if (stateDisk[drive].diskdb)
{
if (!stateDisk[drive].track_buffer_raw)
{
if (stateDisk[drive].track_buffer_dirty)
{
stateDisk[drive].track_buffer_handle = DmGetRecord(stateDisk[drive].diskimage, stateDisk[drive].last_track);
values = (UInt8 *) MemHandleLock(stateDisk[drive].track_buffer_handle);
NibblesToSectors(stateDisk[drive].nibble_buf, values, 254, stateDisk[drive].last_track);
MemHandleUnlock(stateDisk[drive].track_buffer_handle);
DmReleaseRecord(stateDisk[drive].diskimage, stateDisk[drive].last_track, true);
}
}
else if (stateDisk[drive].track_buffer_handle)
{
MemHandleUnlock(stateDisk[drive].track_buffer_handle);
}
}
toggleMotor(drive + 1, 0);
stateDisk[drive].physical_track_no = 0;
stateDisk[drive].track_buffer_handle = 0;
stateDisk[drive].track_buffer_pos = 0;
stateDisk[drive].track_buffer_valid = false;
stateDisk[drive].track_buffer_dirty = false;
}
#else
umountDisk(1);
umountDisk(2);
mountDisk(1, stateDisk[0].diskname, stateDisk[0].write_protect);
mountDisk(2, stateDisk[1].diskname, stateDisk[1].write_protect);
#endif
drive_no = 0;
setCurrentDisk(1);
}
/*****************************************************************************\
* *
* I/O page access *
* *
\*****************************************************************************/
/*
* I/O Read.
*/
UInt8 RIOM(UInt16);
UInt8 cwrap_RIOM(UInt16);
UInt8 awrap_RIOM(UInt16 a)
{
asm(".global RIOM");
asm("RIOM:");
/*
* Quick check for Disk read byte.
*/
asm("cmp.b #0xEC, %d6");
asm("bne.b L1");
/*
* Check for buffer valid.
*/
asm("tst.b track_buffer_valid@END.w(%a5)");
asm("beq.b L1");
/*
* Update access time.
*/
asm("move.l AppleInstrInc@END.w(%a5), %d0");
asm("sub.l %d1, %d0");
asm("add.l AppleInstrCount@END.w(%a5), %d0");
asm("move.l %d0, %a6");
asm("sub.l LastDskIoICount@END.w(%a5), %d0");
asm("move.l %d0, DskIoICountDiff@END.w(%a5)");
asm("move.l %a6, LastDskIoICount@END.w(%a5)");
/*
* Check for back-to-back read.
*/
asm("cmp.l #100, %d0"); // This is the instruction count that determines if it is back-to-back
asm("bgt.b L1");
/*
* Check for read or write.
*/
asm("tst.b write_mode@END.w(%a5)");
asm("bne.b L1");
/*