/* | |
Copyright (c) 2015-2016, 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_sys.c: CDC1700 system description | |
*/ | |
#include "cdc1700_defs.h" | |
#include <ctype.h> | |
extern void buildDCtables(void); | |
extern void buildIOtable(void); | |
extern int disassem(char *, uint16, t_bool, t_bool, t_bool); | |
extern uint16 M[]; | |
extern REG cpu_reg[]; | |
extern DEVICE cpu_dev, dca_dev, dcb_dev, dcc_dev, | |
tti_dev, tto_dev, ptr_dev, ptp_dev, mt_dev, lp_dev, dp_dev, | |
cd_dev, drm_dev, rtc_dev; | |
extern UNIT cpu_unit; | |
t_stat autoload(int32, CONST char *); | |
t_stat CDautoload(void); | |
t_stat DPautoload(void); | |
t_stat DRMautoload(void); | |
t_bool RelValid = FALSE; | |
uint16 RelBase; | |
/* SCP data structures and interface routines | |
sim_name simulator name string | |
sim_PC pointer to saved PC register descriptor | |
sim_emax number of words for examine | |
sim_devices array of pointers to simulated devices | |
sim_stop_messages array of pointers to stop messages | |
sim_load binary loader | |
*/ | |
char sim_name[] = "CDC1700"; | |
REG *sim_PC = &cpu_reg[0]; | |
int32 sim_emax = 2; | |
DEVICE *sim_devices[] = { | |
&cpu_dev, | |
&rtc_dev, | |
&dca_dev, | |
&dcb_dev, | |
&dcc_dev, | |
&tti_dev, | |
&tto_dev, | |
&ptr_dev, | |
&ptp_dev, | |
&mt_dev, | |
&lp_dev, | |
&dp_dev, | |
&cd_dev, | |
&drm_dev, | |
NULL | |
}; | |
const char *sim_stop_messages[] = { | |
"OK", | |
"Indirect addressing loop count exceeded", | |
"Selective Stop", | |
"Invalid bits set in EXI instruction", | |
"Breakpoint", | |
"Stop on reject", | |
"Unimpl. instruction" | |
}; | |
/* | |
* New top-level command(s) for the CDC1700 | |
*/ | |
CTAB cdc1700_cmd[] = { | |
{ "AUTOLOAD", &autoload, 0, | |
"a{utoload} <controller> Autoload from default device on controller\n" | |
" Loads track 0 to location 0\n" | |
}, | |
{ NULL } | |
}; | |
/* | |
* Command post-processing routine. | |
*/ | |
static void postUpdate(t_bool from_scp) | |
{ | |
/* | |
* Rebuild the I/O device and buffered data channel tables in case the | |
* command changed the configuration. | |
*/ | |
buildIOtable(); | |
buildDCtables(); | |
RelValid = FALSE; | |
} | |
/* | |
* Special address print routine for "Relative" display. | |
*/ | |
static void sprintAddress(char *buf, DEVICE *dptr, t_addr addr) | |
{ | |
if ((dptr == sim_devices[0]) && ((sim_switches & SWMASK('R')) != 0)) { | |
if (!RelValid) { | |
RelBase = (uint16)addr; | |
RelValid = TRUE; | |
} | |
addr -= RelBase; | |
} | |
sprint_val(buf, addr, dptr->aradix, dptr->awidth, PV_RZRO); | |
} | |
static void printAddress(FILE *st, DEVICE *dptr, t_addr addr) | |
{ | |
char buf[64]; | |
sprintAddress(buf, dptr, addr); | |
fprintf (st, "%s", buf); | |
} | |
/* | |
* Once-only VM initialization | |
*/ | |
static void VMinit(void) | |
{ | |
sim_vm_sprint_addr = &sprintAddress; | |
sim_vm_fprint_addr = &printAddress; | |
sim_vm_post = &postUpdate; | |
sim_vm_cmd = cdc1700_cmd; | |
/* | |
* Initialize the "CPU" device to make sure the data structures are | |
* correctly initialized. | |
*/ | |
(cpu_dev.reset)(&cpu_dev); | |
} | |
void (*sim_vm_init)(void) = &VMinit; | |
/* | |
* Check for duplicate equipment addresses. | |
*/ | |
static t_bool checkDuplicate(DEVICE *dptr, uint8 equipment) | |
{ | |
int i = 0; | |
DEVICE *dptr2; | |
while ((dptr2 = sim_devices[i++]) != NULL) { | |
if ((dptr2 != dptr) && ((dptr2->flags & DEV_DIS) == 0)) { | |
IO_DEVICE *iod = (IO_DEVICE *)dptr2->ctxt; | |
if (iod->iod_equip == equipment) | |
return TRUE; | |
} | |
} | |
return FALSE; | |
} | |
/* | |
* Common routine to change the equipment address of a peripheral. Some | |
* devices (e.g. TT, PTR etc) cannot have their equipment address changed. | |
*/ | |
t_stat set_equipment(UNIT *uptr, int32 val, CONST char *cptr, void *desc) | |
{ | |
DEVICE *dptr; | |
IO_DEVICE *iod; | |
t_value v; | |
t_stat r; | |
if (cptr == NULL) | |
return SCPE_ARG; | |
v = get_uint(cptr, DEV_RDX, 15, &r); | |
if (r != SCPE_OK) | |
return r; | |
if (v == 0) | |
return SCPE_ARG; | |
/* | |
* Check to see if any other, non-disabled device is already using this | |
* address. | |
*/ | |
if ((dptr = find_dev_from_unit(uptr)) != NULL) { | |
if (checkDuplicate(dptr, v)) | |
return sim_messagef(SCPE_ARG, "Equipment address already in use\n"); | |
iod = (IO_DEVICE *)dptr->ctxt; | |
iod->iod_equip = v; | |
iod->iod_interrupt = 1 << v; | |
return SCPE_OK; | |
} | |
return SCPE_NXDEV; | |
} | |
/* | |
* Check for a duplicate address when a device is reset. If a duplicate is | |
* found, the device being reset is disabled. | |
*/ | |
t_stat checkReset(DEVICE *dptr, uint8 equipment) | |
{ | |
if (checkDuplicate(dptr, equipment)) { | |
dptr->flags |= DEV_DIS; | |
return sim_messagef(SCPE_ARG, "Equipment address already in use\n"); | |
} | |
return SCPE_OK; | |
} | |
t_stat sim_load(FILE *fileref, CONST char *cptr, CONST char *fname, int flag) | |
{ | |
t_addr lo, hi; | |
if (flag == 0) | |
return SCPE_ARG; | |
/* | |
* We want to write the memory in some device-dependent format. sim_switches | |
* contains the command switches which will be used to determine the | |
* format: | |
* | |
* -p Paper tape format | |
* | |
* Command syntax is: | |
* | |
* dump <file> -p <loaddr>-<hiaddr> | |
*/ | |
if ((sim_switches & SWMASK('P')) != 0) { | |
const char *tptr; | |
t_addr addr; | |
int temp, count = 0; | |
tptr = get_range(NULL, cptr, &lo, &hi, cpu_dev.aradix, cpu_unit.capac - 1, 0); | |
if (tptr != NULL) { | |
/* | |
* Output a couple of NULL frames to start the dump | |
*/ | |
fputc(0, fileref); | |
fputc(0, fileref); | |
for (addr = lo; addr <= hi; addr++) { | |
temp = M[addr]; | |
/* | |
* If the data is 0, map it to -0 (0xFFFF) since 0 terminates the | |
* sequence. We also count the number of times this happens and | |
* report it at the end. | |
*/ | |
if (temp == 0) { | |
temp =0xFFFF; | |
count++; | |
} | |
fputc((temp >> 8) & 0xFF, fileref); | |
fputc(temp & 0xFF, fileref); | |
} | |
/* | |
* Terminate the dump with 2 more NULL frames | |
*/ | |
fputc(0, fileref); | |
fputc(0, fileref); | |
if (count != 0) | |
printf("%d zero word translated to 0xFFFF\n", count); | |
return SCPE_OK; | |
} | |
} | |
return SCPE_ARG; | |
} | |
/* | |
* Symbolic decode | |
*/ | |
#define FMTASC(x) ((x) < 040) ? "<%03o>" : "%c", (x) | |
t_stat fprint_sym(FILE *of, t_addr addr, t_value *val, UNIT *uptr, int32 sw) | |
{ | |
int32 inst = val[0]; | |
t_bool target = (sw & SWMASK('T')) != 0; | |
char buf[128]; | |
int consume; | |
if ((sw & SWMASK('A')) != 0) { | |
/* ASCII character */ | |
if (inst > 0377) | |
return SCPE_ARG; | |
fprintf(of, FMTASC(inst & 0177)); | |
return SCPE_OK; | |
} | |
if ((sw & SWMASK('C')) != 0) { | |
unsigned char c1 = (inst >> 8) & 0xFF, c2 = inst & 0xFF; | |
fprintf(of, FMTASC(c1 & 0177)); | |
fprintf(of, FMTASC(c2 & 0177)); | |
return SCPE_OK; | |
} | |
if ((sw & SWMASK('M')) == 0) | |
return SCPE_ARG; | |
consume = disassem(buf, (uint16)addr, FALSE, target, FALSE); | |
fprintf(of, "%s", buf); | |
return -(consume - 1); | |
} | |
/* | |
* Autoload top-level command routine | |
*/ | |
t_stat autoload(int32 flag, CONST char *ptr) | |
{ | |
char gbuf[CBUFSIZE]; | |
DEVICE *dptr; | |
if (!ptr || !*ptr) | |
return SCPE_2FARG; | |
get_glyph(ptr, gbuf, 0); | |
dptr = find_dev(gbuf); | |
if (dptr == NULL) | |
return SCPE_ARG; | |
if (dptr == &cd_dev) | |
return CDautoload(); | |
if (dptr == &dp_dev) | |
return DPautoload(); | |
if (dptr == &drm_dev) | |
return DRMautoload(); | |
return SCPE_NOFNC; | |
} |