diff --git a/.gitignore b/.gitignore index 81d87a57..74bdfd2c 100644 --- a/.gitignore +++ b/.gitignore @@ -31,3 +31,6 @@ src/jstest src/jstest.exe src/gtest src/gtest.exe +src/fsmap +src/hdfmt +src/fdresize diff --git a/src/Makefile.am b/src/Makefile.am index ed9bfa2d..138881d1 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,6 +1,6 @@ # Makefile.am for B-em -bin_PROGRAMS = b-em jstest gtest +bin_PROGRAMS = b-em hdfmt jstest gtest noinst_SCRIPTS = ../b-em CLEANFILES = $(noinst_SCRIPTS) @@ -128,6 +128,8 @@ if NO_TSEARCH b_em_SOURCES += tsearch.c endif +hdfmt_SOURCES = hdfmt.c + jstest_SOURCES = jstest.c jstest_LDADD = -lallegro -lallegro_main diff --git a/src/fsmap.c b/src/fsmap.c new file mode 100644 index 00000000..aeac9e5f --- /dev/null +++ b/src/fsmap.c @@ -0,0 +1,50 @@ +#include +#include +#include +#include +#include + +int main(int argc, char **argv) +{ + int status; + + if (argc > 1) { + status = 0; + while (--argc) { + const char *fn = *++argv; + FILE *fp = fopen(fn, "rb"); + if (fp) { + unsigned char fsmap[0x200]; + if (fread(fsmap, sizeof fsmap, 1, fp) == 1) { + puts(fn); + unsigned char *sptr = fsmap; + unsigned char *eptr = fsmap + fsmap[0x1FE]; + unsigned char *lptr = fsmap + 0x100; + while (sptr < eptr) { + uint32_t start = *sptr++; + start |= (*sptr++ << 8); + start |= (*sptr++ << 16); + uint32_t len = *lptr++; + len |= (*lptr++ << 8); + len |= (*lptr++ << 16); + if (len > 0) + printf("%06X %06X (%d)\n", start, len, len); + } + } + else { + fprintf(stderr, "fsmap: unable to read fsmap from %s: %s\n", fn, strerror(errno)); + status = 3; + } + } + else { + fprintf(stderr, "fsmap: unable to open %s for reading: %s\n", fn, strerror(errno)); + status = 2; + } + } + } + else { + fputs("Usage: fsmap [ ... ]\n", stderr); + status = 1; + } + return status; +} diff --git a/src/hdfmt.c b/src/hdfmt.c index 8dd68de4..477432a0 100644 --- a/src/hdfmt.c +++ b/src/hdfmt.c @@ -150,7 +150,7 @@ int main(int argc, char **argv) } else { - fprintf(stderr, "hdfmt: %s is not a valid size\n", argv[1]); + fprintf(stderr, "hdfmt: %s is not a valid size\n", argv[2]); status = 1; } } diff --git a/src/hdresize.c b/src/hdresize.c new file mode 100644 index 00000000..b1717be3 --- /dev/null +++ b/src/hdresize.c @@ -0,0 +1,157 @@ +#include +#include +#include +#include +#include + +static int parse_size(const char *size) +{ + int value; + char *end; + + value = strtol(size, &end, 10); + switch (*end) { + case 'k': + case 'K': + value *= 1024; + break; + case 'm': + case 'M': + value *= 1024 * 1024; + break; + case 'g': + case 'G': + value *= 1024 * 1024 * 1024; + break; + } + return value; +} + +static inline uint32_t read24(const unsigned char *base) +{ + return base[0] | (base[1] << 8) | (base[2] << 16); +} + +static inline void write24(uint8_t *base, uint32_t value) +{ + base[0] = value & 0xff; + base[1] = (value >> 8) & 0xff; + base[2] = (value >> 16) & 0xff; +} + +static uint8_t checksum(uint8_t *base) +{ + int i = 255, c = 0; + unsigned sum = 255; + while (--i >= 0) { + sum += base[i] + c; + c = 0; + if (sum >= 256) { + sum &= 0xff; + c = 1; + } + } + return sum; +} + +int main(int argc, char **argv) +{ + int status; + + if (argc == 3) { + int size = parse_size(argv[2]); + if (size > 0) { + const char *fn = argv[1]; + size_t len = strlen(fn) + 5; + char *dat_fn = alloca(len); + snprintf(dat_fn, len, "%s.dat", fn); + FILE *dat_fp = fopen(dat_fn, "rb+"); + if (dat_fp) { + unsigned char fsmap[512]; + if (fread(fsmap, sizeof fsmap, 1, dat_fp) == 1) { + if (fsmap[0x1FE] <= 3) { + status = 0; + char *dsc_fn = alloca(len); + snprintf(dsc_fn, len, "%s.dsc", fn); + FILE *dsc_fp = fopen(dsc_fn, "rb+"); + if (dsc_fp) { + unsigned char geom[22]; + if (fread(geom, sizeof geom, 1, dsc_fp) == 1) { + int new_sects = size / 256; + int old_sects = read24(fsmap + 0x0FC); + printf("hdresize: old sectors=%d, new_sects=%d\n", old_sects, new_sects); + if (new_sects > old_sects) { + write24(fsmap + 0x0FC, new_sects); + fsmap[0x0FF] = checksum(fsmap); + unsigned char *ptr = fsmap + 0x100; + write24(ptr, read24(ptr) + (new_sects - old_sects)); + fsmap[0x1ff] = checksum(ptr); + int cyl = 1 + ((new_sects - 1) / (33 * 255)); + geom[13] = cyl % 256; + geom[14] = cyl / 256; + geom[15] = 255; + if (fseek(dsc_fp, 0, SEEK_SET) == 0 && fwrite(geom, sizeof geom, 1, dsc_fp) == 1) { + if (fseek(dat_fp, 0, SEEK_SET) == 0 && fwrite(fsmap, sizeof fsmap, 1, dat_fp) == 1) { + status = 0; + printf("hdresize: %s grown\n", fn); + } + else + { + fprintf(stderr, "hdresize: unable to write fsmap to %s: %s\n", dat_fn, strerror(errno)); + status = 8; + } + } + else { + fprintf(stderr, "hdresize: unable to write geometry to %s: %s\n", dsc_fn, strerror(errno)); + status = 7; + } + } + else { + fputs("hdresize: shrinking not implemented\n", stderr); + status = 6; + } + } + else { + fprintf(stderr, "hdresize: unable to read geometry from %s: %s\n", dsc_fn, strerror(errno)); + status = 5; + } + } + else { + fprintf(stderr, "hdresize: unable to open dsc file %s: %s\n", dsc_fn, strerror(errno)); + status = 2; + } + } + else { + fprintf(stderr, "hdresize: %s has more than one free entry, compact before resizing\n", fn); + status = 4; + } + } + else { + fprintf(stderr, "hdresize: unable to read fsmap from %s: %s\n", dat_fn, strerror(errno)); + status = 3; + } + fclose(dat_fp); + } + else { + fprintf(stderr, "hdresize: unable to open data file %s: %s\n", dat_fn, strerror(errno)); + status = 2; + } + } + else { + fprintf(stderr, "hdresize: %s is not a valid size\n", argv[2]); + status = 1; + } + } + else { + fputs("usage: hdresize \n", stderr); + status = 1; + } + return status; +} + + + + + + + diff --git a/src/sdf-geo.c b/src/sdf-geo.c index 44aa4f7f..66fbfc23 100644 --- a/src/sdf-geo.c +++ b/src/sdf-geo.c @@ -168,7 +168,7 @@ struct sdf_geometry sdf_geo_tab[] = { "ADFS-S", SDF_SIDES_SINGLE, SDF_DENS_DOUBLE, 40, 16, 256, new_adfs }, { "ADFS-M", SDF_SIDES_SINGLE, SDF_DENS_DOUBLE, 80, 16, 256, new_adfs }, { "ADFS-L", SDF_SIDES_INTERLEAVED, SDF_DENS_DOUBLE, 80, 16, 256, new_adfs }, - { "ADFS-D", SDF_SIDES_SEQUENTIAL, SDF_DENS_DOUBLE, 80, 5, 1024, NULL }, + { "ADFS-D", SDF_SIDES_INTERLEAVED, SDF_DENS_DOUBLE, 80, 5, 1024, NULL }, { "Acorn DFS", SDF_SIDES_SINGLE, SDF_DENS_SINGLE, 40, 10, 256, new_dfs_single }, { "Acorn DFS", SDF_SIDES_INTERLEAVED, SDF_DENS_SINGLE, 40, 10, 256, new_dfs_interleaved }, { "Acorn DFS", SDF_SIDES_SEQUENTIAL, SDF_DENS_SINGLE, 40, 10, 256, NULL }, @@ -286,6 +286,10 @@ static int32_t dfs_size(FILE *fp, long offset) base += 8; dirsize -= 8; new_start = ((base[6] & 0x03) << 8) | base[7]; + if (new_start == 0) { + log_debug("sdf: impossible start position"); + return -1; + } if (new_start > cur_start) { log_debug("sdf: catalogue not sorted"); return -1; @@ -326,10 +330,17 @@ static const struct sdf_geometry *find_geo_dfs(const char *fn, const char *ext, } track_bytes = geo->sectors_per_track * geo->sector_size; side_bytes = track_bytes * geo->tracks; - if (fsize > side_bytes && dfs_size(fp, side_bytes) >= 3) - geo += 2; // sequential sided-version. - else if (!strcasecmp(ext, "dsd") || !strcasecmp(ext, "ddd")) - geo++; // interleaved side version. + if (fsize > track_bytes) { + if (dfs_size(fp, track_bytes) >= 3) { + geo++; // interleaved side version. + if (dfs_size(fp, side_bytes) >= 3 && strcasecmp(ext, "dsd") && strcasecmp(ext, "ddd")) + geo++; // sequential side version. + } + else if (dfs_size(fp, side_bytes) >= 3) + geo += 2; // sequential side version. + else if (!strcasecmp(ext, "dsd") || !strcasecmp(ext, "ddd")) + geo++; // interleaved side version. + } return geo; } return NULL; diff --git a/src/tube.c b/src/tube.c index 04c0f33f..5d779a0e 100644 --- a/src/tube.c +++ b/src/tube.c @@ -62,10 +62,21 @@ void tube_updateints() if ((tubeula.r1stat & 1) && (tubeula.hstat[3] & 128)) interrupt |= 8; - if (((tubeula.r1stat & 2) && (tubeula.pstat[0] & 128)) || ((tubeula.r1stat & 4) && (tubeula.pstat[3] & 128))) + if (((tubeula.r1stat & 2) && (tubeula.pstat[0] & 128)) || ((tubeula.r1stat & 4) && (tubeula.pstat[3] & 128))) { new_irq |= 1; - if (tubeula.r1stat & 8 && (tubeula.ph3pos == 0 || tubeula.hp3pos > (tubeula.r1stat & 16) ? 1 : 0)) + if (!(tube_irq & 1)) + log_debug("tube: parasite IRQ asserted"); + } + else if (tube_irq & 1) + log_debug("tube: parasite IRQ de-asserted"); + + if (tubeula.r1stat & 8 && (tubeula.ph3pos == 0 || tubeula.hp3pos > (tubeula.r1stat & 16) ? 1 : 0)) { new_irq |= 2; + if (!(tube_irq & 2)) + log_debug("tube: parasite NMI asserted"); + } + else if (tube_irq & 2) + log_debug("tube: parasite NMI de-asserted"); if (new_irq != tube_irq) { switch(tube_type) { @@ -346,7 +357,8 @@ void tube_reset(void) tubeula.ph3pos = 1; tubeula.r1stat = 0; tubeula.hstat[0] = tubeula.hstat[1] = tubeula.hstat[3] = 0x40; - tubeula.pstat[0] = tubeula.pstat[1] = tubeula.pstat[2] = tubeula.pstat[3] = 0x40; + tubeula.pstat[0] = 0x40; + tubeula.pstat[1] = tubeula.pstat[2] = tubeula.pstat[3] = 0x7f; tubeula.hstat[2] = 0xC0; tube_romin = 1; }