diff --git a/AltairZ80/altairz80_defs.h b/AltairZ80/altairz80_defs.h index fc2f1cbd..1c7d0583 100644 --- a/AltairZ80/altairz80_defs.h +++ b/AltairZ80/altairz80_defs.h @@ -52,6 +52,8 @@ #define LDA_INSTRUCTION 0x3e /* op-code for LD A,<8-bit value> instruction */ #define UNIT_NO_OFFSET_1 0x37 /* LD A, */ #define UNIT_NO_OFFSET_2 0xb4 /* LD a,80h | */ +#define LDB_INSTRUCTION 0x06 /* op-code for LD B,<8-bit value> instruction */ +#define START_SECTOR_OFFSET 0x57 /* LD B, */ #define CPU_INDEX_8080 4 /* index of default PC register */ diff --git a/AltairZ80/altairz80_dsk.c b/AltairZ80/altairz80_dsk.c index 8290edbf..10c92b44 100644 --- a/AltairZ80/altairz80_dsk.c +++ b/AltairZ80/altairz80_dsk.c @@ -33,15 +33,14 @@ The controller is interfaced to the CPU by use of 3 I/O addresses, standardly, these are device numbers 10, 11, and 12 (octal). - Address Mode Function - ------- ---- -------- - - 10 Out Selects and enables Controller and Drive - 10 In Indicates status of Drive and Controller - 11 Out Controls Disk Function - 11 In Indicates current sector position of disk - 12 Out Write data - 12 In Read data + Address Mode Function + ------- ---- -------- + 10 Out Selects and enables Controller and Drive + 10 In Indicates status of Drive and Controller + 11 Out Controls Disk Function + 11 In Indicates current sector position of disk + 12 Out Write data + 12 In Read data Drive Select Out (Device 10 OUT): @@ -141,21 +140,24 @@ #define TRACK_STUCK_MSG (1 << 5) #define VERBOSE_MSG (1 << 6) -#define UNIT_V_DSK_WLK (UNIT_V_UF + 0) /* write locked */ +#define UNIT_V_DSK_WLK (UNIT_V_UF + 0) /* write locked */ #define UNIT_DSK_WLK (1 << UNIT_V_DSK_WLK) -#define DSK_SECTSIZE 137 /* size of sector */ -#define DSK_SECT 32 /* sectors per track */ +#define DSK_SECTSIZE 137 /* size of sector */ +#define DSK_SECT 32 /* sectors per track */ #define MAX_TRACKS 2048 /* number of tracks, - original Altair has 77 tracks only */ + original Altair has 77 tracks only */ #define DSK_TRACSIZE (DSK_SECTSIZE * DSK_SECT) #define MAX_DSK_SIZE (DSK_TRACSIZE * MAX_TRACKS) #define NUM_OF_DSK_MASK (NUM_OF_DSK - 1) -#define BOOTROM_SIZE_DSK 256 /* size of boot rom */ +#define BOOTROM_SIZE_DSK 256 /* size of boot rom */ -#define MINI_DISK_SECT 16 /* mini disk sectors per track */ -#define MINI_DISK_TRACKS 35 /* number of tracks on mini disk */ +#define MINI_DISK_SECT 16 /* mini disk sectors per track */ +#define MINI_DISK_TRACKS 35 /* number of tracks on mini disk */ #define MINI_DISK_SIZE (MINI_DISK_TRACKS * MINI_DISK_SECT * DSK_SECTSIZE) -#define MINI_DISK_DELTA 4096 /* threshold for detecting mini disks */ +#define MINI_DISK_DELTA 4096 /* threshold for detecting mini disks */ + +#define ALTAIR_DISK_SIZE 337664 /* size of regular Altair disks */ +#define ALTAIR_DISK_DELTA 256 /* threshold for detecting regular Altair disks */ int32 dsk10(const int32 port, const int32 io, const int32 data); int32 dsk11(const int32 port, const int32 io, const int32 data); @@ -187,6 +189,7 @@ static int32 sectors_per_track [NUM_OF_DSK] = { DSK_SECT, DSK_SECT, DSK_SECT, DS DSK_SECT, DSK_SECT, DSK_SECT, DSK_SECT, DSK_SECT, DSK_SECT, DSK_SECT, DSK_SECT, DSK_SECT, DSK_SECT, DSK_SECT, DSK_SECT }; +static int32 current_imageSize [NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; static int32 tracks [NUM_OF_DSK] = { MAX_TRACKS, MAX_TRACKS, MAX_TRACKS, MAX_TRACKS, MAX_TRACKS, MAX_TRACKS, MAX_TRACKS, MAX_TRACKS, MAX_TRACKS, MAX_TRACKS, MAX_TRACKS, MAX_TRACKS, @@ -310,6 +313,8 @@ static REG dsk_reg[] = { "Number of tracks register array"), REG_CIRC }, { BRDATAD (SECTPERTRACK, sectors_per_track, 10, 32, NUM_OF_DSK, "Number of sectors per track register array"), REG_CIRC }, + { BRDATAD (IMAGESIZE, current_imageSize, 10, 32, NUM_OF_DSK, + "Size of disk image array"), REG_CIRC + REG_RO }, { DRDATAD (IN9COUNT, in9_count, 4, "Count of IN(9) register"), REG_RO }, { DRDATAD (IN9MESSAGE, in9_message, 4, @@ -378,12 +383,12 @@ static const char* selectInOut(const int32 io) { static t_stat dsk_reset(DEVICE *dptr) { int32 i; for (i = 0; i < NUM_OF_DSK; i++) { - warnLock[i] = 0; - warnAttached[i] = 0; - current_track[i] = 0; - current_sector[i] = 0; - current_byte[i] = 0; - current_flag[i] = 0; + warnLock[i] = 0; + warnAttached[i] = 0; + current_track[i] = 0; + current_sector[i] = 0; + current_byte[i] = 0; + current_flag[i] = 0; } warnDSK10 = 0; warnDSK11 = 0; @@ -413,6 +418,7 @@ static t_stat dsk_attach(UNIT *uptr, CONST char *cptr) { tracks to 16, otherwise, 32 sectors per track. */ imageSize = sim_fsize(uptr -> fileref); + current_imageSize[thisUnitIndex] = imageSize; sectors_per_track[thisUnitIndex] = (((MINI_DISK_SIZE - MINI_DISK_DELTA < imageSize) && (imageSize < MINI_DISK_SIZE + MINI_DISK_DELTA)) ? MINI_DISK_SECT : DSK_SECT); @@ -426,7 +432,13 @@ void install_ALTAIRbootROM(void) { } /* The boot routine modifies the boot ROM in such a way that subsequently - the specified disk is used for boot purposes. + the specified disk is used for boot purposes. Furthermore, it determines based on the + size of the attached disk image which boot ROM should be used. The logic is: + - If the size is close to MINI_DISK_SIZE, the ROM for mini disk support is used + - If the size is close to ALTAIR_DISK_SIZE, the standard ROM is modified to start + loading at track 0, sector 0 + - Otherwise the standard ROM is is modified to start loading at track 0, sector 8 + See DSKBOOT.MAC on the cpm2.dsk for the source code of the boot ROM. */ static t_stat dsk_boot(int32 unitno, DEVICE *dptr) { if (cpu_unit.flags & (UNIT_CPU_ALTAIRROM | UNIT_CPU_BANKED)) { @@ -434,18 +446,29 @@ static t_stat dsk_boot(int32 unitno, DEVICE *dptr) { const t_bool result = (install_bootrom(alt_bootrom_dsk, BOOTROM_SIZE_DSK, ALTAIR_ROM_LOW, TRUE) == SCPE_OK); ASSURE(result); - } else { - /* check whether we are really modifying an LD A,<> instruction */ + } else { /* patch standard ROM with correct unit number and first track */ + + /* check whether we are really modifying an LD B,<> instruction */ + if (bootrom_dsk[START_SECTOR_OFFSET - 1] == LDB_INSTRUCTION) + bootrom_dsk[START_SECTOR_OFFSET] = + (ALTAIR_DISK_SIZE - ALTAIR_DISK_DELTA < current_imageSize[unitno]) && + (current_imageSize[unitno] < ALTAIR_DISK_SIZE + ALTAIR_DISK_DELTA) ? 0 : 8; + else { /* Attempt to modify non LD B,<> instructions is refused. */ + sim_printf("Incorrect boot ROM first sector offset detected.\n"); + return SCPE_IERR; + } + + /* check whether we are really modifying an LD A,<> instruction */ if ((bootrom_dsk[UNIT_NO_OFFSET_1 - 1] == LDA_INSTRUCTION) && (bootrom_dsk[UNIT_NO_OFFSET_2 - 1] == LDA_INSTRUCTION)) { - bootrom_dsk[UNIT_NO_OFFSET_1] = unitno & 0xff; /* LD A, */ - bootrom_dsk[UNIT_NO_OFFSET_2] = 0x80 | (unitno & 0xff); /* LD a,80h | */ - } else { /* Attempt to modify non LD A,<> instructions is refused. */ - sim_printf("Incorrect boot ROM offsets detected.\n"); - return SCPE_IERR; + bootrom_dsk[UNIT_NO_OFFSET_1] = unitno & 0xff; /* LD A, */ + bootrom_dsk[UNIT_NO_OFFSET_2] = 0x80 | (unitno & 0xff); /* LD a,80h | */ + } else { /* Attempt to modify non LD A,<> instructions is refused. */ + sim_printf("Incorrect boot ROM unit number offset detected.\n"); + return SCPE_IERR; + } + install_ALTAIRbootROM(); /* install modified ROM */ } - install_ALTAIRbootROM(); /* install modified ROM */ - } } *((int32 *) sim_PC->loc) = ALTAIR_ROM_LOW; return SCPE_OK; @@ -546,7 +569,7 @@ int32 dsk10(const int32 port, const int32 io, const int32 data) { } current_disk = NUM_OF_DSK; } else { - current_sector[current_disk] = 0xff; /* reset internal counters */ + current_sector[current_disk] = 0xff; /* reset internal counters */ current_byte[current_disk] = 0xff; if (data & 0x80) /* disable drive? */ current_flag[current_disk] = 0; /* yes, clear all flags */ @@ -572,7 +595,7 @@ int32 dsk11(const int32 port, const int32 io, const int32 data) { " Attempt of %s 0x09 on unattached disk - ignored.\n", current_disk, PCX, selectInOut(io)); } - return 0xff; /* no drive selected - can do nothing */ + return 0xff; /* no drive selected - can do nothing */ } /* now current_disk < NUM_OF_DSK */