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

View file

@ -4,15 +4,40 @@ Installing MSOS 5 on the CDC 1700 Simulator
1. Overview. 1. Overview.
A Mass Storage Operating System Version 5 (MSOS 5) distribution tape A Mass Storage Operating System Version 5 (MSOS 5) distribution tape
which will run on the CDC 1700 Simulator is available from bitsaver.org as which will run on the CDC 1700 Simulator is available from bitsavers.org as
bits/CDC/1700_Cyber18/20100524/MSOS5_SL136.tap. At the time, CDC would have bits/CDC/1700_Cyber18/20100524/MSOS5_SL136.tap. At the time, CDC would have
tailored a distribution tape for the customers specific hardware and this tailored a distribution tape for the customer's specific hardware and this
tape was built for a 64KW 1784 system used by Exxon. Not all of the tape was built for a 64KW 1784 system used by Exxon. Not all of the
peripherals included in the system are implemented on the simulator due to peripherals included in the system are implemented on the simulator due to
lack of documentation but enough are available to perform a basic lack of documentation but enough are available to perform a basic
installation. installation.
2. Installation 2. Utilities
While implementing this simulator, I developed a number of tools for
manipulating SIMH .tap container files and some of the CDC MSOS -specific file
formats. These utilities are available from the simtools Github repository:
extractors/rawtap
Allows extract, create and append operations on .tap files.
extractors/cpytap
Copies a .tap file to a new .tap file while allowing file level edits;
skip file, replace file, append files and insert files. Any files
copies from the original source .tap will have their internal record
structure maintained. Files read from the local file system will be
written to the destination .tap file with a fixed record size.
converters/cosy
COSY is a compressed file format used by the CDC 1700 for source
card decks. This utility allows for the extraction of all files from
an archive or the creation of a new archive. It assumes that you
would have used rawtap to extract the archive from a .tap file.
3. Installation
Installation of MSOS 5 occurs in 2 phases: Installation of MSOS 5 occurs in 2 phases:
@ -40,13 +65,15 @@ successfully but the batch subsystem will refuse to start.
Sample installation run of MSOS 5 (user input to MSOS is marked with "<==="): Sample installation run of MSOS 5 (user input to MSOS is marked with "<==="):
CDC1700 simulator V4.0-0 Beta git commit id: 9d2079df CDC1700 simulator V4.0-0 Beta git commit id: 9d2079df
sim> set cpu instr=basic
sim> set cpu mode65k,64k sim> set cpu mode65k,64k
sim> set mt type=1732-3 sim> set mt type=1732-3
sim> att mt0 MSOS5_SL136.tap sim> att mt0 MSOS5_SL136.tap
sim> set lp type=1742 sim> set lp type=1742
sim> att lp MSOSinstall.lpt sim> att lp MSOSinstall.lpt
LP: creating new file LP: creating new file
sim> att cdd0 MSOS5.dsk sim> att cdd0 MSOS5-A.dsk
sim> att cdd1 MSOS5-B.dsk
CDD: creating new file CDD: creating new file
sim> boot mt0 sim> boot mt0
@ -586,3 +613,220 @@ Sample installation run of MSOS 5 (user input to MSOS is marked with "<==="):
Output from the batch jobs is sent to the line printer. Output from the batch jobs is sent to the line printer.
4. MSOS 5
4.1 Limitations
The distribution tapes for MSOS 5 were generated by CDC individually
for each customer so the one we have available (MSOS5_SL136.tap) is for a
machine initially installed at Exxon. This particular system included 4 1733-2
disk drives and a 1752 drum. The 1733-2 disks are full supported by the
simulator but the 1752 drum is not since I have not been able to locate any
documentation of the programming interface. The file manager storage is spread
out over all of the above devices so there will always be at least 1 error
detected when trying to create files. It is possible to patch the system so
that some of these devices are no longer present. Create a file "patchMSOS5"
in the directory you would normally run the emulator and add the following:
# Patch out unwanted devices
# 1752 drum
d 057C 0649
# 1733-2 unit 3
d 0589 0649
# 1733-2 unit 2
d 0570 0649
# 1733-2 unit 1
d 056F 0649
#
set cpu protect
continue
When the system boots and asks the operator to "SET PROGRAM PROTECT", use ^E
to get a "sim> " prompt and execute this script with "do patchMSOS5". The
unwanted devices will be replaced with software dummy alternate device.
4.2 Using MSOS 5
The MSOS 5 reference manual contains all of this information (and more)
and is available from bitsavers.org as
pdf/cdc/1700/msos/MSOS_5/96769400C_MSOS_Version_5_Reference_Oct77.pdf.
To start using MSOS 5, use the "autoload cdd/run 0" as described above
to start execution of the MSOS 5 installation. Enable protect mode when
requested and enter the current date and time (the system is not Y2K
compliant so dates are only good through 1999).
The installation tape (MSOS5_SL136.tap) includes most optional
components; Macro Assembler, Fortran Compiler, File Manager, Sort/Merge. (So
far the only component I have found missing is RPG and there appears to be a
tape available on bitsavers.org).
Console input is only accepted once the manual interrupt character
(Control + G) has been typed and, even then, only a limited set of commands
is accepted. To execute applications from within the program library you must
start the batch sub-system and type in batch commands on the console. To
start batch and create a new job:
MI <==================================== ^G (Control + G) for
manual interrupt
*BATCH <================================ Start batch subsystem
J
*JOB <================================== Start a new batch job
J
4.3 MSOS 5 Utilities
As an example the following sequence will output the logical unit table
to the printer:
*LULIST <=============================== Load the listing program
E *E <================================== Start execution - the first
"E" is output by the loader
J
In this example, the initial "E" was an indication that the program
included some unpatched externals. At this point the following inputs are
valid:
* Causes execution regardless of unpatched externals
*E Resolves unpatched externals with core-resident entry
points and, if none are left, causes execution.
*T Causes job termination.
Using the same example we can change the logical device assignments so that
the output will be on the comment device (the console teletype):
*K,L4 <================================ Set system print unit to teletype
J
*LULIST
E10 List of unpatched externals
LOG1A
SYSID
SYSYER
SYSDAY
SYSMON
E *E <================================= Resolve externals and execute
MSOS 5.0 LOGICAL UNIT LISTING FOR EXXON DEVELOPMENT SYSTEM 01/26/82
LU. EQUIPMENT DESCRIPTION READ/WRITE CLASS CODE EQ NO
01. SOFTWARE CORE ALLOCATOR READ/WRITE NO CLASS CODE EQ 00
02. SOFTWARE DUMMY ALTERNATE DEVICE READ/WRITE NO CLASS CODE EQ 00
03. SOFTWARE DUMMY ALTERNATE DEVICE READ/WRITE NO CLASS CODE EQ 00
04. 1711 TELETYPEWRITER READ/WRITE TELETYPE EQ 01
05. COSY UNIT READ/WRITE MAGNETIC TAPE EQ 00
06. 1732-3/616-92 MAG TAPE READ/WRITE MAGNETIC TAPE EQ 07
07. PSEUDO TAPE UNIT READ/WRITE MAGNETIC TAPE EQ 00
08. 1733-2/856-4 DISK UNIT (4.5M) READ/WRITE MASS STORAGE EQ 03
09. 1742-120 LINE PRINTER WRITE ONLY LINE PRINTER EQ 04
10. 1732-3/616-92 MAG TAPE READ/WRITE MAGNETIC TAPE EQ 07
11. 1728/430 CARD READER/PUNCH READ/WRITE CARD RDR/PUNCH EQ 10
12. 1742-120 LINE PRINTER WRITE ONLY LINE PRINTER EQ 04
13. 1733-2/856-4 DISK UNIT (4.5M) READ/WRITE MASS STORAGE EQ 03
14. 1733-2/856-4 DISK UNIT (4.5M) READ/WRITE MASS STORAGE EQ 03
15. 1733-2/856-4 DISK UNIT (4.5M) READ/WRITE MASS STORAGE EQ 03
16. 1732-3/616-92 MAG TAPE READ/WRITE MAGNETIC TAPE EQ 07
17. 1732-3/616-92 MAG TAPE READ/WRITE MAGNETIC TAPE EQ 07
18. 1732-3/616-92 MAG TAPE READ/WRITE MAGNETIC TAPE EQ 07
19. PSEUDO TAPE UNIT READ/WRITE MAGNETIC TAPE EQ 00
20. PSEUDO TAPE UNIT READ/WRITE MAGNETIC TAPE EQ 00
21. PSEUDO TAPE UNIT READ/WRITE MAGNETIC TAPE EQ 00
22. PSEUDO DISK DRIVER READ/WRITE MASS STORAGE EQ 00
23. PSEUDO DISK DRIVER READ/WRITE MASS STORAGE EQ 00
24. PSEUDO DISK DRIVER READ/WRITE MASS STORAGE EQ 00
25. PSEUDO DISK DRIVER READ/WRITE MASS STORAGE EQ 00
26. 1752 DRUM UNIT READ/WRITE MASS STORAGE EQ 02
27. COSY UNIT READ/WRITE MAGNETIC TAPE EQ 00
28. 1728/430 CARD READER/PUNCH READ/WRITE CARD RDR/PUNCH EQ 10
29. 1732-3/616-92 MAG TAPE READ/WRITE MAGNETIC TAPE EQ 07
30. 1743-2 ASYN COMM CONTR READ/WRITE TELETYPE EQ 05
31. 1743-2 ASYN COMM CONTR READ/WRITE TELETYPE EQ 05
32. 1743-2 ASYN COMM CONTR READ/WRITE TELETYPE EQ 05
33. 1743-2 ASYN COMM CONTR READ/WRITE TELETYPE EQ 05
34. 1743-2 ASYN COMM CONTR READ/WRITE TELETYPE EQ 05
35. 1743-2 ASYN COMM CONTR READ/WRITE TELETYPE EQ 05
36. 1732-3/616-92 MAG TAPE READ/WRITE MAGNETIC TAPE EQ 07
37. 1732-3/616-92 MAG TAPE READ/WRITE MAGNETIC TAPE EQ 07
38. 1742-120 LINE PRINTER WRITE ONLY LINE PRINTER EQ 04
39. 1728/430 CARD READER/PUNCH READ/WRITE CARD RDR/PUNCH EQ 10
40. 1743-2 ASYN COMM CONTR READ/WRITE TELETYPE EQ 05
41. 1743-2 ASYN COMM CONTR READ/WRITE TELETYPE EQ 05
42. 1743-2 ASYN COMM CONTR READ/WRITE TELETYPE EQ 05
43. 1743-2 ASYN COMM CONTR READ/WRITE TELETYPE EQ 05
44. 1743-2 ASYN COMM CONTR READ/WRITE TELETYPE EQ 05
45. 1743-2 ASYN COMM CONTR READ/WRITE TELETYPE EQ 05
46. 1711 TELETYPEWRITER READ/WRITE TELETYPE EQ 01
J
4.4 Software Development Tools
The easiest way to make use of the software development tools (Macro
Assembler and Fortran Compiler) is through the batch system. For this
description I'm going to assume the source code (assembler or Fortran) is
available on the host system (I'm assuming a Linux or Unix derivative system).
You will need the mksimtape utility available in the simtools respository on
github:
1. Create the source file (e.g. test.ftn) in upper case only.
2. Wrap the source code with compiler directives:
OPT ABC
PROGRAM XYZ
C FORTRAN PROGRAM
...
...
MON
The OPT/MON commands must be indented by 1 space. The OPT command specifies
what the compiler is to do with the input; generate listing, objects etc.
The MON command causes the compiler to return control to the operating
system once the compilation is complete.
3. Wrap the source again with batch directives:
*JOB
*FTN
OPT LAPX
PROGRAM XYZ
C COMMENT
...
...
END
MON
*CTO,COMPILATION COMPLETE
*LGO
data
*Z
This will compile the source code, send a message to the comment device
(typically the console TTY) and then load an execute the program. If the
program reads data from standard input it should follow the *LGO command.
4. The compiler/assembler expects each line of input to be in a separate
record on magtape so we need to convert the input file into fixed length
records. On Linux/Unix, dd will do this:
dd if=test.ftn of=test.blk cbs=72 conv=block
5. Write the file to a .tap container:
mksimtape test.blk:72 >test.tap
6. Now boot up MSOS5 in the simulator, attach test.tap to mt0, type ^G to
get the system's attention and type *BATCH to start the batch system
running. Listings should be sent to the line printer along with any
output from the application.
If you want to code is Macro Assembler, the operations are the same; change
*FTN to *ASSEM and change the OPT parameters. Documentation for both the
Macro Assembler and Fortran compiler are available on bitsavers.org.

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 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

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 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;

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 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,6 +257,8 @@ 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" },
{ "ENHANCED", DBG_ENH, "Display enh. instructions in basic mode" },
{ "MSOS5", DBG_MSOS5, "Display MSOS5 requests" },
{ "FULL", DBG_ALL }, { "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,10 +687,9 @@ 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;
@ -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,12 +1161,35 @@ t_stat executeAnInstruction(void)
case OPC_SPECIAL: case OPC_SPECIAL:
switch (instr & OPC_SPECIALMASK) { switch (instr & OPC_SPECIALMASK) {
case OPC_SLS: case OPC_SLS:
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) { if ((cpu_unit.flags & UNIT_STOPSW) != 0) {
dumpRegisters(); dumpRegisters();
return SCPE_SSTOP; return SCPE_SSTOP;
} }
break; 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;
case OPC_SKIPS: case OPC_SKIPS:
switch (instr & (OPC_SKIPS | OPC_SKIPMASK)) { switch (instr & (OPC_SKIPS | OPC_SKIPMASK)) {
case OPC_SAZ: case OPC_SAZ:
@ -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;
@ -1252,17 +1386,22 @@ t_stat executeAnInstruction(void)
break; break;
/* /*
* The following instructions (EIN, IIN, SPB, CPB and EXI) * EIN, IIN, SPB and CPB operate differently depending on the
* generate a protect fault if the protect switch is set and * currently selected instruction set.
* 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.
*/ */
case OPC_IIN: 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 ((cpu_unit.flags & UNIT_CHAR) != 0) {
if ((instr & 0xFF) != 0) { if ((instr & OPC_MODMASK) != 0) {
switch (instr) { switch (instr) {
case OPC_ECA: case OPC_ECA:
CAenable = 1; CAenable = 1;
@ -1272,15 +1411,38 @@ t_stat executeAnInstruction(void)
CAenable = 0; CAenable = 0;
break; 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; break;
} }
} /* FALLTHROUGH */
case OPC_EIN: /*
case OPC_SPB: * The following instructions (EIN, IIN, SPB, CPB and EXI)
case OPC_CPB: * 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".
*/
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"

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 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;

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 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
*/ */

View file

@ -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:
switch (INSTR_SET) {
case INSTR_ORIGINAL:
sprintf(decoded, "%s", spc); sprintf(decoded, "%s", spc);
break; 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: 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) {
case 1:
sprintf(buf, "[ => %04X%s %s {%04X}", taddr2, rel, sprintf(buf, "[ => %04X%s %s {%04X}", taddr2, rel,
P[MEMADDR(taddr)] ? "(P)" : "", P[MEMADDR(taddr)] ? "(P)" : "",
LoadFromMem(taddr)); LoadFromMem(taddr));
else sprintf(buf, "[ => %04X%s (B:%04X%s) %s {%04X}", break;
case 2:
sprintf(buf, "[ => %04X%s (B:%04X%s) %s {%04X}",
taddr2, rel, base, rel, taddr2, rel, base, rel,
P[MEMADDR(taddr)] ? "(P)" : "", P[MEMADDR(taddr)] ? "(P)" : "",
LoadFromMem(taddr)); 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 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
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 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:

View file

@ -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
}; };
/* /*

View file

@ -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"
> >

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_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))
# #

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_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}
### ###