home *** CD-ROM | disk | FTP | other *** search
- /*
- * 1541d64.c - 1541-Emulation in .d64-Datei
- *
- * Copyright (C) 1994-1995 by Christian Bauer
- */
-
- /*
- * Anmerkungen:
- * ------------
- *
- * Routinen:
- * - Die Schnittstelle zu den IEC-Routinen besteht in den Routinen
- * D64_Init, D64_Exit, D64_Open, D64_Close, D64_Read und D64_Write:
- * D64_Init bereitet die Emulation vor
- * D64_Exit beendet die Emulation
- * D64_Open öffnet einen Kanal
- * D64_Close schließt einen Kanal
- * D64_Read liest aus einem Kanal
- * D64_Write schreibt in einen Kanal
- *
- * DriveData:
- * - lock enthält das FileHandle der .d64-Datei
- *
- * Inkompatibilitäten/Verbesserungen:
- * - Nur Lesezugriffe möglich
- * - Keine Wildcards beim Directory-Lesen
- * - Nur 'I'-Befehl implementiert
- */
-
-
- #include <exec/types.h>
- #include <exec/memory.h>
- #include <clib/exec_protos.h>
- #include <clib/dos_protos.h>
- #include <stdlib.h>
- #include <string.h>
-
- #include "IEC.h"
- #include "1541d64.h"
- #include "Display.h"
- #define CATCOMP_NUMBERS 1
- #include "LocStrings.h"
-
-
- // Kanalmodi
- enum {
- CHMOD_FREE, // Kanal frei
- CHMOD_COMMAND, // Kommando-/Fehlerkanal
- CHMOD_DIRECTORY, // Directory wird gelesen
- CHMOD_FILE, // Sequentielle Datei ist geöffnet
- CHMOD_DIRECT // Direkter Pufferzugriff ('#')
- };
-
- // Anzahl Tracks
- #define NUM_TRACKS 35
-
-
- // Aus Main.asm
- extern void ResetC64(void);
-
-
- // Prototypes
- int open_file(DriveData *drive, int channel, const char *filename);
- void convert_filename(const char *srcname, char *destname, int *filemode, int *filetype);
- BOOL find_file(DriveData *drive, const char *filename, int *track, int *sector);
- int open_file_ts(DriveData *drive, int channel, int track, int sector);
- int open_directory(DriveData *drive, const char *filename);
- int open_direct(DriveData *drive, int channel, const char *filename);
- void close_all_channels(DriveData *drive);
- void execute_command(DriveData *drive, const char *command);
- void block_read_cmd(DriveData *drive, char *command);
- void buffer_ptr_cmd(DriveData *drive, char *command);
- BOOL parse_bcmd(char *cmd, int *arg1, int *arg2, int *arg3, int *arg4);
- int alloc_buffer(DriveData *drive, int want);
- void free_buffer(DriveData *drive, int buf);
- BOOL read_sector(DriveData *drive, int track, int sector, char *buffer);
- int offset_from_ts(int track, int sector);
-
-
- /**
- ** Emulation vorbereiten, .d64-Datei öffnen, prefs zeigt auf den
- ** Preferences-String
- **/
-
- struct FileInfoBlock fib;
-
- void D64_Init(DriveData *drive, char *prefs)
- {
- BPTR lock;
- int i;
- ULONG magic;
-
- // Dateilänge prüfen
- if (lock = Lock(prefs, ACCESS_READ)) {
- Examine(lock, &fib);
- UnLock(lock);
-
- if (fib.fib_Size < 174848)
- return;
- } else
- return;
-
- if (drive->ram = malloc(2048)) {
- drive->BAM = drive->ram + 0x700;
-
- if (drive->lock = Open(prefs, MODE_OLDFILE)) {
-
- // x64 Image?
- Read(drive->lock, &magic, 4);
- drive->image_header = (magic == 0x43154164 ? 64 : 0);
-
- // BAM lesen
- read_sector(drive, 18, 0, (char *)drive->BAM);
-
- for (i=0; i<=14; i++) {
- drive->chan_mode[i] = CHMOD_FREE;
- drive->chan_buf[i] = NULL;
- }
-
- drive->chan_mode[15] = CHMOD_COMMAND;
- drive->cmd_length = 0;
-
- for (i=0; i<4; i++)
- drive->buf_free[i] = TRUE;
-
- SetError(drive, ERR_STARTUP);
- }
- }
- }
-
-
- /**
- ** Emulation beenden, .d64-Datei schließen
- **/
-
- void D64_Exit(DriveData *drive)
- {
- if (drive->lock) {
- close_all_channels(drive);
-
- Close(drive->lock);
- drive->lock = NULL;
- }
-
- if (drive->ram) {
- free(drive->ram);
- drive->ram = NULL;
- }
- }
-
-
- /**
- ** Kanal öffnen, filename ist Null-terminiert
- **/
-
- int D64_Open(DriveData *drive, int channel, char *filename)
- {
- SetError(drive, ERR_OK);
-
- // Kanal 15: Dateiname als Befehl ausführen
- if (channel == 15) {
- execute_command(drive, filename);
- return ST_OK;
- }
-
- if (drive->chan_mode[channel] != CHMOD_FREE) {
- SetError(drive, ERR_NOCHANNEL);
- return ST_OK;
- }
-
- if (filename[0] == '$')
- if (channel)
- return open_file_ts(drive, channel, 18, 0);
- else
- return open_directory(drive, filename);
-
- if (filename[0] == '#')
- return open_direct(drive, channel, filename);
-
- return open_file(drive, channel, filename);
- }
-
-
- /*
- * Datei wird geöffnet
- */
-
- // Zugriffsmodi
- enum {
- FMODE_READ, FMODE_WRITE, FMODE_APPEND
- };
-
- // Dateitypen
- enum {
- FTYPE_PRG, FTYPE_SEQ, FTYPE_USR, FTYPE_REL
- };
-
- int open_file(DriveData *drive, int channel, const char *filename)
- {
- char plainname[256];
- int filemode = FMODE_READ;
- int filetype = FTYPE_PRG;
- int track, sector;
-
- convert_filename(filename, plainname, &filemode, &filetype);
-
- // Bei Kanal 0 immer PRG lesen, bei Kanal 1 immer PRG schreiben
- if (!channel) {
- filemode = FMODE_READ;
- filetype = FTYPE_PRG;
- }
- if (channel == 1) {
- filemode = FMODE_WRITE;
- filetype = FTYPE_PRG;
- }
-
- // Nur Lesezugriffe erlaubt
- if (filemode != FMODE_READ) {
- SetError(drive, ERR_WRITEPROTECT);
- return ST_OK;
- }
-
- // Datei im Directory suchen und öffnen
- if (find_file(drive, plainname, &track, §or))
- return open_file_ts(drive, channel, track, sector);
- else
- SetError(drive, ERR_FILENOTFOUND);
-
- return ST_OK;
- }
-
-
- /*
- * Dateibezeichnung analysieren, Dateimodus und -typ ermitteln
- */
-
- void convert_filename(const char *srcname, char *destname, int *filemode, int *filetype)
- {
- char *p, *q;
- int i;
-
- // Nach ':' suchen, p zeigt auf erstes Zeichen hinter dem ':'
- if (p = strchr(srcname, ':'))
- p++;
- else
- p = srcname;
-
- // Reststring -> destname
- strncpy(destname, p, NAMEBUF_LENGTH);
-
- // Nach ',' suchen
- p = destname;
- while (*p && (*p != ',')) p++;
-
- // Nach Modusparametern, getrennt durch ',' suchen
- p = destname;
- while (p = strchr(p, ',')) {
-
- // String hinter dem ersten ',' abschneiden
- *p++ = 0;
-
- switch (*p) {
- case 'P':
- *filetype = FTYPE_PRG;
- break;
- case 'S':
- *filetype = FTYPE_SEQ;
- break;
- case 'U':
- *filetype = FTYPE_USR;
- break;
- case 'L':
- *filetype = FTYPE_REL;
- break;
- case 'R':
- *filemode = FMODE_READ;
- break;
- case 'W':
- *filemode = FMODE_WRITE;
- break;
- case 'A':
- *filemode = FMODE_APPEND;
- break;
- }
- }
- }
-
-
- /*
- * Datei im Directory suchen, ersten Track und Sektor ermitteln
- * FALSE=nicht gefunden, TRUE=gefunden
- */
-
- BOOL find_file(DriveData *drive, const char *filename, int *track, int *sector)
- {
- int i, j;
- UBYTE *p, *q;
- DirEntry *dir;
-
- // Alle Directory-Blöcke scannen
- drive->dir.next_track = drive->BAM->dir_track;
- drive->dir.next_sector = drive->BAM->dir_sector;
-
- while (drive->dir.next_track) {
- if (!read_sector(drive, drive->dir.next_track, drive->dir.next_sector,
- (char *) &drive->dir))
- return FALSE;
-
- // Alle 8 Einträge eines Blocks scannen
- for (j=0; j<8; j++) {
- dir = &drive->dir.entry[j];
- *track = dir->track;
- *sector = dir->sector;
-
- if (dir->type) {
- p = filename;
- q = dir->name;
- for (i=0; i<16 && *p; i++, p++, q++) {
- if (*p == '*')
- return TRUE;
- if (*p != *q) {
- if (*p != '?') goto next;
- if (*q == 0xa0) goto next;
- }
- }
-
- if (i == 16 || *q == 0xa0)
- return TRUE;
- }
- next:
- }
- }
-
- return FALSE;
- }
-
-
- /*
- * Datei öffnen, Track und Sektor des ersten Blocks gegeben
- */
- int open_file_ts(DriveData *drive, int channel, int track, int sector)
- {
- if (drive->chan_buf[channel] = malloc(256)) {
- drive->chan_mode[channel] = CHMOD_FILE;
-
- // Beim nächsten D64_Read-Aufruf wird der erste Block gelesen
- drive->chan_buf[channel][0] = track;
- drive->chan_buf[channel][1] = sector;
- drive->buf_len[channel] = 0;
- }
-
- return ST_OK;
- }
-
-
- /*
- * Directory als Basic-Programm vorbereiten (Kanal 0)
- */
-
- const char type_char_1[] = {'D', 'S', 'P', 'U', 'R'};
- const char type_char_2[] = {'E', 'E', 'R', 'S', 'E'};
- const char type_char_3[] = {'L', 'Q', 'G', 'R', 'L'};
-
- int open_directory(DriveData *drive, const char *filename)
- {
- int i, j, n, m;
- char *p, *q;
- DirEntry *dir;
- UBYTE c;
-
- if (p = drive->buf_ptr[0] = drive->chan_buf[0] = malloc(8192)) {
- drive->chan_mode[0] = CHMOD_DIRECTORY;
-
- // Directory-Titel erzeugen
- *p++ = 0x01; // Ladeadresse $0401 (aus PET-Zeiten :-)
- *p++ = 0x04;
- *p++ = 0x01; // Dummy-Verkettung
- *p++ = 0x01;
- *p++ = 0; // Laufwerksnummer (0) als Zeilennummer
- *p++ = 0;
- *p++ = 0x12; // RVS ON
- *p++ = '\"';
-
- q = drive->BAM->disk_name;
- for (i=0; i<23; i++) {
- if ((c = *q++) == 0xa0)
- *p++ = ' '; // 0xa0 durch Leerzeichen ersetzen
- else
- *p++ = c;
- }
- *(p-7) = '\"';
- *p++ = 0;
-
- // Alle Directory-Blöcke scannen
- drive->dir.next_track = drive->BAM->dir_track;
- drive->dir.next_sector = drive->BAM->dir_sector;
-
- while (drive->dir.next_track) {
- if (!read_sector(drive, drive->dir.next_track, drive->dir.next_sector,
- (char *) &drive->dir))
- return ST_OK;
-
- // Alle 8 Einträge eines Blocks scannen
- for (j=0; j<8; j++) {
- dir = &drive->dir.entry[j];
-
- if (dir->type) {
- *p++ = 0x01; // Dummy-Verkettung
- *p++ = 0x01;
-
- *p++ = dir->num_blocks_l; // Zeilennummer
- *p++ = dir->num_blocks_h;
-
- *p++ = ' ';
- n = (dir->num_blocks_h << 8) + dir->num_blocks_l;
- if (n<10) *p++ = ' ';
- if (n<100) *p++ = ' ';
-
- *p++ = '\"';
- q = dir->name;
- m = 0;
- for (i=0; i<16; i++) {
- if ((c = *q++) == 0xa0) {
- if (m)
- *p++ = ' '; // Alle 0xa0 durch Leerzeichen ersetzen
- else
- m = *p++ = '\"'; // Aber das erste durch einen '"'
- } else
- *p++ = c;
- }
- if (m)
- *p++ = ' ';
- else
- *p++ = '\"'; // Kein 0xa0, dann ein Leerzeichen anhängen
-
- if (dir->type & 0x80)
- *p++ = ' ';
- else
- *p++ = '*';
-
- *p++ = type_char_1[dir->type & 0x0f];
- *p++ = type_char_2[dir->type & 0x0f];
- *p++ = type_char_3[dir->type & 0x0f];
-
- if (dir->type & 0x40)
- *p++ = '<';
- else
- *p++ = ' ';
-
- *p++ = ' ';
- if (n >= 10) *p++ = ' ';
- if (n >= 100) *p++ = ' ';
- *p++ = 0;
- }
- }
- }
-
- // Abschlußzeile
- q = p;
- for (i=0; i<29; i++)
- *q++ = ' ';
-
- n = 0;
- for (i=0; i<35; i++)
- n += drive->BAM->bitmap[i*4];
-
- *p++ = 0x01; // Dummy-Verkettung
- *p++ = 0x01;
- *p++ = n & 0xff; // Anzahl freier Blöcke als Zeilennummer
- *p++ = (n >> 8) & 0xff;
-
- *p++ = 'B';
- *p++ = 'L';
- *p++ = 'O';
- *p++ = 'C';
- *p++ = 'K';
- *p++ = 'S';
- *p++ = ' ';
- *p++ = 'F';
- *p++ = 'R';
- *p++ = 'E';
- *p++ = 'E';
- *p++ = '.';
-
- p = q;
- *p++ = 0;
- *p++ = 0;
- *p++ = 0;
-
- drive->buf_len[0] = p - drive->chan_buf[0];
- }
-
- return ST_OK;
- }
-
-
- /*
- * Kanal für direkten Pufferzugriff öffnen
- */
-
- int open_direct(DriveData *drive, int channel, const char *filename)
- {
- int buf = -1;
-
- if (filename[1] == 0)
- buf = alloc_buffer(drive, -1);
- else
- if ((filename[1] >= '0') && (filename[1] <= '3') && (filename[2] == 0))
- buf = alloc_buffer(drive, filename[1] - '0');
-
- if (buf == -1) {
- SetError(drive, ERR_NOCHANNEL);
- return ST_OK;
- }
-
- // Die Puffer liegen im 1541-RAM ab $300 und belegen je 256 Byte
- drive->chan_buf[channel] = drive->buf_ptr[channel] = drive->ram + 0x300 + (buf << 8);
- drive->chan_mode[channel] = CHMOD_DIRECT;
- drive->chan_buf_num[channel] = buf;
-
- // Tatsächliche Puffernummer im Puffer ablegen
- *drive->chan_buf[channel] = buf + '0';
- drive->buf_len[channel] = 1;
-
- return ST_OK;
- }
-
-
- /**
- ** Kanal schließen
- **/
-
- int D64_Close(DriveData *drive, int channel)
- {
- if (channel==15) {
- close_all_channels(drive);
- return ST_OK;
- }
-
- switch (drive->chan_mode[channel]) {
- case CHMOD_FREE:
- break;
-
- case CHMOD_DIRECT:
- free_buffer(drive, drive->chan_buf_num[channel]);
- drive->chan_buf[channel] = NULL;
- drive->chan_mode[channel] = CHMOD_FREE;
- break;
-
- default:
- free(drive->chan_buf[channel]);
- drive->chan_buf[channel] = NULL;
- drive->chan_mode[channel] = CHMOD_FREE;
- break;
- }
-
- return ST_OK;
- }
-
-
- /*
- * Alle Kanäle schließen
- */
-
- void close_all_channels(DriveData *drive)
- {
- int i;
-
- for (i=0; i<15; i++) D64_Close(drive, i);
-
- drive->cmd_length = 0;
- }
-
-
- /**
- ** Ein Byte aus Kanal lesen
- **/
-
- int D64_Read(DriveData *drive, int channel, char *data)
- {
- switch (drive->chan_mode[channel]) {
- case CHMOD_FREE:
- return ST_READ_TIMEOUT;
- break;
-
- case CHMOD_COMMAND:
- *data = *drive->error_ptr++;
- if (--drive->error_length)
- return ST_OK;
- else {
- SetError(drive, ERR_OK);
- return ST_EOF;
- }
- break;
-
- case CHMOD_FILE:
- // Nächsten Block lesen, wenn notwendig
- if (drive->chan_buf[channel][0] && !drive->buf_len[channel]) {
- if (!read_sector(drive, drive->chan_buf[channel][0],
- drive->chan_buf[channel][1], drive->chan_buf[channel]))
- return ST_READ_TIMEOUT;
- drive->buf_ptr[channel] = drive->chan_buf[channel] + 2;
-
- // Blocklänge ermitteln
- drive->buf_len[channel] = drive->chan_buf[channel][0] ? 254 : (UBYTE)drive->chan_buf[channel][1];
- }
-
- if (drive->buf_len[channel] > 0) {
- *data = *drive->buf_ptr[channel]++;
- if (!--drive->buf_len[channel] && !drive->chan_buf[channel][0])
- return ST_EOF;
- else
- return ST_OK;
- } else
- return ST_READ_TIMEOUT;
- break;
-
- case CHMOD_DIRECTORY:
- case CHMOD_DIRECT:
- if (drive->buf_len[channel] > 0) {
- *data = *drive->buf_ptr[channel]++;
- if (--drive->buf_len[channel])
- return ST_OK;
- else
- return ST_EOF;
- } else
- return ST_READ_TIMEOUT;
- break;
- }
- }
-
-
- /**
- ** Ein Byte in Kanal schreiben
- **/
-
- int D64_Write(DriveData *drive, int channel, char data, char eof)
- {
- // Kanal 15: Zeichen sammeln und bei EOF Befehl ausführen
- if (channel == 15) {
- if (drive->cmd_length >= 40)
- return ST_TIMEOUT;
-
- drive->cmd_buffer[drive->cmd_length++] = data;
-
- if (eof < 0) {
- drive->cmd_buffer[drive->cmd_length++] = 0;
- drive->cmd_length = 0;
- execute_command(drive, drive->cmd_buffer);
- }
- return ST_OK;
- }
-
- if (drive->chan_mode[channel] == CHMOD_FREE)
- SetError(drive, ERR_FILENOTOPEN);
-
- if (drive->chan_mode[channel] == CHMOD_DIRECTORY)
- SetError(drive, ERR_WRITEFILEOPEN);
-
- return ST_TIMEOUT;
- }
-
-
- /*
- * Befehlsstring ausführen
- */
-
- void execute_command(DriveData *drive, const char *command)
- {
- UWORD adr;
- APTR args;
-
- switch (command[0]) {
- case 'B':
- if (command[1] != '-') {
- SetError(drive, ERR_SYNTAX30);
- } else {
- switch (command[2]) {
- case 'R':
- block_read_cmd(drive, &command[3]);
- break;
-
- case 'P':
- buffer_ptr_cmd(drive, &command[3]);
- break;
-
- case 'A':
- case 'F':
- case 'W':
- SetError(drive, ERR_WRITEPROTECT);
- break;
-
- case 'E':
- args = "B-E";
- if (ShowRequester(MSG_UNSUPFLOPPYCMD, MSG_REQGADS3, &args))
- ResetC64();
- SetError(drive, ERR_SYNTAX30);
- break;
-
- default:
- SetError(drive, ERR_SYNTAX30);
- break;
- }
- }
- break;
-
- case 'M':
- if (command[1] != '-') {
- SetError(drive, ERR_SYNTAX30);
- } else {
- switch (command[2]) {
- case 'R':
- adr = ((UBYTE)command[4] << 8) | ((UBYTE)command[3]);
- drive->error_ptr = drive->ram + (adr & 0x07ff);
- if (!(drive->error_length = (UBYTE)command[5]))
- drive->error_length = 1;
- break;
-
- case 'E':
- args = "M-E";
- if (ShowRequester(MSG_UNSUPFLOPPYCMD, MSG_REQGADS3, &args))
- ResetC64();
- SetError(drive, ERR_SYNTAX30);
- break;
-
- case 'W':
- args = "M-W";
- if (ShowRequester(MSG_UNSUPFLOPPYCMD, MSG_REQGADS3, &args))
- ResetC64();
- SetError(drive, ERR_SYNTAX30);
- break;
-
- default:
- SetError(drive, ERR_SYNTAX30);
- break;
- }
- }
- break;
-
- case 'I':
- close_all_channels(drive);
- read_sector(drive, 18, 0, (char *)drive->BAM);
- SetError(drive, ERR_OK);
- break;
-
- case 'U':
- switch (command[1] & 0x0f) {
- case 1: // U1/UA: Block-Read
- block_read_cmd(drive, &command[2]);
- break;
-
- case 2: // U2/UB: Block-Write
- SetError(drive, ERR_WRITEPROTECT);
- break;
-
- case 10: // U:/UJ: Reset
- close_all_channels(drive);
- read_sector(drive, 18, 0, (char *)drive->BAM);
- SetError(drive, ERR_STARTUP);
- break;
-
- default:
- SetError(drive, ERR_SYNTAX30);
- break;
- }
- break;
-
- case 'C':
- case 'N':
- case 'R':
- case 'S':
- case 'V':
- SetError(drive, ERR_WRITEPROTECT);
- break;
-
- default:
- SetError(drive, ERR_SYNTAX30);
- break;
- }
- }
-
-
- /*
- * B-R-Befehl ausführen
- */
-
- void block_read_cmd(DriveData *drive, char *command)
- {
- int channel, drvnum, track, sector;
-
- if (parse_bcmd(command, &channel, &drvnum, &track, §or)) {
- if (drive->chan_mode[channel] == CHMOD_DIRECT) {
- read_sector(drive, track, sector, drive->buf_ptr[channel] = drive->chan_buf[channel]);
- drive->buf_len[channel] = 256;
- SetError(drive, ERR_OK);
- } else
- SetError(drive, ERR_NOCHANNEL);
- } else
- SetError(drive, ERR_SYNTAX30);
- }
-
-
- /*
- * B-P-Befehl ausführen
- */
-
- void buffer_ptr_cmd(DriveData *drive, char *command)
- {
- int channel, pointer, i;
-
- if (parse_bcmd(command, &channel, &pointer, &i, &i)) {
- if (drive->chan_mode[channel] == CHMOD_DIRECT) {
- drive->buf_ptr[channel] = drive->chan_buf[channel] + pointer;
- drive->buf_len[channel] = 256 - pointer;
- SetError(drive, ERR_OK);
- } else
- SetError(drive, ERR_NOCHANNEL);
- } else
- SetError(drive, ERR_SYNTAX30);
- }
-
-
- /*
- * Parameter der Block-Befehle auswerten
- * TRUE: OK, FALSE: Fehler
- */
-
- BOOL parse_bcmd(char *cmd, int *arg1, int *arg2, int *arg3, int *arg4)
- {
- int i;
-
- if (*cmd == ':') cmd++;
-
- // Vier durch Leerzeichen, Cursor Right oder Komma getrennte Parameter lesen
- while (*cmd == ' ' || *cmd == 0x1d || *cmd == 0x2c) cmd++;
- if (!*cmd) return FALSE;
-
- i = 0;
- while (*cmd >= 0x30 && *cmd < 0x40) {
- i *= 10;
- i += *cmd++ & 0x0f;
- }
- *arg1 = i & 0xff;
-
- while (*cmd == ' ' || *cmd == 0x1d || *cmd == 0x2c) cmd++;
- if (!*cmd) return TRUE;
-
- i = 0;
- while (*cmd >= 0x30 && *cmd < 0x40) {
- i *= 10;
- i += *cmd++ & 0x0f;
- }
- *arg2 = i & 0xff;
-
- while (*cmd == ' ' || *cmd == 0x1d || *cmd == 0x2c) cmd++;
- if (!*cmd) return TRUE;
-
- i = 0;
- while (*cmd >= 0x30 && *cmd < 0x40) {
- i *= 10;
- i += *cmd++ & 0x0f;
- }
- *arg3 = i & 0xff;
-
- while (*cmd == ' ' || *cmd == 0x1d || *cmd == 0x2c) cmd++;
-
- i = 0;
- while (*cmd >= 0x30 && *cmd < 0x40) {
- i *= 10;
- i += *cmd++ & 0x0f;
- }
- *arg4 = i & 0xff;
-
- return TRUE;
- }
-
-
- /*
- * Einen Floppy-Puffer belegen
- * -> Gewünschte Puffernummer oder -1
- * <- Belegte Puffernummer oder -1
- */
-
- int alloc_buffer(DriveData *drive, int want)
- {
- if (want == -1) {
- for (want=3; want>=0; want--)
- if (drive->buf_free[want]) {
- drive->buf_free[want] = FALSE;
- return want;
- }
- return -1;
- }
-
- if (want < 4)
- if (drive->buf_free[want]) {
- drive->buf_free[want] = FALSE;
- return want;
- } else
- return -1;
- else
- return -1;
- }
-
-
- /*
- * Einen Floppy-Puffer freigeben
- */
-
- void free_buffer(DriveData *drive, int buf)
- {
- drive->buf_free[buf] = TRUE;
- }
-
-
- /*
- * Einen Sektor lesen (256 Bytes)
- * TRUE: Gelungen, FALSE: Fehler
- */
-
- BOOL read_sector(DriveData *drive, int track, int sector, char *buffer)
- {
- int offset;
-
- // Track/Sektor-Angabe in Byteoffset in der Datei umwandeln
- if ((offset = offset_from_ts(track, sector)) < 0) {
- SetError(drive, ERR_ILLEGALTS);
- return FALSE;
- }
-
- Seek(drive->lock, offset + drive->image_header, OFFSET_BEGINNING);
- Read(drive->lock, buffer, 256);
- return TRUE;
- }
-
-
- /*
- * Track/Sektor in Offset umrechnen
- */
-
- const int num_sectors[36] = {
- 0,
- 21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21
- 19,19,19,19,19,19,19,
- 18,18,18,18,18,18,
- 17,17,17,17,17
- };
-
- const int sector_offset[36] = {
- 0,
- 0,21,42,63,84,105,126,147,168,189,210,231,252,273,294,315,336,
- 357,376,395,414,433,452,471,
- 490,508,526,544,562,580,
- 598,615,632,649,666
- };
-
- int offset_from_ts(int track, int sector)
- {
- if ((track < 1) || (track > NUM_TRACKS) ||
- (sector < 0) || (sector >= num_sectors[track]))
- return -1;
-
- return (sector_offset[track] + sector) << 8;
- }
-