| /* i7010_sys.c: IBM 7010 Simulator system interface. | |
| Copyright (c) 2005-2016, Richard Cornwell | |
| 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 | |
| RICHARD CORNWELL 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. | |
| */ | |
| #include "i7010_defs.h" | |
| #include "sim_card.h" | |
| #include <ctype.h> | |
| /* 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[] = "IBM 7010"; | |
| REG *sim_PC = &cpu_reg[0]; | |
| int32 sim_emax = 50; | |
| DEVICE *sim_devices[] = { | |
| &cpu_dev, | |
| &chan_dev, | |
| #ifdef NUM_DEVS_CDR | |
| &cdr_dev, | |
| #endif | |
| #ifdef NUM_DEVS_CDP | |
| &cdp_dev, | |
| #endif | |
| #ifdef STACK_DEV | |
| &stack_dev, | |
| #endif | |
| #ifdef NUM_DEVS_LPR | |
| &lpr_dev, | |
| #endif | |
| #ifdef NUM_DEVS_CON | |
| &con_dev, | |
| #endif | |
| #if NUM_DEVS_MT > 0 | |
| &mta_dev, | |
| #if NUM_DEVS_MT > 1 | |
| &mtb_dev, | |
| #if NUM_DEVS_MT > 2 | |
| &mtc_dev, | |
| #endif | |
| #endif | |
| #endif | |
| #ifdef NUM_DEVS_HD | |
| &hsdrm_dev, | |
| #endif | |
| #ifdef NUM_DEVS_DR | |
| &drm_dev, | |
| #endif | |
| #ifdef NUM_DEVS_DSK | |
| &dsk_dev, | |
| #endif | |
| #ifdef NUM_DEVS_COM | |
| &coml_dev, | |
| &com_dev, | |
| #endif | |
| #ifdef NUM_DEVS_CHRON | |
| &chron_dev, | |
| #endif | |
| NULL | |
| }; | |
| /* Device addressing words */ | |
| #ifdef NUM_DEVS_CDP | |
| DIB cdp_dib = { CH_TYP_UREC, 1, 00400, 07700, &cdp_cmd, &cdp_ini }; | |
| #endif | |
| #ifdef NUM_DEVS_CDR | |
| DIB cdr_dib = { CH_TYP_UREC, 1, 00100, 07700, &cdr_cmd, NULL }; | |
| #endif | |
| #ifdef NUM_DEVS_LPR | |
| DIB lpr_dib = { CH_TYP_UREC, 1, 00200, 07700, &lpr_cmd, &lpr_ini }; | |
| #endif | |
| #ifdef NUM_DEVS_CON | |
| DIB con_dib = { CH_TYP_UREC, 1, 02300, 07700, &con_cmd, &con_ini }; | |
| #endif | |
| #ifdef NUM_DEVS_MT | |
| DIB mt_dib = { CH_TYP_UREC, NUM_UNITS_MT, 02400, 07700, &mt_cmd, &mt_ini }; | |
| #endif | |
| #ifdef NUM_DEVS_CHRON | |
| DIB chron_dib = { CH_TYP_UREC, 1, 02400, 07700, &chron_cmd, NULL }; | |
| #endif | |
| #ifdef NUM_DEVS_DSK | |
| DIB dsk_dib = { CH_TYP_79XX|CH_TYP_UREC, 0, 06600, 07700, &dsk_cmd, &dsk_ini }; | |
| #endif | |
| #ifdef NUM_DEVS_COM | |
| DIB com_dib = { CH_TYP_79XX|CH_TYP_UREC, 0, 04200, 07700, &com_cmd, NULL }; | |
| #endif | |
| /* Simulator stop codes */ | |
| const char *sim_stop_messages[] = { | |
| "Unknown error", | |
| "IO device not ready", | |
| "HALT instruction", | |
| "Breakpoint", | |
| "Unknown Opcode", | |
| "Error1", /* Ind limit */ /* Not on 7010 */ | |
| "Error2", /* XEC limit */ /* Not on 7010 */ | |
| "I/O Check opcode", | |
| "Error3", /* MM in trap */ /* Not on 7010 */ | |
| "7750 invalid line number", | |
| "7750 invalid message", | |
| "7750 No free output buffers", | |
| "7750 No free input buffers", | |
| "Error4", /* Field overflow */ /* Not on 7010 */ | |
| "Error5", /* Sign change */ /* Not on 7010 */ | |
| "Divide error", | |
| "Error6", /* Alpha index */ /* Not on 7010 */ | |
| "No word mark", | |
| "Invalid Address", | |
| "Invalid Lenght Instruction", | |
| "Program Check", | |
| "Protect Check", | |
| 0, | |
| }; | |
| /* Simulator debug controls */ | |
| DEBTAB dev_debug[] = { | |
| {"CHANNEL", DEBUG_CHAN}, | |
| {"TRAP", DEBUG_TRAP}, | |
| {"CMD", DEBUG_CMD}, | |
| {"DATA", DEBUG_DATA}, | |
| {"DETAIL", DEBUG_DETAIL}, | |
| {"EXP", DEBUG_EXP}, | |
| {"SENSE", DEBUG_SNS}, | |
| {0, 0} | |
| }; | |
| DEBTAB crd_debug[] = { | |
| {"CHAN", DEBUG_CHAN}, | |
| {"CMD", DEBUG_CMD}, | |
| {"DATA", DEBUG_DATA}, | |
| {"DETAIL", DEBUG_DETAIL}, | |
| {"EXP", DEBUG_EXP}, | |
| {"CARD", DEBUG_CARD}, | |
| {0, 0} | |
| }; | |
| /* Character conversion tables */ | |
| const char ascii_to_six[128] = { | |
| /* Control */ | |
| -1, -1, -1, -1, -1, -1, -1, -1, /* 0 - 37 */ | |
| /* Control */ | |
| -1, -1, -1, -1, -1, -1, -1, -1, | |
| /* Control */ | |
| -1, -1, -1, -1, -1, -1, -1, -1, | |
| /* Control */ | |
| -1, -1, -1, -1, -1, -1, -1, -1, | |
| /*sp ! " # $ % & ' */ | |
| 000, 052, -1, 032, 053, 017, 060, 014, /* 40 - 77 */ | |
| /* ( ) * + , - . / */ | |
| 034, 074, 054, 060, 033, 040, 073, 021, | |
| /* 0 1 2 3 4 5 6 7 */ | |
| 012, 001, 002, 003, 004, 005, 006, 007, | |
| /* 8 9 : ; < = > ? */ | |
| 010, 011, 015, 056, 076, 013, 016, 032, | |
| /* @ A B C D E F G */ | |
| 014, 061, 062, 063, 064, 065, 066, 067, /* 100 - 137 */ | |
| /* H I J K L M N O */ | |
| 070, 071, 041, 042, 043, 044, 045, 046, | |
| /* P Q R S T U V W */ | |
| 047, 050, 051, 022, 023, 024, 025, 026, | |
| /* X Y Z [ \ ] ^ _ */ | |
| 027, 030, 031, 075, 036, 055, 057, 020, | |
| /* ` a b c d e f g */ | |
| 035, 061, 062, 063, 064, 065, 066, 067, /* 140 - 177 */ | |
| /* h i j k l m n o */ | |
| 070, 071, 041, 042, 043, 044, 045, 046, | |
| /* p q r s t u v w */ | |
| 047, 050, 051, 022, 023, 024, 025, 026, | |
| /* x y z { | } ~ del*/ | |
| 027, 030, 031, 057, 077, 017, -1, -1 | |
| }; | |
| const char mem_to_ascii[64] = { | |
| ' ', '1', '2', '3', '4', '5', '6', '7', | |
| '8', '9', '0', '=', '\'', ':', '>', 's', | |
| 'b', '/', 'S', 'T', 'U', 'V', 'W', 'X', | |
| 'Y', 'Z', 'x', ',', '(', '`', '\\', '_', | |
| '-', 'J', 'K', 'L', 'M', 'N', 'O', 'P', | |
| 'Q', 'R', '!', '$', '*', ']', ';', '^', | |
| '+', 'A', 'B', 'C', 'D', 'E', 'F', 'G', | |
| 'H', 'I', '?', '.', ')', '[', '<', '|', | |
| /*Sq*/ /*RM*/ | |
| }; | |
| /* Load a card image file into memory. */ | |
| t_stat | |
| sim_load(FILE * fileref, CONST char *cptr, CONST char *fnam, int flag) | |
| { | |
| return SCPE_NOFNC; | |
| } | |
| /* Symbol tables */ | |
| typedef struct _opcode | |
| { | |
| uint16 opbase; | |
| const char *name; | |
| uint8 type; | |
| } | |
| t_opcode; | |
| #define TYPE_0 0 /* no operands, no options */ | |
| #define TYPE_1 1 /* One operand, no options */ | |
| #define TYPE_2 2 /* Two operands, no options */ | |
| #define TYPE_T 4 /* Tape opcode, option */ | |
| #define TYPE_B 5 /* Branch, one operand, option */ | |
| #define TYPE_BE 6 /* Branch, three operands */ | |
| #define TYPE_BZ 7 /* Branch, three operands */ | |
| #define TYPE_CC 8 /* Carrage control */ | |
| #define TYPE_IO 9 /* IO select, address, option */ | |
| #define TYPE_Y 10 /* one operand, option */ | |
| #define TYPE_M 11 /* Move type, two ops, mod */ | |
| #define TYPE_BS 12 /* One operand, print mod */ | |
| #define MOD(x) (x<<6) | |
| t_opcode ops_1401[] = { | |
| {CHR_A, "A", TYPE_2}, | |
| {OP_B|MOD(CHR_9), "BC9", TYPE_B}, | |
| {OP_B|MOD(CHR_QUOT),"BCV", TYPE_B}, | |
| {OP_B|MOD(CHR_Z), "BAV", TYPE_B}, | |
| {OP_B|MOD(CHR_S), "BE", TYPE_B}, | |
| {OP_B|MOD(CHR_T), "BH", TYPE_B}, | |
| {OP_B|MOD(CHR_U), "BL", TYPE_B}, | |
| {OP_B|MOD(CHR_SLSH),"BU", TYPE_B}, | |
| {OP_B|MOD(CHR_A), "BLC", TYPE_B}, | |
| {OP_B|MOD(CHR_B), "BSS", TYPE_BS}, | |
| {OP_B|MOD(CHR_C), "BSS", TYPE_BS}, | |
| {OP_B|MOD(CHR_D), "BSS", TYPE_BS}, | |
| {OP_B|MOD(CHR_E), "BSS", TYPE_BS}, | |
| {OP_B|MOD(CHR_F), "BSS", TYPE_BS}, | |
| {OP_B|MOD(CHR_K), "BEF", TYPE_B}, | |
| {OP_B|MOD(CHR_L), "BER", TYPE_B}, | |
| {OP_B|MOD(CHR_P), "BPB", TYPE_B}, | |
| {OP_B|MOD(CHR_N), "BIN", TYPE_BS}, | |
| {OP_B|MOD(CHR_I), "BIN", TYPE_BS}, | |
| {OP_B|MOD(CHR_RM), "BIN", TYPE_BS}, | |
| {OP_B|MOD(CHR_V), "BIN", TYPE_BS}, | |
| {OP_B|MOD(CHR_W), "BIN", TYPE_BS}, | |
| {OP_B|MOD(CHR_X), "BIN", TYPE_BS}, | |
| {OP_B|MOD(CHR_Z), "BIN", TYPE_BS}, | |
| {OP_B|MOD(CHR_STAR),"BIN", TYPE_BS}, | |
| {OP_B|MOD(CHR_QUEST),"BIN", TYPE_BS}, | |
| {OP_B|MOD(CHR_RPARN),"BIN", TYPE_BS}, | |
| {OP_B|MOD(CHR_9), "BPCB", TYPE_B}, | |
| {OP_B, "B", TYPE_BS}, | |
| {OP_BCE, "BCE", TYPE_BE}, | |
| {OP_BBE, "BBE", TYPE_BE}, | |
| {OP_BWE, "BWZ", TYPE_BE}, | |
| {OP_CC1, "CC", TYPE_CC}, | |
| {OP_CS, "CS", TYPE_2}, | |
| {OP_CWM, "CW", TYPE_2}, | |
| {OP_C, "C", TYPE_2}, | |
| {OP_D, "D", TYPE_2}, | |
| {OP_M, "M", TYPE_2}, | |
| {OP_H, "H", TYPE_1}, | |
| {CHR_M, "MLC", TYPE_IO}, | |
| {CHR_P, "MRCM", TYPE_2}, | |
| {CHR_Z, "MCS", TYPE_2}, | |
| {CHR_Y, "MLZS", TYPE_2}, | |
| {CHR_E, "MCE", TYPE_2}, | |
| {CHR_D, "MLNS", TYPE_2}, | |
| {CHR_L, "MLCWA", TYPE_IO}, | |
| {CHR_Q, "SAR", TYPE_2}, | |
| {CHR_H, "SBR", TYPE_2}, | |
| {CHR_1, "R", TYPE_1}, | |
| {CHR_2|07400, "WM", TYPE_Y}, | |
| {CHR_2, "W", TYPE_1}, | |
| {CHR_3, "WR", TYPE_1}, | |
| {CHR_4, "P", TYPE_1}, | |
| {CHR_5, "RP", TYPE_1}, | |
| {CHR_6, "WP", TYPE_1}, | |
| {CHR_7, "WRP", TYPE_1}, | |
| {CHR_EQ, "MA", TYPE_2}, | |
| {OP_NOP, "NOP", TYPE_0}, | |
| {OP_SWM, "SW", TYPE_2}, | |
| {OP_UC|06100, "SKF", TYPE_T}, | |
| {OP_UC|06200, "BSP", TYPE_T}, | |
| {OP_UC|06500, "SKP", TYPE_T}, | |
| {OP_UC|05100, "RWD", TYPE_T}, | |
| {OP_UC|02400, "RUN", TYPE_T}, | |
| {OP_UC|04400, "WTM", TYPE_T}, | |
| {OP_UC, "UC", TYPE_IO}, | |
| {OP_S, "S", TYPE_2}, | |
| {OP_SSF1, "SSF1", TYPE_CC}, | |
| {OP_SSF2, "SSF2", TYPE_CC}, | |
| {OP_ZA, "ZA", TYPE_2}, | |
| {OP_ZS, "ZS", TYPE_2}, | |
| {0, NULL, TYPE_BE}, | |
| }; | |
| /* Opcodes */ | |
| t_opcode base_ops[] = { | |
| {OP_IO1|MOD(077), "BA1", TYPE_B}, | |
| {OP_IO1|MOD(001), "BNR1", TYPE_B}, | |
| {OP_IO1|MOD(002), "BCB1", TYPE_B}, | |
| {OP_IO1|MOD(004), "BER1", TYPE_B}, | |
| {OP_IO1|MOD(010), "BEF1", TYPE_B}, | |
| {OP_IO1|MOD(020), "BNT1", TYPE_B}, | |
| {OP_IO1|MOD(040), "BWL1", TYPE_B}, | |
| {OP_IO1|MOD(000), "BEX1", TYPE_B}, | |
| {OP_IO1|MOD(000), "BEX1", TYPE_BE}, | |
| {OP_IO2|MOD(077), "BA2", TYPE_B}, | |
| {OP_IO2|MOD(001), "BNR2", TYPE_B}, | |
| {OP_IO2|MOD(002), "BCB2", TYPE_B}, | |
| {OP_IO2|MOD(004), "BER2", TYPE_B}, | |
| {OP_IO2|MOD(010), "BEF2", TYPE_B}, | |
| {OP_IO2|MOD(020), "BNT2", TYPE_B}, | |
| {OP_IO2|MOD(040), "BWL2", TYPE_B}, | |
| {OP_IO2|MOD(000), "BEX2", TYPE_B}, | |
| {OP_IO2|MOD(000), "BEX2", TYPE_BE}, | |
| {OP_IO3|MOD(077), "BA3", TYPE_B}, | |
| {OP_IO3|MOD(001), "BNR3", TYPE_B}, | |
| {OP_IO3|MOD(002), "BCB3", TYPE_B}, | |
| {OP_IO3|MOD(004), "BER3", TYPE_B}, | |
| {OP_IO3|MOD(010), "BEF3", TYPE_B}, | |
| {OP_IO3|MOD(020), "BNT3", TYPE_B}, | |
| {OP_IO3|MOD(040), "BWL3", TYPE_B}, | |
| {OP_IO3|MOD(000), "BEX3", TYPE_B}, | |
| {OP_IO3|MOD(000), "BEX3", TYPE_BE}, | |
| {OP_IO4|MOD(077), "BA4", TYPE_B}, | |
| {OP_IO4|MOD(001), "BNR4", TYPE_B}, | |
| {OP_IO4|MOD(002), "BCB4", TYPE_B}, | |
| {OP_IO4|MOD(004), "BER4", TYPE_B}, | |
| {OP_IO4|MOD(010), "BEF4", TYPE_B}, | |
| {OP_IO4|MOD(020), "BNT4", TYPE_B}, | |
| {OP_IO4|MOD(040), "BWL4", TYPE_B}, | |
| {OP_IO4|MOD(000), "BEX4", TYPE_B}, | |
| {OP_IO4|MOD(000), "BEX4", TYPE_BE}, | |
| {OP_A, "A", TYPE_2}, | |
| {OP_BBE, "BBE", TYPE_BE}, | |
| {OP_BCE, "BCE", TYPE_BE}, | |
| {OP_B|04100, "BPCB", TYPE_B}, | |
| {OP_B|04300, "BPCB2", TYPE_B}, | |
| {OP_B|01000, "BC9", TYPE_B}, | |
| {OP_B|05200, "BC92", TYPE_B}, | |
| {OP_B|03200, "BCV", TYPE_B}, | |
| {OP_B|07400, "BCV2", TYPE_B}, | |
| {OP_B|03100, "BAV", TYPE_B}, | |
| {OP_B|02200, "BE", TYPE_B}, | |
| {OP_B|02400, "BH", TYPE_B}, | |
| {OP_B|02300, "BL", TYPE_B}, | |
| {OP_B|02100, "BU", TYPE_B}, | |
| {OP_B|02600, "BDV", TYPE_B}, | |
| {OP_B|05000, "BNQ", TYPE_B}, | |
| {OP_B|05400, "BNQ2", TYPE_B}, | |
| {OP_B|00100, "BOL1", TYPE_B}, | |
| {OP_B|00200, "BOL2", TYPE_B}, | |
| {OP_B|00300, "BOL3", TYPE_B}, | |
| {OP_B|00400, "BOL4", TYPE_B}, | |
| {OP_B|04200, "BTI", TYPE_B}, | |
| {OP_B|02500, "BZ", TYPE_B}, | |
| {OP_B|02700, "BXO", TYPE_B}, | |
| {OP_B|03000, "BXU", TYPE_B}, | |
| {OP_BWE|00100, "BW", TYPE_BZ}, | |
| {OP_BWE|00300, "BWZ", TYPE_BZ}, | |
| {OP_BWE|00200, "BZN", TYPE_BZ}, | |
| {OP_BWE|00000, "BWE", TYPE_Y}, | |
| {OP_B, "B", TYPE_B}, | |
| {OP_B, "JIO", TYPE_Y}, | |
| {OP_CC1, "CC1", TYPE_CC}, | |
| {OP_CC2, "CC2", TYPE_CC}, | |
| {OP_CS, "CS", TYPE_2}, | |
| {OP_CWM, "CW", TYPE_2}, | |
| {OP_C, "C", TYPE_2}, | |
| {OP_D, "D", TYPE_2}, | |
| {OP_H, "H", TYPE_1}, | |
| {OP_T|00200, "LE", TYPE_B}, | |
| {OP_T|00600, "LEH", TYPE_B}, | |
| {OP_T|00400, "LH", TYPE_B}, | |
| {OP_T|00100, "LL", TYPE_B}, | |
| {OP_T|00300, "LLE", TYPE_B}, | |
| {OP_T|00500, "LLH", TYPE_B}, | |
| {OP_T|00700, "LA", TYPE_B}, | |
| {OP_T|00000, "L", TYPE_B}, | |
| {OP_MSZ, "MCS", TYPE_2}, | |
| {OP_E, "MCE", TYPE_2}, | |
| {OP_M, "M", TYPE_2}, | |
| {OP_MOV|00100, "MLNS", TYPE_M}, | |
| {OP_MOV|00200, "MLZS", TYPE_M}, | |
| {OP_MOV|00300, "MLCS", TYPE_M}, | |
| {OP_MOV|00400, "MLWS", TYPE_M}, | |
| {OP_MOV|00500, "MLNWS", TYPE_M}, | |
| {OP_MOV|00600, "MLZWS", TYPE_M}, | |
| {OP_MOV|00700, "MLCWS", TYPE_M}, | |
| {OP_MOV|01000, "SCNR", TYPE_M}, | |
| {OP_MOV|01100, "MRN", TYPE_M}, | |
| {OP_MOV|01200, "MRZ", TYPE_M}, | |
| {OP_MOV|01300, "MRC", TYPE_M}, | |
| {OP_MOV|01400, "MRW", TYPE_M}, | |
| {OP_MOV|01500, "MRNW", TYPE_M}, | |
| {OP_MOV|01600, "MRZW", TYPE_M}, | |
| {OP_MOV|01700, "MRCW", TYPE_M}, | |
| {OP_MOV|02000, "SCNLA", TYPE_M}, | |
| {OP_MOV|02100, "MLNA", TYPE_M}, | |
| {OP_MOV|02200, "MLZA", TYPE_M}, | |
| {OP_MOV|02300, "MLCA", TYPE_M}, | |
| {OP_MOV|02400, "MLWA", TYPE_M}, | |
| {OP_MOV|02500, "MLNWA", TYPE_M}, | |
| {OP_MOV|02600, "MLZWA", TYPE_M}, | |
| {OP_MOV|02700, "MLCWA", TYPE_M}, | |
| {OP_MOV|03000, "SCNRR", TYPE_M}, | |
| {OP_MOV|03100, "MRNR", TYPE_M}, | |
| {OP_MOV|03200, "MRZR", TYPE_M}, | |
| {OP_MOV|03300, "MRCR", TYPE_M}, | |
| {OP_MOV|03400, "MRWR", TYPE_M}, | |
| {OP_MOV|03500, "MRNWR", TYPE_M}, | |
| {OP_MOV|03600, "MRZWR", TYPE_M}, | |
| {OP_MOV|03700, "MRCWR", TYPE_M}, | |
| {OP_MOV|04000, "SCNLB", TYPE_M}, | |
| {OP_MOV|04100, "MLNB", TYPE_M}, | |
| {OP_MOV|04200, "MLZB", TYPE_M}, | |
| {OP_MOV|04300, "MLCB", TYPE_M}, | |
| {OP_MOV|04400, "MLWB", TYPE_M}, | |
| {OP_MOV|04500, "MLNWB", TYPE_M}, | |
| {OP_MOV|04600, "MLZWB", TYPE_M}, | |
| {OP_MOV|04700, "MLCWB", TYPE_M}, | |
| {OP_MOV|05000, "SCNRG", TYPE_M}, | |
| {OP_MOV|05100, "MRNG", TYPE_M}, | |
| {OP_MOV|05200, "MRZG", TYPE_M}, | |
| {OP_MOV|05300, "MRCG", TYPE_M}, | |
| {OP_MOV|05400, "MRWG", TYPE_M}, | |
| {OP_MOV|05500, "MRNWG", TYPE_M}, | |
| {OP_MOV|05600, "MRZWG", TYPE_M}, | |
| {OP_MOV|05700, "MRCWG", TYPE_M}, | |
| {OP_MOV|06000, "SCNL", TYPE_M}, | |
| {OP_MOV|06100, "MLN", TYPE_M}, | |
| {OP_MOV|06200, "MLZ", TYPE_M}, | |
| {OP_MOV|06300, "MLC", TYPE_M}, | |
| {OP_MOV|06400, "MLW", TYPE_M}, | |
| {OP_MOV|06500, "MLNW", TYPE_M}, | |
| {OP_MOV|06600, "MLZW", TYPE_M}, | |
| {OP_MOV|06700, "MLCW", TYPE_M}, | |
| {OP_MOV|07000, "SCNRM", TYPE_M}, | |
| {OP_MOV|07100, "MRNM", TYPE_M}, | |
| {OP_MOV|07200, "MRZM", TYPE_M}, | |
| {OP_MOV|07300, "MRCM", TYPE_M}, | |
| {OP_MOV|07400, "MRWM", TYPE_M}, | |
| {OP_MOV|07500, "MRNWM", TYPE_M}, | |
| {OP_MOV|07600, "MRZWM", TYPE_M}, | |
| {OP_MOV|07700, "MRCWM", TYPE_M}, | |
| {OP_MOV|00000, "SCNLS", TYPE_M}, | |
| {OP_NOP, "NOP", TYPE_0}, | |
| {OP_SWM, "SW", TYPE_2}, | |
| {OP_UC|06100, "SKF", TYPE_T}, | |
| {OP_UC|06200, "BSP", TYPE_T}, | |
| {OP_UC|06500, "SKP", TYPE_T}, | |
| {OP_UC|05100, "RWD", TYPE_T}, | |
| {OP_UC|02400, "RUN", TYPE_T}, | |
| {OP_UC|04400, "WTM", TYPE_T}, | |
| {OP_SAR|06100, "SAR", TYPE_1}, | |
| {OP_SAR|06200, "SBR", TYPE_1}, | |
| {OP_SAR|06500, "SER", TYPE_1}, | |
| {OP_SAR|06600, "SFR", TYPE_1}, | |
| {OP_SAR|06700, "SGR", TYPE_1}, | |
| {OP_SAR|07000, "SHR", TYPE_1}, | |
| {OP_SAR|02300, "STC", TYPE_1}, | |
| {OP_S, "S", TYPE_2}, | |
| {OP_SSF1, "SSF1", TYPE_CC}, | |
| {OP_SSF2, "SSF2", TYPE_CC}, | |
| {OP_ZA, "ZA", TYPE_2}, | |
| {OP_ZS, "ZS", TYPE_2}, | |
| {OP_RD|00000, "MU", TYPE_IO}, | |
| {OP_RDW|00000, "LU", TYPE_IO}, | |
| {OP_STS|00000, "STATS", TYPE_Y}, | |
| {OP_FP|05100, "FRA", TYPE_B}, | |
| {OP_FP|04300, "FST", TYPE_B}, | |
| {OP_FP|06100, "FA", TYPE_B}, | |
| {OP_FP|02200, "FS", TYPE_B}, | |
| {OP_FP|04400, "FM", TYPE_B}, | |
| {OP_FP|06400, "FD", TYPE_B}, | |
| {OP_FP|00000, "FP", TYPE_Y}, | |
| {OP_PRI|02400, "BUPR1", TYPE_B}, | |
| {OP_PRI|06600, "BUPR2", TYPE_B}, | |
| {OP_PRI|00100, "BOPR1", TYPE_B}, | |
| {OP_PRI|00200, "BOPR2", TYPE_B}, | |
| {OP_PRI|00300, "BOPR3", TYPE_B}, | |
| {OP_PRI|00400, "BOPR4", TYPE_B}, | |
| {OP_PRI|05000, "BIPR1", TYPE_B}, | |
| {OP_PRI|05500, "BIPR2", TYPE_B}, | |
| {OP_PRI|04500, "BQPR1", TYPE_B}, | |
| {OP_PRI|03200, "BQPR2", TYPE_B}, | |
| {OP_PRI|02200, "BSPR1", TYPE_B}, | |
| {OP_PRI|02300, "BSPR2", TYPE_B}, | |
| {OP_PRI|03000, "BSPR3", TYPE_B}, | |
| {OP_PRI|03400, "BSPR4", TYPE_B}, | |
| {OP_PRI|02700, "BXPA", TYPE_B}, | |
| {OP_PRI|06500, "BEPA", TYPE_B}, | |
| {OP_PRI|06100, "BXPR1", TYPE_B}, | |
| {OP_PRI|06200, "BXPR2", TYPE_B}, | |
| {OP_PRI|06300, "BXPR3", TYPE_B}, | |
| {OP_PRI|06400, "BXPR4", TYPE_B}, | |
| {OP_PRI|00000, "BPI", TYPE_Y}, | |
| {0, NULL, TYPE_BE}, | |
| }; | |
| const char *chname[] = { | |
| "*", "1", "2", "3", "4" | |
| }; | |
| /* Print out a address plus index */ | |
| t_stat fprint_addr (FILE *of, uint32 addr) { | |
| int i; | |
| int reg; | |
| reg = ((addr >> 10) & 03) | ((addr >> 14) & 014); | |
| addr &= 07777171777; /* Mask register bits */ | |
| for(i = 24; i>=0; i -= 6) | |
| fputc(mem_to_ascii[(addr >> i) & 077], of); | |
| if (reg != 0) | |
| fprintf(of, "+X%d", reg); | |
| return SCPE_OK; | |
| } | |
| /* Print out a 1401 address plus index */ | |
| t_stat fprint_addr_1401 (FILE *of, uint32 addr) { | |
| int reg; | |
| int v = 0; | |
| if ((addr & 0170000) != 0120000) | |
| v += ((addr >> 12) & 017) * 100; | |
| if ((addr & 01700) != 01200) | |
| v += ((addr >> 6) & 017) * 10; | |
| if ((addr & 017) != 012) | |
| v += addr & 017; | |
| v += ((addr & 0600000) >> 16) * 1000; | |
| v += ((addr & 060) >> 4) * 4000; | |
| reg = (addr >> 10) & 03; | |
| fprintf(of, "%d", v); | |
| if (reg != 0) | |
| fprintf(of, "+X%d", reg); | |
| return SCPE_OK; | |
| } | |
| /* Symbolic decode | |
| Inputs: | |
| *of = output stream | |
| addr = current PC | |
| *val = pointer to values | |
| *uptr = pointer to unit | |
| sw = switches | |
| Outputs: | |
| return = status code | |
| */ | |
| t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, UNIT *uptr, int32 sw) | |
| { | |
| int32 i, t; | |
| uint32 a, b; | |
| uint8 op, mod, flags; | |
| if (sw & SWMASK ('C')) { /* character? */ | |
| t = val[0]; | |
| fprintf (of, (t & WM)? "`%c<%02o> ": " %c<%02o> ", mem_to_ascii[t & 077], | |
| t & 077); | |
| return SCPE_OK; | |
| } | |
| if ((uptr != NULL) && (uptr != &cpu_unit)) return SCPE_ARG; /* CPU? */ | |
| if (sw & SWMASK ('D')) { /* dump? */ | |
| for (i = 0; i < 50; i++) fprintf (of, "%c", mem_to_ascii[val[i]&077]) ; | |
| fprintf (of, "\n\t"); | |
| for (i = 0; i < 50; i++) fprintf (of, (val[i]&WM)? "1": " ") ; | |
| return -(i - 1); | |
| } | |
| if (sw & SWMASK ('S')) { /* string? */ | |
| i = 0; | |
| do { | |
| t = val[i++]; | |
| fprintf (of, (t & WM)? "`%c": "%c", mem_to_ascii[t & 077]); | |
| } while ((i < 50) && ((val[i] & WM) == 0)); | |
| return -(i - 1); | |
| } | |
| if (sw & SWMASK ('N')) { /* 1401 machine code? */ | |
| uint16 temp; | |
| t_opcode *tab; | |
| mod = 0; | |
| flags = 0; | |
| a = 0; | |
| b = 0; | |
| i = 0; | |
| op = val[i++] & 077; | |
| /* 1 234 567 8 */ | |
| /* 0 123 456 7 */ | |
| /* o a b m */ | |
| /* 0 123 */ | |
| /* 0 123 4 */ | |
| /* 0 123 456 */ | |
| /* 0 1 */ | |
| if ((val[i] & WM) == 0) { | |
| /* Grab next value if one */ | |
| /* Grab 3 address digits */ | |
| do { | |
| a = (a << 6) | (val[i++] & 077); | |
| } while((val[i] & WM) == 0 && i < 4); | |
| } | |
| /* If more then grab B address and or modifier */ | |
| if ((val[i] & WM) == 0) { | |
| do { | |
| b = (b << 6) | (val[i++] & 077); | |
| } while((val[i] & WM) == 0 && i < 7); | |
| } | |
| /* Grab modifier */ | |
| if ((val[i] & WM) == 0) { | |
| mod = val[i++] & 077; | |
| flags |= 010; | |
| } | |
| /* Determine A, B and modifier values */ | |
| if (i == 2) { /* Only mod */ | |
| mod = a; | |
| flags |= 010; | |
| } else if (i == 4) { /* Only A */ | |
| flags |= 002; | |
| } else if (i == 5) { /* A + mod */ | |
| mod = b; | |
| flags |= 012; | |
| } else if (i > 6) { /* A + B */ | |
| flags |= 006; | |
| } | |
| /* Modify 2 op branch to BCE or B */ | |
| if (op == CHR_B) { | |
| switch(i) { | |
| case 1: | |
| case 7: | |
| case 8: op = CHR_B; break; | |
| default: op = CHR_J; break; | |
| } | |
| } | |
| temp = (mod << 6) | op; | |
| for(tab = ops_1401; tab->name != NULL; tab++) { | |
| if (temp == tab->opbase) | |
| break; | |
| if ((tab->type == TYPE_BE || tab->type == TYPE_CC) && | |
| (temp & 077) == tab->opbase) | |
| break; | |
| if (tab->type == TYPE_BZ && (temp & 0377) == tab->opbase) | |
| break; | |
| if ((temp & 077) == tab->opbase) | |
| break; | |
| } | |
| if (tab->type == TYPE_IO && (a & 0770000) == 0340000) { | |
| fprintf(of, "%cU\t", mem_to_ascii[op]); | |
| flags &= 075; | |
| flags |= 020; | |
| } else if (tab->name == NULL) | |
| fprintf(of, "%c<%02o>\t", mem_to_ascii[op], op); | |
| else | |
| fprintf(of, "%s\t", tab->name); | |
| switch(tab->type) { | |
| case TYPE_0: /* no operands, no options */ | |
| case TYPE_1: /* One operand, no options */ | |
| case TYPE_2: /* Two operands, no options */ | |
| case TYPE_B: /* Branch, one operand, option */ | |
| case TYPE_M: | |
| if (flags & 02) | |
| fprint_addr_1401(of, a); | |
| if (flags & 04) { | |
| fputc(',', of); | |
| fprint_addr_1401(of, b); | |
| } | |
| if (flags & 010) { | |
| fputc(',', of); | |
| fputc(mem_to_ascii[mod], of); | |
| } | |
| break; | |
| case TYPE_BS: /* Branch, one operand, option */ | |
| if (flags & 02) | |
| fprint_addr_1401(of, a); | |
| if (flags & 04) { | |
| fputc(',', of); | |
| fprint_addr_1401(of, b); | |
| } | |
| if (flags &010) { | |
| fputc(',', of); | |
| fputc(mem_to_ascii[mod], of); | |
| } | |
| break; | |
| case TYPE_IO: /* Tape opcode or move */ | |
| if (flags & 020) | |
| for (t = 18; t >= 0; t-=6) | |
| fprintf (of, "%c", mem_to_ascii[(a>>t)&077]) ; | |
| else if (flags & 02) | |
| fprint_addr_1401(of, a); | |
| if (flags & 04) { | |
| fputc(',', of); | |
| fprint_addr_1401(of, b); | |
| } | |
| if (flags & 010) | |
| fprintf (of, ",%c", mem_to_ascii[mod]); | |
| break; | |
| case TYPE_T: /* Tape opcode, option */ | |
| if (flags & 02) | |
| for (t = 18; t >= 0; t-=6) | |
| fprintf (of, "%c", mem_to_ascii[(a>>t)&077]) ; | |
| if (flags & 04) { | |
| fputc(',', of); | |
| fprint_addr_1401(of, b); | |
| } | |
| break; | |
| case TYPE_BZ: /* Branch, three operands */ | |
| if (flags & 02) | |
| fprint_addr_1401(of, a); | |
| if (flags & 04) { | |
| fputc(',', of); | |
| fprint_addr_1401(of, b); | |
| } | |
| if (flags & 010 && mod & 060) { | |
| fputc(',', of); | |
| if (mod & 020) | |
| fputc('A', of); | |
| if (mod & 040) | |
| fputc('B', of); | |
| } | |
| break; | |
| case TYPE_BE: /* Branch, three operands */ | |
| case TYPE_Y: /* Store special */ | |
| default: | |
| if (flags & 02) | |
| fprint_addr_1401(of, a); | |
| if (flags & 04) { | |
| fputc(',', of); | |
| fprint_addr_1401(of, b); | |
| } | |
| if (flags &010) { | |
| fputc(',', of); | |
| fputc(mem_to_ascii[mod], of); | |
| } | |
| break; | |
| case TYPE_CC: | |
| if (flags & 02) { | |
| fprint_addr_1401(of, a); | |
| if (flags & 010) | |
| fputc(',', of); | |
| } | |
| if (flags &010) | |
| fputc(mem_to_ascii[mod], of); | |
| break; | |
| } | |
| return -(i - 1); | |
| } | |
| if (sw & SWMASK ('M')) { /* machine code? */ | |
| uint16 temp; | |
| t_opcode *tab; | |
| mod = 0; | |
| flags = 0; | |
| a = 0; | |
| b = 0; | |
| i = 0; | |
| op = val[i++] & 077; | |
| if ((val[i] & WM) == 0) { | |
| /* Grab next value if one */ | |
| if (op == OP_RD || op == OP_RDW || op == OP_UC) { | |
| /* Three digit IO address */ | |
| do { | |
| a = (a << 6) | (val[i++] & 077); | |
| } while((val[i] & WM) == 0 && i < 4); | |
| flags = 1; | |
| } else { | |
| /* Grab 5 address digits */ | |
| do { | |
| a = (a << 6) | (val[i++] & 077); | |
| } while((val[i] & WM) == 0 && i < 6); | |
| } | |
| } | |
| /* If more then grab B address and or modifier */ | |
| if ((val[i] & WM) == 0) { | |
| int j = 0; | |
| do { | |
| b = (b << 6) | (val[i++] & 077); | |
| } while((val[i] & WM) == 0 && ++j < 5); | |
| } | |
| /* Determine A, B and modifier values */ | |
| if (i == 2) { | |
| mod = a; | |
| flags |= 010; | |
| } else if ((flags == 1 && i == 5) || (flags == 0 && i == 7)) { | |
| mod = b; | |
| flags |= 012; | |
| } else if ((flags == 1 && i == 4) || (flags == 0 && i == 6)) { | |
| flags |= 002; | |
| } else { | |
| flags |= 006; | |
| if ((val[i] & WM) == 0) { | |
| mod = val[i++] & 077; | |
| flags |= 010; | |
| } | |
| } | |
| temp = (mod << 6) | op; | |
| for(tab = base_ops; tab->name != NULL; tab++) { | |
| if (temp == tab->opbase) | |
| break; | |
| if ((tab->type == TYPE_BE || tab->type == TYPE_CC) && | |
| (temp & 077) == tab->opbase) | |
| break; | |
| if (tab->type == TYPE_BZ && (temp & 0377) == tab->opbase) | |
| break; | |
| if ((temp & 077) == tab->opbase) | |
| break; | |
| } | |
| if (tab->name == NULL) | |
| fprintf(of, "%c<%02o>\t", mem_to_ascii[op], op); | |
| else | |
| fprintf(of, "%s\t", tab->name); | |
| switch(tab->type) { | |
| case TYPE_0: /* no operands, no options */ | |
| case TYPE_1: /* One operand, no options */ | |
| case TYPE_2: /* Two operands, no options */ | |
| case TYPE_B: /* Branch, one operand, option */ | |
| case TYPE_M: | |
| if (flags & 02) | |
| fprint_addr(of, a); | |
| if (flags & 04) { | |
| fputc(',', of); | |
| fprint_addr(of, b); | |
| } | |
| break; | |
| case TYPE_IO: /* Tape opcode, option */ | |
| case TYPE_T: /* Tape opcode, option */ | |
| if (flags & 010) | |
| fprintf (of, "%c", mem_to_ascii[mod]); | |
| if (flags & 02) | |
| for (t = 18; t >= 0; t-=6) | |
| fprintf (of, "%c", mem_to_ascii[(a>>t)&077]) ; | |
| if (flags & 04) { | |
| fputc(',', of); | |
| fprint_addr(of, b); | |
| } | |
| break; | |
| case TYPE_BZ: /* Branch, three operands */ | |
| if (flags & 02) | |
| fprint_addr(of, a); | |
| if (flags & 04) { | |
| fputc(',', of); | |
| fprint_addr(of, b); | |
| } | |
| if (flags & 010 && mod & 060) { | |
| fputc(',', of); | |
| if (mod & 020) | |
| fputc('A', of); | |
| if (mod & 040) | |
| fputc('B', of); | |
| } | |
| break; | |
| case TYPE_BE: /* Branch, three operands */ | |
| case TYPE_Y: /* Store special */ | |
| default: | |
| if (flags & 02) | |
| fprint_addr(of, a); | |
| if (flags & 04) { | |
| fputc(',', of); | |
| fprint_addr(of, b); | |
| } | |
| if (flags &010) { | |
| fputc(',', of); | |
| fputc(mem_to_ascii[mod], of); | |
| } | |
| break; | |
| case TYPE_CC: | |
| if (flags &010) | |
| fputc(mem_to_ascii[mod], of); | |
| break; | |
| } | |
| return -(i - 1); | |
| } | |
| t = val[0]; | |
| fprintf (of, (t & WM)? "~%02o ": " %02o ", t & 077); | |
| return 0; | |
| } | |
| t_opcode * | |
| find_opcode(char *op, t_opcode * tab) | |
| { | |
| while (tab->name != NULL) { | |
| if (*tab->name != '\0' && strcmp(op, tab->name) == 0) | |
| return tab; | |
| tab++; | |
| } | |
| return NULL; | |
| } | |
| /* Symbolic input | |
| Inputs: | |
| *cptr = pointer to input string | |
| addr = current PC | |
| uptr = pointer to unit | |
| *val = pointer to output values | |
| sw = switches | |
| Outputs: | |
| status = error status | |
| */ | |
| t_stat | |
| parse_sym(CONST char *cptr, t_addr addr, UNIT * uptr, t_value * val, int32 sw) | |
| { | |
| int i; | |
| t_value d; | |
| char buffer[100]; | |
| int wm_seen; | |
| while (isspace(*cptr)) | |
| cptr++; | |
| d = 0; | |
| if (sw & SWMASK('C')) { | |
| i = 0; | |
| wm_seen = 0; | |
| while (*cptr != '\0') { | |
| if (*cptr == '~' && wm_seen == 0) | |
| wm_seen = WM; | |
| else { | |
| d = ascii_to_six[0177 & *cptr] | wm_seen; | |
| val[i++] = d; | |
| wm_seen = 0; | |
| } | |
| cptr++; | |
| } | |
| if (i == 0 || wm_seen) | |
| return SCPE_ARG; | |
| return -(i - 1); | |
| } else if (sw & SWMASK('M')) { | |
| t_opcode *op; | |
| int j; | |
| int32 addr; | |
| i = 0; | |
| /* Grab opcode */ | |
| cptr = get_glyph(cptr, buffer, 0); | |
| if ((op = find_opcode(buffer, base_ops)) == 0) | |
| return STOP_UUO; | |
| /* Skip blanks */ | |
| while(isspace(*cptr)) cptr++; | |
| val[i++] = WM | (op->opbase & 077); | |
| switch(op->type) { | |
| case TYPE_0: /* no operands, no options */ | |
| if (*cptr != '\0') | |
| return SCPE_ARG; | |
| return -(i - 1); | |
| case TYPE_CC: | |
| if (*cptr == '\0') | |
| val[i++] = 10; | |
| else | |
| val[i++] = ascii_to_six[(int)*cptr++]; | |
| return -(i - 1); | |
| case TYPE_IO: /* Tape opcode, option */ | |
| case TYPE_T: /* Tape opcode, option */ | |
| if (*cptr == '\0') | |
| return SCPE_ARG; | |
| val[i++] = ascii_to_six[(int)*cptr++]; | |
| if (*cptr == '\0') | |
| return SCPE_ARG; | |
| val[i++] = ascii_to_six[(int)*cptr++]; | |
| if (*cptr == '\0') | |
| return SCPE_ARG; | |
| val[i++] = ascii_to_six[(int)*cptr++]; | |
| /* Go grab address */ | |
| if (op->type == TYPE_T) { | |
| val[i++] = (op->opbase >> 6) & 077; | |
| return -(i-1); | |
| } | |
| break; | |
| case TYPE_1: /* One operand, no options */ | |
| case TYPE_2: /* Two operands, no options */ | |
| case TYPE_BE: /* Branch, three operands */ | |
| case TYPE_Y: /* Store special */ | |
| if (*cptr == '\0') | |
| return -(i - 1); | |
| break; | |
| case TYPE_B: /* Branch, one operand, option */ | |
| case TYPE_BZ: /* Branch, three operands */ | |
| case TYPE_M: /* Move opcode */ | |
| default: | |
| if (*cptr == '\0') { | |
| val[i++] = (op->opbase >> 6) & 077; | |
| return -(i-1); | |
| } | |
| break; | |
| } | |
| /* Pick up at least one address & possible index */ | |
| addr = 0; | |
| while(*cptr != '\0') { | |
| if (*cptr >= '0' && *cptr <= '9') | |
| addr = (addr * 10) + (*cptr++ - '0'); | |
| else if (*cptr == '+' || *cptr == ',') | |
| break; | |
| } | |
| /* Convert to BCD */ | |
| for(j = 4; j >= 0;j--) { | |
| buffer[j] = addr % 10; | |
| if (buffer[j] == 0) | |
| buffer[j] = 10; | |
| addr /= 10; | |
| } | |
| /* Merge in index bits if any */ | |
| if (*cptr == '+') { | |
| int n = 0; | |
| cptr++; | |
| if (*cptr != 'X' && *cptr != 'x') | |
| return SCPE_ARG; | |
| cptr++; | |
| if (!(*cptr >= '0' && *cptr <= '9')) | |
| return SCPE_ARG; | |
| n = *cptr++ - '0'; | |
| if (*cptr >= '0' && *cptr <= '9') | |
| n = (n * 10) + (*cptr++ - '0'); | |
| if (n > 16) | |
| return SCPE_ARG; | |
| buffer[3] |= (n & 3) << 4; | |
| buffer[2] |= (n & 014) << 2; | |
| } | |
| /* Copy over address */ | |
| for(j = 0; j <= 4; j++) | |
| val[i++] = buffer[j]; | |
| /* Skip blanks */ | |
| while(isspace(*cptr)) cptr++; | |
| switch(op->type) { | |
| case TYPE_IO: /* Tape opcode, option */ | |
| case TYPE_T: /* Tape opcode, option */ | |
| if (*cptr == ',') { | |
| val[i++] = ascii_to_six[(int)*++cptr]; | |
| while(isspace(*++cptr)); | |
| } | |
| if (*cptr == '\0') | |
| return -(i - 1); | |
| return SCPE_ARG; | |
| default: | |
| case TYPE_1: /* One operand, no options */ | |
| if (*cptr != '\0') | |
| return SCPE_ARG; | |
| return -(i - 1); | |
| case TYPE_2: /* Two operands, no options */ | |
| case TYPE_BE: /* Branch, three operands */ | |
| if (*cptr == '\0') | |
| return -(i - 1); | |
| break; | |
| case TYPE_B: /* Branch, one operand, option */ | |
| val[i++] = (op->opbase >> 6) & 077; | |
| return -(i-1); | |
| case TYPE_Y: /* Store special */ | |
| if (*cptr == ',') { | |
| val[i++] = ascii_to_six[(int)*++cptr]; | |
| while(isspace(*++cptr)); | |
| } | |
| if (*cptr == '\0') | |
| return -(i - 1); | |
| return SCPE_ARG; | |
| case TYPE_BZ: /* Branch, three operands */ | |
| case TYPE_M: /* Move opcode */ | |
| if (*cptr == '\0') { | |
| val[i++] = (op->opbase >> 6) & 077; | |
| return -(i-1); | |
| } | |
| break; | |
| } | |
| if (*cptr != ',') | |
| return SCPE_ARG; | |
| cptr++; | |
| /* Skip blanks */ | |
| while(isspace(*cptr)) cptr++; | |
| /* Pick up at least one address & possible index */ | |
| addr = 0; | |
| while(*cptr != '\0') { | |
| if (*cptr >= '0' && *cptr <= '9') | |
| addr = (addr * 10) + (*cptr++ - '0'); | |
| else if (*cptr == '+' || *cptr == ',') | |
| break; | |
| } | |
| /* Convert to BCD */ | |
| for(j = 4; j >= 0;j--) { | |
| buffer[j] = addr % 10; | |
| if (buffer[j] == 0) | |
| buffer[j] = 10; | |
| addr /= 10; | |
| } | |
| /* Merge in index bits if any */ | |
| if (*cptr == '+') { | |
| int n = 0; | |
| cptr++; | |
| if (*cptr != 'X' && *cptr != 'x') | |
| return SCPE_ARG; | |
| cptr++; | |
| if (!(*cptr >= '0' && *cptr <= '9')) | |
| return SCPE_ARG; | |
| n = *cptr++ - '0'; | |
| if (*cptr >= '0' && *cptr <= '9') | |
| n = (n * 10) + (*cptr++ - '0'); | |
| if (n > 16) | |
| return SCPE_ARG; | |
| buffer[3] |= (n & 3) << 4; | |
| buffer[2] |= (n & 014) << 2; | |
| } | |
| /* Copy over address */ | |
| for(j = 0; j <= 4; j++) | |
| val[i++] = buffer[j]; | |
| /* Skip blanks */ | |
| while(isspace(*cptr)) cptr++; | |
| switch(op->type) { | |
| case TYPE_M: /* Move opcode */ | |
| val[i++] = (op->opbase >> 6) & 077; | |
| /* fall through */ | |
| default: | |
| case TYPE_IO: /* Tape opcode, option */ | |
| case TYPE_T: /* Tape opcode, option */ | |
| case TYPE_1: /* One operand, no options */ | |
| case TYPE_B: /* Branch, one operand, option */ | |
| case TYPE_Y: /* Store special */ | |
| case TYPE_2: /* Two operands, no options */ | |
| if (*cptr == '\0') | |
| return -(i - 1); | |
| break; | |
| case TYPE_BE: /* Branch, three operands */ | |
| if (*cptr == ',') { | |
| val[i++] = ascii_to_six[(int)*++cptr]; | |
| while(isspace(*++cptr)); | |
| } | |
| if (*cptr == '\0') | |
| return -(i - 1); | |
| break; | |
| case TYPE_BZ: /* Branch, three operands */ | |
| if (*cptr == '\0') { | |
| val[i++] = (op->opbase >> 6) & 077; | |
| return -(i-1); | |
| } else if (*cptr == ',') { | |
| d = (op->opbase >> 6) & 077; | |
| cptr++; | |
| /* Skip blanks */ | |
| while(isspace(*cptr)) cptr++; | |
| while(*cptr != '\0') { | |
| if (*cptr == 'A' || *cptr == 'a') | |
| d |= 020; | |
| else if (*cptr == 'B' || *cptr == 'b') | |
| d |= 040; | |
| else | |
| return SCPE_ARG; | |
| cptr++; | |
| } | |
| val[i++] = d; | |
| return -(i-1); | |
| } | |
| } | |
| return SCPE_ARG; | |
| } else { | |
| int sign = 0; | |
| i = 0; | |
| wm_seen = 1; | |
| while (*cptr != '\0') { | |
| sign = 0; | |
| /* Skip blanks */ | |
| while(isspace(*cptr)) cptr++; | |
| if (*cptr == '+') { | |
| cptr++; | |
| sign = 1; | |
| } else if (*cptr == '-') { | |
| cptr++; | |
| sign = -1; | |
| } | |
| if (!(*cptr >= '0' && *cptr <= '9')) | |
| return SCPE_ARG; | |
| while(*cptr >= '0' && *cptr <= '9') { | |
| d = *cptr++ - '0'; | |
| if (d == 0) | |
| d = 10; | |
| if (wm_seen) { | |
| d |= WM; | |
| wm_seen = 0; | |
| } | |
| val[i++] = d; | |
| } | |
| if (*cptr == ',') | |
| cptr++; | |
| if (sign != 0) | |
| val[i-1] |= (sign < 0)?040:060; /* Set sign last digit */ | |
| } | |
| if (i == 0) | |
| return SCPE_ARG; | |
| return -(i - 1); | |
| } | |
| return SCPE_OK; | |
| } |