Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions AltairZ80/altairz80_defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,<unitno> */
#define UNIT_NO_OFFSET_2 0xb4 /* LD a,80h | <unitno> */
#define LDB_INSTRUCTION 0x06 /* op-code for LD B,<8-bit value> instruction */
#define START_SECTOR_OFFSET 0x57 /* LD B,<start_sector_offset> */

#define CPU_INDEX_8080 4 /* index of default PC register */

Expand Down
95 changes: 59 additions & 36 deletions AltairZ80/altairz80_dsk.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* altairz80_dsk.c: MITS Altair 88-DISK Simulator

Copyright (c) 2002-2023, Peter Schorn
Copyright (c) 2002-2025, Peter Schorn

Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
Expand Down Expand Up @@ -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):

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand All @@ -426,26 +432,43 @@ 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)) {
if (sectors_per_track[unitno] == MINI_DISK_SECT) {
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,<unitno> */
bootrom_dsk[UNIT_NO_OFFSET_2] = 0x80 | (unitno & 0xff); /* LD a,80h | <unitno> */
} 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,<unitno> */
bootrom_dsk[UNIT_NO_OFFSET_2] = 0x80 | (unitno & 0xff); /* LD a,80h | <unitno> */
} 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;
Expand Down Expand Up @@ -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 */
Expand All @@ -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 */
Expand Down
Loading