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:
parent
ca19ac921c
commit
df1baf2528
14 changed files with 2083 additions and 723 deletions
File diff suppressed because it is too large
Load diff
|
@ -45,8 +45,8 @@ mostly from the early period of its release:
|
||||||
|
|
||||||
MT 1732-A or 1732-3 Magtape controller, 3 9-track drives
|
MT 1732-A or 1732-3 Magtape controller, 3 9-track drives
|
||||||
(MT0 - MT2) and 1 7-track drive (MT3). The type of
|
(MT0 - MT2) and 1 7-track drive (MT3). The type of
|
||||||
the controller may be chaged using the command
|
the controller may be changed using the command
|
||||||
"set mt type={1732-a|1732-3}". The 1732-A controller
|
"set mt type={1732-A|1732-3}". The 1732-A controller
|
||||||
supports 200, 556 and 800 BPI on the 9 track drives
|
supports 200, 556 and 800 BPI on the 9 track drives
|
||||||
and allows DMA access via a 1706 Buffered Data
|
and allows DMA access via a 1706 Buffered Data
|
||||||
Channel (device DCA). The 1733-3 controller supports
|
Channel (device DCA). The 1733-3 controller supports
|
||||||
|
|
|
@ -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
|
Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
copy of this software and associated documentation files (the "Software"),
|
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 CD856_4_SIZE (CD_SURF * CD_856_4CY * CD_NUMSC * CD_NUMBY)
|
||||||
|
|
||||||
#define CDLBA(i) \
|
#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
|
* Disk address fields
|
||||||
|
@ -362,7 +362,7 @@ REG cd_reg[] = {
|
||||||
MTAB cd_mod[] = {
|
MTAB cd_mod[] = {
|
||||||
{ MTAB_XTD|MTAB_VDV, 0, "1733-2 Cartridge Disk Drive Controller" },
|
{ MTAB_XTD|MTAB_VDV, 0, "1733-2 Cartridge Disk Drive Controller" },
|
||||||
{ MTAB_XTD|MTAB_VDV, 0, "EQUIPMENT", "EQUIPMENT=hexAddress",
|
{ 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,
|
{ MTAB_XTD|MTAB_VUN, 0, "DRIVE", NULL,
|
||||||
NULL, &show_drive, NULL, "Display type of drive (856-2 or 856-4)" },
|
NULL, &show_drive, NULL, "Display type of drive (856-2 or 856-4)" },
|
||||||
{ MTAB_XTD|MTAB_VUN, 0, NULL, "856-2",
|
{ MTAB_XTD|MTAB_VUN, 0, NULL, "856-2",
|
||||||
|
@ -383,7 +383,7 @@ MTAB cd_mod[] = {
|
||||||
{ MTAB_XTD|MTAB_VDV, 0, NULL, "CARTFIRST",
|
{ MTAB_XTD|MTAB_VDV, 0, NULL, "CARTFIRST",
|
||||||
&set_cartfirst, NULL, NULL, "Set cartridge as logical disk 0" },
|
&set_cartfirst, NULL, NULL, "Set cartridge as logical disk 0" },
|
||||||
{ MTAB_XTD|MTAB_VDV, 0, NULL, "FIXEDFIRST",
|
{ 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 }
|
{ 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -663,10 +663,32 @@ static void StartCDDiskIO(UNIT *uptr, struct cdio_unit *iou, uint16 state)
|
||||||
|
|
||||||
fw_IOunderwayEOP2(&CDdev, 0);
|
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,
|
fprintf(DBGOUT,
|
||||||
"%sCD - Start I/O, cur: %04X, len: %04X, state: %s\r\n",
|
"%sCD - Start I/O, drive: %s, disk: %s, cur: %04X, len: %04X, state: %s\r\n",
|
||||||
INTprefix, CDdev.CWA, CDdev.BUFLEN, CDstateStr[state]);
|
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;
|
CDdev.DCYLSTATUS &= ~iou->seekComplete;
|
||||||
|
|
||||||
|
@ -709,8 +731,13 @@ static enum cdio_status CDDiskIORead(UNIT *uptr)
|
||||||
CDdev.DCYLSTATUS &= ~CD_CYL_MASK;
|
CDdev.DCYLSTATUS &= ~CD_CYL_MASK;
|
||||||
CDdev.DCYLSTATUS |= (iou->cylinder << CD_CYL_SHIFT);
|
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++) {
|
for (i = 0; i < CD_NUMWD; i++) {
|
||||||
/*** TODO: fix protect check ***/
|
/*** TODO: fix protect check ***/
|
||||||
|
@ -752,8 +779,14 @@ static enum cdio_status CDDiskIOWrite(UNIT *uptr)
|
||||||
CDdev.DCYLSTATUS &= ~CD_CYL_MASK;
|
CDdev.DCYLSTATUS &= ~CD_CYL_MASK;
|
||||||
CDdev.DCYLSTATUS |= (iou->cylinder << CD_CYL_SHIFT);
|
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);
|
CDDiskIOIncSector(iou);
|
||||||
return fill ? CDIO_DONE : CDIO_MORE;
|
return fill ? CDIO_DONE : CDIO_MORE;
|
||||||
}
|
}
|
||||||
|
@ -773,8 +806,13 @@ static enum cdio_status CDDiskIOCompare(UNIT *uptr)
|
||||||
CDdev.DCYLSTATUS &= ~CD_CYL_MASK;
|
CDdev.DCYLSTATUS &= ~CD_CYL_MASK;
|
||||||
CDdev.DCYLSTATUS |= (iou->cylinder << CD_CYL_SHIFT);
|
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++) {
|
for (i = 0; i < CD_NUMWD; i++) {
|
||||||
if (iou->buf[i] != LoadFromMem(CDdev.CWA))
|
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;
|
struct cdio_unit *iou = (struct cdio_unit *)uptr->up7;
|
||||||
const char *error = "Unknown";
|
const char *error = "Unknown";
|
||||||
enum cdio_status status;
|
enum cdio_status status = CDIO_ADDRERR;
|
||||||
|
|
||||||
switch (iotype) {
|
switch (iotype) {
|
||||||
case CD_WRITE:
|
case CD_WRITE:
|
||||||
|
@ -1023,7 +1061,7 @@ static t_stat CDreset(DEVICE *dptr)
|
||||||
|
|
||||||
t_stat cd_reset(DEVICE *dptr)
|
t_stat cd_reset(DEVICE *dptr)
|
||||||
{
|
{
|
||||||
t_stat r;
|
t_stat r = SCPE_OK;
|
||||||
|
|
||||||
if (IOFWinitialized)
|
if (IOFWinitialized)
|
||||||
if ((dptr->flags & DEV_DIS) == 0)
|
if ((dptr->flags & DEV_DIS) == 0)
|
||||||
|
@ -1326,8 +1364,8 @@ t_stat CDautoload(void)
|
||||||
t_offset offset = i * CD_NUMBY;
|
t_offset offset = i * CD_NUMBY;
|
||||||
void * buf = &M[i * CD_NUMWD];
|
void * buf = &M[i * CD_NUMWD];
|
||||||
|
|
||||||
sim_fseeko(uptr->fileref, offset, SEEK_SET);
|
if (sim_fseeko(uptr->fileref, offset, SEEK_SET) ||
|
||||||
if (sim_fread(buf, sizeof(uint16), CD_NUMWD, uptr->fileref) != CD_NUMWD)
|
(sim_fread(buf, sizeof(uint16), CD_NUMWD, uptr->fileref) != CD_NUMWD))
|
||||||
return SCPE_IOERR;
|
return SCPE_IOERR;
|
||||||
}
|
}
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
|
|
|
@ -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
|
Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
copy of this software and associated documentation files (the "Software"),
|
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
|
* 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
|
* "End of Operation"? A channel-specific interrupt or a pass-through
|
||||||
* interrupt from the device being controlled or some other?
|
* 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"
|
#include "cdc1700_defs.h"
|
||||||
|
@ -97,6 +137,13 @@ uint32 CountRejects = 0;
|
||||||
|
|
||||||
t_bool FirstAddr = TRUE;
|
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 int disassem(char *, uint16, t_bool, t_bool, t_bool);
|
||||||
|
|
||||||
extern enum IOstatus doIO(t_bool, DEVICE **);
|
extern enum IOstatus doIO(t_bool, DEVICE **);
|
||||||
|
@ -105,6 +152,9 @@ extern void rebuildPending(void);
|
||||||
|
|
||||||
extern void dev1Interrupts(char *);
|
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_reset(DEVICE *);
|
||||||
t_stat cpu_set_size(UNIT *, int32, CONST char *, void *);
|
t_stat cpu_set_size(UNIT *, int32, CONST char *, void *);
|
||||||
t_stat cpu_ex(t_value *, t_addr, UNIT *, int32);
|
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_MODE65K (1 << UNIT_V_MODE65K)
|
||||||
#define UNIT_V_CHAR (UNIT_V_UF + 4) /* Character addressing */
|
#define UNIT_V_CHAR (UNIT_V_UF + 4) /* Character addressing */
|
||||||
#define UNIT_CHAR (1 << UNIT_V_CHAR)
|
#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_PROT (1 << UNIT_V_PROT)
|
||||||
#define UNIT_V_MSIZE (UNIT_V_UF + 6) /* Memory size */
|
#define UNIT_V_MSIZE (UNIT_V_UF + 6) /* Memory size */
|
||||||
#define UNIT_MSIZE (1 << UNIT_V_MSIZE)
|
#define UNIT_MSIZE (1 << UNIT_V_MSIZE)
|
||||||
|
@ -154,6 +204,8 @@ REG cpu_reg[] = {
|
||||||
|
|
||||||
MTAB cpu_mod[] = {
|
MTAB cpu_mod[] = {
|
||||||
{ MTAB_XTD|MTAB_VDV, 0, "1714 CDC 1700 series CPU", NULL, NULL, NULL },
|
{ 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",
|
{ UNIT_STOPSW, UNIT_STOPSW, "Selective Stop", "SSTOP",
|
||||||
NULL, NULL, NULL, "Enable Selective Stop" },
|
NULL, NULL, NULL, "Enable Selective Stop" },
|
||||||
{ UNIT_STOPSW, 0, "No Selective Stop", "NOSSTOP",
|
{ UNIT_STOPSW, 0, "No Selective Stop", "NOSSTOP",
|
||||||
|
@ -166,10 +218,10 @@ MTAB cpu_mod[] = {
|
||||||
NULL, NULL, NULL, "Enable 65K Indirect Addressing Mode" },
|
NULL, NULL, NULL, "Enable 65K Indirect Addressing Mode" },
|
||||||
{ UNIT_MODE65K, 0, "32K Addressing Mode", "MODE32K",
|
{ UNIT_MODE65K, 0, "32K Addressing Mode", "MODE32K",
|
||||||
NULL, NULL, NULL, "Enable 32K Indirect Addressing Mode" },
|
NULL, NULL, NULL, "Enable 32K Indirect Addressing Mode" },
|
||||||
{ UNIT_CHAR, UNIT_CHAR, "Character Addressing", "CHAR",
|
{ UNIT_CHAR, UNIT_CHAR, NULL, "CHAR",
|
||||||
NULL, NULL, NULL, "Enable Character Addressing Mode" },
|
NULL, NULL, NULL, "Enable Character Addressing Extensions" },
|
||||||
{ UNIT_CHAR, 0, "No Character Addressing", "NOCHAR",
|
{ UNIT_CHAR, 0, NULL, "NOCHAR",
|
||||||
NULL, NULL, NULL, "Disable Character Addressing Mode" },
|
NULL, NULL, NULL, "Disable Character Addressing Extensions" },
|
||||||
{ UNIT_PROT, UNIT_PROT, "Program Protect", "PROTECT",
|
{ UNIT_PROT, UNIT_PROT, "Program Protect", "PROTECT",
|
||||||
NULL, NULL, NULL, "Enable Protect Mode Operation" },
|
NULL, NULL, NULL, "Enable Protect Mode Operation" },
|
||||||
{ UNIT_PROT, 0, "", "NOPROTECT",
|
{ UNIT_PROT, 0, "", "NOPROTECT",
|
||||||
|
@ -205,7 +257,9 @@ DEBTAB cpu_deb[] = {
|
||||||
{ "INTLVL", DBG_INTLVL, "Add interrupt level to all displays" },
|
{ "INTLVL", DBG_INTLVL, "Add interrupt level to all displays" },
|
||||||
{ "PROTECT", DBG_PROTECT, "Display protect faults" },
|
{ "PROTECT", DBG_PROTECT, "Display protect faults" },
|
||||||
{ "MISSING", DBG_MISSING, "Display info about missing devices" },
|
{ "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 }
|
{ NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -259,6 +313,45 @@ static uint16 interruptBit[] = {
|
||||||
0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000, 0x8000
|
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
|
* Reset routine
|
||||||
*/
|
*/
|
||||||
|
@ -421,7 +514,7 @@ uint16 LoadFromMem(uint16 addr)
|
||||||
*/
|
*/
|
||||||
t_bool StoreToMem(uint16 addr, uint16 value)
|
t_bool StoreToMem(uint16 addr, uint16 value)
|
||||||
{
|
{
|
||||||
if ((cpu_unit.flags & UNIT_PROT) != 0) {
|
if (inProtectedMode()) {
|
||||||
if (!Protected) {
|
if (!Protected) {
|
||||||
if (P[MEMADDR(addr)]) {
|
if (P[MEMADDR(addr)]) {
|
||||||
if ((cpu_dev.dctrl & DBG_PROTECT) != 0) {
|
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)
|
t_bool IOStoreToMem(uint16 addr, uint16 value, t_bool prot)
|
||||||
{
|
{
|
||||||
if ((cpu_unit.flags & UNIT_PROT) != 0) {
|
if (inProtectedMode()) {
|
||||||
if (!prot) {
|
if (!prot) {
|
||||||
if (P[MEMADDR(addr)]) {
|
if (P[MEMADDR(addr)]) {
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
@ -550,13 +643,26 @@ void doDIV(uint16 a)
|
||||||
sign++;
|
sign++;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The documentation does not specify the result of a divide by zero.
|
* Handle divide by 0 (plus or minus) as documented in the 1784 reference
|
||||||
* Hopefully, the diagnostics will provide some insight. Until then we
|
* manual.
|
||||||
* just set the overflow flag and return saturated positive values.
|
|
||||||
*/
|
*/
|
||||||
if (divisor == 0) {
|
if (divisor == 0) {
|
||||||
Oflag = 1;
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -581,12 +687,11 @@ void doDIV(uint16 a)
|
||||||
if ((result & 0xFFFF8000) != 0)
|
if ((result & 0xFFFF8000) != 0)
|
||||||
Oflag = 1;
|
Oflag = 1;
|
||||||
|
|
||||||
if ((result & 0x7FFF) != 0)
|
if ((sign & 1) != 0)
|
||||||
if ((sign & 1) != 0)
|
result = ~result;
|
||||||
result = ~result;
|
|
||||||
if ((remainder & 0x7FFF) != 0)
|
if (rsign != 0)
|
||||||
if (rsign != 0)
|
remainder = ~remainder;
|
||||||
remainder = ~remainder;
|
|
||||||
|
|
||||||
Areg = TRUNC16(result);
|
Areg = TRUNC16(result);
|
||||||
Qreg = TRUNC16(remainder);
|
Qreg = TRUNC16(remainder);
|
||||||
|
@ -879,26 +984,30 @@ t_stat executeAnInstruction(void)
|
||||||
* Check for protected mode operation where we are about to execute a
|
* Check for protected mode operation where we are about to execute a
|
||||||
* protected instruction and the previous instruction was unprotected.
|
* protected instruction and the previous instruction was unprotected.
|
||||||
*/
|
*/
|
||||||
if ((cpu_unit.flags & UNIT_PROT) != 0) {
|
if (inProtectedMode()) {
|
||||||
if (!lastP && Protected) {
|
if (!lastP && Protected) {
|
||||||
if ((cpu_dev.dctrl & DBG_PROTECT) != 0) {
|
if ((cpu_dev.dctrl & DBG_PROTECT) != 0) {
|
||||||
fprintf(DBGOUT,
|
fprintf(DBGOUT,
|
||||||
"%sProtect fault, unprotected after protected at %04X\r\n",
|
"%sProtect fault, protected after unprotected at %04X\r\n",
|
||||||
INTprefix, OrigPreg);
|
INTprefix, OrigPreg);
|
||||||
}
|
}
|
||||||
Pfault = TRUE;
|
Pfault = TRUE;
|
||||||
RaiseInternalInterrupt();
|
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) {
|
if ((cpu_unit.flags & UNIT_STOPSW) != 0) {
|
||||||
dumpRegisters();
|
dumpRegisters();
|
||||||
|
@ -1052,9 +1161,32 @@ t_stat executeAnInstruction(void)
|
||||||
case OPC_SPECIAL:
|
case OPC_SPECIAL:
|
||||||
switch (instr & OPC_SPECIALMASK) {
|
switch (instr & OPC_SPECIALMASK) {
|
||||||
case OPC_SLS:
|
case OPC_SLS:
|
||||||
if ((cpu_unit.flags & UNIT_STOPSW) != 0) {
|
switch (INSTR_SET) {
|
||||||
dumpRegisters();
|
case INSTR_BASIC:
|
||||||
return SCPE_SSTOP;
|
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;
|
break;
|
||||||
|
|
||||||
|
@ -1143,6 +1275,8 @@ t_stat executeAnInstruction(void)
|
||||||
case OPC_SNF:
|
case OPC_SNF:
|
||||||
if (!Pfault)
|
if (!Pfault)
|
||||||
Preg = doADDinternal(Preg, instr & OPC_SKIPCOUNT);
|
Preg = doADDinternal(Preg, instr & OPC_SKIPCOUNT);
|
||||||
|
Pfault = FALSE;
|
||||||
|
rebuildPending();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -1251,36 +1385,64 @@ t_stat executeAnInstruction(void)
|
||||||
}
|
}
|
||||||
break;
|
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)
|
* The following instructions (EIN, IIN, SPB, CPB and EXI)
|
||||||
* generate a protect fault if the protect switch is set and
|
* generate a protect fault if the protect switch is set and
|
||||||
* the instruction is not protected. If the system is unable
|
* the instruction is not protected. If the system is unable
|
||||||
* to handle the interrupt (interrupts disabled or interrupt 0
|
* to handle the interrupt (interrupts disabled or interrupt 0
|
||||||
* masked), the instruction executes as a "Selective Stop". Note
|
* masked), the instruction executes as a "Selective Stop".
|
||||||
* that the character addressing instructions are a subset
|
|
||||||
* of IIN and have to be checked separately.
|
|
||||||
*/
|
*/
|
||||||
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:
|
case OPC_EXI:
|
||||||
if ((cpu_unit.flags & UNIT_PROT) != 0) {
|
if (inProtectedMode()) {
|
||||||
if (!Protected) {
|
if (!Protected) {
|
||||||
if ((cpu_dev.dctrl & DBG_PROTECT) != 0) {
|
if ((cpu_dev.dctrl & DBG_PROTECT) != 0) {
|
||||||
fprintf(DBGOUT,
|
fprintf(DBGOUT,
|
||||||
|
@ -1322,7 +1484,20 @@ t_stat executeAnInstruction(void)
|
||||||
INTprefix, Areg, Qreg, Mreg, Oflag, INTflag, DEFERflag);
|
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;
|
INTflag = 0;
|
||||||
|
done:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OPC_SPB:
|
case OPC_SPB:
|
||||||
|
@ -1366,7 +1541,7 @@ t_stat executeAnInstruction(void)
|
||||||
* Protection fault if the instruction is not protected and
|
* Protection fault if the instruction is not protected and
|
||||||
* modifies M
|
* modifies M
|
||||||
*/
|
*/
|
||||||
if ((cpu_unit.flags & UNIT_PROT) != 0) {
|
if (inProtectedMode()) {
|
||||||
if ((instr & MOD_D_M) != 0) {
|
if ((instr & MOD_D_M) != 0) {
|
||||||
if (!Protected) {
|
if (!Protected) {
|
||||||
if ((cpu_dev.dctrl & DBG_PROTECT) != 0) {
|
if ((cpu_dev.dctrl & DBG_PROTECT) != 0) {
|
||||||
|
@ -1446,6 +1621,24 @@ t_stat executeAnInstruction(void)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OPC_NOP:
|
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;
|
break;
|
||||||
|
|
||||||
case OPC_ENQ:
|
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"
|
" 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"
|
" The amount of memory available to the system can be changed with:\n\n"
|
||||||
"+sim> SET CPU nK\n\n"
|
"+sim> SET CPU nK\n\n"
|
||||||
" The original 1700 series CPU (the 1704) only allowed up to 32KW to be\n"
|
" The original 1700 series CPU (the 1704) only allowed up to 32KW of\n"
|
||||||
" attached to the CPU and indirect memory references would continue to\n"
|
"to be attached to the CPU and indirect memory references would continue\n"
|
||||||
" loop through memory if bit 15 of the target address was set. When 64KW\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"
|
" 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"
|
" so that the entire 16-bits of address could be used. Systems which\n"
|
||||||
" addressing mode may be changed by:\n\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 MODE32K\n"
|
||||||
"+sim> SET CPU MODE65K\n\n"
|
"+sim> SET CPU MODE65K\n\n"
|
||||||
" In 32KW addressing mode, the number of indirect address chaining\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"
|
" reserve interrupt 0 (and therefore equipment address 0) for parity\n"
|
||||||
" errors (never detected by the simulator), protect faults and power fail\n"
|
" errors (never detected by the simulator), protect faults and power fail\n"
|
||||||
" (not supported by the simulator).\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 $Registers\n"
|
||||||
"2 Front Panel Switches\n"
|
"2 Front Panel Switches\n"
|
||||||
" The 1714 front panel includes a number of switches which control the\n"
|
" The 1714 front panel includes a number of switches which control the\n"
|
||||||
|
|
|
@ -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
|
Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
copy of this software and associated documentation files (the "Software"),
|
copy of this software and associated documentation files (the "Software"),
|
||||||
|
@ -312,7 +312,7 @@ t_stat dc_svc(UNIT *uptr)
|
||||||
{
|
{
|
||||||
DEVICE *dptr;
|
DEVICE *dptr;
|
||||||
enum IOstatus status;
|
enum IOstatus status;
|
||||||
uint16 temp;
|
uint16 temp = 0;
|
||||||
|
|
||||||
if ((dptr = find_dev_from_unit(uptr)) != NULL) {
|
if ((dptr = find_dev_from_unit(uptr)) != NULL) {
|
||||||
IO_DEVICE *iod = (IO_DEVICE *)dptr->ctxt;
|
IO_DEVICE *iod = (IO_DEVICE *)dptr->ctxt;
|
||||||
|
|
|
@ -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
|
Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
copy of this software and associated documentation files (the "Software"),
|
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_INTLVL 9 /* Prefix with interrupt level */
|
||||||
#define DBG_V_PROTECT 10 /* Display protect fault information */
|
#define DBG_V_PROTECT 10 /* Display protect fault information */
|
||||||
#define DBG_V_MISSING 11 /* Display access to missing devices */
|
#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_DISASS (1 << DBG_V_DISASS)
|
||||||
#define DBG_IDISASS (1 << DBG_V_IDISASS)
|
#define DBG_IDISASS (1 << DBG_V_IDISASS)
|
||||||
|
@ -94,6 +97,8 @@
|
||||||
#define DBG_INTLVL (1 << DBG_V_INTLVL)
|
#define DBG_INTLVL (1 << DBG_V_INTLVL)
|
||||||
#define DBG_PROTECT (1 << DBG_V_PROTECT)
|
#define DBG_PROTECT (1 << DBG_V_PROTECT)
|
||||||
#define DBG_MISSING (1 << DBG_V_MISSING)
|
#define DBG_MISSING (1 << DBG_V_MISSING)
|
||||||
|
#define DBG_ENH (1 << DBG_V_ENH)
|
||||||
|
#define DBG_MSOS5 (1 << DBG_V_MSOS5)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Default device radix
|
* Default device radix
|
||||||
|
@ -117,6 +122,14 @@
|
||||||
/*
|
/*
|
||||||
* CPU
|
* 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 MAXMEMSIZE 65536
|
||||||
#define DEFAULTMEMSIZE 32768
|
#define DEFAULTMEMSIZE 32768
|
||||||
|
|
||||||
|
@ -202,8 +215,6 @@ enum IOstatus {
|
||||||
#define MOD_I1 0x200
|
#define MOD_I1 0x200
|
||||||
#define MOD_I2 0x100
|
#define MOD_I2 0x100
|
||||||
|
|
||||||
#define ISCONSTANT(i) ((i & (MOD_RE | MOD_IN | 0xFF)) == 0)
|
|
||||||
|
|
||||||
#define OPC_MASK 0xF000
|
#define OPC_MASK 0xF000
|
||||||
#define OPC_ADQ 0xF000
|
#define OPC_ADQ 0xF000
|
||||||
#define OPC_LDQ 0xE000
|
#define OPC_LDQ 0xE000
|
||||||
|
@ -296,9 +307,9 @@ enum IOstatus {
|
||||||
#define OPC_EXI 0x0E00
|
#define OPC_EXI 0x0E00
|
||||||
|
|
||||||
#define OPC_MODMASK 0x00FF
|
#define OPC_MODMASK 0x00FF
|
||||||
#define EXTEND16(v) ((v) & 0x8000) ? (v) | 0xFFFF0000 : (v)
|
#define EXTEND16(v) (((v) & 0x8000) ? (v) | 0xFFFF0000 : (v))
|
||||||
#define EXTEND8(v) ((v) & 0x80) ? (v) | 0xFF00 : (v)
|
#define EXTEND8(v) (((v) & 0x80) ? (v) | 0xFF00 : (v))
|
||||||
#define EXTEND4(v) ((v) & 0x8) ? (v) | 0xFFF0 : (v)
|
#define EXTEND4(v) (((v) & 0x8) ? (v) | 0xFFF0 : (v))
|
||||||
#define TRUNC16(v) ((v) & 0xFFFF)
|
#define TRUNC16(v) ((v) & 0xFFFF)
|
||||||
#define CANEXTEND8(v) (((v) & 0xFF80) == 0xFF80)
|
#define CANEXTEND8(v) (((v) & 0xFF80) == 0xFF80)
|
||||||
|
|
||||||
|
@ -308,7 +319,6 @@ enum IOstatus {
|
||||||
#define MOD_S_A 0x40
|
#define MOD_S_A 0x40
|
||||||
#define MOD_S_Q 0x20
|
#define MOD_S_Q 0x20
|
||||||
#define OPC_SHIFTCOUNT 0x001F
|
#define OPC_SHIFTCOUNT 0x001F
|
||||||
#define OPC_ADDRMASK 0x00FF
|
|
||||||
|
|
||||||
#define OPC_QRS (OPC_SHIFTS | MOD_S_Q)
|
#define OPC_QRS (OPC_SHIFTS | MOD_S_Q)
|
||||||
#define OPC_ARS (OPC_SHIFTS | MOD_S_A)
|
#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_ALS (OPC_SHIFTS | MOD_LR | MOD_S_A)
|
||||||
#define OPC_LLS (OPC_SHIFTS | MOD_LR | MOD_S_A | MOD_S_Q)
|
#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
|
* Interrupt vector definitions
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -99,21 +99,20 @@ int disassem(char *buf, uint16 addr, t_bool dbg, t_bool targ, t_bool exec)
|
||||||
{
|
{
|
||||||
int consumed = 1;
|
int consumed = 1;
|
||||||
char prot = ISPROTECTED(addr) ? 'P' : ' ';
|
char prot = ISPROTECTED(addr) ? 'P' : ' ';
|
||||||
char mode[8], optional[8], temp[8], decoded[64];
|
char optional[8], temp[8], decoded[64];
|
||||||
const char *spc, *shift, *inter, *dest;
|
const char *mode, *spc, *shift, *inter, *dest;
|
||||||
uint16 instr = LoadFromMem(addr);
|
uint16 instr = LoadFromMem(addr);
|
||||||
uint16 delta = instr & OPC_ADDRMASK;
|
uint16 delta = instr & OPC_ADDRMASK;
|
||||||
|
uint8 more = 0, isconst = 0;
|
||||||
uint16 t;
|
uint16 t;
|
||||||
|
|
||||||
strcpy(optional, " ");
|
strcpy(optional, " ");
|
||||||
strcpy(decoded, "UNDEF");
|
strcpy(decoded, "UNDEF");
|
||||||
|
|
||||||
if ((instr & OPC_MASK) != 0) {
|
if ((instr & OPC_MASK) != 0) {
|
||||||
strcpy(decoded, opName[(instr & OPC_MASK) >> 12]);
|
|
||||||
|
|
||||||
if ((instr & MOD_RE) == 0)
|
if ((instr & MOD_RE) == 0)
|
||||||
strcpy(mode, delta == 0 ? "+ " : "- ");
|
mode = delta == 0 ? "+ " : "- ";
|
||||||
else strcpy(mode, "* ");
|
else mode = "* ";
|
||||||
|
|
||||||
switch (instr & OPC_MASK) {
|
switch (instr & OPC_MASK) {
|
||||||
case OPC_ADQ:
|
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_DVI:
|
||||||
case OPC_MUI:
|
case OPC_MUI:
|
||||||
if (ISCONSTANT(instr))
|
if (ISCONSTANT(instr))
|
||||||
strcat(mode, "=");
|
isconst = 1;
|
||||||
break;
|
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));
|
sprintf(temp, "$%04X", LoadFromMem(addr + 1));
|
||||||
} else sprintf(temp, "$%02X", delta);
|
} else sprintf(temp, "$%02X", delta);
|
||||||
|
|
||||||
strcat(decoded, mode);
|
sprintf(decoded, "%s%s%s%s%s%s%s",
|
||||||
if ((instr & MOD_IN) != 0)
|
opName[(instr & OPC_MASK) >> 12],
|
||||||
strcat(decoded, "(");
|
mode,
|
||||||
strcat(decoded, temp);
|
isconst ? "=" : "",
|
||||||
if ((instr & MOD_IN) != 0)
|
(instr & MOD_IN) != 0 ? "(" : "",
|
||||||
strcat(decoded, ")");
|
temp,
|
||||||
|
(instr & MOD_IN) != 0 ? ")" : "",
|
||||||
strcat(decoded, idxName[(instr & (MOD_I1 | MOD_I2)) >> 8]);
|
idxName[(instr & (MOD_I1 | MOD_I2)) >> 8]);
|
||||||
} else {
|
} else {
|
||||||
spc = spcName[(instr & OPC_SPECIALMASK) >> 8];
|
spc = spcName[(instr & OPC_SPECIALMASK) >> 8];
|
||||||
|
|
||||||
switch (instr & OPC_SPECIALMASK) {
|
switch (instr & OPC_SPECIALMASK) {
|
||||||
case OPC_EIN:
|
|
||||||
case OPC_IIN:
|
case OPC_IIN:
|
||||||
|
case OPC_EIN:
|
||||||
case OPC_SPB:
|
case OPC_SPB:
|
||||||
case OPC_CPB:
|
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:
|
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;
|
break;
|
||||||
|
|
||||||
case OPC_EXI:
|
case OPC_EXI:
|
||||||
sprintf(decoded, "%s $%02X", spc, instr & OPC_MODMASK);
|
sprintf(decoded, "%s $%02X", spc, delta);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OPC_SKIPS:
|
case OPC_SKIPS:
|
||||||
|
@ -166,6 +214,23 @@ int disassem(char *buf, uint16 addr, t_bool dbg, t_bool targ, t_bool exec)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OPC_SLS:
|
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_INP:
|
||||||
case OPC_OUT:
|
case OPC_OUT:
|
||||||
case OPC_INA:
|
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",
|
sprintf(buf, "%c %04X %s %s",
|
||||||
prot, instr, optional, decoded);
|
prot, instr, optional, decoded);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (targ) {
|
if (targ) {
|
||||||
const char *rel = "";
|
const char *rel = "";
|
||||||
t_bool indJmp = FALSE;
|
t_bool indJmp = FALSE;
|
||||||
uint8 more = 0;
|
|
||||||
uint16 taddr, taddr2, base;
|
uint16 taddr, taddr2, base;
|
||||||
|
|
||||||
switch (instr & OPC_MASK) {
|
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) {
|
if (indJmp) {
|
||||||
sprintf(buf, "[ => (%04X%s)", taddr2, rel);
|
sprintf(buf, "[ => (%04X%s)", taddr2, rel);
|
||||||
} else {
|
} else {
|
||||||
if (more == 1)
|
switch (more) {
|
||||||
sprintf(buf, "[ => %04X%s %s {%04X}", taddr2, rel,
|
case 1:
|
||||||
P[MEMADDR(taddr)] ? "(P)" : "",
|
sprintf(buf, "[ => %04X%s %s {%04X}", taddr2, rel,
|
||||||
LoadFromMem(taddr));
|
P[MEMADDR(taddr)] ? "(P)" : "",
|
||||||
else sprintf(buf, "[ => %04X%s (B:%04X%s) %s {%04X}",
|
LoadFromMem(taddr));
|
||||||
taddr2, rel, base, rel,
|
break;
|
||||||
P[MEMADDR(taddr)] ? "(P)" : "",
|
|
||||||
LoadFromMem(taddr));
|
case 2:
|
||||||
|
sprintf(buf, "[ => %04X%s (B:%04X%s) %s {%04X}",
|
||||||
|
taddr2, rel, base, rel,
|
||||||
|
P[MEMADDR(taddr)] ? "(P)" : "",
|
||||||
|
LoadFromMem(taddr));
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
copy of this software and associated documentation files (the "Software"),
|
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)
|
if (iou->cylinder >= numcy)
|
||||||
return DPIO_ADDRERR;
|
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++) {
|
for (i = 0; i < DP_NUMWD; i++) {
|
||||||
/*** TODO: fix protect check ***/
|
/*** TODO: fix protect check ***/
|
||||||
|
@ -579,8 +584,14 @@ static enum dpio_status DPDiskIOWrite(UNIT *uptr)
|
||||||
} else iou->buf[i] = 0;
|
} 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);
|
DPDiskIOIncSector(iou);
|
||||||
return fill ? DPIO_DONE : DPIO_MORE;
|
return fill ? DPIO_DONE : DPIO_MORE;
|
||||||
}
|
}
|
||||||
|
@ -598,8 +609,13 @@ static enum dpio_status DPDiskIOCompare(UNIT *uptr)
|
||||||
if (iou->cylinder >= numcy)
|
if (iou->cylinder >= numcy)
|
||||||
return DPIO_ADDRERR;
|
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++) {
|
for (i = 0; i < DP_NUMWD; i++) {
|
||||||
if (iou->buf[i] != LoadFromMem(iou->CWA))
|
if (iou->buf[i] != LoadFromMem(iou->CWA))
|
||||||
|
@ -1101,8 +1117,8 @@ t_stat DPautoload(void)
|
||||||
t_offset offset = i * DP_NUMBY;
|
t_offset offset = i * DP_NUMBY;
|
||||||
void *buf = &M[i * DP_NUMWD];
|
void *buf = &M[i * DP_NUMWD];
|
||||||
|
|
||||||
sim_fseeko(uptr->fileref, offset, SEEK_SET);
|
if (sim_fseeko(uptr->fileref, offset, SEEK_SET) ||
|
||||||
if (sim_fread(buf, sizeof(uint16), DP_NUMWD, uptr->fileref) != DP_NUMWD)
|
(sim_fread(buf, sizeof(uint16), DP_NUMWD, uptr->fileref) != DP_NUMWD))
|
||||||
return SCPE_IOERR;
|
return SCPE_IOERR;
|
||||||
}
|
}
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
|
|
631
CDC1700/cdc1700_msos5.c
Normal file
631
CDC1700/cdc1700_msos5.c
Normal 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);
|
||||||
|
}
|
|
@ -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
|
Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
copy of this software and associated documentation files (the "Software"),
|
copy of this software and associated documentation files (the "Software"),
|
||||||
|
@ -718,7 +718,7 @@ void mt_dump(void)
|
||||||
char msg[80], text[16];
|
char msg[80], text[16];
|
||||||
|
|
||||||
if (MTremain > 0) {
|
if (MTremain > 0) {
|
||||||
printf("Dump of MTbuf:\r\n");
|
fprintf(DBGOUT, "Dump of MTbuf:\r\n");
|
||||||
|
|
||||||
while (count > 0) {
|
while (count > 0) {
|
||||||
t_mtrlnt remain = count >= 10 ? 10 : count;
|
t_mtrlnt remain = count >= 10 ? 10 : count;
|
||||||
|
@ -738,7 +738,7 @@ void mt_dump(void)
|
||||||
}
|
}
|
||||||
text[remain] = '\0';
|
text[remain] = '\0';
|
||||||
|
|
||||||
printf("%-55s%s\r\n", msg, text);
|
fprintf(DBGOUT, "%-55s%s\r\n", msg, text);
|
||||||
|
|
||||||
count -= remain;
|
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 mt_densityTimeout(t_bool loose)
|
||||||
{
|
{
|
||||||
int32 result;
|
int32 result = MT_200_WAIT;
|
||||||
|
|
||||||
switch (MTdev.STATUS2 & (IO_ST2_556 | IO_ST2_800)) {
|
switch (MTdev.STATUS2 & (IO_ST2_556 | IO_ST2_800)) {
|
||||||
case 0:
|
case 0:
|
||||||
|
|
|
@ -80,7 +80,7 @@ static const char *opcode[] = {
|
||||||
"CAQ", "CAB", "INA", "ENA",
|
"CAQ", "CAB", "INA", "ENA",
|
||||||
"NOP", "ENQ", "INQ", "EXI",
|
"NOP", "ENQ", "INQ", "EXI",
|
||||||
"QRS", "ARS", "LRS", "QLS",
|
"QRS", "ARS", "LRS", "QLS",
|
||||||
"ALS", "LLS",
|
"ALS", "LLS", "ECA", "DCA",
|
||||||
NULL
|
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_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_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_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
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -224,6 +224,10 @@
|
||||||
RelativePath="..\CDC1700\cdc1700_lp.c"
|
RelativePath="..\CDC1700\cdc1700_lp.c"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\CDC1700\cdc1700_msos5.c"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\CDC1700\cdc1700_mt.c"
|
RelativePath="..\CDC1700\cdc1700_mt.c"
|
||||||
>
|
>
|
||||||
|
|
|
@ -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_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_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_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))
|
CDC1700_OPTIONS = /INCL=($(SIMH_DIR),$(CDC1700_DIR))/DEF=($(CC_DEFS))
|
||||||
|
|
||||||
#
|
#
|
||||||
|
|
2
makefile
2
makefile
|
@ -1497,7 +1497,7 @@ CDC1700 = ${CDC1700D}/cdc1700_cpu.c ${CDC1700D}/cdc1700_dis.c \
|
||||||
${CDC1700D}/cdc1700_dc.c ${CDC1700D}/cdc1700_iofw.c \
|
${CDC1700D}/cdc1700_dc.c ${CDC1700D}/cdc1700_iofw.c \
|
||||||
${CDC1700D}/cdc1700_lp.c ${CDC1700D}/cdc1700_dp.c \
|
${CDC1700D}/cdc1700_lp.c ${CDC1700D}/cdc1700_dp.c \
|
||||||
${CDC1700D}/cdc1700_cd.c ${CDC1700D}/cdc1700_sym.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}
|
CDC1700_OPT = -I ${CDC1700D}
|
||||||
|
|
||||||
###
|
###
|
||||||
|
|
Loading…
Add table
Reference in a new issue