blob: 3eda26547f55b0e7e7db864c3a8e8b11a2fbedb6 [file] [log] [blame] [raw]
/* b5500_sys.c: Burroughs 5500 Simulator system interface.
Copyright (c) 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 "sim_defs.h"
#include "b5500_defs.h"
#include "sim_card.h"
#include <ctype.h>
t_stat parse_sym(CONST char *cptr, t_addr addr, UNIT * uptr, t_value * val, int32 sw);
/* 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[] = "B5500";
REG *sim_PC = &cpu_reg[0];
int32 sim_emax = 1;
DEVICE *sim_devices[] = {
&cpu_dev,
&chan_dev,
#if NUM_DEVS_CDR > 0
&cdr_dev,
#endif
#if NUM_DEVS_CDP > 0
&cdp_dev,
#endif
#if NUM_DEVS_LPR > 0
&lpr_dev,
#endif
#if NUM_DEVS_CON > 0
&con_dev,
#endif
#if NUM_DEVS_MT > 0
&mt_dev,
#endif
#if NUM_DEVS_DR > 0
&drm_dev,
#endif
#if NUM_DEVS_DSK > 0
&esu_dev,
&dsk_dev,
#endif
#if NUM_DEVS_DTC > 0
&dtc_dev,
#endif
NULL
};
/* Simulator stop codes */
const char *sim_stop_messages[] = {
0,
};
/* Simulator debug controls */
DEBTAB dev_debug[] = {
{"CMD", DEBUG_CMD, "Show command execution to devices"},
{"DATA", DEBUG_DATA, "Show data transfers"},
{"DETAIL", DEBUG_DETAIL, "Show details about device"},
{"EXP", DEBUG_EXP, "Show exception information"},
{0, 0}
};
uint8 parity_table[64] = {
/* 0 1 2 3 4 5 6 7 */
0000, 0100, 0100, 0000, 0100, 0000, 0000, 0100,
0100, 0000, 0000, 0100, 0000, 0100, 0100, 0000,
0100, 0000, 0000, 0100, 0000, 0100, 0100, 0000,
0000, 0100, 0100, 0000, 0100, 0000, 0000, 0100,
0100, 0000, 0000, 0100, 0000, 0100, 0100, 0000,
0000, 0100, 0100, 0000, 0100, 0000, 0000, 0100,
0000, 0100, 0100, 0000, 0100, 0000, 0000, 0100,
0100, 0000, 0000, 0100, 0000, 0100, 0100, 0000
};
uint8 mem_to_ascii[64] = {
/* x0 x1 x2 x3 x4 x5 x6 x7 */
'0', '1', '2', '3', '4', '5', '6', '7', /* 0x */
'8', '9', '#', '@', '?', ':', '>', '}', /* 1x */
'+', 'A', 'B', 'C', 'D', 'E', 'F', 'G', /* 2x */
'H', 'I', '.', '[', '&', '(', '<', '~', /* 3x */
'|', 'J', 'K', 'L', 'M', 'N', 'O', 'P', /* 4x */
'Q', 'R', '$', '*', '-', ')', ';', '{', /* 5x */
' ', '/', 'S', 'T', 'U', 'V', 'W', 'X', /* 6x */
'Y', 'Z', ',', '%', '!', '=', ']', '"' /* 7x */
};
const char con_to_ascii[64] = {
'?', '1', '2', '3', '4', '5', '6', '7',
'8', '9', '0', '#', '@', ':', '>', '}', /* 17 = box */
' ', '/', 'S', 'T', 'U', 'V', 'W', 'X',
'Y', 'Z', '!', ',', '%', '=', ']', '"',
'-', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
'Q', 'R', '|', '$', '*', ')', ';', '{', /* 57 = triangle */
'&', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
'H', 'I', '+', '.', '[', '(', '<', '~', /* 37 = stop code */
}; /* 72 = rec mark */
/* 75 = squiggle, 77 = del */
const char ascii_to_con[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 ! " # $ % & ' */
020, 032, 037, 013, 053, 034, 060, 014, /* 40 - 77 */
/* ( ) * + , - . / */
075, 055, 054, 072, 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, 035, 016, 000,
/* @ 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, 074, 036, 036, 057, 000,
/* ` 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, 052, 017, -1, -1
};
/* Load a card image file into memory. */
t_stat
sim_load(FILE * fileref, CONST char *cptr, CONST char *fnam, int flag)
{
/* Currently not implimented until I know format of load files */
return SCPE_NOFNC;
}
#define TYPE_A 1 /* Full 12 bit opcode */
#define TYPE_B 2 /* 6 Bit Opcode with 6 bit field */
#define TYPE_C 3 /* 8 Bit opcode with 4 bit field */
#define TYPE_D 4 /* 2 bit opcode, 10 bit field */
/* Opcodes */
t_opcode word_ops[] = {
/* Word mode opcodes */
WMOP_LITC, TYPE_D, "LITC", /* Load literal */
WMOP_OPDC, TYPE_D, "OPDC", /* Load operand */
WMOP_DESC, TYPE_D, "DESC", /* Load Descriptor */
WMOP_DEL, TYPE_A, "DEL", /* Delete top of stack */
WMOP_NOP, TYPE_A, "NOP", /* Nop operation */
WMOP_XRT, TYPE_A, "XRT", /* Set Variant */
WMOP_ADD, TYPE_A, "ADD", /* Add */
WMOP_DLA, TYPE_A, "DLA", /* Double Precision Add */
WMOP_PRL, TYPE_A, "PRL", /* Program Release */
WMOP_LNG, TYPE_A, "LNG", /* Logical Negate */
WMOP_CID, TYPE_A, "CID", /* Conditional Integer Store Destructive */
WMOP_GEQ, TYPE_A, "GEQ", /* B greater than or equal to A */
WMOP_BBC, TYPE_A, "BBC", /* Branch Backward Conditional */
WMOP_BRT, TYPE_A, "BRT", /* Branch Return */
WMOP_INX, TYPE_A, "INX", /* Index */
WMOP_ITI, TYPE_A, "ITI", /* Interrogate interrupt */
WMOP_LOR, TYPE_A, "LOR", /* Logical Or */
WMOP_CIN, TYPE_A, "CIN", /* Conditional Integer Store non-destructive */
WMOP_GTR, TYPE_A, "GTR", /* B Greater than A */
WMOP_BFC, TYPE_A, "BFC", /* Branch Forward Conditional */
WMOP_RTN, TYPE_A, "RTN", /* Return normal */
WMOP_COC, TYPE_A, "COC", /* Construct Operand Call */
WMOP_SUB, TYPE_A, "SUB", /* Subtract */
WMOP_DLS, TYPE_A, "DLS", /* Double Precision Subtract */
WMOP_MUL, TYPE_A, "MUL", /* Multiply */
WMOP_DLM, TYPE_A, "DLM", /* Double Precision Multiply */
WMOP_RTR, TYPE_A, "RTR", /* Read Timer */
WMOP_LND, TYPE_A, "LND", /* Logical And */
WMOP_STD, TYPE_A, "STD", /* B Store Destructive */
WMOP_NEQ, TYPE_A, "NEQ", /* B Not equal to A */
WMOP_SSN, TYPE_A, "SSN", /* Set Sign Bit */
WMOP_XIT, TYPE_A, "XIT", /* Exit */
WMOP_MKS, TYPE_A, "MKS", /* Mark Stack */
WMOP_DIV, TYPE_A, "DIV", /* Divide */
WMOP_DLD, TYPE_A, "DLD", /* Double Precision Divide */
WMOP_COM, TYPE_A, "COM", /* Communication operator */
WMOP_LQV, TYPE_A, "LQV", /* Logical Equivalence */
WMOP_SND, TYPE_A, "SND", /* B Store Non-destructive */
WMOP_XCH, TYPE_A, "XCH", /* Exchange */
WMOP_CHS, TYPE_A, "CHS", /* Change sign bit */
WMOP_RTS, TYPE_A, "RTS", /* Return Special */
WMOP_CDC, TYPE_A, "CDC", /* Construct descriptor call */
WMOP_FTC, TYPE_A, "FTC", /* Transfer F Field to Core Field */
WMOP_MOP, TYPE_A, "MOP", /* Reset Flag bit */
WMOP_LOD, TYPE_A, "LOD", /* Load */
WMOP_DUP, TYPE_A, "DUP", /* Duplicate */
WMOP_TOP, TYPE_A, "TOP", /* Test Flag Bit */
WMOP_IOR, TYPE_A, "IOR", /* I/O Release */
WMOP_LBC, TYPE_A, "LBC", /* Word Branch Backward Conditional */
WMOP_SSF, TYPE_A, "SSF", /* Set or Store S or F registers */
WMOP_HP2, TYPE_A, "HP2", /* Halt P2 */
WMOP_LFC, TYPE_A, "LFC", /* Word Branch Forward Conditional */
WMOP_ZP1, TYPE_A, "ZP1", /* Conditional Halt */
WMOP_TUS, TYPE_A, "TUS", /* Interrogate Peripheral Status */
WMOP_LLL, TYPE_A, "LLL", /* Link List Look-up */
WMOP_IDV, TYPE_A, "IDV", /* Integer Divide Integer */
WMOP_SFI, TYPE_A, "SFI", /* Store for Interrupt */
WMOP_SFT, TYPE_A, "SFT", /* Store for Test */
WMOP_FTF, TYPE_A, "FTF", /* Transfer F Field to F Field */
WMOP_MDS, TYPE_A, "MDS", /* Set Flag Bit */
WMOP_IP1, TYPE_A, "IP1", /* Initiate P1 */
WMOP_ISD, TYPE_A, "ISD", /* Interger Store Destructive */
WMOP_LEQ, TYPE_A, "LEQ", /* B Less Than or Equal to A */
WMOP_BBW, TYPE_A, "BBW", /* Banch Backward Conditional */
WMOP_IP2, TYPE_A, "IP2", /* Initiate P2 */
WMOP_ISN, TYPE_A, "ISN", /* Integer Store Non-Destructive */
WMOP_LSS, TYPE_A, "LSS", /* B Less Than A */
WMOP_BFW, TYPE_A, "BFW", /* Branch Forward Unconditional */
WMOP_IIO, TYPE_A, "IIO", /* Initiate I/O */
WMOP_EQL, TYPE_A, "EQL", /* B Equal A */
WMOP_SSP, TYPE_A, "SSP", /* Reset Sign Bit */
WMOP_CMN, TYPE_A, "CMN", /* Enter Character Mode In Line */
WMOP_IFT, TYPE_A, "IFT", /* Test Initiate */
WMOP_CTC, TYPE_A, "CTC", /* Transfer Core Field to Core Field */
WMOP_LBU, TYPE_A, "LBU", /* Word Branch Backward Unconditional */
WMOP_LFU, TYPE_A, "LFU", /* Word Branch Forward Unconditional */
WMOP_TIO, TYPE_A, "TIO", /* Interrogate I/O Channels */
WMOP_RDV, TYPE_A, "RDV", /* Remainder Divide */
WMOP_FBS, TYPE_A, "FBS", /* Flag Bit Search */
WMOP_CTF, TYPE_A, "CTF", /* Transfer Core Field to F Field */
WMOP_ISO, TYPE_B, "ISO", /* Variable Field Isolate XX */
WMOP_CBD, TYPE_C, "CBD", /* Non-Zero Field Branch Backward Destructive Xy */
WMOP_CBN, TYPE_C, "CBN", /* Non-Zero Field Branch Backward Non-Destructive Xy */
WMOP_CFD, TYPE_C, "CFD", /* Non-Zero Field Branch Forward Destructive Xy */
WMOP_CFN, TYPE_B, "CFN", /* Non-Zero Field Branch Forward Non-Destructive Xy */
WMOP_DIA, TYPE_B, "DIA", /* Dial A XX */
WMOP_DIB, TYPE_B, "DIB", /* Dial B XX Upper 6 not Zero */
WMOP_TRB, TYPE_B, "TRB", /* Transfer Bits XX */
WMOP_FCL, TYPE_B, "FCL", /* Compare Field Low XX */
WMOP_FCE, TYPE_B, "FCE", /* Compare Field Equal XX */
{0, 0, NULL},
};
t_opcode char_ops[] = {
/* Character Mode */
CMOP_EXC, TYPE_A, "EXC", /* Exit Character Mode */
CMOP_CMX, TYPE_A, "CMX", /* Exit Character Mode In Line */
CMOP_BSD, TYPE_B, "BSD", /* Skip Bit Destiniation */
CMOP_BSS, TYPE_B, "BSS", /* SKip Bit Source */
CMOP_RDA, TYPE_B, "RDA", /* Recall Destination Address */
CMOP_TRW, TYPE_B, "TRW", /* Transfer Words */
CMOP_SED, TYPE_B, "SED", /* Set Destination Address */
CMOP_TDA, TYPE_B, "TDA", /* Transfer Destination Address */
CMOP_TBN, TYPE_B, "TBN", /* Transfer Blanks for Non-Numerics */
WMOP_ITI, TYPE_A, "ITI", /* Interrogate interrupt */
WMOP_SFI, TYPE_A, "SFI", /* Store for Interrupt */
WMOP_SFT, TYPE_A, "SFT", /* Store for Test */
WMOP_ZP1, TYPE_A, "ZP1", /* Conditional Halt */
WMOP_HP2, TYPE_A, "HP2", /* Halt P2 */
CMOP_SDA, TYPE_B, "SDA", /* Store Destination Address */
CMOP_SSA, TYPE_B, "SSA", /* Store Source Address */
CMOP_SFD, TYPE_B, "SFD", /* Skip Forward Destination */
CMOP_SRD, TYPE_B, "SRD", /* Skip Reverse Destination */
CMOP_SES, TYPE_B, "SES", /* Set Source Address */
CMOP_TEQ, TYPE_B, "TEQ", /* Test for Equal */
CMOP_TNE, TYPE_B, "TNE", /* Test for Not-Equal */
CMOP_TEG, TYPE_B, "TEG", /* Test for Greater Or Equal */
CMOP_TGR, TYPE_B, "TGR", /* Test For Greater */
CMOP_SRS, TYPE_B, "SRS", /* Skip Reverse Source */
CMOP_SFS, TYPE_B, "SFS", /* Skip Forward Source */
CMOP_TEL, TYPE_B, "TEL", /* Test For Equal or Less */
CMOP_TLS, TYPE_B, "TLS", /* Test For Less */
CMOP_TAN, TYPE_B, "TAN", /* Test for Alphanumeric */
CMOP_BIT, TYPE_B, "BIT", /* Test Bit */
CMOP_INC, TYPE_B, "INC", /* Increase Tally */
CMOP_STC, TYPE_B, "STC", /* Store Tally */
CMOP_SEC, TYPE_B, "SEC", /* Set Tally */
CMOP_CRF, TYPE_B, "CRF", /* Call repeat Field */
CMOP_JNC, TYPE_B, "JNC", /* Jump Out Of Loop Conditional */
CMOP_JFC, TYPE_B, "JFC", /* Jump Forward Conditional */
CMOP_JNS, TYPE_B, "JNS", /* Jump out of loop unconditional */
CMOP_JFW, TYPE_B, "JFW", /* Jump Forward Unconditional */
CMOP_RCA, TYPE_B, "RCA", /* Recall Control Address */
CMOP_ENS, TYPE_B, "ENS", /* End Loop */
CMOP_BNS, TYPE_B, "BNS", /* Begin Loop */
CMOP_RSA, TYPE_B, "RSA", /* Recall Source Address */
CMOP_SCA, TYPE_B, "SCA", /* Store Control Address */
CMOP_JRC, TYPE_B, "JRC", /* Jump Reverse Conditional */
CMOP_TSA, TYPE_B, "TSA", /* Transfer Source Address */
CMOP_JRV, TYPE_B, "JRV", /* Jump Reverse Unconditional */
CMOP_CEQ, TYPE_B, "CEQ", /* Compare Equal */
CMOP_CNE, TYPE_B, "CNE", /* COmpare for Not Equal */
CMOP_CEG, TYPE_B, "CEG", /* Compare For Greater Or Equal */
CMOP_CGR, TYPE_B, "CGR", /* Compare For Greater */
CMOP_BIS, TYPE_B, "BIS", /* Set Bit */
CMOP_BIR, TYPE_B, "BIR", /* Reet Bit */
CMOP_OCV, TYPE_B, "OCV", /* Output Convert */
CMOP_ICV, TYPE_B, "ICV", /* Input Convert */
CMOP_CEL, TYPE_B, "CEL", /* Compare For Equal or Less */
CMOP_CLS, TYPE_B, "CLS", /* Compare for Less */
CMOP_FSU, TYPE_B, "FSU", /* Field Subtract */
CMOP_FAD, TYPE_B, "FAD", /* Field Add */
CMOP_TRP, TYPE_B, "TRP", /* Transfer Program Characters */
CMOP_TRN, TYPE_B, "TRN", /* Transfer Numeric */
CMOP_TRZ, TYPE_B, "TRZ", /* Transfer Zones */
CMOP_TRS, TYPE_B, "TRS", /* Transfer Source Characters */
{0, 0, NULL},
};
/* Print out an instruction */
void
print_opcode(FILE * of, t_value val, int chr_mode)
{
uint16 op;
t_opcode *tab = (chr_mode) ? char_ops: word_ops;
op = val;
while (tab->name != NULL) {
switch(tab->type) {
case TYPE_A:
if (op != tab->op)
break;
fputs(tab->name, of);
fputs(" ",of);
return;
case TYPE_B:
if ((op & 077) != tab->op)
break;
fputs(tab->name, of);
fputc(' ',of);
fputc(' ',of);
fprint_val(of, (val >> 6), 8, 6, 0);
fputs(" ",of);
return;
case TYPE_C:
if ((op & 0377) != tab->op)
break;
fputs(tab->name, of);
fputc(' ',of);
fprint_val(of, (val >> 8), 8, 4, 0);
fputs(" ",of);
return;
case TYPE_D:
if ((op & 03) != tab->op)
break;
fputs(tab->name, of);
fputc(' ',of);
fprint_val(of, (val >> 2), 8, 10, 0);
fputc(' ',of);
return;
}
tab++;
}
fprintf(of, "*%04o uuo ", op);
}
/* 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)
{
t_value inst = *val;
int i;
fputc(' ', of);
fprint_val(of, inst, 8, 48, PV_RZRO);
if (sw & SWMASK('W')) { /* Word mode opcodes */
fputs(" ", of);
for (i = 36; i >= 0; i-=12) {
int op = (int)(inst >> i) & 07777;
print_opcode(of, op, 0);
}
}
if (sw & SWMASK('C')) { /* Char mode opcodes */
fputs(" ", of);
for (i = 36; i >= 0; i-=12) {
int op = (int)(inst >> i) & 07777;
print_opcode(of, op, 1);
}
}
if (sw & SWMASK('B')) { /* BCD mode */
fputs(" '", of);
for (i = 42; i >= 0; i-=6) {
int ch;
ch = (int)(inst >> i) & 077;
fputc(mem_to_ascii[ch], of);
}
fputc('\'', of);
}
if (sw & SWMASK('F')) { /* Floating point/Descriptor */
}
return SCPE_OK;
}
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;
int opr;
char opcode[100];
while (isspace(*cptr))
cptr++;
d = 0;
if (sw & (SWMASK('W')|SWMASK('C'))) {
t_opcode *op;
/* Grab opcode */
cptr = get_glyph(cptr, opcode, 0);
op = 0;
opr = -1;
if((op = find_opcode(opcode,
(SWMASK('W') ? word_ops : char_ops))) == 0) {
return SCPE_UNK;
}
while (*cptr == ' ' || *cptr == '\t')
cptr++;
/* Collect first argument if there is one */
while (*cptr >= '0' && *cptr <= '7')
opr = (opr << 3) + (*cptr++ - '0');
/* Skip blanks */
while (*cptr == ' ' || *cptr == '\t')
cptr++;
switch (op->type) {
case TYPE_A:
if (opr >= 0)
return SCPE_2MARG;
*val = op->op;
return SCPE_OK;
case TYPE_B:
if (opr < 0 || opr > 64)
return SCPE_ARG;
*val = (opr << 6) | op->op;
return SCPE_OK;
case TYPE_C:
if (opr < 0 || opr > 16)
return SCPE_ARG;
*val = (opr << 8) | op->op;
return SCPE_OK;
case TYPE_D:
if (opr < 0 || opr > 1024)
return SCPE_ARG;
*val = (opr << 2) | op->op;
return SCPE_OK;
}
} else if (sw & SWMASK('B')) {
i = 0;
while (*cptr != '\0' && i < 8) {
d <<= 6;
d |= (int)sim_ascii_to_six[0177 & *cptr];
cptr++;
i++;
}
d <<= 6 * (8 - i);
} else {
while (*cptr >= '0' && *cptr <= '7') {
d <<= 3;
d |= *cptr++ - '0';
}
}
*val = d;
return SCPE_OK;
}