792 lines
29 KiB
C
792 lines
29 KiB
C
/* s3_disk.c: IBM 5444 Disk Drives
|
|
|
|
Copyright (c) 2001-2005, Charles E. Owen
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a
|
|
copy of this software and associated documentation files (the "Software"),
|
|
to deal in the Software without restriction, including without limitation
|
|
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
and/or sell copies of the Software, and to permit persons to whom the
|
|
Software is furnished to do so, subject to the following conditions:
|
|
|
|
The above copyright notice and this permission notice shall be included in
|
|
all copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
Except as contained in this notice, the name of Charles E. Owen shall not be
|
|
used in advertising or otherwise to promote the sale, use or other dealings
|
|
in this Software without prior written authorization from Charles E. Owen.
|
|
|
|
r1 Removeable disk 1
|
|
f1 Fixed disk 1
|
|
r2 Removeable disk 2
|
|
f2 Fixed disk 2
|
|
|
|
25-Apr-03 RMS Revised for extended file support
|
|
08-Oct-02 RMS Added impossible function catcher
|
|
*/
|
|
|
|
#include "s3_defs.h"
|
|
#include <ctype.h>
|
|
|
|
extern uint8 M[];
|
|
extern int32 IAR[], level;
|
|
extern FILE *trace;
|
|
extern int32 debug_reg;
|
|
char dbuf[DSK_SECTSIZE]; /* Disk buffer */
|
|
int32 dsk (int32 disk, int32 op, int32 m, int32 n, int32 data);
|
|
int32 read_sector(UNIT *uptr, char *dbuf, int32 sect);
|
|
int32 write_sector(UNIT *uptr, char *dbuf, int32 sect);
|
|
t_stat r1_svc (UNIT *uptr);
|
|
t_stat r1_boot (int32 unitno, DEVICE *dptr);
|
|
t_stat r1_attach (UNIT *uptr, char *cptr);
|
|
t_stat r1_reset (DEVICE *dptr);
|
|
t_stat f1_svc (UNIT *uptr);
|
|
t_stat f1_boot (int32 unitno, DEVICE *dptr);
|
|
t_stat f1_attach (UNIT *uptr, char *cptr);
|
|
t_stat f1_reset (DEVICE *dptr);
|
|
t_stat r2_svc (UNIT *uptr);
|
|
t_stat r2_boot (int32 unitno, DEVICE *dptr);
|
|
t_stat r2_attach (UNIT *uptr, char *cptr);
|
|
t_stat r2_reset (DEVICE *dptr);
|
|
t_stat f2_svc (UNIT *uptr);
|
|
t_stat f2_boot (int32 unitno, DEVICE *dptr);
|
|
t_stat f2_attach (UNIT *uptr, char *cptr);
|
|
t_stat f2_reset (DEVICE *dptr);
|
|
extern int32 GetMem(int32 addr);
|
|
extern int32 PutMem(int32 addr, int32 data);
|
|
|
|
char opstr[5][5] = { "SIO", "LIO", "TIO", "SNS", "APL" };
|
|
|
|
int32 DDAR[2]; /* Data address register */
|
|
int32 DCAR[2]; /* Disk Control Address Register */
|
|
int32 diskerr[2] = { 0, 0 }; /* Error status */
|
|
int32 notrdy[2] = { 0, 0 }; /* Not ready error */
|
|
int32 seekbusy[2] = { 0, 0 }; /* Drive busy flags */
|
|
int32 seekhead[2] = { 0, 0 }; /* Disk head 0,1 */
|
|
int32 found[2] = { 0, 0 }; /* Scan found bit */
|
|
int32 RIDsect[2] = { 0, 0 }; /* for Read ID */
|
|
|
|
/* Disk data structures
|
|
|
|
xy_dev CDR descriptor
|
|
xy_unit CDR unit descriptor
|
|
xy_reg CDR register list
|
|
|
|
x = F or R
|
|
y = 1 or 2
|
|
*/
|
|
|
|
UNIT r1_unit = { UDATA (&r1_svc, UNIT_FIX+UNIT_ATTABLE, 0), 100 };
|
|
|
|
REG r1_reg[] = {
|
|
{ FLDATA (NOTRDY, notrdy[0], 0) },
|
|
{ FLDATA (SEEK, seekbusy[0], 0) },
|
|
{ HRDATA (DAR, DDAR[0], 16) },
|
|
{ HRDATA (CAR, DCAR[0], 16) },
|
|
{ HRDATA (ERR, diskerr[0], 16) },
|
|
{ DRDATA (CYL, r1_unit.u3, 8) },
|
|
{ DRDATA (HEAD, seekhead[0], 8) },
|
|
{ DRDATA (POS, r1_unit.pos, T_ADDR_W), PV_LEFT },
|
|
{ DRDATA (TIME, r1_unit.wait, 24), PV_LEFT },
|
|
{ BRDATA (BUF, dbuf, 8, 8, 256) },
|
|
{ NULL }
|
|
};
|
|
|
|
DEVICE r1_dev = {
|
|
"R1", &r1_unit, r1_reg, NULL,
|
|
1, 10, 31, 1, 8, 7,
|
|
NULL, NULL, &r1_reset,
|
|
&r1_boot, &r1_attach, NULL
|
|
};
|
|
|
|
UNIT f1_unit = { UDATA (&f1_svc, UNIT_FIX+UNIT_ATTABLE, 0), 100 };
|
|
|
|
REG f1_reg[] = {
|
|
{ FLDATA (NOTRDY, notrdy[0], 0) },
|
|
{ FLDATA (SEEK, seekbusy[0], 0) },
|
|
{ HRDATA (DAR, DDAR[0], 16) },
|
|
{ HRDATA (CAR, DCAR[0], 16) },
|
|
{ HRDATA (ERR, diskerr[0], 16) },
|
|
{ DRDATA (CYL, f1_unit.u3, 8) },
|
|
{ DRDATA (HEAD, seekhead[0], 8) },
|
|
{ DRDATA (POS, f1_unit.pos, 32), PV_LEFT },
|
|
{ DRDATA (TIME, f1_unit.wait, 24), PV_LEFT },
|
|
{ BRDATA (BUF, dbuf, 8, 8, 256) },
|
|
{ NULL }
|
|
};
|
|
|
|
DEVICE f1_dev = {
|
|
"F1", &f1_unit, f1_reg, NULL,
|
|
1, 10, 31, 1, 8, 7,
|
|
NULL, NULL, &f1_reset,
|
|
&f1_boot, &f1_attach, NULL
|
|
};
|
|
|
|
UNIT r2_unit = { UDATA (&r2_svc, UNIT_FIX+UNIT_ATTABLE, 0), 100 };
|
|
|
|
REG r2_reg[] = {
|
|
{ FLDATA (NOTRDY, notrdy[1], 0) },
|
|
{ FLDATA (SEEK, seekbusy[1], 0) },
|
|
{ HRDATA (DAR, DDAR[1], 16) },
|
|
{ HRDATA (CAR, DCAR[1], 16) },
|
|
{ HRDATA (ERR, diskerr[1], 16) },
|
|
{ DRDATA (CYL, r2_unit.u3, 8) },
|
|
{ DRDATA (HEAD, seekhead[1], 8) },
|
|
{ DRDATA (POS, r2_unit.pos, 32), PV_LEFT },
|
|
{ DRDATA (TIME, r2_unit.wait, 24), PV_LEFT },
|
|
{ BRDATA (BUF, dbuf, 8, 8, 256) },
|
|
{ NULL }
|
|
};
|
|
|
|
DEVICE r2_dev = {
|
|
"R2", &r2_unit, r2_reg, NULL,
|
|
1, 10, 31, 1, 8, 7,
|
|
NULL, NULL, &r2_reset,
|
|
&r2_boot, &r2_attach, NULL
|
|
};
|
|
|
|
UNIT f2_unit = { UDATA (&f2_svc, UNIT_FIX+UNIT_ATTABLE, 0), 100 };
|
|
|
|
REG f2_reg[] = {
|
|
{ FLDATA (NOTRDY, notrdy[1], 0) },
|
|
{ FLDATA (SEEK, seekbusy[1], 0) },
|
|
{ HRDATA (DAR, DDAR[1], 16) },
|
|
{ HRDATA (CAR, DCAR[1], 16) },
|
|
{ HRDATA (ERR, diskerr[1], 16) },
|
|
{ DRDATA (CYL, f2_unit.u3, 8) },
|
|
{ DRDATA (HEAD, seekhead[1], 8) },
|
|
{ DRDATA (POS, f2_unit.pos, 32), PV_LEFT },
|
|
{ DRDATA (TIME, f2_unit.wait, 24), PV_LEFT },
|
|
{ BRDATA (BUF, dbuf, 8, 8, 256) },
|
|
{ NULL }
|
|
};
|
|
|
|
DEVICE f2_dev = {
|
|
"F2", &f2_unit, f2_reg, NULL,
|
|
1, 10, 31, 1, 8, 7,
|
|
NULL, NULL, &f2_reset,
|
|
&f2_boot, &f2_attach, NULL
|
|
};
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/* 5444: master routines */
|
|
|
|
int32 dsk1 (int32 op, int32 m, int32 n, int32 data)
|
|
{
|
|
int32 r;
|
|
|
|
r = dsk(0, op, m, n, data);
|
|
return (r);
|
|
}
|
|
|
|
int32 dsk2 (int32 op, int32 m, int32 n, int32 data)
|
|
{
|
|
int32 r;
|
|
|
|
r = dsk(1, op, m, n, data);
|
|
return (r);
|
|
}
|
|
|
|
/* 5444: operational routine */
|
|
|
|
int32 dsk (int32 disk, int32 op, int32 m, int32 n, int32 data)
|
|
{
|
|
int32 iodata, i, j, u, sect, nsects, addr, r, c, res;
|
|
int32 F, C, S, N, usave;
|
|
UNIT *uptr;
|
|
|
|
u = m;
|
|
if (disk == 1) u += 2;
|
|
F = GetMem(DCAR[disk]+0); /* Flag bits */
|
|
C = GetMem(DCAR[disk]+1); /* Cylinder */
|
|
S = GetMem(DCAR[disk]+2); /* Sector */
|
|
N = GetMem(DCAR[disk]+3); /* Number of sectors */
|
|
switch (u) {
|
|
case 0:
|
|
uptr = r1_dev.units;
|
|
break;
|
|
case 1:
|
|
uptr = f1_dev.units;
|
|
break;
|
|
case 2:
|
|
uptr = r2_dev.units;
|
|
break;
|
|
case 3:
|
|
uptr = f2_dev.units;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
if (debug_reg & 0x02)
|
|
fprintf(trace, "==> %04X %s %01X,%d,%04X DAR=%04X CAR=%04X C=%02X, S=%02X, N=%02X\n",
|
|
IAR[level],
|
|
opstr[op],
|
|
m, n, data,
|
|
DDAR[disk],
|
|
DCAR[disk],
|
|
C, S, N);
|
|
|
|
switch (op) {
|
|
|
|
/* SIO 5444 */
|
|
case 0:
|
|
if ((uptr->flags & UNIT_ATT) == 0)
|
|
return SCPE_UNATT;
|
|
diskerr[disk] = 0; /* SIO resets errors */
|
|
found[disk] = 0; /* ... and found bit */
|
|
iodata = 0;
|
|
switch (n) {
|
|
case 0x00: /* Seek */
|
|
if (S & 0x80)
|
|
seekhead[disk] = 1;
|
|
else
|
|
seekhead[disk] = 0;
|
|
if (S & 1) {
|
|
uptr -> u3 += N;
|
|
} else {
|
|
uptr -> u3 -= N;
|
|
}
|
|
if (uptr -> u3 < 0)
|
|
uptr -> u3 = 0;
|
|
if (uptr -> u3 > 203) {
|
|
uptr -> u3 = 0;
|
|
diskerr[disk] |= 0x0100;
|
|
if (debug_reg & 0x02)
|
|
fprintf(trace, "==> Seek Past End of Disk\n");
|
|
}
|
|
|
|
/*sim_activate(uptr, uptr -> wait);*/
|
|
sim_activate(uptr, 1);
|
|
|
|
/* Seek arms are the same for both disks on a drive:
|
|
update the other arm */
|
|
|
|
usave = uptr -> u3;
|
|
if (u == 0) uptr = f1_dev.units;
|
|
if (u == 1) uptr = r1_dev.units;
|
|
if (u == 2) uptr = f2_dev.units;
|
|
if (u == 3) uptr = r2_dev.units;
|
|
uptr -> u3 = usave;
|
|
|
|
seekbusy[disk] = 1;
|
|
iodata = SCPE_OK;
|
|
break;
|
|
|
|
case 0x01: /* Read */
|
|
switch (data) {
|
|
case 0: /* Read data */
|
|
sect = (S >> 2) & 0x3F;
|
|
nsects = N + 1;
|
|
addr = DDAR[disk];
|
|
|
|
for (i = 0; i < nsects; i++) {
|
|
r = read_sector(uptr, dbuf, sect);
|
|
if (r != 1 || uptr->u3 != C) {
|
|
diskerr[disk] |= 0x0800;
|
|
break;
|
|
}
|
|
for (j = 0; j < DSK_SECTSIZE; j++) {
|
|
PutMem(addr, dbuf[j]);
|
|
addr++;
|
|
}
|
|
|
|
if (sect == 55) { /* HJS MODS */
|
|
S = sect;
|
|
N = nsects - i - 2;
|
|
if (N > -1) diskerr[disk] |= 0x0020; /* end of cyl. */
|
|
DDAR[disk] = addr & 0xFFFF; /* HJS mod */
|
|
PutMem(DCAR[disk]+2, S << 2);
|
|
PutMem(DCAR[disk]+3, N);
|
|
sim_activate(uptr, 1);
|
|
iodata = SCPE_OK;
|
|
break;
|
|
}
|
|
|
|
sect++;
|
|
S = sect - 1;
|
|
N = nsects - i - 2;
|
|
if (sect == 24)
|
|
sect = 32;
|
|
}
|
|
DDAR[disk] = addr & 0xFFFF; /* HJS mod */
|
|
PutMem(DCAR[disk]+2, S << 2);
|
|
PutMem(DCAR[disk]+3, N);
|
|
/*sim_activate(uptr, uptr -> wait);*/
|
|
sim_activate(uptr, 1);
|
|
iodata = SCPE_OK;
|
|
break;
|
|
case 1: /* Read ID */
|
|
if (uptr -> u3 > 0 && uptr -> u3 < 4)
|
|
PutMem(DCAR[disk], 1);
|
|
else
|
|
PutMem(DCAR[disk], 0);
|
|
PutMem(DCAR[disk]+1, uptr -> u3);
|
|
PutMem(DCAR[disk]+2, RIDsect[disk]);
|
|
RIDsect[disk]++;
|
|
if (RIDsect[disk] > 23)
|
|
RIDsect[disk] = 32;
|
|
if (RIDsect[disk] > 55)
|
|
RIDsect[disk] = 0;
|
|
break;
|
|
case 2: /* Read Diagnostic */
|
|
iodata = STOP_INVDEV;
|
|
break;
|
|
case 3: /* Verify */
|
|
sect = (S >> 2) & 0x3F;
|
|
nsects = N + 1;
|
|
addr = DDAR[disk];
|
|
for (i = 0; i < nsects; i++) {
|
|
r = read_sector(uptr, dbuf, sect);
|
|
if (r != 1 || uptr->u3 != C) {
|
|
diskerr[disk] |= 0x0800;
|
|
break;
|
|
}
|
|
if (sect == 55) { /* HJS MODS */
|
|
S = sect;
|
|
N = nsects - i - 2;
|
|
if (N > -1) diskerr[disk] |= 0x0020; /* end of cyl. */
|
|
DDAR[disk] = addr & 0xFFFF;
|
|
PutMem(DCAR[disk]+2, S << 2);
|
|
PutMem(DCAR[disk]+3, N);
|
|
sim_activate(uptr, 1);
|
|
iodata = SCPE_OK;
|
|
break;
|
|
}
|
|
sect++;
|
|
S = sect - 1;
|
|
N = nsects - i - 2;
|
|
if (sect == 24)
|
|
sect = 32;
|
|
}
|
|
DDAR[disk] = addr & 0xFFFF;
|
|
PutMem(DCAR[disk]+2, S << 2);
|
|
PutMem(DCAR[disk]+3, N);
|
|
/*sim_activate(uptr, uptr -> wait);*/
|
|
sim_activate(uptr, 1);
|
|
break;
|
|
default:
|
|
return STOP_INVDEV;
|
|
}
|
|
break;
|
|
case 0x02: /* Write */
|
|
switch (data) {
|
|
case 0: /* Write Data */
|
|
sect = (S >> 2) & 0x3F;
|
|
nsects = N + 1;
|
|
addr = DDAR[disk];
|
|
for (i = 0; i < nsects; i++) {
|
|
for (j = 0; j < DSK_SECTSIZE; j++) {
|
|
dbuf[j] = GetMem(addr);
|
|
addr++;
|
|
}
|
|
r = write_sector(uptr, dbuf, sect);
|
|
if (r != 1 || uptr->u3 != C) {
|
|
diskerr[disk] |= 0x0400;
|
|
break;
|
|
}
|
|
if (sect == 55) { /* HJS MODS */
|
|
S = sect;
|
|
N = nsects - i - 2;
|
|
if (N > -1) diskerr[disk] |= 0x0020; /* end of cyl. */
|
|
DDAR[disk] = addr & 0xFFFF;
|
|
PutMem(DCAR[disk]+2, S << 2);
|
|
PutMem(DCAR[disk]+3, N);
|
|
sim_activate(uptr, 1);
|
|
iodata = SCPE_OK;
|
|
break;
|
|
}
|
|
sect++;
|
|
S = sect - 1;
|
|
N = nsects - i - 2;
|
|
if (sect == 24)
|
|
sect = 32;
|
|
}
|
|
DDAR[disk] = addr & 0xFFFF; /* HJS mod */
|
|
PutMem(DCAR[disk]+2, S << 2);
|
|
PutMem(DCAR[disk]+3, N);
|
|
/*sim_activate(uptr, uptr -> wait);*/
|
|
sim_activate(uptr, 1);
|
|
break;
|
|
case 1: /* Write identifier */
|
|
if (seekhead[disk] == 0)
|
|
S = 0;
|
|
else
|
|
S = 0x80;
|
|
N = 23;
|
|
|
|
sect = (S >> 2) & 0x3F;
|
|
nsects = N + 1;
|
|
addr = DDAR[disk];
|
|
for (i = 0; i < nsects; i++) {
|
|
for (j = 0; j < DSK_SECTSIZE; j++) {
|
|
dbuf[j] = GetMem(addr);
|
|
}
|
|
r = write_sector(uptr, dbuf, sect);
|
|
if (r != 1) {
|
|
diskerr[disk] |= 0x0400;
|
|
break;
|
|
}
|
|
if (sect == 55) {
|
|
S = sect;
|
|
N = nsects - i - 2;
|
|
if (N > 0) diskerr[disk] |= 0x0020;
|
|
DDAR[disk] = addr & 0xFFFF;
|
|
PutMem(DCAR[disk]+2, S << 2);
|
|
PutMem(DCAR[disk]+3, N);
|
|
sim_activate(uptr, 1);
|
|
iodata = SCPE_OK;
|
|
break;
|
|
}
|
|
sect++;
|
|
S = sect - 1;
|
|
N = nsects - i - 2;
|
|
if (sect == 24)
|
|
sect = 32;
|
|
}
|
|
DDAR[disk] = addr & 0xFFFF;
|
|
PutMem(DCAR[disk]+2, S << 2);
|
|
PutMem(DCAR[disk]+3, N);
|
|
/*sim_activate(uptr, uptr -> wait);*/
|
|
sim_activate(uptr, 1);
|
|
break;
|
|
default:
|
|
return STOP_INVDEV;
|
|
}
|
|
break;
|
|
case 0x03: /* Scan */
|
|
sect = (S >> 2) & 0x3F;
|
|
nsects = N + 1;
|
|
addr = DDAR[disk];
|
|
for (i = 0; i < nsects; i++) {
|
|
r = read_sector(uptr, dbuf, sect);
|
|
if (r != 1 || uptr->u3 != C) {
|
|
diskerr[disk] |= 0x0800;
|
|
break;
|
|
}
|
|
res = 0;
|
|
for (j = 0; j < DSK_SECTSIZE; j++) {
|
|
c = GetMem(addr);
|
|
if (j != 0xff) {
|
|
if (dbuf[i] < c)
|
|
res = 1;
|
|
if (dbuf[i] > c)
|
|
res = 3;
|
|
}
|
|
addr++;
|
|
}
|
|
if (res == 0)
|
|
found[disk] = 1;
|
|
if (res == data)
|
|
break;
|
|
if (sect == 55) { /* HJS MODS */
|
|
S = sect;
|
|
N = nsects - i - 2;
|
|
if (N > -1) diskerr[disk] |= 0x0020; /* end of cyl. */
|
|
DDAR[disk] = addr & 0xFFFF;
|
|
PutMem(DCAR[disk]+2, S << 2);
|
|
PutMem(DCAR[disk]+3, N);
|
|
sim_activate(uptr, 1);
|
|
iodata = SCPE_OK;
|
|
break;
|
|
}
|
|
sect++;
|
|
S = sect - 1;
|
|
N = nsects - i - 2;
|
|
if (sect == 24)
|
|
sect = 32;
|
|
}
|
|
PutMem(DCAR[disk]+2, S << 2);
|
|
PutMem(DCAR[disk]+3, N);
|
|
/*sim_activate(uptr, uptr -> wait);*/
|
|
sim_activate(uptr, 1);
|
|
break;
|
|
default:
|
|
return STOP_INVDEV;
|
|
}
|
|
return iodata;
|
|
|
|
/* LIO 5444 */
|
|
case 1:
|
|
if ((uptr->flags & UNIT_ATT) == 0)
|
|
return SCPE_UNATT;
|
|
switch (n) {
|
|
case 0x04: /* Data Addr */
|
|
DDAR[disk] = data;
|
|
break;
|
|
case 0x06: /* Control Addr */
|
|
DCAR[disk] = data;
|
|
break;
|
|
default:
|
|
return STOP_INVDEV;
|
|
}
|
|
return SCPE_OK;
|
|
/* TIO 5444 */
|
|
case 2:
|
|
if ((uptr->flags & UNIT_ATT) == 0)
|
|
return SCPE_UNATT << 16;
|
|
iodata = 0;
|
|
switch (n) {
|
|
case 0x00: /* Error */
|
|
if (diskerr[disk] || notrdy[disk])
|
|
iodata = 1;
|
|
if ((uptr -> flags & UNIT_ATT) == 0)
|
|
iodata = 1;
|
|
break;
|
|
case 0x02: /* Busy */
|
|
if (sim_is_active (uptr))
|
|
iodata = 1;
|
|
break;
|
|
case 0x04:
|
|
if (found[disk])
|
|
iodata = 1;
|
|
break;
|
|
default:
|
|
return (STOP_INVDEV << 16);
|
|
}
|
|
return ((SCPE_OK << 16) | iodata);
|
|
|
|
/* SNS 5444 */
|
|
case 3:
|
|
if ((uptr->flags & UNIT_ATT) == 0)
|
|
return SCPE_UNATT << 16;
|
|
iodata = 0;
|
|
switch (n) {
|
|
case 0x01:
|
|
break;
|
|
case 0x02:
|
|
iodata = diskerr[disk];
|
|
if (notrdy[disk])
|
|
iodata |= 0x4000;
|
|
if ((uptr -> flags & UNIT_ATT) == 0)
|
|
iodata |= 0x4000;
|
|
if (seekbusy[disk])
|
|
iodata |= 0x0010;
|
|
if (uptr -> u3 == 0)
|
|
iodata |= 0x0040;
|
|
break;
|
|
case 0x03:
|
|
iodata = 0;
|
|
break;
|
|
case 0x04:
|
|
iodata = DDAR[disk];
|
|
break;
|
|
case 0x06:
|
|
iodata = DCAR[disk];
|
|
break;
|
|
default:
|
|
return (STOP_INVDEV << 16);
|
|
}
|
|
iodata |= ((SCPE_OK << 16) & 0xffff0000);
|
|
return (iodata);
|
|
|
|
/* APL 5444 */
|
|
case 4:
|
|
if ((uptr->flags & UNIT_ATT) == 0)
|
|
return SCPE_UNATT << 16;
|
|
iodata = 0;
|
|
switch (n) {
|
|
case 0x00: /* Error */
|
|
if (diskerr[disk] || notrdy[disk])
|
|
iodata = 1;
|
|
if ((uptr -> flags & UNIT_ATT) == 0)
|
|
iodata = 1;
|
|
break;
|
|
case 0x02: /* Busy */
|
|
if (sim_is_active (uptr))
|
|
iodata = 1;
|
|
break;
|
|
default:
|
|
return (STOP_INVDEV << 16);
|
|
}
|
|
return ((SCPE_OK << 16) | iodata);
|
|
default:
|
|
break;
|
|
}
|
|
printf (">>DSK%d non-existent function %d\n", disk, op);
|
|
return SCPE_OK;
|
|
}
|
|
|
|
/* Disk unit service. If a stacker select is active, copy to the
|
|
selected stacker. Otherwise, copy to the normal stacker. If the
|
|
unit is unattached, simply exit.
|
|
*/
|
|
|
|
t_stat r1_svc (UNIT *uptr)
|
|
{
|
|
seekbusy[0] = 0;
|
|
return SCPE_OK;
|
|
}
|
|
t_stat f1_svc (UNIT *uptr)
|
|
{
|
|
seekbusy[0] = 0;
|
|
return SCPE_OK;
|
|
}
|
|
t_stat r2_svc (UNIT *uptr)
|
|
{
|
|
seekbusy[1] = 0;
|
|
return SCPE_OK;
|
|
}
|
|
t_stat f2_svc (UNIT *uptr)
|
|
{
|
|
seekbusy[1] = 0;
|
|
return SCPE_OK;
|
|
}
|
|
|
|
|
|
/* Disk reset */
|
|
|
|
t_stat r1_reset (DEVICE *dptr)
|
|
{
|
|
diskerr[0] = notrdy[0] = seekbusy[0] = 0; /* clear indicators */
|
|
found[0] = 0;
|
|
sim_cancel (&r1_unit); /* clear event */
|
|
r1_unit.u3 = 0; /* cylinder 0 */
|
|
return SCPE_OK;
|
|
}
|
|
t_stat f1_reset (DEVICE *dptr)
|
|
{
|
|
diskerr[0] = notrdy[0] = seekbusy[0] = 0; /* clear indicators */
|
|
found[0] = 0;
|
|
sim_cancel (&f1_unit); /* clear event */
|
|
f1_unit.u3 = 0; /* cylinder 0 */
|
|
return SCPE_OK;
|
|
}
|
|
t_stat r2_reset (DEVICE *dptr)
|
|
{
|
|
diskerr[1] = notrdy[1] = seekbusy[1] = 0; /* clear indicators */
|
|
found[1] = 0;
|
|
sim_cancel (&r2_unit); /* clear event */
|
|
r2_unit.u3 = 0; /* cylinder 0 */
|
|
return SCPE_OK;
|
|
}
|
|
t_stat f2_reset (DEVICE *dptr)
|
|
{
|
|
diskerr[1] = notrdy[1] = seekbusy[1] = 0; /* clear indicators */
|
|
found[1] = 0;
|
|
sim_cancel (&f2_unit); /* clear event */
|
|
f2_unit.u3 = 0; /* cylinder 0 */
|
|
return SCPE_OK;
|
|
}
|
|
|
|
/* Disk unit attach */
|
|
|
|
t_stat r1_attach (UNIT *uptr, char *cptr)
|
|
{
|
|
diskerr[0] = notrdy[0] = seekbusy[0] = 0; /* clear status */
|
|
found[0] = 0;
|
|
uptr -> u3 = 0; /* cylinder 0 */
|
|
return attach_unit (uptr, cptr);
|
|
}
|
|
t_stat f1_attach (UNIT *uptr, char *cptr)
|
|
{
|
|
diskerr[0] = notrdy[0] = seekbusy[0] = 0; /* clear status */
|
|
found[0] = 0;
|
|
uptr -> u3 = 0; /* cylinder 0 */
|
|
return attach_unit (uptr, cptr);
|
|
}
|
|
t_stat r2_attach (UNIT *uptr, char *cptr)
|
|
{
|
|
diskerr[1] = notrdy[1] = seekbusy[1] = 0; /* clear status */
|
|
found[1] = 0;
|
|
uptr -> u3 = 0; /* cylinder 0 */
|
|
return attach_unit (uptr, cptr);
|
|
}
|
|
t_stat f2_attach (UNIT *uptr, char *cptr)
|
|
{
|
|
diskerr[1] = notrdy[1] = seekbusy[1] = 0; /* clear status */
|
|
found[1] = 0;
|
|
uptr -> u3 = 0; /* cylinder 0 */
|
|
return attach_unit (uptr, cptr);
|
|
}
|
|
|
|
/* Bootstrap routine */
|
|
|
|
t_stat r1_boot (int32 unitno, DEVICE *dptr)
|
|
{
|
|
int i;
|
|
r1_unit.u3 = 0;
|
|
read_sector(r1_dev.units, dbuf, 0);
|
|
for (i = 0; i < 256; i++) {
|
|
M[i] = dbuf[i];
|
|
}
|
|
return SCPE_OK;
|
|
}
|
|
t_stat f1_boot (int32 unitno, DEVICE *dptr)
|
|
{
|
|
int i;
|
|
f1_unit.u3 = 0;
|
|
read_sector(f1_dev.units, dbuf, 0);
|
|
for (i = 0; i < 256; i++) {
|
|
M[i] = dbuf[i];
|
|
}
|
|
return SCPE_OK;
|
|
}
|
|
t_stat r2_boot (int32 unitno, DEVICE *dptr)
|
|
{
|
|
int i;
|
|
r2_unit.u3 = 0;
|
|
read_sector(r2_dev.units, dbuf, 0);
|
|
for (i = 0; i < 256; i++) {
|
|
M[i] = dbuf[i];
|
|
}
|
|
return SCPE_OK;
|
|
}
|
|
t_stat f2_boot (int32 unitno, DEVICE *dptr)
|
|
{
|
|
int i;
|
|
f2_unit.u3 = 0;
|
|
read_sector(f2_dev.units, dbuf, 0);
|
|
for (i = 0; i < 256; i++) {
|
|
M[i] = dbuf[i];
|
|
}
|
|
return SCPE_OK;
|
|
}
|
|
|
|
|
|
/* Raw Disk Data In/Out */
|
|
|
|
int32 read_sector(UNIT *uptr, char *dbuf, int32 sect)
|
|
{
|
|
static int32 rtn, realsect;
|
|
static long pos;
|
|
|
|
/* calculate real sector no */
|
|
if (sect > 23)
|
|
realsect = sect - 8;
|
|
else
|
|
realsect = sect;
|
|
/* physically read the sector */
|
|
pos = DSK_CYLSIZE * uptr -> u3;
|
|
pos += DSK_SECTSIZE * realsect;
|
|
rtn = fseek(uptr -> fileref, pos, 0);
|
|
rtn = fread(dbuf, DSK_SECTSIZE, 1, uptr -> fileref);
|
|
return (rtn);
|
|
}
|
|
|
|
int32 write_sector(UNIT *uptr, char *dbuf, int32 sect)
|
|
{
|
|
static int32 rtn, realsect;
|
|
static long pos;
|
|
|
|
/* calculate real sector no */
|
|
if (sect > 23)
|
|
realsect = sect - 8;
|
|
else
|
|
realsect = sect;
|
|
if (uptr -> u3 == 0 && realsect == 32)
|
|
rtn = 0;
|
|
/* physically write the sector */
|
|
pos = DSK_CYLSIZE * uptr -> u3;
|
|
pos += DSK_SECTSIZE * realsect;
|
|
rtn = fseek(uptr -> fileref, pos, 0);
|
|
rtn = fwrite(dbuf, DSK_SECTSIZE, 1, uptr -> fileref);
|
|
return (rtn);
|
|
}
|