/* disk.c V1.1.1 * * FD17xx emulering for TIKI-100_emul * Copyright (C) Asbjørn Djupdal 2000-2001 */ #include "TIKI-100_emul.h" #include "protos.h" #include enum diskCommands { NO_COMMAND, READ_SECT, READ_ADDR, WRITE_SECT, READ_TRACK, WRITE_TRACK }; #define STEPIN 1 #define STEPOUT -1 /* data for en diskettstasjon */ struct diskParams { byte *diskImage; /* diskettbilde */ boolean active; /* om det er diskett i stasjonen */ int tracks; /* antall spor */ int sides; /* antall sider - 1 */ int sectors; /* sektorer pr spor */ int sectSize; /* bytes pr sektor */ int realTrack; /* hvilken spor r/w-hode står over */ }; /* protos */ static void setLights (void); static void setLight (int drive, boolean status); /* variabler */ static struct diskParams params0; /* data for stasjon 0 */ static struct diskParams params1; /* data for stasjon 1 */ static struct diskParams *params; /* data for aktiv plate */ static int side = 0; /* gjeldende side (0 eller 1) */ static boolean motOn = FALSE; /* om motor er på */ static byte track = 0; /* sporregister */ static byte sector = 1; /* sektorregister */ static byte data = 0; /* dataregister */ static byte status = 0x20; /* statusregister */ static byte stepDir = STEPIN; /* verdi som legges til realTrack ved STEP */ static byte command = NO_COMMAND; /* kommando som pågår */ static long imageOffset = 0; /* offset inn i diskImage, ved r/w */ static long endOffset = 0; /* hvor en r/w kommando skal avslutte */ static int byteCount = 0; /* antall behandlede bytes ved READ_ADDR, WRITE_TRACK */ /*****************************************************************************/ /* skriv til kontrollregister */ void diskControl (byte value) { /* restore */ if ((value & 0xf0) == 0x00) { track = 0; params->realTrack = 0; status = 0x24; } /* søk */ else if ((value & 0xf0) == 0x10) { if (data >= params->tracks) status = 0x30 | (params->realTrack == 0 ? 0x04 : 0x00); else { params->realTrack = data; track = params->realTrack; status = 0x20 | (params->realTrack == 0 ? 0x04 : 0x00); } } /* step */ else if ((value & 0xe0) == 0x20) { params->realTrack += stepDir; if (params->realTrack >= params->tracks) params->realTrack = params->tracks - 1; if (params->realTrack < 0) params->realTrack = 0; status = 0x20 | (params->realTrack == 0 ? 0x04 : 0x00); if (value & 0x10) track = params->realTrack; } /* step inn */ else if ((value & 0xe0) == 0x40) { params->realTrack += STEPIN; if (params->realTrack >= params->tracks) params->realTrack = params->tracks - 1; stepDir = STEPIN; status = 0x20; if (value & 0x10) track = params->realTrack; } /* step ut */ else if ((value & 0xe0) == 0x60) { params->realTrack += STEPOUT; if (params->realTrack < 0) params->realTrack = 0; stepDir = STEPOUT; status = 0x20 | (params->realTrack == 0 ? 0x04 : 0x00); if (value & 0x10) track = params->realTrack; } /* les sektor */ else if ((value & 0xe0) == 0x80) { if (params->active) { side = (value & 0x02) ? 1 : 0; if ((sector > params->sectors) || (side > params->sides)) { status = 0x10; } else { if (value & 0x10) /* les resten av sektor i spor */ endOffset = (((params->realTrack+1) << params->sides) + side) * /* BUG ?? */ params->sectors * params->sectSize; else /* les kun 1 sektor */ endOffset = ((params->realTrack << params->sides) + side) * params->sectors * params->sectSize + sector * params->sectSize; imageOffset = ((params->realTrack << params->sides) + side) * params->sectors * params->sectSize + (sector-1) * params->sectSize; command = READ_SECT; status = 0x02; } } else { status = 0x80; } } /* skriv sektor */ else if ((value & 0xe0) == 0xa0) { if (params->active) { side = (value & 0x02) ? 1 : 0; if ((sector > params->sectors) || (side > params->sides)) { status = 0x10; } else { if (value & 0x10) /* skriv resten av sektor i spor */ endOffset = (((params->realTrack+1) << params->sides) + side) * /* BUG ?? */ params->sectors * params->sectSize; else /* skriv kun 1 sektor */ endOffset = ((params->realTrack << params->sides) + side) * params->sectors * params->sectSize + sector * params->sectSize; imageOffset = ((params->realTrack << params->sides) + side) * params->sectors * params->sectSize + (sector-1) * params->sectSize; command = WRITE_SECT; status = 0x02; } } else { status = 0x80; } } /* les adresse */ else if ((value & 0xf8) == 0xc0) { if (params->active) { side = (value & 0x02) ? 1 : 0; if (side > params->sides) { status = 0x10; } else { command = READ_ADDR; byteCount = 0; status = 0x02; } } else { status = 0x80; } } /* les spor -- ikke implementert */ else if ((value & 0xf8) == 0xe0) { status = 0x80; } /* skriv spor -- kun delvis implementert */ else if ((value & 0xf8) == 0xf0) { if (params->active) { side = (value & 0x02) ? 1 : 0; if (side > params->sides) { status = 0x10; } else { command = WRITE_TRACK; byteCount = 0; status = 0x02; } } else { status = 0x80; } } /* avbryt */ else if ((value & 0xf0) == 0xd0) { command = NO_COMMAND; if (status & 0x01) { status = status & 0xfe; } else { status = 0x20 | (params->realTrack == 0 ? 0x04 : 0x00); } } } /* skriv til sporregister */ void newTrack (byte value) { track = value; } /* skriv til sektorregister */ void newSector (byte value) { sector = value; } /* skriv til dataregister */ void newDiskData (byte value) { data = value; switch (command) { case WRITE_SECT: params->diskImage[imageOffset++] = data; if (imageOffset == endOffset) { command = NO_COMMAND; status = 0x00; } break; case WRITE_TRACK: /* kun delvis implementert */ if (++byteCount > 6200) { memset (¶ms->diskImage[((params->realTrack << params->sides) + side) * params->sectors * params->sectSize], 0xe5, params->sectors * params->sectSize); command = NO_COMMAND; status = 0x00; } break; } } /* les statusregister */ byte diskStatus (void) { return status; } /* les sporregister */ byte getTrack (void) { return track; } /* les sektorregister */ byte getSector (void) { return sector; } /* les dataregister */ byte getDiskData (void) { switch (command) { case READ_SECT: data = params->diskImage[imageOffset++]; if (imageOffset == endOffset) { command = NO_COMMAND; status = 0x00; } break; case READ_ADDR: switch (byteCount++) { case 0: data = params->realTrack; break; case 1: data = side; break; case 2: data = 1; break; case 3: switch (params->sectSize) { case 128: data = 0; break; case 256: data = 1; break; case 512: data = 2; break; case 1024: data = 3; break; } break; case 4: data = 0; break; case 5: data = 0; command = NO_COMMAND; status = 0x00; break; } break; case READ_TRACK: /* ikke implementert */ break; } return data; } /* sett disk 0 aktiv / inaktiv */ void disk0 (boolean status) { if (status) { params = ¶ms0; } else { params = ¶ms1; } setLights(); } /* sett disk 1 aktiv / inaktiv */ void disk1 (boolean status) { if (status) { params = ¶ms1; } else { params = ¶ms0; } setLights(); } /* skru motor på / av */ void diskMotor (boolean status) { motOn = status; setLights(); } /* sett alle disklys */ static void setLights (void) { int disk = params == ¶ms0 ? 0 : 1; int otherDisk = disk == 1 ? 0 : 1; if (motOn) { setLight (disk, 1); setLight (otherDisk, 0); } else { setLight (0, 0); setLight (1, 0); } } /* sett disk lys til gitt stasjon og status */ static void setLight (int drive, boolean status) { static int l[2] = {0, 0}; if (l[drive] != status) { l[drive] = status; diskLight (drive, status); } } /* ny diskett i stasjon * disk: Hvilken stasjon * diskImage: Peker til diskettbilde-data * resten er diskparametre */ void insertDisk (int drive, byte *dskImg, int trcks, int sds, int sctrs, int sctSize) { struct diskParams *dp = drive ? ¶ms1 : ¶ms0; dp->active = TRUE; dp->diskImage = dskImg; dp->tracks = trcks; dp->sides = sds - 1; dp->sectors = sctrs; dp->sectSize = sctSize; } /* fjern diskett fra stasjon */ void removeDisk (int drive) { struct diskParams *dp = drive ? ¶ms1 :¶ms0; dp->active = FALSE; }