CDC1700: Release 2

- Fix protect fault for 2-word instructions so that background tasks do not
   crash.
- Lay the ground work for supporting the enhanced instruction set.
- Fix disk layout bug (disks are no longer compatible with previous version).
- Add debugging support for displaying MSOS 5 system requests.
- Fix bugs found by Coverity.
This commit is contained in:
Mark Pizzolato 2017-03-14 13:36:57 -07:00
parent ca19ac921c
commit df1baf2528
14 changed files with 2083 additions and 723 deletions

File diff suppressed because it is too large Load diff

View file

@ -45,8 +45,8 @@ mostly from the early period of its release:
MT 1732-A or 1732-3 Magtape controller, 3 9-track drives
(MT0 - MT2) and 1 7-track drive (MT3). The type of
the controller may be chaged using the command
"set mt type={1732-a|1732-3}". The 1732-A controller
the controller may be changed using the command
"set mt type={1732-A|1732-3}". The 1732-A controller
supports 200, 556 and 800 BPI on the 9 track drives
and allows DMA access via a 1706 Buffered Data
Channel (device DCA). The 1733-3 controller supports

View file

@ -1,6 +1,6 @@
/*
Copyright (c) 2015-2016, John Forecast
Copyright (c) 2015-2017, John Forecast
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -96,7 +96,7 @@ t_stat cd_help(FILE *, DEVICE *, UNIT *, int32, const char *);
#define CD856_4_SIZE (CD_SURF * CD_856_4CY * CD_NUMSC * CD_NUMBY)
#define CDLBA(i) \
((i->surface * i->maxcylinder * CD_NUMSC) + (i->cylinder * CD_NUMSC) + i->sector)
((((i->cylinder * CD_SURF) + i->surface) * CD_NUMSC) + i->sector)
/*
* Disk address fields
@ -362,7 +362,7 @@ REG cd_reg[] = {
MTAB cd_mod[] = {
{ MTAB_XTD|MTAB_VDV, 0, "1733-2 Cartridge Disk Drive Controller" },
{ MTAB_XTD|MTAB_VDV, 0, "EQUIPMENT", "EQUIPMENT=hexAddress",
&set_equipment, &show_addr, NULL, "Display equipment address" },
&set_equipment, &show_addr, NULL, "Set/Display equipment address" },
{ MTAB_XTD|MTAB_VUN, 0, "DRIVE", NULL,
NULL, &show_drive, NULL, "Display type of drive (856-2 or 856-4)" },
{ MTAB_XTD|MTAB_VUN, 0, NULL, "856-2",
@ -383,7 +383,7 @@ MTAB cd_mod[] = {
{ MTAB_XTD|MTAB_VDV, 0, NULL, "CARTFIRST",
&set_cartfirst, NULL, NULL, "Set cartridge as logical disk 0" },
{ MTAB_XTD|MTAB_VDV, 0, NULL, "FIXEDFIRST",
&set_fixedfirst, NULL, NULL, "Set fixec disk as logical disk 0" },
&set_fixedfirst, NULL, NULL, "Set fixed disk as logical disk 0" },
{ 0 }
};
@ -663,10 +663,32 @@ static void StartCDDiskIO(UNIT *uptr, struct cdio_unit *iou, uint16 state)
fw_IOunderwayEOP2(&CDdev, 0);
if ((cd_dev.dctrl & DBG_DTRACE) != 0)
if ((cd_dev.dctrl & DBG_DTRACE) != 0) {
const char *active = "None";
if (iou != NULL) {
if (iou->active != NULL) {
if (iou->active == iou->ondrive[0])
active = "0";
if (iou->active == iou->ondrive[1])
active = "1";
}
}
fprintf(DBGOUT,
"%sCD - Start I/O, cur: %04X, len: %04X, state: %s\r\n",
INTprefix, CDdev.CWA, CDdev.BUFLEN, CDstateStr[state]);
"%sCD - Start I/O, drive: %s, disk: %s, cur: %04X, len: %04X, state: %s\r\n",
INTprefix, iou != NULL ? iou->name : "None", active,
CDdev.CWA, CDdev.BUFLEN, CDstateStr[state]);
if (iou != NULL) {
uint16 sector;
sector = (((2 * iou->cylinder) + iou->surface) * CD_NUMSC) + iou->sector;
fprintf(DBGOUT,
"%sCD - Disk Address: c:%u,s:%c,d:%c,s:%u (0x%04X), Log. Sector %u (0x%04X)\r\n",
INTprefix, iou->cylinder, '0' + iou->surface, '0' + iou->disk,
iou->sector, iou->sectorAddr, sector, sector);
}
}
CDdev.DCYLSTATUS &= ~iou->seekComplete;
@ -709,8 +731,13 @@ static enum cdio_status CDDiskIORead(UNIT *uptr)
CDdev.DCYLSTATUS &= ~CD_CYL_MASK;
CDdev.DCYLSTATUS |= (iou->cylinder << CD_CYL_SHIFT);
sim_fseeko(uptr->fileref, lba * CD_NUMBY, SEEK_SET);
sim_fread(iou->buf, sizeof(uint16), CD_NUMWD, uptr->fileref);
/*
* Report any error in the underlying container infrastructure as an
* address error.
*/
if (sim_fseeko(uptr->fileref, lba * CD_NUMBY, SEEK_SET) ||
(sim_fread(iou->buf, sizeof(uint16), CD_NUMWD, uptr->fileref) != CD_NUMWD))
return CDIO_ADDRERR;
for (i = 0; i < CD_NUMWD; i++) {
/*** TODO: fix protect check ***/
@ -752,8 +779,14 @@ static enum cdio_status CDDiskIOWrite(UNIT *uptr)
CDdev.DCYLSTATUS &= ~CD_CYL_MASK;
CDdev.DCYLSTATUS |= (iou->cylinder << CD_CYL_SHIFT);
sim_fseeko(uptr->fileref, lba * CD_NUMBY, SEEK_SET);
sim_fwrite(iou->buf, sizeof(uint16), CD_NUMWD, uptr->fileref);
/*
* Report any error in the underlying container infrastructure as an
* address error.
*/
if (sim_fseeko(uptr->fileref, lba * CD_NUMBY, SEEK_SET) ||
(sim_fwrite(iou->buf, sizeof(uint16), CD_NUMWD, uptr->fileref) != CD_NUMWD))
return CDIO_ADDRERR;
CDDiskIOIncSector(iou);
return fill ? CDIO_DONE : CDIO_MORE;
}
@ -773,8 +806,13 @@ static enum cdio_status CDDiskIOCompare(UNIT *uptr)
CDdev.DCYLSTATUS &= ~CD_CYL_MASK;
CDdev.DCYLSTATUS |= (iou->cylinder << CD_CYL_SHIFT);
sim_fseeko(uptr->fileref, lba * CD_NUMBY, SEEK_SET);
sim_fread(iou->buf, sizeof(uint16), CD_NUMWD, uptr->fileref);
/*
* Report any error in the underlying container infrastructure as an
* address error.
*/
if (sim_fseeko(uptr->fileref, lba * CD_NUMBY, SEEK_SET) ||
(sim_fread(iou->buf, sizeof(uint16), CD_NUMWD, uptr->fileref) != CD_NUMWD))
return CDIO_ADDRERR;
for (i = 0; i < CD_NUMWD; i++) {
if (iou->buf[i] != LoadFromMem(CDdev.CWA))
@ -798,7 +836,7 @@ void CDDiskIO(UNIT *uptr, uint16 iotype)
{
struct cdio_unit *iou = (struct cdio_unit *)uptr->up7;
const char *error = "Unknown";
enum cdio_status status;
enum cdio_status status = CDIO_ADDRERR;
switch (iotype) {
case CD_WRITE:
@ -1023,7 +1061,7 @@ static t_stat CDreset(DEVICE *dptr)
t_stat cd_reset(DEVICE *dptr)
{
t_stat r;
t_stat r = SCPE_OK;
if (IOFWinitialized)
if ((dptr->flags & DEV_DIS) == 0)
@ -1326,8 +1364,8 @@ t_stat CDautoload(void)
t_offset offset = i * CD_NUMBY;
void * buf = &M[i * CD_NUMWD];
sim_fseeko(uptr->fileref, offset, SEEK_SET);
if (sim_fread(buf, sizeof(uint16), CD_NUMWD, uptr->fileref) != CD_NUMWD)
if (sim_fseeko(uptr->fileref, offset, SEEK_SET) ||
(sim_fread(buf, sizeof(uint16), CD_NUMWD, uptr->fileref) != CD_NUMWD))
return SCPE_IOERR;
}
return SCPE_OK;

View file

@ -1,6 +1,6 @@
/*
Copyright (c) 2015-2016, John Forecast
Copyright (c) 2015-2017, John Forecast
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -74,6 +74,46 @@
* 6. For the 1706-A buffered data channel, what interrupt is used to signal
* "End of Operation"? A channel-specific interrupt or a pass-through
* interrupt from the device being controlled or some other?
*
* Instruction set evolution
*
* Over time the instruction set for the CDC 1700/Cyber 18 was extended in,
* sometime incompatible, ways. The emulator will attempt to implement the
* various discreet instructions sets that were available within the
* constraints of the emulator environment:
*
* 1. Original
*
* This was the original instruction set defined when the 1700 series
* was first released. The instruction set encoding wasted a number of
* bits (e.g. IIN, EIN, SPB and CPB each had 8 unused bits which were
* ignored during execution).
*
* Character addressing was an optional extension to the 1774 (and maybe
* the 1714) which was enabled/disabled by new instructions which made
* use of the used bits of the IIN instruction. Note that the encoding
* of these instructions is incompatible with the enhanced instruction
* set (see below).
*
* 2. Basic
*
* The basic instruction set is identical to the original instruction set
* but limits the encoding of the unused bits in some instructions. For
* example, IIN will only execute the IIN functionality if the low-order
* 8 bits are encoded as zero, any other value will cause the instruction
* to execute as a NOP.
*
* 3. Enhanced (Unimplemented)
*
* The enhanced instruction set makes use of the unused bits of the basic
* instruction set to add new functionality:
*
* - Additional 4 registers
* - Character addressing mode
* - Field references
* - Multi-register save/restore
* - etc
*
*/
#include "cdc1700_defs.h"
@ -97,6 +137,13 @@ uint32 CountRejects = 0;
t_bool FirstAddr = TRUE;
/*
* Memory location holding MSOS5 system request routine address
*/
#define NMON 0x00F4
extern void MSOS5request(uint16, uint16);
extern int disassem(char *, uint16, t_bool, t_bool, t_bool);
extern enum IOstatus doIO(t_bool, DEVICE **);
@ -105,6 +152,9 @@ extern void rebuildPending(void);
extern void dev1Interrupts(char *);
t_stat cpu_set_instr(UNIT *, int32, CONST char *, void *);
t_stat cpu_show_instr(FILE *, UNIT *, int32, CONST void *);
t_stat cpu_reset(DEVICE *);
t_stat cpu_set_size(UNIT *, int32, CONST char *, void *);
t_stat cpu_ex(t_value *, t_addr, UNIT *, int32);
@ -120,7 +170,7 @@ t_stat cpu_help(FILE *, DEVICE *, UNIT *, int32, const char *);
#define UNIT_MODE65K (1 << UNIT_V_MODE65K)
#define UNIT_V_CHAR (UNIT_V_UF + 4) /* Character addressing */
#define UNIT_CHAR (1 << UNIT_V_CHAR)
#define UNIT_V_PROT (UNIT_V_UF + 5)
#define UNIT_V_PROT (UNIT_V_UF + 5) /* Protect mode */
#define UNIT_PROT (1 << UNIT_V_PROT)
#define UNIT_V_MSIZE (UNIT_V_UF + 6) /* Memory size */
#define UNIT_MSIZE (1 << UNIT_V_MSIZE)
@ -154,6 +204,8 @@ REG cpu_reg[] = {
MTAB cpu_mod[] = {
{ MTAB_XTD|MTAB_VDV, 0, "1714 CDC 1700 series CPU", NULL, NULL, NULL },
{ MTAB_XTD|MTAB_VDV, 0, "INSTR", "INSTR={ORIGINAL|BASIC|ENHANCED}",
&cpu_set_instr, &cpu_show_instr, NULL, "Set CPU instruction set" },
{ UNIT_STOPSW, UNIT_STOPSW, "Selective Stop", "SSTOP",
NULL, NULL, NULL, "Enable Selective Stop" },
{ UNIT_STOPSW, 0, "No Selective Stop", "NOSSTOP",
@ -166,10 +218,10 @@ MTAB cpu_mod[] = {
NULL, NULL, NULL, "Enable 65K Indirect Addressing Mode" },
{ UNIT_MODE65K, 0, "32K Addressing Mode", "MODE32K",
NULL, NULL, NULL, "Enable 32K Indirect Addressing Mode" },
{ UNIT_CHAR, UNIT_CHAR, "Character Addressing", "CHAR",
NULL, NULL, NULL, "Enable Character Addressing Mode" },
{ UNIT_CHAR, 0, "No Character Addressing", "NOCHAR",
NULL, NULL, NULL, "Disable Character Addressing Mode" },
{ UNIT_CHAR, UNIT_CHAR, NULL, "CHAR",
NULL, NULL, NULL, "Enable Character Addressing Extensions" },
{ UNIT_CHAR, 0, NULL, "NOCHAR",
NULL, NULL, NULL, "Disable Character Addressing Extensions" },
{ UNIT_PROT, UNIT_PROT, "Program Protect", "PROTECT",
NULL, NULL, NULL, "Enable Protect Mode Operation" },
{ UNIT_PROT, 0, "", "NOPROTECT",
@ -205,7 +257,9 @@ DEBTAB cpu_deb[] = {
{ "INTLVL", DBG_INTLVL, "Add interrupt level to all displays" },
{ "PROTECT", DBG_PROTECT, "Display protect faults" },
{ "MISSING", DBG_MISSING, "Display info about missing devices" },
{ "FULL", DBG_ALL },
{ "ENHANCED", DBG_ENH, "Display enh. instructions in basic mode" },
{ "MSOS5", DBG_MSOS5, "Display MSOS5 requests" },
{ "FULL", DBG_ALL },
{ NULL }
};
@ -259,6 +313,45 @@ static uint16 interruptBit[] = {
0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000, 0x8000
};
t_stat cpu_set_instr(UNIT *uptr, int32 val, CONST char *cptr, void *desc)
{
if (!cptr)
return SCPE_IERR;
if (!strcmp(cptr, "ORIGINAL")) {
INSTR_SET = INSTR_ORIGINAL;
} else if (!strcmp(cptr, "BASIC")) {
INSTR_SET = INSTR_BASIC;
} else if (!strcmp(cptr, "ENHANCED")) {
INSTR_SET = INSTR_ENHANCED;
} else return SCPE_ARG;
return SCPE_OK;
}
t_stat cpu_show_instr(FILE *st, UNIT *uptr, int32 val, CONST void *desc)
{
switch (INSTR_SET) {
case INSTR_ORIGINAL:
fprintf(st, "\n\tOriginal instruction set");
if ((cpu_unit.flags & UNIT_CHAR) != 0)
fprintf(st, " + character addressing");
break;
case INSTR_BASIC:
fprintf(st, "\n\tBasic instruction set");
break;
case INSTR_ENHANCED:
fprintf(st, "\n\tEnhanced instruction set (Unimplemented)");
break;
default:
return SCPE_IERR;
}
return SCPE_OK;
}
/*
* Reset routine
*/
@ -421,7 +514,7 @@ uint16 LoadFromMem(uint16 addr)
*/
t_bool StoreToMem(uint16 addr, uint16 value)
{
if ((cpu_unit.flags & UNIT_PROT) != 0) {
if (inProtectedMode()) {
if (!Protected) {
if (P[MEMADDR(addr)]) {
if ((cpu_dev.dctrl & DBG_PROTECT) != 0) {
@ -448,7 +541,7 @@ t_bool StoreToMem(uint16 addr, uint16 value)
*/
t_bool IOStoreToMem(uint16 addr, uint16 value, t_bool prot)
{
if ((cpu_unit.flags & UNIT_PROT) != 0) {
if (inProtectedMode()) {
if (!prot) {
if (P[MEMADDR(addr)]) {
return FALSE;
@ -550,13 +643,26 @@ void doDIV(uint16 a)
sign++;
/*
* The documentation does not specify the result of a divide by zero.
* Hopefully, the diagnostics will provide some insight. Until then we
* just set the overflow flag and return saturated positive values.
* Handle divide by 0 (plus or minus) as documented in the 1784 reference
* manual.
*/
if (divisor == 0) {
Oflag = 1;
Areg = Qreg = MAXPOS;
Qreg = Areg;
Areg = (sign & 1) != 0 ? 0 : ~0;
return;
}
/*
* Special case check for zero dividend.
*/
if (remainder == 0) {
Areg = Qreg = 0;
if ((sign & 1) != 0)
Areg = ~Areg;
if (rsign)
Qreg = ~Qreg;
return;
}
@ -581,12 +687,11 @@ void doDIV(uint16 a)
if ((result & 0xFFFF8000) != 0)
Oflag = 1;
if ((result & 0x7FFF) != 0)
if ((sign & 1) != 0)
result = ~result;
if ((remainder & 0x7FFF) != 0)
if (rsign != 0)
remainder = ~remainder;
if ((sign & 1) != 0)
result = ~result;
if (rsign != 0)
remainder = ~remainder;
Areg = TRUNC16(result);
Qreg = TRUNC16(remainder);
@ -879,26 +984,30 @@ t_stat executeAnInstruction(void)
* Check for protected mode operation where we are about to execute a
* protected instruction and the previous instruction was unprotected.
*/
if ((cpu_unit.flags & UNIT_PROT) != 0) {
if (inProtectedMode()) {
if (!lastP && Protected) {
if ((cpu_dev.dctrl & DBG_PROTECT) != 0) {
fprintf(DBGOUT,
"%sProtect fault, unprotected after protected at %04X\r\n",
"%sProtect fault, protected after unprotected at %04X\r\n",
INTprefix, OrigPreg);
}
Pfault = TRUE;
RaiseInternalInterrupt();
/*
* Make sure we skip over the failing instruction.
*/
if ((instr & OPC_MASK) != 0) {
if ((instr & OPC_ADDRMASK) == 0) {
INCP;
}
}
/*
* Execute this instructionas an unprotected Selective Stop.
* The exact semantics of a protected fault are not documented in any
* the hardware references. The code in this simulator was created
* by examining the source code of MSOS 5.0. In the case of a 2 word
* instruction causing the trap, P is left pointing at the second word
* of the instruction. Note that the SMM diagnostics do not check for
* this case.
*/
/*
* Execute this instruction as an unprotected Selective Stop. If a
* stop occurs, P may not point to a valid instruction (see above).
* A subsequent "continue" command will cause a trap to the protect
* fault processor.
*/
if ((cpu_unit.flags & UNIT_STOPSW) != 0) {
dumpRegisters();
@ -1052,9 +1161,32 @@ t_stat executeAnInstruction(void)
case OPC_SPECIAL:
switch (instr & OPC_SPECIALMASK) {
case OPC_SLS:
if ((cpu_unit.flags & UNIT_STOPSW) != 0) {
dumpRegisters();
return SCPE_SSTOP;
switch (INSTR_SET) {
case INSTR_BASIC:
if ((instr & OPC_MODMASK) != 0) {
if ((cpu_dev.dctrl & DBG_ENH) != 0)
fprintf(DBGOUT, "%s Possible Enh. Instruction (%04X) at %04x\r\n",
INTprefix, instr, OrigPreg);
}
/* FALLTHROUGH */
case INSTR_ORIGINAL:
if ((cpu_unit.flags & UNIT_STOPSW) != 0) {
dumpRegisters();
return SCPE_SSTOP;
}
break;
case INSTR_ENHANCED:
if ((instr & OPC_MODMASK) == 0) {
if ((cpu_unit.flags & UNIT_STOPSW) != 0) {
dumpRegisters();
return SCPE_SSTOP;
}
break;
}
/*** TODO: Enhanced skip instructions ***/
break;
}
break;
@ -1143,6 +1275,8 @@ t_stat executeAnInstruction(void)
case OPC_SNF:
if (!Pfault)
Preg = doADDinternal(Preg, instr & OPC_SKIPCOUNT);
Pfault = FALSE;
rebuildPending();
break;
}
break;
@ -1251,36 +1385,64 @@ t_stat executeAnInstruction(void)
}
break;
/*
* EIN, IIN, SPB and CPB operate differently depending on the
* currently selected instruction set.
*/
case OPC_IIN:
case OPC_EIN:
case OPC_SPB:
case OPC_CPB:
switch (INSTR_SET) {
case INSTR_ORIGINAL:
/*
* Character addressing enable/disable is only available as
* an extension to the original instruction set.
*/
if ((instr & OPC_SPECIALMASK) == OPC_IIN) {
if ((cpu_unit.flags & UNIT_CHAR) != 0) {
if ((instr & OPC_MODMASK) != 0) {
switch (instr) {
case OPC_ECA:
CAenable = 1;
break;
case OPC_DCA:
CAenable = 0;
break;
}
goto done;
}
}
}
break;
case INSTR_BASIC:
if ((instr & OPC_MODMASK) != 0) {
if ((cpu_dev.dctrl & DBG_ENH) != 0)
fprintf(DBGOUT, "%s Possible Enh. Instruction (%04X) at %04x\r\n",
INTprefix, instr, OrigPreg);
}
break;
case INSTR_ENHANCED:
if ((instr & OPC_MODMASK) != 0) {
/*** TODO: Enhanced instructions ***/
goto done;
}
break;
}
/* FALLTHROUGH */
/*
* The following instructions (EIN, IIN, SPB, CPB and EXI)
* generate a protect fault if the protect switch is set and
* the instruction is not protected. If the system is unable
* to handle the interrupt (interrupts disabled or interrupt 0
* masked), the instruction executes as a "Selective Stop". Note
* that the character addressing instructions are a subset
* of IIN and have to be checked separately.
* masked), the instruction executes as a "Selective Stop".
*/
case OPC_IIN:
if ((cpu_unit.flags & UNIT_CHAR) != 0) {
if ((instr & 0xFF) != 0) {
switch (instr) {
case OPC_ECA:
CAenable = 1;
break;
case OPC_DCA:
CAenable = 0;
break;
}
break;
}
}
case OPC_EIN:
case OPC_SPB:
case OPC_CPB:
case OPC_EXI:
if ((cpu_unit.flags & UNIT_PROT) != 0) {
if (inProtectedMode()) {
if (!Protected) {
if ((cpu_dev.dctrl & DBG_PROTECT) != 0) {
fprintf(DBGOUT,
@ -1322,7 +1484,20 @@ t_stat executeAnInstruction(void)
INTprefix, Areg, Qreg, Mreg, Oflag, INTflag, DEFERflag);
}
/*
* Check for MSOS5 system requests. If we are executing the first
* instruction of the MSOS5 request processor (which is also an
* IIN instruction), dump information about the current request.
* This test will work correctly independent of whether a 1 or 2
* word RTJ is used to call the request processor.
*/
if ((cpu_dev.dctrl & DBG_MSOS5) != 0) {
if (OrigPreg == (M[NMON] + 1))
MSOS5request(M[M[NMON]], 0);
}
INTflag = 0;
done:
break;
case OPC_SPB:
@ -1366,7 +1541,7 @@ t_stat executeAnInstruction(void)
* Protection fault if the instruction is not protected and
* modifies M
*/
if ((cpu_unit.flags & UNIT_PROT) != 0) {
if (inProtectedMode()) {
if ((instr & MOD_D_M) != 0) {
if (!Protected) {
if ((cpu_dev.dctrl & DBG_PROTECT) != 0) {
@ -1446,6 +1621,24 @@ t_stat executeAnInstruction(void)
break;
case OPC_NOP:
switch (INSTR_SET) {
case INSTR_ORIGINAL:
break;
case INSTR_BASIC:
if ((instr & OPC_MODMASK) != 0) {
if ((cpu_dev.dctrl & DBG_ENH) != 0)
fprintf(DBGOUT, "%s Possible Enh. Instruction (%04X) at %04x\r\n",
INTprefix, instr, OrigPreg);
}
break;
case INSTR_ENHANCED:
if ((instr & OPC_MODMASK) != 0) {
/*** TODO: Enhanced miscellaneous instructions ***/
}
break;
}
break;
case OPC_ENQ:
@ -1573,12 +1766,13 @@ t_stat cpu_help(FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr
" storage access bus and 3 1706-A buffered data channels are included.\n\n"
" The amount of memory available to the system can be changed with:\n\n"
"+sim> SET CPU nK\n\n"
" The original 1700 series CPU (the 1704) only allowed up to 32KW to be\n"
" attached to the CPU and indirect memory references would continue to\n"
" loop through memory if bit 15 of the target address was set. When 64KW\n"
" support was added indirect addressing was limited to a single level\n"
" so that the entire 16-bits of address could be used. The indirect\n"
" addressing mode may be changed by:\n\n"
" The original 1700 series CPU (the 1704) only allowed up to 32KW of\n"
"to be attached to the CPU and indirect memory references would continue\n"
"to loop through memory if bit 15 of the target address was set. When 64KW\n"
" support was added, indirect addressing was limited to a single level\n"
" so that the entire 16-bits of address could be used. Systems which\n"
" supported 64KW of memory had a front-panel switch to allow software\n"
" to run in either mode. The indirect addressing mode may be changed by:\n\n"
"+sim> SET CPU MODE32K\n"
"+sim> SET CPU MODE65K\n\n"
" In 32KW addressing mode, the number of indirect address chaining\n"
@ -1588,6 +1782,33 @@ t_stat cpu_help(FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr
" reserve interrupt 0 (and therefore equipment address 0) for parity\n"
" errors (never detected by the simulator), protect faults and power fail\n"
" (not supported by the simulator).\n"
"2 Instruction Set\n"
" The instruction set implemented by the CDC 1700 series, and later\n"
" Cyber-18 models changed as new features were added. When originally\n"
" released, the 1704 had a number of instruction bits which were ignored\n"
" by the CPU (e.g. the IIN and EIN instructions each had 8 unused bits).\n"
" Later the instruction set was refined into Basic and Enhanced. The\n"
" Basic instruction set reserved these unsed bits (e.g. IIN and EIN\n"
" instructions were only recognised if the previously unused bits were\n"
" all set to zero). The MP17 microprocessor implementation of the\n"
" architecture made use of these newly available bits to implement\n"
" the Enhanced instruction set. The supported instruction set may be\n"
" changed by:\n\n"
"+sim> SET CPU INSTR=ORIGINAL\n"
"+sim> SET CPU INSTR=BASIC\n"
"+sim> SET CPU INSTR=ENHANCED\n\n"
" The Enhanced instruction set is not currently implemented by the\n"
" simulator. Note that disassembly will always be done with respect to\n"
" the currently selected instruction set. If the instruction set is set\n"
" to BASIC, enhanced instructions will be displayed as:\n\n"
"+ NOP [ Possible enhanced instruction\n"
"2 Character Addressing Mode\n"
" The ORIGINAL instruction set could be enhanced with character (8-bit)\n"
" addressing mode which added 2 new instructions; enable/disable\n"
" character addressing mode (ECA/DCA). These new instructions and the\n"
" ability to perform character addressing may be controlled by:\n\n"
"+sim> SET CPU CHAR\n"
"+sim> SET CPU NOCHAR\n"
"2 $Registers\n"
"2 Front Panel Switches\n"
" The 1714 front panel includes a number of switches which control the\n"

View file

@ -1,6 +1,6 @@
/*
Copyright (c) 2015-2016, John Forecast
Copyright (c) 2015-2017, John Forecast
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -312,7 +312,7 @@ t_stat dc_svc(UNIT *uptr)
{
DEVICE *dptr;
enum IOstatus status;
uint16 temp;
uint16 temp = 0;
if ((dptr = find_dev_from_unit(uptr)) != NULL) {
IO_DEVICE *iod = (IO_DEVICE *)dptr->ctxt;

View file

@ -1,6 +1,6 @@
/*
Copyright (c) 2015-2016, John Forecast
Copyright (c) 2015-2017, John Forecast
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -81,6 +81,9 @@
#define DBG_V_INTLVL 9 /* Prefix with interrupt level */
#define DBG_V_PROTECT 10 /* Display protect fault information */
#define DBG_V_MISSING 11 /* Display access to missing devices */
#define DBG_V_ENH 12 /* Display enh. instructions ignored */
/* in basic instruction mode */
#define DBG_V_MSOS5 13 /* Trace MSOS5 system requests */
#define DBG_DISASS (1 << DBG_V_DISASS)
#define DBG_IDISASS (1 << DBG_V_IDISASS)
@ -94,6 +97,8 @@
#define DBG_INTLVL (1 << DBG_V_INTLVL)
#define DBG_PROTECT (1 << DBG_V_PROTECT)
#define DBG_MISSING (1 << DBG_V_MISSING)
#define DBG_ENH (1 << DBG_V_ENH)
#define DBG_MSOS5 (1 << DBG_V_MSOS5)
/*
* Default device radix
@ -117,6 +122,14 @@
/*
* CPU
*/
/* The currently supported instruction set is held in u3. */
#define INSTR_ORIGINAL 0 /* Original instruction set */
#define INSTR_BASIC 1 /* Basic instruction set */
#define INSTR_ENHANCED 2 /* Enhanced instruction set */
#define INSTR_SET (cpu_unit.u3)
#define MAXMEMSIZE 65536
#define DEFAULTMEMSIZE 32768
@ -202,8 +215,6 @@ enum IOstatus {
#define MOD_I1 0x200
#define MOD_I2 0x100
#define ISCONSTANT(i) ((i & (MOD_RE | MOD_IN | 0xFF)) == 0)
#define OPC_MASK 0xF000
#define OPC_ADQ 0xF000
#define OPC_LDQ 0xE000
@ -296,9 +307,9 @@ enum IOstatus {
#define OPC_EXI 0x0E00
#define OPC_MODMASK 0x00FF
#define EXTEND16(v) ((v) & 0x8000) ? (v) | 0xFFFF0000 : (v)
#define EXTEND8(v) ((v) & 0x80) ? (v) | 0xFF00 : (v)
#define EXTEND4(v) ((v) & 0x8) ? (v) | 0xFFF0 : (v)
#define EXTEND16(v) (((v) & 0x8000) ? (v) | 0xFFFF0000 : (v))
#define EXTEND8(v) (((v) & 0x80) ? (v) | 0xFF00 : (v))
#define EXTEND4(v) (((v) & 0x8) ? (v) | 0xFFF0 : (v))
#define TRUNC16(v) ((v) & 0xFFFF)
#define CANEXTEND8(v) (((v) & 0xFF80) == 0xFF80)
@ -308,7 +319,6 @@ enum IOstatus {
#define MOD_S_A 0x40
#define MOD_S_Q 0x20
#define OPC_SHIFTCOUNT 0x001F
#define OPC_ADDRMASK 0x00FF
#define OPC_QRS (OPC_SHIFTS | MOD_S_Q)
#define OPC_ARS (OPC_SHIFTS | MOD_S_A)
@ -317,6 +327,131 @@ enum IOstatus {
#define OPC_ALS (OPC_SHIFTS | MOD_LR | MOD_S_A)
#define OPC_LLS (OPC_SHIFTS | MOD_LR | MOD_S_A | MOD_S_Q)
#define OPC_ADDRMASK 0x00FF
#define ISCONSTANT(i) ((i & (MOD_RE | MOD_IN | OPC_ADDRMASK)) == 0)
/*
* Enhanced instruction layout.
*
* Enhanced storage reference instructions:
*
* 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
* +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
* | F = 0 | F1 = 4 |r |i | Ra | Rb |
* +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
* | F4 | F5 | delta |
* +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
* | 16-bit address, only present if delta = 0 |
* +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
*
* Field reference instructions:
*
* 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
* +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
* | F = 0 | F1 = 5 |r |i | Ra | Rb |
* +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
* | FLDSTR | FLDLTH-1 | delta |
* +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
* | 16-bit address, only present if delta = 0 |
* +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
*
* Enhanced inter-register instructions:
*
* 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
* +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
* | F = 0 | F1 = 7 | Ra | F2a | Rb |
* +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
*
* Enhanced skip instructions:
*
* 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
* +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
* | F = 0 | F1 = 0 | F2 | SK |
* +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
*
* Decrement and repeat instructions:
*
* 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
* +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
* | F = 0 | F1 = 6 | Ra |0 | SK |
* +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
*
* Miscellaneous instructions:
*
* 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
* +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
* | F = 0 | F1 = B | Ra |0 | F3 |
* +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
*
*/
#define MOD_ENHRE 0x0080
#define MOD_ENHIN 0x0040
//#define REG_NONE 0x0
#define REG_R1 0x1
#define REG_R2 0x2
#define REG_R3 0x3
#define REG_R4 0x4
#define REG_Q 0x5
#define REG_A 0x6
#define REG_I 0x7
#define WORD_REG 0x0
#define WORD_MEM 0x1
#define CHAR_REG 0x2
#define CHAR_MEM 0x3
#define OPC_ENHSUBJX 0x5000
#define OPC_ENHADDR 0x8000
#define OPC_ENHSUBR 0x9000
#define OPC_ENHANDR 0xA000
#define OPC_ENHANDM 0xA100
#define OPC_ENHLOAD 0xC000
#define OPC_ENHSTORE 0xC100
#define OPC_ENHLOADC 0xC200
#define OPC_ENHSTOREC 0xC300
#define OPC_ENHORR 0xD000
#define OPC_ENHORM 0xD100
#define OPC_CMPREQ 0xE000
#define OPC_CMPCEQ 0xE200
#define OPC_FLDSFZ 0x2
#define OPC_FLDSFN 0x3
#define OPC_FLDLOAD 0x4
#define OPC_FLDSTORE 0x5
#define OPC_FLDCLEAR 0x6
#define OPC_FLDSET 0x7
#define OPC_ENHSKIPZ 0x0
#define OPC_ENHSKIPNZ 0x1
#define OPC_ENHSKIPPOS 0x2
#define OPC_ENHSKIPNEG 0x3
#define OPC_ENHSKIPR1 0x4
#define OPC_ENHSKIPR2 0x8
#define OPC_ENHSKIPR3 0xC
#define OPC_ENHSKIPR4 0x0
#define OPC_ENHLMM 0x1
#define OPC_ENHLRG 0x2
#define OPC_ENHSRG 0x3
#define OPC_ENHSIO 0x4
#define OPC_ENHSPS 0x5
#define OPC_ENHDMI 0x6
#define OPC_ENHCBP 0x7
#define OPC_ENHGPE 0x8
#define OPC_ENHGPO 0x9
#define OPC_ENHASC 0xA
#define OPC_ENHAPM 0xB
#define OPC_ENHPM0 0xC
#define OPC_ENHPM1 0xD
#define OPC_ENHLUB 0x0
#define OPC_ENHLLB 0x1
#define OPC_ENHEMS 0x2
#define OPC_ENHWPR 0x3
#define OPC_ENHRPR 0x4
#define OPC_ENHECC 0x5
/*
* Interrupt vector definitions
*/

View file

@ -99,21 +99,20 @@ int disassem(char *buf, uint16 addr, t_bool dbg, t_bool targ, t_bool exec)
{
int consumed = 1;
char prot = ISPROTECTED(addr) ? 'P' : ' ';
char mode[8], optional[8], temp[8], decoded[64];
const char *spc, *shift, *inter, *dest;
char optional[8], temp[8], decoded[64];
const char *mode, *spc, *shift, *inter, *dest;
uint16 instr = LoadFromMem(addr);
uint16 delta = instr & OPC_ADDRMASK;
uint8 more = 0, isconst = 0;
uint16 t;
strcpy(optional, " ");
strcpy(decoded, "UNDEF");
if ((instr & OPC_MASK) != 0) {
strcpy(decoded, opName[(instr & OPC_MASK) >> 12]);
if ((instr & MOD_RE) == 0)
strcpy(mode, delta == 0 ? "+ " : "- ");
else strcpy(mode, "* ");
mode = delta == 0 ? "+ " : "- ";
else mode = "* ";
switch (instr & OPC_MASK) {
case OPC_ADQ:
@ -126,7 +125,7 @@ int disassem(char *buf, uint16 addr, t_bool dbg, t_bool targ, t_bool exec)
case OPC_DVI:
case OPC_MUI:
if (ISCONSTANT(instr))
strcat(mode, "=");
isconst = 1;
break;
}
@ -136,28 +135,77 @@ int disassem(char *buf, uint16 addr, t_bool dbg, t_bool targ, t_bool exec)
sprintf(temp, "$%04X", LoadFromMem(addr + 1));
} else sprintf(temp, "$%02X", delta);
strcat(decoded, mode);
if ((instr & MOD_IN) != 0)
strcat(decoded, "(");
strcat(decoded, temp);
if ((instr & MOD_IN) != 0)
strcat(decoded, ")");
strcat(decoded, idxName[(instr & (MOD_I1 | MOD_I2)) >> 8]);
sprintf(decoded, "%s%s%s%s%s%s%s",
opName[(instr & OPC_MASK) >> 12],
mode,
isconst ? "=" : "",
(instr & MOD_IN) != 0 ? "(" : "",
temp,
(instr & MOD_IN) != 0 ? ")" : "",
idxName[(instr & (MOD_I1 | MOD_I2)) >> 8]);
} else {
spc = spcName[(instr & OPC_SPECIALMASK) >> 8];
switch (instr & OPC_SPECIALMASK) {
case OPC_EIN:
case OPC_IIN:
case OPC_EIN:
case OPC_SPB:
case OPC_CPB:
switch (INSTR_SET) {
case INSTR_ORIGINAL:
/*
* Character addressing enable/disable is only available as
* an extension to the original set.
*/
switch (instr) {
case OPC_ECA:
sprintf(decoded, "%s", "ECA");
break;
case OPC_DCA:
sprintf(decoded, "%s", "DCA");
break;
default:
sprintf(decoded, "%s", spc);
break;
}
break;
case INSTR_BASIC:
if (delta == 0) {
sprintf(decoded, "%s", spc);
} else {
sprintf(decoded, "%s", "NOP [ Possible enhanced instruction");
}
break;
case INSTR_ENHANCED:
sprintf(decoded, "%s", delta != 0 ? "Enhanced" : spc);
break;
}
break;
case OPC_NOP:
sprintf(decoded, "%s", spc);
switch (INSTR_SET) {
case INSTR_ORIGINAL:
sprintf(decoded, "%s", spc);
break;
case INSTR_BASIC:
if (delta != 0) {
sprintf(decoded, "%s", "NOP [ Possible enhanced instruction");
} else sprintf(decoded, "%s", spc);
break;
case INSTR_ENHANCED:
sprintf(decoded, "%s", delta != 0 ? "Enhanced" : spc);
break;
}
break;
case OPC_EXI:
sprintf(decoded, "%s $%02X", spc, instr & OPC_MODMASK);
sprintf(decoded, "%s $%02X", spc, delta);
break;
case OPC_SKIPS:
@ -166,6 +214,23 @@ int disassem(char *buf, uint16 addr, t_bool dbg, t_bool targ, t_bool exec)
break;
case OPC_SLS:
if (delta != 0) {
switch (INSTR_SET) {
case INSTR_BASIC:
sprintf(decoded, "%s", "NOP [ Possible enhanced instruction");
break;
case INSTR_ORIGINAL:
sprintf(decoded, "%s $%02X", spc, delta);
break;
case INSTR_ENHANCED:
sprintf(decoded, "%s", "Enhanced");
break;
}
break;
}
case OPC_INP:
case OPC_OUT:
case OPC_INA:
@ -198,10 +263,10 @@ int disassem(char *buf, uint16 addr, t_bool dbg, t_bool targ, t_bool exec)
sprintf(buf, "%c %04X %s %s",
prot, instr, optional, decoded);
}
if (targ) {
const char *rel = "";
t_bool indJmp = FALSE;
uint8 more = 0;
uint16 taddr, taddr2, base;
switch (instr & OPC_MASK) {
@ -310,14 +375,20 @@ int disassem(char *buf, uint16 addr, t_bool dbg, t_bool targ, t_bool exec)
if (indJmp) {
sprintf(buf, "[ => (%04X%s)", taddr2, rel);
} else {
if (more == 1)
sprintf(buf, "[ => %04X%s %s {%04X}", taddr2, rel,
P[MEMADDR(taddr)] ? "(P)" : "",
LoadFromMem(taddr));
else sprintf(buf, "[ => %04X%s (B:%04X%s) %s {%04X}",
taddr2, rel, base, rel,
P[MEMADDR(taddr)] ? "(P)" : "",
LoadFromMem(taddr));
switch (more) {
case 1:
sprintf(buf, "[ => %04X%s %s {%04X}", taddr2, rel,
P[MEMADDR(taddr)] ? "(P)" : "",
LoadFromMem(taddr));
break;
case 2:
sprintf(buf, "[ => %04X%s (B:%04X%s) %s {%04X}",
taddr2, rel, base, rel,
P[MEMADDR(taddr)] ? "(P)" : "",
LoadFromMem(taddr));
break;
}
}
}
}

View file

@ -1,6 +1,6 @@
/*
Copyright (c) 2015-2016, John Forecast
Copyright (c) 2015-2017, John Forecast
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -538,8 +538,13 @@ static enum dpio_status DPDiskIORead(UNIT *uptr)
if (iou->cylinder >= numcy)
return DPIO_ADDRERR;
sim_fseeko(uptr->fileref, lba * DP_NUMBY, SEEK_SET);
sim_fread(iou->buf, sizeof(uint16), DP_NUMWD, uptr->fileref);
/*
* Report any error in the underlying container infrastructure as an
* address error.
*/
if (sim_fseeko(uptr->fileref, lba * DP_NUMBY, SEEK_SET) ||
(sim_fread(iou->buf, sizeof(uint16), DP_NUMWD, uptr->fileref) != DP_NUMWD))
return DPIO_ADDRERR;
for (i = 0; i < DP_NUMWD; i++) {
/*** TODO: fix protect check ***/
@ -579,8 +584,14 @@ static enum dpio_status DPDiskIOWrite(UNIT *uptr)
} else iou->buf[i] = 0;
}
sim_fseeko(uptr->fileref, lba * DP_NUMBY, SEEK_SET);
sim_fwrite(iou->buf, sizeof(uint16), DP_NUMWD, uptr->fileref);
/*
* Report any error in the underlying container infrastructure as an
* address error.
*/
if (sim_fseeko(uptr->fileref, lba * DP_NUMBY, SEEK_SET) ||
(sim_fwrite(iou->buf, sizeof(uint16), DP_NUMWD, uptr->fileref) != DP_NUMWD))
return DPIO_ADDRERR;
DPDiskIOIncSector(iou);
return fill ? DPIO_DONE : DPIO_MORE;
}
@ -598,8 +609,13 @@ static enum dpio_status DPDiskIOCompare(UNIT *uptr)
if (iou->cylinder >= numcy)
return DPIO_ADDRERR;
sim_fseeko(uptr->fileref, lba * DP_NUMBY, SEEK_SET);
sim_fread(iou->buf, sizeof(uint16), DP_NUMWD, uptr->fileref);
/*
* Report any error in the underlying container infrastructure as an
* address error.
*/
if (sim_fseeko(uptr->fileref, lba * DP_NUMBY, SEEK_SET) ||
(sim_fread(iou->buf, sizeof(uint16), DP_NUMWD, uptr->fileref) != DP_NUMWD))
return DPIO_ADDRERR;
for (i = 0; i < DP_NUMWD; i++) {
if (iou->buf[i] != LoadFromMem(iou->CWA))
@ -1101,8 +1117,8 @@ t_stat DPautoload(void)
t_offset offset = i * DP_NUMBY;
void *buf = &M[i * DP_NUMWD];
sim_fseeko(uptr->fileref, offset, SEEK_SET);
if (sim_fread(buf, sizeof(uint16), DP_NUMWD, uptr->fileref) != DP_NUMWD)
if (sim_fseeko(uptr->fileref, offset, SEEK_SET) ||
(sim_fread(buf, sizeof(uint16), DP_NUMWD, uptr->fileref) != DP_NUMWD))
return SCPE_IOERR;
}
return SCPE_OK;

631
CDC1700/cdc1700_msos5.c Normal file
View file

@ -0,0 +1,631 @@
/*
Copyright (c) 2015-2017, John Forecast
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
JOHN FORECAST 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 John Forecast shall not
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from John Forecast.
*/
/* cdc1700_msos5.c: CDC1700 MSOS 5 trace and debugging support
*/
#include "cdc1700_defs.h"
extern uint16 M[], Preg, Areg, Qreg;
extern char INTprefix[];
extern uint16 doADDinternal(uint16, uint16);
/*
* Information about monitor requests.
*/
#define RQ_SYSDIRREAD 0 /* System directory read (monitor only) */
#define RQ_READ 1 /* Normal read */
#define RQ_WRITE 2 /* Normal write */
#define RQ_STATUS 3 /* I/O request status */
#define RQ_FREAD 4 /* Formatted read */
#define RQ_EXIT 5 /* Unprotected exit */
#define RQ_FWRITE 6 /* Formatted write */
#define RQ_LOADER 7 /* Relocatable binary loader */
#define RQ_TIMER 8 /* Schedule program with delay */
#define RQ_SCHDLE 9 /* Schedule program */
#define RQ_SPACE 10 /* Allocate core */
#define RQ_CORE 11 /* Unprotected core bounds */
#define RQ_RELEAS 12 /* Release core */
#define RQ_GTFILE 13 /* Access permanent file in program library */
#define RQ_MOTION 14 /* Tape motion */
#define RQ_TIMPT1 15 /* Schedule directory program with delay */
#define RQ_INDIR 16 /* Indirect (use another parameter list) */
#define RQ_PTNCOR 17 /* Allocate partitioned core */
#define RQ_SYSCHD 18 /* Schedule directory program */
#define RQ_DIRCHD 19 /* Enable/Disable system directory scheduling */
/*
* Masks for default fields in the first parameter word.
*/
#define D 0x4000 /* Part 1 request indicator */
#define RQ 0x3E00 /* Request code */
#define X 0x0100 /* Relative/indirect indicator */
#define RP 0x00F0 /* Request priority */
#define CP 0x000F /* Completion priority */
#define TELETYPE 0x04 /* Console TTY LU */
/*
* Well-known locations within MSOS 5.
*/
#define LIBLU 0x00C2 /* Library LU */
#define CREXTB 0x00E9 /* Extended communications region */
#define LOG1A 28 /* Offset to LOG1A table address */
/*
* Queueable requests have a completion address as the second parameter.
* Note that INDIR requests may or may not be queueable depending on the
* target parameter list.
*/
t_bool queueable[] = {
TRUE, TRUE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, TRUE,
TRUE, FALSE, FALSE, TRUE, TRUE, TRUE, FALSE, TRUE, TRUE, FALSE
};
const char *indent[] = {
"", " ", " ", " ", " ", " ", " ", " ", " "
};
const char mode[] = { 'B', 'A' };
const char luchr[] = { ' ', 'R', 'I', '?' };
const char rel[] = { '0', '1' };
const char part1[] = { '0', '1' };
const char exitind[] = { '0', '1' };
const char units[] = {
'0', '1', '2', '3', '?', '?', '?', '?',
'?', '?', '?', '?', '?', '?', '?', '?'
};
const char *density[] = {
"", "800 BPI", "556 BPI", "200 BPI", "1600 BPI", "???", "???", "???",
"???", "???", "???", "???", "???", "???", "???", "???"
};
const char *action[] = {
"", "BSR", "EOF", "REW", "UNL", "FSF", "BSF", "ADR",
"???", "???", "???", "???", "???", "???", "???", "???"
};
uint32 seqno = 0;
#define END(s) &s[strlen(s)]
/*
* Character representation.
*/
const char *charRep[128] = {
"<00>", "<01>", "<02?", "<03>", "<04>", "<05>", "<06>", "<07>",
"<08>", "<09>", "<0A>", "<0B>", "<0C>", "<0D>", "<0E>", "<0F>",
"<10>", "<11>", "<12>", "<13>", "<14>", "<15>", "<16>", "<17>",
"<18>", "<19>", "<1A>", "<1B>", "<1C>", "<1D>", "<1E>", "<1F>",
" ", "!", "\"", "#", "$", "%", "&", "'",
"(", ")", "*", "+", ",", "-", ".", "/",
"0", "1", "2", "3", "4", "5", "6", "7",
"8", "9", ":", ";", "<", "=", ">", "?",
"@", "A", "B", "C", "D", "E", "F", "G",
"H", "I", "J", "K", "L", "M", "N", "O",
"P", "Q", "R", "S", "T", "U", "V", "W",
"X", "Y", "Z", "[", "\\", "]", "^", "_",
"<60>", "<61>", "<62>", "<63>", "<64>", "<65>", "<66>", "<67>",
"<68>", "<69>", "<6A>", "<6B>", "<6C>", "<6D>", "<6E>", "<6F>",
"<70>", "<71>", "<72>", "<73>", "<74>", "<75>", "<76>", "<77>",
"<78>", "<79>", "<7A>", "<7B>", "<7C>", "<7D>", "<7E>", "<7F>",
};
/*
* Check if a logical unit is a mass storage device.
*/
t_bool isMassStorage(uint16 lu)
{
uint16 extbv4 = M[CREXTB];
uint16 log1a = M[extbv4 + LOG1A];
if ((lu > 0) && (lu <= M[log1a])) {
uint16 physDev = M[log1a + lu];
/*
* Check if equipment class is 2 (Mass storage)
*/
if ((M[physDev + 8] & 0x3800) == 0x1000)
return TRUE;
}
return FALSE;
}
/*
* Get the mass storage sector address associated with a read/write
* request.
*/
uint32 getMSA(uint16 reqCode, uint16 param)
{
if (reqCode == RQ_SYSDIRREAD)
return M[param + 6];
if ((M[param] & D) == 0) {
uint16 sa = M[param + 5];
if ((M[param] & X) == 0) {
if ((sa & 0x8000) != 0) {
sa &= 0x7FFF;
return (M[sa + 1] << 15) | (M[sa + 2] & 0x7FFF);
}
} else {
if ((sa & 0x8000) != 0) {
sa = param + (sa & 0x7FFF);
return (M[sa + 1] << 15) | (M[sa + 2] & 0x7FFF);
}
}
}
return (M[param + 6] << 15) | (M[param + 7] & 0x7FFF);
}
/*
* Parameter conversion routines. Based on the assembly source code of MSOS 5
* available on bitsavers.
*/
/*
* Convert Logical Unit parameter to absolute value
*/
static uint16 luabs(uint16 param, uint16 lu, uint16 a)
{
switch (a) {
case ' ':
break;
case 'R':
if ((lu & 0x200) != 0)
lu |= 0xFC00;
lu = doADDinternal(param, lu);
break;
case 'I':
lu = M[lu];
if ((lu & 0x8000) != 0)
lu = doADDinternal(lu, 0x7FFF);
break;
case 3:
lu = 0xFFFF;
break;
}
return lu;
}
/*
* Convert Starting Address parameter to absolute value
*/
static uint16 spabs(uint16 param)
{
uint16 sa = M[param + 5];
uint16 l, sl = param + 5;
/*
* If the D bit is set, the starting address must be absolute.
*/
if ((M[param] & D) != 0)
return sa;
if ((M[param] & X) == 0) {
if ((sa & 0x8000) != 0)
sa = M[sa & 0x7FFF];
} else {
if ((sa & 0x8000) != 0)
sa = param + (M[param + (sa & 0x7FFF)] & 0x7FFF);
else sa = param + sa;
}
return sa;
}
/*
* Convert Number of words to absolute value
*/
static uint16 npabs(uint16 param)
{
uint16 nw = M[param + 4];
/*
* If the D bit is set, the number of words must be absolute.
*/
if ((M[param] & D) != 0)
return nw;
if ((nw & 0x8000) != 0) {
nw = nw + (((M[param] & X) != 0) ? (param & 0x7FFF) : 0);
if ((nw & 0x8000) != 0)
nw = doADDinternal(nw, 0x7FFF);
nw = M[nw];
if ((nw & 0x8000) != 0)
nw = doADDinternal(nw, 0x7FFF);
}
return nw;
}
/*
* Convert completion address to absolute value
*/
static char *cpabs(uint16 param, char *buf)
{
uint16 ca = M[param + 1];
/*
* Only absolutize the completion address if one is specified.
*/
if (ca != 0) {
/*
* If the D bit is set, the completion address must be absolute.
*/
if ((M[param] & D) == 0) {
if ((ca & 0x8000) != 0) {
/*
* If negative, System directory reference
*/
sprintf(buf, "SYSDIR(%u)", ca & 0x7FFF);
return buf;
} else {
if ((M[param] & X) != 0) {
if ((param & 0x8000) == 0)
param = doADDinternal(param, 0x8000);
ca = doADDinternal(ca, param);
}
}
if ((ca & 0x8000) != 0)
ca = doADDinternal(ca, 0x7FFF);
}
}
sprintf(buf, "$%04X", ca);
return buf;
}
/*
* Describe motion parameters
*/
static void motion(uint16 param, char *d)
{
uint16 commands = M[param + 4];
if ((commands & 0xF) != 0)
sprintf(END(d), " Density = %s\r\n", density[commands & 0xF]);
if ((commands & 0x8000) == 0) {
if ((commands & 0xF000) != 0) {
sprintf(END(d), " Actions = %s", action[(commands & 0xF000) >> 12]);
if ((commands & 0xF00) != 0) {
sprintf(END(d), ",%s", action[(commands & 0xF00) >> 8]);
if ((commands & 0xF0) != 0)
sprintf(END(d), ",%s", action[(commands & 0xF0) >> 4]);
}
sprintf(END(d), "\r\n");
}
} else {
sprintf(END(d), " Repeat = %s, %u times\r\n",
action[(commands & 0x7) >> 12], commands & 0xFFF);
}
}
/*
* Generate a test representation of a write to the console teletype. If the
* text is too long to fix (> 50 chars) it will be truncated.
*/
#define MAXTEXT 50
char *textRep(uint16 start, uint16 len)
{
int i;
static char text[64];
text[0] = '\0';
for (i = 0; i < (2 * len); i++) {
uint16 ch = M[start];
if ((i & 1) == 0)
ch >>= 8;
else start++;
ch &= 0x7F;
strcat(text, charRep[ch]);
if (strlen(text) > MAXTEXT)
break;
}
return text;
}
/*
* Dump MSOS5 request information.
*/
void MSOS5request(uint16 param, uint16 depth)
{
uint16 reqCode = (M[param] & RQ) >> 9;
char partOne = part1[(M[param] & D) >> 14];
char relative = rel[(M[param] & X) >> 8];
uint16 completion = M[param + 1];
const char *request;
char parameters[128], details[512];
char luadr;
uint16 lu, abslu, abss, abswd, i;
uint32 sector;
t_bool secondary = FALSE;
parameters[0] = '\0';
details[0] = '\0';
if (depth == 0) {
/*
* Check for INDIR request with 15-bit addressing.
*/
if ((M[param] & 0x8000) != 0) {
fprintf(DBGOUT, "%sMSOS5(%06u): [RQ: $%04X]%sINDIR $%04X,0\r\n",
INTprefix, seqno++, param, indent[depth & 0x7],
M[param] & 0x7FFF);
MSOS5request(M[param] & 0x7FFF, depth + 1);
return;
}
}
if ((M[param] & 0x8000) != 0) {
/*
* Secondary scheduler call
*/
secondary = TRUE;
reqCode = RQ_SCHDLE;
}
/*
* Check for invalid monitor requests
*/
if (reqCode > RQ_DIRCHD) {
fprintf(DBGOUT, "%sUnknown MSOS5 request (code %u)\r\n",
INTprefix, reqCode);
return;
}
if (queueable[reqCode]) {
char temp[16];
if (secondary)
sprintf(details, " Compl = $%04X\r\n", M[param + 1]);
else sprintf(details, " Compl = %s\r\n", cpabs(param, temp));
}
switch (reqCode) {
case RQ_SYSDIRREAD:
request = "*SYSDIRREAD*";
goto rw;
case RQ_READ:
request = "READ";
goto rw;
case RQ_WRITE:
request = "WRITE";
goto rw;
case RQ_STATUS:
request = "STATUS";
luadr = luchr[(M[param + 1] & 0xC00) >> 10];
lu = M[param + 1] & 0x3FF;
sprintf(parameters, "%u, 0, %c, 0, %c", lu, luadr, partOne);
sprintf(END(details), " LU = %u\r\n", luabs(param, lu, luadr));
break;
case RQ_FREAD:
request = "FREAD";
goto rw;
case RQ_EXIT:
request = "EXIT";
/* No parameters */
break;
case RQ_FWRITE:
request = "FWRITE";
rw:
luadr = luchr[(M[param + 3] & 0xC00) >> 10];
lu = M[param + 3] & 0x3FF;
sprintf(parameters, "%u, $%04X, $%04X, %u, %c, %u, %u, %c, %c, %c",
lu, completion, M[param + 5], M[param + 4],
mode[(M[param + 3] & 0x1000) >> 12],
(M[param] & RP) >> 4, M[param] & CP,
luadr, relative, partOne);
if (reqCode == RQ_SYSDIRREAD) {
abslu = M[LIBLU];
abss = completion;
} else {
abslu = luabs(param, lu, luadr);
abss = spabs(param);
}
abswd = npabs(param);
sprintf(END(details), " LU = %u\r\n", abslu);
sprintf(END(details), " Start = $%04X\r\n", abss);
sprintf(END(details), " Words = %u ($%04X)\r\n", abswd, abswd);
if (isMassStorage(abslu))
sprintf(END(details), " MSA = $%08X\r\n", getMSA(reqCode, param));
/*
* If this a write to the console teletype, generate a partial
* representation of the text being written so that we can correlate
* our current location with the output.
*/
if (abslu == TELETYPE) {
if ((M[param + 3] & 0x1000) != 0) {
if ((reqCode == RQ_WRITE) || (reqCode == RQ_FWRITE)) {
sprintf(END(details), " Text = %s\r\n",
textRep(spabs(param), npabs(param)));
}
}
}
break;
case RQ_LOADER:
request = "LOADER";
sprintf(parameters, "[A: %04X, Q: %04X, lu: %u, t: %u, tna: %04X]",
Areg, Qreg, (Areg & 0xFFF0) >> 4, Areg & 0xF, Qreg);
break;
case RQ_TIMER:
request = "TIMER";
sprintf(parameters, "$%04X, %u, %c, %u, %c, %c",
M[param + 1], M[param] & 0xF,
relative, M[param + 2],
units[(M[param] & 0xF0) >> 4], partOne);
break;
case RQ_SCHDLE:
request = secondary ? "Secondary SCHDLE" : "SCHDLE";
sprintf(parameters, "$%04X, %u, %c, %c",
M[param + 1], M[param] & CP, relative, partOne);
break;
case RQ_SPACE:
request = "SPACE";
sprintf(parameters, "%u, $%04X, %u, %u, %c, %c",
M[param + 4], M[param + 1],
(M[param] & RP) >> 4, M[param] & CP, relative, partOne);
break;
case RQ_CORE:
request = "CORE";
sprintf(parameters, "[A: %04X, Q: %04X]", Areg, Qreg);
break;
case RQ_RELEAS:
request = "RELEAS";
sprintf(parameters, "$%04X, %c, %c, %c",
M[param + 1], exitind[M[param] & 0x01], relative, partOne);
break;
case RQ_GTFILE:
request = "GTFILE";
sprintf(parameters, "$%04X, $%04X, $%04X, $%04X, $%04X, %c, %u, %u, %c",
M[param + 1], M[param + 7], M[param + 5],
M[param + 4], M[param + 6], relative,
(M[param] & RP) >> 4, M[param] & CP, partOne);
/*
* The reference manual does not correctly document the GTFILE request.
* According to the MSOS 5.0 source code, there is a 10th parameter
* which is used in calculating the address of the name block.
*/
i = M[param + 7];
if ((i & 0x8000) == 0) {
i = doADDinternal(M[param + 10], i);
if ((M[param] & D) == 0) {
i = doADDinternal(i, 0x8000);
i &= 0x7FFF;
}
} else i &= 0x7FFF;
sector = (M[param + 8] << 16) | M[param + 9];
if (sector != 0)
sprintf(END(details), " Sector = %u\r\n", sector);
else sprintf(END(details), " Name = %c%c%c%c%c%c\r\n",
(M[i] >> 8) & 0xFF, M[i] & 0xFF,
(M[i + 1] >> 8) & 0xFF, M[i + 1] & 0xFF,
(M[i + 2] >> 8) & 0xFF, M[i + 2] & 0xFF);
break;
case RQ_MOTION:
request = "MOTION";
luadr = luchr[(M[param + 3] & 0xC00) >> 10];
lu = M[param + 3] & 0x3FF;
sprintf(parameters, "%u, $%04X, %u, %u, %u, %u, %u, %u, %c, %c, %c, %c",
lu, M[param + 1],
(M[param + 4] & 0xF000) >> 12,
(M[param + 4] & 0xF00) >> 8,
(M[param + 4] & 0xF0) >> 4, M[param + 4] & 0xF,
(M[param] & RP) >> 4, M[param] & CP,
luadr, relative, partOne,
mode[(M[param + 3] & 0x1000) >> 12]);
sprintf(END(details), " LU = %u\r\n", luabs(param, lu, luadr));
motion(param, details);
break;
case RQ_TIMPT1:
request = "TIMPT1";
sprintf(parameters, "$%04X, %u, 0, %u, %c",
M[param + 1], M[param] & 0xF,
M[param + 2], units[(M[param] & 0xF0) >> 4]);
break;
case RQ_INDIR:
fprintf(DBGOUT, "%sMSOS5(%06u): [RQ: $%04X]%sINDIR $%04X,1\r\n",
INTprefix, seqno++, param, indent[depth & 0x7], M[param + 1]);
MSOS5request(M[param + 1], depth + 1);
return;
case RQ_PTNCOR:
request = "PTNCOR";
sprintf(parameters, "%u, $%04X, %u, %u, %u, %c, %c",
M[param + 4], M[param + 1], M[param + 5],
(M[param] & RP) >> 4, M[param] & CP,
relative, partOne);
break;
case RQ_SYSCHD:
request = "SYSCHD";
sprintf(parameters, "$%04X, %u",
M[param + 1], M[param & 0xF]);
break;
case RQ_DIRCHD:
switch (M[param] & 0xFF) {
case 0:
request = "ENSCHD";
sprintf(parameters, "$%04X", M[param + 1]);
break;
case 0xFF:
request = "DISCHD";
sprintf(parameters, "$%04X", M[param + 1]);
break;
default:
request = "SYSCHD";
strcpy(parameters, "Invalid directory scheduling code");
break;
}
default:
request = "*Unknown*";
sprintf(parameters, "Request code: %d", (M[param] & 0x3E00) >> 9);
break;
}
done:
fprintf(DBGOUT, "%sMSOS5(%06u): [RQ: $%04X]%s%s %s\r\n",
INTprefix, seqno++, param, indent[depth & 0x7], request, parameters);
if (details[0] != '\0')
fprintf(DBGOUT, "%s\r\n", details);
}

View file

@ -1,6 +1,6 @@
/*
Copyright (c) 2015-2016, John Forecast
Copyright (c) 2015-2017, John Forecast
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -718,7 +718,7 @@ void mt_dump(void)
char msg[80], text[16];
if (MTremain > 0) {
printf("Dump of MTbuf:\r\n");
fprintf(DBGOUT, "Dump of MTbuf:\r\n");
while (count > 0) {
t_mtrlnt remain = count >= 10 ? 10 : count;
@ -738,7 +738,7 @@ void mt_dump(void)
}
text[remain] = '\0';
printf("%-55s%s\r\n", msg, text);
fprintf(DBGOUT, "%-55s%s\r\n", msg, text);
count -= remain;
}
@ -849,7 +849,7 @@ t_stat mt_show_transport(FILE *st, UNIT *uptr, int32 val, CONST void *desc)
*/
int32 mt_densityTimeout(t_bool loose)
{
int32 result;
int32 result = MT_200_WAIT;
switch (MTdev.STATUS2 & (IO_ST2_556 | IO_ST2_800)) {
case 0:

View file

@ -80,7 +80,7 @@ static const char *opcode[] = {
"CAQ", "CAB", "INA", "ENA",
"NOP", "ENQ", "INQ", "EXI",
"QRS", "ARS", "LRS", "QLS",
"ALS", "LLS",
"ALS", "LLS", "ECA", "DCA",
NULL
};
@ -103,7 +103,7 @@ static const int32 opc_val[] = {
OPC_CAQ + I_INTER, OPC_CAB + I_INTER, OPC_INA + I_REG + I_SIGNED, OPC_ENA + I_REG + I_SIGNED,
OPC_NOP + I_NOARG, OPC_ENQ + I_REG + I_SIGNED, OPC_INQ + I_REG + I_SIGNED, OPC_EXI + I_REG + I_ABS,
OPC_QRS + I_SHIFT, OPC_ARS + I_SHIFT, OPC_LRS + I_SHIFT, OPC_QLS + I_SHIFT,
OPC_ALS + I_SHIFT, OPC_LLS + I_SHIFT,
OPC_ALS + I_SHIFT, OPC_LLS + I_SHIFT, OPC_ECA + I_NOARG, OPC_DCA + I_NOARG
};
/*

View file

@ -224,6 +224,10 @@
RelativePath="..\CDC1700\cdc1700_lp.c"
>
</File>
<File
RelativePath="..\CDC1700\cdc1700_msos5.c"
>
</File>
<File
RelativePath="..\CDC1700\cdc1700_mt.c"
>

View file

@ -686,7 +686,7 @@ CDC1700_SOURCE = $(CDC1700_DIR)CDC1700_CPU.C,$(CDC1700_DIR)CDC1700_DIS.C,$(CDC17
$(CDC1700_DIR)CDC1700_SYS.C,$(CDC1700_DIR)CDC1700_DEV1.C,$(CDC1700_DIR)CDC1700_MT.C,\
$(CDC1700_DIR)CDC1700_DC.C,$(CDC1700_DIR)CDC1700_IOFW.C,$(CDC1700_DIR)CDC1700_LP.C,\
$(CDC1700_DIR)CDC1700_DP.C,$(CDC1700_DIR)CDC1700_CD.C,$(CDC1700_DIR)CDC1700_SYM.C,\
$(CDC1700_DIR)CDC1700_RTC.C
$(CDC1700_DIR)CDC1700_RTC.C $(CDC1700_DIR)CDC1700_MSOS5.C
CDC1700_OPTIONS = /INCL=($(SIMH_DIR),$(CDC1700_DIR))/DEF=($(CC_DEFS))
#

View file

@ -1497,7 +1497,7 @@ CDC1700 = ${CDC1700D}/cdc1700_cpu.c ${CDC1700D}/cdc1700_dis.c \
${CDC1700D}/cdc1700_dc.c ${CDC1700D}/cdc1700_iofw.c \
${CDC1700D}/cdc1700_lp.c ${CDC1700D}/cdc1700_dp.c \
${CDC1700D}/cdc1700_cd.c ${CDC1700D}/cdc1700_sym.c \
${CDC1700D}/cdc1700_rtc.c
${CDC1700D}/cdc1700_rtc.c ${CDC1700D}/cdc1700_msos5.c
CDC1700_OPT = -I ${CDC1700D}
###