11/* altairz80_dsk.c: MITS Altair 88-DISK Simulator
22
3- Copyright (c) 2002-2023 , Peter Schorn
3+ Copyright (c) 2002-2026 , Peter Schorn
44
55 Permission is hereby granted, free of charge, to any person obtaining a
66 copy of this software and associated documentation files (the "Software"),
3333 The controller is interfaced to the CPU by use of 3 I/O addresses,
3434 standardly, these are device numbers 10, 11, and 12 (octal).
3535
36- Address Mode Function
37- ------- ---- --------
38-
39- 10 Out Selects and enables Controller and Drive
40- 10 In Indicates status of Drive and Controller
41- 11 Out Controls Disk Function
42- 11 In Indicates current sector position of disk
43- 12 Out Write data
44- 12 In Read data
36+ Address Mode Function
37+ ------- ---- --------
38+ 10 Out Selects and enables Controller and Drive
39+ 10 In Indicates status of Drive and Controller
40+ 11 Out Controls Disk Function
41+ 11 In Indicates current sector position of disk
42+ 12 Out Write data
43+ 12 In Read data
4544
4645 Drive Select Out (Device 10 OUT):
4746
141140#define TRACK_STUCK_MSG (1 << 5)
142141#define VERBOSE_MSG (1 << 6)
143142
144- #define UNIT_V_DSK_WLK (UNIT_V_UF + 0) /* write locked */
143+ #define UNIT_V_DSK_WLK (UNIT_V_UF + 0) /* write locked */
145144#define UNIT_DSK_WLK (1 << UNIT_V_DSK_WLK)
146- #define DSK_SECTSIZE 137 /* size of sector */
147- #define DSK_SECT 32 /* sectors per track */
145+ #define DSK_SECTSIZE 137 /* size of sector */
146+ #define DSK_SECT 32 /* sectors per track */
148147#define MAX_TRACKS 2048 /* number of tracks,
149- original Altair has 77 tracks only */
148+ original Altair has 77 tracks only */
150149#define DSK_TRACSIZE (DSK_SECTSIZE * DSK_SECT)
151150#define MAX_DSK_SIZE (DSK_TRACSIZE * MAX_TRACKS)
152151#define NUM_OF_DSK_MASK (NUM_OF_DSK - 1)
153- #define BOOTROM_SIZE_DSK 256 /* size of boot rom */
152+ #define BOOTROM_SIZE_DSK 256 /* size of boot rom */
154153
155- #define MINI_DISK_SECT 16 /* mini disk sectors per track */
156- #define MINI_DISK_TRACKS 35 /* number of tracks on mini disk */
154+ #define MINI_DISK_SECT 16 /* mini disk sectors per track */
155+ #define MINI_DISK_TRACKS 35 /* number of tracks on mini disk */
157156#define MINI_DISK_SIZE (MINI_DISK_TRACKS * MINI_DISK_SECT * DSK_SECTSIZE)
158- #define MINI_DISK_DELTA 4096 /* threshold for detecting mini disks */
157+ #define MINI_DISK_DELTA 4096 /* threshold for detecting mini disks */
158+
159+ #define ALTAIR_DISK_SIZE 337664 /* size of regular Altair disks */
160+ #define ALTAIR_DISK_DELTA 256 /* threshold for detecting regular Altair disks */
159161
160162int32 dsk10 (const int32 port , const int32 io , const int32 data );
161163int32 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
187189 DSK_SECT , DSK_SECT , DSK_SECT , DSK_SECT ,
188190 DSK_SECT , DSK_SECT , DSK_SECT , DSK_SECT ,
189191 DSK_SECT , DSK_SECT , DSK_SECT , DSK_SECT };
192+ static int32 current_imageSize [NUM_OF_DSK ] = {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 };
190193static int32 tracks [NUM_OF_DSK ] = { MAX_TRACKS , MAX_TRACKS , MAX_TRACKS , MAX_TRACKS ,
191194 MAX_TRACKS , MAX_TRACKS , MAX_TRACKS , MAX_TRACKS ,
192195 MAX_TRACKS , MAX_TRACKS , MAX_TRACKS , MAX_TRACKS ,
@@ -310,6 +313,8 @@ static REG dsk_reg[] = {
310313 "Number of tracks register array" ), REG_CIRC },
311314 { BRDATAD (SECTPERTRACK , sectors_per_track , 10 , 32 , NUM_OF_DSK ,
312315 "Number of sectors per track register array" ), REG_CIRC },
316+ { BRDATAD (IMAGESIZE , current_imageSize , 10 , 32 , NUM_OF_DSK ,
317+ "Size of disk image array" ), REG_CIRC + REG_RO },
313318 { DRDATAD (IN9COUNT , in9_count , 4 ,
314319 "Count of IN(9) register" ), REG_RO },
315320 { DRDATAD (IN9MESSAGE , in9_message , 4 ,
@@ -378,12 +383,12 @@ static const char* selectInOut(const int32 io) {
378383static t_stat dsk_reset (DEVICE * dptr ) {
379384 int32 i ;
380385 for (i = 0 ; i < NUM_OF_DSK ; i ++ ) {
381- warnLock [i ] = 0 ;
382- warnAttached [i ] = 0 ;
383- current_track [i ] = 0 ;
384- current_sector [i ] = 0 ;
385- current_byte [i ] = 0 ;
386- current_flag [i ] = 0 ;
386+ warnLock [i ] = 0 ;
387+ warnAttached [i ] = 0 ;
388+ current_track [i ] = 0 ;
389+ current_sector [i ] = 0 ;
390+ current_byte [i ] = 0 ;
391+ current_flag [i ] = 0 ;
387392 }
388393 warnDSK10 = 0 ;
389394 warnDSK11 = 0 ;
@@ -413,6 +418,7 @@ static t_stat dsk_attach(UNIT *uptr, CONST char *cptr) {
413418 tracks to 16, otherwise, 32 sectors per track. */
414419
415420 imageSize = sim_fsize (uptr -> fileref );
421+ current_imageSize [thisUnitIndex ] = imageSize ;
416422 sectors_per_track [thisUnitIndex ] = (((MINI_DISK_SIZE - MINI_DISK_DELTA < imageSize ) &&
417423 (imageSize < MINI_DISK_SIZE + MINI_DISK_DELTA )) ?
418424 MINI_DISK_SECT : DSK_SECT );
@@ -426,26 +432,43 @@ void install_ALTAIRbootROM(void) {
426432}
427433
428434/* The boot routine modifies the boot ROM in such a way that subsequently
429- the specified disk is used for boot purposes.
435+ the specified disk is used for boot purposes. Furthermore, it determines based on the
436+ size of the attached disk image which boot ROM should be used. The logic is:
437+ - If the size is close to MINI_DISK_SIZE, the ROM for mini disk support is used
438+ - If the size is close to ALTAIR_DISK_SIZE, the standard ROM is modified to start
439+ loading at track 0, sector 0
440+ - Otherwise the standard ROM is is modified to start loading at track 0, sector 8
441+ See DSKBOOT.MAC on the cpm2.dsk for the source code of the boot ROM.
430442*/
431443static t_stat dsk_boot (int32 unitno , DEVICE * dptr ) {
432444 if (cpu_unit .flags & (UNIT_CPU_ALTAIRROM | UNIT_CPU_BANKED )) {
433445 if (sectors_per_track [unitno ] == MINI_DISK_SECT ) {
434446 const t_bool result = (install_bootrom (alt_bootrom_dsk , BOOTROM_SIZE_DSK ,
435447 ALTAIR_ROM_LOW , TRUE) == SCPE_OK );
436448 ASSURE (result );
437- } else {
438- /* check whether we are really modifying an LD A,<> instruction */
449+ } else { /* patch standard ROM with correct unit number and first track */
450+
451+ /* check whether we are really modifying an LD B,<> instruction */
452+ if (bootrom_dsk [START_SECTOR_OFFSET - 1 ] == LDB_INSTRUCTION )
453+ bootrom_dsk [START_SECTOR_OFFSET ] =
454+ (ALTAIR_DISK_SIZE - ALTAIR_DISK_DELTA < current_imageSize [unitno ]) &&
455+ (current_imageSize [unitno ] < ALTAIR_DISK_SIZE + ALTAIR_DISK_DELTA ) ? 0 : 8 ;
456+ else { /* Attempt to modify non LD B,<> instructions is refused. */
457+ sim_printf ("Incorrect boot ROM first sector offset detected.\n" );
458+ return SCPE_IERR ;
459+ }
460+
461+ /* check whether we are really modifying an LD A,<> instruction */
439462 if ((bootrom_dsk [UNIT_NO_OFFSET_1 - 1 ] == LDA_INSTRUCTION ) &&
440463 (bootrom_dsk [UNIT_NO_OFFSET_2 - 1 ] == LDA_INSTRUCTION )) {
441- bootrom_dsk [UNIT_NO_OFFSET_1 ] = unitno & 0xff ; /* LD A,<unitno> */
442- bootrom_dsk [UNIT_NO_OFFSET_2 ] = 0x80 | (unitno & 0xff ); /* LD a,80h | <unitno> */
443- } else { /* Attempt to modify non LD A,<> instructions is refused. */
444- sim_printf ("Incorrect boot ROM offsets detected.\n" );
445- return SCPE_IERR ;
464+ bootrom_dsk [UNIT_NO_OFFSET_1 ] = unitno & 0xff ; /* LD A,<unitno> */
465+ bootrom_dsk [UNIT_NO_OFFSET_2 ] = 0x80 | (unitno & 0xff ); /* LD a,80h | <unitno> */
466+ } else { /* Attempt to modify non LD A,<> instructions is refused. */
467+ sim_printf ("Incorrect boot ROM unit number offset detected.\n" );
468+ return SCPE_IERR ;
469+ }
470+ install_ALTAIRbootROM (); /* install modified ROM */
446471 }
447- install_ALTAIRbootROM (); /* install modified ROM */
448- }
449472 }
450473 * ((int32 * ) sim_PC -> loc ) = ALTAIR_ROM_LOW ;
451474 return SCPE_OK ;
@@ -546,7 +569,7 @@ int32 dsk10(const int32 port, const int32 io, const int32 data) {
546569 }
547570 current_disk = NUM_OF_DSK ;
548571 } else {
549- current_sector [current_disk ] = 0xff ; /* reset internal counters */
572+ current_sector [current_disk ] = 0xff ; /* reset internal counters */
550573 current_byte [current_disk ] = 0xff ;
551574 if (data & 0x80 ) /* disable drive? */
552575 current_flag [current_disk ] = 0 ; /* yes, clear all flags */
@@ -572,7 +595,7 @@ int32 dsk11(const int32 port, const int32 io, const int32 data) {
572595 " Attempt of %s 0x09 on unattached disk - ignored.\n" ,
573596 current_disk , PCX , selectInOut (io ));
574597 }
575- return 0xff ; /* no drive selected - can do nothing */
598+ return 0xff ; /* no drive selected - can do nothing */
576599 }
577600
578601 /* now current_disk < NUM_OF_DSK */
0 commit comments