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