2017-09-13 01:58:18 -04:00
|
|
|
/*
|
2022-10-27 17:08:58 -04:00
|
|
|
* 86Box A hypervisor and IBM PC system emulator that specializes in
|
|
|
|
|
* running old operating systems and software designed for IBM
|
|
|
|
|
* PC systems and compatibles from 1981 through fairly recent
|
|
|
|
|
* system designs based on the PCI bus.
|
2017-09-13 01:58:18 -04:00
|
|
|
*
|
2022-10-27 17:08:58 -04:00
|
|
|
* This file is part of the 86Box distribution.
|
2017-09-13 01:58:18 -04:00
|
|
|
*
|
2022-10-27 17:08:58 -04:00
|
|
|
* Implementation of the PCjs JSON floppy image format.
|
2017-09-13 01:58:18 -04:00
|
|
|
*
|
2020-03-25 00:46:02 +02:00
|
|
|
*
|
2017-09-13 01:58:18 -04:00
|
|
|
*
|
2022-10-27 17:08:58 -04:00
|
|
|
* Authors: Fred N. van Kempen, <decwiz@yahoo.com>
|
2017-10-12 14:25:17 -04:00
|
|
|
*
|
2022-10-27 17:08:58 -04:00
|
|
|
* Copyright 2017-2019 Fred N. van Kempen.
|
2018-03-19 01:02:04 +01:00
|
|
|
*
|
2022-10-27 17:08:58 -04:00
|
|
|
* Redistribution and use in source and binary forms, with
|
|
|
|
|
* or without modification, are permitted provided that the
|
|
|
|
|
* following conditions are met:
|
2018-03-19 01:02:04 +01:00
|
|
|
*
|
2022-10-27 17:08:58 -04:00
|
|
|
* 1. Redistributions of source code must retain the entire
|
|
|
|
|
* above notice, this list of conditions and the following
|
|
|
|
|
* disclaimer.
|
2018-03-19 01:02:04 +01:00
|
|
|
*
|
2022-10-27 17:08:58 -04:00
|
|
|
* 2. Redistributions in binary form must reproduce the above
|
|
|
|
|
* copyright notice, this list of conditions and the
|
|
|
|
|
* following disclaimer in the documentation and/or other
|
|
|
|
|
* materials provided with the distribution.
|
2018-03-19 01:02:04 +01:00
|
|
|
*
|
2022-10-27 17:08:58 -04:00
|
|
|
* 3. Neither the name of the copyright holder nor the names
|
|
|
|
|
* of its contributors may be used to endorse or promote
|
|
|
|
|
* products derived from this software without specific
|
|
|
|
|
* prior written permission.
|
2018-03-19 01:02:04 +01:00
|
|
|
*
|
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
|
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
|
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
|
|
|
|
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
|
|
|
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
|
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
|
|
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
|
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
|
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
|
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
|
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
2017-09-13 01:58:18 -04:00
|
|
|
*/
|
2018-05-21 19:04:05 +02:00
|
|
|
#include <stdarg.h>
|
2017-09-25 04:31:20 -04:00
|
|
|
#include <stdint.h>
|
2018-05-21 19:04:05 +02:00
|
|
|
#include <stdio.h>
|
2017-09-25 04:31:20 -04:00
|
|
|
#include <string.h>
|
2017-09-13 01:58:18 -04:00
|
|
|
#include <stdlib.h>
|
2017-09-25 04:31:20 -04:00
|
|
|
#include <wchar.h>
|
2018-05-21 19:04:05 +02:00
|
|
|
#define HAVE_STDARG_H
|
2020-03-29 14:24:42 +02:00
|
|
|
#include <86box/86box.h>
|
|
|
|
|
#include <86box/timer.h>
|
|
|
|
|
#include <86box/plat.h>
|
|
|
|
|
#include <86box/fdd.h>
|
|
|
|
|
#include <86box/fdd_86f.h>
|
|
|
|
|
#include <86box/fdc.h>
|
|
|
|
|
#include <86box/fdd_common.h>
|
|
|
|
|
#include <86box/fdd_json.h>
|
2017-09-13 01:58:18 -04:00
|
|
|
|
2022-09-18 17:14:15 -04:00
|
|
|
#define NTRACKS 256
|
|
|
|
|
#define NSIDES 2
|
|
|
|
|
#define NSECTORS 256
|
2017-09-13 01:58:18 -04:00
|
|
|
|
|
|
|
|
typedef struct {
|
2022-09-18 17:14:15 -04:00
|
|
|
uint8_t track, /* ID: track number */
|
|
|
|
|
side, /* side number */
|
|
|
|
|
sector; /* sector number 1.. */
|
|
|
|
|
uint16_t size; /* encoded size of sector */
|
|
|
|
|
uint8_t *data; /* allocated data for it */
|
2017-09-13 01:58:18 -04:00
|
|
|
} sector_t;
|
|
|
|
|
|
|
|
|
|
typedef struct {
|
2022-09-18 17:14:15 -04:00
|
|
|
FILE *f;
|
2017-09-13 01:58:18 -04:00
|
|
|
|
|
|
|
|
/* Geometry. */
|
2022-09-18 17:14:15 -04:00
|
|
|
uint8_t tracks, /* number of tracks */
|
|
|
|
|
sides, /* number of sides */
|
|
|
|
|
sectors, /* number of sectors per track */
|
|
|
|
|
spt[NTRACKS][NSIDES]; /* number of sectors per track */
|
2017-09-13 01:58:18 -04:00
|
|
|
|
2022-09-18 17:14:15 -04:00
|
|
|
uint8_t track, /* current track */
|
|
|
|
|
side, /* current side */
|
|
|
|
|
sector[NSIDES]; /* current sector */
|
2017-09-13 01:58:18 -04:00
|
|
|
|
2022-09-18 17:14:15 -04:00
|
|
|
uint8_t dmf; /* disk is DMF format */
|
|
|
|
|
uint8_t interleave;
|
2017-09-13 01:58:18 -04:00
|
|
|
#if 0
|
2022-10-27 17:08:58 -04:00
|
|
|
uint8_t skew;
|
2017-09-13 01:58:18 -04:00
|
|
|
#endif
|
2022-09-18 17:14:15 -04:00
|
|
|
uint8_t gap2_len;
|
|
|
|
|
uint8_t gap3_len;
|
|
|
|
|
int track_width;
|
2017-09-13 01:58:18 -04:00
|
|
|
|
2022-09-18 17:14:15 -04:00
|
|
|
uint16_t disk_flags, /* flags for the entire disk */
|
|
|
|
|
track_flags; /* flags for the current track */
|
2017-09-13 01:58:18 -04:00
|
|
|
|
2022-09-18 17:14:15 -04:00
|
|
|
uint8_t interleave_ordered[NTRACKS][NSIDES];
|
2017-09-13 01:58:18 -04:00
|
|
|
|
2022-09-18 17:14:15 -04:00
|
|
|
sector_t sects[NTRACKS][NSIDES][NSECTORS];
|
2017-09-13 01:58:18 -04:00
|
|
|
} json_t;
|
|
|
|
|
|
2022-09-18 17:14:15 -04:00
|
|
|
static json_t *images[FDD_NUM];
|
2017-09-13 01:58:18 -04:00
|
|
|
|
PIC rewrite, proper SMRAM API, complete SiS 471 rewrite and addition of 40x, 460, and 461, changes to mem.c/h, disabled Voodoo memory dumping on exit, bumped SDL Hardware scale quality to 2, bumped IDE/ATAPI drives to ATA-6, finally bumped emulator version to 3.0, redid the bus type ID's to allow for planned ATAPI hard disks, made SST flash set its high mappings to the correct address if the CPU is 16-bit, and added the SiS 401 AMI 486 Clone, AOpen Vi15G, and the Soyo 4SA2 (486 with SiS 496/497 that can boot from CD-ROM), assorted 286+ protected mode fixes (for slightly more accuracy), and fixes to 808x emulation (MS Word 1.0 and 1.10 for DOS now work correctly from floppy).
2020-10-14 23:15:01 +02:00
|
|
|
#define ENABLE_JSON_LOG 1
|
2018-05-21 19:04:05 +02:00
|
|
|
#ifdef ENABLE_JSON_LOG
|
|
|
|
|
int json_do_log = ENABLE_JSON_LOG;
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
json_log(const char *fmt, ...)
|
|
|
|
|
{
|
2022-09-18 17:14:15 -04:00
|
|
|
va_list ap;
|
|
|
|
|
|
|
|
|
|
if (json_do_log) {
|
|
|
|
|
va_start(ap, fmt);
|
|
|
|
|
pclog_ex(fmt, ap);
|
|
|
|
|
va_end(ap);
|
|
|
|
|
}
|
2018-05-21 19:04:05 +02:00
|
|
|
}
|
2018-10-19 00:39:32 +02:00
|
|
|
#else
|
2022-09-18 17:14:15 -04:00
|
|
|
# define json_log(fmt, ...)
|
2018-10-19 00:39:32 +02:00
|
|
|
#endif
|
2018-05-21 19:04:05 +02:00
|
|
|
|
2017-09-13 01:58:18 -04:00
|
|
|
static void
|
2018-03-19 01:02:04 +01:00
|
|
|
handle(json_t *dev, char *name, char *str)
|
2017-09-13 01:58:18 -04:00
|
|
|
{
|
|
|
|
|
sector_t *sec = NULL;
|
2022-09-18 17:14:15 -04:00
|
|
|
uint32_t l, pat;
|
|
|
|
|
uint8_t *p;
|
|
|
|
|
char *sp;
|
|
|
|
|
int i, s;
|
2017-09-13 01:58:18 -04:00
|
|
|
|
|
|
|
|
/* Point to the currently selected sector. */
|
2022-09-18 17:14:15 -04:00
|
|
|
sec = &dev->sects[dev->track][dev->side][dev->dmf - 1];
|
2017-09-13 01:58:18 -04:00
|
|
|
|
|
|
|
|
/* If no name given, assume sector is done. */
|
|
|
|
|
if (name == NULL) {
|
2022-09-18 17:14:15 -04:00
|
|
|
/* If no buffer, assume one with 00's. */
|
|
|
|
|
if (sec->data == NULL) {
|
|
|
|
|
sec->data = (uint8_t *) malloc(sec->size);
|
|
|
|
|
memset(sec->data, 0x00, sec->size);
|
|
|
|
|
}
|
2017-09-13 01:58:18 -04:00
|
|
|
|
2022-09-18 17:14:15 -04:00
|
|
|
/* Encode the sector size. */
|
|
|
|
|
sec->size = fdd_sector_size_code(sec->size);
|
2017-09-13 01:58:18 -04:00
|
|
|
|
2022-09-18 17:14:15 -04:00
|
|
|
/* Set up the rest of the Sector ID. */
|
|
|
|
|
sec->track = dev->track;
|
|
|
|
|
sec->side = dev->side;
|
2017-09-13 01:58:18 -04:00
|
|
|
|
2022-09-18 17:14:15 -04:00
|
|
|
return;
|
2017-09-13 01:58:18 -04:00
|
|
|
}
|
|
|
|
|
|
2022-09-18 17:14:15 -04:00
|
|
|
if (!strcmp(name, "sector")) {
|
|
|
|
|
sec->sector = atoi(str);
|
|
|
|
|
sec->size = 512;
|
|
|
|
|
} else if (!strcmp(name, "length")) {
|
|
|
|
|
sec->size = atoi(str);
|
|
|
|
|
} else if (!strcmp(name, "pattern")) {
|
|
|
|
|
pat = atol(str);
|
|
|
|
|
|
|
|
|
|
if (sec->data == NULL)
|
|
|
|
|
sec->data = (uint8_t *) malloc(sec->size);
|
|
|
|
|
p = sec->data;
|
|
|
|
|
s = (sec->size / sizeof(uint32_t));
|
|
|
|
|
for (i = 0; i < s; i++) {
|
|
|
|
|
l = pat;
|
|
|
|
|
*p++ = (l & 0x000000ff);
|
|
|
|
|
l >>= 8;
|
|
|
|
|
*p++ = (l & 0x000000ff);
|
|
|
|
|
l >>= 8;
|
|
|
|
|
*p++ = (l & 0x000000ff);
|
|
|
|
|
l >>= 8;
|
|
|
|
|
*p++ = (l & 0x000000ff);
|
|
|
|
|
}
|
|
|
|
|
} else if (!strcmp(name, "data")) {
|
|
|
|
|
if (sec->data == NULL)
|
|
|
|
|
sec->data = (uint8_t *) malloc(sec->size);
|
|
|
|
|
p = sec->data;
|
|
|
|
|
while (str && *str) {
|
|
|
|
|
sp = strchr(str, ',');
|
|
|
|
|
if (sp != NULL)
|
|
|
|
|
*sp++ = '\0';
|
|
|
|
|
l = atol(str);
|
|
|
|
|
|
|
|
|
|
*p++ = (l & 0x000000ff);
|
|
|
|
|
l >>= 8;
|
|
|
|
|
*p++ = (l & 0x000000ff);
|
|
|
|
|
l >>= 8;
|
|
|
|
|
*p++ = (l & 0x000000ff);
|
|
|
|
|
l >>= 8;
|
|
|
|
|
*p++ = (l & 0x000000ff);
|
|
|
|
|
|
|
|
|
|
str = sp;
|
|
|
|
|
}
|
2017-09-13 01:58:18 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
unexpect(int c, int state, int level)
|
|
|
|
|
{
|
2018-05-21 19:04:05 +02:00
|
|
|
json_log("JSON: Unexpected '%c' in state %d/%d.\n", c, state, level);
|
2017-09-13 01:58:18 -04:00
|
|
|
|
2022-09-18 17:14:15 -04:00
|
|
|
return (-1);
|
2017-09-13 01:58:18 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
2018-03-19 01:02:04 +01:00
|
|
|
load_image(json_t *dev)
|
2017-09-13 01:58:18 -04:00
|
|
|
{
|
2022-09-18 17:14:15 -04:00
|
|
|
char buff[4096], name[32];
|
|
|
|
|
int c, i, j, state, level;
|
2017-09-13 01:58:18 -04:00
|
|
|
char *ptr;
|
|
|
|
|
|
2018-03-19 01:02:04 +01:00
|
|
|
if (dev->f == NULL) {
|
2022-09-18 17:14:15 -04:00
|
|
|
json_log("JSON: no file loaded!\n");
|
|
|
|
|
return (0);
|
2017-09-13 01:58:18 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Initialize. */
|
2022-09-18 17:14:15 -04:00
|
|
|
for (i = 0; i < NTRACKS; i++) {
|
|
|
|
|
for (j = 0; j < NSIDES; j++)
|
|
|
|
|
memset(dev->sects[i][j], 0x00, sizeof(sector_t));
|
2017-09-13 01:58:18 -04:00
|
|
|
}
|
2022-09-18 17:14:15 -04:00
|
|
|
dev->track = dev->side = dev->dmf = 0; /* "dmf" is "sector#" */
|
2017-09-13 01:58:18 -04:00
|
|
|
|
|
|
|
|
/* Now run the state machine. */
|
2022-09-18 17:14:15 -04:00
|
|
|
ptr = NULL;
|
2017-09-13 01:58:18 -04:00
|
|
|
level = state = 0;
|
|
|
|
|
while (state >= 0) {
|
2022-09-18 17:14:15 -04:00
|
|
|
/* Get a character from the input. */
|
|
|
|
|
c = fgetc(dev->f);
|
|
|
|
|
if ((c == EOF) || ferror(dev->f)) {
|
|
|
|
|
state = -1;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Process it. */
|
|
|
|
|
switch (state) {
|
|
|
|
|
case 0: /* read level header */
|
|
|
|
|
dev->dmf = 1;
|
|
|
|
|
if ((c != '[') && (c != '{') && (c != '\r') && (c != '\n')) {
|
|
|
|
|
state = unexpect(c, state, level);
|
|
|
|
|
} else if (c == '[') {
|
|
|
|
|
if (++level == 3)
|
|
|
|
|
state++;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 1: /* read sector header */
|
|
|
|
|
if (c != '{')
|
|
|
|
|
state = unexpect(c, state, level);
|
|
|
|
|
else
|
|
|
|
|
state++;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 2: /* begin sector data name */
|
|
|
|
|
if (c != '\"') {
|
|
|
|
|
state = unexpect(c, state, level);
|
|
|
|
|
} else {
|
|
|
|
|
ptr = name;
|
|
|
|
|
state++;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 3: /* read sector data name */
|
|
|
|
|
if (c == '\"') {
|
|
|
|
|
*ptr = '\0';
|
|
|
|
|
state++;
|
|
|
|
|
} else {
|
|
|
|
|
*ptr++ = c;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 4: /* end of sector data name */
|
|
|
|
|
if (c != ':') {
|
|
|
|
|
state = unexpect(c, state, level);
|
|
|
|
|
} else {
|
|
|
|
|
ptr = buff;
|
|
|
|
|
state++;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 5: /* read sector value data */
|
|
|
|
|
switch (c) {
|
|
|
|
|
case ',':
|
|
|
|
|
case '}':
|
|
|
|
|
*ptr = '\0';
|
|
|
|
|
handle(dev, name, buff);
|
|
|
|
|
|
|
|
|
|
if (c == '}')
|
|
|
|
|
state = 7; /* done */
|
|
|
|
|
else
|
|
|
|
|
state = 2; /* word */
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case '[':
|
|
|
|
|
state++;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
*ptr++ = c;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 6: /* read sector data complex */
|
|
|
|
|
if (c != ']')
|
|
|
|
|
*ptr++ = c;
|
|
|
|
|
else
|
|
|
|
|
state = 5;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 7: /* sector done */
|
|
|
|
|
handle(dev, NULL, NULL);
|
|
|
|
|
switch (c) {
|
|
|
|
|
case ',': /* next sector */
|
|
|
|
|
dev->dmf++;
|
|
|
|
|
state = 1;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ']': /* all sectors done */
|
|
|
|
|
if (--level == 0)
|
|
|
|
|
state = -1;
|
|
|
|
|
else
|
|
|
|
|
state++;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
state = unexpect(c, state, level);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 8: /* side done */
|
|
|
|
|
switch (c) {
|
|
|
|
|
case ',': /* next side */
|
|
|
|
|
state = 0;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ']': /* all sides done */
|
|
|
|
|
if (--level == 0)
|
|
|
|
|
state = -1;
|
|
|
|
|
else
|
|
|
|
|
state++;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
state = unexpect(c, state, level);
|
|
|
|
|
}
|
|
|
|
|
dev->spt[dev->track][dev->side] = dev->dmf;
|
|
|
|
|
dev->side++;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 9: /* track done */
|
|
|
|
|
switch (c) {
|
|
|
|
|
case ',': /* next track */
|
|
|
|
|
dev->side = 0;
|
|
|
|
|
state = 0;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ']': /* all tracks done */
|
|
|
|
|
if (--level == 0)
|
|
|
|
|
state = -1;
|
|
|
|
|
else
|
|
|
|
|
state++;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
state = unexpect(c, state, level);
|
|
|
|
|
}
|
|
|
|
|
dev->track++;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2017-09-13 01:58:18 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Save derived values. */
|
2018-03-19 01:02:04 +01:00
|
|
|
dev->tracks = dev->track;
|
2022-09-18 17:14:15 -04:00
|
|
|
dev->sides = dev->side;
|
2017-09-13 01:58:18 -04:00
|
|
|
|
2022-09-18 17:14:15 -04:00
|
|
|
return (1);
|
2017-09-13 01:58:18 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Seek the heads to a track, and prepare to read data from that track. */
|
|
|
|
|
static void
|
|
|
|
|
json_seek(int drive, int track)
|
|
|
|
|
{
|
2022-09-18 17:14:15 -04:00
|
|
|
uint8_t id[4] = { 0, 0, 0, 0 };
|
|
|
|
|
json_t *dev = images[drive];
|
|
|
|
|
int side, sector;
|
|
|
|
|
int rate, gap2, gap3, pos;
|
|
|
|
|
int ssize, rsec, asec;
|
2017-09-13 01:58:18 -04:00
|
|
|
|
2018-03-19 01:02:04 +01:00
|
|
|
if (dev->f == NULL) {
|
2022-09-18 17:14:15 -04:00
|
|
|
json_log("JSON: seek: no file loaded!\n");
|
|
|
|
|
return;
|
2017-09-13 01:58:18 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Allow for doublestepping tracks. */
|
2022-09-18 17:14:15 -04:00
|
|
|
if (!dev->track_width && fdd_doublestep_40(drive))
|
|
|
|
|
track /= 2;
|
2017-09-13 01:58:18 -04:00
|
|
|
|
|
|
|
|
/* Set the new track. */
|
2018-03-19 01:02:04 +01:00
|
|
|
dev->track = track;
|
2018-01-17 18:43:36 +01:00
|
|
|
d86f_set_cur_track(drive, track);
|
2017-09-13 01:58:18 -04:00
|
|
|
|
|
|
|
|
/* Reset the 86F state machine. */
|
|
|
|
|
d86f_reset_index_hole_pos(drive, 0);
|
2018-03-15 00:02:19 +01:00
|
|
|
d86f_destroy_linked_lists(drive, 0);
|
2018-03-19 01:02:04 +01:00
|
|
|
d86f_reset_index_hole_pos(drive, 1);
|
2018-03-15 00:02:19 +01:00
|
|
|
d86f_destroy_linked_lists(drive, 1);
|
2017-09-13 01:58:18 -04:00
|
|
|
|
2018-03-19 01:02:04 +01:00
|
|
|
if (track > dev->tracks) {
|
2022-09-18 17:14:15 -04:00
|
|
|
d86f_zero_track(drive);
|
|
|
|
|
return;
|
2018-01-17 18:43:36 +01:00
|
|
|
}
|
|
|
|
|
|
2022-09-18 17:14:15 -04:00
|
|
|
for (side = 0; side < dev->sides; side++) {
|
|
|
|
|
/* Get transfer rate for this side. */
|
|
|
|
|
rate = dev->track_flags & 0x07;
|
|
|
|
|
if (!rate && (dev->track_flags & 0x20))
|
|
|
|
|
rate = 4;
|
|
|
|
|
|
|
|
|
|
/* Get correct GAP3 value for this side. */
|
|
|
|
|
gap3 = fdd_get_gap3_size(rate,
|
|
|
|
|
dev->sects[track][side][0].size,
|
|
|
|
|
dev->spt[track][side]);
|
|
|
|
|
|
|
|
|
|
/* Get correct GAP2 value for this side. */
|
|
|
|
|
gap2 = ((dev->track_flags & 0x07) >= 3) ? 41 : 22;
|
|
|
|
|
|
|
|
|
|
pos = d86f_prepare_pretrack(drive, side, 0);
|
|
|
|
|
|
|
|
|
|
for (sector = 0; sector < dev->spt[track][side]; sector++) {
|
|
|
|
|
rsec = dev->sects[track][side][sector].sector;
|
|
|
|
|
asec = sector;
|
|
|
|
|
|
|
|
|
|
id[0] = track;
|
|
|
|
|
id[1] = side;
|
|
|
|
|
id[2] = rsec;
|
|
|
|
|
if (dev->sects[track][side][asec].size > 255)
|
|
|
|
|
perror("fdd_json.c: json_seek: sector size too big.");
|
|
|
|
|
id[3] = dev->sects[track][side][asec].size & 0xff;
|
|
|
|
|
ssize = fdd_sector_code_size(dev->sects[track][side][asec].size & 0xff);
|
|
|
|
|
|
|
|
|
|
pos = d86f_prepare_sector(
|
|
|
|
|
drive, side, pos, id,
|
|
|
|
|
dev->sects[track][side][asec].data,
|
|
|
|
|
ssize, gap2, gap3,
|
|
|
|
|
0 /*flags*/
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (sector == 0)
|
|
|
|
|
d86f_initialize_last_sector_id(drive, id[0], id[1], id[2], id[3]);
|
|
|
|
|
}
|
2017-09-13 01:58:18 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static uint16_t
|
|
|
|
|
disk_flags(int drive)
|
|
|
|
|
{
|
2018-03-19 01:02:04 +01:00
|
|
|
json_t *dev = images[drive];
|
|
|
|
|
|
2022-09-18 17:14:15 -04:00
|
|
|
return (dev->disk_flags);
|
2017-09-13 01:58:18 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static uint16_t
|
|
|
|
|
track_flags(int drive)
|
|
|
|
|
{
|
2018-03-19 01:02:04 +01:00
|
|
|
json_t *dev = images[drive];
|
|
|
|
|
|
2022-09-18 17:14:15 -04:00
|
|
|
return (dev->track_flags);
|
2017-09-13 01:58:18 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
set_sector(int drive, int side, uint8_t c, uint8_t h, uint8_t r, uint8_t n)
|
|
|
|
|
{
|
2018-03-19 01:02:04 +01:00
|
|
|
json_t *dev = images[drive];
|
2022-09-18 17:14:15 -04:00
|
|
|
int i;
|
2017-09-13 01:58:18 -04:00
|
|
|
|
2018-03-19 01:02:04 +01:00
|
|
|
dev->sector[side] = 0;
|
2017-09-13 01:58:18 -04:00
|
|
|
|
|
|
|
|
/* Make sure we are on the desired track. */
|
2022-09-18 17:14:15 -04:00
|
|
|
if (c != dev->track)
|
|
|
|
|
return;
|
2017-09-13 01:58:18 -04:00
|
|
|
|
|
|
|
|
/* Set the desired side. */
|
2018-03-19 01:02:04 +01:00
|
|
|
dev->side = side;
|
2017-09-13 01:58:18 -04:00
|
|
|
|
|
|
|
|
/* Now loop over all sector ID's on this side to find our sector. */
|
2022-09-18 17:14:15 -04:00
|
|
|
for (i = 0; i < dev->spt[c][side]; i++) {
|
|
|
|
|
if ((dev->sects[dev->track][side][i].track == c) && (dev->sects[dev->track][side][i].side == h) && (dev->sects[dev->track][side][i].sector == r) && (dev->sects[dev->track][side][i].size == n)) {
|
|
|
|
|
dev->sector[side] = i;
|
|
|
|
|
}
|
2017-09-13 01:58:18 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static uint8_t
|
|
|
|
|
poll_read_data(int drive, int side, uint16_t pos)
|
|
|
|
|
{
|
2018-03-19 01:02:04 +01:00
|
|
|
json_t *dev = images[drive];
|
|
|
|
|
uint8_t sec = dev->sector[side];
|
2017-09-13 01:58:18 -04:00
|
|
|
|
2022-09-18 17:14:15 -04:00
|
|
|
return (dev->sects[dev->track][side][sec].data[pos]);
|
2017-09-13 01:58:18 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
json_init(void)
|
|
|
|
|
{
|
|
|
|
|
memset(images, 0x00, sizeof(images));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2021-03-14 20:35:01 +01:00
|
|
|
json_load(int drive, char *fn)
|
2017-09-13 01:58:18 -04:00
|
|
|
{
|
2022-09-18 17:14:15 -04:00
|
|
|
double bit_rate;
|
|
|
|
|
int temp_rate;
|
2018-03-19 01:02:04 +01:00
|
|
|
sector_t *sec;
|
2022-09-18 17:14:15 -04:00
|
|
|
json_t *dev;
|
|
|
|
|
int i;
|
2017-09-13 01:58:18 -04:00
|
|
|
|
|
|
|
|
/* Just in case- remove ourselves from 86F. */
|
|
|
|
|
d86f_unregister(drive);
|
|
|
|
|
|
2018-03-19 01:02:04 +01:00
|
|
|
/* Allocate a drive block. */
|
2022-09-18 17:14:15 -04:00
|
|
|
dev = (json_t *) malloc(sizeof(json_t));
|
2018-03-19 01:02:04 +01:00
|
|
|
memset(dev, 0x00, sizeof(json_t));
|
2017-09-13 01:58:18 -04:00
|
|
|
|
|
|
|
|
/* Open the image file. */
|
2021-03-14 20:35:01 +01:00
|
|
|
dev->f = plat_fopen(fn, "rb");
|
2018-03-19 01:02:04 +01:00
|
|
|
if (dev->f == NULL) {
|
2022-09-18 17:14:15 -04:00
|
|
|
free(dev);
|
|
|
|
|
memset(fn, 0x00, sizeof(char));
|
|
|
|
|
return;
|
2017-09-13 01:58:18 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Our images are always RO. */
|
|
|
|
|
writeprot[drive] = 1;
|
|
|
|
|
|
2018-03-19 01:02:04 +01:00
|
|
|
/* Set up the drive unit. */
|
|
|
|
|
images[drive] = dev;
|
|
|
|
|
|
2017-09-13 01:58:18 -04:00
|
|
|
/* Load all sectors from the image file. */
|
2022-09-18 17:14:15 -04:00
|
|
|
if (!load_image(dev)) {
|
|
|
|
|
json_log("JSON: failed to initialize\n");
|
|
|
|
|
(void) fclose(dev->f);
|
|
|
|
|
free(dev);
|
|
|
|
|
images[drive] = NULL;
|
|
|
|
|
memset(fn, 0x00, sizeof(char));
|
|
|
|
|
return;
|
2017-09-13 01:58:18 -04:00
|
|
|
}
|
|
|
|
|
|
2021-03-14 20:35:01 +01:00
|
|
|
json_log("JSON(%d): %s (%i tracks, %i sides, %i sectors)\n",
|
2022-09-18 17:14:15 -04:00
|
|
|
drive, fn, dev->tracks, dev->sides, dev->spt[0][0]);
|
2017-09-13 01:58:18 -04:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If the image has more than 43 tracks, then
|
|
|
|
|
* the tracks are thin (96 tpi).
|
|
|
|
|
*/
|
2018-03-19 01:02:04 +01:00
|
|
|
dev->track_width = (dev->tracks > 43) ? 1 : 0;
|
2017-09-13 01:58:18 -04:00
|
|
|
|
|
|
|
|
/* If the image has 2 sides, mark it as such. */
|
2018-03-19 01:02:04 +01:00
|
|
|
dev->disk_flags = 0x00;
|
|
|
|
|
if (dev->sides == 2)
|
2022-09-18 17:14:15 -04:00
|
|
|
dev->disk_flags |= 0x08;
|
2017-09-13 01:58:18 -04:00
|
|
|
|
|
|
|
|
/* JSON files are always assumed to be MFM-encoded. */
|
2018-03-19 01:02:04 +01:00
|
|
|
dev->track_flags = 0x08;
|
2017-09-13 01:58:18 -04:00
|
|
|
|
2018-03-19 01:02:04 +01:00
|
|
|
dev->interleave = 0;
|
2017-09-13 01:58:18 -04:00
|
|
|
#if 0
|
2018-03-19 01:02:04 +01:00
|
|
|
dev->skew = 0;
|
2017-09-13 01:58:18 -04:00
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
temp_rate = 0xff;
|
2022-09-18 17:14:15 -04:00
|
|
|
sec = &dev->sects[0][0][0];
|
|
|
|
|
for (i = 0; i < 6; i++) {
|
|
|
|
|
if (dev->spt[0][0] > fdd_max_sectors[sec->size][i])
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
bit_rate = fdd_bit_rates_300[i];
|
|
|
|
|
temp_rate = fdd_rates[i];
|
|
|
|
|
dev->disk_flags |= (fdd_holes[i] << 1);
|
|
|
|
|
|
|
|
|
|
if ((bit_rate == 500.0) && (dev->spt[0][0] == 21) && (sec->size == 2) && (dev->tracks >= 80) && (dev->tracks <= 82) && (dev->sides == 2)) {
|
|
|
|
|
/*
|
|
|
|
|
* This is a DMF floppy, set the flag so
|
|
|
|
|
* we know to interleave the sectors.
|
|
|
|
|
*/
|
|
|
|
|
dev->dmf = 1;
|
|
|
|
|
} else {
|
|
|
|
|
if ((bit_rate == 500.0) && (dev->spt[0][0] == 22) && (sec->size == 2) && (dev->tracks >= 80) && (dev->tracks <= 82) && (dev->sides == 2)) {
|
|
|
|
|
/*
|
|
|
|
|
* This is marked specially because of the
|
|
|
|
|
* track flag (a RPM slow down is needed).
|
|
|
|
|
*/
|
|
|
|
|
dev->interleave = 2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dev->dmf = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
break;
|
2017-09-13 01:58:18 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (temp_rate == 0xff) {
|
2022-09-18 17:14:15 -04:00
|
|
|
json_log("JSON: invalid image (temp_rate=0xff)\n");
|
|
|
|
|
(void) fclose(dev->f);
|
|
|
|
|
dev->f = NULL;
|
|
|
|
|
free(dev);
|
|
|
|
|
images[drive] = NULL;
|
|
|
|
|
memset(fn, 0x00, sizeof(char));
|
|
|
|
|
return;
|
2017-09-13 01:58:18 -04:00
|
|
|
}
|
|
|
|
|
|
2018-03-19 01:02:04 +01:00
|
|
|
if (dev->interleave == 2) {
|
2022-09-18 17:14:15 -04:00
|
|
|
dev->interleave = 1;
|
|
|
|
|
dev->disk_flags |= 0x60;
|
2017-09-13 01:58:18 -04:00
|
|
|
}
|
|
|
|
|
|
2018-03-19 01:02:04 +01:00
|
|
|
dev->gap2_len = (temp_rate == 3) ? 41 : 22;
|
|
|
|
|
if (dev->dmf)
|
2022-09-18 17:14:15 -04:00
|
|
|
dev->gap3_len = 8;
|
|
|
|
|
else
|
|
|
|
|
dev->gap3_len = fdd_get_gap3_size(temp_rate, sec->size, dev->spt[0][0]);
|
|
|
|
|
|
|
|
|
|
if (!dev->gap3_len) {
|
|
|
|
|
json_log("JSON: image of unknown format was inserted into drive %c:!\n",
|
|
|
|
|
'C' + drive);
|
|
|
|
|
(void) fclose(dev->f);
|
|
|
|
|
dev->f = NULL;
|
|
|
|
|
free(dev);
|
|
|
|
|
images[drive] = NULL;
|
|
|
|
|
memset(fn, 0x00, sizeof(char));
|
|
|
|
|
return;
|
2017-09-13 01:58:18 -04:00
|
|
|
}
|
|
|
|
|
|
2022-09-18 17:14:15 -04:00
|
|
|
dev->track_flags |= (temp_rate & 0x03); /* data rate */
|
2017-09-13 01:58:18 -04:00
|
|
|
if (temp_rate & 0x04)
|
2022-09-18 17:14:15 -04:00
|
|
|
dev->track_flags |= 0x20; /* RPM */
|
2017-09-13 01:58:18 -04:00
|
|
|
|
2018-05-21 19:04:05 +02:00
|
|
|
json_log(" disk_flags: 0x%02x, track_flags: 0x%02x, GAP3 length: %i\n",
|
2022-09-18 17:14:15 -04:00
|
|
|
dev->disk_flags, dev->track_flags, dev->gap3_len);
|
2018-05-21 19:04:05 +02:00
|
|
|
json_log(" bit rate 300: %.2f, temporary rate: %i, hole: %i, DMF: %i\n",
|
2022-09-18 17:14:15 -04:00
|
|
|
bit_rate, temp_rate, (dev->disk_flags >> 1), dev->dmf);
|
2017-09-13 01:58:18 -04:00
|
|
|
|
|
|
|
|
/* Set up handlers for 86F layer. */
|
2022-09-18 17:14:15 -04:00
|
|
|
d86f_handler[drive].disk_flags = disk_flags;
|
|
|
|
|
d86f_handler[drive].side_flags = track_flags;
|
|
|
|
|
d86f_handler[drive].writeback = null_writeback;
|
|
|
|
|
d86f_handler[drive].set_sector = set_sector;
|
|
|
|
|
d86f_handler[drive].read_data = poll_read_data;
|
|
|
|
|
d86f_handler[drive].write_data = null_write_data;
|
2017-09-13 01:58:18 -04:00
|
|
|
d86f_handler[drive].format_conditions = null_format_conditions;
|
2022-09-18 17:14:15 -04:00
|
|
|
d86f_handler[drive].extra_bit_cells = null_extra_bit_cells;
|
|
|
|
|
d86f_handler[drive].encoded_data = common_encoded_data;
|
|
|
|
|
d86f_handler[drive].read_revolution = common_read_revolution;
|
|
|
|
|
d86f_handler[drive].index_hole_pos = null_index_hole_pos;
|
|
|
|
|
d86f_handler[drive].get_raw_size = common_get_raw_size;
|
|
|
|
|
d86f_handler[drive].check_crc = 1;
|
2017-09-13 01:58:18 -04:00
|
|
|
d86f_set_version(drive, 0x0063);
|
|
|
|
|
|
|
|
|
|
d86f_common_handlers(drive);
|
|
|
|
|
|
|
|
|
|
drives[drive].seek = json_seek;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Close the image. */
|
|
|
|
|
void
|
|
|
|
|
json_close(int drive)
|
|
|
|
|
{
|
2018-03-19 01:02:04 +01:00
|
|
|
json_t *dev = images[drive];
|
2022-09-18 17:14:15 -04:00
|
|
|
int t, h, s;
|
2017-09-13 01:58:18 -04:00
|
|
|
|
2022-09-18 17:14:15 -04:00
|
|
|
if (dev == NULL)
|
|
|
|
|
return;
|
2018-03-19 01:02:04 +01:00
|
|
|
|
2017-09-13 01:58:18 -04:00
|
|
|
/* Unlink image from the system. */
|
|
|
|
|
d86f_unregister(drive);
|
|
|
|
|
|
|
|
|
|
/* Release all the sector buffers. */
|
2022-09-18 17:14:15 -04:00
|
|
|
for (t = 0; t < 256; t++) {
|
|
|
|
|
for (h = 0; h < 2; h++) {
|
|
|
|
|
memset(dev->sects[t][h], 0x00, sizeof(sector_t));
|
|
|
|
|
for (s = 0; s < 256; s++) {
|
|
|
|
|
if (dev->sects[t][h][s].data != NULL)
|
|
|
|
|
free(dev->sects[t][h][s].data);
|
|
|
|
|
dev->sects[t][h][s].data = NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-09-13 01:58:18 -04:00
|
|
|
}
|
|
|
|
|
|
2018-03-19 01:02:04 +01:00
|
|
|
if (dev->f != NULL)
|
2022-09-18 17:14:15 -04:00
|
|
|
(void) fclose(dev->f);
|
2018-03-19 01:02:04 +01:00
|
|
|
|
|
|
|
|
/* Release the memory. */
|
|
|
|
|
free(dev);
|
|
|
|
|
images[drive] = NULL;
|
2017-09-13 01:58:18 -04:00
|
|
|
}
|