diff --git a/0readme_310.txt b/0readme_310.txt new file mode 100644 index 00000000..1eae0682 --- /dev/null +++ b/0readme_310.txt @@ -0,0 +1,61 @@ +Notes For V3.10 + +3.10 is mostly an attempt to get aligned with the current head of the +GitHub 4.0 sources. While the core libraries and SCP have diverged too +far for real forward and backward compatibility, enough 4.0 workalikes +have been added to allow much closer convergence of the two streams. + +3.10 will provide the basis for my future simulation work. + + +1. New Features + +1.1 SCP and libraries + +- -n added in ATTACH, meaning "force new file" + +1.2 1401 + +- option to read cards from the console terminal window +- option to print line printer output in the console terminal window + +1.3 1620 + +- tab stop support added to console terminal + +1.4 PDP-8 + +- LOAD command now supports multi-segment binary tapes + +1.5 PDP11 + +- added RS03/RS04 Massbus fixed head disk support + + +2. Bugs Fixed + +Please see the revision history on http://simh.trailing-edge.com or +in the source module sim_rev.h. + + +3. Status Report + +The main branch of SimH is maintained in a public repository + + https://github.com/simh/simh + +under the general editorship of Dave Hittner and Mark Pizzolato. The +3.X branch provides a simpler environment for debugging, for my taste. + +Because of divergences between 3.X and 4.0, certain features in 4.0 +cannot work in 3.X and are not present: + +PDP11/VAX/PDP10 - DUP11 and DMC11 synchronous network interfaces + +PDP10 - front- end keep-alive timer + +H316 - IMP network interface + +In addition, the PDP11 DZ, VH, XQ, and XU implementations are significantly +"down rev" compared to 4.0, due to differences in supporting libraries. + diff --git a/ALTAIR/altair_cpu.c b/ALTAIR/altair_cpu.c index 80fce7d6..8c79acd8 100644 --- a/ALTAIR/altair_cpu.c +++ b/ALTAIR/altair_cpu.c @@ -25,6 +25,7 @@ cpu 8080 CPU + 02-Feb-15 RSB Fixed initialization of "uninstalled" memory 19-Mar-12 RMS Fixed data type for breakpoint variables 08-Oct-02 RMS Tied off spurious compiler warnings @@ -67,7 +68,7 @@ 3. Non-existent memory. On the 8080, reads to non-existent memory return 0377, and writes are ignored. In the simulator, the - largest possible memory is instantiated and initialized to zero. + largest possible memory is instantiated and initialized to 0377. Thus, only writes need be checked against actual memory size. 4. Adding I/O devices. These modules must be modified: @@ -107,9 +108,6 @@ int32 chip = 0; /* 0 = 8080 chip, 1 = z8 int32 PCX; /* External view of PC */ -extern int32 sim_int_char; -extern uint32 sim_brk_types, sim_brk_dflt, sim_brk_summ;/* breakpoint info */ - /* function prototypes */ t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); @@ -300,9 +298,8 @@ DEVICE cpu_dev = { NULL, NULL, NULL }; -int32 sim_instr (void) +t_stat sim_instr (void) { - extern int32 sim_interval; int32 PC, IR, OP, DAR, reason, hi, lo, carry, i; PC = saved_PC & ADDRMASK; /* load local PC */ @@ -313,7 +310,7 @@ int32 sim_instr (void) while (reason == 0) { /* loop until halted */ if (sim_interval <= 0) { /* check clock queue */ - if (reason = sim_process_event ()) break; + if ((reason = sim_process_event ())) break; } if (int_req > 0) { /* interrupt? */ @@ -366,7 +363,7 @@ int32 sim_instr (void) if ((OP & 0xCF) == 0x01) { /* LXI */ DAR = M[PC] & 0x00ff; PC++; - DAR = DAR | (M[PC] <<8) & 0xFF00;; + DAR = DAR | ((M[PC] <<8) & 0xFF00); putpair((OP >> 4) & 0x03, DAR); PC++; continue; @@ -1177,7 +1174,7 @@ for (i = val; i < MEMSIZE; i++) mc = mc | M[i]; if ((mc != 0) && (!get_yn ("Really truncate memory [N]?", FALSE))) return SCPE_OK; MEMSIZE = val; -for (i = MEMSIZE; i < MAXMEMSIZE; i++) M[i] = 0; +for (i = MEMSIZE; i < MAXMEMSIZE; i++) M[i] = 0377; return SCPE_OK; } diff --git a/ALTAIR/altair_defs.h b/ALTAIR/altair_defs.h index ca8444a9..b911f755 100644 --- a/ALTAIR/altair_defs.h +++ b/ALTAIR/altair_defs.h @@ -24,19 +24,19 @@ in this Software without prior written authorization from Charles E. Owen. */ -#include "sim_defs.h" /* simulator defns */ +#include "sim_defs.h" /* simulator defns */ /* Memory */ -#define MAXMEMSIZE 65536 /* max memory size */ -#define MEMSIZE (cpu_unit.capac) /* actual memory size */ -#define ADDRMASK (MAXMEMSIZE - 1) /* address mask */ -#define MEM_ADDR_OK(x) (((uint32) (x)) < MEMSIZE) +#define MAXMEMSIZE 65536 /* max memory size */ +#define MEMSIZE (cpu_unit.capac) /* actual memory size */ +#define ADDRMASK (MAXMEMSIZE - 1) /* address mask */ +#define MEM_ADDR_OK(x) (((uint32) (x)) < MEMSIZE) /* Simulator stop codes */ -#define STOP_RSRV 1 /* must be 1 */ -#define STOP_HALT 2 /* HALT */ -#define STOP_IBKPT 3 /* breakpoint */ -#define STOP_OPCODE 4 +#define STOP_RSRV 1 /* must be 1 */ +#define STOP_HALT 2 /* HALT */ +#define STOP_IBKPT 3 /* breakpoint */ +#define STOP_OPCODE 4 diff --git a/ALTAIR/altair_sys.c b/ALTAIR/altair_sys.c index fa32695a..c6e82e75 100644 --- a/ALTAIR/altair_sys.c +++ b/ALTAIR/altair_sys.c @@ -153,7 +153,7 @@ int32 oplen[256] = { load starts at the current value of the PC. */ -int32 sim_load (FILE *fileref, char *cptr, char *fnam, int flag) +t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag) { int32 i, addr = 0, cnt = 0; @@ -164,7 +164,7 @@ while ((i = getc (fileref)) != EOF) { addr++; cnt++; } /* end while */ -printf ("%d Bytes loaded.\n", cnt); +sim_printf ("%d Bytes loaded.\n", cnt); return (SCPE_OK); } @@ -180,7 +180,7 @@ return (SCPE_OK); status = error code */ -int32 fprint_sym (FILE *of, int32 addr, uint32 *val, +t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, UNIT *uptr, int32 sw) { int32 cflag, c1, c2, inst, adr; @@ -229,7 +229,7 @@ return -(oplen[inst] - 1); status = error status */ -int32 parse_sym (char *cptr, int32 addr, UNIT *uptr, uint32 *val, int32 sw) +t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw) { int32 cflag, i = 0, j, r; char gbuf[CBUFSIZE]; diff --git a/AltairZ80/altairz80_cpu.c b/AltairZ80/altairz80_cpu.c index 7b4e7a5c..9d7c6580 100644 --- a/AltairZ80/altairz80_cpu.c +++ b/AltairZ80/altairz80_cpu.c @@ -1,6 +1,6 @@ /* altairz80_cpu.c: MITS Altair CPU (8080 and Z80) - Copyright (c) 2002-2011, Peter Schorn + Copyright (c) 2002-2012, Peter Schorn Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -75,57 +75,58 @@ /* CHECK_CPU_8080 must be invoked whenever a Z80 only instruction is executed In case a Z80 instruction is executed on an 8080 the following two cases exist: 1) Trapping is enabled: execution stops - 2) Trapping is not enabled: decoding continues with the next byte + 2) Trapping is not enabled: decoding continues with the next byte, i.e. interpret as NOP + Note: in some cases different instructions need to be chosen on 8080 */ -#define CHECK_CPU_8080 \ - if (chiptype == CHIP_TYPE_8080) { \ - if (cpu_unit.flags & UNIT_CPU_OPSTOP) { \ - reason = STOP_OPCODE; \ - goto end_decode; \ - } \ - else { \ - sim_brk_pend[0] = FALSE; \ - continue; \ - } \ +#define CHECK_CPU_8080 \ + if (chiptype == CHIP_TYPE_8080) { \ + if (cpu_unit.flags & UNIT_CPU_OPSTOP) { \ + reason = STOP_OPCODE; \ + goto end_decode; \ + } \ + else { \ + sim_brk_pend[0] = FALSE; \ + continue; \ + } \ } /* CHECK_CPU_Z80 must be invoked whenever a non Z80 instruction is executed */ -#define CHECK_CPU_Z80 \ - if (cpu_unit.flags & UNIT_CPU_OPSTOP) { \ - reason = STOP_OPCODE; \ - goto end_decode; \ +#define CHECK_CPU_Z80 \ + if (cpu_unit.flags & UNIT_CPU_OPSTOP) { \ + reason = STOP_OPCODE; \ + goto end_decode; \ } -#define POP(x) { \ - register uint32 y = RAM_PP(SP); \ - x = y + (RAM_PP(SP) << 8); \ +#define POP(x) { \ + register uint32 y = RAM_PP(SP); \ + x = y + (RAM_PP(SP) << 8); \ } -#define JPC(cond) { \ - tStates += 10; \ - if (cond) { \ - PCQ_ENTRY(PCX); \ - PC = GET_WORD(PC); \ - } \ - else { \ - PC += 2; \ - } \ +#define JPC(cond) { \ + tStates += 10; \ + if (cond) { \ + PCQ_ENTRY(PCX); \ + PC = GET_WORD(PC); \ + } \ + else { \ + PC += 2; \ + } \ } -#define CALLC(cond) { \ - if (cond) { \ - register uint32 adrr = GET_WORD(PC); \ - CHECK_BREAK_WORD(SP - 2); \ - PUSH(PC + 2); \ - PCQ_ENTRY(PCX); \ - PC = adrr; \ - tStates += 17; \ - } \ - else { \ - sim_brk_pend[0] = FALSE; \ - PC += 2; \ - tStates += 10; \ - } \ +#define CALLC(cond) { \ + if (cond) { \ + register uint32 adrr = GET_WORD(PC); \ + CHECK_BREAK_WORD(SP - 2); \ + PUSH(PC + 2); \ + PCQ_ENTRY(PCX); \ + PC = adrr; \ + tStates += 17; \ + } \ + else { \ + sim_brk_pend[0] = FALSE; \ + PC += 2; \ + tStates += (chiptype == CHIP_TYPE_8080 ? 11 : 10); \ + } \ } extern int32 sim_int_char; @@ -1777,12 +1778,12 @@ static int32 sim_brk_lookup (const t_addr loc, const int32 btyp) { extern char *sim_brk_act; BRKTAB *bp; if ((bp = sim_brk_fnd (loc)) && /* entry in table? */ - (btyp & bp -> typ) && /* type match? */ + (btyp & bp->typ) && /* type match? */ (!sim_brk_pend[0] || (loc != sim_brk_ploc[0])) && /* new location? */ - (--(bp -> cnt) <= 0)) { /* count reach 0? */ - bp -> cnt = 0; /* reset count */ + (--(bp->cnt) <= 0)) { /* count reach 0? */ + bp->cnt = 0; /* reset count */ sim_brk_ploc[0] = loc; /* save location */ - sim_brk_act = bp -> act; /* set up actions */ + sim_brk_act = bp->act; /* set up actions */ sim_brk_pend[0] = TRUE; /* don't do twice */ return TRUE; } @@ -2023,31 +2024,31 @@ static t_stat sim_instr_mmu (void) { switch(RAM_PP(PC)) { case 0x00: /* NOP */ - tStates += 4; + tStates += 4; /* NOP 4 */ sim_brk_pend[0] = FALSE; break; case 0x01: /* LD BC,nnnn */ - tStates += 10; + tStates += 10; /* LXI B,nnnn 10 */ sim_brk_pend[0] = FALSE; BC = GET_WORD(PC); PC += 2; break; case 0x02: /* LD (BC),A */ - tStates += 7; + tStates += 7; /* STAX B 7 */ CHECK_BREAK_BYTE(BC) PutBYTE(BC, HIGH_REGISTER(AF)); break; case 0x03: /* INC BC */ - tStates += 6; + tStates += (chiptype == CHIP_TYPE_8080 ? 5 : 6); /* INX B 5 */ sim_brk_pend[0] = FALSE; ++BC; break; case 0x04: /* INC B */ - tStates += 4; + tStates += (chiptype == CHIP_TYPE_8080 ? 5 : 4); /* INR B 5 */ sim_brk_pend[0] = FALSE; BC += 0x100; temp = HIGH_REGISTER(BC); @@ -2055,7 +2056,7 @@ static t_stat sim_instr_mmu (void) { break; case 0x05: /* DEC B */ - tStates += 4; + tStates += (chiptype == CHIP_TYPE_8080 ? 5 : 4); /* DCR B 5 */ sim_brk_pend[0] = FALSE; BC -= 0x100; temp = HIGH_REGISTER(BC); @@ -2063,20 +2064,20 @@ static t_stat sim_instr_mmu (void) { break; case 0x06: /* LD B,nn */ - tStates += 7; + tStates += 7; /* MVI B,nn 7 */ sim_brk_pend[0] = FALSE; SET_HIGH_REGISTER(BC, RAM_PP(PC)); break; case 0x07: /* RLCA */ - tStates += 4; + tStates += 4; /* RLC 4 */ sim_brk_pend[0] = FALSE; AF = ((AF >> 7) & 0x0128) | ((AF << 1) & ~0x1ff) | (AF & 0xc4) | ((AF >> 15) & 1); break; case 0x08: /* EX AF,AF' */ - tStates += 4; + tStates += 4; /* NOP 4 */ sim_brk_pend[0] = FALSE; CHECK_CPU_8080; temp = AF; @@ -2085,7 +2086,7 @@ static t_stat sim_instr_mmu (void) { break; case 0x09: /* ADD HL,BC */ - tStates += 11; + tStates += (chiptype == CHIP_TYPE_8080 ? 10 : 11); /* DAD B 10 */ sim_brk_pend[0] = FALSE; HL &= ADDRMASK; BC &= ADDRMASK; @@ -2095,19 +2096,19 @@ static t_stat sim_instr_mmu (void) { break; case 0x0a: /* LD A,(BC) */ - tStates += 7; + tStates += 7; /* LDAX B 7 */ CHECK_BREAK_BYTE(BC) SET_HIGH_REGISTER(AF, GetBYTE(BC)); break; case 0x0b: /* DEC BC */ - tStates += 6; + tStates += (chiptype == CHIP_TYPE_8080 ? 5 : 6); /* DCX B 5 */ sim_brk_pend[0] = FALSE; --BC; break; case 0x0c: /* INC C */ - tStates += 4; + tStates += (chiptype == CHIP_TYPE_8080 ? 5 : 4); /* INR C 5 */ sim_brk_pend[0] = FALSE; temp = LOW_REGISTER(BC) + 1; SET_LOW_REGISTER(BC, temp); @@ -2115,7 +2116,7 @@ static t_stat sim_instr_mmu (void) { break; case 0x0d: /* DEC C */ - tStates += 4; + tStates += (chiptype == CHIP_TYPE_8080 ? 5 : 4); /* DCR C 5 */ sim_brk_pend[0] = FALSE; temp = LOW_REGISTER(BC) - 1; SET_LOW_REGISTER(BC, temp); @@ -2123,19 +2124,21 @@ static t_stat sim_instr_mmu (void) { break; case 0x0e: /* LD C,nn */ - tStates += 7; + tStates += 7; /* MVI C,nn 7 */ sim_brk_pend[0] = FALSE; SET_LOW_REGISTER(BC, RAM_PP(PC)); break; case 0x0f: /* RRCA */ - tStates += 4; + tStates += 4; /* RRC 4 */ sim_brk_pend[0] = FALSE; AF = (AF & 0xc4) | rrcaTable[HIGH_REGISTER(AF)]; break; case 0x10: /* DJNZ dd */ sim_brk_pend[0] = FALSE; + if (chiptype == CHIP_TYPE_8080) + tStates += 4; /* NOP 4 */ CHECK_CPU_8080; if ((BC -= 0x100) & 0xff00) { PCQ_ENTRY(PCX); @@ -2149,26 +2152,26 @@ static t_stat sim_instr_mmu (void) { break; case 0x11: /* LD DE,nnnn */ - tStates += 10; + tStates += 10; /* LXI D,nnnn 10 */ sim_brk_pend[0] = FALSE; DE = GET_WORD(PC); PC += 2; break; case 0x12: /* LD (DE),A */ - tStates += 7; + tStates += 7; /* STAX D 7 */ CHECK_BREAK_BYTE(DE) PutBYTE(DE, HIGH_REGISTER(AF)); break; case 0x13: /* INC DE */ - tStates += 6; + tStates += (chiptype == CHIP_TYPE_8080 ? 5 : 6); /* INX D 5 */ sim_brk_pend[0] = FALSE; ++DE; break; case 0x14: /* INC D */ - tStates += 4; + tStates += (chiptype == CHIP_TYPE_8080 ? 5 : 4); /* INR D 5 */ sim_brk_pend[0] = FALSE; DE += 0x100; temp = HIGH_REGISTER(DE); @@ -2176,7 +2179,7 @@ static t_stat sim_instr_mmu (void) { break; case 0x15: /* DEC D */ - tStates += 4; + tStates += (chiptype == CHIP_TYPE_8080 ? 5 : 4); /* DCR D 5 */ sim_brk_pend[0] = FALSE; DE -= 0x100; temp = HIGH_REGISTER(DE); @@ -2184,20 +2187,20 @@ static t_stat sim_instr_mmu (void) { break; case 0x16: /* LD D,nn */ - tStates += 7; + tStates += 7; /* MVI D,nn 7 */ sim_brk_pend[0] = FALSE; SET_HIGH_REGISTER(DE, RAM_PP(PC)); break; case 0x17: /* RLA */ - tStates += 4; + tStates += 4; /* RAL 4 */ sim_brk_pend[0] = FALSE; AF = ((AF << 8) & 0x0100) | ((AF >> 7) & 0x28) | ((AF << 1) & ~0x01ff) | (AF & 0xc4) | ((AF >> 15) & 1); break; case 0x18: /* JR dd */ - tStates += 12; + tStates += (chiptype == CHIP_TYPE_8080 ? 4 : 12); /* NOP 4 */ sim_brk_pend[0] = FALSE; CHECK_CPU_8080; PCQ_ENTRY(PCX); @@ -2205,7 +2208,7 @@ static t_stat sim_instr_mmu (void) { break; case 0x19: /* ADD HL,DE */ - tStates += 11; + tStates += (chiptype == CHIP_TYPE_8080 ? 10 : 11); /* DAD D 10 */ sim_brk_pend[0] = FALSE; HL &= ADDRMASK; DE &= ADDRMASK; @@ -2215,19 +2218,19 @@ static t_stat sim_instr_mmu (void) { break; case 0x1a: /* LD A,(DE) */ - tStates += 7; + tStates += 7; /* LDAX D 7 */ CHECK_BREAK_BYTE(DE) SET_HIGH_REGISTER(AF, GetBYTE(DE)); break; case 0x1b: /* DEC DE */ - tStates += 6; + tStates += (chiptype == CHIP_TYPE_8080 ? 5 : 6); /* DCX D 5 */ sim_brk_pend[0] = FALSE; --DE; break; case 0x1c: /* INC E */ - tStates += 4; + tStates += (chiptype == CHIP_TYPE_8080 ? 5 : 4); /* INR E 5 */ sim_brk_pend[0] = FALSE; temp = LOW_REGISTER(DE) + 1; SET_LOW_REGISTER(DE, temp); @@ -2235,7 +2238,7 @@ static t_stat sim_instr_mmu (void) { break; case 0x1d: /* DEC E */ - tStates += 4; + tStates += (chiptype == CHIP_TYPE_8080 ? 5 : 4); /* DCR E 5 */ sim_brk_pend[0] = FALSE; temp = LOW_REGISTER(DE) - 1; SET_LOW_REGISTER(DE, temp); @@ -2243,18 +2246,20 @@ static t_stat sim_instr_mmu (void) { break; case 0x1e: /* LD E,nn */ - tStates += 7; + tStates += 7; /* MVI E 7 */ sim_brk_pend[0] = FALSE; SET_LOW_REGISTER(DE, RAM_PP(PC)); break; case 0x1f: /* RRA */ - tStates += 4; + tStates += 4; /* RAR 4 */ sim_brk_pend[0] = FALSE; AF = ((AF & 1) << 15) | (AF & 0xc4) | rraTable[HIGH_REGISTER(AF)]; break; case 0x20: /* JR NZ,dd */ + if (chiptype == CHIP_TYPE_8080) + tStates += 4; /* NOP 4 */ sim_brk_pend[0] = FALSE; CHECK_CPU_8080; if (TSTFLAG(Z)) { @@ -2269,14 +2274,14 @@ static t_stat sim_instr_mmu (void) { break; case 0x21: /* LD HL,nnnn */ - tStates += 10; + tStates += 10; /* LXI H,nnnn 10 */ sim_brk_pend[0] = FALSE; HL = GET_WORD(PC); PC += 2; break; case 0x22: /* LD (nnnn),HL */ - tStates += 16; + tStates += 16; /* SHLD 16 */ temp = GET_WORD(PC); CHECK_BREAK_WORD(temp); PutWORD(temp, HL); @@ -2284,13 +2289,13 @@ static t_stat sim_instr_mmu (void) { break; case 0x23: /* INC HL */ - tStates += 6; + tStates += (chiptype == CHIP_TYPE_8080 ? 5 : 6); /* INX H 5 */ sim_brk_pend[0] = FALSE; ++HL; break; case 0x24: /* INC H */ - tStates += 4; + tStates += (chiptype == CHIP_TYPE_8080 ? 5 : 4); /* INR H 5 */ sim_brk_pend[0] = FALSE; HL += 0x100; temp = HIGH_REGISTER(HL); @@ -2298,7 +2303,7 @@ static t_stat sim_instr_mmu (void) { break; case 0x25: /* DEC H */ - tStates += 4; + tStates += (chiptype == CHIP_TYPE_8080 ? 5 : 4); /* DCR H 5 */ sim_brk_pend[0] = FALSE; HL -= 0x100; temp = HIGH_REGISTER(HL); @@ -2306,13 +2311,13 @@ static t_stat sim_instr_mmu (void) { break; case 0x26: /* LD H,nn */ - tStates += 7; + tStates += 7; /* MVI H,nn 7 */ sim_brk_pend[0] = FALSE; SET_HIGH_REGISTER(HL, RAM_PP(PC)); break; case 0x27: /* DAA */ - tStates += 4; + tStates += 4; /* DAA 4 */ sim_brk_pend[0] = FALSE; acu = HIGH_REGISTER(AF); temp = LOW_DIGIT(acu); @@ -2341,6 +2346,8 @@ static t_stat sim_instr_mmu (void) { break; case 0x28: /* JR Z,dd */ + if (chiptype == CHIP_TYPE_8080) + tStates += 4; /* NOP 4 */ sim_brk_pend[0] = FALSE; CHECK_CPU_8080; if (TSTFLAG(Z)) { @@ -2355,7 +2362,7 @@ static t_stat sim_instr_mmu (void) { break; case 0x29: /* ADD HL,HL */ - tStates += 11; + tStates += (chiptype == CHIP_TYPE_8080 ? 10 : 11); /* DAD H 10 */ sim_brk_pend[0] = FALSE; HL &= ADDRMASK; sum = HL + HL; @@ -2364,7 +2371,7 @@ static t_stat sim_instr_mmu (void) { break; case 0x2a: /* LD HL,(nnnn) */ - tStates += 16; + tStates += 16; /* LHLD nnnn 16 */ temp = GET_WORD(PC); CHECK_BREAK_WORD(temp); HL = GET_WORD(temp); @@ -2372,13 +2379,13 @@ static t_stat sim_instr_mmu (void) { break; case 0x2b: /* DEC HL */ - tStates += 6; + tStates += (chiptype == CHIP_TYPE_8080 ? 5 : 6); /* DCX H 5 */ sim_brk_pend[0] = FALSE; --HL; break; case 0x2c: /* INC L */ - tStates += 4; + tStates += (chiptype == CHIP_TYPE_8080 ? 5 : 4); /* INR L 5 */ sim_brk_pend[0] = FALSE; temp = LOW_REGISTER(HL) + 1; SET_LOW_REGISTER(HL, temp); @@ -2386,7 +2393,7 @@ static t_stat sim_instr_mmu (void) { break; case 0x2d: /* DEC L */ - tStates += 4; + tStates += (chiptype == CHIP_TYPE_8080 ? 5 : 4); /* DCR L 5 */ sim_brk_pend[0] = FALSE; temp = LOW_REGISTER(HL) - 1; SET_LOW_REGISTER(HL, temp); @@ -2394,18 +2401,20 @@ static t_stat sim_instr_mmu (void) { break; case 0x2e: /* LD L,nn */ - tStates += 7; + tStates += 7; /* MVI L,nn 7 */ sim_brk_pend[0] = FALSE; SET_LOW_REGISTER(HL, RAM_PP(PC)); break; case 0x2f: /* CPL */ - tStates += 4; + tStates += 4; /* CMA 4 */ sim_brk_pend[0] = FALSE; AF = (~AF & ~0xff) | (AF & 0xc5) | ((~AF >> 8) & 0x28) | 0x12; break; case 0x30: /* JR NC,dd */ + if (chiptype == CHIP_TYPE_8080) + tStates += 4; /* NOP 4 */ sim_brk_pend[0] = FALSE; CHECK_CPU_8080; if (TSTFLAG(C)) { @@ -2420,14 +2429,14 @@ static t_stat sim_instr_mmu (void) { break; case 0x31: /* LD SP,nnnn */ - tStates += 10; + tStates += 10; /* LXI SP,nnnn 10 */ sim_brk_pend[0] = FALSE; SP = GET_WORD(PC); PC += 2; break; case 0x32: /* LD (nnnn),A */ - tStates += 13; + tStates += 13; /* STA nnnn 13 */ temp = GET_WORD(PC); CHECK_BREAK_BYTE(temp); PutBYTE(temp, HIGH_REGISTER(AF)); @@ -2435,13 +2444,13 @@ static t_stat sim_instr_mmu (void) { break; case 0x33: /* INC SP */ - tStates += 6; + tStates += (chiptype == CHIP_TYPE_8080 ? 5 : 6); /* INX SP 5 */ sim_brk_pend[0] = FALSE; ++SP; break; case 0x34: /* INC (HL) */ - tStates += 11; + tStates += (chiptype == CHIP_TYPE_8080 ? 10 : 11); /* INR M 10 */ CHECK_BREAK_BYTE(HL); temp = GetBYTE(HL) + 1; PutBYTE(HL, temp); @@ -2449,7 +2458,7 @@ static t_stat sim_instr_mmu (void) { break; case 0x35: /* DEC (HL) */ - tStates += 11; + tStates += (chiptype == CHIP_TYPE_8080 ? 10 : 11); /* DCR M 10 */ CHECK_BREAK_BYTE(HL); temp = GetBYTE(HL) - 1; PutBYTE(HL, temp); @@ -2457,18 +2466,20 @@ static t_stat sim_instr_mmu (void) { break; case 0x36: /* LD (HL),nn */ - tStates += 10; + tStates += 10; /* MVI M 10 */ CHECK_BREAK_BYTE(HL); PutBYTE(HL, RAM_PP(PC)); break; case 0x37: /* SCF */ - tStates += 4; + tStates += 4; /* STC 4 */ sim_brk_pend[0] = FALSE; AF = (AF & ~0x3b) | ((AF >> 8) & 0x28) | 1; break; case 0x38: /* JR C,dd */ + if (chiptype == CHIP_TYPE_8080) + tStates += 4; /* NOP 4 */ sim_brk_pend[0] = FALSE; CHECK_CPU_8080; if (TSTFLAG(C)) { @@ -2483,7 +2494,7 @@ static t_stat sim_instr_mmu (void) { break; case 0x39: /* ADD HL,SP */ - tStates += 11; + tStates += (chiptype == CHIP_TYPE_8080 ? 10 : 11); /* DAD SP 10 */ sim_brk_pend[0] = FALSE; HL &= ADDRMASK; SP &= ADDRMASK; @@ -2493,7 +2504,7 @@ static t_stat sim_instr_mmu (void) { break; case 0x3a: /* LD A,(nnnn) */ - tStates += 13; + tStates += 13; /* LDA nnnn 13 */ temp = GET_WORD(PC); CHECK_BREAK_BYTE(temp); SET_HIGH_REGISTER(AF, GetBYTE(temp)); @@ -2501,13 +2512,13 @@ static t_stat sim_instr_mmu (void) { break; case 0x3b: /* DEC SP */ - tStates += 6; + tStates += (chiptype == CHIP_TYPE_8080 ? 5 : 6); /* DCX SP 5 */ sim_brk_pend[0] = FALSE; --SP; break; case 0x3c: /* INC A */ - tStates += 4; + tStates += (chiptype == CHIP_TYPE_8080 ? 5 : 4); /* INR A 5 */ sim_brk_pend[0] = FALSE; AF += 0x100; temp = HIGH_REGISTER(AF); @@ -2515,7 +2526,7 @@ static t_stat sim_instr_mmu (void) { break; case 0x3d: /* DEC A */ - tStates += 4; + tStates += (chiptype == CHIP_TYPE_8080 ? 5 : 4); /* DCR A 5 */ sim_brk_pend[0] = FALSE; AF -= 0x100; temp = HIGH_REGISTER(AF); @@ -2523,337 +2534,337 @@ static t_stat sim_instr_mmu (void) { break; case 0x3e: /* LD A,nn */ - tStates += 7; + tStates += 7; /* MVI A,nn 7 */ sim_brk_pend[0] = FALSE; SET_HIGH_REGISTER(AF, RAM_PP(PC)); break; case 0x3f: /* CCF */ - tStates += 4; + tStates += 4; /* CMC 4 */ sim_brk_pend[0] = FALSE; AF = (AF & ~0x3b) | ((AF >> 8) & 0x28) | ((AF & 1) << 4) | (~AF & 1); break; case 0x40: /* LD B,B */ - tStates += 4; + tStates += (chiptype == CHIP_TYPE_8080 ? 5 : 4); /* MOV B,B 5 */ sim_brk_pend[0] = FALSE; /* nop */ break; case 0x41: /* LD B,C */ - tStates += 4; + tStates += (chiptype == CHIP_TYPE_8080 ? 5 : 4); /* MOV B,C 5 */ sim_brk_pend[0] = FALSE; BC = (BC & 0xff) | ((BC & 0xff) << 8); break; case 0x42: /* LD B,D */ - tStates += 4; + tStates += (chiptype == CHIP_TYPE_8080 ? 5 : 4); /* MOV B,D 5 */ sim_brk_pend[0] = FALSE; BC = (BC & 0xff) | (DE & ~0xff); break; case 0x43: /* LD B,E */ - tStates += 4; + tStates += (chiptype == CHIP_TYPE_8080 ? 5 : 4); /* MOV B,E 5 */ sim_brk_pend[0] = FALSE; BC = (BC & 0xff) | ((DE & 0xff) << 8); break; case 0x44: /* LD B,H */ - tStates += 4; + tStates += (chiptype == CHIP_TYPE_8080 ? 5 : 4); /* MOV B,H 5 */ sim_brk_pend[0] = FALSE; BC = (BC & 0xff) | (HL & ~0xff); break; case 0x45: /* LD B,L */ - tStates += 4; + tStates += (chiptype == CHIP_TYPE_8080 ? 5 : 4); /* MOV B,L 5 */ sim_brk_pend[0] = FALSE; BC = (BC & 0xff) | ((HL & 0xff) << 8); break; case 0x46: /* LD B,(HL) */ - tStates += 7; + tStates += 7; /* MOV B,M 7 */ CHECK_BREAK_BYTE(HL); SET_HIGH_REGISTER(BC, GetBYTE(HL)); break; case 0x47: /* LD B,A */ - tStates += 4; + tStates += (chiptype == CHIP_TYPE_8080 ? 5 : 4); /* MOV B,A 5 */ sim_brk_pend[0] = FALSE; BC = (BC & 0xff) | (AF & ~0xff); break; case 0x48: /* LD C,B */ - tStates += 4; + tStates += (chiptype == CHIP_TYPE_8080 ? 5 : 4); /* MOV C,B 5 */ sim_brk_pend[0] = FALSE; BC = (BC & ~0xff) | ((BC >> 8) & 0xff); break; case 0x49: /* LD C,C */ - tStates += 4; + tStates += (chiptype == CHIP_TYPE_8080 ? 5 : 4); /* MOV C,C 5 */ sim_brk_pend[0] = FALSE; /* nop */ break; case 0x4a: /* LD C,D */ - tStates += 4; + tStates += (chiptype == CHIP_TYPE_8080 ? 5 : 4); /* MOV C,D 5 */ sim_brk_pend[0] = FALSE; BC = (BC & ~0xff) | ((DE >> 8) & 0xff); break; case 0x4b: /* LD C,E */ - tStates += 4; + tStates += (chiptype == CHIP_TYPE_8080 ? 5 : 4); /* MOV C,E 5 */ sim_brk_pend[0] = FALSE; BC = (BC & ~0xff) | (DE & 0xff); break; case 0x4c: /* LD C,H */ - tStates += 4; + tStates += (chiptype == CHIP_TYPE_8080 ? 5 : 4); /* MOV C,H 5 */ sim_brk_pend[0] = FALSE; BC = (BC & ~0xff) | ((HL >> 8) & 0xff); break; case 0x4d: /* LD C,L */ - tStates += 4; + tStates += (chiptype == CHIP_TYPE_8080 ? 5 : 4); /* MOV C,L 5 */ sim_brk_pend[0] = FALSE; BC = (BC & ~0xff) | (HL & 0xff); break; case 0x4e: /* LD C,(HL) */ - tStates += 7; + tStates += 7; /* MOV C,M 7 */ CHECK_BREAK_BYTE(HL); SET_LOW_REGISTER(BC, GetBYTE(HL)); break; case 0x4f: /* LD C,A */ - tStates += 4; + tStates += (chiptype == CHIP_TYPE_8080 ? 5 : 4); /* MOV C,A 5 */ sim_brk_pend[0] = FALSE; BC = (BC & ~0xff) | ((AF >> 8) & 0xff); break; case 0x50: /* LD D,B */ - tStates += 4; + tStates += (chiptype == CHIP_TYPE_8080 ? 5 : 4); /* MOV D,B 5 */ sim_brk_pend[0] = FALSE; DE = (DE & 0xff) | (BC & ~0xff); break; case 0x51: /* LD D,C */ - tStates += 4; + tStates += (chiptype == CHIP_TYPE_8080 ? 5 : 4); /* MOV D,C 5 */ sim_brk_pend[0] = FALSE; DE = (DE & 0xff) | ((BC & 0xff) << 8); break; case 0x52: /* LD D,D */ - tStates += 4; + tStates += (chiptype == CHIP_TYPE_8080 ? 5 : 4); /* MOV D,D 5 */ sim_brk_pend[0] = FALSE; /* nop */ break; case 0x53: /* LD D,E */ - tStates += 4; + tStates += (chiptype == CHIP_TYPE_8080 ? 5 : 4); /* MOV D,E 5 */ sim_brk_pend[0] = FALSE; DE = (DE & 0xff) | ((DE & 0xff) << 8); break; case 0x54: /* LD D,H */ - tStates += 4; + tStates += (chiptype == CHIP_TYPE_8080 ? 5 : 4); /* MOV D,H 5 */ sim_brk_pend[0] = FALSE; DE = (DE & 0xff) | (HL & ~0xff); break; case 0x55: /* LD D,L */ - tStates += 4; + tStates += (chiptype == CHIP_TYPE_8080 ? 5 : 4); /* MOV D,L 5 */ sim_brk_pend[0] = FALSE; DE = (DE & 0xff) | ((HL & 0xff) << 8); break; case 0x56: /* LD D,(HL) */ - tStates += 7; + tStates += 7; /* MOV D,M 7 */ CHECK_BREAK_BYTE(HL); SET_HIGH_REGISTER(DE, GetBYTE(HL)); break; case 0x57: /* LD D,A */ - tStates += 4; + tStates += (chiptype == CHIP_TYPE_8080 ? 5 : 4); /* MOV D,A 5 */ sim_brk_pend[0] = FALSE; DE = (DE & 0xff) | (AF & ~0xff); break; case 0x58: /* LD E,B */ - tStates += 4; + tStates += (chiptype == CHIP_TYPE_8080 ? 5 : 4); /* MOV E,B 5 */ sim_brk_pend[0] = FALSE; DE = (DE & ~0xff) | ((BC >> 8) & 0xff); break; case 0x59: /* LD E,C */ - tStates += 4; + tStates += (chiptype == CHIP_TYPE_8080 ? 5 : 4); /* MOV E,C 5 */ sim_brk_pend[0] = FALSE; DE = (DE & ~0xff) | (BC & 0xff); break; case 0x5a: /* LD E,D */ - tStates += 4; + tStates += (chiptype == CHIP_TYPE_8080 ? 5 : 4); /* MOV E,D 5 */ sim_brk_pend[0] = FALSE; DE = (DE & ~0xff) | ((DE >> 8) & 0xff); break; case 0x5b: /* LD E,E */ - tStates += 4; + tStates += (chiptype == CHIP_TYPE_8080 ? 5 : 4); /* MOV E,E 5 */ sim_brk_pend[0] = FALSE; /* nop */ break; case 0x5c: /* LD E,H */ - tStates += 4; + tStates += (chiptype == CHIP_TYPE_8080 ? 5 : 4); /* MOV E,H 5 */ sim_brk_pend[0] = FALSE; DE = (DE & ~0xff) | ((HL >> 8) & 0xff); break; case 0x5d: /* LD E,L */ - tStates += 4; + tStates += (chiptype == CHIP_TYPE_8080 ? 5 : 4); /* MOV E,L 5 */ sim_brk_pend[0] = FALSE; DE = (DE & ~0xff) | (HL & 0xff); break; case 0x5e: /* LD E,(HL) */ - tStates += 7; + tStates += 7; /* MOV E,M 7 */ CHECK_BREAK_BYTE(HL); SET_LOW_REGISTER(DE, GetBYTE(HL)); break; case 0x5f: /* LD E,A */ - tStates += 4; + tStates += (chiptype == CHIP_TYPE_8080 ? 5 : 4); /* MOV E,A 5 */ sim_brk_pend[0] = FALSE; DE = (DE & ~0xff) | ((AF >> 8) & 0xff); break; case 0x60: /* LD H,B */ - tStates += 4; + tStates += (chiptype == CHIP_TYPE_8080 ? 5 : 4); /* MOV H,B 5 */ sim_brk_pend[0] = FALSE; HL = (HL & 0xff) | (BC & ~0xff); break; case 0x61: /* LD H,C */ - tStates += 4; + tStates += (chiptype == CHIP_TYPE_8080 ? 5 : 4); /* MOV H,C 5 */ sim_brk_pend[0] = FALSE; HL = (HL & 0xff) | ((BC & 0xff) << 8); break; case 0x62: /* LD H,D */ - tStates += 4; + tStates += (chiptype == CHIP_TYPE_8080 ? 5 : 4); /* MOV H,D 5 */ sim_brk_pend[0] = FALSE; HL = (HL & 0xff) | (DE & ~0xff); break; case 0x63: /* LD H,E */ - tStates += 4; + tStates += (chiptype == CHIP_TYPE_8080 ? 5 : 4); /* MOV H,E 5 */ sim_brk_pend[0] = FALSE; HL = (HL & 0xff) | ((DE & 0xff) << 8); break; case 0x64: /* LD H,H */ - tStates += 4; + tStates += (chiptype == CHIP_TYPE_8080 ? 5 : 4); /* MOV H,H 5 */ sim_brk_pend[0] = FALSE; /* nop */ break; case 0x65: /* LD H,L */ - tStates += 4; + tStates += (chiptype == CHIP_TYPE_8080 ? 5 : 4); /* MOV H,L 5 */ sim_brk_pend[0] = FALSE; HL = (HL & 0xff) | ((HL & 0xff) << 8); break; case 0x66: /* LD H,(HL) */ - tStates += 7; + tStates += 7; /* MOV H,M 7 */ CHECK_BREAK_BYTE(HL); SET_HIGH_REGISTER(HL, GetBYTE(HL)); break; case 0x67: /* LD H,A */ - tStates += 4; + tStates += (chiptype == CHIP_TYPE_8080 ? 5 : 4); /* MOV H,A 5 */ sim_brk_pend[0] = FALSE; HL = (HL & 0xff) | (AF & ~0xff); break; case 0x68: /* LD L,B */ - tStates += 4; + tStates += (chiptype == CHIP_TYPE_8080 ? 5 : 4); /* MOV L,B 5 */ sim_brk_pend[0] = FALSE; HL = (HL & ~0xff) | ((BC >> 8) & 0xff); break; case 0x69: /* LD L,C */ - tStates += 4; + tStates += (chiptype == CHIP_TYPE_8080 ? 5 : 4); /* MOV L,C 5 */ sim_brk_pend[0] = FALSE; HL = (HL & ~0xff) | (BC & 0xff); break; case 0x6a: /* LD L,D */ - tStates += 4; + tStates += (chiptype == CHIP_TYPE_8080 ? 5 : 4); /* MOV L,D 5 */ sim_brk_pend[0] = FALSE; HL = (HL & ~0xff) | ((DE >> 8) & 0xff); break; case 0x6b: /* LD L,E */ - tStates += 4; + tStates += (chiptype == CHIP_TYPE_8080 ? 5 : 4); /* MOV L,E 5 */ sim_brk_pend[0] = FALSE; HL = (HL & ~0xff) | (DE & 0xff); break; case 0x6c: /* LD L,H */ - tStates += 4; + tStates += (chiptype == CHIP_TYPE_8080 ? 5 : 4); /* MOV L,H 5 */ sim_brk_pend[0] = FALSE; HL = (HL & ~0xff) | ((HL >> 8) & 0xff); break; case 0x6d: /* LD L,L */ - tStates += 4; + tStates += (chiptype == CHIP_TYPE_8080 ? 5 : 4); /* MOV L,L 5 */ sim_brk_pend[0] = FALSE; /* nop */ break; case 0x6e: /* LD L,(HL) */ - tStates += 7; + tStates += 7; /* MOV L,M 7 */ CHECK_BREAK_BYTE(HL); SET_LOW_REGISTER(HL, GetBYTE(HL)); break; case 0x6f: /* LD L,A */ - tStates += 4; + tStates += (chiptype == CHIP_TYPE_8080 ? 5 : 4); /* MOV L,A 5 */ sim_brk_pend[0] = FALSE; HL = (HL & ~0xff) | ((AF >> 8) & 0xff); break; case 0x70: /* LD (HL),B */ - tStates += 7; + tStates += 7; /* MOV M,B 7 */ CHECK_BREAK_BYTE(HL); PutBYTE(HL, HIGH_REGISTER(BC)); break; case 0x71: /* LD (HL),C */ - tStates += 7; + tStates += 7; /* MOV M,C 7 */ CHECK_BREAK_BYTE(HL); PutBYTE(HL, LOW_REGISTER(BC)); break; case 0x72: /* LD (HL),D */ - tStates += 7; + tStates += 7; /* MOV M,D 7 */ CHECK_BREAK_BYTE(HL); PutBYTE(HL, HIGH_REGISTER(DE)); break; case 0x73: /* LD (HL),E */ - tStates += 7; + tStates += 7; /* MOV M,E 7 */ CHECK_BREAK_BYTE(HL); PutBYTE(HL, LOW_REGISTER(DE)); break; case 0x74: /* LD (HL),H */ - tStates += 7; + tStates += 7; /* MOV M,H 7 */ CHECK_BREAK_BYTE(HL); PutBYTE(HL, HIGH_REGISTER(HL)); break; case 0x75: /* LD (HL),L */ - tStates += 7; + tStates += 7; /* MOV M,L 7 */ CHECK_BREAK_BYTE(HL); PutBYTE(HL, LOW_REGISTER(HL)); break; case HALTINSTRUCTION: /* HALT */ - tStates += 4; + tStates += (chiptype == CHIP_TYPE_8080 ? 7 : 4); /* HLT 7 */ sim_brk_pend[0] = FALSE; PC--; if (cpu_unit.flags & UNIT_CPU_STOPONHALT) { @@ -2865,60 +2876,60 @@ static t_stat sim_instr_mmu (void) { break; case 0x77: /* LD (HL),A */ - tStates += 7; + tStates += 7; /* MOV M,A 7 */ CHECK_BREAK_BYTE(HL); PutBYTE(HL, HIGH_REGISTER(AF)); break; case 0x78: /* LD A,B */ - tStates += 4; + tStates += (chiptype == CHIP_TYPE_8080 ? 5 : 4); /* MOV A,B 5 */ sim_brk_pend[0] = FALSE; AF = (AF & 0xff) | (BC & ~0xff); break; case 0x79: /* LD A,C */ - tStates += 4; + tStates += (chiptype == CHIP_TYPE_8080 ? 5 : 4); /* MOV A,C 5 */ sim_brk_pend[0] = FALSE; AF = (AF & 0xff) | ((BC & 0xff) << 8); break; case 0x7a: /* LD A,D */ - tStates += 4; + tStates += (chiptype == CHIP_TYPE_8080 ? 5 : 4); /* MOV A,D 5 */ sim_brk_pend[0] = FALSE; AF = (AF & 0xff) | (DE & ~0xff); break; case 0x7b: /* LD A,E */ - tStates += 4; + tStates += (chiptype == CHIP_TYPE_8080 ? 5 : 4); /* MOV A,E 5 */ sim_brk_pend[0] = FALSE; AF = (AF & 0xff) | ((DE & 0xff) << 8); break; case 0x7c: /* LD A,H */ - tStates += 4; + tStates += (chiptype == CHIP_TYPE_8080 ? 5 : 4); /* MOV A,H 5 */ sim_brk_pend[0] = FALSE; AF = (AF & 0xff) | (HL & ~0xff); break; case 0x7d: /* LD A,L */ - tStates += 4; + tStates += (chiptype == CHIP_TYPE_8080 ? 5 : 4); /* MOV A,L 5 */ sim_brk_pend[0] = FALSE; AF = (AF & 0xff) | ((HL & 0xff) << 8); break; case 0x7e: /* LD A,(HL) */ - tStates += 7; + tStates += 7; /* MOV A,M 7 */ CHECK_BREAK_BYTE(HL); SET_HIGH_REGISTER(AF, GetBYTE(HL)); break; case 0x7f: /* LD A,A */ - tStates += 4; + tStates += (chiptype == CHIP_TYPE_8080 ? 5 : 4); /* MOV A,A 5 */ sim_brk_pend[0] = FALSE; /* nop */ break; case 0x80: /* ADD A,B */ - tStates += 4; + tStates += 4; /* ADD B 4 */ sim_brk_pend[0] = FALSE; temp = HIGH_REGISTER(BC); acu = HIGH_REGISTER(AF); @@ -2928,7 +2939,7 @@ static t_stat sim_instr_mmu (void) { break; case 0x81: /* ADD A,C */ - tStates += 4; + tStates += 4; /* ADD C 4 */ sim_brk_pend[0] = FALSE; temp = LOW_REGISTER(BC); acu = HIGH_REGISTER(AF); @@ -2938,7 +2949,7 @@ static t_stat sim_instr_mmu (void) { break; case 0x82: /* ADD A,D */ - tStates += 4; + tStates += 4; /* ADD D 4 */ sim_brk_pend[0] = FALSE; temp = HIGH_REGISTER(DE); acu = HIGH_REGISTER(AF); @@ -2948,7 +2959,7 @@ static t_stat sim_instr_mmu (void) { break; case 0x83: /* ADD A,E */ - tStates += 4; + tStates += 4; /* ADD E 4 */ sim_brk_pend[0] = FALSE; temp = LOW_REGISTER(DE); acu = HIGH_REGISTER(AF); @@ -2958,7 +2969,7 @@ static t_stat sim_instr_mmu (void) { break; case 0x84: /* ADD A,H */ - tStates += 4; + tStates += 4; /* ADD H 4 */ sim_brk_pend[0] = FALSE; temp = HIGH_REGISTER(HL); acu = HIGH_REGISTER(AF); @@ -2968,7 +2979,7 @@ static t_stat sim_instr_mmu (void) { break; case 0x85: /* ADD A,L */ - tStates += 4; + tStates += 4; /* ADD L 4 */ sim_brk_pend[0] = FALSE; temp = LOW_REGISTER(HL); acu = HIGH_REGISTER(AF); @@ -2978,7 +2989,7 @@ static t_stat sim_instr_mmu (void) { break; case 0x86: /* ADD A,(HL) */ - tStates += 7; + tStates += 7; /* ADD M 7 */ CHECK_BREAK_BYTE(HL); temp = GetBYTE(HL); acu = HIGH_REGISTER(AF); @@ -2988,14 +2999,14 @@ static t_stat sim_instr_mmu (void) { break; case 0x87: /* ADD A,A */ - tStates += 4; + tStates += 4; /* ADD A 4 */ sim_brk_pend[0] = FALSE; cbits = 2 * HIGH_REGISTER(AF); AF = cbitsDup8Table[cbits] | (SET_PVS(cbits)); break; case 0x88: /* ADC A,B */ - tStates += 4; + tStates += 4; /* ADC B 4 */ sim_brk_pend[0] = FALSE; temp = HIGH_REGISTER(BC); acu = HIGH_REGISTER(AF); @@ -3005,7 +3016,7 @@ static t_stat sim_instr_mmu (void) { break; case 0x89: /* ADC A,C */ - tStates += 4; + tStates += 4; /* ADC C 4 */ sim_brk_pend[0] = FALSE; temp = LOW_REGISTER(BC); acu = HIGH_REGISTER(AF); @@ -3015,7 +3026,7 @@ static t_stat sim_instr_mmu (void) { break; case 0x8a: /* ADC A,D */ - tStates += 4; + tStates += 4; /* ADC D 4 */ sim_brk_pend[0] = FALSE; temp = HIGH_REGISTER(DE); acu = HIGH_REGISTER(AF); @@ -3025,7 +3036,7 @@ static t_stat sim_instr_mmu (void) { break; case 0x8b: /* ADC A,E */ - tStates += 4; + tStates += 4; /* ADC E 4 */ sim_brk_pend[0] = FALSE; temp = LOW_REGISTER(DE); acu = HIGH_REGISTER(AF); @@ -3035,7 +3046,7 @@ static t_stat sim_instr_mmu (void) { break; case 0x8c: /* ADC A,H */ - tStates += 4; + tStates += 4; /* ADC H 4 */ sim_brk_pend[0] = FALSE; temp = HIGH_REGISTER(HL); acu = HIGH_REGISTER(AF); @@ -3045,7 +3056,7 @@ static t_stat sim_instr_mmu (void) { break; case 0x8d: /* ADC A,L */ - tStates += 4; + tStates += 4; /* ADC L 4 */ sim_brk_pend[0] = FALSE; temp = LOW_REGISTER(HL); acu = HIGH_REGISTER(AF); @@ -3055,7 +3066,7 @@ static t_stat sim_instr_mmu (void) { break; case 0x8e: /* ADC A,(HL) */ - tStates += 7; + tStates += 7; /* ADC M 7 */ CHECK_BREAK_BYTE(HL); temp = GetBYTE(HL); acu = HIGH_REGISTER(AF); @@ -3065,14 +3076,14 @@ static t_stat sim_instr_mmu (void) { break; case 0x8f: /* ADC A,A */ - tStates += 4; + tStates += 4; /* ADC A 4 */ sim_brk_pend[0] = FALSE; cbits = 2 * HIGH_REGISTER(AF) + TSTFLAG(C); AF = cbitsDup8Table[cbits] | (SET_PVS(cbits)); break; case 0x90: /* SUB B */ - tStates += 4; + tStates += 4; /* SUB B 4 */ sim_brk_pend[0] = FALSE; temp = HIGH_REGISTER(BC); acu = HIGH_REGISTER(AF); @@ -3082,7 +3093,7 @@ static t_stat sim_instr_mmu (void) { break; case 0x91: /* SUB C */ - tStates += 4; + tStates += 4; /* SUB C 4 */ sim_brk_pend[0] = FALSE; temp = LOW_REGISTER(BC); acu = HIGH_REGISTER(AF); @@ -3092,7 +3103,7 @@ static t_stat sim_instr_mmu (void) { break; case 0x92: /* SUB D */ - tStates += 4; + tStates += 4; /* SUB D 4 */ sim_brk_pend[0] = FALSE; temp = HIGH_REGISTER(DE); acu = HIGH_REGISTER(AF); @@ -3102,7 +3113,7 @@ static t_stat sim_instr_mmu (void) { break; case 0x93: /* SUB E */ - tStates += 4; + tStates += 4; /* SUB E 4 */ sim_brk_pend[0] = FALSE; temp = LOW_REGISTER(DE); acu = HIGH_REGISTER(AF); @@ -3112,7 +3123,7 @@ static t_stat sim_instr_mmu (void) { break; case 0x94: /* SUB H */ - tStates += 4; + tStates += 4; /* SUB H 4 */ sim_brk_pend[0] = FALSE; temp = HIGH_REGISTER(HL); acu = HIGH_REGISTER(AF); @@ -3122,7 +3133,7 @@ static t_stat sim_instr_mmu (void) { break; case 0x95: /* SUB L */ - tStates += 4; + tStates += 4; /* SUB L 4 */ sim_brk_pend[0] = FALSE; temp = LOW_REGISTER(HL); acu = HIGH_REGISTER(AF); @@ -3132,7 +3143,7 @@ static t_stat sim_instr_mmu (void) { break; case 0x96: /* SUB (HL) */ - tStates += 7; + tStates += 7; /* SUB M 7 */ CHECK_BREAK_BYTE(HL); temp = GetBYTE(HL); acu = HIGH_REGISTER(AF); @@ -3142,13 +3153,13 @@ static t_stat sim_instr_mmu (void) { break; case 0x97: /* SUB A */ - tStates += 4; + tStates += 4; /* SUB A 4 */ sim_brk_pend[0] = FALSE; AF = (chiptype == CHIP_TYPE_Z80) ? 0x42 : 0x46; break; case 0x98: /* SBC A,B */ - tStates += 4; + tStates += 4; /* SBB B 4 */ sim_brk_pend[0] = FALSE; temp = HIGH_REGISTER(BC); acu = HIGH_REGISTER(AF); @@ -3158,7 +3169,7 @@ static t_stat sim_instr_mmu (void) { break; case 0x99: /* SBC A,C */ - tStates += 4; + tStates += 4; /* SBB C 4 */ sim_brk_pend[0] = FALSE; temp = LOW_REGISTER(BC); acu = HIGH_REGISTER(AF); @@ -3168,7 +3179,7 @@ static t_stat sim_instr_mmu (void) { break; case 0x9a: /* SBC A,D */ - tStates += 4; + tStates += 4; /* SBB D 4 */ sim_brk_pend[0] = FALSE; temp = HIGH_REGISTER(DE); acu = HIGH_REGISTER(AF); @@ -3178,7 +3189,7 @@ static t_stat sim_instr_mmu (void) { break; case 0x9b: /* SBC A,E */ - tStates += 4; + tStates += 4; /* SBB E 4 */ sim_brk_pend[0] = FALSE; temp = LOW_REGISTER(DE); acu = HIGH_REGISTER(AF); @@ -3188,7 +3199,7 @@ static t_stat sim_instr_mmu (void) { break; case 0x9c: /* SBC A,H */ - tStates += 4; + tStates += 4; /* SBB H 4 */ sim_brk_pend[0] = FALSE; temp = HIGH_REGISTER(HL); acu = HIGH_REGISTER(AF); @@ -3198,7 +3209,7 @@ static t_stat sim_instr_mmu (void) { break; case 0x9d: /* SBC A,L */ - tStates += 4; + tStates += 4; /* SBB L 4 */ sim_brk_pend[0] = FALSE; temp = LOW_REGISTER(HL); acu = HIGH_REGISTER(AF); @@ -3208,7 +3219,7 @@ static t_stat sim_instr_mmu (void) { break; case 0x9e: /* SBC A,(HL) */ - tStates += 7; + tStates += 7; /* SBB M 7 */ CHECK_BREAK_BYTE(HL); temp = GetBYTE(HL); acu = HIGH_REGISTER(AF); @@ -3218,158 +3229,158 @@ static t_stat sim_instr_mmu (void) { break; case 0x9f: /* SBC A,A */ - tStates += 4; + tStates += 4; /* SBB A 4 */ sim_brk_pend[0] = FALSE; cbits = -TSTFLAG(C); AF = subTable[cbits & 0xff] | cbitsTable[cbits & 0x1ff] | (SET_PVS(cbits)); break; case 0xa0: /* AND B */ - tStates += 4; + tStates += 4; /* ANA B 4 */ sim_brk_pend[0] = FALSE; AF = andTable[((AF & BC) >> 8) & 0xff]; break; case 0xa1: /* AND C */ - tStates += 4; + tStates += 4; /* ANA C 4 */ sim_brk_pend[0] = FALSE; AF = andTable[((AF >> 8) & BC) & 0xff]; break; case 0xa2: /* AND D */ - tStates += 4; + tStates += 4; /* ANA D 4 */ sim_brk_pend[0] = FALSE; AF = andTable[((AF & DE) >> 8) & 0xff]; break; case 0xa3: /* AND E */ - tStates += 4; + tStates += 4; /* ANA E 4 */ sim_brk_pend[0] = FALSE; AF = andTable[((AF >> 8) & DE) & 0xff]; break; case 0xa4: /* AND H */ - tStates += 4; + tStates += 4; /* ANA H 4 */ sim_brk_pend[0] = FALSE; AF = andTable[((AF & HL) >> 8) & 0xff]; break; case 0xa5: /* AND L */ - tStates += 4; + tStates += 4; /* ANA L 4 */ sim_brk_pend[0] = FALSE; AF = andTable[((AF >> 8) & HL) & 0xff]; break; case 0xa6: /* AND (HL) */ - tStates += 7; + tStates += 7; /* ANA M 7 */ CHECK_BREAK_BYTE(HL); AF = andTable[((AF >> 8) & GetBYTE(HL)) & 0xff]; break; case 0xa7: /* AND A */ - tStates += 4; + tStates += 4; /* ANA A 4 */ sim_brk_pend[0] = FALSE; AF = andTable[(AF >> 8) & 0xff]; break; case 0xa8: /* XOR B */ - tStates += 4; + tStates += 4; /* XRA B 4 */ sim_brk_pend[0] = FALSE; AF = xororTable[((AF ^ BC) >> 8) & 0xff]; break; case 0xa9: /* XOR C */ - tStates += 4; + tStates += 4; /* XRA C 4 */ sim_brk_pend[0] = FALSE; AF = xororTable[((AF >> 8) ^ BC) & 0xff]; break; case 0xaa: /* XOR D */ - tStates += 4; + tStates += 4; /* XRA D 4 */ sim_brk_pend[0] = FALSE; AF = xororTable[((AF ^ DE) >> 8) & 0xff]; break; case 0xab: /* XOR E */ - tStates += 4; + tStates += 4; /* XRA E 4 */ sim_brk_pend[0] = FALSE; AF = xororTable[((AF >> 8) ^ DE) & 0xff]; break; case 0xac: /* XOR H */ - tStates += 4; + tStates += 4; /* XRA H 4 */ sim_brk_pend[0] = FALSE; AF = xororTable[((AF ^ HL) >> 8) & 0xff]; break; case 0xad: /* XOR L */ - tStates += 4; + tStates += 4; /* XRA L 4 */ sim_brk_pend[0] = FALSE; AF = xororTable[((AF >> 8) ^ HL) & 0xff]; break; case 0xae: /* XOR (HL) */ - tStates += 7; + tStates += 7; /* XRA M 7 */ CHECK_BREAK_BYTE(HL); AF = xororTable[((AF >> 8) ^ GetBYTE(HL)) & 0xff]; break; case 0xaf: /* XOR A */ - tStates += 4; + tStates += 4; /* XRA A 4 */ sim_brk_pend[0] = FALSE; AF = 0x44; break; case 0xb0: /* OR B */ - tStates += 4; + tStates += 4; /* ORA B 4 */ sim_brk_pend[0] = FALSE; AF = xororTable[((AF | BC) >> 8) & 0xff]; break; case 0xb1: /* OR C */ - tStates += 4; + tStates += 4; /* ORA C 4 */ sim_brk_pend[0] = FALSE; AF = xororTable[((AF >> 8) | BC) & 0xff]; break; case 0xb2: /* OR D */ - tStates += 4; + tStates += 4; /* ORA D 4 */ sim_brk_pend[0] = FALSE; AF = xororTable[((AF | DE) >> 8) & 0xff]; break; case 0xb3: /* OR E */ - tStates += 4; + tStates += 4; /* ORA E 4 */ sim_brk_pend[0] = FALSE; AF = xororTable[((AF >> 8) | DE) & 0xff]; break; case 0xb4: /* OR H */ - tStates += 4; + tStates += 4; /* ORA H 4 */ sim_brk_pend[0] = FALSE; AF = xororTable[((AF | HL) >> 8) & 0xff]; break; case 0xb5: /* OR L */ - tStates += 4; + tStates += 4; /* ORA L 4 */ sim_brk_pend[0] = FALSE; AF = xororTable[((AF >> 8) | HL) & 0xff]; break; case 0xb6: /* OR (HL) */ - tStates += 7; + tStates += 7; /* ORA M 7 */ CHECK_BREAK_BYTE(HL); AF = xororTable[((AF >> 8) | GetBYTE(HL)) & 0xff]; break; case 0xb7: /* OR A */ - tStates += 4; + tStates += 4; /* ORA A 4 */ sim_brk_pend[0] = FALSE; AF = xororTable[(AF >> 8) & 0xff]; break; case 0xb8: /* CP B */ - tStates += 4; + tStates += 4; /* CMP B 4 */ sim_brk_pend[0] = FALSE; temp = HIGH_REGISTER(BC); AF = (AF & ~0x28) | (temp & 0x28); @@ -3381,7 +3392,7 @@ static t_stat sim_instr_mmu (void) { break; case 0xb9: /* CP C */ - tStates += 4; + tStates += 4; /* CMP C 4 */ sim_brk_pend[0] = FALSE; temp = LOW_REGISTER(BC); AF = (AF & ~0x28) | (temp & 0x28); @@ -3393,7 +3404,7 @@ static t_stat sim_instr_mmu (void) { break; case 0xba: /* CP D */ - tStates += 4; + tStates += 4; /* CMP D 4 */ sim_brk_pend[0] = FALSE; temp = HIGH_REGISTER(DE); AF = (AF & ~0x28) | (temp & 0x28); @@ -3405,7 +3416,7 @@ static t_stat sim_instr_mmu (void) { break; case 0xbb: /* CP E */ - tStates += 4; + tStates += 4; /* CMP E 4 */ sim_brk_pend[0] = FALSE; temp = LOW_REGISTER(DE); AF = (AF & ~0x28) | (temp & 0x28); @@ -3417,7 +3428,7 @@ static t_stat sim_instr_mmu (void) { break; case 0xbc: /* CP H */ - tStates += 4; + tStates += 4; /* CMP H 4 */ sim_brk_pend[0] = FALSE; temp = HIGH_REGISTER(HL); AF = (AF & ~0x28) | (temp & 0x28); @@ -3429,7 +3440,7 @@ static t_stat sim_instr_mmu (void) { break; case 0xbd: /* CP L */ - tStates += 4; + tStates += 4; /* CMP L 4 */ sim_brk_pend[0] = FALSE; temp = LOW_REGISTER(HL); AF = (AF & ~0x28) | (temp & 0x28); @@ -3441,7 +3452,7 @@ static t_stat sim_instr_mmu (void) { break; case 0xbe: /* CP (HL) */ - tStates += 7; + tStates += 7; /* CMP M 7 */ CHECK_BREAK_BYTE(HL); temp = GetBYTE(HL); AF = (AF & ~0x28) | (temp & 0x28); @@ -3453,7 +3464,7 @@ static t_stat sim_instr_mmu (void) { break; case 0xbf: /* CP A */ - tStates += 4; + tStates += 4; /* CMP A 4 */ sim_brk_pend[0] = FALSE; SET_LOW_REGISTER(AF, (HIGH_REGISTER(AF) & 0x28) | (chiptype == CHIP_TYPE_Z80 ? 0x42 : 0x46)); break; @@ -3461,30 +3472,30 @@ static t_stat sim_instr_mmu (void) { case 0xc0: /* RET NZ */ if (TSTFLAG(Z)) { sim_brk_pend[0] = FALSE; - tStates += 5; + tStates += 5; /* RNZ 5 */ } else { CHECK_BREAK_WORD(SP); PCQ_ENTRY(PCX); POP(PC); - tStates += 11; + tStates += 11; /* RNZ 11 */ } break; case 0xc1: /* POP BC */ - tStates += 10; + tStates += 10; /* POP B 10 */ CHECK_BREAK_WORD(SP); POP(BC); break; case 0xc2: /* JP NZ,nnnn */ sim_brk_pend[0] = FALSE; - JPC(!TSTFLAG(Z)); /* also updates tStates */ + JPC(!TSTFLAG(Z)); /* also updates tStates, Z80 and 8080 are equal */ break; case 0xc3: /* JP nnnn */ sim_brk_pend[0] = FALSE; - JPC(1); /* also updates tStates */ + JPC(1); /* also updates tStates, Z80 and 8080 are equal */ break; case 0xc4: /* CALL NZ,nnnn */ @@ -3492,13 +3503,13 @@ static t_stat sim_instr_mmu (void) { break; case 0xc5: /* PUSH BC */ - tStates += 11; + tStates += 11; /* PUSH B 11 */ CHECK_BREAK_WORD(SP - 2); PUSH(BC); break; case 0xc6: /* ADD A,nn */ - tStates += 7; + tStates += 7; /* ADI nn 7 */ sim_brk_pend[0] = FALSE; temp = RAM_PP(PC); acu = HIGH_REGISTER(AF); @@ -3508,7 +3519,7 @@ static t_stat sim_instr_mmu (void) { break; case 0xc7: /* RST 0 */ - tStates += 11; + tStates += 11; /* RST 0 11 */ CHECK_BREAK_WORD(SP - 2); PUSH(PC); PCQ_ENTRY(PCX); @@ -3520,16 +3531,16 @@ static t_stat sim_instr_mmu (void) { CHECK_BREAK_WORD(SP); PCQ_ENTRY(PCX); POP(PC); - tStates += 11; + tStates += 11; /* RZ 11 */ } else { sim_brk_pend[0] = FALSE; - tStates += 5; + tStates += 5; /* RZ 5 */ } break; case 0xc9: /* RET */ - tStates += 10; + tStates += 10; /* RET 10 */ CHECK_BREAK_WORD(SP); PCQ_ENTRY(PCX); POP(PC); @@ -3541,7 +3552,17 @@ static t_stat sim_instr_mmu (void) { break; case 0xcb: /* CB prefix */ - CHECK_CPU_8080; + if (chiptype == CHIP_TYPE_8080) { + if (cpu_unit.flags & UNIT_CPU_OPSTOP) { + reason = STOP_OPCODE; + goto end_decode; + } + else { + sim_brk_pend[0] = FALSE; + JPC(1); + break; + } + } adr = HL; switch ((op = GetBYTE(PC)) & 7) { @@ -3717,7 +3738,7 @@ static t_stat sim_instr_mmu (void) { break; case 0xce: /* ADC A,nn */ - tStates += 7; + tStates += 7; /* ACI nn 7 */ sim_brk_pend[0] = FALSE; temp = RAM_PP(PC); acu = HIGH_REGISTER(AF); @@ -3727,7 +3748,7 @@ static t_stat sim_instr_mmu (void) { break; case 0xcf: /* RST 8 */ - tStates += 11; + tStates += 11; /* RST 1 */ CHECK_BREAK_WORD(SP - 2); PUSH(PC); PCQ_ENTRY(PCX); @@ -3737,18 +3758,18 @@ static t_stat sim_instr_mmu (void) { case 0xd0: /* RET NC */ if (TSTFLAG(C)) { sim_brk_pend[0] = FALSE; - tStates += 5; + tStates += 5; /* RNC 5 */ } else { CHECK_BREAK_WORD(SP); PCQ_ENTRY(PCX); POP(PC); - tStates += 11; + tStates += 11; /* RNC 11 */ } break; case 0xd1: /* POP DE */ - tStates += 10; + tStates += 10; /* POP D 10 */ CHECK_BREAK_WORD(SP); POP(DE); break; @@ -3759,7 +3780,7 @@ static t_stat sim_instr_mmu (void) { break; case 0xd3: /* OUT (nn),A */ - tStates += 11; + tStates += (chiptype == CHIP_TYPE_8080 ? 10 :11); /* OUT nn 10 */ sim_brk_pend[0] = FALSE; out(RAM_PP(PC), HIGH_REGISTER(AF)); break; @@ -3769,13 +3790,13 @@ static t_stat sim_instr_mmu (void) { break; case 0xd5: /* PUSH DE */ - tStates += 11; + tStates += 11; /* PUSH D 11 */ CHECK_BREAK_WORD(SP - 2); PUSH(DE); break; case 0xd6: /* SUB nn */ - tStates += 7; + tStates += 7; /* SUI nn 7 */ sim_brk_pend[0] = FALSE; temp = RAM_PP(PC); acu = HIGH_REGISTER(AF); @@ -3785,7 +3806,7 @@ static t_stat sim_instr_mmu (void) { break; case 0xd7: /* RST 10H */ - tStates += 11; + tStates += 11; /* RST 2 11 */ CHECK_BREAK_WORD(SP - 2); PUSH(PC); PCQ_ENTRY(PCX); @@ -3797,18 +3818,30 @@ static t_stat sim_instr_mmu (void) { CHECK_BREAK_WORD(SP); PCQ_ENTRY(PCX); POP(PC); - tStates += 11; + tStates += 11; /* RC 11 */ } else { sim_brk_pend[0] = FALSE; - tStates += 5; + tStates += 5; /* RC 5 */ } break; case 0xd9: /* EXX */ + if (chiptype == CHIP_TYPE_8080) { + if (cpu_unit.flags & UNIT_CPU_OPSTOP) { + reason = STOP_OPCODE; + goto end_decode; + } + else { + tStates += 10; /* RET 10 */ + CHECK_BREAK_WORD(SP); + PCQ_ENTRY(PCX); + POP(PC); + break; + } + } tStates += 4; sim_brk_pend[0] = FALSE; - CHECK_CPU_8080; temp = BC; BC = BC1_S; BC1_S = temp; @@ -3826,7 +3859,7 @@ static t_stat sim_instr_mmu (void) { break; case 0xdb: /* IN A,(nn) */ - tStates += 11; + tStates += (chiptype == CHIP_TYPE_8080 ? 10 : 11); /* IN nn 10 */ sim_brk_pend[0] = FALSE; SET_HIGH_REGISTER(AF, in(RAM_PP(PC))); break; @@ -3836,7 +3869,16 @@ static t_stat sim_instr_mmu (void) { break; case 0xdd: /* DD prefix */ - CHECK_CPU_8080; + if (chiptype == CHIP_TYPE_8080) { + if (cpu_unit.flags & UNIT_CPU_OPSTOP) { + reason = STOP_OPCODE; + goto end_decode; + } + else { + CALLC(1); /* also updates tStates */ + break; + } + } switch (RAM_PP(PC)) { case 0x09: /* ADD IX,BC */ @@ -4611,7 +4653,7 @@ static t_stat sim_instr_mmu (void) { break; case 0xde: /* SBC A,nn */ - tStates += 7; + tStates += 7; /* SBI nn 7 */ sim_brk_pend[0] = FALSE; temp = RAM_PP(PC); acu = HIGH_REGISTER(AF); @@ -4621,7 +4663,7 @@ static t_stat sim_instr_mmu (void) { break; case 0xdf: /* RST 18H */ - tStates += 11; + tStates += 11; /* RST 3 11 */ CHECK_BREAK_WORD(SP - 2); PUSH(PC); PCQ_ENTRY(PCX); @@ -4631,18 +4673,18 @@ static t_stat sim_instr_mmu (void) { case 0xe0: /* RET PO */ if (TSTFLAG(P)) { sim_brk_pend[0] = FALSE; - tStates += 5; + tStates += 5; /* RPO 5 */ } else { CHECK_BREAK_WORD(SP); PCQ_ENTRY(PCX); POP(PC); - tStates += 11; + tStates += 11; /* RPO 11 */ } break; case 0xe1: /* POP HL */ - tStates += 10; + tStates += 10; /* POP H 10 */ CHECK_BREAK_WORD(SP); POP(HL); break; @@ -4653,7 +4695,7 @@ static t_stat sim_instr_mmu (void) { break; case 0xe3: /* EX (SP),HL */ - tStates += 19; + tStates += (chiptype == CHIP_TYPE_8080 ? 18 : 19); /* XTHL 18 */ CHECK_BREAK_WORD(SP); temp = HL; POP(HL); @@ -4665,19 +4707,19 @@ static t_stat sim_instr_mmu (void) { break; case 0xe5: /* PUSH HL */ - tStates += 11; + tStates += 11; /* PUSH H 11 */ CHECK_BREAK_WORD(SP - 2); PUSH(HL); break; case 0xe6: /* AND nn */ - tStates += 7; + tStates += 7; /* ANI nn 7 */ sim_brk_pend[0] = FALSE; AF = andTable[((AF >> 8) & RAM_PP(PC)) & 0xff]; break; case 0xe7: /* RST 20H */ - tStates += 11; + tStates += 11; /* RST 4 11 */ CHECK_BREAK_WORD(SP - 2); PUSH(PC); PCQ_ENTRY(PCX); @@ -4689,16 +4731,16 @@ static t_stat sim_instr_mmu (void) { CHECK_BREAK_WORD(SP); PCQ_ENTRY(PCX); POP(PC); - tStates += 11; + tStates += 11; /* RPE 11 */ } else { sim_brk_pend[0] = FALSE; - tStates += 5; + tStates += 5; /* RPE 5 */ } break; case 0xe9: /* JP (HL) */ - tStates += 4; + tStates += (chiptype == CHIP_TYPE_8080 ? 5 : 4); /* PCHL 5 */ sim_brk_pend[0] = FALSE; PCQ_ENTRY(PCX); PC = HL; @@ -4710,7 +4752,7 @@ static t_stat sim_instr_mmu (void) { break; case 0xeb: /* EX DE,HL */ - tStates += 4; + tStates += (chiptype == CHIP_TYPE_8080 ? 5 : 4); /* XCHG 5 */ sim_brk_pend[0] = FALSE; temp = HL; HL = DE; @@ -4722,7 +4764,16 @@ static t_stat sim_instr_mmu (void) { break; case 0xed: /* ED prefix */ - CHECK_CPU_8080; + if (chiptype == CHIP_TYPE_8080) { + if (cpu_unit.flags & UNIT_CPU_OPSTOP) { + reason = STOP_OPCODE; + goto end_decode; + } + else { + CALLC(1); /* also updates tStates */ + break; + } + } switch (RAM_PP(PC)) { case 0x40: /* IN B,(C) */ @@ -5363,13 +5414,13 @@ static t_stat sim_instr_mmu (void) { break; case 0xee: /* XOR nn */ - tStates += 7; + tStates += 7; /* XRI nn 7 */ sim_brk_pend[0] = FALSE; AF = xororTable[((AF >> 8) ^ RAM_PP(PC)) & 0xff]; break; case 0xef: /* RST 28H */ - tStates += 11; + tStates += 11; /* RST 5 11 */ CHECK_BREAK_WORD(SP - 2); PUSH(PC); PCQ_ENTRY(PCX); @@ -5379,18 +5430,18 @@ static t_stat sim_instr_mmu (void) { case 0xf0: /* RET P */ if (TSTFLAG(S)) { sim_brk_pend[0] = FALSE; - tStates += 5; + tStates += 5; /* RP 5 */ } else { CHECK_BREAK_WORD(SP); PCQ_ENTRY(PCX); POP(PC); - tStates += 11; + tStates += 11; /* RP 11 */ } break; case 0xf1: /* POP AF */ - tStates += 10; + tStates += 10; /* POP PSW 10 */ CHECK_BREAK_WORD(SP); POP(AF); break; @@ -5401,7 +5452,7 @@ static t_stat sim_instr_mmu (void) { break; case 0xf3: /* DI */ - tStates += 4; + tStates += 4; /* DI 4 */ sim_brk_pend[0] = FALSE; IFF_S = 0; break; @@ -5411,19 +5462,19 @@ static t_stat sim_instr_mmu (void) { break; case 0xf5: /* PUSH AF */ - tStates += 11; + tStates += 11; /* PUSH PSW 11 */ CHECK_BREAK_WORD(SP - 2); PUSH(AF); break; case 0xf6: /* OR nn */ - tStates += 7; + tStates += 7; /* ORI nn 7 */ sim_brk_pend[0] = FALSE; AF = xororTable[((AF >> 8) | RAM_PP(PC)) & 0xff]; break; case 0xf7: /* RST 30H */ - tStates += 11; + tStates += 11; /* RST 6 11 */ CHECK_BREAK_WORD(SP - 2); PUSH(PC); PCQ_ENTRY(PCX); @@ -5435,16 +5486,16 @@ static t_stat sim_instr_mmu (void) { CHECK_BREAK_WORD(SP); PCQ_ENTRY(PCX); POP(PC); - tStates += 11; + tStates += 11; /* RM 11 */ } else { sim_brk_pend[0] = FALSE; - tStates += 5; + tStates += 5; /* RM 5 */ } break; case 0xf9: /* LD SP,HL */ - tStates += 6; + tStates += (chiptype == CHIP_TYPE_8080 ? 5 : 6); /* SPHL 5 */ sim_brk_pend[0] = FALSE; SP = HL; break; @@ -5455,7 +5506,7 @@ static t_stat sim_instr_mmu (void) { break; case 0xfb: /* EI */ - tStates += 4; + tStates += 4; /* EI 4 */ sim_brk_pend[0] = FALSE; IFF_S = 3; break; @@ -5465,7 +5516,16 @@ static t_stat sim_instr_mmu (void) { break; case 0xfd: /* FD prefix */ - CHECK_CPU_8080; + if (chiptype == CHIP_TYPE_8080) { + if (cpu_unit.flags & UNIT_CPU_OPSTOP) { + reason = STOP_OPCODE; + goto end_decode; + } + else { + CALLC(1); /* also updates tStates */ + break; + } + } switch (RAM_PP(PC)) { case 0x09: /* ADD IY,BC */ @@ -6240,7 +6300,7 @@ static t_stat sim_instr_mmu (void) { break; case 0xfe: /* CP nn */ - tStates += 7; + tStates += 7; /* CPI nn 7 */ sim_brk_pend[0] = FALSE; temp = RAM_PP(PC); AF = (AF & ~0x28) | (temp & 0x28); @@ -6252,7 +6312,7 @@ static t_stat sim_instr_mmu (void) { break; case 0xff: /* RST 38H */ - tStates += 11; + tStates += 11; /* RST 7 11 */ CHECK_BREAK_WORD(SP - 2); PUSH(PC); PCQ_ENTRY(PCX); @@ -6271,7 +6331,7 @@ static t_stat sim_instr_mmu (void) { /* simulation halted */ PC_S = ((reason == STOP_OPCODE) || (reason == STOP_MEM)) ? PCX : (PC & ADDRMASK); - pcq_r -> qptr = pcq_p; /* update pc q ptr */ + pcq_r->qptr = pcq_p; /* update pc q ptr */ AF_S = AF; BC_S = BC; DE_S = DE; @@ -6302,7 +6362,7 @@ static t_stat cpu_reset(DEVICE *dptr) { pcq_p = 0; pcq_r = find_reg("PCQ", NULL, dptr); if (pcq_r) - pcq_r -> qptr = 0; + pcq_r->qptr = 0; else return SCPE_IERR; return SCPE_OK; diff --git a/AltairZ80/altairz80_cpu_nommu.c b/AltairZ80/altairz80_cpu_nommu.c index a390ca4b..dbd38f27 100644 --- a/AltairZ80/altairz80_cpu_nommu.c +++ b/AltairZ80/altairz80_cpu_nommu.c @@ -1,6 +1,6 @@ /* altairz80_cpu_opt.c: MITS Altair CPU (8080 and Z80) - Copyright (c) 2002-2011, Peter Schorn + Copyright (c) 2002-2012, Peter Schorn Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/AltairZ80/altairz80_defs.h b/AltairZ80/altairz80_defs.h index 162fd7c9..75341d49 100644 --- a/AltairZ80/altairz80_defs.h +++ b/AltairZ80/altairz80_defs.h @@ -1,6 +1,6 @@ /* altairz80_defs.h: MITS Altair simulator definitions - Copyright (c) 2002-2011, Peter Schorn + Copyright (c) 2002-2012, Peter Schorn Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/AltairZ80/altairz80_dsk.c b/AltairZ80/altairz80_dsk.c index 4c7e9742..4dcca246 100644 --- a/AltairZ80/altairz80_dsk.c +++ b/AltairZ80/altairz80_dsk.c @@ -1,6 +1,6 @@ /* altairz80_dsk.c: MITS Altair 88-DISK Simulator - Copyright (c) 2002-2011, Peter Schorn + Copyright (c) 2002-2012, Peter Schorn Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -330,7 +330,7 @@ static t_stat dsk_boot(int32 unitno, DEVICE *dptr) { } static int32 dskseek(const UNIT *xptr) { - return sim_fseek(xptr -> fileref, DSK_TRACSIZE * current_track[current_disk] + + return sim_fseek(xptr->fileref, DSK_TRACSIZE * current_track[current_disk] + DSK_SECTSIZE * current_sector[current_disk], SEEK_SET); } @@ -342,7 +342,7 @@ static void writebuf(void) { while (i < DSK_SECTSIZE) dskbuf[i++] = 0; uptr = dsk_dev.units + current_disk; - if (((uptr -> flags) & UNIT_DSK_WLK) == 0) { /* write enabled */ + if (((uptr->flags) & UNIT_DSK_WLK) == 0) { /* write enabled */ sim_debug(WRITE_MSG, &dsk_dev, "DSK%i: " ADDRESS_FORMAT " OUT 0x0a (WRITE) D%d T%d S%d\n", current_disk, PCX, current_disk, @@ -353,7 +353,7 @@ static void writebuf(void) { current_disk, PCX, current_disk, current_track[current_disk], current_sector[current_disk]); } - rtn = sim_fwrite(dskbuf, 1, DSK_SECTSIZE, uptr -> fileref); + rtn = sim_fwrite(dskbuf, 1, DSK_SECTSIZE, uptr->fileref); if (rtn != DSK_SECTSIZE) { sim_debug(VERBOSE_MSG, &dsk_dev, "DSK%i: " ADDRESS_FORMAT " sim_fwrite failed T%d S%d Return=%d\n", @@ -414,7 +414,7 @@ int32 dsk10(const int32 port, const int32 io, const int32 data) { writebuf(); sim_debug(OUT_MSG, &dsk_dev, "DSK%i: " ADDRESS_FORMAT " OUT 0x08: %x\n", current_disk, PCX, data); current_disk = data & NUM_OF_DSK_MASK; /* 0 <= current_disk < NUM_OF_DSK */ - current_disk_flags = (dsk_dev.units + current_disk) -> flags; + current_disk_flags = (dsk_dev.units + current_disk)->flags; if ((current_disk_flags & UNIT_ATT) == 0) { /* nothing attached? */ if ( (dsk_dev.dctrl & VERBOSE_MSG) && (warnAttached[current_disk] < warnLevelDSK) ) { warnAttached[current_disk]++; @@ -482,6 +482,7 @@ int32 dsk11(const int32 port, const int32 io, const int32 data) { "DSK%i: " ADDRESS_FORMAT " Unnecessary step in.\n", current_disk, PCX); current_track[current_disk]++; + current_flag[current_disk] &= 0xbf; /* mwd 1/29/13: track zero now false */ if (current_track[current_disk] > (tracks[current_disk] - 1)) current_track[current_disk] = (tracks[current_disk] - 1); if (dirty) /* implies that current_disk < NUM_OF_DSK */ @@ -568,7 +569,7 @@ int32 dsk12(const int32 port, const int32 io, const int32 data) { current_track[current_disk], current_sector[current_disk]); } } - rtn = sim_fread(dskbuf, 1, DSK_SECTSIZE, uptr -> fileref); + rtn = sim_fread(dskbuf, 1, DSK_SECTSIZE, uptr->fileref); if (rtn != DSK_SECTSIZE) { if ((dsk_dev.dctrl & VERBOSE_MSG) && (warnDSK12 < warnLevelDSK)) { warnDSK12++; diff --git a/AltairZ80/altairz80_hdsk.c b/AltairZ80/altairz80_hdsk.c index 085b17e5..fb277571 100644 --- a/AltairZ80/altairz80_hdsk.c +++ b/AltairZ80/altairz80_hdsk.c @@ -1,6 +1,6 @@ /* altairz80_hdsk.c: simulated hard disk device to increase capacity - Copyright (c) 2002-2011, Peter Schorn + Copyright (c) 2002-2012, Peter Schorn Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -28,6 +28,7 @@ #include "altairz80_defs.h" #include +#include "sim_imd.h" /* Debug flags */ #define READ_MSG (1 << 0) @@ -43,6 +44,9 @@ static t_stat show_format(FILE *st, UNIT *uptr, int32 val, void *desc); static t_stat hdsk_reset(DEVICE *dptr); static t_stat hdsk_attach(UNIT *uptr, char *cptr); static t_stat hdsk_detach(UNIT *uptr); +static uint32 is_imd(const UNIT *uptr); +static void assignFormat(UNIT *uptr); +static void verifyDiskInfo(const DISK_INFO info, const char unitChar); #define UNIT_V_HDSK_WLK (UNIT_V_UF + 0) /* write locked */ #define UNIT_HDSK_WLK (1 << UNIT_V_HDSK_WLK) @@ -68,6 +72,7 @@ static t_stat hdsk_detach(UNIT *uptr); extern uint32 PCX; extern REG *sim_PC; extern UNIT cpu_unit; +extern FILE *sim_deb; extern void install_ALTAIRbootROM(void); extern void PutBYTEWrapper(const uint32 Addr, const uint32 Value); @@ -118,6 +123,7 @@ typedef struct { #define SPT16 16 #define SPT32 32 #define SPT26 26 +#define SPT52 52 static HDSK_INFO hdsk_info_data = { { 0x0000, 0, 0xFD, 1 } }; @@ -126,18 +132,18 @@ static int32 standard8[SPT26] = { 0, 6, 12, 18, 24, 4, 10, 16, 19, 25, 5, 11, 17, 23, 3, 9, 15, 21 }; -static int32 appple_ii_DOS[SPT16] = { 0, 6, 12, 3, 9, 15, 14, 5, +static int32 apple_ii_DOS[SPT16] = { 0, 6, 12, 3, 9, 15, 14, 5, 11, 2, 8, 7, 13, 4, 10, 1 }; -static int32 appple_ii_DOS2[SPT32] = { 0, 1, 12, 13, 24, 25, 6, 7, +static int32 apple_ii_DOS2[SPT32] = { 0, 1, 12, 13, 24, 25, 6, 7, 18, 19, 30, 31, 28, 29, 10, 11, 22, 23, 4, 5, 16, 17, 14, 15, 26, 27, 8, 9, 20, 21, 2, 3 }; -static int32 appple_ii_PRODOS[SPT16] = { 0, 9, 3, 12, 6, 15, 1, 10, +static int32 apple_ii_PRODOS[SPT16] = { 0, 9, 3, 12, 6, 15, 1, 10, 4, 13, 7, 8, 2, 11, 5, 14 }; -static int32 appple_ii_PRODOS2[SPT32] = { 0, 1, 18, 19, 6, 7, 24, 25, +static int32 apple_ii_PRODOS2[SPT32] = { 0, 1, 18, 19, 6, 7, 24, 25, 12, 13, 30, 31, 2, 3, 20, 21, 8, 9, 26, 27, 14, 15, 16, 17, 4, 5, 22, 23, 10, 11, 28, 29 }; @@ -197,17 +203,44 @@ static DPB dpb[] = { { "SSSD8S", 256256, SPT26, 0x03, 0x07, 0x00, 242, 0x003F, 0xC0, 0x00, 0x0000, 0x0002, 0x00, 0x00, 0, 0, standard8 }, /* Standard 8" SS SD with skew */ + { "SSDD8", 512512, SPT52, 0x04, 0x0F, 0x01, 242, 0x007F, + 0xC0, 0x00, 0x0000, 0x0002, 0x01, 0x01, 0, 0, NULL }, /* Standard 8" SS DD */ + + { "SSDD8S", 512512, SPT52, 0x04, 0x0F, 0x01, 242, 0x007F, + 0xC0, 0x00, 0x0000, 0x0002, 0x01, 0x01, 0, 0, standard8 }, /* Standard 8" SS DD with skew */ + + { "DSDD8", 1025024, SPT52, 0x04, 0x0F, 0x00, 493, 0x007F, + 0xC0, 0x00, 0x0000, 0x0002, 0x01, 0x01, 0, 0, NULL }, /* Standard 8" DS DD */ + + { "DSDD8S", 1025024, SPT52, 0x04, 0x0F, 0x00, 493, 0x007F, + 0xC0, 0x00, 0x0000, 0x0002, 0x01, 0x01, 0, 0, NULL }, /* Standard 8" DS DD with skew */ + + {"512SSDD8",591360, 60, 0x04, 0x0F, 0x00, 280, 0x007F, + 0xC0, 0x00, 0x0000, 0x0002, 0x02, 0x03, 0, 0, NULL }, /* Standard 8" SS DD with 512 byte sectors */ + + {"512DSDD8",1182720, 60, 0x04, 0x0F, 0x00, 569, 0x007F, + 0xC0, 0x00, 0x0000, 0x0002, 0x02, 0x03, 0, 0, NULL }, /* Standard 8" DS DD with 512 byte sectors */ + +#if 0 + /* CP/M 3 BIOS currently does not support physical sector size 1024 */ + {"1024SSDD8",630784, 64, 0x04, 0x0F, 0x00, 299, 0x007F, + 0xC0, 0x00, 0x0000, 0x0002, 0x03, 0x07, 0, 0, NULL }, /* Standard 8" SS DD with 1024 byte sectors */ + + {"1024DSDD8",1261568, 64, 0x04, 0x0F, 0x00, 607, 0x007F, + 0xC0, 0x00, 0x0000, 0x0002, 0x03, 0x07, 0, 0, NULL }, /* Standard 8" DS DD with 1024 byte sectors */ +#endif + { "APPLE-DO",143360, SPT32, 0x03, 0x07, 0x00, 127, 0x003F, - 0xC0, 0x00, 0x0000, 0x0003, 0x01, 0x01, 0, 0, appple_ii_DOS }, /* Apple II DOS 3.3 */ + 0xC0, 0x00, 0x0000, 0x0003, 0x01, 0x01, 0, 0, apple_ii_DOS }, /* Apple II DOS 3.3 */ { "APPLE-PO",143360, SPT32, 0x03, 0x07, 0x00, 127, 0x003F, - 0xC0, 0x00, 0x0000, 0x0003, 0x01, 0x01, 0, 0, appple_ii_PRODOS }, /* Apple II PRODOS */ + 0xC0, 0x00, 0x0000, 0x0003, 0x01, 0x01, 0, 0, apple_ii_PRODOS }, /* Apple II PRODOS */ { "APPLE-D2",143360, SPT32, 0x03, 0x07, 0x00, 127, 0x003F, - 0xC0, 0x00, 0x0000, 0x0003, 0x00, 0x00, 0, 0, appple_ii_DOS2 }, /* Apple II DOS 3.3, deblocked */ + 0xC0, 0x00, 0x0000, 0x0003, 0x00, 0x00, 0, 0, apple_ii_DOS2 }, /* Apple II DOS 3.3, deblocked */ { "APPLE-P2",143360, SPT32, 0x03, 0x07, 0x00, 127, 0x003F, - 0xC0, 0x00, 0x0000, 0x0003, 0x00, 0x00, 0, 0, appple_ii_PRODOS2 }, /* Apple II PRODOS, deblocked */ + 0xC0, 0x00, 0x0000, 0x0003, 0x00, 0x00, 0, 0, apple_ii_PRODOS2 }, /* Apple II PRODOS, deblocked */ { "MITS", 337568, SPT32, 0x03, 0x07, 0x00, 254, 0x00FF, 0xFF, 0x00, 0x0000, 0x0006, 0x00, 0x00, 137, 3, mits }, /* MITS Altair original */ @@ -215,6 +248,20 @@ static DPB dpb[] = { { "MITS2", 1113536, SPT32, 0x04, 0x0F, 0x00, 0x1EF, 0x00FF, 0xF0, 0x00, 0x0000, 0x0006, 0x00, 0x00, 137, 3, mits }, /* MITS Altair original, extra */ + /* + dw 40 ;#128 byte records/track + db 4,0fh ;block shift mask (2K) + db 1 ;extent mask + dw 194 ;maximun block number + dw 127 ;max number of dir entry - 1 + db 0C0H,00h ;alloc vector for directory + dw 0020h ;checksum size + dw 2 ;offset for sys tracks + db 2,3 ;physical sector shift (512 sector) + */ + { "V1050", 409600, 40, 0x04, 0x0F, 0x01, 194, 0x007F, + 0xC0, 0x00, 0x0000, 0x0002, 0x02, 0x03, 0, 0, NULL }, /* Visual Technology Visual 1050, http://www.metabarn.com/v1050/index.html */ + { "", 0 } }; @@ -228,6 +275,7 @@ static UNIT hdsk_unit[] = { { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, HDSK_CAPACITY) }, { UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, HDSK_CAPACITY) } }; +static DISK_INFO* hdsk_imd[HDSK_NUMBER]; static REG hdsk_reg[] = { { DRDATA (HDCMD, hdskLastCommand, 32), REG_RO }, @@ -268,9 +316,9 @@ DEVICE hdsk_dev = { /* Reset routine */ static t_stat hdsk_reset(DEVICE *dptr) { PNP_INFO *pnp = (PNP_INFO *)dptr->ctxt; - if (dptr->flags & DEV_DIS) { + if (dptr->flags & DEV_DIS) sim_map_resource(pnp->io_base, pnp->io_size, RESOURCE_TYPE_IO, &hdsk_io, TRUE); - } else { + else { /* Connect HDSK at base address */ if (sim_map_resource(pnp->io_base, pnp->io_size, RESOURCE_TYPE_IO, &hdsk_io, FALSE) != 0) { printf("%s: error mapping I/O resource at 0x%04x\n", __FUNCTION__, pnp->mem_base); @@ -281,83 +329,156 @@ static t_stat hdsk_reset(DEVICE *dptr) { return SCPE_OK; } -/* Attach routine */ -static t_stat hdsk_attach(UNIT *uptr, char *cptr) { - t_stat r; +#ifdef _WIN32 +#define strcasecmp _stricmp +#endif +static uint32 is_imd(const UNIT *uptr) { + return ((uptr != NULL) && (uptr->filename != NULL) && (strlen(uptr->filename) > 3) && + (strcasecmp(".IMD", uptr->filename + strlen(uptr->filename) - 4) == 0)); +} + +static void assignFormat(UNIT *uptr) { uint32 i; - char unitChar; - - r = attach_unit(uptr, cptr); /* attach unit */ - if ( r != SCPE_OK) /* error? */ - return r; - - /* Step 1: Determine capacity of this disk */ - uptr -> capac = sim_fsize(uptr -> fileref); /* the file length is a good indication */ - if (uptr -> capac == 0) { /* file does not exist or has length 0 */ - uptr -> capac = uptr -> HDSK_NUMBER_OF_TRACKS * - uptr -> HDSK_SECTORS_PER_TRACK * uptr -> HDSK_SECTOR_SIZE; - if (uptr -> capac == 0) - uptr -> capac = HDSK_CAPACITY; - } /* post condition: uptr -> capac > 0 */ - assert(uptr -> capac); - - /* Step 2: Determine format based on disk capacity */ - uptr -> HDSK_FORMAT_TYPE = -1; /* default to unknown format type */ - for (i = 0; dpb[i].capac != 0; i++) { /* find disk parameter block */ - if (dpb[i].capac == uptr -> capac) { /* found if correct capacity */ - uptr -> HDSK_FORMAT_TYPE = i; + uptr->HDSK_FORMAT_TYPE = -1; /* default to unknown format type */ + for (i = 0; dpb[i].capac != 0; i++) { /* find disk parameter block */ + if (dpb[i].capac == uptr->capac) { /* found if correct capacity */ + uptr->HDSK_FORMAT_TYPE = i; break; } } +} +static void verifyDiskInfo(const DISK_INFO info, const char unitChar) { + uint32 track, head; + if (info.ntracks < 1) + printf("HDSK%c (IMD): WARNING: Number of tracks is 0.\n", unitChar); + if (info.nsides < 1) { + printf("HDSK%c (IMD): WARNING: Number of sides is 0.\n", unitChar); + return; + } + for (track = 0; track < info.ntracks / info.nsides; track++) + for (head = 0; head < info.nsides; head++) { + if (info.track[track][head].nsects != info.track[1][0].nsects) + printf("HDSK%c (IMD): WARNING: For track %i and head %i expected number of sectors " + "%i but got %i.\n", unitChar, track, head, + info.track[1][0].nsects, info.track[track][head].nsects); + if (info.track[track][head].sectsize != info.track[1][0].sectsize) + printf("HDSK%c (IMD): WARNING: For track %i and head %i expected sector size " + "%i but got %i.\n", unitChar, track, head, + info.track[1][0].sectsize, info.track[track][head].sectsize); + if (info.track[track][head].start_sector != info.track[1][0].start_sector) + printf("HDSK%c (IMD): WARNING: For track %i and head %i expected start sector " + "%i but got %i.\n", unitChar, track, head, + info.track[1][0].start_sector, info.track[track][head].start_sector); + } +} + +/* Attach routine */ +static t_stat hdsk_attach(UNIT *uptr, char *cptr) { + int32 thisUnitIndex; + char unitChar; + const t_stat r = attach_unit(uptr, cptr); /* attach unit */ + if (r != SCPE_OK) /* error? */ + return r; + + assert(uptr != NULL); + thisUnitIndex = find_unit_index(uptr); + unitChar = '0' + thisUnitIndex; + assert((0 <= thisUnitIndex) && (thisUnitIndex < HDSK_NUMBER)); + + if (is_imd(uptr)) { + if ((sim_fsize(uptr->fileref) == 0) && + (diskCreate(uptr->fileref, "$Id: SIMH hdsk.c $") != SCPE_OK)) { + printf("HDSK%c (IMD): Failed to create IMD disk.\n", unitChar); + detach_unit(uptr); + return SCPE_OPENERR; + } + hdsk_imd[thisUnitIndex] = diskOpen(uptr->fileref, sim_deb && (hdsk_dev.dctrl & VERBOSE_MSG)); + if (hdsk_imd[thisUnitIndex] == NULL) + return SCPE_IOERR; + verifyDiskInfo(*hdsk_imd[thisUnitIndex], '0' + thisUnitIndex); + uptr->HDSK_NUMBER_OF_TRACKS = hdsk_imd[thisUnitIndex]->ntracks; + uptr->HDSK_SECTORS_PER_TRACK = hdsk_imd[thisUnitIndex]->track[1][0].nsects; + uptr->HDSK_SECTOR_SIZE = hdsk_imd[thisUnitIndex]->track[1][0].sectsize; + uptr->capac = ((uptr->HDSK_NUMBER_OF_TRACKS) * + (uptr->HDSK_SECTORS_PER_TRACK) * + (uptr->HDSK_SECTOR_SIZE)); + assignFormat(uptr); + if (uptr->HDSK_FORMAT_TYPE == -1) { /* Case 1: no disk parameter block found*/ + uptr->HDSK_FORMAT_TYPE = 0; + printf("HDSK%c (IMD): WARNING: Unsupported disk capacity, assuming HDSK type " + "with capacity %iKB.\n", unitChar, uptr->capac / 1000); + uptr->flags |= UNIT_HDSK_WLK; + printf("HDSK%c (IMD): WARNING: Forcing WRTLCK.\n", unitChar); + } + return SCPE_OK; + } + + /* Step 1: Determine capacity of this disk */ + uptr->capac = sim_fsize(uptr->fileref); /* the file length is a good indication */ + if (uptr->capac == 0) { /* file does not exist or has length 0 */ + uptr->capac = (uptr->HDSK_NUMBER_OF_TRACKS * + uptr->HDSK_SECTORS_PER_TRACK * uptr->HDSK_SECTOR_SIZE); + if (uptr->capac == 0) + uptr->capac = HDSK_CAPACITY; + } /* post condition: uptr->capac > 0 */ + assert(uptr->capac); + + /* Step 2: Determine format based on disk capacity */ + assignFormat(uptr); + /* Step 3: Set number of sectors per track and sector size */ - if (uptr -> HDSK_FORMAT_TYPE == -1) { /* Case 1: no disk parameter block found*/ - for (i = 0; i < hdsk_dev.numunits; i++) /* find affected unit number */ - if (&hdsk_unit[i] == uptr) - break; /* found */ - unitChar = '0' + i; - uptr -> HDSK_FORMAT_TYPE = 0; + if (uptr->HDSK_FORMAT_TYPE == -1) { /* Case 1: no disk parameter block found*/ + uptr->HDSK_FORMAT_TYPE = 0; printf("HDSK%c: WARNING: Unsupported disk capacity, assuming HDSK type with capacity %iKB.\n", - unitChar, uptr -> capac / 1000); - uptr -> flags |= UNIT_HDSK_WLK; + unitChar, uptr->capac / 1000); + uptr->flags |= UNIT_HDSK_WLK; printf("HDSK%c: WARNING: Forcing WRTLCK.\n", unitChar); /* check whether capacity corresponds to setting of tracks, sectors per track and sector size */ - if (uptr -> capac != (uint32)(uptr -> HDSK_NUMBER_OF_TRACKS * - uptr -> HDSK_SECTORS_PER_TRACK * uptr -> HDSK_SECTOR_SIZE)) { + if (uptr->capac != (uint32)(uptr->HDSK_NUMBER_OF_TRACKS * + uptr->HDSK_SECTORS_PER_TRACK * uptr->HDSK_SECTOR_SIZE)) { printf("HDSK%c: WARNING: Fixing geometry.\n", unitChar); - if (uptr -> HDSK_SECTORS_PER_TRACK == 0) - uptr -> HDSK_SECTORS_PER_TRACK = 32; - if (uptr -> HDSK_SECTOR_SIZE == 0) - uptr -> HDSK_SECTOR_SIZE = 128; + if (uptr->HDSK_SECTORS_PER_TRACK == 0) + uptr->HDSK_SECTORS_PER_TRACK = 32; + if (uptr->HDSK_SECTOR_SIZE == 0) + uptr->HDSK_SECTOR_SIZE = 128; } } else { /* Case 2: disk parameter block found */ - uptr -> HDSK_SECTORS_PER_TRACK = dpb[uptr -> HDSK_FORMAT_TYPE].spt >> dpb[uptr -> HDSK_FORMAT_TYPE].psh; - uptr -> HDSK_SECTOR_SIZE = (128 << dpb[uptr -> HDSK_FORMAT_TYPE].psh); + uptr->HDSK_SECTORS_PER_TRACK = dpb[uptr->HDSK_FORMAT_TYPE].spt >> dpb[uptr->HDSK_FORMAT_TYPE].psh; + uptr->HDSK_SECTOR_SIZE = (128 << dpb[uptr->HDSK_FORMAT_TYPE].psh); } - assert((uptr -> HDSK_SECTORS_PER_TRACK) && (uptr -> HDSK_SECTOR_SIZE) && (uptr -> HDSK_FORMAT_TYPE >= 0)); - + assert((uptr->HDSK_SECTORS_PER_TRACK) && (uptr->HDSK_SECTOR_SIZE) && (uptr->HDSK_FORMAT_TYPE >= 0)); + /* Step 4: Number of tracks is smallest number to accomodate capacity */ - uptr -> HDSK_NUMBER_OF_TRACKS = (uptr -> capac + uptr -> HDSK_SECTORS_PER_TRACK * - uptr -> HDSK_SECTOR_SIZE - 1) / (uptr -> HDSK_SECTORS_PER_TRACK * uptr -> HDSK_SECTOR_SIZE); - assert( ( (t_addr) ((uptr -> HDSK_NUMBER_OF_TRACKS - 1) * uptr -> HDSK_SECTORS_PER_TRACK * - uptr -> HDSK_SECTOR_SIZE) < uptr -> capac) && - (uptr -> capac <= (t_addr) (uptr -> HDSK_NUMBER_OF_TRACKS * - uptr -> HDSK_SECTORS_PER_TRACK * uptr -> HDSK_SECTOR_SIZE) ) ); - + uptr->HDSK_NUMBER_OF_TRACKS = (uptr->capac + uptr->HDSK_SECTORS_PER_TRACK * + uptr->HDSK_SECTOR_SIZE - 1) / (uptr->HDSK_SECTORS_PER_TRACK * uptr->HDSK_SECTOR_SIZE); + assert( ( (t_addr) ((uptr->HDSK_NUMBER_OF_TRACKS - 1) * uptr->HDSK_SECTORS_PER_TRACK * + uptr->HDSK_SECTOR_SIZE) < uptr->capac) && + (uptr->capac <= (t_addr) (uptr->HDSK_NUMBER_OF_TRACKS * + uptr->HDSK_SECTORS_PER_TRACK * uptr->HDSK_SECTOR_SIZE) ) ); + return SCPE_OK; } static t_stat hdsk_detach(UNIT *uptr) { t_stat result; + int32 unitIndex; if (uptr == NULL) return SCPE_IERR; + if (is_imd(uptr)) { + unitIndex = find_unit_index(uptr); + if (unitIndex == -1) + return SCPE_IERR; + assert((0 <= unitIndex) && (unitIndex < HDSK_NUMBER)); + diskClose(&hdsk_imd[unitIndex]); + } result = detach_unit(uptr); - uptr -> capac = HDSK_CAPACITY; - uptr -> HDSK_FORMAT_TYPE = 0; - uptr -> HDSK_SECTOR_SIZE = 0; - uptr -> HDSK_SECTORS_PER_TRACK = 0; - uptr -> HDSK_NUMBER_OF_TRACKS = 0; + uptr->capac = HDSK_CAPACITY; + uptr->HDSK_FORMAT_TYPE = 0; + uptr->HDSK_SECTOR_SIZE = 0; + uptr->HDSK_SECTORS_PER_TRACK = 0; + uptr->HDSK_NUMBER_OF_TRACKS = 0; return result; } @@ -370,7 +491,7 @@ static t_stat set_geom(UNIT *uptr, int32 val, char *cptr, void *desc) { return SCPE_ARG; if (uptr == NULL) return SCPE_IERR; - if (((uptr -> flags) & UNIT_ATT) == 0) { + if (((uptr->flags) & UNIT_ATT) == 0) { printf("Cannot set geometry for not attached unit %i.\n", find_unit_index(uptr)); return SCPE_ARG; } @@ -380,10 +501,10 @@ static t_stat set_geom(UNIT *uptr, int32 val, char *cptr, void *desc) { if ((result != 3) || (result == EOF) || (cptr[n] != 0)) return SCPE_ARG; } - uptr -> HDSK_NUMBER_OF_TRACKS = numberOfTracks; - uptr -> HDSK_SECTORS_PER_TRACK = numberOfSectors; - uptr -> HDSK_SECTOR_SIZE = sectorSize; - uptr -> capac = numberOfTracks * numberOfSectors * sectorSize; + uptr->HDSK_NUMBER_OF_TRACKS = numberOfTracks; + uptr->HDSK_SECTORS_PER_TRACK = numberOfSectors; + uptr->HDSK_SECTOR_SIZE = sectorSize; + uptr->capac = numberOfTracks * numberOfSectors * sectorSize; return SCPE_OK; } @@ -391,8 +512,8 @@ static t_stat set_geom(UNIT *uptr, int32 val, char *cptr, void *desc) { static t_stat show_geom(FILE *st, UNIT *uptr, int32 val, void *desc) { if (uptr == NULL) return SCPE_IERR; - fprintf(st, "T:%d/N:%d/S:%d", uptr -> HDSK_NUMBER_OF_TRACKS, - uptr -> HDSK_SECTORS_PER_TRACK, uptr -> HDSK_SECTOR_SIZE); + fprintf(st, "T:%d/N:%d/S:%d", uptr->HDSK_NUMBER_OF_TRACKS, + uptr->HDSK_SECTORS_PER_TRACK, uptr->HDSK_SECTOR_SIZE); return SCPE_OK; } @@ -409,21 +530,21 @@ static t_stat set_format(UNIT *uptr, int32 val, char *cptr, void *desc) { return SCPE_IERR; if (sscanf(cptr, "%" QUOTE2(DPB_NAME_LENGTH) "s", fmtname) == 0) return SCPE_ARG; - if (((uptr -> flags) & UNIT_ATT) == 0) { + if (((uptr->flags) & UNIT_ATT) == 0) { printf("Cannot set format for not attached unit %i.\n", find_unit_index(uptr)); return SCPE_ARG; } for (i = 0; dpb[i].capac != 0; i++) { if (strncmp(fmtname, dpb[i].name, strlen(fmtname)) == 0) { - uptr -> HDSK_FORMAT_TYPE = i; - uptr -> capac = dpb[i].capac; /* Set capacity */ + uptr->HDSK_FORMAT_TYPE = i; + uptr->capac = dpb[i].capac; /* Set capacity */ /* Configure physical disk geometry */ - uptr -> HDSK_SECTOR_SIZE = (128 << dpb[uptr -> HDSK_FORMAT_TYPE].psh); - uptr -> HDSK_SECTORS_PER_TRACK = dpb[uptr -> HDSK_FORMAT_TYPE].spt >> dpb[uptr -> HDSK_FORMAT_TYPE].psh; - uptr -> HDSK_NUMBER_OF_TRACKS = (uptr -> capac + - uptr -> HDSK_SECTORS_PER_TRACK * uptr -> HDSK_SECTOR_SIZE - 1) / - (uptr -> HDSK_SECTORS_PER_TRACK * uptr -> HDSK_SECTOR_SIZE); + uptr->HDSK_SECTOR_SIZE = (128 << dpb[uptr->HDSK_FORMAT_TYPE].psh); + uptr->HDSK_SECTORS_PER_TRACK = dpb[uptr->HDSK_FORMAT_TYPE].spt >> dpb[uptr->HDSK_FORMAT_TYPE].psh; + uptr->HDSK_NUMBER_OF_TRACKS = (uptr->capac + + uptr->HDSK_SECTORS_PER_TRACK * uptr->HDSK_SECTOR_SIZE - 1) / + (uptr->HDSK_SECTORS_PER_TRACK * uptr->HDSK_SECTOR_SIZE); return SCPE_OK; } @@ -435,7 +556,7 @@ static t_stat set_format(UNIT *uptr, int32 val, char *cptr, void *desc) { static t_stat show_format(FILE *st, UNIT *uptr, int32 val, void *desc) { if (uptr == NULL) return SCPE_IERR; - fprintf(st, "%s", dpb[uptr -> HDSK_FORMAT_TYPE].name); + fprintf(st, "%s", dpb[uptr->HDSK_FORMAT_TYPE].name); return SCPE_OK; } @@ -559,40 +680,40 @@ static int32 checkParameters(void) { " Disk %i is not attached.\n", selectedDisk, PCX, selectedDisk); return FALSE; /* cannot read or write */ } - if ((selectedSector < 0) || (selectedSector >= uptr -> HDSK_SECTORS_PER_TRACK)) { + if ((selectedSector < 0) || (selectedSector >= uptr->HDSK_SECTORS_PER_TRACK)) { sim_debug(VERBOSE_MSG, &hdsk_dev, "HDSK%d: " ADDRESS_FORMAT " Constraint violation 0 <= Sector=%02d < %d, will use sector 0 instead.\n", - selectedDisk, PCX, selectedSector, uptr -> HDSK_SECTORS_PER_TRACK); + selectedDisk, PCX, selectedSector, uptr->HDSK_SECTORS_PER_TRACK); selectedSector = 0; } - if ((selectedTrack < 0) || (selectedTrack >= uptr -> HDSK_NUMBER_OF_TRACKS)) { + if ((selectedTrack < 0) || (selectedTrack >= uptr->HDSK_NUMBER_OF_TRACKS)) { sim_debug(VERBOSE_MSG, &hdsk_dev, "HDSK%d: " ADDRESS_FORMAT " Constraint violation 0 <= Track=%04d < %04d, will use track 0 instead.\n", - selectedDisk, PCX, selectedTrack, uptr -> HDSK_NUMBER_OF_TRACKS); + selectedDisk, PCX, selectedTrack, uptr->HDSK_NUMBER_OF_TRACKS); selectedTrack = 0; } selectedDMA &= ADDRMASK; if (hdskLastCommand == HDSK_READ) sim_debug(READ_MSG, &hdsk_dev, "HDSK%d " ADDRESS_FORMAT " Read Track=%04d Sector=%02d Len=%04d DMA=%04x\n", - selectedDisk, PCX, selectedTrack, selectedSector, uptr -> HDSK_SECTOR_SIZE, selectedDMA); + selectedDisk, PCX, selectedTrack, selectedSector, uptr->HDSK_SECTOR_SIZE, selectedDMA); if (hdskLastCommand == HDSK_WRITE) sim_debug(WRITE_MSG, &hdsk_dev, "HDSK%d " ADDRESS_FORMAT " Write Track=%04d Sector=%02d Len=%04d DMA=%04x\n", - selectedDisk, PCX, selectedTrack, selectedSector, uptr -> HDSK_SECTOR_SIZE, selectedDMA); + selectedDisk, PCX, selectedTrack, selectedSector, uptr->HDSK_SECTOR_SIZE, selectedDMA); return TRUE; } /* pre-condition: checkParameters has been executed to repair any faulty parameters */ static int32 doSeek(void) { UNIT *uptr = &hdsk_dev.units[selectedDisk]; - int32 hostSector = (dpb[uptr -> HDSK_FORMAT_TYPE].skew == NULL) ? - selectedSector : dpb[uptr -> HDSK_FORMAT_TYPE].skew[selectedSector]; - int32 sectorSize = (dpb[uptr -> HDSK_FORMAT_TYPE].physicalSectorSize == 0) ? - uptr -> HDSK_SECTOR_SIZE : dpb[uptr -> HDSK_FORMAT_TYPE].physicalSectorSize; - if (sim_fseek(uptr -> fileref, - sectorSize * (uptr -> HDSK_SECTORS_PER_TRACK * selectedTrack + hostSector) + - dpb[uptr -> HDSK_FORMAT_TYPE].offset, SEEK_SET)) { + int32 hostSector = (dpb[uptr->HDSK_FORMAT_TYPE].skew == NULL) ? + selectedSector : dpb[uptr->HDSK_FORMAT_TYPE].skew[selectedSector]; + int32 sectorSize = (dpb[uptr->HDSK_FORMAT_TYPE].physicalSectorSize == 0) ? + uptr->HDSK_SECTOR_SIZE : dpb[uptr->HDSK_FORMAT_TYPE].physicalSectorSize; + if (sim_fseek(uptr->fileref, + sectorSize * (uptr->HDSK_SECTORS_PER_TRACK * selectedTrack + hostSector) + + dpb[uptr->HDSK_FORMAT_TYPE].offset, SEEK_SET)) { sim_debug(VERBOSE_MSG, &hdsk_dev, "HDSK%d: " ADDRESS_FORMAT " Could not access Sector=%02d[=%02d] Track=%04d.\n", selectedDisk, PCX, selectedSector, hostSector, selectedTrack); @@ -601,24 +722,59 @@ static int32 doSeek(void) { return CPM_OK; } -uint8 hdskbuf[HDSK_MAX_SECTOR_SIZE] = { 0 }; /* data buffer */ +static uint8 hdskbuf[HDSK_MAX_SECTOR_SIZE] = { 0 }; /* data buffer */ /* pre-condition: checkParameters has been executed to repair any faulty parameters */ static int32 doRead(void) { int32 i; + t_stat result; + DISK_INFO *thisDisk; + int32 hostSector; + int32 sectorSize; + uint32 flags; + uint32 readlen; + uint32 cylinder; + uint32 head; UNIT *uptr = &hdsk_dev.units[selectedDisk]; - if (doSeek()) - return CPM_ERROR; - - if (sim_fread(hdskbuf, 1, uptr -> HDSK_SECTOR_SIZE, uptr -> fileref) != (size_t)(uptr -> HDSK_SECTOR_SIZE)) { - for (i = 0; i < uptr -> HDSK_SECTOR_SIZE; i++) - hdskbuf[i] = CPM_EMPTY; - sim_debug(VERBOSE_MSG, &hdsk_dev, "HDSK%d: " ADDRESS_FORMAT - " Could not read Sector=%02d Track=%04d.\n", - selectedDisk, PCX, selectedSector, selectedTrack); - return CPM_OK; /* allows the creation of empty hard disks */ + if (is_imd(uptr)) { + thisDisk = hdsk_imd[selectedDisk]; + hostSector = ((dpb[uptr->HDSK_FORMAT_TYPE].skew == NULL) ? + selectedSector : dpb[uptr->HDSK_FORMAT_TYPE].skew[selectedSector]) + thisDisk->track[1][0].start_sector; + sectorSize = ((dpb[uptr->HDSK_FORMAT_TYPE].physicalSectorSize == 0) ? + uptr->HDSK_SECTOR_SIZE : + dpb[uptr->HDSK_FORMAT_TYPE].physicalSectorSize); + flags = 0; + readlen = 0; + cylinder = selectedTrack; + head = 0; + if (cylinder >= thisDisk->ntracks / thisDisk->nsides) { + head = 1; + cylinder -= thisDisk->ntracks / thisDisk->nsides; + } + result = sectRead(thisDisk, cylinder, head, hostSector, hdskbuf, sectorSize, + &flags, &readlen); + if (result != SCPE_OK) { + for (i = 0; i < uptr->HDSK_SECTOR_SIZE; i++) + hdskbuf[i] = CPM_EMPTY; + sim_debug(VERBOSE_MSG, &hdsk_dev, "HDSK%d (IMD): " ADDRESS_FORMAT + " . Could not read Sector=%02d Track=%04d.\n", + selectedDisk, PCX, selectedSector, selectedTrack); + return CPM_ERROR; + } + } else { + if (doSeek()) + return CPM_ERROR; + + if (sim_fread(hdskbuf, 1, uptr->HDSK_SECTOR_SIZE, uptr->fileref) != (size_t)(uptr->HDSK_SECTOR_SIZE)) { + for (i = 0; i < uptr->HDSK_SECTOR_SIZE; i++) + hdskbuf[i] = CPM_EMPTY; + sim_debug(VERBOSE_MSG, &hdsk_dev, "HDSK%d: " ADDRESS_FORMAT + " Could not read Sector=%02d Track=%04d.\n", + selectedDisk, PCX, selectedSector, selectedTrack); + return CPM_OK; /* allows the creation of empty hard disks */ + } } - for (i = 0; i < uptr -> HDSK_SECTOR_SIZE; i++) + for (i = 0; i < uptr->HDSK_SECTOR_SIZE; i++) PutBYTEWrapper(selectedDMA + i, hdskbuf[i]); return CPM_OK; } @@ -626,19 +782,54 @@ static int32 doRead(void) { /* pre-condition: checkParameters has been executed to repair any faulty parameters */ static int32 doWrite(void) { int32 i; + t_stat result; + DISK_INFO *thisDisk; + int32 hostSector; + int32 sectorSize; + uint32 flags; + uint32 writelen; + uint32 cylinder; + uint32 head; size_t rtn; UNIT *uptr = &hdsk_dev.units[selectedDisk]; - if (((uptr -> flags) & UNIT_HDSK_WLK) == 0) { /* write enabled */ - if (doSeek()) - return CPM_ERROR; - for (i = 0; i < uptr -> HDSK_SECTOR_SIZE; i++) - hdskbuf[i] = GetBYTEWrapper(selectedDMA + i); - rtn = sim_fwrite(hdskbuf, 1, uptr -> HDSK_SECTOR_SIZE, uptr -> fileref); - if (rtn != (size_t)(uptr -> HDSK_SECTOR_SIZE)) { - sim_debug(VERBOSE_MSG, &hdsk_dev, "HDSK%d: " ADDRESS_FORMAT - " Could not write Sector=%02d Track=%04d Result=%zd.\n", - selectedDisk, PCX, selectedSector, selectedTrack, rtn); - return CPM_ERROR; + if (((uptr->flags) & UNIT_HDSK_WLK) == 0) { /* write enabled */ + if (is_imd(uptr)) { + for (i = 0; i < uptr->HDSK_SECTOR_SIZE; i++) + hdskbuf[i] = GetBYTEWrapper(selectedDMA + i); + thisDisk = hdsk_imd[selectedDisk]; + hostSector = ((dpb[uptr->HDSK_FORMAT_TYPE].skew == NULL) ? + selectedSector : dpb[uptr->HDSK_FORMAT_TYPE].skew[selectedSector]) + thisDisk->track[1][0].start_sector; + sectorSize = ((dpb[uptr->HDSK_FORMAT_TYPE].physicalSectorSize == 0) ? + uptr->HDSK_SECTOR_SIZE : + dpb[uptr->HDSK_FORMAT_TYPE].physicalSectorSize); + flags = 0; + writelen = 0; + cylinder = selectedTrack; + head = 0; + if (cylinder >= thisDisk->ntracks / thisDisk->nsides) { + head = 1; + cylinder -= thisDisk->ntracks / thisDisk->nsides; + } + result = sectWrite(thisDisk, cylinder, head, hostSector, hdskbuf, + sectorSize, &flags, &writelen); + if (result != SCPE_OK) { + sim_debug(VERBOSE_MSG, &hdsk_dev, "HDSK%d (IMD): " ADDRESS_FORMAT + " . Could not write Sector=%02d Track=%04d.\n", + selectedDisk, PCX, selectedSector, selectedTrack); + return CPM_ERROR; + } + } else { + if (doSeek()) + return CPM_ERROR; + for (i = 0; i < uptr->HDSK_SECTOR_SIZE; i++) + hdskbuf[i] = GetBYTEWrapper(selectedDMA + i); + rtn = sim_fwrite(hdskbuf, 1, uptr->HDSK_SECTOR_SIZE, uptr->fileref); + if (rtn != (size_t)(uptr->HDSK_SECTOR_SIZE)) { + sim_debug(VERBOSE_MSG, &hdsk_dev, "HDSK%d: " ADDRESS_FORMAT + " Could not write Sector=%02d Track=%04d Result=%zd.\n", + selectedDisk, PCX, selectedSector, selectedTrack, rtn); + return CPM_ERROR; + } } } else { @@ -682,10 +873,10 @@ static int32 hdsk_out(const int32 port, const int32 data) { parameterCount = 0; thisDisk = (0 <= data) && (data < HDSK_NUMBER) ? data : 0; uptr = &hdsk_dev.units[thisDisk]; - if ((uptr -> flags) & UNIT_ATT) { - current = dpb[uptr -> HDSK_FORMAT_TYPE]; - parameterBlock[17] = uptr -> HDSK_SECTOR_SIZE & 0xff; - parameterBlock[18] = (uptr -> HDSK_SECTOR_SIZE >> 8) & 0xff; + if ((uptr->flags) & UNIT_ATT) { + current = dpb[uptr->HDSK_FORMAT_TYPE]; + parameterBlock[17] = uptr->HDSK_SECTOR_SIZE & 0xff; + parameterBlock[18] = (uptr->HDSK_SECTOR_SIZE >> 8) & 0xff; } else { current = dpb[0]; diff --git a/AltairZ80/altairz80_net.c b/AltairZ80/altairz80_net.c index fa5e5103..ea2bf276 100644 --- a/AltairZ80/altairz80_net.c +++ b/AltairZ80/altairz80_net.c @@ -1,6 +1,6 @@ /* altairz80_net.c: networking capability - Copyright (c) 2002-2011, Peter Schorn + Copyright (c) 2002-2012, Peter Schorn Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/AltairZ80/altairz80_sio.c b/AltairZ80/altairz80_sio.c index 54447c58..984f8772 100644 --- a/AltairZ80/altairz80_sio.c +++ b/AltairZ80/altairz80_sio.c @@ -1,6 +1,6 @@ /* altairz80_sio.c: MITS Altair serial I/O card - Copyright (c) 2002-2011, Peter Schorn + Copyright (c) 2002-2012, Peter Schorn Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -1559,7 +1559,7 @@ static int32 simh_out(const int32 port, const int32 data) { } } break; - + case setClockZSDOSCmd: if (setClockZSDOSPos == 0) { setClockZSDOSAdr = data; @@ -1571,7 +1571,7 @@ static int32 simh_out(const int32 port, const int32 data) { setClockZSDOSPos = lastCommand = 0; } break; - + case setClockCPM3Cmd: if (setClockCPM3Pos == 0) { setClockCPM3Adr = data; @@ -1583,7 +1583,7 @@ static int32 simh_out(const int32 port, const int32 data) { setClockCPM3Pos = lastCommand = 0; } break; - + case setCPUClockFrequency: if (setClockFrequencyPos == 0) { newClockFrequency = data; @@ -1594,7 +1594,7 @@ static int32 simh_out(const int32 port, const int32 data) { setClockFrequencyPos = lastCommand = 0; } break; - + case setBankSelectCmd: if (cpu_unit.flags & UNIT_CPU_BANKED) setBankSelect(data & BANKMASK); @@ -1604,7 +1604,7 @@ static int32 simh_out(const int32 port, const int32 data) { PCX, data & 3); lastCommand = 0; break; - + case setTimerDeltaCmd: if (setTimerDeltaPos == 0) { timerDelta = data; @@ -1621,7 +1621,7 @@ static int32 simh_out(const int32 port, const int32 data) { } } break; - + case setTimerInterruptAdrCmd: if (setTimerInterruptAdrPos == 0) { timerInterruptHandler = data; @@ -1632,21 +1632,21 @@ static int32 simh_out(const int32 port, const int32 data) { setTimerInterruptAdrPos = lastCommand = 0; } break; - + default: /* lastCommand not yet set */ sim_debug(CMD_MSG, &simh_device, "SIMH: " ADDRESS_FORMAT " CMD(0x%02x) <- %i (0x%02x, '%s')\n", PCX, port, data, data, (0 <= data) && (data < kSimhPseudoDeviceCommands) ? cmdNames[data] : "Unknown command"); - + lastCommand = data; switch(data) { case readURLCmd: urlPointer = 0; isInReadPhase = FALSE; break; - + case getHostFilenamesCmd: #if UNIX_PLATFORM if (!globValid) { @@ -1681,18 +1681,18 @@ static int32 simh_out(const int32 port, const int32 data) { } #endif break; - + case SIMHSleepCmd: do_SIMH_sleep(); break; - + case printTimeCmd: /* print time */ if (rtc_avail) printf("SIMH: " ADDRESS_FORMAT " Current time in milliseconds = %d." NLP, PCX, sim_os_msec()); else warnNoRealTimeClock(); break; - + case startTimerCmd: /* create a new timer on top of stack */ if (rtc_avail) if (markTimeSP < TIMER_STACK_LIMIT) @@ -1702,7 +1702,7 @@ static int32 simh_out(const int32 port, const int32 data) { else warnNoRealTimeClock(); break; - + case stopTimerCmd: /* stop timer on top of stack and show time difference */ if (rtc_avail) if (markTimeSP > 0) { @@ -1714,23 +1714,23 @@ static int32 simh_out(const int32 port, const int32 data) { else warnNoRealTimeClock(); break; - + case resetPTRCmd: /* reset ptr device */ ptr_reset(&ptr_dev); break; - + case attachPTRCmd: /* attach ptr to the file with name at beginning of CP/M command line */ attachCPM(&ptr_unit); break; - + case detachPTRCmd: /* detach ptr */ detach_unit(&ptr_unit); break; - + case getSIMHVersionCmd: versionPos = 0; break; - + case getClockZSDOSCmd: time(&now); now += ClockZSDOSDelta; @@ -1738,11 +1738,11 @@ static int32 simh_out(const int32 port, const int32 data) { currentTimeValid = TRUE; getClockZSDOSPos = 0; break; - + case setClockZSDOSCmd: setClockZSDOSPos = 0; break; - + case getClockCPM3Cmd: time(&now); now += ClockCPM3Delta; @@ -1751,29 +1751,29 @@ static int32 simh_out(const int32 port, const int32 data) { daysCPM3SinceOrg = (int32) ((now - mkCPM3Origin()) / SECONDS_PER_DAY); getClockCPM3Pos = 0; break; - + case setClockCPM3Cmd: setClockCPM3Pos = 0; break; - + case getCommonCmd: getCommonPos = 0; break; - + case getCPUClockFrequency: getClockFrequencyPos = 0; break; - + case setCPUClockFrequency: setClockFrequencyPos = 0; break; - + case getBankSelectCmd: case setBankSelectCmd: case hasBankedMemoryCmd: case getHostOSPathSeparatorCmd: break; - + case resetSIMHInterfaceCmd: markTimeSP = 0; lastCommand = 0; @@ -1791,7 +1791,7 @@ static int32 simh_out(const int32 port, const int32 data) { } #endif break; - + case showTimerCmd: /* show time difference to timer on top of stack */ if (rtc_avail) if (markTimeSP > 0) { @@ -1803,52 +1803,52 @@ static int32 simh_out(const int32 port, const int32 data) { else warnNoRealTimeClock(); break; - + case attachPTPCmd: /* attach ptp to the file with name at beginning of CP/M command line */ attachCPM(&ptp_unit); break; - + case detachPTPCmd: /* detach ptp */ detach_unit(&ptp_unit); break; - + case setZ80CPUCmd: chiptype = CHIP_TYPE_Z80; break; - + case set8080CPUCmd: chiptype = CHIP_TYPE_8080; break; - + case startTimerInterruptsCmd: if (simh_dev_set_timeron(NULL, 0, NULL, NULL) == SCPE_OK) { timerInterrupt = FALSE; simh_unit.flags |= UNIT_SIMH_TIMERON; } break; - + case stopTimerInterruptsCmd: simh_unit.flags &= ~UNIT_SIMH_TIMERON; simh_dev_set_timeroff(NULL, 0, NULL, NULL); break; - + case setTimerDeltaCmd: setTimerDeltaPos = 0; break; - + case setTimerInterruptAdrCmd: setTimerInterruptAdrPos = 0; break; - + case resetStopWatchCmd: stopWatchNow = rtc_avail ? sim_os_msec() : 0; break; - + case readStopWatchCmd: getStopWatchDeltaPos = 0; stopWatchDelta = rtc_avail ? sim_os_msec() - stopWatchNow : 0; break; - + default: sim_debug(CMD_MSG, &simh_device, "SIMH: " ADDRESS_FORMAT " Unknown command (%i) to SIMH pseudo device on port %03xh ignored.\n", diff --git a/AltairZ80/altairz80_sys.c b/AltairZ80/altairz80_sys.c index 6a4f8985..c1285ead 100644 --- a/AltairZ80/altairz80_sys.c +++ b/AltairZ80/altairz80_sys.c @@ -1,6 +1,6 @@ /* altairz80_sys.c: MITS Altair system interface - Copyright (c) 2002-2011, Peter Schorn + Copyright (c) 2002-2012, Peter Schorn Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -138,13 +138,13 @@ const char *sim_stop_messages[] = { static char *const Mnemonics8080[] = { /* 0/8 1/9 2/A 3/B 4/C 5/D 6/E 7/F */ "NOP", "LXI B,#h", "STAX B", "INX B", "INR B", "DCR B", "MVI B,*h", "RLC", /* 00-07 */ - "DB 09h", "DAD B", "LDAX B", "DCX B", "INR C", "DCR C", "MVI C,*h", "RRC", /* 08-0f */ - "DB 10h", "LXI D,#h", "STAX D", "INX D", "INR D", "DCR D", "MVI D,*h", "RAL", /* 10-17 */ - "DB 18h", "DAD D", "LDAX D", "DCX D", "INR E", "DCR E", "MVI E,*h", "RAR", /* 18-1f */ - "DB 20h", "LXI H,#h", "SHLD #h", "INX H", "INR H", "DCR H", "MVI H,*h", "DAA", /* 20-27 */ - "DB 28h", "DAD H", "LHLD #h", "DCX H", "INR L", "DCR L", "MVI L,*h", "CMA", /* 28-2f */ - "DB 30h", "LXI SP,#h", "STA #h", "INX SP", "INR M", "DCR M", "MVI M,*h", "STC", /* 30-37 */ - "DB 38h", "DAD SP", "LDA #h", "DCX SP", "INR A", "DCR A", "MVI A,*h", "CMC", /* 38-3f */ + "_NOP", "DAD B", "LDAX B", "DCX B", "INR C", "DCR C", "MVI C,*h", "RRC", /* 08-0f */ + "_NOP", "LXI D,#h", "STAX D", "INX D", "INR D", "DCR D", "MVI D,*h", "RAL", /* 10-17 */ + "_NOP", "DAD D", "LDAX D", "DCX D", "INR E", "DCR E", "MVI E,*h", "RAR", /* 18-1f */ + "_NOP", "LXI H,#h", "SHLD #h", "INX H", "INR H", "DCR H", "MVI H,*h", "DAA", /* 20-27 */ + "_NOP", "DAD H", "LHLD #h", "DCX H", "INR L", "DCR L", "MVI L,*h", "CMA", /* 28-2f */ + "_NOP", "LXI SP,#h", "STA #h", "INX SP", "INR M", "DCR M", "MVI M,*h", "STC", /* 30-37 */ + "_NOP", "DAD SP", "LDA #h", "DCX SP", "INR A", "DCR A", "MVI A,*h", "CMC", /* 38-3f */ "MOV B,B", "MOV B,C", "MOV B,D", "MOV B,E", "MOV B,H", "MOV B,L", "MOV B,M", "MOV B,A", /* 40-47 */ "MOV C,B", "MOV C,C", "MOV C,D", "MOV C,E", "MOV C,H", "MOV C,L", "MOV C,M", "MOV C,A", /* 48-4f */ "MOV D,B", "MOV D,C", "MOV D,D", "MOV D,E", "MOV D,H", "MOV D,L", "MOV D,M", "MOV D,A", /* 50-57 */ @@ -162,13 +162,13 @@ static char *const Mnemonics8080[] = { "ORA B", "ORA C", "ORA D", "ORA E", "ORA H", "ORA L", "ORA M", "ORA A", /* b0-b7 */ "CMP B", "CMP C", "CMP D", "CMP E", "CMP H", "CMP L", "CMP M", "CMP A", /* b8-bf */ "RNZ", "POP B", "JNZ #h", "JMP #h", "CNZ #h", "PUSH B", "ADI *h", "RST 0", /* c0-c7 */ - "RZ", "RET", "JZ #h", "DB CBh", "CZ #h", "CALL #h", "ACI *h", "RST 1", /* c8-cf */ + "RZ", "RET", "JZ #h", "_JMP #h", "CZ #h", "CALL #h", "ACI *h", "RST 1", /* c8-cf */ "RNC", "POP D", "JNC #h", "OUT *h", "CNC #h", "PUSH D", "SUI *h", "RST 2", /* d0-d7 */ - "RC", "DB D9h", "JC #h", "IN *h", "CC #h", "DB DDh", "SBI *h", "RST 3", /* d8-df */ + "RC", "_RET", "JC #h", "IN *h", "CC #h", "_CALL #h", "SBI *h", "RST 3", /* d8-df */ "RPO", "POP H", "JPO #h", "XTHL", "CPO #h", "PUSH H", "ANI *h", "RST 4", /* e0-e7 */ - "RPE", "PCHL", "JPE #h", "XCHG", "CPE #h", "DB EDh", "XRI *h", "RST 5", /* e8-ef */ + "RPE", "PCHL", "JPE #h", "XCHG", "CPE #h", "_CALL #h", "XRI *h", "RST 5", /* e8-ef */ "RP", "POP PSW", "JP #h", "DI", "CP #h", "PUSH PSW", "ORI *h", "RST 6", /* f0-f7 */ - "RM", "SPHL", "JM #h", "EI", "CM #h", "DB FDh", "CPI *h", "RST 7" /* f8-ff */ + "RM", "SPHL", "JM #h", "EI", "CM #h", "_CALL #h", "CPI *h", "RST 7" /* f8-ff */ }; static char *const MnemonicsZ80[256] = { diff --git a/AltairZ80/s100_fif.c b/AltairZ80/s100_fif.c index ca5481c4..fe8a6b18 100644 --- a/AltairZ80/s100_fif.c +++ b/AltairZ80/s100_fif.c @@ -2,7 +2,7 @@ IMSAI FIF Disk Controller by Ernie Price - Based on altairz80_dsk.c, Copyright (c) 2002-2011, Peter Schorn + Based on altairz80_dsk.c, Copyright (c) 2002-2012, Peter Schorn Plug-n-Play added by Howard M. Harte @@ -131,7 +131,7 @@ static t_stat fif_set_verbose(UNIT *uptr, int32 value, char *cptr, void *desc) { static int32 hasVerbose(void) { int32 i; for (i = 0; i < NUM_OF_DSK; i++) { - if (((fif_dev.units + i) -> flags) & UNIT_DSK_VERBOSE) { + if (((fif_dev.units + i)->flags) & UNIT_DSK_VERBOSE) { return TRUE; } } @@ -219,7 +219,7 @@ static int DoDiskOperation(desc_t *dsc, uint8 val) } return 0; /* no drive selected - can do nothing */ } - current_disk_flags = (fif_dev.units + current_disk) -> flags; + current_disk_flags = (fif_dev.units + current_disk)->flags; if ((current_disk_flags & UNIT_ATT) == 0) { /* nothing attached? */ if ( (current_disk_flags & UNIT_DSK_VERBOSE) && (warnAttached[current_disk] < warnLevelDSK) ) { warnAttached[current_disk]++; diff --git a/AltairZ80/wd179x.c b/AltairZ80/wd179x.c index f3992603..589877df 100644 --- a/AltairZ80/wd179x.c +++ b/AltairZ80/wd179x.c @@ -42,6 +42,7 @@ /*#define DBG_MSG */ #include "altairz80_defs.h" +#include #if defined (_WIN32) #include @@ -514,12 +515,12 @@ uint8 WD179X_Read(const uint32 Addr) /* Compute Sector Size */ wd179x_info->fdc_sec_len = floorlog2( pDrive->imd->track[pDrive->track][wd179x_info->fdc_head].sectsize) - 7; - if((wd179x_info->fdc_sec_len == 0xF8) || (wd179x_info->fdc_sec_len > WD179X_MAX_SEC_LEN)) { /* Error calculating N or N too large */ + if(wd179x_info->fdc_sec_len > WD179X_MAX_SEC_LEN) { /* Error calculating N or N too large */ sim_debug(ERROR_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT " Invalid sector size!\n", wd179x_info->sel_drive, PCX); wd179x_info->fdc_sec_len = 0; return cData; } - + assert(wd179x_info->fdc_sec_len >= 0); // convince static analyzer that << is ok wd179x_info->fdc_sector ++; sim_debug(RD_DATA_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT " MULTI_READ_REC, T:%d/S:%d/N:%d, %s, len=%d\n", wd179x_info->sel_drive, PCX, pDrive->track, wd179x_info->fdc_head, wd179x_info->fdc_sector, wd179x_info->ddens ? "DD" : "SD", 128 << wd179x_info->fdc_sec_len); @@ -703,7 +704,7 @@ static uint8 Do1793Command(uint8 cCommand) /* Compute Sector Size */ wd179x_info->fdc_sec_len = floorlog2( pDrive->imd->track[pDrive->track][wd179x_info->fdc_head].sectsize) - 7; - if((wd179x_info->fdc_sec_len == 0xF8) || (wd179x_info->fdc_sec_len > WD179X_MAX_SEC_LEN)) { /* Error calculating N or N too large */ + if(wd179x_info->fdc_sec_len > WD179X_MAX_SEC_LEN) { /* Error calculating N or N too large */ sim_debug(ERROR_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT " Invalid sector size!\n", wd179x_info->sel_drive, PCX); wd179x_info->fdc_status |= WD179X_STAT_NOT_FOUND; /* Sector not found */ @@ -712,7 +713,8 @@ static uint8 Do1793Command(uint8 cCommand) wd179x_info->drq = 0; wd179x_info->fdc_sec_len = 0; return 0xFF; - } + }; + assert(wd179x_info->fdc_sec_len >= 0); // convince static analyzer that << is ok wd179x_info->fdc_multiple = (cCommand & 0x10) ? TRUE : FALSE; sim_debug(RD_DATA_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT @@ -766,7 +768,7 @@ static uint8 Do1793Command(uint8 cCommand) /* Compute Sector Size */ wd179x_info->fdc_sec_len = floorlog2( pDrive->imd->track[pDrive->track][wd179x_info->fdc_head].sectsize) - 7; - if((wd179x_info->fdc_sec_len == 0xF8) || (wd179x_info->fdc_sec_len > WD179X_MAX_SEC_LEN)) { /* Error calculating N or N too large */ + if(wd179x_info->fdc_sec_len > WD179X_MAX_SEC_LEN) { /* Error calculating N or N too large */ sim_debug(ERROR_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT " Invalid sector size!\n", wd179x_info->sel_drive, PCX); wd179x_info->fdc_sec_len = 0; @@ -798,7 +800,7 @@ static uint8 Do1793Command(uint8 cCommand) /* Compute Sector Size */ wd179x_info->fdc_sec_len = floorlog2( pDrive->imd->track[pDrive->track][wd179x_info->fdc_head].sectsize) - 7; - if((wd179x_info->fdc_sec_len == 0xF8) || (wd179x_info->fdc_sec_len > WD179X_MAX_SEC_LEN)) { /* Error calculating N or N too large */ + if(wd179x_info->fdc_sec_len > WD179X_MAX_SEC_LEN) { /* Error calculating N or N too large */ sim_debug(ERROR_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT " Invalid sector size!\n", wd179x_info->sel_drive, PCX); wd179x_info->fdc_sec_len = 0; @@ -1080,7 +1082,7 @@ uint8 WD179X_Write(const uint32 Addr, uint8 cData) wd179x_info->fdc_dataindex++; } else { wd179x_info->fdc_sec_len = floorlog2(wd179x_info->fdc_dataindex) - 7; - if((wd179x_info->fdc_sec_len == 0xF8) || (wd179x_info->fdc_sec_len > WD179X_MAX_SEC_LEN)) { /* Error calculating N or N too large */ + if(wd179x_info->fdc_sec_len > WD179X_MAX_SEC_LEN) { /* Error calculating N or N too large */ sim_debug(ERROR_MSG, &wd179x_dev, "WD179X[%d]: " ADDRESS_FORMAT " Invalid sector size!\n", wd179x_info->sel_drive, PCX); wd179x_info->fdc_sec_len = 0; diff --git a/GRI/gri_cpu.c b/GRI/gri_cpu.c index 3eb3fa2e..65cbb45c 100644 --- a/GRI/gri_cpu.c +++ b/GRI/gri_cpu.c @@ -1,6 +1,6 @@ /* gri_cpu.c: GRI-909 CPU simulator - Copyright (c) 2001-2008, Robert M. Supnik + Copyright (c) 2001-2015, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -187,10 +187,6 @@ int16 scq[SCQ_SIZE] = { 0 }; /* PC queue */ int32 scq_p = 0; /* PC queue ptr */ REG *scq_r = NULL; /* PC queue reg ptr */ -extern int32 sim_interval; -extern int32 sim_int_char; -extern uint32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ - t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw); t_stat cpu_reset (DEVICE *dptr); @@ -421,7 +417,7 @@ ao_update (); /* update AO */ while (reason == 0) { /* loop until halted */ if (sim_interval <= 0) { /* check clock queue */ - if (reason = sim_process_event ()) + if ((reason = sim_process_event ())) break; } @@ -438,11 +434,11 @@ while (reason == 0) { /* loop until halted */ for (i = 15; i >= 0; i--) { if ((t >> i) & 1) break; - } + } if ((i < 0) || ((vec = vec_map[i]) < 0)) { /* undefined? */ reason = STOP_ILLINT; /* stop */ break; - } + } dev_done = dev_done & ~INT_ON; /* int off */ M[vec] = SC; /* save SC */ SC = vec + 1; /* new SC */ diff --git a/GRI/gri_defs.h b/GRI/gri_defs.h index 034d3337..82e8fb7e 100644 --- a/GRI/gri_defs.h +++ b/GRI/gri_defs.h @@ -1,6 +1,6 @@ /* gri_defs.h: GRI-909 simulator definitions - Copyright (c) 2001-2010, Robert M. Supnik + Copyright (c) 2001-2015, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -47,8 +47,8 @@ 5. How does the EAO handle divide overflow? Answer: set link. */ -#ifndef _GRI_DEFS_H_ -#define _GRI_DEFS_H_ 0 +#ifndef GRI_DEFS_H_ +#define GRI_DEFS_H_ 0 #include "sim_defs.h" /* simulator defns */ diff --git a/GRI/gri_stddev.c b/GRI/gri_stddev.c index 53a3b13d..aab1c45f 100644 --- a/GRI/gri_stddev.c +++ b/GRI/gri_stddev.c @@ -1,6 +1,6 @@ /* gri_stddev.c: GRI-909 standard devices - Copyright (c) 2001-2008, Robert M Supnik + Copyright (c) 2001-2015, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -29,6 +29,7 @@ hsp S42-006 high speed punch rtc real time clock + 28-Mar-15 RMS Revised to use sim_printf 31-May-08 RMS Fixed declarations (Peter Schorn) 30-Sep-06 RMS Fixed handling of non-printable characters in KSR mode 22-Nov-05 RMS Revised for new terminal processing routines @@ -341,7 +342,7 @@ if ((hsr_unit.flags & UNIT_ATT) == 0) /* attached? */ if ((temp = getc (hsr_unit.fileref)) == EOF) { /* read char */ if (feof (hsr_unit.fileref)) { /* err or eof? */ if (hsr_stopioe) - printf ("HSR end of file\n"); + sim_printf ("HSR end of file\n"); else return SCPE_OK; } else perror ("HSR I/O error"); @@ -417,6 +418,7 @@ return SCPE_OK; t_stat rtc_reset (DEVICE *dptr) { +sim_register_clock_unit (&rtc_unit); /* declare clock unit */ dev_done = dev_done & ~INT_RTC; /* clear ready */ sim_cancel (&rtc_unit); /* stop clock */ return SCPE_OK; diff --git a/GRI/gri_sys.c b/GRI/gri_sys.c index 42e793d2..55168369 100644 --- a/GRI/gri_sys.c +++ b/GRI/gri_sys.c @@ -1,6 +1,6 @@ /* gri_sys.c: GRI-909 simulator interface - Copyright (c) 2001-2008, Robert M Supnik + Copyright (c) 2001-2015, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -37,7 +37,6 @@ extern DEVICE hsr_dev, hsp_dev; extern DEVICE rtc_dev; extern REG cpu_reg[]; extern uint16 M[]; -extern int32 sim_switches; void fprint_addr (FILE *of, uint32 val, uint32 mod, uint32 dst); diff --git a/H316/h316_cpu.c b/H316/h316_cpu.c index b1ba29bb..2caa42b9 100644 --- a/H316/h316_cpu.c +++ b/H316/h316_cpu.c @@ -1,6 +1,6 @@ /* h316_cpu.c: Honeywell 316/516 CPU simulator - Copyright (c) 1999-2011, Robert M. Supnik + Copyright (c) 1999-2015, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,12 @@ cpu H316/H516 CPU + 21-May-13 RLA Add IMP/TIP support + Move SMK/OTK instructions here (from CLK) + Make SET CPU DMA work as documented + Implement extended interrupts + Add "interrupt taken" flag to CPU HISTORY + Add "break on write" breakpoints 19-Nov-11 RMS Fixed XR behavior (Adrian Wise) 19-Nov-11 RMS Fixed bugs in double precision, normalization, SC (Adrian Wise) 10-Jan-10 RMS Fixed bugs in LDX, STX introduced in 3.8-1 (Theo Engel) @@ -176,12 +182,19 @@ unknown I/O device and stop_dev flag set I/O error in I/O simulator - 2. Interrupts. Interrupts are maintained by two parallel variables: + 2. Interrupts. Interrupts are maintained by parallel variables: - dev_int device interrupt flags - dev_enb device interrupt enable flags + dev_int[2] device interrupt flags + dev_enb[2] device interrupt enable flags - In addition, dev_int contains the interrupt enable and interrupt no + Note that these are actually arrays of two 16 bit words each. The first + word of each vector contains the bits for the standard interrupt devices, + and the second word is the bits for the extended interrupts 1..17. The + IMP uses these extended interrupts, however this was a standard H316 option + and is in no way IMP specific. Actually the H316 supported up to 48 extra + interrupts, but it seems like overkill to implement them all. + + In addition, dev_int[0] contains the interrupt enable and interrupt no defer flags. If interrupt enable and interrupt no defer are set, and at least one interrupt request is pending, then an interrupt occurs. The order of flags in these variables corresponds to the order @@ -212,6 +225,9 @@ */ #include "h316_defs.h" +#ifdef VM_IMPTIP +#include "h316_imp.h" +#endif #define PCQ_SIZE 64 /* must be 2**n */ #define PCQ_MASK (PCQ_SIZE - 1) @@ -242,6 +258,7 @@ typedef struct { int32 xr; int32 ea; int32 opnd; + t_bool iack; // [RLA] TRUE if an interrupt occurred } InstHistory; uint16 M[MAXMEMSIZE] = { 0 }; /* memory */ @@ -259,6 +276,9 @@ int32 sc = 0; /* shift count */ int32 ss[4]; /* sense switches */ int32 dev_int = 0; /* dev ready */ int32 dev_enb = 0; /* dev enable */ +uint32 ext_ints = 0; // [RLA] 16 if extended interrupts enabled +uint16 dev_ext_int = 0; // [RLA] extended interrupt request bitmap +uint16 dev_ext_enb = 0; // [RLA] extended interrupt enable bitmap int32 ind_max = 8; /* iadr nest limit */ int32 stop_inst = 1; /* stop on ill inst */ int32 stop_dev = 2; /* stop on ill dev */ @@ -276,12 +296,6 @@ int32 hst_p = 0; /* history pointer */ int32 hst_lnt = 0; /* history length */ InstHistory *hst = NULL; /* instruction history */ -extern int32 sim_int_char; -extern int32 sim_interval; -extern uint32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ -extern FILE *sim_log; -extern DEVICE *sim_devices[]; - t_bool devtab_init (void); int32 dmaio (int32 inst, int32 fnc, int32 dat, int32 dev); int32 undio (int32 inst, int32 fnc, int32 dat, int32 dev); @@ -295,9 +309,11 @@ t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc); t_stat cpu_show_dma (FILE *st, UNIT *uptr, int32 val, void *desc); t_stat cpu_set_nchan (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat cpu_show_nchan (FILE *st, UNIT *uptr, int32 val, void *desc); - -extern t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, - UNIT *uptr, int32 sw); +t_stat cpu_set_interrupts (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat cpu_show_interrupts (FILE *st, UNIT *uptr, int32 val, void *desc); +int32 sim_ota_2024 (int32 inst, int32 fnc, int32 dat, int32 dev); +int32 cpu_interrupt (int32 vec); +int32 cpu_ext_interrupt (void); /* CPU data structures @@ -307,7 +323,7 @@ extern t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, cpu_mod CPU modifiers list */ -DIB cpu_dib = { DMA, IOBUS, 1, &dmaio }; +DIB cpu_dib = { DMA, 1, IOBUS, IOBUS, INT_V_NONE, INT_V_NONE, &dmaio, 0 }; UNIT cpu_unit = { UDATA (NULL, UNIT_FIX+UNIT_BINK+UNIT_EXT+UNIT_HSA+UNIT_DMC, MAXMEMSIZE) @@ -333,6 +349,8 @@ REG cpu_reg[] = { { FLDATA (START, dev_int, INT_V_START) }, { ORDATA (DEVINT, dev_int, 16), REG_RO }, { ORDATA (DEVENB, dev_enb, 16), REG_RO }, + { ORDATA (EXTINT, dev_ext_int, 16), REG_RO }, + { ORDATA (EXTENB, dev_ext_enb, 16), REG_RO }, { ORDATA (CHREQ, chan_req, DMA_MAX + DMC_MAX) }, { BRDATA (DMAAD, dma_ad, 8, 16, DMA_MAX) }, { BRDATA (DMAWC, dma_wc, 8, 16, DMA_MAX) }, @@ -362,18 +380,14 @@ MTAB cpu_mod[] = { { UNIT_MSIZE, 32768, NULL, "32K", &cpu_set_size }, { MTAB_XTD | MTAB_VDV, 0, "channels", "CHANNELS", &cpu_set_nchan, &cpu_show_nchan, NULL }, + { MTAB_XTD | MTAB_VDV, 0, NULL, "DMA", // [RLA] this is the way it's + &cpu_set_nchan, NULL, NULL }, // [RLA] documented to work! { UNIT_DMC, 0, "no DMC", "NODMC", NULL }, { UNIT_DMC, UNIT_DMC, "DMC", "DMC", NULL }, { MTAB_XTD|MTAB_VDV|MTAB_NMO|MTAB_SHP, 0, "HISTORY", "HISTORY", &cpu_set_hist, &cpu_show_hist }, - { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "DMA1", NULL, - NULL, &cpu_show_dma, NULL }, - { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "DMA2", NULL, - NULL, &cpu_show_dma, NULL }, - { MTAB_XTD | MTAB_VDV | MTAB_NMO, 2, "DMA3", NULL, - NULL, &cpu_show_dma, NULL }, - { MTAB_XTD | MTAB_VDV | MTAB_NMO, 3, "DMA4", NULL, - NULL, &cpu_show_dma, NULL }, + { MTAB_XTD | MTAB_VDV, 0, "extended interrupts", "EXTINT", + &cpu_set_interrupts, &cpu_show_interrupts, NULL }, { 0 } }; @@ -389,9 +403,10 @@ t_stat sim_instr (void) { int32 AR, BR, MB, Y, t1, t2, t3, skip, dev; uint32 ut; +t_bool iack; // [RLA] TRUE if an interrupt was taken this cycle t_stat reason; t_stat Ea (int32 inst, int32 *addr); -void Write (int32 addr, int32 val); +t_stat Write (int32 addr, int32 val); // [RLA] Write() can now cause a break int32 Add16 (int32 val1, int32 val2); int32 Add31 (int32 val1, int32 val2); int32 Operate (int32 MB, int32 AR); @@ -424,7 +439,7 @@ reason = 0; while (reason == 0) { /* loop until halted */ if (sim_interval <= 0) { /* check clock queue */ - if (reason = sim_process_event ()) + if ((reason = sim_process_event ())) break; } @@ -452,13 +467,14 @@ if (chan_req) { /* channel request? */ return STOP_DMAER; if ((r = t >> IOT_V_REASON) != 0) return r; + // [RLA] Note that we intentionally ignore address breaks here! Write (ad, t & DMASK); /* write to mem */ } else { /* no, output */ t = iotab[dev] (ioOTA, 0, Read (ad), dev); /* output word */ if ((t & IOT_SKIP) == 0) return STOP_DMAER; - if (r = (t >> IOT_V_REASON)) + if ((r = (t >> IOT_V_REASON))) return r; } if (Q_DMA (i)) { /* DMA? */ @@ -473,6 +489,7 @@ if (chan_req) { /* channel request? */ } else { /* DMC */ st = (st & DMA_IN) | ((ad + 1) & X_AMASK); + // [RLA] Note that we intentionally ignore address breaks here! Write (dmcad, st); /* update start */ end = Read (dmcad + 1); /* get end */ if (((ad ^ end) & X_AMASK) == 0) { /* start == end? */ @@ -488,12 +505,17 @@ if (chan_req) { /* channel request? */ /* Interrupts */ -if ((dev_int & (INT_PEND|INT_NMI|dev_enb)) > INT_PEND) {/* int req? */ - pme = ext; /* save extend */ - if (cpu_unit.flags & UNIT_EXT) /* ext opt? extend on */ - ext = 1; - dev_int = dev_int & ~INT_ON; /* intr off */ - MB = 0120000 | M_INT; /* inst = JST* 63 */ +//[RLA] Todo - add WDT interrupts ???? + +iack = FALSE; +if ((dev_int & (INT_PEND|INT_NMI|dev_enb)) > INT_PEND) { // [RLA] check for standard interrupt + MB = cpu_interrupt(M_INT); + iack = TRUE; + } +else if (((dev_ext_int & dev_ext_enb) != 0) // [RLA] check for extended interrupt + && ((dev_int & INT_PEND) == INT_PEND)) { + MB = cpu_ext_interrupt (); + iack = TRUE; } /* Instruction fetch */ @@ -521,6 +543,7 @@ if (hst_lnt) { /* instr hist? */ hst[hst_p].ar = AR; hst[hst_p].br = BR; hst[hst_p].xr = XR; + hst[hst_p].iack = iack; // [RLA] record if interrupt taken } /* Memory reference instructions */ @@ -528,7 +551,7 @@ if (hst_lnt) { /* instr hist? */ switch (I_GETOP (MB)) { /* case on <1:6> */ case 001: case 021: case 041: case 061: /* JMP */ - if (reason = Ea (MB, &Y)) /* eff addr */ + if ((reason = Ea (MB, &Y))) /* eff addr */ break; PCQ_ENTRY; /* save PC */ PC = NEWA (PC, Y); /* set new PC */ @@ -537,7 +560,7 @@ switch (I_GETOP (MB)) { /* case on <1:6> */ break; case 002: case 022: case 042: case 062: /* LDA */ - if (reason = Ea (MB, &Y)) /* eff addr */ + if ((reason = Ea (MB, &Y))) /* eff addr */ break; if (dp) { /* double prec? */ AR = Read (Y & ~1); /* get doubleword */ @@ -548,29 +571,31 @@ switch (I_GETOP (MB)) { /* case on <1:6> */ break; case 003: case 023: case 043: case 063: /* ANA */ - if (reason = Ea (MB, &Y)) /* eff addr */ + if ((reason = Ea (MB, &Y))) /* eff addr */ break; AR = AR & Read (Y); break; case 004: case 024: case 044: case 064: /* STA */ - if (reason = Ea (MB, &Y)) /* eff addr */ + if ((reason = Ea (MB, &Y))) /* eff addr */ break; - Write (Y, AR); /* store A */ + if ((reason = Write(Y, AR))) + break; /* [RLA] store A */ if (dp) { /* double prec? */ - Write (Y | 1, BR); /* store B */ + if ((reason = Write(Y | 1, BR))) + break; /* [RLA] store B */ sc = 0; } break; case 005: case 025: case 045: case 065: /* ERA */ - if (reason = Ea (MB, &Y)) /* eff addr */ + if ((reason = Ea (MB, &Y))) /* eff addr */ break; AR = AR ^ Read (Y); break; case 006: case 026: case 046: case 066: /* ADD */ - if (reason = Ea (MB, &Y)) /* eff addr */ + if ((reason = Ea (MB, &Y))) /* eff addr */ break; if (dp) { /* double prec? */ t1 = GETDBL_S (AR, BR); /* get A'B */ @@ -583,7 +608,7 @@ switch (I_GETOP (MB)) { /* case on <1:6> */ break; case 007: case 027: case 047: case 067: /* SUB */ - if (reason = Ea (MB, &Y)) /* eff addr */ + if ((reason = Ea (MB, &Y))) /* eff addr */ break; if (dp) { /* double prec? */ t1 = GETDBL_S (AR, BR); /* get A'B */ @@ -596,16 +621,17 @@ switch (I_GETOP (MB)) { /* case on <1:6> */ break; case 010: case 030: case 050: case 070: /* JST */ - if (reason = Ea (MB, &Y)) /* eff addr */ + if ((reason = Ea (MB, &Y))) /* eff addr */ break; MB = NEWA (Read (Y), PC); /* merge old PC */ - Write (Y, MB); + if ((reason = Write(Y, MB))) + break; // [RLA] PCQ_ENTRY; PC = NEWA (PC, Y + 1); /* set new PC */ break; case 011: case 031: case 051: case 071: /* CAS */ - if (reason = Ea (MB, &Y)) /* eff addr */ + if ((reason = Ea (MB, &Y))) /* eff addr */ break; MB = Read (Y); if (AR == MB) @@ -615,30 +641,33 @@ switch (I_GETOP (MB)) { /* case on <1:6> */ break; case 012: case 032: case 052: case 072: /* IRS */ - if (reason = Ea (MB, &Y)) /* eff addr */ + if ((reason = Ea (MB, &Y))) /* eff addr */ break; MB = (Read (Y) + 1) & DMASK; /* incr, rewrite */ - Write (Y, MB); + if ((reason = Write(Y, MB))) + break; // [RLA] if (MB == 0) /* skip if zero */ PC = NEWA (PC, PC + 1); break; case 013: case 033: case 053: case 073: /* IMA */ - if (reason = Ea (MB, &Y)) /* eff addr */ + if ((reason = Ea (MB, &Y))) /* eff addr */ break; MB = Read (Y); - Write (Y, AR); /* A to mem */ + if ((reason = Write(Y, AR))) + break; /* [RLA] A to mem */ AR = MB; /* mem to A */ break; case 015: case 055: /* STX */ - if (reason = Ea (MB & ~IDX, &Y)) /* eff addr */ + if ((reason = Ea (MB & ~IDX, &Y))) /* eff addr */ break; - Write (Y, XR); /* store XR */ + if ((reason = Write(Y, XR))) + break; /* [RLA] store XR */ break; case 035: case 075: /* LDX */ - if (reason = Ea (MB & ~IDX, &Y)) /* eff addr */ + if ((reason = Ea (MB & ~IDX, &Y))) /* eff addr */ break; XR = Read (Y); /* load XR */ M[M_XR] = XR; /* update mem too */ @@ -646,7 +675,7 @@ switch (I_GETOP (MB)) { /* case on <1:6> */ case 016: case 036: case 056: case 076: /* MPY */ if (cpu_unit.flags & UNIT_HSA) { /* installed? */ - if (reason = Ea (MB, &Y)) /* eff addr */ + if ((reason = Ea (MB, &Y))) /* eff addr */ break; t1 = SEXT (AR) * SEXT (Read (Y)); PUTDBL_Z (t1); @@ -657,7 +686,7 @@ switch (I_GETOP (MB)) { /* case on <1:6> */ case 017: case 037: case 057: case 077: /* DIV */ if (cpu_unit.flags & UNIT_HSA) { /* installed? */ - if (reason = Ea (MB, &Y)) /* eff addr */ + if ((reason = Ea (MB, &Y))) /* eff addr */ break; t2 = SEXT (Read (Y)); /* divr */ if (t2) { /* divr != 0? */ @@ -704,6 +733,10 @@ switch (I_GETOP (MB)) { /* case on <1:6> */ case 074: /* OTA */ dev = MB & DEVMASK; + // [RLA] OTA w/devices 20 or 24 are SMK or OTK! + if ((dev == 020) || (dev == 024)) + t2 = sim_ota_2024(ioOTA, I_GETFNC (MB), AR, dev); + else t2 = iotab[dev] (ioOTA, I_GETFNC (MB), AR, dev); reason = t2 >> IOT_V_REASON; if (t2 & IOT_SKIP) /* skip? */ @@ -826,7 +859,7 @@ switch (I_GETOP (MB)) { /* case on <1:6> */ break; case 003: /* "long right arot" */ - if (reason = stop_inst) /* stop on undef? */ + if ((reason = stop_inst)) /* stop on undef? */ break; for (t2 = 0; t2 < t1; t2++) { /* bit by bit */ C = BR & 1; /* C = last out */ @@ -859,7 +892,7 @@ switch (I_GETOP (MB)) { /* case on <1:6> */ break; case 007: /* "short right arot" */ - if (reason = stop_inst) /* stop on undef? */ + if ((reason = stop_inst)) /* stop on undef? */ break; for (t2 = 0; t2 < t1; t2++) { /* bit by bit */ C = AR & 1; /* C = last out */ @@ -899,7 +932,7 @@ switch (I_GETOP (MB)) { /* case on <1:6> */ break; case 013: /* "long left arot" */ - if (reason = stop_inst) /* stop on undef? */ + if ((reason = stop_inst)) /* stop on undef? */ break; for (t2 = 0; t2 < t1; t2++) { /* bit by bit */ AR = (AR << 1) | ((BR >> 14) & 1); @@ -935,7 +968,7 @@ switch (I_GETOP (MB)) { /* case on <1:6> */ break; case 017: /* "short left arot" */ - if (reason = stop_inst) /* stop on undef? */ + if ((reason = stop_inst)) /* stop on undef? */ break; for (t2 = 0; t2 < t1; t2++) { /* bit by bit */ if ((AR & SIGN) != ((AR << 1) & SIGN)) C = 1; @@ -1003,7 +1036,7 @@ switch (I_GETOP (MB)) { /* case on <1:6> */ AR = (AR << 8) & DMASK; else if (MB == 0141340) /* ICA */ AR = ((AR << 8) | (AR >> 8)) & DMASK; - else if (reason = stop_inst) + else if ((reason = stop_inst)) break; else AR = Operate (MB, AR); /* undefined */ break; @@ -1064,13 +1097,18 @@ return SCPE_OK; /* Write memory */ -void Write (int32 addr, int32 val) +t_stat Write (int32 addr, int32 val) { +// [RLA] Write() now checks for address breaks ... if (((addr == 0) || (addr >= 020)) && MEM_ADDR_OK (addr)) M[addr] = val; if (addr == M_XR) /* write XR loc? */ - XR = val; /* update XR */ -return; + XR = val; + // [RLA] Implement "break on memory write" ... + if (sim_brk_summ && sim_brk_test (addr, SWMASK ('W'))) + return STOP_IBKPT; + else + return SCPE_OK; } /* Add */ @@ -1095,6 +1133,54 @@ else C = 0; return r; } +// [RLA] Standard (fixed vector) interrupt action ... + +int32 cpu_interrupt (int32 vec) +{ +pme = ext; /* save extend */ +if (cpu_unit.flags & UNIT_EXT) + ext = 1; /* ext opt? extend on */ +dev_int = dev_int & ~INT_ON; /* intr off */ +return 0120000 | vec; /* inst = JST* vector */ +} + +// [RLA] Extended (priority) interrupt action ... +int32 cpu_ext_interrupt (void) { + // Unlike the standard interrupts, which have a fixed vector shared by all + // devices, the extended interrupts have a unique vector for every device. + // Moreover, extended interrupts are prioritized so that the lowest numbered + // interrupts have priority. That means we have to actually scan the bitmap + // of active interrupts to figure out which one to take. + // + // One uncomfortable thing about the external interrupts is that it appears + // that they were edge triggered - once an interrupt on a given level was + // granted, that interrupt wouldn't occur again until another edge occurred on + // the same request. I'm "uncomfortable" with this because it's different from + // the way the standard interrupt works - that's completely level sensitive. + // Still, this Honeywell document + // + // http://bitsavers.informatik.uni-stuttgart.de/pdf/honeywell/series16/h316/70130072167D_316_Interfacing_Apr73.pdf + // + // (read Chapter 4, Priority Interrupts, the very first paragraph) at least + // seems to imply edge triggering. And the IMP firmware is written as if they + // are edge triggered - there are many cases (modem output, task, RTC) where + // the IMP code does nothing to clear the interrupt request flag. So we're + // going with edge triggered version for now... + int32 i; uint16 m, irq; + irq = dev_ext_int & dev_ext_enb; + for (i = 1, m = SIGN; m != 0; ++i, m >>= 1) { + if ((irq & m) != 0) { + // Extended interrupts are edge triggered (see above) - when this + // interrupt is granted, clear the request ... + CLR_EXT_INT(m); + return cpu_interrupt(M_INT+i); + } + } + // If we get here, it means that we were called with no interrupt bits set. + // That really should never happen, so just HALT ... + return(0); +} + /* Unimplemented I/O device */ int32 undio (int32 op, int32 fnc, int32 val, int32 dev) @@ -1102,6 +1188,63 @@ int32 undio (int32 op, int32 fnc, int32 val, int32 dev) return ((stop_dev << IOT_V_REASON) | val); } +/* [RLA] Special I/O devices */ + +int32 sim_ota_2024 (int32 inst, int32 fnc, int32 dat, int32 dev) +{ + // OTA instructions with a device code of 20 or 24 are really SMK + // (Set interrupt Mask) instructions. OTA 20 sets the standard H316 + // interrupt mask, and OTA 120, OTA 220 and OTA 320 set the extended + // interrupt mask (of which only one, OTA 120, is used by the IMP). + // + // Further, OTA 1020 is the OTK instruction which sets special CPU + // flags (single or double precision HSA, extended addressing mode, + // the carry flag, etc). + // + // This routine implements these special OTKs as part of the CPU. + // That allows us to implement the extra interrupt masks needed by the + // IMP, and it also allows the CLK device to be disabled without losing + // the SMK or OTK instructions. The clock was an option on the original + // H316 and is not required to be present, and the IMP in particular + // needs it to be disabled. + + // Although OTA 24 is reserved nothing we currently simulate uses it! + + if (dev == 024) + return IOBADFNC (dat); + + // Device code 20... + switch (fnc) { + case 000: // SMK 020 - set standard interrupt mask + dev_enb = dat; + break; + case 001: // SMK 120 - set extended interrupt mask #1 + if (ext_ints < 16) + return IOBADFNC(dat); + dev_ext_enb = dat; + break; + case 002: // SMK 220 - set extended interrupt mask #2 + case 003: // SMK 320 - set extended interrupt mask #3 + return IOBADFNC(dat); + case 010: // OTK - output keys + C = (dat >> 15) & 1; /* set C */ + if (cpu_unit.flags & UNIT_HSA) /* HSA included? */ + dp = (dat >> 14) & 1; /* set dp */ + if (cpu_unit.flags & UNIT_EXT) { /* ext opt? */ + if (dat & 020000) { /* ext set? */ + ext = 1; /* yes, set */ + extoff_pending = 0; + } + else extoff_pending = 1; /* no, clr later */ + } + sc = dat & 037; /* set sc */ + break; + default: + return IOBADFNC (dat); + } + return dat; +} + /* DMA control */ int32 dmaio (int32 inst, int32 fnc, int32 dat, int32 dev) @@ -1296,7 +1439,7 @@ C = 0; dp = 0; ext = pme = extoff_pending = 0; dev_int = dev_int & ~(INT_PEND|INT_NMI); -dev_enb = 0; +dev_ext_int = dev_enb = dev_ext_enb = 0; for (i = 0; i < DMA_MAX; i++) dma_ad[i] = dma_wc[i] = dma_eor[i] = 0; chan_req = 0; @@ -1304,7 +1447,10 @@ pcq_r = find_reg ("PCQ", NULL, dptr); if (pcq_r) pcq_r->qptr = 0; else return SCPE_IERR; -sim_brk_types = sim_brk_dflt = SWMASK ('E'); +// [RLA] We now have two break types - "E" (break on execution) and also "W" +// [RLA] (break on write)... +sim_brk_types = SWMASK('W') | SWMASK('E'); +sim_brk_dflt = SWMASK ('E'); return SCPE_OK; } @@ -1358,6 +1504,28 @@ for (i = MEMSIZE; i < MAXMEMSIZE; i++) return SCPE_OK; } +/* [RLA] Set/Show number of interrupts supported */ + +t_stat cpu_set_interrupts (UNIT *uptr, int32 val, char *cptr, void *desc) +{ + uint32 newint; t_stat ret; + if (cptr == NULL) return SCPE_ARG; + newint = get_uint (cptr, 10, 49, &ret); + if (ret != SCPE_OK) return ret; + if ((newint != 0) && (newint != 16)) return SCPE_ARG; + ext_ints = newint; + return SCPE_OK; +} + +t_stat cpu_show_interrupts (FILE *st, UNIT *uptr, int32 val, void *desc) +{ + if (ext_ints == 0) + fprintf(st,"standard interrupts"); + else + fprintf(st,"extended interrupts = %d", ext_ints); + return SCPE_OK; +} + t_stat cpu_set_nchan (UNIT *uptr, int32 val, char *cptr, void *desc) { uint32 i, newmax; @@ -1382,7 +1550,7 @@ t_stat cpu_show_nchan (FILE *st, UNIT *uptr, int32 val, void *desc) { if (dma_nch) fprintf (st, "DMA channels = %d", dma_nch); -else fprintf (st, "no DMA channels"); +else fprintf (st, "no DMA"); return SCPE_OK; } @@ -1489,60 +1657,60 @@ return SCPE_OK; } /* Set up I/O dispatch and channel maps */ +// [RLA] Check for DMC conflicts (on both DMC channels!) ... + +t_bool set_chanmap (DEVICE *dptr, DIB *dibp, uint32 dno, uint32 chan) +{ + if ((chan < DMC_V_DMC1) && (chan >= dma_nch)) { + sim_printf ("%s configured for DMA channel %d\n", sim_dname (dptr), chan + 1); + return TRUE; + } + if ((chan >= DMC_V_DMC1) && !(cpu_unit.flags & UNIT_DMC)) { + sim_printf ("%s configured for DMC, option disabled\n", sim_dname (dptr)); + return TRUE; + } + if (chan_map[chan]) { /* channel conflict? */ + sim_printf ("%s DMA/DMC channel conflict, devno = %02o\n", sim_dname (dptr), dno); + return TRUE; + } + chan_map[chan] = dno; /* channel back map */ + return FALSE; +} t_bool devtab_init (void) { DEVICE *dptr; DIB *dibp; -uint32 i, j, dno, chan; +uint32 i, j, dno; for (i = 0; i < DEV_MAX; i++) iotab[i] = NULL; for (i = 0; i < (DMA_MAX + DMC_MAX); i++) chan_map[i] = 0; -for (i = 0; dptr = sim_devices[i]; i++) { /* loop thru devices */ +for (i = 0; (dptr = sim_devices[i]); i++) { /* loop thru devices */ dibp = (DIB *) dptr->ctxt; /* get DIB */ if ((dibp == NULL) || (dptr->flags & DEV_DIS)) /* exist, enabled? */ continue; dno = dibp->dev; /* device number */ for (j = 0; j < dibp->num; j++) { /* repeat for slots */ if (iotab[dno + j]) { /* conflict? */ - printf ("%s device number conflict, devno = %02o\n", - sim_dname (dptr), dno + j); - if (sim_log) - fprintf (sim_log, "%s device number conflict, devno = %02o\n", + sim_printf ("%s device number conflict, devno = %02o\n", sim_dname (dptr), dno + j); return TRUE; } iotab[dno + j] = dibp->io; /* set I/O routine */ } /* end for */ - if (dibp->chan) { /* DMA/DMC? */ - chan = dibp->chan - 1; - if ((chan < DMC_V_DMC1) && (chan >= dma_nch)) { - printf ("%s configured for DMA channel %d\n", - sim_dname (dptr), chan + 1); - if (sim_log) - fprintf (sim_log, "%s configured for DMA channel %d\n", - sim_dname (dptr), chan + 1); + // [RLA] set up the channel map + if (dibp->chan != 0) + if (set_chanmap(dptr, dibp, dno, dibp->chan-1)) return TRUE; - } - if ((chan >= DMC_V_DMC1) && !(cpu_unit.flags & UNIT_DMC)) { - printf ("%s configured for DMC, option disabled\n", - sim_dname (dptr)); - if (sim_log) - fprintf (sim_log, "%s configured for DMC, option disabled\n", - sim_dname (dptr)); + if (dibp->chan2 != 0) + if (set_chanmap(dptr, dibp, dno, dibp->chan2-1)) return TRUE; - } - if (chan_map[chan]) { /* channel conflict? */ - printf ("%s DMA/DMC channel conflict, devno = %02o\n", - sim_dname (dptr), dno); - if (sim_log) - fprintf (sim_log, "%s DMA/DMC channel conflict, devno = %02o\n", - sim_dname (dptr), dno); - return TRUE; - } - chan_map[chan] = dno; /* channel back map */ + // [RLA] If the device uses extended interrupts, check that they're enabled. + if ((dibp->inum != INT_V_NONE) && (dibp->inum >= INT_V_EXTD) && (ext_ints == 0)) { + sim_printf ("%s uses extended interrupts but that option is disabled\n", sim_dname (dptr)); + return TRUE; } } /* end for */ for (i = 0; i < DEV_MAX; i++) { /* fill in blanks */ @@ -1592,8 +1760,6 @@ char *cptr = (char *) desc; t_value sim_eval; t_stat r; InstHistory *h; -extern t_stat fprint_sym (FILE *ofile, t_addr addr, t_value *val, - UNIT *uptr, int32 sw); static uint8 has_opnd[16] = { 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1 }; @@ -1609,7 +1775,8 @@ else lnt = hst_lnt; di = hst_p - lnt; /* work forward */ if (di < 0) di = di + hst_lnt; -fprintf (st, "PC C A B X ea IR\n\n"); +fprintf (st, " PC C A B X ea IR\n"); +fprintf (st, "----- - ------ ------ ------ ----- -----------\n\n"); for (k = 0; k < lnt; k++) { /* print specified */ h = &hst[(++di) % hst_lnt]; /* entry pointer */ if (h->pc & HIST_PC) { /* instruction? */ @@ -1626,6 +1793,8 @@ for (k = 0; k < lnt; k++) { /* print specified */ op = I_GETOP (h->ir) & 017; /* base op */ if (has_opnd[op]) fprintf (st, " [%06o]", h->opnd); + if (h->iack) // [RLA] + fprintf(st, " INTERRUPT"); // [RLA] fputc ('\n', st); /* end line */ } /* end else instruction */ } /* end for */ diff --git a/H316/h316_defs.h b/H316/h316_defs.h index d647742a..dc7a8ba6 100644 --- a/H316/h316_defs.h +++ b/H316/h316_defs.h @@ -1,6 +1,6 @@ /* h316_defs.h: Honeywell 316/516 simulator definitions - Copyright (c) 1999-2011, Robert M. Supnik + Copyright (c) 1999-2015, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -23,6 +23,7 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 31-May-13 RLA DIB - add second channel, interrupt and user parameter 19-Nov-11 RMS Removed XR macro, added XR_LOC macro (from Adrian Wise) 22-May-10 RMS Added check for 64b definitions 15-Feb-05 RMS Added start button interrupt @@ -31,8 +32,8 @@ 25-Apr-03 RMS Revised for extended file support */ -#ifndef _H316_DEFS_H_ -#define _H316_DEFS_H_ 0 +#ifndef H316_DEFS_H_ +#define H316_DEFS_H_ 0 #include "sim_defs.h" /* simulator defns */ @@ -111,10 +112,14 @@ struct h316_dib { uint32 dev; /* device number */ - uint32 chan; /* dma/dmc channel */ uint32 num; /* number of slots */ - int32 (*io) (int32 inst, int32 fnc, int32 dat, int32 dev); }; - + uint32 chan; /* dma/dmc channel */ + uint32 chan2; /* alternate DMA/DMD channel */ + uint32 inum; /* interrupt number */ + uint32 inum2; /* alternate interrupt */ + int32 (*io) (int32 inst, int32 fnc, int32 dat, int32 dev); + uint32 u3; /* "user" parameter #1 */ +}; typedef struct h316_dib DIB; /* DMA/DMC channel numbers */ @@ -169,6 +174,8 @@ typedef struct h316_dib DIB; #define INT_V_START 16 /* start button */ #define INT_V_NODEF 17 /* int not deferred */ #define INT_V_ON 18 /* int on */ +#define INT_V_EXTD 16 /* first extended interrupt */ +#define INT_V_NONE 0xffffffff /* no interrupt used */ /* I/O macros */ @@ -195,12 +202,21 @@ typedef struct h316_dib DIB; #define INT_NMI (INT_START) #define INT_PEND (INT_ON | INT_NODEF) +// [RLA] These macros now all affect the standard interrupts. We'll leave +// [RLA] them alone for backward compatibility with the existing code. #define SET_INT(x) dev_int = dev_int | (x) #define CLR_INT(x) dev_int = dev_int & ~(x) #define TST_INT(x) ((dev_int & (x)) != 0) #define CLR_ENB(x) dev_enb = dev_enb & ~(x) #define TST_INTREQ(x) ((dev_int & dev_enb & (x)) != 0) +// [RLA] These macros are functionally identical, but affect extended interrupts. +#define SET_EXT_INT(x) dev_ext_int = dev_ext_int | (x) +#define CLR_EXT_INT(x) dev_ext_int = dev_ext_int & ~(x) +#define TST_EXT_INT(x) ((dev_ext_int & (x)) != 0) +#define CLR_EXT_ENB(x) dev_ext_enb = dev_ext_enb & ~(x) +#define TST_EXT_INTREQ(x) ((dev_ext_int & dev_ext_enb & (x)) != 0) + /* Prototypes */ t_stat io_set_iobus (UNIT *uptr, int32 val, char *cptr, void *desc); diff --git a/H316/h316_dp.c b/H316/h316_dp.c index 40468675..ac0145c7 100644 --- a/H316/h316_dp.c +++ b/H316/h316_dp.c @@ -1,6 +1,6 @@ /* h316_dp.c: Honeywell 4623, 4651, 4720 disk simulator - Copyright (c) 2003-2012, Robert M. Supnik + Copyright (c) 2003-2015, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -27,6 +27,7 @@ 4651 disk subsystem 4720 disk subsystem + 03-Jul-13 RLA compatibility changes for extended interrupts 19-Mar-12 RMS Fixed declaration of chan_req (Mark Pizzolato) 04-Sep-05 RMS Fixed missing return (Peter Schorn) 15-Jul-05 RMS Fixed bug in attach routine @@ -220,7 +221,6 @@ extern int32 dev_int, dev_enb; extern uint32 chan_req; extern int32 stop_inst; extern uint32 dma_ad[DMA_MAX]; -extern int32 sim_switches; uint32 dp_cw1 = 0; /* cmd word 1 */ uint32 dp_cw2 = 0; /* cmd word 2 */ @@ -270,7 +270,7 @@ t_stat dp_showformat (FILE *st, UNIT *uptr, int32 val, void *desc); dp_mod DP modifier list */ -DIB dp_dib = { DP, DMC1, 1, &dpio }; +DIB dp_dib = { DP, 1, DMC1, IOBUS, INT_V_DP, INT_V_NONE, &dpio, 0 }; UNIT dp_unit[] = { { UDATA (&dp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ @@ -617,7 +617,7 @@ switch (uptr->FNC) { /* case on function */ case FNC_RCA: /* read current addr */ if (h >= dp_tab[dp_ctype].surf) /* invalid head? */ return dp_done (1, STA_ADRER); /* error */ - if (r = dp_rdtrk (uptr, dpxb, uptr->CYL, h)) /* get track; error? */ + if ((r = dp_rdtrk (uptr, dpxb, uptr->CYL, h))) /* get track; error? */ return r; dp_rptr = 0; /* init rec ptr */ if (dpxb[dp_rptr + REC_LNT] == 0) /* unformated? */ @@ -722,7 +722,7 @@ switch (uptr->FNC) { /* case on function */ case FNC_RW: /* read/write */ if (h >= dp_tab[dp_ctype].surf) /* invalid head? */ return dp_done (1, STA_ADRER); /* error */ - if (r = dp_rdtrk (uptr, dpxb, uptr->CYL, h)) /* get track; error? */ + if ((r = dp_rdtrk (uptr, dpxb, uptr->CYL, h))) /* get track; error? */ return r; if (!dp_findrec (dp_cw2)) /* find rec; error? */ return dp_done (1, STA_ADRER); /* address error */ @@ -750,7 +750,7 @@ switch (uptr->FNC) { /* case on function */ if (dp_cw1 & CW1_RW) { /* write? */ if (dp_sta & STA_RDY) /* timing failure? */ return dp_wrdone (uptr, STA_DTRER); /* yes, error */ - if (r = dp_wrwd (uptr, dp_buf)) /* wr word, error? */ + if ((r = dp_wrwd (uptr, dp_buf))) /* wr word, error? */ return r; if (dp_eor) { /* transfer done? */ dpxb[dp_rptr + REC_DATA + dp_wptr] = dp_csum; @@ -855,7 +855,7 @@ if (dp_wptr < (lnt + REC_MAXEXT)) { } dpxb[dp_rptr + REC_DATA + dp_wptr] = dp_csum; /* write csum */ dpxb[dp_rptr + lnt + REC_OVHD] = 0; /* zap rest of track */ -if (r = dp_wrdone (uptr, STA_UNSER)) /* dump track */ +if ((r = dp_wrdone (uptr, STA_UNSER))) /* dump track */ return r; return STOP_DPOVR; } @@ -1002,7 +1002,7 @@ else { if (nr <= 0) return SCPE_ARG; } -printf ("Proposed format: records/track = %d, record size = %d\n", nr, nw); +sim_printf ("Proposed format: records/track = %d, record size = %d\n", nr, nw); if (!get_yn ("Formatting will destroy all data on this disk; proceed? [N]", FALSE)) return SCPE_OK; for (c = cntr = 0; c < dp_tab[dp_ctype].cyl; c++) { @@ -1017,11 +1017,11 @@ for (c = cntr = 0; c < dp_tab[dp_ctype].cyl; c++) { else tbuf[rptr + REC_ADDR] = (c << 8) + (h << 3) + i; rptr = rptr + nw + REC_OVHD; } - if (r = dp_wrtrk (uptr, tbuf, c, h)) + if ((r = dp_wrtrk (uptr, tbuf, c, h))) return r; } } -printf ("Formatting complete\n"); +sim_printf ("Formatting complete\n"); return SCPE_OK; } @@ -1043,7 +1043,7 @@ if ((uptr->flags & UNIT_ATT) == 0) return SCPE_UNATT; for (c = 0; c < dp_tab[dp_ctype].cyl; c++) { for (h = 0; h < dp_tab[dp_ctype].surf; h++) { - if (r = dp_rdtrk (uptr, tbuf, c, h)) + if ((r = dp_rdtrk (uptr, tbuf, c, h))) return r; rptr = 0; rlnt = tbuf[rptr + REC_LNT]; diff --git a/H316/h316_fhd.c b/H316/h316_fhd.c index 3f984da3..e711adab 100644 --- a/H316/h316_fhd.c +++ b/H316/h316_fhd.c @@ -1,6 +1,6 @@ /* h316_fhd.c: H316/516 fixed head simulator - Copyright (c) 2003-2013, Robert M. Supnik + Copyright (c) 2003-2015, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,7 +25,8 @@ fhd 516-4400 fixed head disk - 03-Sep-13 RMS Added explicit cast on void * pointer + 03-Sep-13 RMS Added explicit void * cast + 03-Jul-13 RLA compatibility changes for extended interrupts 19-Mar-12 RMS Fixed declaration of chan_req (Mark Pizzolato) 15-May-06 RMS Fixed bug in autosize attach (David Gesswein) 04-Jan-04 RMS Changed sim_fsize calling sequence @@ -114,7 +115,7 @@ uint32 fhd_csword (uint32 cs, uint32 ch); fhd_reg register list */ -DIB fhd_dib = { FHD, IOBUS, 1, &fhdio }; +DIB fhd_dib = { FHD, 1, IOBUS, IOBUS, INT_V_FHD, INT_V_NONE, &fhdio, 0 }; UNIT fhd_unit = { UDATA (&fhd_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+UNIT_MUSTBUF, diff --git a/H316/h316_hi.c b/H316/h316_hi.c new file mode 100644 index 00000000..6ef81e56 --- /dev/null +++ b/H316/h316_hi.c @@ -0,0 +1,324 @@ +/* h316_hi.c- BBN ARPAnet IMP Host Interface + Based on the SIMH simulator package written by Robert M Supnik. + + Copyright (c) 2013 Robert Armstrong, bob@jfcl.com. + + 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 + ROBERT ARMSTRONG 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 Robert Armstrong shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert Armstrong. + + hi host interface + + 21-May-13 RLA New file + + The host interface is one of the BBN engineered devices unique to the + ARPAnet IMP. This is the famous "1822" card which connected each IMP to a + host computer - a DECSYSTEM-10, an SDS Sigma 7, an IBM 360/90, a CDC6600, + or any one of many other ARPAnet hosts. The idea is to simulate this + interface by using a TCP/UDP connection to another simh instance emulating + the host machine and running the ARPAnet host software. + + Presently the details of the host interface card are not well known, and + this implementation is simply a place holder. It's enough to allow the IMP + software to run, but not actually to communicate with a host. The IMP simply + believes that all the attached hosts are down at the moment. + + Host interface state is maintained in a set of position and state variables: + + Host state is maintained in the following variables - + + TBA TBA + + TODO + + IMPLEMENT THIS MODULE!!! +*/ +#ifdef VM_IMPTIP +#include "h316_defs.h" // H316 emulator definitions +#include "h316_imp.h" // ARPAnet IMP/TIP definitions + +// Externals from other parts of simh ... +extern uint16 dev_ext_int, dev_ext_enb; // current IRQ and IEN bit vectors +extern int32 PC; // current PC (for debug messages) +extern int32 stop_inst; // needed by IOBADFNC() +extern uint16 M[]; // main memory (for DMC access) + +// Forward declarations ... +int32 hi_io (uint16 line, int32 inst, int32 fnc, int32 dat, int32 dev); +int32 hi1_io (int32 inst, int32 fnc, int32 dat, int32 dev); +int32 hi2_io (int32 inst, int32 fnc, int32 dat, int32 dev); +int32 hi3_io (int32 inst, int32 fnc, int32 dat, int32 dev); +int32 hi4_io (int32 inst, int32 fnc, int32 dat, int32 dev); +t_stat hi_service (UNIT *uptr); +t_stat hi_reset (DEVICE *dptr); +t_stat hi_attach (UNIT *uptr, char *cptr); +t_stat hi_detach (UNIT *uptr); + + + +//////////////////////////////////////////////////////////////////////////////// +////////////////////// D A T A S T R U C T U R E S ////////////////////// +//////////////////////////////////////////////////////////////////////////////// + +// Host interface data blocks ... +// The HIDB is our own internal data structure for each host. It keeps data +// about the TCP/IP connection, buffers, etc. +#define HI_HIDB(N) {0, 0, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE} +HIDB hi1_db = HI_HIDB(1), hi2_db = HI_HIDB(2); +HIDB hi3_db = HI_HIDB(3), hi4_db = HI_HIDB(4); + +// Host Device Information Blocks ... +// The DIB is the structure simh uses to keep track of the device IO address +// and IO service routine. It can also hold the DMC channel, but we don't use +// that because it's unit specific. +#define HI_DIB(N) {HI##N, 1, HI##N##_RX_DMC, HI##N##_TX_DMC, \ + INT_V_HI##N##RX, INT_V_HI##N##TX, &hi##N##_io, N} +DIB hi1_dib = HI_DIB(1), hi2_dib = HI_DIB(2); +DIB hi3_dib = HI_DIB(3), hi4_dib = HI_DIB(4); + +// Host Device Unit data ... +// simh uses the unit data block primarily to schedule device service events. +// The UNIT data also contains four "user" fields which devices can reuse for +// any purpose and we take advantage of that to store the line number. +#define hline u3 // our host line number is stored in user data 3 +#define HI_UNIT(N) {UDATA (&hi_service, UNIT_ATTABLE, 0), HI_POLL_DELAY, N, 0, 0, 0} +UNIT hi1_unit = HI_UNIT(1), hi2_unit = HI_UNIT(2); +UNIT hi3_unit = HI_UNIT(3), hi4_unit = HI_UNIT(4); + +// Host Device Registers ... +// These are the simh device "registers" - they c can be viewed with the +// "EXAMINE HIxn STATE" command and modified by "DEPOSIT HIxn ..." +#define HI_REG(N) { \ + { DRDATA (POLL, hi##N##_unit.wait, 24), REG_NZ + PV_LEFT }, \ + { FLDATA (RXIRQ, dev_ext_int, INT_V_HI##N##RX-INT_V_EXTD) }, \ + { FLDATA (RXIEN, dev_ext_enb, INT_V_HI##N##RX-INT_V_EXTD) }, \ + { DRDATA (RXTOT, hi##N##_db.rxtotal,32), REG_RO + PV_LEFT }, \ + { FLDATA (TXIRQ, dev_ext_int, INT_V_HI##N##TX-INT_V_EXTD) }, \ + { FLDATA (TXIEN, dev_ext_enb, INT_V_HI##N##TX-INT_V_EXTD) }, \ + { DRDATA (TXTOT, hi##N##_db.txtotal,32), REG_RO + PV_LEFT }, \ + { FLDATA (LLOOP, hi##N##_db.lloop, 0), PV_RZRO }, \ + { FLDATA (ERROR, hi##N##_db.error, 0), PV_RZRO }, \ + { FLDATA (READY, hi##N##_db.ready, 0), PV_RZRO }, \ + { FLDATA (FULL, hi##N##_db.full , 0), PV_RZRO }, \ + { NULL } \ +} +REG hi1_reg[] = HI_REG(1), hi2_reg[] = HI_REG(2); +REG hi3_reg[] = HI_REG(3), hi4_reg[] = HI_REG(4); + +// Host Device Modifiers ... +// These are the modifiers simh uses for the "SET MIxn" and "SHOW MIx" commands. +#define HI_MOD(N) { \ + { 0 } \ +} +MTAB hi1_mod[] = HI_MOD(1), hi2_mod[] = HI_MOD(2); +MTAB hi3_mod[] = HI_MOD(3), hi4_mod[] = HI_MOD(4); + +// Debug modifiers for "SET HIn DEBUG = xxx" ... +DEBTAB hi_debug[] = { + {"WARN", IMP_DBG_WARN}, // print warnings that would otherwise be suppressed + {"UDP", IMP_DBG_UDP}, // print all UDP messages sent and received + {"IO", IMP_DBG_IOT}, // print all program I/O instructions + {0} +}; + +// Host Device data ... +// This is the primary simh structure that defines each device - it gives the +// plain text name, the addresses of the unit, register and modifier tables, and +// the addresses of all action routines (e.g. attach, reset, etc). +#define HI_DEV(HI,N,F) { \ + #HI, &hi##N##_unit, hi##N##_reg, hi##N##_mod, \ + 1, 10, 31, 1, 8, 8, \ + NULL, NULL, &hi_reset, NULL, &hi_attach, &hi_detach, \ + &hi##N##_dib, DEV_DISABLE|DEV_DEBUG|(F), 0, hi_debug, NULL, NULL \ +} +DEVICE hi1_dev = HI_DEV(HI1,1,DEV_DIS), hi2_dev = HI_DEV(HI2,2,DEV_DIS); +DEVICE hi3_dev = HI_DEV(HI3,3,DEV_DIS), hi4_dev = HI_DEV(HI4,4,DEV_DIS); + +// Host Tables ... +// These tables make it easy to locate the data associated with any host. +DEVICE *const hi_devices[HI_NUM] = {&hi1_dev, &hi2_dev, &hi3_dev, &hi4_dev }; +UNIT *const hi_units [HI_NUM] = {&hi1_unit, &hi2_unit, &hi3_unit, &hi4_unit}; +DIB *const hi_dibs [HI_NUM] = {&hi1_dib, &hi2_dib, &hi3_dib, &hi4_dib }; +HIDB *const hi_hidbs [HI_NUM] = {&hi1_db, &hi2_db, &hi3_db, &hi4_db }; + + + +//////////////////////////////////////////////////////////////////////////////// +////////////////// L O W L E V E L F U N C T I O N S /////////////////// +//////////////////////////////////////////////////////////////////////////////// + +// Find a pointer to the DEVICE, UNIT, DIB or HIDB given the host number ... +#define PDEVICE(h) hi_devices[(h)-1] +#define PUNIT(h) hi_units[(h)-1] +#define PDIB(h) hi_dibs[(h)-1] +#define PHIDB(h) hi_hidbs[(h)-1] + +// These macros set and clear the interrupt request and enable flags ... +#define SET_RX_IRQ(h) SET_EXT_INT((1u << (PDIB(h)->rxint - INT_V_EXTD))) +#define SET_TX_IRQ(h) SET_EXT_INT((1u << (PDIB(h)->txint - INT_V_EXTD))) +#define CLR_RX_IRQ(h) CLR_EXT_INT((1u << (PDIB(h)->rxint - INT_V_EXTD))) +#define CLR_TX_IRQ(h) CLR_EXT_INT((1u << (PDIB(h)->txint - INT_V_EXTD))) +#define CLR_RX_IEN(h) CLR_EXT_ENB((1u << (PDIB(h)->rxint - INT_V_EXTD))) +#define CLR_TX_IEN(h) CLR_EXT_ENB((1u << (PDIB(h)->txint - INT_V_EXTD))) + +// TRUE if the host has the specified debugging output enabled ... +#define ISHDBG(l,f) ((PDEVICE(l)->dctrl & (f)) != 0) + +// Reset receiver (clear flags AND initialize all data) ... +void hi_reset_rx (uint16 host) +{ + PHIDB(host)->lloop = PHIDB(host)->error = PHIDB(host)->enabled = FALSE; + PHIDB(host)->ready = PHIDB(host)->eom = FALSE; + PHIDB(host)->rxtotal = 0; + CLR_RX_IRQ(host); CLR_RX_IEN(host); +} + +// Reset transmitter (clear flags AND initialize all data) ... +void hi_reset_tx (uint16 host) +{ + PHIDB(host)->lloop = PHIDB(host)->enabled = PHIDB(host)->full = FALSE; + PHIDB(host)->txtotal = 0; + CLR_TX_IRQ(host); CLR_TX_IEN(host); +} + + + +//////////////////////////////////////////////////////////////////////////////// +//////////// I / O I N S T R U C T I O N E M U L A T I O N ///////////// +//////////////////////////////////////////////////////////////////////////////// + +// Host specific I/O routines ... +int32 hi1_io(int32 inst, int32 fnc, int32 dat, int32 dev) {return hi_io(1, inst, fnc, dat, dev);} +int32 hi2_io(int32 inst, int32 fnc, int32 dat, int32 dev) {return hi_io(2, inst, fnc, dat, dev);} +int32 hi3_io(int32 inst, int32 fnc, int32 dat, int32 dev) {return hi_io(3, inst, fnc, dat, dev);} +int32 hi4_io(int32 inst, int32 fnc, int32 dat, int32 dev) {return hi_io(4, inst, fnc, dat, dev);} + +// Common I/O simulation routine ... +int32 hi_io (uint16 host, int32 inst, int32 fnc, int32 dat, int32 dev) +{ + // This routine is invoked by the CPU module whenever the code executes any + // I/O instruction (OCP, SKS, INA or OTA) with one of our modem's device + // address. + + // OCP (output control pulse) initiates various modem operations ... + if (inst == ioOCP) { + switch (fnc) { + case 000: + // HnROUT - start regular host output ... + sim_debug(IMP_DBG_IOT, PDEVICE(host), "start regular output (PC=%06o)\n", PC-1); + return dat; + case 001: + // HnIN - start host input ... + sim_debug(IMP_DBG_IOT, PDEVICE(host), "start input (PC=%06o)\n", PC-1); + return dat; + case 002: + // HnFOUT - start final host output ... + sim_debug(IMP_DBG_IOT, PDEVICE(host), "start final output (PC=%06o)\n", PC-1); + return dat; + case 003: + // HnXP - cross patch ... + sim_debug(IMP_DBG_IOT, PDEVICE(host), "enable cross patch (PC=%06o)\n", PC-1); + return dat; + case 004: + // HnUNXP - un-cross patch ... + sim_debug(IMP_DBG_IOT, PDEVICE(host), "disable cross patch (PC=%06o)\n", PC-1); + return dat; + case 005: + // HnENAB - enable ... + sim_debug(IMP_DBG_IOT, PDEVICE(host), "enable host (PC=%06o)\n", PC-1); + return dat; + } + + // SKS (skip) tests various modem conditions ... + } else if (inst == ioSKS) { + switch (fnc) { + case 000: + // HnERR - skip on host error ... + sim_debug(IMP_DBG_IOT, PDEVICE(host), "skip on error (PC=%06o %s)\n", PC-1, "NOSKIP"); + return dat; + case 001: + // HnRDY - skip on host ready ... + sim_debug(IMP_DBG_IOT, PDEVICE(host), "skip on ready (PC=%06o %s)\n", PC-1, "NOSKIP"); + return dat; + case 002: + // HnEOM - skip on end of message ... + sim_debug(IMP_DBG_IOT, PDEVICE(host), "skip on end of message (PC=%06o %s)\n", PC-1, "NOSKIP"); + return dat; + case 005: + // HnFULL - skip on host buffer full ... + sim_debug(IMP_DBG_IOT, PDEVICE(host), "skip on buffer full (PC=%06o %s)\n", PC-1, "NOSKIP"); + return dat; + } + } + + // Anything else is an error... + sim_debug(IMP_DBG_WARN, PDEVICE(host), "UNIMPLEMENTED I/O (PC=%06o, instruction=%o, function=%02o)\n", PC-1, inst, fnc); + return IOBADFNC(dat); +} + + + + +//////////////////////////////////////////////////////////////////////////////// +/////////////////// H O S T E V E N T S E R V I C E //////////////////// +//////////////////////////////////////////////////////////////////////////////// + +// Unit service ... +t_stat hi_service (UNIT *uptr) +{ + return SCPE_OK; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/////////////// D E V I C E A C T I O N C O M M A N D S //////////////// +//////////////////////////////////////////////////////////////////////////////// + +// Reset routine ... +t_stat hi_reset (DEVICE *dptr) +{ + // simh calls this routine for the RESET command ... + UNIT *uptr = dptr->units; + uint16 host= uptr->hline; + hi_reset_rx(host); hi_reset_tx(host); + return SCPE_OK; +} + +// Attach (connect) ... +t_stat hi_attach (UNIT *uptr, char *cptr) +{ + // simh calls this routine for (what else?) the ATTACH command. + uint16 host = uptr->hline; + fprintf(stderr,"HI%d - host interface not yet implemented\n", host); + return SCPE_IERR; +} + +// Detach (connect) ... +t_stat hi_detach (UNIT *uptr) +{ + // simh calls this routine for (you guessed it!) the DETACH command. + uint16 host = uptr->hline; + fprintf(stderr,"HI%d - host interface not yet implemented\n", host); + return SCPE_IERR; +} + + +#endif // #ifdef VM_IMPTIP from the very top diff --git a/H316/h316_imp.c b/H316/h316_imp.c new file mode 100644 index 00000000..a99c43a1 --- /dev/null +++ b/H316/h316_imp.c @@ -0,0 +1,192 @@ +/* h316_imp.c- BBN ARPAnet IMP/TIP Specific Hardware + Based on the SIMH simulator package written by Robert M Supnik. + + Copyright (c) 2013 Robert Armstrong, bob@jfcl.com. + + 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 + ROBERT ARMSTRONG 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 Robert Armstrong shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert Armstrong. + + tks task switch device + mlc multiline controller (aka TIP) + + 21-May-13 RLA New file + + OVERVIEW + + This module implements the IMP pseudo device - this hack takes care of two + custom devices in the IMP hardware - device 041, which implements task + switching and the RDIMPN instruction, and device 42, which implements the + AMIMLC ("am I a multiline controller") instruction. This module also contains + a few miscellaneous routines which are used by the IMP support in general. + + IMP state is maintained in a set of state variables: + + MLC always zero (TIP flag) + IEN task interrupt enabled + IRQ task interrupt pending + + TODO +*/ +#ifdef VM_IMPTIP +#include "h316_defs.h" // H316 emulator definitions +#include "h316_imp.h" // ARPAnet IMP/TIP definitions + +// Locals ... +uint16 imp_station = IMP_STATION; // IMP number (or address) +uint16 imp_ismlc = 0; // 1 for MLC (not yet implemented!) + +// Externals from other parts of simh ... +extern uint16 dev_ext_int, dev_ext_enb; // current IRQ and IEN bit vectors +extern int32 PC; // current PC (for debug messages) +extern int32 stop_inst; // needed by IOBADFNC() + +// Forward declarations ... +int32 imp_io (int32 inst, int32 fnc, int32 dat, int32 dev); +t_stat imp_service (UNIT *uptr); +t_stat imp_reset (DEVICE *dptr); +t_stat imp_show_station (FILE *st, UNIT *uptr, int32 val, void *dp); +t_stat io_show_int (FILE *st, UNIT *uptr, int32 val, void *dp); +t_stat imp_set_station (UNIT *uptr, int32 val, char *cptr, void *dp); +t_stat io_set_int (UNIT *uptr, int32 val, char *cptr, void *dp); + + + +//////////////////////////////////////////////////////////////////////////////// +////////////////////// D A T A S T R U C T U R E S ////////////////////// +//////////////////////////////////////////////////////////////////////////////// + +// IMP device information block ... +DIB imp_dib = { IMP, 2, IOBUS, IOBUS, INT_V_TASK, INT_V_NONE, &imp_io, 0 }; + +// IMP unit data (we have only one!) ... +UNIT imp_unit = { UDATA (&imp_service, 0, 0) }; + +// IMP device registers (for "EXAMINE IMP STATE") ... +REG imp_reg[] = { + { FLDATA (MLC, imp_ismlc, 0), REG_RO }, + { FLDATA (IEN, dev_ext_enb, INT_V_TASK-INT_V_EXTD) }, + { FLDATA (IRQ, dev_ext_int, INT_V_TASK-INT_V_EXTD) }, + { NULL } +}; + +// IMP device modifiers (for "SET/SHOW IMP xxx") ... +MTAB imp_mod[] = { + { MTAB_XTD|MTAB_VDV, 0, "NUM", "NUM", &imp_set_station, &imp_show_station, NULL }, + { 0 } +}; + +// IMP debugging flags (for "SET IMP DEBUG=xxx") ... +DEBTAB imp_debug[] = { + {"WARN", IMP_DBG_WARN}, + {"IO", IMP_DBG_IOT}, + {0} +}; + +// And finally tie it all together ... +DEVICE imp_dev = { + "IMP", &imp_unit, imp_reg, imp_mod, + 1, 0, 0, 0, 0, 0, + NULL, NULL, &imp_reset, NULL, NULL, NULL, + &imp_dib, DEV_DIS|DEV_DISABLE|DEV_DEBUG, 0, imp_debug, NULL, NULL +}; + + + +//////////////////////////////////////////////////////////////////////////////// +////////// I M P I / O A N D S E R V I C E R O U T I N E S ////////// +//////////////////////////////////////////////////////////////////////////////// + +// Set and clear the TASK IRQ and IEN ... +#define SET_TASK_IRQ() SET_EXT_INT((1u << (imp_dib.inum - INT_V_EXTD))) +#define CLR_TASK_IRQ() CLR_EXT_INT((1u << (imp_dib.inum - INT_V_EXTD))) +#define CLR_TASK_IEN() CLR_EXT_ENB((1u << (imp_dib.inum - INT_V_EXTD))) + +// IMP I/O routine ... +int32 imp_io (int32 inst, int32 fnc, int32 dat, int32 dev) +{ + if (dev == IMP) { + if ((inst == ioOCP) && (fnc == 000)) { + // TASK - just set the task interrupt request bit ... + sim_debug(IMP_DBG_IOT, &imp_dev, "request task interrupt (PC=%06o)\n", PC-1); + SET_TASK_IRQ(); return dat; + } else if ((inst == ioINA) && ((fnc == 010) || (fnc == 000))) { + // RDIMPN - return the IMP address and always skip ... + sim_debug(IMP_DBG_IOT, &imp_dev, "read address (PC=%06o)\n", PC-1); + return IOSKIP(imp_station); + } + } else if (dev == IMP+1) { + if ((inst == ioSKS) && (fnc == 000)) { + // AMIMLC - skip if this machine is an MLC ... + sim_debug(IMP_DBG_IOT, &imp_dev, "skip on MLC (PC=%06o %s)\n", PC-1, imp_ismlc ? "SKIP" : "NOSKIP"); + if (imp_ismlc != 0) return IOSKIP(dat); else return dat; + } + } + + // Anything else is an error... + sim_debug(IMP_DBG_WARN, &imp_dev, "UNIMPLEMENTED I/O (PC=%06o, instruction=%o, function=%02o)\n", PC-1, inst, fnc); + return IOBADFNC(dat); +} + +// Unit service ... +t_stat imp_service (UNIT *uptr) +{ + return SCPE_OK; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/////////////// D E V I C E A C T I O N C O M M A N D S //////////////// +//////////////////////////////////////////////////////////////////////////////// + +// Reset routine ... +t_stat imp_reset (DEVICE *dptr) +{ + // The simh RESET command clears both the interrupt request and enable... + CLR_TASK_IRQ(); CLR_TASK_IEN(); + return SCPE_OK; +} + + + +//////////////////////////////////////////////////////////////////////////////// +///////// D E V I C E S E T A N D S H O W C O M M A N D S ////////// +//////////////////////////////////////////////////////////////////////////////// + +// Show the station number ... +t_stat imp_show_station (FILE *st, UNIT *uptr, int32 val, void *desc) +{ + fprintf(st,"station=%d", imp_station); + return SCPE_OK; +} + +// Set the station number ... +t_stat imp_set_station (UNIT *uptr, int32 val, char *cptr, void *dp) +{ + uint32 newnum; t_stat sts; + if (cptr == NULL) return SCPE_ARG; + newnum = get_uint (cptr, 10, 9999, &sts); + if (newnum == 0) return SCPE_ARG; + imp_station = newnum; + return SCPE_OK; +} + +#endif // #ifdef VM_IMPTIP from the very top diff --git a/H316/h316_imp.h b/H316/h316_imp.h new file mode 100644 index 00000000..78e37a66 --- /dev/null +++ b/H316/h316_imp.h @@ -0,0 +1,199 @@ +/* h316_imp.h- BBN ARPAnet IMP/TIP Definitions + + Copyright (c) 2013, Robert Armstrong, bob@jfcl.com + + 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 + ROBERT ARMSTRONG 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 Robert Armstrong shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert Armstrong. + + 21-May-13 RLA New file. +*/ +#ifdef VM_IMPTIP +#ifndef H316_IMP_H_ +#define H316_IMP_H_ 0 +#include "sim_defs.h" + +// Common modem and host parameters ... +#define MI_NUM 5 // number of modem interfaces +#define HI_NUM 4 // number of host interfaces +#define MI_MAX_MSG 256 // longest possible modem message (words!) +#define HI_MAX_MSG 256 // longest possible host message (words!) +#define MI_RXPOLL 100 // RX polling delay for UDP messages +#define MI_TXBPS 56000UL // default TX speed (bits per second) +#define HI_POLL_DELAY 1000 // polling delay for messages + +// Modem interface, line #1 ... +#define MI1 071 // IO address for modem interface #1 +#define MI1_RX_DMC (DMC1-1+ 1) // DMC channel for modem 1 receive +#define MI1_TX_DMC (DMC1-1+ 6) // DMC channel for modem 1 transmit +#define INT_V_MI1RX (INT_V_EXTD+15) // modem 1 receive interrupt +#define INT_V_MI1TX (INT_V_EXTD+10) // modem 1 transmit interrupt + +// Modem interface, line #2 ... +#define MI2 072 // IO address for modem interface #2 +#define MI2_RX_DMC (DMC1-1+ 2) // DMC channel for modem 2 receive +#define MI2_TX_DMC (DMC1-1+ 7) // DMC channel for modem 2 transmit +#define INT_V_MI2RX (INT_V_EXTD+14) // modem 2 receive interrupt +#define INT_V_MI2TX (INT_V_EXTD+ 9) // modem 2 transmit interrupt + +// Modem interface, line #3 ... +#define MI3 073 // IO address for modem interface #3 +#define MI3_RX_DMC (DMC1-1+ 3) // DMC channel for modem 3 receive +#define MI3_TX_DMC (DMC1-1+ 8) // DMC channel for modem 3 transmit +#define INT_V_MI3RX (INT_V_EXTD+13) // modem 3 receive interrupt +#define INT_V_MI3TX (INT_V_EXTD+ 8) // modem 3 transmit interrupt + +// Modem interface, line #4 ... +#define MI4 074 // IO address for modem interface #4 +#define MI4_RX_DMC (DMC1-1+ 4) // DMC channel for modem 4 receive +#define MI4_TX_DMC (DMC1-1+ 9) // DMC channel for modem 4 transmit +#define INT_V_MI4RX (INT_V_EXTD+12) // modem 4 receive interrupt +#define INT_V_MI4TX (INT_V_EXTD+ 7) // modem 4 transmit interrupt + +// Modem interface, line #5 ... +#define MI5 075 // IO address for modem interface #5 +#define MI5_RX_DMC (DMC1-1+ 5) // DMC channel for modem 5 receive +#define MI5_TX_DMC (DMC1-1+10) // DMC channel for modem 5 transmit +#define INT_V_MI5RX (INT_V_EXTD+11) // modem 5 receive interrupt +#define INT_V_MI5TX (INT_V_EXTD+ 6) // modem 5 transmit interrupt + +// Host interface, line #1 ... +#define HI1 070 // device address for host interface #1 +#define HI1_RX_DMC (DMC1+13-1) // DMC channel for host 1 receive +#define HI1_TX_DMC (DMC1+11-1) // DMC channel for host 1 transmit +#define INT_V_HI1RX (INT_V_EXTD+ 3) // host 1 receive interrupt +#define INT_V_HI1TX (INT_V_EXTD+ 5) // host 1 transmit interrupt + +// Host interface, line #2 ... +#define HI2 060 // device address for host interface #2 +#define HI2_RX_DMC (DMC1-1+14) // DMC channel for host 2 receive +#define HI2_TX_DMC (DMC1-1+12) // DMC channel for host 2 transmit +#define INT_V_HI2RX (INT_V_EXTD+ 2) // host 2 receive interrupt +#define INT_V_HI2TX (INT_V_EXTD+ 4) // host 2 transmit interrupt + +// Host interface, line #3 ... +#define HI3 051 // device address for host interface #3 +#define HI3_RX_DMC (DMC1-1+16) // DMC channel for host 3 receive +#define HI3_TX_DMC (DMC1-1+15) // DMC channel for host 3 transmit +#define INT_V_HI3RX (INT_V_EXTD+ 6) // host 3 receive interrupt +#define INT_V_HI3TX (INT_V_EXTD+11) // host 3 transmit interrupt + +// Host interface, line #4 ... +#define HI4 050 // device address for host interface #4 +#define HI4_RX_DMC (DMC1-1+10) // DMC channel for host 4 receive +#define HI4_TX_DMC (DMC1-1+ 5) // DMC channel for host 4 transmit +#define INT_V_HI4RX (INT_V_EXTD+ 7) // host 4 receive interrupt +#define INT_V_HI4TX (INT_V_EXTD+12) // host 4 transmit interrupt + +// IMP defaults ... +#define IMP 041 // IMP device IO address (41 & 42 actually!) +#define INT_V_TASK (INT_V_EXTD+ 0) // task switch interrupt number +#define IMP_STATION 1 // default station number + +// RTC defaults ... +#define RTC 040 // real time clock IO address +#define INT_V_RTC (INT_V_EXTD+ 1) // RTC interrupt number +#define RTC_INTERVAL 20UL // default RTC interval (20us == 50kHz) +#define RTC_QUANTUM 32UL // default RTC quantum (32 ticks) + +// WDT defaults ... +#define WDT 026 // watchdog timer IO address +#define WDT_VECTOR 000062 // WDT timeout vector +#define WDT_DELAY 0 // default WDT timeout (in milliseconds) + +// Debugging flags ... +// In general, these bits are used as arguments for sim_debug(). Bits that +// begin with "IMP_DBG_xyz" are shared by more than one device (e.g. IMP_DBG_UDP) +// and must have unique bit assignments. Bits prefixed with a device name (e.g. +// "MI_DBG_xyz") apply to that device only. +#define IMP_DBG_WARN 0x0001 // all: print warnings +#define IMP_DBG_IOT 0x0002 // all: trace all program I/O instructions +#define IMP_DBG_UDP 0x0004 // all: trace UDP packets +#define MI_DBG_MSG 0x8000 // modem: decode and print all messages +#define WDT_DBG_LIGHTS 0x8000 // wdt: show status light changes + +// Synonyms for DIB and UNIT fields ... +#define rxdmc chan // dib->rxdmc +#define txdmc chan2 // dib->txdmc +#define rxint inum // dib->rxint +#define txint inum2 // dib->txint + +// Modem interface data block .... +// One of these is allocated to every modem interface to keep track of the +// current state, COM port, UDP connection , etc... +struct _MIDB { + // Receiver data ... + t_bool rxpending; // TRUE if a read is pending on this line + t_bool rxerror; // TRUE if any modem error detected + uint32 rxtotal; // total number of H316 words received + // Transmitter data ... + uint32 txtotal; // total number of H316 words transmitted + uint32 txdelay; // RTC ticks until TX done interrupt + // Other data ... + t_bool lloop; // line loop back enabled + t_bool iloop; // interface loop back enabled + int32 link; // h316_udp link number + uint32 bps; // simulated line speed or COM port baud rate +}; +typedef struct _MIDB MIDB; + +// Host interface data block ... +// One of these is allocated to every host interface ... +struct _HIDB { + // Receiver (HOST -> IMP) data ... + uint32 rxtotal; // total host messages received + // Transmitter (IMP -> HOST) data ... + uint32 txtotal; // total host messages sent + // Other data ... + t_bool lloop; // local loop back enabled + t_bool enabled; // TRUE if the host is enabled + t_bool error; // TRUE for any host error + t_bool ready; // TRUE if the host is ready + t_bool full; // TRUE if the host buffer is full + t_bool eom; // TRUE when end of message is reached +}; +typedef struct _HIDB HIDB; + +// I can't believe Bob managed to live without these, but I can't! +#ifndef LOBYTE // these are in winsock.h too! +#define LOBYTE(x) ((uint8) ( (x) & 0xFF)) +#define HIBYTE(x) ((uint8) (((x) >> 8) & 0xFF)) +#define MKWORD(h,l) ((uint16) ( (((h)&0xFF) << 8) | ((l)&0xFF) )) +#define LOWORD(x) ((uint16) ( (x) & 0xFFFF)) +#define HIWORD(x) ((uint16) (((x) >> 16) & 0xFFFF)) +#define MKLONG(h,l) ((uint32) ( (((h)&0xFFFF) << 16) | ((l)&0xFFFF) )) +#endif + +// Prototypes for the RTC module ... +// I really hate sharing things like this, but it's the only way to get the +// modem transmitter timing exactly right! +extern uint32 rtc_interval; +extern t_stat mi_tx_service (uint32 quantum); + +// Prototypes for UDP modem/host interface emulation routines ... +#define NOLINK (-1) +t_stat udp_create (DEVICE *pdtr, char *premote, int32 *plink); +t_stat udp_release (DEVICE *dptr, int32 link); +t_stat udp_send (DEVICE *pdtr, int32 link, uint16 *pdata, uint16 count); +t_stat udp_set_link_loopback (DEVICE *dptr, int32 link, t_bool enable_loopback); +int32 udp_receive (DEVICE *dptr, int32 link, uint16 *pdata, uint16 maxbufg); + +#endif // #ifndef _H316_IMP_H_ +#endif // #ifdef VM_IMPTIP diff --git a/H316/h316_lp.c b/H316/h316_lp.c index 46151911..6f97d85c 100644 --- a/H316/h316_lp.c +++ b/H316/h316_lp.c @@ -1,6 +1,6 @@ /* h316_lp.c: Honeywell 316/516 line printer - Copyright (c) 1999-2008, Robert M. Supnik + Copyright (c) 1999-2015, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,7 @@ lpt line printer + 03-Jul-13 RLA compatibility changes for extended interrupts 09-Jun-07 RMS Fixed lost last print line (Theo Engel) 19-Jan-06 RMS Added UNIT_TEXT flag 03-Apr-06 RMS Fixed bug in blanks backscanning (Theo Engel) @@ -105,7 +106,7 @@ t_stat lpt_reset (DEVICE *dptr); lpt_reg LPT register list */ -DIB lpt_dib = { LPT, IOBUS, 1, &lptio }; +DIB lpt_dib = { LPT, 1, IOBUS, IOBUS, INT_V_LPT, INT_V_NONE, &lptio, 0 }; UNIT lpt_unit = { UDATA (&lpt_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_TEXT, 0) }; diff --git a/H316/h316_mi.c b/H316/h316_mi.c new file mode 100644 index 00000000..ae4371f4 --- /dev/null +++ b/H316/h316_mi.c @@ -0,0 +1,766 @@ +/* h316_mi.c- BBN ARPAnet IMP/TIP Modem Interface + Based on the SIMH simulator package written by Robert M Supnik. + + Copyright (c) 2013 Robert Armstrong, bob@jfcl.com. + + 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 + ROBERT ARMSTRONG 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 Robert Armstrong shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert Armstrong. + + + REVISION HISTORY + + mi modem interface + + 21-May-13 RLA New file + + + OVERVIEW + + The modem interface is one of the BBN engineered devices unique to the + ARPAnet IMP/TIP. The original hardware was a full duplex synchronous serial + line interface operating at 56k bps. The hardware was fairly smart and was + able to handle line synchronization (SYN), packet start (STX) and end (ETX), + and data escape (DLE) autonomously. Data is transferred directly to and + from H316 main memory using the DMC mechanism. The modem interface also + calculated a 24 bit "parity" (and by that I assume they meant some form of + CRC) value. This was automatically appended to the end of the transmitted + data and automatically verified by the receiving modem. + + CONNECTIONS + + This module provides two basic options for emulating the modem. Option 1 + takes the data packets from H316 memory, wraps them in a UDP packet, and + sends them to another simh instance. The remote simh then unwraps the data + packet and loads it directly into H316 memory. In this instance, + synchronization, start of text/end of text, and data escapes are pointless + and are not used. The words are simply moved verbatim from one H316 to + another. + + The other option is to logically connect the emulated modem to a physical + serial port on this PC. In that case we attempt to emulate the actions + of the original modem as closely as possible, including the synchronization, + start of text/end of text and data escape characters. Synchronization is + pointless on an asynchronous interface, of course, but we do it anyway in + the interest of compatability. We also attempt to calculate a 24 bit CRC + using (as best I can determine) the same algorithm as the original modems. + + MULTIPLE INSTANCES + + Each IMP can support up to five modem lines, and fitting this into simh + presents an architectural problem. The temptation is to treat all modems as + one device with multiple units (each unit corresponding to one line), but + that's a problem. The simh view of units is like a disk or tape - there's + a single controller that has one IO address, one interrupt and one DMA/DMC + channel. That controller then has multiple units attached to it that are + selected by bits in a controller register and all units share the same + IO, interrupt and DMA/DMC assignments. + + The modems aren't like that at all - each of the five cards is completely + independent with its own distinct IO address, interrupt and DMC assignments. + It's analagous to five instances of the same controller installed in the + machine, but simh unfortunately has limited support for multiple instances + of the same controller. The few instances of prior art in simh that I can + find (e.g. xq, xqb on the PDP11/VAX) have just been done ad hoc by + duplicating all the device data. Rather than rewrite simh, that's the + approach I took here, even though with five instances it gets awkward. + + POLLING AND SERVICE + + The IMP software turns out to be extraordinarily sensitive to modem timing. + It actually goes to the trouble of measuring the effective line speed by + using the RTC to time how long it takes to send a message, and one thing that + especially annoys the IMP are variations in the effective line speed. They + had a lot of trouble with AT&T Long Lines back in the Old Days, and the IMP + has quite a bit of code to monitor line quality. Even fairly minor variations + in speed will cause it to mark the line as "down" and sent a trouble report + back to BBN. + + To combat this, we actually let the RTC code time the transmitter interrupts. + When the IMP software does a "start modem output" OCP the entire packet will + be extracted from H316 memory and transmitted via UDP at that instant, BUT + the transmitter done interrupt will be deferred. The delay is computed from + the length of the packet and the simulated line speed, and then the RTC is + used to count down the interval. When the time expires, the interrupt request + is generated. It's unfortunate to have to couple the RTC and the modem in + this way, but since the IMP code is using the RTC to measure the line speed + AND since the RTC determines when the transmit done occurs, it guarantees + that the IMP always sees exactly the same delay. + + The modem receiver is completely independent of the transmitter and is polled + by the usual simh event queue mechanism and mi_service() routine. When the + IMP code executes a "start modem input" OCP a read pending flag is set in the + modem status but nothing else occurs. Each poll checks the UDP socket for + incoming data and, if a packet was received AND a read operation is pending, + then the read completes that moment and the interrupt request is asserted. + The UDP socket is polled regardless of whether a read is pending and if data + arrives without a read then it's discarded. That's exactly what a real modem + would do. + + ERROR HANDLING + + Transmitter error handling is easy - fatal errors print a message and abort + the simulation, but any other errors are simply ignored. The IMP modems had + no kind of error dection on the transmitter side and no way to report them + anyway so we do the same. Any data packet associated with the error is just + discarded. In particular with both UDP and COM ports there's no way to tell + whether anybody is on the other end listening, so even packets that are + successfully transmitted may disappear into the ether. This isn't a problem + for the IMP - the real world was like that too and the IMP is able to handle + retransmitting packets without our help. + + Receiver errors set the error flag in the modem status; this flag can be + tested and cleared by the "skip on modem error" SKS instruction. The only + receiver error that can be detected is buffer overrun (i.e. the sender's + message was longer than the receiver's buffer). With a serial connection + checksum errors are also possible, but those never occur with UDP. + + Transmitting or receiving on a modem that's not attached isn't an error - it + simply does nothing. It's analogous to a modem with the phone line unplugged. + Hard I/O errors for UDP or COM ports print an error message and then detach + the modem connection. It's up to the user to interrupt the simulation and + reattach if he wants to try again. + + STATE + + Modem state is maintained in the following variables - + + RXPOLL 24 receiver polling interval + RXPEND 1 an input operation is pending + RXERR 1 receiver error flag + RXIEN 1 receiver interrupt enable + RXIRQ 1 receiver interrupt request + RXTOT 32 count of total messages received + TXDLY 32 RTC ticks until TX done interrupt + TXIEN 1 transmitter interrupt enable + TXIRQ 1 transmitter interrupt request + TXTOT 32 count of total messages transmitted + LINKNO 32 link number for h316_udp module + BPS 32 simulated bps for UDP delay calculations + actual baud rate for physical COM ports + ILOOP 1 interface (local) loopback enabled + RLOOP 1 remote (line) loopback enabled + + Most of these values will be found in the Modem Information Data Block (aka + "MIDB") but a few are stored elsewhere (e.g. IRQ/IEN are in the CPU's dev_int + and dev_enb vectors). + + TODO + + Implement checksum handling + Implement remote loopback +*/ +#ifdef VM_IMPTIP +#include "h316_defs.h" // H316 emulator definitions +#include "h316_imp.h" // ARPAnet IMP/TIP definitions + +// Externals from other parts of simh ... +extern uint16 dev_ext_int, dev_ext_enb; // current IRQ and IEN bit vectors +extern int32 PC; // current PC (for debug messages) +extern int32 stop_inst; // needed by IOBADFNC() +extern uint16 M[]; // main memory (for DMC access) + +// Forward declarations ... +int32 mi_io (uint16 line, int32 inst, int32 fnc, int32 dat, int32 dev); +int32 mi1_io (int32 inst, int32 fnc, int32 dat, int32 dev); +int32 mi2_io (int32 inst, int32 fnc, int32 dat, int32 dev); +int32 mi3_io (int32 inst, int32 fnc, int32 dat, int32 dev); +int32 mi4_io (int32 inst, int32 fnc, int32 dat, int32 dev); +int32 mi5_io (int32 inst, int32 fnc, int32 dat, int32 dev); +t_stat mi_rx_service (UNIT *uptr); +void mi_rx_local (uint16 line, uint16 txnext, uint16 txcount); +t_stat mi_reset (DEVICE *dptr); +t_stat mi_attach (UNIT *uptr, char *cptr); +t_stat mi_detach (UNIT *uptr); +t_stat mi_set_loopback (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat mi_show_loopback (FILE *st, UNIT *uptr, int32 val, void *desc); + + + +//////////////////////////////////////////////////////////////////////////////// +////////////////////// D A T A S T R U C T U R E S ////////////////////// +//////////////////////////////////////////////////////////////////////////////// + +// simh requires several data structures for every device - a DIB, one or more +// UNITS, a modifier table, a register list, and a device definition. The sit- +// uation here is even more complicated because we have five identical modems to +// define, and so lots of clever macros are used to handle the repetition and +// save some typing. + +// Modem Information Data Blocks ... +// The MIDB is our own internal data structure for each modem. It keeps data +// about the current state, COM port, UDP connection, etc. +#define MI_MIDB(N) {FALSE, FALSE, 0, 0, 0, FALSE, FALSE, NOLINK, MI_TXBPS} +MIDB mi1_db = MI_MIDB(1), mi2_db = MI_MIDB(2); +MIDB mi3_db = MI_MIDB(3), mi4_db = MI_MIDB(4); +MIDB mi5_db = MI_MIDB(5); + +// Modem Device Information Blocks ... +// The DIB is the structure simh uses to keep track of the device IO address +// and IO service routine. It can also hold the DMC channel, but we don't use +// that because it's unit specific. +#define MI_DIB(N) {MI##N, 1, MI##N##_RX_DMC, MI##N##_TX_DMC, \ + INT_V_MI##N##RX, INT_V_MI##N##TX, &mi##N##_io, N} +DIB mi1_dib = MI_DIB(1), mi2_dib = MI_DIB(2); +DIB mi3_dib = MI_DIB(3), mi4_dib = MI_DIB(4); +DIB mi5_dib = MI_DIB(5); + +// Modem Device Unit data ... +// simh uses the unit data block primarily to schedule device service events. +#define mline u3 // our modem line number is stored in user data 3 +#define MI_UNIT(N) {UDATA (&mi_rx_service, UNIT_ATTABLE, 0), MI_RXPOLL, N, 0, 0, 0} +UNIT mi1_unit = MI_UNIT(1), mi2_unit = MI_UNIT(2); +UNIT mi3_unit = MI_UNIT(3), mi4_unit = MI_UNIT(4); +UNIT mi5_unit = MI_UNIT(5); + +// Modem Device Registers ... +// These are the simh device "registers" - they c can be viewed with the +// "EXAMINE MIn STATE" command and modified by "DEPOSIT MIn ..." +#define MI_REG(N) { \ + { DRDATA (RXPOLL, mi##N##_unit.wait, 24), REG_NZ + PV_LEFT }, \ + { FLDATA (RXPEND, mi##N##_db.rxpending, 0), REG_RO + PV_RZRO }, \ + { FLDATA (RXERR, mi##N##_db.rxerror, 0), PV_RZRO }, \ + { FLDATA (RXIEN, dev_ext_enb, INT_V_MI##N##RX-INT_V_EXTD) }, \ + { FLDATA (RXIRQ, dev_ext_int, INT_V_MI##N##RX-INT_V_EXTD) }, \ + { DRDATA (RXTOT, mi##N##_db.rxtotal, 32), REG_RO + PV_LEFT }, \ + { DRDATA (TXDLY, mi##N##_db.txdelay, 32), PV_LEFT }, \ + { FLDATA (TXIEN, dev_ext_enb, INT_V_MI##N##TX-INT_V_EXTD) }, \ + { FLDATA (TXIRQ, dev_ext_int, INT_V_MI##N##TX-INT_V_EXTD) }, \ + { DRDATA (TXTOT, mi##N##_db.txtotal, 32), REG_RO + PV_LEFT }, \ + { DRDATA (LINK, mi##N##_db.link, 32), REG_RO + PV_LEFT }, \ + { DRDATA (BPS, mi##N##_db.bps, 32), REG_NZ + PV_LEFT }, \ + { FLDATA (LLOOP, mi##N##_db.lloop, 0), REG_RO + PV_RZRO }, \ + { FLDATA (ILOOP, mi##N##_db.iloop, 0), REG_RO + PV_RZRO }, \ + { NULL } \ +} +REG mi1_reg[] = MI_REG(1), mi2_reg[] = MI_REG(2); +REG mi3_reg[] = MI_REG(3), mi4_reg[] = MI_REG(4); +REG mi5_reg[] = MI_REG(5); + +// Modem Device Modifiers ... +// These are the modifiers simh uses for the "SET MIn" and "SHOW MIn" commands. +#define MI_MOD(N) { \ + { MTAB_XTD|MTAB_VDV, 0, "LOOPBACK", "LOOPINTERFACE", &mi_set_loopback, &mi_show_loopback, NULL }, \ + { MTAB_XTD|MTAB_VDV, 1, NULL, "NOLOOPINTERFACE", &mi_set_loopback, NULL, NULL }, \ + { MTAB_XTD|MTAB_VDV, 2, NULL, "LOOPLINE", &mi_set_loopback, NULL, NULL }, \ + { MTAB_XTD|MTAB_VDV, 3, NULL, "NOLOOPLINE", &mi_set_loopback, NULL, NULL }, \ + { 0 } \ +} +MTAB mi1_mod[] = MI_MOD(1), mi2_mod[] = MI_MOD(2); +MTAB mi3_mod[] = MI_MOD(3), mi4_mod[] = MI_MOD(4); +MTAB mi5_mod[] = MI_MOD(5); + +// Debug modifiers for "SET MIn DEBUG = xxx" ... +DEBTAB mi_debug[] = { + {"WARN", IMP_DBG_WARN}, // print warnings that would otherwise be suppressed + {"UDP", IMP_DBG_UDP}, // print all UDP messages sent and received + {"IO", IMP_DBG_IOT}, // print all program I/O instructions + {"MSG", MI_DBG_MSG}, // decode and print all messages + {0} +}; + +// Modem Device data ... +// This is the primary simh structure that defines each device - it gives the +// plain text name, the addresses of the unit, register and modifier tables, and +// the addresses of all action routines (e.g. attach, reset, etc). +#define MI_DEV(MI,N,F) { \ + #MI, &mi##N##_unit, mi##N##_reg, mi##N##_mod, \ + 1, 10, 31, 1, 8, 8, \ + NULL, NULL, &mi_reset, NULL, &mi_attach, &mi_detach, \ + &mi##N##_dib, DEV_DISABLE|DEV_DEBUG|(F), 0, mi_debug, NULL, NULL \ +} +DEVICE mi1_dev = MI_DEV(MI1,1,DEV_DIS), mi2_dev = MI_DEV(MI2,2,DEV_DIS); +DEVICE mi3_dev = MI_DEV(MI3,3,DEV_DIS), mi4_dev = MI_DEV(MI4,4,DEV_DIS); +DEVICE mi5_dev = MI_DEV(MI5,5,DEV_DIS); + +// Modem Tables ... +// These tables make it easy to locate the data associated with any line. +DEVICE *const mi_devices[MI_NUM] = {&mi1_dev, &mi2_dev, &mi3_dev, &mi4_dev, &mi5_dev }; +UNIT *const mi_units [MI_NUM] = {&mi1_unit, &mi2_unit, &mi3_unit, &mi4_unit, &mi5_unit}; +DIB *const mi_dibs [MI_NUM] = {&mi1_dib, &mi2_dib, &mi3_dib, &mi4_dib, &mi5_dib }; +MIDB *const mi_midbs [MI_NUM] = {&mi1_db, &mi2_db, &mi3_db, &mi4_db, &mi5_db }; + + + +//////////////////////////////////////////////////////////////////////////////// +////////////////// L O W L E V E L F U N C T I O N S /////////////////// +//////////////////////////////////////////////////////////////////////////////// + +// Find a pointer to the DEVICE, UNIT, DIB or MIDB given the line number ... +#define PDEVICE(l) mi_devices[(l)-1] +#define PUNIT(l) mi_units[(l)-1] +#define PDIB(l) mi_dibs[(l)-1] +#define PMIDB(l) mi_midbs[(l)-1] + +// These macros set and clear the interrupt request and enable flags ... +#define SET_RX_IRQ(l) SET_EXT_INT((1u << (PDIB(l)->rxint - INT_V_EXTD))) +#define SET_TX_IRQ(l) SET_EXT_INT((1u << (PDIB(l)->txint - INT_V_EXTD))) +#define CLR_RX_IRQ(l) CLR_EXT_INT((1u << (PDIB(l)->rxint - INT_V_EXTD))) +#define CLR_TX_IRQ(l) CLR_EXT_INT((1u << (PDIB(l)->txint - INT_V_EXTD))) +#define CLR_RX_IEN(l) CLR_EXT_ENB((1u << (PDIB(l)->rxint - INT_V_EXTD))) +#define CLR_TX_IEN(l) CLR_EXT_ENB((1u << (PDIB(l)->txint - INT_V_EXTD))) + +// TRUE if the line has the specified debugging output enabled ... +#define ISLDBG(l,f) ((PDEVICE(l)->dctrl & (f)) != 0) + +// Reset receiver (clear flags AND initialize all data) ... +void mi_reset_rx (uint16 line) +{ + PMIDB(line)->iloop = PMIDB(line)->lloop = FALSE; + udp_set_link_loopback (PDEVICE(line), PMIDB(line)->link, FALSE); + PMIDB(line)->rxerror = PMIDB(line)->rxpending = FALSE; + PMIDB(line)->rxtotal = 0; + CLR_RX_IRQ(line); CLR_RX_IEN(line); +} + +// Reset transmitter (clear flags AND initialize all data) ... +void mi_reset_tx (uint16 line) +{ + PMIDB(line)->iloop = PMIDB(line)->lloop = FALSE; + udp_set_link_loopback (PDEVICE(line), PMIDB(line)->link, FALSE); + PMIDB(line)->txtotal = PMIDB(line)->txdelay = 0; + CLR_TX_IRQ(line); CLR_TX_IEN(line); +} + +// Get the DMC control words (starting address, end and length) for the channel. +void mi_get_dmc (uint16 dmc, uint16 *pnext, uint16 *plast, uint16 *pcount) +{ + uint16 dmcad; + if ((dmc(DMC1+DMC_MAX-1))) { + *pnext = *plast = *pcount = 0; return; + } + dmcad = DMC_BASE + (dmc-DMC1)*2; + *pnext = M[dmcad] & X_AMASK; *plast = M[dmcad+1] & X_AMASK; + *pcount = (*plast - *pnext + 1) & DMASK; +} + +// Update the DMC words to show "count" words transferred. +void mi_update_dmc (uint32 dmc, uint32 count) +{ + uint16 dmcad, next; + if ((dmc(DMC1+DMC_MAX-1))) return; + dmcad = DMC_BASE + (dmc-DMC1)*2; + next = M[dmcad]; + M[dmcad] = (next & DMA_IN) | ((next+count) & X_AMASK); +} + +// Link error recovery ... +void mi_link_error (uint16 line) +{ + // Any physical I/O error, either for the UDP link or a COM port, prints a + // message and detaches the modem. It's up to the user to decide what to do + // after that... + fprintf(stderr,"MI%d - UNRECOVERABLE I/O ERROR!\n", line); + mi_reset_rx(line); mi_reset_tx(line); + sim_cancel(PUNIT(line)); mi_detach(PUNIT(line)); + PMIDB(line)->link = NOLINK; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/////////////////// D E B U G G I N G R O U T I N E S //////////////////// +//////////////////////////////////////////////////////////////////////////////// + +// Log a modem input or output including DMC words ... +void mi_debug_mio (uint16 line, uint32 dmc, const char *ptext) +{ + uint16 next, last, count; + if (!ISLDBG(line, IMP_DBG_IOT)) return; + mi_get_dmc(dmc, &next, &last, &count); + sim_debug(IMP_DBG_IOT, PDEVICE(line), + "start %s (PC=%06o, next=%06o, last=%06o, count=%d)\n", + ptext, PC-1, next, last, count); +} + +// Log the contents of a message sent or received ... +void mi_debug_msg (uint16 line, uint16 next, uint16 count, const char *ptext) +{ + uint16 i; char buf[CBUFSIZE]; int len = 0; + if (!ISLDBG(line, MI_DBG_MSG)) return; + sim_debug(MI_DBG_MSG, PDEVICE(line), "message %s (length=%d)\n", ptext, count); + for (i = 1, len = 0; i <= count; ++i) { + len += sprintf(buf+len, "%06o ", M[next+i-1]); + if (((i & 7) == 0) || (i == count)) { + sim_debug(MI_DBG_MSG, PDEVICE(line), "- %s\n", buf); len = 0; + } + } +} + + + +//////////////////////////////////////////////////////////////////////////////// +///////////////// T R A N S M I T A N D R E C E I V E ////////////////// +//////////////////////////////////////////////////////////////////////////////// + +// Start the transmitter ... +void mi_start_tx (uint16 line) +{ + // This handles all the work of the "start modem output" OCP, including + // extracting the packet from H316 memory, EXCEPT for actually setting the + // transmit done interrupt. That's handled by the RTC polling routine after + // a delay that we calculate.. + uint16 next, last, count; uint32 nbits; t_stat ret; + + // Get the DMC words for this channel and update the next pointer as if the + // transfer actually occurred. + mi_get_dmc(PDIB(line)->txdmc, &next, &last, &count); + mi_update_dmc(PDIB(line)->txdmc, count); + mi_debug_msg (line, next, count, "sent"); + + // Transmit the data, handling both the interface loopback AND the line loop + // back flags in the process. Note that in particular the interface loop back + // does NOT require that the modem be attached! + if (PMIDB(line)->iloop) { + mi_rx_local(line, next, count); + } else if (PMIDB(line)->link != NOLINK) { + ret = udp_send(PDEVICE(line), PMIDB(line)->link, &M[next], count); + if (ret != SCPE_OK) mi_link_error(line); + } + + // Do some fancy math to figure out how long, in RTC ticks, it would actually + // take to transmit a packet of this length with a real modem and phone line. + // Note that the "+12" is an approximation for the modem overhead, including + // DLE, STX, ETX and checksum bytes, that would be added to the packet. + nbits = (((uint32) count)*2UL + 12UL) * 8UL; + PMIDB(line)->txdelay = (nbits * 1000000UL) / (PMIDB(line)->bps * rtc_interval); + //fprintf(stderr,"MI%d - transmit packet, length=%d, bits=%ld, interval=%ld, delay=%ld\n", line, count, nbits, rtc_interval, PMIDB(line)->txdelay); + + // That's it - we're done until it's time for the TX done interrupt ... + CLR_TX_IRQ(line); +} + +// Poll for transmitter done interrupts ... +void mi_poll_tx (uint16 line, uint32 quantum) +{ + // This routine is called, via the RTC service, to count down the interval + // until the transmitter finishes. When it hits zero, an interrupt occurs. + if (PMIDB(line)->txdelay == 0) return; + if (PMIDB(line)->txdelay <= quantum) { + SET_TX_IRQ(line); PMIDB(line)->txdelay = 0; PMIDB(line)->txtotal++; + sim_debug(IMP_DBG_IOT, PDEVICE(line), "transmit done (message #%d, intreq=%06o)\n", PMIDB(line)->txtotal, dev_ext_int); + } else + PMIDB(line)->txdelay -= quantum; +} + +// Start the receiver ... +void mi_start_rx (uint16 line) +{ + // "Starting" the receiver simply sets the RX pending flag. Nothing else + // needs to be done (nothing else _can_ be done!) until we actually receive + // a real packet. + + // We check for the case of another receive already pending, but I don't + // think the real hardware detected this or considered it an error condition. + if (PMIDB(line)->rxpending) { + sim_debug(IMP_DBG_WARN,PDEVICE(line),"start input while input already pending\n"); + } + PMIDB(line)->rxpending = TRUE; PMIDB(line)->rxerror = FALSE; + CLR_RX_IRQ(line); +} + +// Poll for receiver data ... +void mi_poll_rx (uint16 line) +{ + // This routine is called by mi_service to poll for any packets received. + // This is done regardless of whether a receive is pending on the line. If + // a packet is waiting AND a receive is pending then we'll store it and finish + // the receive operation. If a packet is waiting but no receive is pending + // then the packet is discarded... + uint16 next, last, maxbuf; uint16 *pdata; int16 count; + + // If the modem isn't attached, then the read never completes! + if (PMIDB(line)->link == NOLINK) return; + + // Get the DMC words for this channel, or zeros if no read is pending ... + if (PMIDB(line)->rxpending) { + mi_get_dmc(PDIB(line)->rxdmc, &next, &last, &maxbuf); + pdata = &M[next]; + } else { + next = last = maxbuf = 0; pdata = NULL; + } + // Try to read a packet. If we get nothing then just return. + count = udp_receive(PDEVICE(line), PMIDB(line)->link, pdata, maxbuf); + if (count == 0) return; + if (count < 0) {mi_link_error(line); return;} + + // Now would be a good time to worry about whether a receive is pending! + if (!PMIDB(line)->rxpending) { + sim_debug(IMP_DBG_WARN, PDEVICE(line), "data received with no input pending\n"); + return; + } + + // We really got a packet! Update the DMC pointers to reflect the actual + // size of the packet received. If the packet length would have exceeded the + // receiver buffer, then that sets the error flag too. + if (count > maxbuf) { + sim_debug(IMP_DBG_WARN, PDEVICE(line), "receiver overrun (length=%d maxbuf=%d)\n", count, maxbuf); + PMIDB(line)->rxerror = TRUE; count = maxbuf; + } + mi_update_dmc(PDIB(line)->rxdmc, count); + mi_debug_msg (line, next, count, "received"); + + // Assert the interrupt request and we're done! + SET_RX_IRQ(line); PMIDB(line)->rxpending = FALSE; PMIDB(line)->rxtotal++; + sim_debug(IMP_DBG_IOT, PDEVICE(line), "receive done (message #%d, intreq=%06o)\n", PMIDB(line)->rxtotal, dev_ext_int); +} + +// Receive cross patched data ... +void mi_rx_local (uint16 line, uint16 txnext, uint16 txcount) +{ + // This routine is invoked by the mi_start_tx() function when this modem has + // the "interface cross patch" bit set. This flag causes the modem to talk to + // to itself, and data sent by the transmitter goes directly to the receiver. + // The modem is bypassed completely and in fact need not even be connected. + // This is essentially a special case of the mi_poll_rx() routine and it's a + // shame they don't share more code, but that's the way it is. + // Get the DMC words for this channel, or zeros if no read is pending ... + uint16 rxnext, rxlast, maxbuf; + + // If no read is pending, then just throw away the data ... + if (!PMIDB(line)->rxpending) return; + + // Get the DMC words for the receiver and copy data from one buffer to the other. + mi_get_dmc(PDIB(line)->rxdmc, &rxnext, &rxlast, &maxbuf); + if (txcount > maxbuf) {txcount = maxbuf; PMIDB(line)->rxerror = TRUE;} + memmove(&M[rxnext], &M[txnext], txcount * sizeof(uint16)); + + // Update the receiver DMC pointers, assert IRQ and we're done! + mi_update_dmc(PDIB(line)->rxdmc, txcount); + mi_debug_msg (line, rxnext, txcount, "received"); + SET_RX_IRQ(line); PMIDB(line)->rxpending = FALSE; PMIDB(line)->rxtotal++; + sim_debug(IMP_DBG_IOT, PDEVICE(line), "receive done (message #%d, intreq=%06o)\n", PMIDB(line)->rxtotal, dev_ext_int); +} + + + +//////////////////////////////////////////////////////////////////////////////// +//////////// I / O I N S T R U C T I O N E M U L A T I O N ///////////// +//////////////////////////////////////////////////////////////////////////////// + +// Line specific I/O routines ... +// Unfortunately simh doesn't pass the I/O emulation routine any data about the +// device except for its device address. In particular, it doesn't pass a pointer +// to the device or unit data blocks, so we're on our own to find those. Rather +// than a search on the device address, we just provide a separate I/O routine +// for each modem line. All they do is call the common I/O routine with an extra +// parameter - problem solved! +int32 mi1_io(int32 inst, int32 fnc, int32 dat, int32 dev) {return mi_io(1, inst, fnc, dat, dev);} +int32 mi2_io(int32 inst, int32 fnc, int32 dat, int32 dev) {return mi_io(2, inst, fnc, dat, dev);} +int32 mi3_io(int32 inst, int32 fnc, int32 dat, int32 dev) {return mi_io(3, inst, fnc, dat, dev);} +int32 mi4_io(int32 inst, int32 fnc, int32 dat, int32 dev) {return mi_io(4, inst, fnc, dat, dev);} +int32 mi5_io(int32 inst, int32 fnc, int32 dat, int32 dev) {return mi_io(5, inst, fnc, dat, dev);} + +// Common I/O simulation routine ... +int32 mi_io (uint16 line, int32 inst, int32 fnc, int32 dat, int32 dev) +{ + // This routine is invoked by the CPU module whenever the code executes any + // I/O instruction (OCP, SKS, INA or OTA) with one of our modem's device + // address. + + // OCP (output control pulse) initiates various modem operations ... + if (inst == ioOCP) { + switch (fnc) { + case 000: + // MnOUT - start modem output ... + mi_debug_mio(line, PDIB(line)->txdmc, "output"); + mi_start_tx(line); return dat; + case 001: + // MnUNXP - un-cross patch modem ... + sim_debug(IMP_DBG_IOT,PDEVICE(line),"un-cross patch modem (PC=%06o)\n", PC-1); + PMIDB(line)->iloop = PMIDB(line)->lloop = FALSE; + udp_set_link_loopback (PDEVICE(line), PMIDB(line)->link, FALSE); + return dat; + case 002: + // MnLXP - enable line cross patch ... + sim_debug(IMP_DBG_IOT,PDEVICE(line),"enable line cross patch (PC=%06o)\n", PC-1); + PMIDB(line)->lloop = TRUE; + udp_set_link_loopback (PDEVICE(line), PMIDB(line)->link, TRUE); + PMIDB(line)->iloop = FALSE; return dat; + case 003: + // MnIXP - enable interface cross patch ... + sim_debug(IMP_DBG_IOT,PDEVICE(line),"enable interface cross patch (PC=%06o)\n", PC-1); + PMIDB(line)->iloop = TRUE; PMIDB(line)->lloop = FALSE; + udp_set_link_loopback (PDEVICE(line), PMIDB(line)->link, FALSE); + return dat; + case 004: + // MnIN - start modem input ... + mi_debug_mio(line, PDIB(line)->rxdmc, "input"); + mi_start_rx(line); return dat; + } + + // SKS (skip) tests various modem conditions ... + } else if (inst == ioSKS) { + switch (fnc) { + case 004: + // MnERR - skip on modem error ... + sim_debug(IMP_DBG_IOT,PDEVICE(line),"skip on error (PC=%06o, %s)\n", + PC-1, PMIDB(line)->rxerror ? "SKIP" : "NOSKIP"); + return PMIDB(line)->rxerror ? IOSKIP(dat) : dat; + // NOTE - the following skip, MnRXDONE, isn't actually part of the + // original IMP design. As far as I can tell the IMP had no way to + // explicitly poll this flags; the only way to tell when a modem finished + // was to catch the associated interrupt. I've added one for testing + // purposes, using an unimplemented SKS instruction. + case 002: + // MnRXDONE - skip on receive done ... + return PMIDB(line)->rxpending ? dat : IOSKIP(dat); + } + } + + // Anything else is an error... + sim_debug(IMP_DBG_WARN,PDEVICE(line),"UNIMPLEMENTED I/O (PC=%06o, instruction=%o, function=%02o)\n", PC-1, inst, fnc); + return IOBADFNC(dat); +} + +// Receiver service ... +t_stat mi_rx_service (UNIT *uptr) +{ + // This is the standard simh "service" routine that's called when an event + // queue entry expires. It just polls the receiver and reschedules itself. + // That's it! + uint16 line = uptr->mline; + mi_poll_rx(line); + sim_activate(uptr, uptr->wait); + return SCPE_OK; +} + +// Transmitter service ... +t_stat mi_tx_service (uint32 quantum) +{ + // This is the special transmitter service routine that's called by the RTC + // service every time the RTC is updated. This routine polls ALL the modem + // transmitters (or at least any which are active) and figures out whether it + // is time for an interrupt. + uint32 i; + for (i = 1; i <= MI_NUM; ++i) mi_poll_tx(i, quantum); + return SCPE_OK; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/////////////// D E V I C E A C T I O N C O M M A N D S //////////////// +//////////////////////////////////////////////////////////////////////////////// + +// Reset device ... +t_stat mi_reset (DEVICE *dptr) +{ + // simh calls this routine for the RESET command ... + UNIT *uptr = dptr->units; + uint16 line = uptr->mline; + + // Reset the devices AND clear the interrupt enable bits ... + mi_reset_rx(line); mi_reset_tx(line); + + // If the unit is attached, then make sure we restart polling because some + // simh commands (e.g. boot) dump the pending event queue! + sim_cancel(uptr); + if ((uptr->flags & UNIT_ATT) != 0) sim_activate(uptr, uptr->wait); + return SCPE_OK; +} + +// Attach device ... +t_stat mi_attach (UNIT *uptr, char *cptr) +{ + // simh calls this routine for (what else?) the ATTACH command. There are + // three distinct formats for ATTACH - + // + // ATTACH -p MIn COMnn - attach MIn to a physical COM port + // ATTACH MIn llll:w.x.y.z:rrrr - connect via UDP to a remote simh host + // + t_stat ret; char *pfn; uint16 line = uptr->mline; + t_bool fport = sim_switches & SWMASK('P'); + + // If we're already attached, then detach ... + if ((uptr->flags & UNIT_ATT) != 0) detach_unit(uptr); + + // The physical (COM port) attach isn't implemented yet ... + if (fport) { + fprintf(stderr,"MI%d - physical COM support is not yet implemented\n", line); + return SCPE_ARG; + } + + // Make a copy of the "file name" argument. udp_create() actually modifies + // the string buffer we give it, so we make a copy now so we'll have something + // to display in the "SHOW MIn ..." command. + pfn = (char *) calloc (CBUFSIZE, sizeof (char)); + if (pfn == NULL) return SCPE_MEM; + strncpy (pfn, cptr, CBUFSIZE); + + // Create the UDP connection. + ret = udp_create(PDEVICE(line), cptr, &(PMIDB(line)->link)); + if (ret != SCPE_OK) {free(pfn); return ret;}; + + // Reset the flags and start polling ... + uptr->flags |= UNIT_ATT; uptr->filename = pfn; + return mi_reset(find_dev_from_unit(uptr)); +} + +// Detach device ... +t_stat mi_detach (UNIT *uptr) +{ + // simh calls this routine for (you guessed it!) the DETACH command. This + // disconnects the modem from any UDP connection or COM port and effectively + // makes the modem "off line". A disconnected modem acts like a real modem + // with its phone line unplugged. + t_stat ret; uint16 line = uptr->mline; + if ((uptr->flags & UNIT_ATT) == 0) return SCPE_OK; + ret = udp_release(PDEVICE(line), PMIDB(line)->link); + if (ret != SCPE_OK) return ret; + PMIDB(line)->link = NOLINK; uptr->flags &= ~UNIT_ATT; + free (uptr->filename); uptr->filename = NULL; + return mi_reset(PDEVICE(line)); +} + +t_stat mi_set_loopback (UNIT *uptr, int32 val, char *cptr, void *desc) +{ + t_stat ret = SCPE_OK; uint16 line = uptr->mline; + + switch (val) { + case 0: // LOOPINTERFACE + case 1: // NOLOOPINTERFACE + PMIDB(line)->iloop = (val == 0) ? 1 : 0; + break; + case 2: // LOOPLINE + case 3: // NOLOOPLINE + if (PMIDB(line)->link == NOLINK) + return SCPE_UNATT; + val = (val == 2) ? 1 : 0; + ret = udp_set_link_loopback (PDEVICE(line), PMIDB(line)->link, val); + if (ret == SCPE_OK) + PMIDB(line)->lloop = val; + break; + } + return ret; +} + +t_stat mi_show_loopback (FILE *st, UNIT *uptr, int32 val, void *desc) +{ + uint16 line = uptr->mline; + + if (PMIDB(line)->iloop) + fprintf (st, "Interface (local) Loopback"); + if (PMIDB(line)->lloop) + fprintf (st, "Line (remote) Loopback"); + return SCPE_OK; +} + +#endif // #ifdef VM_IMPTIP from the very top diff --git a/H316/h316_mt.c b/H316/h316_mt.c index 125945a9..320a6ab9 100644 --- a/H316/h316_mt.c +++ b/H316/h316_mt.c @@ -25,6 +25,7 @@ mt 516-4100 seven track magnetic tape + 03-Jul-13 RLA compatibility changes for extended interrupts 19-Mar-12 RMS Fixed declaration of chan_req (Mark Pizzolato) 09-Jun-07 RMS Fixed bug in write without stop (Theo Engel) 16-Feb-06 RMS Added tape capacity checking @@ -119,7 +120,7 @@ void mt_wrwd (UNIT *uptr, uint32 dat); mt_mod MT modifier list */ -DIB mt_dib = { MT, IOBUS, MT_NUMDR, &mtio }; +DIB mt_dib = { MT, MT_NUMDR, IOBUS, IOBUS, INT_V_MT, INT_V_NONE, &mtio, 0 }; UNIT mt_unit[] = { { UDATA (&mt_svc, UNIT_ATTABLE + UNIT_ROABLE + UNIT_DISABLE, 0) }, @@ -371,17 +372,17 @@ switch (uptr->FNC) { /* case on function */ return SCPE_OK; case FNC_WEOF: /* write file mark */ - if (st = sim_tape_wrtmk (uptr)) /* write tmk, err? */ + if ((st = sim_tape_wrtmk (uptr))) /* write tmk, err? */ r = mt_map_err (uptr, st); /* map error */ break; /* sched end motion */ case FNC_FSR: /* space fwd rec */ - if (st = sim_tape_sprecf (uptr, &tbc)) /* space fwd, err? */ + if ((st = sim_tape_sprecf (uptr, &tbc))) /* space fwd, err? */ r = mt_map_err (uptr, st); /* map error */ break; /* sched end motion */ case FNC_BSR: /* space rev rec */ - if (st = sim_tape_sprecr (uptr, &tbc)) /* space rev, err? */ + if ((st = sim_tape_sprecr (uptr, &tbc))) /* space rev, err? */ r = mt_map_err (uptr, st); /* map error */ break; /* sched end motion */ @@ -455,7 +456,7 @@ switch (uptr->FNC) { /* case on function */ mt_wrwd (uptr, mt_buf); else mt_rdy = 0; /* rdy must be clr */ if (mt_ptr) { /* any data? */ - if (st = sim_tape_wrrecf (uptr, mtxb, mt_ptr)) /* write, err? */ + if ((st = sim_tape_wrrecf (uptr, mtxb, mt_ptr)))/* write, err? */ r = mt_map_err (uptr, st); /* map error */ } break; /* sched end motion */ diff --git a/H316/h316_rtc.c b/H316/h316_rtc.c new file mode 100644 index 00000000..91916ba9 --- /dev/null +++ b/H316/h316_rtc.c @@ -0,0 +1,384 @@ +/* h316_rtc.c- BBN ARPAnet IMP/TIP Real Time Clock and Watch Dog Timer + Based on the SIMH simulator package written by Robert M Supnik. + + Copyright (c) 2013 Robert Armstrong, bob@jfcl.com. + + 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 + ROBERT ARMSTRONG 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 Robert Armstrong shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert Armstrong. + + rtc real time clock + wdt watch dog timer + + 21-May-13 RLA New file + + OVERVIEW + + The IMP and TIP used a custom real time clock that was apparently created + by BBN just for those devices. The IMP/TIP RTC is NOT the same as the + official Honeywell real time clock option, H316-12. When emulating an IMP + or TIP, this RTC device must be enabled and the standard simh H316 CLK + device must be disabled. + + The IMP and TIP also had a watch dog timer which, if ever allowed to time + out, would cause a non-maskable interrupt via location 62(8) - this is the + same trap location used by the memory lockout option, which the IMP/TIP + lacked. Not much is known about the WDT, and the current implementation is + simply a place holder that doesn't do much. + + RTC state is maintained in a set of state variables: + + ENA RTC is enabled + COUNT current count + IEN RTC interrupt enabled + IRQ RTC interrupt pending + TPS effective ticks per second + WAIT simulator time until the next tick + + WDT state is maintained in a set of state variables: + + COUNT current countdown + TMO WDT timed out + LIGHTS last "set status lights" + WAIT simulator time until the next tick + + TODO + + Implement the WDT!! +*/ +#ifdef VM_IMPTIP +#include "h316_defs.h" // H316 emulator definitions +#include "h316_imp.h" // ARPAnet IMP/TIP definitions + +// Locals ... +uint32 rtc_interval = RTC_INTERVAL; // RTC tick interval (in microseconds) +uint32 rtc_quantum = RTC_QUANTUM; // RTC update interval (in ticks) +uint32 rtc_tps = 1000000UL / (RTC_INTERVAL * RTC_QUANTUM); +uint16 rtc_enabled = 1; // RTC enabled +uint32 rtc_count = 0; // current RTC count +uint32 wdt_delay = WDT_DELAY; // WDT timeout (in milliseconds, 0=none) +uint32 wdt_count = 0; // current WDT countdown +uint16 wdt_lights = 0; // last "set status lights" output + +// Externals from other parts of simh ... +extern uint16 dev_ext_int, dev_ext_enb; // current IRQ and IEN bit vectors +extern int32 PC; // current PC (for debug messages) +extern int32 stop_inst; // needed by IOBADFNC() + +// Forward declarations ... +int32 rtc_io (int32 inst, int32 fnc, int32 dat, int32 dev); +t_stat rtc_service (UNIT *uptr); +t_stat rtc_reset (DEVICE *dptr); +int32 wdt_io (int32 inst, int32 fnc, int32 dat, int32 dev); +t_stat wdt_service (UNIT *uptr); +t_stat wdt_reset (DEVICE *dptr); +t_stat rtc_set_interval (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat rtc_show_interval (FILE *st, UNIT *uptr, int32 val, void *desc); +t_stat rtc_set_quantum(UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat rtc_show_quantum (FILE *st, UNIT *uptr, int32 val, void *desc); +t_stat wdt_set_delay (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat wdt_show_delay (FILE *st, UNIT *uptr, int32 val, void *desc); + + + +//////////////////////////////////////////////////////////////////////////////// +////////////////// R T C D A T A S T R U C T U R E S ////////////////// +//////////////////////////////////////////////////////////////////////////////// + +// RTC device information block ... +DIB rtc_dib = { RTC, 1, IOBUS, IOBUS, INT_V_RTC, INT_V_NONE, &rtc_io, 0 }; + +// RTC unit data block (we have only one unit!) ... +UNIT rtc_unit = { UDATA (&rtc_service, 0, 0), (RTC_INTERVAL*RTC_QUANTUM) }; + +// RTC device registers (for "EXAMINE RTC STATE") ... +REG rtc_reg[] = { + { FLDATA (ENA, rtc_enabled, 0) }, + { DRDATA (COUNT, rtc_count, 16), PV_LEFT }, + { FLDATA (IEN, dev_ext_enb, INT_V_RTC-INT_V_EXTD) }, + { FLDATA (IRQ, dev_ext_int, INT_V_RTC-INT_V_EXTD) }, + { DRDATA (TPS, rtc_tps, 32), PV_LEFT }, + { DRDATA (WAIT, rtc_unit.wait, 24), REG_NZ + PV_LEFT }, + { NULL } +}; + +// RTC device modifiers (for "SET/SHOW RTC xxx") ... +MTAB rtc_mod[] = { + { MTAB_XTD|MTAB_VDV, 0, "INTERVAL", "INTERVAL", &rtc_set_interval, &rtc_show_interval, NULL }, + { MTAB_XTD|MTAB_VDV, 0, "QUANTUM", "QUANTUM", &rtc_set_quantum, &rtc_show_quantum, NULL }, + { 0 } +}; + +// RTC debugging flags (for "SET RTC DEBUG=xxx") ... +DEBTAB rtc_debug[] = { + {"WARN", IMP_DBG_WARN}, + {"IO", IMP_DBG_IOT}, + {0} +}; + +// And finally tie it all together ... +DEVICE rtc_dev = { + "RTC", &rtc_unit, rtc_reg, rtc_mod, + 1, 0, 0, 0, 0, 0, + NULL, NULL, &rtc_reset, NULL, NULL, NULL, + &rtc_dib, DEV_DIS|DEV_DISABLE|DEV_DEBUG, 0, rtc_debug, NULL, NULL +}; + + + +//////////////////////////////////////////////////////////////////////////////// +////////////////// W D T D A T A S T R U C T U R E S ////////////////// +//////////////////////////////////////////////////////////////////////////////// + +// WDT device information block ... +DIB wdt_dib = { WDT, 1, IOBUS, IOBUS, INT_V_NONE, INT_V_NONE, &wdt_io, 0 }; + +// WDT unit data block (it has only one) ... +UNIT wdt_unit = { UDATA (&wdt_service, 0, 0), 1000 }; + +// WDT device registers (for "EXAMINE WDT STATE") ... +REG wdt_reg[] = { + { DRDATA (COUNT, wdt_count, 16), PV_LEFT }, + { DRDATA (WAIT, wdt_unit.wait, 24), REG_NZ | PV_LEFT }, + { ORDATA (LIGHTS, wdt_lights, 16), REG_RO | PV_LEFT }, + { NULL } +}; + +// WDT device modifiers (for "SET/SHOW WDT xxx") ... +MTAB wdt_mod[] = { + { MTAB_XTD | MTAB_VDV, 0, "DELAY", "DELAY", &wdt_set_delay, &wdt_show_delay, NULL }, + { 0 } +}; + +// WDT debugging flags (for "SET WDT DEBUG=xxx") ... +DEBTAB wdt_debug[] = { + {"WARN", IMP_DBG_WARN}, + {"IO", IMP_DBG_IOT}, + {"LIGHTS", WDT_DBG_LIGHTS}, + {0} +}; + +// And summarize ... +DEVICE wdt_dev = { + "WDT", &wdt_unit, wdt_reg, wdt_mod, + 1, 0, 0, 0, 0, 0, + NULL, NULL, &wdt_reset, NULL, NULL, NULL, + &wdt_dib, DEV_DIS|DEV_DISABLE|DEV_DEBUG, 0, wdt_debug, NULL, NULL +}; + + + +//////////////////////////////////////////////////////////////////////////////// +////////// R T C I / O A N D S E R V I C E R O U T I N E S ////////// +//////////////////////////////////////////////////////////////////////////////// + +// Set and clear the RTC IRQ and IEN ... +#define SET_RTC_IRQ() SET_EXT_INT((1u << (rtc_dib.inum - INT_V_EXTD))) +#define CLR_RTC_IRQ() CLR_EXT_INT((1u << (rtc_dib.inum - INT_V_EXTD))) +#define CLR_RTC_IEN() CLR_EXT_ENB((1u << (rtc_dib.inum - INT_V_EXTD))) + +// RTC IO routine ... +int32 rtc_io (int32 inst, int32 fnc, int32 dat, int32 dev) +{ + switch (inst) { + case ioOCP: + if (fnc == 010) { + // CLKOFF - turn the RTC off ... + sim_cancel(&rtc_unit); rtc_enabled = 0; CLR_RTC_IRQ(); + sim_debug(IMP_DBG_IOT, &rtc_dev, "disabled (PC=%06o)\n", PC-1); + return dat; + } else if (fnc == 000) { + // CLKON - turn the RTC on ... + rtc_enabled = 1; CLR_RTC_IRQ(); + if (sim_is_active(&rtc_unit) == 0) + sim_activate (&rtc_unit, sim_rtc_init (rtc_unit.wait)); + sim_debug(IMP_DBG_IOT, &rtc_dev, "enabled (PC=%06o)\n", PC-1); + return dat; + } + break; + + case ioINA: + if ((fnc == 010) || (fnc == 000)) { + // RDCLOK - return the current count + sim_debug(IMP_DBG_IOT, &rtc_dev, "read clock (PC=%06o, RTC=%06o)\n", PC-1, (rtc_count & DMASK)); + return IOSKIP((rtc_count & DMASK)); + } + break; + } + + sim_debug(IMP_DBG_WARN, &rtc_dev, "UNIMPLEMENTED I/O (PC=%06o, instruction=%o, function=%02o)\n", PC-1, inst, fnc); + return IOBADFNC(dat); +} + +// RTC unit service ... +t_stat rtc_service (UNIT *uptr) +{ + // Add the current quantum to the clock register and, if the clock register + // has overflowed, request an interrupt. The real hardware interrupts when + // there is a carry out of the low byte (in other words, every 256 clocks). + // Note that we can't simply check the low byte for zero to detect overflows + // because of the quantum. Since we aren't necessarily incrementing by 1, we + // may never see a value of exactly zero. We'll have to be more clever. + uint8 rtc_high = HIBYTE(rtc_count); + rtc_count = (rtc_count + rtc_quantum) & DMASK; + if (HIBYTE(rtc_count) != rtc_high) { + sim_debug(IMP_DBG_IOT, &rtc_dev, "interrupt request\n"); + SET_RTC_IRQ(); + } + mi_tx_service(rtc_quantum); + uptr->wait = sim_rtc_calb (rtc_tps); /* recalibrate */ + sim_activate_after (uptr, 1000000/rtc_tps); /* reactivate unit */ + return SCPE_OK; +} + + + +//////////////////////////////////////////////////////////////////////////////// +////////// W D T I / O A N D S E R V I C E R O U T I N E S ////////// +//////////////////////////////////////////////////////////////////////////////// + +// WDT IO routine ... +int32 wdt_io (int32 inst, int32 fnc, int32 dat, int32 dev) +{ + if ((inst == ioOCP) && (fnc == 0)) { + // Reset WDT ... + sim_debug(IMP_DBG_IOT, &wdt_dev, "reset (PC=%06o)\n", PC-1); + return dat; + } else if ((inst == ioOTA) && (fnc == 0)) { + // Set status lights ... + if (wdt_lights != dat) { + sim_debug(WDT_DBG_LIGHTS, &wdt_dev, "changed to %06o\n", dat); + } + sim_debug(IMP_DBG_IOT, &wdt_dev, "set status lights (PC=%06o, LIGHTS=%06o)\n", PC-1, dat); + wdt_lights = dat; return dat; + } + + sim_debug(IMP_DBG_WARN, &wdt_dev, "UNIMPLEMENTED I/O (PC=%06o, instruction=%o, function=%02o)\n", PC-1, inst, fnc); + return IOBADFNC(dat); +} + +// WDT unit service ... +t_stat wdt_service (UNIT *uptr) +{ + return SCPE_OK; +} + + + +//////////////////////////////////////////////////////////////////////////////// +/////////////// D E V I C E A C T I O N C O M M A N D S //////////////// +//////////////////////////////////////////////////////////////////////////////// + +// RTC reset routine ... +t_stat rtc_reset (DEVICE *dptr) +{ + // Clear the interrupt enable and any pending interrupts, reset the count + // and enable the clock. At least I assume that's what a reset does - the + // docs aren't too specific on this point... + rtc_enabled = 1; rtc_count = 0; + CLR_RTC_IRQ(); CLR_RTC_IEN(); + sim_cancel (&rtc_unit); + sim_register_clock_unit ((dptr->flags & DEV_DIS) ? NULL : &rtc_unit); + return SCPE_OK; +} + +// WDT reset routine ... +t_stat wdt_reset (DEVICE *dptr) +{ + // Clear the WDT countdown and turn off all the lights ... + wdt_count = 0; wdt_lights = 0; + sim_cancel (&wdt_unit); + return SCPE_OK; +} + + + +//////////////////////////////////////////////////////////////////////////////// +///////// D E V I C E S E T A N D S H O W C O M M A N D S ////////// +//////////////////////////////////////////////////////////////////////////////// + +// Set/Show RTC interval ... +t_stat rtc_set_interval (UNIT *uptr, int32 val, char *cptr, void *desc) +{ + uint32 newint, newtps; t_stat ret; + if (cptr == NULL) return SCPE_ARG; + newint = get_uint (cptr, 10, 1000000, &ret); + if (ret != SCPE_OK) return ret; + if (newint == 0) return SCPE_ARG; + newtps = 1000000UL / (newint * rtc_quantum); + if ((newtps == 0) || (newtps >= 100000)) return SCPE_ARG; + rtc_interval = newint; rtc_tps = newtps; + uptr->wait = sim_rtc_calb (rtc_tps); + return SCPE_OK; +} + +t_stat rtc_show_interval (FILE *st, UNIT *uptr, int32 val, void *desc) +{ + fprintf(st,"interval=%d (us)", rtc_interval); + return SCPE_OK; +} + +// Set/Show RTC quantum ... +t_stat rtc_set_quantum (UNIT *uptr, int32 val, char *cptr, void *desc) +{ + uint32 newquant, newtps; t_stat ret; + if (cptr == NULL) return SCPE_ARG; + newquant = get_uint (cptr, 10, 1000000, &ret); + if (ret != SCPE_OK) return ret; + if (newquant == 0) return SCPE_ARG; + newtps = 1000000UL / (rtc_interval * newquant); + if ((newtps == 0) || (newtps >= 100000)) return SCPE_ARG; + rtc_quantum = newquant; rtc_tps = newtps; + uptr->wait = sim_rtc_calb (rtc_tps); + return SCPE_OK; +} + +t_stat rtc_show_quantum (FILE *st, UNIT *uptr, int32 val, void *desc) +{ + fprintf(st,"quantum=%d (ticks)", rtc_quantum); + return SCPE_OK; +} + +// Set/Show WDT delay ... +t_stat wdt_set_delay (UNIT *uptr, int32 val, char *cptr, void *desc) +{ + uint32 newint; t_stat ret; + if (cptr == NULL) return SCPE_ARG; + newint = get_uint (cptr, 10, 65535, &ret); + if (ret != SCPE_OK) return ret; + if (newint != 0) { + fprintf(stderr,"WDT - timeout not yet implemented\n"); + return SCPE_IERR; + } + wdt_delay = newint; +// TBA add calculations here??? + return SCPE_OK; +} + +t_stat wdt_show_delay (FILE *st, UNIT *uptr, int32 val, void *desc) +{ + if (wdt_delay > 0) + fprintf(st,"delay=%d (ms)", wdt_delay); + else + fprintf(st,"no timeout"); + return SCPE_OK; +} + +#endif // #ifdef VM_IMPTIP from the very top diff --git a/H316/h316_stddev.c b/H316/h316_stddev.c index 151a3513..448f076e 100644 --- a/H316/h316_stddev.c +++ b/H316/h316_stddev.c @@ -1,6 +1,6 @@ /* h316_stddev.c: Honeywell 316/516 standard devices - Copyright (c) 1999-2013, Robert M. Supnik + Copyright (c) 1999-2015, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -30,6 +30,9 @@ 10-Sep-13 RMS Fixed several bugs in the TTY logic Added SET file type commands to PTR/PTP + 03-Jul-13 RLA compatibility changes for extended interrupts + 23-May-13 RLA Move the SMK/OTK to h316_cpu (where it belongs!) + Allow the CLK device to be disabled 09-Jun-07 RMS Fixed bug in clock increment (Theo Engel) 30-Sep-06 RMS Fixed handling of non-printable characters in KSR mode 03-Apr-06 RMS Fixed bugs in punch state handling (Theo Engel) @@ -106,7 +109,6 @@ extern int32 PC; extern int32 stop_inst; extern int32 C, dp, ext, extoff_pending, sc; extern int32 dev_int, dev_enb; -extern int32 sim_switches; extern UNIT cpu_unit; uint32 ptr_motion = 0; /* read motion */ @@ -158,7 +160,7 @@ t_stat ttp_write (int32 c); ptr_reg PTR register list */ -DIB ptr_dib = { PTR, IOBUS, 1, &ptrio }; +DIB ptr_dib = { PTR, 1, IOBUS, IOBUS, INT_V_PTR, INT_V_NONE, &ptrio, 0 }; UNIT ptr_unit = { UDATA (&ptr_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE, 0), @@ -203,7 +205,7 @@ DEVICE ptr_dev = { ptp_reg PTP register list */ -DIB ptp_dib = { PTP, IOBUS, 1, &ptpio }; +DIB ptp_dib = { PTP, 1, IOBUS, IOBUS, INT_V_PTP, INT_V_NONE, &ptpio, 0 }; UNIT ptp_unit = { UDATA (&ptp_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT @@ -243,7 +245,7 @@ DEVICE ptp_dev = { #define TTR 2 #define TTP 3 -DIB tty_dib = { TTY, IOBUS, 1, &ttyio }; +DIB tty_dib = { TTY, 1, IOBUS, IOBUS, INT_V_TTY, INT_V_NONE, &ttyio, 0 }; UNIT tty_unit[] = { { UDATA (&tti_svc, TT_MODE_KSR, 0), KBD_POLL_WAIT }, @@ -308,7 +310,7 @@ DEVICE tty_dev = { clk_reg CLK register list */ -DIB clk_dib = { CLK_KEYS, IOBUS, 1, &clkio }; +DIB clk_dib = { CLK_KEYS, 1, IOBUS, IOBUS, INT_V_CLK, INT_V_NONE, &clkio, 0 }; UNIT clk_unit = { UDATA (&clk_svc, 0, 0), 16000 }; @@ -335,7 +337,7 @@ DEVICE clk_dev = { 1, 0, 0, 0, 0, 0, NULL, NULL, &clk_reset, NULL, NULL, NULL, - &clk_dib, 0 + &clk_dib, /* [RLA] */ DEV_DISABLE }; /* Paper tape reader: IO routine */ @@ -392,7 +394,7 @@ else { if ((c = getc (uptr->fileref)) == EOF) { /* read byte */ if (feof (uptr->fileref)) { if (ptr_stopioe) - printf ("PTR end of file\n"); + sim_printf ("PTR end of file\n"); else return SCPE_OK; } else perror ("PTR I/O error"); @@ -421,7 +423,7 @@ t_stat r; if (!(uptr->flags & UNIT_ATTABLE)) /* not tti,tto */ return SCPE_NOFNC; -if (r = attach_unit (uptr, cptr)) +if ((r = attach_unit (uptr, cptr))) return r; if (sim_switches & SWMASK ('A')) /* -a? ASCII */ uptr->flags |= UNIT_ASC; @@ -483,7 +485,7 @@ static const int32 pboot[] = { t_stat ptr_boot (int32 unitno, DEVICE *dptr) { -int32 i; +size_t i; for (i = 0; i < PBOOT_SIZE; i++) /* copy bootstrap */ M[PBOOT_START + i] = pboot[i]; @@ -597,7 +599,7 @@ switch (inst) { /* case on opcode */ tty_busy = 0; tty_mode = 0; /* mode is input */ tty_2nd = 0; -/* sim_cancel (&tty_unit[TTO]); /* cancel output */ +/* sim_cancel (&tty_unit[TTO]); *//* cancel output */ } CLR_INT (INT_TTY); /* clear intr */ break; @@ -682,7 +684,7 @@ else if ((ruptr->flags & UNIT_ATT) && /* TTR attached */ if (feof (ruptr->fileref)) { /* EOF? */ ruptr->STA &= ~RUNNING; /* stop reader */ if (ttr_stopioe) - printf ("TTR end of file\n"); + sim_printf ("TTR end of file\n"); else return SCPE_OK; } else perror ("TTR I/O error"); @@ -891,32 +893,28 @@ switch (inst) { /* case on opcode */ if (!TST_INTREQ (INT_CLK)) return IOSKIP (dat); } - else if ((fnc & 007) == 002) { /* mem parity? */ - if (((fnc == 002) && !TST_INT (INT_MPE)) || - ((fnc == 012) && TST_INT (INT_MPE))) - return IOSKIP (dat); - } + // [RLA] I'm not sure where this comes from - I can't find any H316 + // [RLA] documentation that supports this. According to my manual, + // [RLA] skip on memory parity error (SPS) is opcode 101200 and skip + // [RLA] on no parity error (SPN) is 100200. Neither of these look + // [RLA] like an SKS to device 20. + // + // [RLA] In any case this code can't stay here since the clock can + // [RLA] now be disabled. It'll have to move to h316_cpu.c no matter + // [RLA] how it's supposed to work. + // + // [RLA] else if ((fnc & 007) == 002) { /* mem parity? */ + // [RLA] if (((fnc == 002) && !TST_INT (INT_MPE)) || + // [RLA] ((fnc == 012) && TST_INT (INT_MPE))) + // [RLA] return IOSKIP (dat); + // [RLA] } else return IOBADFNC (dat); /* invalid fnc */ break; case ioOTA: /* OTA */ - if (fnc == 000) /* SMK */ - dev_enb = dat; - else if (fnc == 010) { /* OTK */ - C = (dat >> 15) & 1; /* set C */ - if (cpu_unit.flags & UNIT_HSA) /* HSA included? */ - dp = (dat >> 14) & 1; /* set dp */ - if (cpu_unit.flags & UNIT_EXT) { /* ext opt? */ - if (dat & 020000) { /* ext set? */ - ext = 1; /* yes, set */ - extoff_pending = 0; - } - else extoff_pending = 1; /* no, clr later */ - } - sc = dat & 037; /* set sc */ - } - else return IOBADFNC (dat); - break; + // [RLA] This case never gets here - OTA with device 20 is the SMK or + // [RLA] OTK instructions, and those are handled directly in h316_cpu.c + return IOBADFNC (dat); } return dat; @@ -930,7 +928,8 @@ t_stat clk_svc (UNIT *uptr) M[M_CLK] = (M[M_CLK] + 1) & DMASK; /* increment mem ctr */ if (M[M_CLK] == 0) /* = 0? set flag */ SET_INT (INT_CLK); -sim_activate (&clk_unit, sim_rtc_calb (clk_tps)); /* reactivate */ +sim_rtc_calb (clk_tps); /* recalibrate */ +sim_activate_after (uptr, 1000000/clk_tps); /* reactivate unit */ return SCPE_OK; } @@ -938,6 +937,7 @@ return SCPE_OK; t_stat clk_reset (DEVICE *dptr) { +sim_register_clock_unit (&clk_unit); /* declare clock unit */ CLR_INT (INT_CLK); /* clear ready, enb */ CLR_ENB (INT_CLK); sim_cancel (&clk_unit); /* deactivate unit */ diff --git a/H316/h316_sys.c b/H316/h316_sys.c index 2dabbeff..20024d5b 100644 --- a/H316/h316_sys.c +++ b/H316/h316_sys.c @@ -1,6 +1,6 @@ /* h316_sys.c: Honeywell 316/516 simulator interface - Copyright (c) 1999-2013, Robert M Supnik + Copyright (c) 1999-2015, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,7 @@ 15-Sep-13 RMS Added device name support for IO instructions Fixed handling of OTK + 21-May-13 RLA Add IMP/TIP devices 01-Dec-04 RMS Fixed fprint_opr calling sequence 24-Oct-03 RMS Added DMA/DMC support 17-Sep-01 RMS Removed multiconsole support @@ -43,9 +44,13 @@ extern DEVICE clk_dev; extern DEVICE dp_dev; extern DEVICE fhd_dev; extern DEVICE mt_dev; +#ifdef VM_IMPTIP +extern DEVICE rtc_dev, wdt_dev, imp_dev; +extern DEVICE mi1_dev, mi2_dev, mi3_dev, mi4_dev, mi5_dev; +extern DEVICE hi1_dev, hi2_dev, hi3_dev, hi4_dev; +#endif extern REG cpu_reg[]; extern uint16 M[]; -extern int32 sim_switches; /* SCP data structures and interface routines @@ -67,12 +72,19 @@ DEVICE *sim_devices[] = { &cpu_dev, &ptr_dev, &ptp_dev, - &tty_dev, &lpt_dev, - &clk_dev, - &dp_dev, - &fhd_dev, + &tty_dev, &mt_dev, + &clk_dev, + &fhd_dev, + &dp_dev, +#ifdef VM_IMPTIP + &wdt_dev, + &rtc_dev, + &imp_dev, + &mi1_dev, &mi2_dev, &mi3_dev, &mi4_dev, &mi5_dev, + &hi1_dev, &hi2_dev, &hi3_dev, &hi4_dev, +#endif NULL }; @@ -398,11 +410,11 @@ switch (j) { /* case on class */ case I_V_MRF: case I_V_MRX: /* mem ref */ cptr = get_glyph (cptr, gbuf, ','); /* get next field */ - if (k = (strcmp (gbuf, "C") == 0)) { /* C specified? */ + if ((k = (strcmp (gbuf, "C") == 0))) { /* C specified? */ val[0] = val[0] | SC; cptr = get_glyph (cptr, gbuf, 0); } - else if (k = (strcmp (gbuf, "Z") == 0)) { /* Z specified? */ + else if ((k = (strcmp (gbuf, "Z") == 0))) { /* Z specified? */ cptr = get_glyph (cptr, gbuf, ','); } d = get_uint (gbuf, 8, X_AMASK, &r); /* construe as addr */ diff --git a/H316/h316_udp.c b/H316/h316_udp.c new file mode 100644 index 00000000..c1cb3a2f --- /dev/null +++ b/H316/h316_udp.c @@ -0,0 +1,468 @@ +/* h316_udp.c: IMP/TIP Modem and Host Interface socket routines using UDP + + Copyright (c) 2013 Robert Armstrong, bob@jfcl.com + + 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 + ROBERT ARMSTRONG 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 Robert Armstrong shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert Armstrong. + + + REVISION HISTORY + + udp socket routines + + 26-Jun-13 RLA Rewritten from TCP version + 26-Nov-13 MP Rewritten to use TMXR layer packet semantics thus + allowing portability to all simh hosts. + 2-Dec-13 RLA Improve error recovery if the other simh is restarted + + OVERVIEW + + This module emulates low level communications between two virtual modems + using UDP packets over the modern network connections. It's used by both + the IMP modem interface and the host interface modules to implement IMP to + IMP and IMP to HOST connections. + + TCP vs UDP + + Why UDP and not TCP? TCP has a couple of advantages after all - it's + stream oriented, which is intrinsically like a modem, and it handles all + the network "funny stuff" for us. TCP has a couple of problems too - first, + it's inherently asymmetrical. There's a "server" end which opens a master + socket and passively listens for connections, and a "client" end which + actively attempts to connect. That's annoying, but it can be worked around. + + The big problem with TCP is that even though it treats the data like a stream + it's internally buffering it, and you really have absolutely no control over + when TCP will decide to send its buffer. Google "nagle algorithm" to get an + idea. Yes, you can set TCP_NODELAY to disable Nagle, but the data's still + buffered and it doesn't fix the problem. What's the issue with buffering? + It introduces completely unpredictable delays into the message traffic. A + transmitting IMP could send two or three (or ten or twenty!) messages before + TCP actually decides to try to deliver them to the destination. + + And it turns out that IMPs are extraordinarily sensitive to line speed. The + IMP firmware actually goes to the trouble of measuring the effective line + speed by using the RTC to figure out how long it takes to send a message. + One thing that screws up the IMP to no end is variation in the effective + line speed. I guess they had a lot of trouble with AT&T Long Lines back in + the Old Days, and the IMP has quite a bit of code to monitor line quality. + Even fairly minor variations in speed will cause it to mark the line as + "down" and sent a trouble report back to BBN. And no, I'm not making this up! + + UDP gives us a few advantages. First, it's inherently packet oriented so + we can simply grab the entire packet from the transmitting IMP's memory, wrap + a little extra information around it, and ship it off in one datagram. The + receiving IMP gets the whole packet at once and it can simply BLT it into + the receiving IMP's memory. No fuss, no muss, no need convert the packet + into a stream, add word counts, wait for complete packets, etc. And UDP is + symmetrical - both ends listen and send in the same way. There's no need for + master sockets, passive (server) and active (client) ends, or any of that. + + Also UDP has no buffering - the packet goes out on the wire when we send it. + The data doesn't wait around in some buffer for TCP to decide when it wants + to let it go. The latency and delay for UDP is much more predictable and + consistent, at least for local networks. If you're actually sending the + packets out on the big, wide, Internet then all bets are off on that. + + UDP has a few problems that we have to worry about. First, it's not + guaranteed delivery so just because one IMP sends a packet doesn't mean that + the other end will ever see it. Surprisingly that's not a problem for us. + Phone lines have noise and dropouts, and real modems lose packets too. The + IMP code is completely happy and able to deal with that, and generally we + don't worry about dropped packets at all. + + There are other issues with UDP - it doesn't guarantee packet order, so the + sending IMP might transmit packets 1, 2 and 3 and the receiving IMP will get + 1, 3 then 2. THAT would never happen with a real modem and we have to shield + the IMP code from any such eventuality. Also, with UDP packets can be + duplicated so the receiving IMP might see 1, 2, 2, 3 (or even 1, 3, 2, 1!). + Again, a modem would never do that and we have to prevent it from happening. + Both cases are easily dealt with by adding a sequence number to the header + we wrap around the IMP's packet. Out of sequence or duplicate packets can + be detected and are simply dropped. If necessary, the IMP will deal with + retransmitting them in its own time. + + One more thing about UDP - there is no way to tell whether a connection is + established or not and for that matter there is no "connection" at all + (that's why it's a "connectionless" protocol, after all!). We simply send + packets out and there's no way to know whether anybody is hearing them. The + real IMP modem hardware had no carrier detect or other dataset control + functions, so it was identical in that respect. An IMP sent messages out the + modem and, unless it received a message back, it had no way to know whether + the IMP on the other end was hearing them. + + + INTERFACE + + This module provides a simplified UDP socket interface. These functions are + implemented - + + udp_create define a connection to the remote IMP + udp_release release a connection + udp_send send an IMP message to the other end + udp_receive receive (w/o blocking!) a message if available + + Note that each connection is assigned a unique "handle", a small integer, + which is used as an index into our internal connection data table. There + is a limit on the maximum number of connections available, as set my the + MAXLINKS parameter. Also, notice that all links are intrinsically full + duplex and bidirectional - data can be sent and received in both directions + independently. Real modems and host cards were exactly the same. + +*/ +#ifdef VM_IMPTIP +#include "sim_defs.h" // simh machine independent definitions +#include "sim_tmxr.h" // The MUX layer exposes packet send and receive semantics +#include "h316_defs.h" // H316 emulator definitions +#include "h316_imp.h" // ARPAnet IMP/TIP definitions + +// Local constants ... +#define MAXLINKS 10 // maximum number of simultaneous connections +// This constant determines the longest possible IMP data payload that can be +// sent. Most IMP messages are trivially small - 68 words or so - but, when one +// IMP asks for a reload the neighbor IMP sends the entire memory image in a +// single message! That message is about 14K words long. +// The next thing you should worry about is whether the underlying IP network +// can actually send a UDP packet of this size. It turns out that there's no +// simple answer to that - it'll be fragmented for sure, but as long as all +// the fragments arrive intact then the destination should reassemble them. +#define MAXDATA 16384 // longest possible IMP packet (in H316 words) + +// UDP connection data structure ... +// One of these blocks is allocated for every simulated modem link. +struct _UDP_LINK { + t_bool used; // TRUE if this UDP_LINK is in use + char rhostport[64]; // Remote host:port + char lport[64]; // Local port + uint32 rxsequence; // next message sequence number for receive + uint32 txsequence; // next message sequence number for transmit + DEVICE *dptr; // Device associated with link +}; +typedef struct _UDP_LINK UDP_LINK; + +// This magic number is stored at the beginning of every UDP message and is +// checked on receive. It's hardly foolproof, but its a simple attempt to +// guard against other applications dumping unsolicited UDP messages into our +// receiver socket... +#define MAGIC ((uint32) (((((('H' << 8) | '3') << 8) | '1') << 8) | '6')) + +// UDP wrapper data structure ... +// This is the UDP packet which is actually transmitted or received. It +// contains the actual IMP packet, plus whatever additional information we +// need to keep track of things. NOTE THAT ALL DATA IN THIS PACKET, INCLUDING +// THE H316 MEMORY WORDS, ARE SENT AND RECEIVED WITH NETWORK BYTE ORDER! +struct _UDP_PACKET { + uint32 magic; // UDP "magic number" (see above) + uint32 sequence; // UDP packet sequence number + uint16 count; // number of H316 words to follow + uint16 data[MAXDATA]; // and the actual H316 data words/IMP packet +}; +typedef struct _UDP_PACKET UDP_PACKET; +#define UDP_HEADER_LEN (2*sizeof(uint32) + sizeof(uint16)) + +// Locals ... +UDP_LINK udp_links[MAXLINKS] = { {0} }; // data for every active connection +TMLN udp_lines[MAXLINKS] = { {0} }; // line descriptors +TMXR udp_tmxr = { MAXLINKS, NULL, 0, udp_lines};// datagram mux + +int32 udp_find_free_link (void) +{ + // Find a free UDP_LINK block, initialize it and return its index. If none + // are free, then return -1 ... + int32 i; + for (i = 0; i < MAXLINKS; ++i) { + if (udp_links[i].used == 0) { + memset(&udp_links[i], 0, sizeof(UDP_LINK)); + return i; + } + } + return NOLINK; +} + +t_stat udp_parse_remote (int32 link, char *premote) +{ + // This routine will parse a remote address string in any of these forms - + // + // llll:w.x.y.z:rrrr + // llll:name.domain.com:rrrr + // llll::rrrr + // w.x.y.z:rrrr + // name.domain.com:rrrr + // + // In all examples, "llll" is the local port number that we use for listening, + // and "rrrr" is the remote port number that we use for transmitting. The + // local port is optional and may be omitted, in which case it defaults to the + // same as the remote port. This works fine if the other IMP is actually on + // a different host, but don't try that with localhost - you'll be talking to + // yourself!! In both cases, "w.x.y.z" is a dotted IP for the remote machine + // and "name.domain.com" is its name (which will be looked up to get the IP). + // If the host name/IP is omitted then it defaults to "localhost". + char *end; int32 lport, rport; + char host[64], port[16]; + if (*premote == '\0') return SCPE_2FARG; + memset (udp_links[link].lport, 0, sizeof(udp_links[link].lport)); + memset (udp_links[link].rhostport, 0, sizeof(udp_links[link].rhostport)); + // Handle the llll::rrrr case first + if (2 == sscanf (premote, "%d::%d", &lport, &rport)) { + if ((lport < 1) || (lport >65535) || (rport < 1) || (rport >65535)) return SCPE_ARG; + sprintf (udp_links[link].lport, "%d", lport); + sprintf (udp_links[link].rhostport, "localhost:%d", rport); + return SCPE_OK; + } + + // Look for the local port number and save it away. + lport = strtoul(premote, &end, 10); + if ((*end == ':') && (lport > 0)) { + sprintf (udp_links[link].lport, "%d", lport); + premote = end+1; + } + + if (sim_parse_addr (premote, host, sizeof(host), "localhost", port, sizeof(port), NULL, NULL)) + return SCPE_ARG; + sprintf (udp_links[link].rhostport, "%s:%s", host, port); + if (udp_links[link].lport[0] == '\0') + strcpy (udp_links[link].lport, port); + + if ((strcmp (udp_links[link].lport, port) == 0) && + (strcmp ("localhost", host) == 0)) + fprintf(stderr,"WARNING - use different transmit and receive ports!\n"); + + return SCPE_OK; +} + +t_stat udp_error (int32 link, const char *msg) +{ + // This routine is called whenever a SOCKET_ERROR is returned for any I/O. + fprintf(stderr,"UDP%d - %s failed with error %d\n", link, msg, WSAGetLastError()); + return SCPE_IOERR; +} + +t_stat udp_create (DEVICE *dptr, char *premote, int32 *pln) +{ + // Create a logical UDP link to the specified remote system. The "remote" + // string specifies both the remote host name or IP and a port number. The + // port number is both the port we send datagrams to, and also the port we + // listen on for incoming datagrams. UDP doesn't have any real concept of a + // "connection" of course, and this routine simply creates the necessary + // sockets in this host. We have no way of knowing whether the remote host is + // listening or even if it exists. + // + // We return SCPE_OK if we're successful and an error code if we aren't. If + // we are successful, then the ln parameter is assigned the link number, + // which is a handle used to identify this connection to all future udp_xyz() + // calls. + t_stat ret; + char linkinfo[128]; + int32 link = udp_find_free_link(); + if (link < 0) return SCPE_MEM; + + // Parse the remote name and set up the ipaddr and port ... + if ((ret = udp_parse_remote(link, premote)) != SCPE_OK) return ret; + + // Create the socket connection to the destination ... + sprintf(linkinfo, "Buffer=%d,Line=%d,%s,UDP,Connect=%s", (int)(sizeof(UDP_PACKET)+sizeof(int32)), link, udp_links[link].lport, udp_links[link].rhostport); + ret = tmxr_open_master (&udp_tmxr, linkinfo); + if (ret != SCPE_OK) return ret; + + // All done - mark the TCP_LINK data as "used" and return the index. + udp_links[link].used = TRUE; *pln = link; + udp_lines[link].dptr = udp_links[link].dptr = dptr; // save device + udp_tmxr.uptr = dptr->units; + udp_tmxr.last_poll_time = 1; // h316'a use of TMXR doesn't poll periodically for connects + tmxr_poll_conn (&udp_tmxr); // force connection initialization now + udp_tmxr.last_poll_time = 1; // h316'a use of TMXR doesn't poll periodically for connects + sim_debug(IMP_DBG_UDP, dptr, "link %d - listening on port %s and sending to %s\n", link, udp_links[link].lport, udp_links[link].rhostport); + return SCPE_OK; +} + +t_stat udp_release (DEVICE *dptr, int32 link) +{ + // Close a link that was created by udp_create() and release any resources + // allocated to it. We always return SCPE_OK unless the link specified is + // already unused. + if ((link < 0) || (link >= MAXLINKS)) return SCPE_IERR; + if (!udp_links[link].used) return SCPE_IERR; + if (dptr != udp_links[link].dptr) return SCPE_IERR; + + tmxr_detach_ln (&udp_lines[link]); + udp_links[link].used = FALSE; + sim_debug(IMP_DBG_UDP, dptr, "link %d - closed\n", link); + + return SCPE_OK; +} + +t_stat udp_send (DEVICE *dptr, int32 link, uint16 *pdata, uint16 count) +{ + // This routine does all the work of sending an IMP data packet. pdata + // is a pointer (usually into H316 simulated memory) to the IMP packet data, + // count is the length of the data (in H316 words, not bytes!), and pdest is + // the destination socket. There are two things worthy of note here - first, + // notice that the H316 words are sent in network order, so the remote simh + // doesn't necessarily need to have the same endian-ness as this machine. + // Second, notice that transmitting sockets are NOT set to non blocking so + // this routine might wait, but we assume the wait will never be too long. + UDP_PACKET pkt; int pktlen; uint16 i; t_stat iret; + if ((link < 0) || (link >= MAXLINKS)) return SCPE_IERR; + if (!udp_links[link].used) return SCPE_IERR; + if ((pdata == NULL) || (count == 0) || (count > MAXDATA)) return SCPE_IERR; + if (dptr != udp_links[link].dptr) return SCPE_IERR; + + // Build the UDP packet, filling in our own header information and copying + // the H316 words from memory. REMEMBER THAT EVERYTHING IS IN NETWORK ORDER! + pkt.magic = htonl(MAGIC); + pkt.sequence = htonl(udp_links[link].txsequence++); + pkt.count = htons(count); + for (i = 0; i < count; ++i) pkt.data[i] = htons(*pdata++); + pktlen = UDP_HEADER_LEN + count*sizeof(uint16); + + // Send it and we're outta here ... + iret = tmxr_put_packet_ln (&udp_lines[link], (const uint8 *)&pkt, (size_t)pktlen); + if (iret != SCPE_OK) return udp_error(link, "tmxr_put_packet_ln()"); + sim_debug(IMP_DBG_UDP, dptr, "link %d - packet sent (sequence=%d, length=%d)\n", link, ntohl(pkt.sequence), ntohs(pkt.count)); + return SCPE_OK; +} + +t_stat udp_set_link_loopback (DEVICE *dptr, int32 link, t_bool enable_loopback) +{ + // Enable or disable the local (interface) loopback on this link... + if ((link < 0) || (link >= MAXLINKS)) return SCPE_IERR; + if (!udp_links[link].used) return SCPE_IERR; + if (dptr != udp_links[link].dptr) return SCPE_IERR; + + return tmxr_set_line_loopback (&udp_lines[link], enable_loopback); +} + +int32 udp_receive_packet (int32 link, UDP_PACKET *ppkt) +{ + // This routine will do the hard part of receiving a UDP packet. If it's + // successful the packet length, in bytes, is returned. The receiver socket + // is non-blocking, so if no packet is available then zero will be returned + // instead. Lastly, if a fatal socket I/O error occurs, -1 is returned. + // + // Note that this routine only receives the packet - it doesn't handle any + // of the checking for valid packets, unexpected packets, duplicate or out of + // sequence packets. That's strictly the caller's problem! + size_t pktsiz; + const uint8 *pbuf; + t_stat ret; + + udp_lines[link].rcve = TRUE; // Enable receiver + tmxr_poll_rx (&udp_tmxr); + ret = tmxr_get_packet_ln (&udp_lines[link], &pbuf, &pktsiz); + udp_lines[link].rcve = FALSE; // Disable receiver + if (ret != SCPE_OK) { + udp_error(link, "tmxr_get_packet_ln()"); + return NOLINK; + } + if (pbuf == NULL) return 0; + // Got a packet, so copy it to the packet buffer + memcpy (ppkt, pbuf, pktsiz); + return pktsiz; +} + +int32 udp_receive (DEVICE *dptr, int32 link, uint16 *pdata, uint16 maxbuf) +{ + // Receive an IMP packet from the virtual modem. pdata is a pointer usually + // directly into H316 simulated memory) to where the IMP packet data should + // be stored, and maxbuf is the maximum length of that buffer in H316 words + // (not bytes!). If a message is successfully received then this routine + // returns the length, again in H316 words, of the IMP packet. The caller + // can detect buffer overflows by comparing this result to maxbuf. If no + // packets are waiting right now then zero is returned, and -1 is returned + // in the event of any fatal socket I/O error. + // + // This routine also handles checking for unsolicited messages and duplicate + // or out of sequence messages. All of these are unceremoniously discarded. + // + // One final note - it's explicitly allowed for pdata to be null and/or + // maxbuf to be zero. In either case the received package is discarded, but + // the actual length of the discarded package is still returned. + UDP_PACKET pkt; int32 pktlen, explen, implen, i; uint32 magic, pktseq; + if ((link < 0) || (link >= MAXLINKS)) return SCPE_IERR; + if (!udp_links[link].used) return SCPE_IERR; + if (dptr != udp_links[link].dptr) return SCPE_IERR; + + while ((pktlen = udp_receive_packet(link, &pkt)) > 0) { + // First do some header checks for a valid UDP packet ... + if (((size_t)pktlen) < UDP_HEADER_LEN) { + sim_debug(IMP_DBG_UDP, dptr, "link %d - received packet w/o header (length=%d)\n", link, pktlen); + continue; + } + magic = ntohl(pkt.magic); + if (magic != MAGIC) { + sim_debug(IMP_DBG_UDP, dptr, "link %d - received packet w/bad magic number (magic=%08x)\n", link, magic); + continue; + } + implen = ntohs(pkt.count); + explen = UDP_HEADER_LEN + implen*sizeof(uint16); + if (explen != pktlen) { + sim_debug(IMP_DBG_UDP, dptr, "link %d - received packet length wrong (expected=%d received=%d)\n", link, explen, pktlen); + continue; + } + + // Now the hard part = check the sequence number. The rxsequence value is + // the number of the next packet we expect to receive - that's the number + // this packet should have. If this packet's sequence is less than that, + // then this packet is out of order or a duplicate and we discard it. If + // this packet is greater than that, then we must have missed one or two + // packets. In that case we MUST update rxsequence to match this one; + // otherwise the two ends could never resynchronize after a lost packet. + // + // And there's one final complication to worry about - if the simh on the + // other end is restarted for some reason, then his sequence numbers will + // reset to zero. In that case we'll never recover synchronization without + // special efforts. The hack is to check for a packet sequence number of + // zero and, if we find it, force synchronization. This improves the + // situation, but I freely admit that it's possible to think of a number of + // cases where this also fails. The only absolute solution is to implement + // a more complicated system with non-IMP control messages exchanged between + // the modem emulation on both ends. That'd be nice, but I'll leave it as + // an exercise for later. + pktseq = ntohl(pkt.sequence); + if ((pktseq == 0) && (udp_links[link].rxsequence != 0)) { + sim_debug(IMP_DBG_UDP, dptr, "link %d - remote modem restarted\n", link); + } else if (pktseq < udp_links[link].rxsequence) { + sim_debug(IMP_DBG_UDP, dptr, "link %d - received packet out of sequence 1 (expected=%d received=%d\n", link, udp_links[link].rxsequence, pktseq); + continue; // discard this packet! + } + else if (pktseq != udp_links[link].rxsequence) { + sim_debug(IMP_DBG_UDP, dptr, "link %d - received packet out of sequence 2 (expected=%d received=%d\n", link, udp_links[link].rxsequence, pktseq); + } + udp_links[link].rxsequence = pktseq+1; + + // It's a valid packet - if there's no buffer then just discard it. + if ((pdata == NULL) || (maxbuf == 0)) { + sim_debug(IMP_DBG_UDP, dptr, "link %d - received packet discarded (no buffer available)\n", link); + return implen; + } + + // Copy the data to the H316 memory and we're done! + sim_debug(IMP_DBG_UDP, dptr, "link %d - packet received (sequence=%d, length=%d)\n", link, pktseq, pktlen); + for (i = 0; i < (implen < maxbuf ? implen : maxbuf); ++i) + *pdata++ = ntohs(pkt.data[i]); + return implen; + } + + // Here if pktlen <= 0 ... + return pktlen; +} + +#endif // ifdef VM_IMPTIP diff --git a/H316/tests/c-listing-ps.txt b/H316/tests/c-listing-ps.txt new file mode 100644 index 00000000..1241aa8d --- /dev/null +++ b/H316/tests/c-listing-ps.txt @@ -0,0 +1,13422 @@ + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 1 IMP,3050,IMP 7:20 PM 9/16/1973 + + IMP SYSTEM + + .VERS.=3050 + + DCA=0 + + PRINTX /NETWORK VERSION / + PNTNUM .VERS. + PRINTX / + / + + REPEAT 1IF VZ DCA,[ + PRINTX /ARPA NET SYSTEM + + / ] + + REPEAT 0IF VZ DCA,[ + PRINTX /DCA NET SYSTEM + + / ] + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 2 IMP,3050,IMP 7:20 PM 9/16/1973 + + ACA=141216 + ADD=14000 /516 OPCODES + ANA=6000 + AOA=141206 + CAL=141050 + CAR=141044 + CAS=22000 + CHS=140024 + CMA=140401 + CRA=140040 + CSA=140320 + DXA=11 + .ENB=401 + ERA=12000 + EXA=13 + HLT=0 + IAB=201 + ICA=141340 + ICL=141140 + ICR=141240 + IMA=26000 + .INH=1001 + INK=43 + IRS=24000 + JMP=2000 + JST=20000 + LDA=4000 + LDX=72000 + NOP=101000 + OTK=171020 + RCB=140200 + SCB=140600 + SKP=100000 + SLN=101100 + SLZ=100100 + SMI=101400 + SNZ=101040 + SPL=100400 + SRC=100001 + SR1=100020 + SR2=100010 + SR3=100004 + SR4=100002 + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 3 IMP,3050,IMP 7:20 PM 9/16/1973 + + SSC=101001 + SSM=140500 + SSP=140100 + SS1=101020 + SS2=101010 + SS3=101004 + SS4=101002 + STA=10000 + STX=32000 + SUB=16000 + SZE=100040 + TCA=140407 + + IRP [I,,ALS,ARS,ALR,ARR,LGL,LGR,LLS,LRS,LLR,LRR,LLL,LRL], [N,, + 415,405,416,406,414,404,411,401,412,402,410,400] + + DEFINE I C + 0 0 N'00+100-C"A"77 + TERMINATE + + ENDIRP + + + IRP [I,,INA,OCP,OTA,SKS,SMK],[N,,13,3,17,7,17] + + DEFINE I C + 0 0 N'0000 C + TERMINATE + + ENDIRP + + + X=40000 + I=100000 + XI=140000 + + DEFINE BSS N + 200000 + 0 0 . N-1/ + TERMINATE + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 4 IMP,3050,IMP 7:20 PM 9/16/1973 + + /SKS'S, OCP'S, ETC FOR PRODUCTION MACHINES + + IRP [NUM,,1,2,3,4,5] + + M'NUM'OUT=OCP 7'NUM + M'NUM'UNXP=OCP 17'NUM + M'NUM'LXP=OCP 27'NUM + M'NUM'IXP=OCP 37'NUM + M'NUM'IN=OCP 47'NUM + + M'NUM'ERR=SKS 47'NUM + + M'NUM'INIL=63 NUM + M'NUM'OTIL=70 NUM + + M'NUM'INBP=16 NUM NUM + M'NUM'OTBP=30 NUM NUM + + ENDIRP + + + IRP [NUM,,1,2,3] + + H'NUM'ROUT=OCP 100-[10"T"NUM] + H'NUM'IN=OCP 200-[10"T"NUM] + H'NUM'FOUT=OCP 300-[10"T"NUM] + H'NUM'XP=OCP 400-[10"T"NUM] + H'NUM'UNXP=OCP 500-[10"T"NUM] + H'NUM'ENAB=OCP 600-[10"T"NUM] + + H'NUM'ERR=SKS 100-[10"T"NUM] + H'NUM'RDY=SKS 200-[10"T"NUM] + H'NUM'EOM=SKS 300-[10"T"NUM] + H'NUM'FULL=SKS 500-[10"T"NUM] + + H'NUM'OTIL=75 NUM + H'NUM'INIL=77 NUM + + H'NUM'OTBP=42 NUM NUM + H'NUM'INBP=46 NUM NUM + + ENDIRP + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 5 IMP,3050,IMP 7:20 PM 9/16/1973 + + H3OTIL=M5INIL /HOST 3 IS A LITTLE STRANGE + H3INIL=M5OTIL + H3OTBP=54 + H3INBP=56 + H4OTIL=M4INIL /HOST 4 IS YET STRANGER + H4INIL=M4OTIL + H4OTBP=M5INBP + H4INBP=M5OTBP + H4ROUT=OCP 51 + H4IN=OCP 151 + H4FOUT=OCP 251 + H4XP=OCP 351 + H4UNXP=OCP 451 + H4ENAB=OCP 551 + H4ERR=SKS 51 + H4RDY=SKS 151 + H4EOM=SKS 251 + H4FULL=SKS 451 + + CLKON=OCP 40 + CLKOFF=OCP 1040 + RDCLOK=INA 1040 + CLOKIL=102 + + TASK=OCP 41 + TASKIL=103 + + WDT=OCP 26 + WDTIL=62 + PFIL=60 + SWDTIL=61 + + LITES=OTA 26 + RDIMPN=INA 1041 + + AMIMLC=SKS 42 + + AMI516=SKS 26 + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 6 IMP,3050,IMP 7:20 PM 9/16/1973 + + /SKS'S AND OCP'S NATIVE TO THE 516 + + STDIL=63 /STANDARD INTERRUPT LOCATION + TTSIM=OCP 4 /SELECT INPUT MODE + TTSOM=OCP 104 /SELECT OUTPUT MODE + TTSRDY=SKS 4 + TTSNBZ=SKS 104 + TTSNSC=SKS 504 + TTINA=INA 4 + TTINB=INA 204 + TTINAC=INA 1004 + TTINBC=INA 1204 + TTOTA=OTA 4 + TTOTB=OTA 204 + + INTM=120 /SMK TO SET THE PRIORITY INTERRUPT 1 + JUNK=1 + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 7 IMP,3050,IMP 7:20 PM 9/16/1973 + + EQUALS R,REPEAT + EQUALS D,DEFINE + EQUALS T,TERMINATE + EQUALS P,PRINTX + EQUALS PR,PRINT + + /MACROS TO TYPE OUT INTERESTING LOCATIONS + + D DEFPLC TX + .TA.=. 100201/ + .TA. .ASCII /TX'"Z"/ + .TA./ + T DEFPLC + + D RELOAD TX + .TA.=. 100301/ + .TA.+1 .ASCII /TX'"Z"/ + .TA./ + T RELOAD + + D DEFHLT TX + .TA.=. 100101/ + .TA.+1 .ASCII /TX'"Z"/ + .TA./ + T DEFHLT + + /TITLES FOR DUMPED TEXTS + 100200/ + .ASCII /USEFUL LOCATIONS + "Z"/ + 100100/ + .ASCII /HALT LOCATIONS + "Z"/ + 100000/ + .ASCII / PATCH BEG END BUFS"Z"/ + 100300/ + .ASCII /CRASH-RELOAD LOCATIONS + "Z"/ + 100400/ + .ASCII / IMP BUFFERS ASSIGNED + PAGE + "Z"/ + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 8 IMP,3050,IMP 7:20 PM 9/16/1973 + + /MACROS TO SET UP STATISIICS TABLES + + NSTATS=0 + MAXSTAT=22. + + /CALL DEFSTAT , + D DEFSTAT A,B + .TA.=. + .TB.=A A + R 1IF P,[ + SW1+NSTATS/ B + SB1+NSTATS/ .TA. + SC1+NSTATS/ .TB. + .TA.+1/ + ] + NSTATS=NSTATS+1 + R 1IF VP NSTATS-MAXSTAT,[ + PR "TOO MANY STATISTICS" + NSTATS=NSTATS-1 + ] + T DEFSTAT + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 9 IMP,3050,IMP 7:20 PM 9/16/1973 + + /MACROS FOR IMP/TIP INITIALIZATION + NITB=0 + MAXITB=20.+4 /SATDEF USES 4 + /CALL TIPDEF , + + D TIPDEF A,B + .TA.=. + .TB.=A BSS 1 + .TC.=B + R 1IF P,[ + ITBLOC+NITB/ .TA. + ITBIMP+NITB/ .TB. + ITBTIP+NITB/ .TC. + .TA.+1/ + ] + NITB=NITB+1 + R 0IF VP MAXITB-NITB,[ + PR "TOO MANY IMP/TIP INSTRS" + NITB=NITB-1 + ] + T TIPDEF + + R 1IF P,[ + ITBLOC/ + R MAXITB,[ + 1 + ] +02236 000001 ] +02237 000001 +02240 000001 +02241 000001 +02242 000001 +02243 000001 +02244 000001 +02245 000001 +02246 000001 +02247 000001 +02250 000001 +02251 000001 +02252 000001 +02253 000001 +02254 000001 +02255 000001 +02256 000001 +02257 000001 +02260 000001 +02261 000001 +02262 000001 +02263 000001 +02264 000001 +02265 000001 + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 10 IMP,3050,IMP 7:20 PM 9/16/1973 + + / VDH/IMP DEF MACRO + D VDHD LOC,VDH,IMP + .TA.=. + LOC/ + .TC.=VDH + .TB.=IMP + BSS 1 + ITBVDH+ITBVP/ .TC. + ITBNVD+ITBVP/ .TB. + ITBVDL+ITBVP/ LOC + ITBVP=ITBVP+1 + R 0IF VP MAXVDH-ITBVP,[ + PR "TOO MANY IMP/VDH INSTRS" + ITBVP=ITBVP-1 + ] + 0+0+.TA./ + T + /SAT/IMP DEF (RESTORE) MACRO + D SATDEF A + TIPDEF A,A + T SATDEF + + /MACRO TO COMPUTE 16 BIT ADD CHECKSUM + /FOR ROUTING CODE, USED BY I2MLT AND RTGO + + D K ARG + .TA.=ARG + CHK=0 0 177777"A"[CHK+0+.TA.] + ARG + T K + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 11 IMP,3050,IMP 7:20 PM 9/16/1973 + + /THE STANDARD IMP INTERRUPT LEVELS + M2I=0 /MODEM-TO-IMP RUNS LOCKED + I2M=M2I+2 /IMP-TO-MODEM - SKIP VDI + I2H=I2M+1 /IMP-TO-HOST + H2I=I2H+1 /HOST-TO-IMP + T.O=H2I+1 /TIMEOUT + TSK=T.O+1 /TASK + BCK=TSK+1 /BACKGROUND + + /SOME OTHER LEVEL 0 TYPES + INI=0 /INITIALIZATION + TTY=0 /TELETYPE INTERRUPT + WDI=0 /WATCH DOG TIMER INTERRUPT + RSI=0 /POWER FAIL INTERRUPT + SIN=0 /SOFTWARE INTERRUPT CALLS + ALL=0 /UNINTERRUPTABLE CODE LIKE DXA JMP SEQUENCE + FRE=0 /REFERENCES TO FREE LIST AND COUNT + MSK=0 /REFERENCES TO INTERRUPT MASK + + /VDH LEVELS + VDI=M2I+1 /INPUT INTERRUPT + VDO=I2M /OUTPUT INTERRUPT + VDB=I2H /BACKGROUND RUNS AT IMP-TO-HOST LEVEL + + /TIP LEVELS + TPO=0 /OUTPUT INTERRUPT + TPC=H2I /CLOCK INTERRUPT + TPB=BCK /BACKGROUND + + /MISCELLANEOUS + VAR=75 /VARIABLES + CON=76 /CONSTANTS + UND=77 /UNDEFINED + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 12 IMP,3050,IMP 7:20 PM 9/16/1973 + + /MACROS TO ESTABLISH INTERRUPT LEVELS FOR CODE AND DATA + /XLEV IS HARDWARE LEVEL ESTABLISHED BY SMK INSTRUCTIONS + /YLEV IS SOFTWARE LEVEL ESTABLISHED BY INH INSTRUCTIONS + + XLEV=0 + YLEV=0 + + /MACROS WHICH ASSEMBLE CODE - INT,INH,ENB + + /DECLARE HARDWARE INTERRUPT ENTRANCE ON LEVEL N + D INT N + XLEV=N + YLEV=0 + WORD 0 0 300000+XLEV"T"100+YLEV + 0 + T INT + + /INHIBIT INTERRUPTS FROM LEVELS IN LIST + D INH LIST + R 0IF P,[ + IRP [Q,,LIST] + R 1IF VP 0 0 Q-YLEV, [ + PRINTX /REDUNDANT INH AT / + PNTNUM . + PRINTX / + / ] + ENDIRP + ] + + YLEV=100 + IRP [Q,,LIST] + R 1IF VP 0 0 YLEV-Q,YLEV=Q + ENDIRP + + .INH + WORD 0 0 300000+XLEV"T"100+YLEV + T INH + + /ENABLE HIGHER INTERRUPTS FROM LEVEL N + D ENB N + R 0IF P,[ + R 0IF VZ 0 0 XLEV-N, [ + PRINTX /INCORRECT ENB AT / + PNTNUM . + PRINTX / + / ] + ] + YLEV=N + .ENB + WORD 0 0 300000+XLEV"T"100+YLEV + T ENB + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 13 IMP,3050,IMP 7:20 PM 9/16/1973 + + /MORE INTERRUPT LEVEL MACROS + /MACROS WHICH DO NOT ASSEMBLE CODE - LEV,LCK,RET + + /DECLARE CODE OR DATA TO BE AT LOGICAL LEVELS IN LIST + D LEV LIST + XLEV=100 + IRP [Q,,LIST] + R 1IF VP 0 0 XLEV-Q,XLEV=Q + ENDIRP + YLEV=XLEV + WORD 0 0 300000+XLEV"T"100+YLEV + T LEV + + /DECLARE AN IMPLICIT INH IN CODE + D LCK LIST + R 0IF P,[ + IRP [Q,,LIST] + R 1IF VP 0 0 Q-YLEV, [ + PRINTX /REDUNDANT LCK AT / + PNTNUM . + PRINTX / + / ] + ENDIRP + ] + + YLEV=100 + IRP [Q,,LIST] + R 1IF VP 0 0 YLEV-Q,YLEV=Q + ENDIRP + + WORD 0 0 300000+XLEV"T"100+YLEV + T LCK + + /DECLARE AN IMPLICIT ENB IN CODE + D RET N + R 0IF P,[ + R 0IF VZ 0 0 XLEV-N, [ + PRINTX /INCORRECT RET AT / + PNTNUM . + PRINTX / + / ] + ] + YLEV=N + WORD 0 0 300000+XLEV"T"100+YLEV + T RET + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 14 IMP,3050,IMP 7:20 PM 9/16/1973 + + /SOME SYSTEM PARAMETERS + NH=4 /NO OF REAL HOSTS + FH=4 /NO OF FAKE HOSTS + TH=NH+FH + BH=6 /NO OF BACK HOSTS + CH=5 /NO OF PHONE LINES + NIMP=64. /NO OF IMPS + NACH=8 /NO OF ACK CHANNELS PER LINE + R 0IF VZ DCA, BBNIMP=1 /DCA NCC IMP + R 1IF VZ DCA, BBNIMP=5 /ARPA NCC IMP + BBNTIP=30. /IMP NO OF BBN TIP + PDP1D=305 /HOST PDP-1D AT BBN IMP + DIAGTT=47. /DESTINATION FOR DIAG MESSAGES + H.N=1 /NUMBER OF VDH HOST + M.N=2 /NUMBER OF VDH MODEM (UCSB) + PTCK=60. /NUMBER OF TICKS TO PROP ROUTING + 30SEC=47. /NUMBER OF TICKS IN 30 SECS + MAXH=22. /MAX NO OF HOPS IN NET + NSPD=4 /= OF DIFFFRENT LINE SPDS WE HANDLE + + /WORDS IN BUFFER + IT=1 /INPUT TIME + ST=1 /SENT TIME + PTRT=2 /PNTR TO TRACE BLOCK + INCH=3 /INPUT CHANNEL + ACKH=4 /ACKNOWLEDGE HEADER + HEAD=5 /HEADER - 4 WORDS + HEAD1=6 + CNTL=7 + HEAD2=7 + HEAD3=8 + MINPL=HEAD3 + DATA=9 /BEGINNING OF DATA STORAGE + BUFE=73. /PNTR TO END OF DATA + + /WORDS IN TRACE BLOCK + TIT=1 /TRACE INPUT TIME + TTT=2 /TRACE TASK TIME + TST=3 /TRACE OUTPUT TIME + TAT=4 /TRACE ACKNOWLEDGE TIME + THED=5 /TRACE HEADER (4 WORDS) + TQUE=9 /TRACE QUEUE + TDONE=10. /TRACE DONE (100000=DONE) + + /WORDS IN REASSEMBLY BLOCK + RID=1 /ID # MESS NO + IMP NO + RMAX=2 /NO OF PCKTS MAX + REAS=3 /BLOCK OF 8 PCKT PNTRS + RSF=11. /NO OF PCKTS SO FAR - USED AS 9TH P + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 15 IMP,3050,IMP 7:20 PM 9/16/1973 + + /BITS IN INCH + HSTMOD=100000 /1 IF FROM HOST, 0 IF FROM MODEM + INPCHN=17 /INPUT CHANNEL + + /BITS IN ACKH + ODEVEN=100000 + QUADAC=60000 /WHICH QUADRANT WE ARE ACKING + CHANUM=17400 /CHANNEL NO FOR THIS PKT + ACKBTS=377 /MAX OF 8 ACKS + + /BITS IN HEAD (REG MESSAGE) + MESSNO=177400 + ONEOR8=200 /1= ONE-PACKET + REQALL=100 /TRANSMIT ONLY + RFNM=100 /REPLY ONLY + ORDNO=60 + INCTRN=10 /1= INC (ALSO SET ON RFNM FOR GVB) + TRNREP=4 /1=TRANS, 0=REPLY + GVBALL=2 /TRANSMIT ONLY + ALLOC=2 /REPLY ONLY + LINETS=1 + /BITS IN RUTHED (ROUTING MESSAGE) + SNDCOR=100000 + RUTIMP=37400 /IMPNO TO IDENTIFY LOOPED LINES + IHERDU=20 + RUTDMP=10 /1=CORE DUMP ON FIRST HOP FROM DEAD + GETCOR=4 /1=DEMAND THE IMP TO RELOAD + NULPKT=2 /1=NULL PKT WITH ACKS ONLY + LINETS=1 /1=ROUTING MESSAGE + + /BITS IN HEAD1 + PRIBIT=100000 + FORIMP=40000 + TRACE=20000 + FOROCT=10000 + PKTNO=3400 /TRANSMIT ONLY + PKTN1=400 /LOW ORDER BIT OF PACKET NUMBER + REPDED=400 /REPLY ONLY - DEST DEAD + DESTH=300 + DESTI=77 + DESTHI=377 + + /BITS IN HEAD2 + LSTPKT=100000 + FRMIMP=40000 + FRMOCT=10000 + IHCODE=7400 + HICODE=7400 + ENDBIT=1000 /1=PKT FROM HI NO IMP ON LINE + SRCEH=300 + SRCEI=77 + SRCEHI=377 + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 16 IMP,3050,IMP 7:20 PM 9/16/1973 + + /BITS IN HEAD3 + LINKNO=177760 + SUBCOD=7 /IMP-TO-HOST SUB-CODES + + /BITS IN BUFE + TWOQ=100000 /1 = ON TWO QUEUES (IN PPT) + + /BITS IN TMESS + MESSNO=177400 /LAST MESS NO TRANSMITTED + MESS1=400 /LOW ORDER BIT + MSTO2=200 + MSTO1=100 /2 TIMEOUT BITS + ORDNO=60 /LAST ORDER NO TRANSMITTED + MESBTS=17 /1= MESS ANSWERED + + /BITS IN RMESS + MESSNO=177400 /OLDEST INCOMPLETE MESS NO + 3 + ORDNO=60 /NEXT ORDER NO WE WANT + MESBTS=17 /1= MESS COMPLETE + + /BITS IN AMESS + MESSNO=177400 /NEXT MESS NO TO REPLY TO + + /BITS IN TALLY + SRCEI=77 /FOREIGN IMP WHO ALLOCATED US 8 + + /BITS IN RALLY + ONEOR8=200 + RFNM=100 + + /WORDS IN PPT + PPT0=0 + PPT1=PPTL /HOST STAT TIME SENT + /BITS IN PPT0 + RETRAN=100000 /1= GOT AN ALLOCATE FOR HIM, MUST R + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 17 IMP,3050,IMP 7:20 PM 9/16/1973 + + + /WORDS IN PLT + PLT0=0 + PLT1=PLTL + PLT2=PLTL+PLTL + PLT3=PLTL+PLTL+PLTL /HOST STAT TIME SENT + + /BITS IN PLT0 + MESSNO=177400 + PLTUSE=200 /1 = THIS PLT ENTRY IN USE + REQALL=100 /USEFUL FOR INC TRN + PLTHST=7 /LOCAL HOST NO + + /BITS IN PLT1 + PRIBIT=100000 + FORIMP=40000 + TRACE=20000 + FOROCT=10000 + DESTHI=377 + + /BITS IN RLT2 + LINKNO=177760 + SUBCOD=7 /IMP-TO-HOST SUB-CODES + + /BITS IN TSEX + ACKTAB=377 + + /BITS IN RSEX + ACKTAB=377 + + /IH CODES + CREG=0 /REG + CERRLD=400 /ERROR IN HI LEADER + CERR32=0 /ERROR IN FIRST 32 BITS + CSHORT=1 /LESS THAN 32 BITS IN MESSAGE + CILLGL=2 /ILLEGAL HI CODE + CIMPDN=1000 /IMP GOING DOWN + /BLOCKED LINK + CNOP=2000 /NOP + CRFNM=2400 /RFNM + /LINK TABLE FULL + CDESTD=3400 /DESTINATION DEAD + CIMPD=0 /DEST IMP DEAD + CHSTD=1 /DEST HOST DEAD + CERRDT=4000 /ERROR IN HI DATA + CINCTR=4400 /INCOMPLETE TRANS + CSLOWD=0 /DEST HOST TOOK >30 SECS + CLONG=1 /MORE THAN 8095 BITS + CSLOWS=2 /SOURCE HOST TOOK >15 SECS + CLOST=3 /LOST IN SUBNET + CBLOCK=4 /SOURCE IMP TOOK > 15 SECS + CERROR=4 /ERROR BIT SET (BECOMES CERRDT) + CRESET=5000 /IMP-TO-HOST RESET - READY LINE FLA + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 18 IMP,3050,IMP 7:20 PM 9/16/1973 + + /MACROS TO COLLECT FREE SPACE AND PRINT TABLES + PAGES=32. + BUFL=BUFE+1 + + NBUFS=-1 + + + D PAGEND A,U,E + P /PAGE / PNTNUM A P / + / + FB=0 0 .+0'E + NB=0 + R 1IF VZ A+0-FB"Q"1000, [ + NB=1+0+[0 0 1000"T"[A+1]+0-FB]"Q"BUFL + NBUFS=NBUFS+NB] + 0 0 SPAR+A-2/ FB"A"777-[NB+1]"T"1000 + .TA.=FB+0+NB"T"BUFL + 100004/ + U + FB + .TA. + NB + .ASCII /"Z"/ + 100400+NB+1/ .TB.=FB A + R NB, .TB. .TB.=.TB.+0+BUFL + .ASCII /"Z"/ + .TA./ + T PAGEND + + /FB IS THE ADDRESS OF THE FIRST BUFFER ON THE PAGE + /NB IS THE NUMBER OF BUFFERS BETWEEN THIS PAGE AND THE NEXT + /FORMAT OF SPAR: + /HI 7 BITS = -(NB+1) + /LO 9 BITS = LO 9 BITS OF FB + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 19 IMP,3050,IMP 7:20 PM 9/16/1973 + + 104/ + / CONSTANTS - THESE FIRST FEW MUST NOT MOVE + LEV CON +00104 023033 C DDSAI: DDSA /DDT S.A. START ADDRESS +00105 003050 C VERS: .VERS. /VERSION NUMBER +00106 C MINE: BSS 1 /MY IMP NUMBER + /TIME CONSTANTS IN TERMS OF 640 MS TICKS +00107 177721 C M30SEC: -30SEC /30 SECONDS +00110 177704 C PTICKS: -PTCK /ROUTING PROPAGATION TIME +00111 C ADDRET: BSS 1 /CHKSM ADDER RETURN +00112 100000 C SIGN: 100000 +00113 000000 C ZERO: 0 +00114 000001 C ONE: 1 +00115 000002 C TWO: 2 +00116 000003 C THREE: 3 +00117 000004 C FOUR: 4 +00120 000007 C SEVEN: 7 +00121 177777 C MINUS1: -1 +00122 177776 C MINUS2: -2 +00123 177775 C MINUS3: -3 +00124 177774 C MINUS4: -4 +00125 177773 C MINUS5: -5 +00126 177772 C MINUS6: -6 +00127 177773 C MICH: -CH +00130 000004 C PLNH: NH +00131 177770 C MITH: -TH + MIN100: +00132 177700 C MINIMP: -NIMP +00133 000000 C RSFLAG: 0 /FLAG TO DETECT WDT AND RELOADS + /0=NONE, 1=RESTART, 2=RELOAD, 3=WDT, 4=POWER FAIL + LEV VAR +00134 V PRIM: BSS 1 /PRIORITY INTERRUPT MASK + + /NCC OPERATIONS LOCATIONS 135-157 MUST NOT MOVE! + LEV CON + DEFPLC [DDT STAND ALONE ENTRY] +00135 102104 C DDT: JMP DDSAI I +00136 000000 C TIPRSF: 0 /ASSEMBLE IN A ZERO + DEFPLC [NICE-STOP AND RELOAD FLAG] +00137 C SW3FG: BSS 1 /ZERO=NICE STOP, THEN RELOAD + />0=SPECIFIC LINE + DEFPLC [NICE-STOP AND RESTART FLAG] +00140 C NRSTF: BSS 1 /ZERO=NICE STOP, THEN RESTART + /ONE=VDH RESTART + DEFPLC [HOST & MODEM INTERFACE CONTROL] +00141 C HTPAR: BSS 1 /MODEM TEST FLAG + DEFPLC [HOST INTERFACE TEST ENABLE AND TEST WORD] +00142 C HLNM: BSS 1 /# OF INTERFACE BEING TESTED +00143 177400 C HL2WD: 177400 /SECOND WORD OF DATA - ONLY LEFT HA + DEFPLC [VDH RESTART FLAG] +00144 000000 C VDHRSF: 0 /SET NON-ZERO TO RESTART VDH + DEFPLC [SAT RESTART FLAG] +00145 000000 C SATRSF: 0 + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 20 IMP,3050,IMP 7:20 PM 9/16/1973 + + PG0FIX=160 /START OF 2ND INVARIANT AREA + .TA.=. + 100002/ .TA. PG0FIX + .ASCII /"Z"/ PG0FIX/ + LEV VAR + ZEROB: /START ZEROING HERE + DEFPLC [NEIGHB] + /USED BY [M2I,TSK,BCK] +00160 V NEIGHB: BSS CH /IMP NUMBER OF ADJACENT IMP + DEFPLC [RUT] + /USED BY [H2I,T.O,TSK,BCK] +00165 V RUT: BSS NIMP /ROUTE USE TABLE + DEFPLC [SLT] + /USED BY [M2I,I2M,T.O,BCK] +00265 V SLT: BSS CH /SEND LINE TEST (USED FOR RELOAD [ + + QUEUEB: /QUEUE START POINTERS + /MUST PRECEDE COUNTA + /USED BY [I2H,TSK] +00272 V SHQ: BSS TH /REG HOST +00302 V SHPQ: BSS TH /PRI HOST + /USED BY [I2M,T.O,TSK] +00312 V SMQ: BSS CH /REG MODEM +00317 V SMPQ: BSS CH /PRI MODEM + /USED BY FRE +00324 V FREE: BSS 1 /FREE BUFFERS + /USED BY [TSK,BCK] +00325 V TTF: BSS 1 /FREE TRACE BLOCKS + /USED BY [T.O,TSK] +00326 V RASF: BSS 1 /FREE REASSEMBLY BLOCKS +00327 V MESSTK: BSS 1 /STACK OF COMPLETE REG MESSAGES + /USED BY [M2I,H2I,TSK,BCK] +00330 V STQ: BSS 1 /TASK + /USED BY [T.O,TSK,BCK] +00331 V SRQ: BSS 1 /REPLY,REROUTE,DEST DEAD + /USED BY [I2H,H2I,T.O.TSK,BCK] +00332 V SHWQ: BSS NH+1 /HOST WORD +00337 V SHBQ: BSS 1 /HOST ONE WORD BUFFERS + /USED BY [T.O,TSK] +00340 V SHRQ: BSS 1 /REASSEMBLY BLOCKS + /USED BY [TSK,BCK] +00341 V STRQ: BSS 1 /TRACE BLOCKS + /USED BY [ALL] +00342 V DIAGQ: BSS 1 /DIAG PACKET QUEUE + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 21 IMP,3050,IMP 7:20 PM 9/16/1973 + + QUEUEE: /QUEUE END POINTERS + /USED BY [I2H,TSK] +00343 V EHQ: BSS TH +00353 V EHPQ: BSS TH + /USED BY [I2M,T.O,TSK] +00363 V EMQ: BSS CH +00370 V EMPQ: BSS CH +00375 V BSS 4 /SPARE + /USED BY [M2I,H2I,TSK,BCK] +00401 V ETQ: BSS 1 + /USED BY [T.O,TSK,BCK] +00402 V ERQ: BSS 1 + /USED BY [I2H,H2I,T.O,TSK,BCK] +00403 V EHWQ: BSS NH+1 +00410 V BSS 4 /SPARE + + QUEUEL=QUEUEE-QUEUEB + /USED BY [TSK,BCK] +00414 V TTO: BSS 1 /TRACE TABLE OVERFLOW + /USED BY ALL +00415 V TIME: BSS 1 /TIME IN FAST T1CKS + /USED BY [I2H,T.O,TSK] +00416 V TIMES: BSS 1 /TIME IN SLOW TICKS + /USED BY [T.D,BCK] +00417 V SYNC: BSS 1 /TIME FOR STAT ROUTINES + /USED BY [M2I,T.O] +00420 V THD: BSS 1 /CHANNEL TO MAX NO IMP + /USED BY [I2M,TSK] +00421 V SIHY: BSS CH /SEND I HEARD YOU IF NOT ZERO + /USED BY [T.O,TSK] +00426 V LAC: BSS CH /LINE ALIVE COUNT + /USED BY [M2I,T.O,TSK] +00433 V LINE: BSS CH /LINE ALIVE-DEAD STATUS + /USED BY [I2M,T.O,TSK] +00440 V NONE: BSS CH /MODEM IDLE IF ZERO + /NEGATIVE= -(M30SEC-NO OF SLOW TICKS SINCE LAST OUTPUT) +00445 V SNULL: BSS CH /SEND NULL PKT IF NON-ZERO + /USED 5Y [M2I,T.O,TSK] +00452 V LUUP: BSS 1 /NON-ZERO=SOME MODEM IS LOOPED + /USED BY [H2I,TSK,BCK] + TSKFLG: /TASK-HOST COMMUNICATION + DEFPLC [HILO] +00453 V HILO: BSS TH /RETURN ADDRESSES WHERE HI LEFT OFF +00463 V BSS BH /0=NO ACTION, 1=NACK, 2=ACK + /USED BY BCK +00471 V BSS 1 /TO PRESERVE P0 LOCATIONS +00472 V DDTI: BSS 1 /DDT INTERRUPT FLAG +00473 V OVRDF: BSS 1 /SS4 IS OVERRIDDEN IF THIS IS NON, + /USED BY [TTY,BCK] +00474 V TTFG: BSS 1 /TTY COMMUNICATION SWITCH + /USED BY VD5 +00475 V VD.OT: BSS 1 /VDH TYPE OF OUTPUT FLAG + /USED BY T.O +00476 V VD.RDY: BSS 1 /NON-ZERO=VDH READY LINE FLAPPED + /USED BY [I2H,T.O,TSK,BCK] +00477 V RALLCF: BSS 1 /RALLY COMMUNICATION FLAG FOR PUT-G + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 22 IMP,3050,IMP 7:20 PM 9/16/1973 + + /USED BY MSK +00500 V IHM: BSS 1 /IH MASK +00501 V HIM: BSS 1 /HI MASK +00502 V MOM: BSS 1 /MODEM OUT MASK + /USED BY [T.O,I2H(OWP)] +00503 V WDTIME: BSS 1 /SOFTWARE W.D.T. + /USED BY [H2I,I2H.T.O,TSK,BCK] +00504 V HIHD: BSS TH /HOST STATUS + HSTUP=0 /HOST IS UP + HSTGDN=1 /GOT A HOST-GOING-DOWN MESSAGE + HSTTRD=2 /HOST WAS TARDY IN ACCEPTING AN IMP MESSAGE + HSTOFF=3 /HOST READY LINE IS DOWN + HSTIDN=4 /IMP IS COMING UP OR GOING DOWN + /USED BY TSK +00514 V THIS: BSS 1 /CURRENT TASK BUFFER + /USED BY FRE +00515 V TWDP: BSS 1 /SECOND WORD IN TWO WORD PUT + /USED BY I2H +00516 V TWDG: BSS 1 /SECOND WORD IN TWO WORD GET + + COUNTA: /ADDITIVE COUNTS - KEEP IN ORDER + /USED BY [I2H,TSK] +00517 V NHA: BSS TH /REG HOST QUEUE +00527 V BSS TH /PRI HOST QUEUE + /USED BY FRE +00537 V NFA: BSS 1 /FREE LIST + /USED BY [M2I,I2M,T.O,TSK] +00540 V NSFA: BSS 1 /STORE-AND-FORWARD COUNT + /USED BY [I2H,T.O,TSK] +00541 V NREA: BSS 1 /REASSEMBLY COUNT + /USED BY [T.O,TSK,5CK] +00542 V NALA: BSS 1 /ALLOCATE COUNT + + COUNTS: /SUBTRACTIVE COUNTS + /USED BY [I2H,TSK] +00543 V NHS: BSS TH +00553 V BSS TH + /USED BY FRE +00563 V NFS: BSS 1 + /USED BY [M2I,I2M,T.O,TSK] +00564 V NSFS: BSS 1 + /USED BY [I2H,T.O,TSK] +00565 V NRES: BSS 1 + /USED BY [T.O,TSK,BCK] +00566 V NALS: BSS 1 + COUNTL=COUNTS-COUNTA + + /USED BY [BCK] +00567 V VDHUPF: BSS 1 /VDH UP/DOWN FLAG + ZEROE: + ZEROL=ZEROE-ZEROB + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 23 IMP,3050,IMP 7:20 PM 9/16/1973 + + LEV CON +00570 000004 C MINF: CH-1 /MIN NUMBER OF FREE BUFFERS +00571 C MAXS: BSS 1 /MAX NUMBER OF S/F PACKETS +00572 C MAXR: BSS 1 /MAX NUMBER OF REASSEMBLY PACKETS +00573 C MAXSI: BSS 1 /S&F LIMIT USED BY MODEM TASK +00574 C SW1: BSS MAXSTAT /ADDRES OF STAT GATHERING SUBRS + +00622 032030 C I2MTAB: I2MB0 /START ADDR OF BLOCK OF CHANNEL PNT +00623 032040 C I2MB1 +00624 032050 C I2MB2 +00625 032060 C I2MB3 +00626 032070 C I2MB4 + LEV VAR +00627 V I2MEND: BSS CH /END ADDRESS OF EACH BLOCK +00634 V I2MNXT: BSS CH /PKT PNTR FOR LATEST OUTPUT + /0=ROUTE,NULL,OR NO OUTPUT, SIGN ON=ACK RECEIVED WHILE PKT O + DEFPLC [TSEX - TRANSMIT ODD-EVEN BITS] +00641 V TSEX: BSS CH /ODD-EVEN BIT TO USE FOR NEXT OUTF + DEFPLC [RSEX - RECEIVE ODD-EVEN BITS] +00646 V RSEX: BSS CH /COMP OF ODD-EVEN BIT WE EXPECT NEX + /USED BY [M2I,TSK] +00653 V CHFREE: BSS CH +00660 V RST.O: BSS 1 /PTR TO RM OUTPUT AREA +00661 V RST.F: BSS 1 / " " " FREE " +00662 V RST.N: BSS 1 / " " " NEW " +00663 V RST.C: BSS 1 / " " " COMPARE " + + LEV CON /ADDRESS CONSTANTS +00664 013210 C JAM: GAM /GIVE A WORD FROM FAKE HOST TO IMP +00665 003234 C DOZE: BKX /JAM WAIT +00666 017347 C SUCK: SUC /GET A WORD FOR FAKE HOST FROM IMP +00667 003240 C WAIT: BKW /SUCK WAIT +00670 015371 C OWP: OWPE /ENTRY INTO ONE WORD PUT +00671 005373 C FLUSHI: FLUSH /PNTR TO SUBR TO FREE BUFFER +00672 017343 C DODXA: .DODXA /ENTRY INTO DO DXA SUBROUTINE + DEFPLC [HOST SIMULATOR FLAG] +00673 000000 C HSFG: 0 /NON-ZERO = START UP HOST SIMULATOR + + LEV VAR +00674 V MP: BSS 1 /MODEM-TO-IMP CURRENT MODEM NO +00675 V HIP: BSS 1 /HOST-TO-IMP CURRENT HOST NO +00676 V IHP: BSS 1 /IMP-TO-HOST CURRENT HOST NO + LEV CON +00677 053333 C HIXX: HISP 0 X /HOST-TO-IMP INDEXED SAVE PNTR +00700 056155 C IHXX: IHSP 0 X /IMP-TO-HOST INDEXED SAVE PNTR + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 24 IMP,3050,IMP 7:20 PM 9/16/1973 + + TIPCON=745 + .TA.=. + 100002/ .TA. TIPCON + .ASCII /"Z"/ + + /LINKS TO TIP PROGRAM + TIPHST=2 /THE TIP TAKES THE HOST 2 SLOT + TIPBKG=40001 + TIPVER=40000 + + TIPCON/ +00745 022404 C HLTNCC: HLTWRD /PNTR TO HALT REPORTING SUBR +00746 000000 C HLTLOC: 0 /PC OF LAST HALT +00747 C HLTA: BSS 1 /A REG AT LAST HALT +00750 C HLTX: BSS 1 /X REG AT LAST HALT + 8PKTS: /NO OF PKTS PER MESSAGE + CMINPL: /MIN PKT LENGTH +00751 000010 C TEN: 10 0"A"MINPL +00752 000077 C C77: 77 +00753 000100 C C100: 100 +00754 C BSS 9. /SOME ROOM FOR TIP CONSTANTS +00765 000000 C TPOPEN: 0 /COUNT OF NO OF OPEN CONNECTIONS ON +00766 016177 C IHLSTP+TIPHST /MINUS IF LAST IMP-TO-TIP PKT +00767 021664 C TIPSKP /SKP IF TIP UP, NOP IF TIP DOWN +00770 C TIPLNK: BSS 1 /IMP-TO-TIP DMC DUTPUT PNTR +00771 C BSS 1 /IMP-IO-TIP OMC OUTPUT END PNTR +00772 C BSS 1 /TIP-TO-IMP DMC INPUT PNTR +00773 C BSS 1 /TIP-TO-IMP DMC INPUT END PNTR +00774 000000 C 0 /(IMP-TO-TIP PKT RNTR) +00775 013315 C EMFH+TIPHST /SKP IF LAST TIP-TO-IMP PKT, ELSE +00776 013141 C HITT+TIPHST /TIP-TO-IMP INTERFACE TIMER +00777 C BSS 1 /LOC 777 USED BY RELOAD CODE + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 25 IMP,3050,IMP 7:20 PM 9/16/1973 + + + /WATCHDOG TIMER AND POWER FAIL ROUTINES + + /THESE 2 INSTRS FOLLOW A COMPUTED SKS MODEM ERROR IN PAGE 0 + LEV WDI +01000 003111 0 JMP LD10 +01001 003031 0 JMP WDLUP +01002 001177 0 WDC4: WDT1 +01003 003021 0 JMP WDTM2 /START HERE TO LOAD FROM THE NET +01004 003022 0 JMP WDLOD /START HERE TO LOAD FROM A LINE + + DEFPLC [HOST34 SWITCH] +01005 0 HOST34: BSS 1 /MEANING OF BITS 1&2 FOLLOWS + /0 FOR 5 MODEMS + />0 FOR 4 MODEMS, 3 HOSTS + /<0 FOR 3 MODEMS, 4 HOSTS + /USE >0 FOR TIP/MLC + /BIT 16 ZERO MEANS PAGE 27 IS BUFFERS + /BIT 16 NON-ZERO MEANS PAGE 27 IS NOT TO BE OVERLAID WITH BU] + /VDHF INDICATES WHETHER VDH CODE IS ACTUALLY PRESENT + +01006 0 BSS 3 /FOR COMPATIBILITY WITH IMPLOD 2513 + + /** THIS IS THE CRITICAL CODE WHICH MUST NOT CHANGE ** + /** BOTH LOCATION AND CONTENTS MUST STAY CONSTANT ** + /** IN ORDER THAT ONE IMP VERSION MAY RELOAD ANOTHER ** +01011 010045 0 LWAIT: STA 45 /**THIS IS WHERE THE IMP WAITS +01012 024045 0 IRS 45 /**AFTER SENDING A REQUEST FOR CORE +01013 003012 0 JMP .-1 /**THIS CODE IS OVERLAID WITH THE +01014 024044 0 IRS 44 /**NEW CORE IMAGE WHILE IT IS RUN: +01015 003011 0 JMP LWAIT /**SO IT MUST BE INVARIANT ITSELF +01016 003102 0 JMP LD7 + + CORELO=60 + COREHI=33000 + /CORE IMAGE IS LOADED STARTING AT CORELO + /AND ENDING AT COREHI-1 + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 26 IMP,3050,IMP 7:20 PM 9/16/1973 + + WDTM: +00062 001017 0 WDTIL/ WDTM +01017 000000 0 WDTM/ INT WDI +01020 024133 0 IRS RSFLAG +01021 140040 0 WDTM2: CRA /ENTER HERE FOR RANDOM RELOAD + LEV BCK /COME HERE FROM NICE STOP CODE +01022 001001 7 WDLOD: INH ALL /ENTER HERE WITH LINE # (1-4) IN AC +01023 030040 7 0 CLKON +01024 017560 7 0 SUB (1) +01025 041577 7 0 ALS 1 +01026 010047 7 0 STA 47 +01027 005005 7 0 LDA HOST34 /SAVE HOST CONFIGURATION +01030 010046 7 0 STA 46 /SHOULD BE 51 + /LDA RSFLAG /SAVE RESTART-RELOAD FLAG + /STA 43 +01031 005037 7 0 WDLUP: LDA LD8 +01032 101000 7 0 NOP /FOR FILLER +01033 000201 7 0 IAB +01034 005561 7 0 LDA (-23) /DON'T LET CLOCK INTS IN +01035 000011 7 0 DXA +01036 003154 7 0 JMP CLEA +01037 001040 7 0 LD8: .+1 +01040 004047 7 0 LDA 47 +01041 101400 7 0 SMI /RANDOM RELOAD? +01042 003046 7 0 JMP LD11 /NO +01043 131040 7 0 RDCLOK /YES +01044 003043 7 0 JMP .-1 +01045 007562 7 0 ANA (6) /GET TWO BIT NUMBER +01046 010000 7 0 LD11: STA 0 +01047 005563 7 0 LDA (SENDC) /SET UP REQUEST FOR CORE +01050 050032 7 0 STA M1OTBP X +01051 015564 7 0 ADD (4) +01052 050033 7 0 STA M1OTBP+1 X +01053 005565 7 0 LDA (CORELO 0 I) /SET UP CORE IMAGE BOUNDS +01054 050020 7 0 STA M1INBP X +01055 005566 7 0 LDA (COREHI 0 I) +01056 050021 7 0 STA M1INBP+1 X +01057 143137 7 0 JMP LDT XI +01060 030071 7 0 LD1: M1OUT /SEND OUT REQUEST FOR CORE +01061 003213 7 0 JMP LD12 +01062 003073 7 0 JMP LD5 +01063 030072 7 0 LD2: M2OUT +01064 003213 7 0 JMP LD12 +01065 003073 7 0 JMP LD5 +01066 030073 7 0 LD3: M3OUT +01067 003213 7 0 JMP LD12 +01070 003073 7 0 JMP LD5 +01071 030074 7 0 LD4: M4OUT +01072 003213 7 0 JMP LD12 +01073 005567 7 0 LD5: LDA (-3000.) +01074 010044 7 0 STA 44 + /JMP LWAIT + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 27 IMP,3050,IMP 7:20 PM 9/16/1973 + + /NOP /TO KEEP LOC OF LD6 CONSTANT + /THE NEXT 5 REGS CAN COME OUT AFTER COMPATIBILITY WITH 2634 +01075 010045 7 0 LD6: STA 45 +01076 024045 7 0 IRS 45 +01077 003076 7 0 JMP .-1 +01100 024044 7 0 IRS 44 +01101 003075 7 0 JMP LD6 +01102 044020 7 0 LD7: LDA M1INBP X +01103 013566 7 0 ERA (COREHI 0 I) +01104 100040 7 0 SZE +01105 003031 7 0 JMP WDLUP +01106 045140 7 0 LDA LDERR X +01107 010777 7 0 STA 777 +01110 002777 7 0 JMP 777 + +01111 031040 7 0 LD10: CLKOFF +01112 004046 7 0 LDA 46 /SHOULD BE 51 /RESTORE HOST C +01113 011005 7 0 STA HOST34 + /LDA 43 /RESTORE RESTART-RELOAD FLAG + /STA RSFLAG +01114 073570 7 0 LDX (56-104) /SAVE INTERRUPT ENTRANCES +01115 044104 7 0 LDA 104 X +01116 111571 7 0 STA (30000 0 X) I +01117 024000 7 0 IRS 0 +01120 003115 7 0 JMP .-3 +01121 005127 7 0 LDA LD9 +01122 000201 7 0 IAB +01123 005572 7 0 LDA (-21) +01124 070042 7 0 AMIMLC +01125 005573 7 0 LDA (-1) +01126 003154 7 0 JMP CLEA +01127 001130 7 0 LD9: .+1 +01130 073570 7 0 LDX (56-104) /RESTORE INTERRUPT ENTRANCES +01131 105571 7 0 LDA (30000 0 X) I +01132 050104 7 0 STA 104 X +01133 024000 7 0 IRS 0 +01134 003131 7 0 JMP .-3 +01135 024133 7 0 IRS RSFLAG +01136 103574 7 0 JMP (INIT) I +01137 001060 7 0 LDT: LD1 +01140 070471 7 0 LDERR: M1ERR +01141 001063 7 0 LD2 +01142 070472 7 0 M2ERR +01143 001066 7 0 LD3 +01144 070473 7 0 M3ERR +01145 001071 7 0 LD4 +01146 070474 7 0 M4ERR + +01147 040001 7 0 SENDC: 40001 +01150 100001 7 0 SNDCOR 0 LINETS +01151 000000 7 0 0 +01152 000000 7 0 0 +01153 040001 7 0 -[40001 0 SNDCOR LINETS -3] + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 28 IMP,3050,IMP 7:20 PM 9/16/1973 + +01154 170120 7 0 CLEA: SMK 120 + LEV BCK LCK ALL +01155 073575 7 0 LDX (STDIL-0-TASKIL) +01156 005002 7 0 LDA WDC4 +01157 050104 7 0 STA TASKIL+1 X /RESET ALL INTERRUPT ENTRANCES +01160 024000 7 0 IRS 0 +01161 003157 7 0 JMP .-2 +01162 073576 7 0 LDX (-2) /MUST UNPATCH TWICE 1? +01163 030171 7 0 WDT2: M1UNXP +01164 030172 7 0 M2UNXP +01165 030173 7 0 M3UNXP +01166 030174 7 0 M4UNXP +01167 030175 7 0 M5UNXP +01170 030470 7 0 HUNXPT: H1UNXP /THESE MUST BE IN ORDER11 +01171 030460 7 0 H2UNXP +01172 030450 7 0 H3UNXP +01173 030451 7 0 H4UNXP +01174 024000 7 0 IRS 0 +01175 003163 7 0 JMP WDT2 +01176 021177 7 0 JST WDT1 /AND WAIT + +01177 000000 7 0 WDT1: 0 /NULL INTERRUPT ENTRY +01200 000011 7 0 DXA /ALL INTERRUPTS COME HERE TO DIE +01201 003202 7 0 JMP . 1 +01202 000401 7 0 ENB BCK +01203 073577 7 LDX (0) +01204 024000 7 IRS 0 +01205 003204 7 JMP .-1 /WAIT 600 MS +01206 000201 7 IAB /5=>X +01207 026000 7 IMA 0 /0=>A +01210 170120 7 SMK 120 /NOW WE BLOCK ALL FUTURE INTERRUPTS + LEV WDI +01211 001001 0 INH ALL +01212 042000 0 JMP 0 X /GO TO LD8+1 +01213 005600 0 LD12: LDA (-533.) +01214 010044 0 STA 44 +01215 010045 0 LD13: STA 45 +01216 024045 0 IRS 45 +01217 003216 0 JMP .-1 +01220 024044 0 IRS 44 +01221 003215 0 JMP LD13 +01222 043223 0 JMP .+1 X +01223 030471 0 M1IN +01224 003073 0 JMP LD5 +01225 030472 0 M2IN +01226 003073 0 JMP LD5 +01227 030473 0 M3IN +01230 003073 0 JMP LD5 +01231 030474 0 M4IN +01232 003073 0 JMP LD5 + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 29 IMP,3050,IMP 7:20 PM 9/16/1973 + + LEV CON +01233 000001 C BITTAB: 1 /BITS FOR ACK AND MESSAGE STUFF +01234 000002 C 2 +01235 000004 C 4 +01236 000010 C 10 +01237 000020 C 20 +01240 000040 C 40 +01241 000100 C 100 +01242 000200 C SWCHB: 200 +01243 000400 C 400 +01244 001000 C 1000 +01245 002000 C 2000 + +01246 000010 C MBITS: 10 +01247 000004 C 4 +01250 000002 C 2 +01251 000001 C 1 + + SWDT: +00061 001252 C SWDTIL/ SWDT /SOFTWARE W-D-T INTERRUPT CALL + SWDT/ +01252 000000 0 INT WDI +01253 001001 0 INH ALL +01254 111601 0 STA (37775) I /SAVED A +01255 133602 0 STX (37776) I /SAVED X +01256 005252 0 LDA SWDT /IF NOT MEM PROTECT (MAY NEED TO BE +01257 111603 0 STA (37774) I /SAVED P/Y +01260 120062 0 JST WDTIL I + + RSTR: /POWER FAIL COMES HERE +00060 001261 0 PFIL/ RSTR +01261 000000 0 RSTR/ INT RSI +01262 030026 0 WDT /POKE WATCHDOG TIMER SO WE DON'T ( +01263 140040 0 CRA +01264 010324 0 STA FREE /COPY SOME PROGRAM INTO PAGE 0 +01265 005604 0 LDA (3) +01266 010133 0 STA RSFLAG /SO THAT RESTART WILL INDICATE POWE +01267 005273 0 LDA RST2A /THESE ARE FOR WHEN THE POWER COMES +01270 010517 0 STA NHA +01271 073274 0 LDX RST3 +01272 002324 0 JMP FREE /GO LOCK UP THE MACHINE +01273 002000 0 RST2A: 2000 +01274 102517 0 RST3: JMP NHA I + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 30 IMP,3050,IMP 7:20 PM 9/16/1973 + + + /CORE DUMP TO PDP-1D AT BBN + /COPY EACH 100-WORD BLOCK OF CORE INTO CORBUF=>CORBUF+77 + /SEND BLOCK 1 FROM ITSELF, THEN 2-277 (OR HIGHER), THEN BLOC. + /USE CORBUF-4=>CORBUF-1 AS HEADER AND TEMP STORE + CORBUF=100 + CORCNT=CORBUF-4 /ACKH - USE AS TEMP + CORHED=CORBUF-3 /HEAD - FIXED HEADER, GOES AS ROUTI1 + CORPUT=CORBUF-2 /HEAD1 - USE AS TEMP + CORGET=CORBUF-1 /HEAD2 - FIRST LOCATION OF BLOCK BE + /HEAD3 THRU BUFE-1 ARE 100 DATA WOR] + + LEV BCK + DEFPLC [CORE DUMP] +01275 001001 7 CORE: INH ALL +01276 000013 7 0 EXA +01277 030451 7 0 H4UNXP +01300 030551 7 0 H4ENAB +01301 030251 7 0 H4FOUT +01302 000201 7 0 IAB /ENTER WITH LINE NO 1-5 IN AC +01303 073605 7 0 LDX (-104) +01304 044200 7 0 LDA CORCNT+104 X +01305 051551 7 0 STA CORSAV+104 X /SAVE CORBUF-4=>CORBUF+77 +01306 024000 7 0 IRS 0 +01307 003304 7 0 JMP .-3 +01310 024000 7 0 IRS 0 +01311 003310 7 0 JMP .-1 /WAIT FOR READY LINE +01312 000201 7 0 IAB +01313 041577 7 0 ALS 1 +01314 010000 7 0 STA 0 /SAVE 2*MODEM NO +01315 131041 7 0 RDIMPN +01316 003315 7 0 JMP .-1 +01317 013606 7 0 ERA (BBNIMP) +01320 101040 7 0 SNZ /ARE WE THE BBN IMP? +01321 010000 7 0 STA 0 /YES, THEN WE SEND CORE OUT TO HOST +01322 005607 7 0 LDA (RUTDMP 0 LINETS) +01323 010075 7 0 STA CORHED /SET UP FIXED HEADER +01324 005610 7 0 LDA (CORBUF) +01325 010077 7 0 STA CORGET /SET UP BLOCK TO COPY FROM + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 31 IMP,3050,IMP 7:20 PM 9/16/1973 + +01326 004000 7 0 CORNXT: LDA 0 +01327 100040 7 0 SZE /ARE WE SENDING TO A HOST? +01330 005611 7 0 LDA (CORPUT-CORCNT) /NO, NEED FULL HEADER FC +01331 015612 7 0 ADD (CORCNT) /NEED ONLY LEADER TO HOST +01332 050030 7 0 STA H4OTBP X /SET UP DMC PNTRS +01333 005613 7 0 LDA (CORBUF+77) +01334 050031 7 0 STA H4OTBP+1 X +01335 005610 7 0 LDA (CORBUF) +01336 010076 7 0 STA CORPUT /SET UP BLOCK TO COPY INTO +01337 140407 7 0 TCA +01340 010074 7 0 STA CORCNT /SET UP COPY COUNT +01341 004077 7 0 LDA CORGET +01342 100040 7 0 SZE /ARE WE DOING BLOCK 0? +01343 003347 7 0 JMP CORCOP /NO +01344 024077 7 0 IRS CORGET /YES, START WITH REG 1 +01345 024076 7 0 IRS CORPUT /SINCE CORBUF HAS HIGHEST CORE BLOC1 +01346 024074 7 0 IRS CORCNT +01347 104077 7 0 CORCOP: LDA CORGET I /DO THE COPY +01350 110076 7 0 STA CORPUT I +01351 024077 7 0 IRS CORGET +01352 024076 7 0 IRS CORPUT +01353 024074 7 0 IRS CORCNT +01354 003347 7 0 JMP CORCOP +01355 043356 7 0 JMP COROCP X /DO OCP OUTPUT + +01356 030251 7 0 COROCP: H4FOUT +01357 003371 7 0 JMP CORWAT +01360 030071 7 0 M1OUT +01361 003371 7 0 JMP CORWAT +01362 030072 7 0 M2OUT +01363 003371 7 0 JMP CORWAT +01364 030073 7 0 M3OUT +01365 003371 7 0 JMP CORWAT +01366 030074 7 0 M4OUT +01367 003371 7 0 JMP CORWAT +01370 030075 7 0 M5OUT + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 32 IMP,3050,IMP 7:20 PM 9/16/1973 + +01371 004077 7 0 CORWAT: LDA CORGET +01372 013610 7 0 ERA (CORBUF) +01373 101040 7 0 SNZ /DID WE JUST SEND BLOCK 0? +01374 003426 7 0 JMP COREND /YES +01375 005614 7 0 LDA (100000) +01376 010074 7 0 STA CORCNT +01377 024074 7 0 IRS CORCNT +01400 003377 7 0 JMP .-1 /WAIT +01401 030026 7 0 WDT /JUST IN CASE +01402 004077 7 0 LDA CORGET +01403 017615 7 0 SUB (30000) +01404 100400 7 0 SPL /HAVE WE DONE FIRST 12K YET? +01405 003326 7 0 JMP CORNXT /NO, KEEP GOING +01406 104077 7 0 LDA CORGET I /YES, NOW WE MUST CHECK FOR PRESENC1 +01407 140401 7 0 CMA /ABOVE 12K MINIMUM +01410 126077 7 0 IMA CORGET I +01411 122077 7 0 CAS CORGET I +01412 100000 7 0 SKP +01413 003416 7 0 JMP .+3 /NO TRANSITION, NO MORE MEMORY +01414 110077 7 0 STA CORGET I /RESTORE TEST CELL +01415 003326 7 0 JMP CORNXT /AND KEEP GOING +01416 140040 7 0 CRA +01417 026077 7 0 IMA CORGET /RESET PTR TO BLOCK 0 +01420 010100 7 0 STA CORBUF /SAVE HIGHEST CORE BLOCK IN CORBUF +01421 131041 7 0 RDIMPN +01422 003421 7 0 JMP .-1 +01423 012100 7 0 ERA CORBUF /PUT IMP NO IN RIGHT PART OF REG C +01424 010100 7 0 STA CORBUF +01425 003326 7 0 JMP CORNXT /GO BACK AND SEND BLOCK 0 + +01426 073616 7 0 COREND: LDX (-4) +01427 045451 7 0 LDA CORSAV+4 X +01430 050200 7 0 STA CORCNT+CORBUF+4 X +01431 024000 7 0 IRS 0 /RESTORE CORBUF-4=>CORBUF-1 IN THE +01432 003427 7 0 JMP .-3 +01433 024000 7 0 IRS 0 +01434 003433 7 0 JMP .-1 /WAIT +01435 073605 7 0 LDX (-104) +01436 045551 7 0 LDA CORSAV+104 X +01437 050200 7 0 STA CORCNT+104 X /RESTORE CORBUF-4=>CORBUF +01440 024000 7 0 IRS 0 +01441 003436 7 0 JMP .-3 +01442 030026 7 0 WDT +01443 000000 7 0 HLT /DONE +01444 003442 7 0 JMP .-2 + CORSAV: /SAVE SPACE FOR CORBUF-4=>CORBUF+77 + /NEXT 104 LOCS USED BY COR DMP + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 33 IMP,3050,IMP 7:20 PM 9/16/1973 + + /THIS CODE IS THE ADD CHAIN WHICH COMPUTES PACKET CHECKSUMS + /IT IS RE-ENTRANT AND IS CALLED BY DIFFERENT INTERRUPTS + LEV ALL +01445 054115 0 ADDTOP: ADD BUFE+4 X +01446 054114 0 ADD BUFE+3 X +01447 054113 0 ADD BUFE+2 X +01450 054112 0 ADD BUFE+1 X +01451 054111 0 ADD BUFE X +01452 054110 0 ADD BUFE-1 X +01453 054107 0 ADD DATA+76 X +01454 054106 0 ADD DATA+75 X +01455 054105 0 ADD DATA+74 X +01456 054104 0 ADD DATA+73 X +01457 054103 0 ADD DATA+72 X +01460 054102 0 ADD DATA+71 X +01461 054101 0 ADD DATA+70 X +01462 054100 0 ADD DATA+67 X +01463 054077 0 ADD DATA+66 X +01464 054076 0 ADD DATA+65 X +01465 054075 0 ADD DATA+64 X +01466 054074 0 ADD DATA+63 X +01467 054073 0 ADD DATA+62 X +01470 054072 0 ADD DATA+61 X +01471 054071 0 ADD DATA+60 X +01472 054070 0 ADD DATA+57 X +01473 054067 0 ADD DATA+56 X +01474 054066 0 ADD DATA+55 X +01475 054065 0 ADD DATA+54 X +01476 054064 0 ADD DATA+53 X +01477 054063 0 ADD DATA+52 X +01500 054062 0 ADD DATA+51 X +01501 054061 0 ADD DATA+50 X +01502 054060 0 ADD DATA+47 X +01503 054057 0 ADD DATA+46 X +01504 054056 0 ADD DATA+45 X +01505 054055 0 ADD DATA+44 X +01506 054054 0 ADD DATA+43 X +01507 054053 0 ADD DATA+42 X +01510 054052 0 ADD DATA+41 X +01511 054051 0 ADD DATA+40 X + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 34 IMP,3050,IMP 7:20 PM 9/16/1973 + +01512 054050 0 ADD DATA+37 X +01513 054047 0 ADD DATA+36 X +01514 054046 0 ADD DATA+35 X +01515 054045 0 ADD DATA+34 X +01516 054044 0 ADD DATA+33 X +01517 054043 0 ADD DATA+32 X +01520 054042 0 ADD DATA+31 X +01521 054041 0 ADD DATA+30 X +01522 054040 0 ADD DATA+27 X +01523 054037 0 ADD DATA+26 X +01524 054036 0 ADD DATA+25 X +01525 054035 0 ADD DATA+24 X +01526 054034 0 ADD DATA+23 X +01527 054033 0 ADD DATA+22 X +01530 054032 0 ADD DATA+21 X +01531 054031 0 ADD DATA+20 X +01532 054030 0 ADD DATA+17 X +01533 054027 0 ADD DATA+16 X +01534 054026 0 ADD DATA+15 X +01535 054025 0 ADD DATA+14 X +01536 054024 0 ADD DATA+13 X +01537 054023 0 ADD DATA+12 X +01540 054022 0 ADD DATA+11 X +01541 054021 0 ADD DATA+10 X +01542 054020 0 ADD DATA+7 X +01543 054017 0 ADD DATA+6 X +01544 054016 0 ADD DATA+5 X +01545 054015 0 ADD DATA+4 X +01546 054014 0 ADD DATA+3 X +01547 054013 0 ADD DATA+2 X +01550 054012 0 ADD DATA+1 X +01551 054011 0 ADD DATA X +01552 054010 0 ADD HEAD3 X +01553 054007 0 ADD HEAD2 X +01554 054006 0 ADD HEAD1 X +01555 054005 0 ADD HEAD X +01556 054004 0 ADDBOT: ADD ACKH X +01557 102111 0 JMP ADDRET I /RETURN TO CALLING INTERRUPT ROUTIN + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 35 IMP,3050,IMP 7:20 PM 9/16/1973 + + +01560 000001 C LEV CON CONSTANTS +01561 177755 C +01562 000006 C +01563 001147 C +01564 000004 C +01565 100060 C +01566 133000 C +01567 172110 C +01570 177752 C +01571 070000 C +01572 177757 C +01573 177777 C +01574 002000 C +01575 177760 C +01576 177776 C +01577 000000 C +01600 176753 C +01601 037775 C +01602 037776 C +01603 037774 C +01604 000003 C +01605 177674 C +01606 000005 C +01607 000011 C +01610 000100 C +01611 000002 C +01612 000074 C +01613 000177 C +01614 100000 C +01615 030000 C +01616 177774 C +01777 000000 C 1777/ 0 /LOC 1777 USED IN SWCH CODE + /FOR MEM PROTECT TEST + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 36 IMP,3050,IMP 7:20 PM 9/16/1973 + + + /INITIALIZATION + LEV BCK +02000 120672 7 INIT: JST DODXA I RET BCK +02001 001001 7 INH INI +02002 140040 7 0 CRA +02003 170120 7 0 SMK INTM /LOCK OUT INTERRUPTS FOR INIT +02004 010134 7 0 STA PRIM +02005 026133 7 0 IMA RSFLAG +02006 141206 7 0 AOA +02007 111465 7 0 STA (RSFNCC) I /SET UP RSTART INDICATOR FOR NCC +02010 022114 7 0 CAS ONE /RESTART +02011 022116 7 0 CAS THREE /OR POWERFAIL (4) +02012 003202 7 0 JMP INIVDH /==>SEE IF VDH GETS RESTARTED +02013 101000 7 0 NOP / (MUST COME BEFORE ZEROING 0-AF +02014 140040 7 0 CRA +02015 010145 7 0 STA SATRSF +02016 010136 7 0 INIVDR: STA TIPRSF +02017 010765 7 0 STA TPOPEN +02020 073466 7 0 LDX (-MAXITB) /MUST PRECEDE ZEROING +02021 045346 7 0 INIT1: LDA ITBTIP+MAXITB X /SO THAT APPROPRIATE INT'I +02022 070042 7 0 AMIMLC /ENTRIES ARE CLEARED +02023 045316 7 0 LDA ITBIMP+MAXITB X +02024 151266 7 0 STA ITBLOC+MAXITB XI /INIT TIP-HOST3 LOCS +02025 024000 7 0 IRS 0 +02026 003021 7 0 JMP INIT1 +02027 073467 7 0 LDX (-MAXVDH) +02030 045361 7 0 LDA ITBNVD+MAXVDH X +02031 151374 7 0 STA ITBVDL MAXVDH XI +02032 024000 7 0 IRS 0 +02033 003030 7 0 JMP .-3 +02034 073470 7 0 LDX (-INITZN) /INIT THE ZERO STORAGE AREAS +02035 045221 7 0 INIT0: LDA INITZB+INITZN X +02036 011212 7 0 STA IT1 +02037 045226 7 0 LDA INITZL+INITZN X +02040 011213 7 0 STA IT2 +02041 140040 7 0 CRA /MUST PRECED QUEUE INIT +02042 111212 7 0 STA IT1 I +02043 025212 7 0 IRS IT1 +02044 025213 7 0 IRS IT2 +02045 003042 7 0 JMP .-3 +02046 024000 7 0 IRS 0 +02047 003035 7 0 JMP INIT0 +02050 010144 7 0 STA VDHRSF /VDH WILL NOT RESTART +02051 131041 7 0 RDIMPN +02052 003051 7 0 JMP .-1 +02053 010106 7 0 STA MINE /INIT MINE +02054 005471 7 0 LDA (NS1) +02055 111472 7 0 STA (NSRR) I + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 37 IMP,3050,IMP 7:20 PM 9/16/1973 + +02056 073473 7 0 LDX (-QUEUEL) +02057 005474 7 0 LDA (QUEUEB) /INIT QUEUE PNTRS +02060 050414 7 0 INIT3: STA QUEUEE+QUEUEL X +02061 141206 7 0 AOA +02062 024000 7 0 IRS 0 +02063 003060 7 0 JMP INIT3 +02064 005475 7 0 LDA (ZERO) +02065 010324 7 0 STA FREE +02066 105476 7 0 LDA (HOST34) I +02067 006115 7 0 ANA TWO +02070 100040 7 0 SZE +02071 004116 7 0 LDA THREE +02072 111477 7 0 STA (SATNO) I +02073 105476 7 0 LDA (HOST34) I +02074 006114 7 0 ANA ONE +02075 010000 7 0 STA 0 +02076 101040 7 0 SNZ +02077 010144 7 0 STA VDHRSF /JUST IN CASE +02100 100040 7 0 SZE +02101 005500 7 0 LDA (-CH 0 M.N) /SET VDHNO FOR VDH IMPS.. +02102 111501 7 0 STA (VDHNO) I /...0 FOR NON-VDH +02103 045405 7 0 LDA P36END X +02104 011445 7 0 STA SPAR+36-2 /SET UP END OF P36 FOR VDH OR NOT +02105 045407 7 0 LDA P37END X +02106 011446 7 0 STA SPAR+37-2 /SET UP END OF P37 AND BEYOND +02107 004115 7 0 LDA TWO /START COLLECTING BUFFERS ON P2 +02110 011212 7 0 STA IT1 +02111 073502 7 0 LDX (-PAGES+2) +02112 045447 7 0 INIT4: LDA SPAR+PAGES-2 X +02113 040167 7 0 LRS 9. /PICK UP NUMBER OF BUFFERS ON THI[ + /NOTE THAT NO MORE THAN 64 8UFFERS CAN BE CLAIMED PER ENTRY +02114 011213 7 0 STA IT2 +02115 005212 7 0 LDA IT1 /PICK UP PAGE NUMBER +02116 025212 7 0 IRS IT1 +02117 041167 7 0 LLS 9. /PICK UP START OF BUFFER STORAGE +02120 003126 7 0 JMP INIT6 + +02121 024537 7 0 INIT5: IRS NFA /COUNT ANOTHER FREE BUFFER +02122 026324 7 0 IMA FREE +02123 110324 7 0 STA FREE I /ADD TO FREE LIST +02124 004324 7 0 LDA FREE +02125 015503 7 0 ADD (BUFL) +02126 025213 7 0 INIT6: IRS IT2 /HAVE WE TAKEN ALL THE BUFFERS +02127 003121 7 0 JMP INIT5 /NO, MORE ON THIS PAGE +02130 024000 7 0 IRS 0 /YES, GO ON TO NEXT PAGE +02131 003112 7 0 JMP INIT4 + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 38 IMP,3050,IMP 7:20 PM 9/16/1973 + +02132 005504 7 0 LDA (4"T"CH) +02133 010571 7 0 STA MAXS +02134 010573 7 0 STA MAXSI +02135 140407 7 0 TCA +02136 014537 7 0 ADD NFA +02137 014751 7 0 ADD 8PKTS +02140 040575 7 0 ARS 3 +02141 041575 7 0 ALS 3 +02142 014115 7 0 ADD TWO +02143 010572 7 0 STA MAXR +02144 072122 7 0 LDX MINUS2 /INIT THE FREE REAS+TRACE LISTS +02145 045230 7 0 INIT7: LDA INIBLK+2 X +02146 011212 7 0 STA IT1 +02147 045232 7 0 LDA INIQUE+2 X +02150 151234 7 0 STA INISTR+2 XI +02151 011213 7 0 STA IT2 +02152 055236 7 0 INIT8: ADD INILNG+2 X +02153 111213 7 0 STA IT2 I +02154 011213 7 0 STA IT2 +02155 025212 7 0 IRS IT1 +02156 003152 7 0 JMP INIT8 +02157 140040 7 0 CRA +02160 111213 7 0 STA IT2 I +02161 024000 7 0 IRS 0 +02162 003145 7 0 JMP INIT7 +02163 004132 7 0 LDA MINIMP +02164 011212 7 0 STA IT1 +02165 072113 7 0 LDX ZERO +02166 021374 7 0 INIT9: JST MESINI /INIT TMESS,RMESS +02167 024000 7 0 IRS 0 +02170 025212 7 0 IRS IT1 +02171 003166 7 0 JMP INIT9 +02172 005505 7 0 LDA (TALLY) +02173 111506 7 0 STA (TALLYI) I +02174 073507 7 0 LDX (0 0-2"T"FH-BH) +02175 045465 7 0 INIT13: LDA TTOI+FH+FH+BH X +02176 111510 7 0 STA (DZTB+FH+FH+BH 0 X) I +02177 024000 7 0 IRS 0 +02200 003175 7 0 JMP INIT13 +02201 103511 7 0 JMP (INITNP) I + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 39 IMP,3050,IMP 7:20 PM 9/16/1973 + +02202 004567 7 0 INIVDH: LDA VDHUPF /PWR FAIL OR PLAIN RESTART +02203 010144 7 0 STA VDHRSF /THEN RESTART VDH IF IT WAS UP +02204 004145 7 0 LDA SATRSF +02205 140100 7 0 SSP +02206 010145 7 0 STA SATRSF +02207 004136 7 0 LDA TIPRSF +02210 140100 7 0 SSP /0=>0, -=>+ +02211 003016 7 0 JMP INIVDR + + LEV VAR +02212 V IT1: BSS 1 +02213 V IT2: BSS 1 + LEV CON +02214 000160 C INITZB: ZEROB +02215 032030 C I2MB0 +02216 032030 C TABZB +02217 030434 C PARAMT +02220 100063 C STDIL 0 I /IN CASE NON-EXA IMP RELOADS FROM +02221 177370 C INITZL: -ZEROL +02222 177730 C -[CH"T"NACH] +02223 176201 C -TABZL +02224 177740 C -PARAML +02225 177760 C STDIL-0-TASKIL + INITZN=INITZL-0-INITZB +02226 177771 C INIBLK: -NREAB+0+1 +02227 177771 C -NTRCB+0+1 +02230 033317 C INIQUE: REASQ +02231 032131 C TRACEQ +02232 000326 C INISTR: RASF +02233 000325 C TTF +02234 000014 C INILNG: REASL +02235 000013 C TRACEL + + +02236 C ITBLOC: BSS MAXITB +02266 C ITBIMP: BSS MAXITB +02316 C ITBTIP: BSS MAXITB + MAXVDH=11. +02346 C ITBNVD: BSS MAXVDH +02361 000001 C ITBVDL: REPEAT MAXVDH,JUNK +02362 000001 C +02363 000001 C +02364 000001 C +02365 000001 C +02366 000001 C +02367 000001 C +02370 000001 C +02371 000001 C +02372 000001 C +02373 000001 C + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 40 IMP,3050,IMP 7:20 PM 9/16/1973 + + LEV [INI,T.O] +02374 000000 0 MESINI: 0 +02375 005512 0 LDA (0 0 177777"X"MSTO1"X"MSTO2) +02376 111513 0 STA (TMESS 0 X) I +02377 005514 0 LDA (0 0 3"T"400) 0"A"MESSNO +02400 111515 0 STA (RMESS 0 X) I +02401 140040 0 CRA +02402 111516 0 STA (AMESS 0 X) I +02403 111517 0 STA (RALLY 0 X) I +02404 103374 0 JMP MESINI I + + LEV CON +02405 170067 C P36END: P36FB"A"777-[P36NB+1]"T"1000 +02406 171067 C P36FB"A"777-[P36NB]"T"1000 +02407 172075 C P37END: P37FB"A"777-[P37NB]"T"1000 +02410 177777 C VDHEND"A"777-[0+1]"T"1000 + +02411 C SPAR: BSS PAGES-2 /TABLE OF ENDS-OF-PAGES + /FORMAT IS HI 7 BITS = -(NUMBER OF BUFFS ON PAGE+1) + /LO 9 BITS = STARTING ADDRESS OF FIRST BUFFER + + /FAKE HOST OUTPUT (JAM) SLOTS IN DZTB +02447 025117 C TTOI: TTYI /FH0 (TTY) OUTPUT FROM IMP TO FH +02450 023066 C DOTI /FH1 (DDT) OUTPUT FROM IMP TO FH +02451 030477 C BTRE /FH2 (TRACE) OUTPUT FROM IMP TO FH +02452 030056 C STTI /FH3 (STAT) OUTPUT FROM IMP TO FH + /FAKE HOST INPUT (SUCK) SLOTS IN WTTB +02453 025310 C TTO0 /FH0 (TTY) INPUT TO IMP FROM FH +02454 024012 C DIN4 /FH1 (DDT) INPUT TO IMP FROM FH +02455 030414 C BEST /FH2 (PARAM CHANGE) INPUT TO IMP E +02456 030474 C STXY /FH3 (DISCARD) INPUT TO IMP FROM FH + /BACK HOST SLOTS IN SLTB +02457 004101 C BACK0 /BH0 (SEND RFNMS+ALLOCATES) +02460 004206 C BACK1 /BH1 (SEND INCOMPLETE TRANSMISSIONS +02461 004302 C BACK2 /BH2 (SEND GIVE BACKS) +02462 004347 C BACK3 /BH3 (RETRANSMIT FROM PPT) +02463 004356 C BACK4 /BH4 (SEND OUT-OF-RANGE REPLIES) + / (REROUTE DEAD LINE STUFF) + / (RETURN DESTINATION DEADS) +02464 004365 C BACK5 + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 41 IMP,3050,IMP 7:20 PM 9/16/1973 + +02465 003560 C LEV CON CONSTANTS +02466 177750 C +02467 177765 C +02470 177773 C +02471 003452 C +02472 003450 C +02473 177727 C +02474 000272 C +02475 000113 C +02476 001005 C +02477 005153 C +02500 177775 C +02501 020544 C +02502 177742 C +02503 000112 C +02504 000024 C +02505 032261 C +02506 015155 C +02507 177762 C +02510 043433 C +02511 003074 C +02512 177477 C +02513 072271 C +02514 001400 C +02515 072371 C +02516 072471 C +02517 072571 C +02411 174524 C PAGEND 2,UNCON,4 + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 42 IMP,3050,IMP 7:20 PM 9/16/1973 + + /CONSTANTS, VARIABLE FOR NEW INIT PAGE + + LEV VAR +03062 V IT3: BSS 1 + + LEV CON +03063 010047 C M2IIT: M2I1A +03064 010073 C M2I2A +03065 010117 C M2I3A +03066 010143 C M2I4A +03067 010167 C M2I5A + +03070 C HIM.I: TIPDEF 177660,177664 +02236 003070 C +02266 177660 C +02316 177664 C +03071 C HIM.I4: TIPDEF 177460,177464 +02237 003071 C +02267 177460 C +02317 177464 C +03072 C IHM.I: TIPDEF 173600,173624 +02240 003072 C +02270 173600 C +02320 173624 C +03073 C IHM.I4: TIPDEF 163400,163424 +02241 003073 C +02271 163400 C +02321 163424 C + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 43 IMP,3050,IMP 7:20 PM 9/16/1973 + + LEV BCK LCK INI +03074 105561 7 0 INITNP: LDA (HOST34) I /THIS IS <>0 IF 3 OR 4 HOSTS +03075 006124 7 0 ANA MINUS4 + /=0 FOR 5 MODEMS, 2 HOSTS + />0 FOR 4 MODEMS, 3 HOSTS + /<0 FOR 3 MODEMS, 4 HOSTS +03076 072132 7 0 LDX MIN100 /5M,2H +03077 100040 7 0 SZE +03100 073072 7 0 LDX IHM.I /4M,3H +03101 100400 7 0 SPL +03102 073073 7 0 LDX IHM.I4 /3M,4H +03103 032500 7 0 STX IHM /* +03104 073562 7 0 LDX (-20) /5M,2H +03105 100040 7 0 SZE +03106 073070 7 0 LDX HIM.I /4M,3H +03107 100400 7 0 SPL +03110 073071 7 0 LDX HIM.I4 /3M,4H +03111 032501 7 0 STX HIM /* +03112 073563 7 0 LDX (-4000) /5M,2H +03113 100040 7 0 SZE +03114 073564 7 0 LDX (-10000) /4M,3H +03115 100400 7 0 SPL +03116 073565 7 0 LDX (-20000) /3M,4H +03117 032502 7 0 STX MOM /* +03120 072113 7 0 LDX ZERO /5M,2H +03121 100040 7 0 SZE +03122 072121 7 0 LDX MINUS1 /4M,3H +03123 100400 7 0 SPL +03124 072122 7 0 LDX MINUS2 /3M,4H +03125 133566 7 0 STX (MODNO) I /* +03126 073567 7 0 LDX (M2I5) /5M +03127 100040 7 0 SZE +03130 073570 7 0 LDX (IH2E) /4M OR 3M +03131 032070 7 0 STX M5INIL /* +03132 073571 7 0 LDX (M2I4) /5M OR 4M +03133 100400 7 0 SPL +03134 073572 7 0 LDX (IH3E) /3M +03135 032067 7 0 STX M4INIL /* +03136 073573 7 0 LDX (I2M5) /5M +03137 100040 7 0 SZE +03140 073574 7 0 LDX (HI2E) /4M OR 3M +03141 032075 7 0 STX M5OTIL /* +03142 073575 7 0 LDX (I2M4) /5M OR 4M +03143 100400 7 0 SPL +03144 073576 7 0 LDX (HI3E) /3M +03145 032074 7 0 STX M4OTIL /* + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 44 IMP,3050,IMP 7:20 PM 9/16/1973 + +03146 121577 7 0 JST (RUTINI) I /INIT ROUTING TABLES +03147 121600 7 0 JST (TOI) I /INITIALIZE TIMEOUT +03150 131040 7 0 RDCLOK +03151 003150 7 0 JMP .-1 /WAIT 3 SECONDS +03152 101400 7 0 SMI +03153 003150 7 0 JMP .-3 /BEFORE STARTING INTERRUPT PROGRAF' +03154 121601 7 0 JST (SWCH) I /FIRE OFF A TRBL REPT NOW - FOLLOWS + /START MODEM INPUT - MUST FOLLOW TOI +03155 073602 7 0 LDX (-[2"T"CH]) +03156 005603 7 0 LDA (I 0 1) +03157 050032 7 0 INIT17: STA M1INBP+2"T"CH X +03160 024000 7 0 IRS 0 +03161 003157 7 0 JMP INIT17 +03162 005604 7 0 LDA (M1IN) +03163 011174 7 0 STA INIT19 +03164 072127 7 0 LDX MICH +03165 005605 7 0 INIT18: LDA (JMP+0+1000+M2II"A"777) +03166 151070 7 0 STA M2IIT+CH XI /FIRST IN WILL BE DISCAF +03167 105606 7 0 LDA (VDHNO) I /SKIP FOR VDH'S MODEM +03170 016000 7 0 SUB 0 +03171 100040 7 0 SZE +03172 117607 7 0 SUB (SATNO) I /ENTERING AC IS -C(0) +03173 100040 7 0 SZE +03174 7 0 INIT19: BSS 1 /STARTUP MODEM INS +03175 025174 7 0 IRS INIT19 +03176 024000 7 0 IRS 0 +03177 003165 7 0 JMP INIT18 + /START THE HOST/IMP AND IMP/HOST ROUTINES +03200 004131 7 0 LDA MITH +03201 011062 7 0 STA IT3 /COUNTING ON X=0 AT THIS POINT +03202 004117 7 0 INIT15: LDA FOUR 0"A"HSTIDN /HOSTS ARE DOWN WHILE IMP +03203 050504 7 0 STA HIHD X +03204 121610 7 0 JST (IHIN) I /** MUST BE IN THIS ORDER +03205 121611 7 0 JST (HIST) I /** +03206 024000 7 0 IRS 0 +03207 025062 7 0 IRS IT3 +03210 003202 7 0 JMP INIT15 +03211 004121 7 0 LDA MINUS1 +03212 010137 7 0 STA SW3FG +03213 010140 7 0 STA NRSTF +03214 010134 7 0 STA PRIM +03215 170120 7 0 SMK INTM +03216 000401 7 0 ENB BCK +03217 131040 7 RDCLOK /ALLOW ALL T/O PROGRAMS TO RUN +03220 003217 7 JMP .-1 +03221 100400 7 SPL +03222 003217 7 JMP .-3 /BEFORE BACK BEGINS + /FALL INTO BACKST ----- + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 45 IMP,3050,IMP 7:20 PM 9/16/1973 + + + /BACKGROUND LOOP + LEV BCK +03223 005612 7 BACKST: LDA (BBNIMP) /1ST REPORT MUST GO TO NCC +03224 111613 7 BACK: STA (TRBD) I +03225 005614 7 LDA (-FH) +03226 011410 7 STA BT1 +03227 005410 7 BKV: LDA BT1 +03230 017614 7 SUB (-FH) +03231 010000 7 STA 0 +03232 011412 7 STA FAKENO /FOR DEBUG +03233 143415 7 JMP DZTB XI /RESUME WHERE JAM LEFT OFF + +03234 000000 7 BKX: 0 /JAM WAIT (DOZE) +03235 005234 7 LDA BKX +03236 051415 7 STA DZTB X +03237 143421 7 JMP WTTB XI /RESUME WHERE SUCK LEFT OFF + +03240 000000 7 BKW: 0 /SUCK WAIT (WAIT) +03241 005240 7 LDA BKW +03242 051421 7 STA WTTB X +03243 000401 7 ENB BCK +03244 025410 7 IRS BT1 +03245 003227 7 JMP BKV +03246 005615 7 LDA (-BH) +03247 011410 7 STA BT1 +03250 072113 7 LDX ZERO +03251 133616 7 BKY: STX (BACKNO) I +03252 072114 7 LDX ONE +03253 001001 7 INH ALL +03254 143260 7 0 DXATS1: JMP DXATST XI /ARE WE EXA OR DXA? + DEFHLT [BACKGROUND IN EXA MODE (BACK0)!] +03255 021262 7 0 JST DXABUG /DXA +03256 173616 7 0 DXATS2: LDX (BACKNO) I /EXA +03257 143425 7 0 JMP SLTB XI /RESUME WHERE BACK HOSTS LEFT OFF + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 46 IMP,3050,IMP 7:20 PM 9/16/1973 + + LEV CON +03260 003254 C DXATST: DXATS1 +03261 003256 C DXATS2 + LEV BCK LCK ALL +03262 000000 7 0 DXABUG: 0 +03263 120745 7 0 JST HLTNCC I +03264 000011 7 0 DXA +03265 103262 7 0 JMP DXABUG I + + RET BCK +03266 000000 7 BKZ: 0 /BACK HOST WAIT (SLEEP) +03267 000401 7 ENB BCK +03270 173616 7 LDX (BACKNO) I +03271 005266 7 LDA BKZ +03272 051425 7 STA SLTB X +03273 024000 7 B5Z: IRS 0 +03274 025410 7 IRS BT1 +03275 003251 7 JMP BKY +03276 140040 7 CRA +03277 100004 7 SR3 +03300 010137 7 STA SW3FG /DO NICE STOP IF SS3 +03301 004137 7 LDA SW3FG /REMOTE NICE-STOP+RELOAD +03302 100400 7 SPL +03303 004140 7 LDA NRSTF +03304 101400 7 SMI +03305 021446 7 JST NSRT /NICE-STOP IF SW3FG>=0 OR NRSTF>=0 + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 47 IMP,3050,IMP 7:20 PM 9/16/1973 + +03306 004415 7 LDA TIME +03307 027413 7 IMA WDTOLD /IS T.O RUNNING? +03310 013413 7 ERA WDTOLD +03311 100040 7 SZE +03312 003316 7 JMP BKT /TIME CHANGED...YES +03313 025414 7 IRS WDTBAK +03314 003320 7 JMP BKU /DON'T GIVE UP YET + RELOAD [BACKGROUND SAW TIMEOUT STOP] +03315 120061 7 JST SWDTIL I + +03316 005617 7 BKT: LDA (-10000.) /GIVE T.O A LONG TIME TO RUN +03317 011414 7 STA WDTBAK /AND RESET BACK-WDT +03320 000401 7 BKU: ENB BCK +03321 7 TIPDEF [JMP BKS],[LDA TIPRSF] +02242 003321 7 +02272 003334 7 +02322 004136 7 +03322 101040 7 SNZ +03323 003331 7 JMP BKR +03324 000013 7 EXA +03325 121620 7 JST (TIPBKG) I +03326 001001 7 INH ALL +03327 120672 7 0 JST DODXA I RET BCK +03330 003334 7 JMP BKS +03331 004063 7 BKR: LDA STDIL +03332 010101 7 STA H2INIL +03333 010077 7 STA H2OTIL +03334 073621 7 BKS: LDX (-LITN) /LIGHTS DISPLAY +03335 145446 7 LIT2: LDA LITT+LITN XI +03336 100040 7 SZE +03337 140500 7 SSM +03340 041277 7 LLR 1 +03341 024000 7 IRS 0 +03342 003335 7 JMP LIT2 +03343 140040 7 CRA +03344 040267 7 LRR LITN +03345 012452 7 ERA LUUP +03346 011434 7 STA LITS +03347 001001 7 INH ALL +03350 000013 7 0 EXA +03351 105433 7 0 LDA LITP I +03352 120672 7 0 JST DODXA I RET BCK +03353 100020 7 SR1 +03354 004121 7 LDA MINUS1 /LAMP TEST +03355 170026 7 LITES +03356 101000 7 NOP +03357 000201 7 IAB +03360 025411 7 IRS BACKX /KEEP COUNT OF BACK LOOPS +03361 101000 7 NOP + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 48 IMP,3050,IMP 7:20 PM 9/16/1973 + +03362 140040 7 CRA +03363 026144 7 IMA VDHRSF /CHECK AND RESET VDH RESTART FLAG +03364 100040 7 SZE +03365 121622 7 JST (VD.I) I /YES, RESTART +03366 101000 7 VDH2: NOP /VDH BACKGROUND CALL +03367 004172 7 LDA RUT+BBNIMP +03370 101400 7 SMI 0"A"RUTDED /IS NCC IMP UP? +03371 003223 7 JMP BACKST /YES +03372 072132 7 LDX MINIMP /MUST FIND RANDOM IMP UP +03373 044265 7 BKWD1: LDA RUT+NIMP X +03374 101400 7 SMI 0"A"RUTDED /DEAD? +03375 101040 7 SNZ 0"A"RUTUS +03376 003403 7 JMP BKWD2 /DON'T USE OURSELVES EXCEPT AS A LA1 +03377 004000 7 LDA 0 /GOT ONE +03400 016132 7 SUB MINIMP +03401 013623 7 BKWD3: ERA (DESTH 0 FORIMP) /TO DISCARD +03402 003224 7 JMP BACK +03403 024000 7 BKWD2: IRS 0 +03404 003373 7 JMP BKWD1 +03405 004106 7 LDA MINE /EVERYONE IS DEAD, USE OURSELVES +03406 003401 7 JMP BKWD3 +03407 037511 7 VDH2.: VD.B + + LEV VAR +03410 V BT1: BSS 1 +03411 V BACKX: BSS 1 /NO OF BACK LOOPS +03412 V FAKENO: BSS 1 +03413 V WDTOLD: BSS 1 /OLD TIME READING +03414 V WDTBAK: BSS 1 /BACK WDT TIMER + /THESE 3 TABLES MUST STAY IN ORDER11 + DEFPLC [DZTB - GOES WITH JAM] +03415 V DZTB: BSS FH + DEFPLC [WTTB - GOES WITH SUCK] +03421 V WTTB: BSS FH + DEFPLC [SLTB - GOES WITH SLEEP (BACK HOSTS)] +03425 V SLTB: BSS BH + + DEFPLC [LIGHT DISPLAY POINTER AND NOMINAL DISPLAY WORD] +03433 003434 V LITP: LITS +03434 V LITS: BSS 1 + + /LIGHTS TABLE AND CONDITION INDICATED BY LIT LIGHT + LEV CON +03435 000433 C LITT: LINE /1 - 100000 1ST CHANNEL DEAD +03436 000434 C LINE+1 /2 - 40000 2ND CHANNEL DEAD +03437 000435 C LINE+2 /3 - 20000 3RD CHANNEL DEAD +03440 000436 C LINE+3 /4 - 10000 4TH CHANNEL DEAD +03441 000504 C HIHD /5 - 4000 HOST 1 DEAD +03442 000505 C HIHD+1 /6 - 2000 HOST 2 DEAD +03443 000506 C HIHD+2 /7 - 1000 HOST 3 DEAD +03444 000507 C HIHD+3 /8 - 400 HOST 4 DEAD +03445 000765 C TPOPEN /9 - 200 TIP HAS OPEN CONNECTION + LITN=0 0 .-LITT + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 49 IMP,3050,IMP 7:20 PM 9/16/1973 + + / NICE STOP ROUTINE + LEV BCK +03446 000000 7 NSRT: 0 +03447 103450 7 JMP NSRR I +03450 000000 7 NSRR: 0 +03451 103446 7 JMP NSRT I +03452 004137 7 NS1: LDA SW3FG /SET UP RSFNCC WORD FOR NICE STOP +03453 006120 7 ANA SEVEN +03454 041675 7 ALR 3 +03455 012140 7 ERA NRSTF +03456 007624 7 ANA (177770) +03457 012140 7 ERA NRSTF +03460 012752 7 ERA C77 +03461 041675 7 ALR 3 +03462 101004 7 SS3 /DO NOT SET RSFNCC FOR SS3 +03463 011560 7 STA RSFNCC +03464 140040 7 CRA /SEND IMP GOING DOWN IN 30 SEC +03465 021525 7 JST IHDOWN LCK FRE +03466 000401 7 0 ENB BCK +03467 021543 7 JST NSWT /WAIT 5 SECONDS +03470 004117 7 LDA FOUR 0"A"HSTIDN +03471 010504 7 STA HIHD /STOP NET TRAFFIC TO AND FROM HOSTS +03472 010505 7 STA HIHD+1 /MARK HOSTS DEAD, IMP NOT UP +03473 010506 7 STA HIHD+2 +03474 010507 7 STA HIHD+3 +03475 021543 7 JST NSWT /WAIT 5 SECONDS +03476 004121 7 LDA MINUS1 /STOP STORE-AND-FORWARD TRAFFIC BI +03477 010573 7 STA MAXSI /MAKING MAXS COPY SMALL +03500 021543 7 JST NSWT /WAIT 5 SECONDS +03501 004127 7 LDA MICH +03502 011556 7 STA BT2 /STOP EXCHANGE OF ROUTING AND ACKNO +03503 072113 7 LDX ZERO /TURNING OFF ALL LINES +03504 001001 7 INH [M2I,T.O,TSK] +03505 121625 7 0 NS3: JST (KILLIN) I /KILL LINE AT ONCE +03506 024000 7 0 IRS 0 +03507 025556 7 0 IRS BT2 +03510 003505 7 0 JMP NS3 +03511 000401 7 0 ENB BCK +03512 021543 7 JST NSWT /WAIT 5 SECONDS +03513 021543 7 JST NSWT /WAIT UNTIL SLT DELAY OVER +03514 004140 7 LDA NRSTF +03515 101400 7 SMI /RESTART? +03516 103626 7 JMP (INIT) I /GO TO 2000 +03517 004137 7 LDA SW3FG /FOR VDH OR NON-VDH +03520 101004 7 SS3 /STOP OR RELOAD? +03521 103627 7 JMP (WDLOD) I +03522 030026 7 WDT +03523 000000 7 HLT +03524 003522 7 JMP .-2 + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 50 IMP,3050,IMP 7:20 PM 9/16/1973 + +03525 000000 7 IHDOWN: 0 /NOTIFY ALL HOSTS OF IMP DOWN +03526 001001 7 INH FRE +03527 010515 7 0 STA TWDP +03530 004131 7 0 LDA MITH +03531 011556 7 0 STA BT2 +03532 005556 7 0 NS2: LDA BT2 +03533 016131 7 0 SUB MITH +03534 010000 7 0 STA 0 +03535 005630 7 0 LDA (CIMPDN) /IMP GOING DOWN MESSAGE +03536 120670 7 0 JST OWP I +03537 101000 7 0 NOP +03540 025556 7 0 IRS BT2 +03541 003532 7 0 JMP NS2 +03542 103525 7 0 JMP IHDOWN I + +03543 000000 7 0 NSWT: 0 /WAIT 5 SECONDS +03544 030026 7 0 WDT +03545 004415 7 0 LDA TIME +03546 011557 7 0 STA NSTM +03547 021450 7 0 NS5: JST NSRR +03550 004415 7 0 LDA TIME +03551 017557 7 0 SUB NSTM +03552 141044 7 0 CAR /WAIT FIVE SECONDS +03553 101040 7 0 SNZ +03554 003547 7 0 JMP NS5 +03555 103543 7 0 JMP NSWT I + + LEV VAR +03556 V BT2: BSS 1 /TEMP +03557 V NSTM: BSS 1 /FOR STOP +03560 V RSFNCC: BSS 1 /RESTART PLACE FOR NCC -FORMAT FOLL + /RSFNCC HAS THE FORM 000XYZ WHERE X,Y,Z ARE OCTAL DIGITS + /X IS RELOAD REQUEST INDICATOR, X=0 NO REQUEST + /X=7 RANDOM RELOAD, X=6 RELOAD FOR LINE 1, X=5 LINE 2, X=4 L + /X=3 LINE 4, X=2 LINE 5 + /Y IS RESTART REQUEST INDICATOR, Y=0 NO REQUEST + /Y=7 RESTART AT 2000 - NON-VDH, X=6 RESTART AT 2001 - VDH + /Z IS PROGRAM INITIALIZATION INDICATOR, Z=0 NO INIT + /Z=1 RESTARTED, Z=2 RELOADED, Z=3 WATCH DOG TIMER RELOADED + /Z=4 POWER FAIL RESTARTED + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 51 IMP,3050,IMP 7:20 PM 9/16/1973 + +03561 001005 C LEV CON CONSTANTS +03562 177760 C +03563 174000 C +03564 170000 C +03565 160000 C +03566 020545 C +03567 010163 C +03570 016020 C +03571 010137 C +03572 016012 C +03573 012107 C +03574 013064 C +03575 012113 C +03576 013056 C +03577 026070 C +03600 020075 C +03601 022320 C +03602 177766 C +03603 100001 C +03604 030471 C +03605 003207 C +03606 020544 C +03607 005153 C +03610 016217 C +03611 013256 C +03612 000005 C +03613 030456 C +03614 177774 C +03615 177772 C +03616 004420 C +03617 154360 C +03620 040001 C +03621 177767 C +03622 037025 C +03623 040300 C +03624 177770 C +03625 011133 C +03626 002000 C +03627 001022 C +03630 001000 C +02412 175637 C PAGEND 3,UNCON,4 + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 52 IMP,3050,IMP 7:20 PM 9/16/1973 + + /SEND OFF ALLOCATED RFNMS AND ALLOCATES AND RFNMS + LEV BCK +04063 140040 7 B0AA: CRA +04064 011157 7 STA BALLOC +04065 121417 7 B0A: JST SLEEP I +04066 021372 7 B0B: JST GETFRE LCK FRE /GET A BUFFER FOR OUR AL 1 +04067 003065 7 0 JMP B0A /NOT NOW, WAIT +04070 005155 7 0 LDA BRALLY 0"A"DESTI /GET OUR RALLY +04071 007603 7 0 ANA (DESTI) +04072 050006 7 0 STA HEAD1 X /SAVE IN HEADER +04073 013155 7 0 ERA BRALLY 0"A"[MESSNO 0 ONEOR8 RFNM] +04074 013157 7 0 ERA BALLOC 0"A"TRNREP /SET ALLOC BIT OR NOT +04075 013160 7 0 ERA BREPIN 0"A"INCTRN +04076 050005 7 0 STA HEAD X +04077 021435 7 0 JST GIVTSK RET BCK /GIVE RALLY TO TASK +04100 121417 7 B0C: JST SLEEP I +04101 021473 7 BACK0: JST RALLYG /GET NEXT RALLY TO GO +04102 003100 7 JMP B0C +04103 100000 7 SKP /GOOD RETURN +04104 003100 7 JMP B0C /GOT A DESTINATION DEAD, SENT ALREA +04105 011155 7 STA BRALLY /SAVE RALLY +04106 007604 7 ANA (ONEOR8 0 RFNM) +04107 013604 7 ERA (ONEOR8 0 RFNM) +04110 101040 7 SNZ /IS THIS JUST A 1-PKT RFNM? +04111 003063 7 JMP B0AA /YES, NO ALLOC NECESSARY +04112 005155 7 LDA BRALLY +04113 007605 7 ANA (ONEOR8) +04114 100040 7 SZE +04115 005606 7 LDA (-7) 0"A"8PKTS +04116 014751 7 ADD 8PKTS +04117 011157 7 STA BALLOC +04120 004415 7 LDA TIME +04121 011156 7 STA BALLTO +04122 121417 7 B0D: JST SLEEP I +04123 004415 7 LDA TIME +04124 017156 7 SUB BALLTO +04125 017607 7 SUB (40.) +04126 100400 7 SPL /HAVE WE BEEN WAITING 1 SEC? +04127 003134 7 JMP B0F /NOT YET +04130 005155 7 LDA BRALLY +04131 007610 7 ANA (RFNM) +04132 100040 7 SZE /ARE WE SENDING AN ALLOCATED RFNMT +04133 003063 7 JMP B0AA /YES, SEND IT OFF WITHOUT ALLOC + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 53 IMP,3050,IMP 7:20 PM 9/16/1973 + +04134 001001 7 B0F: INH [T.O,TSK] +04135 004542 7 5 LDA NALA +04136 016566 7 5 SUB NALS +04137 014541 7 5 ADD NREA +04140 016565 7 5 SUB NRES +04141 015157 7 5 ADD BALLOC +04142 022572 7 5 CAS MAXR /CAN WE HAVE THE ROOM? +04143 003122 7 5 JMP B0D /NOT YET +04144 003122 7 5 JMP B0D +04145 005611 7 5 LDA (ALLOC) +04146 027157 7 5 IMA BALLOC /SET ALLOC BIT IN OUR REPLY +04147 014542 7 5 ADD NALA +04150 010542 7 5 STA NALA /YES, SO TAKE IT +04151 004107 7 5 LDA M30SEC /2 MINUTES BEFORE WE ARE IDLE +04152 041576 7 5 ALS 2 +04153 011161 7 5 STA SNTALL +04154 003066 7 5 JMP B0B + + LEV VAR +04155 V BRALLY: BSS 1 /OUR ALLOCATE TO MAKE +04156 V BALLTO: BSS 1 /TIME WE STARTED TO TRY FOR ALLOC +04157 V BALLOC: BSS 1 /NO OF BUFFERS WE NEED TO ALLOC +04160 V BREPIN: BSS 1 /BIT ON IF INC TRN REPLY +04161 V SNTALL: BSS 1 /TIMER FOR GARBAGE COLLECTION OF 1 1 + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 54 IMP,3050,IMP 7:20 PM 9/16/1973 + + LEV BCK + /SEND OFF INCOMPLETE TRASMISSIONS IF ANY TMESS NO OVERDUE + LCK [H2I,T.O,TSK] +04162 121612 7 4 B1A: JST (PPTGET) I /GET THE PPT ENTRY +04163 003257 7 4 JMP B1F /NOT IN PPT OR PLT, SO ITS A GVB +04164 044111 7 4 LDA BUFE X +04165 140100 7 4 SSP 0"A"TWOQ +04166 011262 7 4 STA BACK1T /SAVE PTR TO PKT CKSUM +04167 044010 7 4 LDA HEAD3 X +04170 007613 7 4 ANA (0 0 177777"X"SUBCOD) +04171 013614 7 4 ERA (CLOST) /MARK MESS AS LOST IN NET +04172 066010 7 4 IMA HEAD3 X +04173 056010 7 4 SUB HEAD3 X +04174 115262 7 4 ADD BACK1T I /ADJUST CKSUM +04175 111262 7 4 STA BACK1T I +04176 005605 7 4 LDA (ONEOR8) /MARK AS INC TRN FOR ONE-PKT +04177 073430 7 4 B1B: LDX HOLD+1 /GET OUR PKT +04200 052005 7 4 ERA HEAD X +04201 050005 7 4 STA HEAD X +04202 021435 7 4 JST GIVTSK RET BCK /AND GIVE TO TASK +04203 005261 7 B1C: LDA BACK1P /LOOK AT NEXT TMESS ENTRY +04204 141206 7 AOA +04205 023615 7 CAS (TMESS 0 NIMP) +04206 005615 7 BACK1: LDA (TMESS 0 NIMP) /SHOULDNT HAPPEN +04207 014132 7 ADD MINIMP /WRAPAROUND TMESS TABLE +04210 011261 7 STA BACK1P /SAVE PNTR TO TMESS +04211 121417 7 B1D: JST SLEEP I +04212 001001 7 INH [H2I,T.O,TSK] +04213 105261 7 4 LDA BACK1P I +04214 007604 7 4 ANA (MSTO1 0 MSTO2) +04215 013604 7 4 ERA (MSTO1 0 MSTO2) +04216 100040 7 4 SZE /HAS THIS MESS NO TIMED OUT? +04217 003203 7 4 JMP B1C /NO +04220 011262 7 4 STA BACK1T /INIT TEMP COUNTER. USED LATER +04221 021372 7 4 JST GETFRE /YES, GET A BUFFER FOR OUR INC TRN +04222 003211 7 4 JMP B1D /NOT NOW, TRY AGAIN +04223 033430 7 4 STX HOLD+1 +04224 005261 7 4 LDA BACK1P +04225 017616 7 4 SUB (TMESS) /SET UP OUR DEST +04226 050006 7 4 STA HEAD1 X 0"A"DESTI +04227 105261 7 4 LDA BACK1P I +04230 007617 7 4 ANA (0 0 177777"X"MSTO1"X"MSTO2) +04231 111261 7 4 STA BACK1P I /CLEAR TIMEOUT BITS +04232 025262 7 4 B1E: IRS BACK1T /1 MEANS OLDEST, 2 NEXT OLDEST ... +04233 040677 7 4 ARR 1 +04234 100400 7 4 SPL /IS THE OLDEST POSSIBLE MESS INC? +04235 003232 7 4 JMP B1E /NO, COUNT ONE MORE BACKWARDS + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 55 IMP,3050,IMP 7:20 PM 9/16/1973 + +04236 005262 7 4 LDA BACK1T +04237 141240 7 4 ICR /GET NO OF MESS NOS TO ROLL BACK +04240 115261 7 4 ADD BACK1P I +04241 141044 7 4 CAR 0"A"MESSNO +04242 015620 7 4 ADD (INCTRN 0 -2000 TRNREP 0"A"LINETS) +04243 050005 7 4 STA HEAD X /SET UP INC TRN WITH RIGHT MESS N( +04244 141044 7 4 CAR 0"A"MESSNO +04245 052006 7 4 ERA HEAD1 X /SET UP MESS NO + IMP NO +04246 121621 7 4 JST (PLTGET) I /GET THE PLT ENTRY +04247 003162 7 4 JMP B1A /NOT IN PLT, TRY PPT +04250 044030 7 4 LDA PLT2 X +04251 007613 7 4 ANA (0 0 177777"X"SUBCOD) +04252 013614 7 4 ERA (CLOST) /MARK MESS AS LOST IN NET +04253 050030 7 4 STA PLT2 X +04254 044000 7 4 LDA PLT0 X +04255 007610 7 4 ANA (REQALL) +04256 003177 7 4 JMP B1B + +04257 005622 7 4 B1F: LDA (GVBALL 0 ONEOR8) +04260 003177 7 4 JMP B1B /MAKE UP AN INC GVB + LEV VAR +04261 V BACK1P: BSS 1 /PNTR TO TMESS ENTRY +04262 V BACK1T: BSS 1 /COUNT OF NO OF MESS NOS TO GO BACK + + /SEND OFF GIVE BACKS WHEN ALLOCATES TIME OUT + LEV BCK +04263 121417 7 B2A: JST SLEEP I +04264 021372 7 B2B: JST GETFRE LCK FRE /GET A BUFFER FOR OUR GIV +04265 003263 7 0 JMP B2A /NOT NOW, WAIT +04266 033431 7 0 STX HOLD+2 +04267 121417 7 0 B2C: JST SLEEP I RET BCK +04270 073431 7 LDX HOLD+2 +04271 005314 7 LDA BACK2D 0"A"PRIBIT /GET OUR DEST +04272 050006 7 STA HEAD1 X /PUT IN PKT (NOT PRI) +04273 001001 7 INH H2I +04274 121623 7 4 JST (MESGET) I +04275 003267 7 4 JMP B2C /CANT HAVE MESS NO +04276 013622 7 4 ERA (GVBALL 0 ONEOR8 0"A"LINETS"A"INCTRN) +04277 050005 7 4 STA HEAD X /SET UP GVB +04300 021435 7 4 JST GIVTSK RET BCK /GIVE THE GVB TO TASK +04301 121417 7 B2D: JST SLEEP I +04302 001001 7 BACK2: INH [H2I,T.O] +04303 004126 7 4 LDA MINUS6 /ALLOCATES TIME OUT IN 125 MS +04304 115624 7 4 ADD (TALLYC) I +04305 100400 7 4 SPL /IS ALLOC TOO OLD? +04306 003301 7 4 JMP B2D /NOT USED UP YET +04307 105625 7 4 LDA (TALLY) I /GET TOP TALLY ENTRY +04310 121626 7 4 JST (TALLYG) I /PULL IT OFF +04311 003301 7 4 JMP B2D /NOT THERE? +04312 011314 7 4 STA BACK2D /SAVE OUR DEST +04313 003264 7 4 JMP B2B + LEV VAR +04314 V BACK2D: BSS 1 /DEST OF GIVE BACK + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 56 IMP,3050,IMP 7:20 PM 9/16/1973 + + /DO RETRANSMISSSIONS OF REQ1 IN PPT THAT HAS GOT ALL1 IN RET1 + LEV BCK +04315 121417 7 B3B: JST SLEEP I +04316 173353 7 LDX BACK3P I +04317 044111 7 LDA BUFE X +04320 100400 7 SPL 0"A"TWOQ /IS THIS PKT STILL ON 2 QUEUES? +04321 003315 7 JMP B3B /YES, NEED TO DELAY WHILE ACK IS PR1 +04322 011354 7 STA B3T1 /TEMP CKSUM POINTER +04323 140500 7 SSM 0"A"TWOQ +04324 050111 7 STA BUFE X /PPT ENTRY GOES ON 2 QUEUES AGAIN +04325 044005 7 LDA HEAD X +04326 007627 7 ANA (0 0 177777"X"REQALL) +04327 050005 7 STA HEAD X /TURN OFF REQ BIT, KEEP SAME MESS N1 +04330 105353 7 LDA BACK3P I +04331 140100 7 SSP 0"A"RETRAN +04332 111353 7 STA BACK3P I +04333 105354 7 LDA B3T1 I +04334 015610 7 ADD (REQALL) /NOW ADJUST CHECKSUM +04335 111354 7 STA B3T1 I +04336 140040 7 CRA /GIVTSK WON'T MAKE CHECKSUM +04337 021435 7 JST GIVTSK /GIVE TO TASK +04340 121417 7 B3C: JST SLEEP I +04341 105353 7 LDA BACK3P I /LOOK AT NEXT PPT ENTRY +04342 100400 7 SPL 0"A"RETRAN /MUST WE RETRANSMIT IT? +04343 003315 7 JMP B3B /YES +04344 005353 7 LDA BACK3P +04345 141206 7 AOA /GET NEXT PPT SLOT +04346 023630 7 CAS (PPT+0+PPTL) +04347 005630 7 BACK3: LDA (PPT+0+PPTL) /SHOULDNT HAPPEN +04350 017631 7 SUB (PPTL) /WRAPAROUND PPT +04351 011353 7 STA BACK3P /SAVE PPT SLOT +04352 003340 7 JMP B3C + LEV VAR +04353 V BACK3P: BSS 1 /PNTR TO PPT ENTRY +04354 V B3T1: BSS 1 /PNTR TO CHKSM IN PKT + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 57 IMP,3050,IMP 7:20 PM 9/16/1973 + + /SEND OFF PACKETS FROM A LINE WHICH JUST DIED - REROUTE + /SEND OFF DESTINATION DEAD MESSAGES TO SOURCE + LEV BCK +04355 121417 7 B4A: JST SLEEP I +04356 073632 7 BACK4: LDX (SRQ) /GET NEXT REPLY +04357 001001 7 INH [I2H,T.O] +04360 121633 7 3 JST (GETQ) I +04361 003355 7 3 JMP B4A /NONE, SO SLEEP +04362 140040 7 3 CRA /TELL GIVTSK NOT TO CKSUM +04363 021435 7 3 JST GIVTSK RET BCK /GIVE THE REPLY TO TASK +04364 003355 7 JMP B4A + + /SATELLITE BACK HOST + LEV BCK +04365 004145 7 BACK5: LDA SATRSF +04366 7 B5A: SATDEF SZE +02243 004366 7 +02273 100040 7 +02323 100040 7 +04367 121634 7 JST (SATBCK) I +04370 121417 7 JST SLEEP I +04371 003365 7 JMP BACK5 + + SATBCK=37700 + + LEV [VDB,BCK] +04372 000000 3 GETFRE: 0 /GET A FREE BUFFER FOR A BACK HOSI +04373 001001 3 INH FRE +04374 004537 3 0 LDA NFA +04375 016563 3 0 SUB NFS +04376 016570 3 0 SUB MINF +04377 100400 3 0 SPL +04400 103372 3 0 JMP GETFRE I /NOT ENOUGH BUFFERS FOR MODEM INP1 +04401 104324 3 0 LDA FREE I +04402 101040 3 0 SNZ +04403 103372 3 0 JMP GETFRE I +04404 026324 3 0 IMA FREE +04405 010000 3 0 STA 0 +04406 024563 3 0 IRS NFS +04407 014751 3 0 ADD CMINPL 0"A"TWOQ +04410 050111 3 0 STA BUFE X +04411 004106 3 0 LDA MINE +04412 050007 3 0 STA HEAD2 X /SET UP SOURCE IMP +04413 140040 3 0 CRA +04414 050000 3 0 STA 0 X +04415 025372 3 0 IRS GETFRE /SKIP=SUCCESS +04416 103372 3 0 JMP GETFRE I + + LEV CON +04417 003266 C SLEEP: BKZ /BACK HOST WAIT + LEV VAR +04420 V BACKNO: BSS 1 /NO OF BACK HOST CURRENTLY ACTIVE +04421 V GIVTST: BSS BH /RETURN ADDRS FOR BACK HOSTS GIVING +04427 V HOLD: BSS BH /PKT PNTRS FOR BACK HOSTS GIVING -' + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 58 IMP,3050,IMP 7:20 PM 9/16/1973 + + LEV BCK +04435 000000 7 GIVTSK: 0 +04436 101040 7 SNZ +04437 003446 7 JMP GIVT0 /NOT GENERATING A CHECKSUM +04440 004117 7 LDA FOUR 0"A"[MINPL-ACKH] +04441 056004 7 SUB ACKH X +04442 056005 7 SUB HEAD X +04443 056006 7 SUB HEAD1 X +04444 056007 7 SUB HEAD2 X +04445 050010 7 STA HEAD3 X /THERE'S THE CHECKSUM +04446 005420 7 GIVT0: LDA BACKNO 0"A"INPCHN +04447 015635 7 ADD (HSTMOD 0 TH) +04450 050003 7 STA INCH X /SET UP INPUT CHANNEL +04451 004000 7 LDA 0 +04452 073420 7 LDX BACKNO +04453 140100 7 SSP 0"A"RETRAN /NEC FOR BACK3 +04454 051427 7 STA HOLD X /SAVE PKT PNTR +04455 005435 7 LDA GIVTSK +04456 051421 7 STA GIVTST X /SAVE RETURN ADDR +04457 045427 7 GIVT1: LDA HOLD X +04460 001001 7 INH M2I +04461 110401 7 0 STA ETQ I +04462 010401 7 0 STA ETQ /PUT ON TASK QUEUE +04463 030041 7 0 TASK /POKE TASK +04464 121417 7 0 JST SLEEP I RET BCK +04465 140040 7 CRA +04466 066463 7 IMA TSKFLG+TH X +04467 101100 7 SLN /TASK REFUSED IT +04470 143421 7 JMP GIVTST XI /TASK TOOK IT +04471 121417 7 JST SLEEP I /WAIT ONE BACKGROUND LOOP +04472 003457 7 JMP GIVT1 /THEN TRY AGAIN + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 59 IMP,3050,IMP 7:20 PM 9/16/1973 + + LEV BCK +04473 000000 7 RALLYG: 0 /GET AN ENTRY IN RALLY TABLE +04474 140040 7 CRA +04475 026477 7 IMA RALLCF +04476 101040 7 SNZ /ANY ALLOCATES TO GO? +04477 103473 7 JMP RALLYG I /NO +04500 140040 7 CRA +04501 011600 7 STA RALLYX +04502 005636 7 LDA (MESS1) +04503 011602 7 STA RALADD /PRESET TABLE INCREMENTER +04504 073601 7 LDX RALTRY +04505 105637 7 RALLG: LDA (RALLY+NIMP 0 X) I +04506 101040 7 SNZ /ANY RALLY ENTRIES TO GO? +04507 003565 7 JMP RALLG0 /NO +04510 025600 7 IRS RALLYX /COUNT SOMETHING THERE +04511 105640 7 LDA (AMESS+NIMP 0 X) I +04512 141140 7 ICL +04513 006116 7 ANA THREE /GET NEXT MESS NO TO USE +04514 041576 7 ALS 2 +04515 140407 7 TCA +04516 015641 7 ADD (ALR 0 +04517 011523 7 STA RALGS1 +04520 013642 7 ERA (1000) +04521 011534 7 STA RALGS2 +04522 005643 7 LDA (17) +04523 7 RALGS1: BSS 1 /SHIFT MASK OVER +04524 001001 7 INH [I2H,TSK] +04525 107637 7 3 ANA (RALLY+NIMP 0 X) I +04526 101040 7 3 SNZ /ANYTHING IN NEXT SLOT TO GO? +04527 003565 7 3 JMP RALLG0 /NO +04530 113637 7 3 ERA (RALLY+NIMP 0 X) I +04531 127637 7 3 IMA (RALLY+NIMP 0 X) I /TURN OFF BITS +04532 113637 7 3 ERA (RALLY+NIMP 0 X) I +04533 000401 7 3 ENB BCK +04534 7 RALGS2: BSS 1 /SHIFT BACK THE BITS IN QUESTION +04535 023644 7 CAS (13) +04536 025473 7 IRS RALLYG /DEST DEAD, DOUBLE SKIP +04537 101000 7 NOP +04540 011160 7 STA BREPIN +04541 007631 7 ANA (INCTRN) +04542 027160 7 IMA BREPIN /GET INCTRN BIT AND SAVE IT +04543 006116 7 ANA THREE /EXTRACT THEM +04544 012115 7 ERA TWO 0"A"[ONEOR8 0 RFNM] +04545 101040 7 SNZ /IS THIS A REQ FOR 1 +04546 011602 7 STA RALADD /YES, DO NOT BUMP MESSAGE NO +04547 012115 7 ERA TWO /RESTORE A +04550 041672 7 ALR 6 0"A"[ONEOR8 0 RFNM] +04551 113640 7 ERA (AMESS+NIMP 0 X) I +04552 014000 7 ADD 0 +04553 016132 7 SUB MINIMP /OR IN MESS NO AND IMP NO +04554 127640 7 IMA (AMESS+NIMP 0 X) I +04555 015602 7 ADD RALADD /BUMP NEXT MESS TO REPLY TO +04556 127640 7 IMA (AMESS+NIMP 0 X) I + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 60 IMP,3050,IMP 7:20 PM 9/16/1973 + +04557 024000 7 IRS 0 +04560 100000 7 SKP +04561 072132 7 LDX MINIMP +04562 033601 7 STX RALTRY +04563 025473 7 IRS RALLYG +04564 003576 7 JMP RALLEX + +04565 000401 7 RALLG0: ENB BCK +04566 024000 7 IRS 0 +04567 003505 7 JMP RALLG +04570 004132 7 LDA MINIMP +04571 027601 7 IMA RALTRY +04572 013601 7 ERA RALTRY +04573 101040 7 SNZ /DID WE MAKE A COMPLETE PASS? +04574 005600 7 LDA RALLYX +04575 100040 7 SZE /AND DID WE FIND NOTHING AT ALL? +04576 010477 7 RALLEX: STA RALLCF /IF NO FOR EITHER, MUST COME BACK AT +04577 103473 7 JMP RALLYG I /IF YES FOR BOTH, LEAVE RALLCF AL( 1 + /IF ENTRIES WERE PUT DURING OUR PASS, RALLCF WILL HAVE BEEN 1 + + LEV VAR +04600 V RALLYX: BSS 1 /NON-ZERO = SOMETHING IN RALLY +04601 V RALTRY: BSS 1 +04602 V RALADD: BSS 1 /INCREMENT TO AMESS = 0 OR MESS1 + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 61 IMP,3050,IMP 7:20 PM 9/16/1973 + +04603 000077 C LEV CON CONSTANTS +04604 000300 C +04605 000200 C +04606 177771 C +04607 000050 C +04610 000100 C +04611 000002 C +04612 015033 C +04613 177770 C +04614 000003 C +04615 032371 C +04616 032271 C +04617 177477 C +04620 176014 C +04621 015205 C +04622 000202 C +04623 015161 C +04624 020210 C +04625 032261 C +04626 015114 C +04627 177677 C +04630 033467 C +04631 000010 C +04632 000331 C +04633 015504 C +04634 037700 C +04635 100010 C +04636 000400 C +04637 072671 C +04640 072571 C +04641 041700 C +04642 001000 C +04643 000017 C +04644 000013 C +02413 175663 C PAGEND 4,UNCON,4 + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 62 IMP,3050,IMP 7:20 PM 9/16/1973 + + + TSKI: LEV TSK /TASK INTERRUPT +00103 005107 6 TASKIL/ TSKI +05107 000000 6 0 TSKI/ INT TSK /TASK INTERRUPT COMES HERE +05110 000011 6 0 DXA +05111 003112 6 0 JMP .+1 +05112 011140 6 0 STA TA1 +05113 033141 6 0 STX TX1 +05114 000043 6 0 INK +05115 011142 6 0 STA TK1 +05116 004122 6 0 TSKMSK: LDA MINUS2 +05117 170120 6 0 SMK INTM +05120 010134 6 0 STA PRIM +05121 000401 6 0 TSKL: ENB TSK /ALL TASKS RETURN HERE +05122 004330 6 LDA STQ +05123 001001 6 INH MSK +05124 100040 6 0 SZE /IS TASK QUEUE EMPTY? +05125 003161 6 0 JMP TSKM /GOT A TASK +05126 140401 6 0 CMA /YES, TURN ON ALL BITS IN PRTY INT T +05127 010134 6 0 STA PRIM +05130 170120 6 0 SMK INTM /RESTORE REGISTERS AND KEYS +05131 073141 6 0 LDX TX1 +05132 000013 6 0 EXA +05133 005142 6 0 LDA TK1 +05134 171020 6 0 OTK +05135 005140 6 0 LDA TA1 +05136 000401 6 0 ENB TSK +05137 103107 6 JMP TSKI I + + LEV VAR +05140 V TA1: BSS 1 /TEMP A +05141 V TX1: BSS 1 /TEMP X +05142 V TK1: BSS 1 /TEMP KEYS +05143 V TASKIN: BSS 1 /INPUT CHAN - SIGN ON=FROM HOST +05144 V ACKBIT: BSS 1 /BIT PNTR FOR OUR ACK +05145 V OURR: BSS 1 /OUR OUTPUT MODEM CHANNEL +05146 V I2MSLT: BSS 1 /THE CHANNEL PNTR WE NEED +05147 V I2MBIT: BSS 1 /ODD-EVEN BIT POSITION FOR THIS PKT +05150 V ACKCH: BSS 1 /TRANSMIT ACK CHANNEL FOR THIS PK- +05151 V ACKP: BSS 1 /PNTR TO RELEVANT RSEX ENTRY +05152 V SWPCHT: BSS 1 /TEMP FOP SWPCHK +05153 V SATNO: BSS 1 /0 IF NONE, CH#+1 ELSE + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 63 IMP,3050,IMP 7:20 PM 9/16/1973 + + LEV TSK LCK MSK +05154 005710 6 0 TSKM2: LDA (STQ) /CLEAN UP Q PNTRS +05155 010401 6 0 STA ETQ +05156 003171 6 0 JMP TSKM1 + LEV TSK +05157 105151 6 TSKM3: LDA ACKP I +05160 003215 6 JMP TSKM4 + + LEV TSK LCK MSK +05161 010000 6 0 TSKM: STA 0 /TASK +05162 010514 6 0 STA THIS /STORE BUFF ADDR IN X AND THIS +05163 140040 6 0 CRA +05164 050002 6 0 STA PTRT X /CLEAR TRACE PTR +05165 066000 6 0 IMA 0 X /CLEAR BUFF CHAIN PNTR AND LOAD IN +05166 010330 6 0 STA STQ /STORE NEW ADDR IN HEAD OF Q +05167 101040 6 0 SNZ /WAS THIS LAST ENTRY IN Q? +05170 003154 6 0 JMP TSKM2 /YES +05171 000401 6 0 TSKM1: ENB TSK /X HAS BUFF ADDR +05172 044003 6 LDA INCH X +05173 011143 6 STA TASKIN /SAVE INPUT CHANNEL +05174 100400 6 SPL 0"A"HSTMOD /FROM HOST? +05175 003220 6 JMP TSKFOR /YES +05176 015711 6 ADD (RSEX) /NO,FROM MODEM, MUST DUPLICATE-DETF +05177 011151 6 STA ACKP +05200 044005 6 LDA HEAD X +05201 100100 6 SLZ 0"A"LINETS /IS THIS A ROUTING MESSAGE? +05202 003407 6 JMP TSKRUT /YES +05203 044004 6 LDA ACKH X +05204 141340 6 ICA +05205 006120 6 ANA SEVEN 0"A"CHANUM /GET CHANNEL NO +05206 015712 6 ADD (BITTAB) +05207 011144 6 STA ACKBIT /CONVERT TO BIT PNTR TABLE ADDR +05210 044004 6 LDA ACKH X +05211 100400 6 SPL 0"A"ODEVEN /GET ODD-EVEN BIT FROM PKT +05212 003157 6 JMP TSKM3 /JUMP IF BIT IS ONE +05213 105151 6 LDA ACKP I /COMPARE WITH WHAT WE WANT +05214 140401 6 CMA +05215 107144 6 TSKM4: ANA ACKBIT I /MASK WITH CONTENTS OF BITTAB +05216 100040 6 SZE +05217 003642 6 JMP FQMOD /IF DUPLICATE --FREE AND QUIT MODEM +05220 044006 6 TSKFOR: LDA HEAD1 X +05221 007713 6 ANA (DESTI) +05222 010000 6 STA 0 /STOR DEST NO FROM HEADER IN X +05223 044165 6 LDA RUT X /GET ROUTE +05224 101040 6 SNZ 0"A"RUTUS /IS IT FOR US? +05225 103714 6 JMP (FORUS) I /YES +05226 100400 6 SPL 0"A"RUTDED +05227 003601 6 JMP FQOK /FOR DEAD GUY, RUT WD WAS MINUS +05230 007715 6 ANA (RUTDLC) +05231 016114 6 SUB ONE /TASK STORE-AND-FORWARD +05232 010000 6 STA 0 /STOPE SHIFTED ROUTE IN X (0 TO C1 +05233 044433 6 LDA LINE X /TEST FOR LINE TEST STATUS +05234 100040 6 SZE /IS LINE DEAD? +05235 003637 6 JMP FQNG /YES, WAIT TILL ROUTING STABLE + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 64 IMP,3050,IMP 7:20 PM 9/16/1973 + +05236 001001 6 INH [M2I,I2M,H2I] +05237 004540 6 0 LDA NSFA /COMPUTE NO SF BUFFS IN USE +05240 016564 6 0 SUB NSFS +05241 141206 6 0 AOA /WE NEED ONE MORE +05242 022573 6 0 CAS MAXSI /ENOUGH S-F ROOM? +05243 003637 6 0 JMP FQNG /NO +05244 003637 6 0 JMP FQNG /NO +05245 004537 6 0 LDA NFA +05246 016563 6 0 SUB NFS /COMPUTE NO OF FREE BUFFS AVAIL, +05247 016542 6 0 SUB NALA /CONSIDERING ALLOCATED AND USED +05250 014566 6 0 ADD NALS +05251 016570 6 0 SUB MINF +05252 100400 6 0 SPL /DO WE HAVE MIN FREE BUFFS? +05253 003637 6 0 JMP FQNG /NO +05254 044653 6 0 LDA CHFREE X /FREE SLOT BITS +05255 140407 6 0 TCA +05256 046653 6 0 ANA CHFREE X /SINGLE LEAST SIGNIFICANT BIT SET +05257 101040 6 0 SNZ +05260 003637 6 0 JMP FQNG /ALL CHANNELS ARE IN USE +05261 011147 6 0 STA I2MBIT /FOR MARKING CHANNEL LATER +05262 052653 6 0 ERA CHFREE X /NOW MARK IT ASSIGNED +05263 050653 6 0 STA CHFREE X +05264 000401 6 0 ENB TSK /YES +05265 033145 6 STX OURR /SAVE OUR ROUTE (0 TO CH-1) + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 65 IMP,3050,IMP 7:20 PM 9/16/1973 + +05266 005147 6 LDA I2MBIT +05267 022116 6 CAS THREE +05270 040575 6 ARS 3 /CH 2-7 +05271 100000 6 SKP /CAS IS NEVER EQUAL +05272 003277 6 JMP GOTCHN /CH 0-1 +05273 022116 6 CAS THREE +05274 040575 6 ARS 3 /CH 5-7 +05275 014116 6 ADD THREE /CAS IS NEVER EQUAL +05276 014116 6 ADD THREE +05277 016114 6 GOTCHN: SUB ONE /GOT CHANNEL 0-7 +05300 011150 6 STA ACKCH +05301 054622 6 ADD I2MTAB X /GET PTR TO SLOT +05302 011146 6 STA I2MSLT +05303 005147 6 LDA I2MBIT +05304 111146 6 STA I2MSLT I /MARK SLOT IN USE +05305 046641 6 ANA TSEX X /GET O/E BIT IN TSEX +05306 100040 6 SZE /WAS IT ZERO? +05307 005716 6 LDA (200) 0"A"ODEVEN /NO, SET O/E BIT +05310 013150 6 ERA ACKCH /PUT SLOT NO IN A +05311 141240 6 ICR /PUT IN LEFT HALF +05312 072514 6 LDX THIS /BUFF ADDR TO X +05313 011147 6 STA I2MBIT /USED AS A TEMP WORD +05314 044111 6 LDA BUFE X +05315 140100 6 SSP 0"A"TWOQ +05316 027147 6 IMA I2MBIT /NOW HAS PTR TO CHECKSUM +05317 066004 6 IMA ACKH X /SAVE BIT, CHANNEL IN ACKHEADER +05320 056004 6 SUB ACKH X +05321 115147 6 ADD I2MBIT I /AND ADJUST CHECKSUM +05322 111147 6 STA I2MBIT I +05323 044007 6 LDA HEAD2 X /NOW PUT IN BIT FOR LO-HI LINE EN[ +05324 007717 6 ANA (0 0 177777"X"ENDBIT) +05325 073145 6 LDX OURR /THIS BIT DETECTS LOOPED LINES +05326 113720 6 ERA (LEND 0 X) I +05327 072514 6 LDX THIS +05330 066007 6 IMA HEAD2 X +05331 056007 6 SUB HEAD2 X /ADJUST CHECKSUM AGAIN +05332 115147 6 ADD I2MBIT I +05333 111147 6 STA I2MBIT I + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 66 IMP,3050,IMP 7:20 PM 9/16/1973 + +05334 044006 6 LDA HEAD1 X +05335 007721 6 ANA (TRACE) +05336 100040 6 SZE /MUST WE TRACE HIM? +05337 021504 6 JST TSUB /TRACE HIM IF NECESSARY +05340 005146 6 LDA I2MSLT /PUT OUR SLOT IN PKT +05341 050003 6 STA INCH X /AND I2M WILL SET IT UP AT OUTPUT * +05342 044005 6 LDA HEAD X +05343 007722 6 ANA (TRNREP) /GET TRNREP BIT +05344 001001 6 INH SIN +05345 101040 6 0 SNZ /IS THIS A REPLY? +05346 003357 6 0 JMP SFPRI /YES +05347 044006 6 0 LDA HEAD1 X +05350 100400 6 0 SPL 0"A"PRIBIT /IS THIS A PRI TRN? +05351 003357 6 0 JMP SFPRI /YES +05352 004514 6 0 LDA THIS /NO, SO PUT ON REG MODEM QUEUE +05353 073145 6 0 LDX OURR +05354 150363 6 0 STA EMQ XI /LINK BUFF TO END OF REG CHL Q +05355 050363 6 0 STA EMQ X +05356 003363 6 0 JMP SFALL + +05357 004514 6 0 SFPRI: LDA THIS /YES, SO PUT ON PRI MODEM QUEUE +05360 073145 6 0 LDX OURR +05361 150370 6 0 STA EMPQ XI /LINK BUFF TO END OF PRI CHL Q +05362 050370 6 0 STA EMPQ X +05363 024540 6 0 SFALL: IRS NSFA /COUNT A S-F PKT +05364 044440 6 0 LDA NONE X +05365 100040 6 0 SZE /POKE MODEM OUTPUT IF IDLE +05366 003604 6 0 JMP GOODM /NO NEED +05367 121723 6 0 JST (I2MSB) I RET TSK +05370 001001 6 INH ALL +05371 000011 6 0 DXA +05372 003604 6 0 JMP GOODM /RETURN GOOD ACK + + LEV FRE /CALL WITH INTERRUPTS LOCKED +05373 000000 0 FLUSH: 0 /RETURN BUFFER TO FREE LIST +05374 044111 0 LDA BUFE X +05375 100400 0 SPL 0"A"TWOQ /IS PACKET ON 2 QUEUES? +05376 003404 0 JMP FLUSH1 /YES +05377 004324 0 LDA FREE /NO, SO FREE IT +05400 050000 0 STA 0 X /STORE PNTR TO FREE LIST +05401 032324 0 STX FREE /STORE PNTR TO PACKET +05402 024537 0 IRS NFA /INCREASE NO OF FREE PKTS +05403 103373 0 JMP FLUSH I +05404 140100 0 FLUSH1: SSP 0"A"TWOQ /MARK PACKET AS ON ONE QUEUE +05405 050111 0 STA BUFE X +05406 103373 0 JMP FLUSH I + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 67 IMP,3050,IMP 7:20 PM 9/16/1973 + + LEV TSK +05407 073143 6 TSKRUT: LDX TASKIN /INPUT CHL NO +05410 040677 6 ARR 1 0"A"NULPKT +05411 100100 6 SLZ /THIS A NULL PACKET? +05412 003446 6 JMP TSKNUL /YES +05413 041677 6 ALR 1 +05414 141140 6 ICL /GET OTHER GUYS IMPNO +05415 066160 6 IMA NEIGHB X /SAVE IT +05416 100040 6 SZE /DO NOT KILL LINE IF WE JUST DID +05417 052160 6 ERA NEIGHB X +05420 100040 6 SZE /DO KILL LINE IF NEIGHBOR HAS CHANG1 +05421 003452 6 JMP NEIKIL +05422 065565 6 IRS E123 X /INCREMENT NUMBER OF RECD RUT MSGS +05423 101000 6 NOP +05424 044160 6 LDA NEIGHB X /COMPUTE AND SET HI-LO BIT +05425 016106 6 SUB MINE +05426 100040 6 SZE +05427 003433 6 JMP TSKCPY /COPY IN ROUTING INFO +05430 004114 6 LDA ONE +05431 010452 6 STA LUUP /BLINK LUUPED LITE +05432 003642 6 JMP FQMOD + +05433 001001 6 TSKCPY: INH MSK +05434 004124 6 0 LDA MINUS4 /LOCK OUT SLOW T.O +05435 170120 6 0 SMK INTM /SHARED CODE & TABLES +05436 010134 6 0 STA PRIM LEV T.O LCK MSK +05437 140040 5 0 CRA /MARK AS REAL INPUT +05440 000401 5 0 ENB T.O +05441 121724 5 JST (RSTINP) I +05442 072514 5 LDX THIS +05443 001001 5 INH [MSK,FRE] +05444 021373 5 0 JST FLUSH +05445 003116 5 0 JMP TSKMSK + + LEV TSK +05446 040675 6 TSKNUL: ARR 3 0"A"IHERDU +05447 100100 6 TSKNU2: SLZ /DID WE GET AN IHEARD YOU? +05450 064426 6 TSKNU3: DEFSTAT IRS LAC X, TSKIH /YES +00574 031212 6 +31770 005450 6 +32010 064426 6 +05451 003642 6 TSKNU4: JMP FQMOD + +05452 001001 6 NEIKIL: INH ALL +05453 011576 6 0 STA NEIT +05454 121725 6 0 JST (KILLIN) I +05455 005576 6 0 LDA NEIT + DEFHLT [NEIGHBOR IMP CHANGED] +05456 021635 6 0 JST THLTNG + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 68 IMP,3050,IMP 7:20 PM 9/16/1973 + + LEV TSK LCK [H2I,T.O] +05457 000000 6 4 SWPCHK: 0 +05460 011152 6 4 STA SWPCHT /BITS TO PUT INTO HEAD1 +05461 044006 6 4 LDA HEAD1 X +05462 007726 6 4 ANA (FORIMP 0 FOROCT DESTHI) +05463 066007 6 4 IMA HEAD2 X /SWITCH SRC FOR DEST AND V.V. +05464 007726 6 4 ANA (FRMIMP 0 FRMOCT SRCEHI) +05465 013152 6 4 ERA SWPCHT +05466 050006 6 4 STA HEAD1 X +05467 044111 6 4 LDA BUFE X +05470 006112 6 4 ANA SIGN 0"A"TWOQ +05471 014000 6 4 ADD 0 +05472 015727 6 4 ADD (MINPL+1) /FIX LENGTH OF REPLY +05473 050111 6 4 STA BUFE X +05474 005730 6 4 LDA (MINPL-ACKH+1) +05475 056004 6 4 SUB ACKH X +05476 056005 6 4 SUB HEAD X +05477 056006 6 4 SUB HEAD1 X /BUILD CHECKSUM +05500 056007 6 4 SUB HEAD2 X +05501 056010 6 4 SUB HEAD3 X +05502 050011 6 4 STA DATA X /NOW STORE IT +05503 103457 6 4 JMP SWPCHK I + + LEV TSK /TSUB DOES THE TASK PART OF TRACING +05504 000000 6 TSUB: 0 +05505 004416 6 LDA TIMES /GET TIME IN SLOW TICKS +05506 016107 6 SUB M30SEC +05507 050003 6 STA INCH X /GIVE PKT 30 SEC. TO LIVE +05510 044006 6 LDA HEAD1 X +05511 007721 6 ANA (TRACE) +05512 100040 6 SZE /MUST WE TRACE HIM? +05513 105731 6 TSUB2: LDA (TRON) I +05514 101040 6 SNZ +05515 103504 6 JMP TSUB I +05516 004325 6 LDA TTF /FREE TRACE BLOCK PNTR +05517 100040 6 SZE +05520 003524 6 JMP TS2 /JUMP IF THERE ARE FREE TRACE BLOCK +05521 141206 6 AOA +05522 010414 6 STA TTO /MARK TRACE TABLE OVERFLOW +05523 103504 6 JMP TSUB I + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 69 IMP,3050,IMP 7:20 PM 9/16/1973 + +05524 033572 6 TS2: STX SPB /SAVE BUFFER PNTR +05525 011573 6 STA STB /FREE TRC BLK BUFF PNTR +05526 050002 6 STA PTRT X /SET UP TRACE POINTER +05527 026341 6 IMA STRQ /GET STRT OF ACTIVE TRC Q +05530 127573 6 IMA STB I /LINK TO TOP OF TRACE Q +05531 010325 6 STA TTF /STORE ADDR OF NEXT FREE BLK +05532 004341 6 LDA STRQ /ADDR OF NEW TOP OF Q +05533 015732 6 ADD (THED+4 X) /SET UP LAST TRC BUFF ADDR +05534 011574 6 STA ITB +05535 005572 6 LDA SPB /ADDR OF PKT BUFF +05536 015732 6 ADD (HEAD+4 X) /SET UP LAST PKT BUFF ADDR +05537 011575 6 STA IMB +05540 072124 6 LDX MINUS4 /TRANSFER PKT BUFF TO TRC BUFF +05541 105575 6 LDA IMB I +05542 111574 6 STA ITB I +05543 024000 6 IRS 0 /FINISHED? +05544 003541 6 JMP .-3 /NO +05545 073572 6 LDX SPB /YES +05546 044001 6 LDA IT X /SAVE INPUT TIME IN TRACE TABLE +05547 073573 6 LDX STB +05550 050001 6 STA TIT X +05551 073572 6 LDX SPB +05552 044111 6 LDA BUFE X +05553 140100 6 SSP 0"A"TWOQ +05554 016000 6 SUB 0 +05555 016117 6 SUB FOUR 0"A"ACKH /CALCULATE PACKET LENGTH +05556 073573 6 LDX STB +05557 050012 6 STA TDONE X +05560 131040 6 RDCLOK +05561 003560 6 JMP .-1 /SAVE TASK TIME IN TRACE TABLE +05562 050002 6 STA TTT X +05563 073572 6 LDX SPB /RESTORE BUFFER PNTR IN X +05564 103504 6 JMP TSUB I + + LEV VAR +05565 V E123: BSS CH /NUMBER OF RUT MSGS RECD FROM CHL( +05572 V SPB: BSS 1 /SAVE PACKET BUFFER +05573 V STB: BSS 1 /SAVE TRACE BUFFER +05574 V ITB: BSS 1 /INDIRECT TO TRACE BUFFER +05575 V IMB: BSS 1 /INDIRECT TO PACKET BUFFER +05576 V NEIT: BSS 1 /TEMP + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 70 IMP,3050,IMP 7:20 PM 9/16/1973 + + /END-OF-TASK ROUTINES + /RETURN A NACK OR ACK TO THE SENDING MODEM, HOST, OR BACK + LEV TSK LCK ALL +05577 000000 6 0 THLTOK: 0 /REPORT BUG AND GIVE GOOD RETURN +05600 120745 6 0 JST HLTNCC I + LEV TSK +05601 072514 6 FQOK: LDX THIS /FREE+QUIT, GOOD RETURN +05602 001001 6 INH [FRE,SIN] +05603 021373 6 0 JST FLUSH /FREE THE BUFFER +05604 005143 6 0 GOODM: LDA TASKIN /GOOD RETURN +05605 100400 6 0 SPL 0"A"HSTMOD /FROM HOST? +05606 003622 6 0 JMP GOODH /YES +05607 010000 6 0 STA 0 0"A"INPCHN +05610 105144 6 0 LDA ACKBIT I /FROM MODEM, GIVE ACK +05611 050445 6 0 STA SNULL X /SEND A NULL PKT IF NECESSARY TO E'1 +05612 052646 6 0 ERA RSEX X /REVERSE PROPER BIT IN RSEX +05613 050646 6 0 STA RSEX X +05614 044440 6 0 LDA NONE X /CHECK ACTIVITY ON MODEM +05615 101040 6 0 SNZ /RESTART I2M IF NECESSARY FOR MY AC +05616 121723 6 0 JST (I2MSB) I RET TSK +05617 001001 6 INH ALL +05620 000011 6 0 DXA +05621 003121 6 0 JMP TSKL + +05622 140100 6 0 GOODH: SSP 0"A"HSTMOD /NEED TO CLEAR SIGN FOR HISB +05623 010000 6 0 STA 0 0"A"INPCHN +05624 064453 6 0 IRS TSKFLG X /DOUBLE SKIP = GOOD RETURN +05625 064453 6 0 IRS TSKFLG X +05626 014131 6 0 ADD MITH +05627 000013 6 0 EXA +05630 100400 6 0 SPL /FROM BACK HOST? +05631 121733 6 0 JST (HISB) I RET TSK /NO, POKE HOST WAITING FO +05632 001001 6 INH ALL +05633 000011 6 0 DXA +05634 003121 6 0 JMP TSKL + + LEV TSK LCK ALL +05635 000000 6 0 THLTNG: 0 /REPORT BUG AND GIVE BAD RETURN +05636 120745 6 0 JST HLTNCC I + LEV TSK +05637 005143 6 FQNG: LDA TASKIN /FREE+QUIT, BAD RETURN +05640 100400 6 SPL 0"A"HSTMOD /FROM HOST? +05641 003646 6 JMP BADH +05642 072514 6 FQMOD: LDX THIS /FROM MODEM, DO NOT ACK +05643 001001 6 INH FRE +05644 021373 6 0 JST FLUSH +05645 003121 6 0 JMP TSKL + + LEV TSK +05646 010000 6 BADH: STA 0 0"A"INPCHN /YES, RETURN A NACK TO HO +05647 064453 6 IRS TSKFLG X /SINGLE SKIP = BAD RETURN +05650 003121 6 JMP TSKL /DO NOT POKE HOST (ALLOW BACK TO RU + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 71 IMP,3050,IMP 7:20 PM 9/16/1973 + + LEV TSK LCK FRE +05651 004326 6 0 NEWMES: LDA RASF /NEW MULTI-PACKET MESSAGE FOR US +05652 101040 6 0 SNZ /GET REAS BLOCK + DEFHLT [NO REAS BLOCK FOR MULTI-PKT MESS] +05653 121734 6 0 JST (THLTNG) I +05654 004751 6 0 LDA 8PKTS +05655 014541 6 0 ADD NREA /CHECK REAS ROOM +05656 016565 6 0 SUB NRES +05657 022572 6 0 CAS MAXR +05660 101000 6 0 NOP /NO ROOM, FOUL-UP + DEFHLT [MAXR EXCEEDED BY NON-REQUEST MULTI-PKT MESS] +05661 121734 6 0 JST (THLTNG) I +05662 004537 6 0 LDA NFA +05663 016563 6 0 SUB NFS +05664 016751 6 0 SUB 8PKTS +05665 016570 6 0 SUB MINF +05666 100400 6 0 SPL + DEFHLT [MINF VIOLATED BY NON-REQUEST MULTI-PKT MESS] +05667 121734 6 0 JST (THLTNG) I +05670 104326 6 0 LDA RASF I +05671 026326 6 0 IMA RASF +05672 010000 6 0 STA 0 +05673 026340 6 0 IMA SHRQ /PUT ON REAS QUEUE +05674 050000 6 0 STA 0 X +05675 004751 6 0 LDA 8PKTS +05676 014541 6 0 ADD NREA /NOW TAKE ROOM +05677 010541 6 0 STA NREA +05700 004751 6 0 LDA 8PKTS +05701 014566 6 0 ADD NALS +05702 010566 6 0 STA NALS +05703 004112 6 0 LDA SIGN /INIT RMAX +05704 050002 6 0 STA RMAX X +05705 105735 6 0 LDA (MESSID) I /ESTABLISH RID +05706 050001 6 0 STA RID X + /RSF IS SET UP AT INIT AND AFTER USE TO BE ZERO + /THE SAME IS TRUE OF REAS PNTRS +05707 103736 6 0 JMP (OLDMES) I + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 72 IMP,3050,IMP 7:20 PM 9/16/1973 + +05710 000330 C LEV CON CONSTANTS +05711 000646 C +05712 001233 C +05713 000077 C +05714 006056 C +05715 000037 C +05716 000200 C +05717 176777 C +05720 050254 C +05721 020000 C +05722 000004 C +05723 012604 C +05724 026120 C +05725 011133 C +05726 050377 C +05727 000011 C +05730 000005 C +05731 030434 C +05732 040011 C +05733 013106 C +05734 005635 C +05735 006664 C +05736 006313 C +02414 176744 C PAGEND 5,UNCON,4 + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 73 IMP,3050,IMP 7:20 PM 9/16/1973 + + /TASK REASSEMBLY + LEV TSK +06056 072514 6 FORUS: LDX THIS /PNTR TO PKT BUFF +06057 044007 6 LDA HEAD2 X /TASK FOR US +06060 007674 6 ANA (SRCEI) /SOURCE IMP MASK +06061 011673 6 STA SOURCE /PREPARE MESS TABLE ENTRY +06062 044005 6 LDA HEAD X +06063 141044 6 CAR 0"A"MESSNO +06064 011661 6 STA MESNUM /SAVE OUR MESS NO +06065 013673 6 ERA SOURCE +06066 011664 6 STA MESSID /PREPARE MESSAGE ID +06067 044005 6 LDA HEAD X +06070 007675 6 ANA (TRNREP) +06071 100040 6 SZE +06072 005676 6 LDA (0 0 RMESS"X"TMESS) +06073 013677 6 ERA (TMESS) /PICK TRANSMIT OR REPLY TABLE +06074 015673 6 ADD SOURCE +06075 011660 6 STA MESTAB +06076 001001 6 INH [H2I,T.O] +06077 105660 6 4 LDA MESTAB I /GET OLDEST MSG NO WE ARE EXPECTING +06100 141044 6 4 CAR 0"A"MESSNO /GET MESS NO WE WANT +06101 017661 6 4 SUB MESNUM /COMPARE WITH MESS NO WE GOT +06102 100400 6 4 SPL /IS MESS NO WE GOT TOO HIGH? +06103 003375 6 4 JMP MESOUT /YES +06104 141140 6 4 ICL +06105 022116 6 4 CAS THREE /IS MESS NO WE GOT TOO LOW? +06106 003375 6 4 JMP MESOUT /YES +06107 101000 6 4 NOP /GOOD MESS NO +06110 015700 6 4 ADD (MBITS) /NOW CONVERT DIFF BETWEEN MESSNOS +06111 011662 6 4 STA MESBIT /INTO A BIT - 1,2,4, OR 10 +06112 044005 6 4 LDA HEAD X +06113 007701 6 4 ANA (INCTRN 0 TRNREP) +06114 013701 6 4 ERA (INCTRN 0 TRNREP) +06115 101040 6 4 SNZ /IS IT AN INCOMPLETE TRANS? +06116 003431 6 4 JMP INCGOT /YES +06117 105662 6 4 LDA MESBIT I /NO, LOAD DIFFERENCE BIT +06120 107660 6 4 ANA MESTAB I /CHECK AGAINST MSG NO +06121 000401 6 4 ENB TSK +06122 100040 6 SZE /IS MESS NO A DUPLICATE? +06123 103702 6 JMP (FQOK) I /YES, DISCARD PKT +06124 044005 6 LDA HEAD X /GOOD MESSAGE FOR US +06125 007675 6 ANA (TRNREP) +06126 101040 6 SNZ /IS IT A REPLY? +06127 103703 6 JMP (REPGOT) I /YES +06130 073673 6 LDX SOURCE +06131 001001 6 INH [FRE,H2I,T.O] +06132 044165 6 0 LDA RUT X +06133 100400 6 0 SPL + DEFHLT [RECVD TRANSMISSION FROM DEAD IMP] +06134 121704 6 0 JST (THLTOK) I +06135 007705 6 0 ANA (0 0 177777"X"RUTCMU) +06136 050165 6 0 STA RUT X +06137 072514 6 0 LDX THIS + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 74 IMP,3050,IMP 7:20 PM 9/16/1973 + +06140 044005 6 0 LDA HEAD X +06141 007706 6 0 ANA (GVBALL) +06142 100040 6 0 SZE /IS IT A REGULAR TRANSMIT? +06143 003447 6 0 JMP GUDGVB /NO, WE MUST RETURN A REPLY +06144 044006 6 0 LDA HEAD1 X +06145 121707 6 0 JST (HOSTNO) I +06146 000401 6 0 ENB TSK +06147 010000 6 STA 0 +06150 044504 6 LDA HIHD X 0"A"HSTUP +06151 072514 6 LDX THIS +06152 100040 6 SZE /IS THIS TRANS FOR A DEAD HOST? +06153 005710 6 LDA (0 0 TRNDED"X"TRNDIS) +06154 013711 6 ERA (JMP TRNDIS) /PICK REGULAR OR DEAD DIS[ +06155 011164 6 STA TRNJMP +06156 044005 6 LDA HEAD X /GOOD TRANSMISSION FOR US +06157 141050 6 CAL +06160 040572 6 ARS 6 0"A"ONEOR8"A"REQALL +06161 015164 6 ADD TRNJMP +06162 011164 6 STA TRNJMP +06163 001001 6 INH FRE +06164 6 0 TRNJMP: BSS 1 /DISPATCH ON 1 OR 8 PKT, REQ OR RE' +06165 003302 6 0 TRNDIS: JMP TRNGT8 /NON-REQ S PKT +06166 003455 6 0 JMP GUDRQ8 /REQ 8 PKT +06167 003227 6 0 JMP TRNGT1 /NON-REQ 1 PKT +06170 105662 6 0 LDA MESBIT I /REQ 1 PKT +06171 012114 6 0 ERA ONE +06172 101040 6 0 SNZ /IS THIS REQ THE NEXT TO GO? +06173 003204 6 0 JMP TRNDS1 /YES +06174 044006 6 0 LDA HEAD1 X /NO +06175 101400 6 0 SMI 0"A"PRIBIT /IS IT A PRI REQ? +06176 003222 6 0 JMP GUDRQ1 /NOT PRI, SO WE CAN GO NO FURTHER +06177 105660 6 0 LDA MESTAB I +06200 052005 6 0 ERA HEAD X +06201 007712 6 0 ANA (ORDNO) +06202 100040 6 0 SZE /IS HIS PRI ORD NO UP YET? +06203 003222 6 0 JMP GUDRQ1 /NO, SO HE MUST WAIT +06204 004542 6 0 TRNDS1: LDA NALA +06205 016566 6 0 SUB NALS +06206 014541 6 0 ADD NREA +06207 016565 6 0 SUB NRES +06210 141206 6 0 AOA +06211 022572 6 0 CAS MAXR +06212 003222 6 0 JMP GUDRQ1 /NO ROOM FOR 1 PKT MESS, TREAT AS R +06213 003222 6 0 JMP GUDRQ1 /NO ROOM FOR 1 PKT MESS, TREAT AS R +06214 004563 6 0 LDA NFS +06215 016537 6 0 SUB NFA +06216 141206 6 0 AOA +06217 014570 6 0 ADD MINF +06220 100400 6 0 SPL +06221 003244 6 0 JMP GUDTR1 + /NOTE THAT NO DUPLICATE DETECTION IS DONE HERE +06222 005664 6 0 GUDRQ1: LDA MESSID /ENTER HIS REQUEST +06223 013713 6 0 ERA (ONEOR8) /FOR ONE BUFFER +06224 121714 6 0 JST (RALLYP) I + DEFHLT [RALLY ENTRY ALREADY PRESENT FOR REQ 1 PKT] +06225 121704 6 0 JST (THLTOK) I +06226 103702 6 0 JMP (FQOK) I /DO NOT MARK MESS NO COMPLETE + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 75 IMP,3050,IMP 7:20 PM 9/16/1973 + +06227 004541 6 0 TRNGT1: LDA NREA /CHECK REAS ROOM +06230 016565 6 0 SUB NRES +06231 141206 6 0 AOA /ROOM FOR ONE MORE? +06232 022572 6 0 CAS MAXR + DEFHLT [MAXR EXCEEDED BY A NON-REQUEST 1 PKT MESS] +06233 101000 6 0 NOP +06234 121715 6 0 JST (THLTNG) I /NO, A FOUL-UP +06235 004563 6 0 LDA NFS +06236 016537 6 0 SUB NFA +06237 141206 6 0 AOA +06240 014570 6 0 ADD MINF +06241 101400 6 0 SMI /DO WE HAVE ENOUGH FREE? + DEFHLT [MINF VIOLATED BY A NON-REQUEST 1 PKT MESS] +06242 121715 6 0 JST (THLTNG) I /NO, A FOUL-UP +06243 024566 6 0 IRS NALS +06244 024541 6 0 GUDTR1: IRS NREA /YES, SO TAKE IT +06245 000401 6 0 ENB TSK +06246 033670 6 STX READY /SAVE PACKET POINTER +06247 003350 6 JMP GUDTRN /NOW TRY TO GIVE TO HOST + + LCK FRE +06250 003276 6 0 TRNDED: JMP TRNDD8 /NON-REQ 8 PKT +06251 003455 6 0 JMP GUDRQ8 /REQ 8 PKT +06252 024566 6 0 IRS NALS /NON-REQ 1 PKT - ONLY HAPPENS IF [' +06253 064010 6 0 TRNDD1: IRS HEAD3 X 0"A"CHSTD /REQ 1 PKT +06254 044005 6 0 LDA HEAD X +06255 007716 6 0 ANA (0 0 177777"X"INCTRN"X"TRNREP"X"ALLOC) +06256 050005 6 0 STA HEAD X +06257 005717 6 0 LDA (REPDED) /SWAP SRC&DEST +06260 121720 6 0 JST (SWPCHK) I /AND CHECKSUM IT +06261 005664 6 0 LDA MESSID +06262 072112 6 0 LDX SIGN /MARK ENTRY FOR DEST DEAD +06263 121714 6 0 JST (RALLYP) I /PUT IN A DUMMY ENTRY + DEFHLT [RALLY ENTRY ALREADY PRESENT FOR DESTINATION DEAD] +06264 121704 6 0 JST (THLTOK) I +06265 072514 6 0 LDX THIS +06266 132402 6 0 STX ERQ I /HAND TO BAK +06267 032402 6 0 STX ERQ +06270 021537 6 0 JST REASGT +06271 003463 6 0 JMP NXMES1 /NO PKTS CAME IN SO FAR +06272 044000 6 0 LDA 0 X +06273 111667 6 0 STA TEND I /SPLICE UP REAS Q +06274 121721 6 0 JST (REASF) I /AND FREE UP THIS BLK +06275 003463 6 0 JMP NXMES1 + +06276 004751 6 0 TRNDD8: LDA 8PKTS +06277 014566 6 0 ADD NALS +06300 010566 6 0 STA NALS /MUST TAKE BACK ROOM WE ALLOCATED +06301 003253 6 0 JMP TRNDD1 + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 76 IMP,3050,IMP 7:20 PM 9/16/1973 + +06302 000401 6 0 TRNGT8: ENB TSK +06303 044006 6 LDA HEAD1 X /MULTI-PACKET TRANS FOR US +06304 141340 6 ICA +06305 006120 6 ANA SEVEN 0"A"PKTNO /GET PACKET NO +06306 011663 6 STA PKTN +06307 015722 6 ADD (REAS 0 X) +06310 011666 6 STA ORS /SAVE POST-INDEXED PNTR TO OUR REAS +06311 021537 6 JST REASGT LCK T.O /FIND OUR GUY IN REAS +06312 103723 6 5 JMP (NEWMES) I /NOT THERE, SO START A NEW MESS +06313 033665 6 5 OLDMES: STX ORB /SAVE PNTR TO OUR REAS BLOCK +06314 105666 6 5 LDA ORS I +06315 100040 6 5 SZE /IS IT EMPTY? +06316 103702 6 5 JMP (FQOK) I /NO, A DUPLICATE PACKET +06317 004514 6 5 LDA THIS +06320 111666 6 5 STA ORS I /PUT PACKET IN OUR REAS SLOT +06321 010000 6 5 STA 0 +06322 044007 6 5 LDA HEAD2 X +06323 073665 6 5 LDX ORB +06324 101400 6 5 SMI 0"A"LSTPKT /IS THIS THE LAST PACKET? +06325 003334 6 5 JMP NOTL /NO +06326 005663 6 5 LDA PKTN /GET PACKET NO +06327 050002 6 5 STA RMAX X /SAVE IN REAS BLOCK +06330 016120 6 5 SUB SEVEN 0"A"8PKTS +06331 140407 6 5 TCA +06332 014565 6 5 ADD NRES +06333 010565 6 5 STA NRES /ADJUST REAS COUNT FOR SURPLUS +06334 044013 6 5 NOTL: LDA RSF X +06335 062002 6 5 CAS RMAX X /IS REAS DONE? +06336 100000 6 5 SKP /NO +06337 003342 6 5 JMP DONE /YES +06340 064013 6 5 IRS RSF X +06341 103724 6 5 JMP (GOODM) I + +06342 044000 6 5 DONE: LDA 0 X /REAS COMPLETE +06343 111667 6 5 STA TEND I /REMOVE BLOCK FROM QUEUE +06344 000401 6 5 ENB TSK +06345 005665 6 LDA ORB +06346 140500 6 SSM /MARK AS MULTI-PACKET +06347 011670 6 STA READY + +06350 021360 6 GUDTRN: JST MESSOK LCK [H2I,T.O] +06351 100100 6 4 SLZ /IS MESS NO THE ONE WE WANT? +06352 003555 6 4 JMP T2H /YES, GIVE TO HOST +06353 005670 6 4 LDA READY /NO, PUT BUFFER OR BLOCK +06354 026327 6 4 IMA MESSTK /ON COMPLETED MESSAGE STACK +06355 072327 6 4 LDX MESSTK /DO THIS SINCE SIGN BIT MAY BE SET +06356 050000 6 4 STA 0 X +06357 003471 6 4 JMP SMSTK /AND SEARCH FOR NEXT MESS + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 77 IMP,3050,IMP 7:20 PM 9/16/1973 + + LEV TSK +06360 000000 6 MESSOK: 0 /MARK MESS NO TO PREVENT DUPLICATES +06361 001001 6 INH [H2I,T.O] +06362 105660 6 4 LDA MESTAB I +06363 141044 6 4 CAR 0"A"MESSNO +06364 017661 6 4 SUB MESNUM +06365 141140 6 4 ICL +06366 015700 6 4 ADD (MBITS) +06367 011662 6 4 STA MESBIT +06370 105662 6 4 LDA MESBIT I +06371 113660 6 4 ERA MESTAB I /TURN ON GOT-IT BIT +06372 007725 6 4 ANA (0 0 177777"X"MSTO1"X"MSTO2) +06373 111660 6 4 STA MESTAB I /TURN OFF TIME OUT BITS +06374 103360 6 4 JMP MESSOK I + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 78 IMP,3050,IMP 7:20 PM 9/16/1973 + + LEV TSK LCK [H2I,T.O] +06375 044005 6 4 MESOUT: LDA HEAD X +06376 007701 6 4 ANA (INCTRN 0 TRNREP) +06377 013701 6 4 ERA (INCTRN 0 TRNREP) +06400 100040 6 4 SZE /IS THIS AN INC TRN? +06401 103702 6 4 JMP (FQOK) I /NO, OUT OF RANGE, DISCARD PKT +06402 044005 6 4 INCREP: LDA HEAD X /THIS CODE IS FOR OUT-OF-RANGE MESS +06403 007726 6 4 ANA (0 0 177777"X"INCTRN"X"TRNREP"X"GVBALL"X"RFNM) +06404 013676 6 4 ERA (RFNM) /RFNM ON IN ALL RPLYS XCPT REQ8 +06405 066005 6 4 IMA HEAD X +06406 007727 6 4 ANA (ONEOR8 0 REQALL) +06407 013676 6 4 ERA (REQALL) +06410 100040 6 4 SZE /REQ FOR 8? +06411 003415 6 4 JMP PUTREP /NO, MAKE A REPLY +06412 005730 6 4 LDA (ALLOC 0 RFNM) /Y, TURN OFF RFNM, TURN 'T +06413 052005 6 4 ERA HEAD X +06414 050005 6 4 STA HEAD X +06415 140040 6 4 PUTREP: CRA /SWAP DEST FOR SRC +06416 121720 6 4 JST (SWPCHK) I /AND CHECKSUM IT +06417 132402 6 4 STX ERQ I /ADD TO REPLY QUEUE +06420 032402 6 4 STX ERQ +06421 103724 6 4 JMP (GOODM) I /AND GIVE GOOD RETURN + +06422 021537 6 4 INCGT8: JST REASGT /FIND THIS INC TRN IN REAS +06423 003427 6 4 JMP SNDRP8 /NOT THERE, WE NEVER SAW HIM +06424 044000 6 4 LDA 0 X +06425 111667 6 4 STA TEND I /REMOVE FROM REAS QUEUE +06426 121721 6 4 JST (REASF) I /FREE REAS BLOCK AND PKTS +06427 005676 6 4 SNDRP8: LDA (RFNM) /CREATE A REPLY TO 8-PKT INC TRN +06430 003453 6 4 JMP SNDRP1 + +06431 105662 6 4 INCGOT: LDA MESBIT I /GOT AN INC TRANS +06432 107660 6 4 ANA MESTAB I /EXPLICITLY PERMIT DUPLICATES +06433 100040 6 4 SZE /HAVE WE SEEN HIM COMPLETED YET? +06434 003402 6 4 JMP INCREP /YES, SEND BACK DUPLICATE REPLY +06435 044005 6 4 LDA HEAD X +06436 007727 6 4 ANA (ONEOR8 0 REQALL) +06437 101040 6 4 SNZ /8 PKT INC TPN? +06440 003422 6 4 JMP INCGT8 /YES +06441 007713 6 4 ANA (ONEOR8) +06442 101040 6 4 SNZ /8 PKT REQ FOR ALL? +06443 003455 6 4 JMP GUDRQ8 /YES, IT IS INSIDE WINDOW +06444 044005 6 4 LDA HEAD X /NEVER SAW THIS 1 PKT GUY +06445 007706 6 4 ANA (GVBALL) +06446 100040 6 4 SZE /IS THIS A GVB? +06447 004751 6 4 GUDGVB: LDA 8PKTS /YES +06450 014566 6 4 ADD NALS /REMOVE BUFFER FROM ALLOCATE COUNT +06451 010566 6 4 STA NALS +06452 005727 6 4 LDA (ONEOR8 0 RFNM) +06453 072121 6 4 SNDRP1: LDX MINUS1 /MAKE A REPLY TO 1-PKT INC TRN +06454 003456 6 4 JMP GUDRAL + /SINCE IT MAY HAVE BEEN A REPLY TO AN INC TRN THAT WAS LOST + /WE SHOULD KEEP A RECORD OF THE HOST QUEUE LAST FLUSHED + /THIS WAY WE COULD SEND THE CORRECT DUPLICATE REPLY + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 79 IMP,3050,IMP 7:20 PM 9/16/1973 + +06455 140040 6 4 GUDRQ8: CRA +06456 013664 6 4 GUDRAL: ERA MESSID +06457 121714 6 4 JST (RALLYP) I /SET UP ENTRY TO REPLY + DEFHLT [RALLY ENTRY ALREADY PRESENT FOR INC OR REQ8] +06460 121704 6 4 JST (THLTOK) I +06461 072514 6 4 LDX THIS +06462 120671 6 4 JST FLUSHI I +06463 021360 6 4 NXMES1: JST MESSOK /MARK MESS NO AS COMPLETED +06464 105660 6 4 NXTMES: LDA MESTAB I +06465 101100 6 4 SLN /IS THIS THE MESS NO WE WANT? +06466 103724 6 4 JMP (GOODM) I /NO +06467 073660 6 4 LDX MESTAB +06470 121731 6 4 JST (UPMESS) I + + RET TSK +06471 005732 6 SMSTK: LDA (MESSTK) /SEARCH THE MESSAGE STACK +06472 011667 6 STA TEND /FOR MESSAGES WHOSE NUMBERS ARE UP +06473 001001 6 INH T.O +06474 004327 6 5 LDA MESSTK /GET CONTENTS OF STACK ENTRY +06475 101040 6 5 SRCSTK: SNZ /IS STACK EMPTY? +06476 003464 6 5 JMP NXTMES /YES +06477 011670 6 5 STA READY +06500 010000 6 5 STA 0 +06501 100400 6 5 SPL /IS THIS A REAS BLOCK? +06502 044003 6 5 LDA REAS X /YES, SO GET A PACKET +06503 010000 6 5 STA 0 +06504 044007 6 5 LDA HEAD2 X /GET SOURCE OF THIS PACKET +06505 013673 6 5 ERA SOURCE /COMPARE WITH OURS +06506 007674 6 5 ANA (SRCEI) +06507 100040 6 5 SZE /MATCH? +06510 003532 6 5 JMP SRCSTL /NO +06511 044006 6 5 LDA HEAD1 X +06512 101400 6 5 SMI 0"A"PRIBIT /IS IT PRIORITY? +06513 003520 6 5 JMP SRCST2 /NO +06514 105660 6 5 LDA MESTAB I /GET ORD NO WE WANT +06515 052005 6 5 ERA HEAD X /COMPARE WITH THIS PACKET +06516 007712 6 5 ANA (ORDNO) +06517 003524 6 5 JMP SRCST3 +06520 105660 6 5 SRCST2: LDA MESTAB I /GET MESS NO WE WANT +06521 017733 6 5 SUB (0 0 3"T"400) +06522 052005 6 5 ERA HEAD X /COMPARE WITH THIS PACKET +06523 141044 6 5 CAR 0"A"MESSNO +06524 100040 6 5 SRCST3: SZE /IS THIS THE NEXT TO GO? +06525 003532 6 5 JMP SRCSTL /NO +06526 073670 6 5 LDX READY +06527 066000 6 5 IMA 0 X /YES +06530 111667 6 5 STA TEND I /REMOVE FROM MESS STACK +06531 003555 6 5 JMP T2H /AND GIVE TO HOST + +06532 005670 6 5 SRCSTL: LDA READY /LOOP BACK FOR MORE +06533 140100 6 5 SSP +06534 011667 6 5 STA TEND +06535 105667 6 5 LDA TEND I +06536 003475 6 5 JMP SRCSTK + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 80 IMP,3050,IMP 7:20 PM 9/16/1973 + + LEV TSK +06537 000000 6 REASGT: 0 /FIND A MATCH ON MESSID IN REAS STO+ +06540 073734 6 LDX (SHRQ) +06541 001001 6 INH T.O /LOOK FOR THIS MESSAGE IN REAS +06542 044000 6 5 RELOOK: LDA 0 X /NEXT REAS BLOCK +06543 101040 6 5 SNZ /NO MORE REAS BLOCKS? +06544 103537 6 5 JMP REASGT I /YES, SO RETURN NO SKIP +06545 033667 6 5 STX TEND /SAVE END PNTR +06546 010000 6 5 STA 0 +06547 044001 6 5 LDA RID X /GET THIS MESS ID +06550 013664 6 5 ERA MESSID /COMPARE WITH OURS +06551 100040 6 5 SZE /IS THIS OUR MESSAGE? +06552 003542 6 5 JMP RELOOK /NO +06553 025537 6 5 IRS REASGT /SKIP=SUCCESS +06554 103537 6 5 JMP REASGT I + +06555 000401 6 5 T2H: ENB TSK +06556 004114 6 LDA ONE +06557 011672 6 STA NPKTS +06560 073670 6 LDX READY /LOAD THE PACKET PNTR +06561 005670 6 LDA READY /REGULAR MESSAGE READY FOR HOST +06562 100400 6 SPL /IS THIS A SINGLE PACKET? +06563 003625 6 JMP T2H8 /NO +06564 011671 6 STA READYE /SAVE END PNTR +06565 121735 6 T2HL1: JST (TSUB) I +06566 044006 6 LDA HEAD1 X +06567 001001 6 INH [I2H,H2I,T.O] +06570 121707 6 3 JST (HOSTNO) I /GET HOST NUMBER +06571 044006 6 3 LDA HEAD1 X +06572 006112 6 3 ANA SIGN 0"A"PRIBIT +06573 100040 6 3 SZE /PICK PRI OR REG QUEUE +06574 005736 6 3 LDA (EHPQ+0-EHQ) +06575 115737 6 3 ADD (LOCHST) I /AOD OFFSET GENERATED IN HOSTNO +06576 026000 6 3 IMA 0 /PUT IN X AND GET PKT PNTR +06577 150343 6 3 STA EHQ XI /PUT ON HOST QUEUE +06600 005671 6 3 LDA READYE +06601 050343 6 3 STA EHQ X +06602 005672 6 3 LDA NPKTS /NUM PKTS IN MSG +06603 054517 6 3 ADD NHA X /NUM PKTS FOR HOST +06604 050517 6 3 STA NHA X /ADJUST COUNTS +06605 073670 6 3 LDX READY +06606 044006 6 3 LDA HEAD1 X +06607 073660 6 3 LDX MESTAB +06610 101400 6 3 SMI 0"A"PRIBIT /PRIORITY? +06611 003622 6 3 JMP T2HL2 /NO +06612 121740 6 3 JST (UPORD) I /YES, SO BUMP ORD NO +06613 073670 6 3 LDX READY +06614 105660 6 3 LDA MESTAB I /GET MESS NO WE WANT +06615 017733 6 3 SUB (0 0 3"T"400) +06616 052005 6 3 ERA HEAD X /COMPARE WITH WHAT WE GOT +06617 141044 6 3 CAR 0"A"MESSNO +06620 073660 6 3 LDX MESTAB +06621 101040 6 3 SNZ /MATCH? +06622 121731 6 3 T2HL2: JST (UPMESS) I /BUMP MESS NO +06623 121741 6 3 JST (TASK2H) I RET TSK /POKE HOST IF NECESSARY +06624 003471 6 JMP SMSTK /GO BACK FOR MORE + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 81 IMP,3050,IMP 7:20 PM 9/16/1973 + + /THE FIRST PKT IS COUNTED FIRST, IN T2H + /AND TRACED LAST, IN T2HL1 + /SUBSEQUENT PKTS ARE COUNTED AND TRACED IN T2HS1 + LEV TSK +06625 140100 6 T2H8: SSP /MULTI-PACKET MESSAGE READY +06626 011665 6 STA ORB /OUR REASSY BLOCK +06627 044003 6 LDA REAS X /LOAD PKT PNTR +06630 011670 6 STA READY +06631 140040 6 CRA +06632 050013 6 STA REAS+8 X 0"A"RSF + /A TRICK TO INIT RSF AND MAKE IT LOOK LIKE PKT 9 +06633 044004 6 T2H81: LDA REAS+1 X /LOAD ADDR OF NEXT PACKET +06634 150003 6 STA REAS XI /CHAIN PACKETS TOGETHER +06635 101040 6 SNZ /IS THIS THE LAST PKT? +06636 003650 6 JMP T2H82 /YES +06637 033671 6 STX READYE /NO, STORE THE PKT PNTR +06640 010000 6 STA 0 +06641 121735 6 JST (TSUB) I /TRACE PKT IF NECESSARY +06642 073671 6 LDX READYE +06643 140040 6 CRA /CLEAR REAS PNTR +06644 050003 6 STA REAS X +06645 024000 6 IRS 0 /INCREMENT ADDRESS +06646 025672 6 IRS NPKTS /INCREMENT PKT COUNT +06647 003633 6 JMP T2H81 /CHAIN NEXT PACKET + +06650 066003 6 T2H82: IMA REAS X /CLEAR REAS PNTR +06651 011671 6 STA READYE /AND SAVE LAST PKT PNTR +06652 073670 6 LDX READY /LOAD FIRST PKT PNTR +06653 005665 6 LDA ORB /LOAD REASSY BLOCK PNTR +06654 001001 6 INH T.O +06655 026326 6 5 IMA RASF /FREE REAS BLOCK AND LINK TO TOP +06656 110326 6 5 STA RASF I /OF FREE LIST +06657 003565 6 5 JMP T2HL1 + + LEV VAR +06660 V MESTAB: BSS 1 /PNTR TO MESS TAB ENTRY +06661 V MESNUM: BSS 1 /MESSNO OF THIS PKT +06662 V MESBIT: BSS 1 /BIT CORRESPONDING TO OUR MESSAGE +06663 V PKTN: BSS 1 /NUMBER OF THIS PACKET +06664 V MESSID: BSS 1 /MESSAGE ID (MESS NO+SRCE IMP) +06665 V ORB: BSS 1 /OUR REAS BLOCK +06666 V ORS: BSS 1 /OUR REAS SLOT +06667 V TEND: BSS 1 /TEMP END PNTR +06670 V READY: BSS 1 /PNTR TO PACKET TO GIVE TO HOST +06671 V READYE: BSS 1 /END PNTR FOR READY +06672 V NPKTS: BSS 1 /PKT COUNTER +06673 V SOURCE: BSS 1 /SOURCE IMP FOR THIS PACKET + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 82 IMP,3050,IMP 7:20 PM 9/16/1973 + +06674 000077 C LEV CON CONSTANTS +06675 000004 C +06676 000100 C +06677 032271 C +06700 001246 C +06701 000014 C +06702 005601 C +06703 007063 C +06704 005577 C +06705 177437 C +06706 000002 C +06707 007244 C +06710 000335 C +06711 003165 C +06712 000060 C +06713 000200 C +06714 015303 C +06715 005635 C +06716 177761 C +06717 000400 C +06720 005457 C +06721 021321 C +06722 040003 C +06723 005651 C +06724 005604 C +06725 177477 C +06726 177661 C +06727 000300 C +06730 000102 C +06731 015347 C +06732 000327 C +06733 001400 C +06734 000340 C +06735 005504 C +06736 000010 C +06737 007257 C +06740 015361 C +06741 007222 C +02415 176751 C PAGEND 6,UNCON,1 + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 83 IMP,3050,IMP 7:20 PM 9/16/1973 + + LEV TSK +07063 044005 6 REPGOT: LDA HEAD X /REPLY TO A TRANSMISSION OF OURS +07064 007327 6 ANA (ONEOR8) +07065 101040 6 SNZ /IS IT A REPLY TO A MULTI-PACKET? +07066 003134 6 JMP REPGT8 /YES +07067 105330 6 LDA (MESSID) I +07070 001001 6 INH [H2I,T.O] +07071 121331 6 4 JST (PPTGET) I /FIND OUR TRANS IN RPT +07072 003220 6 4 JMP GOTGVB /NOT THERE, MUST BE A GVB +07073 011131 6 4 STA PPTASK /SAVE PPT PNTR +07074 000401 6 4 ENB TSK +07075 072514 6 LDX THIS +07076 044005 6 LDA HEAD X +07077 007332 6 ANA (ALLOC) +07100 101040 6 SNZ /IS THIS REPLY AN ALLOCATE OF 1? +07101 003113 6 JMP NOALL1 /NO +07102 173131 6 LDX PPTASK I /YES, CHECK FOR DUPLICATE ALLOC +07103 044005 6 LDA HEAD X +07104 007333 6 ANA (REQALL) +07105 101040 6 SNZ /WAS REQUEST BIT SET? +07106 103334 6 JMP (FQOK) I /NO, SO ALLOC IS A DUPLICATE +07107 105131 6 LDA PPTASK I /YES, SO WE MARK PPT +07110 140500 6 SSM 0"A"RETRAN /FOR RETRANSMISSION FROM BACK +07111 111131 6 STA PPTASK I +07112 103334 6 JMP (FQOK) I /MESS NO NOT REPLIED TO YET + +07113 021260 6 NOALL1: JST RFNM1 /SET UP TWDPA FOR RFNM OR INC +07114 003125 6 0 LCK FRE JMP DDEAD1 /GIVE HOST A DESTINATION DEAD +07115 173131 6 LEV TSK LDX PPTASK I +07116 044010 6 LDA HEAD3 X /PICK UP LINK WORD +07117 021306 6 JST RFNM2 LCK FRE +07120 044007 6 0 LDA HEAD2 X +07121 021244 6 0 JST HOSTNO +07122 044006 6 0 LDA HEAD1 X /GFT SOURCE OF MESS +07123 007335 6 0 ANA (0 0 177777"X"LSTPKT"X"HICODE) +07124 013132 6 0 ERA TWDPA /PUT IN IH MESS TYPE +07125 073257 6 0 DDEAD1: LDX LOCHST +07126 120670 6 0 JST OWP I /DO A 2 WRD PUT +07127 003213 6 0 DEFSTAT JMP PPTFRE, HS6 +00575 031304 6 0 +31771 007127 6 0 +32011 003213 6 0 +07130 103336 6 0 JMP (FQNG) I /NO ROOM FOR 2 WRD MESS + + LEV VAR +07131 V PPTASK: BSS 1 /POINTER TO OUR PPT OR PLT SLOT +07132 V TWDPA: BSS 1 /FIRST WORD OF 2 WRD PUT +07133 V LOCHNO: BSS 1 + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 84 IMP,3050,IMP 7:20 PM 9/16/1973 + + LEV TSK +07134 105330 6 REPGT8: LDA (MESSID) I /REPLY TO A MULTI-PCKT TRANS +07135 001001 6 INH [H2I,T.O] +07136 121337 6 4 JST (PLTGET) I /FIND OUR TRANS IN PLT + DEFHLT [CANT FIND MULTI-PKT MESS FOR THIS REPLY] +07137 121340 6 4 JST (THLTOK) I /NOT THERE, FOUL-UP +07140 033131 6 4 STX PPTASK /SAVE PLT PNTR +07141 044000 6 4 LDA PLT0 X +07142 006120 6 4 ANA SEVEN 0"A"PLTHST +07143 011133 6 4 STA LOCHNO /GET LOCAL HOST NO +07144 072514 6 4 LDX THIS +07145 044005 6 4 LDA HEAD X +07146 007332 6 4 ANA (ALLOC) +07147 000401 6 4 ENB TSK +07150 101040 6 SNZ /IS THIS REPLY AN ALLOCATE OF 8? +07151 003166 6 JMP NOALL8 /NO +07152 001001 6 INH [SIN,H2I,T.O] +07153 105341 6 0 LDA (TALLYI) I /GET IN PNTR +07154 013342 6 0 ERA (TALLY+TALLYL) /COMPARE WITH END PNTR +07155 101040 6 0 SNZ /AT END? +07156 103336 6 0 JMP (FQNG) I /YES, NO ROOM FOR ALLOCATE SO NACF +07157 105343 6 0 LDA (SOURCE) I /GET SOURCE OF ALLOC +07160 111344 6 0 STA (TALLYI 0 I) I /STUFF THRU IN PNTR +07161 125341 6 0 IRS (TALLYI) I /BUMP IN PNTR +07162 044005 6 0 LDA HEAD X +07163 007333 6 0 ANA (RFNM) +07164 101040 6 0 SNZ /IS THIS REPLY AN ALLOCATED RFNM? +07165 003233 6 0 JMP GUDAL8 /NO, JUST AN ALLOCATE OF 8, POKE HO + RET TSK +07166 021260 6 NOALL8: JST RFNM1 /SET UP TWDPA FOR RFNM OR INC +07167 003176 6 0 LCK FRE JMP DDEAD8 /GIVE HOST A DESTINATION DEAD +07170 073131 6 LEV TSK LDX PPTASK +07171 044030 6 LDA PLT2 X /PICK UP LINK WORD +07172 021306 6 JST RFNM2 LCK FRE +07173 044014 6 0 LDA PLT1 X /GET SOURCE OF MESS +07174 007335 6 0 ANA (0 0 177777"X"LSTPKT"X"HICODE) +07175 013132 6 0 ERA TWDPA /PUT IN IH MESS TYPE +07176 073133 6 0 DDEAD8: LDX LOCHNO +07177 033257 6 0 STX LOCHST +07200 120670 6 0 JST OWP I /DO A 2 WRD PUT +07201 003215 6 0 DEFSTAT JMP GUDRP0, HS7 /AND POKE HOST +00576 031313 6 0 +31772 007201 6 0 +32012 003215 6 0 + +07202 072514 6 0 LDX THIS /NO ROOM FOR 2 WRD MESS +07203 044005 6 0 LDA HEAD X +07204 007332 6 0 ANA (ALLOC) +07205 101040 6 0 SNZ /WAS REPLY AN ALLOCATE OF 8? +07206 103336 6 0 JMP (FQNG) I /NO, SO QUIT +07207 105343 6 0 LDA (SOURCE) I /YES, GET SOURCE +07210 121345 6 0 JST (TALLYG) I /AND GET TALLY ENTRY BACK AGAIN +07211 103336 6 0 JMP (FQNG) I /NOT THERE, FOUL-UP +07212 103336 6 0 JMP (FQNG) I /AND QUIT + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 85 IMP,3050,IMP 7:20 PM 9/16/1973 + +07213 173131 6 0 PPTFRE: LDX PPTASK I +07214 120671 6 0 JST FLUSHI I /FREE PPT ENTRY NOW THAT RFNM IS IN +07215 021222 6 0 GUDRP0: JST TASK2H /POKE HOST IF NECESSARY + LEV TSK +07216 140040 6 GUDRP1: CRA +07217 111131 6 STA PPTASK I /CLEAR PPT OR PLT ENTRY +07220 121346 6 GOTGVB: JST (MESSOK) I /MARK MESS NO AS REPLIED + LCK [H2I,T.O] +07221 103334 6 4 JMP (FQOK) I + + LCK SIN +07222 000000 6 0 TASK2H: 0 /GOT SOMETHING FOR HOST OUTPUT +07223 073257 6 0 LDX LOCHST +07224 104700 6 0 LDA IHXX I +07225 000013 6 0 EXA +07226 101040 6 0 SNZ /IS HOST IDLE? +07227 121347 6 0 JST (IHSB) I RET TSK /YES, SO POKE IT +07230 001001 6 INH ALL +07231 120672 6 0 JST DODXA I RET TSK +07232 103222 6 JMP TASK2H I + + LCK SIN +07233 073133 6 0 GUDAL8: LDX LOCHNO /GOT AN ALLOCATE OF 8 FOR HOST INPU +07234 044453 6 0 LDA HILO X +07235 017350 6 0 SUB (HIALL) +07236 000013 6 0 EXA +07237 101040 6 0 SNZ /IS HOST HUNG ON ALLOCATE? +07240 121351 6 0 JST (HISB) I RET TSK /POKE HIM SINCE HE IS WAI +07241 001001 6 INH ALL +07242 120672 6 0 JST DODXA I RET TSK +07243 003216 6 JMP GUDRP1 + + LEV [T.O,TSK] +07244 000000 5 HOSTNO: 0 /COMPUTE HOST NO +07245 011257 5 STA LOCHST +07246 007352 5 ANA (DESTH) +07247 040672 5 ARR 6 +07250 027257 5 IMA LOCHST /SAVE DEST HOST +07251 007353 5 ANA (FORIMP) +07252 100040 5 SZE /FAKE HOST? +07253 004130 5 LDA PLNH /YES +07254 015257 5 ADD LOCHST +07255 011257 5 STA LOCHST +07256 103244 5 JMP HOSTNO I + LEV VAR +07257 V LOCHST: BSS 1 /WHICH HOST WE ARE FEEDING + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 86 IMP,3050,IMP 7:20 PM 9/16/1973 + + LEV TSK +07260 000000 6 RFNM1: 0 /DISTINGUISH BETWEEN RFNM AND INC T: +07261 044006 6 LDA HEAD1 X +07262 007354 6 ANA (REPDED) +07263 100040 6 SZE /IS THIS A DESTINATION DEAD? +07264 003275 6 JMP RFNMD /YES +07265 044005 6 LDA HEAD X +07266 007355 6 ANA (INCTRN) +07267 100040 6 SZE /IS THIS REPLY MARKED INCOMFLETE? +07270 005356 6 LDA (0 0 CRFNM"X"CINCTR) /YES +07271 013357 6 ERA (CRFNM) /NO +07272 011132 6 STA TWDPA /SAVE IH MESS TYPE +07273 025260 6 IRS RFNM1 +07274 103260 6 JMP RFNM1 I + +07275 044010 6 RFNMD: LDA HEAD3 X 0"A"CHSTD +07276 001001 6 INH FRE +07277 010515 6 0 STA TWDP /SAVE LINK WORD ANO CODE +07300 044006 6 0 LDA HEAD1 X +07301 021244 6 0 JST HOSTNO +07302 044007 6 0 LDA HEAD2 X +07303 007335 6 0 ANA (0 0 177777"X"LSTPKT"X"HICODE) +07304 013360 6 0 ERA (CDESTD) /PUT IN DEST DEAD CODE +07305 103260 6 0 JMP RFNM1 I + + LEV TSK +07306 000000 6 RFNM2: 0 /TRANSLATE SOME INCOMPLETES INTO +07307 001001 6 INH FRE /ERROR IN DATA MESS +07310 010515 6 0 STA TWDP /SAVE LINK WORD +07311 007361 6 0 ANA (SUBCOD) +07312 013362 6 0 ERA (CERROR) +07313 100040 6 0 SZE /WAS THIS MARKED AS AN ERROR AT SOU +07314 003317 6 0 JMP .+3 /NO +07315 005363 6 0 LDA (CERRDT) /YES, SO CHANGE IH MESS TYPE +07316 011132 6 0 STA TWDPA +07317 005132 6 0 LDA TWDPA +07320 013364 6 0 ERA (CINCTR) +07321 101040 6 0 SNZ /IS THE IH MESS TYPE INC TRN? +07322 103306 6 0 JMP RFNM2 I /YES, KEEP SUB CODE +07323 004515 6 0 LDA TWDP /NO, A RFNM OR ERROR IN DATA +07324 007365 6 0 ANA (LINKNO) +07325 010515 6 0 STA TWDP /WE MAY HAVE PUT IN AT INC? TIME +07326 103306 6 0 JMP RFNM2 I + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 87 IMP,3050,IMP 7:20 PM 9/16/1973 + +07327 000200 C LEV CON CONSTANTS +07330 006664 C +07331 015033 C +07332 000002 C +07333 000100 C +07334 005601 C +07335 070377 C +07336 005637 C +07337 015205 C +07340 005577 C +07341 015155 C +07342 032271 C +07343 006673 C +07344 115155 C +07345 015114 C +07346 006360 C +07347 016042 C +07350 014445 C +07351 013106 C +07352 000300 C +07353 040000 C +07354 000400 C +07355 000010 C +07356 006000 C +07357 002400 C +07360 003400 C +07361 000007 C +07362 000004 C +07363 004000 C +07364 004400 C +07365 177760 C +02416 173373 C PAGEND 7,UNCON,4 + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 88 IMP,3050,IMP 7:20 PM 9/16/1973 + + + PAGM2I: LEV M2I / MODEM TO IMP (M2I) +00064 010043 0 M1INIL/ M2I1 +00065 010067 0 M2INIL/ M2I2 +00066 010113 0 M3INIL/ M2I3 +00067 010137 0 M4INIL/ M2I4 +00070 010163 0 M5INIL/ M2I5 + PAGM2I/ +10043 000000 0 M2I1: INT M2I /MODEM 1 ENTPANCE +10044 000011 0 DXA +10045 033244 0 STX TX /SAVE X REG +10046 072113 0 LDX ZERO /SET UP ACTIVE MODEM NO +10047 0 M2I1A: BSS 1 /INITIALLY A JMP M2II UNTIL AN INPL +10050 000043 0 INK +10051 011245 0 STA TK /SAVE KEYS +10052 070471 0 DEFSTAT M1ERR,MI1 +00577 031202 0 +31773 010052 0 +32013 070471 0 +10053 003231 0 M1OK: JMP M2I0 /THIS IS A NOP WHEN THE LINE GOES DI +10054 004021 0 DIS1: LDA M1INBP+1 +10055 017625 0 SUB (BUFE-ACKH) +10056 010020 0 M2I1B: STA M1INBP +10057 030471 0 M1IN /ERROR- NEW "IN" INTO SAME BUFFER +10060 005245 0 DPP1: LDA TK +10061 000013 0 EXA +10062 171020 0 OTK +10063 005243 0 LDA TA +10064 073244 0 LDX TX +10065 000401 0 ENB M2I +10066 103043 0 JMP M2I1 I + +10067 000000 0 M2I2: INT M2I /MODEM 2 ENTRANCE +10070 000011 0 DXA +10071 033244 0 STX TX +10072 072114 0 LDX ONE +10073 0 M2I2A: BSS 1 +10074 000043 0 INK +10075 011245 0 STA TK +10076 070472 0 DEFSTAT M2ERR,MI1A +00600 031226 0 +31774 010076 0 +32014 070472 0 +10077 003231 0 M2OK: JMP M2I0 +10100 004023 0 DIS2: LDA M2INBP+1 +10101 017625 0 SUB (BUFE-ACKH) +10102 010022 0 STA M2INBP +10103 030472 0 M2IN +10104 005245 0 DPP2: LDA TK +10105 000013 0 EXA +10106 171020 0 OTK +10107 005243 0 LDA TA +10110 073244 0 LDX TX +10111 000401 0 ENB M2I +10112 103067 0 JMP M2I2 I + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 89 IMP,3050,IMP 7:20 PM 9/16/1973 + +10113 000000 0 M2I3: INT M2I /MODEM 3 ENTRANCE +10114 000011 0 DXA +10115 033244 0 STX TX +10116 072115 0 LDX TWO +10117 0 M2I3A: BSS 1 +10120 000043 0 INK +10121 011245 0 STA TK +10122 070473 0 DEFSTAT M3ERR,MI1B +00601 031236 0 +31775 010122 0 +32015 070473 0 +10123 003231 0 M3OK: JMP M2I0 +10124 004025 0 DIS3: LDA M3INBP+1 +10125 017625 0 SUB (BUFE-ACKH) +10126 010024 0 STA M3INBP +10127 030473 0 M3IN +10130 005245 0 DPP3: LDA TK +10131 000013 0 EXA +10132 171020 0 OTK +10133 005243 0 LDA TA +10134 073244 0 LDX TX +10135 000401 0 ENB M2I +10136 103113 0 JMP M2I3 I + +10137 000000 0 M2I4: INT M2I /MODEM 4 ENTRANCE +10140 000011 0 DXA +10141 033244 0 STX TX +10142 072116 0 LDX THREE +10143 0 M2I4A: BSS 1 +10144 000043 0 INK +10145 011245 0 STA TK +10146 070474 0 DEFSTAT M4ERR,MI1C +00602 031246 0 +31776 010146 0 +32016 070474 0 +10147 003231 0 M4OK: JMP M2I0 +10150 004027 0 DIS4: LDA M4INBP+1 +10151 017625 0 SUB (BUFE-ACKH) +10152 010026 0 STA M4INBP +10153 030474 0 M4IN +10154 005245 0 DPP4: LDA TK +10155 000013 0 EXA +10156 171020 0 OTK +10157 005243 0 LDA TA +10160 073244 0 LDX TX +10161 000401 0 ENB M2I +10162 103137 0 JMP M2I4 I + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 90 IMP,3050,IMP 7:20 PM 9/16/1973 + +10163 000000 0 M2I5: INT M2I /MODEM 5 ENTRANCE +10164 000011 0 DXA +10165 033244 0 STX TX +10166 072117 0 LDX FOUR +10167 0 M2I5A: BSS 1 +10170 000043 0 INK +10171 011245 0 STA TK +10172 070475 0 DEFSTAT M5ERR,MI1D +00603 031256 0 +31777 010172 0 +32017 070475 0 +10173 003231 0 M5OK: JMP M2I0 +10174 004031 0 DIS5: LDA M5INBP+1 +10175 017625 0 SUB (BUFE-ACKH) +10176 010030 0 STA M5INBP +10177 030475 0 M5IN +10200 005245 0 DPP5: LDA TK +10201 000013 0 EXA +10202 171020 0 OTK +10203 005243 0 LDA TA +10204 073244 0 LDX TX +10205 000401 0 ENB M2I +10206 103163 0 JMP M2I5 I + + /SOME OFFSETS WE NEED FOR THE FIRST MODEM INPUT TO GRAB A BU + DIS1O=DIS1-0-M2I1 + M2I1AO=M2I1A-0-M2I1 + M2I1BO=M2I1B-0-M2I1 +10207 011243 0 M2II: STA TA +10210 044064 0 LDA M1INIL X +10211 010000 0 STA 0 /BASE REG FOR OUR INSTR MODIFICATIO +10212 044011 0 LDA DIS1O X +10213 015626 0 ADD (STA-0-LDA) +10214 011223 0 STA M2II1 +10215 104324 0 LDA FREE I +10216 101040 0 SNZ +10217 003227 0 JMP M2II2 +10220 026324 0 IMA FREE +10221 024563 0 IRS NFS +10222 015627 0 ADD (BUFE 0 I) +10223 0 M2II1: BSS 1 /SET UP FIRST REAL INPUT BUFFER +10224 005207 0 LDA M2II +10225 050004 0 STA M2I1AO X +10226 042011 0 JMP DIS1O X + +10227 005630 0 M2II2: LDA (I 0 1) +10230 042013 0 JMP M2I1BO X + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 91 IMP,3050,IMP 7:20 PM 9/16/1973 + +10231 032674 0 M2I0: STX MP /SAVE ACTIVE MODEM NO +10232 045254 0 LDA LEND X /PICK UP END-OF-LINE BIT FOR THIS MI +10233 011261 0 STA LENDT +10234 104324 0 LDA FREE I /GET PKT FOR FREE LIST +10235 101040 0 DEFSTAT SNZ, MI3 +00604 031217 0 +32000 010235 0 +32020 101040 0 +10236 143604 0 JMP DIS XI /FREE LIST EMPTY - INPUT LOST +10237 024563 0 IRS NFS +10240 026324 0 IMA FREE +10241 015631 0 ADD (ACKH 0 I) /SET UP DMC START INPUT PNTR +10242 143262 0 JMP DIP XI /DISPATCH TO SEPARATE CODE FOR EACH + + LEV VAR +10243 V TA: BSS 1 /SAVE A REG +10244 V TX: BSS 1 /SAVE X REG +10245 V TK: BSS 1 /SAVE KEYS +10246 V TAR: BSS 1 /SAVE ADDRET +10247 010053 V M2IOK: M1OK +10250 010077 V M2OK +10251 010123 V M3OK +10252 010147 V M4OK +10253 010173 V M5OK +10254 V LEND: BSS CH /ENDBIT ON=HIGH NO IMP + /SIGN BIT ON= DEAD LINE +10261 V LENDT: BSS 1 /TEMP BECAUSE OF ONLY ONE X REG + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 92 IMP,3050,IMP 7:20 PM 9/16/1973 + + LEV CON +10262 010317 C DIP: DP1 +10263 010311 C DP2 +10264 C SATDEF DP3 +02244 010264 C +02274 010303 C +02324 010303 C +10265 010275 C DP4 +10266 010267 C DP5 + + LEV M2I +10267 072030 0 DP5: LDX M5INBP +10270 010030 0 STA M5INBP +10271 015625 0 ADD (BUFE-ACKH) +10272 026031 0 IMA M5INBP+1 +10273 030475 0 M5IN +10274 003324 0 JMP DIPE + +10275 072026 0 DP4: LDX M4INBP +10276 010026 0 STA M4INBP +10277 015625 0 ADD (BUFE-ACKH) +10300 026027 0 IMA M4INBP+1 +10301 030474 0 M4IN +10302 003324 0 JMP DIPE + +10303 072024 0 DP3: LDX M3INBP +10304 010024 0 STA M3INBP +10305 015625 0 ADD (BUFE-ACKH) +10306 026025 0 IMA M3INBP+1 +10307 030473 0 M3IN +10310 003324 0 JMP DIPE + +10311 072022 0 DP2: LDX M2INBP +10312 010022 0 STA M2INBP +10313 015625 0 ADD (BUFE-ACKH) +10314 026023 0 IMA M2INBP+1 +10315 030472 0 M2IN +10316 003324 0 JMP DIPE + +10317 072020 0 DP1: LDX M1INBP /PICK UP OUR DMC INPUT PNTR +10320 010020 0 STA M1INBP /STORE NEW DMC INPUT PNTR +10321 015625 0 ADD (BUFE-ACKH) /COMPUTE NEW DMC END PN+' +10322 026021 0 IMA M1INBP+1 /SWAP FOR CURRENT END PNTR +10323 030471 0 M1IN /DO NEW INPUT OCP + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 93 IMP,3050,IMP 7:20 PM 9/16/1973 + +10324 017627 0 DIPE: SUB (BUFE 0 I) /GET OLD PKT PNTR + SAVE IN X +10325 011611 0 STA M2ISP /SAVE FOR TASK-ING OR FLUSHING +10326 026000 0 IMA 0 /SWAP IT FOR END PNTR +10327 017630 0 SUB (1 0 I) /ADJUST IT FOR ONE OFF +10330 050111 0 STA BUFE X 0"A"TWOQ /SAVE IT IN PKT END PNTR +10331 140040 0 CRA +10332 050000 0 STA 0 X /CLEAR CHAIN PNTR +10333 044005 0 LDA HEAD X +10334 100400 0 SPL 0"A"SNDCOR +10335 101100 0 SLN 0"A"LINETS +10336 100000 0 SKP /ALLOW SNDCOR W/O CHKSUM +10337 103632 0 JMP (M2IRQC) I /SEND CORE REQUEST +10340 005633 0 LDA (M2IADR) +10341 026111 0 IMA ADDRET /SET UP ADD CHAIN RETURN FOR M2I +10342 011246 0 STA TAR /AND SAVE CURRENT OWNER OF ADDER +10343 004000 0 LDA 0 +10344 056111 0 SUB BUFE X /COMPUTE BUFFER LENGTH +10345 015634 0 ADD (ADDBOT+ACKH) /ADD IN TABLE OFFSET +10346 011351 0 STA M2IADJ /AND SAVE AS ADD DISPATCH +10347 017635 0 SUB (ADDBOT) /GET -(NO OF WORDS) IN A +10350 103351 0 JMP M2IADJ I /AND JMP INTO ADD CHAIN +10351 0 M2IADJ: BSS 1 +10352 100040 0 M2IADR: SZE /IS THE CHECKSUM GOOD? + DEFPLC [NOP HERE TO ACCEPT BAD CHECKSUM PACKETS] +10353 003402 0 JMP PKTCH1 /NO, REPORT AS AN ERROR +10354 005246 0 LDA TAR +10355 010111 0 STA ADDRET /AND RESTORE PREVIOUS OWNER OF ADC +10356 131040 0 RDCLOK +10357 003356 0 JMP .-1 +10360 050001 0 STA IT X /SAVE INPUT TIME- 100 MS CLOCK +10361 004674 0 LDA MP 0"A"INPCHN"A"HSTMOD +10362 050003 0 STA INCH X /SAVE INPUT MODEM NO +10363 044005 0 LDA HEAD X +10364 101100 0 SLN 0"A"LINETS /LT OR ROUTE? +10365 003420 0 JMP M2IPKT /NO +10366 040677 0 ARR 1 +10367 100100 0 SLZ 0"A"NULPKT /IS THIS A NULL PKT OF ACKS ONLY? +10370 003404 0 JMP M2INUL /YES +10371 040677 0 ARR 1 +10372 100100 0 SLZ 0"A"GETCOR /A RELOAD DEMAND? +10373 103636 0 JMP (M2IDMC) I /YES +10374 073611 0 M2T0: LDX M2ISP +10375 132401 0 M2T: STX ETQ I /PUT ON TASK QUEUE +10376 032401 0 STX ETQ +10377 030041 0 TASK /POKE TASK INTERRUPT +10400 072674 0 LDX MP +10401 143577 0 JMP DIPP XI /DISMISS INTERRUPT + +10402 072674 0 PKTCH1: LDX MP + DEFHLT [SOFTWARE CHECKSUM ERROR IN PACKET] +10403 121637 0 JST (PKTCHK) I + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 94 IMP,3050,IMP 7:20 PM 9/16/1973 + +10404 044005 0 M2INUL: LDA HEAD X /GOT A NULL PACKET OF ACKS +10405 141140 0 ICL /PICK UP IMP NO +10406 012106 0 ERA MINE /COMPARE WITH MINE +10407 101040 0 SNZ /IS THIS LINE LOOPED? +10410 003375 0 JMP M2T /YES, GIVE NULL TO TASK, IGNORE ACK1 +10411 004420 0 LDA THD /PICK UP CHAN TO HIGH NO IMP +10412 012674 0 ERA MP /COMPARE WITH THIS LINE NO +10413 100040 0 SZE /IS IT THIS LINE? +10414 003426 0 JMP M2IACK /NO +10415 044006 0 LDA HEAD1 X /YES, SO COPY IN HIS VALUE FOR SYNC +10416 010417 0 STA SYNC /KEEPING GLOBAL TIME THROUGHOUT NET +10417 003426 0 JMP M2IACK /NO, PROCESS ACKS, THEN GIVE TO TA 1 + +10420 044007 0 M2IPKT: LDA HEAD2 X +10421 007640 0 ANA (ENDBIT) +10422 013261 0 ERA LENDT +10423 101400 0 SMI /IS THIS LINE DOWN? +10424 101040 0 SNZ /IS THIS PKT FROM US? +10425 103641 0 JMP (M2IFRE) I /YES. THROW AWAY PKT +10426 044004 0 M2IACK: LDA ACKH X +10427 140401 0 CMA +10430 141050 0 CAL 0"A"ACKTAB +10431 011612 0 STA ACKT /ACKS FROM PACKET +10432 072674 0 LDX MP +10433 052641 0 ERA TSEX X +10434 046653 0 ANA CHFREE X /SHOULD BE NO ACKS ON FREE SLOTS +10435 100040 0 SZE + DEFHLT [SPURIOUS ACK] +10436 121642 0 JST (PKTCH2) I +10437 005612 0 LDA ACKT +10440 066641 0 IMA TSEX X /COMPARE WITH WHAT WE GOT +10441 052641 0 ERA TSEX X +10442 101040 0 SNZ +10443 003374 0 JMP M2T0 /NO ACKS, SO QUIT +10444 011612 0 STA ACKT /SAVE ACKS TO PROCESS +10445 052653 0 ERA CHFREE X /FREE UR ACKED CHANNELS +10446 050653 0 STA CHFREE X +10447 005612 0 LDA ACKT + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 95 IMP,3050,IMP 7:20 PM 9/16/1973 + +10450 173643 0 ACKLOP: LDX (I2MTAB 0 X) I +10451 140407 0 TCA +10452 007612 0 ANA ACKT /GET LOWEST BIT THAT TRANSITIONED +10453 013612 0 ERA ACKT /TURN IT OFF +10454 027612 0 IMA ACKT /UPDATE SET OF ACKS TO PROCESS +10455 013612 0 ERA ACKT /AND GO PROCESS THIS ONE +10456 023644 0 CAS (20) +10457 003547 0 JMP ACK567 +10460 003563 0 JMP ACK4 +10461 022117 0 CAS FOUR +10462 003566 0 JMP ACK3 +10463 003571 0 JMP ACK2 +10464 101100 0 SLN +10465 003574 0 JMP ACK1 +10466 140040 0 CRA +10467 066000 0 IMA 0 X +10470 072674 0 ACKS: LDX MP +10471 023645 0 CAS (1777) /IS THIS A TRUE PKT PNTR? +10472 003475 0 JMP ACKGUD /YES +10473 101000 0 NOP + DEFHLT [QUASI-IMPOSSIBLE SPURIOUS ACK] +10474 121642 0 JST (PKTCH2) I /DEBUG SPURIOUS ACK +10475 062634 0 ACKGUD: CAS I2MNXT X /IS THIS THE PKT CURRENTLY ON THE L +10476 100000 0 SKP /NO +10477 003536 0 JMP ACKSYN /YES, WE CANT FREE IT YET +10500 010000 0 STA 0 +10501 044111 0 LDA BUFE X +10502 100400 0 SPL 0"A"TWOQ +10503 003511 0 JMP FREE1 /ON TWO QUEUES +10504 004324 0 LDA FREE /ON ONE ONLY, SO FREE +10505 050000 0 STA 0 X +10506 032324 0 STX FREE +10507 024537 0 IRS NFA +10510 003513 0 JMP FREE2 +10511 140100 0 FREE1: SSP 0"A"TWOQ +10512 050111 0 STA BUFE X /MARK AS ON ONE QUEUE NOW +10513 024564 0 FREE2: IRS NSFS + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 96 IMP,3050,IMP 7:20 PM 9/16/1973 + +10514 044002 0 ACKS1: LDA PTRT X /TRACING? +10515 100040 0 SZE +10516 003543 0 JMP ACTR2 /GO DO IT +10517 044111 0 ACTR1: LDA BUFE X /GET PACKET LENGTH +10520 140100 0 SSP 0"A"TWOQ +10521 016000 0 SUB 0 +10522 016116 0 SUB THREE 0"A"[ACKH-1] +10523 072674 0 LDX MP +10524 055613 0 ADD THRUPW X +10525 100400 0 SPL +10526 004112 0 LDA SIGN /MARK OFLO +10527 051613 0 STA THRUPW X +10530 065620 0 IRS THRUPT X +10531 101000 0 NOP +10532 005612 0 LDA ACKT +10533 101040 0 SNZ /HAVE WE PROCESSED ALL THE ACKS? +10534 003374 0 JMP M2T0 /YES, SO QUIT +10535 003450 0 JMP ACKLOP +10536 140500 0 ACKSYN: SSM +10537 050634 0 STA I2MNXT X +10540 140100 0 SSP +10541 010000 0 STA 0 +10542 003514 0 JMP ACKS1 /MARK THE BUFFER AS ACKED + +10543 121646 0 ACTR2: JST (TRCDUN) I /TRACING PACKET +10544 072674 0 LDX MP /NEEDED FOR TRCDUN +10545 073611 0 LDX M2ISP +10546 003517 0 JMP ACTR1 + +10547 022753 0 ACK567: CAS C100 +10550 003560 0 JMP ACK7 +10551 003555 0 JMP ACK6 +10552 140040 0 ACK5: CRA +10553 066005 0 IMA 5 X +10554 003470 0 JMP ACKS +10555 140040 0 ACK6: CRA +10556 066006 0 IMA 6 X +10557 003470 0 JMP ACKS +10560 140040 0 ACK7: CRA +10561 066007 0 IMA 7 X +10562 003470 0 JMP ACKS +10563 140040 0 ACK4: CRA +10564 066004 0 IMA 4 X +10565 003470 0 JMP ACKS +10566 140040 0 ACK3: CRA +10567 066003 0 IMA 3 X +10570 003470 0 JMP ACKS +10571 140040 0 ACK2: CRA +10572 066002 0 IMA 2 X +10573 003470 0 JMP ACKS +10574 140040 0 ACK1: CRA +10575 066001 0 IMA 1 X +10576 003470 0 JMP ACKS + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 97 IMP,3050,IMP 7:20 PM 9/16/1973 + + LEV CON +10577 010060 C DIPP: DPP1 +10600 010104 C DPP2 +10601 010130 C DPP3 +10602 010154 C DPP4 +10603 010200 C DPP5 +10604 010054 C DIS: DIS1 +10605 010100 C DIS2 +10606 010124 C DIS3 +10607 010150 C DIS4 +10610 010174 C DIS5 + + LEV VAR +10611 V M2ISP: BSS 1 /SAVED PACKET POINTER +10612 V ACKT: BSS 1 +10613 V THRUPW: BSS CH +10620 V THRUPT: BSS CH + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 98 IMP,3050,IMP 7:20 PM 9/16/1973 + +10625 000105 C LEV CON CONSTANTS +10626 004000 C +10627 100111 C +10630 100001 C +10631 100004 C +10632 011116 C +10633 010352 C +10634 001562 C +10635 001556 C +10636 011170 C +10637 011101 C +10640 001000 C +10641 011124 C +10642 011127 C +10643 040622 C +10644 000020 C +10645 001777 C +10646 011144 C +02417 175655 C PAGEND 10,UNCON,5 + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 99 IMP,3050,IMP 7:20 PM 9/16/1973 + + + /MODEM TO IMP PACKET-ERROR STUFF + + LEV M2I +11101 000000 0 PKTCHK: 0 /ADDRESS OF PKT ERROR +11102 120745 0 JST HLTNCC I /REPORT TRAP TO NCC +11103 105366 0 PKTCHC: LDA (TAR) I +11104 010111 0 STA ADDRET /RESTORE PREVIOUS OWNER OF ADDER +11105 004537 0 LDA NFA +11106 016563 0 SUB NFS +11107 016751 0 SUB TEN /LEAVE MORE THAN MINF +11110 100400 0 SPL /ROOM TO SEND PKT TO DIAG? +11111 003123 0 JMP NODIAG /NO +11112 105367 0 LDA (M2ISP) I /PICK UP PKT PNTR +11113 026342 0 IMA DIAGQ /PUT ON DIAG QUEUE +11114 111370 0 STA (M2ISP 0 I) I /AND SET UP CHAIN PNTR +11115 103371 0 JMP (DIPP 0 XI) I /DISMISS + +11116 072674 0 M2IRQC: LDX MP +11117 004124 0 LDA MINUS4 +11120 050265 0 STA SLT X +11121 004112 0 LDA SIGN 0"A"SNDCOR +11122 050421 0 STA SIHY X /MARK TO SEND CORE +11123 173367 0 NODIAG: LDX (M2ISP) I /AND FREE BAD PKT +11124 120671 0 M2IFRE: JST FLUSHI I +11125 072674 0 LDX MP +11126 103371 0 JMP (DIPP 0 XI) I + +11127 000000 0 PKTCH2: 0 +11130 120745 0 JST HLTNCC I +11131 021133 0 JST KILLIN /KILL LINES FOR SPURIOUS ACKS +11132 003103 0 JMP PKTCHC /CONTINUE + KILTIM=10. /LINE HELD DEAD TIME + + LEV [M2I,T.O,TSK,BCK] +11133 000000 0 KILLIN: 0 /SUBR TO STOP INPUT AND OUTPUT ON +11134 005372 0 LDA (NOP) /KILL THE LINE INSTANTLY +11135 111373 0 STA (M2IOK 0 XI) I +11136 005374 0 LDA (-KILTIM) /OTHER IMP WILL SEE THE LINE GO D[ +11137 050265 0 STA SLT X +11140 050433 0 STA LINE X /FOR NCC AND RTGO +11141 140040 0 KILL2: CRA +11142 050160 0 KILL3: STA NEIGHB X +11143 103133 0 KILL4: JMP KILLIN I + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 100 IMP,3050,IMP 7:20 PM 9/16/1973 + + LEV [M2I,I2H] +11144 000000 0 TRCDUN: 0 /FINISH TRACE BLOCK +11145 011167 0 STA TRCD +11146 044001 0 LDA ST X +11147 073167 0 LDX TRCD +11150 050003 0 STA TST X +11151 131040 0 RDCLOK +11152 003151 0 JMP .-1 +11153 050004 0 STA TAT X +11154 004112 0 LDA SIGN +11155 052012 0 ERA TDONE X +11156 050012 0 STA TDONE X +11157 005167 0 LDA TRCD +11160 015375 0 ADD (TQUE) +11161 011167 0 STA TRCD +11162 105144 0 LDA TRCDUN I +11163 011164 0 STA .+1 +11164 0 BSS 1 /LDX FROM PAGE 0 +11165 133167 0 STX TRCD I +11166 103144 0 JMP TRCDUN I + LEV VAR +11167 V TRCD: BSS 1 /TRCDUN PTR + + LEV M2I +11170 044007 0 M2IDMC: LDA HEAD2 X /RELOAD DEMAND +11171 013205 0 ERA PASWRD /CHECK PASSWORD +11172 100040 0 SZE /KOSHER? +11173 003203 0 JMP M2IDM1 /NO +11174 044004 0 LDA ACKH X /LOOK AT DEMAND +11175 101400 0 SMI /PANIC DEMAND? +11176 103376 0 JMP (1004) I /YES. INSTANT RELOAD, A=MODEM NUMBE +11177 004674 0 LDA MP /NO, USE OUR MODEM NO. +11200 141206 0 AOA /(COUNTING 1-4) +11201 010137 0 STA SW3FG /AND NICE-STOP/RELOAD +11202 003124 0 JMP M2IFRE + +11203 072674 0 M2IDM1: LDX MP + DEFHLT [RELOAD DEMAND WITH BAD PASSWORD] +11204 021101 0 JST PKTCHK + + DEFPLC [DEMAND RELOAD PASSWORD] +11205 175461 0 PASWRD: 175461 /KEEP NEXT LOCATIONS IN ORDER +11206 177777 0 DMNDCR: -1 /ACKH. USED FOR RELOAD CODE +11207 000005 0 GETCOR 0 LINETS /HEADER +11210 000000 0 0 /SYNC +11211 000000 0 0 /PASSWORD PUT HERE MANUALLY +11212 0 BSS 1 /CHECKSUM + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 101 IMP,3050,IMP 7:20 PM 9/16/1973 + + + /LINE SPEED COMPUTATIONS + LEV I2M LCK ALL +11213 012114 2 0 I2MRM: ERA ONE 0"A"RM /THIS IS RM CLEAR FLAG +11214 111377 2 0 STA (RMFLG 0 X) I /NOW CHK TO SEE IF TIME I: +11215 100400 2 0 SPL /SIGN MINUS IF FIRST TIME THROUGH +11216 003323 2 0 JMP I2MRMI /INITIALIZATION +11217 141140 2 0 ICL /SPD TYPE FROM L. HALF INTD RT. +11220 010000 2 0 STA 0 /USED AS INDEX INTO MARGIN TABLE +11221 045331 2 0 LDA DELSPD X /GET PERMISSABLE VARIANCE +11222 011360 2 0 STA DELTA +11223 173400 2 0 LDX (OCHN) I /RESTORE CHAN # IN X +11224 055346 2 0 ADD RMLAST X /MAXIMUM ACCEPTABLE TIME FOR THIS M: +11225 123401 2 0 CAS (THIST) I /COMP W/ACTUAL TIME FOR THIS MSG +11226 003240 2 0 JMP I2MRMA /MAX>THIS, SO FAR SO GOOD +11227 003245 2 0 JMP I2MRMB /MAX=THIS, ALL OK, IN SPEC + DEFHLT [LINE SPEED DECREASED] +11230 021231 2 0 I2MRMD: JST I2MSCG +11231 000000 2 0 I2MSCG: 0 +11232 120745 2 0 JST HLTNCC I /SEND MSG TO NCC +11233 105377 2 0 LDA (RMFLG 0 X) I /DO HOLD DOWN +11234 007402 2 0 ANA (0 0 177777"X"SHD) +11235 013403 2 0 ERA (SHD) /(6) SPEED HOLD DOWN +11236 111377 2 0 STA (RMFLG 0 X) I /STORED IN RMFLG +11237 003260 2 0 JMP I2MRMC /PUT THIST INTO LAST AND QUIT + + /TIME WAS MIN? +11240 017360 2 0 I2MRMA: SUB DELTA +11241 017360 2 0 SUB DELTA /MIN ACCEPTABLE TIME +11242 123401 2 0 CAS (THIST) I /COMP W/ACTUAL TIME + DEFHLT [LINE SPEED INCREASED] +11243 021231 2 0 JST I2MSCG /MIN>THIS, TOO SLOW +11244 101000 2 0 NOP /MIN=THIS, ALL OK +11245 105377 2 0 I2MRMB: LDA (RMFLG 0 X) I /MINTHIS) +11275 003300 2 0 JMP I2MRMH / " " " " = " +11276 024000 2 0 IRS 0 /NOPE, TRY NEXT SLOWER TYPE +11277 003272 2 0 JMP I2MRMG +11300 045340 2 0 I2MRMH: LDA LINDTT+NSPD-1 X /GET LINE DEAD TIME FOR T1 +11301 011360 2 0 STA DELTA /AND SAVE IN TEMP +11302 004000 2 0 LDA 0 /INDEX= -TYPE +11303 140407 2 0 TCA /COMPLIMENT +11304 141340 2 0 ICA /INTO LEFT HALF +11305 173400 2 0 LDX (OCHN) I /RESTORE CHAN IN X +11306 111377 2 0 STA (RMFLG 0 X) I 0"A"SHD"A"RM /BACK INTO RMFLT +11307 141340 2 0 ICA /GET SPEED TYPE +11310 015407 2 0 ADD (RMCLKS) /ADD TABLE ADDRESS +11311 051353 2 0 STA RMCLKP X /SAVE FOR USE IN RSTOUT +11312 005360 2 0 LDA DELTA /PICK UP TEMP +11313 051361 2 0 STA LINDT X /AND SAVE AS THIS LINE'S DEAD TIME +11314 044433 2 0 LDA LINE X +11315 100040 2 0 SZE /IS LINE UP? +11316 021133 2 0 JST KILLIN /NO, RESET TIME IN CASE JUST RELO7 +11317 105401 2 0 LDA (THIST) I /PUT (THIS+LAST)/2 INTO ACTUAL +11320 055346 2 0 ADD RMLAST X +11321 040477 2 0 LGR 1 +11322 003257 2 0 JMP I2MRMF + +11323 140100 2 0 I2MRMI: SSP /INITIALIZE FIRST TIME THROUGH +11324 111377 2 0 STA (RMFLG 0 X) I /CLEAR INIT BIT TOO, +11325 003260 2 0 JMP I2MRMC /PUT THIS INTO LAST AND QUIT + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 103 IMP,3050,IMP 7:20 PM 9/16/1973 + + LEV CON + /NSPD-1 ENTRIES +11326 000161 C TIMSPC: 161 /(125K)MAX TIME A RM TAKES IN TYP1 ] +11327 001066 C 1066 /(25K) TYPE 2 +11330 004202 C 4202 /(6.5K) TYPE 1 (ALL SLOWER TYPE 0) + + /NSPD ENTRIES +11331 000377 C DELSPD: 377 /00 10X OF EXPECTED TIME FOR RM (+8I +11332 000177 C 177 /01 +11333 000060 C 60 /10 +11334 000060 C 60 /11 + /NSPD ENTRIES +11335 177324 C LINDTT: 0 0-PTCK"T"5 /FOR 250KBS +11336 177704 C 0 0-PTCK /FOR 50KBS +11337 177764 C 0 0-PTCK"Q"5 /FOR 10KBS +11340 177771 C 0 0-PTCK"Q"10 /LINE DEAD TIME FOR 5KBS + + LEV VAR +11341 V RMTACT: BSS CH /ACTUAL TIME FOR RM (AVERAGED) +11346 V RMLAST: BSS CH /TIME FOR LAST RM IN 100 MU SEC'S +11353 V RMCLKP: BSS CH /PTR TO ENTRY IN RMCLKS +11360 V DELTA: BSS 1 /DELSPD ENTRY FOR THIS LINE +11361 V LINDT: BSS CH /LINE HELD DEAD TIMES + +11366 010246 C LEV CON CONSTANTS +11367 010611 C +11370 110611 C +11371 150577 C +11372 101000 C +11373 150247 C +11374 177766 C +11375 000011 C +11376 001004 C +11377 052620 C +11400 012654 C +11401 012644 C +11402 177771 C +11403 000006 C +11404 012156 C +11405 000002 C +11406 177775 C +11407 020274 C +02420 173433 C PAGEND 11,UNCON,4 + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 104 IMP,3050,IMP 7:20 PM 9/16/1973 + + /IMP TO MODEM (I2M) + + PAGI2M: + LEV I2M + +00071 012127 2 M1OTIL/ I2M1 +00072 012123 2 M2OTIL/ I2M2 +00073 012117 2 M3OTIL/ I2M3 +00074 012113 2 M4OTIL/ I2M4 +00075 012107 2 M5OTIL/ I2M5 + + PAGI2M/ LEV VAR + +12103 V TATA: BSS 1 /I2M TEMPS +12104 V TXTX: BSS 1 +12105 V TCTC: BSS 1 +12106 V IRET: BSS 1 + + /IMP TO MODEM INTERRUPTS COME TO THIS PAGE. +12107 000000 2 0 I2M5: INT I2M +12110 033104 2 0 STX TXTX +12111 072117 2 0 LDX FOUR +12112 003132 2 0 JMP I2M0 +12113 000000 2 0 I2M4: INT I2M +12114 033104 2 0 STX TXTX +12115 072116 2 0 LDX THREE +12116 003132 2 0 JMP I2M0 +12117 000000 2 0 I2M3: INT I2M +12120 033104 2 0 STX TXTX +12121 072115 2 0 LDX TWO +12122 003132 2 0 JMP I2M0 +12123 000000 2 0 I2M2: INT I2M +12124 033104 2 0 STX TXTX +12125 072114 2 0 LDX ONE +12126 003132 2 0 JMP I2M0 +12127 000000 2 0 I2M1: INT I2M +12130 033104 2 0 STX TXTX +12131 072113 2 0 LDX ZERO + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 105 IMP,3050,IMP 7:20 PM 9/16/1973 + +12132 033654 2 0 I2M0: STX OCHN /SAVE MODEM NUMBER +12133 011103 2 0 STA TATA +12134 000011 2 0 DXA +12135 003136 2 0 JMP .+1 +12136 000043 2 0 INK +12137 011105 2 0 STA TCTC +12140 004416 2 0 LDA TIMES /CURRENT 640 MS CLOCK +12141 057632 2 0 SUB TIM640 X /INITIAL READING FOR THIS MSG +12142 017712 2 0 SUB (10.) /10.24 TICKS/WRAP OF 100 MUS CLK +12143 101400 2 0 SMI /<10 TICKS? +12144 003516 2 0 JMP RAPT /NO, MSG TOOK TOO LONG, CLOCK WRAPPI +12145 131040 2 0 RDCLOK /100 MU SEC CLOCK +12146 003145 2 0 JMP .-1 +12147 057637 2 0 SUB TIM100 X /MINUS START TIMER +12150 011644 2 0 STA THIST /TIME FOR THIS MESSAGE +12151 055625 2 0 ADD CUMTIM X /ADD TO TOTAL +12152 051625 2 0 STA CUMTIM X /AND SAVE +12153 045620 2 0 LDA RMFLG X /ROUTING MSG FLAGS +12154 100100 2 0 SLZ /WAS THIS A ROUTING MESSAGE? +12155 103713 2 0 JMP (I2MRM) I /YES, GO DO LINE SPEED COMPUTNS +12156 004502 2 0 I2MS: LDA MOM /LOAD MODEM OUTPUT MASK +12157 170120 2 0 SMK INTM /SET PRI INTERRUPT +12160 026134 2 0 IMA PRIM +12161 011652 2 0 STA TMTM +12162 140040 2 0 CRA +12163 066634 2 0 IMA I2MNXT X /PKT PNTR FOR NEXT OUTPUT FOR CHL +12164 101400 2 0 SMI /WAS THERE AN ACK FOR THE PKT WE L 1 +12165 003173 2 0 JMP I2MALL /NO, DO NOT RELEASE PKT +12166 140100 2 0 SSP +12167 010000 2 0 STA 0 +12170 120671 2 0 JST FLUSHI I /YES, SO WE CAN FREE IT NOW +12171 024564 2 0 IRS NSFS +12172 073654 2 0 LDX OCHN + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 106 IMP,3050,IMP 7:20 PM 9/16/1973 + +12173 000401 2 0 I2MALL: ENB I2M +12174 044265 2 LDA SLT X +12175 100040 2 SZE /TIME TO SEND A ROUTING MESSAGE? +12176 003276 2 JMP I2MLT /YES +12177 045660 2 LDA I2MLST X /PICK UP RING PNTR +12200 141206 2 AOA /ADVANCE IT +12201 062627 2 CAS I2MEND X +12202 101000 2 NOP +12203 044622 2 LDA I2MTAB X /WRAP AROUND +12204 051660 2 STA I2MLST X +12205 001001 2 INH M2I /PREVENT M2I FROM ACKING +12206 145660 2 0 LDA I2MLST XI /WHILE WE LOOK AT THIS SLOT +12207 023714 2 0 CAS (1777) /IS THERE A PKT HERE? +12210 003550 2 0 JMP I2MRET /YES, SEE IF IT IS TOO OLD +12211 073654 2 0 I2MNEW: LDX OCHN /NO, NOTHING TO RETRANSMIT +12212 000401 2 0 ENB I2M +12213 044317 2 LDA SMPQ X +12214 100040 2 SZE /A NEW PRIORITY PACKET TO SEND? +12215 003363 2 JMP I2MPRI /YES +12216 044312 2 LDA SMQ X +12217 100040 2 SZE /A NEW REGULAR PACKET TO SEND? +12220 003375 2 JMP I2MREG /YES +12221 044445 2 LDA SNULL X +12222 101040 2 SNZ /SHOULD WE SEND A NULL PKT? +12223 003500 2 JMP I2MQUT /NO, SO QUIT + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 107 IMP,3050,IMP 7:20 PM 9/16/1973 + +12224 140040 2 I2MNUL: CRA /SEND A NULL PKT WITH IHY +12225 066421 2 IMA SIHY X +12226 100400 2 SPL 0"A"SNDCOR /DID WE GET A REQUEST TO SEND CORE +12227 003262 2 JMP I2MCOR /YES. SO SERVICE IT +12230 100040 2 SZE /DID WE GET IN ANY ROUTING MESSAGES1 +12231 005715 2 LDA (IHERDU) /YES. SEND AN I HEARD YOU +12232 013716 2 ERA (LINETS 0 NULPKT) /IN A NULL PKT +12233 141340 2 ICA +12234 012106 2 ERA MINE +12235 141340 2 ICA +12236 151704 2 STA NULPTR XI /SET UP HEADER OF NULL PKT +12237 045704 2 LDA NULPTR X /PICK UP PNTR TO NULL AREA +12240 016114 2 SUB ONE +12241 151665 2 STA MOPX XI /SET UP OUR OUTPUT AREA +12242 011655 2 STA ACKWRD +12243 014117 2 ADD FOUR 0"A"[MINPL-ACKH] /MIN PACKET LENT +12244 151672 2 STA MOP1 XI +12245 044646 2 LDA RSEX X /PUT IN ACKS +12246 073655 2 LDX ACKWRD +12247 050000 2 STA ACKH-ACKH X +12250 004417 2 LDA SYNC /PUTTING SYNC TIME INTO NULLS +12251 050002 2 STA HEAD1-ACKH X +12252 004117 2 I2MNLC: LDA FOUR 0"A"[MINPL-ACKH] +12253 056000 2 SUB ACKH-ACKH X /BUILD CKSUM +12254 056001 2 SUB HEAD-ACKH X +12255 056002 2 SUB HEAD1-ACKH X +12256 056003 2 SUB HEAD2-ACKH X +12257 050004 2 STA HEAD3-ACKH X /AND STORE IT +12260 073654 2 LDX OCHN +12261 003465 2 JMP I2MDN1 + +12262 005717 2 I2MCOR: LDA (CORELO) +12263 151665 2 STA MOPX XI +12264 005720 2 LDA (COREHI-1) +12265 151672 2 STA MOP1 XI +12266 003467 2 JMP I2MDUN /RETURN TO DO OUTPUT, NO ACKS + +12267 005721 2 I2MDMC: LDA (DMNDCR) /SEND 'DEMAND CORE' +12270 151665 2 STA MOPX XI +12271 014117 2 ADD FOUR 0"A"[MINPL-ACKH] +12272 151672 2 STA MOP1 XI +12273 016117 2 SUB FOUR 0"A"[MINPL-ACKH] +12274 010000 2 STA 0 +12275 003252 2 JMP I2MNLC /GET CHECKSUM AND SEND IT + +12276 100400 2 I2MLT: SPL /ARE WE HOLDING LINE DEAD? +12277 003500 2 JMP I2MQUT /YES, GO NO FURTHER +12300 016114 2 I2ML2: SUB ONE +12301 050265 2 I2ML3: STA SLT X +12302 022114 2 I2ML4: CAS ONE /RELOAD DEMAND TO SEND? +12303 003267 2 JMP I2MDMC /YES +12304 003224 2 JMP I2MNUL /NULL TO SEND + /---FALL THROUGH TO SEND ROUTING + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 108 IMP,3050,IMP 7:20 PM 9/16/1973 + + /THE WORDS FROM I2MCK1 TO I2MCK2 ARE CHECKSUMMED + CHK=0 +12305 073361 2 I2MCK1: K LDX I2MCKX /PICK UP -[# OF WDS IN CODE TO CK[ 1 +12306 055363 2 K ADD I2MCK2+1 X /ADD THEM (NOTE 0 IN AN I1 +12307 024000 2 K IRS 0 +12310 003306 2 K JMP .-2 +12311 100040 2 K SZE /DIFFERENT? + RELOAD [I2M ROUTING CODE BROKEN] +12312 120061 2 K JST SWDTIL I /SOFTWARE WDT, DO A RELOAD +12313 073654 2 K LDX OCHN +12314 125353 2 K IRS IMHSI I /KEEP STAT COUNTER +12315 101000 2 K NOP +12316 004660 2 K LDA RST.O /GET OUTPUT PTR +12317 015355 2 K ADD I2MRC1 +12320 151665 2 K STA MOPX XI /BEG POINTER +12321 017356 2 K SUB I2MRC2 +12322 151672 2 K STA MOP1 XI +12323 015357 2 K ADD I2MRC3 +12324 010000 2 K STA 0 +12325 005354 2 K LDA I2MRAP /(RUTADR) +12326 026111 2 K IMA ADDRET /SAVE CURRENT OWNER OF ADDER +12327 011653 2 K STA TARTAR +12330 005356 2 K LDA I2MRC2 /(-NIMP - HEAD1 + ACKH) +12331 103332 2 K JMP .+1 I /JUMP INTO RIGHT PLACE IN ADD CHAI +12332 001454 2 K ADDBOT+0-NIMP-HEAD1+ACKH +12333 140407 2 RUTADR: K TCA +12334 072113 2 K LDX ZERO /USE TO FIND CKSUM POST INDEXED +12335 112660 2 K ERA RST.O I /COMPARE CKSUM W/ THAT GENERATED BY +12336 027653 2 K IMA TARTAR +12337 010111 2 K STA ADDRET +12340 005653 2 K LDA TARTAR +12341 073654 2 K LDX OCHN +12342 001001 2 K .INH LCK ALL +12343 100040 2 0 K SZE /DIFFERENT? + DEFHLT [ROUTING MESSAGE CHECKSUM ERROR - INTRA IMP] +12344 021571 2 0 K JST I2MHLT +12345 141206 2 0 K AOA /1 +12346 053620 2 0 K ERA RMFLG X /SAYS ROUTING MSG GOING OUT +12347 051620 2 0 K STA RMFLG X +12350 105360 2 0 K LDA I2MRP I /(RSTSN) +12351 051645 2 0 K STA RSTSNO X /SAVE SER # OF LAST OUTPUT +12352 003467 2 0 K JMP I2MDUN + + LEV CON +12353 071615 C IMHSI: K IMHS 0 X +12354 012333 C I2MRAP: K RUTADR +12355 137675 C I2MRC1: K -X 0-NIMP-HEAD1+ACKH-1 +12356 177675 C I2MRC2: K -NIMP-HEAD1+ACKH-1 +12357 177671 C I2MRC3: K -NIMP-HEAD1-1 +12360 026644 C I2MRP: K RSTSN +12361 177722 C I2MCKX: K I2MCK1-0-I2MCK2-1 /CHECKSUM COUNTER +12362 044107 C I2MCK2: -CHK /CHECKSUM ON CODE GOES HERE + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 109 IMP,3050,IMP 7:20 PM 9/16/1973 + + LEV I2M +12363 050634 2 I2MPRI: STA I2MNXT X +12364 140040 2 CRA +12365 166634 2 IMA I2MNXT XI +12366 050317 2 STA SMPQ X +12367 100040 2 SZE +12370 003406 2 JMP I2MGNU +12371 005722 2 LDA (SMPQ) +12372 015654 2 ADD OCHN +12373 050370 2 STA EMPQ X +12374 003406 2 JMP I2MGNU + +12375 050634 2 I2MREG: STA I2MNXT X /LOAD WITH TOP OF Q ADDR +12376 140040 2 CRA +12377 166634 2 IMA I2MNXT XI /GET CHAIN PNTR OF NEW REQ +12400 050312 2 STA SMQ X /LINK TO TOP OF Q +12401 100040 2 SZE /WAS THIS LAST? +12402 003406 2 JMP I2MGNU /NO +12403 005723 2 LDA (SMQ) /YES, FIX UP Q PNTRS +12404 015654 2 ADD OCHN +12405 050363 2 STA EMQ X + + +12406 173724 2 I2MGNU: LDX (I2MNXT 0 X) I /GOT A NEW PKT +12407 133725 2 STX (INCH 0 XI) I /SET UP SLOT PNTR +12410 005726 2 LDA (-200.) /GIVE A PKT 200 TRIES +12411 050003 2 STA INCH X /TO BE ACCEPTED +12412 011657 2 STA I2MREF /MARK AS NEW PKT, DON'T CHECKSUM +12413 073654 2 LDX OCHN +12414 044634 2 LDA I2MNXT X + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 110 IMP,3050,IMP 7:20 PM 9/16/1973 + +12415 140100 2 I2MGOT: SSP +12416 015727 2 ADD (ACKH) +12417 151665 2 STA MOPX XI +12420 011655 2 DEFSTAT STA ACKWRD, IM1 +00605 031160 2 +32001 012420 2 +32021 011655 2 +12421 173724 2 LDX (I2MNXT 0 X) I +12422 131040 2 RDCLOK +12423 003422 2 JMP .-1 +12424 050001 2 STA ST X +12425 044111 2 LDA BUFE X +12426 140100 2 SSP 0"A"TWOQ +12427 073654 2 LDX OCHN +12430 151672 2 STA MOP1 XI +12431 011656 2 STA ENDWRD +12432 005657 2 LDA I2MREF /RETRANSMISSION OR NEW? + DEFPLC [NOP HERE TO STOP CHECKSUM VERIFY IN I2M] +12433 100040 2 SZE +12434 003456 2 JMP I2MCHF /NO CKSUM +12435 005730 2 LDA (I2MADR) /CAPTURE ADDER +12436 026111 2 IMA ADDRET +12437 011653 2 STA TARTAR +12440 005655 2 LDA ACKWRD +12441 016117 2 SUB FOUR 0"A"ACKH +12442 010000 2 STA 0 /PACKET POINTER +12443 017656 2 SUB ENDWRD /LENGTH OF PACKET +12444 015731 2 ADD (ADDBOT+ACKH) +12445 011450 2 STA I2MADJ +12446 017732 2 SUB (ADDBOT) +12447 103450 2 JMP I2MADJ I +12450 2 I2MADJ: BSS 1 +12451 100040 2 I2MADR: SZE +12452 003524 2 JMP I2MCHE /CHECKSUM ERROR! +12453 005653 2 LDA TARTAR +12454 010111 2 STA ADDRET /RESTORE ADDER OWNER +12455 073654 2 LDX OCHN +12456 105655 2 I2MCHF: LDA ACKWRD I +12457 141044 2 CAR 0"A"ACKBTS /PUT IN ACKS +12460 052646 2 ERA RSEX X +12461 127655 2 IMA ACKWRD I /AND CORRECT CHECKSUM +12462 117655 2 SUB ACKWRD I +12463 115656 2 ADD ENDWRD I +12464 111656 2 STA ENDWRD I +12465 140040 2 I2MDN1: CRA +12466 050445 2 STA SNULL X /ACKS MARKED AS SENT + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 111 IMP,3050,IMP 7:20 PM 9/16/1973 + +12467 004416 2 I2MDUN: LDA TIMES /640 MS COUNTER +12470 051632 2 STA TIM640 X /TABLE OF MODEM OUT START TIMES +12471 131040 2 RDCLOK /100 MICRO SEC CLOCK +12472 003471 2 JMP .-1 +12473 051637 2 STA TIM100 X /SAVE THIS CLOCK TOO +12474 045677 2 LDA MXOUT X +12475 011476 2 STA . 1 +12476 2 BSS 1 +12477 005711 2 LDA M30SCF /SET TO WAIT FOR HARDWARE COMPLETE +12500 050440 2 I2MQUT: STA NONE X /OR SET FLAG TO INDICATE IDLE +12501 001001 2 INH MSK +12502 005652 2 0 LDA TMTM +12503 010134 2 0 STA PRIM +12504 170120 2 0 SMK INTM +12505 144071 2 0 LDA M1OTIL XI +12506 011106 2 0 STA IRET +12507 000013 2 0 EXA +12510 005105 2 0 LDA TCTC +12511 171020 2 0 OTK +12512 005103 2 0 LDA TATA +12513 073104 2 0 LDX TXTX +12514 000401 2 0 ENB I2M +12515 103106 2 JMP IRET I + + LEV I2M LCK ALL +12516 005733 2 0 RAPT: LDA (14400) /6400MS, 1 SLOW T.O IN 100MUS UNITS +12517 051625 2 0 STA CUMTIM X /RM TOOK TOO LONG, MAX+TIMER +12520 045620 2 0 LDA RMFLG X /CLEAR RM FLAG BIT +12521 006122 2 0 ANA MINUS2 0"A"RM /177776 +12522 051620 2 0 STA RMFLG X +12523 003156 2 0 JMP I2MS /AND RETURN + + LEV I2M +12524 001001 2 I2MCHE: INH ALL + DEFHLT [MODEM OUT DETECTED INTRA-IMP CHECKSUM ERROR] +12525 021526 2 0 JST .+1 +12526 000000 2 0 0 +12527 120745 2 0 JST HLTNCC I /RERORT IT +12530 004000 2 0 LDA 0 +12531 026342 2 0 IMA DIAGQ /AND TO DIAG TTY +12532 050000 2 0 STA 0 X +12533 000401 2 0 ENB I2M +12534 005653 2 LDA TARTAR +12535 010111 2 STA ADDRET +12536 024564 2 IRS NSFS +12537 044004 2 LDA ACKH X /FREE UP UN-ACKED CHANNEL +12540 007734 2 ANA (CHANUM) +12541 141140 2 ICL +12542 073654 2 LDX OCHN +12543 054622 2 ADD I2MTAB X /GET SLOT POINTER +12544 011653 2 STA TARTAR /(TEMP) +12545 140040 2 CRA +12546 111653 2 STA TARTAR I /CLEAR SLOT PTR +12547 003500 2 JMP I2MQUT /LEAVE MODEM OUTPUT IDLE FOR A BI- + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 112 IMP,3050,IMP 7:20 PM 9/16/1973 + + LCK M2I +12550 010000 2 0 I2MRET: STA 0 /SAVE PKT PNTR +12551 131040 2 0 RDCLOK +12552 003551 2 0 JMP .-1 +12553 056001 2 0 SUB ST X /COMPARE TIME NOW WITH SENT TIME +12554 100400 2 0 SPL +12555 140407 2 0 TCA /MAKE DIFF A POSITIVE NUMBER +12556 017735 2 0 SUB (1250.) /COMPARE WITH 125 MS + /THIS CONSTANT VARIES WITH LINE LENGTH AND SPEED + /IT SHOULD BE TABLED WHEN WE GET FAST LINES+SATELLITES +12557 100400 2 0 SPL /TOO OLD? +12560 003211 2 0 JMP I2MNEW /NOT YET +12561 064003 2 0 IRS INCH X /COUNT ANOTHER RETRANSMIT +12562 003575 2 0 JMP I2MRTR /NOT OVER THE LIMIT +12563 120671 2 0 JST FLUSHI I /KILL PKT AFTER 200 TRIES +12564 024564 2 0 IRS NSFS /AND COUNT IT OUT +12565 073654 2 0 LDX OCHN +12566 140040 2 0 CRA +12567 151660 2 0 STA I2MLST XI /SO IT WON'T BE FLUSHED TWICE + DEFHLT [200 RETRANSMISSIONS - SERIOUS MALFUNCTION] +12570 021571 2 0 JST I2MHLT +12571 000000 2 0 I2MHLT: 0 +12572 120745 2 0 JST HLTNCC I /REPORT TROUBLE TO NCC +12573 121736 2 0 JST (KILLIN) I /KILL LINE INSTANTLY +12574 003500 2 0 JMP I2MQUT /DISMISS INTERRUPT + +12575 073654 2 0 I2MRTR: LDX OCHN +12576 140040 2 0 CRA /MARK PACKET AS A RETRANSMISSION +12577 011657 2 0 STA I2MREF /SO CHECKSUM IS VERIFIED +12600 145660 2 0 LDA I2MLST XI /PACKET SENT >125MS AGO +12601 050634 2 0 STA I2MNXT X /SO RETRANSMIT IT +12602 000401 2 0 ENB I2M +12603 003415 2 JMP I2MGOT + + LEV [T.O,TSK] LCK SIN +12604 000000 5 0 I2MSB: 0 /SOFTWARE WAKELP OF MODEM OUTPUT +12605 033104 5 0 STX TXTX /ALWAYS CALLED FROM LOW CORE AND DX +12606 011103 5 0 STA TATA +12607 033654 5 0 STX OCHN +12610 005604 5 0 LDA I2MSB +12611 150071 5 0 STA M1OTIL XI +12612 143613 5 0 JMP I2MSBT XI /CLEAR X BIT IN ADDR AND LEAP IN F + + LEV VAR +12613 012156 V I2MSBT: I2MS +12614 012156 V I2MS +12615 V SATDEF I2MS +02245 012615 V +02275 012156 V +02325 012156 V +12616 012156 V I2MS +12617 012156 V I2MS + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 113 IMP,3050,IMP 7:20 PM 9/16/1973 + + + /BITS IN RMFLG + RMINIT=100000 /SET IF FIRST TIME THROUGH (IN INI + SPDTYP=77400 /TYPE 0 = 5KBS + /TYPE 1 = 10KBS + /TYPE 2 = 50KBS + /TYPE 3 = 250 KBS + SHD=6 /SPEED HOLD-DOWN COUNTER + SHD1=2 /BOTTOM BIT OF SHD + RM=1 /IF SET, SAYS ROUTING MESSAGE PENDING + + LEV VAR +12620 V RMFLG: BSS CH /INIT TO 1006(HD ON 50KB LINE) +12625 V CUMTIM: BSS CH /CUMULATIVE BUSY TIME OVER INTERVAL +12632 V TIM640: BSS CH /'TIMES' AT START OF OUTPUT +12637 V TIM100: BSS CH /100 MUS CLOCK AT START OF OUTPUT +12644 V THIST: BSS 1 /ELAPSED TIME FOR THIS TRANSMISSION +12645 V RSTSNO: BSS CH /SERIAL NO. OF LAST RM OUTPUT + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 114 IMP,3050,IMP 7:20 PM 9/16/1973 + + LEV VAR +12652 V TMTM: BSS 1 /TEMP M +12653 V TARTAR: BSS 1 /TEMP ADDER RETURN +12654 V OCHN: BSS 1 /ACTIVE MODEM NUMBER +12655 V ACKWRD: BSS 1 /PNTR TO WORD IN PKT WHERE ACKS GO +12656 V ENDWRD: BSS 1 /PNTR TO LAST WORD IN PKT +12657 V I2MREF: BSS 1 /RETRANSMIT FLAG: CHECKSUM IF FLAG I +12660 V I2MLST: BSS CH /PNTR TO LAST SLOT SENT + LEV CON +12665 000032 C MOPX: M1OTBP /DMC OUTPUT PNTRS +12666 000034 C M2OTBP +12667 000036 C M3OTBP +12670 000040 C M4OTBP +12671 000042 C M5OTBP +12672 000033 C MOP1: M1OTBP+1 /DMC OUTPUT END PNTRS +12673 000035 C M2OTBP+1 +12674 000037 C M3OTBP+1 +12675 000041 C M4OTBP+1 +12676 000043 C M5OTBP+1 +12677 030071 C MXOUT: M1OUT /OUTPUT INSTRUCTIONS +12700 030072 C M2OUT +12701 030073 C M3OUT +12702 030074 C M4OUT +12703 030075 C M5OUT +12704 032101 C NULPTR: NULS1+1 /PNTRS TO NULL PKT AREAS +12705 032106 C NULS2+1 +12706 032113 C NULS3+1 +12707 032120 C NULS4+1 +12710 032125 C NULS5+1 + +12711 175551 C M30SCF: -[0 0 30SEC"T"25.] + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 115 IMP,3050,IMP 7:20 PM 9/16/1973 + +12712 000012 C LEV CON CONSTANTS +12713 011213 C +12714 001777 C +12715 000020 C +12716 000003 C +12717 000060 C +12720 032777 C +12721 011206 C +12722 000317 C +12723 000312 C +12724 040634 C +12725 140003 C +12726 177470 C +12727 000004 C +12730 012451 C +12731 001562 C +12732 001556 C +12733 014400 C +12734 017400 C +12735 002342 C +12736 011133 C +02421 176744 C PAGEND 12,UNCON,5 + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 116 IMP,3050,IMP 7:20 PM 9/16/1973 + + + /HOST TO IMP (HI) + + PAGH2I: + LEV H2I + +00100 013100 4 H1INIL/ HI0E +00101 4 H2INIL/ TIPDEF HI1E, TINT +02246 000101 4 +02276 013072 4 +02326 025061 4 +00075 013064 4 H3INIL/ HI2E +00074 013056 4 H4INIL/ HI3E + + PAGH2I/ + /HOST 3 INTERRUPT ROUTINE +13056 000000 4 0 HI3E: INT H2I +13057 033135 4 0 STX HIX +13060 073056 4 0 LDX HI3E +13061 033106 4 0 STX HISB +13062 072116 4 0 LDX THREE +13063 003110 4 0 JMP HISB2 + /HOST 2 INTERRUPT ROUTINE +13064 000000 4 0 HI2E: INT H2I +13065 033135 4 0 STX HIX +13066 073064 4 0 LDX HI2E +13067 033106 4 0 STX HISB +13070 072115 4 0 LDX TWO +13071 003110 4 0 JMP HISB2 + /HOST 1 INTERRUPT ROUTINE +13072 000000 4 0 HI1E: INT H2I +13073 033135 4 0 STX HIX +13074 073072 4 0 LDX HI1E +13075 033106 4 0 STX HISB +13076 072114 4 0 LDX ONE +13077 003110 4 0 JMP HISB2 + /HOST 0 INTERRUPT ROUTINE +13100 000000 4 0 HI0E: INT H2I +13101 033135 4 0 STX HIX /SAVE INDEX REGISTER +13102 073100 4 0 LDX HI0E +13103 033106 4 0 STX HISB /SET UP RETURN ADDRESS +13104 072113 4 0 LDX ZERO /INTERRUPT FROM HOST 0 +13105 003110 4 0 JMP HISB2 + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 117 IMP,3050,IMP 7:20 PM 9/16/1973 + + / FROM HERE ON IS COMMON TO ALL HOST INTERRUPT ROUTINES + +13106 000000 4 0 HISB: 0 +13107 033135 4 0 STX HIX +13110 000011 4 0 HISB2: DXA +13111 003112 4 0 JMP . 1 +13112 032675 4 0 STX HIP /SAVE CURRENT HOST +13113 011133 4 0 STA HIA /SAVE AC +13114 000043 4 0 INK +13115 011134 4 0 STA HIK +13116 004501 4 0 LDA HIM /SET UP NEW INTERRUPT MASK (177760) +13117 170120 4 0 SMK INTM /OUTPUT IT +13120 026134 4 0 IMA PRIM /SAVE IT IN PRIM +13121 011136 4 0 STA HIMS /SAVE OLD PRIM +13122 000401 4 0 ENB H2I +13123 142453 4 JMP HILO XI /RESTART WHERE LAST LEFT OFF + +13124 000000 4 HIWM: 0 /DEBREAK AND WAKE UP 25MS LATER +13125 072675 4 LDX HIP +13126 005124 4 LDA HIWM +13127 050453 4 HIWM1: STA HILO X +13130 004121 4 LDA MINUS1 +13131 051137 4 STA HITT X /SET TIMEOUT TO WAIT 1 PERIOD +13132 003516 4 JMP HIDONE + + LEV VAR +13133 V HIA: BSS 1 /AC SAVE +13134 V HIK: BSS 1 /K SAVE +13135 V HIX: BSS 1 /IR SAVE +13136 V HIMS: BSS 1 /PRIM SAVE +13137 V HITT: BSS TH /HOST-TO-IMP INTERFACE TIMER + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 118 IMP,3050,IMP 7:20 PM 9/16/1973 + + LEV CON +13147 000050 C HIB1: H1INBP /DMC INPUT PNTRS +13150 C TIPDEF H2INBP,JUNK +02247 013150 C +02277 000052 C +02327 000001 C +13151 C TIPDEF H3INBP,TIPLNK+2 +02250 013151 C +02300 000056 C +02330 000772 C +13152 000042 C H4INBP +13153 013323 C HIBB +13154 013324 C HIBB+1 +13155 013325 C HIBB+2 +13156 013326 C HIBB+3 +13157 000051 C HIB2: H1INBP+1 /DMC INPUT END PNTRS +13160 C TIPDEF H2INBP+1,JUNK +02251 013160 C +02301 000053 C +02331 000001 C +13161 C TIPDEF H3INBP+1,TIPLNK+3 +02252 013161 C +02302 000057 C +02332 000773 C +13162 000043 C H4INBP+1 +13163 013327 C HIBC +13164 013330 C HIBC+1 +13165 013331 C HIBC+2 +13166 013332 C HIBC+3 +13167 003014 C HER0: JMP 0 1000 777"A"HITEST /NEEDED FOR HOST TEST + /MUST PRECEDE HER! +13170 070070 C HER: H1ERR /SKIP ON ERROR FROM HOST +13171 070060 C H2ERR +13172 C TIPDEF H3ERR,NOP +02253 013172 C +02303 070050 C +02333 101000 C +13173 070051 C H4ERR +13174 101000 C NOP +13175 101000 C NOP +13176 101000 C NOP +13177 101000 C NOP +13200 030170 C HIN: H1IN /INPUT INSTRUCTIONS +13201 030160 C H2IN +13202 C TIPDEF H3IN,JMP+0+1000+HIFAKE"A"777 +02254 013202 C +02304 030150 C +02334 003531 C +13203 030151 C H4IN +13204 003531 C JMP HIFAKE +13205 003531 C JMP HIFAKE +13206 003531 C JMP HIFAKE +13207 003531 C JMP HIFAKE + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 119 IMP,3050,IMP 7:20 PM 9/16/1973 + + /FAKE HOST TO IMP (JAM) + /SIMULATE HOST-TO-IMP INTERFACE HARDWARE FOR FAKE HOSTS: + /1- RECEIVE A WORD FROM HOST + /2- STORE THE WORD THROUGH THE DMC INPUT POINTER + /3- INCREMENT THE DMC INPUT POINTER + /4- IF LAST BIT INDICATOR IS SET, OR + / IF THE DMC INPUT AND INPUT END POINTERS CROSS + / GIVE INPUT COMPLETED INTERRUPT + /5- GO TO 1 + /HIBB SERVES AS THE DMC INPUT POINTER + /HIBC SERVES AS THE DMC INPUT END POINTER + /CALLING SEQUENCE + /FAKE HOST NUMBER IN X REG - 0=TTY,1=DDT,2=TRACE,3=STATISTIC1 + /SIGN BIT OF X REG IS LAST BIT INDICATOR - BIT ON=LAST BIT + /THE WORD TO GIVE TO THE IMP IN A REG + /JST JAM - SEND THIS WORD TO IMP FROM THIS FAKE HOST + / - IMPLICIT BACKGROUND WAIT UNTIL THIS WORD IS TAKEN + / - AND ANOTHER WORD MAY BE SENT + LEV BCK +13210 000000 7 GAM: 0 +13211 151323 7 STA HIBB XI /STORE NEXT WORD THROUGH INPUT PNI +13212 065323 7 IRS HIBB X /INCREMENT INPUT PNTR +13213 004000 7 LDA 0 +13214 100400 7 SPL /IS LAST BIT FLAG SET? +13215 003247 7 JMP GAM2 /YES +13216 045327 7 LDA HIBC X +13217 057323 7 SUB HIBB X +13220 101400 7 SMI /HAVE PNTRS CROSSED? +13221 103210 7 JMP GAM I /NO, RETURN +13222 005177 7 LDA HER+NH+3 /(NOP) +13223 051317 7 GAM1: STA EMFH+NH X /SET UP LAST BIT INSTRUCTION FOR HO +13224 005210 7 LDA GAM +13225 051251 7 STA GAMT X /SAVE RETURN ADDRESS +13226 004000 7 LDA 0 +13227 140100 7 SSP +13230 011255 7 STA GAMX +13231 014130 7 ADD PLNH +13232 010000 7 STA 0 /SET UP X REG FOR THIS FAKE HOST +13233 001001 7 INH SIN /SOFTWARE INTERRUPT HOST-TO-IMP +13234 000013 7 0 EXA +13235 021106 7 0 JST HISB RET BCK +13236 001001 7 INH ALL +13237 120672 7 0 JST DODXA I RET BCK +13240 073255 7 LDX GAMX +13241 045143 7 GAM3: LDA HITT+NH X /TIMER HAS THREE POSSIBLE STATES +13242 140401 7 CMA /0 - WAITING FOR LEADER INPUT +13243 100040 7 SZE /-1 - WAITING FOR SOFTWARE INTERRU +13244 143251 7 JMP GAMT XI /IF NOT -1, INPUT CAN GO, SO RETUF +13245 120665 7 JST DOZE I /-N - WAITING FOR DATA INPUT + DEFPLC [JAM CALL TO DOZE] +13246 003241 7 JMP GAM3 /WAIT UNTIL INPUT IS ALLOWED +13247 004112 7 GAM2: LDA SIGN /(SKP) +13250 003223 7 JMP GAM1 + LEV VAR DEFPLC [GAMT] +13251 V GAMT: BSS FH /TABLE OF RETURN ADDRESSES +13255 V GAMX: BSS 1 + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 120 IMP,3050,IMP 7:20 PM 9/16/1973 + + LEV BCK LCK INI +13256 000000 7 0 HIST: 0 /RESTART HOST TO IMP +13257 140040 7 0 CRA +13260 051333 7 0 STA HISP X +13261 011106 7 0 STA HISB /IN CASE NON-DXA IMP RELOADED FROM ] +13262 111535 7 0 STA (HIDEST 0 X) I +13263 045273 7 0 LDA HISTAB X +13264 050453 7 0 STA HILO X /SET UP INITIAL ADDRESS TO GO TO +13265 045303 7 0 LDA EMIT X +13266 051313 7 0 STA EMFH X /SET UP FOM INSTRUCTION +13267 000013 7 0 EXA +13270 021106 7 0 JST HISB /CALL HOST +13271 120672 7 0 JST DODXA I +13272 103256 7 0 JMP HIST I + + LEV CON +13273 013353 C HISTAB: HISTRH /INITIAL COROUTINE ENTRANCES +13274 013353 C HISTRH +13275 C TIPDEF HISTRH, HISTFH +02255 013275 C +02305 013353 C +02335 013416 C +13276 013353 C HISTRH +13277 013416 C HISTFH +13300 013416 C HISTFH +13301 013416 C HISTFH +13302 013416 C HISTFH + +13303 070270 C EMIT: H1EOM /SKIP ON LAST BIT INSTRUCTIONS +13304 070260 C H2EOM +13305 C TIPDEF H3EOM, SKP +02256 013305 C +02306 070250 C +02336 100000 C +13306 070251 C H4EOM +13307 100000 C SKP +13310 100000 C SKP +13311 100000 C SKP +13312 100000 C SKP + + LEV VAR +13313 V EMFH: BSS TH /SKIP ON END OF MESSAGE FROM HOST +13323 V HIBB: BSS FH /DMC INPUT PNTRS FOR FAKE HOSTS +13327 V HIBC: BSS FH /DMC INPUT END PNTRS FOR FAKE HOSTS +13333 V HISP: BSS TH /POINTER TO CURRENT BUFFER +13343 V HINWAT: BSS TH /HOLD UP HOST INPUT + + LEV H2I +13353 005536 4 HISTRH: LDA (HIFRST) /DISCARD FIRST INPUT OF REAL HOST +13354 003417 4 JMP HISTLO + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 121 IMP,3050,IMP 7:20 PM 9/16/1973 + +13355 004114 4 HIDOWN: LDA ONE 0"A"HSTGDN +13356 050504 4 STA HIHD X /MARK HOST GOING DOWN + DEFPLC [HI - WAITING FOR A PKT TO THROW AWAY] +13357 140040 4 HIDISC: CRA +13360 127535 4 IMA (HIDEST 0 X) I +13361 101400 4 SMI /DID THIS GUY JUST TAKE TOO LONG? +13362 003367 4 JMP HIDSC1 /NO +13363 005537 4 LDA (HIDISC) +13364 050453 4 STA HILO X +13365 140040 4 CRA /DONT'T SET ALARM CLOCK AGAIN +13366 003470 4 JMP HINLO1 +13367 045333 4 HIDSC1: LDA HISP X /FLUSH HISP +13370 101040 4 SNZ +13371 003400 4 JMP HIFRST +13372 010000 4 STA 0 +13373 050111 4 STA BUFE X 0"A"TWOQ +13374 001001 4 INH FRE +13375 120671 4 0 JST FLUSHI I +13376 000401 4 0 ENB H2I +13377 072675 4 LDX HIP + DEFPLC [HI - WAITING FOR INITIAL INPUT] +13400 045313 4 HIFRST: LDA EMFH X /IS EOM SET? +13401 011403 4 STA .+2 +13402 005537 4 LDA (HIDISC) +13403 4 BSS 1 +13404 003466 4 JMP HINLO /NO +13405 140040 4 HIDB: CRA +13406 051333 4 STA HISP X +13407 045313 4 LDA EMFH X /IS EOM SET? +13410 011411 4 STA .+1 +13411 4 BSS 1 +13412 003457 4 JMP HINBUF /NO +13413 045343 4 HIWAIT: LDA HINWAT X /INPUT TO BE BLOCKED? +13414 100040 4 SZE +13415 003430 4 JMP HIBLKD /YES +13416 005540 4 HISTFH: LDA (HILEAD) +13417 050453 4 HISTLO: STA HILO X +13420 140040 4 CRA +13421 051137 4 STA HITT X /GIVE HIM FOREVER TO INPUT NEXT ME' +13422 004000 4 LDA 0 +13423 041577 4 ALS 1 +13424 015541 4 ADD (I 0 HICWS) +13425 151147 4 STA HIB1 XI +13426 141206 4 AOA +13427 003511 4 JMP HINB2 + +13430 021124 4 HIBLKD: JST HIWM + DEFPLC [HI - INPUT BEING BLOCKED BY OUTPUT] +13431 003413 4 JMP HIWAIT + + LEV CON + DEFPLC [HI - 2 WORD INPUT AREA] +13432 C HICWS: BSS TH+TH + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 122 IMP,3050,IMP 7:20 PM 9/16/1973 + + LEV H2I +13452 044453 4 HIWBUF: LDA HILO X +13453 051333 4 STA HISP X /SAVE RETURN ADDRESS +13454 021124 4 JST HIWM + DEFPLC [HI - NO FREE SPACE] +13455 045333 4 LDA HISP X +13456 003466 4 JMP HINLO /RESTORE RETURN ADDRESS +13457 005542 4 HINBUF: LDA (PKTN1) +13460 115543 4 ADD (HIH1 0 X) I +13461 111543 4 STA (HIH1 0 X) I +13462 007544 4 ANA (PKTNO) +13463 101040 4 SNZ /WILL NEXT PKT BE NO 10? +13464 003357 4 JMP HIDISC /YES +13465 005545 4 LDA (HI25) +13466 050453 4 HINLO: STA HILO X +13467 005546 4 LDA (0 0 -15000."Q"25.) +13470 051137 4 HINLO1: STA HITT X /GIVE HOST 15 SECS TO INPUT PKT +13471 001001 4 INH FRE +13472 004537 4 0 LDA NFA +13473 016563 4 0 SUB NFS +13474 016570 4 0 SUB MINF +13475 100400 4 0 SPL +13476 003452 4 0 JMP HIWBUF /NOT ENOUGH BUFFERS FOR MODEM INPUT +13477 104324 4 0 LDA FREE I +13500 101040 4 0 SNZ +13501 003452 4 0 JMP HIWBUF +13502 026324 4 0 IMA FREE +13503 024563 4 0 IRS NFS +13504 000401 4 0 ENB H2I +13505 051333 4 STA HISP X /SAVE POINTER TO BUFFER +13506 015547 4 ADD (I 0 DATA) +13507 151147 4 STA HIB1 XI + /THIS CONSTANT DETERMINES PACKET LENGTH FOR THE WHOLE IMPSY' +13510 015550 4 ADD (BUFE-2-DATA) /ALLOW FOR CHKSM +13511 140100 4 HINB2: SSP /FOR FAKE HOSTS +13512 151157 4 STA HIB2 XI +13513 045200 4 LDA HIN X +13514 011515 4 STA .+1 +13515 4 BSS 1 +13516 005136 4 HIDONE: LDA HIMS /RESTORE INTERRUPT MASK +13517 001001 4 INH MSK +13520 170120 4 0 SMK INTM +13521 010134 4 0 STA PRIM +13522 000013 4 0 EXA +13523 005134 4 0 LDA HIK +13524 171020 4 0 OTK +13525 073135 4 0 LDX HIX /RESTORE IR +13526 005133 4 0 LDA HIA /RESTORE AC +13527 000401 4 0 ENB H2I +13530 103106 4 JMP HISB I + +13531 145147 4 HIFAKE: LDA HIB1 XI +13532 140100 4 SSP +13533 151147 4 STA HIB1 XI +13534 003516 4 JMP HIDONE + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 123 IMP,3050,IMP 7:20 PM 9/16/1973 + +13535 054177 C LEV CON CONSTANTS +13536 013400 C +13537 013357 C +13540 014053 C +13541 113432 C +13542 000400 C +13543 054147 C +13544 003400 C +13545 014544 C +13546 176650 C +13547 100011 C +13550 000076 C +02422 175557 C PAGEND 13,UNCON,4 + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 124 IMP,3050,IMP 7:20 PM 9/16/1973 + + LEV VAR +14003 000000 V HICW1: 0 /TEMP USED TO RETRIEVE CONTROL WORD1 + LEV H2I +14004 000000 4 HILOOP: 0 +14005 045042 4 LDA HBTS X +14006 012106 4 ERA MINE +14007 051147 4 STA HIH1 X +14010 004143 4 LDA HL2WD +14011 051167 4 STA HIH3 X +14012 103004 4 JMP HILOOP I + +14013 021004 4 HIEXER: JST HILOOP +14014 045147 4 HITEST: LDA HIH1 X /MSG A NOP? +14015 007627 4 ANA (HICODE) +14016 013630 4 ERA (CNOP) +14017 100040 4 SZE +14020 103631 4 JMP (HIDISC) I /NO. FLUSH MESSAGE +14021 045167 4 LDA HIH3 X /DATA WORD MATCH? +14022 012143 4 ERA HL2WD +14023 101040 4 SNZ +14024 125632 4 IRS (HLRCVD) I /YES, COUNT A GOOD ONE +14025 103631 4 JMP (HIDISC) I /AND FLUSH MSG + + /USE TO CLEAN UP UNTIL IMPDIE LOGIC TAKES OVER +14026 000000 4 HIWMD: 0 /HIWM WITH DEAD TEST +14027 072675 4 LDX HIP +14030 173633 4 LDX (HIDEST 0 X) I +14031 044165 4 LDA RUT X +14032 072675 4 LDX HIP +14033 100400 4 SPL 0"A"RUTDED /IS DEST IMP DEAD? +14034 003272 4 JMP HI19 /YES +14035 044504 4 LDA HIHD X 0"A"HSTUP +14036 100040 4 SZE /IS SOURCE HOST DEAD? +14037 003232 4 JMP HIERR /YES +14040 005026 4 LDA HIWMD +14041 103634 4 JMP (HIWM1) I /NO, WAIT ONE TICK + + LEV CON +14042 000000 C HBTS: 0 /FROM IMP AND HOST BITS +14043 000100 C 100 +14044 000200 C 200 +14045 000300 C 300 +14046 040000 C 40000 +14047 040100 C 40100 +14050 040200 C 40200 +14051 040300 C 40300 + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 125 IMP,3050,IMP 7:20 PM 9/16/1973 + + + LEV H2I +14052 121635 4 HIHDN: JST (HIWM) I + DEFPLC [HI - WAITING FOR LEADER] + VD.1P: +14053 044504 4 HILEAD: LDA HIHD X 0"A"HSTIDN +14054 022116 4 CAS THREE +14055 003052 4 JMP HIHDN 0"A"HSTIDN +14056 101000 4 NOP +14057 004000 4 LDA 0 /SET UP HIH1, HIH3 FROM CONTROL INP1 +14060 041577 4 ALS 1 +14061 010000 4 STA 0 +14062 105636 4 LDA (HICWS 0 X) I +14063 011003 4 STA HICW1 +14064 105637 4 LDA (HICWS+1 X) I +14065 072675 4 LDX HIP +14066 007640 4 ANA (LINKNO) +14067 051167 4 STA HIH3 X +14070 005003 4 LDA HICW1 0"A"[PRIBIT 0 FORIMP TRACE FOROCT DESTHI] +14071 051147 4 STA HIH1 X 0"A"PKTNO +14072 007627 4 ANA (HICODE) +14073 141140 4 ICL +14074 015641 4 ADD (HI2 0 I) +14075 051137 4 STA HIH0 X +14076 017134 4 SUB HIDE +14077 101400 4 SMI +14100 103132 4 JMP HI2+7 I /ASSUMES NO TYPE 7 MESSAGE +14101 105642 4 LDA (HER 0 X) I +14102 011103 4 STA .+1 +14103 4 BSS 1 /ERROR?, LOOP JST, OR EXER OR TEST +14104 100000 4 SKP /NO +14105 003232 4 JMP HIERR /ERROR BIT SET IN LEADER +14106 140040 4 CRA 0"A"HSTUP +14107 066504 4 IMA HIHD X +14110 100040 4 SZE /WAS HOST DOWN? +14111 104700 4 LDA IHXX I /YES, IS OUTPUT IN PROGRESS? +14112 101040 4 SNZ +14113 003116 4 JMP .+3 /NOT BOTH +14114 004107 4 LDA M30SEC /WAS DOWN, GIVE OUTPUT FULL 30 SE(' +14115 111643 4 STA (IHTT 0 X) I +14116 105644 4 LDA (EMFH 0 X) I /YES +14117 011120 4 STA .+1 +14120 4 BSS 1 /EOM? +14121 143137 4 DEFSTAT JMP HIH0 XI, HS2 /N0,DISPATCH ON TYPE +00606 031072 4 +32002 014121 4 +32022 143137 4 +14122 003231 4 JMP HISHRT /YES, LESS THAN 32 BIT MESSAGE + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 126 IMP,3050,IMP 7:20 PM 9/16/1973 + + LEV CON +14123 014243 C HI2: HI20 /0 - REG +14124 013357 C HIDISC /1 - IMP FORMAT ERROR +14125 013355 C HIDOWN /2 - HOST GOING DOWN +14126 014230 C HIBADC /3 +14127 013357 C HIDISC /4 - NOP +14130 014230 C HIBADC /5 +14131 014230 C HIBADC /6 +14132 014230 C HIBADC /7 - USED IN CODE FOR HIBADC REFEF ' +14133 013357 C HIDISC /8 - IMP FORMAT ERROR WITH ID +14134 114134 C HIDE: . 0 I + + LEV VAR + /MORE OF HOST-TO-IMP, INCLUDING PACKET PROCESSING +14135 V HIT1: BSS 1 /TEMP +14136 177777 V HITF: -1 +14137 V HIH0: BSS TH /SAVED HEAD,HEAD1,HEAD2,HEAD3 +14147 V HIH1: BSS TH +14157 V HIH2: BSS TH +14167 V HIH3: BSS TH +14177 V HIDEST: BSS TH /DESTINATION OF CURRENT MESS + /SIGN BIT ON MEANS HOST TOOK TOO LO1 +14207 V HILINK: BSS TH /PNTR TO SAVED LINK+SUB-CODE WORD +14217 V HIBLKT: BSS TH /TIME TO WAIT FOR MESS NO +14227 V HIAR: BSS 1 /TEMP ADDER RETURN + + LEV H2I +14230 065167 4 HIBADC: IRS HIH3 X 0"A"CILLGL +14231 065167 4 HISHRT: IRS HIH3 X 0"A"CSHORT +14232 140040 4 HIERR: CRA 0"A"CERR32 +14233 051147 4 STA HIH1 X +14234 005645 4 LDA (CERRLD) +14235 003273 4 JMP HI16 + +14236 005646 4 HIBLK: LDA (CBLOCK) +14237 053167 4 ERA HIH3 X +14240 051167 4 STA HIH3 X +14241 005647 4 LDA (CINCTR) +14242 003273 4 JMP HI16 + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 127 IMP,3050,IMP 7:20 PM 9/16/1973 + +14243 004675 4 HI20: LDA HIP /FIGURE OUT HOW LONG TO WAIT FOR ME: +14244 012130 4 ERA PLNH /IS THIS FROM TTY? +14245 100040 4 SZE /GIVE IT 150 MS OR 15 SECS IF NOT +14246 005650 4 LDA (0 0 -6"X"-450.) +14247 012126 4 ERA MINUS6 /15 SECS FOR ALL OTHER HOST +14250 051217 4 STA HIBLKT X +14251 045147 4 LDA HIH1 X +14252 007651 4 ANA (DESTI) +14253 051177 4 STA HIDEST X +14254 010000 4 STA 0 +14255 044165 4 LDA RUT X +14256 072675 4 LDX HIP +14257 101400 4 SMI 0"A"CIMPD 0"A"RUTDED +14260 007652 4 ANA (RUTCMU) /HOSTS AT DEAD IMPS ARE DEAD +14261 100040 4 SZE /IS THERE A DELAY IN BRINGING THI1 +14262 003272 4 JMP HI19 /YES, IMP IS STILL DEAD +14263 045147 4 LDA HIH1 X +14264 007653 4 ANA (FORIMP 0 DESTH) +14265 013654 4 ERA (FORIMP 0 200) +14266 101010 4 SS2 /ALL HOSTS ARE UP IF SS2 IS UP +14267 100040 4 SZE /PARAM CHANGE IS DOWN IF IT'S NOT +14270 003311 4 JMP HI23 /HOST IS UP +14271 065167 4 HI18: IRS HIH3 X 0"A"CHSTD +14272 005655 4 HI19: LDA (CDESTD) +14273 051137 4 HI16: STA HIH0 X +14274 001001 4 HI17: INH FRE +14275 045167 4 0 LDA HIH3 X +14276 010515 4 0 STA TWDP +14277 045147 4 0 LDA HIH1 X +14300 053137 4 0 ERA HIH0 X +14301 120670 4 0 JST OWP I +14302 103631 4 0 JMP (HIDISC) I +14303 121635 4 0 JST (HIWM) I RET H2I + DEFPLC [HI - WAITING FOR TWO-WORD STORE] +14304 003274 4 JMP HI17 + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 128 IMP,3050,IMP 7:20 PM 9/16/1973 + +14305 065217 4 HI22: IRS HIBLKT X /HAVE WE WAITED TOO LDNG? +14306 100000 4 SKP /NO +14307 003236 4 JMP HIBLK /YES, SEND BACK BLOCKED +14310 021026 4 JST HIWMD + DEFPLC [HI - WAITING FOR MESS NO] +14311 045147 4 HI23: LDA HIH1 X +14312 007656 4 ANA (PRIBIT 0 DESTI) +14313 121657 4 JST (MESGET) I +14314 003305 4 JMP HI22 /MESSNO IN USE, WAIT +14315 051137 4 STA HIH0 X /SET UP HIH0, HIH2 +14316 045147 4 LDA HIH1 X +14317 007660 4 ANA (FOROCT) 0"A"LSTPKT +14320 012106 4 ERA MINE /CONSTRUCT SOURCE +14321 053042 4 ERA HBTS X 0"A"SRCEH +14322 051157 4 STA HIH2 X +14323 004675 4 LDA HIP +14324 013661 4 ERA (NH+2) +14325 100040 4 SZE /DO NOT AUTO-TRACE TRACE +14326 105662 4 LDA (TF) I +14327 100040 4 SZE /IS AUTO TRACE ON? +14330 025136 4 IRS HITF /YES, IS IT TIME TO TRACE? +14331 003341 4 JMP HI24 /NO +14332 045147 4 LDA HIH1 X /YES +14333 007663 4 ANA (0 0 177777"X"TRACE) +14334 013664 4 ERA (TRACE) /TURN ON TRACE BIT +14335 051147 4 STA HIH1 X +14336 105662 4 LDA (TF) I +14337 140407 4 TCA +14340 011136 4 STA HITF /RESET AUTO TRACE INTERVAL +14341 005665 4 HI24: LDA (HIPKT1) +14342 103666 4 JMP (HINLO) I + DEFPLC [HI - WAITING FOR FIRST PKT] +14343 105667 4 HIPKT1: LDA (HITT 0 X) I +14344 101040 4 SNZ /DID ALARM CLOCK GO OFF? +14345 003353 4 JMP HIPK1S /YES +14346 105644 4 LDA (EMFH 0 X) I +14347 011350 4 STA .+1 +14350 4 BSS 1 +14351 003400 4 JMP HIPLT /MULTI-PACKET INPUT +14352 003361 4 JMP HIPK1A + +14353 140500 4 HIPK1S: SSM +14354 051177 4 STA HIDEST X /MARK AS TOO SLOW +14355 045147 4 LDA HIH1 X +14356 007670 4 ANA (0 0 177777"X"PKTNO) +14357 013655 4 ERA (PKTNO) /MARK AS LAST PKT - FOR HIDISC +14360 051147 4 STA HIH1 X +14361 005671 4 HIPK1A: LDA (ONEOR8 0 REQALL) /MARK AS REQ FOR 1 +14362 053137 4 ERA HIH0 X +14363 051137 4 STA HIH0 X +14364 021464 4 JST HIPKT +14365 003370 4 JMP HIPPT + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 129 IMP,3050,IMP 7:20 PM 9/16/1973 + +14366 021026 4 HIPPT0: JST HIWMD + DEFPLC [HI - WAITING FOR PPT SLOT FOR REQ1] +14367 172677 4 LDX HIXX I +14370 121672 4 HIPPT: JST (PPTPUT) I +14371 003366 4 JMP HIPPT0 /NO ROOM IN PPT, WAIT +14372 051207 4 HIMESS: STA HILINK X /SAVE PNTR INTO RPT OR PLT +14373 045177 4 LDA HIDEST X +14374 100400 4 SPL /DID THIS GUY TAKE TOO LONG +14375 003610 4 JMP HIPSLO /YES, GO TO TASK +14376 121673 4 JST (HTPMT) I /COUNT A MESSAGE OF THROUGHPUT +14377 003551 4 JMP HI26 + +14400 045177 4 HIPLT: LDA HIDEST X +14401 121674 4 JST (TALLYG) I /ANY ALLOC FROM OUR DEST? +14402 003412 4 JMP HIPLT2 /NO +14403 021464 4 HIPLTA: JST HIPKT +14404 072675 4 LDX HIP +14405 003407 4 JMP HIPLT1 +14406 021026 4 JST HIWMD + DEFPLC [HI - WAITING FOR PLT SLOT FOR MESS8] +14407 121675 4 HIPLT1: JST (PLTPUT) I +14410 003406 4 JMP .-2 /NO PLT ROOM, WAIT +14411 003372 4 JMP HIMESS + +14412 005676 4 HIPLT2: LDA (REQALL) /MARK AS REQUEST FOR 8 +14413 053137 4 ERA HIH0 X +14414 051137 4 STA HIH0 X +14415 021464 4 JST HIPKT /COPY HEADER +14416 004000 4 LDA 0 +14417 015677 4 ADD (TWOQ MINPL) /MARK AS ON TWO QUEUES, +14420 050111 4 STA BUFE X /FROM SAME BUFFER +14421 072675 4 LDX HIP +14422 100000 4 SKP +14423 021026 4 JST HIWMD + DEFPLC [HI - WAITING FOR PLT SLOT FOR REQ8] +14424 121675 4 JST (PLTPUT) I +14425 003423 4 JMP .-2 /NO PLT ROOM, WAIT +14426 051207 4 STA HILINK X /SAVE PNTR INTO PLT +14427 172677 4 HIPLT3: LDX HIXX I +14430 021520 4 JST HICKSM /MAKE A CHECKSUM +14431 001001 4 INH M2I +14432 132401 4 0 STX ETQ I +14433 032401 4 0 STX ETQ +14434 030041 4 0 TASK +14435 121635 4 0 HIPLT4: JST (HIWM) I RET H2I + DEFPLC [HI - WAITING FOR TASK TO TAKE A REQ8] +14436 003435 4 JMP HIPLT4 +14437 003427 4 JMP HIPLT3 /TASK REFUSED IT + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 130 IMP,3050,IMP 7:20 PM 9/16/1973 + +14440 045177 4 HIPLT5: LDA HIDEST X +14441 121674 4 JST (TALLYG) I /ANY ALLOC FROM OUR DEST? +14442 003444 4 JMP HIPLT6 /NO +14443 003447 4 JMP HIPLT8 +14444 021026 4 HIPLT6: JST HIWMD + DEFPLC [HI - WAITING FOR ALL8] +14445 003440 4 HIALL: JMP HIPLT5 + +14446 121635 4 HIPLT7: JST (HIWM) I +14447 172677 4 HIPLT8: LDX HIXX I +14450 044111 4 LDA BUFE X +14451 100400 4 SPL 0"A"TWOQ /HAS THE ACK FOR THIS PKT BEEN PRC*] +14452 003446 4 JMP HIPLT7 /NOT YET, PKT STILL ON LINE, SO WAI +14453 072675 4 LDX HIP +14454 003456 4 JMP HIPLT0 + +14455 021026 4 HIPLT9: JST HIWMD + DEFPLC [HI - WAITING FOR MESS NO FOR MESS8] +14456 045177 4 HIPLT0: LDA HIDEST X /KEEP SAME ORDNO AS REQS +14457 121657 4 JST (MESGET) I /GET NEW MESS NO FOR MESS8 +14460 003455 4 JMP HIPLT9 /MESS NO IN USE, WAIT +14461 051137 4 STA HIH0 X 0"A"REQALL /SAVE IN HEADER +14462 111667 4 STA (HITT 0 X) I /DEFEAT INC TRN LOGIC +14463 003403 4 JMP HIPLTA + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 131 IMP,3050,IMP 7:20 PM 9/16/1973 + +14464 000000 4 HIPKT: 0 +14465 104677 4 LDA HIXX I /COPY HEADER +14466 015700 4 ADD (HEAD) +14467 011135 4 STA HIT1 +14470 045137 4 LDA HIH0 X +14471 111135 4 STA HIT1 I +14472 025135 4 IRS HIT1 +14473 045147 4 LDA HIH1 X +14474 111135 4 STA HIT1 I +14475 025135 4 IRS HIT1 +14476 045157 4 LDA HIH2 X +14477 111135 4 STA HIT1 I +14500 025135 4 IRS HIT1 +14501 045167 4 LDA HIH3 X +14502 111135 4 STA HIT1 I +14503 105701 4 LDA (HIB1 0 XI) I /SAVE LENGTH +14504 140100 4 SSP 0"A"TWOQ +14505 172677 4 LDX HIXX I /LEAVE ROOM FOR CKSUM WRD +14506 050111 4 STA BUFE X /SET UP TWOQ BIT AFTER CALL TO HIPK +14507 131040 4 RDCLOK /SAVE TIME +14510 003507 4 JMP .-1 +14511 050001 4 STA IT X +14512 004675 4 LDA HIP 0"A"INPCHN +14513 140500 4 SSM 0"A"HSTMOD +14514 050003 4 STA INCH X +14515 140040 4 CRA +14516 050000 4 STA 0 X /CLEAR CHAIN POINTER +14517 103464 4 JMP HIPKT I + +14520 000000 4 HICKSM: 0 +14521 005702 4 LDA (HICKAD) /GRAB ADDER +14522 026111 4 IMA ADDRET /AND SAVE OLD OWNER +14523 011227 4 STA HIAR +14524 044111 4 LDA BUFE X +14525 140100 4 SSP 0"A"TWOQ +14526 011543 4 STA HICKT +14527 140407 4 TCA +14530 014000 4 ADD 0 +14531 015703 4 ADD (ADDBOT+ACKH+1) +14532 011535 4 STA HICKAJ +14533 017704 4 SUB (ADDBOT+1) /-NO DF WORDS +14534 103535 4 JMP HICKAJ I +14535 4 HICKAJ: BSS 1 +14536 140407 4 HICKAD: TCA + DEFPLC [NOP HERE TO TURN OFF H2I CHECKSUM GENERATION] +14537 111543 4 STA HICKT I /STORE CHECKSUM +14540 005227 4 LDA HIAR /PUT BACK OLD OWNER +14541 010111 4 STA ADDRET +14542 103520 4 JMP HICKSM I + LEV VAR +14543 V HICKT: BSS 1 /TEMP BUFE PTR + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 132 IMP,3050,IMP 7:20 PM 9/16/1973 + + /TOP OF PACKET LOOP + LEV H2I + DEFPLC [HI - WAITING FOR MIDDLE PACKET] +14544 021464 4 HI25: JST HIPKT /SET UP HEADER AND BUFFER CONTROL W[ +14545 072675 4 LDX HIP +14546 105667 4 LDA (HITT 0 X) I +14547 101040 4 SNZ /DID ALARM CLOCK GO OFF? +14550 003610 4 JMP HIPSLO /YES +14551 105642 4 HI26: LDA (HER 0 X) I +14552 011553 4 STA .+1 +14553 4 BSS 1 /ERROR? +14554 003570 4 JMP HI84 /NO +14555 005646 4 LDA (CERROR) /YES, MARK MESS AS ERROR IN DATA +14556 153207 4 HISUBC: ERA HILINK XI /PUT IN NEW SUB CODE +14557 006120 4 ANA SEVEN 0"A"SUBCOD +14560 153207 4 ERA HILINK XI /INTO PNTR TO LINK AND SUB CODE WOR[ +14561 151207 4 STA HILINK XI +14562 172677 4 LDX HIXX I +14563 044005 4 LDA HEAD X +14564 007705 4 ANA (0 0 177777"X"INCTRN) +14565 013706 4 ERA (INCTRN) /SET INC TRN BIT +14566 050005 4 STA HEAD X +14567 003616 4 JMP H2TASK + +14570 045177 4 HI84: LDA HIDEST X /COUNT A PACKET OF THROUGHPUT +14571 121707 4 JST (HTPPT) I +14572 105644 4 LDA (EMFH 0 X) I +14573 011574 4 STA HIEM1 +14574 4 HIEM1: BSS 1 /IS FOM SET? +14575 003577 4 JMP .+2 /NO +14576 003612 4 JMP HI87 /YES +14577 045147 4 LDA HIH1 X /GET PACKET # +14600 007655 4 ANA (PKTNO) +14601 013655 4 ERA (PKTNO) +14602 101040 4 SNZ /IS PKT NO=7 ? +14603 003606 4 JMP HIPLNG /YES +14604 172677 4 HI85: LDX HIXX I +14605 003616 4 JMP H2TASK /NO + +14606 004114 4 HIPLNG: LDA ONE 0"A"CLONG +14607 003556 4 JMP HISUBC /MARK MESS AS TOO LONG + +14610 004115 4 HIPSLO: LDA TWO 0"A"CSLOWS +14611 003556 4 JMP HISUBC /MARK MESS AS TOO SLOW + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 133 IMP,3050,IMP 7:20 PM 9/16/1973 + +14612 172677 4 HI87: LDX HIXX I +14613 044007 4 DEFSTAT LDA HEAD2 X, HS0 +00607 031055 4 +32003 014613 4 +32023 044007 4 +14614 140500 4 SSM 0"A"LSTPKT +14615 050007 4 STA HEAD2 X +14616 021520 4 H2TASK: JST HICKSM /CHECKSUM PACKET +14617 001001 4 INH M2I +14620 132401 4 0 STX ETQ I /PUT PACKET ON MIDDLE TASK QUEUE +14621 032401 4 0 STX ETQ +14622 030041 4 0 TASK /POKE TASK INTERRUPT +14623 121635 4 0 H2TSKS: JST (HIWM) I RET H2I + DEFPLC [HI - WAITING FOR TASK TO TAKE A PKT] +14624 003623 4 JMP H2TSKS /NO ACTION YET +14625 003604 4 JMP HI85 /TASK REFUSED IT +14626 103710 4 JMP (HIDB) I /TASK TOOK IT + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 134 IMP,3050,IMP 7:20 PM 9/16/1973 + +14627 007400 C LEV CON CONSTANTS +14630 002000 C +14631 013357 C +14632 021431 C +14633 054177 C +14634 013127 C +14635 013124 C +14636 053432 C +14637 053433 C +14640 177760 C +14641 114123 C +14642 053170 C +14643 056306 C +14644 053313 C +14645 000400 C +14646 000004 C +14647 004400 C +14650 000704 C +14651 000077 C +14652 000340 C +14653 040300 C +14654 040200 C +14655 003400 C +14656 100077 C +14657 015161 C +14660 010000 C +14661 000006 C +14662 030457 C +14663 157777 C +14664 020000 C +14665 014343 C +14666 013466 C +14667 053137 C +14670 174377 C +14671 000300 C +14672 015064 C +14673 022415 C +14674 015114 C +14675 015233 C +14676 000100 C +14677 100010 C +14700 000005 C +14701 153147 C +14702 014536 C +14703 001563 C +14704 001557 C +14705 177767 C +14706 000010 C +14707 022426 C +14710 013405 C +02423 176721 C PAGEND 14,UNCON,4 + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 135 IMP,3050,IMP 7:20 PM 9/16/1973 + + + LEV [T.O,TSK,BCK] LCK H2I + /PENDING PACKET TABLE SUBROUTINES - LOCK INTERRUPTS +15033 000000 5 4 PPTGET: 0 /GET AN ENTRY FROM PPT +15034 011160 5 4 STA PPWANT /MATCH ON MESSNO AND IMPNO IN A +15035 005521 5 4 LDA (-PPTL) +15036 011157 5 4 STA PPTRY +15037 005522 5 4 LDA (PPT) +15040 011156 5 4 STA PPSLT +15041 105156 5 4 PPTL1: LDA PPSLT I /LOOK AT NEXT SLOT +15042 101040 5 4 SNZ /IS THIS SLOT OCCUPIED? +15043 003060 5 4 JMP PPTN1 /NO +15044 010000 5 4 STA 0 /YES, SO LOOK FOR MATCH +15045 044005 5 4 LDA HEAD X +15046 141044 5 4 CAR 0"A"MESSNO +15047 052006 5 4 ERA HEAD1 X +15050 007523 5 4 ANA (0 0 177777"X"DESTI) +15051 052006 5 4 ERA HEAD1 X +15052 013160 5 4 ERA PPWANT +15053 100040 5 4 SZE /MATCH ON MESSNO+IMPNO? +15054 003060 5 4 JMP PPTN1 /NO +15055 005156 5 4 LDA PPSLT /RETURN PNTR TO PPT PNTR IN AC +15056 025033 5 4 IRS PPTGET /SKIP=SUCCESS +15057 103033 5 4 JMP PPTGET I +15060 025156 5 4 PPTN1: IRS PPSLT /GET NEXT SLOT +15061 025157 5 4 IRS PPTRY +15062 003041 5 4 JMP PPTL1 /LOOP BACK +15063 103033 5 4 JMP PPTGET I /NO MATCH, NO SKIP + + LEV H2I +15064 000000 4 PPTPUT: 0 /PUT AN ENTRY INTO PPT - PNTR IN X +15065 004675 4 LDA HIP /TABLE IS PPTL DEEP FOR FAKE HOSTS +15066 040576 4 ARS 2 +15067 140407 4 TCA 0"A"NH /AND PPTL-1 DEEP FOR REAL HOSTS +15070 015524 4 ADD (0 1-PPTL) +15071 011157 4 STA PPTRY +15072 005522 4 LDA (PPT) +15073 011156 4 STA PPSLT +15074 105156 4 PPTL2: LDA PPSLT I +15075 100040 4 SZE /IS THIS SLOT FREE? +15076 003110 4 JMP PPTN2 /NO +15077 133156 4 STX PPSLT I /YES, SO PUT IN OUR PNTR +15100 044111 4 LDA BUFE X +15101 140500 4 SSM 0"A"TWOQ /MARK PACKET AS ON 2 QUEUES +15102 050111 4 DEFSTAT STA BUFE X, HS4 +00610 031266 4 +32004 015102 4 +32024 050111 4 +15103 004000 4 LDA 0 +15104 015525 4 ADD (HEAD3) +15105 072675 4 LDX HIP +15106 025064 4 IRS PPTPUT /SKIP=SUCCESS +15107 103064 4 JMP PPTPUT I +15110 025156 4 PPTN2: IRS PPSLT /GET NEXT SLOT +15111 025157 4 IRS PPTRY +15112 003074 4 JMP PPTL2 /LOOP BACK +15113 103064 4 JMP PPTPUT I /NO ROOM, NO SKIP + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 136 IMP,3050,IMP 7:20 PM 9/16/1973 + + LEV [H2I,T.O,BCK] + /TALLY TABLE SUBROUTINES - LOCK INTERRUPTS + /ARG PASSED IN A, AND X PRESERVED +15114 000000 4 TALLYG: 0 /GET AN ENTRY FROM TALLY +15115 011153 4 STA TALLYT /IMPNO TO MATCH IN A +15116 033154 4 STX TALLYX +15117 073526 4 LDX (TALLY-1) +15120 024000 4 TALLYK: IRS 0 +15121 004000 4 LDA 0 +15122 023155 4 CAS TALLYI /COMPARE WITH IN PNTR +15123 003150 4 JMP TALLYR +15124 003150 4 JMP TALLYR /NO MATCH, NO SKIP +15125 044000 4 LDA 0 X +15126 013153 4 ERA TALLYT +15127 100040 4 SZE /IS THIS ENTRY ONE WE WANT? +15130 003120 4 JMP TALLYK /NO, LOOP BACK +15131 004000 4 LDA 0 +15132 013527 4 ERA (TALLY) +15133 101040 4 SNZ /DID WE JUST GRAB THE OLDEST ALLOCA +15134 111530 4 STA (TALLYC) I /YES, SO RESET TALLY CLOCK +15135 044001 4 TALLYM: LDA 1 X +15136 050000 4 STA 0 X /MOVE REST OF TABLE UP BY ONE SLOT +15137 024000 4 IRS 0 +15140 004000 4 LDA 0 +15141 013155 4 ERA TALLYI +15142 100040 4 SZE /DONE YET? +15143 003135 4 JMP TALLYM /NO, LOOP BACK +15144 005155 4 LDA TALLYI /YES, NOW ADJUST IN PNTR +15145 016114 4 SUB ONE +15146 011155 4 STA TALLYI +15147 025114 4 IRS TALLYG /SKIP=SUCCFSS +15150 073154 4 TALLYR: LDX TALLYX /RESTORE X +15151 005153 4 LDA TALLYT /RESTORE A +15152 103114 4 JMP TALLYG I + + LEV VAR +15153 V TALLYT: BSS 1 /TEMP A +15154 V TALLYX: BSS 1 /TEMP X +15155 V TALLYI: BSS 1 /IN PNTR + +15156 V PPSLT: BSS 1 /PNTR TO PPT ENTRY +15157 V PPTRY: BSS 1 /NO OF TIMES TO LOOK +15160 V PPWANT: BSS 1 /MESSNO + IMPNO WE WANT + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 137 IMP,3050,IMP 7:20 PM 9/16/1973 + + LEV [H2I,BCK] +15161 000000 4 MESGET: 0 /GFT MESSNO, DEST IMP IN A +15162 033204 4 STX MESGX +15163 011203 4 STA MESGT +15164 140100 4 SSP 0"A"PRIBIT +15165 015531 4 ADD (TMESS) +15166 010000 4 STA 0 +15167 044000 4 LDA 0 X +15170 101100 4 SLN 0"A"MESBTS +15171 003201 4 JMP MESGND /MESS NO IN USE +15172 005203 4 LDA MESGT +15173 100400 4 SPL 0"A"PRIBIT /NEED A NEW ORD NO? +15174 021361 4 JST UPORD /YES +15175 021347 4 JST UPMESS +15176 007532 4 ANA (MESSNO 0 ORDNO) +15177 013533 4 ERA (TRNREP) /MARK AS TRANSMISSION +15200 025161 4 IRS MESGET /SKIP=SUCCESS +15201 073204 4 MESGND: LDX MESGX +15202 103161 4 JMP MESGET I + LEV VAR +15203 V MESGT: BSS 1 +15204 V MESGX: BSS 1 + + LEV [T.O,TSK,BCK] LCK H2I + /PENDING LEADER TABLE SUBROUTINES - LOCK INTERRUPTS +15205 000000 5 4 PLTGET: 0 /GET AN ENTRY FROM PLT +15206 011274 5 4 STA PLWANT /MATCH ON MESSNO AND IMPNO IN A +15207 005534 5 4 LDA (-PLTL) +15210 011273 5 4 STA PLTRY +15211 073535 5 4 LDX (PLT) +15212 044000 5 4 PLTL1: LDA PLT0 X +15213 101040 5 4 SNZ /IS THIS ENTRY EMPTY? +15214 003226 5 4 JMP PLTN1 /YES +15215 141044 5 4 CAR 0"A"MESSNO +15216 052014 5 4 ERA PLT1 X +15217 007523 5 4 ANA (0 0 177777"X"DESTI) +15220 052014 5 4 ERA PLT1 X +15221 013274 5 4 ERA PLWANT +15222 100040 5 4 SZE /MATCH ON MESSNO+IMPNO? +15223 003226 5 4 JMP PLTN1 /NO +15224 025205 5 4 IRS PLTGET /SKIP=SUCCESS +15225 103205 5 4 JMP PLTGET I /RETURN PNTR TO PLT ENTRY IN X +15226 024000 5 4 PLTN1: IRS 0 /GET NEXT ENTRY +15227 025273 5 4 IRS PLTRY +15230 003212 5 4 JMP PLTL1 /LOOP BACK +15231 005274 5 4 LDA PLWANT /RESTORE A +15232 103205 5 4 JMP PLTGET I /NO MATCH, NO SKIP + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 138 IMP,3050,IMP 7:20 PM 9/16/1973 + + LEV H2I +15233 000000 4 PLTPUT: 0 /PUT AN ENTRY INTD PLT +15234 004000 4 LDA 0 /HOST NO IN A +15235 113536 4 ERA (HIH0 0 X) I +15236 007537 4 ANA (0 0 177777"X"MESSNO"X"REQALL) +15237 113536 4 ERA (HIH0 0 X) I +15240 013540 4 ERA (PLTUSE) /MARK PLT0 ENTRY IN USE +15241 011275 4 STA PLTH /SAVE PLT0 ENTRY +15242 105541 4 LDA (HIH1 0 X) I +15243 011276 4 STA PLTH1 /SAVE PLT1 ENTRY +15244 105542 4 LDA (HIH3 0 X) I +15245 011277 4 STA PLTH3 /SAVE PLT2 ENTRY +15246 005534 4 LDA (-PLTL) +15247 011273 4 STA PLTRY +15250 073535 4 LDX (PLT) +15251 044000 4 PLTL2: LDA PLT0 X +15252 100040 4 SZE /IS THIS ENTRY FREE? +15253 003267 4 JMP PLTN2 /NO +15254 005275 4 LDA PLTH /YES, SO PLANT PLT0,1,2 +15255 050000 4 STA PLT0 X +15256 005276 4 LDA PLTH1 +15257 050014 4 STA PLT1 X +15260 005277 4 LDA PLTH3 +15261 050030 4 DEFSTAT STA PLT2 X, HS5 +00611 031276 4 +32005 015261 4 +32025 050030 4 +15262 025233 4 IRS PLTPUT /SKIP=SUCCESS +15263 004000 4 PLTPX: LDA 0 +15264 015543 4 ADD (PLT2) +15265 072675 4 LDX HIP +15266 103233 4 JMP PLTPUT I +15267 024000 4 PLTN2: IRS 0 /GET NEXT ENTRY +15270 025273 4 IRS PLTRY +15271 003251 4 JMP PLTL2 /LOOP BACK +15272 003263 4 JMP PLTPX /NO ROOM, NO SKIP + + LEV VAR +15273 V PLTRY: BSS 1 +15274 V PLWANT: BSS 1 +15275 V PLTH: BSS 1 +15276 V PLTH1: BSS 1 +15277 V PLTH3: BSS 1 + +15300 V RALLYA: BSS 1 +15301 V RALLYI: BSS 1 +15302 V RALMRK: BSS 1 + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 139 IMP,3050,IMP 7:20 PM 9/16/1973 + + + /RALLY TABLE SUBROUTINES + LEV [I2H,TSK] +15303 000000 3 RALLYP: 0 /PUT AN ENTRY IN RALLY TABLE +15304 011300 3 STA RALLYA /A = MESSNO, ONEOR8, RFNM, SRCEI +15305 007544 3 ANA (SRCEI) +15306 015545 3 ADD (RALLY) +15307 011301 3 STA RALLYI /SET UP INPUT PNTR +15310 004121 3 LDA MINUS1 +15311 022000 3 CAS 0 /X = REGULAR. INCOMPLETE, OR DEAD +15312 141206 3 AOA /X=SIGN, DEAD +15313 141206 3 AOA /X=MINUS1, INCOMPLETE +15314 141206 3 AOA /X=0 OR X>0, REGULAR +15315 141206 3 AOA /MAKE INTO 11, 10, OR 01 +15316 041576 3 ALS 2 /SHIFT INTO POSITION +15317 011302 3 STA RALMRK /AND SAVE AS MARK BITS +15320 005300 3 LDA RALLYA +15321 141140 3 ICL 0"A"MESSNO +15322 006116 3 ANA THREE +15323 041576 3 ALS 2 +15324 140407 3 TCA +15325 015546 3 ADD (ALR 0 +15326 011331 3 STA RALPS1 /SET UP SHIFT +15327 011341 3 STA RALPS2 +15330 005547 3 LDA (17) +15331 3 RALPS1: BSS 1 +15332 107301 3 ANA RALLYI I +15333 100040 3 SZE /SOMETHING ALREADY THERE? +15334 003346 3 JMP RALPX /YES, A BUG +15335 005300 3 LDA RALLYA +15336 040672 3 ARR 6 0"A"[ONEOR8 0 RFNM] +15337 006116 3 ANA THREE /GET BITS +15340 013302 3 ERA RALMRK /MARK GOT-IT BIT +15341 3 RALPS2: BSS 1 /SHIFT THEM OVER +15342 113301 3 ERA RALLYI I /OR THE BITS IN +15343 111301 3 STA RALLYI I +15344 010477 3 STA RALLCF /COUNT AN ALLOCATE PENDING +15345 025303 3 IRS RALLYP /SKIP=SUCCESS +15346 103303 3 RALPX: JMP RALLYP I + + /FORMAT OF EACH RALLY WORD IS 4 4-BIT BYTES: A,B,C,D + /THIS TABLE RUNS IN PARALLEL WITH AMESS, THE NEXT MESSAGE + /NUMBER FOR WHICH A REPLY SHOULD BE RETURNED + /BYTE A IS FOR AMESS=3 MOD 4, B FOR AMESS=2 MOD 4 + /C= 1 MOD 4, D= 0 MOD 4 + /FORMAT OF EACH 4 -BIT BYTE IS TTMM: + /TT=00 NO ENTRY + /TT=01 RFNM OR RFNM/ALLOCATE + /TT=10 INCOMPLETE TRANSMISSION + /TT=11 DESTINATION DEAD + /FOR TT=10 OR TT=01: + /MM=00 8 PKT ALLOCATE + /MM=01 8 PKT RFNM/ALLOCATE + /MM=10 1 PKT ALLOCATE + /MM=11 1 PKT RFNM + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 140 IMP,3050,IMP 7:20 PM 9/16/1973 + + LEV [H2I,T.O,TSK,BCK] +15347 000000 4 UPMESS: 0 /ADD ONE TO MESS NO +15350 044000 4 LDA 0 X /PNTR TO MESS TAB IN X +15351 007547 4 ANA (MESBTS) +15352 040477 4 LGR 1 /SHIFT BITS +15353 052000 4 ERA 0 X +15354 007547 4 ANA (MESBTS) +15355 052000 4 ERA 0 X +15356 015550 4 ADD (MESS1) 0"A"MESSNO +15357 050000 4 STA 0 X /INCREMENT MESS NO +15360 103347 4 JMP UPMESS I + +15361 000000 4 UPORD: 0 /ADD ONE TO ORDER NO +15362 044000 4 LDA 0 X /PNTR TO MESS TAB IN X +15363 015551 4 ADD (20) 0"A"ORDNO +15364 052000 4 ERA 0 X /INCREMENT ORDER NO +15365 007552 4 ANA (ORDNO) +15366 052000 4 ERA 0 X +15367 050000 4 STA 0 X +15370 103361 4 JMP UPORD I + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 141 IMP,3050,IMP 7:20 PM 9/16/1973 + + LEV FRE + /PUT A TWO-WORD MESSAGE - LOCK INTERRUPTS + /CALLED BY I2H,H2I,T.O,TSK,BCK +15371 000000 0 OWPE: 0 +15372 033501 0 STX HNUM +15373 011502 0 STA ONEW +15374 005501 0 LDA HNUM +15375 022130 0 CAS PLNH /REAL HOST? +15376 003442 0 JMP OWPF /NO +15377 101000 0 NOP /TTY LIKE REAL HOST +15400 073553 0 LDX (SHBQ) +15401 004124 0 LDA MINUS4 +15402 011500 0 STA TPEE +15403 003411 0 JMP OWP4 +15404 010000 0 OWP0: STA 0 +15405 064003 0 IRS 3 X +15406 003462 0 JMP OWP3 +15407 004121 0 LDA MINUS1 +15410 050003 0 STA 3 X +15411 025500 0 OWP4: IRS TPEE /ALLOWED TO HAVE ANOTHER BUFFER? +15412 003415 0 JMP OWP8 /YES +15413 025371 0 OWP7: IRS OWPE /NO +15414 003476 0 JMP OWP5 +15415 044000 0 OWP8: LDA 0 X +15416 100040 0 SZE +15417 003404 0 JMP OWP0 +15420 104324 0 LDA FREE I +15421 101040 0 SNZ +15422 003413 0 JMP OWP7 +15423 026324 0 IMA FREE +15424 024563 0 IRS NFS +15425 050000 0 STA 0 X +15426 011500 0 STA TPEE +15427 026000 0 IMA 0 +15430 050001 0 STA 1 X +15431 005554 0 LDA (-17.) /(DECIMAL) +15432 011503 0 STA OWT3 +15433 050003 0 STA 3 X +15434 140040 0 CRA +15435 050000 0 STA 0 X +15436 005500 0 LDA TPEE +15437 014117 0 ADD FOUR +15440 050002 0 STA 2 X +15441 003452 0 JMP OWP1 + +15442 012120 0 OWPF: ERA SEVEN /DISCARD? +15443 100040 0 SZE +15444 103371 0 JMP OWPE I /NO. +15445 005555 0 LDA (-300.) /YES, RESET SOFTWARE WDT. TO 3 MIN. +15446 010503 0 STA WDTIME +15447 030026 0 WDT /AND POKE THE HARDWARE +15450 103371 0 JMP OWPE I + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 142 IMP,3050,IMP 7:20 PM 9/16/1973 + +15451 044000 0 OWP2: LDA 0 X +15452 010000 0 OWP1: STA 0 +15453 014117 0 ADD FOUR +15454 050000 0 STA 0 X +15455 005500 0 LDA TPEE +15456 050003 0 STA 3 X +15457 025503 0 IRS OWT3 +15460 003451 0 JMP OWP2 +15461 073500 0 LDX TPEE + +15462 144002 0 OWP3: LDA 2 XI +15463 066002 0 IMA 2 X +15464 073501 0 LDX HNUM +15465 150403 0 STA EHWQ XI +15466 050403 0 STA EHWQ X +15467 010000 0 STA 0 +15470 140040 0 CRA +15471 050000 0 STA 0 X +15472 005502 0 LDA ONEW +15473 050001 0 STA 1 X +15474 004515 0 LDA TWDP +15475 050002 0 STA 2 X +15476 073501 0 OWP5: LDX HNUM +15477 103371 0 JMP OWPE I + + LEV VAR +15500 V TPEE: BSS 1 +15501 V HNUM: BSS 1 +15502 V ONEW: BSS 1 +15503 V OWT3: BSS 1 + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 143 IMP,3050,IMP 7:20 PM 9/16/1973 + + /SUBROUTINE TO GET FROM A QUEUE - LOCK INTEPRUPTS + LEV [I2H,T.O,BCK] +15504 000000 3 GETQ: 0 +15505 044000 3 LDA 0 X +15506 101040 3 SNZ +15507 103504 3 JMP GETQ I /NOTHING ON QUEUE +15510 144000 3 LDA 0 XI +15511 101040 3 SNZ /IS THIS THE ONLY THING ON QUEUE? +15512 133556 3 STX (QUEUEE-QUEUEB X) I /YES, MAKE END POINT TO +15513 066000 3 IMA 0 X /REMOVE FROM QUEUE +15514 010000 3 STA 0 +15515 140040 3 CRA +15516 050000 3 STA 0 X /CLEAR CHAIN POINTER +15517 025504 3 IRS GETQ +15520 103504 3 JMP GETQ I + +15521 177770 C LEV CON CONSTANTS +15522 033457 C +15523 177700 C +15524 177771 C +15525 000010 C +15526 032260 C +15527 032261 C +15530 020210 C +15531 032271 C +15532 177460 C +15533 000004 C +15534 177764 C +15535 033477 C +15536 054137 C +15537 000277 C +15540 000200 C +15541 054147 C +15542 054167 C +15543 000030 C +15544 000077 C +15545 032571 C +15546 041700 C +15547 000017 C +15550 000400 C +15551 000020 C +15552 000060 C +15553 000337 C +15554 177757 C +15555 177324 C +15556 040051 C +02424 175566 C PAGEND 15,UNCON,4 + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 144 IMP,3050,IMP 7:20 PM 9/16/1973 + + + /IMP TO HOST (IH) + + PAGI2H: + LEV I2H + +00076 016034 3 H1OTIL/ IH0E +00077 3 H2OTIL/ TIPDEF IH1E,TINT +02257 000077 3 +02307 016026 3 +02337 025061 3 +00070 016020 3 H3OTIL/ IH2E +00067 016012 3 H4OTIL/ IH3E + + PAGI2H/ + /HOST 3 INTERRUPT ROUTINE +16012 000000 3 0 IH3E: INT I2H +16013 033121 3 0 STX IHX +16014 073012 3 0 LDX IH3E +16015 033042 3 0 STX IHSB +16016 072116 3 0 LDX THREE +16017 003044 3 0 JMP IHSB2 + /HOST 2 INTERRUPT ROUTINE +16020 000000 3 0 IH2E: INT I2H +16021 033121 3 0 STX IHX +16022 073020 3 0 LDX IH2E +16023 033042 3 0 STX IHSB +16024 072115 3 0 LDX TWO +16025 003044 3 0 JMP IHSB2 + /HOST 1 INTERRUPT ROUTINE +16026 000000 3 0 IH1E: INT I2H +16027 033121 3 0 STX IHX +16030 073026 3 0 LDX IH1E +16031 033042 3 0 STX IHSB +16032 072114 3 0 LDX ONE +16033 003044 3 0 JMP IHSB2 + /HOST 0 INTERRUPT ROUTINE +16034 000000 3 0 IH0E: INT I2H +16035 033121 3 0 STX IHX /SAVE INDEX REGISTER +16036 073034 3 0 LDX IH0E +16037 033042 3 0 STX IHSB +16040 072113 3 0 LDX ZERO /NOTE HOST WHICH CAUSED INTERRUPT +16041 003044 3 0 JMP IHSB2 + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 145 IMP,3050,IMP 7:20 PM 9/16/1973 + + /FROM HERE ON IS COMMON TO ALL IMP-HOST INTERRUPT ROUTINES +16042 000000 3 0 IHSB: 0 +16043 033121 3 0 STX IHX +16044 000011 3 0 IHSB2: DXA +16045 003046 3 0 JMP . 1 +16046 011117 3 0 STA IHA /SAVE AC +16047 000043 3 0 INK +16050 011120 3 0 STA IHK /SAVE EX-MODE +16051 032676 3 0 STX IHP /SAVE CURRENT HOST +16052 004500 3 0 LDA IHM /SET UP NEW INTERRUPT MASK (177700) +16053 170120 3 0 SMK INTM /OUTPUT IT +16054 026134 3 0 IMA PRIM /SAVE IT IN PRIM +16055 011122 3 0 STA IHMS /SAVE OLD PRIM +16056 000401 3 0 ENB I2H +16057 143107 3 JMP IHLO XI /RESTART WHERE LAST LEFT OFF + +16060 000000 3 IHDB: 0 /DEBREAK +16061 004000 3 LDA 0 +16062 016130 3 SUB PLNH +16063 100400 3 SPL +16064 003071 3 JMP IHDO /REAL HOST - DO THE OCP +16065 004107 3 LDA M30SEC /FAKE HOSTS ALWAYS GET 2 MINUTES +16066 041576 3 ALS 2 +16067 051306 3 STA IHTT X +16070 100000 3 SKP /DON'T DO OCP FOR FAKE GUYS +16071 3 IHDO: BSS 1 +16072 005060 3 LDA IHDB +16073 051107 3 IHDONE: STA IHLO X +16074 005122 3 LDA IHMS /RESTORE INTERPUPT MASK +16075 001001 3 INH MSK +16076 170120 3 0 SMK INTM +16077 010134 3 0 STA PRIM +16100 000013 3 0 EXA +16101 005120 3 0 LDA IHK +16102 171020 3 0 OTK /RESTORE EX-MODE +16103 073121 3 0 LDX IHX /RESTORE IR +16104 005117 3 0 LDA IHA /RESTORE AC +16105 000401 3 0 ENB I2H +16106 103042 3 JMP IHSB I + + LEV VAR + / IHLO INDICATES WHAT ROUTINES DID LAST + DEFPLC [IHLO] +16107 V IHLO: BSS TH /RETURN ADDRESSES WHERE IH LEFT OFF +16117 V IHA: BSS 1 /AC SAVE +16120 V IHK: BSS 1 /K SAVE +16121 V IHX: BSS 1 /IR SAVE +16122 V IHMS: BSS 1 /OLD PRIM SAVE +16123 V IHAR: BSS 1 /ADD RET SAVE + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 146 IMP,3050,IMP 7:20 PM 9/16/1973 + + /IMP-TO-HOST ROUTINES LOCAL STORAGE + LEV CON +16124 030270 C IHED: H1FOUT /FINAL OUTPUT INSTRUCTIONS +16125 030260 C H2FOUT +16126 C TIPDEF H3FOUT, NOP +02260 016126 C +02310 030250 C +02340 101000 C +16127 030251 C H4FOUT +16130 016205 C OWOP: OWO /PNTRS TO TWO WORD OUTPUT AREAS +16131 016207 C OWO+2 +16132 016211 C OWO+4 +16133 016213 C OWO+6 +16134 016215 C OWO+10 +16135 000044 C IHB1: H1OTBP /DMC OUTPUT PNTRS +16136 000046 C H2OTBP +16137 C TIPDEF H3OTBP, TIPLNK +02261 016137 C +02311 000054 C +02341 000770 C +16140 000030 C H4OTBP +16141 017407 C IHBB +16142 017410 C IHBB+1 +16143 017411 C IHBB+2 +16144 017412 C IHBB+3 +16145 000045 C IHB2: H1OTBP+1 /DMC OUTPUT END PNTRS +16146 000047 C H2OTBP+1 +16147 C TIPDEF H3OTBP+1, TIPLNK+1 +02262 016147 C +02312 000055 C +02342 000771 C +16150 000031 C H4OTBP+1 +16151 017413 C IHBC +16152 017414 C IHBC+1 +16153 017415 C IHBC+2 +16154 017416 C IHBC+3 + LEV VAR + /IN IHSP: + /0 ==> NOTHING IS GOING OUT + /100000 ==> LEADER ONLY (2-WRD MSG) GOING + /2000-37777 ==> PACKET 1S GOING OUT + /102000-137777 ==> PACKET WITH BAD CKSUM IS GOING OUT +16155 V IHSP: BSS TH /SAVED BUFFER POINTERS +16165 V IHWQ: BSS TH /SAVED QUEUE POINTERS +16175 V IHLSTP: BSS TH /MINUS IF LAST PKT + DEFPLC [IH - 2 WORD OUTPUT AREA] +16205 V OWO: BSS [[NH+1]"T"2] /TWO WORD OUTPUT AREA + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 147 IMP,3050,IMP 7:20 PM 9/16/1973 + + LEV BCK LCK INI /INITIALIZATION ROUTINE +16217 000000 7 0 IHIN: 0 +16220 140040 7 0 CRA +16221 051155 7 0 STA IHSP X +16222 151135 7 0 STA IHB1 XI /FOR FAKE HOSTS +16223 011042 7 0 STA IHSB /IN CASE NON-DXA IMP RELOADS FROM 1 +16224 140500 7 0 SSM /BLOCK INPUT! +16225 111575 7 0 STA (HINWAT 0 X) I +16226 005576 7 0 LDA (IHBEG) +16227 021273 7 0 JST IHST +16230 103217 7 0 JMP IHIN I + + LEV I2H +16231 000000 3 IHS1: 0 /DISCARD BUFFERS FROM QUEUE +16232 014676 3 ADD IHP +16233 011303 3 STA IHT2 +16234 015577 3 ADD (NHS+0-SHQ) +16235 011304 3 STA IHT3 +16236 004676 3 LDA IHP +16237 012120 3 ERA SEVEN +16240 101040 3 SNZ /DISCARD? +16241 103231 3 JMP IHS1 I /YES, DO NOT DISCARD DISCARD +16242 105303 3 IHS1A: LDA IHT2 I +16243 101040 3 SNZ /ANYTHING ON THIS QUEUE? +16244 103231 3 JMP IHS1 I /NO, QUIT +16245 010000 3 STA 0 +16246 005305 3 LDA IHS1F /=0, FLUSH ALL, ELSE, FLUSH TIMEOL' +16247 101040 3 SNZ /DISCARD ALL? +16250 003261 3 JMP IHS1B /YES +16251 004416 3 LDA TIMES /GFT TIME IN SLOW TICKS +16252 056003 3 SUB INCH X /NO, CHECK TIME +16253 100400 3 SPL /TOO OLD? +16254 003267 3 JMP IHS1C /NO, SO SAVE TIME LEFT +16255 004676 3 LDA IHP +16256 016130 3 SUB PLNH +16257 101400 3 SMI /FAKE HOST? +16260 103231 3 JMP IHS1 I /YES, HAVE MERCY +16261 073303 3 IHS1B: LDX IHT2 +16262 121600 3 JST (GETQ) I +16263 103231 3 JMP IHS1 I /SHOULDNT HAPPEN +16264 121601 3 JST (IHS5) I +16265 125304 3 IRS IHT3 I +16266 003242 3 JMP IHS1A + +16267 023305 3 IHS1C: CAS IHS1F /PICK MIN TIME LEFT +16270 011305 3 STA IHS1F /FOR OLDEST PKT ON PRI OR REG QUEUE +16271 101000 3 NOP /IF NOTHING THERE, USE 30 SECS +16272 103231 3 JMP IHS1 I + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 148 IMP,3050,IMP 7:20 PM 9/16/1973 + + LEV T.O /RESTART ROUTINE +16273 000000 5 IHST: 0 /HERE AT INIT AND WHEN HOST READY DT +16274 051107 5 STA IHLO X /THROW AWAY ALL MESSAGES +16275 001001 5 INH SIN +16276 000013 5 0 EXA /BUT DO NOT FLAP IMP'S READY LINE +16277 021042 5 0 JST IHSB RET T.O +16300 001001 5 INH ALL +16301 120672 5 0 JST DODXA I RET T.O +16302 103273 5 JMP IHST I + + LEV VAR +16303 V IHT2: BSS 1 /TEMP +16304 V IHT3: BSS 1 /TEMP +16305 V IHS1F: BSS 1 /0=FLUSH ALL, ELSE=FLUSH TIMEOUTS + /ALSO KEEPS ALARM CLOCK TIME FOR [ 1 +16306 V IHTT: BSS TH /TIME OUT CHECK FLAGS + + LEV CON +16316 030570 C HENABT: H1ENAB +16317 030560 C H2ENAB +16320 030550 C H3ENAB +16321 030551 C H4ENAB + + LEV I2H +16322 000000 3 IHW640: 0 /SUBR TO WAIT 640 MS +16323 011324 3 STA .+1 /SET UP READY LINE OCP +16324 3 BSS 1 /DO IT +16325 004121 3 LDA MINUS1 /AND WAIT 640 MS FOR RELAY TO SETTL1 +16326 051306 3 STA IHTT X +16327 005322 3 LDA IHW640 +16330 003073 3 JMP IHDONE + +16331 004110 3 IHBEG: LDA PTICKS /A LITTLE MORE THAN TWICE PTICKS +16332 016120 3 SUB SEVEN +16333 041577 3 ALS 1 /WAIT FOR LINES TO COME UP AND ROUT +16334 051306 3 STA IHTT X +16335 005602 3 LDA (IHWAIT) +16336 003073 3 JMP IHDONE +16337 005603 3 IHWT1: LDA (NOP) +16340 021322 3 JST IHW640 + DEFPLC [IH - WAITING FOR INITIALIZATION DELAY] +16341 004172 3 IHWAIT: LDA RUT+BBNIMP +16342 100400 3 SPL 0"A"RUTDED /IS NCC UP YET? +16343 003347 3 JMP IHWT2 /NEVER COMING UP...GO AHEAD +16344 007604 3 ANA (RUTCMU) /COMING UP? +16345 100040 3 SZE +16346 003337 3 JMP IHWT1 /YES, WAIT SOME MORE +16347 004116 3 IHWT2: LDA THREE 0"A"HSTOFF /OK, START UP HOSTS +16350 003357 3 JMP IHR11 /HOLD DOWN RDY FOR 60 SECS AT INIT + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 149 IMP,3050,IMP 7:20 PM 9/16/1973 + +16351 004000 3 IHR2: LDA 0 /HERE TO FLUSH ALL/FLAP READY LINE +16352 016120 3 SUB SEVEN /DON'T FLUSH STUFF ON DISCARD QUEUE +16353 101040 3 SNZ +16354 103605 3 JMP (IH62) I +16355 111575 3 STA (HINWAT 0 X) I /DISCARD STUFF ON OTHER O1 +16356 004115 3 LDA TWO 0"A"HSTTRD +16357 050504 3 IHR11: STA HIHD X /MARK HOST AS TARDY (DEAD) +16360 121606 3 IHR1: JST (OWGE) I /HERE TO FLUSH ALL/NO READY LINE FL +16361 100000 3 SKP /THROW AWAY ALL 2 WORD MESSAGES +16362 003360 3 JMP IHR1 +16363 140040 3 CRA /FLUSH BUFFER CURRENTLY IN INTERFACI +16364 151145 3 STA IHB2 XI +16365 151135 3 STA IHB1 XI +16366 067155 3 IMA IHSP X +16367 140100 3 SSP /IF 0, NOTHING GOING +16370 101040 3 SNZ /IF SIGN BIT ONLY, TWO WORD GOING +16371 003400 3 JMP IS40 /IN EITHER CASE, NOTHING TO FLUSH +16372 024541 3 IRS NREA +16373 011305 3 STA IHS1F /SAVE PKT PNTR IN TEMP +16374 045175 3 LDA IHLSTP X /PICK UP LST PKT BIT +16375 073305 3 LDX IHS1F /GET PKT PNTR +16376 050007 3 STA HEAD2 X /AND RESTORE LST PKT BIT TO PKT +16377 121601 3 JST (IHS5) I +16400 140040 3 IS40: CRA /SET TO DISCARD ALL BUFFERS ON QU[ +16401 011305 3 STA IHS1F +16402 005607 3 LDA (SHQ) /GET REGULAR QUEUE +16403 021231 3 JST IHS1 +16404 005610 3 LDA (SHPQ) /GET PRIORITY QUEUE +16405 021231 3 JST IHS1 +16406 072676 3 LDX IHP +16407 004000 3 LDA 0 +16410 016130 3 SUB PLNH +16411 101400 3 SMI /FAKE HOST? +16412 003422 3 JMP IS30 /YES, DO NOT DROP READY LINE +16413 105575 3 LDA (HINWAT 0 X) I /WE BLOCKING INPUT? +16414 101040 3 SNZ +16415 003422 3 JMP IS30 /NO, DON'T DROP READY LINE +16416 105611 3 LDA (HUNXPT 0 X) I +16417 021322 3 JST IHW640 /WAIT FOR 640 MS + DEFPLC [IH - WAITING FOR READY LINE TO DROP] +16420 045316 3 LDA HENABT X +16421 021322 3 JST IHW640 /WAIT FOR 640 MS + DEFPLC [IH - WAITING FOR READY LINE TO GO UP] +16422 004123 3 IS30: LDA MINUS3 +16423 011303 3 STA IHT2 +16424 000401 3 IS10: ENB I2H +16425 005612 3 LDA (CNOP) +16426 001001 3 INH FRE +16427 120670 3 0 JST OWP I /PUT 3 NOPS ON HOST TWO WORD QUEUE +16430 101000 3 0 NOP +16431 025303 3 0 IRS IHT2 +16432 003424 3 0 JMP IS10 +16433 005613 3 0 LDA (CRESET) +16434 120670 3 0 JST OWP I /PUT AN IMP-TO-HOST RESET MESS ON ' +16435 101000 3 0 NOP +16436 000401 3 0 ENB I2H + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 150 IMP,3050,IMP 7:20 PM 9/16/1973 + +16437 140040 3 CRA /RELEASE INPUT +16440 111575 3 STA (HINWAT 0 X) I +16441 005603 3 IH00: LDA (NOP) +16442 021322 3 JST IHW640 RET I2H + DEFPLC [IH - NOTHING TO DO] +16443 004107 3 IH1: LDA M30SEC /SET TO DISCARD TIMED-OUT BUFFERS +16444 011305 3 STA IHS1F /AND SAVE TIME LEFT ON OLDEST +16445 005607 3 LDA (SHQ) +16446 021231 3 JST IHS1 /CHECK REG QUEUE FOR OLD MESS +16447 005610 3 LDA (SHPQ) +16450 021231 3 JST IHS1 /AND PRI QUEUE ALSO +16451 072676 3 LDX IHP +16452 121606 3 JST (OWGE) I /IS THERE ENTRY ON ONE WORD QUEUE +16453 003503 3 JMP IH2 /NO +16454 151130 3 STA OWOP XI /(OWO+2*IR) PUT WORD IN OUTPUT ARE +16455 045130 3 LDA OWOP X /GET POINTER TO FRONT OF AREA +16456 151135 3 STA IHB1 XI /BUILD FIRST BUFFER CONTROL WORD +16457 141206 3 DEFSTAT AOA,HS3 +00612 031113 3 +32006 016457 3 +32026 141206 3 +16460 151145 3 STA IHB2 XI /BUILD SECOND BUFFER CONTROL WORD +16461 051155 3 STA IHSP X +16462 004516 3 LDA TWDG +16463 151155 3 STA IHSP XI /PUT OUT SECOND WORD +16464 045124 3 LDA IHED X +16465 011071 3 STA IHDO /DO OUTPUT + END +16466 004112 3 LDA SIGN +16467 051155 3 STA IHSP X +16470 051175 3 STA IHLSTP X /SO SUCK AND TIP WILL WORK PROPER1 +16471 005305 3 LDA IHS1F /USE MIN TIME LEFT FOR PKTS ON QUEU +16472 051306 3 STA IHTT X /OR 30 SECS IF BOTH QUEUES EMPTY +16473 021060 3 JST IHDB + / WAITING FOR INTERRUPT AFTER OUTPUT OF 2 WORD MESSAGE + DEFPLC [IH - SENDING 2 WORD MSG] +16474 140040 3 CRA +16475 151135 3 STA IHB1 XI +16476 051155 3 STA IHSP X +16477 045306 3 LDA IHTT X +16500 101040 3 SNZ /DID HARDWARE INTERRUPT? +16501 003351 3 JMP IHR2 /NO, ALARM CLOCK WENT OFF- HOST TAR +16502 003443 3 JMP IH1 /YES, NORMAL OUTPUT COMPLETE + +16503 044302 3 IH2: LDA SHPQ X /IS THERE SOMETHING IN THE PRIORITY +16504 101040 3 SNZ +16505 003510 3 JMP .+3 /NO +16506 005610 3 LDA (SHPQ) +16507 003514 3 JMP IH19 +16510 044272 3 LDA SHQ X /IS THERE SOMETHING IN THE REGULAR +16511 101040 3 SNZ +16512 003441 3 JMP IH00 +16513 005607 3 LDA (SHQ) +16514 014000 3 IH19: ADD 0 +16515 051165 3 STA IHWQ X /SAVE POINTER TO QUEUE + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 151 IMP,3050,IMP 7:20 PM 9/16/1973 + +16516 004115 3 LDA TWO 0"A"[DATA-HEAD2] +16517 111614 3 STA (FPSW 0 X) I +16520 145165 3 IH21: LDA IHWQ XI +16521 051155 3 STA IHSP X /SAVE POINTER TO BUFFER +16522 045165 3 LDA IHWQ X +16523 010000 3 STA 0 +16524 144000 3 LDA 0 XI /UPDATE QUEUE START POINTER +16525 050000 3 STA 0 X +16526 101040 3 SNZ /IS THIS LAST ENTRY ON QUEUE +16527 133615 3 STX (EHQ-SHQ X) I /MAKE START PTR POINTED TT +16530 064251 3 IRS NHS-SHQ X +16531 072676 3 LDX IHP +16532 172700 3 LDX IHXX I +16533 005616 3 LDA (IHCKAD) +16534 026111 3 IMA ADDRET +16535 011123 3 STA IHAR +16536 004000 3 LDA 0 +16537 056111 3 SUB BUFE X +16540 015617 3 ADD (ADDBOT+ACKH) +16541 140100 3 SSP 0"A"TWOQ +16542 011545 3 STA IHCKAJ +16543 017620 3 SUB (ADDBOT) /-NO OF WORDS +16544 103545 3 JMP IHCKAJ I +16545 3 IHCKAJ: BSS 1 +16546 100040 3 IHCKAD: SZE +16547 003553 3 JMP IHBAD +16550 005123 3 LDA IHAR +16551 010111 3 STA ADDRET +16552 103621 3 JMP (IHNOCK) I + +16553 027123 3 IHBAD: IMA IHAR /TEMP FOR CKSUM ERROR +16554 010111 3 STA ADDRET /AND RESTORE OWNER +16555 004676 3 LDA IHP +16556 012120 3 ERA SEVEN + DEFPLC [NOP HERE TO TURN OFF I2H CHECKSUM CHECK] +16557 101040 3 SNZ +16560 103621 3 JMP (IHNOCK) I /DON'T REPORT DISCARD ERRORS +16561 005123 3 LDA IHAR +16562 001001 3 INH ALL + DEFHLT [HOST OUTPUT DETECTED INTRA-IMP CKSUM ERROR] +16563 021564 3 0 JST .+1 /NOW TRAP TO NCC +16564 000000 3 0 0 +16565 120745 3 0 JST HLTNCC I +16566 000401 3 0 ENB I2H +16567 072676 3 LDX IHP +16570 045155 3 LDA IHSP X +16571 140500 3 SSM /FLAG PACKET TO GO TO DIAGTT +16572 051155 3 STA IHSP X +16573 140100 3 SSP +16574 103622 3 JMP (IHNOC2) I /AND CONTINUE ANYWAY + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 152 IMP,3050,IMP 7:20 PM 9/16/1973 + +16575 053343 C LEV CON CONSTANTS +16576 016331 C +16577 000251 C +16600 015504 C +16601 017237 C +16602 016341 C +16603 101000 C +16604 000340 C +16605 017143 C +16606 017250 C +16607 000272 C +16610 000302 C +16611 041170 C +16612 002000 C +16613 005000 C +16614 057203 C +16615 040051 C +16616 016546 C +16617 001562 C +16620 001556 C +16621 017062 C +16622 017064 C +02425 175632 C PAGEND 16,UNCON,4 + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 153 IMP,3050,IMP 7:20 PM 9/16/1973 + + LEV CON +17056 030070 C IHOT: H1ROUT /REGULAR OUTPUT INSTRUCTIONS +17057 030060 C H2ROUT +17060 C TIPDEF H3ROUT, NOP +02263 017060 C +02313 030050 C +02343 101000 C +17061 030051 C H4ROUT + + LEV I2H /MORE IMP-TO-HOST CODE +17062 072676 3 IHNOCK: LDX IHP +17063 105424 3 LDA (IHSP 0 X) I +17064 015425 3 IHNOC2: ADD (DATA) +17065 057203 3 SUB FPSW X /BUILD FIRST BUFFER CONTROL WORD +17066 111426 3 STA (IHB1 0 XI) I +17067 172700 3 LDX IHXX I +17070 131040 3 RDCLOK +17071 003070 3 JMP .-1 +17072 050001 3 STA ST X +17073 140040 3 CRA +17074 050000 3 STA 0 X /CLEAR CHAIN PNTR +17075 044111 3 LDA BUFE X +17076 140100 3 SSP 0"A"TWOQ +17077 016114 3 SUB ONE /STRIP CHECKSUM/DUMMY WRD +17100 072676 3 LDX IHP +17101 111427 3 STA (IHB2 0 XI) I /MAKE SECOND BUFFER CONTR +17102 024565 3 IRS NRES /UPDATE REASSEMBLY COUNT +17103 172700 3 LDX IHXX I +17104 044007 3 LDA HEAD2 X /TURN OFF BITS FOR HOSTS +17105 007430 3 ANA (FRMIMP 0 FRMOCT SRCEHI) +17106 066007 3 IMA HEAD2 X 0"A"[LSTPKT 0 ENDBIT] +17107 072676 3 LDX IHP +17110 111431 3 STA (IHLSTP 0 X) I /SAVE LAST PKT FLAG +17111 100400 3 SPL 0"A"LSTPKT /IS THIS LAST PACKET OF M +17112 003115 3 JMP IH4 /YES +17113 045056 3 LDA IHOT X +17114 100000 3 SKP +17115 105432 3 IH4: DEFSTAT LDA (IHED 0 X) I, HS1 +00613 031076 3 +32007 017115 3 +32027 105432 3 +17116 111433 3 STA (IHDO) I /DO OUTPUT +17117 021127 3 JST IH6 +17120 105431 3 LDA (IHLSTP 0 X) I +17121 121434 3 JST (HTPPF) I /COUNT A PACKET OF THROUGHPUT +17122 105431 3 LDA (IHLSTP 0 X) I +17123 101400 3 SMI /DID WE JUST PUT OUT LAST PKT? +17124 103435 3 JMP (IH21) I /NO +17125 121436 3 JST (HTPMF) I /COUNT A MESSAGE OF THROUGHPUT +17126 103437 3 JMP (IH1) I /YES + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 154 IMP,3050,IMP 7:20 PM 9/16/1973 + + LEV I2H /MORE DF IMP-TO-HOST +17127 000000 3 IH6: 0 /SEND OUT A PKT +17130 172700 3 LDX IHXX I +17131 004416 3 LDA TIMES /GET TIME IN SLOW TICKS +17132 056003 3 SUB INCH X +17133 072676 3 LDX IHP +17134 111440 3 STA (IHTT 0 X) I +17135 100400 3 SPL +17136 003143 3 JMP IH62 /SOME TIME LEFT - GO USE IT +17137 004000 3 LDA 0 /RUN OUT - FAKE HOST? +17140 016130 3 SUB PLNH +17141 100400 3 SPL +17142 103441 3 JMP (IHR2) I /NO - HAVE NO MERCY +17143 121442 3 IH62: JST (IHDB) I + DEFPLC [IH - SENDING OUT A PKT] +17144 140040 3 CRA +17145 111426 3 STA (IHB1 0 XI) I +17146 105440 3 LDA (IHTT 0 X) I +17147 101040 3 SNZ /DID HARDWARE INTERRUPT? +17150 103441 3 JMP (IHR2) I /NO, ALARM CLOCK WENT OFF - HOST TA +17151 172700 3 LDX IHXX I /YES, NORMAL OUTPUT COMPLETE +17152 044002 3 LDA PTRT X +17153 001001 3 INH M2I +17154 100040 3 0 SZE /MUST WE TRACE HIM? +17155 121443 3 0 JST (TRCDUN) I /YES +17156 072676 3 0 LDX IHP /MUST FOLLOW TRCDUN CALL +17157 000401 3 0 ENB I2H +17160 140040 3 CRA +17161 067203 3 IMA FPSW X /RESET FIRST PKT SWITCH +17162 172700 3 LDX IHXX I +17163 100040 3 SZE /IS THIS THE FIRST PKT? +17164 003214 3 JMP IH63 /YES +17165 072676 3 IH6F: LDX IHP +17166 140040 3 CRA +17167 126700 3 IMA IHXX I /CLEAR OUT IHSP +17170 010000 3 STA 0 +17171 001001 3 INH FRE +17172 100400 3 0 SPL +17173 003177 3 0 JMP IH6B /WAS BAD PACKET. PUT ON DIAG Q +17174 120671 3 0 JST FLUSHI I /FLUSH PACKET +17175 072676 3 0 IH6F1: LDX IHP +17176 103127 3 0 JMP IH6 I + +17177 140100 3 0 IH6B: SSP +17200 026342 3 0 IMA DIAGQ /PUT ON DIAG Q +17201 050000 3 0 STA 0 X +17202 003175 3 0 JMP IH6F1 + + LEV VAR +17203 V FPSW: BSS TH /FIRST PACKET SWITCH +17213 V IH6INC: BSS 1 /MINUS IF RFNM IS FOR INC TRN + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 155 IMP,3050,IMP 7:20 PM 9/16/1973 + + LEV I2H +17214 044006 3 IH63: LDA HEAD1 X /THIS CODE IS FOR MULTI-PKT MESS FO: +17215 007444 3 ANA (PKTNO) /THAT WAS ON IH Q TOO LONG IN MID. ] +17216 100040 3 SZE /IS THIS FIRST PACKET? +17217 003165 3 JMP IH6F /NO, THE RFNM HAS BEEN SENT ALREADY +17220 044005 3 LDA HEAD X /NORMAL CASE, SEND BACK RFNM-ALLOC +17221 007445 3 ANA (INCTRN) +17222 100040 3 SZE +17223 004121 3 LDA MINUS1 +17224 011213 3 STA IH6INC +17225 044005 3 LDA HEAD X +17226 007446 3 ANA (MESSNO 0 ONEOR8) +17227 013447 3 ERA (RFNM) +17230 052007 3 ERA HEAD2 X +17231 007450 3 ANA (0 0 177777"X"SRCEI) +17232 052007 3 ERA HEAD2 X +17233 073213 3 LDX IH6INC /SET UP AS INCTRN OR NOT +17234 121451 3 JST (RALLYP) I /PUT IN RALLY TABLE +17235 101000 3 NOP /ENTRY ALREADY THERE - BAD +17236 003165 3 JMP IH6F + + + LEV I2H +17237 000000 3 IHS5: 0 +17240 044005 3 LDA HEAD X +17241 007452 3 ANA (0 0 177777"X"INCTRN) +17242 013445 3 ERA (INCTRN) +17243 050005 3 STA HEAD X +17244 132352 3 STX EHQ+NH+3 I +17245 032352 3 STX EHQ+NH+3 +17246 024526 3 IRS NHA+NH+3 +17247 103237 3 JMP IHS5 I + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 156 IMP,3050,IMP 7:20 PM 9/16/1973 + + /ROUTINE TO GET WORD OFF ONE WORD MESSAGE QUEUE TO HOST + /CALLING SEQUENCE + + /INDEX REGISTER CONTAINS HOST NUMBER + / JST OWG I + / + / + + LEV I2H +17250 000000 3 OWGE: 0 +17251 033337 3 STX OWGY +17252 044332 3 LDA SHWQ X /GET START OF HOST ONE WORD QUEUE +17253 100040 3 SZE +17254 003260 3 JMP OWGL /RETURN IF NOTHING ON QUEUE +17255 073337 3 OWGX: LDX OWGY +17256 005340 3 LDA OWGA /GET DATA IN AC +17257 103250 3 JMP OWGE I /RETURN +17260 011341 3 OWGL: STA OWGS /SAVE START OF QUEUE FOR LATER USE +17261 004000 3 LDA 0 +17262 022130 3 CAS PLNH /REAL HOST? +17263 003255 3 JMP OWGX /NO +17264 101000 3 NOP /TTY LIKE REAL HOST +17265 025250 3 IRS OWGE /PREPARE TO TAKE SECOND RETURN +17266 073341 3 LDX OWGS /PUT START OF QUEUE IN INDEX REGI[*1 +17267 044001 3 LDA 1 X +17270 011340 3 STA OWGA +17271 044002 3 LDA 2 X +17272 010516 3 STA TWDG +17273 044003 3 LDA 3 X /GET POINTER TO POINTER TO HEAD OF +17274 011342 3 STA OWGT /SAVE FOP LATER USE +17275 073337 3 LDX OWGY /GET HOST NUMBER +17276 144332 3 LDA SHWQ XI +17277 050332 3 STA SHWQ X /UPDATE QUEUE POINTER +17300 100040 3 SZE +17301 003305 3 JMP OWG1 +17302 005453 3 LDA (SHWQ) +17303 014000 3 ADD 0 +17304 050403 3 STA EHWQ X /IF QUEUE NOW EMPTY FIX THINGS + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 157 IMP,3050,IMP 7:20 PM 9/16/1973 + +17305 073342 3 OWG1: LDX OWGT /GET POINTER TO HEAD OF BUFFER +17306 044002 3 LDA 2 X /GET FREE STORAGE POINTER FOR THIS I +17307 111341 3 STA OWGS I +17310 005341 3 LDA OWGS /PUT THREE WORD BLOCK ON FREE STORA1 +17311 050002 3 STA 2 X +17312 044003 3 LDA 3 X /GET FREE BLOCK COUNT +17313 016114 3 SUB ONE +17314 050003 3 STA 3 X /UPDATE FREE BLOCK COUNT +17315 023454 3 CAS (-18.) /IS BUFFER EMPTY +17316 003255 3 JMP OWGX /IF NO, RETURN +17317 044001 3 LDA 1 X /IF YES, PUT IT ON FREE LIST +17320 054000 3 ADD 0 X +17321 017455 3 SUB (SHBQ) /CHECK FOR LAST BUFFER ON QUEUE +17322 101040 3 SNZ +17323 003255 3 JMP OWGX /IF YES, RETURN +17324 044000 3 LDA 0 X /TAKE BUFFER OUT OF USE FOR ONE WORI +17325 150001 3 STA 1 XI +17326 044001 3 LDA 1 X +17327 064000 3 IRS 0 X +17330 150000 3 STA 0 XI +17331 140040 3 CRA 0"A"TWOQ +17332 050111 3 STA BUFE X +17333 001001 3 INH FRE +17334 120671 3 0 JST FLUSHI I +17335 000401 3 0 ENB I2H +17336 003255 3 JMP OWGX + + LEV VAR +17337 V OWGY: BSS 1 +17340 V OWGA: BSS 1 +17341 V OWGS: BSS 1 +17342 V OWGT: BSS 1 + + LEV ALL + /CALLED BY VDI,T.O,TSK,PCK +17343 000000 0 .DODXA: 0 /DISABLE EXTENDED ADDRESSING +17344 000011 0 DXA /CALLED WITH INTERRUPTS LOCKED +17345 000401 0 ENB ALL /RETURNS WITH INTERRUPTS ENABLED +17346 103343 0 JMP .DODXA I + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 158 IMP,3050,IMP 7:20 PM 9/16/1973 + + /IMP TO FAKE HOST (SUCK) + /SIMULATE IMP-TO-HOST INTERFACE HARDWARE FOR FAKE HOSTS: + /1- IF THE DMC OUTPUT AND OUTPUT END POINTERS CROSS, + / GIVE OUTPUT COMPLETED INTERRUPT + /2- FETCH NEXT WORD THROUGH THE DMC OUTPUT POINTER + /3- INCREMENT THE DMC OUTPUT POINTER, AND IF THE POINTERS C'1 + / AND IF THIS IS A FINAL OUTPUT, SET THE LAST BIT INDICATOI + /4- SEND THE WORD TO THE HOST + /5- GO TO 1 + /IHBB SERVES AS THE DMC OUTPUT POINTER + /IHBC SERVES AS THE DMC OUTPUT END POINTER + /CALLING SEQUENCE + /FAKE HOST NUMBER IN X REG - 0=TTY,1=DDT.2=PARAM CHANGE,3=DI1 + /JST SUCK - GET NEXT WORD FROM IMP FOR THIS FAKE HOST + / - IMPLICIT BACKGROUND WAIT UNTIL WORD IS READY + /R1 - WORD IN A REG + /R2 - WORD IN A REG IS LAST WORD OF CURRENT MESSAGE + LEV BCK +17347 000000 7 SUC: 0 +17350 045407 7 SUC1: LDA IHBB X /IS THERE ANY OUTPUT TO GO? +17351 101040 7 SNZ +17352 003366 7 JMP SUC2 /NO, WAIT ONE BACKGROUND LOOP +17353 057413 7 SUB IHBC X +17354 022113 7 CAS ZERO /HAVE PNTRS CROSSED? +17355 003374 7 JMP SUC4 /YES +17356 003362 7 JMP SUC3 /ALMOST, THIS IS LAST WORD IN BUFFE1 +17357 145407 7 SUC5: LDA IHBB XI /FETCH NEXT WORD FROM OUTPUT PNTR +17360 065407 7 IRS IHBB X /INCREMENT OUTPUT PNTR +17361 103347 7 JMP SUC I /NOW RETURN WITH DATA + +17362 105456 7 SUC3: LDA (IHLSTP+NH X) I /YES +17363 100400 7 SPL 0"A"LSTPKT /IS THIS THE LAST PKT? +17364 025347 7 IRS SUC /YES, SO GIVE SKIP RETURN=LAST BIT +17365 003357 7 JMP SUC5 + +17366 005347 7 SUC2: LDA SUC +17367 051420 7 STA SUCT X /SAVE RETURN ADDRESS +17370 120667 7 JST WAIT I /COROUTINE RETURN TO BACKGROUND + DEFPLC [SUCK CALL TO WAIT] +17371 045420 7 LDA SUCT X +17372 011347 7 STA SUC /RESTORE RETURN ADDRESS +17373 003350 7 JMP SUC1 + +17374 033417 7 SUC4: STX SUCX /YES, SO INTERRUPT ON OUTPUT COMPLE +17375 004000 7 LDA 0 +17376 014130 7 ADD PLNH +17377 010000 7 STA 0 /SET UP X REG FOR THIS FAKE HOST +17400 001001 7 INH SIN /SOFTWARE INTERRUPT IMP-TO-HOST +17401 000013 7 0 EXA +17402 121457 7 0 JST (IHSB) I RET BCK +17403 001001 7 INH ALL +17404 120672 7 0 JST DODXA I RET BCK +17405 073417 7 LDX SUCX +17406 003350 7 JMP SUC1 /NOW GO BACK FOR MORE OUTPUT + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 159 IMP,3050,IMP 7:20 PM 9/16/1973 + + LEV VAR +17407 V IHBB: BSS FH /DMC OUTPUT PNTRS FOR FAKE HOSTS +17413 V IHBC: BSS FH /DMC OUTPUT END PNTRS FOR FAKE HOE : +17417 V SUCX: BSS 1 + DEFPLC [SUCT] +17420 V SUCT: BSS FH /TABLE OF RETURN ADDRESSES + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 160 IMP,3050,IMP 7:20 PM 9/16/1973 + +17424 056155 C LEV CON CONSTANTS +17425 000011 C +17426 156135 C +17427 156145 C +17430 050377 C +17431 056175 C +17432 056124 C +17433 016071 C +17434 022462 C +17435 016520 C +17436 022451 C +17437 016443 C +17440 056306 C +17441 016351 C +17442 016060 C +17443 011144 C +17444 003400 C +17445 000010 C +17446 177600 C +17447 000100 C +17450 177700 C +17451 015303 C +17452 177767 C +17453 000332 C +17454 177756 C +17455 000337 C +17456 056201 C +17457 016042 C +02426 174464 C PAGEND 17,UNCON,4 + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 161 IMP,3050,IMP 7:20 PM 9/16/1973 + + + TO: LEV T.O +00102 020022 5 CLOKIL/ TO +20022 000000 5 0 TO/ INT T.O /TIMEOUT INTERRUPT ENTRANCE +20023 000011 5 0 DXA +20024 003025 5 0 JMP . 1 +20025 033145 5 0 STX TOT +20026 025143 5 0 IRS TOSLOW /IS THIS REALLY A SLOW TICK? +20027 003034 5 0 JMP TO1 /NO +20030 073574 5 0 LDX (-25.) /YES, RESET CLOCK +20031 033143 5 0 STX TOSLOW /EVERY 25TH TICK +20032 072114 5 0 LDX ONE +20033 100000 5 0 SKP +20034 072113 5 0 TO1: LDX ZERO /CHOOSE APPROPRIATE X +20035 051146 5 0 STA TOA X /SAVE AC +20036 045160 5 0 LDA TOM X +20037 170120 5 0 SMK INTM +20040 026134 5 0 IMA PRIM +20041 051156 5 0 STA TOMK X +20042 000043 5 0 INK +20043 051150 5 0 STA TOCK X +20044 005145 5 0 LDA TOT +20045 051152 5 0 STA TOX X +20046 005022 5 0 LDA TO /SAVE RETURN +20047 051154 5 0 STA TOC X +20050 024415 5 0 IRS TIME /COUNT LOCAL TIME +20051 101000 5 0 NOP +20052 024417 5 0 IRS SYNC /COUNT GLOBAL TIME +20053 101000 5 0 NOP +20054 030026 5 0 WDT /** TAKE THIS AWAY WHEN ALGORITHM ' +20055 143162 5 0 JMP TOS XI + + LEV T.O +20056 001001 5 TOR: INH MSK +20057 045154 5 0 LDA TOC X +20060 011022 5 0 STA TO +20061 045152 5 0 LDA TOX X +20062 011145 5 0 STA TOT +20063 045156 5 0 LDA TOMK X +20064 170120 5 0 SMK INTM +20065 010134 5 0 STA PRIM +20066 000013 5 0 EXA +20067 045150 5 0 LDA TOCK X +20070 171020 5 0 OTK +20071 045146 5 0 LDA TOA X +20072 073145 5 0 LDX TOT +20073 000401 5 0 ENB T.O +20074 103022 5 JMP TO I + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 162 IMP,3050,IMP 7:20 PM 9/16/1973 + + LEV BCK LCK INI +20075 000000 7 0 TOI: 0 /TIMEOUT INITIALIZATION +20076 004127 7 0 LDA MICH +20077 010141 7 0 STA HTPAR +20100 072113 7 0 LDX ZERO +20101 140040 7 0 TOIL: CRA +20102 111575 7 0 STA (E123 0 X) I /CLEAR LINE ERROR +20103 004115 7 0 LDA TWO +20104 051300 7 0 STA RMBIT X /TIMER BIT FOR VAR FRQ RM'S +20105 005576 7 0 LDA (1000 SHD RMINIT) /101006, 50 KB LINE FULL 1 +20106 111577 7 0 STA (RMFLG 0 X) I /AND INIT FLAG IN EACH RM] +20107 005600 7 0 LDA (RMCLKS+2) /POINT ALL LINES AT 50KB TIME +20110 111601 7 0 STA (RMCLKP 0 X) I +20111 004110 7 0 LDA PTICKS +20112 111602 7 0 STA (LINDT 0 X) I +20113 004121 7 0 LDA MINUS1 +20114 051452 7 0 STA LTR X +20115 021354 7 0 TOIL2: JST DEDL /SET SLT MINUS, KILL LINE +20116 024000 7 0 IRS 0 +20117 024141 7 0 IRS HTPAR /ENDS UF BY SETTING HTPAR TO 0 +20120 003101 7 0 JMP TOIL +20121 004121 7 0 LDA MINUS1 +20122 011143 7 0 STA TOSLOW /START WITH SLOW TICK +20123 010142 7 0 STA HLNM /CLEAR HOST INTERFACE TEST +20124 111603 7 0 STA (HLNMS) I +20125 111604 7 0 STA (RTSSNT) I +20126 011210 7 0 STA TALLYC /DO THIS OR BACK2 WONT WORK RIGHT +20127 111605 7 0 STA (RALTRY) I +20130 111606 7 0 STA (GODWNC) I +20131 111607 7 0 STA (COMUPC) I +20132 111610 7 0 STA (MESST) I + /THIS CODE IS TO START ALL LINES W/ROUTING MSG SYNC-ED W/SLO +20133 011277 7 0 STA RMCLKS+NSPD-1 +20134 004122 7 0 LDA MINUS2 +20135 073611 7 0 LDX (-NSPD+1) +20136 051277 7 0 TOIL1: STA RMCLKS+NSPD-1 X +20137 024000 7 0 IRS 0 +20140 003136 7 0 JMP TOIL1 +20141 030040 7 0 CLKON +20142 103075 7 0 JMP TOI I + + LEV VAR +20143 V TOSLOW: BSS 1 +20144 V TOK: BSS 1 +20145 V TOT: BSS 1 +20146 V TOA: BSS 2 +20150 V TOCK: BSS 2 +20152 V TOX: BSS 2 +20154 V TOC: BSS 2 +20156 V TOMK: BSS 2 + LEV CON +20160 177774 C TOM: -4 /LOCK OUT T.O IN JOBF +20161 177774 C -4 /ENB T.O IN JOBS **TEMP NOT** +20162 020170 C TOS: JOBF +20163 021075 C JOBS + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 163 IMP,3050,IMP 7:20 PM 9/16/1973 + + LEV T.O +20164 005160 5 JOBF1: LDA TOM /DONE WITH SLOW TICK +20165 170120 5 SMK INTM +20166 010134 5 STA PRIM /LOCK OUT T.O +20167 072114 5 LDX ONE /REMEMBER IT IS A SLOW TICK + /FAST TIMEOUT JOBS - RESTART EVERYBODY +20170 033144 5 JOBF: STX TOK /SAVE TYPE OF TICK +20171 021211 5 JST RSTOUT /MUST PRECEDE IMTC +20172 021305 5 JST IMTC RET T.O /ATTEMPT TO RESTART MODEI +20173 021327 5 JST HITC /ATTEMPT TO RESTART HOST INS +20174 121612 5 JST (SWCH) I /MONITOR THINGS +20175 021200 5 JST TALLYB /TIME OUT OLDEST ALLOCATE WE HAVE +20176 073144 5 LDX TOK +20177 003056 5 JMP TOR + +20200 000000 5 TALLYB: 0 /BUMP TALLY CLOCK EVERY 25 MS +20201 005613 5 LDA (TALLY) +20202 113614 5 ERA (TALLYI) I +20203 101040 5 SNZ /IS THE TALLY TABLE EMPTY? +20204 011210 5 STA TALLYC /YES, HOLD TALLYC AT 1 WHILE QUIESC +20205 025210 5 IRS TALLYC /BUMP TALLY CLOCK +20206 101000 5 NOP /IN CASE BACK ISNT GOING +20207 103200 5 JMP TALLYB I + + LEV VAR +20210 V TALLYC: BSS 1 /TALLY CLOCK - COUNTS FROM 0 TO 5 + + LEV T.O +20211 000000 5 RSTOUT: 0 +20212 025274 5 IRS RMCLKS /CHECK TO SEND ROUTING MSGS +20213 100000 5 SKP /...RUN CLKS FOR EACH POSS LINE SPD +20214 003255 5 JMP RSTR50 /2 SLOW TICKS +20215 025275 5 IRS RMCLKS+1 +20216 100000 5 SKP +20217 003257 5 JMP RSTR25 /RESET (1 SLOW TICK) +20220 025276 5 IRS RMCLKS+2 +20221 100000 5 SKP +20222 003261 5 JMP RSTR5 /5 FAST TICKS [RMCLKS+3 IS FAST T.O + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 164 IMP,3050,IMP 7:20 PM 9/16/1973 + +20223 072127 5 RSTR0: LDX MICH +20224 004121 5 LDA MINUS1 +20225 123615 5 RSTO2: CAS (RMCLKP+CH XI) I /TIME UP TEST +20226 100000 5 SKP +20227 003233 5 JMP RSTO4 /YES, DO ROUTING CHECK +20230 024000 5 RSTO3: IRS 0 /NO, GO TO NEXT LINE +20231 003225 5 JMP RSTO2 +20232 103211 5 JMP RSTOUT I /DONE + +20233 045305 5 RSTO4: LDA RMBIT+CH X /ADVANCE BIT POINTER +20234 040677 5 ARR 1 +20235 100400 5 SPL /TIME TO WRAP? +20236 005616 5 LDA (20) /YES, RESET TO 5TH BIT +20237 051305 5 STA RMBIT+CH X +20240 107617 5 ANA (RUTFRQ+CH XI) I /GET RIGHT BIT OUT OF RI 1 +20241 101040 5 SNZ /TIME TO SEND ROUTING? +20242 003253 5 JMP RSTO5 /NO, GO TO NEXT LINE +20243 100100 5 SLZ +20244 003264 5 JMP RSTDL +20245 001001 5 RSTO6: INH I2M /SEND ROUTING +20246 044272 5 2 LDA SLT+CH X +20247 101040 5 2 SNZ /NO ROUTING IF HELD DEAD OR BUSY +20250 004115 5 2 LDA TWO /ALWAYS SEND NULL W/ROUTING +20251 050272 5 2 STA SLT+CH X +20252 000401 5 2 ENB T.O +20253 004121 5 RSTO5: LDA MINUS1 /ON TO NEXT LINE +20254 003230 5 JMP RSTO3 + + +20255 005620 5 RSTR50: LDA (-50.) +20256 011274 5 STA RMCLKS +20257 005574 5 RSTR25: LDA (-25.) +20260 011275 5 STA RMCLKS+1 +20261 004125 5 RSTR5: LDA MINUS5 +20262 011276 5 STA RMCLKS+2 +20263 003223 5 JMP RSTR0 + +20264 033273 5 RSTDL: STX RSTDT /SAVE X +20265 004000 5 LDA 0 +20266 016127 5 SUB MICH /CONVERT NEG X TO POS X +20267 010000 5 STA 0 +20270 021354 5 JST DEDL /CALL DEDL FOR HELLO-IHY AT BASIC * +20271 073273 5 LDX RSTDT /RESTORE X +20272 003245 5 JMP RSTO6 + + LEV VAR +20273 V RSTDT: BSS 1 /TEMP X +20274 V RMCLKS: BSS NSPD /1 CLOCK/SPD +20300 V RMBIT: BSS CH /5 BIT ROTATE BIT 1/LINE + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 165 IMP,3050,IMP 7:20 PM 9/16/1973 + + LEV T.O +20305 000000 5 IMTC: 0 /WAKE UP IDLE MODEMS +20306 072113 5 LDX ZERO +20307 004127 5 LDA MICH /DO FOR ALL MODEMS +20310 011353 5 STA IMTK +20311 001001 5 IMTCL: INH SIN +20312 044440 5 0 LDA NONE X /CHECK STATUS OF MODEM +20313 100040 5 0 SZE /WAITING FOR HARDWARE INTERRUPT? +20314 003324 5 0 JMP I2MTC2 +20315 121621 5 0 I2MTC0: JST (I2MSB) I RET T.O /NO, SO GIVE SOFTWARE INT] +20316 001001 5 INH ALL +20317 120672 5 0 JST DODXA I RET T.O +20320 024000 5 I2MTC1: IRS 0 +20321 025353 5 IRS IMTK +20322 003311 5 JMP IMTCL +20323 103305 5 JMP IMTC I + + LEV T.O LCK SIN +20324 064440 5 0 I2MTC2: IRS NONE X +20325 003320 5 0 JMP I2MTC1 +20326 003315 5 0 JMP I2MTC0 + + LEV T.O +20327 000000 5 HITC: 0 /TIMEOUT CHECK ROUTINE +20330 004131 5 LDA MITH +20331 011352 5 STA HITK /ATTEMPT TO WAKE UP ALL HOST-TO-IMP +20332 005352 5 HITZ: LDA HITK +20333 012415 5 ERA TIME /USE A RANDOM WAKEUP ORDER +20334 006120 5 ANA SEVEN /TO FACILITATE RESOURCE SHARING +20335 010000 5 STA 0 +20336 001001 5 INH [SIN,H2I,TPC] +20337 105622 5 0 LDA (HITT 0 X) I +20340 100040 5 0 SZE /IS THIS HOST WAITING TO WAKE UP? +20341 125622 5 0 IRS (HITT 0 X) I /YES, TIME TO WAKE HIM YF +20342 003346 5 0 JMP HITZL /NO +20343 000013 5 0 EXA /YES. SOFTWARE INTERRUPT HOST-TO-I' +20344 121623 5 0 JST (HISB) I RET T.O +20345 001001 5 INH ALL +20346 120672 5 0 HITZL: JST DODXA I RET T.O +20347 025352 5 IRS HITK +20350 003332 5 JMP HITZ +20351 103327 5 JMP HITC I + + LEV VAR +20352 V HITK: BSS 1 +20353 V IMTK: BSS 1 /TEMP COUNTER + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 166 IMP,3050,IMP 7:20 PM 9/16/1973 + + LEV T.O +20354 000000 5 DEDL: 0 /INVESTIGATE FOR LINE STATUS +20355 044265 5 LDA SLT X +20356 100400 5 SPL /IS THIS LINE IN DEAD STATE? +20357 003445 5 JMP HEL4 /YES, GO NO FURTHER +20360 140040 5 CRA +20361 127575 5 IMA (E123 0 X) I +20362 101040 5 SNZ /DID WE GET ANY ROUTING MSGS? +20363 003367 5 JMP DED1 /NO +20364 064421 5 IRS SIHY X /YES, COUNT ONE AS AN HELLO +20365 065457 5 IRS RTRCVD X /AND RETURN AN I-HEARD-YOU +20366 101000 5 NOP +20367 125624 5 DED1: IRS (RTSSNT 0 X) I /COUNT HELLO SENT +20370 101000 5 NOP +20371 044426 5 LDA LAC X /CHECK LINE ALIVE COUNT +20372 101040 5 SNZ /DID WE GET AN I-HEARD-YOU? +20373 003416 5 JMP NOC /NO INPUT ON THIS CHANNEL +20374 016114 5 SUB ONE /YES, CAN ONLY GET ONE (TWO IN CAI' +20375 100040 5 SZE /PER BASIC INTERVAL +20376 004114 5 LDA ONE +20377 050426 5 STA LAC X +20400 044433 5 LDA LINE X +20401 101040 5 SNZ +20402 003414 5 JMP DED3 /LINE WAS ALREADY ALIVE +20403 065452 5 IRS LTR X +20404 103354 5 JMP DEDL I /NOT TIME TO BRING LINE UP YET +20405 140040 5 CRA +20406 050433 5 STA LINE X +20407 044160 5 LDA NEIGHB X /FOR DETECTING PACKETS ON LOOPED LI +20410 016106 5 SUB MINE +20411 006112 5 ANA SIGN /1=I AM THE HIGHER NUMBER IMP +20412 040672 5 ARR 6 0"A"ENDBIT +20413 111625 5 STA (LEND 0 X) I /SAVE FOR USE IN PACKET +20414 004125 5 DED3: LDA MINUS5 +20415 003431 5 JMP HEL1 + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 167 IMP,3050,IMP 7:20 PM 9/16/1973 + +20416 044433 5 NOC: LDA LINE X +20417 100040 5 SZE /WAS LINE ALIVE? +20420 003433 5 JMP DED4 /LINE STILL IS DEAD +20421 065452 5 IRS LTR X /CURRENTLY UP, SHOULD IT BE? +20422 003440 5 JMP HEL3 /NOT TIME TO KILL LINE YET +20423 001001 5 INH M2I +20424 121626 5 0 JST (KILLIN) I +20425 000401 5 0 ENB T.O +20426 105602 5 HELD: LDA (LINDT 0 X) I +20427 111625 5 STA (LEND 0 X) I /MARK LINE DOWN +20430 050433 5 HEL0: STA LINE X +20431 051452 5 HEL1: STA LTR X +20432 103354 5 JMP DEDL I + +20433 045452 5 DED4: LDA LTR X /LINE IS DEAD +20434 123602 5 CAS (LINDT 0 X) I /IS IT AT MAX DEAD COUNT? +20435 016114 5 SUB ONE /NOT YET. COUNT DOWN +20436 003430 5 JMP HEL0 /AND RETURN +20437 003426 5 JMP HELD /PAST MAX!? RESET + +20440 045452 5 HEL3: LDA LTR X /LINE IS DYING +20441 022123 5 CAS MINUS3 /IS IT TIME TO GIVE FAKE ROUTING? +20442 100000 5 SKP /NO +20443 121627 5 JST (RSTINP) I /YES,CALL ROUTING INPUT W/ DUMMY F +20444 103354 5 JMP DEDL I + +20445 023630 5 HEL4: CAS (-KILTIM+1) /LINE HAS BEEN KILLED +20446 100000 5 SKP /IS IT TIME TO GIVE FAKE ROUTING? +20447 121627 5 JST (RSTINP) I /YES, CALL ROUT INPUT W/ DUMMY MSG +20450 021464 5 JST JSRT +20451 003426 5 JMP HELD + + LEV VAR +20452 V LTR: BSS CH +20457 V RTRCVD: BSS CH /COUNT OF HELLO'S RCVD + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 168 IMP,3050,IMP 7:20 PM 9/16/1973 + + LEV T.O +20464 000000 5 JSRT: 0 +20465 004112 5 LDA SIGN /TURN OFF I2MTC CLOCK WAKEUP +20466 050440 5 STA NONE X /FOR DEAD OR NON-EXISTENT LINES +20467 004000 5 LDA 0 +20470 014127 5 ADD MICH +20471 023544 5 CAS VDHNO +20472 100000 5 SKP /IS THIS MODEM STOLEN BY VDH? +20473 103464 5 JMP JSRT I /YES +20474 023545 5 CAS MODNO +20475 103464 5 JMP JSRT I /IS THIS MODEM STOLEN BY HOST? +20476 103464 5 JMP JSRT I +20477 115631 5 ADD (SATNO) I +20500 101040 5 SNZ +20501 103543 5 JMP SATGCI I +20502 064265 5 IRS SLT X /YES, TIME TO START BRINGING IT UP? +20503 103464 5 JMP JSRT I /NO +20504 001001 5 INH I2M +20505 033546 5 2 STX SENR +20506 005632 5 2 JSRT2: LDA (SMPQ) +20507 021547 5 2 JSRT3: JST JSRTS +20510 005633 5 2 JSRT4: LDA (SMQ) +20511 021547 5 2 JST JSRTS +20512 073546 5 2 LDX SENR +20513 005634 5 2 LDA (ACKTAB) +20514 050646 5 2 STA RSEX X +20515 050653 5 2 STA CHFREE X +20516 044622 5 2 LDA I2MTAB X +20517 111635 5 2 STA (I2MLST 0 X) I +20520 050627 5 2 STA I2MEND X +20521 005636 5 2 LDA (-NACH) +20522 050634 5 2 STA I2MNXT X +20523 140040 5 2 NACKL: CRA +20524 050641 5 2 STA TSEX X /ZERO THIS - LOOP UNNECESSARY +20525 050440 5 2 STA NONE X /ZERO THIS - LOOP UNNECESSARY +20526 166627 5 2 IMA I2MEND XI +20527 010000 5 2 STA 0 +20530 023637 5 2 CAS (1777) +20531 021557 5 2 JST RQSUB +20532 101000 5 2 NOP /NOTHING THERE OR JUST A DUMMY +20533 073546 5 2 LDX SENR +20534 064627 5 2 IRS I2MEND X +20535 064634 5 2 IRS I2MNXT X +20536 003523 5 2 JMP NACKL +20537 005640 5 2 LDA (JMP+0+1000+M2I0"A"777) +20540 111641 5 2 STA (M2IOK 0 XI) I +20541 000401 5 2 ENB T.O +20542 103464 5 JMP JSRT I + + LEV VAR +20543 V SATGCI: SATDEF [0 0 JSRT I] +02264 020543 V +02314 120464 V +02344 120464 V +20544 V VDHNO: BSS 1 /0 FOR NO VDH, ELSE M.N-5 +20545 V MODNO: BSS 1 /0=5 MODS, -1=4 MODS, -2=3 MODS +20546 V SENR: BSS 1 + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 169 IMP,3050,IMP 7:20 PM 9/16/1973 + + LEV T.O LCK I2M +20547 000000 5 2 JSRTS: 0 +20550 015546 5 2 ADD SENR +20551 011573 5 2 STA JSRTQ +20552 073573 5 2 JSRTS1: LDX JSRTQ +20553 121642 5 2 JST (GETQ) I +20554 103547 5 2 JMP JSRTS I +20555 021557 5 2 JST RQSUB +20556 003552 5 2 JMP JSRTS1 + +20557 000000 5 2 RQSUB: 0 +20560 132402 5 2 STX ERQ I +20561 032402 5 2 STX ERQ +20562 024564 5 2 IRS NSFS /TASK WILL FLUSH IF DEST WENT DEAD +20563 044002 5 2 LDA PTRT X +20564 101040 5 2 SNZ +20565 103557 5 2 JMP RQSUB I +20566 010000 5 2 STA 0 +20567 005643 5 2 LDA (140000) +20570 052012 5 2 ERA TDONE X +20571 050012 5 2 STA TDONE X +20572 103557 5 2 JMP RQSUB I + LEV VAR +20573 V JSRTQ: BSS 1 + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 170 IMP,3050,IMP 7:20 PM 9/16/1973 + +20574 177747 C LEV CON CONSTANTS +20575 045565 C +20576 101006 C +20577 052620 C +20600 020276 C +20601 051353 C +20602 051361 C +20603 022273 C +20604 022303 C +20605 004601 C +20606 027263 C +20607 027264 C +20610 021561 C +20611 177775 C +20612 022320 C +20613 032261 C +20614 015155 C +20615 151360 C +20616 000020 C +20617 167274 C +20620 177716 C +20621 012604 C +20622 053137 C +20623 013106 C +20624 062303 C +20625 050254 C +20626 011133 C +20627 026120 C +20630 177767 C +20631 005153 C +20632 000317 C +20633 000312 C +20634 000377 C +20635 052660 C +20636 177770 C +20637 001777 C +20640 003231 C +20641 150247 C +20642 015504 C +20643 140000 C +02427 175651 C PAGEND 20,UNCON,4 + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 171 IMP,3050,IMP 7:20 PM 9/16/1973 + + LEV T.O LCK ALL + /SLOW TIMEOUT JOBS +21075 021460 5 0 JOBS: JST IHTC RET T.O /ATTEMPT TO RESTART HOST T +21076 021362 5 JST DEDH /ESTABLISH HOST UP/DOWN STATUS +21077 021432 5 JST JED /COMPUTE EFFECTIVE DELAY +21100 121672 5 JST (RUTCLK) I + /THESE FIRST FOUR SHOULD PRECEDE THE ROUTING COMPUTATION +21101 121673 5 JST (RUTOUT) I /COMPUTE ROUTING +21102 021564 5 JST HTEST /OCP INTERFACES IF NECESSARY +21103 021640 5 JST HPOKE /TEST HOST INTERFACE +21104 021134 5 JST DEDI /DEAD IMP CLEANUP - AFTER ROUTING C +21105 021500 5 JST JUQC /ADJUST QUEUE COUNTERS +21106 000401 5 ENB T.O +21107 021526 5 JST MESSTO /TIMEOUT INCOMPLETE MESSAGE NUMBERS +21110 073674 5 LDX (0 0 -ADDBOT-1+ADDTOP) /CHECK ADD CH: +21111 005675 5 LDA (ADD BUFE+4 X) /BASIC INSTRUCTION +21112 123676 5 ADDCH1: CAS (ADDBOT+1 X) I +21113 100000 5 SKP /BAD +21114 100000 5 SKP /GOOD + RELOAD [ADD CHAIN BROKEN] +21115 120061 5 JST SWDTIL I /BAD, GO RELOAD +21116 016114 5 SUB ONE /MODIFY INSTR IN A +21117 024000 5 IRS 0 +21120 003112 5 JMP ADDCH1 +21121 005677 5 LDA (JMP ADDRET I) /CHECK RETURN INSTR +21122 113676 5 ERA (ADDBOT+1 X) I +21123 100040 5 SZE + RELOAD [ADD CHAIN RETURN BROKEN] +21124 120061 5 JST SWDTIL I /BAD, GO RELOAD +21125 010452 5 STA LUUP /BLINK LOOPED LIGHT +21126 101000 5 VDH3: NOP /VDH TIMEOUT CALL +21127 001001 5 INH ALL +21130 024416 5 0 IRS TIMES /COUNT TIME IN SLOW TICKS +21131 024503 5 0 IRS WDTIME /CHECK SOFTWARE W.D.T. +21132 103700 5 0 JMP (JOBF1) I /NOW DO FAST STUFF. + RELOAD [SOFTWARE WDT FIRED] +21133 120061 5 0 JST SWDTIL I + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 172 IMP,3050,IMP 7:20 PM 9/16/1973 + + LEV T.O +21134 000000 5 DEDI: 0 /TIMEOUT COMES HERE TO CLEAN UP +21135 005701 5 LDA (TMESS) +21136 011356 5 STA DMSTAB +21137 072113 5 LDX ZERO +21140 033355 5 IMPD: STX DEDIMP /NO OF IMP WHICH DIED +21141 044165 5 LDA RUT X +21142 101400 5 SMI 0"A"RUTDED /IS THIS IMP DEAD? +21143 003274 5 JMP IMPD7 /NO, GO ON TO NEXT ONE +21144 073356 5 LDX DMSTAB /FIRST CLEAN UP TRANSMIT SIDE +21145 001001 5 INH ALL +21146 044000 5 0 LDA 0 X +21147 007702 5 0 ANA (MESBTS) +21150 013702 5 0 ERA (MESBTS) +21151 101040 5 0 SNZ /ARE THERE ANY OUTSTANDING MESSAGE +21152 003232 5 0 JMP IMPD2A /NO, GO ON TO CLEAN UP OTHER THINGS +21153 004124 5 0 LDA MINUS4 +21154 011357 5 0 STA DEDTRY /LOOK AT 4 POSSIBLE MESS FOR DEAD 1 +21155 044000 5 0 LDA 0 X +21156 017703 5 0 SUB (0 0 3"T"400) 0"A"MESSNO +21157 050000 5 0 STA 0 X /ROLL BACK 4 MESS NOS +21160 100100 5 0 IMPD0: SLZ /IS THIS MESS NO WAITING FOR REPLY? +21161 003226 5 0 JMP IMPD2 /NO +21162 141044 5 0 CAR 0"A"MESSNO /YES, SO LOOK FOR IT +21163 013355 5 0 ERA DEDIMP +21164 121704 5 0 JST (PPTGET) I +21165 003203 5 0 JMP IMPD1 /NOT IN PPT +21166 010000 5 0 STA 0 /GOT IT IN PPT +21167 140040 5 0 CRA +21170 066000 5 0 IMA PPT0 X +21171 140100 5 0 SSP 0"A"RETRAN +21172 010000 5 0 STA 0 +21173 120671 5 0 JST FLUSHI I /IF ON 2 QUEUES, RQSUB WILL FLUSH +21174 044010 5 0 LDA HEAD3 X +21175 141044 5 0 CAR 0"A"CIMPD +21176 010515 5 0 STA TWDP +21177 044007 5 0 LDA HEAD2 X +21200 121705 5 0 JST (HOSTNO) I +21201 044006 5 0 LDA HEAD1 X +21202 003221 5 0 JMP IMPDP +21203 105356 5 0 IMPD1: LDA DMSTAB I +21204 141044 5 0 CAR 0"A"MESSNO +21205 013355 5 0 ERA DEDIMP +21206 121706 5 0 JST (PLTGET) I +21207 003226 5 0 JMP IMPD2 /MUST HAVE BEEN A GIVE BACK +21210 010000 5 0 STA 0 +21211 140040 5 0 CRA +21212 066000 5 0 IMA PLT0 X /CLEAR PLT ENTRY +21213 006120 5 0 ANA SEVEN +21214 011361 5 0 STA IMPDLH +21215 044030 5 0 LDA PLT2 X +21216 141044 5 0 CAR 0"A"CIMPD +21217 010515 5 0 STA TWDP +21220 044014 5 0 LDA PLT1 X + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 173 IMP,3050,IMP 7:20 PM 9/16/1973 + +21221 007707 5 0 IMPDP: ANA (0 0 177777"X"LSTPKT"X"HICODE) +21222 013710 5 0 ERA (CDESTD) /RETURN A DEST IMP DEAD +21223 073361 5 0 LDX IMPDLH +21224 120670 5 0 JST OWP I +21225 101000 5 0 NOP +21226 073356 5 0 IMPD2: LDX DMSTAB +21227 121711 5 0 JST (UPMESS) I +21230 025357 5 0 IRS DEDTRY +21231 003160 5 0 JMP IMPD0 +21232 005355 5 0 IMPD2A: LDA DEDIMP +21233 121712 5 0 JST (TALLYG) I /FLUSH ALL ALLOCATES FROM HIM +21234 100000 5 0 SKP +21235 003232 5 0 JMP IMPD2A +21236 073713 5 0 LDX (SHRQ) /NOW CLEAN UP RECEIVE SIDE +21237 044000 5 0 IMPD3: LDA 0 X /GET ALL REAS BLOCKS BACK +21240 101040 5 0 SNZ +21241 003244 5 0 JMP IMPD3A +21242 021303 5 0 JST DREAS +21243 003237 5 0 JMP IMPD3 +21244 073714 5 0 IMPD3A: LDX (MESSTK) /GET ALL MESSTK ENTRIES BACK +21245 044000 5 0 IMPD4: LDA 0 X +21246 101040 5 0 SNZ +21247 003271 5 0 JMP IMPD6 /END OF MESSTK +21250 100400 5 0 SPL /REAS BLOCK? +21251 003267 5 0 JMP IMPD5 /YES +21252 033360 5 0 STX DTEND +21253 010000 5 0 STA 0 +21254 044007 5 0 LDA HEAD2 X +21255 013355 5 0 ERA DEDIMP +21256 007715 5 0 ANA (SRCEI) +21257 100040 5 0 SZE /FROM DEAD IMP? +21260 003245 5 0 JMP IMPD4 /NO +21261 044000 5 0 LDA 0 X /YES, REMOVE FROM MESSTK +21262 111360 5 0 STA DTEND I +21263 120671 5 0 JST FLUSHI I /AND FREE BUFFER +21264 024565 5 0 IRS NRES /ADJUST REAS COUNT +21265 073360 5 0 LDX DTEND +21266 003245 5 0 JMP IMPD4 +21267 021303 5 0 IMPD5: JST DREAS +21270 003245 5 0 JMP IMPD4 +21271 073355 5 0 IMPD6: LDX DEDIMP +21272 121716 5 0 JST (MESINI) I +21273 000401 5 0 ENB T.O +21274 024000 5 IMPD7: IRS 0 +21275 025356 5 IRS DMSTAB +21276 004000 5 LDA 0 +21277 014132 5 ADD MINIMP +21300 100400 5 SPL /HAVE WE DONE ALL IMPS YET? +21301 003140 5 JMP IMPD /NOT YET, CYCLE BACK +21302 103134 5 JMP DEDI I + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 174 IMP,3050,IMP 7:20 PM 9/16/1973 + + LCK ALL +21303 000000 5 0 DREAS: 0 /TRY TO FREE A REAS BLOCK +21304 140100 5 0 SSP +21305 033360 5 0 STX DTEND +21306 010000 5 0 STA 0 +21307 044001 5 0 LDA RID X +21310 013355 5 0 ERA DEDIMP +21311 007715 5 0 ANA (SRCEI) +21312 100040 5 0 SZE /FROM DEAD IMP? +21313 103303 5 0 JMP DREAS I /NO +21314 044000 5 0 LDA 0 X /YES, REMOVE FROM MESSTK OR SHRQ +21315 111360 5 0 STA DTEND I +21316 021321 5 0 JST REASF /FREE REAS BLOCK AND PKTS +21317 073360 5 0 LDX DTEND +21320 103303 5 0 JMP DREAS I + +21321 000000 5 0 REASF: 0 /FREE REAS BLOCK AND ANY PKTS +21322 004000 5 0 LDA 0 +21323 026326 5 0 IMA RASF +21324 110326 5 0 STA RASF I /RETURN REAS BLOCK TO REAS FREE LIS +21325 005717 5 0 LDA (-8) 0"A"8PKTS +21326 011353 5 0 STA INCN +21327 140040 5 0 CRA +21330 050013 5 0 STA RSF X +21331 044002 5 0 LDA RMAX X +21332 100400 5 0 SPL /DID WE GET LAST PKT? +21333 004120 5 0 LDA SEVEN 0"A"8PKTS /NO +21334 141206 5 0 AOA +21335 014565 5 0 ADD NRES +21336 010565 5 0 STA NRES /ADJUST REAS COUNT +21337 140040 5 0 INCFRE: CRA +21340 066003 5 0 IMA REAS X +21341 101040 5 0 SNZ /DID WE GET THIS PKT? +21342 003347 5 0 JMP INCNXT /NO +21343 033354 5 0 STX INCX +21344 010000 5 0 STA 0 /YES, SO FREE IT +21345 120671 5 0 JST FLUSHI I +21346 073354 5 0 LDX INCX +21347 024000 5 0 INCNXT: IRS 0 +21350 025353 5 0 IRS INCN +21351 003337 5 0 JMP INCFRE +21352 103321 5 0 JMP REASF I + + LEV VAR +21353 V INCN: BSS 1 +21354 V INCX: BSS 1 +21355 V DEDIMP: BSS 1 /NO OF A DEAD IMP +21356 V DMSTAB: BSS 1 /PNTR TO HIS TMESS TABLE +21357 V DEDTRY: BSS 1 +21360 V DTEND: BSS 1 /TEMP Q PNTR +21361 V IMPDLH: BSS 1 + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 175 IMP,3050,IMP 7:20 PM 9/16/1973 + + LEV T.O +21362 000000 5 DEDH: 0 /TEST FOR DEAD HOSTS +21363 004131 5 LDA MITH +21364 011430 5 STA DHC +21365 072113 5 LDX ZERO +21366 045662 5 TDH1: LDA SKST X +21367 011372 5 STA TDH4 +21370 001001 5 INH [I2H,H2I] +21371 044504 5 3 LDA HIHD X +21372 5 3 TDH4: BSS 1 +21373 015720 5 3 ADD (TDHDN-0-TDHUP) /READY LINE DOWN +21374 015721 5 3 ADD (JMP TDHUP 0 I) /READY LINE DOWN +21375 011376 5 3 STA .+1 +21376 5 3 BSS 1 + +21377 021423 5 3 TDHUP: TDH5 /STEADY-STATE UP +21400 021423 5 3 TDH5 /READY LINE UP, HOST GOING DOWN +21401 021423 5 3 TDH5 /READY LINE UP, HOST TARDY +21402 021411 5 3 TDH3 /READY LINE JUST WENT UP, WAS DOWN +21403 021423 5 3 TDH5 /IGNORE HOST IF IMP NOT UP + +21404 021421 5 3 TDHDN: TDH2 /READY LINE JUST WENT DOWN, WAS UP +21405 021423 5 3 TDH5 /READY LINE DOWN, HOST GOING DOWN +21406 021421 5 3 TDH2 /READY LINE JUST WENT DOWN, WAS T: +21407 021423 5 3 TDH5 /STEADY-STATE DOWN +21410 021423 5 3 TDH5 /IGNORE HOST IF IMP NOT UR + +21411 140040 5 3 TDH3: CRA +21412 050504 5 3 STA HIHD X +21413 104700 5 3 LDA IHXX I /NOW TRULY UP +21414 101040 5 3 SNZ /IS THERE AN OUTPUT IN PROGESS? +21415 003423 5 3 JMP TDH5 /NO +21416 004107 5 3 LDA M30SEC /YES - MOST LIKELY A NOP +21417 111722 5 3 STA (IHTT 0 X) I /GIVE FULL 30 SECS +21420 003423 5 3 JMP TDH5 + +21421 005723 5 3 TDH2: LDA (IHWAIT) /HOST WENT DOWN, DO NOT DROP IMP RE +21422 121724 5 3 JST (IHST) I RET T.O / CLEAR OUT HIS QUEUES +21423 000401 5 TDH5: ENB T.O +21424 024000 5 IRS 0 +21425 025430 5 IRS DHC +21426 003366 5 JMP TDH1 +21427 103362 5 JMP DEDH I + + LEV VAR +21430 V DHC: BSS 1 + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 176 IMP,3050,IMP 7:20 PM 9/16/1973 + + LEV VAR +21431 000000 V HLRCVD: 0 /= OF CORRECT RESPONSES + + /* COMPUTE OUR EFFECTIVE CHANNEL DELAY + / S= 20L + (100+S) E/T WHERE T=20 + /S' = [(L+5)(256/(20-E))-64] + LEV T.O +21432 000000 5 JED: 0 +21433 072127 5 LDX MICH +21434 001001 5 ED1: INH I2M +21435 004116 5 2 LDA THREE +21436 111455 5 2 STA PCED I +21437 005717 5 2 LDA (-NACH) +21440 011457 5 2 STA JEDC +21441 044627 5 2 LDA I2MTAB+CH X +21442 011456 5 2 STA JEDP +21443 105456 5 2 JEDL: LDA JEDP I +21444 100040 5 2 SZE +21445 125455 5 2 IRS PCED I +21446 025456 5 2 IRS JEDP +21447 025457 5 2 IRS JEDC +21450 003443 5 2 JMP JEDL +21451 000401 5 2 ENB T.O +21452 024000 5 IRS 0 +21453 003434 5 JMP ED1 +21454 103432 5 JMP JED I + LEV CON +21455 066505 C PCED: CED+CH X + LEV VAR +21456 V JEDP: BSS 1 +21457 V JEDC: BSS 1 + + LEV T.O +21460 000000 5 IHTC: 0 /TIME OUT CHECK ROUTINE +21461 004131 5 LDA MITH +21462 011477 5 STA IHTK +21463 072113 5 LDX ZERO /ATTEMPT TO WAKE UP ALL IMP-TO-HOST +21464 125722 5 IHTY: IRS (IHTT 0 X) I /TIME TO WAKE HIM YET? +21465 003473 5 JMP IHTZ /NO +21466 001001 5 INH SIN /YES, SOFTWARE INTERRUPT IMP-TO-HOS +21467 000013 5 0 EXA +21470 121725 5 0 JST (IHSB) I RET T.O +21471 001001 5 INH ALL +21472 120672 5 0 JST DODXA I RET T.O +21473 024000 5 IHTZ: IRS 0 +21474 025477 5 IRS IHTK +21475 003464 5 JMP IHTY +21476 103460 5 JMP IHTC I + LEV VAR +21477 V IHTK: BSS 1 + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 177 IMP,3050,IMP 7:20 PM 9/16/1973 + + + LEV T.O +21500 000000 5 JUQC: 0 +21501 073726 5 LDX (-COUNTL) +21502 001001 5 QC1: INH ALL +21503 044543 5 0 LDA COUNTA+COUNTL X +21504 056567 5 0 SUB COUNTS+COUNTL X +21505 101400 5 0 SMI /NEGATIVE +21506 003513 5 0 JMP QC2 /NO + DEFHLT [QUEUE COUNTER WENT NEGATIVE] +21507 021510 5 0 JST CNTHLT +21510 000000 5 0 CNTHLT: 0 +21511 120745 5 0 JST HLTNCC I +21512 140040 5 0 CRA /RESET COUNT TOT ZERO +21513 050543 5 0 QC2: STA COUNTA+COUNTL X +21514 140040 5 0 CRA +21515 050567 5 0 STA COUNTS+COUNTL X +21516 000401 5 0 ENB T.O +21517 024000 5 IRS 0 +21520 003502 5 JMP QC1 +21521 001001 5 INH ALL +21522 125727 5 0 IRS (SNTALL) I /ARE WE ALLOCATE-IDLE? +21523 103500 5 0 JMP JUQC I /NO +21524 010542 5 0 STA NALA /YES, FREE UP ALLOCATE STORE +21525 103500 5 0 JMP JUQC I + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 178 IMP,3050,IMP 7:20 PM 9/16/1973 + + LEV T.O +21526 000000 5 MESSTO: 0 /TIMEOUT MESS NO IN 34-51 SECS +21527 025561 5 IRS MESST /TIME TO LOOK YET? +21530 103526 5 JMP MESSTO I /NO +21531 072132 5 LDX MINIMP +21532 001001 5 MESST1: INH H2I +21533 105730 5 4 LDA (TMESS+NIMP 0 X) I +21534 007702 5 4 ANA (MESBTS) +21535 013702 5 4 ERA (MESBTS) +21536 101040 5 4 SNZ /ANY MESSAGES OUTSTANDING? +21537 003550 5 4 JMP MESST2 /NOTHING TO TIME OUT +21540 105730 5 4 LDA (TMESS+NIMP 0 X) I +21541 007731 5 4 ANA (MSTO1 0 MSTO2) +21542 013731 5 4 ERA (MSTO1 0 MSTO2) +21543 101040 5 4 SNZ +21544 003550 5 4 JMP MESST2 /ALREADY TIMED OUT +21545 005732 5 4 LDA (MSTO1) +21546 115730 5 4 ADD (TMESS+NIMP 0 X) I +21547 111730 5 4 STA (TMESS+NIMP 0 X) I +21550 000401 5 4 MESST2: ENB T.O +21551 024000 5 IRS 0 +21552 003532 5 JMP MESST1 +21553 004107 5 LDA M30SEC /17 SECS +21554 040575 5 ARS 3 +21555 014107 5 ADD M30SEC +21556 040577 5 ARS 1 +21557 011561 5 STA MESST /BETWEEN LOOKS +21560 103526 5 JMP MESSTO I + + LEV VAR +21561 V MESST: BSS 1 +21562 V HTOLD: BSS 1 +21563 V HTINTF: BSS 1 + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 179 IMP,3050,IMP 7:20 PM 9/16/1973 + + LEV T.O +21564 000000 5 HTEST: 0 +21565 101000 5 HTMIN: NOP +21566 005733 5 LDA (NOP) /RESET MXIN/NOP INSTRUCTION +21567 011565 5 STA HTMIN +21570 004141 5 LDA HTPAR +21571 013562 5 ERA HTOLD +21572 101040 5 SNZ +21573 103564 5 JMP HTEST I /NO CHANGE, NOTHING TO DO +21574 004141 5 LDA HTPAR +21575 006120 5 ANA SEVEN /GET FUNCTION +21576 101040 5 SNZ +21577 003626 5 JMP HTX /FUNCTION ZERO?! +21600 010000 5 STA 0 +21601 004141 5 LDA HTPAR +21602 040575 5 ARS 3 /GET INTERFACE +21603 006752 5 ANA C77 +21604 011563 5 STA HTINTF +21605 055630 5 ADD HTTAB-1 X +21606 011624 5 STA HT5 /CORRECT OCP +21607 004000 5 LDA 0 +21610 022116 5 CAS THREE +21611 003624 5 JMP HT5 /HOST FUNCTION...DO IT +21612 100000 5 SKP /MODEM UNPATCH...MORE TO DO +21613 003621 5 JMP HT1 /MODEM OTHER...SET UP IN +21614 073563 5 LDX HTINTF +21615 001001 5 INH I2M +21616 044437 5 2 LDA NONE-1 X /MODEM BUSY? +21617 100040 5 2 SZE +21620 103564 5 2 JMP HTEST I /YES, COME AGAIN +21621 005563 5 2 HT1: LDA HTINTF /SET UP IN FOR NEXT T.O. TO DO +21622 015734 5 2 ADD (M1IN-1) +21623 011565 5 2 STA HTMIN +21624 5 2 HT5: BSS 1 +21625 000401 5 2 ENB T.O +21626 004141 5 HTX: LDA HTPAR /RESET HTOLD +21627 011562 5 STA HTOLD +21630 103564 5 JMP HTEST I + + LEV CON + /HTPAR HAS VALUE DDF - DEVICE IS DD AND FUNCTION IS F + /D=1,2,3,4,5 FOR MODEMS 1,2,3,4,5 (F=1,2,OR 3) + /D=70,60,50,51 FOR HOSTS 1,2,3,4 (F=4,5,OR 6) +21631 030270 C HTTAB: M1LXP-1 /1 - LINE CROSSPATCH +21632 030370 C M1IXP-1 /2 - INTERFACE CROSSPATCH +21633 030170 C M1UNXP-1 /3 - UNPATCH (RESTORE) +21634 030300 C H1XP-70 /4 - CROSSPATCH HOST INTERFACE +21635 030500 C H1ENAB-70 /5 - ENABLE NORMAL HOST TRAFFIC +21636 030400 C H1UNXP-70 /6 - UNPATCH (CLEAR) HOST INTERFACE +21637 101000 C NOP /7 + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 180 IMP,3050,IMP 7:20 PM 9/16/1973 + + LEV T.O +21640 000000 5 HPOKE: 0 /TEST HOST INTERFACE +21641 001001 5 INH FRE +21642 004142 5 0 LDA HLNM /TESTER TURNED ON? +21643 100400 5 0 SPL +21644 003656 5 0 JMP HPOKE2 /OFF +21645 010000 5 0 STA 0 +21646 044332 5 0 LDA SHWQ X /ROOM FOR ANOTHER TEST PROD? +21647 100040 5 0 SZE +21650 003656 5 0 JMP HPOKE2 /NO +21651 004143 5 0 LDA HL2WD +21652 010515 5 0 STA TWDP +21653 005735 5 0 LDA (CNOP) +21654 120670 5 0 JST OWP I +21655 025660 5 0 IRS HLSNT /COUNT ANOTHER POKE +21656 000401 5 0 HPOKE2: ENB T.O +21657 103640 5 JMP HPOKE I + LEV VAR +21660 V HLSNT: BSS 1 + LEV CON +21661 037454 C VDH3.: VD.TO + +21662 070170 C SKST: H1RDY +21663 070160 C H2RDY +21664 C TIPSKP: TIPDEF H3RDY, NOP +02265 021664 C +02315 070150 C +02345 101000 C +21665 070151 C H4RDY +21666 100000 C SKP +21667 100000 C SKP +21670 100000 C SKP +21671 100000 C SKP + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 181 IMP,3050,IMP 7:20 PM 9/16/1973 + +21672 027112 C LEV CON CONSTANTS +21673 026512 C +21674 177666 C +21675 054115 C +21676 041557 C +21677 102111 C +21700 020164 C +21701 032271 C +21702 000017 C +21703 001400 C +21704 015033 C +21705 007244 C +21706 015205 C +21707 070377 C +21710 003400 C +21711 015347 C +21712 015114 C +21713 000340 C +21714 000327 C +21715 000077 C +21716 002374 C +21717 177770 C +21720 000005 C +21721 103377 C +21722 056306 C +21723 016341 C +21724 016273 C +21725 016042 C +21726 177754 C +21727 004161 C +21730 072371 C +21731 000300 C +21732 000100 C +21733 101000 C +21734 030470 C +21735 002000 C +02430 176745 C PAGEND 21,UNCON,4 + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 182 IMP,3050,IMP 7:20 PM 9/16/1973 + + + + LEV BCK + /TROUBLE REPORTS TO NCC AT HOST 0 AT BBN +22057 005524 7 TRBL: LDA (301) /*SEND TRBL REPT CODE +22060 011301 7 STA NTRCKS /INIT THE CHECKSUM COUNTER +22061 121525 7 JST (GIVE) I +22062 073526 7 LDX (-NH) +22063 001001 7 INH ALL /USING B REG - MUST LOCK INTERRUPT' +22064 044510 7 0 NTR6: LDA HIHD+NH X +22065 100040 7 0 SZE +22066 004112 7 0 LDA SIGN +22067 140024 7 0 CHS +22070 041277 7 0 LLR 1 +22071 024000 7 0 IRS 0 +22072 003064 7 0 JMP NTR6 +22073 040274 7 0 LRR NH +22074 013272 7 0 ERA SWS /*SEND ANOMALY WORD - HOSTS + SWIT ] +22075 021310 7 0 JST NTGIVE RET BCK +22076 127527 7 IMA (RSFNCC) I /*SEND RESTART-RELOAD INDICATOR +22077 021310 7 JST NTGIVE +22100 026746 7 IMA HLTLOC /*SEND HALT PC REG +22101 021310 7 JST NTGIVE +22102 004747 7 LDA HLTA /*SEND HALT A REG +22103 021310 7 JST NTGIVE +22104 004750 7 LDA HLTX /*SEND HALT X REG +22105 021310 7 JST NTGIVE +22106 072124 7 LDX MINUS4 /*SEND COUNTS FOR +22107 001001 7 NTR7: INH ALL /FREE, REAS, S+F, AND ALLOCATE +22110 044543 7 0 LDA NFA+4 X +22111 056567 7 0 SUB NFS+4 X +22112 021310 7 0 JST NTGIVE RET BCK +22113 024000 7 IRS 0 +22114 003107 7 JMP NTR7 +22115 004105 7 LDA VERS /*SEND IMP VERSION NO +22116 021310 7 JST NTGIVE +22117 105530 7 LDA (HOST34) I /*SEND HOST34 CONFIGURATOR WORD +22120 021310 7 JST NTGIVE +22121 000013 7 EXA +22122 105531 7 LDA (TIPVER) I /*SEND TIP VERSION NO +22123 001001 7 INH [ALL] +22124 120672 7 0 JST DODXA I RET BCK +22125 021310 7 JST NTGIVE +22126 004142 7 LDA HLNM /*SEND NO OF HOST INTERFACE BEING T +22127 021310 7 JST NTGIVE +22130 127532 7 IMA (HLSNT) I /*SEND TEST MESS SENT COUNT +22131 021310 7 JST NTGIVE +22132 127533 7 IMA (HLRCVD) I /*SEND TEST MESS RECVD COUNT +22133 021310 7 JST NTGIVE +22134 011277 7 STA NTRTM1 /ZERO LINE-SPEEDS WORD +22135 072127 7 LDX MICH /TAKE A SNAPSHOT OF LINE ERRORS +22136 001001 7 NTR1: INH [T.O,TSK] /A=0 NOW + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 183 IMP,3050,IMP 7:20 PM 9/16/1973 + +22137 140040 7 5 CRA +22140 127534 7 5 IMA (RTRCVD+CH 0 X) I +22141 057310 7 5 SUB RTSSNT+CH X /SUBTRACT ROUTING MESS E , +22142 140407 7 5 TCA /COMPUTE NO OF ROUTING MESS MISSED +22143 100400 7 5 SPL +22144 140040 7 5 CRA /MUST BE A POSITIVE NUMBER +22145 023535 7 5 CAS (377) +22146 005535 7 5 LDA (377) +22147 101000 7 5 NOP +22150 011302 7 5 STA E321 /SAVE AS ERROR COUNT FOR THIS LINE +22151 004121 7 5 LDA MINUS1 +22152 067310 7 5 IMA RTSSNT+CH X /*SEND NO OF ROUTING MEI +22153 023535 7 5 CAS (377) +22154 005535 7 5 LDA (377) +22155 101000 7 5 NOP +22156 021310 7 5 JST NTGIVE RET BCK +22157 044440 7 LDA LINE+CH X /NOW ERROR+THROUGHPUT COUNTS FOR EAT +22160 100040 7 SZE +22161 005536 7 LDA (200) +22162 052165 7 ERA NEIGHB+CH X /PICK UP NEIGHBOR IMP NUMT +22163 022106 7 CAS MINE /IS LINE LOOPED? +22164 100000 7 SKP /NO +22165 012753 7 ERA C100 /YES, PUT IN LOOPED BIT +22166 141340 7 ICA +22167 013302 7 ERA E321 /*SEND NO OF ROUTING MESS MISSED +22170 021310 7 JST NTGIVE +22171 105537 7 LDA (RMFLG+CH X) I /GET LINE SPEED BITS +22172 141340 7 ICA +22173 006116 7 ANA THREE 0"A"SPDTYP +22174 013277 7 ERA NTRTM1 +22175 041676 7 ALR 2 +22176 011277 7 STA NTRTM1 +22177 024000 7 IRS 0 +22200 003136 7 JMP NTR1 +22201 041674 7 ALR 4 /LEFT ADJUST +22202 021310 7 JST NTGIVE /*SEND LINE SPEEDS +22203 072123 7 LDX MINUS3 +22204 105540 7 LDA (37777 0 X) I /*SEND TRAP INFO (P, A, X +22205 021310 7 JST NTGIVE +22206 024000 7 IRS 0 +22207 003204 7 JMP .-3 + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 184 IMP,3050,IMP 7:20 PM 9/16/1973 + +22210 027301 7 IMA NTRCKS /A=0 NOW +22211 140407 7 TCA +22212 121525 7 JST (GIVE) I /*SEND CHECKSUM +22213 140040 7 CRA +22214 027276 7 IMA TRBSTF /FIRED BY SYNC OR SWCH? +22215 100040 7 SZE +22216 103541 7 JMP (GIVLST) I /*SEND PADDING--FIRED BY SWCH +22217 073542 7 LDX (100003) /END OUR OWN MESSAGE +22220 004112 7 LDA SIGN +22221 120664 7 JST JAM I /*PADDING AND END OF MESSAGE +22222 105543 7 LDA (TRBD) I /*NCC DEST +22223 121525 7 JST (GIVE) I +22224 105544 7 LDA (TRBD+0+TLNK-TDST) I /*NCC LINK +22225 121525 7 JST (GIVE) I +22226 005545 7 LDA (302) /*STAT MESSAGE CODE +22227 021310 7 JST NTGIVE +22230 072127 7 LDX MICH /SEND LINE STATS +22231 127546 7 NTR8: IMA (THRUPT+CH X) I +22232 021310 7 JST NTGIVE /*PACKET THRUPUT +22233 127547 7 IMA (THRUPW+CH X) I +22234 021310 7 JST NTGIVE /*WORD THRUPUT +22235 024000 7 IRS 0 +22236 003231 7 JMP NTR8 +22237 073526 7 LDX (-NH) /NOW HOST THROUGHPUTS FOR EACH HO1' +22240 005550 7 NTR5: LDA (-10.) /AND FOR EACH OF 10 FLAVORS +22241 011277 7 STA NTRTM1 +22242 005551 7 LDA (NTRTAB 0 I) +22243 011300 7 STA NTRTM2 +22244 140040 7 NTR4: CRA +22245 127300 7 IMA NTRTM2 I /*SEND HOST THROUGHPUT COUNT +22246 021310 7 JST NTGIVE +22247 025300 7 IRS NTRTM2 +22250 025277 7 IRS NTRTM1 +22251 003244 7 JMP NTR4 +22252 024000 7 IRS 0 +22253 003240 7 JMP NTR5 +22254 027301 7 IMA NTRCKS /A=0 NOW +22255 140407 7 TCA +22256 121525 7 JST (GIVE) I /*SEND CKSUM +22257 103541 7 JMP (GIVLST) I /*SEND PADDING + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 185 IMP,3050,IMP 7:20 PM 9/16/1973 + + LEV CON + +22260 073563 C NTRTAB: HTPMTN+NH X +22261 073567 C HTPMFN+NH X +22262 073573 C HTPPTN+NH X +22263 073577 C HTPPFN+NH X +22264 073603 C NTRT1: HTPMTL+NH X +22265 073607 C NTRT3: HTPMFL+NH X +22266 073613 C NTRT2: HTPPTL+NH X +22267 073617 C NTRT4: HTPPFL+NH X +22270 073623 C HTPWTI+NH X +22271 073627 C HTPWFI+NH X + + LEV VAR +22272 V SWS: BSS 1 /ANOMALIES +22273 V HLNMS: BSS 1 +22274 V SWCHTM: BSS 1 +22275 003014 V HERSAV: JMP 0 1000 777"A"HITEST +22276 V TRBSTF: BSS 1 +22277 V NTRTM1: BSS 1 +22300 V NTRTM2: BSS 1 +22301 V NTRCKS: BSS 1 /CHECKSUM FOR TROUBLE REPT +22302 V E321: BSS 1 /NO OF ERRORS ON EACH LINE +22303 V RTSSNT: BSS CH /NO OF HELLO'S SENT + + LEV BCK +22310 000000 7 NTGIVE: 0 /BUILD CHECKSUM +22311 000401 7 ENB BCK +22312 027301 7 IMA NTRCKS +22313 015301 7 ADD NTRCKS +22314 027301 7 IMA NTRCKS +22315 121525 7 JST (GIVE) I /AND GIVE A WORD TO IMP VIA JAM +22316 140040 7 CRA +22317 103310 7 JMP NTGIVE I + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 186 IMP,3050,IMP 7:20 PM 9/16/1973 + + /BITS IN SWS (TROUBLE REPORT ANOMALIES): + / 100000 - HOST 0 UP (NOT KEPT IN SWS) + / 40000 - HOST 1 UP (NOT KEPT IN SWS) + / 20000 - HOST 2 UP (NOT KEPT IN SWS) + / 10000 - HOST 3 UP (NOT KEPT IN SWS) + / 4000 - VDH SOFTWARE IS UP + / 2000 - M.GENERATOR IS ON + / 1000 - STATISTICS IS ON + / 400 - SNAPSHOT IS ON + / 200 - TRACE IS ON + / 100 - MEM PROTECT IS OFF + / 40 - SPARE + / 20 - OVERRIDE IS ON + / 10 - SS 1 IS ON + / 4 - SS 2 IS ON + / 2 - SS 3 IS ON + / 1 - SS 4 IS ON + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 187 IMP,3050,IMP 7:20 PM 9/16/1973 + + LEV T.O +22320 000000 5 SWCH: 0 /SET UP SWITCH SETTINGS FOR TROUBLE +22321 005552 5 LDA (4000) /SET UP FREQ FOR NCC TRBL REPTS +22322 111553 5 STA (TRBF) I /DEST IS SET IN BACK +22323 072121 5 LDX MINUS1 +22324 105527 5 LDA (RSFNCC) I +22325 101040 5 SNZ +22326 105554 5 LDA (HLTLOC) I +22327 100040 5 SZE /IF RSFLAG OR HLTLOC NON-ZERO +22330 033272 5 STX SWS /FIRE OFF A TRBL REPT NOW +22331 004142 5 LDA HLNM +22332 027273 5 IMA HLNMS +22333 023273 5 CAS HLNMS +22334 100000 5 SKP /CHANGE IN HOST TEST STATUS? +22335 003345 5 JMP SWCH0 /NO +22336 033272 5 STX SWS +22337 010000 5 STA 0 /RICK HOST NO GOING OFF +22340 005275 5 LDA HERSAV +22341 127555 5 IMA (HER 0 X) I /INTERCHANGE PATCH REGIST +22342 072142 5 LDX HLNM /PICK HOST NO COMING ON +22343 127555 5 IMA (HER 0 X) I +22344 011275 5 STA HERSAV 0"A"HER0 +22345 004753 5 SWCH0: LDA C100 +22346 111556 5 STA (1777) I /ATTEMPT TO CHANGE WORD ON PROT P: +22347 140040 5 CRA +22350 127556 5 IMA (1777) I /IF SUCCESSFUL, PUT IN MP OFF BIT +22351 012473 5 ERA OVRDF /OVRDF=20 IF ON, =0 IF OFF +22352 100020 5 SR1 +22353 012751 5 ERA TEN +22354 100010 5 SR2 +22355 012117 5 ERA FOUR +22356 100004 5 SR3 +22357 012115 5 ERA TWO +22360 100002 5 SR4 +22361 012114 5 ERA ONE +22362 072124 5 LDX MINUS4 +22363 011274 5 SWCH4: STA SWCHTM +22364 105557 5 LDA (PARAMT+4 X) I +22365 100040 5 SZE +22366 105560 5 LDA (SWCHB+4 X) I /SET THE BIT +22367 013274 5 ERA SWCHTM +22370 024000 5 IRS 0 +22371 003363 5 JMP SWCH4 +22372 012567 5 ERA VDHUPF /=4000 IF VDH IS UP +22373 027272 5 IMA SWS +22374 013272 5 ERA SWS +22375 101040 5 SNZ +22376 103320 5 JMP SWCH I +22377 011276 5 STA TRBSTF /TELL TRBL RPTS THAT SWS FIRED IT +22400 004417 5 LDA SYNC +22401 117553 5 SUB (TRBF) I +22402 111561 5 STA (TRBOLD) I +22403 103320 5 JMP SWCH I + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 188 IMP,3050,IMP 7:20 PM 9/16/1973 + + LEV [M2I,VDI,I2H,T.O,TSK] +22404 000000 0 HLTWRD: 0 +22405 010747 0 STA HLTA +22406 032750 0 STX HLTX +22407 004122 0 LDA MINUS2 +22410 015404 0 ADD HLTWRD +22411 010746 0 STA HLTLOC +22412 104746 0 LDA HLTLOC I +22413 010746 0 STA HLTLOC /SAVE LOC OF HLT +22414 103404 0 JMP HLTWRD I + + LEV H2I /8-WAY BREAKDOWN OF HOST THROUGHPUT +22415 000000 4 HTPMT: 0 /COUNT MESSAGES TO NET +22416 012106 4 ERA MINE +22417 100040 4 SZE /INTER- OR INTRA-NODE? +22420 005562 4 LDA (HTPMTN+0-HTPMTL) +22421 015264 4 ADD NTRT1 +22422 001001 4 INH I2H +22423 021505 4 3 JST HTPIRS RET H2I +22424 101000 4 NOP +22425 103415 4 JMP HTPMT I + +22426 000000 4 HTPPT: 0 /COUNT PACKETS TO NET +22427 012106 4 ERA MINE +22430 100040 4 SZE /INTER- OR INTRA-NODE? +22431 005562 4 LDA (HTPPTN+0-HTPPTL) +22432 015266 4 ADD NTRT2 +22433 001001 4 INH I2H +22434 021505 4 3 JST HTPIRS RET H2I +22435 103426 4 JMP HTPPT I /R1==>FH - DON'T GET LENGTH +22436 172677 4 LDX HIXX I +22437 044111 4 LDA BUFE X +22440 016000 4 SUB 0 +22441 140100 4 SSP 0"A"TWOQ +22442 017563 4 SUB (DATA) /GOT PACKET LENGTH, NOT COUNTING LE +22443 072675 4 LDX HIP +22444 115564 4 ADD (HTPWTI 0 X) I +22445 100400 4 SPL +22446 004112 4 LDA SIGN /MARK OFLO +22447 111564 4 STA (HTPWTI 0 X) I +22450 103426 4 JMP HTPPT I + + LEV I2H +22451 000000 3 HTPMF: 0 /COUNT MESSAGES FROM NET +22452 012106 3 ERA MINE +22453 007565 3 ANA (SRCEI) +22454 100040 3 SZE /INTER- OR INTRA-NODE? +22455 005562 3 LDA (HTPMFN+0-HTPMFL) +22456 015265 3 ADD NTRT3 +22457 021505 3 JST HTPIRS +22460 101000 3 NOP +22461 103451 3 JMP HTPMF I + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 189 IMP,3050,IMP 7:20 PM 9/16/1973 + +22462 000000 3 HTPPF: 0 /COUNT PACKETS FROM NET +22463 012106 3 ERA MINE +22464 007565 3 ANA (SRCEI) +22465 100040 3 SZE /INTER- OR INTRA-NODE? +22466 005562 3 LDA (HTPPFN+0-HTPPFL) +22467 015267 3 ADD NTRT4 +22470 021505 3 JST HTPIRS +22471 103462 3 JMP HTPPF I /R1==>FH +22472 172700 3 LDX IHXX I +22473 044111 3 LDA BUFE X +22474 016000 3 SUB 0 +22475 140100 3 SSP 0"A"TWOQ +22476 017563 3 SUB (DATA) /GOT PKT LENGTH +22477 072676 3 LDX IHP +22500 115566 3 ADD (HTPWFI 0 X) I +22501 100400 3 SPL +22502 004112 3 LDA SIGN /MARKING OVERFLOW +22503 111566 3 STA (HTPWFI 0 X) I +22504 103462 3 JMP HTPPF I + + /HOST THROOGHPUT TABLES AND COUNT ROUTINE +22505 000000 3 HTPIRS: 0 /TBL IN A, HOST NUM IN X +22506 016130 3 SUB PLNH +22507 011523 3 STA HTPIR1 +22510 004000 3 LDA 0 +22511 016130 3 SUB PLNH +22512 101400 3 SMI /FAKE HOST? +22513 003521 3 JMP HTPIR2 /YES, DO NOT COUNT TRAFFIC TO OR FR +22514 105523 3 LDA HTPIR1 I +22515 101400 3 SMI /OVERFLOWED--LEAVE AT 100000 +22516 141206 3 AOA /ADD ONE TO COUNTER +22517 111523 3 STA HTPIR1 I +22520 025505 3 IRS HTPIRS /R2==>REAL (NOT FAKE) HOST +22521 000401 3 HTPIR2: ENB I2H +22522 103505 3 JMP HTPIRS I + LEV VAR +22523 V HTPIR1: BSS 1 /PNTR INTO HTPTBL + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 190 IMP,3050,IMP 7:20 PM 9/16/1973 + +22524 000301 C LEV CON CONSTANTS +22525 030403 C +22526 177774 C +22527 003560 C +22530 001005 C +22531 040000 C +22532 021660 C +22533 021431 C +22534 060464 C +22535 000377 C +22536 000200 C +22537 052625 C +22540 077777 C +22541 030165 C +22542 100003 C +22543 030456 C +22544 030450 C +22545 000302 C +22546 050625 C +22547 050620 C +22550 177766 C +22551 122260 C +22552 004000 C +22553 030464 C +22554 000746 C +22555 053170 C +22556 001777 C +22557 070440 C +22560 041246 C +22561 030210 C +22562 177760 C +22563 000011 C +22564 073617 C +22565 000077 C +22566 073623 C +02431 175607 C PAGEND 22,UNCON,4 + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 191 IMP,3050,IMP 7:20 PM 9/16/1973 + + + /DDT CONTROL LANGUAGE INFORMATION + / + /************CURRENTLY IMPLEMENTED COMMANDS*****************, + / + /SHIFT-CONTROL-P (OR THE BREAK KEY) HAS THE FOLLOWING EFFE( : + /1- ANY DDT OUTPUT IS STOPPED + /2- THE CURRENTLY OPENED REGISTER IS CLOSED WITH NO NEW CONT1 + /3- DDT FORGETS WHATEVER NUMBER WAS BEING TYPED IN + /4- DDT TYPES A CARRAIGE RETURN-LINE FEED + /5- DDT IS UN-CROSSPATCHED - THAT IS YOU ARE NOW TYPING + / TO THE LOCAL DDT IF YOU WERE CROSSPATCHED BEFORE + / + / HAS THE FOLLOWING EFFECTS: + /1- DDT FORGETS WHATEVER NUMBER WAS BEING TYPED IN + /2- DDT TYPES "= " + / + /. HAS THE VALUE OF THE CURRENT REGISTER'S ADDRESS (14-BITI + / + / HAS THE VALUE OF THE LAST THING TYPED BY DDT + / + /* HAS THE VALUE OF THE CONTENTS OF THE REGISTER ADDRESSED B + /HAS BEEN ASSEMBLED AS THE CURRENT SYLLABLE. IT ALWAYS USES + /THE CURRENT SYLLABLE AS A 14 BIT ADDRESS AND CAN BE APPLI[ + /ITSELF OR TO ANY SYLLABLE + / + /T HAS THE VALUE OF THE IMP NUMBER OF THE LAST FOREIGN IMP + /TO SEND A TTY MESSAGE TO THIS IMP. USED IN T= OR TC. + / + /, SEPARATES ARGUMENTS TO MULTIPLE ARGUMENT COMMANDS + / + /A1/ OPENS REGISTER AT LOCATION A1 (14-BIT ADDRESS) + / + /A1 OPEN REGISTER AT LOCATION A1 (USED AS + /A 9 BIT RELATIVE ADDRESS TO THE PAGE . IS ON. + / + /A1 CLOSES THE CURRENTLY OPEN REGISTER (IF ANY) + /INSERTS A1 AS ITS NEW CONTENTS (IF SUPPLIED) + / + /A1- CLOSES THE CURRENTLY OPEN REGISTER (AS LINEFEED) AND + /THE PREVIOUS REGISTER + + /A1 CLOSES THE CURRENTLY OPEN REGISTER (AS LINEFEE + /OPENS THE NEXT REGISTER + / + / AND + BOTH MEAN ADDITION + / + /- MEANS SUBTRACTION + / + /D MEANS THE NUMBER FOLLOWING IS DECIMAL + / + /" MEANS THAT THE TWO CHARACTERS FOLLOWING ARE TO BE TAKEN + /AS LITERAL ASCII VALUES AND PACKED INTO A WORD LEFT HALF, R + / + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 192 IMP,3050,IMP 7:20 PM 9/16/1973 + + /= TYPES OUT THE OCTAL VALUE OF THE LAST INPUT + /EG: 3=3, 3+6=11, D11=13, "AB=40502, "AB+D10=40514, .=3033 + / + /> TYPES OUT THE ASCII VALUE OF THE LAST OUTPUT (IE AB + / + / + /A1.A2,A3Z CLEARS ["ZEROES"] CORE BETWEEN LIMITS - A1 IS T1 + /CONSTANT CORE WILL BE CLEARED TO. A2 AND A3 ARE THE (INCLL' + /LOWER AND UPPER LIMITS, REPECTIVELY. + / + /A1,A2W DUMPS OUT ["WRITES"] CORE BETWEEN LIMITS - A1 AN( + /ARE THE (INCLUSIVE) LOWER AND UPPER LIMITS. RESPECTIVELY. + / + /A1,A2,A3S STARTS UP A PROGRAM (I.E. CAUSE A TRANSFER TO + /LOCATION). A3 IS THE (14 BIT) ADDRESS AT WHICH THE PROGRAM + /IS TO BE STARTED. A2 SPECIFIES THE CONTENTS OF THE A REGIST1 + /WHEN THE PROGRAM IS STARTED UP. A1 SPECIFIES THE + /X REGISTER WHEN THE PROGRAM IS STARTED UP. + / + /A1C CROSSPATCHES DDT TO IMP A1. + /MESSAGES ARE THEN TRANSMITTED TO IMP A1 + /FOR EVERY CHARACTER THAT IS TYPED IN + / + /A1,A2H SETS UP THE HEADER FOR MESSAGE + /TRANSMISSION - MESSAGES ARE TRANSMITTED BY + /TYPING A SEMICOLON, THEN ALL THE CHARACTERS UP TO THE + /NEXT SEMICOLON ARE SENT OFF AS A MESSAGE TO + /DESTINATION AS DETERMINED BY THIS HEADER. + /A1 GIVES LEADER WORD 1 (DESTINATION) + /A2 GIVES LEADER WORD 2 (LINK =). + / + /A1$ SENDS AN IMP GOING DOWN MESSAGE TO ALL THE HOSTS + /AT THE SITE TO WHICH DDT IS CROSSPATCHED. + /A1 IS THE LINK DR SUB-CODE WORD AND MUST BE SUPPLIED + / + /Q TURNS DDT OUTPUT OFF AND ON - REVERSES THE CURRENT STAT + /IF DDT TYPES NOTHING BACK IT IS OFF ["QUIET"] + /OTHERWISE DDT WILL TYPE A CARRIAGE RETURN-LINE FEED + / + /I PRODUCES AN INTERRUPT PRINT + /A DUMP OF SOME INTERESTING INTERRUPT LOCATIONS + / + /1 PRODUCES A QUEUE PRINT + /A DUMP DF SOME INTERESTING QUEUE AND TABLE LOCATIONS + / + /A1,A2,A3,A4[E N] WORD SEARCHES: UNDER A MASK OF A1, DOT + /SEARCH FOR WORDS EQUAL (NOTEQUAL) TO A2 BETWEEN THE + /LIMITS A3 TO A4. + / + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 193 IMP,3050,IMP 7:20 PM 9/16/1973 + + / + /*****************SENSE SWITCH FOUR********************* + / + / HAVING SENSE SWITCH 4 DOWN INHIBITS ALL OF + /DDT'S COMMANDS WHICH COULD DESTROY THE PROGRAM BEING + /LSOKED AT. IF YOU ATTEMPT TO CHANGE CORE WITH SS4 DOWN, ( ' + /WILL TYPE "= " AT YOU AND COMPLETELY IGNORE THE COMMAND. + /THE COMMANDS AFFECTED ARE: S, Q, Z,S, AND LINEFEED, UPARRO' + /CARRIAGE RETURN IF TRYING TO SUPPLY NEW CONTENTS. + + /*****************NULL ARGUMENT CONVENTIONS*****************, + / + /FOR =,CR,LF,-, AND IF + /THE ARGUMENT A1 IS LEFT OUT, THE LAST NUMBER TYPED BY DDT W + /BE USED AS THE ARGUMENT. + / + /FOR E, N, Z AND W, IF EITHER (OR BOTH) OF THE LIMITS ARE LET + /DDT WILL USE THE LAST LIMITS SPECIFIED FOR EITHER A Z OR : 1 + /OR AN E OR AN N. + /IF THE VALUE IS LEFT OUT IN AN E, N OR Z COMMAND, THE LAST + /SPECIFIED IN ANY E, N, OR Z COMMAND WILL BE USED. IF THE + /IS LEFT OUT OF AN E OR N COMMAND IT WILL BE SUPPLIED FROM + /THE LAST E OR N DONE. OR -1 IF NO MASK HAS EVER + /BEEN SPECIFIED. + / + /FOR S, ANY ARGUMENTS LEFT OUT WILL BE SUPPLIED FROM THE LAS + /THOSE ARGUMENTS WERE SPECIFIED. + / + /*********************************************************** + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 194 IMP,3050,IMP 7:20 PM 9/16/1973 + + LEV BCK + /DDT - STAND ALONE AND BACKGROUND + /THE SAME PROGRAM IS USED FOR STAND ALONE USE + /AND AS A BACKGROUND PROGRAM RUNNING WITH THE IMP SYSTEM + /THE ONLY DIFFERENCE IS IN THE INPUT AND OUTPUT PORTS + /CALLS TO INPUT A CHARACTER AND TO OUTPUT A CHARACTER + /ARE MADE INDIRECT THROUGH LDIN AND LDOT RESPECTIVELY + /STAND ALONE THESE POINT TO SIMPLE TTY I/O HANDLERS + /UNDER IMPSYS THESE POINT TO COMPLEX COROUTINES IN BACKGRO1 ] +23033 005633 7 DDSA: LDA (DDA3) /ENTRY TO STAND ALONE DDT +23034 011163 7 STA LDIN /SET UP STAND ALONE INPUT +23035 005634 7 LDA (DDA4) +23036 011164 7 STA LDOT /SET UP STAND ALONE OUTPUT +23037 005635 7 LDA (QNUL) +23040 011632 7 STA QPTR /TURN OFF QUIET MODE +23041 011162 7 STA BBNF /SET DEST TO NON-BBN +23042 140040 7 CRA +23043 010473 7 STA OVRDF /TURN OFF SOFTWARE SS4 +23044 000013 7 EXA +23045 003076 7 JMP DCLR /GO TO RESTART ENTRY + +23046 000000 7 DDA3: 0 /STAND ALONE DDT INPUT +23047 131004 7 TTINAC /GET INPUT CHAR +23050 003047 7 JMP .-1 +23051 007636 7 ANA (177) +23052 013637 7 ERA (200) /ALWAYS PUT IN PARITY BIT +23053 103046 7 JMP DDA3 I + +23054 000000 7 DDA4: 0 /STAND ALONE DDT OUTPUT +23055 070104 7 TTSNBZ +23056 003075 7 JMP DDA5 /BUSY, SO GET THE INPUT CHAR +23057 030104 7 TTSOM /GO INTO OUTPUT MODE +23060 170004 7 TTOTA /DO OUTPUT +23061 003060 7 JMP .-1 +23062 070004 7 TTSRDY +23063 003062 7 JMP .-1 +23064 030004 7 TTSIM /GO BACK TO INPUT MODE +23065 103054 7 JMP DDA4 I + + /START BACKGROUND DDT OUTPUT +23066 005640 7 DOTI: LDA (DOUT) +23067 011164 7 STA LDOT +23070 005641 7 LDA (DIN) +23071 011163 7 STA LDIN +23072 005635 7 LDA (QNUL) +23073 011632 7 STA QPTR +23074 103642 7 JMP (DOTI1) I + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 195 IMP,3050,IMP 7:20 PM 9/16/1973 + + /DDT + /NOTE THAT DDT RUNS WITH INTERRUPTS LOCKED - PI OFF + /IT ALSO RUNS WITH EXTENDED ADDRESSING ENABLED - EA ON + /MAIN LISTEN LOOP + +23075 021046 7 DDA5: JST DDA3 + LCK ALL +23076 021165 7 0 DCLR: JST CRLF /RESTART ENTRY +23077 140040 7 0 CRA +23100 011145 7 0 STA PRS +23101 021261 7 0 LF: JST CLS +23102 005643 7 0 LDA (215) /TYPE A CR +23103 121164 7 0 JST LDOT I +23104 021215 7 0 CLSE: JST CSL +23105 140040 7 0 CRA +23106 011145 7 0 STA PRS +23107 011144 7 0 STA PAR1 +23110 121163 7 0 LSE: JST LDIN I +23111 006752 7 0 ANA C77 +23112 011161 7 0 STA CHARIN +23113 015644 7 0 ADD (DTAB) /DISPATCH TABLE +23114 010000 7 0 STA 0 +23115 044000 7 0 LDA 0 X +23116 100400 7 0 SPL +23117 003122 7 0 JMP DDTDIS /SIGN BIT MEANS ALWAYS DO IT +23120 005162 7 0 LDA BBNF /ELSE ONLY IF OVERRIDDEN OR BBN +23121 021126 7 0 JST SS4ON +23122 044000 7 0 DDTDIS: LDA 0 X +23123 010000 7 0 STA 0 +23124 005161 7 0 LDA CHARIN +23125 042000 7 0 JMP 0 X + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 196 IMP,3050,IMP 7:20 PM 9/16/1973 + +23126 000000 7 0 SS4ON: 0 +23127 101040 7 0 SNZ /A IS 0 IF OK (E.G. BBNF) +23130 103126 7 0 JMP SS4ON I +23131 004473 7 0 LDA OVRDF /ELSE REQUIRE OVERRIDE ON +23132 101040 7 0 SNZ +23133 100002 7 0 SR4 /OR SS4 ON +23134 103126 7 0 JMP SS4ON I /ELSE FALL INTO RUB +23135 005645 7 0 RUB: LDA (243) /TYPE A # +23136 121164 7 0 RUB1: JST LDOT I +23137 021173 7 0 RUB2: JST TAB /AND THREE SPACES +23140 003104 7 0 JMP CLSE + + LEV VAR +23141 V BSS 1 /PARAMETERS STORAGE BLOCK +23142 V BSS 1 +23143 V BSS 1 +23144 V PAR1: BSS 1 +23145 V PRS: BSS 1 /PARAMETER SUPPLIED - 1=> YES (R I' +23146 V SYL: BSS 1 /LAST SYLLABLE TYPED IN +23147 000000 V LAST: 0 /LAST WORD TYPED (CURRENT VALUE OF +23150 000000 V PT: 0 /CURRENT VALUE OF . +23151 000000 V OPEN: 0 /ADDRESS OF OPEN REG (<0 IF NONE) +23152 000000 V DLO: 0 /LOW LIMIT +23153 000000 V DHI: 0 /HI LIMIT +23154 000000 V VAL: 0 /VALUE FOR CLEAR AND SEARCHES +23155 000000 V CNT: 0 /COUNT FOR LOOPING +23156 177777 V SMSK: -1 /MASK FOR SEARCHES +23157 000000 V SP: 0 /LAST DDT START ADDRESS +23160 000000 V SX: 0 /LAST DDT START X REG +23161 V CHARIN: BSS 1 /TEMP INPUT CHARACTER +23162 V BBNF: BSS 1 /0 IF DDT MESS FROM BBN + + LEV CON +23163 024052 C LDIN: DIN /DDT INPUT CHAR ROUTINE +23164 024163 C LDOT: DOUT /DDT OUTPUT CHAR ROUTINE + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 197 IMP,3050,IMP 7:20 PM 9/16/1973 + + /UTILITY SUBROUTINES AND STUFF + + LEV BCK LCK ALL +23165 000000 7 0 CRLF: 0 +23166 005643 7 0 LDA (215) /TYPE A CARRIAGE RETURN +23167 121164 7 0 JST LDOT I +23170 005646 7 0 LDA (212) /AND A LINE FEED +23171 121164 7 0 JST LDOT I +23172 103165 7 0 JMP CRLF I + +23173 000000 7 0 TAB: 0 +23174 005647 7 0 LDA (240) /TYPE THREE SPACES +23175 121164 7 0 JST LDOT I +23176 121164 7 0 JST LDOT I +23177 121164 7 0 JST LDOT I +23200 103173 7 0 JMP TAB I + +23201 000000 7 0 GP: 0 /GET A PARAMETER +23202 007145 7 0 ANA PRS +23203 101040 7 0 DSNZ: SNZ /WAS PARAM SUPPLIED? +23204 025201 7 0 IRS GP /NO, SKIP +23205 045144 7 0 LDA PAR1 X /YES, RETURN VALUE +23206 103201 7 0 JMP GP I + +23207 000000 7 0 GP1: 0 /GET PARAMETER 1 +23210 072113 7 0 LDX ZERO +23211 004114 7 0 LDA ONE +23212 021201 7 0 JST GP +23213 025207 7 0 IRS GP1 /GOT VALUE, GIVE SKIP RETURN +23214 103207 7 0 JMP GP1 I + +23215 000000 7 0 CSL: 0 /COMBINE IN A SYLLABLE +23216 140040 7 0 CRA +23217 027146 7 0 IMA SYL +23220 100000 7 0 CSLX: SKP /SKP (DEFAULT) MEANS DO ADDITION +23221 140407 7 0 TCA /ELSE DO SUBTRACTION +23222 015144 7 0 ADD PAR1 /COMBINE WITH PARAM 1 +23223 011144 7 0 STA PAR1 /ACCUMULATE IN PARAM 1 +23224 004112 7 0 LDA SIGN +23225 011220 7 0 STA CSLX /RESET +/- FLAG +23226 103215 7 0 JMP CSL I + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 198 IMP,3050,IMP 7:20 PM 9/16/1973 + +23227 000000 7 0 PAC: 0 /PRINT ADDRESS AND CONTENTS +23230 140100 7 0 SSP +23231 011244 7 0 STA OPN /SAVE ADDRESS OF REG TO BE PRINTE[ +23232 021165 7 0 JST CRLF /TYPE A CR - LF +23233 005244 7 0 LDA OPN +23234 021302 7 0 JST OPT /TYPE THE ADDRESS IN OCTAL +23235 005650 7 0 LDA (257) /TYPE A / +23236 121164 7 0 JST LDOT I +23237 021207 7 0 JST GP1 +23240 025145 7 0 IRS PRS +23241 005244 7 0 LDA OPN +23242 021244 7 0 JST OPN /OPEN REG AND TYPE CONTENTS +23243 103227 7 0 JMP PAC I + +23244 000000 7 0 OPN: 0 /OPEN A REGISTER AND TYPE ITS CONT 1 +23245 140100 7 0 SSP +23246 011151 7 0 STA OPEN +23247 021207 7 0 JST GP1 +23250 003253 7 0 JMP OPN1 /NO ARG, DON'T RESET . +23251 005151 7 0 LDA OPEN +23252 011150 7 0 STA PT +23253 021173 7 0 OPN1: JST TAB +23254 073151 7 0 LDX OPEN +23255 044000 7 0 LDA 0 X +23256 021302 7 0 JST OPT +23257 021173 7 0 JST TAB +23260 103244 7 0 JMP OPN I + +23261 000000 7 0 CLS: 0 /CLOSE A REGISTER +23262 005651 7 0 LDA (JMP DIG1) +23263 011355 7 0 STA DIG +23264 021215 7 0 JST CSL +23265 005151 7 0 LDA OPEN +23266 101400 7 0 SMI +23267 021207 7 0 JST GP1 +23270 003277 7 0 JMP CLS1 /NO NEW CONTENTS FOR THE REG +23271 011147 7 0 STA LAST +23272 004114 7 0 LDA ONE /REAL OVERRIDE NEEDED +23273 021126 7 0 JST SS4ON +23274 005147 7 0 LDA LAST +23275 073151 7 0 LDX OPEN +23276 050000 7 0 STA 0 X +23277 140500 7 0 CLS1: SSM +23300 011151 7 0 STA OPEN +23301 103261 7 0 JMP CLS I + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 199 IMP,3050,IMP 7:20 PM 9/16/1973 + +23302 000000 7 0 OPT: 0 +23303 011147 7 0 STA LAST +23304 000201 7 0 IAB +23305 072125 7 0 LDX MINUS5 +23306 004121 7 0 LDA MINUS1 +23307 011333 7 0 STA OPTT +23310 005652 7 0 LDA (130) +23311 041077 7 0 LLL 1 +23312 023653 7 0 OPT1: CAS (260) /ZERO? +23313 100000 7 0 SKP +23314 003326 7 0 JMP OPT4 /SEE IF WE SHOULD SUPRESS IT +23315 025333 7 0 IRS OPTT +23316 101000 7 0 DNOP: NOP +23317 121164 7 0 OPT3: JST LDOT I +23320 005654 7 0 OPT2: LDA (26) +23321 041075 7 0 LLL 3 +23322 024000 7 0 IRS 0 +23323 003312 7 0 JMP OPT1 +23324 121164 7 0 JST LDOT I /ALWAYS PRINT LOWEST ORDER DIGIT +23325 103302 7 0 JMP OPT I +23326 025333 7 0 OPT4: IRS OPTT +23327 003317 7 0 JMP OPT3 +23330 004121 7 0 LDA MINUS1 /SUPRESS A ZERO +23331 011333 7 0 STA OPTT +23332 003320 7 0 JMP OPT2 +23333 7 0 OPTT: BSS 1 + +23334 021173 7 0 ASCOUT: JST TAB +23335 005147 7 0 LDA LAST +23336 141140 7 0 ICL +23337 121164 7 0 JST LDOT I +23340 005147 7 0 LDA LAST +23341 141050 7 0 CAL +23342 003136 7 0 JMP RUB1 + +23343 021215 7 0 COM: JST CSL /, DISPATCH +23344 140040 7 0 CRA +23345 027144 7 0 IMA PAR1 +23346 027143 7 0 IMA PAR1-1 +23347 027142 7 0 IMA PAR1-2 +23350 027141 7 0 IMA PAR1-3 +23351 005145 7 0 LDA PRS +23352 041477 7 0 LGL 1 +23353 011145 7 0 STA PRS +23354 003110 7 0 JMP LSE + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 200 IMP,3050,IMP 7:20 PM 9/16/1973 + + /DISPATCHER ROUTINES +23355 7 0 DIG: BSS 1 /JMP DIG1 OR NOP +23356 015146 7 0 ADD SYL +23357 015146 7 0 ADD SYL +23360 040175 7 0 DIG1: LRS 3 /DIGITS DISPATCH +23361 015146 7 0 ADD SYL +23362 041175 7 0 LLS 3 +23363 017655 7 0 SUB (60) +23364 011146 7 0 DIG2: STA SYL +23365 021207 7 0 JST GP1 +23366 025145 7 0 IRS PRS +23367 003110 7 0 JMP LSE + +23370 005316 7 0 DECIN: LDA DNOP +23371 011355 7 0 STA DIG +23372 003110 7 0 JMP LSE + +23373 021215 7 0 EQS: JST CSL /EQUALS DISPATCH +23374 005144 7 0 LDA PAR1 +23375 021302 7 0 JST OPT +23376 003137 7 0 JMP RUB2 + +23377 021215 7 0 PLUS: JST CSL /ADDITION DISPATCH +23400 003110 7 0 JMP LSE + +23401 021215 7 0 MIN: JST CSL /MINUS DISPATCH +23402 005316 7 0 LDA DNOP +23403 011220 7 0 STA CSLX +23404 003110 7 0 JMP LSE + +23405 005150 7 0 PTOP: LDA PT /. DISPATCH +23406 003364 7 0 JMP DIG2 + +23407 073146 7 0 STAR: LDX SYL /* DISPATCH +23410 044000 7 0 LDA 0 X +23411 003364 7 0 JMP DIG2 + +23412 005147 7 0 BARR: LDA LAST / DISPATCH +23413 003364 7 0 JMP DIG2 + +23414 005656 7 0 BOP: LDA (IHTT) /HOST OUTPUT TIMER +23415 003364 7 0 JMP DIG2 /FOR WBB - HOST INTERFACE DEBUG + +23416 105657 7 0 TOP: LDA (WHOTTY) I /TTY OUTPUT SOURCE +23417 003364 7 0 JMP DIG2 /FOR NCC OPS- WHO IS TYPING ON TTY + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 201 IMP,3050,IMP 7:20 PM 9/16/1973 + +23420 021215 7 0 SLH: JST CSL // DISPATCH +23421 021207 7 0 JST GP1 +23422 005147 7 0 LDA LAST +23423 021244 7 0 SLH2: JST OPN +23424 003104 7 0 JMP CLSE + +23425 021215 7 0 BS: JST CSL /BACKSLASH DISPATCH +23426 021207 7 0 JST GP1 +23427 005147 7 0 LDA LAST +23430 011147 7 0 STA LAST +23431 007660 7 0 ANA (1000) /GET PAGE BIT +23432 100040 7 0 SZE /PAGE 0? +23433 005150 7 0 LDA PT /NO, THIS PAGE +23434 013147 7 0 ERA LAST +23435 007661 7 0 ANA (77000) +23436 013147 7 0 ERA LAST +23437 003423 7 0 JMP SLH2 + +23440 021261 7 0 UA: JST CLS /- DISPATCH +23441 004121 7 0 LDA MINUS1 +23442 003445 7 0 JMP CR1 + +23443 021261 7 0 CR: JST CLS /CARRIAGE RETURN DISPATCH +23444 004114 7 0 LDA ONE +23445 015150 7 0 CR1: ADD PT +23446 011150 7 0 STA PT +23447 021227 7 0 JST PAC +23450 003104 7 0 JMP CLSE + +23451 121163 7 0 ASCIN: JST LDIN I +23452 141240 7 0 ICR +23453 011147 7 0 STA LAST +23454 121163 7 0 JST LDIN I +23455 013147 7 0 ERA LAST +23456 011147 7 0 STA LAST +23457 003364 7 0 JMP DIG2 + +23460 021215 7 0 S: JST CSL /S DISPATCH +23461 021207 7 0 JST GP1 +23462 100000 7 0 SKP +23463 011157 7 0 STA SP +23464 004114 7 0 LDA ONE /REAL OVERRIDE, NOT JUST BBNF +23465 021126 7 0 JST SS4ON +23466 072122 7 0 LDX MINUS2 +23467 004117 7 0 LDA FOUR +23470 021201 7 0 JST GP +23471 011160 7 0 STA SX +23472 072121 7 0 LDX MINUS1 +23473 004115 7 0 LDA TWO +23474 021201 7 0 JST GP +23475 101000 7 0 NOP +23476 073160 7 0 LDX SX +23477 103157 7 0 JMP SP I + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 202 IMP,3050,IMP 7:20 PM 9/16/1973 + +23500 021126 7 0 Z: JST SS4ON /A NOT ZERO - REAL OVERRIDE +23501 005662 7 0 LDA (JMP Z1) +23502 003513 7 0 JMP SCH1 +23503 005154 7 0 Z1: LDA VAL +23504 050000 7 0 STA 0 X +23505 003553 7 0 JMP SCH2 + +23506 005526 7 0 W: LDA DSKP +23507 003513 7 0 JMP SCH1 /W DISPATCH +23510 005570 7 0 EQ: LDA DSZE +23511 003513 7 0 JMP SCH1 /E DISPATCH +23512 005203 7 0 NEQ: LDA DSNZ /N DISPATCH +23513 011546 7 0 SCH1: STA SXEC /SET UP TEST +23514 072123 7 0 LDX MINUS3 +23515 004751 7 0 LDA TEN +23516 021201 7 0 JST GP +23517 011156 7 0 STA SMSK /FIRST PARAM - MASK +23520 072122 7 0 LDX MINUS2 +23521 004117 7 0 LDA FOUR +23522 021201 7 0 JST GP +23523 011154 7 0 STA VAL /SECOND PARAM - VALUE +23524 021215 7 0 JST CSL +23525 021207 7 0 JST GP1 +23526 100000 7 0 DSKP: SKP +23527 011153 7 0 STA DHI /FOURTH PARAM - HI BOUND +23530 072121 7 0 LDX MINUS1 +23531 004115 7 0 LDA TWO +23532 021201 7 0 JST GP +23533 011152 7 0 STA DLO /THIRD PARAM - LO BOUND +23534 005152 7 0 LDA DLO +23535 017153 7 0 SUB DHI +23536 016114 7 0 SUB ONE +23537 011155 7 0 STA CNT /LEAVE COUNT IN CNT +23540 101400 7 0 SMI +23541 003135 7 0 JMP RUB /INVERTED BLOCK +23542 073152 7 0 LDX DLO +23543 044000 7 0 SCH3: LDA 0 X +23544 013154 7 0 ERA VAL /COMPARE +23545 007156 7 0 ANA SMSK /MASK OFF BITS TO BE IGNORED +23546 7 0 SXEC: BSS 1 /TEST - SET UP BY CALLS +23547 003553 7 0 JMP SCH2 /FAILURE +23550 004000 7 0 LDA 0 +23551 021227 7 0 JST PAC +23552 073151 7 0 LDX OPEN +23553 024000 7 0 SCH2: IRS 0 +23554 025155 7 0 IRS CNT +23555 003543 7 0 JMP SCH3 +23556 003076 7 0 JMP DCLR + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 203 IMP,3050,IMP 7:20 PM 9/16/1973 + +23557 021126 7 0 DOWNM: JST SS4ON /A NOT ZERO +23560 021215 7 0 JST CSL /S DISPATCH +23561 021207 7 0 JST GP1 +23562 003135 7 0 JMP RUB /MUST HAVE SS4 ON AND GIVE A PARAM +23563 120672 7 0 JST DODXA I RET BCK +23564 121663 7 JST (IHDOWN) I /TELL ALL HOSTS IMP GOING DOWN +23565 000013 7 EXA +23566 003076 7 JMP DCLR + + LCK ALL +23567 004473 7 0 OVRD: LDA OVRDF /O DISPATCH +23570 100040 7 0 DSZE: SZE +23571 003575 7 0 JMP OVRD1 /LEAVING OVERRIDE MODE +23572 005162 7 0 LDA BBNF /FROM BBN +23573 021126 7 0 JST SS4ON +23574 140040 7 0 CRA /THEN YOU CAN ENTER OVERRIDE +23575 013664 7 0 OVRD1: ERA (20) +23576 010473 7 0 STA OVRDF +23577 040677 7 0 ARR 1 +23600 013665 7 0 ERA (306) /MAKE AN N OR AN F +23601 121164 7 0 JST LDOT I /TYPE ON OR OFF +23602 003076 7 0 JMP DCLR + +23603 021215 7 0 C: JST CSL +23604 021207 7 0 JST GP1 /CROSSPATCH +23605 003135 7 0 JMP RUB +23606 007666 7 0 ANA (0 0 177777"X"HICODE) +23607 013667 7 0 ERA (PRIBIT 0 FORIMP) +23610 111670 7 0 STA (HED0) I /SET "FOP IMP" BIT +23611 003076 7 0 JMP DCLR + +23612 021215 7 0 H: JST CSL /SET UP A HEADER +23613 072121 7 0 LDX MINUS1 +23614 004115 7 0 LDA TWO +23615 021201 7 0 JST GP +23616 111671 7 0 STA (MHD0) I +23617 021207 7 0 JST GP1 +23620 100000 7 0 SKP +23621 111672 7 0 STA (MHD1) I +23622 003076 7 0 JMP DCLR + +23623 021126 7 0 QDSP: JST SS4ON +23624 005632 7 0 LDA QPTR /QUIET MODE CONTROL +23625 027164 7 0 IMA LDOT +23626 011632 7 0 STA QPTR +23627 003076 7 0 JMP DCLR + +23630 000000 7 0 QNUL: 0 /NULL SUBROUTINE +23631 103630 7 0 JMP .-1 I + LEV VAR +23632 V QPTR: BSS 1 + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 204 IMP,3050,IMP 7:20 PM 9/16/1973 + +23633 023046 C LEV CON CONSTANTS +23634 023054 C +23635 023630 C +23636 000177 C +23637 000200 C +23640 024163 C +23641 024052 C +23642 024157 C +23643 000215 C +23644 024400 C +23645 000243 C +23646 000212 C +23647 000240 C +23650 000257 C +23651 003360 C +23652 000130 C +23653 000260 C +23654 000026 C +23655 000060 C +23656 016306 C +23657 025506 C +23660 001000 C +23661 077000 C +23662 003503 C +23663 003525 C +23664 000020 C +23665 000306 C +23666 170377 C +23667 140000 C +23670 025165 C +23671 025166 C +23672 025167 C +02432 176700 C PAGEND 23,UNCON,4 + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 205 IMP,3050,IMP 7:20 PM 9/16/1973 + + LEV BCK +24012 120666 7 DIN4: JST SUCK I +24013 140500 7 SSM 0"A"PRIBIT +24014 011050 7 STA DSRC +24015 007500 7 ANA (FRMIMP 0 SRCEHI) +24016 013501 7 ERA (FRMIMP 0 BBNIMP) +24017 100040 7 SZE /SET FLAG IF MESS FROM BBN IMP TTY +24020 013502 7 ERA (0 0 BBNIMP"X"BBNTIP) +24021 100040 7 SZE /SET FLAG IF MESS FROM BBN TIP TTY +24022 013503 7 ERA (FRMIMP 0 BBNTIP"X"PDP1D) +24023 111504 7 STA (BBNF) I /SET FLAG IF MESS FROM BBN IMP HOST +24024 120666 7 JST SUCK I +24025 011051 7 STA DSRC+1 +24026 120666 7 DIN1: JST SUCK I +24027 003040 7 JMP DIN2 +24030 011047 7 STA DINW +24031 141050 7 CAL +24032 101040 7 SNZ +24033 003036 7 JMP DIN3 /NOTHING AT ALL IN THIS WORD +24034 005047 7 LDA DINW +24035 021076 7 JST DINR +24036 025067 7 DIN3: IRS DEND /HAVE OUTPUT CLOSE OFF THEIR MESSAG1 +24037 003012 7 JMP DIN4 /GO BACK FOR NEXT MESSAGE + +24040 011047 7 DIN2: STA DINW /FEED DDT A WORD +24041 021076 7 JST DINR +24042 005047 7 LDA DINW +24043 141340 7 ICA +24044 021076 7 JST DINR +24045 003026 7 JMP DIN1 + + LEV VAR +24046 V DINC: BSS 1 +24047 V DINW: BSS 1 +24050 V DSRC: BSS 2 /DDT DEST/SOURCE + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 206 IMP,3050,IMP 7:20 PM 9/16/1973 + + LEV BCK +24052 000000 7 DIN: 0 /DDT CALLS HERE TO GET A CHARACTER +24053 072114 7 DIN7: LDX ONE +24054 001001 7 INH ALL +24055 120672 7 0 JST DODXA I RET BCK +24056 100000 7 SKP +24057 120665 7 DIN8: JST DOZE I +24060 140040 7 CRA +24061 027067 7 IMA DEND /TIME TO END A MESSAGE? +24062 101040 7 SNZ +24063 003070 7 JMP DIN9 /NO +24064 005505 7 LDA (DIN7) /CLOSE A MESSAGE +24065 011163 7 STA DOUT +24066 003116 7 JMP DOT2 +24067 7 DEND: BSS 1 + +24070 027046 7 DIN9: IMA DINC /INPUT CHAR READY? +24071 101040 7 SNZ +24072 003057 7 JMP DIN8 +24073 001001 7 INH ALL +24074 000013 7 0 EXA +24075 103052 7 0 JMP DIN I + + LEV BCK +24076 000000 7 DINR: 0 /ROUTINE CALLS HERE TO FEED A CHAR +24077 101400 7 SMI +24100 103076 7 JMP DINR I +24101 140100 7 SSP +24102 141140 7 ICL +24103 100040 7 SZE +24104 003110 7 JMP DINA +24105 010472 7 STA DDTI /WE ARE GIVING DDT A "BREAK" +24106 005335 7 LDA LRET +24107 011052 7 STA DIN +24110 011046 7 DINA: STA DINC +24111 120667 7 JST WAIT I /LET DDT GRAB THE CHAR +24112 005046 7 LDA DINC +24113 100040 7 SZE +24114 003111 7 JMP .-3 +24115 103076 7 JMP DINR I + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 207 IMP,3050,IMP 7:20 PM 9/16/1973 + +24116 005207 7 DOT2: LDA DOTW /START HERE TO CLOSE OFF LAST MESSA[ +24117 073506 7 DOT5: LDX (100001) +24120 120664 7 JST JAM I +24121 004112 7 DOT6: LDA SIGN /START HERE WITH EMPTY WORLD +24122 021176 7 JST DOTR +24123 072114 7 LDX ONE +24124 005050 7 LDA DSRC /*SEND DEST HOST +24125 120664 7 JST JAM I /(=SOURCE OF LAST MESS RECVD) +24126 005051 7 LDA DSRC+1 /*SEND DEST LINK +24127 120664 7 JST JAM I /(=LINK OF LAST MESS RECVD) +24130 005507 7 LDA (-500.) /NUMBER OF WORDS PER MESSAGE +24131 011213 7 STA DCNT +24132 005210 7 LDA DOTA +24133 007510 7 ANA (177) +24134 000201 7 IAB +24135 041050 7 DOT3: LLL 24. +24136 013511 7 ERA (100200) +24137 021176 7 JST DOTR +24140 004472 7 LDA DDTI /DDT BEING INTERRUPTED? +24141 100040 7 SZE +24142 003152 7 JMP DOT4 /YES, SUPRESS OUTPUT +24143 000201 7 IAB +24144 072114 7 LDX ONE +24145 120664 7 JST JAM I /*SEND TWO CHARS PER WORD +24146 025213 7 IRS DCNT +24147 003154 7 JMP DOT7 +24150 004112 7 LDA SIGN +24151 003117 7 JMP DOT5 + +24152 005512 7 DOT4: LDA (LSE) +24153 011163 7 STA DOUT +24154 004112 7 DOT7: LDA SIGN +24155 021176 7 JST DOTR +24156 003135 7 JMP DOT3 + +24157 005335 7 DOTI1: LDA LRET +24160 011163 7 STA DOUT +24161 011067 7 STA DEND +24162 003121 7 JMP DOT6 + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 208 IMP,3050,IMP 7:20 PM 9/16/1973 + +24163 000000 7 DOUT: 0 /DDT CALLS HERE WITH A CHAR TO TYPE +24164 011210 7 STA DOTA +24165 007510 7 ANA (177) +24166 013207 7 ERA DOTW +24167 000201 7 IAB +24170 011211 7 STA DOTB +24171 033212 7 STX DOTX +24172 001001 7 INH ALL +24173 120672 7 0 JST DODXA I RET BCK +24174 072114 7 LDX ONE +24175 103176 7 JMP DOTR I + +24176 000000 7 DOTR: 0 /ROUTINES CALL HERE TO RETURN TO DD +24177 011207 7 STA DOTW +24200 005211 7 LDA DOTB +24201 000201 7 IAB +24202 005210 7 LDA DOTA +24203 073212 7 LDX DOTX +24204 001001 7 INH ALL +24205 000013 7 0 EXA +24206 103163 7 0 JMP DOUT I + + LEV VAR +24207 V DOTW: BSS 1 +24210 V DOTA: BSS 1 +24211 V DOTB: BSS 1 +24212 V DOTX: BSS 1 +24213 V DCNT: BSS 1 /NUMBER OF WORDS LEFT IN OUTPUT PAC + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 209 IMP,3050,IMP 7:20 PM 9/16/1973 + + LEV BCK LCK ALL +24214 005337 7 0 QP: LDA QPC1 /QUEUE PRINT +24215 011360 7 0 STA QT1 +24216 005340 7 0 QPQ1: LDA QPC2 +24217 015360 7 0 ADD QT1 +24220 011361 7 0 STA QT2 +24221 010000 7 0 STA 0 +24222 044000 7 0 LDA 0 X +24223 101040 7 0 SNZ +24224 003244 7 0 JMP QPQ3 +24225 121332 7 0 JST QPCR I +24226 004000 7 0 LDA 0 +24227 121333 7 0 JST QPOP I +24230 121334 7 0 JST QPTB I +24231 005513 7 0 LDA (-10) +24232 011362 7 0 STA QT3 +24233 073361 7 0 QPQ2: LDX QT2 +24234 044000 7 0 LDA 0 X +24235 101040 7 0 SNZ +24236 003244 7 0 JMP QPQ3 +24237 011361 7 0 STA QT2 +24240 121333 7 0 JST QPOP I +24241 121334 7 0 JST QPTB I +24242 025362 7 0 IRS QT3 +24243 003233 7 0 JMP QPQ2 +24244 025360 7 0 QPQ3: IRS QT1 +24245 003216 7 0 JMP QPQ1 +24246 005357 7 0 LDA QTB3 +24247 011360 7 0 STA QT1 + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 210 IMP,3050,IMP 7:20 PM 9/16/1973 + +24250 073360 7 0 QPB1: LDX QT1 +24251 045350 7 0 LDA QTB1+QTBL X +24252 011361 7 0 STA QT2 +24253 045357 7 0 LDA QTB2+QTBL X +24254 011362 7 0 STA QT3 +24255 073362 7 0 QPB2: LDX QT3 +24256 044000 7 0 LDA 0 X +24257 101040 7 0 SNZ +24260 003305 7 0 JMP QPB4 +24261 011363 7 0 STA QT4 +24262 005362 7 0 LDA QT3 +24263 010000 7 0 STA 0 +24264 101400 7 0 SMI +24265 003275 7 0 JMP QPB3 +24266 025362 7 0 IRS QT3 +24267 044001 7 0 LDA 1 X +24270 023506 7 0 CAS (100001) +24271 100000 7 0 SKP +24272 003305 7 0 JMP QPB4 +24273 017514 7 0 SUB (BUFE 0 I) +24274 011363 7 0 STA QT4 +24275 121332 7 0 QPB3: JST QPCR I +24276 005362 7 0 LDA QT3 +24277 140100 7 0 SSP +24300 121333 7 0 JST QPOP I +24301 121334 7 0 JST QPTB I +24302 005363 7 0 LDA QT4 +24303 121333 7 0 JST QPOP I +24304 121334 7 0 JST QPTB I +24305 025362 7 0 QPB4: IRS QT3 +24306 025361 7 0 IRS QT2 +24307 003255 7 0 JMP QPB2 +24310 025360 7 0 IRS QT1 +24311 003250 7 0 JMP QPB1 +24312 103335 7 0 JMP QPND I + +24313 073515 7 0 IP: LDX (-IPL) /INTERRUPT PRINT +24314 045400 7 0 IP1: LDA IPT+IPL X +24315 033360 7 0 STX QT1 +24316 121336 7 0 JST QPAC I /PRINT SOME KEY PARAMETERS +24317 073360 7 0 LDX QT1 +24320 024000 7 0 IRS 0 +24321 003314 7 0 JMP IP1 +24322 073516 7 0 LDX (STDIL-0-TASKIL) +24323 044104 7 0 IP2: LDA TASKIL+1 X +24324 033360 7 0 STX QT1 +24325 121336 7 0 JST QPAC I /PRINT ALL INTERRUPT ENTRANCES +24326 073360 7 0 LDX QT1 +24327 024000 7 0 IRS 0 +24330 003323 7 0 JMP IP2 +24331 103335 7 0 JMP QPND I + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 211 IMP,3050,IMP 7:20 PM 9/16/1973 + +24332 023165 7 0 QPCR: CRLF /QUEUE PRINT CONSTANTS AND VARIABLE: +24333 023302 7 0 QPOP: OPT +24334 023173 7 0 QPTB: TAB + LRET: /SAME AS QPND +24335 023076 7 0 QPND: DCLR +24336 023227 7 0 QPAC: PAC +24337 177727 7 0 QPC1: -QUEUEL +24340 000343 7 0 QPC2: QUEUEB+QUEUEL + +24341 177770 7 0 QTB1: -PPTL +24342 177770 7 0 -TH +24343 177770 7 0 -TH +24344 177730 7 0 -[CH"T"NACH] +24345 177774 7 0 -CH+0+1 +24346 177730 7 0 0 0 -2"T"COUNTL +24347 177720 7 0 -PLTNUM +24350 033457 7 0 QTB2: PPT +24351 013333 7 0 HISP +24352 016155 7 0 IHSP +24353 032030 7 0 I2MB0 +24354 100020 7 0 100020 +24355 000517 7 0 COUNTA +24356 033477 7 0 PLT + QTBL=QTB2-0-QTB1 +24357 177771 7 0 QTB3: -QTBL + + LEV VAR +24360 V QT1: BSS 1 +24361 V QT2: BSS 1 +24362 V QT3: BSS 1 +24363 V QT4: BSS 1 + + LEV CON +24364 000134 C IPT: PRIM /INTERRUPT PRINT LOCS +24365 000674 C MP +24366 012654 C OCHN +24367 012604 C I2MSB +24370 000675 C HIP +24371 013106 C HISB +24372 000676 C IHP +24373 016042 C IHSB +24374 020144 C TOK +24375 003412 C FAKENO +24376 004420 C BACKNO +24377 000111 C ADDRET + IPL=.-0-IPT + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 212 IMP,3050,IMP 7:20 PM 9/16/1973 + + + DDOK=100000 + /SIGNBIT ON (DDOK) ==> NON-PRIVELEGED DISPATCH + + LEV CON +24400 123076 C DTAB: DCLR+0+DDOK /@ +24401 123110 C LSE+0+DDOK /A +24402 023414 C BOP /B +24403 123603 C C+0+DDOK /C +24404 023370 C DECIN /D +24405 023510 C EQ /E +24406 123110 C LSE+0+DDOK /F +24407 123110 C LSE+0+DDOK /G +24410 123612 C H+0+DDOK /H +24411 024313 C IP /I +24412 023101 C LF /J - 12 - LINEFEED +24413 123110 C LSE+0+DDOK /K +24414 123612 C H+0+DDOK /L +24415 023443 C CR /M - 15 - CR +24416 023512 C NEQ /N +24417 123567 C OVRD+0+DDOK /O +24420 123110 C LSE+0+DDOK /P +24421 023623 C QDSP /Q +24422 123110 C LSE+0+DDOK /R +24423 023460 C S /S +24424 123416 C TOP+0+DDOK /T +24425 123110 C LSE+0+DDOK /U +24426 123110 C LSE+0+DDOK /V +24427 023506 C W /W +24430 123110 C LSE+0+DDOK /X +24431 123110 C LSE+0+DDOK /Y +24432 023500 C Z /Z +24433 123110 C LSE+0+DDOK /[ +24434 023425 C BS / +24435 123110 C LSE+0+DDOK /] +24436 023440 C UA /~ +24437 023412 C BARR / + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 213 IMP,3050,IMP 7:20 PM 9/16/1973 + +24440 123377 C PLUS+0+DDOK / +24441 024214 C QP /! +24442 023451 C ASCIN /" +24443 123110 C LSE+0+DDOK /# +24444 023557 C DOWNM /$ +24445 123110 C LSE+0+DDOK /% +24446 123110 C LSE+0+DDOK /& +24447 123110 C LSE+0+DDOK /' +24450 123110 C LSE+0+DDOK /( +24451 123110 C LSE+0+DDOK /) +24452 023407 C STAR /* +24453 123377 C PLUS+0+DDOK /+ +24454 123343 C COM+0+DDOK /, +24455 123401 C MIN+0+DDOK /- +24456 023405 C PTOP /. +24457 023420 C SLH // +24460 123355 C DIG+0+DDOK /0 +24461 123355 C DIG+0+DDOK /1 +24462 123355 C DIG+0+DDOK /2 +24463 123355 C DIG+0+DDOK /3 +24464 123355 C DIG+0+DDOK /4 +24465 123355 C DIG+0+DDOK /5 +24466 123355 C DIG+0+DDOK /6 +24467 123355 C DIG+0+DDOK /7 +24470 123355 C DIG+0+DDOK /8 +24471 123355 C DIG+0+DDOK /9 +24472 123110 C LSE+0+DDOK /: +24473 123110 C LSE+0+DDOK /; +24474 123110 C LSE+0+DDOK /< +24475 123373 C EQS+0+DDOK /= +24476 023334 C ASCOUT /> +24477 023135 C RUB /? - 177 - RUBOUT + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 214 IMP,3050,IMP 7:20 PM 9/16/1973 + +24500 040377 C LEV CON CONSTANTS +24501 040005 C +24502 000033 C +24503 040333 C +24504 023162 C +24505 024053 C +24506 100001 C +24507 177014 C +24510 000177 C +24511 100200 C +24512 023110 C +24513 177770 C +24514 100111 C +24515 177764 C +24516 177760 C +02433 174523 C PAGEND 24,UNCON,4 + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 215 IMP,3050,IMP 7:20 PM 9/16/1973 + + + TINT: LEV TTY /TTY INTERRUPT +00063 025061 0 STDIL/ TINT +25061 000000 0 TINT/ INT TTY +25062 011115 0 STA TINA /SAVE A REG +25063 070004 0 TTSRDY +25064 003077 0 JMP TTRT /NOT REALLY A TTY INTERRUPT +25065 140040 0 CRA +25066 022474 0 CAS TTFG /IS TTFG = -1,0,1? +25067 003112 0 JMP TIN1 /-1 WE JUST TYPED A BACKSLASH +25070 003104 0 JMP TIN2 / 0 NORMAL INTERRUPT +25071 030104 0 TTSOM / 1 WE MUST TYPE A BACKSLASH +25072 005511 0 LDA (334) +25073 170004 0 TTOTA +25074 003112 0 JMP TIN1 +25075 004121 0 LDA MINUS1 /SET TTFG TO -1 +25076 010474 0 TIN3: STA TTFG +25077 000043 0 TTRT: INK +25100 171020 0 OTK +25101 005115 0 LDA TINA /RESTORE A REG +25102 000401 0 ENB TTY +25103 103061 0 JMP TINT I + +25104 005503 0 TIN2: LDA OTGO /CHECK HALF-DUPLEX FLAG +25105 100040 0 SZE /ARE WE IN INPUT MODE? +25106 003112 0 JMP TIN1 /NO, THIS IS AN OUTPUT INTERRUPT +25107 131004 0 TTINAC /YES, GET INPUT CHAR +25110 003107 0 JMP .-1 +25111 011116 0 STA TTCR /SAVE IT +25112 030004 0 TIN1: TTSIM +25113 004114 0 LDA ONE /SET TTFG TO 1 +25114 003076 0 JMP TIN3 + LEV VAR +25115 V TINA: BSS 1 /TTY INT SAVED A REG +25116 V TTCR: BSS 1 /RAW TTY INPUT CHAR + + /OTGO IS THE STATE OF THE HALF-DUPLEX INTERFACE + /0=EXPECTING INPUT, 1=HAVE DONE OUTPUT + + /TTFG IS THE COMMUNICATION FLAG BETWEEN + /THE TTY INTERRUPT HANDLER AND THE BACKGROUND TTY PROCESSING + /AT INTERRUPT TIME: + /-1= LAST ACTION WAS TO TYPE A BACKSLASH, NOW 1=>TTFG + / 0= NORMAL - BACKGROUND IS READY FOR TTY INT, NOW 1=>TTFG + / 1= A SECOND TTY INT CAME IN BEFORE BACKGROUND CAUGHT UP + / SO TYPE A BACKSLASH, NOW -1=>TTFG + /AT BACKGROUND LEVEL: + /USE A CRA, IMA TTFG SEQUENCE TO INTERROGATE TTY + /0=>TTFG, USE CHAR IF TTFG WAS = 1 + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 216 IMP,3050,IMP 7:20 PM 9/16/1973 + + LEV BCK +25117 140040 7 TTYI: CRA /TELETYPE INPUT STARTS HERE +25120 011503 7 STA OTGO +25121 010673 7 STA HSFG +25122 011504 7 STA HSGO +25123 011163 7 STA TTCH +25124 111512 7 STA (DINC) I +25125 004106 7 LDA MINE +25126 013513 7 ERA (PRIBIT 0 FORIMP) +25127 111514 7 STA (DSRC) I +25130 012753 7 ERA C100 +25131 011165 7 STA HED0 +25132 005515 7 LDA (40) +25133 170020 7 SMK 20 /ENABLE TTY INTERRUPTS ONLY +25134 003174 7 JMP TTI3 /GO FIRE OFF A DUMMY MSG TO DDT + +25135 005170 7 IND1: LDA TTI2 +25136 011160 7 STA INDB +25137 000401 7 TTI1: ENB BCK +25140 072113 7 LDX ZERO +25141 120665 7 JST DOZE I /WAIT FOR NEXT INPUT CHAR +25142 005503 7 LDA OTGO /OUTPUT ACTIVE? +25143 100040 7 SZE +25144 003137 7 JMP TTI1 /YES +25145 001001 7 INH TTY +25146 026474 7 0 IMA TTFG /TTY HAVE SOMETHING FOR US?? +25147 101400 7 0 SMI /IF TTFG= -1, NO +25150 101040 7 0 SNZ /IF TTFG= 0, NO +25151 003137 7 0 JMP TTI1 /NO +25152 005116 7 0 LDA TTCR /IF TTFG= 1, YES +25153 007516 7 0 ANA (177) /PUT IN PARITY BIT +25154 013517 7 0 ERA (200) +25155 011163 7 0 STA TTCH +25156 000401 7 0 ENB BCK +25157 103160 7 JMP INDB I /GO PROCESS THE CHAR + +25160 000000 7 INDB: 0 /COME HERE TO GET NEXT CHAR FROM TT +25161 011164 7 STA TTIW /SAVE THE INPUT WORD SO FAR +25162 003137 7 JMP TTI1 + + LEV VAR +25163 V TTCH: BSS 1 /RAW TTY INPUT CHAR+PARITY BIT +25164 V TTIW: BSS 1 +25165 V HED0: BSS 1 /CROSSPATCH HEADER +25166 V MHD0: BSS 1 /MESSAGE HEADER +25167 V MHD1: BSS 1 + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 217 IMP,3050,IMP 7:20 PM 9/16/1973 + + MSGT=273 /SEMI + NUMB=272 /COLON + LEV BCK +25170 025171 7 TTI2: .+1 /PLACE TO START BUILDING NEW MESSAGI +25171 023520 7 CAS (MSGT) /IS IT A MESSAGE INITIATOR? +25172 100000 7 SKP +25173 003221 7 JMP MSG /YES + + /SEND A SINGLE CHAR MESSAGE +25174 005165 7 TTI3: LDA HED0 /*SEND CROSSPATCH HEADER +25175 120664 7 JST JAM I +25176 140040 7 CRA /*SEND ON LINK ZERO +25177 120664 7 JST JAM I +25200 005163 7 LDA TTCH +25201 013517 7 ERA (200) +25202 100040 7 SZE /IS THE CHAR TO SEND A BREAK? +25203 003207 7 JMP TTI5 /NO +25204 004106 7 LDA MINE /YES, RESET CROSSPATCH HEADER TO [ 1 +25205 013521 7 ERA (PRIBIT 0 FORIMP 100) +25206 011165 7 STA HED0 /DDT AT SELF - PRIORITY +25207 005163 7 TTI5: LDA TTCH +25210 140500 7 SSM +25211 141340 7 ICA +25212 011164 7 STA TTIW +25213 140040 7 CRA +25214 011504 7 STA HSGO +25215 005164 7 MSG2: LDA TTIW /*SEND 1 CHAR MESSAGE +25216 072112 7 LDX SIGN /CLOSE OFF THE MESSAGE +25217 120664 7 JST JAM I +25220 003135 7 JMP IND1 + + /SEND A SEMICOLON MESSAGE - MULTI-CHARACTER +25221 004673 7 MSG: LDA HSFG /SEND A MESSAGE +25222 011504 7 STA HSGO +25223 005166 7 LDA MHD0 /*SEND MESSAGE HOST +25224 120664 7 JST JAM I +25225 005167 7 LDA MHD1 /*SEND MESSAGE LINK +25226 120664 7 JST JAM I +25227 004112 7 MSG0: LDA SIGN +25230 021277 7 JST MSG1 /GET ONE CHAR +25231 140500 7 SSM /PUT IN PARITY +25232 141340 7 ICA /SAVE +25233 021277 7 JST MSG1 /GET OTHER CHAR +25234 013517 7 ERA (200) /PUT IN PARITY +25235 013164 7 ERA TTIW +25236 120664 7 JST JAM I /*SEND NEXT TWO CHARS +25237 003227 7 JMP MSG0 /GO BACK FOR MORE + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 218 IMP,3050,IMP 7:20 PM 9/16/1973 + +25240 140040 7 MSG3: CRA /BUILD A NUMBER +25241 021277 7 MSG4: JST MSG1 /GET NEXT CHAR +25242 023522 7 CAS (215) /CR? +25243 100000 7 SKP /NO +25244 003253 7 JMP MSG5 /YES, END OF THE NUMBER +25245 001001 7 INH ALL /USING B REG - MUST LOCK INTS +25246 040075 7 0 LRL 3 +25247 005164 7 0 LDA TTIW +25250 041075 7 0 LLL 3 +25251 000401 7 0 ENB BCK +25252 003241 7 JMP MSG4 + +25253 070104 7 MSG5: TTSNBZ /ECHO CR WITH A LF +25254 003274 7 JMP MSG6 /FORGET IT +25255 030104 7 TTSOM +25256 005523 7 LDA (212) +25257 170004 7 TTOTA +25260 003257 7 JMP .-1 +25261 025503 7 IRS OTGO +25262 120665 7 MSG7: JST DOZE I /WAIT FOR CHAR TO TYPE OUT +25263 140040 7 CRA +25264 026474 7 IMA TTFG +25265 101040 7 SNZ /HAS TTY INTERRUPTED? +25266 003262 7 JMP MSG7 /NOT YET, WAIT +25267 005503 7 LDA OTGO /NOW UNSTEP OUTPUT FLAG +25270 016114 7 SUB ONE +25271 100400 7 SPL +25272 140040 7 CRA +25273 011503 7 STA OTGO +25274 005164 7 MSG6: LDA TTIW /ADD NUMBER TO MESSAGE +25275 120664 7 JST JAM I +25276 003227 7 JMP MSG0 + +25277 000000 7 MSG1: 0 /SUBR TO GET NEXT CHAR FOR MESSAGE +25300 021160 7 JST INDB /GET THE CHAR +25301 023520 7 CAS (MSGT) /IS IT MESSAGE TERMINATOR? +25302 100000 7 SKP /NO +25303 003215 7 JMP MSG2 /YES, DONE - LEAP INTO INDB CODE +25304 023524 7 CAS (NUMB) /IS IT NUMBER INDICATOR? +25305 103277 7 JMP MSG1 I /NO, RETURN WITH CHAR +25306 003240 7 JMP MSG3 /YES, PUT AN OCTAL NUMBER IN THE ME +25307 103277 7 JMP MSG1 I /NO, RETURN WITH CHAR + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 219 IMP,3050,IMP 7:20 PM 9/16/1973 + +25310 072113 7 TTO0: LDX ZERO /TELETYPE OUTPUT ROUTINES +25311 033505 7 STX TTNM /CLEAR FLAG +25312 120666 7 JST SUCK I /WAIT FOR SOME OUTPUT TO HAPPEN +25313 025503 7 IRS OTGO /GRAB THE TTY +25314 011501 7 STA TTOW +25315 007525 7 ANA (SRCEHI) +25316 022106 7 CAS MINE /NOT IF FROM US +25317 022752 7 CAS C77 /NOT IF NON-TTY +25320 003323 7 JMP TTO01 +25321 101000 7 NOP +25322 011506 7 STA WHOTTY /LAST FOREIGN IMP TTY TO SEND TO TT' +25323 120667 7 TTO01: JST WAIT I +25324 005501 7 LDA TTOW +25325 041475 7 LGL 3 0"A"FOROCT +25326 011502 7 STA OCTL +25327 101400 7 SMI +25330 005504 7 LDA HSGO + /MAKE A SKP TO SEE ALL I2H MESSAGES - RFNMS FOR SINGLE CHA[ +25331 101040 7 SNZ +25332 003353 7 JMP TTO2 +25333 005522 7 LDA (215) +25334 021450 7 JST SEND +25335 005523 7 LDA (212) +25336 021450 7 JST SEND +25337 005523 7 LDA (212) +25340 021450 7 JST SEND +25341 005501 7 LDA TTOW +25342 021412 7 JST OCTO +25343 120666 7 JST SUCK I +25344 100000 7 SKP +25345 003350 7 JMP TTO7 +25346 021412 7 JST OCTO +25347 003356 7 JMP TTO3 + +25350 025505 7 TTO7: IRS TTNM /SET END FLAG +25351 021412 7 JST OCTO +25352 003370 7 JMP TTO5 + +25353 120666 7 TTO2: JST SUCK I /FROM DDT: SKIP OVER REST OF LEAD[ +25354 100000 7 SKP +25355 003437 7 JMP TTO8 +25356 120666 7 TTO3: JST SUCK I +25357 003374 7 JMP TTO4 /MORE MESSAGE +25360 025505 7 IRS TTNM +25361 011501 7 STA TTOW /DONE +25362 141050 7 CAL +25363 101040 7 SNZ +25364 003370 7 JMP TTO5 +25365 005501 7 LDA TTOW /GET LAST CHAR +25366 141140 7 ICL +25367 021450 7 JST SEND +25370 140040 7 TTO5: CRA +25371 011503 7 STA OTGO +25372 011502 7 STA OCTL +25373 003310 7 JMP TTO0 + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 220 IMP,3050,IMP 7:20 PM 9/16/1973 + + LEV BCK +25374 011501 7 TTO4: STA TTOW /SEND ANOTHER WORD OF THE MESSAGE +25375 005502 7 LDA OCTL +25376 100400 7 SPL +25377 003407 7 JMP TTO6 +25400 005501 7 LDA TTOW +25401 141140 7 ICL +25402 021450 7 JST SEND +25403 005501 7 LDA TTOW +25404 141050 7 CAL +25405 021450 7 JST SEND +25406 003356 7 JMP TTO3 + +25407 005501 7 TTO6: LDA TTOW +25410 021412 7 JST OCTO +25411 003356 7 JMP TTO3 + +25412 000000 7 OCTO: 0 /OCTAL OUTPUT +25413 000201 7 IAB +25414 004126 7 LDA MINUS6 +25415 011507 7 STA OCO1 +25416 005526 7 LDA (130) +25417 041077 7 LLL 1 +25420 000201 7 OCO2: IAB +25421 011510 7 STA OCO3 +25422 000201 7 IAB +25423 021450 7 JST SEND +25424 005510 7 LDA OCO3 +25425 000201 7 IAB +25426 005527 7 LDA (26) +25427 041075 7 LLL 3 +25430 025507 7 IRS OCO1 +25431 003420 7 JMP OCO2 +25432 005522 7 LDA (215) +25433 021450 7 JST SEND +25434 005523 7 LDA (212) +25435 021450 7 JST SEND +25436 103412 7 JMP OCTO I + +25437 025505 7 TTO8: IRS TTNM +25440 005501 7 LDA TTOW +25441 007530 7 ANA (IHCODE) +25442 013531 7 ERA (CINCTR) +25443 100040 7 SZE /BLOCKED OR LOST? +25444 003370 7 JMP TTO5 /NO +25445 005511 7 LDA (334) /YES, TYPE A BACKSLASH SINCE OUR ME +25446 021450 7 JST SEND +25447 003370 7 JMP TTO5 + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 221 IMP,3050,IMP 7:20 PM 9/16/1973 + +25450 000000 7 SEND: 0 /SUBR TO TYPE OUT A CHAR +25451 023517 7 CAS (200) /'200 BIT SET? +25452 101000 7 NOP +25453 100000 7 SKP +25454 103450 7 JMP SEND I /NO, IGNORE THE CALL +25455 072113 7 LDX ZERO +25456 070104 7 TTSNBZ +25457 003472 7 JMP SND2 /INTERRUPTING OUTPUT! +25460 030104 7 TTSOM +25461 170004 7 TTOTA +25462 003472 7 JMP SND2 +25463 120667 7 SND3: JST WAIT I /WAIT FOR CHAR TO GO OUT +25464 140040 7 CRA +25465 026474 7 IMA TTFG +25466 101400 7 SMI +25467 101040 7 SNZ +25470 003463 7 JMP SND3 +25471 103450 7 JMP SEND I + +25472 005505 7 SND2: LDA TTNM /AT END OF MSG? +25473 100040 7 SZE +25474 003370 7 JMP TTO5 /YES, NO MSG TO SKIP +25475 120666 7 JST SUCK I /SKIP REST OF MESSAGE +25476 003472 7 JMP SND2 +25477 010472 7 STA DDTI +25500 003370 7 JMP TTO5 /AND CONTINUE LOOKING FOR A NEW MES + + LEV VAR +25501 V TTOW: BSS 1 +25502 V OCTL: BSS 1 +25503 V OTGO: BSS 1 +25504 V HSGO: BSS 1 +25505 V TTNM: BSS 1 /END OF MSG IF NON ZERO +25506 000000 V WHOTTY: 0 /LAST FOREIGN TYPIST ON THIS TTY +25507 V OCO1: BSS 1 +25510 V OCO3: BSS 1 + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 222 IMP,3050,IMP 7:20 PM 9/16/1973 + +25511 000334 C LEV CON CONSTANTS +25512 024046 C +25513 140000 C +25514 024050 C +25515 000040 C +25516 000177 C +25517 000200 C +25520 000273 C +25521 140100 C +25522 000215 C +25523 000212 C +25524 000272 C +25525 000377 C +25526 000130 C +25527 000026 C +25530 007400 C +25531 004400 C +02434 174532 C PAGEND 25,UNCON + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 223 IMP,3050,IMP 7:20 PM 9/16/1973 + + + + /NEW ROUTING + /THESE ROUTINES BUILD TWO MAIN TABLES + + + /RUT - ROUTE USE TABLE, THE BEST LINE DIRECTORY + /RST - ROUTE SEND TABLE, THE HOPS/DELAY INFORMATION UPDATE M[ + /THE NEW VALUE OF HOPS AND DELAY ON THE BEST LINES FOR EAC1 , + /RSTN - THE RST NEW TABLE + / THE IDENTITY OF THE BEST LINE FOR EACH IS KEPT IN + /RUTW - THE RUT WORKING TABLE + + /A NAMING CONVENTION -- TAGS LIKE RST.N AND RST.W ARE INDIRET + /POINTERS [FOR '.' READ "POINT"], POST-INDEXED BY NEGATIVE 1 + /RST.N IS THUS THE RST POINTER TO THE NEW TABLE + + /BITS IN RUT + RUTDED=100000 /THIS IMP IS DOWN,UNREACHABLE OR NO1 + RUTGOD=60000 /GOING-DOWN DELAY CNTR - EVERY 4TH ] + RUTGD1=20000 /LOW ORDER BIT OF RUTGOD + RUTHPC=17400 /LINE # +1 OF SHORTEST HOP PATH + RUTCMU=340 /COMING-UP DELAY COUNTER - EVERY 8T1 + RUTCM1=40 /LOW ORDER BIT OF RUTCMU + RUTDLC=37 /LINE # +1 OF BEST DELAY PATH + RUTUS=0 + + /BITS IN RUTW + RUTHPH=60000 /HOLD-DOWN TIMER FOR MIN HOP PATH + RTHPH1=20000 /LOW ORDER BIT OF RUTHPH + RUTDLH=140 /HOLD-DOWN TIMER FOR MIN DELAY PATH + RTDLH1=40 /LOW ORDER BIT OF RUTDLH + + /BITS IN RST, RSTN + HOPS=174000 /5 BITS OF HOP COUNT + HOPS1=4000 /LOW ORDER BIT OF HOPS + DELS=3777 /11 BITS OF DELAY COUNT + + /BITS IN ROUTING MSG + /IN HEAD1 + RMSN=177400 /RM SERIAL # + RMSN1=400 /LOW-ORDER BIT IF SER # + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 224 IMP,3050,IMP 7:20 PM 9/16/1973 + + /RUTINI IS AN INITIALIZATION ROUTINE TO SET UP + /THE ROUTING TABLES + LEV BCK LCK INI +26070 000000 7 0 RUTINI: 0 +26071 005645 7 0 LDA (RST 0 NIMP X) +26072 010660 7 0 STA RST.O +26073 005646 7 0 LDA (RST1 0 NIMP X) +26074 010661 7 0 STA RST.F +26075 005647 7 0 LDA (RST2 0 NIMP X) +26076 010662 7 0 STA RST.N +26077 073346 7 0 LDX NEGIMP /LOOP OVER ALL IMPS +26100 005637 7 0 RUTINL: LDA CDEAD /(100000) +26101 050265 7 0 STA RUT+NIMP X 0"A"RUTDED +26102 140040 7 0 CRA +26103 051500 7 0 STA RUTW+NIMP X +26104 005640 7 0 LDA CMAXHD /(177777) +26105 110660 7 0 STA RST.O I +26106 110661 7 0 STA RST.F I +26107 110662 7 0 STA RST.N I +26110 024000 7 0 IRS 0 +26111 003100 7 0 JMP RUTINL +26112 072106 7 0 LDX MINE +26113 140040 7 0 CRA 0"A"RUTUS +26114 011644 7 0 STA RSTSN /START SER # AT 0 +26115 050165 7 0 STA RUT X /CLEAR RUT +26116 111650 7 0 STA (RST2 0 X) I /AND RSTN +26117 103070 7 0 JMP RUTINI I + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 225 IMP,3050,IMP 7:20 PM 9/16/1973 + + /RSTINP IS A ROUTINE TO COPY A RECIEVED ROUTING MESSAGE INTO + /RSTN, RSTW AND RUTW TABLES. + CHK=0 + LEV T.O +26120 000000 5 RSTINP: 0 +26121 033365 5 RSTCK1: K STX LINEX /SAVE LINE# +26122 011372 5 K STA RST.I /SAVE AC FLAG +26123 073342 5 K LDX RSTCKX /(RSTCK1-0-RSTCK2-1) +26124 140040 5 K CRA /CALCULATE CHECKSUM FOR THIS CODE +26125 055365 5 K ADD RSTCK2+1 X +26126 024000 5 K IRS 0 +26127 003125 5 K JMP .-2 +26130 100040 5 K SZE /DIFFERENT? + RELOAD [RUTINP CODE BROKEN] +26131 120061 5 K JST SWDTIL I /YES, RELOAD +26132 073365 5 K LDX LINEX /RESTORE LINE # IN X +26133 045500 5 K LDA CED X /PICK UP COMPUTED EFFECTIVE DELAY +26134 141206 5 K AOA +26135 011366 5 K STA DELOUR /AND SAVE IT +26136 004000 5 K LDA 0 +26137 141206 5 K AOA +26140 011367 5 K STA CHANR /SAVE CHAN=+1 IN RT HALF +26141 141340 5 K ICA +26142 011370 5 K STA CHANL /ALSO IN LEFT HALF +26143 013367 5 K ERA CHANR +26144 011371 5 K STA CHANB /SAVE CHAN=+1 IN BOTH HALVES +26145 005372 5 K LDA RST.I /PICK UP FLAG +26146 101040 5 K SNZ /WERE WE CALLED BY TASK? +26147 003152 5 K JMP RSTI1 /YES, TRUE INPUT +26150 005344 5 K LDA DUMYIN /NO, MAKE UP DUMMY INPUT OF ALL 1: +26151 003167 5 K JMP RSTI2 +26152 044433 5 RSTI1: K LDA LINE X +26153 100040 5 K SZE /IS LINE DOWN? +26154 103120 5 K JMP RSTINP I /YES, IGNORE ROUTING +26155 072514 5 K LDX THIS /GET PKT PTR +26156 044006 5 K LDA HEAD1 X /TO RM +26157 141044 5 K CAR 0"A"RMSN /EXTRACT SERIAL # +26160 073365 5 K LDX LINEX +26161 067505 5 K IMA RSTSNI X /SAVE AS LATEST INPUT # +26162 053505 5 K ERA RSTSNI X /COMPARE W/ PREV # +26163 101040 5 K SNZ /NEW? +26164 103120 5 K JMP RSTINP I /NO, WE SAW IT BEFORE***NOP ON REI' +26165 004514 5 K LDA THIS /BUILD POST INDEXED PTR TO PKT +26166 015343 5 K ADD RSTCP1 /(HEAD2 0 NIMP X) +26167 011372 5 RSTI2: K STA RST.I +26170 073346 5 K LDX NEGIMP /LOOP OVER ALL IMPS + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 226 IMP,3050,IMP 7:20 PM 9/16/1973 + +26171 105372 5 COPYL: K LDA RST.I I /GET ENTRY FROM RECEIVED ROUTING +26172 007347 5 K ANA HOPM /(174000) +26173 015353 5 K ADD HOPM1 /(4000) ADD IN OUR HOP +26174 101040 5 K SNZ /MAX VALUE? +26175 005347 5 K LDA HOPM /YES +26176 011373 5 K STA HOPIN /SAVE RECEIVED HOP COUNT +26177 141340 5 K ICA +26200 011374 5 K STA HOPINS +26201 105372 5 K LDA RST.I I /EXTRACT RECEIVED DELAY +26202 007350 5 K ANA DELM +26203 015366 5 K ADD DELOUR /ADD IN LOCAL DELAY +26204 023350 5 K CAS DELM /(3777) +26205 005350 5 K LDA DELM /TRUNCATE AT MAX DELAY +26206 101000 5 K NOP +26207 011375 5 K STA DELIN /SAVE TOTAL DELAY +26210 005371 5 K LDA CHANB /COMPARE THIS LINE # +26211 052265 5 K ERA RUT+NIMP X /...WITH PREVIOUS BEST FO1 +26212 007363 5 K ANA CHANM /(17437)EXTRACT LINE FIELDS ONLY +26213 023352 5 K CAS BSTDEL /(37)THIS MIN HOP LINE? +26214 003262 5 K JMP COPY11 /NO, SEE IF IT HAS GOOD DATA +26215 101000 5 K NOP +26216 011376 5 K STA CHANS /SAVE + /THIS LINE IS PREVIOUS BEST FOR HOPS +26217 104662 5 COPY1: K LDA RST.N I +26220 007350 5 K ANA DELM /EXTRACT OLD DELAY +26221 013373 5 K ERA HOPIN /PUT IN NEW HOPS +26222 126662 5 K IMA RST.N I /SAVE IN RSTN +26223 007347 5 K ANA HOPM +26224 141340 5 K ICA +26225 017374 5 K SUB HOPINS /COMPARE +26226 100400 5 K SPL /CHANGED? +26227 003252 5 K JMP HOLD1 /YES, IF HOPS WORSE DO HOLD-DOWN +26230 005376 5 COPY2: K LDA CHANS /LOOK AI OUR CHAN +26231 100040 5 K SZE /IS IT THE BEST DELAY? +26232 003320 5 K JMP COPY21 /NO + /THIS LINE PREVIOUS BEST FOR DELAY +26233 104662 5 K LDA RST.N I /YES +26234 007347 5 K ANA HOPM /EXTRACT OLD HOPS +26235 013375 5 K ERA DELIN /PUT IN NEW DELAY +26236 126662 5 K IMA RST.N I /SAVE IN RSTN +26237 007350 5 K ANA DELM +26240 017375 5 K SUB DELIN /COMPARE +26241 015351 5 K ADD DELCLP /ALLOW FOR SMALL CHANGE W/O HLDDWN +26242 100400 5 K SPL /DELAY GET MUCH WORSE? +26243 003310 5 K JMP HOLD2 /Y, DO HOLD-DOWN +26244 024000 5 COPYI: K IRS 0 /LOOP OVFR ALL IMPS +26245 003171 5 K JMP COPYL +26246 025377 5 K IRS RSTINC /COUNT ANOTHER INPUT COPY COMPLETE +26247 101000 5 K NOP +26250 073365 5 K LDX LINEX /RESTORE X +26251 103120 5 K JMP RSTINP I /RETURN TO TASK + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 227 IMP,3050,IMP 7:20 PM 9/16/1973 + + /THIS LINE WAS PREVIOUS BEST FOR HOPS, HOPS CHANGED +26252 045500 5 HOLD1: K LDA RUTW+NIMP X /HOPS GOT WORSE +26253 007356 5 K ANA HLDH /GET HOLD-DOWN TIMER +26254 100040 5 K SZE /ON? +26255 003230 5 K JMP COPY2 /Y, GO ON TO DELAY +26256 005356 5 K LDA HLDH /N, TURN IT ON +26257 053500 5 K ERA RUTW+NIMP X /...AND SAVE IN RUTW +26260 051500 5 K STA RUTW+NIMP X +26261 003230 5 K JMP COPY2 + + /THIS LINE WAS NOT PREVIOUS BEST FOR HOPS +26262 007352 5 COPY11: K ANA BSTDEL /TURN OFF HOP CHAN BITS +26263 011376 5 K STA CHANS /SAVE IN CHANS +26264 045500 5 K LDA RUTW+NIMP X +26265 007356 5 K ANA HLDH /GET HOLD-DOWN TIMER FOR HOPS +26266 100040 5 K SZE +26267 003230 5 K JMP COPY2 /NOT 0, GO DO DELAY NEXT + /NOT PREVIOUS BEST HOPS, NOT HOLDING +26270 104662 5 K LDA RST.N I +26271 007347 5 K ANA HOPM /EXTRACT CURRENT HOPS ON BEST +26272 141340 5 K ICA +26273 023374 5 K CAS HOPINS /COMPARE W/ RCVD HOPS +26274 003277 5 K JMP COPY13 /RCVD HOPS BETTER +26275 003230 5 K JMP COPY2 /NO BETTER, DO DELAY NEXT +26276 003230 5 K JMP COPY2 /DITTO + + /NOT PREVIOUS BEST HOPS, NOT HOLDING, BETTER THAN PREVIOUS +26277 141340 5 COPY13: K ICA +26300 112662 5 K ERA RST.N I /EXTRACT OLD BEST DELAY +26301 013373 5 K ERA HOPIN /PUT IN NEW HOPS +26302 110662 5 K STA RST.N I /SAVE IN RSTN +26303 044265 5 K LDA RUT+NIMP X +26304 007361 5 K ANA CHANML /(160377)EXTRACT CHAN OF MIN DELA1 +26305 013370 5 K ERA CHANL /UPDATE CHAN OF MIN HOPS +26306 050265 5 K STA RUT+NIMP X /SAVE IN RUT +26307 003230 5 K JMP COPY2 + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 228 IMP,3050,IMP 7:20 PM 9/16/1973 + + /THIS LINE WAS PREVIOUS BEST FOR DELAY, DELAY GOT WORSE +26310 045500 5 HOLD2: K LDA RUTW+NIMP X /DELAY GOT WORSE +26311 007357 5 K ANA HLDD /GET DELAY HOLD-DOWN TIMER +26312 100040 5 K SZE /IS IT ON? +26313 003244 5 K JMP COPYI /YES, GO ON TO NEXT IMP +26314 005357 5 K LDA HLDD /NO, TURN IT ON +26315 053500 5 K ERA RUTW+NIMP X /SAVE IN RUTW +26316 051500 5 K STA RUTW+NIMP X +26317 003244 5 K JMP COPYI + + /THIS LINE WAS NOT PREVIOUS BEST FOR DELAY +26320 045500 5 COPY21: K LDA RUTW+NIMP X +26321 007357 5 K ANA HLDD /GET DELAY HOLD-DOWN TIMER +26322 100040 5 K SZE +26323 003244 5 K JMP COPYI /NOT 0, GO TO NEXT IMP + /NOT PREVIOUS BEST DELAY, NOT HOLDING +26324 104662 5 K LDA RST.N I +26325 007350 5 K ANA DELM /EXTRACT CURRENT DELAY ON BEST +26326 023375 5 K CAS DELIN /COMP W/ RCVD DELAY +26327 003332 5 K JMP COPY23 /RCVD DELAY BETTER +26330 003244 5 K JMP COPYI /NO BETTER. GO ON TO NEXT IMP +26331 003244 5 K JMP COPYI /DITTO + + /NOT PREV BEST DELAY, NOT HOLDING, BETTER THAN PREVIOUS +26332 112662 5 COPY23: K ERA RST.N I /EXTRACT OLD BEST HOP COUNT +26333 013375 5 K ERA DELIN /PUT IN NEW DELAY +26334 110662 5 K STA RST.N I /SAVE IN RSTN +26335 044265 5 K LDA RUT+NIMP X +26336 007360 5 K ANA CHANMR /(177740)EXTRACT CHAN OF MIN HOP +26337 013367 5 K ERA CHANR /UPDATE CHAN OF BEST DELAY +26340 050265 5 K STA RUT+NIMP X /SAVE IN RUT +26341 003244 5 K JMP COPYI /GO ON TO NEXT IMP + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 229 IMP,3050,IMP 7:20 PM 9/16/1973 + + LEV CON +26342 177534 C RSTCKX: K RSTCK1-0-RSTCK2-1 +26343 040107 C RSTCP1: K HEAD2 0 NIMP X +26344 026345 C DUMYIN: K .+1 /PTR TO DUMMY MAX INPUT +26345 177777 C K HOPS+0+DELS +26346 177700 C NEGIMP: K -NIMP +26347 174000 C HOPM: K HOPS +26350 003777 C DELM: K DELS +26351 000010 C DELCLP: K 10 /SMALL CHANGE TO DELAY IS OK +26352 000037 C BSTDEL: K RUTDLC +26353 004000 C HOPM1: K HOPS1 /4000 +26354 020000 C HLDH1: K RTHPH1 /20000 +26355 000040 C HLDD1: K RTDLH1 /40 +26356 060000 C HLDH: K RUTHPH /60000 +26357 000140 C HLDD: K RUTDLH /140 +26360 177740 C CHANMR: K 0 0 177777"X"RUTDLC +26361 160377 C CHANML: K 0 0 177777"X"RUTHPC +26362 160340 C CHANMB: K 0 0 177777"X"RUTDLC"X"RUTHPC +26363 017437 C CHANM: K 0 0 RUTDLC"X"RUTHPC +26364 104676 C RSTCK2: -CHK + + LEV VAR +26365 V LINEX: BSS 1 /INPUT LINE= (0 TO CH-1) +26366 V DELOUR: BSS 1 /OUR LOCAL DELAY OUT OF THIS LINE +26367 V CHANR: BSS 1 /THIS LINE # +1, IN RIGHT HALF +26370 V CHANL: BSS 1 / LEFT +26371 V CHANB: BSS 1 / BOTH HALVES +26372 V RST.I: BSS 1 /RST POINTER TO INPUT MESSAGE +26373 V HOPIN: BSS 1 /RCVD HOP COUNT TO THIS IMP +26374 V HOPINS: BSS 1 /HOPIN WITH HALVES SWAPPED +26375 V DELIN: BSS 1 /RCVD DELAY TO THIS IMP PLUS LOCAL +26376 V CHANS: BSS 1 /TEMP = XOR(INPUT LINE, RUT ENTRY) +26377 V RSTINC: BSS 1 /COUNTER OF CALLS OF RSTIN FOR AL1 +26400 V RUTW: BSS NIMP +26500 V CED: BSS CH /COMPUTED EFFECTIVE DELAY +26505 V RSTSNI: BSS CH /SERIAL # OF LAST RM INPUT + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 230 IMP,3050,IMP 7:20 PM 9/16/1973 + + CHK=0 + LEV T.O +26512 000000 5 RUTOUT: 0 +26513 073627 5 RUTCK1: K LDX RUTCKX /(RUTCK1-0-RUTCK2-1) +26514 140040 5 K CRA +26515 055642 5 K ADD RUTCK2+1 X +26516 024000 5 K IRS 0 /CHECKSUM THIS CODE +26517 003515 5 K JMP .-2 +26520 100040 5 K SZE /DIFFERENT? + RELOAD [RUTOUT CODE BROKEN] +26521 120061 5 K JST SWDTIL I /YES, RELOAD +26522 073630 5 K LDX CRSTC /(-NIMP-HEAD2-ACKH) +26523 033642 5 K STX RSTC /INIT CKSUM=-# OF WORDS +26524 110660 5 K STA RST.O I /INIT ACK HEADER AT ZERO +26525 024000 5 K IRS 0 +26526 015642 5 K ADD RSTC /ADD INTO MSG CKSUM +26527 011642 5 K STA RSTC +26530 004106 5 K LDA MINE /THIS IMP # +26531 141340 5 K ICA +26532 141206 5 K AOA 0"A"LINETS /PUT IN ROUTING MSG BIT +26533 110660 5 K STA RST.O I /INIT HEADER +26534 024000 5 K IRS 0 +26535 015642 5 K ADD RSTC /ADD INTO MSG CKSUM +26536 011642 5 K STA RSTC +26537 005644 5 K LDA RSTSN +26540 015631 5 K ADD CRMSN1 /INCREMENT SER # +26541 011644 5 K STA RSTSN +26542 110660 5 K STA RST.O I +26543 024000 5 K IRS 0 +26544 015642 5 K ADD RSTC /ADD INTO MSG CKSUM +26545 011642 5 K STA RSTC + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 231 IMP,3050,IMP 7:20 PM 9/16/1973 + +26546 044265 5 COMPL: K LDA RUT+NIMP X +26547 100400 5 K SPL 0"A"RUTDED /THIS IMP DEAD? +26550 003602 5 K JMP RTDEAD /YES +26551 104662 5 K LDA RST.N I +26552 007347 5 K ANA HOPM /GET HOP COUNT +26553 141340 5 K ICA +26554 023633 5 K CAS CMAXH /COMPARE W/ MAX VALUE +26555 003614 5 K JMP RTDIED /TOO BIG, THIS IMP HAS DIED +26556 003614 5 K JMP RTDIED /DITTO +26557 044265 5 K LDA RUT+NIMP X +26560 007636 5 K ANA NOGODN /THIS IMP UP, CLEAR GOING DOWN +26561 050265 5 K STA RUT+NIMP X +26562 033643 5 K STX THDTMP /THIS IMP UP, SAVE AS HIGHEST # SO T +26563 104662 5 NWRST1: K LDA RST.N I +26564 110660 5 NEWRST: K STA RST.O I /SAVE IN RST +26565 015642 5 K ADD RSTC /ADD IN ROUTING MSG CKSUM +26566 011642 5 K STA RSTC /AND PUT IT BACK +26567 024000 5 K IRS 0 /LOOP OVER ALL IMPS +26570 003546 5 K JMP COMPL +26571 140407 5 K TCA /PICK UP FINAL CKSUM ANDCOMPLEMENT +26572 110660 5 K STA RST.O I /STORE AS LAST WRD OF MSG +26573 073643 5 K LDX THDTMP /PICK UP HIGHEST # IMP +26574 044265 5 K LDA RUT+NIMP X +26575 007632 5 K ANA HOPCHM /EXTRACT OUR MIN HOP PATH TO IT +26576 141340 5 K ICA +26577 016114 5 K SUB ONE +26600 010420 5 K STA THD /SAVE IN THD, FOR SYNC ACQUISITIO: +26601 103512 5 K JMP RUTOUT I /AND RETURN + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 232 IMP,3050,IMP 7:20 PM 9/16/1973 + +26602 104662 5 RTDEAD: K LDA RST.N I /THIS IMP WAS DEAD +26603 007347 5 K ANA HOPM /EXTRACT BEST HOPS THIS TIME +26604 141340 5 K ICA +26605 023633 5 K CAS CMAXH /COMPARE WITH MAX +26606 003624 5 K JMP RTDOWN /STILL TOO MANY. DEAD +26607 003624 5 K JMP RTDOWN /DITTO +26610 044265 5 RTNOTD: K LDA RUT+NIMP X /GET BEST LINES +26611 007363 5 K ANA CHANM 0"A"RUTDED /TURN OFF RUTDED BIT +26612 013634 5 K ERA COMUPM /PUT IN INITIAL COME-UP DELAY +26613 003622 5 K JMP NWRST2 /PUT IN RUT, THEN SET UF RST + +26614 044265 5 RTDIED: K LDA RUT+NIMP X +26615 007635 5 K ANA GODWNM /IMP WAS UP +26616 100040 5 K SZE /IS IT MARKED AS GOING DOWN? +26617 003563 5 K JMP NWRST1 /YES +26620 005635 5 K LDA GODWNM /NO, MARK IT NOW +26621 052265 5 K ERA RUT+NIMP X +26622 050265 5 NWRST2: K STA RUT+NIMP X +26623 003563 5 K JMP NWRST1 + +26624 005640 5 RTDOWN: K LDA CMAXHD /REPORT AS DOWN TO NEIGHBORS +26625 110662 5 K STA RST.N I /AND KEEP MAX VAL FOR US +26626 003564 5 K JMP NEWRST /...BY SETTING RST TO MAX VALUE + + LEV CON +26627 177651 C RUTCKX: K RUTCK1-0-RUTCK2-1 +26630 177675 C CRSTC: K -NIMP-HEAD2+ACKH +26631 000400 C CRMSN1: K RMSN1 /400 +26632 017400 C HOPCHM: K RUTHPC /17400 +26633 000260 C CMAXH: K 0 0 MAXH"T"8. /260 +26634 000340 C COMUPM: K RUTCMU /340 +26635 060000 C GODWNM: K RUTGOD /60000 +26636 117777 C NOGODN: K 0 0 177777"X"RUTGOD /117777 +26637 100000 C CDEAD: K RUTDED /100000 +26640 177777 C CMAXHD: K 0 0 HOPS"X"DELS /177777 +26641 125362 C RUTCK2: -CHK + + LEV VAR +26642 V RSTC: BSS 1 /ROUTING MESSAGE CHECKSUM +26643 V THDTMP: BSS 1 /TEMP FOR THD + +26644 V RSTSN: BSS 1 /SERIAL # OF LAST RM COMPUTATION + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 233 IMP,3050,IMP 7:20 PM 9/16/1973 + +26645 073106 C LEV CON CONSTANTS +26646 073212 C +26647 073316 C +26650 073216 C +02435 175666 C PAGEND 26,UNCON,15 + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 234 IMP,3050,IMP 7:20 PM 9/16/1973 + + + LEV T.O + CHK=0 +27112 000000 5 RUTCLK: 0 +27113 073261 5 RTCLK1: K LDX RTCLKX +27114 140040 5 K CRA +27115 055263 5 K ADD RTCLK2+1 X +27116 024000 5 K IRS 0 +27117 003115 5 K JMP .-2 +27120 100040 5 K SZE + RELOAD [RUTCLK CODE BROKEN] +27121 120061 5 K JST SWDTIL I +27122 073230 5 K LDX NIMPMI /LOOP OVER ALL IMPS FOR HOLD-DOWN +27123 105241 5 HLDC1: K LDA RUT.W I +27124 007243 5 K ANA HOLDH +27125 101040 5 K SNZ /ARE WE HOLDING DOWN MIN HOP PATH? +27126 003132 5 K JMP HLDC2 /NO +27127 105241 5 K LDA RUT.W I +27130 017251 5 K SUB HOLDH1 /DECREMENT TIMER +27131 111241 5 K STA RUT.W I +27132 105241 5 HLDC2: K LDA RUT.W I /NO +27133 007244 5 K ANA HOLDD +27134 101040 5 K SNZ /HOLDING DOWN MIN DELAY PATH? +27135 003141 5 K JMP HLDC3 /NC +27136 105241 5 K LDA RUT.W I +27137 017252 5 K SUB HOLDD1 /DECREMENT TIMER +27140 111241 5 K STA RUT.W I +27141 024000 5 HLDC3: K IRS 0 +27142 003123 5 K JMP HLDC1 /NEXT +27143 025263 5 K IRS GODWNC /IS IT TIME TO DO GOING DOWN DELA' +27144 003170 5 K JMP CMUC0 /NO +27145 005237 5 K LDA GODWNK /YES, EVERY 4TH TICK +27146 011263 5 K STA GODWNC +27147 073230 5 K LDX NIMPMI /LOOP OVER ALL IMPS FOR GOING DOWNS +27150 044265 5 GODC1: K LDA RUT+NIMP X +27151 007245 5 K ANA MGODWN +27152 101040 5 K SNZ /THIS IMP GOING DOWN? +27153 003166 5 K JMP GODC2 /NO +27154 044265 5 K LDA RUT+NIMP X /YES +27155 017246 5 K SUB MGODW1 /DECREMENT TIMER +27156 050265 5 K STA RUT+NIMP X +27157 007245 5 K ANA MGODWN +27160 100040 5 K SZE /IS IT COMPLETELY DOWN? +27161 003166 5 K JMP GODC2 /NO +27162 005235 5 K LDA MAXRST /YES. HE IS REALLY DEAD +27163 111242 5 K STA RST.N2 I /SET UP RSTN +27164 005236 5 K LDA MAXRUT +27165 050265 5 K STA RUT+NIMP X /AND RUT +27166 024000 5 GODC2: K IRS 0 +27167 003150 5 K JMP GODC1 + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 235 IMP,3050,IMP 7:20 PM 9/16/1973 + +27170 025264 5 CMUC0: K IRS COMUPC /IS IT TIME TO DO COMING-UP DELAYS +27171 003206 5 K JMP RMVFRQ /NO, DO VBL FRQ CMPTNS +27172 005240 5 K LDA COMUPK /YES, EVERY TENTH TICK +27173 011264 5 K STA COMUPC +27174 073230 5 K LDX NIMPMI /LOOP OVER ALL IMPS FOR COMING UP +27175 044265 5 CMUC1: K LDA RUT+NIMP X +27176 007247 5 K ANA MCOMUP +27177 101040 5 K SNZ /IS THIS IMP COMING UP? +27200 003204 5 K JMP CMUC2 /NO +27201 044265 5 K LDA RUT+NIMP X /YES +27202 017250 5 K SUB MCOMU1 /DECREMENT TIMER +27203 050265 5 K STA RUT+NIMP X /SAVE IN RUT(IF HE CAME [ +27204 024000 5 CMUC2: K IRS 0 +27205 003175 5 K JMP CMUC1 +27206 073231 5 RMVFRQ: K LDX RMMICH /-CH +27207 140040 5 RMVFRC: K CRA +27210 011266 5 K STA RMVT +27211 127232 5 K IMA CTIMK I /CLEAR CUMTIM AND COMPUTE EXTRAS +27212 017234 5 RMVFRA: K SUB MS132K +27213 100400 5 K SPL +27214 003217 5 K JMP RMVFRB +27215 025266 5 K IRS RMVT +27216 003212 5 K JMP RMVFRA +27217 005233 5 RMVFRB: K LDA RMFOUR +27220 017266 5 K SUB RMVT +27221 100400 5 K SPL +27222 140040 5 K CRA +27223 015260 5 K ADD CRMVTB +27224 051274 5 K STA RUTFRQ+CH X +27225 024000 5 K IRS 0 +27226 003207 5 K JMP RMVFRC /LOOP OVER ALL LINES +27227 103112 5 K JMP RUTCLK I + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 236 IMP,3050,IMP 7:20 PM 9/16/1973 + + LEV CON +27230 177700 C NIMPMI: K -NIMP +27231 177773 C RMMICH: K -CH +27232 052632 C CTIMK: K CUMTIM CH X +27233 000004 C RMFOUR: K 4 +27234 002450 C MS132K: K 2450 +27235 177777 C MAXRST: K HOPS+0+DELS +27236 100000 C MAXRUT: K RUTDED +27237 177772 C GODWNK: K -6 +27240 177767 C COMUPK: K -9. +27241 066500 C RUT.W: K RUTW+NIMP X +27242 073316 C RST.N2: K RST2+NIMP X +27243 060000 C HOLDH: K RUTHPH +27244 000140 C HOLDD: K RUTDLH +27245 060000 C MGODWN: K RUTGOD +27246 020000 C MGODW1: K RUTGD1 +27247 000340 C MCOMUP: K RUTCMU +27250 000040 C MCOMU1: K RUTCM1 +27251 020000 C HOLDH1: K RTHPH1 +27252 000040 C HOLDD1: K RTDLH1 + /RMVTAB USED BY RSTOUT +27253 000001 C RMVTAB: K 1 /1BIT IN 5 (# OF EXTRA +1 RM'S TO S1 +27254 000005 C K 5 /2 IN 5 (I.E. 1 EXTRA) +27255 000015 C K 15 +27256 000033 C K 33 +27257 000037 C K 37 +27260 027253 C CRMVTB: K RMVTAB +27261 177630 C RTCLKX: K RTCLK1-0-RTCLK2-1 +27262 147750 C RTCLK2: -CHK + + LEV VAR +27263 V GODWNC: BSS 1 /COUNTER - EVERY 4TH TICK +27264 V COMUPC: BSS 1 /COUNTER - EVERY 10TH TICK +27265 V HOLDT: BSS 1 /TEMP +27266 V RMVT: BSS 1 /TEMP +27267 V RUTFRQ: BSS CH /# OF EXTRA RM'S PERMITTED AS PER + + LEV CON CONSTANTS +02436 172274 C PAGEND 27,UNCON + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 237 IMP,3050,IMP 7:20 PM 9/16/1973 + + + LEV BCK + /STATISTICS PROGRAMS + /ALL CALLS TO DEFSTAT MUST PRECEDE THIS PAGE +30056 004114 7 STTI: LDA ONE +30057 011213 7 STA SOFO /BEGIN BY SAVING COPY OF SON +30060 005436 7 BKST: LDA SON /PICK UP 10-SEC STAT ON-OFF FLAG +30061 027213 7 IMA SOFO /KEEP A COPY +30062 023436 7 CAS SON /ANY CHANGE IN STATUS? +30063 100000 7 SKP /YES, MUST CHANGE STATISTICS LOCATI1 +30064 003104 7 JMP SP2 /NO +30065 101040 7 SNZ /WAS 10-SEC STAT JUST TURNED ON? +30066 003075 7 JMP SP1 /YES +30067 073575 7 LDX (-NSTATS) /NO, JUST TURNED OFF +30070 105576 7 LDA (SC1+NSTATS 0 X) I /PICK UP STANDARD CONTE:'1 +30071 111577 7 STA (SB1+NSTATS 0 XI) I /AND PLANT IN DESIGNATED ] +30072 024000 7 IRS 0 /THIS RESTORES PROGRAM TO ITS DEFAUT +30073 003070 7 JMP .-3 +30074 003104 7 JMP SP2 +30075 021256 7 SP1: JST CLST /CLEAR OUT 10-SEC STAT TABLES +30076 073575 7 LDX (-NSTATS) +30077 005600 7 LDA (JST SW1 I) /PLANT JST'S TO STATISTIC +30100 111577 7 STA (SB1+NSTATS 0 XI) I +30101 141206 7 AOA /THIS PUTS BREAKPOINT-LIKE CODE +30102 024000 7 IRS 0 /IN KEY PLACES THROUGHOUT THE PROGR +30103 003100 7 JMP .-3 +30104 005601 7 SP2: LDA (50000+0+DIAGTT) +30105 011455 7 STA DIAGD +30106 005602 7 LDA (DIAGQ 0 I) +30107 011440 7 STA DIAGON /DIAG IS ALWAYS ON +30110 005603 7 LDA (TRON 0 I) +30111 011212 7 STA SP81 /INDIRECT POINTER FOR ON FLAGS +30112 072125 7 LDX MINUS5 /SO THAT NCC TRBL REPTS ALWAYS GO[ +30113 033441 7 STX TPON /TURN ON NCC TRBL REPTS +30114 033211 7 SP3: STX SP8 /LOOP HERE FOR EACH STAT PROGRAM +30115 105212 7 LDA SP81 I +30116 101040 7 SNZ /IS THIS STAT PROGRAM TURNED ON? +30117 003170 7 JMP SP91 /NO +30120 004417 7 LDA SYNC /PICK UP CURRENT TIME +30121 057211 7 SUB OLDS+5 X /COMPARE WITH THE LAST TIME THIS PR +30122 100400 7 SPL /CORRECT FOR TIMER OVERFLOW +30123 140407 7 TCA /EVERY 30 MINUTES +30124 057465 7 SUB STATF+5 X /LOOK AT INTERVAL BETWEEN PROGRAM R +30125 100400 7 SPL /IS IT TIME TO ACTIVATE THIS PROG? +30126 003170 7 JMP SP91 /NO +30127 140040 7 CRA /YES +30130 011214 7 STA SKEWT /INIT A TIME-SKEWING TEMP +30131 004000 7 LDA 0 +30132 012124 7 ERA MINUS4 +30133 100040 7 SZE /ARE WE DOING 10-SEC STAT? +30134 003153 7 JMP STAT6 /NO + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 238 IMP,3050,IMP 7:20 PM 9/16/1973 + +30135 045465 7 LDA STATF+5 X /YES, SKEW REPORTS BY IMP NUMBER +30136 040572 7 ARS 6 0"A"NIMP /DIV BY 100 = IMPNO +30137 101040 7 SNZ +30140 003153 7 JMP STAT6 /TOO SMALL AN INTERVAL TO SKEW +30141 140407 7 TCA +30142 011215 7 STA COUNT1 /BUILD MULTIPLY LOOP +30143 004106 7 STAT4: LDA MINE +30144 140407 7 TCA +30145 011216 7 STA COUNT2 +30146 025214 7 STAT5: IRS SKEWT /COMPUTE SKEWT=(MINE/100)*STATF +30147 025216 7 IRS COUNT2 +30150 003146 7 JMP STAT5 +30151 025215 7 IRS COUNT1 +30152 003143 7 JMP STAT4 +30153 045465 7 STAT6: LDA STATF+5 X +30154 140407 7 TCA +30155 006417 7 ANA SYNC +30156 015214 7 ADD SKEWT +30157 051211 7 STA OLDS+5 X +30160 045457 7 LDA STATD+5 X /*SEND STAT DEST +30161 021403 7 JST GIVE +30162 045451 7 LDA STATL+5 X /*SEND STAT LINK +30163 021403 7 JST GIVE +30164 143204 7 JMP CAWL+5 XI /CALL STAT PROGRAM + +30165 073604 7 GIVLST: LDX (100003) /TERMINATE STAT MESSAGE +30166 004112 7 LDA SIGN /*SEND PADDING +30167 120664 7 JST JAM I +30170 073211 7 SP91: LDX SP8 /LOOP BACK OVER EACH STAT PROG +30171 025212 7 IRS SP81 +30172 024000 7 IRS 0 +30173 003114 7 JMP SP3 +30174 072116 7 LDX THREE +30175 120665 7 JST DOZE I +30176 003060 7 JMP BKST + + LEV CON +30177 030217 C CAWL: SNAP /SNAPSHOT STATISTICS PROGRAM +30200 030243 C SEST /CUMULATIVE STATISTICS PROGRAM +30201 030267 C GENM /MESSAGE GENERATOR +30202 030347 C DIAG /DIAGNOSTIC SENDER +30203 022057 C TRBL /NCC TROUBLE REPORT PROGRAM + LEV VAR +30204 000000 V OLDS: 0 +30205 000000 V 0 +30206 000000 V 0 +30207 000000 V 0 +30210 000000 V TRBOLD: 0 + +30211 V SP8: BSS 1 /COUNTER FOR WHICH STAT PROG TO RUN +30212 V SP81: BSS 1 /STAT FLAGS INDIRECT PTR +30213 V SOFO: BSS 1 /SAVED COPY OF SON +30214 V SKEWT: BSS 1 /AMOUNT OF TIME TO SKEW STAT REPTS +30215 V COUNT1: BSS 1 +30216 V COUNT2: BSS 1 + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 239 IMP,3050,IMP 7:20 PM 9/16/1973 + + /SEND SNAPSHOT STATISTICS + LEV BCK +30217 005605 7 SNAP: LDA (5) /*SEND SNAPSHOT CODE +30220 021403 7 JST GIVE +30221 004415 7 LDA TIME /*SEND LOCAL TIME +30222 021403 7 JST GIVE +30223 073606 7 LDX (-COUNTL) +30224 001001 7 SNP2: INH ALL +30225 044543 7 0 LDA COUNTA+COUNTL X /*SEND QUEUE LENGTHS +30226 056567 7 0 SUB COUNTS+COUNTL X +30227 000401 7 0 ENB BCK +30230 021403 7 JST GIVE +30231 024000 7 IRS 0 +30232 003224 7 JMP SNP2 +30233 072132 7 LDX MINIMP +30234 044265 7 SNP3: LDA RUT+NIMP X /*SEND ROUTE USE TABLE +30235 021403 7 JST GIVE +30236 105607 7 LDA (RST+NIMP 0 X) I /*SEND ROUTE SEND TABLE +30237 021403 7 JST GIVE +30240 024000 7 IRS 0 +30241 003234 7 JMP SNP3 +30242 003165 7 JMP GIVLST /*SEND PADDING AND END MESSAGE + + /SEND 10 SECOND (CUMULATIVE) STATISTICS +30243 004115 7 SEST: LDA TWO /*SEND 10-SEC STAT CODE +30244 021403 7 JST GIVE +30245 004417 7 LDA SYNC /*SEND NETWORK-WIDE TIME +30246 021403 7 JST GIVE +30247 073610 7 LDX (-NST) +30250 105611 7 LDA (STTB+NST X) I /*SEND 10-SEC STAT TABLE +30251 021403 7 JST GIVE +30252 024000 7 IRS 0 +30253 003250 7 JMP .-3 +30254 021256 7 JST CLST /CLEAR THE 10-SEC STAT TABLES +30255 003165 7 JMP GIVLST /*SEND PADDING AND END MESSAGE + + LEV BCK + /CLEAR ALL ENTRIES IN 10-SEC STAT TABLES +30256 000000 7 CLST: 0 +30257 073610 7 LDX (-NST) +30260 140040 7 CRA +30261 001001 7 INH ALL +30262 111611 7 0 STA (STTB+NST X) I +30263 024000 7 0 IRS 0 +30264 003262 7 0 JMP .-2 +30265 000401 7 0 ENB BCK +30266 103256 7 JMP CLST I + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 240 IMP,3050,IMP 7:20 PM 9/16/1973 + + /MESSAGE GENERATOR +30267 072116 7 GENM: LDX THREE /FAKE HOST 3 - STATISTICS +30270 005465 7 LDA MGNL /PICK UP LENGTH OF MESSAGE +30271 007612 7 ANA (777) +30272 101040 7 SNZ +30273 003301 7 JMP GENM1 +30274 140407 7 TCA /GIVES RIGHT NUMBER, EXCLUDING PADD +30275 011346 7 STA MGCNT +30276 120664 7 JST JAM I /*SEND MGNL WORDS +30277 025346 7 IRS MGCNT +30300 003276 7 JMP .-2 +30301 131040 7 GENM1: RDCLOK +30302 003301 7 JMP .-1 + /CRA FOR ALL REG, LDA ONE FOR ALL PRI, ANA ONE FOR RANDOM MI +30303 140040 7 CRA +30304 100040 7 SZE +30305 004112 7 LDA SIGN +30306 013454 7 ERA MGD +30307 011454 7 STA MGD +30310 005446 7 LDA MGLK +30311 101000 7 NOP /"SKP" TO RUN LINK CYCLER +30312 003165 7 JMP GIVLST /*SEND PADDING AND END MESSAGE +30313 101040 7 SNZ +30314 003333 7 JMP LC1 +30315 015613 7 LC3: ADD (400) +30316 011446 7 STA MGLK +30317 100040 7 SZE +30320 003165 7 JMP GIVLST /*SEND PADDING AND END MESSAGE +30321 004415 7 LDA TIME +30322 017345 7 SUB OTIM +30323 111343 7 STA PLAC I +30324 025343 7 IRS PLAC +30325 005465 7 LDA MGNL +30326 015342 7 ADD IGTH +30327 011465 7 STA MGNL +30330 017344 7 SUB LIMT +30331 101400 7 SMI +30332 003337 7 JMP LC44 +30333 004415 7 LC1: LDA TIME +30334 011345 7 STA OTIM +30335 005446 7 LDA MGLK +30336 003315 7 JMP LC3 + +30337 140040 7 LC44: CRA /WHEN DONE, SHUT MGEN OFF +30340 011437 7 STA MGON +30341 003165 7 JMP GIVLST /*SEND PADDING AND END MESSAGE + + LEV VAR +30342 000010 V IGTH: 10 /LENGTH INCREMENT +30343 030000 V PLAC: 30000 /CORE POINTER FOR TABLE BUILDING +30344 000760 V LIMT: 760 /LONGEST MESSAGE TO SEND +30345 V OTIM: BSS 1 /TEMP TO SAVE STARTING TIME OF BLOC +30346 V MGCNT: BSS 1 /TEMP COUNTER FOR MESS LENGTH + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 241 IMP,3050,IMP 7:20 PM 9/16/1973 + + LEV BCK +30347 001001 7 DIAG: INH ALL /SEND BROKEN PACKETS TO NCC FOR DIAT +30350 104342 7 0 LDA DIAGQ I +30351 026342 7 0 IMA DIAGQ /GET PKT OFF DIAG QUEUE +30352 000401 7 0 ENB BCK +30353 011401 7 STA DIAGP /SAVE PNTR +30354 004746 7 LDA HLTLOC /*SEND HLT PC +30355 021403 7 JST GIVE +30356 004747 7 LDA HLTA /*SEND HLT A REG +30357 021403 7 JST GIVE +30360 004750 7 LDA HLTX /*SEND HLT X REG +30361 021403 7 JST GIVE +30362 005401 7 LDA DIAGP /*SEND PKT PNTR +30363 010000 7 STA 0 +30364 021403 7 JST GIVE +30365 005614 7 LDA (-BUFL) +30366 011402 7 STA DIAGC /SET UP SEND COUNTER +30367 044000 7 DIAG1: LDA 0 X /*SEND CONTENTS OF BAD PACKET +30370 021403 7 JST GIVE +30371 024000 7 IRS 0 +30372 025402 7 IRS DIAGC +30373 003367 7 JMP DIAG1 +30374 001001 7 INH ALL +30375 073401 7 0 LDX DIAGP +30376 120671 7 0 JST FLUSHI I +30377 000401 7 0 ENB BCK +30400 003165 7 JMP GIVLST + + LEV VAR +30401 V DIAGP: BSS 1 /PKT PNTR +30402 V DIAGC: BSS 1 /LOOP COUNTER + + LEV BCK +30403 000000 7 GIVE: 0 /STAT CALLS TO JAM +30404 033411 7 STX STT8 /SAVE X-REG +30405 072116 7 LDX THREE +30406 120664 7 JST JAM I +30407 073411 7 LDX STT8 +30410 103403 7 JMP GIVE I + LEV VAR +30411 V STT8: BSS 1 + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 242 IMP,3050,IMP 7:20 PM 9/16/1973 + + LEV BCK /FAKE IMP-TO-HOST 2 - PARAMETER CHANGE +30412 120666 7 BTR1: JST SUCK I /SKIP OVER REST OF MESSAGE +30413 003412 7 JMP BTR1 +30414 120666 7 BEST: JST SUCK I /BEGIN TO ACCEPT MESSAGE HERE +30415 120666 7 JST SUCK I /IGNORE LEADER +30416 120666 7 BTR4: JST SUCK I /GET NUMBER OF PARAM TO CHANGE +30417 100000 7 SKP /END OF MESSAGE? +30420 003414 7 JMP BEST /YES, GO BACK +30421 100400 7 SPL /IS NO OF PARAM ROSTIVE? +30422 003412 7 JMP BTR1 /NO, IGNORE REST OF MESSAGE +30423 007615 7 ANA (37) /YES, MASK DOWN TO 5 BITS +30424 015616 7 ADD (PARAMT) /BUILD PNTR TO PARAM TABLE +30425 011433 7 STA BTR2 +30426 120666 7 JST SUCK I /GET NEW VALUE FOR PARAMETER +30427 100000 7 SKP /END OF MESSAGE? +30430 003414 7 JMP BEST /YES, NO CHANGE TO THIS PARAM +30431 111433 7 STA BTR2 I /NO, PUT NEW VALUE IN PARAM +30432 003416 7 JMP BTR4 /AND GO BACK FOR MORE + LEV VAR +30433 000000 V BTR2: 0 + + DEFPLC [PARAMETERS TABLE] + PARAMT: + PARAML=32. +30434 V TRON: BSS 1 /0-TRACE ON +30435 V SNON: BSS 1 /1-SNAP ON +30436 V SON: BSS 1 /2-10-SEC STAT ON +30437 V MGON: BSS 1 /3-MESS GEN ON +30440 V DIAGON: BSS 1 /4-DIAG ON +30441 V TPON: BSS 1 /5-TRBL REPT ON +30442 V BSS 1 /6 + +30443 V TLNK: BSS 1 /7-TRACE LINK +30444 V STATL: BSS 1 /10-SNAP LINK +30445 V BSS 1 /11-10-SEC LINK +30446 V MGLK: BSS 1 /12-MESS GEN LINK +30447 V BSS 1 /13-DIAG LINK +30450 V BSS 1 /14-TRBL REPT LINK + +30451 V TDST: BSS 1 /15-TRACE DEST +30452 V STATD: BSS 1 /16-SNAP DEST +30453 V BSS 1 /17-10-SEC DEST +30454 V MGD: BSS 1 /20-MESS GEN DEST +30455 V DIAGD: BSS 1 /21-DIAG DEST +30456 V TRBD: BSS 1 /22-TRBL REPT DEST + +30457 V TF: BSS 1 /23-AUTO TRACE FREQ +30460 V STATF: BSS 1 /24-SNAP FREQ +30461 V BSS 1 /25-10-SEC FREQ +30462 V BSS 1 /26-MESS GEN FREQ +30463 V BSS 1 /27-DIAG FREQ +30464 V TRBF: BSS 1 /30-TRBL REPT FREQ + +30465 V MGNL: BSS 1 /31-MESS GEN LENGTH +30466 V BSS PARAMT+1+PARAML-. + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 243 IMP,3050,IMP 7:20 PM 9/16/1973 + + LEV BCK /FAKE IMP-TO-HOST 3 - DISCARD +30474 120666 7 STXY: JST SUCK I /GET EACH WORD AS IT IS READY +30475 003474 7 JMP .-1 /AND RETURN IMMEDIATELY FOR MORE +30476 003474 7 JMP .-2 /EVEN ON END OF MESSAGE + + /FAKE HOST-TO-IMP 2 - TRACE +30477 140500 7 BTRE: SSM /START HERE +30500 003515 7 JMP BTRF + + LCK TSK +30501 000401 7 6 BTD: ENB BCK +30502 005572 7 LDA T3BX +30503 101040 7 SNZ +30504 003527 7 JMP BTRD +30505 004112 7 LDA SIGN +30506 073617 7 LDX (100002) +30507 120664 7 JST JAM I +30510 120665 7 BTRC: JST DOZE I /WAIT ONE BACKGROUND LOOP +30511 004341 7 LDA STRQ /START HERE +30512 101040 7 SNZ /ANYTHING TO SEND? +30513 003510 7 JMP BTRC /QUIT IF TRACE QUEUE EMPTY +30514 140040 7 CRA +30515 011572 7 BTRF: STA T3BX +30516 005451 7 LDA TDST /*SEND TRACE DEST +30517 120664 7 JST JAM I +30520 005443 7 LDA TLNK /*SEND TRACE LINK +30521 120664 7 JST JAM I +30522 004114 7 LDA ONE /*SEND TRACE CODE +30523 120664 7 JST JAM I +30524 140040 7 CRA /RESET OVERFLOW FLAG +30525 026414 7 IMA TTO /*SEND STATE OF OVERFLOW FLAG +30526 120664 7 JST JAM I +30527 072115 7 BTRD: LDX TWO +30530 120665 7 JST DOZE I +30531 005621 7 BRL2: LDA ((STRQ)) +30532 011573 7 STA OLD2 +30533 001001 7 INH TSK + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 244 IMP,3050,IMP 7:20 PM 9/16/1973 + +30534 105573 7 6 BTRL: LDA OLD2 I /SEARCH TRACE QUEUE +30535 011573 7 6 STA OLD2 +30536 105573 7 6 LDA OLD2 I +30537 011574 7 6 STA OLD1 +30540 101040 7 6 SNZ +30541 003501 7 6 JMP BTD /JUMP IF DONE WITH TRACE QUEUE +30542 010000 7 6 STA 0 +30543 044012 7 6 LDA TDONE X +30544 101400 7 6 SMI /IS THIS TRACE BLOCK COMPLETE? +30545 003534 7 6 JMP BTRL /NO +30546 044000 7 6 LDA 0 X /YES, PICK UP ITS CHAIN PNTR +30547 111573 7 6 STA OLD2 I /REMOVE FROM TRACE QUEUE +30550 000401 7 6 ENB BCK +30551 025572 7 IRS T3BX +30552 005622 7 LDA (-TDONE) +30553 011571 7 STA T2BX +30554 072115 7 LDX TWO +30555 025574 7 IRS OLD1 +30556 105574 7 LDA OLD1 I +30557 120664 7 JST JAM I /*SEND TRACE BLOCK +30560 025571 7 IRS T2BX +30561 003555 7 JMP .-4 +30562 005574 7 LDA OLD1 +30563 015622 7 ADD (-TDONE) +30564 001001 7 INH TSK +30565 026325 7 6 IMA TTF /PUT DN FREE TRACE QUEUE +30566 110325 7 6 STA TTF I +30567 000401 7 6 ENB BCK +30570 003531 7 JMP BRL2 /LOOP SEARCHING TRACE QUEUE + + LEV VAR +30571 V T2BX: BSS 1 /COPY LOOP COUNTER +30572 V T3BX: BSS 1 /COUNT OF NUMBER OF BLOCKS COPIED +30573 V OLD2: BSS 1 /QUEUE PNTR - USED IN SEARCH +30574 V OLD1: BSS 1 /PACKET PNTR - USED IN COPY + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 245 IMP,3050,IMP 7:20 PM 9/16/1973 + +30575 177760 C LEV CON CONSTANTS +30576 072030 C +30577 172010 C +30600 120574 C +30601 050057 C +30602 100342 C +30603 130434 C +30604 100003 C +30605 000005 C +30606 177754 C +30607 073106 C +30610 177423 C +30611 071716 C +30612 000777 C +30613 000400 C +30614 177666 C +30615 000037 C +30616 030434 C +30617 100002 C +30620 000341 C +30621 030620 C +30622 177766 C +02437 175631 C PAGEND 30,UNCON,3 + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 246 IMP,3050,IMP 7:20 PM 9/16/1973 + + LEV H2I + /HOST TO IMP STATISTICS +31055 000000 4 HS0: 0 +31056 005753 4 LDA (STTB) +31057 001001 4 INH [I2M,I2H] +31060 011121 4 2 STA WHER +31061 004675 4 2 LDA HIP +31062 021123 4 2 JST SUB1 +31063 015356 4 2 ADD TOT1 +31064 011356 4 2 STA TOT1 +31065 000401 4 2 ENB H2I +31066 072675 4 LDX HIP +31067 172677 4 LDX HIXX I +31070 044007 4 LDA HEAD2 X +31071 103055 4 JMP HS0 I + + / HOST TO IMP ALL MESSAGES +31072 000000 4 HS2: 0 +31073 065375 4 IRS CNT2 X +31074 101000 4 NOP +31075 103754 4 JMP (HIH0 0 XI) I + + LEV I2H + / IMP TO HOST STATISTICS +31076 000000 3 HS1: 0 +31077 005755 3 LDA (XGP) +31100 001001 3 INH I2M +31101 011121 3 2 STA WHER +31102 004676 3 2 LDA IHP +31103 172700 3 2 LDX IHXX I +31104 021123 3 2 JST SUB1 +31105 015374 3 2 ADD TOT2 +31106 011374 3 2 STA TOT2 +31107 000401 3 2 ENB I2H +31110 072676 3 LDX IHP +31111 105756 3 LDA (IHED 0 X) I +31112 103076 3 JMP HS1 I + + / IMP TO HOST CONTROL MESSAGES +31113 000000 3 HS3: 0 +31114 141206 3 AOA +31115 065405 3 IRS CNT3 X +31116 101000 3 NOP +31117 103113 3 JMP HS3 I + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 247 IMP,3050,IMP 7:20 PM 9/16/1973 + + LEV VAR +31120 V WHERL: BSS 1 +31121 V WHER: BSS 1 +31122 V SUBL: BSS 1 + + LEV I2M +31123 000000 2 SUB1: 0 +31124 016130 2 SUB PLNH +31125 101400 2 SMI +31126 003156 2 JMP SP6 +31127 044111 2 LDA BUFE X +31130 016000 2 SUB 0 +31131 017757 2 SUB (DATA) +31132 140100 2 SSP 0"A"TWOQ +31133 011122 2 STA SUBL +31134 021717 2 JST LOG +31135 014120 2 ADD SEVEN /POINTS TO LAST-PACKET LENGTH COUNT] +31136 015121 2 ADD WHER /...IN CORRECT TABLE +31137 011120 2 STA WHERL +31140 125120 2 IRS WHERL I /AND GOOSE COUNTER +31141 101000 2 NOP +31142 044006 2 LDA HEAD1 X +31143 141340 2 ICA 0"A"PKTNO +31144 006120 2 ANA SEVEN +31145 101040 2 SNZ +31146 003154 2 JMP SP4 /NO SEPARATE COUNTER FOR 1PKT MSGS +31147 016114 2 SUB ONE /BACK OFF 1 +31150 015121 2 ADD WHER +31151 011121 2 STA WHER +31152 125121 2 IRS WHER I +31153 101000 2 NOP +31154 005122 2 SP4: LDA SUBL +31155 103123 2 JMP SUB1 I + +31156 073123 2 SP6: LDX SUB1 +31157 042002 2 JMP 2 X + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 248 IMP,3050,IMP 7:20 PM 9/16/1973 + + / IMP TO MODEM MESSAGES +31160 000000 2 IM1: 0 +31161 111760 2 STA (ACKWRD) I +31162 010000 2 STA 0 +31163 044105 2 LDA BUFE-ACKH X +31164 016000 2 SUB 0 +31165 016116 2 SUB THREE 0"A"[HEAD2-ACKH] +31166 140100 2 SSP 0"A"TWOQ +31167 011337 2 STA IMT1 +31170 021717 2 JST LOG +31171 173761 2 LDX (OCHN) I +31172 055331 2 ADD TUB1 X +31173 011340 2 STA IMT2 +31174 125340 2 IRS IMT2 I +31175 101000 2 NOP +31176 005337 2 LDA IMT1 +31177 055622 2 ADD ANS4 X +31200 051622 2 STA ANS4 X +31201 103160 2 JMP IM1 I + + LEV M2I + / MODEM TO INP DISCARD +31202 000000 0 MI1: 0 +31203 025627 0 IRS MTOT +31204 070471 0 M1ERR +31205 103202 0 JMP MI1 I +31206 025634 0 IRS CKSM +31207 025202 0 IRS MI1 +31210 101000 0 NOP +31211 103202 0 JMP MI1 I + + /TASK I HEARD YOU MESSAGES RECEIVED +31212 000000 0 TSKIH: 0 +31213 064426 0 IRS LAC X +31214 065641 0 IRS TSKIHY X +31215 101000 0 NOP +31216 103212 0 JMP TSKIH I + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 249 IMP,3050,IMP 7:20 PM 9/16/1973 + + / MODEM TO IMP BUFFER TROUBLE +31217 000000 0 MI3: 0 +31220 100040 0 SZE +31221 025217 0 IRS MI3 +31222 101040 0 SNZ +31223 065646 0 IRS BUFT X +31224 101000 0 NOP +31225 103217 0 JMP MI3 I + + /MORE OF MODEM TO IMP DISCARD + +31226 000000 0 MI1A: 0 +31227 025630 0 IRS MTOT+1 +31230 070472 0 M2ERR +31231 103226 0 JMP MI1A I +31232 025635 0 IRS CKSM+1 +31233 025226 0 IRS MI1A +31234 101000 0 NOP +31235 103226 0 JMP MI1A I + +31236 000000 0 MI1B: 0 +31237 025631 0 IRS MTOT+2 +31240 070473 0 M3ERR +31241 103236 0 JMP MI1B I +31242 025636 0 IRS CKSM+2 +31243 025236 0 IRS MI1B +31244 101000 0 NOP +31245 103236 0 JMP MI1B I + +31246 000000 0 MI1C: 0 +31247 025632 0 IRS MTOT+3 +31250 070474 0 M4ERR +31251 103246 0 JMP MI1C I +31252 025637 0 IRS CKSM+3 +31253 025246 0 IRS MI1C +31254 101000 0 NOP +31255 103246 0 JMP MI1C I + +31256 000000 0 MI1D: 0 +31257 025633 0 IRS MTOT+4 +31260 070475 0 M5ERR +31261 103256 0 JMP MI1D I +31262 025640 0 IRS CKSM+4 +31263 025256 0 IRS MI1D +31264 101000 0 NOP +31265 103256 0 JMP MI1D I + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 250 IMP,3050,IMP 7:20 PM 9/16/1973 + + LEV H2I +31266 000000 4 HS4: 0 +31267 050111 4 STA BUFE X +31270 173762 4 LDX (PPSLT) I +31271 131040 4 RDCLOK +31272 003271 4 JMP .-1 +31273 050010 4 STA PPT1 X /SAVE SENT TIME FOR 1 PKT MESS +31274 173763 4 LDX (PPSLT 0 I) I +31275 103266 4 JMP HS4 I + +31276 000000 4 HS5: 0 /SHOULD ONLY DO THIS ONCE, NEED A C+ +31277 050030 4 STA PLT2 X +31300 131040 4 RDCLOK +31301 003300 4 JMP .-1 +31302 050044 4 STA PLT3 X /SAVE SENT TIME FOR 8 PKT MESS +31303 103276 4 JMP HS5 I + + LEV TSK LCK FRE +31304 000000 6 0 HS6: 0 +31305 131040 6 0 RDCLOK +31306 003305 6 0 JMP .-1 +31307 173764 6 0 LDX (PPTASK) I +31310 056010 6 0 SUB PPT1 X +31311 021322 6 0 JST HSTIME /GET ROUND-TRIP TIME FOR 1 PKT ME1 +31312 103765 6 0 JMP (PPTFRE) I + +31313 000000 6 0 HS7: 0 +31314 131040 6 0 RDCLOK +31315 003314 6 0 JMP .-1 +31316 173764 6 0 LDX (PPTASK) I +31317 056044 6 0 SUB PLT3 X +31320 021322 6 0 JST HSTIME /GET ROUND-TRIP TIME FOR 8 PKT MESS +31321 103766 6 0 JMP (GUDRP0) I + +31322 000000 6 0 HSTIME: 0 +31323 040475 6 0 LGR 3 +31324 173767 6 0 LDX (SOURCE) I +31325 055415 6 0 ADD HS4R X +31326 051415 6 0 STA HS4R X +31327 065515 6 0 IRS HS4S X +31330 103322 6 0 JMP HSTIME I + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 251 IMP,3050,IMP 7:20 PM 9/16/1973 + + LEV CON +31331 031660 C TUB1: XGP1+0 +31332 031666 C XGP1+6 +31333 031674 C XGP1+12. +31334 031702 C XGP1+18. +31335 031710 C XGP1+24. +31336 031716 C XGP1+30. + LEV VAR +31337 V IMT1: BSS 1 +31340 V IMT2: BSS 1 + + + /CUMULATIVE STATS SENT IN THIS ORDER + /STATISTICS GATHERED BY H2I +31341 V STTB: BSS 13. /HISTOGRAM OF H2I MESS LENGTH - A1 +31356 V TOT1: BSS 1 /TOTAL # OF H2I WORDS + /STATISTICS GATHERED BY I2H +31357 V XGP: BSS 13. /HISTOGRAM OF I2H MESS LENGTH - A1 +31374 V TOT2: BSS 1 /TOTAL # OF I2H WORDS + /STATISTICS GATHERED BY H2I +31375 V CNT2: BSS TH /# OF H2I ALL MESSAGES PER HOST + /STATISTICS GATHERED BY I2H +31405 V CNT3: BSS TH /# OF I2H CONTROL MESSAGES PER HOST + /STATISTICS GATHERED BY TSK +31415 V HS4R: BSS NIMP /TOTAL ROUND TRIP TIME IN 800 MS PE1 +31515 V HS4S: BSS NIMP /# OF ROUND TRIPS MEASURED ABOVE + /STATISTICS GATHERED BY I2M +31615 V IMHS: BSS CH /# OF HELLOS SENT PER LINE +31622 V ANS4: BSS CH /# OF DATA WOSDS SENT PER LINE + /STATISTICS GATHERED BY M2I +31627 V MTOT: BSS CH /# OF INPUTS RECVD PER LINE +31634 V CKSM: BSS CH /# OF CHECKSUM ERRORS PER LINE + /STATISTICS GATHERED BY TSK +31641 V TSKIHY: BSS CH /# OF I HEARD YOUS RECVD PER LINE + /STATISTICS GATHERED BY M2I +31646 V BUFT: BSS CH /# OF INPUTS LOST DUE TO LACK OF [ +31653 V SLOW: BSS CH /UNUSED + /STATISTICS GATHERED BY I2M +31660 V XGP1: BSS CH+CH+CH+CH+CH+CH /HISTOGRAM OF I2M MESSA[ +31716 V EP20: BSS 1 /BEGINNING OF PATCH AREA + NST=0+0+EP20-STTB + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 252 IMP,3050,IMP 7:20 PM 9/16/1973 + + LEV I2M + / LOG SUBROUTINE +31717 000000 2 LOG: 0 +31720 033742 2 STX LOGX +31721 022120 2 CAS SEVEN +31722 003731 2 JMP LOG1 +31723 101000 2 NOP +31724 100400 2 SPL +31725 003733 2 JMP LOG3 +31726 010000 2 STA 0 +31727 045743 2 LDA LOGT X +31730 003740 2 JMP LOG2 +31731 040575 2 LOG1: ARS 3 +31732 022120 2 CAS SEVEN +31733 004120 2 LOG3: LDA SEVEN +31734 101000 2 NOP +31735 010000 2 STA 0 +31736 045743 2 LDA LOGT X +31737 014116 2 ADD THREE +31740 073742 2 LOG2: LDX LOGX +31741 103717 2 JMP LOG I + + LEV VAR +31742 V LOGX: BSS 1 + LEV CON +31743 000000 C LOGT: 0 +31744 000000 C 0 +31745 000001 C 1 +31746 000001 C 1 +31747 000002 C 2 +31750 000002 C 2 +31751 000002 C 2 +31752 000002 C 2 + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 253 IMP,3050,IMP 7:20 PM 9/16/1973 + +31753 031341 C LEV CON CONSTANTS +31754 154137 C +31755 031357 C +31756 056124 C +31757 000011 C +31760 012655 C +31761 012654 C +31762 015156 C +31763 115156 C +31764 007131 C +31765 007213 C +31766 007215 C +31767 006673 C +31770 C SB1: BSS NSTATS /ADDRESSES FOR STAT INSTR +32010 C SC1: BSS NSTATS /NOMINAL CONTENTS + +02440 177030 C PAGEND 31,SC1+NSTATS + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 254 IMP,3050,IMP 7:20 PM 9/16/1973 + + + LEV VAR + TABZB: /THIS ENTIRE PAGE IS ZEROED AT INIT + /TABLES OF BUFFER PNTRS, NACH FOR EACH LINE +32030 V I2MB0: BSS NACH +32040 V I2MB1: BSS NACH +32050 V I2MB2: BSS NACH +32060 V I2MB3: BSS NACH +32070 V I2MB4: BSS NACH + /NULL AREAS +32100 V NULS1: BSS HEAD3-ACKH+1 /ACKS GO HERE +32105 V NULS2: BSS HEAD3-ACKH+1 /ACKS GO HERE +32112 V NULS3: BSS HEAD3-ACKH+1 /ACKS GO HERE +32117 V NULS4: BSS HEAD3-ACKH+1 /ACKS GO HERE +32124 V NULS5: BSS HEAD3-ACKH+1 /ACKS GO HERE + NTRCB=8 + TRACEL=TDONE+1 +32131 V TRACEQ: BSS NTRCB"T"TRACEL /TRACE STORE + TALLYL=8. +32261 V TALLY: BSS TALLYL /STACK OF TRANSMIT ALLOCATES WE HAVT + + DEFPLC [TRANSMIT, RECEIVE, AND ALLOCATE MESSAGE TABLES] +32271 V TMESS: BSS NIMP +32371 V RMESS: BSS NIMP +32471 V AMESS: BSS NIMP + DEFPLC [RALLY TABLE - ALLOCATES TO SEND] +32571 V RALLY: BSS NIMP + LEV CON +02441 176671 C PAGEND 32,-0 + + LEV VAR + /ROUTE SEND TABLES + /SEND ROUTING MESSAGE FROM HERE +33003 V RSTX: BSS 1 /ACKS +33004 V BSS 1 /HEADER +33005 V BSS 1 /SERIAL NO. (LH) +33006 V RST: BSS NIMP /ROUTE SEND TABLE +33106 V RSTCKS: BSS 1 /CHECKSUM + /END OF ROUTING MESSAGE + + /ALTERNATE ROUTING MESSAGE BUFFER 1 +33107 V RSTX1: BSS 1 /ACKS +33110 V BSS 1 /HEADER +33111 V BSS 1 /SERAIL NO. (LH) +33112 V RST1: BSS NIMP /ROUTE SEND TABLE +33212 V BSS 1 /CHECKSUM + + /ALTERNATE ROUTING MESSAGE BUFFER 2 +33213 V RSTX2: BSS 1 /ACKS +33214 V BSS 1 /HEADER +33215 V BSS 1 /SERIAL NO. (LH) +33216 V RST2: BSS NIMP /ROUTE SEND TABLE +33316 V BSS 1 /CHECKSUM + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 255 IMP,3050,IMP 7:20 PM 9/16/1973 + + LEV VAR + NREAB=8 /8 - NEED MANY FOR <8 PKT MESSAGES + REASL=RSF+1 +33317 V REASQ: BSS NREAB"T"REASL /REASSEMBLY STORE + PPTL=8. /NUMBER OF ENTRIES IN PPT + PPTN=2 /NUMBER OF WORDS PER ENTRY IN PPT + PPTNUM=PPTL"T"PPTN + DEFPLC [PPT - PENDING PACKET TABLE] +33457 V PPT: BSS PPTNUM /TABLE OF PNTRS TO PENDING PACKET1 + PLTL=12. /NUMBER OF ENTRIES IN PLT + PLTN=4 /NUMBER OF WORDS PER ENTRY IN PLT + PLTNUM=PLTL"T"PLTN + DEFPLC [PLT - PENDING LEADER TABLE] +33477 V PLT: BSS PLTNUM /TABLE OF COPIED PENDING LEADERS + HTPTBL: /TABLE OF HOST THROUGHPUTS +33557 V HTPMTN: BSS NH /MESSAGES FROM HOST TO NET +33563 V HTPMFN: BSS NH /MESSAGES TO HOST FROM NET +33567 V HTPPTN: BSS NH /PACKETS FROM HOST TO NET +33573 V HTPPFN: BSS NH /PACKETS TO HOST FROM NET +33577 V HTPMTL: BSS NH /MESSAGES FROM HOST TO LOCAL HOST +33603 V HTPMFL: BSS NH /MESSAGES TO HOST FROM LOCAL HO1 +33607 V HTPPTL: BSS NH /PACKETS FROM HOST TO LOCAL HOST +33613 V HTPPFL: BSS NH /PACKETS TO HOST FROM LOCAL HOST +33617 V HTPWTI: BSS NH /WORDS FROM HOST TO IMP +33623 V HTPWFI: BSS NH /WORDS TO HOST FROM IMP + TABZE: + TABZL=TABZE+0-TABZB + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 256 IMP,3050,IMP 7:20 PM 9/16/1973 + + LEV CON + IRP [PAGEN,,33,34,35,36] + PAGEND PAGEN,-0 + +02442 175627 C ENDIRP +02443 170053 C +02444 170061 C +02445 170067 C + + P36FB=FB + P36NB=NB +02446 170075 C PAGEND 37,-0 + P37NB=NB-1 /ALLOW FOR SAT CODE + P37FB=FB + + + 100003/ -0 VDHSTART VDHEND + .ASCII / VDH + + "Z"/ + NMAXS=4"T"CH + + 100001/ NBUFS-2 + .ASCII / TOTAL BUFFERS"Z"/ + + 100001/ P37NB + .ASCII / FEWER BUFFERS IF VDH PRESENT"Z"/ + + + 100001/ NMAXS + .ASCII / STORE AND FORWARD LIMIT"Z"/ + + 100001/ 0 0 [0 0 [NBUFS-NMAXS+10]"Q"10]"T"10+2 + .ASCII / REASSEMBLY LIMIT"Z"/ + + 100001/ NITB + .ASCII / IMP-TIP CONVERSION REGISTERS"Z"/ + + 100001/ NSTATS + .ASCII / STATISTICS GATHERING PLACES"Z"/ + + START + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 257 IMP,3050,IMP 7:20 PM 9/16/1973 + + /VERY DISTANT HOST + 37000/ VDHSTART: + ITBVP=0 + /FILL IN THE VDH/IMP INITIALIZATION TABLE + + LEV CON +03366 C VDHD VDH2,JST VDH2. I,NOP +37717 121407 C +02346 101000 C +02361 003366 C +21126 C VDHD VDH3,JST VDH3. I,NOP +37720 121661 C +02347 101000 C +02362 021126 C + + + /BUILD INSTRUCTIONS DEPENDENT ON M.N & H.N AND FINISH TABLE + + IRPC [L,,1234] + REPEAT 1IF VZ L-1-H.N,[ + + VD.HOI=H'L'OTIL + VD.HII=H'L'INIL + VD.HIB=H'L'INBP + VD.IHB=H'L'OTBP + VDHD SKST H.N,NOP,H'L'RDY + VDHD IHED H.N,IRS VD.OT,H'L'FOUT + VDHD IHOT H.N,NOP,H'L'ROUT + VDHD HER H.N,NOP,H'L'ERR + VDHD HIN H.N,JMP HIFAKE,H'L'IN + VDHD EMIT H.N,SKP,H'L'EOM + VDHD HENABT H.N, IRS VD.RDY, H'L'ENAB + ] + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 258 IMP,3050,IMP 7:20 PM 9/16/1973 + + /END THE REPEAT +21663 C ENDIRP +37721 101000 C +02350 070160 C +02363 021663 C +16125 C +37722 024475 C +02351 030260 C +02364 016125 C +17057 C +37723 101000 C +02352 030060 C +02365 017057 C +13171 C +37724 101000 C +02353 070060 C +02366 013171 C +13201 C +37725 003531 C +02354 030160 C +02367 013201 C +13304 C +37726 100000 C +02355 070260 C +02370 013304 C +16317 C +37727 024476 C +02356 030560 C +02371 016317 C + /HOST34=0 + V.1=74000 + V.2=134000 + V.3=154000 + V.4=164000 + V.5=170000 + /HOST34>0 + V..1=70000 + V..2=130000 + V..3=150000 + V..4=160000 + V..5=170000 + /HOST34<0 + V...1=60000 + V...2=120000 + V...3=140000 + V...4=160000 + V...5=160000 + + IRPC [L,,12345] + + REPEAT 1IF VZ L-1-M.N,[ + + VD.IIM=V.'L + VD..IM=V..'L + VD...M=V...'L + VD.OIP=M'L'OTBP + VDHD 64 M.N,VD.II,M2I'L + + + VDHD 71 M.N,VD.OI,I2M'L + + ] /END OF REPEAT +00066 C ENDIRP +37730 037124 C +02357 010113 C +02372 000066 C +00073 C +37731 037331 C +02360 012117 C +02373 000073 C + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 259 IMP,3050,IMP 7:20 PM 9/16/1973 + + + + + /PACKET CONTROL WORD FORMAT + + /BITS MEANINGS + /1 LAST PACKET BIT + /2 PACKET'S ODD/EVEN BIT + /3-8 PACKET'S WORD COUNT + / 0 = ACKS ALONE + / 1-63 = NUMBER OF WORDS (INCLUDING LEADER) + /9 HOST/IMP BIT -- ONE FROM HOST + /10 UNUSED + /11-12 UNUSED (CHANNEL 3 < CHANNEL 2 ACKS) + /13 CHANNEL 1 ACK + /14 CHANNEL 0 ACK + /15 UNUSED (EXTENDED CHANNEL NUMBER) + /16 CHANNEL NUMBER + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 260 IMP,3050,IMP 7:20 PM 9/16/1973 + + /VERY DISTANT HOST VARIABLES + VDHNC=2 /NUMBER OF CHANNELS + + LEV VAR +37000 V VD.TB: BSS VDHNC /TRANSMIT BUFFER POINTERS + /ZERO MEANS UNUSED + +37002 V VD.RB: BSS VDHNC /RECEIVE BUFFER POINTERS + /ZERO MEANS UNUSED + + VD.ZVB: /BEGINNING OF VARIABLES TO BE ZEROEI + +37004 000000 V VD.TFP: 0 /TRANSMIT FILL POINTER -- MUST "SEQ1 +37005 000000 V VD.TEP: 0 /TRANSMIT EMPTY POINTER + +37006 000000 V VD.REP: 0 /RECEIVE EMPTY POINTER -- MUST "SEQ1 + +37007 V VD.TOE: BSS VDHNC /TRANSMIT ODD/EVEN BITS + +37011 V VD.ROE: BSS VDHNC /RECEIVE ODD/EVEN BITS + +37013 000000 V VD.T: 0 /COUNTS IF TOO LONG WITHOUT ACK + /POSITIVE MEANS TOO LONG +37014 000000 V VD.R: 0 /COUNTS IF IT IS TIME TO SEND DUPL T + /POSITIVE MEANS SEND ON +37015 000000 V VD.D: 0 /COUNTS IF LINE HAS BEEN HELD DEAD T + /NEG MEANS NOT LONG ENOUGH + +37016 V VD.TE: BSS VDHNC /TRANSMIT LAST PACKET BIT +37020 V VD.RE: BSS VDHNC /RECEIVE LAST PACKET BIT + + + VD.ZVE: /END OF VARIABLES TO BE ZEROED + +37022 000000 V VD.HOL: 0 /EXPECTING OUTPUT OF LEADER FLAG + +37023 000000 V VD.RCN: 0 /RECEIVE CHANNEL NUMBER + +37024 000000 V VD.EXP: 0 /200 IF EXPECTING PKTS FROM HOST + /0 IF EXPECTING FROM SELF (LOOPED) + 15SECS=30 + 5SECS=10 + 2.5SECS=4 + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 261 IMP,3050,IMP 7:20 PM 9/16/1973 + + /VERY DISTANT HOST INITIALIZATION + + LEV BCK +37025 000000 7 VD.I: 0 +37026 005732 7 LDA (4000) +37027 026567 7 IMA VDHUPF /MARK VDH AS UP +37030 100040 7 SZE /WAS ALREADY UP? +37031 103025 7 JMP VD.I I /YES, JUST GO AWAY QUIETLY +37032 011000 7 STA VD.TB /ZERO RECEIVE AND TRANSMIT BUFFER ': +37033 011001 7 STA VD.TB 1 +37034 011002 7 STA VD.RB +37035 011003 7 STA VD.RB 1 +37036 005733 7 LDA (200) /BEGIN EXPECTING LINE UNLOOPED +37037 011024 7 STA VD.EXP +37040 001001 7 INH ALL +37041 121734 7 0 JST (GETFRE) I +37042 003112 7 0 JMP VD.I9 /NO BUFFERS FREE +37043 004000 7 0 LDA 0 +37044 015735 7 0 ADD (100000+CNTL+1) +37045 010024 7 0 STA M1INBP+2"T"M.N +37046 015736 7 0 ADD (BUFE-CNTL-1) +37047 010025 7 0 STA M1INBP+2"T"M.N+1 +37050 073737 7 0 LDX (-MAXVDH) +37051 045732 7 0 LDA ITBVDH+MAXVDH X /VDHDEFS +37052 111740 7 0 STA (ITBVDL+MAXVDH XI) I +37053 024000 7 0 IRS 0 +37054 003051 7 0 JMP .-3 +37055 030473 7 0 M1IN+M.N +37056 021060 7 0 JST VD.REI +37057 103025 7 0 JMP VD.I I + + LEV [VDI,T.O] LCK ALL +37060 000000 1 0 VD.REI: 0 /REINITIALIZE +37061 073741 1 0 LDX (VD.ZVB 0-VD.ZVE +37062 140040 1 0 CRA /ZERO VARIABLES WHICH NEED IT +37063 051022 1 0 STA VD.ZVE X +37064 024000 1 0 IRS 0 +37065 003063 1 0 JMP .-2 +37066 010036 1 0 STA VD.OIP /CLEAR OUTPUT INTERRUPT PENDING F1 +37067 072124 1 0 LDX MINUS4 /FREE ANY BUFFERS +37070 033022 1 0 STX VD.HOL /INITIALIZE TO NON-ZERO +37071 032475 1 0 STX VD.OT /FIX OUTPUT TYPE FLAG *TEMP* +37072 140040 1 0 VD.REK: CRA +37073 067004 1 0 IMA VD.TB 4 X +37074 101040 1 0 SNZ +37075 003103 1 0 JMP VD.REJ +37076 033114 1 0 STX VD.REX +37077 140100 1 0 SSP +37100 010000 1 0 STA 0 +37101 120671 1 0 JST FLUSHI I +37102 073114 1 0 LDX VD.REX +37103 024000 1 0 VD.REJ: IRS 0 +37104 003072 1 0 JMP VD.REK +37105 005742 1 0 LDA (-15SECS +37106 011015 1 0 STA VD.D /MARK TO HOLD LINE DEAD +37107 005743 1 0 LDA (NOP /DROP READY LINE +37110 111744 1 0 STA (SKST H.N) I + + +37111 103060 1 0 JMP VD.REI I /DONE, SO RETURN + +37112 024144 1 0 VD.I9: IRS VDHRSF /TRY AGAIN LATER +37113 003025 1 0 JMP VD.I + LEV VAR +37114 000000 V VD.REX: 0 + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 262 IMP,3050,IMP 7:20 PM 9/16/1973 + + /VERY DISTANT HOST INPUT INTERRUPT ROUTINE + LEV VAR +37115 000000 V VD.IK: 0 /SAVED KEYS +37116 000000 V VD.IIB: 0 /BUFFER POINTER +37117 000000 V VD.IA: 0 /SAVED A +37120 000000 V VD.IX: 0 /SAVED X +37121 000000 V VD.IM: 0 /SAVED MASK +37122 000000 V VD.RBL: 0 /RECEIVE BUFFER LENGTH +37123 000000 V VD.CWP: 0 /POINTER TO PACKET CONTROL WORD + +37124 000000 1 0 VD.II: INT VDI +37125 011117 1 0 STA VD.IA /SAVE MASK AND REGISTERS +37126 033120 1 0 STX VD.IX +37127 105745 1 0 LDA (HOST34) I +37130 073746 1 0 LDX (VD.IIM) /HOST34=0 +37131 100040 1 0 SZE +37132 073747 1 0 LDX (VD..IM) /HOST34>0 +37133 100400 1 0 SPL +37134 073750 1 0 LDX (VD...M) /HOST34<0 +37135 004000 1 0 LDA 0 +37136 170120 1 0 SMK INTM +37137 026134 1 0 IMA PRIM +37140 011121 1 0 STA VD.IM +37141 000043 1 0 INK +37142 011115 1 0 STA VD.IK +37143 120672 1 0 JST DODXA I RET VDI +37144 004025 1 LDA M1INBP+1 2"T"M.N /GET BUFFER POINTER +37145 140100 1 SSP +37146 017751 1 SUB (BUFE /SAVE BUFFER POINTER +37147 011116 1 STA VD.IIB +37150 015752 1 ADD (CNTL 1 +37151 011123 1 STA VD.CWP +37152 005015 1 LDA VD.D /IS LINE BEING HELD DEAD +37153 100400 1 SPL +37154 003171 1 JMP VD.II2 /YES +37155 070473 1 M1ERR M.N /ERROR? +37156 100000 1 SKP +37157 003171 1 JMP VD.II2 /YES +37160 105123 1 LDA VD.CWP I +37161 007733 1 ANA (200) +37162 013024 1 ERA VD.EXP /IS PACKET FROM WHOM EXPECTED? +37163 101040 1 SNZ +37164 003212 1 JMP VD.II1 /YES, GO PROCESS IT +37165 013024 1 ERA VD.EXP /NO, CHANGE STATE OF VD.EXP +37166 011024 1 STA VD.EXP +37167 001001 1 INH ALL + DEFHLT [VDH LOOP STATE CHANGED] +37170 021317 1 0 JST VD.APH + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 263 IMP,3050,IMP 7:20 PM 9/16/1973 + + LEV VDI +37171 005116 1 VD.II2: LDA VD.IIB /DO INPUT +37172 015735 1 VD.II8: ADD (100000 CNTL 1 +37173 010024 1 STA M1INBP 2"T"M.N +37174 015736 1 ADD (BUFE-CNTL-1 +37175 010025 1 STA M1INBP+1 2"T"M.N +37176 030473 1 M1IN M.N +37177 073120 1 LDX VD.IX /RESTORE MASK AND REGISTERS +37200 001001 1 INH MSK +37201 005121 1 0 LDA VD.IM +37202 170120 1 0 SMK INTM +37203 010134 1 0 STA PRIM +37204 000013 1 0 EXA +37205 005115 1 0 LDA VD.IK +37206 171020 1 0 OTK +37207 005117 1 0 LDA VD.IA +37210 000401 1 0 ENB VDI +37211 103124 1 JMP VD.II I /RETURN + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 264 IMP,3050,IMP 7:20 PM 9/16/1973 + +37212 105123 1 VD.II1: LDA VD.CWP I /PROCESS ACKS +37213 072113 1 LDX ZERO /CHANNEL ZERO ACK +37214 040576 1 ARS 2 +37215 021273 1 JST VD.AP +37216 072114 1 LDX ONE /CHANNEL ONE ACK +37217 105123 1 LDA VD.CWP I +37220 040575 1 ARS 3 +37221 021273 1 JST VD.AP +37222 105123 1 LDA VD.CWP I /IS PACKET A DUPLICATE +37223 006114 1 ANA ONE +37224 011023 1 STA VD.RCN /SAVE CHANNEL # FOR LATER USE +37225 010000 1 STA 0 +37226 105123 1 LDA VD.CWP I /GET PACKET O/E BIT +37227 041676 1 ALR 2 +37230 053011 1 ERA VD.ROE X /MATCH AGAINST RECEIVE O/E BIT +37231 100100 1 SLZ +37232 003171 1 JMP VD.II2 /DUPLICATE +37233 105123 1 LDA VD.CWP I /IS THERE ANY DATA +37234 141340 1 ICA +37235 006752 1 ANA C77 +37236 101040 1 SNZ +37237 003171 1 JMP VD.II2 /NO +37240 011122 1 STA VD.RBL +37241 073023 1 LDX VD.RCN /IS THERE ROOM FOR THIS BUFFER +37242 045002 1 LDA VD.RB X +37243 100040 1 SZE +37244 003171 1 JMP VD.II2 /NO +37245 105123 1 LDA VD.CWP I /SAVE LAST PACKET BIT FOR BACKGROUN +37246 006112 1 ANA SIGN +37247 051020 1 STA VD.RE X +37250 001001 1 INH FRE /IS THERE A FREE BUFFER +37251 104324 1 0 LDA FREE I +37252 101040 1 0 SNZ /POSITIVE NO IN A REG +37253 003171 1 0 JMP VD.II2 /NO +37254 011014 1 0 STA VD.R /MARK THAT THERE IS ACK TO SEND +37255 045011 1 0 LDA VD.ROE X /COMPLEMENT O/E BIT +37256 012114 1 0 ERA ONE +37257 051011 1 0 STA VD.ROE X +37260 005116 1 0 LDA VD.IIB /USE NEW BUFFER FOR INPUT +37261 051002 1 0 STA VD.RB X /PASS RECEIVED BUFFER TO BACKGROUND +37262 010000 1 0 STA 0 /GET BUFFER LENGTH +37263 005122 1 0 LDA VD.RBL /PUT COUNT IN BUFE +37264 050111 1 0 STA BUFE X + LEV VDI +37265 001001 1 VD.II7: INH FRE +37266 024563 1 0 IRS NFS /GET A FREE BUFFER NFS +37267 104324 1 0 LDA FREE I +37270 026324 1 0 IMA FREE +37271 000401 1 0 ENB VDI +37272 003172 1 JMP VD.II8 + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 265 IMP,3050,IMP 7:20 PM 9/16/1973 + + /VERY DISTANT HOST ACKNOWLEDGE PROCESSOR + /CALL WITH ACK BIT IN AC + +37273 000000 1 VD.AP: 0 +37274 053007 1 ERA VD.TOE X /IS THIS A DUPLICATE ACK +37275 101100 1 SLN +37276 003312 1 JMP VD.AP1 /YES +37277 045007 1 LDA VD.TOE X /COMPLEMENT TRANSMIT O/E BIT +37300 012114 1 ERA ONE +37301 051007 1 STA VD.TOE X +37302 045000 1 LDA VD.TB X +37303 001001 1 INH ALL +37304 100040 1 0 SZE /SPURIOUS ACK? +37305 003307 1 0 JMP VD.AP2 /NO + DEFHLT [VDH SPURIOUS ACK] +37306 021317 1 0 JST VD.APH /YES +37307 000401 1 0 VD.AP2: ENB VDI +37310 140500 1 SSM /MARK CHANNEL UNUSED +37311 051000 1 STA VD.TB X +37312 005753 1 VD.AP1: LDA (-5SECS /RESET T +37313 011013 1 STA VD.T +37314 004112 1 LDA SIGN /BRING READY LINE UP +37315 111744 1 STA (SKST H.N) I +37316 103273 1 JMP VD.AP I + + LCK M2I +37317 000000 1 0 VD.APH: 0 +37320 120745 1 0 JST HLTNCC I +37321 021060 1 0 JST VD.REI +37322 003171 1 0 JMP VD.II2 + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 266 IMP,3050,IMP 7:20 PM 9/16/1973 + + /VERY DISTANT HOST OUTPUT INTERRUPT + LEV VAR +37323 000000 V VD.OK: 0 /SAVED KEYS +37324 000000 V VD.OA: 0 /SAVED A +37325 000000 V VD.OX: 0 /SAVED X +37326 000000 V VD.OM: 0 /SAVED MASK +37327 000000 V VD.OB: 0 /SAVED POINTER +37330 000000 V VD.CW: 0 /CONTROL WORD + +37331 000000 2 0 VD.OI: INT VDO +37332 011324 2 0 STA VD.OA /SAVE MASK AND REGISTERS +37333 004502 2 0 LDA MOM +37334 170120 2 0 SMK INTM +37335 026134 2 0 IMA PRIM +37336 011326 2 0 STA VD.OM +37337 000043 2 0 INK +37340 011323 2 0 STA VD.OK +37341 120672 2 0 JST DODXA I RET VDO +37342 033325 2 STX VD.OX +37343 140040 2 CRA +37344 010036 2 STA VD.OIP /CLEAR OUTPUT INT PENDING FLAG + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 267 IMP,3050,IMP 7:20 PM 9/16/1973 + +37345 005015 2 LDA VD.D /LINE BEING HELD DEAD? +37346 100400 2 SPL +37347 003364 2 JMP VD.OI2 /YES +37350 021407 2 JST VD.OIS /SERVICE ONE CHANNEL +37351 021407 2 JST VD.OIS /SERVICE ANOTHER CHANNEL +37352 005014 2 LDA VD.R /ACK WAITING TO GO BACK? +37353 100400 2 SPL +37354 003364 2 JMP VD.OI2 /NO +37355 021377 2 JST VD.OIT +37356 005754 2 LDA (VD.CW /SETUP OUTPUT POINTER TO SEND CW +37357 010036 2 STA M1OTBP 2"T"M.N +37360 010037 2 VD.OI3: STA M1OTBP+1 2"T"M.N +37361 005755 2 LDA (-2.5SECS /RESET R +37362 011014 2 STA VD.R +37363 030073 2 M1OUT M.N /DO OUTPUT + + +37364 073325 2 VD.OI2: LDX VD.OX /RESTORE MASK AND REGISTERS +37365 001001 2 INH MSK +37366 005326 2 0 LDA VD.OM +37367 170120 2 0 SMK INTM +37370 010134 2 0 STA PRIM +37371 000013 2 0 EXA +37372 005323 2 0 LDA VD.OK +37373 171020 2 0 OTK +37374 005324 2 0 LDA VD.OA +37375 000401 2 0 ENB VDO +37376 103331 2 JMP VD.OI I /RETURN + + +37377 000000 2 VD.OIT: 0 /BUILD ACKS +37400 001001 2 INH VDI +37401 005012 2 1 LDA VD.ROE 1 +37402 041577 2 1 ALS 1 +37403 013011 2 1 ERA VD.ROE +37404 041576 2 1 ALS 2 +37405 011330 2 1 STA VD.CW +37406 103377 2 1 JMP VD.OIT I + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 268 IMP,3050,IMP 7:20 PM 9/16/1973 + + RET VDO +37407 000000 2 VD.OIS: 0 +37410 005005 2 LDA VD.TEP /TRY OTHER CHANNEL +37411 012114 2 ERA ONE +37412 011005 2 STA VD.TEP +37413 001001 2 INH VDI +37414 073005 2 1 LDX VD.TEP +37415 045000 2 1 LDA VD.TB X +37416 101040 2 1 SNZ +37417 103407 2 1 JMP VD.OIS I /NOTHING TO DO WITH CHANNEL +37420 100400 2 1 SPL +37421 003445 2 1 JMP VD.OI1 +37422 011327 2 1 STA VD.OB +37423 021377 2 1 JST VD.OIT +37424 045007 2 1 LDA VD.TOE X /SET UP MORE OF CONTROL WORD +37425 040676 2 1 ARR 2 +37426 013330 2 1 ERA VD.CW /O/E BIT +37427 013005 2 1 ERA VD.TEP /CHANNEL NUMBER +37430 053016 2 1 ERA VD.TE X /LAST PACKET BIT +37431 011330 2 1 STA VD.CW +37432 073327 2 1 LDX VD.OB /SET UP CONTROL WORD IN OUTPUT BUF*] +37433 044111 2 1 LDA BUFE X /PUT COUNT IN CW +37434 141240 2 1 ICR +37435 015330 2 1 ADD VD.CW +37436 050010 2 1 STA CNTL 1 X +37437 004000 2 1 LDA 0 /SET UP OUTPUT POINTERS +37440 015752 2 1 ADD (CNTL 1 +37441 010036 2 1 STA M1OTBP 2"T"M.N +37442 054111 2 1 ADD BUFE X +37443 140100 2 1 SSP 0"A"TWOQ +37444 003360 2 1 JMP VD.OI3 +37445 140040 2 1 VD.OI1: CRA +37446 067000 2 1 IMA VD.TB X +37447 140100 2 1 SSP /FREE BUFFER +37450 010000 2 1 STA 0 +37451 001001 2 1 INH FRE +37452 120671 2 0 JST FLUSHI I +37453 103407 2 0 JMP VD.OIS I + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 269 IMP,3050,IMP 7:20 PM 9/16/1973 + + /VERY DISTANT HOST TIMEOUT ROUTINE + + LEV T.O +37454 000000 5 VD.TO: 0 +37455 140040 5 CRA +37456 026476 5 IMA VD.RDY /DID IH FLAP READY LINE? +37457 100040 5 SZE +37460 003476 5 JMP VD.TO3 /YES +37461 005015 5 LDA VD.D /IS D COUNTING +37462 101400 5 SMI +37463 003471 5 JMP VD.TO1 /NO +37464 025015 5 IRS VD.D /WAITED LONG ENOUGH ? +37465 103454 5 JMP VD.TO I /NO +37466 005755 5 LDA (-2.5SECS /RESET R +37467 011014 5 STA VD.R +37470 103454 5 JMP VD.TO I +37471 005013 5 VD.TO1: LDA VD.T +37472 101400 5 SMI +37473 103454 5 JMP VD.TO I +37474 025013 5 IRS VD.T /HAS LINE GONE DEAD +37475 003501 5 JMP VD.TO2 /NO +37476 001001 5 VD.TO3: INH VDI +37477 021060 5 1 JST VD.REI /REINITIALIZE +37500 103454 5 1 JMP VD.TO I +37501 025014 5 1 VD.TO2: IRS VD.R /TIME TO SEND HELLO? +37502 101000 5 1 NOP +37503 103454 5 1 JMP VD.TO I + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 270 IMP,3050,IMP 7:20 PM 9/16/1973 + + /VERY DISTANT HOST BACKGROUND ROUTINE + LEV VAR +37504 000000 V VD.BM: 0 /SAVED MASK +37505 000000 V VD.IB: 0 +37506 000000 V VD.BB: 0 +37507 000000 V VD.BBT: 0 +37510 000000 V VD.BBF: 0 + + LEV VDB +37511 000000 3 VD.B: 0 +37512 001001 3 INH MSK +37513 004500 3 0 LDA IHM +37514 170120 3 0 SMK INTM +37515 026134 3 0 IMA PRIM +37516 011504 3 0 STA VD.BM +37517 000401 3 0 ENB VDB +37520 105756 3 LDA (HITT H.N) I /IS HOST WAITING FOR INPU +37521 022121 3 CAS MINUS1 +37522 100000 3 SKP +37523 003612 3 JMP VD.B1 /ND +37524 005743 3 LDA (NOP +37525 111757 3 STA (EMFH H.N) I +37526 073006 3 LDX VD.REP /HAS THE NEXT SEQUENTIAL PACKET ARR +37527 045002 3 LDA VD.RB X +37530 101040 3 SNZ +37531 003612 3 JMP VD.B1 /NO +37532 011505 3 STA VD.IB /SAVE BUFFER POINTER FOR LATER USF +37533 004454 3 LDA HILO H.N +37534 013760 3 ERA (HIFRST /INITIAL INPUT EXPECTED BY HI +37535 101040 3 SNZ +37536 003605 3 JMP VD.B4 /YES +37537 013761 3 ERA (0 0 HIFRST"X"VD.1P /HI EXPECTING LEADER +37540 100040 3 SZE +37541 003560 3 JMP VD.B3 /NO +37542 073505 3 LDX VD.IB /SAVE LEADER IN HOST BUFFER +37543 044011 3 LDA DATA X +37544 110052 3 STA VD.HIB I +37545 044012 3 LDA DATA 1 X +37546 024052 3 IRS VD.HIB +37547 110052 3 STA VD.HIB I +37550 073006 3 LDX VD.REP /LAST PACKET IN MESSAGE +37551 045020 3 LDA VD.RE X +37552 100400 3 SPL +37553 003605 3 JMP VD.B4 /YES +37554 001001 3 VD.B53: INH FRE /FLUSH THE BUFFER THE LEADER CAME ' +37555 073505 3 0 LDX VD.IB +37556 120671 3 0 JST FLUSHI I +37557 003577 3 0 JMP VD.B13 + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 271 IMP,3050,IMP 7:20 PM 9/16/1973 + + LEV VDB +37560 005505 3 VD.B3: LDA VD.IB /SWAP RECEIVED BUFFER WITH HOST BUF[ +37561 127762 3 IMA (HISP H.N) I +37562 010000 3 STA 0 +37563 050111 3 STA BUFE X +37564 001001 3 INH FRE /RETURN HOST BUFFER TO FREE LIST +37565 120671 3 0 JST FLUSHI I +37566 073505 3 0 LDX VD.IB /SET UP HARDWARE BUFFER POINTER +37567 044111 3 0 LDA BUFE X +37570 015505 3 0 ADD VD.IB +37571 015763 3 0 ADD (DATA +37572 010052 3 0 STA VD.HIB +37573 073006 3 0 LDX VD.REP +37574 045020 3 0 LDA VD.RE X +37575 100400 3 0 SPL +37576 111757 3 0 STA (EMFH H.N) I +37577 073006 3 0 VD.B13: LDX VD.REP +37600 140040 3 0 CRA +37601 051002 3 0 STA VD.RB X /CLEAR CHANNEL +37602 005006 3 0 LDA VD.REP /SEQUENCE REP +37603 012114 3 0 ERA ONE +37604 011006 3 0 STA VD.REP + LEV VDB +37605 001001 3 VD.B4: INH SIN +37606 000013 3 0 EXA +37607 120101 3 0 JST VD.HII I RET VDB +37610 001001 3 INH ALL +37611 120672 3 0 JST DODXA I RET VDB + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 272 IMP,3050,IMP 7:20 PM 9/16/1973 + +37612 073004 3 VD.B1: LDX VD.TFP /IS NEXT SEQUENTIAL OUTPUT CHANNEL , +37613 045000 3 LDA VD.TB X +37614 100040 3 SZE +37615 003704 3 JMP VD.B2 /NO +37616 051016 3 STA VD.TE X /CLEAR LAST PACKET INDICATOR +37617 004046 3 LDA VD.IHB /IS THERE SOMETHING TO SEND FROM F'1 +37620 101040 3 SNZ +37621 003704 3 JMP VD.B2 /NO +37622 121734 3 JST (GETFRE) I LCK FRE /CAN WE HAVE A FREE BUFF T +37623 003704 3 0 JMP VD.B2 /NO +37624 000401 3 0 ENB VDB +37625 033506 3 STX VD.BB /PUT BUFFER IN OUTPUT CHANNEL +37626 027022 3 IMA VD.HOL /LEADER? +37627 100040 3 SZE +37630 003646 3 JMP VD.B6 /YES +37631 004047 3 LDA VD.IHB+1 /SAVE LENGTH +37632 016046 3 SUB VD.IHB +37633 141206 3 AOA +37634 050111 3 STA BUFE X +37635 104046 3 VD.B6N: LDA VD.IHB I /COPY A WORD +37636 050011 3 STA DATA X +37637 024000 3 IRS 0 +37640 024046 3 IRS VD.IHB +37641 004047 3 LDA VD.IHB+1 /DONE? +37642 016046 3 SUB VD.IHB +37643 101400 3 SMI +37644 003635 3 JMP VD.B6N /NO +37645 003662 3 JMP VD.B6D + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 273 IMP,3050,IMP 7:20 PM 9/16/1973 + +37646 104046 3 VD.B6: LDA VD.IHB I /COPY LEADER +37647 050011 3 STA DATA X +37650 024046 3 IRS VD.IHB +37651 104046 3 LDA VD.IHB I +37652 050012 3 STA DATA 1 X +37653 004115 3 LDA TWO /SET UP WORD COUNT +37654 050111 3 STA BUFE X +37655 004046 3 LDA VD.IHB +37656 024046 3 IRS VD.IHB +37657 016047 3 SUB VD.IHB 1 /ONLY LEADER IN MESSAGE? +37660 100040 3 SZE +37661 003676 3 JMP VD.B6K /NO +37662 140040 3 VD.B6D: CRA +37663 026475 3 IMA VD.OT /CLEAR FINAL OUT FLAG +37664 011022 3 STA VD.HOL /SET EXPECTING LEADER OR NOT +37665 100040 3 SZE +37666 004112 3 LDA SIGN /PASS LAST PACKET BIT TO OUTPUT +37667 073004 3 LDX VD.TFP +37670 051016 3 STA VD.TE X +37671 001001 3 INH SIN +37672 000013 3 0 EXA +37673 120077 3 0 JST VD.HOI I RET VDB /FAKE HOST INTERRUPT +37674 001001 3 INH SIN +37675 120672 3 0 JST DODXA I RET VDB +37676 073004 3 VD.B6K: LDX VD.TFP /FILL OUTPUT CHANNEL +37677 005506 3 LDA VD.BB +37700 051000 3 STA VD.TB X +37701 005004 3 LDA VD.TFP /SEQUENCE TFP +37702 012114 3 ERA ONE +37703 011004 3 STA VD.TFP + +37704 004036 3 VD.B2: LDA VD.OIP /OUTPUT INTERRUPT PENDING? +37705 001001 3 INH SIN +37706 000013 3 0 EXA +37707 101040 3 0 SNZ +37710 021331 3 0 JST VD.OI RET VDB /NO -- WAKE UP OUTPUT IT* +37711 001001 3 INH MSK +37712 005504 3 0 LDA VD.BM +37713 170120 3 0 SMK INTM +37714 010134 3 0 STA PRIM +37715 120672 3 0 JST DODXA I RET VDB +37716 103511 3 JMP VD.B I + + + + + *** THIS DOCUMENT MAY CONTAIN BBN PROPRIETARY INFORMATION. *** + *** FURNISHED FOR U. S. GOVERNMENT END USE ONLY. *** +PAGE 274 IMP,3050,IMP 7:20 PM 9/16/1973 + + LEV CON +37717 C ITBVDH: BSS MAXVDH +37732 004000 C CONSTANTS +37733 000200 C +37734 004372 C +37735 100010 C +37736 000101 C +37737 177765 C +37740 142374 C +37741 177762 C +37742 177750 C +37743 101000 C +37744 021663 C +37745 001005 C +37746 154000 C +37747 150000 C +37750 140000 C +37751 000111 C +37752 000010 C +37753 177770 C +37754 037330 C +37755 177774 C +37756 013140 C +37757 013314 C +37760 013400 C +37761 007453 C +37762 013334 C +37763 000011 C + VDHEND=37777 + START diff --git a/H316/tests/imp2.cmd b/H316/tests/imp2.cmd new file mode 100644 index 00000000..6502c13f --- /dev/null +++ b/H316/tests/imp2.cmd @@ -0,0 +1,19 @@ +;; *** IMP NODE #2 SETUP *** + +; IMP #2 connects to IMP #2 via modem line 1 on both ends ... + +; Set the simulator configuration ... +echo Creating standard configuration for IMP #2 ... +do impconfig.cmd +SET IMP NUM=2 + +; Load the IMP code ... +echo Loading IMP code ... +do impcode.cmd + +; Start up the modem links! +echo Attaching modem links ... +ATTACH MI1 4421::4431 + +; And we're done .. +echo Type GO to start ... diff --git a/H316/tests/imp3.cmd b/H316/tests/imp3.cmd new file mode 100644 index 00000000..1e4eeefe --- /dev/null +++ b/H316/tests/imp3.cmd @@ -0,0 +1,22 @@ +;; *** IMP NODE #3 SETUP *** + +; IMP #3 connects to IMP #2 and #4 both. Modem line 1 on this end connects +; to line 1 on the IMP 2 end, and line 2 on this end connects to IMP 3 line 1. + +; Set the simulator configuration ... +echo Creating standard configuration for IMP #3 ... +do impconfig.cmd +SET IMP NUM=3 + +; Load the IMP code ... +echo Loading IMP code ... +do impcode.cmd + +; Start up the modem links! +echo Attaching modem links ... +SET MI2 ENABLED +ATTACH MI1 4431::4421 +ATTACH MI2 4432::4441 + +; And we're done .. +echo Type GO to start ... diff --git a/H316/tests/imp4.cmd b/H316/tests/imp4.cmd new file mode 100644 index 00000000..355b7a6d --- /dev/null +++ b/H316/tests/imp4.cmd @@ -0,0 +1,20 @@ +;; *** IMP NODE #4 SETUP *** + +; IMP #4 coneects to IMP #3 via modem line 1 on this end and modem line +; 2 on the IMP 3 end ... + +; Set the simulator configuration ... +echo Creating standard configuration for IMP #4 ... +do impconfig.cmd +SET IMP NUM=4 + +; Load the IMP code ... +echo Loading IMP code ... +do impcode.cmd + +; Start up the modem links! +echo Attaching modem links ... +ATTACH MI1 4441::4432 + +; And we're done .. +echo Type GO to start ... diff --git a/H316/tests/impcode.cmd b/H316/tests/impcode.cmd new file mode 100644 index 00000000..af5213d3 --- /dev/null +++ b/H316/tests/impcode.cmd @@ -0,0 +1,8237 @@ +de all 000000 +de 00060 001261 +de 00061 001252 +de 00062 001017 +de 00063 025061 +de 00064 010043 +de 00065 010067 +de 00066 010113 +de 00067 010137 +de 00067 016012 +de 00070 010163 +de 00070 016020 +de 00071 012127 +de 00072 012123 +de 00073 012117 +de 00074 012113 +de 00074 013056 +de 00075 012107 +de 00075 013064 +de 00076 016034 +de 00100 013100 +de 00102 020022 +de 00103 005107 +de 00104 023033 +de 00105 003050 +de 00107 177721 +de 00110 177704 +de 00112 100000 +de 00114 000001 +de 00115 000002 +de 00116 000003 +de 00117 000004 +de 00120 000007 +de 00121 177777 +de 00122 177776 +de 00123 177775 +de 00124 177774 +de 00125 177773 +de 00126 177772 +de 00127 177773 +de 00130 000004 +de 00131 177770 +de 00132 177700 +de 00135 102104 +de 00143 177400 +de 00570 000004 +de 00574 031212 +de 00575 031304 +de 00576 031313 +de 00577 031202 +de 00600 031226 +de 00601 031236 +de 00602 031246 +de 00603 031256 +de 00604 031217 +de 00605 031160 +de 00606 031072 +de 00607 031055 +de 00610 031266 +de 00611 031276 +de 00612 031113 +de 00613 031076 +de 00622 032030 +de 00623 032040 +de 00624 032050 +de 00625 032060 +de 00626 032070 +de 00664 013210 +de 00665 003234 +de 00666 017347 +de 00667 003240 +de 00670 015371 +de 00671 005373 +de 00672 017343 +de 00677 053333 +de 00700 056155 +de 00745 022404 +de 00751 000010 +de 00752 000077 +de 00753 000100 +de 00766 016177 +de 00767 021664 +de 00775 013315 +de 00776 013141 +de 01000 003111 +de 01001 003031 +de 01002 001177 +de 01003 003021 +de 01004 003022 +de 01011 010045 +de 01012 024045 +de 01013 003012 +de 01014 024044 +de 01015 003011 +de 01016 003102 +de 01020 024133 +de 01021 140040 +de 01022 001001 +de 01023 030040 +de 01024 017560 +de 01025 041577 +de 01026 010047 +de 01027 005005 +de 01030 010046 +de 01031 005037 +de 01032 101000 +de 01033 000201 +de 01034 005561 +de 01035 000011 +de 01036 003154 +de 01037 001040 +de 01040 004047 +de 01041 101400 +de 01042 003046 +de 01043 131040 +de 01044 003043 +de 01045 007562 +de 01046 010000 +de 01047 005563 +de 01050 050032 +de 01051 015564 +de 01052 050033 +de 01053 005565 +de 01054 050020 +de 01055 005566 +de 01056 050021 +de 01057 143137 +de 01060 030071 +de 01061 003213 +de 01062 003073 +de 01063 030072 +de 01064 003213 +de 01065 003073 +de 01066 030073 +de 01067 003213 +de 01070 003073 +de 01071 030074 +de 01072 003213 +de 01073 005567 +de 01074 010044 +de 01075 010045 +de 01076 024045 +de 01077 003076 +de 01100 024044 +de 01101 003075 +de 01102 044020 +de 01103 013566 +de 01104 100040 +de 01105 003031 +de 01106 045140 +de 01107 010777 +de 01110 002777 +de 01111 031040 +de 01112 004046 +de 01113 011005 +de 01114 073570 +de 01115 044104 +de 01116 111571 +de 01117 024000 +de 01120 003115 +de 01121 005127 +de 01122 000201 +de 01123 005572 +de 01124 070042 +de 01125 005573 +de 01126 003154 +de 01127 001130 +de 01130 073570 +de 01131 105571 +de 01132 050104 +de 01133 024000 +de 01134 003131 +de 01135 024133 +de 01136 103574 +de 01137 001060 +de 01140 070471 +de 01141 001063 +de 01142 070472 +de 01143 001066 +de 01144 070473 +de 01145 001071 +de 01146 070474 +de 01147 040001 +de 01150 100001 +de 01153 040001 +de 01154 170120 +de 01155 073575 +de 01156 005002 +de 01157 050104 +de 01160 024000 +de 01161 003157 +de 01162 073576 +de 01163 030171 +de 01164 030172 +de 01165 030173 +de 01166 030174 +de 01167 030175 +de 01170 030470 +de 01171 030460 +de 01172 030450 +de 01173 030451 +de 01174 024000 +de 01175 003163 +de 01176 021177 +de 01200 000011 +de 01201 003202 +de 01202 000401 +de 01203 073577 +de 01204 024000 +de 01205 003204 +de 01206 000201 +de 01207 026000 +de 01210 170120 +de 01211 001001 +de 01212 042000 +de 01213 005600 +de 01214 010044 +de 01215 010045 +de 01216 024045 +de 01217 003216 +de 01220 024044 +de 01221 003215 +de 01222 043223 +de 01223 030471 +de 01224 003073 +de 01225 030472 +de 01226 003073 +de 01227 030473 +de 01230 003073 +de 01231 030474 +de 01232 003073 +de 01233 000001 +de 01234 000002 +de 01235 000004 +de 01236 000010 +de 01237 000020 +de 01240 000040 +de 01241 000100 +de 01242 000200 +de 01243 000400 +de 01244 001000 +de 01245 002000 +de 01246 000010 +de 01247 000004 +de 01250 000002 +de 01251 000001 +de 01253 001001 +de 01254 111601 +de 01255 133602 +de 01256 005252 +de 01257 111603 +de 01260 120062 +de 01262 030026 +de 01263 140040 +de 01264 010324 +de 01265 005604 +de 01266 010133 +de 01267 005273 +de 01270 010517 +de 01271 073274 +de 01272 002324 +de 01273 002000 +de 01274 102517 +de 01275 001001 +de 01276 000013 +de 01277 030451 +de 01300 030551 +de 01301 030251 +de 01302 000201 +de 01303 073605 +de 01304 044200 +de 01305 051551 +de 01306 024000 +de 01307 003304 +de 01310 024000 +de 01311 003310 +de 01312 000201 +de 01313 041577 +de 01314 010000 +de 01315 131041 +de 01316 003315 +de 01317 013606 +de 01320 101040 +de 01321 010000 +de 01322 005607 +de 01323 010075 +de 01324 005610 +de 01325 010077 +de 01326 004000 +de 01327 100040 +de 01330 005611 +de 01331 015612 +de 01332 050030 +de 01333 005613 +de 01334 050031 +de 01335 005610 +de 01336 010076 +de 01337 140407 +de 01340 010074 +de 01341 004077 +de 01342 100040 +de 01343 003347 +de 01344 024077 +de 01345 024076 +de 01346 024074 +de 01347 104077 +de 01350 110076 +de 01351 024077 +de 01352 024076 +de 01353 024074 +de 01354 003347 +de 01355 043356 +de 01356 030251 +de 01357 003371 +de 01360 030071 +de 01361 003371 +de 01362 030072 +de 01363 003371 +de 01364 030073 +de 01365 003371 +de 01366 030074 +de 01367 003371 +de 01370 030075 +de 01371 004077 +de 01372 013610 +de 01373 101040 +de 01374 003426 +de 01375 005614 +de 01376 010074 +de 01377 024074 +de 01400 003377 +de 01401 030026 +de 01402 004077 +de 01403 017615 +de 01404 100400 +de 01405 003326 +de 01406 104077 +de 01407 140401 +de 01410 126077 +de 01411 122077 +de 01412 100000 +de 01413 003416 +de 01414 110077 +de 01415 003326 +de 01416 140040 +de 01417 026077 +de 01420 010100 +de 01421 131041 +de 01422 003421 +de 01423 012100 +de 01424 010100 +de 01425 003326 +de 01426 073616 +de 01427 045451 +de 01430 050200 +de 01431 024000 +de 01432 003427 +de 01433 024000 +de 01434 003433 +de 01435 073605 +de 01436 045551 +de 01437 050200 +de 01440 024000 +de 01441 003436 +de 01442 030026 +de 01444 003442 +de 01445 054115 +de 01446 054114 +de 01447 054113 +de 01450 054112 +de 01451 054111 +de 01452 054110 +de 01453 054107 +de 01454 054106 +de 01455 054105 +de 01456 054104 +de 01457 054103 +de 01460 054102 +de 01461 054101 +de 01462 054100 +de 01463 054077 +de 01464 054076 +de 01465 054075 +de 01466 054074 +de 01467 054073 +de 01470 054072 +de 01471 054071 +de 01472 054070 +de 01473 054067 +de 01474 054066 +de 01475 054065 +de 01476 054064 +de 01477 054063 +de 01500 054062 +de 01501 054061 +de 01502 054060 +de 01503 054057 +de 01504 054056 +de 01505 054055 +de 01506 054054 +de 01507 054053 +de 01510 054052 +de 01511 054051 +de 01512 054050 +de 01513 054047 +de 01514 054046 +de 01515 054045 +de 01516 054044 +de 01517 054043 +de 01520 054042 +de 01521 054041 +de 01522 054040 +de 01523 054037 +de 01524 054036 +de 01525 054035 +de 01526 054034 +de 01527 054033 +de 01530 054032 +de 01531 054031 +de 01532 054030 +de 01533 054027 +de 01534 054026 +de 01535 054025 +de 01536 054024 +de 01537 054023 +de 01540 054022 +de 01541 054021 +de 01542 054020 +de 01543 054017 +de 01544 054016 +de 01545 054015 +de 01546 054014 +de 01547 054013 +de 01550 054012 +de 01551 054011 +de 01552 054010 +de 01553 054007 +de 01554 054006 +de 01555 054005 +de 01556 054004 +de 01557 102111 +de 01560 000001 +de 01561 177755 +de 01562 000006 +de 01563 001147 +de 01564 000004 +de 01565 100060 +de 01566 133000 +de 01567 172110 +de 01570 177752 +de 01571 070000 +de 01572 177757 +de 01573 177777 +de 01574 002000 +de 01575 177760 +de 01576 177776 +de 01600 176753 +de 01601 037775 +de 01602 037776 +de 01603 037774 +de 01604 000003 +de 01605 177674 +de 01606 000005 +de 01607 000011 +de 01610 000100 +de 01611 000002 +de 01612 000074 +de 01613 000177 +de 01614 100000 +de 01615 030000 +de 01616 177774 +de 02000 120672 +de 02001 001001 +de 02002 140040 +de 02003 170120 +de 02004 010134 +de 02005 026133 +de 02006 141206 +de 02007 111465 +de 02010 022114 +de 02011 022116 +de 02012 003202 +de 02013 101000 +de 02014 140040 +de 02015 010145 +de 02016 010136 +de 02017 010765 +de 02020 073466 +de 02021 045346 +de 02022 070042 +de 02023 045316 +de 02024 151266 +de 02025 024000 +de 02026 003021 +de 02027 073467 +de 02030 045361 +de 02031 151374 +de 02032 024000 +de 02033 003030 +de 02034 073470 +de 02035 045221 +de 02036 011212 +de 02037 045226 +de 02040 011213 +de 02041 140040 +de 02042 111212 +de 02043 025212 +de 02044 025213 +de 02045 003042 +de 02046 024000 +de 02047 003035 +de 02050 010144 +de 02051 131041 +de 02052 003051 +de 02053 010106 +de 02054 005471 +de 02055 111472 +de 02056 073473 +de 02057 005474 +de 02060 050414 +de 02061 141206 +de 02062 024000 +de 02063 003060 +de 02064 005475 +de 02065 010324 +de 02066 105476 +de 02067 006115 +de 02070 100040 +de 02071 004116 +de 02072 111477 +de 02073 105476 +de 02074 006114 +de 02075 010000 +de 02076 101040 +de 02077 010144 +de 02100 100040 +de 02101 005500 +de 02102 111501 +de 02103 045405 +de 02104 011445 +de 02105 045407 +de 02106 011446 +de 02107 004115 +de 02110 011212 +de 02111 073502 +de 02112 045447 +de 02113 040167 +de 02114 011213 +de 02115 005212 +de 02116 025212 +de 02117 041167 +de 02120 003126 +de 02121 024537 +de 02122 026324 +de 02123 110324 +de 02124 004324 +de 02125 015503 +de 02126 025213 +de 02127 003121 +de 02130 024000 +de 02131 003112 +de 02132 005504 +de 02133 010571 +de 02134 010573 +de 02135 140407 +de 02136 014537 +de 02137 014751 +de 02140 040575 +de 02141 041575 +de 02142 014115 +de 02143 010572 +de 02144 072122 +de 02145 045230 +de 02146 011212 +de 02147 045232 +de 02150 151234 +de 02151 011213 +de 02152 055236 +de 02153 111213 +de 02154 011213 +de 02155 025212 +de 02156 003152 +de 02157 140040 +de 02160 111213 +de 02161 024000 +de 02162 003145 +de 02163 004132 +de 02164 011212 +de 02165 072113 +de 02166 021374 +de 02167 024000 +de 02170 025212 +de 02171 003166 +de 02172 005505 +de 02173 111506 +de 02174 073507 +de 02175 045465 +de 02176 111510 +de 02177 024000 +de 02200 003175 +de 02201 103511 +de 02202 004567 +de 02203 010144 +de 02204 004145 +de 02205 140100 +de 02206 010145 +de 02207 004136 +de 02210 140100 +de 02211 003016 +de 02214 000160 +de 02215 032030 +de 02216 032030 +de 02217 030434 +de 02220 100063 +de 02221 177370 +de 02222 177730 +de 02223 176201 +de 02224 177740 +de 02225 177760 +de 02226 177771 +de 02227 177771 +de 02230 033317 +de 02231 032131 +de 02232 000326 +de 02233 000325 +de 02234 000014 +de 02235 000013 +de 02236 003070 +de 02237 003071 +de 02240 003072 +de 02241 003073 +de 02242 003321 +de 02243 004366 +de 02244 010264 +de 02245 012615 +de 02246 000101 +de 02247 013150 +de 02250 013151 +de 02251 013160 +de 02252 013161 +de 02253 013172 +de 02254 013202 +de 02255 013275 +de 02256 013305 +de 02257 000077 +de 02260 016126 +de 02261 016137 +de 02262 016147 +de 02263 017060 +de 02264 020543 +de 02265 021664 +de 02266 177660 +de 02267 177460 +de 02270 173600 +de 02271 163400 +de 02272 003334 +de 02273 100040 +de 02274 010303 +de 02275 012156 +de 02276 013072 +de 02277 000052 +de 02300 000056 +de 02301 000053 +de 02302 000057 +de 02303 070050 +de 02304 030150 +de 02305 013353 +de 02306 070250 +de 02307 016026 +de 02310 030250 +de 02311 000054 +de 02312 000055 +de 02313 030050 +de 02314 120464 +de 02315 070150 +de 02316 177664 +de 02317 177464 +de 02320 173624 +de 02321 163424 +de 02322 004136 +de 02323 100040 +de 02324 010303 +de 02325 012156 +de 02326 025061 +de 02327 000001 +de 02330 000772 +de 02331 000001 +de 02332 000773 +de 02333 101000 +de 02334 003531 +de 02335 013416 +de 02336 100000 +de 02337 025061 +de 02340 101000 +de 02341 000770 +de 02342 000771 +de 02343 101000 +de 02344 120464 +de 02345 101000 +de 02346 101000 +de 02347 101000 +de 02350 070160 +de 02351 030260 +de 02352 030060 +de 02353 070060 +de 02354 030160 +de 02355 070260 +de 02356 030560 +de 02357 010113 +de 02360 012117 +de 02361 000001 +de 02361 003366 +de 02362 000001 +de 02362 021126 +de 02363 000001 +de 02363 021663 +de 02364 000001 +de 02364 016125 +de 02365 000001 +de 02365 017057 +de 02366 000001 +de 02366 013171 +de 02367 000001 +de 02367 013201 +de 02370 000001 +de 02370 013304 +de 02371 000001 +de 02371 016317 +de 02372 000001 +de 02372 000066 +de 02373 000001 +de 02373 000073 +de 02375 005512 +de 02376 111513 +de 02377 005514 +de 02400 111515 +de 02401 140040 +de 02402 111516 +de 02403 111517 +de 02404 103374 +de 02405 170067 +de 02406 171067 +de 02407 172075 +de 02410 177777 +de 02411 174524 +de 02412 175637 +de 02413 175663 +de 02414 176744 +de 02415 176751 +de 02416 173373 +de 02417 175655 +de 02420 173433 +de 02421 176744 +de 02422 175557 +de 02423 176721 +de 02424 175566 +de 02425 175632 +de 02426 174464 +de 02427 175651 +de 02430 176745 +de 02431 175607 +de 02432 176700 +de 02433 174523 +de 02434 174532 +de 02435 175666 +de 02436 172274 +de 02437 175631 +de 02440 177030 +de 02441 176671 +de 02442 175627 +de 02443 170053 +de 02444 170061 +de 02445 170067 +de 02446 170075 +de 02447 025117 +de 02450 023066 +de 02451 030477 +de 02452 030056 +de 02453 025310 +de 02454 024012 +de 02455 030414 +de 02456 030474 +de 02457 004101 +de 02460 004206 +de 02461 004302 +de 02462 004347 +de 02463 004356 +de 02464 004365 +de 02465 003560 +de 02466 177750 +de 02467 177765 +de 02470 177773 +de 02471 003452 +de 02472 003450 +de 02473 177727 +de 02474 000272 +de 02475 000113 +de 02476 001005 +de 02477 005153 +de 02500 177775 +de 02501 020544 +de 02502 177742 +de 02503 000112 +de 02504 000024 +de 02505 032261 +de 02506 015155 +de 02507 177762 +de 02510 043433 +de 02511 003074 +de 02512 177477 +de 02513 072271 +de 02514 001400 +de 02515 072371 +de 02516 072471 +de 02517 072571 +de 03063 010047 +de 03064 010073 +de 03065 010117 +de 03066 010143 +de 03067 010167 +de 03074 105561 +de 03075 006124 +de 03076 072132 +de 03077 100040 +de 03100 073072 +de 03101 100400 +de 03102 073073 +de 03103 032500 +de 03104 073562 +de 03105 100040 +de 03106 073070 +de 03107 100400 +de 03110 073071 +de 03111 032501 +de 03112 073563 +de 03113 100040 +de 03114 073564 +de 03115 100400 +de 03116 073565 +de 03117 032502 +de 03120 072113 +de 03121 100040 +de 03122 072121 +de 03123 100400 +de 03124 072122 +de 03125 133566 +de 03126 073567 +de 03127 100040 +de 03130 073570 +de 03131 032070 +de 03132 073571 +de 03133 100400 +de 03134 073572 +de 03135 032067 +de 03136 073573 +de 03137 100040 +de 03140 073574 +de 03141 032075 +de 03142 073575 +de 03143 100400 +de 03144 073576 +de 03145 032074 +de 03146 121577 +de 03147 121600 +de 03150 131040 +de 03151 003150 +de 03152 101400 +de 03153 003150 +de 03154 121601 +de 03155 073602 +de 03156 005603 +de 03157 050032 +de 03160 024000 +de 03161 003157 +de 03162 005604 +de 03163 011174 +de 03164 072127 +de 03165 005605 +de 03166 151070 +de 03167 105606 +de 03170 016000 +de 03171 100040 +de 03172 117607 +de 03173 100040 +de 03175 025174 +de 03176 024000 +de 03177 003165 +de 03200 004131 +de 03201 011062 +de 03202 004117 +de 03203 050504 +de 03204 121610 +de 03205 121611 +de 03206 024000 +de 03207 025062 +de 03210 003202 +de 03211 004121 +de 03212 010137 +de 03213 010140 +de 03214 010134 +de 03215 170120 +de 03216 000401 +de 03217 131040 +de 03220 003217 +de 03221 100400 +de 03222 003217 +de 03223 005612 +de 03224 111613 +de 03225 005614 +de 03226 011410 +de 03227 005410 +de 03230 017614 +de 03231 010000 +de 03232 011412 +de 03233 143415 +de 03235 005234 +de 03236 051415 +de 03237 143421 +de 03241 005240 +de 03242 051421 +de 03243 000401 +de 03244 025410 +de 03245 003227 +de 03246 005615 +de 03247 011410 +de 03250 072113 +de 03251 133616 +de 03252 072114 +de 03253 001001 +de 03254 143260 +de 03255 021262 +de 03256 173616 +de 03257 143425 +de 03260 003254 +de 03261 003256 +de 03263 120745 +de 03264 000011 +de 03265 103262 +de 03267 000401 +de 03270 173616 +de 03271 005266 +de 03272 051425 +de 03273 024000 +de 03274 025410 +de 03275 003251 +de 03276 140040 +de 03277 100004 +de 03300 010137 +de 03301 004137 +de 03302 100400 +de 03303 004140 +de 03304 101400 +de 03305 021446 +de 03306 004415 +de 03307 027413 +de 03310 013413 +de 03311 100040 +de 03312 003316 +de 03313 025414 +de 03314 003320 +de 03315 120061 +de 03316 005617 +de 03317 011414 +de 03320 000401 +de 03322 101040 +de 03323 003331 +de 03324 000013 +de 03325 121620 +de 03326 001001 +de 03327 120672 +de 03330 003334 +de 03331 004063 +de 03332 010101 +de 03333 010077 +de 03334 073621 +de 03335 145446 +de 03336 100040 +de 03337 140500 +de 03340 041277 +de 03341 024000 +de 03342 003335 +de 03343 140040 +de 03344 040267 +de 03345 012452 +de 03346 011434 +de 03347 001001 +de 03350 000013 +de 03351 105433 +de 03352 120672 +de 03353 100020 +de 03354 004121 +de 03355 170026 +de 03356 101000 +de 03357 000201 +de 03360 025411 +de 03361 101000 +de 03362 140040 +de 03363 026144 +de 03364 100040 +de 03365 121622 +de 03366 101000 +de 03367 004172 +de 03370 101400 +de 03371 003223 +de 03372 072132 +de 03373 044265 +de 03374 101400 +de 03375 101040 +de 03376 003403 +de 03377 004000 +de 03400 016132 +de 03401 013623 +de 03402 003224 +de 03403 024000 +de 03404 003373 +de 03405 004106 +de 03406 003401 +de 03407 037511 +de 03433 003434 +de 03435 000433 +de 03436 000434 +de 03437 000435 +de 03440 000436 +de 03441 000504 +de 03442 000505 +de 03443 000506 +de 03444 000507 +de 03445 000765 +de 03447 103450 +de 03451 103446 +de 03452 004137 +de 03453 006120 +de 03454 041675 +de 03455 012140 +de 03456 007624 +de 03457 012140 +de 03460 012752 +de 03461 041675 +de 03462 101004 +de 03463 011560 +de 03464 140040 +de 03465 021525 +de 03466 000401 +de 03467 021543 +de 03470 004117 +de 03471 010504 +de 03472 010505 +de 03473 010506 +de 03474 010507 +de 03475 021543 +de 03476 004121 +de 03477 010573 +de 03500 021543 +de 03501 004127 +de 03502 011556 +de 03503 072113 +de 03504 001001 +de 03505 121625 +de 03506 024000 +de 03507 025556 +de 03510 003505 +de 03511 000401 +de 03512 021543 +de 03513 021543 +de 03514 004140 +de 03515 101400 +de 03516 103626 +de 03517 004137 +de 03520 101004 +de 03521 103627 +de 03522 030026 +de 03524 003522 +de 03526 001001 +de 03527 010515 +de 03530 004131 +de 03531 011556 +de 03532 005556 +de 03533 016131 +de 03534 010000 +de 03535 005630 +de 03536 120670 +de 03537 101000 +de 03540 025556 +de 03541 003532 +de 03542 103525 +de 03544 030026 +de 03545 004415 +de 03546 011557 +de 03547 021450 +de 03550 004415 +de 03551 017557 +de 03552 141044 +de 03553 101040 +de 03554 003547 +de 03555 103543 +de 03561 001005 +de 03562 177760 +de 03563 174000 +de 03564 170000 +de 03565 160000 +de 03566 020545 +de 03567 010163 +de 03570 016020 +de 03571 010137 +de 03572 016012 +de 03573 012107 +de 03574 013064 +de 03575 012113 +de 03576 013056 +de 03577 026070 +de 03600 020075 +de 03601 022320 +de 03602 177766 +de 03603 100001 +de 03604 030471 +de 03605 003207 +de 03606 020544 +de 03607 005153 +de 03610 016217 +de 03611 013256 +de 03612 000005 +de 03613 030456 +de 03614 177774 +de 03615 177772 +de 03616 004420 +de 03617 154360 +de 03620 040001 +de 03621 177767 +de 03622 037025 +de 03623 040300 +de 03624 177770 +de 03625 011133 +de 03626 002000 +de 03627 001022 +de 03630 001000 +de 04063 140040 +de 04064 011157 +de 04065 121417 +de 04066 021372 +de 04067 003065 +de 04070 005155 +de 04071 007603 +de 04072 050006 +de 04073 013155 +de 04074 013157 +de 04075 013160 +de 04076 050005 +de 04077 021435 +de 04100 121417 +de 04101 021473 +de 04102 003100 +de 04103 100000 +de 04104 003100 +de 04105 011155 +de 04106 007604 +de 04107 013604 +de 04110 101040 +de 04111 003063 +de 04112 005155 +de 04113 007605 +de 04114 100040 +de 04115 005606 +de 04116 014751 +de 04117 011157 +de 04120 004415 +de 04121 011156 +de 04122 121417 +de 04123 004415 +de 04124 017156 +de 04125 017607 +de 04126 100400 +de 04127 003134 +de 04130 005155 +de 04131 007610 +de 04132 100040 +de 04133 003063 +de 04134 001001 +de 04135 004542 +de 04136 016566 +de 04137 014541 +de 04140 016565 +de 04141 015157 +de 04142 022572 +de 04143 003122 +de 04144 003122 +de 04145 005611 +de 04146 027157 +de 04147 014542 +de 04150 010542 +de 04151 004107 +de 04152 041576 +de 04153 011161 +de 04154 003066 +de 04162 121612 +de 04163 003257 +de 04164 044111 +de 04165 140100 +de 04166 011262 +de 04167 044010 +de 04170 007613 +de 04171 013614 +de 04172 066010 +de 04173 056010 +de 04174 115262 +de 04175 111262 +de 04176 005605 +de 04177 073430 +de 04200 052005 +de 04201 050005 +de 04202 021435 +de 04203 005261 +de 04204 141206 +de 04205 023615 +de 04206 005615 +de 04207 014132 +de 04210 011261 +de 04211 121417 +de 04212 001001 +de 04213 105261 +de 04214 007604 +de 04215 013604 +de 04216 100040 +de 04217 003203 +de 04220 011262 +de 04221 021372 +de 04222 003211 +de 04223 033430 +de 04224 005261 +de 04225 017616 +de 04226 050006 +de 04227 105261 +de 04230 007617 +de 04231 111261 +de 04232 025262 +de 04233 040677 +de 04234 100400 +de 04235 003232 +de 04236 005262 +de 04237 141240 +de 04240 115261 +de 04241 141044 +de 04242 015620 +de 04243 050005 +de 04244 141044 +de 04245 052006 +de 04246 121621 +de 04247 003162 +de 04250 044030 +de 04251 007613 +de 04252 013614 +de 04253 050030 +de 04254 044000 +de 04255 007610 +de 04256 003177 +de 04257 005622 +de 04260 003177 +de 04263 121417 +de 04264 021372 +de 04265 003263 +de 04266 033431 +de 04267 121417 +de 04270 073431 +de 04271 005314 +de 04272 050006 +de 04273 001001 +de 04274 121623 +de 04275 003267 +de 04276 013622 +de 04277 050005 +de 04300 021435 +de 04301 121417 +de 04302 001001 +de 04303 004126 +de 04304 115624 +de 04305 100400 +de 04306 003301 +de 04307 105625 +de 04310 121626 +de 04311 003301 +de 04312 011314 +de 04313 003264 +de 04315 121417 +de 04316 173353 +de 04317 044111 +de 04320 100400 +de 04321 003315 +de 04322 011354 +de 04323 140500 +de 04324 050111 +de 04325 044005 +de 04326 007627 +de 04327 050005 +de 04330 105353 +de 04331 140100 +de 04332 111353 +de 04333 105354 +de 04334 015610 +de 04335 111354 +de 04336 140040 +de 04337 021435 +de 04340 121417 +de 04341 105353 +de 04342 100400 +de 04343 003315 +de 04344 005353 +de 04345 141206 +de 04346 023630 +de 04347 005630 +de 04350 017631 +de 04351 011353 +de 04352 003340 +de 04355 121417 +de 04356 073632 +de 04357 001001 +de 04360 121633 +de 04361 003355 +de 04362 140040 +de 04363 021435 +de 04364 003355 +de 04365 004145 +de 04367 121634 +de 04370 121417 +de 04371 003365 +de 04373 001001 +de 04374 004537 +de 04375 016563 +de 04376 016570 +de 04377 100400 +de 04400 103372 +de 04401 104324 +de 04402 101040 +de 04403 103372 +de 04404 026324 +de 04405 010000 +de 04406 024563 +de 04407 014751 +de 04410 050111 +de 04411 004106 +de 04412 050007 +de 04413 140040 +de 04414 050000 +de 04415 025372 +de 04416 103372 +de 04417 003266 +de 04436 101040 +de 04437 003446 +de 04440 004117 +de 04441 056004 +de 04442 056005 +de 04443 056006 +de 04444 056007 +de 04445 050010 +de 04446 005420 +de 04447 015635 +de 04450 050003 +de 04451 004000 +de 04452 073420 +de 04453 140100 +de 04454 051427 +de 04455 005435 +de 04456 051421 +de 04457 045427 +de 04460 001001 +de 04461 110401 +de 04462 010401 +de 04463 030041 +de 04464 121417 +de 04465 140040 +de 04466 066463 +de 04467 101100 +de 04470 143421 +de 04471 121417 +de 04472 003457 +de 04474 140040 +de 04475 026477 +de 04476 101040 +de 04477 103473 +de 04500 140040 +de 04501 011600 +de 04502 005636 +de 04503 011602 +de 04504 073601 +de 04505 105637 +de 04506 101040 +de 04507 003565 +de 04510 025600 +de 04511 105640 +de 04512 141140 +de 04513 006116 +de 04514 041576 +de 04515 140407 +de 04516 015641 +de 04517 011523 +de 04520 013642 +de 04521 011534 +de 04522 005643 +de 04524 001001 +de 04525 107637 +de 04526 101040 +de 04527 003565 +de 04530 113637 +de 04531 127637 +de 04532 113637 +de 04533 000401 +de 04535 023644 +de 04536 025473 +de 04537 101000 +de 04540 011160 +de 04541 007631 +de 04542 027160 +de 04543 006116 +de 04544 012115 +de 04545 101040 +de 04546 011602 +de 04547 012115 +de 04550 041672 +de 04551 113640 +de 04552 014000 +de 04553 016132 +de 04554 127640 +de 04555 015602 +de 04556 127640 +de 04557 024000 +de 04560 100000 +de 04561 072132 +de 04562 033601 +de 04563 025473 +de 04564 003576 +de 04565 000401 +de 04566 024000 +de 04567 003505 +de 04570 004132 +de 04571 027601 +de 04572 013601 +de 04573 101040 +de 04574 005600 +de 04575 100040 +de 04576 010477 +de 04577 103473 +de 04603 000077 +de 04604 000300 +de 04605 000200 +de 04606 177771 +de 04607 000050 +de 04610 000100 +de 04611 000002 +de 04612 015033 +de 04613 177770 +de 04614 000003 +de 04615 032371 +de 04616 032271 +de 04617 177477 +de 04620 176014 +de 04621 015205 +de 04622 000202 +de 04623 015161 +de 04624 020210 +de 04625 032261 +de 04626 015114 +de 04627 177677 +de 04630 033467 +de 04631 000010 +de 04632 000331 +de 04633 015504 +de 04634 037700 +de 04635 100010 +de 04636 000400 +de 04637 072671 +de 04640 072571 +de 04641 041700 +de 04642 001000 +de 04643 000017 +de 04644 000013 +de 05110 000011 +de 05111 003112 +de 05112 011140 +de 05113 033141 +de 05114 000043 +de 05115 011142 +de 05116 004122 +de 05117 170120 +de 05120 010134 +de 05121 000401 +de 05122 004330 +de 05123 001001 +de 05124 100040 +de 05125 003161 +de 05126 140401 +de 05127 010134 +de 05130 170120 +de 05131 073141 +de 05132 000013 +de 05133 005142 +de 05134 171020 +de 05135 005140 +de 05136 000401 +de 05137 103107 +de 05154 005710 +de 05155 010401 +de 05156 003171 +de 05157 105151 +de 05160 003215 +de 05161 010000 +de 05162 010514 +de 05163 140040 +de 05164 050002 +de 05165 066000 +de 05166 010330 +de 05167 101040 +de 05170 003154 +de 05171 000401 +de 05172 044003 +de 05173 011143 +de 05174 100400 +de 05175 003220 +de 05176 015711 +de 05177 011151 +de 05200 044005 +de 05201 100100 +de 05202 003407 +de 05203 044004 +de 05204 141340 +de 05205 006120 +de 05206 015712 +de 05207 011144 +de 05210 044004 +de 05211 100400 +de 05212 003157 +de 05213 105151 +de 05214 140401 +de 05215 107144 +de 05216 100040 +de 05217 003642 +de 05220 044006 +de 05221 007713 +de 05222 010000 +de 05223 044165 +de 05224 101040 +de 05225 103714 +de 05226 100400 +de 05227 003601 +de 05230 007715 +de 05231 016114 +de 05232 010000 +de 05233 044433 +de 05234 100040 +de 05235 003637 +de 05236 001001 +de 05237 004540 +de 05240 016564 +de 05241 141206 +de 05242 022573 +de 05243 003637 +de 05244 003637 +de 05245 004537 +de 05246 016563 +de 05247 016542 +de 05250 014566 +de 05251 016570 +de 05252 100400 +de 05253 003637 +de 05254 044653 +de 05255 140407 +de 05256 046653 +de 05257 101040 +de 05260 003637 +de 05261 011147 +de 05262 052653 +de 05263 050653 +de 05264 000401 +de 05265 033145 +de 05266 005147 +de 05267 022116 +de 05270 040575 +de 05271 100000 +de 05272 003277 +de 05273 022116 +de 05274 040575 +de 05275 014116 +de 05276 014116 +de 05277 016114 +de 05300 011150 +de 05301 054622 +de 05302 011146 +de 05303 005147 +de 05304 111146 +de 05305 046641 +de 05306 100040 +de 05307 005716 +de 05310 013150 +de 05311 141240 +de 05312 072514 +de 05313 011147 +de 05314 044111 +de 05315 140100 +de 05316 027147 +de 05317 066004 +de 05320 056004 +de 05321 115147 +de 05322 111147 +de 05323 044007 +de 05324 007717 +de 05325 073145 +de 05326 113720 +de 05327 072514 +de 05330 066007 +de 05331 056007 +de 05332 115147 +de 05333 111147 +de 05334 044006 +de 05335 007721 +de 05336 100040 +de 05337 021504 +de 05340 005146 +de 05341 050003 +de 05342 044005 +de 05343 007722 +de 05344 001001 +de 05345 101040 +de 05346 003357 +de 05347 044006 +de 05350 100400 +de 05351 003357 +de 05352 004514 +de 05353 073145 +de 05354 150363 +de 05355 050363 +de 05356 003363 +de 05357 004514 +de 05360 073145 +de 05361 150370 +de 05362 050370 +de 05363 024540 +de 05364 044440 +de 05365 100040 +de 05366 003604 +de 05367 121723 +de 05370 001001 +de 05371 000011 +de 05372 003604 +de 05374 044111 +de 05375 100400 +de 05376 003404 +de 05377 004324 +de 05400 050000 +de 05401 032324 +de 05402 024537 +de 05403 103373 +de 05404 140100 +de 05405 050111 +de 05406 103373 +de 05407 073143 +de 05410 040677 +de 05411 100100 +de 05412 003446 +de 05413 041677 +de 05414 141140 +de 05415 066160 +de 05416 100040 +de 05417 052160 +de 05420 100040 +de 05421 003452 +de 05422 065565 +de 05423 101000 +de 05424 044160 +de 05425 016106 +de 05426 100040 +de 05427 003433 +de 05430 004114 +de 05431 010452 +de 05432 003642 +de 05433 001001 +de 05434 004124 +de 05435 170120 +de 05436 010134 +de 05437 140040 +de 05440 000401 +de 05441 121724 +de 05442 072514 +de 05443 001001 +de 05444 021373 +de 05445 003116 +de 05446 040675 +de 05447 100100 +de 05450 064426 +de 05451 003642 +de 05452 001001 +de 05453 011576 +de 05454 121725 +de 05455 005576 +de 05456 021635 +de 05460 011152 +de 05461 044006 +de 05462 007726 +de 05463 066007 +de 05464 007726 +de 05465 013152 +de 05466 050006 +de 05467 044111 +de 05470 006112 +de 05471 014000 +de 05472 015727 +de 05473 050111 +de 05474 005730 +de 05475 056004 +de 05476 056005 +de 05477 056006 +de 05500 056007 +de 05501 056010 +de 05502 050011 +de 05503 103457 +de 05505 004416 +de 05506 016107 +de 05507 050003 +de 05510 044006 +de 05511 007721 +de 05512 100040 +de 05513 105731 +de 05514 101040 +de 05515 103504 +de 05516 004325 +de 05517 100040 +de 05520 003524 +de 05521 141206 +de 05522 010414 +de 05523 103504 +de 05524 033572 +de 05525 011573 +de 05526 050002 +de 05527 026341 +de 05530 127573 +de 05531 010325 +de 05532 004341 +de 05533 015732 +de 05534 011574 +de 05535 005572 +de 05536 015732 +de 05537 011575 +de 05540 072124 +de 05541 105575 +de 05542 111574 +de 05543 024000 +de 05544 003541 +de 05545 073572 +de 05546 044001 +de 05547 073573 +de 05550 050001 +de 05551 073572 +de 05552 044111 +de 05553 140100 +de 05554 016000 +de 05555 016117 +de 05556 073573 +de 05557 050012 +de 05560 131040 +de 05561 003560 +de 05562 050002 +de 05563 073572 +de 05564 103504 +de 05600 120745 +de 05601 072514 +de 05602 001001 +de 05603 021373 +de 05604 005143 +de 05605 100400 +de 05606 003622 +de 05607 010000 +de 05610 105144 +de 05611 050445 +de 05612 052646 +de 05613 050646 +de 05614 044440 +de 05615 101040 +de 05616 121723 +de 05617 001001 +de 05620 000011 +de 05621 003121 +de 05622 140100 +de 05623 010000 +de 05624 064453 +de 05625 064453 +de 05626 014131 +de 05627 000013 +de 05630 100400 +de 05631 121733 +de 05632 001001 +de 05633 000011 +de 05634 003121 +de 05636 120745 +de 05637 005143 +de 05640 100400 +de 05641 003646 +de 05642 072514 +de 05643 001001 +de 05644 021373 +de 05645 003121 +de 05646 010000 +de 05647 064453 +de 05650 003121 +de 05651 004326 +de 05652 101040 +de 05653 121734 +de 05654 004751 +de 05655 014541 +de 05656 016565 +de 05657 022572 +de 05660 101000 +de 05661 121734 +de 05662 004537 +de 05663 016563 +de 05664 016751 +de 05665 016570 +de 05666 100400 +de 05667 121734 +de 05670 104326 +de 05671 026326 +de 05672 010000 +de 05673 026340 +de 05674 050000 +de 05675 004751 +de 05676 014541 +de 05677 010541 +de 05700 004751 +de 05701 014566 +de 05702 010566 +de 05703 004112 +de 05704 050002 +de 05705 105735 +de 05706 050001 +de 05707 103736 +de 05710 000330 +de 05711 000646 +de 05712 001233 +de 05713 000077 +de 05714 006056 +de 05715 000037 +de 05716 000200 +de 05717 176777 +de 05720 050254 +de 05721 020000 +de 05722 000004 +de 05723 012604 +de 05724 026120 +de 05725 011133 +de 05726 050377 +de 05727 000011 +de 05730 000005 +de 05731 030434 +de 05732 040011 +de 05733 013106 +de 05734 005635 +de 05735 006664 +de 05736 006313 +de 06056 072514 +de 06057 044007 +de 06060 007674 +de 06061 011673 +de 06062 044005 +de 06063 141044 +de 06064 011661 +de 06065 013673 +de 06066 011664 +de 06067 044005 +de 06070 007675 +de 06071 100040 +de 06072 005676 +de 06073 013677 +de 06074 015673 +de 06075 011660 +de 06076 001001 +de 06077 105660 +de 06100 141044 +de 06101 017661 +de 06102 100400 +de 06103 003375 +de 06104 141140 +de 06105 022116 +de 06106 003375 +de 06107 101000 +de 06110 015700 +de 06111 011662 +de 06112 044005 +de 06113 007701 +de 06114 013701 +de 06115 101040 +de 06116 003431 +de 06117 105662 +de 06120 107660 +de 06121 000401 +de 06122 100040 +de 06123 103702 +de 06124 044005 +de 06125 007675 +de 06126 101040 +de 06127 103703 +de 06130 073673 +de 06131 001001 +de 06132 044165 +de 06133 100400 +de 06134 121704 +de 06135 007705 +de 06136 050165 +de 06137 072514 +de 06140 044005 +de 06141 007706 +de 06142 100040 +de 06143 003447 +de 06144 044006 +de 06145 121707 +de 06146 000401 +de 06147 010000 +de 06150 044504 +de 06151 072514 +de 06152 100040 +de 06153 005710 +de 06154 013711 +de 06155 011164 +de 06156 044005 +de 06157 141050 +de 06160 040572 +de 06161 015164 +de 06162 011164 +de 06163 001001 +de 06165 003302 +de 06166 003455 +de 06167 003227 +de 06170 105662 +de 06171 012114 +de 06172 101040 +de 06173 003204 +de 06174 044006 +de 06175 101400 +de 06176 003222 +de 06177 105660 +de 06200 052005 +de 06201 007712 +de 06202 100040 +de 06203 003222 +de 06204 004542 +de 06205 016566 +de 06206 014541 +de 06207 016565 +de 06210 141206 +de 06211 022572 +de 06212 003222 +de 06213 003222 +de 06214 004563 +de 06215 016537 +de 06216 141206 +de 06217 014570 +de 06220 100400 +de 06221 003244 +de 06222 005664 +de 06223 013713 +de 06224 121714 +de 06225 121704 +de 06226 103702 +de 06227 004541 +de 06230 016565 +de 06231 141206 +de 06232 022572 +de 06233 101000 +de 06234 121715 +de 06235 004563 +de 06236 016537 +de 06237 141206 +de 06240 014570 +de 06241 101400 +de 06242 121715 +de 06243 024566 +de 06244 024541 +de 06245 000401 +de 06246 033670 +de 06247 003350 +de 06250 003276 +de 06251 003455 +de 06252 024566 +de 06253 064010 +de 06254 044005 +de 06255 007716 +de 06256 050005 +de 06257 005717 +de 06260 121720 +de 06261 005664 +de 06262 072112 +de 06263 121714 +de 06264 121704 +de 06265 072514 +de 06266 132402 +de 06267 032402 +de 06270 021537 +de 06271 003463 +de 06272 044000 +de 06273 111667 +de 06274 121721 +de 06275 003463 +de 06276 004751 +de 06277 014566 +de 06300 010566 +de 06301 003253 +de 06302 000401 +de 06303 044006 +de 06304 141340 +de 06305 006120 +de 06306 011663 +de 06307 015722 +de 06310 011666 +de 06311 021537 +de 06312 103723 +de 06313 033665 +de 06314 105666 +de 06315 100040 +de 06316 103702 +de 06317 004514 +de 06320 111666 +de 06321 010000 +de 06322 044007 +de 06323 073665 +de 06324 101400 +de 06325 003334 +de 06326 005663 +de 06327 050002 +de 06330 016120 +de 06331 140407 +de 06332 014565 +de 06333 010565 +de 06334 044013 +de 06335 062002 +de 06336 100000 +de 06337 003342 +de 06340 064013 +de 06341 103724 +de 06342 044000 +de 06343 111667 +de 06344 000401 +de 06345 005665 +de 06346 140500 +de 06347 011670 +de 06350 021360 +de 06351 100100 +de 06352 003555 +de 06353 005670 +de 06354 026327 +de 06355 072327 +de 06356 050000 +de 06357 003471 +de 06361 001001 +de 06362 105660 +de 06363 141044 +de 06364 017661 +de 06365 141140 +de 06366 015700 +de 06367 011662 +de 06370 105662 +de 06371 113660 +de 06372 007725 +de 06373 111660 +de 06374 103360 +de 06375 044005 +de 06376 007701 +de 06377 013701 +de 06400 100040 +de 06401 103702 +de 06402 044005 +de 06403 007726 +de 06404 013676 +de 06405 066005 +de 06406 007727 +de 06407 013676 +de 06410 100040 +de 06411 003415 +de 06412 005730 +de 06413 052005 +de 06414 050005 +de 06415 140040 +de 06416 121720 +de 06417 132402 +de 06420 032402 +de 06421 103724 +de 06422 021537 +de 06423 003427 +de 06424 044000 +de 06425 111667 +de 06426 121721 +de 06427 005676 +de 06430 003453 +de 06431 105662 +de 06432 107660 +de 06433 100040 +de 06434 003402 +de 06435 044005 +de 06436 007727 +de 06437 101040 +de 06440 003422 +de 06441 007713 +de 06442 101040 +de 06443 003455 +de 06444 044005 +de 06445 007706 +de 06446 100040 +de 06447 004751 +de 06450 014566 +de 06451 010566 +de 06452 005727 +de 06453 072121 +de 06454 003456 +de 06455 140040 +de 06456 013664 +de 06457 121714 +de 06460 121704 +de 06461 072514 +de 06462 120671 +de 06463 021360 +de 06464 105660 +de 06465 101100 +de 06466 103724 +de 06467 073660 +de 06470 121731 +de 06471 005732 +de 06472 011667 +de 06473 001001 +de 06474 004327 +de 06475 101040 +de 06476 003464 +de 06477 011670 +de 06500 010000 +de 06501 100400 +de 06502 044003 +de 06503 010000 +de 06504 044007 +de 06505 013673 +de 06506 007674 +de 06507 100040 +de 06510 003532 +de 06511 044006 +de 06512 101400 +de 06513 003520 +de 06514 105660 +de 06515 052005 +de 06516 007712 +de 06517 003524 +de 06520 105660 +de 06521 017733 +de 06522 052005 +de 06523 141044 +de 06524 100040 +de 06525 003532 +de 06526 073670 +de 06527 066000 +de 06530 111667 +de 06531 003555 +de 06532 005670 +de 06533 140100 +de 06534 011667 +de 06535 105667 +de 06536 003475 +de 06540 073734 +de 06541 001001 +de 06542 044000 +de 06543 101040 +de 06544 103537 +de 06545 033667 +de 06546 010000 +de 06547 044001 +de 06550 013664 +de 06551 100040 +de 06552 003542 +de 06553 025537 +de 06554 103537 +de 06555 000401 +de 06556 004114 +de 06557 011672 +de 06560 073670 +de 06561 005670 +de 06562 100400 +de 06563 003625 +de 06564 011671 +de 06565 121735 +de 06566 044006 +de 06567 001001 +de 06570 121707 +de 06571 044006 +de 06572 006112 +de 06573 100040 +de 06574 005736 +de 06575 115737 +de 06576 026000 +de 06577 150343 +de 06600 005671 +de 06601 050343 +de 06602 005672 +de 06603 054517 +de 06604 050517 +de 06605 073670 +de 06606 044006 +de 06607 073660 +de 06610 101400 +de 06611 003622 +de 06612 121740 +de 06613 073670 +de 06614 105660 +de 06615 017733 +de 06616 052005 +de 06617 141044 +de 06620 073660 +de 06621 101040 +de 06622 121731 +de 06623 121741 +de 06624 003471 +de 06625 140100 +de 06626 011665 +de 06627 044003 +de 06630 011670 +de 06631 140040 +de 06632 050013 +de 06633 044004 +de 06634 150003 +de 06635 101040 +de 06636 003650 +de 06637 033671 +de 06640 010000 +de 06641 121735 +de 06642 073671 +de 06643 140040 +de 06644 050003 +de 06645 024000 +de 06646 025672 +de 06647 003633 +de 06650 066003 +de 06651 011671 +de 06652 073670 +de 06653 005665 +de 06654 001001 +de 06655 026326 +de 06656 110326 +de 06657 003565 +de 06674 000077 +de 06675 000004 +de 06676 000100 +de 06677 032271 +de 06700 001246 +de 06701 000014 +de 06702 005601 +de 06703 007063 +de 06704 005577 +de 06705 177437 +de 06706 000002 +de 06707 007244 +de 06710 000335 +de 06711 003165 +de 06712 000060 +de 06713 000200 +de 06714 015303 +de 06715 005635 +de 06716 177761 +de 06717 000400 +de 06720 005457 +de 06721 021321 +de 06722 040003 +de 06723 005651 +de 06724 005604 +de 06725 177477 +de 06726 177661 +de 06727 000300 +de 06730 000102 +de 06731 015347 +de 06732 000327 +de 06733 001400 +de 06734 000340 +de 06735 005504 +de 06736 000010 +de 06737 007257 +de 06740 015361 +de 06741 007222 +de 07063 044005 +de 07064 007327 +de 07065 101040 +de 07066 003134 +de 07067 105330 +de 07070 001001 +de 07071 121331 +de 07072 003220 +de 07073 011131 +de 07074 000401 +de 07075 072514 +de 07076 044005 +de 07077 007332 +de 07100 101040 +de 07101 003113 +de 07102 173131 +de 07103 044005 +de 07104 007333 +de 07105 101040 +de 07106 103334 +de 07107 105131 +de 07110 140500 +de 07111 111131 +de 07112 103334 +de 07113 021260 +de 07114 003125 +de 07115 173131 +de 07116 044010 +de 07117 021306 +de 07120 044007 +de 07121 021244 +de 07122 044006 +de 07123 007335 +de 07124 013132 +de 07125 073257 +de 07126 120670 +de 07127 003213 +de 07130 103336 +de 07134 105330 +de 07135 001001 +de 07136 121337 +de 07137 121340 +de 07140 033131 +de 07141 044000 +de 07142 006120 +de 07143 011133 +de 07144 072514 +de 07145 044005 +de 07146 007332 +de 07147 000401 +de 07150 101040 +de 07151 003166 +de 07152 001001 +de 07153 105341 +de 07154 013342 +de 07155 101040 +de 07156 103336 +de 07157 105343 +de 07160 111344 +de 07161 125341 +de 07162 044005 +de 07163 007333 +de 07164 101040 +de 07165 003233 +de 07166 021260 +de 07167 003176 +de 07170 073131 +de 07171 044030 +de 07172 021306 +de 07173 044014 +de 07174 007335 +de 07175 013132 +de 07176 073133 +de 07177 033257 +de 07200 120670 +de 07201 003215 +de 07202 072514 +de 07203 044005 +de 07204 007332 +de 07205 101040 +de 07206 103336 +de 07207 105343 +de 07210 121345 +de 07211 103336 +de 07212 103336 +de 07213 173131 +de 07214 120671 +de 07215 021222 +de 07216 140040 +de 07217 111131 +de 07220 121346 +de 07221 103334 +de 07223 073257 +de 07224 104700 +de 07225 000013 +de 07226 101040 +de 07227 121347 +de 07230 001001 +de 07231 120672 +de 07232 103222 +de 07233 073133 +de 07234 044453 +de 07235 017350 +de 07236 000013 +de 07237 101040 +de 07240 121351 +de 07241 001001 +de 07242 120672 +de 07243 003216 +de 07245 011257 +de 07246 007352 +de 07247 040672 +de 07250 027257 +de 07251 007353 +de 07252 100040 +de 07253 004130 +de 07254 015257 +de 07255 011257 +de 07256 103244 +de 07261 044006 +de 07262 007354 +de 07263 100040 +de 07264 003275 +de 07265 044005 +de 07266 007355 +de 07267 100040 +de 07270 005356 +de 07271 013357 +de 07272 011132 +de 07273 025260 +de 07274 103260 +de 07275 044010 +de 07276 001001 +de 07277 010515 +de 07300 044006 +de 07301 021244 +de 07302 044007 +de 07303 007335 +de 07304 013360 +de 07305 103260 +de 07307 001001 +de 07310 010515 +de 07311 007361 +de 07312 013362 +de 07313 100040 +de 07314 003317 +de 07315 005363 +de 07316 011132 +de 07317 005132 +de 07320 013364 +de 07321 101040 +de 07322 103306 +de 07323 004515 +de 07324 007365 +de 07325 010515 +de 07326 103306 +de 07327 000200 +de 07330 006664 +de 07331 015033 +de 07332 000002 +de 07333 000100 +de 07334 005601 +de 07335 070377 +de 07336 005637 +de 07337 015205 +de 07340 005577 +de 07341 015155 +de 07342 032271 +de 07343 006673 +de 07344 115155 +de 07345 015114 +de 07346 006360 +de 07347 016042 +de 07350 014445 +de 07351 013106 +de 07352 000300 +de 07353 040000 +de 07354 000400 +de 07355 000010 +de 07356 006000 +de 07357 002400 +de 07360 003400 +de 07361 000007 +de 07362 000004 +de 07363 004000 +de 07364 004400 +de 07365 177760 +de 10044 000011 +de 10045 033244 +de 10046 072113 +de 10050 000043 +de 10051 011245 +de 10052 070471 +de 10053 003231 +de 10054 004021 +de 10055 017625 +de 10056 010020 +de 10057 030471 +de 10060 005245 +de 10061 000013 +de 10062 171020 +de 10063 005243 +de 10064 073244 +de 10065 000401 +de 10066 103043 +de 10070 000011 +de 10071 033244 +de 10072 072114 +de 10074 000043 +de 10075 011245 +de 10076 070472 +de 10077 003231 +de 10100 004023 +de 10101 017625 +de 10102 010022 +de 10103 030472 +de 10104 005245 +de 10105 000013 +de 10106 171020 +de 10107 005243 +de 10110 073244 +de 10111 000401 +de 10112 103067 +de 10114 000011 +de 10115 033244 +de 10116 072115 +de 10120 000043 +de 10121 011245 +de 10122 070473 +de 10123 003231 +de 10124 004025 +de 10125 017625 +de 10126 010024 +de 10127 030473 +de 10130 005245 +de 10131 000013 +de 10132 171020 +de 10133 005243 +de 10134 073244 +de 10135 000401 +de 10136 103113 +de 10140 000011 +de 10141 033244 +de 10142 072116 +de 10144 000043 +de 10145 011245 +de 10146 070474 +de 10147 003231 +de 10150 004027 +de 10151 017625 +de 10152 010026 +de 10153 030474 +de 10154 005245 +de 10155 000013 +de 10156 171020 +de 10157 005243 +de 10160 073244 +de 10161 000401 +de 10162 103137 +de 10164 000011 +de 10165 033244 +de 10166 072117 +de 10170 000043 +de 10171 011245 +de 10172 070475 +de 10173 003231 +de 10174 004031 +de 10175 017625 +de 10176 010030 +de 10177 030475 +de 10200 005245 +de 10201 000013 +de 10202 171020 +de 10203 005243 +de 10204 073244 +de 10205 000401 +de 10206 103163 +de 10207 011243 +de 10210 044064 +de 10211 010000 +de 10212 044011 +de 10213 015626 +de 10214 011223 +de 10215 104324 +de 10216 101040 +de 10217 003227 +de 10220 026324 +de 10221 024563 +de 10222 015627 +de 10224 005207 +de 10225 050004 +de 10226 042011 +de 10227 005630 +de 10230 042013 +de 10231 032674 +de 10232 045254 +de 10233 011261 +de 10234 104324 +de 10235 101040 +de 10236 143604 +de 10237 024563 +de 10240 026324 +de 10241 015631 +de 10242 143262 +de 10247 010053 +de 10250 010077 +de 10251 010123 +de 10252 010147 +de 10253 010173 +de 10262 010317 +de 10263 010311 +de 10265 010275 +de 10266 010267 +de 10267 072030 +de 10270 010030 +de 10271 015625 +de 10272 026031 +de 10273 030475 +de 10274 003324 +de 10275 072026 +de 10276 010026 +de 10277 015625 +de 10300 026027 +de 10301 030474 +de 10302 003324 +de 10303 072024 +de 10304 010024 +de 10305 015625 +de 10306 026025 +de 10307 030473 +de 10310 003324 +de 10311 072022 +de 10312 010022 +de 10313 015625 +de 10314 026023 +de 10315 030472 +de 10316 003324 +de 10317 072020 +de 10320 010020 +de 10321 015625 +de 10322 026021 +de 10323 030471 +de 10324 017627 +de 10325 011611 +de 10326 026000 +de 10327 017630 +de 10330 050111 +de 10331 140040 +de 10332 050000 +de 10333 044005 +de 10334 100400 +de 10335 101100 +de 10336 100000 +de 10337 103632 +de 10340 005633 +de 10341 026111 +de 10342 011246 +de 10343 004000 +de 10344 056111 +de 10345 015634 +de 10346 011351 +de 10347 017635 +de 10350 103351 +de 10352 100040 +de 10353 003402 +de 10354 005246 +de 10355 010111 +de 10356 131040 +de 10357 003356 +de 10360 050001 +de 10361 004674 +de 10362 050003 +de 10363 044005 +de 10364 101100 +de 10365 003420 +de 10366 040677 +de 10367 100100 +de 10370 003404 +de 10371 040677 +de 10372 100100 +de 10373 103636 +de 10374 073611 +de 10375 132401 +de 10376 032401 +de 10377 030041 +de 10400 072674 +de 10401 143577 +de 10402 072674 +de 10403 121637 +de 10404 044005 +de 10405 141140 +de 10406 012106 +de 10407 101040 +de 10410 003375 +de 10411 004420 +de 10412 012674 +de 10413 100040 +de 10414 003426 +de 10415 044006 +de 10416 010417 +de 10417 003426 +de 10420 044007 +de 10421 007640 +de 10422 013261 +de 10423 101400 +de 10424 101040 +de 10425 103641 +de 10426 044004 +de 10427 140401 +de 10430 141050 +de 10431 011612 +de 10432 072674 +de 10433 052641 +de 10434 046653 +de 10435 100040 +de 10436 121642 +de 10437 005612 +de 10440 066641 +de 10441 052641 +de 10442 101040 +de 10443 003374 +de 10444 011612 +de 10445 052653 +de 10446 050653 +de 10447 005612 +de 10450 173643 +de 10451 140407 +de 10452 007612 +de 10453 013612 +de 10454 027612 +de 10455 013612 +de 10456 023644 +de 10457 003547 +de 10460 003563 +de 10461 022117 +de 10462 003566 +de 10463 003571 +de 10464 101100 +de 10465 003574 +de 10466 140040 +de 10467 066000 +de 10470 072674 +de 10471 023645 +de 10472 003475 +de 10473 101000 +de 10474 121642 +de 10475 062634 +de 10476 100000 +de 10477 003536 +de 10500 010000 +de 10501 044111 +de 10502 100400 +de 10503 003511 +de 10504 004324 +de 10505 050000 +de 10506 032324 +de 10507 024537 +de 10510 003513 +de 10511 140100 +de 10512 050111 +de 10513 024564 +de 10514 044002 +de 10515 100040 +de 10516 003543 +de 10517 044111 +de 10520 140100 +de 10521 016000 +de 10522 016116 +de 10523 072674 +de 10524 055613 +de 10525 100400 +de 10526 004112 +de 10527 051613 +de 10530 065620 +de 10531 101000 +de 10532 005612 +de 10533 101040 +de 10534 003374 +de 10535 003450 +de 10536 140500 +de 10537 050634 +de 10540 140100 +de 10541 010000 +de 10542 003514 +de 10543 121646 +de 10544 072674 +de 10545 073611 +de 10546 003517 +de 10547 022753 +de 10550 003560 +de 10551 003555 +de 10552 140040 +de 10553 066005 +de 10554 003470 +de 10555 140040 +de 10556 066006 +de 10557 003470 +de 10560 140040 +de 10561 066007 +de 10562 003470 +de 10563 140040 +de 10564 066004 +de 10565 003470 +de 10566 140040 +de 10567 066003 +de 10570 003470 +de 10571 140040 +de 10572 066002 +de 10573 003470 +de 10574 140040 +de 10575 066001 +de 10576 003470 +de 10577 010060 +de 10600 010104 +de 10601 010130 +de 10602 010154 +de 10603 010200 +de 10604 010054 +de 10605 010100 +de 10606 010124 +de 10607 010150 +de 10610 010174 +de 10625 000105 +de 10626 004000 +de 10627 100111 +de 10630 100001 +de 10631 100004 +de 10632 011116 +de 10633 010352 +de 10634 001562 +de 10635 001556 +de 10636 011170 +de 10637 011101 +de 10640 001000 +de 10641 011124 +de 10642 011127 +de 10643 040622 +de 10644 000020 +de 10645 001777 +de 10646 011144 +de 11102 120745 +de 11103 105366 +de 11104 010111 +de 11105 004537 +de 11106 016563 +de 11107 016751 +de 11110 100400 +de 11111 003123 +de 11112 105367 +de 11113 026342 +de 11114 111370 +de 11115 103371 +de 11116 072674 +de 11117 004124 +de 11120 050265 +de 11121 004112 +de 11122 050421 +de 11123 173367 +de 11124 120671 +de 11125 072674 +de 11126 103371 +de 11130 120745 +de 11131 021133 +de 11132 003103 +de 11134 005372 +de 11135 111373 +de 11136 005374 +de 11137 050265 +de 11140 050433 +de 11141 140040 +de 11142 050160 +de 11143 103133 +de 11145 011167 +de 11146 044001 +de 11147 073167 +de 11150 050003 +de 11151 131040 +de 11152 003151 +de 11153 050004 +de 11154 004112 +de 11155 052012 +de 11156 050012 +de 11157 005167 +de 11160 015375 +de 11161 011167 +de 11162 105144 +de 11163 011164 +de 11165 133167 +de 11166 103144 +de 11170 044007 +de 11171 013205 +de 11172 100040 +de 11173 003203 +de 11174 044004 +de 11175 101400 +de 11176 103376 +de 11177 004674 +de 11200 141206 +de 11201 010137 +de 11202 003124 +de 11203 072674 +de 11204 021101 +de 11205 175461 +de 11206 177777 +de 11207 000005 +de 11213 012114 +de 11214 111377 +de 11215 100400 +de 11216 003323 +de 11217 141140 +de 11220 010000 +de 11221 045331 +de 11222 011360 +de 11223 173400 +de 11224 055346 +de 11225 123401 +de 11226 003240 +de 11227 003245 +de 11230 021231 +de 11232 120745 +de 11233 105377 +de 11234 007402 +de 11235 013403 +de 11236 111377 +de 11237 003260 +de 11240 017360 +de 11241 017360 +de 11242 123401 +de 11243 021231 +de 11244 101000 +de 11245 105377 +de 11246 007403 +de 11247 100040 +de 11250 003263 +de 11251 045341 +de 11252 041477 +de 11253 055341 +de 11254 115401 +de 11255 040476 +de 11256 141216 +de 11257 051341 +de 11260 105401 +de 11261 051346 +de 11262 103404 +de 11263 105377 +de 11264 017405 +de 11265 111377 +de 11266 007403 +de 11267 100040 +de 11270 003260 +de 11271 073406 +de 11272 045331 +de 11273 123401 +de 11274 003300 +de 11275 003300 +de 11276 024000 +de 11277 003272 +de 11300 045340 +de 11301 011360 +de 11302 004000 +de 11303 140407 +de 11304 141340 +de 11305 173400 +de 11306 111377 +de 11307 141340 +de 11310 015407 +de 11311 051353 +de 11312 005360 +de 11313 051361 +de 11314 044433 +de 11315 100040 +de 11316 021133 +de 11317 105401 +de 11320 055346 +de 11321 040477 +de 11322 003257 +de 11323 140100 +de 11324 111377 +de 11325 003260 +de 11326 000161 +de 11327 001066 +de 11330 004202 +de 11331 000377 +de 11332 000177 +de 11333 000060 +de 11334 000060 +de 11335 177324 +de 11336 177704 +de 11337 177764 +de 11340 177771 +de 11366 010246 +de 11367 010611 +de 11370 110611 +de 11371 150577 +de 11372 101000 +de 11373 150247 +de 11374 177766 +de 11375 000011 +de 11376 001004 +de 11377 052620 +de 11400 012654 +de 11401 012644 +de 11402 177771 +de 11403 000006 +de 11404 012156 +de 11405 000002 +de 11406 177775 +de 11407 020274 +de 12110 033104 +de 12111 072117 +de 12112 003132 +de 12114 033104 +de 12115 072116 +de 12116 003132 +de 12120 033104 +de 12121 072115 +de 12122 003132 +de 12124 033104 +de 12125 072114 +de 12126 003132 +de 12130 033104 +de 12131 072113 +de 12132 033654 +de 12133 011103 +de 12134 000011 +de 12135 003136 +de 12136 000043 +de 12137 011105 +de 12140 004416 +de 12141 057632 +de 12142 017712 +de 12143 101400 +de 12144 003516 +de 12145 131040 +de 12146 003145 +de 12147 057637 +de 12150 011644 +de 12151 055625 +de 12152 051625 +de 12153 045620 +de 12154 100100 +de 12155 103713 +de 12156 004502 +de 12157 170120 +de 12160 026134 +de 12161 011652 +de 12162 140040 +de 12163 066634 +de 12164 101400 +de 12165 003173 +de 12166 140100 +de 12167 010000 +de 12170 120671 +de 12171 024564 +de 12172 073654 +de 12173 000401 +de 12174 044265 +de 12175 100040 +de 12176 003276 +de 12177 045660 +de 12200 141206 +de 12201 062627 +de 12202 101000 +de 12203 044622 +de 12204 051660 +de 12205 001001 +de 12206 145660 +de 12207 023714 +de 12210 003550 +de 12211 073654 +de 12212 000401 +de 12213 044317 +de 12214 100040 +de 12215 003363 +de 12216 044312 +de 12217 100040 +de 12220 003375 +de 12221 044445 +de 12222 101040 +de 12223 003500 +de 12224 140040 +de 12225 066421 +de 12226 100400 +de 12227 003262 +de 12230 100040 +de 12231 005715 +de 12232 013716 +de 12233 141340 +de 12234 012106 +de 12235 141340 +de 12236 151704 +de 12237 045704 +de 12240 016114 +de 12241 151665 +de 12242 011655 +de 12243 014117 +de 12244 151672 +de 12245 044646 +de 12246 073655 +de 12247 050000 +de 12250 004417 +de 12251 050002 +de 12252 004117 +de 12253 056000 +de 12254 056001 +de 12255 056002 +de 12256 056003 +de 12257 050004 +de 12260 073654 +de 12261 003465 +de 12262 005717 +de 12263 151665 +de 12264 005720 +de 12265 151672 +de 12266 003467 +de 12267 005721 +de 12270 151665 +de 12271 014117 +de 12272 151672 +de 12273 016117 +de 12274 010000 +de 12275 003252 +de 12276 100400 +de 12277 003500 +de 12300 016114 +de 12301 050265 +de 12302 022114 +de 12303 003267 +de 12304 003224 +de 12305 073361 +de 12306 055363 +de 12307 024000 +de 12310 003306 +de 12311 100040 +de 12312 120061 +de 12313 073654 +de 12314 125353 +de 12315 101000 +de 12316 004660 +de 12317 015355 +de 12320 151665 +de 12321 017356 +de 12322 151672 +de 12323 015357 +de 12324 010000 +de 12325 005354 +de 12326 026111 +de 12327 011653 +de 12330 005356 +de 12331 103332 +de 12332 001454 +de 12333 140407 +de 12334 072113 +de 12335 112660 +de 12336 027653 +de 12337 010111 +de 12340 005653 +de 12341 073654 +de 12342 001001 +de 12343 100040 +de 12344 021571 +de 12345 141206 +de 12346 053620 +de 12347 051620 +de 12350 105360 +de 12351 051645 +de 12352 003467 +de 12353 071615 +de 12354 012333 +de 12355 137675 +de 12356 177675 +de 12357 177671 +de 12360 026644 +de 12361 177722 +de 12362 044107 +de 12363 050634 +de 12364 140040 +de 12365 166634 +de 12366 050317 +de 12367 100040 +de 12370 003406 +de 12371 005722 +de 12372 015654 +de 12373 050370 +de 12374 003406 +de 12375 050634 +de 12376 140040 +de 12377 166634 +de 12400 050312 +de 12401 100040 +de 12402 003406 +de 12403 005723 +de 12404 015654 +de 12405 050363 +de 12406 173724 +de 12407 133725 +de 12410 005726 +de 12411 050003 +de 12412 011657 +de 12413 073654 +de 12414 044634 +de 12415 140100 +de 12416 015727 +de 12417 151665 +de 12420 011655 +de 12421 173724 +de 12422 131040 +de 12423 003422 +de 12424 050001 +de 12425 044111 +de 12426 140100 +de 12427 073654 +de 12430 151672 +de 12431 011656 +de 12432 005657 +de 12433 100040 +de 12434 003456 +de 12435 005730 +de 12436 026111 +de 12437 011653 +de 12440 005655 +de 12441 016117 +de 12442 010000 +de 12443 017656 +de 12444 015731 +de 12445 011450 +de 12446 017732 +de 12447 103450 +de 12451 100040 +de 12452 003524 +de 12453 005653 +de 12454 010111 +de 12455 073654 +de 12456 105655 +de 12457 141044 +de 12460 052646 +de 12461 127655 +de 12462 117655 +de 12463 115656 +de 12464 111656 +de 12465 140040 +de 12466 050445 +de 12467 004416 +de 12470 051632 +de 12471 131040 +de 12472 003471 +de 12473 051637 +de 12474 045677 +de 12475 011476 +de 12477 005711 +de 12500 050440 +de 12501 001001 +de 12502 005652 +de 12503 010134 +de 12504 170120 +de 12505 144071 +de 12506 011106 +de 12507 000013 +de 12510 005105 +de 12511 171020 +de 12512 005103 +de 12513 073104 +de 12514 000401 +de 12515 103106 +de 12516 005733 +de 12517 051625 +de 12520 045620 +de 12521 006122 +de 12522 051620 +de 12523 003156 +de 12524 001001 +de 12525 021526 +de 12527 120745 +de 12530 004000 +de 12531 026342 +de 12532 050000 +de 12533 000401 +de 12534 005653 +de 12535 010111 +de 12536 024564 +de 12537 044004 +de 12540 007734 +de 12541 141140 +de 12542 073654 +de 12543 054622 +de 12544 011653 +de 12545 140040 +de 12546 111653 +de 12547 003500 +de 12550 010000 +de 12551 131040 +de 12552 003551 +de 12553 056001 +de 12554 100400 +de 12555 140407 +de 12556 017735 +de 12557 100400 +de 12560 003211 +de 12561 064003 +de 12562 003575 +de 12563 120671 +de 12564 024564 +de 12565 073654 +de 12566 140040 +de 12567 151660 +de 12570 021571 +de 12572 120745 +de 12573 121736 +de 12574 003500 +de 12575 073654 +de 12576 140040 +de 12577 011657 +de 12600 145660 +de 12601 050634 +de 12602 000401 +de 12603 003415 +de 12605 033104 +de 12606 011103 +de 12607 033654 +de 12610 005604 +de 12611 150071 +de 12612 143613 +de 12613 012156 +de 12614 012156 +de 12616 012156 +de 12617 012156 +de 12665 000032 +de 12666 000034 +de 12667 000036 +de 12670 000040 +de 12671 000042 +de 12672 000033 +de 12673 000035 +de 12674 000037 +de 12675 000041 +de 12676 000043 +de 12677 030071 +de 12700 030072 +de 12701 030073 +de 12702 030074 +de 12703 030075 +de 12704 032101 +de 12705 032106 +de 12706 032113 +de 12707 032120 +de 12710 032125 +de 12711 175551 +de 12712 000012 +de 12713 011213 +de 12714 001777 +de 12715 000020 +de 12716 000003 +de 12717 000060 +de 12720 032777 +de 12721 011206 +de 12722 000317 +de 12723 000312 +de 12724 040634 +de 12725 140003 +de 12726 177470 +de 12727 000004 +de 12730 012451 +de 12731 001562 +de 12732 001556 +de 12733 014400 +de 12734 017400 +de 12735 002342 +de 12736 011133 +de 13057 033135 +de 13060 073056 +de 13061 033106 +de 13062 072116 +de 13063 003110 +de 13065 033135 +de 13066 073064 +de 13067 033106 +de 13070 072115 +de 13071 003110 +de 13073 033135 +de 13074 073072 +de 13075 033106 +de 13076 072114 +de 13077 003110 +de 13101 033135 +de 13102 073100 +de 13103 033106 +de 13104 072113 +de 13105 003110 +de 13107 033135 +de 13110 000011 +de 13111 003112 +de 13112 032675 +de 13113 011133 +de 13114 000043 +de 13115 011134 +de 13116 004501 +de 13117 170120 +de 13120 026134 +de 13121 011136 +de 13122 000401 +de 13123 142453 +de 13125 072675 +de 13126 005124 +de 13127 050453 +de 13130 004121 +de 13131 051137 +de 13132 003516 +de 13147 000050 +de 13152 000042 +de 13153 013323 +de 13154 013324 +de 13155 013325 +de 13156 013326 +de 13157 000051 +de 13162 000043 +de 13163 013327 +de 13164 013330 +de 13165 013331 +de 13166 013332 +de 13167 003014 +de 13170 070070 +de 13171 070060 +de 13173 070051 +de 13174 101000 +de 13175 101000 +de 13176 101000 +de 13177 101000 +de 13200 030170 +de 13201 030160 +de 13203 030151 +de 13204 003531 +de 13205 003531 +de 13206 003531 +de 13207 003531 +de 13211 151323 +de 13212 065323 +de 13213 004000 +de 13214 100400 +de 13215 003247 +de 13216 045327 +de 13217 057323 +de 13220 101400 +de 13221 103210 +de 13222 005177 +de 13223 051317 +de 13224 005210 +de 13225 051251 +de 13226 004000 +de 13227 140100 +de 13230 011255 +de 13231 014130 +de 13232 010000 +de 13233 001001 +de 13234 000013 +de 13235 021106 +de 13236 001001 +de 13237 120672 +de 13240 073255 +de 13241 045143 +de 13242 140401 +de 13243 100040 +de 13244 143251 +de 13245 120665 +de 13246 003241 +de 13247 004112 +de 13250 003223 +de 13257 140040 +de 13260 051333 +de 13261 011106 +de 13262 111535 +de 13263 045273 +de 13264 050453 +de 13265 045303 +de 13266 051313 +de 13267 000013 +de 13270 021106 +de 13271 120672 +de 13272 103256 +de 13273 013353 +de 13274 013353 +de 13276 013353 +de 13277 013416 +de 13300 013416 +de 13301 013416 +de 13302 013416 +de 13303 070270 +de 13304 070260 +de 13306 070251 +de 13307 100000 +de 13310 100000 +de 13311 100000 +de 13312 100000 +de 13353 005536 +de 13354 003417 +de 13355 004114 +de 13356 050504 +de 13357 140040 +de 13360 127535 +de 13361 101400 +de 13362 003367 +de 13363 005537 +de 13364 050453 +de 13365 140040 +de 13366 003470 +de 13367 045333 +de 13370 101040 +de 13371 003400 +de 13372 010000 +de 13373 050111 +de 13374 001001 +de 13375 120671 +de 13376 000401 +de 13377 072675 +de 13400 045313 +de 13401 011403 +de 13402 005537 +de 13404 003466 +de 13405 140040 +de 13406 051333 +de 13407 045313 +de 13410 011411 +de 13412 003457 +de 13413 045343 +de 13414 100040 +de 13415 003430 +de 13416 005540 +de 13417 050453 +de 13420 140040 +de 13421 051137 +de 13422 004000 +de 13423 041577 +de 13424 015541 +de 13425 151147 +de 13426 141206 +de 13427 003511 +de 13430 021124 +de 13431 003413 +de 13452 044453 +de 13453 051333 +de 13454 021124 +de 13455 045333 +de 13456 003466 +de 13457 005542 +de 13460 115543 +de 13461 111543 +de 13462 007544 +de 13463 101040 +de 13464 003357 +de 13465 005545 +de 13466 050453 +de 13467 005546 +de 13470 051137 +de 13471 001001 +de 13472 004537 +de 13473 016563 +de 13474 016570 +de 13475 100400 +de 13476 003452 +de 13477 104324 +de 13500 101040 +de 13501 003452 +de 13502 026324 +de 13503 024563 +de 13504 000401 +de 13505 051333 +de 13506 015547 +de 13507 151147 +de 13510 015550 +de 13511 140100 +de 13512 151157 +de 13513 045200 +de 13514 011515 +de 13516 005136 +de 13517 001001 +de 13520 170120 +de 13521 010134 +de 13522 000013 +de 13523 005134 +de 13524 171020 +de 13525 073135 +de 13526 005133 +de 13527 000401 +de 13530 103106 +de 13531 145147 +de 13532 140100 +de 13533 151147 +de 13534 003516 +de 13535 054177 +de 13536 013400 +de 13537 013357 +de 13540 014053 +de 13541 113432 +de 13542 000400 +de 13543 054147 +de 13544 003400 +de 13545 014544 +de 13546 176650 +de 13547 100011 +de 13550 000076 +de 14005 045042 +de 14006 012106 +de 14007 051147 +de 14010 004143 +de 14011 051167 +de 14012 103004 +de 14013 021004 +de 14014 045147 +de 14015 007627 +de 14016 013630 +de 14017 100040 +de 14020 103631 +de 14021 045167 +de 14022 012143 +de 14023 101040 +de 14024 125632 +de 14025 103631 +de 14027 072675 +de 14030 173633 +de 14031 044165 +de 14032 072675 +de 14033 100400 +de 14034 003272 +de 14035 044504 +de 14036 100040 +de 14037 003232 +de 14040 005026 +de 14041 103634 +de 14043 000100 +de 14044 000200 +de 14045 000300 +de 14046 040000 +de 14047 040100 +de 14050 040200 +de 14051 040300 +de 14052 121635 +de 14053 044504 +de 14054 022116 +de 14055 003052 +de 14056 101000 +de 14057 004000 +de 14060 041577 +de 14061 010000 +de 14062 105636 +de 14063 011003 +de 14064 105637 +de 14065 072675 +de 14066 007640 +de 14067 051167 +de 14070 005003 +de 14071 051147 +de 14072 007627 +de 14073 141140 +de 14074 015641 +de 14075 051137 +de 14076 017134 +de 14077 101400 +de 14100 103132 +de 14101 105642 +de 14102 011103 +de 14104 100000 +de 14105 003232 +de 14106 140040 +de 14107 066504 +de 14110 100040 +de 14111 104700 +de 14112 101040 +de 14113 003116 +de 14114 004107 +de 14115 111643 +de 14116 105644 +de 14117 011120 +de 14121 143137 +de 14122 003231 +de 14123 014243 +de 14124 013357 +de 14125 013355 +de 14126 014230 +de 14127 013357 +de 14130 014230 +de 14131 014230 +de 14132 014230 +de 14133 013357 +de 14134 114134 +de 14136 177777 +de 14230 065167 +de 14231 065167 +de 14232 140040 +de 14233 051147 +de 14234 005645 +de 14235 003273 +de 14236 005646 +de 14237 053167 +de 14240 051167 +de 14241 005647 +de 14242 003273 +de 14243 004675 +de 14244 012130 +de 14245 100040 +de 14246 005650 +de 14247 012126 +de 14250 051217 +de 14251 045147 +de 14252 007651 +de 14253 051177 +de 14254 010000 +de 14255 044165 +de 14256 072675 +de 14257 101400 +de 14260 007652 +de 14261 100040 +de 14262 003272 +de 14263 045147 +de 14264 007653 +de 14265 013654 +de 14266 101010 +de 14267 100040 +de 14270 003311 +de 14271 065167 +de 14272 005655 +de 14273 051137 +de 14274 001001 +de 14275 045167 +de 14276 010515 +de 14277 045147 +de 14300 053137 +de 14301 120670 +de 14302 103631 +de 14303 121635 +de 14304 003274 +de 14305 065217 +de 14306 100000 +de 14307 003236 +de 14310 021026 +de 14311 045147 +de 14312 007656 +de 14313 121657 +de 14314 003305 +de 14315 051137 +de 14316 045147 +de 14317 007660 +de 14320 012106 +de 14321 053042 +de 14322 051157 +de 14323 004675 +de 14324 013661 +de 14325 100040 +de 14326 105662 +de 14327 100040 +de 14330 025136 +de 14331 003341 +de 14332 045147 +de 14333 007663 +de 14334 013664 +de 14335 051147 +de 14336 105662 +de 14337 140407 +de 14340 011136 +de 14341 005665 +de 14342 103666 +de 14343 105667 +de 14344 101040 +de 14345 003353 +de 14346 105644 +de 14347 011350 +de 14351 003400 +de 14352 003361 +de 14353 140500 +de 14354 051177 +de 14355 045147 +de 14356 007670 +de 14357 013655 +de 14360 051147 +de 14361 005671 +de 14362 053137 +de 14363 051137 +de 14364 021464 +de 14365 003370 +de 14366 021026 +de 14367 172677 +de 14370 121672 +de 14371 003366 +de 14372 051207 +de 14373 045177 +de 14374 100400 +de 14375 003610 +de 14376 121673 +de 14377 003551 +de 14400 045177 +de 14401 121674 +de 14402 003412 +de 14403 021464 +de 14404 072675 +de 14405 003407 +de 14406 021026 +de 14407 121675 +de 14410 003406 +de 14411 003372 +de 14412 005676 +de 14413 053137 +de 14414 051137 +de 14415 021464 +de 14416 004000 +de 14417 015677 +de 14420 050111 +de 14421 072675 +de 14422 100000 +de 14423 021026 +de 14424 121675 +de 14425 003423 +de 14426 051207 +de 14427 172677 +de 14430 021520 +de 14431 001001 +de 14432 132401 +de 14433 032401 +de 14434 030041 +de 14435 121635 +de 14436 003435 +de 14437 003427 +de 14440 045177 +de 14441 121674 +de 14442 003444 +de 14443 003447 +de 14444 021026 +de 14445 003440 +de 14446 121635 +de 14447 172677 +de 14450 044111 +de 14451 100400 +de 14452 003446 +de 14453 072675 +de 14454 003456 +de 14455 021026 +de 14456 045177 +de 14457 121657 +de 14460 003455 +de 14461 051137 +de 14462 111667 +de 14463 003403 +de 14465 104677 +de 14466 015700 +de 14467 011135 +de 14470 045137 +de 14471 111135 +de 14472 025135 +de 14473 045147 +de 14474 111135 +de 14475 025135 +de 14476 045157 +de 14477 111135 +de 14500 025135 +de 14501 045167 +de 14502 111135 +de 14503 105701 +de 14504 140100 +de 14505 172677 +de 14506 050111 +de 14507 131040 +de 14510 003507 +de 14511 050001 +de 14512 004675 +de 14513 140500 +de 14514 050003 +de 14515 140040 +de 14516 050000 +de 14517 103464 +de 14521 005702 +de 14522 026111 +de 14523 011227 +de 14524 044111 +de 14525 140100 +de 14526 011543 +de 14527 140407 +de 14530 014000 +de 14531 015703 +de 14532 011535 +de 14533 017704 +de 14534 103535 +de 14536 140407 +de 14537 111543 +de 14540 005227 +de 14541 010111 +de 14542 103520 +de 14544 021464 +de 14545 072675 +de 14546 105667 +de 14547 101040 +de 14550 003610 +de 14551 105642 +de 14552 011553 +de 14554 003570 +de 14555 005646 +de 14556 153207 +de 14557 006120 +de 14560 153207 +de 14561 151207 +de 14562 172677 +de 14563 044005 +de 14564 007705 +de 14565 013706 +de 14566 050005 +de 14567 003616 +de 14570 045177 +de 14571 121707 +de 14572 105644 +de 14573 011574 +de 14575 003577 +de 14576 003612 +de 14577 045147 +de 14600 007655 +de 14601 013655 +de 14602 101040 +de 14603 003606 +de 14604 172677 +de 14605 003616 +de 14606 004114 +de 14607 003556 +de 14610 004115 +de 14611 003556 +de 14612 172677 +de 14613 044007 +de 14614 140500 +de 14615 050007 +de 14616 021520 +de 14617 001001 +de 14620 132401 +de 14621 032401 +de 14622 030041 +de 14623 121635 +de 14624 003623 +de 14625 003604 +de 14626 103710 +de 14627 007400 +de 14630 002000 +de 14631 013357 +de 14632 021431 +de 14633 054177 +de 14634 013127 +de 14635 013124 +de 14636 053432 +de 14637 053433 +de 14640 177760 +de 14641 114123 +de 14642 053170 +de 14643 056306 +de 14644 053313 +de 14645 000400 +de 14646 000004 +de 14647 004400 +de 14650 000704 +de 14651 000077 +de 14652 000340 +de 14653 040300 +de 14654 040200 +de 14655 003400 +de 14656 100077 +de 14657 015161 +de 14660 010000 +de 14661 000006 +de 14662 030457 +de 14663 157777 +de 14664 020000 +de 14665 014343 +de 14666 013466 +de 14667 053137 +de 14670 174377 +de 14671 000300 +de 14672 015064 +de 14673 022415 +de 14674 015114 +de 14675 015233 +de 14676 000100 +de 14677 100010 +de 14700 000005 +de 14701 153147 +de 14702 014536 +de 14703 001563 +de 14704 001557 +de 14705 177767 +de 14706 000010 +de 14707 022426 +de 14710 013405 +de 15034 011160 +de 15035 005521 +de 15036 011157 +de 15037 005522 +de 15040 011156 +de 15041 105156 +de 15042 101040 +de 15043 003060 +de 15044 010000 +de 15045 044005 +de 15046 141044 +de 15047 052006 +de 15050 007523 +de 15051 052006 +de 15052 013160 +de 15053 100040 +de 15054 003060 +de 15055 005156 +de 15056 025033 +de 15057 103033 +de 15060 025156 +de 15061 025157 +de 15062 003041 +de 15063 103033 +de 15065 004675 +de 15066 040576 +de 15067 140407 +de 15070 015524 +de 15071 011157 +de 15072 005522 +de 15073 011156 +de 15074 105156 +de 15075 100040 +de 15076 003110 +de 15077 133156 +de 15100 044111 +de 15101 140500 +de 15102 050111 +de 15103 004000 +de 15104 015525 +de 15105 072675 +de 15106 025064 +de 15107 103064 +de 15110 025156 +de 15111 025157 +de 15112 003074 +de 15113 103064 +de 15115 011153 +de 15116 033154 +de 15117 073526 +de 15120 024000 +de 15121 004000 +de 15122 023155 +de 15123 003150 +de 15124 003150 +de 15125 044000 +de 15126 013153 +de 15127 100040 +de 15130 003120 +de 15131 004000 +de 15132 013527 +de 15133 101040 +de 15134 111530 +de 15135 044001 +de 15136 050000 +de 15137 024000 +de 15140 004000 +de 15141 013155 +de 15142 100040 +de 15143 003135 +de 15144 005155 +de 15145 016114 +de 15146 011155 +de 15147 025114 +de 15150 073154 +de 15151 005153 +de 15152 103114 +de 15162 033204 +de 15163 011203 +de 15164 140100 +de 15165 015531 +de 15166 010000 +de 15167 044000 +de 15170 101100 +de 15171 003201 +de 15172 005203 +de 15173 100400 +de 15174 021361 +de 15175 021347 +de 15176 007532 +de 15177 013533 +de 15200 025161 +de 15201 073204 +de 15202 103161 +de 15206 011274 +de 15207 005534 +de 15210 011273 +de 15211 073535 +de 15212 044000 +de 15213 101040 +de 15214 003226 +de 15215 141044 +de 15216 052014 +de 15217 007523 +de 15220 052014 +de 15221 013274 +de 15222 100040 +de 15223 003226 +de 15224 025205 +de 15225 103205 +de 15226 024000 +de 15227 025273 +de 15230 003212 +de 15231 005274 +de 15232 103205 +de 15234 004000 +de 15235 113536 +de 15236 007537 +de 15237 113536 +de 15240 013540 +de 15241 011275 +de 15242 105541 +de 15243 011276 +de 15244 105542 +de 15245 011277 +de 15246 005534 +de 15247 011273 +de 15250 073535 +de 15251 044000 +de 15252 100040 +de 15253 003267 +de 15254 005275 +de 15255 050000 +de 15256 005276 +de 15257 050014 +de 15260 005277 +de 15261 050030 +de 15262 025233 +de 15263 004000 +de 15264 015543 +de 15265 072675 +de 15266 103233 +de 15267 024000 +de 15270 025273 +de 15271 003251 +de 15272 003263 +de 15304 011300 +de 15305 007544 +de 15306 015545 +de 15307 011301 +de 15310 004121 +de 15311 022000 +de 15312 141206 +de 15313 141206 +de 15314 141206 +de 15315 141206 +de 15316 041576 +de 15317 011302 +de 15320 005300 +de 15321 141140 +de 15322 006116 +de 15323 041576 +de 15324 140407 +de 15325 015546 +de 15326 011331 +de 15327 011341 +de 15330 005547 +de 15332 107301 +de 15333 100040 +de 15334 003346 +de 15335 005300 +de 15336 040672 +de 15337 006116 +de 15340 013302 +de 15342 113301 +de 15343 111301 +de 15344 010477 +de 15345 025303 +de 15346 103303 +de 15350 044000 +de 15351 007547 +de 15352 040477 +de 15353 052000 +de 15354 007547 +de 15355 052000 +de 15356 015550 +de 15357 050000 +de 15360 103347 +de 15362 044000 +de 15363 015551 +de 15364 052000 +de 15365 007552 +de 15366 052000 +de 15367 050000 +de 15370 103361 +de 15372 033501 +de 15373 011502 +de 15374 005501 +de 15375 022130 +de 15376 003442 +de 15377 101000 +de 15400 073553 +de 15401 004124 +de 15402 011500 +de 15403 003411 +de 15404 010000 +de 15405 064003 +de 15406 003462 +de 15407 004121 +de 15410 050003 +de 15411 025500 +de 15412 003415 +de 15413 025371 +de 15414 003476 +de 15415 044000 +de 15416 100040 +de 15417 003404 +de 15420 104324 +de 15421 101040 +de 15422 003413 +de 15423 026324 +de 15424 024563 +de 15425 050000 +de 15426 011500 +de 15427 026000 +de 15430 050001 +de 15431 005554 +de 15432 011503 +de 15433 050003 +de 15434 140040 +de 15435 050000 +de 15436 005500 +de 15437 014117 +de 15440 050002 +de 15441 003452 +de 15442 012120 +de 15443 100040 +de 15444 103371 +de 15445 005555 +de 15446 010503 +de 15447 030026 +de 15450 103371 +de 15451 044000 +de 15452 010000 +de 15453 014117 +de 15454 050000 +de 15455 005500 +de 15456 050003 +de 15457 025503 +de 15460 003451 +de 15461 073500 +de 15462 144002 +de 15463 066002 +de 15464 073501 +de 15465 150403 +de 15466 050403 +de 15467 010000 +de 15470 140040 +de 15471 050000 +de 15472 005502 +de 15473 050001 +de 15474 004515 +de 15475 050002 +de 15476 073501 +de 15477 103371 +de 15505 044000 +de 15506 101040 +de 15507 103504 +de 15510 144000 +de 15511 101040 +de 15512 133556 +de 15513 066000 +de 15514 010000 +de 15515 140040 +de 15516 050000 +de 15517 025504 +de 15520 103504 +de 15521 177770 +de 15522 033457 +de 15523 177700 +de 15524 177771 +de 15525 000010 +de 15526 032260 +de 15527 032261 +de 15530 020210 +de 15531 032271 +de 15532 177460 +de 15533 000004 +de 15534 177764 +de 15535 033477 +de 15536 054137 +de 15537 000277 +de 15540 000200 +de 15541 054147 +de 15542 054167 +de 15543 000030 +de 15544 000077 +de 15545 032571 +de 15546 041700 +de 15547 000017 +de 15550 000400 +de 15551 000020 +de 15552 000060 +de 15553 000337 +de 15554 177757 +de 15555 177324 +de 15556 040051 +de 16013 033121 +de 16014 073012 +de 16015 033042 +de 16016 072116 +de 16017 003044 +de 16021 033121 +de 16022 073020 +de 16023 033042 +de 16024 072115 +de 16025 003044 +de 16027 033121 +de 16030 073026 +de 16031 033042 +de 16032 072114 +de 16033 003044 +de 16035 033121 +de 16036 073034 +de 16037 033042 +de 16040 072113 +de 16041 003044 +de 16043 033121 +de 16044 000011 +de 16045 003046 +de 16046 011117 +de 16047 000043 +de 16050 011120 +de 16051 032676 +de 16052 004500 +de 16053 170120 +de 16054 026134 +de 16055 011122 +de 16056 000401 +de 16057 143107 +de 16061 004000 +de 16062 016130 +de 16063 100400 +de 16064 003071 +de 16065 004107 +de 16066 041576 +de 16067 051306 +de 16070 100000 +de 16072 005060 +de 16073 051107 +de 16074 005122 +de 16075 001001 +de 16076 170120 +de 16077 010134 +de 16100 000013 +de 16101 005120 +de 16102 171020 +de 16103 073121 +de 16104 005117 +de 16105 000401 +de 16106 103042 +de 16124 030270 +de 16125 030260 +de 16127 030251 +de 16130 016205 +de 16131 016207 +de 16132 016211 +de 16133 016213 +de 16134 016215 +de 16135 000044 +de 16136 000046 +de 16140 000030 +de 16141 017407 +de 16142 017410 +de 16143 017411 +de 16144 017412 +de 16145 000045 +de 16146 000047 +de 16150 000031 +de 16151 017413 +de 16152 017414 +de 16153 017415 +de 16154 017416 +de 16220 140040 +de 16221 051155 +de 16222 151135 +de 16223 011042 +de 16224 140500 +de 16225 111575 +de 16226 005576 +de 16227 021273 +de 16230 103217 +de 16232 014676 +de 16233 011303 +de 16234 015577 +de 16235 011304 +de 16236 004676 +de 16237 012120 +de 16240 101040 +de 16241 103231 +de 16242 105303 +de 16243 101040 +de 16244 103231 +de 16245 010000 +de 16246 005305 +de 16247 101040 +de 16250 003261 +de 16251 004416 +de 16252 056003 +de 16253 100400 +de 16254 003267 +de 16255 004676 +de 16256 016130 +de 16257 101400 +de 16260 103231 +de 16261 073303 +de 16262 121600 +de 16263 103231 +de 16264 121601 +de 16265 125304 +de 16266 003242 +de 16267 023305 +de 16270 011305 +de 16271 101000 +de 16272 103231 +de 16274 051107 +de 16275 001001 +de 16276 000013 +de 16277 021042 +de 16300 001001 +de 16301 120672 +de 16302 103273 +de 16316 030570 +de 16317 030560 +de 16320 030550 +de 16321 030551 +de 16323 011324 +de 16325 004121 +de 16326 051306 +de 16327 005322 +de 16330 003073 +de 16331 004110 +de 16332 016120 +de 16333 041577 +de 16334 051306 +de 16335 005602 +de 16336 003073 +de 16337 005603 +de 16340 021322 +de 16341 004172 +de 16342 100400 +de 16343 003347 +de 16344 007604 +de 16345 100040 +de 16346 003337 +de 16347 004116 +de 16350 003357 +de 16351 004000 +de 16352 016120 +de 16353 101040 +de 16354 103605 +de 16355 111575 +de 16356 004115 +de 16357 050504 +de 16360 121606 +de 16361 100000 +de 16362 003360 +de 16363 140040 +de 16364 151145 +de 16365 151135 +de 16366 067155 +de 16367 140100 +de 16370 101040 +de 16371 003400 +de 16372 024541 +de 16373 011305 +de 16374 045175 +de 16375 073305 +de 16376 050007 +de 16377 121601 +de 16400 140040 +de 16401 011305 +de 16402 005607 +de 16403 021231 +de 16404 005610 +de 16405 021231 +de 16406 072676 +de 16407 004000 +de 16410 016130 +de 16411 101400 +de 16412 003422 +de 16413 105575 +de 16414 101040 +de 16415 003422 +de 16416 105611 +de 16417 021322 +de 16420 045316 +de 16421 021322 +de 16422 004123 +de 16423 011303 +de 16424 000401 +de 16425 005612 +de 16426 001001 +de 16427 120670 +de 16430 101000 +de 16431 025303 +de 16432 003424 +de 16433 005613 +de 16434 120670 +de 16435 101000 +de 16436 000401 +de 16437 140040 +de 16440 111575 +de 16441 005603 +de 16442 021322 +de 16443 004107 +de 16444 011305 +de 16445 005607 +de 16446 021231 +de 16447 005610 +de 16450 021231 +de 16451 072676 +de 16452 121606 +de 16453 003503 +de 16454 151130 +de 16455 045130 +de 16456 151135 +de 16457 141206 +de 16460 151145 +de 16461 051155 +de 16462 004516 +de 16463 151155 +de 16464 045124 +de 16465 011071 +de 16466 004112 +de 16467 051155 +de 16470 051175 +de 16471 005305 +de 16472 051306 +de 16473 021060 +de 16474 140040 +de 16475 151135 +de 16476 051155 +de 16477 045306 +de 16500 101040 +de 16501 003351 +de 16502 003443 +de 16503 044302 +de 16504 101040 +de 16505 003510 +de 16506 005610 +de 16507 003514 +de 16510 044272 +de 16511 101040 +de 16512 003441 +de 16513 005607 +de 16514 014000 +de 16515 051165 +de 16516 004115 +de 16517 111614 +de 16520 145165 +de 16521 051155 +de 16522 045165 +de 16523 010000 +de 16524 144000 +de 16525 050000 +de 16526 101040 +de 16527 133615 +de 16530 064251 +de 16531 072676 +de 16532 172700 +de 16533 005616 +de 16534 026111 +de 16535 011123 +de 16536 004000 +de 16537 056111 +de 16540 015617 +de 16541 140100 +de 16542 011545 +de 16543 017620 +de 16544 103545 +de 16546 100040 +de 16547 003553 +de 16550 005123 +de 16551 010111 +de 16552 103621 +de 16553 027123 +de 16554 010111 +de 16555 004676 +de 16556 012120 +de 16557 101040 +de 16560 103621 +de 16561 005123 +de 16562 001001 +de 16563 021564 +de 16565 120745 +de 16566 000401 +de 16567 072676 +de 16570 045155 +de 16571 140500 +de 16572 051155 +de 16573 140100 +de 16574 103622 +de 16575 053343 +de 16576 016331 +de 16577 000251 +de 16600 015504 +de 16601 017237 +de 16602 016341 +de 16603 101000 +de 16604 000340 +de 16605 017143 +de 16606 017250 +de 16607 000272 +de 16610 000302 +de 16611 041170 +de 16612 002000 +de 16613 005000 +de 16614 057203 +de 16615 040051 +de 16616 016546 +de 16617 001562 +de 16620 001556 +de 16621 017062 +de 16622 017064 +de 17056 030070 +de 17057 030060 +de 17061 030051 +de 17062 072676 +de 17063 105424 +de 17064 015425 +de 17065 057203 +de 17066 111426 +de 17067 172700 +de 17070 131040 +de 17071 003070 +de 17072 050001 +de 17073 140040 +de 17074 050000 +de 17075 044111 +de 17076 140100 +de 17077 016114 +de 17100 072676 +de 17101 111427 +de 17102 024565 +de 17103 172700 +de 17104 044007 +de 17105 007430 +de 17106 066007 +de 17107 072676 +de 17110 111431 +de 17111 100400 +de 17112 003115 +de 17113 045056 +de 17114 100000 +de 17115 105432 +de 17116 111433 +de 17117 021127 +de 17120 105431 +de 17121 121434 +de 17122 105431 +de 17123 101400 +de 17124 103435 +de 17125 121436 +de 17126 103437 +de 17130 172700 +de 17131 004416 +de 17132 056003 +de 17133 072676 +de 17134 111440 +de 17135 100400 +de 17136 003143 +de 17137 004000 +de 17140 016130 +de 17141 100400 +de 17142 103441 +de 17143 121442 +de 17144 140040 +de 17145 111426 +de 17146 105440 +de 17147 101040 +de 17150 103441 +de 17151 172700 +de 17152 044002 +de 17153 001001 +de 17154 100040 +de 17155 121443 +de 17156 072676 +de 17157 000401 +de 17160 140040 +de 17161 067203 +de 17162 172700 +de 17163 100040 +de 17164 003214 +de 17165 072676 +de 17166 140040 +de 17167 126700 +de 17170 010000 +de 17171 001001 +de 17172 100400 +de 17173 003177 +de 17174 120671 +de 17175 072676 +de 17176 103127 +de 17177 140100 +de 17200 026342 +de 17201 050000 +de 17202 003175 +de 17214 044006 +de 17215 007444 +de 17216 100040 +de 17217 003165 +de 17220 044005 +de 17221 007445 +de 17222 100040 +de 17223 004121 +de 17224 011213 +de 17225 044005 +de 17226 007446 +de 17227 013447 +de 17230 052007 +de 17231 007450 +de 17232 052007 +de 17233 073213 +de 17234 121451 +de 17235 101000 +de 17236 003165 +de 17240 044005 +de 17241 007452 +de 17242 013445 +de 17243 050005 +de 17244 132352 +de 17245 032352 +de 17246 024526 +de 17247 103237 +de 17251 033337 +de 17252 044332 +de 17253 100040 +de 17254 003260 +de 17255 073337 +de 17256 005340 +de 17257 103250 +de 17260 011341 +de 17261 004000 +de 17262 022130 +de 17263 003255 +de 17264 101000 +de 17265 025250 +de 17266 073341 +de 17267 044001 +de 17270 011340 +de 17271 044002 +de 17272 010516 +de 17273 044003 +de 17274 011342 +de 17275 073337 +de 17276 144332 +de 17277 050332 +de 17300 100040 +de 17301 003305 +de 17302 005453 +de 17303 014000 +de 17304 050403 +de 17305 073342 +de 17306 044002 +de 17307 111341 +de 17310 005341 +de 17311 050002 +de 17312 044003 +de 17313 016114 +de 17314 050003 +de 17315 023454 +de 17316 003255 +de 17317 044001 +de 17320 054000 +de 17321 017455 +de 17322 101040 +de 17323 003255 +de 17324 044000 +de 17325 150001 +de 17326 044001 +de 17327 064000 +de 17330 150000 +de 17331 140040 +de 17332 050111 +de 17333 001001 +de 17334 120671 +de 17335 000401 +de 17336 003255 +de 17344 000011 +de 17345 000401 +de 17346 103343 +de 17350 045407 +de 17351 101040 +de 17352 003366 +de 17353 057413 +de 17354 022113 +de 17355 003374 +de 17356 003362 +de 17357 145407 +de 17360 065407 +de 17361 103347 +de 17362 105456 +de 17363 100400 +de 17364 025347 +de 17365 003357 +de 17366 005347 +de 17367 051420 +de 17370 120667 +de 17371 045420 +de 17372 011347 +de 17373 003350 +de 17374 033417 +de 17375 004000 +de 17376 014130 +de 17377 010000 +de 17400 001001 +de 17401 000013 +de 17402 121457 +de 17403 001001 +de 17404 120672 +de 17405 073417 +de 17406 003350 +de 17424 056155 +de 17425 000011 +de 17426 156135 +de 17427 156145 +de 17430 050377 +de 17431 056175 +de 17432 056124 +de 17433 016071 +de 17434 022462 +de 17435 016520 +de 17436 022451 +de 17437 016443 +de 17440 056306 +de 17441 016351 +de 17442 016060 +de 17443 011144 +de 17444 003400 +de 17445 000010 +de 17446 177600 +de 17447 000100 +de 17450 177700 +de 17451 015303 +de 17452 177767 +de 17453 000332 +de 17454 177756 +de 17455 000337 +de 17456 056201 +de 17457 016042 +de 20023 000011 +de 20024 003025 +de 20025 033145 +de 20026 025143 +de 20027 003034 +de 20030 073574 +de 20031 033143 +de 20032 072114 +de 20033 100000 +de 20034 072113 +de 20035 051146 +de 20036 045160 +de 20037 170120 +de 20040 026134 +de 20041 051156 +de 20042 000043 +de 20043 051150 +de 20044 005145 +de 20045 051152 +de 20046 005022 +de 20047 051154 +de 20050 024415 +de 20051 101000 +de 20052 024417 +de 20053 101000 +de 20054 030026 +de 20055 143162 +de 20056 001001 +de 20057 045154 +de 20060 011022 +de 20061 045152 +de 20062 011145 +de 20063 045156 +de 20064 170120 +de 20065 010134 +de 20066 000013 +de 20067 045150 +de 20070 171020 +de 20071 045146 +de 20072 073145 +de 20073 000401 +de 20074 103022 +de 20076 004127 +de 20077 010141 +de 20100 072113 +de 20101 140040 +de 20102 111575 +de 20103 004115 +de 20104 051300 +de 20105 005576 +de 20106 111577 +de 20107 005600 +de 20110 111601 +de 20111 004110 +de 20112 111602 +de 20113 004121 +de 20114 051452 +de 20115 021354 +de 20116 024000 +de 20117 024141 +de 20120 003101 +de 20121 004121 +de 20122 011143 +de 20123 010142 +de 20124 111603 +de 20125 111604 +de 20126 011210 +de 20127 111605 +de 20130 111606 +de 20131 111607 +de 20132 111610 +de 20133 011277 +de 20134 004122 +de 20135 073611 +de 20136 051277 +de 20137 024000 +de 20140 003136 +de 20141 030040 +de 20142 103075 +de 20160 177774 +de 20161 177774 +de 20162 020170 +de 20163 021075 +de 20164 005160 +de 20165 170120 +de 20166 010134 +de 20167 072114 +de 20170 033144 +de 20171 021211 +de 20172 021305 +de 20173 021327 +de 20174 121612 +de 20175 021200 +de 20176 073144 +de 20177 003056 +de 20201 005613 +de 20202 113614 +de 20203 101040 +de 20204 011210 +de 20205 025210 +de 20206 101000 +de 20207 103200 +de 20212 025274 +de 20213 100000 +de 20214 003255 +de 20215 025275 +de 20216 100000 +de 20217 003257 +de 20220 025276 +de 20221 100000 +de 20222 003261 +de 20223 072127 +de 20224 004121 +de 20225 123615 +de 20226 100000 +de 20227 003233 +de 20230 024000 +de 20231 003225 +de 20232 103211 +de 20233 045305 +de 20234 040677 +de 20235 100400 +de 20236 005616 +de 20237 051305 +de 20240 107617 +de 20241 101040 +de 20242 003253 +de 20243 100100 +de 20244 003264 +de 20245 001001 +de 20246 044272 +de 20247 101040 +de 20250 004115 +de 20251 050272 +de 20252 000401 +de 20253 004121 +de 20254 003230 +de 20255 005620 +de 20256 011274 +de 20257 005574 +de 20260 011275 +de 20261 004125 +de 20262 011276 +de 20263 003223 +de 20264 033273 +de 20265 004000 +de 20266 016127 +de 20267 010000 +de 20270 021354 +de 20271 073273 +de 20272 003245 +de 20306 072113 +de 20307 004127 +de 20310 011353 +de 20311 001001 +de 20312 044440 +de 20313 100040 +de 20314 003324 +de 20315 121621 +de 20316 001001 +de 20317 120672 +de 20320 024000 +de 20321 025353 +de 20322 003311 +de 20323 103305 +de 20324 064440 +de 20325 003320 +de 20326 003315 +de 20330 004131 +de 20331 011352 +de 20332 005352 +de 20333 012415 +de 20334 006120 +de 20335 010000 +de 20336 001001 +de 20337 105622 +de 20340 100040 +de 20341 125622 +de 20342 003346 +de 20343 000013 +de 20344 121623 +de 20345 001001 +de 20346 120672 +de 20347 025352 +de 20350 003332 +de 20351 103327 +de 20355 044265 +de 20356 100400 +de 20357 003445 +de 20360 140040 +de 20361 127575 +de 20362 101040 +de 20363 003367 +de 20364 064421 +de 20365 065457 +de 20366 101000 +de 20367 125624 +de 20370 101000 +de 20371 044426 +de 20372 101040 +de 20373 003416 +de 20374 016114 +de 20375 100040 +de 20376 004114 +de 20377 050426 +de 20400 044433 +de 20401 101040 +de 20402 003414 +de 20403 065452 +de 20404 103354 +de 20405 140040 +de 20406 050433 +de 20407 044160 +de 20410 016106 +de 20411 006112 +de 20412 040672 +de 20413 111625 +de 20414 004125 +de 20415 003431 +de 20416 044433 +de 20417 100040 +de 20420 003433 +de 20421 065452 +de 20422 003440 +de 20423 001001 +de 20424 121626 +de 20425 000401 +de 20426 105602 +de 20427 111625 +de 20430 050433 +de 20431 051452 +de 20432 103354 +de 20433 045452 +de 20434 123602 +de 20435 016114 +de 20436 003430 +de 20437 003426 +de 20440 045452 +de 20441 022123 +de 20442 100000 +de 20443 121627 +de 20444 103354 +de 20445 023630 +de 20446 100000 +de 20447 121627 +de 20450 021464 +de 20451 003426 +de 20465 004112 +de 20466 050440 +de 20467 004000 +de 20470 014127 +de 20471 023544 +de 20472 100000 +de 20473 103464 +de 20474 023545 +de 20475 103464 +de 20476 103464 +de 20477 115631 +de 20500 101040 +de 20501 103543 +de 20502 064265 +de 20503 103464 +de 20504 001001 +de 20505 033546 +de 20506 005632 +de 20507 021547 +de 20510 005633 +de 20511 021547 +de 20512 073546 +de 20513 005634 +de 20514 050646 +de 20515 050653 +de 20516 044622 +de 20517 111635 +de 20520 050627 +de 20521 005636 +de 20522 050634 +de 20523 140040 +de 20524 050641 +de 20525 050440 +de 20526 166627 +de 20527 010000 +de 20530 023637 +de 20531 021557 +de 20532 101000 +de 20533 073546 +de 20534 064627 +de 20535 064634 +de 20536 003523 +de 20537 005640 +de 20540 111641 +de 20541 000401 +de 20542 103464 +de 20550 015546 +de 20551 011573 +de 20552 073573 +de 20553 121642 +de 20554 103547 +de 20555 021557 +de 20556 003552 +de 20560 132402 +de 20561 032402 +de 20562 024564 +de 20563 044002 +de 20564 101040 +de 20565 103557 +de 20566 010000 +de 20567 005643 +de 20570 052012 +de 20571 050012 +de 20572 103557 +de 20574 177747 +de 20575 045565 +de 20576 101006 +de 20577 052620 +de 20600 020276 +de 20601 051353 +de 20602 051361 +de 20603 022273 +de 20604 022303 +de 20605 004601 +de 20606 027263 +de 20607 027264 +de 20610 021561 +de 20611 177775 +de 20612 022320 +de 20613 032261 +de 20614 015155 +de 20615 151360 +de 20616 000020 +de 20617 167274 +de 20620 177716 +de 20621 012604 +de 20622 053137 +de 20623 013106 +de 20624 062303 +de 20625 050254 +de 20626 011133 +de 20627 026120 +de 20630 177767 +de 20631 005153 +de 20632 000317 +de 20633 000312 +de 20634 000377 +de 20635 052660 +de 20636 177770 +de 20637 001777 +de 20640 003231 +de 20641 150247 +de 20642 015504 +de 20643 140000 +de 21075 021460 +de 21076 021362 +de 21077 021432 +de 21100 121672 +de 21101 121673 +de 21102 021564 +de 21103 021640 +de 21104 021134 +de 21105 021500 +de 21106 000401 +de 21107 021526 +de 21110 073674 +de 21111 005675 +de 21112 123676 +de 21113 100000 +de 21114 100000 +de 21115 120061 +de 21116 016114 +de 21117 024000 +de 21120 003112 +de 21121 005677 +de 21122 113676 +de 21123 100040 +de 21124 120061 +de 21125 010452 +de 21126 101000 +de 21127 001001 +de 21130 024416 +de 21131 024503 +de 21132 103700 +de 21133 120061 +de 21135 005701 +de 21136 011356 +de 21137 072113 +de 21140 033355 +de 21141 044165 +de 21142 101400 +de 21143 003274 +de 21144 073356 +de 21145 001001 +de 21146 044000 +de 21147 007702 +de 21150 013702 +de 21151 101040 +de 21152 003232 +de 21153 004124 +de 21154 011357 +de 21155 044000 +de 21156 017703 +de 21157 050000 +de 21160 100100 +de 21161 003226 +de 21162 141044 +de 21163 013355 +de 21164 121704 +de 21165 003203 +de 21166 010000 +de 21167 140040 +de 21170 066000 +de 21171 140100 +de 21172 010000 +de 21173 120671 +de 21174 044010 +de 21175 141044 +de 21176 010515 +de 21177 044007 +de 21200 121705 +de 21201 044006 +de 21202 003221 +de 21203 105356 +de 21204 141044 +de 21205 013355 +de 21206 121706 +de 21207 003226 +de 21210 010000 +de 21211 140040 +de 21212 066000 +de 21213 006120 +de 21214 011361 +de 21215 044030 +de 21216 141044 +de 21217 010515 +de 21220 044014 +de 21221 007707 +de 21222 013710 +de 21223 073361 +de 21224 120670 +de 21225 101000 +de 21226 073356 +de 21227 121711 +de 21230 025357 +de 21231 003160 +de 21232 005355 +de 21233 121712 +de 21234 100000 +de 21235 003232 +de 21236 073713 +de 21237 044000 +de 21240 101040 +de 21241 003244 +de 21242 021303 +de 21243 003237 +de 21244 073714 +de 21245 044000 +de 21246 101040 +de 21247 003271 +de 21250 100400 +de 21251 003267 +de 21252 033360 +de 21253 010000 +de 21254 044007 +de 21255 013355 +de 21256 007715 +de 21257 100040 +de 21260 003245 +de 21261 044000 +de 21262 111360 +de 21263 120671 +de 21264 024565 +de 21265 073360 +de 21266 003245 +de 21267 021303 +de 21270 003245 +de 21271 073355 +de 21272 121716 +de 21273 000401 +de 21274 024000 +de 21275 025356 +de 21276 004000 +de 21277 014132 +de 21300 100400 +de 21301 003140 +de 21302 103134 +de 21304 140100 +de 21305 033360 +de 21306 010000 +de 21307 044001 +de 21310 013355 +de 21311 007715 +de 21312 100040 +de 21313 103303 +de 21314 044000 +de 21315 111360 +de 21316 021321 +de 21317 073360 +de 21320 103303 +de 21322 004000 +de 21323 026326 +de 21324 110326 +de 21325 005717 +de 21326 011353 +de 21327 140040 +de 21330 050013 +de 21331 044002 +de 21332 100400 +de 21333 004120 +de 21334 141206 +de 21335 014565 +de 21336 010565 +de 21337 140040 +de 21340 066003 +de 21341 101040 +de 21342 003347 +de 21343 033354 +de 21344 010000 +de 21345 120671 +de 21346 073354 +de 21347 024000 +de 21350 025353 +de 21351 003337 +de 21352 103321 +de 21363 004131 +de 21364 011430 +de 21365 072113 +de 21366 045662 +de 21367 011372 +de 21370 001001 +de 21371 044504 +de 21373 015720 +de 21374 015721 +de 21375 011376 +de 21377 021423 +de 21400 021423 +de 21401 021423 +de 21402 021411 +de 21403 021423 +de 21404 021421 +de 21405 021423 +de 21406 021421 +de 21407 021423 +de 21410 021423 +de 21411 140040 +de 21412 050504 +de 21413 104700 +de 21414 101040 +de 21415 003423 +de 21416 004107 +de 21417 111722 +de 21420 003423 +de 21421 005723 +de 21422 121724 +de 21423 000401 +de 21424 024000 +de 21425 025430 +de 21426 003366 +de 21427 103362 +de 21433 072127 +de 21434 001001 +de 21435 004116 +de 21436 111455 +de 21437 005717 +de 21440 011457 +de 21441 044627 +de 21442 011456 +de 21443 105456 +de 21444 100040 +de 21445 125455 +de 21446 025456 +de 21447 025457 +de 21450 003443 +de 21451 000401 +de 21452 024000 +de 21453 003434 +de 21454 103432 +de 21455 066505 +de 21461 004131 +de 21462 011477 +de 21463 072113 +de 21464 125722 +de 21465 003473 +de 21466 001001 +de 21467 000013 +de 21470 121725 +de 21471 001001 +de 21472 120672 +de 21473 024000 +de 21474 025477 +de 21475 003464 +de 21476 103460 +de 21501 073726 +de 21502 001001 +de 21503 044543 +de 21504 056567 +de 21505 101400 +de 21506 003513 +de 21507 021510 +de 21511 120745 +de 21512 140040 +de 21513 050543 +de 21514 140040 +de 21515 050567 +de 21516 000401 +de 21517 024000 +de 21520 003502 +de 21521 001001 +de 21522 125727 +de 21523 103500 +de 21524 010542 +de 21525 103500 +de 21527 025561 +de 21530 103526 +de 21531 072132 +de 21532 001001 +de 21533 105730 +de 21534 007702 +de 21535 013702 +de 21536 101040 +de 21537 003550 +de 21540 105730 +de 21541 007731 +de 21542 013731 +de 21543 101040 +de 21544 003550 +de 21545 005732 +de 21546 115730 +de 21547 111730 +de 21550 000401 +de 21551 024000 +de 21552 003532 +de 21553 004107 +de 21554 040575 +de 21555 014107 +de 21556 040577 +de 21557 011561 +de 21560 103526 +de 21565 101000 +de 21566 005733 +de 21567 011565 +de 21570 004141 +de 21571 013562 +de 21572 101040 +de 21573 103564 +de 21574 004141 +de 21575 006120 +de 21576 101040 +de 21577 003626 +de 21600 010000 +de 21601 004141 +de 21602 040575 +de 21603 006752 +de 21604 011563 +de 21605 055630 +de 21606 011624 +de 21607 004000 +de 21610 022116 +de 21611 003624 +de 21612 100000 +de 21613 003621 +de 21614 073563 +de 21615 001001 +de 21616 044437 +de 21617 100040 +de 21620 103564 +de 21621 005563 +de 21622 015734 +de 21623 011565 +de 21625 000401 +de 21626 004141 +de 21627 011562 +de 21630 103564 +de 21631 030270 +de 21632 030370 +de 21633 030170 +de 21634 030300 +de 21635 030500 +de 21636 030400 +de 21637 101000 +de 21641 001001 +de 21642 004142 +de 21643 100400 +de 21644 003656 +de 21645 010000 +de 21646 044332 +de 21647 100040 +de 21650 003656 +de 21651 004143 +de 21652 010515 +de 21653 005735 +de 21654 120670 +de 21655 025660 +de 21656 000401 +de 21657 103640 +de 21661 037454 +de 21662 070170 +de 21663 070160 +de 21665 070151 +de 21666 100000 +de 21667 100000 +de 21670 100000 +de 21671 100000 +de 21672 027112 +de 21673 026512 +de 21674 177666 +de 21675 054115 +de 21676 041557 +de 21677 102111 +de 21700 020164 +de 21701 032271 +de 21702 000017 +de 21703 001400 +de 21704 015033 +de 21705 007244 +de 21706 015205 +de 21707 070377 +de 21710 003400 +de 21711 015347 +de 21712 015114 +de 21713 000340 +de 21714 000327 +de 21715 000077 +de 21716 002374 +de 21717 177770 +de 21720 000005 +de 21721 103377 +de 21722 056306 +de 21723 016341 +de 21724 016273 +de 21725 016042 +de 21726 177754 +de 21727 004161 +de 21730 072371 +de 21731 000300 +de 21732 000100 +de 21733 101000 +de 21734 030470 +de 21735 002000 +de 22057 005524 +de 22060 011301 +de 22061 121525 +de 22062 073526 +de 22063 001001 +de 22064 044510 +de 22065 100040 +de 22066 004112 +de 22067 140024 +de 22070 041277 +de 22071 024000 +de 22072 003064 +de 22073 040274 +de 22074 013272 +de 22075 021310 +de 22076 127527 +de 22077 021310 +de 22100 026746 +de 22101 021310 +de 22102 004747 +de 22103 021310 +de 22104 004750 +de 22105 021310 +de 22106 072124 +de 22107 001001 +de 22110 044543 +de 22111 056567 +de 22112 021310 +de 22113 024000 +de 22114 003107 +de 22115 004105 +de 22116 021310 +de 22117 105530 +de 22120 021310 +de 22121 000013 +de 22122 105531 +de 22123 001001 +de 22124 120672 +de 22125 021310 +de 22126 004142 +de 22127 021310 +de 22130 127532 +de 22131 021310 +de 22132 127533 +de 22133 021310 +de 22134 011277 +de 22135 072127 +de 22136 001001 +de 22137 140040 +de 22140 127534 +de 22141 057310 +de 22142 140407 +de 22143 100400 +de 22144 140040 +de 22145 023535 +de 22146 005535 +de 22147 101000 +de 22150 011302 +de 22151 004121 +de 22152 067310 +de 22153 023535 +de 22154 005535 +de 22155 101000 +de 22156 021310 +de 22157 044440 +de 22160 100040 +de 22161 005536 +de 22162 052165 +de 22163 022106 +de 22164 100000 +de 22165 012753 +de 22166 141340 +de 22167 013302 +de 22170 021310 +de 22171 105537 +de 22172 141340 +de 22173 006116 +de 22174 013277 +de 22175 041676 +de 22176 011277 +de 22177 024000 +de 22200 003136 +de 22201 041674 +de 22202 021310 +de 22203 072123 +de 22204 105540 +de 22205 021310 +de 22206 024000 +de 22207 003204 +de 22210 027301 +de 22211 140407 +de 22212 121525 +de 22213 140040 +de 22214 027276 +de 22215 100040 +de 22216 103541 +de 22217 073542 +de 22220 004112 +de 22221 120664 +de 22222 105543 +de 22223 121525 +de 22224 105544 +de 22225 121525 +de 22226 005545 +de 22227 021310 +de 22230 072127 +de 22231 127546 +de 22232 021310 +de 22233 127547 +de 22234 021310 +de 22235 024000 +de 22236 003231 +de 22237 073526 +de 22240 005550 +de 22241 011277 +de 22242 005551 +de 22243 011300 +de 22244 140040 +de 22245 127300 +de 22246 021310 +de 22247 025300 +de 22250 025277 +de 22251 003244 +de 22252 024000 +de 22253 003240 +de 22254 027301 +de 22255 140407 +de 22256 121525 +de 22257 103541 +de 22260 073563 +de 22261 073567 +de 22262 073573 +de 22263 073577 +de 22264 073603 +de 22265 073607 +de 22266 073613 +de 22267 073617 +de 22270 073623 +de 22271 073627 +de 22275 003014 +de 22311 000401 +de 22312 027301 +de 22313 015301 +de 22314 027301 +de 22315 121525 +de 22316 140040 +de 22317 103310 +de 22321 005552 +de 22322 111553 +de 22323 072121 +de 22324 105527 +de 22325 101040 +de 22326 105554 +de 22327 100040 +de 22330 033272 +de 22331 004142 +de 22332 027273 +de 22333 023273 +de 22334 100000 +de 22335 003345 +de 22336 033272 +de 22337 010000 +de 22340 005275 +de 22341 127555 +de 22342 072142 +de 22343 127555 +de 22344 011275 +de 22345 004753 +de 22346 111556 +de 22347 140040 +de 22350 127556 +de 22351 012473 +de 22352 100020 +de 22353 012751 +de 22354 100010 +de 22355 012117 +de 22356 100004 +de 22357 012115 +de 22360 100002 +de 22361 012114 +de 22362 072124 +de 22363 011274 +de 22364 105557 +de 22365 100040 +de 22366 105560 +de 22367 013274 +de 22370 024000 +de 22371 003363 +de 22372 012567 +de 22373 027272 +de 22374 013272 +de 22375 101040 +de 22376 103320 +de 22377 011276 +de 22400 004417 +de 22401 117553 +de 22402 111561 +de 22403 103320 +de 22405 010747 +de 22406 032750 +de 22407 004122 +de 22410 015404 +de 22411 010746 +de 22412 104746 +de 22413 010746 +de 22414 103404 +de 22416 012106 +de 22417 100040 +de 22420 005562 +de 22421 015264 +de 22422 001001 +de 22423 021505 +de 22424 101000 +de 22425 103415 +de 22427 012106 +de 22430 100040 +de 22431 005562 +de 22432 015266 +de 22433 001001 +de 22434 021505 +de 22435 103426 +de 22436 172677 +de 22437 044111 +de 22440 016000 +de 22441 140100 +de 22442 017563 +de 22443 072675 +de 22444 115564 +de 22445 100400 +de 22446 004112 +de 22447 111564 +de 22450 103426 +de 22452 012106 +de 22453 007565 +de 22454 100040 +de 22455 005562 +de 22456 015265 +de 22457 021505 +de 22460 101000 +de 22461 103451 +de 22463 012106 +de 22464 007565 +de 22465 100040 +de 22466 005562 +de 22467 015267 +de 22470 021505 +de 22471 103462 +de 22472 172700 +de 22473 044111 +de 22474 016000 +de 22475 140100 +de 22476 017563 +de 22477 072676 +de 22500 115566 +de 22501 100400 +de 22502 004112 +de 22503 111566 +de 22504 103462 +de 22506 016130 +de 22507 011523 +de 22510 004000 +de 22511 016130 +de 22512 101400 +de 22513 003521 +de 22514 105523 +de 22515 101400 +de 22516 141206 +de 22517 111523 +de 22520 025505 +de 22521 000401 +de 22522 103505 +de 22524 000301 +de 22525 030403 +de 22526 177774 +de 22527 003560 +de 22530 001005 +de 22531 040000 +de 22532 021660 +de 22533 021431 +de 22534 060464 +de 22535 000377 +de 22536 000200 +de 22537 052625 +de 22540 077777 +de 22541 030165 +de 22542 100003 +de 22543 030456 +de 22544 030450 +de 22545 000302 +de 22546 050625 +de 22547 050620 +de 22550 177766 +de 22551 122260 +de 22552 004000 +de 22553 030464 +de 22554 000746 +de 22555 053170 +de 22556 001777 +de 22557 070440 +de 22560 041246 +de 22561 030210 +de 22562 177760 +de 22563 000011 +de 22564 073617 +de 22565 000077 +de 22566 073623 +de 23033 005633 +de 23034 011163 +de 23035 005634 +de 23036 011164 +de 23037 005635 +de 23040 011632 +de 23041 011162 +de 23042 140040 +de 23043 010473 +de 23044 000013 +de 23045 003076 +de 23047 131004 +de 23050 003047 +de 23051 007636 +de 23052 013637 +de 23053 103046 +de 23055 070104 +de 23056 003075 +de 23057 030104 +de 23060 170004 +de 23061 003060 +de 23062 070004 +de 23063 003062 +de 23064 030004 +de 23065 103054 +de 23066 005640 +de 23067 011164 +de 23070 005641 +de 23071 011163 +de 23072 005635 +de 23073 011632 +de 23074 103642 +de 23075 021046 +de 23076 021165 +de 23077 140040 +de 23100 011145 +de 23101 021261 +de 23102 005643 +de 23103 121164 +de 23104 021215 +de 23105 140040 +de 23106 011145 +de 23107 011144 +de 23110 121163 +de 23111 006752 +de 23112 011161 +de 23113 015644 +de 23114 010000 +de 23115 044000 +de 23116 100400 +de 23117 003122 +de 23120 005162 +de 23121 021126 +de 23122 044000 +de 23123 010000 +de 23124 005161 +de 23125 042000 +de 23127 101040 +de 23130 103126 +de 23131 004473 +de 23132 101040 +de 23133 100002 +de 23134 103126 +de 23135 005645 +de 23136 121164 +de 23137 021173 +de 23140 003104 +de 23156 177777 +de 23163 024052 +de 23164 024163 +de 23166 005643 +de 23167 121164 +de 23170 005646 +de 23171 121164 +de 23172 103165 +de 23174 005647 +de 23175 121164 +de 23176 121164 +de 23177 121164 +de 23200 103173 +de 23202 007145 +de 23203 101040 +de 23204 025201 +de 23205 045144 +de 23206 103201 +de 23210 072113 +de 23211 004114 +de 23212 021201 +de 23213 025207 +de 23214 103207 +de 23216 140040 +de 23217 027146 +de 23220 100000 +de 23221 140407 +de 23222 015144 +de 23223 011144 +de 23224 004112 +de 23225 011220 +de 23226 103215 +de 23230 140100 +de 23231 011244 +de 23232 021165 +de 23233 005244 +de 23234 021302 +de 23235 005650 +de 23236 121164 +de 23237 021207 +de 23240 025145 +de 23241 005244 +de 23242 021244 +de 23243 103227 +de 23245 140100 +de 23246 011151 +de 23247 021207 +de 23250 003253 +de 23251 005151 +de 23252 011150 +de 23253 021173 +de 23254 073151 +de 23255 044000 +de 23256 021302 +de 23257 021173 +de 23260 103244 +de 23262 005651 +de 23263 011355 +de 23264 021215 +de 23265 005151 +de 23266 101400 +de 23267 021207 +de 23270 003277 +de 23271 011147 +de 23272 004114 +de 23273 021126 +de 23274 005147 +de 23275 073151 +de 23276 050000 +de 23277 140500 +de 23300 011151 +de 23301 103261 +de 23303 011147 +de 23304 000201 +de 23305 072125 +de 23306 004121 +de 23307 011333 +de 23310 005652 +de 23311 041077 +de 23312 023653 +de 23313 100000 +de 23314 003326 +de 23315 025333 +de 23316 101000 +de 23317 121164 +de 23320 005654 +de 23321 041075 +de 23322 024000 +de 23323 003312 +de 23324 121164 +de 23325 103302 +de 23326 025333 +de 23327 003317 +de 23330 004121 +de 23331 011333 +de 23332 003320 +de 23334 021173 +de 23335 005147 +de 23336 141140 +de 23337 121164 +de 23340 005147 +de 23341 141050 +de 23342 003136 +de 23343 021215 +de 23344 140040 +de 23345 027144 +de 23346 027143 +de 23347 027142 +de 23350 027141 +de 23351 005145 +de 23352 041477 +de 23353 011145 +de 23354 003110 +de 23356 015146 +de 23357 015146 +de 23360 040175 +de 23361 015146 +de 23362 041175 +de 23363 017655 +de 23364 011146 +de 23365 021207 +de 23366 025145 +de 23367 003110 +de 23370 005316 +de 23371 011355 +de 23372 003110 +de 23373 021215 +de 23374 005144 +de 23375 021302 +de 23376 003137 +de 23377 021215 +de 23400 003110 +de 23401 021215 +de 23402 005316 +de 23403 011220 +de 23404 003110 +de 23405 005150 +de 23406 003364 +de 23407 073146 +de 23410 044000 +de 23411 003364 +de 23412 005147 +de 23413 003364 +de 23414 005656 +de 23415 003364 +de 23416 105657 +de 23417 003364 +de 23420 021215 +de 23421 021207 +de 23422 005147 +de 23423 021244 +de 23424 003104 +de 23425 021215 +de 23426 021207 +de 23427 005147 +de 23430 011147 +de 23431 007660 +de 23432 100040 +de 23433 005150 +de 23434 013147 +de 23435 007661 +de 23436 013147 +de 23437 003423 +de 23440 021261 +de 23441 004121 +de 23442 003445 +de 23443 021261 +de 23444 004114 +de 23445 015150 +de 23446 011150 +de 23447 021227 +de 23450 003104 +de 23451 121163 +de 23452 141240 +de 23453 011147 +de 23454 121163 +de 23455 013147 +de 23456 011147 +de 23457 003364 +de 23460 021215 +de 23461 021207 +de 23462 100000 +de 23463 011157 +de 23464 004114 +de 23465 021126 +de 23466 072122 +de 23467 004117 +de 23470 021201 +de 23471 011160 +de 23472 072121 +de 23473 004115 +de 23474 021201 +de 23475 101000 +de 23476 073160 +de 23477 103157 +de 23500 021126 +de 23501 005662 +de 23502 003513 +de 23503 005154 +de 23504 050000 +de 23505 003553 +de 23506 005526 +de 23507 003513 +de 23510 005570 +de 23511 003513 +de 23512 005203 +de 23513 011546 +de 23514 072123 +de 23515 004751 +de 23516 021201 +de 23517 011156 +de 23520 072122 +de 23521 004117 +de 23522 021201 +de 23523 011154 +de 23524 021215 +de 23525 021207 +de 23526 100000 +de 23527 011153 +de 23530 072121 +de 23531 004115 +de 23532 021201 +de 23533 011152 +de 23534 005152 +de 23535 017153 +de 23536 016114 +de 23537 011155 +de 23540 101400 +de 23541 003135 +de 23542 073152 +de 23543 044000 +de 23544 013154 +de 23545 007156 +de 23547 003553 +de 23550 004000 +de 23551 021227 +de 23552 073151 +de 23553 024000 +de 23554 025155 +de 23555 003543 +de 23556 003076 +de 23557 021126 +de 23560 021215 +de 23561 021207 +de 23562 003135 +de 23563 120672 +de 23564 121663 +de 23565 000013 +de 23566 003076 +de 23567 004473 +de 23570 100040 +de 23571 003575 +de 23572 005162 +de 23573 021126 +de 23574 140040 +de 23575 013664 +de 23576 010473 +de 23577 040677 +de 23600 013665 +de 23601 121164 +de 23602 003076 +de 23603 021215 +de 23604 021207 +de 23605 003135 +de 23606 007666 +de 23607 013667 +de 23610 111670 +de 23611 003076 +de 23612 021215 +de 23613 072121 +de 23614 004115 +de 23615 021201 +de 23616 111671 +de 23617 021207 +de 23620 100000 +de 23621 111672 +de 23622 003076 +de 23623 021126 +de 23624 005632 +de 23625 027164 +de 23626 011632 +de 23627 003076 +de 23631 103630 +de 23633 023046 +de 23634 023054 +de 23635 023630 +de 23636 000177 +de 23637 000200 +de 23640 024163 +de 23641 024052 +de 23642 024157 +de 23643 000215 +de 23644 024400 +de 23645 000243 +de 23646 000212 +de 23647 000240 +de 23650 000257 +de 23651 003360 +de 23652 000130 +de 23653 000260 +de 23654 000026 +de 23655 000060 +de 23656 016306 +de 23657 025506 +de 23660 001000 +de 23661 077000 +de 23662 003503 +de 23663 003525 +de 23664 000020 +de 23665 000306 +de 23666 170377 +de 23667 140000 +de 23670 025165 +de 23671 025166 +de 23672 025167 +de 24012 120666 +de 24013 140500 +de 24014 011050 +de 24015 007500 +de 24016 013501 +de 24017 100040 +de 24020 013502 +de 24021 100040 +de 24022 013503 +de 24023 111504 +de 24024 120666 +de 24025 011051 +de 24026 120666 +de 24027 003040 +de 24030 011047 +de 24031 141050 +de 24032 101040 +de 24033 003036 +de 24034 005047 +de 24035 021076 +de 24036 025067 +de 24037 003012 +de 24040 011047 +de 24041 021076 +de 24042 005047 +de 24043 141340 +de 24044 021076 +de 24045 003026 +de 24053 072114 +de 24054 001001 +de 24055 120672 +de 24056 100000 +de 24057 120665 +de 24060 140040 +de 24061 027067 +de 24062 101040 +de 24063 003070 +de 24064 005505 +de 24065 011163 +de 24066 003116 +de 24070 027046 +de 24071 101040 +de 24072 003057 +de 24073 001001 +de 24074 000013 +de 24075 103052 +de 24077 101400 +de 24100 103076 +de 24101 140100 +de 24102 141140 +de 24103 100040 +de 24104 003110 +de 24105 010472 +de 24106 005335 +de 24107 011052 +de 24110 011046 +de 24111 120667 +de 24112 005046 +de 24113 100040 +de 24114 003111 +de 24115 103076 +de 24116 005207 +de 24117 073506 +de 24120 120664 +de 24121 004112 +de 24122 021176 +de 24123 072114 +de 24124 005050 +de 24125 120664 +de 24126 005051 +de 24127 120664 +de 24130 005507 +de 24131 011213 +de 24132 005210 +de 24133 007510 +de 24134 000201 +de 24135 041050 +de 24136 013511 +de 24137 021176 +de 24140 004472 +de 24141 100040 +de 24142 003152 +de 24143 000201 +de 24144 072114 +de 24145 120664 +de 24146 025213 +de 24147 003154 +de 24150 004112 +de 24151 003117 +de 24152 005512 +de 24153 011163 +de 24154 004112 +de 24155 021176 +de 24156 003135 +de 24157 005335 +de 24160 011163 +de 24161 011067 +de 24162 003121 +de 24164 011210 +de 24165 007510 +de 24166 013207 +de 24167 000201 +de 24170 011211 +de 24171 033212 +de 24172 001001 +de 24173 120672 +de 24174 072114 +de 24175 103176 +de 24177 011207 +de 24200 005211 +de 24201 000201 +de 24202 005210 +de 24203 073212 +de 24204 001001 +de 24205 000013 +de 24206 103163 +de 24214 005337 +de 24215 011360 +de 24216 005340 +de 24217 015360 +de 24220 011361 +de 24221 010000 +de 24222 044000 +de 24223 101040 +de 24224 003244 +de 24225 121332 +de 24226 004000 +de 24227 121333 +de 24230 121334 +de 24231 005513 +de 24232 011362 +de 24233 073361 +de 24234 044000 +de 24235 101040 +de 24236 003244 +de 24237 011361 +de 24240 121333 +de 24241 121334 +de 24242 025362 +de 24243 003233 +de 24244 025360 +de 24245 003216 +de 24246 005357 +de 24247 011360 +de 24250 073360 +de 24251 045350 +de 24252 011361 +de 24253 045357 +de 24254 011362 +de 24255 073362 +de 24256 044000 +de 24257 101040 +de 24260 003305 +de 24261 011363 +de 24262 005362 +de 24263 010000 +de 24264 101400 +de 24265 003275 +de 24266 025362 +de 24267 044001 +de 24270 023506 +de 24271 100000 +de 24272 003305 +de 24273 017514 +de 24274 011363 +de 24275 121332 +de 24276 005362 +de 24277 140100 +de 24300 121333 +de 24301 121334 +de 24302 005363 +de 24303 121333 +de 24304 121334 +de 24305 025362 +de 24306 025361 +de 24307 003255 +de 24310 025360 +de 24311 003250 +de 24312 103335 +de 24313 073515 +de 24314 045400 +de 24315 033360 +de 24316 121336 +de 24317 073360 +de 24320 024000 +de 24321 003314 +de 24322 073516 +de 24323 044104 +de 24324 033360 +de 24325 121336 +de 24326 073360 +de 24327 024000 +de 24330 003323 +de 24331 103335 +de 24332 023165 +de 24333 023302 +de 24334 023173 +de 24335 023076 +de 24336 023227 +de 24337 177727 +de 24340 000343 +de 24341 177770 +de 24342 177770 +de 24343 177770 +de 24344 177730 +de 24345 177774 +de 24346 177730 +de 24347 177720 +de 24350 033457 +de 24351 013333 +de 24352 016155 +de 24353 032030 +de 24354 100020 +de 24355 000517 +de 24356 033477 +de 24357 177771 +de 24364 000134 +de 24365 000674 +de 24366 012654 +de 24367 012604 +de 24370 000675 +de 24371 013106 +de 24372 000676 +de 24373 016042 +de 24374 020144 +de 24375 003412 +de 24376 004420 +de 24377 000111 +de 24400 123076 +de 24401 123110 +de 24402 023414 +de 24403 123603 +de 24404 023370 +de 24405 023510 +de 24406 123110 +de 24407 123110 +de 24410 123612 +de 24411 024313 +de 24412 023101 +de 24413 123110 +de 24414 123612 +de 24415 023443 +de 24416 023512 +de 24417 123567 +de 24420 123110 +de 24421 023623 +de 24422 123110 +de 24423 023460 +de 24424 123416 +de 24425 123110 +de 24426 123110 +de 24427 023506 +de 24430 123110 +de 24431 123110 +de 24432 023500 +de 24433 123110 +de 24434 023425 +de 24435 123110 +de 24436 023440 +de 24437 023412 +de 24440 123377 +de 24441 024214 +de 24442 023451 +de 24443 123110 +de 24444 023557 +de 24445 123110 +de 24446 123110 +de 24447 123110 +de 24450 123110 +de 24451 123110 +de 24452 023407 +de 24453 123377 +de 24454 123343 +de 24455 123401 +de 24456 023405 +de 24457 023420 +de 24460 123355 +de 24461 123355 +de 24462 123355 +de 24463 123355 +de 24464 123355 +de 24465 123355 +de 24466 123355 +de 24467 123355 +de 24470 123355 +de 24471 123355 +de 24472 123110 +de 24473 123110 +de 24474 123110 +de 24475 123373 +de 24476 023334 +de 24477 023135 +de 24500 040377 +de 24501 040005 +de 24502 000033 +de 24503 040333 +de 24504 023162 +de 24505 024053 +de 24506 100001 +de 24507 177014 +de 24510 000177 +de 24511 100200 +de 24512 023110 +de 24513 177770 +de 24514 100111 +de 24515 177764 +de 24516 177760 +de 25062 011115 +de 25063 070004 +de 25064 003077 +de 25065 140040 +de 25066 022474 +de 25067 003112 +de 25070 003104 +de 25071 030104 +de 25072 005511 +de 25073 170004 +de 25074 003112 +de 25075 004121 +de 25076 010474 +de 25077 000043 +de 25100 171020 +de 25101 005115 +de 25102 000401 +de 25103 103061 +de 25104 005503 +de 25105 100040 +de 25106 003112 +de 25107 131004 +de 25110 003107 +de 25111 011116 +de 25112 030004 +de 25113 004114 +de 25114 003076 +de 25117 140040 +de 25120 011503 +de 25121 010673 +de 25122 011504 +de 25123 011163 +de 25124 111512 +de 25125 004106 +de 25126 013513 +de 25127 111514 +de 25130 012753 +de 25131 011165 +de 25132 005515 +de 25133 170020 +de 25134 003174 +de 25135 005170 +de 25136 011160 +de 25137 000401 +de 25140 072113 +de 25141 120665 +de 25142 005503 +de 25143 100040 +de 25144 003137 +de 25145 001001 +de 25146 026474 +de 25147 101400 +de 25150 101040 +de 25151 003137 +de 25152 005116 +de 25153 007516 +de 25154 013517 +de 25155 011163 +de 25156 000401 +de 25157 103160 +de 25161 011164 +de 25162 003137 +de 25170 025171 +de 25171 023520 +de 25172 100000 +de 25173 003221 +de 25174 005165 +de 25175 120664 +de 25176 140040 +de 25177 120664 +de 25200 005163 +de 25201 013517 +de 25202 100040 +de 25203 003207 +de 25204 004106 +de 25205 013521 +de 25206 011165 +de 25207 005163 +de 25210 140500 +de 25211 141340 +de 25212 011164 +de 25213 140040 +de 25214 011504 +de 25215 005164 +de 25216 072112 +de 25217 120664 +de 25220 003135 +de 25221 004673 +de 25222 011504 +de 25223 005166 +de 25224 120664 +de 25225 005167 +de 25226 120664 +de 25227 004112 +de 25230 021277 +de 25231 140500 +de 25232 141340 +de 25233 021277 +de 25234 013517 +de 25235 013164 +de 25236 120664 +de 25237 003227 +de 25240 140040 +de 25241 021277 +de 25242 023522 +de 25243 100000 +de 25244 003253 +de 25245 001001 +de 25246 040075 +de 25247 005164 +de 25250 041075 +de 25251 000401 +de 25252 003241 +de 25253 070104 +de 25254 003274 +de 25255 030104 +de 25256 005523 +de 25257 170004 +de 25260 003257 +de 25261 025503 +de 25262 120665 +de 25263 140040 +de 25264 026474 +de 25265 101040 +de 25266 003262 +de 25267 005503 +de 25270 016114 +de 25271 100400 +de 25272 140040 +de 25273 011503 +de 25274 005164 +de 25275 120664 +de 25276 003227 +de 25300 021160 +de 25301 023520 +de 25302 100000 +de 25303 003215 +de 25304 023524 +de 25305 103277 +de 25306 003240 +de 25307 103277 +de 25310 072113 +de 25311 033505 +de 25312 120666 +de 25313 025503 +de 25314 011501 +de 25315 007525 +de 25316 022106 +de 25317 022752 +de 25320 003323 +de 25321 101000 +de 25322 011506 +de 25323 120667 +de 25324 005501 +de 25325 041475 +de 25326 011502 +de 25327 101400 +de 25330 005504 +de 25331 101040 +de 25332 003353 +de 25333 005522 +de 25334 021450 +de 25335 005523 +de 25336 021450 +de 25337 005523 +de 25340 021450 +de 25341 005501 +de 25342 021412 +de 25343 120666 +de 25344 100000 +de 25345 003350 +de 25346 021412 +de 25347 003356 +de 25350 025505 +de 25351 021412 +de 25352 003370 +de 25353 120666 +de 25354 100000 +de 25355 003437 +de 25356 120666 +de 25357 003374 +de 25360 025505 +de 25361 011501 +de 25362 141050 +de 25363 101040 +de 25364 003370 +de 25365 005501 +de 25366 141140 +de 25367 021450 +de 25370 140040 +de 25371 011503 +de 25372 011502 +de 25373 003310 +de 25374 011501 +de 25375 005502 +de 25376 100400 +de 25377 003407 +de 25400 005501 +de 25401 141140 +de 25402 021450 +de 25403 005501 +de 25404 141050 +de 25405 021450 +de 25406 003356 +de 25407 005501 +de 25410 021412 +de 25411 003356 +de 25413 000201 +de 25414 004126 +de 25415 011507 +de 25416 005526 +de 25417 041077 +de 25420 000201 +de 25421 011510 +de 25422 000201 +de 25423 021450 +de 25424 005510 +de 25425 000201 +de 25426 005527 +de 25427 041075 +de 25430 025507 +de 25431 003420 +de 25432 005522 +de 25433 021450 +de 25434 005523 +de 25435 021450 +de 25436 103412 +de 25437 025505 +de 25440 005501 +de 25441 007530 +de 25442 013531 +de 25443 100040 +de 25444 003370 +de 25445 005511 +de 25446 021450 +de 25447 003370 +de 25451 023517 +de 25452 101000 +de 25453 100000 +de 25454 103450 +de 25455 072113 +de 25456 070104 +de 25457 003472 +de 25460 030104 +de 25461 170004 +de 25462 003472 +de 25463 120667 +de 25464 140040 +de 25465 026474 +de 25466 101400 +de 25467 101040 +de 25470 003463 +de 25471 103450 +de 25472 005505 +de 25473 100040 +de 25474 003370 +de 25475 120666 +de 25476 003472 +de 25477 010472 +de 25500 003370 +de 25511 000334 +de 25512 024046 +de 25513 140000 +de 25514 024050 +de 25515 000040 +de 25516 000177 +de 25517 000200 +de 25520 000273 +de 25521 140100 +de 25522 000215 +de 25523 000212 +de 25524 000272 +de 25525 000377 +de 25526 000130 +de 25527 000026 +de 25530 007400 +de 25531 004400 +de 26071 005645 +de 26072 010660 +de 26073 005646 +de 26074 010661 +de 26075 005647 +de 26076 010662 +de 26077 073346 +de 26100 005637 +de 26101 050265 +de 26102 140040 +de 26103 051500 +de 26104 005640 +de 26105 110660 +de 26106 110661 +de 26107 110662 +de 26110 024000 +de 26111 003100 +de 26112 072106 +de 26113 140040 +de 26114 011644 +de 26115 050165 +de 26116 111650 +de 26117 103070 +de 26121 033365 +de 26122 011372 +de 26123 073342 +de 26124 140040 +de 26125 055365 +de 26126 024000 +de 26127 003125 +de 26130 100040 +de 26131 120061 +de 26132 073365 +de 26133 045500 +de 26134 141206 +de 26135 011366 +de 26136 004000 +de 26137 141206 +de 26140 011367 +de 26141 141340 +de 26142 011370 +de 26143 013367 +de 26144 011371 +de 26145 005372 +de 26146 101040 +de 26147 003152 +de 26150 005344 +de 26151 003167 +de 26152 044433 +de 26153 100040 +de 26154 103120 +de 26155 072514 +de 26156 044006 +de 26157 141044 +de 26160 073365 +de 26161 067505 +de 26162 053505 +de 26163 101040 +de 26164 103120 +de 26165 004514 +de 26166 015343 +de 26167 011372 +de 26170 073346 +de 26171 105372 +de 26172 007347 +de 26173 015353 +de 26174 101040 +de 26175 005347 +de 26176 011373 +de 26177 141340 +de 26200 011374 +de 26201 105372 +de 26202 007350 +de 26203 015366 +de 26204 023350 +de 26205 005350 +de 26206 101000 +de 26207 011375 +de 26210 005371 +de 26211 052265 +de 26212 007363 +de 26213 023352 +de 26214 003262 +de 26215 101000 +de 26216 011376 +de 26217 104662 +de 26220 007350 +de 26221 013373 +de 26222 126662 +de 26223 007347 +de 26224 141340 +de 26225 017374 +de 26226 100400 +de 26227 003252 +de 26230 005376 +de 26231 100040 +de 26232 003320 +de 26233 104662 +de 26234 007347 +de 26235 013375 +de 26236 126662 +de 26237 007350 +de 26240 017375 +de 26241 015351 +de 26242 100400 +de 26243 003310 +de 26244 024000 +de 26245 003171 +de 26246 025377 +de 26247 101000 +de 26250 073365 +de 26251 103120 +de 26252 045500 +de 26253 007356 +de 26254 100040 +de 26255 003230 +de 26256 005356 +de 26257 053500 +de 26260 051500 +de 26261 003230 +de 26262 007352 +de 26263 011376 +de 26264 045500 +de 26265 007356 +de 26266 100040 +de 26267 003230 +de 26270 104662 +de 26271 007347 +de 26272 141340 +de 26273 023374 +de 26274 003277 +de 26275 003230 +de 26276 003230 +de 26277 141340 +de 26300 112662 +de 26301 013373 +de 26302 110662 +de 26303 044265 +de 26304 007361 +de 26305 013370 +de 26306 050265 +de 26307 003230 +de 26310 045500 +de 26311 007357 +de 26312 100040 +de 26313 003244 +de 26314 005357 +de 26315 053500 +de 26316 051500 +de 26317 003244 +de 26320 045500 +de 26321 007357 +de 26322 100040 +de 26323 003244 +de 26324 104662 +de 26325 007350 +de 26326 023375 +de 26327 003332 +de 26330 003244 +de 26331 003244 +de 26332 112662 +de 26333 013375 +de 26334 110662 +de 26335 044265 +de 26336 007360 +de 26337 013367 +de 26340 050265 +de 26341 003244 +de 26342 177534 +de 26343 040107 +de 26344 026345 +de 26345 177777 +de 26346 177700 +de 26347 174000 +de 26350 003777 +de 26351 000010 +de 26352 000037 +de 26353 004000 +de 26354 020000 +de 26355 000040 +de 26356 060000 +de 26357 000140 +de 26360 177740 +de 26361 160377 +de 26362 160340 +de 26363 017437 +de 26364 104676 +de 26513 073627 +de 26514 140040 +de 26515 055642 +de 26516 024000 +de 26517 003515 +de 26520 100040 +de 26521 120061 +de 26522 073630 +de 26523 033642 +de 26524 110660 +de 26525 024000 +de 26526 015642 +de 26527 011642 +de 26530 004106 +de 26531 141340 +de 26532 141206 +de 26533 110660 +de 26534 024000 +de 26535 015642 +de 26536 011642 +de 26537 005644 +de 26540 015631 +de 26541 011644 +de 26542 110660 +de 26543 024000 +de 26544 015642 +de 26545 011642 +de 26546 044265 +de 26547 100400 +de 26550 003602 +de 26551 104662 +de 26552 007347 +de 26553 141340 +de 26554 023633 +de 26555 003614 +de 26556 003614 +de 26557 044265 +de 26560 007636 +de 26561 050265 +de 26562 033643 +de 26563 104662 +de 26564 110660 +de 26565 015642 +de 26566 011642 +de 26567 024000 +de 26570 003546 +de 26571 140407 +de 26572 110660 +de 26573 073643 +de 26574 044265 +de 26575 007632 +de 26576 141340 +de 26577 016114 +de 26600 010420 +de 26601 103512 +de 26602 104662 +de 26603 007347 +de 26604 141340 +de 26605 023633 +de 26606 003624 +de 26607 003624 +de 26610 044265 +de 26611 007363 +de 26612 013634 +de 26613 003622 +de 26614 044265 +de 26615 007635 +de 26616 100040 +de 26617 003563 +de 26620 005635 +de 26621 052265 +de 26622 050265 +de 26623 003563 +de 26624 005640 +de 26625 110662 +de 26626 003564 +de 26627 177651 +de 26630 177675 +de 26631 000400 +de 26632 017400 +de 26633 000260 +de 26634 000340 +de 26635 060000 +de 26636 117777 +de 26637 100000 +de 26640 177777 +de 26641 125362 +de 26645 073106 +de 26646 073212 +de 26647 073316 +de 26650 073216 +de 27113 073261 +de 27114 140040 +de 27115 055263 +de 27116 024000 +de 27117 003115 +de 27120 100040 +de 27121 120061 +de 27122 073230 +de 27123 105241 +de 27124 007243 +de 27125 101040 +de 27126 003132 +de 27127 105241 +de 27130 017251 +de 27131 111241 +de 27132 105241 +de 27133 007244 +de 27134 101040 +de 27135 003141 +de 27136 105241 +de 27137 017252 +de 27140 111241 +de 27141 024000 +de 27142 003123 +de 27143 025263 +de 27144 003170 +de 27145 005237 +de 27146 011263 +de 27147 073230 +de 27150 044265 +de 27151 007245 +de 27152 101040 +de 27153 003166 +de 27154 044265 +de 27155 017246 +de 27156 050265 +de 27157 007245 +de 27160 100040 +de 27161 003166 +de 27162 005235 +de 27163 111242 +de 27164 005236 +de 27165 050265 +de 27166 024000 +de 27167 003150 +de 27170 025264 +de 27171 003206 +de 27172 005240 +de 27173 011264 +de 27174 073230 +de 27175 044265 +de 27176 007247 +de 27177 101040 +de 27200 003204 +de 27201 044265 +de 27202 017250 +de 27203 050265 +de 27204 024000 +de 27205 003175 +de 27206 073231 +de 27207 140040 +de 27210 011266 +de 27211 127232 +de 27212 017234 +de 27213 100400 +de 27214 003217 +de 27215 025266 +de 27216 003212 +de 27217 005233 +de 27220 017266 +de 27221 100400 +de 27222 140040 +de 27223 015260 +de 27224 051274 +de 27225 024000 +de 27226 003207 +de 27227 103112 +de 27230 177700 +de 27231 177773 +de 27232 052632 +de 27233 000004 +de 27234 002450 +de 27235 177777 +de 27236 100000 +de 27237 177772 +de 27240 177767 +de 27241 066500 +de 27242 073316 +de 27243 060000 +de 27244 000140 +de 27245 060000 +de 27246 020000 +de 27247 000340 +de 27250 000040 +de 27251 020000 +de 27252 000040 +de 27253 000001 +de 27254 000005 +de 27255 000015 +de 27256 000033 +de 27257 000037 +de 27260 027253 +de 27261 177630 +de 27262 147750 +de 30056 004114 +de 30057 011213 +de 30060 005436 +de 30061 027213 +de 30062 023436 +de 30063 100000 +de 30064 003104 +de 30065 101040 +de 30066 003075 +de 30067 073575 +de 30070 105576 +de 30071 111577 +de 30072 024000 +de 30073 003070 +de 30074 003104 +de 30075 021256 +de 30076 073575 +de 30077 005600 +de 30100 111577 +de 30101 141206 +de 30102 024000 +de 30103 003100 +de 30104 005601 +de 30105 011455 +de 30106 005602 +de 30107 011440 +de 30110 005603 +de 30111 011212 +de 30112 072125 +de 30113 033441 +de 30114 033211 +de 30115 105212 +de 30116 101040 +de 30117 003170 +de 30120 004417 +de 30121 057211 +de 30122 100400 +de 30123 140407 +de 30124 057465 +de 30125 100400 +de 30126 003170 +de 30127 140040 +de 30130 011214 +de 30131 004000 +de 30132 012124 +de 30133 100040 +de 30134 003153 +de 30135 045465 +de 30136 040572 +de 30137 101040 +de 30140 003153 +de 30141 140407 +de 30142 011215 +de 30143 004106 +de 30144 140407 +de 30145 011216 +de 30146 025214 +de 30147 025216 +de 30150 003146 +de 30151 025215 +de 30152 003143 +de 30153 045465 +de 30154 140407 +de 30155 006417 +de 30156 015214 +de 30157 051211 +de 30160 045457 +de 30161 021403 +de 30162 045451 +de 30163 021403 +de 30164 143204 +de 30165 073604 +de 30166 004112 +de 30167 120664 +de 30170 073211 +de 30171 025212 +de 30172 024000 +de 30173 003114 +de 30174 072116 +de 30175 120665 +de 30176 003060 +de 30177 030217 +de 30200 030243 +de 30201 030267 +de 30202 030347 +de 30203 022057 +de 30217 005605 +de 30220 021403 +de 30221 004415 +de 30222 021403 +de 30223 073606 +de 30224 001001 +de 30225 044543 +de 30226 056567 +de 30227 000401 +de 30230 021403 +de 30231 024000 +de 30232 003224 +de 30233 072132 +de 30234 044265 +de 30235 021403 +de 30236 105607 +de 30237 021403 +de 30240 024000 +de 30241 003234 +de 30242 003165 +de 30243 004115 +de 30244 021403 +de 30245 004417 +de 30246 021403 +de 30247 073610 +de 30250 105611 +de 30251 021403 +de 30252 024000 +de 30253 003250 +de 30254 021256 +de 30255 003165 +de 30257 073610 +de 30260 140040 +de 30261 001001 +de 30262 111611 +de 30263 024000 +de 30264 003262 +de 30265 000401 +de 30266 103256 +de 30267 072116 +de 30270 005465 +de 30271 007612 +de 30272 101040 +de 30273 003301 +de 30274 140407 +de 30275 011346 +de 30276 120664 +de 30277 025346 +de 30300 003276 +de 30301 131040 +de 30302 003301 +de 30303 140040 +de 30304 100040 +de 30305 004112 +de 30306 013454 +de 30307 011454 +de 30310 005446 +de 30311 101000 +de 30312 003165 +de 30313 101040 +de 30314 003333 +de 30315 015613 +de 30316 011446 +de 30317 100040 +de 30320 003165 +de 30321 004415 +de 30322 017345 +de 30323 111343 +de 30324 025343 +de 30325 005465 +de 30326 015342 +de 30327 011465 +de 30330 017344 +de 30331 101400 +de 30332 003337 +de 30333 004415 +de 30334 011345 +de 30335 005446 +de 30336 003315 +de 30337 140040 +de 30340 011437 +de 30341 003165 +de 30342 000010 +de 30343 030000 +de 30344 000760 +de 30347 001001 +de 30350 104342 +de 30351 026342 +de 30352 000401 +de 30353 011401 +de 30354 004746 +de 30355 021403 +de 30356 004747 +de 30357 021403 +de 30360 004750 +de 30361 021403 +de 30362 005401 +de 30363 010000 +de 30364 021403 +de 30365 005614 +de 30366 011402 +de 30367 044000 +de 30370 021403 +de 30371 024000 +de 30372 025402 +de 30373 003367 +de 30374 001001 +de 30375 073401 +de 30376 120671 +de 30377 000401 +de 30400 003165 +de 30404 033411 +de 30405 072116 +de 30406 120664 +de 30407 073411 +de 30410 103403 +de 30412 120666 +de 30413 003412 +de 30414 120666 +de 30415 120666 +de 30416 120666 +de 30417 100000 +de 30420 003414 +de 30421 100400 +de 30422 003412 +de 30423 007615 +de 30424 015616 +de 30425 011433 +de 30426 120666 +de 30427 100000 +de 30430 003414 +de 30431 111433 +de 30432 003416 +de 30474 120666 +de 30475 003474 +de 30476 003474 +de 30477 140500 +de 30500 003515 +de 30501 000401 +de 30502 005572 +de 30503 101040 +de 30504 003527 +de 30505 004112 +de 30506 073617 +de 30507 120664 +de 30510 120665 +de 30511 004341 +de 30512 101040 +de 30513 003510 +de 30514 140040 +de 30515 011572 +de 30516 005451 +de 30517 120664 +de 30520 005443 +de 30521 120664 +de 30522 004114 +de 30523 120664 +de 30524 140040 +de 30525 026414 +de 30526 120664 +de 30527 072115 +de 30530 120665 +de 30531 005621 +de 30532 011573 +de 30533 001001 +de 30534 105573 +de 30535 011573 +de 30536 105573 +de 30537 011574 +de 30540 101040 +de 30541 003501 +de 30542 010000 +de 30543 044012 +de 30544 101400 +de 30545 003534 +de 30546 044000 +de 30547 111573 +de 30550 000401 +de 30551 025572 +de 30552 005622 +de 30553 011571 +de 30554 072115 +de 30555 025574 +de 30556 105574 +de 30557 120664 +de 30560 025571 +de 30561 003555 +de 30562 005574 +de 30563 015622 +de 30564 001001 +de 30565 026325 +de 30566 110325 +de 30567 000401 +de 30570 003531 +de 30575 177760 +de 30576 072030 +de 30577 172010 +de 30600 120574 +de 30601 050057 +de 30602 100342 +de 30603 130434 +de 30604 100003 +de 30605 000005 +de 30606 177754 +de 30607 073106 +de 30610 177423 +de 30611 071716 +de 30612 000777 +de 30613 000400 +de 30614 177666 +de 30615 000037 +de 30616 030434 +de 30617 100002 +de 30620 000341 +de 30621 030620 +de 30622 177766 +de 31056 005753 +de 31057 001001 +de 31060 011121 +de 31061 004675 +de 31062 021123 +de 31063 015356 +de 31064 011356 +de 31065 000401 +de 31066 072675 +de 31067 172677 +de 31070 044007 +de 31071 103055 +de 31073 065375 +de 31074 101000 +de 31075 103754 +de 31077 005755 +de 31100 001001 +de 31101 011121 +de 31102 004676 +de 31103 172700 +de 31104 021123 +de 31105 015374 +de 31106 011374 +de 31107 000401 +de 31110 072676 +de 31111 105756 +de 31112 103076 +de 31114 141206 +de 31115 065405 +de 31116 101000 +de 31117 103113 +de 31124 016130 +de 31125 101400 +de 31126 003156 +de 31127 044111 +de 31130 016000 +de 31131 017757 +de 31132 140100 +de 31133 011122 +de 31134 021717 +de 31135 014120 +de 31136 015121 +de 31137 011120 +de 31140 125120 +de 31141 101000 +de 31142 044006 +de 31143 141340 +de 31144 006120 +de 31145 101040 +de 31146 003154 +de 31147 016114 +de 31150 015121 +de 31151 011121 +de 31152 125121 +de 31153 101000 +de 31154 005122 +de 31155 103123 +de 31156 073123 +de 31157 042002 +de 31161 111760 +de 31162 010000 +de 31163 044105 +de 31164 016000 +de 31165 016116 +de 31166 140100 +de 31167 011337 +de 31170 021717 +de 31171 173761 +de 31172 055331 +de 31173 011340 +de 31174 125340 +de 31175 101000 +de 31176 005337 +de 31177 055622 +de 31200 051622 +de 31201 103160 +de 31203 025627 +de 31204 070471 +de 31205 103202 +de 31206 025634 +de 31207 025202 +de 31210 101000 +de 31211 103202 +de 31213 064426 +de 31214 065641 +de 31215 101000 +de 31216 103212 +de 31220 100040 +de 31221 025217 +de 31222 101040 +de 31223 065646 +de 31224 101000 +de 31225 103217 +de 31227 025630 +de 31230 070472 +de 31231 103226 +de 31232 025635 +de 31233 025226 +de 31234 101000 +de 31235 103226 +de 31237 025631 +de 31240 070473 +de 31241 103236 +de 31242 025636 +de 31243 025236 +de 31244 101000 +de 31245 103236 +de 31247 025632 +de 31250 070474 +de 31251 103246 +de 31252 025637 +de 31253 025246 +de 31254 101000 +de 31255 103246 +de 31257 025633 +de 31260 070475 +de 31261 103256 +de 31262 025640 +de 31263 025256 +de 31264 101000 +de 31265 103256 +de 31267 050111 +de 31270 173762 +de 31271 131040 +de 31272 003271 +de 31273 050010 +de 31274 173763 +de 31275 103266 +de 31277 050030 +de 31300 131040 +de 31301 003300 +de 31302 050044 +de 31303 103276 +de 31305 131040 +de 31306 003305 +de 31307 173764 +de 31310 056010 +de 31311 021322 +de 31312 103765 +de 31314 131040 +de 31315 003314 +de 31316 173764 +de 31317 056044 +de 31320 021322 +de 31321 103766 +de 31323 040475 +de 31324 173767 +de 31325 055415 +de 31326 051415 +de 31327 065515 +de 31330 103322 +de 31331 031660 +de 31332 031666 +de 31333 031674 +de 31334 031702 +de 31335 031710 +de 31336 031716 +de 31720 033742 +de 31721 022120 +de 31722 003731 +de 31723 101000 +de 31724 100400 +de 31725 003733 +de 31726 010000 +de 31727 045743 +de 31730 003740 +de 31731 040575 +de 31732 022120 +de 31733 004120 +de 31734 101000 +de 31735 010000 +de 31736 045743 +de 31737 014116 +de 31740 073742 +de 31741 103717 +de 31745 000001 +de 31746 000001 +de 31747 000002 +de 31750 000002 +de 31751 000002 +de 31752 000002 +de 31753 031341 +de 31754 154137 +de 31755 031357 +de 31756 056124 +de 31757 000011 +de 31760 012655 +de 31761 012654 +de 31762 015156 +de 31763 115156 +de 31764 007131 +de 31765 007213 +de 31766 007215 +de 31767 006673 +de 31770 005450 +de 31771 007127 +de 31772 007201 +de 31773 010052 +de 31774 010076 +de 31775 010122 +de 31776 010146 +de 31777 010172 +de 32000 010235 +de 32001 012420 +de 32002 014121 +de 32003 014613 +de 32004 015102 +de 32005 015261 +de 32006 016457 +de 32007 017115 +de 32010 064426 +de 32011 003213 +de 32012 003215 +de 32013 070471 +de 32014 070472 +de 32015 070473 +de 32016 070474 +de 32017 070475 +de 32020 101040 +de 32021 011655 +de 32022 143137 +de 32023 044007 +de 32024 050111 +de 32025 050030 +de 32026 141206 +de 32027 105432 +de 37026 005732 +de 37027 026567 +de 37030 100040 +de 37031 103025 +de 37032 011000 +de 37033 011001 +de 37034 011002 +de 37035 011003 +de 37036 005733 +de 37037 011024 +de 37040 001001 +de 37041 121734 +de 37042 003112 +de 37043 004000 +de 37044 015735 +de 37045 010024 +de 37046 015736 +de 37047 010025 +de 37050 073737 +de 37051 045732 +de 37052 111740 +de 37053 024000 +de 37054 003051 +de 37055 030473 +de 37056 021060 +de 37057 103025 +de 37061 073741 +de 37062 140040 +de 37063 051022 +de 37064 024000 +de 37065 003063 +de 37066 010036 +de 37067 072124 +de 37070 033022 +de 37071 032475 +de 37072 140040 +de 37073 067004 +de 37074 101040 +de 37075 003103 +de 37076 033114 +de 37077 140100 +de 37100 010000 +de 37101 120671 +de 37102 073114 +de 37103 024000 +de 37104 003072 +de 37105 005742 +de 37106 011015 +de 37107 005743 +de 37110 111744 +de 37111 103060 +de 37112 024144 +de 37113 003025 +de 37125 011117 +de 37126 033120 +de 37127 105745 +de 37130 073746 +de 37131 100040 +de 37132 073747 +de 37133 100400 +de 37134 073750 +de 37135 004000 +de 37136 170120 +de 37137 026134 +de 37140 011121 +de 37141 000043 +de 37142 011115 +de 37143 120672 +de 37144 004025 +de 37145 140100 +de 37146 017751 +de 37147 011116 +de 37150 015752 +de 37151 011123 +de 37152 005015 +de 37153 100400 +de 37154 003171 +de 37155 070473 +de 37156 100000 +de 37157 003171 +de 37160 105123 +de 37161 007733 +de 37162 013024 +de 37163 101040 +de 37164 003212 +de 37165 013024 +de 37166 011024 +de 37167 001001 +de 37170 021317 +de 37171 005116 +de 37172 015735 +de 37173 010024 +de 37174 015736 +de 37175 010025 +de 37176 030473 +de 37177 073120 +de 37200 001001 +de 37201 005121 +de 37202 170120 +de 37203 010134 +de 37204 000013 +de 37205 005115 +de 37206 171020 +de 37207 005117 +de 37210 000401 +de 37211 103124 +de 37212 105123 +de 37213 072113 +de 37214 040576 +de 37215 021273 +de 37216 072114 +de 37217 105123 +de 37220 040575 +de 37221 021273 +de 37222 105123 +de 37223 006114 +de 37224 011023 +de 37225 010000 +de 37226 105123 +de 37227 041676 +de 37230 053011 +de 37231 100100 +de 37232 003171 +de 37233 105123 +de 37234 141340 +de 37235 006752 +de 37236 101040 +de 37237 003171 +de 37240 011122 +de 37241 073023 +de 37242 045002 +de 37243 100040 +de 37244 003171 +de 37245 105123 +de 37246 006112 +de 37247 051020 +de 37250 001001 +de 37251 104324 +de 37252 101040 +de 37253 003171 +de 37254 011014 +de 37255 045011 +de 37256 012114 +de 37257 051011 +de 37260 005116 +de 37261 051002 +de 37262 010000 +de 37263 005122 +de 37264 050111 +de 37265 001001 +de 37266 024563 +de 37267 104324 +de 37270 026324 +de 37271 000401 +de 37272 003172 +de 37274 053007 +de 37275 101100 +de 37276 003312 +de 37277 045007 +de 37300 012114 +de 37301 051007 +de 37302 045000 +de 37303 001001 +de 37304 100040 +de 37305 003307 +de 37306 021317 +de 37307 000401 +de 37310 140500 +de 37311 051000 +de 37312 005753 +de 37313 011013 +de 37314 004112 +de 37315 111744 +de 37316 103273 +de 37320 120745 +de 37321 021060 +de 37322 003171 +de 37332 011324 +de 37333 004502 +de 37334 170120 +de 37335 026134 +de 37336 011326 +de 37337 000043 +de 37340 011323 +de 37341 120672 +de 37342 033325 +de 37343 140040 +de 37344 010036 +de 37345 005015 +de 37346 100400 +de 37347 003364 +de 37350 021407 +de 37351 021407 +de 37352 005014 +de 37353 100400 +de 37354 003364 +de 37355 021377 +de 37356 005754 +de 37357 010036 +de 37360 010037 +de 37361 005755 +de 37362 011014 +de 37363 030073 +de 37364 073325 +de 37365 001001 +de 37366 005326 +de 37367 170120 +de 37370 010134 +de 37371 000013 +de 37372 005323 +de 37373 171020 +de 37374 005324 +de 37375 000401 +de 37376 103331 +de 37400 001001 +de 37401 005012 +de 37402 041577 +de 37403 013011 +de 37404 041576 +de 37405 011330 +de 37406 103377 +de 37410 005005 +de 37411 012114 +de 37412 011005 +de 37413 001001 +de 37414 073005 +de 37415 045000 +de 37416 101040 +de 37417 103407 +de 37420 100400 +de 37421 003445 +de 37422 011327 +de 37423 021377 +de 37424 045007 +de 37425 040676 +de 37426 013330 +de 37427 013005 +de 37430 053016 +de 37431 011330 +de 37432 073327 +de 37433 044111 +de 37434 141240 +de 37435 015330 +de 37436 050010 +de 37437 004000 +de 37440 015752 +de 37441 010036 +de 37442 054111 +de 37443 140100 +de 37444 003360 +de 37445 140040 +de 37446 067000 +de 37447 140100 +de 37450 010000 +de 37451 001001 +de 37452 120671 +de 37453 103407 +de 37455 140040 +de 37456 026476 +de 37457 100040 +de 37460 003476 +de 37461 005015 +de 37462 101400 +de 37463 003471 +de 37464 025015 +de 37465 103454 +de 37466 005755 +de 37467 011014 +de 37470 103454 +de 37471 005013 +de 37472 101400 +de 37473 103454 +de 37474 025013 +de 37475 003501 +de 37476 001001 +de 37477 021060 +de 37500 103454 +de 37501 025014 +de 37502 101000 +de 37503 103454 +de 37512 001001 +de 37513 004500 +de 37514 170120 +de 37515 026134 +de 37516 011504 +de 37517 000401 +de 37520 105756 +de 37521 022121 +de 37522 100000 +de 37523 003612 +de 37524 005743 +de 37525 111757 +de 37526 073006 +de 37527 045002 +de 37530 101040 +de 37531 003612 +de 37532 011505 +de 37533 004454 +de 37534 013760 +de 37535 101040 +de 37536 003605 +de 37537 013761 +de 37540 100040 +de 37541 003560 +de 37542 073505 +de 37543 044011 +de 37544 110052 +de 37545 044012 +de 37546 024052 +de 37547 110052 +de 37550 073006 +de 37551 045020 +de 37552 100400 +de 37553 003605 +de 37554 001001 +de 37555 073505 +de 37556 120671 +de 37557 003577 +de 37560 005505 +de 37561 127762 +de 37562 010000 +de 37563 050111 +de 37564 001001 +de 37565 120671 +de 37566 073505 +de 37567 044111 +de 37570 015505 +de 37571 015763 +de 37572 010052 +de 37573 073006 +de 37574 045020 +de 37575 100400 +de 37576 111757 +de 37577 073006 +de 37600 140040 +de 37601 051002 +de 37602 005006 +de 37603 012114 +de 37604 011006 +de 37605 001001 +de 37606 000013 +de 37607 120101 +de 37610 001001 +de 37611 120672 +de 37612 073004 +de 37613 045000 +de 37614 100040 +de 37615 003704 +de 37616 051016 +de 37617 004046 +de 37620 101040 +de 37621 003704 +de 37622 121734 +de 37623 003704 +de 37624 000401 +de 37625 033506 +de 37626 027022 +de 37627 100040 +de 37630 003646 +de 37631 004047 +de 37632 016046 +de 37633 141206 +de 37634 050111 +de 37635 104046 +de 37636 050011 +de 37637 024000 +de 37640 024046 +de 37641 004047 +de 37642 016046 +de 37643 101400 +de 37644 003635 +de 37645 003662 +de 37646 104046 +de 37647 050011 +de 37650 024046 +de 37651 104046 +de 37652 050012 +de 37653 004115 +de 37654 050111 +de 37655 004046 +de 37656 024046 +de 37657 016047 +de 37660 100040 +de 37661 003676 +de 37662 140040 +de 37663 026475 +de 37664 011022 +de 37665 100040 +de 37666 004112 +de 37667 073004 +de 37670 051016 +de 37671 001001 +de 37672 000013 +de 37673 120077 +de 37674 001001 +de 37675 120672 +de 37676 073004 +de 37677 005506 +de 37700 051000 +de 37701 005004 +de 37702 012114 +de 37703 011004 +de 37704 004036 +de 37705 001001 +de 37706 000013 +de 37707 101040 +de 37710 021331 +de 37711 001001 +de 37712 005504 +de 37713 170120 +de 37714 010134 +de 37715 120672 +de 37716 103511 +de 37717 121407 +de 37720 121661 +de 37721 101000 +de 37722 024475 +de 37723 101000 +de 37724 101000 +de 37725 003531 +de 37726 100000 +de 37727 024476 +de 37730 037124 +de 37731 037331 +de 37732 004000 +de 37733 000200 +de 37734 004372 +de 37735 100010 +de 37736 000101 +de 37737 177765 +de 37740 142374 +de 37741 177762 +de 37742 177750 +de 37743 101000 +de 37744 021663 +de 37745 001005 +de 37746 154000 +de 37747 150000 +de 37750 140000 +de 37751 000111 +de 37752 000010 +de 37753 177770 +de 37754 037330 +de 37755 177774 +de 37756 013140 +de 37757 013314 +de 37760 013400 +de 37761 007453 +de 37762 013334 +de 37763 000011 + +; ****** OFFICIAL BBN PATCHES FROM PATCH.3050 ****** +de 03631 140040 +de 03632 110147 +de 03633 004121 +de 03634 110146 +de 03635 003074 +de 02511 003631 +de 00146 011206 +de 00147 011211 + +de 22567 072121 +de 22570 004342 +de 22571 111573 +de 22572 003324 +de 22573 030440 +de 22323 003567 + +de 30107 101000 +de 30115 045442 +de 22524 000303 + + +; ****** NEUHAUSER/RLA LOCAL PATCHES ******* + +; Changing 3416 to -2 limits the startup to two "fake" hosts - DDT and the +; console terminal. It disables the statistics task, which was causing +; problems ... +;;d 3614 177776 + +; Disable the software WDT. I'm not completely sure what this was originally +; for, but it appears to reboot the IMP if it goes 3 minutes w/o receiving any +; message from a host or another IMP. That makes testing difficult! +d -m 21131 NOP + +; Patch the DELSPD table to give a wider range of acceptable line speeds .... +;;de 11331 777 +;;de 11332 577 +;;de 11333 577 +;;de 11334 577 + +; Disable the requirement for one IHY message every short interval ... +;;de -m 20375 NOP + +; One remaining kludge - the IMP code around IHWAIT trashes the DMC pointers +; for modem line #5. IHWAIT is actually IMP to HOST code, and it's deciding +; that host #4 is down, so it aborts any I/O and clears the host 4 DMC pointers. +; Trouble is, host 4 shares DMC channels with modem 5! Needless to say, that +; trashes modem 5. I think this is actually a bug in the original IMP code +; (the IHWAIT code should check the HOST34 flag to see if host 4 exists before +; zeroing the DMC pointers), but what do I know?? +; +; In any case, this patch will allow five modem lines to work. All it does +; is modify the host interface DMC tables at IHB1 and IHB2 so that the pointers +; for host 4 are the same as host 3. Since neither exists it doesn't really +; matter, and this keeps IHWAIT from trashing modem 5... +de 16140 46 +de 16150 47 + +; Set the start address ... +de p 02000 diff --git a/H316/tests/impconfig.cmd b/H316/tests/impconfig.cmd new file mode 100644 index 00000000..34706ed6 --- /dev/null +++ b/H316/tests/impconfig.cmd @@ -0,0 +1,65 @@ +;; ***** GENERIC IMP CONFIGURATION ***** + +; This simh command file sets up the H316 simulator configuration for a generic +; IMP node. Note that it doesn't load any IMP code (the caller is expected to +; do that) and it doesn't define any IMP node specific settings (e.g. modem +; links, IMP address, etc). +; +; RLA [4-Jun-13] +RESET ALL + +; Define the CPU configuration ... +; NOTE - real IMPs only had 16K of memory! +SET CPU 16K NOHSA DMA=0 DMC EXTINT=16 + +; Disable all the devices an IMP doesn't have ... +SET LPT DISABLED +SET MT DISABLED +SET CLK DISABLED +SET FHD DISABLED +SET DP DISABLED + +; Enable the IMP device but leave the station address undefined ... +SET IMP ENABLED +;;SET IMP NUM=1 + +; Enable the RTC to count at 50kHz (20us intervals) ... +SET RTC ENABLED +SET RTC INTERVAL=20 +SET RTC QUANTUM=32 + +; Enable the WDT but don't ever time out (we have enough problems!)... +SET WDT ENABLED +SET WDT DELAY=0 + +; Enable only modem line 1 and disable all the rest ... +SET MI1 ENABLED +SET MI2 DISABLED +SET MI3 DISABLED +SET MI4 DISABLED +SET MI5 DISABLED + +; Enable only one host interface and disable all the rest ... +SET HI1 ENABLED +SET HI2 DISABLED +SET HI3 DISABLED +SET HI4 DISABLED + +; Just ignore I/Os to disconnected devices ... +DEPOSIT CPU STOP_DEV 0 + +; SS4 ON is required to run DDT! +DEPOSIT CPU SS4 1 + +; Set the TTY speed to realistic values (about 9600BPS in this case) ... +DEPOSIT TTY KTIME 1000 +DEPOSIT TTY TTIME 1000 + +; Don't know for sure what SS2 does, but it appears to have something to do +; with the IMP startup. Leave it ON for now... +DEPOSIT CPU SS2 1 + +; All done .... +SET CPU HISTORY=65000 +SET CONSOLE DEBUG=STDERR +SET WDT DEBUG=LIGHTS \ No newline at end of file diff --git a/H316/tests/implloop4.cmd b/H316/tests/implloop4.cmd new file mode 100644 index 00000000..927713b3 --- /dev/null +++ b/H316/tests/implloop4.cmd @@ -0,0 +1,21 @@ +;; *** IMP LINE FOUR (ONLY!) LOOPBACK TEST *** + +; Set the simulator configuration ... +echo IMP line four loopback test... +do impconfig.cmd +SET IMP NUM=2 + +; Load the IMP code ... +echo Loading IMP code ... +do impcode.cmd + +; Start up the modem links! +SET MI1 DISABLED +SET MI2 DISABLED +SET MI3 DISABLED +SET MI4 ENABLED +DEPOSIT MI4 LLOOP 1 +SET MI5 DISABLED + +; And we're done .. +echo Type GO to start ... diff --git a/H316/tests/imploop.cmd b/H316/tests/imploop.cmd new file mode 100644 index 00000000..9dc63784 --- /dev/null +++ b/H316/tests/imploop.cmd @@ -0,0 +1,25 @@ +;; *** IMP FIVE MODEM LINE LOOPBACK TEST *** + +; Set the simulator configuration ... +echo IMP five modem line interface loopback test... +do impconfig.cmd +SET IMP NUM=2 + +; Load the IMP code ... +echo Loading IMP code ... +do impcode.cmd + +; Start up the modem links! +SET MI1 ENABLED +SET MI1 LOOPINTERFACE +SET MI2 ENABLED +SET MI2 LOOPINTERFACE +SET MI3 ENABLED +SET MI3 LOOPINTERFACE +SET MI4 ENABLED +SET MI4 LOOPINTERFACE +SET MI5 ENABLED +SET MI5 LOOPINTERFACE + +; And we're done .. +echo Type GO to start ... diff --git a/H316/tests/imploop4.cmd b/H316/tests/imploop4.cmd new file mode 100644 index 00000000..1611f80f --- /dev/null +++ b/H316/tests/imploop4.cmd @@ -0,0 +1,21 @@ +;; *** IMP LINE FOUR (ONLY!) LOOPBACK TEST *** + +; Set the simulator configuration ... +echo IMP line four loopback test... +do impconfig.cmd +SET IMP NUM=2 + +; Load the IMP code ... +echo Loading IMP code ... +do impcode.cmd + +; Start up the modem links! +SET MI1 DISABLED +SET MI2 DISABLED +SET MI3 DISABLED +SET MI4 ENABLED +SET MI4 LOOPINTERFACE +SET MI5 DISABLED + +; And we're done .. +echo Type GO to start ... diff --git a/H316/tests/imploop4l.cmd b/H316/tests/imploop4l.cmd new file mode 100644 index 00000000..cdae40f8 --- /dev/null +++ b/H316/tests/imploop4l.cmd @@ -0,0 +1,22 @@ +;; *** IMP LINE FOUR (ONLY!) LOOPBACK TEST *** + +; Set the simulator configuration ... +echo IMP line four loopback test... +do impconfig.cmd +SET IMP NUM=2 + +; Load the IMP code ... +echo Loading IMP code ... +do impcode.cmd + +; Start up the modem links! +SET MI1 DISABLED +SET MI2 DISABLED +SET MI3 DISABLED +SET MI4 ENABLED +ATTACH MI4 4424:4434 +SET MI4 LOOPLINE +SET MI5 DISABLED + +; And we're done .. +echo Type GO to start ... diff --git a/H316/tests/imploopl.cmd b/H316/tests/imploopl.cmd new file mode 100644 index 00000000..ba7efca9 --- /dev/null +++ b/H316/tests/imploopl.cmd @@ -0,0 +1,30 @@ +;; *** IMP FIVE MODEM LINE LOOPBACK TEST *** + +; Set the simulator configuration ... +echo IMP five modem line interface loopback test... +do impconfig.cmd +SET IMP NUM=2 + +; Load the IMP code ... +echo Loading IMP code ... +do impcode.cmd + +; Start up the modem links! +SET MI1 ENABLED +ATTACH MI1 4421:4431 +SET MI1 LOOPLINE +SET MI2 ENABLED +ATTACH MI2 4422:4432 +SET MI2 LOOPLINE +SET MI3 ENABLED +ATTACH MI3 4423:4433 +SET MI3 LOOPLINE +SET MI4 ENABLED +ATTACH MI4 4424:4434 +SET MI4 LOOPLINE +SET MI5 ENABLED +ATTACH MI5 4425:4435 +SET MI5 LOOPLINE + +; And we're done .. +echo Type GO to start ... diff --git a/H316/tests/mdmtest1.cmd b/H316/tests/mdmtest1.cmd new file mode 100644 index 00000000..854c0083 --- /dev/null +++ b/H316/tests/mdmtest1.cmd @@ -0,0 +1,61 @@ +; TEST1 - send a test modem message + +; Set up the configuration ... +RESET ALL +SET CPU 32K NOHSA DMA=0 DMC EXTINT=16 +SET LPT DISABLED +SET MT DISABLED +SET CLK DISABLED +SET FHD DISABLED +SET DP DISABLED +SET IMP DISABLED +SET RTC DISABLED +SET WDT DISABLED +SET MI1 ENABLED +SET MI2 DISABLED +SET MI3 DISABLED +SET MI4 DISABLED +SET MI5 DISABLED +SET HI1 DISABLED +SET HI2 DISABLED +SET HI3 DISABLED +SET HI4 DISABLED + +; Deposit the test message in memory at 000100..000107 ... +DEPOSIT ALL 0 +DEPOSIT 100 100000 +DEPOSIT 101 011111 +DEPOSIT 102 122222 +DEPOSIT 103 033333 +DEPOSIT 104 144444 +DEPOSIT 105 055555 +DEPOSIT 106 166666 +DEPOSIT 107 077777 + +; Store a little program to set up the DMC and do start modem output .. +DEPOSIT 32 100 +DEPOSIT 33 107 +DEPOSIT -m 10 OCP 0071 +DEPOSIT -m 11 HLT +DEPOSIT P 10 + +; Tell the world ... +echo +echo Here are the DMC pointers before sending - +ex 32:33 +echo +echo And here is the data we're sending - +ex 100:107 + +; Away we go! +echo +echo Starting simulation ... +ATTACH MI1 4431::4432 +go + +; All done... +echo +echo Here are the DMC pointers after sending ... +ex 32:33 + + diff --git a/H316/tests/mdmtest2.cmd b/H316/tests/mdmtest2.cmd new file mode 100644 index 00000000..379aa460 --- /dev/null +++ b/H316/tests/mdmtest2.cmd @@ -0,0 +1,54 @@ +; TEST2 - receive a test modem message + +; Set up the configuration ... +RESET ALL +SET CPU 32K NOHSA DMA=0 DMC EXTINT=16 +SET LPT DISABLED +SET MT DISABLED +SET CLK DISABLED +SET FHD DISABLED +SET DP DISABLED +SET IMP DISABLED +SET RTC DISABLED +SET WDT DISABLED +SET MI1 ENABLED +SET MI2 DISABLED +SET MI3 DISABLED +SET MI4 DISABLED +SET MI5 DISABLED +SET HI1 DISABLED +SET HI2 DISABLED +SET HI3 DISABLED +SET HI4 DISABLED + +; Clear the receiver buffer at 000100 ... +DEPOSIT ALL 0 + +; Store a little program to receive the message ... +DEPOSIT 20 100 +DEPOSIT 21 177 +DEPOSIT -m 10 OCP 0471 +DEPOSIT -m 11 SKS 0271 +DEPOSIT -m 12 JMP 11 +DEPOSIT -m 13 HLT +DEPOSIT P 10 + +; Tell the world ... +echo +echo Here are the DMC pointers before receiving - +ex 20:21 + +; and wait for "GO" ... +echo +echo Starting simulation ... +ATTACH MI1 4432::4431 +go + +; All done ... +echo +echo Here is the data we received - +ex 100:107 +echo +echo And here are the DMC pointers after receiving - +ex 20:21 +echo diff --git a/H316/tests/testrtc.cmd b/H316/tests/testrtc.cmd new file mode 100644 index 00000000..d4f9bc73 --- /dev/null +++ b/H316/tests/testrtc.cmd @@ -0,0 +1,42 @@ +; This is a super simple simh script to test the IMP RTC and verify that it is +; incrementing at the correct 100us interval. It simply waits for the clock +; count to overflow (which takes 65535 * 100us or about 6.5 seconds) and then +; repeats for a total of 10 iterations. If all is well, this loop should take +; pretty close to 65 seconds to complete. +; +; RLA [15-Jun-13] +echo +echo SIMH IMP RTC INTERVAL CALIBRATION TEST + +; Turn on the RTC (this requires extended interrupt support) +set cpu extint=16 +set rtc enabled + +; Turn the clock on (OCP 40 ==> CLKON) ... +d 1000 030040 + +; Loop reading the clock register until it becomes negative ... +d 1001 131040 +d -m 1002 HLT +d -m 1003 SMI +d -m 1004 JMP 1001 + +; Loop reading the clock register until it becomes positive again ... +d 1005 131040 +d -m 1006 HLT +d -m 1007 SPL +d -m 1010 JMP 1005 + +; And repeat the above for ten iterations ... +d -m 1011 IRS 1015 +d -m 1012 JMP 1001 +d -m 1013 HLT +d -m 1014 0 +d -m 1015 177766 + +; That's it... +d p 1000 +echo Start your stopwatch and at the same moment type "GO". +echo The program should halt in exactly 65 seconds ... + + diff --git a/HP2100/hp2100_baci.c b/HP2100/hp2100_baci.c index 063705a6..5018c8f9 100644 --- a/HP2100/hp2100_baci.c +++ b/HP2100/hp2100_baci.c @@ -1,6 +1,6 @@ /* hp2100_baci.c: HP 12966A buffered asynchronous communications interface simulator - Copyright (c) 2007-2012, J. David Bryan + Copyright (c) 2007-2014, J. David Bryan Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,7 +25,10 @@ BACI 12966A BACI card + 24-Dec-14 JDB Added casts for explicit downward conversions + 10-Jan-13 MP Added DEV_MUX and additional DEVICE field values 10-Feb-12 JDB Deprecated DEVNO in favor of SC + Removed DEV_NET to allow restoration of listening port 28-Mar-11 JDB Tidied up signal handling 26-Oct-10 JDB Changed I/O signal handler for revised signal model 25-Nov-08 JDB Revised for new multiplexer library SHOW routines @@ -154,7 +157,6 @@ #include #include "hp2100_defs.h" -#include "sim_sock.h" #include "sim_tmxr.h" @@ -365,7 +367,7 @@ static int32 service_time (uint32 control_word); static void update_status (void); static void master_reset (void); -static uint32 fifo_get (void); +static uint16 fifo_get (void); static void fifo_put (uint8 ch); static void clock_uart (void); @@ -502,11 +504,15 @@ DEVICE baci_dev = { &baci_attach, /* attach routine */ &baci_detach, /* detach routine */ &baci_dib, /* device information block */ - DEV_DEBUG | DEV_DISABLE, /* device flags */ + DEV_DEBUG | DEV_DISABLE | DEV_MUX, /* device flags */ 0, /* debug control flags */ baci_deb, /* debug flag name table */ NULL, /* memory size change routine */ - NULL }; /* logical device name */ + NULL, /* logical device name */ + NULL, /* help routine */ + NULL, /* help attach routine*/ + (void *) &baci_desc /* help context */ + }; /* I/O signal handler. @@ -866,7 +872,8 @@ while (xmit_loop && (baci_uart_thr & IN_VALID)) { /* valid character in UA if ((status == SCPE_OK) && /* transmitted OK? */ DEBUG_PRI (baci_dev, DEB_XFER)) fprintf (sim_deb, ">>BACI xfer: Character %s " - "transmitted from UART\n", fmt_char (baci_uart_tr)); + "transmitted from UART\n", + fmt_char ((uint8) baci_uart_tr)); } } @@ -910,8 +917,11 @@ if (recv_loop && /* ok to process? */ /* Reception */ -while (recv_loop && /* OK to process? */ - (baci_uart_rr = tmxr_getc_ln (&baci_ldsc))) { /* and new character available? */ +while (recv_loop) { /* OK to process? */ + baci_uart_rr = tmxr_getc_ln (&baci_ldsc); /* get a new character */ + + if (baci_uart_rr == 0) /* if there are no more characters available */ + break; /* then quit the reception loop */ if (baci_uart_rr & SCPE_BREAK) { /* break detected? */ baci_status = baci_status | IN_BREAK; /* set break status */ @@ -920,17 +930,17 @@ while (recv_loop && /* OK to process? */ fputs (">>BACI xfer: Break detected\n", sim_deb); } - data_bits = 5 + (baci_cfcw & OUT_CHARSIZE); /* calculate number of data bits */ - data_mask = (1 << data_bits) - 1; /* generate mask for data bits */ - baci_uart_rhr = baci_uart_rr & data_mask; /* mask data into holding register */ - baci_uart_rr = CLEAR_R; /* clear receiver register */ + data_bits = 5 + (baci_cfcw & OUT_CHARSIZE); /* calculate number of data bits */ + data_mask = (1 << data_bits) - 1; /* generate mask for data bits */ + baci_uart_rhr = (uint16) (baci_uart_rr & data_mask); /* mask data into holding register */ + baci_uart_rr = CLEAR_R; /* clear receiver register */ if (DEBUG_PRI (baci_dev, DEB_XFER)) fprintf (sim_deb, ">>BACI xfer: Character %s received by UART\n", fmt_char ((uint8) baci_uart_rhr)); - if (baci_term.flags & UNIT_CAPSLOCK) /* caps lock mode? */ - baci_uart_rhr = toupper (baci_uart_rhr); /* convert to upper case if lower */ + if (baci_term.flags & UNIT_CAPSLOCK) /* caps lock mode? */ + baci_uart_rhr = (uint16) toupper (baci_uart_rhr); /* convert to upper case if lower */ if (baci_cfcw & OUT_ECHO) /* echo wanted? */ tmxr_putc_ln (&baci_ldsc, baci_uart_rhr); /* send it back */ @@ -1314,9 +1324,9 @@ return ticks [GET_BAUDRATE (control_word)]; /* return service time f not 0. */ -static uint32 fifo_get (void) +static uint16 fifo_get (void) { -uint32 data; +uint16 data; data = baci_fifo [baci_fget]; /* get character */ @@ -1326,7 +1336,8 @@ if ((baci_fget != baci_fput) || (baci_fcount >= 128)) { /* FIFO occupied? */ if (DEBUG_PRI (baci_dev, DEB_BUF)) fprintf (sim_deb, ">>BACI buf: Character %s get from FIFO [%d], " - "character counter = %d\n", fmt_char (data), baci_fget, baci_fcount); + "character counter = %d\n", + fmt_char ((uint8) data), baci_fget, baci_fcount); baci_fget = (baci_fget + 1) % FIFO_SIZE; /* bump index modulo array size */ @@ -1497,14 +1508,15 @@ if (baci_uart_clk > 0) { /* transfer in progress? ((baci_cfcw & OUT_PARITY) != 0) + /* plus parity bit if used */ ((baci_cfcw & OUT_STBITS) != 0); /* plus extra stop bit if used */ - baci_uart_rhr = baci_uart_rr >> (16 - uart_bits); /* position data to right align */ - baci_uart_rr = CLEAR_R; /* clear receiver register */ + baci_uart_rhr = (uint16) (baci_uart_rr >> (16 - uart_bits)); /* position data to right align */ + baci_uart_rr = CLEAR_R; /* clear receiver register */ if (DEBUG_PRI (baci_dev, DEB_XFER)) fprintf (sim_deb, ">>BACI xfer: UART receiver = %06o (%s)\n", - baci_uart_rhr, fmt_char (baci_uart_rhr & data_mask)); + baci_uart_rhr, + fmt_char ((uint8) (baci_uart_rhr & data_mask))); - fifo_put (baci_uart_rhr & data_mask); /* put data in FIFO */ + fifo_put ((uint8) (baci_uart_rhr & data_mask)); /* put data in FIFO */ update_status (); /* update FIFO status */ if (baci_cfcw & OUT_PARITY) { /* parity present? */ @@ -1563,7 +1575,8 @@ if ((baci_uart_clk == 0) && /* start of transfer? */ if (DEBUG_PRI (baci_dev, DEB_XFER)) fprintf (sim_deb, ">>BACI xfer: UART transmitter = %06o (%s), " "clock count = %d\n", baci_uart_tr & DMASK, - fmt_char (baci_uart_thr & data_mask), baci_uart_clk); + fmt_char ((uint8) (baci_uart_thr & data_mask)), + baci_uart_clk); } else { diff --git a/HP2100/hp2100_bugfixes.txt b/HP2100/hp2100_bugfixes.txt index 80793696..4dd55c48 100644 --- a/HP2100/hp2100_bugfixes.txt +++ b/HP2100/hp2100_bugfixes.txt @@ -1,6 +1,6 @@ HP 2100 SIMULATOR BUG FIX WRITEUPS ================================== - Last update: 2012-03-25 + Last update: 2015-01-03 1. PROBLEM: Booting from magnetic tape reports "HALT instruction, P: 77756 @@ -6280,3 +6280,512 @@ (hp2100_mt.c). STATUS: Fixed in version 3.9-0. + + + +247. PROBLEM: The ICD disc read end-of-track delay is not optimal. + + VERSION: 3.9-0 + + OBSERVATION: To avoid End of Cylinder errors when reading the last sector + of a track, the ICD controller must delay more than the usual intersector + time to allow the OS driver to send an Untalk if a read is to be + terminated. Currently, the longer delay is used if an end-of-cylinder + condition is present. However, the delay is needed only if the resulting + seek attempt would cause an error if the read is continued; the normal + delay should be used if the seek is permitted and would succeed. + + Also, if the host does send an Untalk during this time, the longer delay + should be cancelled, and command termination should be scheduled for + immediate processing. + + CAUSE: Suboptimal implementation. + + RESOLUTION: Modify "end_read" (hp_disclib.c) to use the longer time only + if the seek would fail, and modify "complete_read" (hp2100_di_da.c) to + cancel the intersector delay and schedule the completion phase immediately. + + STATUS: Fixed in version 4.0-0. + + + +248. PROBLEM: Calling a VMA routine from a non-VMA program does not MP abort. + + VERSION: 3.9-0 + + OBSERVATION: If a virtual memory routine, such as .LBP, is called from a + non-VMA program, it should be aborted with a memory protect error. + Instead, a dynamic mapping error occurs instead: + + ASMB,R + NAM MAPPR + EXT EXEC,.LBP + START CLA + CLB + JSB .LBP + NOP + JSB EXEC + DEF *+2 + DEF *+1 + DEC 6 + END START + + DM VIOL = 160377 + DM INST = 105257 + ABE 0 0 0 + XYO 0 0 0 + DM MAPPR 2014 + MAPPR ABORTED + + CAUSE: The page mapping routine, "cpu_vma_mapte", returns TRUE if the page + table is set up and valid and FALSE if not. If a program is not a VMA + program, then it has no page table, but "cpu_vma_mapte" is returning TRUE + erroneously. That results in a DM error when the invalid page entry is + used. + + The microcode explicitly tests for a non-VMA program, i.e., one with no ID + extension, and generates an MP error in this case. + + RESOLUTION: Modify "cpu_vma_mapte" (hp2100_cpu5.c) to return FALSE if + called for a non-VMA program. + + STATUS: Fixed in version 4.0-0. + + + +249. PROBLEM: RESTORing a previously SAVEd session fails if the 12792C + multiplexer is attached. + + VERSION: 3.9-0 + + OBSERVATION: If the MPX device has a listening port attached when a + session is saved, attempting to restore that session results in a "Unit not + attachable" error. + + CAUSE: The MPX attach routine only allows attachment to unit 0, i.e., + ATTACH MPX , but the actual attachment is made to the Telnet poll + unit (unit 9). As SAVE finds the port attached to unit 9, RESTORE attempts + to reattach it to unit 9. + + RESOLUTION: Modify "mpx_attach" (hp2100_mpx.c) to allow attachment to unit + 9 only during a RESTORE. + + STATUS: Fixed in version 4.0-0. + + + +250. PROBLEM: DEASSIGNing the TBG device generates a debug warning. + + VERSION: 3.9-0 + + OBSERVATION: When running the simulator under a debugger, entering the + command DEASSIGN TBG prints "warning: Invalid Address specified to + RtlFreeHeap." + + CAUSE: The TBG logical name is specified statically in the DEVICE + structure, but "deassign_device" calls "free" on the pointer. The + developer's manual does not state that the logical name must be dynamically + allocated, but deassigning assumes that it was. + + RESOLUTION: Modify "clk_reset" (hp2100_stddev.c) to allocate the logical + name during a power-on reset. + + STATUS: Fixed in version 4.0-0. + + + +251. PROBLEM: Constants required for exdep_cmd and brk_cmd aren't in scp.h. + + VERSION: 3.9-0 + + OBSERVATION: The scp.h header file exports the exdep_cmd and brk_cmd + functions, but the constants that must be passed in the "flag" parameters + for proper operation are not present. The run_cmd function also requires + constants for the "flag" parameter, but these are present. + + CAUSE: Oversight. + + RESOLUTION: Move the EX_D, EX_E, EX_I, SSH_ST, SSH_CL, and SSH_SH + constants from scp.c to scp.h. + + STATUS: Fixed in version 4.0-0. + + + +252. PROBLEM: Stop calls VM-provided address printer for PC without REG_VMAD. + + VERSION: 3.9-0 + + OBSERVATION: For a simulator stop, sim_vm_fprint_addr (if defined) is + called to print the value of the program counter, regardless of whether or + not the register was defined with REG_VMAD. However, displaying the PC + value with "examine" calls sim_vm_fprint_addr only if the REG_VMAD flag is + present. The displayed value of the PC should be the same in both cases. + + CAUSE: The call to sim_vm_fprint_addr in fprint_stopped_gen is not + conditional on the PC register having the REG_VMAD flag. + + RESOLUTION: Modify "fprint_stopped_gen" (scp.c) to require REG_VMAD before + calling the VM-specific address printer for the program counter value. + + STATUS: Fixed in version 4.0-0. + + + +253. PROBLEM: Cannot show radix, etc. for a device that has no modifiers. + + VERSION: 3.9-0 + + OBSERVATION: The default data radix for a device may be set with the SET + OCT|DEC|HEX command. However, if the device does not have a modifier + table, SHOW RADIX is rejected with "No settable parameters". + + The same problem occurs for SHOW DEBUG and SHOW NAMES. For a + device that provides debug printouts, SHOW MOD will list "DEBUG, + NODEBUG" among the modifiers, and the SHOW DEBUG command will display + the current debug status. However, if the device does not contain a + modifier table, SHOW MOD and SHOW DEBUG will report "No + settable parameters", even though SET DEBUG is accepted and works as + expected. For such a device, SHOW MOD will show "DEBUG, NODEBUG" as + acceptable modifiers. + + CAUSE: The "show_cmd_fi" routine checks for a modifier table and returns + an error without checking for global actions. + + RESOLUTION: Modify "show_cmd_fi" (scp.c) to continue to process global + actions if the modifier table is not defined. + + STATUS: Fixed in version 4.0-0. + + + +254. PROBLEM: SET and SHOW responses for invalid entry are inconsistent. + + VERSION: 3.9-0 + + OBSERVATION: Entering SET where is not defined in the + device's modifier table displays "Non-existent parameter." Entering SHOW + with the same parameters displays "Invalid argument." + + Similarly, entering SET DEBUG for a device that does not have + debugging capability displays "Command not allowed." Entering SHOW with + the same parameters displays nothing. + + In both cases, the messages displayed should be the same for the same + error. + + CAUSE: Oversight. + + RESOLUTION: Modify "show_cmd_fi" (scp.c) to return the same status codes + as "set_cmd" does. + + STATUS: Fixed in version 4.0-0. + + + +255. ENHANCEMENT: Add a "-N" (new file) option to the SET CONSOLE LOG and SET + CONSOLE DEBUG commands. + + VERSION: 3.9-0 + + OBSERVATION: These commands normally append to their respective log files. + If the user wants to recreate the log file instead, it must be deleted + first with OS-specific commands. Adding a "-N" option to perform the + delete removes commands dependent on a specific OS. + + RESOLUTION: Modify "sim_set_logon" and "sim_set_debon" (sim_console.c) to + check for a "-N" option and to open for writing instead of appending if + detected. + + STATUS: Fixed in version 4.0-0. + + + +256. ENHANCEMENT: Add tape runaway support to the simulator tape library. + + VERSION: 3.9-0 + + OBSERVATION: The ANSI specifications for NRZI, PE, and GCR tape recording + mandate a maximum length of 25 feet for erase gaps. Currently, an erase + gap of any length is ignored when reading or spacing. To allow detection + of non-compliant tape images, the simulator tape library is enhanced to + halt positioning and return tape runaway status if a gap of 25 feet or more + is encountered. + + Runaway detection is enabled by calling the tape library to set the tape + density in bits per inch. If this call is not made, erase gaps present in + a tape image are effectively ignored. Also, with the addition of a + separate "set density" call, it is no longer necessary to supply the + density when writing erase gaps. + + RESOLUTION: Modify "sim_tape_rdlntf" and "sim_tape_rdlntr" (sim_tape.c) to + detect tape runaway, and add a new MTSE_RUNAWAY status to sim_tape.h. Add + new "sim_tape_set_dens" and "sim_tape_show_dens" functions to set and show + the bits per inch for a unit, respectively, and eliminate the "bpi" + parameter to "sim_tape_wrgap" in preference to using the density + established by a previous "sim_tape_set_dens" call. Add named constants + to "sim_tape.h" that specify the density. + + STATUS: Fixed in version 4.0-0. + + + +257. ENHANCEMENT: Improve performance when reading or spacing over erase gaps. + + VERSION: 3.9-0 + + OBSERVATION: Performance when reading or spacing over erase gaps is poor, + especially in the reverse direction. Currently, each 4-byte gap marker is + read individually, and in the reverse direction, each read is preceded by a + seek to move the file pointer backward. This combination causes stream + cache invalidation and a physical disc access for each gap marker. As a + single gap consists of over 1000 markers, performance is far worse than if + a gap was read as a block. + + RESOLUTION: Modify "sim_tape_rdlntf" and "sim_tape_rdlntr" (sim_tape.c) to + buffer reads of gap markers. Using a 128-element buffer, performance + improves about thirty-fold. + + STATUS: Fixed in version 4.0-0. + + + +258. PROBLEM: Writing an end-of-medium positions the tape image after the mark. + + VERSION: 3.9-0 + + OBSERVATION: The "sim_tape_wreom" simulator tape library function writes + an end-of-medium marker on the tape image. The intent is to erase the + remainder of the tape. The "SIMH Magtape Representation and Handling" + document states that the tape position is not updated by this function. + However, the function leaves the tape positioned after the marker. + + A subsequent read would stop at the EOM marker. However, writing a new + marker over that one would then allow reading of the data following the EOM + that supposedly had been erased by the original "sim_tape_wreom" call. + + CAUSE: The tape position is updated by the internal "sim_tape_wrdata" call + that is used to write the EOM marker, but it is not reset afterward by the + function. + + RESOLUTION: Modify "sim_tape_wreom" (sim_tape.c) to reset the tape + position to point at the EOM marker before returning. This prevents + reading past an EOM marker, and a subsequent write will overwrite the + marker rather than embed it between data records. + + STATUS: Fixed in version 4.0-0. + + + +259. PROBLEM: Reading through an erase gap in reverse may return EOM status. + + VERSION: 3.9-0 + + OBSERVATION: A reverse read or spacing operation through an erase gap may + return end-of-medium status. Reading or spacing forward through the same + gap works properly. + + CAUSE: Writing an erase gap over existing records may produce a gap that + is longer than requested. This occurs when truncating the last record to + be overlaid by the gap would leave a record that is shorter than the + minimum size allowed (eight bytes for the length words plus two bytes for + the data). In this case, the gap is lengthened to overlay the entire + record. If the new gap size is not evenly divisible by four, a half-gap is + metadata marker of value 0xFFFF added to the beginning of the gap. + + If a gap that begins with a half-gap marker is written immediately after + a previous gap, the "seam" between gaps will contain the bytes FE FF FF FF + ( FF FF ) FE FF FF FF.... Reading forward across this seam will yield a + metadata value of 0xFFFEFFFF, which is recognized and handled by seeking + two bytes back to resynchronize reading. However, reading in reverse will + yield the value 0xFFFFFFFF, which is interpreted as end-of-medium. + + RESOLUTION: Modify "sim_tape_rdlntr" (sim_tape.c) to recognize 0xFFFFFFFF + as a half-gap marker and resynchronize in response. End of medium cannot + occur when reading in reverse, as it is impossible to position the tape + image beyond an EOM marker. Therefore, any 0xFFFFFFFF value encountered + must be a half-gap "seam" originating as above. + + STATUS: Fixed in version 4.0-0. + + + +260. PROBLEM: sim_tape_wrgap fails when format is changed from SIMH format. + + VERSION: 3.9-0 + + OBSERVATION: The HP 2100 magnetic tape simulator supports erase gaps and + calls sim_tape_wrgap when commanded to write a gap. However, if a tape + format other than SIMH format is selected, the call fails with MTSE_FMT. + + CAUSE: Erase gaps are not supported in formats other than SIMH, but the + call should not fail. Instead, the call should be a "no-operation" if the + underlying format does not support gaps. + + RESOLUTION: Modify "sim_tape_wrgap" (sim_tape.c) to return MTSE_OK with no + action performed if a tape format other than SIMH is selected. + + STATUS: Fixed in version 4.0-0. + + + +261. PROBLEM: The magnetic tape format of an attached unit may be changed. + + VERSION: 3.9-0 + + OBSERVATION: The magnetic tape library supports several tape image + formats. The format to use may be specified either by an "ATTACH -F" + command or by a "SET FORMAT" command. The latter calls the + "sim_tape_set_fmt" function, which allows the format of a file currently + attached to be changed. However, the format is an intrinsic property of + the tape image file, so changing it once the file has been attached makes + no sense. + + CAUSE: Oversight. + + RESOLUTION: Modify "sim_tape_set_fmt" (sim_tape.c) to return an error + (SCPE_ALATT, "Unit already attached") if the unit is attached. + + STATUS: Fixed in version 4.0-0. + + + +262. ENHANCEMENT: Add CRCC and LRCC support to the HP 2100 MS simulation. + + VERSION: 3.9-0 + + OBSERVATION: The HP 2100 MS device simulates the HP 7970 B/E magnetic tape + drives. The 7970B uses NRZI format, and its associated controller supports + returning the cyclic redundancy check character and longitudinal redundancy + check character (CRCC and LRCC) to the CPU. Typically, these are used only + by the controller diagnostic, but support is easy to add. + + RESOLUTION: Modify "hp2100_ms.c" to add a function that calculates CRCC + and LRCC for reads and writes, and call that function when the CPU requests + that the controller deliver the values. + + STATUS: Fixed in version 4.0-0. + + + +263. ENHANCEMENT: Allow the VM to print simulator stop message information in + lieu of, or in addition to, the default message. + + VERSION: 3.9-0 + + OBSERVATION: The current implementation of "run_cmd" in scp.c calls + "fprint_stopped_gen" (via "fprint_stopped") to print the message associated + with the "sim_instr" return status. Messages associated with VM stops must + be provided to the SCP via the "sim_stop_messages" array. + + "fprint_stopped_gen" prints the status message in a rigid format: the + message string, a comma, the program counter register name, a colon, the + current PC value, and the instruction at that address in symbolic format. + For example: + + HALT instruction, P: 24713 (LDA 1) + + Only the message string is under the control of the VM. If additional + information is needed, it can only be added before the first comma. + + The HP2100 simulator does this for halt instructions, which contain device + select code and flag hold/clear bit fields that, in practice, are used to + communicate to the operator the significance of the particular halt + encountered, rather than to affect the device interface: + + HALT instruction 102077, P: 24713 (LDA 1) + + To implement this, the simulator must define the message as a variable and + then copy the formatted octal value into the buffer at the appropriate + location before returning from "sim_instr". + + However, if the VM wants to display a different register value, e.g.: + + Self test #13 complete, STAT: 000020 + + ...this cannot be done without also displaying the program counter, which + may be irrelevant for the given stop condition. + + RESOLUTION: Modify "fprint_stopped_gen" (scp.c) to check a VM-specific + simulation stop printer pointer ("sim_vm_fprint_stopped") that is + initialized to NULL and can be overridden by the VM, and, if overridden, + call it after printing the message string and before printing the program + counter. If the VM printer returns TRUE, print the comma and the program + counter as before. If the VM routine returns FALSE, print just the + terminating newline. + + STATUS: Fixed in version 4.0-0. + + + +264. ENHANCEMENT: Indicate that "examine" is being called for a simulator stop. + + VERSION: 3.9-0 + + OBSERVATION: As part of the simulator stop message, the fprint_stopped_gen + routine prints the instruction pointed to by the program counter. In + addition to the "M" (mnemonic) switch, it passes the SIM_SW_STOP flag to + the fprint_sym routine to indicate that it is being called for a simulator + stop. This allows the VM-defined routine to take any action specifically + appropriate to the stop. + + To get the instruction value, fprint_stopped_gen calls the CPU's "examine" + routine and passes the program counter value as the address. However, + interpretation of addresses may differ, depending on context. For example, + a given address may be relative to a code, data, or stack space pointer. + To attempt to address this, the "examine" call includes the "V" (virtual) + switch. However, "virtual" (and the associated "-v" command line switch) + may have a different meaning assigned by a given VM. What is needed is an + unequivocal indication that a machine instruction value is being retrieved. + + RESOLUTION: Modify "fprint_stopped_gen" (scp.c) to pass SIM_SW_STOP to + "examine" as well as "fprint_sym", so that these routines have unambiguous + indications that they are being called in the context of a simulator stop. + + STATUS: Fixed in version 4.0-0. + + + +265. PROBLEM: Compiling the HP simulator for 64-bit addressing generates + warnings. + + VERSION: 3.9-0 + + OBSERVATION: Compiling the simulator and defining USE_INT64 and USE_ADDR64 + with implicit conversion warnings enabled reveals a number of places where + assumptions were made that addresses would always be 32 bits. This is a + reasonable assumption, as there are no devices (CPU or peripherals) that + can handle gigabyte addressing. Still, many of these assumptions are not + necessary, and some future peripheral simulator may exceed this limit. + + CAUSE: Future expansion to 64-bit addressing was not envisioned. + + RESOLUTION: Modify source files to ensure that "t_addr" and "t_value" + types are used instead of "uint32" and "int32" types where addressing and + data values may be 64 bits. Also ensure that valid conversions to smaller + sizes use explicit casts. + + STATUS: Fixed in version 4.0-0. + + + +266. PROBLEM: BOOT devices require a duplicate S-register declaration. + + VERSION: 3.9-0 + + OBSERVATION: All of the peripheral devices that support the BOOT command + set the select code and other parameters into the S register during the + boot process. This direct register access requires an external declaration + that duplicates the one in the full CPU declarations file (hp2100_cpu.h). + A better method that avoids the duplicate declaration would be for the + "ibl_copy" routine to modify the S register on behalf of the caller. + + CAUSE: Poor original implementation. + + RESOLUTION: Modify "ibl_copy" (hp2100_cpu.c) to take two additional + parameters that clear and set bits, respectively, in the S register on + behalf of the caller. Modify the boot routines for the CPU, DA, DP, DQ, + DR, DS, IPL, MS, and PTR devices to use the new parameters instead of + modifying the S register directly. + + STATUS: Fixed in version 4.0-0. diff --git a/HP2100/hp2100_cpu.c b/HP2100/hp2100_cpu.c index 7ccb3c4e..b09d27a3 100644 --- a/HP2100/hp2100_cpu.c +++ b/HP2100/hp2100_cpu.c @@ -1,4034 +1,4029 @@ -/* hp2100_cpu.c: HP 21xx/1000 CPU simulator - - Copyright (c) 1993-2012, Robert M. Supnik - - 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 - ROBERT M SUPNIK 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 Robert M Supnik shall not be - used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from Robert M Supnik. - - CPU 2114C/2115A/2116C/2100A/1000-M/E/F central processing unit - 12731A memory expansion module - MP 12581A/12892B memory protect - DMA1,DMA2 12607B/12578A/12895A direct memory access controller - DCPC1,DCPC2 12897B dual channel port controller - - 13-Jan-12 JDB Minor speedup in "is_mapped" - Added casts to cpu_mod, dmasio, dmapio, cpu_reset, dma_reset - 07-Apr-11 JDB Fixed I/O return status bug for DMA cycles - Failed I/O cycles now stop on failing instruction - 28-Mar-11 JDB Tidied up signal handling - 29-Oct-10 JDB Revised DMA for new multi-card paradigm - Consolidated DMA reset routines - DMA channels renamed from 0,1 to 1,2 to match documentation - 27-Oct-10 JDB Changed I/O instructions, handlers, and DMA for revised signal model - Changed I/O dispatch table to use DIB pointers - 19-Oct-10 JDB Removed DMA latency counter - 13-Oct-10 JDB Fixed DMA requests to enable stealing every cycle - Fixed DMA priority for channel 1 over channel 2 - Corrected comments for "cpu_set_idle" - 30-Sep-08 JDB Breakpoints on interrupt trap cells now work - 05-Sep-08 JDB VIS and IOP are now mutually exclusive on 1000-F - 11-Aug-08 JDB Removed A/B shadow register variables - 07-Aug-08 JDB Moved hp_setdev, hp_showdev to hp2100_sys.c - Moved non-existent memory checks to WritePW - 05-Aug-08 JDB Fixed mp_dms_jmp to accept lower bound, check write protection - 30-Jul-08 JDB Corrected DMS violation register set conditions - Refefined ABORT to pass address, moved def to hp2100_cpu.h - Combined dms and dms_io routines - 29-Jul-08 JDB JSB to 0/1 with W5 out and fence = 0 erroneously causes MP abort - 11-Jul-08 JDB Unified I/O slot dispatch by adding DIBs for CPU, MP, and DMA - 26-Jun-08 JDB Rewrote device I/O to model backplane signals - EDT no longer passes DMA channel - 30-Apr-08 JDB Enabled SIGNAL instructions, SIG debug flag - 28-Apr-08 JDB Added SET CPU IDLE/NOIDLE, idle detection for DOS/RTE - 24-Apr-08 JDB Fixed single stepping through interrupts - 20-Apr-08 JDB Enabled EMA and VIS, added EMA, VIS, and SIGNAL debug flags - 03-Dec-07 JDB Memory ex/dep and bkpt type default to current map mode - 26-Nov-07 JDB Added SET CPU DEBUG and OS/VMA flags, enabled OS/VMA - 15-Nov-07 JDB Corrected MP W5 (JSB) jumper action, SET/SHOW reversal, - mp_mevff clear on interrupt with I/O instruction in trap cell - 04-Nov-07 JDB Removed DBI support from 1000-M (was temporary for RTE-6/VM) - 28-Apr-07 RMS Removed clock initialization - 02-Mar-07 JDB EDT passes input flag and DMA channel in dat parameter - 11-Jan-07 JDB Added 12578A DMA byte packing - 28-Dec-06 JDB CLC 0 now sends CRS instead of CLC to devices - 26-Dec-06 JDB Fixed improper IRQ deferral for 21xx CPUs - Fixed improper interrupt servicing in resolve - 21-Dec-06 JDB Added 21xx loader enable/disable support - 16-Dec-06 JDB Added 2114 and 2115 CPU options. - Added support for 12607B (2114) and 12578A (2115/6) DMA - 01-Dec-06 JDB Added 1000-F CPU option (requires HAVE_INT64) - SHOW CPU displays 1000-M/E instead of 21MX-M/E - 16-Oct-06 JDB Moved ReadF to hp2100_cpu1.c - 12-Oct-06 JDB Fixed INDMAX off-by-one error in resolve - 26-Sep-06 JDB Added iotrap parameter to UIG dispatchers for RTE microcode - 12-Sep-06 JDB iogrp returns NOTE_IOG to recalc interrupts - resolve returns NOTE_INDINT to service held-off interrupt - 16-Aug-06 JDB Added support for future microcode options, future F-Series - 09-Aug-06 JDB Added double integer microcode, 1000-M/E synonyms - Enhanced CPU option validity checking - Added DCPC as a synonym for DMA for 21MX simulations - 26-Dec-05 JDB Improved reporting in dev_conflict - 22-Sep-05 RMS Fixed declarations (from Sterling Garwood) - 21-Jan-05 JDB Reorganized CPU option flags - 15-Jan-05 RMS Split out EAU and MAC instructions - 26-Dec-04 RMS DMA reset doesn't clear alternate CTL flop (from Dave Bryan) - DMA reset shouldn't clear control words (from Dave Bryan) - Alternate CTL flop not visible as register (from Dave Bryan) - Fixed CBS, SBS, TBS to perform virtual reads - Separated A/B from M[0/1] for DMA IO (from Dave Bryan) - Fixed bug in JPY (from Dave Bryan) - 25-Dec-04 JDB Added SET CPU 21MX-M, 21MX-E (21MX defaults to MX-E) - TIMER/EXECUTE/DIAG instructions disabled for 21MX-M - T-register reflects changes in M-register when halted - 25-Sep-04 JDB Moved MP into its own device; added MP option jumpers - Modified DMA to allow disabling - Modified SET CPU 2100/2116 to truncate memory > 32K - Added -F switch to SET CPU to force memory truncation - Fixed S-register behavior on 2116 - Fixed LIx/MIx behavior for DMA on 2116 and 2100 - Fixed LIx/MIx behavior for empty I/O card slots - Modified WRU to be REG_HRO - Added BRK and DEL to save console settings - Fixed use of "unsigned int16" in cpu_reset - Modified memory size routine to return SCPE_INCOMP if - memory size truncation declined - 20-Jul-04 RMS Fixed bug in breakpoint test (reported by Dave Bryan) - Back up PC on instruction errors (from Dave Bryan) - 14-May-04 RMS Fixed bugs and added features from Dave Bryan - - SBT increments B after store - - DMS console map must check dms_enb - - SFS x,C and SFC x,C work - - MP violation clears automatically on interrupt - - SFS/SFC 5 is not gated by protection enabled - - DMS enable does not disable mem prot checks - - DMS status inconsistent at simulator halt - - Examine/deposit are checking wrong addresses - - Physical addresses are 20b not 15b - - Revised DMS to use memory rather than internal format - - Added instruction printout to HALT message - - Added M and T internal registers - - Added N, S, and U breakpoints - Revised IBL facility to conform to microcode - Added DMA EDT I/O pseudo-opcode - Separated DMA SRQ (service request) from FLG - 12-Mar-03 RMS Added logical name support - 02-Feb-03 RMS Fixed last cycle bug in DMA output (found by Mike Gemeny) - 22-Nov-02 RMS Added 21MX IOP support - 24-Oct-02 RMS Fixed bugs in IOP and extended instructions - Fixed bugs in memory protection and DMS - Added clock calibration - 25-Sep-02 RMS Fixed bug in DMS decode (found by Robert Alan Byer) - 26-Jul-02 RMS Restructured extended instructions, added IOP support - 22-Mar-02 RMS Changed to allocate memory array dynamically - 11-Mar-02 RMS Cleaned up setjmp/auto variable interaction - 17-Feb-02 RMS Added DMS support - Fixed bugs in extended instructions - 03-Feb-02 RMS Added terminal multiplexor support - Changed PCQ macro to use unmodified PC - Fixed flop restore logic (found by Bill McDermith) - Fixed SZx,SLx,RSS bug (found by Bill McDermith) - Added floating point support - 16-Jan-02 RMS Added additional device support - 07-Jan-02 RMS Fixed DMA register tables (found by Bill McDermith) - 07-Dec-01 RMS Revised to use breakpoint package - 03-Dec-01 RMS Added extended SET/SHOW support - 10-Aug-01 RMS Removed register in declarations - 26-Nov-00 RMS Fixed bug in dual device number routine - 21-Nov-00 RMS Fixed bug in reset routine - 15-Oct-00 RMS Added dynamic device number support - - References: - - 2100A Computer Reference Manual (02100-90001, Dec-1971) - - Model 2100A Computer Installation and Maintenance Manual - (02100-90002, Aug-1972) - - HP 1000 M/E/F-Series Computers Technical Reference Handbook - (5955-0282, Mar-1980) - - HP 1000 M/E/F-Series Computers Engineering and Reference Documentation - (92851-90001, Mar-1981) - - HP 1000 M/E/F-Series Computers I/O Interfacing Guide - (02109-90006, Sep-1980) - - 12607A Direct Memory Access Operating and Service Manual - (12607-90002, Jan-1970) - - 12578A/12578A-01 Direct Memory Access Operating and Service Manual - (12578-9001, Mar-1972) - - 12892B Memory Protect Installation Manual (12892-90007, Jun-1978) - - - The register state for the HP 2116 CPU is: - - AR<15:0> A register - addressable as location 0 - BR<15:0> B register - addressable as location 1 - PC<14:0> P register - program counter - SR<15:0> S register - switch register - MR<14:0> M register - memory address - TR<15:0> T register - memory data - E extend flag (carry out) - O overflow flag - - The 2100 adds memory protection logic: - - mp_fence<14:0> memory fence register - mp_viol<15:0> memory protection violation register (F register) - - The 21MX adds a pair of index registers and memory expansion logic: - - XR<15:0> X register - YR<15:0> Y register - dms_sr<15:0> dynamic memory system status register - dms_vr<15:0> dynamic memory system violation register - - The original HP 2116 has four instruction formats: memory reference, - shift, alter/skip, and I/O. The HP 2100 added extended memory reference - and extended arithmetic. The HP21MX added extended byte, bit, and word - instructions as well as extended memory. - - The memory reference format is: - - 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - |in| op |cp| offset | memory reference - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - - <14:11> mnemonic action - - 0010 AND A = A & M[MA] - 0011 JSB M[MA] = P, P = MA + 1 - 0100 XOR A = A ^ M[MA] - 0101 JMP P = MA - 0110 IOR A = A | M[MA] - 0111 ISZ M[MA] = M[MA] + 1, skip if M[MA] == 0 - 1000 ADA A = A + M[MA] - 1001 ADB B = B + M[MA] - 1010 CPA skip if A != M[MA] - 1011 CPB skip if B != M[MA] - 1100 LDA A = M[MA] - 1101 LDB B = M[MA] - 1110 STA M[MA] = A - 1111 STB M[MA] = B - - <15,10> mode action - - 0,0 page zero direct MA = IR<9:0> - 0,1 current page direct MA = PC<14:0>'IR,9:0> - 1,0 page zero indirect MA = M[IR<9:0>] - 1,1 current page indirect MA = M[PC<14:10>'IR<9:0>] - - Memory reference instructions can access an address space of 32K words. - An instruction can directly reference the first 1024 words of memory - (called page zero), as well as 1024 words of the current page; it can - indirectly access all 32K. - - The shift format is: - - 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - | 0 0 0 0|ab| 0|s1| op1 |ce|s2|sl| op2 | shift - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - | | \---+---/ | | | \---+---/ - | | | | | | | - | | | | | | +---- shift 2 opcode - | | | | | +---------- skip if low bit == 0 - | | | | +------------- shift 2 enable - | | | +---------------- clear Extend - | | +---------------------- shift 1 opcode - | +---------------------------- shift 1 enable - +---------------------------------- A/B select - - The alter/skip format is: - - 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - | 0 0 0 0|ab| 1|regop| e op|se|ss|sl|in|sz|rs| alter/skip - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - | \-+-/ \-+-/ | | | | | | - | | | | | | | | +- reverse skip sense - | | | | | | | +---- skip if register == 0 - | | | | | | +------- increment register - | | | | | +---------- skip if low bit == 0 - | | | | +------------- skip if sign bit == 0 - | | | +---------------- skip if Extend == 0 - | | +--------------------- clr/com/set Extend - | +--------------------------- clr/com/set register - +---------------------------------- A/B select - - The I/O transfer format is: - - 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - | 1 0 0 0|ab| 1|hc| opcode | device | I/O transfer - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - | | \---+---/\-------+-------/ - | | | | - | | | +--------- device select - | | +---------------------- opcode - | +---------------------------- hold/clear flag - +---------------------------------- A/B select - - The IO transfer instruction controls the specified device. - Depending on the opcode, the instruction may set or clear - the device flag, start or stop I/O, or read or write data. - - The 2100 added an extended memory reference instruction; - the 21MX added extended arithmetic, operate, byte, word, - and bit instructions. Note that the HP 21xx is, despite - the right-to-left bit numbering, a big endian system. - Bits <15:8> are byte 0, and bits <7:0> are byte 1. - - - The extended memory reference format (HP 2100) is: - - 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - | 1| 0 0 0|op| 0| opcode | extended mem ref - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - |in| operand address | - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - - The extended arithmetic format (HP 2100) is: - - 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - | 1| 0 0 0 0 0|dr| 0 0| opcode |shift count| extended arithmetic - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - - The extended operate format (HP 21MX) is: - - 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - | 1| 0 0 0|op| 0| 1 1 1 1 1| opcode | extended operate - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - - The extended byte and word format (HP 21MX) is: - - 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - | 1| 0 0 0 1 0 1 1 1 1 1 1| opcode | extended byte/word - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - |in| operand address | - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0| - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - - The extended bit operate format (HP 21MX) is: - - 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - | 1| 0 0 0 1 0 1 1 1 1 1 1 1| opcode | extended bit operate - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - |in| operand address | - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - |in| operand address | - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - - General notes: - - 1. Reasons to stop. The simulator can be stopped by: - - HALT instruction - breakpoint encountered - infinite indirection loop - unimplemented instruction and stop_inst flag set - unknown I/O device and stop_dev flag set - I/O error in I/O simulator - - 2. Interrupts. I/O devices are modelled by substituting software states for - I/O backplane signals. Signals generated by I/O instructions and DMA - cycles are dispatched to the target device for action. Backplane signals - are processed sequentially, except for the "clear flag" signal, which may - be generated in parallel with another signal. For example, the "STC sc,C" - instruction generates the "set control" and the "clear flag" signals - concurrently. - - CPU interrupt signals are modelled as three parallel arrays: - - - device request priority as bit vector dev_prl [2] [31..0] - - device interrupt requests as bit vector dev_irq [2] [31..0] - - device service requests as bit vector dev_srq [2] [31..0] - - Each array forms a 64-bit vector, with bits 0-31 of the first element - corresponding to select codes 00-37 octal, and bits 0-31 of the second - element corresponding to select codes 40-77 octal. - - The HP 2100 interrupt structure is based on the PRH, PRL, IRQ, and IAK - signals. PRH indicates that no higher-priority device is interrupting. - PRL indicates to lower-priority devices that a given device is not - interrupting. IRQ indicates that a given device is requesting an - interrupt. IAK indicates that the given device's interrupt request is - being acknowledged. - - PRH and PRL form a hardware priority chain that extends from interface to - interface on the backplane. We model just PRL, as PRH is calculated from - the PRLs of higher-priority devices. - - Typical I/O devices have a flag, flag buffer, and control flip-flop. If a - device's flag, flag buffer, and control bits are set, and the device is - the highest priority on the interrupt chain, it requests an interrupt by - asserting IRQ. When the interrupt is acknowledged with IAK, the flag - buffer is cleared, preventing further interrupt requests from that device. - The combination of flag and control set blocks interrupts from lower - priority devices. - - Service requests are used to trigger the DMA service logic. Setting the - device flag typically also sets SRQ, although SRQ may be calculated - independently. - - 3. Non-existent memory. On the HP 2100, reads to non-existent memory - return zero, and writes are ignored. In the simulator, the - largest possible memory is instantiated and initialized to zero. - Thus, only writes need be checked against memory size. - - On the 21xx machines, doing SET CPU LOADERDISABLE decreases available - memory size by 64 words. - - 4. Adding I/O devices. These modules must be modified: - - hp2100_defs.h add interrupt request definition - hp2100_sys.c add sim_devices table entry - - 5. Instruction interruptibility. The simulator is fast enough, compared - to the run-time of the longest instructions, for interruptibility not - to matter. But the HP diagnostics explicitly test interruptibility in - EIS and DMS instructions, and long indirect address chains. Accordingly, - the simulator does "just enough" to pass these tests. In particular, if - an interrupt is pending but deferred at the beginning of an interruptible - instruction, the interrupt is taken at the appropriate point; but there - is no testing for new interrupts during execution (that is, the event - timer is not called). - - 6. Interrupt deferral. At instruction fetch time, a pending interrupt - request will be deferred if the previous instruction was a JMP indirect, - JSB indirect, STC, CLC, STF, CLF, or was executing from an interrupt trap - cell. In addition, the following instructions will cause deferral on the - 1000 series: SFS, SFC, JRS, DJP, DJS, SJP, SJS, UJP, and UJS. - - On the HP 1000, the request is always deferred until after the current - instruction completes. On the 21xx, the request is deferred unless the - current instruction is an MRG instruction other than JMP or JMP,I or - JSB,I. Note that for the 21xx, SFS and SFC are not included in the - deferral criteria. - - 7. Terminology. The 1000 series of computers was originally called the 21MX - at introduction. The 21MX (occasionally, 21MXM) corresponds to the 1000 - M-Series, and the 21MXE (occasionally, 21XE) corresponds to the 1000 - E-Series. The model numbers were changed before the introduction of the - 1000 F-Series, although some internal HP documentation refers to a 21MXF. - - The terms MEM (Memory Expansion Module), MEU (Memory Expansion Unit), DMI - (Dynamic Mapping Instructions), and DMS (Dynamic Mapping System) are used - somewhat interchangeably to refer to the logical-to-physical memory - address translation option provided on the 1000-Series. DMS consists of - the MEM card (12731A) and the DMI firmware (13307A). However, MEM and MEU - have been used interchangeably to refer to the mapping card, as have DMI - and DMS to refer to the firmware instructions. -*/ - - -#include "hp2100_defs.h" -#include "hp2100_cpu.h" - - -/* Memory protect constants */ - -#define UNIT_V_MP_JSB (UNIT_V_UF + 0) /* MP jumper W5 */ -#define UNIT_V_MP_INT (UNIT_V_UF + 1) /* MP jumper W6 */ -#define UNIT_V_MP_SEL1 (UNIT_V_UF + 2) /* MP jumper W7 */ -#define UNIT_MP_JSB (1 << UNIT_V_MP_JSB) /* 1 = W5 is out */ -#define UNIT_MP_INT (1 << UNIT_V_MP_INT) /* 1 = W6 is out */ -#define UNIT_MP_SEL1 (1 << UNIT_V_MP_SEL1) /* 1 = W7 is out */ - -/* DMA channels */ - -typedef enum { ch1, ch2 } CHANNEL; /* channel number */ - -#define DMA_CHAN_COUNT 2 /* number of DMA channels */ - -#define DMA_OE 020000000000 /* byte packing odd/even flag */ -#define DMA1_STC 0100000 /* DMA - issue STC */ -#define DMA1_PB 0040000 /* DMA - pack bytes */ -#define DMA1_CLC 0020000 /* DMA - issue CLC */ -#define DMA2_OI 0100000 /* DMA - output/input */ - -typedef struct { - FLIP_FLOP control; /* control flip-flop */ - FLIP_FLOP flag; /* flag flip-flop */ - FLIP_FLOP flagbuf; /* flag buffer flip-flop */ - FLIP_FLOP xferen; /* transfer enable flip-flop */ - FLIP_FLOP select; /* register select flip-flop */ - - uint32 cw1; /* device select */ - uint32 cw2; /* direction, address */ - uint32 cw3; /* word count */ - uint32 packer; /* byte-packer holding reg */ - } DMA_STATE; - -#define DMA_1_REQ (1 << ch1) /* channel 1 request */ -#define DMA_2_REQ (1 << ch2) /* channel 2 request */ - - -/* Command line switches */ - -#define ALL_BKPTS (SWMASK('E')|SWMASK('N')|SWMASK('S')|SWMASK('U')) -#define ALL_MAPMODES (SWMASK('S')|SWMASK('U')|SWMASK('P')|SWMASK('Q')) - - -/* RTE base-page addresses. */ - -static const uint32 xeqt = 0001717; /* XEQT address */ -static const uint32 tbg = 0001674; /* TBG address */ - -/* DOS base-page addresses. */ - -static const uint32 m64 = 0000040; /* constant -64 address */ -static const uint32 p64 = 0000067; /* constant +64 address */ - -/* CPU local data */ - -static uint32 jsb_plb = 2; /* protected lower bound for JSB */ -static uint32 saved_MR = 0; /* between executions */ -static uint32 fwanxm = 0; /* first word addr of nx mem */ - -/* CPU global data */ - -uint16 *M = NULL; /* memory */ -uint16 ABREG[2]; /* A/B registers */ -uint32 PC = 0; /* P register */ -uint32 SR = 0; /* S register */ -uint32 MR = 0; /* M register */ -uint32 TR = 0; /* T register */ -uint32 XR = 0; /* X register */ -uint32 YR = 0; /* Y register */ -uint32 E = 0; /* E register */ -uint32 O = 0; /* O register */ -FLIP_FLOP ion = CLEAR; /* interrupt enable */ -t_bool ion_defer = FALSE; /* interrupt defer */ -uint32 intaddr = 0; /* interrupt addr */ -uint32 stop_inst = 1; /* stop on ill inst */ -uint32 stop_dev = 0; /* stop on ill dev */ -uint16 pcq[PCQ_SIZE] = { 0 }; /* PC queue */ -uint32 pcq_p = 0; /* PC queue ptr */ -REG *pcq_r = NULL; /* PC queue reg ptr */ - -uint32 dev_prl [2] = { ~(uint32) 0, ~(uint32) 0 }; /* device priority low bit vector */ -uint32 dev_irq [2] = { 0, 0 }; /* device interrupt request bit vector */ -uint32 dev_srq [2] = { 0, 0 }; /* device service request bit vector */ - -/* Memory protect global data */ - -FLIP_FLOP mp_control = CLEAR; /* MP control flip-flop */ -FLIP_FLOP mp_flag = CLEAR; /* MP flag flip-flop */ -FLIP_FLOP mp_flagbuf = CLEAR; /* MP flag buffer flip-flop */ -FLIP_FLOP mp_mevff = CLEAR; /* memory expansion violation flip-flop */ -FLIP_FLOP mp_evrff = SET; /* enable violation register flip-flop */ - -uint32 mp_fence = 0; /* MP fence register */ -uint32 mp_viol = 0; /* MP violation register */ - -uint32 iop_sp = 0; /* iop stack reg */ -uint32 ind_max = 16; /* iadr nest limit */ -uint32 err_PC = 0; /* error PC */ -jmp_buf save_env; /* MP abort handler */ - -/* DMA global data */ - -DMA_STATE dma [DMA_CHAN_COUNT]; /* per-channel state */ - -/* Dynamic mapping system global data */ - -uint32 dms_enb = 0; /* dms enable */ -uint32 dms_ump = 0; /* dms user map */ -uint32 dms_sr = 0; /* dms status reg */ -uint32 dms_vr = 0; /* dms violation reg */ -uint16 dms_map[MAP_NUM * MAP_LNT] = { 0 }; /* dms maps */ - -/* External data */ - -extern int32 sim_interval; -extern int32 sim_int_char; -extern int32 sim_brk_char; -extern int32 sim_del_char; -extern uint32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ -extern DEVICE *sim_devices[]; -extern char halt_msg[]; -extern t_bool sim_idle_enab; -extern DIB clk_dib; /* CLK DIB for idle check */ - -/* CPU local routines */ - -static t_stat Ea (uint32 IR, uint32 *addr, uint32 irq); -static uint16 ReadTAB (uint32 va); -static uint32 dms (uint32 va, uint32 map, uint32 prot); -static uint32 shift (uint32 inval, uint32 flag, uint32 oper); -static t_stat dma_cycle (CHANNEL chan, uint32 map); -static uint32 calc_dma (void); -static t_bool dev_conflict (void); -static uint32 devdisp (uint32 select_code, IOCYCLE signal_set, uint16 data); - -/* CPU global routines */ - -t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); -t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw); -t_stat cpu_reset (DEVICE *dptr); -t_stat cpu_boot (int32 unitno, DEVICE *dptr); -t_stat mp_reset (DEVICE *dptr); -t_stat dma_reset (DEVICE *dptr); -t_stat cpu_set_size (UNIT *uptr, int32 new_size, char *cptr, void *desc); -t_stat cpu_set_model (UNIT *uptr, int32 new_model, char *cptr, void *desc); -t_stat cpu_show_model (FILE *st, UNIT *uptr, int32 val, void *desc); -t_stat cpu_set_opt (UNIT *uptr, int32 option, char *cptr, void *desc); -t_stat cpu_clr_opt (UNIT *uptr, int32 option, char *cptr, void *desc); -t_stat cpu_set_ldr (UNIT *uptr, int32 enable, char *cptr, void *desc); -t_stat cpu_set_idle (UNIT *uptr, int32 option, char *cptr, void *desc); -t_stat cpu_show_idle (FILE *st, UNIT *uptr, int32 val, void *desc); -void hp_post_cmd (t_bool from_scp); - -IOHANDLER cpuio; -IOHANDLER ovflio; -IOHANDLER pwrfio; -IOHANDLER protio; -IOHANDLER dmapio; -IOHANDLER dmasio; -IOHANDLER nullio; - -/* External routines */ - -extern t_stat cpu_eau (uint32 IR, uint32 intrq); -extern t_stat cpu_uig_0 (uint32 IR, uint32 intrq, uint32 iotrap); -extern t_stat cpu_uig_1 (uint32 IR, uint32 intrq, uint32 iotrap); - -extern void (*sim_vm_post) (t_bool from_scp); - - -/* Table of CPU features by model. - - Fields: - - typ: standard features plus typically configured options. - - opt: complete list of optional features. - - maxmem: maximum configurable memory in 16-bit words. - - Features in the "typical" list are enabled when the CPU model is selected. - If a feature appears in the "typical" list but NOT in the "optional" list, - then it is standard equipment and cannot be disabled. If a feature appears - in the "optional" list, then it may be enabled or disabled as desired by the - user. -*/ - -struct FEATURE_TABLE { /* CPU model feature table: */ - uint32 typ; /* - typical features */ - uint32 opt; /* - optional features */ - uint32 maxmem; /* - maximum memory */ - }; - -static struct FEATURE_TABLE cpu_features[] = { /* features in UNIT_xxxx order*/ - { UNIT_DMA | UNIT_MP, /* UNIT_2116 */ - UNIT_PFAIL | UNIT_DMA | UNIT_MP | UNIT_EAU, - 32768 }, - { UNIT_DMA, /* UNIT_2115 */ - UNIT_PFAIL | UNIT_DMA | UNIT_EAU, - 8192 }, - { UNIT_DMA, /* UNIT_2114 */ - UNIT_PFAIL | UNIT_DMA, - 16384 }, - { 0, 0, 0 }, - { UNIT_PFAIL | UNIT_MP | UNIT_DMA | UNIT_EAU, /* UNIT_2100 */ - UNIT_DMA | UNIT_FP | UNIT_IOP | UNIT_FFP, - 32768 }, - { 0, 0, 0 }, - { 0, 0, 0 }, - { 0, 0, 0 }, - { UNIT_MP | UNIT_DMA | UNIT_EAU | UNIT_FP | UNIT_DMS, /* UNIT_1000_M */ - UNIT_PFAIL | UNIT_DMA | UNIT_MP | UNIT_DMS | - UNIT_IOP | UNIT_FFP | UNIT_DS, - 1048576 }, - { UNIT_MP | UNIT_DMA | UNIT_EAU | UNIT_FP | UNIT_DMS, /* UNIT_1000_E */ - UNIT_PFAIL | UNIT_DMA | UNIT_MP | UNIT_DMS | - UNIT_IOP | UNIT_FFP | UNIT_DBI | UNIT_DS | UNIT_EMA_VMA, - 1048576 }, - { UNIT_MP | UNIT_DMA | UNIT_EAU | UNIT_FP | /* UNIT_1000_F */ - UNIT_FFP | UNIT_DBI | UNIT_DMS, - UNIT_PFAIL | UNIT_DMA | UNIT_MP | UNIT_VIS | - UNIT_IOP | UNIT_DS | UNIT_SIGNAL | UNIT_EMA_VMA, - 1048576 } - }; - - -/* Null device information block */ - -DIB null_dib = { &nullio, 0 }; - -/* CPU data structures - - cpu_dib CPU device information block - cpu_dev CPU device descriptor - cpu_unit CPU unit descriptor - cpu_reg CPU register list - cpu_mod CPU modifiers list - cpu_deb CPU debug flags -*/ - -DIB cpu_dib = { &cpuio, CPU }; - -UNIT cpu_unit = { UDATA (NULL, UNIT_FIX + UNIT_BINK, 0) }; - -REG cpu_reg[] = { - { ORDATA (P, PC, 15) }, - { ORDATA (A, AR, 16), REG_FIT }, - { ORDATA (B, BR, 16), REG_FIT }, - { ORDATA (M, MR, 15) }, - { ORDATA (T, TR, 16), REG_RO }, - { ORDATA (X, XR, 16) }, - { ORDATA (Y, YR, 16) }, - { ORDATA (S, SR, 16) }, - { FLDATA (E, E, 0) }, - { FLDATA (O, O, 0) }, - { FLDATA (ION, ion, 0) }, - { FLDATA (ION_DEFER, ion_defer, 0) }, - { ORDATA (CIR, intaddr, 6) }, - { FLDATA (DMSENB, dms_enb, 0) }, - { FLDATA (DMSCUR, dms_ump, VA_N_PAG) }, - { ORDATA (DMSSR, dms_sr, 16) }, - { ORDATA (DMSVR, dms_vr, 16) }, - { BRDATA (DMSMAP, dms_map, 8, 16, MAP_NUM * MAP_LNT) }, - { ORDATA (IOPSP, iop_sp, 16) }, - { FLDATA (STOP_INST, stop_inst, 0) }, - { FLDATA (STOP_DEV, stop_dev, 1) }, - { DRDATA (INDMAX, ind_max, 16), REG_NZ + PV_LEFT }, - { BRDATA (PCQ, pcq, 8, 15, PCQ_SIZE), REG_RO+REG_CIRC }, - { ORDATA (PCQP, pcq_p, 6), REG_HRO }, - { ORDATA (JSBPLB, jsb_plb, 32), REG_HRO }, - { ORDATA (SAVEDMR, saved_MR, 32), REG_HRO }, - { ORDATA (FWANXM, fwanxm, 32), REG_HRO }, - { ORDATA (WRU, sim_int_char, 8), REG_HRO }, - { ORDATA (BRK, sim_brk_char, 8), REG_HRO }, - { ORDATA (DEL, sim_del_char, 8), REG_HRO }, - { BRDATA (PRL, dev_prl, 8, 32, 2), REG_HRO }, - { BRDATA (IRQ, dev_irq, 8, 32, 2), REG_HRO }, - { BRDATA (SRQ, dev_srq, 8, 32, 2), REG_HRO }, - { NULL } - }; - -/* CPU modifier table. - - The 21MX monikers are deprecated in favor of the 1000 designations. See the - "HP 1000 Series Naming History" on the back inside cover of the Technical - Reference Handbook. */ - -MTAB cpu_mod[] = { - { UNIT_MODEL_MASK, UNIT_2116, "", "2116", &cpu_set_model, &cpu_show_model, (void *) "2116" }, - { UNIT_MODEL_MASK, UNIT_2115, "", "2115", &cpu_set_model, &cpu_show_model, (void *) "2115" }, - { UNIT_MODEL_MASK, UNIT_2114, "", "2114", &cpu_set_model, &cpu_show_model, (void *) "2114" }, - { UNIT_MODEL_MASK, UNIT_2100, "", "2100", &cpu_set_model, &cpu_show_model, (void *) "2100" }, - { UNIT_MODEL_MASK, UNIT_1000_E, "", "1000-E", &cpu_set_model, &cpu_show_model, (void *) "1000-E" }, - { UNIT_MODEL_MASK, UNIT_1000_E, NULL, "21MX-E", &cpu_set_model, &cpu_show_model, (void *) "1000-E" }, - { UNIT_MODEL_MASK, UNIT_1000_M, "", "1000-M", &cpu_set_model, &cpu_show_model, (void *) "1000-M" }, - { UNIT_MODEL_MASK, UNIT_1000_M, NULL, "21MX-M", &cpu_set_model, &cpu_show_model, (void *) "1000-M" }, - -#if defined (HAVE_INT64) - { UNIT_MODEL_MASK, UNIT_1000_F, "", "1000-F", &cpu_set_model, &cpu_show_model, (void *) "1000-F" }, -#endif - - { MTAB_XTD | MTAB_VDV, 1, "IDLE", "IDLE", &cpu_set_idle, &cpu_show_idle, NULL }, - { MTAB_XTD | MTAB_VDV, 0, NULL, "NOIDLE", &cpu_set_idle, NULL, NULL }, - - { MTAB_XTD | MTAB_VDV, 1, NULL, "LOADERENABLE", &cpu_set_ldr, NULL, NULL }, - { MTAB_XTD | MTAB_VDV, 0, NULL, "LOADERDISABLE", &cpu_set_ldr, NULL, NULL }, - - { UNIT_EAU, UNIT_EAU, "EAU", "EAU", &cpu_set_opt, NULL, NULL }, - { UNIT_EAU, 0, "no EAU", NULL, NULL, NULL, NULL }, - { MTAB_XTD | MTAB_VDV, UNIT_EAU, NULL, "NOEAU", &cpu_clr_opt, NULL, NULL }, - - { UNIT_FP, UNIT_FP, "FP", "FP", &cpu_set_opt, NULL, NULL }, - { UNIT_FP, 0, "no FP", NULL, NULL, NULL, NULL }, - { MTAB_XTD | MTAB_VDV, UNIT_FP, NULL, "NOFP", &cpu_clr_opt, NULL, NULL }, - - { UNIT_IOP, UNIT_IOP, "IOP", "IOP", &cpu_set_opt, NULL, NULL }, - { UNIT_IOP, 0, "no IOP", NULL, NULL, NULL, NULL }, - { MTAB_XTD | MTAB_VDV, UNIT_IOP, NULL, "NOIOP", &cpu_clr_opt, NULL, NULL }, - - { UNIT_DMS, UNIT_DMS, "DMS", "DMS", &cpu_set_opt, NULL, NULL }, - { UNIT_DMS, 0, "no DMS", NULL, NULL, NULL, NULL }, - { MTAB_XTD | MTAB_VDV, UNIT_DMS, NULL, "NODMS", &cpu_clr_opt, NULL, NULL }, - - { UNIT_FFP, UNIT_FFP, "FFP", "FFP", &cpu_set_opt, NULL, NULL }, - { UNIT_FFP, 0, "no FFP", NULL, NULL, NULL, NULL }, - { MTAB_XTD | MTAB_VDV, UNIT_FFP, NULL, "NOFFP", &cpu_clr_opt, NULL, NULL }, - - { UNIT_DBI, UNIT_DBI, "DBI", "DBI", &cpu_set_opt, NULL, NULL }, - { UNIT_DBI, 0, "no DBI", NULL, NULL, NULL, NULL }, - { MTAB_XTD | MTAB_VDV, UNIT_DBI, NULL, "NODBI", &cpu_clr_opt, NULL, NULL }, - - { UNIT_EMA_VMA, UNIT_EMA, "EMA", "EMA", &cpu_set_opt, NULL, NULL }, - { MTAB_XTD | MTAB_VDV, UNIT_EMA, NULL, "NOEMA", &cpu_clr_opt, NULL, NULL }, - - { UNIT_EMA_VMA, UNIT_VMAOS, "VMA", "VMA", &cpu_set_opt, NULL, NULL }, - { MTAB_XTD | MTAB_VDV, UNIT_VMAOS, NULL, "NOVMA", &cpu_clr_opt, NULL, NULL }, - - { UNIT_EMA_VMA, 0, "no EMA/VMA", NULL, &cpu_set_opt, NULL, NULL }, - -#if defined (HAVE_INT64) - { UNIT_VIS, UNIT_VIS, "VIS", "VIS", &cpu_set_opt, NULL, NULL }, - { UNIT_VIS, 0, "no VIS", NULL, NULL, NULL, NULL }, - { MTAB_XTD | MTAB_VDV, UNIT_VIS, NULL, "NOVIS", &cpu_clr_opt, NULL, NULL }, - - { UNIT_SIGNAL, UNIT_SIGNAL,"SIGNAL", "SIGNAL", &cpu_set_opt, NULL, NULL }, - { UNIT_SIGNAL, 0, "no SIGNAL", NULL, NULL, NULL, NULL }, - { MTAB_XTD | MTAB_VDV, UNIT_SIGNAL, NULL, "NOSIGNAL", &cpu_clr_opt, NULL, NULL }, -#endif - -/* Future microcode support. - { UNIT_DS, UNIT_DS, "DS", "DS", &cpu_set_opt, NULL, NULL }, - { UNIT_DS, 0, "no DS", NULL, NULL, NULL, NULL }, - { MTAB_XTD | MTAB_VDV, UNIT_DS, NULL, "NODS", &cpu_clr_opt, NULL, NULL }, -*/ - - { MTAB_XTD | MTAB_VDV, 4096, NULL, "4K", &cpu_set_size, NULL, NULL }, - { MTAB_XTD | MTAB_VDV, 8192, NULL, "8K", &cpu_set_size, NULL, NULL }, - { MTAB_XTD | MTAB_VDV, 12288, NULL, "12K", &cpu_set_size, NULL, NULL }, - { MTAB_XTD | MTAB_VDV, 16384, NULL, "16K", &cpu_set_size, NULL, NULL }, - { MTAB_XTD | MTAB_VDV, 24576, NULL, "24K", &cpu_set_size, NULL, NULL }, - { MTAB_XTD | MTAB_VDV, 32768, NULL, "32K", &cpu_set_size, NULL, NULL }, - { MTAB_XTD | MTAB_VDV, 65536, NULL, "64K", &cpu_set_size, NULL, NULL }, - { MTAB_XTD | MTAB_VDV, 131072, NULL, "128K", &cpu_set_size, NULL, NULL }, - { MTAB_XTD | MTAB_VDV, 262144, NULL, "256K", &cpu_set_size, NULL, NULL }, - { MTAB_XTD | MTAB_VDV, 524288, NULL, "512K", &cpu_set_size, NULL, NULL }, - { MTAB_XTD | MTAB_VDV, 1048576, NULL, "1024K", &cpu_set_size, NULL, NULL }, - { 0 } - }; - -DEBTAB cpu_deb[] = { - { "OS", DEB_OS }, - { "OSTBG", DEB_OSTBG }, - { "VMA", DEB_VMA }, - { "EMA", DEB_EMA }, - { "VIS", DEB_VIS }, - { "SIG", DEB_SIG }, - { NULL, 0 } - }; - -DEVICE cpu_dev = { - "CPU", /* device name */ - &cpu_unit, /* unit array */ - cpu_reg, /* register array */ - cpu_mod, /* modifier array */ - 1, /* number of units */ - 8, /* address radix */ - PA_N_SIZE, /* address width */ - 1, /* address increment */ - 8, /* data radix */ - 16, /* data width */ - &cpu_ex, /* examine routine */ - &cpu_dep, /* deposit routine */ - &cpu_reset, /* reset routine */ - &cpu_boot, /* boot routine */ - NULL, /* attach routine */ - NULL, /* detach routine */ - &cpu_dib, /* device information block */ - DEV_DEBUG, /* device flags */ - 0, /* debug control flags */ - cpu_deb, /* debug flag name table */ - NULL, /* memory size change routine */ - NULL }; /* logical device name */ - -/* Overflow device information block */ - -DIB ovfl_dib = { &ovflio, OVF }; - -/* Powerfail device information block */ - -DIB pwrf_dib = { &pwrfio, PWR }; - -/* Memory protect data structures - - mp_dib MP device information block - mp_dev MP device descriptor - mp_unit MP unit descriptor - mp_reg MP register list - mp_mod MP modifiers list -*/ - -DIB mp_dib = { &protio, PRO }; - -UNIT mp_unit = { UDATA (NULL, UNIT_MP_SEL1, 0) }; /* default is JSB in, INT in, SEL1 out */ - -REG mp_reg[] = { - { FLDATA (CTL, mp_control, 0) }, - { FLDATA (FLG, mp_flag, 0) }, - { FLDATA (FBF, mp_flagbuf, 0) }, - { ORDATA (FR, mp_fence, 15) }, - { ORDATA (VR, mp_viol, 16) }, - { FLDATA (EVR, mp_evrff, 0) }, - { FLDATA (MEV, mp_mevff, 0) }, - { NULL } - }; - -MTAB mp_mod[] = { - { UNIT_MP_JSB, UNIT_MP_JSB, "JSB (W5) out", "JSBOUT", NULL }, - { UNIT_MP_JSB, 0, "JSB (W5) in", "JSBIN", NULL }, - { UNIT_MP_INT, UNIT_MP_INT, "INT (W6) out", "INTOUT", NULL }, - { UNIT_MP_INT, 0, "INT (W6) in", "INTIN", NULL }, - { UNIT_MP_SEL1, UNIT_MP_SEL1, "SEL1 (W7) out", "SEL1OUT", NULL }, - { UNIT_MP_SEL1, 0, "SEL1 (W7) in", "SEL1IN", NULL }, - { 0 } - }; - -DEVICE mp_dev = { - "MP", /* device name */ - &mp_unit, /* unit array */ - mp_reg, /* register array */ - mp_mod, /* modifier array */ - 1, /* number of units */ - 8, /* address radix */ - 1, /* address width */ - 1, /* address increment */ - 8, /* data radix */ - 16, /* data width */ - NULL, /* examine routine */ - NULL, /* deposit routine */ - &mp_reset, /* reset routine */ - NULL, /* boot routine */ - NULL, /* attach routine */ - NULL, /* detach routine */ - &mp_dib, /* device information block */ - DEV_DISABLE | DEV_DIS, /* device flags */ - 0, /* debug control flags */ - NULL, /* debug flag name table */ - NULL, /* memory size change routine */ - NULL }; /* logical device name */ - -/* DMA controller data structures - - dmax_dib DMAx device information block - dmax_dev DMAx device descriptor - dmax_reg DMAx register list -*/ - -DIB dmap1_dib = { &dmapio, DMA1, ch1 }; -DIB dmas1_dib = { &dmasio, DMALT1, ch1 }; - -UNIT dma1_unit = { UDATA (NULL, 0, 0) }; - -REG dma1_reg[] = { - { FLDATA (XFR, dma [ch1].xferen, 0) }, - { FLDATA (CTL, dma [ch1].control, 0) }, - { FLDATA (FLG, dma [ch1].flag, 0) }, - { FLDATA (FBF, dma [ch1].flagbuf, 0) }, - { FLDATA (CTL2, dma [ch1].select, 0) }, - { ORDATA (CW1, dma [ch1].cw1, 16) }, - { ORDATA (CW2, dma [ch1].cw2, 16) }, - { ORDATA (CW3, dma [ch1].cw3, 16) }, - { FLDATA (BYTE, dma [ch1].packer, 31) }, - { ORDATA (PACKER, dma [ch1].packer, 8) }, - { NULL } - }; - -DEVICE dma1_dev = { - "DMA1", /* device name */ - &dma1_unit, /* unit array */ - dma1_reg, /* register array */ - NULL, /* modifier array */ - 1, /* number of units */ - 8, /* address radix */ - 1, /* address width */ - 1, /* address increment */ - 8, /* data radix */ - 16, /* data width */ - NULL, /* examine routine */ - NULL, /* deposit routine */ - &dma_reset, /* reset routine */ - NULL, /* boot routine */ - NULL, /* attach routine */ - NULL, /* detach routine */ - &dmap1_dib, /* device information block */ - DEV_DISABLE, /* device flags */ - 0, /* debug control flags */ - NULL, /* debug flag name table */ - NULL, /* memory size change routine */ - NULL }; /* logical device name */ - -DIB dmap2_dib = { &dmapio, DMA2, ch2 }; -DIB dmas2_dib = { &dmasio, DMALT2, ch2 }; - -UNIT dma2_unit = { UDATA (NULL, 0, 0) }; - -REG dma2_reg[] = { - { FLDATA (XFR, dma [ch2].xferen, 0) }, - { FLDATA (CTL, dma [ch2].control, 0) }, - { FLDATA (FLG, dma [ch2].flag, 0) }, - { FLDATA (FBF, dma [ch2].flagbuf, 0) }, - { FLDATA (CTL2, dma [ch2].select, 0) }, - { ORDATA (CW1, dma [ch2].cw1, 16) }, - { ORDATA (CW2, dma [ch2].cw2, 16) }, - { ORDATA (CW3, dma [ch2].cw3, 16) }, - { FLDATA (BYTE, dma [ch2].packer, 31) }, - { ORDATA (PACKER, dma [ch2].packer, 8) }, - { NULL } - }; - -DEVICE dma2_dev = { - "DMA2", /* device name */ - &dma2_unit, /* unit array */ - dma2_reg, /* register array */ - NULL, /* modifier array */ - 1, /* number of units */ - 8, /* address radix */ - 1, /* address width */ - 1, /* address increment */ - 8, /* data radix */ - 16, /* data width */ - NULL, /* examine routine */ - NULL, /* deposit routine */ - &dma_reset, /* reset routine */ - NULL, /* boot routine */ - NULL, /* attach routine */ - NULL, /* detach routine */ - &dmap2_dib, /* device information block */ - DEV_DISABLE, /* device flags */ - 0, /* debug control flags */ - NULL, /* debug flag name table */ - NULL, /* memory size change routine */ - NULL }; /* logical device name */ - -static DEVICE *dma_dptrs [] = { &dma1_dev, &dma2_dev }; - - -/* Interrupt deferral table (1000 version) */ -/* Deferral for I/O subops: soHLT, soFLG, soSFC, soSFS, soMIX, soLIX, soOTX, soCTL */ -static t_bool defer_tab [] = { FALSE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, TRUE }; - -/* Device I/O dispatch table */ - -DIB *dtab [64] = { &cpu_dib, &ovfl_dib }; /* init with immutable devices */ - - - -/* Execute CPU instructions. - - This routine is the instruction decode routine for the HP 2100. It is called - from the simulator control program to execute instructions in simulated - memory, starting at the simulated PC. It runs until 'reason' is set to a - status other than SCPE_OK. -*/ - -t_stat sim_instr (void) -{ -uint32 intrq, dmarq; /* set after setjmp */ -uint32 iotrap = 0; /* set after setjmp */ -t_stat reason = SCPE_OK; /* set after setjmp */ -int32 i; /* temp */ -DEVICE *dptr; /* temp */ -DIB *dibptr; /* temp */ -int abortval; - -/* Restore register state */ - -if (dev_conflict ()) /* check device assignment consistency */ - return SCPE_STOP; /* conflict; stop execution */ - -err_PC = PC = PC & VAMASK; /* load local PC */ - -/* Restore I/O state */ - -dev_prl [0] = dev_prl [1] = ~(uint32) 0; /* set all priority lows */ -dev_irq [0] = dev_irq [1] = 0; /* clear all interrupt requests */ -dev_srq [0] = dev_srq [1] = 0; /* clear all service requests */ - -for (i = OPTDEV; i <= MAXDEV; i++) /* default optional devices */ - dtab [i] = &null_dib; - -dtab [PWR] = &pwrf_dib; /* for now, powerfail is always present */ - -for (i = 0; dptr = sim_devices [i]; i++) { /* loop thru dev */ - dibptr = (DIB *) dptr->ctxt; /* get DIB */ - - if (dibptr && !(dptr->flags & DEV_DIS)) { /* handler exists and device is enabled? */ - dtab [dibptr->select_code] = dibptr; /* set DIB pointer into dispatch table */ - dibptr->io_handler (dibptr, ioSIR, 0); /* set interrupt request state */ - } - } - -if (dtab [DMA1] != &null_dib) /* first DMA channel enabled? */ - dtab [DMALT1] = &dmas1_dib; /* set up secondary device handler */ - -if (dtab [DMA2] != &null_dib) /* second DMA channel enabled? */ - dtab [DMALT2] = &dmas2_dib; /* set up secondary device handler */ - -/* Configure interrupt deferral table */ - -if (UNIT_CPU_FAMILY == UNIT_FAMILY_21XX) /* 21xx series? */ - defer_tab [soSFC] = defer_tab [soSFS] = FALSE; /* SFC/S doesn't defer */ -else /* 1000 series */ - defer_tab [soSFC] = defer_tab [soSFS] = TRUE; /* SFC/S does defer */ - - -/* Set MP abort handling. - - If an abort occurs in memory protection, the relocation routine executes a - longjmp to this area OUTSIDE the main simulation loop. Memory protection - errors are the only sources of aborts in the HP 2100. All referenced - variables must be globals, and all sim_instr scoped automatics must be set - after the setjmp. - - To initiate an MP abort, use the MP_ABORT macro and pass the violation - address. MP_ABORT should only be called if "mp_control" is SET, as aborts do - not occur if MP is turned off. - - An MP interrupt (SC 05) is qualified by "ion" but not by "ion_defer". If the - interrupt system is off when an MP violation is detected, the violating - instruction will be aborted, even though no interrupt occurs. In this case, - neither the flag nor flag buffer are set, and EVR is not cleared. - - Implementation notes: - - 1. The protected lower bound address for the JSB instruction depends on the - W5 jumper setting. If W5 is in, then the lower bound is 2, allowing JSBs - to the A and B registers. If W5 is out, then the lower bound is 0, just - as with JMP. - - 2. The violation address is passed to enable the MEM violation register to - be updated. The "longjmp" routine will not pass a value of 0; it is - converted internally to 1. This is OK, because only the page number - of the address value is used, and locations 0 and 1 are both on page 0. - - 3. This routine is used both for MP and MEM violations. The MEV flip-flop - will be clear for the former and set for the latter. The MEV violation - register will be updated by "dms_upd_vr" only if the call is NOT for an - MEM violation; if it is, then the VR has already been set and should not - be disturbed. -*/ - -jsb_plb = (mp_unit.flags & UNIT_MP_JSB) ? 0 : 2; /* set protected lower bound for JSB */ - -abortval = setjmp (save_env); /* set abort hdlr */ - -if (abortval) { /* memory protect abort? */ - dms_upd_vr (abortval); /* update violation register (if not MEV) */ - - if (ion) /* interrupt system on? */ - protio (dtab [PRO], ioENF, 0); /* set flag */ - } - -dmarq = calc_dma (); /* initial recalc of DMA masks */ -intrq = calc_int (); /* initial recalc of interrupts */ - - -/* Main instruction fetch/decode loop */ - -while (reason == SCPE_OK) { /* loop until halted */ - uint32 IR, MA, absel, v1, t, skip; - - err_PC = PC; /* save PC for error recovery */ - - if (sim_interval <= 0) { /* event timeout? */ - reason = sim_process_event (); /* process event service */ - - if (reason != SCPE_OK) /* service failed? */ - break; /* stop execution */ - - dmarq = calc_dma (); /* recalc DMA reqs */ - intrq = calc_int (); /* recalc interrupts */ - } - -/* DMA cycles are requested by an I/O card asserting its SRQ signal. If a DMA - channel is programmed to respond to that card's select code, a DMA cycle will - be initiated. A DMA cycle consists of a memory cycle and an I/O cycle. - These cycles are synchronized with the control processor on the 21xx CPUs. - On the 1000s, memory cycles are asynchronous, while I/O cycles are - synchronous. Memory cycle time is about 40% of the I/O cycle time. - - With properly designed interface cards, DMA is capable of taking consecutive - I/O cycles. On all machines except the 1000 M-Series, a DMA cycle freezes - the CPU for the duration of the cycle. On the M-Series, a DMA cycle freezes - the CPU if it attempts an I/O cycle (including IAK) or a directly-interfering - memory cycle. An interleaved memory cycle is allowed. Otherwise, the - control processor is allowed to run. Therefore, during consecutive DMA - cycles, the M-Series CPU will run until an IOG instruction is attempted, - whereas the other CPUs will freeze completely. - - All DMA cards except the 12607B provide two independent channels. If both - channels are active simultaneously, channel 1 has priority for I/O cycles - over channel 2. - - Most I/O cards assert SRQ no more than 50% of the time. A few buffered - cards, such as the 12821A and 13175A Disc Interfaces, are capable of - asserting SRQ continuously while filling or emptying the buffer. If SRQ for - channel 1 is asserted continuously when both channels are active, then no - channel 2 cycles will occur until channel 1 completes. - - Implementation notes: - - 1. CPU freeze is simulated by skipping instruction execution during the - current loop cycle. - - 2. If both channels have SRQ asserted, DMA priority is simulated by skipping - the channel 2 cycle if channel 1's SRQ is still asserted at the end of - its cycle. If it is not, then channel 2 steals the next cycle from the - CPU. - - 3. The 1000 M-Series allows some CPU processing concurrently with - continuous DMA cycles, whereas all other CPUs freeze. The processor - freezes if an I/O cycle is attempted, including an interrupt - acknowledgement. Because some microcode extensions (e.g., Access IOP, - RTE-6/VM OS) perform I/O cycles, advance detection of I/O cycles is - difficult. Therefore, we freeze all processing for the M-Series as well. -*/ - - if (dmarq) { - if (dmarq & DMA_1_REQ) { /* DMA channel 1 request? */ - reason = dma_cycle (ch1, PAMAP); /* do one DMA cycle using port A map */ - - if (reason == SCPE_OK) /* cycle OK? */ - dmarq = calc_dma (); /* recalc DMA requests */ - else - break; /* cycle failed, so stop */ - } - - if ((dmarq & (DMA_1_REQ | DMA_2_REQ)) == DMA_2_REQ) { /* DMA channel 1 idle and channel 2 request? */ - reason = dma_cycle (ch2, PBMAP); /* do one DMA cycle using port B map */ - - if (reason == SCPE_OK) /* cycle OK? */ - dmarq = calc_dma (); /* recalc DMA requests */ - else - break; /* cycle failed, so stop */ - } - - if (dmarq) /* DMA request still pending? */ - continue; /* service it before instruction execution */ - - intrq = calc_int (); /* recalc interrupts */ - } - - if (intrq && ion_defer) /* interrupt pending but deferred? */ - ion_defer = calc_defer (); /* confirm deferral */ - -/* Check for pending interrupt request. - - Interrupt recognition is controlled by three state variables: "ion", - "ion_defer", and "intrq". "ion" corresponds to the INTSYS flip-flop in the - 1000 CPU, "ion_defer" corresponds to the INTEN flip-flop, and "intrq" - corresponds to the NRMINT flip-flop. STF 00 and CLF 00 set and clear INTSYS, - turning the interrupt system on and off. Micro-orders ION and IOFF set and - clear INTEN, deferring or allowing certain interrupts. An IRQ signal from a - device, qualified by the corresponding PRL signal, will set NRMINT to request - a normal interrupt; an IOFF or IAK will clear it. - - Under simulation, "ion" is controlled by STF/CLF 00. "ion_defer" is set or - cleared as appropriate by the individual instruction simulators. "intrq" is - set to the successfully interrupting device's select code, or to zero if - there is no qualifying interrupt request. - - Presuming PRL is set to allow priority to an interrupting device: - - 1. Power fail (SC 04) may interrupt if "ion_defer" is clear; this is not - conditional on "ion" being set. - - 2. Memory protect (SC 05) may interrupt if "ion" is set; this is not - conditional on "ion_defer" being clear. - - 3. Parity error (SC 05) may interrupt always; this is not conditional on - "ion" being set or "ion_defer" being clear. - - 4. All other devices (SC 06 and up) may interrupt if "ion" is set and - "ion_defer" is clear. - - Qualification with "ion" is performed by "calc_int", except for case 2, which - is qualified by the MP abort handler above (because qualification occurs on - the MP card, rather than in the CPU). Therefore, we need only qualify by - "ion_defer" here. -*/ - - if (intrq && ((intrq == PRO) || !ion_defer)) { /* interrupt request? */ - if (sim_brk_summ && /* any breakpoints? */ - sim_brk_test (intrq, SWMASK ('E') | /* unconditional or right type for DMS? */ - (dms_enb ? SWMASK ('S') : SWMASK ('N')))) { - reason = STOP_IBKPT; /* stop simulation */ - break; - } - - intaddr = intrq; /* save int addr in CIR */ - intrq = 0; /* clear request */ - ion_defer = TRUE; /* defer interrupts */ - iotrap = 1; /* mark as I/O trap cell instr */ - - if (dms_enb) /* dms enabled? */ - dms_sr = dms_sr | MST_ENBI; /* set in status */ - else /* not enabled */ - dms_sr = dms_sr & ~MST_ENBI; /* clear in status */ - - if (dms_ump) { /* user map enabled at interrupt? */ - dms_sr = dms_sr | MST_UMPI; /* set in status */ - dms_ump = SMAP; /* switch to system map */ - } - else /* system map enabled at interrupt */ - dms_sr = dms_sr & ~MST_UMPI; /* clear in status */ - - IR = ReadW (intaddr); /* get trap cell instruction */ - - devdisp (intaddr, ioIAK, (uint16) IR); /* acknowledge interrupt */ - - if (intaddr != PRO) /* not MP interrupt? */ - protio (dtab [intaddr], ioIAK, IR); /* send IAK for device to MP too */ - } - - else { /* normal instruction */ - iotrap = 0; /* not a trap cell instruction */ - - if (sim_brk_summ && /* any breakpoints? */ - sim_brk_test (PC, SWMASK ('E') | /* unconditional or */ - (dms_enb ? /* correct type for DMS state? */ - (dms_ump ? - SWMASK ('U') : SWMASK ('S')) : - SWMASK ('N')))) { - reason = STOP_IBKPT; /* stop simulation */ - break; - } - - if (mp_evrff) /* violation register enabled */ - mp_viol = PC; /* update with current PC */ - - IR = ReadW (PC); /* fetch instr */ - PC = (PC + 1) & VAMASK; - ion_defer = FALSE; - } - - sim_interval = sim_interval - 1; /* count instruction */ - -/* Instruction decode. The 21MX does a 256-way decode on IR<15:8> - - 15 14 13 12 11 10 09 08 instruction - - x <-!= 0-> x x x x memory reference - 0 0 0 0 x 0 x x shift - 0 0 0 0 x 0 x x alter-skip - 1 0 0 0 x 1 x x IO - 1 0 0 0 0 0 x 0 extended arithmetic - 1 0 0 0 0 0 0 1 divide (decoded as 100400) - 1 0 0 0 1 0 0 0 double load (decoded as 104000) - 1 0 0 0 1 0 0 1 double store (decoded as 104400) - 1 0 0 0 1 0 1 0 extended instr group 0 (A/B must be set) - 1 0 0 0 x 0 1 1 extended instr group 1 (A/B ignored) */ - - absel = (IR & I_AB) ? 1 : 0; /* get A/B select */ - - switch ((IR >> 8) & 0377) { /* decode IR<15:8> */ - -/* Memory reference instructions */ - - case 0020:case 0021:case 0022:case 0023: - case 0024:case 0025:case 0026:case 0027: - case 0220:case 0221:case 0222:case 0223: - case 0224:case 0225:case 0226:case 0227: - reason = Ea (IR, &MA, intrq); /* AND */ - - if (reason != SCPE_OK) /* address failed to resolve? */ - break; /* stop execution */ - - AR = AR & ReadW (MA); - break; - -/* JSB is a little tricky. It is possible to generate both an MP and a DM - violation simultaneously, as the MP and MEM cards validate in parallel. - Consider a JSB to a location under the MP fence and on a write-protected - page. This situation must be reported as a DM violation, because it has - priority (SFS 5 and SFC 5 check only the MEVFF, which sets independently of - the MP fence violation). Under simulation, this means that DM violations - must be checked, and the MEVFF must be set, before an MP abort is taken. - This is done by the "mp_dms_jmp" routine. -*/ - - case 0230:case 0231:case 0232:case 0233: - case 0234:case 0235:case 0236:case 0237: - ion_defer = TRUE; /* defer if JSB,I */ - - case 0030:case 0031:case 0032:case 0033: - case 0034:case 0035:case 0036:case 0037: - reason = Ea (IR, &MA, intrq); /* JSB */ - - if (reason != SCPE_OK) /* address failed to resolve? */ - break; /* stop execution */ - - mp_dms_jmp (MA, jsb_plb); /* validate jump address */ - - WriteW (MA, PC); /* store PC */ - PCQ_ENTRY; - PC = (MA + 1) & VAMASK; /* jump */ - break; - - case 0040:case 0041:case 0042:case 0043: - case 0044:case 0045:case 0046:case 0047: - case 0240:case 0241:case 0242:case 0243: - case 0244:case 0245:case 0246:case 0247: - reason = Ea (IR, &MA, intrq); /* XOR */ - - if (reason != SCPE_OK) /* address failed to resolve? */ - break; /* stop execution */ - - AR = AR ^ ReadW (MA); - break; - -/* CPU idle processing. - - The 21xx/1000 CPUs have no "wait for interrupt" instruction. Idling in HP - operating systems consists of sitting in "idle loops" that end with JMP - instructions. We test for certain known patterns when a JMP instruction is - executed to decide if the simulator should idle. - - Idling must not occur if an interrupt is pending. As mentioned in the - "General Notes" above, HP CPUs will defer interrupts if certain instructions - are executed. OS interrupt handlers exit via such deferring instructions. - If there is a pending interrupt when the OS is otherwise idle, the idle loop - will execute one instruction before reentering the interrupt handler. If we - call sim_idle() in this case, we will lose interrupts. - - Consider the situation in RTE. Under simulation, the TTY and CLK events are - co-scheduled, with the CLK expiring one instruction after the TTY. When the - TTY interrupts, $CIC in RTE is entered. One instruction later, the CLK - expires and posts its interrupt, but it is not immediately handled, because - the JSB $CIC,I / JMP $CIC0,I / SFS 0,C instruction entry sequence continually - defers interrupts until the interrupt system is turned off. When $CIC - returns via $IRT, one instruction of the idle loop is executed, even though - the CLK interrupt is still pending, because the UJP instruction used to - return also defers interrupts. - - If sim_idle() is called at this point, the simulator will sleep when it - should be handling the pending CLK interrupt. When it awakes, TTY expiration - will be moved forward to the next instruction. The still-pending CLK - interrupt will then be recognized, and $CIC will be entered. But the TTY and - then the CLK will then expire and attempt to interrupt again, although they - are deferred by the $CIC entry sequence. This causes the second CLK - interrupt to be missed, as processing of the first one is just now being - started. - - Similarly, at the end of the CLK handling, the TTY interrupt is still - pending. When $IRT returns to the idle loop, sim_idle() would be called - again, so the TTY and then CLK interrupt a third time. Because the second - TTY interrupt is still pending, $CIC is entered, but the third TTY interrupt - is lost. - - We solve this problem by testing for a pending interrupt before calling - sim_idle(). The system isn't really quiescent if it is just about to handle - an interrupt. -*/ - - case 0250:case 0251:case 0252:case 0253: - case 0254:case 0255:case 0256:case 0257: - ion_defer = TRUE; /* defer if JMP,I */ - - case 0050:case 0051:case 0052:case 0053: - case 0054:case 0055:case 0056:case 0057: - reason = Ea (IR, &MA, intrq); /* JMP */ - - if (reason != SCPE_OK) /* address failed to resolve? */ - break; /* stop execution */ - - mp_dms_jmp (MA, 0); /* validate jump addr */ - PCQ_ENTRY; - PC = MA; /* jump */ - -/* Idle conditions by operating system: - - RTE-6/VM: - - ISZ / JMP *-1 - - mp_fence = 0 - - XEQT (address 1717B) = 0 - - DMS on with system map enabled - - RTE verification: TBG (address 1674B) = CLK select code - - RTE though RTE-IVB: - - JMP * - - mp_fence = 0 - - XEQT (address 1717B) = 0 - - DMS on with user map enabled (RTE-III through RTE-IVB only) - - RTE verification: TBG (address 1674B) = CLK select code - - DOS through DOS-III: - - STF 0 / CCA / CCB / JMP *-3 - - DOS verification: A = B = -1, address 40B = -64, address 67B = +64 - - Note that in DOS, the TBG is set to 100 milliseconds -*/ - - if ((sim_idle_enab) && (intrq == 0)) /* idle enabled w/o pending irq? */ - if (((PC == err_PC) || /* RTE through RTE-IVB */ - ((PC == (err_PC - 1)) && /* RTE-6/VM */ - ((ReadW (PC) & I_MRG) == I_ISZ))) && /* RTE jump target */ - (mp_fence == CLEAR) && (M [xeqt] == 0) && /* RTE idle indications */ - (M [tbg] == clk_dib.select_code) || /* RTE verification */ - - (PC == (err_PC - 3)) && /* DOS through DOS-III */ - (ReadW (PC) == I_STF) && /* DOS jump target */ - (AR == 0177777) && (BR == 0177777) && /* DOS idle indication */ - (M [m64] == 0177700) && /* DOS verification */ - (M [p64] == 0000100)) /* DOS verification */ - - sim_idle (TMR_POLL, FALSE); /* idle the simulator */ - break; - - case 0060:case 0061:case 0062:case 0063: - case 0064:case 0065:case 0066:case 0067: - case 0260:case 0261:case 0262:case 0263: - case 0264:case 0265:case 0266:case 0267: - reason = Ea (IR, &MA, intrq); /* IOR */ - - if (reason != SCPE_OK) /* address failed to resolve? */ - break; /* stop execution */ - - AR = AR | ReadW (MA); - break; - - case 0070:case 0071:case 0072:case 0073: - case 0074:case 0075:case 0076:case 0077: - case 0270:case 0271:case 0272:case 0273: - case 0274:case 0275:case 0276:case 0277: - reason = Ea (IR, &MA, intrq); /* ISZ */ - - if (reason != SCPE_OK) /* address failed to resolve? */ - break; /* stop execution */ - - t = (ReadW (MA) + 1) & DMASK; - WriteW (MA, t); - - if (t == 0) - PC = (PC + 1) & VAMASK; - break; - - case 0100:case 0101:case 0102:case 0103: - case 0104:case 0105:case 0106:case 0107: - case 0300:case 0301:case 0302:case 0303: - case 0304:case 0305:case 0306:case 0307: - reason = Ea (IR, &MA, intrq); /* ADA */ - - if (reason != SCPE_OK) /* address failed to resolve? */ - break; /* stop execution */ - - v1 = ReadW (MA); - t = AR + v1; - - if (t > DMASK) - E = 1; - - if (((~AR ^ v1) & (AR ^ t)) & SIGN) - O = 1; - - AR = t & DMASK; - break; - - case 0110:case 0111:case 0112:case 0113: - case 0114:case 0115:case 0116:case 0117: - case 0310:case 0311:case 0312:case 0313: - case 0314:case 0315:case 0316:case 0317: - reason = Ea (IR, &MA, intrq); /* ADB */ - - if (reason != SCPE_OK) /* address failed to resolve? */ - break; /* stop execution */ - - v1 = ReadW (MA); - t = BR + v1; - - if (t > DMASK) - E = 1; - - if (((~BR ^ v1) & (BR ^ t)) & SIGN) - O = 1; - - BR = t & DMASK; - break; - - case 0120:case 0121:case 0122:case 0123: - case 0124:case 0125:case 0126:case 0127: - case 0320:case 0321:case 0322:case 0323: - case 0324:case 0325:case 0326:case 0327: - reason = Ea (IR, &MA, intrq); /* CPA */ - - if (reason != SCPE_OK) /* address failed to resolve? */ - break; /* stop execution */ - - if (AR != ReadW (MA)) - PC = (PC + 1) & VAMASK; - break; - - case 0130:case 0131:case 0132:case 0133: - case 0134:case 0135:case 0136:case 0137: - case 0330:case 0331:case 0332:case 0333: - case 0334:case 0335:case 0336:case 0337: - reason = Ea (IR, &MA, intrq); /* CPB */ - - if (reason != SCPE_OK) /* address failed to resolve? */ - break; /* stop execution */ - - if (BR != ReadW (MA)) - PC = (PC + 1) & VAMASK; - break; - - case 0140:case 0141:case 0142:case 0143: - case 0144:case 0145:case 0146:case 0147: - case 0340:case 0341:case 0342:case 0343: - case 0344:case 0345:case 0346:case 0347: - reason = Ea (IR, &MA, intrq); /* LDA */ - - if (reason != SCPE_OK) /* address failed to resolve? */ - break; /* stop execution */ - - AR = ReadW (MA); - break; - - case 0150:case 0151:case 0152:case 0153: - case 0154:case 0155:case 0156:case 0157: - case 0350:case 0351:case 0352:case 0353: - case 0354:case 0355:case 0356:case 0357: - reason = Ea (IR, &MA, intrq); /* LDB */ - - if (reason != SCPE_OK) /* address failed to resolve? */ - break; /* stop execution */ - - BR = ReadW (MA); - break; - - case 0160:case 0161:case 0162:case 0163: - case 0164:case 0165:case 0166:case 0167: - case 0360:case 0361:case 0362:case 0363: - case 0364:case 0365:case 0366:case 0367: - reason = Ea (IR, &MA, intrq); /* STA */ - - if (reason != SCPE_OK) /* address failed to resolve? */ - break; /* stop execution */ - - WriteW (MA, AR); - break; - - case 0170:case 0171:case 0172:case 0173: - case 0174:case 0175:case 0176:case 0177: - case 0370:case 0371:case 0372:case 0373: - case 0374:case 0375:case 0376:case 0377: - reason = Ea (IR, &MA, intrq); /* STB */ - - if (reason != SCPE_OK) /* address failed to resolve? */ - break; /* stop execution */ - - WriteW (MA, BR); - break; - -/* Alter/skip instructions */ - - case 0004:case 0005:case 0006:case 0007: - case 0014:case 0015:case 0016:case 0017: - skip = 0; /* no skip */ - - if (IR & 000400) /* CLx */ - t = 0; - else - t = ABREG[absel]; - - if (IR & 001000) /* CMx */ - t = t ^ DMASK; - - if (IR & 000001) { /* RSS? */ - if ((IR & 000040) && (E != 0)) /* SEZ,RSS */ - skip = 1; - - if (IR & 000100) /* CLE */ - E = 0; - - if (IR & 000200) /* CME */ - E = E ^ 1; - - if (((IR & 000030) == 000030) && /* SSx,SLx,RSS */ - ((t & 0100001) == 0100001)) - skip = 1; - - if (((IR & 000030) == 000020) && /* SSx,RSS */ - ((t & SIGN) != 0)) - skip = 1; - - if (((IR & 000030) == 000010) && /* SLx,RSS */ - ((t & 1) != 0)) - skip = 1; - - if (IR & 000004) { /* INx */ - t = (t + 1) & DMASK; - - if (t == 0) - E = 1; - - if (t == SIGN) - O = 1; - } - - if ((IR & 000002) && (t != 0)) /* SZx,RSS */ - skip = 1; - - if ((IR & 000072) == 0) /* RSS */ - skip = 1; - } /* end if RSS */ - - else { - if ((IR & 000040) && (E == 0)) /* SEZ */ - skip = 1; - - if (IR & 000100) /* CLE */ - E = 0; - - if (IR & 000200) /* CME */ - E = E ^ 1; - - if ((IR & 000020) && /* SSx */ - ((t & SIGN) == 0)) - skip = 1; - - if ((IR & 000010) && /* SLx */ - ((t & 1) == 0)) - skip = 1; - - if (IR & 000004) { /* INx */ - t = (t + 1) & DMASK; - - if (t == 0) - E = 1; - - if (t == SIGN) - O = 1; - } - if ((IR & 000002) && (t == 0)) /* SZx */ - skip = 1; - } /* end if ~RSS */ - - ABREG[absel] = t; /* store result */ - PC = (PC + skip) & VAMASK; /* add in skip */ - break; /* end if alter/skip */ - -/* Shift instructions */ - - case 0000:case 0001:case 0002:case 0003: - case 0010:case 0011:case 0012:case 0013: - t = shift (ABREG[absel], IR & 01000, IR >> 6); /* do first shift */ - - if (IR & 000040) /* CLE */ - E = 0; - - if ((IR & 000010) && ((t & 1) == 0)) /* SLx */ - PC = (PC + 1) & VAMASK; - - ABREG[absel] = shift (t, IR & 00020, IR); /* do second shift */ - break; /* end if shift */ - -/* I/O instructions */ - - case 0204:case 0205:case 0206:case 0207: - case 0214:case 0215:case 0216:case 0217: - reason = iogrp (IR, iotrap); /* execute instr */ - break; /* end if I/O */ - -/* Extended arithmetic */ - - case 0200: /* EAU group 0 */ - case 0201: /* divide */ - case 0202: /* EAU group 2 */ - case 0210: /* DLD */ - case 0211: /* DST */ - reason = cpu_eau (IR, intrq); /* extended arith */ - break; - -/* Extended instructions */ - - case 0212: /* UIG 0 extension */ - reason = cpu_uig_0 (IR, intrq, iotrap); /* extended opcode */ - break; - - case 0203: /* UIG 1 extension */ - case 0213: - reason = cpu_uig_1 (IR, intrq, iotrap); /* extended opcode */ - break; - } /* end case IR */ - - if (reason == NOTE_IOG) { /* I/O instr exec? */ - dmarq = calc_dma (); /* recalc DMA masks */ - intrq = calc_int (); /* recalc interrupts */ - reason = SCPE_OK; /* continue */ - } - - else if (reason == NOTE_INDINT) { /* intr pend during indir? */ - PC = err_PC; /* back out of inst */ - reason = SCPE_OK; /* continue */ - } - } /* end while */ - -/* Simulation halted */ - -if (iotrap && (reason == STOP_HALT)) /* HLT in trap cell? */ - MR = intaddr; /* M = interrupt address */ -else /* normal HLT */ - MR = (PC - 1) & VAMASK; /* M = P - 1 */ - -TR = ReadTAB (MR); /* T = last word fetched */ -saved_MR = MR; /* save for T cmd update */ - -if (reason == STOP_HALT) /* programmed halt? */ - cpu_set_ldr (NULL, FALSE, NULL, NULL); /* disable loader (after T is read) */ -else /* simulation stop */ - PC = err_PC; /* back out instruction */ - -dms_upd_sr (); /* update dms_sr */ -dms_upd_vr (MR); /* update dms_vr */ -pcq_r->qptr = pcq_p; /* update pc q ptr */ - -if (dms_enb) /* DMS enabled? */ - if (dms_ump) /* set default */ - sim_brk_dflt = SWMASK ('U'); /* breakpoint type */ - else /* to current */ - sim_brk_dflt = SWMASK ('S'); /* map mode */ - -else /* DMS disabled */ - sim_brk_dflt = SWMASK ('N'); /* set breakpoint type to non-DMS */ - -return reason; /* return status code */ -} - - -/* Resolve indirect addresses. - - An indirect chain is followed until a direct address is obtained. Under - simulation, a maximum number of indirect levels are allowed (typically 16), - after which the instruction will be aborted. - - If the memory protect feature is present, an indirect counter is used that - allows a pending interrupt to be serviced if more than three levels of - indirection are encountered. If MP jumper W6 ("INT") is out and MP is - enabled, then pending interrupts are serviced immediately. When employing - the indirect counter, the hardware clears a pending interrupt deferral after - the third indirection and aborts the instruction after the fourth. -*/ - -t_stat resolve (uint32 MA, uint32 *addr, uint32 irq) -{ -uint32 i; -t_bool pending = (irq && !(mp_unit.flags & DEV_DIS)); -t_bool int_enable = ((mp_unit.flags & UNIT_MP_INT) && mp_control); - -for (i = 0; (i < ind_max) && (MA & I_IA); i++) { /* resolve multilevel */ - if (pending) { /* interrupt pending and MP enabled? */ - if ((i == 2) || int_enable) /* 3rd level indirect or INT out? */ - ion_defer = FALSE; /* reenable interrrupts */ - if ((i > 2) || int_enable) /* 4th or higher or INT out? */ - return NOTE_INDINT; /* break out now */ - } - - MA = ReadW (MA & VAMASK); /* follow address chain */ - } - -if (MA & I_IA) /* indirect loop? */ - return STOP_IND; /* stop simulation */ - -*addr = MA; -return SCPE_OK; -} - - -/* Get effective address from IR */ - -static t_stat Ea (uint32 IR, uint32 *addr, uint32 irq) -{ -uint32 MA; - -MA = IR & (I_IA | I_DISP); /* ind + disp */ - -if (IR & I_CP) /* current page? */ - MA = ((PC - 1) & I_PAGENO) | MA; /* merge in page from PC */ - -return resolve (MA, addr, irq); /* resolve indirects */ -} - - -/* Shift micro operation */ - -static uint32 shift (uint32 t, uint32 flag, uint32 op) -{ -uint32 oldE; - -op = op & 07; /* get shift op */ -if (flag) { /* enabled? */ - switch (op) { /* case on operation */ - - case 00: /* signed left shift */ - return ((t & SIGN) | ((t << 1) & 077777)); - - case 01: /* signed right shift */ - return ((t & SIGN) | (t >> 1)); - - case 02: /* rotate left */ - return (((t << 1) | (t >> 15)) & DMASK); - - case 03: /* rotate right */ - return (((t >> 1) | (t << 15)) & DMASK); - - case 04: /* left shift, 0 sign */ - return ((t << 1) & 077777); - - case 05: /* ext right rotate */ - oldE = E; - E = t & 1; - return ((t >> 1) | (oldE << 15)); - - case 06: /* ext left rotate */ - oldE = E; - E = (t >> 15) & 1; - return (((t << 1) | oldE) & DMASK); - - case 07: /* rotate left four */ - return (((t << 4) | (t >> 12)) & DMASK); - } /* end case */ - } /* end if */ - -if (op == 05) /* disabled ext rgt rot */ - E = t & 1; - -if (op == 06) /* disabled ext lft rot */ - E = (t >> 15) & 1; - -return t; /* input unchanged */ -} - - -/* I/O instruction decode. - - If memory protect is enabled, and the instruction is not in a trap cell, then - HLT instructions are illegal and will cause a memory protect violation. If - jumper W7 (SEL1) is in, then all other I/O instructions are legal; if W7 is - out, then only I/O instructions to select code 1 are legal, and I/O to other - select codes will cause a violation. - - If the instruction is allowed, then the I/O signal corresponding to the - instruction is determined, the state of the interrupt deferral flag is set. - Then the signal is dispatched to the device simulator indicated by the target - select code. The return value is split into status and data values, with the - latter containing the SKF signal state or data to be returned in the A or B - registers. - - Implementation notes: - - 1. If the H/C (hold/clear flag) bit is set, then the ioCLF signal is added - (not ORed) to the base signal derived from the I/O instruction. - - 2. ioNONE is dispatched for HLT instructions because although HLT does not - assert any backplane signals, the H/C bit may be set. If it is, then the - result will be to dispatch ioCLF. - - 3. Device simulators return either ioSKF or ioNONE in response to an SFC or - SFS signal. ioSKF means that the instruction should skip. Because - device simulators return the "data" parameter value by default, we - initialize that parameter to ioNONE to ensure that a simulator that does - not implement SFC or SFS does not skip, which is the correct action for - an interface that does not drive the SKF signal. - - 4. STF/CLF and STC/CLC share sub-opcode values and must be further decoded - by the state of instruction register bits 9 and 11, respectively. - - 5. We return NOTE_IOG for normal status instead of SCPE_OK to request that - interrupts be recalculated at the end of the instruction (execution of - the I/O group instructions can change the interrupt priority chain). -*/ - -t_stat iogrp (uint32 ir, uint32 iotrap) -{ - -/* Translation for I/O subopcodes: soHLT, soFLG, soSFC, soSFS, soMIX, soLIX, soOTX, soCTL */ -static const IOSIGNAL generate_signal [] = { ioNONE, ioSTF, ioSFC, ioSFS, ioIOI, ioIOI, ioIOO, ioSTC }; - -const uint32 dev = ir & I_DEVMASK; /* device select code */ -const uint32 sop = I_GETIOOP (ir); /* I/O subopcode */ -const uint32 ab = (ir & I_AB) != 0; /* A/B register select */ -const t_bool clf = (ir & I_HC) != 0; /* H/C flag select */ -uint16 iodata = (uint16) ioNONE; /* initialize for SKF test */ -uint32 ioreturn; -t_stat iostat; -IOCYCLE signal_set; - -if (!iotrap && mp_control && /* instr not in trap cell and MP on? */ - ((sop == soHLT) || /* and is HLT? */ - ((dev != OVF) && (mp_unit.flags & UNIT_MP_SEL1)))) { /* or is not SC 01 and SEL1 out? */ - if (sop == soLIX) /* MP violation; is LIA/B instruction? */ - ABREG [ab] = 0; /* A/B writes anyway */ - - MP_ABORT (err_PC); /* MP abort */ - } - -signal_set = generate_signal [sop]; /* generate I/O signal from instruction */ -ion_defer = defer_tab [sop]; /* defer depending on instruction */ - -if (sop == soOTX) /* OTA/B instruction? */ - iodata = ABREG [ab]; /* pass A/B register value */ - -else if ((sop == soCTL) && (ir & I_CTL)) /* CLC instruction? */ - signal_set = ioCLC; /* change STC to CLC signal */ - -if ((sop == soFLG) && clf) /* CLF instruction? */ - signal_set = ioCLF; /* change STF to CLF signal */ - -else if (clf) /* CLF with another instruction? */ - signal_set = signal_set | ioCLF; /* add CLF signal */ - -ioreturn = devdisp (dev, signal_set, IORETURN (SCPE_OK, iodata)); /* dispatch I/O signal */ - -iostat = IOSTATUS (ioreturn); /* extract status */ -iodata = IODATA (ioreturn); /* extract return data value */ - -if (((sop == soSFC) || (sop == soSFS)) && /* testing flag state? */ - ((IOSIGNAL) iodata == ioSKF)) /* and SKF asserted? */ - PC = (PC + 1) & VAMASK; /* bump P to skip next instruction */ - -else if (sop == soLIX) /* LIA/B instruction? */ - ABREG [ab] = iodata; /* load returned data */ - -else if (sop == soMIX) /* MIA/B instruction? */ - ABREG [ab] = ABREG [ab] | iodata; /* merge returned data */ - -else if (sop == soHLT) { /* HLT instruction? */ - const int32 len = strlen (halt_msg); /* find end msg */ - sprintf (&halt_msg[len - 6], "%06o", ir); /* add the halt */ - return STOP_HALT; - } - -if (iostat == SCPE_OK) /* normal status? */ - return NOTE_IOG; /* request interrupt recalc */ -else /* abnormal status */ - return iostat; /* return it */ -} - - -/* Device I/O signal dispatcher */ - -static uint32 devdisp (uint32 select_code, IOCYCLE signal_set, uint16 data) -{ -return dtab [select_code]->io_handler (dtab [select_code], - signal_set, - IORETURN (SCPE_OK, data)); -} - - -/* Calculate DMA requests */ - -static uint32 calc_dma (void) -{ -uint32 r = 0; - -if (dma [ch1].xferen && SRQ (dma [ch1].cw1 & I_DEVMASK)) /* check DMA1 cycle */ - r = r | DMA_1_REQ; -if (dma [ch2].xferen && SRQ (dma [ch2].cw1 & I_DEVMASK)) /* check DMA2 cycle */ - r = r | DMA_2_REQ; -return r; -} - - -/* Determine whether a pending interrupt deferral should be inhibited. - - Execution of certain instructions generally cause a pending interrupt to be - deferred until the succeeding instruction completes. However, the interrupt - deferral rules differ on the 21xx vs. the 1000. - - The 1000 always defers until the completion of the instruction following a - deferring instruction. The 21xx defers unless the following instruction is - an MRG instruction other than JMP or JMP,I or JSB,I. If it is, then the - deferral is inhibited, i.e., the pending interrupt will be serviced. - - See the "Set Phase Logic Flowchart," transition from phase 1A to phase 1B, - and the "Theory of Operation," "Control Section Detailed Theory," "Phase - Control Logic," "Phase 1B" paragraph in the Model 2100A Computer Installation - and Maintenance Manual for details. -*/ - -t_bool calc_defer (void) -{ -uint16 IR; - -if (UNIT_CPU_FAMILY == UNIT_FAMILY_21XX) { /* 21xx series? */ - IR = ReadW (PC); /* prefetch next instr */ - - if (((IR & I_MRG & ~I_AB) != 0000000) && /* is MRG instruction? */ - ((IR & I_MRG_I) != I_JSB_I) && /* but not JSB,I? */ - ((IR & I_MRG) != I_JMP)) /* and not JMP or JMP,I? */ - return FALSE; /* yes, so inhibit deferral */ - else - return TRUE; /* no, so allow deferral */ - } -else - return TRUE; /* 1000 always allows deferral */ -} - - -/* Calculate interrupt requests. - - The interrupt request (IRQ) of the highest-priority device for which all - higher-priority PRL bits are set is granted. That is, there must be an - unbroken chain of priority to a device requesting an interrupt for that - request to be granted. - - A device sets its IRQ bit to request an interrupt, and it clears its PRL bit - to prevent lower-priority devices from interrupting. IRQ is cleared by an - interrupt acknowledge (IAK) signal. PRL generally remains low while a - device's interrupt service routine is executing to prevent preemption. - - IRQ and PRL indicate one of four possible states for a device: - - IRQ PRL Device state - --- --- ---------------------- - 0 1 Not interrupting - 1 0 Interrupt requested - 0 0 Interrupt acknowledged - 1 1 (not allowed) - - Note that PRL must be dropped when requesting an interrupt (IRQ set). This - is a hardware requirement of the 1000 series. The IRQ lines from the - backplane are not priority encoded. Instead, the PRL chain expresses the - priority by allowing only one IRQ line to be active at a time. This allows a - simple pull-down encoding of the CIR inputs. - - The end of priority chain is marked by the highest-priority (lowest-order) - bit that is clear. The device corresponding to that bit is the only device - that may interrupt (a higher priority device that had IRQ set would also have - had PRL set, which is a state violation). We calculate a priority mask by - ANDing the complement of the PRL bits with an increment of the PRL bits. - Only the lowest-order bit will differ. For example: - - dev_prl : ...1 1 0 1 1 0 1 1 1 1 1 1 (PRL denied for SC 06 and 11) - - dev_prl + 1 : ...1 1 0 1 1 1 0 0 0 0 0 0 - ~dev_prl : ...0 0 1 0 0 1 0 0 0 0 0 0 - ANDed value : ...0 0 0 0 0 1 0 0 0 0 0 0 (break is at SC 06) - - The interrupt requests are then ANDed with the priority mask to determine if - a request is pending: - - pri mask : ...0 0 0 0 0 1 0 0 0 0 0 0 (allowed interrupt source) - dev_irq : ...0 0 1 0 0 1 0 0 0 0 0 0 (devices requesting interrupts) - ANDed value : ...0 0 0 0 0 1 0 0 0 0 0 0 (request to grant) - - The select code corresponding to the granted request is then returned to the - caller. - - If ION is clear, only power fail (SC 04) and parity error (SC 05) are - eligible to interrupt (memory protect shares SC 05, but qualification occurs - in the MP abort handler, so if SC 05 is interrupting when ION is clear, it - must be a parity error interrupt). -*/ - -uint32 calc_int (void) -{ -uint32 sc, pri_mask [2], req_grant [2]; - -pri_mask [0] = ~dev_prl [0] & (dev_prl [0] + 1); /* calculate lower priority mask */ -req_grant [0] = pri_mask [0] & dev_irq [0]; /* calculate lower request to grant */ - -if (ion) /* interrupt system on? */ - if ((req_grant [0] == 0) && (pri_mask [0] == 0)) { /* no requests in lower set and PRL unbroken? */ - pri_mask [1] = ~dev_prl [1] & (dev_prl [1] + 1); /* calculate upper priority mask */ - req_grant [1] = pri_mask [1] & dev_irq [1]; /* calculate upper request to grant */ - } - else /* lower set has request */ - req_grant [1] = 0; /* no grants to upper set */ - -else { /* interrupt system off */ - req_grant [0] = req_grant [0] & /* only PF and PE can interrupt */ - (BIT_M (PWR) | BIT_M (PRO)); - req_grant [1] = 0; - } - -if (req_grant [0]) /* device in lower half? */ - for (sc = 0; sc <= 31; sc++) /* determine interrupting select code */ - if (req_grant [0] & 1) /* grant this request? */ - return sc; /* return this select code */ - else /* not this one */ - req_grant [0] = req_grant [0] >> 1; /* position next request */ - -else if (req_grant [1]) /* device in upper half */ - for (sc = 32; sc <= 63; sc++) /* determine interrupting select code */ - if (req_grant [1] & 1) /* grant this request? */ - return sc; /* return this select code */ - else /* not this one */ - req_grant [1] = req_grant [1] >> 1; /* position next request */ - -return 0; /* no interrupt granted */ -} - - -/* Memory access routines. - - These routines access memory for reads and writes. They validate the - accesses for MP and MEM violations, if enabled. The following routines are - provided: - - - ReadPW : Read a word using a physical address - - ReadB : Read a byte using the current map - - ReadBA : Read a byte using the alternate map - - ReadW : Read a word using the current map - - ReadWA : Read a word using the alternate map - - ReadIO : Read a word using the specified map without protection - - ReadTAB : Read a word using the current map without protection - - - WritePW : Write a word using a physical address - - WriteB : Write a byte using the current map - - WriteBA : Write a byte using the alternate map - - WriteW : Write a word using the current map - - WriteWA : Write a word using the alternate map - - WriteIO : Write a word using the specified map without protection - - The memory protect (MP) and memory expansion module (MEM) accessories provide - a protected mode that guards against improper accesses by user programs. - They may be enabled or disabled independently, although protection requires - that both be enabled. MP checks that memory writes do not fall below the - Memory Protect Fence Register (MPFR) value, and MEM checks that read/write - protection rules on the target page are compatible with the access desired. - If either check fails, and MP is enabled, then the request is aborted. - - Each mapped routine calls "dms" if DMS is enabled to translate the logical - address supplied to a physical address. "dms" performs a protection check - and aborts without returning if the check fails. The write routines perform - an additional memory-protect check and abort if a violation occurs (so, to - pass, a page must be writable AND the target must be above the MP fence). - - Note that MP uses a lower bound of 2 for memory writes, allowing unrestricted - access to the A and B registers (addressed as locations 0 and 1). -*/ - -#define MP_TEST(va) (mp_control && ((va) >= 2) && ((va) < mp_fence)) - - -/* Read a word using a physical address */ - -uint16 ReadPW (uint32 pa) -{ -if (pa <= 1) /* read locations 0 or 1? */ - return ABREG[pa]; /* return A/B register */ -else /* location >= 2 */ - return M[pa]; /* return physical memory value */ -} - - -/* Read a byte using the current map */ - -uint8 ReadB (uint32 va) -{ -int32 pa; - -if (dms_enb) /* MEM enabled? */ - pa = dms (va >> 1, dms_ump, RDPROT); /* translate address */ -else /* MEM disabled */ - pa = va >> 1; /* use logical as physical address */ - -if (va & 1) /* low byte addressed? */ - return (ReadPW (pa) & 0377); /* mask to lower byte */ -else /* high byte addressed */ - return ((ReadPW (pa) >> 8) & 0377); /* position higher byte and mask */ -} - - -/* Read a byte using the alternate map */ - -uint8 ReadBA (uint32 va) -{ -uint32 pa; - -if (dms_enb) /* MEM enabled? */ - pa = dms (va >> 1, dms_ump ^ MAP_LNT, RDPROT); /* translate address using alternate map */ -else /* MEM disabled */ - pa = va >> 1; /* use logical as physical address */ - -if (va & 1) /* low byte addressed? */ - return (ReadPW (pa) & 0377); /* mask to lower byte */ -else /* high byte addressed */ - return ((ReadPW (pa) >> 8) & 0377); /* position higher byte and mask */ -} - - -/* Read a word using the current map */ - -uint16 ReadW (uint32 va) -{ -uint32 pa; - -if (dms_enb) /* MEM enabled? */ - pa = dms (va, dms_ump, RDPROT); /* translate address */ -else /* MEM disabled */ - pa = va; /* use logical as physical address */ - -return ReadPW (pa); /* return word */ -} - - -/* Read a word using the alternate map */ - -uint16 ReadWA (uint32 va) -{ -uint32 pa; - -if (dms_enb) /* MEM enabled? */ - pa = dms (va, dms_ump ^ MAP_LNT, RDPROT); /* translate address using alternate map */ -else /* MEM disabled */ - pa = va; /* use logical as physical address */ - -return ReadPW (pa); /* return word */ -} - - -/* Read a word using the specified map without protection */ - -uint16 ReadIO (uint32 va, uint32 map) -{ -uint32 pa; - -if (dms_enb) /* MEM enabled? */ - pa = dms (va, map, NOPROT); /* translate address with no protection */ -else /* MEM disabled */ - pa = va; /* use logical as physical address */ - -return M[pa]; /* return word without A/B interception */ -} - - -/* Read a word using the current map without protection */ - -static uint16 ReadTAB (uint32 va) -{ -uint32 pa; - -if (dms_enb) /* MEM enabled? */ - pa = dms (va, dms_ump, NOPROT); /* translate address with no protection */ -else /* MEM disabled */ - pa = va; /* use logical as physical address */ - -return ReadPW (pa); /* return word */ -} - - -/* Write a word using a physical address */ - -void WritePW (uint32 pa, uint32 dat) -{ -if (pa <= 1) /* write locations 0 or 1? */ - ABREG[pa] = dat & DMASK; /* store A/B register */ -else if (pa < fwanxm) /* 2 <= location <= LWA memory? */ - M[pa] = dat & DMASK; /* store physical memory value */ - -return; -} - - -/* Write a byte using the current map */ - -void WriteB (uint32 va, uint32 dat) -{ -uint32 pa, t; - -if (dms_enb) /* MEM enabled? */ - pa = dms (va >> 1, dms_ump, WRPROT); /* translate address */ -else /* MEM disabled */ - pa = va >> 1; /* use logical as physical address */ - -if (MP_TEST (va >> 1)) /* MPCK? */ - MP_ABORT (va >> 1); /* MP violation */ - -t = ReadPW (pa); /* get word */ - -if (va & 1) /* low byte addressed? */ - t = (t & 0177400) | (dat & 0377); /* merge in lower byte */ -else /* high byte addressed */ - t = (t & 0377) | ((dat & 0377) << 8); /* position higher byte and merge */ - -WritePW (pa, t); /* store word */ -return; -} - - -/* Write a byte using the alternate map */ - -void WriteBA (uint32 va, uint32 dat) -{ -uint32 pa, t; - -if (dms_enb) { /* MEM enabled? */ - dms_viol (va >> 1, MVI_WPR); /* always a violation if protected */ - pa = dms (va >> 1, dms_ump ^ MAP_LNT, WRPROT); /* translate address using alternate map */ - } -else /* MEM disabled */ - pa = va >> 1; /* use logical as physical address */ - -if (MP_TEST (va >> 1)) /* MPCK? */ - MP_ABORT (va >> 1); /* MP violation */ - -t = ReadPW (pa); /* get word */ - -if (va & 1) /* low byte addressed? */ - t = (t & 0177400) | (dat & 0377); /* merge in lower byte */ -else /* high byte addressed */ - t = (t & 0377) | ((dat & 0377) << 8); /* position higher byte and merge */ - -WritePW (pa, t); /* store word */ -return; -} - - -/* Write a word using the current map */ - -void WriteW (uint32 va, uint32 dat) -{ -uint32 pa; - -if (dms_enb) /* MEM enabled? */ - pa = dms (va, dms_ump, WRPROT); /* translate address */ -else /* MEM disabled */ - pa = va; /* use logical as physical address */ - -if (MP_TEST (va)) /* MPCK? */ - MP_ABORT (va); /* MP violation */ - -WritePW (pa, dat); /* store word */ -return; -} - - -/* Write a word using the alternate map */ - -void WriteWA (uint32 va, uint32 dat) -{ -int32 pa; - -if (dms_enb) { /* MEM enabled? */ - dms_viol (va, MVI_WPR); /* always a violation if protected */ - pa = dms (va, dms_ump ^ MAP_LNT, WRPROT); /* translate address using alternate map */ - } -else /* MEM disabled */ - pa = va; /* use logical as physical address */ - -if (MP_TEST (va)) /* MPCK? */ - MP_ABORT (va); /* MP violation */ - -WritePW (pa, dat); /* store word */ -return; -} - - -/* Write a word using the specified map without protection */ - -void WriteIO (uint32 va, uint32 dat, uint32 map) -{ -uint32 pa; - -if (dms_enb) /* MEM enabled? */ - pa = dms (va, map, NOPROT); /* translate address with no protection */ -else /* MEM disabled */ - pa = va; /* use logical as physical address */ - -if (pa < fwanxm) - M[pa] = dat & DMASK; /* store word without A/B interception */ -return; -} - - -/* Mapped access check. - - Returns TRUE if the address will be mapped (presuming MEM is enabled). -*/ - -static t_bool is_mapped (uint32 va) -{ -uint32 dms_fence; - -if (va >= 02000) /* above the base bage? */ - return TRUE; /* always mapped */ -else { - dms_fence = dms_sr & MST_FENCE; /* get BP fence value */ - return (dms_sr & MST_FLT) ? (va < dms_fence) : /* below BP fence and lower portion mapped? */ - (va >= dms_fence); /* or above BP fence and upper portion mapped? */ - } -} - - -/* DMS relocation. - - This routine translates logical into physical addresses. It must be called - only when DMS is enabled, as that condition is not checked. The logical - address, desired map, and desired access type are supplied. If the access is - legal, the mapped physical address is returned; if it is not, then a MEM - violation is indicated. - - The current map may be specified by passing "dms_ump" as the "map" parameter, - or a specific map may be used. Normally, read and write accesses pass RDPROT - or WRPROT as the "prot" parameter to request access checking. For DMA - accesses, NOPROT must be passed to inhibit access checks. - - This routine checks for read, write, and base-page violations and will call - "dms_viol" as appropriate. The latter routine will abort if MP is enabled, - or will return if protection is off. -*/ - -static uint32 dms (uint32 va, uint32 map, uint32 prot) -{ -uint32 pgn, mpr; - -if (va <= 1) /* reference to A/B register? */ - return va; /* use address */ - -if (!is_mapped (va)) { /* unmapped? */ - if ((va >= 2) && (prot == WRPROT)) /* base page write access? */ - dms_viol (va, MVI_BPG); /* signal a base page violation */ - return va; /* use unmapped address */ - } - -pgn = VA_GETPAG (va); /* get page num */ -mpr = dms_map[map + pgn]; /* get map reg */ - -if (mpr & prot) /* desired access disallowed? */ - dms_viol (va, prot); /* signal protection violation */ - -return (MAP_GETPAG (mpr) | VA_GETOFF (va)); /* return mapped address */ -} - - -/* DMS relocation for console access. - - Console access allows the desired map to be specified by switches on the - command line. All protection checks are off for console access. - - This routine is called to restore a saved configuration, and mapping is not - used for restoration. -*/ - -static uint32 dms_cons (uint32 va, int32 sw) -{ -uint32 map_sel; - -if ((dms_enb == 0) || /* DMS off? */ - (sw & (SWMASK ('N') | SIM_SW_REST))) /* no mapping rqst or save/rest? */ - return va; /* use physical address */ - -else if (sw & SWMASK ('S')) - map_sel = SMAP; - -else if (sw & SWMASK ('U')) - map_sel = UMAP; - -else if (sw & SWMASK ('P')) - map_sel = PAMAP; - -else if (sw & SWMASK ('Q')) - map_sel = PBMAP; - -else /* dflt to log addr, cur map */ - map_sel = dms_ump; - -if (va >= VASIZE) /* virtual, must be 15b */ - return MEMSIZE; - -else if (dms_enb) /* DMS on? go thru map */ - return dms (va, map_sel, NOPROT); - -else /* else return virtual */ - return va; -} - - -/* Memory protect and DMS validation for jumps. - - Jumps are a special case of write validation. The target address is treated - as a write, even when no physical write takes place, so jumping to a - write-protected page causes a MEM violation. In addition, a MEM violation is - indicated if the jump is to the unmapped portion of the base page. Finally, - jumping to a location under the memory-protect fence causes an MP violation. - - Because the MP and MEM hardware works in parallel, all three violations may - exist concurrently. For example, a JMP to the unmapped portion of the base - page that is write protected and under the MP fence will indicate a - base-page, write, and MP violation, whereas a JMP to the mapped portion will - indicate a write and MP violation (BPV is inhibited by the MEBEN signal). If - MEM and MP violations occur concurrently, the MEM violation takes precedence, - as the SFS and SFC instructions test the MEV flip-flop. - - The lower bound of protected memory is passed in the "plb" argument. This - must be either 0 or 2. All violations are qualified by the MPCND signal, - which responds to the lower bound. Therefore, if the lower bound is 2, and - if the part below the base-page fence is unmapped, or if the base page is - write-protected, then a MEM violation will occur only if the access is not to - locations 0 or 1. The instruction set firmware uses a lower bound of 0 for - JMP, JLY, and JPY (and for JSB with W5 out), and of 2 for DJP, SJP, UJP, JRS, - and .GOTO (and JSB with W5 in). - - Finally, all violations are inhibited if MP is off (mp_control is CLEAR), and - MEM violations are inhibited if the MEM is disabled. -*/ - -void mp_dms_jmp (uint32 va, uint32 plb) -{ -uint32 violation = 0; -uint32 pgn = VA_GETPAG (va); /* get page number */ - -if (mp_control) { /* MP on? */ - if (dms_enb) { /* MEM on? */ - if (dms_map [dms_ump + pgn] & WRPROT) /* page write protected? */ - violation = MVI_WPR; /* write violation occured */ - - if (!is_mapped (va) && (va >= plb)) /* base page target? */ - violation = violation | MVI_BPG; /* base page violation occured */ - - if (violation) /* any violation? */ - dms_viol (va, violation); /* signal MEM violation */ - } - - if ((va >= plb) && (va < mp_fence)) /* jump under fence? */ - MP_ABORT (va); /* signal MP violation */ - } - -return; -} - - -/* DMS read and write map registers */ - -uint16 dms_rmap (uint32 mapi) -{ -mapi = mapi & MAP_MASK; -return (dms_map[mapi] & ~MAP_RSVD); -} - -void dms_wmap (uint32 mapi, uint32 dat) -{ -mapi = mapi & MAP_MASK; -dms_map[mapi] = (uint16) (dat & ~MAP_RSVD); -return; -} - - -/* Process a MEM violation. - - A MEM violation will report the cause in the violation register. This occurs - even if the MEM is not in the protected mode (i.e., MP is not enabled). If - MP is enabled, an MP abort is taken with the MEV flip-flop set. Otherwise, - we return to the caller. -*/ - -void dms_viol (uint32 va, uint32 st) -{ -dms_vr = st | dms_upd_vr (va); /* set violation cause in register */ - -if (mp_control) { /* memory protect on? */ - mp_mevff = SET; /* record memory expansion violation */ - MP_ABORT (va); /* abort */ - } -return; -} - - -/* Update the MEM violation register. - - In hardware, the MEM violation register (VR) is clocked on every memory read, - every memory write above the lower bound of protected memory, and every - execution of a privileged DMS instruction. The register is not clocked when - MP is disabled by an MP or MEM error (i.e., when MEVFF sets or CTL5FF - clears), in order to capture the state of the MEM. In other words, the VR - continually tracks the memory map register accessed plus the MEM state - (MEBEN, MAPON, and USR) until a violation occurs, and then it's "frozen." - - Under simulation, we do not have to update the VR on every memory access, - because the visible state is only available via a programmed RVA/B - instruction or via the SCP interface. Therefore, it is sufficient if the - register is updated: - - - at a MEM violation (when freezing) - - at an MP violation (when freezing) - - during RVA/B execution (if not frozen) - - before returning to SCP after a simulator stop (if not frozen) -*/ - -uint32 dms_upd_vr (uint32 va) -{ -if (mp_control && (mp_mevff == CLEAR)) { /* violation register unfrozen? */ - dms_vr = VA_GETPAG (va) | /* set map address */ - (dms_enb ? MVI_MEM : 0) | /* and MEM enabled */ - (dms_ump ? MVI_UMP : 0); /* and user map enabled */ - - if (is_mapped (va)) /* is addressed mapped? */ - dms_vr = dms_vr | MVI_MEB; /* ME bus is enabled */ - } - -return dms_vr; -} - - -/* Update the MEM status register */ - -uint32 dms_upd_sr (void) -{ -dms_sr = dms_sr & ~(MST_ENB | MST_UMP | MST_PRO); - -if (dms_enb) - dms_sr = dms_sr | MST_ENB; - -if (dms_ump) - dms_sr = dms_sr | MST_UMP; - -if (mp_control) - dms_sr = dms_sr | MST_PRO; - -return dms_sr; -} - - -/* CPU (SC 0) I/O signal handler. - - I/O instructions for select code 0 manipulate the interrupt system. STF and - CLF turn the interrupt system on and off, and SFS and SFC test the state of - the interrupt system. When the interrupt system is off, only power fail and - parity error interrupts are allowed. - - A PON reset initializes certain CPU registers. The 1000 series does a - microcoded memory clear and leaves the T and P registers set as a result. - - Front-panel PRESET performs additional initialization. We also handle MEM - preset here. - - Implementation notes: - - 1. An IOI signal reads the floating I/O bus (0 on all machines). - - 2. A CLC 0 issues CRS to all devices, not CLC. While most cards react - identically to CRS and CLC, some do not, e.g., the 12566B when used as an - I/O diagnostic target. - - 3. RTE uses the undocumented SFS 0,C instruction to both test and turn off - the interrupt system. This is confirmed in the "RTE-6/VM Technical - Specifications" manual (HP 92084-90015), section 2.3.1 "Process the - Interrupt", subsection "A.1 $CIC": - - "Test to see if the interrupt system is on or off. This is done with - the SFS 0,C instruction. In either case, turn it off (the ,C does - it)." - - ...and in section 5.8, "Parity Error Detection": - - "Because parity error interrupts can occur even when the interrupt - system is off, the code at $CIC must be able to save the complete - system status. The major hole in being able to save the complete state - is in saving the interrupt system state. In order to do this in both - the 21MX and the 21XE the instruction 103300 was used to both test the - interrupt system and turn it off." - - 4. Select code 0 cannot interrupt, so there is no SIR handler. -*/ - -uint32 cpuio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) -{ -uint32 sc; -IOSIGNAL signal; -IOCYCLE working_set = signal_set; /* no SIR handler needed */ - -while (working_set) { - signal = IONEXT (working_set); /* isolate next signal */ - - switch (signal) { /* dispatch I/O signal */ - - case ioCLF: /* clear flag flip-flop */ - ion = CLEAR; /* turn interrupt system off */ - break; - - case ioSTF: /* set flag flip-flop */ - ion = SET; /* turn interrupt system on */ - break; - - case ioSFC: /* skip if flag is clear */ - setSKF (!ion); /* skip if interrupt system is off */ - break; - - case ioSFS: /* skip if flag is set */ - setSKF (ion); /* skip if interupt system is on */ - break; - - case ioIOI: /* I/O input */ - stat_data = IORETURN (SCPE_OK, 0); /* returns 0 */ - break; - - case ioPON: /* power on normal */ - AR = 0; /* clear A register */ - BR = 0; /* clear B register */ - SR = 0; /* clear S register */ - TR = 0; /* clear T register */ - E = 1; /* set E register */ - - if (UNIT_CPU_FAMILY == UNIT_FAMILY_1000) { /* 1000 series? */ - memset (M, 0, MEMSIZE * 2); /* zero allocated memory */ - MR = 0077777; /* set M register */ - PC = 0100000; /* set P register */ - } - - else { /* 21xx series */ - MR = 0; /* clear M register */ - PC = 0; /* clear P register */ - } - break; - - case ioPOPIO: /* power-on preset to I/O */ - O = 0; /* clear O register */ - ion = CLEAR; /* turn off interrupt system */ - ion_defer = FALSE; /* clear interrupt deferral */ - - dms_enb = 0; /* turn DMS off */ - dms_ump = 0; /* init to system map */ - dms_sr = 0; /* clear status register and BP fence */ - dms_vr = 0; /* clear violation register */ - break; - - case ioCLC: /* clear control flip-flop */ - for (sc = CRSDEV; sc <= MAXDEV; sc++) /* send CRS to devices */ - devdisp (sc, ioCRS, 0); /* from select code 6 and up */ - break; - - default: /* all other signals */ - break; /* are ignored */ - } - - working_set = working_set & ~signal; /* remove current signal from set */ - } - -return stat_data; -} - - -/* Overflow/S-register (SC 1) I/O signal handler. - - Flag instructions directed to select code 1 manipulate the overflow (O) - register. Input and output instructions access the switch (S) register. On - the 2115 and 2116, there is no S-register indicator, so it is effectively - read-only. On the other machines, a front-panel display of the S-register is - provided. On all machines, front-panel switches are provided to set the - contents of the S register. - - Implementation notes: - - 1. Select code 1 cannot interrupt, so there is no SIR handler. -*/ - -uint32 ovflio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) -{ -IOSIGNAL signal; -IOCYCLE working_set = signal_set; /* no SIR handler needed */ - -while (working_set) { - signal = IONEXT (working_set); /* isolate next signal */ - - switch (signal) { /* dispatch I/O signal */ - - case ioCLF: /* clear flag flip-flop */ - O = 0; /* clear overflow */ - break; - - case ioSTF: /* set flag flip-flop */ - O = 1; /* set overflow */ - break; - - case ioSFC: /* skip if flag is clear */ - setSKF (!O); /* skip if overflow is clear */ - break; - - case ioSFS: /* skip if flag is set */ - setSKF (O); /* skip if overflow is set */ - break; - - case ioIOI: /* I/O input */ - stat_data = IORETURN (SCPE_OK, SR); /* read switch register value */ - break; - - case ioIOO: /* I/O output */ - if ((UNIT_CPU_MODEL != UNIT_2116) && /* no S register display on */ - (UNIT_CPU_MODEL != UNIT_2115)) /* 2116 and 2115 machines */ - SR = IODATA (stat_data); /* write S register value */ - break; - - default: /* all other signals */ - break; /* are ignored */ - } - - working_set = working_set & ~signal; /* remove current signal from set */ - } - -return stat_data; -} - - -/* Power fail (SC 4) I/O signal handler. - - Power fail detection is standard on 2100 and 1000 systems and is optional on - 21xx systems. Power fail recovery is standard on the 2100 and optional on - the others. Power failure or restoration will cause an interrupt on select - code 4. The direction of power change (down or up) can be tested by SFC. - - We do not implement power fail under simulation. However, the central - interrupt register (CIR) is always read by an IOI directed to select code 4. -*/ - -uint32 pwrfio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) -{ -IOSIGNAL signal; -IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ - -while (working_set) { - signal = IONEXT (working_set); /* isolate next signal */ - - switch (signal) { /* dispatch I/O signal */ - - case ioSTC: /* set control flip-flop */ - break; /* reinitializes power fail */ - - case ioCLC: /* clear control flip-flop */ - break; /* reinitializes power fail */ - - case ioSFC: /* skip if flag is clear */ - break; /* skips if power fail occurred */ - - case ioIOI: /* I/O input */ - stat_data = IORETURN (SCPE_OK, intaddr); /* input CIR value */ - break; - - default: /* all other signals */ - break; /* are ignored */ - } - - working_set = working_set & ~signal; /* remove current signal from set */ - } - -return stat_data; -} - - -/* Memory protect/parity error (SC 5) I/O signal handler. - - The memory protect card has a number of non-standard features: - - - CLF and STF affect the parity error enable flip-flop, not the flag - - SFC and SFS test the memory expansion violation flip-flop, not the flag - - POPIO clears control, flag, and flag buffer instead of setting the flags - - CLC does not clear control (the only way to turn off MP is to cause a - violation) - - PRL and IRQ are a function of the flag only, not flag and control - - IAK is used unqualified by IRQ - - The IAK backplane signal is asserted when any interrupt is acknowledged by - the CPU. Normally, an interface qualifies IAK with its own IRQ to ensure - that it responds only to an acknowledgement of its own request. The MP card - does this to reset its flag buffer and flag flip-flops, and to reset the - parity error indication. However, it also responds to an unqualified IAK - (i.e., for any interface) as follows: - - - clears the MPV flip-flop - - clears the indirect counter - - clears the control flip-flop - - sets the INTPT flip-flop - - The INTPT flip-flop indicates an occurrence of an interrupt. If the trap - cell of the interrupting device contains an I/O instruction that is not a - HLT, action equivalent to STC 05 is taken, i.e.: - - - sets the control flip-flop - - set the EVR flip-flop - - clears the MEV flip-flop - - clears the PARERR flip-flop - - In other words, an interrupt for any device will disable MP unless the trap - cell contains an I/O instruction other than a HLT. - - Implementation notes: - - 1. Because the card uses IAK unqualified, this routine is called whenever - any interrupt occurs. If the MP card itself is not interrupting, the - select code passed will not be SC 05. In either case, the trap cell - instruction is passed in the data portion of the "stat_data" parameter. - - 2. The MEV flip-flop records memory expansion (a.k.a. dynamic mapping) - violations. It is set when an DM violation is encountered and can be - tested via SFC/SFS. - - 3. MP cannot be turned off in hardware, except by causing a violation. - Microcode typically does this by executing an IOG micro-order with select - code /= 1, followed by an IAK to clear the interrupt and a FTCH to clear - the INTPT flip-flop. Under simulation, mp_control may be set to CLEAR to - produce the same effect. - - 4. Parity error logic is not implemented. -*/ - -uint32 protio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) -{ -uint16 data; -IOSIGNAL signal; -IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ - -while (working_set) { - signal = IONEXT (working_set); /* isolate next signal */ - - switch (signal) { /* dispatch I/O signal */ - - case ioCLF: /* clear flag flip-flop */ - break; /* turns off PE interrupt */ - - case ioSTF: /* set flag flip-flop */ - break; /* turns on PE interrupt */ - - case ioENF: /* enable flag */ - mp_flag = mp_flagbuf = SET; /* set flag buffer and flag flip-flops */ - mp_evrff = CLEAR; /* inhibit violation register updates */ - break; - - case ioSFC: /* skip if flag is clear */ - setSKF (!mp_mevff); /* skip if MP interrupt */ - break; - - case ioSFS: /* skip if flag is set */ - setSKF (mp_mevff); /* skip if DMS interrupt */ - break; - - case ioIOI: /* I/O input */ - stat_data = IORETURN (SCPE_OK, mp_viol); /* read MP violation register */ - break; - - case ioIOO: /* I/O output */ - mp_fence = IODATA (stat_data) & VAMASK; /* write to MP fence register */ - - if (cpu_unit.flags & UNIT_2100) /* 2100 IOP uses MP fence */ - iop_sp = mp_fence; /* as a stack pointer */ - break; - - case ioPOPIO: /* power-on preset to I/O */ - mp_control = CLEAR; /* clear control flip-flop */ - mp_flag = mp_flagbuf = CLEAR; /* clear flag and flag buffer flip-flops */ - mp_mevff = CLEAR; /* clear memory expansion violation flip-flop */ - mp_evrff = SET; /* set enable violation register flip-flop */ - break; - - case ioSTC: /* set control flip-flop */ - mp_control = SET; /* turn on MP */ - mp_mevff = CLEAR; /* clear memory expansion violation flip-flop */ - mp_evrff = SET; /* set enable violation register flip-flop */ - break; - - case ioSIR: /* set interrupt request */ - setPRL (PRO, !mp_flag); /* set PRL signal */ - setIRQ (PRO, mp_flag); /* set IRQ signal */ - break; - - case ioIAK: /* interrupt acknowledge */ - if (dibptr->select_code == PRO) /* MP interrupt acknowledgement? */ - mp_flag = mp_flagbuf = CLEAR; /* clear flag and flag buffer */ - - data = IODATA (stat_data); /* get trap cell instruction */ - - if (((data & I_NMRMASK) != I_IO) || /* trap cell instruction not I/O */ - (I_GETIOOP (data) == soHLT)) /* or is halt? */ - mp_control = CLEAR; /* turn protection off */ - else { /* non-HLT I/O instruction leaves MP on */ - mp_mevff = CLEAR; /* but clears MEV flip-flop */ - mp_evrff = SET; /* and reenables violation register flip-flop */ - } - break; - - default: /* all other signals */ - break; /* are ignored */ - } - - working_set = working_set & ~signal; /* remove current signal from set */ - } - -return stat_data; -} - - -/* DMA/DCPC secondary (SC 2/3) I/O signal handler. - - DMA consists of one (12607B) or two (12578A/12895A/12897B) channels. Each - channel uses two select codes: 2 and 6 for channel 1, and 3 and 7 for channel - 2. The lower select codes are used to configure the memory address register - (control word 2) and the word count register (control word 3). The upper - select codes are used to configure the service select register (control word - 1) and to activate and terminate the transfer. - - There are differences in the implementations of the memory address and word - count registers among the various cards. The 12607B (2114) supports 14-bit - addresses and 13-bit word counts. The 12578A (2115/6) supports 15-bit - addresses and 14-bit word counts. The 12895A (2100) and 12897B (1000) - support 15-bit addresses and 16-bit word counts. - - Implementation notes: - - 1. Because the I/O bus floats to zero on 211x computers, an IOI (read word - count) returns zeros in the unused bit locations, even though the word - count is a negative value. - - 2. Select codes 2 and 3 cannot interrupt, so there is no SIR handler. -*/ - -uint32 dmasio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) -{ -const CHANNEL ch = (CHANNEL) dibptr->card_index; /* DMA channel number */ -uint16 data; -IOSIGNAL signal; -IOCYCLE working_set = signal_set; /* no SIR handler needed */ - -while (working_set) { - signal = IONEXT (working_set); /* isolate next signal */ - - switch (signal) { /* dispatch I/O signal */ - - case ioIOI: /* I/O data input */ - if (UNIT_CPU_MODEL == UNIT_2114) /* 2114? */ - data = dma [ch].cw3 & 0017777; /* only 13-bit count */ - else if (UNIT_CPU_TYPE == UNIT_TYPE_211X) /* 2115/2116? */ - data = dma [ch].cw3 & 0037777; /* only 14-bit count */ - else /* other models */ - data = dma [ch].cw3; /* rest use full value */ - - stat_data = IORETURN (SCPE_OK, data); /* merge status and remaining word count */ - break; - - case ioIOO: /* I/O data output */ - if (dma [ch].select) /* word count selected? */ - dma [ch].cw3 = IODATA (stat_data); /* save count */ - else /* memory address selected */ - if (UNIT_CPU_MODEL == UNIT_2114) /* 2114? */ - dma [ch].cw2 = IODATA (stat_data) & 0137777; /* only 14-bit address */ - else /* other models */ - dma [ch].cw2 = IODATA (stat_data); /* full address stored */ - break; - - case ioCLC: /* clear control flip-flop */ - dma [ch].select = CLEAR; /* set for word count access */ - break; - - case ioSTC: /* set control flip-flop */ - dma [ch].select = SET; /* set for memory address access */ - break; - - default: /* all other signals */ - break; /* are ignored */ - } - - working_set = working_set & ~signal; /* remove current signal from set */ - } - -return stat_data; -} - - -/* DMA/DCPC primary (SC 6/7) I/O signal handler. - - The primary DMA control interface and the service select register are - manipulated through select codes 6 and 7. Each channel has transfer enable, - control, flag, and flag buffer flip-flops. Transfer enable must be set via - STC to start DMA. Control is used only to enable the DMA completion - interrupt; it is set by STC and cleared by CLC. Flag and flag buffer are set - at transfer completion to signal an interrupt. STF may be issued to abort a - transfer in progress. - - Again, there are hardware differences between the various DMA cards. The - 12607B (2114) stores only bits 2-0 of the select code and interprets them as - select codes 10-16 (SRQ17 is not decoded). The 12578A (2115/16), 12895A - (2100), and 12897B (1000) support the full range of select codes (10-77 - octal). - - Implementation notes: - - 1. An IOI reads the floating S-bus (high on the 1000, low on the 21xx). - - 2. The CRS signal on the DMA card resets the secondary (SC 2/3) select - flip-flops. Under simulation, ioCRS is dispatched to select codes 6 and - up, so we reset the flip-flop in our handler. - - 3. The 12578A supports byte-sized transfers by setting bit 14. Bit 14 is - ignored by all other DMA cards, which support word transfers only. - Under simulation, we use a byte-packing/unpacking register to hold one - byte while the other is read or written during the DMA cycle. -*/ - -uint32 dmapio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) -{ -const CHANNEL ch = (CHANNEL) dibptr->card_index; /* DMA channel number */ -uint16 data; -IOSIGNAL signal; -IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ - -while (working_set) { - signal = IONEXT (working_set); /* isolate next signal */ - - switch (signal) { /* dispatch I/O signal */ - - case ioCLF: /* clear flag flip-flop */ - dma [ch].flag = dma [ch].flagbuf = CLEAR; /* clear flag and flag buffer */ - break; - - case ioSTF: /* set flag flip-flop */ - case ioENF: /* enable flag */ - dma [ch].flag = dma [ch].flagbuf = SET; /* set flag and flag buffer */ - dma [ch].xferen = CLEAR; /* clear transfer enable to abort transfer */ - break; - - case ioSFC: /* skip if flag is clear */ - setstdSKF (dma [ch]); /* skip if transfer in progress */ - break; - - case ioSFS: /* skip if flag is set */ - setstdSKF (dma [ch]); /* skip if transfer is complete */ - break; - - case ioIOI: /* I/O data input */ - if (UNIT_CPU_TYPE == UNIT_TYPE_1000) /* 1000? */ - stat_data = IORETURN (SCPE_OK, DMASK); /* return all ones */ - else /* other models */ - stat_data = IORETURN (SCPE_OK, 0); /* return all zeros */ - break; - - case ioIOO: /* I/O data output */ - data = IODATA (stat_data); /* clear supplied status */ - - if (UNIT_CPU_MODEL == UNIT_2114) /* 12607? */ - dma [ch].cw1 = (data & 0137707) | 010; /* mask SC, convert to 10-17 */ - else if (UNIT_CPU_TYPE == UNIT_TYPE_211X) /* 12578? */ - dma [ch].cw1 = data; /* store full select code, flags */ - else /* 12895, 12897 */ - dma [ch].cw1 = data & ~DMA1_PB; /* clip byte-packing flag */ - break; - - case ioPOPIO: /* power-on preset to I/O */ - dma [ch].flag = dma [ch].flagbuf = SET; /* set flag and flag buffer */ - break; - - case ioCRS: /* control reset */ - dma [ch].xferen = CLEAR; /* clear transfer enable */ - dma [ch].select = CLEAR; /* set secondary for word count access */ - /* fall into CLC handler */ - - case ioCLC: /* clear control flip-flop */ - dma [ch].control = CLEAR; /* clear control */ - break; - - case ioSTC: /* set control flip-flop */ - dma [ch].packer = 0; /* clear packing register */ - dma [ch].xferen = dma [ch].control = SET; /* set transfer enable and control */ - break; - - case ioSIR: /* set interrupt request */ - setstdPRL (dma [ch]); - setstdIRQ (dma [ch]); - break; - - case ioIAK: /* interrupt acknowledge */ - dma [ch].flagbuf = CLEAR; /* clear flag buffer */ - break; - - default: /* all other signals */ - break; /* are ignored */ - } - - working_set = working_set & ~signal; /* remove current signal from set */ - } - -return stat_data; -} - - -/* Unassigned select code I/O signal handler. - - The 21xx/1000 I/O structure requires that no empty slots exist between - interface cards. This is due to the hardware priority chaining (PRH/PRL). - If it is necessary to leave unused I/O slots, HP 12777A Priority Jumper Cards - must be installed in them to maintain priority continuity. - - Under simulation, every unassigned I/O slot behaves as though a 12777A were - resident. - - Implementation notes: - - 1. For select codes < 10 octal, an IOI reads the floating S-bus (high on - the 1000, low on the 21xx). For select codes >= 10 octal, an IOI reads - the floating I/O bus (low on all machines). - - 2. If "stop_dev" is TRUE, then the simulator will stop when an unassigned - device is accessed. -*/ - -uint32 nullio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) -{ -uint16 data = 0; -IOSIGNAL signal; -IOCYCLE working_set = signal_set; /* no SIR handler needed */ - -while (working_set) { - signal = IONEXT (working_set); /* isolate next signal */ - - switch (signal) { /* dispatch I/O signal */ - - case ioIOI: /* I/O data input */ - if ((dibptr->select_code < VARDEV) && /* internal device */ - (UNIT_CPU_TYPE == UNIT_TYPE_1000)) /* and 1000? */ - data = DMASK; /* return all ones */ - else /* external or other model */ - data = 0; /* return all zeros */ - break; - - default: /* all other signals */ - break; /* are ignored */ - } - - working_set = working_set & ~signal; /* remove current signal from set */ - } - -return IORETURN (stop_dev, data); /* flag missing device */ -} - - -/* DMA cycle routine. - - This routine performs one DMA input or output cycle using the indicated DMA - channel number and DMS map. When the transfer word count reaches zero, the - flag is set on the corresponding DMA channel to indicate completion. - - The 12578A card supports byte-packing. If bit 14 in control word 1 is set, - each transfer will involve one read/write from memory and two output/input - operations in order to transfer sequential bytes to/from the device. - - DMA I/O cycles differ from programmed I/O cycles in that multiple I/O control - backplane signals may be asserted simultaneously. With programmed I/O, only - CLF may be asserted with other signals, specifically with STC, CLC, SFS, SFC, - IOI, or IOO. With DMA, as many as five signals may be asserted concurrently. - - DMA I/O timing looks like this: - - ------------ Input ------------ ----------- Output ------------ - Sig Normal Cycle Last Cycle Normal Cycle Last Cycle - === ============== ============== ============== ============== - IOI T2-T3 T2-T3 - IOO T3-T4 T3-T4 - STC * T3 T3 T3 - CLC * T3-T4 T3-T4 - CLF T3 T3 T3 - EDT T4 T4 - - * if enabled by control word 1 - - Under simulation, this routine dispatches one set of I/O signals per DMA - cycle to the target device's I/O signal handler. The signals correspond to - the table above, except that all signals for a given cycle are concurrent - (e.g., the last input cycle has IOI, EDT, and optionally CLC asserted, even - though IOI and EDT are not coincident in hardware). I/O signal handlers will - process these signals sequentially, in the order listed above, before - returning. - - Implementation notes: - - 1. The address increment and word count decrement is done only after the I/O - cycle has completed successfully. This allows a failed transfer to be - retried after correcting the I/O error. -*/ - -static t_stat dma_cycle (CHANNEL ch, uint32 map) -{ -const uint32 dev = dma [ch].cw1 & I_DEVMASK; /* device select code */ -const uint32 stc = dma [ch].cw1 & DMA1_STC; /* STC enable flag */ -const uint32 bytes = dma [ch].cw1 & DMA1_PB; /* pack bytes flag */ -const uint32 clc = dma [ch].cw1 & DMA1_CLC; /* CLC enable flag */ -const uint32 MA = dma [ch].cw2 & VAMASK; /* memory address */ -const uint32 input = dma [ch].cw2 & DMA2_OI; /* input flag */ -const uint32 even = dma [ch].packer & DMA_OE; /* odd/even packed byte flag */ -uint16 data; -t_stat status; -uint32 ioresult; -IOCYCLE signals; - -if (bytes && !even || dma [ch].cw3 != DMASK) { /* normal cycle? */ - if (input) /* input cycle? */ - signals = ioIOI | ioCLF; /* assert IOI and CLF */ - else /* output cycle */ - signals = ioIOO | ioCLF; /* assert IOO and CLF */ - - if (stc) /* STC wanted? */ - signals = signals | ioSTC; /* assert STC */ - } - -else { /* last cycle */ - if (input) /* input cycle? */ - signals = ioIOI | ioEDT; /* assert IOI and EDT */ - else { /* output cycle */ - signals = ioIOO | ioCLF | ioEDT; /* assert IOO and CLF and EDT */ - - if (stc) /* STC wanted? */ - signals = signals | ioSTC; /* assert STC */ - } - - if (clc) /* CLC wanted? */ - signals = signals | ioCLC; /* assert CLC */ - } - -if (input) { /* input cycle? */ - ioresult = devdisp (dev, signals, /* do I/O input */ - IORETURN (SCPE_OK, 0)); - - status = IOSTATUS (ioresult); /* get cycle status */ - - if (status == SCPE_OK) { /* good I/O cycle? */ - data = IODATA (ioresult); /* extract return data value */ - - if (bytes) { /* byte packing? */ - if (even) { /* second byte? */ - data = (dma [ch].packer << 8) | /* merge stored byte */ - (data & DMASK8); - WriteIO (MA, data, map); /* store word data */ - } - else /* first byte */ - dma [ch].packer = (data & DMASK8); /* save it */ - - dma [ch].packer = dma [ch].packer ^ DMA_OE; /* flip odd/even bit */ - } - else /* no byte packing */ - WriteIO (MA, data, map); /* store word data */ - } - } - -else { /* output cycle */ - if (bytes) { /* byte packing? */ - if (even) /* second byte? */ - data = dma [ch].packer & DMASK8; /* retrieve it */ - - else { /* first byte */ - dma [ch].packer = ReadIO (MA, map); /* read word data */ - data = (dma [ch].packer >> 8) & DMASK8; /* get high byte */ - } - - dma [ch].packer = dma [ch].packer ^ DMA_OE; /* flip odd/even bit */ - } - else /* no byte packing */ - data = ReadIO (MA, map); /* read word data */ - - ioresult = devdisp (dev, signals, /* do I/O output */ - IORETURN (SCPE_OK, data)); - - status = IOSTATUS (ioresult); /* get cycle status */ - } - -if ((even || !bytes) && (status == SCPE_OK)) { /* new byte or no packing and good xfer? */ - dma [ch].cw2 = input | (dma [ch].cw2 + 1) & VAMASK; /* increment address */ - dma [ch].cw3 = (dma [ch].cw3 + 1) & DMASK; /* increment word count */ - - if (dma [ch].cw3 == 0) /* end of transfer? */ - dmapio (dtab [DMA1 + ch], ioENF, 0); /* set DMA channel flag */ - } - -return status; /* return I/O status */ -} - - -/* Reset routines. - - The reset routines are called to simulate either an initial power on - condition or a front-panel PRESET button press. For initial power on - (corresponds to PON, POPIO, and CRS signal assertion in the CPU), the "P" - command switch will be set. For PRESET (corresponds to POPIO and CRS - assertion), the switch will be clear. - - SCP delivers a power-on reset to all devices when the simulator is started. - A RUN, BOOT, RESET, or RESET ALL command delivers a PRESET to all devices. A - RESET delivers a PRESET to a specific device. -*/ - - -/* CPU reset. - - If this is the first call after simulator startup, allocate the initial - memory array, set the default CPU model, and install the default BBL. -*/ - -t_stat cpu_reset (DEVICE *dptr) -{ -if (M == NULL) { /* initial call after startup? */ - pcq_r = find_reg ("PCQ", NULL, dptr); /* get PC queue pointer */ - - if (pcq_r) /* defined? */ - pcq_r->qptr = 0; /* initialize queue */ - else /* not defined */ - return SCPE_IERR; /* internal error */ - - M = (uint16 *) calloc (PASIZE, sizeof (uint16)); /* alloc mem */ - - if (M == NULL) /* alloc fail? */ - return SCPE_MEM; - else { /* do one-time init */ - MEMSIZE = 32768; /* set initial memory size */ - cpu_set_model (NULL, UNIT_2116, NULL, NULL); /* set initial CPU model */ - SR = 001000; /* select PTR boot ROM at SC 10 */ - cpu_boot (0, NULL); /* install loader for 2116 */ - cpu_set_ldr (NULL, FALSE, NULL, NULL); /* disable loader (was enabled) */ - SR = 0; /* clear S */ - sim_vm_post = &hp_post_cmd; /* set cmd post proc */ - sim_brk_types = ALL_BKPTS; /* register allowed breakpoint types */ - } - } - -if (sim_switches & SWMASK ('P')) /* PON reset? */ - IOPOWERON (&cpu_dib); -else /* PRESET */ - IOPRESET (&cpu_dib); - -sim_brk_dflt = SWMASK ('N'); /* type is nomap as DMS is off */ - -return SCPE_OK; -} - - -/* Memory protect reset */ - -t_stat mp_reset (DEVICE *dptr) -{ -IOPRESET (&mp_dib); /* PRESET device (does not use PON) */ - -mp_fence = 0; /* clear fence register */ -mp_viol = 0; /* clear violation register */ - -return SCPE_OK; -} - - -/* DMA reset */ - -t_stat dma_reset (DEVICE *dptr) -{ -DIB *dibptr = (DIB *) dptr->ctxt; /* DIB pointer */ -const CHANNEL ch = (CHANNEL) dibptr->card_index; /* DMA channel number */ - -if (UNIT_CPU_MODEL != UNIT_2114) /* 2114 has only one channel */ - hp_enbdis_pair (dma_dptrs [ch], /* make specified channel */ - dma_dptrs [ch ^ 1]); /* consistent with other channel */ - -if (sim_switches & SWMASK ('P')) { /* power-on reset? */ - dma [ch].cw1 = 0; /* clear control word registers */ - dma [ch].cw2 = 0; - dma [ch].cw3 = 0; - } - -IOPRESET (dibptr); /* PRESET device (does not use PON) */ - -dma [ch].packer = 0; /* clear byte packer */ - -return SCPE_OK; -} - - -/* Memory examine */ - -t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw) -{ -uint16 d; - -if ((sw & ALL_MAPMODES) && (dms_enb == 0)) /* req map with DMS off? */ - return SCPE_NOFNC; /* command not allowed */ - -addr = dms_cons (addr, sw); /* translate address as indicated */ - -if (addr >= MEMSIZE) /* beyond memory limits? */ - return SCPE_NXM; /* non-existent memory */ - -if ((sw & SIM_SW_REST) || (addr >= 2)) /* restoring or memory access? */ - d = M[addr]; /* return memory value */ -else /* not restoring and A/B access */ - d = ABREG[addr]; /* return A/B register value */ - -if (vptr != NULL) - *vptr = d & DMASK; /* store return value */ -return SCPE_OK; -} - -/* Memory deposit */ - -t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw) -{ -if ((sw & ALL_MAPMODES) && (dms_enb == 0)) /* req map with DMS off? */ - return SCPE_NOFNC; /* command not allowed */ - -addr = dms_cons (addr, sw); /* translate address as indicated */ - -if (addr >= MEMSIZE) /* beyond memory limits? */ - return SCPE_NXM; /* non-existent memory */ - -if ((sw & SIM_SW_REST) || (addr >= 2)) /* restoring or memory access? */ - M[addr] = val & DMASK; /* store memory value */ -else /* not restoring and A/B access */ - ABREG[addr] = val & DMASK; /* store A/B register value */ - -return SCPE_OK; -} - - -/* Make a pair of devices consistent */ - -void hp_enbdis_pair (DEVICE *ccp, DEVICE *dcp) -{ -if (ccp->flags & DEV_DIS) - dcp->flags = dcp->flags | DEV_DIS; -else - dcp->flags = dcp->flags & ~DEV_DIS; - -return; -} - - -/* VM command post-processor - - Update T register to contents of memory addressed by M register - if M register has changed. */ - -void hp_post_cmd (t_bool from_scp) -{ -if (MR != saved_MR) { /* M changed since last update? */ - saved_MR = MR; - TR = ReadTAB (MR); /* sync T with new M */ - } -return; -} - - -/* Test for device conflict */ - -static t_bool dev_conflict (void) -{ -DEVICE *dptr; -DIB *dibptr; -uint32 i, j, k; -t_bool is_conflict = FALSE; -uint32 conflicts[MAXDEV + 1] = { 0 }; - -for (i = 0; dptr = sim_devices[i]; i++) { - dibptr = (DIB *) dptr->ctxt; - if (dibptr && !(dptr->flags & DEV_DIS)) - if (++conflicts[dibptr->select_code] > 1) - is_conflict = TRUE; - } - -if (is_conflict) { - sim_ttcmd(); - for (i = 0; i <= MAXDEV; i++) { - if (conflicts[i] > 1) { - k = conflicts[i]; - - printf ("Select code %o conflict:", i); - - if (sim_log) - fprintf (sim_log, "Select code %o conflict:", i); - - for (j = 0; dptr = sim_devices[j]; j++) { - dibptr = (DIB *) dptr->ctxt; - if (dibptr && !(dptr->flags & DEV_DIS) && (i == dibptr->select_code)) { - if (k < conflicts[i]) { - printf (" and"); - - if (sim_log) - fputs (" and", sim_log); - } - - printf (" %s", sim_dname (dptr)); - - if (sim_log) - fprintf (sim_log, " %s", sim_dname (dptr)); - - k = k - 1; - - if (k == 0) { - putchar ('\n'); - - if (sim_log) - fputc ('\n', sim_log); - break; - } - } - } - } - } - } -return is_conflict; -} - - -/* Change CPU memory size. - - On a 21xx, move the current loader to the top of the new memory size. Then - clear "non-existent memory" so that reads return zero, per spec. - - Validation: - - New size <= maximum size for current CPU. - - New size a positive multiple of 4K (progamming error if not). - - If new size < old size, truncation accepted. -*/ - -t_stat cpu_set_size (UNIT *uptr, int32 new_size, char *cptr, void *desc) -{ -int32 mc = 0; -uint32 i; -uint32 model = CPU_MODEL_INDEX; /* current CPU model index */ -uint32 old_size = MEMSIZE; /* current memory size */ - -if ((uint32) new_size > cpu_features[model].maxmem) - return SCPE_NOFNC; /* mem size unsupported */ - -if ((new_size <= 0) || (new_size > PASIZE) || ((new_size & 07777) != 0)) - return SCPE_NXM; /* invalid size (prog err) */ - -if (!(sim_switches & SWMASK ('F'))) { /* force truncation? */ - for (i = new_size; i < MEMSIZE; i++) /* check truncated memory */ - mc = mc | M[i]; /* for content */ - - if ((mc != 0) && (!get_yn ("Really truncate memory [N]?", FALSE))) - return SCPE_INCOMP; - } - -if (UNIT_CPU_FAMILY == UNIT_FAMILY_21XX) { /* 21xx CPU? */ - cpu_set_ldr (uptr, FALSE, NULL, NULL); /* save loader to shadow RAM */ - MEMSIZE = new_size; /* set new memory size */ - fwanxm = MEMSIZE - IBL_LNT; /* reserve memory for loader */ - } -else /* loader unsupported */ - fwanxm = MEMSIZE = new_size; /* set new memory size */ - -for (i = fwanxm; i < old_size; i++) /* zero non-existent memory */ - M[i] = 0; - -return SCPE_OK; -} - - -/* Change CPU models. - - For convenience, MP and DMA are typically enabled if available; they may be - disabled subsequently if desired. Note that the 2114 supports only one DMA - channel (channel 1). All other models support two channels. - - Validation: - - Sets standard equipment and convenience features. - - Changes DMA device name to DCPC if 1000 is selected. - - Enforces maximum memory allowed (doesn't change otherwise). - - Disables loader on 21xx machines. -*/ - -t_stat cpu_set_model (UNIT *uptr, int32 new_model, char *cptr, void *desc) -{ -uint32 old_family = UNIT_CPU_FAMILY; /* current CPU type */ -uint32 new_family = new_model & UNIT_FAMILY_MASK; /* new CPU family */ -uint32 new_index = new_model >> UNIT_V_CPU; /* new CPU model index */ -uint32 new_memsize; -t_stat result; - -cpu_unit.flags = cpu_unit.flags & ~UNIT_OPTS | /* set typical features */ - cpu_features[new_index].typ & UNIT_OPTS; /* mask pseudo-opts */ - - -if (cpu_features[new_index].typ & UNIT_MP) /* MP in typ config? */ - mp_dev.flags = mp_dev.flags & ~DEV_DIS; /* enable it */ -else - mp_dev.flags = mp_dev.flags | DEV_DIS; /* disable it */ - -if (cpu_features[new_index].opt & UNIT_MP) /* MP an option? */ - mp_dev.flags = mp_dev.flags | DEV_DISABLE; /* make it alterable */ -else - mp_dev.flags = mp_dev.flags & ~DEV_DISABLE; /* make it unalterable */ - - -if (cpu_features[new_index].typ & UNIT_DMA) { /* DMA in typ config? */ - dma1_dev.flags = dma1_dev.flags & ~DEV_DIS; /* enable DMA channel 1 */ - - if (new_model == UNIT_2114) /* 2114 has only one channel */ - dma2_dev.flags = dma2_dev.flags | DEV_DIS; /* disable channel 2 */ - else /* all others have two channels */ - dma2_dev.flags = dma2_dev.flags & ~DEV_DIS; /* enable it */ - } -else { - dma1_dev.flags = dma1_dev.flags | DEV_DIS; /* disable channel 1 */ - dma2_dev.flags = dma2_dev.flags | DEV_DIS; /* disable channel 2 */ - } - -if (cpu_features[new_index].opt & UNIT_DMA) { /* DMA an option? */ - dma1_dev.flags = dma1_dev.flags | DEV_DISABLE; /* make it alterable */ - - if (new_model == UNIT_2114) /* 2114 has only one channel */ - dma2_dev.flags = dma2_dev.flags & ~DEV_DISABLE; /* make it unalterable */ - else /* all others have two channels */ - dma2_dev.flags = dma2_dev.flags | DEV_DISABLE; /* make it alterable */ - } -else { - dma1_dev.flags = dma1_dev.flags & ~DEV_DISABLE; /* make it unalterable */ - dma2_dev.flags = dma2_dev.flags & ~DEV_DISABLE; /* make it unalterable */ - } - - -if ((old_family == UNIT_FAMILY_1000) && /* if current family is 1000 */ - (new_family == UNIT_FAMILY_21XX)) { /* and new family is 21xx */ - deassign_device (&dma1_dev); /* delete DCPC names */ - deassign_device (&dma2_dev); - } -else if ((old_family == UNIT_FAMILY_21XX) && /* if current family is 21xx */ - (new_family == UNIT_FAMILY_1000)) { /* and new family is 1000 */ - assign_device (&dma1_dev, "DCPC1"); /* change DMA device name */ - assign_device (&dma2_dev, "DCPC2"); /* to DCPC for familiarity */ - } - -if ((MEMSIZE == 0) || /* current mem size not set? */ - (MEMSIZE > cpu_features[new_index].maxmem)) /* current mem size too large? */ - new_memsize = cpu_features[new_index].maxmem; /* set it to max supported */ -else - new_memsize = MEMSIZE; /* or leave it unchanged */ - -result = cpu_set_size (uptr, new_memsize, NULL, NULL); /* set memory size */ - -if (result == SCPE_OK) /* memory change OK? */ - if (new_family == UNIT_FAMILY_21XX) /* 21xx CPU? */ - fwanxm = MEMSIZE - IBL_LNT; /* reserve memory for loader */ - else - fwanxm = MEMSIZE; /* loader reserved only for 21xx */ - -return result; -} - - -/* Display the CPU model and optional loader status. - - Loader status is displayed for 21xx models and suppressed for 1000 models. -*/ - -t_stat cpu_show_model (FILE *st, UNIT *uptr, int32 val, void *desc) -{ -fputs ((char *) desc, st); /* write model name */ - -if (UNIT_CPU_FAMILY == UNIT_FAMILY_21XX) /* valid only for 21xx */ - if (fwanxm < MEMSIZE) /* loader area non-existent? */ - fputs (", loader disabled", st); /* yes, so access disabled */ - else - fputs (", loader enabled", st); /* no, so access enabled */ -return SCPE_OK; -} - - -/* Set a CPU option. - - Validation: - - Checks that the current CPU model supports the option selected. - - If CPU is 1000-F, ensures that VIS and IOP are mutually exclusive. - - If CPU is 2100, ensures that FP/FFP and IOP are mutually exclusive. - - If CPU is 2100, ensures that FP is enabled if FFP enabled - (FP is required for FFP installation). -*/ - -t_stat cpu_set_opt (UNIT *uptr, int32 option, char *cptr, void *desc) -{ -uint32 model = CPU_MODEL_INDEX; /* current CPU model index */ - -if ((cpu_features[model].opt & option) == 0) /* option supported? */ - return SCPE_NOFNC; /* no */ - -if (UNIT_CPU_TYPE == UNIT_TYPE_2100) { - if ((option == UNIT_FP) || (option == UNIT_FFP)) /* 2100 IOP and FP/FFP options */ - uptr->flags = uptr->flags & ~UNIT_IOP; /* are mutually exclusive */ - else if (option == UNIT_IOP) - uptr->flags = uptr->flags & ~(UNIT_FP | UNIT_FFP); - - if (option == UNIT_FFP) /* 2100 FFP option requires FP */ - uptr->flags = uptr->flags | UNIT_FP; - } - -else if (UNIT_CPU_MODEL == UNIT_1000_F) - if (option == UNIT_VIS) /* 1000-F IOP and VIS options */ - uptr->flags = uptr->flags & ~UNIT_IOP; /* are mutually exclusive */ - else if (option == UNIT_IOP) - uptr->flags = uptr->flags & ~UNIT_VIS; - -return SCPE_OK; -} - - -/* Clear a CPU option. - - Validation: - - Checks that the current CPU model supports the option selected. - - Clears flag from unit structure (we are processing MTAB_XTD entries). - - If CPU is 2100, ensures that FFP is disabled if FP disabled - (FP is required for FFP installation). -*/ - -t_bool cpu_clr_opt (UNIT *uptr, int32 option, char *cptr, void *desc) -{ -uint32 model = CPU_MODEL_INDEX; /* current CPU model index */ - -if ((cpu_features[model].opt & option) == 0) /* option supported? */ - return SCPE_NOFNC; /* no */ - -uptr->flags = uptr->flags & ~option; /* disable option */ - -if ((UNIT_CPU_TYPE == UNIT_TYPE_2100) && /* disabling 2100 FP? */ - (option == UNIT_FP)) - uptr->flags = uptr->flags & ~UNIT_FFP; /* yes, so disable FFP too */ - -return SCPE_OK; -} - - -/* 21xx loader enable/disable function. - - The 21xx CPUs store their initial binary loaders in the last 64 words of - available memory. This memory is protected by a LOADER ENABLE switch on the - front panel. When the switch is off (disabled), main memory effectively ends - 64 locations earlier, i.e., the loader area is treated as non-existent. - Because these are core machines, the loader is retained when system power is - off. - - 1000 CPUs do not have a protected loader feature. Instead, loaders are - stored in PROMs and are copied into main memory for execution by the IBL - switch. - - Under simulation, we keep both a total configured memory size (MEMSIZE) and a - current configured memory size (fwanxm = "first word address of non-existent - memory"). When the two are equal, the loader is enabled. When the current - size is less than the total size, the loader is disabled. - - Disabling the loader copies the last 64 words to a shadow array, zeros the - corresponding memory, and decreases the last word of addressable memory by - 64. Enabling the loader reverses this process. - - Disabling may be done manually by user command or automatically when a halt - instruction is executed. Enabling occurs only by user command. This differs - slightly from actual machine operation, which additionally disables the - loader when a manual halt is performed. We do not do this to allow - breakpoints within and single-stepping through the loaders. -*/ - -t_stat cpu_set_ldr (UNIT *uptr, int32 enable, char *cptr, void *desc) -{ -static BOOT_ROM loader; -int32 i; -t_bool is_enabled = (fwanxm == MEMSIZE); - -if ((UNIT_CPU_FAMILY != UNIT_FAMILY_21XX) || /* valid only for 21xx */ - (MEMSIZE == 0)) /* and for initialized memory */ - return SCPE_NOFNC; - -if (is_enabled && (enable == 0)) { /* disable loader? */ - fwanxm = MEMSIZE - IBL_LNT; /* decrease available memory */ - for (i = 0; i < IBL_LNT; i++) { /* copy loader */ - loader[i] = M[fwanxm + i]; /* from memory */ - M[fwanxm + i] = 0; /* and zero location */ - } - } - -else if ((!is_enabled) && (enable == 1)) { /* enable loader? */ - for (i = 0; i < IBL_LNT; i++) /* copy loader */ - M[fwanxm + i] = loader[i]; /* to memory */ - fwanxm = MEMSIZE; /* increase available memory */ - } - -return SCPE_OK; -} - - -/* Idle enable/disable */ - -t_stat cpu_set_idle (UNIT *uptr, int32 option, char *cptr, void *desc) -{ - if (option) - return sim_set_idle (uptr, 10, NULL, NULL); - else - return sim_clr_idle (uptr, 0, NULL, NULL); -} - - -/* Idle display */ - -t_stat cpu_show_idle (FILE *st, UNIT *uptr, int32 val, void *desc) -{ - return sim_show_idle (st, uptr, val, desc); -} - - -/* IBL routine (CPU boot) */ - -t_stat cpu_boot (int32 unitno, DEVICE *dptr) -{ -extern const BOOT_ROM ptr_rom, dq_rom, ms_rom, ds_rom; -int32 dev = (SR >> IBL_V_DEV) & I_DEVMASK; -int32 sel = (SR >> IBL_V_SEL) & IBL_M_SEL; - -if (dev < 010) - return SCPE_NOFNC; - -switch (sel) { - - case 0: /* PTR boot */ - ibl_copy (ptr_rom, dev); - break; - - case 1: /* DP/DQ boot */ - ibl_copy (dq_rom, dev); - break; - - case 2: /* MS boot */ - ibl_copy (ms_rom, dev); - break; - - case 3: /* DS boot */ - ibl_copy (ds_rom, dev); - break; - } - -return SCPE_OK; -} - - -/* IBL boot ROM copy - - - Use memory size to set the initial PC and base of the boot area - - Copy boot ROM to memory, updating I/O instructions - - Place 2s complement of boot base in last location - - Notes: - - SR settings are done by the caller - - Boot ROMs must be assembled with a device code of 10 (10 and 11 for - devices requiring two codes) -*/ - -t_stat ibl_copy (const BOOT_ROM rom, int32 dev) -{ -int32 i; -uint16 wd; - -cpu_set_ldr (NULL, TRUE, NULL, NULL); /* enable loader (ignore errors) */ - -if (dev < 010) /* valid device? */ - return SCPE_ARG; - -PC = ((MEMSIZE - 1) & ~IBL_MASK) & VAMASK; /* start at mem top */ - -for (i = 0; i < IBL_LNT; i++) { /* copy bootstrap */ - wd = rom[i]; /* get word */ - - if (((wd & I_NMRMASK) == I_IO) && /* IO instruction? */ - ((wd & I_DEVMASK) >= 010) && /* dev >= 10? */ - (I_GETIOOP (wd) != soHLT)) /* not a HALT? */ - M[PC + i] = (wd + (dev - 010)) & DMASK; /* change dev code */ - - else /* leave unchanged */ - M[PC + i] = wd; - } - -M[PC + IBL_DPC] = (M[PC + IBL_DPC] + (dev - 010)) & DMASK; /* patch DMA ctrl */ -M[PC + IBL_END] = (~PC + 1) & DMASK; /* fill in start of boot */ -return SCPE_OK; -} +/* hp2100_cpu.c: HP 21xx/1000 CPU simulator + + Copyright (c) 1993-2014, Robert M. Supnik + + 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 + ROBERT M SUPNIK 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 Robert M Supnik shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + + CPU 2114C/2115A/2116C/2100A/1000-M/E/F central processing unit + 12731A memory expansion module + MP 12581A/12892B memory protect + DMA1,DMA2 12607B/12578A/12895A direct memory access controller + DCPC1,DCPC2 12897B dual channel port controller + + 31-Dec-14 JDB Corrected devdisp data parameters + 30-Dec-14 JDB Added S-register parameters to ibl_copy + 24-Dec-14 JDB Added casts for explicit downward conversions + 18-Mar-13 JDB Removed redundant extern declarations + 05-Feb-13 JDB HLT instruction handler now relies on sim_vm_fprint_stopped + 09-May-12 JDB Separated assignments from conditional expressions + 13-Jan-12 JDB Minor speedup in "is_mapped" + Added casts to cpu_mod, dmasio, dmapio, cpu_reset, dma_reset + 07-Apr-11 JDB Fixed I/O return status bug for DMA cycles + Failed I/O cycles now stop on failing instruction + 28-Mar-11 JDB Tidied up signal handling + 29-Oct-10 JDB Revised DMA for new multi-card paradigm + Consolidated DMA reset routines + DMA channels renamed from 0,1 to 1,2 to match documentation + 27-Oct-10 JDB Changed I/O instructions, handlers, and DMA for revised signal model + Changed I/O dispatch table to use DIB pointers + 19-Oct-10 JDB Removed DMA latency counter + 13-Oct-10 JDB Fixed DMA requests to enable stealing every cycle + Fixed DMA priority for channel 1 over channel 2 + Corrected comments for "cpu_set_idle" + 30-Sep-08 JDB Breakpoints on interrupt trap cells now work + 05-Sep-08 JDB VIS and IOP are now mutually exclusive on 1000-F + 11-Aug-08 JDB Removed A/B shadow register variables + 07-Aug-08 JDB Moved hp_setdev, hp_showdev to hp2100_sys.c + Moved non-existent memory checks to WritePW + 05-Aug-08 JDB Fixed mp_dms_jmp to accept lower bound, check write protection + 30-Jul-08 JDB Corrected DMS violation register set conditions + Refefined ABORT to pass address, moved def to hp2100_cpu.h + Combined dms and dms_io routines + 29-Jul-08 JDB JSB to 0/1 with W5 out and fence = 0 erroneously causes MP abort + 11-Jul-08 JDB Unified I/O slot dispatch by adding DIBs for CPU, MP, and DMA + 26-Jun-08 JDB Rewrote device I/O to model backplane signals + EDT no longer passes DMA channel + 30-Apr-08 JDB Enabled SIGNAL instructions, SIG debug flag + 28-Apr-08 JDB Added SET CPU IDLE/NOIDLE, idle detection for DOS/RTE + 24-Apr-08 JDB Fixed single stepping through interrupts + 20-Apr-08 JDB Enabled EMA and VIS, added EMA, VIS, and SIGNAL debug flags + 03-Dec-07 JDB Memory ex/dep and bkpt type default to current map mode + 26-Nov-07 JDB Added SET CPU DEBUG and OS/VMA flags, enabled OS/VMA + 15-Nov-07 JDB Corrected MP W5 (JSB) jumper action, SET/SHOW reversal, + mp_mevff clear on interrupt with I/O instruction in trap cell + 04-Nov-07 JDB Removed DBI support from 1000-M (was temporary for RTE-6/VM) + 28-Apr-07 RMS Removed clock initialization + 02-Mar-07 JDB EDT passes input flag and DMA channel in dat parameter + 11-Jan-07 JDB Added 12578A DMA byte packing + 28-Dec-06 JDB CLC 0 now sends CRS instead of CLC to devices + 26-Dec-06 JDB Fixed improper IRQ deferral for 21xx CPUs + Fixed improper interrupt servicing in resolve + 21-Dec-06 JDB Added 21xx loader enable/disable support + 16-Dec-06 JDB Added 2114 and 2115 CPU options. + Added support for 12607B (2114) and 12578A (2115/6) DMA + 01-Dec-06 JDB Added 1000-F CPU option (requires HAVE_INT64) + SHOW CPU displays 1000-M/E instead of 21MX-M/E + 16-Oct-06 JDB Moved ReadF to hp2100_cpu1.c + 12-Oct-06 JDB Fixed INDMAX off-by-one error in resolve + 26-Sep-06 JDB Added iotrap parameter to UIG dispatchers for RTE microcode + 12-Sep-06 JDB iogrp returns NOTE_IOG to recalc interrupts + resolve returns NOTE_INDINT to service held-off interrupt + 16-Aug-06 JDB Added support for future microcode options, future F-Series + 09-Aug-06 JDB Added double integer microcode, 1000-M/E synonyms + Enhanced CPU option validity checking + Added DCPC as a synonym for DMA for 21MX simulations + 26-Dec-05 JDB Improved reporting in dev_conflict + 22-Sep-05 RMS Fixed declarations (from Sterling Garwood) + 21-Jan-05 JDB Reorganized CPU option flags + 15-Jan-05 RMS Split out EAU and MAC instructions + 26-Dec-04 RMS DMA reset doesn't clear alternate CTL flop (from Dave Bryan) + DMA reset shouldn't clear control words (from Dave Bryan) + Alternate CTL flop not visible as register (from Dave Bryan) + Fixed CBS, SBS, TBS to perform virtual reads + Separated A/B from M[0/1] for DMA IO (from Dave Bryan) + Fixed bug in JPY (from Dave Bryan) + 25-Dec-04 JDB Added SET CPU 21MX-M, 21MX-E (21MX defaults to MX-E) + TIMER/EXECUTE/DIAG instructions disabled for 21MX-M + T-register reflects changes in M-register when halted + 25-Sep-04 JDB Moved MP into its own device; added MP option jumpers + Modified DMA to allow disabling + Modified SET CPU 2100/2116 to truncate memory > 32K + Added -F switch to SET CPU to force memory truncation + Fixed S-register behavior on 2116 + Fixed LIx/MIx behavior for DMA on 2116 and 2100 + Fixed LIx/MIx behavior for empty I/O card slots + Modified WRU to be REG_HRO + Added BRK and DEL to save console settings + Fixed use of "unsigned int16" in cpu_reset + Modified memory size routine to return SCPE_INCOMP if + memory size truncation declined + 20-Jul-04 RMS Fixed bug in breakpoint test (reported by Dave Bryan) + Back up PC on instruction errors (from Dave Bryan) + 14-May-04 RMS Fixed bugs and added features from Dave Bryan + - SBT increments B after store + - DMS console map must check dms_enb + - SFS x,C and SFC x,C work + - MP violation clears automatically on interrupt + - SFS/SFC 5 is not gated by protection enabled + - DMS enable does not disable mem prot checks + - DMS status inconsistent at simulator halt + - Examine/deposit are checking wrong addresses + - Physical addresses are 20b not 15b + - Revised DMS to use memory rather than internal format + - Added instruction printout to HALT message + - Added M and T internal registers + - Added N, S, and U breakpoints + Revised IBL facility to conform to microcode + Added DMA EDT I/O pseudo-opcode + Separated DMA SRQ (service request) from FLG + 12-Mar-03 RMS Added logical name support + 02-Feb-03 RMS Fixed last cycle bug in DMA output (found by Mike Gemeny) + 22-Nov-02 RMS Added 21MX IOP support + 24-Oct-02 RMS Fixed bugs in IOP and extended instructions + Fixed bugs in memory protection and DMS + Added clock calibration + 25-Sep-02 RMS Fixed bug in DMS decode (found by Robert Alan Byer) + 26-Jul-02 RMS Restructured extended instructions, added IOP support + 22-Mar-02 RMS Changed to allocate memory array dynamically + 11-Mar-02 RMS Cleaned up setjmp/auto variable interaction + 17-Feb-02 RMS Added DMS support + Fixed bugs in extended instructions + 03-Feb-02 RMS Added terminal multiplexor support + Changed PCQ macro to use unmodified PC + Fixed flop restore logic (found by Bill McDermith) + Fixed SZx,SLx,RSS bug (found by Bill McDermith) + Added floating point support + 16-Jan-02 RMS Added additional device support + 07-Jan-02 RMS Fixed DMA register tables (found by Bill McDermith) + 07-Dec-01 RMS Revised to use breakpoint package + 03-Dec-01 RMS Added extended SET/SHOW support + 10-Aug-01 RMS Removed register in declarations + 26-Nov-00 RMS Fixed bug in dual device number routine + 21-Nov-00 RMS Fixed bug in reset routine + 15-Oct-00 RMS Added dynamic device number support + + References: + - 2100A Computer Reference Manual (02100-90001, Dec-1971) + - Model 2100A Computer Installation and Maintenance Manual + (02100-90002, Aug-1972) + - HP 1000 M/E/F-Series Computers Technical Reference Handbook + (5955-0282, Mar-1980) + - HP 1000 M/E/F-Series Computers Engineering and Reference Documentation + (92851-90001, Mar-1981) + - HP 1000 M/E/F-Series Computers I/O Interfacing Guide + (02109-90006, Sep-1980) + - 12607A Direct Memory Access Operating and Service Manual + (12607-90002, Jan-1970) + - 12578A/12578A-01 Direct Memory Access Operating and Service Manual + (12578-9001, Mar-1972) + - 12892B Memory Protect Installation Manual (12892-90007, Jun-1978) + + + The register state for the HP 2116 CPU is: + + AR<15:0> A register - addressable as location 0 + BR<15:0> B register - addressable as location 1 + PC<14:0> P register - program counter + SR<15:0> S register - switch register + MR<14:0> M register - memory address + TR<15:0> T register - memory data + E extend flag (carry out) + O overflow flag + + The 2100 adds memory protection logic: + + mp_fence<14:0> memory fence register + mp_viol<15:0> memory protection violation register (F register) + + The 21MX adds a pair of index registers and memory expansion logic: + + XR<15:0> X register + YR<15:0> Y register + dms_sr<15:0> dynamic memory system status register + dms_vr<15:0> dynamic memory system violation register + + The original HP 2116 has four instruction formats: memory reference, + shift, alter/skip, and I/O. The HP 2100 added extended memory reference + and extended arithmetic. The HP21MX added extended byte, bit, and word + instructions as well as extended memory. + + The memory reference format is: + + 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + |in| op |cp| offset | memory reference + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + + <14:11> mnemonic action + + 0010 AND A = A & M[MA] + 0011 JSB M[MA] = P, P = MA + 1 + 0100 XOR A = A ^ M[MA] + 0101 JMP P = MA + 0110 IOR A = A | M[MA] + 0111 ISZ M[MA] = M[MA] + 1, skip if M[MA] == 0 + 1000 ADA A = A + M[MA] + 1001 ADB B = B + M[MA] + 1010 CPA skip if A != M[MA] + 1011 CPB skip if B != M[MA] + 1100 LDA A = M[MA] + 1101 LDB B = M[MA] + 1110 STA M[MA] = A + 1111 STB M[MA] = B + + <15,10> mode action + + 0,0 page zero direct MA = IR<9:0> + 0,1 current page direct MA = PC<14:0>'IR,9:0> + 1,0 page zero indirect MA = M[IR<9:0>] + 1,1 current page indirect MA = M[PC<14:10>'IR<9:0>] + + Memory reference instructions can access an address space of 32K words. + An instruction can directly reference the first 1024 words of memory + (called page zero), as well as 1024 words of the current page; it can + indirectly access all 32K. + + The shift format is: + + 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + | 0 0 0 0|ab| 0|s1| op1 |ce|s2|sl| op2 | shift + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + | | \---+---/ | | | \---+---/ + | | | | | | | + | | | | | | +---- shift 2 opcode + | | | | | +---------- skip if low bit == 0 + | | | | +------------- shift 2 enable + | | | +---------------- clear Extend + | | +---------------------- shift 1 opcode + | +---------------------------- shift 1 enable + +---------------------------------- A/B select + + The alter/skip format is: + + 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + | 0 0 0 0|ab| 1|regop| e op|se|ss|sl|in|sz|rs| alter/skip + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + | \-+-/ \-+-/ | | | | | | + | | | | | | | | +- reverse skip sense + | | | | | | | +---- skip if register == 0 + | | | | | | +------- increment register + | | | | | +---------- skip if low bit == 0 + | | | | +------------- skip if sign bit == 0 + | | | +---------------- skip if Extend == 0 + | | +--------------------- clr/com/set Extend + | +--------------------------- clr/com/set register + +---------------------------------- A/B select + + The I/O transfer format is: + + 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + | 1 0 0 0|ab| 1|hc| opcode | device | I/O transfer + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + | | \---+---/\-------+-------/ + | | | | + | | | +--------- device select + | | +---------------------- opcode + | +---------------------------- hold/clear flag + +---------------------------------- A/B select + + The IO transfer instruction controls the specified device. + Depending on the opcode, the instruction may set or clear + the device flag, start or stop I/O, or read or write data. + + The 2100 added an extended memory reference instruction; + the 21MX added extended arithmetic, operate, byte, word, + and bit instructions. Note that the HP 21xx is, despite + the right-to-left bit numbering, a big endian system. + Bits <15:8> are byte 0, and bits <7:0> are byte 1. + + + The extended memory reference format (HP 2100) is: + + 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + | 1| 0 0 0|op| 0| opcode | extended mem ref + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + |in| operand address | + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + + The extended arithmetic format (HP 2100) is: + + 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + | 1| 0 0 0 0 0|dr| 0 0| opcode |shift count| extended arithmetic + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + + The extended operate format (HP 21MX) is: + + 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + | 1| 0 0 0|op| 0| 1 1 1 1 1| opcode | extended operate + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + + The extended byte and word format (HP 21MX) is: + + 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + | 1| 0 0 0 1 0 1 1 1 1 1 1| opcode | extended byte/word + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + |in| operand address | + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + | 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0| + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + + The extended bit operate format (HP 21MX) is: + + 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + | 1| 0 0 0 1 0 1 1 1 1 1 1 1| opcode | extended bit operate + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + |in| operand address | + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + |in| operand address | + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + + General notes: + + 1. Reasons to stop. The simulator can be stopped by: + + HALT instruction + breakpoint encountered + infinite indirection loop + unimplemented instruction and stop_inst flag set + unknown I/O device and stop_dev flag set + I/O error in I/O simulator + + 2. Interrupts. I/O devices are modelled by substituting software states for + I/O backplane signals. Signals generated by I/O instructions and DMA + cycles are dispatched to the target device for action. Backplane signals + are processed sequentially, except for the "clear flag" signal, which may + be generated in parallel with another signal. For example, the "STC sc,C" + instruction generates the "set control" and the "clear flag" signals + concurrently. + + CPU interrupt signals are modelled as three parallel arrays: + + - device request priority as bit vector dev_prl [2] [31..0] + - device interrupt requests as bit vector dev_irq [2] [31..0] + - device service requests as bit vector dev_srq [2] [31..0] + + Each array forms a 64-bit vector, with bits 0-31 of the first element + corresponding to select codes 00-37 octal, and bits 0-31 of the second + element corresponding to select codes 40-77 octal. + + The HP 2100 interrupt structure is based on the PRH, PRL, IRQ, and IAK + signals. PRH indicates that no higher-priority device is interrupting. + PRL indicates to lower-priority devices that a given device is not + interrupting. IRQ indicates that a given device is requesting an + interrupt. IAK indicates that the given device's interrupt request is + being acknowledged. + + PRH and PRL form a hardware priority chain that extends from interface to + interface on the backplane. We model just PRL, as PRH is calculated from + the PRLs of higher-priority devices. + + Typical I/O devices have a flag, flag buffer, and control flip-flop. If a + device's flag, flag buffer, and control bits are set, and the device is + the highest priority on the interrupt chain, it requests an interrupt by + asserting IRQ. When the interrupt is acknowledged with IAK, the flag + buffer is cleared, preventing further interrupt requests from that device. + The combination of flag and control set blocks interrupts from lower + priority devices. + + Service requests are used to trigger the DMA service logic. Setting the + device flag typically also sets SRQ, although SRQ may be calculated + independently. + + 3. Non-existent memory. On the HP 2100, reads to non-existent memory + return zero, and writes are ignored. In the simulator, the + largest possible memory is instantiated and initialized to zero. + Thus, only writes need be checked against memory size. + + On the 21xx machines, doing SET CPU LOADERDISABLE decreases available + memory size by 64 words. + + 4. Adding I/O devices. These modules must be modified: + + hp2100_defs.h add interrupt request definition + hp2100_sys.c add sim_devices table entry + + 5. Instruction interruptibility. The simulator is fast enough, compared + to the run-time of the longest instructions, for interruptibility not + to matter. But the HP diagnostics explicitly test interruptibility in + EIS and DMS instructions, and long indirect address chains. Accordingly, + the simulator does "just enough" to pass these tests. In particular, if + an interrupt is pending but deferred at the beginning of an interruptible + instruction, the interrupt is taken at the appropriate point; but there + is no testing for new interrupts during execution (that is, the event + timer is not called). + + 6. Interrupt deferral. At instruction fetch time, a pending interrupt + request will be deferred if the previous instruction was a JMP indirect, + JSB indirect, STC, CLC, STF, CLF, or was executing from an interrupt trap + cell. In addition, the following instructions will cause deferral on the + 1000 series: SFS, SFC, JRS, DJP, DJS, SJP, SJS, UJP, and UJS. + + On the HP 1000, the request is always deferred until after the current + instruction completes. On the 21xx, the request is deferred unless the + current instruction is an MRG instruction other than JMP or JMP,I or + JSB,I. Note that for the 21xx, SFS and SFC are not included in the + deferral criteria. + + 7. Terminology. The 1000 series of computers was originally called the 21MX + at introduction. The 21MX (occasionally, 21MXM) corresponds to the 1000 + M-Series, and the 21MXE (occasionally, 21XE) corresponds to the 1000 + E-Series. The model numbers were changed before the introduction of the + 1000 F-Series, although some internal HP documentation refers to a 21MXF. + + The terms MEM (Memory Expansion Module), MEU (Memory Expansion Unit), DMI + (Dynamic Mapping Instructions), and DMS (Dynamic Mapping System) are used + somewhat interchangeably to refer to the logical-to-physical memory + address translation option provided on the 1000-Series. DMS consists of + the MEM card (12731A) and the DMI firmware (13307A). However, MEM and MEU + have been used interchangeably to refer to the mapping card, as have DMI + and DMS to refer to the firmware instructions. +*/ + + +#include "hp2100_defs.h" +#include "hp2100_cpu.h" +#include "hp2100_cpu1.h" + + +/* Memory protect constants */ + +#define UNIT_V_MP_JSB (UNIT_V_UF + 0) /* MP jumper W5 */ +#define UNIT_V_MP_INT (UNIT_V_UF + 1) /* MP jumper W6 */ +#define UNIT_V_MP_SEL1 (UNIT_V_UF + 2) /* MP jumper W7 */ +#define UNIT_MP_JSB (1 << UNIT_V_MP_JSB) /* 1 = W5 is out */ +#define UNIT_MP_INT (1 << UNIT_V_MP_INT) /* 1 = W6 is out */ +#define UNIT_MP_SEL1 (1 << UNIT_V_MP_SEL1) /* 1 = W7 is out */ + +/* DMA channels */ + +typedef enum { ch1, ch2 } CHANNEL; /* channel number */ + +#define DMA_CHAN_COUNT 2 /* number of DMA channels */ + +#define DMA_OE 020000000000 /* byte packing odd/even flag */ +#define DMA1_STC 0100000 /* DMA - issue STC */ +#define DMA1_PB 0040000 /* DMA - pack bytes */ +#define DMA1_CLC 0020000 /* DMA - issue CLC */ +#define DMA2_OI 0100000 /* DMA - output/input */ + +typedef struct { + FLIP_FLOP control; /* control flip-flop */ + FLIP_FLOP flag; /* flag flip-flop */ + FLIP_FLOP flagbuf; /* flag buffer flip-flop */ + FLIP_FLOP xferen; /* transfer enable flip-flop */ + FLIP_FLOP select; /* register select flip-flop */ + + uint32 cw1; /* device select */ + uint32 cw2; /* direction, address */ + uint32 cw3; /* word count */ + uint32 packer; /* byte-packer holding reg */ + } DMA_STATE; + +#define DMA_1_REQ (1 << ch1) /* channel 1 request */ +#define DMA_2_REQ (1 << ch2) /* channel 2 request */ + + +/* Command line switches */ + +#define ALL_BKPTS (SWMASK('E')|SWMASK('N')|SWMASK('S')|SWMASK('U')) +#define ALL_MAPMODES (SWMASK('S')|SWMASK('U')|SWMASK('P')|SWMASK('Q')) + + +/* RTE base-page addresses. */ + +static const uint32 xeqt = 0001717; /* XEQT address */ +static const uint32 tbg = 0001674; /* TBG address */ + +/* DOS base-page addresses. */ + +static const uint32 m64 = 0000040; /* constant -64 address */ +static const uint32 p64 = 0000067; /* constant +64 address */ + +/* CPU local data */ + +static uint32 jsb_plb = 2; /* protected lower bound for JSB */ +static uint32 saved_MR = 0; /* between executions */ +static uint32 fwanxm = 0; /* first word addr of nx mem */ + +/* CPU global data */ + +uint16 *M = NULL; /* memory */ +uint16 ABREG[2]; /* A/B registers */ +uint32 PC = 0; /* P register */ +uint32 SR = 0; /* S register */ +uint32 MR = 0; /* M register */ +uint32 TR = 0; /* T register */ +uint32 XR = 0; /* X register */ +uint32 YR = 0; /* Y register */ +uint32 E = 0; /* E register */ +uint32 O = 0; /* O register */ +FLIP_FLOP ion = CLEAR; /* interrupt enable */ +t_bool ion_defer = FALSE; /* interrupt defer */ +uint32 intaddr = 0; /* interrupt addr */ +uint32 stop_inst = 1; /* stop on ill inst */ +uint32 stop_dev = 0; /* stop on ill dev */ +uint16 pcq[PCQ_SIZE] = { 0 }; /* PC queue */ +uint32 pcq_p = 0; /* PC queue ptr */ +REG *pcq_r = NULL; /* PC queue reg ptr */ + +uint32 dev_prl [2] = { ~(uint32) 0, ~(uint32) 0 }; /* device priority low bit vector */ +uint32 dev_irq [2] = { 0, 0 }; /* device interrupt request bit vector */ +uint32 dev_srq [2] = { 0, 0 }; /* device service request bit vector */ + +/* Memory protect global data */ + +FLIP_FLOP mp_control = CLEAR; /* MP control flip-flop */ +FLIP_FLOP mp_flag = CLEAR; /* MP flag flip-flop */ +FLIP_FLOP mp_flagbuf = CLEAR; /* MP flag buffer flip-flop */ +FLIP_FLOP mp_mevff = CLEAR; /* memory expansion violation flip-flop */ +FLIP_FLOP mp_evrff = SET; /* enable violation register flip-flop */ + +uint32 mp_fence = 0; /* MP fence register */ +uint32 mp_viol = 0; /* MP violation register */ + +uint32 iop_sp = 0; /* iop stack reg */ +uint32 ind_max = 16; /* iadr nest limit */ +uint32 err_PC = 0; /* error PC */ +jmp_buf save_env; /* MP abort handler */ + +/* DMA global data */ + +DMA_STATE dma [DMA_CHAN_COUNT]; /* per-channel state */ + +/* Dynamic mapping system global data */ + +uint32 dms_enb = 0; /* dms enable */ +uint32 dms_ump = 0; /* dms user map */ +uint32 dms_sr = 0; /* dms status reg */ +uint32 dms_vr = 0; /* dms violation reg */ +uint16 dms_map[MAP_NUM * MAP_LNT] = { 0 }; /* dms maps */ + +/* External data */ + +extern DIB clk_dib; /* CLK DIB for idle check */ +extern const BOOT_ROM ptr_rom, dq_rom, ms_rom, ds_rom; /* boot ROMs for cpu_boot routine */ + +/* CPU local routines */ + +static t_stat Ea (uint32 IR, uint32 *addr, uint32 irq); +static uint16 ReadTAB (uint32 va); +static uint32 dms (uint32 va, uint32 map, uint32 prot); +static uint32 shift (uint32 inval, uint32 flag, uint32 oper); +static t_stat dma_cycle (CHANNEL chan, uint32 map); +static uint32 calc_dma (void); +static t_bool dev_conflict (void); +static uint32 devdisp (uint32 select_code, IOCYCLE signal_set, uint16 data); + +/* CPU global routines */ + +t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); +t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw); +t_stat cpu_reset (DEVICE *dptr); +t_stat cpu_boot (int32 unitno, DEVICE *dptr); +t_stat mp_reset (DEVICE *dptr); +t_stat dma_reset (DEVICE *dptr); +t_stat cpu_set_size (UNIT *uptr, int32 new_size, char *cptr, void *desc); +t_stat cpu_set_model (UNIT *uptr, int32 new_model, char *cptr, void *desc); +t_stat cpu_show_model (FILE *st, UNIT *uptr, int32 val, void *desc); +t_stat cpu_set_opt (UNIT *uptr, int32 option, char *cptr, void *desc); +t_stat cpu_clr_opt (UNIT *uptr, int32 option, char *cptr, void *desc); +t_stat cpu_set_ldr (UNIT *uptr, int32 enable, char *cptr, void *desc); +t_stat cpu_set_idle (UNIT *uptr, int32 option, char *cptr, void *desc); +t_stat cpu_show_idle (FILE *st, UNIT *uptr, int32 val, void *desc); +void hp_post_cmd (t_bool from_scp); + +IOHANDLER cpuio; +IOHANDLER ovflio; +IOHANDLER pwrfio; +IOHANDLER protio; +IOHANDLER dmapio; +IOHANDLER dmasio; +IOHANDLER nullio; + + +/* Table of CPU features by model. + + Fields: + - typ: standard features plus typically configured options. + - opt: complete list of optional features. + - maxmem: maximum configurable memory in 16-bit words. + + Features in the "typical" list are enabled when the CPU model is selected. + If a feature appears in the "typical" list but NOT in the "optional" list, + then it is standard equipment and cannot be disabled. If a feature appears + in the "optional" list, then it may be enabled or disabled as desired by the + user. +*/ + +struct FEATURE_TABLE { /* CPU model feature table: */ + uint32 typ; /* - typical features */ + uint32 opt; /* - optional features */ + uint32 maxmem; /* - maximum memory */ + }; + +static struct FEATURE_TABLE cpu_features[] = { /* features in UNIT_xxxx order*/ + { UNIT_DMA | UNIT_MP, /* UNIT_2116 */ + UNIT_PFAIL | UNIT_DMA | UNIT_MP | UNIT_EAU, + 32768 }, + { UNIT_DMA, /* UNIT_2115 */ + UNIT_PFAIL | UNIT_DMA | UNIT_EAU, + 8192 }, + { UNIT_DMA, /* UNIT_2114 */ + UNIT_PFAIL | UNIT_DMA, + 16384 }, + { 0, 0, 0 }, + { UNIT_PFAIL | UNIT_MP | UNIT_DMA | UNIT_EAU, /* UNIT_2100 */ + UNIT_DMA | UNIT_FP | UNIT_IOP | UNIT_FFP, + 32768 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { UNIT_MP | UNIT_DMA | UNIT_EAU | UNIT_FP | UNIT_DMS, /* UNIT_1000_M */ + UNIT_PFAIL | UNIT_DMA | UNIT_MP | UNIT_DMS | + UNIT_IOP | UNIT_FFP | UNIT_DS, + 1048576 }, + { UNIT_MP | UNIT_DMA | UNIT_EAU | UNIT_FP | UNIT_DMS, /* UNIT_1000_E */ + UNIT_PFAIL | UNIT_DMA | UNIT_MP | UNIT_DMS | + UNIT_IOP | UNIT_FFP | UNIT_DBI | UNIT_DS | UNIT_EMA_VMA, + 1048576 }, + { UNIT_MP | UNIT_DMA | UNIT_EAU | UNIT_FP | /* UNIT_1000_F */ + UNIT_FFP | UNIT_DBI | UNIT_DMS, + UNIT_PFAIL | UNIT_DMA | UNIT_MP | UNIT_VIS | + UNIT_IOP | UNIT_DS | UNIT_SIGNAL | UNIT_EMA_VMA, + 1048576 } + }; + + +/* Null device information block */ + +DIB null_dib = { &nullio, 0 }; + +/* CPU data structures + + cpu_dib CPU device information block + cpu_dev CPU device descriptor + cpu_unit CPU unit descriptor + cpu_reg CPU register list + cpu_mod CPU modifiers list + cpu_deb CPU debug flags +*/ + +DIB cpu_dib = { &cpuio, CPU }; + +UNIT cpu_unit = { UDATA (NULL, UNIT_FIX + UNIT_BINK, 0) }; + +REG cpu_reg[] = { + { ORDATA (P, PC, 15) }, + { ORDATA (A, AR, 16), REG_FIT }, + { ORDATA (B, BR, 16), REG_FIT }, + { ORDATA (M, MR, 15) }, + { ORDATA (T, TR, 16), REG_RO }, + { ORDATA (X, XR, 16) }, + { ORDATA (Y, YR, 16) }, + { ORDATA (S, SR, 16) }, + { FLDATA (E, E, 0) }, + { FLDATA (O, O, 0) }, + { FLDATA (ION, ion, 0) }, + { FLDATA (ION_DEFER, ion_defer, 0) }, + { ORDATA (CIR, intaddr, 6) }, + { FLDATA (DMSENB, dms_enb, 0) }, + { FLDATA (DMSCUR, dms_ump, VA_N_PAG) }, + { ORDATA (DMSSR, dms_sr, 16) }, + { ORDATA (DMSVR, dms_vr, 16) }, + { BRDATA (DMSMAP, dms_map, 8, 16, MAP_NUM * MAP_LNT) }, + { ORDATA (IOPSP, iop_sp, 16) }, + { FLDATA (STOP_INST, stop_inst, 0) }, + { FLDATA (STOP_DEV, stop_dev, 1) }, + { DRDATA (INDMAX, ind_max, 16), REG_NZ + PV_LEFT }, + { BRDATA (PCQ, pcq, 8, 15, PCQ_SIZE), REG_RO+REG_CIRC }, + { ORDATA (PCQP, pcq_p, 6), REG_HRO }, + { ORDATA (JSBPLB, jsb_plb, 32), REG_HRO }, + { ORDATA (SAVEDMR, saved_MR, 32), REG_HRO }, + { ORDATA (FWANXM, fwanxm, 32), REG_HRO }, + { ORDATA (WRU, sim_int_char, 8), REG_HRO }, + { ORDATA (BRK, sim_brk_char, 8), REG_HRO }, + { ORDATA (DEL, sim_del_char, 8), REG_HRO }, + { BRDATA (PRL, dev_prl, 8, 32, 2), REG_HRO }, + { BRDATA (IRQ, dev_irq, 8, 32, 2), REG_HRO }, + { BRDATA (SRQ, dev_srq, 8, 32, 2), REG_HRO }, + { NULL } + }; + +/* CPU modifier table. + + The 21MX monikers are deprecated in favor of the 1000 designations. See the + "HP 1000 Series Naming History" on the back inside cover of the Technical + Reference Handbook. */ + +MTAB cpu_mod[] = { + { UNIT_MODEL_MASK, UNIT_2116, "", "2116", &cpu_set_model, &cpu_show_model, (void *) "2116" }, + { UNIT_MODEL_MASK, UNIT_2115, "", "2115", &cpu_set_model, &cpu_show_model, (void *) "2115" }, + { UNIT_MODEL_MASK, UNIT_2114, "", "2114", &cpu_set_model, &cpu_show_model, (void *) "2114" }, + { UNIT_MODEL_MASK, UNIT_2100, "", "2100", &cpu_set_model, &cpu_show_model, (void *) "2100" }, + { UNIT_MODEL_MASK, UNIT_1000_E, "", "1000-E", &cpu_set_model, &cpu_show_model, (void *) "1000-E" }, + { UNIT_MODEL_MASK, UNIT_1000_E, NULL, "21MX-E", &cpu_set_model, &cpu_show_model, (void *) "1000-E" }, + { UNIT_MODEL_MASK, UNIT_1000_M, "", "1000-M", &cpu_set_model, &cpu_show_model, (void *) "1000-M" }, + { UNIT_MODEL_MASK, UNIT_1000_M, NULL, "21MX-M", &cpu_set_model, &cpu_show_model, (void *) "1000-M" }, + +#if defined (HAVE_INT64) + { UNIT_MODEL_MASK, UNIT_1000_F, "", "1000-F", &cpu_set_model, &cpu_show_model, (void *) "1000-F" }, +#endif + + { MTAB_XTD | MTAB_VDV, 1, "IDLE", "IDLE", &cpu_set_idle, &cpu_show_idle, NULL }, + { MTAB_XTD | MTAB_VDV, 0, NULL, "NOIDLE", &cpu_set_idle, NULL, NULL }, + + { MTAB_XTD | MTAB_VDV, 1, NULL, "LOADERENABLE", &cpu_set_ldr, NULL, NULL }, + { MTAB_XTD | MTAB_VDV, 0, NULL, "LOADERDISABLE", &cpu_set_ldr, NULL, NULL }, + + { UNIT_EAU, UNIT_EAU, "EAU", "EAU", &cpu_set_opt, NULL, NULL }, + { UNIT_EAU, 0, "no EAU", NULL, NULL, NULL, NULL }, + { MTAB_XTD | MTAB_VDV, UNIT_EAU, NULL, "NOEAU", &cpu_clr_opt, NULL, NULL }, + + { UNIT_FP, UNIT_FP, "FP", "FP", &cpu_set_opt, NULL, NULL }, + { UNIT_FP, 0, "no FP", NULL, NULL, NULL, NULL }, + { MTAB_XTD | MTAB_VDV, UNIT_FP, NULL, "NOFP", &cpu_clr_opt, NULL, NULL }, + + { UNIT_IOP, UNIT_IOP, "IOP", "IOP", &cpu_set_opt, NULL, NULL }, + { UNIT_IOP, 0, "no IOP", NULL, NULL, NULL, NULL }, + { MTAB_XTD | MTAB_VDV, UNIT_IOP, NULL, "NOIOP", &cpu_clr_opt, NULL, NULL }, + + { UNIT_DMS, UNIT_DMS, "DMS", "DMS", &cpu_set_opt, NULL, NULL }, + { UNIT_DMS, 0, "no DMS", NULL, NULL, NULL, NULL }, + { MTAB_XTD | MTAB_VDV, UNIT_DMS, NULL, "NODMS", &cpu_clr_opt, NULL, NULL }, + + { UNIT_FFP, UNIT_FFP, "FFP", "FFP", &cpu_set_opt, NULL, NULL }, + { UNIT_FFP, 0, "no FFP", NULL, NULL, NULL, NULL }, + { MTAB_XTD | MTAB_VDV, UNIT_FFP, NULL, "NOFFP", &cpu_clr_opt, NULL, NULL }, + + { UNIT_DBI, UNIT_DBI, "DBI", "DBI", &cpu_set_opt, NULL, NULL }, + { UNIT_DBI, 0, "no DBI", NULL, NULL, NULL, NULL }, + { MTAB_XTD | MTAB_VDV, UNIT_DBI, NULL, "NODBI", &cpu_clr_opt, NULL, NULL }, + + { UNIT_EMA_VMA, UNIT_EMA, "EMA", "EMA", &cpu_set_opt, NULL, NULL }, + { MTAB_XTD | MTAB_VDV, UNIT_EMA, NULL, "NOEMA", &cpu_clr_opt, NULL, NULL }, + + { UNIT_EMA_VMA, UNIT_VMAOS, "VMA", "VMA", &cpu_set_opt, NULL, NULL }, + { MTAB_XTD | MTAB_VDV, UNIT_VMAOS, NULL, "NOVMA", &cpu_clr_opt, NULL, NULL }, + + { UNIT_EMA_VMA, 0, "no EMA/VMA", NULL, &cpu_set_opt, NULL, NULL }, + +#if defined (HAVE_INT64) + { UNIT_VIS, UNIT_VIS, "VIS", "VIS", &cpu_set_opt, NULL, NULL }, + { UNIT_VIS, 0, "no VIS", NULL, NULL, NULL, NULL }, + { MTAB_XTD | MTAB_VDV, UNIT_VIS, NULL, "NOVIS", &cpu_clr_opt, NULL, NULL }, + + { UNIT_SIGNAL, UNIT_SIGNAL,"SIGNAL", "SIGNAL", &cpu_set_opt, NULL, NULL }, + { UNIT_SIGNAL, 0, "no SIGNAL", NULL, NULL, NULL, NULL }, + { MTAB_XTD | MTAB_VDV, UNIT_SIGNAL, NULL, "NOSIGNAL", &cpu_clr_opt, NULL, NULL }, +#endif + +/* Future microcode support. + { UNIT_DS, UNIT_DS, "DS", "DS", &cpu_set_opt, NULL, NULL }, + { UNIT_DS, 0, "no DS", NULL, NULL, NULL, NULL }, + { MTAB_XTD | MTAB_VDV, UNIT_DS, NULL, "NODS", &cpu_clr_opt, NULL, NULL }, +*/ + + { MTAB_XTD | MTAB_VDV, 4096, NULL, "4K", &cpu_set_size, NULL, NULL }, + { MTAB_XTD | MTAB_VDV, 8192, NULL, "8K", &cpu_set_size, NULL, NULL }, + { MTAB_XTD | MTAB_VDV, 12288, NULL, "12K", &cpu_set_size, NULL, NULL }, + { MTAB_XTD | MTAB_VDV, 16384, NULL, "16K", &cpu_set_size, NULL, NULL }, + { MTAB_XTD | MTAB_VDV, 24576, NULL, "24K", &cpu_set_size, NULL, NULL }, + { MTAB_XTD | MTAB_VDV, 32768, NULL, "32K", &cpu_set_size, NULL, NULL }, + { MTAB_XTD | MTAB_VDV, 65536, NULL, "64K", &cpu_set_size, NULL, NULL }, + { MTAB_XTD | MTAB_VDV, 131072, NULL, "128K", &cpu_set_size, NULL, NULL }, + { MTAB_XTD | MTAB_VDV, 262144, NULL, "256K", &cpu_set_size, NULL, NULL }, + { MTAB_XTD | MTAB_VDV, 524288, NULL, "512K", &cpu_set_size, NULL, NULL }, + { MTAB_XTD | MTAB_VDV, 1048576, NULL, "1024K", &cpu_set_size, NULL, NULL }, + { 0 } + }; + +DEBTAB cpu_deb[] = { + { "OS", DEB_OS }, + { "OSTBG", DEB_OSTBG }, + { "VMA", DEB_VMA }, + { "EMA", DEB_EMA }, + { "VIS", DEB_VIS }, + { "SIG", DEB_SIG }, + { NULL, 0 } + }; + +DEVICE cpu_dev = { + "CPU", /* device name */ + &cpu_unit, /* unit array */ + cpu_reg, /* register array */ + cpu_mod, /* modifier array */ + 1, /* number of units */ + 8, /* address radix */ + PA_N_SIZE, /* address width */ + 1, /* address increment */ + 8, /* data radix */ + 16, /* data width */ + &cpu_ex, /* examine routine */ + &cpu_dep, /* deposit routine */ + &cpu_reset, /* reset routine */ + &cpu_boot, /* boot routine */ + NULL, /* attach routine */ + NULL, /* detach routine */ + &cpu_dib, /* device information block */ + DEV_DEBUG, /* device flags */ + 0, /* debug control flags */ + cpu_deb, /* debug flag name table */ + NULL, /* memory size change routine */ + NULL }; /* logical device name */ + +/* Overflow device information block */ + +DIB ovfl_dib = { &ovflio, OVF }; + +/* Powerfail device information block */ + +DIB pwrf_dib = { &pwrfio, PWR }; + +/* Memory protect data structures + + mp_dib MP device information block + mp_dev MP device descriptor + mp_unit MP unit descriptor + mp_reg MP register list + mp_mod MP modifiers list +*/ + +DIB mp_dib = { &protio, PRO }; + +UNIT mp_unit = { UDATA (NULL, UNIT_MP_SEL1, 0) }; /* default is JSB in, INT in, SEL1 out */ + +REG mp_reg[] = { + { FLDATA (CTL, mp_control, 0) }, + { FLDATA (FLG, mp_flag, 0) }, + { FLDATA (FBF, mp_flagbuf, 0) }, + { ORDATA (FR, mp_fence, 15) }, + { ORDATA (VR, mp_viol, 16) }, + { FLDATA (EVR, mp_evrff, 0) }, + { FLDATA (MEV, mp_mevff, 0) }, + { NULL } + }; + +MTAB mp_mod[] = { + { UNIT_MP_JSB, UNIT_MP_JSB, "JSB (W5) out", "JSBOUT", NULL }, + { UNIT_MP_JSB, 0, "JSB (W5) in", "JSBIN", NULL }, + { UNIT_MP_INT, UNIT_MP_INT, "INT (W6) out", "INTOUT", NULL }, + { UNIT_MP_INT, 0, "INT (W6) in", "INTIN", NULL }, + { UNIT_MP_SEL1, UNIT_MP_SEL1, "SEL1 (W7) out", "SEL1OUT", NULL }, + { UNIT_MP_SEL1, 0, "SEL1 (W7) in", "SEL1IN", NULL }, + { 0 } + }; + +DEVICE mp_dev = { + "MP", /* device name */ + &mp_unit, /* unit array */ + mp_reg, /* register array */ + mp_mod, /* modifier array */ + 1, /* number of units */ + 8, /* address radix */ + 1, /* address width */ + 1, /* address increment */ + 8, /* data radix */ + 16, /* data width */ + NULL, /* examine routine */ + NULL, /* deposit routine */ + &mp_reset, /* reset routine */ + NULL, /* boot routine */ + NULL, /* attach routine */ + NULL, /* detach routine */ + &mp_dib, /* device information block */ + DEV_DISABLE | DEV_DIS, /* device flags */ + 0, /* debug control flags */ + NULL, /* debug flag name table */ + NULL, /* memory size change routine */ + NULL }; /* logical device name */ + +/* DMA controller data structures + + dmax_dib DMAx device information block + dmax_dev DMAx device descriptor + dmax_reg DMAx register list +*/ + +DIB dmap1_dib = { &dmapio, DMA1, ch1 }; +DIB dmas1_dib = { &dmasio, DMALT1, ch1 }; + +UNIT dma1_unit = { UDATA (NULL, 0, 0) }; + +REG dma1_reg[] = { + { FLDATA (XFR, dma [ch1].xferen, 0) }, + { FLDATA (CTL, dma [ch1].control, 0) }, + { FLDATA (FLG, dma [ch1].flag, 0) }, + { FLDATA (FBF, dma [ch1].flagbuf, 0) }, + { FLDATA (CTL2, dma [ch1].select, 0) }, + { ORDATA (CW1, dma [ch1].cw1, 16) }, + { ORDATA (CW2, dma [ch1].cw2, 16) }, + { ORDATA (CW3, dma [ch1].cw3, 16) }, + { FLDATA (BYTE, dma [ch1].packer, 31) }, + { ORDATA (PACKER, dma [ch1].packer, 8) }, + { NULL } + }; + +DEVICE dma1_dev = { + "DMA1", /* device name */ + &dma1_unit, /* unit array */ + dma1_reg, /* register array */ + NULL, /* modifier array */ + 1, /* number of units */ + 8, /* address radix */ + 1, /* address width */ + 1, /* address increment */ + 8, /* data radix */ + 16, /* data width */ + NULL, /* examine routine */ + NULL, /* deposit routine */ + &dma_reset, /* reset routine */ + NULL, /* boot routine */ + NULL, /* attach routine */ + NULL, /* detach routine */ + &dmap1_dib, /* device information block */ + DEV_DISABLE, /* device flags */ + 0, /* debug control flags */ + NULL, /* debug flag name table */ + NULL, /* memory size change routine */ + NULL }; /* logical device name */ + +DIB dmap2_dib = { &dmapio, DMA2, ch2 }; +DIB dmas2_dib = { &dmasio, DMALT2, ch2 }; + +UNIT dma2_unit = { UDATA (NULL, 0, 0) }; + +REG dma2_reg[] = { + { FLDATA (XFR, dma [ch2].xferen, 0) }, + { FLDATA (CTL, dma [ch2].control, 0) }, + { FLDATA (FLG, dma [ch2].flag, 0) }, + { FLDATA (FBF, dma [ch2].flagbuf, 0) }, + { FLDATA (CTL2, dma [ch2].select, 0) }, + { ORDATA (CW1, dma [ch2].cw1, 16) }, + { ORDATA (CW2, dma [ch2].cw2, 16) }, + { ORDATA (CW3, dma [ch2].cw3, 16) }, + { FLDATA (BYTE, dma [ch2].packer, 31) }, + { ORDATA (PACKER, dma [ch2].packer, 8) }, + { NULL } + }; + +DEVICE dma2_dev = { + "DMA2", /* device name */ + &dma2_unit, /* unit array */ + dma2_reg, /* register array */ + NULL, /* modifier array */ + 1, /* number of units */ + 8, /* address radix */ + 1, /* address width */ + 1, /* address increment */ + 8, /* data radix */ + 16, /* data width */ + NULL, /* examine routine */ + NULL, /* deposit routine */ + &dma_reset, /* reset routine */ + NULL, /* boot routine */ + NULL, /* attach routine */ + NULL, /* detach routine */ + &dmap2_dib, /* device information block */ + DEV_DISABLE, /* device flags */ + 0, /* debug control flags */ + NULL, /* debug flag name table */ + NULL, /* memory size change routine */ + NULL }; /* logical device name */ + +static DEVICE *dma_dptrs [] = { &dma1_dev, &dma2_dev }; + + +/* Interrupt deferral table (1000 version) */ +/* Deferral for I/O subops: soHLT, soFLG, soSFC, soSFS, soMIX, soLIX, soOTX, soCTL */ +static t_bool defer_tab [] = { FALSE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, TRUE }; + +/* Device I/O dispatch table */ + +DIB *dtab [64] = { &cpu_dib, &ovfl_dib }; /* init with immutable devices */ + + + +/* Execute CPU instructions. + + This routine is the instruction decode routine for the HP 2100. It is called + from the simulator control program to execute instructions in simulated + memory, starting at the simulated PC. It runs until 'reason' is set to a + status other than SCPE_OK. +*/ + +t_stat sim_instr (void) +{ +uint32 intrq, dmarq; /* set after setjmp */ +uint32 iotrap = 0; /* set after setjmp */ +t_stat reason = SCPE_OK; /* set after setjmp */ +int32 i; /* temp */ +DEVICE *dptr; /* temp */ +DIB *dibptr; /* temp */ +int abortval; + +/* Restore register state */ + +if (dev_conflict ()) /* check device assignment consistency */ + return SCPE_STOP; /* conflict; stop execution */ + +err_PC = PC = PC & VAMASK; /* load local PC */ + +/* Restore I/O state */ + +dev_prl [0] = dev_prl [1] = ~(uint32) 0; /* set all priority lows */ +dev_irq [0] = dev_irq [1] = 0; /* clear all interrupt requests */ +dev_srq [0] = dev_srq [1] = 0; /* clear all service requests */ + +for (i = OPTDEV; i <= MAXDEV; i++) /* default optional devices */ + dtab [i] = &null_dib; + +dtab [PWR] = &pwrf_dib; /* for now, powerfail is always present */ + +for (i = 0; sim_devices [i] != NULL; i++) { /* loop thru dev */ + dptr = sim_devices [i]; + dibptr = (DIB *) dptr->ctxt; /* get DIB */ + + if (dibptr && !(dptr->flags & DEV_DIS)) { /* handler exists and device is enabled? */ + dtab [dibptr->select_code] = dibptr; /* set DIB pointer into dispatch table */ + dibptr->io_handler (dibptr, ioSIR, 0); /* set interrupt request state */ + } + } + +if (dtab [DMA1] != &null_dib) /* first DMA channel enabled? */ + dtab [DMALT1] = &dmas1_dib; /* set up secondary device handler */ + +if (dtab [DMA2] != &null_dib) /* second DMA channel enabled? */ + dtab [DMALT2] = &dmas2_dib; /* set up secondary device handler */ + +/* Configure interrupt deferral table */ + +if (UNIT_CPU_FAMILY == UNIT_FAMILY_21XX) /* 21xx series? */ + defer_tab [soSFC] = defer_tab [soSFS] = FALSE; /* SFC/S doesn't defer */ +else /* 1000 series */ + defer_tab [soSFC] = defer_tab [soSFS] = TRUE; /* SFC/S does defer */ + + +/* Set MP abort handling. + + If an abort occurs in memory protection, the relocation routine executes a + longjmp to this area OUTSIDE the main simulation loop. Memory protection + errors are the only sources of aborts in the HP 2100. All referenced + variables must be globals, and all sim_instr scoped automatics must be set + after the setjmp. + + To initiate an MP abort, use the MP_ABORT macro and pass the violation + address. MP_ABORT should only be called if "mp_control" is SET, as aborts do + not occur if MP is turned off. + + An MP interrupt (SC 05) is qualified by "ion" but not by "ion_defer". If the + interrupt system is off when an MP violation is detected, the violating + instruction will be aborted, even though no interrupt occurs. In this case, + neither the flag nor flag buffer are set, and EVR is not cleared. + + Implementation notes: + + 1. The protected lower bound address for the JSB instruction depends on the + W5 jumper setting. If W5 is in, then the lower bound is 2, allowing JSBs + to the A and B registers. If W5 is out, then the lower bound is 0, just + as with JMP. + + 2. The violation address is passed to enable the MEM violation register to + be updated. The "longjmp" routine will not pass a value of 0; it is + converted internally to 1. This is OK, because only the page number + of the address value is used, and locations 0 and 1 are both on page 0. + + 3. This routine is used both for MP and MEM violations. The MEV flip-flop + will be clear for the former and set for the latter. The MEV violation + register will be updated by "dms_upd_vr" only if the call is NOT for an + MEM violation; if it is, then the VR has already been set and should not + be disturbed. +*/ + +jsb_plb = (mp_unit.flags & UNIT_MP_JSB) ? 0 : 2; /* set protected lower bound for JSB */ + +abortval = setjmp (save_env); /* set abort hdlr */ + +if (abortval) { /* memory protect abort? */ + dms_upd_vr (abortval); /* update violation register (if not MEV) */ + + if (ion) /* interrupt system on? */ + protio (dtab [PRO], ioENF, 0); /* set flag */ + } + +dmarq = calc_dma (); /* initial recalc of DMA masks */ +intrq = calc_int (); /* initial recalc of interrupts */ + + +/* Main instruction fetch/decode loop */ + +while (reason == SCPE_OK) { /* loop until halted */ + uint32 IR, MA, absel, v1, t, skip; + + err_PC = PC; /* save PC for error recovery */ + + if (sim_interval <= 0) { /* event timeout? */ + reason = sim_process_event (); /* process event service */ + + if (reason != SCPE_OK) /* service failed? */ + break; /* stop execution */ + + dmarq = calc_dma (); /* recalc DMA reqs */ + intrq = calc_int (); /* recalc interrupts */ + } + +/* DMA cycles are requested by an I/O card asserting its SRQ signal. If a DMA + channel is programmed to respond to that card's select code, a DMA cycle will + be initiated. A DMA cycle consists of a memory cycle and an I/O cycle. + These cycles are synchronized with the control processor on the 21xx CPUs. + On the 1000s, memory cycles are asynchronous, while I/O cycles are + synchronous. Memory cycle time is about 40% of the I/O cycle time. + + With properly designed interface cards, DMA is capable of taking consecutive + I/O cycles. On all machines except the 1000 M-Series, a DMA cycle freezes + the CPU for the duration of the cycle. On the M-Series, a DMA cycle freezes + the CPU if it attempts an I/O cycle (including IAK) or a directly-interfering + memory cycle. An interleaved memory cycle is allowed. Otherwise, the + control processor is allowed to run. Therefore, during consecutive DMA + cycles, the M-Series CPU will run until an IOG instruction is attempted, + whereas the other CPUs will freeze completely. + + All DMA cards except the 12607B provide two independent channels. If both + channels are active simultaneously, channel 1 has priority for I/O cycles + over channel 2. + + Most I/O cards assert SRQ no more than 50% of the time. A few buffered + cards, such as the 12821A and 13175A Disc Interfaces, are capable of + asserting SRQ continuously while filling or emptying the buffer. If SRQ for + channel 1 is asserted continuously when both channels are active, then no + channel 2 cycles will occur until channel 1 completes. + + Implementation notes: + + 1. CPU freeze is simulated by skipping instruction execution during the + current loop cycle. + + 2. If both channels have SRQ asserted, DMA priority is simulated by skipping + the channel 2 cycle if channel 1's SRQ is still asserted at the end of + its cycle. If it is not, then channel 2 steals the next cycle from the + CPU. + + 3. The 1000 M-Series allows some CPU processing concurrently with + continuous DMA cycles, whereas all other CPUs freeze. The processor + freezes if an I/O cycle is attempted, including an interrupt + acknowledgement. Because some microcode extensions (e.g., Access IOP, + RTE-6/VM OS) perform I/O cycles, advance detection of I/O cycles is + difficult. Therefore, we freeze all processing for the M-Series as well. +*/ + + if (dmarq) { + if (dmarq & DMA_1_REQ) { /* DMA channel 1 request? */ + reason = dma_cycle (ch1, PAMAP); /* do one DMA cycle using port A map */ + + if (reason == SCPE_OK) /* cycle OK? */ + dmarq = calc_dma (); /* recalc DMA requests */ + else + break; /* cycle failed, so stop */ + } + + if ((dmarq & (DMA_1_REQ | DMA_2_REQ)) == DMA_2_REQ) { /* DMA channel 1 idle and channel 2 request? */ + reason = dma_cycle (ch2, PBMAP); /* do one DMA cycle using port B map */ + + if (reason == SCPE_OK) /* cycle OK? */ + dmarq = calc_dma (); /* recalc DMA requests */ + else + break; /* cycle failed, so stop */ + } + + if (dmarq) /* DMA request still pending? */ + continue; /* service it before instruction execution */ + + intrq = calc_int (); /* recalc interrupts */ + } + + if (intrq && ion_defer) /* interrupt pending but deferred? */ + ion_defer = calc_defer (); /* confirm deferral */ + +/* Check for pending interrupt request. + + Interrupt recognition is controlled by three state variables: "ion", + "ion_defer", and "intrq". "ion" corresponds to the INTSYS flip-flop in the + 1000 CPU, "ion_defer" corresponds to the INTEN flip-flop, and "intrq" + corresponds to the NRMINT flip-flop. STF 00 and CLF 00 set and clear INTSYS, + turning the interrupt system on and off. Micro-orders ION and IOFF set and + clear INTEN, deferring or allowing certain interrupts. An IRQ signal from a + device, qualified by the corresponding PRL signal, will set NRMINT to request + a normal interrupt; an IOFF or IAK will clear it. + + Under simulation, "ion" is controlled by STF/CLF 00. "ion_defer" is set or + cleared as appropriate by the individual instruction simulators. "intrq" is + set to the successfully interrupting device's select code, or to zero if + there is no qualifying interrupt request. + + Presuming PRL is set to allow priority to an interrupting device: + + 1. Power fail (SC 04) may interrupt if "ion_defer" is clear; this is not + conditional on "ion" being set. + + 2. Memory protect (SC 05) may interrupt if "ion" is set; this is not + conditional on "ion_defer" being clear. + + 3. Parity error (SC 05) may interrupt always; this is not conditional on + "ion" being set or "ion_defer" being clear. + + 4. All other devices (SC 06 and up) may interrupt if "ion" is set and + "ion_defer" is clear. + + Qualification with "ion" is performed by "calc_int", except for case 2, which + is qualified by the MP abort handler above (because qualification occurs on + the MP card, rather than in the CPU). Therefore, we need only qualify by + "ion_defer" here. +*/ + + if (intrq && ((intrq == PRO) || !ion_defer)) { /* interrupt request? */ + if (sim_brk_summ && /* any breakpoints? */ + sim_brk_test (intrq, SWMASK ('E') | /* unconditional or right type for DMS? */ + (dms_enb ? SWMASK ('S') : SWMASK ('N')))) { + reason = STOP_IBKPT; /* stop simulation */ + break; + } + + intaddr = intrq; /* save int addr in CIR */ + intrq = 0; /* clear request */ + ion_defer = TRUE; /* defer interrupts */ + iotrap = 1; /* mark as I/O trap cell instr */ + + if (dms_enb) /* dms enabled? */ + dms_sr = dms_sr | MST_ENBI; /* set in status */ + else /* not enabled */ + dms_sr = dms_sr & ~MST_ENBI; /* clear in status */ + + if (dms_ump) { /* user map enabled at interrupt? */ + dms_sr = dms_sr | MST_UMPI; /* set in status */ + dms_ump = SMAP; /* switch to system map */ + } + else /* system map enabled at interrupt */ + dms_sr = dms_sr & ~MST_UMPI; /* clear in status */ + + IR = ReadW (intaddr); /* get trap cell instruction */ + + devdisp (intaddr, ioIAK, (uint16) IR); /* acknowledge interrupt */ + + if (intaddr != PRO) /* not MP interrupt? */ + protio (dtab [intaddr], ioIAK, IR); /* send IAK for device to MP too */ + } + + else { /* normal instruction */ + iotrap = 0; /* not a trap cell instruction */ + + if (sim_brk_summ && /* any breakpoints? */ + sim_brk_test (PC, SWMASK ('E') | /* unconditional or */ + (dms_enb ? /* correct type for DMS state? */ + (dms_ump ? + SWMASK ('U') : SWMASK ('S')) : + SWMASK ('N')))) { + reason = STOP_IBKPT; /* stop simulation */ + break; + } + + if (mp_evrff) /* violation register enabled */ + mp_viol = PC; /* update with current PC */ + + IR = ReadW (PC); /* fetch instr */ + PC = (PC + 1) & VAMASK; + ion_defer = FALSE; + } + + sim_interval = sim_interval - 1; /* count instruction */ + +/* Instruction decode. The 21MX does a 256-way decode on IR<15:8> + + 15 14 13 12 11 10 09 08 instruction + + x <-!= 0-> x x x x memory reference + 0 0 0 0 x 0 x x shift + 0 0 0 0 x 0 x x alter-skip + 1 0 0 0 x 1 x x IO + 1 0 0 0 0 0 x 0 extended arithmetic + 1 0 0 0 0 0 0 1 divide (decoded as 100400) + 1 0 0 0 1 0 0 0 double load (decoded as 104000) + 1 0 0 0 1 0 0 1 double store (decoded as 104400) + 1 0 0 0 1 0 1 0 extended instr group 0 (A/B must be set) + 1 0 0 0 x 0 1 1 extended instr group 1 (A/B ignored) */ + + absel = (IR & I_AB) ? 1 : 0; /* get A/B select */ + + switch ((IR >> 8) & 0377) { /* decode IR<15:8> */ + +/* Memory reference instructions */ + + case 0020:case 0021:case 0022:case 0023: + case 0024:case 0025:case 0026:case 0027: + case 0220:case 0221:case 0222:case 0223: + case 0224:case 0225:case 0226:case 0227: + reason = Ea (IR, &MA, intrq); /* AND */ + + if (reason != SCPE_OK) /* address failed to resolve? */ + break; /* stop execution */ + + AR = AR & ReadW (MA); + break; + +/* JSB is a little tricky. It is possible to generate both an MP and a DM + violation simultaneously, as the MP and MEM cards validate in parallel. + Consider a JSB to a location under the MP fence and on a write-protected + page. This situation must be reported as a DM violation, because it has + priority (SFS 5 and SFC 5 check only the MEVFF, which sets independently of + the MP fence violation). Under simulation, this means that DM violations + must be checked, and the MEVFF must be set, before an MP abort is taken. + This is done by the "mp_dms_jmp" routine. +*/ + + case 0230:case 0231:case 0232:case 0233: + case 0234:case 0235:case 0236:case 0237: + ion_defer = TRUE; /* defer if JSB,I */ + + case 0030:case 0031:case 0032:case 0033: + case 0034:case 0035:case 0036:case 0037: + reason = Ea (IR, &MA, intrq); /* JSB */ + + if (reason != SCPE_OK) /* address failed to resolve? */ + break; /* stop execution */ + + mp_dms_jmp (MA, jsb_plb); /* validate jump address */ + + WriteW (MA, PC); /* store PC */ + PCQ_ENTRY; + PC = (MA + 1) & VAMASK; /* jump */ + break; + + case 0040:case 0041:case 0042:case 0043: + case 0044:case 0045:case 0046:case 0047: + case 0240:case 0241:case 0242:case 0243: + case 0244:case 0245:case 0246:case 0247: + reason = Ea (IR, &MA, intrq); /* XOR */ + + if (reason != SCPE_OK) /* address failed to resolve? */ + break; /* stop execution */ + + AR = AR ^ ReadW (MA); + break; + +/* CPU idle processing. + + The 21xx/1000 CPUs have no "wait for interrupt" instruction. Idling in HP + operating systems consists of sitting in "idle loops" that end with JMP + instructions. We test for certain known patterns when a JMP instruction is + executed to decide if the simulator should idle. + + Idling must not occur if an interrupt is pending. As mentioned in the + "General Notes" above, HP CPUs will defer interrupts if certain instructions + are executed. OS interrupt handlers exit via such deferring instructions. + If there is a pending interrupt when the OS is otherwise idle, the idle loop + will execute one instruction before reentering the interrupt handler. If we + call sim_idle() in this case, we will lose interrupts. + + Consider the situation in RTE. Under simulation, the TTY and CLK events are + co-scheduled, with the CLK expiring one instruction after the TTY. When the + TTY interrupts, $CIC in RTE is entered. One instruction later, the CLK + expires and posts its interrupt, but it is not immediately handled, because + the JSB $CIC,I / JMP $CIC0,I / SFS 0,C instruction entry sequence continually + defers interrupts until the interrupt system is turned off. When $CIC + returns via $IRT, one instruction of the idle loop is executed, even though + the CLK interrupt is still pending, because the UJP instruction used to + return also defers interrupts. + + If sim_idle() is called at this point, the simulator will sleep when it + should be handling the pending CLK interrupt. When it awakes, TTY expiration + will be moved forward to the next instruction. The still-pending CLK + interrupt will then be recognized, and $CIC will be entered. But the TTY and + then the CLK will then expire and attempt to interrupt again, although they + are deferred by the $CIC entry sequence. This causes the second CLK + interrupt to be missed, as processing of the first one is just now being + started. + + Similarly, at the end of the CLK handling, the TTY interrupt is still + pending. When $IRT returns to the idle loop, sim_idle() would be called + again, so the TTY and then CLK interrupt a third time. Because the second + TTY interrupt is still pending, $CIC is entered, but the third TTY interrupt + is lost. + + We solve this problem by testing for a pending interrupt before calling + sim_idle(). The system isn't really quiescent if it is just about to handle + an interrupt. +*/ + + case 0250:case 0251:case 0252:case 0253: + case 0254:case 0255:case 0256:case 0257: + ion_defer = TRUE; /* defer if JMP,I */ + + case 0050:case 0051:case 0052:case 0053: + case 0054:case 0055:case 0056:case 0057: + reason = Ea (IR, &MA, intrq); /* JMP */ + + if (reason != SCPE_OK) /* address failed to resolve? */ + break; /* stop execution */ + + mp_dms_jmp (MA, 0); /* validate jump addr */ + PCQ_ENTRY; + PC = MA; /* jump */ + +/* Idle conditions by operating system: + + RTE-6/VM: + - ISZ / JMP *-1 + - mp_fence = 0 + - XEQT (address 1717B) = 0 + - DMS on with system map enabled + - RTE verification: TBG (address 1674B) = CLK select code + + RTE though RTE-IVB: + - JMP * + - mp_fence = 0 + - XEQT (address 1717B) = 0 + - DMS on with user map enabled (RTE-III through RTE-IVB only) + - RTE verification: TBG (address 1674B) = CLK select code + + DOS through DOS-III: + - STF 0 / CCA / CCB / JMP *-3 + - DOS verification: A = B = -1, address 40B = -64, address 67B = +64 + - Note that in DOS, the TBG is set to 100 milliseconds +*/ + + if ((sim_idle_enab) && (intrq == 0)) /* idle enabled w/o pending irq? */ + if (((PC == err_PC) || /* RTE through RTE-IVB */ + ((PC == (err_PC - 1)) && /* RTE-6/VM */ + ((ReadW (PC) & I_MRG) == I_ISZ))) && /* RTE jump target */ + (mp_fence == CLEAR) && (M [xeqt] == 0) && /* RTE idle indications */ + (M [tbg] == clk_dib.select_code) || /* RTE verification */ + + (PC == (err_PC - 3)) && /* DOS through DOS-III */ + (ReadW (PC) == I_STF) && /* DOS jump target */ + (AR == 0177777) && (BR == 0177777) && /* DOS idle indication */ + (M [m64] == 0177700) && /* DOS verification */ + (M [p64] == 0000100)) /* DOS verification */ + + sim_idle (TMR_POLL, FALSE); /* idle the simulator */ + break; + + case 0060:case 0061:case 0062:case 0063: + case 0064:case 0065:case 0066:case 0067: + case 0260:case 0261:case 0262:case 0263: + case 0264:case 0265:case 0266:case 0267: + reason = Ea (IR, &MA, intrq); /* IOR */ + + if (reason != SCPE_OK) /* address failed to resolve? */ + break; /* stop execution */ + + AR = AR | ReadW (MA); + break; + + case 0070:case 0071:case 0072:case 0073: + case 0074:case 0075:case 0076:case 0077: + case 0270:case 0271:case 0272:case 0273: + case 0274:case 0275:case 0276:case 0277: + reason = Ea (IR, &MA, intrq); /* ISZ */ + + if (reason != SCPE_OK) /* address failed to resolve? */ + break; /* stop execution */ + + t = (ReadW (MA) + 1) & DMASK; + WriteW (MA, t); + + if (t == 0) + PC = (PC + 1) & VAMASK; + break; + + case 0100:case 0101:case 0102:case 0103: + case 0104:case 0105:case 0106:case 0107: + case 0300:case 0301:case 0302:case 0303: + case 0304:case 0305:case 0306:case 0307: + reason = Ea (IR, &MA, intrq); /* ADA */ + + if (reason != SCPE_OK) /* address failed to resolve? */ + break; /* stop execution */ + + v1 = ReadW (MA); + t = AR + v1; + + if (t > DMASK) + E = 1; + + if (((~AR ^ v1) & (AR ^ t)) & SIGN) + O = 1; + + AR = t & DMASK; + break; + + case 0110:case 0111:case 0112:case 0113: + case 0114:case 0115:case 0116:case 0117: + case 0310:case 0311:case 0312:case 0313: + case 0314:case 0315:case 0316:case 0317: + reason = Ea (IR, &MA, intrq); /* ADB */ + + if (reason != SCPE_OK) /* address failed to resolve? */ + break; /* stop execution */ + + v1 = ReadW (MA); + t = BR + v1; + + if (t > DMASK) + E = 1; + + if (((~BR ^ v1) & (BR ^ t)) & SIGN) + O = 1; + + BR = t & DMASK; + break; + + case 0120:case 0121:case 0122:case 0123: + case 0124:case 0125:case 0126:case 0127: + case 0320:case 0321:case 0322:case 0323: + case 0324:case 0325:case 0326:case 0327: + reason = Ea (IR, &MA, intrq); /* CPA */ + + if (reason != SCPE_OK) /* address failed to resolve? */ + break; /* stop execution */ + + if (AR != ReadW (MA)) + PC = (PC + 1) & VAMASK; + break; + + case 0130:case 0131:case 0132:case 0133: + case 0134:case 0135:case 0136:case 0137: + case 0330:case 0331:case 0332:case 0333: + case 0334:case 0335:case 0336:case 0337: + reason = Ea (IR, &MA, intrq); /* CPB */ + + if (reason != SCPE_OK) /* address failed to resolve? */ + break; /* stop execution */ + + if (BR != ReadW (MA)) + PC = (PC + 1) & VAMASK; + break; + + case 0140:case 0141:case 0142:case 0143: + case 0144:case 0145:case 0146:case 0147: + case 0340:case 0341:case 0342:case 0343: + case 0344:case 0345:case 0346:case 0347: + reason = Ea (IR, &MA, intrq); /* LDA */ + + if (reason != SCPE_OK) /* address failed to resolve? */ + break; /* stop execution */ + + AR = ReadW (MA); + break; + + case 0150:case 0151:case 0152:case 0153: + case 0154:case 0155:case 0156:case 0157: + case 0350:case 0351:case 0352:case 0353: + case 0354:case 0355:case 0356:case 0357: + reason = Ea (IR, &MA, intrq); /* LDB */ + + if (reason != SCPE_OK) /* address failed to resolve? */ + break; /* stop execution */ + + BR = ReadW (MA); + break; + + case 0160:case 0161:case 0162:case 0163: + case 0164:case 0165:case 0166:case 0167: + case 0360:case 0361:case 0362:case 0363: + case 0364:case 0365:case 0366:case 0367: + reason = Ea (IR, &MA, intrq); /* STA */ + + if (reason != SCPE_OK) /* address failed to resolve? */ + break; /* stop execution */ + + WriteW (MA, AR); + break; + + case 0170:case 0171:case 0172:case 0173: + case 0174:case 0175:case 0176:case 0177: + case 0370:case 0371:case 0372:case 0373: + case 0374:case 0375:case 0376:case 0377: + reason = Ea (IR, &MA, intrq); /* STB */ + + if (reason != SCPE_OK) /* address failed to resolve? */ + break; /* stop execution */ + + WriteW (MA, BR); + break; + +/* Alter/skip instructions */ + + case 0004:case 0005:case 0006:case 0007: + case 0014:case 0015:case 0016:case 0017: + skip = 0; /* no skip */ + + if (IR & 000400) /* CLx */ + t = 0; + else + t = ABREG[absel]; + + if (IR & 001000) /* CMx */ + t = t ^ DMASK; + + if (IR & 000001) { /* RSS? */ + if ((IR & 000040) && (E != 0)) /* SEZ,RSS */ + skip = 1; + + if (IR & 000100) /* CLE */ + E = 0; + + if (IR & 000200) /* CME */ + E = E ^ 1; + + if (((IR & 000030) == 000030) && /* SSx,SLx,RSS */ + ((t & 0100001) == 0100001)) + skip = 1; + + if (((IR & 000030) == 000020) && /* SSx,RSS */ + ((t & SIGN) != 0)) + skip = 1; + + if (((IR & 000030) == 000010) && /* SLx,RSS */ + ((t & 1) != 0)) + skip = 1; + + if (IR & 000004) { /* INx */ + t = (t + 1) & DMASK; + + if (t == 0) + E = 1; + + if (t == SIGN) + O = 1; + } + + if ((IR & 000002) && (t != 0)) /* SZx,RSS */ + skip = 1; + + if ((IR & 000072) == 0) /* RSS */ + skip = 1; + } /* end if RSS */ + + else { + if ((IR & 000040) && (E == 0)) /* SEZ */ + skip = 1; + + if (IR & 000100) /* CLE */ + E = 0; + + if (IR & 000200) /* CME */ + E = E ^ 1; + + if ((IR & 000020) && /* SSx */ + ((t & SIGN) == 0)) + skip = 1; + + if ((IR & 000010) && /* SLx */ + ((t & 1) == 0)) + skip = 1; + + if (IR & 000004) { /* INx */ + t = (t + 1) & DMASK; + + if (t == 0) + E = 1; + + if (t == SIGN) + O = 1; + } + if ((IR & 000002) && (t == 0)) /* SZx */ + skip = 1; + } /* end if ~RSS */ + + ABREG[absel] = (uint16) t; /* store result */ + PC = (PC + skip) & VAMASK; /* add in skip */ + break; /* end if alter/skip */ + +/* Shift instructions */ + + case 0000:case 0001:case 0002:case 0003: + case 0010:case 0011:case 0012:case 0013: + t = shift (ABREG[absel], IR & 01000, IR >> 6); /* do first shift */ + + if (IR & 000040) /* CLE */ + E = 0; + + if ((IR & 000010) && ((t & 1) == 0)) /* SLx */ + PC = (PC + 1) & VAMASK; + + ABREG[absel] = (uint16) shift (t, IR & 00020, IR); /* do second shift */ + break; /* end if shift */ + +/* I/O instructions */ + + case 0204:case 0205:case 0206:case 0207: + case 0214:case 0215:case 0216:case 0217: + reason = iogrp (IR, iotrap); /* execute instr */ + break; /* end if I/O */ + +/* Extended arithmetic */ + + case 0200: /* EAU group 0 */ + case 0201: /* divide */ + case 0202: /* EAU group 2 */ + case 0210: /* DLD */ + case 0211: /* DST */ + reason = cpu_eau (IR, intrq); /* extended arith */ + break; + +/* Extended instructions */ + + case 0212: /* UIG 0 extension */ + reason = cpu_uig_0 (IR, intrq, iotrap); /* extended opcode */ + break; + + case 0203: /* UIG 1 extension */ + case 0213: + reason = cpu_uig_1 (IR, intrq, iotrap); /* extended opcode */ + break; + } /* end case IR */ + + if (reason == NOTE_IOG) { /* I/O instr exec? */ + dmarq = calc_dma (); /* recalc DMA masks */ + intrq = calc_int (); /* recalc interrupts */ + reason = SCPE_OK; /* continue */ + } + + else if (reason == NOTE_INDINT) { /* intr pend during indir? */ + PC = err_PC; /* back out of inst */ + reason = SCPE_OK; /* continue */ + } + } /* end while */ + +/* Simulation halted */ + +if (iotrap && (reason == STOP_HALT)) /* HLT in trap cell? */ + MR = intaddr; /* M = interrupt address */ +else /* normal HLT */ + MR = (PC - 1) & VAMASK; /* M = P - 1 */ + +TR = ReadTAB (MR); /* T = last word fetched */ +saved_MR = MR; /* save for T cmd update */ + +if (reason == STOP_HALT) /* programmed halt? */ + cpu_set_ldr (NULL, FALSE, NULL, NULL); /* disable loader (after T is read) */ +else /* simulation stop */ + PC = err_PC; /* back out instruction */ + +dms_upd_sr (); /* update dms_sr */ +dms_upd_vr (MR); /* update dms_vr */ +pcq_r->qptr = pcq_p; /* update pc q ptr */ + +if (dms_enb) /* DMS enabled? */ + if (dms_ump) /* set default */ + sim_brk_dflt = SWMASK ('U'); /* breakpoint type */ + else /* to current */ + sim_brk_dflt = SWMASK ('S'); /* map mode */ + +else /* DMS disabled */ + sim_brk_dflt = SWMASK ('N'); /* set breakpoint type to non-DMS */ + +return reason; /* return status code */ +} + + +/* Resolve indirect addresses. + + An indirect chain is followed until a direct address is obtained. Under + simulation, a maximum number of indirect levels are allowed (typically 16), + after which the instruction will be aborted. + + If the memory protect feature is present, an indirect counter is used that + allows a pending interrupt to be serviced if more than three levels of + indirection are encountered. If MP jumper W6 ("INT") is out and MP is + enabled, then pending interrupts are serviced immediately. When employing + the indirect counter, the hardware clears a pending interrupt deferral after + the third indirection and aborts the instruction after the fourth. +*/ + +t_stat resolve (uint32 MA, uint32 *addr, uint32 irq) +{ +uint32 i; +t_bool pending = (irq && !(mp_unit.flags & DEV_DIS)); +t_bool int_enable = ((mp_unit.flags & UNIT_MP_INT) && mp_control); + +for (i = 0; (i < ind_max) && (MA & I_IA); i++) { /* resolve multilevel */ + if (pending) { /* interrupt pending and MP enabled? */ + if ((i == 2) || int_enable) /* 3rd level indirect or INT out? */ + ion_defer = FALSE; /* reenable interrrupts */ + if ((i > 2) || int_enable) /* 4th or higher or INT out? */ + return NOTE_INDINT; /* break out now */ + } + + MA = ReadW (MA & VAMASK); /* follow address chain */ + } + +if (MA & I_IA) /* indirect loop? */ + return STOP_IND; /* stop simulation */ + +*addr = MA; +return SCPE_OK; +} + + +/* Get effective address from IR */ + +static t_stat Ea (uint32 IR, uint32 *addr, uint32 irq) +{ +uint32 MA; + +MA = IR & (I_IA | I_DISP); /* ind + disp */ + +if (IR & I_CP) /* current page? */ + MA = ((PC - 1) & I_PAGENO) | MA; /* merge in page from PC */ + +return resolve (MA, addr, irq); /* resolve indirects */ +} + + +/* Shift micro operation */ + +static uint32 shift (uint32 t, uint32 flag, uint32 op) +{ +uint32 oldE; + +op = op & 07; /* get shift op */ +if (flag) { /* enabled? */ + switch (op) { /* case on operation */ + + case 00: /* signed left shift */ + return ((t & SIGN) | ((t << 1) & 077777)); + + case 01: /* signed right shift */ + return ((t & SIGN) | (t >> 1)); + + case 02: /* rotate left */ + return (((t << 1) | (t >> 15)) & DMASK); + + case 03: /* rotate right */ + return (((t >> 1) | (t << 15)) & DMASK); + + case 04: /* left shift, 0 sign */ + return ((t << 1) & 077777); + + case 05: /* ext right rotate */ + oldE = E; + E = t & 1; + return ((t >> 1) | (oldE << 15)); + + case 06: /* ext left rotate */ + oldE = E; + E = (t >> 15) & 1; + return (((t << 1) | oldE) & DMASK); + + case 07: /* rotate left four */ + return (((t << 4) | (t >> 12)) & DMASK); + } /* end case */ + } /* end if */ + +if (op == 05) /* disabled ext rgt rot */ + E = t & 1; + +if (op == 06) /* disabled ext lft rot */ + E = (t >> 15) & 1; + +return t; /* input unchanged */ +} + + +/* I/O instruction decode. + + If memory protect is enabled, and the instruction is not in a trap cell, then + HLT instructions are illegal and will cause a memory protect violation. If + jumper W7 (SEL1) is in, then all other I/O instructions are legal; if W7 is + out, then only I/O instructions to select code 1 are legal, and I/O to other + select codes will cause a violation. + + If the instruction is allowed, then the I/O signal corresponding to the + instruction is determined, the state of the interrupt deferral flag is set. + Then the signal is dispatched to the device simulator indicated by the target + select code. The return value is split into status and data values, with the + latter containing the SKF signal state or data to be returned in the A or B + registers. + + Implementation notes: + + 1. If the H/C (hold/clear flag) bit is set, then the ioCLF signal is added + (not ORed) to the base signal derived from the I/O instruction. + + 2. ioNONE is dispatched for HLT instructions because although HLT does not + assert any backplane signals, the H/C bit may be set. If it is, then the + result will be to dispatch ioCLF. + + 3. Device simulators return either ioSKF or ioNONE in response to an SFC or + SFS signal. ioSKF means that the instruction should skip. Because + device simulators return the "data" parameter value by default, we + initialize that parameter to ioNONE to ensure that a simulator that does + not implement SFC or SFS does not skip, which is the correct action for + an interface that does not drive the SKF signal. + + 4. STF/CLF and STC/CLC share sub-opcode values and must be further decoded + by the state of instruction register bits 9 and 11, respectively. + + 5. We return NOTE_IOG for normal status instead of SCPE_OK to request that + interrupts be recalculated at the end of the instruction (execution of + the I/O group instructions can change the interrupt priority chain). +*/ + +t_stat iogrp (uint32 ir, uint32 iotrap) +{ + +/* Translation for I/O subopcodes: soHLT, soFLG, soSFC, soSFS, soMIX, soLIX, soOTX, soCTL */ +static const IOSIGNAL generate_signal [] = { ioNONE, ioSTF, ioSFC, ioSFS, ioIOI, ioIOI, ioIOO, ioSTC }; + +const uint32 dev = ir & I_DEVMASK; /* device select code */ +const uint32 sop = I_GETIOOP (ir); /* I/O subopcode */ +const uint32 ab = (ir & I_AB) != 0; /* A/B register select */ +const t_bool clf = (ir & I_HC) != 0; /* H/C flag select */ +uint16 iodata = (uint16) ioNONE; /* initialize for SKF test */ +uint32 ioreturn; +t_stat iostat; +IOCYCLE signal_set; + +if (!iotrap && mp_control && /* instr not in trap cell and MP on? */ + ((sop == soHLT) || /* and is HLT? */ + ((dev != OVF) && (mp_unit.flags & UNIT_MP_SEL1)))) { /* or is not SC 01 and SEL1 out? */ + if (sop == soLIX) /* MP violation; is LIA/B instruction? */ + ABREG [ab] = 0; /* A/B writes anyway */ + + MP_ABORT (err_PC); /* MP abort */ + } + +signal_set = generate_signal [sop]; /* generate I/O signal from instruction */ +ion_defer = defer_tab [sop]; /* defer depending on instruction */ + +if (sop == soOTX) /* OTA/B instruction? */ + iodata = ABREG [ab]; /* pass A/B register value */ + +else if ((sop == soCTL) && (ir & I_CTL)) /* CLC instruction? */ + signal_set = ioCLC; /* change STC to CLC signal */ + +if ((sop == soFLG) && clf) /* CLF instruction? */ + signal_set = ioCLF; /* change STF to CLF signal */ + +else if (clf) /* CLF with another instruction? */ + signal_set = signal_set | ioCLF; /* add CLF signal */ + +ioreturn = devdisp (dev, signal_set, iodata); /* dispatch I/O signal */ + +iostat = IOSTATUS (ioreturn); /* extract status */ +iodata = IODATA (ioreturn); /* extract return data value */ + +if (((sop == soSFC) || (sop == soSFS)) && /* testing flag state? */ + ((IOSIGNAL) iodata == ioSKF)) /* and SKF asserted? */ + PC = (PC + 1) & VAMASK; /* bump P to skip next instruction */ + +else if (sop == soLIX) /* LIA/B instruction? */ + ABREG [ab] = iodata; /* load returned data */ + +else if (sop == soMIX) /* MIA/B instruction? */ + ABREG [ab] = ABREG [ab] | iodata; /* merge returned data */ + +else if (sop == soHLT) { /* HLT instruction? */ + return STOP_HALT; /* return halt status */ + } + +if (iostat == SCPE_OK) /* normal status? */ + return NOTE_IOG; /* request interrupt recalc */ +else /* abnormal status */ + return iostat; /* return it */ +} + + +/* Device I/O signal dispatcher */ + +static uint32 devdisp (uint32 select_code, IOCYCLE signal_set, uint16 data) +{ +return dtab [select_code]->io_handler (dtab [select_code], + signal_set, + IORETURN (SCPE_OK, data)); +} + + +/* Calculate DMA requests */ + +static uint32 calc_dma (void) +{ +uint32 r = 0; + +if (dma [ch1].xferen && SRQ (dma [ch1].cw1 & I_DEVMASK)) /* check DMA1 cycle */ + r = r | DMA_1_REQ; +if (dma [ch2].xferen && SRQ (dma [ch2].cw1 & I_DEVMASK)) /* check DMA2 cycle */ + r = r | DMA_2_REQ; +return r; +} + + +/* Determine whether a pending interrupt deferral should be inhibited. + + Execution of certain instructions generally cause a pending interrupt to be + deferred until the succeeding instruction completes. However, the interrupt + deferral rules differ on the 21xx vs. the 1000. + + The 1000 always defers until the completion of the instruction following a + deferring instruction. The 21xx defers unless the following instruction is + an MRG instruction other than JMP or JMP,I or JSB,I. If it is, then the + deferral is inhibited, i.e., the pending interrupt will be serviced. + + See the "Set Phase Logic Flowchart," transition from phase 1A to phase 1B, + and the "Theory of Operation," "Control Section Detailed Theory," "Phase + Control Logic," "Phase 1B" paragraph in the Model 2100A Computer Installation + and Maintenance Manual for details. +*/ + +t_bool calc_defer (void) +{ +uint16 IR; + +if (UNIT_CPU_FAMILY == UNIT_FAMILY_21XX) { /* 21xx series? */ + IR = ReadW (PC); /* prefetch next instr */ + + if (((IR & I_MRG & ~I_AB) != 0000000) && /* is MRG instruction? */ + ((IR & I_MRG_I) != I_JSB_I) && /* but not JSB,I? */ + ((IR & I_MRG) != I_JMP)) /* and not JMP or JMP,I? */ + return FALSE; /* yes, so inhibit deferral */ + else + return TRUE; /* no, so allow deferral */ + } +else + return TRUE; /* 1000 always allows deferral */ +} + + +/* Calculate interrupt requests. + + The interrupt request (IRQ) of the highest-priority device for which all + higher-priority PRL bits are set is granted. That is, there must be an + unbroken chain of priority to a device requesting an interrupt for that + request to be granted. + + A device sets its IRQ bit to request an interrupt, and it clears its PRL bit + to prevent lower-priority devices from interrupting. IRQ is cleared by an + interrupt acknowledge (IAK) signal. PRL generally remains low while a + device's interrupt service routine is executing to prevent preemption. + + IRQ and PRL indicate one of four possible states for a device: + + IRQ PRL Device state + --- --- ---------------------- + 0 1 Not interrupting + 1 0 Interrupt requested + 0 0 Interrupt acknowledged + 1 1 (not allowed) + + Note that PRL must be dropped when requesting an interrupt (IRQ set). This + is a hardware requirement of the 1000 series. The IRQ lines from the + backplane are not priority encoded. Instead, the PRL chain expresses the + priority by allowing only one IRQ line to be active at a time. This allows a + simple pull-down encoding of the CIR inputs. + + The end of priority chain is marked by the highest-priority (lowest-order) + bit that is clear. The device corresponding to that bit is the only device + that may interrupt (a higher priority device that had IRQ set would also have + had PRL set, which is a state violation). We calculate a priority mask by + ANDing the complement of the PRL bits with an increment of the PRL bits. + Only the lowest-order bit will differ. For example: + + dev_prl : ...1 1 0 1 1 0 1 1 1 1 1 1 (PRL denied for SC 06 and 11) + + dev_prl + 1 : ...1 1 0 1 1 1 0 0 0 0 0 0 + ~dev_prl : ...0 0 1 0 0 1 0 0 0 0 0 0 + ANDed value : ...0 0 0 0 0 1 0 0 0 0 0 0 (break is at SC 06) + + The interrupt requests are then ANDed with the priority mask to determine if + a request is pending: + + pri mask : ...0 0 0 0 0 1 0 0 0 0 0 0 (allowed interrupt source) + dev_irq : ...0 0 1 0 0 1 0 0 0 0 0 0 (devices requesting interrupts) + ANDed value : ...0 0 0 0 0 1 0 0 0 0 0 0 (request to grant) + + The select code corresponding to the granted request is then returned to the + caller. + + If ION is clear, only power fail (SC 04) and parity error (SC 05) are + eligible to interrupt (memory protect shares SC 05, but qualification occurs + in the MP abort handler, so if SC 05 is interrupting when ION is clear, it + must be a parity error interrupt). +*/ + +uint32 calc_int (void) +{ +uint32 sc, pri_mask [2], req_grant [2]; + +pri_mask [0] = ~dev_prl [0] & (dev_prl [0] + 1); /* calculate lower priority mask */ +req_grant [0] = pri_mask [0] & dev_irq [0]; /* calculate lower request to grant */ + +if (ion) /* interrupt system on? */ + if ((req_grant [0] == 0) && (pri_mask [0] == 0)) { /* no requests in lower set and PRL unbroken? */ + pri_mask [1] = ~dev_prl [1] & (dev_prl [1] + 1); /* calculate upper priority mask */ + req_grant [1] = pri_mask [1] & dev_irq [1]; /* calculate upper request to grant */ + } + else /* lower set has request */ + req_grant [1] = 0; /* no grants to upper set */ + +else { /* interrupt system off */ + req_grant [0] = req_grant [0] & /* only PF and PE can interrupt */ + (BIT_M (PWR) | BIT_M (PRO)); + req_grant [1] = 0; + } + +if (req_grant [0]) /* device in lower half? */ + for (sc = 0; sc <= 31; sc++) /* determine interrupting select code */ + if (req_grant [0] & 1) /* grant this request? */ + return sc; /* return this select code */ + else /* not this one */ + req_grant [0] = req_grant [0] >> 1; /* position next request */ + +else if (req_grant [1]) /* device in upper half */ + for (sc = 32; sc <= 63; sc++) /* determine interrupting select code */ + if (req_grant [1] & 1) /* grant this request? */ + return sc; /* return this select code */ + else /* not this one */ + req_grant [1] = req_grant [1] >> 1; /* position next request */ + +return 0; /* no interrupt granted */ +} + + +/* Memory access routines. + + These routines access memory for reads and writes. They validate the + accesses for MP and MEM violations, if enabled. The following routines are + provided: + + - ReadPW : Read a word using a physical address + - ReadB : Read a byte using the current map + - ReadBA : Read a byte using the alternate map + - ReadW : Read a word using the current map + - ReadWA : Read a word using the alternate map + - ReadIO : Read a word using the specified map without protection + - ReadTAB : Read a word using the current map without protection + + - WritePW : Write a word using a physical address + - WriteB : Write a byte using the current map + - WriteBA : Write a byte using the alternate map + - WriteW : Write a word using the current map + - WriteWA : Write a word using the alternate map + - WriteIO : Write a word using the specified map without protection + + The memory protect (MP) and memory expansion module (MEM) accessories provide + a protected mode that guards against improper accesses by user programs. + They may be enabled or disabled independently, although protection requires + that both be enabled. MP checks that memory writes do not fall below the + Memory Protect Fence Register (MPFR) value, and MEM checks that read/write + protection rules on the target page are compatible with the access desired. + If either check fails, and MP is enabled, then the request is aborted. + + Each mapped routine calls "dms" if DMS is enabled to translate the logical + address supplied to a physical address. "dms" performs a protection check + and aborts without returning if the check fails. The write routines perform + an additional memory-protect check and abort if a violation occurs (so, to + pass, a page must be writable AND the target must be above the MP fence). + + Note that MP uses a lower bound of 2 for memory writes, allowing unrestricted + access to the A and B registers (addressed as locations 0 and 1). +*/ + +#define MP_TEST(va) (mp_control && ((va) >= 2) && ((va) < mp_fence)) + + +/* Read a word using a physical address */ + +uint16 ReadPW (uint32 pa) +{ +if (pa <= 1) /* read locations 0 or 1? */ + return ABREG[pa]; /* return A/B register */ +else /* location >= 2 */ + return M[pa]; /* return physical memory value */ +} + + +/* Read a byte using the current map */ + +uint8 ReadB (uint32 va) +{ +int32 pa; + +if (dms_enb) /* MEM enabled? */ + pa = dms (va >> 1, dms_ump, RDPROT); /* translate address */ +else /* MEM disabled */ + pa = va >> 1; /* use logical as physical address */ + +if (va & 1) /* low byte addressed? */ + return (ReadPW (pa) & 0377); /* mask to lower byte */ +else /* high byte addressed */ + return ((ReadPW (pa) >> 8) & 0377); /* position higher byte and mask */ +} + + +/* Read a byte using the alternate map */ + +uint8 ReadBA (uint32 va) +{ +uint32 pa; + +if (dms_enb) /* MEM enabled? */ + pa = dms (va >> 1, dms_ump ^ MAP_LNT, RDPROT); /* translate address using alternate map */ +else /* MEM disabled */ + pa = va >> 1; /* use logical as physical address */ + +if (va & 1) /* low byte addressed? */ + return (ReadPW (pa) & 0377); /* mask to lower byte */ +else /* high byte addressed */ + return ((ReadPW (pa) >> 8) & 0377); /* position higher byte and mask */ +} + + +/* Read a word using the current map */ + +uint16 ReadW (uint32 va) +{ +uint32 pa; + +if (dms_enb) /* MEM enabled? */ + pa = dms (va, dms_ump, RDPROT); /* translate address */ +else /* MEM disabled */ + pa = va; /* use logical as physical address */ + +return ReadPW (pa); /* return word */ +} + + +/* Read a word using the alternate map */ + +uint16 ReadWA (uint32 va) +{ +uint32 pa; + +if (dms_enb) /* MEM enabled? */ + pa = dms (va, dms_ump ^ MAP_LNT, RDPROT); /* translate address using alternate map */ +else /* MEM disabled */ + pa = va; /* use logical as physical address */ + +return ReadPW (pa); /* return word */ +} + + +/* Read a word using the specified map without protection */ + +uint16 ReadIO (uint32 va, uint32 map) +{ +uint32 pa; + +if (dms_enb) /* MEM enabled? */ + pa = dms (va, map, NOPROT); /* translate address with no protection */ +else /* MEM disabled */ + pa = va; /* use logical as physical address */ + +return M[pa]; /* return word without A/B interception */ +} + + +/* Read a word using the current map without protection */ + +static uint16 ReadTAB (uint32 va) +{ +uint32 pa; + +if (dms_enb) /* MEM enabled? */ + pa = dms (va, dms_ump, NOPROT); /* translate address with no protection */ +else /* MEM disabled */ + pa = va; /* use logical as physical address */ + +return ReadPW (pa); /* return word */ +} + + +/* Write a word using a physical address */ + +void WritePW (uint32 pa, uint32 dat) +{ +if (pa <= 1) /* write locations 0 or 1? */ + ABREG[pa] = dat & DMASK; /* store A/B register */ +else if (pa < fwanxm) /* 2 <= location <= LWA memory? */ + M[pa] = dat & DMASK; /* store physical memory value */ + +return; +} + + +/* Write a byte using the current map */ + +void WriteB (uint32 va, uint32 dat) +{ +uint32 pa, t; + +if (dms_enb) /* MEM enabled? */ + pa = dms (va >> 1, dms_ump, WRPROT); /* translate address */ +else /* MEM disabled */ + pa = va >> 1; /* use logical as physical address */ + +if (MP_TEST (va >> 1)) /* MPCK? */ + MP_ABORT (va >> 1); /* MP violation */ + +t = ReadPW (pa); /* get word */ + +if (va & 1) /* low byte addressed? */ + t = (t & 0177400) | (dat & 0377); /* merge in lower byte */ +else /* high byte addressed */ + t = (t & 0377) | ((dat & 0377) << 8); /* position higher byte and merge */ + +WritePW (pa, t); /* store word */ +return; +} + + +/* Write a byte using the alternate map */ + +void WriteBA (uint32 va, uint32 dat) +{ +uint32 pa, t; + +if (dms_enb) { /* MEM enabled? */ + dms_viol (va >> 1, MVI_WPR); /* always a violation if protected */ + pa = dms (va >> 1, dms_ump ^ MAP_LNT, WRPROT); /* translate address using alternate map */ + } +else /* MEM disabled */ + pa = va >> 1; /* use logical as physical address */ + +if (MP_TEST (va >> 1)) /* MPCK? */ + MP_ABORT (va >> 1); /* MP violation */ + +t = ReadPW (pa); /* get word */ + +if (va & 1) /* low byte addressed? */ + t = (t & 0177400) | (dat & 0377); /* merge in lower byte */ +else /* high byte addressed */ + t = (t & 0377) | ((dat & 0377) << 8); /* position higher byte and merge */ + +WritePW (pa, t); /* store word */ +return; +} + + +/* Write a word using the current map */ + +void WriteW (uint32 va, uint32 dat) +{ +uint32 pa; + +if (dms_enb) /* MEM enabled? */ + pa = dms (va, dms_ump, WRPROT); /* translate address */ +else /* MEM disabled */ + pa = va; /* use logical as physical address */ + +if (MP_TEST (va)) /* MPCK? */ + MP_ABORT (va); /* MP violation */ + +WritePW (pa, dat); /* store word */ +return; +} + + +/* Write a word using the alternate map */ + +void WriteWA (uint32 va, uint32 dat) +{ +int32 pa; + +if (dms_enb) { /* MEM enabled? */ + dms_viol (va, MVI_WPR); /* always a violation if protected */ + pa = dms (va, dms_ump ^ MAP_LNT, WRPROT); /* translate address using alternate map */ + } +else /* MEM disabled */ + pa = va; /* use logical as physical address */ + +if (MP_TEST (va)) /* MPCK? */ + MP_ABORT (va); /* MP violation */ + +WritePW (pa, dat); /* store word */ +return; +} + + +/* Write a word using the specified map without protection */ + +void WriteIO (uint32 va, uint32 dat, uint32 map) +{ +uint32 pa; + +if (dms_enb) /* MEM enabled? */ + pa = dms (va, map, NOPROT); /* translate address with no protection */ +else /* MEM disabled */ + pa = va; /* use logical as physical address */ + +if (pa < fwanxm) + M[pa] = dat & DMASK; /* store word without A/B interception */ +return; +} + + +/* Mapped access check. + + Returns TRUE if the address will be mapped (presuming MEM is enabled). +*/ + +static t_bool is_mapped (uint32 va) +{ +uint32 dms_fence; + +if (va >= 02000) /* above the base bage? */ + return TRUE; /* always mapped */ +else { + dms_fence = dms_sr & MST_FENCE; /* get BP fence value */ + return (dms_sr & MST_FLT) ? (va < dms_fence) : /* below BP fence and lower portion mapped? */ + (va >= dms_fence); /* or above BP fence and upper portion mapped? */ + } +} + + +/* DMS relocation. + + This routine translates logical into physical addresses. It must be called + only when DMS is enabled, as that condition is not checked. The logical + address, desired map, and desired access type are supplied. If the access is + legal, the mapped physical address is returned; if it is not, then a MEM + violation is indicated. + + The current map may be specified by passing "dms_ump" as the "map" parameter, + or a specific map may be used. Normally, read and write accesses pass RDPROT + or WRPROT as the "prot" parameter to request access checking. For DMA + accesses, NOPROT must be passed to inhibit access checks. + + This routine checks for read, write, and base-page violations and will call + "dms_viol" as appropriate. The latter routine will abort if MP is enabled, + or will return if protection is off. +*/ + +static uint32 dms (uint32 va, uint32 map, uint32 prot) +{ +uint32 pgn, mpr; + +if (va <= 1) /* reference to A/B register? */ + return va; /* use address */ + +if (!is_mapped (va)) { /* unmapped? */ + if ((va >= 2) && (prot == WRPROT)) /* base page write access? */ + dms_viol (va, MVI_BPG); /* signal a base page violation */ + return va; /* use unmapped address */ + } + +pgn = VA_GETPAG (va); /* get page num */ +mpr = dms_map[map + pgn]; /* get map reg */ + +if (mpr & prot) /* desired access disallowed? */ + dms_viol (va, prot); /* signal protection violation */ + +return (MAP_GETPAG (mpr) | VA_GETOFF (va)); /* return mapped address */ +} + + +/* DMS relocation for console access. + + Console access allows the desired map to be specified by switches on the + command line. All protection checks are off for console access. + + This routine is called to restore a saved configuration, and mapping is not + used for restoration. +*/ + +static uint32 dms_cons (t_addr va, int32 sw) +{ +uint32 map_sel; + +if ((dms_enb == 0) || /* DMS off? */ + (sw & (SWMASK ('N') | SIM_SW_REST))) /* no mapping rqst or save/rest? */ + return (uint32) va; /* use physical address */ + +else if (sw & SWMASK ('S')) + map_sel = SMAP; + +else if (sw & SWMASK ('U')) + map_sel = UMAP; + +else if (sw & SWMASK ('P')) + map_sel = PAMAP; + +else if (sw & SWMASK ('Q')) + map_sel = PBMAP; + +else /* dflt to log addr, cur map */ + map_sel = dms_ump; + +if (va >= VASIZE) /* virtual, must be 15b */ + return (uint32) MEMSIZE; + +else if (dms_enb) /* DMS on? go thru map */ + return dms ((uint32) va, map_sel, NOPROT); + +else /* else return virtual */ + return (uint32) va; +} + + +/* Memory protect and DMS validation for jumps. + + Jumps are a special case of write validation. The target address is treated + as a write, even when no physical write takes place, so jumping to a + write-protected page causes a MEM violation. In addition, a MEM violation is + indicated if the jump is to the unmapped portion of the base page. Finally, + jumping to a location under the memory-protect fence causes an MP violation. + + Because the MP and MEM hardware works in parallel, all three violations may + exist concurrently. For example, a JMP to the unmapped portion of the base + page that is write protected and under the MP fence will indicate a + base-page, write, and MP violation, whereas a JMP to the mapped portion will + indicate a write and MP violation (BPV is inhibited by the MEBEN signal). If + MEM and MP violations occur concurrently, the MEM violation takes precedence, + as the SFS and SFC instructions test the MEV flip-flop. + + The lower bound of protected memory is passed in the "plb" argument. This + must be either 0 or 2. All violations are qualified by the MPCND signal, + which responds to the lower bound. Therefore, if the lower bound is 2, and + if the part below the base-page fence is unmapped, or if the base page is + write-protected, then a MEM violation will occur only if the access is not to + locations 0 or 1. The instruction set firmware uses a lower bound of 0 for + JMP, JLY, and JPY (and for JSB with W5 out), and of 2 for DJP, SJP, UJP, JRS, + and .GOTO (and JSB with W5 in). + + Finally, all violations are inhibited if MP is off (mp_control is CLEAR), and + MEM violations are inhibited if the MEM is disabled. +*/ + +void mp_dms_jmp (uint32 va, uint32 plb) +{ +uint32 violation = 0; +uint32 pgn = VA_GETPAG (va); /* get page number */ + +if (mp_control) { /* MP on? */ + if (dms_enb) { /* MEM on? */ + if (dms_map [dms_ump + pgn] & WRPROT) /* page write protected? */ + violation = MVI_WPR; /* write violation occured */ + + if (!is_mapped (va) && (va >= plb)) /* base page target? */ + violation = violation | MVI_BPG; /* base page violation occured */ + + if (violation) /* any violation? */ + dms_viol (va, violation); /* signal MEM violation */ + } + + if ((va >= plb) && (va < mp_fence)) /* jump under fence? */ + MP_ABORT (va); /* signal MP violation */ + } + +return; +} + + +/* DMS read and write map registers */ + +uint16 dms_rmap (uint32 mapi) +{ +mapi = mapi & MAP_MASK; +return (dms_map[mapi] & ~MAP_RSVD); +} + +void dms_wmap (uint32 mapi, uint32 dat) +{ +mapi = mapi & MAP_MASK; +dms_map[mapi] = (uint16) (dat & ~MAP_RSVD); +return; +} + + +/* Process a MEM violation. + + A MEM violation will report the cause in the violation register. This occurs + even if the MEM is not in the protected mode (i.e., MP is not enabled). If + MP is enabled, an MP abort is taken with the MEV flip-flop set. Otherwise, + we return to the caller. +*/ + +void dms_viol (uint32 va, uint32 st) +{ +dms_vr = st | dms_upd_vr (va); /* set violation cause in register */ + +if (mp_control) { /* memory protect on? */ + mp_mevff = SET; /* record memory expansion violation */ + MP_ABORT (va); /* abort */ + } +return; +} + + +/* Update the MEM violation register. + + In hardware, the MEM violation register (VR) is clocked on every memory read, + every memory write above the lower bound of protected memory, and every + execution of a privileged DMS instruction. The register is not clocked when + MP is disabled by an MP or MEM error (i.e., when MEVFF sets or CTL5FF + clears), in order to capture the state of the MEM. In other words, the VR + continually tracks the memory map register accessed plus the MEM state + (MEBEN, MAPON, and USR) until a violation occurs, and then it's "frozen." + + Under simulation, we do not have to update the VR on every memory access, + because the visible state is only available via a programmed RVA/B + instruction or via the SCP interface. Therefore, it is sufficient if the + register is updated: + + - at a MEM violation (when freezing) + - at an MP violation (when freezing) + - during RVA/B execution (if not frozen) + - before returning to SCP after a simulator stop (if not frozen) +*/ + +uint32 dms_upd_vr (uint32 va) +{ +if (mp_control && (mp_mevff == CLEAR)) { /* violation register unfrozen? */ + dms_vr = VA_GETPAG (va) | /* set map address */ + (dms_enb ? MVI_MEM : 0) | /* and MEM enabled */ + (dms_ump ? MVI_UMP : 0); /* and user map enabled */ + + if (is_mapped (va)) /* is addressed mapped? */ + dms_vr = dms_vr | MVI_MEB; /* ME bus is enabled */ + } + +return dms_vr; +} + + +/* Update the MEM status register */ + +uint32 dms_upd_sr (void) +{ +dms_sr = dms_sr & ~(MST_ENB | MST_UMP | MST_PRO); + +if (dms_enb) + dms_sr = dms_sr | MST_ENB; + +if (dms_ump) + dms_sr = dms_sr | MST_UMP; + +if (mp_control) + dms_sr = dms_sr | MST_PRO; + +return dms_sr; +} + + +/* CPU (SC 0) I/O signal handler. + + I/O instructions for select code 0 manipulate the interrupt system. STF and + CLF turn the interrupt system on and off, and SFS and SFC test the state of + the interrupt system. When the interrupt system is off, only power fail and + parity error interrupts are allowed. + + A PON reset initializes certain CPU registers. The 1000 series does a + microcoded memory clear and leaves the T and P registers set as a result. + + Front-panel PRESET performs additional initialization. We also handle MEM + preset here. + + Implementation notes: + + 1. An IOI signal reads the floating I/O bus (0 on all machines). + + 2. A CLC 0 issues CRS to all devices, not CLC. While most cards react + identically to CRS and CLC, some do not, e.g., the 12566B when used as an + I/O diagnostic target. + + 3. RTE uses the undocumented SFS 0,C instruction to both test and turn off + the interrupt system. This is confirmed in the "RTE-6/VM Technical + Specifications" manual (HP 92084-90015), section 2.3.1 "Process the + Interrupt", subsection "A.1 $CIC": + + "Test to see if the interrupt system is on or off. This is done with + the SFS 0,C instruction. In either case, turn it off (the ,C does + it)." + + ...and in section 5.8, "Parity Error Detection": + + "Because parity error interrupts can occur even when the interrupt + system is off, the code at $CIC must be able to save the complete + system status. The major hole in being able to save the complete state + is in saving the interrupt system state. In order to do this in both + the 21MX and the 21XE the instruction 103300 was used to both test the + interrupt system and turn it off." + + 4. Select code 0 cannot interrupt, so there is no SIR handler. +*/ + +uint32 cpuio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) +{ +uint32 sc; +IOSIGNAL signal; +IOCYCLE working_set = signal_set; /* no SIR handler needed */ + +while (working_set) { + signal = IONEXT (working_set); /* isolate next signal */ + + switch (signal) { /* dispatch I/O signal */ + + case ioCLF: /* clear flag flip-flop */ + ion = CLEAR; /* turn interrupt system off */ + break; + + case ioSTF: /* set flag flip-flop */ + ion = SET; /* turn interrupt system on */ + break; + + case ioSFC: /* skip if flag is clear */ + setSKF (!ion); /* skip if interrupt system is off */ + break; + + case ioSFS: /* skip if flag is set */ + setSKF (ion); /* skip if interupt system is on */ + break; + + case ioIOI: /* I/O input */ + stat_data = IORETURN (SCPE_OK, 0); /* returns 0 */ + break; + + case ioPON: /* power on normal */ + AR = 0; /* clear A register */ + BR = 0; /* clear B register */ + SR = 0; /* clear S register */ + TR = 0; /* clear T register */ + E = 1; /* set E register */ + + if (UNIT_CPU_FAMILY == UNIT_FAMILY_1000) { /* 1000 series? */ + memset (M, 0, (uint32) MEMSIZE * 2); /* zero allocated memory */ + MR = 0077777; /* set M register */ + PC = 0100000; /* set P register */ + } + + else { /* 21xx series */ + MR = 0; /* clear M register */ + PC = 0; /* clear P register */ + } + break; + + case ioPOPIO: /* power-on preset to I/O */ + O = 0; /* clear O register */ + ion = CLEAR; /* turn off interrupt system */ + ion_defer = FALSE; /* clear interrupt deferral */ + + dms_enb = 0; /* turn DMS off */ + dms_ump = 0; /* init to system map */ + dms_sr = 0; /* clear status register and BP fence */ + dms_vr = 0; /* clear violation register */ + break; + + case ioCLC: /* clear control flip-flop */ + for (sc = CRSDEV; sc <= MAXDEV; sc++) /* send CRS to devices */ + devdisp (sc, ioCRS, 0); /* from select code 6 and up */ + break; + + default: /* all other signals */ + break; /* are ignored */ + } + + working_set = working_set & ~signal; /* remove current signal from set */ + } + +return stat_data; +} + + +/* Overflow/S-register (SC 1) I/O signal handler. + + Flag instructions directed to select code 1 manipulate the overflow (O) + register. Input and output instructions access the switch (S) register. On + the 2115 and 2116, there is no S-register indicator, so it is effectively + read-only. On the other machines, a front-panel display of the S-register is + provided. On all machines, front-panel switches are provided to set the + contents of the S register. + + Implementation notes: + + 1. Select code 1 cannot interrupt, so there is no SIR handler. +*/ + +uint32 ovflio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) +{ +IOSIGNAL signal; +IOCYCLE working_set = signal_set; /* no SIR handler needed */ + +while (working_set) { + signal = IONEXT (working_set); /* isolate next signal */ + + switch (signal) { /* dispatch I/O signal */ + + case ioCLF: /* clear flag flip-flop */ + O = 0; /* clear overflow */ + break; + + case ioSTF: /* set flag flip-flop */ + O = 1; /* set overflow */ + break; + + case ioSFC: /* skip if flag is clear */ + setSKF (!O); /* skip if overflow is clear */ + break; + + case ioSFS: /* skip if flag is set */ + setSKF (O); /* skip if overflow is set */ + break; + + case ioIOI: /* I/O input */ + stat_data = IORETURN (SCPE_OK, SR); /* read switch register value */ + break; + + case ioIOO: /* I/O output */ + if ((UNIT_CPU_MODEL != UNIT_2116) && /* no S register display on */ + (UNIT_CPU_MODEL != UNIT_2115)) /* 2116 and 2115 machines */ + SR = IODATA (stat_data); /* write S register value */ + break; + + default: /* all other signals */ + break; /* are ignored */ + } + + working_set = working_set & ~signal; /* remove current signal from set */ + } + +return stat_data; +} + + +/* Power fail (SC 4) I/O signal handler. + + Power fail detection is standard on 2100 and 1000 systems and is optional on + 21xx systems. Power fail recovery is standard on the 2100 and optional on + the others. Power failure or restoration will cause an interrupt on select + code 4. The direction of power change (down or up) can be tested by SFC. + + We do not implement power fail under simulation. However, the central + interrupt register (CIR) is always read by an IOI directed to select code 4. +*/ + +uint32 pwrfio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) +{ +IOSIGNAL signal; +IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ + +while (working_set) { + signal = IONEXT (working_set); /* isolate next signal */ + + switch (signal) { /* dispatch I/O signal */ + + case ioSTC: /* set control flip-flop */ + break; /* reinitializes power fail */ + + case ioCLC: /* clear control flip-flop */ + break; /* reinitializes power fail */ + + case ioSFC: /* skip if flag is clear */ + break; /* skips if power fail occurred */ + + case ioIOI: /* I/O input */ + stat_data = IORETURN (SCPE_OK, intaddr); /* input CIR value */ + break; + + default: /* all other signals */ + break; /* are ignored */ + } + + working_set = working_set & ~signal; /* remove current signal from set */ + } + +return stat_data; +} + + +/* Memory protect/parity error (SC 5) I/O signal handler. + + The memory protect card has a number of non-standard features: + + - CLF and STF affect the parity error enable flip-flop, not the flag + - SFC and SFS test the memory expansion violation flip-flop, not the flag + - POPIO clears control, flag, and flag buffer instead of setting the flags + - CLC does not clear control (the only way to turn off MP is to cause a + violation) + - PRL and IRQ are a function of the flag only, not flag and control + - IAK is used unqualified by IRQ + + The IAK backplane signal is asserted when any interrupt is acknowledged by + the CPU. Normally, an interface qualifies IAK with its own IRQ to ensure + that it responds only to an acknowledgement of its own request. The MP card + does this to reset its flag buffer and flag flip-flops, and to reset the + parity error indication. However, it also responds to an unqualified IAK + (i.e., for any interface) as follows: + + - clears the MPV flip-flop + - clears the indirect counter + - clears the control flip-flop + - sets the INTPT flip-flop + + The INTPT flip-flop indicates an occurrence of an interrupt. If the trap + cell of the interrupting device contains an I/O instruction that is not a + HLT, action equivalent to STC 05 is taken, i.e.: + + - sets the control flip-flop + - set the EVR flip-flop + - clears the MEV flip-flop + - clears the PARERR flip-flop + + In other words, an interrupt for any device will disable MP unless the trap + cell contains an I/O instruction other than a HLT. + + Implementation notes: + + 1. Because the card uses IAK unqualified, this routine is called whenever + any interrupt occurs. If the MP card itself is not interrupting, the + select code passed will not be SC 05. In either case, the trap cell + instruction is passed in the data portion of the "stat_data" parameter. + + 2. The MEV flip-flop records memory expansion (a.k.a. dynamic mapping) + violations. It is set when an DM violation is encountered and can be + tested via SFC/SFS. + + 3. MP cannot be turned off in hardware, except by causing a violation. + Microcode typically does this by executing an IOG micro-order with select + code /= 1, followed by an IAK to clear the interrupt and a FTCH to clear + the INTPT flip-flop. Under simulation, mp_control may be set to CLEAR to + produce the same effect. + + 4. Parity error logic is not implemented. +*/ + +uint32 protio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) +{ +uint16 data; +IOSIGNAL signal; +IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ + +while (working_set) { + signal = IONEXT (working_set); /* isolate next signal */ + + switch (signal) { /* dispatch I/O signal */ + + case ioCLF: /* clear flag flip-flop */ + break; /* turns off PE interrupt */ + + case ioSTF: /* set flag flip-flop */ + break; /* turns on PE interrupt */ + + case ioENF: /* enable flag */ + mp_flag = mp_flagbuf = SET; /* set flag buffer and flag flip-flops */ + mp_evrff = CLEAR; /* inhibit violation register updates */ + break; + + case ioSFC: /* skip if flag is clear */ + setSKF (!mp_mevff); /* skip if MP interrupt */ + break; + + case ioSFS: /* skip if flag is set */ + setSKF (mp_mevff); /* skip if DMS interrupt */ + break; + + case ioIOI: /* I/O input */ + stat_data = IORETURN (SCPE_OK, mp_viol); /* read MP violation register */ + break; + + case ioIOO: /* I/O output */ + mp_fence = IODATA (stat_data) & VAMASK; /* write to MP fence register */ + + if (cpu_unit.flags & UNIT_2100) /* 2100 IOP uses MP fence */ + iop_sp = mp_fence; /* as a stack pointer */ + break; + + case ioPOPIO: /* power-on preset to I/O */ + mp_control = CLEAR; /* clear control flip-flop */ + mp_flag = mp_flagbuf = CLEAR; /* clear flag and flag buffer flip-flops */ + mp_mevff = CLEAR; /* clear memory expansion violation flip-flop */ + mp_evrff = SET; /* set enable violation register flip-flop */ + break; + + case ioSTC: /* set control flip-flop */ + mp_control = SET; /* turn on MP */ + mp_mevff = CLEAR; /* clear memory expansion violation flip-flop */ + mp_evrff = SET; /* set enable violation register flip-flop */ + break; + + case ioSIR: /* set interrupt request */ + setPRL (PRO, !mp_flag); /* set PRL signal */ + setIRQ (PRO, mp_flag); /* set IRQ signal */ + break; + + case ioIAK: /* interrupt acknowledge */ + if (dibptr->select_code == PRO) /* MP interrupt acknowledgement? */ + mp_flag = mp_flagbuf = CLEAR; /* clear flag and flag buffer */ + + data = IODATA (stat_data); /* get trap cell instruction */ + + if (((data & I_NMRMASK) != I_IO) || /* trap cell instruction not I/O */ + (I_GETIOOP (data) == soHLT)) /* or is halt? */ + mp_control = CLEAR; /* turn protection off */ + else { /* non-HLT I/O instruction leaves MP on */ + mp_mevff = CLEAR; /* but clears MEV flip-flop */ + mp_evrff = SET; /* and reenables violation register flip-flop */ + } + break; + + default: /* all other signals */ + break; /* are ignored */ + } + + working_set = working_set & ~signal; /* remove current signal from set */ + } + +return stat_data; +} + + +/* DMA/DCPC secondary (SC 2/3) I/O signal handler. + + DMA consists of one (12607B) or two (12578A/12895A/12897B) channels. Each + channel uses two select codes: 2 and 6 for channel 1, and 3 and 7 for channel + 2. The lower select codes are used to configure the memory address register + (control word 2) and the word count register (control word 3). The upper + select codes are used to configure the service select register (control word + 1) and to activate and terminate the transfer. + + There are differences in the implementations of the memory address and word + count registers among the various cards. The 12607B (2114) supports 14-bit + addresses and 13-bit word counts. The 12578A (2115/6) supports 15-bit + addresses and 14-bit word counts. The 12895A (2100) and 12897B (1000) + support 15-bit addresses and 16-bit word counts. + + Implementation notes: + + 1. Because the I/O bus floats to zero on 211x computers, an IOI (read word + count) returns zeros in the unused bit locations, even though the word + count is a negative value. + + 2. Select codes 2 and 3 cannot interrupt, so there is no SIR handler. +*/ + +uint32 dmasio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) +{ +const CHANNEL ch = (CHANNEL) dibptr->card_index; /* DMA channel number */ +uint16 data; +IOSIGNAL signal; +IOCYCLE working_set = signal_set; /* no SIR handler needed */ + +while (working_set) { + signal = IONEXT (working_set); /* isolate next signal */ + + switch (signal) { /* dispatch I/O signal */ + + case ioIOI: /* I/O data input */ + if (UNIT_CPU_MODEL == UNIT_2114) /* 2114? */ + data = dma [ch].cw3 & 0017777; /* only 13-bit count */ + else if (UNIT_CPU_TYPE == UNIT_TYPE_211X) /* 2115/2116? */ + data = dma [ch].cw3 & 0037777; /* only 14-bit count */ + else /* other models */ + data = (uint16) dma [ch].cw3; /* rest use full value */ + + stat_data = IORETURN (SCPE_OK, data); /* merge status and remaining word count */ + break; + + case ioIOO: /* I/O data output */ + if (dma [ch].select) /* word count selected? */ + dma [ch].cw3 = IODATA (stat_data); /* save count */ + else /* memory address selected */ + if (UNIT_CPU_MODEL == UNIT_2114) /* 2114? */ + dma [ch].cw2 = IODATA (stat_data) & 0137777; /* only 14-bit address */ + else /* other models */ + dma [ch].cw2 = IODATA (stat_data); /* full address stored */ + break; + + case ioCLC: /* clear control flip-flop */ + dma [ch].select = CLEAR; /* set for word count access */ + break; + + case ioSTC: /* set control flip-flop */ + dma [ch].select = SET; /* set for memory address access */ + break; + + default: /* all other signals */ + break; /* are ignored */ + } + + working_set = working_set & ~signal; /* remove current signal from set */ + } + +return stat_data; +} + + +/* DMA/DCPC primary (SC 6/7) I/O signal handler. + + The primary DMA control interface and the service select register are + manipulated through select codes 6 and 7. Each channel has transfer enable, + control, flag, and flag buffer flip-flops. Transfer enable must be set via + STC to start DMA. Control is used only to enable the DMA completion + interrupt; it is set by STC and cleared by CLC. Flag and flag buffer are set + at transfer completion to signal an interrupt. STF may be issued to abort a + transfer in progress. + + Again, there are hardware differences between the various DMA cards. The + 12607B (2114) stores only bits 2-0 of the select code and interprets them as + select codes 10-16 (SRQ17 is not decoded). The 12578A (2115/16), 12895A + (2100), and 12897B (1000) support the full range of select codes (10-77 + octal). + + Implementation notes: + + 1. An IOI reads the floating S-bus (high on the 1000, low on the 21xx). + + 2. The CRS signal on the DMA card resets the secondary (SC 2/3) select + flip-flops. Under simulation, ioCRS is dispatched to select codes 6 and + up, so we reset the flip-flop in our handler. + + 3. The 12578A supports byte-sized transfers by setting bit 14. Bit 14 is + ignored by all other DMA cards, which support word transfers only. + Under simulation, we use a byte-packing/unpacking register to hold one + byte while the other is read or written during the DMA cycle. +*/ + +uint32 dmapio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) +{ +const CHANNEL ch = (CHANNEL) dibptr->card_index; /* DMA channel number */ +uint16 data; +IOSIGNAL signal; +IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ + +while (working_set) { + signal = IONEXT (working_set); /* isolate next signal */ + + switch (signal) { /* dispatch I/O signal */ + + case ioCLF: /* clear flag flip-flop */ + dma [ch].flag = dma [ch].flagbuf = CLEAR; /* clear flag and flag buffer */ + break; + + case ioSTF: /* set flag flip-flop */ + case ioENF: /* enable flag */ + dma [ch].flag = dma [ch].flagbuf = SET; /* set flag and flag buffer */ + dma [ch].xferen = CLEAR; /* clear transfer enable to abort transfer */ + break; + + case ioSFC: /* skip if flag is clear */ + setstdSKF (dma [ch]); /* skip if transfer in progress */ + break; + + case ioSFS: /* skip if flag is set */ + setstdSKF (dma [ch]); /* skip if transfer is complete */ + break; + + case ioIOI: /* I/O data input */ + if (UNIT_CPU_TYPE == UNIT_TYPE_1000) /* 1000? */ + stat_data = IORETURN (SCPE_OK, DMASK); /* return all ones */ + else /* other models */ + stat_data = IORETURN (SCPE_OK, 0); /* return all zeros */ + break; + + case ioIOO: /* I/O data output */ + data = IODATA (stat_data); /* clear supplied status */ + + if (UNIT_CPU_MODEL == UNIT_2114) /* 12607? */ + dma [ch].cw1 = (data & 0137707) | 010; /* mask SC, convert to 10-17 */ + else if (UNIT_CPU_TYPE == UNIT_TYPE_211X) /* 12578? */ + dma [ch].cw1 = data; /* store full select code, flags */ + else /* 12895, 12897 */ + dma [ch].cw1 = data & ~DMA1_PB; /* clip byte-packing flag */ + break; + + case ioPOPIO: /* power-on preset to I/O */ + dma [ch].flag = dma [ch].flagbuf = SET; /* set flag and flag buffer */ + break; + + case ioCRS: /* control reset */ + dma [ch].xferen = CLEAR; /* clear transfer enable */ + dma [ch].select = CLEAR; /* set secondary for word count access */ + /* fall into CLC handler */ + + case ioCLC: /* clear control flip-flop */ + dma [ch].control = CLEAR; /* clear control */ + break; + + case ioSTC: /* set control flip-flop */ + dma [ch].packer = 0; /* clear packing register */ + dma [ch].xferen = dma [ch].control = SET; /* set transfer enable and control */ + break; + + case ioSIR: /* set interrupt request */ + setstdPRL (dma [ch]); + setstdIRQ (dma [ch]); + break; + + case ioIAK: /* interrupt acknowledge */ + dma [ch].flagbuf = CLEAR; /* clear flag buffer */ + break; + + default: /* all other signals */ + break; /* are ignored */ + } + + working_set = working_set & ~signal; /* remove current signal from set */ + } + +return stat_data; +} + + +/* Unassigned select code I/O signal handler. + + The 21xx/1000 I/O structure requires that no empty slots exist between + interface cards. This is due to the hardware priority chaining (PRH/PRL). + If it is necessary to leave unused I/O slots, HP 12777A Priority Jumper Cards + must be installed in them to maintain priority continuity. + + Under simulation, every unassigned I/O slot behaves as though a 12777A were + resident. + + Implementation notes: + + 1. For select codes < 10 octal, an IOI reads the floating S-bus (high on + the 1000, low on the 21xx). For select codes >= 10 octal, an IOI reads + the floating I/O bus (low on all machines). + + 2. If "stop_dev" is TRUE, then the simulator will stop when an unassigned + device is accessed. +*/ + +uint32 nullio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) +{ +uint16 data = 0; +IOSIGNAL signal; +IOCYCLE working_set = signal_set; /* no SIR handler needed */ + +while (working_set) { + signal = IONEXT (working_set); /* isolate next signal */ + + switch (signal) { /* dispatch I/O signal */ + + case ioIOI: /* I/O data input */ + if ((dibptr->select_code < VARDEV) && /* internal device */ + (UNIT_CPU_TYPE == UNIT_TYPE_1000)) /* and 1000? */ + data = DMASK; /* return all ones */ + else /* external or other model */ + data = 0; /* return all zeros */ + break; + + default: /* all other signals */ + break; /* are ignored */ + } + + working_set = working_set & ~signal; /* remove current signal from set */ + } + +return IORETURN (stop_dev, data); /* flag missing device */ +} + + +/* DMA cycle routine. + + This routine performs one DMA input or output cycle using the indicated DMA + channel number and DMS map. When the transfer word count reaches zero, the + flag is set on the corresponding DMA channel to indicate completion. + + The 12578A card supports byte-packing. If bit 14 in control word 1 is set, + each transfer will involve one read/write from memory and two output/input + operations in order to transfer sequential bytes to/from the device. + + DMA I/O cycles differ from programmed I/O cycles in that multiple I/O control + backplane signals may be asserted simultaneously. With programmed I/O, only + CLF may be asserted with other signals, specifically with STC, CLC, SFS, SFC, + IOI, or IOO. With DMA, as many as five signals may be asserted concurrently. + + DMA I/O timing looks like this: + + ------------ Input ------------ ----------- Output ------------ + Sig Normal Cycle Last Cycle Normal Cycle Last Cycle + === ============== ============== ============== ============== + IOI T2-T3 T2-T3 + IOO T3-T4 T3-T4 + STC * T3 T3 T3 + CLC * T3-T4 T3-T4 + CLF T3 T3 T3 + EDT T4 T4 + + * if enabled by control word 1 + + Under simulation, this routine dispatches one set of I/O signals per DMA + cycle to the target device's I/O signal handler. The signals correspond to + the table above, except that all signals for a given cycle are concurrent + (e.g., the last input cycle has IOI, EDT, and optionally CLC asserted, even + though IOI and EDT are not coincident in hardware). I/O signal handlers will + process these signals sequentially, in the order listed above, before + returning. + + Implementation notes: + + 1. The address increment and word count decrement is done only after the I/O + cycle has completed successfully. This allows a failed transfer to be + retried after correcting the I/O error. +*/ + +static t_stat dma_cycle (CHANNEL ch, uint32 map) +{ +const uint32 dev = dma [ch].cw1 & I_DEVMASK; /* device select code */ +const uint32 stc = dma [ch].cw1 & DMA1_STC; /* STC enable flag */ +const uint32 bytes = dma [ch].cw1 & DMA1_PB; /* pack bytes flag */ +const uint32 clc = dma [ch].cw1 & DMA1_CLC; /* CLC enable flag */ +const uint32 MA = dma [ch].cw2 & VAMASK; /* memory address */ +const uint32 input = dma [ch].cw2 & DMA2_OI; /* input flag */ +const uint32 even = dma [ch].packer & DMA_OE; /* odd/even packed byte flag */ +uint16 data; +t_stat status; +uint32 ioresult; +IOCYCLE signals; + +if (bytes && !even || dma [ch].cw3 != DMASK) { /* normal cycle? */ + if (input) /* input cycle? */ + signals = ioIOI | ioCLF; /* assert IOI and CLF */ + else /* output cycle */ + signals = ioIOO | ioCLF; /* assert IOO and CLF */ + + if (stc) /* STC wanted? */ + signals = signals | ioSTC; /* assert STC */ + } + +else { /* last cycle */ + if (input) /* input cycle? */ + signals = ioIOI | ioEDT; /* assert IOI and EDT */ + else { /* output cycle */ + signals = ioIOO | ioCLF | ioEDT; /* assert IOO and CLF and EDT */ + + if (stc) /* STC wanted? */ + signals = signals | ioSTC; /* assert STC */ + } + + if (clc) /* CLC wanted? */ + signals = signals | ioCLC; /* assert CLC */ + } + +if (input) { /* input cycle? */ + ioresult = devdisp (dev, signals, 0); /* do I/O input */ + + status = IOSTATUS (ioresult); /* get cycle status */ + + if (status == SCPE_OK) { /* good I/O cycle? */ + data = IODATA (ioresult); /* extract return data value */ + + if (bytes) { /* byte packing? */ + if (even) { /* second byte? */ + data = (uint16) (dma [ch].packer << 8) /* merge stored byte */ + | (data & DMASK8); + WriteIO (MA, data, map); /* store word data */ + } + else /* first byte */ + dma [ch].packer = (data & DMASK8); /* save it */ + + dma [ch].packer = dma [ch].packer ^ DMA_OE; /* flip odd/even bit */ + } + else /* no byte packing */ + WriteIO (MA, data, map); /* store word data */ + } + } + +else { /* output cycle */ + if (bytes) { /* byte packing? */ + if (even) /* second byte? */ + data = dma [ch].packer & DMASK8; /* retrieve it */ + + else { /* first byte */ + dma [ch].packer = ReadIO (MA, map); /* read word data */ + data = (dma [ch].packer >> 8) & DMASK8; /* get high byte */ + } + + dma [ch].packer = dma [ch].packer ^ DMA_OE; /* flip odd/even bit */ + } + else /* no byte packing */ + data = ReadIO (MA, map); /* read word data */ + + ioresult = devdisp (dev, signals, data); /* do I/O output */ + + status = IOSTATUS (ioresult); /* get cycle status */ + } + +if ((even || !bytes) && (status == SCPE_OK)) { /* new byte or no packing and good xfer? */ + dma [ch].cw2 = input | (dma [ch].cw2 + 1) & VAMASK; /* increment address */ + dma [ch].cw3 = (dma [ch].cw3 + 1) & DMASK; /* increment word count */ + + if (dma [ch].cw3 == 0) /* end of transfer? */ + dmapio (dtab [DMA1 + ch], ioENF, 0); /* set DMA channel flag */ + } + +return status; /* return I/O status */ +} + + +/* Reset routines. + + The reset routines are called to simulate either an initial power on + condition or a front-panel PRESET button press. For initial power on + (corresponds to PON, POPIO, and CRS signal assertion in the CPU), the "P" + command switch will be set. For PRESET (corresponds to POPIO and CRS + assertion), the switch will be clear. + + SCP delivers a power-on reset to all devices when the simulator is started. + A RUN, BOOT, RESET, or RESET ALL command delivers a PRESET to all devices. A + RESET delivers a PRESET to a specific device. +*/ + + +/* CPU reset. + + If this is the first call after simulator startup, allocate the initial + memory array, set the default CPU model, and install the default BBL. +*/ + +t_stat cpu_reset (DEVICE *dptr) +{ +if (M == NULL) { /* initial call after startup? */ + pcq_r = find_reg ("PCQ", NULL, dptr); /* get PC queue pointer */ + + if (pcq_r) /* defined? */ + pcq_r->qptr = 0; /* initialize queue */ + else /* not defined */ + return SCPE_IERR; /* internal error */ + + M = (uint16 *) calloc (PASIZE, sizeof (uint16)); /* alloc mem */ + + if (M == NULL) /* alloc fail? */ + return SCPE_MEM; + else { /* do one-time init */ + MEMSIZE = 32768; /* set initial memory size */ + cpu_set_model (NULL, UNIT_2116, NULL, NULL); /* set initial CPU model */ + SR = 001000; /* select PTR boot ROM at SC 10 */ + cpu_boot (0, NULL); /* install loader for 2116 */ + cpu_set_ldr (NULL, FALSE, NULL, NULL); /* disable loader (was enabled) */ + SR = 0; /* clear S */ + sim_vm_post = &hp_post_cmd; /* set cmd post proc */ + sim_vm_fprint_stopped = &hp_fprint_stopped; /* set sim stop printer */ + sim_brk_types = ALL_BKPTS; /* register allowed breakpoint types */ + } + } + +if (sim_switches & SWMASK ('P')) /* PON reset? */ + IOPOWERON (&cpu_dib); +else /* PRESET */ + IOPRESET (&cpu_dib); + +sim_brk_dflt = SWMASK ('N'); /* type is nomap as DMS is off */ + +return SCPE_OK; +} + + +/* Memory protect reset */ + +t_stat mp_reset (DEVICE *dptr) +{ +IOPRESET (&mp_dib); /* PRESET device (does not use PON) */ + +mp_fence = 0; /* clear fence register */ +mp_viol = 0; /* clear violation register */ + +return SCPE_OK; +} + + +/* DMA reset */ + +t_stat dma_reset (DEVICE *dptr) +{ +DIB *dibptr = (DIB *) dptr->ctxt; /* DIB pointer */ +const CHANNEL ch = (CHANNEL) dibptr->card_index; /* DMA channel number */ + +if (UNIT_CPU_MODEL != UNIT_2114) /* 2114 has only one channel */ + hp_enbdis_pair (dma_dptrs [ch], /* make specified channel */ + dma_dptrs [ch ^ 1]); /* consistent with other channel */ + +if (sim_switches & SWMASK ('P')) { /* power-on reset? */ + dma [ch].cw1 = 0; /* clear control word registers */ + dma [ch].cw2 = 0; + dma [ch].cw3 = 0; + } + +IOPRESET (dibptr); /* PRESET device (does not use PON) */ + +dma [ch].packer = 0; /* clear byte packer */ + +return SCPE_OK; +} + + +/* Memory examine */ + +t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw) +{ +uint16 d; + +if ((sw & ALL_MAPMODES) && (dms_enb == 0)) /* req map with DMS off? */ + return SCPE_NOFNC; /* command not allowed */ + +addr = dms_cons (addr, sw); /* translate address as indicated */ + +if (addr >= MEMSIZE) /* beyond memory limits? */ + return SCPE_NXM; /* non-existent memory */ + +if ((sw & SIM_SW_REST) || (addr >= 2)) /* restoring or memory access? */ + d = M[addr]; /* return memory value */ +else /* not restoring and A/B access */ + d = ABREG[addr]; /* return A/B register value */ + +if (vptr != NULL) + *vptr = d & DMASK; /* store return value */ +return SCPE_OK; +} + +/* Memory deposit */ + +t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw) +{ +if ((sw & ALL_MAPMODES) && (dms_enb == 0)) /* req map with DMS off? */ + return SCPE_NOFNC; /* command not allowed */ + +addr = dms_cons (addr, sw); /* translate address as indicated */ + +if (addr >= MEMSIZE) /* beyond memory limits? */ + return SCPE_NXM; /* non-existent memory */ + +if ((sw & SIM_SW_REST) || (addr >= 2)) /* restoring or memory access? */ + M[addr] = val & DMASK; /* store memory value */ +else /* not restoring and A/B access */ + ABREG[addr] = val & DMASK; /* store A/B register value */ + +return SCPE_OK; +} + + +/* Make a pair of devices consistent */ + +void hp_enbdis_pair (DEVICE *ccp, DEVICE *dcp) +{ +if (ccp->flags & DEV_DIS) + dcp->flags = dcp->flags | DEV_DIS; +else + dcp->flags = dcp->flags & ~DEV_DIS; + +return; +} + + +/* VM command post-processor + + Update T register to contents of memory addressed by M register + if M register has changed. +*/ + +void hp_post_cmd (t_bool from_scp) +{ +if (MR != saved_MR) { /* M changed since last update? */ + saved_MR = MR; + TR = ReadTAB (MR); /* sync T with new M */ + } +return; +} + + +/* Test for device conflict */ + +static t_bool dev_conflict (void) +{ +DEVICE *dptr; +DIB *dibptr; +uint32 i, j, k; +t_bool is_conflict = FALSE; +uint32 conflicts [MAXDEV + 1] = { 0 }; + +for (i = 0; sim_devices [i] != NULL; i++) { + dptr = sim_devices [i]; + dibptr = (DIB *) dptr->ctxt; + if (dibptr && !(dptr->flags & DEV_DIS)) + if (++conflicts [dibptr->select_code] > 1) + is_conflict = TRUE; + } + +if (is_conflict) { + sim_ttcmd(); + for (i = 0; i <= MAXDEV; i++) { + if (conflicts [i] > 1) { + k = conflicts [i]; + + printf ("Select code %o conflict:", i); + + if (sim_log) + fprintf (sim_log, "Select code %o conflict:", i); + + for (j = 0; sim_devices [j] != NULL; j++) { + dptr = sim_devices [j]; + dibptr = (DIB *) dptr->ctxt; + if (dibptr && !(dptr->flags & DEV_DIS) && i == dibptr->select_code) { + if (k < conflicts [i]) { + printf (" and"); + + if (sim_log) + fputs (" and", sim_log); + } + + printf (" %s", sim_dname (dptr)); + + if (sim_log) + fprintf (sim_log, " %s", sim_dname (dptr)); + + k = k - 1; + + if (k == 0) { + putchar ('\n'); + + if (sim_log) + fputc ('\n', sim_log); + break; + } + } + } + } + } + } +return is_conflict; +} + + +/* Change CPU memory size. + + On a 21xx, move the current loader to the top of the new memory size. Then + clear "non-existent memory" so that reads return zero, per spec. + + Validation: + - New size <= maximum size for current CPU. + - New size a positive multiple of 4K (progamming error if not). + - If new size < old size, truncation accepted. +*/ + +t_stat cpu_set_size (UNIT *uptr, int32 new_size, char *cptr, void *desc) +{ +int32 mc = 0; +uint32 i; +uint32 model = CPU_MODEL_INDEX; /* current CPU model index */ +uint32 old_size = (uint32) MEMSIZE; /* current memory size */ + +if ((uint32) new_size > cpu_features[model].maxmem) + return SCPE_NOFNC; /* mem size unsupported */ + +if ((new_size <= 0) || (new_size > PASIZE) || ((new_size & 07777) != 0)) + return SCPE_NXM; /* invalid size (prog err) */ + +if (!(sim_switches & SWMASK ('F'))) { /* force truncation? */ + for (i = new_size; i < MEMSIZE; i++) /* check truncated memory */ + mc = mc | M[i]; /* for content */ + + if ((mc != 0) && (!get_yn ("Really truncate memory [N]?", FALSE))) + return SCPE_INCOMP; + } + +if (UNIT_CPU_FAMILY == UNIT_FAMILY_21XX) { /* 21xx CPU? */ + cpu_set_ldr (uptr, FALSE, NULL, NULL); /* save loader to shadow RAM */ + MEMSIZE = new_size; /* set new memory size */ + fwanxm = (uint32) MEMSIZE - IBL_LNT; /* reserve memory for loader */ + } +else /* loader unsupported */ + MEMSIZE = fwanxm = new_size; /* set new memory size */ + +for (i = fwanxm; i < old_size; i++) /* zero non-existent memory */ + M[i] = 0; + +return SCPE_OK; +} + + +/* Change CPU models. + + For convenience, MP and DMA are typically enabled if available; they may be + disabled subsequently if desired. Note that the 2114 supports only one DMA + channel (channel 1). All other models support two channels. + + Validation: + - Sets standard equipment and convenience features. + - Changes DMA device name to DCPC if 1000 is selected. + - Enforces maximum memory allowed (doesn't change otherwise). + - Disables loader on 21xx machines. +*/ + +t_stat cpu_set_model (UNIT *uptr, int32 new_model, char *cptr, void *desc) +{ +uint32 old_family = UNIT_CPU_FAMILY; /* current CPU type */ +uint32 new_family = new_model & UNIT_FAMILY_MASK; /* new CPU family */ +uint32 new_index = new_model >> UNIT_V_CPU; /* new CPU model index */ +uint32 new_memsize; +t_stat result; + +cpu_unit.flags = cpu_unit.flags & ~UNIT_OPTS | /* set typical features */ + cpu_features[new_index].typ & UNIT_OPTS; /* mask pseudo-opts */ + + +if (cpu_features[new_index].typ & UNIT_MP) /* MP in typ config? */ + mp_dev.flags = mp_dev.flags & ~DEV_DIS; /* enable it */ +else + mp_dev.flags = mp_dev.flags | DEV_DIS; /* disable it */ + +if (cpu_features[new_index].opt & UNIT_MP) /* MP an option? */ + mp_dev.flags = mp_dev.flags | DEV_DISABLE; /* make it alterable */ +else + mp_dev.flags = mp_dev.flags & ~DEV_DISABLE; /* make it unalterable */ + + +if (cpu_features[new_index].typ & UNIT_DMA) { /* DMA in typ config? */ + dma1_dev.flags = dma1_dev.flags & ~DEV_DIS; /* enable DMA channel 1 */ + + if (new_model == UNIT_2114) /* 2114 has only one channel */ + dma2_dev.flags = dma2_dev.flags | DEV_DIS; /* disable channel 2 */ + else /* all others have two channels */ + dma2_dev.flags = dma2_dev.flags & ~DEV_DIS; /* enable it */ + } +else { + dma1_dev.flags = dma1_dev.flags | DEV_DIS; /* disable channel 1 */ + dma2_dev.flags = dma2_dev.flags | DEV_DIS; /* disable channel 2 */ + } + +if (cpu_features[new_index].opt & UNIT_DMA) { /* DMA an option? */ + dma1_dev.flags = dma1_dev.flags | DEV_DISABLE; /* make it alterable */ + + if (new_model == UNIT_2114) /* 2114 has only one channel */ + dma2_dev.flags = dma2_dev.flags & ~DEV_DISABLE; /* make it unalterable */ + else /* all others have two channels */ + dma2_dev.flags = dma2_dev.flags | DEV_DISABLE; /* make it alterable */ + } +else { + dma1_dev.flags = dma1_dev.flags & ~DEV_DISABLE; /* make it unalterable */ + dma2_dev.flags = dma2_dev.flags & ~DEV_DISABLE; /* make it unalterable */ + } + + +if ((old_family == UNIT_FAMILY_1000) && /* if current family is 1000 */ + (new_family == UNIT_FAMILY_21XX)) { /* and new family is 21xx */ + deassign_device (&dma1_dev); /* delete DCPC names */ + deassign_device (&dma2_dev); + } +else if ((old_family == UNIT_FAMILY_21XX) && /* if current family is 21xx */ + (new_family == UNIT_FAMILY_1000)) { /* and new family is 1000 */ + assign_device (&dma1_dev, "DCPC1"); /* change DMA device name */ + assign_device (&dma2_dev, "DCPC2"); /* to DCPC for familiarity */ + } + +if ((MEMSIZE == 0) || /* current mem size not set? */ + (MEMSIZE > cpu_features[new_index].maxmem)) /* current mem size too large? */ + new_memsize = cpu_features[new_index].maxmem; /* set it to max supported */ +else + new_memsize = (uint32) MEMSIZE; /* or leave it unchanged */ + +result = cpu_set_size (uptr, new_memsize, NULL, NULL); /* set memory size */ + +if (result == SCPE_OK) /* memory change OK? */ + if (new_family == UNIT_FAMILY_21XX) /* 21xx CPU? */ + fwanxm = (uint32) MEMSIZE - IBL_LNT; /* reserve memory for loader */ + else + fwanxm = (uint32) MEMSIZE; /* loader reserved only for 21xx */ + +return result; +} + + +/* Display the CPU model and optional loader status. + + Loader status is displayed for 21xx models and suppressed for 1000 models. +*/ + +t_stat cpu_show_model (FILE *st, UNIT *uptr, int32 val, void *desc) +{ +fputs ((char *) desc, st); /* write model name */ + +if (UNIT_CPU_FAMILY == UNIT_FAMILY_21XX) /* valid only for 21xx */ + if (fwanxm < MEMSIZE) /* loader area non-existent? */ + fputs (", loader disabled", st); /* yes, so access disabled */ + else + fputs (", loader enabled", st); /* no, so access enabled */ +return SCPE_OK; +} + + +/* Set a CPU option. + + Validation: + - Checks that the current CPU model supports the option selected. + - If CPU is 1000-F, ensures that VIS and IOP are mutually exclusive. + - If CPU is 2100, ensures that FP/FFP and IOP are mutually exclusive. + - If CPU is 2100, ensures that FP is enabled if FFP enabled + (FP is required for FFP installation). +*/ + +t_stat cpu_set_opt (UNIT *uptr, int32 option, char *cptr, void *desc) +{ +uint32 model = CPU_MODEL_INDEX; /* current CPU model index */ + +if ((cpu_features[model].opt & option) == 0) /* option supported? */ + return SCPE_NOFNC; /* no */ + +if (UNIT_CPU_TYPE == UNIT_TYPE_2100) { + if ((option == UNIT_FP) || (option == UNIT_FFP)) /* 2100 IOP and FP/FFP options */ + uptr->flags = uptr->flags & ~UNIT_IOP; /* are mutually exclusive */ + else if (option == UNIT_IOP) + uptr->flags = uptr->flags & ~(UNIT_FP | UNIT_FFP); + + if (option == UNIT_FFP) /* 2100 FFP option requires FP */ + uptr->flags = uptr->flags | UNIT_FP; + } + +else if (UNIT_CPU_MODEL == UNIT_1000_F) + if (option == UNIT_VIS) /* 1000-F IOP and VIS options */ + uptr->flags = uptr->flags & ~UNIT_IOP; /* are mutually exclusive */ + else if (option == UNIT_IOP) + uptr->flags = uptr->flags & ~UNIT_VIS; + +return SCPE_OK; +} + + +/* Clear a CPU option. + + Validation: + - Checks that the current CPU model supports the option selected. + - Clears flag from unit structure (we are processing MTAB_XTD entries). + - If CPU is 2100, ensures that FFP is disabled if FP disabled + (FP is required for FFP installation). +*/ + +t_bool cpu_clr_opt (UNIT *uptr, int32 option, char *cptr, void *desc) +{ +uint32 model = CPU_MODEL_INDEX; /* current CPU model index */ + +if ((cpu_features[model].opt & option) == 0) /* option supported? */ + return SCPE_NOFNC; /* no */ + +uptr->flags = uptr->flags & ~option; /* disable option */ + +if ((UNIT_CPU_TYPE == UNIT_TYPE_2100) && /* disabling 2100 FP? */ + (option == UNIT_FP)) + uptr->flags = uptr->flags & ~UNIT_FFP; /* yes, so disable FFP too */ + +return SCPE_OK; +} + + +/* 21xx loader enable/disable function. + + The 21xx CPUs store their initial binary loaders in the last 64 words of + available memory. This memory is protected by a LOADER ENABLE switch on the + front panel. When the switch is off (disabled), main memory effectively ends + 64 locations earlier, i.e., the loader area is treated as non-existent. + Because these are core machines, the loader is retained when system power is + off. + + 1000 CPUs do not have a protected loader feature. Instead, loaders are + stored in PROMs and are copied into main memory for execution by the IBL + switch. + + Under simulation, we keep both a total configured memory size (MEMSIZE) and a + current configured memory size (fwanxm = "first word address of non-existent + memory"). When the two are equal, the loader is enabled. When the current + size is less than the total size, the loader is disabled. + + Disabling the loader copies the last 64 words to a shadow array, zeros the + corresponding memory, and decreases the last word of addressable memory by + 64. Enabling the loader reverses this process. + + Disabling may be done manually by user command or automatically when a halt + instruction is executed. Enabling occurs only by user command. This differs + slightly from actual machine operation, which additionally disables the + loader when a manual halt is performed. We do not do this to allow + breakpoints within and single-stepping through the loaders. +*/ + +t_stat cpu_set_ldr (UNIT *uptr, int32 enable, char *cptr, void *desc) +{ +static BOOT_ROM loader; +int32 i; +t_bool is_enabled = (fwanxm == MEMSIZE); + +if ((UNIT_CPU_FAMILY != UNIT_FAMILY_21XX) || /* valid only for 21xx */ + (MEMSIZE == 0)) /* and for initialized memory */ + return SCPE_NOFNC; + +if (is_enabled && (enable == 0)) { /* disable loader? */ + fwanxm = (uint32) MEMSIZE - IBL_LNT; /* decrease available memory */ + for (i = 0; i < IBL_LNT; i++) { /* copy loader */ + loader[i] = M[fwanxm + i]; /* from memory */ + M[fwanxm + i] = 0; /* and zero location */ + } + } + +else if ((!is_enabled) && (enable == 1)) { /* enable loader? */ + for (i = 0; i < IBL_LNT; i++) /* copy loader */ + M[fwanxm + i] = loader[i]; /* to memory */ + fwanxm = (uint32) MEMSIZE; /* increase available memory */ + } + +return SCPE_OK; +} + + +/* Idle enable/disable */ + +t_stat cpu_set_idle (UNIT *uptr, int32 option, char *cptr, void *desc) +{ + if (option) + return sim_set_idle (uptr, 10, NULL, NULL); + else + return sim_clr_idle (uptr, 0, NULL, NULL); +} + + +/* Idle display */ + +t_stat cpu_show_idle (FILE *st, UNIT *uptr, int32 val, void *desc) +{ + return sim_show_idle (st, uptr, val, desc); +} + + +/* IBL routine (CPU boot) */ + +t_stat cpu_boot (int32 unitno, DEVICE *dptr) +{ +int32 dev = (SR >> IBL_V_DEV) & I_DEVMASK; +int32 sel = (SR >> IBL_V_SEL) & IBL_M_SEL; + +if (dev < 010) + return SCPE_NOFNC; + +switch (sel) { + + case 0: /* PTR boot */ + ibl_copy (ptr_rom, dev, IBL_S_NOCLR, IBL_S_NOSET); + break; + + case 1: /* DP/DQ boot */ + ibl_copy (dq_rom, dev, IBL_S_NOCLR, IBL_S_NOSET); + break; + + case 2: /* MS boot */ + ibl_copy (ms_rom, dev, IBL_S_NOCLR, IBL_S_NOSET); + break; + + case 3: /* DS boot */ + ibl_copy (ds_rom, dev, IBL_S_NOCLR, IBL_S_NOSET); + break; + } + +return SCPE_OK; +} + + +/* IBL boot ROM copy + + - Use memory size to set the initial PC and base of the boot area + - Copy boot ROM to memory, updating I/O instructions + - Place 2s complement of boot base in last location + - Modify S register as indicated + + Notes: + - Boot ROMs must be assembled with a device code of 10 (10 and 11 for + devices requiring two codes) +*/ + +t_stat ibl_copy (const BOOT_ROM rom, int32 dev, uint32 sr_clear, uint32 sr_set) +{ +int32 i; +uint16 wd; + +cpu_set_ldr (NULL, TRUE, NULL, NULL); /* enable loader (ignore errors) */ + +if (dev < 010) /* valid device? */ + return SCPE_ARG; + +PC = ((MEMSIZE - 1) & ~IBL_MASK) & VAMASK; /* start at mem top */ + +for (i = 0; i < IBL_LNT; i++) { /* copy bootstrap */ + wd = rom[i]; /* get word */ + + if (((wd & I_NMRMASK) == I_IO) && /* IO instruction? */ + ((wd & I_DEVMASK) >= 010) && /* dev >= 10? */ + (I_GETIOOP (wd) != soHLT)) /* not a HALT? */ + M[PC + i] = (wd + (dev - 010)) & DMASK; /* change dev code */ + + else /* leave unchanged */ + M[PC + i] = wd; + } + +M[PC + IBL_DPC] = (M[PC + IBL_DPC] + (dev - 010)) & DMASK; /* patch DMA ctrl */ +M[PC + IBL_END] = (~PC + 1) & DMASK; /* fill in start of boot */ + +SR = (SR & sr_clear) | sr_set; /* modify the S register as indicated */ + +return SCPE_OK; +} diff --git a/HP2100/hp2100_cpu.h b/HP2100/hp2100_cpu.h index 4e0db47e..74b28d8b 100644 --- a/HP2100/hp2100_cpu.h +++ b/HP2100/hp2100_cpu.h @@ -1,331 +1,335 @@ -/* hp2100_cpu.h: HP 2100 CPU definitions - - Copyright (c) 2005-2010, Robert M. Supnik - - 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 - ROBERT M SUPNIK 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 Robert M Supnik shall not - be used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from Robert M Supnik. - - 03-Jan-10 RMS Changed declarations of mp_control, mp_mefvv, for VMS compiler - 15-Jul-08 JDB Rearranged declarations with hp2100_cpu.c and hp2100_defs.h - 26-Jun-08 JDB Added mp_control to CPU state externals - 24-Apr-08 JDB Added calc_defer() prototype - 20-Apr-08 JDB Added DEB_VIS and DEB_SIG debug flags - 26-Nov-07 JDB Added extern sim_deb, cpu_dev, DEB flags for debug printouts - 05-Nov-07 JDB Added extern intaddr, mp_viol, mp_mevff, calc_int, dev_ctl, - ReadIO, WriteIO for RTE-6/VM microcode support - 16-Dec-06 JDB Added UNIT_2115 and UNIT_2114 - 16-Oct-06 JDB Moved ReadF to hp2100_cpu1.c - 26-Sep-06 JDB Added CPU externs for microcode simulators - 16-Aug-06 JDB Added UNIT_EMA for future RTE-4 EMA microcode - Added UNIT_VMA for future RTE-6 VMA and OS microcode - Added UNIT_1000_F for future F-Series support - 09-Aug-06 JDB Added UNIT_DBI for double integer microcode - 21-Jan-05 JDB Reorganized CPU option flags - 14-Jan-05 RMS Cloned from hp2100_cpu.c - - CPU models are broken down into family, type, and series to facilitate option - validation. Bit 3 encodes the family, bit 2 encodes the type, and bits 1:0 - encode the series within the type. -*/ - -#ifndef _HP2100_CPU_H_ -#define _HP2100_CPU_H_ 0 - -#include - - -/* CPU model definition flags */ - -#define CPU_V_SERIES 0 -#define CPU_V_TYPE 2 -#define CPU_V_FAMILY 3 - -#define FAMILY_21XX (0 << CPU_V_FAMILY) -#define FAMILY_1000 (1 << CPU_V_FAMILY) - -#define TYPE_211X (0 << CPU_V_TYPE) /* 2114, 2115, 2116 */ -#define TYPE_2100 (1 << CPU_V_TYPE) /* 2100A, 2100S */ -#define TYPE_1000MEF (0 << CPU_V_TYPE) /* 1000-M, 1000-E, 1000-F */ -#define TYPE_1000AL (1 << CPU_V_TYPE) /* 1000-L, A600, A700, A900, A990 */ - -#define SERIES_16 (0 << CPU_V_SERIES) /* 211X */ -#define SERIES_15 (1 << CPU_V_SERIES) /* 211X */ -#define SERIES_14 (2 << CPU_V_SERIES) /* 211X */ -#define SERIES_00 (0 << CPU_V_SERIES) /* 2100 */ -#define SERIES_M (0 << CPU_V_SERIES) /* 1000 */ -#define SERIES_E (1 << CPU_V_SERIES) /* 1000 */ -#define SERIES_F (2 << CPU_V_SERIES) /* 1000 */ - -/* CPU unit flags */ - -#define UNIT_M_CPU 017 /* CPU model mask [3:0] */ -#define UNIT_M_TYPE 014 /* CPU type mask [3:2] */ -#define UNIT_M_FAMILY 010 /* CPU family mask [3:3] */ - -#define UNIT_V_CPU (UNIT_V_UF + 0) /* CPU model bits 0-3 */ -#define UNIT_V_EAU (UNIT_V_UF + 4) /* EAU installed */ -#define UNIT_V_FP (UNIT_V_UF + 5) /* FP installed */ -#define UNIT_V_IOP (UNIT_V_UF + 6) /* IOP installed */ -#define UNIT_V_DMS (UNIT_V_UF + 7) /* DMS installed */ -#define UNIT_V_FFP (UNIT_V_UF + 8) /* FFP installed */ -#define UNIT_V_DBI (UNIT_V_UF + 9) /* DBI installed */ -#define UNIT_V_EMA (UNIT_V_UF + 10) /* RTE-4 EMA installed */ -#define UNIT_V_VMAOS (UNIT_V_UF + 11) /* RTE-6 VMA/OS installed */ -#define UNIT_V_VIS (UNIT_V_UF + 12) /* VIS installed */ -#define UNIT_V_SIGNAL (UNIT_V_UF + 13) /* SIGNAL/1000 installed */ -/* Future microcode expansion; reuse flags bottom-up if needed */ -#define UNIT_V_DS (UNIT_V_UF + 14) /* DS installed */ - -/* Unit models */ - -#define UNIT_MODEL_MASK (UNIT_M_CPU << UNIT_V_CPU) - -#define UNIT_2116 ((FAMILY_21XX | TYPE_211X | SERIES_16) << UNIT_V_CPU) -#define UNIT_2115 ((FAMILY_21XX | TYPE_211X | SERIES_15) << UNIT_V_CPU) -#define UNIT_2114 ((FAMILY_21XX | TYPE_211X | SERIES_14) << UNIT_V_CPU) -#define UNIT_2100 ((FAMILY_21XX | TYPE_2100 | SERIES_00) << UNIT_V_CPU) -#define UNIT_1000_M ((FAMILY_1000 | TYPE_1000MEF | SERIES_M) << UNIT_V_CPU) -#define UNIT_1000_E ((FAMILY_1000 | TYPE_1000MEF | SERIES_E) << UNIT_V_CPU) -#define UNIT_1000_F ((FAMILY_1000 | TYPE_1000MEF | SERIES_F) << UNIT_V_CPU) - -/* Unit types */ - -#define UNIT_TYPE_MASK (UNIT_M_TYPE << UNIT_V_CPU) - -#define UNIT_TYPE_211X ((FAMILY_21XX | TYPE_211X) << UNIT_V_CPU) -#define UNIT_TYPE_2100 ((FAMILY_21XX | TYPE_2100) << UNIT_V_CPU) -#define UNIT_TYPE_1000 ((FAMILY_1000 | TYPE_1000MEF) << UNIT_V_CPU) - -/* Unit families */ - -#define UNIT_FAMILY_MASK (UNIT_M_FAMILY << UNIT_V_CPU) - -#define UNIT_FAMILY_21XX (FAMILY_21XX << UNIT_V_CPU) -#define UNIT_FAMILY_1000 (FAMILY_1000 << UNIT_V_CPU) - -/* Unit accessors */ - -#define UNIT_CPU_MODEL (cpu_unit.flags & UNIT_MODEL_MASK) -#define UNIT_CPU_TYPE (cpu_unit.flags & UNIT_TYPE_MASK) -#define UNIT_CPU_FAMILY (cpu_unit.flags & UNIT_FAMILY_MASK) - -#define CPU_MODEL_INDEX (UNIT_CPU_MODEL >> UNIT_V_CPU) - -/* Unit features */ - -#define UNIT_EAU (1 << UNIT_V_EAU) -#define UNIT_FP (1 << UNIT_V_FP) -#define UNIT_IOP (1 << UNIT_V_IOP) -#define UNIT_DMS (1 << UNIT_V_DMS) -#define UNIT_FFP (1 << UNIT_V_FFP) -#define UNIT_DBI (1 << UNIT_V_DBI) -#define UNIT_EMA (1 << UNIT_V_EMA) -#define UNIT_VMAOS (1 << UNIT_V_VMAOS) -#define UNIT_VIS (1 << UNIT_V_VIS) -#define UNIT_DS (1 << UNIT_V_DS) -#define UNIT_SIGNAL (1 << UNIT_V_SIGNAL) - -#define UNIT_EMA_VMA (UNIT_EMA | UNIT_VMAOS) - -#define UNIT_OPTS (UNIT_EAU | UNIT_FP | UNIT_IOP | \ - UNIT_DMS | UNIT_FFP | UNIT_DBI | \ - UNIT_EMA | UNIT_VMAOS | \ - UNIT_VIS | UNIT_DS | UNIT_SIGNAL) - -/* "Pseudo-option" flags used only for option testing; never set into UNIT structure. */ - -#define UNIT_V_PFAIL (UNIT_V_UF - 1) /* Power fail installed */ -#define UNIT_V_DMA (UNIT_V_UF - 2) /* DMA installed */ -#define UNIT_V_MP (UNIT_V_UF - 3) /* Memory protect installed */ - -#define UNIT_PFAIL (1 << UNIT_V_PFAIL) -#define UNIT_DMA (1 << UNIT_V_DMA) -#define UNIT_MP (1 << UNIT_V_MP) - -#define UNIT_NONE 0 /* no options */ - -/* Debug flags */ - -#define DEB_OS (1 << 0) /* RTE-6/VM OS firmware non-TBG processing */ -#define DEB_OSTBG (1 << 1) /* RTE-6/VM OS firmware TBG processing */ -#define DEB_VMA (1 << 2) /* RTE-6/VM VMA firmware instructions */ -#define DEB_EMA (1 << 3) /* RTE-6/VM EMA firmware instructions */ -#define DEB_VIS (1 << 4) /* E/F-Series VIS firmware instructions */ -#define DEB_SIG (1 << 5) /* F-Series SIGNAL/1000 firmware instructions */ - -/* PC queue. */ - -#define PCQ_SIZE 64 /* must be 2**n */ -#define PCQ_MASK (PCQ_SIZE - 1) -#define PCQ_ENTRY pcq[pcq_p = (pcq_p - 1) & PCQ_MASK] = err_PC - -/* Memory reference instructions */ - -#define I_IA 0100000 /* indirect address */ -#define I_AB 0004000 /* A/B select */ -#define I_CP 0002000 /* current page */ -#define I_DISP 0001777 /* page displacement */ -#define I_PAGENO 0076000 /* page number */ - -/* Other instructions */ - -#define I_NMRMASK 0172000 /* non-mrf opcode */ -#define I_ASKP 0002000 /* alter/skip */ -#define I_IO 0102000 /* I/O */ -#define I_CTL 0004000 /* CTL on/off */ -#define I_HC 0001000 /* hold/clear */ -#define I_DEVMASK 0000077 /* device select code mask */ -#define I_GETIOOP(x) (((x) >> 6) & 07) /* I/O sub op */ - -/* Instruction masks */ - -#define I_MRG 0074000 /* MRG instructions */ -#define I_MRG_I (I_MRG | I_IA) /* MRG indirect instruction group */ -#define I_JSB 0014000 /* JSB instruction */ -#define I_JSB_I (I_JSB | I_IA) /* JSB,I instruction */ -#define I_JMP 0024000 /* JMP instruction */ -#define I_ISZ 0034000 /* ISZ instruction */ - -#define I_IOG 0107700 /* I/O group instruction */ -#define I_SFS 0102300 /* SFS instruction */ -#define I_STF 0102100 /* STF instruction */ - -/* Memory management */ - -#define VA_N_OFF 10 /* offset width */ -#define VA_M_OFF ((1 << VA_N_OFF) - 1) /* offset mask */ -#define VA_GETOFF(x) ((x) & VA_M_OFF) -#define VA_N_PAG (VA_N_SIZE - VA_N_OFF) /* page width */ -#define VA_V_PAG (VA_N_OFF) /* page offset */ -#define VA_M_PAG ((1 << VA_N_PAG) - 1) /* page mask */ -#define VA_GETPAG(x) (((x) >> VA_V_PAG) & VA_M_PAG) - -/* Maps */ - -#define MAP_NUM 4 /* num maps */ -#define MAP_LNT (1 << VA_N_PAG) /* map length */ -#define MAP_MASK ((MAP_NUM * MAP_LNT) - 1) -#define SMAP 0 /* system map */ -#define UMAP (SMAP + MAP_LNT) /* user map */ -#define PAMAP (UMAP + MAP_LNT) /* port A map */ -#define PBMAP (PAMAP + MAP_LNT) /* port B map */ - -/* DMS map entries */ - -#define MAP_V_RPR 15 /* read prot */ -#define MAP_V_WPR 14 /* write prot */ -#define RDPROT (1 << MAP_V_RPR) /* read access check */ -#define WRPROT (1 << MAP_V_WPR) /* write access check */ -#define NOPROT 0 /* no access check */ -#define MAP_RSVD 0036000 /* reserved bits */ -#define MAP_N_PAG (PA_N_SIZE - VA_N_OFF) /* page width */ -#define MAP_V_PAG (VA_N_OFF) -#define MAP_M_PAG ((1 << MAP_N_PAG) - 1) -#define MAP_GETPAG(x) (((x) & MAP_M_PAG) << MAP_V_PAG) - -/* MEM status register */ - -#define MST_ENBI 0100000 /* MEM enabled at interrupt */ -#define MST_UMPI 0040000 /* User map selected at inerrupt */ -#define MST_ENB 0020000 /* MEM enabled currently */ -#define MST_UMP 0010000 /* User map selected currently */ -#define MST_PRO 0004000 /* Protected mode enabled currently */ -#define MST_FLT 0002000 /* Base page portion mapped */ -#define MST_FENCE 0001777 /* Base page fence */ - -/* MEM violation register */ - -#define MVI_V_RPR 15 /* must be same as */ -#define MVI_V_WPR 14 /* MAP_V_xPR */ -#define MVI_RPR (1 << MVI_V_RPR) /* rd viol */ -#define MVI_WPR (1 << MVI_V_WPR) /* wr viol */ -#define MVI_BPG 0020000 /* base page viol */ -#define MVI_PRV 0010000 /* priv viol */ -#define MVI_MEB 0000200 /* me bus enb @ viol */ -#define MVI_MEM 0000100 /* mem enb @ viol */ -#define MVI_UMP 0000040 /* usr map @ viol */ -#define MVI_PAG 0000037 /* pag sel */ - -/* CPU registers */ - -#define AR ABREG[0] /* A = reg 0 */ -#define BR ABREG[1] /* B = reg 1 */ - -extern uint16 ABREG[2]; /* A/B regs (use AR/BR) */ -extern uint32 PC; /* P register */ -extern uint32 SR; /* S register */ -extern uint32 MR; /* M register */ -extern uint32 TR; /* T register */ -extern uint32 XR; /* X register */ -extern uint32 YR; /* Y register */ -extern uint32 E; /* E register */ -extern uint32 O; /* O register */ - -/* CPU state */ - -extern uint32 err_PC; -extern uint32 dms_enb; -extern uint32 dms_ump; -extern uint32 dms_sr; -extern uint32 dms_vr; -extern FLIP_FLOP mp_control; -extern uint32 mp_fence; -extern uint32 mp_viol; -extern FLIP_FLOP mp_mevff; -extern uint32 iop_sp; -extern t_bool ion_defer; -extern uint32 intaddr; -extern uint16 pcq [PCQ_SIZE]; -extern uint32 pcq_p; -extern uint32 stop_inst; -extern UNIT cpu_unit; -extern DEVICE cpu_dev; -extern jmp_buf save_env; - - -/* CPU functions */ - -#define MP_ABORT(va) longjmp (save_env, (va)) - -extern t_stat resolve (uint32 MA, uint32 *addr, uint32 irq); -extern uint16 ReadPW (uint32 pa); -extern uint8 ReadB (uint32 va); -extern uint8 ReadBA (uint32 va); -extern uint16 ReadW (uint32 va); -extern uint16 ReadWA (uint32 va); -extern uint16 ReadIO (uint32 va, uint32 map); -extern void WritePW (uint32 pa, uint32 dat); -extern void WriteB (uint32 va, uint32 dat); -extern void WriteBA (uint32 va, uint32 dat); -extern void WriteW (uint32 va, uint32 dat); -extern void WriteWA (uint32 va, uint32 dat); -extern void WriteIO (uint32 va, uint32 dat, uint32 map); -extern t_stat iogrp (uint32 ir, uint32 iotrap); -extern uint32 calc_int (void); -extern t_bool calc_defer (void); -extern void mp_dms_jmp (uint32 va, uint32 plb); -extern uint16 dms_rmap (uint32 mapi); -extern void dms_wmap (uint32 mapi, uint32 dat); -extern void dms_viol (uint32 va, uint32 st); -extern uint32 dms_upd_vr (uint32 va); -extern uint32 dms_upd_sr (void); - -#endif +/* hp2100_cpu.h: HP 2100 CPU definitions + + Copyright (c) 2005-2014, Robert M. Supnik + + 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 + ROBERT M SUPNIK 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 Robert M Supnik shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + + 24-Dec-14 JDB Added casts for explicit downward conversions + 18-Mar-13 JDB Added declarations for the MP abort handler and CPU registers + 14-Mar-13 MP Changed guard macro name to avoid reserved namespace + 03-Jan-10 RMS Changed declarations of mp_control, mp_mefvv, for VMS compiler + 15-Jul-08 JDB Rearranged declarations with hp2100_cpu.c and hp2100_defs.h + 26-Jun-08 JDB Added mp_control to CPU state externals + 24-Apr-08 JDB Added calc_defer() prototype + 20-Apr-08 JDB Added DEB_VIS and DEB_SIG debug flags + 26-Nov-07 JDB Added extern sim_deb, cpu_dev, DEB flags for debug printouts + 05-Nov-07 JDB Added extern intaddr, mp_viol, mp_mevff, calc_int, dev_ctl, + ReadIO, WriteIO for RTE-6/VM microcode support + 16-Dec-06 JDB Added UNIT_2115 and UNIT_2114 + 16-Oct-06 JDB Moved ReadF to hp2100_cpu1.c + 26-Sep-06 JDB Added CPU externs for microcode simulators + 16-Aug-06 JDB Added UNIT_EMA for future RTE-4 EMA microcode + Added UNIT_VMA for future RTE-6 VMA and OS microcode + Added UNIT_1000_F for future F-Series support + 09-Aug-06 JDB Added UNIT_DBI for double integer microcode + 21-Jan-05 JDB Reorganized CPU option flags + 14-Jan-05 RMS Cloned from hp2100_cpu.c + + CPU models are broken down into family, type, and series to facilitate option + validation. Bit 3 encodes the family, bit 2 encodes the type, and bits 1:0 + encode the series within the type. +*/ + +#ifndef HP2100_CPU_H_ +#define HP2100_CPU_H_ 0 + +#include + + +/* CPU model definition flags */ + +#define CPU_V_SERIES 0 +#define CPU_V_TYPE 2 +#define CPU_V_FAMILY 3 + +#define FAMILY_21XX (0 << CPU_V_FAMILY) +#define FAMILY_1000 (1 << CPU_V_FAMILY) + +#define TYPE_211X (0 << CPU_V_TYPE) /* 2114, 2115, 2116 */ +#define TYPE_2100 (1 << CPU_V_TYPE) /* 2100A, 2100S */ +#define TYPE_1000MEF (0 << CPU_V_TYPE) /* 1000-M, 1000-E, 1000-F */ +#define TYPE_1000AL (1 << CPU_V_TYPE) /* 1000-L, A600, A700, A900, A990 */ + +#define SERIES_16 (0 << CPU_V_SERIES) /* 211X */ +#define SERIES_15 (1 << CPU_V_SERIES) /* 211X */ +#define SERIES_14 (2 << CPU_V_SERIES) /* 211X */ +#define SERIES_00 (0 << CPU_V_SERIES) /* 2100 */ +#define SERIES_M (0 << CPU_V_SERIES) /* 1000 */ +#define SERIES_E (1 << CPU_V_SERIES) /* 1000 */ +#define SERIES_F (2 << CPU_V_SERIES) /* 1000 */ + +/* CPU unit flags */ + +#define UNIT_M_CPU 017 /* CPU model mask [3:0] */ +#define UNIT_M_TYPE 014 /* CPU type mask [3:2] */ +#define UNIT_M_FAMILY 010 /* CPU family mask [3:3] */ + +#define UNIT_V_CPU (UNIT_V_UF + 0) /* CPU model bits 0-3 */ +#define UNIT_V_EAU (UNIT_V_UF + 4) /* EAU installed */ +#define UNIT_V_FP (UNIT_V_UF + 5) /* FP installed */ +#define UNIT_V_IOP (UNIT_V_UF + 6) /* IOP installed */ +#define UNIT_V_DMS (UNIT_V_UF + 7) /* DMS installed */ +#define UNIT_V_FFP (UNIT_V_UF + 8) /* FFP installed */ +#define UNIT_V_DBI (UNIT_V_UF + 9) /* DBI installed */ +#define UNIT_V_EMA (UNIT_V_UF + 10) /* RTE-4 EMA installed */ +#define UNIT_V_VMAOS (UNIT_V_UF + 11) /* RTE-6 VMA/OS installed */ +#define UNIT_V_VIS (UNIT_V_UF + 12) /* VIS installed */ +#define UNIT_V_SIGNAL (UNIT_V_UF + 13) /* SIGNAL/1000 installed */ +/* Future microcode expansion; reuse flags bottom-up if needed */ +#define UNIT_V_DS (UNIT_V_UF + 14) /* DS installed */ + +/* Unit models */ + +#define UNIT_MODEL_MASK (UNIT_M_CPU << UNIT_V_CPU) + +#define UNIT_2116 ((FAMILY_21XX | TYPE_211X | SERIES_16) << UNIT_V_CPU) +#define UNIT_2115 ((FAMILY_21XX | TYPE_211X | SERIES_15) << UNIT_V_CPU) +#define UNIT_2114 ((FAMILY_21XX | TYPE_211X | SERIES_14) << UNIT_V_CPU) +#define UNIT_2100 ((FAMILY_21XX | TYPE_2100 | SERIES_00) << UNIT_V_CPU) +#define UNIT_1000_M ((FAMILY_1000 | TYPE_1000MEF | SERIES_M) << UNIT_V_CPU) +#define UNIT_1000_E ((FAMILY_1000 | TYPE_1000MEF | SERIES_E) << UNIT_V_CPU) +#define UNIT_1000_F ((FAMILY_1000 | TYPE_1000MEF | SERIES_F) << UNIT_V_CPU) + +/* Unit types */ + +#define UNIT_TYPE_MASK (UNIT_M_TYPE << UNIT_V_CPU) + +#define UNIT_TYPE_211X ((FAMILY_21XX | TYPE_211X) << UNIT_V_CPU) +#define UNIT_TYPE_2100 ((FAMILY_21XX | TYPE_2100) << UNIT_V_CPU) +#define UNIT_TYPE_1000 ((FAMILY_1000 | TYPE_1000MEF) << UNIT_V_CPU) + +/* Unit families */ + +#define UNIT_FAMILY_MASK (UNIT_M_FAMILY << UNIT_V_CPU) + +#define UNIT_FAMILY_21XX (FAMILY_21XX << UNIT_V_CPU) +#define UNIT_FAMILY_1000 (FAMILY_1000 << UNIT_V_CPU) + +/* Unit accessors */ + +#define UNIT_CPU_MODEL (cpu_unit.flags & UNIT_MODEL_MASK) +#define UNIT_CPU_TYPE (cpu_unit.flags & UNIT_TYPE_MASK) +#define UNIT_CPU_FAMILY (cpu_unit.flags & UNIT_FAMILY_MASK) + +#define CPU_MODEL_INDEX (UNIT_CPU_MODEL >> UNIT_V_CPU) + +/* Unit features */ + +#define UNIT_EAU (1 << UNIT_V_EAU) +#define UNIT_FP (1 << UNIT_V_FP) +#define UNIT_IOP (1 << UNIT_V_IOP) +#define UNIT_DMS (1 << UNIT_V_DMS) +#define UNIT_FFP (1 << UNIT_V_FFP) +#define UNIT_DBI (1 << UNIT_V_DBI) +#define UNIT_EMA (1 << UNIT_V_EMA) +#define UNIT_VMAOS (1 << UNIT_V_VMAOS) +#define UNIT_VIS (1 << UNIT_V_VIS) +#define UNIT_DS (1 << UNIT_V_DS) +#define UNIT_SIGNAL (1 << UNIT_V_SIGNAL) + +#define UNIT_EMA_VMA (UNIT_EMA | UNIT_VMAOS) + +#define UNIT_OPTS (UNIT_EAU | UNIT_FP | UNIT_IOP | \ + UNIT_DMS | UNIT_FFP | UNIT_DBI | \ + UNIT_EMA | UNIT_VMAOS | \ + UNIT_VIS | UNIT_DS | UNIT_SIGNAL) + +/* "Pseudo-option" flags used only for option testing; never set into UNIT structure. */ + +#define UNIT_V_PFAIL (UNIT_V_UF - 1) /* Power fail installed */ +#define UNIT_V_DMA (UNIT_V_UF - 2) /* DMA installed */ +#define UNIT_V_MP (UNIT_V_UF - 3) /* Memory protect installed */ + +#define UNIT_PFAIL (1 << UNIT_V_PFAIL) +#define UNIT_DMA (1 << UNIT_V_DMA) +#define UNIT_MP (1 << UNIT_V_MP) + +#define UNIT_NONE 0 /* no options */ + +/* Debug flags */ + +#define DEB_OS (1 << 0) /* RTE-6/VM OS firmware non-TBG processing */ +#define DEB_OSTBG (1 << 1) /* RTE-6/VM OS firmware TBG processing */ +#define DEB_VMA (1 << 2) /* RTE-6/VM VMA firmware instructions */ +#define DEB_EMA (1 << 3) /* RTE-6/VM EMA firmware instructions */ +#define DEB_VIS (1 << 4) /* E/F-Series VIS firmware instructions */ +#define DEB_SIG (1 << 5) /* F-Series SIGNAL/1000 firmware instructions */ + +/* PC queue. */ + +#define PCQ_SIZE 64 /* must be 2**n */ +#define PCQ_MASK (PCQ_SIZE - 1) +#define PCQ_ENTRY pcq[pcq_p = (pcq_p - 1) & PCQ_MASK] = (uint16) err_PC + +/* Memory reference instructions */ + +#define I_IA 0100000 /* indirect address */ +#define I_AB 0004000 /* A/B select */ +#define I_CP 0002000 /* current page */ +#define I_DISP 0001777 /* page displacement */ +#define I_PAGENO 0076000 /* page number */ + +/* Other instructions */ + +#define I_NMRMASK 0172000 /* non-mrf opcode */ +#define I_ASKP 0002000 /* alter/skip */ +#define I_IO 0102000 /* I/O */ +#define I_CTL 0004000 /* CTL on/off */ +#define I_HC 0001000 /* hold/clear */ +#define I_DEVMASK 0000077 /* device select code mask */ +#define I_GETIOOP(x) (((x) >> 6) & 07) /* I/O sub op */ + +/* Instruction masks */ + +#define I_MRG 0074000 /* MRG instructions */ +#define I_MRG_I (I_MRG | I_IA) /* MRG indirect instruction group */ +#define I_JSB 0014000 /* JSB instruction */ +#define I_JSB_I (I_JSB | I_IA) /* JSB,I instruction */ +#define I_JMP 0024000 /* JMP instruction */ +#define I_ISZ 0034000 /* ISZ instruction */ + +#define I_IOG 0107700 /* I/O group instruction */ +#define I_SFS 0102300 /* SFS instruction */ +#define I_STF 0102100 /* STF instruction */ + +/* Memory management */ + +#define VA_N_OFF 10 /* offset width */ +#define VA_M_OFF ((1 << VA_N_OFF) - 1) /* offset mask */ +#define VA_GETOFF(x) ((x) & VA_M_OFF) +#define VA_N_PAG (VA_N_SIZE - VA_N_OFF) /* page width */ +#define VA_V_PAG (VA_N_OFF) /* page offset */ +#define VA_M_PAG ((1 << VA_N_PAG) - 1) /* page mask */ +#define VA_GETPAG(x) (((x) >> VA_V_PAG) & VA_M_PAG) + +/* Maps */ + +#define MAP_NUM 4 /* num maps */ +#define MAP_LNT (1 << VA_N_PAG) /* map length */ +#define MAP_MASK ((MAP_NUM * MAP_LNT) - 1) +#define SMAP 0 /* system map */ +#define UMAP (SMAP + MAP_LNT) /* user map */ +#define PAMAP (UMAP + MAP_LNT) /* port A map */ +#define PBMAP (PAMAP + MAP_LNT) /* port B map */ + +/* DMS map entries */ + +#define MAP_V_RPR 15 /* read prot */ +#define MAP_V_WPR 14 /* write prot */ +#define RDPROT (1 << MAP_V_RPR) /* read access check */ +#define WRPROT (1 << MAP_V_WPR) /* write access check */ +#define NOPROT 0 /* no access check */ +#define MAP_RSVD 0036000 /* reserved bits */ +#define MAP_N_PAG (PA_N_SIZE - VA_N_OFF) /* page width */ +#define MAP_V_PAG (VA_N_OFF) +#define MAP_M_PAG ((1 << MAP_N_PAG) - 1) +#define MAP_GETPAG(x) (((x) & MAP_M_PAG) << MAP_V_PAG) + +/* MEM status register */ + +#define MST_ENBI 0100000 /* MEM enabled at interrupt */ +#define MST_UMPI 0040000 /* User map selected at inerrupt */ +#define MST_ENB 0020000 /* MEM enabled currently */ +#define MST_UMP 0010000 /* User map selected currently */ +#define MST_PRO 0004000 /* Protected mode enabled currently */ +#define MST_FLT 0002000 /* Base page portion mapped */ +#define MST_FENCE 0001777 /* Base page fence */ + +/* MEM violation register */ + +#define MVI_V_RPR 15 /* must be same as */ +#define MVI_V_WPR 14 /* MAP_V_xPR */ +#define MVI_RPR (1 << MVI_V_RPR) /* rd viol */ +#define MVI_WPR (1 << MVI_V_WPR) /* wr viol */ +#define MVI_BPG 0020000 /* base page viol */ +#define MVI_PRV 0010000 /* priv viol */ +#define MVI_MEB 0000200 /* me bus enb @ viol */ +#define MVI_MEM 0000100 /* mem enb @ viol */ +#define MVI_UMP 0000040 /* usr map @ viol */ +#define MVI_PAG 0000037 /* pag sel */ + +/* CPU registers */ + +#define AR ABREG[0] /* A = reg 0 */ +#define BR ABREG[1] /* B = reg 1 */ + +extern uint16 ABREG[2]; /* A/B regs (use AR/BR) */ +extern uint32 PC; /* P register */ +extern uint32 SR; /* S register */ +extern uint32 MR; /* M register */ +extern uint32 TR; /* T register */ +extern uint32 XR; /* X register */ +extern uint32 YR; /* Y register */ +extern uint32 E; /* E register */ +extern uint32 O; /* O register */ + +/* CPU state */ + +extern uint32 err_PC; +extern uint32 dms_enb; +extern uint32 dms_ump; +extern uint32 dms_sr; +extern uint32 dms_vr; +extern FLIP_FLOP mp_control; +extern uint32 mp_fence; +extern uint32 mp_viol; +extern FLIP_FLOP mp_mevff; +extern uint32 iop_sp; +extern t_bool ion_defer; +extern uint32 intaddr; +extern uint16 pcq [PCQ_SIZE]; +extern uint32 pcq_p; +extern uint32 stop_inst; +extern UNIT cpu_unit; +extern DEVICE cpu_dev; +extern REG cpu_reg []; +extern jmp_buf save_env; + + +/* CPU functions */ + +#define MP_ABORT(va) longjmp (save_env, (va)) + +extern t_stat resolve (uint32 MA, uint32 *addr, uint32 irq); +extern uint16 ReadPW (uint32 pa); +extern uint8 ReadB (uint32 va); +extern uint8 ReadBA (uint32 va); +extern uint16 ReadW (uint32 va); +extern uint16 ReadWA (uint32 va); +extern uint16 ReadIO (uint32 va, uint32 map); +extern void WritePW (uint32 pa, uint32 dat); +extern void WriteB (uint32 va, uint32 dat); +extern void WriteBA (uint32 va, uint32 dat); +extern void WriteW (uint32 va, uint32 dat); +extern void WriteWA (uint32 va, uint32 dat); +extern void WriteIO (uint32 va, uint32 dat, uint32 map); +extern t_stat iogrp (uint32 ir, uint32 iotrap); +extern uint32 calc_int (void); +extern t_bool calc_defer (void); +extern void mp_dms_jmp (uint32 va, uint32 plb); +extern uint16 dms_rmap (uint32 mapi); +extern void dms_wmap (uint32 mapi, uint32 dat); +extern void dms_viol (uint32 va, uint32 st); +extern uint32 dms_upd_vr (uint32 va); +extern uint32 dms_upd_sr (void); + +#endif diff --git a/HP2100/hp2100_cpu0.c b/HP2100/hp2100_cpu0.c index 838d2883..2208707e 100644 --- a/HP2100/hp2100_cpu0.c +++ b/HP2100/hp2100_cpu0.c @@ -1,266 +1,271 @@ -/* hp2100_cpu0.c: HP 1000 user microcode and unimplemented instruction set stubs - - Copyright (c) 2006-2010, J. David Bryan - - 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 - THE AUTHOR 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 the author shall not be - used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from the author. - - CPU0 User microcode and unimplemented firmware options - - 04-Nov-10 JDB Removed DS note regarding PIF card (is now implemented) - 18-Sep-08 JDB .FLUN and self-tests for VIS and SIGNAL are NOP if not present - 11-Sep-08 JDB Moved microcode function prototypes to hp2100_cpu1.h - 05-Sep-08 JDB Removed option-present tests (now in UIG dispatchers) - Added "user microcode" dispatcher for unclaimed instructions - 26-Feb-08 HV Removed and implemented "cpu_vis" and "cpu_signal" - 22-Nov-07 JDB Removed and implemented "cpu_rte_ema" - 12-Nov-07 JDB Removed and implemented "cpu_rte_vma" and "cpu_rte_os" - 01-Dec-06 JDB Removed and implemented "cpu_sis". - 26-Sep-06 JDB Created - - Primary references: - - HP 1000 M/E/F-Series Computers Technical Reference Handbook - (5955-0282, Mar-1980) - - HP 1000 M/E/F-Series Computers Engineering and Reference Documentation - (92851-90001, Mar-1981) - - Macro/1000 Reference Manual (92059-90001, Dec-1992) - - Additional references are listed with the associated firmware - implementations, as are the HP option model numbers pertaining to the - applicable CPUs. - - - This file contains template simulations for the firmware options that have - not yet been implemented. When a given firmware option is implemented, it - should be moved out of this file and into another (or its own, depending on - complexity). - - It also contains a user-microprogram dispatcher to allow simulation of - site-specific firmware. All UIG instructions unclaimed by installed firmware - options are directed here and may be simulated by writing the appropriate - code. -*/ - - -#include "hp2100_defs.h" -#include "hp2100_cpu.h" -#include "hp2100_cpu1.h" - - -/* Distributed System. - - Distributed System firmware was provided with the HP 91740A DS/1000 product - for use with the HP 12771A (12665A) Serial Interface and 12773A Modem - Interface system interconnection kits. Firmware permitted high-speed - transfers with minimum impact to the processor. The advent of the - "intelligent" 12794A and 12825A HDLC cards, the 12793A and 12834A Bisync - cards, and the 91750A DS-1000/IV software obviated the need for CPU firmware, - as essentially the firmware was moved onto the I/O cards. - - Primary documentation for the DS instructions has not been located. However, - examination of the DS/1000 sources reveals that two instruction were used by - the DVA65 Serial Interface driver (91740-18071) and placed in the trap cells - of the communications interfaces. Presumably they handled interrupts from - the cards. - - Implementation of the DS instructions will also require simulation of the - 12665A Hardwired Serial Data Interface Card. - - Option implementation by CPU was as follows: - - 2114 2115 2116 2100 1000-M 1000-E 1000-F - ------ ------ ------ ------ ------ ------ ------ - N/A N/A N/A N/A 91740A 91740B 91740B - - The routines are mapped to instruction codes as follows: - - Instr. 1000-M 1000-E/F Description - ------ ------ -------- ---------------------------------------------- - 105520 105300 "Open loop" (trap cell handler) - 105521 105301 "Closed loop" (trap cell handler) - 105522 105302 [unknown] - [test] 105524 105304 [self test] - -- 105310 7974 boot loader ROM extension - - Notes: - - 1. The E/F-Series opcodes were moved from 105340-357 to 105300-317 at - revision 1813. - - 2. DS/1000 ROM data are available from Bitsavers. - - Additional references (documents unavailable): - - HP 91740A M-Series Distributed System (DS/1000) Firmware Installation - Manual (91740-90007). - - HP 91740B Distributed System (DS/1000) Firmware Installation Manual - (91740-90009). -*/ - -static const OP_PAT op_ds[16] = { - OP_N, OP_N, OP_N, OP_N, /* --- --- --- --- */ - OP_N, OP_N, OP_N, OP_N, /* --- --- --- --- */ - OP_N, OP_N, OP_N, OP_N, /* --- --- --- --- */ - OP_N, OP_N, OP_N, OP_N /* --- --- --- --- */ - }; - -t_stat cpu_ds (uint32 IR, uint32 intrq) -{ -t_stat reason = SCPE_OK; -OPS op; -uint32 entry; - -entry = IR & 017; /* mask to entry point */ - -if (op_ds[entry] != OP_N) - if (reason = cpu_ops (op_ds[entry], op, intrq)) /* get instruction operands */ - return reason; - -switch (entry) { /* decode IR<3:0> */ - - default: /* others undefined */ - reason = stop_inst; - } - -return reason; -} - - -/* User firmware dispatcher. - - All UIG instructions unclaimed by installed firmware options are directed - here. User- or site-specific firmware may be simulated by dispatching to the - appropriate simulator routine. Unimplemented instructions should return - "stop_inst" to cause a simulator stop if enabled. - - Implementation notes: - - 1. This routine may be passed any opcode in the ranges 101400-101737 and - 105000-105737. The 10x740-777 range is dedicated to the EIG instructions - and is unavailable for user microprograms. - - 2. HP operating systems and subsystems depend on the following instructions - to execute as NOP and return success if the corresponding firmware is not - installed: - - 105226 -- Fast FORTRAN Processor .FLUN instruction - 105355 -- RTE-6/VM OS self-test instruction - 105477 -- Vector Instruction Set self-test - 105617 -- SIGNAL/1000 self-test - - These instructions are executed to determine firmware configuration - dynamically. If you use any of these opcodes for your own use, be aware - that certain HP programs may fail. - - 3. User microprograms occupied one or more firmware modules, each containing - 16 potential instruction entry points. A skeleton dispatcher for the 32 - possible modules is implemented below, along with a sample module. -*/ - -t_stat cpu_user (uint32 IR, uint32 intrq) -{ -t_stat reason = SCPE_OK; - -if (UNIT_CPU_TYPE == UNIT_TYPE_211X) /* 2116/15/14 CPU? */ - return stop_inst; /* user microprograms not supported */ - -switch (IR) { - case 0105226: /* firmware detection: FFP .FLUN */ - case 0105355: /* firmware detection: RTE-6/VM OS self-test */ - case 0105477: /* firmware detection: VIS self-test */ - case 0105617: /* firmware detection: SIGNAL/1000 self-test */ - return SCPE_OK; /* execute as NOP */ - } - -switch ((IR >> 4) & 037) { /* decode IR<8:4> */ - -/* case 000: /* 105000-105017 */ -/* return cpu_user_00 (IR, intrq); /* uncomment to handle instruction */ - -/* case 001: /* 105020-105037 */ -/* return cpu_user_01 (IR, intrq); /* uncomment to handle instruction */ - -/* case 0nn: /* other cases as needed */ -/* return cpu_user_nn (IR, intrq); /* uncomment to handle instruction */ - - case 020: /* 10x400-10x417 */ - return cpu_user_20 (IR, intrq); /* call sample dispatcher */ - -/* case 021: /* 10x420-10x437 */ -/* return cpu_user_21 (IR, intrq); /* uncomment to handle instruction */ - -/* case 0nn: /* other cases as needed */ -/* return cpu_user_nn (IR, intrq); /* uncomment to handle instruction */ - - default: /* others undefined */ - reason = stop_inst; - } - -return reason; -} - - -/* Example user microprogram simulator. - - User- or site-specific firmware may be simulated by writing the appropriate - code below. Unimplemented instructions should return "stop_inst" to cause a - simulator stop if enabled. - - For information on the operand patterns used in the "op_user" array, see the - comments preceding the "cpu_ops" routine in "hp2100_cpu1.c" and the "operand - processing encoding" constants in "hp2100_cpu1.h". -*/ - -static const OP_PAT op_user_20[16] = { - OP_N, OP_N, OP_N, OP_N, /* --- --- --- --- */ - OP_N, OP_N, OP_N, OP_N, /* --- --- --- --- */ - OP_N, OP_N, OP_N, OP_N, /* --- --- --- --- */ - OP_N, OP_N, OP_N, OP_N /* --- --- --- --- */ - }; - -t_stat cpu_user_20 (uint32 IR, uint32 intrq) -{ -t_stat reason = SCPE_OK; -OPS op; -uint32 entry; - -entry = IR & 017; /* mask to entry point */ - -if (op_user_20 [entry] != OP_N) - if (reason = cpu_ops (op_user_20 [entry], op, intrq)) /* get instruction operands */ - return reason; - -switch (entry) { /* decode IR<4:0> */ - - case 000: /* 10x400 */ -/* break; /* uncomment to handle instruction */ - - case 001: /* 10x401 */ -/* break; /* uncomment to handle instruction */ - -/* case 0nn: /* other cases as needed */ -/* break; /* uncomment to handle instruction */ - - default: /* others undefined */ - reason = stop_inst; - } - -return reason; -} +/* hp2100_cpu0.c: HP 1000 user microcode and unimplemented instruction set stubs + + Copyright (c) 2006-2012, J. David Bryan + + 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 + THE AUTHOR 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 the author shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from the author. + + CPU0 User microcode and unimplemented firmware options + + 09-May-12 JDB Separated assignments from conditional expressions + 04-Nov-10 JDB Removed DS note regarding PIF card (is now implemented) + 18-Sep-08 JDB .FLUN and self-tests for VIS and SIGNAL are NOP if not present + 11-Sep-08 JDB Moved microcode function prototypes to hp2100_cpu1.h + 05-Sep-08 JDB Removed option-present tests (now in UIG dispatchers) + Added "user microcode" dispatcher for unclaimed instructions + 26-Feb-08 HV Removed and implemented "cpu_vis" and "cpu_signal" + 22-Nov-07 JDB Removed and implemented "cpu_rte_ema" + 12-Nov-07 JDB Removed and implemented "cpu_rte_vma" and "cpu_rte_os" + 01-Dec-06 JDB Removed and implemented "cpu_sis". + 26-Sep-06 JDB Created + + Primary references: + - HP 1000 M/E/F-Series Computers Technical Reference Handbook + (5955-0282, Mar-1980) + - HP 1000 M/E/F-Series Computers Engineering and Reference Documentation + (92851-90001, Mar-1981) + - Macro/1000 Reference Manual (92059-90001, Dec-1992) + + Additional references are listed with the associated firmware + implementations, as are the HP option model numbers pertaining to the + applicable CPUs. + + + This file contains template simulations for the firmware options that have + not yet been implemented. When a given firmware option is implemented, it + should be moved out of this file and into another (or its own, depending on + complexity). + + It also contains a user-microprogram dispatcher to allow simulation of + site-specific firmware. All UIG instructions unclaimed by installed firmware + options are directed here and may be simulated by writing the appropriate + code. +*/ + + +#include "hp2100_defs.h" +#include "hp2100_cpu.h" +#include "hp2100_cpu1.h" + + +/* Distributed System. + + Distributed System firmware was provided with the HP 91740A DS/1000 product + for use with the HP 12771A (12665A) Serial Interface and 12773A Modem + Interface system interconnection kits. Firmware permitted high-speed + transfers with minimum impact to the processor. The advent of the + "intelligent" 12794A and 12825A HDLC cards, the 12793A and 12834A Bisync + cards, and the 91750A DS-1000/IV software obviated the need for CPU firmware, + as essentially the firmware was moved onto the I/O cards. + + Primary documentation for the DS instructions has not been located. However, + examination of the DS/1000 sources reveals that two instruction were used by + the DVA65 Serial Interface driver (91740-18071) and placed in the trap cells + of the communications interfaces. Presumably they handled interrupts from + the cards. + + Implementation of the DS instructions will also require simulation of the + 12665A Hardwired Serial Data Interface Card. + + Option implementation by CPU was as follows: + + 2114 2115 2116 2100 1000-M 1000-E 1000-F + ------ ------ ------ ------ ------ ------ ------ + N/A N/A N/A N/A 91740A 91740B 91740B + + The routines are mapped to instruction codes as follows: + + Instr. 1000-M 1000-E/F Description + ------ ------ -------- ---------------------------------------------- + 105520 105300 "Open loop" (trap cell handler) + 105521 105301 "Closed loop" (trap cell handler) + 105522 105302 [unknown] + [test] 105524 105304 [self test] + -- 105310 7974 boot loader ROM extension + + Notes: + + 1. The E/F-Series opcodes were moved from 105340-357 to 105300-317 at + revision 1813. + + 2. DS/1000 ROM data are available from Bitsavers. + + Additional references (documents unavailable): + - HP 91740A M-Series Distributed System (DS/1000) Firmware Installation + Manual (91740-90007). + - HP 91740B Distributed System (DS/1000) Firmware Installation Manual + (91740-90009). +*/ + +static const OP_PAT op_ds[16] = { + OP_N, OP_N, OP_N, OP_N, /* --- --- --- --- */ + OP_N, OP_N, OP_N, OP_N, /* --- --- --- --- */ + OP_N, OP_N, OP_N, OP_N, /* --- --- --- --- */ + OP_N, OP_N, OP_N, OP_N /* --- --- --- --- */ + }; + +t_stat cpu_ds (uint32 IR, uint32 intrq) +{ +t_stat reason = SCPE_OK; +OPS op; +uint32 entry; + +entry = IR & 017; /* mask to entry point */ + +if (op_ds [entry] != OP_N) { + reason = cpu_ops (op_ds[entry], op, intrq); /* get instruction operands */ + if (reason != SCPE_OK) /* did the evaluation fail? */ + return reason; /* return the reason for failure */ + } + +switch (entry) { /* decode IR<3:0> */ + + default: /* others undefined */ + reason = stop_inst; + } + +return reason; +} + + +/* User firmware dispatcher. + + All UIG instructions unclaimed by installed firmware options are directed + here. User- or site-specific firmware may be simulated by dispatching to the + appropriate simulator routine. Unimplemented instructions should return + "stop_inst" to cause a simulator stop if enabled. + + Implementation notes: + + 1. This routine may be passed any opcode in the ranges 101400-101737 and + 105000-105737. The 10x740-777 range is dedicated to the EIG instructions + and is unavailable for user microprograms. + + 2. HP operating systems and subsystems depend on the following instructions + to execute as NOP and return success if the corresponding firmware is not + installed: + + 105226 -- Fast FORTRAN Processor .FLUN instruction + 105355 -- RTE-6/VM OS self-test instruction + 105477 -- Vector Instruction Set self-test + 105617 -- SIGNAL/1000 self-test + + These instructions are executed to determine firmware configuration + dynamically. If you use any of these opcodes for your own use, be aware + that certain HP programs may fail. + + 3. User microprograms occupied one or more firmware modules, each containing + 16 potential instruction entry points. A skeleton dispatcher for the 32 + possible modules is implemented below, along with a sample module. +*/ + +t_stat cpu_user (uint32 IR, uint32 intrq) +{ +t_stat reason = SCPE_OK; + +if (UNIT_CPU_TYPE == UNIT_TYPE_211X) /* 2116/15/14 CPU? */ + return stop_inst; /* user microprograms not supported */ + +switch (IR) { + case 0105226: /* firmware detection: FFP .FLUN */ + case 0105355: /* firmware detection: RTE-6/VM OS self-test */ + case 0105477: /* firmware detection: VIS self-test */ + case 0105617: /* firmware detection: SIGNAL/1000 self-test */ + return SCPE_OK; /* execute as NOP */ + } + +switch ((IR >> 4) & 037) { /* decode IR<8:4> */ + +/* case 000: ** 105000-105017 */ +/* return cpu_user_00 (IR, intrq); ** uncomment to handle instruction */ + +/* case 001: ** 105020-105037 */ +/* return cpu_user_01 (IR, intrq); ** uncomment to handle instruction */ + +/* case 0nn: ** other cases as needed */ +/* return cpu_user_nn (IR, intrq); ** uncomment to handle instruction */ + + case 020: /* 10x400-10x417 */ + return cpu_user_20 (IR, intrq); /* call sample dispatcher */ + +/* case 021: ** 10x420-10x437 */ +/* return cpu_user_21 (IR, intrq); ** uncomment to handle instruction */ + +/* case 0nn: ** other cases as needed */ +/* return cpu_user_nn (IR, intrq); ** uncomment to handle instruction */ + + default: /* others undefined */ + reason = stop_inst; + } + +return reason; +} + + +/* Example user microprogram simulator. + + User- or site-specific firmware may be simulated by writing the appropriate + code below. Unimplemented instructions should return "stop_inst" to cause a + simulator stop if enabled. + + For information on the operand patterns used in the "op_user" array, see the + comments preceding the "cpu_ops" routine in "hp2100_cpu1.c" and the "operand + processing encoding" constants in "hp2100_cpu1.h". +*/ + +static const OP_PAT op_user_20[16] = { + OP_N, OP_N, OP_N, OP_N, /* --- --- --- --- */ + OP_N, OP_N, OP_N, OP_N, /* --- --- --- --- */ + OP_N, OP_N, OP_N, OP_N, /* --- --- --- --- */ + OP_N, OP_N, OP_N, OP_N /* --- --- --- --- */ + }; + +t_stat cpu_user_20 (uint32 IR, uint32 intrq) +{ +t_stat reason = SCPE_OK; +OPS op; +uint32 entry; + +entry = IR & 017; /* mask to entry point */ + +if (op_user_20 [entry] != OP_N) { + reason = cpu_ops (op_user_20 [entry], op, intrq); /* get instruction operands */ + if (reason != SCPE_OK) /* did the evaluation fail? */ + return reason; /* return the reason for failure */ + } + +switch (entry) { /* decode IR<4:0> */ + + case 000: /* 10x400 */ +/* break; ** uncomment to handle instruction */ + + case 001: /* 10x401 */ +/* break; ** uncomment to handle instruction */ + +/* case 0nn: ** other cases as needed */ +/* break; ** uncomment to handle instruction */ + + default: /* others undefined */ + reason = stop_inst; + } + +return reason; +} diff --git a/HP2100/hp2100_cpu1.c b/HP2100/hp2100_cpu1.c index d176db83..4bfa632e 100644 --- a/HP2100/hp2100_cpu1.c +++ b/HP2100/hp2100_cpu1.c @@ -1,918 +1,928 @@ -/* hp2100_cpu1.c: HP 2100/1000 EAU simulator and UIG dispatcher - - Copyright (c) 2005-2008, Robert M. Supnik - - 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 - ROBERT M SUPNIK 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 Robert M Supnik shall not be - used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from Robert M Supnik. - - CPU1 Extended arithmetic and optional microcode dispatchers - - 11-Sep-08 JDB Moved microcode function prototypes to hp2100_cpu1.h - 05-Sep-08 JDB Moved option-present tests to UIG dispatchers - Call "user microcode" dispatcher for unclaimed UIG instructions - 20-Apr-08 JDB Fixed VIS and SIGNAL to depend on the FPP and HAVE_INT64 - 28-Nov-07 JDB Added fprint_ops, fprint_regs for debug printouts - 17-Nov-07 JDB Enabled DIAG as NOP on 1000 F-Series - 04-Jan-07 JDB Added special DBI dispatcher for non-INT64 diagnostic - 29-Dec-06 JDB Allows RRR as NOP if 2114 (diag config test) - 01-Dec-06 JDB Substitutes FPP for firmware FP if HAVE_INT64 - 16-Oct-06 JDB Generalized operands for F-Series FP types - 26-Sep-06 JDB Split hp2100_cpu1.c into multiple modules to simplify extensions - Added iotrap parameter to UIG dispatchers for RTE microcode - 22-Feb-05 JDB Removed EXECUTE instruction (is NOP in actual microcode) - 21-Jan-05 JDB Reorganized CPU option and operand processing flags - Split code along microcode modules - 15-Jan-05 RMS Cloned from hp2100_cpu.c - - Primary references: - - HP 1000 M/E/F-Series Computers Technical Reference Handbook - (5955-0282, Mar-1980) - - HP 1000 M/E/F-Series Computers Engineering and Reference Documentation - (92851-90001, Mar-1981) - - Macro/1000 Reference Manual (92059-90001, Dec-1992) - - HP 93585A Double Integer Firmware Package Installation and Programming - Manual (93585-90007, Feb-1984) - - Additional references are listed with the associated firmware - implementations, as are the HP option model numbers pertaining to the - applicable CPUs. - - - This source file contains the Extended Arithmetic Unit simulator and the User - Instruction Group (a.k.a. "Macro") dispatcher for the 2100 and 1000 (21MX) - CPUs. The UIG simulators reside in separate source files, due to the large - number of firmware options available for these machines. Unit flags indicate - which options are present in the current system. - - This module also provides generalized instruction operand processing. - - The 2100 and 1000 machines were microprogrammable; the 2116/15/14 machines - were not. Both user- and HP-written microprograms were supported. The - microcode address space of the 2100 encompassed four modules of 256 words - each. The 1000 M-series expanded that to sixteen modules, and the 1000 - E/F-series expanded that still further to sixty-four modules. Each CPU had - its own microinstruction set, although the micromachines of the various 1000 - models were similar internally. - - The UIG instructions were divided into ranges assigned to HP firmware - options, reserved for future HP use, and reserved for user microprograms. - User microprograms could occupy any range not already used on a given - machine, but in practice, some effort was made to avoid the HP-reserved - ranges. - - User microprogram simulation is supported by routing any UIG instruction not - allocated to an installed firmware option to a user-firmware dispatcher. - Site-specific microprograms may be simulated there. In the absence of such a - simulation, an unimplemented instruction stop will occur. - - Regarding option instruction sets, there was some commonality across CPU - types. EAU instructions were identical across all models, and the floating - point set was the same on the 2100 and 1000. Other options implemented - proper instruction supersets (e.g., the Fast FORTRAN Processor from 2100 to - 1000-M to 1000-E to 1000-F) or functional equivalence with differing code - points (the 2000 I/O Processor from 2100 to 1000, and the extended-precision - floating-point instructions from 1000-E to 1000-F). - - The 2100 decoded the EAU and UIG sets separately in hardware and supported - only the UIG 0 code points. Bits 7-4 of a UIG instruction decoded one of - sixteen entry points in the lowest-numbered module after module 0. Those - entry points could be used directly (as for the floating-point instructions), - or additional decoding based on bits 3-0 could be implemented. - - The 1000 generalized the instruction decoding to a series of microcoded - jumps, based on the bits in the instruction. Bits 15-8 indicated the group - of the current instruction: EAU (200, 201, 202, 210, and 211), UIG 0 (212), - or UIG 1 (203 and 213). UIG 0, UIG 1, and some EAU instructions were decoded - further by selecting one of sixteen modules within the group via bits 7-4. - Finally, each UIG module decoded up to sixteen instruction entry points via - bits 3-0. Jump tables for all firmware options were contained in the base - set, so modules needed only to be concerned with decoding their individual - entry points within the module. - - While the 2100 and 1000 hardware decoded these instruction sets differently, - the decoding mechanism of the simulation follows that of the 1000 E/F-series. - Where needed, CPU type- or model-specific behavior is simulated. - - The design of the 1000 microinstruction set was such that executing an - instruction for which no microcode was present (e.g., executing a FFP - instruction when the FFP firmware was not installed) resulted in a NOP. - Under simulation, such execution causes an undefined instruction stop if - "stop_inst" is non-zero and a NOP otherwise. -*/ - - -#include "hp2100_defs.h" -#include "hp2100_cpu.h" -#include "hp2100_cpu1.h" - - -/* EAU - - The Extended Arithmetic Unit (EAU) adds ten instructions with double-word - operands, including multiply, divide, shifts, and rotates. Option - implementation by CPU was as follows: - - 2114 2115 2116 2100 1000-M 1000-E 1000-F - ------ ------ ------ ------ ------ ------ ------ - N/A 12579A 12579A std std std std - - The instruction codes are mapped to routines as follows: - - Instr. Bits - Code 15-8 7-4 2116 2100 1000-M 1000-E 1000-F Note - ------ ---- --- ------ ------ ------ ------ ------ --------------------- - 100000 200 00 [diag] [diag] [self test] - 100020 200 01 ASL ASL ASL ASL ASL Bits 3-0 encode shift - 100040 200 02 LSL LSL LSL LSL LSL Bits 3-0 encode shift - 100060 200 03 TIMER TIMER [deterministic delay] - 100100 200 04 RRL RRL RRL RRL RRL Bits 3-0 encode shift - 100200 200 10 MPY MPY MPY MPY MPY - 100400 201 xx DIV DIV DIV DIV DIV - 101020 202 01 ASR ASR ASR ASR ASR Bits 3-0 encode shift - 101040 202 02 LSR LSR LSR LSR LSR Bits 3-0 encode shift - 101100 202 04 RRR RRR RRR RRR RRR Bits 3-0 encode shift - 104200 210 xx DLD DLD DLD DLD DLD - 104400 211 xx DST DST DST DST DST - - The remaining codes for bits 7-4 are undefined and will cause a simulator - stop if enabled. On a real 1000-M, all undefined instructions in the 200 - group decode as MPY, and all in the 202 group decode as NOP. On a real - 1000-E, instruction patterns 200/05 through 200/07 and 202/03 decode as NOP; - all others cause erroneous execution. - - EAU instruction decoding on the 1000 M-series is convoluted. The JEAU - microorder maps IR bits 11, 9-7 and 5-4 to bits 2-0 of the microcode jump - address. The map is detailed on page IC-84 of the ERD. - - The 1000 E/F-series add two undocumented instructions to the 200 group: TIMER - and DIAG. These are described in the ERD on page IA 5-5, paragraph 5-7. The - M-series executes these as MPY and RRL, respectively. A third instruction, - EXECUTE (100120), is also described but was never implemented, and the - E/F-series microcode execute a NOP for this instruction code. - - Notes: - - 1. Under simulation, TIMER, DIAG, and EXECUTE cause undefined instruction - stops if the CPU is set to 21xx. DIAG and EXECUTE also cause stops on - the 1000-M. TIMER does not, because it is used by several HP programs - to differentiate between M- and E/F-series machines. - - 2. DIAG is not implemented under simulation. On the E/F, it performs a - destructive test of all installed memory. Because of this, it is only - functional if the machine is halted, i.e., if the instruction is - executed with the INSTR STEP button. If it is executed in a program, - the result is NOP. - - 3. RRR is permitted and executed as NOP if the CPU is a 2114, as the - presence of the EAU is tested by the diagnostic configurator to - differentiate between 2114 and 2100/1000 CPUs. -*/ - -t_stat cpu_eau (uint32 IR, uint32 intrq) -{ -t_stat reason = SCPE_OK; -OPS op; -uint32 rs, qs, sc, v1, v2, t; -int32 sop1, sop2; - -if ((cpu_unit.flags & UNIT_EAU) == 0) /* option installed? */ - if ((UNIT_CPU_MODEL == UNIT_2114) && (IR == 0101100)) /* 2114 and RRR 16? */ - return SCPE_OK; /* allowed as NOP */ - else - return stop_inst; /* fail */ - -switch ((IR >> 8) & 0377) { /* decode IR<15:8> */ - - case 0200: /* EAU group 0 */ - switch ((IR >> 4) & 017) { /* decode IR<7:4> */ - - case 000: /* DIAG 100000 */ - if ((UNIT_CPU_MODEL != UNIT_1000_E) && /* must be 1000 E-series */ - (UNIT_CPU_MODEL != UNIT_1000_F)) /* or 1000 F-series */ - return stop_inst; /* trap if not */ - break; /* DIAG is NOP unless halted */ - - case 001: /* ASL 100020-100037 */ - sc = (IR & 017)? (IR & 017): 16; /* get sc */ - O = 0; /* clear ovflo */ - while (sc-- != 0) { /* bit by bit */ - t = BR << 1; /* shift B */ - BR = (BR & SIGN) | (t & 077777) | (AR >> 15); - AR = (AR << 1) & DMASK; - if ((BR ^ t) & SIGN) O = 1; - } - break; - - case 002: /* LSL 100040-100057 */ - sc = (IR & 017)? (IR & 017): 16; /* get sc */ - BR = ((BR << sc) | (AR >> (16 - sc))) & DMASK; - AR = (AR << sc) & DMASK; /* BR'AR lsh left */ - break; - - case 003: /* TIMER 100060 */ - if (UNIT_CPU_TYPE != UNIT_TYPE_1000) /* must be 1000 */ - return stop_inst; /* trap if not */ - if (UNIT_CPU_MODEL == UNIT_1000_M) /* 1000 M-series? */ - goto MPY; /* decode as MPY */ - BR = (BR + 1) & DMASK; /* increment B */ - if (BR) PC = err_PC; /* if !=0, repeat */ - break; - - case 004: /* RRL 100100-100117 */ - sc = (IR & 017)? (IR & 017): 16; /* get sc */ - t = BR; /* BR'AR rot left */ - BR = ((BR << sc) | (AR >> (16 - sc))) & DMASK; - AR = ((AR << sc) | (t >> (16 - sc))) & DMASK; - break; - - case 010: /* MPY 100200 (OP_K) */ - MPY: - if (reason = cpu_ops (OP_K, op, intrq)) /* get operand */ - break; - sop1 = SEXT (AR); /* sext AR */ - sop2 = SEXT (op[0].word); /* sext mem */ - sop1 = sop1 * sop2; /* signed mpy */ - BR = (sop1 >> 16) & DMASK; /* to BR'AR */ - AR = sop1 & DMASK; - O = 0; /* no overflow */ - break; - - default: /* others undefined */ - return stop_inst; - } - - break; - - case 0201: /* DIV 100400 (OP_K) */ - if (reason = cpu_ops (OP_K, op, intrq)) /* get operand */ - break; - if (rs = qs = BR & SIGN) { /* save divd sign, neg? */ - AR = (~AR + 1) & DMASK; /* make B'A pos */ - BR = (~BR + (AR == 0)) & DMASK; /* make divd pos */ - } - v2 = op[0].word; /* divr = mem */ - if (v2 & SIGN) { /* neg? */ - v2 = (~v2 + 1) & DMASK; /* make divr pos */ - qs = qs ^ SIGN; /* sign of quotient */ - } - if (BR >= v2) O = 1; /* divide work? */ - else { /* maybe... */ - O = 0; /* assume ok */ - v1 = (BR << 16) | AR; /* 32b divd */ - AR = (v1 / v2) & DMASK; /* quotient */ - BR = (v1 % v2) & DMASK; /* remainder */ - if (AR) { /* quotient > 0? */ - if (qs) AR = (~AR + 1) & DMASK; /* apply quo sign */ - if ((AR ^ qs) & SIGN) O = 1; /* still wrong? ovflo */ - } - if (rs) BR = (~BR + 1) & DMASK; /* apply rem sign */ - } - break; - - case 0202: /* EAU group 2 */ - switch ((IR >> 4) & 017) { /* decode IR<7:4> */ - - case 001: /* ASR 101020-101037 */ - sc = (IR & 017)? (IR & 017): 16; /* get sc */ - AR = ((BR << (16 - sc)) | (AR >> sc)) & DMASK; - BR = (SEXT (BR) >> sc) & DMASK; /* BR'AR ash right */ - O = 0; - break; - - case 002: /* LSR 101040-101057 */ - sc = (IR & 017)? (IR & 017): 16; /* get sc */ - AR = ((BR << (16 - sc)) | (AR >> sc)) & DMASK; - BR = BR >> sc; /* BR'AR log right */ - break; - - case 004: /* RRR 101100-101117 */ - sc = (IR & 017)? (IR & 017): 16; /* get sc */ - t = AR; /* BR'AR rot right */ - AR = ((AR >> sc) | (BR << (16 - sc))) & DMASK; - BR = ((BR >> sc) | (t << (16 - sc))) & DMASK; - break; - - default: /* others undefined */ - return stop_inst; - } - - break; - - case 0210: /* DLD 104200 (OP_D) */ - if (reason = cpu_ops (OP_D, op, intrq)) /* get operand */ - break; - AR = (op[0].dword >> 16) & DMASK; /* load AR */ - BR = op[0].dword & DMASK; /* load BR */ - break; - - case 0211: /* DST 104400 (OP_A) */ - if (reason = cpu_ops (OP_A, op, intrq)) /* get operand */ - break; - WriteW (op[0].word, AR); /* store AR */ - WriteW ((op[0].word + 1) & VAMASK, BR); /* store BR */ - break; - - default: /* should never get here */ - return SCPE_IERR; /* bad call from cpu_instr */ - } - -return reason; -} - - -/* UIG 0 - - The first User Instruction Group (UIG) encodes firmware options for the 2100 - and 1000. Instruction codes 105000-105377 are assigned to microcode options - as follows: - - Instructions Option Name 2100 1000-M 1000-E 1000-F - ------------- -------------------------- ------ ------ ------ ------ - 105000-105362 2000 I/O Processor opt - - - - 105000-105137 Floating Point opt std std std - 105200-105237 Fast FORTRAN Processor opt opt opt std - 105240-105257 RTE-IVA/B Extended Memory - - opt opt - 105240-105257 RTE-6/VM Virtual Memory - - opt opt - 105300-105317 Distributed System - - opt opt - 105320-105337 Double Integer - - opt - - 105320-105337 Scientific Instruction Set - - - std - 105340-105357 RTE-6/VM Operating System - - opt opt - - If the 2100 IOP is installed, the only valid UIG instructions are IOP - instructions, as the IOP used the full 2100 microcode addressing space. The - IOP dispatcher remaps the 2100 codes to 1000 codes for execution. - - The F-Series moved the three-word extended real instructions from the FFP - range to the base floating-point range and added four-word double real and - two-word double integer instructions. The double integer instructions - occupied some of the vacated extended real instruction codes in the FFP, with - the rest assigned to the floating-point range. Consequently, many - instruction codes for the F-Series are different from the E-Series. - - Implementation notes: - - 1. Product 93585A, available from the "Specials" group, added double integer - microcode to the E-Series. The instruction codes were different from - those in the F-Series to avoid conflicting with the E-Series FFP. - - 2. To run the double-integer instructions diagnostic in the absence of - 64-bit integer support (and therefore of F-Series simulation), a special - DBI dispatcher may be enabled by defining ENABLE_DIAG during compilation. - This dispatcher will remap the F-Series DBI instructions to the E-Series - codes, so that the F-Series diagnostic may be run. Because several of - the F-Series DBI instruction codes replace M/E-Series FFP codes, this - dispatcher will only operate if FFP is disabled. - - Note that enabling the dispatcher will produce non-standard FP behavior. - For example, any code in the range 105000-105017 normally would execute a - FAD instruction. With the dispatcher enabled, 105014 would execute a - .DAD, while the other codes would execute a FAD. Therefore, ENABLE_DIAG - should only be used to run the diagnostic and is not intended for general - use. - - 3. Any instruction not claimed by an installed option will be sent to the - user microcode dispatcher. -*/ - -t_stat cpu_uig_0 (uint32 IR, uint32 intrq, uint32 iotrap) -{ -if ((cpu_unit.flags & UNIT_IOP) && /* I/O Processor? */ - (UNIT_CPU_TYPE == UNIT_TYPE_2100)) /* and 2100 CPU? */ - return cpu_iop (IR, intrq); /* dispatch to IOP */ - - -#if !defined (HAVE_INT64) && defined (ENABLE_DIAG) /* special DBI diagnostic dispatcher */ - -if (((cpu_unit.flags & UNIT_FFP) == 0) && /* FFP absent? */ - (cpu_unit.flags & UNIT_DBI)) /* and DBI present? */ - switch (IR & 0377) { - case 0014: /* .DAD 105014 */ - return cpu_dbi (0105321, intrq); - - case 0034: /* .DSB 105034 */ - return cpu_dbi (0105327, intrq); - - case 0054: /* .DMP 105054 */ - return cpu_dbi (0105322, intrq); - - case 0074: /* .DDI 105074 */ - return cpu_dbi (0105325, intrq); - - case 0114: /* .DSBR 105114 */ - return cpu_dbi (0105334, intrq); - - case 0134: /* .DDIR 105134 */ - return cpu_dbi (0105326, intrq); - - case 0203: /* .DNG 105203 */ - return cpu_dbi (0105323, intrq); - - case 0204: /* .DCO 105204 */ - return cpu_dbi (0105324, intrq); - - case 0210: /* .DIN 105210 */ - return cpu_dbi (0105330, intrq); - - case 0211: /* .DDE 105211 */ - return cpu_dbi (0105331, intrq); - - case 0212: /* .DIS 105212 */ - return cpu_dbi (0105332, intrq); - - case 0213: /* .DDS 105213 */ - return cpu_dbi (0105333, intrq); - } /* otherwise, continue */ - -#endif /* end of special DBI dispatcher */ - - -switch ((IR >> 4) & 017) { /* decode IR<7:4> */ - - case 000: /* 105000-105017 */ - case 001: /* 105020-105037 */ - case 002: /* 105040-105057 */ - case 003: /* 105060-105077 */ - case 004: /* 105100-105117 */ - case 005: /* 105120-105137 */ - if (cpu_unit.flags & UNIT_FP) /* FP option installed? */ -#if defined (HAVE_INT64) /* int64 support available */ - return cpu_fpp (IR, intrq); /* Floating Point Processor */ -#else /* int64 support unavailable */ - return cpu_fp (IR, intrq); /* Firmware Floating Point */ -#endif /* end of int64 support */ - else - break; - - case 010: /* 105200-105217 */ - case 011: /* 105220-105237 */ - if (cpu_unit.flags & UNIT_FFP) /* FFP option installed? */ - return cpu_ffp (IR, intrq); /* Fast FORTRAN Processor */ - else - break; - - case 012: /* 105240-105257 */ - if (cpu_unit.flags & UNIT_VMAOS) /* VMA/OS option installed? */ - return cpu_rte_vma (IR, intrq); /* RTE-6 VMA */ - else if (cpu_unit.flags & UNIT_EMA) /* EMA option installed? */ - return cpu_rte_ema (IR, intrq); /* RTE-4 EMA */ - else - break; - - case 014: /* 105300-105317 */ - if (cpu_unit.flags & UNIT_DS) /* DS option installed? */ - return cpu_ds (IR, intrq); /* Distributed System */ - else - break; - - case 015: /* 105320-105337 */ -#if defined (HAVE_INT64) /* int64 support available */ - if (UNIT_CPU_MODEL == UNIT_1000_F) /* F-series? */ - return cpu_sis (IR, intrq); /* Scientific Instruction is standard */ - else /* M/E-series */ -#endif /* end of int64 support */ - if (cpu_unit.flags & UNIT_DBI) /* DBI option installed? */ - return cpu_dbi (IR, intrq); /* Double integer */ - else - break; - - case 016: /* 105340-105357 */ - if (cpu_unit.flags & UNIT_VMAOS) /* VMA/OS option installed? */ - return cpu_rte_os (IR, intrq, iotrap); /* RTE-6 OS */ - else - break; - } - -return cpu_user (IR, intrq); /* try user microcode */ -} - - -/* UIG 1 - - The second User Instruction Group (UIG) encodes firmware options for the - 1000. Instruction codes 101400-101777 and 105400-105777 are assigned to - microcode options as follows ("x" is "1" or "5" below): - - Instructions Option Name 1000-M 1000-E 1000-F - ------------- ---------------------------- ------ ------ ------ - 10x400-10x437 2000 IOP opt opt opt - 10x460-10x477 2000 IOP opt opt opt - 10x460-10x477 Vector Instruction Set - - opt - 10x520-10x537 Distributed System opt - - - 10x600-10x617 SIGNAL/1000 Instruction Set - - opt - 10x700-10x737 Dynamic Mapping System opt opt std - 10x740-10x777 Extended Instruction Group std std std - - Only 1000 systems execute these instructions. - - Implementation notes: - - 1. The Distributed System (DS) microcode was mapped to different instruction - ranges for the M-Series and the E/F-Series. The sequence of instructions - was identical, though, so we remap the former range to the latter before - dispatching. - - 2. Any instruction not claimed by an installed option will be sent to the - user microcode dispatcher. -*/ - -t_stat cpu_uig_1 (uint32 IR, uint32 intrq, uint32 iotrap) -{ -if (UNIT_CPU_TYPE != UNIT_TYPE_1000) /* 1000 execution? */ - return stop_inst; /* no, so trap */ - -switch ((IR >> 4) & 017) { /* decode IR<7:4> */ - - case 000: /* 105400-105417 */ - case 001: /* 105420-105437 */ - if (cpu_unit.flags & UNIT_IOP) /* IOP option installed? */ - return cpu_iop (IR, intrq); /* 2000 I/O Processor */ - else - break; - - case 003: /* 105460-105477 */ -#if defined (HAVE_INT64) /* int64 support available */ - if (cpu_unit.flags & UNIT_VIS) /* VIS option installed? */ - return cpu_vis (IR, intrq); /* Vector Instruction Set */ - else -#endif /* end of int64 support */ - if (cpu_unit.flags & UNIT_IOP) /* IOP option installed? */ - return cpu_iop (IR, intrq); /* 2000 I/O Processor */ - else - break; - - case 005: /* 105520-105537 */ - if (cpu_unit.flags & UNIT_DS) { /* DS option installed? */ - IR = IR ^ 0000620; /* remap to 105300-105317 */ - return cpu_ds (IR, intrq); /* Distributed System */ - } - else - break; - -#if defined (HAVE_INT64) /* int64 support available */ - case 010: /* 105600-105617 */ - if (cpu_unit.flags & UNIT_SIGNAL) /* SIGNAL option installed? */ - return cpu_signal (IR, intrq); /* SIGNAL/1000 Instructions */ - else - break; -#endif /* end of int64 support */ - - case 014: /* 105700-105717 */ - case 015: /* 105720-105737 */ - if (cpu_unit.flags & UNIT_DMS) /* DMS option installed? */ - return cpu_dms (IR, intrq); /* Dynamic Mapping System */ - else - break; - - case 016: /* 105740-105757 */ - case 017: /* 105760-105777 */ - return cpu_eig (IR, intrq); /* Extended Instruction Group */ - } - -return cpu_user (IR, intrq); /* try user microcode */ -} - - -/* Read a multiple-precision operand value. */ - -OP ReadOp (uint32 va, OPSIZE precision) -{ -OP operand; -uint32 i; - -if (precision == in_s) - operand.word = ReadW (va); /* read single integer */ - -else if (precision == in_d) - operand.dword = ReadW (va) << 16 | /* read double integer */ - ReadW ((va + 1) & VAMASK); /* merge high and low words */ - -else - for (i = 0; i < (uint32) precision; i++) { /* read fp 2 to 5 words */ - operand.fpk[i] = ReadW (va); - va = (va + 1) & VAMASK; - } -return operand; -} - -/* Write a multiple-precision operand value. */ - -void WriteOp (uint32 va, OP operand, OPSIZE precision) -{ -uint32 i; - -if (precision == in_s) - WriteW (va, operand.word); /* write single integer */ - -else if (precision == in_d) { - WriteW (va, (operand.dword >> 16) & DMASK); /* write double integer */ - WriteW ((va + 1) & VAMASK, operand.dword & DMASK); /* high word, then low word */ - } - -else - for (i = 0; i < (uint32) precision; i++) { /* write fp 2 to 5 words */ - WriteW (va, operand.fpk[i]); - va = (va + 1) & VAMASK; - } -return; -} - - -/* Get instruction operands. - - Operands for a given instruction are specifed by an "operand pattern" - consisting of flags indicating the types and storage methods. The pattern - directs how each operand is to be retrieved and whether the operand value or - address is returned in the operand array. - - Typically, a microcode simulation handler will define an OP_PAT array, with - each element containing an operand pattern corresponding to the simulated - instruction. Operand patterns are defined in the header file accompanying - this source file. After calling this function with the appropriate operand - pattern and a pointer to an array of OPs, operands are decoded and stored - sequentially in the array. - - The following operand encodings are defined: - - Code Operand Description Example Return - ------ ---------------------------------------- ----------- ------------ - OP_NUL No operand present [inst] None - - OP_IAR Integer constant in A register LDA I Value of I - [inst] - ... - I DEC 0 - - OP_DAB Double integer constant in A/B registers DLD J Value of J - [inst] - ... - J DEC 0,0 - - OP_FAB 2-word FP constant in A/B registers DLD F Value of F - [inst] - ... - F DEC 0.0 - - OP_CON Inline 1-word constant [inst] Value of C - C DEC 0 - ... - - OP_VAR Inline 1-word variable [inst] Address of V - V BSS 1 - ... - - OP_ADR Inline address [inst] Address of A - DEF A - ... - A EQU * - - OP_ADK Address of integer constant [inst] Value of K - DEF K - ... - K DEC 0 - - OP_ADD Address of double integer constant [inst] Value of D - DEF D - ... - D DEC 0,0 - - OP_ADF Address of 2-word FP constant [inst] Value of F - DEF F - ... - F DEC 0.0 - - OP_ADX Address of 3-word FP constant [inst] Value of X - DEF X - ... - X DEX 0.0 - - OP_ADT Address of 4-word FP constant [inst] Value of T - DEF T - ... - T DEY 0.0 - - OP_ADE Address of 5-word FP constant [inst] Value of E - DEF E - ... - E DEC 0,0,0,0,0 - - Address operands, i.e., those having a DEF to the operand, will be resolved - to direct addresses. If an interrupt is pending and more than three levels - of indirection are used, the routine returns without completing operand - retrieval (the instruction will be retried after interrupt servicing). - Addresses are always resolved in the current DMS map. - - An operand pattern consists of one or more operand encodings, corresponding - to the operands required by a given instruction. Values are returned in - sequence to the operand array. -*/ - -t_stat cpu_ops (OP_PAT pattern, OPS op, uint32 irq) -{ -t_stat reason = SCPE_OK; -OP_PAT flags; -uint32 i, MA; - -for (i = 0; i < OP_N_F; i++) { - flags = pattern & OP_M_FLAGS; /* get operand pattern */ - - if (flags >= OP_ADR) /* address operand? */ - if (reason = resolve (ReadW (PC), &MA, irq)) /* resolve indirects */ - return reason; - - switch (flags) { - case OP_NUL: /* null operand */ - return reason; /* no more, so quit */ - - case OP_IAR: /* int in A */ - (*op++).word = AR; /* get one-word value */ - break; - - case OP_JAB: /* dbl-int in A/B */ - (*op++).dword = (AR << 16) | BR; /* get two-word value */ - break; - - case OP_FAB: /* 2-word FP in A/B */ - (*op).fpk[0] = AR; /* get high FP word */ - (*op++).fpk[1] = BR; /* get low FP word */ - break; - - case OP_CON: /* inline constant operand */ - *op++ = ReadOp (PC, in_s); /* get value */ - break; - - case OP_VAR: /* inline variable operand */ - (*op++).word = PC; /* get pointer to variable */ - break; - - case OP_ADR: /* inline address operand */ - (*op++).word = MA; /* get address */ - break; - - case OP_ADK: /* address of int constant */ - *op++ = ReadOp (MA, in_s); /* get value */ - break; - - case OP_ADD: /* address of dbl-int constant */ - *op++ = ReadOp (MA, in_d); /* get value */ - break; - - case OP_ADF: /* address of 2-word FP const */ - *op++ = ReadOp (MA, fp_f); /* get value */ - break; - - case OP_ADX: /* address of 3-word FP const */ - *op++ = ReadOp (MA, fp_x); /* get value */ - break; - - case OP_ADT: /* address of 4-word FP const */ - *op++ = ReadOp (MA, fp_t); /* get value */ - break; - - case OP_ADE: /* address of 5-word FP const */ - *op++ = ReadOp (MA, fp_e); /* get value */ - break; - - default: - return SCPE_IERR; /* not implemented */ - } - - if (flags >= OP_CON) /* operand after instruction? */ - PC = (PC + 1) & VAMASK; /* yes, so bump to next */ - pattern = pattern >> OP_N_FLAGS; /* move next pattern into place */ - } -return reason; -} - - -/* Print operands to the debug device. - - The values of an operand array are printed to the debug device. The types of - the operands are specified by an operand pattern. Typically, the operand - pattern is the same one that was used to fill the array originally. -*/ - -void fprint_ops (OP_PAT pattern, OPS op) -{ -OP_PAT flags; -uint32 i; - -for (i = 0; i < OP_N_F; i++) { - flags = pattern & OP_M_FLAGS; /* get operand pattern */ - - switch (flags) { - case OP_NUL: /* null operand */ - return; /* no more, so quit */ - - case OP_IAR: /* int in A */ - case OP_CON: /* inline constant operand */ - case OP_VAR: /* inline variable operand */ - case OP_ADR: /* inline address operand */ - case OP_ADK: /* address of int constant */ - fprintf (sim_deb, - ", op[%d] = %06o", - i, op[i].word); - break; - - case OP_JAB: /* dbl-int in A/B */ - case OP_ADD: /* address of dbl-int constant */ - fprintf (sim_deb, - ", op[%d] = %011o", - i, op[i].dword); - break; - - case OP_FAB: /* 2-word FP in A/B */ - case OP_ADF: /* address of 2-word FP const */ - fprintf (sim_deb, - ", op[%d] = (%06o, %06o)", - i, op[i].fpk[0], op[i].fpk[1]); - break; - - case OP_ADX: /* address of 3-word FP const */ - fprintf (sim_deb, - ", op[%d] = (%06o, %06o, %06o)", - i, op[i].fpk[0], op[i].fpk[1], - op[i].fpk[2]); - break; - - case OP_ADT: /* address of 4-word FP const */ - fprintf (sim_deb, - ", op[%d] = (%06o, %06o, %06o, %06o)", - i, op[i].fpk[0], op[i].fpk[1], - op[i].fpk[2], op[i].fpk[3]); - break; - - case OP_ADE: /* address of 5-word FP const */ - fprintf (sim_deb, - ", op[%d] = (%06o, %06o, %06o, %06o, %06o)", - i, op[i].fpk[0], op[i].fpk[1], - op[i].fpk[2], op[i].fpk[3], op[i].fpk[4]); - break; - - default: - fprintf (sim_deb, "UNKNOWN OPERAND TYPE"); /* not implemented */ - } - - pattern = pattern >> OP_N_FLAGS; /* move next pattern into place */ - } -} - - -/* Print CPU registers to the debug device. - - One or more CPU registers may be printed to the debug output device, which - must be valid before calling. -*/ - -void fprint_regs (char *caption, uint32 regs, uint32 base) -{ -static uint32 ARX, BRX, PRL; /* static so addresses are constant */ - -static const char *reg_names[] = { "CIR", "A", "B", "E", "X", "Y", "O", "P", "return" }; -static const uint32 *reg_ptrs[] = { &intaddr, &ARX, &BRX, &E, &XR, &YR, &O, &PC, &PRL }; -static const char *formats[] = { "%02o", "%06o", "%06o", "%01o", "%06o", "%06o", "%01o", "%06o", "P+%d" }; - -static char format[20] = " %s = "; /* base format string */ -static const int eos = 6; /* length of base format string */ - -uint32 i; -t_bool first = TRUE; /* first-time through flag */ - -ARX = AR; /* copy 16-bit value to static variable */ -BRX = BR; /* copy 16-bit value to static variable */ -PRL = PC - base; /* compute value in static variable */ - -for (i = 0; i < REG_COUNT; i++) { - if (regs & 1) { /* register requested? */ - if (first) /* first time? */ - fputs (caption, sim_deb); /* print caption */ - else - fputc (',', sim_deb); /* print separator */ - - strcpy (&format[eos], formats[i]); /* copy format specifier */ - fprintf (sim_deb, format, reg_names[i], *reg_ptrs[i]); - - first = FALSE; - } - - regs = regs >> 1; /* align next register flag */ - } -return; -} +/* hp2100_cpu1.c: HP 2100/1000 EAU simulator and UIG dispatcher + + Copyright (c) 2005-2014, Robert M. Supnik + + 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 + ROBERT M SUPNIK 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 Robert M Supnik shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + + CPU1 Extended arithmetic and optional microcode dispatchers + + 24-Dec-14 JDB Added casts for explicit downward conversions + 05-Apr-14 JDB Corrected typo in comments for cpu_ops + 09-May-12 JDB Separated assignments from conditional expressions + 11-Sep-08 JDB Moved microcode function prototypes to hp2100_cpu1.h + 05-Sep-08 JDB Moved option-present tests to UIG dispatchers + Call "user microcode" dispatcher for unclaimed UIG instructions + 20-Apr-08 JDB Fixed VIS and SIGNAL to depend on the FPP and HAVE_INT64 + 28-Nov-07 JDB Added fprint_ops, fprint_regs for debug printouts + 17-Nov-07 JDB Enabled DIAG as NOP on 1000 F-Series + 04-Jan-07 JDB Added special DBI dispatcher for non-INT64 diagnostic + 29-Dec-06 JDB Allows RRR as NOP if 2114 (diag config test) + 01-Dec-06 JDB Substitutes FPP for firmware FP if HAVE_INT64 + 16-Oct-06 JDB Generalized operands for F-Series FP types + 26-Sep-06 JDB Split hp2100_cpu1.c into multiple modules to simplify extensions + Added iotrap parameter to UIG dispatchers for RTE microcode + 22-Feb-05 JDB Removed EXECUTE instruction (is NOP in actual microcode) + 21-Jan-05 JDB Reorganized CPU option and operand processing flags + Split code along microcode modules + 15-Jan-05 RMS Cloned from hp2100_cpu.c + + Primary references: + - HP 1000 M/E/F-Series Computers Technical Reference Handbook + (5955-0282, Mar-1980) + - HP 1000 M/E/F-Series Computers Engineering and Reference Documentation + (92851-90001, Mar-1981) + - Macro/1000 Reference Manual (92059-90001, Dec-1992) + - HP 93585A Double Integer Firmware Package Installation and Programming + Manual (93585-90007, Feb-1984) + + Additional references are listed with the associated firmware + implementations, as are the HP option model numbers pertaining to the + applicable CPUs. + + + This source file contains the Extended Arithmetic Unit simulator and the User + Instruction Group (a.k.a. "Macro") dispatcher for the 2100 and 1000 (21MX) + CPUs. The UIG simulators reside in separate source files, due to the large + number of firmware options available for these machines. Unit flags indicate + which options are present in the current system. + + This module also provides generalized instruction operand processing. + + The 2100 and 1000 machines were microprogrammable; the 2116/15/14 machines + were not. Both user- and HP-written microprograms were supported. The + microcode address space of the 2100 encompassed four modules of 256 words + each. The 1000 M-series expanded that to sixteen modules, and the 1000 + E/F-series expanded that still further to sixty-four modules. Each CPU had + its own microinstruction set, although the micromachines of the various 1000 + models were similar internally. + + The UIG instructions were divided into ranges assigned to HP firmware + options, reserved for future HP use, and reserved for user microprograms. + User microprograms could occupy any range not already used on a given + machine, but in practice, some effort was made to avoid the HP-reserved + ranges. + + User microprogram simulation is supported by routing any UIG instruction not + allocated to an installed firmware option to a user-firmware dispatcher. + Site-specific microprograms may be simulated there. In the absence of such a + simulation, an unimplemented instruction stop will occur. + + Regarding option instruction sets, there was some commonality across CPU + types. EAU instructions were identical across all models, and the floating + point set was the same on the 2100 and 1000. Other options implemented + proper instruction supersets (e.g., the Fast FORTRAN Processor from 2100 to + 1000-M to 1000-E to 1000-F) or functional equivalence with differing code + points (the 2000 I/O Processor from 2100 to 1000, and the extended-precision + floating-point instructions from 1000-E to 1000-F). + + The 2100 decoded the EAU and UIG sets separately in hardware and supported + only the UIG 0 code points. Bits 7-4 of a UIG instruction decoded one of + sixteen entry points in the lowest-numbered module after module 0. Those + entry points could be used directly (as for the floating-point instructions), + or additional decoding based on bits 3-0 could be implemented. + + The 1000 generalized the instruction decoding to a series of microcoded + jumps, based on the bits in the instruction. Bits 15-8 indicated the group + of the current instruction: EAU (200, 201, 202, 210, and 211), UIG 0 (212), + or UIG 1 (203 and 213). UIG 0, UIG 1, and some EAU instructions were decoded + further by selecting one of sixteen modules within the group via bits 7-4. + Finally, each UIG module decoded up to sixteen instruction entry points via + bits 3-0. Jump tables for all firmware options were contained in the base + set, so modules needed only to be concerned with decoding their individual + entry points within the module. + + While the 2100 and 1000 hardware decoded these instruction sets differently, + the decoding mechanism of the simulation follows that of the 1000 E/F-series. + Where needed, CPU type- or model-specific behavior is simulated. + + The design of the 1000 microinstruction set was such that executing an + instruction for which no microcode was present (e.g., executing a FFP + instruction when the FFP firmware was not installed) resulted in a NOP. + Under simulation, such execution causes an undefined instruction stop if + "stop_inst" is non-zero and a NOP otherwise. +*/ + + +#include "hp2100_defs.h" +#include "hp2100_cpu.h" +#include "hp2100_cpu1.h" + + +/* EAU + + The Extended Arithmetic Unit (EAU) adds ten instructions with double-word + operands, including multiply, divide, shifts, and rotates. Option + implementation by CPU was as follows: + + 2114 2115 2116 2100 1000-M 1000-E 1000-F + ------ ------ ------ ------ ------ ------ ------ + N/A 12579A 12579A std std std std + + The instruction codes are mapped to routines as follows: + + Instr. Bits + Code 15-8 7-4 2116 2100 1000-M 1000-E 1000-F Note + ------ ---- --- ------ ------ ------ ------ ------ --------------------- + 100000 200 00 [diag] [diag] [self test] + 100020 200 01 ASL ASL ASL ASL ASL Bits 3-0 encode shift + 100040 200 02 LSL LSL LSL LSL LSL Bits 3-0 encode shift + 100060 200 03 TIMER TIMER [deterministic delay] + 100100 200 04 RRL RRL RRL RRL RRL Bits 3-0 encode shift + 100200 200 10 MPY MPY MPY MPY MPY + 100400 201 xx DIV DIV DIV DIV DIV + 101020 202 01 ASR ASR ASR ASR ASR Bits 3-0 encode shift + 101040 202 02 LSR LSR LSR LSR LSR Bits 3-0 encode shift + 101100 202 04 RRR RRR RRR RRR RRR Bits 3-0 encode shift + 104200 210 xx DLD DLD DLD DLD DLD + 104400 211 xx DST DST DST DST DST + + The remaining codes for bits 7-4 are undefined and will cause a simulator + stop if enabled. On a real 1000-M, all undefined instructions in the 200 + group decode as MPY, and all in the 202 group decode as NOP. On a real + 1000-E, instruction patterns 200/05 through 200/07 and 202/03 decode as NOP; + all others cause erroneous execution. + + EAU instruction decoding on the 1000 M-series is convoluted. The JEAU + microorder maps IR bits 11, 9-7 and 5-4 to bits 2-0 of the microcode jump + address. The map is detailed on page IC-84 of the ERD. + + The 1000 E/F-series add two undocumented instructions to the 200 group: TIMER + and DIAG. These are described in the ERD on page IA 5-5, paragraph 5-7. The + M-series executes these as MPY and RRL, respectively. A third instruction, + EXECUTE (100120), is also described but was never implemented, and the + E/F-series microcode execute a NOP for this instruction code. + + Notes: + + 1. Under simulation, TIMER, DIAG, and EXECUTE cause undefined instruction + stops if the CPU is set to 21xx. DIAG and EXECUTE also cause stops on + the 1000-M. TIMER does not, because it is used by several HP programs + to differentiate between M- and E/F-series machines. + + 2. DIAG is not implemented under simulation. On the E/F, it performs a + destructive test of all installed memory. Because of this, it is only + functional if the machine is halted, i.e., if the instruction is + executed with the INSTR STEP button. If it is executed in a program, + the result is NOP. + + 3. RRR is permitted and executed as NOP if the CPU is a 2114, as the + presence of the EAU is tested by the diagnostic configurator to + differentiate between 2114 and 2100/1000 CPUs. +*/ + +t_stat cpu_eau (uint32 IR, uint32 intrq) +{ +t_stat reason = SCPE_OK; +OPS op; +uint32 rs, qs, sc, v1, v2, t; +int32 sop1, sop2; + +if ((cpu_unit.flags & UNIT_EAU) == 0) /* option installed? */ + if ((UNIT_CPU_MODEL == UNIT_2114) && (IR == 0101100)) /* 2114 and RRR 16? */ + return SCPE_OK; /* allowed as NOP */ + else + return stop_inst; /* fail */ + +switch ((IR >> 8) & 0377) { /* decode IR<15:8> */ + + case 0200: /* EAU group 0 */ + switch ((IR >> 4) & 017) { /* decode IR<7:4> */ + + case 000: /* DIAG 100000 */ + if ((UNIT_CPU_MODEL != UNIT_1000_E) && /* must be 1000 E-series */ + (UNIT_CPU_MODEL != UNIT_1000_F)) /* or 1000 F-series */ + return stop_inst; /* trap if not */ + break; /* DIAG is NOP unless halted */ + + case 001: /* ASL 100020-100037 */ + sc = (IR & 017)? (IR & 017): 16; /* get sc */ + O = 0; /* clear ovflo */ + while (sc-- != 0) { /* bit by bit */ + t = BR << 1; /* shift B */ + BR = (BR & SIGN) | (t & 077777) | (AR >> 15); + AR = (AR << 1) & DMASK; + if ((BR ^ t) & SIGN) O = 1; + } + break; + + case 002: /* LSL 100040-100057 */ + sc = (IR & 017)? (IR & 017): 16; /* get sc */ + BR = ((BR << sc) | (AR >> (16 - sc))) & DMASK; + AR = (AR << sc) & DMASK; /* BR'AR lsh left */ + break; + + case 003: /* TIMER 100060 */ + if (UNIT_CPU_TYPE != UNIT_TYPE_1000) /* must be 1000 */ + return stop_inst; /* trap if not */ + if (UNIT_CPU_MODEL == UNIT_1000_M) /* 1000 M-series? */ + goto MPY; /* decode as MPY */ + BR = (BR + 1) & DMASK; /* increment B */ + if (BR) PC = err_PC; /* if !=0, repeat */ + break; + + case 004: /* RRL 100100-100117 */ + sc = (IR & 017)? (IR & 017): 16; /* get sc */ + t = BR; /* BR'AR rot left */ + BR = ((BR << sc) | (AR >> (16 - sc))) & DMASK; + AR = ((AR << sc) | (t >> (16 - sc))) & DMASK; + break; + + case 010: /* MPY 100200 (OP_K) */ + MPY: + reason = cpu_ops (OP_K, op, intrq); /* get operand */ + if (reason == SCPE_OK) { /* successful eval? */ + sop1 = SEXT (AR); /* sext AR */ + sop2 = SEXT (op[0].word); /* sext mem */ + sop1 = sop1 * sop2; /* signed mpy */ + BR = (sop1 >> 16) & DMASK; /* to BR'AR */ + AR = sop1 & DMASK; + O = 0; /* no overflow */ + } + break; + + default: /* others undefined */ + return stop_inst; + } + + break; + + case 0201: /* DIV 100400 (OP_K) */ + reason = cpu_ops (OP_K, op, intrq); /* get operand */ + if (reason != SCPE_OK) /* eval failed? */ + break; + rs = qs = BR & SIGN; /* save divd sign */ + if (rs) { /* neg? */ + AR = (~AR + 1) & DMASK; /* make B'A pos */ + BR = (~BR + (AR == 0)) & DMASK; /* make divd pos */ + } + v2 = op[0].word; /* divr = mem */ + if (v2 & SIGN) { /* neg? */ + v2 = (~v2 + 1) & DMASK; /* make divr pos */ + qs = qs ^ SIGN; /* sign of quotient */ + } + if (BR >= v2) O = 1; /* divide work? */ + else { /* maybe... */ + O = 0; /* assume ok */ + v1 = (BR << 16) | AR; /* 32b divd */ + AR = (v1 / v2) & DMASK; /* quotient */ + BR = (v1 % v2) & DMASK; /* remainder */ + if (AR) { /* quotient > 0? */ + if (qs) AR = (~AR + 1) & DMASK; /* apply quo sign */ + if ((AR ^ qs) & SIGN) O = 1; /* still wrong? ovflo */ + } + if (rs) BR = (~BR + 1) & DMASK; /* apply rem sign */ + } + break; + + case 0202: /* EAU group 2 */ + switch ((IR >> 4) & 017) { /* decode IR<7:4> */ + + case 001: /* ASR 101020-101037 */ + sc = (IR & 017)? (IR & 017): 16; /* get sc */ + AR = ((BR << (16 - sc)) | (AR >> sc)) & DMASK; + BR = (SEXT (BR) >> sc) & DMASK; /* BR'AR ash right */ + O = 0; + break; + + case 002: /* LSR 101040-101057 */ + sc = (IR & 017)? (IR & 017): 16; /* get sc */ + AR = ((BR << (16 - sc)) | (AR >> sc)) & DMASK; + BR = BR >> sc; /* BR'AR log right */ + break; + + case 004: /* RRR 101100-101117 */ + sc = (IR & 017)? (IR & 017): 16; /* get sc */ + t = AR; /* BR'AR rot right */ + AR = ((AR >> sc) | (BR << (16 - sc))) & DMASK; + BR = ((BR >> sc) | (t << (16 - sc))) & DMASK; + break; + + default: /* others undefined */ + return stop_inst; + } + + break; + + case 0210: /* DLD 104200 (OP_D) */ + reason = cpu_ops (OP_D, op, intrq); /* get operand */ + if (reason == SCPE_OK) { /* successful eval? */ + AR = (op[0].dword >> 16) & DMASK; /* load AR */ + BR = op[0].dword & DMASK; /* load BR */ + } + break; + + case 0211: /* DST 104400 (OP_A) */ + reason = cpu_ops (OP_A, op, intrq); /* get operand */ + if (reason == SCPE_OK) { /* successful eval? */ + WriteW (op[0].word, AR); /* store AR */ + WriteW ((op[0].word + 1) & VAMASK, BR); /* store BR */ + } + break; + + default: /* should never get here */ + return SCPE_IERR; /* bad call from cpu_instr */ + } + +return reason; +} + + +/* UIG 0 + + The first User Instruction Group (UIG) encodes firmware options for the 2100 + and 1000. Instruction codes 105000-105377 are assigned to microcode options + as follows: + + Instructions Option Name 2100 1000-M 1000-E 1000-F + ------------- -------------------------- ------ ------ ------ ------ + 105000-105362 2000 I/O Processor opt - - - + 105000-105137 Floating Point opt std std std + 105200-105237 Fast FORTRAN Processor opt opt opt std + 105240-105257 RTE-IVA/B Extended Memory - - opt opt + 105240-105257 RTE-6/VM Virtual Memory - - opt opt + 105300-105317 Distributed System - - opt opt + 105320-105337 Double Integer - - opt - + 105320-105337 Scientific Instruction Set - - - std + 105340-105357 RTE-6/VM Operating System - - opt opt + + If the 2100 IOP is installed, the only valid UIG instructions are IOP + instructions, as the IOP used the full 2100 microcode addressing space. The + IOP dispatcher remaps the 2100 codes to 1000 codes for execution. + + The F-Series moved the three-word extended real instructions from the FFP + range to the base floating-point range and added four-word double real and + two-word double integer instructions. The double integer instructions + occupied some of the vacated extended real instruction codes in the FFP, with + the rest assigned to the floating-point range. Consequently, many + instruction codes for the F-Series are different from the E-Series. + + Implementation notes: + + 1. Product 93585A, available from the "Specials" group, added double integer + microcode to the E-Series. The instruction codes were different from + those in the F-Series to avoid conflicting with the E-Series FFP. + + 2. To run the double-integer instructions diagnostic in the absence of + 64-bit integer support (and therefore of F-Series simulation), a special + DBI dispatcher may be enabled by defining ENABLE_DIAG during compilation. + This dispatcher will remap the F-Series DBI instructions to the E-Series + codes, so that the F-Series diagnostic may be run. Because several of + the F-Series DBI instruction codes replace M/E-Series FFP codes, this + dispatcher will only operate if FFP is disabled. + + Note that enabling the dispatcher will produce non-standard FP behavior. + For example, any code in the range 105000-105017 normally would execute a + FAD instruction. With the dispatcher enabled, 105014 would execute a + .DAD, while the other codes would execute a FAD. Therefore, ENABLE_DIAG + should only be used to run the diagnostic and is not intended for general + use. + + 3. Any instruction not claimed by an installed option will be sent to the + user microcode dispatcher. +*/ + +t_stat cpu_uig_0 (uint32 IR, uint32 intrq, uint32 iotrap) +{ +if ((cpu_unit.flags & UNIT_IOP) && /* I/O Processor? */ + (UNIT_CPU_TYPE == UNIT_TYPE_2100)) /* and 2100 CPU? */ + return cpu_iop (IR, intrq); /* dispatch to IOP */ + + +#if !defined (HAVE_INT64) && defined (ENABLE_DIAG) /* special DBI diagnostic dispatcher */ + +if (((cpu_unit.flags & UNIT_FFP) == 0) && /* FFP absent? */ + (cpu_unit.flags & UNIT_DBI)) /* and DBI present? */ + switch (IR & 0377) { + case 0014: /* .DAD 105014 */ + return cpu_dbi (0105321, intrq); + + case 0034: /* .DSB 105034 */ + return cpu_dbi (0105327, intrq); + + case 0054: /* .DMP 105054 */ + return cpu_dbi (0105322, intrq); + + case 0074: /* .DDI 105074 */ + return cpu_dbi (0105325, intrq); + + case 0114: /* .DSBR 105114 */ + return cpu_dbi (0105334, intrq); + + case 0134: /* .DDIR 105134 */ + return cpu_dbi (0105326, intrq); + + case 0203: /* .DNG 105203 */ + return cpu_dbi (0105323, intrq); + + case 0204: /* .DCO 105204 */ + return cpu_dbi (0105324, intrq); + + case 0210: /* .DIN 105210 */ + return cpu_dbi (0105330, intrq); + + case 0211: /* .DDE 105211 */ + return cpu_dbi (0105331, intrq); + + case 0212: /* .DIS 105212 */ + return cpu_dbi (0105332, intrq); + + case 0213: /* .DDS 105213 */ + return cpu_dbi (0105333, intrq); + } /* otherwise, continue */ + +#endif /* end of special DBI dispatcher */ + + +switch ((IR >> 4) & 017) { /* decode IR<7:4> */ + + case 000: /* 105000-105017 */ + case 001: /* 105020-105037 */ + case 002: /* 105040-105057 */ + case 003: /* 105060-105077 */ + case 004: /* 105100-105117 */ + case 005: /* 105120-105137 */ + if (cpu_unit.flags & UNIT_FP) /* FP option installed? */ +#if defined (HAVE_INT64) /* int64 support available */ + return cpu_fpp (IR, intrq); /* Floating Point Processor */ +#else /* int64 support unavailable */ + return cpu_fp (IR, intrq); /* Firmware Floating Point */ +#endif /* end of int64 support */ + else + break; + + case 010: /* 105200-105217 */ + case 011: /* 105220-105237 */ + if (cpu_unit.flags & UNIT_FFP) /* FFP option installed? */ + return cpu_ffp (IR, intrq); /* Fast FORTRAN Processor */ + else + break; + + case 012: /* 105240-105257 */ + if (cpu_unit.flags & UNIT_VMAOS) /* VMA/OS option installed? */ + return cpu_rte_vma (IR, intrq); /* RTE-6 VMA */ + else if (cpu_unit.flags & UNIT_EMA) /* EMA option installed? */ + return cpu_rte_ema (IR, intrq); /* RTE-4 EMA */ + else + break; + + case 014: /* 105300-105317 */ + if (cpu_unit.flags & UNIT_DS) /* DS option installed? */ + return cpu_ds (IR, intrq); /* Distributed System */ + else + break; + + case 015: /* 105320-105337 */ +#if defined (HAVE_INT64) /* int64 support available */ + if (UNIT_CPU_MODEL == UNIT_1000_F) /* F-series? */ + return cpu_sis (IR, intrq); /* Scientific Instruction is standard */ + else /* M/E-series */ +#endif /* end of int64 support */ + if (cpu_unit.flags & UNIT_DBI) /* DBI option installed? */ + return cpu_dbi (IR, intrq); /* Double integer */ + else + break; + + case 016: /* 105340-105357 */ + if (cpu_unit.flags & UNIT_VMAOS) /* VMA/OS option installed? */ + return cpu_rte_os (IR, intrq, iotrap); /* RTE-6 OS */ + else + break; + } + +return cpu_user (IR, intrq); /* try user microcode */ +} + + +/* UIG 1 + + The second User Instruction Group (UIG) encodes firmware options for the + 1000. Instruction codes 101400-101777 and 105400-105777 are assigned to + microcode options as follows ("x" is "1" or "5" below): + + Instructions Option Name 1000-M 1000-E 1000-F + ------------- ---------------------------- ------ ------ ------ + 10x400-10x437 2000 IOP opt opt opt + 10x460-10x477 2000 IOP opt opt opt + 10x460-10x477 Vector Instruction Set - - opt + 10x520-10x537 Distributed System opt - - + 10x600-10x617 SIGNAL/1000 Instruction Set - - opt + 10x700-10x737 Dynamic Mapping System opt opt std + 10x740-10x777 Extended Instruction Group std std std + + Only 1000 systems execute these instructions. + + Implementation notes: + + 1. The Distributed System (DS) microcode was mapped to different instruction + ranges for the M-Series and the E/F-Series. The sequence of instructions + was identical, though, so we remap the former range to the latter before + dispatching. + + 2. Any instruction not claimed by an installed option will be sent to the + user microcode dispatcher. +*/ + +t_stat cpu_uig_1 (uint32 IR, uint32 intrq, uint32 iotrap) +{ +if (UNIT_CPU_TYPE != UNIT_TYPE_1000) /* 1000 execution? */ + return stop_inst; /* no, so trap */ + +switch ((IR >> 4) & 017) { /* decode IR<7:4> */ + + case 000: /* 105400-105417 */ + case 001: /* 105420-105437 */ + if (cpu_unit.flags & UNIT_IOP) /* IOP option installed? */ + return cpu_iop (IR, intrq); /* 2000 I/O Processor */ + else + break; + + case 003: /* 105460-105477 */ +#if defined (HAVE_INT64) /* int64 support available */ + if (cpu_unit.flags & UNIT_VIS) /* VIS option installed? */ + return cpu_vis (IR, intrq); /* Vector Instruction Set */ + else +#endif /* end of int64 support */ + if (cpu_unit.flags & UNIT_IOP) /* IOP option installed? */ + return cpu_iop (IR, intrq); /* 2000 I/O Processor */ + else + break; + + case 005: /* 105520-105537 */ + if (cpu_unit.flags & UNIT_DS) { /* DS option installed? */ + IR = IR ^ 0000620; /* remap to 105300-105317 */ + return cpu_ds (IR, intrq); /* Distributed System */ + } + else + break; + +#if defined (HAVE_INT64) /* int64 support available */ + case 010: /* 105600-105617 */ + if (cpu_unit.flags & UNIT_SIGNAL) /* SIGNAL option installed? */ + return cpu_signal (IR, intrq); /* SIGNAL/1000 Instructions */ + else + break; +#endif /* end of int64 support */ + + case 014: /* 105700-105717 */ + case 015: /* 105720-105737 */ + if (cpu_unit.flags & UNIT_DMS) /* DMS option installed? */ + return cpu_dms (IR, intrq); /* Dynamic Mapping System */ + else + break; + + case 016: /* 105740-105757 */ + case 017: /* 105760-105777 */ + return cpu_eig (IR, intrq); /* Extended Instruction Group */ + } + +return cpu_user (IR, intrq); /* try user microcode */ +} + + +/* Read a multiple-precision operand value. */ + +OP ReadOp (uint32 va, OPSIZE precision) +{ +OP operand; +uint32 i; + +if (precision == in_s) + operand.word = ReadW (va); /* read single integer */ + +else if (precision == in_d) + operand.dword = ReadW (va) << 16 | /* read double integer */ + ReadW ((va + 1) & VAMASK); /* merge high and low words */ + +else + for (i = 0; i < (uint32) precision; i++) { /* read fp 2 to 5 words */ + operand.fpk[i] = ReadW (va); + va = (va + 1) & VAMASK; + } +return operand; +} + +/* Write a multiple-precision operand value. */ + +void WriteOp (uint32 va, OP operand, OPSIZE precision) +{ +uint32 i; + +if (precision == in_s) + WriteW (va, operand.word); /* write single integer */ + +else if (precision == in_d) { + WriteW (va, (operand.dword >> 16) & DMASK); /* write double integer */ + WriteW ((va + 1) & VAMASK, operand.dword & DMASK); /* high word, then low word */ + } + +else + for (i = 0; i < (uint32) precision; i++) { /* write fp 2 to 5 words */ + WriteW (va, operand.fpk[i]); + va = (va + 1) & VAMASK; + } +return; +} + + +/* Get instruction operands. + + Operands for a given instruction are specifed by an "operand pattern" + consisting of flags indicating the types and storage methods. The pattern + directs how each operand is to be retrieved and whether the operand value or + address is returned in the operand array. + + Typically, a microcode simulation handler will define an OP_PAT array, with + each element containing an operand pattern corresponding to the simulated + instruction. Operand patterns are defined in the header file accompanying + this source file. After calling this function with the appropriate operand + pattern and a pointer to an array of OPs, operands are decoded and stored + sequentially in the array. + + The following operand encodings are defined: + + Code Operand Description Example Return + ------ ---------------------------------------- ----------- ------------ + OP_NUL No operand present [inst] None + + OP_IAR Integer constant in A register LDA I Value of I + [inst] + ... + I DEC 0 + + OP_JAB Double integer constant in A/B registers DLD J Value of J + [inst] + ... + J DEC 0,0 + + OP_FAB 2-word FP constant in A/B registers DLD F Value of F + [inst] + ... + F DEC 0.0 + + OP_CON Inline 1-word constant [inst] Value of C + C DEC 0 + ... + + OP_VAR Inline 1-word variable [inst] Address of V + V BSS 1 + ... + + OP_ADR Inline address [inst] Address of A + DEF A + ... + A EQU * + + OP_ADK Address of integer constant [inst] Value of K + DEF K + ... + K DEC 0 + + OP_ADD Address of double integer constant [inst] Value of D + DEF D + ... + D DEC 0,0 + + OP_ADF Address of 2-word FP constant [inst] Value of F + DEF F + ... + F DEC 0.0 + + OP_ADX Address of 3-word FP constant [inst] Value of X + DEF X + ... + X DEX 0.0 + + OP_ADT Address of 4-word FP constant [inst] Value of T + DEF T + ... + T DEY 0.0 + + OP_ADE Address of 5-word FP constant [inst] Value of E + DEF E + ... + E DEC 0,0,0,0,0 + + Address operands, i.e., those having a DEF to the operand, will be resolved + to direct addresses. If an interrupt is pending and more than three levels + of indirection are used, the routine returns without completing operand + retrieval (the instruction will be retried after interrupt servicing). + Addresses are always resolved in the current DMS map. + + An operand pattern consists of one or more operand encodings, corresponding + to the operands required by a given instruction. Values are returned in + sequence to the operand array. +*/ + +t_stat cpu_ops (OP_PAT pattern, OPS op, uint32 irq) +{ +t_stat reason = SCPE_OK; +OP_PAT flags; +uint32 i, MA; + +for (i = 0; i < OP_N_F; i++) { + flags = pattern & OP_M_FLAGS; /* get operand pattern */ + + if (flags >= OP_ADR) { /* address operand? */ + reason = resolve (ReadW (PC), &MA, irq); /* resolve indirects */ + if (reason != SCPE_OK) /* resolution failed? */ + return reason; + } + + switch (flags) { + case OP_NUL: /* null operand */ + return reason; /* no more, so quit */ + + case OP_IAR: /* int in A */ + (*op++).word = AR; /* get one-word value */ + break; + + case OP_JAB: /* dbl-int in A/B */ + (*op++).dword = (AR << 16) | BR; /* get two-word value */ + break; + + case OP_FAB: /* 2-word FP in A/B */ + (*op).fpk[0] = AR; /* get high FP word */ + (*op++).fpk[1] = BR; /* get low FP word */ + break; + + case OP_CON: /* inline constant operand */ + *op++ = ReadOp (PC, in_s); /* get value */ + break; + + case OP_VAR: /* inline variable operand */ + (*op++).word = (uint16) PC; /* get pointer to variable */ + break; + + case OP_ADR: /* inline address operand */ + (*op++).word = (uint16) MA; /* get address (set by "resolve" above) */ + break; + + case OP_ADK: /* address of int constant */ + *op++ = ReadOp (MA, in_s); /* get value */ + break; + + case OP_ADD: /* address of dbl-int constant */ + *op++ = ReadOp (MA, in_d); /* get value */ + break; + + case OP_ADF: /* address of 2-word FP const */ + *op++ = ReadOp (MA, fp_f); /* get value */ + break; + + case OP_ADX: /* address of 3-word FP const */ + *op++ = ReadOp (MA, fp_x); /* get value */ + break; + + case OP_ADT: /* address of 4-word FP const */ + *op++ = ReadOp (MA, fp_t); /* get value */ + break; + + case OP_ADE: /* address of 5-word FP const */ + *op++ = ReadOp (MA, fp_e); /* get value */ + break; + + default: + return SCPE_IERR; /* not implemented */ + } + + if (flags >= OP_CON) /* operand after instruction? */ + PC = (PC + 1) & VAMASK; /* yes, so bump to next */ + pattern = pattern >> OP_N_FLAGS; /* move next pattern into place */ + } +return reason; +} + + +/* Print operands to the debug device. + + The values of an operand array are printed to the debug device. The types of + the operands are specified by an operand pattern. Typically, the operand + pattern is the same one that was used to fill the array originally. +*/ + +void fprint_ops (OP_PAT pattern, OPS op) +{ +OP_PAT flags; +uint32 i; + +for (i = 0; i < OP_N_F; i++) { + flags = pattern & OP_M_FLAGS; /* get operand pattern */ + + switch (flags) { + case OP_NUL: /* null operand */ + return; /* no more, so quit */ + + case OP_IAR: /* int in A */ + case OP_CON: /* inline constant operand */ + case OP_VAR: /* inline variable operand */ + case OP_ADR: /* inline address operand */ + case OP_ADK: /* address of int constant */ + fprintf (sim_deb, + ", op[%d] = %06o", + i, op[i].word); + break; + + case OP_JAB: /* dbl-int in A/B */ + case OP_ADD: /* address of dbl-int constant */ + fprintf (sim_deb, + ", op[%d] = %011o", + i, op[i].dword); + break; + + case OP_FAB: /* 2-word FP in A/B */ + case OP_ADF: /* address of 2-word FP const */ + fprintf (sim_deb, + ", op[%d] = (%06o, %06o)", + i, op[i].fpk[0], op[i].fpk[1]); + break; + + case OP_ADX: /* address of 3-word FP const */ + fprintf (sim_deb, + ", op[%d] = (%06o, %06o, %06o)", + i, op[i].fpk[0], op[i].fpk[1], + op[i].fpk[2]); + break; + + case OP_ADT: /* address of 4-word FP const */ + fprintf (sim_deb, + ", op[%d] = (%06o, %06o, %06o, %06o)", + i, op[i].fpk[0], op[i].fpk[1], + op[i].fpk[2], op[i].fpk[3]); + break; + + case OP_ADE: /* address of 5-word FP const */ + fprintf (sim_deb, + ", op[%d] = (%06o, %06o, %06o, %06o, %06o)", + i, op[i].fpk[0], op[i].fpk[1], + op[i].fpk[2], op[i].fpk[3], op[i].fpk[4]); + break; + + default: + fprintf (sim_deb, "UNKNOWN OPERAND TYPE"); /* not implemented */ + } + + pattern = pattern >> OP_N_FLAGS; /* move next pattern into place */ + } +} + + +/* Print CPU registers to the debug device. + + One or more CPU registers may be printed to the debug output device, which + must be valid before calling. +*/ + +void fprint_regs (char *caption, uint32 regs, uint32 base) +{ +static uint32 ARX, BRX, PRL; /* static so addresses are constant */ + +static const char *reg_names[] = { "CIR", "A", "B", "E", "X", "Y", "O", "P", "return" }; +static const uint32 *reg_ptrs[] = { &intaddr, &ARX, &BRX, &E, &XR, &YR, &O, &PC, &PRL }; +static const char *formats[] = { "%02o", "%06o", "%06o", "%01o", "%06o", "%06o", "%01o", "%06o", "P+%d" }; + +static char format[20] = " %s = "; /* base format string */ +static const int eos = 6; /* length of base format string */ + +uint32 i; +t_bool first = TRUE; /* first-time through flag */ + +ARX = AR; /* copy 16-bit value to static variable */ +BRX = BR; /* copy 16-bit value to static variable */ +PRL = PC - base; /* compute value in static variable */ + +for (i = 0; i < REG_COUNT; i++) { + if (regs & 1) { /* register requested? */ + if (first) /* first time? */ + fputs (caption, sim_deb); /* print caption */ + else + fputc (',', sim_deb); /* print separator */ + + strcpy (&format[eos], formats[i]); /* copy format specifier */ + fprintf (sim_deb, format, reg_names[i], *reg_ptrs[i]); + + first = FALSE; + } + + regs = regs >> 1; /* align next register flag */ + } +return; +} diff --git a/HP2100/hp2100_cpu1.h b/HP2100/hp2100_cpu1.h index 52b6a8c5..2c954443 100644 --- a/HP2100/hp2100_cpu1.h +++ b/HP2100/hp2100_cpu1.h @@ -1,315 +1,323 @@ -/* hp2100_cpu1.h: HP 2100/1000 firmware dispatcher definitions - - Copyright (c) 2006-2008, J. David Bryan - - 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 - THE AUTHOR 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 the author shall not - be used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from the author. - - 11-Sep-08 JDB Moved microcode function prototypes here - 30-Apr-08 JDB Corrected OP_AFF to OP_AAFF for SIGNAL/1000 - Removed unused operand patterns - 23-Feb-08 HV Added more OP_* for SIGNAL/1000 and VIS - 28-Nov-07 JDB Added fprint_ops, fprint_regs for debug printouts - 19-Oct-07 JDB Revised OP_KKKAKK operand profile to OP_CCCACC for $LOC - 16-Oct-06 JDB Generalized operands for F-Series FP types - 26-Sep-06 JDB Split from hp2100_cpu1.c -*/ - -#ifndef _HP2100_CPU1_H_ -#define _HP2100_CPU1_H_ - - -/* Register print encoding */ - -#define REG_COUNT 9 /* count of print flags */ - -#define REG_CIR (1 << 0) /* print central interrupt register */ -#define REG_A (1 << 1) /* print A register */ -#define REG_B (1 << 2) /* print B register */ -#define REG_E (1 << 3) /* print E register */ -#define REG_X (1 << 4) /* print X register */ -#define REG_Y (1 << 5) /* print Y register */ -#define REG_O (1 << 6) /* print O register */ -#define REG_P (1 << 7) /* print P register */ -#define REG_P_REL (1 << 8) /* print P register as relative */ - - -/* Operand processing encoding */ - -/* Base operand types. Note that all address encodings must be grouped together - after OP_ADR. -*/ - -#define OP_NUL 0 /* no operand */ -#define OP_IAR 1 /* 1-word int in A reg */ -#define OP_JAB 2 /* 2-word int in A/B regs */ -#define OP_FAB 3 /* 2-word FP const in A/B regs */ -#define OP_CON 4 /* inline 1-word constant */ -#define OP_VAR 5 /* inline 1-word variable */ - -#define OP_ADR 6 /* inline address */ -#define OP_ADK 7 /* addr of 1-word int const */ -#define OP_ADD 8 /* addr of 2-word int const */ -#define OP_ADF 9 /* addr of 2-word FP const */ -#define OP_ADX 10 /* addr of 3-word FP const */ -#define OP_ADT 11 /* addr of 4-word FP const */ -#define OP_ADE 12 /* addr of 5-word FP const */ - -#define OP_N_FLAGS 4 /* number of bits needed for flags */ -#define OP_M_FLAGS ((1 << OP_N_FLAGS) - 1) /* mask for flag bits */ - -#define OP_N_F (8 * sizeof (uint32) / OP_N_FLAGS) /* max number of op fields */ - -#define OP_V_F1 (0 * OP_N_FLAGS) /* 1st operand field */ -#define OP_V_F2 (1 * OP_N_FLAGS) /* 2nd operand field */ -#define OP_V_F3 (2 * OP_N_FLAGS) /* 3rd operand field */ -#define OP_V_F4 (3 * OP_N_FLAGS) /* 4th operand field */ -#define OP_V_F5 (4 * OP_N_FLAGS) /* 5th operand field */ -#define OP_V_F6 (5 * OP_N_FLAGS) /* 6th operand field */ -#define OP_V_F7 (6 * OP_N_FLAGS) /* 7th operand field */ -#define OP_V_F8 (7 * OP_N_FLAGS) /* 8th operand field */ - -/* Operand processing patterns */ - -#define OP_N (OP_NUL << OP_V_F1) -#define OP_I (OP_IAR << OP_V_F1) -#define OP_J (OP_JAB << OP_V_F1) -#define OP_R (OP_FAB << OP_V_F1) -#define OP_C (OP_CON << OP_V_F1) -#define OP_V (OP_VAR << OP_V_F1) -#define OP_A (OP_ADR << OP_V_F1) -#define OP_K (OP_ADK << OP_V_F1) -#define OP_D (OP_ADD << OP_V_F1) -#define OP_X (OP_ADX << OP_V_F1) -#define OP_T (OP_ADT << OP_V_F1) -#define OP_E (OP_ADE << OP_V_F1) - -#define OP_IA ((OP_IAR << OP_V_F1) | (OP_ADR << OP_V_F2)) -#define OP_JA ((OP_JAB << OP_V_F1) | (OP_ADR << OP_V_F2)) -#define OP_JD ((OP_JAB << OP_V_F1) | (OP_ADD << OP_V_F2)) -#define OP_RC ((OP_FAB << OP_V_F1) | (OP_CON << OP_V_F2)) -#define OP_RK ((OP_FAB << OP_V_F1) | (OP_ADK << OP_V_F2)) -#define OP_RF ((OP_FAB << OP_V_F1) | (OP_ADF << OP_V_F2)) -#define OP_CV ((OP_CON << OP_V_F1) | (OP_VAR << OP_V_F2)) -#define OP_AC ((OP_ADR << OP_V_F1) | (OP_CON << OP_V_F2)) -#define OP_AA ((OP_ADR << OP_V_F1) | (OP_ADR << OP_V_F2)) -#define OP_AK ((OP_ADR << OP_V_F1) | (OP_ADK << OP_V_F2)) -#define OP_AX ((OP_ADR << OP_V_F1) | (OP_ADX << OP_V_F2)) -#define OP_AT ((OP_ADR << OP_V_F1) | (OP_ADT << OP_V_F2)) -#define OP_KV ((OP_ADK << OP_V_F1) | (OP_VAR << OP_V_F2)) -#define OP_KA ((OP_ADK << OP_V_F1) | (OP_ADR << OP_V_F2)) -#define OP_KK ((OP_ADK << OP_V_F1) | (OP_ADK << OP_V_F2)) - -#define OP_IIF ((OP_IAR << OP_V_F1) | (OP_IAR << OP_V_F2) | \ - (OP_ADF << OP_V_F3)) - -#define OP_IAT ((OP_IAR << OP_V_F1) | (OP_ADR << OP_V_F2) | \ - (OP_ADT << OP_V_F3)) - -#define OP_CVA ((OP_CON << OP_V_F1) | (OP_VAR << OP_V_F2) | \ - (OP_ADR << OP_V_F3)) - -#define OP_AAA ((OP_ADR << OP_V_F1) | (OP_ADR << OP_V_F2) | \ - (OP_ADR << OP_V_F3)) - -#define OP_AAF ((OP_ADR << OP_V_F1) | (OP_ADR << OP_V_F2) | \ - (OP_ADF << OP_V_F3)) - -#define OP_AAX ((OP_ADR << OP_V_F1) | (OP_ADR << OP_V_F2) | \ - (OP_ADX << OP_V_F3)) - -#define OP_AAT ((OP_ADR << OP_V_F1) | (OP_ADR << OP_V_F2) | \ - (OP_ADT << OP_V_F3)) - -#define OP_AKA ((OP_ADR << OP_V_F1) | (OP_ADK << OP_V_F2) | \ - (OP_ADR << OP_V_F3)) - -#define OP_AKK ((OP_ADR << OP_V_F1) | (OP_ADK << OP_V_F2) | \ - (OP_ADK << OP_V_F3)) - -#define OP_AXX ((OP_ADR << OP_V_F1) | (OP_ADX << OP_V_F2) | \ - (OP_ADX << OP_V_F3)) - -#define OP_ATT ((OP_ADR << OP_V_F1) | (OP_ADT << OP_V_F2) | \ - (OP_ADT << OP_V_F3)) - -#define OP_AEE ((OP_ADR << OP_V_F1) | (OP_ADE << OP_V_F2) | \ - (OP_ADE << OP_V_F3)) - -#define OP_AAXX ((OP_ADR << OP_V_F1) | (OP_ADR << OP_V_F2) | \ - (OP_ADX << OP_V_F3) | (OP_ADX << OP_V_F4)) - -#define OP_AAFF ((OP_ADR << OP_V_F1) | (OP_ADR << OP_V_F2) | \ - (OP_ADF << OP_V_F3) | (OP_ADF << OP_V_F4)) - -#define OP_AAKK ((OP_ADR << OP_V_F1) | (OP_ADR << OP_V_F2) | \ - (OP_ADK << OP_V_F3) | (OP_ADK << OP_V_F4)) - -#define OP_KKKK ((OP_ADK << OP_V_F1) | (OP_ADK << OP_V_F2) | \ - (OP_ADK << OP_V_F3) | (OP_ADK << OP_V_F4)) - -#define OP_AAAKK ((OP_ADR << OP_V_F1) | (OP_ADR << OP_V_F2) | \ - (OP_ADR << OP_V_F3) | (OP_ADK << OP_V_F4) | \ - (OP_ADK << OP_V_F5)) - -#define OP_AKAKK ((OP_ADR << OP_V_F1) | (OP_ADK << OP_V_F2) | \ - (OP_ADR << OP_V_F3) | (OP_ADK << OP_V_F4) | \ - (OP_ADK << OP_V_F5)) - -#define OP_AAACCC ((OP_ADR << OP_V_F1) | (OP_ADR << OP_V_F2) | \ - (OP_ADR << OP_V_F3) | (OP_CON << OP_V_F4) | \ - (OP_CON << OP_V_F5) | (OP_CON << OP_V_F6)) - -#define OP_AAFFKK ((OP_ADR << OP_V_F1) | (OP_ADR << OP_V_F2) | \ - (OP_ADF << OP_V_F3) | (OP_ADF << OP_V_F4) | \ - (OP_ADK << OP_V_F5) | (OP_ADK << OP_V_F6)) - -#define OP_AAKAKK ((OP_ADR << OP_V_F1) | (OP_ADR << OP_V_F2) | \ - (OP_ADK << OP_V_F3) | (OP_ADR << OP_V_F4) | \ - (OP_ADK << OP_V_F5) | (OP_ADK << OP_V_F6)) - -#define OP_CATAKK ((OP_CON << OP_V_F1) | (OP_ADR << OP_V_F2) | \ - (OP_ADT << OP_V_F3) | (OP_ADR << OP_V_F4) | \ - (OP_ADK << OP_V_F5) | (OP_ADK << OP_V_F6)) - -#define OP_CCCACC ((OP_CON << OP_V_F1) | (OP_CON << OP_V_F2) | \ - (OP_CON << OP_V_F3) | (OP_ADR << OP_V_F4) | \ - (OP_CON << OP_V_F5) | (OP_CON << OP_V_F6)) - -#define OP_AAAFFKK ((OP_ADR << OP_V_F1) | (OP_ADR << OP_V_F2) | \ - (OP_ADR << OP_V_F3) | (OP_ADF << OP_V_F4) | \ - (OP_ADF << OP_V_F5) | (OP_ADK << OP_V_F6) | \ - (OP_ADK << OP_V_F7)) - -#define OP_AKAKAKK ((OP_ADR << OP_V_F1) | (OP_ADK << OP_V_F2) | \ - (OP_ADR << OP_V_F3) | (OP_ADK << OP_V_F4) | \ - (OP_ADR << OP_V_F5) | (OP_ADK << OP_V_F6) | \ - (OP_ADK << OP_V_F7)) - -#define OP_AAKAKAKK ((OP_ADR << OP_V_F1) | (OP_ADR << OP_V_F2) | \ - (OP_ADK << OP_V_F3) | (OP_ADR << OP_V_F4) | \ - (OP_ADK << OP_V_F5) | (OP_ADR << OP_V_F6) | \ - (OP_ADK << OP_V_F7) | (OP_ADK << OP_V_F8)) - -#define OP_CCACACCA ((OP_CON << OP_V_F1) | (OP_CON << OP_V_F2) | \ - (OP_ADR << OP_V_F3) | (OP_CON << OP_V_F4) | \ - (OP_ADR << OP_V_F5) | (OP_CON << OP_V_F6) | \ - (OP_CON << OP_V_F7) | (OP_ADR << OP_V_F8)) - - -/* Operand precisions (compatible with F-Series FPP): - - - S = 1-word integer - - D = 2-word integer - - F = 2-word single-precision floating-point - - X = 3-word extended-precision floating-point - - T = 4-word double-precision floating-point - - E = 5-word expanded-exponent floating-point - - A = null operand (operand is in FPP accumulator) - - 5-word floating-point numbers are supported by the F-Series Floating-Point - Processor hardware, but the instruction codes are not documented. - - Note that ordering is important, as we depend on the "fp" type codes to - reflect the number of words needed. -*/ - -typedef enum { in_s, in_d, fp_f, fp_x, fp_t, fp_e, fp_a } OPSIZE; - - -/* Conversion from operand size to word count */ - -#define TO_COUNT(s) ((s == fp_a) ? 0 : (uint32) (s + (s < fp_f))) - - -/* HP in-memory representation of a packed floating-point number. - Actual value will use two, three, four, or five words, as needed. -*/ - -typedef uint16 FPK[5]; - - -/* Operand processing types. - - NOTE: Microsoft VC++ 6.0 does not support the C99 standard, so we cannot - initialize unions by arbitrary variant ("designated initializers"). - Therefore, we follow the C90 form of initializing via the first named - variant. The FPK variant must appear first in the OP structure, as we define - a number of FPK constants in other modules. -*/ - -typedef union { /* general operand */ - FPK fpk; /* floating-point value */ - uint16 word; /* 16-bit integer */ - uint32 dword; /* 32-bit integer */ - } OP; - -typedef OP OPS[OP_N_F]; /* operand array */ - -typedef uint32 OP_PAT; /* operand pattern */ - - -/* Microcode dispatcher functions (grouped by cpu module number) */ - -extern t_stat cpu_ds (uint32 IR, uint32 intrq); /* [0] Distributed System stub */ -extern t_stat cpu_user (uint32 IR, uint32 intrq); /* [0] User firmware dispatcher */ -extern t_stat cpu_user_20 (uint32 IR, uint32 intrq); /* [0] Module 20 user microprograms stub */ - -extern t_stat cpu_eau (uint32 IR, uint32 intrq); /* [1] EAU group simulator */ -extern t_stat cpu_uig_0 (uint32 IR, uint32 intrq, uint32 iotrap); /* [1] UIG group 0 dispatcher */ -extern t_stat cpu_uig_1 (uint32 IR, uint32 intrq, uint32 iotrap); /* [1] UIG group 1 dispatcher */ - -#if !defined (HAVE_INT64) /* int64 support unavailable */ -extern t_stat cpu_fp (uint32 IR, uint32 intrq); /* [2] Firmware Floating Point */ -#endif -extern t_stat cpu_dms (uint32 IR, uint32 intrq); /* [2] Dynamic mapping system */ -extern t_stat cpu_eig (uint32 IR, uint32 intrq); /* [2] Extended instruction group */ -extern t_stat cpu_iop (uint32 IR, uint32 intrq); /* [2] 2000 I/O Processor */ - -extern t_stat cpu_ffp (uint32 IR, uint32 intrq); /* [3] Fast FORTRAN Processor */ -extern t_stat cpu_dbi (uint32 IR, uint32 intrq); /* [3] Double-Integer instructions */ - -#if defined (HAVE_INT64) /* int64 support available */ -extern t_stat cpu_fpp (uint32 IR, uint32 intrq); /* [4] Floating Point Processor */ -extern t_stat cpu_sis (uint32 IR, uint32 intrq); /* [4] Scientific Instruction Set */ -#endif - -extern t_stat cpu_rte_vma (uint32 IR, uint32 intrq); /* [5] RTE-6 VMA */ -extern t_stat cpu_rte_ema (uint32 IR, uint32 intrq); /* [5] RTE-IV EMA */ - -extern t_stat cpu_rte_os (uint32 IR, uint32 intrq, uint32 iotrap); /* [6] RTE-6 OS */ - -#if defined (HAVE_INT64) /* int64 support available */ -extern t_stat cpu_vis (uint32 IR, uint32 intrq); /* [7] Vector Instruction Set */ -extern t_stat cpu_signal (uint32 IR, uint32 intrq); /* [7] SIGNAL/1000 Instructions */ -#endif - - -/* Microcode helper functions */ - -OP ReadOp (uint32 va, OPSIZE precision); /* generalized operand read */ -void WriteOp (uint32 va, OP operand, OPSIZE precision); /* generalized operand write */ -t_stat cpu_ops (OP_PAT pattern, OPS op, uint32 irq); /* operand processor */ - -void fprint_ops (OP_PAT pattern, OPS op); /* debug print operands */ -void fprint_regs (char *caption, uint32 regs, uint32 base); /* debug print CPU registers */ - -#endif +/* hp2100_cpu1.h: HP 2100/1000 firmware dispatcher definitions + + Copyright (c) 2006-2013, J. David Bryan + + 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 + THE AUTHOR 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 the author shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from the author. + + 18-Mar-13 JDB Added externs for microcode helper functions + 14-Mar-13 MP Changed guard macro name to avoid reserved namespace + 11-Sep-08 JDB Moved microcode function prototypes here + 30-Apr-08 JDB Corrected OP_AFF to OP_AAFF for SIGNAL/1000 + Removed unused operand patterns + 23-Feb-08 HV Added more OP_* for SIGNAL/1000 and VIS + 28-Nov-07 JDB Added fprint_ops, fprint_regs for debug printouts + 19-Oct-07 JDB Revised OP_KKKAKK operand profile to OP_CCCACC for $LOC + 16-Oct-06 JDB Generalized operands for F-Series FP types + 26-Sep-06 JDB Split from hp2100_cpu1.c +*/ + +#ifndef HP2100_CPU1_H_ +#define HP2100_CPU1_H_ + + +/* Register print encoding */ + +#define REG_COUNT 9 /* count of print flags */ + +#define REG_CIR (1 << 0) /* print central interrupt register */ +#define REG_A (1 << 1) /* print A register */ +#define REG_B (1 << 2) /* print B register */ +#define REG_E (1 << 3) /* print E register */ +#define REG_X (1 << 4) /* print X register */ +#define REG_Y (1 << 5) /* print Y register */ +#define REG_O (1 << 6) /* print O register */ +#define REG_P (1 << 7) /* print P register */ +#define REG_P_REL (1 << 8) /* print P register as relative */ + + +/* Operand processing encoding */ + +/* Base operand types. Note that all address encodings must be grouped together + after OP_ADR. +*/ + +#define OP_NUL 0 /* no operand */ +#define OP_IAR 1 /* 1-word int in A reg */ +#define OP_JAB 2 /* 2-word int in A/B regs */ +#define OP_FAB 3 /* 2-word FP const in A/B regs */ +#define OP_CON 4 /* inline 1-word constant */ +#define OP_VAR 5 /* inline 1-word variable */ + +#define OP_ADR 6 /* inline address */ +#define OP_ADK 7 /* addr of 1-word int const */ +#define OP_ADD 8 /* addr of 2-word int const */ +#define OP_ADF 9 /* addr of 2-word FP const */ +#define OP_ADX 10 /* addr of 3-word FP const */ +#define OP_ADT 11 /* addr of 4-word FP const */ +#define OP_ADE 12 /* addr of 5-word FP const */ + +#define OP_N_FLAGS 4 /* number of bits needed for flags */ +#define OP_M_FLAGS ((1 << OP_N_FLAGS) - 1) /* mask for flag bits */ + +#define OP_N_F (8 * sizeof (uint32) / OP_N_FLAGS) /* max number of op fields */ + +#define OP_V_F1 (0 * OP_N_FLAGS) /* 1st operand field */ +#define OP_V_F2 (1 * OP_N_FLAGS) /* 2nd operand field */ +#define OP_V_F3 (2 * OP_N_FLAGS) /* 3rd operand field */ +#define OP_V_F4 (3 * OP_N_FLAGS) /* 4th operand field */ +#define OP_V_F5 (4 * OP_N_FLAGS) /* 5th operand field */ +#define OP_V_F6 (5 * OP_N_FLAGS) /* 6th operand field */ +#define OP_V_F7 (6 * OP_N_FLAGS) /* 7th operand field */ +#define OP_V_F8 (7 * OP_N_FLAGS) /* 8th operand field */ + +/* Operand processing patterns */ + +#define OP_N (OP_NUL << OP_V_F1) +#define OP_I (OP_IAR << OP_V_F1) +#define OP_J (OP_JAB << OP_V_F1) +#define OP_R (OP_FAB << OP_V_F1) +#define OP_C (OP_CON << OP_V_F1) +#define OP_V (OP_VAR << OP_V_F1) +#define OP_A (OP_ADR << OP_V_F1) +#define OP_K (OP_ADK << OP_V_F1) +#define OP_D (OP_ADD << OP_V_F1) +#define OP_X (OP_ADX << OP_V_F1) +#define OP_T (OP_ADT << OP_V_F1) +#define OP_E (OP_ADE << OP_V_F1) + +#define OP_IA ((OP_IAR << OP_V_F1) | (OP_ADR << OP_V_F2)) +#define OP_JA ((OP_JAB << OP_V_F1) | (OP_ADR << OP_V_F2)) +#define OP_JD ((OP_JAB << OP_V_F1) | (OP_ADD << OP_V_F2)) +#define OP_RC ((OP_FAB << OP_V_F1) | (OP_CON << OP_V_F2)) +#define OP_RK ((OP_FAB << OP_V_F1) | (OP_ADK << OP_V_F2)) +#define OP_RF ((OP_FAB << OP_V_F1) | (OP_ADF << OP_V_F2)) +#define OP_CV ((OP_CON << OP_V_F1) | (OP_VAR << OP_V_F2)) +#define OP_AC ((OP_ADR << OP_V_F1) | (OP_CON << OP_V_F2)) +#define OP_AA ((OP_ADR << OP_V_F1) | (OP_ADR << OP_V_F2)) +#define OP_AK ((OP_ADR << OP_V_F1) | (OP_ADK << OP_V_F2)) +#define OP_AX ((OP_ADR << OP_V_F1) | (OP_ADX << OP_V_F2)) +#define OP_AT ((OP_ADR << OP_V_F1) | (OP_ADT << OP_V_F2)) +#define OP_KV ((OP_ADK << OP_V_F1) | (OP_VAR << OP_V_F2)) +#define OP_KA ((OP_ADK << OP_V_F1) | (OP_ADR << OP_V_F2)) +#define OP_KK ((OP_ADK << OP_V_F1) | (OP_ADK << OP_V_F2)) + +#define OP_IIF ((OP_IAR << OP_V_F1) | (OP_IAR << OP_V_F2) | \ + (OP_ADF << OP_V_F3)) + +#define OP_IAT ((OP_IAR << OP_V_F1) | (OP_ADR << OP_V_F2) | \ + (OP_ADT << OP_V_F3)) + +#define OP_CVA ((OP_CON << OP_V_F1) | (OP_VAR << OP_V_F2) | \ + (OP_ADR << OP_V_F3)) + +#define OP_AAA ((OP_ADR << OP_V_F1) | (OP_ADR << OP_V_F2) | \ + (OP_ADR << OP_V_F3)) + +#define OP_AAF ((OP_ADR << OP_V_F1) | (OP_ADR << OP_V_F2) | \ + (OP_ADF << OP_V_F3)) + +#define OP_AAX ((OP_ADR << OP_V_F1) | (OP_ADR << OP_V_F2) | \ + (OP_ADX << OP_V_F3)) + +#define OP_AAT ((OP_ADR << OP_V_F1) | (OP_ADR << OP_V_F2) | \ + (OP_ADT << OP_V_F3)) + +#define OP_AKA ((OP_ADR << OP_V_F1) | (OP_ADK << OP_V_F2) | \ + (OP_ADR << OP_V_F3)) + +#define OP_AKK ((OP_ADR << OP_V_F1) | (OP_ADK << OP_V_F2) | \ + (OP_ADK << OP_V_F3)) + +#define OP_AXX ((OP_ADR << OP_V_F1) | (OP_ADX << OP_V_F2) | \ + (OP_ADX << OP_V_F3)) + +#define OP_ATT ((OP_ADR << OP_V_F1) | (OP_ADT << OP_V_F2) | \ + (OP_ADT << OP_V_F3)) + +#define OP_AEE ((OP_ADR << OP_V_F1) | (OP_ADE << OP_V_F2) | \ + (OP_ADE << OP_V_F3)) + +#define OP_AAXX ((OP_ADR << OP_V_F1) | (OP_ADR << OP_V_F2) | \ + (OP_ADX << OP_V_F3) | (OP_ADX << OP_V_F4)) + +#define OP_AAFF ((OP_ADR << OP_V_F1) | (OP_ADR << OP_V_F2) | \ + (OP_ADF << OP_V_F3) | (OP_ADF << OP_V_F4)) + +#define OP_AAKK ((OP_ADR << OP_V_F1) | (OP_ADR << OP_V_F2) | \ + (OP_ADK << OP_V_F3) | (OP_ADK << OP_V_F4)) + +#define OP_KKKK ((OP_ADK << OP_V_F1) | (OP_ADK << OP_V_F2) | \ + (OP_ADK << OP_V_F3) | (OP_ADK << OP_V_F4)) + +#define OP_AAAKK ((OP_ADR << OP_V_F1) | (OP_ADR << OP_V_F2) | \ + (OP_ADR << OP_V_F3) | (OP_ADK << OP_V_F4) | \ + (OP_ADK << OP_V_F5)) + +#define OP_AKAKK ((OP_ADR << OP_V_F1) | (OP_ADK << OP_V_F2) | \ + (OP_ADR << OP_V_F3) | (OP_ADK << OP_V_F4) | \ + (OP_ADK << OP_V_F5)) + +#define OP_AAACCC ((OP_ADR << OP_V_F1) | (OP_ADR << OP_V_F2) | \ + (OP_ADR << OP_V_F3) | (OP_CON << OP_V_F4) | \ + (OP_CON << OP_V_F5) | (OP_CON << OP_V_F6)) + +#define OP_AAFFKK ((OP_ADR << OP_V_F1) | (OP_ADR << OP_V_F2) | \ + (OP_ADF << OP_V_F3) | (OP_ADF << OP_V_F4) | \ + (OP_ADK << OP_V_F5) | (OP_ADK << OP_V_F6)) + +#define OP_AAKAKK ((OP_ADR << OP_V_F1) | (OP_ADR << OP_V_F2) | \ + (OP_ADK << OP_V_F3) | (OP_ADR << OP_V_F4) | \ + (OP_ADK << OP_V_F5) | (OP_ADK << OP_V_F6)) + +#define OP_CATAKK ((OP_CON << OP_V_F1) | (OP_ADR << OP_V_F2) | \ + (OP_ADT << OP_V_F3) | (OP_ADR << OP_V_F4) | \ + (OP_ADK << OP_V_F5) | (OP_ADK << OP_V_F6)) + +#define OP_CCCACC ((OP_CON << OP_V_F1) | (OP_CON << OP_V_F2) | \ + (OP_CON << OP_V_F3) | (OP_ADR << OP_V_F4) | \ + (OP_CON << OP_V_F5) | (OP_CON << OP_V_F6)) + +#define OP_AAAFFKK ((OP_ADR << OP_V_F1) | (OP_ADR << OP_V_F2) | \ + (OP_ADR << OP_V_F3) | (OP_ADF << OP_V_F4) | \ + (OP_ADF << OP_V_F5) | (OP_ADK << OP_V_F6) | \ + (OP_ADK << OP_V_F7)) + +#define OP_AKAKAKK ((OP_ADR << OP_V_F1) | (OP_ADK << OP_V_F2) | \ + (OP_ADR << OP_V_F3) | (OP_ADK << OP_V_F4) | \ + (OP_ADR << OP_V_F5) | (OP_ADK << OP_V_F6) | \ + (OP_ADK << OP_V_F7)) + +#define OP_AAKAKAKK ((OP_ADR << OP_V_F1) | (OP_ADR << OP_V_F2) | \ + (OP_ADK << OP_V_F3) | (OP_ADR << OP_V_F4) | \ + (OP_ADK << OP_V_F5) | (OP_ADR << OP_V_F6) | \ + (OP_ADK << OP_V_F7) | (OP_ADK << OP_V_F8)) + +#define OP_CCACACCA ((OP_CON << OP_V_F1) | (OP_CON << OP_V_F2) | \ + (OP_ADR << OP_V_F3) | (OP_CON << OP_V_F4) | \ + (OP_ADR << OP_V_F5) | (OP_CON << OP_V_F6) | \ + (OP_CON << OP_V_F7) | (OP_ADR << OP_V_F8)) + + +/* Operand precisions (compatible with F-Series FPP): + + - S = 1-word integer + - D = 2-word integer + - F = 2-word single-precision floating-point + - X = 3-word extended-precision floating-point + - T = 4-word double-precision floating-point + - E = 5-word expanded-exponent floating-point + - A = null operand (operand is in FPP accumulator) + + 5-word floating-point numbers are supported by the F-Series Floating-Point + Processor hardware, but the instruction codes are not documented. + + Note that ordering is important, as we depend on the "fp" type codes to + reflect the number of words needed. +*/ + +typedef enum { in_s, in_d, fp_f, fp_x, fp_t, fp_e, fp_a } OPSIZE; + + +/* Conversion from operand size to word count */ + +#define TO_COUNT(s) ((s == fp_a) ? 0 : (uint32) (s + (s < fp_f))) + + +/* HP in-memory representation of a packed floating-point number. + Actual value will use two, three, four, or five words, as needed. +*/ + +typedef uint16 FPK[5]; + + +/* Operand processing types. + + NOTE: Microsoft VC++ 6.0 does not support the C99 standard, so we cannot + initialize unions by arbitrary variant ("designated initializers"). + Therefore, we follow the C90 form of initializing via the first named + variant. The FPK variant must appear first in the OP structure, as we define + a number of FPK constants in other modules. +*/ + +typedef union { /* general operand */ + FPK fpk; /* floating-point value */ + uint16 word; /* 16-bit integer */ + uint32 dword; /* 32-bit integer */ + } OP; + +typedef OP OPS[OP_N_F]; /* operand array */ + +typedef uint32 OP_PAT; /* operand pattern */ + + +/* Microcode dispatcher functions (grouped by cpu module number) */ + +extern t_stat cpu_ds (uint32 IR, uint32 intrq); /* [0] Distributed System stub */ +extern t_stat cpu_user (uint32 IR, uint32 intrq); /* [0] User firmware dispatcher */ +extern t_stat cpu_user_20 (uint32 IR, uint32 intrq); /* [0] Module 20 user microprograms stub */ + +extern t_stat cpu_eau (uint32 IR, uint32 intrq); /* [1] EAU group simulator */ +extern t_stat cpu_uig_0 (uint32 IR, uint32 intrq, uint32 iotrap); /* [1] UIG group 0 dispatcher */ +extern t_stat cpu_uig_1 (uint32 IR, uint32 intrq, uint32 iotrap); /* [1] UIG group 1 dispatcher */ + +#if !defined (HAVE_INT64) /* int64 support unavailable */ +extern t_stat cpu_fp (uint32 IR, uint32 intrq); /* [2] Firmware Floating Point */ +#endif +extern t_stat cpu_dms (uint32 IR, uint32 intrq); /* [2] Dynamic mapping system */ +extern t_stat cpu_eig (uint32 IR, uint32 intrq); /* [2] Extended instruction group */ +extern t_stat cpu_iop (uint32 IR, uint32 intrq); /* [2] 2000 I/O Processor */ + +extern t_stat cpu_ffp (uint32 IR, uint32 intrq); /* [3] Fast FORTRAN Processor */ +extern t_stat cpu_dbi (uint32 IR, uint32 intrq); /* [3] Double-Integer instructions */ + +#if defined (HAVE_INT64) /* int64 support available */ +extern t_stat cpu_fpp (uint32 IR, uint32 intrq); /* [4] Floating Point Processor */ +extern t_stat cpu_sis (uint32 IR, uint32 intrq); /* [4] Scientific Instruction Set */ +#endif + +extern t_stat cpu_rte_vma (uint32 IR, uint32 intrq); /* [5] RTE-6 VMA */ +extern t_stat cpu_rte_ema (uint32 IR, uint32 intrq); /* [5] RTE-IV EMA */ + +extern t_stat cpu_rte_os (uint32 IR, uint32 intrq, uint32 iotrap); /* [6] RTE-6 OS */ + +#if defined (HAVE_INT64) /* int64 support available */ +extern t_stat cpu_vis (uint32 IR, uint32 intrq); /* [7] Vector Instruction Set */ +extern t_stat cpu_signal (uint32 IR, uint32 intrq); /* [7] SIGNAL/1000 Instructions */ +#endif + + +/* Microcode helper functions */ + +extern OP ReadOp (uint32 va, OPSIZE precision); /* generalized operand read */ +extern void WriteOp (uint32 va, OP operand, OPSIZE precision); /* generalized operand write */ +extern t_stat cpu_ops (OP_PAT pattern, OPS op, uint32 irq); /* operand processor */ + +extern void fprint_ops (OP_PAT pattern, OPS op); /* debug print operands */ +extern void fprint_regs (char *caption, uint32 regs, uint32 base); /* debug print CPU registers */ + +/* implemented in hp2100_cpu5.c (RTE-IV EMA functions) */ + +extern t_stat cpu_ema_eres (uint32 *rtn, uint32 dtbl, uint32 atbl, t_bool debug); +extern t_stat cpu_ema_eseg (uint32 *rtn, uint32 ir, uint32 tbl, t_bool debug); +extern t_stat cpu_ema_vset (uint32 *rtn, OPS op, t_bool debug); + +#endif diff --git a/HP2100/hp2100_cpu2.c b/HP2100/hp2100_cpu2.c index e5dac17c..f303b8b6 100644 --- a/HP2100/hp2100_cpu2.c +++ b/HP2100/hp2100_cpu2.c @@ -1,1116 +1,1130 @@ -/* hp2100_cpu2.c: HP 2100/1000 FP/DMS/EIG/IOP instructions - - Copyright (c) 2005-2008, Robert M. Supnik - - 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 - ROBERT M SUPNIK 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 Robert M Supnik shall not be - used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from Robert M Supnik. - - CPU2 Floating-point, dynamic mapping, extended, and I/O processor - instructions - - 11-Sep-08 JDB Moved microcode function prototypes to hp2100_cpu1.h - 05-Sep-08 JDB Removed option-present tests (now in UIG dispatchers) - 05-Aug-08 JDB Updated mp_dms_jmp calling sequence - Fixed DJP, SJP, and UJP jump target validation - 30-Jul-08 JDB RVA/B conditionally updates dms_vr before returning value - 19-Dec-06 JDB DMS self-test now executes as NOP on 1000-M - 01-Dec-06 JDB Substitutes FPP for firmware FP if HAVE_INT64 - 26-Sep-06 JDB Moved from hp2100_cpu1.c to simplify extensions - 22-Feb-05 JDB Fixed missing MPCK on JRS target - 21-Jan-05 JDB Reorganized CPU option and operand processing flags - Split code along microcode modules - 15-Jan-05 RMS Cloned from hp2100_cpu.c - - Primary references: - - HP 1000 M/E/F-Series Computers Technical Reference Handbook - (5955-0282, Mar-1980) - - HP 1000 M/E/F-Series Computers Engineering and Reference Documentation - (92851-90001, Mar-1981) - - Macro/1000 Reference Manual (92059-90001, Dec-1992) - - Additional references are listed with the associated firmware - implementations, as are the HP option model numbers pertaining to the - applicable CPUs. -*/ - -#include "hp2100_defs.h" -#include "hp2100_cpu.h" -#include "hp2100_cpu1.h" - -#if !defined (HAVE_INT64) /* int64 support unavailable */ - -#include "hp2100_fp.h" - - -/* Single-Precision Floating Point Instructions - - The 2100 and 1000 CPUs share the single-precision (two word) floating-point - instruction codes. Floating-point firmware was an option on the 2100 and was - standard on the 1000-M and E. The 1000-F had a standard hardware Floating - Point Processor that executed these six instructions and added extended- and - double-precision floating- point instructions, as well as double-integer - instructions (the FPP is simulated separately). - - Option implementation by CPU was as follows: - - 2114 2115 2116 2100 1000-M 1000-E 1000-F - ------ ------ ------ ------ ------ ------ ------ - N/A N/A N/A 12901A std std N/A - - The instruction codes for the 2100 and 1000-M/E systems are mapped to - routines as follows: - - Instr. 2100/1000-M/E Description - ------ ------------- ----------------------------------- - 105000 FAD Single real add - 105020 FSB Single real subtract - 105040 FMP Single real multiply - 105060 FDV Single real divide - 105100 FIX Single integer to single real fix - 105120 FLT Single real to single integer float - - Bits 3-0 are not decoded by these instructions, so FAD (e.g.) would be - executed by any instruction in the range 105000-105017. - - Implementation note: rather than have two simulators that each executes the - single-precision FP instruction set, we compile conditionally, based on the - availability of 64-bit integer support in the host compiler. 64-bit integers - are required for the FPP, so if they are available, then the FPP is used to - handle the six single-precision instructions for the 2100 and M/E-Series, and - this function is omitted. If support is unavailable, this function is used - instead. - - Implementation note: the operands to FAD, etc. are floating-point values, so - OP_F would normally be used. However, the firmware FP support routines want - floating-point operands as 32-bit integer values, so OP_D is used to achieve - this. -*/ - -static const OP_PAT op_fp[8] = { - OP_D, OP_D, OP_D, OP_D, /* FAD FSB FMP FDV */ - OP_N, OP_N, OP_N, OP_N /* FIX FLT --- --- */ - }; - -t_stat cpu_fp (uint32 IR, uint32 intrq) -{ -t_stat reason = SCPE_OK; -OPS op; -uint32 entry; - -entry = (IR >> 4) & 017; /* mask to entry point */ - -if (op_fp[entry] != OP_N) - if (reason = cpu_ops (op_fp[entry], op, intrq)) /* get instruction operands */ - return reason; - -switch (entry) { /* decode IR<7:4> */ - - case 000: /* FAD 105000 (OP_D) */ - O = f_as (op[0].dword, 0); /* add, upd ovflo */ - break; - - case 001: /* FSB 105020 (OP_D) */ - O = f_as (op[0].dword, 1); /* sub, upd ovflo */ - break; - - case 002: /* FMP 105040 (OP_D) */ - O = f_mul (op[0].dword); /* mul, upd ovflo */ - break; - - case 003: /* FDV 105060 (OP_D) */ - O = f_div (op[0].dword); /* div, upd ovflo */ - break; - - case 004: /* FIX 105100 (OP_N) */ - O = f_fix (); /* fix, upd ovflo */ - break; - - case 005: /* FLT 105120 (OP_N) */ - O = f_flt (); /* float, upd ovflo */ - break; - - default: /* should be impossible */ - return SCPE_IERR; - } - -return reason; -} - -#endif /* int64 support unavailable */ - - -/* Dynamic Mapping System - - The 1000 Dynamic Mapping System (DMS) consisted of the 12731A Memory - Expansion Module (MEM) card and 38 instructions to expand the basic 32K - logical address space to a 1024K physical space. The MEM provided four maps - of 32 mapping registers each: a system map, a user map, and two DCPC maps. - DMS worked in conjunction with memory protect to provide a "protected mode" - in which memory read and write violations could be trapped, and that - inhibited "privileged" instruction execution that attempted to alter the - memory mapping. - - Option implementation by CPU was as follows: - - 2114 2115 2116 2100 1000-M 1000-E 1000-F - ------ ------ ------ ------ ------ ------ ------ - N/A N/A N/A N/A 12976B 13307B std - - The instruction codes are mapped to routines as follows: - - Instr. 1000-M 1000-E/F Instr. 1000-M 1000-E/F - ------ ------ -------- ------ ------ -------- - 10x700 [xmm] [xmm] 10x720 XMM XMM - 10x701 [nop] [test] 10x721 XMS XMS - 10x702 MBI MBI 10x722 XM* XM* - 10x703 MBF MBF 10x723 [nop] [nop] - 10x704 MBW MBW 10x724 XL* XL* - 10x705 MWI MWI 10x725 XS* XS* - 10x706 MWF MWF 10x726 XC* XC* - 10x707 MWW MWW 10x727 LF* LF* - 10x710 SY* SY* 10x730 RS* RS* - - 10x711 US* US* 10x731 RV* RV* - 10x712 PA* PA* 10x732 DJP DJP - 10x713 PB* PB* 10x733 DJS DJS - 10x714 SSM SSM 10x734 SJP SJP - 10x715 JRS JRS 10x735 SJS SJS - 10x716 [nop] [nop] 10x736 UJP UJP - 10x717 [nop] [nop] 10x737 UJS UJS - - Instructions that use IR bit 9 to select the A or B register are designated - with a * above (e.g., 101710 is SYA, and 105710 is SYB). For those that do - not use this feature, either the 101xxx or 105xxx code will execute the - corresponding instruction, although the 105xxx form is the documented - instruction code. - - Implementation notes: - - 1. Instruction code 10x700 will execute the XMM instruction, although 10x720 - is the documented instruction value. - - 2. Instruction code 10x701 will complement the A or B register, as - indicated, on 1000-E and F-Series machines. This instruction is a NOP on - M-Series machines. - - 3. The DMS privilege violation rules are: - - load map and CTL5 set (XMM, XMS, XM*, SY*, US*, PA*, PB*) - - load state or fence and UMAP set (JRS, DJP, DJS, SJP, SJS, UJP, UJS, LF*) - - 4. The 1000 manual is incorrect in stating that M*I, M*W, XS* are - privileged. - - 5. The protected memory lower bound for the DJP, SJP, UJP, and JRS - instructions is 2. -*/ - -static const OP_PAT op_dms[32] = { - OP_N, OP_N, OP_N, OP_N, /* [xmm] [test] MBI MBF */ - OP_N, OP_N, OP_N, OP_N, /* MBW MWI MWF MWW */ - OP_N, OP_N, OP_N, OP_N, /* SYA/B USA/B PAA/B PBA/B */ - OP_A, OP_KA, OP_N, OP_N, /* SSM JRS nop nop */ - OP_N, OP_N, OP_N, OP_N, /* XMM XMS XMA/B nop */ - OP_A, OP_A, OP_A, OP_N, /* XLA/B XSA/B XCA/B LFA/B */ - OP_N, OP_N, OP_A, OP_A, /* RSA/B RVA/B DJP DJS */ - OP_A, OP_A, OP_A, OP_A /* SJP SJS UJP UJS */ - }; - -t_stat cpu_dms (uint32 IR, uint32 intrq) -{ -t_stat reason = SCPE_OK; -OPS op; -uint32 entry, absel; -uint32 i, t, mapi, mapj; - -absel = (IR & I_AB)? 1: 0; /* get A/B select */ -entry = IR & 037; /* mask to entry point */ - -if (op_dms[entry] != OP_N) - if (reason = cpu_ops (op_dms[entry], op, intrq)) /* get instruction operands */ - return reason; - -switch (entry) { /* decode IR<3:0> */ - -/* DMS module 1 */ - - case 000: /* [undefined] 105700 (OP_N) */ - goto XMM; /* decodes as XMM */ - - case 001: /* [self test] 105701 (OP_N) */ - if (UNIT_CPU_MODEL != UNIT_1000_M) /* executes as NOP on 1000-M */ - ABREG[absel] = ~ABREG[absel]; /* CMA or CMB */ - break; - - case 002: /* MBI 105702 (OP_N) */ - AR = AR & ~1; /* force A, B even */ - BR = BR & ~1; - while (XR != 0) { /* loop */ - t = ReadB (AR); /* read curr */ - WriteBA (BR, t); /* write alt */ - AR = (AR + 1) & DMASK; /* incr ptrs */ - BR = (BR + 1) & DMASK; - XR = (XR - 1) & DMASK; - if (XR && intrq && !(AR & 1)) { /* more, int, even? */ - PC = err_PC; /* stop for now */ - break; - } - } - break; - - case 003: /* MBF 105703 (OP_N) */ - AR = AR & ~1; /* force A, B even */ - BR = BR & ~1; - while (XR != 0) { /* loop */ - t = ReadBA (AR); /* read alt */ - WriteB (BR, t); /* write curr */ - AR = (AR + 1) & DMASK; /* incr ptrs */ - BR = (BR + 1) & DMASK; - XR = (XR - 1) & DMASK; - if (XR && intrq && !(AR & 1)) { /* more, int, even? */ - PC = err_PC; /* stop for now */ - break; - } - } - break; - - case 004: /* MBW 105704 (OP_N) */ - AR = AR & ~1; /* force A, B even */ - BR = BR & ~1; - while (XR != 0) { /* loop */ - t = ReadBA (AR); /* read alt */ - WriteBA (BR, t); /* write alt */ - AR = (AR + 1) & DMASK; /* incr ptrs */ - BR = (BR + 1) & DMASK; - XR = (XR - 1) & DMASK; - if (XR && intrq && !(AR & 1)) { /* more, int, even? */ - PC = err_PC; /* stop for now */ - break; - } - } - break; - - case 005: /* MWI 105705 (OP_N) */ - while (XR != 0) { /* loop */ - t = ReadW (AR & VAMASK); /* read curr */ - WriteWA (BR & VAMASK, t); /* write alt */ - AR = (AR + 1) & DMASK; /* incr ptrs */ - BR = (BR + 1) & DMASK; - XR = (XR - 1) & DMASK; - if (XR && intrq) { /* more and intr? */ - PC = err_PC; /* stop for now */ - break; - } - } - break; - - case 006: /* MWF 105706 (OP_N) */ - while (XR != 0) { /* loop */ - t = ReadWA (AR & VAMASK); /* read alt */ - WriteW (BR & VAMASK, t); /* write curr */ - AR = (AR + 1) & DMASK; /* incr ptrs */ - BR = (BR + 1) & DMASK; - XR = (XR - 1) & DMASK; - if (XR && intrq) { /* more and intr? */ - PC = err_PC; /* stop for now */ - break; - } - } - break; - - case 007: /* MWW 105707 (OP_N) */ - while (XR != 0) { /* loop */ - t = ReadWA (AR & VAMASK); /* read alt */ - WriteWA (BR & VAMASK, t); /* write alt */ - AR = (AR + 1) & DMASK; /* incr ptrs */ - BR = (BR + 1) & DMASK; - XR = (XR - 1) & DMASK; - if (XR && intrq) { /* more and intr? */ - PC = err_PC; /* stop for now */ - break; - } - } - break; - - case 010: /* SYA, SYB 10x710 (OP_N) */ - case 011: /* USA, USB 10x711 (OP_N) */ - case 012: /* PAA, PAB 10x712 (OP_N) */ - case 013: /* PBA, PBB 10x713 (OP_N) */ - mapi = (IR & 03) << VA_N_PAG; /* map base */ - if (ABREG[absel] & SIGN) { /* store? */ - for (i = 0; i < MAP_LNT; i++) { - t = dms_rmap (mapi + i); /* map to memory */ - WriteW ((ABREG[absel] + i) & VAMASK, t); - } - } - else { /* load */ - dms_viol (err_PC, MVI_PRV); /* priv if PRO */ - for (i = 0; i < MAP_LNT; i++) { - t = ReadW ((ABREG[absel] + i) & VAMASK); - dms_wmap (mapi + i, t); /* mem to map */ - } - } - ABREG[absel] = (ABREG[absel] + MAP_LNT) & DMASK; - break; - - case 014: /* SSM 105714 (OP_A) */ - WriteW (op[0].word, dms_upd_sr ()); /* store stat */ - break; - - case 015: /* JRS 105715 (OP_KA) */ - if (dms_ump) dms_viol (err_PC, MVI_PRV); /* priv viol if prot */ - dms_enb = 0; /* assume off */ - dms_ump = SMAP; - if (op[0].word & 0100000) { /* set enable? */ - dms_enb = 1; - if (op[0].word & 0040000) dms_ump = UMAP; /* set/clr usr */ - } - mp_dms_jmp (op[1].word, 2); /* mpck jmp target */ - PCQ_ENTRY; /* save old PC */ - PC = op[1].word; /* jump */ - ion_defer = 1; /* defer intr */ - break; - -/* DMS module 2 */ - - case 020: /* XMM 105720 (OP_N) */ - XMM: - if (XR == 0) break; /* nop? */ - while (XR != 0) { /* loop */ - if (XR & SIGN) { /* store? */ - t = dms_rmap (AR); /* map to mem */ - WriteW (BR & VAMASK, t); - XR = (XR + 1) & DMASK; - } - else { /* load */ - dms_viol (err_PC, MVI_PRV); /* priv viol if prot */ - t = ReadW (BR & VAMASK); /* mem to map */ - dms_wmap (AR, t); - XR = (XR - 1) & DMASK; - } - AR = (AR + 1) & DMASK; - BR = (BR + 1) & DMASK; - if (intrq && ((XR & 017) == 017)) { /* intr, grp of 16? */ - PC = err_PC; /* stop for now */ - break; - } - } - break; - - case 021: /* XMS 105721 (OP_N) */ - if ((XR & SIGN) || (XR == 0)) break; /* nop? */ - dms_viol (err_PC, MVI_PRV); /* priv viol if prot */ - while (XR != 0) { - dms_wmap (AR, BR); /* AR to map */ - XR = (XR - 1) & DMASK; - AR = (AR + 1) & DMASK; - BR = (BR + 1) & DMASK; - if (intrq && ((XR & 017) == 017)) { /* intr, grp of 16? */ - PC = err_PC; - break; - } - } - break; - - case 022: /* XMA, XMB 10x722 (OP_N) */ - dms_viol (err_PC, MVI_PRV); /* priv viol if prot */ - if (ABREG[absel] & 0100000) mapi = UMAP; - else mapi = SMAP; - if (ABREG[absel] & 0000001) mapj = PBMAP; - else mapj = PAMAP; - for (i = 0; i < MAP_LNT; i++) { - t = dms_rmap (mapi + i); /* read map */ - dms_wmap (mapj + i, t); /* write map */ - } - break; - - case 024: /* XLA, XLB 10x724 (OP_A) */ - ABREG[absel] = ReadWA (op[0].word); /* load alt */ - break; - - case 025: /* XSA, XSB 10x725 (OP_A) */ - WriteWA (op[0].word, ABREG[absel]); /* store alt */ - break; - - case 026: /* XCA, XCB 10x726 (OP_A) */ - if (ABREG[absel] != ReadWA (op[0].word)) /* compare alt */ - PC = (PC + 1) & VAMASK; - break; - - case 027: /* LFA, LFB 10x727 (OP_N) */ - if (dms_ump) dms_viol (err_PC, MVI_PRV); /* priv viol if prot */ - dms_sr = (dms_sr & ~(MST_FLT | MST_FENCE)) | - (ABREG[absel] & (MST_FLT | MST_FENCE)); - break; - - case 030: /* RSA, RSB 10x730 (OP_N) */ - ABREG[absel] = dms_upd_sr (); /* save stat */ - break; - - case 031: /* RVA, RVB 10x731 (OP_N) */ - ABREG[absel] = dms_upd_vr (err_PC); /* return updated violation register */ - break; - - case 032: /* DJP 105732 (OP_A) */ - if (dms_ump) dms_viol (err_PC, MVI_PRV); /* priv viol if prot */ - dms_enb = 0; /* disable map */ - dms_ump = SMAP; - mp_dms_jmp (op[0].word, 2); /* validate jump addr */ - PCQ_ENTRY; /* save curr PC */ - PC = op[0].word; /* new PC */ - ion_defer = 1; - break; - - case 033: /* DJS 105733 (OP_A) */ - if (dms_ump) dms_viol (err_PC, MVI_PRV); /* priv viol if prot */ - WriteW (op[0].word, PC); /* store ret addr */ - PCQ_ENTRY; /* save curr PC */ - PC = (op[0].word + 1) & VAMASK; /* new PC */ - dms_enb = 0; /* disable map */ - dms_ump = SMAP; - ion_defer = 1; /* defer intr */ - break; - - case 034: /* SJP 105734 (OP_A) */ - if (dms_ump) dms_viol (err_PC, MVI_PRV); /* priv viol if prot */ - dms_enb = 1; /* enable system */ - dms_ump = SMAP; - mp_dms_jmp (op[0].word, 2); /* validate jump addr */ - PCQ_ENTRY; /* save curr PC */ - PC = op[0].word; /* jump */ - ion_defer = 1; /* defer intr */ - break; - - case 035: /* SJS 105735 (OP_A) */ - if (dms_ump) dms_viol (err_PC, MVI_PRV); /* priv viol if prot */ - t = PC; /* save retn addr */ - PCQ_ENTRY; /* save curr PC */ - PC = (op[0].word + 1) & VAMASK; /* new PC */ - dms_enb = 1; /* enable system */ - dms_ump = SMAP; - WriteW (op[0].word, t); /* store ret addr */ - ion_defer = 1; /* defer intr */ - break; - - case 036: /* UJP 105736 (OP_A) */ - if (dms_ump) dms_viol (err_PC, MVI_PRV); /* priv viol if prot */ - dms_enb = 1; /* enable user */ - dms_ump = UMAP; - mp_dms_jmp (op[0].word, 2); /* validate jump addr */ - PCQ_ENTRY; /* save curr PC */ - PC = op[0].word; /* jump */ - ion_defer = 1; /* defer intr */ - break; - - case 037: /* UJS 105737 (OP_A) */ - if (dms_ump) dms_viol (err_PC, MVI_PRV); /* priv viol if prot */ - t = PC; /* save retn addr */ - PCQ_ENTRY; /* save curr PC */ - PC = (op[0].word + 1) & VAMASK; /* new PC */ - dms_enb = 1; /* enable user */ - dms_ump = UMAP; - WriteW (op[0].word, t); /* store ret addr */ - ion_defer = 1; /* defer intr */ - break; - - default: /* others NOP */ - break; - } - -return reason; -} - - -/* Extended Instruction Group - - The Extended Instruction Group (EIG) adds 32 index and 10 bit/byte/word - manipulation instructions to the 1000 base set. These instructions - use the new X and Y index registers that were added to the 1000. - - Option implementation by CPU was as follows: - - 2114 2115 2116 2100 1000-M 1000-E 1000-F - ------ ------ ------ ------ ------ ------ ------ - N/A N/A N/A N/A std std std - - The instruction codes are mapped to routines as follows: - - Instr. 1000-M/E/F Instr. 1000-M/E/F - ------ ---------- ------ ---------- - 10x740 S*X 10x760 ISX - 10x741 C*X 10x761 DSX - 10x742 L*X 10x762 JLY - 10x743 STX 10x763 LBT - 10x744 CX* 10x764 SBT - 10x745 LDX 10x765 MBT - 10x746 ADX 10x766 CBT - 10x747 X*X 10x767 SFB - - 10x750 S*Y 10x770 ISY - 10x751 C*Y 10x771 DSY - 10x752 L*Y 10x772 JPY - 10x753 STY 10x773 SBS - 10x754 CY* 10x774 CBS - 10x755 LDY 10x775 TBS - 10x756 ADY 10x776 CMW - 10x757 X*Y 10x777 MVW - - Instructions that use IR bit 9 to select the A or B register are designated - with a * above (e.g., 101740 is SAX, and 105740 is SBX). For those that do - not use this feature, either the 101xxx or 105xxx code will execute the - corresponding instruction, although the 105xxx form is the documented - instruction code. - - Implementation notes: - - 1. The LBT, SBT, MBT, and MVW instructions are used as part of the 2100 IOP - implementation. When so called, the MBT and MVW instructions have the - additional restriction that the count must be positive. - - 2. The protected memory lower bound for the JLY and JPY instructions is 0. -*/ - -static const OP_PAT op_eig[32] = { - OP_A, OP_N, OP_A, OP_A, /* S*X C*X L*X STX */ - OP_N, OP_K, OP_K, OP_N, /* CX* LDX ADX X*X */ - OP_A, OP_N, OP_A, OP_A, /* S*Y C*Y L*Y STY */ - OP_N, OP_K, OP_K, OP_N, /* CY* LDY ADY X*Y */ - OP_N, OP_N, OP_A, OP_N, /* ISX DSX JLY LBT */ - OP_N, OP_KV, OP_KV, OP_N, /* SBT MBT CBT SFB */ - OP_N, OP_N, OP_C, OP_KA, /* ISY DSY JPY SBS */ - OP_KA, OP_KK, OP_KV, OP_KV /* CBS TBS CMW MVW */ - }; - -t_stat cpu_eig (uint32 IR, uint32 intrq) -{ -t_stat reason = SCPE_OK; -OPS op; -uint32 entry, absel; -uint32 t, v1, v2, wc; -int32 sop1, sop2; - -absel = (IR & I_AB)? 1: 0; /* get A/B select */ -entry = IR & 037; /* mask to entry point */ - -if (op_eig[entry] != OP_N) - if (reason = cpu_ops (op_eig[entry], op, intrq)) /* get instruction operands */ - return reason; - -switch (entry) { /* decode IR<4:0> */ - -/* EIG module 1 */ - - case 000: /* SAX, SBX 10x740 (OP_A) */ - op[0].word = (op[0].word + XR) & VAMASK; /* indexed addr */ - WriteW (op[0].word, ABREG[absel]); /* store */ - break; - - case 001: /* CAX, CBX 10x741 (OP_N) */ - XR = ABREG[absel]; /* copy to XR */ - break; - - case 002: /* LAX, LBX 10x742 (OP_A) */ - op[0].word = (op[0].word + XR) & VAMASK; /* indexed addr */ - ABREG[absel] = ReadW (op[0].word); /* load */ - break; - - case 003: /* STX 105743 (OP_A) */ - WriteW (op[0].word, XR); /* store XR */ - break; - - case 004: /* CXA, CXB 10x744 (OP_N) */ - ABREG[absel] = XR; /* copy from XR */ - break; - - case 005: /* LDX 105745 (OP_K)*/ - XR = op[0].word; /* load XR */ - break; - - case 006: /* ADX 105746 (OP_K) */ - t = XR + op[0].word; /* add to XR */ - if (t > DMASK) E = 1; /* set E, O */ - if (((~XR ^ op[0].word) & (XR ^ t)) & SIGN) O = 1; - XR = t & DMASK; - break; - - case 007: /* XAX, XBX 10x747 (OP_N) */ - t = XR; /* exchange XR */ - XR = ABREG[absel]; - ABREG[absel] = t; - break; - - case 010: /* SAY, SBY 10x750 (OP_A) */ - op[0].word = (op[0].word + YR) & VAMASK; /* indexed addr */ - WriteW (op[0].word, ABREG[absel]); /* store */ - break; - - case 011: /* CAY, CBY 10x751 (OP_N) */ - YR = ABREG[absel]; /* copy to YR */ - break; - - case 012: /* LAY, LBY 10x752 (OP_A) */ - op[0].word = (op[0].word + YR) & VAMASK; /* indexed addr */ - ABREG[absel] = ReadW (op[0].word); /* load */ - break; - - case 013: /* STY 105753 (OP_A) */ - WriteW (op[0].word, YR); /* store YR */ - break; - - case 014: /* CYA, CYB 10x754 (OP_N) */ - ABREG[absel] = YR; /* copy from YR */ - break; - - case 015: /* LDY 105755 (OP_K) */ - YR = op[0].word; /* load YR */ - break; - - case 016: /* ADY 105756 (OP_K) */ - t = YR + op[0].word; /* add to YR */ - if (t > DMASK) E = 1; /* set E, O */ - if (((~YR ^ op[0].word) & (YR ^ t)) & SIGN) O = 1; - YR = t & DMASK; - break; - - case 017: /* XAY, XBY 10x757 (OP_N) */ - t = YR; /* exchange YR */ - YR = ABREG[absel]; - ABREG[absel] = t; - break; - -/* EIG module 2 */ - - case 020: /* ISX 105760 (OP_N) */ - XR = (XR + 1) & DMASK; /* incr XR */ - if (XR == 0) PC = (PC + 1) & VAMASK; /* skip if zero */ - break; - - case 021: /* DSX 105761 (OP_N) */ - XR = (XR - 1) & DMASK; /* decr XR */ - if (XR == 0) PC = (PC + 1) & VAMASK; /* skip if zero */ - break; - - case 022: /* JLY 105762 (OP_A) */ - mp_dms_jmp (op[0].word, 0); /* validate jump addr */ - PCQ_ENTRY; - YR = PC; /* ret addr to YR */ - PC = op[0].word; /* jump */ - break; - - case 023: /* LBT 105763 (OP_N) */ - AR = ReadB (BR); /* load byte */ - BR = (BR + 1) & DMASK; /* incr ptr */ - break; - - case 024: /* SBT 105764 (OP_N) */ - WriteB (BR, AR); /* store byte */ - BR = (BR + 1) & DMASK; /* incr ptr */ - break; - - case 025: /* MBT 105765 (OP_KV) */ - wc = ReadW (op[1].word); /* get continuation count */ - if (wc == 0) wc = op[0].word; /* none? get initiation count */ - if ((wc & SIGN) && - (UNIT_CPU_TYPE == UNIT_TYPE_2100)) - break; /* < 0 is NOP for 2100 IOP */ - while (wc != 0) { /* while count */ - WriteW (op[1].word, wc); /* for MP abort */ - t = ReadB (AR); /* move byte */ - WriteB (BR, t); - AR = (AR + 1) & DMASK; /* incr src */ - BR = (BR + 1) & DMASK; /* incr dst */ - wc = (wc - 1) & DMASK; /* decr cnt */ - if (intrq && wc) { /* intr, more to do? */ - PC = err_PC; /* back up PC */ - break; - } - } - WriteW (op[1].word, wc); /* clean up inline */ - break; - - case 026: /* CBT 105766 (OP_KV) */ - wc = ReadW (op[1].word); /* get continuation count */ - if (wc == 0) wc = op[0].word; /* none? get initiation count */ - while (wc != 0) { /* while count */ - WriteW (op[1].word, wc); /* for MP abort */ - v1 = ReadB (AR); /* get src1 */ - v2 = ReadB (BR); /* get src2 */ - if (v1 != v2) { /* compare */ - PC = (PC + 1 + (v1 > v2)) & VAMASK; - BR = (BR + wc) & DMASK; /* update BR */ - wc = 0; /* clr interim */ - break; - } - AR = (AR + 1) & DMASK; /* incr src1 */ - BR = (BR + 1) & DMASK; /* incr src2 */ - wc = (wc - 1) & DMASK; /* decr cnt */ - if (intrq && wc) { /* intr, more to do? */ - PC = err_PC; /* back up PC */ - break; - } - } - WriteW (op[1].word, wc); /* clean up inline */ - break; - - case 027: /* SFB 105767 (OP_N) */ - v1 = AR & 0377; /* test byte */ - v2 = (AR >> 8) & 0377; /* term byte */ - for (;;) { /* scan */ - t = ReadB (BR); /* read byte */ - if (t == v1) break; /* test match? */ - BR = (BR + 1) & DMASK; - if (t == v2) { /* term match? */ - PC = (PC + 1) & VAMASK; - break; - } - if (intrq) { /* int pending? */ - PC = err_PC; /* back up PC */ - break; - } - } - break; - - case 030: /* ISY 105770 (OP_N) */ - YR = (YR + 1) & DMASK; /* incr YR */ - if (YR == 0) PC = (PC + 1) & VAMASK; /* skip if zero */ - break; - - case 031: /* DSY 105771 (OP_N) */ - YR = (YR - 1) & DMASK; /* decr YR */ - if (YR == 0) PC = (PC + 1) & VAMASK; /* skip if zero */ - break; - - case 032: /* JPY 105772 (OP_C) */ - op[0].word = (op[0].word + YR) & VAMASK; /* index, no indir */ - mp_dms_jmp (op[0].word, 0); /* validate jump addr */ - PCQ_ENTRY; - PC = op[0].word; /* jump */ - break; - - case 033: /* SBS 105773 (OP_KA) */ - WriteW (op[1].word, /* set bits */ - ReadW (op[1].word) | op[0].word); - break; - - case 034: /* CBS 105774 (OP_KA) */ - WriteW (op[1].word, /* clear bits */ - ReadW (op[1].word) & ~op[0].word); - break; - - case 035: /* TBS 105775 (OP_KK) */ - if ((op[1].word & op[0].word) != op[0].word) /* test bits */ - PC = (PC + 1) & VAMASK; - break; - - case 036: /* CMW 105776 (OP_KV) */ - wc = ReadW (op[1].word); /* get continuation count */ - if (wc == 0) wc = op[0].word; /* none? get initiation count */ - while (wc != 0) { /* while count */ - WriteW (op[1].word, wc); /* for abort */ - v1 = ReadW (AR & VAMASK); /* first op */ - v2 = ReadW (BR & VAMASK); /* second op */ - sop1 = (int32) SEXT (v1); /* signed */ - sop2 = (int32) SEXT (v2); - if (sop1 != sop2) { /* compare */ - PC = (PC + 1 + (sop1 > sop2)) & VAMASK; - BR = (BR + wc) & DMASK; /* update BR */ - wc = 0; /* clr interim */ - break; - } - AR = (AR + 1) & DMASK; /* incr src1 */ - BR = (BR + 1) & DMASK; /* incr src2 */ - wc = (wc - 1) & DMASK; /* decr cnt */ - if (intrq && wc) { /* intr, more to do? */ - PC = err_PC; /* back up PC */ - break; - } - } - WriteW (op[1].word, wc); /* clean up inline */ - break; - - case 037: /* MVW 105777 (OP_KV) */ - wc = ReadW (op[1].word); /* get continuation count */ - if (wc == 0) wc = op[0].word; /* none? get initiation count */ - if ((wc & SIGN) && - (UNIT_CPU_TYPE == UNIT_TYPE_2100)) - break; /* < 0 is NOP for 2100 IOP */ - while (wc != 0) { /* while count */ - WriteW (op[1].word, wc); /* for abort */ - t = ReadW (AR & VAMASK); /* move word */ - WriteW (BR & VAMASK, t); - AR = (AR + 1) & DMASK; /* incr src */ - BR = (BR + 1) & DMASK; /* incr dst */ - wc = (wc - 1) & DMASK; /* decr cnt */ - if (intrq && wc) { /* intr, more to do? */ - PC = err_PC; /* back up PC */ - break; - } - } - WriteW (op[1].word, wc); /* clean up inline */ - break; - - } - -return reason; -} - - -/* 2000 I/O Processor - - The IOP accelerates certain operations of the HP 2000 Time-Share BASIC system - I/O processor. Most 2000 systems were delivered with 2100 CPUs, although IOP - microcode was developed for the 1000-M and 1000-E. As the I/O processors - were specific to the 2000 system, general compatibility with other CPU - microcode options was unnecessary, and indeed no other options were possible - for the 2100. - - Option implementation by CPU was as follows: - - 2114 2115 2116 2100 1000-M 1000-E 1000-F - ------ ------ ------ ------ ------ ------ ------ - N/A N/A N/A 13206A 13207A 22702A N/A - - The routines are mapped to instruction codes as follows: - - Instr. 2100 1000-M/E Description - ------ ---------- ---------- -------------------------------------------- - SAI 105060-117 101400-037 Store A indexed by B (+/- offset in IR<4:0>) - LAI 105020-057 105400-037 Load A indexed by B (+/- offset in IR<4:0>) - CRC 105150 105460 Generate CRC - REST 105340 105461 Restore registers from stack - READF 105220 105462 Read F register (stack pointer) - INS -- 105463 Initialize F register (stack pointer) - ENQ 105240 105464 Enqueue - PENQ 105257 105465 Priority enqueue - DEQ 105260 105466 Dequeue - TRSLT 105160 105467 Translate character - ILIST 105000 105470 Indirect address list (similar to $SETP) - PRFEI 105222 105471 Power fail exit with I/O - PRFEX 105223 105472 Power fail exit - PRFIO 105221 105473 Power fail I/O - SAVE 105362 105474 Save registers to stack - - MBYTE 105120 105765 Move bytes (MBT) - MWORD 105200 105777 Move words (MVW) - SBYTE 105300 105764 Store byte (SBT) - LBYTE 105320 105763 Load byte (LBT) - - The INS instruction was not required in the 2100 implementation because the - stack pointer was actually the memory protect fence register and so could be - loaded directly with an OTA/B 05. Also, the 1000 implementation did not - offer the MBYTE, MWORD, SBYTE, and LBYTE instructions because the equivalent - instructions from the standard Extended Instruction Group were used instead. - - Note that the 2100 MBYTE and MWORD instructions operate slightly differently - from the 1000 MBT and MVW instructions. Specifically, the move count is - signed on the 2100 and unsigned on the 1000. A negative count on the 2100 - results in a NOP. - - The simulator remaps the 2100 instructions to the 1000 codes. The four EIG - equivalents are dispatched to the EIG simulator. The rest are handled here. - - Additional reference: - - HP 2000 Computer System Sources and Listings Documentation - (22687-90020, undated), section 3, pages 2-74 through 2-91. -*/ - -static const OP_PAT op_iop[16] = { - OP_V, OP_N, OP_N, OP_N, /* CRC RESTR READF INS */ - OP_N, OP_N, OP_N, OP_V, /* ENQ PENQ DEQ TRSLT */ - OP_AC, OP_CVA, OP_A, OP_CV, /* ILIST PRFEI PRFEX PRFIO */ - OP_N, OP_N, OP_N, OP_N /* SAVE --- --- --- */ - }; - -t_stat cpu_iop (uint32 IR, uint32 intrq) -{ -t_stat reason = SCPE_OK; -OPS op; -uint32 entry; -uint32 hp, tp, i, t, wc, MA; - -if (UNIT_CPU_TYPE == UNIT_TYPE_2100) { /* 2100 IOP? */ - if ((IR >= 0105020) && (IR <= 0105057)) /* remap LAI */ - IR = 0105400 | (IR - 0105020); - else if ((IR >= 0105060) && (IR <= 0105117)) /* remap SAI */ - IR = 0101400 | (IR - 0105060); - else { - switch (IR) { /* remap others */ - case 0105000: IR = 0105470; break; /* ILIST */ - case 0105120: return cpu_eig (0105765, intrq); /* MBYTE (maps to MBT) */ - case 0105150: IR = 0105460; break; /* CRC */ - case 0105160: IR = 0105467; break; /* TRSLT */ - case 0105200: return cpu_eig (0105777, intrq); /* MWORD (maps to MVW) */ - case 0105220: IR = 0105462; break; /* READF */ - case 0105221: IR = 0105473; break; /* PRFIO */ - case 0105222: IR = 0105471; break; /* PRFEI */ - case 0105223: IR = 0105472; break; /* PRFEX */ - case 0105240: IR = 0105464; break; /* ENQ */ - case 0105257: IR = 0105465; break; /* PENQ */ - case 0105260: IR = 0105466; break; /* DEQ */ - case 0105300: return cpu_eig (0105764, intrq); /* SBYTE (maps to SBT) */ - case 0105320: return cpu_eig (0105763, intrq); /* LBYTE (maps to LBT) */ - case 0105340: IR = 0105461; break; /* REST */ - case 0105362: IR = 0105474; break; /* SAVE */ - - default: /* all others invalid */ - return stop_inst; - } - } - } - -entry = IR & 077; /* mask to entry point */ - -if (entry <= 037) { /* LAI/SAI 10x400-437 */ - MA = ((entry - 020) + BR) & VAMASK; /* +/- offset */ - if (IR & I_AB) AR = ReadW (MA); /* AB = 1 -> LAI */ - else WriteW (MA, AR); /* AB = 0 -> SAI */ - return reason; - } -else if (entry <= 057) /* IR = 10x440-457? */ - return stop_inst; /* not part of IOP */ - -entry = entry - 060; /* offset 10x460-477 */ - -if (op_iop[entry] != OP_N) - if (reason = cpu_ops (op_iop[entry], op, intrq)) /* get instruction operands */ - return reason; - -switch (entry) { /* decode IR<5:0> */ - - case 000: /* CRC 105460 (OP_V) */ - t = ReadW (op[0].word) ^ (AR & 0377); /* xor prev CRC and char */ - for (i = 0; i < 8; i++) { /* apply polynomial */ - t = (t >> 1) | ((t & 1) << 15); /* rotate right */ - if (t & SIGN) t = t ^ 020001; /* old t<0>? xor */ - } - WriteW (op[0].word, t); /* rewrite CRC */ - break; - - case 001: /* RESTR 105461 (OP_N) */ - iop_sp = (iop_sp - 1) & VAMASK; /* decr stack ptr */ - t = ReadW (iop_sp); /* get E and O */ - O = ((t >> 1) ^ 1) & 1; /* restore O */ - E = t & 1; /* restore E */ - iop_sp = (iop_sp - 1) & VAMASK; /* decr sp */ - BR = ReadW (iop_sp); /* restore B */ - iop_sp = (iop_sp - 1) & VAMASK; /* decr sp */ - AR = ReadW (iop_sp); /* restore A */ - if (UNIT_CPU_MODEL == UNIT_2100) - mp_fence = iop_sp; /* 2100 keeps sp in MP FR */ - break; - - case 002: /* READF 105462 (OP_N) */ - AR = iop_sp; /* copy stk ptr */ - break; - - case 003: /* INS 105463 (OP_N) */ - iop_sp = AR; /* init stk ptr */ - break; - - case 004: /* ENQ 105464 (OP_N) */ - hp = ReadW (AR & VAMASK); /* addr of head */ - tp = ReadW ((AR + 1) & VAMASK); /* addr of tail */ - WriteW ((BR - 1) & VAMASK, 0); /* entry link */ - WriteW ((tp - 1) & VAMASK, BR); /* tail link */ - WriteW ((AR + 1) & VAMASK, BR); /* queue tail */ - if (hp != 0) PC = (PC + 1) & VAMASK; /* q not empty? skip */ - break; - - case 005: /* PENQ 105465 (OP_N) */ - hp = ReadW (AR & VAMASK); /* addr of head */ - WriteW ((BR - 1) & VAMASK, hp); /* becomes entry link */ - WriteW (AR & VAMASK, BR); /* queue head */ - if (hp == 0) /* q empty? */ - WriteW ((AR + 1) & VAMASK, BR); /* queue tail */ - else PC = (PC + 1) & VAMASK; /* skip */ - break; - - case 006: /* DEQ 105466 (OP_N) */ - BR = ReadW (AR & VAMASK); /* addr of head */ - if (BR) { /* queue not empty? */ - hp = ReadW ((BR - 1) & VAMASK); /* read hd entry link */ - WriteW (AR & VAMASK, hp); /* becomes queue head */ - if (hp == 0) /* q now empty? */ - WriteW ((AR + 1) & VAMASK, (AR + 1) & DMASK); - PC = (PC + 1) & VAMASK; /* skip */ - } - break; - - case 007: /* TRSLT 105467 (OP_V) */ - wc = ReadW (op[0].word); /* get count */ - if (wc & SIGN) break; /* cnt < 0? */ - while (wc != 0) { /* loop */ - MA = (AR + AR + ReadB (BR)) & VAMASK; - t = ReadB (MA); /* xlate */ - WriteB (BR, t); /* store char */ - BR = (BR + 1) & DMASK; /* incr ptr */ - wc = (wc - 1) & DMASK; /* decr cnt */ - if (wc && intrq) { /* more and intr? */ - WriteW (op[0].word, wc); /* save count */ - PC = err_PC; /* stop for now */ - break; - } - } - break; - - case 010: /* ILIST 105470 (OP_AC) */ - do { /* for count */ - WriteW (op[0].word, AR); /* write AR to mem */ - AR = (AR + 1) & DMASK; /* incr AR */ - op[0].word = (op[0].word + 1) & VAMASK; /* incr MA */ - op[1].word = (op[1].word - 1) & DMASK; /* decr count */ - } - while (op[1].word != 0); - break; - - case 011: /* PRFEI 105471 (OP_CVA) */ - WriteW (op[1].word, 1); /* set flag */ - reason = iogrp (op[0].word, 0); /* execute I/O instr */ - op[0].word = op[2].word; /* set rtn and fall through */ - - case 012: /* PRFEX 105472 (OP_A) */ - PCQ_ENTRY; - PC = ReadW (op[0].word) & VAMASK; /* jump indirect */ - WriteW (op[0].word, 0); /* clear exit */ - break; - - case 013: /* PRFIO 105473 (OP_CV) */ - WriteW (op[1].word, 1); /* set flag */ - reason = iogrp (op[0].word, 0); /* execute instr */ - break; - - case 014: /* SAVE 105474 (OP_N) */ - WriteW (iop_sp, AR); /* save A */ - iop_sp = (iop_sp + 1) & VAMASK; /* incr stack ptr */ - WriteW (iop_sp, BR); /* save B */ - iop_sp = (iop_sp + 1) & VAMASK; /* incr stack ptr */ - t = ((O ^ 1) << 1) | E; /* merge E and O */ - WriteW (iop_sp, t); /* save E and O */ - iop_sp = (iop_sp + 1) & VAMASK; /* incr stack ptr */ - if (UNIT_CPU_TYPE == UNIT_TYPE_2100) - mp_fence = iop_sp; /* 2100 keeps sp in MP FR */ - break; - - default: /* instruction undefined */ - return stop_inst; - } - -return reason; -} +/* hp2100_cpu2.c: HP 2100/1000 FP/DMS/EIG/IOP instructions + + Copyright (c) 2005-2014, Robert M. Supnik + + 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 + ROBERT M SUPNIK 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 Robert M Supnik shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + + CPU2 Floating-point, dynamic mapping, extended, and I/O processor + instructions + + 24-Dec-14 JDB Added casts for explicit downward conversions + 09-May-12 JDB Separated assignments from conditional expressions + 11-Sep-08 JDB Moved microcode function prototypes to hp2100_cpu1.h + 05-Sep-08 JDB Removed option-present tests (now in UIG dispatchers) + 05-Aug-08 JDB Updated mp_dms_jmp calling sequence + Fixed DJP, SJP, and UJP jump target validation + 30-Jul-08 JDB RVA/B conditionally updates dms_vr before returning value + 19-Dec-06 JDB DMS self-test now executes as NOP on 1000-M + 01-Dec-06 JDB Substitutes FPP for firmware FP if HAVE_INT64 + 26-Sep-06 JDB Moved from hp2100_cpu1.c to simplify extensions + 22-Feb-05 JDB Fixed missing MPCK on JRS target + 21-Jan-05 JDB Reorganized CPU option and operand processing flags + Split code along microcode modules + 15-Jan-05 RMS Cloned from hp2100_cpu.c + + Primary references: + - HP 1000 M/E/F-Series Computers Technical Reference Handbook + (5955-0282, Mar-1980) + - HP 1000 M/E/F-Series Computers Engineering and Reference Documentation + (92851-90001, Mar-1981) + - Macro/1000 Reference Manual (92059-90001, Dec-1992) + + Additional references are listed with the associated firmware + implementations, as are the HP option model numbers pertaining to the + applicable CPUs. +*/ + +#include "hp2100_defs.h" +#include "hp2100_cpu.h" +#include "hp2100_cpu1.h" + +#if !defined (HAVE_INT64) /* int64 support unavailable */ + +#include "hp2100_fp.h" + + +/* Single-Precision Floating Point Instructions + + The 2100 and 1000 CPUs share the single-precision (two word) floating-point + instruction codes. Floating-point firmware was an option on the 2100 and was + standard on the 1000-M and E. The 1000-F had a standard hardware Floating + Point Processor that executed these six instructions and added extended- and + double-precision floating- point instructions, as well as double-integer + instructions (the FPP is simulated separately). + + Option implementation by CPU was as follows: + + 2114 2115 2116 2100 1000-M 1000-E 1000-F + ------ ------ ------ ------ ------ ------ ------ + N/A N/A N/A 12901A std std N/A + + The instruction codes for the 2100 and 1000-M/E systems are mapped to + routines as follows: + + Instr. 2100/1000-M/E Description + ------ ------------- ----------------------------------- + 105000 FAD Single real add + 105020 FSB Single real subtract + 105040 FMP Single real multiply + 105060 FDV Single real divide + 105100 FIX Single integer to single real fix + 105120 FLT Single real to single integer float + + Bits 3-0 are not decoded by these instructions, so FAD (e.g.) would be + executed by any instruction in the range 105000-105017. + + Implementation note: rather than have two simulators that each executes the + single-precision FP instruction set, we compile conditionally, based on the + availability of 64-bit integer support in the host compiler. 64-bit integers + are required for the FPP, so if they are available, then the FPP is used to + handle the six single-precision instructions for the 2100 and M/E-Series, and + this function is omitted. If support is unavailable, this function is used + instead. + + Implementation note: the operands to FAD, etc. are floating-point values, so + OP_F would normally be used. However, the firmware FP support routines want + floating-point operands as 32-bit integer values, so OP_D is used to achieve + this. +*/ + +static const OP_PAT op_fp[8] = { + OP_D, OP_D, OP_D, OP_D, /* FAD FSB FMP FDV */ + OP_N, OP_N, OP_N, OP_N /* FIX FLT --- --- */ + }; + +t_stat cpu_fp (uint32 IR, uint32 intrq) +{ +t_stat reason = SCPE_OK; +OPS op; +uint32 entry; + +entry = (IR >> 4) & 017; /* mask to entry point */ + +if (op_fp [entry] != OP_N) { + reason = cpu_ops (op_fp [entry], op, intrq); /* get instruction operands */ + + if (reason != SCPE_OK) /* evaluation failed? */ + return reason; /* return reason for failure */ + } + +switch (entry) { /* decode IR<7:4> */ + + case 000: /* FAD 105000 (OP_D) */ + O = f_as (op[0].dword, 0); /* add, upd ovflo */ + break; + + case 001: /* FSB 105020 (OP_D) */ + O = f_as (op[0].dword, 1); /* sub, upd ovflo */ + break; + + case 002: /* FMP 105040 (OP_D) */ + O = f_mul (op[0].dword); /* mul, upd ovflo */ + break; + + case 003: /* FDV 105060 (OP_D) */ + O = f_div (op[0].dword); /* div, upd ovflo */ + break; + + case 004: /* FIX 105100 (OP_N) */ + O = f_fix (); /* fix, upd ovflo */ + break; + + case 005: /* FLT 105120 (OP_N) */ + O = f_flt (); /* float, upd ovflo */ + break; + + default: /* should be impossible */ + return SCPE_IERR; + } + +return reason; +} + +#endif /* int64 support unavailable */ + + +/* Dynamic Mapping System + + The 1000 Dynamic Mapping System (DMS) consisted of the 12731A Memory + Expansion Module (MEM) card and 38 instructions to expand the basic 32K + logical address space to a 1024K physical space. The MEM provided four maps + of 32 mapping registers each: a system map, a user map, and two DCPC maps. + DMS worked in conjunction with memory protect to provide a "protected mode" + in which memory read and write violations could be trapped, and that + inhibited "privileged" instruction execution that attempted to alter the + memory mapping. + + Option implementation by CPU was as follows: + + 2114 2115 2116 2100 1000-M 1000-E 1000-F + ------ ------ ------ ------ ------ ------ ------ + N/A N/A N/A N/A 12976B 13307B std + + The instruction codes are mapped to routines as follows: + + Instr. 1000-M 1000-E/F Instr. 1000-M 1000-E/F + ------ ------ -------- ------ ------ -------- + 10x700 [xmm] [xmm] 10x720 XMM XMM + 10x701 [nop] [test] 10x721 XMS XMS + 10x702 MBI MBI 10x722 XM* XM* + 10x703 MBF MBF 10x723 [nop] [nop] + 10x704 MBW MBW 10x724 XL* XL* + 10x705 MWI MWI 10x725 XS* XS* + 10x706 MWF MWF 10x726 XC* XC* + 10x707 MWW MWW 10x727 LF* LF* + 10x710 SY* SY* 10x730 RS* RS* + + 10x711 US* US* 10x731 RV* RV* + 10x712 PA* PA* 10x732 DJP DJP + 10x713 PB* PB* 10x733 DJS DJS + 10x714 SSM SSM 10x734 SJP SJP + 10x715 JRS JRS 10x735 SJS SJS + 10x716 [nop] [nop] 10x736 UJP UJP + 10x717 [nop] [nop] 10x737 UJS UJS + + Instructions that use IR bit 9 to select the A or B register are designated + with a * above (e.g., 101710 is SYA, and 105710 is SYB). For those that do + not use this feature, either the 101xxx or 105xxx code will execute the + corresponding instruction, although the 105xxx form is the documented + instruction code. + + Implementation notes: + + 1. Instruction code 10x700 will execute the XMM instruction, although 10x720 + is the documented instruction value. + + 2. Instruction code 10x701 will complement the A or B register, as + indicated, on 1000-E and F-Series machines. This instruction is a NOP on + M-Series machines. + + 3. The DMS privilege violation rules are: + - load map and CTL5 set (XMM, XMS, XM*, SY*, US*, PA*, PB*) + - load state or fence and UMAP set (JRS, DJP, DJS, SJP, SJS, UJP, UJS, LF*) + + 4. The 1000 manual is incorrect in stating that M*I, M*W, XS* are + privileged. + + 5. The protected memory lower bound for the DJP, SJP, UJP, and JRS + instructions is 2. +*/ + +static const OP_PAT op_dms[32] = { + OP_N, OP_N, OP_N, OP_N, /* [xmm] [test] MBI MBF */ + OP_N, OP_N, OP_N, OP_N, /* MBW MWI MWF MWW */ + OP_N, OP_N, OP_N, OP_N, /* SYA/B USA/B PAA/B PBA/B */ + OP_A, OP_KA, OP_N, OP_N, /* SSM JRS nop nop */ + OP_N, OP_N, OP_N, OP_N, /* XMM XMS XMA/B nop */ + OP_A, OP_A, OP_A, OP_N, /* XLA/B XSA/B XCA/B LFA/B */ + OP_N, OP_N, OP_A, OP_A, /* RSA/B RVA/B DJP DJS */ + OP_A, OP_A, OP_A, OP_A /* SJP SJS UJP UJS */ + }; + +t_stat cpu_dms (uint32 IR, uint32 intrq) +{ +t_stat reason = SCPE_OK; +OPS op; +uint32 entry, absel; +uint32 i, t, mapi, mapj; + +absel = (IR & I_AB)? 1: 0; /* get A/B select */ +entry = IR & 037; /* mask to entry point */ + +if (op_dms [entry] != OP_N) { + reason = cpu_ops (op_dms [entry], op, intrq); /* get instruction operands */ + + if (reason != SCPE_OK) /* evaluation failed? */ + return reason; /* return reason for failure */ + } + +switch (entry) { /* decode IR<3:0> */ + +/* DMS module 1 */ + + case 000: /* [undefined] 105700 (OP_N) */ + goto XMM; /* decodes as XMM */ + + case 001: /* [self test] 105701 (OP_N) */ + if (UNIT_CPU_MODEL != UNIT_1000_M) /* executes as NOP on 1000-M */ + ABREG[absel] = ~ABREG[absel]; /* CMA or CMB */ + break; + + case 002: /* MBI 105702 (OP_N) */ + AR = AR & ~1; /* force A, B even */ + BR = BR & ~1; + while (XR != 0) { /* loop */ + t = ReadB (AR); /* read curr */ + WriteBA (BR, t); /* write alt */ + AR = (AR + 1) & DMASK; /* incr ptrs */ + BR = (BR + 1) & DMASK; + XR = (XR - 1) & DMASK; + if (XR && intrq && !(AR & 1)) { /* more, int, even? */ + PC = err_PC; /* stop for now */ + break; + } + } + break; + + case 003: /* MBF 105703 (OP_N) */ + AR = AR & ~1; /* force A, B even */ + BR = BR & ~1; + while (XR != 0) { /* loop */ + t = ReadBA (AR); /* read alt */ + WriteB (BR, t); /* write curr */ + AR = (AR + 1) & DMASK; /* incr ptrs */ + BR = (BR + 1) & DMASK; + XR = (XR - 1) & DMASK; + if (XR && intrq && !(AR & 1)) { /* more, int, even? */ + PC = err_PC; /* stop for now */ + break; + } + } + break; + + case 004: /* MBW 105704 (OP_N) */ + AR = AR & ~1; /* force A, B even */ + BR = BR & ~1; + while (XR != 0) { /* loop */ + t = ReadBA (AR); /* read alt */ + WriteBA (BR, t); /* write alt */ + AR = (AR + 1) & DMASK; /* incr ptrs */ + BR = (BR + 1) & DMASK; + XR = (XR - 1) & DMASK; + if (XR && intrq && !(AR & 1)) { /* more, int, even? */ + PC = err_PC; /* stop for now */ + break; + } + } + break; + + case 005: /* MWI 105705 (OP_N) */ + while (XR != 0) { /* loop */ + t = ReadW (AR & VAMASK); /* read curr */ + WriteWA (BR & VAMASK, t); /* write alt */ + AR = (AR + 1) & DMASK; /* incr ptrs */ + BR = (BR + 1) & DMASK; + XR = (XR - 1) & DMASK; + if (XR && intrq) { /* more and intr? */ + PC = err_PC; /* stop for now */ + break; + } + } + break; + + case 006: /* MWF 105706 (OP_N) */ + while (XR != 0) { /* loop */ + t = ReadWA (AR & VAMASK); /* read alt */ + WriteW (BR & VAMASK, t); /* write curr */ + AR = (AR + 1) & DMASK; /* incr ptrs */ + BR = (BR + 1) & DMASK; + XR = (XR - 1) & DMASK; + if (XR && intrq) { /* more and intr? */ + PC = err_PC; /* stop for now */ + break; + } + } + break; + + case 007: /* MWW 105707 (OP_N) */ + while (XR != 0) { /* loop */ + t = ReadWA (AR & VAMASK); /* read alt */ + WriteWA (BR & VAMASK, t); /* write alt */ + AR = (AR + 1) & DMASK; /* incr ptrs */ + BR = (BR + 1) & DMASK; + XR = (XR - 1) & DMASK; + if (XR && intrq) { /* more and intr? */ + PC = err_PC; /* stop for now */ + break; + } + } + break; + + case 010: /* SYA, SYB 10x710 (OP_N) */ + case 011: /* USA, USB 10x711 (OP_N) */ + case 012: /* PAA, PAB 10x712 (OP_N) */ + case 013: /* PBA, PBB 10x713 (OP_N) */ + mapi = (IR & 03) << VA_N_PAG; /* map base */ + if (ABREG[absel] & SIGN) { /* store? */ + for (i = 0; i < MAP_LNT; i++) { + t = dms_rmap (mapi + i); /* map to memory */ + WriteW ((ABREG[absel] + i) & VAMASK, t); + } + } + else { /* load */ + dms_viol (err_PC, MVI_PRV); /* priv if PRO */ + for (i = 0; i < MAP_LNT; i++) { + t = ReadW ((ABREG[absel] + i) & VAMASK); + dms_wmap (mapi + i, t); /* mem to map */ + } + } + ABREG[absel] = (ABREG[absel] + MAP_LNT) & DMASK; + break; + + case 014: /* SSM 105714 (OP_A) */ + WriteW (op[0].word, dms_upd_sr ()); /* store stat */ + break; + + case 015: /* JRS 105715 (OP_KA) */ + if (dms_ump) dms_viol (err_PC, MVI_PRV); /* priv viol if prot */ + dms_enb = 0; /* assume off */ + dms_ump = SMAP; + if (op[0].word & 0100000) { /* set enable? */ + dms_enb = 1; + if (op[0].word & 0040000) dms_ump = UMAP; /* set/clr usr */ + } + mp_dms_jmp (op[1].word, 2); /* mpck jmp target */ + PCQ_ENTRY; /* save old PC */ + PC = op[1].word; /* jump */ + ion_defer = 1; /* defer intr */ + break; + +/* DMS module 2 */ + + case 020: /* XMM 105720 (OP_N) */ + XMM: + if (XR == 0) break; /* nop? */ + while (XR != 0) { /* loop */ + if (XR & SIGN) { /* store? */ + t = dms_rmap (AR); /* map to mem */ + WriteW (BR & VAMASK, t); + XR = (XR + 1) & DMASK; + } + else { /* load */ + dms_viol (err_PC, MVI_PRV); /* priv viol if prot */ + t = ReadW (BR & VAMASK); /* mem to map */ + dms_wmap (AR, t); + XR = (XR - 1) & DMASK; + } + AR = (AR + 1) & DMASK; + BR = (BR + 1) & DMASK; + if (intrq && ((XR & 017) == 017)) { /* intr, grp of 16? */ + PC = err_PC; /* stop for now */ + break; + } + } + break; + + case 021: /* XMS 105721 (OP_N) */ + if ((XR & SIGN) || (XR == 0)) break; /* nop? */ + dms_viol (err_PC, MVI_PRV); /* priv viol if prot */ + while (XR != 0) { + dms_wmap (AR, BR); /* AR to map */ + XR = (XR - 1) & DMASK; + AR = (AR + 1) & DMASK; + BR = (BR + 1) & DMASK; + if (intrq && ((XR & 017) == 017)) { /* intr, grp of 16? */ + PC = err_PC; + break; + } + } + break; + + case 022: /* XMA, XMB 10x722 (OP_N) */ + dms_viol (err_PC, MVI_PRV); /* priv viol if prot */ + if (ABREG[absel] & 0100000) mapi = UMAP; + else mapi = SMAP; + if (ABREG[absel] & 0000001) mapj = PBMAP; + else mapj = PAMAP; + for (i = 0; i < MAP_LNT; i++) { + t = dms_rmap (mapi + i); /* read map */ + dms_wmap (mapj + i, t); /* write map */ + } + break; + + case 024: /* XLA, XLB 10x724 (OP_A) */ + ABREG[absel] = ReadWA (op[0].word); /* load alt */ + break; + + case 025: /* XSA, XSB 10x725 (OP_A) */ + WriteWA (op[0].word, ABREG[absel]); /* store alt */ + break; + + case 026: /* XCA, XCB 10x726 (OP_A) */ + if (ABREG[absel] != ReadWA (op[0].word)) /* compare alt */ + PC = (PC + 1) & VAMASK; + break; + + case 027: /* LFA, LFB 10x727 (OP_N) */ + if (dms_ump) dms_viol (err_PC, MVI_PRV); /* priv viol if prot */ + dms_sr = (dms_sr & ~(MST_FLT | MST_FENCE)) | + (ABREG[absel] & (MST_FLT | MST_FENCE)); + break; + + case 030: /* RSA, RSB 10x730 (OP_N) */ + ABREG[absel] = (uint16) dms_upd_sr (); /* save stat */ + break; + + case 031: /* RVA, RVB 10x731 (OP_N) */ + ABREG[absel] = (uint16) dms_upd_vr (err_PC); /* return updated violation register */ + break; + + case 032: /* DJP 105732 (OP_A) */ + if (dms_ump) dms_viol (err_PC, MVI_PRV); /* priv viol if prot */ + dms_enb = 0; /* disable map */ + dms_ump = SMAP; + mp_dms_jmp (op[0].word, 2); /* validate jump addr */ + PCQ_ENTRY; /* save curr PC */ + PC = op[0].word; /* new PC */ + ion_defer = 1; + break; + + case 033: /* DJS 105733 (OP_A) */ + if (dms_ump) dms_viol (err_PC, MVI_PRV); /* priv viol if prot */ + WriteW (op[0].word, PC); /* store ret addr */ + PCQ_ENTRY; /* save curr PC */ + PC = (op[0].word + 1) & VAMASK; /* new PC */ + dms_enb = 0; /* disable map */ + dms_ump = SMAP; + ion_defer = 1; /* defer intr */ + break; + + case 034: /* SJP 105734 (OP_A) */ + if (dms_ump) dms_viol (err_PC, MVI_PRV); /* priv viol if prot */ + dms_enb = 1; /* enable system */ + dms_ump = SMAP; + mp_dms_jmp (op[0].word, 2); /* validate jump addr */ + PCQ_ENTRY; /* save curr PC */ + PC = op[0].word; /* jump */ + ion_defer = 1; /* defer intr */ + break; + + case 035: /* SJS 105735 (OP_A) */ + if (dms_ump) dms_viol (err_PC, MVI_PRV); /* priv viol if prot */ + t = PC; /* save retn addr */ + PCQ_ENTRY; /* save curr PC */ + PC = (op[0].word + 1) & VAMASK; /* new PC */ + dms_enb = 1; /* enable system */ + dms_ump = SMAP; + WriteW (op[0].word, t); /* store ret addr */ + ion_defer = 1; /* defer intr */ + break; + + case 036: /* UJP 105736 (OP_A) */ + if (dms_ump) dms_viol (err_PC, MVI_PRV); /* priv viol if prot */ + dms_enb = 1; /* enable user */ + dms_ump = UMAP; + mp_dms_jmp (op[0].word, 2); /* validate jump addr */ + PCQ_ENTRY; /* save curr PC */ + PC = op[0].word; /* jump */ + ion_defer = 1; /* defer intr */ + break; + + case 037: /* UJS 105737 (OP_A) */ + if (dms_ump) dms_viol (err_PC, MVI_PRV); /* priv viol if prot */ + t = PC; /* save retn addr */ + PCQ_ENTRY; /* save curr PC */ + PC = (op[0].word + 1) & VAMASK; /* new PC */ + dms_enb = 1; /* enable user */ + dms_ump = UMAP; + WriteW (op[0].word, t); /* store ret addr */ + ion_defer = 1; /* defer intr */ + break; + + default: /* others NOP */ + break; + } + +return reason; +} + + +/* Extended Instruction Group + + The Extended Instruction Group (EIG) adds 32 index and 10 bit/byte/word + manipulation instructions to the 1000 base set. These instructions + use the new X and Y index registers that were added to the 1000. + + Option implementation by CPU was as follows: + + 2114 2115 2116 2100 1000-M 1000-E 1000-F + ------ ------ ------ ------ ------ ------ ------ + N/A N/A N/A N/A std std std + + The instruction codes are mapped to routines as follows: + + Instr. 1000-M/E/F Instr. 1000-M/E/F + ------ ---------- ------ ---------- + 10x740 S*X 10x760 ISX + 10x741 C*X 10x761 DSX + 10x742 L*X 10x762 JLY + 10x743 STX 10x763 LBT + 10x744 CX* 10x764 SBT + 10x745 LDX 10x765 MBT + 10x746 ADX 10x766 CBT + 10x747 X*X 10x767 SFB + + 10x750 S*Y 10x770 ISY + 10x751 C*Y 10x771 DSY + 10x752 L*Y 10x772 JPY + 10x753 STY 10x773 SBS + 10x754 CY* 10x774 CBS + 10x755 LDY 10x775 TBS + 10x756 ADY 10x776 CMW + 10x757 X*Y 10x777 MVW + + Instructions that use IR bit 9 to select the A or B register are designated + with a * above (e.g., 101740 is SAX, and 105740 is SBX). For those that do + not use this feature, either the 101xxx or 105xxx code will execute the + corresponding instruction, although the 105xxx form is the documented + instruction code. + + Implementation notes: + + 1. The LBT, SBT, MBT, and MVW instructions are used as part of the 2100 IOP + implementation. When so called, the MBT and MVW instructions have the + additional restriction that the count must be positive. + + 2. The protected memory lower bound for the JLY and JPY instructions is 0. +*/ + +static const OP_PAT op_eig[32] = { + OP_A, OP_N, OP_A, OP_A, /* S*X C*X L*X STX */ + OP_N, OP_K, OP_K, OP_N, /* CX* LDX ADX X*X */ + OP_A, OP_N, OP_A, OP_A, /* S*Y C*Y L*Y STY */ + OP_N, OP_K, OP_K, OP_N, /* CY* LDY ADY X*Y */ + OP_N, OP_N, OP_A, OP_N, /* ISX DSX JLY LBT */ + OP_N, OP_KV, OP_KV, OP_N, /* SBT MBT CBT SFB */ + OP_N, OP_N, OP_C, OP_KA, /* ISY DSY JPY SBS */ + OP_KA, OP_KK, OP_KV, OP_KV /* CBS TBS CMW MVW */ + }; + +t_stat cpu_eig (uint32 IR, uint32 intrq) +{ +t_stat reason = SCPE_OK; +OPS op; +uint32 entry, absel; +uint32 t, v1, v2, wc; +int32 sop1, sop2; + +absel = (IR & I_AB)? 1: 0; /* get A/B select */ +entry = IR & 037; /* mask to entry point */ + +if (op_eig [entry] != OP_N) { + reason = cpu_ops (op_eig [entry], op, intrq); /* get instruction operands */ + + if (reason != SCPE_OK) /* evaluation failed? */ + return reason; /* return reason for failure */ + } + +switch (entry) { /* decode IR<4:0> */ + +/* EIG module 1 */ + + case 000: /* SAX, SBX 10x740 (OP_A) */ + op[0].word = (op[0].word + XR) & VAMASK; /* indexed addr */ + WriteW (op[0].word, ABREG[absel]); /* store */ + break; + + case 001: /* CAX, CBX 10x741 (OP_N) */ + XR = ABREG[absel]; /* copy to XR */ + break; + + case 002: /* LAX, LBX 10x742 (OP_A) */ + op[0].word = (op[0].word + XR) & VAMASK; /* indexed addr */ + ABREG[absel] = ReadW (op[0].word); /* load */ + break; + + case 003: /* STX 105743 (OP_A) */ + WriteW (op[0].word, XR); /* store XR */ + break; + + case 004: /* CXA, CXB 10x744 (OP_N) */ + ABREG[absel] = (uint16) XR; /* copy from XR */ + break; + + case 005: /* LDX 105745 (OP_K)*/ + XR = op[0].word; /* load XR */ + break; + + case 006: /* ADX 105746 (OP_K) */ + t = XR + op[0].word; /* add to XR */ + if (t > DMASK) E = 1; /* set E, O */ + if (((~XR ^ op[0].word) & (XR ^ t)) & SIGN) O = 1; + XR = t & DMASK; + break; + + case 007: /* XAX, XBX 10x747 (OP_N) */ + t = XR; /* exchange XR */ + XR = ABREG[absel]; + ABREG[absel] = (uint16) t; + break; + + case 010: /* SAY, SBY 10x750 (OP_A) */ + op[0].word = (op[0].word + YR) & VAMASK; /* indexed addr */ + WriteW (op[0].word, ABREG[absel]); /* store */ + break; + + case 011: /* CAY, CBY 10x751 (OP_N) */ + YR = ABREG[absel]; /* copy to YR */ + break; + + case 012: /* LAY, LBY 10x752 (OP_A) */ + op[0].word = (op[0].word + YR) & VAMASK; /* indexed addr */ + ABREG[absel] = ReadW (op[0].word); /* load */ + break; + + case 013: /* STY 105753 (OP_A) */ + WriteW (op[0].word, YR); /* store YR */ + break; + + case 014: /* CYA, CYB 10x754 (OP_N) */ + ABREG[absel] = (uint16) YR; /* copy from YR */ + break; + + case 015: /* LDY 105755 (OP_K) */ + YR = op[0].word; /* load YR */ + break; + + case 016: /* ADY 105756 (OP_K) */ + t = YR + op[0].word; /* add to YR */ + if (t > DMASK) E = 1; /* set E, O */ + if (((~YR ^ op[0].word) & (YR ^ t)) & SIGN) O = 1; + YR = t & DMASK; + break; + + case 017: /* XAY, XBY 10x757 (OP_N) */ + t = YR; /* exchange YR */ + YR = ABREG[absel]; + ABREG[absel] = (uint16) t; + break; + +/* EIG module 2 */ + + case 020: /* ISX 105760 (OP_N) */ + XR = (XR + 1) & DMASK; /* incr XR */ + if (XR == 0) PC = (PC + 1) & VAMASK; /* skip if zero */ + break; + + case 021: /* DSX 105761 (OP_N) */ + XR = (XR - 1) & DMASK; /* decr XR */ + if (XR == 0) PC = (PC + 1) & VAMASK; /* skip if zero */ + break; + + case 022: /* JLY 105762 (OP_A) */ + mp_dms_jmp (op[0].word, 0); /* validate jump addr */ + PCQ_ENTRY; + YR = PC; /* ret addr to YR */ + PC = op[0].word; /* jump */ + break; + + case 023: /* LBT 105763 (OP_N) */ + AR = ReadB (BR); /* load byte */ + BR = (BR + 1) & DMASK; /* incr ptr */ + break; + + case 024: /* SBT 105764 (OP_N) */ + WriteB (BR, AR); /* store byte */ + BR = (BR + 1) & DMASK; /* incr ptr */ + break; + + case 025: /* MBT 105765 (OP_KV) */ + wc = ReadW (op[1].word); /* get continuation count */ + if (wc == 0) wc = op[0].word; /* none? get initiation count */ + if ((wc & SIGN) && + (UNIT_CPU_TYPE == UNIT_TYPE_2100)) + break; /* < 0 is NOP for 2100 IOP */ + while (wc != 0) { /* while count */ + WriteW (op[1].word, wc); /* for MP abort */ + t = ReadB (AR); /* move byte */ + WriteB (BR, t); + AR = (AR + 1) & DMASK; /* incr src */ + BR = (BR + 1) & DMASK; /* incr dst */ + wc = (wc - 1) & DMASK; /* decr cnt */ + if (intrq && wc) { /* intr, more to do? */ + PC = err_PC; /* back up PC */ + break; + } + } + WriteW (op[1].word, wc); /* clean up inline */ + break; + + case 026: /* CBT 105766 (OP_KV) */ + wc = ReadW (op[1].word); /* get continuation count */ + if (wc == 0) wc = op[0].word; /* none? get initiation count */ + while (wc != 0) { /* while count */ + WriteW (op[1].word, wc); /* for MP abort */ + v1 = ReadB (AR); /* get src1 */ + v2 = ReadB (BR); /* get src2 */ + if (v1 != v2) { /* compare */ + PC = (PC + 1 + (v1 > v2)) & VAMASK; + BR = (BR + wc) & DMASK; /* update BR */ + wc = 0; /* clr interim */ + break; + } + AR = (AR + 1) & DMASK; /* incr src1 */ + BR = (BR + 1) & DMASK; /* incr src2 */ + wc = (wc - 1) & DMASK; /* decr cnt */ + if (intrq && wc) { /* intr, more to do? */ + PC = err_PC; /* back up PC */ + break; + } + } + WriteW (op[1].word, wc); /* clean up inline */ + break; + + case 027: /* SFB 105767 (OP_N) */ + v1 = AR & 0377; /* test byte */ + v2 = (AR >> 8) & 0377; /* term byte */ + for (;;) { /* scan */ + t = ReadB (BR); /* read byte */ + if (t == v1) break; /* test match? */ + BR = (BR + 1) & DMASK; + if (t == v2) { /* term match? */ + PC = (PC + 1) & VAMASK; + break; + } + if (intrq) { /* int pending? */ + PC = err_PC; /* back up PC */ + break; + } + } + break; + + case 030: /* ISY 105770 (OP_N) */ + YR = (YR + 1) & DMASK; /* incr YR */ + if (YR == 0) PC = (PC + 1) & VAMASK; /* skip if zero */ + break; + + case 031: /* DSY 105771 (OP_N) */ + YR = (YR - 1) & DMASK; /* decr YR */ + if (YR == 0) PC = (PC + 1) & VAMASK; /* skip if zero */ + break; + + case 032: /* JPY 105772 (OP_C) */ + op[0].word = (op[0].word + YR) & VAMASK; /* index, no indir */ + mp_dms_jmp (op[0].word, 0); /* validate jump addr */ + PCQ_ENTRY; + PC = op[0].word; /* jump */ + break; + + case 033: /* SBS 105773 (OP_KA) */ + WriteW (op[1].word, /* set bits */ + ReadW (op[1].word) | op[0].word); + break; + + case 034: /* CBS 105774 (OP_KA) */ + WriteW (op[1].word, /* clear bits */ + ReadW (op[1].word) & ~op[0].word); + break; + + case 035: /* TBS 105775 (OP_KK) */ + if ((op[1].word & op[0].word) != op[0].word) /* test bits */ + PC = (PC + 1) & VAMASK; + break; + + case 036: /* CMW 105776 (OP_KV) */ + wc = ReadW (op[1].word); /* get continuation count */ + if (wc == 0) wc = op[0].word; /* none? get initiation count */ + while (wc != 0) { /* while count */ + WriteW (op[1].word, wc); /* for abort */ + v1 = ReadW (AR & VAMASK); /* first op */ + v2 = ReadW (BR & VAMASK); /* second op */ + sop1 = (int32) SEXT (v1); /* signed */ + sop2 = (int32) SEXT (v2); + if (sop1 != sop2) { /* compare */ + PC = (PC + 1 + (sop1 > sop2)) & VAMASK; + BR = (BR + wc) & DMASK; /* update BR */ + wc = 0; /* clr interim */ + break; + } + AR = (AR + 1) & DMASK; /* incr src1 */ + BR = (BR + 1) & DMASK; /* incr src2 */ + wc = (wc - 1) & DMASK; /* decr cnt */ + if (intrq && wc) { /* intr, more to do? */ + PC = err_PC; /* back up PC */ + break; + } + } + WriteW (op[1].word, wc); /* clean up inline */ + break; + + case 037: /* MVW 105777 (OP_KV) */ + wc = ReadW (op[1].word); /* get continuation count */ + if (wc == 0) wc = op[0].word; /* none? get initiation count */ + if ((wc & SIGN) && + (UNIT_CPU_TYPE == UNIT_TYPE_2100)) + break; /* < 0 is NOP for 2100 IOP */ + while (wc != 0) { /* while count */ + WriteW (op[1].word, wc); /* for abort */ + t = ReadW (AR & VAMASK); /* move word */ + WriteW (BR & VAMASK, t); + AR = (AR + 1) & DMASK; /* incr src */ + BR = (BR + 1) & DMASK; /* incr dst */ + wc = (wc - 1) & DMASK; /* decr cnt */ + if (intrq && wc) { /* intr, more to do? */ + PC = err_PC; /* back up PC */ + break; + } + } + WriteW (op[1].word, wc); /* clean up inline */ + break; + + } + +return reason; +} + + +/* 2000 I/O Processor + + The IOP accelerates certain operations of the HP 2000 Time-Share BASIC system + I/O processor. Most 2000 systems were delivered with 2100 CPUs, although IOP + microcode was developed for the 1000-M and 1000-E. As the I/O processors + were specific to the 2000 system, general compatibility with other CPU + microcode options was unnecessary, and indeed no other options were possible + for the 2100. + + Option implementation by CPU was as follows: + + 2114 2115 2116 2100 1000-M 1000-E 1000-F + ------ ------ ------ ------ ------ ------ ------ + N/A N/A N/A 13206A 13207A 22702A N/A + + The routines are mapped to instruction codes as follows: + + Instr. 2100 1000-M/E Description + ------ ---------- ---------- -------------------------------------------- + SAI 105060-117 101400-037 Store A indexed by B (+/- offset in IR<4:0>) + LAI 105020-057 105400-037 Load A indexed by B (+/- offset in IR<4:0>) + CRC 105150 105460 Generate CRC + REST 105340 105461 Restore registers from stack + READF 105220 105462 Read F register (stack pointer) + INS -- 105463 Initialize F register (stack pointer) + ENQ 105240 105464 Enqueue + PENQ 105257 105465 Priority enqueue + DEQ 105260 105466 Dequeue + TRSLT 105160 105467 Translate character + ILIST 105000 105470 Indirect address list (similar to $SETP) + PRFEI 105222 105471 Power fail exit with I/O + PRFEX 105223 105472 Power fail exit + PRFIO 105221 105473 Power fail I/O + SAVE 105362 105474 Save registers to stack + + MBYTE 105120 105765 Move bytes (MBT) + MWORD 105200 105777 Move words (MVW) + SBYTE 105300 105764 Store byte (SBT) + LBYTE 105320 105763 Load byte (LBT) + + The INS instruction was not required in the 2100 implementation because the + stack pointer was actually the memory protect fence register and so could be + loaded directly with an OTA/B 05. Also, the 1000 implementation did not + offer the MBYTE, MWORD, SBYTE, and LBYTE instructions because the equivalent + instructions from the standard Extended Instruction Group were used instead. + + Note that the 2100 MBYTE and MWORD instructions operate slightly differently + from the 1000 MBT and MVW instructions. Specifically, the move count is + signed on the 2100 and unsigned on the 1000. A negative count on the 2100 + results in a NOP. + + The simulator remaps the 2100 instructions to the 1000 codes. The four EIG + equivalents are dispatched to the EIG simulator. The rest are handled here. + + Additional reference: + - HP 2000 Computer System Sources and Listings Documentation + (22687-90020, undated), section 3, pages 2-74 through 2-91. +*/ + +static const OP_PAT op_iop[16] = { + OP_V, OP_N, OP_N, OP_N, /* CRC RESTR READF INS */ + OP_N, OP_N, OP_N, OP_V, /* ENQ PENQ DEQ TRSLT */ + OP_AC, OP_CVA, OP_A, OP_CV, /* ILIST PRFEI PRFEX PRFIO */ + OP_N, OP_N, OP_N, OP_N /* SAVE --- --- --- */ + }; + +t_stat cpu_iop (uint32 IR, uint32 intrq) +{ +t_stat reason = SCPE_OK; +OPS op; +uint32 entry; +uint32 hp, tp, i, t, wc, MA; + +if (UNIT_CPU_TYPE == UNIT_TYPE_2100) { /* 2100 IOP? */ + if ((IR >= 0105020) && (IR <= 0105057)) /* remap LAI */ + IR = 0105400 | (IR - 0105020); + else if ((IR >= 0105060) && (IR <= 0105117)) /* remap SAI */ + IR = 0101400 | (IR - 0105060); + else { + switch (IR) { /* remap others */ + case 0105000: IR = 0105470; break; /* ILIST */ + case 0105120: return cpu_eig (0105765, intrq); /* MBYTE (maps to MBT) */ + case 0105150: IR = 0105460; break; /* CRC */ + case 0105160: IR = 0105467; break; /* TRSLT */ + case 0105200: return cpu_eig (0105777, intrq); /* MWORD (maps to MVW) */ + case 0105220: IR = 0105462; break; /* READF */ + case 0105221: IR = 0105473; break; /* PRFIO */ + case 0105222: IR = 0105471; break; /* PRFEI */ + case 0105223: IR = 0105472; break; /* PRFEX */ + case 0105240: IR = 0105464; break; /* ENQ */ + case 0105257: IR = 0105465; break; /* PENQ */ + case 0105260: IR = 0105466; break; /* DEQ */ + case 0105300: return cpu_eig (0105764, intrq); /* SBYTE (maps to SBT) */ + case 0105320: return cpu_eig (0105763, intrq); /* LBYTE (maps to LBT) */ + case 0105340: IR = 0105461; break; /* REST */ + case 0105362: IR = 0105474; break; /* SAVE */ + + default: /* all others invalid */ + return stop_inst; + } + } + } + +entry = IR & 077; /* mask to entry point */ + +if (entry <= 037) { /* LAI/SAI 10x400-437 */ + MA = ((entry - 020) + BR) & VAMASK; /* +/- offset */ + if (IR & I_AB) AR = ReadW (MA); /* AB = 1 -> LAI */ + else WriteW (MA, AR); /* AB = 0 -> SAI */ + return reason; + } +else if (entry <= 057) /* IR = 10x440-457? */ + return stop_inst; /* not part of IOP */ + +entry = entry - 060; /* offset 10x460-477 */ + +if (op_iop [entry] != OP_N) { + reason = cpu_ops (op_iop [entry], op, intrq); /* get instruction operands */ + + if (reason != SCPE_OK) /* evaluation failed? */ + return reason; /* return reason for failure */ + } + +switch (entry) { /* decode IR<5:0> */ + + case 000: /* CRC 105460 (OP_V) */ + t = ReadW (op[0].word) ^ (AR & 0377); /* xor prev CRC and char */ + for (i = 0; i < 8; i++) { /* apply polynomial */ + t = (t >> 1) | ((t & 1) << 15); /* rotate right */ + if (t & SIGN) t = t ^ 020001; /* old t<0>? xor */ + } + WriteW (op[0].word, t); /* rewrite CRC */ + break; + + case 001: /* RESTR 105461 (OP_N) */ + iop_sp = (iop_sp - 1) & VAMASK; /* decr stack ptr */ + t = ReadW (iop_sp); /* get E and O */ + O = ((t >> 1) ^ 1) & 1; /* restore O */ + E = t & 1; /* restore E */ + iop_sp = (iop_sp - 1) & VAMASK; /* decr sp */ + BR = ReadW (iop_sp); /* restore B */ + iop_sp = (iop_sp - 1) & VAMASK; /* decr sp */ + AR = ReadW (iop_sp); /* restore A */ + if (UNIT_CPU_MODEL == UNIT_2100) + mp_fence = iop_sp; /* 2100 keeps sp in MP FR */ + break; + + case 002: /* READF 105462 (OP_N) */ + AR = (uint16) iop_sp; /* copy stk ptr */ + break; + + case 003: /* INS 105463 (OP_N) */ + iop_sp = AR; /* init stk ptr */ + break; + + case 004: /* ENQ 105464 (OP_N) */ + hp = ReadW (AR & VAMASK); /* addr of head */ + tp = ReadW ((AR + 1) & VAMASK); /* addr of tail */ + WriteW ((BR - 1) & VAMASK, 0); /* entry link */ + WriteW ((tp - 1) & VAMASK, BR); /* tail link */ + WriteW ((AR + 1) & VAMASK, BR); /* queue tail */ + if (hp != 0) PC = (PC + 1) & VAMASK; /* q not empty? skip */ + break; + + case 005: /* PENQ 105465 (OP_N) */ + hp = ReadW (AR & VAMASK); /* addr of head */ + WriteW ((BR - 1) & VAMASK, hp); /* becomes entry link */ + WriteW (AR & VAMASK, BR); /* queue head */ + if (hp == 0) /* q empty? */ + WriteW ((AR + 1) & VAMASK, BR); /* queue tail */ + else PC = (PC + 1) & VAMASK; /* skip */ + break; + + case 006: /* DEQ 105466 (OP_N) */ + BR = ReadW (AR & VAMASK); /* addr of head */ + if (BR) { /* queue not empty? */ + hp = ReadW ((BR - 1) & VAMASK); /* read hd entry link */ + WriteW (AR & VAMASK, hp); /* becomes queue head */ + if (hp == 0) /* q now empty? */ + WriteW ((AR + 1) & VAMASK, (AR + 1) & DMASK); + PC = (PC + 1) & VAMASK; /* skip */ + } + break; + + case 007: /* TRSLT 105467 (OP_V) */ + wc = ReadW (op[0].word); /* get count */ + if (wc & SIGN) break; /* cnt < 0? */ + while (wc != 0) { /* loop */ + MA = (AR + AR + ReadB (BR)) & VAMASK; + t = ReadB (MA); /* xlate */ + WriteB (BR, t); /* store char */ + BR = (BR + 1) & DMASK; /* incr ptr */ + wc = (wc - 1) & DMASK; /* decr cnt */ + if (wc && intrq) { /* more and intr? */ + WriteW (op[0].word, wc); /* save count */ + PC = err_PC; /* stop for now */ + break; + } + } + break; + + case 010: /* ILIST 105470 (OP_AC) */ + do { /* for count */ + WriteW (op[0].word, AR); /* write AR to mem */ + AR = (AR + 1) & DMASK; /* incr AR */ + op[0].word = (op[0].word + 1) & VAMASK; /* incr MA */ + op[1].word = (op[1].word - 1) & DMASK; /* decr count */ + } + while (op[1].word != 0); + break; + + case 011: /* PRFEI 105471 (OP_CVA) */ + WriteW (op[1].word, 1); /* set flag */ + reason = iogrp (op[0].word, 0); /* execute I/O instr */ + op[0].word = op[2].word; /* set rtn and fall through */ + + case 012: /* PRFEX 105472 (OP_A) */ + PCQ_ENTRY; + PC = ReadW (op[0].word) & VAMASK; /* jump indirect */ + WriteW (op[0].word, 0); /* clear exit */ + break; + + case 013: /* PRFIO 105473 (OP_CV) */ + WriteW (op[1].word, 1); /* set flag */ + reason = iogrp (op[0].word, 0); /* execute instr */ + break; + + case 014: /* SAVE 105474 (OP_N) */ + WriteW (iop_sp, AR); /* save A */ + iop_sp = (iop_sp + 1) & VAMASK; /* incr stack ptr */ + WriteW (iop_sp, BR); /* save B */ + iop_sp = (iop_sp + 1) & VAMASK; /* incr stack ptr */ + t = ((O ^ 1) << 1) | E; /* merge E and O */ + WriteW (iop_sp, t); /* save E and O */ + iop_sp = (iop_sp + 1) & VAMASK; /* incr stack ptr */ + if (UNIT_CPU_TYPE == UNIT_TYPE_2100) + mp_fence = iop_sp; /* 2100 keeps sp in MP FR */ + break; + + default: /* instruction undefined */ + return stop_inst; + } + +return reason; +} diff --git a/HP2100/hp2100_cpu3.c b/HP2100/hp2100_cpu3.c index 028e6857..03ab3848 100644 --- a/HP2100/hp2100_cpu3.c +++ b/HP2100/hp2100_cpu3.c @@ -1,814 +1,827 @@ -/* hp2100_cpu3.c: HP 2100/1000 FFP/DBI instructions - - Copyright (c) 2005-2008, J. David Bryan - - 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 - THE AUTHOR 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 the author shall not be - used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from the author. - - CPU3 Fast FORTRAN and Double Integer instructions - - 11-Sep-08 JDB Moved microcode function prototypes to hp2100_cpu1.h - 05-Sep-08 JDB Removed option-present tests (now in UIG dispatchers) - 05-Aug-08 JDB Updated mp_dms_jmp calling sequence - 27-Feb-08 JDB Added DBI self-test instruction - 23-Oct-07 JDB Fixed unsigned-divide bug in .DDI - 17-Oct-07 JDB Fixed unsigned-multiply bug in .DMP - 16-Oct-06 JDB Calls FPP for extended-precision math - 12-Oct-06 JDB Altered DBLE, DDINT for F-Series FFP compatibility - 26-Sep-06 JDB Moved from hp2100_cpu1.c to simplify extensions - 09-Aug-06 JDB Added double-integer instruction set - 18-Feb-05 JDB Add 2100/21MX Fast FORTRAN Processor instructions - - Primary references: - - HP 1000 M/E/F-Series Computers Technical Reference Handbook - (5955-0282, Mar-1980) - - HP 1000 M/E/F-Series Computers Engineering and Reference Documentation - (92851-90001, Mar-1981) - - Macro/1000 Reference Manual (92059-90001, Dec-1992) - - Additional references are listed with the associated firmware - implementations, as are the HP option model numbers pertaining to the - applicable CPUs. -*/ - -#include "hp2100_defs.h" -#include "hp2100_cpu.h" -#include "hp2100_cpu1.h" - -#if defined (HAVE_INT64) /* int64 support available */ -#include "hp2100_fp1.h" -#else /* int64 support unavailable */ -#include "hp2100_fp.h" -#endif /* end of int64 support */ - - -/* Fast FORTRAN Processor. - - The Fast FORTRAN Processor (FFP) is a set of FORTRAN language accelerators - and extended-precision (three-word) floating point routines. Although the - FFP is an option for the 2100 and later CPUs, each implements the FFP in a - slightly different form. - - Option implementation by CPU was as follows: - - 2114 2115 2116 2100 1000-M 1000-E 1000-F - ------ ------ ------ ------ ------ ------ ------ - N/A N/A N/A 12907A 12977B 13306B std - - The instruction codes are mapped to routines as follows: - - Instr. 2100 1000-M 1000-E 1000-F Instr. 2100 1000-M 1000-E 1000-F - ------ ------ ------ ------ ------ ------ ------ ------ ------ ------ - 105200 -- [nop] [nop] [test] 105220 .XFER .XFER .XFER .XFER - 105201 DBLE DBLE DBLE DBLE 105221 .GOTO .GOTO .GOTO .GOTO - 105202 SNGL SNGL SNGL SNGL 105222 ..MAP ..MAP ..MAP ..MAP - 105203 .XMPY .XMPY .XMPY .DNG 105223 .ENTR .ENTR .ENTR .ENTR - 105204 .XDIV .XDIV .XDIV .DCO 105224 .ENTP .ENTP .ENTP .ENTP - 105205 .DFER .DFER .DFER .DFER 105225 -- .PWR2 .PWR2 .PWR2 - 105206 -- .XPAK .XPAK .XPAK 105226 -- .FLUN .FLUN .FLUN - 105207 -- XADD XADD .BLE 105227 $SETP $SETP $SETP $SETP - - 105210 -- XSUB XSUB .DIN 105230 -- .PACK .PACK .PACK - 105211 -- XMPY XMPY .DDE 105231 -- -- .CFER .CFER - 105212 -- XDIV XDIV .DIS 105232 -- -- -- ..FCM - 105213 .XADD .XADD .XADD .DDS 105233 -- -- -- ..TCM - 105214 .XSUB .XSUB .XSUB .NGL 105234 -- -- -- -- - 105215 -- .XCOM .XCOM .XCOM 105235 -- -- -- -- - 105216 -- ..DCM ..DCM ..DCM 105236 -- -- -- -- - 105217 -- DDINT DDINT DDINT 105237 -- -- -- -- - - The F-Series maps different instructions to several of the standard FFP - opcodes. We first look for these and dispatch them appropriately before - falling into the handler for the common instructions. - - The math functions use the F-Series FPP for implementation. The FPP requires - that the host compiler support 64-bit integers. Therefore, if 64-bit - integers are not available, the math instructions of the FFP are disabled. - We allow this partial implementation as an aid in running systems generated - for the FFP. Most system programs did not use the math instructions, but - almost all use .ENTR. Supporting the latter even on systems that do not - support the former still allows such systems to boot. - - Implementation notes: - - 1. The "$SETP" instruction is sometimes listed as ".SETP" in the - documentation. - - 2. Extended-precision arithmetic routines (e.g., .XMPY) exist on the 1000-F, - but they are assigned instruction codes in the single-precision - floating-point module range. They are replaced by several double integer - instructions, which we dispatch to the double integer handler. - - 3. The software implementation of ..MAP supports 1-, 2-, or 3-dimensional - arrays, designated by setting A = -1, 0, and +1, respectively. The - firmware implementation supports only 2- and 3-dimensional access. - - 4. The documentation for ..MAP for the 2100 FFP shows A = 0 or -1 for two or - three dimensions, respectively, but the 1000 FFP shows A = 0 or +1. The - firmware actually only checks the LSB of A. - - 5. The .DFER and .XFER implementations for the 2100 FFP return X+4 and Y+4 - in the A and B registers, whereas the 1000 FFP returns X+3 and Y+3. - - 6. The .XFER implementation for the 2100 FFP returns to P+2, whereas the - 1000 implementation returns to P+1. - - 7. The firmware implementations of DBLE, .BLE, and DDINT clear the overflow - flag. The software implementations do not change overflow. - - 8. The M/E-Series FFP arithmetic instructions (.XADD, etc.) return negative - infinity on negative overflow and positive infinity on positive overflow. - The equivalent F-Series instructions return positive infinity on both. - - 9. The protected memory lower bound for the .GOTO instruction is 2. - - Additional references: - - DOS/RTE Relocatable Library Reference Manual (24998-90001, Oct-1981) - - Implementing the HP 2100 Fast FORTRAN Processor (12907-90010, Nov-1974) -*/ - -static const OP_PAT op_ffp_f[32] = { /* patterns for F-Series only */ - OP_N, OP_AAF, OP_AX, OP_N, /* [tst] DBLE SNGL .DNG */ - OP_N, OP_AA, OP_A, OP_AAF, /* .DCO .DFER .XPAK .BLE */ - OP_N, OP_N, OP_N, OP_N, /* .DIN .DDE .DIS .DDS */ - OP_AT, OP_A, OP_A, OP_AAX, /* .NGL .XCOM ..DCM DDINT */ - OP_N, OP_AK, OP_KKKK, OP_A, /* .XFER .GOTO ..MAP .ENTR */ - OP_A, OP_RK, OP_R, OP_K, /* .ENTP .PWR2 .FLUN $SETP */ - OP_RC, OP_AA, OP_R, OP_A, /* .PACK .CFER ..FCM ..TCM */ - OP_N, OP_N, OP_N, OP_N /* --- --- --- --- */ - }; - -static const OP_PAT op_ffp_e[32] = { /* patterns for 2100/M/E-Series */ - OP_N, OP_AAF, OP_AX, OP_AXX, /* [nop] DBLE SNGL .XMPY */ - OP_AXX, OP_AA, OP_A, OP_AAXX, /* .XDIV .DFER .XPAK XADD */ - OP_AAXX, OP_AAXX, OP_AAXX, OP_AXX, /* XSUB XMPY XDIV .XADD */ - OP_AXX, OP_A, OP_A, OP_AAX, /* .XSUB .XCOM ..DCM DDINT */ - OP_N, OP_AK, OP_KKKK, OP_A, /* .XFER .GOTO ..MAP .ENTR */ - OP_A, OP_RK, OP_R, OP_K, /* .ENTP .PWR2 .FLUN $SETP */ - OP_RC, OP_AA, OP_N, OP_N, /* .PACK .CFER --- --- */ - OP_N, OP_N, OP_N, OP_N /* --- --- --- --- */ - }; - -t_stat cpu_ffp (uint32 IR, uint32 intrq) -{ -OP fpop; -OPS op, op2; -uint32 entry; -uint32 j, sa, sb, sc, da, dc, ra, MA; -int32 expon; -t_stat reason = SCPE_OK; - -#if defined (HAVE_INT64) /* int64 support available */ - -int32 i; - -#endif /* end of int64 support */ - -entry = IR & 037; /* mask to entry point */ - -if (UNIT_CPU_MODEL != UNIT_1000_F) { /* 2100/M/E-Series? */ - if (op_ffp_e[entry] != OP_N) - if (reason = cpu_ops (op_ffp_e[entry], op, intrq)) /* get instruction operands */ - return reason; - } - -#if defined (HAVE_INT64) /* int64 support available */ - -else { /* F-Series */ - if (op_ffp_f[entry] != OP_N) - if (reason = cpu_ops (op_ffp_f[entry], op, intrq)) /* get instruction operands */ - return reason; - - switch (entry) { /* decode IR<4:0> */ - - case 000: /* [tst] 105200 (OP_N) */ - XR = 4; /* firmware revision */ - SR = 0102077; /* test passed code */ - AR = 0; /* test clears A/B */ - BR = 0; - PC = (PC + 1) & VAMASK; /* P+2 return for firmware w/DBI */ - return reason; - - case 003: /* .DNG 105203 (OP_N) */ - return cpu_dbi (0105323, intrq); /* remap to double int handler */ - - case 004: /* .DCO 105204 (OP_N) */ - return cpu_dbi (0105324, intrq); /* remap to double int handler */ - - case 007: /* .BLE 105207 (OP_AAF) */ - O = fp_cvt (&op[2], fp_f, fp_t); /* convert value and clear overflow */ - WriteOp (op[1].word, op[2], fp_t); /* write double-precision value */ - return reason; - - case 010: /* .DIN 105210 (OP_N) */ - return cpu_dbi (0105330, intrq); /* remap to double int handler */ - - case 011: /* .DDE 105211 (OP_N) */ - return cpu_dbi (0105331, intrq); /* remap to double int handler */ - - case 012: /* .DIS 105212 (OP_N) */ - return cpu_dbi (0105332, intrq); /* remap to double int handler */ - - case 013: /* .DDS 105213 (OP_N) */ - return cpu_dbi (0105333, intrq); /* remap to double int handler */ - - case 014: /* .NGL 105214 (OP_AT) */ - O = fp_cvt (&op[1], fp_t, fp_f); /* convert value */ - AR = op[1].fpk[0]; /* move MSB to A */ - BR = op[1].fpk[1]; /* move LSB to B */ - return reason; - - case 032: /* ..FCM 105232 (OP_R) */ - O = fp_pcom (&op[0], fp_f); /* complement value */ - AR = op[0].fpk[0]; /* return result */ - BR = op[0].fpk[1]; /* to A/B registers */ - return reason; - - case 033: /* ..TCM 105233 (OP_A) */ - fpop = ReadOp (op[0].word, fp_t); /* read 4-word value */ - O = fp_pcom (&fpop, fp_t); /* complement it */ - WriteOp (op[0].word, fpop, fp_t); /* write 4-word value */ - return reason; - } /* fall thru if not special to F */ - } - -#endif /* end of int64 support */ - -switch (entry) { /* decode IR<4:0> */ - -/* FFP module 1 */ - - case 000: /* [nop] 105200 (OP_N) */ - if (UNIT_CPU_TYPE != UNIT_TYPE_1000) /* must be 1000 M/E-series */ - return stop_inst; /* trap if not */ - break; - -#if defined (HAVE_INT64) /* int64 support available */ - - case 001: /* DBLE 105201 (OP_AAF) */ - O = fp_cvt (&op[2], fp_f, fp_x); /* convert value and clear overflow */ - WriteOp (op[1].word, op[2], fp_x); /* write extended-precision value */ - break; - - case 002: /* SNGL 105202 (OP_AX) */ - O = fp_cvt (&op[1], fp_x, fp_f); /* convert value */ - AR = op[1].fpk[0]; /* move MSB to A */ - BR = op[1].fpk[1]; /* move LSB to B */ - break; - - case 003: /* .XMPY 105203 (OP_AXX) */ - i = 0; /* params start at op[0] */ - goto XMPY; /* process as XMPY */ - - case 004: /* .XDIV 105204 (OP_AXX) */ - i = 0; /* params start at op[0] */ - goto XDIV; /* process as XDIV */ - -#endif /* end of int64 support */ - - case 005: /* .DFER 105205 (OP_AA) */ - BR = op[0].word; /* get destination address */ - AR = op[1].word; /* get source address */ - goto XFER; /* do transfer */ - -#if defined (HAVE_INT64) /* int64 support available */ - - case 006: /* .XPAK 105206 (OP_A) */ - if (UNIT_CPU_TYPE != UNIT_TYPE_1000) /* must be 1000 */ - return stop_inst; /* trap if not */ - - if (intrq) { /* interrupt pending? */ - PC = err_PC; /* restart instruction */ - break; - } - - fpop = ReadOp (op[0].word, fp_x); /* read unpacked */ - O = fp_nrpack (&fpop, fpop, (int16) AR, fp_x); /* nrm/rnd/pack mantissa, exponent */ - WriteOp (op[0].word, fpop, fp_x); /* write result */ - break; - - case 007: /* XADD 105207 (OP_AAXX) */ - i = 1; /* params start at op[1] */ - XADD: /* enter here from .XADD */ - if (intrq) { /* interrupt pending? */ - PC = err_PC; /* restart instruction */ - break; - } - - O = fp_exec (001, &fpop, op[i + 1], op[i + 2]); /* three-word add */ - WriteOp (op[i].word, fpop, fp_x); /* write sum */ - break; - - case 010: /* XSUB 105210 (OP_AAXX) */ - i = 1; /* params start at op[1] */ - XSUB: /* enter here from .XSUB */ - if (intrq) { /* interrupt pending? */ - PC = err_PC; /* restart instruction */ - break; - } - - O = fp_exec (021, &fpop, op[i + 1], op[i + 2]); /* three-word subtract */ - WriteOp (op[i].word, fpop, fp_x); /* write difference */ - break; - - case 011: /* XMPY 105211 (OP_AAXX) */ - i = 1; /* params start at op[1] */ - XMPY: /* enter here from .XMPY */ - if (intrq) { /* interrupt pending? */ - PC = err_PC; /* restart instruction */ - break; - } - - O = fp_exec (041, &fpop, op[i + 1], op[i + 2]); /* three-word multiply */ - WriteOp (op[i].word, fpop, fp_x); /* write product */ - break; - - case 012: /* XDIV 105212 (OP_AAXX) */ - i = 1; /* params start at op[1] */ - XDIV: /* enter here from .XDIV */ - if (intrq) { /* interrupt pending? */ - PC = err_PC; /* restart instruction */ - break; - } - - O = fp_exec (061, &fpop, op[i + 1], op[i + 2]); /* three-word divide */ - WriteOp (op[i].word, fpop, fp_x); /* write quotient */ - break; - - case 013: /* .XADD 105213 (OP_AXX) */ - i = 0; /* params start at op[0] */ - goto XADD; /* process as XADD */ - - case 014: /* .XSUB 105214 (OP_AXX) */ - i = 0; /* params start at op[0] */ - goto XSUB; /* process as XSUB */ - - case 015: /* .XCOM 105215 (OP_A) */ - if (UNIT_CPU_TYPE != UNIT_TYPE_1000) /* must be 1000 */ - return stop_inst; /* trap if not */ - - fpop = ReadOp (op[0].word, fp_x); /* read unpacked */ - AR = fp_ucom (&fpop, fp_x); /* complement and rtn exp adj */ - WriteOp (op[0].word, fpop, fp_x); /* write result */ - break; - - case 016: /* ..DCM 105216 (OP_A) */ - if (UNIT_CPU_TYPE != UNIT_TYPE_1000) /* must be 1000 */ - return stop_inst; /* trap if not */ - - if (intrq) { /* interrupt pending? */ - PC = err_PC; /* restart instruction */ - break; - } - - fpop = ReadOp (op[0].word, fp_x); /* read operand */ - O = fp_pcom (&fpop, fp_x); /* complement (can't ovf neg) */ - WriteOp (op[0].word, fpop, fp_x); /* write result */ - break; - - case 017: /* DDINT 105217 (OP_AAX) */ - if (UNIT_CPU_TYPE != UNIT_TYPE_1000) /* must be 1000 */ - return stop_inst; /* trap if not */ - - if (intrq) { /* interrupt pending? */ - PC = err_PC; /* restart instruction */ - break; - } - - O = fp_trun (&fpop, op[2], fp_x); /* truncate operand (can't ovf) */ - WriteOp (op[1].word, fpop, fp_x); /* write result */ - break; - -#endif /* end of int64 support */ - -/* FFP module 2 */ - - case 020: /* .XFER 105220 (OP_N) */ - if (UNIT_CPU_TYPE == UNIT_TYPE_2100) - PC = (PC + 1) & VAMASK; /* 2100 .XFER returns to P+2 */ - XFER: /* enter here from .DFER */ - sc = 3; /* set count for 3-wd xfer */ - goto CFER; /* do transfer */ - - case 021: /* .GOTO 105221 (OP_AK) */ - if ((int16) op[1].word < 1) /* index < 1? */ - op[1].word = 1; /* reset min */ - - sa = PC + op[1].word - 1; /* point to jump target */ - if (sa >= op[0].word) /* must be <= last target */ - sa = op[0].word - 1; - - da = ReadW (sa); /* get jump target */ - if (reason = resolve (da, &MA, intrq)) { /* resolve indirects */ - PC = err_PC; /* irq restarts instruction */ - break; - } - - mp_dms_jmp (MA, 2); /* validate jump addr */ - PCQ_ENTRY; /* record last PC */ - PC = MA; /* jump */ - BR = op[0].word; /* (for 2100 FFP compat) */ - break; - - case 022: /* ..MAP 105222 (OP_KKKK) */ - op[1].word = op[1].word - 1; /* decrement 1st subscr */ - - if ((AR & 1) == 0) /* 2-dim access? */ - op[1].word = op[1].word + /* compute element offset */ - (op[2].word - 1) * op[3].word; - else { /* 3-dim access */ - if (reason = cpu_ops (OP_KK, op2, intrq)) { /* get 1st, 2nd ranges */ - PC = err_PC; /* irq restarts instruction */ - break; - } - op[1].word = op[1].word + /* offset */ - ((op[3].word - 1) * op2[1].word + - op[2].word - 1) * op2[0].word; - } - - AR = (op[0].word + op[1].word * BR) & DMASK; /* return element address */ - break; - - case 023: /* .ENTR 105223 (OP_A) */ - MA = PC - 3; /* get addr of entry point */ - ENTR: /* enter here from .ENTP */ - da = op[0].word; /* get addr of 1st formal */ - dc = MA - da; /* get count of formals */ - sa = ReadW (MA); /* get addr of return point */ - ra = ReadW (sa++); /* get rtn, ptr to 1st actual */ - WriteW (MA, ra); /* stuff rtn into caller's ent */ - sc = ra - sa; /* get count of actuals */ - if (sc > dc) /* use min (actuals, formals) */ - sc = dc; - - for (j = 0; j < sc; j++) { - MA = ReadW (sa++); /* get addr of actual */ - if (reason = resolve (MA, &MA, intrq)) { /* resolve indirect */ - PC = err_PC; /* irq restarts instruction */ - break; - } - WriteW (da++, MA); /* put addr into formal */ - } - - AR = ra; /* return address */ - BR = da; /* addr of 1st unused formal */ - break; - - case 024: /* .ENTP 105224 (OP_A) */ - MA = PC - 5; /* get addr of entry point */ - goto ENTR; - - case 025: /* .PWR2 105225 (OP_RK) */ - if (UNIT_CPU_TYPE != UNIT_TYPE_1000) /* must be 1000 */ - return stop_inst; /* trap if not */ - - fp_unpack (&fpop, &expon, op[0], fp_f); /* unpack value */ - expon = expon + (int16) (op[1].word); /* multiply by 2**n */ - fp_pack (&fpop, fpop, expon, fp_f); /* repack value */ - AR = fpop.fpk[0]; /* return result */ - BR = fpop.fpk[1]; /* to A/B registers */ - break; - - case 026: /* .FLUN 105226 (OP_R) */ - if (UNIT_CPU_TYPE != UNIT_TYPE_1000) /* must be 1000 */ - return stop_inst; /* trap if not */ - - fp_unpack (&fpop, &expon, op[0], fp_f); /* unpack value */ - AR = (int16) expon; /* return expon to A */ - BR = fpop.fpk[1]; /* and low mant to B */ - break; - - case 027: /* $SETP 105227 (OP_K) */ - j = sa = AR; /* save initial value */ - sb = BR; /* save initial address */ - AR = 0; /* AR will return = 0 */ - BR = BR & VAMASK; /* addr must be direct */ - - do { - WriteW (BR, j); /* write value to address */ - j = (j + 1) & DMASK; /* incr value */ - BR = (BR + 1) & VAMASK; /* incr address */ - op[0].word = op[0].word - 1; /* decr count */ - if (op[0].word && intrq) { /* more and intr? */ - AR = sa; /* restore A */ - BR = sb; /* restore B */ - PC = err_PC; /* restart instruction */ - break; - } - } - while (op[0].word != 0); /* loop until count exhausted */ - break; - - case 030: /* .PACK 105230 (OP_RC) */ - if (UNIT_CPU_TYPE != UNIT_TYPE_1000) /* must be 1000 */ - return stop_inst; /* trap if not */ - - O = fp_nrpack (&fpop, op[0], /* nrm/rnd/pack value */ - (int16) (op[1].word), fp_f); - AR = fpop.fpk[0]; /* return result */ - BR = fpop.fpk[1]; /* to A/B registers */ - break; - - case 031: /* .CFER 105231 (OP_AA) */ - if ((UNIT_CPU_MODEL != UNIT_1000_E) && /* must be 1000 E-series */ - (UNIT_CPU_MODEL != UNIT_1000_F)) /* or 1000 F-series */ - return stop_inst; /* trap if not */ - - BR = op[0].word; /* get destination address */ - AR = op[1].word; /* get source address */ - sc = 4; /* set for 4-wd xfer */ - CFER: /* enter here from .XFER */ - for (j = 0; j < sc; j++) { /* xfer loop */ - WriteW (BR, ReadW (AR)); /* transfer word */ - AR = (AR + 1) & VAMASK; /* bump source addr */ - BR = (BR + 1) & VAMASK; /* bump destination addr */ - } - - E = 0; /* routine clears E */ - - if (UNIT_CPU_TYPE == UNIT_TYPE_2100) { /* 2100 (and .DFER/.XFER)? */ - AR = (AR + 1) & VAMASK; /* 2100 FFP returns X+4, Y+4 */ - BR = (BR + 1) & VAMASK; - } - break; - - default: /* others undefined */ - reason = stop_inst; - } - -return reason; -} - - -/* Double-Integer Instructions. - - The double-integer instructions were added to the HP instruction set at - revision 1920 of the 1000-F. They were immediately adopted in a number of HP - software products, most notably the RTE file management package (FMP) - routines. As these routines are used in nearly every RTE program, F-Series - programs were almost always a few hundred bytes smaller than their M- and - E-Series counterparts. This became significant as RTE continued to grow in - size, and some customer programs ran out of address space on E-Series - machines. - - While HP never added double-integer instructions to the standard E-Series, a - product from the HP "specials group," HP 93585A, provided microcoded - replacements for the E-Series. This could provide just enough address-space - savings to allow programs to load in E-Series systems, in addition to - accelerating these common operations. - - There was no equivalent M-Series microcode, due to the limited micromachine - address space on that system. - - Option implementation by CPU was as follows: - - 2114 2115 2116 2100 1000-M 1000-E 1000-F - ------ ------ ------ ------ ------ ------ ------ - N/A N/A N/A N/A N/A 93585A std - - The routines are mapped to instruction codes as follows: - - Instr. 1000-E 1000-F Description - ------ ------ ------ ----------------------------------------- - [test] 105320 -- [self test] - .DAD 105321 105014 Double integer add - .DMP 105322 105054 Double integer multiply - .DNG 105323 105203 Double integer negate - .DCO 105324 105204 Double integer compare - .DDI 105325 105074 Double integer divide - .DDIR 105326 105134 Double integer divide (reversed) - .DSB 105327 105034 Double integer subtract - .DIN 105330 105210 Double integer increment - .DDE 105331 105211 Double integer decrement - .DIS 105332 105212 Double integer increment and skip if zero - .DDS 105333 105213 Double integer decrement and skip if zero - .DSBR 105334 105114 Double integer subtraction (reversed) - - On the F-Series, the double-integer instruction codes are split among the - floating-point processor and the Fast FORTRAN Processor ranges. They are - dispatched from those respective simulators for processing here. - - Implementation notes: - - 1. Opcodes 105335-105337 are NOPs in the microcode. They generate - unimplemented instructions stops under simulation. - - 2. This is an implementation of Revision 2 of the microcode, which was - released as ROM part numbers 93585-80003, 93585-80005, and 93585-80001 - (Revision 1 substituted -80002 for -80005). - - 3. The F-Series firmware executes .DMP and .DDI/.DDIR by floating the 32-bit - double integer to a 48-bit extended-precision number, calling the FPP to - execute the extended-precision multiply/divide, and then fixing the - product to a 32-bit double integer. We simulate these directly with 64- - or 32-bit integer arithmetic. - - Additional references: - - 93585A Microcode Source (93585-18002 Rev. 2005) - - 93585A Double Integer Instructions Installation and Reference Manual - (93585-90007) -*/ - -static const OP_PAT op_dbi[16] = { - OP_N, OP_JD, OP_JD, OP_J, /* [test] .DAD .DMP .DNG */ - OP_JD, OP_JD, OP_JD, OP_JD, /* .DCO .DDI .DDIR .DSB */ - OP_J, OP_J, OP_A, OP_A, /* .DIN .DDE .DIS .DDS */ - OP_JD, OP_N, OP_N, OP_N /* .DSBR --- --- --- */ - }; - -t_stat cpu_dbi (uint32 IR, uint32 intrq) -{ -OP din; -OPS op; -uint32 entry, t; -t_stat reason = SCPE_OK; - -entry = IR & 017; /* mask to entry point */ - -if (op_dbi[entry] != OP_N) - if (reason = cpu_ops (op_dbi[entry], op, intrq)) /* get instruction operands */ - return reason; - -switch (entry) { /* decode IR<3:0> */ - - case 000: /* [test] 105320 (OP_N) */ - XR = 2; /* set revision */ - BR = 0377; /* side effect of microcode */ - SR = 0102077; /* set "pass" code */ - PC = (PC + 1) & VAMASK; /* return to P+1 */ - t = (AR << 16) | BR; /* set t for return */ - break; - - case 001: /* .DAD 105321 (OP_JD) */ - t = op[0].dword + op[1].dword; /* add values */ - E = E | (t < op[0].dword); /* carry if result smaller */ - O = (((~op[0].dword ^ op[1].dword) & /* overflow if sign wrong */ - (op[0].dword ^ t) & SIGN32) != 0); - break; - - case 002: /* .DMP 105322 (OP_JD) */ - { - -#if defined (HAVE_INT64) /* int64 support available */ - - t_int64 t64; - - t64 = (t_int64) INT32 (op[0].dword) * /* multiply signed values */ - (t_int64) INT32 (op[1].dword); - O = ((t64 < -(t_int64) 0x80000000) || /* overflow if out of range */ - (t64 > (t_int64) 0x7FFFFFFF)); - if (O) - t = ~SIGN32; /* if overflow, rtn max pos */ - else - t = (uint32) (t64 & DMASK32); /* else lower 32 bits of result */ - -#else /* int64 support unavailable */ - - uint32 sign, xu, yu, rh, rl; - - sign = ((int32) op[0].dword < 0) ^ /* save sign of result */ - ((int32) op[1].dword < 0); - - xu = (uint32) abs ((int32) op[0].dword); /* make operands pos */ - yu = (uint32) abs ((int32) op[1].dword); - - if ((xu & 0xFFFF0000) == 0 && /* 16 x 16 multiply? */ - (yu & 0xFFFF0000) == 0) { - t = xu * yu; /* do it */ - O = 0; /* can't overflow */ - } - - else if ((xu & 0xFFFF0000) != 0 && /* 32 x 32 multiply? */ - (yu & 0xFFFF0000) != 0) - O = 1; /* always overflows */ - - else { /* 16 x 32 or 32 x 16 */ - rl = (xu & 0xFFFF) * (yu & 0xFFFF); /* form 1st partial product */ - - if ((xu & 0xFFFF0000) == 0) - rh = xu * (yu >> 16) + (rl >> 16); /* 16 x 32 2nd partial */ - else - rh = (xu >> 16) * yu + (rl >> 16); /* 32 x 16 2nd partial */ - - O = (rh > 0x7FFF + sign); /* check for out of range */ - if (O == 0) - t = (rh << 16) | (rl & 0xFFFF); /* combine partials */ - } - - if (O) - t = ~SIGN32; /* if overflow, rtn max pos */ - else if (sign) - t = ~t + 1; /* if result neg, 2s compl */ - -#endif /* end of int64 support */ - - } - break; - - case 003: /* .DNG 105323 (OP_J) */ - t = ~op[0].dword + 1; /* negate value */ - O = (op[0].dword == SIGN32); /* overflow if max neg */ - if (op[0].dword == 0) /* borrow if result zero */ - E = 1; - break; - - case 004: /* .DCO 105324 (OP_JD) */ - t = op[0].dword; /* copy for later store */ - if ((int32) op[0].dword < (int32) op[1].dword) - PC = (PC + 1) & VAMASK; /* < rtns to P+2 */ - else if ((int32) op[0].dword > (int32) op[1].dword) - PC = (PC + 2) & VAMASK; /* > rtns to P+3 */ - break; /* = rtns to P+1 */ - - case 005: /* .DDI 105325 (OP_JD) */ - DDI: - O = ((op[1].dword == 0) || /* overflow if div 0 */ - ((op[0].dword == SIGN32) && /* or max neg div -1 */ - ((int32) op[1].dword == -1))); - if (O) - t = ~SIGN32; /* rtn max pos for ovf */ - else - t = (uint32) (INT32 (op[0].dword) / /* else return quotient */ - INT32 (op[1].dword)); - break; - - case 006: /* .DDIR 105326 (OP_JD) */ - t = op[0].dword; /* swap operands */ - op[0].dword = op[1].dword; - op[1].dword = t; - goto DDI; /* continue at .DDI */ - - case 007: /* .DSB 105327 (OP_JD) */ - DSB: - t = op[0].dword - op[1].dword; /* subtract values */ - E = E | (op[0].dword < op[1].dword); /* borrow if minu < subtr */ - O = (((op[0].dword ^ op[1].dword) & /* overflow if sign wrong */ - (op[0].dword ^ t) & SIGN32) != 0); - break; - - case 010: /* .DIN 105330 (OP_J) */ - t = op[0].dword + 1; /* increment value */ - O = (t == SIGN32); /* overflow if sign flipped */ - if (t == 0) - E = 1; /* carry if result zero */ - break; - - case 011: /* .DDE 105331 (OP_J) */ - t = op[0].dword - 1; /* decrement value */ - O = (t == ~SIGN32); /* overflow if sign flipped */ - if ((int32) t == -1) - E = 1; /* borrow if result -1 */ - break; - - case 012: /* .DIS 105332 (OP_A) */ - din = ReadOp (op[0].word, in_d); /* get value */ - t = din.dword = din.dword + 1; /* increment value */ - WriteOp (op[0].word, din, in_d); /* store it back */ - if (t == 0) - PC = (PC + 1) & VAMASK; /* skip if result zero */ - break; - - case 013: /* .DDS 105333 (OP_A) */ - din = ReadOp (op[0].word, in_d); /* get value */ - t = din.dword = din.dword - 1; /* decrement value */ - WriteOp (op[0].word, din, in_d); /* write it back */ - if (t == 0) - PC = (PC + 1) & VAMASK; /* skip if result zero */ - break; - - case 014: /* .DSBR 105334 (OP_JD) */ - t = op[0].dword; /* swap operands */ - op[0].dword = op[1].dword; - op[1].dword = t; - goto DSB; /* continue at .DSB */ - - default: /* others undefined */ - t = (AR << 16) | BR; /* set t for NOP */ - reason = stop_inst; - } - -if (reason == SCPE_OK) { /* if return OK */ - AR = (t >> 16) & DMASK; /* break result */ - BR = t & DMASK; /* into A and B */ - } - -return reason; -} +/* hp2100_cpu3.c: HP 2100/1000 FFP/DBI instructions + + Copyright (c) 2005-2014, J. David Bryan + + 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 + THE AUTHOR 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 the author shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from the author. + + CPU3 Fast FORTRAN and Double Integer instructions + + 24-Dec-14 JDB Added casts for explicit downward conversions + 09-May-12 JDB Separated assignments from conditional expressions + 11-Sep-08 JDB Moved microcode function prototypes to hp2100_cpu1.h + 05-Sep-08 JDB Removed option-present tests (now in UIG dispatchers) + 05-Aug-08 JDB Updated mp_dms_jmp calling sequence + 27-Feb-08 JDB Added DBI self-test instruction + 23-Oct-07 JDB Fixed unsigned-divide bug in .DDI + 17-Oct-07 JDB Fixed unsigned-multiply bug in .DMP + 16-Oct-06 JDB Calls FPP for extended-precision math + 12-Oct-06 JDB Altered DBLE, DDINT for F-Series FFP compatibility + 26-Sep-06 JDB Moved from hp2100_cpu1.c to simplify extensions + 09-Aug-06 JDB Added double-integer instruction set + 18-Feb-05 JDB Add 2100/21MX Fast FORTRAN Processor instructions + + Primary references: + - HP 1000 M/E/F-Series Computers Technical Reference Handbook + (5955-0282, Mar-1980) + - HP 1000 M/E/F-Series Computers Engineering and Reference Documentation + (92851-90001, Mar-1981) + - Macro/1000 Reference Manual (92059-90001, Dec-1992) + + Additional references are listed with the associated firmware + implementations, as are the HP option model numbers pertaining to the + applicable CPUs. +*/ + +#include "hp2100_defs.h" +#include "hp2100_cpu.h" +#include "hp2100_cpu1.h" + +#if defined (HAVE_INT64) /* int64 support available */ +#include "hp2100_fp1.h" +#else /* int64 support unavailable */ +#include "hp2100_fp.h" +#endif /* end of int64 support */ + + +/* Fast FORTRAN Processor. + + The Fast FORTRAN Processor (FFP) is a set of FORTRAN language accelerators + and extended-precision (three-word) floating point routines. Although the + FFP is an option for the 2100 and later CPUs, each implements the FFP in a + slightly different form. + + Option implementation by CPU was as follows: + + 2114 2115 2116 2100 1000-M 1000-E 1000-F + ------ ------ ------ ------ ------ ------ ------ + N/A N/A N/A 12907A 12977B 13306B std + + The instruction codes are mapped to routines as follows: + + Instr. 2100 1000-M 1000-E 1000-F Instr. 2100 1000-M 1000-E 1000-F + ------ ------ ------ ------ ------ ------ ------ ------ ------ ------ + 105200 -- [nop] [nop] [test] 105220 .XFER .XFER .XFER .XFER + 105201 DBLE DBLE DBLE DBLE 105221 .GOTO .GOTO .GOTO .GOTO + 105202 SNGL SNGL SNGL SNGL 105222 ..MAP ..MAP ..MAP ..MAP + 105203 .XMPY .XMPY .XMPY .DNG 105223 .ENTR .ENTR .ENTR .ENTR + 105204 .XDIV .XDIV .XDIV .DCO 105224 .ENTP .ENTP .ENTP .ENTP + 105205 .DFER .DFER .DFER .DFER 105225 -- .PWR2 .PWR2 .PWR2 + 105206 -- .XPAK .XPAK .XPAK 105226 -- .FLUN .FLUN .FLUN + 105207 -- XADD XADD .BLE 105227 $SETP $SETP $SETP $SETP + + 105210 -- XSUB XSUB .DIN 105230 -- .PACK .PACK .PACK + 105211 -- XMPY XMPY .DDE 105231 -- -- .CFER .CFER + 105212 -- XDIV XDIV .DIS 105232 -- -- -- ..FCM + 105213 .XADD .XADD .XADD .DDS 105233 -- -- -- ..TCM + 105214 .XSUB .XSUB .XSUB .NGL 105234 -- -- -- -- + 105215 -- .XCOM .XCOM .XCOM 105235 -- -- -- -- + 105216 -- ..DCM ..DCM ..DCM 105236 -- -- -- -- + 105217 -- DDINT DDINT DDINT 105237 -- -- -- -- + + The F-Series maps different instructions to several of the standard FFP + opcodes. We first look for these and dispatch them appropriately before + falling into the handler for the common instructions. + + The math functions use the F-Series FPP for implementation. The FPP requires + that the host compiler support 64-bit integers. Therefore, if 64-bit + integers are not available, the math instructions of the FFP are disabled. + We allow this partial implementation as an aid in running systems generated + for the FFP. Most system programs did not use the math instructions, but + almost all use .ENTR. Supporting the latter even on systems that do not + support the former still allows such systems to boot. + + Implementation notes: + + 1. The "$SETP" instruction is sometimes listed as ".SETP" in the + documentation. + + 2. Extended-precision arithmetic routines (e.g., .XMPY) exist on the 1000-F, + but they are assigned instruction codes in the single-precision + floating-point module range. They are replaced by several double integer + instructions, which we dispatch to the double integer handler. + + 3. The software implementation of ..MAP supports 1-, 2-, or 3-dimensional + arrays, designated by setting A = -1, 0, and +1, respectively. The + firmware implementation supports only 2- and 3-dimensional access. + + 4. The documentation for ..MAP for the 2100 FFP shows A = 0 or -1 for two or + three dimensions, respectively, but the 1000 FFP shows A = 0 or +1. The + firmware actually only checks the LSB of A. + + 5. The .DFER and .XFER implementations for the 2100 FFP return X+4 and Y+4 + in the A and B registers, whereas the 1000 FFP returns X+3 and Y+3. + + 6. The .XFER implementation for the 2100 FFP returns to P+2, whereas the + 1000 implementation returns to P+1. + + 7. The firmware implementations of DBLE, .BLE, and DDINT clear the overflow + flag. The software implementations do not change overflow. + + 8. The M/E-Series FFP arithmetic instructions (.XADD, etc.) return negative + infinity on negative overflow and positive infinity on positive overflow. + The equivalent F-Series instructions return positive infinity on both. + + 9. The protected memory lower bound for the .GOTO instruction is 2. + + Additional references: + - DOS/RTE Relocatable Library Reference Manual (24998-90001, Oct-1981) + - Implementing the HP 2100 Fast FORTRAN Processor (12907-90010, Nov-1974) +*/ + +static const OP_PAT op_ffp_f[32] = { /* patterns for F-Series only */ + OP_N, OP_AAF, OP_AX, OP_N, /* [tst] DBLE SNGL .DNG */ + OP_N, OP_AA, OP_A, OP_AAF, /* .DCO .DFER .XPAK .BLE */ + OP_N, OP_N, OP_N, OP_N, /* .DIN .DDE .DIS .DDS */ + OP_AT, OP_A, OP_A, OP_AAX, /* .NGL .XCOM ..DCM DDINT */ + OP_N, OP_AK, OP_KKKK, OP_A, /* .XFER .GOTO ..MAP .ENTR */ + OP_A, OP_RK, OP_R, OP_K, /* .ENTP .PWR2 .FLUN $SETP */ + OP_RC, OP_AA, OP_R, OP_A, /* .PACK .CFER ..FCM ..TCM */ + OP_N, OP_N, OP_N, OP_N /* --- --- --- --- */ + }; + +static const OP_PAT op_ffp_e[32] = { /* patterns for 2100/M/E-Series */ + OP_N, OP_AAF, OP_AX, OP_AXX, /* [nop] DBLE SNGL .XMPY */ + OP_AXX, OP_AA, OP_A, OP_AAXX, /* .XDIV .DFER .XPAK XADD */ + OP_AAXX, OP_AAXX, OP_AAXX, OP_AXX, /* XSUB XMPY XDIV .XADD */ + OP_AXX, OP_A, OP_A, OP_AAX, /* .XSUB .XCOM ..DCM DDINT */ + OP_N, OP_AK, OP_KKKK, OP_A, /* .XFER .GOTO ..MAP .ENTR */ + OP_A, OP_RK, OP_R, OP_K, /* .ENTP .PWR2 .FLUN $SETP */ + OP_RC, OP_AA, OP_N, OP_N, /* .PACK .CFER --- --- */ + OP_N, OP_N, OP_N, OP_N /* --- --- --- --- */ + }; + +t_stat cpu_ffp (uint32 IR, uint32 intrq) +{ +OP fpop; +OPS op, op2; +uint32 entry; +uint32 j, sa, sb, sc, da, dc, ra, MA; +int32 expon; +t_stat reason = SCPE_OK; + +#if defined (HAVE_INT64) /* int64 support available */ + +int32 i; + +#endif /* end of int64 support */ + +entry = IR & 037; /* mask to entry point */ + +if (UNIT_CPU_MODEL != UNIT_1000_F) { /* 2100/M/E-Series? */ + if (op_ffp_e [entry] != OP_N) { + reason = cpu_ops (op_ffp_e [entry], op, intrq); /* get instruction operands */ + + if (reason != SCPE_OK) /* evaluation failed? */ + return reason; /* return reason for failure */ + } + } + +#if defined (HAVE_INT64) /* int64 support available */ + +else { /* F-Series */ + if (op_ffp_f [entry] != OP_N) { + reason = cpu_ops (op_ffp_f [entry], op, intrq); /* get instruction operands */ + + if (reason != SCPE_OK) /* evaluation failed? */ + return reason; /* return reason for failure */ + } + + switch (entry) { /* decode IR<4:0> */ + + case 000: /* [tst] 105200 (OP_N) */ + XR = 4; /* firmware revision */ + SR = 0102077; /* test passed code */ + AR = 0; /* test clears A/B */ + BR = 0; + PC = (PC + 1) & VAMASK; /* P+2 return for firmware w/DBI */ + return reason; + + case 003: /* .DNG 105203 (OP_N) */ + return cpu_dbi (0105323, intrq); /* remap to double int handler */ + + case 004: /* .DCO 105204 (OP_N) */ + return cpu_dbi (0105324, intrq); /* remap to double int handler */ + + case 007: /* .BLE 105207 (OP_AAF) */ + O = fp_cvt (&op[2], fp_f, fp_t); /* convert value and clear overflow */ + WriteOp (op[1].word, op[2], fp_t); /* write double-precision value */ + return reason; + + case 010: /* .DIN 105210 (OP_N) */ + return cpu_dbi (0105330, intrq); /* remap to double int handler */ + + case 011: /* .DDE 105211 (OP_N) */ + return cpu_dbi (0105331, intrq); /* remap to double int handler */ + + case 012: /* .DIS 105212 (OP_N) */ + return cpu_dbi (0105332, intrq); /* remap to double int handler */ + + case 013: /* .DDS 105213 (OP_N) */ + return cpu_dbi (0105333, intrq); /* remap to double int handler */ + + case 014: /* .NGL 105214 (OP_AT) */ + O = fp_cvt (&op[1], fp_t, fp_f); /* convert value */ + AR = op[1].fpk[0]; /* move MSB to A */ + BR = op[1].fpk[1]; /* move LSB to B */ + return reason; + + case 032: /* ..FCM 105232 (OP_R) */ + O = fp_pcom (&op[0], fp_f); /* complement value */ + AR = op[0].fpk[0]; /* return result */ + BR = op[0].fpk[1]; /* to A/B registers */ + return reason; + + case 033: /* ..TCM 105233 (OP_A) */ + fpop = ReadOp (op[0].word, fp_t); /* read 4-word value */ + O = fp_pcom (&fpop, fp_t); /* complement it */ + WriteOp (op[0].word, fpop, fp_t); /* write 4-word value */ + return reason; + } /* fall thru if not special to F */ + } + +#endif /* end of int64 support */ + +switch (entry) { /* decode IR<4:0> */ + +/* FFP module 1 */ + + case 000: /* [nop] 105200 (OP_N) */ + if (UNIT_CPU_TYPE != UNIT_TYPE_1000) /* must be 1000 M/E-series */ + return stop_inst; /* trap if not */ + break; + +#if defined (HAVE_INT64) /* int64 support available */ + + case 001: /* DBLE 105201 (OP_AAF) */ + O = fp_cvt (&op[2], fp_f, fp_x); /* convert value and clear overflow */ + WriteOp (op[1].word, op[2], fp_x); /* write extended-precision value */ + break; + + case 002: /* SNGL 105202 (OP_AX) */ + O = fp_cvt (&op[1], fp_x, fp_f); /* convert value */ + AR = op[1].fpk[0]; /* move MSB to A */ + BR = op[1].fpk[1]; /* move LSB to B */ + break; + + case 003: /* .XMPY 105203 (OP_AXX) */ + i = 0; /* params start at op[0] */ + goto XMPY; /* process as XMPY */ + + case 004: /* .XDIV 105204 (OP_AXX) */ + i = 0; /* params start at op[0] */ + goto XDIV; /* process as XDIV */ + +#endif /* end of int64 support */ + + case 005: /* .DFER 105205 (OP_AA) */ + BR = op[0].word; /* get destination address */ + AR = op[1].word; /* get source address */ + goto XFER; /* do transfer */ + +#if defined (HAVE_INT64) /* int64 support available */ + + case 006: /* .XPAK 105206 (OP_A) */ + if (UNIT_CPU_TYPE != UNIT_TYPE_1000) /* must be 1000 */ + return stop_inst; /* trap if not */ + + if (intrq) { /* interrupt pending? */ + PC = err_PC; /* restart instruction */ + break; + } + + fpop = ReadOp (op[0].word, fp_x); /* read unpacked */ + O = fp_nrpack (&fpop, fpop, (int16) AR, fp_x); /* nrm/rnd/pack mantissa, exponent */ + WriteOp (op[0].word, fpop, fp_x); /* write result */ + break; + + case 007: /* XADD 105207 (OP_AAXX) */ + i = 1; /* params start at op[1] */ + XADD: /* enter here from .XADD */ + if (intrq) { /* interrupt pending? */ + PC = err_PC; /* restart instruction */ + break; + } + + O = fp_exec (001, &fpop, op[i + 1], op[i + 2]); /* three-word add */ + WriteOp (op[i].word, fpop, fp_x); /* write sum */ + break; + + case 010: /* XSUB 105210 (OP_AAXX) */ + i = 1; /* params start at op[1] */ + XSUB: /* enter here from .XSUB */ + if (intrq) { /* interrupt pending? */ + PC = err_PC; /* restart instruction */ + break; + } + + O = fp_exec (021, &fpop, op[i + 1], op[i + 2]); /* three-word subtract */ + WriteOp (op[i].word, fpop, fp_x); /* write difference */ + break; + + case 011: /* XMPY 105211 (OP_AAXX) */ + i = 1; /* params start at op[1] */ + XMPY: /* enter here from .XMPY */ + if (intrq) { /* interrupt pending? */ + PC = err_PC; /* restart instruction */ + break; + } + + O = fp_exec (041, &fpop, op[i + 1], op[i + 2]); /* three-word multiply */ + WriteOp (op[i].word, fpop, fp_x); /* write product */ + break; + + case 012: /* XDIV 105212 (OP_AAXX) */ + i = 1; /* params start at op[1] */ + XDIV: /* enter here from .XDIV */ + if (intrq) { /* interrupt pending? */ + PC = err_PC; /* restart instruction */ + break; + } + + O = fp_exec (061, &fpop, op[i + 1], op[i + 2]); /* three-word divide */ + WriteOp (op[i].word, fpop, fp_x); /* write quotient */ + break; + + case 013: /* .XADD 105213 (OP_AXX) */ + i = 0; /* params start at op[0] */ + goto XADD; /* process as XADD */ + + case 014: /* .XSUB 105214 (OP_AXX) */ + i = 0; /* params start at op[0] */ + goto XSUB; /* process as XSUB */ + + case 015: /* .XCOM 105215 (OP_A) */ + if (UNIT_CPU_TYPE != UNIT_TYPE_1000) /* must be 1000 */ + return stop_inst; /* trap if not */ + + fpop = ReadOp (op[0].word, fp_x); /* read unpacked */ + AR = fp_ucom (&fpop, fp_x); /* complement and rtn exp adj */ + WriteOp (op[0].word, fpop, fp_x); /* write result */ + break; + + case 016: /* ..DCM 105216 (OP_A) */ + if (UNIT_CPU_TYPE != UNIT_TYPE_1000) /* must be 1000 */ + return stop_inst; /* trap if not */ + + if (intrq) { /* interrupt pending? */ + PC = err_PC; /* restart instruction */ + break; + } + + fpop = ReadOp (op[0].word, fp_x); /* read operand */ + O = fp_pcom (&fpop, fp_x); /* complement (can't ovf neg) */ + WriteOp (op[0].word, fpop, fp_x); /* write result */ + break; + + case 017: /* DDINT 105217 (OP_AAX) */ + if (UNIT_CPU_TYPE != UNIT_TYPE_1000) /* must be 1000 */ + return stop_inst; /* trap if not */ + + if (intrq) { /* interrupt pending? */ + PC = err_PC; /* restart instruction */ + break; + } + + O = fp_trun (&fpop, op[2], fp_x); /* truncate operand (can't ovf) */ + WriteOp (op[1].word, fpop, fp_x); /* write result */ + break; + +#endif /* end of int64 support */ + +/* FFP module 2 */ + + case 020: /* .XFER 105220 (OP_N) */ + if (UNIT_CPU_TYPE == UNIT_TYPE_2100) + PC = (PC + 1) & VAMASK; /* 2100 .XFER returns to P+2 */ + XFER: /* enter here from .DFER */ + sc = 3; /* set count for 3-wd xfer */ + goto CFER; /* do transfer */ + + case 021: /* .GOTO 105221 (OP_AK) */ + if ((int16) op[1].word < 1) /* index < 1? */ + op[1].word = 1; /* reset min */ + + sa = PC + op[1].word - 1; /* point to jump target */ + if (sa >= op[0].word) /* must be <= last target */ + sa = op[0].word - 1; + + da = ReadW (sa); /* get jump target */ + reason = resolve (da, &MA, intrq); /* resolve indirects */ + if (reason != SCPE_OK) { /* resolution failed? */ + PC = err_PC; /* irq restarts instruction */ + break; + } + + mp_dms_jmp (MA, 2); /* validate jump addr */ + PCQ_ENTRY; /* record last PC */ + PC = MA; /* jump */ + BR = op[0].word; /* (for 2100 FFP compat) */ + break; + + case 022: /* ..MAP 105222 (OP_KKKK) */ + op[1].word = op[1].word - 1; /* decrement 1st subscr */ + + if ((AR & 1) == 0) /* 2-dim access? */ + op[1].word = op[1].word + /* compute element offset */ + (op[2].word - 1) * op[3].word; + else { /* 3-dim access */ + reason = cpu_ops (OP_KK, op2, intrq); /* get 1st, 2nd ranges */ + if (reason != SCPE_OK) { /* evaluation failed? */ + PC = err_PC; /* irq restarts instruction */ + break; + } + op[1].word = op[1].word + /* offset */ + ((op[3].word - 1) * op2[1].word + + op[2].word - 1) * op2[0].word; + } + + AR = (op[0].word + op[1].word * BR) & DMASK; /* return element address */ + break; + + case 023: /* .ENTR 105223 (OP_A) */ + MA = PC - 3; /* get addr of entry point */ + ENTR: /* enter here from .ENTP */ + da = op[0].word; /* get addr of 1st formal */ + dc = MA - da; /* get count of formals */ + sa = ReadW (MA); /* get addr of return point */ + ra = ReadW (sa++); /* get rtn, ptr to 1st actual */ + WriteW (MA, ra); /* stuff rtn into caller's ent */ + sc = ra - sa; /* get count of actuals */ + if (sc > dc) /* use min (actuals, formals) */ + sc = dc; + + for (j = 0; j < sc; j++) { + MA = ReadW (sa++); /* get addr of actual */ + reason = resolve (MA, &MA, intrq); /* resolve indirect */ + if (reason != SCPE_OK) { /* resolution failed? */ + PC = err_PC; /* irq restarts instruction */ + break; + } + WriteW (da++, MA); /* put addr into formal */ + } + + AR = (uint16) ra; /* return address */ + BR = (uint16) da; /* addr of 1st unused formal */ + break; + + case 024: /* .ENTP 105224 (OP_A) */ + MA = PC - 5; /* get addr of entry point */ + goto ENTR; + + case 025: /* .PWR2 105225 (OP_RK) */ + if (UNIT_CPU_TYPE != UNIT_TYPE_1000) /* must be 1000 */ + return stop_inst; /* trap if not */ + + fp_unpack (&fpop, &expon, op[0], fp_f); /* unpack value */ + expon = expon + (int16) (op[1].word); /* multiply by 2**n */ + fp_pack (&fpop, fpop, expon, fp_f); /* repack value */ + AR = fpop.fpk[0]; /* return result */ + BR = fpop.fpk[1]; /* to A/B registers */ + break; + + case 026: /* .FLUN 105226 (OP_R) */ + if (UNIT_CPU_TYPE != UNIT_TYPE_1000) /* must be 1000 */ + return stop_inst; /* trap if not */ + + fp_unpack (&fpop, &expon, op[0], fp_f); /* unpack value */ + AR = (int16) expon; /* return expon to A */ + BR = fpop.fpk[1]; /* and low mant to B */ + break; + + case 027: /* $SETP 105227 (OP_K) */ + j = sa = AR; /* save initial value */ + sb = BR; /* save initial address */ + AR = 0; /* AR will return = 0 */ + BR = BR & VAMASK; /* addr must be direct */ + + do { + WriteW (BR, j); /* write value to address */ + j = (j + 1) & DMASK; /* incr value */ + BR = (BR + 1) & VAMASK; /* incr address */ + op[0].word = op[0].word - 1; /* decr count */ + if (op[0].word && intrq) { /* more and intr? */ + AR = (uint16) sa; /* restore A */ + BR = (uint16) sb; /* restore B */ + PC = err_PC; /* restart instruction */ + break; + } + } + while (op[0].word != 0); /* loop until count exhausted */ + break; + + case 030: /* .PACK 105230 (OP_RC) */ + if (UNIT_CPU_TYPE != UNIT_TYPE_1000) /* must be 1000 */ + return stop_inst; /* trap if not */ + + O = fp_nrpack (&fpop, op[0], /* nrm/rnd/pack value */ + (int16) (op[1].word), fp_f); + AR = fpop.fpk[0]; /* return result */ + BR = fpop.fpk[1]; /* to A/B registers */ + break; + + case 031: /* .CFER 105231 (OP_AA) */ + if ((UNIT_CPU_MODEL != UNIT_1000_E) && /* must be 1000 E-series */ + (UNIT_CPU_MODEL != UNIT_1000_F)) /* or 1000 F-series */ + return stop_inst; /* trap if not */ + + BR = op[0].word; /* get destination address */ + AR = op[1].word; /* get source address */ + sc = 4; /* set for 4-wd xfer */ + CFER: /* enter here from .XFER */ + for (j = 0; j < sc; j++) { /* xfer loop */ + WriteW (BR, ReadW (AR)); /* transfer word */ + AR = (AR + 1) & VAMASK; /* bump source addr */ + BR = (BR + 1) & VAMASK; /* bump destination addr */ + } + + E = 0; /* routine clears E */ + + if (UNIT_CPU_TYPE == UNIT_TYPE_2100) { /* 2100 (and .DFER/.XFER)? */ + AR = (AR + 1) & VAMASK; /* 2100 FFP returns X+4, Y+4 */ + BR = (BR + 1) & VAMASK; + } + break; + + default: /* others undefined */ + reason = stop_inst; + } + +return reason; +} + + +/* Double-Integer Instructions. + + The double-integer instructions were added to the HP instruction set at + revision 1920 of the 1000-F. They were immediately adopted in a number of HP + software products, most notably the RTE file management package (FMP) + routines. As these routines are used in nearly every RTE program, F-Series + programs were almost always a few hundred bytes smaller than their M- and + E-Series counterparts. This became significant as RTE continued to grow in + size, and some customer programs ran out of address space on E-Series + machines. + + While HP never added double-integer instructions to the standard E-Series, a + product from the HP "specials group," HP 93585A, provided microcoded + replacements for the E-Series. This could provide just enough address-space + savings to allow programs to load in E-Series systems, in addition to + accelerating these common operations. + + There was no equivalent M-Series microcode, due to the limited micromachine + address space on that system. + + Option implementation by CPU was as follows: + + 2114 2115 2116 2100 1000-M 1000-E 1000-F + ------ ------ ------ ------ ------ ------ ------ + N/A N/A N/A N/A N/A 93585A std + + The routines are mapped to instruction codes as follows: + + Instr. 1000-E 1000-F Description + ------ ------ ------ ----------------------------------------- + [test] 105320 -- [self test] + .DAD 105321 105014 Double integer add + .DMP 105322 105054 Double integer multiply + .DNG 105323 105203 Double integer negate + .DCO 105324 105204 Double integer compare + .DDI 105325 105074 Double integer divide + .DDIR 105326 105134 Double integer divide (reversed) + .DSB 105327 105034 Double integer subtract + .DIN 105330 105210 Double integer increment + .DDE 105331 105211 Double integer decrement + .DIS 105332 105212 Double integer increment and skip if zero + .DDS 105333 105213 Double integer decrement and skip if zero + .DSBR 105334 105114 Double integer subtraction (reversed) + + On the F-Series, the double-integer instruction codes are split among the + floating-point processor and the Fast FORTRAN Processor ranges. They are + dispatched from those respective simulators for processing here. + + Implementation notes: + + 1. Opcodes 105335-105337 are NOPs in the microcode. They generate + unimplemented instructions stops under simulation. + + 2. This is an implementation of Revision 2 of the microcode, which was + released as ROM part numbers 93585-80003, 93585-80005, and 93585-80001 + (Revision 1 substituted -80002 for -80005). + + 3. The F-Series firmware executes .DMP and .DDI/.DDIR by floating the 32-bit + double integer to a 48-bit extended-precision number, calling the FPP to + execute the extended-precision multiply/divide, and then fixing the + product to a 32-bit double integer. We simulate these directly with 64- + or 32-bit integer arithmetic. + + Additional references: + - 93585A Microcode Source (93585-18002 Rev. 2005) + - 93585A Double Integer Instructions Installation and Reference Manual + (93585-90007) +*/ + +static const OP_PAT op_dbi[16] = { + OP_N, OP_JD, OP_JD, OP_J, /* [test] .DAD .DMP .DNG */ + OP_JD, OP_JD, OP_JD, OP_JD, /* .DCO .DDI .DDIR .DSB */ + OP_J, OP_J, OP_A, OP_A, /* .DIN .DDE .DIS .DDS */ + OP_JD, OP_N, OP_N, OP_N /* .DSBR --- --- --- */ + }; + +t_stat cpu_dbi (uint32 IR, uint32 intrq) +{ +OP din; +OPS op; +uint32 entry, t; +t_stat reason = SCPE_OK; + +entry = IR & 017; /* mask to entry point */ + +if (op_dbi[entry] != OP_N) { + reason = cpu_ops (op_dbi [entry], op, intrq); /* get instruction operands */ + if (reason != SCPE_OK) /* evaluation failed? */ + return reason; /* return reason for failure */ + } + +switch (entry) { /* decode IR<3:0> */ + + case 000: /* [test] 105320 (OP_N) */ + XR = 2; /* set revision */ + BR = 0377; /* side effect of microcode */ + SR = 0102077; /* set "pass" code */ + PC = (PC + 1) & VAMASK; /* return to P+1 */ + t = (AR << 16) | BR; /* set t for return */ + break; + + case 001: /* .DAD 105321 (OP_JD) */ + t = op[0].dword + op[1].dword; /* add values */ + E = E | (t < op[0].dword); /* carry if result smaller */ + O = (((~op[0].dword ^ op[1].dword) & /* overflow if sign wrong */ + (op[0].dword ^ t) & SIGN32) != 0); + break; + + case 002: /* .DMP 105322 (OP_JD) */ + { + +#if defined (HAVE_INT64) /* int64 support available */ + + t_int64 t64; + + t64 = (t_int64) INT32 (op[0].dword) * /* multiply signed values */ + (t_int64) INT32 (op[1].dword); + O = ((t64 < -(t_int64) 0x80000000) || /* overflow if out of range */ + (t64 > (t_int64) 0x7FFFFFFF)); + if (O) + t = ~SIGN32; /* if overflow, rtn max pos */ + else + t = (uint32) (t64 & DMASK32); /* else lower 32 bits of result */ + +#else /* int64 support unavailable */ + + uint32 sign, xu, yu, rh, rl; + + sign = ((int32) op[0].dword < 0) ^ /* save sign of result */ + ((int32) op[1].dword < 0); + + xu = (uint32) abs ((int32) op[0].dword); /* make operands pos */ + yu = (uint32) abs ((int32) op[1].dword); + + if ((xu & 0xFFFF0000) == 0 && /* 16 x 16 multiply? */ + (yu & 0xFFFF0000) == 0) { + t = xu * yu; /* do it */ + O = 0; /* can't overflow */ + } + + else if ((xu & 0xFFFF0000) != 0 && /* 32 x 32 multiply? */ + (yu & 0xFFFF0000) != 0) + O = 1; /* always overflows */ + + else { /* 16 x 32 or 32 x 16 */ + rl = (xu & 0xFFFF) * (yu & 0xFFFF); /* form 1st partial product */ + + if ((xu & 0xFFFF0000) == 0) + rh = xu * (yu >> 16) + (rl >> 16); /* 16 x 32 2nd partial */ + else + rh = (xu >> 16) * yu + (rl >> 16); /* 32 x 16 2nd partial */ + + O = (rh > 0x7FFF + sign); /* check for out of range */ + if (O == 0) + t = (rh << 16) | (rl & 0xFFFF); /* combine partials */ + } + + if (O) /* if overflow occurred */ + t = ~SIGN32; /* then return the largest positive number */ + else if (sign) /* otherwise if the result is negative */ + t = ~t + 1; /* then return the twos complement (set if O = 0 above) */ + +#endif /* end of int64 support */ + + } + break; + + case 003: /* .DNG 105323 (OP_J) */ + t = ~op[0].dword + 1; /* negate value */ + O = (op[0].dword == SIGN32); /* overflow if max neg */ + if (op[0].dword == 0) /* borrow if result zero */ + E = 1; + break; + + case 004: /* .DCO 105324 (OP_JD) */ + t = op[0].dword; /* copy for later store */ + if ((int32) op[0].dword < (int32) op[1].dword) + PC = (PC + 1) & VAMASK; /* < rtns to P+2 */ + else if ((int32) op[0].dword > (int32) op[1].dword) + PC = (PC + 2) & VAMASK; /* > rtns to P+3 */ + break; /* = rtns to P+1 */ + + case 005: /* .DDI 105325 (OP_JD) */ + DDI: + O = ((op[1].dword == 0) || /* overflow if div 0 */ + ((op[0].dword == SIGN32) && /* or max neg div -1 */ + ((int32) op[1].dword == -1))); + if (O) + t = ~SIGN32; /* rtn max pos for ovf */ + else + t = (uint32) (INT32 (op[0].dword) / /* else return quotient */ + INT32 (op[1].dword)); + break; + + case 006: /* .DDIR 105326 (OP_JD) */ + t = op[0].dword; /* swap operands */ + op[0].dword = op[1].dword; + op[1].dword = t; + goto DDI; /* continue at .DDI */ + + case 007: /* .DSB 105327 (OP_JD) */ + DSB: + t = op[0].dword - op[1].dword; /* subtract values */ + E = E | (op[0].dword < op[1].dword); /* borrow if minu < subtr */ + O = (((op[0].dword ^ op[1].dword) & /* overflow if sign wrong */ + (op[0].dword ^ t) & SIGN32) != 0); + break; + + case 010: /* .DIN 105330 (OP_J) */ + t = op[0].dword + 1; /* increment value */ + O = (t == SIGN32); /* overflow if sign flipped */ + if (t == 0) + E = 1; /* carry if result zero */ + break; + + case 011: /* .DDE 105331 (OP_J) */ + t = op[0].dword - 1; /* decrement value */ + O = (t == ~SIGN32); /* overflow if sign flipped */ + if ((int32) t == -1) + E = 1; /* borrow if result -1 */ + break; + + case 012: /* .DIS 105332 (OP_A) */ + din = ReadOp (op[0].word, in_d); /* get value */ + t = din.dword = din.dword + 1; /* increment value */ + WriteOp (op[0].word, din, in_d); /* store it back */ + if (t == 0) + PC = (PC + 1) & VAMASK; /* skip if result zero */ + break; + + case 013: /* .DDS 105333 (OP_A) */ + din = ReadOp (op[0].word, in_d); /* get value */ + t = din.dword = din.dword - 1; /* decrement value */ + WriteOp (op[0].word, din, in_d); /* write it back */ + if (t == 0) + PC = (PC + 1) & VAMASK; /* skip if result zero */ + break; + + case 014: /* .DSBR 105334 (OP_JD) */ + t = op[0].dword; /* swap operands */ + op[0].dword = op[1].dword; + op[1].dword = t; + goto DSB; /* continue at .DSB */ + + default: /* others undefined */ + t = (AR << 16) | BR; /* set t for NOP */ + reason = stop_inst; + } + +if (reason == SCPE_OK) { /* if return OK */ + AR = (t >> 16) & DMASK; /* break result */ + BR = t & DMASK; /* into A and B */ + } + +return reason; +} diff --git a/HP2100/hp2100_cpu4.c b/HP2100/hp2100_cpu4.c index 3da7a9d3..0d4502b5 100644 --- a/HP2100/hp2100_cpu4.c +++ b/HP2100/hp2100_cpu4.c @@ -1,1120 +1,1128 @@ -/* hp2100_cpu4.c: HP 1000 FPP/SIS - - Copyright (c) 2006-2012, J. David Bryan - - 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 - THE AUTHOR 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 the author shall not be - used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from the author. - - CPU4 Floating Point Processor and Scientific Instruction Set - - 06-Feb-12 JDB Added OPSIZE casts to fp_accum calls in .FPWR/.TPWR - 11-Sep-08 JDB Moved microcode function prototypes to hp2100_cpu1.h - 05-Sep-08 JDB Removed option-present tests (now in UIG dispatchers) - 18-Mar-08 JDB Fixed B register return bug in /CMRT - 01-Dec-06 JDB Substitutes FPP for firmware FP if HAVE_INT64 - - Primary references: - - HP 1000 M/E/F-Series Computers Technical Reference Handbook - (5955-0282, Mar-1980) - - HP 1000 M/E/F-Series Computers Engineering and Reference Documentation - (92851-90001, Mar-1981) - - Macro/1000 Reference Manual (92059-90001, Dec-1992) - - Additional references are listed with the associated firmware - implementations, as are the HP option model numbers pertaining to the - applicable CPUs. -*/ - -#include "hp2100_defs.h" -#include "hp2100_cpu.h" -#include "hp2100_cpu1.h" - -#if defined (HAVE_INT64) /* int64 support available */ - -#include "hp2100_fp1.h" - - -/* Floating-Point Processor. - - The 1000 F-Series replaces the six 2100/1000-M/E single-precision firmware - floating-point instructions with a hardware floating-point processor (FPP). - The FPP executes single-, extended-, and double-precision floating-point - instructions, as well as double-integer instructions. All of the - floating-point instructions, as well as the single- and double-integer fix - and float instructions, are handled here. Pure double-integer instructions - are dispatched to the double-integer handler for simulation. - - Option implementation by CPU was as follows: - - 2114 2115 2116 2100 1000-M 1000-E 1000-F - ------ ------ ------ ------ ------ ------ ------ - N/A N/A N/A N/A N/A N/A std - - For the F-Series, the instruction codes are mapped to routines as follows: - - Instr. 1000-F Description - ------ ------ ------------------------------------- - 105000 FAD Single real add - 105001 .XADD Extended real add - 105002 .TADD Double real add - 105003 [EAD] [5-word add] - 105004 [tst] [Floating Point Processor self test] - 105005 [xpd] [Expand exponent] - 105006 [rst] [Floating Point Processor reset] - 105007 [stk] [Process stack of operands] - 105010 [chk] [FPP addressing check] - 105014 .DAD Double integer add - 105020 FSB Single real subtract - 105021 .XSUB Extended real subtract - 105022 .TSUB Double real subtract - 105023 [ESB] [5-word subtract] - 105034 .DSB Double integer subtract - 105040 FMP Single real multiply - 105041 .XMPY Extended real multiply - 105042 .TMPY Double real multiply - 105043 [EMP] [5-word multiply] - 105054 .DMP Double integer multiply - 105060 FDV Single real divide - 105061 .XDIV Extended real divide - 105062 .TDIV Double real divide - 105063 [EDV] [5-word divide] - 105074 .DDI Double integer divide - 105100 FIX Single real to integer fix - 105101 .XFXS Extended real to integer fix (.DINT) - 105102 .TXFS Double real to integer fix (.TINT) - 105103 [EFS] [5-word FIXS] - 105104 .FIXD Real to double integer fix - 105105 .XFXD Extended real to double integer fix - 105106 .TFXD Double real to double integer fix - 105107 [EFD] [5-word FIXD] - 105114 .DSBR Double integer subtraction (reversed) - 105120 FLT Integer to single real float - 105121 .XFTS Integer to extended real float (.IDBL) - 105122 .TFTS Integer to double real float (.ITBL) - 105123 [ELS] [5-word FLTS] - 105124 .FLTD Double integer to real float - 105125 .XFTD Double integer to extended real float - 105126 .TFTD Double integer to double real float - 105127 [ELD] [5-word FLTD] - 105134 .DDIR Double integer divide (reversed) - - Implementation note: rather than have two simulators that each executes the - single-precision FP instruction set, we compile conditionally, based on the - availability of 64-bit integer support in the host compiler. 64-bit integers - are required for the FPP, so if they are available, then we handle the - single-precision instructions for the 2100 and M/E-Series here, and the - firmware simulation is omitted. If support is unavailable, then the firmware - function is used instead. - - Notes: - - 1. Single-precision arithmetic instructions (.FAD, etc.) and extended- and - double-precision F-Series FPP arithmetic instructions (.XADD, .TADD, - etc.) return positive infinity on both positive and negative overflow. - The equivalent extended-precision M/E-Series FFP instructions return - negative infinity on negative overflow and positive infinity on positive - overflow. - - 2. The items in brackets above are undocumented instructions that are used - by the 12740 FPP-SIS-FFP diagnostic only. - - 3. The five-word arithmetic instructions (e.g., 105003) use an expanded - operand format that dedicates a separate word to the exponent. See the - implementation notes in the hardware floating-point processor simulation - for details. - - 4. The "self test" instruction (105004) returned to P+1 for early F-Series - units without double-integer support. Units incorporating such support - returned to P+2. - - 5. The "expand exponent" instruction (105005) is used as a "prefix" - instruction to enable a 10-bit exponent range. It is placed immediately - before a 5-word arithmetic instruction sequence, e.g., immediately - preceding an EAD instruction sequence. The arithmetic instruction - executes normally, except that under/overflow is not indicated unless - the exponent exceeds the 10-bit range, instead of the normal 8-bit - range. If overflow is indicated, the exponent is still set to +128. - - Note that as 2-, 3-, and 4-word packed numbers only have room for 8-bit - exponents, the Expand Exponent instruction serves no useful purpose in - conjunction with instructions associated with these precisions. If - used, the resulting values may be in error, as overflow from the 8-bit - exponents will not be indicated. - - 6. The "FPP reset" instruction (105006) is provided to reset a hung box, - e.g., in cases where an improper number of parameters is supplied. The - hardware resets its internal state machine in response to this - instruction. Under simulation, the instruction has no effect, as the - simulated FPP cannot hang. - - 7. The "process stack" instruction (105007) executes a series of FPP - instruction sets in sequence. Each set consists of a single FPP - instruction and associated operands that specifies the operation, - followed by a "result" instruction and operand. The result instruction - is optional and is only used to specify the result precision; the - instruction itself is not executed. If the result instruction is NOP, - then the result precision is that of the executed FPP instruction. If - the result operand is null, then the result is kept in the internal FPP - accumulator for later use. - - The calling sequence is as follows: - - STK Process stack instruction - DEF ERRTN Address of error return - DEF SET1 Address of first instruction set - DEF SET2 Address of second instruction set - . - . - . - ERRTN EQU * Return here if execution in error - OKRTN EQU * Return here if execution OK - - Instruction sets are specified as follows (e.g.): - - SET1 .TADD Operation instruction (NOP to terminate series) - DEC 4 Number of words in first operand (or 0 if accum) - DEF OP1 Address of first operand - DEC 4 Number of words in second operand (or 0 if accum) - DEF OP2 Address of second operand - .XADD Result precision conversion instruction (or NOP) - DEC 3 Number of words to store (or 0 if no store) - DEF RSLT Address of buffer to hold value - - The primary use of the "process stack" instruction is to enable chained - operations employing the FPP accumulator for intermediate results and to - enable expanded exponent usage across multiple instructions. - - 8. The "addressing check" instruction sets bit 0 of the L register to 1, - copies the X register value to the FPP, and then reads the FPP and - stores the result in the Y register. Setting the L register bit 0 to 1 - normally deselects the FPP, so that the value in Y is 177777. However, - the FPP box has a strap that inverts the selection logic, even though - the box will not work with the base-set firmware if this is done. The - "addressing check" instruction is provided to test whether the strap is - in the alternate location. Under simulation, the return value is always - 177777, indicating that the strap is correctly set. - - Additional references: - - DOS/RTE Relocatable Library Reference Manual (24998-90001, Oct-1981) - - FPP-SIS-FFP Diagnostic Source (12740-18001, Rev. 1926) -*/ - -static const OP_PAT op_fpp[96] = { - OP_RF, OP_AXX, OP_ATT, OP_AEE, /* FAD .XADD .TADD .EADD */ - OP_N, OP_C, OP_N, OP_A, /* [tst] [xpd] [rst] [stk] */ - OP_N, OP_N, OP_N, OP_N, /* [chk] --- --- --- */ - OP_N, OP_N, OP_N, OP_N, /* .DAD --- --- --- */ - OP_RF, OP_AXX, OP_ATT, OP_AEE, /* FSB .XSUB .TSUB .ESUB */ - OP_N, OP_N, OP_N, OP_N, /* --- --- --- --- */ - OP_N, OP_N, OP_N, OP_N, /* --- --- --- --- */ - OP_N, OP_N, OP_N, OP_N, /* .DSB --- --- --- */ - OP_RF, OP_AXX, OP_ATT, OP_AEE, /* FMP .XMPY .TMPY .EMPY */ - OP_N, OP_N, OP_N, OP_N, /* --- --- --- --- */ - OP_N, OP_N, OP_N, OP_N, /* --- --- --- --- */ - OP_N, OP_N, OP_N, OP_N, /* .DMP --- --- --- */ - OP_RF, OP_AXX, OP_ATT, OP_AEE, /* FDV .XDIV .TDIV .EDIV */ - OP_N, OP_N, OP_N, OP_N, /* --- --- --- --- */ - OP_N, OP_N, OP_N, OP_N, /* --- --- --- --- */ - OP_N, OP_N, OP_N, OP_N, /* .DDI --- --- --- */ - OP_R, OP_X, OP_T, OP_E, /* FIX .XFXS .TFXS .EFXS */ - OP_R, OP_X, OP_T, OP_E, /* .FIXD .XFXD .TFXD .EFXD */ - OP_N, OP_N, OP_N, OP_N, /* --- --- --- --- */ - OP_N, OP_N, OP_N, OP_N, /* .DSBR --- --- --- */ - OP_I, OP_IA, OP_IA, OP_IA, /* FLT .XFTS .TFTS .EFTS */ - OP_J, OP_JA, OP_JA, OP_JA, /* .FLTD .XFTD .TFTD .EFTD */ - OP_N, OP_N, OP_N, OP_N, /* --- --- --- --- */ - OP_N, OP_N, OP_N, OP_N /* .DDIR --- --- --- */ - }; - -t_stat cpu_fpp (uint32 IR, uint32 intrq) -{ -OP fpop; -OPS op; -OPSIZE op1_prec, op2_prec, rslt_prec, cvt_prec; -uint16 opcode, rtn_addr, stk_ptr; -uint32 entry; -t_stat reason = SCPE_OK; - -if (UNIT_CPU_MODEL == UNIT_1000_F) /* F-Series? */ - opcode = (uint16) (IR & 0377); /* yes, use full opcode */ -else - opcode = (uint16) (IR & 0160); /* no, use 6 SP FP opcodes */ - -entry = opcode & 0177; /* map to <6:0> */ - -if (op_fpp[entry] != OP_N) - if (reason = cpu_ops (op_fpp[entry], op, intrq)) /* get instruction operands */ - return reason; - -switch (entry) { /* decode IR<6:0> */ - case 0000: /* FAD 105000 (OP_RF) */ - case 0020: /* FSB 105020 (OP_RF) */ - case 0040: /* FMP 105040 (OP_RF) */ - case 0060: /* FDV 105060 (OP_RF) */ - O = fp_exec (opcode, &fpop, op[0], op[1]); /* execute operation */ - AR = fpop.fpk[0]; /* return result to A/B */ - BR = fpop.fpk[1]; - break; - - case 0001: /* .XADD 105001 (OP_AXX) */ - case 0002: /* .TADD 105002 (OP_ATT) */ - case 0003: /* .EADD 105003 (OP_AEE) */ - - case 0021: /* .XSUB 105021 (OP_AXX) */ - case 0022: /* .TSUB 105022 (OP_ATT) */ - case 0023: /* .ESUB 105023 (OP_AEE) */ - - case 0041: /* .XMPY 105041 (OP_AXX) */ - case 0042: /* .TMPY 105042 (OP_ATT) */ - case 0043: /* .EMPY 105043 (OP_AEE) */ - - case 0061: /* .XDIV 105061 (OP_AXX) */ - case 0062: /* .TDIV 105062 (OP_ATT) */ - case 0063: /* .EDIV 105063 (OP_AEE) */ - O = fp_exec (opcode, &fpop, op[1], op[2]); /* execute operation */ - fp_prec (opcode, NULL, NULL, &rslt_prec); /* determine result precision */ - WriteOp (op[0].word, fpop, rslt_prec); /* write result */ - break; - - case 0004: /* [tst] 105004 (OP_N) */ - XR = 3; /* firmware revision */ - SR = 0102077; /* test passed code */ - PC = (PC + 1) & VAMASK; /* P+2 return for firmware w/DBI */ - break; - - case 0005: /* [xpd] 105005 (OP_C) */ - return cpu_fpp (op[0].word | 0200, intrq); /* set bit 7, execute instr */ - - case 0006: /* [rst] 105006 (OP_N) */ - break; /* do nothing for FPP reset */ - - case 0007: /* [stk] 105007 (OP_A) */ - O = 0; /* clear overflow */ - stk_ptr = PC; /* save ptr to next buf */ - rtn_addr = op[0].word; /* save return address */ - - while (TRUE) { - PC = ReadW (stk_ptr) & VAMASK; /* point at next instruction set */ - stk_ptr = (stk_ptr + 1) & VAMASK; - - reason = cpu_ops (OP_CCACACCA, op, intrq); /* get instruction set */ - - if (reason) { - PC = err_PC; /* irq restarts */ - break; - } - - if (op[0].word == 0) { /* opcode = NOP? */ - PC = (rtn_addr + 1) & VAMASK; /* bump to good return */ - break; /* done */ - } - - fp_prec ((uint16) (op[0].word & 0377), /* determine operand precisions */ - &op1_prec, &op2_prec, &rslt_prec); - - if (TO_COUNT(op1_prec) != op[1].word) { /* first operand precisions agree? */ - PC = rtn_addr; /* no, so take error return */ - break; - } - - else if (op1_prec != fp_a) /* operand in accumulator? */ - op[1] = ReadOp (op[2].word, op1_prec); /* no, so get operand 1 */ - - if (TO_COUNT(op2_prec) != op[3].word) { /* second operand precisions agree? */ - PC = rtn_addr; /* no, so take error return */ - break; - } - - else if (op2_prec != fp_a) /* operand in accumulator? */ - op[2] = ReadOp (op[4].word, op2_prec); /* no, so get operand 2 */ - - O = O | /* execute instruction */ - fp_exec ((uint16) (op[0].word & 0377), /* and accumulate overflow */ - &fpop, op[1], op[2]); - - if (op[5].word) { /* precision conversion? */ - fp_prec ((uint16) (op[5].word & 0377), /* determine conversion precision */ - NULL, NULL, &cvt_prec); - - fpop = fp_accum (NULL, cvt_prec); /* convert result */ - } - else /* no conversion specified */ - cvt_prec = rslt_prec; /* so use original precision */ - - if (op[6].word) /* store result? */ - WriteOp (op[7].word, fpop, cvt_prec); /* yes, so write it */ - } - - break; - - case 0010: /* [chk] 105010 (OP_N) */ - YR = 0177777; /* -1 if selection strap OK */ - break; - - case 0014: /* .DAD 105014 (OP_N) */ - return cpu_dbi (0105321, intrq); /* remap to double int handler */ - - case 0034: /* .DSB 105034 (OP_N) */ - return cpu_dbi (0105327, intrq); /* remap to double int handler */ - - case 0054: /* .DMP 105054 (OP_N) */ - return cpu_dbi (0105322, intrq); /* remap to double int handler */ - - case 0074: /* .DDI 105074 (OP_N) */ - return cpu_dbi (0105325, intrq); /* remap to double int handler */ - - case 0100: /* FIX 105100 (OP_R) */ - case 0101: /* .XFXS 105101 (OP_X) */ - case 0102: /* .TFXS 105102 (OP_T) */ - case 0103: /* .EFXS 105103 (OP_E) */ - O = fp_exec (opcode, &fpop, op[0], NOP); /* fix to integer */ - AR = fpop.fpk[0]; /* save result */ - break; - - case 0104: /* .FIXD 105104 (OP_R) */ - case 0105: /* .XFXD 105105 (OP_X) */ - case 0106: /* .TFXD 105106 (OP_T) */ - case 0107: /* .EFXD 105107 (OP_E) */ - O = fp_exec (opcode, &fpop, op[0], NOP); /* fix to integer */ - AR = (fpop.dword >> 16) & DMASK; /* save result */ - BR = fpop.dword & DMASK; /* in A and B */ - break; - - case 0114: /* .DSBR 105114 (OP_N) */ - return cpu_dbi (0105334, intrq); /* remap to double int handler */ - - case 0120: /* FLT 105120 (OP_I) */ - case 0124: /* .FLTD 105124 (OP_J) */ - O = fp_exec (opcode, &fpop, op[0], NOP); /* float to single */ - AR = fpop.fpk[0]; /* save result */ - BR = fpop.fpk[1]; /* into A/B */ - break; - - case 0121: /* .XFTS 105121 (OP_IA) */ - case 0122: /* .TFTS 105122 (OP_IA) */ - case 0123: /* .EFTS 105123 (OP_IA) */ - case 0125: /* .XFTD 105125 (OP_JA) */ - case 0126: /* .TFTD 105126 (OP_JA) */ - case 0127: /* .EFTD 105127 (OP_JA) */ - O = fp_exec (opcode, &fpop, op[0], NOP); /* float integer */ - fp_prec (opcode, NULL, NULL, &rslt_prec); /* determine result precision */ - WriteOp (op[1].word, fpop, rslt_prec); /* write result */ - break; - - case 0134: /* .DDIR 105134 (OP_N) */ - return cpu_dbi (0105326, intrq); /* remap to double int handler */ - - default: /* others undefined */ - reason = stop_inst; - } - -return reason; -} - - -/* Scientific Instruction Set. - - The SIS adds single-precision trigonometric and logarithmic, and - double-precision polynomial evaluation instructions to the 1000-F instruction - set. The SIS is standard on the 1000-F. - - Option implementation by CPU was as follows: - - 2114 2115 2116 2100 1000-M 1000-E 1000-F - ------ ------ ------ ------ ------ ------ ------ - N/A N/A N/A N/A N/A N/A std - - The routines are mapped to instruction codes as follows: - - Instr. 1000-F Description - ------ ------ ---------------------------------------------- - TAN 105320 Tangent - SQRT 105321 Square root - ALOG 105322 Natural logarithm - ATAN 105323 Arc tangent - COS 105324 Cosine - SIN 105325 Sine - EXP 105326 E to the power X - ALOGT 105327 Common logarithm - TANH 105330 Hyperbolic tangent - DPOLY 105331 Double-precision polynomial evaluation - /CMRT 105332 Double-precision common range reduction - /ATLG 105333 Compute (1-x)/(1+x) for .ATAN and .LOG - .FPWR 105334 Single-precision exponentiation - .TPWR 105335 Double-precision exponentiation - [tst] 105337 [self test] - - The SIS simulation follows the F-Series SIS microcode, which, in turn, - follows the algebraic approximations given in the Relocatable Library manual - descriptions of the equivalent software routines. - - Notes: - - 1. The word following the DPOLY instruction contains up to three flag bits - to indicate one of several polynomial forms to evaluate. The comments - in the DPOLY software library routine source interchange the actions of - the bit 14 and bit 0 flags. The DPOLY description in the Technical - Reference Handbook is correct. - - 2. Several instructions (e.g., DPOLY) are documented as leaving undefined - values in the A, B, X, Y, E, or O registers. Simulation does not - attempt to reproduce the same values as would be obtained with the - hardware. - - 3. The SIS uses the hardware FPP of the F-Series. FPP malfunctions are - detected by the SIS firmware and are indicated by a memory-protect - violation and setting the overflow flag. Under simulation, - malfunctions cannot occur. - - 4. We use OP_IIT for the .FPWR operand pattern. The "II" is redundant, but - it aligns the operands with the OP_IAT of .TPWR, so the code may be - shared. - - Additional references: - - DOS/RTE Relocatable Library Reference Manual (24998-90001, Oct-1981) - - HP 1000 E-Series and F-Series Computer Microprogramming Reference Manual - (02109-90004, Apr-1980). -*/ - - -/* Common single-precision range reduction for SIN, COS, TAN, and EXP. - - This routine is called by the SIN, COS, TAN, and EXP handlers to reduce the - range of the argument. Reduction is performed in extended-precision. We - calculate: - - multiple = (nearest even integer to argument * multiplier) - argument = argument * multiplier - multiple -*/ - -static uint32 reduce (OP *argument, int32 *multiple, OP multiplier) -{ -OP product, count; -uint32 overflow; - -fp_cvt (argument, fp_f, fp_x); /* convert to extended precision */ -fp_exec (0041, &product, *argument, multiplier); /* product = argument * multiplier */ -overflow = fp_exec (0111, &count, NOP, NOP); /* count = FIX (acc) */ - -if ((int16) count.word >= 0) /* nearest even integer */ - count.word = count.word + 1; -count.word = count.word & ~1; -*multiple = (int16) count.word; - -if (overflow == 0) { /* in range? */ - fp_exec (0121, ACCUM, count, NOP); /* acc = FLT (count) */ - overflow = fp_exec (0025, ACCUM, product, NOP); /* acc = product - acc */ - *argument = fp_accum (NULL, fp_f); /* trim to single-precision */ - } -return overflow; -} - - -/* SIS dispatcher. */ - -static const OP_PAT op_sis[16] = { - OP_R, OP_R, OP_R, OP_R, /* TAN SQRT ALOG ATAN */ - OP_R, OP_R, OP_R, OP_R, /* COS SIN EXP ALOGT */ - OP_R, OP_CATAKK, OP_AAT, OP_A, /* TANH DPOLY /CMRT /ATLG */ - OP_IIF, OP_IAT, OP_N, OP_N /* .FPWR .TPWR --- [tst] */ - }; - -t_stat cpu_sis (uint32 IR, uint32 intrq) -{ -OPS op; -OP arg, coeff, pwr, product, count, result; -int16 f, p; -int32 multiple, power, exponent, rsltexp; -uint32 entry, i; -t_bool flag, sign; -t_stat reason = SCPE_OK; - -static const OP tan_c4 = { { 0137763, 0051006 } }; /* DEC -4.0030956 */ -static const OP tan_c3 = { { 0130007, 0051026 } }; /* DEC -1279.5424 */ -static const OP tan_c2 = { { 0040564, 0012761 } }; /* DEC 0.0019974806 */ -static const OP tan_c1 = { { 0045472, 0001375 } }; /* DEC 0.14692695 */ - -static const OP alog_c3 = { { 0065010, 0063002 } }; /* DEC 1.6567626301 */ -static const OP alog_c2 = { { 0125606, 0044404 } }; /* DEC -2.6398577035 */ -static const OP alog_c1 = { { 0051260, 0037402 } }; /* DEC 1.2920070987 */ - -static const OP atan_c4 = { { 0040257, 0154404 } }; /* DEC 2.0214656 */ -static const OP atan_c3 = { { 0132062, 0133406 } }; /* DEC -4.7376165 */ -static const OP atan_c2 = { { 0047407, 0173775 } }; /* DEC 0.154357652 */ -static const OP atan_c1 = { { 0053447, 0014002 } }; /* DEC 1.3617611 */ - -static const OP sin_c4 = { { 0132233, 0040745 } }; /* DEC -0.000035950439 */ -static const OP sin_c3 = { { 0050627, 0122361 } }; /* DEC 0.002490001 */ -static const OP sin_c2 = { { 0126521, 0011373 } }; /* DEC -0.0807454325 */ -static const OP sin_c1 = { { 0062207, 0166400 } }; /* DEC 0.78539816 */ - -static const OP cos_c4 = { { 0126072, 0002753 } }; /* DEC -0.00031957 */ -static const OP cos_c3 = { { 0040355, 0007767 } }; /* DEC 0.015851077 */ -static const OP cos_c2 = { { 0130413, 0011377 } }; /* DEC -0.30842483 */ -static const OP cos_c1 = { { 0040000, 0000002 } }; /* DEC 1.0 */ - -static const OP sqrt_a2 = { { 0045612, 0067400 } }; /* DEC 0.5901621 */ -static const OP sqrt_b2 = { { 0065324, 0126377 } }; /* DEC 0.4173076 */ -static const OP sqrt_a1 = { { 0065324, 0126400 } }; /* DEC 0.8346152 */ -static const OP sqrt_b1 = { { 0045612, 0067400 } }; /* DEC 0.5901621 */ - -static const OP exp_c2 = { { 0073000, 0070771 } }; /* DEC 0.05761803 */ -static const OP exp_c1 = { { 0056125, 0041406 } }; /* DEC 5.7708162 */ - -static const OP tanh_c3 = { { 0050045, 0022004 } }; /* DEC 2.5045337 */ -static const OP tanh_c2 = { { 0041347, 0101404 } }; /* DEC 2.0907609 */ -static const OP tanh_c1 = { { 0052226, 0047375 } }; /* DEC 0.16520923 */ - -static const OP minus_1 = { { 0100000, 0000000 } }; /* DEC -1.0 */ -static const OP plus_1 = { { 0040000, 0000002 } }; /* DEC +1.0 */ -static const OP plus_half = { { 0040000, 0000000 } }; /* DEC +0.5 */ -static const OP ln_2 = { { 0054271, 0006000 } }; /* DEC 0.6931471806 (ln 2.0) */ -static const OP log_e = { { 0067455, 0166377 } }; /* DEC 0.43429228 (log e) */ -static const OP pi_over_4 = { { 0062207, 0166400 } }; /* Pi / 4.0 */ -static const OP pi_over_2 = { { 0062207, 0166402 } }; /* Pi / 2.0 */ - -static const OP four_over_pi = { { 0050574, 0140667, 0023402 } }; /* 4.0 / Pi */ -static const OP two_over_ln2 = { { 0056125, 0016624, 0127404 } }; /* 2.0 / ln(2.0) */ - -static const OP t_one = { { 0040000, 0000000, 0000000, 0000002 } }; /* DEY 1.0 */ - - -entry = IR & 017; /* mask to entry point */ - -if (op_sis[entry] != OP_N) - if (reason = cpu_ops (op_sis[entry], op, intrq)) /* get instruction operands */ - return reason; - -switch (entry) { /* decode IR<3:0> */ - - case 000: /* TAN 105320 (OP_R) */ - O = reduce (&op[0], &multiple, four_over_pi); /* reduce range */ - - if (O) { /* out of range? */ - op[0].fpk[0] = '0' << 8 | '9'; /* return '09' */ - op[0].fpk[1] = 'O' << 8 | 'R'; /* return 'OR' */ - break; /* error return is P+1 */ - } - - fp_exec (0040, &op[1], op[0], op[0]); /* op1 = arg ^ 2 */ - fp_exec (0010, ACCUM, NOP, tan_c4); /* acc = acc + C4 */ - fp_exec (0064, ACCUM, tan_c3, NOP); /* acc = C3 / acc */ - fp_exec (0010, ACCUM, NOP, op[1]); /* acc = acc + op1 */ - fp_exec (0050, ACCUM, NOP, tan_c2); /* acc = acc * C2 */ - fp_exec (0010, ACCUM, NOP, tan_c1); /* acc = acc + C1 */ - fp_exec (0050, &op[0], NOP, op[0]); /* res = acc * arg */ - - if (multiple & 0002) /* multiple * 2 odd? */ - fp_exec (0064, &op[0], minus_1, NOP); /* res = -1.0 / acc */ - - PC = (PC + 1) & VAMASK; /* normal return is P+2 */ - break; - - - case 001: /* SQRT 105321 (OP_R) */ - O = 0; /* clear overflow */ - - if (op[0].fpk[0] == 0) { /* arg = 0? */ - PC = (PC + 1) & VAMASK; /* normal return is P+2 */ - break; - } - - else if ((int16) op[0].fpk[0] < 0) { /* sqrt of neg? */ - op[0].fpk[0] = '0' << 8 | '3'; /* return '03' */ - op[0].fpk[1] = 'U' << 8 | 'N'; /* return 'UN' */ - O = 1; /* set overflow */ - break; /* error return is P+1 */ - } - - fp_unpack (&op[1], &exponent, op[0], fp_f); /* unpack argument */ - - if (exponent & 1) { /* exponent odd? */ - fp_exec (0040, ACCUM, op[1], sqrt_a1); /* acc = op1 * A1 */ - fp_exec (0010, &op[2], NOP, sqrt_b1); /* op2 = acc + B1 */ - op[1].fpk[1] = op[1].fpk[1] + 2; /* op1 = op1 * 2.0 */ - } - else { /* exponent even */ - fp_exec (0040, ACCUM, op[1], sqrt_a2); /* acc = op1 * A2 */ - fp_exec (0010, &op[2], NOP, sqrt_b2); /* op2 = acc + B2 */ - } - - fp_exec (0064, ACCUM, op[1], NOP); /* acc = op1 / acc */ - fp_exec (0010, &op[2], NOP, op[2]); /* op2 = acc + op2 */ - - op[1].fpk[1] = op[1].fpk[1] + 4; /* op1 = op1 * 4.0 */ - - fp_exec (0064, ACCUM, op[1], NOP); /* acc = op1 / acc */ - fp_exec (0010, &op[0], NOP, op[2]); /* res = acc + op2 */ - - power = (exponent >> 1) - 2; - - if (op[0].fpk[0]) { /* calc x * 2**n */ - fp_unpack (&op[1], &exponent, op[0], fp_f); /* unpack argument */ - exponent = exponent + power; /* multiply by 2**n */ - - if ((exponent > 0177) || /* exponent overflow? */ - (exponent < -0200)) { /* or underflow? */ - O = 1; /* rtn unscaled val, set ovf */ - break; /* error return is P+1 */ - } - - else - fp_pack (&op[0], op[1], exponent, fp_f);/* repack result */ - } - - PC = (PC + 1) & VAMASK; /* normal return is P+2 */ - break; - - - case 002: /* ALOG 105322 (OP_R) */ - case 007: /* ALOGT 105327 (OP_R) */ - O = 0; /* clear overflow */ - - if ((int16) op[0].fpk[0] <= 0) { /* log of neg or zero? */ - op[0].fpk[0] = '0' << 8 | '2'; /* return '02' */ - op[0].fpk[1] = 'U' << 8 | 'N'; /* return 'UN' */ - O = 1; /* set overflow */ - break; /* error return is P+1 */ - } - - fp_unpack (&op[1], &exponent, op[0], fp_f); /* unpack argument */ - - if (op[0].fpk[0] < 0055000) { /* out of range? */ - exponent = exponent - 1; /* drop exponent */ - op[1].fpk[1] = op[1].fpk[1] | 2; /* set "exponent" to 1 */ - } - - op[2].fpk[0] = exponent; - fp_exec (0120, &op[3], op[2], NOP); /* op3 = FLT(exponent) */ - - fp_exec (0020, &op[4], op[1], plus_1); /* op4 = op1 - 1.0 */ - fp_exec (0000, ACCUM, op[1], plus_1); /* acc = op1 + 1.0 */ - fp_exec (0064, &op[5], op[4], NOP); /* op5 = op4 / acc */ - - fp_exec (0054, ACCUM, NOP, NOP); /* acc = acc * acc */ - fp_exec (0030, ACCUM, NOP, alog_c3); /* acc = acc - c3 */ - fp_exec (0064, ACCUM, alog_c2, NOP); /* acc = c2 / acc */ - fp_exec (0010, ACCUM, NOP, alog_c1); /* acc = acc + c1 */ - fp_exec (0050, ACCUM, NOP, op[5]); /* acc = acc * op5 */ - fp_exec (0010, ACCUM, NOP, op[3]); /* acc = acc + op3 */ - fp_exec (0050, &op[0], NOP, ln_2); /* res = acc * ln2 */ - - if (entry == 007) /* ALOGT? */ - fp_exec (0050, &op[0], NOP, log_e); /* res = acc * log(e) */ - - PC = (PC + 1) & VAMASK; /* normal return is P+2 */ - break; - - - case 003: /* ATAN 105323 (OP_R) */ - O = 0; /* clear overflow */ - - if (op[0].fpk[0] == 0) /* argument zero? */ - break; /* result zero */ - - flag = (op[0].fpk[1] & 1); /* get exponent sign */ - sign = ((int16) op[0].fpk[0] < 0); /* get argument sign */ - - if (flag == 0) { /* exp pos? (abs >= 0.5)? */ - if (sign) /* argument negative? */ - fp_pcom (&op[0], fp_f); /* make positive */ - - if (op[0].fpk[1] & 0374) { /* arg >= 2? */ - fp_exec(0060, &op[0], plus_1, op[0]); /* arg = 1.0 / arg */ - op[2] = pi_over_2; /* constant = pi / 2.0 */ - } - else { - fp_exec (0020, &op[1], plus_1, op[0]); /* op1 = 1.0 - arg */ - fp_exec (0000, ACCUM, plus_1, op[0]); /* acc = 1.0 + arg */ - fp_exec (0064, &op[0], op[1], NOP); /* arg = op1 / acc */ - op[2] = pi_over_4; /* constant = pi / 4.0 */ - } - } - - fp_exec (0040, &op[1], op[0], op[0]); /* op1 = arg * arg */ - fp_exec (0010, ACCUM, NOP, atan_c4); /* acc = acc + C4 */ - fp_exec (0064, ACCUM, atan_c3, NOP); /* acc = C3 / acc */ - fp_exec (0010, ACCUM, NOP, op[1]); /* acc = acc + op1 */ - fp_exec (0050, ACCUM, NOP, atan_c2); /* acc = acc * C2 */ - fp_exec (0010, ACCUM, NOP, atan_c1); /* acc = acc + C1 */ - fp_exec (0064, &op[0], op[0], NOP); /* res = arg / acc */ - - if (flag == 0) { /* exp pos? (abs >= 0.5)? */ - fp_exec (0030, &op[0], NOP, op[2]); /* res = acc - pi / n */ - - if (sign == 0) /* argument positive? */ - fp_pcom (&op[0], fp_f); /* make negative */ - } - - break; - - - case 004: /* COS 105324 (OP_R) */ - case 005: /* SIN 105325 (OP_R) */ - O = reduce (&op[0], &multiple, four_over_pi); /* reduce range */ - - if (O) { /* out of range? */ - op[0].fpk[0] = '0' << 8 | '5'; /* return '05' */ - op[0].fpk[1] = 'O' << 8 | 'R'; /* return 'OR' */ - break; /* error return is P+1 */ - } - - multiple = multiple / 2 + (entry == 004); /* add one for cosine */ - flag = (multiple & 1); /* decide on series */ - - fp_exec (0040, &op[1], op[0], op[0]); /* op1 = arg ^ 2 */ - - if (flag) { - fp_exec (0050, ACCUM, NOP, cos_c4); /* acc = acc * c4 */ - fp_exec (0010, ACCUM, NOP, cos_c3); /* acc = acc + c3 */ - fp_exec (0050, ACCUM, NOP, op[1]); /* acc = acc * op1 */ - fp_exec (0010, ACCUM, NOP, cos_c2); /* acc = acc + c2 */ - fp_exec (0050, ACCUM, NOP, op[1]); /* acc = acc * op1 */ - fp_exec (0010, &op[0], NOP, cos_c1); /* res = acc + c1 */ - } - - else { - fp_exec (0050, ACCUM, NOP, sin_c4); /* acc = acc * c4 */ - fp_exec (0010, ACCUM, NOP, sin_c3); /* acc = acc + c3 */ - fp_exec (0050, ACCUM, NOP, op[1]); /* acc = acc * op1 */ - fp_exec (0010, ACCUM, NOP, sin_c2); /* acc = acc + c2 */ - fp_exec (0050, ACCUM, NOP, op[1]); /* acc = acc * op1 */ - fp_exec (0010, ACCUM, NOP, sin_c1); /* acc = acc + c1 */ - fp_exec (0050, &op[0], NOP, op[0]); /* res = acc * arg */ - } - - if (multiple & 0002) /* multiple * 2 odd? */ - fp_pcom (&op[0], fp_f); /* make negative */ - - PC = (PC + 1) & VAMASK; /* normal return is P+2 */ - break; - - - case 006: /* EXP 105326 (OP_R) */ - sign = ((int16) op[0].fpk[0] < 0); /* get argument sign */ - - O = reduce (&op[0], &multiple, two_over_ln2); /* reduce range */ - multiple = multiple / 2; /* get true multiple */ - - if ((sign == 0) && (O | (multiple > 128))) { /* pos and ovf or out of range? */ - op[0].fpk[0] = '0' << 8 | '7'; /* return '07' */ - op[0].fpk[1] = 'O' << 8 | 'F'; /* return 'OF' */ - O = 1; /* set overflow */ - break; /* error return is P+1 */ - } - - else if (sign && (multiple < -128)) { /* neg and out of range? */ - op[0].fpk[0] = 0; /* result is zero */ - op[0].fpk[1] = 0; - O = 0; /* clear for underflow */ - PC = (PC + 1) & VAMASK; /* normal return is P+2 */ - break; - } - - fp_exec (0040, ACCUM, op[0], op[0]); /* acc = arg ^ 2 */ - fp_exec (0050, ACCUM, NOP, exp_c2); /* acc = acc * c2 */ - fp_exec (0030, ACCUM, NOP, op[0]); /* acc = acc - op0 */ - fp_exec (0010, ACCUM, NOP, exp_c1); /* acc = acc + c1 */ - fp_exec (0064, ACCUM, op[0], NOP); /* acc = op0 / acc */ - fp_exec (0010, &op[0], NOP, plus_half); /* res = acc + 0.5 */ - - power = multiple + 1; - - if (op[0].fpk[0]) { /* calc x * 2**n */ - fp_unpack (&op[1], &exponent, op[0], fp_f); /* unpack argument */ - exponent = exponent + power; /* multiply by 2**n */ - - if ((exponent > 0177) || /* exponent overflow? */ - (exponent < -0200)) { /* or underflow? */ - if (sign == 0) { /* arg positive? */ - op[0].fpk[0] = '0' << 8 | '7'; /* return '07' */ - op[0].fpk[1] = 'O' << 8 | 'F'; /* return 'OF' */ - O = 1; /* set overflow */ - } - else { - op[0].fpk[0] = 0; /* result is zero */ - op[0].fpk[1] = 0; - O = 0; /* clear for underflow */ - } - break; /* error return is P+1 */ - } - - else { - fp_pack (&op[0], op[1], exponent, fp_f);/* repack value */ - O = 0; - } - } - - PC = (PC + 1) & VAMASK; /* normal return is P+2 */ - break; - - - case 010: /* TANH 105330 (OP_R) */ - O = 0; - sign = ((int16) op[0].fpk[0] < 0); /* get argument sign */ - - if (op[0].fpk[1] & 1) { /* abs (arg) < 0.5? */ - fp_exec (0040, ACCUM, op[0], op[0]); /* acc = arg ^ 2 */ - fp_exec (0010, ACCUM, NOP, tanh_c3); /* acc = acc + c3 */ - fp_exec (0064, ACCUM, tanh_c2, NOP); /* acc = c2 / acc */ - fp_exec (0010, ACCUM, NOP, tanh_c1); /* acc = acc + c1 */ - fp_exec (0050, &op[0], NOP, op[0]); /* res = acc * arg */ - } - - else if (op[0].fpk[1] & 0370) /* abs (arg) >= 8.0? */ - if (sign) /* arg negative? */ - op[0] = minus_1; /* result = -1.0 */ - else /* arg positive */ - op[0] = plus_1; /* result = +1.0 */ - - else { /* 0.5 <= abs (arg) < 8.0 */ - BR = BR + 2; /* arg = arg * 2.0 */ - cpu_sis (0105326, intrq); /* calc exp (arg) */ - PC = (PC - 1) & VAMASK; /* correct P (always good rtn) */ - - op[0].fpk[0] = AR; /* save value */ - op[0].fpk[1] = BR; - - fp_exec (0020, &op[1], op[0], plus_1); /* op1 = op0 - 1.0 */ - fp_exec (0000, ACCUM, op[0], plus_1); /* acc = op0 + 1.0 */ - fp_exec (0064, &op[0], op[1], NOP); /* res = op1 / acc */ - } - - break; - - - case 011: /* DPOLY 105331 (OP_CATAKK) */ - O = 0; /* clear overflow */ - AR = op[0].word; /* get flag word */ - - if ((int16) AR >= 0) { /* flags present? */ - AR = 1; /* no, so set default */ - arg = op[2]; /* arg = X */ - } - - else /* bit 15 set */ - fp_exec (0042, &arg, op[2], op[2]); /* arg = X ^ 2 */ - - coeff = ReadOp (op[3].word, fp_t); /* get first coefficient */ - op[3].word = (op[3].word + 4) & VAMASK; /* point at next */ - fp_accum (&coeff, fp_t); /* acc = coeff */ - - for (i = 0; i < op[4].word; i++) { /* compute numerator */ - fp_exec (0052, ACCUM, NOP, arg); /* acc = P[m] * arg */ - coeff = ReadOp (op[3].word, fp_t); /* get next coefficient */ - op[3].word = (op[3].word + 4) & VAMASK; /* point at next */ - fp_exec (0012, ACCUM, NOP, coeff); /* acc = acc + P[m-1] */ - } - - if (AR & 1) /* bit 0 set? */ - op[6] = fp_accum (NULL, fp_t); /* save numerator */ - else - fp_exec (0046, &op[6], op[2], NOP); /* acc = X * acc */ - - - if (op[5].word) { /* n > 0 ? */ - fp_accum (&t_one, fp_t); /* acc = 1.0 */ - - for (i = 0; i < op[5].word; i++) { /* compute denominator */ - fp_exec (0052, ACCUM, NOP, arg); /* acc = P[m] * arg */ - coeff = ReadOp (op[3].word, fp_t); /* get next coefficient */ - op[3].word = (op[3].word + 4) & VAMASK; /* point at next */ - fp_exec (0012, ACCUM, NOP, coeff); /* acc = acc + P[m-1] */ - } - - if (AR & 0040000) /* bit 14 set? */ - fp_exec (0032, ACCUM, NOP, op[6]); /* acc = den - num */ - - fp_exec (0066, &op[6], op[6], NOP); /* op6 = num / den */ - } - - WriteOp (op[1].word, op[6], fp_t); /* write result */ - - if (O) /* overflow? */ - op[0].fpk[0] = 0; /* microcode rtns with A = 0 */ - break; - - - case 012: /* /CMRT 105332 (OP_AAT) */ - O = 0; - f = (int16) AR; /* save flags */ - - coeff = ReadOp (op[1].word, fp_t); /* get coefficient (C) */ - - fp_unpack (NULL, &exponent, op[2], fp_t); /* unpack exponent */ - - if ((f == -1) || (exponent < 4)) { /* TANH or abs (arg) < 16.0? */ - - /* result = x * c - n */ - - fp_exec (0042, &product, op[2], coeff); /* product = arg * C */ - O = fp_exec (0112, &count, NOP, NOP); /* count = FIX (acc) */ - - if ((int16) count.word >= 0) /* nearest even integer */ - count.word = count.word + 1; - BR = count.word = count.word & ~1; /* save LSBs of N */ - - O = O | fp_exec (0122, ACCUM, count, NOP); /* acc = FLT (count) */ - - if (O) { /* out of range? */ - op[0].fpk[0] = 0; /* microcode rtns with A = 0 */ - break; /* error return is P+1 */ - } - - fp_exec (0026, &result, product, NOP); /* acc = product - acc */ - fp_unpack (NULL, &rsltexp, result, fp_t); /* unpack exponent */ - - /* determine if cancellation matters */ - - if ((f < 0) || (f == 2) || (f == 6) || /* EXP, TANH, or COS? */ - (exponent - rsltexp < 5)) { /* bits lost < 5? */ - WriteOp (op[0].word, result, fp_t); /* write result */ - PC = (PC + 1) & VAMASK; /* P+2 return for good result */ - op[0].fpk[1] = BR; /* return LSBs of N in B */ - break; /* all done! */ - } - } - - /* result = (xu * cu - n) + (x - xu) * c + xu * cl */ - - if (exponent >= (8 + 16 * (f >= 0))) { /* exp >= 8 (EXP,TANH)? */ - op[0].fpk[0] = 0; /* or 24 (SIN/COS/TAN)? */ - break; /* range error return is P+1 */ - } - - op[3].fpk[0] = coeff.fpk[0]; /* form upper bits of C (CU) */ - op[3].fpk[1] = coeff.fpk[1] & 0177770; - op[3].fpk[2] = 0; - op[3].fpk[3] = coeff.fpk[3] & 0000377; - - op[4].fpk[0] = op[2].fpk[0]; /* form upper bits of X (XU) */ - op[4].fpk[1] = op[2].fpk[1] & 0177770; - op[4].fpk[2] = 0; - op[4].fpk[3] = op[2].fpk[3] & 0000377; - - fp_exec (0042, &op[5], op[3], op[4]); /* op5 = cu * xu */ - - fp_exec (0116, &op[6], NOP, NOP); /* op6 = fix (acc) (2wd) */ - - if ((int32) op[6].dword >= 0) /* nearest even integer */ - op[6].dword = op[6].dword + 1; - op[6].dword = op[6].dword & ~1; - BR = op[6].dword & DMASK; /* save LSBs of N */ - - O = fp_exec (0126, ACCUM, op[6], NOP); /* acc = flt (op6) */ - - if (O) { /* overflow? */ - op[0].fpk[0] = 0; /* microcode rtns with A = 0 */ - break; /* range error return is P+1 */ - } - - fp_exec (0026, &op[7], op[5], NOP); /* op7 = cu * xu - n */ - - fp_exec (0022, ACCUM, op[2], op[4]); /* acc = x - xu */ - fp_exec (0052, ACCUM, NOP, coeff); /* acc = (x - xu) * c */ - fp_exec (0012, &op[5], NOP, op[7]); /* op5 = acc + (cu * xu - n) */ - - op[1].word = (op[1].word + 4) & VAMASK; /* point at second coefficient */ - coeff = ReadOp (op[1].word, fp_t); /* get coefficient (CL) */ - - fp_exec (0042, ACCUM, op[4], coeff); /* acc = xu * cl */ - fp_exec (0012, &result, NOP, op[5]); /* result = acc + (x - xu) * c + (cu * xu - n) */ - - WriteOp (op[0].word, result, fp_t); /* write result */ - PC = (PC + 1) & VAMASK; /* P+2 return for good result */ - op[0].fpk[1] = BR; /* return LSBs of N in B */ - break; - - - case 013: /* /ATLG 105333 (OP_A) */ - arg = ReadOp (op[0].word, fp_t); /* get argument */ - - fp_exec (0022, &op[1], t_one, arg); /* op1 = 1.0 - arg */ - fp_exec (0002, ACCUM, t_one, arg); /* acc = 1.0 + arg */ - fp_exec (0066, &op[1], op[1], NOP); /* res = op1 / acc */ - - WriteOp (op[0].word, op[1], fp_t); /* write result */ - break; - - - case 014: /* .FPWR 105334 (OP_IIF) */ - p = 0; /* set to single-precision */ - goto NPWR; - - case 015: /* .TPWR 105335 (OP_IAT) */ - p = 2; /* set to double-precision */ - - NPWR: - if (op[2].fpk[0]) { /* non-zero base? */ - fp_exec (0120, &pwr, op[0], NOP); /* float power */ - - sign = ((int16) pwr.fpk[0] < 0); /* save sign of power */ - i = (pwr.fpk[0] << 2) & DMASK; /* clear it */ - - fp_unpack (NULL, &exponent, pwr, fp_f); /* unpack exponent */ - - if (sign == 0) - exponent = exponent - 1; - - O = 0; /* clear overflow */ - fp_accum (&op[2], (OPSIZE) (fp_f + p)); /* acc = arg */ - - while (exponent-- > 0) { - O = O | fp_exec ((uint16) (0054 | p), /* square acc */ - ACCUM, NOP, NOP); - - if (i & SIGN) - O = O | fp_exec ((uint16) (0050 | p), /* acc = acc * arg */ - ACCUM, NOP, op[2]); - i = i << 1; - } - - op[2] = fp_accum (NULL, (OPSIZE) (fp_f + p)); /* get accum */ - - if (op[2].fpk[0] == 0) /* result zero? */ - O = 1; /* underflow */ - } - - if (entry == 014) /* .FPWR ? */ - op[0] = op[2]; /* copy result */ - else /* .TPWR */ - WriteOp (op[1].word, op[2], fp_t); /* write result */ - - break; - - - case 017: /* [tst] 105337 (OP_N) */ - XR = 4; /* firmware revision */ - SR = 0102077; /* test passed code */ - PC = (PC + 1) & VAMASK; /* P+2 return for firmware w/DPOLY */ - return reason; - - - default: /* others undefined */ - return stop_inst; - } - -AR = op[0].fpk[0]; /* save result */ -BR = op[0].fpk[1]; /* into A/B */ -return reason; -} - -#endif /* end of int64 support */ +/* hp2100_cpu4.c: HP 1000 FPP/SIS + + Copyright (c) 2006-2014, J. David Bryan + + 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 + THE AUTHOR 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 the author shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from the author. + + CPU4 Floating Point Processor and Scientific Instruction Set + + 24-Dec-14 JDB Added casts for explicit downward conversions + 09-May-12 JDB Separated assignments from conditional expressions + 06-Feb-12 JDB Added OPSIZE casts to fp_accum calls in .FPWR/.TPWR + 11-Sep-08 JDB Moved microcode function prototypes to hp2100_cpu1.h + 05-Sep-08 JDB Removed option-present tests (now in UIG dispatchers) + 18-Mar-08 JDB Fixed B register return bug in /CMRT + 01-Dec-06 JDB Substitutes FPP for firmware FP if HAVE_INT64 + + Primary references: + - HP 1000 M/E/F-Series Computers Technical Reference Handbook + (5955-0282, Mar-1980) + - HP 1000 M/E/F-Series Computers Engineering and Reference Documentation + (92851-90001, Mar-1981) + - Macro/1000 Reference Manual (92059-90001, Dec-1992) + + Additional references are listed with the associated firmware + implementations, as are the HP option model numbers pertaining to the + applicable CPUs. +*/ + +#include "hp2100_defs.h" +#include "hp2100_cpu.h" +#include "hp2100_cpu1.h" + +#if defined (HAVE_INT64) /* int64 support available */ + +#include "hp2100_fp1.h" + + +/* Floating-Point Processor. + + The 1000 F-Series replaces the six 2100/1000-M/E single-precision firmware + floating-point instructions with a hardware floating-point processor (FPP). + The FPP executes single-, extended-, and double-precision floating-point + instructions, as well as double-integer instructions. All of the + floating-point instructions, as well as the single- and double-integer fix + and float instructions, are handled here. Pure double-integer instructions + are dispatched to the double-integer handler for simulation. + + Option implementation by CPU was as follows: + + 2114 2115 2116 2100 1000-M 1000-E 1000-F + ------ ------ ------ ------ ------ ------ ------ + N/A N/A N/A N/A N/A N/A std + + For the F-Series, the instruction codes are mapped to routines as follows: + + Instr. 1000-F Description + ------ ------ ------------------------------------- + 105000 FAD Single real add + 105001 .XADD Extended real add + 105002 .TADD Double real add + 105003 [EAD] [5-word add] + 105004 [tst] [Floating Point Processor self test] + 105005 [xpd] [Expand exponent] + 105006 [rst] [Floating Point Processor reset] + 105007 [stk] [Process stack of operands] + 105010 [chk] [FPP addressing check] + 105014 .DAD Double integer add + 105020 FSB Single real subtract + 105021 .XSUB Extended real subtract + 105022 .TSUB Double real subtract + 105023 [ESB] [5-word subtract] + 105034 .DSB Double integer subtract + 105040 FMP Single real multiply + 105041 .XMPY Extended real multiply + 105042 .TMPY Double real multiply + 105043 [EMP] [5-word multiply] + 105054 .DMP Double integer multiply + 105060 FDV Single real divide + 105061 .XDIV Extended real divide + 105062 .TDIV Double real divide + 105063 [EDV] [5-word divide] + 105074 .DDI Double integer divide + 105100 FIX Single real to integer fix + 105101 .XFXS Extended real to integer fix (.DINT) + 105102 .TXFS Double real to integer fix (.TINT) + 105103 [EFS] [5-word FIXS] + 105104 .FIXD Real to double integer fix + 105105 .XFXD Extended real to double integer fix + 105106 .TFXD Double real to double integer fix + 105107 [EFD] [5-word FIXD] + 105114 .DSBR Double integer subtraction (reversed) + 105120 FLT Integer to single real float + 105121 .XFTS Integer to extended real float (.IDBL) + 105122 .TFTS Integer to double real float (.ITBL) + 105123 [ELS] [5-word FLTS] + 105124 .FLTD Double integer to real float + 105125 .XFTD Double integer to extended real float + 105126 .TFTD Double integer to double real float + 105127 [ELD] [5-word FLTD] + 105134 .DDIR Double integer divide (reversed) + + Implementation note: rather than have two simulators that each executes the + single-precision FP instruction set, we compile conditionally, based on the + availability of 64-bit integer support in the host compiler. 64-bit integers + are required for the FPP, so if they are available, then we handle the + single-precision instructions for the 2100 and M/E-Series here, and the + firmware simulation is omitted. If support is unavailable, then the firmware + function is used instead. + + Notes: + + 1. Single-precision arithmetic instructions (.FAD, etc.) and extended- and + double-precision F-Series FPP arithmetic instructions (.XADD, .TADD, + etc.) return positive infinity on both positive and negative overflow. + The equivalent extended-precision M/E-Series FFP instructions return + negative infinity on negative overflow and positive infinity on positive + overflow. + + 2. The items in brackets above are undocumented instructions that are used + by the 12740 FPP-SIS-FFP diagnostic only. + + 3. The five-word arithmetic instructions (e.g., 105003) use an expanded + operand format that dedicates a separate word to the exponent. See the + implementation notes in the hardware floating-point processor simulation + for details. + + 4. The "self test" instruction (105004) returned to P+1 for early F-Series + units without double-integer support. Units incorporating such support + returned to P+2. + + 5. The "expand exponent" instruction (105005) is used as a "prefix" + instruction to enable a 10-bit exponent range. It is placed immediately + before a 5-word arithmetic instruction sequence, e.g., immediately + preceding an EAD instruction sequence. The arithmetic instruction + executes normally, except that under/overflow is not indicated unless + the exponent exceeds the 10-bit range, instead of the normal 8-bit + range. If overflow is indicated, the exponent is still set to +128. + + Note that as 2-, 3-, and 4-word packed numbers only have room for 8-bit + exponents, the Expand Exponent instruction serves no useful purpose in + conjunction with instructions associated with these precisions. If + used, the resulting values may be in error, as overflow from the 8-bit + exponents will not be indicated. + + 6. The "FPP reset" instruction (105006) is provided to reset a hung box, + e.g., in cases where an improper number of parameters is supplied. The + hardware resets its internal state machine in response to this + instruction. Under simulation, the instruction has no effect, as the + simulated FPP cannot hang. + + 7. The "process stack" instruction (105007) executes a series of FPP + instruction sets in sequence. Each set consists of a single FPP + instruction and associated operands that specifies the operation, + followed by a "result" instruction and operand. The result instruction + is optional and is only used to specify the result precision; the + instruction itself is not executed. If the result instruction is NOP, + then the result precision is that of the executed FPP instruction. If + the result operand is null, then the result is kept in the internal FPP + accumulator for later use. + + The calling sequence is as follows: + + STK Process stack instruction + DEF ERRTN Address of error return + DEF SET1 Address of first instruction set + DEF SET2 Address of second instruction set + . + . + . + ERRTN EQU * Return here if execution in error + OKRTN EQU * Return here if execution OK + + Instruction sets are specified as follows (e.g.): + + SET1 .TADD Operation instruction (NOP to terminate series) + DEC 4 Number of words in first operand (or 0 if accum) + DEF OP1 Address of first operand + DEC 4 Number of words in second operand (or 0 if accum) + DEF OP2 Address of second operand + .XADD Result precision conversion instruction (or NOP) + DEC 3 Number of words to store (or 0 if no store) + DEF RSLT Address of buffer to hold value + + The primary use of the "process stack" instruction is to enable chained + operations employing the FPP accumulator for intermediate results and to + enable expanded exponent usage across multiple instructions. + + 8. The "addressing check" instruction sets bit 0 of the L register to 1, + copies the X register value to the FPP, and then reads the FPP and + stores the result in the Y register. Setting the L register bit 0 to 1 + normally deselects the FPP, so that the value in Y is 177777. However, + the FPP box has a strap that inverts the selection logic, even though + the box will not work with the base-set firmware if this is done. The + "addressing check" instruction is provided to test whether the strap is + in the alternate location. Under simulation, the return value is always + 177777, indicating that the strap is correctly set. + + Additional references: + - DOS/RTE Relocatable Library Reference Manual (24998-90001, Oct-1981) + - FPP-SIS-FFP Diagnostic Source (12740-18001, Rev. 1926) +*/ + +static const OP_PAT op_fpp[96] = { + OP_RF, OP_AXX, OP_ATT, OP_AEE, /* FAD .XADD .TADD .EADD */ + OP_N, OP_C, OP_N, OP_A, /* [tst] [xpd] [rst] [stk] */ + OP_N, OP_N, OP_N, OP_N, /* [chk] --- --- --- */ + OP_N, OP_N, OP_N, OP_N, /* .DAD --- --- --- */ + OP_RF, OP_AXX, OP_ATT, OP_AEE, /* FSB .XSUB .TSUB .ESUB */ + OP_N, OP_N, OP_N, OP_N, /* --- --- --- --- */ + OP_N, OP_N, OP_N, OP_N, /* --- --- --- --- */ + OP_N, OP_N, OP_N, OP_N, /* .DSB --- --- --- */ + OP_RF, OP_AXX, OP_ATT, OP_AEE, /* FMP .XMPY .TMPY .EMPY */ + OP_N, OP_N, OP_N, OP_N, /* --- --- --- --- */ + OP_N, OP_N, OP_N, OP_N, /* --- --- --- --- */ + OP_N, OP_N, OP_N, OP_N, /* .DMP --- --- --- */ + OP_RF, OP_AXX, OP_ATT, OP_AEE, /* FDV .XDIV .TDIV .EDIV */ + OP_N, OP_N, OP_N, OP_N, /* --- --- --- --- */ + OP_N, OP_N, OP_N, OP_N, /* --- --- --- --- */ + OP_N, OP_N, OP_N, OP_N, /* .DDI --- --- --- */ + OP_R, OP_X, OP_T, OP_E, /* FIX .XFXS .TFXS .EFXS */ + OP_R, OP_X, OP_T, OP_E, /* .FIXD .XFXD .TFXD .EFXD */ + OP_N, OP_N, OP_N, OP_N, /* --- --- --- --- */ + OP_N, OP_N, OP_N, OP_N, /* .DSBR --- --- --- */ + OP_I, OP_IA, OP_IA, OP_IA, /* FLT .XFTS .TFTS .EFTS */ + OP_J, OP_JA, OP_JA, OP_JA, /* .FLTD .XFTD .TFTD .EFTD */ + OP_N, OP_N, OP_N, OP_N, /* --- --- --- --- */ + OP_N, OP_N, OP_N, OP_N /* .DDIR --- --- --- */ + }; + +t_stat cpu_fpp (uint32 IR, uint32 intrq) +{ +OP fpop; +OPS op; +OPSIZE op1_prec, op2_prec, rslt_prec, cvt_prec; +uint16 opcode, rtn_addr, stk_ptr; +uint32 entry; +t_stat reason = SCPE_OK; + +if (UNIT_CPU_MODEL == UNIT_1000_F) /* F-Series? */ + opcode = (uint16) (IR & 0377); /* yes, use full opcode */ +else + opcode = (uint16) (IR & 0160); /* no, use 6 SP FP opcodes */ + +entry = opcode & 0177; /* map to <6:0> */ + +if (op_fpp [entry] != OP_N) { + reason = cpu_ops (op_fpp [entry], op, intrq); /* get instruction operands */ + + if (reason != SCPE_OK) /* evaluation failed? */ + return reason; /* return reason for failure */ + } + +switch (entry) { /* decode IR<6:0> */ + case 0000: /* FAD 105000 (OP_RF) */ + case 0020: /* FSB 105020 (OP_RF) */ + case 0040: /* FMP 105040 (OP_RF) */ + case 0060: /* FDV 105060 (OP_RF) */ + O = fp_exec (opcode, &fpop, op[0], op[1]); /* execute operation */ + AR = fpop.fpk[0]; /* return result to A/B */ + BR = fpop.fpk[1]; + break; + + case 0001: /* .XADD 105001 (OP_AXX) */ + case 0002: /* .TADD 105002 (OP_ATT) */ + case 0003: /* .EADD 105003 (OP_AEE) */ + + case 0021: /* .XSUB 105021 (OP_AXX) */ + case 0022: /* .TSUB 105022 (OP_ATT) */ + case 0023: /* .ESUB 105023 (OP_AEE) */ + + case 0041: /* .XMPY 105041 (OP_AXX) */ + case 0042: /* .TMPY 105042 (OP_ATT) */ + case 0043: /* .EMPY 105043 (OP_AEE) */ + + case 0061: /* .XDIV 105061 (OP_AXX) */ + case 0062: /* .TDIV 105062 (OP_ATT) */ + case 0063: /* .EDIV 105063 (OP_AEE) */ + O = fp_exec (opcode, &fpop, op[1], op[2]); /* execute operation */ + fp_prec (opcode, NULL, NULL, &rslt_prec); /* determine result precision */ + WriteOp (op[0].word, fpop, rslt_prec); /* write result */ + break; + + case 0004: /* [tst] 105004 (OP_N) */ + XR = 3; /* firmware revision */ + SR = 0102077; /* test passed code */ + PC = (PC + 1) & VAMASK; /* P+2 return for firmware w/DBI */ + break; + + case 0005: /* [xpd] 105005 (OP_C) */ + return cpu_fpp (op[0].word | 0200, intrq); /* set bit 7, execute instr */ + + case 0006: /* [rst] 105006 (OP_N) */ + break; /* do nothing for FPP reset */ + + case 0007: /* [stk] 105007 (OP_A) */ + O = 0; /* clear overflow */ + stk_ptr = (uint16) PC; /* save ptr to next buf */ + rtn_addr = op[0].word; /* save return address */ + + while (TRUE) { + PC = ReadW (stk_ptr) & VAMASK; /* point at next instruction set */ + stk_ptr = (stk_ptr + 1) & VAMASK; + + reason = cpu_ops (OP_CCACACCA, op, intrq); /* get instruction set */ + + if (reason) { + PC = err_PC; /* irq restarts */ + break; + } + + if (op[0].word == 0) { /* opcode = NOP? */ + PC = (rtn_addr + 1) & VAMASK; /* bump to good return */ + break; /* done */ + } + + fp_prec ((uint16) (op[0].word & 0377), /* determine operand precisions */ + &op1_prec, &op2_prec, &rslt_prec); + + if (TO_COUNT(op1_prec) != op[1].word) { /* first operand precisions agree? */ + PC = rtn_addr; /* no, so take error return */ + break; + } + + else if (op1_prec != fp_a) /* operand in accumulator? */ + op[1] = ReadOp (op[2].word, op1_prec); /* no, so get operand 1 */ + + if (TO_COUNT(op2_prec) != op[3].word) { /* second operand precisions agree? */ + PC = rtn_addr; /* no, so take error return */ + break; + } + + else if (op2_prec != fp_a) /* operand in accumulator? */ + op[2] = ReadOp (op[4].word, op2_prec); /* no, so get operand 2 */ + + O = O | /* execute instruction */ + fp_exec ((uint16) (op[0].word & 0377), /* and accumulate overflow */ + &fpop, op[1], op[2]); + + if (op[5].word) { /* precision conversion? */ + fp_prec ((uint16) (op[5].word & 0377), /* determine conversion precision */ + NULL, NULL, &cvt_prec); + + fpop = fp_accum (NULL, cvt_prec); /* convert result */ + } + else /* no conversion specified */ + cvt_prec = rslt_prec; /* so use original precision */ + + if (op[6].word) /* store result? */ + WriteOp (op[7].word, fpop, cvt_prec); /* yes, so write it */ + } + + break; + + case 0010: /* [chk] 105010 (OP_N) */ + YR = 0177777; /* -1 if selection strap OK */ + break; + + case 0014: /* .DAD 105014 (OP_N) */ + return cpu_dbi (0105321, intrq); /* remap to double int handler */ + + case 0034: /* .DSB 105034 (OP_N) */ + return cpu_dbi (0105327, intrq); /* remap to double int handler */ + + case 0054: /* .DMP 105054 (OP_N) */ + return cpu_dbi (0105322, intrq); /* remap to double int handler */ + + case 0074: /* .DDI 105074 (OP_N) */ + return cpu_dbi (0105325, intrq); /* remap to double int handler */ + + case 0100: /* FIX 105100 (OP_R) */ + case 0101: /* .XFXS 105101 (OP_X) */ + case 0102: /* .TFXS 105102 (OP_T) */ + case 0103: /* .EFXS 105103 (OP_E) */ + O = fp_exec (opcode, &fpop, op[0], NOP); /* fix to integer */ + AR = fpop.fpk[0]; /* save result */ + break; + + case 0104: /* .FIXD 105104 (OP_R) */ + case 0105: /* .XFXD 105105 (OP_X) */ + case 0106: /* .TFXD 105106 (OP_T) */ + case 0107: /* .EFXD 105107 (OP_E) */ + O = fp_exec (opcode, &fpop, op[0], NOP); /* fix to integer */ + AR = (fpop.dword >> 16) & DMASK; /* save result */ + BR = fpop.dword & DMASK; /* in A and B */ + break; + + case 0114: /* .DSBR 105114 (OP_N) */ + return cpu_dbi (0105334, intrq); /* remap to double int handler */ + + case 0120: /* FLT 105120 (OP_I) */ + case 0124: /* .FLTD 105124 (OP_J) */ + O = fp_exec (opcode, &fpop, op[0], NOP); /* float to single */ + AR = fpop.fpk[0]; /* save result */ + BR = fpop.fpk[1]; /* into A/B */ + break; + + case 0121: /* .XFTS 105121 (OP_IA) */ + case 0122: /* .TFTS 105122 (OP_IA) */ + case 0123: /* .EFTS 105123 (OP_IA) */ + case 0125: /* .XFTD 105125 (OP_JA) */ + case 0126: /* .TFTD 105126 (OP_JA) */ + case 0127: /* .EFTD 105127 (OP_JA) */ + O = fp_exec (opcode, &fpop, op[0], NOP); /* float integer */ + fp_prec (opcode, NULL, NULL, &rslt_prec); /* determine result precision */ + WriteOp (op[1].word, fpop, rslt_prec); /* write result */ + break; + + case 0134: /* .DDIR 105134 (OP_N) */ + return cpu_dbi (0105326, intrq); /* remap to double int handler */ + + default: /* others undefined */ + reason = stop_inst; + } + +return reason; +} + + +/* Scientific Instruction Set. + + The SIS adds single-precision trigonometric and logarithmic, and + double-precision polynomial evaluation instructions to the 1000-F instruction + set. The SIS is standard on the 1000-F. + + Option implementation by CPU was as follows: + + 2114 2115 2116 2100 1000-M 1000-E 1000-F + ------ ------ ------ ------ ------ ------ ------ + N/A N/A N/A N/A N/A N/A std + + The routines are mapped to instruction codes as follows: + + Instr. 1000-F Description + ------ ------ ---------------------------------------------- + TAN 105320 Tangent + SQRT 105321 Square root + ALOG 105322 Natural logarithm + ATAN 105323 Arc tangent + COS 105324 Cosine + SIN 105325 Sine + EXP 105326 E to the power X + ALOGT 105327 Common logarithm + TANH 105330 Hyperbolic tangent + DPOLY 105331 Double-precision polynomial evaluation + /CMRT 105332 Double-precision common range reduction + /ATLG 105333 Compute (1-x)/(1+x) for .ATAN and .LOG + .FPWR 105334 Single-precision exponentiation + .TPWR 105335 Double-precision exponentiation + [tst] 105337 [self test] + + The SIS simulation follows the F-Series SIS microcode, which, in turn, + follows the algebraic approximations given in the Relocatable Library manual + descriptions of the equivalent software routines. + + Notes: + + 1. The word following the DPOLY instruction contains up to three flag bits + to indicate one of several polynomial forms to evaluate. The comments + in the DPOLY software library routine source interchange the actions of + the bit 14 and bit 0 flags. The DPOLY description in the Technical + Reference Handbook is correct. + + 2. Several instructions (e.g., DPOLY) are documented as leaving undefined + values in the A, B, X, Y, E, or O registers. Simulation does not + attempt to reproduce the same values as would be obtained with the + hardware. + + 3. The SIS uses the hardware FPP of the F-Series. FPP malfunctions are + detected by the SIS firmware and are indicated by a memory-protect + violation and setting the overflow flag. Under simulation, + malfunctions cannot occur. + + 4. We use OP_IIT for the .FPWR operand pattern. The "II" is redundant, but + it aligns the operands with the OP_IAT of .TPWR, so the code may be + shared. + + Additional references: + - DOS/RTE Relocatable Library Reference Manual (24998-90001, Oct-1981) + - HP 1000 E-Series and F-Series Computer Microprogramming Reference Manual + (02109-90004, Apr-1980). +*/ + + +/* Common single-precision range reduction for SIN, COS, TAN, and EXP. + + This routine is called by the SIN, COS, TAN, and EXP handlers to reduce the + range of the argument. Reduction is performed in extended-precision. We + calculate: + + multiple = (nearest even integer to argument * multiplier) + argument = argument * multiplier - multiple +*/ + +static uint32 reduce (OP *argument, int32 *multiple, OP multiplier) +{ +OP product, count; +uint32 overflow; + +fp_cvt (argument, fp_f, fp_x); /* convert to extended precision */ +fp_exec (0041, &product, *argument, multiplier); /* product = argument * multiplier */ +overflow = fp_exec (0111, &count, NOP, NOP); /* count = FIX (acc) */ + +if ((int16) count.word >= 0) /* nearest even integer */ + count.word = count.word + 1; +count.word = count.word & ~1; +*multiple = (int16) count.word; + +if (overflow == 0) { /* in range? */ + fp_exec (0121, ACCUM, count, NOP); /* acc = FLT (count) */ + overflow = fp_exec (0025, ACCUM, product, NOP); /* acc = product - acc */ + *argument = fp_accum (NULL, fp_f); /* trim to single-precision */ + } +return overflow; +} + + +/* SIS dispatcher. */ + +static const OP_PAT op_sis[16] = { + OP_R, OP_R, OP_R, OP_R, /* TAN SQRT ALOG ATAN */ + OP_R, OP_R, OP_R, OP_R, /* COS SIN EXP ALOGT */ + OP_R, OP_CATAKK, OP_AAT, OP_A, /* TANH DPOLY /CMRT /ATLG */ + OP_IIF, OP_IAT, OP_N, OP_N /* .FPWR .TPWR --- [tst] */ + }; + +t_stat cpu_sis (uint32 IR, uint32 intrq) +{ +OPS op; +OP arg, coeff, pwr, product, count, result; +int16 f, p; +int32 multiple, power, exponent, rsltexp; +uint32 entry, i; +t_bool flag, sign; +t_stat reason = SCPE_OK; + +static const OP tan_c4 = { { 0137763, 0051006 } }; /* DEC -4.0030956 */ +static const OP tan_c3 = { { 0130007, 0051026 } }; /* DEC -1279.5424 */ +static const OP tan_c2 = { { 0040564, 0012761 } }; /* DEC 0.0019974806 */ +static const OP tan_c1 = { { 0045472, 0001375 } }; /* DEC 0.14692695 */ + +static const OP alog_c3 = { { 0065010, 0063002 } }; /* DEC 1.6567626301 */ +static const OP alog_c2 = { { 0125606, 0044404 } }; /* DEC -2.6398577035 */ +static const OP alog_c1 = { { 0051260, 0037402 } }; /* DEC 1.2920070987 */ + +static const OP atan_c4 = { { 0040257, 0154404 } }; /* DEC 2.0214656 */ +static const OP atan_c3 = { { 0132062, 0133406 } }; /* DEC -4.7376165 */ +static const OP atan_c2 = { { 0047407, 0173775 } }; /* DEC 0.154357652 */ +static const OP atan_c1 = { { 0053447, 0014002 } }; /* DEC 1.3617611 */ + +static const OP sin_c4 = { { 0132233, 0040745 } }; /* DEC -0.000035950439 */ +static const OP sin_c3 = { { 0050627, 0122361 } }; /* DEC 0.002490001 */ +static const OP sin_c2 = { { 0126521, 0011373 } }; /* DEC -0.0807454325 */ +static const OP sin_c1 = { { 0062207, 0166400 } }; /* DEC 0.78539816 */ + +static const OP cos_c4 = { { 0126072, 0002753 } }; /* DEC -0.00031957 */ +static const OP cos_c3 = { { 0040355, 0007767 } }; /* DEC 0.015851077 */ +static const OP cos_c2 = { { 0130413, 0011377 } }; /* DEC -0.30842483 */ +static const OP cos_c1 = { { 0040000, 0000002 } }; /* DEC 1.0 */ + +static const OP sqrt_a2 = { { 0045612, 0067400 } }; /* DEC 0.5901621 */ +static const OP sqrt_b2 = { { 0065324, 0126377 } }; /* DEC 0.4173076 */ +static const OP sqrt_a1 = { { 0065324, 0126400 } }; /* DEC 0.8346152 */ +static const OP sqrt_b1 = { { 0045612, 0067400 } }; /* DEC 0.5901621 */ + +static const OP exp_c2 = { { 0073000, 0070771 } }; /* DEC 0.05761803 */ +static const OP exp_c1 = { { 0056125, 0041406 } }; /* DEC 5.7708162 */ + +static const OP tanh_c3 = { { 0050045, 0022004 } }; /* DEC 2.5045337 */ +static const OP tanh_c2 = { { 0041347, 0101404 } }; /* DEC 2.0907609 */ +static const OP tanh_c1 = { { 0052226, 0047375 } }; /* DEC 0.16520923 */ + +static const OP minus_1 = { { 0100000, 0000000 } }; /* DEC -1.0 */ +static const OP plus_1 = { { 0040000, 0000002 } }; /* DEC +1.0 */ +static const OP plus_half = { { 0040000, 0000000 } }; /* DEC +0.5 */ +static const OP ln_2 = { { 0054271, 0006000 } }; /* DEC 0.6931471806 (ln 2.0) */ +static const OP log_e = { { 0067455, 0166377 } }; /* DEC 0.43429228 (log e) */ +static const OP pi_over_4 = { { 0062207, 0166400 } }; /* Pi / 4.0 */ +static const OP pi_over_2 = { { 0062207, 0166402 } }; /* Pi / 2.0 */ + +static const OP four_over_pi = { { 0050574, 0140667, 0023402 } }; /* 4.0 / Pi */ +static const OP two_over_ln2 = { { 0056125, 0016624, 0127404 } }; /* 2.0 / ln(2.0) */ + +static const OP t_one = { { 0040000, 0000000, 0000000, 0000002 } }; /* DEY 1.0 */ + + +entry = IR & 017; /* mask to entry point */ + +if (op_sis [entry] != OP_N) { + reason = cpu_ops (op_sis [entry], op, intrq); /* get instruction operands */ + + if (reason != SCPE_OK) /* evaluation failed? */ + return reason; /* return reason for failure */ + } + +switch (entry) { /* decode IR<3:0> */ + + case 000: /* TAN 105320 (OP_R) */ + O = reduce (&op[0], &multiple, four_over_pi); /* reduce range */ + + if (O) { /* out of range? */ + op[0].fpk[0] = '0' << 8 | '9'; /* return '09' */ + op[0].fpk[1] = 'O' << 8 | 'R'; /* return 'OR' */ + break; /* error return is P+1 */ + } + + fp_exec (0040, &op[1], op[0], op[0]); /* op1 = arg ^ 2 */ + fp_exec (0010, ACCUM, NOP, tan_c4); /* acc = acc + C4 */ + fp_exec (0064, ACCUM, tan_c3, NOP); /* acc = C3 / acc */ + fp_exec (0010, ACCUM, NOP, op[1]); /* acc = acc + op1 */ + fp_exec (0050, ACCUM, NOP, tan_c2); /* acc = acc * C2 */ + fp_exec (0010, ACCUM, NOP, tan_c1); /* acc = acc + C1 */ + fp_exec (0050, &op[0], NOP, op[0]); /* res = acc * arg */ + + if (multiple & 0002) /* multiple * 2 odd? */ + fp_exec (0064, &op[0], minus_1, NOP); /* res = -1.0 / acc */ + + PC = (PC + 1) & VAMASK; /* normal return is P+2 */ + break; + + + case 001: /* SQRT 105321 (OP_R) */ + O = 0; /* clear overflow */ + + if (op[0].fpk[0] == 0) { /* arg = 0? */ + PC = (PC + 1) & VAMASK; /* normal return is P+2 */ + break; + } + + else if ((int16) op[0].fpk[0] < 0) { /* sqrt of neg? */ + op[0].fpk[0] = '0' << 8 | '3'; /* return '03' */ + op[0].fpk[1] = 'U' << 8 | 'N'; /* return 'UN' */ + O = 1; /* set overflow */ + break; /* error return is P+1 */ + } + + fp_unpack (&op[1], &exponent, op[0], fp_f); /* unpack argument */ + + if (exponent & 1) { /* exponent odd? */ + fp_exec (0040, ACCUM, op[1], sqrt_a1); /* acc = op1 * A1 */ + fp_exec (0010, &op[2], NOP, sqrt_b1); /* op2 = acc + B1 */ + op[1].fpk[1] = op[1].fpk[1] + 2; /* op1 = op1 * 2.0 */ + } + else { /* exponent even */ + fp_exec (0040, ACCUM, op[1], sqrt_a2); /* acc = op1 * A2 */ + fp_exec (0010, &op[2], NOP, sqrt_b2); /* op2 = acc + B2 */ + } + + fp_exec (0064, ACCUM, op[1], NOP); /* acc = op1 / acc */ + fp_exec (0010, &op[2], NOP, op[2]); /* op2 = acc + op2 */ + + op[1].fpk[1] = op[1].fpk[1] + 4; /* op1 = op1 * 4.0 */ + + fp_exec (0064, ACCUM, op[1], NOP); /* acc = op1 / acc */ + fp_exec (0010, &op[0], NOP, op[2]); /* res = acc + op2 */ + + power = (exponent >> 1) - 2; + + if (op[0].fpk[0]) { /* calc x * 2**n */ + fp_unpack (&op[1], &exponent, op[0], fp_f); /* unpack argument */ + exponent = exponent + power; /* multiply by 2**n */ + + if ((exponent > 0177) || /* exponent overflow? */ + (exponent < -0200)) { /* or underflow? */ + O = 1; /* rtn unscaled val, set ovf */ + break; /* error return is P+1 */ + } + + else + fp_pack (&op[0], op[1], exponent, fp_f);/* repack result */ + } + + PC = (PC + 1) & VAMASK; /* normal return is P+2 */ + break; + + + case 002: /* ALOG 105322 (OP_R) */ + case 007: /* ALOGT 105327 (OP_R) */ + O = 0; /* clear overflow */ + + if ((int16) op[0].fpk[0] <= 0) { /* log of neg or zero? */ + op[0].fpk[0] = '0' << 8 | '2'; /* return '02' */ + op[0].fpk[1] = 'U' << 8 | 'N'; /* return 'UN' */ + O = 1; /* set overflow */ + break; /* error return is P+1 */ + } + + fp_unpack (&op[1], &exponent, op[0], fp_f); /* unpack argument */ + + if (op[0].fpk[0] < 0055000) { /* out of range? */ + exponent = exponent - 1; /* drop exponent */ + op[1].fpk[1] = op[1].fpk[1] | 2; /* set "exponent" to 1 */ + } + + op[2].fpk[0] = (uint16) exponent; + fp_exec (0120, &op[3], op[2], NOP); /* op3 = FLT(exponent) */ + + fp_exec (0020, &op[4], op[1], plus_1); /* op4 = op1 - 1.0 */ + fp_exec (0000, ACCUM, op[1], plus_1); /* acc = op1 + 1.0 */ + fp_exec (0064, &op[5], op[4], NOP); /* op5 = op4 / acc */ + + fp_exec (0054, ACCUM, NOP, NOP); /* acc = acc * acc */ + fp_exec (0030, ACCUM, NOP, alog_c3); /* acc = acc - c3 */ + fp_exec (0064, ACCUM, alog_c2, NOP); /* acc = c2 / acc */ + fp_exec (0010, ACCUM, NOP, alog_c1); /* acc = acc + c1 */ + fp_exec (0050, ACCUM, NOP, op[5]); /* acc = acc * op5 */ + fp_exec (0010, ACCUM, NOP, op[3]); /* acc = acc + op3 */ + fp_exec (0050, &op[0], NOP, ln_2); /* res = acc * ln2 */ + + if (entry == 007) /* ALOGT? */ + fp_exec (0050, &op[0], NOP, log_e); /* res = acc * log(e) */ + + PC = (PC + 1) & VAMASK; /* normal return is P+2 */ + break; + + + case 003: /* ATAN 105323 (OP_R) */ + O = 0; /* clear overflow */ + + if (op[0].fpk[0] == 0) /* argument zero? */ + break; /* result zero */ + + flag = (op[0].fpk[1] & 1); /* get exponent sign */ + sign = ((int16) op[0].fpk[0] < 0); /* get argument sign */ + + if (flag == 0) { /* exp pos? (abs >= 0.5)? */ + if (sign) /* argument negative? */ + fp_pcom (&op[0], fp_f); /* make positive */ + + if (op[0].fpk[1] & 0374) { /* arg >= 2? */ + fp_exec(0060, &op[0], plus_1, op[0]); /* arg = 1.0 / arg */ + op[2] = pi_over_2; /* constant = pi / 2.0 */ + } + else { + fp_exec (0020, &op[1], plus_1, op[0]); /* op1 = 1.0 - arg */ + fp_exec (0000, ACCUM, plus_1, op[0]); /* acc = 1.0 + arg */ + fp_exec (0064, &op[0], op[1], NOP); /* arg = op1 / acc */ + op[2] = pi_over_4; /* constant = pi / 4.0 */ + } + } + + fp_exec (0040, &op[1], op[0], op[0]); /* op1 = arg * arg */ + fp_exec (0010, ACCUM, NOP, atan_c4); /* acc = acc + C4 */ + fp_exec (0064, ACCUM, atan_c3, NOP); /* acc = C3 / acc */ + fp_exec (0010, ACCUM, NOP, op[1]); /* acc = acc + op1 */ + fp_exec (0050, ACCUM, NOP, atan_c2); /* acc = acc * C2 */ + fp_exec (0010, ACCUM, NOP, atan_c1); /* acc = acc + C1 */ + fp_exec (0064, &op[0], op[0], NOP); /* res = arg / acc */ + + if (flag == 0) { /* exp pos? (abs >= 0.5)? */ + fp_exec (0030, &op[0], NOP, op[2]); /* res = acc - pi / n */ + + if (sign == 0) /* argument positive? */ + fp_pcom (&op[0], fp_f); /* make negative */ + } + + break; + + + case 004: /* COS 105324 (OP_R) */ + case 005: /* SIN 105325 (OP_R) */ + O = reduce (&op[0], &multiple, four_over_pi); /* reduce range */ + + if (O) { /* out of range? */ + op[0].fpk[0] = '0' << 8 | '5'; /* return '05' */ + op[0].fpk[1] = 'O' << 8 | 'R'; /* return 'OR' */ + break; /* error return is P+1 */ + } + + multiple = multiple / 2 + (entry == 004); /* add one for cosine */ + flag = (multiple & 1); /* decide on series */ + + fp_exec (0040, &op[1], op[0], op[0]); /* op1 = arg ^ 2 */ + + if (flag) { + fp_exec (0050, ACCUM, NOP, cos_c4); /* acc = acc * c4 */ + fp_exec (0010, ACCUM, NOP, cos_c3); /* acc = acc + c3 */ + fp_exec (0050, ACCUM, NOP, op[1]); /* acc = acc * op1 */ + fp_exec (0010, ACCUM, NOP, cos_c2); /* acc = acc + c2 */ + fp_exec (0050, ACCUM, NOP, op[1]); /* acc = acc * op1 */ + fp_exec (0010, &op[0], NOP, cos_c1); /* res = acc + c1 */ + } + + else { + fp_exec (0050, ACCUM, NOP, sin_c4); /* acc = acc * c4 */ + fp_exec (0010, ACCUM, NOP, sin_c3); /* acc = acc + c3 */ + fp_exec (0050, ACCUM, NOP, op[1]); /* acc = acc * op1 */ + fp_exec (0010, ACCUM, NOP, sin_c2); /* acc = acc + c2 */ + fp_exec (0050, ACCUM, NOP, op[1]); /* acc = acc * op1 */ + fp_exec (0010, ACCUM, NOP, sin_c1); /* acc = acc + c1 */ + fp_exec (0050, &op[0], NOP, op[0]); /* res = acc * arg */ + } + + if (multiple & 0002) /* multiple * 2 odd? */ + fp_pcom (&op[0], fp_f); /* make negative */ + + PC = (PC + 1) & VAMASK; /* normal return is P+2 */ + break; + + + case 006: /* EXP 105326 (OP_R) */ + sign = ((int16) op[0].fpk[0] < 0); /* get argument sign */ + + O = reduce (&op[0], &multiple, two_over_ln2); /* reduce range */ + multiple = multiple / 2; /* get true multiple */ + + if ((sign == 0) && (O | (multiple > 128))) { /* pos and ovf or out of range? */ + op[0].fpk[0] = '0' << 8 | '7'; /* return '07' */ + op[0].fpk[1] = 'O' << 8 | 'F'; /* return 'OF' */ + O = 1; /* set overflow */ + break; /* error return is P+1 */ + } + + else if (sign && (multiple < -128)) { /* neg and out of range? */ + op[0].fpk[0] = 0; /* result is zero */ + op[0].fpk[1] = 0; + O = 0; /* clear for underflow */ + PC = (PC + 1) & VAMASK; /* normal return is P+2 */ + break; + } + + fp_exec (0040, ACCUM, op[0], op[0]); /* acc = arg ^ 2 */ + fp_exec (0050, ACCUM, NOP, exp_c2); /* acc = acc * c2 */ + fp_exec (0030, ACCUM, NOP, op[0]); /* acc = acc - op0 */ + fp_exec (0010, ACCUM, NOP, exp_c1); /* acc = acc + c1 */ + fp_exec (0064, ACCUM, op[0], NOP); /* acc = op0 / acc */ + fp_exec (0010, &op[0], NOP, plus_half); /* res = acc + 0.5 */ + + power = multiple + 1; + + if (op[0].fpk[0]) { /* calc x * 2**n */ + fp_unpack (&op[1], &exponent, op[0], fp_f); /* unpack argument */ + exponent = exponent + power; /* multiply by 2**n */ + + if ((exponent > 0177) || /* exponent overflow? */ + (exponent < -0200)) { /* or underflow? */ + if (sign == 0) { /* arg positive? */ + op[0].fpk[0] = '0' << 8 | '7'; /* return '07' */ + op[0].fpk[1] = 'O' << 8 | 'F'; /* return 'OF' */ + O = 1; /* set overflow */ + } + else { + op[0].fpk[0] = 0; /* result is zero */ + op[0].fpk[1] = 0; + O = 0; /* clear for underflow */ + } + break; /* error return is P+1 */ + } + + else { + fp_pack (&op[0], op[1], exponent, fp_f);/* repack value */ + O = 0; + } + } + + PC = (PC + 1) & VAMASK; /* normal return is P+2 */ + break; + + + case 010: /* TANH 105330 (OP_R) */ + O = 0; + sign = ((int16) op[0].fpk[0] < 0); /* get argument sign */ + + if (op[0].fpk[1] & 1) { /* abs (arg) < 0.5? */ + fp_exec (0040, ACCUM, op[0], op[0]); /* acc = arg ^ 2 */ + fp_exec (0010, ACCUM, NOP, tanh_c3); /* acc = acc + c3 */ + fp_exec (0064, ACCUM, tanh_c2, NOP); /* acc = c2 / acc */ + fp_exec (0010, ACCUM, NOP, tanh_c1); /* acc = acc + c1 */ + fp_exec (0050, &op[0], NOP, op[0]); /* res = acc * arg */ + } + + else if (op[0].fpk[1] & 0370) /* abs (arg) >= 8.0? */ + if (sign) /* arg negative? */ + op[0] = minus_1; /* result = -1.0 */ + else /* arg positive */ + op[0] = plus_1; /* result = +1.0 */ + + else { /* 0.5 <= abs (arg) < 8.0 */ + BR = BR + 2; /* arg = arg * 2.0 */ + cpu_sis (0105326, intrq); /* calc exp (arg) */ + PC = (PC - 1) & VAMASK; /* correct P (always good rtn) */ + + op[0].fpk[0] = AR; /* save value */ + op[0].fpk[1] = BR; + + fp_exec (0020, &op[1], op[0], plus_1); /* op1 = op0 - 1.0 */ + fp_exec (0000, ACCUM, op[0], plus_1); /* acc = op0 + 1.0 */ + fp_exec (0064, &op[0], op[1], NOP); /* res = op1 / acc */ + } + + break; + + + case 011: /* DPOLY 105331 (OP_CATAKK) */ + O = 0; /* clear overflow */ + AR = op[0].word; /* get flag word */ + + if ((int16) AR >= 0) { /* flags present? */ + AR = 1; /* no, so set default */ + arg = op[2]; /* arg = X */ + } + + else /* bit 15 set */ + fp_exec (0042, &arg, op[2], op[2]); /* arg = X ^ 2 */ + + coeff = ReadOp (op[3].word, fp_t); /* get first coefficient */ + op[3].word = (op[3].word + 4) & VAMASK; /* point at next */ + fp_accum (&coeff, fp_t); /* acc = coeff */ + + for (i = 0; i < op[4].word; i++) { /* compute numerator */ + fp_exec (0052, ACCUM, NOP, arg); /* acc = P[m] * arg */ + coeff = ReadOp (op[3].word, fp_t); /* get next coefficient */ + op[3].word = (op[3].word + 4) & VAMASK; /* point at next */ + fp_exec (0012, ACCUM, NOP, coeff); /* acc = acc + P[m-1] */ + } + + if (AR & 1) /* bit 0 set? */ + op[6] = fp_accum (NULL, fp_t); /* save numerator */ + else + fp_exec (0046, &op[6], op[2], NOP); /* acc = X * acc */ + + + if (op[5].word) { /* n > 0 ? */ + fp_accum (&t_one, fp_t); /* acc = 1.0 */ + + for (i = 0; i < op[5].word; i++) { /* compute denominator */ + fp_exec (0052, ACCUM, NOP, arg); /* acc = P[m] * arg */ + coeff = ReadOp (op[3].word, fp_t); /* get next coefficient */ + op[3].word = (op[3].word + 4) & VAMASK; /* point at next */ + fp_exec (0012, ACCUM, NOP, coeff); /* acc = acc + P[m-1] */ + } + + if (AR & 0040000) /* bit 14 set? */ + fp_exec (0032, ACCUM, NOP, op[6]); /* acc = den - num */ + + fp_exec (0066, &op[6], op[6], NOP); /* op6 = num / den */ + } + + WriteOp (op[1].word, op[6], fp_t); /* write result */ + + if (O) /* overflow? */ + op[0].fpk[0] = 0; /* microcode rtns with A = 0 */ + break; + + + case 012: /* /CMRT 105332 (OP_AAT) */ + O = 0; + f = (int16) AR; /* save flags */ + + coeff = ReadOp (op[1].word, fp_t); /* get coefficient (C) */ + + fp_unpack (NULL, &exponent, op[2], fp_t); /* unpack exponent */ + + if ((f == -1) || (exponent < 4)) { /* TANH or abs (arg) < 16.0? */ + + /* result = x * c - n */ + + fp_exec (0042, &product, op[2], coeff); /* product = arg * C */ + O = fp_exec (0112, &count, NOP, NOP); /* count = FIX (acc) */ + + if ((int16) count.word >= 0) /* nearest even integer */ + count.word = count.word + 1; + BR = count.word = count.word & ~1; /* save LSBs of N */ + + O = O | fp_exec (0122, ACCUM, count, NOP); /* acc = FLT (count) */ + + if (O) { /* out of range? */ + op[0].fpk[0] = 0; /* microcode rtns with A = 0 */ + break; /* error return is P+1 */ + } + + fp_exec (0026, &result, product, NOP); /* acc = product - acc */ + fp_unpack (NULL, &rsltexp, result, fp_t); /* unpack exponent */ + + /* determine if cancellation matters */ + + if ((f < 0) || (f == 2) || (f == 6) || /* EXP, TANH, or COS? */ + (exponent - rsltexp < 5)) { /* bits lost < 5? */ + WriteOp (op[0].word, result, fp_t); /* write result */ + PC = (PC + 1) & VAMASK; /* P+2 return for good result */ + op[0].fpk[1] = BR; /* return LSBs of N in B */ + break; /* all done! */ + } + } + + /* result = (xu * cu - n) + (x - xu) * c + xu * cl */ + + if (exponent >= (8 + 16 * (f >= 0))) { /* exp >= 8 (EXP,TANH)? */ + op[0].fpk[0] = 0; /* or 24 (SIN/COS/TAN)? */ + break; /* range error return is P+1 */ + } + + op[3].fpk[0] = coeff.fpk[0]; /* form upper bits of C (CU) */ + op[3].fpk[1] = coeff.fpk[1] & 0177770; + op[3].fpk[2] = 0; + op[3].fpk[3] = coeff.fpk[3] & 0000377; + + op[4].fpk[0] = op[2].fpk[0]; /* form upper bits of X (XU) */ + op[4].fpk[1] = op[2].fpk[1] & 0177770; + op[4].fpk[2] = 0; + op[4].fpk[3] = op[2].fpk[3] & 0000377; + + fp_exec (0042, &op[5], op[3], op[4]); /* op5 = cu * xu */ + + fp_exec (0116, &op[6], NOP, NOP); /* op6 = fix (acc) (2wd) */ + + if ((int32) op[6].dword >= 0) /* nearest even integer */ + op[6].dword = op[6].dword + 1; + op[6].dword = op[6].dword & ~1; + BR = op[6].dword & DMASK; /* save LSBs of N */ + + O = fp_exec (0126, ACCUM, op[6], NOP); /* acc = flt (op6) */ + + if (O) { /* overflow? */ + op[0].fpk[0] = 0; /* microcode rtns with A = 0 */ + break; /* range error return is P+1 */ + } + + fp_exec (0026, &op[7], op[5], NOP); /* op7 = cu * xu - n */ + + fp_exec (0022, ACCUM, op[2], op[4]); /* acc = x - xu */ + fp_exec (0052, ACCUM, NOP, coeff); /* acc = (x - xu) * c */ + fp_exec (0012, &op[5], NOP, op[7]); /* op5 = acc + (cu * xu - n) */ + + op[1].word = (op[1].word + 4) & VAMASK; /* point at second coefficient */ + coeff = ReadOp (op[1].word, fp_t); /* get coefficient (CL) */ + + fp_exec (0042, ACCUM, op[4], coeff); /* acc = xu * cl */ + fp_exec (0012, &result, NOP, op[5]); /* result = acc + (x - xu) * c + (cu * xu - n) */ + + WriteOp (op[0].word, result, fp_t); /* write result */ + PC = (PC + 1) & VAMASK; /* P+2 return for good result */ + op[0].fpk[1] = BR; /* return LSBs of N in B */ + break; + + + case 013: /* /ATLG 105333 (OP_A) */ + arg = ReadOp (op[0].word, fp_t); /* get argument */ + + fp_exec (0022, &op[1], t_one, arg); /* op1 = 1.0 - arg */ + fp_exec (0002, ACCUM, t_one, arg); /* acc = 1.0 + arg */ + fp_exec (0066, &op[1], op[1], NOP); /* res = op1 / acc */ + + WriteOp (op[0].word, op[1], fp_t); /* write result */ + break; + + + case 014: /* .FPWR 105334 (OP_IIF) */ + p = 0; /* set to single-precision */ + goto NPWR; + + case 015: /* .TPWR 105335 (OP_IAT) */ + p = 2; /* set to double-precision */ + + NPWR: + if (op[2].fpk[0]) { /* non-zero base? */ + fp_exec (0120, &pwr, op[0], NOP); /* float power */ + + sign = ((int16) pwr.fpk[0] < 0); /* save sign of power */ + i = (pwr.fpk[0] << 2) & DMASK; /* clear it */ + + fp_unpack (NULL, &exponent, pwr, fp_f); /* unpack exponent */ + + if (sign == 0) + exponent = exponent - 1; + + O = 0; /* clear overflow */ + fp_accum (&op[2], (OPSIZE) (fp_f + p)); /* acc = arg */ + + while (exponent-- > 0) { + O = O | fp_exec ((uint16) (0054 | p), /* square acc */ + ACCUM, NOP, NOP); + + if (i & SIGN) + O = O | fp_exec ((uint16) (0050 | p), /* acc = acc * arg */ + ACCUM, NOP, op[2]); + i = i << 1; + } + + op[2] = fp_accum (NULL, (OPSIZE) (fp_f + p)); /* get accum */ + + if (op[2].fpk[0] == 0) /* result zero? */ + O = 1; /* underflow */ + } + + if (entry == 014) /* .FPWR ? */ + op[0] = op[2]; /* copy result */ + else /* .TPWR */ + WriteOp (op[1].word, op[2], fp_t); /* write result */ + + break; + + + case 017: /* [tst] 105337 (OP_N) */ + XR = 4; /* firmware revision */ + SR = 0102077; /* test passed code */ + PC = (PC + 1) & VAMASK; /* P+2 return for firmware w/DPOLY */ + return reason; + + + default: /* others undefined */ + return stop_inst; + } + +AR = op[0].fpk[0]; /* save result */ +BR = op[0].fpk[1]; /* into A/B */ +return reason; +} + +#endif /* end of int64 support */ diff --git a/HP2100/hp2100_cpu5.c b/HP2100/hp2100_cpu5.c index 9865f47a..c8c64e20 100644 --- a/HP2100/hp2100_cpu5.c +++ b/HP2100/hp2100_cpu5.c @@ -1,1421 +1,1442 @@ -/* hp2100_cpu5.c: HP 1000 RTE-6/VM VMA and RTE-IV EMA instructions - - Copyright (c) 2007-2008, Holger Veit - Copyright (c) 2006-2012, J. David Bryan - - 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 - THE AUTHORS 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 the authors shall not be - used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from the authors. - - CPU5 RTE-6/VM and RTE-IV firmware option instructions - - 23-Mar-12 JDB Added sign extension for dim count in "cpu_ema_resolve" - 28-Dec-11 JDB Eliminated unused variable in "cpu_ema_vset" - 11-Sep-08 JDB Moved microcode function prototypes to hp2100_cpu1.h - 05-Sep-08 JDB Removed option-present tests (now in UIG dispatchers) - 30-Jul-08 JDB Redefined ABORT to pass address, moved def to hp2100_cpu.h - 26-Jun-08 JDB Rewrote device I/O to model backplane signals - 01-May-08 HV Fixed mapping bug in "cpu_ema_emap" - 21-Apr-08 JDB Added EMA support from Holger - 25-Nov-07 JDB Added TF fix from Holger - 07-Nov-07 HV VMACK diagnostic tests 1...32 passed - 19-Oct-07 JDB Corrected $LOC operand profile to OP_CCCACC - 03-Oct-07 HV Moved RTE-6/VM instrs from hp2100_cpu0.c - 26-Sep-06 JDB Created - - Primary references: - - HP 1000 M/E/F-Series Computers Technical Reference Handbook - (5955-0282, Mar-1980) - - HP 1000 M/E/F-Series Computers Engineering and Reference Documentation - (92851-90001, Mar-1981) - - Macro/1000 Reference Manual (92059-90001, Dec-1992) - - Additional references are listed with the associated firmware - implementations, as are the HP option model numbers pertaining to the - applicable CPUs. -*/ - -#include -#include "hp2100_defs.h" -#include "hp2100_cpu.h" -#include "hp2100_cpu1.h" - - -/* RTE-6/VM Virtual Memory Area Instructions - - RTE-6/VM (product number 92084A) introduced Virtual Memory Area (VMA) - instructions -- a superset of the RTE-IV EMA instructions. Different - microcode was supplied with the operating system that replaced the microcode - used with RTE-IV. Microcode was limited to the E/F-Series, and the M-Series - used software equivalents. - - Option implementation by CPU was as follows: - - 2114 2115 2116 2100 1000-M 1000-E 1000-F - ------ ------ ------ ------ ------ ------ ------ - N/A N/A N/A N/A N/A 92084A 92084A - - The routines are mapped to instruction codes as follows: - - Instr. 1000-E/F Description - ------ -------- ---------------------------------------------- - .PMAP 105240 Map VMA page into map register - $LOC 105241 Load on call - [test] 105242 [self test] - .SWP 105243 [Swap A and B registers] - .STAS 105244 [STA B; LDA SP] - .LDAS 105245 [LDA SP] - .MYAD 105246 [NOP in microcode] - .UMPY 105247 [Unsigned multiply and add] - - .IMAP 105250 Integer element resolve address and map - .IMAR 105251 Integer element resolve address - .JMAP 105252 Double integer element resolve address and map - .JMAR 105253 Double integer element resolve address - .LPXR 105254 Map pointer in P+1 plus offset in P+2 - .LPX 105255 Map pointer in A/B plus offset in P+1 - .LBPR 105256 Map pointer in P+1 - .LBP 105257 Map pointer in A/B registers - - Implementation notes: - - 1. The opcodes 105243-247 are undocumented and do not appear to be used in - any HP software. - - 2. The opcode list in the CE Handbook incorrectly shows 105246 as ".MYAD - - multiply 2 signed integers." The microcode listing shows that this - instruction was deleted, and the opcode is now a NOP. - - 3. RTE-IV EMA and RTE-6 VMA instructions shared the same address space, so a - given machine could run one or the other, but not both. - - Additional references: - - RTE-6/VM VMA/EMA Microcode Source (92084-18828, revision 3). - - RTE-6/VM Technical Specifications (92084-90015, Apr-1983). - - M/E/F-Series Computer Systems CE Handbook (5950-3767, Jul-1984). -*/ - -static const OP_PAT op_vma[16] = { - OP_N, OP_CCCACC, OP_N, OP_N, /* .PMAP $LOC [test] .SWAP */ - OP_N, OP_N, OP_N, OP_K, /* .STAS .LDAS .MYAD .UMPY */ - OP_A, OP_A, OP_A, OP_A, /* .IMAP .IMAR .JMAP .JMAR */ - OP_AA, OP_A, OP_A, OP_N /* .LPXR .LPX .LBPR .LBP */ - }; - -/* some addresses in page0 of RTE-6/VM */ -static const uint32 idx = 0001645; -static const uint32 xmata = 0001646; -static const uint32 xi = 0001647; -static const uint32 xeqt = 0001717; -static const uint32 vswp = 0001776; -static const uint32 umaps = 0003740; -static const uint32 page30 = 0074000; -static const uint32 page31 = 0076000; -static const uint32 ptemiss = 0176000; - -/* frequent constants in paging */ -#define SUITMASK 0176000 -#define NILPAGE 0176000 -#define PAGEIDX 0001777 -#define MSEGMASK 0076000 -#define RWPROT 0141777 - - -/* microcode version of resolve(): allows a much higher # of indirection levels. Used for - instance for LBP microcode diagnostics which will check > 100 levels. - */ -#define VMA_INDMAX 200 - -static t_stat vma_resolve (uint32 MA, uint32 *addr, t_bool debug) -{ -uint32 i; -uint32 faultma = MA; - -for (i = 0; (i < VMA_INDMAX) && (MA & I_IA); i++) { /* resolve multilevel */ - MA = ReadW (MA & VAMASK); /* follow address chain */ - } - -if (MA & I_IA) { - if (debug) - fprintf(sim_deb,">>CPU VMA: vma_resolve indirect loop addr=%06o\n",faultma); - return STOP_IND; /* indirect loop */ - } - -*addr = MA; -return SCPE_OK; -} - -/* $LOC - ASSEMBLER CALLING SEQUENCE: - - $MTHK NOP RETURN ADDRESS OF CALL (REDONE AFTER THIS ROUTINE) - JSB $LOC - .DTAB OCT LGPG# LOGICAL PAGE # AT WHICH THE NODE TO - * BE MAPPED IN BELONGS (0-31) - OCT RELPG RELATIVE PAGE OFFSET FROM BEGINING - * OF PARTITION OF WHERE THAT NODE RESIDES. - * (0 - 1023) - OCT RELBP RELATIVE PAGE OFFSET FROM BEGINING OF - * PARTITION OF WHERE BASE PAGE RESIDES - * (0 - 1023) - CNODE DEF .CNOD THIS IS THE ADDRESS OF CURRENT PATH # WORD - .ORD OCT XXXXX THIS NODE'S LEAF # (IE PATH #) - .NOD# OCT XXXXX THIS NODE'S ORDINAL # -*/ - -static t_stat cpu_vma_loc(OPS op,uint32 intrq,t_bool debug) -{ -uint32 eqt,mls,pnod,lstpg,fstpg,rotsz,lgpg,relpg,relbp,matloc,ptnpg,physpg,cnt,pgs,umapr; - -eqt = ReadIO(xeqt,UMAP); /* get ID segment */ -mls = ReadIO(eqt+33,SMAP); /* get word33 of alternate map */ -if ((mls & 0x8000) == 0) { /* this is not an MLS prog! */ - PC = err_PC; - if (debug) - fprintf(sim_deb,">>CPU VMA: cpu_vma_loc at P=%06o: not an MLS program\n", PC); - if (mp_control) MP_ABORT (eqt+33); /* allow an MP abort */ - return STOP_HALT; /* FATAL error! */ - } - -pnod = mls & 01777; /* get #pages of mem res nodes */ -if (pnod == 0) { /* no pages? FATAL! */ - PC = err_PC; - if (debug) - fprintf(sim_deb,">>CPU VMA: cpu_vma_loc at P=%06o: no mem resident pages\n", PC); - if (mp_control) MP_ABORT (eqt+33); /* allow an MP abort */ - return STOP_HALT; - } - -lstpg = (ReadIO(eqt+29,SMAP) >> 10) - 1; /* last page# of code */ -fstpg = ReadIO(eqt+23,SMAP) >> 10; /* index to 1st addr + mem nodes */ -rotsz = fstpg - (ReadIO(eqt+22,SMAP) >> 10); /* #pages in root */ -lgpg = op[0].word; - -/* lets do some consistency checks, CPU halt if they fail */ -if (lstpg < lgpg || lgpg < fstpg) { /* assert LSTPG >= LGPG# >= FSTPG */ - PC = err_PC; - if (debug) - fprintf(sim_deb, - ">>CPU VMA: $LOC at P=%06o: failed check LSTPG >= LGPG# >= FSTPG\n",PC); - if (mp_control) MP_ABORT (eqt+22); /* allow an MP abort */ - return STOP_HALT; - } - -relpg = op[1].word; -if (pnod < relpg || relpg < (rotsz+1)) { /* assert #PNOD >= RELPG >= ROTSZ+1 */ - PC = err_PC; - if (debug) - fprintf(sim_deb, - ">>CPU VMA: $LOC at %06o: failed check #PNOD >= RELPG >= ROTSZ+1\n",PC); - if (mp_control) MP_ABORT (eqt+22); /* allow an MP abort */ - return STOP_HALT; - } - -relbp = op[2].word; -if (relbp != 0) /* assert RELBP == 0 OR */ - if (pnod < relbp || relbp < (rotsz+1)) { /* #PNOD >= RELBP >= ROTSZ+1 */ - PC = err_PC; - if (debug) - fprintf(sim_deb, - ">>CPU VMA: $LOC at P=%06o: failed check: #PNOD >= RELBP >= ROTSZ+1\n",PC); - if (mp_control) MP_ABORT (eqt+22); /* allow an MP abort */ - return STOP_HALT; - } - -cnt = lstpg - lgpg + 1; /* #pages to map */ -pgs = pnod - relpg + 1; /* #pages from start node to end of code */ -if (pgs < cnt) cnt = pgs; /* ensure minimum, so not to map into EMA */ - -matloc = ReadIO(xmata,UMAP); /* get MAT $LOC address */ -ptnpg = ReadIO(matloc+3,SMAP) & 01777; /* index to start phys pg */ -physpg = ptnpg + relpg; /* phys pg # of node */ -umapr = 32 + lgpg; /* map register to start */ - -/* do an XMS with AR=umapr,BR=physpg,XR=cnt */ -if (debug) - fprintf(sim_deb, - ">>CPU VMA: $LOC map %d pgs from phys=%06o to mapr=%d\n", - cnt,physpg,umapr); -while (cnt != 0) { - dms_wmap (umapr, physpg); /* map pages of new overlay segment */ - cnt = (cnt - 1) & DMASK; - umapr = (umapr + 1) & DMASK; - physpg = (physpg + 1) & DMASK; - } - -dms_wmap(32,relbp+ptnpg); /* map base page again */ -WriteW(op[3].word,op[4].word); /* path# we are going to */ - -PC = (PC - 8) & DMASK; /* adjust PC to return address */ - /* word before the $LOC microinstr. */ -PC = (ReadW(PC) - 1) & DMASK; /* but the call has to be rerun, */ - /* so must skip back to the original call */ - /* which will now lead to the real routine */ -if (debug) - fprintf(sim_deb,">>CPU VMA: $LOC done: path#=%06o, P=%06o\n",op[4].word,PC); -return SCPE_OK; -} - -/* map pte into last page - return FALSE if page fault, nil flag in PTE or suit mismatch - return TRUE if suit match, physpg = physical page - or page=0 -> last+1 page -*/ -static t_bool cpu_vma_ptevl(uint32 pagid,uint32* physpg) -{ -uint32 suit; -uint32 pteidx = pagid & 0001777; /* build index */ -uint32 reqst = pagid & SUITMASK; /* required suit */ -uint32 pteval = ReadW(page31 | pteidx); /* get PTE entry */ -*physpg = pteval & 0001777; /* store physical page number */ -suit = pteval & SUITMASK; /* suit number seen */ -if (pteval == NILPAGE) return FALSE; /* NIL value in PTE */ -return suit == reqst || !*physpg; /* good page or last+1 */ -} - -/* handle page fault */ -static t_stat cpu_vma_fault(uint32 x,uint32 y,int32 mapr, - uint32 ptepg,uint32 ptr,uint32 faultpc, t_bool debug) -{ -uint32 pre = ReadIO(xi,UMAP); /* get program preamble */ -uint32 ema = ReadIO(pre+2,UMAP); /* get address of $EMA$/$VMA$ */ -WriteIO(ema,faultpc,UMAP); /* write addr of fault instr */ -XR = x; /* X = faulting page */ -YR = y; /* Y = faulting address for page */ - -if (mapr>0) - dms_wmap(mapr+UMAP,ptepg); /* map PTE into specified user dmsmap */ - -/* do a safety check: first instr of $EMA$/$VMA$ must be a DST instr */ -if (ReadIO(ema+1,UMAP) != 0104400) { - if (debug) - fprintf(sim_deb, ">>CPU VMA: pg fault: no EMA/VMA user code present\n"); - if (mp_control) MP_ABORT (ema+1); /* allow an MP abort */ - return STOP_HALT; /* FATAL: no EMA/VMA! */ - } - -PC = (ema+1) & VAMASK; /* restart $EMA$ user code, */ - /* will return to fault instruction */ - -AR = (ptr >> 16) & DMASK; /* restore A, B */ -BR = ptr & DMASK; -E = 0; /* enforce E = 0 */ -if (debug) - fprintf(sim_deb, - ">>CPU VMA: Call pg fault OS exit, AR=%06o BR=%06o P=%06o\n", - AR, BR, PC); -return SCPE_OK; -} - -/* map in PTE into last page, return false, if page fault */ -static t_bool cpu_vma_mapte(uint32* ptepg) -{ -uint32 idext,idext2; -uint32 dispatch = ReadIO(vswp,UMAP) & 01777; /* get fresh dispatch flag */ -t_bool swapflag = TRUE; - -if (dispatch == 0) { /* not yet set */ - idext = ReadIO(idx,UMAP); /* go into IDsegment extent */ - if (idext != 0) { /* is ema/vma program? */ - dispatch = ReadWA(idext+1) & 01777; /* get 1st ema page: new vswp */ - WriteIO(vswp,dispatch,UMAP); /* move into $VSWP */ - idext2 = ReadWA(idext+2); /* get swap bit */ - swapflag = (idext2 & 020000) != 0; /* bit 13 = swap bit */ - } - } - -if (dispatch) { /* some page is defined */ - dms_wmap(31 + UMAP,dispatch); /* map $VSWP to register 31 */ - *ptepg = dispatch; /* return PTEPG# for later */ - } - -return swapflag; /* true for swap bit set */ -} - -/* .LBP - ASSEMBLER CALLING SEQUENCE: - - DLD PONTR TRANSLATE 32 BIT POINTER TO 15 - JSB .LBP BIT POINTER. - - - 32 bit pointer: - ----------AR------------ -----BR----- - 15 14....10 9....4 3...0 15.10 9....0 - L<----------------------------------- L=1 local reference bit - XXXXXXXX<------------------------- 5 bit unused - PPPPPP PPPPP PPPPP<------ 16 bit PAGEID - SSSSSS<------------------ SUIT# within PAGEID - PPPPP PPPPP<------ 10 bit PAGEID index into PTE - OOOOOO 10 bit OFFSET -*/ - -static t_stat cpu_vma_lbp(uint32 ptr,uint32 aoffset,uint32 faultpc,uint32 intrq,t_bool debug) -{ -uint32 pagid,offset,ptrl,pgidx,ptepg; -uint16 p30,p31,suit; -t_stat reason = SCPE_OK; -uint32 faultab = ptr; /* remember A,B for page fault */ -ptr += aoffset; /* add the offset e.g. for .LPX */ - -if (debug) - fprintf(sim_deb,">>CPU VMA: cpu_vma_lbp: ptr=%o/%o\n", - (ptr>>16) & DMASK,ptr & DMASK); - -O = 0; /* clear overflow */ -if (ptr & 0x80000000) { /* is it a local reference? */ - ptrl = ptr & VAMASK; - if ((ptr&I_IA) && (reason = vma_resolve (ReadW (ptrl), &ptrl, debug))) - return reason; /* yes, resolve indirect ref */ - BR = ptrl & VAMASK; /* address is local */ - AR = (ptr >> 16) & DMASK; - if (debug) - fprintf(sim_deb,">>CPU VMA: cpu_vma_lbp: local ref AR=%06o BR=%06o\n",AR,BR); - return SCPE_OK; - } - -pagid = (ptr >> 10) & DMASK; /* extract page id (16 bit idx, incl suit*/ -offset = ptr & 01777; /* and offset */ -suit = pagid & SUITMASK; /* suit of page */ -pgidx = pagid & PAGEIDX; /* index into PTE */ - -if (!cpu_vma_mapte(&ptepg)) /* map in PTE */ - return cpu_vma_fault(65535,ptemiss,-1,ptepg,faultab,faultpc, debug); /* oops, must init PTE */ - -/* ok, we have the PTE mapped to page31 */ -/* the microcode tries to reads two consecutive data pages into page30 and page31 */ - -/* read the 1st page value from PTE */ -p30 = ReadW(page31 | pgidx) ^ suit; -if (!p30) /* matched suit for 1st page */ - return cpu_vma_fault(pagid,page30,30,ptepg,faultab,faultpc,debug); - -/* suit switch situation: 1st page is in last idx of PTE, then following page - * must be in idx 0 of PTE */ -if (pgidx==01777) { /* suit switch situation */ - pgidx = 0; /* select correct idx 0 */ - suit = pagid+1; /* suit needs increment */ - if (suit==0) { /* is it page 65536? */ - offset += 02000; /* adjust to 2nd page */ - suit = NILPAGE; - pgidx = 01777; - } -} else - pgidx++; /* select next page */ - -p31 = ReadW(page31 | pgidx) ^ suit; -if (!p31) { /* matched suit for 2nd page */ - dms_wmap(31+UMAP,p30); - if (p30 & SUITMASK) - return cpu_vma_fault(pagid,page30,30,ptepg,faultab,faultpc,debug); - if (!(p31 ^ NILPAGE)) /* suit is 63: fault */ - return cpu_vma_fault(pagid+1,page31,31,ptepg,faultab,faultpc,debug); - - offset += 02000; /* adjust offset to last user map because */ - /* the address requested page 76xxx */ - } -else { - dms_wmap(30+UMAP,p30); - if (p30 & SUITMASK) - return cpu_vma_fault(pagid,page30,30,ptepg,faultab,faultpc,debug); - dms_wmap(31+UMAP,p31); - if (p31 & SUITMASK) - return cpu_vma_fault(pagid+1,page31,31,ptepg,faultab,faultpc,debug); - } - -AR = pagid; /* return pagid in A */ -BR = page30+offset; /* mapped address in B */ -if (debug) - fprintf(sim_deb,">>CPU VMA: cpu_vma_lbp: map done AR=%06o BR=%o6o\n",AR,BR); -return SCPE_OK; -} - -/* .PMAP - ASSEMBLER CALLING SEQUENCE: - - LDA UMAPR (MSEG - 31) - LDB PAGID (0-65535) - JSB .PMAP GO MAP IT IN - A-REG = REASON, NOTE 1 - > SEE NOTE 2> - - NOTE 1 : IF BIT 15 OF A-REG SET, THEN ALL NORMAL BRANCHES TO THE - $EMA$/$VMA$ CODE WILL BE CHANGED TO P+1 EXIT. THE A-REG - WILL BE THE REASON THE MAPPING WAS NOT SUCCESSFUL IF BIT 15 - OF THE A-REG WAS NOT SET. - THIS WAS DONE SO THAT A ROUTINE ($VMA$) CAN DO A MAPPING - WITHOUT THE POSSIBILITY OF BEING RE-CURRED. IT IS USED - BY $VMA$ AND PSTVM IN THE PRIVLEDGED MODE. - NOTE 2: E-REG WILL = 1 IF THE LAST+1 PAGE IS REQUESTED AND - MAPPED READ/WRITE PROTECTED ON A GOOD P+2 RETURN. -*/ -static t_stat cpu_vma_pmap(uint32 umapr,uint32 pagid, t_bool debug) -{ -uint32 physpg, ptr, pgpte; -uint32 mapnm = umapr & 0x7fff; /* strip off bit 15 */ - -if (debug) - fprintf(sim_deb, ">>CPU VMA: .PMAP AR=%06o(umapr) BR=%06o(pagid)\n",umapr,pagid); - -if (mapnm > 31) { /* check for invalid map register */ - AR = 80; /* error: corrupt EMA/VMA system */ - if (debug) - fprintf(sim_deb, ">>CPU VMA: .PMAP invalid mapr: AR=80, exit P+1\n"); - return SCPE_OK; /* return exit PC+1 */ - } - -ptr = (umapr << 16) | (pagid & DMASK); /* build the ptr argument for vma_fault */ -if (!cpu_vma_mapte(&pgpte)) { /* map the PTE */ - if (umapr & 0x8000) { - XR = 65535; - YR = ptemiss; - if (debug) - fprintf(sim_deb, - ">>CPU VMA: .PMAP pg fault&bit15: XR=%06o YR=%06o, exit P+1\n", - XR, YR); - return SCPE_OK; /* use PC+1 error exit */ - } - return cpu_vma_fault(65535,ptemiss,-1,pgpte,ptr,PC-1,debug); /* oops: fix PTE */ - } - -/* PTE is successfully mapped to page31 and dmsmap[63] */ -if (!cpu_vma_ptevl(pagid,&physpg)) { - if (umapr & 0x8000) { - XR = pagid; - YR = page31; - if (debug) - fprintf(sim_deb, - ">>CPU VMA: .PMAP pg map&bit15: XR=%06o YR=%06o, exit P+1\n", - XR, YR); - return SCPE_OK; /* use PC+1 error exit*/ - } - return cpu_vma_fault(pagid,page31,31,pgpte,ptr,PC-1,debug); /* page not present */ - } - -E = 1; -if (physpg == 0) /* last+1 page ? */ - physpg = RWPROT; /* yes, use page 1023 RW/Protected */ -else E = 0; /* normal page to map */ - -dms_wmap(mapnm+UMAP,physpg); /* map page to user page reg */ -if (mapnm != 31) /* unless already unmapped, */ - dms_wmap(31+UMAP,RWPROT); /* unmap PTE */ - -AR = (umapr + 1) & DMASK; /* increment mapr for next call */ -BR = (pagid + 1) & DMASK; /* increment pagid for next call */ -O = 0; /* clear overflow */ -PC = (PC + 1) & VAMASK; /* normal PC+2 return */ -if (debug) - fprintf(sim_deb,">>CPU VMA: .PMAP map done: AR=%06o BR=%o6o exit P+2\n",AR,BR); -return SCPE_OK; -} - -/* array calc helper for .imar, .jmar, .imap, .jmap - ij=in_s: 16 bit descriptors - ij=in_d: 32 bit descriptors - - This helper expects mainly the following arguments: - dtbl: pointer to an array descriptor table - atbl: pointer to the table of actual subscripts - - where subscript table is the following: - atbl-> DEF last_subscript,I (point to single or double integer) - ... - DEF first subscript,I (point to single or double integer) - - where Descriptor_table is the following table: - dtbl-> DEC #dimensions - DEC/DIN next-to-last dimension (single or double integer) - ... - DEC/DIN first dimension (single or double integer) - DEC elementsize in words - DEC high,low offset from start of EMA to element(0,0...0) - - Note that subscripts are counting from 0 -*/ -static t_stat cpu_vma_ijmar(OPSIZE ij,uint32 dtbl,uint32 atbl,uint32* dimret, - uint32 intrq,t_bool debug) -{ -t_stat reason = SCPE_OK; -uint32 ndim,MA,i,ws; -int32 accu,ax,dx; -OP din; -int opsz = ij==in_d ? 2 : 1; - -ndim = ReadW(dtbl++); /* get #dimensions itself */ -if (debug) { - fprintf(sim_deb, ">>CPU VMA array calc #dim=%d, size=%d\n",ndim,opsz); - fprintf(sim_deb, ">>CPU VMA: array actual subscripts ("); - for (i=0; i0) fputc(',',sim_deb); - fprintf(sim_deb,"%d",ij==in_d?INT32(din.dword) : INT16(din.word)); - } - - fprintf(sim_deb,")\n>>CPU VMA: array descriptor table ("); - if (ndim) { - for (i=0; i0) fputc(',',sim_deb); - fprintf(sim_deb,"%d",ij==in_d?INT32(din.dword) : INT16(din.word)); - } - i = dtbl+1+(ndim-1)*opsz; - ws = ReadW(i-1); - } - else { - i = dtbl; - ws = 1; - } - fprintf(sim_deb,")\n>>CPU VMA: array elemsz=%d base=%o/%o\n", - ws,ReadW(i),ReadW(i+1)); - } - -if (dimret) *dimret = ndim; /* return dimensions */ -if (ndim == 0) { /* no dimensions: */ - AR = ReadW(dtbl++); /* return the array base itself */ - BR = ReadW(dtbl); - if (debug) - fprintf(sim_deb,">>CPU VMA: #dim=0, AR=%06o, BR=%06o\n",AR,BR); - return SCPE_OK; - } - -/* calculate - * (...(An*Dn-1)+An-1)*Dn-2)+An-2....)+A2)*D1)+A1)*#words + Array base - * Depending on ij, Ax and Dx can be 16 or 32 bit - */ -accu = 0; -while (ndim-- > 0) { - MA = ReadW(atbl++); /* get addr of subscript */ - if ((reason = resolve (MA, &MA, intrq))) /* and resolve it */ - return reason; - din = ReadOp(MA,ij); /* get actual subscript value */ - ax = ij==in_d ? INT32(din.dword) : INT16(din.word); - accu += ax; /* add to accu */ - - if (ndim==0) ij = in_s; /* #words is single */ - din = ReadOp(dtbl,ij); /* get dimension from descriptor table */ - if (ij==in_d) { - dx = INT32(din.dword); /* either get double or single dimension */ - dtbl += 2; - } else { - dx = INT16(din.word); - dtbl++; - } - accu *= dx; /* multiply */ - } - -din = ReadOp(dtbl,in_d); /* add base address */ -accu += din.dword; - -AR = (accu >> 16) & DMASK; /* transfer to AB */ -BR = accu & DMASK; -if (debug) - fprintf(sim_deb,">>CPU VMA: resulting virt addr=%o (AR=%06o, BR=%06o)\n",accu,AR,BR); -return reason; -} - -/* - * This is the main handler for the RTE6/VMA microcodes */ -t_stat cpu_rte_vma (uint32 IR, uint32 intrq) -{ -t_stat reason = SCPE_OK; -OPS op; -OP_PAT pattern; -uint32 entry,t32,ndim; -uint32 dtbl,atbl; /* descriptor table ptr, actual args ptr */ -OP dop0,dop1; -uint32 pcsave = (PC+1) & VAMASK; /* save PC to check for redo in imap/jmap */ -t_bool debug = DEBUG_PRI (cpu_dev, DEB_VMA); - -entry = IR & 017; /* mask to entry point */ -pattern = op_vma[entry]; /* get operand pattern */ - -if (pattern != OP_N) - if (reason = cpu_ops (pattern, op, intrq)) /* get instruction operands */ - return reason; - -if (debug) { /* debugging? */ - fprintf (sim_deb, ">>CPU VMA: IR = %06o (", IR); /* print preamble and IR */ - fprint_sym (sim_deb, err_PC, (t_value *) &IR, /* print instruction mnemonic */ - NULL, SWMASK('M')); - fprintf (sim_deb, "), P = %06o, XEQT = %06o", /* print location and program ID */ - err_PC, ReadW (xeqt)); - - fprint_ops (pattern, op); /* print operands */ - fputc ('\n', sim_deb); /* terminate line */ - } - -switch (entry) { /* decode IR<3:0> */ - - case 000: /* .PMAP 105240 (OP_N) */ - reason = cpu_vma_pmap(AR,BR,debug); /* map pages */ - break; - - case 001: /* $LOC 105241 (OP_CCCACC) */ - reason = cpu_vma_loc(op,intrq,debug); /* handle the coroutine switch */ - break; - - case 002: /* [test] 105242 (OP_N) */ - XR = 3; /* refer to src code 92084-18828 rev 3 */ - SR = 0102077; /* HLT 77 instruction */ - YR = 1; /* ROMs correctly installed */ - PC = (PC+1) & VAMASK; /* skip instr if VMA/EMA ROM installed */ - break; - - case 003: /* [swap] 105243 (OP_N) */ - t32 = AR; /* swap A and B registers */ - AR = BR; - BR = t32; - break; - - case 004: /* [---] 105244 (OP_N) */ - reason = stop_inst; /* fragment of dead code */ - break; /* in microrom */ - - case 005: /* [---] 105245 (OP_N) */ - reason = stop_inst; /* fragment of dead code */ - break; /* in microrom */ - - case 006: /* [nop] 105246 (OP_N) */ - break; /* do nothing */ - - case 007: /* [umpy] 105247 (OP_K) */ - t32 = AR * op[0].word; /* get multiplier */ - t32 += BR; /* add B */ - AR = (t32 >> 16) & DMASK; /* move result back to AB */ - BR = t32 & DMASK; - O = 0; /* instr clears OV */ - break; - - case 010: /* .IMAP 105250 (OP_A) */ - dtbl = op[0].word; - atbl = PC; - if ((reason = cpu_vma_ijmar(in_s,dtbl,atbl,&ndim,intrq,debug))) /* calc the virt address to AB */ - return reason; - t32 = (AR << 16) | (BR & DMASK); - if ((reason = cpu_vma_lbp(t32,0,PC-2,intrq,debug))) - return reason; - if (PC==pcsave) - PC = (PC+ndim) & VAMASK; /* adjust PC: skip ndim subscript words */ - break; - - case 011: /* .IMAR 105251 (OP_A) */ - dtbl = ReadW(op[0].word); - atbl = (op[0].word+1) & VAMASK; - reason = cpu_vma_ijmar(in_s,dtbl,atbl,0,intrq,debug); /* calc the virt address to AB */ - break; - - case 012: /* .JMAP 105252 (OP_A) */ - dtbl = op[0].word; - atbl = PC; - if ((reason = cpu_vma_ijmar(in_d,dtbl,atbl,&ndim,intrq,debug))) /* calc the virtual address to AB */ - return reason; - t32 = (AR << 16) | (BR & DMASK); - if ((reason = cpu_vma_lbp(t32,0,PC-2,intrq,debug))) - return reason; - if (PC==pcsave) - PC = (PC + ndim) & VAMASK; /* adjust PC: skip ndim subscript dword ptr */ - break; - - case 013: /* .JMAR 105253 (OP_A) */ - dtbl = ReadW(op[0].word); - atbl = (op[0].word+1) & VAMASK; - reason = cpu_vma_ijmar(in_d,dtbl,atbl,0,intrq,debug); /* calc the virt address to AB */ - break; - - case 014: /* .LPXR 105254 (OP_AA) */ - dop0 = ReadOp(op[0].word,in_d); /* get pointer from arg */ - dop1 = ReadOp(op[1].word,in_d); - t32 = dop0.dword + dop1.dword; /* add offset to it */ - reason = cpu_vma_lbp(t32,0,PC-3,intrq,debug); - break; - - case 015: /* .LPX 105255 (OP_A) */ - t32 = (AR << 16) | (BR & DMASK); /* pointer in AB */ - dop0 = ReadOp(op[0].word,in_d); - reason = cpu_vma_lbp(t32,dop0.dword,PC-2,intrq,debug); - break; - - case 016: /* .LBPR 105256 (OP_A) */ - dop0 = ReadOp(op[0].word,in_d); /* get the pointer */ - reason = cpu_vma_lbp(dop0.dword,0,PC-2,intrq,debug); - break; - - case 017: /* .LBP 105257 (OP_N) */ - t32 = (AR << 16) | (BR & DMASK); - reason = cpu_vma_lbp(t32,0,PC-1,intrq,debug); - break; - } - -return reason; -} - - -/* RTE-IV Extended Memory Area Instructions - - The RTE-IV operating system (HP product number 92067A) introduced the - Extended Memory Area (EMA) instructions. EMA provided a mappable data area - up to one megaword in size. These three instructions accelerated data - accesses to variables stored in EMA partitions. Support was limited to - E/F-Series machines; M-Series machines used software equivalents. - - Option implementation by CPU was as follows: - - 2114 2115 2116 2100 1000-M 1000-E 1000-F - ------ ------ ------ ------ ------ ------ ------ - N/A N/A N/A N/A N/A 92067A 92067A - - The routines are mapped to instruction codes as follows: - - Instr. 1000-E/F Description - ------ -------- ---------------------------------------------- - .EMIO 105240 EMA I/O - MMAP 105241 Map physical to logical memory - [test] 105242 [self test] - .EMAP 105257 Resolve array element address - - Notes: - - 1. RTE-IV EMA and RTE-6 VMA instructions share the same address space, so a - given machine can run one or the other, but not both. - - 2. The EMA diagnostic (92067-16013) reports bogus MMAP failures if it is - not loaded at the start of its partition (e.g., because of a LOADR "LO" - command). The "ICMPS" map comparison check in the diagnostic assumes - that the starting page of the program's partition contains the first - instruction of the program and prints "MMAP ERROR" if it does not. - - Additional references: - - RTE-IVB Programmer's Reference Manual (92068-90004, Dec-1983). - - RTE-IVB Technical Specifications (92068-90013, Jan-1980). -*/ - -static const OP_PAT op_ema[16] = { - OP_AKA, OP_AKK, OP_N, OP_N, /* .EMIO MMAP [test] --- */ - OP_N, OP_N, OP_N, OP_N, /* --- --- --- --- */ - OP_N, OP_N, OP_N, OP_N, /* --- --- --- --- */ - OP_N, OP_N, OP_N, OP_AAA /* --- --- --- .EMAP */ - }; - -/* calculate the 32 bit EMA subscript for an array */ -static t_bool cpu_ema_resolve(uint32 dtbl,uint32 atbl,uint32* sum) -{ -int32 sub, act, low, sz, ndim; -uint32 MA, base; - -ndim = ReadW(dtbl++); /* # dimensions */ -ndim = SEXT(ndim); /* sign extend */ -if (ndim < 0) return FALSE; /* invalid? */ - -*sum = 0; /* accu for index calc */ -while (ndim > 0) { - MA = ReadW(atbl++); /* get address of A(N) */ - resolve (MA, &MA, 0); - act = ReadW(MA); /* A(N) */ - low = ReadW(dtbl++); /* -L(N) */ - sub = SEXT(act) + SEXT(low); /* subscript */ - if (sub & 0xffff8000) return FALSE; /* overflow? */ - *sum += sub; /* accumulate */ - sz = ReadW(dtbl++); - sz = SEXT(sz); - if (sz < 0) return FALSE; - *sum *= sz; - if (*sum > (512*1024)) return FALSE; /* overflow? */ - ndim--; -} -base = (ReadW(dtbl+1)<<16) | (ReadW(dtbl) & 0xffff); /* base of array in EMA */ -if (base & 0x8000000) return FALSE; -*sum += base; /* calculate address into EMA */ -if (*sum & 0xf8000000) return FALSE; /* overflow? */ -return TRUE; -} - -/* implementation of VIS RTE-IVB EMA support - * .ERES microcode routine, resolves only EMA addresses - * Call: - * .OCT 101474B - * DEF RTN error return (rtn), good return is rtn+1 - * DEF DUMMY dummy argument for compatibility with .EMAP - * DEF TABLE[,I] array declaration (dtbl) - * DEF A(N)[,I] actual subscripts (atbl) - * DEF A(N-1)[,I] - * ... - * DEF A(2)[,I] - * DEF A(1)[,I] - * RTN EQU * error return A="20", B="EM" - * RTN+1 EQU *+1 good return B=logical address - * - * TABLE DEC # # dimensions - * DEC -L(N) - * DEC D(N-1) - * DEC -L(N-1) lower bound (n-1)st dim - * DEC D(N-2) (n-2)st dim - * ... - * DEC D(1) 1st dim - * DEC -L(1) lower bound 1st dim - * DEC # # words/element - * OFFSET 1 EMA Low - * OFFSET 2 EMA High - */ -t_stat cpu_ema_eres(uint32 *rtn,uint32 dtbl,uint32 atbl,t_bool debug) -{ -uint32 sum; -if (cpu_ema_resolve(dtbl,atbl,&sum)) { /* calculate subscript */ - AR = sum & 0xffff; - BR = sum >> 16; - if (!(BR & SIGN)) { /* no overflow? */ - (*rtn)++; /* return via good exit */ - return SCPE_OK; - } -} -AR = 0x3230; /* error condition: */ -BR = 0x454d; /* AR = '20', BR = 'EM' */ -return SCPE_OK; /* return via unmodified rtn */ -} - -/* implementation of VIS RTE-IVB EMA support - * .ESEG microcode routine - * Call: - * LDA FIRST first map to set - * LDB N # of maps to set - * .OCT 101475B/105475B - * DEF RTN ptr to return - * DEF TABLE map table - * RTN EQU * error return A="21", B="EM" - * RTN+1 EQU *+1 good return B=logical address - * - * load maps FIRST to FIRST+N from TABLE, with FIRST = FIRST + LOG_START MSEG - * update map table in base page. Set LOG_START MSEG=0 if opcode==105475 - */ -t_stat cpu_ema_eseg(uint32* rtn, uint32 IR, uint32 tbl, t_bool debug) -{ -uint32 xidex,eqt,idext0,idext1; -uint32 msegsz,phys,msegn,last,emasz,pg0,pg1,pg,i,lp; - -if ((BR & SIGN) || BR==0) goto em21; /* #maps not positive? */ -xidex = ReadIO(idx,UMAP); /* read ID extension */ -if (xidex==0) goto em21; -idext0 = ReadWA(xidex+0); /* get 1st word idext */ -msegsz = idext0 & 037; /* S7 MSEG size */ -WriteIO(xidex+0, idext0 | 0100000, SMAP); /* enforce nonstd MSEG */ -idext1 = ReadWA(xidex+1); /* get 2nd word idext */ -phys = idext1 & 01777; /* S5 phys start of EMA */ -msegn = (idext1 >> 11) & 037; /* S9 get logical start MSEG# */ -if (IR & 04000) { /* opcode == 105475? (.VPRG) */ - msegn = 0; /* log start = 0 */ - msegsz = 32; /* size = full range */ -} -last = AR-1 + BR; /* last page */ -if (last > msegsz) goto em21; /* too many? error */ -eqt = ReadIO(xeqt,UMAP); -emasz = (ReadWA(eqt+28) & 01777) - 1; /* S6 EMA size in pages */ - -/* locations 1740...1777 of user base page contain the map entries we need. - * They are normally hidden by BP fence, therefore they have to be accessed by - * another fence-less map register. uCode uses #1 temporarily */ -pg0 = dms_rmap(UMAP+0); /* read map #0 */ -pg1 = dms_rmap(UMAP+1); /* save map #1 */ -dms_wmap(UMAP+1,pg0); /* copy #0 into reg #1 */ -lp = AR + msegn; /* first */ -for (i=0; i emasz) pg |= 0140000; /* write protect if outside */ - pg += phys; /* adjust into EMA page range */ - WriteIO(umaps+lp+i, pg, UMAP); /* copy pg to user map */ -/* printf("MAP val %oB to reg %d (addr=%oB)\n",pg,lp+i,umaps+lp+i); */ - dms_wmap(UMAP+lp+i, pg); /* set DMS reg */ -} -dms_wmap(UMAP+1,pg1); /* restore map #1 */ -O = 0; /* clear overflow */ -(*rtn)++; /* return via good exit */ -return SCPE_OK; - -em21: -AR = 0x3231; /* error condition: */ -BR = 0x454d; /* AR = '21', BR = 'EM' */ -return SCPE_OK; /* return via unmodified rtn */ -} - -/* implementation of VIS RTE-IVB EMA support - * .VSET microcode routine - * Call: - * .OCT 101476B - * DEF RTN return address - * DEF VIN input vector - * DEF VOUT output vector - * DEF MAPS - * OCT #SCALARS - * OCT #VECTORS - * OCT K 1024/(#words/element) - * RTN EQU * error return (B,A) = "VI22" - * RTN+1 EQU *+1 hard return, A = K/IMAX - * RTN+2 EQU *+2 easy return, A = 0, B = 2* #VCTRS - */ -t_stat cpu_ema_vset(uint32* rtn, OPS op, t_bool debug) -{ -uint32 vin = op[0].word; /* S1 */ -uint32 vout = op[1].word; /* S2 */ -uint32 maps = op[2].word; /* S3 */ -uint32 scalars = op[3].word; /* S4 */ -uint32 vectors = op[4].word; /* S5 */ -uint32 k = op[5].word; /* S6 */ -uint32 imax = 0; /* imax S11*/ -uint32 xidex, idext1, mseg, addr, i, MA; -t_bool negflag = FALSE; - -for (i=0; i> 1) & MSEGMASK; /* S9 get logical start MSEG */ - -for (i=0; i> 10) & 0xffff; /* get page */ - WriteW(maps++, addr); /* save page# */ - WriteW(maps++, addr+1); /* save next page# as well */ - MA = ReadW(vin++); /* get index into Y */ - resolve(MA, &MA, 0); - YR = ReadW(MA); /* get index value */ - WriteW(vout++, MA); /* copy address of index */ - if (YR & SIGN) { /* index is negative */ - negflag = TRUE; /* mark a negative index (HARD) */ - YR = (~YR + 1) & DMASK; /* make index positive */ - } - if (imax < YR) imax = YR; /* set maximum index */ - mseg += 04000; /* incr mseg address by 2 more pages */ -} -MA = ReadW(vin); /* get N index into Y */ -resolve(MA, &MA, 0); -YR = ReadW(MA); -WriteW(vout++, MA); vin++; /* copy address of N */ - -if (imax==0) goto easy; /* easy case */ -AR = k / imax; AR++; /* calculate K/IMAX */ -if (negflag) goto hard; /* had a negative index? */ -if (YR > AR) goto hard; - -easy: -(*rtn)++; /* return via exit 2 */ -AR = 0; - -hard: -(*rtn)++; /* return via exit 1 */ -BR = 2 * op[4].word; /* B = 2* vectors */ -return SCPE_OK; - -vi22: /* error condition */ - AR=0x3232; /* AR = '22' */ - BR=0x5649; /* BR = 'VI' */ - return SCPE_OK; /* return via unmodified e->rtn */ -} - -typedef struct ema4 { - uint32 mseg; /* logical start of MSEG */ - uint32 msegsz; /* size of std mseg in pgs */ - uint32 pgoff; /* pg # in EMA containing element */ - uint32 offs; /* offset into page of element */ - uint32 msoff; /* total offset to element in MSEG */ - uint32 emasz; /* size of ema in pgs */ - uint32 msegno; /* # of std mseg */ - uint32 ipgs; /* # of pgs to start of MSEG */ - uint32 npgs; /* # of pgs needed */ - uint32 spmseg; /* first phys pg of MSEG */ -} EMA4; - -static t_bool cpu_ema_emas(uint32 dtbl,uint32 atbl,EMA4* e) -{ -uint32 xidex, eqt; -uint32 sum, msegsz,pgoff,offs,emasz,msegno,msoff,ipgs; - -if (!cpu_ema_resolve(dtbl,atbl,&sum)) return FALSE; /* calculate 32 bit index */ - -xidex = ReadIO(idx,UMAP); /* read ID extension */ -msegsz = ReadWA(xidex+0) & 037; /* S5 # pgs for std MSEG */ -pgoff = sum >> 10; /* S2 page containing element */ -offs = sum & 01777; /* S6 offset in page to element */ -if (pgoff > 1023) return FALSE; /* overflow? */ -eqt = ReadIO(xeqt,UMAP); -emasz = ReadWA(eqt+28) & 01777; /* S EMA size in pages */ -if (pgoff > emasz) return FALSE; /* outside EMA? */ -msegno = pgoff / msegsz; /* S4 # of MSEG */ -msoff = pgoff % msegsz; /* offset within MSEG in pgs */ -ipgs = pgoff - msoff; /* S7 # pgs to start of MSEG */ -msoff = msoff << 10; /* offset within MSEG in words */ -msoff += offs; /* S1 offset to element in words */ - -e->msegsz = msegsz; /* return calculated data */ -e->pgoff = pgoff; -e->offs = offs; -e->emasz = emasz; -e->msegno = msegno; -e->ipgs = ipgs; -e->msoff = msoff; -return TRUE; -} - -static t_bool cpu_ema_mmap01(EMA4* e) -{ -uint32 xidex,idext0, pg, pg0, pg1, i; - -uint32 base = e->mseg >> 10; /* get the # of first MSEG DMS reg */ -xidex = ReadIO(idx,UMAP); /* get ID extension */ -idext0 = ReadWA(xidex+1); - -if (e->npgs==0) return FALSE; /* no pages to map? */ -if ((e->npgs+1+e->ipgs) <= e->emasz) e->npgs++; /* actually map npgs+1 pgs */ - -/* locations 1740...1777 of user base page contain the map entries we need. - * They are normally hidden by BP fence, therefore they have to be accessed by - * another fence-less map register. uCode uses #1, macro code uses $DVCT (==2) - */ -pg0 = dms_rmap(UMAP+0); /* read base page map# */ -pg1 = dms_rmap(UMAP+1); /* save map# 1 */ -dms_wmap(UMAP+1,pg0); /* map #0 into reg #1 */ -for (i=0; (base+i)<32; i++) { - pg = inpgs ? e->spmseg : 0140000; /* write protect if outside */ - WriteIO(umaps+base+i, pg, UMAP); /* copy pg to user map */ -/* printf("MAP val %d to reg %d (addr=%o)\n",pg,base+i,umaps+base+i); */ - dms_wmap(UMAP+base+i, pg); /* set DMS reg */ - e->spmseg++; -} -dms_wmap(UMAP+1,pg1); /* restore map #1 */ - -xidex = ReadIO(idx,UMAP); /* get ID extension */ -idext0 = ReadWA(xidex+0); -if (e->msegno == 0xffff) /* non std mseg */ - idext0 |= 0x8000; /* set nonstd marker */ -else - idext0 = (idext0 & 037) | (e->msegno<<5); /* set new current mseg# */ -WriteIO(xidex, idext0, SMAP); /* save back value */ -AR = 0; /* was successful */ -return TRUE; -} - -static t_bool cpu_ema_mmap02(EMA4* e) -{ -uint32 xidex, eqt, idext1; -uint32 mseg,phys,spmseg,emasz,msegsz,msegno; - -xidex = ReadIO(idx,UMAP); /* get ID extension */ -msegsz = ReadWA(xidex+0) & 037; /* P size of std MSEG */ -idext1 = ReadWA(xidex+1); -mseg = (idext1 >> 1) & MSEGMASK; /* S9 get logical start MSEG */ -phys = idext1 & 01777; /* S phys start of EMA */ -spmseg = phys + e->ipgs; /* S7 phys pg# of MSEG */ -msegno = e->ipgs / msegsz; -if ((e->ipgs % msegsz) != 0) /* non std MSEG? */ - msegno = 0xffff; /* S4 yes, set marker */ -if (e->npgs > msegsz) return FALSE; /* map more pages than MSEG sz? */ -eqt = ReadIO(xeqt,UMAP); -emasz = ReadWA(eqt+28) & 01777; /* B EMA size in pages */ -if ((e->ipgs+e->npgs) > emasz) return FALSE; /* outside EMA? */ -if ((e->ipgs+msegsz) > emasz) /* if MSEG overlaps end of EMA */ - e->npgs = emasz - e->ipgs; /* only map until end of EMA */ - -e->emasz = emasz; /* copy arguments */ -e->msegsz = msegsz; -e->msegno = msegno; -e->spmseg = spmseg; -e->mseg = mseg; -return cpu_ema_mmap01(e); -} - -static t_stat cpu_ema_mmap(uint32 ipage,uint32 npgs, t_bool debug) -{ -uint32 xidex; -EMA4 ema4, *e = &ema4; - -e->ipgs = ipage; /* S6 set the arguments */ -e->npgs = npgs; /* S5 */ - -AR = 0; -xidex = ReadIO(idx,UMAP); -if ((ipage & SIGN) || /* negative page displacement? */ - (npgs & SIGN) || /* negative # of pages? */ - xidex == 0 || /* no EMA? */ - !cpu_ema_mmap02(e)) /* mapping failed? */ - AR = 0177777; /* return with error */ -return SCPE_OK; /* leave */ -} - -static t_bool cpu_ema_emat(EMA4* e) -{ -uint32 xidex,idext0; -uint32 curmseg,phys,msnum,lastpgs; - -xidex = ReadIO(idx,UMAP); /* read ID extension */ -idext0 = ReadWA(xidex+0); /* get current segment */ -curmseg = idext0 >> 5; -if ((idext0 & 0100000) || /* was nonstd MSEG? */ - curmseg != e->msegno) { /* or different MSEG last time? */ - phys = ReadWA(xidex+1) & 01777; /* physical start pg of EMA */ - e->spmseg = phys + e->ipgs; /* physical start pg of MSEG */ - msnum = e->emasz / e->msegsz; /* find last MSEG# */ - lastpgs = e->emasz % e->msegsz; /* #pgs in last MSEG */ - if (lastpgs==0) msnum--; /* adjust # of last MSEG */ - e->npgs = msnum==e->msegno ? lastpgs : e->msegsz; /* for last MSEG, only map available pgs */ - if (!cpu_ema_mmap01(e)) return FALSE; /* map npgs pages at ipgs */ -} -BR = e->mseg + e->msoff; /* return address of element */ -return TRUE; /* and everything done */ -} - -/* .EMIO microcode routine, resolves element addr for EMA array - * and maps the appropriate map segment - * - * Call: - * OCT 105250B - * DEF RTN error return (rtn), good return is rtn+1 - * DEF BUFLEN length of buffer in words (bufl) - * DEF TABLE[,I] array declaration (dtbl) - * DEF A(N)[,I] actual subscripts (atbl) - * DEF A(N-1)[,I] - * ... - * DEF A(2)[,I] - * DEF A(1)[,I] - * RTN EQU * error return A="15", B="EM" - * RTN+1 EQU *+1 good return B=logical address - * - * TABLE DEC # # dimensions - * DEC -L(N) - * DEC D(N-1) - * DEC -L(N-1) lower bound (n-1)st dim - * DEC D(N-2) (n-2)st dim - * ... - * DEC D(1) 1st dim - * DEC -L(1) lower bound 1st dim - * DEC # # words/element - * OFFSET 1 EMA Low - * OFFSET 2 EMA High - */ -static t_stat cpu_ema_emio(uint32* rtn,uint32 bufl,uint32 dtbl,uint32 atbl,t_bool debug) -{ -uint32 xidex, idext1; -uint32 mseg, bufpgs, npgs; -EMA4 ema4, *e = &ema4; - -xidex = ReadIO(idx,UMAP); /* read ID extension */ -if (bufl & SIGN || /* buffer length negative? */ - xidex==0) goto em16; /* no EMA declared? */ - -idext1 = ReadWA(xidex+1); /* |logstrt mseg|d|physstrt ema| */ -mseg = (idext1 >> 1) & MSEGMASK; /* get logical start MSEG */ -if (!cpu_ema_emas(dtbl,atbl,e)) goto em16; /* resolve address */ -bufpgs = (bufl + e->offs) >> 10; /* # of pgs reqd for buffer */ -if ((bufl + e->offs) & 01777) bufpgs++; /* S11 add 1 if not at pg boundary */ -if ((bufpgs + e->pgoff) > e->emasz) goto em16; /* exceeds EMA limit? */ -npgs = (e->msoff + bufl) >> 10; /* # of pgs reqd for MSEG */ -if ((e->msoff + bufl) & 01777) npgs++; /* add 1 if not at pg boundary */ -if (npgs < e->msegsz) { - e->mseg = mseg; /* logical stat of MSEG */ - if (!cpu_ema_emat(e)) goto em16; /* do a std mapping */ -} else { - BR = mseg + e->offs; /* logical start of buffer */ - e->npgs = bufpgs; /* S5 # pgs required */ - e->ipgs = e->pgoff; /* S6 page offset to reqd pg */ - if (!cpu_ema_mmap02(e)) goto em16; /* do nonstd mapping */ -} -(*rtn)++; /* return via good exit */ -return SCPE_OK; - -em16: /* error condition */ -AR=0x3136; /* AR = '16' */ -BR=0x454d; /* BR = 'EM' */ -return SCPE_OK; /* return via unmodified rtn */ -} - -/* .EMAP microcode routine, resolves both EMA/non-EMA calls - * Call: - * OCT 105257B - * DEF RTN error return (rtn), good return is rtn+1 - * DEF ARRAY[,I] array base (abase) - * DEF TABLE[,I] array declaration (dtbl) - * DEF A(N)[,I] actual subscripts (atbl) - * DEF A(N-1)[,I] - * ... - * DEF A(2)[,I] - * DEF A(1)[,I] - * RTN EQU * error return A="15", B="EM" - * RTN+1 EQU *+1 good return B=logical address - * - * TABLE DEC # # dimensions - * DEC -L(N) - * DEC D(N-1) - * DEC -L(N-1) lower bound (n-1)st dim - * DEC D(N-2) (n-2)st dim - * ... - * DEC D(1) 1st dim - * DEC -L(1) lower bound 1st dim - * DEC # # words/element - * OFFSET 1 EMA Low - * OFFSET 2 EMA High - */ -static t_stat cpu_ema_emap(uint32* rtn,uint32 abase,uint32 dtbl,uint32 atbl,t_bool debug) -{ -uint32 xidex, eqt, idext0, idext1; -int32 sub, act, low, ndim, sz; -uint32 offs, pgoff, emasz, phys, msgn, mseg, sum, MA, pg0, pg1; - -xidex = ReadIO(idx,UMAP); /* read ID Extension */ -if (xidex) { /* is EMA declared? */ - idext1 = ReadWA(xidex+1); /* get word 1 of idext */ - mseg = (idext1 >> 1) & MSEGMASK; /* get logical start MSEG */ - if (abase >= mseg) { /* EMA reference? */ - if (!cpu_ema_resolve(dtbl,atbl,&sum)) /* calculate subscript */ - goto em15; - offs = sum & 01777; /* address offset within page */ - pgoff = sum >> 10; /* ema offset in pages */ - if (pgoff > 1023) goto em15; /* overflow? */ - eqt = ReadIO(xeqt,UMAP); - emasz = ReadWA(eqt+28) & 01777; /* EMA size in pages */ - phys = idext1 & 01777; /* physical start pg of EMA */ - if (pgoff > emasz) goto em15; /* outside EMA range? */ - - msgn = mseg >> 10; /* get # of 1st MSEG reg */ - phys += pgoff; - - pg0 = dms_rmap(UMAP+0); /* read base page map# */ - pg1 = dms_rmap(UMAP+1); /* save map# 1 */ - dms_wmap(UMAP+1,pg0); /* map #0 into reg #1 */ - - WriteIO(umaps+msgn, phys, UMAP); /* store 1st mapped pg in user map */ - dms_wmap(UMAP+msgn, phys); /* and set the map register */ - phys = (pgoff+1)==emasz ? 0140000 : phys+1; /* protect 2nd map if end of EMA */ - WriteIO(umaps+msgn+1, phys, UMAP); /* store 2nd mapped pg in user map */ - dms_wmap(UMAP+msgn+1, phys); /* and set the map register */ - - dms_wmap(UMAP+1,pg1); /* restore map #1 */ - - idext0 = ReadWA(xidex+0) | 0100000; /* set NS flag in id extension */ - WriteIO(xidex+0, idext0, SMAP); /* save back value */ - AR = 0; /* was successful */ - BR = mseg + offs; /* calculate log address */ - (*rtn)++; /* return via good exit */ - return SCPE_OK; - } -} /* not EMA reference */ -ndim = ReadW(dtbl++); -if (ndim<0) goto em15; /* negative ´dimensions */ -sum = 0; /* accu for index calc */ -while (ndim > 0) { - MA = ReadW(atbl++); /* get address of A(N) */ - resolve (MA, &MA, 0); - act = ReadW(MA); /* A(N) */ - low = ReadW(dtbl++); /* -L(N) */ - sub = SEXT(act) + SEXT(low); /* subscript */ - if (sub & 0xffff8000) goto em15; /* overflow? */ - sum += sub; /* accumulate */ - sz = ReadW(dtbl++); - sz = SEXT(sz); - if (sz < 0) goto em15; - sum *= sz; /* and multiply with sz of dimension */ - if (sum & 0xffff8000) goto em15; /* overflow? */ - ndim--; -} -BR = abase + sum; /* add displacement */ -(*rtn)++; /* return via good exit */ -return SCPE_OK; - -em15: /* error condition */ - AR=0x3135; /* AR = '15' */ - BR=0x454d; /* BR = 'EM' */ - return SCPE_OK; /* return via unmodified e->rtn */ -} - -t_stat cpu_rte_ema (uint32 IR, uint32 intrq) -{ -t_stat reason = SCPE_OK; -OPS op; -OP_PAT pattern; -uint32 entry, rtn; -t_bool debug = DEBUG_PRI (cpu_dev, DEB_EMA); - -entry = IR & 017; /* mask to entry point */ -pattern = op_ema[entry]; /* get operand pattern */ - -if (pattern != OP_N) - if (reason = cpu_ops (pattern, op, intrq)) /* get instruction operands */ - return reason; - -if (debug) { /* debugging? */ - fprintf (sim_deb, ">>CPU EMA: PC = %06o, IR = %06o (", err_PC,IR); /* print preamble and IR */ - fprint_sym (sim_deb, err_PC, (t_value *) &IR, /* print instruction mnemonic */ - NULL, SWMASK('M')); - fputc (')', sim_deb); - - fprint_ops (pattern, op); /* print operands */ - fputc ('\n', sim_deb); /* terminate line */ - } - -switch (entry) { /* decode IR<3:0> */ - case 000: /* .EMIO 105240 (OP_A) */ - rtn = op[0].word; - reason = cpu_ema_emio(&rtn, op[1].word, - op[2].word, PC, debug); /* handle the EMIO instruction */ - PC = rtn; - if (debug) - fprintf (sim_deb, ">>CPU EMA: return .EMIO: AR = %06o, BR = %06o, rtn=%s\n", - AR, BR, PC==op[0].word?"error":"good"); - break; - - case 001: /* .MMAP 105241 (OP_AKK) */ - reason = cpu_ema_mmap(op[1].word, - op[2].word, debug); /* handle the MMAP instruction */ - if (debug) - fprintf (sim_deb, ">>CPU EMA: return .MMAP: AR = %06o\n",AR); - break; - - case 002: /* [test] 105242 (OP_N) */ - /* effectively, this code just returns without error: - * real microcode will set S register to 102077B when in single step mode */ - if (sim_step==1) { - if (debug) - fprintf(sim_deb, ">>CPU EMA: EMA option 92067 correctly installed: S=102077\n"); - SR = 0102077; - } - break; - - case 017: /* .EMAP 105247 (OP_A) */ - rtn = op[0].word; /* error return */ - reason = cpu_ema_emap(&rtn, op[1].word, - op[2].word, PC, debug); /* handle the EMAP instruction */ - PC = rtn; - if (debug) { - fprintf (sim_deb, ">>CPU EMA: return .EMAP: AR = %06o, BR = %06o, rtn=%s\n", - AR, BR, PC==op[0].word?"error":"good"); - } - break; - - default: /* others undefined */ - reason = stop_inst; - } - -return reason; -} +/* hp2100_cpu5.c: HP 1000 RTE-6/VM VMA and RTE-IV EMA instructions + + Copyright (c) 2007-2008, Holger Veit + Copyright (c) 2006-2014, J. David Bryan + + 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 + THE AUTHORS 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 the authors shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from the authors. + + CPU5 RTE-6/VM and RTE-IV firmware option instructions + + 24-Dec-14 JDB Added casts for explicit downward conversions + 17-Dec-12 JDB Fixed cpu_vma_mapte to return FALSE if not a VMA program + 09-May-12 JDB Separated assignments from conditional expressions + 23-Mar-12 JDB Added sign extension for dim count in "cpu_ema_resolve" + 28-Dec-11 JDB Eliminated unused variable in "cpu_ema_vset" + 11-Sep-08 JDB Moved microcode function prototypes to hp2100_cpu1.h + 05-Sep-08 JDB Removed option-present tests (now in UIG dispatchers) + 30-Jul-08 JDB Redefined ABORT to pass address, moved def to hp2100_cpu.h + 26-Jun-08 JDB Rewrote device I/O to model backplane signals + 01-May-08 HV Fixed mapping bug in "cpu_ema_emap" + 21-Apr-08 JDB Added EMA support from Holger + 25-Nov-07 JDB Added TF fix from Holger + 07-Nov-07 HV VMACK diagnostic tests 1...32 passed + 19-Oct-07 JDB Corrected $LOC operand profile to OP_CCCACC + 03-Oct-07 HV Moved RTE-6/VM instrs from hp2100_cpu0.c + 26-Sep-06 JDB Created + + Primary references: + - HP 1000 M/E/F-Series Computers Technical Reference Handbook + (5955-0282, Mar-1980) + - HP 1000 M/E/F-Series Computers Engineering and Reference Documentation + (92851-90001, Mar-1981) + - Macro/1000 Reference Manual (92059-90001, Dec-1992) + + Additional references are listed with the associated firmware + implementations, as are the HP option model numbers pertaining to the + applicable CPUs. +*/ + +#include +#include "hp2100_defs.h" +#include "hp2100_cpu.h" +#include "hp2100_cpu1.h" + + +/* RTE-6/VM Virtual Memory Area Instructions + + RTE-6/VM (product number 92084A) introduced Virtual Memory Area (VMA) + instructions -- a superset of the RTE-IV EMA instructions. Different + microcode was supplied with the operating system that replaced the microcode + used with RTE-IV. Microcode was limited to the E/F-Series, and the M-Series + used software equivalents. + + Option implementation by CPU was as follows: + + 2114 2115 2116 2100 1000-M 1000-E 1000-F + ------ ------ ------ ------ ------ ------ ------ + N/A N/A N/A N/A N/A 92084A 92084A + + The routines are mapped to instruction codes as follows: + + Instr. 1000-E/F Description + ------ -------- ---------------------------------------------- + .PMAP 105240 Map VMA page into map register + $LOC 105241 Load on call + [test] 105242 [self test] + .SWP 105243 [Swap A and B registers] + .STAS 105244 [STA B; LDA SP] + .LDAS 105245 [LDA SP] + .MYAD 105246 [NOP in microcode] + .UMPY 105247 [Unsigned multiply and add] + + .IMAP 105250 Integer element resolve address and map + .IMAR 105251 Integer element resolve address + .JMAP 105252 Double integer element resolve address and map + .JMAR 105253 Double integer element resolve address + .LPXR 105254 Map pointer in P+1 plus offset in P+2 + .LPX 105255 Map pointer in A/B plus offset in P+1 + .LBPR 105256 Map pointer in P+1 + .LBP 105257 Map pointer in A/B registers + + Implementation notes: + + 1. The opcodes 105243-247 are undocumented and do not appear to be used in + any HP software. + + 2. The opcode list in the CE Handbook incorrectly shows 105246 as ".MYAD - + multiply 2 signed integers." The microcode listing shows that this + instruction was deleted, and the opcode is now a NOP. + + 3. RTE-IV EMA and RTE-6 VMA instructions shared the same address space, so a + given machine could run one or the other, but not both. + + Additional references: + - RTE-6/VM VMA/EMA Microcode Source (92084-18828, revision 3). + - RTE-6/VM Technical Specifications (92084-90015, Apr-1983). + - M/E/F-Series Computer Systems CE Handbook (5950-3767, Jul-1984). +*/ + +static const OP_PAT op_vma[16] = { + OP_N, OP_CCCACC, OP_N, OP_N, /* .PMAP $LOC [test] .SWAP */ + OP_N, OP_N, OP_N, OP_K, /* .STAS .LDAS .MYAD .UMPY */ + OP_A, OP_A, OP_A, OP_A, /* .IMAP .IMAR .JMAP .JMAR */ + OP_AA, OP_A, OP_A, OP_N /* .LPXR .LPX .LBPR .LBP */ + }; + +/* some addresses in page0 of RTE-6/VM */ +static const uint32 idx = 0001645; +static const uint32 xmata = 0001646; +static const uint32 xi = 0001647; +static const uint32 xeqt = 0001717; +static const uint32 vswp = 0001776; +static const uint32 umaps = 0003740; +static const uint32 page30 = 0074000; +static const uint32 page31 = 0076000; +static const uint32 ptemiss = 0176000; + +/* frequent constants in paging */ +#define SUITMASK 0176000 +#define NILPAGE 0176000 +#define PAGEIDX 0001777 +#define MSEGMASK 0076000 +#define RWPROT 0141777 + + +/* microcode version of resolve(): allows a much higher # of indirection levels. Used for + instance for LBP microcode diagnostics which will check > 100 levels. + */ +#define VMA_INDMAX 200 + +static t_stat vma_resolve (uint32 MA, uint32 *addr, t_bool debug) +{ +uint32 i; +uint32 faultma = MA; + +for (i = 0; (i < VMA_INDMAX) && (MA & I_IA); i++) { /* resolve multilevel */ + MA = ReadW (MA & VAMASK); /* follow address chain */ + } + +if (MA & I_IA) { + if (debug) + fprintf(sim_deb,">>CPU VMA: vma_resolve indirect loop addr=%06o\n",faultma); + return STOP_IND; /* indirect loop */ + } + +*addr = MA; +return SCPE_OK; +} + +/* $LOC + ASSEMBLER CALLING SEQUENCE: + + $MTHK NOP RETURN ADDRESS OF CALL (REDONE AFTER THIS ROUTINE) + JSB $LOC + .DTAB OCT LGPG# LOGICAL PAGE # AT WHICH THE NODE TO + * BE MAPPED IN BELONGS (0-31) + OCT RELPG RELATIVE PAGE OFFSET FROM BEGINING + * OF PARTITION OF WHERE THAT NODE RESIDES. + * (0 - 1023) + OCT RELBP RELATIVE PAGE OFFSET FROM BEGINING OF + * PARTITION OF WHERE BASE PAGE RESIDES + * (0 - 1023) + CNODE DEF .CNOD THIS IS THE ADDRESS OF CURRENT PATH # WORD + .ORD OCT XXXXX THIS NODE'S LEAF # (IE PATH #) + .NOD# OCT XXXXX THIS NODE'S ORDINAL # +*/ + +static t_stat cpu_vma_loc(OPS op,uint32 intrq,t_bool debug) +{ +uint32 eqt,mls,pnod,lstpg,fstpg,rotsz,lgpg,relpg,relbp,matloc,ptnpg,physpg,cnt,pgs,umapr; + +eqt = ReadIO(xeqt,UMAP); /* get ID segment */ +mls = ReadIO(eqt+33,SMAP); /* get word33 of alternate map */ +if ((mls & 0x8000) == 0) { /* this is not an MLS prog! */ + PC = err_PC; + if (debug) + fprintf(sim_deb,">>CPU VMA: cpu_vma_loc at P=%06o: not an MLS program\n", PC); + if (mp_control) MP_ABORT (eqt+33); /* allow an MP abort */ + return STOP_HALT; /* FATAL error! */ + } + +pnod = mls & 01777; /* get #pages of mem res nodes */ +if (pnod == 0) { /* no pages? FATAL! */ + PC = err_PC; + if (debug) + fprintf(sim_deb,">>CPU VMA: cpu_vma_loc at P=%06o: no mem resident pages\n", PC); + if (mp_control) MP_ABORT (eqt+33); /* allow an MP abort */ + return STOP_HALT; + } + +lstpg = (ReadIO(eqt+29,SMAP) >> 10) - 1; /* last page# of code */ +fstpg = ReadIO(eqt+23,SMAP) >> 10; /* index to 1st addr + mem nodes */ +rotsz = fstpg - (ReadIO(eqt+22,SMAP) >> 10); /* #pages in root */ +lgpg = op[0].word; + +/* lets do some consistency checks, CPU halt if they fail */ +if (lstpg < lgpg || lgpg < fstpg) { /* assert LSTPG >= LGPG# >= FSTPG */ + PC = err_PC; + if (debug) + fprintf(sim_deb, + ">>CPU VMA: $LOC at P=%06o: failed check LSTPG >= LGPG# >= FSTPG\n",PC); + if (mp_control) MP_ABORT (eqt+22); /* allow an MP abort */ + return STOP_HALT; + } + +relpg = op[1].word; +if (pnod < relpg || relpg < (rotsz+1)) { /* assert #PNOD >= RELPG >= ROTSZ+1 */ + PC = err_PC; + if (debug) + fprintf(sim_deb, + ">>CPU VMA: $LOC at %06o: failed check #PNOD >= RELPG >= ROTSZ+1\n",PC); + if (mp_control) MP_ABORT (eqt+22); /* allow an MP abort */ + return STOP_HALT; + } + +relbp = op[2].word; +if (relbp != 0) /* assert RELBP == 0 OR */ + if (pnod < relbp || relbp < (rotsz+1)) { /* #PNOD >= RELBP >= ROTSZ+1 */ + PC = err_PC; + if (debug) + fprintf(sim_deb, + ">>CPU VMA: $LOC at P=%06o: failed check: #PNOD >= RELBP >= ROTSZ+1\n",PC); + if (mp_control) MP_ABORT (eqt+22); /* allow an MP abort */ + return STOP_HALT; + } + +cnt = lstpg - lgpg + 1; /* #pages to map */ +pgs = pnod - relpg + 1; /* #pages from start node to end of code */ +if (pgs < cnt) cnt = pgs; /* ensure minimum, so not to map into EMA */ + +matloc = ReadIO(xmata,UMAP); /* get MAT $LOC address */ +ptnpg = ReadIO(matloc+3,SMAP) & 01777; /* index to start phys pg */ +physpg = ptnpg + relpg; /* phys pg # of node */ +umapr = 32 + lgpg; /* map register to start */ + +/* do an XMS with AR=umapr,BR=physpg,XR=cnt */ +if (debug) + fprintf(sim_deb, + ">>CPU VMA: $LOC map %d pgs from phys=%06o to mapr=%d\n", + cnt,physpg,umapr); +while (cnt != 0) { + dms_wmap (umapr, physpg); /* map pages of new overlay segment */ + cnt = (cnt - 1) & DMASK; + umapr = (umapr + 1) & DMASK; + physpg = (physpg + 1) & DMASK; + } + +dms_wmap(32,relbp+ptnpg); /* map base page again */ +WriteW(op[3].word,op[4].word); /* path# we are going to */ + +PC = (PC - 8) & DMASK; /* adjust PC to return address */ + /* word before the $LOC microinstr. */ +PC = (ReadW(PC) - 1) & DMASK; /* but the call has to be rerun, */ + /* so must skip back to the original call */ + /* which will now lead to the real routine */ +if (debug) + fprintf(sim_deb,">>CPU VMA: $LOC done: path#=%06o, P=%06o\n",op[4].word,PC); +return SCPE_OK; +} + +/* map pte into last page + return FALSE if page fault, nil flag in PTE or suit mismatch + return TRUE if suit match, physpg = physical page + or page=0 -> last+1 page +*/ +static t_bool cpu_vma_ptevl(uint32 pagid,uint32* physpg) +{ +uint32 suit; +uint32 pteidx = pagid & 0001777; /* build index */ +uint32 reqst = pagid & SUITMASK; /* required suit */ +uint32 pteval = ReadW(page31 | pteidx); /* get PTE entry */ +*physpg = pteval & 0001777; /* store physical page number */ +suit = pteval & SUITMASK; /* suit number seen */ +if (pteval == NILPAGE) return FALSE; /* NIL value in PTE */ +return suit == reqst || !*physpg; /* good page or last+1 */ +} + +/* handle page fault */ +static t_stat cpu_vma_fault(uint32 x,uint32 y,int32 mapr, + uint32 ptepg,uint32 ptr,uint32 faultpc, t_bool debug) +{ +uint32 pre = ReadIO(xi,UMAP); /* get program preamble */ +uint32 ema = ReadIO(pre+2,UMAP); /* get address of $EMA$/$VMA$ */ +WriteIO(ema,faultpc,UMAP); /* write addr of fault instr */ +XR = x; /* X = faulting page */ +YR = y; /* Y = faulting address for page */ + +if (mapr>0) + dms_wmap(mapr+UMAP,ptepg); /* map PTE into specified user dmsmap */ + +/* do a safety check: first instr of $EMA$/$VMA$ must be a DST instr */ +if (ReadIO(ema+1,UMAP) != 0104400) { + if (debug) + fprintf(sim_deb, ">>CPU VMA: pg fault: no EMA/VMA user code present\n"); + if (mp_control) MP_ABORT (ema+1); /* allow an MP abort */ + return STOP_HALT; /* FATAL: no EMA/VMA! */ + } + +PC = (ema+1) & VAMASK; /* restart $EMA$ user code, */ + /* will return to fault instruction */ + +AR = (ptr >> 16) & DMASK; /* restore A, B */ +BR = ptr & DMASK; +E = 0; /* enforce E = 0 */ +if (debug) + fprintf(sim_deb, + ">>CPU VMA: Call pg fault OS exit, AR=%06o BR=%06o P=%06o\n", + AR, BR, PC); +return SCPE_OK; +} + +/* map in PTE into last page, return false, if page fault */ +static t_bool cpu_vma_mapte(uint32* ptepg) +{ +uint32 idext,idext2; +uint32 dispatch = ReadIO(vswp,UMAP) & 01777; /* get fresh dispatch flag */ +t_bool swapflag = TRUE; + +if (dispatch == 0) { /* not yet set */ + idext = ReadIO(idx,UMAP); /* go into ID segment extent */ + if (idext == 0) { /* is ema/vma program? */ + swapflag = FALSE; /* no, so mark PTE as invalid */ + *ptepg = (uint32) -1; /* and return an invalid page number */ + } + + else { /* is an EMA/VMA program */ + dispatch = ReadWA(idext+1) & 01777; /* get 1st ema page: new vswp */ + WriteIO(vswp,dispatch,UMAP); /* move into $VSWP */ + idext2 = ReadWA(idext+2); /* get swap bit */ + swapflag = (idext2 & 020000) != 0; /* bit 13 = swap bit */ + } + } + +if (dispatch) { /* some page is defined */ + dms_wmap(31 + UMAP,dispatch); /* map $VSWP to register 31 */ + *ptepg = dispatch; /* return PTEPG# for later */ + } + +return swapflag; /* true for valid PTE */ +} + +/* .LBP + ASSEMBLER CALLING SEQUENCE: + + DLD PONTR TRANSLATE 32 BIT POINTER TO 15 + JSB .LBP BIT POINTER. + + + 32 bit pointer: + ----------AR------------ -----BR----- + 15 14....10 9....4 3...0 15.10 9....0 + L<----------------------------------- L=1 local reference bit + XXXXXXXX<------------------------- 5 bit unused + PPPPPP PPPPP PPPPP<------ 16 bit PAGEID + SSSSSS<------------------ SUIT# within PAGEID + PPPPP PPPPP<------ 10 bit PAGEID index into PTE + OOOOOO 10 bit OFFSET +*/ + +static t_stat cpu_vma_lbp(uint32 ptr,uint32 aoffset,uint32 faultpc,uint32 intrq,t_bool debug) +{ +uint32 pagid,offset,ptrl,pgidx,ptepg; +uint16 p30,p31,suit; +t_stat reason = SCPE_OK; +uint32 faultab = ptr; /* remember A,B for page fault */ +ptr += aoffset; /* add the offset e.g. for .LPX */ + +if (debug) + fprintf(sim_deb,">>CPU VMA: cpu_vma_lbp: ptr=%o/%o\n", + (ptr>>16) & DMASK,ptr & DMASK); + +O = 0; /* clear overflow */ +if (ptr & 0x80000000) { /* is it a local reference? */ + ptrl = ptr & VAMASK; + if (ptr&I_IA) { + reason = vma_resolve (ReadW (ptrl), &ptrl, debug); + if (reason) + return reason; /* yes, resolve indirect ref */ + } + BR = ptrl & VAMASK; /* address is local */ + AR = (ptr >> 16) & DMASK; + if (debug) + fprintf(sim_deb,">>CPU VMA: cpu_vma_lbp: local ref AR=%06o BR=%06o\n",AR,BR); + return SCPE_OK; + } + +pagid = (ptr >> 10) & DMASK; /* extract page id (16 bit idx, incl suit*/ +offset = ptr & 01777; /* and offset */ +suit = pagid & SUITMASK; /* suit of page */ +pgidx = pagid & PAGEIDX; /* index into PTE */ + +if (!cpu_vma_mapte(&ptepg)) /* map in PTE */ + return cpu_vma_fault(65535,ptemiss,-1,ptepg,faultab,faultpc, debug); /* oops, must init PTE */ + +/* ok, we have the PTE mapped to page31 */ +/* the microcode tries to reads two consecutive data pages into page30 and page31 */ + +/* read the 1st page value from PTE */ +p30 = ReadW(page31 | pgidx) ^ suit; +if (!p30) /* matched suit for 1st page */ + return cpu_vma_fault(pagid,page30,30,ptepg,faultab,faultpc,debug); + +/* suit switch situation: 1st page is in last idx of PTE, then following page + * must be in idx 0 of PTE */ +if (pgidx==01777) { /* suit switch situation */ + pgidx = 0; /* select correct idx 0 */ + suit = (uint16) (pagid + 1); /* suit needs increment */ + if (suit==0) { /* is it page 65536? */ + offset += 02000; /* adjust to 2nd page */ + suit = NILPAGE; + pgidx = 01777; + } +} else + pgidx++; /* select next page */ + +p31 = ReadW(page31 | pgidx) ^ suit; +if (!p31) { /* matched suit for 2nd page */ + dms_wmap(31+UMAP,p30); + if (p30 & SUITMASK) + return cpu_vma_fault(pagid,page30,30,ptepg,faultab,faultpc,debug); + if (!(p31 ^ NILPAGE)) /* suit is 63: fault */ + return cpu_vma_fault(pagid+1,page31,31,ptepg,faultab,faultpc,debug); + + offset += 02000; /* adjust offset to last user map because */ + /* the address requested page 76xxx */ + } +else { + dms_wmap(30+UMAP,p30); + if (p30 & SUITMASK) + return cpu_vma_fault(pagid,page30,30,ptepg,faultab,faultpc,debug); + dms_wmap(31+UMAP,p31); + if (p31 & SUITMASK) + return cpu_vma_fault(pagid+1,page31,31,ptepg,faultab,faultpc,debug); + } + +AR = (uint16) pagid; /* return pagid in A */ +BR = (uint16) (page30 + offset); /* mapped address in B */ +if (debug) + fprintf(sim_deb,">>CPU VMA: cpu_vma_lbp: map done AR=%06o BR=%o6o\n",AR,BR); +return SCPE_OK; +} + +/* .PMAP + ASSEMBLER CALLING SEQUENCE: + + LDA UMAPR (MSEG - 31) + LDB PAGID (0-65535) + JSB .PMAP GO MAP IT IN + A-REG = REASON, NOTE 1 + > SEE NOTE 2> + + NOTE 1 : IF BIT 15 OF A-REG SET, THEN ALL NORMAL BRANCHES TO THE + $EMA$/$VMA$ CODE WILL BE CHANGED TO P+1 EXIT. THE A-REG + WILL BE THE REASON THE MAPPING WAS NOT SUCCESSFUL IF BIT 15 + OF THE A-REG WAS NOT SET. + THIS WAS DONE SO THAT A ROUTINE ($VMA$) CAN DO A MAPPING + WITHOUT THE POSSIBILITY OF BEING RE-CURRED. IT IS USED + BY $VMA$ AND PSTVM IN THE PRIVLEDGED MODE. + NOTE 2: E-REG WILL = 1 IF THE LAST+1 PAGE IS REQUESTED AND + MAPPED READ/WRITE PROTECTED ON A GOOD P+2 RETURN. +*/ +static t_stat cpu_vma_pmap(uint32 umapr,uint32 pagid, t_bool debug) +{ +uint32 physpg, ptr, pgpte; +uint32 mapnm = umapr & 0x7fff; /* strip off bit 15 */ + +if (debug) + fprintf(sim_deb, ">>CPU VMA: .PMAP AR=%06o(umapr) BR=%06o(pagid)\n",umapr,pagid); + +if (mapnm > 31) { /* check for invalid map register */ + AR = 80; /* error: corrupt EMA/VMA system */ + if (debug) + fprintf(sim_deb, ">>CPU VMA: .PMAP invalid mapr: AR=80, exit P+1\n"); + return SCPE_OK; /* return exit PC+1 */ + } + +ptr = (umapr << 16) | (pagid & DMASK); /* build the ptr argument for vma_fault */ +if (!cpu_vma_mapte(&pgpte)) { /* map the PTE */ + if (umapr & 0x8000) { + XR = 65535; + YR = ptemiss; + if (debug) + fprintf(sim_deb, + ">>CPU VMA: .PMAP pg fault&bit15: XR=%06o YR=%06o, exit P+1\n", + XR, YR); + return SCPE_OK; /* use PC+1 error exit */ + } + return cpu_vma_fault(65535,ptemiss,-1,pgpte,ptr,PC-1,debug); /* oops: fix PTE */ + } + +/* PTE is successfully mapped to page31 and dmsmap[63] */ +if (!cpu_vma_ptevl(pagid,&physpg)) { + if (umapr & 0x8000) { + XR = pagid; + YR = page31; + if (debug) + fprintf(sim_deb, + ">>CPU VMA: .PMAP pg map&bit15: XR=%06o YR=%06o, exit P+1\n", + XR, YR); + return SCPE_OK; /* use PC+1 error exit*/ + } + return cpu_vma_fault(pagid,page31,31,pgpte,ptr,PC-1,debug); /* page not present */ + } + +E = 1; +if (physpg == 0) /* last+1 page ? */ + physpg = RWPROT; /* yes, use page 1023 RW/Protected */ +else E = 0; /* normal page to map */ + +dms_wmap(mapnm+UMAP,physpg); /* map page to user page reg */ +if (mapnm != 31) /* unless already unmapped, */ + dms_wmap(31+UMAP,RWPROT); /* unmap PTE */ + +AR = (umapr + 1) & DMASK; /* increment mapr for next call */ +BR = (pagid + 1) & DMASK; /* increment pagid for next call */ +O = 0; /* clear overflow */ +PC = (PC + 1) & VAMASK; /* normal PC+2 return */ +if (debug) + fprintf(sim_deb,">>CPU VMA: .PMAP map done: AR=%06o BR=%o6o exit P+2\n",AR,BR); +return SCPE_OK; +} + +/* array calc helper for .imar, .jmar, .imap, .jmap + ij=in_s: 16 bit descriptors + ij=in_d: 32 bit descriptors + + This helper expects mainly the following arguments: + dtbl: pointer to an array descriptor table + atbl: pointer to the table of actual subscripts + + where subscript table is the following: + atbl-> DEF last_subscript,I (point to single or double integer) + ... + DEF first subscript,I (point to single or double integer) + + where Descriptor_table is the following table: + dtbl-> DEC #dimensions + DEC/DIN next-to-last dimension (single or double integer) + ... + DEC/DIN first dimension (single or double integer) + DEC elementsize in words + DEC high,low offset from start of EMA to element(0,0...0) + + Note that subscripts are counting from 0 +*/ +static t_stat cpu_vma_ijmar(OPSIZE ij,uint32 dtbl,uint32 atbl,uint32* dimret, + uint32 intrq,t_bool debug) +{ +t_stat reason = SCPE_OK; +uint32 ndim,MA,i,ws; +int32 accu,ax,dx; +OP din; +int opsz = ij==in_d ? 2 : 1; + +ndim = ReadW(dtbl++); /* get #dimensions itself */ +if (debug) { + fprintf(sim_deb, ">>CPU VMA array calc #dim=%d, size=%d\n",ndim,opsz); + fprintf(sim_deb, ">>CPU VMA: array actual subscripts ("); + for (i=0; i0) fputc(',',sim_deb); + fprintf(sim_deb,"%d",ij==in_d?INT32(din.dword) : INT16(din.word)); + } + + fprintf(sim_deb,")\n>>CPU VMA: array descriptor table ("); + if (ndim) { + for (i=0; i0) fputc(',',sim_deb); + fprintf(sim_deb,"%d",ij==in_d?INT32(din.dword) : INT16(din.word)); + } + i = dtbl+1+(ndim-1)*opsz; + ws = ReadW(i-1); + } + else { + i = dtbl; + ws = 1; + } + fprintf(sim_deb,")\n>>CPU VMA: array elemsz=%d base=%o/%o\n", + ws,ReadW(i),ReadW(i+1)); + } + +if (dimret) *dimret = ndim; /* return dimensions */ +if (ndim == 0) { /* no dimensions: */ + AR = ReadW(dtbl++); /* return the array base itself */ + BR = ReadW(dtbl); + if (debug) + fprintf(sim_deb,">>CPU VMA: #dim=0, AR=%06o, BR=%06o\n",AR,BR); + return SCPE_OK; + } + +/* calculate + * (...(An*Dn-1)+An-1)*Dn-2)+An-2....)+A2)*D1)+A1)*#words + Array base + * Depending on ij, Ax and Dx can be 16 or 32 bit + */ +accu = 0; +while (ndim-- > 0) { + MA = ReadW(atbl++); /* get addr of subscript */ + reason = resolve (MA, &MA, intrq); /* and resolve it */ + if (reason) + return reason; + din = ReadOp(MA,ij); /* get actual subscript value */ + ax = ij==in_d ? INT32(din.dword) : INT16(din.word); + accu += ax; /* add to accu */ + + if (ndim==0) ij = in_s; /* #words is single */ + din = ReadOp(dtbl,ij); /* get dimension from descriptor table */ + if (ij==in_d) { + dx = INT32(din.dword); /* either get double or single dimension */ + dtbl += 2; + } else { + dx = INT16(din.word); + dtbl++; + } + accu *= dx; /* multiply */ + } + +din = ReadOp(dtbl,in_d); /* add base address */ +accu += din.dword; + +AR = (accu >> 16) & DMASK; /* transfer to AB */ +BR = accu & DMASK; +if (debug) + fprintf(sim_deb,">>CPU VMA: resulting virt addr=%o (AR=%06o, BR=%06o)\n",accu,AR,BR); +return reason; +} + +/* + * This is the main handler for the RTE6/VMA microcodes */ +t_stat cpu_rte_vma (uint32 IR, uint32 intrq) +{ +t_stat reason = SCPE_OK; +OPS op; +OP_PAT pattern; +uint16 t16; +uint32 entry,t32,ndim; +uint32 dtbl,atbl; /* descriptor table ptr, actual args ptr */ +OP dop0,dop1; +uint32 pcsave = (PC+1) & VAMASK; /* save PC to check for redo in imap/jmap */ +t_bool debug = DEBUG_PRI (cpu_dev, DEB_VMA); + +entry = IR & 017; /* mask to entry point */ +pattern = op_vma[entry]; /* get operand pattern */ + +if (pattern != OP_N) { + reason = cpu_ops (pattern, op, intrq); /* get instruction operands */ + if (reason != SCPE_OK) /* evaluation failed? */ + return reason; /* return reason for failure */ + } + +if (debug) { /* debugging? */ + fprintf (sim_deb, ">>CPU VMA: IR = %06o (", IR); /* print preamble and IR */ + fprint_sym (sim_deb, err_PC, (t_value *) &IR, /* print instruction mnemonic */ + NULL, SWMASK('M')); + fprintf (sim_deb, "), P = %06o, XEQT = %06o", /* print location and program ID */ + err_PC, ReadW (xeqt)); + + fprint_ops (pattern, op); /* print operands */ + fputc ('\n', sim_deb); /* terminate line */ + } + +switch (entry) { /* decode IR<3:0> */ + + case 000: /* .PMAP 105240 (OP_N) */ + reason = cpu_vma_pmap(AR,BR,debug); /* map pages */ + break; + + case 001: /* $LOC 105241 (OP_CCCACC) */ + reason = cpu_vma_loc(op,intrq,debug); /* handle the coroutine switch */ + break; + + case 002: /* [test] 105242 (OP_N) */ + XR = 3; /* refer to src code 92084-18828 rev 3 */ + SR = 0102077; /* HLT 77 instruction */ + YR = 1; /* ROMs correctly installed */ + PC = (PC+1) & VAMASK; /* skip instr if VMA/EMA ROM installed */ + break; + + case 003: /* [swap] 105243 (OP_N) */ + t16 = AR; /* swap A and B registers */ + AR = BR; + BR = t16; + break; + + case 004: /* [---] 105244 (OP_N) */ + reason = stop_inst; /* fragment of dead code */ + break; /* in microrom */ + + case 005: /* [---] 105245 (OP_N) */ + reason = stop_inst; /* fragment of dead code */ + break; /* in microrom */ + + case 006: /* [nop] 105246 (OP_N) */ + break; /* do nothing */ + + case 007: /* [umpy] 105247 (OP_K) */ + t32 = AR * op[0].word; /* get multiplier */ + t32 += BR; /* add B */ + AR = (t32 >> 16) & DMASK; /* move result back to AB */ + BR = t32 & DMASK; + O = 0; /* instr clears OV */ + break; + + case 010: /* .IMAP 105250 (OP_A) */ + dtbl = op[0].word; + atbl = PC; + reason = cpu_vma_ijmar(in_s,dtbl,atbl,&ndim,intrq,debug); /* calc the virt address to AB */ + if (reason) + return reason; + t32 = (AR << 16) | (BR & DMASK); + reason = cpu_vma_lbp(t32,0,PC-2,intrq,debug); + if (reason) + return reason; + if (PC==pcsave) + PC = (PC+ndim) & VAMASK; /* adjust PC: skip ndim subscript words */ + break; + + case 011: /* .IMAR 105251 (OP_A) */ + dtbl = ReadW(op[0].word); + atbl = (op[0].word+1) & VAMASK; + reason = cpu_vma_ijmar(in_s,dtbl,atbl,0,intrq,debug); /* calc the virt address to AB */ + break; + + case 012: /* .JMAP 105252 (OP_A) */ + dtbl = op[0].word; + atbl = PC; + reason = cpu_vma_ijmar(in_d,dtbl,atbl,&ndim,intrq,debug); /* calc the virtual address to AB */ + if (reason) + return reason; + t32 = (AR << 16) | (BR & DMASK); + reason = cpu_vma_lbp(t32,0,PC-2,intrq,debug); + if (reason) + return reason; + if (PC==pcsave) + PC = (PC + ndim) & VAMASK; /* adjust PC: skip ndim subscript dword ptr */ + break; + + case 013: /* .JMAR 105253 (OP_A) */ + dtbl = ReadW(op[0].word); + atbl = (op[0].word+1) & VAMASK; + reason = cpu_vma_ijmar(in_d,dtbl,atbl,0,intrq,debug); /* calc the virt address to AB */ + break; + + case 014: /* .LPXR 105254 (OP_AA) */ + dop0 = ReadOp(op[0].word,in_d); /* get pointer from arg */ + dop1 = ReadOp(op[1].word,in_d); + t32 = dop0.dword + dop1.dword; /* add offset to it */ + reason = cpu_vma_lbp(t32,0,PC-3,intrq,debug); + break; + + case 015: /* .LPX 105255 (OP_A) */ + t32 = (AR << 16) | (BR & DMASK); /* pointer in AB */ + dop0 = ReadOp(op[0].word,in_d); + reason = cpu_vma_lbp(t32,dop0.dword,PC-2,intrq,debug); + break; + + case 016: /* .LBPR 105256 (OP_A) */ + dop0 = ReadOp(op[0].word,in_d); /* get the pointer */ + reason = cpu_vma_lbp(dop0.dword,0,PC-2,intrq,debug); + break; + + case 017: /* .LBP 105257 (OP_N) */ + t32 = (AR << 16) | (BR & DMASK); + reason = cpu_vma_lbp(t32,0,PC-1,intrq,debug); + break; + } + +return reason; +} + + +/* RTE-IV Extended Memory Area Instructions + + The RTE-IV operating system (HP product number 92067A) introduced the + Extended Memory Area (EMA) instructions. EMA provided a mappable data area + up to one megaword in size. These three instructions accelerated data + accesses to variables stored in EMA partitions. Support was limited to + E/F-Series machines; M-Series machines used software equivalents. + + Option implementation by CPU was as follows: + + 2114 2115 2116 2100 1000-M 1000-E 1000-F + ------ ------ ------ ------ ------ ------ ------ + N/A N/A N/A N/A N/A 92067A 92067A + + The routines are mapped to instruction codes as follows: + + Instr. 1000-E/F Description + ------ -------- ---------------------------------------------- + .EMIO 105240 EMA I/O + MMAP 105241 Map physical to logical memory + [test] 105242 [self test] + .EMAP 105257 Resolve array element address + + Notes: + + 1. RTE-IV EMA and RTE-6 VMA instructions share the same address space, so a + given machine can run one or the other, but not both. + + 2. The EMA diagnostic (92067-16013) reports bogus MMAP failures if it is + not loaded at the start of its partition (e.g., because of a LOADR "LO" + command). The "ICMPS" map comparison check in the diagnostic assumes + that the starting page of the program's partition contains the first + instruction of the program and prints "MMAP ERROR" if it does not. + + Additional references: + - RTE-IVB Programmer's Reference Manual (92068-90004, Dec-1983). + - RTE-IVB Technical Specifications (92068-90013, Jan-1980). +*/ + +static const OP_PAT op_ema[16] = { + OP_AKA, OP_AKK, OP_N, OP_N, /* .EMIO MMAP [test] --- */ + OP_N, OP_N, OP_N, OP_N, /* --- --- --- --- */ + OP_N, OP_N, OP_N, OP_N, /* --- --- --- --- */ + OP_N, OP_N, OP_N, OP_AAA /* --- --- --- .EMAP */ + }; + +/* calculate the 32 bit EMA subscript for an array */ +static t_bool cpu_ema_resolve(uint32 dtbl,uint32 atbl,uint32* sum) +{ +int32 sub, act, low, sz, ndim; +uint32 MA, base; + +ndim = ReadW(dtbl++); /* # dimensions */ +ndim = SEXT(ndim); /* sign extend */ +if (ndim < 0) return FALSE; /* invalid? */ + +*sum = 0; /* accu for index calc */ +while (ndim > 0) { + MA = ReadW(atbl++); /* get address of A(N) */ + resolve (MA, &MA, 0); + act = ReadW(MA); /* A(N) */ + low = ReadW(dtbl++); /* -L(N) */ + sub = SEXT(act) + SEXT(low); /* subscript */ + if (sub & 0xffff8000) return FALSE; /* overflow? */ + *sum += sub; /* accumulate */ + sz = ReadW(dtbl++); + sz = SEXT(sz); + if (sz < 0) return FALSE; + *sum *= sz; + if (*sum > (512*1024)) return FALSE; /* overflow? */ + ndim--; +} +base = (ReadW(dtbl+1)<<16) | (ReadW(dtbl) & 0xffff); /* base of array in EMA */ +if (base & 0x8000000) return FALSE; +*sum += base; /* calculate address into EMA */ +if (*sum & 0xf8000000) return FALSE; /* overflow? */ +return TRUE; +} + +/* implementation of VIS RTE-IVB EMA support + * .ERES microcode routine, resolves only EMA addresses + * Call: + * .OCT 101474B + * DEF RTN error return (rtn), good return is rtn+1 + * DEF DUMMY dummy argument for compatibility with .EMAP + * DEF TABLE[,I] array declaration (dtbl) + * DEF A(N)[,I] actual subscripts (atbl) + * DEF A(N-1)[,I] + * ... + * DEF A(2)[,I] + * DEF A(1)[,I] + * RTN EQU * error return A="20", B="EM" + * RTN+1 EQU *+1 good return B=logical address + * + * TABLE DEC # # dimensions + * DEC -L(N) + * DEC D(N-1) + * DEC -L(N-1) lower bound (n-1)st dim + * DEC D(N-2) (n-2)st dim + * ... + * DEC D(1) 1st dim + * DEC -L(1) lower bound 1st dim + * DEC # # words/element + * OFFSET 1 EMA Low + * OFFSET 2 EMA High + */ +t_stat cpu_ema_eres(uint32 *rtn,uint32 dtbl,uint32 atbl,t_bool debug) +{ +uint32 sum; +if (cpu_ema_resolve(dtbl,atbl,&sum)) { /* calculate subscript */ + AR = sum & 0xffff; + BR = sum >> 16; + if (!(BR & SIGN)) { /* no overflow? */ + (*rtn)++; /* return via good exit */ + return SCPE_OK; + } +} +AR = 0x3230; /* error condition: */ +BR = 0x454d; /* AR = '20', BR = 'EM' */ +return SCPE_OK; /* return via unmodified rtn */ +} + +/* implementation of VIS RTE-IVB EMA support + * .ESEG microcode routine + * Call: + * LDA FIRST first map to set + * LDB N # of maps to set + * .OCT 101475B/105475B + * DEF RTN ptr to return + * DEF TABLE map table + * RTN EQU * error return A="21", B="EM" + * RTN+1 EQU *+1 good return B=logical address + * + * load maps FIRST to FIRST+N from TABLE, with FIRST = FIRST + LOG_START MSEG + * update map table in base page. Set LOG_START MSEG=0 if opcode==105475 + */ +t_stat cpu_ema_eseg(uint32* rtn, uint32 IR, uint32 tbl, t_bool debug) +{ +uint32 xidex,eqt,idext0,idext1; +uint32 msegsz,phys,msegn,last,emasz,pg0,pg1,pg,i,lp; + +if ((BR & SIGN) || BR==0) goto em21; /* #maps not positive? */ +xidex = ReadIO(idx,UMAP); /* read ID extension */ +if (xidex==0) goto em21; +idext0 = ReadWA(xidex+0); /* get 1st word idext */ +msegsz = idext0 & 037; /* S7 MSEG size */ +WriteIO(xidex+0, idext0 | 0100000, SMAP); /* enforce nonstd MSEG */ +idext1 = ReadWA(xidex+1); /* get 2nd word idext */ +phys = idext1 & 01777; /* S5 phys start of EMA */ +msegn = (idext1 >> 11) & 037; /* S9 get logical start MSEG# */ +if (IR & 04000) { /* opcode == 105475? (.VPRG) */ + msegn = 0; /* log start = 0 */ + msegsz = 32; /* size = full range */ +} +last = AR-1 + BR; /* last page */ +if (last > msegsz) goto em21; /* too many? error */ +eqt = ReadIO(xeqt,UMAP); +emasz = (ReadWA(eqt+28) & 01777) - 1; /* S6 EMA size in pages */ + +/* locations 1740...1777 of user base page contain the map entries we need. + * They are normally hidden by BP fence, therefore they have to be accessed by + * another fence-less map register. uCode uses #1 temporarily */ +pg0 = dms_rmap(UMAP+0); /* read map #0 */ +pg1 = dms_rmap(UMAP+1); /* save map #1 */ +dms_wmap(UMAP+1,pg0); /* copy #0 into reg #1 */ +lp = AR + msegn; /* first */ +for (i=0; i emasz) pg |= 0140000; /* write protect if outside */ + pg += phys; /* adjust into EMA page range */ + WriteIO(umaps+lp+i, pg, UMAP); /* copy pg to user map */ +/* printf("MAP val %oB to reg %d (addr=%oB)\n",pg,lp+i,umaps+lp+i); */ + dms_wmap(UMAP+lp+i, pg); /* set DMS reg */ +} +dms_wmap(UMAP+1,pg1); /* restore map #1 */ +O = 0; /* clear overflow */ +(*rtn)++; /* return via good exit */ +return SCPE_OK; + +em21: +AR = 0x3231; /* error condition: */ +BR = 0x454d; /* AR = '21', BR = 'EM' */ +return SCPE_OK; /* return via unmodified rtn */ +} + +/* implementation of VIS RTE-IVB EMA support + * .VSET microcode routine + * Call: + * .OCT 101476B + * DEF RTN return address + * DEF VIN input vector + * DEF VOUT output vector + * DEF MAPS + * OCT #SCALARS + * OCT #VECTORS + * OCT K 1024/(#words/element) + * RTN EQU * error return (B,A) = "VI22" + * RTN+1 EQU *+1 hard return, A = K/IMAX + * RTN+2 EQU *+2 easy return, A = 0, B = 2* #VCTRS + */ +t_stat cpu_ema_vset(uint32* rtn, OPS op, t_bool debug) +{ +uint32 vin = op[0].word; /* S1 */ +uint32 vout = op[1].word; /* S2 */ +uint32 maps = op[2].word; /* S3 */ +uint32 scalars = op[3].word; /* S4 */ +uint32 vectors = op[4].word; /* S5 */ +uint32 k = op[5].word; /* S6 */ +uint32 imax = 0; /* imax S11*/ +uint32 xidex, idext1, mseg, addr, i, MA; +t_bool negflag = FALSE; + +for (i=0; i> 1) & MSEGMASK; /* S9 get logical start MSEG */ + +for (i=0; i> 10) & 0xffff; /* get page */ + WriteW(maps++, addr); /* save page# */ + WriteW(maps++, addr+1); /* save next page# as well */ + MA = ReadW(vin++); /* get index into Y */ + resolve(MA, &MA, 0); + YR = ReadW(MA); /* get index value */ + WriteW(vout++, MA); /* copy address of index */ + if (YR & SIGN) { /* index is negative */ + negflag = TRUE; /* mark a negative index (HARD) */ + YR = (~YR + 1) & DMASK; /* make index positive */ + } + if (imax < YR) imax = YR; /* set maximum index */ + mseg += 04000; /* incr mseg address by 2 more pages */ +} +MA = ReadW(vin); /* get N index into Y */ +resolve(MA, &MA, 0); +YR = ReadW(MA); +WriteW(vout++, MA); vin++; /* copy address of N */ + +if (imax==0) goto easy; /* easy case */ +AR = (uint16) (k / imax); AR++; /* calculate K/IMAX */ +if (negflag) goto hard; /* had a negative index? */ +if (YR > AR) goto hard; + +easy: +(*rtn)++; /* return via exit 2 */ +AR = 0; + +hard: +(*rtn)++; /* return via exit 1 */ +BR = 2 * op[4].word; /* B = 2* vectors */ +return SCPE_OK; + +vi22: /* error condition */ + AR=0x3232; /* AR = '22' */ + BR=0x5649; /* BR = 'VI' */ + return SCPE_OK; /* return via unmodified e->rtn */ +} + +typedef struct ema4 { + uint32 mseg; /* logical start of MSEG */ + uint32 msegsz; /* size of std mseg in pgs */ + uint32 pgoff; /* pg # in EMA containing element */ + uint32 offs; /* offset into page of element */ + uint32 msoff; /* total offset to element in MSEG */ + uint32 emasz; /* size of ema in pgs */ + uint32 msegno; /* # of std mseg */ + uint32 ipgs; /* # of pgs to start of MSEG */ + uint32 npgs; /* # of pgs needed */ + uint32 spmseg; /* first phys pg of MSEG */ +} EMA4; + +static t_bool cpu_ema_emas(uint32 dtbl,uint32 atbl,EMA4* e) +{ +uint32 xidex, eqt; +uint32 sum, msegsz,pgoff,offs,emasz,msegno,msoff,ipgs; + +if (!cpu_ema_resolve(dtbl,atbl,&sum)) return FALSE; /* calculate 32 bit index */ + +xidex = ReadIO(idx,UMAP); /* read ID extension */ +msegsz = ReadWA(xidex+0) & 037; /* S5 # pgs for std MSEG */ +pgoff = sum >> 10; /* S2 page containing element */ +offs = sum & 01777; /* S6 offset in page to element */ +if (pgoff > 1023) return FALSE; /* overflow? */ +eqt = ReadIO(xeqt,UMAP); +emasz = ReadWA(eqt+28) & 01777; /* S EMA size in pages */ +if (pgoff > emasz) return FALSE; /* outside EMA? */ +msegno = pgoff / msegsz; /* S4 # of MSEG */ +msoff = pgoff % msegsz; /* offset within MSEG in pgs */ +ipgs = pgoff - msoff; /* S7 # pgs to start of MSEG */ +msoff = msoff << 10; /* offset within MSEG in words */ +msoff += offs; /* S1 offset to element in words */ + +e->msegsz = msegsz; /* return calculated data */ +e->pgoff = pgoff; +e->offs = offs; +e->emasz = emasz; +e->msegno = msegno; +e->ipgs = ipgs; +e->msoff = msoff; +return TRUE; +} + +static t_bool cpu_ema_mmap01(EMA4* e) +{ +uint32 xidex,idext0, pg, pg0, pg1, i; + +uint32 base = e->mseg >> 10; /* get the # of first MSEG DMS reg */ +xidex = ReadIO(idx,UMAP); /* get ID extension */ +idext0 = ReadWA(xidex+1); + +if (e->npgs==0) return FALSE; /* no pages to map? */ +if ((e->npgs+1+e->ipgs) <= e->emasz) e->npgs++; /* actually map npgs+1 pgs */ + +/* locations 1740...1777 of user base page contain the map entries we need. + * They are normally hidden by BP fence, therefore they have to be accessed by + * another fence-less map register. uCode uses #1, macro code uses $DVCT (==2) + */ +pg0 = dms_rmap(UMAP+0); /* read base page map# */ +pg1 = dms_rmap(UMAP+1); /* save map# 1 */ +dms_wmap(UMAP+1,pg0); /* map #0 into reg #1 */ +for (i=0; (base+i)<32; i++) { + pg = inpgs ? e->spmseg : 0140000; /* write protect if outside */ + WriteIO(umaps+base+i, pg, UMAP); /* copy pg to user map */ +/* printf("MAP val %d to reg %d (addr=%o)\n",pg,base+i,umaps+base+i); */ + dms_wmap(UMAP+base+i, pg); /* set DMS reg */ + e->spmseg++; +} +dms_wmap(UMAP+1,pg1); /* restore map #1 */ + +xidex = ReadIO(idx,UMAP); /* get ID extension */ +idext0 = ReadWA(xidex+0); +if (e->msegno == 0xffff) /* non std mseg */ + idext0 |= 0x8000; /* set nonstd marker */ +else + idext0 = (idext0 & 037) | (e->msegno<<5); /* set new current mseg# */ +WriteIO(xidex, idext0, SMAP); /* save back value */ +AR = 0; /* was successful */ +return TRUE; +} + +static t_bool cpu_ema_mmap02(EMA4* e) +{ +uint32 xidex, eqt, idext1; +uint32 mseg,phys,spmseg,emasz,msegsz,msegno; + +xidex = ReadIO(idx,UMAP); /* get ID extension */ +msegsz = ReadWA(xidex+0) & 037; /* P size of std MSEG */ +idext1 = ReadWA(xidex+1); +mseg = (idext1 >> 1) & MSEGMASK; /* S9 get logical start MSEG */ +phys = idext1 & 01777; /* S phys start of EMA */ +spmseg = phys + e->ipgs; /* S7 phys pg# of MSEG */ +msegno = e->ipgs / msegsz; +if ((e->ipgs % msegsz) != 0) /* non std MSEG? */ + msegno = 0xffff; /* S4 yes, set marker */ +if (e->npgs > msegsz) return FALSE; /* map more pages than MSEG sz? */ +eqt = ReadIO(xeqt,UMAP); +emasz = ReadWA(eqt+28) & 01777; /* B EMA size in pages */ +if ((e->ipgs+e->npgs) > emasz) return FALSE; /* outside EMA? */ +if ((e->ipgs+msegsz) > emasz) /* if MSEG overlaps end of EMA */ + e->npgs = emasz - e->ipgs; /* only map until end of EMA */ + +e->emasz = emasz; /* copy arguments */ +e->msegsz = msegsz; +e->msegno = msegno; +e->spmseg = spmseg; +e->mseg = mseg; +return cpu_ema_mmap01(e); +} + +static t_stat cpu_ema_mmap(uint32 ipage,uint32 npgs, t_bool debug) +{ +uint32 xidex; +EMA4 ema4, *e = &ema4; + +e->ipgs = ipage; /* S6 set the arguments */ +e->npgs = npgs; /* S5 */ + +AR = 0; +xidex = ReadIO(idx,UMAP); +if ((ipage & SIGN) || /* negative page displacement? */ + (npgs & SIGN) || /* negative # of pages? */ + xidex == 0 || /* no EMA? */ + !cpu_ema_mmap02(e)) /* mapping failed? */ + AR = 0177777; /* return with error */ +return SCPE_OK; /* leave */ +} + +static t_bool cpu_ema_emat(EMA4* e) +{ +uint32 xidex,idext0; +uint32 curmseg,phys,msnum,lastpgs; + +xidex = ReadIO(idx,UMAP); /* read ID extension */ +idext0 = ReadWA(xidex+0); /* get current segment */ +curmseg = idext0 >> 5; +if ((idext0 & 0100000) || /* was nonstd MSEG? */ + curmseg != e->msegno) { /* or different MSEG last time? */ + phys = ReadWA(xidex+1) & 01777; /* physical start pg of EMA */ + e->spmseg = phys + e->ipgs; /* physical start pg of MSEG */ + msnum = e->emasz / e->msegsz; /* find last MSEG# */ + lastpgs = e->emasz % e->msegsz; /* #pgs in last MSEG */ + if (lastpgs==0) msnum--; /* adjust # of last MSEG */ + e->npgs = msnum==e->msegno ? lastpgs : e->msegsz; /* for last MSEG, only map available pgs */ + if (!cpu_ema_mmap01(e)) return FALSE; /* map npgs pages at ipgs */ +} +BR = (uint16) (e->mseg + e->msoff); /* return address of element */ +return TRUE; /* and everything done */ +} + +/* .EMIO microcode routine, resolves element addr for EMA array + * and maps the appropriate map segment + * + * Call: + * OCT 105250B + * DEF RTN error return (rtn), good return is rtn+1 + * DEF BUFLEN length of buffer in words (bufl) + * DEF TABLE[,I] array declaration (dtbl) + * DEF A(N)[,I] actual subscripts (atbl) + * DEF A(N-1)[,I] + * ... + * DEF A(2)[,I] + * DEF A(1)[,I] + * RTN EQU * error return A="15", B="EM" + * RTN+1 EQU *+1 good return B=logical address + * + * TABLE DEC # # dimensions + * DEC -L(N) + * DEC D(N-1) + * DEC -L(N-1) lower bound (n-1)st dim + * DEC D(N-2) (n-2)st dim + * ... + * DEC D(1) 1st dim + * DEC -L(1) lower bound 1st dim + * DEC # # words/element + * OFFSET 1 EMA Low + * OFFSET 2 EMA High + */ +static t_stat cpu_ema_emio(uint32* rtn,uint32 bufl,uint32 dtbl,uint32 atbl,t_bool debug) +{ +uint32 xidex, idext1; +uint32 mseg, bufpgs, npgs; +EMA4 ema4, *e = &ema4; + +xidex = ReadIO(idx,UMAP); /* read ID extension */ +if (bufl & SIGN || /* buffer length negative? */ + xidex==0) goto em16; /* no EMA declared? */ + +idext1 = ReadWA(xidex+1); /* |logstrt mseg|d|physstrt ema| */ +mseg = (idext1 >> 1) & MSEGMASK; /* get logical start MSEG */ +if (!cpu_ema_emas(dtbl,atbl,e)) goto em16; /* resolve address */ +bufpgs = (bufl + e->offs) >> 10; /* # of pgs reqd for buffer */ +if ((bufl + e->offs) & 01777) bufpgs++; /* S11 add 1 if not at pg boundary */ +if ((bufpgs + e->pgoff) > e->emasz) goto em16; /* exceeds EMA limit? */ +npgs = (e->msoff + bufl) >> 10; /* # of pgs reqd for MSEG */ +if ((e->msoff + bufl) & 01777) npgs++; /* add 1 if not at pg boundary */ +if (npgs < e->msegsz) { + e->mseg = mseg; /* logical stat of MSEG */ + if (!cpu_ema_emat(e)) goto em16; /* do a std mapping */ +} else { + BR = (uint16) (mseg + e->offs); /* logical start of buffer */ + e->npgs = bufpgs; /* S5 # pgs required */ + e->ipgs = e->pgoff; /* S6 page offset to reqd pg */ + if (!cpu_ema_mmap02(e)) goto em16; /* do nonstd mapping */ +} +(*rtn)++; /* return via good exit */ +return SCPE_OK; + +em16: /* error condition */ +AR=0x3136; /* AR = '16' */ +BR=0x454d; /* BR = 'EM' */ +return SCPE_OK; /* return via unmodified rtn */ +} + +/* .EMAP microcode routine, resolves both EMA/non-EMA calls + * Call: + * OCT 105257B + * DEF RTN error return (rtn), good return is rtn+1 + * DEF ARRAY[,I] array base (abase) + * DEF TABLE[,I] array declaration (dtbl) + * DEF A(N)[,I] actual subscripts (atbl) + * DEF A(N-1)[,I] + * ... + * DEF A(2)[,I] + * DEF A(1)[,I] + * RTN EQU * error return A="15", B="EM" + * RTN+1 EQU *+1 good return B=logical address + * + * TABLE DEC # # dimensions + * DEC -L(N) + * DEC D(N-1) + * DEC -L(N-1) lower bound (n-1)st dim + * DEC D(N-2) (n-2)st dim + * ... + * DEC D(1) 1st dim + * DEC -L(1) lower bound 1st dim + * DEC # # words/element + * OFFSET 1 EMA Low + * OFFSET 2 EMA High + */ +static t_stat cpu_ema_emap(uint32* rtn,uint32 abase,uint32 dtbl,uint32 atbl,t_bool debug) +{ +uint32 xidex, eqt, idext0, idext1; +int32 sub, act, low, ndim, sz; +uint32 offs, pgoff, emasz, phys, msgn, mseg, sum, MA, pg0, pg1; + +xidex = ReadIO(idx,UMAP); /* read ID Extension */ +if (xidex) { /* is EMA declared? */ + idext1 = ReadWA(xidex+1); /* get word 1 of idext */ + mseg = (idext1 >> 1) & MSEGMASK; /* get logical start MSEG */ + if (abase >= mseg) { /* EMA reference? */ + if (!cpu_ema_resolve(dtbl,atbl,&sum)) /* calculate subscript */ + goto em15; + offs = sum & 01777; /* address offset within page */ + pgoff = sum >> 10; /* ema offset in pages */ + if (pgoff > 1023) goto em15; /* overflow? */ + eqt = ReadIO(xeqt,UMAP); + emasz = ReadWA(eqt+28) & 01777; /* EMA size in pages */ + phys = idext1 & 01777; /* physical start pg of EMA */ + if (pgoff > emasz) goto em15; /* outside EMA range? */ + + msgn = mseg >> 10; /* get # of 1st MSEG reg */ + phys += pgoff; + + pg0 = dms_rmap(UMAP+0); /* read base page map# */ + pg1 = dms_rmap(UMAP+1); /* save map# 1 */ + dms_wmap(UMAP+1,pg0); /* map #0 into reg #1 */ + + WriteIO(umaps+msgn, phys, UMAP); /* store 1st mapped pg in user map */ + dms_wmap(UMAP+msgn, phys); /* and set the map register */ + phys = (pgoff+1)==emasz ? 0140000 : phys+1; /* protect 2nd map if end of EMA */ + WriteIO(umaps+msgn+1, phys, UMAP); /* store 2nd mapped pg in user map */ + dms_wmap(UMAP+msgn+1, phys); /* and set the map register */ + + dms_wmap(UMAP+1,pg1); /* restore map #1 */ + + idext0 = ReadWA(xidex+0) | 0100000; /* set NS flag in id extension */ + WriteIO(xidex+0, idext0, SMAP); /* save back value */ + AR = 0; /* was successful */ + BR = (uint16) (mseg + offs); /* calculate log address */ + (*rtn)++; /* return via good exit */ + return SCPE_OK; + } +} /* not EMA reference */ +ndim = ReadW(dtbl++); +if (ndim<0) goto em15; /* negative ´dimensions */ +sum = 0; /* accu for index calc */ +while (ndim > 0) { + MA = ReadW(atbl++); /* get address of A(N) */ + resolve (MA, &MA, 0); + act = ReadW(MA); /* A(N) */ + low = ReadW(dtbl++); /* -L(N) */ + sub = SEXT(act) + SEXT(low); /* subscript */ + if (sub & 0xffff8000) goto em15; /* overflow? */ + sum += sub; /* accumulate */ + sz = ReadW(dtbl++); + sz = SEXT(sz); + if (sz < 0) goto em15; + sum *= sz; /* and multiply with sz of dimension */ + if (sum & 0xffff8000) goto em15; /* overflow? */ + ndim--; +} +BR = (uint16) (abase + sum); /* add displacement */ +(*rtn)++; /* return via good exit */ +return SCPE_OK; + +em15: /* error condition */ + AR=0x3135; /* AR = '15' */ + BR=0x454d; /* BR = 'EM' */ + return SCPE_OK; /* return via unmodified e->rtn */ +} + +t_stat cpu_rte_ema (uint32 IR, uint32 intrq) +{ +t_stat reason = SCPE_OK; +OPS op; +OP_PAT pattern; +uint32 entry, rtn; +t_bool debug = DEBUG_PRI (cpu_dev, DEB_EMA); + +entry = IR & 017; /* mask to entry point */ +pattern = op_ema[entry]; /* get operand pattern */ + +if (pattern != OP_N) { + reason = cpu_ops (pattern, op, intrq); /* get instruction operands */ + if (reason != SCPE_OK) /* evaluation failed? */ + return reason; /* return reason for failure */ + } + +if (debug) { /* debugging? */ + fprintf (sim_deb, ">>CPU EMA: PC = %06o, IR = %06o (", err_PC,IR); /* print preamble and IR */ + fprint_sym (sim_deb, err_PC, (t_value *) &IR, /* print instruction mnemonic */ + NULL, SWMASK('M')); + fputc (')', sim_deb); + + fprint_ops (pattern, op); /* print operands */ + fputc ('\n', sim_deb); /* terminate line */ + } + +switch (entry) { /* decode IR<3:0> */ + case 000: /* .EMIO 105240 (OP_A) */ + rtn = op[0].word; + reason = cpu_ema_emio(&rtn, op[1].word, + op[2].word, PC, debug); /* handle the EMIO instruction */ + PC = rtn; + if (debug) + fprintf (sim_deb, ">>CPU EMA: return .EMIO: AR = %06o, BR = %06o, rtn=%s\n", + AR, BR, PC==op[0].word?"error":"good"); + break; + + case 001: /* .MMAP 105241 (OP_AKK) */ + reason = cpu_ema_mmap(op[1].word, + op[2].word, debug); /* handle the MMAP instruction */ + if (debug) + fprintf (sim_deb, ">>CPU EMA: return .MMAP: AR = %06o\n",AR); + break; + + case 002: /* [test] 105242 (OP_N) */ + /* effectively, this code just returns without error: + * real microcode will set S register to 102077B when in single step mode */ + if (sim_step==1) { + if (debug) + fprintf(sim_deb, ">>CPU EMA: EMA option 92067 correctly installed: S=102077\n"); + SR = 0102077; + } + break; + + case 017: /* .EMAP 105247 (OP_A) */ + rtn = op[0].word; /* error return */ + reason = cpu_ema_emap(&rtn, op[1].word, + op[2].word, PC, debug); /* handle the EMAP instruction */ + PC = rtn; + if (debug) { + fprintf (sim_deb, ">>CPU EMA: return .EMAP: AR = %06o, BR = %06o, rtn=%s\n", + AR, BR, PC==op[0].word?"error":"good"); + } + break; + + default: /* others undefined */ + reason = stop_inst; + } + +return reason; +} diff --git a/HP2100/hp2100_cpu6.c b/HP2100/hp2100_cpu6.c index 5606a178..efa3565f 100644 --- a/HP2100/hp2100_cpu6.c +++ b/HP2100/hp2100_cpu6.c @@ -1,821 +1,828 @@ -/* hp2100_cpu6.c: HP 1000 RTE-6/VM OS instructions - - Copyright (c) 2006-2010, J. David Bryan - - 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 - THE AUTHOR 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 the author shall not be - used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from the author. - - CPU6 RTE-6/VM OS instructions - - 29-Oct-10 JDB DMA channels renamed from 0,1 to 1,2 to match documentation - 18-Sep-08 JDB Corrected .SIP debug formatting - 11-Sep-08 JDB Moved microcode function prototypes to hp2100_cpu1.h - 05-Sep-08 JDB Removed option-present tests (now in UIG dispatchers) - 26-Jun-08 JDB Rewrote device I/O to model backplane signals - 27-Nov-07 JDB Implemented OS instructions - 26-Sep-06 JDB Created - - Primary references: - - HP 1000 M/E/F-Series Computers Technical Reference Handbook - (5955-0282, Mar-1980) - - HP 1000 M/E/F-Series Computers Engineering and Reference Documentation - (92851-90001, Mar-1981) - - Macro/1000 Reference Manual (92059-90001, Dec-1992) - - Additional references are listed with the associated firmware - implementations, as are the HP option model numbers pertaining to the - applicable CPUs. -*/ - - -#include -#include "hp2100_defs.h" -#include "hp2100_cpu.h" -#include "hp2100_cpu1.h" - - -/* external variables */ - -extern jmp_buf save_env; /* MP abort handler */ - - -/* Offsets to data and addresses within RTE. */ - -static const uint32 xi = 0001647; /* XI address */ -static const uint32 intba = 0001654; /* INTBA address */ -static const uint32 intlg = 0001655; /* INTLG address */ -static const uint32 eqt1 = 0001660; /* EQT1 address */ -static const uint32 eqt11 = 0001672; /* EQT11 address */ -static const uint32 pvcn = 0001712; /* PVCN address */ -static const uint32 xsusp = 0001730; /* XSUSP address */ -static const uint32 dummy = 0001737; /* DUMMY address */ -static const uint32 mptfl = 0001770; /* MPTFL address */ -static const uint32 eqt12 = 0001771; /* EQT12 address */ -static const uint32 eqt15 = 0001774; /* EQT15 address */ -static const uint32 vctr = 0002000; /* VCTR address */ - -static const uint32 CLC_0 = 0004700; /* CLC 0 instruction */ -static const uint32 STC_0 = 0000700; /* STC 0 instruction */ -static const uint32 CLF_0 = 0001100; /* CLF 0 instruction */ -static const uint32 STF_0 = 0000100; /* STF 0 instruction */ -static const uint32 SFS_0_C = 0003300; /* SFS 0,C instruction */ - -enum vctr_offsets { dms_offset = 0, /* DMS status */ - int_offset, /* interrupt system status */ - sc_offset, /* select code */ - clck_offset, /* TBG IRQ handler */ - cic4_offset, /* illegal IRQ handler */ - cic2_offset, /* device IRQ handler */ - sked_offset, /* prog sched IRQ handler */ - rqst_offset, /* EXEC request handler */ - cic_offset, /* IRQ location */ - perr_offset, /* parity error IRQ handler */ - mper_offset, /* memory protect IRQ handler */ - lxnd_offset }; /* $LIBR return */ - - -/* RTE-6/VM Operating System Instructions - - The OS instructions were added to acccelerate certain time-consuming - operations of the RTE-6/VM operating system, HP product number 92084A. - Microcode was available for the E- and F-Series; the M-Series used software - equivalents. - - Option implementation by CPU was as follows: - - 2114 2115 2116 2100 1000-M 1000-E 1000-F - ------ ------ ------ ------ ------ ------ ------ - N/A N/A N/A N/A N/A 92084A 92084A - - The routines are mapped to instruction codes as follows: - - Instr. 1000-E/F Description - ------ -------- ---------------------------------------------- - $LIBR 105340 Enter privileged/reentrant library routine - $LIBX 105341 Exit privileged/reentrant library routine - .TICK 105342 TBG tick interrupt handler - .TNAM 105343 Find ID segment that matches name - .STIO 105344 Configure I/O instructions - .FNW 105345 Find word with user increment - .IRT 105346 Interrupt return processing - .LLS 105347 Linked list search - - .SIP 105350 Skip if interrupt pending - .YLD 105351 .SIP completion return point - .CPM 105352 Compare words LT/EQ/GT - .ETEQ 105353 Set up EQT pointers in base page - .ENTN 105354 Transfer parameter addresses (utility) - $OTST * 105355 OS firmware self test - .ENTC 105356 Transfer parameter addresses (priv/reent) - .DSPI 105357 Set display indicator - - Opcodes 105354-105357 are "dual use" instructions that take different - actions, depending on whether they are executed from a trap cell during an - interrupt. When executed from a trap cell, they have these actions: - - Instr. 1000-E/F Description - ------ -------- ---------------------------------------------- - $DCPC * 105354 DCPC channel interrupt processing - $MPV * 105355 MP/DMS/PE interrupt processing - $DEV * 105356 Standard device interrupt processing - $TBG * 105357 TBG interrupt processing - - * These mnemonics are recognized by symbolic examine/deposit but are not - official HP mnemonics. - - Implementation notes: - - 1. The microcode differentiates between interrupt processing and normal - execution of the "dual use" instructions by testing the CPU flag. - Interrupt vectoring sets the flag; a normal instruction fetch clears it. - Under simulation, interrupt vectoring is indicated by the value of the - "iotrap" parameter (0 = normal instruction, 1 = trap cell instruction). - - 2. The operand patterns for .ENTN and .ENTC normally would be coded as - "OP_A", as each takes a single address as a parameter. However, because - they might also be executed from a trap cell, we cannot assume that P+1 - is an address, or we might cause a DM abort when trying to resolve - indirects. Therefore, "OP_A" handling is done within each routine, once - the type of use is determined. - - 3. The microcode for .ENTC, .ENTN, .FNW, .LLS, .TICK, and .TNAM explicitly - checks for interrupts during instruction execution. In addition, the - .STIO, .CPM, and .LLS instructions implicitly check for interrupts during - parameter indirect resolution. Because the simulator calculates - interrupt requests only between instructions, this behavior is not - simulated. - - 4. The microcode executes certain I/O instructions (e.g., CLF 0) by building - the instruction in the IR and executing an IOG micro-order. We simulate - this behavior by calling the "iogrp" handler with the appropriate - instruction, rather than manipulating the I/O system directly, so that we - will remain unaffected by any future changes to the underlying I/O - simulation structure. - - 5. The $OTST and .DSPI microcode uses features (reading the RPL switches and - boot loader ROM data, loading the display register) that are not - simulated. The remaining functions of the $OTST instruction are - provided. The .DSPI instruction is a NOP or unimplemented instruction - stop. - - 6. Because of the volume of calls to the OS firmware, debug printouts - attempt to write only one line per instruction invocation. This means - that calling and returned register values are printed separately, with a - newline added at the end of execution. However, many instructions can MP - or DM abort, either intentionally or due to improper use. That would - leave debug lines without the required trailing newlines. - - There are two ways to address this: either we could replace the CPU's - setjmp buffer with one that points to a routine that adds the missing - newline, or we can add a semaphore that is tested on entry to see if it - is already set, implying a longjmp occurred, and then add the newline if - so. The latter would add the newline when the MP trap cell instruction - was entered or when the next user-level instruction was executed. - However, the merged-line problem would still exist if some other module - generated intervening debug printouts. So we do the former. This does - mean that this routine must be changed if the MP abort mechanism is - changed. - - 7. The $LIBX instruction is executed to complete either a privileged or - reentrant execution. In the former case, the privileged nest counter - ($PVCN) is decremented. In the latter, $PVCN decrement is attempted but - the write will trap with an MP violation, as reentrant routines execute - with the interrupt system on. RTE will then complete the release of - memory allocated for the original $LIBR call. - - 8. The documentation for the .SIP and .YLD instructions is misleading in - several places. Comments in the RTE $SIP source file say that .SIP - doesn't return if a "known" interrupt is pending. Actually, .SIP always - returns, either to P+1 for no pending interrupt, or to P+2 if one is - pending. There is no check for "known" interrupt handlers. The - microcode source comments say that the interrupting select code is - returned in the B register. Actually, the B register is unchanged. The - RTE Tech Specs say that .SIP "services any pending system interrupts." - Actually, .SIP only checks for interrupts; no servicing is performed. - - For .YLD, the microcode comments say that two parameters are passed: the - new P value, and the interrupting select code. Actually, only the new P - value is passed. - - The .SIP and .YLD simulations follow the actual microcode rather than the - documentation. - - Additional references: - - RTE-6/VM OS Microcode Source (92084-18831, revision 8). - - RTE-6/VM Technical Specifications (92084-90015, Apr-1983). -*/ - - -/* Save the CPU registers. - - The CPU registers are saved in the current ID segment in preparation for - interrupt handling. Although the RTE base page has separate pointers for the - P, A, B, and E/O registers, they are always contiguous, and the microcode - simply increments the P-register pointer (XSUSP) to store the remaining - values. - - This routine is called from the trap cell interrupt handlers and from the - $LIBX processor. In the latter case, the privileged system interrupt - handling is not required, so it is bypassed. In either case, the current map - will be the system map when we are called. -*/ - -static t_stat cpu_save_regs (uint32 iotrap) -{ -uint16 save_area, priv_fence; -t_stat reason = SCPE_OK; - -save_area = ReadW (xsusp); /* addr of PABEO save area */ - -WriteW (save_area + 0, PC); /* save P */ -WriteW (save_area + 1, AR); /* save A */ -WriteW (save_area + 2, BR); /* save B */ -WriteW (save_area + 3, (E << 15) & SIGN | O & 1); /* save E and O */ - -save_area = ReadW (xi); /* addr of XY save area */ -WriteWA (save_area + 0, XR); /* save X (in user map) */ -WriteWA (save_area + 1, YR); /* save Y (in user map) */ - -if (iotrap) { /* do priv setup only if IRQ */ - priv_fence = ReadW (dummy); /* get priv fence select code */ - - if (priv_fence) { /* privileged system? */ - reason = iogrp (STC_0 + priv_fence, iotrap); /* STC SC on priv fence */ - reason = iogrp (CLC_0 + DMA1, iotrap); /* CLC 6 to inh IRQ on DCPC 1 */ - reason = iogrp (CLC_0 + DMA2, iotrap); /* CLC 7 to inh IRQ on DCPC 2 */ - reason = iogrp (STF_0, iotrap); /* turn interrupt system back on */ - } - } - -return reason; -} - - -/* Save the machine state at interrupt. - - This routine is called from each of the trap cell instructions. Its purpose - is to save the complete state of the machine in preparation for interrupt - handling. - - For the MP/DMS/PE interrupt, the interrupting device must not be cleared and - the CPU registers must not be saved until it is established that the - interrupt is not caused by a parity error. Parity errors cannot be - inhibited, so the interrupt may have occurred while in RTE. Saving the - registers would overwrite the user's registers that were saved at RTE entry. - - Note that the trap cell instructions are dual-use and invoke this routine - only when they are executed during interrupts. Therefore, the current map - will always be the system map when we are called. -*/ - -static t_stat cpu_save_state (uint32 iotrap) -{ -uint16 vectors; -uint32 saved_PC, int_sys_off; -t_stat reason; - -saved_PC = PC; /* save current PC */ -reason = iogrp (SFS_0_C, iotrap); /* turn interrupt system off */ -int_sys_off = (PC == saved_PC); /* set flag if already off */ -PC = saved_PC; /* restore PC in case it bumped */ - -vectors = ReadW (vctr); /* get address of vectors (in SMAP) */ - -WriteW (vectors + dms_offset, dms_upd_sr ()); /* save DMS status (SSM) */ -WriteW (vectors + int_offset, int_sys_off); /* save int status */ -WriteW (vectors + sc_offset, intaddr); /* save select code */ - -WriteW (mptfl, 1); /* show MP is off */ - -if (intaddr != 5) { /* only if not MP interrupt */ - reason = iogrp (CLF_0 + intaddr, iotrap); /* issue CLF to device */ - cpu_save_regs (iotrap); /* save CPU registers */ - } - -return reason; -} - - -/* Get the interrupt table entry corresponding to a select code. - - Return the word in the RTE interrupt table that corresponds to the - interrupting select code. Return 0 if the select code is beyond the end of - the table. -*/ - -uint32 cpu_get_intbl (uint32 select_code) -{ -uint16 interrupt_table; /* interrupt table (starts with SC 06) */ -uint16 table_length; /* length of interrupt table */ - -interrupt_table = ReadW (intba); /* get int table address */ -table_length = ReadW (intlg); /* get int table length */ - -if (select_code - 6 > table_length) /* SC beyond end of table? */ - return 0; /* return 0 for illegal interrupt */ -else - return ReadW (interrupt_table + select_code - 6); /* else return table entry */ -} - - -/* RTE-6/VM OS instruction dispatcher. - - Debugging printouts are provided with the OS and OSTBG debug flags. The OS - flag enables tracing for all instructions except for the three-instruction - sequence executed for the time-base generator interrupt ($TBG, .TICK, and - .IRT). The OSTBG flag enables tracing for just the TBG sequence. The flags - are separate, as the TBG generates 100 interrupts per second. Use caution - when specifying the OSTBG flag, as the debug output file will grow rapidly. - Note that the OS flag enables the .IRT instruction trace for all cases except - a TBG interrupt. - - The default (user microcode) dispatcher will allow the firmware self-test - instruction (105355) to execute as NOP. This is because RTE-6/VM will always - test for the presence of OS and VMA firmware on E/F-Series machines. If the - firmware is not present, then these instructions will return to P+1, and RTE - will then HLT 21. This means that RTE-6/VM will not run on an E/F-Series - machine without the OS and VMA firmware. - - Howwever, RTE allows the firmware instructions to be disabled for debugging - purposes. If the firmware is present and returns to P+2 but sets the X - register to 0, then RTE will use software equivalents. We enable this - condition when the OS firmware is enabled (SET CPU VMA), the OS debug flag is - set (SET CPU DEBUG=OS), but debug output has been disabled (SET CONSOLE - NODEBUG). That is: - - OS Debug - Firmware Debug Output Tracing Self-Test Instruction - ======== ===== ====== ======= ===================== - disabled x x off NOP - enabled clear x off X = revision code - enabled set off off X = 0 - enabled set on on X = revision code -*/ - -static const OP_PAT op_os[16] = { - OP_A, OP_A, OP_N, OP_N, /* $LIBR $LIBX .TICK .TNAM */ - OP_A, OP_K, OP_A, OP_KK, /* .STIO .FNW .IRT .LLS */ - OP_N, OP_C, OP_KK, OP_N, /* .SIP .YLD .CPM .ETEQ */ - OP_N, OP_N, OP_N, OP_N /* .ENTN $OTST .ENTC .DSPI */ - }; - -t_stat cpu_rte_os (uint32 IR, uint32 intrq, uint32 iotrap) -{ -t_stat reason = SCPE_OK; -OPS op; -OP_PAT pattern; -uint32 entry, count, cp, sa, da, i, ma; -uint16 vectors, save_area, priv_fence, eoreg, eqt, key; -char test[6], target[6]; -jmp_buf mp_handler; -int abortval; -t_bool debug_print; -static t_bool tbg_tick = FALSE; /* set if processing TBG interrupt */ - -entry = IR & 017; /* mask to entry point */ -pattern = op_os[entry]; /* get operand pattern */ - -if (pattern != OP_N) - if (reason = cpu_ops (pattern, op, intrq)) /* get instruction operands */ - return reason; - -tbg_tick = tbg_tick || (IR == 0105357) && iotrap; /* set TBG interrupting flag */ - -debug_print = (DEBUG_PRI (cpu_dev, DEB_OS) && !tbg_tick) || - (DEBUG_PRI (cpu_dev, DEB_OSTBG) && tbg_tick); - -if (debug_print) { - fprintf (sim_deb, ">>CPU OS: IR = %06o (", IR); /* print preamble and IR */ - fprint_sym (sim_deb, (iotrap ? intaddr : err_PC), /* print instruction mnemonic */ - (t_value *) &IR, NULL, SWMASK('M')); - fputc (')', sim_deb); - - fprint_ops (pattern, op); /* print operands */ - - memcpy (mp_handler, save_env, sizeof (jmp_buf)); /* save original MP handler */ - abortval = setjmp (save_env); /* set new MP abort handler */ - - if (abortval != 0) { /* MP abort? */ - fputs ("...MP abort\n", sim_deb); /* report it and terminate line */ - memcpy (save_env, mp_handler, sizeof (jmp_buf)); /* restore original MP handler */ - longjmp (save_env, abortval); /* transfer to MP handler */ - } - } - -switch (entry) { /* decode IR<3:0> */ - - case 000: /* $LIBR 105340 (OP_A) */ - if ((op[0].word != 0) || /* reentrant call? */ - (mp_control && (ReadW (dummy) != 0))) { /* or priv call + MP on + priv sys? */ - if (dms_ump) { /* called from user map? */ - dms_viol (err_PC, MVI_PRV); /* privilege violation */ - } - dms_ump = SMAP; /* set system map */ - - vectors = ReadW (vctr); /* get address of vectors (in SMAP) */ - PC = ReadW (vectors + mper_offset); /* vector to $MPER for processing */ - } - - else { /* privileged call */ - if (mp_control) { /* memory protect on? */ - mp_control = CLEAR; /* turn it off */ - reason = iogrp (CLF_0, iotrap); /* turn interrupt system off */ - WriteW (mptfl, 1); /* show MP is off */ - save_area = ReadW (xsusp); /* get addr of P save area */ - - if (dms_ump) /* user map current? */ - WriteWA (save_area, (PC - 2) & VAMASK); /* set point of suspension */ - else /* system map current */ - WriteW (save_area, (PC - 2) & VAMASK); /* set point of suspension */ - } - - WriteW (pvcn, (ReadW (pvcn) + 1) & DMASK); /* increment priv nest counter */ - } - break; - - case 001: /* $LIBX 105341 (OP_A) */ - PC = ReadW (op[0].word); /* set P to return point */ - count = (ReadW (pvcn) - 1) & DMASK; /* decrement priv nest counter */ - WriteW (pvcn, count); /* write it back */ - - if (count == 0) { /* end of priv mode? */ - dms_ump = SMAP; /* set system map */ - reason = cpu_save_regs (iotrap); /* save registers */ - vectors = ReadW (vctr); /* get address of vectors */ - PC = ReadW (vectors + lxnd_offset); /* vector to $LXND for processing */ - } - break; - - case 002: /* .TICK 105342 (OP_N) */ - if (debug_print) /* debugging? */ - fprint_regs (",", REG_A | REG_B, 0); /* print entry registers */ - - do { - eqt = (ReadW (AR) + 1) & DMASK; /* bump timeout from EQT15 */ - - if (eqt != 1) { /* was timeout active? */ - WriteW (AR, eqt); /* yes, write it back */ - - if (eqt == 0) /* did timeout expire? */ - break; /* P+0 return for timeout */ - } - - AR = (AR + 15) & DMASK; /* point at next EQT15 */ - BR = (BR - 1) & DMASK; /* decrement count of EQTs */ - } while ((BR > 0) && (eqt != 0)); /* loop until timeout or done */ - - if (BR == 0) /* which termination condition? */ - PC = (PC + 1) & VAMASK; /* P+1 return for no timeout */ - - if (debug_print) /* debugging? */ - fprint_regs ("; result:", /* print return registers */ - REG_A | REG_B | REG_P_REL, - err_PC + 1); - break; - - case 003: /* .TNAM 105343 (OP_N) */ - if (debug_print) /* debugging? */ - fprint_regs (",", REG_A | REG_B, 0); /* print entry registers */ - - E = 1; /* preset flag for not found */ - cp = (BR << 1) & DMASK; /* form char addr (B is direct) */ - - for (i = 0; i < 5; i++) { /* copy target name */ - target[i] = (char) ReadB (cp); /* name is only 5 chars */ - cp = (cp + 1) & DMASK; - } - - if ((target[0] == '\0') && (target[1] == '\0')) /* if name is null, */ - break; /* return immed to P+0 */ - - key = ReadW (AR); /* get first keyword addr */ - - while (key != 0) { /* end of keywords? */ - cp = ((key + 12) << 1) & DMASK; /* form char addr of name */ - - for (i = 0; i < 6; i++) { /* copy test name */ - test[i] = (char) ReadB (cp); /* name is only 5 chars */ - cp = (cp + 1) & DMASK; /* but copy 6 to get flags */ - } - - if (strncmp (target, test, 5) == 0) { /* names match? */ - AR = (key + 15) & DMASK; /* A = addr of IDSEG [15] */ - BR = key; /* B = addr of IDSEG [0] */ - E = (uint32) ((test[5] >> 4) & 1); /* E = short ID segment bit */ - PC = (PC + 1) & VAMASK; /* P+1 for found return */ - break; - } - - AR = (AR + 1) & DMASK; /* bump to next keyword */ - key = ReadW (AR); /* get next keyword */ - }; - - if (debug_print) /* debugging? */ - fprint_regs ("; result:", /* print return registers */ - REG_A | REG_B | REG_E | REG_P_REL, - err_PC + 1); - break; - - case 004: /* .STIO 105344 (OP_A) */ - count = op[0].word - PC; /* get count of operands */ - - if (debug_print) /* debugging? */ - fprintf (sim_deb, /* print registers on entry */ - ", A = %06o, count = %d", AR, count); - - for (i = 0; i < count; i++) { - ma = ReadW (PC); /* get operand address */ - - if (reason = resolve (ma, &ma, intrq)) { /* resolve indirect */ - PC = err_PC; /* IRQ restarts instruction */ - break; - } - - WriteW (ma, ReadW (ma) & ~I_DEVMASK | AR); /* set SC into instruction */ - PC = (PC + 1) & VAMASK; /* bump to next */ - } - break; - - case 005: /* .FNW 105345 (OP_K) */ - if (debug_print) /* debugging? */ - fprint_regs (",", REG_A | REG_B | REG_X, 0); /* print entry registers */ - - while (XR != 0) { /* all comparisons done? */ - key = ReadW (BR); /* read a buffer word */ - - if (key == AR) { /* does it match? */ - PC = (PC + 1) & VAMASK; /* P+1 found return */ - break; - } - - BR = (BR + op[0].word) & DMASK; /* increment buffer ptr */ - XR = (XR - 1) & DMASK; /* decrement remaining count */ - } - /* P+0 not found return */ - if (debug_print) /* debugging? */ - fprint_regs ("; result:", /* print return registers */ - REG_A | REG_B | REG_X | REG_P_REL, - err_PC + 2); - break; - - case 006: /* .IRT 105346 (OP_A) */ - save_area = ReadW (xsusp); /* addr of PABEO save area */ - - WriteW (op[0].word, ReadW (save_area + 0)); /* restore P to DEF RTN */ - - AR = ReadW (save_area + 1); /* restore A */ - BR = ReadW (save_area + 2); /* restore B */ - - eoreg = ReadW (save_area + 3); /* get combined E and O */ - E = (eoreg >> 15) & 1; /* restore E */ - O = eoreg & 1; /* restore O */ - - save_area = ReadW (xi); /* addr of XY save area */ - XR = ReadWA (save_area + 0); /* restore X (from user map) */ - YR = ReadWA (save_area + 1); /* restore Y (from user map) */ - - reason = iogrp (CLF_0, iotrap); /* turn interrupt system off */ - WriteW (mptfl, 0); /* show MP is on */ - - priv_fence = ReadW (dummy); /* get priv fence select code */ - - if (priv_fence) { /* privileged system? */ - reason = iogrp (CLC_0 + priv_fence, iotrap); /* CLC SC on priv fence */ - reason = iogrp (STF_0 + priv_fence, iotrap); /* STF SC on priv fence */ - - if (cpu_get_intbl (DMA1) & SIGN) /* DCPC 1 active? */ - reason = iogrp (STC_0 + DMA1, iotrap); /* STC 6 to enable IRQ on DCPC 1 */ - - if (cpu_get_intbl (DMA2) & SIGN) /* DCPC 2 active? */ - reason = iogrp (STC_0 + DMA2, iotrap); /* STC 7 to enable IRQ on DCPC 2 */ - } - - tbg_tick = 0; /* .IRT terminates TBG servicing */ - break; - - case 007: /* .LLS 105347 (OP_KK) */ - if (debug_print) /* debugging? */ - fprint_regs (",", REG_A | REG_B | REG_E, 0); /* print entry registers */ - - AR = AR & ~SIGN; /* clear sign bit of A */ - - while ((AR != 0) && ((AR & SIGN) == 0)) { /* end of list or bad list? */ - key = ReadW ((AR + op[1].word) & VAMASK); /* get key value */ - - if ((E == 0) && (key == op[0].word) || /* for E = 0, key = arg? */ - (E != 0) && (key > op[0].word)) /* for E = 1, key > arg? */ - break; /* search is done */ - - BR = AR; /* B = last link */ - AR = ReadW (AR); /* A = next link */ - } - - if (AR == 0) /* exhausted list? */ - PC = (PC + 1) & VAMASK; /* P+1 arg not found */ - else if ((AR & SIGN) == 0) /* good link? */ - PC = (PC + 2) & VAMASK; /* P+2 arg found */ - /* P+0 bad link */ - if (debug_print) /* debugging? */ - fprint_regs ("; result:", /* print return registers */ - REG_A | REG_B | REG_P_REL, - err_PC + 3); - break; - - case 010: /* .SIP 105350 (OP_N) */ - reason = iogrp (STF_0, iotrap); /* turn interrupt system on */ - intrq = calc_int (); /* check for interrupt requests */ - reason = iogrp (CLF_0, iotrap); /* turn interrupt system off */ - - if (intrq) /* was interrupt pending? */ - PC = (PC + 1) & VAMASK; /* P+1 return for pending IRQ */ - /* P+0 return for no pending IRQ */ - if (debug_print) /* debugging? */ - fprintf (sim_deb, /* print return registers */ - ", CIR = %02o, return = P+%d", - intrq, PC - (err_PC + 1)); - break; - - case 011: /* .YLD 105351 (OP_C) */ - PC = op[0].word; /* pick up point of resumption */ - reason = iogrp (STF_0, iotrap); /* turn interrupt system on */ - ion_defer = 0; /* kill defer so irq occurs immed */ - break; - - case 012: /* .CPM 105352 (OP_KK) */ - if (INT16 (op[0].word) > INT16 (op[1].word)) - PC = (PC + 2) & VAMASK; /* P+2 arg1 > arg2 */ - else if (INT16 (op[0].word) < INT16 (op[1].word)) - PC = (PC + 1) & VAMASK; /* P+1 arg1 < arg2 */ - /* P+0 arg1 = arg2 */ - if (debug_print) /* debugging? */ - fprint_regs (",", REG_P_REL, err_PC + 3); /* print return registers */ - break; - - case 013: /* .ETEQ 105353 (OP_N) */ - eqt = ReadW (eqt1); /* get addr of EQT1 */ - - if (AR != eqt) { /* already set up? */ - for (eqt = eqt1; eqt <= eqt11; eqt++) /* init EQT1-EQT11 */ - WriteW (eqt & VAMASK, (AR++ & DMASK)); - for (eqt = eqt12; eqt <= eqt15; eqt++) /* init EQT12-EQT15 */ - WriteW (eqt & VAMASK, (AR++ & DMASK)); /* (not contig with EQT1-11) */ - } - - if (debug_print) /* debugging? */ - fprintf (sim_deb, /* print return registers */ - ", A = %06o, EQT1 = %06o", AR, eqt); - break; - - case 014: /* .ENTN/$DCPC 105354 (OP_N) */ - if (iotrap) { /* in trap cell? */ - reason = cpu_save_state (iotrap); /* DMA interrupt */ - AR = cpu_get_intbl (intaddr) & ~SIGN; /* get intbl value and strip sign */ - goto DEVINT; /* vector by intbl value */ - } - - else { /* .ENTN instruction */ - ma = (PC - 2) & VAMASK; /* get addr of entry point */ - - ENTX: /* enter here from .ENTC */ - reason = cpu_ops (OP_A, op, intrq); /* get instruction operand */ - da = op[0].word; /* get addr of 1st formal */ - count = ma - da; /* get count of formals */ - sa = ReadW (ma); /* get addr of 1st actual */ - WriteW (ma, (sa + count) & VAMASK); /* adjust return point to skip actuals */ - - if (debug_print) /* debugging? */ - fprintf (sim_deb, /* print entry registers */ - ", op [0] = %06o, pcount = %d", - da, count); - - for (i = 0; i < count; i++) { /* parameter loop */ - ma = ReadW (sa); /* get addr of actual */ - sa = (sa + 1) & VAMASK; /* increment address */ - - if (reason = resolve (ma, &ma, intrq)) { /* resolve indirect */ - PC = err_PC; /* irq restarts instruction */ - break; - } - - WriteW (da, ma); /* put addr into formal */ - da = (da + 1) & VAMASK; /* increment address */ - } - - if (entry == 016) /* call was .ENTC? */ - AR = sa; /* set A to return address */ - } - break; - - case 015: /* $OTST/$MPV 105355 (OP_N) */ - if (iotrap) { /* in trap cell? */ - reason = cpu_save_state (iotrap); /* MP/DMS/PE interrupt */ - vectors = ReadW (vctr); /* get address of vectors (in SMAP) */ - - if (mp_viol & SIGN) { /* parity error? */ - WriteW (vectors + cic_offset, PC); /* save point of suspension in $CIC */ - PC = ReadW (vectors + perr_offset); /* vector to $PERR for processing */ - } - - else { /* MP/DMS violation */ - cpu_save_regs (iotrap); /* save CPU registers */ - PC = ReadW (vectors + rqst_offset); /* vector to $RQST for processing */ - } - - if (debug_print) { /* debugging? */ - fprint_regs (",", REG_CIR, 0); /* print interrupt source */ - /* and cause */ - if (mp_viol & SIGN) - fputs (", parity error", sim_deb); - else if (mp_mevff) - fputs (", DM violation", sim_deb); - else - fputs (", MP violation", sim_deb); - } - } - - else { /* self-test instruction */ - YR = 0000000; /* RPL switch (not implemented) */ - AR = 0000000; /* LDR [B] (not implemented) */ - SR = 0102077; /* test passed code */ - PC = (PC + 1) & VAMASK; /* P+1 return for firmware OK */ - - if ((cpu_dev.dctrl & DEB_OS) && /* OS debug flag set, */ - (sim_deb == NULL)) /* but debugging disabled? */ - XR = 0; /* rev = 0 means RTE won't use ucode */ - else - XR = 010; /* firmware revision 10B = 8 */ - - if (debug_print) /* debugging? */ - fprint_regs (",", REG_X | REG_P_REL, /* print return registers */ - err_PC + 1); - } - break; - - case 016: /* .ENTC/$DEV 105356 (OP_N) */ - if (iotrap) { /* in trap cell? */ - reason = cpu_save_state (iotrap); /* device interrupt */ - AR = cpu_get_intbl (intaddr); /* get interrupt table value */ - - DEVINT: - vectors = ReadW (vctr); /* get address of vectors (in SMAP) */ - - if (INT16 (AR) < 0) /* negative (program ID)? */ - PC = ReadW (vectors + sked_offset); /* vector to $SKED for processing */ - else if (AR > 0) /* positive (EQT address)? */ - PC = ReadW (vectors + cic2_offset); /* vector to $CIC2 for processing */ - else /* zero (illegal interrupt) */ - PC = ReadW (vectors + cic4_offset); /* vector to $CIC4 for processing */ - - if (debug_print) /* debugging? */ - fprintf (sim_deb, /* print return registers */ - ", CIR = %02o, INTBL = %06o", - intaddr, AR); - } - - else { /* .ENTC instruction */ - ma = (PC - 4) & VAMASK; /* get addr of entry point */ - goto ENTX; /* continue with common processing */ - } - break; - - case 017: /* .DSPI/$TBG 105357 (OP_N) */ - if (iotrap) { /* in trap cell? */ - reason = cpu_save_state (iotrap); /* TBG interrupt */ - vectors = ReadW (vctr); /* get address of vectors (in SMAP) */ - PC = ReadW (vectors + clck_offset); /* vector to $CLCK for processing */ - - if (debug_print) /* debugging? */ - fprint_regs (",", REG_CIR, 0); /* print interrupt source */ - } - - else /* .DSPI instruction */ - reason = stop_inst; /* not implemented yet */ - - break; - } - -if (debug_print) { /* debugging? */ - fputc ('\n', sim_deb); /* terminate line */ - memcpy (save_env, mp_handler, sizeof (jmp_buf)); /* restore original MP handler */ - } - -return reason; -} +/* hp2100_cpu6.c: HP 1000 RTE-6/VM OS instructions + + Copyright (c) 2006-2014, J. David Bryan + + 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 + THE AUTHOR 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 the author shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from the author. + + CPU6 RTE-6/VM OS instructions + + 24-Dec-14 JDB Added casts for explicit downward conversions + 18-Mar-13 JDB Use MP abort handler declaration in hp2100_cpu.h + 09-May-12 JDB Separated assignments from conditional expressions + 29-Oct-10 JDB DMA channels renamed from 0,1 to 1,2 to match documentation + 18-Sep-08 JDB Corrected .SIP debug formatting + 11-Sep-08 JDB Moved microcode function prototypes to hp2100_cpu1.h + 05-Sep-08 JDB Removed option-present tests (now in UIG dispatchers) + 26-Jun-08 JDB Rewrote device I/O to model backplane signals + 27-Nov-07 JDB Implemented OS instructions + 26-Sep-06 JDB Created + + Primary references: + - HP 1000 M/E/F-Series Computers Technical Reference Handbook + (5955-0282, Mar-1980) + - HP 1000 M/E/F-Series Computers Engineering and Reference Documentation + (92851-90001, Mar-1981) + - Macro/1000 Reference Manual (92059-90001, Dec-1992) + + Additional references are listed with the associated firmware + implementations, as are the HP option model numbers pertaining to the + applicable CPUs. +*/ + + +#include +#include "hp2100_defs.h" +#include "hp2100_cpu.h" +#include "hp2100_cpu1.h" + + +/* Offsets to data and addresses within RTE. */ + +static const uint32 xi = 0001647; /* XI address */ +static const uint32 intba = 0001654; /* INTBA address */ +static const uint32 intlg = 0001655; /* INTLG address */ +static const uint32 eqt1 = 0001660; /* EQT1 address */ +static const uint32 eqt11 = 0001672; /* EQT11 address */ +static const uint32 pvcn = 0001712; /* PVCN address */ +static const uint32 xsusp = 0001730; /* XSUSP address */ +static const uint32 dummy = 0001737; /* DUMMY address */ +static const uint32 mptfl = 0001770; /* MPTFL address */ +static const uint32 eqt12 = 0001771; /* EQT12 address */ +static const uint32 eqt15 = 0001774; /* EQT15 address */ +static const uint32 vctr = 0002000; /* VCTR address */ + +static const uint32 CLC_0 = 0004700; /* CLC 0 instruction */ +static const uint32 STC_0 = 0000700; /* STC 0 instruction */ +static const uint32 CLF_0 = 0001100; /* CLF 0 instruction */ +static const uint32 STF_0 = 0000100; /* STF 0 instruction */ +static const uint32 SFS_0_C = 0003300; /* SFS 0,C instruction */ + +enum vctr_offsets { dms_offset = 0, /* DMS status */ + int_offset, /* interrupt system status */ + sc_offset, /* select code */ + clck_offset, /* TBG IRQ handler */ + cic4_offset, /* illegal IRQ handler */ + cic2_offset, /* device IRQ handler */ + sked_offset, /* prog sched IRQ handler */ + rqst_offset, /* EXEC request handler */ + cic_offset, /* IRQ location */ + perr_offset, /* parity error IRQ handler */ + mper_offset, /* memory protect IRQ handler */ + lxnd_offset }; /* $LIBR return */ + + +/* RTE-6/VM Operating System Instructions + + The OS instructions were added to acccelerate certain time-consuming + operations of the RTE-6/VM operating system, HP product number 92084A. + Microcode was available for the E- and F-Series; the M-Series used software + equivalents. + + Option implementation by CPU was as follows: + + 2114 2115 2116 2100 1000-M 1000-E 1000-F + ------ ------ ------ ------ ------ ------ ------ + N/A N/A N/A N/A N/A 92084A 92084A + + The routines are mapped to instruction codes as follows: + + Instr. 1000-E/F Description + ------ -------- ---------------------------------------------- + $LIBR 105340 Enter privileged/reentrant library routine + $LIBX 105341 Exit privileged/reentrant library routine + .TICK 105342 TBG tick interrupt handler + .TNAM 105343 Find ID segment that matches name + .STIO 105344 Configure I/O instructions + .FNW 105345 Find word with user increment + .IRT 105346 Interrupt return processing + .LLS 105347 Linked list search + + .SIP 105350 Skip if interrupt pending + .YLD 105351 .SIP completion return point + .CPM 105352 Compare words LT/EQ/GT + .ETEQ 105353 Set up EQT pointers in base page + .ENTN 105354 Transfer parameter addresses (utility) + $OTST * 105355 OS firmware self test + .ENTC 105356 Transfer parameter addresses (priv/reent) + .DSPI 105357 Set display indicator + + Opcodes 105354-105357 are "dual use" instructions that take different + actions, depending on whether they are executed from a trap cell during an + interrupt. When executed from a trap cell, they have these actions: + + Instr. 1000-E/F Description + ------ -------- ---------------------------------------------- + $DCPC * 105354 DCPC channel interrupt processing + $MPV * 105355 MP/DMS/PE interrupt processing + $DEV * 105356 Standard device interrupt processing + $TBG * 105357 TBG interrupt processing + + * These mnemonics are recognized by symbolic examine/deposit but are not + official HP mnemonics. + + Implementation notes: + + 1. The microcode differentiates between interrupt processing and normal + execution of the "dual use" instructions by testing the CPU flag. + Interrupt vectoring sets the flag; a normal instruction fetch clears it. + Under simulation, interrupt vectoring is indicated by the value of the + "iotrap" parameter (0 = normal instruction, 1 = trap cell instruction). + + 2. The operand patterns for .ENTN and .ENTC normally would be coded as + "OP_A", as each takes a single address as a parameter. However, because + they might also be executed from a trap cell, we cannot assume that P+1 + is an address, or we might cause a DM abort when trying to resolve + indirects. Therefore, "OP_A" handling is done within each routine, once + the type of use is determined. + + 3. The microcode for .ENTC, .ENTN, .FNW, .LLS, .TICK, and .TNAM explicitly + checks for interrupts during instruction execution. In addition, the + .STIO, .CPM, and .LLS instructions implicitly check for interrupts during + parameter indirect resolution. Because the simulator calculates + interrupt requests only between instructions, this behavior is not + simulated. + + 4. The microcode executes certain I/O instructions (e.g., CLF 0) by building + the instruction in the IR and executing an IOG micro-order. We simulate + this behavior by calling the "iogrp" handler with the appropriate + instruction, rather than manipulating the I/O system directly, so that we + will remain unaffected by any future changes to the underlying I/O + simulation structure. + + 5. The $OTST and .DSPI microcode uses features (reading the RPL switches and + boot loader ROM data, loading the display register) that are not + simulated. The remaining functions of the $OTST instruction are + provided. The .DSPI instruction is a NOP or unimplemented instruction + stop. + + 6. Because of the volume of calls to the OS firmware, debug printouts + attempt to write only one line per instruction invocation. This means + that calling and returned register values are printed separately, with a + newline added at the end of execution. However, many instructions can MP + or DM abort, either intentionally or due to improper use. That would + leave debug lines without the required trailing newlines. + + There are two ways to address this: either we could replace the CPU's + setjmp buffer with one that points to a routine that adds the missing + newline, or we can add a semaphore that is tested on entry to see if it + is already set, implying a longjmp occurred, and then add the newline if + so. The latter would add the newline when the MP trap cell instruction + was entered or when the next user-level instruction was executed. + However, the merged-line problem would still exist if some other module + generated intervening debug printouts. So we do the former. This does + mean that this routine must be changed if the MP abort mechanism is + changed. + + 7. The $LIBX instruction is executed to complete either a privileged or + reentrant execution. In the former case, the privileged nest counter + ($PVCN) is decremented. In the latter, $PVCN decrement is attempted but + the write will trap with an MP violation, as reentrant routines execute + with the interrupt system on. RTE will then complete the release of + memory allocated for the original $LIBR call. + + 8. The documentation for the .SIP and .YLD instructions is misleading in + several places. Comments in the RTE $SIP source file say that .SIP + doesn't return if a "known" interrupt is pending. Actually, .SIP always + returns, either to P+1 for no pending interrupt, or to P+2 if one is + pending. There is no check for "known" interrupt handlers. The + microcode source comments say that the interrupting select code is + returned in the B register. Actually, the B register is unchanged. The + RTE Tech Specs say that .SIP "services any pending system interrupts." + Actually, .SIP only checks for interrupts; no servicing is performed. + + For .YLD, the microcode comments say that two parameters are passed: the + new P value, and the interrupting select code. Actually, only the new P + value is passed. + + The .SIP and .YLD simulations follow the actual microcode rather than the + documentation. + + Additional references: + - RTE-6/VM OS Microcode Source (92084-18831, revision 8). + - RTE-6/VM Technical Specifications (92084-90015, Apr-1983). +*/ + + +/* Save the CPU registers. + + The CPU registers are saved in the current ID segment in preparation for + interrupt handling. Although the RTE base page has separate pointers for the + P, A, B, and E/O registers, they are always contiguous, and the microcode + simply increments the P-register pointer (XSUSP) to store the remaining + values. + + This routine is called from the trap cell interrupt handlers and from the + $LIBX processor. In the latter case, the privileged system interrupt + handling is not required, so it is bypassed. In either case, the current map + will be the system map when we are called. +*/ + +static t_stat cpu_save_regs (uint32 iotrap) +{ +uint16 save_area, priv_fence; +t_stat reason = SCPE_OK; + +save_area = ReadW (xsusp); /* addr of PABEO save area */ + +WriteW (save_area + 0, PC); /* save P */ +WriteW (save_area + 1, AR); /* save A */ +WriteW (save_area + 2, BR); /* save B */ +WriteW (save_area + 3, (E << 15) & SIGN | O & 1); /* save E and O */ + +save_area = ReadW (xi); /* addr of XY save area */ +WriteWA (save_area + 0, XR); /* save X (in user map) */ +WriteWA (save_area + 1, YR); /* save Y (in user map) */ + +if (iotrap) { /* do priv setup only if IRQ */ + priv_fence = ReadW (dummy); /* get priv fence select code */ + + if (priv_fence) { /* privileged system? */ + reason = iogrp (STC_0 + priv_fence, iotrap); /* STC SC on priv fence */ + reason = iogrp (CLC_0 + DMA1, iotrap); /* CLC 6 to inh IRQ on DCPC 1 */ + reason = iogrp (CLC_0 + DMA2, iotrap); /* CLC 7 to inh IRQ on DCPC 2 */ + reason = iogrp (STF_0, iotrap); /* turn interrupt system back on */ + } + } + +return reason; +} + + +/* Save the machine state at interrupt. + + This routine is called from each of the trap cell instructions. Its purpose + is to save the complete state of the machine in preparation for interrupt + handling. + + For the MP/DMS/PE interrupt, the interrupting device must not be cleared and + the CPU registers must not be saved until it is established that the + interrupt is not caused by a parity error. Parity errors cannot be + inhibited, so the interrupt may have occurred while in RTE. Saving the + registers would overwrite the user's registers that were saved at RTE entry. + + Note that the trap cell instructions are dual-use and invoke this routine + only when they are executed during interrupts. Therefore, the current map + will always be the system map when we are called. +*/ + +static t_stat cpu_save_state (uint32 iotrap) +{ +uint16 vectors; +uint32 saved_PC, int_sys_off; +t_stat reason; + +saved_PC = PC; /* save current PC */ +reason = iogrp (SFS_0_C, iotrap); /* turn interrupt system off */ +int_sys_off = (PC == saved_PC); /* set flag if already off */ +PC = saved_PC; /* restore PC in case it bumped */ + +vectors = ReadW (vctr); /* get address of vectors (in SMAP) */ + +WriteW (vectors + dms_offset, dms_upd_sr ()); /* save DMS status (SSM) */ +WriteW (vectors + int_offset, int_sys_off); /* save int status */ +WriteW (vectors + sc_offset, intaddr); /* save select code */ + +WriteW (mptfl, 1); /* show MP is off */ + +if (intaddr != 5) { /* only if not MP interrupt */ + reason = iogrp (CLF_0 + intaddr, iotrap); /* issue CLF to device */ + cpu_save_regs (iotrap); /* save CPU registers */ + } + +return reason; +} + + +/* Get the interrupt table entry corresponding to a select code. + + Return the word in the RTE interrupt table that corresponds to the + interrupting select code. Return 0 if the select code is beyond the end of + the table. +*/ + +static uint16 cpu_get_intbl (uint32 select_code) +{ +uint16 interrupt_table; /* interrupt table (starts with SC 06) */ +uint16 table_length; /* length of interrupt table */ + +interrupt_table = ReadW (intba); /* get int table address */ +table_length = ReadW (intlg); /* get int table length */ + +if (select_code - 6 > table_length) /* SC beyond end of table? */ + return 0; /* return 0 for illegal interrupt */ +else + return ReadW (interrupt_table + select_code - 6); /* else return table entry */ +} + + +/* RTE-6/VM OS instruction dispatcher. + + Debugging printouts are provided with the OS and OSTBG debug flags. The OS + flag enables tracing for all instructions except for the three-instruction + sequence executed for the time-base generator interrupt ($TBG, .TICK, and + .IRT). The OSTBG flag enables tracing for just the TBG sequence. The flags + are separate, as the TBG generates 100 interrupts per second. Use caution + when specifying the OSTBG flag, as the debug output file will grow rapidly. + Note that the OS flag enables the .IRT instruction trace for all cases except + a TBG interrupt. + + The default (user microcode) dispatcher will allow the firmware self-test + instruction (105355) to execute as NOP. This is because RTE-6/VM will always + test for the presence of OS and VMA firmware on E/F-Series machines. If the + firmware is not present, then these instructions will return to P+1, and RTE + will then HLT 21. This means that RTE-6/VM will not run on an E/F-Series + machine without the OS and VMA firmware. + + Howwever, RTE allows the firmware instructions to be disabled for debugging + purposes. If the firmware is present and returns to P+2 but sets the X + register to 0, then RTE will use software equivalents. We enable this + condition when the OS firmware is enabled (SET CPU VMA), the OS debug flag is + set (SET CPU DEBUG=OS), but debug output has been disabled (SET CONSOLE + NODEBUG). That is: + + OS Debug + Firmware Debug Output Tracing Self-Test Instruction + ======== ===== ====== ======= ===================== + disabled x x off NOP + enabled clear x off X = revision code + enabled set off off X = 0 + enabled set on on X = revision code +*/ + +static const OP_PAT op_os[16] = { + OP_A, OP_A, OP_N, OP_N, /* $LIBR $LIBX .TICK .TNAM */ + OP_A, OP_K, OP_A, OP_KK, /* .STIO .FNW .IRT .LLS */ + OP_N, OP_C, OP_KK, OP_N, /* .SIP .YLD .CPM .ETEQ */ + OP_N, OP_N, OP_N, OP_N /* .ENTN $OTST .ENTC .DSPI */ + }; + +t_stat cpu_rte_os (uint32 IR, uint32 intrq, uint32 iotrap) +{ +t_stat reason = SCPE_OK; +OPS op; +OP_PAT pattern; +uint32 entry, count, cp, sa, da, i, ma, eqta; +uint16 vectors, save_area, priv_fence, eoreg, eqt, key; +char test[6], target[6]; +jmp_buf mp_handler; +int abortval; +t_bool debug_print; +static t_bool tbg_tick = FALSE; /* set if processing TBG interrupt */ + +entry = IR & 017; /* mask to entry point */ +pattern = op_os[entry]; /* get operand pattern */ + +if (pattern != OP_N) { + reason = cpu_ops (pattern, op, intrq); /* get instruction operands */ + + if (reason != SCPE_OK) /* evaluation failed? */ + return reason; /* return reason for failure */ + } + +tbg_tick = tbg_tick || (IR == 0105357) && iotrap; /* set TBG interrupting flag */ + +debug_print = (DEBUG_PRI (cpu_dev, DEB_OS) && !tbg_tick) || + (DEBUG_PRI (cpu_dev, DEB_OSTBG) && tbg_tick); + +if (debug_print) { + fprintf (sim_deb, ">>CPU OS: IR = %06o (", IR); /* print preamble and IR */ + fprint_sym (sim_deb, (iotrap ? intaddr : err_PC), /* print instruction mnemonic */ + (t_value *) &IR, NULL, SWMASK('M')); + fputc (')', sim_deb); + + fprint_ops (pattern, op); /* print operands */ + + memcpy (mp_handler, save_env, sizeof (jmp_buf)); /* save original MP handler */ + abortval = setjmp (save_env); /* set new MP abort handler */ + + if (abortval != 0) { /* MP abort? */ + fputs ("...MP abort\n", sim_deb); /* report it and terminate line */ + memcpy (save_env, mp_handler, sizeof (jmp_buf)); /* restore original MP handler */ + longjmp (save_env, abortval); /* transfer to MP handler */ + } + } + +switch (entry) { /* decode IR<3:0> */ + + case 000: /* $LIBR 105340 (OP_A) */ + if ((op[0].word != 0) || /* reentrant call? */ + (mp_control && (ReadW (dummy) != 0))) { /* or priv call + MP on + priv sys? */ + if (dms_ump) { /* called from user map? */ + dms_viol (err_PC, MVI_PRV); /* privilege violation */ + } + dms_ump = SMAP; /* set system map */ + + vectors = ReadW (vctr); /* get address of vectors (in SMAP) */ + PC = ReadW (vectors + mper_offset); /* vector to $MPER for processing */ + } + + else { /* privileged call */ + if (mp_control) { /* memory protect on? */ + mp_control = CLEAR; /* turn it off */ + reason = iogrp (CLF_0, iotrap); /* turn interrupt system off */ + WriteW (mptfl, 1); /* show MP is off */ + save_area = ReadW (xsusp); /* get addr of P save area */ + + if (dms_ump) /* user map current? */ + WriteWA (save_area, (PC - 2) & VAMASK); /* set point of suspension */ + else /* system map current */ + WriteW (save_area, (PC - 2) & VAMASK); /* set point of suspension */ + } + + WriteW (pvcn, (ReadW (pvcn) + 1) & DMASK); /* increment priv nest counter */ + } + break; + + case 001: /* $LIBX 105341 (OP_A) */ + PC = ReadW (op[0].word); /* set P to return point */ + count = (ReadW (pvcn) - 1) & DMASK; /* decrement priv nest counter */ + WriteW (pvcn, count); /* write it back */ + + if (count == 0) { /* end of priv mode? */ + dms_ump = SMAP; /* set system map */ + reason = cpu_save_regs (iotrap); /* save registers */ + vectors = ReadW (vctr); /* get address of vectors */ + PC = ReadW (vectors + lxnd_offset); /* vector to $LXND for processing */ + } + break; + + case 002: /* .TICK 105342 (OP_N) */ + if (debug_print) /* debugging? */ + fprint_regs (",", REG_A | REG_B, 0); /* print entry registers */ + + do { + eqt = (ReadW (AR) + 1) & DMASK; /* bump timeout from EQT15 */ + + if (eqt != 1) { /* was timeout active? */ + WriteW (AR, eqt); /* yes, write it back */ + + if (eqt == 0) /* did timeout expire? */ + break; /* P+0 return for timeout */ + } + + AR = (AR + 15) & DMASK; /* point at next EQT15 */ + BR = (BR - 1) & DMASK; /* decrement count of EQTs */ + } while ((BR > 0) && (eqt != 0)); /* loop until timeout or done */ + + if (BR == 0) /* which termination condition? */ + PC = (PC + 1) & VAMASK; /* P+1 return for no timeout */ + + if (debug_print) /* debugging? */ + fprint_regs ("; result:", /* print return registers */ + REG_A | REG_B | REG_P_REL, + err_PC + 1); + break; + + case 003: /* .TNAM 105343 (OP_N) */ + if (debug_print) /* debugging? */ + fprint_regs (",", REG_A | REG_B, 0); /* print entry registers */ + + E = 1; /* preset flag for not found */ + cp = (BR << 1) & DMASK; /* form char addr (B is direct) */ + + for (i = 0; i < 5; i++) { /* copy target name */ + target[i] = (char) ReadB (cp); /* name is only 5 chars */ + cp = (cp + 1) & DMASK; + } + + if ((target[0] == '\0') && (target[1] == '\0')) /* if name is null, */ + break; /* return immed to P+0 */ + + key = ReadW (AR); /* get first keyword addr */ + + while (key != 0) { /* end of keywords? */ + cp = ((key + 12) << 1) & DMASK; /* form char addr of name */ + + for (i = 0; i < 6; i++) { /* copy test name */ + test[i] = (char) ReadB (cp); /* name is only 5 chars */ + cp = (cp + 1) & DMASK; /* but copy 6 to get flags */ + } + + if (strncmp (target, test, 5) == 0) { /* names match? */ + AR = (key + 15) & DMASK; /* A = addr of IDSEG [15] */ + BR = key; /* B = addr of IDSEG [0] */ + E = (uint32) ((test[5] >> 4) & 1); /* E = short ID segment bit */ + PC = (PC + 1) & VAMASK; /* P+1 for found return */ + break; + } + + AR = (AR + 1) & DMASK; /* bump to next keyword */ + key = ReadW (AR); /* get next keyword */ + }; + + if (debug_print) /* debugging? */ + fprint_regs ("; result:", /* print return registers */ + REG_A | REG_B | REG_E | REG_P_REL, + err_PC + 1); + break; + + case 004: /* .STIO 105344 (OP_A) */ + count = op[0].word - PC; /* get count of operands */ + + if (debug_print) /* debugging? */ + fprintf (sim_deb, /* print registers on entry */ + ", A = %06o, count = %d", AR, count); + + for (i = 0; i < count; i++) { + ma = ReadW (PC); /* get operand address */ + + reason = resolve (ma, &ma, intrq); /* resolve indirect */ + + if (reason != SCPE_OK) { /* resolution failed? */ + PC = err_PC; /* IRQ restarts instruction */ + break; + } + + WriteW (ma, ReadW (ma) & ~I_DEVMASK | AR); /* set SC into instruction */ + PC = (PC + 1) & VAMASK; /* bump to next */ + } + break; + + case 005: /* .FNW 105345 (OP_K) */ + if (debug_print) /* debugging? */ + fprint_regs (",", REG_A | REG_B | REG_X, 0); /* print entry registers */ + + while (XR != 0) { /* all comparisons done? */ + key = ReadW (BR); /* read a buffer word */ + + if (key == AR) { /* does it match? */ + PC = (PC + 1) & VAMASK; /* P+1 found return */ + break; + } + + BR = (BR + op[0].word) & DMASK; /* increment buffer ptr */ + XR = (XR - 1) & DMASK; /* decrement remaining count */ + } + /* P+0 not found return */ + if (debug_print) /* debugging? */ + fprint_regs ("; result:", /* print return registers */ + REG_A | REG_B | REG_X | REG_P_REL, + err_PC + 2); + break; + + case 006: /* .IRT 105346 (OP_A) */ + save_area = ReadW (xsusp); /* addr of PABEO save area */ + + WriteW (op[0].word, ReadW (save_area + 0)); /* restore P to DEF RTN */ + + AR = ReadW (save_area + 1); /* restore A */ + BR = ReadW (save_area + 2); /* restore B */ + + eoreg = ReadW (save_area + 3); /* get combined E and O */ + E = (eoreg >> 15) & 1; /* restore E */ + O = eoreg & 1; /* restore O */ + + save_area = ReadW (xi); /* addr of XY save area */ + XR = ReadWA (save_area + 0); /* restore X (from user map) */ + YR = ReadWA (save_area + 1); /* restore Y (from user map) */ + + reason = iogrp (CLF_0, iotrap); /* turn interrupt system off */ + WriteW (mptfl, 0); /* show MP is on */ + + priv_fence = ReadW (dummy); /* get priv fence select code */ + + if (priv_fence) { /* privileged system? */ + reason = iogrp (CLC_0 + priv_fence, iotrap); /* CLC SC on priv fence */ + reason = iogrp (STF_0 + priv_fence, iotrap); /* STF SC on priv fence */ + + if (cpu_get_intbl (DMA1) & SIGN) /* DCPC 1 active? */ + reason = iogrp (STC_0 + DMA1, iotrap); /* STC 6 to enable IRQ on DCPC 1 */ + + if (cpu_get_intbl (DMA2) & SIGN) /* DCPC 2 active? */ + reason = iogrp (STC_0 + DMA2, iotrap); /* STC 7 to enable IRQ on DCPC 2 */ + } + + tbg_tick = 0; /* .IRT terminates TBG servicing */ + break; + + case 007: /* .LLS 105347 (OP_KK) */ + if (debug_print) /* debugging? */ + fprint_regs (",", REG_A | REG_B | REG_E, 0); /* print entry registers */ + + AR = AR & ~SIGN; /* clear sign bit of A */ + + while ((AR != 0) && ((AR & SIGN) == 0)) { /* end of list or bad list? */ + key = ReadW ((AR + op[1].word) & VAMASK); /* get key value */ + + if ((E == 0) && (key == op[0].word) || /* for E = 0, key = arg? */ + (E != 0) && (key > op[0].word)) /* for E = 1, key > arg? */ + break; /* search is done */ + + BR = AR; /* B = last link */ + AR = ReadW (AR); /* A = next link */ + } + + if (AR == 0) /* exhausted list? */ + PC = (PC + 1) & VAMASK; /* P+1 arg not found */ + else if ((AR & SIGN) == 0) /* good link? */ + PC = (PC + 2) & VAMASK; /* P+2 arg found */ + /* P+0 bad link */ + if (debug_print) /* debugging? */ + fprint_regs ("; result:", /* print return registers */ + REG_A | REG_B | REG_P_REL, + err_PC + 3); + break; + + case 010: /* .SIP 105350 (OP_N) */ + reason = iogrp (STF_0, iotrap); /* turn interrupt system on */ + intrq = calc_int (); /* check for interrupt requests */ + reason = iogrp (CLF_0, iotrap); /* turn interrupt system off */ + + if (intrq) /* was interrupt pending? */ + PC = (PC + 1) & VAMASK; /* P+1 return for pending IRQ */ + /* P+0 return for no pending IRQ */ + if (debug_print) /* debugging? */ + fprintf (sim_deb, /* print return registers */ + ", CIR = %02o, return = P+%d", + intrq, PC - (err_PC + 1)); + break; + + case 011: /* .YLD 105351 (OP_C) */ + PC = op[0].word; /* pick up point of resumption */ + reason = iogrp (STF_0, iotrap); /* turn interrupt system on */ + ion_defer = 0; /* kill defer so irq occurs immed */ + break; + + case 012: /* .CPM 105352 (OP_KK) */ + if (INT16 (op[0].word) > INT16 (op[1].word)) + PC = (PC + 2) & VAMASK; /* P+2 arg1 > arg2 */ + else if (INT16 (op[0].word) < INT16 (op[1].word)) + PC = (PC + 1) & VAMASK; /* P+1 arg1 < arg2 */ + /* P+0 arg1 = arg2 */ + if (debug_print) /* debugging? */ + fprint_regs (",", REG_P_REL, err_PC + 3); /* print return registers */ + break; + + case 013: /* .ETEQ 105353 (OP_N) */ + eqt = ReadW (eqt1); /* get addr of EQT1 */ + + if (AR != eqt) { /* already set up? */ + for (eqta = eqt1; eqta <= eqt11; eqta++) /* init EQT1-EQT11 */ + WriteW (eqta, AR++ & DMASK); + for (eqta = eqt12; eqta <= eqt15; eqta++) /* init EQT12-EQT15 */ + WriteW (eqta, AR++ & DMASK); /* (not contig with EQT1-11) */ + } + + AR = AR & DMASK; /* ensure wraparound */ + + if (debug_print) /* debugging? */ + fprintf (sim_deb, /* print return registers */ + ", A = %06o, EQT1 = %06o", AR, eqt); + break; + + case 014: /* .ENTN/$DCPC 105354 (OP_N) */ + if (iotrap) { /* in trap cell? */ + reason = cpu_save_state (iotrap); /* DMA interrupt */ + AR = cpu_get_intbl (intaddr) & ~SIGN; /* get intbl value and strip sign */ + goto DEVINT; /* vector by intbl value */ + } + + else { /* .ENTN instruction */ + ma = (PC - 2) & VAMASK; /* get addr of entry point */ + + ENTX: /* enter here from .ENTC */ + reason = cpu_ops (OP_A, op, intrq); /* get instruction operand */ + da = op[0].word; /* get addr of 1st formal */ + count = ma - da; /* get count of formals */ + sa = ReadW (ma); /* get addr of 1st actual */ + WriteW (ma, (sa + count) & VAMASK); /* adjust return point to skip actuals */ + + if (debug_print) /* debugging? */ + fprintf (sim_deb, /* print entry registers */ + ", op [0] = %06o, pcount = %d", + da, count); + + for (i = 0; i < count; i++) { /* parameter loop */ + ma = ReadW (sa); /* get addr of actual */ + sa = (sa + 1) & VAMASK; /* increment address */ + + reason = resolve (ma, &ma, intrq); /* resolve indirect */ + + if (reason != SCPE_OK) { /* resolution failed? */ + PC = err_PC; /* irq restarts instruction */ + break; + } + + WriteW (da, ma); /* put addr into formal */ + da = (da + 1) & VAMASK; /* increment address */ + } + + if (entry == 016) /* call was .ENTC? */ + AR = (uint16) sa; /* set A to return address */ + } + break; + + case 015: /* $OTST/$MPV 105355 (OP_N) */ + if (iotrap) { /* in trap cell? */ + reason = cpu_save_state (iotrap); /* MP/DMS/PE interrupt */ + vectors = ReadW (vctr); /* get address of vectors (in SMAP) */ + + if (mp_viol & SIGN) { /* parity error? */ + WriteW (vectors + cic_offset, PC); /* save point of suspension in $CIC */ + PC = ReadW (vectors + perr_offset); /* vector to $PERR for processing */ + } + + else { /* MP/DMS violation */ + cpu_save_regs (iotrap); /* save CPU registers */ + PC = ReadW (vectors + rqst_offset); /* vector to $RQST for processing */ + } + + if (debug_print) { /* debugging? */ + fprint_regs (",", REG_CIR, 0); /* print interrupt source */ + /* and cause */ + if (mp_viol & SIGN) + fputs (", parity error", sim_deb); + else if (mp_mevff) + fputs (", DM violation", sim_deb); + else + fputs (", MP violation", sim_deb); + } + } + + else { /* self-test instruction */ + YR = 0000000; /* RPL switch (not implemented) */ + AR = 0000000; /* LDR [B] (not implemented) */ + SR = 0102077; /* test passed code */ + PC = (PC + 1) & VAMASK; /* P+1 return for firmware OK */ + + if ((cpu_dev.dctrl & DEB_OS) && /* OS debug flag set, */ + (sim_deb == NULL)) /* but debugging disabled? */ + XR = 0; /* rev = 0 means RTE won't use ucode */ + else + XR = 010; /* firmware revision 10B = 8 */ + + if (debug_print) /* debugging? */ + fprint_regs (",", REG_X | REG_P_REL, /* print return registers */ + err_PC + 1); + } + break; + + case 016: /* .ENTC/$DEV 105356 (OP_N) */ + if (iotrap) { /* in trap cell? */ + reason = cpu_save_state (iotrap); /* device interrupt */ + AR = cpu_get_intbl (intaddr); /* get interrupt table value */ + + DEVINT: + vectors = ReadW (vctr); /* get address of vectors (in SMAP) */ + + if (INT16 (AR) < 0) /* negative (program ID)? */ + PC = ReadW (vectors + sked_offset); /* vector to $SKED for processing */ + else if (AR > 0) /* positive (EQT address)? */ + PC = ReadW (vectors + cic2_offset); /* vector to $CIC2 for processing */ + else /* zero (illegal interrupt) */ + PC = ReadW (vectors + cic4_offset); /* vector to $CIC4 for processing */ + + if (debug_print) /* debugging? */ + fprintf (sim_deb, /* print return registers */ + ", CIR = %02o, INTBL = %06o", + intaddr, AR); + } + + else { /* .ENTC instruction */ + ma = (PC - 4) & VAMASK; /* get addr of entry point */ + goto ENTX; /* continue with common processing */ + } + break; + + case 017: /* .DSPI/$TBG 105357 (OP_N) */ + if (iotrap) { /* in trap cell? */ + reason = cpu_save_state (iotrap); /* TBG interrupt */ + vectors = ReadW (vctr); /* get address of vectors (in SMAP) */ + PC = ReadW (vectors + clck_offset); /* vector to $CLCK for processing */ + + if (debug_print) /* debugging? */ + fprint_regs (",", REG_CIR, 0); /* print interrupt source */ + } + + else /* .DSPI instruction */ + reason = stop_inst; /* not implemented yet */ + + break; + } + +if (debug_print) { /* debugging? */ + fputc ('\n', sim_deb); /* terminate line */ + memcpy (save_env, mp_handler, sizeof (jmp_buf)); /* restore original MP handler */ + } + +return reason; +} diff --git a/HP2100/hp2100_cpu7.c b/HP2100/hp2100_cpu7.c index ada35eab..fccccb2d 100644 --- a/HP2100/hp2100_cpu7.c +++ b/HP2100/hp2100_cpu7.c @@ -1,940 +1,942 @@ -/* hp2100_cpu7.c: HP 1000 VIS and SIGNAL/1000 microcode - - Copyright (c) 2008, Holger Veit - Copyright (c) 2006-2012, J. David Bryan - - 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 - THE AUTHORS 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 the authors shall not be - used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from the authors. - - CPU7 Vector Instruction Set and SIGNAL firmware - - 06-Feb-12 JDB Corrected "opsize" parameter type in vis_abs - 11-Sep-08 JDB Moved microcode function prototypes to hp2100_cpu1.h - 05-Sep-08 JDB Removed option-present tests (now in UIG dispatchers) - 30-Apr-08 JDB Updated SIGNAL code from Holger - 24-Apr-08 HV Implemented SIGNAL - 20-Apr-08 JDB Updated comments - 26-Feb-08 HV Implemented VIS - - Primary references: - - HP 1000 M/E/F-Series Computers Technical Reference Handbook - (5955-0282, Mar-1980) - - HP 1000 M/E/F-Series Computers Engineering and Reference Documentation - (92851-90001, Mar-1981) - - Macro/1000 Reference Manual (92059-90001, Dec-1992) - - Additional references are listed with the associated firmware - implementations, as are the HP option model numbers pertaining to the - applicable CPUs. -*/ - -#include "hp2100_defs.h" -#include "hp2100_cpu.h" -#include "hp2100_cpu1.h" - -#if defined (HAVE_INT64) /* int64 support available */ - -#include "hp2100_fp1.h" - - -static const OP zero = { { 0, 0, 0, 0, 0 } }; /* DEC 0.0D0 */ - - -/* Vector Instruction Set - - The VIS provides instructions that operate on one-dimensional arrays of - floating-point values. Both single- and double-precision operations are - supported. VIS uses the F-Series floating-point processor to handle the - floating-point math. - - Option implementation by CPU was as follows: - - 2114 2115 2116 2100 1000-M 1000-E 1000-F - ------ ------ ------ ------ ------ ------ ------ - N/A N/A N/A N/A N/A N/A 12824A - - The routines are mapped to instruction codes as follows: - - Single-Precision Double-Precision - Instr. Opcode Subcod Instr. Opcode Subcod Description - ------ ------ ------ ------ ------ ------ ----------------------------- - VADD 101460 000000 DVADD 105460 004002 Vector add - VSUB 101460 000020 DVSUB 105460 004022 Vector subtract - VMPY 101460 000040 DVMPY 105460 004042 Vector multiply - VDIV 101460 000060 DVDIV 105460 004062 Vector divide - VSAD 101460 000400 DVSAD 105460 004402 Scalar-vector add - VSSB 101460 000420 DVSSB 105460 004422 Scalar-vector subtract - VSMY 101460 000440 DVSMY 105460 004442 Scalar-vector multiply - VSDV 101460 000460 DVSDV 105460 004462 Scalar-vector divide - VPIV 101461 0xxxxx DVPIV 105461 0xxxxx Vector pivot - VABS 101462 0xxxxx DVABS 105462 0xxxxx Vector absolute value - VSUM 101463 0xxxxx DVSUM 105463 0xxxxx Vector sum - VNRM 101464 0xxxxx DVNRM 105464 0xxxxx Vector norm - VDOT 101465 0xxxxx DVDOT 105465 0xxxxx Vector dot product - VMAX 101466 0xxxxx DVMAX 105466 0xxxxx Vector maximum value - VMAB 101467 0xxxxx DVMAB 105467 0xxxxx Vector maximum absolute value - VMIN 101470 0xxxxx DVMIN 105470 0xxxxx Vector minimum value - VMIB 101471 0xxxxx DVMIB 105471 0xxxxx Vector minimum absolute value - VMOV 101472 0xxxxx DVMOV 105472 0xxxxx Vector move - VSWP 101473 0xxxxx DVSWP 105473 0xxxxx Vector swap - .ERES 101474 -- -- -- -- Resolve array element address - .ESEG 101475 -- -- -- -- Load MSEG maps - .VSET 101476 -- -- -- -- Vector setup - [test] -- -- -- 105477 -- [self test] - - Instructions use IR bit 11 to select single- or double-precision format. The - double-precision instruction names begin with "D" (e.g., DVADD vs. VADD). - Most VIS instructions are two words in length, with a sub-opcode immediately - following the primary opcode. - - Notes: - - 1. The .VECT (101460) and .DVCT (105460) opcodes preface a single- or - double-precision arithmetic operation that is determined by the - sub-opcode value. The remainder of the dual-precision sub-opcode values - are "don't care," except for requiring a zero in bit 15. - - 2. The VIS uses the hardware FPP of the F-Series. FPP malfunctions are - detected by the VIS firmware and are indicated by a memory-protect - violation and setting the overflow flag. Under simulation, - malfunctions cannot occur. - - Additional references: - - 12824A Vector Instruction Set User's Manual (12824-90001, Jun-1979). - - VIS Microcode Source (12824-18059, revision 3). -*/ - -/* implemented in hp2100_cpu5.c (RTE-IV EMA functions) */ -extern t_stat cpu_ema_eres(uint32* rtn,uint32 dtbl,uint32 atbl, t_bool debug); -extern t_stat cpu_ema_eseg(uint32* rtn,uint32 ir,uint32 tbl, t_bool debug); -extern t_stat cpu_ema_vset(uint32* rtn,OPS op, t_bool debug); - -static const OP_PAT op_vis[16] = { - OP_N, OP_AAKAKAKK,OP_AKAKK, OP_AAKK, /* .VECT VPIV VABS VSUM */ - OP_AAKK, OP_AAKAKK, OP_AAKK, OP_AAKK, /* VNRM VDOT VMAX VMAB */ - OP_AAKK, OP_AAKK, OP_AKAKK, OP_AKAKK, /* VMIN VMIB VMOV VSWP */ - OP_AA, OP_A, OP_AAACCC,OP_N /* .ERES .ESEG .VSET [test] */ - }; - -static const t_bool op_ftnret[16] = { - FALSE, TRUE, TRUE, TRUE, - TRUE, TRUE, TRUE, TRUE, - TRUE, TRUE, TRUE, TRUE, - FALSE, TRUE, TRUE, FALSE, - }; - - -/* handle the scalar/vector base ops */ -static void vis_svop(uint32 subcode, OPS op, OPSIZE opsize) -{ -OP v1,v2; -int16 delta = opsize==fp_f ? 2 : 4; -OP s = ReadOp(op[0].word,opsize); -uint32 v1addr = op[1].word; -int16 ix1 = INT16(op[2].word) * delta; -uint32 v2addr = op[3].word; -int16 ix2 = INT16(op[4].word) * delta; -int16 i, n = INT16(op[5].word); -uint32 fpuop = (subcode & 060) | (opsize==fp_f ? 0 : 2); - -if (n <= 0) return; -for (i=0; ifpk[0] & 0100000) - -static void vis_abs(OP* in, OPSIZE opsize) -{ -uint32 sign = GET_MSIGN(in); /* get sign */ -if (sign) (void)fp_pcom(in, opsize); /* if negative, make positive */ -} - -static void vis_minmax(OPS op,OPSIZE opsize,t_bool domax,t_bool doabs) -{ -OP v1,vmxmn,res; -int16 delta = opsize==fp_f ? 2 : 4; -uint32 mxmnaddr = op[0].word; -uint32 v1addr = op[1].word; -int16 ix1 = INT16(op[2].word) * delta; -int16 n = INT16(op[3].word); -int16 i,mxmn,sign; -int32 subop = 020 | (opsize==fp_f ? 0 : 2); - -if (n <= 0) return; -mxmn = 0; /* index of maxmin element */ -vmxmn = ReadOp(v1addr,opsize); /* initialize with first element */ -if (doabs) vis_abs(&vmxmn,opsize); /* ABS(v[1]) if requested */ - -for (i = 0; ifpk[0] = in.fpk[0]; -out->fpk[1] = (in.fpk[1] & 0177400) | (in.fpk[3] & 0377); -} - -static void vis_vsmnm(OPS op,OPSIZE opsize,t_bool doabs) -{ -uint32 fpuop; -OP v1,sumnrm = zero; -int16 delta = opsize==fp_f ? 2 : 4; -uint32 saddr = op[0].word; -uint32 v1addr = op[1].word; -int16 ix1 = INT16(op[2].word) * delta; -int16 i,n = INT16(op[3].word); - -if (n <= 0) return; -/* calculates sumnrm = sumnrm + DBLE(v1[i]) resp DBLE(ABS(v1[i])) for incrementing i */ -for (i=0; i>CPU VIS: IR = %06o/%06o (", /* print preamble and IR */ - IR, subcode); - fprint_sym (sim_deb, err_PC, (t_value *) &IR, /* print instruction mnemonic */ - NULL, SWMASK('M')); - fprintf (sim_deb, "), P = %06o", err_PC); /* print location */ - fprint_ops (pattern, op); /* print operands */ - fputc ('\n', sim_deb); /* terminate line */ - } - -switch (entry) { /* decode IR<3:0> */ - case 000: /* .VECT (OP_special) */ - if (subcode & 0400) - vis_svop(subcode,op,opsize); /* scalar/vector op */ - else - vis_vvop(subcode,op,opsize); /* vector/vector op */ - break; - case 001: /* VPIV (OP_(A)AAKAKAKK) */ - vis_vpiv(op,opsize); - break; - case 002: /* VABS (OP_(A)AKAKK) */ - vis_vabs(op,opsize); - break; - case 003: /* VSUM (OP_(A)AAKK) */ - vis_vsmnm(op,opsize,FALSE); - break; - case 004: /* VNRM (OP_(A)AAKK) */ - vis_vsmnm(op,opsize,TRUE); - break; - case 005: /* VDOT (OP_(A)AAKAKK) */ - vis_vdot(op,opsize); - break; - case 006: /* VMAX (OP_(A)AAKK) */ - vis_minmax(op,opsize,TRUE,FALSE); - break; - case 007: /* VMAB (OP_(A)AAKK) */ - vis_minmax(op,opsize,TRUE,TRUE); - break; - case 010: /* VMIN (OP_(A)AAKK) */ - vis_minmax(op,opsize,FALSE,FALSE); - break; - case 011: /* VMIB (OP_(A)AAKK) */ - vis_minmax(op,opsize,FALSE,TRUE); - break; - case 012: /* VMOV (OP_(A)AKAKK) */ - vis_movswp(op,opsize,FALSE); - break; - case 013: /* VSWP (OP_(A)AKAKK) */ - vis_movswp(op,opsize,TRUE); - break; - case 014: /* .ERES (OP_(A)AA) */ - reason = cpu_ema_eres(&rtn,op[2].word,PC,debug); /* handle the ERES instruction */ - PC = rtn; - if (debug) - fprintf (sim_deb, - ">>CPU VIS: return .ERES: AR = %06o, BR = %06o, rtn=%s\n", - AR, BR, PC==op[0].word ? "error" : "good"); - break; - - case 015: /* .ESEG (OP_(A)A) */ - reason = cpu_ema_eseg(&rtn,IR,op[0].word,debug); /* handle the ESEG instruction */ - PC = rtn; - if (debug) - fprintf (sim_deb, - ">>CPU VIS: return .ESEG: AR = %06o , BR = %06o, rtn=%s\n", - AR, BR, rtn==rtn1 ? "error" : "good"); - break; - - case 016: /* .VSET (OP_(A)AAACCC) */ - reason = cpu_ema_vset(&rtn,op,debug); - PC = rtn; - if (debug) - fprintf (sim_deb, ">>CPU VIS: return .VSET: AR = %06o BR = %06o, rtn=%s\n", - AR, BR, - rtn==rtn1 ? "error" : (rtn==(rtn1+1) ? "hard" : "easy") ); - break; - - case 017: /* [test] (OP_N) */ - XR = 3; /* firmware revision */ - SR = 0102077; /* test passed code */ - PC = (PC + 1) & VAMASK; /* P+2 return for firmware w/VIS */ - break; - default: /* others undefined */ - reason = stop_inst; - } - -return reason; -} - - -/* SIGNAL/1000 Instructions - - The SIGNAL/1000 instructions provide fast Fourier transforms and complex - arithmetic. They utilize the F-Series floating-point processor and the - Vector Instruction Set. - - Option implementation by CPU was as follows: - - 2114 2115 2116 2100 1000-M 1000-E 1000-F - ------ ------ ------ ------ ------ ------ ------ - N/A N/A N/A N/A N/A N/A 92835A - - The routines are mapped to instruction codes as follows: - - Instr. 1000-F Description - ------ ------ ---------------------------------------------- - BITRV 105600 Bit reversal - BTRFY 105601 Butterfly algorithm - UNSCR 105602 Unscramble for phasor MPY - PRSCR 105603 Unscramble for phasor MPY - BITR1 105604 Swap two elements in array (alternate format) - BTRF1 105605 Butterfly algorithm (alternate format) - .CADD 105606 Complex number addition - .CSUB 105607 Complex number subtraction - .CMPY 105610 Complex number multiplication - .CDIV 105611 Complex number division - CONJG 105612 Complex conjugate - ..CCM 105613 Complex complement - AIMAG 105614 Return imaginary part - CMPLX 105615 Form complex number - [nop] 105616 [no operation] - [test] 105617 [self test] - - Notes: - - 1. SIGNAL/1000 ROM data are available from Bitsavers. - - Additional references (documents unavailable): - - HP Signal/1000 User Reference and Installation Manual (92835-90002). - - SIGNAL/1000 Microcode Source (92835-18075, revision 2). -*/ - -#define RE(x) (x+0) -#define IM(x) (x+2) - -static const OP_PAT op_signal[16] = { - OP_AAKK, OP_AAFFKK, OP_AAFFKK,OP_AAFFKK, /* BITRV BTRFY UNSCR PRSCR */ - OP_AAAKK, OP_AAAFFKK,OP_AAA, OP_AAA, /* BITR1 BTRF1 .CADD .CSUB */ - OP_AAA, OP_AAA, OP_AAA, OP_A, /* .CMPY .CDIV CONJG ..CCM */ - OP_AA, OP_AAFF, OP_N, OP_N /* AIMAG CMPLX --- [test]*/ - }; - -/* complex addition helper */ -static void sig_caddsub(uint32 addsub,OPS op) -{ -OP a,b,c,d,p1,p2; - -a = ReadOp(RE(op[1].word), fp_f); /* read 1st op */ -b = ReadOp(IM(op[1].word), fp_f); -c = ReadOp(RE(op[2].word), fp_f); /* read 2nd op */ -d = ReadOp(IM(op[2].word), fp_f); -(void)fp_exec(addsub,&p1, a, c); /* add real */ -(void)fp_exec(addsub,&p2, b, d); /* add imag */ -WriteOp(RE(op[0].word), p1, fp_f); /* write result */ -WriteOp(IM(op[0].word), p2, fp_f); /* write result */ -} - -/* butterfly operation helper */ -static void sig_btrfy(uint32 re,uint32 im,OP wr,OP wi,uint32 k, uint32 n2) -{ -/* - * v(k)-------->o-->o----> v(k) - * \ / - * x - * / \ - * v(k+N/2)---->o-->o----> v(k+N/2) - * Wn -1 - * - */ - -OP p1,p2,p3,p4; -OP v1r = ReadOp(re+k, fp_f); /* read v1 */ -OP v1i = ReadOp(im+k, fp_f); -OP v2r = ReadOp(re+k+n2, fp_f); /* read v2 */ -OP v2i = ReadOp(im+k+n2, fp_f); - -/* (p1,p2) := cmul(w,v2) */ -(void)fp_exec(040, &p1, wr, v2r); /* S7,8 p1 := wr*v2r */ -(void)fp_exec(040, ACCUM, wi, v2i); /* ACCUM := wi*v2i */ -(void)fp_exec(024, &p1, p1, NOP); /* S7,S8 p1 := wr*v2r-wi*v2i ==real(w*v2) */ -(void)fp_exec(040, &p2, wi, v2r); /* S9,10 p2 := wi*v2r */ -(void)fp_exec(040, ACCUM, wr, v2i); /* ACCUM := wr*v2i */ -(void)fp_exec(004, &p2, p2, NOP); /* S9,10 p2 := wi*v2r+wr*v2i ==imag(w*v2) */ -/* v2 := v1 - (p1,p2) */ -(void)fp_exec(020, &p3, v1r, p1); /* v2r := v1r-real(w*v2) */ -(void)fp_exec(020, &p4, v1i, p2); /* v2i := v1i-imag(w*v2) */ -WriteOp(re+k+n2, p3, fp_f); /* write v2r */ -WriteOp(im+k+n2, p4, fp_f); /* write v2i */ -/* v1 := v1 + (p1,p2) */ -(void)fp_exec(0, &p3, v1r, p1); /* v1r := v1r+real(w*v2) */ -(void)fp_exec(0, &p4, v1i, p2); /* v1i := v1i+imag(w*v2) */ -WriteOp(re+k, p3, fp_f); /* write v1r */ -WriteOp(im+k, p4, fp_f); /* write v1i */ -O = 0; -} - -/* helper for bit reversal - * idx is 0-based already */ -static void sig_bitrev(uint32 re,uint32 im, uint32 idx, uint32 log2n, int sz) -{ -uint32 i, org=idx, rev = 0; -OP v1r,v1i,v2r,v2i; - -for (i=0; i>= 1; -} - -if (rev < idx) return; /* avoid swapping same pair twice in loop */ - -idx *= sz; /* adjust for element size */ -rev *= sz; /* (REAL*4 vs COMPLEX*8) */ - -v1r = ReadOp(re+idx, fp_f); /* read 1st element */ -v1i = ReadOp(im+idx, fp_f); -v2r = ReadOp(re+rev, fp_f); /* read 2nd element */ -v2i = ReadOp(im+rev, fp_f); -WriteOp(re+idx, v2r, fp_f); /* swap elements */ -WriteOp(im+idx, v2i, fp_f); -WriteOp(re+rev, v1r, fp_f); -WriteOp(im+rev, v1i, fp_f); -} - -/* helper for PRSCR/UNSCR */ -static OP sig_scadd(uint32 oper,t_bool addh, OP a, OP b) -{ -OP r; -static const OP plus_half = { { 0040000, 0000000 } }; /* DEC +0.5 */ - -(void)fp_exec(oper,&r,a,b); /* calculate r := a +/- b */ -if (addh) (void)fp_exec(044,&r,plus_half,NOP); /* if addh set, multiply by 0.5 */ -return r; -} - -/* complex multiply helper */ -static void sig_cmul(OP *r, OP *i, OP a, OP b, OP c, OP d) -{ -OP p; -(void)fp_exec(040, &p , a, c); /* p := ac */ -(void)fp_exec(040, ACCUM, b, d); /* ACCUM := bd */ -(void)fp_exec(024, r, p , NOP); /* real := ac-bd */ -(void)fp_exec(040, &p, a, d); /* p := ad */ -(void)fp_exec(040, ACCUM, b, c); /* ACCUM := bc */ -(void)fp_exec(004, i, p, NOP); /* imag := ad+bc */ -} - -t_stat cpu_signal (uint32 IR, uint32 intrq) -{ -t_stat reason = SCPE_OK; -OPS op; -OP a,b,c,d,p1,p2,p3,p4,m1,m2,wr,wi; -uint32 entry, v, idx1, idx2; -int32 exc, exd; - -t_bool debug = DEBUG_PRI (cpu_dev, DEB_SIG); - -entry = IR & 017; /* mask to entry point */ - -if (op_signal[entry] != OP_N) - if (reason = cpu_ops (op_signal[entry], op, intrq)) /* get instruction operands */ - return reason; - -if (debug) { /* debugging? */ - fprintf (sim_deb, ">>CPU SIG: IR = %06o (", IR); /* print preamble and IR */ - fprint_sym (sim_deb, err_PC, (t_value *) &IR, /* print instruction mnemonic */ - NULL, SWMASK('M')); - fprintf (sim_deb, "), P = %06o", err_PC); /* print location */ - fprint_ops (op_signal[entry], op); /* print operands */ - fputc ('\n', sim_deb); /* terminate line */ - } - -switch (entry) { /* decode IR<3:0> */ - case 000: /* BITRV (OP_AAKK) */ - /* BITRV - * bit reversal for FFT - * JSB BITRV - * DEF ret(,I) return address - * DEF vect,I base address of array - * DEF idx,I index bitmap to be reversed (one-based) - * DEF nbits,I number of bits of index - * - * Given a complex*8 vector of nbits (power of 2), this calculates: - * swap( vect[idx], vect[rev(idx)]) where rev(i) is the bitreversed value of i */ - sig_bitrev(op[1].word, op[1].word+2, op[2].word-1, op[3].word, 4); - PC = op[0].word & VAMASK; - break; - - case 001: /* BTRFY (OP_AAFFKK) */ - /* BTRFY - butterfly operation - * JSB BTRFY - * DEF ret(,I) return address - * DEF vect(,I) complex*8 vector - * DEF wr,I real part of W - * DEF wi,I imag part of W - * DEF node,I index of 1st op (1 based) - * DEF lmax,I offset to 2nd op (0 based) */ - sig_btrfy(op[1].word, op[1].word+2, - op[2], op[3], - 2*(op[4].word-1), 2*op[5].word); - PC = op[0].word & VAMASK; - break; - - case 002: /* UNSCR (OP_AAFFKK) */ - /* UNSCR unscramble for phasor MPY - * JSB UNSCR - * DEF ret(,I) - * DEF vector,I - * DEF WR - * DEF WI - * DEF idx1,I - * DEF idx2,I */ - v = op[1].word; - idx1 = 2 * (op[4].word - 1); - idx2 = 2 * (op[5].word - 1); - wr = op[2]; /* read WR */ - wi = op[3]; /* read WI */ - p1 = ReadOp(RE(v + idx1), fp_f); /* S1 VR[idx1] */ - p2 = ReadOp(RE(v + idx2), fp_f); /* S2 VR[idx2] */ - p3 = ReadOp(IM(v + idx1), fp_f); /* S9 VI[idx1] */ - p4 = ReadOp(IM(v + idx2), fp_f); /* S10 VI[idx2] */ - c = sig_scadd(000, TRUE, p3, p4); /* S5,6 0.5*(p3+p4) */ - d = sig_scadd(020, TRUE, p2, p1); /* S7,8 0.5*(p2-p1) */ - sig_cmul(&m1, &m2, wr, wi, c, d); /* (WR,WI) * (c,d) */ - c = sig_scadd(000, TRUE, p1, p2); /* 0.5*(p1+p2) */ - d = sig_scadd(020, TRUE, p3, p4); /* 0.5*(p3-p4) */ - (void)fp_exec(000, &p1, c, m1); /* VR[idx1] := 0.5*(p1+p2) + real(W*(c,d)) */ - WriteOp(RE(v + idx1), p1, fp_f); - (void)fp_exec(000, &p2, d, m2); /* VI[idx1] := 0.5*(p3-p4) + imag(W*(c,d)) */ - WriteOp(IM(v + idx1), p2, fp_f); - (void)fp_exec(020, &p1, c, m1); /* VR[idx2] := 0.5*(p1+p2) - imag(W*(c,d)) */ - WriteOp(RE(v + idx2), p1, fp_f); - (void)fp_exec(020, &p2, d, m2); /* VI[idx2] := 0.5*(p3-p4) - imag(W*(c,d)) */ - WriteOp(IM(v + idx2), p2, fp_f); - PC = op[0].word & VAMASK; - break; - - case 003: /* PRSCR (OP_AAFFKK) */ - /* PRSCR unscramble for phasor MPY - * JSB PRSCR - * DEF ret(,I) - * DEF vector,I - * DEF WR - * DEF WI - * DEF idx1,I - * DEF idx2,I */ - v = op[1].word; - idx1 = 2 * (op[4].word - 1); - idx2 = 2 * (op[5].word - 1); - wr = op[2]; /* read WR */ - wi = op[3]; /* read WI */ - p1 = ReadOp(RE(v + idx1), fp_f); /* VR[idx1] */ - p2 = ReadOp(RE(v + idx2), fp_f); /* VR[idx2] */ - p3 = ReadOp(IM(v + idx1), fp_f); /* VI[idx1] */ - p4 = ReadOp(IM(v + idx2), fp_f); /* VI[idx2] */ - c = sig_scadd(020, FALSE, p1, p2); /* p1-p2 */ - d = sig_scadd(000, FALSE, p3, p4); /* p3+p4 */ - sig_cmul(&m1,&m2, wr, wi, c, d); /* (WR,WI) * (c,d) */ - c = sig_scadd(000, FALSE, p1, p2); /* p1+p2 */ - d = sig_scadd(020, FALSE, p3,p4); /* p3-p4 */ - (void)fp_exec(020, &p1, c, m2); /* VR[idx1] := (p1-p2) - imag(W*(c,d)) */ - WriteOp(RE(v + idx1), p1, fp_f); - (void)fp_exec(000, &p2, d, m1); /* VI[idx1] := (p3-p4) + real(W*(c,d)) */ - WriteOp(IM(v + idx1), p2, fp_f); - (void)fp_exec(000, &p1, c, m2); /* VR[idx2] := (p1+p2) + imag(W*(c,d)) */ - WriteOp(RE(v + idx2), p1, fp_f); - (void)fp_exec(020, &p2, m1, d); /* VI[idx2] := imag(W*(c,d)) - (p3-p4) */ - WriteOp(IM(v + idx2), p2, fp_f); - PC = op[0].word & VAMASK; - break; - - case 004: /* BITR1 (OP_AAAKK) */ - /* BITR1 - * bit reversal for FFT, alternative version - * JSB BITR1 - * DEF ret(,I) return address if already swapped - * DEF revect,I base address of real vect - * DEF imvect,I base address of imag vect - * DEF idx,I index bitmap to be reversed (one-based) - * DEF nbits,I number of bits of index - * - * Given a complex*8 vector of nbits (power of 2), this calculates: - * swap( vect[idx], vect[rev(idx)]) where rev(i) is the bitreversed value of i - * - * difference to BITRV is that BITRV uses complex*8, and BITR1 uses separate real*4 - * vectors for Real and Imag parts */ - sig_bitrev(op[1].word, op[2].word, op[3].word-1, op[4].word, 2); - PC = op[0].word & VAMASK; - break; - - - case 005: /* BTRF1 (OP_AAAFFKK) */ - /* BTRF1 - butterfly operation with real*4 vectors - * JSB BTRF1 - * DEF ret(,I) return address - * DEF rvect,I real part of vector - * DEF ivect,I imag part of vector - * DEF wr,I real part of W - * DEF wi,I imag part of W - * DEF node,I index (1 based) - * DEF lmax,I index (0 based) */ - sig_btrfy(op[1].word, op[2].word, - op[3], op[4], - op[5].word-1, op[6].word); - PC = op[0].word & VAMASK; - break; - - case 006: /* .CADD (OP_AAA) */ - /* .CADD Complex addition - * JSB .CADD - * DEF result,I - * DEF oprd1,I - * DEF oprd2,I - * complex addition is: (a+bi) + (c+di) => (a+c) + (b+d)i */ - sig_caddsub(000,op); - break; - - case 007: /* .CSUB (OP_AAA) */ - /* .CSUB Complex subtraction - * JSB .CSUB - * DEF result,I - * DEF oprd1,I - * DEF oprd2,I - * complex subtraction is: (a+bi) - (c+di) => (a - c) + (b - d)i */ - sig_caddsub(020,op); - break; - - case 010: /* .CMUL (OP_AAA) */ - /* .CMPY Complex multiplication - * call: - * JSB .CMPY - * DEF result,I - * DEF oprd1,I - * DEF oprd2,I - * complex multiply is: (a+bi)*(c+di) => (ac-bd) + (ad+bc)i */ - a = ReadOp(RE(op[1].word), fp_f); /* read 1st op */ - b = ReadOp(IM(op[1].word), fp_f); - c = ReadOp(RE(op[2].word), fp_f); /* read 2nd op */ - d = ReadOp(IM(op[2].word), fp_f); - sig_cmul(&p1, &p2, a, b, c, d); - WriteOp(RE(op[0].word), p1, fp_f); /* write real result */ - WriteOp(IM(op[0].word), p2, fp_f); /* write imag result */ - break; - - case 011: /* .CDIV (OP_AAA) */ - /* .CDIV Complex division - * call: - * JSB .CDIV - * DEF result,I - * DEF oprd1,I - * DEF oprd2,I - * complex division is: (a+bi)/(c+di) => ((ac+bd) + (bc-ad)i)/(c^2+d^2) */ - a = ReadOp(RE(op[1].word), fp_f); /* read 1st op */ - b = ReadOp(IM(op[1].word), fp_f); - c = ReadOp(RE(op[2].word), fp_f); /* read 2nd op */ - d = ReadOp(IM(op[2].word), fp_f); - (void)fp_unpack (NULL, &exc, c, fp_f); /* get exponents */ - (void)fp_unpack (NULL, &exd, d, fp_f); - if (exc < exd) { /* ensure c/d < 1 */ - p1 = a; a = c; c = p1; /* swap dividend and divisor */ - p1 = b; b = d; d = p1; - } - (void)fp_exec(060, &p1, d, c); /* p1,accu := d/c */ - (void)fp_exec(044, ACCUM, d, NOP); /* ACCUM := dd/c */ - (void)fp_exec(004, &p2, c, NOP); /* p2 := c + dd/c */ - (void)fp_exec(040, ACCUM, b, p1); /* ACCUM := bd/c */ - (void)fp_exec(004, ACCUM, a, NOP); /* ACCUM := a + bd/c */ - (void)fp_exec(070, &p3, NOP, p2); /* p3 := (a+bd/c)/(c+dd/c) == (ac+bd)/(cc+dd) */ - WriteOp(RE(op[0].word), p3, fp_f); /* Write real result */ - (void)fp_exec(040, ACCUM, a, p1); /* ACCUM := ad/c */ - (void)fp_exec(030, ACCUM, NOP, b); /* ACCUM := ad/c - b */ - if (exd < exc) { /* was not swapped? */ - (void)fp_exec(024, ACCUM, zero, NOP); /* ACCUM := -ACCUM */ - } - (void)fp_exec(070, &p3, NOP, p2); /* p3 := (b-ad/c)/(c+dd/c) == (bc-ad)/cc+dd) */ - WriteOp(IM(op[0].word), p3, fp_f); /* Write imag result */ - break; - - case 012: /* CONJG (OP_AAA) */ - /* CONJG build A-Bi from A+Bi - * call: - * JSB CONJG - * DEF RTN - * DEF res,I result - * DEF arg,I input argument */ - a = ReadOp(RE(op[2].word), fp_f); /* read real */ - b = ReadOp(IM(op[2].word), fp_f); /* read imag */ - (void)fp_pcom(&b, fp_f); /* negate imag */ - WriteOp(RE(op[1].word), a, fp_f); /* write real */ - WriteOp(IM(op[1].word), b, fp_f); /* write imag */ - break; - - case 013: /* ..CCM (OP_A) */ - /* ..CCM complement complex - * call - * JSB ..CCM - * DEF arg - * build (-RE,-IM) - */ - v = op[0].word; - a = ReadOp(RE(v), fp_f); /* read real */ - b = ReadOp(IM(v), fp_f); /* read imag */ - (void)fp_pcom(&a, fp_f); /* negate real */ - (void)fp_pcom(&b, fp_f); /* negate imag */ - WriteOp(RE(v), a, fp_f); /* write real */ - WriteOp(IM(v), b, fp_f); /* write imag */ - break; - - case 014: /* AIMAG (OP_AA) */ - /* AIMAG return the imaginary part in AB - * JSB AIMAG - * DEF *+2 - * DEF cplx(,I) - * returns: AB imaginary part of complex number */ - a = ReadOp(IM(op[1].word), fp_f); /* read imag */ - AR = a.fpk[0]; /* move MSB to A */ - BR = a.fpk[1]; /* move LSB to B */ - break; - - case 015: /* CMPLX (OP_AFF) */ - /* CMPLX form a complex number - * JSB CMPLX - * DEF *+4 - * DEF result,I complex number - * DEF repart,I real value - * DEF impart,I imaginary value */ - WriteOp(RE(op[1].word), op[2], fp_f); /* write real part */ - WriteOp(IM(op[1].word), op[3], fp_f); /* write imag part */ - break; - - case 017: /* [slftst] (OP_N) */ - XR = 2; /* firmware revision */ - SR = 0102077; /* test passed code */ - PC = (PC + 1) & VAMASK; /* P+2 return for firmware w/SIGNAL1000 */ - break; - - case 016: /* invalid */ - default: /* others undefined */ - reason = stop_inst; - } - -return reason; -} - -#endif /* end of int64 support */ +/* hp2100_cpu7.c: HP 1000 VIS and SIGNAL/1000 microcode + + Copyright (c) 2008, Holger Veit + Copyright (c) 2006-2014, J. David Bryan + + 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 + THE AUTHORS 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 the authors shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from the authors. + + CPU7 Vector Instruction Set and SIGNAL firmware + + 24-Dec-14 JDB Added casts for explicit downward conversions + 18-Mar-13 JDB Moved EMA helper declarations to hp2100_cpu1.h + 09-May-12 JDB Separated assignments from conditional expressions + 06-Feb-12 JDB Corrected "opsize" parameter type in vis_abs + 11-Sep-08 JDB Moved microcode function prototypes to hp2100_cpu1.h + 05-Sep-08 JDB Removed option-present tests (now in UIG dispatchers) + 30-Apr-08 JDB Updated SIGNAL code from Holger + 24-Apr-08 HV Implemented SIGNAL + 20-Apr-08 JDB Updated comments + 26-Feb-08 HV Implemented VIS + + Primary references: + - HP 1000 M/E/F-Series Computers Technical Reference Handbook + (5955-0282, Mar-1980) + - HP 1000 M/E/F-Series Computers Engineering and Reference Documentation + (92851-90001, Mar-1981) + - Macro/1000 Reference Manual (92059-90001, Dec-1992) + + Additional references are listed with the associated firmware + implementations, as are the HP option model numbers pertaining to the + applicable CPUs. +*/ + +#include "hp2100_defs.h" +#include "hp2100_cpu.h" +#include "hp2100_cpu1.h" + +#if defined (HAVE_INT64) /* int64 support available */ + +#include "hp2100_fp1.h" + + +static const OP zero = { { 0, 0, 0, 0, 0 } }; /* DEC 0.0D0 */ + + +/* Vector Instruction Set + + The VIS provides instructions that operate on one-dimensional arrays of + floating-point values. Both single- and double-precision operations are + supported. VIS uses the F-Series floating-point processor to handle the + floating-point math. + + Option implementation by CPU was as follows: + + 2114 2115 2116 2100 1000-M 1000-E 1000-F + ------ ------ ------ ------ ------ ------ ------ + N/A N/A N/A N/A N/A N/A 12824A + + The routines are mapped to instruction codes as follows: + + Single-Precision Double-Precision + Instr. Opcode Subcod Instr. Opcode Subcod Description + ------ ------ ------ ------ ------ ------ ----------------------------- + VADD 101460 000000 DVADD 105460 004002 Vector add + VSUB 101460 000020 DVSUB 105460 004022 Vector subtract + VMPY 101460 000040 DVMPY 105460 004042 Vector multiply + VDIV 101460 000060 DVDIV 105460 004062 Vector divide + VSAD 101460 000400 DVSAD 105460 004402 Scalar-vector add + VSSB 101460 000420 DVSSB 105460 004422 Scalar-vector subtract + VSMY 101460 000440 DVSMY 105460 004442 Scalar-vector multiply + VSDV 101460 000460 DVSDV 105460 004462 Scalar-vector divide + VPIV 101461 0xxxxx DVPIV 105461 0xxxxx Vector pivot + VABS 101462 0xxxxx DVABS 105462 0xxxxx Vector absolute value + VSUM 101463 0xxxxx DVSUM 105463 0xxxxx Vector sum + VNRM 101464 0xxxxx DVNRM 105464 0xxxxx Vector norm + VDOT 101465 0xxxxx DVDOT 105465 0xxxxx Vector dot product + VMAX 101466 0xxxxx DVMAX 105466 0xxxxx Vector maximum value + VMAB 101467 0xxxxx DVMAB 105467 0xxxxx Vector maximum absolute value + VMIN 101470 0xxxxx DVMIN 105470 0xxxxx Vector minimum value + VMIB 101471 0xxxxx DVMIB 105471 0xxxxx Vector minimum absolute value + VMOV 101472 0xxxxx DVMOV 105472 0xxxxx Vector move + VSWP 101473 0xxxxx DVSWP 105473 0xxxxx Vector swap + .ERES 101474 -- -- -- -- Resolve array element address + .ESEG 101475 -- -- -- -- Load MSEG maps + .VSET 101476 -- -- -- -- Vector setup + [test] -- -- -- 105477 -- [self test] + + Instructions use IR bit 11 to select single- or double-precision format. The + double-precision instruction names begin with "D" (e.g., DVADD vs. VADD). + Most VIS instructions are two words in length, with a sub-opcode immediately + following the primary opcode. + + Notes: + + 1. The .VECT (101460) and .DVCT (105460) opcodes preface a single- or + double-precision arithmetic operation that is determined by the + sub-opcode value. The remainder of the dual-precision sub-opcode values + are "don't care," except for requiring a zero in bit 15. + + 2. The VIS uses the hardware FPP of the F-Series. FPP malfunctions are + detected by the VIS firmware and are indicated by a memory-protect + violation and setting the overflow flag. Under simulation, + malfunctions cannot occur. + + Additional references: + - 12824A Vector Instruction Set User's Manual (12824-90001, Jun-1979). + - VIS Microcode Source (12824-18059, revision 3). +*/ + +static const OP_PAT op_vis[16] = { + OP_N, OP_AAKAKAKK,OP_AKAKK, OP_AAKK, /* .VECT VPIV VABS VSUM */ + OP_AAKK, OP_AAKAKK, OP_AAKK, OP_AAKK, /* VNRM VDOT VMAX VMAB */ + OP_AAKK, OP_AAKK, OP_AKAKK, OP_AKAKK, /* VMIN VMIB VMOV VSWP */ + OP_AA, OP_A, OP_AAACCC,OP_N /* .ERES .ESEG .VSET [test] */ + }; + +static const t_bool op_ftnret[16] = { + FALSE, TRUE, TRUE, TRUE, + TRUE, TRUE, TRUE, TRUE, + TRUE, TRUE, TRUE, TRUE, + FALSE, TRUE, TRUE, FALSE, + }; + + +/* handle the scalar/vector base ops */ +static void vis_svop(uint32 subcode, OPS op, OPSIZE opsize) +{ +OP v1,v2; +int16 delta = opsize==fp_f ? 2 : 4; +OP s = ReadOp(op[0].word,opsize); +uint32 v1addr = op[1].word; +int16 ix1 = INT16(op[2].word) * delta; +uint32 v2addr = op[3].word; +int16 ix2 = INT16(op[4].word) * delta; +int16 i, n = INT16(op[5].word); +uint16 fpuop = (uint16) (subcode & 060) | (opsize==fp_f ? 0 : 2); + +if (n <= 0) return; +for (i=0; ifpk[0] & 0100000) + +static void vis_abs(OP* in, OPSIZE opsize) +{ +uint32 sign = GET_MSIGN(in); /* get sign */ +if (sign) (void)fp_pcom(in, opsize); /* if negative, make positive */ +} + +static void vis_minmax(OPS op,OPSIZE opsize,t_bool domax,t_bool doabs) +{ +OP v1,vmxmn,res; +int16 delta = opsize==fp_f ? 2 : 4; +uint32 mxmnaddr = op[0].word; +uint32 v1addr = op[1].word; +int16 ix1 = INT16(op[2].word) * delta; +int16 n = INT16(op[3].word); +int16 i,mxmn,sign; +uint16 subop = 020 | (opsize==fp_f ? 0 : 2); + +if (n <= 0) return; +mxmn = 0; /* index of maxmin element */ +vmxmn = ReadOp(v1addr,opsize); /* initialize with first element */ +if (doabs) vis_abs(&vmxmn,opsize); /* ABS(v[1]) if requested */ + +for (i = 0; ifpk[0] = in.fpk[0]; +out->fpk[1] = (in.fpk[1] & 0177400) | (in.fpk[3] & 0377); +} + +static void vis_vsmnm(OPS op,OPSIZE opsize,t_bool doabs) +{ +uint16 fpuop; +OP v1,sumnrm = zero; +int16 delta = opsize==fp_f ? 2 : 4; +uint32 saddr = op[0].word; +uint32 v1addr = op[1].word; +int16 ix1 = INT16(op[2].word) * delta; +int16 i,n = INT16(op[3].word); + +if (n <= 0) return; +/* calculates sumnrm = sumnrm + DBLE(v1[i]) resp DBLE(ABS(v1[i])) for incrementing i */ +for (i=0; i>CPU VIS: IR = %06o/%06o (", /* print preamble and IR */ + IR, subcode); + fprint_sym (sim_deb, err_PC, (t_value *) &IR, /* print instruction mnemonic */ + NULL, SWMASK('M')); + fprintf (sim_deb, "), P = %06o", err_PC); /* print location */ + fprint_ops (pattern, op); /* print operands */ + fputc ('\n', sim_deb); /* terminate line */ + } + +switch (entry) { /* decode IR<3:0> */ + case 000: /* .VECT (OP_special) */ + if (subcode & 0400) + vis_svop(subcode,op,opsize); /* scalar/vector op */ + else + vis_vvop(subcode,op,opsize); /* vector/vector op */ + break; + case 001: /* VPIV (OP_(A)AAKAKAKK) */ + vis_vpiv(op,opsize); + break; + case 002: /* VABS (OP_(A)AKAKK) */ + vis_vabs(op,opsize); + break; + case 003: /* VSUM (OP_(A)AAKK) */ + vis_vsmnm(op,opsize,FALSE); + break; + case 004: /* VNRM (OP_(A)AAKK) */ + vis_vsmnm(op,opsize,TRUE); + break; + case 005: /* VDOT (OP_(A)AAKAKK) */ + vis_vdot(op,opsize); + break; + case 006: /* VMAX (OP_(A)AAKK) */ + vis_minmax(op,opsize,TRUE,FALSE); + break; + case 007: /* VMAB (OP_(A)AAKK) */ + vis_minmax(op,opsize,TRUE,TRUE); + break; + case 010: /* VMIN (OP_(A)AAKK) */ + vis_minmax(op,opsize,FALSE,FALSE); + break; + case 011: /* VMIB (OP_(A)AAKK) */ + vis_minmax(op,opsize,FALSE,TRUE); + break; + case 012: /* VMOV (OP_(A)AKAKK) */ + vis_movswp(op,opsize,FALSE); + break; + case 013: /* VSWP (OP_(A)AKAKK) */ + vis_movswp(op,opsize,TRUE); + break; + case 014: /* .ERES (OP_(A)AA) */ + reason = cpu_ema_eres(&rtn,op[2].word,PC,debug); /* handle the ERES instruction */ + PC = rtn; + if (debug) + fprintf (sim_deb, + ">>CPU VIS: return .ERES: AR = %06o, BR = %06o, rtn=%s\n", + AR, BR, PC==op[0].word ? "error" : "good"); + break; + + case 015: /* .ESEG (OP_(A)A) */ + reason = cpu_ema_eseg(&rtn,IR,op[0].word,debug); /* handle the ESEG instruction */ + PC = rtn; + if (debug) + fprintf (sim_deb, + ">>CPU VIS: return .ESEG: AR = %06o , BR = %06o, rtn=%s\n", + AR, BR, rtn==rtn1 ? "error" : "good"); + break; + + case 016: /* .VSET (OP_(A)AAACCC) */ + reason = cpu_ema_vset(&rtn,op,debug); + PC = rtn; + if (debug) + fprintf (sim_deb, ">>CPU VIS: return .VSET: AR = %06o BR = %06o, rtn=%s\n", + AR, BR, + rtn==rtn1 ? "error" : (rtn==(rtn1+1) ? "hard" : "easy") ); + break; + + case 017: /* [test] (OP_N) */ + XR = 3; /* firmware revision */ + SR = 0102077; /* test passed code */ + PC = (PC + 1) & VAMASK; /* P+2 return for firmware w/VIS */ + break; + default: /* others undefined */ + reason = stop_inst; + } + +return reason; +} + + +/* SIGNAL/1000 Instructions + + The SIGNAL/1000 instructions provide fast Fourier transforms and complex + arithmetic. They utilize the F-Series floating-point processor and the + Vector Instruction Set. + + Option implementation by CPU was as follows: + + 2114 2115 2116 2100 1000-M 1000-E 1000-F + ------ ------ ------ ------ ------ ------ ------ + N/A N/A N/A N/A N/A N/A 92835A + + The routines are mapped to instruction codes as follows: + + Instr. 1000-F Description + ------ ------ ---------------------------------------------- + BITRV 105600 Bit reversal + BTRFY 105601 Butterfly algorithm + UNSCR 105602 Unscramble for phasor MPY + PRSCR 105603 Unscramble for phasor MPY + BITR1 105604 Swap two elements in array (alternate format) + BTRF1 105605 Butterfly algorithm (alternate format) + .CADD 105606 Complex number addition + .CSUB 105607 Complex number subtraction + .CMPY 105610 Complex number multiplication + .CDIV 105611 Complex number division + CONJG 105612 Complex conjugate + ..CCM 105613 Complex complement + AIMAG 105614 Return imaginary part + CMPLX 105615 Form complex number + [nop] 105616 [no operation] + [test] 105617 [self test] + + Notes: + + 1. SIGNAL/1000 ROM data are available from Bitsavers. + + Additional references (documents unavailable): + - HP Signal/1000 User Reference and Installation Manual (92835-90002). + - SIGNAL/1000 Microcode Source (92835-18075, revision 2). +*/ + +#define RE(x) (x+0) +#define IM(x) (x+2) + +static const OP_PAT op_signal[16] = { + OP_AAKK, OP_AAFFKK, OP_AAFFKK,OP_AAFFKK, /* BITRV BTRFY UNSCR PRSCR */ + OP_AAAKK, OP_AAAFFKK,OP_AAA, OP_AAA, /* BITR1 BTRF1 .CADD .CSUB */ + OP_AAA, OP_AAA, OP_AAA, OP_A, /* .CMPY .CDIV CONJG ..CCM */ + OP_AA, OP_AAFF, OP_N, OP_N /* AIMAG CMPLX --- [test]*/ + }; + +/* complex addition helper */ +static void sig_caddsub(uint16 addsub,OPS op) +{ +OP a,b,c,d,p1,p2; + +a = ReadOp(RE(op[1].word), fp_f); /* read 1st op */ +b = ReadOp(IM(op[1].word), fp_f); +c = ReadOp(RE(op[2].word), fp_f); /* read 2nd op */ +d = ReadOp(IM(op[2].word), fp_f); +(void)fp_exec(addsub,&p1, a, c); /* add real */ +(void)fp_exec(addsub,&p2, b, d); /* add imag */ +WriteOp(RE(op[0].word), p1, fp_f); /* write result */ +WriteOp(IM(op[0].word), p2, fp_f); /* write result */ +} + +/* butterfly operation helper */ +static void sig_btrfy(uint32 re,uint32 im,OP wr,OP wi,uint32 k, uint32 n2) +{ +/* + * v(k)-------->o-->o----> v(k) + * \ / + * x + * / \ + * v(k+N/2)---->o-->o----> v(k+N/2) + * Wn -1 + * + */ + +OP p1,p2,p3,p4; +OP v1r = ReadOp(re+k, fp_f); /* read v1 */ +OP v1i = ReadOp(im+k, fp_f); +OP v2r = ReadOp(re+k+n2, fp_f); /* read v2 */ +OP v2i = ReadOp(im+k+n2, fp_f); + +/* (p1,p2) := cmul(w,v2) */ +(void)fp_exec(040, &p1, wr, v2r); /* S7,8 p1 := wr*v2r */ +(void)fp_exec(040, ACCUM, wi, v2i); /* ACCUM := wi*v2i */ +(void)fp_exec(024, &p1, p1, NOP); /* S7,S8 p1 := wr*v2r-wi*v2i ==real(w*v2) */ +(void)fp_exec(040, &p2, wi, v2r); /* S9,10 p2 := wi*v2r */ +(void)fp_exec(040, ACCUM, wr, v2i); /* ACCUM := wr*v2i */ +(void)fp_exec(004, &p2, p2, NOP); /* S9,10 p2 := wi*v2r+wr*v2i ==imag(w*v2) */ +/* v2 := v1 - (p1,p2) */ +(void)fp_exec(020, &p3, v1r, p1); /* v2r := v1r-real(w*v2) */ +(void)fp_exec(020, &p4, v1i, p2); /* v2i := v1i-imag(w*v2) */ +WriteOp(re+k+n2, p3, fp_f); /* write v2r */ +WriteOp(im+k+n2, p4, fp_f); /* write v2i */ +/* v1 := v1 + (p1,p2) */ +(void)fp_exec(0, &p3, v1r, p1); /* v1r := v1r+real(w*v2) */ +(void)fp_exec(0, &p4, v1i, p2); /* v1i := v1i+imag(w*v2) */ +WriteOp(re+k, p3, fp_f); /* write v1r */ +WriteOp(im+k, p4, fp_f); /* write v1i */ +O = 0; +} + +/* helper for bit reversal + * idx is 0-based already */ +static void sig_bitrev(uint32 re,uint32 im, uint32 idx, uint32 log2n, int sz) +{ +uint32 i, org=idx, rev = 0; +OP v1r,v1i,v2r,v2i; + +for (i=0; i>= 1; +} + +if (rev < idx) return; /* avoid swapping same pair twice in loop */ + +idx *= sz; /* adjust for element size */ +rev *= sz; /* (REAL*4 vs COMPLEX*8) */ + +v1r = ReadOp(re+idx, fp_f); /* read 1st element */ +v1i = ReadOp(im+idx, fp_f); +v2r = ReadOp(re+rev, fp_f); /* read 2nd element */ +v2i = ReadOp(im+rev, fp_f); +WriteOp(re+idx, v2r, fp_f); /* swap elements */ +WriteOp(im+idx, v2i, fp_f); +WriteOp(re+rev, v1r, fp_f); +WriteOp(im+rev, v1i, fp_f); +} + +/* helper for PRSCR/UNSCR */ +static OP sig_scadd(uint16 oper,t_bool addh, OP a, OP b) +{ +OP r; +static const OP plus_half = { { 0040000, 0000000 } }; /* DEC +0.5 */ + +(void)fp_exec(oper,&r,a,b); /* calculate r := a +/- b */ +if (addh) (void)fp_exec(044,&r,plus_half,NOP); /* if addh set, multiply by 0.5 */ +return r; +} + +/* complex multiply helper */ +static void sig_cmul(OP *r, OP *i, OP a, OP b, OP c, OP d) +{ +OP p; +(void)fp_exec(040, &p , a, c); /* p := ac */ +(void)fp_exec(040, ACCUM, b, d); /* ACCUM := bd */ +(void)fp_exec(024, r, p , NOP); /* real := ac-bd */ +(void)fp_exec(040, &p, a, d); /* p := ad */ +(void)fp_exec(040, ACCUM, b, c); /* ACCUM := bc */ +(void)fp_exec(004, i, p, NOP); /* imag := ad+bc */ +} + +t_stat cpu_signal (uint32 IR, uint32 intrq) +{ +t_stat reason = SCPE_OK; +OPS op; +OP a,b,c,d,p1,p2,p3,p4,m1,m2,wr,wi; +uint32 entry, v, idx1, idx2; +int32 exc, exd; + +t_bool debug = DEBUG_PRI (cpu_dev, DEB_SIG); + +entry = IR & 017; /* mask to entry point */ + +if (op_signal [entry] != OP_N) { + reason = cpu_ops (op_signal [entry], op, intrq); /* get instruction operands */ + if (reason != SCPE_OK) /* evaluation failed? */ + return reason; /* return reason for failure */ + } + +if (debug) { /* debugging? */ + fprintf (sim_deb, ">>CPU SIG: IR = %06o (", IR); /* print preamble and IR */ + fprint_sym (sim_deb, err_PC, (t_value *) &IR, /* print instruction mnemonic */ + NULL, SWMASK('M')); + fprintf (sim_deb, "), P = %06o", err_PC); /* print location */ + fprint_ops (op_signal[entry], op); /* print operands */ + fputc ('\n', sim_deb); /* terminate line */ + } + +switch (entry) { /* decode IR<3:0> */ + case 000: /* BITRV (OP_AAKK) */ + /* BITRV + * bit reversal for FFT + * JSB BITRV + * DEF ret(,I) return address + * DEF vect,I base address of array + * DEF idx,I index bitmap to be reversed (one-based) + * DEF nbits,I number of bits of index + * + * Given a complex*8 vector of nbits (power of 2), this calculates: + * swap( vect[idx], vect[rev(idx)]) where rev(i) is the bitreversed value of i */ + sig_bitrev(op[1].word, op[1].word+2, op[2].word-1, op[3].word, 4); + PC = op[0].word & VAMASK; + break; + + case 001: /* BTRFY (OP_AAFFKK) */ + /* BTRFY - butterfly operation + * JSB BTRFY + * DEF ret(,I) return address + * DEF vect(,I) complex*8 vector + * DEF wr,I real part of W + * DEF wi,I imag part of W + * DEF node,I index of 1st op (1 based) + * DEF lmax,I offset to 2nd op (0 based) */ + sig_btrfy(op[1].word, op[1].word+2, + op[2], op[3], + 2*(op[4].word-1), 2*op[5].word); + PC = op[0].word & VAMASK; + break; + + case 002: /* UNSCR (OP_AAFFKK) */ + /* UNSCR unscramble for phasor MPY + * JSB UNSCR + * DEF ret(,I) + * DEF vector,I + * DEF WR + * DEF WI + * DEF idx1,I + * DEF idx2,I */ + v = op[1].word; + idx1 = 2 * (op[4].word - 1); + idx2 = 2 * (op[5].word - 1); + wr = op[2]; /* read WR */ + wi = op[3]; /* read WI */ + p1 = ReadOp(RE(v + idx1), fp_f); /* S1 VR[idx1] */ + p2 = ReadOp(RE(v + idx2), fp_f); /* S2 VR[idx2] */ + p3 = ReadOp(IM(v + idx1), fp_f); /* S9 VI[idx1] */ + p4 = ReadOp(IM(v + idx2), fp_f); /* S10 VI[idx2] */ + c = sig_scadd(000, TRUE, p3, p4); /* S5,6 0.5*(p3+p4) */ + d = sig_scadd(020, TRUE, p2, p1); /* S7,8 0.5*(p2-p1) */ + sig_cmul(&m1, &m2, wr, wi, c, d); /* (WR,WI) * (c,d) */ + c = sig_scadd(000, TRUE, p1, p2); /* 0.5*(p1+p2) */ + d = sig_scadd(020, TRUE, p3, p4); /* 0.5*(p3-p4) */ + (void)fp_exec(000, &p1, c, m1); /* VR[idx1] := 0.5*(p1+p2) + real(W*(c,d)) */ + WriteOp(RE(v + idx1), p1, fp_f); + (void)fp_exec(000, &p2, d, m2); /* VI[idx1] := 0.5*(p3-p4) + imag(W*(c,d)) */ + WriteOp(IM(v + idx1), p2, fp_f); + (void)fp_exec(020, &p1, c, m1); /* VR[idx2] := 0.5*(p1+p2) - imag(W*(c,d)) */ + WriteOp(RE(v + idx2), p1, fp_f); + (void)fp_exec(020, &p2, d, m2); /* VI[idx2] := 0.5*(p3-p4) - imag(W*(c,d)) */ + WriteOp(IM(v + idx2), p2, fp_f); + PC = op[0].word & VAMASK; + break; + + case 003: /* PRSCR (OP_AAFFKK) */ + /* PRSCR unscramble for phasor MPY + * JSB PRSCR + * DEF ret(,I) + * DEF vector,I + * DEF WR + * DEF WI + * DEF idx1,I + * DEF idx2,I */ + v = op[1].word; + idx1 = 2 * (op[4].word - 1); + idx2 = 2 * (op[5].word - 1); + wr = op[2]; /* read WR */ + wi = op[3]; /* read WI */ + p1 = ReadOp(RE(v + idx1), fp_f); /* VR[idx1] */ + p2 = ReadOp(RE(v + idx2), fp_f); /* VR[idx2] */ + p3 = ReadOp(IM(v + idx1), fp_f); /* VI[idx1] */ + p4 = ReadOp(IM(v + idx2), fp_f); /* VI[idx2] */ + c = sig_scadd(020, FALSE, p1, p2); /* p1-p2 */ + d = sig_scadd(000, FALSE, p3, p4); /* p3+p4 */ + sig_cmul(&m1,&m2, wr, wi, c, d); /* (WR,WI) * (c,d) */ + c = sig_scadd(000, FALSE, p1, p2); /* p1+p2 */ + d = sig_scadd(020, FALSE, p3,p4); /* p3-p4 */ + (void)fp_exec(020, &p1, c, m2); /* VR[idx1] := (p1-p2) - imag(W*(c,d)) */ + WriteOp(RE(v + idx1), p1, fp_f); + (void)fp_exec(000, &p2, d, m1); /* VI[idx1] := (p3-p4) + real(W*(c,d)) */ + WriteOp(IM(v + idx1), p2, fp_f); + (void)fp_exec(000, &p1, c, m2); /* VR[idx2] := (p1+p2) + imag(W*(c,d)) */ + WriteOp(RE(v + idx2), p1, fp_f); + (void)fp_exec(020, &p2, m1, d); /* VI[idx2] := imag(W*(c,d)) - (p3-p4) */ + WriteOp(IM(v + idx2), p2, fp_f); + PC = op[0].word & VAMASK; + break; + + case 004: /* BITR1 (OP_AAAKK) */ + /* BITR1 + * bit reversal for FFT, alternative version + * JSB BITR1 + * DEF ret(,I) return address if already swapped + * DEF revect,I base address of real vect + * DEF imvect,I base address of imag vect + * DEF idx,I index bitmap to be reversed (one-based) + * DEF nbits,I number of bits of index + * + * Given a complex*8 vector of nbits (power of 2), this calculates: + * swap( vect[idx], vect[rev(idx)]) where rev(i) is the bitreversed value of i + * + * difference to BITRV is that BITRV uses complex*8, and BITR1 uses separate real*4 + * vectors for Real and Imag parts */ + sig_bitrev(op[1].word, op[2].word, op[3].word-1, op[4].word, 2); + PC = op[0].word & VAMASK; + break; + + + case 005: /* BTRF1 (OP_AAAFFKK) */ + /* BTRF1 - butterfly operation with real*4 vectors + * JSB BTRF1 + * DEF ret(,I) return address + * DEF rvect,I real part of vector + * DEF ivect,I imag part of vector + * DEF wr,I real part of W + * DEF wi,I imag part of W + * DEF node,I index (1 based) + * DEF lmax,I index (0 based) */ + sig_btrfy(op[1].word, op[2].word, + op[3], op[4], + op[5].word-1, op[6].word); + PC = op[0].word & VAMASK; + break; + + case 006: /* .CADD (OP_AAA) */ + /* .CADD Complex addition + * JSB .CADD + * DEF result,I + * DEF oprd1,I + * DEF oprd2,I + * complex addition is: (a+bi) + (c+di) => (a+c) + (b+d)i */ + sig_caddsub(000,op); + break; + + case 007: /* .CSUB (OP_AAA) */ + /* .CSUB Complex subtraction + * JSB .CSUB + * DEF result,I + * DEF oprd1,I + * DEF oprd2,I + * complex subtraction is: (a+bi) - (c+di) => (a - c) + (b - d)i */ + sig_caddsub(020,op); + break; + + case 010: /* .CMUL (OP_AAA) */ + /* .CMPY Complex multiplication + * call: + * JSB .CMPY + * DEF result,I + * DEF oprd1,I + * DEF oprd2,I + * complex multiply is: (a+bi)*(c+di) => (ac-bd) + (ad+bc)i */ + a = ReadOp(RE(op[1].word), fp_f); /* read 1st op */ + b = ReadOp(IM(op[1].word), fp_f); + c = ReadOp(RE(op[2].word), fp_f); /* read 2nd op */ + d = ReadOp(IM(op[2].word), fp_f); + sig_cmul(&p1, &p2, a, b, c, d); + WriteOp(RE(op[0].word), p1, fp_f); /* write real result */ + WriteOp(IM(op[0].word), p2, fp_f); /* write imag result */ + break; + + case 011: /* .CDIV (OP_AAA) */ + /* .CDIV Complex division + * call: + * JSB .CDIV + * DEF result,I + * DEF oprd1,I + * DEF oprd2,I + * complex division is: (a+bi)/(c+di) => ((ac+bd) + (bc-ad)i)/(c^2+d^2) */ + a = ReadOp(RE(op[1].word), fp_f); /* read 1st op */ + b = ReadOp(IM(op[1].word), fp_f); + c = ReadOp(RE(op[2].word), fp_f); /* read 2nd op */ + d = ReadOp(IM(op[2].word), fp_f); + (void)fp_unpack (NULL, &exc, c, fp_f); /* get exponents */ + (void)fp_unpack (NULL, &exd, d, fp_f); + if (exc < exd) { /* ensure c/d < 1 */ + p1 = a; a = c; c = p1; /* swap dividend and divisor */ + p1 = b; b = d; d = p1; + } + (void)fp_exec(060, &p1, d, c); /* p1,accu := d/c */ + (void)fp_exec(044, ACCUM, d, NOP); /* ACCUM := dd/c */ + (void)fp_exec(004, &p2, c, NOP); /* p2 := c + dd/c */ + (void)fp_exec(040, ACCUM, b, p1); /* ACCUM := bd/c */ + (void)fp_exec(004, ACCUM, a, NOP); /* ACCUM := a + bd/c */ + (void)fp_exec(070, &p3, NOP, p2); /* p3 := (a+bd/c)/(c+dd/c) == (ac+bd)/(cc+dd) */ + WriteOp(RE(op[0].word), p3, fp_f); /* Write real result */ + (void)fp_exec(040, ACCUM, a, p1); /* ACCUM := ad/c */ + (void)fp_exec(030, ACCUM, NOP, b); /* ACCUM := ad/c - b */ + if (exd < exc) { /* was not swapped? */ + (void)fp_exec(024, ACCUM, zero, NOP); /* ACCUM := -ACCUM */ + } + (void)fp_exec(070, &p3, NOP, p2); /* p3 := (b-ad/c)/(c+dd/c) == (bc-ad)/cc+dd) */ + WriteOp(IM(op[0].word), p3, fp_f); /* Write imag result */ + break; + + case 012: /* CONJG (OP_AAA) */ + /* CONJG build A-Bi from A+Bi + * call: + * JSB CONJG + * DEF RTN + * DEF res,I result + * DEF arg,I input argument */ + a = ReadOp(RE(op[2].word), fp_f); /* read real */ + b = ReadOp(IM(op[2].word), fp_f); /* read imag */ + (void)fp_pcom(&b, fp_f); /* negate imag */ + WriteOp(RE(op[1].word), a, fp_f); /* write real */ + WriteOp(IM(op[1].word), b, fp_f); /* write imag */ + break; + + case 013: /* ..CCM (OP_A) */ + /* ..CCM complement complex + * call + * JSB ..CCM + * DEF arg + * build (-RE,-IM) + */ + v = op[0].word; + a = ReadOp(RE(v), fp_f); /* read real */ + b = ReadOp(IM(v), fp_f); /* read imag */ + (void)fp_pcom(&a, fp_f); /* negate real */ + (void)fp_pcom(&b, fp_f); /* negate imag */ + WriteOp(RE(v), a, fp_f); /* write real */ + WriteOp(IM(v), b, fp_f); /* write imag */ + break; + + case 014: /* AIMAG (OP_AA) */ + /* AIMAG return the imaginary part in AB + * JSB AIMAG + * DEF *+2 + * DEF cplx(,I) + * returns: AB imaginary part of complex number */ + a = ReadOp(IM(op[1].word), fp_f); /* read imag */ + AR = a.fpk[0]; /* move MSB to A */ + BR = a.fpk[1]; /* move LSB to B */ + break; + + case 015: /* CMPLX (OP_AFF) */ + /* CMPLX form a complex number + * JSB CMPLX + * DEF *+4 + * DEF result,I complex number + * DEF repart,I real value + * DEF impart,I imaginary value */ + WriteOp(RE(op[1].word), op[2], fp_f); /* write real part */ + WriteOp(IM(op[1].word), op[3], fp_f); /* write imag part */ + break; + + case 017: /* [slftst] (OP_N) */ + XR = 2; /* firmware revision */ + SR = 0102077; /* test passed code */ + PC = (PC + 1) & VAMASK; /* P+2 return for firmware w/SIGNAL1000 */ + break; + + case 016: /* invalid */ + default: /* others undefined */ + reason = stop_inst; + } + +return reason; +} + +#endif /* end of int64 support */ diff --git a/HP2100/hp2100_defs.h b/HP2100/hp2100_defs.h index 3118e2d1..1a57a58d 100644 --- a/HP2100/hp2100_defs.h +++ b/HP2100/hp2100_defs.h @@ -1,469 +1,490 @@ -/* hp2100_defs.h: HP 2100 simulator definitions - - Copyright (c) 1993-2012, Robert M. Supnik - - 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 - ROBERT M SUPNIK 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 Robert M Supnik shall not - be used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from Robert M Supnik. - - 10-Feb-12 JDB Added hp_setsc, hp_showsc functions to support SC modifier - 28-Mar-11 JDB Tidied up signal handling - 29-Oct-10 JDB DMA channels renamed from 0,1 to 1,2 to match documentation - 27-Oct-10 JDB Revised I/O signal enum values for concurrent signals - Revised I/O macros for new signal handling - 09-Oct-10 JDB Added DA and DC device select code assignments - 07-Sep-08 JDB Added POLL_FIRST to indicate immediate connection attempt - 15-Jul-08 JDB Rearranged declarations with hp2100_cpu.h - 26-Jun-08 JDB Rewrote device I/O to model backplane signals - 25-Jun-08 JDB Added PIF device - 17-Jun-08 JDB Declared fmt_char() function - 26-May-08 JDB Added MPX device - 24-Apr-08 JDB Added I_MRG_I, I_JSB, I_JSB_I, and I_JMP instruction masks - 14-Apr-08 JDB Changed TMR_MUX to TMR_POLL for idle support - Added POLLMODE, sync_poll() declaration - Added I_MRG, I_ISZ, I_IOG, I_STF, and I_SFS instruction masks - 07-Dec-07 JDB Added BACI device - 10-Nov-07 JDB Added 16/32-bit unsigned-to-signed conversions - 11-Jan-07 JDB Added 12578A DMA byte packing to DMA structure - 28-Dec-06 JDB Added CRS backplane signal as I/O pseudo-opcode - Added DMASK32 32-bit mask value - 21-Dec-06 JDB Changed MEM_ADDR_OK for 21xx loader support - 12-Sep-06 JDB Define NOTE_IOG to recalc interrupts after instr exec - Rename STOP_INDINT to NOTE_INDINT (not a stop condition) - 30-Dec-04 JDB Added IBL_DS_HEAD head number mask - 19-Nov-04 JDB Added STOP_OFFLINE, STOP_PWROFF stop codes - 25-Apr-04 RMS Added additional IBL definitions - Added DMA EDT I/O pseudo-opcode - 25-Apr-03 RMS Revised for extended file support - 24-Oct-02 RMS Added indirect address interrupt - 08-Feb-02 RMS Added DMS definitions - 01-Feb-02 RMS Added terminal multiplexor support - 16-Jan-02 RMS Added additional device support - 30-Nov-01 RMS Added extended SET/SHOW support - 15-Oct-00 RMS Added dynamic device numbers - 14-Apr-99 RMS Changed t_addr to unsigned - - The author gratefully acknowledges the help of Jeff Moffat in answering - questions about the HP2100; and of Dave Bryan in adding features and - correcting errors throughout the simulator. -*/ - - -#ifndef _HP2100_DEFS_H_ -#define _HP2100_DEFS_H_ 0 - -#include "sim_defs.h" /* simulator defns */ - - -/* Simulator stop and notification codes */ - -#define STOP_RSRV 1 /* must be 1 */ -#define STOP_IODV 2 /* must be 2 */ -#define STOP_HALT 3 /* HALT */ -#define STOP_IBKPT 4 /* breakpoint */ -#define STOP_IND 5 /* indirect loop */ -#define NOTE_INDINT 6 /* indirect intr */ -#define STOP_NOCONN 7 /* no connection */ -#define STOP_OFFLINE 8 /* device offline */ -#define STOP_PWROFF 9 /* device powered off */ -#define NOTE_IOG 10 /* I/O instr executed */ - -/* Memory */ - -#define MEMSIZE (cpu_unit.capac) /* actual memory size */ -#define VA_N_SIZE 15 /* virtual addr size */ -#define VASIZE (1 << VA_N_SIZE) -#define VAMASK 077777 /* virt addr mask */ -#define PA_N_SIZE 20 /* phys addr size */ -#define PASIZE (1 << PA_N_SIZE) -#define PAMASK (PASIZE - 1) /* phys addr mask */ - -/* Architectural constants */ - -#define SIGN32 020000000000 /* 32b sign */ -#define DMASK32 037777777777 /* 32b data mask/maximum value */ -#define DMAX32 017777777777 /* 32b maximum signed value */ -#define SIGN 0100000 /* 16b sign */ -#define DMASK 0177777 /* 16b data mask/maximum value */ -#define DMAX 0077777 /* 16b maximum signed value */ -#define DMASK8 0377 /* 8b data mask/maximum value */ - -/* Portable conversions (sign-extension, unsigned-to-signed) */ - -#define SEXT(x) ((int32) (((x) & SIGN)? ((x) | ~DMASK): ((x) & DMASK))) - -#define INT16(u) ((u) > DMAX ? (-(int16) (DMASK - (u)) - 1) : (int16) (u)) -#define INT32(u) ((u) > DMAX32 ? (-(int32) (DMASK32 - (u)) - 1) : (int32) (u)) - -/* Timers */ - -#define TMR_CLK 0 /* clock */ -#define TMR_POLL 1 /* input polling */ - -#define POLL_RATE 100 /* poll 100 times per second */ -#define POLL_FIRST 1 /* first poll is "immediate" */ -#define POLL_WAIT 15800 /* initial poll ~ 10 msec. */ - -typedef enum { INITIAL, SERVICE } POLLMODE; /* poll synchronization modes */ - -/* I/O instruction sub-opcodes */ - -#define soHLT 0 /* halt */ -#define soFLG 1 /* set/clear flag */ -#define soSFC 2 /* skip on flag clear */ -#define soSFS 3 /* skip on flag set */ -#define soMIX 4 /* merge into A/B */ -#define soLIX 5 /* load into A/B */ -#define soOTX 6 /* output from A/B */ -#define soCTL 7 /* set/clear control */ - -/* I/O devices - fixed select code assignments */ - -#define CPU 000 /* interrupt control */ -#define OVF 001 /* overflow */ -#define DMALT1 002 /* DMA 1 alternate */ -#define DMALT2 003 /* DMA 2 alternate */ -#define PWR 004 /* power fail */ -#define PRO 005 /* parity/mem protect */ -#define DMA1 006 /* DMA channel 1 */ -#define DMA2 007 /* DMA channel 2 */ - -/* I/O devices - variable select code assignment defaults */ - -#define PTR 010 /* 12597A-002 paper tape reader */ -#define TTY 011 /* 12531C teleprinter */ -#define PTP 012 /* 12597A-005 paper tape punch */ -#define CLK 013 /* 12539C time-base generator */ -#define LPS 014 /* 12653A line printer */ -#define LPT 015 /* 12845A line printer */ -#define MTD 020 /* 12559A data */ -#define MTC 021 /* 12559A control */ -#define DPD 022 /* 12557A data */ -#define DPC 023 /* 12557A control */ -#define DQD 024 /* 12565A data */ -#define DQC 025 /* 12565A control */ -#define DRD 026 /* 12610A data */ -#define DRC 027 /* 12610A control */ -#define MSD 030 /* 13181A data */ -#define MSC 031 /* 13181A control */ -#define IPLI 032 /* 12566B link in */ -#define IPLO 033 /* 12566B link out */ -#define DS 034 /* 13037A control */ -#define BACI 035 /* 12966A Buffered Async Comm Interface */ -#define MPX 036 /* 12792A/B/C 8-channel multiplexer */ -#define PIF 037 /* 12620A/12936A Privileged Interrupt Fence */ -#define MUXL 040 /* 12920A lower data */ -#define MUXU 041 /* 12920A upper data */ -#define MUXC 042 /* 12920A control */ -#define DI_DA 043 /* 12821A Disc Interface with Amigo disc devices */ -#define DI_DC 044 /* 12821A Disc Interface with CS/80 disc and tape devices */ - -#define OPTDEV 002 /* start of optional devices */ -#define CRSDEV 006 /* start of devices that receive CRS */ -#define VARDEV 010 /* start of variable assignments */ -#define MAXDEV 077 /* end of select code range */ - -/* IBL assignments */ - -#define IBL_V_SEL 14 /* ROM select <15:14> */ -#define IBL_M_SEL 03 -#define IBL_PTR 0000000 /* ROM 0: 12992K paper tape reader (PTR) */ -#define IBL_DP 0040000 /* ROM 1: 12992A 7900 disc (DP) */ -#define IBL_DQ 0060000 /* ROM 1: 12992A 2883 disc (DQ) */ -#define IBL_MS 0100000 /* ROM 2: 12992D 7970 tape (MS) */ -#define IBL_DS 0140000 /* ROM 3: 12992B 7905/06/20/25 disc (DS) */ -#define IBL_MAN 0010000 /* RPL/manual boot <13:12> */ -#define IBL_V_DEV 6 /* select code <11:6> */ -#define IBL_OPT 0000070 /* options in <5:3> */ -#define IBL_DP_REM 0000001 /* DP removable <0:0> */ -#define IBL_DS_HEAD 0000003 /* DS head number <1:0> */ -#define IBL_LNT 64 /* boot ROM length in words */ -#define IBL_MASK (IBL_LNT - 1) /* boot length mask */ -#define IBL_DPC (IBL_LNT - 2) /* DMA ctrl word */ -#define IBL_END (IBL_LNT - 1) /* last location */ - -typedef uint16 BOOT_ROM [IBL_LNT]; /* boot ROM data */ - - -/* I/O backplane signals. - - The IOSIGNAL declarations mirror the hardware I/O backplane signals. A set - of one or more signals forms an IOCYCLE that is sent to a device IOHANDLER - for action. The CPU and DMA dispatch one signal set to the target device - handler per I/O cycle. A CPU cycle consists of either one or two signals; if - present, the second signal will be CLF. A DMA cycle consists of from two to - five signals. In addition, a front-panel PRESET or power-on reset dispatches - two or three signals, respectively. - - In hardware, signals are assigned to one or more specific I/O T-periods, and - some signals are asserted concurrently. For example, a programmed STC sc,C - instruction asserts the STC and CLF signals together in period T4. Under - simulation, signals are ORed to form an I/O cycle; in this example, the - signal handler would receive an IOCYCLE value of "ioSTC | ioCLF". - - Hardware allows parallel action for concurrent signals. Under simulation, a - "concurrent" set of signals is processed sequentially by the signal handler - in order of ascending numerical value. Although assigned T-periods differ - between programmed I/O and DMA I/O cycles, a single processing order is used. - The order of execution generally follows the order of T-period assertion, - except that ioSIR is processed after all other signals that may affect the - interrupt request chain. - - Implementation notes: - - 1. The ioCLF signal must be processed after ioSFS/ioSFC to ensure that a - true skip test generates ioSKF before the flag is cleared, and after - ioIOI/ioIOO/ioSTC/ioCLC to meet the requirement that executing an - instruction having the H/C bit set is equivalent to executing the same - instruction with the H/C bit clear and then a CLF instruction. - - 2. The ioSKF signal is never sent to an I/O handler. Rather, it is returned - from the handler if the SFC or SFS condition is true. If the condition - is false, ioNONE is returned instead. As these two values are returned - in the 16-bit data portion of the returned value, their assigned values - must be <= 100000 octal. - - 3. An I/O handler will receive ioCRS as a result of a CLC 0 instruction, - ioPOPIO and ioCRS as a result of a RESET command, and ioPON, ioPOPIO, and - ioCRS as a result of a RESET -P command. - - 4. An I/O handler will receive ioNONE when a HLT instruction is executed - that has the H/C bit clear (i.e., no CLF generated). - - 5. In hardware, the SIR signal is generated unconditionally every T5 period - to time the setting of the IRQ flip-flop. Under simulation, ioSIR - indicates that the I/O handler must set the PRL, IRQ, and SRQ signals as - required by the interface logic. ioSIR must be included in the I/O cycle - if any of the flip-flops affecting these signals are changed and the - interface supports interrupts or DMA transfers. - - 6. In hardware, the ENF signal is unconditionally generated every T2 period - to time the setting of the flag flip-flop and to reset the IRQ flip-flop. - If the flag buffer flip-flip is set, then flag will be set by ENF. If - the flag buffer is clear, ENF will not affect flag. Under simulation, - ioENF is sent to set the flag buffer and flag flip-flops. For those - interfaces where this action is identical to that provided by STF, the - ioENF handler may simply fall into the ioSTF handler. - - 7. In hardware, the PON signal is asserted continuously while the CPU is - operating. Under simulation, ioPON is asserted only at simulator - initialization or when processing a RESET -P command. -*/ - -typedef enum { ioNONE = 0000000, /* -- -- -- -- -- no signal asserted */ - ioPON = 0000001, /* T2 T3 T4 T5 T6 power on normal */ - ioENF = 0000002, /* T2 -- -- -- -- enable flag */ - ioIOI = 0000004, /* -- -- T4 T5 -- I/O data input (CPU) - T2 T3 -- -- -- I/O data input (DMA) */ - ioIOO = 0000010, /* -- T3 T4 -- -- I/O data output */ - ioSKF = 0000020, /* -- T3 T4 T5 -- skip on flag */ - ioSFS = 0000040, /* -- T3 T4 T5 -- skip if flag is set */ - ioSFC = 0000100, /* -- T3 T4 T5 -- skip if flag is clear */ - ioSTC = 0000200, /* -- -- T4 -- -- set control flip-flop (CPU) - -- T3 -- -- -- set control flip-flop (DMA) */ - ioCLC = 0000400, /* -- -- T4 -- -- clear control flip-flop (CPU) - -- T3 T4 -- -- clear control flip-flop (DMA) */ - ioSTF = 0001000, /* -- T3 -- -- -- set flag flip-flop */ - ioCLF = 0002000, /* -- -- T4 -- -- clear flag flip-flop (CPU) - -- T3 -- -- -- clear flag flip-flop (DMA) */ - ioEDT = 0004000, /* -- -- T4 -- -- end data transfer */ - ioCRS = 0010000, /* -- -- -- T5 -- control reset */ - ioPOPIO = 0020000, /* -- -- -- T5 -- power-on preset to I/O */ - ioIAK = 0040000, /* -- -- -- -- T6 interrupt acknowledge */ - ioSIR = 0100000 } IOSIGNAL; /* -- -- -- T5 -- set interrupt request */ - - -typedef uint32 IOCYCLE; /* a set of signals forming one I/O cycle */ - -#define IOIRQSET (ioSTC | ioCLC | ioENF | \ - ioSTF | ioCLF | ioIAK | \ - ioCRS | ioPOPIO | ioPON) /* signals that may affect interrupt state */ - - -/* I/O structures */ - -typedef enum { CLEAR, SET } FLIP_FLOP; /* flip-flop type and values */ - -typedef struct dib DIB; /* incomplete definition */ - -typedef uint32 IOHANDLER (DIB *dibptr, /* I/O signal handler prototype */ - IOCYCLE signal_set, - uint32 stat_data); - -struct dib { /* Device information block */ - IOHANDLER *io_handler; /* pointer to device's I/O signal handler */ - uint32 select_code; /* device's select code */ - uint32 card_index; /* device's card index for state variables */ - }; - - -/* I/O signal and status macros. - - The following macros are useful in I/O signal handlers and unit service - routines. The parameter definition symbols employed are: - - I = an IOCYCLE value - E = a t_stat error status value - D = a uint16 data value - C = a uint32 combined status and data value - P = a pointer to a DIB structure - B = a Boolean test value - - Implementation notes: - - 1. The IONEXT macro isolates the next signal in sequence to process from the - I/O cycle I. - - 2. The IOADDSIR macro adds an ioSIR signal to the I/O cycle I if it - contains signals that might change the interrupt state. - - 3. The IORETURN macro forms the combined status and data value to be - returned by a handler from the t_stat error code E and the 16-bit data - value D. - - 4. The IOSTATUS macro isolates the t_stat error code from a combined status - and data value value C. - - 5. The IODATA macro isolates the 16-bit data value from a combined status - and data value value C. - - 6. The IOPOWERON macro calls signal handler P->H with DIB pointer P to - process a power-on reset action. - - 7. The IOPRESET macro calls signal handler P->H with DIB pointer P to - process a front-panel PRESET action. - - 8. The IOERROR macro returns t_stat error code E from a unit service routine - if the Boolean test B is true. -*/ - -#define IONEXT(I) (IOSIGNAL) ((I) & (IOCYCLE) (- (int32) (I))) /* extract next I/O signal to handle */ -#define IOADDSIR(I) ((I) & IOIRQSET ? (I) | ioSIR : (I)) /* add SIR if IRQ state might change */ - -#define IORETURN(E,D) ((uint32) ((E) << 16 | (D) & DMASK)) /* form I/O handler return value */ -#define IOSTATUS(C) ((t_stat) ((C) >> 16) & DMASK) /* extract I/O status from combined value */ -#define IODATA(C) ((uint16) ((C) & DMASK)) /* extract data from combined value */ - -#define IOPOWERON(P) (P)->io_handler ((P), ioPON | ioPOPIO | ioCRS, 0) /* send power-on signals to handler */ -#define IOPRESET(P) (P)->io_handler ((P), ioPOPIO | ioCRS, 0) /* send PRESET signals to handler */ -#define IOERROR(B,E) ((B) ? (E) : SCPE_OK) /* stop on I/O error if enabled */ - - -/* I/O signal logic macros. - - The following macros implement the logic for the SKF, PRL, IRQ, and SRQ - signals. Both standard and general logic macros are provided. The parameter - definition symbols employed are: - - S = a uint32 select code value - B = a Boolean test value - N = a name of a structure containing the standard flip-flops - - Implementation notes: - - 1. The setSKF macro sets the Skip on Flag signal in the return data value if - the Boolean value B is true. - - 2. The setPRL macro sets the Priority Low signal for select code S to the - Boolean value B. - - 3. The setIRQ macro sets the Interrupt Request signal for select code S to - the Boolean value B. - - 4. The setSRQ macro sets the Service Request signal for select code S to the - Boolean value B. - - 5. The PRL macro returns the Priority Low signal for select code S as a - Boolean value. - - 6. The IRQ macro returns the Interrupt Request signal for select code S as a - Boolean value. - - 7. The SRQ macro returns the Service Request signal for select code S as a - Boolean value. - - 8. The setstdSKF macro sets Skip on Flag signal in the return data value if - the flag state in structure N matches the current skip test condition. - - 9. The setstdPRL macro sets the Priority Low signal for the select code - referenced by "dibptr" using the standard logic and the control and flag - states in structure N. - - 10. The setstdIRQ macro sets the Interrupt Request signal for the select code - referenced by "dibptr" using the standard logic and the control, flag, - and flag buffer states in structure N. - - 11. The setstdSRQ macro sets the Service Request signal for the select code - referenced by "dibptr" using the standard logic and the flag state in - structure N. -*/ - -#define BIT_V(S) ((S) & 037) /* convert select code to bit position */ -#define BIT_M(S) (1u << BIT_V (S)) /* convert select code to bit mask */ - -#define setSKF(B) stat_data = IORETURN (SCPE_OK, (uint16) ((B) ? ioSKF : ioNONE)) - -#define setPRL(S,B) dev_prl[(S)/32] = dev_prl[(S)/32] & ~BIT_M (S) | (((B) & 1) << BIT_V (S)) -#define setIRQ(S,B) dev_irq[(S)/32] = dev_irq[(S)/32] & ~BIT_M (S) | (((B) & 1) << BIT_V (S)) -#define setSRQ(S,B) dev_srq[(S)/32] = dev_srq[(S)/32] & ~BIT_M (S) | (((B) & 1) << BIT_V (S)) - -#define PRL(S) ((dev_prl[(S)/32] >> BIT_V (S)) & 1) -#define IRQ(S) ((dev_irq[(S)/32] >> BIT_V (S)) & 1) -#define SRQ(S) ((dev_srq[(S)/32] >> BIT_V (S)) & 1) - -#define setstdSKF(N) setSKF ((signal == ioSFC) && !N.flag || \ - (signal == ioSFS) && N.flag) - -#define setstdPRL(N) setPRL (dibptr->select_code, !(N.control & N.flag)); -#define setstdIRQ(N) setIRQ (dibptr->select_code, N.control & N.flag & N.flagbuf); -#define setstdSRQ(N) setSRQ (dibptr->select_code, N.flag); - - -/* CPU state */ - -extern uint32 SR; /* S register (for IBL) */ -extern uint32 dev_prl [2], dev_irq [2], dev_srq [2]; /* I/O signal vectors */ - -/* Simulator state */ - -extern FILE *sim_deb; -extern FILE *sim_log; -extern int32 sim_step; -extern int32 sim_switches; - -/* CPU functions */ - -extern t_stat ibl_copy (const BOOT_ROM rom, int32 dev); -extern void hp_enbdis_pair (DEVICE *ccp, DEVICE *dcp); - -/* System functions */ - -extern t_stat fprint_sym (FILE *ofile, t_addr addr, t_value *val, UNIT *uptr, int32 sw); -extern const char *fmt_char (uint8 ch); -extern t_stat hp_setsc (UNIT *uptr, int32 val, char *cptr, void *desc); -extern t_stat hp_showsc (FILE *st, UNIT *uptr, int32 val, void *desc); -extern t_stat hp_setdev (UNIT *uptr, int32 val, char *cptr, void *desc); -extern t_stat hp_showdev (FILE *st, UNIT *uptr, int32 val, void *desc); - -/* Device-specific functions */ - -extern int32 sync_poll (POLLMODE poll_mode); - -#endif +/* hp2100_defs.h: HP 2100 simulator definitions + + Copyright (c) 1993-2014, Robert M. Supnik + + 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 + ROBERT M SUPNIK 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 Robert M Supnik shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + + 30-Dec-14 JDB Added S-register parameters to ibl_copy, more IBL constants + 28-Dec-14 JDB Changed suppression from #pragma GCC to #pragma clang + 05-Feb-13 JDB Added declaration for hp_fprint_stopped + 18-Mar-13 JDB Added "-Wdangling-else" to the suppression pragmas + Removed redundant extern declarations + 14-Mar-13 MP Changed guard macro name to avoid reserved namespace + 14-Dec-12 JDB Added "-Wbitwise-op-parentheses" to the suppression pragmas + 12-May-12 JDB Added pragmas to suppress logical operator precedence warnings + 10-Feb-12 JDB Added hp_setsc, hp_showsc functions to support SC modifier + 28-Mar-11 JDB Tidied up signal handling + 29-Oct-10 JDB DMA channels renamed from 0,1 to 1,2 to match documentation + 27-Oct-10 JDB Revised I/O signal enum values for concurrent signals + Revised I/O macros for new signal handling + 09-Oct-10 JDB Added DA and DC device select code assignments + 07-Sep-08 JDB Added POLL_FIRST to indicate immediate connection attempt + 15-Jul-08 JDB Rearranged declarations with hp2100_cpu.h + 26-Jun-08 JDB Rewrote device I/O to model backplane signals + 25-Jun-08 JDB Added PIF device + 17-Jun-08 JDB Declared fmt_char() function + 26-May-08 JDB Added MPX device + 24-Apr-08 JDB Added I_MRG_I, I_JSB, I_JSB_I, and I_JMP instruction masks + 14-Apr-08 JDB Changed TMR_MUX to TMR_POLL for idle support + Added POLLMODE, sync_poll() declaration + Added I_MRG, I_ISZ, I_IOG, I_STF, and I_SFS instruction masks + 07-Dec-07 JDB Added BACI device + 10-Nov-07 JDB Added 16/32-bit unsigned-to-signed conversions + 11-Jan-07 JDB Added 12578A DMA byte packing to DMA structure + 28-Dec-06 JDB Added CRS backplane signal as I/O pseudo-opcode + Added DMASK32 32-bit mask value + 21-Dec-06 JDB Changed MEM_ADDR_OK for 21xx loader support + 12-Sep-06 JDB Define NOTE_IOG to recalc interrupts after instr exec + Rename STOP_INDINT to NOTE_INDINT (not a stop condition) + 30-Dec-04 JDB Added IBL_DS_HEAD head number mask + 19-Nov-04 JDB Added STOP_OFFLINE, STOP_PWROFF stop codes + 25-Apr-04 RMS Added additional IBL definitions + Added DMA EDT I/O pseudo-opcode + 25-Apr-03 RMS Revised for extended file support + 24-Oct-02 RMS Added indirect address interrupt + 08-Feb-02 RMS Added DMS definitions + 01-Feb-02 RMS Added terminal multiplexor support + 16-Jan-02 RMS Added additional device support + 30-Nov-01 RMS Added extended SET/SHOW support + 15-Oct-00 RMS Added dynamic device numbers + 14-Apr-99 RMS Changed t_addr to unsigned + + The author gratefully acknowledges the help of Jeff Moffat in answering + questions about the HP2100; and of Dave Bryan in adding features and + correcting errors throughout the simulator. +*/ + + +#ifndef HP2100_DEFS_H_ +#define HP2100_DEFS_H_ 0 + +#include "sim_defs.h" /* simulator defns */ + + +/* The following pragmas quell clang warnings that are on by default but should + not be, in my opinion. They warn about the use of perfectly valid code and + require the addition of redundant parentheses and braces to silence them. + Rather than clutter up the code with scores of extra symbols that, in my + view, make the code harder to read and maintain, I elect to suppress these + warnings. +*/ + +#if defined (__clang__) +#pragma clang diagnostic ignored "-Wlogical-op-parentheses" +#pragma clang diagnostic ignored "-Wbitwise-op-parentheses" +#pragma clang diagnostic ignored "-Wdangling-else" +#endif + + +/* Simulator stop and notification codes */ + +#define STOP_RSRV 1 /* must be 1 */ +#define STOP_IODV 2 /* must be 2 */ +#define STOP_HALT 3 /* HALT */ +#define STOP_IBKPT 4 /* breakpoint */ +#define STOP_IND 5 /* indirect loop */ +#define NOTE_INDINT 6 /* indirect intr */ +#define STOP_NOCONN 7 /* no connection */ +#define STOP_OFFLINE 8 /* device offline */ +#define STOP_PWROFF 9 /* device powered off */ +#define NOTE_IOG 10 /* I/O instr executed */ + +/* Memory */ + +#define MEMSIZE (cpu_unit.capac) /* actual memory size */ +#define VA_N_SIZE 15 /* virtual addr size */ +#define VASIZE (1 << VA_N_SIZE) +#define VAMASK 077777 /* virt addr mask */ +#define PA_N_SIZE 20 /* phys addr size */ +#define PASIZE (1 << PA_N_SIZE) +#define PAMASK (PASIZE - 1) /* phys addr mask */ + +/* Architectural constants */ + +#define SIGN32 020000000000 /* 32b sign */ +#define DMASK32 037777777777 /* 32b data mask/maximum value */ +#define DMAX32 017777777777 /* 32b maximum signed value */ +#define SIGN 0100000 /* 16b sign */ +#define DMASK 0177777 /* 16b data mask/maximum value */ +#define DMAX 0077777 /* 16b maximum signed value */ +#define DMASK8 0377 /* 8b data mask/maximum value */ + +/* Portable conversions (sign-extension, unsigned-to-signed) */ + +#define SEXT(x) ((int32) (((x) & SIGN)? ((x) | ~DMASK): ((x) & DMASK))) + +#define INT16(u) ((u) > DMAX ? (-(int16) (DMASK - (u)) - 1) : (int16) (u)) +#define INT32(u) ((u) > DMAX32 ? (-(int32) (DMASK32 - (u)) - 1) : (int32) (u)) + +/* Timers */ + +#define TMR_CLK 0 /* clock */ +#define TMR_POLL 1 /* input polling */ + +#define POLL_RATE 100 /* poll 100 times per second */ +#define POLL_FIRST 1 /* first poll is "immediate" */ +#define POLL_WAIT 15800 /* initial poll ~ 10 msec. */ + +typedef enum { INITIAL, SERVICE } POLLMODE; /* poll synchronization modes */ + +/* I/O instruction sub-opcodes */ + +#define soHLT 0 /* halt */ +#define soFLG 1 /* set/clear flag */ +#define soSFC 2 /* skip on flag clear */ +#define soSFS 3 /* skip on flag set */ +#define soMIX 4 /* merge into A/B */ +#define soLIX 5 /* load into A/B */ +#define soOTX 6 /* output from A/B */ +#define soCTL 7 /* set/clear control */ + +/* I/O devices - fixed select code assignments */ + +#define CPU 000 /* interrupt control */ +#define OVF 001 /* overflow */ +#define DMALT1 002 /* DMA 1 alternate */ +#define DMALT2 003 /* DMA 2 alternate */ +#define PWR 004 /* power fail */ +#define PRO 005 /* parity/mem protect */ +#define DMA1 006 /* DMA channel 1 */ +#define DMA2 007 /* DMA channel 2 */ + +/* I/O devices - variable select code assignment defaults */ + +#define PTR 010 /* 12597A-002 paper tape reader */ +#define TTY 011 /* 12531C teleprinter */ +#define PTP 012 /* 12597A-005 paper tape punch */ +#define CLK 013 /* 12539C time-base generator */ +#define LPS 014 /* 12653A line printer */ +#define LPT 015 /* 12845A line printer */ +#define MTD 020 /* 12559A data */ +#define MTC 021 /* 12559A control */ +#define DPD 022 /* 12557A data */ +#define DPC 023 /* 12557A control */ +#define DQD 024 /* 12565A data */ +#define DQC 025 /* 12565A control */ +#define DRD 026 /* 12610A data */ +#define DRC 027 /* 12610A control */ +#define MSD 030 /* 13181A data */ +#define MSC 031 /* 13181A control */ +#define IPLI 032 /* 12566B link in */ +#define IPLO 033 /* 12566B link out */ +#define DS 034 /* 13037A control */ +#define BACI 035 /* 12966A Buffered Async Comm Interface */ +#define MPX 036 /* 12792A/B/C 8-channel multiplexer */ +#define PIF 037 /* 12620A/12936A Privileged Interrupt Fence */ +#define MUXL 040 /* 12920A lower data */ +#define MUXU 041 /* 12920A upper data */ +#define MUXC 042 /* 12920A control */ +#define DI_DA 043 /* 12821A Disc Interface with Amigo disc devices */ +#define DI_DC 044 /* 12821A Disc Interface with CS/80 disc and tape devices */ + +#define OPTDEV 002 /* start of optional devices */ +#define CRSDEV 006 /* start of devices that receive CRS */ +#define VARDEV 010 /* start of variable assignments */ +#define MAXDEV 077 /* end of select code range */ + +/* IBL assignments */ + +#define IBL_V_SEL 14 /* ROM select <15:14> */ +#define IBL_M_SEL 03 +#define IBL_PTR 0000000 /* ROM 0: 12992K paper tape reader (PTR) */ +#define IBL_DP 0040000 /* ROM 1: 12992A 7900 disc (DP) */ +#define IBL_DQ 0060000 /* ROM 1: 12992A 2883 disc (DQ) */ +#define IBL_MS 0100000 /* ROM 2: 12992D 7970 tape (MS) */ +#define IBL_DS 0140000 /* ROM 3: 12992B 7905/06/20/25 disc (DS) */ +#define IBL_MAN 0010000 /* RPL/manual boot <13:12> */ +#define IBL_V_DEV 6 /* select code <11:6> */ +#define IBL_OPT 0000070 /* options in <5:3> */ +#define IBL_DP_REM 0000001 /* DP removable <0:0> */ +#define IBL_DS_HEAD 0000003 /* DS head number <1:0> */ +#define IBL_LNT 64 /* boot ROM length in words */ +#define IBL_MASK (IBL_LNT - 1) /* boot length mask */ +#define IBL_DPC (IBL_LNT - 2) /* DMA ctrl word */ +#define IBL_END (IBL_LNT - 1) /* last location */ + +#define IBL_S_CLR 0000000 /* ibl_copy mask to clear the S register */ +#define IBL_S_NOCLR 0177777 /* ibl_copy mask to preserve the S register */ +#define IBL_S_NOSET 0000000 /* ibl_copy mask to preserve the S register */ + +#define IBL_SET_SC(s) ((s) << IBL_V_DEV) /* position the select code in the S register */ + +typedef uint16 BOOT_ROM [IBL_LNT]; /* boot ROM data */ + + +/* I/O backplane signals. + + The IOSIGNAL declarations mirror the hardware I/O backplane signals. A set + of one or more signals forms an IOCYCLE that is sent to a device IOHANDLER + for action. The CPU and DMA dispatch one signal set to the target device + handler per I/O cycle. A CPU cycle consists of either one or two signals; if + present, the second signal will be CLF. A DMA cycle consists of from two to + five signals. In addition, a front-panel PRESET or power-on reset dispatches + two or three signals, respectively. + + In hardware, signals are assigned to one or more specific I/O T-periods, and + some signals are asserted concurrently. For example, a programmed STC sc,C + instruction asserts the STC and CLF signals together in period T4. Under + simulation, signals are ORed to form an I/O cycle; in this example, the + signal handler would receive an IOCYCLE value of "ioSTC | ioCLF". + + Hardware allows parallel action for concurrent signals. Under simulation, a + "concurrent" set of signals is processed sequentially by the signal handler + in order of ascending numerical value. Although assigned T-periods differ + between programmed I/O and DMA I/O cycles, a single processing order is used. + The order of execution generally follows the order of T-period assertion, + except that ioSIR is processed after all other signals that may affect the + interrupt request chain. + + Implementation notes: + + 1. The ioCLF signal must be processed after ioSFS/ioSFC to ensure that a + true skip test generates ioSKF before the flag is cleared, and after + ioIOI/ioIOO/ioSTC/ioCLC to meet the requirement that executing an + instruction having the H/C bit set is equivalent to executing the same + instruction with the H/C bit clear and then a CLF instruction. + + 2. The ioSKF signal is never sent to an I/O handler. Rather, it is returned + from the handler if the SFC or SFS condition is true. If the condition + is false, ioNONE is returned instead. As these two values are returned + in the 16-bit data portion of the returned value, their assigned values + must be <= 100000 octal. + + 3. An I/O handler will receive ioCRS as a result of a CLC 0 instruction, + ioPOPIO and ioCRS as a result of a RESET command, and ioPON, ioPOPIO, and + ioCRS as a result of a RESET -P command. + + 4. An I/O handler will receive ioNONE when a HLT instruction is executed + that has the H/C bit clear (i.e., no CLF generated). + + 5. In hardware, the SIR signal is generated unconditionally every T5 period + to time the setting of the IRQ flip-flop. Under simulation, ioSIR + indicates that the I/O handler must set the PRL, IRQ, and SRQ signals as + required by the interface logic. ioSIR must be included in the I/O cycle + if any of the flip-flops affecting these signals are changed and the + interface supports interrupts or DMA transfers. + + 6. In hardware, the ENF signal is unconditionally generated every T2 period + to time the setting of the flag flip-flop and to reset the IRQ flip-flop. + If the flag buffer flip-flip is set, then flag will be set by ENF. If + the flag buffer is clear, ENF will not affect flag. Under simulation, + ioENF is sent to set the flag buffer and flag flip-flops. For those + interfaces where this action is identical to that provided by STF, the + ioENF handler may simply fall into the ioSTF handler. + + 7. In hardware, the PON signal is asserted continuously while the CPU is + operating. Under simulation, ioPON is asserted only at simulator + initialization or when processing a RESET -P command. +*/ + +typedef enum { ioNONE = 0000000, /* -- -- -- -- -- no signal asserted */ + ioPON = 0000001, /* T2 T3 T4 T5 T6 power on normal */ + ioENF = 0000002, /* T2 -- -- -- -- enable flag */ + ioIOI = 0000004, /* -- -- T4 T5 -- I/O data input (CPU) + T2 T3 -- -- -- I/O data input (DMA) */ + ioIOO = 0000010, /* -- T3 T4 -- -- I/O data output */ + ioSKF = 0000020, /* -- T3 T4 T5 -- skip on flag */ + ioSFS = 0000040, /* -- T3 T4 T5 -- skip if flag is set */ + ioSFC = 0000100, /* -- T3 T4 T5 -- skip if flag is clear */ + ioSTC = 0000200, /* -- -- T4 -- -- set control flip-flop (CPU) + -- T3 -- -- -- set control flip-flop (DMA) */ + ioCLC = 0000400, /* -- -- T4 -- -- clear control flip-flop (CPU) + -- T3 T4 -- -- clear control flip-flop (DMA) */ + ioSTF = 0001000, /* -- T3 -- -- -- set flag flip-flop */ + ioCLF = 0002000, /* -- -- T4 -- -- clear flag flip-flop (CPU) + -- T3 -- -- -- clear flag flip-flop (DMA) */ + ioEDT = 0004000, /* -- -- T4 -- -- end data transfer */ + ioCRS = 0010000, /* -- -- -- T5 -- control reset */ + ioPOPIO = 0020000, /* -- -- -- T5 -- power-on preset to I/O */ + ioIAK = 0040000, /* -- -- -- -- T6 interrupt acknowledge */ + ioSIR = 0100000 } IOSIGNAL; /* -- -- -- T5 -- set interrupt request */ + + +typedef uint32 IOCYCLE; /* a set of signals forming one I/O cycle */ + +#define IOIRQSET (ioSTC | ioCLC | ioENF | \ + ioSTF | ioCLF | ioIAK | \ + ioCRS | ioPOPIO | ioPON) /* signals that may affect interrupt state */ + + +/* I/O structures */ + +typedef enum { CLEAR, SET } FLIP_FLOP; /* flip-flop type and values */ + +typedef struct dib DIB; /* incomplete definition */ + +typedef uint32 IOHANDLER (DIB *dibptr, /* I/O signal handler prototype */ + IOCYCLE signal_set, + uint32 stat_data); + +struct dib { /* Device information block */ + IOHANDLER *io_handler; /* pointer to device's I/O signal handler */ + uint32 select_code; /* device's select code */ + uint32 card_index; /* device's card index for state variables */ + }; + + +/* I/O signal and status macros. + + The following macros are useful in I/O signal handlers and unit service + routines. The parameter definition symbols employed are: + + I = an IOCYCLE value + E = a t_stat error status value + D = a uint16 data value + C = a uint32 combined status and data value + P = a pointer to a DIB structure + B = a Boolean test value + + Implementation notes: + + 1. The IONEXT macro isolates the next signal in sequence to process from the + I/O cycle I. + + 2. The IOADDSIR macro adds an ioSIR signal to the I/O cycle I if it + contains signals that might change the interrupt state. + + 3. The IORETURN macro forms the combined status and data value to be + returned by a handler from the t_stat error code E and the 16-bit data + value D. + + 4. The IOSTATUS macro isolates the t_stat error code from a combined status + and data value value C. + + 5. The IODATA macro isolates the 16-bit data value from a combined status + and data value value C. + + 6. The IOPOWERON macro calls signal handler P->H with DIB pointer P to + process a power-on reset action. + + 7. The IOPRESET macro calls signal handler P->H with DIB pointer P to + process a front-panel PRESET action. + + 8. The IOERROR macro returns t_stat error code E from a unit service routine + if the Boolean test B is true. +*/ + +#define IONEXT(I) (IOSIGNAL) ((I) & (IOCYCLE) (- (int32) (I))) /* extract next I/O signal to handle */ +#define IOADDSIR(I) ((I) & IOIRQSET ? (I) | ioSIR : (I)) /* add SIR if IRQ state might change */ + +#define IORETURN(E,D) ((uint32) ((E) << 16 | (D) & DMASK)) /* form I/O handler return value */ +#define IOSTATUS(C) ((t_stat) ((C) >> 16) & DMASK) /* extract I/O status from combined value */ +#define IODATA(C) ((uint16) ((C) & DMASK)) /* extract data from combined value */ + +#define IOPOWERON(P) (P)->io_handler ((P), ioPON | ioPOPIO | ioCRS, 0) /* send power-on signals to handler */ +#define IOPRESET(P) (P)->io_handler ((P), ioPOPIO | ioCRS, 0) /* send PRESET signals to handler */ +#define IOERROR(B,E) ((B) ? (E) : SCPE_OK) /* stop on I/O error if enabled */ + + +/* I/O signal logic macros. + + The following macros implement the logic for the SKF, PRL, IRQ, and SRQ + signals. Both standard and general logic macros are provided. The parameter + definition symbols employed are: + + S = a uint32 select code value + B = a Boolean test value + N = a name of a structure containing the standard flip-flops + + Implementation notes: + + 1. The setSKF macro sets the Skip on Flag signal in the return data value if + the Boolean value B is true. + + 2. The setPRL macro sets the Priority Low signal for select code S to the + Boolean value B. + + 3. The setIRQ macro sets the Interrupt Request signal for select code S to + the Boolean value B. + + 4. The setSRQ macro sets the Service Request signal for select code S to the + Boolean value B. + + 5. The PRL macro returns the Priority Low signal for select code S as a + Boolean value. + + 6. The IRQ macro returns the Interrupt Request signal for select code S as a + Boolean value. + + 7. The SRQ macro returns the Service Request signal for select code S as a + Boolean value. + + 8. The setstdSKF macro sets Skip on Flag signal in the return data value if + the flag state in structure N matches the current skip test condition. + + 9. The setstdPRL macro sets the Priority Low signal for the select code + referenced by "dibptr" using the standard logic and the control and flag + states in structure N. + + 10. The setstdIRQ macro sets the Interrupt Request signal for the select code + referenced by "dibptr" using the standard logic and the control, flag, + and flag buffer states in structure N. + + 11. The setstdSRQ macro sets the Service Request signal for the select code + referenced by "dibptr" using the standard logic and the flag state in + structure N. +*/ + +#define BIT_V(S) ((S) & 037) /* convert select code to bit position */ +#define BIT_M(S) (1u << BIT_V (S)) /* convert select code to bit mask */ + +#define setSKF(B) stat_data = IORETURN (SCPE_OK, (uint16) ((B) ? ioSKF : ioNONE)) + +#define setPRL(S,B) dev_prl[(S)/32] = dev_prl[(S)/32] & ~BIT_M (S) | (((B) & 1) << BIT_V (S)) +#define setIRQ(S,B) dev_irq[(S)/32] = dev_irq[(S)/32] & ~BIT_M (S) | (((B) & 1) << BIT_V (S)) +#define setSRQ(S,B) dev_srq[(S)/32] = dev_srq[(S)/32] & ~BIT_M (S) | (((B) & 1) << BIT_V (S)) + +#define PRL(S) ((dev_prl[(S)/32] >> BIT_V (S)) & 1) +#define IRQ(S) ((dev_irq[(S)/32] >> BIT_V (S)) & 1) +#define SRQ(S) ((dev_srq[(S)/32] >> BIT_V (S)) & 1) + +#define setstdSKF(N) setSKF ((signal == ioSFC) && !N.flag || \ + (signal == ioSFS) && N.flag) + +#define setstdPRL(N) setPRL (dibptr->select_code, !(N.control & N.flag)); +#define setstdIRQ(N) setIRQ (dibptr->select_code, N.control & N.flag & N.flagbuf); +#define setstdSRQ(N) setSRQ (dibptr->select_code, N.flag); + + +/* CPU state */ + +extern uint32 dev_prl [2], dev_irq [2], dev_srq [2]; /* I/O signal vectors */ + +/* CPU functions */ + +extern t_stat ibl_copy (const BOOT_ROM rom, int32 dev, uint32 sr_clear, uint32 sr_set); +extern void hp_enbdis_pair (DEVICE *ccp, DEVICE *dcp); + +/* System functions */ + +extern const char *fmt_char (uint8 ch); +extern t_stat hp_setsc (UNIT *uptr, int32 val, char *cptr, void *desc); +extern t_stat hp_showsc (FILE *st, UNIT *uptr, int32 val, void *desc); +extern t_stat hp_setdev (UNIT *uptr, int32 val, char *cptr, void *desc); +extern t_stat hp_showdev (FILE *st, UNIT *uptr, int32 val, void *desc); +extern t_bool hp_fprint_stopped (FILE *st, t_stat reason); + +/* Device-specific functions */ + +extern int32 sync_poll (POLLMODE poll_mode); + +#endif diff --git a/HP2100/hp2100_di.c b/HP2100/hp2100_di.c index 98cc4ef0..14c401aa 100644 --- a/HP2100/hp2100_di.c +++ b/HP2100/hp2100_di.c @@ -1,1927 +1,1911 @@ -/* hp2100_di.c: HP 12821A HP-IB Disc Interface simulator - - Copyright (c) 2010-2012, J. David Bryan - - 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 - THE AUTHOR 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 the author shall not be - used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from the author. - - DI 12821A Disc Interface - - 13-Feb-12 JDB First release - 15-Dec-11 JDB Added dummy DC device for diagnostics - 09-Oct-10 JDB Created DI simulation - - References: - - HP 12821A Disc Interface Installation and Service Manual (12821-90006, - Feb-1985) - - IEEE Standard Digital Interface for Programmable Instrumentation - (IEEE-488A-1980, Sep-1979) - - - The 12821A was a high-speed implementation of the Hewlett-Packard Interface - Bus (HP-IB, formalized as IEEE Std. 488-1978). It was used to interface - HP-IB disc and tape devices, such as the HP 7906H, 7908A, and 7974A, to the - HP 1000 running RTE-IVB or RTE-6/VM. Three device command protocols were - supported by the I/O drivers: Amigo discs by driver DVA32, CS/80 discs by - DVM33, and Amigo tapes by DVS23. - - In an RTE environment, the 12821A was the system controller. While - electrically compatible with the HP-IB specification and capable of receiving - addressing commands from the bus, the 12821A did not use the full IEEE-488 - protocol. Card talker and listener states were set by bits in the control - register, rather than by receiving talk and listen commands over the bus. - The bus address of the card could be set via DIP switches, but this feature - was only used by the diagnostic. - - The card supported packed and unpacked transfers across the bus. Up to four - devices could be connected to each card; this limit was imposed by the - maximum electrical loading on the bus compatible with the high data rate. - - The 12821A had a 16-word FIFO buffer and could sustain DCPC transfers of one - megabyte per second. Burst transfers by the CPU to fill or empty the FIFO - could run at the full bandwidth of the I/O backplane. This could hold off - lower-priority devices for 10-15 microseconds until the card slowed down to - the rate of the disc or tape. - - Card assembly 12821-60003 was revised to add a DCPC pacing option. Placing - jumper W1 in position A inhibited SRQ for one I/O cycle in six to allow a - lower-priority interface card to transfer one word. Position B allowed SRQ - to assert continuously as it did on the earlier card assembly 12821-60001. - - The simulator is logically partitioned into three sets of functions: the - interface card simulation, the HP-IB bus simulation, and the device - simulation. This is the card simulation and the card portion of the HP-IB - simulation. Separate modules for the tape and disc devices contain the - device simulations and the device portions of the HP-IB simulations. - - This simulator is written to allow the definition of multiple DI cards in a - system. The RTE operating system provided separate I/O drivers for the Amigo - disc, Amigo tape, and CS/80 disc devices. As only one I/O driver could - control a given interface, separate interfaces were required if more than one - device class was installed. For example, it was not possible to control an - Amigo disc and an Amigo tape connected to the same interface card. - - - Implementation notes: - - 1. The simulator behaves as though card switches S1-S7 are initially closed, - providing a card bus address of 0. The address may be changed with the - SET ADDRESS=n command. Only addresses 0-7 are supported, and the - address may duplicate a device bus address without conflict, as the - address is only used during the diagnostic when devices are disconnected. - - 2. The simulator behaves as though card switch S8 is open, enabling the card - to be the system controller. This cannot be changed by the user. - - 3. The simulator behaves as though card jumper W1 (DCPC pacing) is in - position B. This currently cannot be changed by the user. -*/ - - - -#include "hp2100_defs.h" -#include "hp2100_di.h" - - - -/* Program constants */ - -#define SW8_SYSCTL 1 /* card is always the system controller (switch 8) */ - -#define IFC_TIMEOUT 157 /* 157 instructions = ~ 100 microseconds */ - -#define CONTROLLER 31 /* dummy unit number for DI */ - - -/* Character constants */ - -#define LF '\012' - - -/* Control Word Register */ - -#define CNTL_SRQ 0100000 /* enable service request interrupt */ -#define CNTL_IFC 0040000 /* assert IFC or enable IFC interrupt */ -#define CNTL_REN 0020000 /* assert remote enable */ -#define CNTL_IRL 0010000 /* enable input-register-loaded interrupt */ -#define CNTL_LBO 0004000 /* enable last-byte-out interrupt */ -#define CNTL_LF 0002000 /* enable line feed terminator */ -#define CNTL_EOI 0001000 /* assert end or identify */ -#define CNTL_ATN 0000400 /* assert attention */ -#define CNTL_DIAG 0000200 /* diagnostic loopback */ -#define CNTL_NRFD 0000100 /* assert not ready for data */ -#define CNTL_PPE 0000040 /* parallel poll enable */ -#define CNTL_ODD 0000020 /* odd number of bytes */ -#define CNTL_PACK 0000010 /* packed data transfer */ -#define CNTL_LSTN 0000004 /* listen */ -#define CNTL_TALK 0000002 /* talk */ -#define CNTL_CIC 0000001 /* controller in charge */ - - -/* Status Word Register */ - -#define STAT_SRQBUS 0100000 /* service request bus state */ -#define STAT_IFCBUS 0040000 /* interface clear bus state */ -#define STAT_RENBUS 0020000 /* remote enable bus state */ -#define STAT_IRL 0010000 /* input register loaded */ -#define STAT_LBO 0004000 /* last byte out */ -#define STAT_LBI 0002000 /* last byte in */ -#define STAT_EOIBUS 0001000 /* end or identify bus state */ -#define STAT_ATNBUS 0000400 /* attention bus state */ -#define STAT_IFC 0000200 /* interface clear seen */ -#define STAT_ODD 0000020 /* odd number of bytes */ -#define STAT_SYSCTL 0000010 /* system controller */ -#define STAT_LSTN 0000004 /* listener */ -#define STAT_TALK 0000002 /* talker */ -#define STAT_CIC 0000001 /* controller in charge */ - - -/* Data word */ - -#define DATA_LBO 0100000 /* last byte out */ -#define DATA_EOI 0001000 /* end or identify */ -#define DATA_ATN 0000400 /* attention */ - - -/* Tag word */ - -#define BUS_SHIFT 16 /* left shift count to align BUS_ATN, EOI with tag */ -#define DATA_SHIFT 8 /* left shift count to align DATA_ATN, EOI with tag */ - -#define TAG_ATN 0000200000 /* bit 16: attention */ -#define TAG_EOI 0000400000 /* bit 17: end or identify */ -#define TAG_EDT 0001000000 /* bit 18: end of data transfer */ -#define TAG_LBR 0002000000 /* bit 19: last byte received */ - -#define TAG_MASK (TAG_ATN | TAG_EOI | TAG_EDT | TAG_LBR) - - -/* FIFO access modes */ - -#define FIFO_EMPTY (di_card->fifo_count == 0) /* FIFO empty test */ -#define FIFO_FULL (di_card->fifo_count == FIFO_SIZE) /* FIFO full test */ - -typedef enum { - bus_access, /* per-byte access */ - cpu_access, /* per-word access */ - diag_access /* mixed access */ - } FIFO_ACCESS; - - -/* Disc interface state variables */ - -DI_STATE di [card_count]; /* per-card state */ - - -/* Disc interface global VM routines */ - -IOHANDLER di_io; -t_stat di_reset (DEVICE *dptr); - -/* Disc interface global SCP routines */ - -t_stat di_set_address (UNIT *uptr, int32 value, char *cptr, void *desc); -t_stat di_show_address (FILE *st, UNIT *uptr, int32 value, void *desc); -t_stat di_set_cable (UNIT *uptr, int32 value, char *cptr, void *desc); -t_stat di_show_cable (FILE *st, UNIT *uptr, int32 value, void *desc); - -/* Disc interface global bus routines */ - -t_bool di_bus_source (CARD_ID card, uint8 data); -void di_bus_control (CARD_ID card, uint32 unit, uint8 assert, uint8 deny); -void di_poll_response (CARD_ID card, uint32 unit, FLIP_FLOP response); - -/* Disc interface local bus routines */ - -static t_bool di_bus_accept (CARD_ID card, uint8 data); -static void di_bus_respond (CARD_ID card, uint8 cntl); -static void di_bus_poll (CARD_ID card); - -/* Disc interface local utility routines */ - -static void master_reset (CARD_ID card); -static void update_state (CARD_ID card); -static void fifo_load (CARD_ID card, uint16 data, FIFO_ACCESS access); -static uint16 fifo_unload (CARD_ID card, FIFO_ACCESS access); -static void fprint_bus (FILE *file, char *format, uint8 cntl); - - - -/* Dummy DC device. - - This temporary dummy device allows the DI diagnostic to test inter-card - signals. Test 15 can only be performed if there are two DIs available. - - This device provides a second "bare" card. Normally, it is disabled and - cannot be enabled by the user. Enabling or disabling DIAG mode on the DA - device automatically enables or disables the DC device. The select code of - the DC device is fixed at 45B and cannot be changed. -*/ - -DIB dc_dib = { &di_io, DI_DC, dc }; - -REG dc_reg [] = { - { BRDATA (FIFO, di [dc].fifo, 8, 20, FIFO_SIZE), REG_CIRC }, /* needed for "qptr" */ - { NULL } - }; - -DEVICE dc_dev = { - "DC", /* device name */ - NULL, /* unit array */ - dc_reg, /* register array */ - NULL, /* modifier array */ - 0, /* number of units */ - 10, /* address radix */ - 31, /* address width */ - 1, /* address increment */ - 8, /* data radix */ - 8, /* data width */ - NULL, /* examine routine */ - NULL, /* deposit routine */ - &di_reset, /* reset routine */ - NULL, /* boot routine */ - NULL, /* attach routine */ - NULL, /* detach routine */ - &dc_dib, /* device information block */ - DEV_DEBUG | DEV_DIS, /* device flags */ - 0, /* debug control flags */ - di_deb, /* debug flag name table */ - NULL, /* memory size change routine */ - NULL }; /* logical device name */ - - - -/* DI data structures. - - *dptrs device pointers - *bus_accept device acceptor function pointers - *bus_respond device responder function pointers - - di_deb DI debug table - - The first three pointer arrays have elements that correspond one-for-one with - the supported devices. These allow the DI simulator to work with multiple - cards. The actual devices are defined in the individual device simulators. - - Note that the DC and MA devices are reserved for future use. Until one or - the other is fully implemented, a dummy DC device is provided above for use - by the diagnostic only. -*/ - -extern DEVICE da_dev; - -static DEVICE *dptrs [card_count] = { &da_dev, &dc_dev, NULL }; -static ACCEPTOR *bus_accept [card_count] = { &da_bus_accept, NULL, NULL }; -static RESPONDER *bus_respond [card_count] = { &da_bus_respond, NULL, NULL }; - - -DEBTAB di_deb [] = { - { "CPU", DEB_CPU }, - { "CMDS", DEB_CMDS }, - { "BUF", DEB_BUF }, - { "XFER", DEB_XFER }, - { "RWSC", DEB_RWSC }, - { "SERV", DEB_SERV }, - { NULL, 0 } - }; - - - -/* Disc interface global VM routines */ - - -/* I/O signal handler. - - The card has two input and two output registers. The Input Data Register and - Output Data Register are addressed when the control flip-flop is set. The - Status Word and the Control Word Register are addressed when the control - flip-flop is clear. The card has the usual control, flag buffer, flag, and - SRQ flip-flops, though flag and SRQ are decoupled to allow the full DCPC - transfer rate. - - In hardware, the presence of the card FIFO, which is necessary to obtain full - DCPC bandwidth, implies a delay between CPU actions, such as outputting the - last word in a data transfer, and device actions, such as accepting the last - word of a disc write. Four flip-flops are used to monitor FIFO status: - - - EDT (End of Data Transfer) - - LBO (Last Byte Out) - - LBI (Last Byte In) - - EOR (End of Record) - - The EDT signal indicates that the final data word of a transfer is being - written to the FIFO. The flip-flop is set by the EDT backplane signal when - the last cycle of a DCPC transfer is executing, or during programmed output - transfers when CLF does not accompany IOO in packed mode, or when bit 15 of - the data word is set in unpacked mode. It remains set until it is cleared by - a master reset. The output of the EDT flip-flop drives the EDT tag input of - the FIFO. - - The LBO signal indicates that the final data byte of a transfer has been - sourced to the bus. The flip-flop is set when the last byte of the entry - tagged with EDT has been unloaded from the FIFO. It is cleared by a master - reset or when an entry not tagged with EDT is unloaded. The output of the - LBO flip-flop drives the LBO bit in the Status Word. - - The LBI signal indicates that the final byte of an input transfer has been - accepted from the bus. The flip-flop is set when a byte tagged with EOI is - received and the EOI bit in the control register is set, or a line-feed byte - is received and the LF bit in the control register is set. It is cleared by - a master reset or when neither of these conditions is true. The input of the - LBI flip-flop also drives the LBR (last byte received) tag input of the FIFO, - and the output of the flip-flop drives the LBI bit in the Status Word. - - The EOR signal indicates that the final data word of a transfer is available - in the Input Data Register. The flip-flop is set when the last byte of the - entry tagged with LBR has been unloaded from the FIFO and written to the IDR. - It is cleared by a master reset or when an entry not tagged with LBR is - unloaded and written to the IDR. The output of the EOR flip-flop sets the - flag flip-flop when the IDR is unloaded. - - - Implementation notes: - - 1. In hardware, the Status Word consists of individual flip-flops and status - signals that are enabled onto the I/O backplane. In simulation, the - individual status values are collected into a Status Word Register, and - the Output Data Register does not exist (output data is written directly - to the FIFO buffer). - - 2. The DIAG, T, and L control bits enable a data loopback path on the card. - An IOO issued to the card unloads a word from the FIFO and then loads the - lower byte back into both bytes of the FIFO. The data word output with - the IOO instruction is not used. - - In hardware, IOO triggers the FIFO unload and reload; T and L are - required only for the loopback path. If L is not asserted, then the FIFO - is loaded with 177777 due to the floating bus. If L is asserted and T is - not, then the FIFO is loaded with 000000 due to pullups on the DIO lines. - In simulation, we look only for DIAG and assume that T/L are set - properly, i.e., unloaded data is reloaded. - - 3. In hardware, the SRQ and NRFD lines are open-collector and may be driven - simultaneously from several bus devices. Simulating this fully would - require keeping the state of the lines for each device and deriving the - common bus signals from the logical OR of the state values. Fortunately, - some simplifications are possible. - - The DI asserts SRQ only if control word bit 15 is 1 and bit 0 is 0. - Other bit combinations deny SRQ; as neither the Amigo nor CS/80 protocols - use SRQ and serial polls, there will be no other driver. - - In hardware, every listener drives NRFD, but in practice there is only - one listener at a time. When the card is the listener, it asserts NRFD - if the FIFO becomes full. In simulation, we assert NRFD on the bus if - NRFD is set in the control register, or we are listening and the FIFO is - full. We deny NRFD if NRFD had been set in the control register but is - no longer, or if we had been a listener but are no longer. That is, we - assume that if we have forced NRFD or set it as a listener, then no one - else will be asserting NRFD, so it's safe for us to deny NRFD when the - override is removed or we are no longer a listener. - - We also deny NRFD when a CRS is issued if NRFD had been explicitly - requested or the card had been listening. The rationale is the same: - only a listener can assert NRFD, so if we were listening, it's safe to - deny it, because only we could have set it. - - 4. In hardware, the IRL, LBO, LBI, and IFC status bits are driven by - corresponding flip-flops. In simulation, the status bits themselves hold - the equivalent states and are set and cleared as indicated. - - 5. The card state must be updated during status read (IOI) processing - because the 7974 boot ROM watches the IFC line to determine when IFC - assertion ends. - - 6. DCPC performance is optimized by recognizing that the normal cases (an - input that empties the FIFO or an output that fills the FIFO) do not - alter the card state, and so the usual update_state call may be omitted. - - 7. The gcc compiler (at least as of version 4.6.2) does not optimize - repeated use of array-of-structures accesses. Instead, it recalculates - the index each time, even though the index is a constant within the - function. To avoid this performance penalty, we use a pointer to the - selected DI_STATE structure. Note that VC++ 2008 does perform this - optimization. -*/ - - -uint32 di_io (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) -{ -static const char * const output_state [] = { "Control", "Data" }; -static const char * const input_state [] = { "Status", "Data" }; - -const char * const hold_or_clear = (signal_set & ioCLF ? ",C" : ""); -const CARD_ID card = (CARD_ID) (dibptr->card_index); -DI_STATE * const di_card = &di [card]; - -uint8 assert, deny; /* new bus control states */ -uint16 data; -t_bool update_required = TRUE; /* TRUE if CLF must update the card state */ - -IOSIGNAL signal; -IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ - -while (working_set) { - signal = IONEXT (working_set); /* isolate the next signal */ - - switch (signal) { /* dispatch an I/O signal */ - - case ioCLF: /* clear flag flip-flop */ - di_card->flag = CLEAR; /* clear the flag */ - di_card->flagbuf = CLEAR; /* and flag buffer */ - - if (DEBUG_PRJ (dptrs [card], DEB_CMDS)) - fprintf (sim_deb, ">>%s cmds: [CLF] Flag cleared\n", - dptrs [card]->name); - - if (update_required) /* if the card state has changed */ - update_state (card); /* then update the state */ - break; - - - case ioSTF: /* set flag flip-flop */ - if (DEBUG_PRJ (dptrs [card], DEB_CMDS)) - fprintf (sim_deb, ">>%s cmds: [STF] Flag set\n", - dptrs [card]->name); - - /* fall into ENF handler */ - - case ioENF: /* enable flag */ - di_card->flag = SET; /* set the flag */ - di_card->flagbuf = SET; /* and flag buffer */ - break; - - - case ioSFC: /* skip if flag is clear */ - setstdSKF (di [card]); - break; - - - case ioSFS: /* skip if flag is set */ - setstdSKF (di [card]); - break; - - - case ioIOI: /* I/O data input */ - if (di_card->control == SET) { /* is the card in data mode? */ - data = di_card->input_data_register; /* read the input data register */ - di_card->status_register &= ~STAT_IRL; /* clear the input register loaded status */ - - if (FIFO_EMPTY && di_card->eor == CLEAR) { /* is the FIFO empty and end of record not seen? */ - if (di_card->srq == SET && DEBUG_PRJ (dptrs [card], DEB_CMDS)) - fprintf (sim_deb, ">>%s cmds: SRQ cleared\n", - dptrs [card]->name); - - di_card->srq = CLEAR; /* clear SRQ */ - update_required = FALSE; /* the card state does not change */ - } - } - - else { /* the card is in status mode */ - di_card->status_register &= /* clear the values to be computed, */ - STAT_IRL | STAT_LBO /* preserving those set elsewhere */ - | STAT_LBI | STAT_IFC; - - di_card->status_register |= /* set T/L/C status from control register */ - di_card->cntl_register /* (T/L are ORed, as MTA or MLA can also set) */ - & (CNTL_CIC | CNTL_TALK | CNTL_LSTN); - - - if (SW8_SYSCTL) /* if SW8 is set, */ - di_card->status_register |= STAT_SYSCTL; /* the card is the system controller */ - - if (di_card->ibp == lower) /* if lower byte input is next */ - di_card->status_register |= STAT_ODD; /* then the last transfer was odd */ - - di_card->status_register |= /* set the bus status bits */ - (di_card->bus_cntl /* from the corresponding bus control lines */ - & (BUS_SRQ | BUS_IFC | BUS_REN - | BUS_EOI | BUS_ATN)) << DATA_SHIFT; - - data = di_card->status_register; /* return the status word */ - } - - if (DEBUG_PRJ (dptrs [card], DEB_CPU)) - fprintf (sim_deb, ">>%s cpu: [LIx%s] %s = %06o\n", - dptrs [card]->name, hold_or_clear, - input_state [di_card->control], data); - - if (update_required && !(signal_set & ioCLF)) /* if an update is required and CLF is not present, */ - update_state (card); /* update the state, else ioCLF will update it */ - - stat_data = IORETURN (SCPE_OK, data); /* merge in the return status */ - break; - - - case ioIOO: /* I/O data output */ - data = IODATA (stat_data); /* get the data value */ - - if (DEBUG_PRJ (dptrs [card], DEB_CPU)) - fprintf (sim_deb, ">>%s cpu: [OTx%s] %s = %06o\n", - dptrs [card]->name, hold_or_clear, - output_state [di_card->control], data); - - if (di_card->control == SET) { /* is the card in data mode? */ - if (signal_set & ioEDT) /* if end of DCPC transfer */ - di_card->edt = SET; /* set the EDT flip-flop */ - - else if (di_card->cntl_register & CNTL_PACK) { /* is this a packed transfer? */ - if (!(signal_set & ioCLF)) /* and CLF not given? */ - di_card->edt = SET; /* set the EDT flip-flop */ - } - - else /* it's an unpacked transfer */ - if (data & DATA_LBO) /* is the last byte out? */ - di_card->edt = SET; /* set the EDT flip-flop */ - - if (di_card->cntl_register & CNTL_DIAG) { /* set for DIAG loopback? */ - data = fifo_unload (card, diag_access); /* unload data from the FIFO */ - fifo_load (card, data, diag_access); /* and load it back in */ - } - - else { /* the card is set for normal operation */ - fifo_load (card, data, cpu_access); /* load the data word into the FIFO */ - - if (FIFO_FULL && (di_card->bus_cntl & BUS_NRFD)) { /* FIFO full and listener not ready? */ - if (di_card->srq == SET && DEBUG_PRJ (dptrs [card], DEB_CMDS)) - fprintf (sim_deb, ">>%s cmds: SRQ cleared\n", - dptrs [card]->name); - - di_card->srq = CLEAR; /* clear SRQ */ - update_required = FALSE; /* the card state does not change */ - } - } - } - - else { /* the card is in control mode */ - assert = 0; /* initialize bus control assertions */ - deny = 0; /* and denials */ - - if (!(data & CNTL_PACK)) /* unpacked mode always sets */ - di_card->ibp = di_card->obp = lower; /* byte selectors to the lower byte */ - - if (data & CNTL_TALK) { /* talking enables ATN and EOI outputs */ - if ((data & (CNTL_PPE | CNTL_CIC)) /* if parallel poll is enabled */ - == (CNTL_PPE | CNTL_CIC)) /* and the card is CIC */ - assert = BUS_PPOLL; /* then conduct a parallel poll */ - - else if ((di_card->cntl_register /* if PP was enabled */ - & (CNTL_PPE | CNTL_CIC)) /* but is not now */ - == (CNTL_PPE | CNTL_CIC)) - deny = BUS_PPOLL; /* then end the parallel poll */ - - else if ((data /* if packed mode */ - & (CNTL_PACK | CNTL_CIC | CNTL_ATN)) /* and the card is CIC */ - == (CNTL_PACK | CNTL_CIC | CNTL_ATN)) /* then the ATN control output */ - assert = BUS_ATN; /* is coupled to the bus */ - - else /* if none of the above */ - deny = BUS_ATN; /* then ATN is not driven */ - } - - else /* the card is not talking */ - deny = BUS_ATN | BUS_EOI; /* so ATN and EOI are disabled */ - - - if (data & CNTL_NRFD) /* is card not ready set explicitly? */ - assert |= BUS_NRFD; /* assert NRFD on the bus */ - - else if (di_card->cntl_register & CNTL_NRFD) /* NRFD was set but is not now? */ - deny |= BUS_NRFD; /* deny NRFD on the bus */ - - if (FIFO_FULL) /* is the FIFO full? */ - if (data & CNTL_LSTN) /* is card now listening? */ - assert |= BUS_NRFD; /* listener and a full FIFO asserts NRFD */ - - else if (di_card->cntl_register & CNTL_LSTN) /* was card a listener but is not now? */ - deny |= BUS_NRFD; /* deny NRFD on the bus */ - - - if (SW8_SYSCTL) { /* system controller drives REN and IFC */ - if (data & CNTL_REN) /* REN control */ - assert |= BUS_REN; /* output is */ - else /* coupled to */ - deny |= BUS_REN; /* the bus */ - - if (data & CNTL_IFC) { /* is IFC set? */ - assert |= BUS_IFC; /* assert IFC on the bus */ - - di_card->status_register = - di_card->status_register - & ~(STAT_LSTN | STAT_TALK) /* clear listen and talk status */ - | STAT_IFC; /* and set IFC status */ - - di_card->ifc_timer = /* start the IFC timer by calculating */ - sim_gtime () + IFC_TIMEOUT; /* the IFC stop time (now + 100 microseconds) */ - } - } - - if ((data & (CNTL_SRQ | CNTL_CIC)) == CNTL_SRQ) /* if service request and not the controller */ - assert |= BUS_SRQ; /* then assert SRQ on the bus */ - else /* else */ - deny |= BUS_SRQ; /* deny SRQ on the bus */ - - di_card->cntl_register = data; /* save the control word */ - di_bus_control (card, CONTROLLER, assert, deny); /* update the bus control state */ - } - - if (update_required && !(signal_set & ioCLF)) /* if update required and CLF is not present, */ - update_state (card); /* update the state, else ioCLF will update it */ - break; - - - case ioPOPIO: /* power-on preset to I/O */ - di_card->flag = SET; /* set the flag */ - di_card->flagbuf = SET; /* and flag buffer */ - - if (DEBUG_PRJ (dptrs [card], DEB_CMDS)) - fprintf (sim_deb, ">>%s cmds: [POPIO] Flag set\n", - dptrs [card]->name); - break; - - - case ioCRS: /* control reset */ - if (DEBUG_PRJ (dptrs [card], DEB_CMDS)) - fprintf (sim_deb, ">>%s cmds: [CRS] Master reset\n", - dptrs [card]->name); - - di_card->status_register &= /* clear listen and talk status */ - ~(STAT_LSTN | STAT_TALK); - - deny = BUS_SRQ | BUS_REN | BUS_ATN | BUS_EOI; /* clear the lines driven by the control register */ - - if (di_card->cntl_register & (CNTL_NRFD | CNTL_LSTN)) /* if asserting NRFD or listening */ - deny |= BUS_NRFD; /* then deny because we're clearing */ - - di_card->cntl_register = 0; /* clear the control word register */ - di_card->control = CLEAR; /* clear control */ - di_card->srq = CLEAR; /* clear SRQ */ - - master_reset (card); /* perform a master reset */ - - di_bus_control (card, CONTROLLER, 0, deny); /* update the bus control state */ - update_state (card); /* update the card state */ - break; - - - case ioCLC: /* clear control flip-flop */ - di_card->control = CLEAR; /* clear control */ - - if (DEBUG_PRJ (dptrs [card], DEB_CMDS)) { - fprintf (sim_deb, ">>%s cmds: [CLC%s] Control cleared (configure mode)", - dptrs [card]->name, hold_or_clear); - - if (signal_set & ioCLF) /* if ioCLF is given, */ - fputs (", master reset\n", sim_deb); /* then report a master reset */ - else - fputc ('\n', sim_deb); - } - - if (signal_set & ioCLF) /* if ioCLF is given, */ - master_reset (card); /* then do a master reset */ - break; /* (ioCLF will call update_state for us) */ - - - case ioSTC: /* set control flip-flop */ - di_card->control = SET; /* set control */ - - if (DEBUG_PRJ (dptrs [card], DEB_CMDS)) - fprintf (sim_deb, ">>%s cmds: [STC%s] Control set (data mode)\n", - dptrs [card]->name, hold_or_clear); - break; - - - case ioEDT: /* end data transfer */ - if (DEBUG_PRJ (dptrs [card], DEB_CPU)) - fprintf (sim_deb, ">>%s cpu: [EDT] DCPC transfer ended\n", - dptrs [card]->name); - break; - - - case ioSIR: /* set interrupt request */ - setstdPRL (di [card]); /* set the standard PRL signal */ - setstdIRQ (di [card]); /* set the standard IRQ signal */ - - setSRQ (dibptr->select_code, /* set the SRQ signal if control and SRQ are set */ - di_card->srq == SET && di_card->control == SET); - break; - - - case ioIAK: /* interrupt acknowledge */ - di_card->flagbuf = CLEAR; /* clear the flag buffer */ - break; - - - default: /* all other signals */ - break; /* are ignored */ - } - - working_set = working_set & ~signal; /* remove the current signal from the set */ - } - -return stat_data; -} - - -/* Reset the simulator. - - During a hardware PRESET, POPIO sets the flag buffer and flag flip-flops, and - CRS clears the control flip-flop and Control Word Register. In addition, CRS - performs a master reset on the card. - - PON is not used by the card. - - - Implementation notes: - - 1. During a power-on reset, a pointer to the FIFO simulation register is - saved to allow access to the "qptr" field during FIFO loading and - unloading. This enables SCP to view the FIFO as a circular queue, so - that the bottom word of the FIFO is always displayed as FIFO[0], - regardless of where it is in the actual FIFO array. -*/ - -t_stat di_reset (DEVICE *dptr) -{ -DIB *dibptr = (DIB *) dptr->ctxt; /* get the DIB pointer */ -const CARD_ID card = (CARD_ID) (dibptr->card_index); /* get the card number */ - -if (sim_switches & SWMASK ('P')) { /* is this a power-on reset? */ - di [card].fifo_reg = find_reg ("FIFO", NULL, dptr); /* find the FIFO register entry */ - - if (di [card].fifo_reg == NULL) /* if not there */ - return SCPE_IERR; /* then this is a programming error! */ - else /* found it */ - di [card].fifo_reg->qptr = 0; /* so reset the FIFO bottom index */ - - di [card].status_register = 0; /* clear the status word */ - - di [card].bus_cntl = 0; /* deny the HP-IB control lines */ - - di [card].listeners = 0; /* clear the map of listeners */ - di [card].talker = 0; /* clear the map of talker */ - di [card].poll_response = 0; /* clear the map of parallel poll responses */ - - di [card].ifc_timer = 0.0; /* clear the IFC timer */ - } - -IOPRESET (dibptr); /* PRESET the device */ - -return SCPE_OK; -} - - - -/* Disc interface global SCP routines */ - - -/* Set a unit's bus address. - - Bus addresses range from 0-7 and are initialized to the unit number. All - units of a device must have unique bus addresses. In addition, the card also - has a bus address, although this is only used for the diagnostic. The card - address may be the same as a unit address, as all units are disconnected - during a diagnostic run. - - The "value" parameter indicates whether the routine is setting a unit's bus - address (0) or a card's bus address (1). - - - Implementation notes: - - 1. To ensure that each address is unique, a check is made of the other units - for conflicting addresses. An "invalid argument" error is returned if - the desired address duplicates another. This means that addresses cannot - be exchanged without first assigning one of them to an unused address. - Also, an address cannot be set that duplicates the address of a disabled - unit (which cannot be displayed without enabling it). - - An alternate implementation would be to set the new assignments into a - "shadow array" that is set into the unit flags (and checked for validity) - only when a power-on reset is done. This would follow the disc and tape - controller hardware, which reads the HP-IB address switch settings only - at power-up. -*/ - -t_stat di_set_address (UNIT *uptr, int32 value, char *cptr, void *desc) -{ -t_stat status; -uint32 index, new_address; -uint32 old_address = GET_BUSADR (uptr->flags); -DEVICE *dptr = (DEVICE *) desc; - -if (cptr == NULL) /* if the address is not given */ - return SCPE_ARG; /* report a missing argument */ - -new_address = get_uint (cptr, 10, 7, &status); /* parse the address value */ - -if (status == SCPE_OK) { /* is the parse OK? */ - if (value) /* are we setting the card address? */ - dptr->flags = dptr->flags & ~DEV_BUSADR /* store the new address in the device flags */ - | SET_DIADR (new_address); - - else { /* we are setting a unit address */ - for (index = 0; index < dptr->numunits; index++) /* look through the units */ - if (new_address != old_address /* to ensure that the address is unique */ - && new_address == GET_BUSADR (dptr->units [index].flags)) { - printf ("Bus address conflict: DA%d\n", index); - - if (sim_log) - fprintf (sim_log, "Bus address conflict: DA%d\n", index); - - return SCPE_NOFNC; /* a duplicate address gives an error */ - } - - uptr->flags = uptr->flags & ~UNIT_BUSADR /* the address is valid; change it */ - | SET_BUSADR (new_address); /* in the unit flags */ - } - } - -return status; /* return the result of the parse */ -} - - -/* Show a unit's bus address. - - The "value" parameter indicates whether the routine is showing a unit's bus - address (0) or a card's bus address (1). -*/ - -t_stat di_show_address (FILE *st, UNIT *uptr, int32 value, void *desc) -{ -DEVICE *dptr = (DEVICE *) desc; - -if (value) /* do we want the card address? */ - fprintf (st, "address=%d", GET_DIADR (dptr->flags)); /* get it from the device flags */ -else /* we want the unit address */ - fprintf (st, "bus=%d", GET_BUSADR (uptr->flags)); /* get it from the unit flags */ - -return SCPE_OK; -} - - -/* Set the bus cable connection. - - In normal use, the various tape and disc devices are connected together and - to the disc interface card by HP-IB cables. For the diagnostic, two disc - interface cards are connected by a single cable. - - The "value" parameter indicates whether the routine is connecting the - cable to devices for normal use (0) or to another card for diagnostics (1). - - - Implementation notes: - - 1. Initially, only one card and peripheral set is simulated: the ICD disc - family (DA device). For diagnostic use, a second, dummy card is enabled - (DC device). Once a second card simulation is implemented, this code - will no longer be necessary. -*/ - -t_stat di_set_cable (UNIT *uptr, int32 value, char *cptr, void *desc) -{ -if (value) { /* is the diagnostic cable selected? */ - ((DEVICE *) desc)->flags |= DEV_DIAG; /* set the diagnostic flag */ - dc_dev.flags &= ~DEV_DIS; /* enable the dummy device */ - dc_dev.flags |= DEV_DIAG; /* and set its flag as well */ - } -else { /* the peripheral cable is selected */ - ((DEVICE *) desc)->flags &= ~DEV_DIAG; /* clear the diagnostic flag */ - dc_dev.flags |= DEV_DIS; /* disable the dummy device */ - dc_dev.flags &= ~DEV_DIAG; /* and clear its flag */ - } - -return SCPE_OK; -} - - -/* Show the bus cable connection. - - The "value" parameter indicates whether the cable is connected to devices for - normal use (0) or to another card for diagnostics (1). -*/ - -t_stat di_show_cable (FILE *st, UNIT *uptr, int32 value, void *desc) -{ -if (((DEVICE *) desc)->flags & DEV_DIAG) /* is the cable connected for diagnostics? */ - fputs ("diagnostic cable", st); /* report it */ -else /* the cable is connected for device use */ - fputs ("HP-IB cable", st); /* report the condition */ - -return SCPE_OK; -} - - - -/* Disc interface global bus routines. - - In hardware, the HP-IB bus consists of eight control lines and eight data - lines. Signals are asserted on the control lines to establish communication - between a source and one or more acceptors. For commands, the source is - always the controller (the 12821A card), and the acceptors are all of the - connected devices. For data, the source is the current talker, and the - acceptors are one or more current listeners. A three-wire interlocking - handshake enables communication at the rate of the slowest of the multiple - acceptors. The controller conducts a parallel poll by asserting ATN and EOI - together. Devices whose parallel poll responses are enabled each assert one - of the data lines to indicate that service is required. - - In simulation, a disabled or detached unit logically is not connected to the - bus. The card maintains a bitmap of acceptors (all devices currently - attached), listeners (all devices currently addressed to listen), the talker - (the device currently addressed to talk), and the enabled parallel poll - responses. Changes in control line state are communicated to all acceptors - via control/respond function calls, and data is exchanged between talker and - listeners via source/acceptor function calls. Data bytes are sent to all - current listeners in bus-address order. The card conducts a parallel poll by - checking the response bitmap; devices must set and clear their poll responses - appropriately in advance of the poll. - - Not all of the HP-IB control lines are simulated. The DAV and NDAC handshake - lines are never asserted; instead, they are simulated by the bus source - function calling one or more bus acceptor functions. SRQ and REN are - asserted as directed by the system controller but are not otherwise used (no - HP disc or tape devices assert SRQ or respond to REN). IFC, ATN, EOI, and - NRFD are asserted and tested by the controller and devices. In particular, - asserting NRFD will hold off a pending data transmission until it is denied. - - The functions that simulate the HP-IB (where "*" is "di", "da", etc.) are: - - di_bus_source -- Source a data byte to the bus. Returns TRUE if the - byte was accepted (i.e., there were one or more - listeners) and FALSE if it was not. Called by the - controller to send commands to devices, and called by - the current talker to send data to the listener(s). ATN - and EOI should be asserted as required on the bus before - calling. - - *_bus_accept -- Accept a data byte from the bus. Returns TRUE if the - byte was accepted and FALSE if it was not. Called by - di_bus_source to handshake between source and acceptor. - If ATN is asserted on the bus, the byte is a command; - otherwise, it is data. If EOI is asserted for a data - byte, it is the last byte of a transmission. - - di_bus_control -- Set the control lines on the bus. Called by the system - controller to assert or deny REN or IFC, by the current - controller to assert or deny SRQ, NRFD, or ATN and EOI - (to conduct or conclude a parallel poll), and by the - current listener to assert or deny NRFD. All connected - devices on the bus are notified of the changes. It is - not necessary to call di_bus_control for changes to ATN - and EOI that accompany a command or data byte. - - *_bus_respond -- Respond to changes in the control lines on the bus. - Called by di_bus_control to inform each connected device - of a change in control state. - - di_poll_response -- Set a device's poll response. Called by a device to - enable or disable its response to a future parallel - poll. -*/ - - -/* Source a byte to the bus. - - This routine is called to send bytes to devices on the bus connected to the - specified card. If the card is in diagnostic mode, which simulate two cards - connected by an HP-IB cable, then the byte is sent to another card in the - card cage that is also in diagnostic mode and enabled to receive. If the - card is not in diagnostic mode, then the byte is sent to all acceptors (if a - command) or to all listeners (if data) on the bus. - - The return value indicates whether or not there were any acceptors on the - bus. - - - Implementation notes: - - 1. If the responses from a previously conducted parallel poll are not - cleared from the FIFO before enabling the card to transmit, the card will - appear to conduct a new parallel poll because the FIFO tags cause ATN and - EOI to be asserted. This "fake" parallel poll is ignored (a real - parallel poll does not source data onto the bus). -*/ - -t_bool di_bus_source (CARD_ID card, uint8 data) -{ -CARD_ID other; -uint32 acceptors, unit; -t_bool accepted = FALSE; - -if (DEBUG_PRJ (dptrs [card], DEB_XFER)) { - fprintf (sim_deb, ">>%s xfer: HP-IB DIO %03o available ", dptrs [card]->name, data); - fprint_bus (sim_deb, "[%s]\n", di [card].bus_cntl); - } - -if (dptrs [card]->flags & DEV_DIAG) /* is this a diagnostic run? */ - for (other = first_card; other <= last_card; other++) { /* look through the list of cards */ - if (other != card && dptrs [other] /* for the other card */ - && (dptrs [other]->flags & DEV_DIAG) /* that is configured for diagnostic mode */ - && (di [other].cntl_register & CNTL_LSTN)) /* and is listening */ - accepted = di_bus_accept (other, data); /* call the interface acceptor for the other card */ - } - -else if ((di [card].bus_cntl & BUS_PPOLL) != BUS_PPOLL) { /* this is a normal run; not a fake poll? */ - if (di [card].cntl_register & CNTL_LSTN) /* is the card a listener? */ - accepted = di_bus_accept (card, data); /* call the interface acceptor for this card */ - - acceptors = di [card].acceptors; /* get the map of acceptors */ - - if (!(di [card].bus_cntl & BUS_ATN) /* if a data transfer, */ - || (data & BUS_COMMAND) == BUS_ACG) /* or an addressed command, e.g., SDC */ - acceptors = di [card].listeners; /* then limit just to listeners */ - - for (unit = 0; acceptors; unit++) { /* loop through the units */ - if (acceptors & 1) /* is the current unit accepting? */ - accepted |= (*bus_accept [card]) (unit, data); /* call the acceptor for this card */ - - acceptors = acceptors >> 1; /* move to the next acceptor */ - } - } - -if (DEBUG_PRJ (dptrs [card], DEB_XFER) && !accepted) - fprintf (sim_deb, ">>%s xfer: HP-IB no acceptors\n", - dptrs [card]->name); - -return accepted; -} - - -/* Assert or deny control on the bus. - - This routine is called by the indicated unit to assert or deny the HP-IB - control lines on the bus connected to the specified card. Separate sets of - signals to assert and deny are provided. - - If the bus state after modification did not change, the routine returns with - no further action. Otherwise, if the card is in diagnostic mode, then - notification of the bus change is sent to another card in the card cage that - is also in diagnostic mode. - - If the card is not in diagnostic mode, then the set of control lines that - are changing is checked to determine whether notification is necessary. If - not, then the change is not broadcast to improve performance. However, if - notification is required, then all acceptors on the bus are informed of the - change. - - - Implementation notes: - - 1. If a signal is asserted and denied in the same call, the assertion takes - precedence. - - 2. Of the sixteen potential control line state changes, only IFC assertion - and ATN and NRFD denial must be broadcast. Asserting IFC unaddresses all - devices, and denying ATN or NRFD allows a waiting talker to source a data - byte to the bus. Devices do not act upon the remaining thirteen state - changes, and a considerable performance improvement is obtained by - omitting the notification calls. - - 3. All control line state notifications are sent in diagnostic mode, as the - responses of the other card are specifically tested by the diagnostic. - - 4. Asserting ATN and EOI will conduct a parallel poll. Devices are not - notified of the poll. Instead, the previously stored parallel poll - responses will be used. -*/ - -#define ASSERT_SET (BUS_IFC) -#define DENY_SET (BUS_ATN | BUS_NRFD) - -void di_bus_control (CARD_ID card, uint32 unit, uint8 assert, uint8 deny) -{ -CARD_ID other; -uint32 acceptors, responder; -t_bool responded; -uint8 new_state, new_assertions, new_denials; - -new_state = di [card].bus_cntl & ~deny | assert; /* set up the new control state */ - -if (new_state == di [card].bus_cntl) /* if the control state did not change */ - return; /* return now */ - -new_assertions = ~di [card].bus_cntl & assert; /* get the changing assertions */ -new_denials = di [card].bus_cntl & deny; /* get the changing denials */ - -di [card].bus_cntl = new_state; /* establish the new control state */ - -if (DEBUG_PRJ (dptrs [card], DEB_XFER)) { - if (unit == CONTROLLER) - fprintf (sim_deb, ">>%s xfer: HP-IB card %d", dptrs [card]->name, card); - else - fprintf (sim_deb, ">>%s xfer: HP-IB address %d", - dptrs [card]->name, GET_BUSADR (dptrs [card]->units [unit].flags)); - - if (new_assertions) - fprint_bus (sim_deb, " asserted [%s]", new_assertions); - - if (new_denials) - fprint_bus (sim_deb, " denied [%s]", new_denials); - - fprint_bus (sim_deb, ", bus is [%s]\n", new_state); - } - -if ((dptrs [card]->flags & DEV_DIAG) /* is the card in diagnostic mode? */ - || (new_assertions & ASSERT_SET) /* or are changed signals in the */ - || (new_denials & DENY_SET)) { /* set that must be broadcast? */ - responded = FALSE; /* assume no response was received */ - - if (dptrs [card]->flags & DEV_DIAG) { /* is this a diagnostic run? */ - for (other = first_card; other <= last_card; other++) /* look through the list of cards */ - if (other != card && dptrs [other] /* for the other card */ - && (dptrs [other]->flags & DEV_DIAG)) { /* that is configured for diagnostic */ - di_bus_respond (other, new_state); /* notify the other card of the new control state */ - responded = TRUE; /* and note that there was a responder */ - } - } - - else { /* this is a normal run */ - update_state (card); /* update the card for the new control state */ - - acceptors = di [card].acceptors; /* get the map of acceptors */ - responded = (acceptors != 0); /* set response if there are any acceptors */ - - for (responder = 0; acceptors; responder++) { /* loop the through units */ - if ((acceptors & 1) && responder != unit) /* is the current unit accepting? */ - (*bus_respond [card]) (card, responder, new_state); /* call the responder for this card */ - - acceptors = acceptors >> 1; /* move to the next acceptor */ - } - } - - if (DEBUG_PRJ (dptrs [card], DEB_XFER) & !responded) - fprintf (sim_deb, ">>%s xfer: HP-IB no responders\n", - dptrs [card]->name); -} - -if ((new_state & BUS_PPOLL) == BUS_PPOLL) /* was a parallel poll requested? */ - di_bus_poll (card); /* conduct the poll */ - -return; -} - - -/* Enable or disable a unit's parallel poll response. - - The poll response for a unit connected to a specified card is set or cleared - as indicated. If a parallel poll is in progress when a poll response is set, - the poll is conducted again to reflect the new response. -*/ - -void di_poll_response (CARD_ID card, uint32 unit, FLIP_FLOP response) -{ -const uint32 address = GET_BUSADR (dptrs [card]->units [unit].flags); -uint32 previous_response = di [card].poll_response; - -if (response == SET) { /* enable the poll response? */ - di [card].poll_response |= PPR (address); /* set the response bit */ - - if ((di [card].bus_cntl & BUS_PPOLL) == BUS_PPOLL) /* is a parallel poll in progress? */ - di_bus_poll (card); /* conduct again with the new response */ - } -else /* disable the poll response */ - di [card].poll_response &= ~PPR (address); /* by clearing the response bit */ - -if (DEBUG_PRJ (dptrs [card], DEB_XFER) - && previous_response != di [card].poll_response) - fprintf (sim_deb, ">>%s xfer: HP-IB address %d parallel poll response %s\n", - dptrs [card]->name, address, (response == SET ? "enabled" : "disabled")); - -return; -} - - - -/* Disc interface local bus routines */ - - -/* Conduct a parallel poll on the bus. - - A controller asserting ATN and EOI simultaneously on the bus is conducting a - parallel poll. In hardware, each device whose poll response is enabled - asserts the data line corresponding to its bus address. The controller - terminates the poll by denying ATN and EOI. - - Setting the CIC (controller in charge) and PPE (parallel poll enable) bits in - the Control Word Register direct the disc interface to conduct a poll. - Setting PPE without CIC enables the poll response for the interface. - - In the diagnostic mode, one card is set to conduct the poll, and the other is - set to respond to it. In the normal mode, connected devices have set or - cleared their respective poll responses before this routine is called. - - - Implementation notes: - - 1. The card hardware fills the upper and lower bytes of the FIFO with the - response byte. In simulation, we use the diag_access mode to do the same - thing (diagnostic loopback also fills both bytes with the lower byte). -*/ - -static void di_bus_poll (CARD_ID card) -{ -CARD_ID other; -uint8 response; - -if ((di [card].cntl_register - & (CNTL_PPE | CNTL_CIC)) == CNTL_PPE) /* is the card's poll response enabled? */ - response = di [card].poll_response /* add the card's response */ - | PPR (GET_DIADR (dptrs [card]->flags)); /* to the devices' responses */ -else - response = di [card].poll_response; /* the card response is disabled, so just use devices */ - -if (dptrs [card]->flags & DEV_DIAG) /* is this a diagnostic run? */ - for (other = first_card; other <= last_card; other++) /* look through the list of cards */ - if (other != card && dptrs [other] /* for another card */ - && (dptrs [other]->flags & DEV_DIAG) /* that is configured for the diagnostic */ - && (di [other].cntl_register /* and has PPE asserted */ - & (CNTL_PPE | CNTL_CIC)) == CNTL_PPE) - response |= /* merge its poll response */ - PPR (GET_DIADR (dptrs [other]->flags)); - -if (response) { /* is a poll response indicated? */ - if (DEBUG_PRJ (dptrs [card], DEB_XFER)) - fprintf (sim_deb, ">>%s xfer: HP-IB parallel poll DIO %03o\n", - dptrs [card]->name, response); - - while (di [card].fifo_count != FIFO_SIZE) /* fill the card FIFO with the responses */ - fifo_load (card, (uint16) response, diag_access); /* (hardware feature) */ - - update_state (card); /* update the card state */ - } - -return; -} - - -/* Accept a data byte from the bus. - - The indicated card accepts a byte that has been sourced to the bus. The byte - is loaded into the FIFO, and the card state is updated to reflect the load. - - Bus acceptors return TRUE to indicate that the byte was accepted. A card - always accepts a byte, so the routine always returns TRUE. -*/ - -static t_bool di_bus_accept (CARD_ID card, uint8 data) -{ -if (DEBUG_PRJ (dptrs [card], DEB_XFER)) - fprintf (sim_deb, ">>%s xfer: HP-IB card %d accepted data %03o \n", - dptrs [card]->name, card, data); - -fifo_load (card, data, bus_access); /* load the data byte into the FIFO */ -update_state (card); /* and update the card state */ -return TRUE; /* indicate that the byte was accepted */ -} - - -/* Respond to the bus control lines. - - The indicated card is notified of the new control state on the bus. The - routine establishes the new bus state and updates the card state to reflect - the change. -*/ - -static void di_bus_respond (CARD_ID card, uint8 new_cntl) -{ -di [card].bus_cntl = new_cntl; /* update the bus control lines */ -update_state (card); /* update the card state */ -return; -} - - - -/* Disc interface local utility routines */ - - -/* Master reset the interface. - - This is the programmed card master reset, not the simulator reset routine. - Master reset initializes a number of flip-flops and data paths on the card. - The primary use, other than during a PRESET, is to clear the FIFO in - preparation to changing the card from a listener to a talker or vice versa. - This ensures that unneeded FIFO data is not transmitted inadvertently to the - bus or to the CPU. It is also used when changing the data mode from unpacked - to packed to release the byte pointer flip-flops, which are held in the - "lower byte" position during unpacked transfers. - - In hardware, a master reset: - - clears the EDT, EOR, IRL, LBO, LBI, and IFC flip-flops - - clears the Input Data Register - - clears the FIFO - - sets or clears the odd/even input and output byte pointer flip-flops, - depending on whether the P (packed transfer) bit is set in the Control - Word Register -*/ - -static void master_reset (CARD_ID card) -{ -di [card].edt = CLEAR; /* clear the EDT flip-flop */ -di [card].eor = CLEAR; /* clear the EOR flip-flop */ - -if (di [card].cntl_register & CNTL_PACK) /* if packed mode is set, */ - di [card].ibp = di [card].obp = upper; /* MR sets the selectors to the upper byte */ -else /* otherwise, unpacked mode overrides */ - di [card].ibp = di [card].obp = lower; /* and sets the selectors to the lower byte */ - -di [card].status_register &= /* clear the status flip-flops */ - ~(STAT_IRL | STAT_LBO | STAT_LBI | STAT_IFC); - -di [card].input_data_register = 0; /* clear the input data register */ -di [card].fifo_count = 0; /* clear the FIFO */ - -if (DEBUG_PRJ (dptrs [card], DEB_BUF)) - fprintf (sim_deb, ">>%s buf: FIFO cleared\n", - dptrs [card]->name); - -return; -} - - -/* Update the interface state. - - In hardware, certain external operations cause automatic responses by the - disc interface card. For example, when the Input Data Register is unloaded - by an LIx instruction, it is automatically reloaded with the next word from - the FIFO. Also, the card may be set to interrupt in response to the - assertion of certain bus control lines. - - In simulation, this routine must be called whenever the FIFO, card control, - or bus control state changes. It determines whether: - - 1. ...the next word from the FIFO should be unloaded into the IDR. If the - card is listening, and the IDR is empty, and the FIFO contains data, then - a word is unloaded and stored in the IDR, and the Input Register Loaded - status bit is set. - - 2. ...the next word from the FIFO should be unloaded and sourced to the bus. - If the card is talking (but not polling), and the listener is ready to - accept data, and the last byte has not been sent, and the FIFO contains - data, then a word is unloaded and sourced to the bus. This occurs - regardless of whether or not there are any listeners. - - 3. ...an interface clear operation has completed. If IFC is asserted, and - the current simulation time is later than the IFC expiration time, then - IFC is denied, and the timer is reset. - - 4. ...the card should assert NRFD to prevent FIFO overflow. If the card is - listening, and the FIFO is full, or the last byte has been received, or a - pause has been explicitly requested, then NRFD is asserted. - - 5. ...the SRQ flip-flop should be set or cleared. If the card is listening - and the Input Data Register has been loaded, or the card is talking and - the FIFO is not full, then SRQ is asserted to request a DCPC transfer. - - 6. ...the flag flip-flop should be set or cleared. If the Input Data - Register has been loaded or the Last Byte Out flip-flop is set and the - corresponding Control Word Register IRL or LBO bits are set, or the End - of Record flip-flop is set and the Input Data Register has been unloaded, - or SRQ is asserted on the bus and the corresponding Control Word Register - bit is set when the card is not the controller-in-charge, or REN or IFC - is asserted on the bus and the corresponding Control Word Register bits - are set when the card is not the system controller, then the flag is set - to request an interrupt. - - - Implementation notes: - - 1. The fifo_unload routine may set STAT_LBO, so the flag test must be done - after unloading. - - 2. The gcc compiler (at least as of version 4.6.2) does not optimize - repeated use of array-of-structures accesses. Instead, it recalculates - the index each time, even though the index is a constant within the - function. To avoid this performance penalty, we use a pointer to the - selected DI_STATE structure. Note that VC++ 2008 does perform this - optimization. - */ - -static void update_state (CARD_ID card) -{ -DIB * const dibptr = (DIB *) dptrs [card]->ctxt; -DI_STATE * const di_card = &di [card]; -uint8 assert = 0; -uint8 deny = 0; -uint16 data; -FLIP_FLOP previous_state; - -if (di_card->cntl_register & CNTL_LSTN) { /* is the card a listener? */ - if (!(di_card->status_register & STAT_IRL) /* is the IDR empty? */ - && ! FIFO_EMPTY) { /* and data remains in the FIFO? */ - data = fifo_unload (card, cpu_access); /* unload the FIFO */ - di_card->input_data_register = data; /* into the IDR */ - di_card->status_register |= STAT_IRL; /* set the input register loaded status */ - } - } - -else if ((di_card->cntl_register /* is the card a talker? */ - & (CNTL_TALK | CNTL_PPE)) == CNTL_TALK) /* and not polling? */ - while (! FIFO_EMPTY /* is data remaining in FIFO? */ - && !(di_card->bus_cntl & BUS_NRFD) /* and NRFD is denied? */ - && !(di_card->status_register & STAT_LBO)) { /* and the last byte has not been sent? */ - data = fifo_unload (card, bus_access); /* unload a FIFO byte */ - di_bus_source (card, (uint8) data); /* source it to the bus */ - } - - -if (di_card->bus_cntl & BUS_IFC /* is an IFC in progress? */ - && di_card->ifc_timer != 0.0 /* and I am timing? */ - && sim_gtime () > di_card->ifc_timer) { /* and has the timeout elapsed? */ - deny = BUS_IFC; /* deny IFC on the bus */ - di_card->ifc_timer = 0.0; /* clear the IFC timer */ - di_card->status_register &= ~STAT_IFC; /* and clear IFC status */ - } - - -if (di_card->cntl_register & CNTL_LSTN) /* is the card a listener? */ - if (di_card->cntl_register & CNTL_NRFD /* if explicitly requested */ - || di_card->status_register & STAT_LBI /* or the last byte is in */ - || FIFO_FULL) /* or the FIFO is full */ - assert = BUS_NRFD; /* then assert NRFD */ - else /* otherwise the card is ready for data */ - deny |= BUS_NRFD; /* so deny NRFD */ - -if (assert != deny) /* was there any change in bus state? */ - di_bus_control (card, CONTROLLER, assert, deny); /* update the bus control */ - - -previous_state = di_card->srq; /* save the current SRQ state */ - -if (di_card->cntl_register & CNTL_LSTN /* if the card is a listener */ - && di_card->status_register & STAT_IRL /* and the input register is loaded, */ - || di_card->cntl_register & CNTL_TALK /* or the card is a talker */ - && ! FIFO_FULL) /* and the FIFO is not full */ - di_card->srq = SET; /* then request a DCPC cycle */ -else - di_card->srq = CLEAR; /* otherwise, DCPC service is not needed */ - - -if (DEBUG_PRJ (dptrs [card], DEB_CMDS) - && di_card->srq != previous_state) - fprintf (sim_deb, ">>%s cmds: SRQ %s\n", - dptrs [card]->name, di_card->srq == SET ? "set" : "cleared"); - - -if (di_card->status_register & STAT_IRL /* is the input register loaded */ - && di_card->cntl_register & CNTL_IRL /* and notification is wanted? */ - || di_card->status_register & STAT_LBO /* or is the last byte out */ - && di_card->cntl_register & CNTL_LBO /* and notification is wanted? */ - || di_card->eor == SET /* or was the end of record seen */ - && !(di_card->status_register & STAT_IRL) /* and the input register was unloaded? */ - || di_card->bus_cntl & BUS_SRQ /* or is SRQ asserted on the bus */ - && di_card->cntl_register & CNTL_SRQ /* and notification is wanted */ - && di_card->cntl_register & CNTL_CIC /* and the card is not controller? */ - || !SW8_SYSCTL /* or is the card not the system controller */ - && di_card->bus_cntl & BUS_REN /* and REN is asserted on the bus */ - && di_card->cntl_register & CNTL_REN /* and notification is wanted? */ - || !SW8_SYSCTL /* or is the card not the system controller */ - && di_card->status_register & STAT_IFC /* and IFC is asserted on the bus */ - && di_card->cntl_register & CNTL_IFC) { /* and notification is wanted? */ - - if (DEBUG_PRJ (dptrs [card], DEB_CMDS)) - fprintf (sim_deb, ">>%s cmds: Flag set\n", - dptrs [card]->name); - - di_io (dibptr, ioENF, 0); /* set the flag and recalculate interrupts */ - } - -else if (di_card->srq != previous_state) /* if SRQ changed state, */ - di_io (dibptr, ioSIR, 0); /* then recalculate interrupts */ - -return; -} - - -/* Load a word or byte into the FIFO. - - A word or byte is loaded into the next available location in the FIFO. The - significance of the data parameter is indicated by the access mode as - follows: - - - For CPU access, the parameter is a 16-bit value. - - - For bus access, the parameter is an 8-bit value in the lower byte and a - zero in the upper byte. - - - For diagnostic access, the parameter is an 8-bit value in the lower byte - that will be duplicated in the upper byte. - - For bus access, byte loading into the FIFO is controlled by the value of the - Input Buffer Pointer (IBP) selector. - - In addition to data words, the FIFO holds tags that mark the last byte - received or to be transmitted and that indicate the state of the ATN and EOI - bus lines (if listening) or the states to assert (if talking). The tag is - assembled into the upper word, the data is assembled into the lower word, and - then the 32-bit value is stored in the next available FIFO location. - - If data is coming from the CPU, the 16-bit value is loaded into the next FIFO - location, and the occupancy count is incremented. - - If the data is coming from the bus, and the input mode is unpacked, the 8-bit - value is loaded into the lower byte of the next FIFO location, and the - occupancy count is incremented. In hardware, the upper FIFO is not clocked; - in simulation, the upper byte is set to zero. The IBP always points at the - lower byte in unpacked mode. - - If the data is coming from the bus, and the input mode is packed, the 8-bit - value is loaded into either the upper or lower byte of the next FIFO - location, depending on the value of the IBP, and the IBP is toggled. If the - value was stored in the lower byte, the occupancy count is incremented. - - A special case occurs when the value is to be stored in the upper byte, and - the LBR tag is set to indicate that this is the last byte to be received. In - this case, the value is stored in both bytes of the next FIFO location, and - the occupancy counter is incremented. - - If data is coming from the diagnostic FIFO loopback, the 8-bit value in the - lower byte is copied to the upper byte, the resulting 16-bit value is loaded - into the next FIFO location, and the occupancy count is incremented. - - - Implementation notes: - - 1. Four tag bits are loaded into the upper word of each FIFO entry: - - - Last Byte Received (while receiving, a line feed is received and the - LF bit is set in the Control Word Register, or a byte with EOI - asserted is received and the EOI bit is set). - - - End of Data Transfer (while transmitting, DCPC asserts the EDT - backplane signal, or an unpacked-mode data word has the LBO bit set, - or a packed-mode OTx is issued without an accompanying CLF). - - - ATN (the state of ATN on the bus if receiving, or the ATN bit in the - unpacked data word if transmitting). - - - EOI (the state of EOI on the bus if receiving, or the EOI bit in the - unpacked data word if transmitting). - - 2. The FIFO is implemented as circular queue to take advantage of REG_CIRC - EXAMINE semantics. REG->qptr is the index of the first word currently in - the FIFO. By specifying REG_CIRC, examining FIFO[0-n] will always - display the words in load order, regardless of the actual array index of - the start of the list. The number of words currently present in the FIFO - is kept in fifo_count (0 = empty, 1-16 = number of words available). - - If fifo_count < FIFO_SIZE, (REG->qptr + fifo_count) mod FIFO_SIZE is the - index of the new word location. Loading stores the word there and then - increments fifo_count. - - 3. Because the load and unload routines need access to qptr in the REG - structure for the FIFO array, pointers to the REG for each card are - stored in the fifo_reg array during device reset. - - 4. The gcc compiler (at least as of version 4.6.2) does not optimize - repeated use of array-of-structures accesses. Instead, it recalculates - the index each time, even though the index is a constant within the - function. To avoid this performance penalty, we use a pointer to the - selected DI_STATE structure. Note that VC++ 2008 does perform this - optimization. -*/ - -static void fifo_load (CARD_ID card, uint16 data, FIFO_ACCESS access) -{ -uint32 tag, index; -t_bool add_word = TRUE; -DI_STATE * const di_card = &di [card]; - -if (FIFO_FULL) { /* is the FIFO already full? */ - if (DEBUG_PRJ (dptrs [card], DEB_BUF)) - fprintf (sim_deb, ">>%s buf: Attempted load to full FIFO, data %0*o\n", - dptrs [card]->name, (access == bus_access ? 3 : 6), data); - - return; /* return with the load ignored */ - } - -if (di_card->cntl_register & CNTL_LSTN) { /* is the card receiving? */ - tag = (di_card->bus_cntl /* set the tag from the bus signals */ - & (BUS_ATN | BUS_EOI)) << BUS_SHIFT; /* shifted to the tag locations */ - - if ((di_card->cntl_register & CNTL_EOI /* EOI detection is enabled, */ - && di_card->bus_cntl & BUS_EOI) /* and data was tagged with EOI? */ - || (di_card->cntl_register & CNTL_LF /* or LF detection is enabled, */ - && GET_LOWER (data) == LF)) { /* and the byte is a line feed? */ - tag = tag | TAG_LBR; /* tag as the last byte received */ - di_card->status_register |= STAT_LBI; /* set the last byte in status */ - } - else /* neither termination condition was seen */ - di_card->status_register &= ~STAT_LBI; /* so clear the last byte in status */ - } - -else /* the card is transmitting */ - tag = (data & (DATA_ATN | DATA_EOI)) << DATA_SHIFT; /* set the tag from the data shifted to the tag location */ - -if (di_card->edt == SET) /* is this the end of the data transfer? */ - tag = tag | TAG_EDT; /* set the EDT tag */ - - -index = (di_card->fifo_reg->qptr /* calculate the index */ - + di_card->fifo_count) % FIFO_SIZE; /* of the next available location */ - -if (access == bus_access) { /* is this a bus access */ - if (di_card->ibp == upper) { /* in packed mode for the upper byte? */ - di_card->ibp = lower; /* set the lower byte as next */ - - if (tag & TAG_LBR) /* is this the last byte? */ - di_card->fifo [index] = /* copy to both bytes of the FIFO */ - tag | SET_BOTH (data); /* and store with the tag */ - else { /* more bytes are expected */ - di_card->fifo [index] = /* so position this byte */ - tag | SET_UPPER (data); /* and store it with the tag */ - add_word = FALSE; /* wait for the second byte before adding */ - } - } - - else /* this is the lower byte */ - if (di_card->cntl_register & CNTL_PACK) { /* is the card in packed mode? */ - di_card->ibp = upper; /* set the upper byte as next */ - - di_card->fifo [index] = /* merge the data and tag values */ - tag | di_card->fifo [index] | SET_LOWER (data); - } - else /* the card is in unpacked mode */ - di_card->fifo [index] = /* position this byte */ - tag | SET_LOWER (data); /* and store with the tag */ - } - -else if (access == cpu_access) /* is this a cpu access? */ - di_card->fifo [index] = tag | data; /* store the tag and full word in the FIFO */ - -else { /* must be diagnostic access */ - data = SET_BOTH (GET_LOWER (data)); /* copy the lower byte to the upper byte */ - di_card->fifo [index] = tag | data; /* and store the tag and full word in the FIFO */ - } - -if (add_word) /* did we add a word to the FIFO? */ - di_card->fifo_count = di_card->fifo_count + 1; /* increment the count of words stored */ - -if (DEBUG_PRJ (dptrs [card], DEB_BUF)) { - fprintf (sim_deb, ">>%s buf: Data %0*o tag ", - dptrs [card]->name, (access == bus_access ? 3 : 6), data); - fprint_val (sim_deb, tag >> BUS_SHIFT, 2, 4, PV_RZRO); - fprintf (sim_deb, " loaded into FIFO (%d)\n", di_card->fifo_count); - } - -return; -} - - -/* Unload a word or byte from the FIFO. - - A word or byte is unloaded from the first location in the FIFO. The - significance of the returned value is indicated by the access mode as - follows: - - - For CPU access, a 16-bit value is unloaded and returned. - - - For bus access, an 8-bit value is unloaded and returned. - - - For diagnostic access, an 16-bit value is unloaded, and the lower byte - is returned. - - For bus access, byte unloading from the FIFO is controlled by the value of - the Output Buffer Pointer (OBP) selector. - - If the FIFO is not empty, the first entry is obtained and split into tag and - data words. The LBR tag value is loaded into the EOR flip-flop if the CPU is - accessing. The EDT tag sets Last Byte Out status if the last byte is being - unloaded. - - If the data is going to the CPU, the 16-bit packed data value is returned as - is, or the lower byte of the unpacked value is merged with the tags for ATN - and EOI and returned. The occupancy count is decremented to unload the FIFO - entry. - - If the data is going to the bus, and the input mode is unpacked, the 8-bit - value is returned in the lower byte, and the occupancy count is decremented. - In hardware, the upper FIFO is not clocked; in simulation, the upper byte is - ignored. The OBP always points at the lower byte in unpacked mode. - - If the data is going to the bus, and the input mode is packed, the 8-bit - value is unloaded from either the upper or lower byte of the data word, - depending on the value of the OBP, and returned in the lower byte. The OBP - value is toggled. If the value was obtained from the lower byte, the - occupancy count is decremented to unload the FIFO. Otherwise, the count is - not altered, so that the lower-byte access will be from the same FIFO entry. - - If data is going to the diagnostic FIFO loopback, the lower byte of the - 16-bit value is returned; the upper byte of the returned value is zero. - - - Implementation notes: - - 1. Four tag bits are unloaded from the upper word of each FIFO entry: - - - Last Byte Received (sets the End of Record flip-flop when the last - byte received is loaded into the Input Data Register). - - - End of Data Transfer (sets the LBO bit in the Status Word Register - when the last byte is unloaded from the FIFO). - - - ATN (in unpacked mode, sets the ATN bit in the returned data word - if listening, or controls the bus ATN line if talking; in packed mode, - the tag is ignored). - - - EOI (in unpacked mode, sets the EOI bit in the returned data word if - listening, or asserts the bus EOI line if talking; in packed mode, the - tag is ignored). - - ATN and EOI tag handling is complex. If the card is listening in the - unpacked mode, the ATN tag substitutes for bit 8 of the data word, and - the EOI tag substitutes for bit 9. In the packed mode, bits 8 and 9 are - as stored in the FIFO (they are upper-byte data bits). - - If the card is talking in the unpacked mode, the ATN tag asserts or - denies ATN on the bus if the card is the CIC, and the EOI tag asserts or - denies EOI on the bus. In the packed mode, the ATN bit in the Control - Word Register asserts or denies ATN on the bus if the card is the CIC, - and the EOI bit asserts EOI on the bus if the last byte of the entry - tagged with EDT has been unloaded from the FIFO (which sets LBO status) - or denies EOI otherwise. - - 2. In hardware, the EOR flip-flop is clocked with the Input Data Register. - Therefore, when the card is listening, EOR is set not when the last byte - is unloaded from the FIFO, but rather when that byte is loaded into the - IDR. These two actions occur together when the IDR is empty. - - However, during diagnostic access, data unloaded from the FIFO is - reloaded, and the IDR is never clocked. As the T and L bits must be set - with DIAG in the Control Word Register to enable the loopback path, the - LBR tag will be entered into the FIFO if EOI or LF detection is enabled, - but the EOR flip-flop will not be set when that word falls through to be - unloaded. - - In simulation, EOR is set whenever the LBR tag is unloaded from the FIFO - during CPU access, as a CPU unload is always followed by an IDR store. - - 3. If fifo_count > 0, REG->qptr is the index of the word to remove. Removal - gets the word and then increments qptr (mod FIFO_SIZE) and decrements - fifo_count. - - 4. The gcc compiler (at least as of version 4.6.2) does not optimize - repeated use of array-of-structures accesses. Instead, it recalculates - the index each time, even though the index is a constant within the - function. To avoid this performance penalty, we use a pointer to the - selected DI_STATE structure. Note that VC++ 2008 does perform this - optimization. -*/ - -static uint16 fifo_unload (CARD_ID card, FIFO_ACCESS access) -{ -uint32 data, tag; -t_bool remove_word = TRUE; -DI_STATE * const di_card = &di [card]; - -if (FIFO_EMPTY) { /* is the FIFO already empty? */ - if (DEBUG_PRJ (dptrs [card], DEB_BUF)) - fprintf (sim_deb, ">>%s buf: Attempted unload from empty FIFO\n", - dptrs [card]->name); - - return 0; /* return with no data */ - } - -data = di_card->fifo [di_card->fifo_reg->qptr]; /* get the tag and data from the FIFO */ - -tag = data & TAG_MASK; /* mask the tag to just the tag bits */ -data = data & DMASK; /* and the data to just the data bits */ - -if (tag & TAG_EDT /* is this the end of a data transfer */ - && (di_card->obp == lower /* and the lower byte is next */ - || di_card->cntl_register & CNTL_ODD)) /* or we are sending an odd number of bytes? */ - di_card->status_register |= STAT_LBO; /* set the last byte out status */ - - -if (access == cpu_access) { /* is this a cpu access? */ - if (!(di_card->cntl_register & CNTL_PACK)) /* in unpacked mode? */ - data = data & ~(DATA_ATN | DATA_EOI) /* substitute the ATN/EOI tag values */ - | (tag & (TAG_ATN | TAG_EOI)) >> DATA_SHIFT; /* into the data word */ - - if (tag & TAG_LBR) /* is this the last byte? */ - di_card->eor = SET; /* set */ - else /* or clear */ - di_card->eor = CLEAR; /* the end-of-record flip-flop */ - } - -else if (access == bus_access) /* is this a bus access? */ - if (di_card->obp == upper) { /* is this the upper byte? */ - di_card->obp = lower; /* set the lower byte as next */ - data = GET_UPPER (data); /* mask and position the upper byte in the data word */ - remove_word = FALSE; /* do not unload the FIFO until the next byte */ - } - - else { /* this is the lower byte */ - data = GET_LOWER (data); /* mask and position it in the data word */ - - if (di_card->cntl_register & CNTL_PACK) /* is the card in the packed mode? */ - di_card->obp = upper; /* set the upper byte as next */ - } - -else /* must be a diagnostic access */ - data = GET_LOWER (data); /* access is to the lower byte only */ - - -if (remove_word) { /* remove the word from the FIFO? */ - di_card->fifo_reg->qptr = /* update the FIFO queue pointer */ - (di_card->fifo_reg->qptr + 1) % FIFO_SIZE; /* and wrap around as needed */ - - di_card->fifo_count = di_card->fifo_count - 1; /* decrement the FIFO count */ - } - - -if (DEBUG_PRJ (dptrs [card], DEB_BUF)) { - fprintf (sim_deb, ">>%s buf: Data %0*o tag ", - dptrs [card]->name, (access == cpu_access ? 6 : 3), data); - fprint_val (sim_deb, tag >> BUS_SHIFT, 2, 4, PV_RZRO); - fprintf (sim_deb, " unloaded from FIFO (%d)\n", di_card->fifo_count); - } - - -if (di_card->cntl_register & CNTL_TALK) /* is the card talking? */ - if (di_card->cntl_register & CNTL_PACK) /* is it in the packed mode? */ - if (di_card->status_register & STAT_LBO /* yes, is the last byte out? */ - && di_card->cntl_register & CNTL_EOI) /* and is EOI control enabled? */ - di_card->bus_cntl |= BUS_EOI; /* assert EOI on the bus */ - else - di_card->bus_cntl &= ~BUS_EOI; /* deny EOI on the bus */ - - else { /* the card is in the unpacked mode */ - if (di_card->cntl_register & CNTL_CIC) /* is the card the controller in charge? */ - di_card->bus_cntl = /* assert or deny the ATN bus line */ - di_card->bus_cntl & ~BUS_ATN /* from the ATN tag value */ - | (tag & TAG_ATN) >> BUS_SHIFT; - - di_card->bus_cntl = /* assert or deny the EOI bus line */ - di_card->bus_cntl & ~BUS_EOI /* from the EOI tag value */ - | (tag & TAG_EOI) >> BUS_SHIFT; - } - -return (uint16) data; /* return the data value */ -} - - -/* Print the bus state for debugging. - - The states of the supplied bus control lines are decoded and printed in - mnemonic form to the specified file using the indicated format string. An - asserted bus signal is indicated by its name; a denied signal is omitted. - - - Implementation notes: - - 1. The strings in the cntl_names array must appear in BUS_xxx order. The - first element corresponds to bus bit 0, etc. -*/ - -static void fprint_bus (FILE *file, char *format, uint8 cntl) -{ -static const char *cntl_names [] = { - "ATN", /* bit 0: attention */ - "EOI", /* bit 1: end or identify */ - "DAV", /* bit 2: data available */ - "NRFD", /* bit 3: not ready for data */ - "NDAC", /* bit 4: not data accepted */ - "REN", /* bit 5: remote enable */ - "IFC", /* bit 6: interface clear */ - "SRQ" /* bit 7: service request */ - }; - -uint32 signal; -char mnemonics [40]; - -if (cntl == 0) /* are any control signals asserted? */ - strcpy (mnemonics, "---"); /* no; use dashes in lieu of an empty string */ - -else { /* one or more signals are asserted */ - mnemonics [0] = '\0'; - - for (signal = 0; signal <= 7; signal++) /* loop though the set of signals */ - if (cntl & (1 << signal)) { /* is this signal asserted? */ - if (strlen (mnemonics) > 0) /* yes; is it the first one asserted? */ - strcat (mnemonics, " "); /* no, so append a space to separate */ - strcat (mnemonics, cntl_names [signal]); /* append the name of the asserted signal */ - } - } - -fprintf (file, format, mnemonics); /* print the bus state */ -return; -} +/* hp2100_di.c: HP 12821A HP-IB Disc Interface simulator + + Copyright (c) 2010-2014, J. David Bryan + + 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 + THE AUTHOR 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 the author shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from the author. + + DI 12821A Disc Interface + + 24-Dec-14 JDB Added casts for explicit downward conversions + Removed redundant global declarations + 13-Feb-12 JDB First release + 15-Dec-11 JDB Added dummy DC device for diagnostics + 09-Oct-10 JDB Created DI simulation + + References: + - HP 12821A Disc Interface Installation and Service Manual (12821-90006, + Feb-1985) + - IEEE Standard Digital Interface for Programmable Instrumentation + (IEEE-488A-1980, Sep-1979) + + + The 12821A was a high-speed implementation of the Hewlett-Packard Interface + Bus (HP-IB, formalized as IEEE Std. 488-1978). It was used to interface + HP-IB disc and tape devices, such as the HP 7906H, 7908A, and 7974A, to the + HP 1000 running RTE-IVB or RTE-6/VM. Three device command protocols were + supported by the I/O drivers: Amigo discs by driver DVA32, CS/80 discs by + DVM33, and Amigo tapes by DVS23. + + In an RTE environment, the 12821A was the system controller. While + electrically compatible with the HP-IB specification and capable of receiving + addressing commands from the bus, the 12821A did not use the full IEEE-488 + protocol. Card talker and listener states were set by bits in the control + register, rather than by receiving talk and listen commands over the bus. + The bus address of the card could be set via DIP switches, but this feature + was only used by the diagnostic. + + The card supported packed and unpacked transfers across the bus. Up to four + devices could be connected to each card; this limit was imposed by the + maximum electrical loading on the bus compatible with the high data rate. + + The 12821A had a 16-word FIFO buffer and could sustain DCPC transfers of one + megabyte per second. Burst transfers by the CPU to fill or empty the FIFO + could run at the full bandwidth of the I/O backplane. This could hold off + lower-priority devices for 10-15 microseconds until the card slowed down to + the rate of the disc or tape. + + Card assembly 12821-60003 was revised to add a DCPC pacing option. Placing + jumper W1 in position A inhibited SRQ for one I/O cycle in six to allow a + lower-priority interface card to transfer one word. Position B allowed SRQ + to assert continuously as it did on the earlier card assembly 12821-60001. + + The simulator is logically partitioned into three sets of functions: the + interface card simulation, the HP-IB bus simulation, and the device + simulation. This is the card simulation and the card portion of the HP-IB + simulation. Separate modules for the tape and disc devices contain the + device simulations and the device portions of the HP-IB simulations. + + This simulator is written to allow the definition of multiple DI cards in a + system. The RTE operating system provided separate I/O drivers for the Amigo + disc, Amigo tape, and CS/80 disc devices. As only one I/O driver could + control a given interface, separate interfaces were required if more than one + device class was installed. For example, it was not possible to control an + Amigo disc and an Amigo tape connected to the same interface card. + + + Implementation notes: + + 1. The simulator behaves as though card switches S1-S7 are initially closed, + providing a card bus address of 0. The address may be changed with the + SET ADDRESS=n command. Only addresses 0-7 are supported, and the + address may duplicate a device bus address without conflict, as the + address is only used during the diagnostic when devices are disconnected. + + 2. The simulator behaves as though card switch S8 is open, enabling the card + to be the system controller. This cannot be changed by the user. + + 3. The simulator behaves as though card jumper W1 (DCPC pacing) is in + position B. This currently cannot be changed by the user. +*/ + + + +#include "hp2100_defs.h" +#include "hp2100_di.h" + + + +/* Program constants */ + +#define SW8_SYSCTL 1 /* card is always the system controller (switch 8) */ + +#define IFC_TIMEOUT 157 /* 157 instructions = ~ 100 microseconds */ + +#define CONTROLLER 31 /* dummy unit number for DI */ + + +/* Character constants */ + +#define LF '\012' + + +/* Control Word Register */ + +#define CNTL_SRQ 0100000 /* enable service request interrupt */ +#define CNTL_IFC 0040000 /* assert IFC or enable IFC interrupt */ +#define CNTL_REN 0020000 /* assert remote enable */ +#define CNTL_IRL 0010000 /* enable input-register-loaded interrupt */ +#define CNTL_LBO 0004000 /* enable last-byte-out interrupt */ +#define CNTL_LF 0002000 /* enable line feed terminator */ +#define CNTL_EOI 0001000 /* assert end or identify */ +#define CNTL_ATN 0000400 /* assert attention */ +#define CNTL_DIAG 0000200 /* diagnostic loopback */ +#define CNTL_NRFD 0000100 /* assert not ready for data */ +#define CNTL_PPE 0000040 /* parallel poll enable */ +#define CNTL_ODD 0000020 /* odd number of bytes */ +#define CNTL_PACK 0000010 /* packed data transfer */ +#define CNTL_LSTN 0000004 /* listen */ +#define CNTL_TALK 0000002 /* talk */ +#define CNTL_CIC 0000001 /* controller in charge */ + + +/* Status Word Register */ + +#define STAT_SRQBUS 0100000 /* service request bus state */ +#define STAT_IFCBUS 0040000 /* interface clear bus state */ +#define STAT_RENBUS 0020000 /* remote enable bus state */ +#define STAT_IRL 0010000 /* input register loaded */ +#define STAT_LBO 0004000 /* last byte out */ +#define STAT_LBI 0002000 /* last byte in */ +#define STAT_EOIBUS 0001000 /* end or identify bus state */ +#define STAT_ATNBUS 0000400 /* attention bus state */ +#define STAT_IFC 0000200 /* interface clear seen */ +#define STAT_ODD 0000020 /* odd number of bytes */ +#define STAT_SYSCTL 0000010 /* system controller */ +#define STAT_LSTN 0000004 /* listener */ +#define STAT_TALK 0000002 /* talker */ +#define STAT_CIC 0000001 /* controller in charge */ + + +/* Data word */ + +#define DATA_LBO 0100000 /* last byte out */ +#define DATA_EOI 0001000 /* end or identify */ +#define DATA_ATN 0000400 /* attention */ + + +/* Tag word */ + +#define BUS_SHIFT 16 /* left shift count to align BUS_ATN, EOI with tag */ +#define DATA_SHIFT 8 /* left shift count to align DATA_ATN, EOI with tag */ + +#define TAG_ATN 0000200000 /* bit 16: attention */ +#define TAG_EOI 0000400000 /* bit 17: end or identify */ +#define TAG_EDT 0001000000 /* bit 18: end of data transfer */ +#define TAG_LBR 0002000000 /* bit 19: last byte received */ + +#define TAG_MASK (TAG_ATN | TAG_EOI | TAG_EDT | TAG_LBR) + + +/* FIFO access modes */ + +#define FIFO_EMPTY (di_card->fifo_count == 0) /* FIFO empty test */ +#define FIFO_FULL (di_card->fifo_count == FIFO_SIZE) /* FIFO full test */ + +typedef enum { + bus_access, /* per-byte access */ + cpu_access, /* per-word access */ + diag_access /* mixed access */ + } FIFO_ACCESS; + + +/* Disc interface state variables */ + +DI_STATE di [card_count]; /* per-card state */ + + +/* Disc interface local bus routines */ + +static t_bool di_bus_accept (CARD_ID card, uint8 data); +static void di_bus_respond (CARD_ID card, uint8 cntl); +static void di_bus_poll (CARD_ID card); + +/* Disc interface local utility routines */ + +static void master_reset (CARD_ID card); +static void update_state (CARD_ID card); +static void fifo_load (CARD_ID card, uint16 data, FIFO_ACCESS access); +static uint16 fifo_unload (CARD_ID card, FIFO_ACCESS access); +static void fprint_bus (FILE *file, char *format, uint8 cntl); + + + +/* Dummy DC device. + + This temporary dummy device allows the DI diagnostic to test inter-card + signals. Test 15 can only be performed if there are two DIs available. + + This device provides a second "bare" card. Normally, it is disabled and + cannot be enabled by the user. Enabling or disabling DIAG mode on the DA + device automatically enables or disables the DC device. The select code of + the DC device is fixed at 45B and cannot be changed. +*/ + +DIB dc_dib = { &di_io, DI_DC, dc }; + +REG dc_reg [] = { + { BRDATA (FIFO, di [dc].fifo, 8, 20, FIFO_SIZE), REG_CIRC }, /* needed for "qptr" */ + { NULL } + }; + +DEVICE dc_dev = { + "DC", /* device name */ + NULL, /* unit array */ + dc_reg, /* register array */ + NULL, /* modifier array */ + 0, /* number of units */ + 10, /* address radix */ + 31, /* address width */ + 1, /* address increment */ + 8, /* data radix */ + 8, /* data width */ + NULL, /* examine routine */ + NULL, /* deposit routine */ + &di_reset, /* reset routine */ + NULL, /* boot routine */ + NULL, /* attach routine */ + NULL, /* detach routine */ + &dc_dib, /* device information block */ + DEV_DEBUG | DEV_DIS, /* device flags */ + 0, /* debug control flags */ + di_deb, /* debug flag name table */ + NULL, /* memory size change routine */ + NULL }; /* logical device name */ + + + +/* DI data structures. + + *dptrs device pointers + *bus_accept device acceptor function pointers + *bus_respond device responder function pointers + + di_deb DI debug table + + The first three pointer arrays have elements that correspond one-for-one with + the supported devices. These allow the DI simulator to work with multiple + cards. The actual devices are defined in the individual device simulators. + + Note that the DC and MA devices are reserved for future use. Until one or + the other is fully implemented, a dummy DC device is provided above for use + by the diagnostic only. +*/ + +extern DEVICE da_dev; + +static DEVICE *dptrs [card_count] = { &da_dev, &dc_dev, NULL }; +static ACCEPTOR *bus_accept [card_count] = { &da_bus_accept, NULL, NULL }; +static RESPONDER *bus_respond [card_count] = { &da_bus_respond, NULL, NULL }; + + +DEBTAB di_deb [] = { + { "CPU", DEB_CPU }, + { "CMDS", DEB_CMDS }, + { "BUF", DEB_BUF }, + { "XFER", DEB_XFER }, + { "RWSC", DEB_RWSC }, + { "SERV", DEB_SERV }, + { NULL, 0 } + }; + + + +/* Disc interface global VM routines */ + + +/* I/O signal handler. + + The card has two input and two output registers. The Input Data Register and + Output Data Register are addressed when the control flip-flop is set. The + Status Word and the Control Word Register are addressed when the control + flip-flop is clear. The card has the usual control, flag buffer, flag, and + SRQ flip-flops, though flag and SRQ are decoupled to allow the full DCPC + transfer rate. + + In hardware, the presence of the card FIFO, which is necessary to obtain full + DCPC bandwidth, implies a delay between CPU actions, such as outputting the + last word in a data transfer, and device actions, such as accepting the last + word of a disc write. Four flip-flops are used to monitor FIFO status: + + - EDT (End of Data Transfer) + - LBO (Last Byte Out) + - LBI (Last Byte In) + - EOR (End of Record) + + The EDT signal indicates that the final data word of a transfer is being + written to the FIFO. The flip-flop is set by the EDT backplane signal when + the last cycle of a DCPC transfer is executing, or during programmed output + transfers when CLF does not accompany IOO in packed mode, or when bit 15 of + the data word is set in unpacked mode. It remains set until it is cleared by + a master reset. The output of the EDT flip-flop drives the EDT tag input of + the FIFO. + + The LBO signal indicates that the final data byte of a transfer has been + sourced to the bus. The flip-flop is set when the last byte of the entry + tagged with EDT has been unloaded from the FIFO. It is cleared by a master + reset or when an entry not tagged with EDT is unloaded. The output of the + LBO flip-flop drives the LBO bit in the Status Word. + + The LBI signal indicates that the final byte of an input transfer has been + accepted from the bus. The flip-flop is set when a byte tagged with EOI is + received and the EOI bit in the control register is set, or a line-feed byte + is received and the LF bit in the control register is set. It is cleared by + a master reset or when neither of these conditions is true. The input of the + LBI flip-flop also drives the LBR (last byte received) tag input of the FIFO, + and the output of the flip-flop drives the LBI bit in the Status Word. + + The EOR signal indicates that the final data word of a transfer is available + in the Input Data Register. The flip-flop is set when the last byte of the + entry tagged with LBR has been unloaded from the FIFO and written to the IDR. + It is cleared by a master reset or when an entry not tagged with LBR is + unloaded and written to the IDR. The output of the EOR flip-flop sets the + flag flip-flop when the IDR is unloaded. + + + Implementation notes: + + 1. In hardware, the Status Word consists of individual flip-flops and status + signals that are enabled onto the I/O backplane. In simulation, the + individual status values are collected into a Status Word Register, and + the Output Data Register does not exist (output data is written directly + to the FIFO buffer). + + 2. The DIAG, T, and L control bits enable a data loopback path on the card. + An IOO issued to the card unloads a word from the FIFO and then loads the + lower byte back into both bytes of the FIFO. The data word output with + the IOO instruction is not used. + + In hardware, IOO triggers the FIFO unload and reload; T and L are + required only for the loopback path. If L is not asserted, then the FIFO + is loaded with 177777 due to the floating bus. If L is asserted and T is + not, then the FIFO is loaded with 000000 due to pullups on the DIO lines. + In simulation, we look only for DIAG and assume that T/L are set + properly, i.e., unloaded data is reloaded. + + 3. In hardware, the SRQ and NRFD lines are open-collector and may be driven + simultaneously from several bus devices. Simulating this fully would + require keeping the state of the lines for each device and deriving the + common bus signals from the logical OR of the state values. Fortunately, + some simplifications are possible. + + The DI asserts SRQ only if control word bit 15 is 1 and bit 0 is 0. + Other bit combinations deny SRQ; as neither the Amigo nor CS/80 protocols + use SRQ and serial polls, there will be no other driver. + + In hardware, every listener drives NRFD, but in practice there is only + one listener at a time. When the card is the listener, it asserts NRFD + if the FIFO becomes full. In simulation, we assert NRFD on the bus if + NRFD is set in the control register, or we are listening and the FIFO is + full. We deny NRFD if NRFD had been set in the control register but is + no longer, or if we had been a listener but are no longer. That is, we + assume that if we have forced NRFD or set it as a listener, then no one + else will be asserting NRFD, so it's safe for us to deny NRFD when the + override is removed or we are no longer a listener. + + We also deny NRFD when a CRS is issued if NRFD had been explicitly + requested or the card had been listening. The rationale is the same: + only a listener can assert NRFD, so if we were listening, it's safe to + deny it, because only we could have set it. + + 4. In hardware, the IRL, LBO, LBI, and IFC status bits are driven by + corresponding flip-flops. In simulation, the status bits themselves hold + the equivalent states and are set and cleared as indicated. + + 5. The card state must be updated during status read (IOI) processing + because the 7974 boot ROM watches the IFC line to determine when IFC + assertion ends. + + 6. DCPC performance is optimized by recognizing that the normal cases (an + input that empties the FIFO or an output that fills the FIFO) do not + alter the card state, and so the usual update_state call may be omitted. + + 7. The gcc compiler (at least as of version 4.6.2) does not optimize + repeated use of array-of-structures accesses. Instead, it recalculates + the index each time, even though the index is a constant within the + function. To avoid this performance penalty, we use a pointer to the + selected DI_STATE structure. Note that VC++ 2008 does perform this + optimization. +*/ + + +uint32 di_io (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) +{ +static const char * const output_state [] = { "Control", "Data" }; +static const char * const input_state [] = { "Status", "Data" }; + +const char * const hold_or_clear = (signal_set & ioCLF ? ",C" : ""); +const CARD_ID card = (CARD_ID) (dibptr->card_index); +DI_STATE * const di_card = &di [card]; + +uint8 assert, deny; /* new bus control states */ +uint16 data; +t_bool update_required = TRUE; /* TRUE if CLF must update the card state */ + +IOSIGNAL signal; +IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ + +while (working_set) { + signal = IONEXT (working_set); /* isolate the next signal */ + + switch (signal) { /* dispatch an I/O signal */ + + case ioCLF: /* clear flag flip-flop */ + di_card->flag = CLEAR; /* clear the flag */ + di_card->flagbuf = CLEAR; /* and flag buffer */ + + if (DEBUG_PRJ (dptrs [card], DEB_CMDS)) + fprintf (sim_deb, ">>%s cmds: [CLF] Flag cleared\n", + dptrs [card]->name); + + if (update_required) /* if the card state has changed */ + update_state (card); /* then update the state */ + break; + + + case ioSTF: /* set flag flip-flop */ + if (DEBUG_PRJ (dptrs [card], DEB_CMDS)) + fprintf (sim_deb, ">>%s cmds: [STF] Flag set\n", + dptrs [card]->name); + + /* fall into ENF handler */ + + case ioENF: /* enable flag */ + di_card->flag = SET; /* set the flag */ + di_card->flagbuf = SET; /* and flag buffer */ + break; + + + case ioSFC: /* skip if flag is clear */ + setstdSKF (di [card]); + break; + + + case ioSFS: /* skip if flag is set */ + setstdSKF (di [card]); + break; + + + case ioIOI: /* I/O data input */ + if (di_card->control == SET) { /* is the card in data mode? */ + data = di_card->input_data_register; /* read the input data register */ + di_card->status_register &= ~STAT_IRL; /* clear the input register loaded status */ + + if (FIFO_EMPTY && di_card->eor == CLEAR) { /* is the FIFO empty and end of record not seen? */ + if (di_card->srq == SET && DEBUG_PRJ (dptrs [card], DEB_CMDS)) + fprintf (sim_deb, ">>%s cmds: SRQ cleared\n", + dptrs [card]->name); + + di_card->srq = CLEAR; /* clear SRQ */ + update_required = FALSE; /* the card state does not change */ + } + } + + else { /* the card is in status mode */ + di_card->status_register &= /* clear the values to be computed, */ + STAT_IRL | STAT_LBO /* preserving those set elsewhere */ + | STAT_LBI | STAT_IFC; + + di_card->status_register |= /* set T/L/C status from control register */ + di_card->cntl_register /* (T/L are ORed, as MTA or MLA can also set) */ + & (CNTL_CIC | CNTL_TALK | CNTL_LSTN); + + + if (SW8_SYSCTL) /* if SW8 is set, */ + di_card->status_register |= STAT_SYSCTL; /* the card is the system controller */ + + if (di_card->ibp == lower) /* if lower byte input is next */ + di_card->status_register |= STAT_ODD; /* then the last transfer was odd */ + + di_card->status_register |= /* set the bus status bits */ + (di_card->bus_cntl /* from the corresponding bus control lines */ + & (BUS_SRQ | BUS_IFC | BUS_REN + | BUS_EOI | BUS_ATN)) << DATA_SHIFT; + + data = di_card->status_register; /* return the status word */ + } + + if (DEBUG_PRJ (dptrs [card], DEB_CPU)) + fprintf (sim_deb, ">>%s cpu: [LIx%s] %s = %06o\n", + dptrs [card]->name, hold_or_clear, + input_state [di_card->control], data); + + if (update_required && !(signal_set & ioCLF)) /* if an update is required and CLF is not present, */ + update_state (card); /* update the state, else ioCLF will update it */ + + stat_data = IORETURN (SCPE_OK, data); /* merge in the return status */ + break; + + + case ioIOO: /* I/O data output */ + data = IODATA (stat_data); /* get the data value */ + + if (DEBUG_PRJ (dptrs [card], DEB_CPU)) + fprintf (sim_deb, ">>%s cpu: [OTx%s] %s = %06o\n", + dptrs [card]->name, hold_or_clear, + output_state [di_card->control], data); + + if (di_card->control == SET) { /* is the card in data mode? */ + if (signal_set & ioEDT) /* if end of DCPC transfer */ + di_card->edt = SET; /* set the EDT flip-flop */ + + else if (di_card->cntl_register & CNTL_PACK) { /* is this a packed transfer? */ + if (!(signal_set & ioCLF)) /* and CLF not given? */ + di_card->edt = SET; /* set the EDT flip-flop */ + } + + else /* it's an unpacked transfer */ + if (data & DATA_LBO) /* is the last byte out? */ + di_card->edt = SET; /* set the EDT flip-flop */ + + if (di_card->cntl_register & CNTL_DIAG) { /* set for DIAG loopback? */ + data = fifo_unload (card, diag_access); /* unload data from the FIFO */ + fifo_load (card, data, diag_access); /* and load it back in */ + } + + else { /* the card is set for normal operation */ + fifo_load (card, data, cpu_access); /* load the data word into the FIFO */ + + if (FIFO_FULL && (di_card->bus_cntl & BUS_NRFD)) { /* FIFO full and listener not ready? */ + if (di_card->srq == SET && DEBUG_PRJ (dptrs [card], DEB_CMDS)) + fprintf (sim_deb, ">>%s cmds: SRQ cleared\n", + dptrs [card]->name); + + di_card->srq = CLEAR; /* clear SRQ */ + update_required = FALSE; /* the card state does not change */ + } + } + } + + else { /* the card is in control mode */ + assert = 0; /* initialize bus control assertions */ + deny = 0; /* and denials */ + + if (!(data & CNTL_PACK)) /* unpacked mode always sets */ + di_card->ibp = di_card->obp = lower; /* byte selectors to the lower byte */ + + if (data & CNTL_TALK) { /* talking enables ATN and EOI outputs */ + if ((data & (CNTL_PPE | CNTL_CIC)) /* if parallel poll is enabled */ + == (CNTL_PPE | CNTL_CIC)) /* and the card is CIC */ + assert = BUS_PPOLL; /* then conduct a parallel poll */ + + else if ((di_card->cntl_register /* if PP was enabled */ + & (CNTL_PPE | CNTL_CIC)) /* but is not now */ + == (CNTL_PPE | CNTL_CIC)) + deny = BUS_PPOLL; /* then end the parallel poll */ + + else if ((data /* if packed mode */ + & (CNTL_PACK | CNTL_CIC | CNTL_ATN)) /* and the card is CIC */ + == (CNTL_PACK | CNTL_CIC | CNTL_ATN)) /* then the ATN control output */ + assert = BUS_ATN; /* is coupled to the bus */ + + else /* if none of the above */ + deny = BUS_ATN; /* then ATN is not driven */ + } + + else /* the card is not talking */ + deny = BUS_ATN | BUS_EOI; /* so ATN and EOI are disabled */ + + + if (data & CNTL_NRFD) /* is card not ready set explicitly? */ + assert |= BUS_NRFD; /* assert NRFD on the bus */ + + else if (di_card->cntl_register & CNTL_NRFD) /* NRFD was set but is not now? */ + deny |= BUS_NRFD; /* deny NRFD on the bus */ + + if (FIFO_FULL) /* is the FIFO full? */ + if (data & CNTL_LSTN) /* is card now listening? */ + assert |= BUS_NRFD; /* listener and a full FIFO asserts NRFD */ + + else if (di_card->cntl_register & CNTL_LSTN) /* was card a listener but is not now? */ + deny |= BUS_NRFD; /* deny NRFD on the bus */ + + + if (SW8_SYSCTL) { /* system controller drives REN and IFC */ + if (data & CNTL_REN) /* REN control */ + assert |= BUS_REN; /* output is */ + else /* coupled to */ + deny |= BUS_REN; /* the bus */ + + if (data & CNTL_IFC) { /* is IFC set? */ + assert |= BUS_IFC; /* assert IFC on the bus */ + + di_card->status_register = + di_card->status_register + & ~(STAT_LSTN | STAT_TALK) /* clear listen and talk status */ + | STAT_IFC; /* and set IFC status */ + + di_card->ifc_timer = /* start the IFC timer by calculating */ + sim_gtime () + IFC_TIMEOUT; /* the IFC stop time (now + 100 microseconds) */ + } + } + + if ((data & (CNTL_SRQ | CNTL_CIC)) == CNTL_SRQ) /* if service request and not the controller */ + assert |= BUS_SRQ; /* then assert SRQ on the bus */ + else /* else */ + deny |= BUS_SRQ; /* deny SRQ on the bus */ + + di_card->cntl_register = data; /* save the control word */ + di_bus_control (card, CONTROLLER, assert, deny); /* update the bus control state */ + } + + if (update_required && !(signal_set & ioCLF)) /* if update required and CLF is not present, */ + update_state (card); /* update the state, else ioCLF will update it */ + break; + + + case ioPOPIO: /* power-on preset to I/O */ + di_card->flag = SET; /* set the flag */ + di_card->flagbuf = SET; /* and flag buffer */ + + if (DEBUG_PRJ (dptrs [card], DEB_CMDS)) + fprintf (sim_deb, ">>%s cmds: [POPIO] Flag set\n", + dptrs [card]->name); + break; + + + case ioCRS: /* control reset */ + if (DEBUG_PRJ (dptrs [card], DEB_CMDS)) + fprintf (sim_deb, ">>%s cmds: [CRS] Master reset\n", + dptrs [card]->name); + + di_card->status_register &= /* clear listen and talk status */ + ~(STAT_LSTN | STAT_TALK); + + deny = BUS_SRQ | BUS_REN | BUS_ATN | BUS_EOI; /* clear the lines driven by the control register */ + + if (di_card->cntl_register & (CNTL_NRFD | CNTL_LSTN)) /* if asserting NRFD or listening */ + deny |= BUS_NRFD; /* then deny because we're clearing */ + + di_card->cntl_register = 0; /* clear the control word register */ + di_card->control = CLEAR; /* clear control */ + di_card->srq = CLEAR; /* clear SRQ */ + + master_reset (card); /* perform a master reset */ + + di_bus_control (card, CONTROLLER, 0, deny); /* update the bus control state */ + update_state (card); /* update the card state */ + break; + + + case ioCLC: /* clear control flip-flop */ + di_card->control = CLEAR; /* clear control */ + + if (DEBUG_PRJ (dptrs [card], DEB_CMDS)) { + fprintf (sim_deb, ">>%s cmds: [CLC%s] Control cleared (configure mode)", + dptrs [card]->name, hold_or_clear); + + if (signal_set & ioCLF) /* if ioCLF is given, */ + fputs (", master reset\n", sim_deb); /* then report a master reset */ + else + fputc ('\n', sim_deb); + } + + if (signal_set & ioCLF) /* if ioCLF is given, */ + master_reset (card); /* then do a master reset */ + break; /* (ioCLF will call update_state for us) */ + + + case ioSTC: /* set control flip-flop */ + di_card->control = SET; /* set control */ + + if (DEBUG_PRJ (dptrs [card], DEB_CMDS)) + fprintf (sim_deb, ">>%s cmds: [STC%s] Control set (data mode)\n", + dptrs [card]->name, hold_or_clear); + break; + + + case ioEDT: /* end data transfer */ + if (DEBUG_PRJ (dptrs [card], DEB_CPU)) + fprintf (sim_deb, ">>%s cpu: [EDT] DCPC transfer ended\n", + dptrs [card]->name); + break; + + + case ioSIR: /* set interrupt request */ + setstdPRL (di [card]); /* set the standard PRL signal */ + setstdIRQ (di [card]); /* set the standard IRQ signal */ + + setSRQ (dibptr->select_code, /* set the SRQ signal if control and SRQ are set */ + di_card->srq == SET && di_card->control == SET); + break; + + + case ioIAK: /* interrupt acknowledge */ + di_card->flagbuf = CLEAR; /* clear the flag buffer */ + break; + + + default: /* all other signals */ + break; /* are ignored */ + } + + working_set = working_set & ~signal; /* remove the current signal from the set */ + } + +return stat_data; +} + + +/* Reset the simulator. + + During a hardware PRESET, POPIO sets the flag buffer and flag flip-flops, and + CRS clears the control flip-flop and Control Word Register. In addition, CRS + performs a master reset on the card. + + PON is not used by the card. + + + Implementation notes: + + 1. During a power-on reset, a pointer to the FIFO simulation register is + saved to allow access to the "qptr" field during FIFO loading and + unloading. This enables SCP to view the FIFO as a circular queue, so + that the bottom word of the FIFO is always displayed as FIFO[0], + regardless of where it is in the actual FIFO array. +*/ + +t_stat di_reset (DEVICE *dptr) +{ +DIB *dibptr = (DIB *) dptr->ctxt; /* get the DIB pointer */ +const CARD_ID card = (CARD_ID) (dibptr->card_index); /* get the card number */ + +if (sim_switches & SWMASK ('P')) { /* is this a power-on reset? */ + di [card].fifo_reg = find_reg ("FIFO", NULL, dptr); /* find the FIFO register entry */ + + if (di [card].fifo_reg == NULL) /* if not there */ + return SCPE_IERR; /* then this is a programming error! */ + else /* found it */ + di [card].fifo_reg->qptr = 0; /* so reset the FIFO bottom index */ + + di [card].status_register = 0; /* clear the status word */ + + di [card].bus_cntl = 0; /* deny the HP-IB control lines */ + + di [card].listeners = 0; /* clear the map of listeners */ + di [card].talker = 0; /* clear the map of talker */ + di [card].poll_response = 0; /* clear the map of parallel poll responses */ + + di [card].ifc_timer = 0.0; /* clear the IFC timer */ + } + +IOPRESET (dibptr); /* PRESET the device */ + +return SCPE_OK; +} + + + +/* Disc interface global SCP routines */ + + +/* Set a unit's bus address. + + Bus addresses range from 0-7 and are initialized to the unit number. All + units of a device must have unique bus addresses. In addition, the card also + has a bus address, although this is only used for the diagnostic. The card + address may be the same as a unit address, as all units are disconnected + during a diagnostic run. + + The "value" parameter indicates whether the routine is setting a unit's bus + address (0) or a card's bus address (1). + + + Implementation notes: + + 1. To ensure that each address is unique, a check is made of the other units + for conflicting addresses. An "invalid argument" error is returned if + the desired address duplicates another. This means that addresses cannot + be exchanged without first assigning one of them to an unused address. + Also, an address cannot be set that duplicates the address of a disabled + unit (which cannot be displayed without enabling it). + + An alternate implementation would be to set the new assignments into a + "shadow array" that is set into the unit flags (and checked for validity) + only when a power-on reset is done. This would follow the disc and tape + controller hardware, which reads the HP-IB address switch settings only + at power-up. +*/ + +t_stat di_set_address (UNIT *uptr, int32 value, char *cptr, void *desc) +{ +t_stat status; +uint32 index, new_address; +uint32 old_address = GET_BUSADR (uptr->flags); +DEVICE *dptr = (DEVICE *) desc; + +if (cptr == NULL) /* if the address is not given */ + return SCPE_ARG; /* report a missing argument */ + +new_address = (uint32) get_uint (cptr, 10, 7, &status); /* parse the address value */ + +if (status == SCPE_OK) { /* is the parse OK? */ + if (value) /* are we setting the card address? */ + dptr->flags = dptr->flags & ~DEV_BUSADR /* store the new address in the device flags */ + | SET_DIADR (new_address); + + else { /* we are setting a unit address */ + for (index = 0; index < dptr->numunits; index++) /* look through the units */ + if (new_address != old_address /* to ensure that the address is unique */ + && new_address == GET_BUSADR (dptr->units [index].flags)) { + printf ("Bus address conflict: DA%d\n", index); + + if (sim_log) + fprintf (sim_log, "Bus address conflict: DA%d\n", index); + + return SCPE_NOFNC; /* a duplicate address gives an error */ + } + + uptr->flags = uptr->flags & ~UNIT_BUSADR /* the address is valid; change it */ + | SET_BUSADR (new_address); /* in the unit flags */ + } + } + +return status; /* return the result of the parse */ +} + + +/* Show a unit's bus address. + + The "value" parameter indicates whether the routine is showing a unit's bus + address (0) or a card's bus address (1). +*/ + +t_stat di_show_address (FILE *st, UNIT *uptr, int32 value, void *desc) +{ +DEVICE *dptr = (DEVICE *) desc; + +if (value) /* do we want the card address? */ + fprintf (st, "address=%d", GET_DIADR (dptr->flags)); /* get it from the device flags */ +else /* we want the unit address */ + fprintf (st, "bus=%d", GET_BUSADR (uptr->flags)); /* get it from the unit flags */ + +return SCPE_OK; +} + + +/* Set the bus cable connection. + + In normal use, the various tape and disc devices are connected together and + to the disc interface card by HP-IB cables. For the diagnostic, two disc + interface cards are connected by a single cable. + + The "value" parameter indicates whether the routine is connecting the + cable to devices for normal use (0) or to another card for diagnostics (1). + + + Implementation notes: + + 1. Initially, only one card and peripheral set is simulated: the ICD disc + family (DA device). For diagnostic use, a second, dummy card is enabled + (DC device). Once a second card simulation is implemented, this code + will no longer be necessary. +*/ + +t_stat di_set_cable (UNIT *uptr, int32 value, char *cptr, void *desc) +{ +if (value) { /* is the diagnostic cable selected? */ + ((DEVICE *) desc)->flags |= DEV_DIAG; /* set the diagnostic flag */ + dc_dev.flags &= ~DEV_DIS; /* enable the dummy device */ + dc_dev.flags |= DEV_DIAG; /* and set its flag as well */ + } +else { /* the peripheral cable is selected */ + ((DEVICE *) desc)->flags &= ~DEV_DIAG; /* clear the diagnostic flag */ + dc_dev.flags |= DEV_DIS; /* disable the dummy device */ + dc_dev.flags &= ~DEV_DIAG; /* and clear its flag */ + } + +return SCPE_OK; +} + + +/* Show the bus cable connection. + + The "value" parameter indicates whether the cable is connected to devices for + normal use (0) or to another card for diagnostics (1). +*/ + +t_stat di_show_cable (FILE *st, UNIT *uptr, int32 value, void *desc) +{ +if (((DEVICE *) desc)->flags & DEV_DIAG) /* is the cable connected for diagnostics? */ + fputs ("diagnostic cable", st); /* report it */ +else /* the cable is connected for device use */ + fputs ("HP-IB cable", st); /* report the condition */ + +return SCPE_OK; +} + + + +/* Disc interface global bus routines. + + In hardware, the HP-IB bus consists of eight control lines and eight data + lines. Signals are asserted on the control lines to establish communication + between a source and one or more acceptors. For commands, the source is + always the controller (the 12821A card), and the acceptors are all of the + connected devices. For data, the source is the current talker, and the + acceptors are one or more current listeners. A three-wire interlocking + handshake enables communication at the rate of the slowest of the multiple + acceptors. The controller conducts a parallel poll by asserting ATN and EOI + together. Devices whose parallel poll responses are enabled each assert one + of the data lines to indicate that service is required. + + In simulation, a disabled or detached unit logically is not connected to the + bus. The card maintains a bitmap of acceptors (all devices currently + attached), listeners (all devices currently addressed to listen), the talker + (the device currently addressed to talk), and the enabled parallel poll + responses. Changes in control line state are communicated to all acceptors + via control/respond function calls, and data is exchanged between talker and + listeners via source/acceptor function calls. Data bytes are sent to all + current listeners in bus-address order. The card conducts a parallel poll by + checking the response bitmap; devices must set and clear their poll responses + appropriately in advance of the poll. + + Not all of the HP-IB control lines are simulated. The DAV and NDAC handshake + lines are never asserted; instead, they are simulated by the bus source + function calling one or more bus acceptor functions. SRQ and REN are + asserted as directed by the system controller but are not otherwise used (no + HP disc or tape devices assert SRQ or respond to REN). IFC, ATN, EOI, and + NRFD are asserted and tested by the controller and devices. In particular, + asserting NRFD will hold off a pending data transmission until it is denied. + + The functions that simulate the HP-IB (where "*" is "di", "da", etc.) are: + + di_bus_source -- Source a data byte to the bus. Returns TRUE if the + byte was accepted (i.e., there were one or more + listeners) and FALSE if it was not. Called by the + controller to send commands to devices, and called by + the current talker to send data to the listener(s). ATN + and EOI should be asserted as required on the bus before + calling. + + *_bus_accept -- Accept a data byte from the bus. Returns TRUE if the + byte was accepted and FALSE if it was not. Called by + di_bus_source to handshake between source and acceptor. + If ATN is asserted on the bus, the byte is a command; + otherwise, it is data. If EOI is asserted for a data + byte, it is the last byte of a transmission. + + di_bus_control -- Set the control lines on the bus. Called by the system + controller to assert or deny REN or IFC, by the current + controller to assert or deny SRQ, NRFD, or ATN and EOI + (to conduct or conclude a parallel poll), and by the + current listener to assert or deny NRFD. All connected + devices on the bus are notified of the changes. It is + not necessary to call di_bus_control for changes to ATN + and EOI that accompany a command or data byte. + + *_bus_respond -- Respond to changes in the control lines on the bus. + Called by di_bus_control to inform each connected device + of a change in control state. + + di_poll_response -- Set a device's poll response. Called by a device to + enable or disable its response to a future parallel + poll. +*/ + + +/* Source a byte to the bus. + + This routine is called to send bytes to devices on the bus connected to the + specified card. If the card is in diagnostic mode, which simulate two cards + connected by an HP-IB cable, then the byte is sent to another card in the + card cage that is also in diagnostic mode and enabled to receive. If the + card is not in diagnostic mode, then the byte is sent to all acceptors (if a + command) or to all listeners (if data) on the bus. + + The return value indicates whether or not there were any acceptors on the + bus. + + + Implementation notes: + + 1. If the responses from a previously conducted parallel poll are not + cleared from the FIFO before enabling the card to transmit, the card will + appear to conduct a new parallel poll because the FIFO tags cause ATN and + EOI to be asserted. This "fake" parallel poll is ignored (a real + parallel poll does not source data onto the bus). +*/ + +t_bool di_bus_source (CARD_ID card, uint8 data) +{ +CARD_ID other; +uint32 acceptors, unit; +t_bool accepted = FALSE; + +if (DEBUG_PRJ (dptrs [card], DEB_XFER)) { + fprintf (sim_deb, ">>%s xfer: HP-IB DIO %03o available ", dptrs [card]->name, data); + fprint_bus (sim_deb, "[%s]\n", di [card].bus_cntl); + } + +if (dptrs [card]->flags & DEV_DIAG) /* is this a diagnostic run? */ + for (other = first_card; other <= last_card; other++) { /* look through the list of cards */ + if (other != card && dptrs [other] /* for the other card */ + && (dptrs [other]->flags & DEV_DIAG) /* that is configured for diagnostic mode */ + && (di [other].cntl_register & CNTL_LSTN)) /* and is listening */ + accepted = di_bus_accept (other, data); /* call the interface acceptor for the other card */ + } + +else if ((di [card].bus_cntl & BUS_PPOLL) != BUS_PPOLL) { /* this is a normal run; not a fake poll? */ + if (di [card].cntl_register & CNTL_LSTN) /* is the card a listener? */ + accepted = di_bus_accept (card, data); /* call the interface acceptor for this card */ + + acceptors = di [card].acceptors; /* get the map of acceptors */ + + if (!(di [card].bus_cntl & BUS_ATN) /* if a data transfer, */ + || (data & BUS_COMMAND) == BUS_ACG) /* or an addressed command, e.g., SDC */ + acceptors = di [card].listeners; /* then limit just to listeners */ + + for (unit = 0; acceptors; unit++) { /* loop through the units */ + if (acceptors & 1) /* is the current unit accepting? */ + accepted |= (*bus_accept [card]) (unit, data); /* call the acceptor for this card */ + + acceptors = acceptors >> 1; /* move to the next acceptor */ + } + } + +if (DEBUG_PRJ (dptrs [card], DEB_XFER) && !accepted) + fprintf (sim_deb, ">>%s xfer: HP-IB no acceptors\n", + dptrs [card]->name); + +return accepted; +} + + +/* Assert or deny control on the bus. + + This routine is called by the indicated unit to assert or deny the HP-IB + control lines on the bus connected to the specified card. Separate sets of + signals to assert and deny are provided. + + If the bus state after modification did not change, the routine returns with + no further action. Otherwise, if the card is in diagnostic mode, then + notification of the bus change is sent to another card in the card cage that + is also in diagnostic mode. + + If the card is not in diagnostic mode, then the set of control lines that + are changing is checked to determine whether notification is necessary. If + not, then the change is not broadcast to improve performance. However, if + notification is required, then all acceptors on the bus are informed of the + change. + + + Implementation notes: + + 1. If a signal is asserted and denied in the same call, the assertion takes + precedence. + + 2. Of the sixteen potential control line state changes, only IFC assertion + and ATN and NRFD denial must be broadcast. Asserting IFC unaddresses all + devices, and denying ATN or NRFD allows a waiting talker to source a data + byte to the bus. Devices do not act upon the remaining thirteen state + changes, and a considerable performance improvement is obtained by + omitting the notification calls. + + 3. All control line state notifications are sent in diagnostic mode, as the + responses of the other card are specifically tested by the diagnostic. + + 4. Asserting ATN and EOI will conduct a parallel poll. Devices are not + notified of the poll. Instead, the previously stored parallel poll + responses will be used. +*/ + +#define ASSERT_SET (BUS_IFC) +#define DENY_SET (BUS_ATN | BUS_NRFD) + +void di_bus_control (CARD_ID card, uint32 unit, uint8 assert, uint8 deny) +{ +CARD_ID other; +uint32 acceptors, responder; +t_bool responded; +uint8 new_state, new_assertions, new_denials; + +new_state = di [card].bus_cntl & ~deny | assert; /* set up the new control state */ + +if (new_state == di [card].bus_cntl) /* if the control state did not change */ + return; /* return now */ + +new_assertions = ~di [card].bus_cntl & assert; /* get the changing assertions */ +new_denials = di [card].bus_cntl & deny; /* get the changing denials */ + +di [card].bus_cntl = new_state; /* establish the new control state */ + +if (DEBUG_PRJ (dptrs [card], DEB_XFER)) { + if (unit == CONTROLLER) + fprintf (sim_deb, ">>%s xfer: HP-IB card %d", dptrs [card]->name, card); + else + fprintf (sim_deb, ">>%s xfer: HP-IB address %d", + dptrs [card]->name, GET_BUSADR (dptrs [card]->units [unit].flags)); + + if (new_assertions) + fprint_bus (sim_deb, " asserted [%s]", new_assertions); + + if (new_denials) + fprint_bus (sim_deb, " denied [%s]", new_denials); + + fprint_bus (sim_deb, ", bus is [%s]\n", new_state); + } + +if ((dptrs [card]->flags & DEV_DIAG) /* is the card in diagnostic mode? */ + || (new_assertions & ASSERT_SET) /* or are changed signals in the */ + || (new_denials & DENY_SET)) { /* set that must be broadcast? */ + responded = FALSE; /* assume no response was received */ + + if (dptrs [card]->flags & DEV_DIAG) { /* is this a diagnostic run? */ + for (other = first_card; other <= last_card; other++) /* look through the list of cards */ + if (other != card && dptrs [other] /* for the other card */ + && (dptrs [other]->flags & DEV_DIAG)) { /* that is configured for diagnostic */ + di_bus_respond (other, new_state); /* notify the other card of the new control state */ + responded = TRUE; /* and note that there was a responder */ + } + } + + else { /* this is a normal run */ + update_state (card); /* update the card for the new control state */ + + acceptors = di [card].acceptors; /* get the map of acceptors */ + responded = (acceptors != 0); /* set response if there are any acceptors */ + + for (responder = 0; acceptors; responder++) { /* loop the through units */ + if ((acceptors & 1) && responder != unit) /* is the current unit accepting? */ + (*bus_respond [card]) (card, responder, new_state); /* call the responder for this card */ + + acceptors = acceptors >> 1; /* move to the next acceptor */ + } + } + + if (DEBUG_PRJ (dptrs [card], DEB_XFER) & !responded) + fprintf (sim_deb, ">>%s xfer: HP-IB no responders\n", + dptrs [card]->name); +} + +if ((new_state & BUS_PPOLL) == BUS_PPOLL) /* was a parallel poll requested? */ + di_bus_poll (card); /* conduct the poll */ + +return; +} + + +/* Enable or disable a unit's parallel poll response. + + The poll response for a unit connected to a specified card is set or cleared + as indicated. If a parallel poll is in progress when a poll response is set, + the poll is conducted again to reflect the new response. +*/ + +void di_poll_response (CARD_ID card, uint32 unit, FLIP_FLOP response) +{ +const uint32 address = GET_BUSADR (dptrs [card]->units [unit].flags); +uint32 previous_response = di [card].poll_response; + +if (response == SET) { /* enable the poll response? */ + di [card].poll_response |= PPR (address); /* set the response bit */ + + if ((di [card].bus_cntl & BUS_PPOLL) == BUS_PPOLL) /* is a parallel poll in progress? */ + di_bus_poll (card); /* conduct again with the new response */ + } +else /* disable the poll response */ + di [card].poll_response &= ~PPR (address); /* by clearing the response bit */ + +if (DEBUG_PRJ (dptrs [card], DEB_XFER) + && previous_response != di [card].poll_response) + fprintf (sim_deb, ">>%s xfer: HP-IB address %d parallel poll response %s\n", + dptrs [card]->name, address, (response == SET ? "enabled" : "disabled")); + +return; +} + + + +/* Disc interface local bus routines */ + + +/* Conduct a parallel poll on the bus. + + A controller asserting ATN and EOI simultaneously on the bus is conducting a + parallel poll. In hardware, each device whose poll response is enabled + asserts the data line corresponding to its bus address. The controller + terminates the poll by denying ATN and EOI. + + Setting the CIC (controller in charge) and PPE (parallel poll enable) bits in + the Control Word Register direct the disc interface to conduct a poll. + Setting PPE without CIC enables the poll response for the interface. + + In the diagnostic mode, one card is set to conduct the poll, and the other is + set to respond to it. In the normal mode, connected devices have set or + cleared their respective poll responses before this routine is called. + + + Implementation notes: + + 1. The card hardware fills the upper and lower bytes of the FIFO with the + response byte. In simulation, we use the diag_access mode to do the same + thing (diagnostic loopback also fills both bytes with the lower byte). +*/ + +static void di_bus_poll (CARD_ID card) +{ +CARD_ID other; +uint8 response; + +if ((di [card].cntl_register + & (CNTL_PPE | CNTL_CIC)) == CNTL_PPE) /* is the card's poll response enabled? */ + response = di [card].poll_response /* add the card's response */ + | PPR (GET_DIADR (dptrs [card]->flags)); /* to the devices' responses */ +else + response = di [card].poll_response; /* the card response is disabled, so just use devices */ + +if (dptrs [card]->flags & DEV_DIAG) /* is this a diagnostic run? */ + for (other = first_card; other <= last_card; other++) /* look through the list of cards */ + if (other != card && dptrs [other] /* for another card */ + && (dptrs [other]->flags & DEV_DIAG) /* that is configured for the diagnostic */ + && (di [other].cntl_register /* and has PPE asserted */ + & (CNTL_PPE | CNTL_CIC)) == CNTL_PPE) + response |= /* merge its poll response */ + PPR (GET_DIADR (dptrs [other]->flags)); + +if (response) { /* is a poll response indicated? */ + if (DEBUG_PRJ (dptrs [card], DEB_XFER)) + fprintf (sim_deb, ">>%s xfer: HP-IB parallel poll DIO %03o\n", + dptrs [card]->name, response); + + while (di [card].fifo_count != FIFO_SIZE) /* fill the card FIFO with the responses */ + fifo_load (card, (uint16) response, diag_access); /* (hardware feature) */ + + update_state (card); /* update the card state */ + } + +return; +} + + +/* Accept a data byte from the bus. + + The indicated card accepts a byte that has been sourced to the bus. The byte + is loaded into the FIFO, and the card state is updated to reflect the load. + + Bus acceptors return TRUE to indicate that the byte was accepted. A card + always accepts a byte, so the routine always returns TRUE. +*/ + +static t_bool di_bus_accept (CARD_ID card, uint8 data) +{ +if (DEBUG_PRJ (dptrs [card], DEB_XFER)) + fprintf (sim_deb, ">>%s xfer: HP-IB card %d accepted data %03o \n", + dptrs [card]->name, card, data); + +fifo_load (card, data, bus_access); /* load the data byte into the FIFO */ +update_state (card); /* and update the card state */ +return TRUE; /* indicate that the byte was accepted */ +} + + +/* Respond to the bus control lines. + + The indicated card is notified of the new control state on the bus. The + routine establishes the new bus state and updates the card state to reflect + the change. +*/ + +static void di_bus_respond (CARD_ID card, uint8 new_cntl) +{ +di [card].bus_cntl = new_cntl; /* update the bus control lines */ +update_state (card); /* update the card state */ +return; +} + + + +/* Disc interface local utility routines */ + + +/* Master reset the interface. + + This is the programmed card master reset, not the simulator reset routine. + Master reset initializes a number of flip-flops and data paths on the card. + The primary use, other than during a PRESET, is to clear the FIFO in + preparation to changing the card from a listener to a talker or vice versa. + This ensures that unneeded FIFO data is not transmitted inadvertently to the + bus or to the CPU. It is also used when changing the data mode from unpacked + to packed to release the byte pointer flip-flops, which are held in the + "lower byte" position during unpacked transfers. + + In hardware, a master reset: + - clears the EDT, EOR, IRL, LBO, LBI, and IFC flip-flops + - clears the Input Data Register + - clears the FIFO + - sets or clears the odd/even input and output byte pointer flip-flops, + depending on whether the P (packed transfer) bit is set in the Control + Word Register +*/ + +static void master_reset (CARD_ID card) +{ +di [card].edt = CLEAR; /* clear the EDT flip-flop */ +di [card].eor = CLEAR; /* clear the EOR flip-flop */ + +if (di [card].cntl_register & CNTL_PACK) /* if packed mode is set, */ + di [card].ibp = di [card].obp = upper; /* MR sets the selectors to the upper byte */ +else /* otherwise, unpacked mode overrides */ + di [card].ibp = di [card].obp = lower; /* and sets the selectors to the lower byte */ + +di [card].status_register &= /* clear the status flip-flops */ + ~(STAT_IRL | STAT_LBO | STAT_LBI | STAT_IFC); + +di [card].input_data_register = 0; /* clear the input data register */ +di [card].fifo_count = 0; /* clear the FIFO */ + +if (DEBUG_PRJ (dptrs [card], DEB_BUF)) + fprintf (sim_deb, ">>%s buf: FIFO cleared\n", + dptrs [card]->name); + +return; +} + + +/* Update the interface state. + + In hardware, certain external operations cause automatic responses by the + disc interface card. For example, when the Input Data Register is unloaded + by an LIx instruction, it is automatically reloaded with the next word from + the FIFO. Also, the card may be set to interrupt in response to the + assertion of certain bus control lines. + + In simulation, this routine must be called whenever the FIFO, card control, + or bus control state changes. It determines whether: + + 1. ...the next word from the FIFO should be unloaded into the IDR. If the + card is listening, and the IDR is empty, and the FIFO contains data, then + a word is unloaded and stored in the IDR, and the Input Register Loaded + status bit is set. + + 2. ...the next word from the FIFO should be unloaded and sourced to the bus. + If the card is talking (but not polling), and the listener is ready to + accept data, and the last byte has not been sent, and the FIFO contains + data, then a word is unloaded and sourced to the bus. This occurs + regardless of whether or not there are any listeners. + + 3. ...an interface clear operation has completed. If IFC is asserted, and + the current simulation time is later than the IFC expiration time, then + IFC is denied, and the timer is reset. + + 4. ...the card should assert NRFD to prevent FIFO overflow. If the card is + listening, and the FIFO is full, or the last byte has been received, or a + pause has been explicitly requested, then NRFD is asserted. + + 5. ...the SRQ flip-flop should be set or cleared. If the card is listening + and the Input Data Register has been loaded, or the card is talking and + the FIFO is not full, then SRQ is asserted to request a DCPC transfer. + + 6. ...the flag flip-flop should be set or cleared. If the Input Data + Register has been loaded or the Last Byte Out flip-flop is set and the + corresponding Control Word Register IRL or LBO bits are set, or the End + of Record flip-flop is set and the Input Data Register has been unloaded, + or SRQ is asserted on the bus and the corresponding Control Word Register + bit is set when the card is not the controller-in-charge, or REN or IFC + is asserted on the bus and the corresponding Control Word Register bits + are set when the card is not the system controller, then the flag is set + to request an interrupt. + + + Implementation notes: + + 1. The fifo_unload routine may set STAT_LBO, so the flag test must be done + after unloading. + + 2. The gcc compiler (at least as of version 4.6.2) does not optimize + repeated use of array-of-structures accesses. Instead, it recalculates + the index each time, even though the index is a constant within the + function. To avoid this performance penalty, we use a pointer to the + selected DI_STATE structure. Note that VC++ 2008 does perform this + optimization. + */ + +static void update_state (CARD_ID card) +{ +DIB * const dibptr = (DIB *) dptrs [card]->ctxt; +DI_STATE * const di_card = &di [card]; +uint8 assert = 0; +uint8 deny = 0; +uint16 data; +FLIP_FLOP previous_state; + +if (di_card->cntl_register & CNTL_LSTN) { /* is the card a listener? */ + if (!(di_card->status_register & STAT_IRL) /* is the IDR empty? */ + && ! FIFO_EMPTY) { /* and data remains in the FIFO? */ + data = fifo_unload (card, cpu_access); /* unload the FIFO */ + di_card->input_data_register = data; /* into the IDR */ + di_card->status_register |= STAT_IRL; /* set the input register loaded status */ + } + } + +else if ((di_card->cntl_register /* is the card a talker? */ + & (CNTL_TALK | CNTL_PPE)) == CNTL_TALK) /* and not polling? */ + while (! FIFO_EMPTY /* is data remaining in FIFO? */ + && !(di_card->bus_cntl & BUS_NRFD) /* and NRFD is denied? */ + && !(di_card->status_register & STAT_LBO)) { /* and the last byte has not been sent? */ + data = fifo_unload (card, bus_access); /* unload a FIFO byte */ + di_bus_source (card, (uint8) data); /* source it to the bus */ + } + + +if (di_card->bus_cntl & BUS_IFC /* is an IFC in progress? */ + && di_card->ifc_timer != 0.0 /* and I am timing? */ + && sim_gtime () > di_card->ifc_timer) { /* and has the timeout elapsed? */ + deny = BUS_IFC; /* deny IFC on the bus */ + di_card->ifc_timer = 0.0; /* clear the IFC timer */ + di_card->status_register &= ~STAT_IFC; /* and clear IFC status */ + } + + +if (di_card->cntl_register & CNTL_LSTN) /* is the card a listener? */ + if (di_card->cntl_register & CNTL_NRFD /* if explicitly requested */ + || di_card->status_register & STAT_LBI /* or the last byte is in */ + || FIFO_FULL) /* or the FIFO is full */ + assert = BUS_NRFD; /* then assert NRFD */ + else /* otherwise the card is ready for data */ + deny |= BUS_NRFD; /* so deny NRFD */ + +if (assert != deny) /* was there any change in bus state? */ + di_bus_control (card, CONTROLLER, assert, deny); /* update the bus control */ + + +previous_state = di_card->srq; /* save the current SRQ state */ + +if (di_card->cntl_register & CNTL_LSTN /* if the card is a listener */ + && di_card->status_register & STAT_IRL /* and the input register is loaded, */ + || di_card->cntl_register & CNTL_TALK /* or the card is a talker */ + && ! FIFO_FULL) /* and the FIFO is not full */ + di_card->srq = SET; /* then request a DCPC cycle */ +else + di_card->srq = CLEAR; /* otherwise, DCPC service is not needed */ + + +if (DEBUG_PRJ (dptrs [card], DEB_CMDS) + && di_card->srq != previous_state) + fprintf (sim_deb, ">>%s cmds: SRQ %s\n", + dptrs [card]->name, di_card->srq == SET ? "set" : "cleared"); + + +if (di_card->status_register & STAT_IRL /* is the input register loaded */ + && di_card->cntl_register & CNTL_IRL /* and notification is wanted? */ + || di_card->status_register & STAT_LBO /* or is the last byte out */ + && di_card->cntl_register & CNTL_LBO /* and notification is wanted? */ + || di_card->eor == SET /* or was the end of record seen */ + && !(di_card->status_register & STAT_IRL) /* and the input register was unloaded? */ + || di_card->bus_cntl & BUS_SRQ /* or is SRQ asserted on the bus */ + && di_card->cntl_register & CNTL_SRQ /* and notification is wanted */ + && di_card->cntl_register & CNTL_CIC /* and the card is not controller? */ + || !SW8_SYSCTL /* or is the card not the system controller */ + && di_card->bus_cntl & BUS_REN /* and REN is asserted on the bus */ + && di_card->cntl_register & CNTL_REN /* and notification is wanted? */ + || !SW8_SYSCTL /* or is the card not the system controller */ + && di_card->status_register & STAT_IFC /* and IFC is asserted on the bus */ + && di_card->cntl_register & CNTL_IFC) { /* and notification is wanted? */ + + if (DEBUG_PRJ (dptrs [card], DEB_CMDS)) + fprintf (sim_deb, ">>%s cmds: Flag set\n", + dptrs [card]->name); + + di_io (dibptr, ioENF, 0); /* set the flag and recalculate interrupts */ + } + +else if (di_card->srq != previous_state) /* if SRQ changed state, */ + di_io (dibptr, ioSIR, 0); /* then recalculate interrupts */ + +return; +} + + +/* Load a word or byte into the FIFO. + + A word or byte is loaded into the next available location in the FIFO. The + significance of the data parameter is indicated by the access mode as + follows: + + - For CPU access, the parameter is a 16-bit value. + + - For bus access, the parameter is an 8-bit value in the lower byte and a + zero in the upper byte. + + - For diagnostic access, the parameter is an 8-bit value in the lower byte + that will be duplicated in the upper byte. + + For bus access, byte loading into the FIFO is controlled by the value of the + Input Buffer Pointer (IBP) selector. + + In addition to data words, the FIFO holds tags that mark the last byte + received or to be transmitted and that indicate the state of the ATN and EOI + bus lines (if listening) or the states to assert (if talking). The tag is + assembled into the upper word, the data is assembled into the lower word, and + then the 32-bit value is stored in the next available FIFO location. + + If data is coming from the CPU, the 16-bit value is loaded into the next FIFO + location, and the occupancy count is incremented. + + If the data is coming from the bus, and the input mode is unpacked, the 8-bit + value is loaded into the lower byte of the next FIFO location, and the + occupancy count is incremented. In hardware, the upper FIFO is not clocked; + in simulation, the upper byte is set to zero. The IBP always points at the + lower byte in unpacked mode. + + If the data is coming from the bus, and the input mode is packed, the 8-bit + value is loaded into either the upper or lower byte of the next FIFO + location, depending on the value of the IBP, and the IBP is toggled. If the + value was stored in the lower byte, the occupancy count is incremented. + + A special case occurs when the value is to be stored in the upper byte, and + the LBR tag is set to indicate that this is the last byte to be received. In + this case, the value is stored in both bytes of the next FIFO location, and + the occupancy counter is incremented. + + If data is coming from the diagnostic FIFO loopback, the 8-bit value in the + lower byte is copied to the upper byte, the resulting 16-bit value is loaded + into the next FIFO location, and the occupancy count is incremented. + + + Implementation notes: + + 1. Four tag bits are loaded into the upper word of each FIFO entry: + + - Last Byte Received (while receiving, a line feed is received and the + LF bit is set in the Control Word Register, or a byte with EOI + asserted is received and the EOI bit is set). + + - End of Data Transfer (while transmitting, DCPC asserts the EDT + backplane signal, or an unpacked-mode data word has the LBO bit set, + or a packed-mode OTx is issued without an accompanying CLF). + + - ATN (the state of ATN on the bus if receiving, or the ATN bit in the + unpacked data word if transmitting). + + - EOI (the state of EOI on the bus if receiving, or the EOI bit in the + unpacked data word if transmitting). + + 2. The FIFO is implemented as circular queue to take advantage of REG_CIRC + EXAMINE semantics. REG->qptr is the index of the first word currently in + the FIFO. By specifying REG_CIRC, examining FIFO[0-n] will always + display the words in load order, regardless of the actual array index of + the start of the list. The number of words currently present in the FIFO + is kept in fifo_count (0 = empty, 1-16 = number of words available). + + If fifo_count < FIFO_SIZE, (REG->qptr + fifo_count) mod FIFO_SIZE is the + index of the new word location. Loading stores the word there and then + increments fifo_count. + + 3. Because the load and unload routines need access to qptr in the REG + structure for the FIFO array, pointers to the REG for each card are + stored in the fifo_reg array during device reset. + + 4. The gcc compiler (at least as of version 4.6.2) does not optimize + repeated use of array-of-structures accesses. Instead, it recalculates + the index each time, even though the index is a constant within the + function. To avoid this performance penalty, we use a pointer to the + selected DI_STATE structure. Note that VC++ 2008 does perform this + optimization. +*/ + +static void fifo_load (CARD_ID card, uint16 data, FIFO_ACCESS access) +{ +uint32 tag, index; +t_bool add_word = TRUE; +DI_STATE * const di_card = &di [card]; + +if (FIFO_FULL) { /* is the FIFO already full? */ + if (DEBUG_PRJ (dptrs [card], DEB_BUF)) + fprintf (sim_deb, ">>%s buf: Attempted load to full FIFO, data %0*o\n", + dptrs [card]->name, (access == bus_access ? 3 : 6), data); + + return; /* return with the load ignored */ + } + +if (di_card->cntl_register & CNTL_LSTN) { /* is the card receiving? */ + tag = (di_card->bus_cntl /* set the tag from the bus signals */ + & (BUS_ATN | BUS_EOI)) << BUS_SHIFT; /* shifted to the tag locations */ + + if ((di_card->cntl_register & CNTL_EOI /* EOI detection is enabled, */ + && di_card->bus_cntl & BUS_EOI) /* and data was tagged with EOI? */ + || (di_card->cntl_register & CNTL_LF /* or LF detection is enabled, */ + && GET_LOWER (data) == LF)) { /* and the byte is a line feed? */ + tag = tag | TAG_LBR; /* tag as the last byte received */ + di_card->status_register |= STAT_LBI; /* set the last byte in status */ + } + else /* neither termination condition was seen */ + di_card->status_register &= ~STAT_LBI; /* so clear the last byte in status */ + } + +else /* the card is transmitting */ + tag = (data & (DATA_ATN | DATA_EOI)) << DATA_SHIFT; /* set the tag from the data shifted to the tag location */ + +if (di_card->edt == SET) /* is this the end of the data transfer? */ + tag = tag | TAG_EDT; /* set the EDT tag */ + + +index = (di_card->fifo_reg->qptr /* calculate the index */ + + di_card->fifo_count) % FIFO_SIZE; /* of the next available location */ + +if (access == bus_access) { /* is this a bus access */ + if (di_card->ibp == upper) { /* in packed mode for the upper byte? */ + di_card->ibp = lower; /* set the lower byte as next */ + + if (tag & TAG_LBR) /* is this the last byte? */ + di_card->fifo [index] = /* copy to both bytes of the FIFO */ + tag | SET_BOTH (data); /* and store with the tag */ + else { /* more bytes are expected */ + di_card->fifo [index] = /* so position this byte */ + tag | SET_UPPER (data); /* and store it with the tag */ + add_word = FALSE; /* wait for the second byte before adding */ + } + } + + else /* this is the lower byte */ + if (di_card->cntl_register & CNTL_PACK) { /* is the card in packed mode? */ + di_card->ibp = upper; /* set the upper byte as next */ + + di_card->fifo [index] = /* merge the data and tag values */ + tag | di_card->fifo [index] | SET_LOWER (data); + } + else /* the card is in unpacked mode */ + di_card->fifo [index] = /* position this byte */ + tag | SET_LOWER (data); /* and store with the tag */ + } + +else if (access == cpu_access) /* is this a cpu access? */ + di_card->fifo [index] = tag | data; /* store the tag and full word in the FIFO */ + +else { /* must be diagnostic access */ + data = SET_BOTH (GET_LOWER (data)); /* copy the lower byte to the upper byte */ + di_card->fifo [index] = tag | data; /* and store the tag and full word in the FIFO */ + } + +if (add_word) /* did we add a word to the FIFO? */ + di_card->fifo_count = di_card->fifo_count + 1; /* increment the count of words stored */ + +if (DEBUG_PRJ (dptrs [card], DEB_BUF)) { + fprintf (sim_deb, ">>%s buf: Data %0*o tag ", + dptrs [card]->name, (access == bus_access ? 3 : 6), data); + fprint_val (sim_deb, tag >> BUS_SHIFT, 2, 4, PV_RZRO); + fprintf (sim_deb, " loaded into FIFO (%d)\n", di_card->fifo_count); + } + +return; +} + + +/* Unload a word or byte from the FIFO. + + A word or byte is unloaded from the first location in the FIFO. The + significance of the returned value is indicated by the access mode as + follows: + + - For CPU access, a 16-bit value is unloaded and returned. + + - For bus access, an 8-bit value is unloaded and returned. + + - For diagnostic access, an 16-bit value is unloaded, and the lower byte + is returned. + + For bus access, byte unloading from the FIFO is controlled by the value of + the Output Buffer Pointer (OBP) selector. + + If the FIFO is not empty, the first entry is obtained and split into tag and + data words. The LBR tag value is loaded into the EOR flip-flop if the CPU is + accessing. The EDT tag sets Last Byte Out status if the last byte is being + unloaded. + + If the data is going to the CPU, the 16-bit packed data value is returned as + is, or the lower byte of the unpacked value is merged with the tags for ATN + and EOI and returned. The occupancy count is decremented to unload the FIFO + entry. + + If the data is going to the bus, and the input mode is unpacked, the 8-bit + value is returned in the lower byte, and the occupancy count is decremented. + In hardware, the upper FIFO is not clocked; in simulation, the upper byte is + ignored. The OBP always points at the lower byte in unpacked mode. + + If the data is going to the bus, and the input mode is packed, the 8-bit + value is unloaded from either the upper or lower byte of the data word, + depending on the value of the OBP, and returned in the lower byte. The OBP + value is toggled. If the value was obtained from the lower byte, the + occupancy count is decremented to unload the FIFO. Otherwise, the count is + not altered, so that the lower-byte access will be from the same FIFO entry. + + If data is going to the diagnostic FIFO loopback, the lower byte of the + 16-bit value is returned; the upper byte of the returned value is zero. + + + Implementation notes: + + 1. Four tag bits are unloaded from the upper word of each FIFO entry: + + - Last Byte Received (sets the End of Record flip-flop when the last + byte received is loaded into the Input Data Register). + + - End of Data Transfer (sets the LBO bit in the Status Word Register + when the last byte is unloaded from the FIFO). + + - ATN (in unpacked mode, sets the ATN bit in the returned data word + if listening, or controls the bus ATN line if talking; in packed mode, + the tag is ignored). + + - EOI (in unpacked mode, sets the EOI bit in the returned data word if + listening, or asserts the bus EOI line if talking; in packed mode, the + tag is ignored). + + ATN and EOI tag handling is complex. If the card is listening in the + unpacked mode, the ATN tag substitutes for bit 8 of the data word, and + the EOI tag substitutes for bit 9. In the packed mode, bits 8 and 9 are + as stored in the FIFO (they are upper-byte data bits). + + If the card is talking in the unpacked mode, the ATN tag asserts or + denies ATN on the bus if the card is the CIC, and the EOI tag asserts or + denies EOI on the bus. In the packed mode, the ATN bit in the Control + Word Register asserts or denies ATN on the bus if the card is the CIC, + and the EOI bit asserts EOI on the bus if the last byte of the entry + tagged with EDT has been unloaded from the FIFO (which sets LBO status) + or denies EOI otherwise. + + 2. In hardware, the EOR flip-flop is clocked with the Input Data Register. + Therefore, when the card is listening, EOR is set not when the last byte + is unloaded from the FIFO, but rather when that byte is loaded into the + IDR. These two actions occur together when the IDR is empty. + + However, during diagnostic access, data unloaded from the FIFO is + reloaded, and the IDR is never clocked. As the T and L bits must be set + with DIAG in the Control Word Register to enable the loopback path, the + LBR tag will be entered into the FIFO if EOI or LF detection is enabled, + but the EOR flip-flop will not be set when that word falls through to be + unloaded. + + In simulation, EOR is set whenever the LBR tag is unloaded from the FIFO + during CPU access, as a CPU unload is always followed by an IDR store. + + 3. If fifo_count > 0, REG->qptr is the index of the word to remove. Removal + gets the word and then increments qptr (mod FIFO_SIZE) and decrements + fifo_count. + + 4. The gcc compiler (at least as of version 4.6.2) does not optimize + repeated use of array-of-structures accesses. Instead, it recalculates + the index each time, even though the index is a constant within the + function. To avoid this performance penalty, we use a pointer to the + selected DI_STATE structure. Note that VC++ 2008 does perform this + optimization. +*/ + +static uint16 fifo_unload (CARD_ID card, FIFO_ACCESS access) +{ +uint32 data, tag; +t_bool remove_word = TRUE; +DI_STATE * const di_card = &di [card]; + +if (FIFO_EMPTY) { /* is the FIFO already empty? */ + if (DEBUG_PRJ (dptrs [card], DEB_BUF)) + fprintf (sim_deb, ">>%s buf: Attempted unload from empty FIFO\n", + dptrs [card]->name); + + return 0; /* return with no data */ + } + +data = di_card->fifo [di_card->fifo_reg->qptr]; /* get the tag and data from the FIFO */ + +tag = data & TAG_MASK; /* mask the tag to just the tag bits */ +data = data & DMASK; /* and the data to just the data bits */ + +if (tag & TAG_EDT /* is this the end of a data transfer */ + && (di_card->obp == lower /* and the lower byte is next */ + || di_card->cntl_register & CNTL_ODD)) /* or we are sending an odd number of bytes? */ + di_card->status_register |= STAT_LBO; /* set the last byte out status */ + + +if (access == cpu_access) { /* is this a cpu access? */ + if (!(di_card->cntl_register & CNTL_PACK)) /* in unpacked mode? */ + data = data & ~(DATA_ATN | DATA_EOI) /* substitute the ATN/EOI tag values */ + | (tag & (TAG_ATN | TAG_EOI)) >> DATA_SHIFT; /* into the data word */ + + if (tag & TAG_LBR) /* is this the last byte? */ + di_card->eor = SET; /* set */ + else /* or clear */ + di_card->eor = CLEAR; /* the end-of-record flip-flop */ + } + +else if (access == bus_access) /* is this a bus access? */ + if (di_card->obp == upper) { /* is this the upper byte? */ + di_card->obp = lower; /* set the lower byte as next */ + data = GET_UPPER (data); /* mask and position the upper byte in the data word */ + remove_word = FALSE; /* do not unload the FIFO until the next byte */ + } + + else { /* this is the lower byte */ + data = GET_LOWER (data); /* mask and position it in the data word */ + + if (di_card->cntl_register & CNTL_PACK) /* is the card in the packed mode? */ + di_card->obp = upper; /* set the upper byte as next */ + } + +else /* must be a diagnostic access */ + data = GET_LOWER (data); /* access is to the lower byte only */ + + +if (remove_word) { /* remove the word from the FIFO? */ + di_card->fifo_reg->qptr = /* update the FIFO queue pointer */ + (di_card->fifo_reg->qptr + 1) % FIFO_SIZE; /* and wrap around as needed */ + + di_card->fifo_count = di_card->fifo_count - 1; /* decrement the FIFO count */ + } + + +if (DEBUG_PRJ (dptrs [card], DEB_BUF)) { + fprintf (sim_deb, ">>%s buf: Data %0*o tag ", + dptrs [card]->name, (access == cpu_access ? 6 : 3), data); + fprint_val (sim_deb, tag >> BUS_SHIFT, 2, 4, PV_RZRO); + fprintf (sim_deb, " unloaded from FIFO (%d)\n", di_card->fifo_count); + } + + +if (di_card->cntl_register & CNTL_TALK) /* is the card talking? */ + if (di_card->cntl_register & CNTL_PACK) /* is it in the packed mode? */ + if (di_card->status_register & STAT_LBO /* yes, is the last byte out? */ + && di_card->cntl_register & CNTL_EOI) /* and is EOI control enabled? */ + di_card->bus_cntl |= BUS_EOI; /* assert EOI on the bus */ + else + di_card->bus_cntl &= ~BUS_EOI; /* deny EOI on the bus */ + + else { /* the card is in the unpacked mode */ + if (di_card->cntl_register & CNTL_CIC) /* is the card the controller in charge? */ + di_card->bus_cntl = /* assert or deny the ATN bus line */ + di_card->bus_cntl & ~BUS_ATN /* from the ATN tag value */ + | (uint8) ((tag & TAG_ATN) >> BUS_SHIFT); + + di_card->bus_cntl = /* assert or deny the EOI bus line */ + di_card->bus_cntl & ~BUS_EOI /* from the EOI tag value */ + | (uint8) ((tag & TAG_EOI) >> BUS_SHIFT); + } + +return (uint16) data; /* return the data value */ +} + + +/* Print the bus state for debugging. + + The states of the supplied bus control lines are decoded and printed in + mnemonic form to the specified file using the indicated format string. An + asserted bus signal is indicated by its name; a denied signal is omitted. + + + Implementation notes: + + 1. The strings in the cntl_names array must appear in BUS_xxx order. The + first element corresponds to bus bit 0, etc. +*/ + +static void fprint_bus (FILE *file, char *format, uint8 cntl) +{ +static const char *cntl_names [] = { + "ATN", /* bit 0: attention */ + "EOI", /* bit 1: end or identify */ + "DAV", /* bit 2: data available */ + "NRFD", /* bit 3: not ready for data */ + "NDAC", /* bit 4: not data accepted */ + "REN", /* bit 5: remote enable */ + "IFC", /* bit 6: interface clear */ + "SRQ" /* bit 7: service request */ + }; + +uint32 signal; +char mnemonics [40]; + +if (cntl == 0) /* are any control signals asserted? */ + strcpy (mnemonics, "---"); /* no; use dashes in lieu of an empty string */ + +else { /* one or more signals are asserted */ + mnemonics [0] = '\0'; + + for (signal = 0; signal <= 7; signal++) /* loop though the set of signals */ + if (cntl & (1 << signal)) { /* is this signal asserted? */ + if (strlen (mnemonics) > 0) /* yes; is it the first one asserted? */ + strcat (mnemonics, " "); /* no, so append a space to separate */ + strcat (mnemonics, cntl_names [signal]); /* append the name of the asserted signal */ + } + } + +fprintf (file, format, mnemonics); /* print the bus state */ +return; +} diff --git a/HP2100/hp2100_di.h b/HP2100/hp2100_di.h index 08171b21..5763ed4a 100644 --- a/HP2100/hp2100_di.h +++ b/HP2100/hp2100_di.h @@ -1,300 +1,300 @@ -/* hp2100_di.h: HP 12821A HP-IB Disc Interface simulator definitions - - Copyright (c) 2010-2012, J. David Bryan - - 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 - THE AUTHOR 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 the author shall not be - used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from the author. - - DI 12821A Disc Interface - - 14-Feb-12 JDB First release - 16-Nov-10 JDB Created DI common definitions file - - - This file defines the interface between HP-IB device simulators and the - 12821A Disc Interface simulator. It must be included by the device-specific - modules (hp2100_di_da.c, etc.). - - - Implementation notes: - - 1. Three CARD_ID values are defined, corresponding to the Amigo disc (DA), - CS/80 disc (DC), and Amigo mag tape (MA) simulators. At first release, - only the DA device is implemented. However, as the 12821A diagnostic - requires two cards to test I/O fully, a dummy DC device is provided by - the DA simulator. It is enabled only when the DA card is configured for - diagnostic mode. This dummy device should be removed when either the DC - or MA device is implemented. -*/ - - - -/* Program constants */ - -#define FIFO_SIZE 16 /* FIFO depth */ - -typedef enum { - da, dc, ma, /* card IDs */ - first_card = da, /* first card ID */ - last_card = ma, /* last card ID */ - card_count /* count of card IDs */ - } CARD_ID; - - -/* Device flags and accessors (bits 7-0 are reserved for disc/tape flags) */ - -#define DEV_V_BUSADR (DEV_V_UF + 8) /* bits 10-8: interface HP-IB address */ -#define DEV_V_DIAG (DEV_V_UF + 11) /* bit 11: diagnostic mode */ -#define DEV_V_W1 (DEV_V_UF + 12) /* bit 12: DCPC pacing jumper */ - -#define DEV_M_BUSADR 07 /* bus address mask */ - -#define DEV_BUSADR (DEV_M_BUSADR << DEV_V_BUSADR) -#define DEV_DIAG (1 << DEV_V_DIAG) -#define DEV_W1 (1 << DEV_V_W1) - -#define GET_DIADR(f) (((f) >> DEV_V_BUSADR) & DEV_M_BUSADR) -#define SET_DIADR(f) (((f) & DEV_M_BUSADR) << DEV_V_BUSADR) - - -/* Unit flags and accessors (bits 7-0 are reserved for disc/tape flags) */ - -#define UNIT_V_BUSADR (UNIT_V_UF + 8) /* bits 10-8: unit HP-IB address */ - -#define UNIT_M_BUSADR 07 /* bus address mask */ - -#define UNIT_BUSADR (UNIT_M_BUSADR << UNIT_V_BUSADR) - -#define GET_BUSADR(f) (((f) >> UNIT_V_BUSADR) & UNIT_M_BUSADR) -#define SET_BUSADR(f) (((f) & UNIT_M_BUSADR) << UNIT_V_BUSADR) - - -/* Debug flags */ - -#define DEB_CPU (1 << 0) /* words received from and sent to the CPU */ -#define DEB_CMDS (1 << 1) /* interface commands received from the CPU */ -#define DEB_BUF (1 << 2) /* data read from and written to the card FIFO */ -#define DEB_XFER (1 << 3) /* data received and transmitted via HP-IB */ -#define DEB_RWSC (1 << 4) /* device read/write/status/control commands */ -#define DEB_SERV (1 << 5) /* unit service scheduling calls */ - - -/* HP-IB control line state bit flags. - - NOTE that these flags align with the corresponding flags in the DI status - register, so don't change the numerical values! -*/ - -#define BUS_ATN 0001 /* attention */ -#define BUS_EOI 0002 /* end or identify */ -#define BUS_DAV 0004 /* data available */ -#define BUS_NRFD 0010 /* not ready for data */ -#define BUS_NDAC 0020 /* not data accepted */ -#define BUS_REN 0040 /* remote enable */ -#define BUS_IFC 0100 /* interface clear */ -#define BUS_SRQ 0200 /* service request */ - -#define BUS_PPOLL (BUS_ATN | BUS_EOI) /* parallel poll */ - -/* HP-IB data */ - -#define BUS_ADDRESS 0037 /* bus address mask */ -#define BUS_GROUP 0140 /* bus group mask */ -#define BUS_COMMAND 0160 /* bus command type mask */ -#define BUS_DATA 0177 /* bus data mask */ -#define BUS_PARITY 0200 /* bus parity mask */ - -#define BUS_PCG 0000 /* primary command group */ -#define BUS_LAG 0040 /* listen address group */ -#define BUS_TAG 0100 /* talk address group */ -#define BUS_SCG 0140 /* secondary command group */ - -#define BUS_UCG 0020 /* universal command group */ -#define BUS_ACG 0000 /* addressed command group */ - -#define BUS_UNADDRESS 0037 /* unlisten and untalk addresses */ - -#define PPR(a) (uint8) (1 << (7 - (a))) /* parallel poll response */ - - -/* Byte accessors */ - -#define BYTE_SHIFT 8 /* byte shift count */ -#define UPPER_BYTE 0177400 /* high-order byte mask */ -#define LOWER_BYTE 0000377 /* low-order byte mask */ - -#define GET_UPPER(w) (uint8) (((w) & UPPER_BYTE) >> BYTE_SHIFT) -#define GET_LOWER(w) (uint8) ((w) & LOWER_BYTE) - -#define SET_UPPER(b) ((b) << BYTE_SHIFT) -#define SET_LOWER(b) (b) -#define SET_BOTH(b) (SET_UPPER (b) | SET_LOWER (b)) - -typedef enum { - upper, /* upper byte selected */ - lower /* lower byte selected */ - } SELECTOR; - - -/* Per-card state variables */ - -typedef struct { - FLIP_FLOP control; /* control flip-flop */ - FLIP_FLOP flag; /* flag flip-flop */ - FLIP_FLOP flagbuf; /* flag buffer flip-flop */ - FLIP_FLOP srq; /* SRQ flip-flop */ - FLIP_FLOP edt; /* EDT flip-flop */ - FLIP_FLOP eor; /* EOR flip-flop */ - SELECTOR ibp; /* input byte pointer selector */ - SELECTOR obp; /* output byte pointer selector */ - - uint16 cntl_register; /* control word register */ - uint16 status_register; /* status word register */ - uint16 input_data_register; /* input data register */ - - uint32 fifo [FIFO_SIZE]; /* FIFO buffer */ - uint32 fifo_count; /* FIFO occupancy counter */ - REG *fifo_reg; /* FIFO register pointer */ - - uint32 acceptors; /* unit bitmap of the bus acceptors */ - uint32 listeners; /* unit bitmap of the bus listeners */ - uint32 talker; /* unit bitmap of the bus talker */ - - uint8 bus_cntl; /* HP-IB bus control state (ATN, EOI, etc.) */ - uint8 poll_response; /* address bitmap of parallel poll responses */ - - double ifc_timer; /* 100 microsecond IFC timer */ - } DI_STATE; - - -/* Disc interface VM global register definitions. - - These definitions should be included before any device-specific registers. - - - Implementation notes: - - 1. The TMR register is included to ensure that the IFC timer is saved by a - SAVE command. It is declared as a hidden, read-only byte array of a size - compatible with a double-precision floating-point value, as there is no - appropriate macro for the double type. -*/ - -#define DI_REGS(dev) \ - { ORDATA (CWR, di [dev].cntl_register, 16), REG_FIT }, \ - { ORDATA (SWR, di [dev].status_register, 16), REG_FIT }, \ - { ORDATA (IDR, di [dev].input_data_register, 16), REG_FIT }, \ - \ - { DRDATA (FCNT, di [dev].fifo_count, 5) }, \ - { BRDATA (FIFO, di [dev].fifo, 8, 20, FIFO_SIZE), REG_CIRC }, \ - \ - { GRDATA (ACPT, di [dev].acceptors, 2, 4, 0) }, \ - { GRDATA (LSTN, di [dev].listeners, 2, 4, 0) }, \ - { GRDATA (TALK, di [dev].talker, 2, 4, 0) }, \ - { GRDATA (PPR, di [dev].poll_response, 2, 8, 0), REG_FIT }, \ - { GRDATA (BUSCTL, di [dev].bus_cntl, 2, 8, 0), REG_FIT }, \ - \ - { FLDATA (CTL, di [dev].control, 0) }, \ - { FLDATA (FLG, di [dev].flag, 0) }, \ - { FLDATA (FBF, di [dev].flagbuf, 0) }, \ - { FLDATA (SRQ, di [dev].srq, 0) }, \ - { FLDATA (EDT, di [dev].edt, 0) }, \ - { FLDATA (EOR, di [dev].eor, 0) }, \ - \ - { BRDATA (TMR, &di [dev].ifc_timer, 10, CHAR_BIT, sizeof (double)), REG_HRO }, \ - \ - { ORDATA (SC, dev##_dib.select_code, 6), REG_HRO } - - -/* Disc interface VM global modifier definitions. - - These definitions should be included before any device-specific modifiers. -*/ - -#define DI_MODS(dev) \ - { MTAB_XTD | MTAB_VDV, 1, "ADDRESS", "ADDRESS", &di_set_address, &di_show_address, &dev }, \ - \ - { MTAB_XTD | MTAB_VDV, 1, NULL, "DIAG", &di_set_cable, NULL, &dev }, \ - { MTAB_XTD | MTAB_VDV, 0, NULL, "HPIB", &di_set_cable, NULL, &dev }, \ - { MTAB_XTD | MTAB_VDV, 0, "CABLE", NULL, NULL, &di_show_cable, &dev }, \ - \ - { MTAB_XTD | MTAB_VDV, 0, "SC", "SC", &hp_setsc, &hp_showsc, &dev }, \ - { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &dev }, \ - \ - { MTAB_XTD | MTAB_VUN, 0, "BUS", "BUS", &di_set_address, &di_show_address, &dev } - - -/* Disc interface global bus routine definitions */ - -typedef t_bool ACCEPTOR (uint32 unit, uint8 data); -typedef void RESPONDER (CARD_ID card, uint32 unit, uint8 new_cntl); - - -/* Disc interface global variables */ - -extern DI_STATE di []; -extern DEBTAB di_deb []; - - -/* Disc interface global VM routines */ - -extern IOHANDLER di_io; -extern t_stat di_reset (DEVICE *dptr); - -/* Disc interface global SCP routines */ - -extern t_stat di_set_address (UNIT *uptr, int32 value, char *cptr, void *desc); -extern t_stat di_show_address (FILE *st, UNIT *uptr, int32 value, void *desc); -extern t_stat di_set_cable (UNIT *uptr, int32 value, char *cptr, void *desc); -extern t_stat di_show_cable (FILE *st, UNIT *uptr, int32 value, void *desc); - -/* Disc interface global bus routines */ - -extern t_bool di_bus_source (CARD_ID card, uint8 data); -extern void di_bus_control (CARD_ID card, uint32 unit, uint8 assert, uint8 deny); -extern void di_poll_response (CARD_ID card, uint32 unit, FLIP_FLOP response); - - -/* Amigo disc global VM routines */ - -extern t_stat da_service (UNIT *uptr); -extern t_stat da_boot (int32 unitno, DEVICE *dptr); - -/* Amigo disc global bus routines */ - -extern ACCEPTOR da_bus_accept; -extern RESPONDER da_bus_respond; - - -/* Amigo mag tape global VM routines */ - -extern t_stat ma_service (UNIT *uptr); -extern t_stat ma_boot (int32 unitno, DEVICE *dptr); - -/* Amigo mag tape global SCP routines */ - -extern t_stat ma_set_timing (UNIT *uptr, int32 val, char *cptr, void *desc); -extern t_stat ma_show_timing (FILE *st, UNIT *uptr, int32 val, void *desc); - -/* Amigo mag tape global bus routines */ - -extern ACCEPTOR ma_bus_accept; -extern RESPONDER ma_bus_respond; +/* hp2100_di.h: HP 12821A HP-IB Disc Interface simulator definitions + + Copyright (c) 2010-2012, J. David Bryan + + 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 + THE AUTHOR 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 the author shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from the author. + + DI 12821A Disc Interface + + 14-Feb-12 JDB First release + 16-Nov-10 JDB Created DI common definitions file + + + This file defines the interface between HP-IB device simulators and the + 12821A Disc Interface simulator. It must be included by the device-specific + modules (hp2100_di_da.c, etc.). + + + Implementation notes: + + 1. Three CARD_ID values are defined, corresponding to the Amigo disc (DA), + CS/80 disc (DC), and Amigo mag tape (MA) simulators. At first release, + only the DA device is implemented. However, as the 12821A diagnostic + requires two cards to test I/O fully, a dummy DC device is provided by + the DA simulator. It is enabled only when the DA card is configured for + diagnostic mode. This dummy device should be removed when either the DC + or MA device is implemented. +*/ + + + +/* Program constants */ + +#define FIFO_SIZE 16 /* FIFO depth */ + +typedef enum { + da, dc, ma, /* card IDs */ + first_card = da, /* first card ID */ + last_card = ma, /* last card ID */ + card_count /* count of card IDs */ + } CARD_ID; + + +/* Device flags and accessors (bits 7-0 are reserved for disc/tape flags) */ + +#define DEV_V_BUSADR (DEV_V_UF + 8) /* bits 10-8: interface HP-IB address */ +#define DEV_V_DIAG (DEV_V_UF + 11) /* bit 11: diagnostic mode */ +#define DEV_V_W1 (DEV_V_UF + 12) /* bit 12: DCPC pacing jumper */ + +#define DEV_M_BUSADR 07 /* bus address mask */ + +#define DEV_BUSADR (DEV_M_BUSADR << DEV_V_BUSADR) +#define DEV_DIAG (1 << DEV_V_DIAG) +#define DEV_W1 (1 << DEV_V_W1) + +#define GET_DIADR(f) (((f) >> DEV_V_BUSADR) & DEV_M_BUSADR) +#define SET_DIADR(f) (((f) & DEV_M_BUSADR) << DEV_V_BUSADR) + + +/* Unit flags and accessors (bits 7-0 are reserved for disc/tape flags) */ + +#define UNIT_V_BUSADR (UNIT_V_UF + 8) /* bits 10-8: unit HP-IB address */ + +#define UNIT_M_BUSADR 07 /* bus address mask */ + +#define UNIT_BUSADR (UNIT_M_BUSADR << UNIT_V_BUSADR) + +#define GET_BUSADR(f) (((f) >> UNIT_V_BUSADR) & UNIT_M_BUSADR) +#define SET_BUSADR(f) (((f) & UNIT_M_BUSADR) << UNIT_V_BUSADR) + + +/* Debug flags */ + +#define DEB_CPU (1 << 0) /* words received from and sent to the CPU */ +#define DEB_CMDS (1 << 1) /* interface commands received from the CPU */ +#define DEB_BUF (1 << 2) /* data read from and written to the card FIFO */ +#define DEB_XFER (1 << 3) /* data received and transmitted via HP-IB */ +#define DEB_RWSC (1 << 4) /* device read/write/status/control commands */ +#define DEB_SERV (1 << 5) /* unit service scheduling calls */ + + +/* HP-IB control line state bit flags. + + NOTE that these flags align with the corresponding flags in the DI status + register, so don't change the numerical values! +*/ + +#define BUS_ATN 0001 /* attention */ +#define BUS_EOI 0002 /* end or identify */ +#define BUS_DAV 0004 /* data available */ +#define BUS_NRFD 0010 /* not ready for data */ +#define BUS_NDAC 0020 /* not data accepted */ +#define BUS_REN 0040 /* remote enable */ +#define BUS_IFC 0100 /* interface clear */ +#define BUS_SRQ 0200 /* service request */ + +#define BUS_PPOLL (BUS_ATN | BUS_EOI) /* parallel poll */ + +/* HP-IB data */ + +#define BUS_ADDRESS 0037 /* bus address mask */ +#define BUS_GROUP 0140 /* bus group mask */ +#define BUS_COMMAND 0160 /* bus command type mask */ +#define BUS_DATA 0177 /* bus data mask */ +#define BUS_PARITY 0200 /* bus parity mask */ + +#define BUS_PCG 0000 /* primary command group */ +#define BUS_LAG 0040 /* listen address group */ +#define BUS_TAG 0100 /* talk address group */ +#define BUS_SCG 0140 /* secondary command group */ + +#define BUS_UCG 0020 /* universal command group */ +#define BUS_ACG 0000 /* addressed command group */ + +#define BUS_UNADDRESS 0037 /* unlisten and untalk addresses */ + +#define PPR(a) (uint8) (1 << (7 - (a))) /* parallel poll response */ + + +/* Byte accessors */ + +#define BYTE_SHIFT 8 /* byte shift count */ +#define UPPER_BYTE 0177400 /* high-order byte mask */ +#define LOWER_BYTE 0000377 /* low-order byte mask */ + +#define GET_UPPER(w) (uint8) (((w) & UPPER_BYTE) >> BYTE_SHIFT) +#define GET_LOWER(w) (uint8) ((w) & LOWER_BYTE) + +#define SET_UPPER(b) (uint16) ((b) << BYTE_SHIFT) +#define SET_LOWER(b) (uint16) (b) +#define SET_BOTH(b) (SET_UPPER (b) | SET_LOWER (b)) + +typedef enum { + upper, /* upper byte selected */ + lower /* lower byte selected */ + } SELECTOR; + + +/* Per-card state variables */ + +typedef struct { + FLIP_FLOP control; /* control flip-flop */ + FLIP_FLOP flag; /* flag flip-flop */ + FLIP_FLOP flagbuf; /* flag buffer flip-flop */ + FLIP_FLOP srq; /* SRQ flip-flop */ + FLIP_FLOP edt; /* EDT flip-flop */ + FLIP_FLOP eor; /* EOR flip-flop */ + SELECTOR ibp; /* input byte pointer selector */ + SELECTOR obp; /* output byte pointer selector */ + + uint16 cntl_register; /* control word register */ + uint16 status_register; /* status word register */ + uint16 input_data_register; /* input data register */ + + uint32 fifo [FIFO_SIZE]; /* FIFO buffer */ + uint32 fifo_count; /* FIFO occupancy counter */ + REG *fifo_reg; /* FIFO register pointer */ + + uint32 acceptors; /* unit bitmap of the bus acceptors */ + uint32 listeners; /* unit bitmap of the bus listeners */ + uint32 talker; /* unit bitmap of the bus talker */ + + uint8 bus_cntl; /* HP-IB bus control state (ATN, EOI, etc.) */ + uint8 poll_response; /* address bitmap of parallel poll responses */ + + double ifc_timer; /* 100 microsecond IFC timer */ + } DI_STATE; + + +/* Disc interface VM global register definitions. + + These definitions should be included before any device-specific registers. + + + Implementation notes: + + 1. The TMR register is included to ensure that the IFC timer is saved by a + SAVE command. It is declared as a hidden, read-only byte array of a size + compatible with a double-precision floating-point value, as there is no + appropriate macro for the double type. +*/ + +#define DI_REGS(dev) \ + { ORDATA (CWR, di [dev].cntl_register, 16), REG_FIT }, \ + { ORDATA (SWR, di [dev].status_register, 16), REG_FIT }, \ + { ORDATA (IDR, di [dev].input_data_register, 16), REG_FIT }, \ + \ + { DRDATA (FCNT, di [dev].fifo_count, 5) }, \ + { BRDATA (FIFO, di [dev].fifo, 8, 20, FIFO_SIZE), REG_CIRC }, \ + \ + { GRDATA (ACPT, di [dev].acceptors, 2, 4, 0) }, \ + { GRDATA (LSTN, di [dev].listeners, 2, 4, 0) }, \ + { GRDATA (TALK, di [dev].talker, 2, 4, 0) }, \ + { GRDATA (PPR, di [dev].poll_response, 2, 8, 0), REG_FIT }, \ + { GRDATA (BUSCTL, di [dev].bus_cntl, 2, 8, 0), REG_FIT }, \ + \ + { FLDATA (CTL, di [dev].control, 0) }, \ + { FLDATA (FLG, di [dev].flag, 0) }, \ + { FLDATA (FBF, di [dev].flagbuf, 0) }, \ + { FLDATA (SRQ, di [dev].srq, 0) }, \ + { FLDATA (EDT, di [dev].edt, 0) }, \ + { FLDATA (EOR, di [dev].eor, 0) }, \ + \ + { BRDATA (TMR, &di [dev].ifc_timer, 10, CHAR_BIT, sizeof (double)), REG_HRO }, \ + \ + { ORDATA (SC, dev##_dib.select_code, 6), REG_HRO } + + +/* Disc interface VM global modifier definitions. + + These definitions should be included before any device-specific modifiers. +*/ + +#define DI_MODS(dev) \ + { MTAB_XTD | MTAB_VDV, 1, "ADDRESS", "ADDRESS", &di_set_address, &di_show_address, &dev }, \ + \ + { MTAB_XTD | MTAB_VDV, 1, NULL, "DIAG", &di_set_cable, NULL, &dev }, \ + { MTAB_XTD | MTAB_VDV, 0, NULL, "HPIB", &di_set_cable, NULL, &dev }, \ + { MTAB_XTD | MTAB_VDV, 0, "CABLE", NULL, NULL, &di_show_cable, &dev }, \ + \ + { MTAB_XTD | MTAB_VDV, 0, "SC", "SC", &hp_setsc, &hp_showsc, &dev }, \ + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &dev }, \ + \ + { MTAB_XTD | MTAB_VUN, 0, "BUS", "BUS", &di_set_address, &di_show_address, &dev } + + +/* Disc interface global bus routine definitions */ + +typedef t_bool ACCEPTOR (uint32 unit, uint8 data); +typedef void RESPONDER (CARD_ID card, uint32 unit, uint8 new_cntl); + + +/* Disc interface global variables */ + +extern DI_STATE di []; +extern DEBTAB di_deb []; + + +/* Disc interface global VM routines */ + +extern IOHANDLER di_io; +extern t_stat di_reset (DEVICE *dptr); + +/* Disc interface global SCP routines */ + +extern t_stat di_set_address (UNIT *uptr, int32 value, char *cptr, void *desc); +extern t_stat di_show_address (FILE *st, UNIT *uptr, int32 value, void *desc); +extern t_stat di_set_cable (UNIT *uptr, int32 value, char *cptr, void *desc); +extern t_stat di_show_cable (FILE *st, UNIT *uptr, int32 value, void *desc); + +/* Disc interface global bus routines */ + +extern t_bool di_bus_source (CARD_ID card, uint8 data); +extern void di_bus_control (CARD_ID card, uint32 unit, uint8 assert, uint8 deny); +extern void di_poll_response (CARD_ID card, uint32 unit, FLIP_FLOP response); + + +/* Amigo disc global VM routines */ + +extern t_stat da_service (UNIT *uptr); +extern t_stat da_boot (int32 unitno, DEVICE *dptr); + +/* Amigo disc global bus routines */ + +extern ACCEPTOR da_bus_accept; +extern RESPONDER da_bus_respond; + + +/* Amigo mag tape global VM routines */ + +extern t_stat ma_service (UNIT *uptr); +extern t_stat ma_boot (int32 unitno, DEVICE *dptr); + +/* Amigo mag tape global SCP routines */ + +extern t_stat ma_set_timing (UNIT *uptr, int32 val, char *cptr, void *desc); +extern t_stat ma_show_timing (FILE *st, UNIT *uptr, int32 val, void *desc); + +/* Amigo mag tape global bus routines */ + +extern ACCEPTOR ma_bus_accept; +extern RESPONDER ma_bus_respond; diff --git a/HP2100/hp2100_di_da.c b/HP2100/hp2100_di_da.c index 005a6215..7020a0e3 100644 --- a/HP2100/hp2100_di_da.c +++ b/HP2100/hp2100_di_da.c @@ -1,2129 +1,2133 @@ -/* hp2100_di_da.c: HP 12821A HP-IB Disc Interface simulator for Amigo disc drives - - Copyright (c) 2011-2012, J. David Bryan - - 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 - THE AUTHOR 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 the author shall not be - used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from the author. - - DA 12821A Disc Interface with Amigo disc drives - - 29-Mar-12 JDB First release - 04-Nov-11 JDB Created DA device - - References: - - HP 13365 Integrated Controller Programming Guide (13365-90901, Feb-1980) - - HP 7910 Disc Drive Service Manual (07910-90903, Apr-1981) - - 12745D Disc Controller (13037) to HP-IB Adapter Kit Installation and - Service Manual (12745-90911, Sep-1983) - - HP's 5 1/4-Inch Winchester Disc Drive Service Documentation - (09134-90032, Aug-1983) - - HP 12992 Loader ROMs Installation Manual (12992-90001, Apr-1986) - - RTE Driver DVA32 Source (92084-18708, revision 2540) - - IEEE Standard Digital Interface for Programmable Instrumentation - (IEEE-488A-1980, Sep-1979) - - - The HP 7906H, 7920H, and 7925H Integrated Controller Disc (ICD) drives were - connected via an 12821A disc interface and provided 20MB, 50MB, and 120MB - capacities. The drives were identical to the 7906M, 7920M, and 7925M - Multi-Access Controller (MAC) units but incorporated internal two-card - controllers in each drive and connected to the CPU interface via the - Hewlett-Packard Interface Bus (HP-IB), HP's implementation of IEEE-488. Each - controller was dedicated to a single drive and operated similarly to the - 12745 Disc Controller to HP-IB Adapter option for the 13037 Disc Controller - chassis. The 7906H was introduced in 1980 (there was no 7905H version, as - the 7905 was obsolete by that time). Up to four ICD drives could be - connected to a single 12821A card. The limitation was imposed by the bus - loading and the target data transfer rate. - - The ICD command set essentially was the MAC command set modified for - single-unit operation. The unit number and CPU hold bit fields in the opcode - words were unused in the ICD implementation. The Load TIO Register, Wakeup, - and Request Syndrome commands were removed, as Load TIO was used with the HP - 3000, Wakeup was used in a multi-CPU environment, and the simpler ICD - controller did not support ECC. Controller status values 02B (Unit - Available) and 27B (Unit Unavailable) were dropped as the controller - supported only single units, 12B (I/O Program Error) was reused to indicate - HP-IB protocol errors, 13B (Sync Not Received) was added, and 17B (Possibly - Correctable Data Error) was removed as error correction was not supported. - - Some minor redefinitions also occurred. For example, status 14B (End of - Cylinder) was expanded to include an auto-seek beyond the drive limits, and - 37B (Drive Attention) was restricted just head unloads from head loads and - unloads. - - The command set was expanded to include several commands related to HP-IB - operation. These were, in large part, adapted from the Amigo disc command - protocol outlined in the service manual for the HP 9133/34/35 series of - 5-1/4" Winchester drives. They include the Amigo Identify and Amigo Clear - sequences, Read and Write Loopback channel tests, and controller Self Test - commands. - - This simulator implements the Amigo disc protocol. It calls the 12821A Disc - Interface (DI) simulator to send and receive bytes across the HP-IB to and - from the CPU, and it calls the HP Disc Library to implement the controller - functions related to disc unit operation (e.g., seek, read, write, etc.). - Four units are provided, and any combination of 7906H/20H/25H drives may be - defined. - - Unfortunately, the primary reference for the ICD controller (the HP 13365 - Integrated Controller Programming Guide) does not indicate parallel poll - responses for these HP-IB commands. Therefore, the responses have been - derived from the sequences in the 7910 and 12745 manuals, although they - sometimes conflict. - - The drives respond to the following commands; the secondary and opcode - numeric values are in hex, and the bus addressing state is indicated by U - [untalk], L [listen], and T [talk]: - - Bus Sec Op Operation - --- --- -- -------------------------------- - U MSA -- Amigo Identify - - L 00 -- Write Data - L 08 00 Cold Load Read - L 08 01 Recalibrate - L 08 02 Seek - L 08 03 Request Status - L 08 04 Request Sector Address - L 08 05 Read - L 08 06 Read Full Sector - L 08 07 Verify - L 08 08 Write - L 08 09 Write Full Sector - L 08 0A Clear - L 08 0B Initialize - L 08 0C Address Record - L 08 0E Read with Offset - L 08 0F Set File Mask - L 08 12 Read without Verify - L 08 14 Request Logical Disc Address - L 08 15 End - L 09 -- Cyclic Redundancy Check - L 10 -- Amigo Clear - L 1E -- Write Loopback - L 1F ss Initiate Self-Test - - T 00 -- Read Data - T 08 -- Read Status - T 09 -- Cyclic Redundancy Check - T 10 -- Device Specified Jump - T 1E -- Read Loopback - T 1F -- Return Self-Test Result - - In addition, the controller responds to the Selected Device Clear primary - (04). - - - HP-IB Transaction Sequences - =========================== - - Amigo Identify - - ATN UNT Untalk - ATN MSA My secondary address - DAB ID data byte #1 = 00H - EOI DAB ID data byte #2 = 03H - ATN OTA Talk 30 - - - Amigo Clear - - ATN MLA My listen address - ATN SCG Secondary command 10H - ppd Parallel poll disabled - EOI DAB Unused data byte - ATN SDC Selected device clear - ATN UNL Unlisten - ... - ppe Parallel poll enabled when clear completes - - - CRC - - ATN MTA My talk address - ATN SCG Secondary command 09H - ppd Parallel poll disabled - DAB Data byte #1 - ... - EOI DAB Data byte #n - ppe Parallel poll enabled - ATN UNT Untalk - - or - - ATN MLA My listen address - ATN SCG Secondary command 09H - ppd Parallel poll disabled - DAB Data byte #1 - ... - EOI DAB Data byte #n - ppe Parallel poll enabled - ATN UNL Unlisten - - - Device Specified Jump - - ATN MTA My talk address - ATN SCG Secondary command 10H - ppd Parallel poll disabled - EOI DAB DSJ data byte - ATN UNT Untalk - - - Initiate Self-Test and Return Self-Test Result - - ATN MLA My listen address - ATN SCG Secondary command 1FH - ppd Parallel poll disabled - EOI DAB Self-test number - ppe Parallel poll enabled - ATN UNL Unlisten - - ATN MTA My talk address - ATN SCG Secondary command 1FH - ppd Parallel poll disabled - EOI DAB Result data byte - ppe Parallel poll enabled - ATN UNT Untalk - - - Write Loopback and Read Loopback - - ATN MLA My listen address - ATN SCG Secondary command 1EH - ppd Parallel poll disabled - DAB Loopback data byte #1 - ... - EOI DAB Loopback data byte #256 - ppe Parallel poll enabled - ATN UNL Unlisten - - ATN MTA My talk address - ATN SCG Secondary command 1EH - ppd Parallel poll disabled - DAB Loopback data byte #1 - ... - EOI DAB Loopback data byte #16 - ppe Parallel poll enabled - ATN UNT Untalk - - - Recalibrate and Seek - - ATN MLA My listen address - ATN SCG Secondary command 08H - ppd Parallel poll disabled - DAB Opcode 01H, 02H - ... (one to five - EOI DAB parameter bytes) - ATN UNL Unlisten - ... - ppe Parallel poll enabled when seek completes - - - Clear, Address Record, and Set File Mask - - ATN MLA My listen address - ATN SCG Secondary command 08H - ppd Parallel poll disabled - DAB Opcode 0AH, 0CH, 0FH - ... (one to five - EOI DAB parameter bytes) - ppe Parallel poll enabled - ATN UNL Unlisten - - - End - - ATN MLA My listen address - ATN SCG Secondary command 08H - ppd Parallel poll disabled - DAB Opcode 15H - EOI DAB Unused data byte - ATN UNL Unlisten - - - Request Status, Request Sector Address, and Request Logical Disc Address - - ATN MLA My listen address - ATN SCG Secondary command 08H - ppd Parallel poll disabled - DAB Opcode 03H, 04H, 14H - EOI DAB Unused data byte - ATN UNL Unlisten - - ATN MTA My talk address - ATN SCG Secondary command 08H - DAB Status byte #1 - ... (two to four - EOI DAB status bytes) - ppe Parallel poll enabled - ATN UNT Untalk - - - Cold Load Read, Read, Read Full Sector, Verify, Read with Offset, and Read - without Verify - - ATN MLA My listen address - ATN SCG Secondary command 08H - ppd Parallel poll disabled - DAB Opcode 00H, 05H, 06H, 07H, 0EH, 12H - EOI DAB Unused data byte - ATN UNL Unlisten - - ATN MTA My talk address - ATN SCG Secondary command 00H - DAB Read data byte #1 - ... - DAB Read data byte #n - ATN UNT Untalk - ... - ppe Parallel poll enabled when sector ends - - - Write, Write Full Sector, and Initialize - - ATN MLA My listen address - ATN SCG Secondary command 08H - ppd Parallel poll disabled - DAB Opcode 08H, 09H, 0BH - EOI DAB Unused data byte - ATN UNL Unlisten - - ATN MLA My listen address - ATN SCG Secondary command 00H - DAB Write data byte #1 - ... - EOI DAB Write data byte #n - ppe Parallel poll enabled - ATN UNL Unlisten - - - Implementation notes: - - 1. The 12745 does not alter the parallel poll response for the - Device-Specified Jump command. - - 2. The 7910 does not perform a parallel poll response enable and disable - between the Initiate Self-Test and Return Self-Test Result commands. - - 3. The 12745 does not disable the parallel poll response for the Read - Loopback command. -*/ - - - -#include "hp2100_defs.h" -#include "hp2100_di.h" -#include "hp_disclib.h" - - - -/* Program constants */ - -#define DA_UNITS 4 /* number of addressable disc units */ - - -/* Interface states */ - -typedef enum { - idle = 0, /* idle = default for reset */ - opcode_wait, /* waiting for opcode reception */ - parameter_wait, /* waiting for parameter reception */ - read_wait, /* waiting for send read data secondary */ - write_wait, /* waiting for receive write data secondary */ - status_wait, /* waiting for send status secondary */ - command_exec, /* executing an interface command */ - command_wait, /* waiting for command completion */ - read_xfer, /* sending read data or status */ - write_xfer, /* receiving write data */ - error_source, /* sending bytes for error recovery */ - error_sink /* receiving bytes for error recovery */ - } IF_STATE; - - -/* Interface state names */ - -static const char *if_state_name [] = { - "idle", - "opcode wait", - "parameter wait", - "read wait", - "write wait", - "status wait", - "command execution", - "command wait", - "read transfer", - "write transfer", - "error source", - "error sink" - }; - - -/* Next interface state after command recognition */ - -static const IF_STATE next_state [] = { - read_wait, /* cold load read */ - command_exec, /* recalibrate */ - command_exec, /* seek */ - status_wait, /* request status */ - status_wait, /* request sector address */ - read_wait, /* read */ - read_wait, /* read full sector */ - command_exec, /* verify */ - write_wait, /* write */ - write_wait, /* write full sector */ - command_exec, /* clear */ - write_wait, /* initialize */ - command_exec, /* address record */ - idle, /* request syndrome */ - read_wait, /* read with offset */ - command_exec, /* set file mask */ - idle, /* invalid */ - idle, /* invalid */ - read_wait, /* read without verify */ - idle, /* load TIO register */ - status_wait, /* request disc address */ - command_exec, /* end */ - idle /* wakeup */ - }; - - -/* Interface commands */ - -typedef enum { - invalid = 0, /* invalid = default for reset */ - disc_command, /* MLA 08 */ - crc_listen, /* MLA 09 */ - amigo_clear, /* MLA 10 */ - write_loopback, /* MLA 1E */ - initiate_self_test, /* MLA 1F */ - crc_talk, /* MTA 09 */ - device_specified_jump, /* MTA 10 */ - read_loopback, /* MTA 1E */ - return_self_test_result, /* MTA 1F */ - amigo_identify /* UNT MSA */ - } IF_COMMAND; - -/* Interface command names */ - -static const char *if_command_name [] = { - "invalid", - "disc command", - "CRC listen", - "Amigo clear", - "write loopback", - "initiate self-test", - "CRC talk", - "device specified jump", - "read loopback", - "return self-test result", - "Amigo identify" - }; - - - -/* Amigo disc state variables */ - -static uint16 buffer [DL_BUFSIZE]; /* command/status/sector buffer */ - -static uint8 if_dsj [DA_UNITS]; /* ICD controller DSJ values */ -static IF_STATE if_state [DA_UNITS]; /* ICD controller state */ -static IF_COMMAND if_command [DA_UNITS]; /* ICD controller command */ - -static CNTLR_VARS icd_cntlr [DA_UNITS] = /* ICD controllers: */ - { { CNTLR_INIT (ICD, buffer, NULL) }, /* unit 0 controller */ - { CNTLR_INIT (ICD, buffer, NULL) }, /* unit 1 controller */ - { CNTLR_INIT (ICD, buffer, NULL) }, /* unit 2 controller */ - { CNTLR_INIT (ICD, buffer, NULL) } }; /* unit 3 controller */ - - - -/* Amigo disc global VM routines */ - -t_stat da_service (UNIT *uptr); -t_stat da_reset (DEVICE *dptr); -t_stat da_attach (UNIT *uptr, char *cptr); -t_stat da_detach (UNIT *uptr); -t_stat da_boot (int32 unitno, DEVICE *dptr); - -/* Amigo disc global SCP routines */ - -t_stat da_load_unload (UNIT *uptr, int32 value, char *cptr, void *desc); - -/* Amigo disc global bus routines */ - -t_bool da_bus_accept (uint32 unit, uint8 data); -void da_bus_respond (CARD_ID card, uint32 unit, uint8 new_cntl); - -/* Amigo disc local utility routines */ - -static t_bool start_command (uint32 unit); -static void abort_command (uint32 unit, CNTLR_STATUS status, IF_STATE state); -static void complete_read (uint32 unit); -static void complete_write (uint32 unit); -static void complete_abort (uint32 unit); -static uint8 get_buffer_byte (CVPTR cvptr); -static void put_buffer_byte (CVPTR cvptr, uint8 data); -static t_stat activate_unit (UNIT *uptr); - - - -/* Amigo disc VM global data structures. - - da_dib DA device information block - da_unit DA unit list - da_reg DA register list - da_mod DA modifier list - da_dev DA device descriptor - - - Implementation notes: - - 1. The IFSTAT and IFCMD registers are declared to accommodate the - corresponding arrays of enums. Arrayed registers assume that elements - are allocated space only to the integral number of bytes implied by the - "width" field. The storage size of an enum is implementation-defined, so - we must determine the number of bits for "width" at compile time. - PV_LEFT is used to avoid the large number of leading zeros that would be - displayed if an implementation stored enums in full words. - - 2. The CNVARS register is included to ensure that the controller state - variables array is saved by a SAVE command. It is declared as a hidden, - read-only byte array of a depth compatible with the size of the array. - - There does not appear to be a way to expose the fields of the four - controller state variables as arrayed registers. Access to an array - always assumes that elements appear at memory offsets equal to the - element size, i.e., a 32-bit arrayed register has elements at four-byte - offsets. There's no way to specify an array of structure elements where - a given 32-bit field appears at, say, 92-byte offsets (i.e., the size of - the structure). -*/ - -DEVICE da_dev; - -DIB da_dib = { &di_io, DI_DA, da }; - -#define UNIT_FLAGS (UNIT_FIX | UNIT_ATTABLE | UNIT_ROABLE | UNIT_DISABLE | UNIT_UNLOAD) - -UNIT da_unit [] = { - { UDATA (&da_service, UNIT_FLAGS | MODEL_7906 | SET_BUSADR (0), D7906_WORDS) }, /* drive unit 0 */ - { UDATA (&da_service, UNIT_FLAGS | MODEL_7906 | SET_BUSADR (1), D7906_WORDS) }, /* drive unit 1 */ - { UDATA (&da_service, UNIT_FLAGS | MODEL_7906 | SET_BUSADR (2), D7906_WORDS) }, /* drive unit 2 */ - { UDATA (&da_service, UNIT_FLAGS | MODEL_7906 | SET_BUSADR (3), D7906_WORDS) } /* drive unit 3 */ - }; - -REG da_reg [] = { - DI_REGS (da), - - { BRDATA (BUFFER, buffer, 8, 16, DL_BUFSIZE) }, - - { BRDATA (DSJ, if_dsj, 10, 2, DA_UNITS) }, - { BRDATA (ISTATE, if_state, 10, sizeof (IF_STATE) * CHAR_BIT, DA_UNITS), PV_LEFT }, - { BRDATA (ICMD, if_command, 10, sizeof (IF_COMMAND) * CHAR_BIT, DA_UNITS), PV_LEFT }, - - { BRDATA (CNVARS, icd_cntlr, 10, CHAR_BIT, sizeof (CNTLR_VARS) * DA_UNITS), REG_HRO }, - - { NULL } - }; - -MTAB da_mod [] = { - DI_MODS (da_dev), - - { UNIT_UNLOAD, UNIT_UNLOAD, "heads unloaded", "UNLOADED", &da_load_unload, NULL, NULL }, - { UNIT_UNLOAD, 0, "heads loaded", "LOADED", &da_load_unload, NULL, NULL }, - - { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL, NULL, NULL }, - { UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL, NULL, NULL }, - - { UNIT_FMT, UNIT_FMT, "format enabled", "FORMAT", NULL, NULL, NULL }, - { UNIT_FMT, 0, "format disabled", "NOFORMAT", NULL, NULL, NULL }, - - { UNIT_MODEL, MODEL_7906, "7906H", "7906H", &dl_set_model, NULL, NULL }, - { UNIT_MODEL, MODEL_7920, "7920H", "7920H", &dl_set_model, NULL, NULL }, - { UNIT_MODEL, MODEL_7925, "7925H", "7925H", &dl_set_model, NULL, NULL }, - - { 0 } - }; - -DEVICE da_dev = { - "DA", /* device name */ - da_unit, /* unit array */ - da_reg, /* register array */ - da_mod, /* modifier array */ - DA_UNITS, /* number of units */ - 10, /* address radix */ - 26, /* address width */ - 1, /* address increment */ - 8, /* data radix */ - 16, /* data width */ - NULL, /* examine routine */ - NULL, /* deposit routine */ - &da_reset, /* reset routine */ - &da_boot, /* boot routine */ - &da_attach, /* attach routine */ - &da_detach, /* detach routine */ - &da_dib, /* device information block */ - DEV_DEBUG | DEV_DISABLE, /* device flags */ - 0, /* debug control flags */ - di_deb, /* debug flag name table */ - NULL, /* memory size change routine */ - NULL /* logical device name */ - }; - - - -/* Amigo disc global VM routines */ - - -/* Service an Amigo disc drive I/O event. - - The service routine is called to execute commands and control the transfer of - data to and from the HP-IB card. The actions to be taken depend on the - current state of the ICD interface. The possibilities are: - - 1. A command is pending on the interface. This occurs only when a command - is received while a Seek or Recalibrate command is in progress. - - 2. A command is executing. - - 3. Data is being sent or received over the HP-IB during command execution. - - 4. Dummy bytes are being sent or received over the HP-IB due to a command - error. - - Entry to the the service routine in any other interface state or to process a - command not allowed in a valid state will return an Internal Error to cause a - simulator stop. Exit from the routine will be either in one of the above - states, or in the idle state if the operation is complete. - - The specific actions taken for the various interface states are as follows: - - command_wait - ============ - - We are entered in this state only if a unit that was busy (still seeking) - was addressed to listen or talk. The card has been held off by asserting - NRFD after receiving MLA or MTA. Upon entry, we complete the seek and then - release the interface by denying NRFD to allow the remainder of the command - sequence to be received from the card. - - command_exec - ============ - - We are entered in this state to initiate, continue, or complete a command. - The command may be a disc command, such as Seek or Read, or an interface - command, such as Amigo Identify or Device-Specified Jump. - - Disc commands call the disc library service routine to perform all of the - common controller actions. Any ICD-specific actions needed, such as - setting the DSJ value, are performed after the call. - - Certain disc commands require multiple execution phases. For example, the - Read command has a start phase that reads data from the disc image file - into the sector buffer, a data phase that transfers bytes from the buffer - to the card, and an end phase that schedules the intersector gap time and - resets to the start phase. Data phase transfers are performed in the - read_xfer or write_xfer interface states. - - The results of the disc library service are inferred by the controller - state. If the controller is busy, then the command continues in a new - phase. Otherwise, the command either has completed normally or has - terminated with an error. If an error has occurred during a disc command - that transfers data, DSJ is set to 1, and the interface state is changed to - source or sink dummy bytes to complete the command sequence. - - Interface commands may either complete immediately (e.g., Amigo Clear) or - transfer data (e.g., DSJ). - - read_xfer - ========= - - Commands that send data to the CPU enter the service routine to source a - byte to the bus. Bytes are transferred only when ATN and NRFD are denied; - if they are not, we simply exit, as we will be rescheduled when the lines - are dropped. Otherwise, we get a byte from the sector buffer and send it - to the card. If the card has stopped listening, or the buffer is now - empty, then we terminate the transfer and move to the end phase of the - command. Otherwise, we reschedule the next data phase byte transfer. - - Disc and interface commands are handled separately, as EOI is always - asserted on the last byte of an interface command transfer and never on a - (good) disc command transfer. - - write_xfer - ========== - - Commands that receive data from the CPU enter the service routine to - determine whether or not to continue the transfer. Our bus accept routine - has already stored the received byte in the sector buffer and has asserted - NRFD to hold off the card. If the buffer is now full, or the byte was - tagged with EOI, then we terminate the transfer and move to the end phase - of the command. Otherwise, we deny NRFD and exit; we will be rescheduled - when the next byte arrives. - - error_source - ============ - - If an error occurred during the data transfer phase of a read or status - command, a dummy byte tagged with EOI is sourced to the bus. This allows - the OS driver for the card to terminate the command and request the - controller's status. - - error_sink - ========== - - If an error occurred during the data transfer phase of a write command, - dummy bytes are sunk from the bus until EOI is seen or the card is - unaddressed. This allows the OS driver to complete the command as expected - and then determine the cause of the failure by requesting the controller's - status. - - - Implementation notes: - - 1. The disc library sets the controller state to idle for a normal End, - Seek, or Recalibrate command and to wait for all other commands that end - normally. So we determine command completion by checking if the - controller is not busy, rather than checking if the controller is idle. - - Drive Attention status is the normal result of the completion of a Seek - or Recalibrate command. Normal Completion status is the normal result of - all other commands. - - 2. The disc library returns the buffer length in words. We double the - return value to count bytes. - - 3. Some commands, such as DSJ, could be completed in the bus accept routine. - They are serviced here instead to avoid presenting a zero execution time - to the CPU. - - 4. The Amigo command set does not provide the disc with the number of bytes - that will be read, and the unit expects to be untalked when the read is - to terminate. The RTE ICD bootstrap extension does not do this. - Instead, it resets the card via CLC 0,C to terminate the Cold Load Read - that was started by the ICD boot loader ROM. - - In hardware, if the LSTN control bit is cleared, e.g., by CRS, - transmission stops because the card denies NDAC and NRFD (the HP-IB - handshake requires NDAC and NRFD to be asserted to start the handshake - sequence; TACS * SDYS * ~NDAC * ~NRFD is an error condition). In - simulation, we handle this by terminating a read transfer if the card - stops accepting. If we did not, then the disc would continue to source - bytes to the bus, overflowing the card FIFO (a FIFO full condition cannot - assert NRFD if the LSTN control bit is clear). -*/ - -t_stat da_service (UNIT *uptr) -{ -uint8 data; -CNTLR_CLASS command_class; -const int32 unit = uptr - da_unit; /* get the disc unit number */ -const CVPTR cvptr = &icd_cntlr [unit]; /* get a pointer to the controller */ -t_stat result = SCPE_OK; -t_bool release_interface = FALSE; - -switch (if_state [unit]) { /* dispatch the interface state */ - - case command_wait: /* command is waiting */ - release_interface = TRUE; /* release the interface at then end if it's idle */ - - /* fall into the command_exec handler to process the current command */ - - case command_exec: /* command is executing */ - switch (if_command [unit]) { /* dispatch the interface command */ - - case disc_command: /* execute a disc command */ - result = dl_service_drive (cvptr, uptr); /* service the disc unit */ - - if (cvptr->opcode == clear) /* is this a Clear command? */ - if_dsj [unit] = 2; /* indicate that the self test is complete */ - - if (cvptr->state != cntlr_busy) { /* has the controller stopped? */ - if_state [unit] = idle; /* idle the interface */ - - if (cvptr->status == normal_completion || /* do we have normal completion */ - cvptr->status == drive_attention) /* or drive attention? */ - break; /* we're done */ - - else { /* if the status is abnormal */ - if_dsj [unit] = 1; /* an error has occurred */ - - command_class = dl_classify (*cvptr); /* classify the command */ - - if (command_class == class_write) { /* did a write command fail? */ - if_state [unit] = error_sink; /* sink the remaining bytes */ - uptr->wait = cvptr->cmd_time; /* activate to complete processing */ - } - - else if (command_class != class_control) { /* did a read or status command fail? */ - if_state [unit] = error_source; /* source an error byte */ - uptr->wait = cvptr->cmd_time; /* activate to complete processing */ - } - } - } - - else if (uptr->PHASE == data_phase) { /* are we starting the data phase? */ - cvptr->length = cvptr->length * 2; /* convert the buffer length to bytes */ - - if (dl_classify (*cvptr) == class_write) /* is this a write command? */ - if_state [unit] = write_xfer; /* set for a write data transfer */ - else /* it is a read or status command */ - if_state [unit] = read_xfer; /* set for a read data transfer */ - } - - break; - - - case amigo_identify: /* Amigo Identify */ - buffer [0] = 0x0003; /* store the response in the buffer */ - cvptr->length = 2; /* return two bytes */ - - if_state [unit] = read_xfer; /* we are ready to transfer the data */ - uptr->wait = cvptr->cmd_time; /* schedule the transfer */ - - if (DEBUG_PRI (da_dev, DEB_RWSC)) - fprintf (sim_deb, ">>DA rwsc: Unit %d Amigo identify response %04XH\n", - unit, buffer [0]); - break; - - - case initiate_self_test: /* Initiate a self test */ - sim_cancel (&da_unit [unit]); /* cancel any operation in progress */ - dl_clear_controller (cvptr, /* hard-clear the controller */ - &da_unit [unit], - hard_clear); - if_dsj [unit] = 2; /* set DSJ for self test completion */ - if_state [unit] = idle; /* the command is complete */ - di_poll_response (da, unit, SET); /* with PPR enabled */ - break; - - - case amigo_clear: /* Amigo clear */ - dl_idle_controller (cvptr); /* idle the controller */ - if_dsj [unit] = 0; /* clear the DSJ value */ - if_state [unit] = idle; /* the command is complete */ - di_poll_response (da, unit, SET); /* with PPR enabled */ - break; - - - default: /* no other commands are executed */ - result = SCPE_IERR; /* signal an internal error */ - break; - } /* end of command dispatch */ - break; - - - case error_source: /* send data after an error */ - if (! (di [da].bus_cntl & (BUS_ATN | BUS_NRFD))) { /* is the card ready for data? */ - di [da].bus_cntl |= BUS_EOI; /* set EOI */ - di_bus_source (da, 0); /* and send a dummy byte to the card */ - if_state [unit] = idle; /* the command is complete */ - } - break; - - - case read_xfer: /* send read data */ - if (! (di [da].bus_cntl & (BUS_ATN | BUS_NRFD))) /* is the card ready for data? */ - switch (if_command [unit]) { /* dispatch the interface command */ - - case disc_command: /* disc read or status commands */ - data = get_buffer_byte (cvptr); /* get the next byte from the buffer */ - - if (di_bus_source (da, data) == FALSE) /* send the byte to the card; is it listening? */ - cvptr->eod = SET; /* no, so terminate the read */ - - if (cvptr->length == 0 || cvptr->eod == SET) { /* is the data phase complete? */ - uptr->PHASE = end_phase; /* set the end phase */ - - if (cvptr->opcode == request_status) /* is it a Request Status command? */ - if_dsj [unit] = 0; /* clear the DSJ value */ - - if_state [unit] = command_exec; /* set to execute the command */ - uptr->wait = cvptr->cmd_time; /* and reschedule the service */ - } - - else /* the data phase continues */ - uptr->wait = cvptr->data_time; /* reschedule the next transfer */ - - break; - - - case amigo_identify: - case read_loopback: - case return_self_test_result: - data = get_buffer_byte (cvptr); /* get the next byte from the buffer */ - - if (cvptr->length == 0) /* is the transfer complete? */ - di [da].bus_cntl |= BUS_EOI; /* set EOI */ - - if (di_bus_source (da, data) /* send the byte to the card; is it listening? */ - && cvptr->length > 0) /* and is there more to transfer? */ - uptr->wait = cvptr->data_time; /* reschedule the next transfer */ - - else { /* the transfer is complete */ - if_state [unit] = idle; /* the command is complete */ - di_poll_response (da, unit, SET); /* enable the PPR */ - } - break; - - - case device_specified_jump: - di [da].bus_cntl |= BUS_EOI; /* set EOI */ - di_bus_source (da, if_dsj [unit]); /* send the DSJ value to the card */ - if_state [unit] = idle; /* the command is complete */ - break; - - - case crc_talk: - di [da].bus_cntl |= BUS_EOI; /* set EOI */ - di_bus_source (da, 0); /* send dummy bytes */ - break; /* until the card untalks */ - - - default: /* no other commands send data */ - result = SCPE_IERR; /* signal an internal error */ - break; - } /* end of read data transfer dispatch */ - break; - - - case error_sink: /* absorb data after an error */ - cvptr->index = 0; /* absorb data until EOI asserts */ - - if (cvptr->eod == SET) /* is the transfer complete? */ - if_state [unit] = idle; /* the command is complete */ - - di_bus_control (da, unit, 0, BUS_NRFD); /* deny NRFD to allow the card to resume */ - break; - - - case write_xfer: /* receive write data */ - switch (if_command [unit]) { /* dispatch the interface command */ - - case disc_command: /* disc write commands */ - if (cvptr->length == 0 || cvptr->eod == SET) { /* is the data phase complete? */ - uptr->PHASE = end_phase; /* set the end phase */ - - if_state [unit] = command_exec; /* set to execute the command */ - uptr->wait = cvptr->cmd_time; /* and schedule the service */ - - if (cvptr->eod == CLEAR) /* is the transfer continuing? */ - break; /* do not deny NRFD until next service! */ - } - - di_bus_control (da, unit, 0, BUS_NRFD); /* deny NRFD to allow the card to resume */ - break; - - - case write_loopback: - if (cvptr->eod == SET) { /* is the transfer complete? */ - cvptr->length = 16 - cvptr->length; /* set the count of bytes transferred */ - if_state [unit] = idle; /* the command is complete */ - } - - di_bus_control (da, unit, 0, BUS_NRFD); /* deny NRFD to allow the card to resume */ - break; - - - default: /* no other commands receive data */ - result = SCPE_IERR; /* signal an internal error */ - break; - } /* end of write data transfer dispatch */ - break; - - - default: /* no other states schedule service */ - result = SCPE_IERR; /* signal an internal error */ - break; - } /* end of interface state dispatch */ - - -if (uptr->wait) /* is service requested? */ - activate_unit (uptr); /* schedule the next event */ - -if (result == SCPE_IERR && DEBUG_PRI (da_dev, DEB_RWSC)) { /* did an internal error occur? */ - fprintf (sim_deb, ">>DA rwsc: Unit %d ", unit); /* report it if debugging */ - - if (if_state [unit] == command_exec - && if_command [unit] == disc_command) - fprintf (sim_deb, "%s command %s phase ", - dl_opcode_name (ICD, (CNTLR_OPCODE) uptr->OP), - dl_phase_name ((CNTLR_PHASE) uptr->PHASE)); - else - fprintf (sim_deb, "%s state %s ", - if_command_name [if_command [unit]], - if_state_name [if_state [unit]]); - - fputs ("service not handled\n", sim_deb); - } - -if (if_state [unit] == idle) { /* is the command now complete? */ - if (if_command [unit] == disc_command) { /* did a disc command complete? */ - if (cvptr->opcode != end) /* yes; if the command was not End, */ - di_poll_response (da, unit, SET); /* then enable PPR */ - - if (DEBUG_PRI (da_dev, DEB_RWSC)) - fprintf (sim_deb, ">>DA rwsc: Unit %d %s disc command completed\n", - unit, dl_opcode_name (ICD, cvptr->opcode)); - } - - else /* an interface command completed */ - if (DEBUG_PRI (da_dev, DEB_RWSC)) - fprintf (sim_deb, ">>DA rwsc: Unit %d %s command completed\n", - unit, if_command_name [if_command [unit]]); - - if (release_interface) /* if the next command is already pending */ - di_bus_control (da, unit, 0, BUS_NRFD); /* deny NRFD to allow the card to resume */ - } - -return result; /* return the result of the service */ -} - - -/* Reset or preset the simulator. - - In hardware, a self-test is performed by the controller at power-on. When - the self-test completes, the controller sets DSJ = 2 and enables the parallel - poll response. - - A front panel PRESET or programmed CRS has no direct effect on the controller - or drive. However, the card reacts to CRS by clearing its talker and - listener states, so an in-progress read or status command will abort when the - next byte sourced to the bus finds no acceptors. -*/ - -t_stat da_reset (DEVICE *dptr) -{ -uint32 unit; -t_stat status; - -status = di_reset (dptr); /* reset the card */ - -if (status == SCPE_OK && (sim_switches & SWMASK ('P'))) /* is the card OK and is this a power-on reset? */ - for (unit = 0; unit < dptr->numunits; unit++) { /* loop through the units */ - sim_cancel (dptr->units + unit); /* cancel any current activation */ - dptr->units [unit].CYL = 0; /* reset the head position */ - dptr->units [unit].pos = 0; /* to cylinder 0 */ - - dl_clear_controller (&icd_cntlr [unit], /* hard-clear the controller */ - dptr->units + unit, - hard_clear); - - if_state [unit] = idle; /* reset the interface state */ - if_command [unit] = invalid; /* reset the interface command */ - - if_dsj [unit] = 2; /* set the DSJ for power up complete */ - } - -return status; -} - - -/* Attach a unit to a disc image file. - - The simulator considers an attached unit to be connected to the bus and an - unattached unit to be disconnected, so we set the card's acceptor bit for the - selected unit if the attach is successful. An attached unit is ready if the - heads are loaded or not ready if not. - - This model is slightly different than the MAC (DS) simulation, where an - unattached unit is considered "connected but not ready" -- the same - indication returned by an attached unit whose heads are unloaded. Therefore, - the situation when the simulator is started is that all DS units are - "connected to the controller but not ready," whereas all DA units are "not - connected to the bus." This eliminates the overhead of sending HP-IB - messages to unused units. - - In tabular form, the simulator responses are: - - Enabled Loaded Attached DS (MAC) DA (ICD) - ------- ------ -------- ------------ ------------ - N N N disconnected disconnected - N N Y -- -- - N Y N -- -- - N Y Y -- -- - Y N N unloaded disconnected - Y N Y unloaded unloaded - Y Y N -- -- - Y Y Y ready ready - - The unspecified responses are illegal conditions; for example, the simulator - does not allow an attached unit to be disabled. - - - Implementation notes: - - 1. To conform exactly to the MAC responses would have required intercepting - the SET DISABLED/ENABLED commands in order to clear or set the unit - accepting bits. However, short of intercepting the all SET commands with - a custom command table, there is no way to ensure that unit enables are - observed. Adding ENABLED and DISABLED to the modifiers table and - specifying a validation routine works for the DISABLED case but not the - ENABLED case -- set_unit_enbdis returns SCPE_UDIS before calling the - validation routine. -*/ - -t_stat da_attach (UNIT *uptr, char *cptr) -{ -t_stat result; -const int32 unit = uptr - da_unit; /* calculate the unit number */ - -result = dl_attach (&icd_cntlr [unit], uptr, cptr); /* attach the drive */ - -if (result == SCPE_OK) /* was the attach successful? */ - di [da].acceptors |= (1 << unit); /* set the unit's accepting bit */ - -return result; -} - - -/* Detach a disc image file from a unit. - - As explained above, detaching a unit is the hardware equivalent of - disconnecting the drive from the bus, so we clear the unit's acceptor bit if - the detach is successful. -*/ - -t_stat da_detach (UNIT *uptr) -{ -t_stat result; -const int32 unit = uptr - da_unit; /* calculate the unit number */ - -result = dl_detach (&icd_cntlr [unit], uptr); /* detach the drive */ - -if (result == SCPE_OK) { /* was the detach successful? */ - di [da].acceptors &= ~(1 << unit); /* clear the unit's accepting bit */ - di_poll_response (da, unit, CLEAR); /* and its PPR, as it's no longer present */ - } - -return result; -} - - -/* Boot an Amigo disc drive. - - The ICD disc bootstrap program is loaded from the HP 12992H Boot Loader ROM - into memory, the I/O instructions are configured for the interface card's - select code, and the program is run to boot from the specified unit. The - loader supports booting the disc at bus address 0 only. Before execution, - the S register is automatically set as follows: - - 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 - ------ ------ ---------------------- ------------- ----- - ROM # 0 1 select code reserved head - - The boot routine sets bits 15-6 of the S register to appropriate values. - Bits 5-3 and 1-0 retain their original values, so S should be set before - booting. These bits are typically set to 0, although bit 5 is set for an RTE - reconfiguration boot, and bits 1-0 may be set if booting from a head other - than 0 is desired. -*/ - -static const BOOT_ROM da_rom = { - 0102501, /* START LIA 1 GET SWITCH REGISTER SETTING */ - 0100044, /* LSL 4 SHIFT A LEFT 4 */ - 0006111, /* CLE,SLB,RSS SR BIT 12 SET FOR MANUAL BOOT? */ - 0100041, /* LSL 1 NO. SHIFT HEAD # FOR RPL BOOT */ - 0001424, /* ALR,ALR SHIFT HEAD 2, CLEAR SIGN */ - 0033744, /* IOR HDSEC SET EOI BIT */ - 0073744, /* STA HDSEC PLACE IN COMMAND BUFFER */ - 0017756, /* JSB BTCTL SEND DUMMY,U-CLR,PP */ - 0102510, /* LIA IBI READ INPUT REGISTER */ - 0101027, /* ASR 7 SHIFT DRIVE 0 RESPONSE TO LSB */ - 0002011, /* SLA,RSS DID DRIVE 0 RESPOND? */ - 0027710, /* JMP *-3 NO, GO LOOK AGAIN */ - 0107700, /* CLC 0,C */ - 0017756, /* JSB BTCTL SEND TALK, CL-RD,BUS HOLDER */ - 0002300, /* CCE */ - 0017756, /* JSB BTCTL TELL CARD TO LISTEN */ - 0063776, /* LDA DMACW LOAD DMA CONTROL WORD */ - 0102606, /* OTA 6 OUTPUT TO DCPC */ - 0106702, /* CLC 2 READY DCPC */ - 0063735, /* LDA ADDR1 LOAD DMA BUFFER ADDRESS */ - 0102602, /* OTA 2 OUTPUT TO DCPC */ - 0063740, /* LDA DMAWC LOAD DMA WORD COUNT */ - 0102702, /* STC 2 READY DCPC */ - 0102602, /* OTA 2 OUTPUT TO DCPC */ - 0103706, /* STC 6,C START DCPC */ - 0102206, /* TEST SFC 6 SKIP IF DMA NOT DONE */ - 0117750, /* JSB ADDR2,I SUCCESSFUL END OF TRANSFER */ - 0102310, /* SFS IBI SKIP IF DISC ABORTED TRANSFER */ - 0027731, /* JMP TEST RECHECK FOR TRANSFER END */ - 0102011, /* ADDR1 HLT 11B ERROR HALT */ - 0000677, /* UNCLR OCT 677 UNLISTEN */ - 0000737, /* OCT 737 UNTALK */ - 0176624, /* DMAWC OCT 176624 UNIVERSAL CLEAR,LBO */ - 0000440, /* LIST OCT 440 LISTEN BUS ADDRESS 0 */ - 0000550, /* CMSEC OCT 550 SECONDARY GET COMMAND */ - 0000000, /* BOOT OCT 0 COLD LOAD READ COMMAND */ - 0001000, /* HDSEC OCT 1000 HEAD,SECTOR PLUS EOI */ - 0000677, /* UNLST OCT 677 ATN,PRIMARY UNLISTEN,PARITY */ - 0000500, /* TALK OCT 500 SEND READ DATA */ - 0100740, /* RDSEC OCT 100740 SECONDARY READ DATA */ - 0102055, /* ADDR2 OCT 102055 BOOT EXTENSION STARTING ADDRESS */ - 0004003, /* CTLP OCT 4003 INT=LBO,T,CIC */ - 0000047, /* OCT 47 PPE,L,T,CIC */ - 0004003, /* OCT 4003 INT=LBO,T,CIC */ - 0000413, /* OCT 413 ATN,P,L,CIC */ - 0001015, /* OCT 1015 INT=EOI,P,L,CIC */ - 0000000, /* BTCTL NOP */ - 0107710, /* CLC IBI,C RESET IBI */ - 0063751, /* BM LDA CTLP LOAD CONTROL WORD */ - 0102610, /* OTA IBI OUTPUT TO CONTROL REGISTER */ - 0102710, /* STC IBI RETURN IBI TO DATA MODE */ - 0037760, /* ISZ BM INCREMENT CONTROL WORD POINTER */ - 0002240, /* SEZ,CME */ - 0127756, /* JMP BTCTL,I RETURN */ - 0063736, /* LABL LDA UNCLR LOAD DATA WORD */ - 0037766, /* ISZ LABL INCREMENT WORD POINTER */ - 0102610, /* OTA IBI OUTPUT TO HPIB */ - 0002021, /* SSA,RSS SKIP IF LAST WORD */ - 0027766, /* JMP LABL GO BACK FOR NEXT WORD */ - 0102310, /* SFS IBI SKIP IF LAST WORD SENT TO BUS */ - 0027773, /* JMP *-1 RECHECK ACCEPTANCE */ - 0027757, /* JMP BTCTL+1 */ - 0000010, /* DMACW ABS IBI */ - 0170100 /* ABS -START */ - }; - -t_stat da_boot (int32 unitno, DEVICE *dptr) -{ -if (GET_BUSADR (da_unit [unitno].flags) != 0) /* booting is supported on bus address 0 only */ - return SCPE_NOFNC; /* report "Command not allowed" if attempted */ - -if (ibl_copy (da_rom, da_dib.select_code)) /* copy the boot ROM to memory and configure */ - return SCPE_IERR; /* return an internal error if the copy failed */ - -SR = SR & (IBL_OPT | IBL_DS_HEAD) /* set S to a reasonable value */ - | IBL_DS | IBL_MAN | (da_dib.select_code << IBL_V_DEV); /* before boot execution */ - -return SCPE_OK; -} - - - -/* Amigo disc global SCP routines */ - - -/* Load or unload a unit's heads. - - The heads are automatically loaded when a unit is attached and unloaded when - a unit is detached. While a unit is attached, the heads may be manually - unloaded; this yields a "not ready" status if the unit is accessed. An - unloaded drive may be manually loaded, returning the unit to "ready" status. - - The ICD controller sets Drive Attention status when the heads unload and also - asserts a parallel poll response if the heads unload while in idle state 2 - (i.e., after an End command). - - - Implementation notes: - - 1. The 13365 manual says on page 28 that Drive Attention status is - "Generated whenever...the drive unloads and the controller is in Idle - State 2 or 3." However, the ICD diagnostic tests for Drive Attention - status on head unload immediately after the Request Status command that - completes the previous step, which leaves the controller in idle state 1. - - Moreover, the diagnostic does NOT check for Drive Attention status if the - Amigo ID is 2 (MAC controller). But the 12745 manual says on page 3-7 - that the status is returned if "...Drive becomes not ready (heads - unload)" with no mention of controller state. - - It appears as though the diagnostic test is exactly backward. However, - we match the diagnostic expectation below. -*/ - -t_stat da_load_unload (UNIT *uptr, int32 value, char *cptr, void *desc) -{ -const int32 unit = uptr - da_unit; /* calculate the unit number */ -const t_bool load = (value != UNIT_UNLOAD); /* true if the heads are loading */ -t_stat result; - -result = dl_load_unload (&icd_cntlr [unit], uptr, load); /* load or unload the heads */ - -if (result == SCPE_OK && ! load) { /* was the unload successful? */ - icd_cntlr [unit].status = drive_attention; /* set Drive Attention status */ - - if (uptr->OP == end) /* is the controller in idle state 2? */ - di_poll_response (da, unit, SET); /* enable PPR */ - } - -return result; -} - - - -/* Amigo disc global bus routines */ - - -/* Accept a data byte from the bus. - - The indicated unit is offered a byte that has been sourced to the bus. The - routine returns TRUE or FALSE to indicate whether or not it accepted the - byte. - - Commands from the bus may be universal (applying to all acceptors) or - addressed (applying only to those acceptors that have been addressed to - listen). Data bytes are accepted only if the unit has been addressed to - listen. As we are called for a data transfer or an addressed command only if - we are currently listening, the only bytes that we do not accept are primary - talk or listen commands directed to another address, or secondary commands - when we are not addressed to listen. - - This routine handles the HP-IB protocol. The type of byte passed is - determined by the state of the ATN signal and, if ATN is asserted, by the - high-order bits of the value. Most of the work involves decoding secondary - commands and their associated data parameters. The interface state is - changed as needed to track the command protocol. The states processed in - this routine are: - - opcode_wait - =========== - - A Receive Disc Command secondary has been received, and the interface is - waiting for the opcode that should follow. - - parameter_wait - ============== - - A disc opcode or interface command has been received, and the interface is - waiting for a parameter byte that should follow. - - write_wait - ========== - - A disc write command has been received, and the interface is waiting for - the Receive Write Data secondary that should follow. - - read_wait - ========= - - A disc read command has been received, and the interface is waiting for the - Send Read Data secondary that should follow. - - status_wait - =========== - - A disc status command has been received, and the interface is waiting for - the Send Disc Status secondary that should follow. - - write_xfer - ========== - - A disc write is in progress, and the interface is waiting for a data byte - that should follow. - - error_sink - ========== - - A disc write has terminated with an error, and the interface is waiting to - absorb all of the remaining data bytes of the transfer. - - - Disc commands and parameters are assembled in the sector buffer before being - passed to the disc library to start the command. Once the command is - started, the interface state is set either to execute the command or to wait - for the receipt of a data transfer secondary before executing, depending on - the command. - - Two disc command protocol errors are detected. First, an Illegal Opcode is - identified during the check for the expected number of disc command - parameters. This allows us to sink an arbitrary number of parameter bytes. - Second, an I/O Program Error occurs if an unsupported secondary is received - or the HP-IB sequence is incorrect. The latter occurs if a command has the - wrong number of parameters or a secondary data transfer sequence is invalid. - - Disc commands that require data transfers (e.g., Read, Write, Request Status) - involve a pair of secondaries. The first transmits the command, and the - second transmits or receives the data. If one occurs without the other, an - I/O Program Error occurs. - - A secondary or command that generates an I/O Program Error is always ignored. - Error recovery is as follows: - - - An unsupported talk secondary sends a single data byte tagged with EOI. - - - An unsupported listen secondary accepts and discards any accompanying data - bytes until EOI is asserted or an Unlisten is received. - - - A supported command with too few parameter bytes or for which the last - parameter byte is not tagged with EOI (before unlisten) does nothing. - - - A supported command with too many parameter bytes accepts and discards - excess parameter bytes until EOI is asserted or an Unlisten is received. - - - A read or status command that is not followed by a Send Read Data or a - Send Disc Status secondary does nothing. The unexpected secondary is - executed normally. - - - A write command that is not followed by a Receive Write Data secondary - does nothing. The unexpected secondary is executed normally. - - - A Send Read Data or a Send Disc Status secondary that is not preceded by a - read or status command sends a single data byte tagged with EOI. - - - A Receive Write Data secondary that is not preceded by a write command - accepts and discards data bytes until EOI is asserted or an Unlisten is - received. - - The Amigo command sequence does not provide a byte count for disc read and - write commands, so the controller continues to source or accept data bytes - until the device is unaddressed. Normally, this is done by an Unlisten or - Untalk. However, per IEEE-488, a listening device may be unaddressed by IFC, - by an Unlisten, or by addressing the device to talk, and a talking device may - be unaddressed by IFC, by addressing another device to talk (or no device via - Untalk), or by addressing the device to listen. Therefore, we must keep - track of whether the unit stopped talking or listening, and if it has, we - check for command termination. - - If the controller is unaddressed in the middle of a sector transfer, the read - or write must be terminated cleanly to ensure that the disc image is - coherent. It is also permissible to untalk the controller before all of the - requested status bytes are returned. - - In addition, the controller has no way to inform the host that an error has - occurred that prevents the command from continuing. For example, if a data - error is encountered while reading or a protected track is encountered while - writing, the controller must still source or sink data bytes until the - command is terminated by the host. The controller handles read errors by - sourcing a single data byte tagged with EOI and write errors by sinking data - bytes until EOI is seen or the unit is unaddressed. - - Therefore, if the unit is unaddressed while a read, write, or status command - is transferring data, the unit service must be scheduled to end the current - command. Unaddressing while an error condition is present merely terminates - the source or sink operation. - - - Implementation notes: - - 1. The 13365 manual does not indicate that the controller responds to - Universal Clear, but the 12992H loader ROM issues this primary and - expects the controller to initialize. - - 2. It is not necessary to check for listening when processing addressed - commands, as only listeners are called by the bus source. -*/ - -t_bool da_bus_accept (uint32 unit, uint8 data) -{ -const uint8 message_address = data & BUS_ADDRESS; -t_bool accepted = TRUE; -t_bool initiated = FALSE; -t_bool addressed = FALSE; -t_bool stopped_listening = FALSE; -t_bool stopped_talking = FALSE; -char action [40] = ""; -uint32 my_address; - -if (di [da].bus_cntl & BUS_ATN) { /* is it a bus command (ATN asserted)? */ - switch (data & BUS_GROUP) { /* dispatch the bus group */ - - case BUS_PCG: /* primary command group */ - switch (message_address) { - - case 0x04: /* selected device clear */ - case 0x05: /* SDC with parity freeze */ - case 0x14: /* universal clear */ - if (DEBUG_PRI (da_dev, DEB_RWSC)) - fprintf (sim_deb, ">>DA rwsc: Unit %d device cleared\n", unit); - - sim_cancel (&da_unit [unit]); /* cancel any in-progress command */ - dl_idle_controller (&icd_cntlr [unit]); /* idle the controller */ - if_dsj [unit] = 0; /* clear DSJ */ - if_state [unit] = idle; /* idle the interface */ - di_poll_response (da, unit, SET); /* enable PPR */ - - if (DEBUG_PRI (da_dev, DEB_XFER)) - strcpy (action, "device clear"); - break; - - - default: /* unsupported universal command */ - break; /* universals are always accepted */ - } - - break; - - - case BUS_LAG: /* listen address group */ - my_address = GET_BUSADR (da_unit [unit].flags); /* get my bus address */ - - if (message_address == my_address) { /* is it my listen address? */ - di [da].listeners |= (1 << unit); /* set my listener bit */ - di [da].talker &= ~(1 << unit); /* clear my talker bit */ - - addressed = TRUE; /* unit is now addressed */ - stopped_talking = TRUE; /* MLA stops the unit from talking */ - - if (DEBUG_PRI (da_dev, DEB_XFER)) - sprintf (action, "listen %d", message_address); - } - - else if (message_address == BUS_UNADDRESS) { /* is it an Unlisten? */ - di [da].listeners = 0; /* clear all of the listeners */ - - stopped_listening = TRUE; /* UNL stops the unit from listening */ - - if (DEBUG_PRI (da_dev, DEB_XFER)) - strcpy (action, "unlisten"); - } - - else /* other listen addresses */ - accepted = FALSE; /* are not accepted */ - - break; - - - case BUS_TAG: /* talk address group */ - my_address = GET_BUSADR (da_unit [unit].flags); /* get my bus address */ - - if (message_address == my_address) { /* is it my talk address? */ - di [da].talker = (1 << unit); /* set my talker bit and clear the others */ - di [da].listeners &= ~(1 << unit); /* clear my listener bit */ - - addressed = TRUE; /* the unit is now addressed */ - stopped_listening = TRUE; /* MTA stops the unit from listening */ - - if (DEBUG_PRI (da_dev, DEB_XFER)) - sprintf (action, "talk %d", message_address); - } - - else { /* it is some other talker (or Untalk) */ - di [da].talker &= ~(1 << unit); /* clear my talker bit */ - - stopped_talking = TRUE; /* UNT or OTA stops the unit from talking */ - - if (message_address != BUS_UNADDRESS) /* other talk addresses */ - accepted = FALSE; /* are not accepted */ - - else /* it's an Untalk */ - if (DEBUG_PRI (da_dev, DEB_XFER)) - strcpy (action, "untalk"); - } - - break; - - - case BUS_SCG: /* secondary command group */ - icd_cntlr [unit].index = 0; /* reset the buffer index */ - - if (di [da].listeners & (1 << unit)) { /* is it a listen secondary? */ - if (if_state [unit] == write_wait /* if we're waiting for a write data secondary */ - && message_address != 0x00) /* but it's not there, */ - abort_command (unit, io_program_error, /* then abort the pending command */ - idle); /* and process the new command */ - - switch (message_address) { /* dispatch the listen secondary */ - - case 0x00: /* Receive Write Data */ - if (if_state [unit] != write_wait) /* if we're not expecting it */ - abort_command (unit, io_program_error, /* abort and sink any data */ - error_sink); - else { /* the sequence is correct */ - if_state [unit] = command_exec; /* the command is ready to execute */ - da_unit [unit].wait = icd_cntlr [unit].cmd_time; /* schedule the unit */ - di_bus_control (da, unit, BUS_NRFD, 0); /* assert NRFD to hold off the card */ - } - - initiated = TRUE; /* log the command or abort initiation */ - break; - - case 0x08: /* disc commands */ - if_command [unit] = disc_command; /* set the command and wait */ - if_state [unit] = opcode_wait; /* for the opcode that must follow */ - break; - - case 0x09: /* CRC (Listen) */ - if_command [unit] = crc_listen; /* set up the command */ - if_state [unit] = error_sink; /* sink any data that will be coming */ - initiated = TRUE; /* log the command initiation */ - break; - - case 0x10: /* Amigo Clear */ - if_command [unit] = amigo_clear; /* set up the command */ - if_state [unit] = parameter_wait; /* a parameter must follow */ - icd_cntlr [unit].length = 1; /* set to expect one (unused) byte */ - break; - - case 0x1E: /* Write Loopback */ - if_command [unit] = write_loopback; /* set up the command */ - if_state [unit] = write_xfer; /* data will be coming */ - icd_cntlr [unit].length = 16; /* accept only the first 16 bytes */ - initiated = TRUE; /* log the command initiation */ - break; - - case 0x1F: /* Initiate Self-Test */ - if_command [unit] = initiate_self_test; /* set up the command */ - if_state [unit] = parameter_wait; /* a parameter must follow */ - icd_cntlr [unit].length = 1; /* set to expect the test ID byte */ - break; - - default: /* an unsupported listen secondary was received */ - abort_command (unit, io_program_error, /* abort and sink any data */ - error_sink); /* that might accompany the command */ - initiated = TRUE; /* log the abort initiation */ - break; - } - } - - - else if (di [da].talker & (1 << unit)) { /* is it a talk secondary? */ - da_unit [unit].wait = icd_cntlr [unit].cmd_time; /* these are always scheduled and */ - initiated = TRUE; /* logged as initiated */ - - if (if_state [unit] == read_wait /* if we're waiting for a send data secondary */ - && message_address != 0x00 /* but it's not there */ - || if_state [unit] == status_wait /* or a send status secondary, */ - && message_address != 0x08) /* but it's not there */ - abort_command (unit, io_program_error, /* then abort the pending command */ - idle); /* and process the new command */ - - switch (message_address) { /* dispatch the talk secondary */ - - case 0x00: /* Send Read Data */ - if (if_state [unit] != read_wait) /* if we're not expecting it */ - abort_command (unit, io_program_error, /* abort and source a data byte */ - error_source); /* tagged with EOI */ - else - if_state [unit] = command_exec; /* the command is ready to execute */ - break; - - case 0x08: /* Read Status */ - if (if_state [unit] != status_wait) /* if we're not expecting it, */ - abort_command (unit, io_program_error, /* abort and source a data byte */ - error_source); /* tagged with EOI */ - else /* all status commands */ - if_state [unit] = read_xfer; /* are ready to transfer data */ - break; - - case 0x09: /* CRC (Talk) */ - if_command [unit] = crc_talk; /* set up the command */ - if_state [unit] = read_xfer; /* data will be going */ - break; - - case 0x10: /* Device-Specified Jump */ - if_command [unit] = device_specified_jump; /* set up the command */ - if_state [unit] = read_xfer; /* data will be going */ - break; - - case 0x1E: /* Read Loopback */ - if_command [unit] = read_loopback; /* set up the command */ - if_state [unit] = read_xfer; /* data will be going */ - break; - - case 0x1F: /* Return Self-Test Result */ - if_command [unit] = return_self_test_result; /* set up the command */ - if_state [unit] = read_xfer; /* data will be going */ - icd_cntlr [unit].length = 1; /* return one byte that indicates */ - buffer [0] = 0; /* that the self-test passed */ - break; - - default: /* an unsupported talk secondary was received */ - abort_command (unit, io_program_error, /* abort and source a data byte */ - error_source); /* tagged with EOI */ - break; - } - } - - - else { /* the unit is not addressed */ - my_address = GET_BUSADR (da_unit [unit].flags); /* get my bus address */ - - if (di [da].talker == 0 && di [da].listeners == 0 /* if there are no talkers or listeners */ - && message_address == my_address) { /* and this is my secondary address, */ - if_command [unit] = amigo_identify; /* then this is an Amigo ID sequence */ - if_state [unit] = command_exec; /* set up for execution */ - da_unit [unit].wait = icd_cntlr [unit].cmd_time; /* schedule the unit */ - initiated = TRUE; /* log the command initiation */ - } - - else /* unaddressed secondaries */ - accepted = FALSE; /* are not accepted */ - } - - - if (accepted) { /* was the command accepted? */ - if (DEBUG_PRI (da_dev, DEB_XFER)) - sprintf (action, "secondary %02XH", message_address); - - if (if_command [unit] != amigo_identify) /* disable PPR for all commands */ - di_poll_response (da, unit, CLEAR); /* except Amigo ID */ - } - - break; /* end of secondary processing */ - } - - - if (addressed && sim_is_active (&da_unit [unit])) { /* is the unit being addressed while it is busy? */ - if_state [unit] = command_wait; /* change the interface state to wait */ - di_bus_control (da, unit, BUS_NRFD, 0); /* and assert NRFD to hold off the card */ - - if (DEBUG_PRI (da_dev, DEB_RWSC)) - fprintf (sim_deb, ">>DA rwsc: Unit %d addressed while controller is busy\n", unit); - } - - if (stopped_listening) { /* was the unit Unlistened? */ - if (icd_cntlr [unit].state == cntlr_busy) /* if the controller is busy, */ - complete_write (unit); /* then check for write completion */ - - else if (if_command [unit] == invalid) /* if a command was aborting, */ - complete_abort (unit); /* then complete it */ - - else if (if_state [unit] == opcode_wait /* if waiting for an opcode */ - || if_state [unit] == parameter_wait) /* or a parameter, */ - abort_command (unit, io_program_error, idle); /* then abort the pending command */ - } - - else if (stopped_talking) { /* was the unit Untalked? */ - if (icd_cntlr [unit].state == cntlr_busy) /* if the controller is busy, */ - complete_read (unit); /* then check for read completion */ - - else if (if_command [unit] == invalid) /* if a command was aborting, */ - complete_abort (unit); /* then complete it */ - } - } /* end of bus command processing */ - - -else { /* it is bus data (ATN is denied) */ - switch (if_state [unit]) { /* dispatch the interface state */ - - case opcode_wait: /* waiting for an opcode */ - if (DEBUG_PRI (da_dev, DEB_XFER)) - sprintf (action, "opcode %02XH", data & DL_OPCODE_MASK); - - buffer [0] = SET_UPPER (data); /* set the opcode into the buffer */ - - if (dl_prepare_command (&icd_cntlr [unit], /* is the command valid? */ - da_unit, unit)) { - if_state [unit] = parameter_wait; /* set up to get the pad byte */ - icd_cntlr [unit].index = 0; /* reset the word index for the next byte */ - icd_cntlr [unit].length = /* convert the parameter count to bytes */ - icd_cntlr [unit].length * 2 + 1; /* and include the pad byte */ - } - - else { /* the disc command is invalid */ - abort_command (unit, illegal_opcode, /* abort the command */ - error_sink); /* and sink any parameter bytes */ - initiated = TRUE; /* log the abort initiation */ - } /* (the unit cannot be busy) */ - break; - - - case parameter_wait: /* waiting for a parameter */ - if (DEBUG_PRI (da_dev, DEB_XFER)) - sprintf (action, "parameter %02XH", data); - - put_buffer_byte (&icd_cntlr [unit], data); /* add the byte to the buffer */ - - if (icd_cntlr [unit].length == 0) /* is this the last parameter? */ - if (di [da].bus_cntl & BUS_EOI) /* does the host agree? */ - initiated = start_command (unit); /* start the command and log the initiation */ - - else { /* the parameter count is wrong */ - abort_command (unit, io_program_error, /* abort the command and sink */ - error_sink); /* any additional parameter bytes */ - initiated = TRUE; /* log the abort initiation */ - } - break; - - - case write_xfer: /* transferring write data */ - if (icd_cntlr [unit].length > 0) /* if there is more to transfer */ - put_buffer_byte (&icd_cntlr [unit], data); /* then add the byte to the buffer */ - - /* fall into error_sink handler */ - - case error_sink: /* sinking data after an error */ - if (DEBUG_PRI (da_dev, DEB_XFER)) - sprintf (action, "data %03o", data); - - if (di [da].bus_cntl & BUS_EOI) /* is this the last byte from the bus? */ - icd_cntlr [unit].eod = SET; /* indicate EOD to the controller */ - - di_bus_control (da, unit, BUS_NRFD, 0); /* assert NRFD to hold off the card */ - - da_unit [unit].wait = icd_cntlr [unit].data_time; /* schedule the unit */ - break; - - - default: /* data was received in the wrong state */ - abort_command (unit, io_program_error, /* report the error */ - error_sink); /* and sink any data that follows */ - - if (DEBUG_PRI (da_dev, DEB_XFER)) - sprintf (action, "unhandled data %03o", data); - break; - } - } - - -if (accepted && DEBUG_PRI (da_dev, DEB_XFER)) - fprintf (sim_deb, ">>DA xfer: HP-IB address %d accepted %s\n", - GET_BUSADR (da_unit [unit].flags), action); - -if (da_unit [unit].wait > 0) /* was service requested? */ - activate_unit (&da_unit [unit]); /* schedule the unit */ - -if (initiated && DEBUG_PRI (da_dev, DEB_RWSC)) - if (if_command [unit] == disc_command) - fprintf (sim_deb, ">>DA rwsc: Unit %d position %d %s disc command initiated\n", - unit, da_unit [unit].pos, dl_opcode_name (ICD, icd_cntlr [unit].opcode)); - else - fprintf (sim_deb, ">>DA rwsc: Unit %d %s command initiated\n", - unit, if_command_name [if_command [unit]]); - -return accepted; /* indicate the acceptance condition */ -} - - -/* Respond to the bus control lines. - - The indicated unit is notified of the new control state on the bus. There - are two conditions to which we must respond: - - 1. An Interface Clear is initiated. IFC unaddresses all units, so any - in-progress disc command must be terminated as if an Untalk and Unlisten - were accepted from the data bus. - - 2. Attention and Not Ready for Data are denied. A device addressed to talk - must wait for ATN to deny before data may be sent. Also, a listener that - has asserted NRFD must deny it before a talker may send data. If the - interface is sending data and both ATN and NRFD are denied, then we - reschedule the service routine to send the next byte. -*/ - -void da_bus_respond (CARD_ID card, uint32 unit, uint8 new_cntl) -{ -if (new_cntl & BUS_IFC) { /* is interface clear asserted? */ - di [da].listeners = 0; /* perform an Unlisten */ - di [da].talker = 0; /* and an Untalk */ - - if (icd_cntlr [unit].state == cntlr_busy) { /* is the controller busy? */ - complete_write (unit); /* check for write completion */ - complete_read (unit); /* or read completion */ - - if (da_unit [unit].wait > 0) /* is service needed? */ - activate_unit (&da_unit [unit]); /* activate the unit */ - } - - else if (if_command [unit] == invalid) /* if a command was aborting, */ - complete_abort (unit); /* then complete it */ - - else if (if_state [unit] == opcode_wait /* if we're waiting for an opcode */ - || if_state [unit] == parameter_wait) /* or a parameter, */ - abort_command (unit, io_program_error, idle); /* then abort the pending command */ - } - -if (!(new_cntl & (BUS_ATN | BUS_NRFD)) /* is the card in data mode and ready for data? */ - && (if_state [unit] == read_xfer /* is the interface waiting to send data */ - || if_state [unit] == error_source)) /* or source error bytes? */ - da_service (&da_unit [unit]); /* start or resume the transfer */ -} - - - -/* Amigo disc local utility routines */ - - -/* Start a command with parameters. - - A command that has been waiting for all of its parameters to be received is - now ready to start. If this is a disc command, call the disc library to - validate the parameters and, if they are OK, to start the command. Status - commands return the status values in the sector buffer and the number of - words that were returned in the buffer length, which we convert to a byte - count. - - If the disc command was accepted, the library returns a pointer to the unit - to be scheduled. For an ICD controller, the unit is always the one currently - addressed, so we simply test if the return is not NULL. If it isn't, then we - set the next interface state as determined by the command that is executing. - For example, a Read command sets the interface to read_wait status in order - to wait until the accompanying Send Read Data secondary is received. - - If the return is NULL, then the command was rejected, so we set DSJ = 1 and - leave the interface state in parameter_wait; the controller status will have - been set to the reason for the rejection. - - If the next interface state is command_exec, then the disc command is ready - for execution, and we return TRUE to schedule the unit service. Otherwise, - we return FALSE, and the appropriate action will be taken by the caller. - - For all other commands, execution begins as soon as the correct parameters - are received, so we set command_exec state and return TRUE. (Only Amigo - Clear and Initiate Self Test require parameters, so they will be the only - other commands that must be started here.) - - - Implementation notes: - - 1. As the ICD implementation does not need to differentiate between unit and - controller commands, the return value from the dl_start_command routine - is not used other than as an indication of success or failure. -*/ - -static t_bool start_command (uint32 unit) -{ -if (if_command [unit] == disc_command) { /* are we starting a disc command? */ - if (dl_start_command (&icd_cntlr [unit], da_unit, unit)) { /* start the command; was it successful? */ - icd_cntlr [unit].length = icd_cntlr [unit].length * 2; /* convert the return length from words to bytes */ - if_state [unit] = next_state [icd_cntlr [unit].opcode]; /* set the next interface state */ - } - - else /* the command was rejected */ - if_dsj [unit] = 1; /* so indicate an error */ - - if (if_state [unit] == command_exec) /* if the command is executing */ - return TRUE; /* activate the unit */ - - else { /* if we must wait */ - da_unit [unit].wait = 0; /* for another secondary, */ - return FALSE; /* then skip the activation */ - } - } - -else { /* all other commands */ - if_state [unit] = command_exec; /* execute as soon */ - da_unit [unit].wait = icd_cntlr [unit].cmd_time; /* as they */ - return TRUE; /* are received */ - } -} - - -/* Abort an in-process command. - - A command sequence partially received via the bus must be aborted. The cause - might be an unknown secondary, an illegal disc command opcode, an improper - secondary sequence (e.g., a Read not followed by Send Read Data), an - incorrect number of parameters, or unaddressing before the sequence was - complete. In any event, the controller and interface are set to an abort - state, and the DSJ value is set to 1 to indicate an error. -*/ - -static void abort_command (uint32 unit, CNTLR_STATUS status, IF_STATE state) -{ -if_command [unit] = invalid; /* indicate an invalid command */ -if_state [unit] = state; /* set the interface state as directed */ -if_dsj [unit] = 1; /* set DSJ to indicate an error condition */ -dl_end_command (&icd_cntlr [unit], status); /* place the disc controller into the wait state */ -return; -} - - -/* Complete an in-process read command. - - An Untalk terminates a Read, Read Full Sector, Read Without Verify, Read With - Offset, or Cold Load Read command, which must be tied off cleanly by setting - the end-of-data condition and calling the service routine. This is required - only if the read has not already aborted (e.g., for an auto-seek error). - - If a read is in progress, the controller will be busy, and the interface - state will be either command_exec (if between sectors) or read_xfer (if - within a sector). We set up the end phase for the command and schedule the - disc service to tidy up. - - If a read has aborted, the controller will be waiting, and the interface - state will be error_source. In this latter case, we no nothing, as the - controller has already set the required error status. - - We must be careful NOT to trigger on an Untalk that may follow the opcode and - precede the Send Read Data sequence. In this case, the controller will be - busy, but the interface state will be either read_wait or status_wait. - - - Implementation notes: - - 1. The test for controller busy is made before calling this routine. This - saves the call overhead for the most common case, which is the card is - being unaddressed after command completion. - - 2. There is no need to test if we are processing a disc command, as the - controller would not be busy otherwise. -*/ - -static void complete_read (uint32 unit) -{ -if ((if_state [unit] == command_exec /* is a command executing */ - || if_state [unit] == read_xfer) /* or is data transferring */ - && (dl_classify (icd_cntlr [unit]) == class_read /* and the controller is executing */ - || dl_classify (icd_cntlr [unit]) == class_status)) { /* a read or status command? */ - icd_cntlr [unit].eod = SET; /* set the end of data flag */ - - if_state [unit] = command_exec; /* set to execute */ - da_unit [unit].PHASE = end_phase; /* the completion phase */ - da_unit [unit].wait = icd_cntlr [unit].data_time; /* ensure that the controller will finish */ - } - -return; -} - - -/* Complete an in-process write command. - - Normally, the host sends a byte tagged with EOI to end a Write, Write Full - Sector, or Initialize command. However, an Unlisten may terminate a write, - which must be tied off cleanly by setting the end-of-data condition and - calling the service routine. This is required only if the write has not - already aborted (e.g., for a write-protected disc). - - If a write is in progress, the controller will be busy, and the interface - state will be either command_exec (if between sectors) or write_xfer (if - within a sector). We set up the end phase for the command and schedule the - disc service to tidy up. - - If a write has aborted, the controller will be waiting, and the interface - state will be error_sink. In this latter case, we do nothing, as the - controller has already set the required error status. - - We must be careful NOT to trigger on the Unlisten that may follow the opcode - and precede the Receive Write Data sequence. In this case, the controller - will be busy, but the interface state will be write_wait. - - - Implementation notes: - - 1. The test for controller busy is made before calling this routine. This - saves the call overhead for the most common case, which is the card is - being unaddressed after command completion. - - 2. There is no need to test if we are processing a disc command, as the - controller would not be busy otherwise. -*/ - -static void complete_write (uint32 unit) -{ -if ((if_state [unit] == command_exec /* is a command executing */ - || if_state [unit] == write_xfer) /* or is data transferring */ - && dl_classify (icd_cntlr [unit]) == class_write) { /* and the controller is executing a write? */ - icd_cntlr [unit].eod = SET; /* set the end of data flag */ - - if_state [unit] = command_exec; /* set to execute */ - da_unit [unit].PHASE = end_phase; /* the completion phase */ - da_unit [unit].wait = icd_cntlr [unit].data_time; /* ensure that the controller will finish */ - } - -return; -} - - -/* Complete an in-process command abort. - - Errors in the command protocol begin an abort sequence that may involve - sourcing or sinking bytes to allow the sequence to complete as expected by - the CPU. Unaddressing the unit terminates the aborted command. - - If an abort is in progress, and the interface is not idle, the end-of-data - indication is set, and the disc service routine is called directly to process - the completion of the abort. The service routine will terminate the - error_source or error_sink state cleanly and then idle the interface. - - - Implementation notes: - - 1. The test for an abort-in-progress is made before calling this routine. - This saves the call overhead for the most common case, which is the card - is being unaddressed after normal command completion. -*/ - -static void complete_abort (uint32 unit) -{ -if (if_state [unit] != idle) { /* is the interface busy? */ - icd_cntlr [unit].eod = SET; /* set the end of data flag */ - da_service (&da_unit [unit]); /* and process the abort completion */ - } - -return; -} - - -/* Get a byte from the sector buffer. - - The next available byte in the sector buffer is returned to the caller. The - determination of which byte of the 16-bit buffer word to return is made by - the polarity of the buffer byte count. The count always begins with an even - number, as it is set by doubling the word count returned from the disc - library. Therefore, because we decrement the count first, the upper byte is - indicated by an odd count, and the lower byte is indicated by an even count. - The buffer index is incremented only after the lower byte is returned. -*/ - -static uint8 get_buffer_byte (CVPTR cvptr) -{ -cvptr->length = cvptr->length - 1; /* count the byte */ - -if (cvptr->length & 1) /* is the upper byte next? */ - return GET_UPPER (buffer [cvptr->index]); /* return the byte */ -else /* the lower byte is next */ - return GET_LOWER (buffer [cvptr->index++]); /* return the byte and bump the word index */ -} - - -/* Put a byte into the sector buffer. - - The supplied byte is stored in the sector buffer. The determination of which - byte of the 16-bit buffer word to store is made by the polarity of the buffer - byte count. The count always begins with an even number, as it is set by - doubling the word count returned from the disc library. Therefore, because - we decrement the count first, the upper byte is indicated by an odd count, - and the lower byte is indicated by an even count. The buffer index is - incremented only after the lower byte is stored. -*/ - -static void put_buffer_byte (CVPTR cvptr, uint8 data) -{ -cvptr->length = cvptr->length - 1; /* count the byte */ - -if (cvptr->length & 1) /* is the upper byte next? */ - buffer [cvptr->index] = SET_UPPER (data); /* save the byte */ -else /* the lower byte is next */ - buffer [cvptr->index++] |= SET_LOWER (data); /* merge the byte and bump the word index */ -return; -} - - -/* Activate the unit. - - The specified unit is activated using the unit's "wait" time. If debugging - is enabled, the activation is logged to the debug file. -*/ - -static t_stat activate_unit (UNIT *uptr) -{ -int32 unit; -t_stat result; - -if (DEBUG_PRI (da_dev, DEB_SERV)) { - unit = uptr - da_unit; - - fprintf (sim_deb, ">>DA serv: Unit %d state %s delay %d service scheduled\n", - unit, if_state_name [if_state [unit]], uptr->wait); - } - -result = sim_activate (uptr, uptr->wait); /* activate the unit */ -uptr->wait = 0; /* reset the activation time */ - -return result; /* return the activation status */ -} +/* hp2100_di_da.c: HP 12821A HP-IB Disc Interface simulator for Amigo disc drives + + Copyright (c) 2011-2014, J. David Bryan + + 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 + THE AUTHOR 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 the author shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from the author. + + DA 12821A Disc Interface with Amigo disc drives + + 30-Dec-14 JDB Added S-register parameters to ibl_copy + 24-Dec-14 JDB Use T_ADDR_FMT with t_addr values for 64-bit compatibility + Removed redundant global declarations + 24-Oct-12 JDB Changed CNTLR_OPCODE to title case to avoid name clash + 07-May-12 JDB Cancel the intersector delay if an untalk is received + 29-Mar-12 JDB First release + 04-Nov-11 JDB Created DA device + + References: + - HP 13365 Integrated Controller Programming Guide (13365-90901, Feb-1980) + - HP 7910 Disc Drive Service Manual (07910-90903, Apr-1981) + - 12745D Disc Controller (13037) to HP-IB Adapter Kit Installation and + Service Manual (12745-90911, Sep-1983) + - HP's 5 1/4-Inch Winchester Disc Drive Service Documentation + (09134-90032, Aug-1983) + - HP 12992 Loader ROMs Installation Manual (12992-90001, Apr-1986) + - RTE Driver DVA32 Source (92084-18708, revision 2540) + - IEEE Standard Digital Interface for Programmable Instrumentation + (IEEE-488A-1980, Sep-1979) + + + The HP 7906H, 7920H, and 7925H Integrated Controller Disc (ICD) drives were + connected via an 12821A disc interface and provided 20MB, 50MB, and 120MB + capacities. The drives were identical to the 7906M, 7920M, and 7925M + Multi-Access Controller (MAC) units but incorporated internal two-card + controllers in each drive and connected to the CPU interface via the + Hewlett-Packard Interface Bus (HP-IB), HP's implementation of IEEE-488. Each + controller was dedicated to a single drive and operated similarly to the + 12745 Disc Controller to HP-IB Adapter option for the 13037 Disc Controller + chassis. The 7906H was introduced in 1980 (there was no 7905H version, as + the 7905 was obsolete by that time). Up to four ICD drives could be + connected to a single 12821A card. The limitation was imposed by the bus + loading and the target data transfer rate. + + The ICD command set essentially was the MAC command set modified for + single-unit operation. The unit number and CPU hold bit fields in the opcode + words were unused in the ICD implementation. The Load TIO Register, Wakeup, + and Request Syndrome commands were removed, as Load TIO was used with the HP + 3000, Wakeup was used in a multi-CPU environment, and the simpler ICD + controller did not support ECC. Controller status values 02B (Unit + Available) and 27B (Unit Unavailable) were dropped as the controller + supported only single units, 12B (I/O Program Error) was reused to indicate + HP-IB protocol errors, 13B (Sync Not Received) was added, and 17B (Possibly + Correctable Data Error) was removed as error correction was not supported. + + Some minor redefinitions also occurred. For example, status 14B (End of + Cylinder) was expanded to include an auto-seek beyond the drive limits, and + 37B (Drive Attention) was restricted just head unloads from head loads and + unloads. + + The command set was expanded to include several commands related to HP-IB + operation. These were, in large part, adapted from the Amigo disc command + protocol outlined in the service manual for the HP 9133/34/35 series of + 5-1/4" Winchester drives. They include the Amigo Identify and Amigo Clear + sequences, Read and Write Loopback channel tests, and controller Self Test + commands. + + This simulator implements the Amigo disc protocol. It calls the 12821A Disc + Interface (DI) simulator to send and receive bytes across the HP-IB to and + from the CPU, and it calls the HP Disc Library to implement the controller + functions related to disc unit operation (e.g., seek, read, write, etc.). + Four units are provided, and any combination of 7906H/20H/25H drives may be + defined. + + Unfortunately, the primary reference for the ICD controller (the HP 13365 + Integrated Controller Programming Guide) does not indicate parallel poll + responses for these HP-IB commands. Therefore, the responses have been + derived from the sequences in the 7910 and 12745 manuals, although they + sometimes conflict. + + The drives respond to the following commands; the secondary and opcode + numeric values are in hex, and the bus addressing state is indicated by U + [untalk], L [listen], and T [talk]: + + Bus Sec Op Operation + --- --- -- -------------------------------- + U MSA -- Amigo Identify + + L 00 -- Write Data + L 08 00 Cold Load Read + L 08 01 Recalibrate + L 08 02 Seek + L 08 03 Request Status + L 08 04 Request Sector Address + L 08 05 Read + L 08 06 Read Full Sector + L 08 07 Verify + L 08 08 Write + L 08 09 Write Full Sector + L 08 0A Clear + L 08 0B Initialize + L 08 0C Address Record + L 08 0E Read with Offset + L 08 0F Set File Mask + L 08 12 Read without Verify + L 08 14 Request Logical Disc Address + L 08 15 End + L 09 -- Cyclic Redundancy Check + L 10 -- Amigo Clear + L 1E -- Write Loopback + L 1F ss Initiate Self-Test + + T 00 -- Read Data + T 08 -- Read Status + T 09 -- Cyclic Redundancy Check + T 10 -- Device Specified Jump + T 1E -- Read Loopback + T 1F -- Return Self-Test Result + + In addition, the controller responds to the Selected Device Clear primary + (04). + + + HP-IB Transaction Sequences + =========================== + + Amigo Identify + + ATN UNT Untalk + ATN MSA My secondary address + DAB ID data byte #1 = 00H + EOI DAB ID data byte #2 = 03H + ATN OTA Talk 30 + + + Amigo Clear + + ATN MLA My listen address + ATN SCG Secondary command 10H + ppd Parallel poll disabled + EOI DAB Unused data byte + ATN SDC Selected device clear + ATN UNL Unlisten + ... + ppe Parallel poll enabled when clear completes + + + CRC + + ATN MTA My talk address + ATN SCG Secondary command 09H + ppd Parallel poll disabled + DAB Data byte #1 + ... + EOI DAB Data byte #n + ppe Parallel poll enabled + ATN UNT Untalk + + or + + ATN MLA My listen address + ATN SCG Secondary command 09H + ppd Parallel poll disabled + DAB Data byte #1 + ... + EOI DAB Data byte #n + ppe Parallel poll enabled + ATN UNL Unlisten + + + Device Specified Jump + + ATN MTA My talk address + ATN SCG Secondary command 10H + ppd Parallel poll disabled + EOI DAB DSJ data byte + ATN UNT Untalk + + + Initiate Self-Test and Return Self-Test Result + + ATN MLA My listen address + ATN SCG Secondary command 1FH + ppd Parallel poll disabled + EOI DAB Self-test number + ppe Parallel poll enabled + ATN UNL Unlisten + + ATN MTA My talk address + ATN SCG Secondary command 1FH + ppd Parallel poll disabled + EOI DAB Result data byte + ppe Parallel poll enabled + ATN UNT Untalk + + + Write Loopback and Read Loopback + + ATN MLA My listen address + ATN SCG Secondary command 1EH + ppd Parallel poll disabled + DAB Loopback data byte #1 + ... + EOI DAB Loopback data byte #256 + ppe Parallel poll enabled + ATN UNL Unlisten + + ATN MTA My talk address + ATN SCG Secondary command 1EH + ppd Parallel poll disabled + DAB Loopback data byte #1 + ... + EOI DAB Loopback data byte #16 + ppe Parallel poll enabled + ATN UNT Untalk + + + Recalibrate and Seek + + ATN MLA My listen address + ATN SCG Secondary command 08H + ppd Parallel poll disabled + DAB Opcode 01H, 02H + ... (one to five + EOI DAB parameter bytes) + ATN UNL Unlisten + ... + ppe Parallel poll enabled when seek completes + + + Clear, Address Record, and Set File Mask + + ATN MLA My listen address + ATN SCG Secondary command 08H + ppd Parallel poll disabled + DAB Opcode 0AH, 0CH, 0FH + ... (one to five + EOI DAB parameter bytes) + ppe Parallel poll enabled + ATN UNL Unlisten + + + End + + ATN MLA My listen address + ATN SCG Secondary command 08H + ppd Parallel poll disabled + DAB Opcode 15H + EOI DAB Unused data byte + ATN UNL Unlisten + + + Request Status, Request Sector Address, and Request Logical Disc Address + + ATN MLA My listen address + ATN SCG Secondary command 08H + ppd Parallel poll disabled + DAB Opcode 03H, 04H, 14H + EOI DAB Unused data byte + ATN UNL Unlisten + + ATN MTA My talk address + ATN SCG Secondary command 08H + DAB Status byte #1 + ... (two to four + EOI DAB status bytes) + ppe Parallel poll enabled + ATN UNT Untalk + + + Cold Load Read, Read, Read Full Sector, Verify, Read with Offset, and Read + without Verify + + ATN MLA My listen address + ATN SCG Secondary command 08H + ppd Parallel poll disabled + DAB Opcode 00H, 05H, 06H, 07H, 0EH, 12H + EOI DAB Unused data byte + ATN UNL Unlisten + + ATN MTA My talk address + ATN SCG Secondary command 00H + DAB Read data byte #1 + ... + DAB Read data byte #n + ATN UNT Untalk + ... + ppe Parallel poll enabled when sector ends + + + Write, Write Full Sector, and Initialize + + ATN MLA My listen address + ATN SCG Secondary command 08H + ppd Parallel poll disabled + DAB Opcode 08H, 09H, 0BH + EOI DAB Unused data byte + ATN UNL Unlisten + + ATN MLA My listen address + ATN SCG Secondary command 00H + DAB Write data byte #1 + ... + EOI DAB Write data byte #n + ppe Parallel poll enabled + ATN UNL Unlisten + + + Implementation notes: + + 1. The 12745 does not alter the parallel poll response for the + Device-Specified Jump command. + + 2. The 7910 does not perform a parallel poll response enable and disable + between the Initiate Self-Test and Return Self-Test Result commands. + + 3. The 12745 does not disable the parallel poll response for the Read + Loopback command. +*/ + + + +#include "hp2100_defs.h" +#include "hp2100_di.h" +#include "hp_disclib.h" + + + +/* Program constants */ + +#define DA_UNITS 4 /* number of addressable disc units */ + + +/* Interface states */ + +typedef enum { + idle = 0, /* idle = default for reset */ + opcode_wait, /* waiting for opcode reception */ + parameter_wait, /* waiting for parameter reception */ + read_wait, /* waiting for send read data secondary */ + write_wait, /* waiting for receive write data secondary */ + status_wait, /* waiting for send status secondary */ + command_exec, /* executing an interface command */ + command_wait, /* waiting for command completion */ + read_xfer, /* sending read data or status */ + write_xfer, /* receiving write data */ + error_source, /* sending bytes for error recovery */ + error_sink /* receiving bytes for error recovery */ + } IF_STATE; + + +/* Interface state names */ + +static const char *if_state_name [] = { + "idle", + "opcode wait", + "parameter wait", + "read wait", + "write wait", + "status wait", + "command execution", + "command wait", + "read transfer", + "write transfer", + "error source", + "error sink" + }; + + +/* Next interface state after command recognition */ + +static const IF_STATE next_state [] = { + read_wait, /* cold load read */ + command_exec, /* recalibrate */ + command_exec, /* seek */ + status_wait, /* request status */ + status_wait, /* request sector address */ + read_wait, /* read */ + read_wait, /* read full sector */ + command_exec, /* verify */ + write_wait, /* write */ + write_wait, /* write full sector */ + command_exec, /* clear */ + write_wait, /* initialize */ + command_exec, /* address record */ + idle, /* request syndrome */ + read_wait, /* read with offset */ + command_exec, /* set file mask */ + idle, /* invalid */ + idle, /* invalid */ + read_wait, /* read without verify */ + idle, /* load TIO register */ + status_wait, /* request disc address */ + command_exec, /* end */ + idle /* wakeup */ + }; + + +/* Interface commands */ + +typedef enum { + invalid = 0, /* invalid = default for reset */ + disc_command, /* MLA 08 */ + crc_listen, /* MLA 09 */ + amigo_clear, /* MLA 10 */ + write_loopback, /* MLA 1E */ + initiate_self_test, /* MLA 1F */ + crc_talk, /* MTA 09 */ + device_specified_jump, /* MTA 10 */ + read_loopback, /* MTA 1E */ + return_self_test_result, /* MTA 1F */ + amigo_identify /* UNT MSA */ + } IF_COMMAND; + +/* Interface command names */ + +static const char *if_command_name [] = { + "invalid", + "disc command", + "CRC listen", + "Amigo clear", + "write loopback", + "initiate self-test", + "CRC talk", + "device specified jump", + "read loopback", + "return self-test result", + "Amigo identify" + }; + + + +/* Amigo disc state variables */ + +static uint16 buffer [DL_BUFSIZE]; /* command/status/sector buffer */ + +static uint8 if_dsj [DA_UNITS]; /* ICD controller DSJ values */ +static IF_STATE if_state [DA_UNITS]; /* ICD controller state */ +static IF_COMMAND if_command [DA_UNITS]; /* ICD controller command */ + +static CNTLR_VARS icd_cntlr [DA_UNITS] = /* ICD controllers: */ + { { CNTLR_INIT (ICD, buffer, NULL) }, /* unit 0 controller */ + { CNTLR_INIT (ICD, buffer, NULL) }, /* unit 1 controller */ + { CNTLR_INIT (ICD, buffer, NULL) }, /* unit 2 controller */ + { CNTLR_INIT (ICD, buffer, NULL) } }; /* unit 3 controller */ + + + +/* Amigo disc global VM routines */ + +t_stat da_reset (DEVICE *dptr); +t_stat da_attach (UNIT *uptr, char *cptr); +t_stat da_detach (UNIT *uptr); + +/* Amigo disc global SCP routines */ + +t_stat da_load_unload (UNIT *uptr, int32 value, char *cptr, void *desc); + +/* Amigo disc local utility routines */ + +static t_bool start_command (uint32 unit); +static void abort_command (uint32 unit, CNTLR_STATUS status, IF_STATE state); +static void complete_read (uint32 unit); +static void complete_write (uint32 unit); +static void complete_abort (uint32 unit); +static uint8 get_buffer_byte (CVPTR cvptr); +static void put_buffer_byte (CVPTR cvptr, uint8 data); +static t_stat activate_unit (UNIT *uptr); + + + +/* Amigo disc VM global data structures. + + da_dib DA device information block + da_unit DA unit list + da_reg DA register list + da_mod DA modifier list + da_dev DA device descriptor + + + Implementation notes: + + 1. The IFSTAT and IFCMD registers are declared to accommodate the + corresponding arrays of enums. Arrayed registers assume that elements + are allocated space only to the integral number of bytes implied by the + "width" field. The storage size of an enum is implementation-defined, so + we must determine the number of bits for "width" at compile time. + PV_LEFT is used to avoid the large number of leading zeros that would be + displayed if an implementation stored enums in full words. + + 2. The CNVARS register is included to ensure that the controller state + variables array is saved by a SAVE command. It is declared as a hidden, + read-only byte array of a depth compatible with the size of the array. + + There does not appear to be a way to expose the fields of the four + controller state variables as arrayed registers. Access to an array + always assumes that elements appear at memory offsets equal to the + element size, i.e., a 32-bit arrayed register has elements at four-byte + offsets. There's no way to specify an array of structure elements where + a given 32-bit field appears at, say, 92-byte offsets (i.e., the size of + the structure). +*/ + +DEVICE da_dev; + +DIB da_dib = { &di_io, DI_DA, da }; + +#define UNIT_FLAGS (UNIT_FIX | UNIT_ATTABLE | UNIT_ROABLE | UNIT_DISABLE | UNIT_UNLOAD) + +UNIT da_unit [] = { + { UDATA (&da_service, UNIT_FLAGS | MODEL_7906 | SET_BUSADR (0), D7906_WORDS) }, /* drive unit 0 */ + { UDATA (&da_service, UNIT_FLAGS | MODEL_7906 | SET_BUSADR (1), D7906_WORDS) }, /* drive unit 1 */ + { UDATA (&da_service, UNIT_FLAGS | MODEL_7906 | SET_BUSADR (2), D7906_WORDS) }, /* drive unit 2 */ + { UDATA (&da_service, UNIT_FLAGS | MODEL_7906 | SET_BUSADR (3), D7906_WORDS) } /* drive unit 3 */ + }; + +REG da_reg [] = { + DI_REGS (da), + + { BRDATA (BUFFER, buffer, 8, 16, DL_BUFSIZE) }, + + { BRDATA (DSJ, if_dsj, 10, 2, DA_UNITS) }, + { BRDATA (ISTATE, if_state, 10, sizeof (IF_STATE) * CHAR_BIT, DA_UNITS), PV_LEFT }, + { BRDATA (ICMD, if_command, 10, sizeof (IF_COMMAND) * CHAR_BIT, DA_UNITS), PV_LEFT }, + + { BRDATA (CNVARS, icd_cntlr, 10, CHAR_BIT, sizeof (CNTLR_VARS) * DA_UNITS), REG_HRO }, + + { NULL } + }; + +MTAB da_mod [] = { + DI_MODS (da_dev), + + { UNIT_UNLOAD, UNIT_UNLOAD, "heads unloaded", "UNLOADED", &da_load_unload, NULL, NULL }, + { UNIT_UNLOAD, 0, "heads loaded", "LOADED", &da_load_unload, NULL, NULL }, + + { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL, NULL, NULL }, + { UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL, NULL, NULL }, + + { UNIT_FMT, UNIT_FMT, "format enabled", "FORMAT", NULL, NULL, NULL }, + { UNIT_FMT, 0, "format disabled", "NOFORMAT", NULL, NULL, NULL }, + + { UNIT_MODEL, MODEL_7906, "7906H", "7906H", &dl_set_model, NULL, NULL }, + { UNIT_MODEL, MODEL_7920, "7920H", "7920H", &dl_set_model, NULL, NULL }, + { UNIT_MODEL, MODEL_7925, "7925H", "7925H", &dl_set_model, NULL, NULL }, + + { 0 } + }; + +DEVICE da_dev = { + "DA", /* device name */ + da_unit, /* unit array */ + da_reg, /* register array */ + da_mod, /* modifier array */ + DA_UNITS, /* number of units */ + 10, /* address radix */ + 26, /* address width */ + 1, /* address increment */ + 8, /* data radix */ + 16, /* data width */ + NULL, /* examine routine */ + NULL, /* deposit routine */ + &da_reset, /* reset routine */ + &da_boot, /* boot routine */ + &da_attach, /* attach routine */ + &da_detach, /* detach routine */ + &da_dib, /* device information block */ + DEV_DEBUG | DEV_DISABLE, /* device flags */ + 0, /* debug control flags */ + di_deb, /* debug flag name table */ + NULL, /* memory size change routine */ + NULL /* logical device name */ + }; + + + +/* Amigo disc global VM routines */ + + +/* Service an Amigo disc drive I/O event. + + The service routine is called to execute commands and control the transfer of + data to and from the HP-IB card. The actions to be taken depend on the + current state of the ICD interface. The possibilities are: + + 1. A command is pending on the interface. This occurs only when a command + is received while a Seek or Recalibrate command is in progress. + + 2. A command is executing. + + 3. Data is being sent or received over the HP-IB during command execution. + + 4. Dummy bytes are being sent or received over the HP-IB due to a command + error. + + Entry to the the service routine in any other interface state or to process a + command not allowed in a valid state will return an Internal Error to cause a + simulator stop. Exit from the routine will be either in one of the above + states, or in the idle state if the operation is complete. + + The specific actions taken for the various interface states are as follows: + + command_wait + ============ + + We are entered in this state only if a unit that was busy (still seeking) + was addressed to listen or talk. The card has been held off by asserting + NRFD after receiving MLA or MTA. Upon entry, we complete the seek and then + release the interface by denying NRFD to allow the remainder of the command + sequence to be received from the card. + + command_exec + ============ + + We are entered in this state to initiate, continue, or complete a command. + The command may be a disc command, such as Seek or Read, or an interface + command, such as Amigo Identify or Device-Specified Jump. + + Disc commands call the disc library service routine to perform all of the + common controller actions. Any ICD-specific actions needed, such as + setting the DSJ value, are performed after the call. + + Certain disc commands require multiple execution phases. For example, the + Read command has a start phase that reads data from the disc image file + into the sector buffer, a data phase that transfers bytes from the buffer + to the card, and an end phase that schedules the intersector gap time and + resets to the start phase. Data phase transfers are performed in the + read_xfer or write_xfer interface states. + + The results of the disc library service are inferred by the controller + state. If the controller is busy, then the command continues in a new + phase. Otherwise, the command either has completed normally or has + terminated with an error. If an error has occurred during a disc command + that transfers data, DSJ is set to 1, and the interface state is changed to + source or sink dummy bytes to complete the command sequence. + + Interface commands may either complete immediately (e.g., Amigo Clear) or + transfer data (e.g., DSJ). + + read_xfer + ========= + + Commands that send data to the CPU enter the service routine to source a + byte to the bus. Bytes are transferred only when ATN and NRFD are denied; + if they are not, we simply exit, as we will be rescheduled when the lines + are dropped. Otherwise, we get a byte from the sector buffer and send it + to the card. If the card has stopped listening, or the buffer is now + empty, then we terminate the transfer and move to the end phase of the + command. Otherwise, we reschedule the next data phase byte transfer. + + Disc and interface commands are handled separately, as EOI is always + asserted on the last byte of an interface command transfer and never on a + (good) disc command transfer. + + write_xfer + ========== + + Commands that receive data from the CPU enter the service routine to + determine whether or not to continue the transfer. Our bus accept routine + has already stored the received byte in the sector buffer and has asserted + NRFD to hold off the card. If the buffer is now full, or the byte was + tagged with EOI, then we terminate the transfer and move to the end phase + of the command. Otherwise, we deny NRFD and exit; we will be rescheduled + when the next byte arrives. + + error_source + ============ + + If an error occurred during the data transfer phase of a read or status + command, a dummy byte tagged with EOI is sourced to the bus. This allows + the OS driver for the card to terminate the command and request the + controller's status. + + error_sink + ========== + + If an error occurred during the data transfer phase of a write command, + dummy bytes are sunk from the bus until EOI is seen or the card is + unaddressed. This allows the OS driver to complete the command as expected + and then determine the cause of the failure by requesting the controller's + status. + + + Implementation notes: + + 1. The disc library sets the controller state to idle for a normal End, + Seek, or Recalibrate command and to wait for all other commands that end + normally. So we determine command completion by checking if the + controller is not busy, rather than checking if the controller is idle. + + Drive Attention status is the normal result of the completion of a Seek + or Recalibrate command. Normal Completion status is the normal result of + all other commands. + + 2. The disc library returns the buffer length in words. We double the + return value to count bytes. + + 3. Some commands, such as DSJ, could be completed in the bus accept routine. + They are serviced here instead to avoid presenting a zero execution time + to the CPU. + + 4. The Amigo command set does not provide the disc with the number of bytes + that will be read, and the unit expects to be untalked when the read is + to terminate. The RTE ICD bootstrap extension does not do this. + Instead, it resets the card via CLC 0,C to terminate the Cold Load Read + that was started by the ICD boot loader ROM. + + In hardware, if the LSTN control bit is cleared, e.g., by CRS, + transmission stops because the card denies NDAC and NRFD (the HP-IB + handshake requires NDAC and NRFD to be asserted to start the handshake + sequence; TACS * SDYS * ~NDAC * ~NRFD is an error condition). In + simulation, we handle this by terminating a read transfer if the card + stops accepting. If we did not, then the disc would continue to source + bytes to the bus, overflowing the card FIFO (a FIFO full condition cannot + assert NRFD if the LSTN control bit is clear). +*/ + +t_stat da_service (UNIT *uptr) +{ +uint8 data; +CNTLR_CLASS command_class; +const int32 unit = uptr - da_unit; /* get the disc unit number */ +const CVPTR cvptr = &icd_cntlr [unit]; /* get a pointer to the controller */ +t_stat result = SCPE_OK; +t_bool release_interface = FALSE; + +switch (if_state [unit]) { /* dispatch the interface state */ + + case command_wait: /* command is waiting */ + release_interface = TRUE; /* release the interface at then end if it's idle */ + + /* fall into the command_exec handler to process the current command */ + + case command_exec: /* command is executing */ + switch (if_command [unit]) { /* dispatch the interface command */ + + case disc_command: /* execute a disc command */ + result = dl_service_drive (cvptr, uptr); /* service the disc unit */ + + if (cvptr->opcode == Clear) /* is this a Clear command? */ + if_dsj [unit] = 2; /* indicate that the self test is complete */ + + if (cvptr->state != cntlr_busy) { /* has the controller stopped? */ + if_state [unit] = idle; /* idle the interface */ + + if (cvptr->status == normal_completion || /* do we have normal completion */ + cvptr->status == drive_attention) /* or drive attention? */ + break; /* we're done */ + + else { /* if the status is abnormal */ + if_dsj [unit] = 1; /* an error has occurred */ + + command_class = dl_classify (*cvptr); /* classify the command */ + + if (command_class == class_write) { /* did a write command fail? */ + if_state [unit] = error_sink; /* sink the remaining bytes */ + uptr->wait = cvptr->cmd_time; /* activate to complete processing */ + } + + else if (command_class != class_control) { /* did a read or status command fail? */ + if_state [unit] = error_source; /* source an error byte */ + uptr->wait = cvptr->cmd_time; /* activate to complete processing */ + } + } + } + + else if (uptr->PHASE == data_phase) { /* are we starting the data phase? */ + cvptr->length = cvptr->length * 2; /* convert the buffer length to bytes */ + + if (dl_classify (*cvptr) == class_write) /* is this a write command? */ + if_state [unit] = write_xfer; /* set for a write data transfer */ + else /* it is a read or status command */ + if_state [unit] = read_xfer; /* set for a read data transfer */ + } + + break; + + + case amigo_identify: /* Amigo Identify */ + buffer [0] = 0x0003; /* store the response in the buffer */ + cvptr->length = 2; /* return two bytes */ + + if_state [unit] = read_xfer; /* we are ready to transfer the data */ + uptr->wait = cvptr->cmd_time; /* schedule the transfer */ + + if (DEBUG_PRI (da_dev, DEB_RWSC)) + fprintf (sim_deb, ">>DA rwsc: Unit %d Amigo identify response %04XH\n", + unit, buffer [0]); + break; + + + case initiate_self_test: /* Initiate a self test */ + sim_cancel (&da_unit [unit]); /* cancel any operation in progress */ + dl_clear_controller (cvptr, /* hard-clear the controller */ + &da_unit [unit], + hard_clear); + if_dsj [unit] = 2; /* set DSJ for self test completion */ + if_state [unit] = idle; /* the command is complete */ + di_poll_response (da, unit, SET); /* with PPR enabled */ + break; + + + case amigo_clear: /* Amigo clear */ + dl_idle_controller (cvptr); /* idle the controller */ + if_dsj [unit] = 0; /* clear the DSJ value */ + if_state [unit] = idle; /* the command is complete */ + di_poll_response (da, unit, SET); /* with PPR enabled */ + break; + + + default: /* no other commands are executed */ + result = SCPE_IERR; /* signal an internal error */ + break; + } /* end of command dispatch */ + break; + + + case error_source: /* send data after an error */ + if (! (di [da].bus_cntl & (BUS_ATN | BUS_NRFD))) { /* is the card ready for data? */ + di [da].bus_cntl |= BUS_EOI; /* set EOI */ + di_bus_source (da, 0); /* and send a dummy byte to the card */ + if_state [unit] = idle; /* the command is complete */ + } + break; + + + case read_xfer: /* send read data */ + if (! (di [da].bus_cntl & (BUS_ATN | BUS_NRFD))) /* is the card ready for data? */ + switch (if_command [unit]) { /* dispatch the interface command */ + + case disc_command: /* disc read or status commands */ + data = get_buffer_byte (cvptr); /* get the next byte from the buffer */ + + if (di_bus_source (da, data) == FALSE) /* send the byte to the card; is it listening? */ + cvptr->eod = SET; /* no, so terminate the read */ + + if (cvptr->length == 0 || cvptr->eod == SET) { /* is the data phase complete? */ + uptr->PHASE = end_phase; /* set the end phase */ + + if (cvptr->opcode == Request_Status) /* is it a Request Status command? */ + if_dsj [unit] = 0; /* clear the DSJ value */ + + if_state [unit] = command_exec; /* set to execute the command */ + uptr->wait = cvptr->cmd_time; /* and reschedule the service */ + } + + else /* the data phase continues */ + uptr->wait = cvptr->data_time; /* reschedule the next transfer */ + + break; + + + case amigo_identify: + case read_loopback: + case return_self_test_result: + data = get_buffer_byte (cvptr); /* get the next byte from the buffer */ + + if (cvptr->length == 0) /* is the transfer complete? */ + di [da].bus_cntl |= BUS_EOI; /* set EOI */ + + if (di_bus_source (da, data) /* send the byte to the card; is it listening? */ + && cvptr->length > 0) /* and is there more to transfer? */ + uptr->wait = cvptr->data_time; /* reschedule the next transfer */ + + else { /* the transfer is complete */ + if_state [unit] = idle; /* the command is complete */ + di_poll_response (da, unit, SET); /* enable the PPR */ + } + break; + + + case device_specified_jump: + di [da].bus_cntl |= BUS_EOI; /* set EOI */ + di_bus_source (da, if_dsj [unit]); /* send the DSJ value to the card */ + if_state [unit] = idle; /* the command is complete */ + break; + + + case crc_talk: + di [da].bus_cntl |= BUS_EOI; /* set EOI */ + di_bus_source (da, 0); /* send dummy bytes */ + break; /* until the card untalks */ + + + default: /* no other commands send data */ + result = SCPE_IERR; /* signal an internal error */ + break; + } /* end of read data transfer dispatch */ + break; + + + case error_sink: /* absorb data after an error */ + cvptr->index = 0; /* absorb data until EOI asserts */ + + if (cvptr->eod == SET) /* is the transfer complete? */ + if_state [unit] = idle; /* the command is complete */ + + di_bus_control (da, unit, 0, BUS_NRFD); /* deny NRFD to allow the card to resume */ + break; + + + case write_xfer: /* receive write data */ + switch (if_command [unit]) { /* dispatch the interface command */ + + case disc_command: /* disc write commands */ + if (cvptr->length == 0 || cvptr->eod == SET) { /* is the data phase complete? */ + uptr->PHASE = end_phase; /* set the end phase */ + + if_state [unit] = command_exec; /* set to execute the command */ + uptr->wait = cvptr->cmd_time; /* and schedule the service */ + + if (cvptr->eod == CLEAR) /* is the transfer continuing? */ + break; /* do not deny NRFD until next service! */ + } + + di_bus_control (da, unit, 0, BUS_NRFD); /* deny NRFD to allow the card to resume */ + break; + + + case write_loopback: + if (cvptr->eod == SET) { /* is the transfer complete? */ + cvptr->length = 16 - cvptr->length; /* set the count of bytes transferred */ + if_state [unit] = idle; /* the command is complete */ + } + + di_bus_control (da, unit, 0, BUS_NRFD); /* deny NRFD to allow the card to resume */ + break; + + + default: /* no other commands receive data */ + result = SCPE_IERR; /* signal an internal error */ + break; + } /* end of write data transfer dispatch */ + break; + + + default: /* no other states schedule service */ + result = SCPE_IERR; /* signal an internal error */ + break; + } /* end of interface state dispatch */ + + +if (uptr->wait) /* is service requested? */ + activate_unit (uptr); /* schedule the next event */ + +if (result == SCPE_IERR && DEBUG_PRI (da_dev, DEB_RWSC)) { /* did an internal error occur? */ + fprintf (sim_deb, ">>DA rwsc: Unit %d ", unit); /* report it if debugging */ + + if (if_state [unit] == command_exec + && if_command [unit] == disc_command) + fprintf (sim_deb, "%s command %s phase ", + dl_opcode_name (ICD, (CNTLR_OPCODE) uptr->OP), + dl_phase_name ((CNTLR_PHASE) uptr->PHASE)); + else + fprintf (sim_deb, "%s state %s ", + if_command_name [if_command [unit]], + if_state_name [if_state [unit]]); + + fputs ("service not handled\n", sim_deb); + } + +if (if_state [unit] == idle) { /* is the command now complete? */ + if (if_command [unit] == disc_command) { /* did a disc command complete? */ + if (cvptr->opcode != End) /* yes; if the command was not End, */ + di_poll_response (da, unit, SET); /* then enable PPR */ + + if (DEBUG_PRI (da_dev, DEB_RWSC)) + fprintf (sim_deb, ">>DA rwsc: Unit %d %s disc command completed\n", + unit, dl_opcode_name (ICD, cvptr->opcode)); + } + + else /* an interface command completed */ + if (DEBUG_PRI (da_dev, DEB_RWSC)) + fprintf (sim_deb, ">>DA rwsc: Unit %d %s command completed\n", + unit, if_command_name [if_command [unit]]); + + if (release_interface) /* if the next command is already pending */ + di_bus_control (da, unit, 0, BUS_NRFD); /* deny NRFD to allow the card to resume */ + } + +return result; /* return the result of the service */ +} + + +/* Reset or preset the simulator. + + In hardware, a self-test is performed by the controller at power-on. When + the self-test completes, the controller sets DSJ = 2 and enables the parallel + poll response. + + A front panel PRESET or programmed CRS has no direct effect on the controller + or drive. However, the card reacts to CRS by clearing its talker and + listener states, so an in-progress read or status command will abort when the + next byte sourced to the bus finds no acceptors. +*/ + +t_stat da_reset (DEVICE *dptr) +{ +uint32 unit; +t_stat status; + +status = di_reset (dptr); /* reset the card */ + +if (status == SCPE_OK && (sim_switches & SWMASK ('P'))) /* is the card OK and is this a power-on reset? */ + for (unit = 0; unit < dptr->numunits; unit++) { /* loop through the units */ + sim_cancel (dptr->units + unit); /* cancel any current activation */ + dptr->units [unit].CYL = 0; /* reset the head position */ + dptr->units [unit].pos = 0; /* to cylinder 0 */ + + dl_clear_controller (&icd_cntlr [unit], /* hard-clear the controller */ + dptr->units + unit, + hard_clear); + + if_state [unit] = idle; /* reset the interface state */ + if_command [unit] = invalid; /* reset the interface command */ + + if_dsj [unit] = 2; /* set the DSJ for power up complete */ + } + +return status; +} + + +/* Attach a unit to a disc image file. + + The simulator considers an attached unit to be connected to the bus and an + unattached unit to be disconnected, so we set the card's acceptor bit for the + selected unit if the attach is successful. An attached unit is ready if the + heads are loaded or not ready if not. + + This model is slightly different than the MAC (DS) simulation, where an + unattached unit is considered "connected but not ready" -- the same + indication returned by an attached unit whose heads are unloaded. Therefore, + the situation when the simulator is started is that all DS units are + "connected to the controller but not ready," whereas all DA units are "not + connected to the bus." This eliminates the overhead of sending HP-IB + messages to unused units. + + In tabular form, the simulator responses are: + + Enabled Loaded Attached DS (MAC) DA (ICD) + ------- ------ -------- ------------ ------------ + N N N disconnected disconnected + N N Y -- -- + N Y N -- -- + N Y Y -- -- + Y N N unloaded disconnected + Y N Y unloaded unloaded + Y Y N -- -- + Y Y Y ready ready + + The unspecified responses are illegal conditions; for example, the simulator + does not allow an attached unit to be disabled. + + + Implementation notes: + + 1. To conform exactly to the MAC responses would have required intercepting + the SET DISABLED/ENABLED commands in order to clear or set the unit + accepting bits. However, short of intercepting the all SET commands with + a custom command table, there is no way to ensure that unit enables are + observed. Adding ENABLED and DISABLED to the modifiers table and + specifying a validation routine works for the DISABLED case but not the + ENABLED case -- set_unit_enbdis returns SCPE_UDIS before calling the + validation routine. +*/ + +t_stat da_attach (UNIT *uptr, char *cptr) +{ +t_stat result; +const int32 unit = uptr - da_unit; /* calculate the unit number */ + +result = dl_attach (&icd_cntlr [unit], uptr, cptr); /* attach the drive */ + +if (result == SCPE_OK) /* was the attach successful? */ + di [da].acceptors |= (1 << unit); /* set the unit's accepting bit */ + +return result; +} + + +/* Detach a disc image file from a unit. + + As explained above, detaching a unit is the hardware equivalent of + disconnecting the drive from the bus, so we clear the unit's acceptor bit if + the detach is successful. +*/ + +t_stat da_detach (UNIT *uptr) +{ +t_stat result; +const int32 unit = uptr - da_unit; /* calculate the unit number */ + +result = dl_detach (&icd_cntlr [unit], uptr); /* detach the drive */ + +if (result == SCPE_OK) { /* was the detach successful? */ + di [da].acceptors &= ~(1 << unit); /* clear the unit's accepting bit */ + di_poll_response (da, unit, CLEAR); /* and its PPR, as it's no longer present */ + } + +return result; +} + + +/* Boot an Amigo disc drive. + + The ICD disc bootstrap program is loaded from the HP 12992H Boot Loader ROM + into memory, the I/O instructions are configured for the interface card's + select code, and the program is run to boot from the specified unit. The + loader supports booting the disc at bus address 0 only. Before execution, + the S register is automatically set as follows: + + 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 + ------ ------ ---------------------- ------------- ----- + ROM # 0 1 select code reserved head + + The boot routine sets bits 15-6 of the S register to appropriate values. + Bits 5-3 and 1-0 retain their original values, so S should be set before + booting. These bits are typically set to 0, although bit 5 is set for an RTE + reconfiguration boot, and bits 1-0 may be set if booting from a head other + than 0 is desired. +*/ + +static const BOOT_ROM da_rom = { + 0102501, /* START LIA 1 GET SWITCH REGISTER SETTING */ + 0100044, /* LSL 4 SHIFT A LEFT 4 */ + 0006111, /* CLE,SLB,RSS SR BIT 12 SET FOR MANUAL BOOT? */ + 0100041, /* LSL 1 NO. SHIFT HEAD # FOR RPL BOOT */ + 0001424, /* ALR,ALR SHIFT HEAD 2, CLEAR SIGN */ + 0033744, /* IOR HDSEC SET EOI BIT */ + 0073744, /* STA HDSEC PLACE IN COMMAND BUFFER */ + 0017756, /* JSB BTCTL SEND DUMMY,U-CLR,PP */ + 0102510, /* LIA IBI READ INPUT REGISTER */ + 0101027, /* ASR 7 SHIFT DRIVE 0 RESPONSE TO LSB */ + 0002011, /* SLA,RSS DID DRIVE 0 RESPOND? */ + 0027710, /* JMP *-3 NO, GO LOOK AGAIN */ + 0107700, /* CLC 0,C */ + 0017756, /* JSB BTCTL SEND TALK, CL-RD,BUS HOLDER */ + 0002300, /* CCE */ + 0017756, /* JSB BTCTL TELL CARD TO LISTEN */ + 0063776, /* LDA DMACW LOAD DMA CONTROL WORD */ + 0102606, /* OTA 6 OUTPUT TO DCPC */ + 0106702, /* CLC 2 READY DCPC */ + 0063735, /* LDA ADDR1 LOAD DMA BUFFER ADDRESS */ + 0102602, /* OTA 2 OUTPUT TO DCPC */ + 0063740, /* LDA DMAWC LOAD DMA WORD COUNT */ + 0102702, /* STC 2 READY DCPC */ + 0102602, /* OTA 2 OUTPUT TO DCPC */ + 0103706, /* STC 6,C START DCPC */ + 0102206, /* TEST SFC 6 SKIP IF DMA NOT DONE */ + 0117750, /* JSB ADDR2,I SUCCESSFUL END OF TRANSFER */ + 0102310, /* SFS IBI SKIP IF DISC ABORTED TRANSFER */ + 0027731, /* JMP TEST RECHECK FOR TRANSFER END */ + 0102011, /* ADDR1 HLT 11B ERROR HALT */ + 0000677, /* UNCLR OCT 677 UNLISTEN */ + 0000737, /* OCT 737 UNTALK */ + 0176624, /* DMAWC OCT 176624 UNIVERSAL CLEAR,LBO */ + 0000440, /* LIST OCT 440 LISTEN BUS ADDRESS 0 */ + 0000550, /* CMSEC OCT 550 SECONDARY GET COMMAND */ + 0000000, /* BOOT OCT 0 COLD LOAD READ COMMAND */ + 0001000, /* HDSEC OCT 1000 HEAD,SECTOR PLUS EOI */ + 0000677, /* UNLST OCT 677 ATN,PRIMARY UNLISTEN,PARITY */ + 0000500, /* TALK OCT 500 SEND READ DATA */ + 0100740, /* RDSEC OCT 100740 SECONDARY READ DATA */ + 0102055, /* ADDR2 OCT 102055 BOOT EXTENSION STARTING ADDRESS */ + 0004003, /* CTLP OCT 4003 INT=LBO,T,CIC */ + 0000047, /* OCT 47 PPE,L,T,CIC */ + 0004003, /* OCT 4003 INT=LBO,T,CIC */ + 0000413, /* OCT 413 ATN,P,L,CIC */ + 0001015, /* OCT 1015 INT=EOI,P,L,CIC */ + 0000000, /* BTCTL NOP */ + 0107710, /* CLC IBI,C RESET IBI */ + 0063751, /* BM LDA CTLP LOAD CONTROL WORD */ + 0102610, /* OTA IBI OUTPUT TO CONTROL REGISTER */ + 0102710, /* STC IBI RETURN IBI TO DATA MODE */ + 0037760, /* ISZ BM INCREMENT CONTROL WORD POINTER */ + 0002240, /* SEZ,CME */ + 0127756, /* JMP BTCTL,I RETURN */ + 0063736, /* LABL LDA UNCLR LOAD DATA WORD */ + 0037766, /* ISZ LABL INCREMENT WORD POINTER */ + 0102610, /* OTA IBI OUTPUT TO HPIB */ + 0002021, /* SSA,RSS SKIP IF LAST WORD */ + 0027766, /* JMP LABL GO BACK FOR NEXT WORD */ + 0102310, /* SFS IBI SKIP IF LAST WORD SENT TO BUS */ + 0027773, /* JMP *-1 RECHECK ACCEPTANCE */ + 0027757, /* JMP BTCTL+1 */ + 0000010, /* DMACW ABS IBI */ + 0170100 /* ABS -START */ + }; + +t_stat da_boot (int32 unitno, DEVICE *dptr) +{ +if (GET_BUSADR (da_unit [unitno].flags) != 0) /* booting is supported on bus address 0 only */ + return SCPE_NOFNC; /* report "Command not allowed" if attempted */ + +if (ibl_copy (da_rom, da_dib.select_code, /* copy the boot ROM to memory and configure */ + IBL_OPT | IBL_DS_HEAD, /* the S register accordingly */ + IBL_DS | IBL_MAN | IBL_SET_SC (da_dib.select_code))) + return SCPE_IERR; /* return an internal error if the copy failed */ +else + return SCPE_OK; +} + + + +/* Amigo disc global SCP routines */ + + +/* Load or unload a unit's heads. + + The heads are automatically loaded when a unit is attached and unloaded when + a unit is detached. While a unit is attached, the heads may be manually + unloaded; this yields a "not ready" status if the unit is accessed. An + unloaded drive may be manually loaded, returning the unit to "ready" status. + + The ICD controller sets Drive Attention status when the heads unload and also + asserts a parallel poll response if the heads unload while in idle state 2 + (i.e., after an End command). + + + Implementation notes: + + 1. The 13365 manual says on page 28 that Drive Attention status is + "Generated whenever...the drive unloads and the controller is in Idle + State 2 or 3." However, the ICD diagnostic tests for Drive Attention + status on head unload immediately after the Request Status command that + completes the previous step, which leaves the controller in idle state 1. + + Moreover, the diagnostic does NOT check for Drive Attention status if the + Amigo ID is 2 (MAC controller). But the 12745 manual says on page 3-7 + that the status is returned if "...Drive becomes not ready (heads + unload)" with no mention of controller state. + + It appears as though the diagnostic test is exactly backward. However, + we match the diagnostic expectation below. +*/ + +t_stat da_load_unload (UNIT *uptr, int32 value, char *cptr, void *desc) +{ +const int32 unit = uptr - da_unit; /* calculate the unit number */ +const t_bool load = (value != UNIT_UNLOAD); /* true if the heads are loading */ +t_stat result; + +result = dl_load_unload (&icd_cntlr [unit], uptr, load); /* load or unload the heads */ + +if (result == SCPE_OK && ! load) { /* was the unload successful? */ + icd_cntlr [unit].status = drive_attention; /* set Drive Attention status */ + + if (uptr->OP == End) /* is the controller in idle state 2? */ + di_poll_response (da, unit, SET); /* enable PPR */ + } + +return result; +} + + + +/* Amigo disc global bus routines */ + + +/* Accept a data byte from the bus. + + The indicated unit is offered a byte that has been sourced to the bus. The + routine returns TRUE or FALSE to indicate whether or not it accepted the + byte. + + Commands from the bus may be universal (applying to all acceptors) or + addressed (applying only to those acceptors that have been addressed to + listen). Data bytes are accepted only if the unit has been addressed to + listen. As we are called for a data transfer or an addressed command only if + we are currently listening, the only bytes that we do not accept are primary + talk or listen commands directed to another address, or secondary commands + when we are not addressed to listen. + + This routine handles the HP-IB protocol. The type of byte passed is + determined by the state of the ATN signal and, if ATN is asserted, by the + high-order bits of the value. Most of the work involves decoding secondary + commands and their associated data parameters. The interface state is + changed as needed to track the command protocol. The states processed in + this routine are: + + opcode_wait + =========== + + A Receive Disc Command secondary has been received, and the interface is + waiting for the opcode that should follow. + + parameter_wait + ============== + + A disc opcode or interface command has been received, and the interface is + waiting for a parameter byte that should follow. + + write_wait + ========== + + A disc write command has been received, and the interface is waiting for + the Receive Write Data secondary that should follow. + + read_wait + ========= + + A disc read command has been received, and the interface is waiting for the + Send Read Data secondary that should follow. + + status_wait + =========== + + A disc status command has been received, and the interface is waiting for + the Send Disc Status secondary that should follow. + + write_xfer + ========== + + A disc write is in progress, and the interface is waiting for a data byte + that should follow. + + error_sink + ========== + + A disc write has terminated with an error, and the interface is waiting to + absorb all of the remaining data bytes of the transfer. + + + Disc commands and parameters are assembled in the sector buffer before being + passed to the disc library to start the command. Once the command is + started, the interface state is set either to execute the command or to wait + for the receipt of a data transfer secondary before executing, depending on + the command. + + Two disc command protocol errors are detected. First, an Illegal Opcode is + identified during the check for the expected number of disc command + parameters. This allows us to sink an arbitrary number of parameter bytes. + Second, an I/O Program Error occurs if an unsupported secondary is received + or the HP-IB sequence is incorrect. The latter occurs if a command has the + wrong number of parameters or a secondary data transfer sequence is invalid. + + Disc commands that require data transfers (e.g., Read, Write, Request Status) + involve a pair of secondaries. The first transmits the command, and the + second transmits or receives the data. If one occurs without the other, an + I/O Program Error occurs. + + A secondary or command that generates an I/O Program Error is always ignored. + Error recovery is as follows: + + - An unsupported talk secondary sends a single data byte tagged with EOI. + + - An unsupported listen secondary accepts and discards any accompanying data + bytes until EOI is asserted or an Unlisten is received. + + - A supported command with too few parameter bytes or for which the last + parameter byte is not tagged with EOI (before unlisten) does nothing. + + - A supported command with too many parameter bytes accepts and discards + excess parameter bytes until EOI is asserted or an Unlisten is received. + + - A read or status command that is not followed by a Send Read Data or a + Send Disc Status secondary does nothing. The unexpected secondary is + executed normally. + + - A write command that is not followed by a Receive Write Data secondary + does nothing. The unexpected secondary is executed normally. + + - A Send Read Data or a Send Disc Status secondary that is not preceded by a + read or status command sends a single data byte tagged with EOI. + + - A Receive Write Data secondary that is not preceded by a write command + accepts and discards data bytes until EOI is asserted or an Unlisten is + received. + + The Amigo command sequence does not provide a byte count for disc read and + write commands, so the controller continues to source or accept data bytes + until the device is unaddressed. Normally, this is done by an Unlisten or + Untalk. However, per IEEE-488, a listening device may be unaddressed by IFC, + by an Unlisten, or by addressing the device to talk, and a talking device may + be unaddressed by IFC, by addressing another device to talk (or no device via + Untalk), or by addressing the device to listen. Therefore, we must keep + track of whether the unit stopped talking or listening, and if it has, we + check for command termination. + + If the controller is unaddressed in the middle of a sector transfer, the read + or write must be terminated cleanly to ensure that the disc image is + coherent. It is also permissible to untalk the controller before all of the + requested status bytes are returned. + + In addition, the controller has no way to inform the host that an error has + occurred that prevents the command from continuing. For example, if a data + error is encountered while reading or a protected track is encountered while + writing, the controller must still source or sink data bytes until the + command is terminated by the host. The controller handles read errors by + sourcing a single data byte tagged with EOI and write errors by sinking data + bytes until EOI is seen or the unit is unaddressed. + + Therefore, if the unit is unaddressed while a read, write, or status command + is transferring data, the unit service must be scheduled to end the current + command. Unaddressing while an error condition is present merely terminates + the source or sink operation. + + + Implementation notes: + + 1. The 13365 manual does not indicate that the controller responds to + Universal Clear, but the 12992H loader ROM issues this primary and + expects the controller to initialize. + + 2. It is not necessary to check for listening when processing addressed + commands, as only listeners are called by the bus source. +*/ + +t_bool da_bus_accept (uint32 unit, uint8 data) +{ +const uint8 message_address = data & BUS_ADDRESS; +t_bool accepted = TRUE; +t_bool initiated = FALSE; +t_bool addressed = FALSE; +t_bool stopped_listening = FALSE; +t_bool stopped_talking = FALSE; +char action [40] = ""; +uint32 my_address; + +if (di [da].bus_cntl & BUS_ATN) { /* is it a bus command (ATN asserted)? */ + switch (data & BUS_GROUP) { /* dispatch the bus group */ + + case BUS_PCG: /* primary command group */ + switch (message_address) { + + case 0x04: /* selected device clear */ + case 0x05: /* SDC with parity freeze */ + case 0x14: /* universal clear */ + if (DEBUG_PRI (da_dev, DEB_RWSC)) + fprintf (sim_deb, ">>DA rwsc: Unit %d device cleared\n", unit); + + sim_cancel (&da_unit [unit]); /* cancel any in-progress command */ + dl_idle_controller (&icd_cntlr [unit]); /* idle the controller */ + if_dsj [unit] = 0; /* clear DSJ */ + if_state [unit] = idle; /* idle the interface */ + di_poll_response (da, unit, SET); /* enable PPR */ + + if (DEBUG_PRI (da_dev, DEB_XFER)) + strcpy (action, "device clear"); + break; + + + default: /* unsupported universal command */ + break; /* universals are always accepted */ + } + + break; + + + case BUS_LAG: /* listen address group */ + my_address = GET_BUSADR (da_unit [unit].flags); /* get my bus address */ + + if (message_address == my_address) { /* is it my listen address? */ + di [da].listeners |= (1 << unit); /* set my listener bit */ + di [da].talker &= ~(1 << unit); /* clear my talker bit */ + + addressed = TRUE; /* unit is now addressed */ + stopped_talking = TRUE; /* MLA stops the unit from talking */ + + if (DEBUG_PRI (da_dev, DEB_XFER)) + sprintf (action, "listen %d", message_address); + } + + else if (message_address == BUS_UNADDRESS) { /* is it an Unlisten? */ + di [da].listeners = 0; /* clear all of the listeners */ + + stopped_listening = TRUE; /* UNL stops the unit from listening */ + + if (DEBUG_PRI (da_dev, DEB_XFER)) + strcpy (action, "unlisten"); + } + + else /* other listen addresses */ + accepted = FALSE; /* are not accepted */ + + break; + + + case BUS_TAG: /* talk address group */ + my_address = GET_BUSADR (da_unit [unit].flags); /* get my bus address */ + + if (message_address == my_address) { /* is it my talk address? */ + di [da].talker = (1 << unit); /* set my talker bit and clear the others */ + di [da].listeners &= ~(1 << unit); /* clear my listener bit */ + + addressed = TRUE; /* the unit is now addressed */ + stopped_listening = TRUE; /* MTA stops the unit from listening */ + + if (DEBUG_PRI (da_dev, DEB_XFER)) + sprintf (action, "talk %d", message_address); + } + + else { /* it is some other talker (or Untalk) */ + di [da].talker &= ~(1 << unit); /* clear my talker bit */ + + stopped_talking = TRUE; /* UNT or OTA stops the unit from talking */ + + if (message_address != BUS_UNADDRESS) /* other talk addresses */ + accepted = FALSE; /* are not accepted */ + + else /* it's an Untalk */ + if (DEBUG_PRI (da_dev, DEB_XFER)) + strcpy (action, "untalk"); + } + + break; + + + case BUS_SCG: /* secondary command group */ + icd_cntlr [unit].index = 0; /* reset the buffer index */ + + if (di [da].listeners & (1 << unit)) { /* is it a listen secondary? */ + if (if_state [unit] == write_wait /* if we're waiting for a write data secondary */ + && message_address != 0x00) /* but it's not there, */ + abort_command (unit, io_program_error, /* then abort the pending command */ + idle); /* and process the new command */ + + switch (message_address) { /* dispatch the listen secondary */ + + case 0x00: /* Receive Write Data */ + if (if_state [unit] != write_wait) /* if we're not expecting it */ + abort_command (unit, io_program_error, /* abort and sink any data */ + error_sink); + else { /* the sequence is correct */ + if_state [unit] = command_exec; /* the command is ready to execute */ + da_unit [unit].wait = icd_cntlr [unit].cmd_time; /* schedule the unit */ + di_bus_control (da, unit, BUS_NRFD, 0); /* assert NRFD to hold off the card */ + } + + initiated = TRUE; /* log the command or abort initiation */ + break; + + case 0x08: /* disc commands */ + if_command [unit] = disc_command; /* set the command and wait */ + if_state [unit] = opcode_wait; /* for the opcode that must follow */ + break; + + case 0x09: /* CRC (Listen) */ + if_command [unit] = crc_listen; /* set up the command */ + if_state [unit] = error_sink; /* sink any data that will be coming */ + initiated = TRUE; /* log the command initiation */ + break; + + case 0x10: /* Amigo Clear */ + if_command [unit] = amigo_clear; /* set up the command */ + if_state [unit] = parameter_wait; /* a parameter must follow */ + icd_cntlr [unit].length = 1; /* set to expect one (unused) byte */ + break; + + case 0x1E: /* Write Loopback */ + if_command [unit] = write_loopback; /* set up the command */ + if_state [unit] = write_xfer; /* data will be coming */ + icd_cntlr [unit].length = 16; /* accept only the first 16 bytes */ + initiated = TRUE; /* log the command initiation */ + break; + + case 0x1F: /* Initiate Self-Test */ + if_command [unit] = initiate_self_test; /* set up the command */ + if_state [unit] = parameter_wait; /* a parameter must follow */ + icd_cntlr [unit].length = 1; /* set to expect the test ID byte */ + break; + + default: /* an unsupported listen secondary was received */ + abort_command (unit, io_program_error, /* abort and sink any data */ + error_sink); /* that might accompany the command */ + initiated = TRUE; /* log the abort initiation */ + break; + } + } + + + else if (di [da].talker & (1 << unit)) { /* is it a talk secondary? */ + da_unit [unit].wait = icd_cntlr [unit].cmd_time; /* these are always scheduled and */ + initiated = TRUE; /* logged as initiated */ + + if (if_state [unit] == read_wait /* if we're waiting for a send data secondary */ + && message_address != 0x00 /* but it's not there */ + || if_state [unit] == status_wait /* or a send status secondary, */ + && message_address != 0x08) /* but it's not there */ + abort_command (unit, io_program_error, /* then abort the pending command */ + idle); /* and process the new command */ + + switch (message_address) { /* dispatch the talk secondary */ + + case 0x00: /* Send Read Data */ + if (if_state [unit] != read_wait) /* if we're not expecting it */ + abort_command (unit, io_program_error, /* abort and source a data byte */ + error_source); /* tagged with EOI */ + else + if_state [unit] = command_exec; /* the command is ready to execute */ + break; + + case 0x08: /* Read Status */ + if (if_state [unit] != status_wait) /* if we're not expecting it, */ + abort_command (unit, io_program_error, /* abort and source a data byte */ + error_source); /* tagged with EOI */ + else /* all status commands */ + if_state [unit] = read_xfer; /* are ready to transfer data */ + break; + + case 0x09: /* CRC (Talk) */ + if_command [unit] = crc_talk; /* set up the command */ + if_state [unit] = read_xfer; /* data will be going */ + break; + + case 0x10: /* Device-Specified Jump */ + if_command [unit] = device_specified_jump; /* set up the command */ + if_state [unit] = read_xfer; /* data will be going */ + break; + + case 0x1E: /* Read Loopback */ + if_command [unit] = read_loopback; /* set up the command */ + if_state [unit] = read_xfer; /* data will be going */ + break; + + case 0x1F: /* Return Self-Test Result */ + if_command [unit] = return_self_test_result; /* set up the command */ + if_state [unit] = read_xfer; /* data will be going */ + icd_cntlr [unit].length = 1; /* return one byte that indicates */ + buffer [0] = 0; /* that the self-test passed */ + break; + + default: /* an unsupported talk secondary was received */ + abort_command (unit, io_program_error, /* abort and source a data byte */ + error_source); /* tagged with EOI */ + break; + } + } + + + else { /* the unit is not addressed */ + my_address = GET_BUSADR (da_unit [unit].flags); /* get my bus address */ + + if (di [da].talker == 0 && di [da].listeners == 0 /* if there are no talkers or listeners */ + && message_address == my_address) { /* and this is my secondary address, */ + if_command [unit] = amigo_identify; /* then this is an Amigo ID sequence */ + if_state [unit] = command_exec; /* set up for execution */ + da_unit [unit].wait = icd_cntlr [unit].cmd_time; /* schedule the unit */ + initiated = TRUE; /* log the command initiation */ + } + + else /* unaddressed secondaries */ + accepted = FALSE; /* are not accepted */ + } + + + if (accepted) { /* was the command accepted? */ + if (DEBUG_PRI (da_dev, DEB_XFER)) + sprintf (action, "secondary %02XH", message_address); + + if (if_command [unit] != amigo_identify) /* disable PPR for all commands */ + di_poll_response (da, unit, CLEAR); /* except Amigo ID */ + } + + break; /* end of secondary processing */ + } + + + if (addressed && sim_is_active (&da_unit [unit])) { /* is the unit being addressed while it is busy? */ + if_state [unit] = command_wait; /* change the interface state to wait */ + di_bus_control (da, unit, BUS_NRFD, 0); /* and assert NRFD to hold off the card */ + + if (DEBUG_PRI (da_dev, DEB_RWSC)) + fprintf (sim_deb, ">>DA rwsc: Unit %d addressed while controller is busy\n", unit); + } + + if (stopped_listening) { /* was the unit Unlistened? */ + if (icd_cntlr [unit].state == cntlr_busy) /* if the controller is busy, */ + complete_write (unit); /* then check for write completion */ + + else if (if_command [unit] == invalid) /* if a command was aborting, */ + complete_abort (unit); /* then complete it */ + + else if (if_state [unit] == opcode_wait /* if waiting for an opcode */ + || if_state [unit] == parameter_wait) /* or a parameter, */ + abort_command (unit, io_program_error, idle); /* then abort the pending command */ + } + + else if (stopped_talking) { /* was the unit Untalked? */ + if (icd_cntlr [unit].state == cntlr_busy) /* if the controller is busy, */ + complete_read (unit); /* then check for read completion */ + + else if (if_command [unit] == invalid) /* if a command was aborting, */ + complete_abort (unit); /* then complete it */ + } + } /* end of bus command processing */ + + +else { /* it is bus data (ATN is denied) */ + switch (if_state [unit]) { /* dispatch the interface state */ + + case opcode_wait: /* waiting for an opcode */ + if (DEBUG_PRI (da_dev, DEB_XFER)) + sprintf (action, "opcode %02XH", data & DL_OPCODE_MASK); + + buffer [0] = SET_UPPER (data); /* set the opcode into the buffer */ + + if (dl_prepare_command (&icd_cntlr [unit], /* is the command valid? */ + da_unit, unit)) { + if_state [unit] = parameter_wait; /* set up to get the pad byte */ + icd_cntlr [unit].index = 0; /* reset the word index for the next byte */ + icd_cntlr [unit].length = /* convert the parameter count to bytes */ + icd_cntlr [unit].length * 2 + 1; /* and include the pad byte */ + } + + else { /* the disc command is invalid */ + abort_command (unit, illegal_opcode, /* abort the command */ + error_sink); /* and sink any parameter bytes */ + initiated = TRUE; /* log the abort initiation */ + } /* (the unit cannot be busy) */ + break; + + + case parameter_wait: /* waiting for a parameter */ + if (DEBUG_PRI (da_dev, DEB_XFER)) + sprintf (action, "parameter %02XH", data); + + put_buffer_byte (&icd_cntlr [unit], data); /* add the byte to the buffer */ + + if (icd_cntlr [unit].length == 0) /* is this the last parameter? */ + if (di [da].bus_cntl & BUS_EOI) /* does the host agree? */ + initiated = start_command (unit); /* start the command and log the initiation */ + + else { /* the parameter count is wrong */ + abort_command (unit, io_program_error, /* abort the command and sink */ + error_sink); /* any additional parameter bytes */ + initiated = TRUE; /* log the abort initiation */ + } + break; + + + case write_xfer: /* transferring write data */ + if (icd_cntlr [unit].length > 0) /* if there is more to transfer */ + put_buffer_byte (&icd_cntlr [unit], data); /* then add the byte to the buffer */ + + /* fall into error_sink handler */ + + case error_sink: /* sinking data after an error */ + if (DEBUG_PRI (da_dev, DEB_XFER)) + sprintf (action, "data %03o", data); + + if (di [da].bus_cntl & BUS_EOI) /* is this the last byte from the bus? */ + icd_cntlr [unit].eod = SET; /* indicate EOD to the controller */ + + di_bus_control (da, unit, BUS_NRFD, 0); /* assert NRFD to hold off the card */ + + da_unit [unit].wait = icd_cntlr [unit].data_time; /* schedule the unit */ + break; + + + default: /* data was received in the wrong state */ + abort_command (unit, io_program_error, /* report the error */ + error_sink); /* and sink any data that follows */ + + if (DEBUG_PRI (da_dev, DEB_XFER)) + sprintf (action, "unhandled data %03o", data); + break; + } + } + + +if (accepted && DEBUG_PRI (da_dev, DEB_XFER)) + fprintf (sim_deb, ">>DA xfer: HP-IB address %d accepted %s\n", + GET_BUSADR (da_unit [unit].flags), action); + +if (da_unit [unit].wait > 0) /* was service requested? */ + activate_unit (&da_unit [unit]); /* schedule the unit */ + +if (initiated && DEBUG_PRI (da_dev, DEB_RWSC)) + if (if_command [unit] == disc_command) + fprintf (sim_deb, ">>DA rwsc: Unit %d position %" T_ADDR_FMT "d %s disc command initiated\n", + unit, da_unit [unit].pos, dl_opcode_name (ICD, icd_cntlr [unit].opcode)); + else + fprintf (sim_deb, ">>DA rwsc: Unit %d %s command initiated\n", + unit, if_command_name [if_command [unit]]); + +return accepted; /* indicate the acceptance condition */ +} + + +/* Respond to the bus control lines. + + The indicated unit is notified of the new control state on the bus. There + are two conditions to which we must respond: + + 1. An Interface Clear is initiated. IFC unaddresses all units, so any + in-progress disc command must be terminated as if an Untalk and Unlisten + were accepted from the data bus. + + 2. Attention and Not Ready for Data are denied. A device addressed to talk + must wait for ATN to deny before data may be sent. Also, a listener that + has asserted NRFD must deny it before a talker may send data. If the + interface is sending data and both ATN and NRFD are denied, then we + reschedule the service routine to send the next byte. +*/ + +void da_bus_respond (CARD_ID card, uint32 unit, uint8 new_cntl) +{ +if (new_cntl & BUS_IFC) { /* is interface clear asserted? */ + di [da].listeners = 0; /* perform an Unlisten */ + di [da].talker = 0; /* and an Untalk */ + + if (icd_cntlr [unit].state == cntlr_busy) { /* is the controller busy? */ + complete_write (unit); /* check for write completion */ + complete_read (unit); /* or read completion */ + + if (da_unit [unit].wait > 0) /* is service needed? */ + activate_unit (&da_unit [unit]); /* activate the unit */ + } + + else if (if_command [unit] == invalid) /* if a command was aborting, */ + complete_abort (unit); /* then complete it */ + + else if (if_state [unit] == opcode_wait /* if we're waiting for an opcode */ + || if_state [unit] == parameter_wait) /* or a parameter, */ + abort_command (unit, io_program_error, idle); /* then abort the pending command */ + } + +if (!(new_cntl & (BUS_ATN | BUS_NRFD)) /* is the card in data mode and ready for data? */ + && (if_state [unit] == read_xfer /* is the interface waiting to send data */ + || if_state [unit] == error_source)) /* or source error bytes? */ + da_service (&da_unit [unit]); /* start or resume the transfer */ +} + + + +/* Amigo disc local utility routines */ + + +/* Start a command with parameters. + + A command that has been waiting for all of its parameters to be received is + now ready to start. If this is a disc command, call the disc library to + validate the parameters and, if they are OK, to start the command. Status + commands return the status values in the sector buffer and the number of + words that were returned in the buffer length, which we convert to a byte + count. + + If the disc command was accepted, the library returns a pointer to the unit + to be scheduled. For an ICD controller, the unit is always the one currently + addressed, so we simply test if the return is not NULL. If it isn't, then we + set the next interface state as determined by the command that is executing. + For example, a Read command sets the interface to read_wait status in order + to wait until the accompanying Send Read Data secondary is received. + + If the return is NULL, then the command was rejected, so we set DSJ = 1 and + leave the interface state in parameter_wait; the controller status will have + been set to the reason for the rejection. + + If the next interface state is command_exec, then the disc command is ready + for execution, and we return TRUE to schedule the unit service. Otherwise, + we return FALSE, and the appropriate action will be taken by the caller. + + For all other commands, execution begins as soon as the correct parameters + are received, so we set command_exec state and return TRUE. (Only Amigo + Clear and Initiate Self Test require parameters, so they will be the only + other commands that must be started here.) + + + Implementation notes: + + 1. As the ICD implementation does not need to differentiate between unit and + controller commands, the return value from the dl_start_command routine + is not used other than as an indication of success or failure. +*/ + +static t_bool start_command (uint32 unit) +{ +if (if_command [unit] == disc_command) { /* are we starting a disc command? */ + if (dl_start_command (&icd_cntlr [unit], da_unit, unit)) { /* start the command; was it successful? */ + icd_cntlr [unit].length = icd_cntlr [unit].length * 2; /* convert the return length from words to bytes */ + if_state [unit] = next_state [icd_cntlr [unit].opcode]; /* set the next interface state */ + } + + else /* the command was rejected */ + if_dsj [unit] = 1; /* so indicate an error */ + + if (if_state [unit] == command_exec) /* if the command is executing */ + return TRUE; /* activate the unit */ + + else { /* if we must wait */ + da_unit [unit].wait = 0; /* for another secondary, */ + return FALSE; /* then skip the activation */ + } + } + +else { /* all other commands */ + if_state [unit] = command_exec; /* execute as soon */ + da_unit [unit].wait = icd_cntlr [unit].cmd_time; /* as they */ + return TRUE; /* are received */ + } +} + + +/* Abort an in-process command. + + A command sequence partially received via the bus must be aborted. The cause + might be an unknown secondary, an illegal disc command opcode, an improper + secondary sequence (e.g., a Read not followed by Send Read Data), an + incorrect number of parameters, or unaddressing before the sequence was + complete. In any event, the controller and interface are set to an abort + state, and the DSJ value is set to 1 to indicate an error. +*/ + +static void abort_command (uint32 unit, CNTLR_STATUS status, IF_STATE state) +{ +if_command [unit] = invalid; /* indicate an invalid command */ +if_state [unit] = state; /* set the interface state as directed */ +if_dsj [unit] = 1; /* set DSJ to indicate an error condition */ +dl_end_command (&icd_cntlr [unit], status); /* place the disc controller into the wait state */ +return; +} + + +/* Complete an in-process read command. + + An Untalk terminates a Read, Read Full Sector, Read Without Verify, Read With + Offset, or Cold Load Read command, which must be tied off cleanly by setting + the end-of-data condition and calling the service routine. This is required + only if the read has not already aborted (e.g., for an auto-seek error). + + If a read is in progress, the controller will be busy, and the interface + state will be either command_exec (if between sectors) or read_xfer (if + within a sector). We set up the end phase for the command and schedule the + disc service to tidy up. + + If a read has aborted, the controller will be waiting, and the interface + state will be error_source. In this latter case, we no nothing, as the + controller has already set the required error status. + + We must be careful NOT to trigger on an Untalk that may follow the opcode and + precede the Send Read Data sequence. In this case, the controller will be + busy, but the interface state will be either read_wait or status_wait. + + + Implementation notes: + + 1. The test for controller busy is made before calling this routine. This + saves the call overhead for the most common case, which is the card is + being unaddressed after command completion. + + 2. There is no need to test if we are processing a disc command, as the + controller would not be busy otherwise. + + 3. If an auto-seek will be needed to continue the read, but the seek will + fail, then an extra delay is inserted before the service call to start + the next sector. Once an Untalk is received, this delay is no longer + needed, so it is cancelled before rescheduling the service routine. +*/ + +static void complete_read (uint32 unit) +{ +if ((if_state [unit] == command_exec /* is a command executing */ + || if_state [unit] == read_xfer) /* or is data transferring */ + && (dl_classify (icd_cntlr [unit]) == class_read /* and the controller is executing */ + || dl_classify (icd_cntlr [unit]) == class_status)) { /* a read or status command? */ + icd_cntlr [unit].eod = SET; /* set the end of data flag */ + + if_state [unit] = command_exec; /* set to execute */ + da_unit [unit].PHASE = end_phase; /* the completion phase */ + + sim_cancel (&da_unit [unit]); /* cancel the EOT delay */ + da_unit [unit].wait = icd_cntlr [unit].data_time; /* reschedule for completion */ + } + +return; +} + + +/* Complete an in-process write command. + + Normally, the host sends a byte tagged with EOI to end a Write, Write Full + Sector, or Initialize command. However, an Unlisten may terminate a write, + which must be tied off cleanly by setting the end-of-data condition and + calling the service routine. This is required only if the write has not + already aborted (e.g., for a write-protected disc). + + If a write is in progress, the controller will be busy, and the interface + state will be either command_exec (if between sectors) or write_xfer (if + within a sector). We set up the end phase for the command and schedule the + disc service to tidy up. + + If a write has aborted, the controller will be waiting, and the interface + state will be error_sink. In this latter case, we do nothing, as the + controller has already set the required error status. + + We must be careful NOT to trigger on the Unlisten that may follow the opcode + and precede the Receive Write Data sequence. In this case, the controller + will be busy, but the interface state will be write_wait. + + + Implementation notes: + + 1. The test for controller busy is made before calling this routine. This + saves the call overhead for the most common case, which is the card is + being unaddressed after command completion. + + 2. There is no need to test if we are processing a disc command, as the + controller would not be busy otherwise. +*/ + +static void complete_write (uint32 unit) +{ +if ((if_state [unit] == command_exec /* is a command executing */ + || if_state [unit] == write_xfer) /* or is data transferring */ + && dl_classify (icd_cntlr [unit]) == class_write) { /* and the controller is executing a write? */ + icd_cntlr [unit].eod = SET; /* set the end of data flag */ + + if_state [unit] = command_exec; /* set to execute */ + da_unit [unit].PHASE = end_phase; /* the completion phase */ + da_unit [unit].wait = icd_cntlr [unit].data_time; /* ensure that the controller will finish */ + } + +return; +} + + +/* Complete an in-process command abort. + + Errors in the command protocol begin an abort sequence that may involve + sourcing or sinking bytes to allow the sequence to complete as expected by + the CPU. Unaddressing the unit terminates the aborted command. + + If an abort is in progress, and the interface is not idle, the end-of-data + indication is set, and the disc service routine is called directly to process + the completion of the abort. The service routine will terminate the + error_source or error_sink state cleanly and then idle the interface. + + + Implementation notes: + + 1. The test for an abort-in-progress is made before calling this routine. + This saves the call overhead for the most common case, which is the card + is being unaddressed after normal command completion. +*/ + +static void complete_abort (uint32 unit) +{ +if (if_state [unit] != idle) { /* is the interface busy? */ + icd_cntlr [unit].eod = SET; /* set the end of data flag */ + da_service (&da_unit [unit]); /* and process the abort completion */ + } + +return; +} + + +/* Get a byte from the sector buffer. + + The next available byte in the sector buffer is returned to the caller. The + determination of which byte of the 16-bit buffer word to return is made by + the polarity of the buffer byte count. The count always begins with an even + number, as it is set by doubling the word count returned from the disc + library. Therefore, because we decrement the count first, the upper byte is + indicated by an odd count, and the lower byte is indicated by an even count. + The buffer index is incremented only after the lower byte is returned. +*/ + +static uint8 get_buffer_byte (CVPTR cvptr) +{ +cvptr->length = cvptr->length - 1; /* count the byte */ + +if (cvptr->length & 1) /* is the upper byte next? */ + return GET_UPPER (buffer [cvptr->index]); /* return the byte */ +else /* the lower byte is next */ + return GET_LOWER (buffer [cvptr->index++]); /* return the byte and bump the word index */ +} + + +/* Put a byte into the sector buffer. + + The supplied byte is stored in the sector buffer. The determination of which + byte of the 16-bit buffer word to store is made by the polarity of the buffer + byte count. The count always begins with an even number, as it is set by + doubling the word count returned from the disc library. Therefore, because + we decrement the count first, the upper byte is indicated by an odd count, + and the lower byte is indicated by an even count. The buffer index is + incremented only after the lower byte is stored. +*/ + +static void put_buffer_byte (CVPTR cvptr, uint8 data) +{ +cvptr->length = cvptr->length - 1; /* count the byte */ + +if (cvptr->length & 1) /* is the upper byte next? */ + buffer [cvptr->index] = SET_UPPER (data); /* save the byte */ +else /* the lower byte is next */ + buffer [cvptr->index++] |= SET_LOWER (data); /* merge the byte and bump the word index */ +return; +} + + +/* Activate the unit. + + The specified unit is activated using the unit's "wait" time. If debugging + is enabled, the activation is logged to the debug file. +*/ + +static t_stat activate_unit (UNIT *uptr) +{ +int32 unit; +t_stat result; + +if (DEBUG_PRI (da_dev, DEB_SERV)) { + unit = uptr - da_unit; + + fprintf (sim_deb, ">>DA serv: Unit %d state %s delay %d service scheduled\n", + unit, if_state_name [if_state [unit]], uptr->wait); + } + +result = sim_activate (uptr, uptr->wait); /* activate the unit */ +uptr->wait = 0; /* reset the activation time */ + +return result; /* return the activation status */ +} diff --git a/HP2100/hp2100_diag.txt b/HP2100/hp2100_diag.txt index c9382484..012a1304 100644 --- a/HP2100/hp2100_diag.txt +++ b/HP2100/hp2100_diag.txt @@ -1,6 +1,6 @@ SIMH/HP 21XX DIAGNOSTICS PERFORMANCE ==================================== - Last update: 2012-03-30 + Last update: 2014-12-18 The HP 24396 diagnostic suite has been run against the SIMH HP 21xx simulation. @@ -2481,7 +2481,7 @@ CONFIGURATION: sim> detach MSC0 HALT instruction 102074 - sim> deposit S 000217 + sim> deposit S 000017 sim> reset sim> go @@ -2605,10 +2605,9 @@ TEST REPORT: 7970-13181 DIAG. TEST RESULT: Partially passed. -TEST NOTES: Test 23 verifies the LRCC and CRCC values obtained from the - interface. These features are not simulated. (Setting bit 7 of - the S register during configuration eliminates most LRCC/CRCC - checks but does not inhibit test 23.) +TEST NOTES: Test 23 performs a reverse record read to verify the CRCC and + LRCC values obtained from the record. This feature is not + simulated. If test 34 is selected manually, E065 WRITE ERROR will occur. This is due to the implementation of the tape simulation diff --git a/HP2100/hp2100_dp.c b/HP2100/hp2100_dp.c index c26d16e6..fcd0723c 100644 --- a/HP2100/hp2100_dp.c +++ b/HP2100/hp2100_dp.c @@ -1,1183 +1,1198 @@ -/* hp2100_dp.c: HP 2100 12557A/13210A disk simulator - - Copyright (c) 1993-2012, Robert M. Supnik - - 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 - ROBERT M SUPNIK 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 Robert M Supnik shall not be - used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from Robert M Supnik. - - DP 12557A 2871 disk subsystem - 13210A 7900 disk subsystem - - 10-Feb-12 JDB Deprecated DEVNO in favor of SC - Added CNTLR_TYPE cast to dp_settype - 28-Mar-11 JDB Tidied up signal handling - 26-Oct-10 JDB Changed I/O signal handler for revised signal model - 10-Aug-08 JDB Added REG_FIT to register variables < 32-bit size - 26-Jun-08 JDB Rewrote device I/O to model backplane signals - 28-Dec-06 JDB Added ioCRS state to I/O decoders - 01-Mar-05 JDB Added SET UNLOAD/LOAD - 07-Oct-04 JDB Fixed enable/disable from either device - Fixed ANY ERROR status for 12557A interface - Fixed unattached drive status for 12557A interface - Status cmd without prior STC DC now completes (12557A) - OTA/OTB CC on 13210A interface also does CLC CC - Fixed RAR model - Fixed seek check on 13210 if sector out of range - 20-Aug-04 JDB Fixes from Dave Bryan - - Check status on unattached drive set busy and not ready - - Check status tests wrong unit for write protect status - - Drive on line sets ATN, will set FLG if polling - 15-Aug-04 RMS Controller resumes polling for ATN interrupts after - read status (found by Dave Bryan) - 22-Jul-04 RMS Controller sets ATN for all commands except - read status (found by Dave Bryan) - 21-Apr-04 RMS Fixed typo in boot loader (found by Dave Bryan) - 26-Apr-04 RMS Fixed SFS x,C and SFC x,C - Fixed SR setting in IBL - Fixed interpretation of SR<0> - Revised IBL loader - Implemented DMA SRQ (follows FLG) - 25-Apr-03 RMS Revised for extended file support - Fixed bug(s) in boot (found by Terry Newton) - 10-Nov-02 RMS Added BOOT command, fixed numerous bugs - 15-Jan-02 RMS Fixed INIT handling (found by Bill McDermith) - 10-Jan-02 RMS Fixed f(x)write call (found by Bill McDermith) - 03-Dec-01 RMS Changed DEVNO to use extended SET/SHOW - 24-Nov-01 RMS Changed STA to be an array - 07-Sep-01 RMS Moved function prototypes - 29-Nov-00 RMS Made variable names unique - 21-Nov-00 RMS Fixed flag, buffer power up state - - References: - - 7900A Disc Drive Operating and Service Manual (07900-90002, Feb-1975) - - 13210A Disc Drive Interface Kit Operating and Service Manual - (13210-90003, Nov-1974) - - 12557A Cartridge Disc Interface Kit Operating and Service Manual - (12557-90001, Sep-1970) - - - The simulator uses a number of state variables: - - dpc_busy set to drive number + 1 when the controller is busy - of the unit in use - dpd_xfer set to 1 if the data channel is executing a data transfer - dpd_wval set to 1 by OTx if either !dpc_busy or dpd_xfer - dpc_poll set to 1 if attention polling is enabled - - dpc_busy and dpd_xfer are set together at the start of a read, write, refine, - or init. When data transfers are complete (CLC DC), dpd_xfer is cleared, but the - operation is not necessarily over. When the operation is complete, dpc_busy - is cleared and the command channel flag is set. - - dpc_busy && !dpd_xfer && STC DC (controller is busy, data channel transfer has - been terminated by CLC DC, but a word has been placed in the data channel buffer) - indicates data overrun. - - dpd_wval is used in write operations to fill out the sector buffer with 0's - if only a partial sector has been transferred. - - dpc_poll indicates whether seek completion polling can occur. It is cleared - by reset and CLC CC and set by issuance of a seek or completion of check status. - - The controller's "Record Address Register" (RAR) contains the CHS address of - the last Seek or Address Record command executed. The RAR is shared among - all drives on the controller. In addition, each drive has an internal - position register that contains the last cylinder position transferred to the - drive during Seek command execution (data operations always start with the - RAR head and sector position). - - In a real drive, the address field of the sector under the head is read and - compared to the RAR. When they match, the target sector is under the head - and is ready for reading or writing. If a match doesn't occur, an Address - Error is indicated. In the simulator, the address field is obtained from the - drive's current position register during a read, i.e., the "on-disc" address - field is assumed to match the current position. - - The following implemented behaviors have been inferred from secondary sources - (diagnostics, operating system drivers, etc.), due to absent or contradictory - authoritative information; future correction may be needed: - - 1. Status bit 15 (ATTENTION) does not set bit 0 (ANY ERROR) on the 12557A. - 2. Omitting STC DC before Status Check does not set DC flag but does poll. -*/ - -#include "hp2100_defs.h" - -#define UNIT_V_WLK (UNIT_V_UF + 0) /* write locked */ -#define UNIT_V_UNLOAD (UNIT_V_UF + 1) /* heads unloaded */ -#define UNIT_WLK (1 << UNIT_V_WLK) -#define UNIT_UNLOAD (1 << UNIT_V_UNLOAD) -#define FNC u3 /* saved function */ -#define DRV u4 /* drive number (DC) */ -#define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write prot */ - -#define DP_N_NUMWD 7 -#define DP_NUMWD (1 << DP_N_NUMWD) /* words/sector */ -#define DP_NUMSC2 12 /* sectors/srf 12557 */ -#define DP_NUMSC3 24 /* sectors/srf 13210 */ -#define DP_NUMSC (dp_ctype ? DP_NUMSC3 : DP_NUMSC2) -#define DP_NUMSF 4 /* surfaces/cylinder */ -#define DP_NUMCY 203 /* cylinders/disk */ -#define DP_SIZE2 (DP_NUMSF * DP_NUMCY * DP_NUMSC2 * DP_NUMWD) -#define DP_SIZE3 (DP_NUMSF * DP_NUMCY * DP_NUMSC3 * DP_NUMWD) -#define DP_NUMDRV 4 /* # drives */ - -/* Command word */ - -#define CW_V_FNC 12 /* function */ -#define CW_M_FNC 017 -#define CW_GETFNC(x) (((x) >> CW_V_FNC) & CW_M_FNC) -#define FNC_STA 000 /* status check */ -#define FNC_WD 001 /* write */ -#define FNC_RD 002 /* read */ -#define FNC_SEEK 003 /* seek */ -#define FNC_REF 005 /* refine */ -#define FNC_CHK 006 /* check */ -#define FNC_INIT 011 /* init */ -#define FNC_AR 013 /* address */ -#define FNC_SEEK1 020 /* fake - seek1 */ -#define FNC_SEEK2 021 /* fake - seek2 */ -#define FNC_SEEK3 022 /* fake - seek3 */ -#define FNC_CHK1 023 /* fake - check1 */ -#define FNC_AR1 024 /* fake - arec1 */ -#define CW_V_DRV 0 /* drive */ -#define CW_M_DRV 03 -#define CW_GETDRV(x) (((x) >> CW_V_DRV) & CW_M_DRV) - -/* Disk address words */ - -#define DA_V_CYL 0 /* cylinder */ -#define DA_M_CYL 0377 -#define DA_GETCYL(x) (((x) >> DA_V_CYL) & DA_M_CYL) -#define DA_V_HD 8 /* head */ -#define DA_M_HD 03 -#define DA_GETHD(x) (((x) >> DA_V_HD) & DA_M_HD) -#define DA_V_SC 0 /* sector */ -#define DA_M_SC2 017 -#define DA_M_SC3 037 -#define DA_M_SC (dp_ctype ? DA_M_SC3 : DA_M_SC2) -#define DA_GETSC(x) (((x) >> DA_V_SC) & DA_M_SC) -#define DA_CKMASK2 037 /* check mask */ -#define DA_CKMASK3 077 -#define DA_CKMASK (dp_ctype ? DA_CKMASK3 : DA_CKMASK2) - -/* Status in dpc_sta[drv], (u) = unused in 13210, (d) = dynamic */ - -#define STA_ATN 0100000 /* attention (u) */ -#define STA_1ST 0040000 /* first status */ -#define STA_OVR 0020000 /* overrun */ -#define STA_RWU 0010000 /* rw unsafe NI (u) */ -#define STA_ACU 0004000 /* access unsafe NI */ -#define STA_HUNT 0002000 /* hunting NI (12557) */ -#define STA_PROT 0002000 /* protected (13210) */ -#define STA_SKI 0001000 /* incomplete NI (u) */ -#define STA_SKE 0000400 /* seek error */ -/* 0000200 /* unused */ -#define STA_NRDY 0000100 /* not ready (d) */ -#define STA_EOC 0000040 /* end of cylinder */ -#define STA_AER 0000020 /* addr error */ -#define STA_FLG 0000010 /* flagged */ -#define STA_BSY 0000004 /* seeking */ -#define STA_DTE 0000002 /* data error */ -#define STA_ERR 0000001 /* any error (d) */ - -#define STA_ERSET2 (STA_1ST | STA_OVR | STA_RWU | STA_ACU | \ - STA_SKI | STA_SKE | STA_NRDY | \ - STA_EOC | STA_AER | STA_DTE) /* 12557A error set */ -#define STA_ERSET3 (STA_ATN | STA_1ST | STA_OVR | STA_RWU | STA_ACU | \ - STA_SKI | STA_SKE | STA_NRDY | STA_EOC | STA_AER | \ - STA_FLG | STA_BSY | STA_DTE) /* 13210A error set */ -#define STA_ANYERR (dp_ctype ? STA_ERSET3 : STA_ERSET2) - -#define STA_UNLOADED (dp_ctype ? (STA_NRDY | STA_BSY) : STA_NRDY) -#define STA_MBZ13 (STA_ATN | STA_RWU | STA_SKI) /* zero in 13210 */ - -struct { - FLIP_FLOP command; /* cch command flip-flop */ - FLIP_FLOP control; /* cch control flip-flop */ - FLIP_FLOP flag; /* cch flag flip-flop */ - FLIP_FLOP flagbuf; /* cch flag buffer flip-flop */ - } dpc = { CLEAR, CLEAR, CLEAR, CLEAR }; - -/* Controller types */ - -typedef enum { - A12557, - A13210 - } CNTLR_TYPE; - -CNTLR_TYPE dp_ctype = A13210; /* ctrl type */ -int32 dpc_busy = 0; /* cch unit */ -int32 dpc_poll = 0; /* cch poll enable */ -int32 dpc_cnt = 0; /* check count */ -int32 dpc_eoc = 0; /* end of cyl */ -int32 dpc_stime = 100; /* seek time */ -int32 dpc_ctime = 100; /* command time */ -int32 dpc_xtime = 5; /* xfer time */ -int32 dpc_dtime = 2; /* dch time */ -int32 dpd_obuf = 0, dpd_ibuf = 0; /* dch buffers */ -int32 dpc_obuf = 0; /* cch buffers */ - -struct { - FLIP_FLOP command; /* dch command flip-flop */ - FLIP_FLOP control; /* dch control flip-flop */ - FLIP_FLOP flag; /* dch flag flip-flop */ - FLIP_FLOP flagbuf; /* dch flag buffer flip-flop */ - } dpd = { CLEAR, CLEAR, CLEAR, CLEAR }; - -int32 dpd_xfer = 0; /* xfer in prog */ -int32 dpd_wval = 0; /* write data valid */ -int32 dp_ptr = 0; /* buffer ptr */ -uint8 dpc_rarc = 0; /* RAR cylinder */ -uint8 dpc_rarh = 0; /* RAR head */ -uint8 dpc_rars = 0; /* RAR sector */ -uint8 dpc_ucyl[DP_NUMDRV] = { 0 }; /* unit cylinder */ -uint16 dpc_sta[DP_NUMDRV] = { 0 }; /* status regs */ -uint16 dpxb[DP_NUMWD]; /* sector buffer */ - -DEVICE dpd_dev, dpc_dev; - -IOHANDLER dpdio; -IOHANDLER dpcio; - -t_stat dpc_svc (UNIT *uptr); -t_stat dpd_svc (UNIT *uptr); -t_stat dpc_reset (DEVICE *dptr); -t_stat dpc_attach (UNIT *uptr, char *cptr); -t_stat dpc_detach (UNIT* uptr); -t_stat dpc_boot (int32 unitno, DEVICE *dptr); -void dp_god (int32 fnc, int32 drv, int32 time); -void dp_goc (int32 fnc, int32 drv, int32 time); -t_stat dpc_load_unload (UNIT *uptr, int32 value, char *cptr, void *desc); -t_stat dp_settype (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat dp_showtype (FILE *st, UNIT *uptr, int32 val, void *desc); - -/* DPD data structures - - dpd_dev DPD device descriptor - dpd_unit DPD unit list - dpd_reg DPD register list -*/ - -DIB dp_dib[] = { - { &dpdio, DPD }, - { &dpcio, DPC } - }; - -#define dpd_dib dp_dib[0] -#define dpc_dib dp_dib[1] - -UNIT dpd_unit = { UDATA (&dpd_svc, 0, 0) }; - -REG dpd_reg[] = { - { ORDATA (IBUF, dpd_ibuf, 16) }, - { ORDATA (OBUF, dpd_obuf, 16) }, - { BRDATA (DBUF, dpxb, 8, 16, DP_NUMWD) }, - { DRDATA (BPTR, dp_ptr, DP_N_NUMWD) }, - { FLDATA (CMD, dpd.command, 0) }, - { FLDATA (CTL, dpd.control, 0) }, - { FLDATA (FLG, dpd.flag, 0) }, - { FLDATA (FBF, dpd.flagbuf, 0) }, - { FLDATA (XFER, dpd_xfer, 0) }, - { FLDATA (WVAL, dpd_wval, 0) }, - { ORDATA (SC, dpd_dib.select_code, 6), REG_HRO }, - { ORDATA (DEVNO, dpd_dib.select_code, 6), REG_HRO }, - { NULL } - }; - -MTAB dpd_mod[] = { - { MTAB_XTD | MTAB_VDV, 1, "SC", "SC", &hp_setsc, &hp_showsc, &dpd_dev }, - { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &dpd_dev }, - { 0 } - }; - -DEVICE dpd_dev = { - "DPD", &dpd_unit, dpd_reg, dpd_mod, - 1, 10, DP_N_NUMWD, 1, 8, 16, - NULL, NULL, &dpc_reset, - NULL, NULL, NULL, - &dpd_dib, DEV_DISABLE - }; - -/* DPC data structures - - dpc_dev DPC device descriptor - dpc_unit DPC unit list - dpc_reg DPC register list - dpc_mod DPC modifier list -*/ - -UNIT dpc_unit[] = { - { UDATA (&dpc_svc, UNIT_FIX | UNIT_ATTABLE | UNIT_ROABLE | - UNIT_DISABLE | UNIT_UNLOAD, DP_SIZE3) }, - { UDATA (&dpc_svc, UNIT_FIX | UNIT_ATTABLE | UNIT_ROABLE | - UNIT_DISABLE | UNIT_UNLOAD, DP_SIZE3) }, - { UDATA (&dpc_svc, UNIT_FIX | UNIT_ATTABLE | UNIT_ROABLE | - UNIT_DISABLE | UNIT_UNLOAD, DP_SIZE3) }, - { UDATA (&dpc_svc, UNIT_FIX | UNIT_ATTABLE | UNIT_ROABLE | - UNIT_DISABLE | UNIT_UNLOAD, DP_SIZE3) } - }; - -REG dpc_reg[] = { - { ORDATA (OBUF, dpc_obuf, 16) }, - { ORDATA (BUSY, dpc_busy, 4), REG_RO }, - { ORDATA (CNT, dpc_cnt, 5) }, - { FLDATA (CMD, dpc.command, 0) }, - { FLDATA (CTL, dpc.control, 0) }, - { FLDATA (FLG, dpc.flag, 0) }, - { FLDATA (FBF, dpc.flagbuf, 0) }, - { FLDATA (EOC, dpc_eoc, 0) }, - { FLDATA (POLL, dpc_poll, 0) }, - { DRDATA (RARC, dpc_rarc, 8), PV_RZRO | REG_FIT }, - { DRDATA (RARH, dpc_rarh, 2), PV_RZRO | REG_FIT }, - { DRDATA (RARS, dpc_rars, 5), PV_RZRO | REG_FIT }, - { BRDATA (CYL, dpc_ucyl, 10, 8, DP_NUMDRV), PV_RZRO }, - { BRDATA (STA, dpc_sta, 8, 16, DP_NUMDRV) }, - { DRDATA (CTIME, dpc_ctime, 24), PV_LEFT }, - { DRDATA (DTIME, dpc_dtime, 24), PV_LEFT }, - { DRDATA (STIME, dpc_stime, 24), PV_LEFT }, - { DRDATA (XTIME, dpc_xtime, 24), REG_NZ | PV_LEFT }, - { FLDATA (CTYPE, dp_ctype, 0), REG_HRO }, - { URDATA (UFNC, dpc_unit[0].FNC, 8, 8, 0, - DP_NUMDRV, REG_HRO) }, - { URDATA (CAPAC, dpc_unit[0].capac, 10, T_ADDR_W, 0, - DP_NUMDRV, PV_LEFT | REG_HRO) }, - { ORDATA (SC, dpc_dib.select_code, 6), REG_HRO }, - { ORDATA (DEVNO, dpc_dib.select_code, 6), REG_HRO }, - { NULL } - }; - -MTAB dpc_mod[] = { - { UNIT_UNLOAD, UNIT_UNLOAD, "heads unloaded", "UNLOADED", dpc_load_unload }, - { UNIT_UNLOAD, 0, "heads loaded", "LOADED", dpc_load_unload }, - { UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL }, - { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL }, - { MTAB_XTD | MTAB_VDV, 1, NULL, "13210A", - &dp_settype, NULL, NULL }, - { MTAB_XTD | MTAB_VDV, 0, NULL, "12557A", - &dp_settype, NULL, NULL }, - { MTAB_XTD | MTAB_VDV, 0, "TYPE", NULL, - NULL, &dp_showtype, NULL }, - { MTAB_XTD | MTAB_VDV, 1, "SC", "SC", &hp_setsc, &hp_showsc, &dpd_dev }, - { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &dpd_dev }, - { 0 } - }; - -DEVICE dpc_dev = { - "DPC", dpc_unit, dpc_reg, dpc_mod, - DP_NUMDRV, 8, 24, 1, 8, 16, - NULL, NULL, &dpc_reset, - &dpc_boot, &dpc_attach, &dpc_detach, - &dpc_dib, DEV_DISABLE - }; - - -/* Data channel I/O signal handler. - - For the 12557A, the card contains the usual control, flag, and flag buffer - flip-flops. PRL, IRQ, and SRQ are standard. A command flip-flop indicates - that data is available. - - For the 13210A, the card has a flag and a flag buffer flip-flop, but no - control or interrupt flip-flop. SRQ is standard. IRQ and PRL are not - driven, and the card does not respond to IAK. STC sets the command flip-flop - to initiate a data transfer. CLC has no effect. - - Implementation notes: - - 1. The CRS signal clears the drive attention register. Under simulation, - drive attention status is generated dynamically, so there is no attention - register. -*/ - -uint32 dpdio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) -{ -IOSIGNAL signal; -IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ - -while (working_set) { - signal = IONEXT (working_set); /* isolate next signal */ - - switch (signal) { /* dispatch I/O signal */ - - case ioCLF: /* clear flag flip-flop */ - dpd.flag = dpd.flagbuf = CLEAR; - break; - - - case ioSTF: /* set flag flip-flop */ - case ioENF: /* enable flag */ - dpd.flag = dpd.flagbuf = SET; - break; - - - case ioSFC: /* skip if flag is clear */ - setstdSKF (dpd); - break; - - - case ioSFS: /* skip if flag is set */ - setstdSKF (dpd); - break; - - - case ioIOI: /* I/O data input */ - stat_data = IORETURN (SCPE_OK, dpd_ibuf); /* merge in return status */ - break; - - - case ioIOO: /* I/O data output */ - dpd_obuf = IODATA (stat_data); /* clear supplied status */ - - if (!dpc_busy || dpd_xfer) /* if !overrun */ - dpd_wval = 1; /* valid */ - break; - - - case ioPOPIO: /* power-on preset to I/O */ - dpd.flag = dpd.flagbuf = SET; /* set flag buffer and flag */ - - if (dp_ctype == A12557) /* 12557? */ - dpd_obuf = 0; /* clear output buffer */ - break; - - - case ioCRS: /* control reset */ - dpd.command = CLEAR; /* clear command */ - - if (dp_ctype == A12557) /* 12557? */ - dpd.control = CLEAR; /* clear control */ - - else { /* 13210 */ - dpc_rarc = 0; /* clear controller cylinder address */ - dpc_ucyl [CW_GETDRV (dpc_obuf)] = 0; /* clear last drive addressed cylinder */ - } - break; - - - case ioCLC: /* clear control flip-flop */ - if (dp_ctype == A12557) /* 12557? */ - dpd.control = CLEAR; /* clear control */ - - dpd_xfer = 0; /* clr xfer in progress */ - break; - - - case ioSTC: /* set control flip-flop */ - if (dp_ctype == A12557) /* 12557? */ - dpd.control = SET; /* set control */ - - dpd.command = SET; /* set cmd */ - - if (dpc_busy && !dpd_xfer) /* overrun? */ - dpc_sta[dpc_busy - 1] |= STA_OVR; - break; - - - case ioSIR: /* set interrupt request */ - if (dp_ctype == A12557) { /* 12557? */ - setstdPRL (dpd); /* set standard PRL signal */ - setstdIRQ (dpd); /* set standard IRQ signal */ - } - - setstdSRQ (dpd); /* set standard SRQ signal */ - break; - - - case ioIAK: /* interrupt acknowledge */ - if (dp_ctype == A12557) /* 12557? */ - dpd.flagbuf = CLEAR; /* clear flag buffer */ - break; - - - default: /* all other signals */ - break; /* are ignored */ - } - - working_set = working_set & ~signal; /* remove current signal from set */ - } - -return stat_data; -} - - -/* Command channel I/O signal handler. - - The 12557A and 13210A have the usual control, flag, and flag buffer - flip-flops. Only the 12557A has a command flip-flop. IRQ, PRL, and SRQ are - standard. - - Implementation notes: - - 1. In hardware, the command channel card passes PRH to PRL. The data card - actually drives PRL with the command channel's control and flag states, - even though the command channel's control, flag, and flag buffer drive - IRQH. That is, the priority chain is broken at the data card, although - the command card is interrupting. This works in hardware, but we must - break PRL at the command card under simulation to allow the command card - to interrupt. -*/ - -uint32 dpcio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) -{ -uint16 data; -int32 i, fnc, drv; -IOSIGNAL signal; -IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ - -while (working_set) { - signal = IONEXT (working_set); /* isolate next signal */ - - switch (signal) { /* dispatch I/O signal */ - - case ioCLF: /* clear flag flip-flop */ - dpc.flag = dpc.flagbuf = CLEAR; - break; - - - case ioSTF: /* set flag flip-flop */ - case ioENF: /* enable flag */ - dpc.flag = dpc.flagbuf = SET; - break; - - - case ioSFC: /* skip if flag is clear */ - setstdSKF (dpc); - break; - - - case ioSFS: /* skip if flag is set */ - setstdSKF (dpc); - break; - - - case ioIOI: /* I/O data input */ - data = 0; - - for (i = 0; i < DP_NUMDRV; i++) /* form attention register value */ - if (dpc_sta[i] & STA_ATN) data = data | (1 << i); - - stat_data = IORETURN (SCPE_OK, data); /* merge in return status */ - break; - - - case ioIOO: /* I/O data output */ - dpc_obuf = IODATA (stat_data); /* clear supplied status */ - - if (dp_ctype == A13210) /* 13210? */ - dpcio (dibptr, ioCLC, 0); /* OTx causes CLC */ - break; - - - case ioPOPIO: /* power-on preset to I/O */ - dpc.flag = dpc.flagbuf = SET; /* set flag buffer and flag */ - - if (dp_ctype == A12557) /* 12557? */ - dpd_obuf = 0; /* clear output buffer */ - break; - - - case ioCRS: /* control reset */ - dpc.control = CLEAR; /* clear control */ - - if (dp_ctype == A12557) /* 12557? */ - dpc.command = CLEAR; /* clear command */ - break; - - - case ioCLC: /* clear control flip-flop */ - dpc.control = CLEAR; /* clr ctl */ - - if (dp_ctype == A12557) /* 12557? */ - dpc.command = CLEAR; /* cancel non-seek */ - - if (dpc_busy) - sim_cancel (&dpc_unit[dpc_busy - 1]); - - sim_cancel (&dpd_unit); /* cancel dch */ - dpd_xfer = 0; /* clr dch xfer */ - dpc_busy = 0; /* clr cch busy */ - dpc_poll = 0; /* clr cch poll */ - break; - - - case ioSTC: /* set control flip-flop */ - dpc.control = SET; /* set ctl */ - - if ((dp_ctype == A13210) || !dpc.command) { /* 13210 or command is clear? */ - if (dp_ctype == A12557) /* 12557? */ - dpc.command = SET; /* set command */ - - drv = CW_GETDRV (dpc_obuf); /* get fnc, drv */ - fnc = CW_GETFNC (dpc_obuf); /* from cmd word */ - - switch (fnc) { /* case on fnc */ - - case FNC_SEEK: /* seek */ - dpc_poll = 1; /* enable polling */ - dp_god (fnc, drv, dpc_dtime); /* sched dch xfr */ - break; - - case FNC_STA: /* rd sta */ - if (dp_ctype == A13210) /* 13210? clr dch flag */ - dpdio (&dpd_dib, ioCLF, 0); - - case FNC_CHK: /* check */ - case FNC_AR: /* addr rec */ - dp_god (fnc, drv, dpc_dtime); /* sched dch xfr */ - break; - - case FNC_RD: case FNC_WD: /* read, write */ - case FNC_REF: case FNC_INIT: /* refine, init */ - dp_goc (fnc, drv, dpc_ctime); /* sched drive */ - break; - } /* end case */ - } /* end if */ - break; - - - case ioSIR: /* set interrupt request */ - setstdPRL (dpc); /* set standard PRL signal */ - setstdIRQ (dpc); /* set standard IRQ signal */ - setstdSRQ (dpc); /* set standard SRQ signal */ - break; - - - case ioIAK: /* interrupt acknowledge */ - dpc.flagbuf = CLEAR; /* clear flag buffer */ - break; - - - default: /* all other signals */ - break; /* are ignored */ - } - - working_set = working_set & ~signal; /* remove current signal from set */ - } - -return stat_data; -} - - -/* Start data channel operation */ - -void dp_god (int32 fnc, int32 drv, int32 time) -{ -dpd_unit.DRV = drv; /* save unit */ -dpd_unit.FNC = fnc; /* save function */ -sim_activate (&dpd_unit, time); -return; -} - - -/* Start controller operation */ - -void dp_goc (int32 fnc, int32 drv, int32 time) -{ -int32 t; - -if (t = sim_is_active (&dpc_unit[drv])) { /* still seeking? */ - sim_cancel (&dpc_unit[drv]); /* stop seek */ - dpc_sta[drv] = dpc_sta[drv] & ~STA_BSY; /* clear busy */ - time = time + t; /* include seek time */ - } -dp_ptr = 0; /* init buf ptr */ -dpc_eoc = 0; /* clear end cyl */ -dpc_busy = drv + 1; /* set busy */ -dpd_xfer = 1; /* xfer in prog */ -dpc_unit[drv].FNC = fnc; /* save function */ -dpc_sta[drv] = dpc_sta[drv] & ~STA_ATN; /* clear ATN */ -sim_activate (&dpc_unit[drv], time); /* activate unit */ -return; -} - - -/* Data channel unit service - - This routine handles the data channel transfers. It also handles - data transfers that are blocked by seek in progress. - - uptr->DRV = target drive - uptr->FNC = target function - - Seek substates - seek - transfer cylinder - seek1 - transfer head/surface - Address record - ar - transfer cylinder - ar1 - transfer head/surface, finish operation - Status check - transfer status, finish operation - Check data - chk - transfer sector count -*/ - -t_stat dpd_svc (UNIT *uptr) -{ -int32 i, drv, st; - -drv = uptr->DRV; /* get drive no */ -switch (uptr->FNC) { /* case function */ - - case FNC_AR: /* arec, need cyl */ - case FNC_SEEK: /* seek, need cyl */ - if (dpd.command) { /* dch active? */ - dpc_rarc = DA_GETCYL (dpd_obuf); /* set RAR from cyl word */ - dpd_wval = 0; /* clr data valid */ - - dpd.command = CLEAR; /* clr dch cmd */ - dpdio (&dpd_dib, ioENF, 0); /* set dch flg */ - - if (uptr->FNC == FNC_AR) uptr->FNC = FNC_AR1; - else uptr->FNC = FNC_SEEK1; /* advance state */ - } - sim_activate (uptr, dpc_xtime); /* no, wait more */ - break; - - case FNC_AR1: /* arec, need hd/sec */ - case FNC_SEEK1: /* seek, need hd/sec */ - if (dpd.command) { /* dch active? */ - dpc_rarh = DA_GETHD (dpd_obuf); /* set RAR from head */ - dpc_rars = DA_GETSC (dpd_obuf); /* set RAR from sector */ - dpd_wval = 0; /* clr data valid */ - - dpd.command = CLEAR; /* clr dch cmd */ - dpdio (&dpd_dib, ioENF, 0); /* set dch flg */ - - if (uptr->FNC == FNC_AR1) { - dpc.command = CLEAR; /* clr cch cmd */ - dpcio (&dpc_dib, ioENF, 0); /* set cch flg */ - - dpc_sta[drv] = dpc_sta[drv] | STA_ATN; /* set drv attn */ - break; /* done if Address Record */ - } - if (sim_is_active (&dpc_unit[drv])) { /* if busy, */ - dpc_sta[drv] = dpc_sta[drv] | STA_SKE; /* seek check */ - break; /* allow prev seek to cmpl */ - } - if ((dpc_rarc >= DP_NUMCY) || /* invalid cyl? */ - ((dp_ctype == A13210) && /* or 13210A */ - (dpc_rars >= DP_NUMSC3))) { /* and invalid sector? */ - dpc_sta[drv] = dpc_sta[drv] | STA_SKE; /* seek check */ - sim_activate (&dpc_unit[drv], 1); /* schedule drive no-wait */ - dpc_unit[drv].FNC = FNC_SEEK3; /* do immed compl w/poll */ - break; - } - st = abs (dpc_rarc - dpc_ucyl[drv]) * dpc_stime; - if (st == 0) st = dpc_stime; /* min time */ - dpc_ucyl[drv] = dpc_rarc; /* transfer RAR */ - sim_activate (&dpc_unit[drv], st); /* schedule drive */ - dpc_sta[drv] = (dpc_sta[drv] | STA_BSY) & - ~(STA_SKE | STA_SKI | STA_HUNT); - dpc_unit[drv].FNC = FNC_SEEK2; /* set operation */ - } - else sim_activate (uptr, dpc_xtime); /* no, wait more */ - break; - - case FNC_STA: /* read status */ - if (dpd.command || (dp_ctype == A13210)) { /* dch act or 13210? */ - if ((dpc_unit[drv].flags & UNIT_UNLOAD) == 0) { /* drive up? */ - dpd_ibuf = dpc_sta[drv] & ~STA_ERR; /* clear err */ - if (dp_ctype == A13210) dpd_ibuf = /* 13210? */ - (dpd_ibuf & ~(STA_MBZ13 | STA_PROT)) | - (dpc_unit[drv].flags & UNIT_WPRT? STA_PROT: 0); - } - else dpd_ibuf = STA_UNLOADED; /* not ready */ - if (dpd_ibuf & STA_ANYERR) /* errors? set flg */ - dpd_ibuf = dpd_ibuf | STA_ERR; - - dpc.command = CLEAR; /* clr cch cmd */ - dpd.command = CLEAR; /* clr dch cmd */ - dpdio (&dpd_dib, ioENF, 0); /* set dch flg */ - } - - dpc_sta[drv] = dpc_sta[drv] & /* clr sta flags */ - ~(STA_ATN | STA_1ST | STA_OVR | - STA_RWU | STA_ACU | STA_EOC | - STA_AER | STA_FLG | STA_DTE); - dpc_poll = 1; /* enable polling */ - for (i = 0; i < DP_NUMDRV; i++) { /* loop thru drives */ - if (dpc_sta[i] & STA_ATN) { /* any ATN set? */ - dpcio (&dpc_dib, ioENF, 0); /* set cch flg */ - break; - } - } - break; - - case FNC_CHK: /* check, need cnt */ - if (dpd.command) { /* dch active? */ - dpc_cnt = dpd_obuf & DA_CKMASK; /* get count */ - dpd_wval = 0; /* clr data valid */ - dp_goc (FNC_CHK1, drv, dpc_xtime); /* sched drv */ - } - else sim_activate (uptr, dpc_xtime); /* wait more */ - break; - - default: - return SCPE_IERR; - } - -return SCPE_OK; -} - - -/* Drive unit service - - This routine handles the data transfers. - - Seek substates - seek2 - done - Refine sector - erase sector, finish operation - Check data - chk1 - finish operation - Read - Write -*/ - -#define GETDA(x,y,z) \ - (((((x) * DP_NUMSF) + (y)) * DP_NUMSC) + (z)) * DP_NUMWD - -t_stat dpc_svc (UNIT *uptr) -{ -int32 da, drv, err; - -err = 0; /* assume no err */ -drv = uptr - dpc_unit; /* get drive no */ -if (uptr->flags & UNIT_UNLOAD) { /* drive down? */ - - dpc.command = CLEAR; /* clr cch cmd */ - dpcio (&dpc_dib, ioENF, 0); /* set cch flg */ - - dpc_sta[drv] = 0; /* clr status */ - dpc_busy = 0; /* ctlr is free */ - dpc_poll = 0; /* polling disabled */ - dpd_xfer = 0; - dpd_wval = 0; - return SCPE_OK; - } -switch (uptr->FNC) { /* case function */ - - case FNC_SEEK2: /* positioning done */ - dpc_sta[drv] = (dpc_sta[drv] | STA_ATN) & ~STA_BSY; /* fall into cmpl */ - case FNC_SEEK3: /* seek complete */ - if (dpc_poll) { /* polling enabled? */ - dpc.command = CLEAR; /* clr cch cmd */ - dpcio (&dpc_dib, ioENF, 0); /* set cch flg */ - } - return SCPE_OK; - - case FNC_REF: /* refine sector */ - break; /* just a NOP */ - - case FNC_RD: /* read */ - case FNC_CHK1: /* check */ - if (dp_ptr == 0) { /* new sector? */ - if (!dpd.command && (uptr->FNC != FNC_CHK1)) break; - if (dpc_rarc != dpc_ucyl[drv]) /* RAR cyl miscompare? */ - dpc_sta[drv] = dpc_sta[drv] | STA_AER; /* set flag, read */ - if (dpc_rars >= DP_NUMSC) { /* bad sector? */ - dpc_sta[drv] = dpc_sta[drv] | STA_AER; /* set flag, stop */ - break; - } - if (dpc_eoc) { /* end of cyl? */ - dpc_sta[drv] = dpc_sta[drv] | STA_EOC; - break; - } - da = GETDA (dpc_rarc, dpc_rarh, dpc_rars); /* calc disk addr */ - dpc_rars = (dpc_rars + 1) % DP_NUMSC; /* incr sector */ - if (dpc_rars == 0) { /* wrap? */ - dpc_rarh = dpc_rarh ^ 1; /* incr head */ - dpc_eoc = ((dpc_rarh & 1) == 0); /* calc eoc */ - } - if (err = fseek (uptr->fileref, da * sizeof (int16), - SEEK_SET)) break; - fxread (dpxb, sizeof (int16), DP_NUMWD, uptr->fileref); - if (err = ferror (uptr->fileref)) break; - } - dpd_ibuf = dpxb[dp_ptr++]; /* get word */ - if (dp_ptr >= DP_NUMWD) { /* end of sector? */ - if (uptr->FNC == FNC_CHK1) { /* check? */ - dpc_cnt = (dpc_cnt - 1) & DA_CKMASK; /* decr count */ - if (dpc_cnt == 0) break; /* stop at zero */ - } - dp_ptr = 0; /* wrap buf ptr */ - } - if (dpd.command && dpd_xfer) /* dch on, xfer? */ - dpdio (&dpd_dib, ioENF, 0); /* set dch flg */ - - dpd.command = CLEAR; /* clr dch cmd */ - sim_activate (uptr, dpc_xtime); /* sched next word */ - return SCPE_OK; - - case FNC_INIT: /* init */ - case FNC_WD: /* write */ - if (dp_ptr == 0) { /* start sector? */ - if (!dpd.command && !dpd_wval) break; /* xfer done? */ - if (uptr->flags & UNIT_WPRT) { /* wr prot? */ - dpc_sta[drv] = dpc_sta[drv] | STA_FLG; /* set status */ - break; /* done */ - } - if ((dpc_rarc != dpc_ucyl[drv]) || /* RAR cyl miscompare? */ - (dpc_rars >= DP_NUMSC)) { /* bad sector? */ - dpc_sta[drv] = dpc_sta[drv] | STA_AER; /* address error */ - break; - } - if (dpc_eoc) { /* end of cyl? */ - dpc_sta[drv] = dpc_sta[drv] | STA_EOC; /* set status */ - break; /* done */ - } - } - dpxb[dp_ptr++] = dpd_wval? dpd_obuf: 0; /* store word/fill */ - dpd_wval = 0; /* clr data valid */ - if (dp_ptr >= DP_NUMWD) { /* buffer full? */ - da = GETDA (dpc_rarc, dpc_rarh, dpc_rars); /* calc disk addr */ - dpc_rars = (dpc_rars + 1) % DP_NUMSC; /* incr sector */ - if (dpc_rars == 0) { /* wrap? */ - dpc_rarh = dpc_rarh ^ 1; /* incr head */ - dpc_eoc = ((dpc_rarh & 1) == 0); /* calc eoc */ - } - if (err = fseek (uptr->fileref, da * sizeof (int16), - SEEK_SET)) break; - fxwrite (dpxb, sizeof (int16), DP_NUMWD, uptr->fileref); - if (err = ferror (uptr->fileref)) break; /* error? */ - dp_ptr = 0; /* next sector */ - } - if (dpd.command && dpd_xfer) /* dch on, xfer? */ - dpdio (&dpd_dib, ioENF, 0); /* set dch flg */ - - dpd.command = CLEAR; /* clr dch cmd */ - sim_activate (uptr, dpc_xtime); /* sched next word */ - return SCPE_OK; - - default: - return SCPE_IERR; - } /* end case fnc */ - -dpc_sta[drv] = dpc_sta[drv] | STA_ATN; /* set ATN */ - -dpc.command = CLEAR; /* clr cch cmd */ -dpcio (&dpc_dib, ioENF, 0); /* set cch flg */ - -dpc_busy = 0; /* ctlr is free */ -dpd_xfer = dpd_wval = 0; - -if (err != 0) { /* error? */ - perror ("DP I/O error"); - clearerr (uptr->fileref); - return SCPE_IOERR; - } -return SCPE_OK; -} - - -/* Reset routine */ - -t_stat dpc_reset (DEVICE *dptr) -{ -int32 drv; -DIB *dibptr = (DIB *) dptr->ctxt; /* DIB pointer */ - -hp_enbdis_pair (dptr, /* make pair cons */ - (dptr == &dpd_dev) ? &dpc_dev : &dpd_dev); - -if (sim_switches & SWMASK ('P')) { /* initialization reset? */ - dpd_ibuf = dpd_obuf = 0; /* clear buffers */ - dpc_obuf = 0; /* clear buffer */ - dpc_rarc = dpc_rarh = dpc_rars = 0; /* clear RAR */ - } - -IOPRESET (dibptr); /* PRESET device (does not use PON) */ - -dpc_busy = 0; /* reset controller state */ -dpc_poll = 0; -dpd_xfer = 0; -dpd_wval = 0; -dpc_eoc = 0; -dp_ptr = 0; - -sim_cancel (&dpd_unit); /* cancel dch */ - -for (drv = 0; drv < DP_NUMDRV; drv++) { /* loop thru drives */ - sim_cancel (&dpc_unit[drv]); /* cancel activity */ - dpc_unit[drv].FNC = 0; /* clear function */ - dpc_ucyl[drv] = 0; /* clear drive pos */ - if (dpc_unit[drv].flags & UNIT_ATT) - dpc_sta[drv] = dpc_sta[drv] & STA_1ST; /* first seek status */ - else dpc_sta[drv] = 0; /* clear status */ - } - -return SCPE_OK; -} - - -/* Attach routine */ - -t_stat dpc_attach (UNIT *uptr, char *cptr) -{ -t_stat r; - -r = attach_unit (uptr, cptr); /* attach unit */ -if (r == SCPE_OK) dpc_load_unload (uptr, 0, NULL, NULL);/* if OK, load heads */ -return r; -} - - -/* Detach routine */ - -t_stat dpc_detach (UNIT* uptr) -{ -dpc_load_unload (uptr, UNIT_UNLOAD, NULL, NULL); /* unload heads */ -return detach_unit (uptr); /* detach unit */ -} - - -/* Load and unload heads */ - -t_stat dpc_load_unload (UNIT *uptr, int32 value, char *cptr, void *desc) -{ -int32 drv; - -if ((uptr->flags & UNIT_ATT) == 0) return SCPE_UNATT; /* must be attached to load */ - -if (value == UNIT_UNLOAD) /* unload heads? */ - uptr->flags = uptr->flags | UNIT_UNLOAD; /* indicate unload */ -else { /* load heads */ - uptr->flags = uptr->flags & ~UNIT_UNLOAD; /* indicate load */ - drv = uptr - dpc_unit; /* get drive no */ - dpc_sta[drv] = dpc_sta[drv] | STA_ATN | STA_1ST; /* update status */ - if (dpc_poll) /* polling enabled? */ - dpcio (&dpc_dib, ioENF, 0); /* set flag */ - } -return SCPE_OK; -} - - -/* Set controller type */ - -t_stat dp_settype (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -int32 i; - -if ((val < 0) || (val > 1) || (cptr != NULL)) - return SCPE_ARG; - -for (i = 0; i < DP_NUMDRV; i++) { - if (dpc_unit[i].flags & UNIT_ATT) - return SCPE_ALATT; - } - -for (i = 0; i < DP_NUMDRV; i++) - dpc_unit[i].capac = (val? DP_SIZE3: DP_SIZE2); - -dp_ctype = (CNTLR_TYPE) val; -return SCPE_OK; -} - - -/* Show controller type */ - -t_stat dp_showtype (FILE *st, UNIT *uptr, int32 val, void *desc) -{ -if (dp_ctype == A13210) - fprintf (st, "13210A"); -else - fprintf (st, "12557A"); - -return SCPE_OK; -} - - -/* 7900/7901 bootstrap routine (HP 12992F ROM) */ - -const BOOT_ROM dp_rom = { - 0106710, /*ST CLC DC ; clr dch */ - 0106711, /* CLC CC ; clr cch */ - 0017757, /* JSB STAT ; get status */ - 0067746, /*SK LDB SKCMD ; seek cmd */ - 0106610, /* OTB DC ; cyl # */ - 0103710, /* STC DC,C ; to dch */ - 0106611, /* OTB CC ; seek cmd */ - 0103711, /* STC CC,C ; to cch */ - 0102310, /* SFS DC ; addr wd ok? */ - 0027710, /* JMP *-1 ; no, wait */ - 0006400, /* CLB */ - 0102501, /* LIA 1 ; read switches */ - 0002011, /* SLA,RSS ; <0> set? */ - 0047747, /* ADB BIT9 ; head 2 = removable */ - 0106610, /* OTB DC ; head/sector */ - 0103710, /* STC DC,C ; to dch */ - 0102311, /* SFS CC ; seek done? */ - 0027720, /* JMP *-1 ; no, wait */ - 0017757, /* JSB STAT ; get status */ - 0067776, /* LDB DMACW ; DMA control */ - 0106606, /* OTB 6 */ - 0067750, /* LDB ADDR1 ; memory addr */ - 0106602, /* OTB 2 */ - 0102702, /* STC 2 ; flip DMA ctrl */ - 0067752, /* LDB CNT ; word count */ - 0106602, /* OTB 2 */ - 0063745, /* LDB RDCMD ; read cmd */ - 0102611, /* OTA CC ; to cch */ - 0103710, /* STC DC,C ; start dch */ - 0103706, /* STC 6,C ; start DMA */ - 0103711, /* STC CC,C ; start cch */ - 0102311, /* SFS CC ; done? */ - 0027737, /* JMP *-1 ; no, wait */ - 0017757, /* JSB STAT ; get status */ - 0027775, /* JMP XT ; done */ - 0037766, /*FSMSK 037766 ; status mask */ - 0004000, /*STMSK 004000 ; unsafe mask */ - 0020000, /*RDCMD 020000 ; read cmd */ - 0030000, /*SKCMD 030000 ; seek cmd */ - 0001000, /*BIT9 001000 ; head 2 select */ - 0102011, /*ADDR1 102011 */ - 0102055, /*ADDR2 102055 */ - 0164000, /*CNT -6144. */ - 0, 0, 0, 0, /* unused */ - 0000000, /*STAT 0 */ - 0002400, /* CLA ; status request */ - 0102611, /* OTC CC ; to cch */ - 0103711, /* STC CC,C ; start cch */ - 0102310, /* SFS DC ; done? */ - 0027763, /* JMP *-1 */ - 0102510, /* LIA DC ; get status */ - 0013743, /* AND FSMSK ; mask 15,14,3,0 */ - 0002003, /* SZA,RSS ; drive ready? */ - 0127757, /* JMP STAT,I ; yes */ - 0013744, /* AND STMSK ; fault? */ - 0002002, /* SZA */ - 0102030, /* HLT 30 ; yes */ - 0027700, /* JMP ST ; no, retry */ - 0117751, /*XT JSB ADDR2,I ; start program */ - 0120010, /*DMACW 120000+DC */ - 0000000 /* -ST */ - }; - -t_stat dpc_boot (int32 unitno, DEVICE *dptr) -{ -int32 dev; - -if (unitno != 0) return SCPE_NOFNC; /* only unit 0 */ -dev = dpd_dib.select_code; /* get data chan dev */ -if (ibl_copy (dp_rom, dev)) return SCPE_IERR; /* copy boot to memory */ -SR = (SR & IBL_OPT) | IBL_DP | (dev << IBL_V_DEV); /* set SR */ -if (sim_switches & SWMASK ('R')) SR = SR | IBL_DP_REM; /* boot from removable? */ -return SCPE_OK; -} +/* hp2100_dp.c: HP 2100 12557A/13210A disk simulator + + Copyright (c) 1993-2014, Robert M. Supnik + + 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 + ROBERT M SUPNIK 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 Robert M Supnik shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + + DP 12557A 2871 disk subsystem + 13210A 7900 disk subsystem + + 30-Dec-14 JDB Added S-register parameters to ibl_copy + 24-Dec-14 JDB Added casts for explicit downward conversions + 18-Dec-12 MP Now calls sim_activate_time to get remaining seek time + 09-May-12 JDB Separated assignments from conditional expressions + 10-Feb-12 JDB Deprecated DEVNO in favor of SC + Added CNTLR_TYPE cast to dp_settype + 28-Mar-11 JDB Tidied up signal handling + 26-Oct-10 JDB Changed I/O signal handler for revised signal model + 10-Aug-08 JDB Added REG_FIT to register variables < 32-bit size + 26-Jun-08 JDB Rewrote device I/O to model backplane signals + 28-Dec-06 JDB Added ioCRS state to I/O decoders + 01-Mar-05 JDB Added SET UNLOAD/LOAD + 07-Oct-04 JDB Fixed enable/disable from either device + Fixed ANY ERROR status for 12557A interface + Fixed unattached drive status for 12557A interface + Status cmd without prior STC DC now completes (12557A) + OTA/OTB CC on 13210A interface also does CLC CC + Fixed RAR model + Fixed seek check on 13210 if sector out of range + 20-Aug-04 JDB Fixes from Dave Bryan + - Check status on unattached drive set busy and not ready + - Check status tests wrong unit for write protect status + - Drive on line sets ATN, will set FLG if polling + 15-Aug-04 RMS Controller resumes polling for ATN interrupts after + read status (found by Dave Bryan) + 22-Jul-04 RMS Controller sets ATN for all commands except + read status (found by Dave Bryan) + 21-Apr-04 RMS Fixed typo in boot loader (found by Dave Bryan) + 26-Apr-04 RMS Fixed SFS x,C and SFC x,C + Fixed SR setting in IBL + Fixed interpretation of SR<0> + Revised IBL loader + Implemented DMA SRQ (follows FLG) + 25-Apr-03 RMS Revised for extended file support + Fixed bug(s) in boot (found by Terry Newton) + 10-Nov-02 RMS Added BOOT command, fixed numerous bugs + 15-Jan-02 RMS Fixed INIT handling (found by Bill McDermith) + 10-Jan-02 RMS Fixed f(x)write call (found by Bill McDermith) + 03-Dec-01 RMS Changed DEVNO to use extended SET/SHOW + 24-Nov-01 RMS Changed STA to be an array + 07-Sep-01 RMS Moved function prototypes + 29-Nov-00 RMS Made variable names unique + 21-Nov-00 RMS Fixed flag, buffer power up state + + References: + - 7900A Disc Drive Operating and Service Manual (07900-90002, Feb-1975) + - 13210A Disc Drive Interface Kit Operating and Service Manual + (13210-90003, Nov-1974) + - 12557A Cartridge Disc Interface Kit Operating and Service Manual + (12557-90001, Sep-1970) + + + The simulator uses a number of state variables: + + dpc_busy set to drive number + 1 when the controller is busy + of the unit in use + dpd_xfer set to 1 if the data channel is executing a data transfer + dpd_wval set to 1 by OTx if either !dpc_busy or dpd_xfer + dpc_poll set to 1 if attention polling is enabled + + dpc_busy and dpd_xfer are set together at the start of a read, write, refine, + or init. When data transfers are complete (CLC DC), dpd_xfer is cleared, but the + operation is not necessarily over. When the operation is complete, dpc_busy + is cleared and the command channel flag is set. + + dpc_busy && !dpd_xfer && STC DC (controller is busy, data channel transfer has + been terminated by CLC DC, but a word has been placed in the data channel buffer) + indicates data overrun. + + dpd_wval is used in write operations to fill out the sector buffer with 0's + if only a partial sector has been transferred. + + dpc_poll indicates whether seek completion polling can occur. It is cleared + by reset and CLC CC and set by issuance of a seek or completion of check status. + + The controller's "Record Address Register" (RAR) contains the CHS address of + the last Seek or Address Record command executed. The RAR is shared among + all drives on the controller. In addition, each drive has an internal + position register that contains the last cylinder position transferred to the + drive during Seek command execution (data operations always start with the + RAR head and sector position). + + In a real drive, the address field of the sector under the head is read and + compared to the RAR. When they match, the target sector is under the head + and is ready for reading or writing. If a match doesn't occur, an Address + Error is indicated. In the simulator, the address field is obtained from the + drive's current position register during a read, i.e., the "on-disc" address + field is assumed to match the current position. + + The following implemented behaviors have been inferred from secondary sources + (diagnostics, operating system drivers, etc.), due to absent or contradictory + authoritative information; future correction may be needed: + + 1. Status bit 15 (ATTENTION) does not set bit 0 (ANY ERROR) on the 12557A. + 2. Omitting STC DC before Status Check does not set DC flag but does poll. +*/ + +#include "hp2100_defs.h" + +#define UNIT_V_WLK (UNIT_V_UF + 0) /* write locked */ +#define UNIT_V_UNLOAD (UNIT_V_UF + 1) /* heads unloaded */ +#define UNIT_WLK (1 << UNIT_V_WLK) +#define UNIT_UNLOAD (1 << UNIT_V_UNLOAD) +#define FNC u3 /* saved function */ +#define DRV u4 /* drive number (DC) */ +#define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write prot */ + +#define DP_N_NUMWD 7 +#define DP_NUMWD (1 << DP_N_NUMWD) /* words/sector */ +#define DP_NUMSC2 12 /* sectors/srf 12557 */ +#define DP_NUMSC3 24 /* sectors/srf 13210 */ +#define DP_NUMSC (dp_ctype ? DP_NUMSC3 : DP_NUMSC2) +#define DP_NUMSF 4 /* surfaces/cylinder */ +#define DP_NUMCY 203 /* cylinders/disk */ +#define DP_SIZE2 (DP_NUMSF * DP_NUMCY * DP_NUMSC2 * DP_NUMWD) +#define DP_SIZE3 (DP_NUMSF * DP_NUMCY * DP_NUMSC3 * DP_NUMWD) +#define DP_NUMDRV 4 /* # drives */ + +/* Command word */ + +#define CW_V_FNC 12 /* function */ +#define CW_M_FNC 017 +#define CW_GETFNC(x) (((x) >> CW_V_FNC) & CW_M_FNC) +#define FNC_STA 000 /* status check */ +#define FNC_WD 001 /* write */ +#define FNC_RD 002 /* read */ +#define FNC_SEEK 003 /* seek */ +#define FNC_REF 005 /* refine */ +#define FNC_CHK 006 /* check */ +#define FNC_INIT 011 /* init */ +#define FNC_AR 013 /* address */ +#define FNC_SEEK1 020 /* fake - seek1 */ +#define FNC_SEEK2 021 /* fake - seek2 */ +#define FNC_SEEK3 022 /* fake - seek3 */ +#define FNC_CHK1 023 /* fake - check1 */ +#define FNC_AR1 024 /* fake - arec1 */ +#define CW_V_DRV 0 /* drive */ +#define CW_M_DRV 03 +#define CW_GETDRV(x) (((x) >> CW_V_DRV) & CW_M_DRV) + +/* Disk address words */ + +#define DA_V_CYL 0 /* cylinder */ +#define DA_M_CYL 0377 +#define DA_GETCYL(x) (((x) >> DA_V_CYL) & DA_M_CYL) +#define DA_V_HD 8 /* head */ +#define DA_M_HD 03 +#define DA_GETHD(x) (((x) >> DA_V_HD) & DA_M_HD) +#define DA_V_SC 0 /* sector */ +#define DA_M_SC2 017 +#define DA_M_SC3 037 +#define DA_M_SC (dp_ctype ? DA_M_SC3 : DA_M_SC2) +#define DA_GETSC(x) (((x) >> DA_V_SC) & DA_M_SC) +#define DA_CKMASK2 037 /* check mask */ +#define DA_CKMASK3 077 +#define DA_CKMASK (dp_ctype ? DA_CKMASK3 : DA_CKMASK2) + +/* Status in dpc_sta[drv], (u) = unused in 13210, (d) = dynamic */ + +#define STA_ATN 0100000 /* attention (u) */ +#define STA_1ST 0040000 /* first status */ +#define STA_OVR 0020000 /* overrun */ +#define STA_RWU 0010000 /* rw unsafe NI (u) */ +#define STA_ACU 0004000 /* access unsafe NI */ +#define STA_HUNT 0002000 /* hunting NI (12557) */ +#define STA_PROT 0002000 /* protected (13210) */ +#define STA_SKI 0001000 /* incomplete NI (u) */ +#define STA_SKE 0000400 /* seek error */ +/* 0000200 (unused) */ +#define STA_NRDY 0000100 /* not ready (d) */ +#define STA_EOC 0000040 /* end of cylinder */ +#define STA_AER 0000020 /* addr error */ +#define STA_FLG 0000010 /* flagged */ +#define STA_BSY 0000004 /* seeking */ +#define STA_DTE 0000002 /* data error */ +#define STA_ERR 0000001 /* any error (d) */ + +#define STA_ERSET2 (STA_1ST | STA_OVR | STA_RWU | STA_ACU | \ + STA_SKI | STA_SKE | STA_NRDY | \ + STA_EOC | STA_AER | STA_DTE) /* 12557A error set */ +#define STA_ERSET3 (STA_ATN | STA_1ST | STA_OVR | STA_RWU | STA_ACU | \ + STA_SKI | STA_SKE | STA_NRDY | STA_EOC | STA_AER | \ + STA_FLG | STA_BSY | STA_DTE) /* 13210A error set */ +#define STA_ANYERR (dp_ctype ? STA_ERSET3 : STA_ERSET2) + +#define STA_UNLOADED (dp_ctype ? (STA_NRDY | STA_BSY) : STA_NRDY) +#define STA_MBZ13 (STA_ATN | STA_RWU | STA_SKI) /* zero in 13210 */ + +struct { + FLIP_FLOP command; /* cch command flip-flop */ + FLIP_FLOP control; /* cch control flip-flop */ + FLIP_FLOP flag; /* cch flag flip-flop */ + FLIP_FLOP flagbuf; /* cch flag buffer flip-flop */ + } dpc = { CLEAR, CLEAR, CLEAR, CLEAR }; + +/* Controller types */ + +typedef enum { + A12557, + A13210 + } CNTLR_TYPE; + +CNTLR_TYPE dp_ctype = A13210; /* ctrl type */ +int32 dpc_busy = 0; /* cch unit */ +int32 dpc_poll = 0; /* cch poll enable */ +int32 dpc_cnt = 0; /* check count */ +int32 dpc_eoc = 0; /* end of cyl */ +int32 dpc_stime = 100; /* seek time */ +int32 dpc_ctime = 100; /* command time */ +int32 dpc_xtime = 5; /* xfer time */ +int32 dpc_dtime = 2; /* dch time */ +int32 dpd_obuf = 0, dpd_ibuf = 0; /* dch buffers */ +int32 dpc_obuf = 0; /* cch buffers */ + +struct { + FLIP_FLOP command; /* dch command flip-flop */ + FLIP_FLOP control; /* dch control flip-flop */ + FLIP_FLOP flag; /* dch flag flip-flop */ + FLIP_FLOP flagbuf; /* dch flag buffer flip-flop */ + } dpd = { CLEAR, CLEAR, CLEAR, CLEAR }; + +int32 dpd_xfer = 0; /* xfer in prog */ +int32 dpd_wval = 0; /* write data valid */ +int32 dp_ptr = 0; /* buffer ptr */ +uint8 dpc_rarc = 0; /* RAR cylinder */ +uint8 dpc_rarh = 0; /* RAR head */ +uint8 dpc_rars = 0; /* RAR sector */ +uint8 dpc_ucyl[DP_NUMDRV] = { 0 }; /* unit cylinder */ +uint16 dpc_sta[DP_NUMDRV] = { 0 }; /* status regs */ +uint16 dpxb[DP_NUMWD]; /* sector buffer */ + +DEVICE dpd_dev, dpc_dev; + +IOHANDLER dpdio; +IOHANDLER dpcio; + +t_stat dpc_svc (UNIT *uptr); +t_stat dpd_svc (UNIT *uptr); +t_stat dpc_reset (DEVICE *dptr); +t_stat dpc_attach (UNIT *uptr, char *cptr); +t_stat dpc_detach (UNIT* uptr); +t_stat dpc_boot (int32 unitno, DEVICE *dptr); +void dp_god (int32 fnc, int32 drv, int32 time); +void dp_goc (int32 fnc, int32 drv, int32 time); +t_stat dpc_load_unload (UNIT *uptr, int32 value, char *cptr, void *desc); +t_stat dp_settype (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat dp_showtype (FILE *st, UNIT *uptr, int32 val, void *desc); + +/* DPD data structures + + dpd_dev DPD device descriptor + dpd_unit DPD unit list + dpd_reg DPD register list +*/ + +DIB dp_dib[] = { + { &dpdio, DPD }, + { &dpcio, DPC } + }; + +#define dpd_dib dp_dib[0] +#define dpc_dib dp_dib[1] + +UNIT dpd_unit = { UDATA (&dpd_svc, 0, 0) }; + +REG dpd_reg[] = { + { ORDATA (IBUF, dpd_ibuf, 16) }, + { ORDATA (OBUF, dpd_obuf, 16) }, + { BRDATA (DBUF, dpxb, 8, 16, DP_NUMWD) }, + { DRDATA (BPTR, dp_ptr, DP_N_NUMWD) }, + { FLDATA (CMD, dpd.command, 0) }, + { FLDATA (CTL, dpd.control, 0) }, + { FLDATA (FLG, dpd.flag, 0) }, + { FLDATA (FBF, dpd.flagbuf, 0) }, + { FLDATA (XFER, dpd_xfer, 0) }, + { FLDATA (WVAL, dpd_wval, 0) }, + { ORDATA (SC, dpd_dib.select_code, 6), REG_HRO }, + { ORDATA (DEVNO, dpd_dib.select_code, 6), REG_HRO }, + { NULL } + }; + +MTAB dpd_mod[] = { + { MTAB_XTD | MTAB_VDV, 1, "SC", "SC", &hp_setsc, &hp_showsc, &dpd_dev }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &dpd_dev }, + { 0 } + }; + +DEVICE dpd_dev = { + "DPD", &dpd_unit, dpd_reg, dpd_mod, + 1, 10, DP_N_NUMWD, 1, 8, 16, + NULL, NULL, &dpc_reset, + NULL, NULL, NULL, + &dpd_dib, DEV_DISABLE + }; + +/* DPC data structures + + dpc_dev DPC device descriptor + dpc_unit DPC unit list + dpc_reg DPC register list + dpc_mod DPC modifier list +*/ + +UNIT dpc_unit[] = { + { UDATA (&dpc_svc, UNIT_FIX | UNIT_ATTABLE | UNIT_ROABLE | + UNIT_DISABLE | UNIT_UNLOAD, DP_SIZE3) }, + { UDATA (&dpc_svc, UNIT_FIX | UNIT_ATTABLE | UNIT_ROABLE | + UNIT_DISABLE | UNIT_UNLOAD, DP_SIZE3) }, + { UDATA (&dpc_svc, UNIT_FIX | UNIT_ATTABLE | UNIT_ROABLE | + UNIT_DISABLE | UNIT_UNLOAD, DP_SIZE3) }, + { UDATA (&dpc_svc, UNIT_FIX | UNIT_ATTABLE | UNIT_ROABLE | + UNIT_DISABLE | UNIT_UNLOAD, DP_SIZE3) } + }; + +REG dpc_reg[] = { + { ORDATA (OBUF, dpc_obuf, 16) }, + { ORDATA (BUSY, dpc_busy, 4), REG_RO }, + { ORDATA (CNT, dpc_cnt, 5) }, + { FLDATA (CMD, dpc.command, 0) }, + { FLDATA (CTL, dpc.control, 0) }, + { FLDATA (FLG, dpc.flag, 0) }, + { FLDATA (FBF, dpc.flagbuf, 0) }, + { FLDATA (EOC, dpc_eoc, 0) }, + { FLDATA (POLL, dpc_poll, 0) }, + { DRDATA (RARC, dpc_rarc, 8), PV_RZRO | REG_FIT }, + { DRDATA (RARH, dpc_rarh, 2), PV_RZRO | REG_FIT }, + { DRDATA (RARS, dpc_rars, 5), PV_RZRO | REG_FIT }, + { BRDATA (CYL, dpc_ucyl, 10, 8, DP_NUMDRV), PV_RZRO }, + { BRDATA (STA, dpc_sta, 8, 16, DP_NUMDRV) }, + { DRDATA (CTIME, dpc_ctime, 24), PV_LEFT }, + { DRDATA (DTIME, dpc_dtime, 24), PV_LEFT }, + { DRDATA (STIME, dpc_stime, 24), PV_LEFT }, + { DRDATA (XTIME, dpc_xtime, 24), REG_NZ | PV_LEFT }, + { FLDATA (CTYPE, dp_ctype, 0), REG_HRO }, + { URDATA (UFNC, dpc_unit[0].FNC, 8, 8, 0, + DP_NUMDRV, REG_HRO) }, + { URDATA (CAPAC, dpc_unit[0].capac, 10, T_ADDR_W, 0, + DP_NUMDRV, PV_LEFT | REG_HRO) }, + { ORDATA (SC, dpc_dib.select_code, 6), REG_HRO }, + { ORDATA (DEVNO, dpc_dib.select_code, 6), REG_HRO }, + { NULL } + }; + +MTAB dpc_mod[] = { + { UNIT_UNLOAD, UNIT_UNLOAD, "heads unloaded", "UNLOADED", dpc_load_unload }, + { UNIT_UNLOAD, 0, "heads loaded", "LOADED", dpc_load_unload }, + { UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL }, + { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL }, + { MTAB_XTD | MTAB_VDV, 1, NULL, "13210A", + &dp_settype, NULL, NULL }, + { MTAB_XTD | MTAB_VDV, 0, NULL, "12557A", + &dp_settype, NULL, NULL }, + { MTAB_XTD | MTAB_VDV, 0, "TYPE", NULL, + NULL, &dp_showtype, NULL }, + { MTAB_XTD | MTAB_VDV, 1, "SC", "SC", &hp_setsc, &hp_showsc, &dpd_dev }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &dpd_dev }, + { 0 } + }; + +DEVICE dpc_dev = { + "DPC", dpc_unit, dpc_reg, dpc_mod, + DP_NUMDRV, 8, 24, 1, 8, 16, + NULL, NULL, &dpc_reset, + &dpc_boot, &dpc_attach, &dpc_detach, + &dpc_dib, DEV_DISABLE + }; + + +/* Data channel I/O signal handler. + + For the 12557A, the card contains the usual control, flag, and flag buffer + flip-flops. PRL, IRQ, and SRQ are standard. A command flip-flop indicates + that data is available. + + For the 13210A, the card has a flag and a flag buffer flip-flop, but no + control or interrupt flip-flop. SRQ is standard. IRQ and PRL are not + driven, and the card does not respond to IAK. STC sets the command flip-flop + to initiate a data transfer. CLC has no effect. + + Implementation notes: + + 1. The CRS signal clears the drive attention register. Under simulation, + drive attention status is generated dynamically, so there is no attention + register. +*/ + +uint32 dpdio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) +{ +IOSIGNAL signal; +IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ + +while (working_set) { + signal = IONEXT (working_set); /* isolate next signal */ + + switch (signal) { /* dispatch I/O signal */ + + case ioCLF: /* clear flag flip-flop */ + dpd.flag = dpd.flagbuf = CLEAR; + break; + + + case ioSTF: /* set flag flip-flop */ + case ioENF: /* enable flag */ + dpd.flag = dpd.flagbuf = SET; + break; + + + case ioSFC: /* skip if flag is clear */ + setstdSKF (dpd); + break; + + + case ioSFS: /* skip if flag is set */ + setstdSKF (dpd); + break; + + + case ioIOI: /* I/O data input */ + stat_data = IORETURN (SCPE_OK, dpd_ibuf); /* merge in return status */ + break; + + + case ioIOO: /* I/O data output */ + dpd_obuf = IODATA (stat_data); /* clear supplied status */ + + if (!dpc_busy || dpd_xfer) /* if !overrun */ + dpd_wval = 1; /* valid */ + break; + + + case ioPOPIO: /* power-on preset to I/O */ + dpd.flag = dpd.flagbuf = SET; /* set flag buffer and flag */ + + if (dp_ctype == A12557) /* 12557? */ + dpd_obuf = 0; /* clear output buffer */ + break; + + + case ioCRS: /* control reset */ + dpd.command = CLEAR; /* clear command */ + + if (dp_ctype == A12557) /* 12557? */ + dpd.control = CLEAR; /* clear control */ + + else { /* 13210 */ + dpc_rarc = 0; /* clear controller cylinder address */ + dpc_ucyl [CW_GETDRV (dpc_obuf)] = 0; /* clear last drive addressed cylinder */ + } + break; + + + case ioCLC: /* clear control flip-flop */ + if (dp_ctype == A12557) /* 12557? */ + dpd.control = CLEAR; /* clear control */ + + dpd_xfer = 0; /* clr xfer in progress */ + break; + + + case ioSTC: /* set control flip-flop */ + if (dp_ctype == A12557) /* 12557? */ + dpd.control = SET; /* set control */ + + dpd.command = SET; /* set cmd */ + + if (dpc_busy && !dpd_xfer) /* overrun? */ + dpc_sta[dpc_busy - 1] |= STA_OVR; + break; + + + case ioSIR: /* set interrupt request */ + if (dp_ctype == A12557) { /* 12557? */ + setstdPRL (dpd); /* set standard PRL signal */ + setstdIRQ (dpd); /* set standard IRQ signal */ + } + + setstdSRQ (dpd); /* set standard SRQ signal */ + break; + + + case ioIAK: /* interrupt acknowledge */ + if (dp_ctype == A12557) /* 12557? */ + dpd.flagbuf = CLEAR; /* clear flag buffer */ + break; + + + default: /* all other signals */ + break; /* are ignored */ + } + + working_set = working_set & ~signal; /* remove current signal from set */ + } + +return stat_data; +} + + +/* Command channel I/O signal handler. + + The 12557A and 13210A have the usual control, flag, and flag buffer + flip-flops. Only the 12557A has a command flip-flop. IRQ, PRL, and SRQ are + standard. + + Implementation notes: + + 1. In hardware, the command channel card passes PRH to PRL. The data card + actually drives PRL with the command channel's control and flag states, + even though the command channel's control, flag, and flag buffer drive + IRQH. That is, the priority chain is broken at the data card, although + the command card is interrupting. This works in hardware, but we must + break PRL at the command card under simulation to allow the command card + to interrupt. +*/ + +uint32 dpcio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) +{ +uint16 data; +int32 i, fnc, drv; +IOSIGNAL signal; +IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ + +while (working_set) { + signal = IONEXT (working_set); /* isolate next signal */ + + switch (signal) { /* dispatch I/O signal */ + + case ioCLF: /* clear flag flip-flop */ + dpc.flag = dpc.flagbuf = CLEAR; + break; + + + case ioSTF: /* set flag flip-flop */ + case ioENF: /* enable flag */ + dpc.flag = dpc.flagbuf = SET; + break; + + + case ioSFC: /* skip if flag is clear */ + setstdSKF (dpc); + break; + + + case ioSFS: /* skip if flag is set */ + setstdSKF (dpc); + break; + + + case ioIOI: /* I/O data input */ + data = 0; + + for (i = 0; i < DP_NUMDRV; i++) /* form attention register value */ + if (dpc_sta[i] & STA_ATN) + data = data | (uint16) (1 << i); + + stat_data = IORETURN (SCPE_OK, data); /* merge in return status */ + break; + + + case ioIOO: /* I/O data output */ + dpc_obuf = IODATA (stat_data); /* clear supplied status */ + + if (dp_ctype == A13210) /* 13210? */ + dpcio (dibptr, ioCLC, 0); /* OTx causes CLC */ + break; + + + case ioPOPIO: /* power-on preset to I/O */ + dpc.flag = dpc.flagbuf = SET; /* set flag buffer and flag */ + + if (dp_ctype == A12557) /* 12557? */ + dpd_obuf = 0; /* clear output buffer */ + break; + + + case ioCRS: /* control reset */ + dpc.control = CLEAR; /* clear control */ + + if (dp_ctype == A12557) /* 12557? */ + dpc.command = CLEAR; /* clear command */ + break; + + + case ioCLC: /* clear control flip-flop */ + dpc.control = CLEAR; /* clr ctl */ + + if (dp_ctype == A12557) /* 12557? */ + dpc.command = CLEAR; /* cancel non-seek */ + + if (dpc_busy) + sim_cancel (&dpc_unit[dpc_busy - 1]); + + sim_cancel (&dpd_unit); /* cancel dch */ + dpd_xfer = 0; /* clr dch xfer */ + dpc_busy = 0; /* clr cch busy */ + dpc_poll = 0; /* clr cch poll */ + break; + + + case ioSTC: /* set control flip-flop */ + dpc.control = SET; /* set ctl */ + + if ((dp_ctype == A13210) || !dpc.command) { /* 13210 or command is clear? */ + if (dp_ctype == A12557) /* 12557? */ + dpc.command = SET; /* set command */ + + drv = CW_GETDRV (dpc_obuf); /* get fnc, drv */ + fnc = CW_GETFNC (dpc_obuf); /* from cmd word */ + + switch (fnc) { /* case on fnc */ + + case FNC_SEEK: /* seek */ + dpc_poll = 1; /* enable polling */ + dp_god (fnc, drv, dpc_dtime); /* sched dch xfr */ + break; + + case FNC_STA: /* rd sta */ + if (dp_ctype == A13210) /* 13210? clr dch flag */ + dpdio (&dpd_dib, ioCLF, 0); + + case FNC_CHK: /* check */ + case FNC_AR: /* addr rec */ + dp_god (fnc, drv, dpc_dtime); /* sched dch xfr */ + break; + + case FNC_RD: case FNC_WD: /* read, write */ + case FNC_REF: case FNC_INIT: /* refine, init */ + dp_goc (fnc, drv, dpc_ctime); /* sched drive */ + break; + } /* end case */ + } /* end if */ + break; + + + case ioSIR: /* set interrupt request */ + setstdPRL (dpc); /* set standard PRL signal */ + setstdIRQ (dpc); /* set standard IRQ signal */ + setstdSRQ (dpc); /* set standard SRQ signal */ + break; + + + case ioIAK: /* interrupt acknowledge */ + dpc.flagbuf = CLEAR; /* clear flag buffer */ + break; + + + default: /* all other signals */ + break; /* are ignored */ + } + + working_set = working_set & ~signal; /* remove current signal from set */ + } + +return stat_data; +} + + +/* Start data channel operation */ + +void dp_god (int32 fnc, int32 drv, int32 time) +{ +dpd_unit.DRV = drv; /* save unit */ +dpd_unit.FNC = fnc; /* save function */ +sim_activate (&dpd_unit, time); +return; +} + + +/* Start controller operation */ + +void dp_goc (int32 fnc, int32 drv, int32 time) +{ +int32 t; + +t = sim_activate_time (&dpc_unit[drv]); +if (t) { /* still seeking? */ + sim_cancel (&dpc_unit[drv]); /* stop seek */ + dpc_sta[drv] = dpc_sta[drv] & ~STA_BSY; /* clear busy */ + time = time + t; /* include seek time */ + } +dp_ptr = 0; /* init buf ptr */ +dpc_eoc = 0; /* clear end cyl */ +dpc_busy = drv + 1; /* set busy */ +dpd_xfer = 1; /* xfer in prog */ +dpc_unit[drv].FNC = fnc; /* save function */ +dpc_sta[drv] = dpc_sta[drv] & ~STA_ATN; /* clear ATN */ +sim_activate (&dpc_unit[drv], time); /* activate unit */ +return; +} + + +/* Data channel unit service + + This routine handles the data channel transfers. It also handles + data transfers that are blocked by seek in progress. + + uptr->DRV = target drive + uptr->FNC = target function + + Seek substates + seek - transfer cylinder + seek1 - transfer head/surface + Address record + ar - transfer cylinder + ar1 - transfer head/surface, finish operation + Status check - transfer status, finish operation + Check data + chk - transfer sector count +*/ + +t_stat dpd_svc (UNIT *uptr) +{ +int32 i, drv, st; + +drv = uptr->DRV; /* get drive no */ +switch (uptr->FNC) { /* case function */ + + case FNC_AR: /* arec, need cyl */ + case FNC_SEEK: /* seek, need cyl */ + if (dpd.command) { /* dch active? */ + dpc_rarc = DA_GETCYL (dpd_obuf); /* set RAR from cyl word */ + dpd_wval = 0; /* clr data valid */ + + dpd.command = CLEAR; /* clr dch cmd */ + dpdio (&dpd_dib, ioENF, 0); /* set dch flg */ + + if (uptr->FNC == FNC_AR) uptr->FNC = FNC_AR1; + else uptr->FNC = FNC_SEEK1; /* advance state */ + } + sim_activate (uptr, dpc_xtime); /* no, wait more */ + break; + + case FNC_AR1: /* arec, need hd/sec */ + case FNC_SEEK1: /* seek, need hd/sec */ + if (dpd.command) { /* dch active? */ + dpc_rarh = DA_GETHD (dpd_obuf); /* set RAR from head */ + dpc_rars = DA_GETSC (dpd_obuf); /* set RAR from sector */ + dpd_wval = 0; /* clr data valid */ + + dpd.command = CLEAR; /* clr dch cmd */ + dpdio (&dpd_dib, ioENF, 0); /* set dch flg */ + + if (uptr->FNC == FNC_AR1) { + dpc.command = CLEAR; /* clr cch cmd */ + dpcio (&dpc_dib, ioENF, 0); /* set cch flg */ + + dpc_sta[drv] = dpc_sta[drv] | STA_ATN; /* set drv attn */ + break; /* done if Address Record */ + } + if (sim_is_active (&dpc_unit[drv])) { /* if busy, */ + dpc_sta[drv] = dpc_sta[drv] | STA_SKE; /* seek check */ + break; /* allow prev seek to cmpl */ + } + if ((dpc_rarc >= DP_NUMCY) || /* invalid cyl? */ + ((dp_ctype == A13210) && /* or 13210A */ + (dpc_rars >= DP_NUMSC3))) { /* and invalid sector? */ + dpc_sta[drv] = dpc_sta[drv] | STA_SKE; /* seek check */ + sim_activate (&dpc_unit[drv], 1); /* schedule drive no-wait */ + dpc_unit[drv].FNC = FNC_SEEK3; /* do immed compl w/poll */ + break; + } + st = abs (dpc_rarc - dpc_ucyl[drv]) * dpc_stime; + if (st == 0) st = dpc_stime; /* min time */ + dpc_ucyl[drv] = dpc_rarc; /* transfer RAR */ + sim_activate (&dpc_unit[drv], st); /* schedule drive */ + dpc_sta[drv] = (dpc_sta[drv] | STA_BSY) & + ~(STA_SKE | STA_SKI | STA_HUNT); + dpc_unit[drv].FNC = FNC_SEEK2; /* set operation */ + } + else sim_activate (uptr, dpc_xtime); /* no, wait more */ + break; + + case FNC_STA: /* read status */ + if (dpd.command || (dp_ctype == A13210)) { /* dch act or 13210? */ + if ((dpc_unit[drv].flags & UNIT_UNLOAD) == 0) { /* drive up? */ + dpd_ibuf = dpc_sta[drv] & ~STA_ERR; /* clear err */ + if (dp_ctype == A13210) dpd_ibuf = /* 13210? */ + (dpd_ibuf & ~(STA_MBZ13 | STA_PROT)) | + (dpc_unit[drv].flags & UNIT_WPRT? STA_PROT: 0); + } + else dpd_ibuf = STA_UNLOADED; /* not ready */ + if (dpd_ibuf & STA_ANYERR) /* errors? set flg */ + dpd_ibuf = dpd_ibuf | STA_ERR; + + dpc.command = CLEAR; /* clr cch cmd */ + dpd.command = CLEAR; /* clr dch cmd */ + dpdio (&dpd_dib, ioENF, 0); /* set dch flg */ + } + + dpc_sta[drv] = dpc_sta[drv] & /* clr sta flags */ + ~(STA_ATN | STA_1ST | STA_OVR | + STA_RWU | STA_ACU | STA_EOC | + STA_AER | STA_FLG | STA_DTE); + dpc_poll = 1; /* enable polling */ + for (i = 0; i < DP_NUMDRV; i++) { /* loop thru drives */ + if (dpc_sta[i] & STA_ATN) { /* any ATN set? */ + dpcio (&dpc_dib, ioENF, 0); /* set cch flg */ + break; + } + } + break; + + case FNC_CHK: /* check, need cnt */ + if (dpd.command) { /* dch active? */ + dpc_cnt = dpd_obuf & DA_CKMASK; /* get count */ + dpd_wval = 0; /* clr data valid */ + dp_goc (FNC_CHK1, drv, dpc_xtime); /* sched drv */ + } + else sim_activate (uptr, dpc_xtime); /* wait more */ + break; + + default: + return SCPE_IERR; + } + +return SCPE_OK; +} + + +/* Drive unit service + + This routine handles the data transfers. + + Seek substates + seek2 - done + Refine sector - erase sector, finish operation + Check data + chk1 - finish operation + Read + Write +*/ + +#define GETDA(x,y,z) \ + (((((x) * DP_NUMSF) + (y)) * DP_NUMSC) + (z)) * DP_NUMWD + +t_stat dpc_svc (UNIT *uptr) +{ +int32 da, drv, err; + +err = 0; /* assume no err */ +drv = uptr - dpc_unit; /* get drive no */ +if (uptr->flags & UNIT_UNLOAD) { /* drive down? */ + + dpc.command = CLEAR; /* clr cch cmd */ + dpcio (&dpc_dib, ioENF, 0); /* set cch flg */ + + dpc_sta[drv] = 0; /* clr status */ + dpc_busy = 0; /* ctlr is free */ + dpc_poll = 0; /* polling disabled */ + dpd_xfer = 0; + dpd_wval = 0; + return SCPE_OK; + } +switch (uptr->FNC) { /* case function */ + + case FNC_SEEK2: /* positioning done */ + dpc_sta[drv] = (dpc_sta[drv] | STA_ATN) & ~STA_BSY; /* fall into cmpl */ + case FNC_SEEK3: /* seek complete */ + if (dpc_poll) { /* polling enabled? */ + dpc.command = CLEAR; /* clr cch cmd */ + dpcio (&dpc_dib, ioENF, 0); /* set cch flg */ + } + return SCPE_OK; + + case FNC_REF: /* refine sector */ + break; /* just a NOP */ + + case FNC_RD: /* read */ + case FNC_CHK1: /* check */ + if (dp_ptr == 0) { /* new sector? */ + if (!dpd.command && (uptr->FNC != FNC_CHK1)) break; + if (dpc_rarc != dpc_ucyl[drv]) /* RAR cyl miscompare? */ + dpc_sta[drv] = dpc_sta[drv] | STA_AER; /* set flag, read */ + if (dpc_rars >= DP_NUMSC) { /* bad sector? */ + dpc_sta[drv] = dpc_sta[drv] | STA_AER; /* set flag, stop */ + break; + } + if (dpc_eoc) { /* end of cyl? */ + dpc_sta[drv] = dpc_sta[drv] | STA_EOC; + break; + } + da = GETDA (dpc_rarc, dpc_rarh, dpc_rars); /* calc disk addr */ + dpc_rars = (dpc_rars + 1) % DP_NUMSC; /* incr sector */ + if (dpc_rars == 0) { /* wrap? */ + dpc_rarh = dpc_rarh ^ 1; /* incr head */ + dpc_eoc = ((dpc_rarh & 1) == 0); /* calc eoc */ + } + err = fseek (uptr->fileref, da * sizeof (int16), SEEK_SET); + if (err) /* error? */ + break; + fxread (dpxb, sizeof (int16), DP_NUMWD, uptr->fileref); + err = ferror (uptr->fileref); + if (err) /* error? */ + break; + } + dpd_ibuf = dpxb[dp_ptr++]; /* get word */ + if (dp_ptr >= DP_NUMWD) { /* end of sector? */ + if (uptr->FNC == FNC_CHK1) { /* check? */ + dpc_cnt = (dpc_cnt - 1) & DA_CKMASK; /* decr count */ + if (dpc_cnt == 0) break; /* stop at zero */ + } + dp_ptr = 0; /* wrap buf ptr */ + } + if (dpd.command && dpd_xfer) /* dch on, xfer? */ + dpdio (&dpd_dib, ioENF, 0); /* set dch flg */ + + dpd.command = CLEAR; /* clr dch cmd */ + sim_activate (uptr, dpc_xtime); /* sched next word */ + return SCPE_OK; + + case FNC_INIT: /* init */ + case FNC_WD: /* write */ + if (dp_ptr == 0) { /* start sector? */ + if (!dpd.command && !dpd_wval) break; /* xfer done? */ + if (uptr->flags & UNIT_WPRT) { /* wr prot? */ + dpc_sta[drv] = dpc_sta[drv] | STA_FLG; /* set status */ + break; /* done */ + } + if ((dpc_rarc != dpc_ucyl[drv]) || /* RAR cyl miscompare? */ + (dpc_rars >= DP_NUMSC)) { /* bad sector? */ + dpc_sta[drv] = dpc_sta[drv] | STA_AER; /* address error */ + break; + } + if (dpc_eoc) { /* end of cyl? */ + dpc_sta[drv] = dpc_sta[drv] | STA_EOC; /* set status */ + break; /* done */ + } + } + dpxb[dp_ptr++] = dpd_wval ? (uint16) dpd_obuf : 0; /* store word/fill */ + dpd_wval = 0; /* clr data valid */ + if (dp_ptr >= DP_NUMWD) { /* buffer full? */ + da = GETDA (dpc_rarc, dpc_rarh, dpc_rars); /* calc disk addr */ + dpc_rars = (dpc_rars + 1) % DP_NUMSC; /* incr sector */ + if (dpc_rars == 0) { /* wrap? */ + dpc_rarh = dpc_rarh ^ 1; /* incr head */ + dpc_eoc = ((dpc_rarh & 1) == 0); /* calc eoc */ + } + err = fseek (uptr->fileref, da * sizeof (int16), SEEK_SET); + if (err) /* error? */ + break; + fxwrite (dpxb, sizeof (int16), DP_NUMWD, uptr->fileref); + err = ferror (uptr->fileref); + if (err) /* error? */ + break; + dp_ptr = 0; /* next sector */ + } + if (dpd.command && dpd_xfer) /* dch on, xfer? */ + dpdio (&dpd_dib, ioENF, 0); /* set dch flg */ + + dpd.command = CLEAR; /* clr dch cmd */ + sim_activate (uptr, dpc_xtime); /* sched next word */ + return SCPE_OK; + + default: + return SCPE_IERR; + } /* end case fnc */ + +dpc_sta[drv] = dpc_sta[drv] | STA_ATN; /* set ATN */ + +dpc.command = CLEAR; /* clr cch cmd */ +dpcio (&dpc_dib, ioENF, 0); /* set cch flg */ + +dpc_busy = 0; /* ctlr is free */ +dpd_xfer = dpd_wval = 0; + +if (err != 0) { /* error? */ + perror ("DP I/O error"); + clearerr (uptr->fileref); + return SCPE_IOERR; + } +return SCPE_OK; +} + + +/* Reset routine */ + +t_stat dpc_reset (DEVICE *dptr) +{ +int32 drv; +DIB *dibptr = (DIB *) dptr->ctxt; /* DIB pointer */ + +hp_enbdis_pair (dptr, /* make pair cons */ + (dptr == &dpd_dev) ? &dpc_dev : &dpd_dev); + +if (sim_switches & SWMASK ('P')) { /* initialization reset? */ + dpd_ibuf = dpd_obuf = 0; /* clear buffers */ + dpc_obuf = 0; /* clear buffer */ + dpc_rarc = dpc_rarh = dpc_rars = 0; /* clear RAR */ + } + +IOPRESET (dibptr); /* PRESET device (does not use PON) */ + +dpc_busy = 0; /* reset controller state */ +dpc_poll = 0; +dpd_xfer = 0; +dpd_wval = 0; +dpc_eoc = 0; +dp_ptr = 0; + +sim_cancel (&dpd_unit); /* cancel dch */ + +for (drv = 0; drv < DP_NUMDRV; drv++) { /* loop thru drives */ + sim_cancel (&dpc_unit[drv]); /* cancel activity */ + dpc_unit[drv].FNC = 0; /* clear function */ + dpc_ucyl[drv] = 0; /* clear drive pos */ + if (dpc_unit[drv].flags & UNIT_ATT) + dpc_sta[drv] = dpc_sta[drv] & STA_1ST; /* first seek status */ + else dpc_sta[drv] = 0; /* clear status */ + } + +return SCPE_OK; +} + + +/* Attach routine */ + +t_stat dpc_attach (UNIT *uptr, char *cptr) +{ +t_stat r; + +r = attach_unit (uptr, cptr); /* attach unit */ +if (r == SCPE_OK) dpc_load_unload (uptr, 0, NULL, NULL);/* if OK, load heads */ +return r; +} + + +/* Detach routine */ + +t_stat dpc_detach (UNIT* uptr) +{ +dpc_load_unload (uptr, UNIT_UNLOAD, NULL, NULL); /* unload heads */ +return detach_unit (uptr); /* detach unit */ +} + + +/* Load and unload heads */ + +t_stat dpc_load_unload (UNIT *uptr, int32 value, char *cptr, void *desc) +{ +int32 drv; + +if ((uptr->flags & UNIT_ATT) == 0) return SCPE_UNATT; /* must be attached to load */ + +if (value == UNIT_UNLOAD) /* unload heads? */ + uptr->flags = uptr->flags | UNIT_UNLOAD; /* indicate unload */ +else { /* load heads */ + uptr->flags = uptr->flags & ~UNIT_UNLOAD; /* indicate load */ + drv = uptr - dpc_unit; /* get drive no */ + dpc_sta[drv] = dpc_sta[drv] | STA_ATN | STA_1ST; /* update status */ + if (dpc_poll) /* polling enabled? */ + dpcio (&dpc_dib, ioENF, 0); /* set flag */ + } +return SCPE_OK; +} + + +/* Set controller type */ + +t_stat dp_settype (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +int32 i; + +if ((val < 0) || (val > 1) || (cptr != NULL)) + return SCPE_ARG; + +for (i = 0; i < DP_NUMDRV; i++) { + if (dpc_unit[i].flags & UNIT_ATT) + return SCPE_ALATT; + } + +for (i = 0; i < DP_NUMDRV; i++) + dpc_unit[i].capac = (val? DP_SIZE3: DP_SIZE2); + +dp_ctype = (CNTLR_TYPE) val; +return SCPE_OK; +} + + +/* Show controller type */ + +t_stat dp_showtype (FILE *st, UNIT *uptr, int32 val, void *desc) +{ +if (dp_ctype == A13210) + fprintf (st, "13210A"); +else + fprintf (st, "12557A"); + +return SCPE_OK; +} + + +/* 7900/7901 bootstrap routine (HP 12992F ROM) */ + +const BOOT_ROM dp_rom = { + 0106710, /*ST CLC DC ; clr dch */ + 0106711, /* CLC CC ; clr cch */ + 0017757, /* JSB STAT ; get status */ + 0067746, /*SK LDB SKCMD ; seek cmd */ + 0106610, /* OTB DC ; cyl # */ + 0103710, /* STC DC,C ; to dch */ + 0106611, /* OTB CC ; seek cmd */ + 0103711, /* STC CC,C ; to cch */ + 0102310, /* SFS DC ; addr wd ok? */ + 0027710, /* JMP *-1 ; no, wait */ + 0006400, /* CLB */ + 0102501, /* LIA 1 ; read switches */ + 0002011, /* SLA,RSS ; <0> set? */ + 0047747, /* ADB BIT9 ; head 2 = removable */ + 0106610, /* OTB DC ; head/sector */ + 0103710, /* STC DC,C ; to dch */ + 0102311, /* SFS CC ; seek done? */ + 0027720, /* JMP *-1 ; no, wait */ + 0017757, /* JSB STAT ; get status */ + 0067776, /* LDB DMACW ; DMA control */ + 0106606, /* OTB 6 */ + 0067750, /* LDB ADDR1 ; memory addr */ + 0106602, /* OTB 2 */ + 0102702, /* STC 2 ; flip DMA ctrl */ + 0067752, /* LDB CNT ; word count */ + 0106602, /* OTB 2 */ + 0063745, /* LDB RDCMD ; read cmd */ + 0102611, /* OTA CC ; to cch */ + 0103710, /* STC DC,C ; start dch */ + 0103706, /* STC 6,C ; start DMA */ + 0103711, /* STC CC,C ; start cch */ + 0102311, /* SFS CC ; done? */ + 0027737, /* JMP *-1 ; no, wait */ + 0017757, /* JSB STAT ; get status */ + 0027775, /* JMP XT ; done */ + 0037766, /*FSMSK 037766 ; status mask */ + 0004000, /*STMSK 004000 ; unsafe mask */ + 0020000, /*RDCMD 020000 ; read cmd */ + 0030000, /*SKCMD 030000 ; seek cmd */ + 0001000, /*BIT9 001000 ; head 2 select */ + 0102011, /*ADDR1 102011 */ + 0102055, /*ADDR2 102055 */ + 0164000, /*CNT -6144. */ + 0, 0, 0, 0, /* unused */ + 0000000, /*STAT 0 */ + 0002400, /* CLA ; status request */ + 0102611, /* OTC CC ; to cch */ + 0103711, /* STC CC,C ; start cch */ + 0102310, /* SFS DC ; done? */ + 0027763, /* JMP *-1 */ + 0102510, /* LIA DC ; get status */ + 0013743, /* AND FSMSK ; mask 15,14,3,0 */ + 0002003, /* SZA,RSS ; drive ready? */ + 0127757, /* JMP STAT,I ; yes */ + 0013744, /* AND STMSK ; fault? */ + 0002002, /* SZA */ + 0102030, /* HLT 30 ; yes */ + 0027700, /* JMP ST ; no, retry */ + 0117751, /*XT JSB ADDR2,I ; start program */ + 0120010, /*DMACW 120000+DC */ + 0000000 /* -ST */ + }; + +t_stat dpc_boot (int32 unitno, DEVICE *dptr) +{ +const int32 dev = dpd_dib.select_code; /* data chan select code */ + +if (unitno != 0) /* boot supported on drive unit 0 only */ + return SCPE_NOFNC; /* report "Command not allowed" if attempted */ + +if (ibl_copy (dp_rom, dev, IBL_OPT, /* copy the boot ROM to memory and configure */ + IBL_DP | IBL_SET_SC (dev) /* the S register accordingly */ + | (sim_switches & SWMASK ('R') ? IBL_DP_REM : 0))) + return SCPE_IERR; /* return an internal error if the copy failed */ +else + return SCPE_OK; +} diff --git a/HP2100/hp2100_dq.c b/HP2100/hp2100_dq.c index 06c92b2b..fe1cc44a 100644 --- a/HP2100/hp2100_dq.c +++ b/HP2100/hp2100_dq.c @@ -1,962 +1,977 @@ -/* hp2100_dq.c: HP 2100 12565A disk simulator - - Copyright (c) 1993-2006, Bill McDermith - Copyright (c) 2004-2012 J. David Bryan - - 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 - ROBERT M SUPNIK 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 names of the authors shall not be - used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from the authors. - - DQ 12565A 2883 disk system - - 10-Feb-12 JDB Deprecated DEVNO in favor of SC - 28-Mar-11 JDB Tidied up signal handling - 26-Oct-10 JDB Changed I/O signal handler for revised signal model - 10-Aug-08 JDB Added REG_FIT to register variables < 32-bit size - 26-Jun-08 JDB Rewrote device I/O to model backplane signals - 28-Dec-06 JDB Added ioCRS state to I/O decoders - 01-Mar-05 JDB Added SET UNLOAD/LOAD - 07-Oct-04 JDB Fixed enable/disable from either device - Shortened xtime from 5 to 3 (drive avg 156KW/second) - Fixed not ready/any error status - Fixed RAR model - 21-Apr-04 RMS Fixed typo in boot loader (found by Dave Bryan) - 26-Apr-04 RMS Fixed SFS x,C and SFC x,C - Fixed SR setting in IBL - Revised IBL loader - Implemented DMA SRQ (follows FLG) - 25-Apr-03 RMS Fixed bug in status check - 10-Nov-02 RMS Added boot command, rebuilt like 12559/13210 - 09-Jan-02 WOM Copied dp driver and mods for 2883 - - Reference: - - 12565A Disc Interface Kit Operating and Service Manual (12565-90003, Aug-1973) - - - Differences between 12559/13210 and 12565 controllers - - 12565 stops transfers on address miscompares; 12559/13210 only stops writes - - 12565 does not set error on positioner busy - - 12565 does not set positioner busy if already on cylinder - - 12565 does not need eoc logic, it will hit an invalid head number - - The controller's "Record Address Register" (RAR) contains the CHS address of - the last Position or Load Address command executed. The RAR is shared among - all drives on the controller. In addition, each drive has an internal - position register that contains the last cylinder and head position - transferred to the drive during Position command execution (sector operations - always start with the RAR sector position). - - In a real drive, the address field of the sector under the head is read and - compared to the RAR. When they match, the target sector is under the head - and is ready for reading or writing. If a match doesn't occur, an Address - Error is indicated. In the simulator, the address field is obtained from the - drive's current position register during a read, i.e., the "on-disc" address - field is assumed to match the current position. - - The following implemented behaviors have been inferred from secondary sources - (diagnostics, operating system drivers, etc.), due to absent or contradictory - authoritative information; future correction may be needed: - - 1. Read Address command starts at the sector number in the RAR. -*/ - -#include "hp2100_defs.h" - -#define UNIT_V_WLK (UNIT_V_UF + 0) /* write locked */ -#define UNIT_V_UNLOAD (UNIT_V_UF + 1) /* heads unloaded */ -#define UNIT_WLK (1 << UNIT_V_WLK) -#define UNIT_UNLOAD (1 << UNIT_V_UNLOAD) -#define FNC u3 /* saved function */ -#define DRV u4 /* drive number (DC) */ -#define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write prot */ - -#define DQ_N_NUMWD 7 -#define DQ_NUMWD (1 << DQ_N_NUMWD) /* words/sector */ -#define DQ_NUMSC 23 /* sectors/track */ -#define DQ_NUMSF 20 /* tracks/cylinder */ -#define DQ_NUMCY 203 /* cylinders/disk */ -#define DQ_SIZE (DQ_NUMSF * DQ_NUMCY * DQ_NUMSC * DQ_NUMWD) -#define DQ_NUMDRV 2 /* # drives */ - -/* Command word */ - -#define CW_V_FNC 12 /* function */ -#define CW_M_FNC 017 -#define CW_GETFNC(x) (((x) >> CW_V_FNC) & CW_M_FNC) -/* 000 /* unused */ -#define FNC_STA 001 /* status check */ -#define FNC_RCL 002 /* recalibrate */ -#define FNC_SEEK 003 /* seek */ -#define FNC_RD 004 /* read */ -#define FNC_WD 005 /* write */ -#define FNC_RA 006 /* read address */ -#define FNC_WA 007 /* write address */ -#define FNC_CHK 010 /* check */ -#define FNC_LA 013 /* load address */ -#define FNC_AS 014 /* address skip */ - -#define FNC_SEEK1 020 /* fake - seek1 */ -#define FNC_SEEK2 021 /* fake - seek2 */ -#define FNC_SEEK3 022 /* fake - seek3 */ -#define FNC_CHK1 023 /* fake - check1 */ -#define FNC_LA1 024 /* fake - ldaddr1 */ - -#define CW_V_DRV 0 /* drive */ -#define CW_M_DRV 01 -#define CW_GETDRV(x) (((x) >> CW_V_DRV) & CW_M_DRV) - -/* Disk address words */ - -#define DA_V_CYL 0 /* cylinder */ -#define DA_M_CYL 0377 -#define DA_GETCYL(x) (((x) >> DA_V_CYL) & DA_M_CYL) -#define DA_V_HD 8 /* head */ -#define DA_M_HD 037 -#define DA_GETHD(x) (((x) >> DA_V_HD) & DA_M_HD) -#define DA_V_SC 0 /* sector */ -#define DA_M_SC 037 -#define DA_GETSC(x) (((x) >> DA_V_SC) & DA_M_SC) -#define DA_CKMASK 0777 /* check mask */ - -/* Status in dqc_sta[drv] - (d) = dynamic */ - -#define STA_DID 0000200 /* drive ID (d) */ -#define STA_NRDY 0000100 /* not ready (d) */ -#define STA_EOC 0000040 /* end of cylinder */ -#define STA_AER 0000020 /* addr error */ -#define STA_FLG 0000010 /* flagged */ -#define STA_BSY 0000004 /* seeking */ -#define STA_DTE 0000002 /* data error */ -#define STA_ERR 0000001 /* any error */ -#define STA_ANYERR (STA_NRDY | STA_EOC | STA_AER | STA_FLG | STA_DTE) - -struct { - FLIP_FLOP command; /* cch command flip-flop */ - FLIP_FLOP control; /* cch control flip-flop */ - FLIP_FLOP flag; /* cch flag flip-flop */ - FLIP_FLOP flagbuf; /* cch flag buffer flip-flop */ - } dqc = { CLEAR, CLEAR, CLEAR, CLEAR }; - -int32 dqc_busy = 0; /* cch xfer */ -int32 dqc_cnt = 0; /* check count */ -int32 dqc_stime = 100; /* seek time */ -int32 dqc_ctime = 100; /* command time */ -int32 dqc_xtime = 3; /* xfer time */ -int32 dqc_dtime = 2; /* dch time */ - -struct { - FLIP_FLOP command; /* dch command flip-flop */ - FLIP_FLOP control; /* dch control flip-flop */ - FLIP_FLOP flag; /* dch flag flip-flop */ - FLIP_FLOP flagbuf; /* dch flag buffer flip-flop */ - } dqd = { CLEAR, CLEAR, CLEAR, CLEAR }; - -int32 dqd_obuf = 0, dqd_ibuf = 0; /* dch buffers */ -int32 dqc_obuf = 0; /* cch buffers */ -int32 dqd_xfer = 0; /* xfer in prog */ -int32 dqd_wval = 0; /* write data valid */ -int32 dq_ptr = 0; /* buffer ptr */ -uint8 dqc_rarc = 0; /* RAR cylinder */ -uint8 dqc_rarh = 0; /* RAR head */ -uint8 dqc_rars = 0; /* RAR sector */ -uint8 dqc_ucyl[DQ_NUMDRV] = { 0 }; /* unit cylinder */ -uint8 dqc_uhed[DQ_NUMDRV] = { 0 }; /* unit head */ -uint16 dqc_sta[DQ_NUMDRV] = { 0 }; /* unit status */ -uint16 dqxb[DQ_NUMWD]; /* sector buffer */ - -DEVICE dqd_dev, dqc_dev; - -IOHANDLER dqdio; -IOHANDLER dqcio; - -t_stat dqc_svc (UNIT *uptr); -t_stat dqd_svc (UNIT *uptr); -t_stat dqc_reset (DEVICE *dptr); -t_stat dqc_attach (UNIT *uptr, char *cptr); -t_stat dqc_detach (UNIT* uptr); -t_stat dqc_load_unload (UNIT *uptr, int32 value, char *cptr, void *desc); -t_stat dqc_boot (int32 unitno, DEVICE *dptr); -void dq_god (int32 fnc, int32 drv, int32 time); -void dq_goc (int32 fnc, int32 drv, int32 time); - -/* DQD data structures - - dqd_dev DQD device descriptor - dqd_unit DQD unit list - dqd_reg DQD register list -*/ - -DIB dq_dib[] = { - { &dqdio, DQD }, - { &dqcio, DQC } - }; - -#define dqd_dib dq_dib[0] -#define dqc_dib dq_dib[1] - -UNIT dqd_unit = { UDATA (&dqd_svc, 0, 0) }; - -REG dqd_reg[] = { - { ORDATA (IBUF, dqd_ibuf, 16) }, - { ORDATA (OBUF, dqd_obuf, 16) }, - { BRDATA (DBUF, dqxb, 8, 16, DQ_NUMWD) }, - { DRDATA (BPTR, dq_ptr, DQ_N_NUMWD) }, - { FLDATA (CMD, dqd.command, 0) }, - { FLDATA (CTL, dqd.control, 0) }, - { FLDATA (FLG, dqd.flag, 0) }, - { FLDATA (FBF, dqd.flagbuf, 0) }, - { FLDATA (XFER, dqd_xfer, 0) }, - { FLDATA (WVAL, dqd_wval, 0) }, - { ORDATA (SC, dqd_dib.select_code, 6), REG_HRO }, - { ORDATA (DEVNO, dqd_dib.select_code, 6), REG_HRO }, - { NULL } - }; - -MTAB dqd_mod[] = { - { MTAB_XTD | MTAB_VDV, 1, "SC", "SC", &hp_setsc, &hp_showsc, &dqd_dev }, - { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &dqd_dev }, - { 0 } - }; - -DEVICE dqd_dev = { - "DQD", &dqd_unit, dqd_reg, dqd_mod, - 1, 10, DQ_N_NUMWD, 1, 8, 16, - NULL, NULL, &dqc_reset, - NULL, NULL, NULL, - &dqd_dib, DEV_DISABLE - }; - -/* DQC data structures - - dqc_dev DQC device descriptor - dqc_unit DQC unit list - dqc_reg DQC register list - dqc_mod DQC modifier list -*/ - -UNIT dqc_unit[] = { - { UDATA (&dqc_svc, UNIT_FIX | UNIT_ATTABLE | UNIT_ROABLE | - UNIT_DISABLE | UNIT_UNLOAD, DQ_SIZE) }, - { UDATA (&dqc_svc, UNIT_FIX | UNIT_ATTABLE | UNIT_ROABLE | - UNIT_DISABLE | UNIT_UNLOAD, DQ_SIZE) } - }; - -REG dqc_reg[] = { - { ORDATA (OBUF, dqc_obuf, 16) }, - { ORDATA (BUSY, dqc_busy, 2), REG_RO }, - { ORDATA (CNT, dqc_cnt, 9) }, - { FLDATA (CMD, dqc.command, 0) }, - { FLDATA (CTL, dqc.control, 0) }, - { FLDATA (FLG, dqc.flag, 0) }, - { FLDATA (FBF, dqc.flagbuf, 0) }, - { DRDATA (RARC, dqc_rarc, 8), PV_RZRO | REG_FIT }, - { DRDATA (RARH, dqc_rarh, 5), PV_RZRO | REG_FIT }, - { DRDATA (RARS, dqc_rars, 5), PV_RZRO | REG_FIT }, - { BRDATA (CYL, dqc_ucyl, 10, 8, DQ_NUMDRV), PV_RZRO }, - { BRDATA (HED, dqc_uhed, 10, 5, DQ_NUMDRV), PV_RZRO }, - { BRDATA (STA, dqc_sta, 8, 16, DQ_NUMDRV) }, - { DRDATA (CTIME, dqc_ctime, 24), PV_LEFT }, - { DRDATA (DTIME, dqc_dtime, 24), PV_LEFT }, - { DRDATA (STIME, dqc_stime, 24), PV_LEFT }, - { DRDATA (XTIME, dqc_xtime, 24), REG_NZ + PV_LEFT }, - { URDATA (UFNC, dqc_unit[0].FNC, 8, 8, 0, - DQ_NUMDRV, REG_HRO) }, - { ORDATA (SC, dqc_dib.select_code, 6), REG_HRO }, - { ORDATA (DEVNO, dqc_dib.select_code, 6), REG_HRO }, - { NULL } - }; - -MTAB dqc_mod[] = { - { UNIT_UNLOAD, UNIT_UNLOAD, "heads unloaded", "UNLOADED", dqc_load_unload }, - { UNIT_UNLOAD, 0, "heads loaded", "LOADED", dqc_load_unload }, - { UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL }, - { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL }, - { MTAB_XTD | MTAB_VDV, 1, "SC", "SC", &hp_setsc, &hp_showsc, &dqd_dev }, - { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &dqd_dev }, - { 0 } - }; - -DEVICE dqc_dev = { - "DQC", dqc_unit, dqc_reg, dqc_mod, - DQ_NUMDRV, 8, 24, 1, 8, 16, - NULL, NULL, &dqc_reset, - &dqc_boot, &dqc_attach, &dqc_detach, - &dqc_dib, DEV_DISABLE - }; - - -/* Data channel I/O signal handler */ - -uint32 dqdio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) -{ -IOSIGNAL signal; -IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ - -while (working_set) { - signal = IONEXT (working_set); /* isolate next signal */ - - switch (signal) { /* dispatch I/O signal */ - - case ioCLF: /* clear flag flip-flop */ - dqd.flag = dqd.flagbuf = CLEAR; - break; - - - case ioSTF: /* set flag flip-flop */ - case ioENF: /* enable flag */ - dqd.flag = dqd.flagbuf = SET; - break; - - - case ioSFC: /* skip if flag is clear */ - setstdSKF (dqd); - break; - - - case ioSFS: /* skip if flag is set */ - setstdSKF (dqd); - break; - - - case ioIOI: /* I/O data input */ - stat_data = IORETURN (SCPE_OK, dqd_ibuf); /* merge in return status */ - break; - - - case ioIOO: /* I/O data output */ - dqd_obuf = IODATA (stat_data); /* clear supplied status */ - - if (!dqc_busy || dqd_xfer) - dqd_wval = 1; /* if !overrun, valid */ - break; - - - case ioPOPIO: /* power-on preset to I/O */ - dqd.flag = dqd.flagbuf = SET; /* set flag and flag buffer */ - dqd_obuf = 0; /* clear output buffer */ - break; - - - case ioCRS: /* control reset */ - dqd.command = CLEAR; /* clear command */ - /* fall into CLC handler */ - - case ioCLC: /* clear control flip-flop */ - dqd.control = CLEAR; /* clear control */ - dqd_xfer = 0; /* clr xfer */ - break; - - - case ioSTC: /* set control flip-flop */ - dqd.command = SET; /* set ctl, cmd */ - dqd.control = SET; - - if (dqc_busy && !dqd_xfer) /* overrun? */ - dqc_sta[dqc_busy - 1] |= STA_DTE; - break; - - - case ioSIR: /* set interrupt request */ - setstdPRL (dqd); /* set standard PRL signal */ - setstdIRQ (dqd); /* set standard IRQ signal */ - setstdSRQ (dqd); /* set standard SRQ signal */ - break; - - - case ioIAK: /* interrupt acknowledge */ - dqd.flagbuf = CLEAR; - break; - - - default: /* all other signals */ - break; /* are ignored */ - } - - working_set = working_set & ~signal; /* remove current signal from set */ - } - -return stat_data; -} - - -/* Command channel I/O signal handler. - - Implementation notes: - - 1. The input buffer register is not connected to the disc controller. - Pullups on the card and an inversion result in reading zeros when IOI is - signalled. -*/ - -uint32 dqcio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) -{ -int32 fnc, drv; -IOSIGNAL signal; -IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ - -while (working_set) { - signal = IONEXT (working_set); /* isolate next signal */ - - switch (signal) { /* dispatch I/O signal */ - - case ioCLF: /* clear flag flip-flop */ - dqc.flag = dqc.flagbuf = CLEAR; - break; - - - case ioSTF: /* set flag flip-flop */ - case ioENF: /* enable flag */ - dqc.flag = dqc.flagbuf = SET; - break; - - - case ioSFC: /* skip if flag is clear */ - setstdSKF (dqc); - break; - - - case ioSFS: /* skip if flag is set */ - setstdSKF (dqc); - break; - - - case ioIOI: /* I/O data input */ - stat_data = IORETURN (SCPE_OK, 0); /* no data */ - break; - - - case ioIOO: /* I/O data output */ - dqc_obuf = IODATA (stat_data); /* clear supplied status */ - break; - - - case ioPOPIO: /* power-on preset to I/O */ - dqc.flag = dqc.flagbuf = SET; /* set flag and flag buffer */ - dqc_obuf = 0; /* clear output buffer */ - break; - - - case ioCRS: /* control reset */ - case ioCLC: /* clear control flip-flop */ - dqc.command = CLEAR; /* clear command */ - dqc.control = CLEAR; /* clear control */ - - if (dqc_busy) - sim_cancel (&dqc_unit[dqc_busy - 1]); - - sim_cancel (&dqd_unit); /* cancel dch */ - dqd_xfer = 0; /* clr dch xfer */ - dqc_busy = 0; /* clr busy */ - break; - - - case ioSTC: /* set control flip-flop */ - dqc.control = SET; /* set ctl */ - - if (!dqc.command) { /* cmd clr? */ - dqc.command = SET; /* set cmd */ - drv = CW_GETDRV (dqc_obuf); /* get fnc, drv */ - fnc = CW_GETFNC (dqc_obuf); /* from cmd word */ - - switch (fnc) { /* case on fnc */ - case FNC_SEEK: case FNC_RCL: /* seek, recal */ - case FNC_CHK: /* check */ - dqc_sta[drv] = 0; /* clear status */ - case FNC_STA: case FNC_LA: /* rd sta, load addr */ - dq_god (fnc, drv, dqc_dtime); /* sched dch xfer */ - break; - case FNC_RD: case FNC_WD: /* read, write */ - case FNC_RA: case FNC_WA: /* rd addr, wr addr */ - case FNC_AS: /* address skip */ - dq_goc (fnc, drv, dqc_ctime); /* sched drive */ - break; - } /* end case */ - } /* end if !CMD */ - break; - - - case ioSIR: /* set interrupt request */ - setstdPRL (dqc); /* set standard PRL signal */ - setstdIRQ (dqc); /* set standard IRQ signal */ - setstdSRQ (dqc); /* set standard SRQ signal */ - break; - - - case ioIAK: /* interrupt acknowledge */ - dqc.flagbuf = CLEAR; - break; - - - default: /* all other signals */ - break; /* are ignored */ - } - - working_set = working_set & ~signal; /* remove current signal from set */ - } -return stat_data; -} - - -/* Start data channel operation */ - -void dq_god (int32 fnc, int32 drv, int32 time) -{ -dqd_unit.DRV = drv; /* save unit */ -dqd_unit.FNC = fnc; /* save function */ -sim_activate (&dqd_unit, time); -return; -} - -/* Start controller operation */ - -void dq_goc (int32 fnc, int32 drv, int32 time) -{ -int32 t; - -if (t = sim_is_active (&dqc_unit[drv])) { /* still seeking? */ - sim_cancel (&dqc_unit[drv]); /* cancel */ - time = time + t; /* include seek time */ - } -dqc_sta[drv] = 0; /* clear status */ -dq_ptr = 0; /* init buf ptr */ -dqc_busy = drv + 1; /* set busy */ -dqd_xfer = 1; /* xfer in prog */ -dqc_unit[drv].FNC = fnc; /* save function */ -sim_activate (&dqc_unit[drv], time); /* activate unit */ -return; -} - -/* Data channel unit service - - This routine handles the data channel transfers. It also handles - data transfers that are blocked by seek in progress. - - uptr->DRV = target drive - uptr->FNC = target function - - Seek substates - seek - transfer cylinder - seek1 - transfer head/surface, sched drive - Recalibrate substates - rcl - clear cyl/head/surface, sched drive - Load address - la - transfer cylinder - la1 - transfer head/surface, finish operation - Status check - transfer status, finish operation - Check data - chk - transfer sector count, sched drive -*/ - -t_stat dqd_svc (UNIT *uptr) -{ -int32 drv, st; - -drv = uptr->DRV; /* get drive no */ - -switch (uptr->FNC) { /* case function */ - - case FNC_LA: /* arec, need cyl */ - case FNC_SEEK: /* seek, need cyl */ - if (dqd.command) { /* dch active? */ - dqc_rarc = DA_GETCYL (dqd_obuf); /* set RAR from cyl word */ - dqd_wval = 0; /* clr data valid */ - dqd.command = CLEAR; /* clr dch cmd */ - dqdio (&dqd_dib, ioENF, 0); /* set dch flg */ - if (uptr->FNC == FNC_LA) uptr->FNC = FNC_LA1; - else uptr->FNC = FNC_SEEK1; /* advance state */ - } - sim_activate (uptr, dqc_xtime); /* no, wait more */ - break; - - case FNC_LA1: /* arec, need hd/sec */ - case FNC_SEEK1: /* seek, need hd/sec */ - if (dqd.command) { /* dch active? */ - dqc_rarh = DA_GETHD (dqd_obuf); /* set RAR from head */ - dqc_rars = DA_GETSC (dqd_obuf); /* set RAR from sector */ - dqd_wval = 0; /* clr data valid */ - dqd.command = CLEAR; /* clr dch cmd */ - dqdio (&dqd_dib, ioENF, 0); /* set dch flg */ - if (uptr->FNC == FNC_LA1) { - dqc.command = CLEAR; /* clr cch cmd */ - dqcio (&dqc_dib, ioENF, 0); /* set cch flg */ - break; /* done if Load Address */ - } - if (sim_is_active (&dqc_unit[drv])) break; /* if busy, seek check */ - st = abs (dqc_rarc - dqc_ucyl[drv]) * dqc_stime; - if (st == 0) st = dqc_xtime; /* if on cyl, min time */ - else dqc_sta[drv] = dqc_sta[drv] | STA_BSY; /* set busy */ - dqc_ucyl[drv] = dqc_rarc; /* transfer RAR */ - dqc_uhed[drv] = dqc_rarh; - sim_activate (&dqc_unit[drv], st); /* schedule op */ - dqc_unit[drv].FNC = FNC_SEEK2; /* advance state */ - } - else sim_activate (uptr, dqc_xtime); /* no, wait more */ - break; - - case FNC_RCL: /* recalibrate */ - dqc_rarc = dqc_rarh = dqc_rars = 0; /* clear RAR */ - if (sim_is_active (&dqc_unit[drv])) break; /* ignore if busy */ - st = dqc_ucyl[drv] * dqc_stime; /* calc diff */ - if (st == 0) st = dqc_xtime; /* if on cyl, min time */ - else dqc_sta[drv] = dqc_sta[drv] | STA_BSY; /* set busy */ - sim_activate (&dqc_unit[drv], st); /* schedule drive */ - dqc_ucyl[drv] = dqc_uhed[drv] = 0; /* clear drive pos */ - dqc_unit[drv].FNC = FNC_SEEK2; /* advance state */ - break; - - case FNC_STA: /* read status */ - if (dqd.command) { /* dch active? */ - if ((dqc_unit[drv].flags & UNIT_UNLOAD) == 0) /* drive up? */ - dqd_ibuf = dqc_sta[drv] & ~STA_DID; - else dqd_ibuf = STA_NRDY; - if (dqd_ibuf & STA_ANYERR) /* errors? set flg */ - dqd_ibuf = dqd_ibuf | STA_ERR; - if (drv) dqd_ibuf = dqd_ibuf | STA_DID; - dqc.command = CLEAR; /* clr cch cmd */ - dqd.command = CLEAR; /* clr dch cmd */ - dqdio (&dqd_dib, ioENF, 0); /* set dch flg */ - dqc_sta[drv] = dqc_sta[drv] & ~STA_ANYERR; /* clr sta flags */ - } - else sim_activate (uptr, dqc_xtime); /* wait more */ - break; - - case FNC_CHK: /* check, need cnt */ - if (dqd.command) { /* dch active? */ - dqc_cnt = dqd_obuf & DA_CKMASK; /* get count */ - dqd_wval = 0; /* clr data valid */ - dq_goc (FNC_CHK1, drv, dqc_ctime); /* sched drv */ - } - else sim_activate (uptr, dqc_xtime); /* wait more */ - break; - - default: - return SCPE_IERR; - } - -return SCPE_OK; -} - -/* Drive unit service - - This routine handles the data transfers. - - Seek substates - seek2 - done - Recalibrate substate - rcl1 - done - Check data substates - chk1 - finish operation - Read - Read address - Address skip (read without header check) - Write - Write address -*/ - -#define GETDA(x,y,z) \ - (((((x) * DQ_NUMSF) + (y)) * DQ_NUMSC) + (z)) * DQ_NUMWD - -t_stat dqc_svc (UNIT *uptr) -{ -int32 da, drv, err; - -err = 0; /* assume no err */ -drv = uptr - dqc_unit; /* get drive no */ -if (uptr->flags & UNIT_UNLOAD) { /* drive down? */ - dqc.command = CLEAR; /* clr cch cmd */ - dqcio (&dqc_dib, ioENF, 0); /* set cch flg */ - dqc_sta[drv] = 0; /* clr status */ - dqc_busy = 0; /* ctlr is free */ - dqd_xfer = dqd_wval = 0; - return SCPE_OK; - } -switch (uptr->FNC) { /* case function */ - - case FNC_SEEK2: /* seek done */ - if (dqc_ucyl[drv] >= DQ_NUMCY) { /* out of range? */ - dqc_sta[drv] = dqc_sta[drv] | STA_BSY | STA_ERR; /* seek check */ - dqc_ucyl[drv] = 0; /* seek to cyl 0 */ - } - else dqc_sta[drv] = dqc_sta[drv] & ~STA_BSY; /* drive not busy */ - case FNC_SEEK3: - if (dqc_busy || dqc.flag) { /* ctrl busy? */ - uptr->FNC = FNC_SEEK3; /* next state */ - sim_activate (uptr, dqc_xtime); /* ctrl busy? wait */ - } - else { - dqc.command = CLEAR; /* clr cch cmd */ - dqcio (&dqc_dib, ioENF, 0); /* set cch flg */ - } - return SCPE_OK; - - case FNC_RA: /* read addr */ - if (!dqd.command) break; /* dch clr? done */ - if (dq_ptr == 0) dqd_ibuf = dqc_ucyl[drv]; /* 1st word? */ - else if (dq_ptr == 1) { /* second word? */ - dqd_ibuf = (dqc_uhed[drv] << DA_V_HD) | /* use drive head */ - (dqc_rars << DA_V_SC); /* and RAR sector */ - dqc_rars = (dqc_rars + 1) % DQ_NUMSC; /* incr sector */ - } - else break; - dq_ptr = dq_ptr + 1; - dqd.command = CLEAR; /* clr dch cmd */ - dqdio (&dqd_dib, ioENF, 0); /* set dch flg */ - sim_activate (uptr, dqc_xtime); /* sched next word */ - return SCPE_OK; - - case FNC_AS: /* address skip */ - case FNC_RD: /* read */ - case FNC_CHK1: /* check */ - if (dq_ptr == 0) { /* new sector? */ - if (!dqd.command && (uptr->FNC != FNC_CHK1)) break; - if ((dqc_rarc != dqc_ucyl[drv]) || /* RAR cyl miscompare? */ - (dqc_rarh != dqc_uhed[drv]) || /* RAR head miscompare? */ - (dqc_rars >= DQ_NUMSC)) { /* bad sector? */ - dqc_sta[drv] = dqc_sta[drv] | STA_AER; /* no record found err */ - break; - } - if (dqc_rarh >= DQ_NUMSF) { /* bad head? */ - dqc_sta[drv] = dqc_sta[drv] | STA_EOC; /* end of cyl err */ - break; - } - da = GETDA (dqc_rarc, dqc_rarh, dqc_rars); /* calc disk addr */ - dqc_rars = (dqc_rars + 1) % DQ_NUMSC; /* incr sector */ - if (dqc_rars == 0) /* wrap? incr head */ - dqc_uhed[drv] = dqc_rarh = dqc_rarh + 1; - if (err = fseek (uptr->fileref, da * sizeof (int16), - SEEK_SET)) break; - fxread (dqxb, sizeof (int16), DQ_NUMWD, uptr->fileref); - if (err = ferror (uptr->fileref)) break; - } - dqd_ibuf = dqxb[dq_ptr++]; /* get word */ - if (dq_ptr >= DQ_NUMWD) { /* end of sector? */ - if (uptr->FNC == FNC_CHK1) { /* check? */ - dqc_cnt = (dqc_cnt - 1) & DA_CKMASK; /* decr count */ - if (dqc_cnt == 0) break; /* if zero, done */ - } - dq_ptr = 0; /* wrap buf ptr */ - } - if (dqd.command && dqd_xfer) { /* dch on, xfer? */ - dqdio (&dqd_dib, ioENF, 0); /* set flag */ - } - dqd.command = CLEAR; /* clr dch cmd */ - sim_activate (uptr, dqc_xtime); /* sched next word */ - return SCPE_OK; - - case FNC_WA: /* write address */ - case FNC_WD: /* write */ - if (dq_ptr == 0) { /* sector start? */ - if (!dqd.command && !dqd_wval) break; /* xfer done? */ - if (uptr->flags & UNIT_WPRT) { /* write protect? */ - dqc_sta[drv] = dqc_sta[drv] | STA_FLG; - break; /* done */ - } - if ((dqc_rarc != dqc_ucyl[drv]) || /* RAR cyl miscompare? */ - (dqc_rarh != dqc_uhed[drv]) || /* RAR head miscompare? */ - (dqc_rars >= DQ_NUMSC)) { /* bad sector? */ - dqc_sta[drv] = dqc_sta[drv] | STA_AER; /* no record found err */ - break; - } - if (dqc_rarh >= DQ_NUMSF) { /* bad head? */ - dqc_sta[drv] = dqc_sta[drv] | STA_EOC; /* end of cyl err */ - break; - } - } - dqxb[dq_ptr++] = dqd_wval? dqd_obuf: 0; /* store word/fill */ - dqd_wval = 0; /* clr data valid */ - if (dq_ptr >= DQ_NUMWD) { /* buffer full? */ - da = GETDA (dqc_rarc, dqc_rarh, dqc_rars); /* calc disk addr */ - dqc_rars = (dqc_rars + 1) % DQ_NUMSC; /* incr sector */ - if (dqc_rars == 0) /* wrap? incr head */ - dqc_uhed[drv] = dqc_rarh = dqc_rarh + 1; - if (err = fseek (uptr->fileref, da * sizeof (int16), - SEEK_SET)) return TRUE; - fxwrite (dqxb, sizeof (int16), DQ_NUMWD, uptr->fileref); - if (err = ferror (uptr->fileref)) break; - dq_ptr = 0; - } - if (dqd.command && dqd_xfer) { /* dch on, xfer? */ - dqdio (&dqd_dib, ioENF, 0); /* set flag */ - } - dqd.command = CLEAR; /* clr dch cmd */ - sim_activate (uptr, dqc_xtime); /* sched next word */ - return SCPE_OK; - - default: - return SCPE_IERR; - } /* end case fnc */ - -dqc.command = CLEAR; /* clr cch cmd */ -dqcio (&dqc_dib, ioENF, 0); /* set cch flg */ -dqc_busy = 0; /* ctlr is free */ -dqd_xfer = dqd_wval = 0; -if (err != 0) { /* error? */ - perror ("DQ I/O error"); - clearerr (uptr->fileref); - return SCPE_IOERR; - } -return SCPE_OK; -} - -/* Reset routine */ - -t_stat dqc_reset (DEVICE *dptr) -{ -int32 drv; -DIB *dibptr = (DIB *) dptr->ctxt; /* DIB pointer */ - -hp_enbdis_pair (dptr, /* make pair cons */ - (dptr == &dqd_dev)? &dqc_dev: &dqd_dev); - -if (sim_switches & SWMASK ('P')) { /* initialization reset? */ - dqd_ibuf = 0; /* clear buffers */ - dqd_obuf = 0; - dqc_obuf = 0; /* clear buffer */ - dqc_rarc = dqc_rarh = dqc_rars = 0; /* clear RAR */ - } - -IOPRESET (dibptr); /* PRESET device (does not use PON) */ - -dqc_busy = 0; /* reset controller state */ -dqd_xfer = 0; -dqd_wval = 0; -dq_ptr = 0; - -sim_cancel (&dqd_unit); /* cancel dch */ - -for (drv = 0; drv < DQ_NUMDRV; drv++) { /* loop thru drives */ - sim_cancel (&dqc_unit[drv]); /* cancel activity */ - dqc_unit[drv].FNC = 0; /* clear function */ - dqc_ucyl[drv] = dqc_uhed[drv] = 0; /* clear drive pos */ - dqc_sta[drv] = 0; /* clear status */ - } - -return SCPE_OK; -} - -/* Attach routine */ - -t_stat dqc_attach (UNIT *uptr, char *cptr) -{ -t_stat r; - -r = attach_unit (uptr, cptr); /* attach unit */ -if (r == SCPE_OK) dqc_load_unload (uptr, 0, NULL, NULL);/* if OK, load heads */ -return r; -} - -/* Detach routine */ - -t_stat dqc_detach (UNIT* uptr) -{ -dqc_load_unload (uptr, UNIT_UNLOAD, NULL, NULL); /* unload heads */ -return detach_unit (uptr); /* detach unit */ -} - -/* Load and unload heads */ - -t_stat dqc_load_unload (UNIT *uptr, int32 value, char *cptr, void *desc) -{ -if ((uptr->flags & UNIT_ATT) == 0) return SCPE_UNATT; /* must be attached to load */ -if (value == UNIT_UNLOAD) /* unload heads? */ - uptr->flags = uptr->flags | UNIT_UNLOAD; /* indicate unload */ -else uptr->flags = uptr->flags & ~UNIT_UNLOAD; /* indicate load */ -return SCPE_OK; -} - -/* 7900/7901/2883/2884 bootstrap routine (HP 12992A ROM) */ - -const BOOT_ROM dq_rom = { - 0102501, /*ST LIA 1 ; get switches */ - 0106501, /* LIB 1 */ - 0013765, /* AND D7 ; isolate hd */ - 0005750, /* BLF,CLE,SLB */ - 0027741, /* JMP RD */ - 0005335, /* RBR,SLB,ERB ; <13>->E, set = 2883 */ - 0027717, /* JMP IS */ - 0102611, /*LP OTA CC ; do 7900 status to */ - 0103711, /* STC CC,C ; clear first seek */ - 0102310, /* SFS DC */ - 0027711, /* JMP *-1 */ - 0002004, /* INA ; get next drive */ - 0053765, /* CPA D7 ; all cleared? */ - 0002001, /* RSS */ - 0027707, /* JMP LP */ - 0067761, /*IS LDB SEEKC ; get seek comnd */ - 0106610, /* OTB DC ; issue cyl addr (0) */ - 0103710, /* STC DC,C ; to dch */ - 0106611, /* OTB CC ; seek cmd */ - 0103711, /* STC CC,C ; to cch */ - 0102310, /* SFS DC ; addr wd ok? */ - 0027724, /* JMP *-1 ; no, wait */ - 0006400, /* CLB */ - 0102501, /* LIA 1 ; get switches */ - 0002051, /* SEZ,SLA,RSS ; subchan = 1 or ISS */ - 0047770, /* ADB BIT9 ; head 2 */ - 0106610, /* OTB DC ; head/sector */ - 0103710, /* STC DC,C ; to dch */ - 0102311, /* SFS CC ; seek done? */ - 0027734, /* JMP *-1 ; no, wait */ - 0063731, /* LDA ISSRD ; get read read */ - 0002341, /* SEZ,CCE,RSS ; iss disc? */ - 0001100, /* ARS ; no, make 7900 read */ - 0067776, /*RD LDB DMACW ; DMA control */ - 0106606, /* OTB 6 */ - 0067762, /* LDB ADDR1 ; memory addr */ - 0077741, /* STB RD ; make non re-executable */ - 0106602, /* OTB 2 */ - 0102702, /* STC 2 ; flip DMA ctrl */ - 0067764, /* LDB COUNT ; word count */ - 0106602, /* OTB 2 */ - 0002041, /* SEZ,RSS */ - 0027766, /* JMP NW */ - 0102611, /* OTA CC ; to cch */ - 0103710, /* STC DC,C ; start dch */ - 0103706, /* STC 6,C ; start DMA */ - 0103711, /* STC CC,C ; start cch */ - 0037773, /* ISZ SK */ - 0027773, /* JMP SK */ - 0030000, /*SEEKC 030000 */ - 0102011, /*ADDR1 102011 */ - 0102055, /*ADDR2 102055 */ - 0164000, /*COUNT -6144. */ - 0000007, /*D7 7 */ - 0106710, /*NW CLC DC ; set 'next wd is cmd' flag */ - 0001720, /* ALF,ALF ; move to head number loc */ - 0001000, /*BIT9 ALS */ - 0103610, /* OTA DC,C ; output cold load cmd */ - 0103706, /* STC 6,C ; start DMA */ - 0102310, /* SFS DC ; done? */ - 0027773, /* JMP *-1 ; no, wait */ - 0117763, /*XT JSB ADDR2,I ; start program */ - 0120010, /*DMACW 120000+DC */ - 0000000 /* -ST */ - }; - -t_stat dqc_boot (int32 unitno, DEVICE *dptr) -{ -int32 dev; - -if (unitno != 0) return SCPE_NOFNC; /* only unit 0 */ -dev = dqd_dib.select_code; /* get data chan dev */ -if (ibl_copy (dq_rom, dev)) return SCPE_IERR; /* copy boot to memory */ -SR = (SR & IBL_OPT) | IBL_DQ | (dev << IBL_V_DEV); /* set SR */ -return SCPE_OK; -} +/* hp2100_dq.c: HP 2100 12565A disk simulator + + Copyright (c) 1993-2006, Bill McDermith + Copyright (c) 2004-2014 J. David Bryan + + 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 + ROBERT M SUPNIK 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 names of the authors shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from the authors. + + DQ 12565A 2883 disk system + + 30-Dec-14 JDB Added S-register parameters to ibl_copy + 24-Dec-14 JDB Added casts for explicit downward conversions + 18-Dec-12 MP Now calls sim_activate_time to get remaining seek time + 09-May-12 JDB Separated assignments from conditional expressions + 10-Feb-12 JDB Deprecated DEVNO in favor of SC + 28-Mar-11 JDB Tidied up signal handling + 26-Oct-10 JDB Changed I/O signal handler for revised signal model + 10-Aug-08 JDB Added REG_FIT to register variables < 32-bit size + 26-Jun-08 JDB Rewrote device I/O to model backplane signals + 28-Dec-06 JDB Added ioCRS state to I/O decoders + 01-Mar-05 JDB Added SET UNLOAD/LOAD + 07-Oct-04 JDB Fixed enable/disable from either device + Shortened xtime from 5 to 3 (drive avg 156KW/second) + Fixed not ready/any error status + Fixed RAR model + 21-Apr-04 RMS Fixed typo in boot loader (found by Dave Bryan) + 26-Apr-04 RMS Fixed SFS x,C and SFC x,C + Fixed SR setting in IBL + Revised IBL loader + Implemented DMA SRQ (follows FLG) + 25-Apr-03 RMS Fixed bug in status check + 10-Nov-02 RMS Added boot command, rebuilt like 12559/13210 + 09-Jan-02 WOM Copied dp driver and mods for 2883 + + Reference: + - 12565A Disc Interface Kit Operating and Service Manual (12565-90003, Aug-1973) + + + Differences between 12559/13210 and 12565 controllers + - 12565 stops transfers on address miscompares; 12559/13210 only stops writes + - 12565 does not set error on positioner busy + - 12565 does not set positioner busy if already on cylinder + - 12565 does not need eoc logic, it will hit an invalid head number + + The controller's "Record Address Register" (RAR) contains the CHS address of + the last Position or Load Address command executed. The RAR is shared among + all drives on the controller. In addition, each drive has an internal + position register that contains the last cylinder and head position + transferred to the drive during Position command execution (sector operations + always start with the RAR sector position). + + In a real drive, the address field of the sector under the head is read and + compared to the RAR. When they match, the target sector is under the head + and is ready for reading or writing. If a match doesn't occur, an Address + Error is indicated. In the simulator, the address field is obtained from the + drive's current position register during a read, i.e., the "on-disc" address + field is assumed to match the current position. + + The following implemented behaviors have been inferred from secondary sources + (diagnostics, operating system drivers, etc.), due to absent or contradictory + authoritative information; future correction may be needed: + + 1. Read Address command starts at the sector number in the RAR. +*/ + +#include "hp2100_defs.h" + +#define UNIT_V_WLK (UNIT_V_UF + 0) /* write locked */ +#define UNIT_V_UNLOAD (UNIT_V_UF + 1) /* heads unloaded */ +#define UNIT_WLK (1 << UNIT_V_WLK) +#define UNIT_UNLOAD (1 << UNIT_V_UNLOAD) +#define FNC u3 /* saved function */ +#define DRV u4 /* drive number (DC) */ +#define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write prot */ + +#define DQ_N_NUMWD 7 +#define DQ_NUMWD (1 << DQ_N_NUMWD) /* words/sector */ +#define DQ_NUMSC 23 /* sectors/track */ +#define DQ_NUMSF 20 /* tracks/cylinder */ +#define DQ_NUMCY 203 /* cylinders/disk */ +#define DQ_SIZE (DQ_NUMSF * DQ_NUMCY * DQ_NUMSC * DQ_NUMWD) +#define DQ_NUMDRV 2 /* # drives */ + +/* Command word */ + +#define CW_V_FNC 12 /* function */ +#define CW_M_FNC 017 +#define CW_GETFNC(x) (((x) >> CW_V_FNC) & CW_M_FNC) +/* 000 (unused) */ +#define FNC_STA 001 /* status check */ +#define FNC_RCL 002 /* recalibrate */ +#define FNC_SEEK 003 /* seek */ +#define FNC_RD 004 /* read */ +#define FNC_WD 005 /* write */ +#define FNC_RA 006 /* read address */ +#define FNC_WA 007 /* write address */ +#define FNC_CHK 010 /* check */ +#define FNC_LA 013 /* load address */ +#define FNC_AS 014 /* address skip */ + +#define FNC_SEEK1 020 /* fake - seek1 */ +#define FNC_SEEK2 021 /* fake - seek2 */ +#define FNC_SEEK3 022 /* fake - seek3 */ +#define FNC_CHK1 023 /* fake - check1 */ +#define FNC_LA1 024 /* fake - ldaddr1 */ + +#define CW_V_DRV 0 /* drive */ +#define CW_M_DRV 01 +#define CW_GETDRV(x) (((x) >> CW_V_DRV) & CW_M_DRV) + +/* Disk address words */ + +#define DA_V_CYL 0 /* cylinder */ +#define DA_M_CYL 0377 +#define DA_GETCYL(x) (((x) >> DA_V_CYL) & DA_M_CYL) +#define DA_V_HD 8 /* head */ +#define DA_M_HD 037 +#define DA_GETHD(x) (((x) >> DA_V_HD) & DA_M_HD) +#define DA_V_SC 0 /* sector */ +#define DA_M_SC 037 +#define DA_GETSC(x) (((x) >> DA_V_SC) & DA_M_SC) +#define DA_CKMASK 0777 /* check mask */ + +/* Status in dqc_sta[drv] - (d) = dynamic */ + +#define STA_DID 0000200 /* drive ID (d) */ +#define STA_NRDY 0000100 /* not ready (d) */ +#define STA_EOC 0000040 /* end of cylinder */ +#define STA_AER 0000020 /* addr error */ +#define STA_FLG 0000010 /* flagged */ +#define STA_BSY 0000004 /* seeking */ +#define STA_DTE 0000002 /* data error */ +#define STA_ERR 0000001 /* any error */ +#define STA_ANYERR (STA_NRDY | STA_EOC | STA_AER | STA_FLG | STA_DTE) + +struct { + FLIP_FLOP command; /* cch command flip-flop */ + FLIP_FLOP control; /* cch control flip-flop */ + FLIP_FLOP flag; /* cch flag flip-flop */ + FLIP_FLOP flagbuf; /* cch flag buffer flip-flop */ + } dqc = { CLEAR, CLEAR, CLEAR, CLEAR }; + +int32 dqc_busy = 0; /* cch xfer */ +int32 dqc_cnt = 0; /* check count */ +int32 dqc_stime = 100; /* seek time */ +int32 dqc_ctime = 100; /* command time */ +int32 dqc_xtime = 3; /* xfer time */ +int32 dqc_dtime = 2; /* dch time */ + +struct { + FLIP_FLOP command; /* dch command flip-flop */ + FLIP_FLOP control; /* dch control flip-flop */ + FLIP_FLOP flag; /* dch flag flip-flop */ + FLIP_FLOP flagbuf; /* dch flag buffer flip-flop */ + } dqd = { CLEAR, CLEAR, CLEAR, CLEAR }; + +int32 dqd_obuf = 0, dqd_ibuf = 0; /* dch buffers */ +int32 dqc_obuf = 0; /* cch buffers */ +int32 dqd_xfer = 0; /* xfer in prog */ +int32 dqd_wval = 0; /* write data valid */ +int32 dq_ptr = 0; /* buffer ptr */ +uint8 dqc_rarc = 0; /* RAR cylinder */ +uint8 dqc_rarh = 0; /* RAR head */ +uint8 dqc_rars = 0; /* RAR sector */ +uint8 dqc_ucyl[DQ_NUMDRV] = { 0 }; /* unit cylinder */ +uint8 dqc_uhed[DQ_NUMDRV] = { 0 }; /* unit head */ +uint16 dqc_sta[DQ_NUMDRV] = { 0 }; /* unit status */ +uint16 dqxb[DQ_NUMWD]; /* sector buffer */ + +DEVICE dqd_dev, dqc_dev; + +IOHANDLER dqdio; +IOHANDLER dqcio; + +t_stat dqc_svc (UNIT *uptr); +t_stat dqd_svc (UNIT *uptr); +t_stat dqc_reset (DEVICE *dptr); +t_stat dqc_attach (UNIT *uptr, char *cptr); +t_stat dqc_detach (UNIT* uptr); +t_stat dqc_load_unload (UNIT *uptr, int32 value, char *cptr, void *desc); +t_stat dqc_boot (int32 unitno, DEVICE *dptr); +void dq_god (int32 fnc, int32 drv, int32 time); +void dq_goc (int32 fnc, int32 drv, int32 time); + +/* DQD data structures + + dqd_dev DQD device descriptor + dqd_unit DQD unit list + dqd_reg DQD register list +*/ + +DIB dq_dib[] = { + { &dqdio, DQD }, + { &dqcio, DQC } + }; + +#define dqd_dib dq_dib[0] +#define dqc_dib dq_dib[1] + +UNIT dqd_unit = { UDATA (&dqd_svc, 0, 0) }; + +REG dqd_reg[] = { + { ORDATA (IBUF, dqd_ibuf, 16) }, + { ORDATA (OBUF, dqd_obuf, 16) }, + { BRDATA (DBUF, dqxb, 8, 16, DQ_NUMWD) }, + { DRDATA (BPTR, dq_ptr, DQ_N_NUMWD) }, + { FLDATA (CMD, dqd.command, 0) }, + { FLDATA (CTL, dqd.control, 0) }, + { FLDATA (FLG, dqd.flag, 0) }, + { FLDATA (FBF, dqd.flagbuf, 0) }, + { FLDATA (XFER, dqd_xfer, 0) }, + { FLDATA (WVAL, dqd_wval, 0) }, + { ORDATA (SC, dqd_dib.select_code, 6), REG_HRO }, + { ORDATA (DEVNO, dqd_dib.select_code, 6), REG_HRO }, + { NULL } + }; + +MTAB dqd_mod[] = { + { MTAB_XTD | MTAB_VDV, 1, "SC", "SC", &hp_setsc, &hp_showsc, &dqd_dev }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &dqd_dev }, + { 0 } + }; + +DEVICE dqd_dev = { + "DQD", &dqd_unit, dqd_reg, dqd_mod, + 1, 10, DQ_N_NUMWD, 1, 8, 16, + NULL, NULL, &dqc_reset, + NULL, NULL, NULL, + &dqd_dib, DEV_DISABLE + }; + +/* DQC data structures + + dqc_dev DQC device descriptor + dqc_unit DQC unit list + dqc_reg DQC register list + dqc_mod DQC modifier list +*/ + +UNIT dqc_unit[] = { + { UDATA (&dqc_svc, UNIT_FIX | UNIT_ATTABLE | UNIT_ROABLE | + UNIT_DISABLE | UNIT_UNLOAD, DQ_SIZE) }, + { UDATA (&dqc_svc, UNIT_FIX | UNIT_ATTABLE | UNIT_ROABLE | + UNIT_DISABLE | UNIT_UNLOAD, DQ_SIZE) } + }; + +REG dqc_reg[] = { + { ORDATA (OBUF, dqc_obuf, 16) }, + { ORDATA (BUSY, dqc_busy, 2), REG_RO }, + { ORDATA (CNT, dqc_cnt, 9) }, + { FLDATA (CMD, dqc.command, 0) }, + { FLDATA (CTL, dqc.control, 0) }, + { FLDATA (FLG, dqc.flag, 0) }, + { FLDATA (FBF, dqc.flagbuf, 0) }, + { DRDATA (RARC, dqc_rarc, 8), PV_RZRO | REG_FIT }, + { DRDATA (RARH, dqc_rarh, 5), PV_RZRO | REG_FIT }, + { DRDATA (RARS, dqc_rars, 5), PV_RZRO | REG_FIT }, + { BRDATA (CYL, dqc_ucyl, 10, 8, DQ_NUMDRV), PV_RZRO }, + { BRDATA (HED, dqc_uhed, 10, 5, DQ_NUMDRV), PV_RZRO }, + { BRDATA (STA, dqc_sta, 8, 16, DQ_NUMDRV) }, + { DRDATA (CTIME, dqc_ctime, 24), PV_LEFT }, + { DRDATA (DTIME, dqc_dtime, 24), PV_LEFT }, + { DRDATA (STIME, dqc_stime, 24), PV_LEFT }, + { DRDATA (XTIME, dqc_xtime, 24), REG_NZ + PV_LEFT }, + { URDATA (UFNC, dqc_unit[0].FNC, 8, 8, 0, + DQ_NUMDRV, REG_HRO) }, + { ORDATA (SC, dqc_dib.select_code, 6), REG_HRO }, + { ORDATA (DEVNO, dqc_dib.select_code, 6), REG_HRO }, + { NULL } + }; + +MTAB dqc_mod[] = { + { UNIT_UNLOAD, UNIT_UNLOAD, "heads unloaded", "UNLOADED", dqc_load_unload }, + { UNIT_UNLOAD, 0, "heads loaded", "LOADED", dqc_load_unload }, + { UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL }, + { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL }, + { MTAB_XTD | MTAB_VDV, 1, "SC", "SC", &hp_setsc, &hp_showsc, &dqd_dev }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &dqd_dev }, + { 0 } + }; + +DEVICE dqc_dev = { + "DQC", dqc_unit, dqc_reg, dqc_mod, + DQ_NUMDRV, 8, 24, 1, 8, 16, + NULL, NULL, &dqc_reset, + &dqc_boot, &dqc_attach, &dqc_detach, + &dqc_dib, DEV_DISABLE + }; + + +/* Data channel I/O signal handler */ + +uint32 dqdio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) +{ +IOSIGNAL signal; +IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ + +while (working_set) { + signal = IONEXT (working_set); /* isolate next signal */ + + switch (signal) { /* dispatch I/O signal */ + + case ioCLF: /* clear flag flip-flop */ + dqd.flag = dqd.flagbuf = CLEAR; + break; + + + case ioSTF: /* set flag flip-flop */ + case ioENF: /* enable flag */ + dqd.flag = dqd.flagbuf = SET; + break; + + + case ioSFC: /* skip if flag is clear */ + setstdSKF (dqd); + break; + + + case ioSFS: /* skip if flag is set */ + setstdSKF (dqd); + break; + + + case ioIOI: /* I/O data input */ + stat_data = IORETURN (SCPE_OK, dqd_ibuf); /* merge in return status */ + break; + + + case ioIOO: /* I/O data output */ + dqd_obuf = IODATA (stat_data); /* clear supplied status */ + + if (!dqc_busy || dqd_xfer) + dqd_wval = 1; /* if !overrun, valid */ + break; + + + case ioPOPIO: /* power-on preset to I/O */ + dqd.flag = dqd.flagbuf = SET; /* set flag and flag buffer */ + dqd_obuf = 0; /* clear output buffer */ + break; + + + case ioCRS: /* control reset */ + dqd.command = CLEAR; /* clear command */ + /* fall into CLC handler */ + + case ioCLC: /* clear control flip-flop */ + dqd.control = CLEAR; /* clear control */ + dqd_xfer = 0; /* clr xfer */ + break; + + + case ioSTC: /* set control flip-flop */ + dqd.command = SET; /* set ctl, cmd */ + dqd.control = SET; + + if (dqc_busy && !dqd_xfer) /* overrun? */ + dqc_sta[dqc_busy - 1] |= STA_DTE; + break; + + + case ioSIR: /* set interrupt request */ + setstdPRL (dqd); /* set standard PRL signal */ + setstdIRQ (dqd); /* set standard IRQ signal */ + setstdSRQ (dqd); /* set standard SRQ signal */ + break; + + + case ioIAK: /* interrupt acknowledge */ + dqd.flagbuf = CLEAR; + break; + + + default: /* all other signals */ + break; /* are ignored */ + } + + working_set = working_set & ~signal; /* remove current signal from set */ + } + +return stat_data; +} + + +/* Command channel I/O signal handler. + + Implementation notes: + + 1. The input buffer register is not connected to the disc controller. + Pullups on the card and an inversion result in reading zeros when IOI is + signalled. +*/ + +uint32 dqcio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) +{ +int32 fnc, drv; +IOSIGNAL signal; +IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ + +while (working_set) { + signal = IONEXT (working_set); /* isolate next signal */ + + switch (signal) { /* dispatch I/O signal */ + + case ioCLF: /* clear flag flip-flop */ + dqc.flag = dqc.flagbuf = CLEAR; + break; + + + case ioSTF: /* set flag flip-flop */ + case ioENF: /* enable flag */ + dqc.flag = dqc.flagbuf = SET; + break; + + + case ioSFC: /* skip if flag is clear */ + setstdSKF (dqc); + break; + + + case ioSFS: /* skip if flag is set */ + setstdSKF (dqc); + break; + + + case ioIOI: /* I/O data input */ + stat_data = IORETURN (SCPE_OK, 0); /* no data */ + break; + + + case ioIOO: /* I/O data output */ + dqc_obuf = IODATA (stat_data); /* clear supplied status */ + break; + + + case ioPOPIO: /* power-on preset to I/O */ + dqc.flag = dqc.flagbuf = SET; /* set flag and flag buffer */ + dqc_obuf = 0; /* clear output buffer */ + break; + + + case ioCRS: /* control reset */ + case ioCLC: /* clear control flip-flop */ + dqc.command = CLEAR; /* clear command */ + dqc.control = CLEAR; /* clear control */ + + if (dqc_busy) + sim_cancel (&dqc_unit[dqc_busy - 1]); + + sim_cancel (&dqd_unit); /* cancel dch */ + dqd_xfer = 0; /* clr dch xfer */ + dqc_busy = 0; /* clr busy */ + break; + + + case ioSTC: /* set control flip-flop */ + dqc.control = SET; /* set ctl */ + + if (!dqc.command) { /* cmd clr? */ + dqc.command = SET; /* set cmd */ + drv = CW_GETDRV (dqc_obuf); /* get fnc, drv */ + fnc = CW_GETFNC (dqc_obuf); /* from cmd word */ + + switch (fnc) { /* case on fnc */ + case FNC_SEEK: case FNC_RCL: /* seek, recal */ + case FNC_CHK: /* check */ + dqc_sta[drv] = 0; /* clear status */ + case FNC_STA: case FNC_LA: /* rd sta, load addr */ + dq_god (fnc, drv, dqc_dtime); /* sched dch xfer */ + break; + case FNC_RD: case FNC_WD: /* read, write */ + case FNC_RA: case FNC_WA: /* rd addr, wr addr */ + case FNC_AS: /* address skip */ + dq_goc (fnc, drv, dqc_ctime); /* sched drive */ + break; + } /* end case */ + } /* end if !CMD */ + break; + + + case ioSIR: /* set interrupt request */ + setstdPRL (dqc); /* set standard PRL signal */ + setstdIRQ (dqc); /* set standard IRQ signal */ + setstdSRQ (dqc); /* set standard SRQ signal */ + break; + + + case ioIAK: /* interrupt acknowledge */ + dqc.flagbuf = CLEAR; + break; + + + default: /* all other signals */ + break; /* are ignored */ + } + + working_set = working_set & ~signal; /* remove current signal from set */ + } +return stat_data; +} + + +/* Start data channel operation */ + +void dq_god (int32 fnc, int32 drv, int32 time) +{ +dqd_unit.DRV = drv; /* save unit */ +dqd_unit.FNC = fnc; /* save function */ +sim_activate (&dqd_unit, time); +return; +} + +/* Start controller operation */ + +void dq_goc (int32 fnc, int32 drv, int32 time) +{ +int32 t; + +t = sim_activate_time (&dqc_unit[drv]); + +if (t) { /* still seeking? */ + sim_cancel (&dqc_unit[drv]); /* cancel */ + time = time + t; /* include seek time */ + } +dqc_sta[drv] = 0; /* clear status */ +dq_ptr = 0; /* init buf ptr */ +dqc_busy = drv + 1; /* set busy */ +dqd_xfer = 1; /* xfer in prog */ +dqc_unit[drv].FNC = fnc; /* save function */ +sim_activate (&dqc_unit[drv], time); /* activate unit */ +return; +} + +/* Data channel unit service + + This routine handles the data channel transfers. It also handles + data transfers that are blocked by seek in progress. + + uptr->DRV = target drive + uptr->FNC = target function + + Seek substates + seek - transfer cylinder + seek1 - transfer head/surface, sched drive + Recalibrate substates + rcl - clear cyl/head/surface, sched drive + Load address + la - transfer cylinder + la1 - transfer head/surface, finish operation + Status check - transfer status, finish operation + Check data + chk - transfer sector count, sched drive +*/ + +t_stat dqd_svc (UNIT *uptr) +{ +int32 drv, st; + +drv = uptr->DRV; /* get drive no */ + +switch (uptr->FNC) { /* case function */ + + case FNC_LA: /* arec, need cyl */ + case FNC_SEEK: /* seek, need cyl */ + if (dqd.command) { /* dch active? */ + dqc_rarc = DA_GETCYL (dqd_obuf); /* set RAR from cyl word */ + dqd_wval = 0; /* clr data valid */ + dqd.command = CLEAR; /* clr dch cmd */ + dqdio (&dqd_dib, ioENF, 0); /* set dch flg */ + if (uptr->FNC == FNC_LA) uptr->FNC = FNC_LA1; + else uptr->FNC = FNC_SEEK1; /* advance state */ + } + sim_activate (uptr, dqc_xtime); /* no, wait more */ + break; + + case FNC_LA1: /* arec, need hd/sec */ + case FNC_SEEK1: /* seek, need hd/sec */ + if (dqd.command) { /* dch active? */ + dqc_rarh = DA_GETHD (dqd_obuf); /* set RAR from head */ + dqc_rars = DA_GETSC (dqd_obuf); /* set RAR from sector */ + dqd_wval = 0; /* clr data valid */ + dqd.command = CLEAR; /* clr dch cmd */ + dqdio (&dqd_dib, ioENF, 0); /* set dch flg */ + if (uptr->FNC == FNC_LA1) { + dqc.command = CLEAR; /* clr cch cmd */ + dqcio (&dqc_dib, ioENF, 0); /* set cch flg */ + break; /* done if Load Address */ + } + if (sim_is_active (&dqc_unit[drv])) break; /* if busy, seek check */ + st = abs (dqc_rarc - dqc_ucyl[drv]) * dqc_stime; + if (st == 0) st = dqc_xtime; /* if on cyl, min time */ + else dqc_sta[drv] = dqc_sta[drv] | STA_BSY; /* set busy */ + dqc_ucyl[drv] = dqc_rarc; /* transfer RAR */ + dqc_uhed[drv] = dqc_rarh; + sim_activate (&dqc_unit[drv], st); /* schedule op */ + dqc_unit[drv].FNC = FNC_SEEK2; /* advance state */ + } + else sim_activate (uptr, dqc_xtime); /* no, wait more */ + break; + + case FNC_RCL: /* recalibrate */ + dqc_rarc = dqc_rarh = dqc_rars = 0; /* clear RAR */ + if (sim_is_active (&dqc_unit[drv])) break; /* ignore if busy */ + st = dqc_ucyl[drv] * dqc_stime; /* calc diff */ + if (st == 0) st = dqc_xtime; /* if on cyl, min time */ + else dqc_sta[drv] = dqc_sta[drv] | STA_BSY; /* set busy */ + sim_activate (&dqc_unit[drv], st); /* schedule drive */ + dqc_ucyl[drv] = dqc_uhed[drv] = 0; /* clear drive pos */ + dqc_unit[drv].FNC = FNC_SEEK2; /* advance state */ + break; + + case FNC_STA: /* read status */ + if (dqd.command) { /* dch active? */ + if ((dqc_unit[drv].flags & UNIT_UNLOAD) == 0) /* drive up? */ + dqd_ibuf = dqc_sta[drv] & ~STA_DID; + else dqd_ibuf = STA_NRDY; + if (dqd_ibuf & STA_ANYERR) /* errors? set flg */ + dqd_ibuf = dqd_ibuf | STA_ERR; + if (drv) dqd_ibuf = dqd_ibuf | STA_DID; + dqc.command = CLEAR; /* clr cch cmd */ + dqd.command = CLEAR; /* clr dch cmd */ + dqdio (&dqd_dib, ioENF, 0); /* set dch flg */ + dqc_sta[drv] = dqc_sta[drv] & ~STA_ANYERR; /* clr sta flags */ + } + else sim_activate (uptr, dqc_xtime); /* wait more */ + break; + + case FNC_CHK: /* check, need cnt */ + if (dqd.command) { /* dch active? */ + dqc_cnt = dqd_obuf & DA_CKMASK; /* get count */ + dqd_wval = 0; /* clr data valid */ + dq_goc (FNC_CHK1, drv, dqc_ctime); /* sched drv */ + } + else sim_activate (uptr, dqc_xtime); /* wait more */ + break; + + default: + return SCPE_IERR; + } + +return SCPE_OK; +} + +/* Drive unit service + + This routine handles the data transfers. + + Seek substates + seek2 - done + Recalibrate substate + rcl1 - done + Check data substates + chk1 - finish operation + Read + Read address + Address skip (read without header check) + Write + Write address +*/ + +#define GETDA(x,y,z) \ + (((((x) * DQ_NUMSF) + (y)) * DQ_NUMSC) + (z)) * DQ_NUMWD + +t_stat dqc_svc (UNIT *uptr) +{ +int32 da, drv, err; + +err = 0; /* assume no err */ +drv = uptr - dqc_unit; /* get drive no */ +if (uptr->flags & UNIT_UNLOAD) { /* drive down? */ + dqc.command = CLEAR; /* clr cch cmd */ + dqcio (&dqc_dib, ioENF, 0); /* set cch flg */ + dqc_sta[drv] = 0; /* clr status */ + dqc_busy = 0; /* ctlr is free */ + dqd_xfer = dqd_wval = 0; + return SCPE_OK; + } +switch (uptr->FNC) { /* case function */ + + case FNC_SEEK2: /* seek done */ + if (dqc_ucyl[drv] >= DQ_NUMCY) { /* out of range? */ + dqc_sta[drv] = dqc_sta[drv] | STA_BSY | STA_ERR; /* seek check */ + dqc_ucyl[drv] = 0; /* seek to cyl 0 */ + } + else dqc_sta[drv] = dqc_sta[drv] & ~STA_BSY; /* drive not busy */ + case FNC_SEEK3: + if (dqc_busy || dqc.flag) { /* ctrl busy? */ + uptr->FNC = FNC_SEEK3; /* next state */ + sim_activate (uptr, dqc_xtime); /* ctrl busy? wait */ + } + else { + dqc.command = CLEAR; /* clr cch cmd */ + dqcio (&dqc_dib, ioENF, 0); /* set cch flg */ + } + return SCPE_OK; + + case FNC_RA: /* read addr */ + if (!dqd.command) break; /* dch clr? done */ + if (dq_ptr == 0) dqd_ibuf = dqc_ucyl[drv]; /* 1st word? */ + else if (dq_ptr == 1) { /* second word? */ + dqd_ibuf = (dqc_uhed[drv] << DA_V_HD) | /* use drive head */ + (dqc_rars << DA_V_SC); /* and RAR sector */ + dqc_rars = (dqc_rars + 1) % DQ_NUMSC; /* incr sector */ + } + else break; + dq_ptr = dq_ptr + 1; + dqd.command = CLEAR; /* clr dch cmd */ + dqdio (&dqd_dib, ioENF, 0); /* set dch flg */ + sim_activate (uptr, dqc_xtime); /* sched next word */ + return SCPE_OK; + + case FNC_AS: /* address skip */ + case FNC_RD: /* read */ + case FNC_CHK1: /* check */ + if (dq_ptr == 0) { /* new sector? */ + if (!dqd.command && (uptr->FNC != FNC_CHK1)) break; + if ((dqc_rarc != dqc_ucyl[drv]) || /* RAR cyl miscompare? */ + (dqc_rarh != dqc_uhed[drv]) || /* RAR head miscompare? */ + (dqc_rars >= DQ_NUMSC)) { /* bad sector? */ + dqc_sta[drv] = dqc_sta[drv] | STA_AER; /* no record found err */ + break; + } + if (dqc_rarh >= DQ_NUMSF) { /* bad head? */ + dqc_sta[drv] = dqc_sta[drv] | STA_EOC; /* end of cyl err */ + break; + } + da = GETDA (dqc_rarc, dqc_rarh, dqc_rars); /* calc disk addr */ + dqc_rars = (dqc_rars + 1) % DQ_NUMSC; /* incr sector */ + if (dqc_rars == 0) /* wrap? incr head */ + dqc_uhed[drv] = dqc_rarh = dqc_rarh + 1; + err = fseek (uptr->fileref, da * sizeof (int16), SEEK_SET); + if (err) + break; + fxread (dqxb, sizeof (int16), DQ_NUMWD, uptr->fileref); + err = ferror (uptr->fileref); + if (err) + break; + } + dqd_ibuf = dqxb[dq_ptr++]; /* get word */ + if (dq_ptr >= DQ_NUMWD) { /* end of sector? */ + if (uptr->FNC == FNC_CHK1) { /* check? */ + dqc_cnt = (dqc_cnt - 1) & DA_CKMASK; /* decr count */ + if (dqc_cnt == 0) break; /* if zero, done */ + } + dq_ptr = 0; /* wrap buf ptr */ + } + if (dqd.command && dqd_xfer) { /* dch on, xfer? */ + dqdio (&dqd_dib, ioENF, 0); /* set flag */ + } + dqd.command = CLEAR; /* clr dch cmd */ + sim_activate (uptr, dqc_xtime); /* sched next word */ + return SCPE_OK; + + case FNC_WA: /* write address */ + case FNC_WD: /* write */ + if (dq_ptr == 0) { /* sector start? */ + if (!dqd.command && !dqd_wval) break; /* xfer done? */ + if (uptr->flags & UNIT_WPRT) { /* write protect? */ + dqc_sta[drv] = dqc_sta[drv] | STA_FLG; + break; /* done */ + } + if ((dqc_rarc != dqc_ucyl[drv]) || /* RAR cyl miscompare? */ + (dqc_rarh != dqc_uhed[drv]) || /* RAR head miscompare? */ + (dqc_rars >= DQ_NUMSC)) { /* bad sector? */ + dqc_sta[drv] = dqc_sta[drv] | STA_AER; /* no record found err */ + break; + } + if (dqc_rarh >= DQ_NUMSF) { /* bad head? */ + dqc_sta[drv] = dqc_sta[drv] | STA_EOC; /* end of cyl err */ + break; + } + } + dqxb[dq_ptr++] = dqd_wval ? (uint16) dqd_obuf : 0; /* store word/fill */ + dqd_wval = 0; /* clr data valid */ + if (dq_ptr >= DQ_NUMWD) { /* buffer full? */ + da = GETDA (dqc_rarc, dqc_rarh, dqc_rars); /* calc disk addr */ + dqc_rars = (dqc_rars + 1) % DQ_NUMSC; /* incr sector */ + if (dqc_rars == 0) /* wrap? incr head */ + dqc_uhed[drv] = dqc_rarh = dqc_rarh + 1; + err = fseek (uptr->fileref, da * sizeof (int16), SEEK_SET); + if (err) + break; + fxwrite (dqxb, sizeof (int16), DQ_NUMWD, uptr->fileref); + err = ferror (uptr->fileref); + if (err) + break; + dq_ptr = 0; + } + if (dqd.command && dqd_xfer) { /* dch on, xfer? */ + dqdio (&dqd_dib, ioENF, 0); /* set flag */ + } + dqd.command = CLEAR; /* clr dch cmd */ + sim_activate (uptr, dqc_xtime); /* sched next word */ + return SCPE_OK; + + default: + return SCPE_IERR; + } /* end case fnc */ + +dqc.command = CLEAR; /* clr cch cmd */ +dqcio (&dqc_dib, ioENF, 0); /* set cch flg */ +dqc_busy = 0; /* ctlr is free */ +dqd_xfer = dqd_wval = 0; +if (err != 0) { /* error? */ + perror ("DQ I/O error"); + clearerr (uptr->fileref); + return SCPE_IOERR; + } +return SCPE_OK; +} + +/* Reset routine */ + +t_stat dqc_reset (DEVICE *dptr) +{ +int32 drv; +DIB *dibptr = (DIB *) dptr->ctxt; /* DIB pointer */ + +hp_enbdis_pair (dptr, /* make pair cons */ + (dptr == &dqd_dev)? &dqc_dev: &dqd_dev); + +if (sim_switches & SWMASK ('P')) { /* initialization reset? */ + dqd_ibuf = 0; /* clear buffers */ + dqd_obuf = 0; + dqc_obuf = 0; /* clear buffer */ + dqc_rarc = dqc_rarh = dqc_rars = 0; /* clear RAR */ + } + +IOPRESET (dibptr); /* PRESET device (does not use PON) */ + +dqc_busy = 0; /* reset controller state */ +dqd_xfer = 0; +dqd_wval = 0; +dq_ptr = 0; + +sim_cancel (&dqd_unit); /* cancel dch */ + +for (drv = 0; drv < DQ_NUMDRV; drv++) { /* loop thru drives */ + sim_cancel (&dqc_unit[drv]); /* cancel activity */ + dqc_unit[drv].FNC = 0; /* clear function */ + dqc_ucyl[drv] = dqc_uhed[drv] = 0; /* clear drive pos */ + dqc_sta[drv] = 0; /* clear status */ + } + +return SCPE_OK; +} + +/* Attach routine */ + +t_stat dqc_attach (UNIT *uptr, char *cptr) +{ +t_stat r; + +r = attach_unit (uptr, cptr); /* attach unit */ +if (r == SCPE_OK) dqc_load_unload (uptr, 0, NULL, NULL);/* if OK, load heads */ +return r; +} + +/* Detach routine */ + +t_stat dqc_detach (UNIT* uptr) +{ +dqc_load_unload (uptr, UNIT_UNLOAD, NULL, NULL); /* unload heads */ +return detach_unit (uptr); /* detach unit */ +} + +/* Load and unload heads */ + +t_stat dqc_load_unload (UNIT *uptr, int32 value, char *cptr, void *desc) +{ +if ((uptr->flags & UNIT_ATT) == 0) return SCPE_UNATT; /* must be attached to load */ +if (value == UNIT_UNLOAD) /* unload heads? */ + uptr->flags = uptr->flags | UNIT_UNLOAD; /* indicate unload */ +else uptr->flags = uptr->flags & ~UNIT_UNLOAD; /* indicate load */ +return SCPE_OK; +} + +/* 7900/7901/2883/2884 bootstrap routine (HP 12992A ROM) */ + +const BOOT_ROM dq_rom = { + 0102501, /*ST LIA 1 ; get switches */ + 0106501, /* LIB 1 */ + 0013765, /* AND D7 ; isolate hd */ + 0005750, /* BLF,CLE,SLB */ + 0027741, /* JMP RD */ + 0005335, /* RBR,SLB,ERB ; <13>->E, set = 2883 */ + 0027717, /* JMP IS */ + 0102611, /*LP OTA CC ; do 7900 status to */ + 0103711, /* STC CC,C ; clear first seek */ + 0102310, /* SFS DC */ + 0027711, /* JMP *-1 */ + 0002004, /* INA ; get next drive */ + 0053765, /* CPA D7 ; all cleared? */ + 0002001, /* RSS */ + 0027707, /* JMP LP */ + 0067761, /*IS LDB SEEKC ; get seek comnd */ + 0106610, /* OTB DC ; issue cyl addr (0) */ + 0103710, /* STC DC,C ; to dch */ + 0106611, /* OTB CC ; seek cmd */ + 0103711, /* STC CC,C ; to cch */ + 0102310, /* SFS DC ; addr wd ok? */ + 0027724, /* JMP *-1 ; no, wait */ + 0006400, /* CLB */ + 0102501, /* LIA 1 ; get switches */ + 0002051, /* SEZ,SLA,RSS ; subchan = 1 or ISS */ + 0047770, /* ADB BIT9 ; head 2 */ + 0106610, /* OTB DC ; head/sector */ + 0103710, /* STC DC,C ; to dch */ + 0102311, /* SFS CC ; seek done? */ + 0027734, /* JMP *-1 ; no, wait */ + 0063731, /* LDA ISSRD ; get read read */ + 0002341, /* SEZ,CCE,RSS ; iss disc? */ + 0001100, /* ARS ; no, make 7900 read */ + 0067776, /*RD LDB DMACW ; DMA control */ + 0106606, /* OTB 6 */ + 0067762, /* LDB ADDR1 ; memory addr */ + 0077741, /* STB RD ; make non re-executable */ + 0106602, /* OTB 2 */ + 0102702, /* STC 2 ; flip DMA ctrl */ + 0067764, /* LDB COUNT ; word count */ + 0106602, /* OTB 2 */ + 0002041, /* SEZ,RSS */ + 0027766, /* JMP NW */ + 0102611, /* OTA CC ; to cch */ + 0103710, /* STC DC,C ; start dch */ + 0103706, /* STC 6,C ; start DMA */ + 0103711, /* STC CC,C ; start cch */ + 0037773, /* ISZ SK */ + 0027773, /* JMP SK */ + 0030000, /*SEEKC 030000 */ + 0102011, /*ADDR1 102011 */ + 0102055, /*ADDR2 102055 */ + 0164000, /*COUNT -6144. */ + 0000007, /*D7 7 */ + 0106710, /*NW CLC DC ; set 'next wd is cmd' flag */ + 0001720, /* ALF,ALF ; move to head number loc */ + 0001000, /*BIT9 ALS */ + 0103610, /* OTA DC,C ; output cold load cmd */ + 0103706, /* STC 6,C ; start DMA */ + 0102310, /* SFS DC ; done? */ + 0027773, /* JMP *-1 ; no, wait */ + 0117763, /*XT JSB ADDR2,I ; start program */ + 0120010, /*DMACW 120000+DC */ + 0000000 /* -ST */ + }; + +t_stat dqc_boot (int32 unitno, DEVICE *dptr) +{ +const int32 dev = dqd_dib.select_code; /* data chan select code */ + +if (unitno != 0) /* boot supported on drive unit 0 only */ + return SCPE_NOFNC; /* report "Command not allowed" if attempted */ + +if (ibl_copy (dq_rom, dev, IBL_OPT, /* copy the boot ROM to memory and configure */ + IBL_DQ | IBL_SET_SC (dev))) /* the S register accordingly */ + return SCPE_IERR; /* return an internal error if the copy failed */ +else + return SCPE_OK; +} diff --git a/HP2100/hp2100_dr.c b/HP2100/hp2100_dr.c index 69c8b7f2..e98ea460 100644 --- a/HP2100/hp2100_dr.c +++ b/HP2100/hp2100_dr.c @@ -1,747 +1,751 @@ -/* hp2100_dr.c: HP 2100 12606B/12610B fixed head disk/drum simulator - - Copyright (c) 1993-2012, Robert M. Supnik - - 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 - ROBERT M SUPNIK 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 Robert M Supnik shall not be - used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from Robert M Supnik. - - DR 12606B 2770/2771 fixed head disk - 12610B 2773/2774/2775 drum - - 10-Feb-12 JDB Deprecated DEVNO in favor of SC - 28-Mar-11 JDB Tidied up signal handling - 26-Oct-10 JDB Changed I/O signal handler for revised signal model - 09-Jul-08 JDB Revised drc_boot to use ibl_copy - 26-Jun-08 JDB Rewrote device I/O to model backplane signals - 28-Dec-06 JDB Added ioCRS state to I/O decoders - 07-Oct-04 JDB Fixed enable/disable from either device - Fixed sector return in status word - Provided protected tracks and "Writing Enabled" status bit - Fixed DMA last word write, incomplete sector fill value - Added "parity error" status return on writes for 12606 - Added track origin test for 12606 - Added SCP test for 12606 - Fixed 12610 SFC operation - Added "Sector Flag" status bit - Added "Read Inhibit" status bit for 12606 - Fixed current-sector determination - Added PROTECTED, UNPROTECTED, TRACKPROT modifiers - 26-Aug-04 RMS Fixed CLC to stop operation (from Dave Bryan) - 26-Apr-04 RMS Fixed SFS x,C and SFC x,C - Revised boot rom to use IBL algorithm - Implemented DMA SRQ (follows FLG) - 27-Jul-03 RMS Fixed drum sizes - Fixed variable capacity interaction with SAVE/RESTORE - 10-Nov-02 RMS Added BOOT command - - References: - - 12606B Disc Memory Interface Kit Operating and Service Manual - (12606-90012, Mar-1970) - - 12610B Drum Memory Interface Kit Operating and Service Manual - (12610-9001, Feb-1970) - - - These head-per-track devices are buffered in memory, to minimize overhead. - - The drum data channel does not have a command flip-flop. Its control - flip-flop is not wired into the interrupt chain; accordingly, the - simulator uses command rather than control for the data channel. Its - flag does not respond to SFS, SFC, or STF. - - The drum control channel does not have any of the traditional flip-flops. - - The 12606 interface implements two diagnostic tests. An SFS CC instruction - will skip if the disk has passed the track origin (sector 0) since the last - CLF CC instruction, and an SFC CC instruction will skip if the Sector Clock - Phase (SCP) flip-flop is clear, indicating that the current sector is - accessible. The 12610 interface does not support these tests; the SKF signal - is not driven, so neither SFC CC nor SFS CC will skip. - - The interface implements a track protect mechanism via a switch and a set of - on-card diodes. The switch sets the protected/unprotected status, and the - particular diodes installed indicate the range of tracks (a power of 2) that - are read-only in the protected mode. - - Somewhat unusually, writing to a protected track completes normally, but the - data isn't actually written, as the write current is inhibited. There is no - "failure" status indication. Instead, a program must note the lack of - "Writing Enabled" status before the write is attempted. - - Specifications (2770/2771): - - 90 sectors per logical track - - 45 sectors per revolution - - 64 words per sector - - 2880 words per revolution - - 3450 RPM = 17.4 ms/revolution - - data timing = 6.0 us/word, 375 us/sector - - inst timing = 4 inst/word, 11520 inst/revolution - - Specifications 2773/2774/2775: - - 32 sectors per logical track - - 32 sectors per revolution - - 64 words per sector - - 2048 words per revolution - - 3450 RPM = 17.4 ms/revolution - - data timing = 8.5 us/word, 550 us/sector - - inst timing = 6 inst/word, 12288 inst/revolution -*/ - -#include "hp2100_defs.h" -#include "hp2100_cpu.h" -#include - -/* Constants */ - -#define DR_NUMWD 64 /* words/sector */ -#define DR_FNUMSC 90 /* fhd sec/track */ -#define DR_DNUMSC 32 /* drum sec/track */ -#define DR_NUMSC ((drc_unit.flags & UNIT_DRUM)? DR_DNUMSC: DR_FNUMSC) -#define DR_SIZE (512 * DR_DNUMSC * DR_NUMWD) /* initial size */ -#define DR_FTIME 4 /* fhd per-word time */ -#define DR_DTIME 6 /* drum per-word time */ -#define DR_OVRHEAD 5 /* overhead words at track start */ -#define UNIT_V_PROT (UNIT_V_UF + 0) /* track protect */ -#define UNIT_V_SZ (UNIT_V_UF + 1) /* disk vs drum */ -#define UNIT_M_SZ 017 /* size */ -#define UNIT_PROT (1 << UNIT_V_PROT) -#define UNIT_SZ (UNIT_M_SZ << UNIT_V_SZ) -#define UNIT_DRUM (1 << UNIT_V_SZ) /* low order bit */ -#define SZ_180K 000 /* disks */ -#define SZ_360K 002 -#define SZ_720K 004 -#define SZ_1024K 001 /* drums: default size */ -#define SZ_1536K 003 -#define SZ_384K 005 -#define SZ_512K 007 -#define SZ_640K 011 -#define SZ_768K 013 -#define SZ_896K 015 -#define DR_GETSZ(x) (((x) >> UNIT_V_SZ) & UNIT_M_SZ) - -/* Command word */ - -#define CW_WR 0100000 /* write vs read */ -#define CW_V_FTRK 7 /* fhd track */ -#define CW_M_FTRK 0177 -#define CW_V_DTRK 5 /* drum track */ -#define CW_M_DTRK 01777 -#define MAX_TRK (((drc_unit.flags & UNIT_DRUM)? CW_M_DTRK: CW_M_FTRK) + 1) -#define CW_GETTRK(x) ((drc_unit.flags & UNIT_DRUM)? \ - (((x) >> CW_V_DTRK) & CW_M_DTRK): \ - (((x) >> CW_V_FTRK) & CW_M_FTRK)) -#define CW_PUTTRK(x) ((drc_unit.flags & UNIT_DRUM)? \ - (((x) & CW_M_DTRK) << CW_V_DTRK): \ - (((x) & CW_M_FTRK) << CW_V_FTRK)) -#define CW_V_FSEC 0 /* fhd sector */ -#define CW_M_FSEC 0177 -#define CW_V_DSEC 0 /* drum sector */ -#define CW_M_DSEC 037 -#define CW_GETSEC(x) ((drc_unit.flags & UNIT_DRUM)? \ - (((x) >> CW_V_DSEC) & CW_M_DSEC): \ - (((x) >> CW_V_FSEC) & CW_M_FSEC)) -#define CW_PUTSEC(x) ((drc_unit.flags & UNIT_DRUM)? \ - (((x) & CW_M_DSEC) << CW_V_DSEC): \ - (((x) & CW_M_FSEC) << CW_V_FSEC)) - -/* Status register, ^ = dynamic */ - -#define DRS_V_NS 8 /* ^next sector */ -#define DRS_M_NS 0177 -#define DRS_SEC 0100000 /* ^sector flag */ -#define DRS_RDY 0000200 /* ^ready */ -#define DRS_RIF 0000100 /* ^read inhibit */ -#define DRS_SAC 0000040 /* sector coincidence */ -#define DRS_ABO 0000010 /* abort */ -#define DRS_WEN 0000004 /* ^write enabled */ -#define DRS_PER 0000002 /* parity error */ -#define DRS_BSY 0000001 /* ^busy */ - -#define CALC_SCP(x) (((int32) fmod ((x) / (double) dr_time, \ - (double) (DR_NUMWD))) >= (DR_NUMWD - 3)) - -int32 drc_cw = 0; /* fnc, addr */ -int32 drc_sta = 0; /* status */ -int32 drc_run = 0; /* run flip-flop */ - -struct { - FLIP_FLOP control; /* control flip-flop */ - FLIP_FLOP flag; /* flag flip-flop */ - } drd = { CLEAR, CLEAR }; - -int32 drd_ibuf = 0; /* input buffer */ -int32 drd_obuf = 0; /* output buffer */ -int32 drd_ptr = 0; /* sector pointer */ -int32 drc_pcount = 1; /* number of prot tracks */ -int32 dr_stopioe = 1; /* stop on error */ -int32 dr_time = DR_DTIME; /* time per word */ - -static int32 sz_tab[16] = { - 184320, 1048576, 368640, 1572864, 737280, 393216, 0, 524288, - 0, 655360, 0, 786432, 0, 917504, 0, 0 }; - -IOHANDLER drdio; -IOHANDLER drcio; - -t_stat drc_svc (UNIT *uptr); -t_stat drc_reset (DEVICE *dptr); -t_stat drc_attach (UNIT *uptr, char *cptr); -t_stat drc_boot (int32 unitno, DEVICE *dptr); -int32 dr_incda (int32 trk, int32 sec, int32 ptr); -int32 dr_seccntr (double simtime); -t_stat dr_set_prot (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat dr_show_prot (FILE *st, UNIT *uptr, int32 val, void *desc); -t_stat dr_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); - -DEVICE drd_dev, drc_dev; - -/* DRD data structures - - drd_dev device descriptor - drd_unit unit descriptor - drd_reg register list -*/ - -DIB dr_dib[] = { - { &drdio, DRD }, - { &drcio, DRC } - }; - -#define drd_dib dr_dib[0] -#define drc_dib dr_dib[1] - -UNIT drd_unit[] = { - { UDATA (NULL, 0, 0) }, - { UDATA (NULL, UNIT_DIS, 0) } - }; - -#define TMR_ORG 0 /* origin timer */ -#define TMR_INH 1 /* inhibit timer */ - -REG drd_reg[] = { - { ORDATA (IBUF, drd_ibuf, 16) }, - { ORDATA (OBUF, drd_obuf, 16) }, - { FLDATA (CTL, drd.control, 0) }, - { FLDATA (FLG, drd.flag, 0) }, - { ORDATA (BPTR, drd_ptr, 6) }, - { ORDATA (SC, drd_dib.select_code, 6), REG_HRO }, - { ORDATA (DEVNO, drd_dib.select_code, 6), REG_HRO }, - { NULL } - }; - -MTAB drd_mod[] = { - { MTAB_XTD | MTAB_VDV, 1, "SC", "SC", &hp_setsc, &hp_showsc, &drd_dev }, - { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &drd_dev }, - { 0 } - }; - -DEVICE drd_dev = { - "DRD", drd_unit, drd_reg, drd_mod, - 2, 0, 0, 0, 0, 0, - NULL, NULL, &drc_reset, - NULL, NULL, NULL, - &drd_dib, DEV_DISABLE - }; - -/* DRC data structures - - drc_dev device descriptor - drc_unit unit descriptor - drc_mod unit modifiers - drc_reg register list -*/ - -UNIT drc_unit = { - UDATA (&drc_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+ - UNIT_MUSTBUF+UNIT_DRUM+UNIT_BINK, DR_SIZE) - }; - -REG drc_reg[] = { - { DRDATA (PCNT, drc_pcount, 10), REG_HIDDEN | PV_LEFT }, - { ORDATA (CW, drc_cw, 16) }, - { ORDATA (STA, drc_sta, 16) }, - { FLDATA (RUN, drc_run, 0) }, - { DRDATA (TIME, dr_time, 24), REG_NZ + PV_LEFT }, - { FLDATA (STOP_IOE, dr_stopioe, 0) }, - { ORDATA (SC, drc_dib.select_code, 6), REG_HRO }, - { ORDATA (DEVNO, drc_dib.select_code, 6), REG_HRO }, - { DRDATA (CAPAC, drc_unit.capac, 24), REG_HRO }, - { NULL } - }; - -MTAB drc_mod[] = { - { UNIT_DRUM, 0, "disk", NULL, NULL }, - { UNIT_DRUM, UNIT_DRUM, "drum", NULL, NULL }, - { UNIT_SZ, (SZ_180K << UNIT_V_SZ), NULL, "180K", &dr_set_size }, - { UNIT_SZ, (SZ_360K << UNIT_V_SZ), NULL, "360K", &dr_set_size }, - { UNIT_SZ, (SZ_720K << UNIT_V_SZ), NULL, "720K", &dr_set_size }, - { UNIT_SZ, (SZ_384K << UNIT_V_SZ), NULL, "384K", &dr_set_size }, - { UNIT_SZ, (SZ_512K << UNIT_V_SZ), NULL, "512K", &dr_set_size }, - { UNIT_SZ, (SZ_640K << UNIT_V_SZ), NULL, "640K", &dr_set_size }, - { UNIT_SZ, (SZ_768K << UNIT_V_SZ), NULL, "768K", &dr_set_size }, - { UNIT_SZ, (SZ_896K << UNIT_V_SZ), NULL, "896K", &dr_set_size }, - { UNIT_SZ, (SZ_1024K << UNIT_V_SZ), NULL, "1024K", &dr_set_size }, - { UNIT_SZ, (SZ_1536K << UNIT_V_SZ), NULL, "1536K", &dr_set_size }, - { UNIT_PROT, UNIT_PROT, "protected", "PROTECTED", NULL }, - { UNIT_PROT, 0, "unprotected", "UNPROTECTED", NULL }, - { MTAB_XTD | MTAB_VDV, 0, "TRACKPROT", "TRACKPROT", - &dr_set_prot, &dr_show_prot, NULL }, - { MTAB_XTD | MTAB_VDV, 1, "SC", "SC", &hp_setsc, &hp_showsc, &drd_dev }, - { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &drd_dev }, - { 0 } - }; - -DEVICE drc_dev = { - "DRC", &drc_unit, drc_reg, drc_mod, - 1, 8, 21, 1, 8, 16, - NULL, NULL, &drc_reset, - &drc_boot, &drc_attach, NULL, - &drc_dib, DEV_DISABLE - }; - - -/* Data channel I/O signal handler. - - The data channel card does not follow the usual interface I/O configuration. - PRL is always asserted, the card does not drive IRQ, FLG, or SKF and does not - respond to IAK. SRQ is driven by the output of the flag flip-flop, which - obeys CLF only. There is no flag buffer. The control flip-flop obeys STC - and CLC. Clearing control clears the flag flip-flop, and setting control - sets the flag flip-flop if the interface is configured for writing. On the - 12606B, POPIO and CRS clear the track address register. - - Implementation notes: - - 1. In response to CRS, the 12606B data channel clears only the track address - register; the command channel clears the sector address register and the - direction flip-flop. Under simulation, all three form the control word, - and as CRS is sent to all devices, we simply clear the control word here. -*/ - -uint32 drdio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) -{ -int32 t; -IOSIGNAL signal; -IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ - -while (working_set) { - signal = IONEXT (working_set); /* isolate next signal */ - - switch (signal) { /* dispatch I/O signal */ - - case ioCLF: /* clear flag flip-flop */ - drd.flag = CLEAR; - break; - - - case ioENF: /* enable flag */ - drd.flag = SET; - break; - - - case ioIOI: /* I/O data input */ - stat_data = IORETURN (SCPE_OK, drd_ibuf); /* merge in return status */ - break; - - - case ioIOO: /* I/O data output */ - drd_obuf = IODATA (stat_data); /* clear supplied status */ - break; - - - case ioCRS: /* control reset */ - if (!(drc_unit.flags & UNIT_DRUM)) /* 12606B? */ - drc_cw = 0; /* clear control word */ - /* fall into CLC handler */ - - case ioCLC: /* clear control flip-flop */ - drd.flag = drd.control = CLEAR; /* clear control and flag */ - - if (!drc_run) /* cancel curr op */ - sim_cancel (&drc_unit); - - drc_sta = drc_sta & ~DRS_SAC; /* clear SAC flag */ - break; - - - case ioSTC: /* set control flip-flop */ - drd.control = SET; /* set ctl */ - - if (drc_cw & CW_WR) /* writing? */ - drd.flag = SET; /* prime DMA */ - - drc_sta = 0; /* clr status */ - drd_ptr = 0; /* clear sec ptr */ - sim_cancel (&drc_unit); /* cancel curr op */ - t = CW_GETSEC (drc_cw) - dr_seccntr (sim_gtime()); - if (t <= 0) t = t + DR_NUMSC; - sim_activate (&drc_unit, t * DR_NUMWD * dr_time); - break; - - - case ioSIR: /* set interrupt request */ - setstdSRQ (drd); /* set SRQ signal */ - break; - - - default: /* all other signals */ - break; /* are ignored */ - } - - working_set = working_set & ~signal; /* remove current signal from set */ - } - -return stat_data; -} - - -/* Command channel I/O signal dispatcher. - - The command channel card does not follow the usual interface I/O - configuration. PRL is always asserted, the card does not drive IRQ, FLG, or - SRQ and does not respond to IAK. There are no control, flag, or flag buffer - flip-flops. CLF clears the track origin flip-flop; STF is ignored. The - 12606B drives SKF, whereas the 12610B does not. On the 12610B, SFS tests the - Track Origin flip-flop, and SFC tests the Sector Clock Phase (SCP) flip-flop. - - Implementation notes: - - 1. CRS clears the Run Flip-Flop, stopping the current operation. Under - simulation, we allow the data channel signal handler to do this, as the - same operation is invoked by CLC DC, and as CRS is sent to all devices. - - 2. The command channel cannot interrupt, so there is no SIR handler. -*/ - -uint32 drcio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) -{ - -uint16 data; -int32 sec; -IOSIGNAL signal; -IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ - -while (working_set) { - signal = IONEXT (working_set); /* isolate next signal */ - - switch (signal) { /* dispatch I/O signal */ - - case ioCLF: /* clear flag flip-flop */ - if (!(drc_unit.flags & UNIT_DRUM)) { /* disk? */ - sec = dr_seccntr (sim_gtime ()); /* current sector */ - sim_cancel (&drd_unit[TMR_ORG]); /* sched origin tmr */ - sim_activate (&drd_unit[TMR_ORG], - (DR_FNUMSC - sec) * DR_NUMWD * dr_time); - } - break; - - - case ioSFC: /* skip if flag is clear */ - if (!(drc_unit.flags & UNIT_DRUM)) /* 12606? */ - setSKF (!(CALC_SCP (sim_gtime()))); /* skip if nearing end of sector */ - break; - - - case ioSFS: /* skip if flag is set */ - if (!(drc_unit.flags & UNIT_DRUM)) /* 12606? */ - setSKF (!sim_is_active (&drd_unit[TMR_ORG])); /* skip if origin seen */ - break; - - - case ioIOI: /* I/O data input */ - data = drc_sta; /* static bits */ - - if (!(drc_unit.flags & UNIT_PROT) || /* not protected? */ - (CW_GETTRK(drc_cw) >= drc_pcount)) /* or not in range? */ - data = data | DRS_WEN; /* set wrt enb status */ - - if (drc_unit.flags & UNIT_ATT) { /* attached? */ - data = data | (dr_seccntr (sim_gtime()) << DRS_V_NS) | DRS_RDY; - if (sim_is_active (&drc_unit)) /* op in progress? */ - data = data | DRS_BSY; - if (CALC_SCP (sim_gtime())) /* SCP ff set? */ - data = data | DRS_SEC; /* set sector flag */ - if (sim_is_active (&drd_unit[TMR_INH]) && /* inhibit timer on? */ - !(drc_cw & CW_WR)) - data = data | DRS_RIF; /* set read inh flag */ - } - - stat_data = IORETURN (SCPE_OK, data); /* merge in return status */ - break; - - - case ioIOO: /* I/O data output */ - if (!(drc_unit.flags & UNIT_DRUM)) { /* disk? */ - sim_cancel (&drd_unit[TMR_INH]); /* schedule inhibit timer */ - sim_activate (&drd_unit[TMR_INH], DR_FTIME * DR_NUMWD); - } - drc_cw = IODATA (stat_data); /* get control word */ - break; - - - default: /* all other signals */ - break; /* are ignored */ - } - - working_set = working_set & ~signal; /* remove current signal from set */ - } - -return stat_data; -} - - -/* Unit service */ - -t_stat drc_svc (UNIT *uptr) -{ -int32 trk, sec; -uint32 da; -uint16 *bptr = (uint16 *) uptr->filebuf; - -if ((uptr->flags & UNIT_ATT) == 0) { - drc_sta = DRS_ABO; - return IOERROR (dr_stopioe, SCPE_UNATT); - } - -trk = CW_GETTRK (drc_cw); -sec = CW_GETSEC (drc_cw); -da = ((trk * DR_NUMSC) + sec) * DR_NUMWD; -drc_sta = drc_sta | DRS_SAC; -drc_run = 1; /* set run ff */ - -if (drc_cw & CW_WR) { /* write? */ - if ((da < uptr->capac) && (sec < DR_NUMSC)) { - bptr[da + drd_ptr] = drd_obuf; - if (((uint32) (da + drd_ptr)) >= uptr->hwmark) - uptr->hwmark = da + drd_ptr + 1; - } - drd_ptr = dr_incda (trk, sec, drd_ptr); /* inc disk addr */ - if (drd.control) { /* dch active? */ - drdio (&drd_dib, ioENF, 0); /* set SRQ */ - sim_activate (uptr, dr_time); /* sched next word */ - } - else { /* done */ - if (drd_ptr) /* need to fill? */ - for ( ; drd_ptr < DR_NUMWD; drd_ptr++) - bptr[da + drd_ptr] = drd_obuf; /* fill with last word */ - if (!(drc_unit.flags & UNIT_DRUM)) /* disk? */ - drc_sta = drc_sta | DRS_PER; /* parity bit sets on write */ - drc_run = 0; /* clear run ff */ - } - } /* end write */ -else { /* read */ - if (drd.control) { /* dch active? */ - if ((da >= uptr->capac) || (sec >= DR_NUMSC)) drd_ibuf = 0; - else drd_ibuf = bptr[da + drd_ptr]; - drd_ptr = dr_incda (trk, sec, drd_ptr); - drdio (&drd_dib, ioENF, 0); /* set SRQ */ - sim_activate (uptr, dr_time); /* sched next word */ - } - else drc_run = 0; /* clear run ff */ - } -return SCPE_OK; -} - -/* Increment current disk address */ - -int32 dr_incda (int32 trk, int32 sec, int32 ptr) -{ -ptr = ptr + 1; /* inc pointer */ -if (ptr >= DR_NUMWD) { /* end sector? */ - ptr = 0; /* new sector */ - sec = sec + 1; /* adv sector */ - if (sec >= DR_NUMSC) { /* end track? */ - sec = 0; /* new track */ - trk = trk + 1; /* adv track */ - if (trk >= MAX_TRK) trk = 0; /* wraps at max */ - } - drc_cw = (drc_cw & CW_WR) | CW_PUTTRK (trk) | CW_PUTSEC (sec); - } -return ptr; -} - -/* Read the sector counter - - The hardware sector counter contains the number of the next sector that will - pass under the heads (so it is one ahead of the current sector). For the - duration of the last sector of the track, the sector counter contains 90 for - the 12606 and 0 for the 12610. The sector counter resets to 0 at track - origin and increments at the start of the first sector. Therefore, the - counter value ranges from 0-90 for the 12606 and 0-31 for the 12610. The 0 - state is quite short in the 12606 and long in the 12610, relative to the - other sector counter states. - - The simulated sector counter is calculated from the simulation time, based on - the time per word and the number of words per track. -*/ - -int32 dr_seccntr (double simtime) -{ -int32 curword; - -curword = (int32) fmod (simtime / (double) dr_time, - (double) (DR_NUMWD * DR_NUMSC + DR_OVRHEAD)); -if (curword <= DR_OVRHEAD) return 0; -else return ((curword - DR_OVRHEAD) / DR_NUMWD + - ((drc_unit.flags & UNIT_DRUM)? 0: 1)); -} - -/* Reset routine */ - -t_stat drc_reset (DEVICE *dptr) -{ -DIB *dibptr = (DIB *) dptr->ctxt; /* DIB pointer */ - -hp_enbdis_pair (dptr, /* make pair cons */ - (dptr == &drd_dev)? &drc_dev: &drd_dev); - -if (sim_switches & SWMASK ('P')) { /* power-on reset? */ - drd_ptr = 0; /* clear sector pointer */ - drc_sta = drc_cw = 0; /* clear controller state variables */ - } - -IOPRESET (dibptr); /* PRESET device (does not use PON) */ - -sim_cancel (&drc_unit); -sim_cancel (&drd_unit[TMR_ORG]); -sim_cancel (&drd_unit[TMR_INH]); - -return SCPE_OK; -} - -/* Attach routine */ - -t_stat drc_attach (UNIT *uptr, char *cptr) -{ -int32 sz = sz_tab[DR_GETSZ (uptr->flags)]; - -if (sz == 0) return SCPE_IERR; -uptr->capac = sz; -return attach_unit (uptr, cptr); -} - -/* Set protected track count */ - -t_stat dr_set_prot (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -int32 count; -t_stat status; - -if (cptr == NULL) - return SCPE_ARG; -count = (int32) get_uint (cptr, 10, 768, &status); -if (status != SCPE_OK) - return status; -else switch (count) { - case 1: - case 2: - case 4: - case 8: - case 16: - case 32: - case 64: - case 128: - drc_pcount = count; - break; - case 256: - case 512: - case 768: - if (drc_unit.flags & UNIT_DRUM) - drc_pcount = count; - else return SCPE_ARG; - break; - default: - return SCPE_ARG; - } -return SCPE_OK; -} - -/* Show protected track count */ - -t_stat dr_show_prot (FILE *st, UNIT *uptr, int32 val, void *desc) -{ -fprintf (st, "protected tracks=%d", drc_pcount); -return SCPE_OK; -} - -/* Set size routine */ - -t_stat dr_set_size (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -int32 sz; -int32 szindex; - -if (val < 0) return SCPE_IERR; -if ((sz = sz_tab[szindex = DR_GETSZ (val)]) == 0) return SCPE_IERR; -if (uptr->flags & UNIT_ATT) return SCPE_ALATT; -uptr->capac = sz; -if (szindex & UNIT_DRUM) dr_time = DR_DTIME; /* drum */ -else { - dr_time = DR_FTIME; /* disk */ - if (drc_pcount > 128) drc_pcount = 128; /* max prot track count */ - } -return SCPE_OK; -} - -/* Fixed head disk/drum bootstrap routine (disc subset of disc/paper tape loader) */ - -#define BOOT_START 060 - -static const BOOT_ROM dr_rom = { /* padded to start at x7760 */ - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, - 0020010, /*DMA 20000+DC */ - 0000000, /* 0 */ - 0107700, /* CLC 0,C */ - 0063756, /* LDA DMA ; DMA ctrl */ - 0102606, /* OTA 6 */ - 0002700, /* CLA,CCE */ - 0102611, /* OTA CC ; trk = sec = 0 */ - 0001500, /* ERA ; A = 100000 */ - 0102602, /* OTA 2 ; DMA in, addr */ - 0063777, /* LDA M64 */ - 0102702, /* STC 2 */ - 0102602, /* OTA 2 ; DMA wc = -64 */ - 0103706, /* STC 6,C ; start DMA */ - 0067776, /* LDB JSF ; get JMP . */ - 0074077, /* STB 77 ; in base page */ - 0102710, /* STC DC ; start disc */ - 0024077, /*JSF JMP 77 ; go wait */ - 0177700 /*M64 -100 */ - }; - -t_stat drc_boot (int32 unitno, DEVICE *dptr) -{ -const int32 dev = drd_dib.select_code; /* data chan select code */ - -if (unitno != 0) /* only unit 0 */ - return SCPE_NOFNC; -if (ibl_copy (dr_rom, dev)) /* copy boot to memory */ - return SCPE_IERR; - -WritePW (PC + IBL_DPC, dr_rom [IBL_DPC]); /* restore overwritten word */ -WritePW (PC + IBL_END, dr_rom [IBL_END]); /* restore overwritten word */ -PC = PC + BOOT_START; /* correct starting address */ -return SCPE_OK; -} +/* hp2100_dr.c: HP 2100 12606B/12610B fixed head disk/drum simulator + + Copyright (c) 1993-2014, Robert M. Supnik + + 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 + ROBERT M SUPNIK 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 Robert M Supnik shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + + DR 12606B 2770/2771 fixed head disk + 12610B 2773/2774/2775 drum + + 30-Dec-14 JDB Added S-register parameters to ibl_copy + 24-Dec-14 JDB Added casts for explicit downward conversions + 10-Feb-12 JDB Deprecated DEVNO in favor of SC + 28-Mar-11 JDB Tidied up signal handling + 26-Oct-10 JDB Changed I/O signal handler for revised signal model + 09-Jul-08 JDB Revised drc_boot to use ibl_copy + 26-Jun-08 JDB Rewrote device I/O to model backplane signals + 28-Dec-06 JDB Added ioCRS state to I/O decoders + 07-Oct-04 JDB Fixed enable/disable from either device + Fixed sector return in status word + Provided protected tracks and "Writing Enabled" status bit + Fixed DMA last word write, incomplete sector fill value + Added "parity error" status return on writes for 12606 + Added track origin test for 12606 + Added SCP test for 12606 + Fixed 12610 SFC operation + Added "Sector Flag" status bit + Added "Read Inhibit" status bit for 12606 + Fixed current-sector determination + Added PROTECTED, UNPROTECTED, TRACKPROT modifiers + 26-Aug-04 RMS Fixed CLC to stop operation (from Dave Bryan) + 26-Apr-04 RMS Fixed SFS x,C and SFC x,C + Revised boot rom to use IBL algorithm + Implemented DMA SRQ (follows FLG) + 27-Jul-03 RMS Fixed drum sizes + Fixed variable capacity interaction with SAVE/RESTORE + 10-Nov-02 RMS Added BOOT command + + References: + - 12606B Disc Memory Interface Kit Operating and Service Manual + (12606-90012, Mar-1970) + - 12610B Drum Memory Interface Kit Operating and Service Manual + (12610-9001, Feb-1970) + + + These head-per-track devices are buffered in memory, to minimize overhead. + + The drum data channel does not have a command flip-flop. Its control + flip-flop is not wired into the interrupt chain; accordingly, the + simulator uses command rather than control for the data channel. Its + flag does not respond to SFS, SFC, or STF. + + The drum control channel does not have any of the traditional flip-flops. + + The 12606 interface implements two diagnostic tests. An SFS CC instruction + will skip if the disk has passed the track origin (sector 0) since the last + CLF CC instruction, and an SFC CC instruction will skip if the Sector Clock + Phase (SCP) flip-flop is clear, indicating that the current sector is + accessible. The 12610 interface does not support these tests; the SKF signal + is not driven, so neither SFC CC nor SFS CC will skip. + + The interface implements a track protect mechanism via a switch and a set of + on-card diodes. The switch sets the protected/unprotected status, and the + particular diodes installed indicate the range of tracks (a power of 2) that + are read-only in the protected mode. + + Somewhat unusually, writing to a protected track completes normally, but the + data isn't actually written, as the write current is inhibited. There is no + "failure" status indication. Instead, a program must note the lack of + "Writing Enabled" status before the write is attempted. + + Specifications (2770/2771): + - 90 sectors per logical track + - 45 sectors per revolution + - 64 words per sector + - 2880 words per revolution + - 3450 RPM = 17.4 ms/revolution + - data timing = 6.0 us/word, 375 us/sector + - inst timing = 4 inst/word, 11520 inst/revolution + + Specifications 2773/2774/2775: + - 32 sectors per logical track + - 32 sectors per revolution + - 64 words per sector + - 2048 words per revolution + - 3450 RPM = 17.4 ms/revolution + - data timing = 8.5 us/word, 550 us/sector + - inst timing = 6 inst/word, 12288 inst/revolution +*/ + +#include "hp2100_defs.h" +#include "hp2100_cpu.h" +#include + +/* Constants */ + +#define DR_NUMWD 64 /* words/sector */ +#define DR_FNUMSC 90 /* fhd sec/track */ +#define DR_DNUMSC 32 /* drum sec/track */ +#define DR_NUMSC ((drc_unit.flags & UNIT_DRUM)? DR_DNUMSC: DR_FNUMSC) +#define DR_SIZE (512 * DR_DNUMSC * DR_NUMWD) /* initial size */ +#define DR_FTIME 4 /* fhd per-word time */ +#define DR_DTIME 6 /* drum per-word time */ +#define DR_OVRHEAD 5 /* overhead words at track start */ +#define UNIT_V_PROT (UNIT_V_UF + 0) /* track protect */ +#define UNIT_V_SZ (UNIT_V_UF + 1) /* disk vs drum */ +#define UNIT_M_SZ 017 /* size */ +#define UNIT_PROT (1 << UNIT_V_PROT) +#define UNIT_SZ (UNIT_M_SZ << UNIT_V_SZ) +#define UNIT_DRUM (1 << UNIT_V_SZ) /* low order bit */ +#define SZ_180K 000 /* disks */ +#define SZ_360K 002 +#define SZ_720K 004 +#define SZ_1024K 001 /* drums: default size */ +#define SZ_1536K 003 +#define SZ_384K 005 +#define SZ_512K 007 +#define SZ_640K 011 +#define SZ_768K 013 +#define SZ_896K 015 +#define DR_GETSZ(x) (((x) >> UNIT_V_SZ) & UNIT_M_SZ) + +/* Command word */ + +#define CW_WR 0100000 /* write vs read */ +#define CW_V_FTRK 7 /* fhd track */ +#define CW_M_FTRK 0177 +#define CW_V_DTRK 5 /* drum track */ +#define CW_M_DTRK 01777 +#define MAX_TRK (((drc_unit.flags & UNIT_DRUM)? CW_M_DTRK: CW_M_FTRK) + 1) +#define CW_GETTRK(x) ((drc_unit.flags & UNIT_DRUM)? \ + (((x) >> CW_V_DTRK) & CW_M_DTRK): \ + (((x) >> CW_V_FTRK) & CW_M_FTRK)) +#define CW_PUTTRK(x) ((drc_unit.flags & UNIT_DRUM)? \ + (((x) & CW_M_DTRK) << CW_V_DTRK): \ + (((x) & CW_M_FTRK) << CW_V_FTRK)) +#define CW_V_FSEC 0 /* fhd sector */ +#define CW_M_FSEC 0177 +#define CW_V_DSEC 0 /* drum sector */ +#define CW_M_DSEC 037 +#define CW_GETSEC(x) ((drc_unit.flags & UNIT_DRUM)? \ + (((x) >> CW_V_DSEC) & CW_M_DSEC): \ + (((x) >> CW_V_FSEC) & CW_M_FSEC)) +#define CW_PUTSEC(x) ((drc_unit.flags & UNIT_DRUM)? \ + (((x) & CW_M_DSEC) << CW_V_DSEC): \ + (((x) & CW_M_FSEC) << CW_V_FSEC)) + +/* Status register, ^ = dynamic */ + +#define DRS_V_NS 8 /* ^next sector */ +#define DRS_M_NS 0177 +#define DRS_SEC 0100000 /* ^sector flag */ +#define DRS_RDY 0000200 /* ^ready */ +#define DRS_RIF 0000100 /* ^read inhibit */ +#define DRS_SAC 0000040 /* sector coincidence */ +#define DRS_ABO 0000010 /* abort */ +#define DRS_WEN 0000004 /* ^write enabled */ +#define DRS_PER 0000002 /* parity error */ +#define DRS_BSY 0000001 /* ^busy */ + +#define CALC_SCP(x) (((int32) fmod ((x) / (double) dr_time, \ + (double) (DR_NUMWD))) >= (DR_NUMWD - 3)) + +int32 drc_cw = 0; /* fnc, addr */ +int32 drc_sta = 0; /* status */ +int32 drc_run = 0; /* run flip-flop */ + +struct { + FLIP_FLOP control; /* control flip-flop */ + FLIP_FLOP flag; /* flag flip-flop */ + } drd = { CLEAR, CLEAR }; + +int32 drd_ibuf = 0; /* input buffer */ +int32 drd_obuf = 0; /* output buffer */ +int32 drd_ptr = 0; /* sector pointer */ +int32 drc_pcount = 1; /* number of prot tracks */ +int32 dr_stopioe = 1; /* stop on error */ +int32 dr_time = DR_DTIME; /* time per word */ + +static int32 sz_tab[16] = { + 184320, 1048576, 368640, 1572864, 737280, 393216, 0, 524288, + 0, 655360, 0, 786432, 0, 917504, 0, 0 }; + +IOHANDLER drdio; +IOHANDLER drcio; + +t_stat drc_svc (UNIT *uptr); +t_stat drc_reset (DEVICE *dptr); +t_stat drc_attach (UNIT *uptr, char *cptr); +t_stat drc_boot (int32 unitno, DEVICE *dptr); +int32 dr_incda (int32 trk, int32 sec, int32 ptr); +int32 dr_seccntr (double simtime); +t_stat dr_set_prot (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat dr_show_prot (FILE *st, UNIT *uptr, int32 val, void *desc); +t_stat dr_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); + +DEVICE drd_dev, drc_dev; + +/* DRD data structures + + drd_dev device descriptor + drd_unit unit descriptor + drd_reg register list +*/ + +DIB dr_dib[] = { + { &drdio, DRD }, + { &drcio, DRC } + }; + +#define drd_dib dr_dib[0] +#define drc_dib dr_dib[1] + +UNIT drd_unit[] = { + { UDATA (NULL, 0, 0) }, + { UDATA (NULL, UNIT_DIS, 0) } + }; + +#define TMR_ORG 0 /* origin timer */ +#define TMR_INH 1 /* inhibit timer */ + +REG drd_reg[] = { + { ORDATA (IBUF, drd_ibuf, 16) }, + { ORDATA (OBUF, drd_obuf, 16) }, + { FLDATA (CTL, drd.control, 0) }, + { FLDATA (FLG, drd.flag, 0) }, + { ORDATA (BPTR, drd_ptr, 6) }, + { ORDATA (SC, drd_dib.select_code, 6), REG_HRO }, + { ORDATA (DEVNO, drd_dib.select_code, 6), REG_HRO }, + { NULL } + }; + +MTAB drd_mod[] = { + { MTAB_XTD | MTAB_VDV, 1, "SC", "SC", &hp_setsc, &hp_showsc, &drd_dev }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &drd_dev }, + { 0 } + }; + +DEVICE drd_dev = { + "DRD", drd_unit, drd_reg, drd_mod, + 2, 0, 0, 0, 0, 0, + NULL, NULL, &drc_reset, + NULL, NULL, NULL, + &drd_dib, DEV_DISABLE + }; + +/* DRC data structures + + drc_dev device descriptor + drc_unit unit descriptor + drc_mod unit modifiers + drc_reg register list +*/ + +UNIT drc_unit = { + UDATA (&drc_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+ + UNIT_MUSTBUF+UNIT_DRUM+UNIT_BINK, DR_SIZE) + }; + +REG drc_reg[] = { + { DRDATA (PCNT, drc_pcount, 10), REG_HIDDEN | PV_LEFT }, + { ORDATA (CW, drc_cw, 16) }, + { ORDATA (STA, drc_sta, 16) }, + { FLDATA (RUN, drc_run, 0) }, + { DRDATA (TIME, dr_time, 24), REG_NZ + PV_LEFT }, + { FLDATA (STOP_IOE, dr_stopioe, 0) }, + { ORDATA (SC, drc_dib.select_code, 6), REG_HRO }, + { ORDATA (DEVNO, drc_dib.select_code, 6), REG_HRO }, + { DRDATA (CAPAC, drc_unit.capac, 24), REG_HRO }, + { NULL } + }; + +MTAB drc_mod[] = { + { UNIT_DRUM, 0, "disk", NULL, NULL }, + { UNIT_DRUM, UNIT_DRUM, "drum", NULL, NULL }, + { UNIT_SZ, (SZ_180K << UNIT_V_SZ), NULL, "180K", &dr_set_size }, + { UNIT_SZ, (SZ_360K << UNIT_V_SZ), NULL, "360K", &dr_set_size }, + { UNIT_SZ, (SZ_720K << UNIT_V_SZ), NULL, "720K", &dr_set_size }, + { UNIT_SZ, (SZ_384K << UNIT_V_SZ), NULL, "384K", &dr_set_size }, + { UNIT_SZ, (SZ_512K << UNIT_V_SZ), NULL, "512K", &dr_set_size }, + { UNIT_SZ, (SZ_640K << UNIT_V_SZ), NULL, "640K", &dr_set_size }, + { UNIT_SZ, (SZ_768K << UNIT_V_SZ), NULL, "768K", &dr_set_size }, + { UNIT_SZ, (SZ_896K << UNIT_V_SZ), NULL, "896K", &dr_set_size }, + { UNIT_SZ, (SZ_1024K << UNIT_V_SZ), NULL, "1024K", &dr_set_size }, + { UNIT_SZ, (SZ_1536K << UNIT_V_SZ), NULL, "1536K", &dr_set_size }, + { UNIT_PROT, UNIT_PROT, "protected", "PROTECTED", NULL }, + { UNIT_PROT, 0, "unprotected", "UNPROTECTED", NULL }, + { MTAB_XTD | MTAB_VDV, 0, "TRACKPROT", "TRACKPROT", + &dr_set_prot, &dr_show_prot, NULL }, + { MTAB_XTD | MTAB_VDV, 1, "SC", "SC", &hp_setsc, &hp_showsc, &drd_dev }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &drd_dev }, + { 0 } + }; + +DEVICE drc_dev = { + "DRC", &drc_unit, drc_reg, drc_mod, + 1, 8, 21, 1, 8, 16, + NULL, NULL, &drc_reset, + &drc_boot, &drc_attach, NULL, + &drc_dib, DEV_DISABLE + }; + + +/* Data channel I/O signal handler. + + The data channel card does not follow the usual interface I/O configuration. + PRL is always asserted, the card does not drive IRQ, FLG, or SKF and does not + respond to IAK. SRQ is driven by the output of the flag flip-flop, which + obeys CLF only. There is no flag buffer. The control flip-flop obeys STC + and CLC. Clearing control clears the flag flip-flop, and setting control + sets the flag flip-flop if the interface is configured for writing. On the + 12606B, POPIO and CRS clear the track address register. + + Implementation notes: + + 1. In response to CRS, the 12606B data channel clears only the track address + register; the command channel clears the sector address register and the + direction flip-flop. Under simulation, all three form the control word, + and as CRS is sent to all devices, we simply clear the control word here. +*/ + +uint32 drdio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) +{ +int32 t; +IOSIGNAL signal; +IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ + +while (working_set) { + signal = IONEXT (working_set); /* isolate next signal */ + + switch (signal) { /* dispatch I/O signal */ + + case ioCLF: /* clear flag flip-flop */ + drd.flag = CLEAR; + break; + + + case ioENF: /* enable flag */ + drd.flag = SET; + break; + + + case ioIOI: /* I/O data input */ + stat_data = IORETURN (SCPE_OK, drd_ibuf); /* merge in return status */ + break; + + + case ioIOO: /* I/O data output */ + drd_obuf = IODATA (stat_data); /* clear supplied status */ + break; + + + case ioCRS: /* control reset */ + if (!(drc_unit.flags & UNIT_DRUM)) /* 12606B? */ + drc_cw = 0; /* clear control word */ + /* fall into CLC handler */ + + case ioCLC: /* clear control flip-flop */ + drd.flag = drd.control = CLEAR; /* clear control and flag */ + + if (!drc_run) /* cancel curr op */ + sim_cancel (&drc_unit); + + drc_sta = drc_sta & ~DRS_SAC; /* clear SAC flag */ + break; + + + case ioSTC: /* set control flip-flop */ + drd.control = SET; /* set ctl */ + + if (drc_cw & CW_WR) /* writing? */ + drd.flag = SET; /* prime DMA */ + + drc_sta = 0; /* clr status */ + drd_ptr = 0; /* clear sec ptr */ + sim_cancel (&drc_unit); /* cancel curr op */ + t = CW_GETSEC (drc_cw) - dr_seccntr (sim_gtime()); + if (t <= 0) t = t + DR_NUMSC; + sim_activate (&drc_unit, t * DR_NUMWD * dr_time); + break; + + + case ioSIR: /* set interrupt request */ + setstdSRQ (drd); /* set SRQ signal */ + break; + + + default: /* all other signals */ + break; /* are ignored */ + } + + working_set = working_set & ~signal; /* remove current signal from set */ + } + +return stat_data; +} + + +/* Command channel I/O signal dispatcher. + + The command channel card does not follow the usual interface I/O + configuration. PRL is always asserted, the card does not drive IRQ, FLG, or + SRQ and does not respond to IAK. There are no control, flag, or flag buffer + flip-flops. CLF clears the track origin flip-flop; STF is ignored. The + 12606B drives SKF, whereas the 12610B does not. On the 12610B, SFS tests the + Track Origin flip-flop, and SFC tests the Sector Clock Phase (SCP) flip-flop. + + Implementation notes: + + 1. CRS clears the Run Flip-Flop, stopping the current operation. Under + simulation, we allow the data channel signal handler to do this, as the + same operation is invoked by CLC DC, and as CRS is sent to all devices. + + 2. The command channel cannot interrupt, so there is no SIR handler. +*/ + +uint32 drcio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) +{ + +uint16 data; +int32 sec; +IOSIGNAL signal; +IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ + +while (working_set) { + signal = IONEXT (working_set); /* isolate next signal */ + + switch (signal) { /* dispatch I/O signal */ + + case ioCLF: /* clear flag flip-flop */ + if (!(drc_unit.flags & UNIT_DRUM)) { /* disk? */ + sec = dr_seccntr (sim_gtime ()); /* current sector */ + sim_cancel (&drd_unit[TMR_ORG]); /* sched origin tmr */ + sim_activate (&drd_unit[TMR_ORG], + (DR_FNUMSC - sec) * DR_NUMWD * dr_time); + } + break; + + + case ioSFC: /* skip if flag is clear */ + if (!(drc_unit.flags & UNIT_DRUM)) /* 12606? */ + setSKF (!(CALC_SCP (sim_gtime()))); /* skip if nearing end of sector */ + break; + + + case ioSFS: /* skip if flag is set */ + if (!(drc_unit.flags & UNIT_DRUM)) /* 12606? */ + setSKF (!sim_is_active (&drd_unit[TMR_ORG])); /* skip if origin seen */ + break; + + + case ioIOI: /* I/O data input */ + data = (uint16) drc_sta; /* static bits */ + + if (!(drc_unit.flags & UNIT_PROT) || /* not protected? */ + (CW_GETTRK(drc_cw) >= drc_pcount)) /* or not in range? */ + data = data | DRS_WEN; /* set wrt enb status */ + + if (drc_unit.flags & UNIT_ATT) { /* attached? */ + data = data | (uint16) (dr_seccntr (sim_gtime()) << DRS_V_NS) | DRS_RDY; + if (sim_is_active (&drc_unit)) /* op in progress? */ + data = data | DRS_BSY; + if (CALC_SCP (sim_gtime())) /* SCP ff set? */ + data = data | DRS_SEC; /* set sector flag */ + if (sim_is_active (&drd_unit[TMR_INH]) && /* inhibit timer on? */ + !(drc_cw & CW_WR)) + data = data | DRS_RIF; /* set read inh flag */ + } + + stat_data = IORETURN (SCPE_OK, data); /* merge in return status */ + break; + + + case ioIOO: /* I/O data output */ + if (!(drc_unit.flags & UNIT_DRUM)) { /* disk? */ + sim_cancel (&drd_unit[TMR_INH]); /* schedule inhibit timer */ + sim_activate (&drd_unit[TMR_INH], DR_FTIME * DR_NUMWD); + } + drc_cw = IODATA (stat_data); /* get control word */ + break; + + + default: /* all other signals */ + break; /* are ignored */ + } + + working_set = working_set & ~signal; /* remove current signal from set */ + } + +return stat_data; +} + + +/* Unit service */ + +t_stat drc_svc (UNIT *uptr) +{ +int32 trk, sec; +uint32 da; +uint16 *bptr = (uint16 *) uptr->filebuf; + +if ((uptr->flags & UNIT_ATT) == 0) { + drc_sta = DRS_ABO; + return IOERROR (dr_stopioe, SCPE_UNATT); + } + +trk = CW_GETTRK (drc_cw); +sec = CW_GETSEC (drc_cw); +da = ((trk * DR_NUMSC) + sec) * DR_NUMWD; +drc_sta = drc_sta | DRS_SAC; +drc_run = 1; /* set run ff */ + +if (drc_cw & CW_WR) { /* write? */ + if ((da < uptr->capac) && (sec < DR_NUMSC)) { + bptr[da + drd_ptr] = (uint16) drd_obuf; + if (((uint32) (da + drd_ptr)) >= uptr->hwmark) + uptr->hwmark = da + drd_ptr + 1; + } + drd_ptr = dr_incda (trk, sec, drd_ptr); /* inc disk addr */ + if (drd.control) { /* dch active? */ + drdio (&drd_dib, ioENF, 0); /* set SRQ */ + sim_activate (uptr, dr_time); /* sched next word */ + } + else { /* done */ + if (drd_ptr) /* need to fill? */ + for ( ; drd_ptr < DR_NUMWD; drd_ptr++) + bptr[da + drd_ptr] = (uint16) drd_obuf; /* fill with last word */ + if (!(drc_unit.flags & UNIT_DRUM)) /* disk? */ + drc_sta = drc_sta | DRS_PER; /* parity bit sets on write */ + drc_run = 0; /* clear run ff */ + } + } /* end write */ +else { /* read */ + if (drd.control) { /* dch active? */ + if ((da >= uptr->capac) || (sec >= DR_NUMSC)) drd_ibuf = 0; + else drd_ibuf = bptr[da + drd_ptr]; + drd_ptr = dr_incda (trk, sec, drd_ptr); + drdio (&drd_dib, ioENF, 0); /* set SRQ */ + sim_activate (uptr, dr_time); /* sched next word */ + } + else drc_run = 0; /* clear run ff */ + } +return SCPE_OK; +} + +/* Increment current disk address */ + +int32 dr_incda (int32 trk, int32 sec, int32 ptr) +{ +ptr = ptr + 1; /* inc pointer */ +if (ptr >= DR_NUMWD) { /* end sector? */ + ptr = 0; /* new sector */ + sec = sec + 1; /* adv sector */ + if (sec >= DR_NUMSC) { /* end track? */ + sec = 0; /* new track */ + trk = trk + 1; /* adv track */ + if (trk >= MAX_TRK) trk = 0; /* wraps at max */ + } + drc_cw = (drc_cw & CW_WR) | CW_PUTTRK (trk) | CW_PUTSEC (sec); + } +return ptr; +} + +/* Read the sector counter + + The hardware sector counter contains the number of the next sector that will + pass under the heads (so it is one ahead of the current sector). For the + duration of the last sector of the track, the sector counter contains 90 for + the 12606 and 0 for the 12610. The sector counter resets to 0 at track + origin and increments at the start of the first sector. Therefore, the + counter value ranges from 0-90 for the 12606 and 0-31 for the 12610. The 0 + state is quite short in the 12606 and long in the 12610, relative to the + other sector counter states. + + The simulated sector counter is calculated from the simulation time, based on + the time per word and the number of words per track. +*/ + +int32 dr_seccntr (double simtime) +{ +int32 curword; + +curword = (int32) fmod (simtime / (double) dr_time, + (double) (DR_NUMWD * DR_NUMSC + DR_OVRHEAD)); +if (curword <= DR_OVRHEAD) return 0; +else return ((curword - DR_OVRHEAD) / DR_NUMWD + + ((drc_unit.flags & UNIT_DRUM)? 0: 1)); +} + +/* Reset routine */ + +t_stat drc_reset (DEVICE *dptr) +{ +DIB *dibptr = (DIB *) dptr->ctxt; /* DIB pointer */ + +hp_enbdis_pair (dptr, /* make pair cons */ + (dptr == &drd_dev)? &drc_dev: &drd_dev); + +if (sim_switches & SWMASK ('P')) { /* power-on reset? */ + drd_ptr = 0; /* clear sector pointer */ + drc_sta = drc_cw = 0; /* clear controller state variables */ + } + +IOPRESET (dibptr); /* PRESET device (does not use PON) */ + +sim_cancel (&drc_unit); +sim_cancel (&drd_unit[TMR_ORG]); +sim_cancel (&drd_unit[TMR_INH]); + +return SCPE_OK; +} + +/* Attach routine */ + +t_stat drc_attach (UNIT *uptr, char *cptr) +{ +int32 sz = sz_tab[DR_GETSZ (uptr->flags)]; + +if (sz == 0) return SCPE_IERR; +uptr->capac = sz; +return attach_unit (uptr, cptr); +} + +/* Set protected track count */ + +t_stat dr_set_prot (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +int32 count; +t_stat status; + +if (cptr == NULL) + return SCPE_ARG; +count = (int32) get_uint (cptr, 10, 768, &status); +if (status != SCPE_OK) + return status; +else switch (count) { + case 1: + case 2: + case 4: + case 8: + case 16: + case 32: + case 64: + case 128: + drc_pcount = count; + break; + case 256: + case 512: + case 768: + if (drc_unit.flags & UNIT_DRUM) + drc_pcount = count; + else return SCPE_ARG; + break; + default: + return SCPE_ARG; + } +return SCPE_OK; +} + +/* Show protected track count */ + +t_stat dr_show_prot (FILE *st, UNIT *uptr, int32 val, void *desc) +{ +fprintf (st, "protected tracks=%d", drc_pcount); +return SCPE_OK; +} + +/* Set size routine */ + +t_stat dr_set_size (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +int32 sz; +int32 szindex; + +if (val < 0) return SCPE_IERR; +if ((sz = sz_tab[szindex = DR_GETSZ (val)]) == 0) return SCPE_IERR; +if (uptr->flags & UNIT_ATT) return SCPE_ALATT; +uptr->capac = sz; +if (szindex & UNIT_DRUM) dr_time = DR_DTIME; /* drum */ +else { + dr_time = DR_FTIME; /* disk */ + if (drc_pcount > 128) drc_pcount = 128; /* max prot track count */ + } +return SCPE_OK; +} + +/* Fixed head disk/drum bootstrap routine (disc subset of disc/paper tape loader) */ + +#define BOOT_START 060 + +static const BOOT_ROM dr_rom = { /* padded to start at x7760 */ + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0020010, /*DMA 20000+DC */ + 0000000, /* 0 */ + 0107700, /* CLC 0,C */ + 0063756, /* LDA DMA ; DMA ctrl */ + 0102606, /* OTA 6 */ + 0002700, /* CLA,CCE */ + 0102611, /* OTA CC ; trk = sec = 0 */ + 0001500, /* ERA ; A = 100000 */ + 0102602, /* OTA 2 ; DMA in, addr */ + 0063777, /* LDA M64 */ + 0102702, /* STC 2 */ + 0102602, /* OTA 2 ; DMA wc = -64 */ + 0103706, /* STC 6,C ; start DMA */ + 0067776, /* LDB JSF ; get JMP . */ + 0074077, /* STB 77 ; in base page */ + 0102710, /* STC DC ; start disc */ + 0024077, /*JSF JMP 77 ; go wait */ + 0177700 /*M64 -100 */ + }; + +t_stat drc_boot (int32 unitno, DEVICE *dptr) +{ +const int32 dev = drd_dib.select_code; /* data chan select code */ + +if (unitno != 0) /* boot supported on drive unit 0 only */ + return SCPE_NOFNC; /* report "Command not allowed" if attempted */ + +if (ibl_copy (dr_rom, dev, IBL_S_NOCLR, IBL_S_NOSET)) /* copy the boot ROM to memory and configure */ + return SCPE_IERR; /* return an internal error if the copy failed */ + +WritePW (PC + IBL_DPC, dr_rom [IBL_DPC]); /* restore overwritten word */ +WritePW (PC + IBL_END, dr_rom [IBL_END]); /* restore overwritten word */ +PC = PC + BOOT_START; /* correct starting address */ + +return SCPE_OK; +} diff --git a/HP2100/hp2100_ds.c b/HP2100/hp2100_ds.c index 29df4589..2a897efd 100644 --- a/HP2100/hp2100_ds.c +++ b/HP2100/hp2100_ds.c @@ -1,1477 +1,1480 @@ -/* hp2100_ds.c: HP 13037D/13175D disc controller/interface simulator - - Copyright (c) 2004-2012, Robert M. Supnik - Copyright (c) 2012 J. David Bryan - - 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 - THE AUTHORS 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 names of the authors shall not be - used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from the authors. - - DS 13037D/13175D disc controller/interface - - 29-Mar-12 JDB Rewritten to use the MAC/ICD disc controller library - ioIOO now notifies controller service of parameter output - 14-Feb-12 JDB Corrected SRQ generation and FIFO under/overrun detection - Corrected Clear command to conform to the hardware - Fixed Request Status to return Unit Unavailable if illegal - Seek and Cold Load Read now Seek Check if seek in progress - Remodeled command wait for seek completion - 10-Feb-12 JDB Deprecated DEVNO in favor of SC - 21-Jun-11 JDB Corrected status returns for disabled drive, auto-seek - beyond drive limits, Request Sector Address and Wakeup - with invalid or offline unit - Address verification reenabled if auto-seek during - Read Without Verify - 28-Mar-11 JDB Tidied up signal handling - 26-Oct-10 JDB Changed I/O signal handler for revised signal model - 26-Jun-08 JDB Rewrote device I/O to model backplane signals - 31-Dec-07 JDB Corrected and verified ioCRS action - 20-Dec-07 JDB Corrected DPTR register definition from FLDATA to DRDATA - 28-Dec-06 JDB Added ioCRS state to I/O decoders - 03-Aug-06 JDB Fixed REQUEST STATUS command to clear status-1 - Removed redundant attached test in "ds_detach" - 18-Mar-05 RMS Added attached test to detach routine - 01-Mar-05 JDB Added SET UNLOAD/LOAD - - References: - - 13037 Disc Controller Technical Information Package (13037-90902, Aug-1980) - - 7925D Disc Drive Service Manual (07925-90913, Apr-1984) - - HP 12992 Loader ROMs Installation Manual (12992-90001, Apr-1986) - - DVR32 RTE Moving Head Driver source (92084-18711, Revision 5000) - - - The 13037D multiple-access (MAC) disc controller supports from one to eight - HP 7905 (15 MB), 7906 (20MB), 7920 (50 MB), and 7925 (120 MB) disc drives - accessed by one to eight CPUs. The controller hardware consists of a 16-bit - microprogrammed processor constructed from 74S181 bit slices operating at 5 - MHz, a device controller providing the interconnections to the drives and CPU - interfaces, and an error correction controller that enables the correction of - up to 32-bit error bursts. 1024 words of 24-bit firmware are stored in ROM. - - The 13175D disc interface is used to connect the HP 1000 CPU to the 13037 - device controller. In a multiple-CPU system, one interface is strapped to - reset the controller when the CPU's front panel PRESET button is pressed. - - This module simulates a 13037D connected to a single 13175D interface. From - one to eight drives may be connected, and drive types may be freely - intermixed. A unit that is enabled but not attached appears to be a - connected drive that does not have a disc pack in place. A unit that is - disabled appears to be disconnected. - - This simulator is an adaptation of the code originally written by Bob Supnik. - The functions of the controller have been separated from the functions of the - interface, with the former placed into a separate disc controller library. - This allows the library to support other CPU interfaces, such as the 12821A - HP-IB disc interface, that use substantially different communication - protocols. The library functions implement the controller command set for - the drive units. The interface functions handle the transfer of commands and - data to and from the CPU. - - In hardware, the controller runs continuously in one of three states: in the - Poll Loop (idle state), in the Command Wait Loop (wait state), or in command - execution (busy state). In simulation, the controller is run only when a - command is executing or when a transition into or out of the two loops might - occur. Internally, the controller handles these transitions: - - - when a command other than End terminates (busy => wait) - - when the End command terminates (busy => idle) - - when a command timeout occurs (wait => idle) - - when a parameter timeout occurs (busy => idle) - - when a seek completes (if idle and interrupts are enabled, idle => wait) - - The interface must call the controller library to handle these transitions: - - - when a command is received from the CPU (idle or wait => busy) - - when interrupts are enabled (if idle and drive Attention, idle => wait) - - In addition, each transition to the wait state must check for a pending - command, and each transition to the idle state must check for both a pending - command and a drive with Attention status asserted. - - - Implementation notes: - - 1. Although the 13175D has a 16-word FIFO, the "full" level is set at 5 - entries in hardware to avoid a long DCPC preemption time at the start of - a disc write as the FIFO fills. -*/ - - - -#include "hp2100_defs.h" -#include "hp_disclib.h" - - - -/* Program constants */ - -#define DS_DRIVES (DL_MAXDRIVE + 1) /* number of disc drive units */ -#define DS_UNITS (DS_DRIVES + DL_AUXUNITS) /* total number of units */ - -#define ds_cntlr ds_unit [DL_MAXDRIVE + 1] /* controller unit alias */ - -#define FIFO_SIZE 16 /* FIFO depth */ - -#define FIFO_EMPTY (ds.fifo_count == 0) /* FIFO empty test */ -#define FIFO_STOP (ds.fifo_count >= 5) /* FIFO stop filling test */ -#define FIFO_FULL (ds.fifo_count == FIFO_SIZE) /* FIFO full test */ - -#define PRESET_ENABLE TRUE /* Preset Jumper (W4) is enabled */ - - -/* Debug flags */ - -#define DEB_CPU (1 << 0) /* words received from and sent to the CPU */ -#define DEB_CMDS (1 << 1) /* interface commands received from the CPU */ -#define DEB_BUF (1 << 2) /* data read from and written to the card FIFO */ -#define DEB_RWSC (1 << 3) /* device read/write/status/control commands */ -#define DEB_SERV (1 << 4) /* unit service scheduling calls */ - - - -/* Per-card state variables */ - -typedef struct { - FLIP_FLOP control; /* control flip-flop */ - FLIP_FLOP flag; /* flag flip-flop */ - FLIP_FLOP flagbuf; /* flag buffer flip-flop */ - FLIP_FLOP srq; /* SRQ flip-flop */ - FLIP_FLOP edt; /* EDT flip-flop */ - FLIP_FLOP cmfol; /* command follows flip-flop */ - FLIP_FLOP cmrdy; /* command ready flip-flop */ - uint16 fifo [FIFO_SIZE]; /* FIFO buffer */ - uint32 fifo_count; /* FIFO occupancy counter */ - REG *fifo_reg; /* FIFO register pointer */ - } CARD_STATE; - - -/* MAC disc state variables */ - -static UNIT ds_unit [DS_UNITS]; /* unit array */ - -static CARD_STATE ds; /* card state */ - -static uint16 buffer [DL_BUFSIZE]; /* command/status/sector buffer */ - -static CNTLR_VARS mac_cntlr = /* MAC controller */ - { CNTLR_INIT (MAC, buffer, &ds_cntlr) }; - - - -/* MAC disc global VM routines */ - -IOHANDLER ds_io; -t_stat ds_service_drive (UNIT *uptr); -t_stat ds_service_controller (UNIT *uptr); -t_stat ds_service_timer (UNIT *uptr); -t_stat ds_reset (DEVICE *dptr); -t_stat ds_attach (UNIT *uptr, char *cptr); -t_stat ds_detach (UNIT *uptr); -t_stat ds_boot (int32 unitno, DEVICE *dptr); - -/* MAC disc global SCP routines */ - -t_stat ds_load_unload (UNIT *uptr, int32 value, char *cptr, void *desc); - -/* MAC disc local utility routines */ - -static void start_command (void); -static void poll_interface (void); -static void poll_drives (void); -static void fifo_load (uint16 data); -static uint16 fifo_unload (void); -static void fifo_clear (void); -static t_stat activate_unit (UNIT *uptr); - - - -/* MAC disc VM data structures. - - ds_dib DS device information block - ds_unit DS unit list - ds_reg DS register list - ds_mod DS modifier list - ds_deb DS debug table - ds_dev DS device descriptor - - For the drive models, the modifiers provide this SHOW behavior: - - - when detached and autosized, prints "autosize" - - when detached and not autosized, prints the model number - - when attached, prints the model number (regardless of autosizing) - - - Implementation notes: - - 1. The validation routine does not allow the model number or autosizing - option to be changed when the unit is attached. Therefore, specifying - UNIT_ATT in the mask field has no adverse effect. - - 2. The modifier DEVNO is deprecated in favor of SC but is retained for - compatibility. -*/ - - -DEVICE ds_dev; - -static DIB ds_dib = { &ds_io, DS }; - -#define UNIT_FLAGS (UNIT_FIX | UNIT_ATTABLE | UNIT_ROABLE | UNIT_DISABLE | UNIT_UNLOAD) - -static UNIT ds_unit [] = { - { UDATA (&ds_service_drive, UNIT_FLAGS | MODEL_7905, D7905_WORDS) }, /* drive unit 0 */ - { UDATA (&ds_service_drive, UNIT_FLAGS | MODEL_7905, D7905_WORDS) }, /* drive unit 1 */ - { UDATA (&ds_service_drive, UNIT_FLAGS | MODEL_7905, D7905_WORDS) }, /* drive unit 2 */ - { UDATA (&ds_service_drive, UNIT_FLAGS | MODEL_7905, D7905_WORDS) }, /* drive unit 3 */ - { UDATA (&ds_service_drive, UNIT_FLAGS | MODEL_7905, D7905_WORDS) }, /* drive unit 4 */ - { UDATA (&ds_service_drive, UNIT_FLAGS | MODEL_7905, D7905_WORDS) }, /* drive unit 5 */ - { UDATA (&ds_service_drive, UNIT_FLAGS | MODEL_7905, D7905_WORDS) }, /* drive unit 6 */ - { UDATA (&ds_service_drive, UNIT_FLAGS | MODEL_7905, D7905_WORDS) }, /* drive unit 7 */ - { UDATA (&ds_service_controller, UNIT_DIS, 0) }, /* controller unit */ - { UDATA (&ds_service_timer, UNIT_DIS, 0) } /* timer unit */ - }; - -static REG ds_reg [] = { - { FLDATA (CMFOL, ds.cmfol, 0) }, - { FLDATA (CMRDY, ds.cmrdy, 0) }, - { DRDATA (FCNT, ds.fifo_count, 5) }, - { BRDATA (FIFO, ds.fifo, 8, 16, FIFO_SIZE), REG_CIRC }, - { ORDATA (FREG, ds.fifo_reg, 32), REG_HRO }, - - { ORDATA (CNTYPE, mac_cntlr.type, 2), REG_HRO }, - { ORDATA (STATE, mac_cntlr.state, 2) }, - { ORDATA (OPCODE, mac_cntlr.opcode, 6) }, - { ORDATA (STATUS, mac_cntlr.status, 6) }, - { FLDATA (EOC, mac_cntlr.eoc, 0) }, - { FLDATA (EOD, mac_cntlr.eod, 0) }, - { ORDATA (SPDU, mac_cntlr.spd_unit, 16) }, - { ORDATA (FLMASK, mac_cntlr.file_mask, 4) }, - { ORDATA (RETRY, mac_cntlr.retry, 4), REG_HRO }, - { ORDATA (CYL, mac_cntlr.cylinder, 16) }, - { ORDATA (HEAD, mac_cntlr.head, 6) }, - { ORDATA (SECTOR, mac_cntlr.sector, 8) }, - { ORDATA (VFYCNT, mac_cntlr.verify_count, 16) }, - { ORDATA (LASPOL, mac_cntlr.poll_unit, 3) }, - { HRDATA (BUFPTR, mac_cntlr.buffer, 32), REG_HRO }, - { BRDATA (BUFFER, buffer, 8, 16, DL_BUFSIZE) }, - { DRDATA (INDEX, mac_cntlr.index, 8) }, - { DRDATA (LENGTH, mac_cntlr.length, 8) }, - { HRDATA (AUXPTR, mac_cntlr.aux, 32), REG_HRO }, - { DRDATA (STIME, mac_cntlr.seek_time, 24), PV_LEFT | REG_NZ }, - { DRDATA (ITIME, mac_cntlr.sector_time, 24), PV_LEFT | REG_NZ }, - { DRDATA (CTIME, mac_cntlr.cmd_time, 24), PV_LEFT | REG_NZ }, - { DRDATA (DTIME, mac_cntlr.data_time, 24), PV_LEFT | REG_NZ }, - { DRDATA (WTIME, mac_cntlr.wait_time, 31), PV_LEFT | REG_NZ }, - - { FLDATA (CTL, ds.control, 0) }, - { FLDATA (FLG, ds.flag, 0) }, - { FLDATA (FBF, ds.flagbuf, 0) }, - { FLDATA (SRQ, ds.srq, 0) }, - { FLDATA (EDT, ds.edt, 0) }, - - { URDATA (UCYL, ds_unit[0].CYL, 10, 10, 0, DS_UNITS, PV_LEFT) }, - { URDATA (UOP, ds_unit[0].OP, 8, 6, 0, DS_UNITS, PV_RZRO) }, - { URDATA (USTAT, ds_unit[0].STAT, 2, 8, 0, DS_UNITS, PV_RZRO) }, - { URDATA (UPHASE, ds_unit[0].PHASE, 8, 3, 0, DS_UNITS, PV_RZRO) }, - { URDATA (UPOS, ds_unit[0].pos, 8, T_ADDR_W, 0, DS_UNITS, PV_LEFT) }, - { URDATA (UWAIT, ds_unit[0].wait, 8, 32, 0, DS_UNITS, PV_LEFT) }, - - { ORDATA (SC, ds_dib.select_code, 6), REG_HRO }, - { ORDATA (DEVNO, ds_dib.select_code, 6), REG_HRO }, - { NULL } - }; - -static MTAB ds_mod [] = { -/* mask match pstring mstring valid disp desc */ - { UNIT_UNLOAD, UNIT_UNLOAD, "heads unloaded", "UNLOADED", &ds_load_unload, NULL, NULL }, - { UNIT_UNLOAD, 0, "heads loaded", "LOADED", &ds_load_unload, NULL, NULL }, - - { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL, NULL, NULL }, - { UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL, NULL, NULL }, - - { UNIT_FMT, UNIT_FMT, "format enabled", "FORMAT", NULL, NULL, NULL }, - { UNIT_FMT, 0, "format disabled", "NOFORMAT", NULL, NULL, NULL }, - -/* mask match pstring mstring valid disp desc */ - { UNIT_AUTO | UNIT_ATT, UNIT_AUTO, "autosize", "AUTOSIZE", &dl_set_model, NULL, NULL }, - { UNIT_AUTO | UNIT_ATT | UNIT_MODEL, MODEL_7905, "7905", "7905", &dl_set_model, NULL, NULL }, - { UNIT_AUTO | UNIT_ATT | UNIT_MODEL, MODEL_7906, "7906", "7906", &dl_set_model, NULL, NULL }, - { UNIT_AUTO | UNIT_ATT | UNIT_MODEL, MODEL_7920, "7920", "7920", &dl_set_model, NULL, NULL }, - { UNIT_AUTO | UNIT_ATT | UNIT_MODEL, MODEL_7925, "7925", "7925", &dl_set_model, NULL, NULL }, - { UNIT_ATT | UNIT_MODEL, UNIT_ATT | MODEL_7905, "7905", NULL, NULL, NULL, NULL }, - { UNIT_ATT | UNIT_MODEL, UNIT_ATT | MODEL_7906, "7906", NULL, NULL, NULL, NULL }, - { UNIT_ATT | UNIT_MODEL, UNIT_ATT | MODEL_7920, "7920", NULL, NULL, NULL, NULL }, - { UNIT_ATT | UNIT_MODEL, UNIT_ATT | MODEL_7925, "7925", NULL, NULL, NULL, NULL }, - - { MTAB_XTD | MTAB_VDV, 0, "SC", "SC", &hp_setsc, &hp_showsc, &ds_dev }, - { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &ds_dev }, - { 0 } - }; - -static DEBTAB ds_deb [] = { - { "CPU", DEB_CPU }, - { "CMDS", DEB_CMDS }, - { "BUF", DEB_BUF }, - { "RWSC", DEB_RWSC }, - { "SERV", DEB_SERV }, - { NULL, 0 } - }; - -DEVICE ds_dev = { - "DS", /* device name */ - ds_unit, /* unit array */ - ds_reg, /* register array */ - ds_mod, /* modifier array */ - DS_UNITS, /* number of units */ - 8, /* address radix */ - 27, /* address width = 128 MB */ - 1, /* address increment */ - 8, /* data radix */ - 16, /* data width */ - NULL, /* examine routine */ - NULL, /* deposit routine */ - &ds_reset, /* reset routine */ - &ds_boot, /* boot routine */ - &ds_attach, /* attach routine */ - &ds_detach, /* detach routine */ - &ds_dib, /* device information block */ - DEV_DEBUG | DEV_DISABLE, /* device flags */ - 0, /* debug control flags */ - ds_deb, /* debug flag name table */ - NULL, /* memory size change routine */ - NULL /* logical device name */ - }; - - - -/* MAC disc global VM routines */ - - -/* I/O signal handler. - - The 13175D disc interface data path consists of an input multiplexer/latch - and a 16-word FIFO buffer. The FIFO source may be either the CPU's I/O - input bus or the controller's interface data bus. The output of the FIFO may - be enabled either to the CPU's I/O output bus or the interface data bus. - - The control path consists of the usual control, flag buffer, flag, and SRQ - flip-flops, although flag and SRQ are decoupled to allow the full DCPC - transfer rate through the FIFO (driving SRQ from the flag limits transfers to - every other cycle). SRQ is based on the FIFO level: if data or room in the - FIFO is available, SRQ is set to initiate a transfer. The flag is only used - to signal an interrupt at the end of a command. - - One unusual aspect is that SFC and SFS test different things, rather than - complementary states of the same thing. SFC tests the controller busy state, - and SFS tests the flag flip-flop. - - In addition, the card contains end-of-data-transfer, command-follows, and - command-ready flip-flops. EDT is set when the DCPC EDT signal is asserted - and is used in conjunction with the FIFO level to assert the end-of-data - signal to the controller. The command-follows flip-flop is set by a CLC to - indicate that the next data word output from the CPU is a disc command. The - command-ready flip-flop is set when a command is received to schedule an - interface poll. - - - Implementation notes: - - 1. In hardware, SRQ is enabled only when the controller is reading or - writing the disc (IFIN or IFOUT functions are asserted) and set when the - FIFO is not empty (read) or not full (write). In simulation, SRQ is set - by the unit service read/write data phase transfers and cleared in the - IOI and IOO signal handlers when the FIFO is empty (read) or full - (write). - - 2. The DCPC EDT signal cannot set the controller's end-of-data flag directly - because a write EOD must occur only after the FIFO has been drained. - - 3. Polling the interface or drives must be deferred to the end of I/O signal - handling. If they are performed in the IOO/STC handlers themselves, an - associated CLF might clear the flag that was set by the poll. - - 4. Executing a CLC sets the controller's end-of-data flag, which will abort - a read or write data transfer in progress. Parameter transfers are not - affected. If a command is received when a parameter is expected, the - word is interpreted as data, even though the command-ready flip-flop is - set. The controller firmware only checks DTRDY for a parameter transfer, - and DTRDY is asserted whenever the FIFO is not empty. - - 5. The hardware Interface Function and Flag Buses are not implemented - explicitly. Instead, interface functions and signals are inferred by the - interface from the current command operation and phase. -*/ - -uint32 ds_io (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) -{ -static const char * const output_state [] = { "Data", "Command" }; -const char * const hold_or_clear = (signal_set & ioCLF ? ",C" : ""); - -uint16 data; -t_stat status; -IOSIGNAL signal; -IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ -t_bool command_issued = FALSE; -t_bool interrupt_enabled = FALSE; - -while (working_set) { - signal = IONEXT (working_set); /* isolate the next signal */ - - switch (signal) { /* dispatch the I/O signal */ - - case ioCLF: /* clear flag flip-flop */ - ds.flag = CLEAR; /* clear the flag */ - ds.flagbuf = CLEAR; /* and flag buffer */ - - if (DEBUG_PRI (ds_dev, DEB_CMDS)) - fputs (">>DS cmds: [CLF] Flag cleared\n", sim_deb); - break; - - - case ioSTF: /* set flag flip-flop */ - case ioENF: /* enable flag */ - ds.flag = SET; /* set the flag */ - ds.flagbuf = SET; /* and flag buffer */ - - if (DEBUG_PRI (ds_dev, DEB_CMDS)) - fputs (">>DS cmds: [STF] Flag set\n", sim_deb); - break; - - - case ioSFC: /* skip if flag is clear */ - setSKF (mac_cntlr.state != cntlr_busy); /* skip if the controller is not busy */ - break; - - - case ioSFS: /* skip if flag is set */ - setstdSKF (ds); /* assert SKF if the flag is set */ - break; - - - case ioIOI: /* I/O data input */ - data = fifo_unload (); /* unload the next word from the FIFO */ - stat_data = IORETURN (SCPE_OK, data); /* merge in the return status */ - - if (DEBUG_PRI (ds_dev, DEB_CPU)) - fprintf (sim_deb, ">>DS cpu: [LIx%s] Data = %06o\n", hold_or_clear, data); - - if (FIFO_EMPTY) { /* is the FIFO now empty? */ - if (ds.srq == SET && DEBUG_PRI (ds_dev, DEB_CMDS)) - fprintf (sim_deb, ">>DS cmds: [LIx%s] SRQ cleared\n", hold_or_clear); - - ds.srq = CLEAR; /* clear SRQ */ - - if (ds_cntlr.PHASE == data_phase) { /* is this an outbound parameter? */ - ds_cntlr.wait = mac_cntlr.data_time; /* activate the controller */ - activate_unit (&ds_cntlr); /* to acknowledge the data */ - } - } - break; - - - case ioIOO: /* I/O data output */ - data = IODATA (stat_data); /* mask to just the data word */ - - if (DEBUG_PRI (ds_dev, DEB_CPU)) - fprintf (sim_deb, ">>DS cpu: [OTx%s] %s = %06o\n", - hold_or_clear, output_state [ds.cmfol], data); - - fifo_load (data); /* load the word into the FIFO */ - - if (ds.cmfol == SET) { /* are we expecting a command? */ - ds.cmfol = CLEAR; /* clear the command follows flip-flop */ - ds.cmrdy = SET; /* set the command ready flip-flop */ - command_issued = TRUE; /* and request an interface poll */ - } - - else { /* not a command */ - if (ds_cntlr.PHASE == data_phase) { /* is this an inbound parameter? */ - ds_cntlr.wait = mac_cntlr.data_time; /* activate the controller */ - activate_unit (&ds_cntlr); /* to receive the data */ - } - - if (FIFO_STOP) { /* is the FIFO now full enough? */ - if (ds.srq == SET && DEBUG_PRI (ds_dev, DEB_CMDS)) - fprintf (sim_deb, ">>DS cmds: [OTx%s] SRQ cleared\n", hold_or_clear); - - ds.srq = CLEAR; /* clear SRQ to stop filling */ - } - } - break; - - - case ioPOPIO: /* power-on preset to I/O */ - ds.flag = SET; /* set the flag */ - ds.flagbuf = SET; /* and flag buffer */ - ds.cmrdy = CLEAR; /* clear the command ready flip-flop */ - - if (DEBUG_PRI (ds_dev, DEB_CMDS)) - fputs (">>DS cmds: [POPIO] Flag set\n", sim_deb); - break; - - - case ioCRS: /* control reset */ - if (DEBUG_PRI (ds_dev, DEB_CMDS)) - fputs (">>DS cmds: [CRS] Master reset\n", sim_deb); - - ds.control = CLEAR; /* clear the control */ - ds.cmfol = CLEAR; /* and command follows flip-flops */ - - if (PRESET_ENABLE) { /* is preset enabled for this interface? */ - fifo_clear (); /* clear the FIFO */ - - status = dl_clear_controller (&mac_cntlr, /* do a hard clear of the controller */ - ds_unit, hard_clear); - - stat_data = IORETURN (status, 0); /* return the status from the controller */ - } - break; - - - case ioCLC: /* clear control flip-flop */ - if (DEBUG_PRI (ds_dev, DEB_CMDS)) - fprintf (sim_deb, ">>DS cmds: [CLC%s] Control cleared\n", hold_or_clear); - - ds.control = CLEAR; /* clear the control */ - ds.edt = CLEAR; /* and EDT flip-flops */ - ds.cmfol = SET; /* set the command follows flip-flop */ - mac_cntlr.eod = SET; /* set the controller's EOD flag */ - - fifo_clear (); /* clear the FIFO */ - break; - - - case ioSTC: /* set control flip-flop */ - ds.control = SET; /* set the control flip-flop */ - - interrupt_enabled = TRUE; /* check for drive attention */ - - if (DEBUG_PRI (ds_dev, DEB_CMDS)) - fprintf (sim_deb, ">>DS cmds: [STC%s] Control set\n", hold_or_clear); - break; - - - case ioEDT: /* end data transfer */ - ds.edt = SET; /* set the EDT flip-flop */ - - if (DEBUG_PRI (ds_dev, DEB_CPU)) - fputs (">>DS cpu: [EDT] DCPC transfer ended\n", sim_deb); - break; - - - case ioSIR: /* set interrupt request */ - setstdPRL (ds); /* set the standard PRL signal */ - setstdIRQ (ds); /* set the standard IRQ signal */ - setSRQ (dibptr->select_code, ds.srq); /* set the SRQ signal */ - break; - - - case ioIAK: /* interrupt acknowledge */ - ds.flagbuf = CLEAR; /* clear the flag */ - break; - - - default: /* all other signals */ - break; /* are ignored */ - } - - working_set = working_set & ~signal; /* remove the current signal from the set */ - } - - -if (command_issued) /* was a command received? */ - poll_interface (); /* poll the interface for the next command */ -else if (interrupt_enabled) /* were interrupts enabled? */ - poll_drives (); /* poll the drives for Attention */ - -return stat_data; -} - - -/* Service the disc drive unit. - - The unit service routine is called to execute scheduled controller commands - for the specified unit. The actions to be taken depend on the current state - of the controller and the unit. - - Generally, the controller library service routine handles all of the disc - operations except data transfer to and from the interface. Read transfers - are responsible for loading words from the sector buffer into the FIFO and - enabling SRQ. If the current sector transfer is complete, either due to EDT - assertion or buffer exhaustion, the controller is moved to the end phase to - complete or continue the read with the next sector. In either case, the unit - is rescheduled. If the FIFO overflows, the read terminates with a data - overrun error. - - Write transfers set the initial SRQ to request words from the CPU. As each - word arrives, it is unloaded from the FIFO into the sector buffer, and SRQ is - enabled. If the current sector transfer is complete, the controller is moved - to the end phase. If the FIFO underflows, the write terminates with a data - overrun error. - - The synchronous nature of the disc drive requires that data be supplied or - accepted continuously by the CPU. DCPC generally assures that this occurs, - and the FIFO allows for some latency before an overrun or underrun occurs. - - The other operation the interface must handle is seek completion. The - controller handles seek completion by setting Attention status in the drive's - status word. The interface is responsible for polling the drives if the - controller is idle and interrupts are enabled. - - - Implementation notes: - - 1. Every command except Seek, Recalibrate, and End sets the flag when the - command completes. A command completes when the controller is no longer - busy (it becomes idle for Seek, Recalibrate, and End, or it becomes - waiting for all others). Seek and Recalibrate may generate errors (e.g., - heads unloaded), in which case the flag must be set. But in these cases, - the controller state is waiting, not idle. - - However, it is insufficient simply to check that the controller has moved - to the wait state, because a seek may complete while the controller is - waiting for the next command. For example, a Seek is started on unit 0, - and the controller moves to the idle state. But before the seek - completes, another command is issued that attempts to access unit 1, - which is not ready. The command fails with a Status-2 error, and the - controller moves to the wait state. When the seek completes, the - controller is waiting with error status. We must determine whether the - seek completed successfully or not, as we must interrupt in the latter - case. - - Therefore, we determine seek completion by checking if the Attention - status was set. Attention sets only if the seek completes successfully. - - (Actually, Attention sets if a seek check occurs, but in that case, the - command terminated before the seek ever started. Also, a seek may - complete while the controller is busy, waiting, or idle.) - - 2. For debug printouts, we want to print the name of the command that has - completed when the controller returns to the idle or wait state. - Normally, we would use the controller's "opcode" field to identify the - command that completed. However, while waiting for Seek or Recalibrate - completion, "opcode" may be set to another command if that command does - not access this drive. For example, it might be set to a Read of another - unit, or a Request Status for this unit. So we can't rely on "opcode" to - report the correct name of the completed positioning command. - - However, we cannot rely on "uptr->OP" either, as that can be changed - during the course of a command. For example, Read Without Verify is - changed to Read after a track crossing. - - Instead, we have to determine whether a seek is completing. If it is, - then we report "uptr->OP"; otherwise, we report "opcode". - - 3. The initial write SRQ must set only at the transition from the start - phase to the data phase. If a write command begins with an auto-seek, - the drive service will be entered twice in the start phase (the first - entry performs the seek, and the second begins the write). In hardware, - SRQ does not assert until the write begins. - - 4. The DCPC EDT signal cannot set the controller's end-of-data flag - directly because a write EOD must only occur after the FIFO has been - drained. -*/ - -t_stat ds_service_drive (UNIT *uptr) -{ -static const char completion_message [] = ">>DS rwsc: Unit %d %s command completed\n"; -t_stat result; -t_bool seek_completion; -int32 unit; -FLIP_FLOP entry_srq = ds.srq; /* get the SRQ state on entry */ -CNTLR_PHASE entry_phase = (CNTLR_PHASE) uptr->PHASE; /* get the operation phase on entry */ -uint32 entry_status = uptr->STAT; /* get the drive status on entry */ - -result = dl_service_drive (&mac_cntlr, uptr); /* service the drive */ - -if ((CNTLR_PHASE) uptr->PHASE == data_phase) /* is the drive in the data phase? */ - switch ((CNTLR_OPCODE) uptr->OP) { /* dispatch the current operation */ - - case read: /* read operations */ - case read_full_sector: - case read_with_offset: - case read_without_verify: - if (mac_cntlr.length == 0 || ds.edt == SET) { /* is the data phase complete? */ - mac_cntlr.eod = ds.edt; /* set EOD if DCPC is done */ - uptr->PHASE = end_phase; /* set the end phase */ - uptr->wait = mac_cntlr.cmd_time; /* and schedule the controller */ - } - - else if (FIFO_FULL) /* is the FIFO already full? */ - dl_end_command (&mac_cntlr, data_overrun); /* terminate the command with an overrun */ - - else { - fifo_load (buffer [mac_cntlr.index++]); /* load the next word into the FIFO */ - mac_cntlr.length--; /* count it */ - ds.srq = SET; /* ask DCPC to pick it up */ - ds_io (&ds_dib, ioSIR, 0); /* and recalculate the interrupts */ - uptr->wait = mac_cntlr.data_time; /* schedule the next data transfer */ - } - - break; - - - case write: /* write operations */ - case write_full_sector: - case initialize: - if (entry_phase == start_phase) { /* is this the phase transition? */ - ds.srq = SET; /* start the DCPC transfer */ - ds_io (&ds_dib, ioSIR, 0); /* and recalculate the interrupts */ - } - - else if (FIFO_EMPTY) /* is the FIFO empty? */ - dl_end_command (&mac_cntlr, data_overrun); /* terminate the command with an underrun */ - - else { - buffer [mac_cntlr.index++] = fifo_unload (); /* unload the next word from the FIFO */ - mac_cntlr.length--; /* count it */ - - if (ds.edt == SET && FIFO_EMPTY) /* if DCPC is complete and the FIFO is empty */ - mac_cntlr.eod = SET; /* then set the end-of-data flag */ - - if (mac_cntlr.length == 0 || mac_cntlr.eod == SET) { /* is the data phase complete? */ - uptr->PHASE = end_phase; /* set the end phase */ - uptr->wait = mac_cntlr.cmd_time; /* and schedule the controller */ - } - - else { - if (ds.edt == CLEAR) { /* if DCPC is still transferring */ - ds.srq = SET; /* then request the next word */ - ds_io (&ds_dib, ioSIR, 0); /* and recalculate the interrupts */ - } - - uptr->wait = mac_cntlr.data_time; /* schedule the next data transfer */ - } - } - - break; - - - default: /* we were entered with an invalid state */ - result = SCPE_IERR; /* return an internal (programming) error */ - break; - } /* end of data phase operation dispatch */ - - -if (DEBUG_PRI (ds_dev, DEB_CMDS) && entry_srq != ds.srq) - fprintf (sim_deb, ">>DS cmds: SRQ %s\n", ds.srq == SET ? "set" : "cleared"); - - -if (uptr->wait) /* was service requested? */ - activate_unit (uptr); /* schedule the next event */ - -seek_completion = ~entry_status & uptr->STAT & DL_S2ATN; /* seek is complete when Attention sets */ - -if (mac_cntlr.state != cntlr_busy) { /* is the command complete? */ - if (mac_cntlr.state == cntlr_wait && !seek_completion) /* is it command but not seek completion? */ - ds_io (&ds_dib, ioENF, 0); /* set the data flag to interrupt the CPU */ - - poll_interface (); /* poll the interface for the next command */ - poll_drives (); /* poll the drives for Attention */ - } - - -if (DEBUG_PRI (ds_dev, DEB_RWSC)) { - unit = uptr - ds_unit; /* get the unit number */ - - if (result == SCPE_IERR) /* did an internal error occur? */ - fprintf (sim_deb, ">>DS rwsc: Unit %d %s command %s phase service not handled\n", - unit, dl_opcode_name (MAC, (CNTLR_OPCODE) uptr->OP), - dl_phase_name ((CNTLR_PHASE) uptr->PHASE)); - - else if (seek_completion) /* if a seek has completed */ - fprintf (sim_deb, completion_message, /* report the unit command */ - unit, dl_opcode_name (MAC, (CNTLR_OPCODE) uptr->OP)); - - else if (mac_cntlr.state == cntlr_wait) /* if the controller has stopped */ - fprintf (sim_deb, completion_message, /* report the controller command */ - unit, dl_opcode_name (MAC, mac_cntlr.opcode)); - } - -return result; /* return the result of the service */ -} - - -/* Service the controller unit. - - The controller service routine is called to execute scheduled controller - commands that do not access drive units. It is also called to obtain command - parameters from the interface and to return command result values to the - interface. - - Most controller commands are handled completely in the library's service - routine, so we call that first. Commands that neither accept nor supply - parameters are complete when the library routine returns, so all we have to - do is set the interface flag if required. - - For parameter transfers in the data phase, the interface is responsible for - moving words between the sector buffer and the FIFO and setting the flag to - notify the CPU. - - - Implementation notes: - - 1. In hardware, the Read With Offset command sets the data flag after the - offset parameter has been read and the head positioner has been moved by - the indicated amount. The intent is to delay the DCPC start until the - drive is ready to supply data from the disc. - - In simulation, the flag is set as soon as the parameter is received. -*/ - -t_stat ds_service_controller (UNIT *uptr) -{ -t_stat result; -const CNTLR_OPCODE opcode = (CNTLR_OPCODE) uptr->OP; - -result = dl_service_controller (&mac_cntlr, uptr); /* service the controller */ - -switch ((CNTLR_PHASE) uptr->PHASE) { /* dispatch the current phase */ - - case start_phase: /* most controller operations */ - case end_phase: /* start and end on the same phase */ - switch (opcode) { /* dispatch the current operation */ - - case request_status: - case request_sector_address: - case address_record: - case request_syndrome: - case load_tio_register: - case request_disc_address: - case end: - break; /* complete the operation without setting the flag */ - - - case clear: - case set_file_mask: - case wakeup: - ds_io (&ds_dib, ioENF, 0); /* complete the operation and set the flag */ - break; - - - default: /* we were entered with an invalid state */ - result = SCPE_IERR; /* return an internal (programming) error */ - break; - } /* end of operation dispatch */ - break; /* end of start and end phase handlers */ - - - case data_phase: - switch (opcode) { /* dispatch the current operation */ - - case seek: /* operations that accept parameters */ - case verify: - case address_record: - case read_with_offset: - case load_tio_register: - buffer [mac_cntlr.index++] = fifo_unload (); /* unload the next word from the FIFO */ - mac_cntlr.length--; /* count it */ - - if (mac_cntlr.length) /* are there more words to transfer? */ - ds_io (&ds_dib, ioENF, 0); /* set the flag to request the next one */ - - else { /* all parameters have been received */ - uptr->PHASE = end_phase; /* set the end phase */ - - if (opcode == read_with_offset) /* a Read With Offset command sets the flag */ - ds_io (&ds_dib, ioENF, 0); /* to indicate that offsetting is complete */ - - start_command (); /* the command is now ready to execute */ - } - break; - - - case request_status: /* operations that supply parameters */ - case request_sector_address: - case request_syndrome: - case request_disc_address: - if (mac_cntlr.length) { /* are there more words to return? */ - fifo_load (buffer [mac_cntlr.index++]); /* load the next word into the FIFO */ - mac_cntlr.length--; /* count it */ - - ds_io (&ds_dib, ioENF, 0); /* set the flag to request pickup by the CPU */ - } - - else { /* all parameters have been sent */ - uptr->PHASE = end_phase; /* set the end phase */ - uptr->wait = mac_cntlr.cmd_time; /* schedule the controller */ - activate_unit (uptr); /* to complete the command */ - } - break; - - - default: /* we were entered with an invalid state */ - result = SCPE_IERR; /* return an internal (programming) error */ - break; - } /* end of operation dispatch */ - break; /* end of data phase handlers */ - } /* end of phase dispatch */ - - -if (result == SCPE_IERR && DEBUG_PRI (ds_dev, DEB_RWSC)) /* did an internal error occur? */ - fprintf (sim_deb, ">>DS rwsc: Controller %s command %s phase service not handled\n", - dl_opcode_name (MAC, opcode), dl_phase_name ((CNTLR_PHASE) uptr->PHASE)); - - -if (mac_cntlr.state != cntlr_busy) { /* has the controller stopped? */ - poll_interface (); /* poll the interface for the next command */ - poll_drives (); /* poll the drives for Attention status */ - - if (DEBUG_PRI (ds_dev, DEB_RWSC)) - fprintf (sim_deb, ">>DS rwsc: Controller %s command completed\n", - dl_opcode_name (MAC, opcode)); - } - -return result; /* return the result of the service */ -} - - -/* Service the command wait timer unit. - - The command wait timer service routine is called if the command wait timer - expires. The library is called to reset the file mask and idle the - controller. Then the interface is polled for a command and the drives are - polled for Attention status. -*/ - -t_stat ds_service_timer (UNIT *uptr) -{ -t_stat result; - -result = dl_service_timer (&mac_cntlr, uptr); /* service the timer */ - -poll_interface (); /* poll the interface for the next command */ -poll_drives (); /* poll the drives for Attention status */ - -return result; /* return the result of the service */ -} - - -/* Reset the simulator. - - In hardware, the PON signal clears the Interface Selected flip-flop, - disconnecting the interface from the disc controller. In simulation, the - interface always remains connected to the controller, so no special action is - needed. - - - Implementation notes: - - 1. During a power-on reset, a pointer to the FIFO simulation register is - saved to allow access to the "qptr" field during FIFO loading and - unloading. This enables SCP to view the FIFO as a circular queue, so - that the bottom word of the FIFO is always displayed as FIFO[0], - regardless of where it is in the actual FIFO array. - - 2. SRQ is denied because neither IFIN nor IFOUT is asserted when the - interface is not selected. -*/ - -t_stat ds_reset (DEVICE *dptr) -{ -uint32 unit; - -if (sim_switches & SWMASK ('P')) { /* is this a power-on reset? */ - ds.fifo_reg = find_reg ("FIFO", NULL, dptr); /* find the FIFO register entry */ - - if (ds.fifo_reg == NULL) /* if it cannot be found, */ - return SCPE_IERR; /* report a programming error */ - - else { /* found it */ - ds.fifo_reg->qptr = 0; /* so reset the FIFO bottom index */ - ds.fifo_count = 0; /* and clear the FIFO */ - } - - for (unit = 0; unit < dptr->numunits; unit++) { /* loop through all of the units */ - sim_cancel (dptr->units + unit); /* cancel activation */ - dptr->units [unit].CYL = 0; /* reset the head position to cylinder 0 */ - dptr->units [unit].pos = 0; /* (irrelevant for the controller and timer) */ - } - } - -IOPRESET (&ds_dib); /* PRESET the device */ -ds.srq = CLEAR; /* clear SRQ */ - -return SCPE_OK; -} - - -/* Attach a drive unit. - - The specified file is attached to the indicated drive unit. The library - attach routine will load the heads. This will set the First Status and - Attention bits in the drive status, so we poll the drives to ensure that the - CPU is notified that the drive is now online. - - - Implementation notes: - - 1. If we are called during a RESTORE command, the drive status will not be - changed, so polling the drives will have no effect. -*/ - -t_stat ds_attach (UNIT *uptr, char *cptr) -{ -t_stat result; - -result = dl_attach (&mac_cntlr, uptr, cptr); /* attach the drive */ - -if (result == SCPE_OK) /* was the attach successful? */ - poll_drives (); /* poll the drives to notify the CPU */ - -return result; -} - - -/* Detach a drive unit. - - The specified file is detached from the indicated drive unit. The library - detach routine will unload the heads. This will set the Attention bit in the - drive status, so we poll the drives to ensure that the CPU is notified that - the drive is now offline. -*/ - -t_stat ds_detach (UNIT *uptr) -{ -t_stat result; - -result = dl_detach (&mac_cntlr, uptr); /* detach the drive */ - -if (result == SCPE_OK) /* was the detach successful? */ - poll_drives (); /* poll the drives to notify the CPU */ - -return result; -} - - -/* Boot a MAC disc drive. - - The MAC disc bootstrap program is loaded from the HP 12992B Boot Loader ROM - into memory, the I/O instructions are configured for the interface card's - select code, and the program is run to boot from the specified unit. The - loader supports booting from cylinder 0 of drive unit 0 only. Before - execution, the S register is automatically set as follows: - - 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 - ------ ------ ---------------------- --------- --------- - ROM # 0 1 select code reserved head - - The boot routine sets bits 15-6 of the S register to appropriate values. - Bits 5-3 and 1-0 retain their original values, so S should be set before - booting. These bits are typically set to 0, although bit 5 is set for an RTE - reconfiguration boot, and bits 1-0 may be set if booting from a head other - than 0 is desired. - - - Implementation notes: - - 1. The Loader ROMs manual indicates that bits 2-0 select the head to use, - implying that heads 0-7 are valid. However, Table 5 has entries only for - heads 0-3, and the boot loader code will malfunction if heads 4-7 are - specified. The code masks the head number to three bits but forms the - Cold Load Read command by shifting the head number six bits to the left. - As the head field in the command is only two bits wide, specifying heads - 4-7 will result in bit 2 being shifted into the opcode field, resulting - in a Recalibrate command. -*/ - - -const BOOT_ROM ds_rom = { - 0017727, /* START JSB STAT GET STATUS */ - 0002021, /* SSA,RSS IS DRIVE READY ? */ - 0027742, /* JMP DMA YES, SET UP DMA */ - 0013714, /* AND B20 NO, CHECK STATUS BITS */ - 0002002, /* SZA IS DRIVE FAULTY OR HARD DOWN ? */ - 0102030, /* HLT 30B YES, HALT 30B, "RUN" TO TRY AGAIN */ - 0027700, /* JMP START NO, TRY AGAIN FOR DISC READY */ - 0102011, /* ADDR1 OCT 102011 */ - 0102055, /* ADDR2 OCT 102055 */ - 0164000, /* CNT DEC -6144 */ - 0000007, /* D7 OCT 7 */ - 0001400, /* STCMD OCT 1400 */ - 0000020, /* B20 OCT 20 */ - 0017400, /* STMSK OCT 17400 */ - 0000000, /* NOP */ - 0000000, /* NOP */ - 0000000, /* NOP */ - 0000000, /* NOP */ - 0000000, /* NOP */ - 0000000, /* NOP */ - 0000000, /* NOP */ - 0000000, /* NOP */ - 0000000, /* NOP */ - 0000000, /* STAT NOP STATUS CHECK SUBROUTINE */ - 0107710, /* CLC DC,C SET STATUS COMMAND MODE */ - 0063713, /* LDA STCMD GET STATUS COMMAND */ - 0102610, /* OTA DC OUTPUT STATUS COMMAND */ - 0102310, /* SFS DC WAIT FOR STATUS#1 WORD */ - 0027733, /* JMP *-1 */ - 0107510, /* LIB DC,C B-REG = STATUS#1 WORD */ - 0102310, /* SFS DC WAIT FOR STATUS#2 WORD */ - 0027736, /* JMP *-1 */ - 0103510, /* LIA DC,C A-REG = STATUS#2 WORD */ - 0127727, /* JMP STAT,I RETURN */ - 0067776, /* DMA LDB DMACW GET DMA CONTROL WORD */ - 0106606, /* OTB 6 OUTPUT DMA CONTROL WORD */ - 0067707, /* LDB ADDR1 GET MEMORY ADDRESS */ - 0106702, /* CLC 2 SET MEMORY ADDRESS INPUT MODE */ - 0106602, /* OTB 2 OUTPUT MEMORY ADDRESS TO DMA */ - 0102702, /* STC 2 SET WORD COUNT INPUT MODE */ - 0067711, /* LDB CNT GET WORD COUNT */ - 0106602, /* OTB 2 OUTPUT WORD COUNT TO DMA */ - 0106710, /* CLDLD CLC DC SET COMMAND INPUT MODE */ - 0102501, /* LIA 1 LOAD SWITCH */ - 0106501, /* LIB 1 REGISTER SETTINGS */ - 0013712, /* AND D7 ISOLATE HEAD NUMBER */ - 0005750, /* BLF,CLE,SLB BIT 12=0? */ - 0027762, /* JMP *+3 NO,MANUAL BOOT */ - 0002002, /* SZA YES,RPL BOOT. HEAD#=0? */ - 0001000, /* ALS NO,HEAD#1, MAKE HEAD#=2 */ - 0001720, /* ALF,ALS FORM COLD LOAD */ - 0001000, /* ALS COMMAND WORD */ - 0103706, /* STC 6,C ACTIVATE DMA */ - 0103610, /* OTA DC,C OUTPUT COLD LOAD COMMAND */ - 0102310, /* SFS DC IS COLD LOAD COMPLETED ? */ - 0027766, /* JMP *-1 NO, WAIT */ - 0017727, /* JSB STAT YES, GET STATUS */ - 0060001, /* LDA 1 */ - 0013715, /* AND STMSK A-REG = STATUS BITS OF STATUS#1 WD */ - 0002002, /* SZA IS TRANSFER OK ? */ - 0027700, /* JMP START NO,TRY AGAIN */ - 0117710, /* EXIT JSB ADDR2,I YES, EXEC LOADED PROGRAM _@ 2055B */ - 0000010, /* DMACW ABS DC */ - 0170100, /* ABS -START */ - }; - -t_stat ds_boot (int32 unitno, DEVICE *dptr) -{ -if (unitno != 0) /* boot supported on drive unit 0 only */ - return SCPE_NOFNC; /* report "Command not allowed" if attempted */ - -if (ibl_copy (ds_rom, ds_dib.select_code)) /* copy the boot ROM to memory and configure */ - return SCPE_IERR; /* return an internal error if the copy failed */ - -SR = SR & (IBL_OPT | IBL_DS_HEAD) /* set S to a reasonable value */ - | IBL_DS | IBL_MAN | (ds_dib.select_code << IBL_V_DEV); /* before boot execution */ - -return SCPE_OK; -} - - - -/* MAC disc global SCP routines */ - - -/* Load or unload the drive heads. - - The SCP command SET DSn UNLOADED simulates setting the hardware RUN/STOP - switch to STOP. The heads are unloaded, and the drive is spun down. - - The SET DSn LOADED command simulates setting the switch to RUN. The drive is - spun up, and the heads are loaded. - - The library handles command validation and setting the appropriate drive unit - status. -*/ - -t_stat ds_load_unload (UNIT *uptr, int32 value, char *cptr, void *desc) -{ -const t_bool load = (value != UNIT_UNLOAD); /* true if the heads are loading */ - -return dl_load_unload (&mac_cntlr, uptr, load); /* load or unload the heads */ -} - - - -/* MAC disc local utility routines */ - - -/* Start a command. - - The previously prepared command is executed by calling the corresponding - library routine. On entry, the controller's opcode field contains the - command to start, and the buffer contains the command word in element 0 and - the parameters required by the command, if any, beginning in element 1. - - If the command started, the returned pointer will point at the unit to - activate (if that unit's "wait" field is non-zero). If the returned pointer - is NULL, the command failed to start, and the controller status has been set - to indicate the reason. The interface flag is set to notify the CPU of the - failure. - - - Implementation notes: - - 1. If a command that accesses the drive is attempted on a drive currently - seeking, the returned pointer will be valid, but the unit's "wait" time - will be zero. The unit must not be activated (as it already is active). - When the seek completes, the command will be executed automatically. - - If a Seek or Cold Load Read command is attempted on a drive currently - seeking, seek completion will occur normally, but Seek Check status will - be set. - - 2. For debug printouts, we want to print the name of the command (Seek or - Recalibrate) in progress when a new command is started. However, when - the library routine returns, the unit operation and controller opcode - have been changed to reflect the new command. Therefore, we must record - the operation in progress before calling the library. - - The problem is in determining which unit's operation code to record. We - cannot blindly use the unit field from the new command, as recorded in - the controller, as preparation has ensured only that the target unit - number is legal but not necessarily valid. Therefore, we must validate - the unit number before accessing the unit's operation code. - - If the unit number is invalid, the command will not start, but the - compiler does not know this. Therefore, we must ensure that the saved - operation code is initialized, or a "variable used uninitialized" warning - will occur. -*/ - -static void start_command (void) -{ -int32 unit, time; -UNIT *uptr; -CNTLR_OPCODE drive_command; - -unit = GET_S1UNIT (mac_cntlr.spd_unit); /* get the (prepared) unit from the command */ - -if (unit <= DL_MAXDRIVE) /* is the unit number valid? */ - drive_command = (CNTLR_OPCODE) ds_unit [unit].OP; /* get the opcode from the unit that will be used */ -else /* the unit is invalid, so the command will not start */ - drive_command = end; /* but the compiler doesn't know this! */ - -uptr = dl_start_command (&mac_cntlr, ds_unit, DL_MAXDRIVE); /* ask the controller to start the command */ - -if (uptr) { /* did the command start? */ - time = uptr->wait; /* save the activation time */ - - if (time) /* was the unit scheduled? */ - activate_unit (uptr); /* activate it (and clear the "wait" field) */ - - if (DEBUG_PRI (ds_dev, DEB_RWSC)) { - unit = uptr - ds_unit; /* get the unit number */ - - if (time == 0) /* was the unit busy? */ - fprintf (sim_deb, ">>DS rwsc: Unit %d %s in progress\n", - unit, dl_opcode_name (MAC, drive_command)); - - fputs (">>DS rwsc: ", sim_deb); - - if (unit > DL_MAXDRIVE) - fputs ("Controller ", sim_deb); - else - fprintf (sim_deb, "Unit %d position %d ", unit, uptr->pos); - - fprintf (sim_deb, "%s command initiated\n", - dl_opcode_name (MAC, mac_cntlr.opcode)); - } - } - -else /* the command failed to start */ - ds_io (&ds_dib, ioENF, 0); /* so set the flag to notify the CPU */ - -return; -} - - -/* Poll the interface for a new command. - - If a new command is available, and the controller is not busy, prepare the - command for execution. If preparation succeeded, and the command needs - parameters before executing, set the flag to request the first one from the - CPU. If no parameters are needed, the command is ready to execute. - - If preparation failed, set the flag to notify the CPU. The controller - status contains the reason for the failure. -*/ - -static void poll_interface (void) -{ -if (ds.cmrdy == SET && mac_cntlr.state != cntlr_busy) { /* are the interface and controller ready? */ - buffer [0] = fifo_unload (); /* unload the command into the buffer */ - - if (dl_prepare_command (&mac_cntlr, ds_unit, DL_MAXDRIVE)) { /* prepare the command; did it succeed? */ - if (mac_cntlr.length) /* does the command require parameters? */ - ds_io (&ds_dib, ioENF, 0); /* set the flag to request the first one */ - else /* if not waiting for parameters */ - start_command (); /* start the command */ - } - - else /* preparation failed */ - ds_io (&ds_dib, ioENF, 0); /* so set the flag to notify the CPU */ - - ds.cmrdy = CLEAR; /* flush the command from the interface */ - } - -return; -} - - -/* Poll the drives for attention requests. - - If the controller is idle and interrupts are allowed, the drives are polled - to see if any drive is requesting attention. If one is found, the controller - resets that drive's Attention status, saves the drive's unit number, sets - Drive Attention status, and waits for a command from the CPU. The interface - sets the flag to notify the CPU. -*/ - -void poll_drives (void) -{ -if (mac_cntlr.state == cntlr_idle && ds.control == SET) /* is the controller idle and interrupts are allowed? */ - if (dl_poll_drives (&mac_cntlr, ds_unit, DL_MAXDRIVE)) /* poll the drives; was Attention seen? */ - ds_io (&ds_dib, ioENF, 0); /* request an interrupt */ -return; -} - - -/* Load a word into the FIFO. - - A word is loaded into the next available location in the FIFO, and the FIFO - occupancy count is incremented. If the FIFO is full on entry, the load is - ignored. - - - Implementation notes: - - 1. The FIFO is implemented as circular queue to take advantage of REG_CIRC - EXAMINE semantics. REG->qptr is the index of the first word currently in - the FIFO. By specifying REG_CIRC, examining FIFO[0-n] will always - display the words in load order, regardless of the actual array index of - the start of the list. The number of words currently present in the FIFO - is kept in fifo_count (0 = empty, 1-16 = number of words available). - - If fifo_count < FIFO_SIZE, (REG->qptr + fifo_count) mod FIFO_SIZE is the - index of the new word location. Loading stores the word there and then - increments fifo_count. - - 2. Because the load and unload routines need access to qptr in the REG - structure for the FIFO array, a pointer to the REG is stored in the - fifo_reg variable during device reset. -*/ - -static void fifo_load (uint16 data) -{ -uint32 index; - -if (FIFO_FULL) { /* is the FIFO already full? */ - if (DEBUG_PRI (ds_dev, DEB_BUF)) - fprintf (sim_deb, ">>DS buf: Attempted load to full FIFO, data %06o\n", data); - - return; /* return with the load ignored */ - } - -index = (ds.fifo_reg->qptr + ds.fifo_count) % FIFO_SIZE; /* calculate the index of the next available location */ - -ds.fifo [index] = data; /* store the word in the FIFO */ -ds.fifo_count = ds.fifo_count + 1; /* increment the count of words stored */ - -if (DEBUG_PRI (ds_dev, DEB_BUF)) - fprintf (sim_deb, ">>DS buf: Data %06o loaded into FIFO (%d)\n", - data, ds.fifo_count); - -return; -} - - -/* Unload a word from the FIFO. - - A word is unloaded from the first location in the FIFO, and the FIFO - occupancy count is decremented. If the FIFO is empty on entry, the unload - returns dummy data. - - - Implementation notes: - - 1. If fifo_count > 0, REG->qptr is the index of the word to remove. Removal - gets the word and then increments qptr (mod FIFO_SIZE) and decrements - fifo_count. -*/ - -static uint16 fifo_unload (void) -{ -uint16 data; - -if (FIFO_EMPTY) { /* is the FIFO already empty? */ - if (DEBUG_PRI (ds_dev, DEB_BUF)) - fputs (">>DS buf: Attempted unload from empty FIFO\n", sim_deb); - - return 0; /* return with no data */ - } - -data = ds.fifo [ds.fifo_reg->qptr]; /* get the word from the FIFO */ - -ds.fifo_reg->qptr = (ds.fifo_reg->qptr + 1) % FIFO_SIZE; /* update the FIFO queue pointer */ -ds.fifo_count = ds.fifo_count - 1; /* decrement the count of words stored */ - -if (DEBUG_PRI (ds_dev, DEB_BUF)) - fprintf (sim_deb, ">>DS buf: Data %06o unloaded from FIFO (%d)\n", - data, ds.fifo_count); - -return data; -} - - -/* Clear the FIFO. - - The FIFO is cleared by setting the occupancy counter to zero. -*/ - -static void fifo_clear (void) -{ -ds.fifo_count = 0; /* clear the FIFO */ - -if (DEBUG_PRI (ds_dev, DEB_BUF)) - fputs (">>DS buf: FIFO cleared\n", sim_deb); - -return; -} - - -/* Activate the unit. - - The specified unit is activated using the unit's "wait" time. If debugging - is enabled, the activation is logged to the debug file. -*/ - -static t_stat activate_unit (UNIT *uptr) -{ -int32 unit; -t_stat result; - -if (DEBUG_PRI (ds_dev, DEB_SERV)) { - unit = uptr - ds_unit; /* calculate the unit number */ - - if (uptr == &ds_cntlr) - fprintf (sim_deb, ">>DS serv: Controller delay %d service scheduled\n", - uptr->wait); - else - fprintf (sim_deb, ">>DS serv: Unit %d delay %d service scheduled\n", - unit, uptr->wait); - } - -result = sim_activate (uptr, uptr->wait); /* activate the unit */ -uptr->wait = 0; /* reset the activation time */ - -return result; /* return the activation status */ -} +/* hp2100_ds.c: HP 13037D/13175D disc controller/interface simulator + + Copyright (c) 2004-2012, Robert M. Supnik + Copyright (c) 2012-2014 J. David Bryan + + 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 + THE AUTHORS 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 names of the authors shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from the authors. + + DS 13037D/13175D disc controller/interface + + 30-Dec-14 JDB Added S-register parameters to ibl_copy + 24-Dec-14 JDB Use T_ADDR_FMT with t_addr values for 64-bit compatibility + 18-Mar-13 JDB Fixed poll_drives definition to match declaration + 24-Oct-12 JDB Changed CNTLR_OPCODE to title case to avoid name clash + 29-Mar-12 JDB Rewritten to use the MAC/ICD disc controller library + ioIOO now notifies controller service of parameter output + 14-Feb-12 JDB Corrected SRQ generation and FIFO under/overrun detection + Corrected Clear command to conform to the hardware + Fixed Request Status to return Unit Unavailable if illegal + Seek and Cold Load Read now Seek Check if seek in progress + Remodeled command wait for seek completion + 10-Feb-12 JDB Deprecated DEVNO in favor of SC + 21-Jun-11 JDB Corrected status returns for disabled drive, auto-seek + beyond drive limits, Request Sector Address and Wakeup + with invalid or offline unit + Address verification reenabled if auto-seek during + Read Without Verify + 28-Mar-11 JDB Tidied up signal handling + 26-Oct-10 JDB Changed I/O signal handler for revised signal model + 26-Jun-08 JDB Rewrote device I/O to model backplane signals + 31-Dec-07 JDB Corrected and verified ioCRS action + 20-Dec-07 JDB Corrected DPTR register definition from FLDATA to DRDATA + 28-Dec-06 JDB Added ioCRS state to I/O decoders + 03-Aug-06 JDB Fixed REQUEST STATUS command to clear status-1 + Removed redundant attached test in "ds_detach" + 18-Mar-05 RMS Added attached test to detach routine + 01-Mar-05 JDB Added SET UNLOAD/LOAD + + References: + - 13037 Disc Controller Technical Information Package (13037-90902, Aug-1980) + - 7925D Disc Drive Service Manual (07925-90913, Apr-1984) + - HP 12992 Loader ROMs Installation Manual (12992-90001, Apr-1986) + - DVR32 RTE Moving Head Driver source (92084-18711, Revision 5000) + + + The 13037D multiple-access (MAC) disc controller supports from one to eight + HP 7905 (15 MB), 7906 (20MB), 7920 (50 MB), and 7925 (120 MB) disc drives + accessed by one to eight CPUs. The controller hardware consists of a 16-bit + microprogrammed processor constructed from 74S181 bit slices operating at 5 + MHz, a device controller providing the interconnections to the drives and CPU + interfaces, and an error correction controller that enables the correction of + up to 32-bit error bursts. 1024 words of 24-bit firmware are stored in ROM. + + The 13175D disc interface is used to connect the HP 1000 CPU to the 13037 + device controller. In a multiple-CPU system, one interface is strapped to + reset the controller when the CPU's front panel PRESET button is pressed. + + This module simulates a 13037D connected to a single 13175D interface. From + one to eight drives may be connected, and drive types may be freely + intermixed. A unit that is enabled but not attached appears to be a + connected drive that does not have a disc pack in place. A unit that is + disabled appears to be disconnected. + + This simulator is an adaptation of the code originally written by Bob Supnik. + The functions of the controller have been separated from the functions of the + interface, with the former placed into a separate disc controller library. + This allows the library to support other CPU interfaces, such as the 12821A + HP-IB disc interface, that use substantially different communication + protocols. The library functions implement the controller command set for + the drive units. The interface functions handle the transfer of commands and + data to and from the CPU. + + In hardware, the controller runs continuously in one of three states: in the + Poll Loop (idle state), in the Command Wait Loop (wait state), or in command + execution (busy state). In simulation, the controller is run only when a + command is executing or when a transition into or out of the two loops might + occur. Internally, the controller handles these transitions: + + - when a command other than End terminates (busy => wait) + - when the End command terminates (busy => idle) + - when a command timeout occurs (wait => idle) + - when a parameter timeout occurs (busy => idle) + - when a seek completes (if idle and interrupts are enabled, idle => wait) + + The interface must call the controller library to handle these transitions: + + - when a command is received from the CPU (idle or wait => busy) + - when interrupts are enabled (if idle and drive Attention, idle => wait) + + In addition, each transition to the wait state must check for a pending + command, and each transition to the idle state must check for both a pending + command and a drive with Attention status asserted. + + + Implementation notes: + + 1. Although the 13175D has a 16-word FIFO, the "full" level is set at 5 + entries in hardware to avoid a long DCPC preemption time at the start of + a disc write as the FIFO fills. +*/ + + + +#include "hp2100_defs.h" +#include "hp_disclib.h" + + + +/* Program constants */ + +#define DS_DRIVES (DL_MAXDRIVE + 1) /* number of disc drive units */ +#define DS_UNITS (DS_DRIVES + DL_AUXUNITS) /* total number of units */ + +#define ds_cntlr ds_unit [DL_MAXDRIVE + 1] /* controller unit alias */ + +#define FIFO_SIZE 16 /* FIFO depth */ + +#define FIFO_EMPTY (ds.fifo_count == 0) /* FIFO empty test */ +#define FIFO_STOP (ds.fifo_count >= 5) /* FIFO stop filling test */ +#define FIFO_FULL (ds.fifo_count == FIFO_SIZE) /* FIFO full test */ + +#define PRESET_ENABLE TRUE /* Preset Jumper (W4) is enabled */ + + +/* Debug flags */ + +#define DEB_CPU (1 << 0) /* words received from and sent to the CPU */ +#define DEB_CMDS (1 << 1) /* interface commands received from the CPU */ +#define DEB_BUF (1 << 2) /* data read from and written to the card FIFO */ +#define DEB_RWSC (1 << 3) /* device read/write/status/control commands */ +#define DEB_SERV (1 << 4) /* unit service scheduling calls */ + + + +/* Per-card state variables */ + +typedef struct { + FLIP_FLOP control; /* control flip-flop */ + FLIP_FLOP flag; /* flag flip-flop */ + FLIP_FLOP flagbuf; /* flag buffer flip-flop */ + FLIP_FLOP srq; /* SRQ flip-flop */ + FLIP_FLOP edt; /* EDT flip-flop */ + FLIP_FLOP cmfol; /* command follows flip-flop */ + FLIP_FLOP cmrdy; /* command ready flip-flop */ + uint16 fifo [FIFO_SIZE]; /* FIFO buffer */ + uint32 fifo_count; /* FIFO occupancy counter */ + REG *fifo_reg; /* FIFO register pointer */ + } CARD_STATE; + + +/* MAC disc state variables */ + +static UNIT ds_unit [DS_UNITS]; /* unit array */ + +static CARD_STATE ds; /* card state */ + +static uint16 buffer [DL_BUFSIZE]; /* command/status/sector buffer */ + +static CNTLR_VARS mac_cntlr = /* MAC controller */ + { CNTLR_INIT (MAC, buffer, &ds_cntlr) }; + + + +/* MAC disc global VM routines */ + +IOHANDLER ds_io; +t_stat ds_service_drive (UNIT *uptr); +t_stat ds_service_controller (UNIT *uptr); +t_stat ds_service_timer (UNIT *uptr); +t_stat ds_reset (DEVICE *dptr); +t_stat ds_attach (UNIT *uptr, char *cptr); +t_stat ds_detach (UNIT *uptr); +t_stat ds_boot (int32 unitno, DEVICE *dptr); + +/* MAC disc global SCP routines */ + +t_stat ds_load_unload (UNIT *uptr, int32 value, char *cptr, void *desc); + +/* MAC disc local utility routines */ + +static void start_command (void); +static void poll_interface (void); +static void poll_drives (void); +static void fifo_load (uint16 data); +static uint16 fifo_unload (void); +static void fifo_clear (void); +static t_stat activate_unit (UNIT *uptr); + + + +/* MAC disc VM data structures. + + ds_dib DS device information block + ds_unit DS unit list + ds_reg DS register list + ds_mod DS modifier list + ds_deb DS debug table + ds_dev DS device descriptor + + For the drive models, the modifiers provide this SHOW behavior: + + - when detached and autosized, prints "autosize" + - when detached and not autosized, prints the model number + - when attached, prints the model number (regardless of autosizing) + + + Implementation notes: + + 1. The validation routine does not allow the model number or autosizing + option to be changed when the unit is attached. Therefore, specifying + UNIT_ATT in the mask field has no adverse effect. + + 2. The modifier DEVNO is deprecated in favor of SC but is retained for + compatibility. +*/ + + +DEVICE ds_dev; + +static DIB ds_dib = { &ds_io, DS }; + +#define UNIT_FLAGS (UNIT_FIX | UNIT_ATTABLE | UNIT_ROABLE | UNIT_DISABLE | UNIT_UNLOAD) + +static UNIT ds_unit [] = { + { UDATA (&ds_service_drive, UNIT_FLAGS | MODEL_7905, D7905_WORDS) }, /* drive unit 0 */ + { UDATA (&ds_service_drive, UNIT_FLAGS | MODEL_7905, D7905_WORDS) }, /* drive unit 1 */ + { UDATA (&ds_service_drive, UNIT_FLAGS | MODEL_7905, D7905_WORDS) }, /* drive unit 2 */ + { UDATA (&ds_service_drive, UNIT_FLAGS | MODEL_7905, D7905_WORDS) }, /* drive unit 3 */ + { UDATA (&ds_service_drive, UNIT_FLAGS | MODEL_7905, D7905_WORDS) }, /* drive unit 4 */ + { UDATA (&ds_service_drive, UNIT_FLAGS | MODEL_7905, D7905_WORDS) }, /* drive unit 5 */ + { UDATA (&ds_service_drive, UNIT_FLAGS | MODEL_7905, D7905_WORDS) }, /* drive unit 6 */ + { UDATA (&ds_service_drive, UNIT_FLAGS | MODEL_7905, D7905_WORDS) }, /* drive unit 7 */ + { UDATA (&ds_service_controller, UNIT_DIS, 0) }, /* controller unit */ + { UDATA (&ds_service_timer, UNIT_DIS, 0) } /* timer unit */ + }; + +static REG ds_reg [] = { + { FLDATA (CMFOL, ds.cmfol, 0) }, + { FLDATA (CMRDY, ds.cmrdy, 0) }, + { DRDATA (FCNT, ds.fifo_count, 5) }, + { BRDATA (FIFO, ds.fifo, 8, 16, FIFO_SIZE), REG_CIRC }, + { ORDATA (FREG, ds.fifo_reg, 32), REG_HRO }, + + { ORDATA (CNTYPE, mac_cntlr.type, 2), REG_HRO }, + { ORDATA (STATE, mac_cntlr.state, 2) }, + { ORDATA (OPCODE, mac_cntlr.opcode, 6) }, + { ORDATA (STATUS, mac_cntlr.status, 6) }, + { FLDATA (EOC, mac_cntlr.eoc, 0) }, + { FLDATA (EOD, mac_cntlr.eod, 0) }, + { ORDATA (SPDU, mac_cntlr.spd_unit, 16) }, + { ORDATA (FLMASK, mac_cntlr.file_mask, 4) }, + { ORDATA (RETRY, mac_cntlr.retry, 4), REG_HRO }, + { ORDATA (CYL, mac_cntlr.cylinder, 16) }, + { ORDATA (HEAD, mac_cntlr.head, 6) }, + { ORDATA (SECTOR, mac_cntlr.sector, 8) }, + { ORDATA (VFYCNT, mac_cntlr.verify_count, 16) }, + { ORDATA (LASPOL, mac_cntlr.poll_unit, 3) }, + { HRDATA (BUFPTR, mac_cntlr.buffer, 32), REG_HRO }, + { BRDATA (BUFFER, buffer, 8, 16, DL_BUFSIZE) }, + { DRDATA (INDEX, mac_cntlr.index, 8) }, + { DRDATA (LENGTH, mac_cntlr.length, 8) }, + { HRDATA (AUXPTR, mac_cntlr.aux, 32), REG_HRO }, + { DRDATA (STIME, mac_cntlr.seek_time, 24), PV_LEFT | REG_NZ }, + { DRDATA (ITIME, mac_cntlr.sector_time, 24), PV_LEFT | REG_NZ }, + { DRDATA (CTIME, mac_cntlr.cmd_time, 24), PV_LEFT | REG_NZ }, + { DRDATA (DTIME, mac_cntlr.data_time, 24), PV_LEFT | REG_NZ }, + { DRDATA (WTIME, mac_cntlr.wait_time, 31), PV_LEFT | REG_NZ }, + + { FLDATA (CTL, ds.control, 0) }, + { FLDATA (FLG, ds.flag, 0) }, + { FLDATA (FBF, ds.flagbuf, 0) }, + { FLDATA (SRQ, ds.srq, 0) }, + { FLDATA (EDT, ds.edt, 0) }, + + { URDATA (UCYL, ds_unit[0].CYL, 10, 10, 0, DS_UNITS, PV_LEFT) }, + { URDATA (UOP, ds_unit[0].OP, 8, 6, 0, DS_UNITS, PV_RZRO) }, + { URDATA (USTAT, ds_unit[0].STAT, 2, 8, 0, DS_UNITS, PV_RZRO) }, + { URDATA (UPHASE, ds_unit[0].PHASE, 8, 3, 0, DS_UNITS, PV_RZRO) }, + { URDATA (UPOS, ds_unit[0].pos, 8, T_ADDR_W, 0, DS_UNITS, PV_LEFT) }, + { URDATA (UWAIT, ds_unit[0].wait, 8, 32, 0, DS_UNITS, PV_LEFT) }, + + { ORDATA (SC, ds_dib.select_code, 6), REG_HRO }, + { ORDATA (DEVNO, ds_dib.select_code, 6), REG_HRO }, + { NULL } + }; + +static MTAB ds_mod [] = { +/* mask match pstring mstring valid disp desc */ + { UNIT_UNLOAD, UNIT_UNLOAD, "heads unloaded", "UNLOADED", &ds_load_unload, NULL, NULL }, + { UNIT_UNLOAD, 0, "heads loaded", "LOADED", &ds_load_unload, NULL, NULL }, + + { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL, NULL, NULL }, + { UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL, NULL, NULL }, + + { UNIT_FMT, UNIT_FMT, "format enabled", "FORMAT", NULL, NULL, NULL }, + { UNIT_FMT, 0, "format disabled", "NOFORMAT", NULL, NULL, NULL }, + +/* mask match pstring mstring valid disp desc */ + { UNIT_AUTO | UNIT_ATT, UNIT_AUTO, "autosize", "AUTOSIZE", &dl_set_model, NULL, NULL }, + { UNIT_AUTO | UNIT_ATT | UNIT_MODEL, MODEL_7905, "7905", "7905", &dl_set_model, NULL, NULL }, + { UNIT_AUTO | UNIT_ATT | UNIT_MODEL, MODEL_7906, "7906", "7906", &dl_set_model, NULL, NULL }, + { UNIT_AUTO | UNIT_ATT | UNIT_MODEL, MODEL_7920, "7920", "7920", &dl_set_model, NULL, NULL }, + { UNIT_AUTO | UNIT_ATT | UNIT_MODEL, MODEL_7925, "7925", "7925", &dl_set_model, NULL, NULL }, + { UNIT_ATT | UNIT_MODEL, UNIT_ATT | MODEL_7905, "7905", NULL, NULL, NULL, NULL }, + { UNIT_ATT | UNIT_MODEL, UNIT_ATT | MODEL_7906, "7906", NULL, NULL, NULL, NULL }, + { UNIT_ATT | UNIT_MODEL, UNIT_ATT | MODEL_7920, "7920", NULL, NULL, NULL, NULL }, + { UNIT_ATT | UNIT_MODEL, UNIT_ATT | MODEL_7925, "7925", NULL, NULL, NULL, NULL }, + + { MTAB_XTD | MTAB_VDV, 0, "SC", "SC", &hp_setsc, &hp_showsc, &ds_dev }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &ds_dev }, + { 0 } + }; + +static DEBTAB ds_deb [] = { + { "CPU", DEB_CPU }, + { "CMDS", DEB_CMDS }, + { "BUF", DEB_BUF }, + { "RWSC", DEB_RWSC }, + { "SERV", DEB_SERV }, + { NULL, 0 } + }; + +DEVICE ds_dev = { + "DS", /* device name */ + ds_unit, /* unit array */ + ds_reg, /* register array */ + ds_mod, /* modifier array */ + DS_UNITS, /* number of units */ + 8, /* address radix */ + 27, /* address width = 128 MB */ + 1, /* address increment */ + 8, /* data radix */ + 16, /* data width */ + NULL, /* examine routine */ + NULL, /* deposit routine */ + &ds_reset, /* reset routine */ + &ds_boot, /* boot routine */ + &ds_attach, /* attach routine */ + &ds_detach, /* detach routine */ + &ds_dib, /* device information block */ + DEV_DEBUG | DEV_DISABLE, /* device flags */ + 0, /* debug control flags */ + ds_deb, /* debug flag name table */ + NULL, /* memory size change routine */ + NULL /* logical device name */ + }; + + + +/* MAC disc global VM routines */ + + +/* I/O signal handler. + + The 13175D disc interface data path consists of an input multiplexer/latch + and a 16-word FIFO buffer. The FIFO source may be either the CPU's I/O + input bus or the controller's interface data bus. The output of the FIFO may + be enabled either to the CPU's I/O output bus or the interface data bus. + + The control path consists of the usual control, flag buffer, flag, and SRQ + flip-flops, although flag and SRQ are decoupled to allow the full DCPC + transfer rate through the FIFO (driving SRQ from the flag limits transfers to + every other cycle). SRQ is based on the FIFO level: if data or room in the + FIFO is available, SRQ is set to initiate a transfer. The flag is only used + to signal an interrupt at the end of a command. + + One unusual aspect is that SFC and SFS test different things, rather than + complementary states of the same thing. SFC tests the controller busy state, + and SFS tests the flag flip-flop. + + In addition, the card contains end-of-data-transfer, command-follows, and + command-ready flip-flops. EDT is set when the DCPC EDT signal is asserted + and is used in conjunction with the FIFO level to assert the end-of-data + signal to the controller. The command-follows flip-flop is set by a CLC to + indicate that the next data word output from the CPU is a disc command. The + command-ready flip-flop is set when a command is received to schedule an + interface poll. + + + Implementation notes: + + 1. In hardware, SRQ is enabled only when the controller is reading or + writing the disc (IFIN or IFOUT functions are asserted) and set when the + FIFO is not empty (read) or not full (write). In simulation, SRQ is set + by the unit service read/write data phase transfers and cleared in the + IOI and IOO signal handlers when the FIFO is empty (read) or full + (write). + + 2. The DCPC EDT signal cannot set the controller's end-of-data flag directly + because a write EOD must occur only after the FIFO has been drained. + + 3. Polling the interface or drives must be deferred to the end of I/O signal + handling. If they are performed in the IOO/STC handlers themselves, an + associated CLF might clear the flag that was set by the poll. + + 4. Executing a CLC sets the controller's end-of-data flag, which will abort + a read or write data transfer in progress. Parameter transfers are not + affected. If a command is received when a parameter is expected, the + word is interpreted as data, even though the command-ready flip-flop is + set. The controller firmware only checks DTRDY for a parameter transfer, + and DTRDY is asserted whenever the FIFO is not empty. + + 5. The hardware Interface Function and Flag Buses are not implemented + explicitly. Instead, interface functions and signals are inferred by the + interface from the current command operation and phase. +*/ + +uint32 ds_io (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) +{ +static const char * const output_state [] = { "Data", "Command" }; +const char * const hold_or_clear = (signal_set & ioCLF ? ",C" : ""); + +uint16 data; +t_stat status; +IOSIGNAL signal; +IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ +t_bool command_issued = FALSE; +t_bool interrupt_enabled = FALSE; + +while (working_set) { + signal = IONEXT (working_set); /* isolate the next signal */ + + switch (signal) { /* dispatch the I/O signal */ + + case ioCLF: /* clear flag flip-flop */ + ds.flag = CLEAR; /* clear the flag */ + ds.flagbuf = CLEAR; /* and flag buffer */ + + if (DEBUG_PRI (ds_dev, DEB_CMDS)) + fputs (">>DS cmds: [CLF] Flag cleared\n", sim_deb); + break; + + + case ioSTF: /* set flag flip-flop */ + case ioENF: /* enable flag */ + ds.flag = SET; /* set the flag */ + ds.flagbuf = SET; /* and flag buffer */ + + if (DEBUG_PRI (ds_dev, DEB_CMDS)) + fputs (">>DS cmds: [STF] Flag set\n", sim_deb); + break; + + + case ioSFC: /* skip if flag is clear */ + setSKF (mac_cntlr.state != cntlr_busy); /* skip if the controller is not busy */ + break; + + + case ioSFS: /* skip if flag is set */ + setstdSKF (ds); /* assert SKF if the flag is set */ + break; + + + case ioIOI: /* I/O data input */ + data = fifo_unload (); /* unload the next word from the FIFO */ + stat_data = IORETURN (SCPE_OK, data); /* merge in the return status */ + + if (DEBUG_PRI (ds_dev, DEB_CPU)) + fprintf (sim_deb, ">>DS cpu: [LIx%s] Data = %06o\n", hold_or_clear, data); + + if (FIFO_EMPTY) { /* is the FIFO now empty? */ + if (ds.srq == SET && DEBUG_PRI (ds_dev, DEB_CMDS)) + fprintf (sim_deb, ">>DS cmds: [LIx%s] SRQ cleared\n", hold_or_clear); + + ds.srq = CLEAR; /* clear SRQ */ + + if (ds_cntlr.PHASE == data_phase) { /* is this an outbound parameter? */ + ds_cntlr.wait = mac_cntlr.data_time; /* activate the controller */ + activate_unit (&ds_cntlr); /* to acknowledge the data */ + } + } + break; + + + case ioIOO: /* I/O data output */ + data = IODATA (stat_data); /* mask to just the data word */ + + if (DEBUG_PRI (ds_dev, DEB_CPU)) + fprintf (sim_deb, ">>DS cpu: [OTx%s] %s = %06o\n", + hold_or_clear, output_state [ds.cmfol], data); + + fifo_load (data); /* load the word into the FIFO */ + + if (ds.cmfol == SET) { /* are we expecting a command? */ + ds.cmfol = CLEAR; /* clear the command follows flip-flop */ + ds.cmrdy = SET; /* set the command ready flip-flop */ + command_issued = TRUE; /* and request an interface poll */ + } + + else { /* not a command */ + if (ds_cntlr.PHASE == data_phase) { /* is this an inbound parameter? */ + ds_cntlr.wait = mac_cntlr.data_time; /* activate the controller */ + activate_unit (&ds_cntlr); /* to receive the data */ + } + + if (FIFO_STOP) { /* is the FIFO now full enough? */ + if (ds.srq == SET && DEBUG_PRI (ds_dev, DEB_CMDS)) + fprintf (sim_deb, ">>DS cmds: [OTx%s] SRQ cleared\n", hold_or_clear); + + ds.srq = CLEAR; /* clear SRQ to stop filling */ + } + } + break; + + + case ioPOPIO: /* power-on preset to I/O */ + ds.flag = SET; /* set the flag */ + ds.flagbuf = SET; /* and flag buffer */ + ds.cmrdy = CLEAR; /* clear the command ready flip-flop */ + + if (DEBUG_PRI (ds_dev, DEB_CMDS)) + fputs (">>DS cmds: [POPIO] Flag set\n", sim_deb); + break; + + + case ioCRS: /* control reset */ + if (DEBUG_PRI (ds_dev, DEB_CMDS)) + fputs (">>DS cmds: [CRS] Master reset\n", sim_deb); + + ds.control = CLEAR; /* clear the control */ + ds.cmfol = CLEAR; /* and command follows flip-flops */ + + if (PRESET_ENABLE) { /* is preset enabled for this interface? */ + fifo_clear (); /* clear the FIFO */ + + status = dl_clear_controller (&mac_cntlr, /* do a hard clear of the controller */ + ds_unit, hard_clear); + + stat_data = IORETURN (status, 0); /* return the status from the controller */ + } + break; + + + case ioCLC: /* clear control flip-flop */ + if (DEBUG_PRI (ds_dev, DEB_CMDS)) + fprintf (sim_deb, ">>DS cmds: [CLC%s] Control cleared\n", hold_or_clear); + + ds.control = CLEAR; /* clear the control */ + ds.edt = CLEAR; /* and EDT flip-flops */ + ds.cmfol = SET; /* set the command follows flip-flop */ + mac_cntlr.eod = SET; /* set the controller's EOD flag */ + + fifo_clear (); /* clear the FIFO */ + break; + + + case ioSTC: /* set control flip-flop */ + ds.control = SET; /* set the control flip-flop */ + + interrupt_enabled = TRUE; /* check for drive attention */ + + if (DEBUG_PRI (ds_dev, DEB_CMDS)) + fprintf (sim_deb, ">>DS cmds: [STC%s] Control set\n", hold_or_clear); + break; + + + case ioEDT: /* end data transfer */ + ds.edt = SET; /* set the EDT flip-flop */ + + if (DEBUG_PRI (ds_dev, DEB_CPU)) + fputs (">>DS cpu: [EDT] DCPC transfer ended\n", sim_deb); + break; + + + case ioSIR: /* set interrupt request */ + setstdPRL (ds); /* set the standard PRL signal */ + setstdIRQ (ds); /* set the standard IRQ signal */ + setSRQ (dibptr->select_code, ds.srq); /* set the SRQ signal */ + break; + + + case ioIAK: /* interrupt acknowledge */ + ds.flagbuf = CLEAR; /* clear the flag */ + break; + + + default: /* all other signals */ + break; /* are ignored */ + } + + working_set = working_set & ~signal; /* remove the current signal from the set */ + } + + +if (command_issued) /* was a command received? */ + poll_interface (); /* poll the interface for the next command */ +else if (interrupt_enabled) /* were interrupts enabled? */ + poll_drives (); /* poll the drives for Attention */ + +return stat_data; +} + + +/* Service the disc drive unit. + + The unit service routine is called to execute scheduled controller commands + for the specified unit. The actions to be taken depend on the current state + of the controller and the unit. + + Generally, the controller library service routine handles all of the disc + operations except data transfer to and from the interface. Read transfers + are responsible for loading words from the sector buffer into the FIFO and + enabling SRQ. If the current sector transfer is complete, either due to EDT + assertion or buffer exhaustion, the controller is moved to the end phase to + complete or continue the read with the next sector. In either case, the unit + is rescheduled. If the FIFO overflows, the read terminates with a data + overrun error. + + Write transfers set the initial SRQ to request words from the CPU. As each + word arrives, it is unloaded from the FIFO into the sector buffer, and SRQ is + enabled. If the current sector transfer is complete, the controller is moved + to the end phase. If the FIFO underflows, the write terminates with a data + overrun error. + + The synchronous nature of the disc drive requires that data be supplied or + accepted continuously by the CPU. DCPC generally assures that this occurs, + and the FIFO allows for some latency before an overrun or underrun occurs. + + The other operation the interface must handle is seek completion. The + controller handles seek completion by setting Attention status in the drive's + status word. The interface is responsible for polling the drives if the + controller is idle and interrupts are enabled. + + + Implementation notes: + + 1. Every command except Seek, Recalibrate, and End sets the flag when the + command completes. A command completes when the controller is no longer + busy (it becomes idle for Seek, Recalibrate, and End, or it becomes + waiting for all others). Seek and Recalibrate may generate errors (e.g., + heads unloaded), in which case the flag must be set. But in these cases, + the controller state is waiting, not idle. + + However, it is insufficient simply to check that the controller has moved + to the wait state, because a seek may complete while the controller is + waiting for the next command. For example, a Seek is started on unit 0, + and the controller moves to the idle state. But before the seek + completes, another command is issued that attempts to access unit 1, + which is not ready. The command fails with a Status-2 error, and the + controller moves to the wait state. When the seek completes, the + controller is waiting with error status. We must determine whether the + seek completed successfully or not, as we must interrupt in the latter + case. + + Therefore, we determine seek completion by checking if the Attention + status was set. Attention sets only if the seek completes successfully. + + (Actually, Attention sets if a seek check occurs, but in that case, the + command terminated before the seek ever started. Also, a seek may + complete while the controller is busy, waiting, or idle.) + + 2. For debug printouts, we want to print the name of the command that has + completed when the controller returns to the idle or wait state. + Normally, we would use the controller's "opcode" field to identify the + command that completed. However, while waiting for Seek or Recalibrate + completion, "opcode" may be set to another command if that command does + not access this drive. For example, it might be set to a Read of another + unit, or a Request Status for this unit. So we can't rely on "opcode" to + report the correct name of the completed positioning command. + + However, we cannot rely on "uptr->OP" either, as that can be changed + during the course of a command. For example, Read Without Verify is + changed to Read after a track crossing. + + Instead, we have to determine whether a seek is completing. If it is, + then we report "uptr->OP"; otherwise, we report "opcode". + + 3. The initial write SRQ must set only at the transition from the start + phase to the data phase. If a write command begins with an auto-seek, + the drive service will be entered twice in the start phase (the first + entry performs the seek, and the second begins the write). In hardware, + SRQ does not assert until the write begins. + + 4. The DCPC EDT signal cannot set the controller's end-of-data flag + directly because a write EOD must only occur after the FIFO has been + drained. +*/ + +t_stat ds_service_drive (UNIT *uptr) +{ +static const char completion_message [] = ">>DS rwsc: Unit %d %s command completed\n"; +t_stat result; +t_bool seek_completion; +int32 unit; +FLIP_FLOP entry_srq = ds.srq; /* get the SRQ state on entry */ +CNTLR_PHASE entry_phase = (CNTLR_PHASE) uptr->PHASE; /* get the operation phase on entry */ +uint32 entry_status = uptr->STAT; /* get the drive status on entry */ + +result = dl_service_drive (&mac_cntlr, uptr); /* service the drive */ + +if ((CNTLR_PHASE) uptr->PHASE == data_phase) /* is the drive in the data phase? */ + switch ((CNTLR_OPCODE) uptr->OP) { /* dispatch the current operation */ + + case Read: /* read operations */ + case Read_Full_Sector: + case Read_With_Offset: + case Read_Without_Verify: + if (mac_cntlr.length == 0 || ds.edt == SET) { /* is the data phase complete? */ + mac_cntlr.eod = ds.edt; /* set EOD if DCPC is done */ + uptr->PHASE = end_phase; /* set the end phase */ + uptr->wait = mac_cntlr.cmd_time; /* and schedule the controller */ + } + + else if (FIFO_FULL) /* is the FIFO already full? */ + dl_end_command (&mac_cntlr, data_overrun); /* terminate the command with an overrun */ + + else { + fifo_load (buffer [mac_cntlr.index++]); /* load the next word into the FIFO */ + mac_cntlr.length--; /* count it */ + ds.srq = SET; /* ask DCPC to pick it up */ + ds_io (&ds_dib, ioSIR, 0); /* and recalculate the interrupts */ + uptr->wait = mac_cntlr.data_time; /* schedule the next data transfer */ + } + + break; + + + case Write: /* write operations */ + case Write_Full_Sector: + case Initialize: + if (entry_phase == start_phase) { /* is this the phase transition? */ + ds.srq = SET; /* start the DCPC transfer */ + ds_io (&ds_dib, ioSIR, 0); /* and recalculate the interrupts */ + } + + else if (FIFO_EMPTY) /* is the FIFO empty? */ + dl_end_command (&mac_cntlr, data_overrun); /* terminate the command with an underrun */ + + else { + buffer [mac_cntlr.index++] = fifo_unload (); /* unload the next word from the FIFO */ + mac_cntlr.length--; /* count it */ + + if (ds.edt == SET && FIFO_EMPTY) /* if DCPC is complete and the FIFO is empty */ + mac_cntlr.eod = SET; /* then set the end-of-data flag */ + + if (mac_cntlr.length == 0 || mac_cntlr.eod == SET) { /* is the data phase complete? */ + uptr->PHASE = end_phase; /* set the end phase */ + uptr->wait = mac_cntlr.cmd_time; /* and schedule the controller */ + } + + else { + if (ds.edt == CLEAR) { /* if DCPC is still transferring */ + ds.srq = SET; /* then request the next word */ + ds_io (&ds_dib, ioSIR, 0); /* and recalculate the interrupts */ + } + + uptr->wait = mac_cntlr.data_time; /* schedule the next data transfer */ + } + } + + break; + + + default: /* we were entered with an invalid state */ + result = SCPE_IERR; /* return an internal (programming) error */ + break; + } /* end of data phase operation dispatch */ + + +if (DEBUG_PRI (ds_dev, DEB_CMDS) && entry_srq != ds.srq) + fprintf (sim_deb, ">>DS cmds: SRQ %s\n", ds.srq == SET ? "set" : "cleared"); + + +if (uptr->wait) /* was service requested? */ + activate_unit (uptr); /* schedule the next event */ + +seek_completion = ~entry_status & uptr->STAT & DL_S2ATN; /* seek is complete when Attention sets */ + +if (mac_cntlr.state != cntlr_busy) { /* is the command complete? */ + if (mac_cntlr.state == cntlr_wait && !seek_completion) /* is it command but not seek completion? */ + ds_io (&ds_dib, ioENF, 0); /* set the data flag to interrupt the CPU */ + + poll_interface (); /* poll the interface for the next command */ + poll_drives (); /* poll the drives for Attention */ + } + + +if (DEBUG_PRI (ds_dev, DEB_RWSC)) { + unit = uptr - ds_unit; /* get the unit number */ + + if (result == SCPE_IERR) /* did an internal error occur? */ + fprintf (sim_deb, ">>DS rwsc: Unit %d %s command %s phase service not handled\n", + unit, dl_opcode_name (MAC, (CNTLR_OPCODE) uptr->OP), + dl_phase_name ((CNTLR_PHASE) uptr->PHASE)); + + else if (seek_completion) /* if a seek has completed */ + fprintf (sim_deb, completion_message, /* report the unit command */ + unit, dl_opcode_name (MAC, (CNTLR_OPCODE) uptr->OP)); + + else if (mac_cntlr.state == cntlr_wait) /* if the controller has stopped */ + fprintf (sim_deb, completion_message, /* report the controller command */ + unit, dl_opcode_name (MAC, mac_cntlr.opcode)); + } + +return result; /* return the result of the service */ +} + + +/* Service the controller unit. + + The controller service routine is called to execute scheduled controller + commands that do not access drive units. It is also called to obtain command + parameters from the interface and to return command result values to the + interface. + + Most controller commands are handled completely in the library's service + routine, so we call that first. Commands that neither accept nor supply + parameters are complete when the library routine returns, so all we have to + do is set the interface flag if required. + + For parameter transfers in the data phase, the interface is responsible for + moving words between the sector buffer and the FIFO and setting the flag to + notify the CPU. + + + Implementation notes: + + 1. In hardware, the Read With Offset command sets the data flag after the + offset parameter has been read and the head positioner has been moved by + the indicated amount. The intent is to delay the DCPC start until the + drive is ready to supply data from the disc. + + In simulation, the flag is set as soon as the parameter is received. +*/ + +t_stat ds_service_controller (UNIT *uptr) +{ +t_stat result; +const CNTLR_OPCODE opcode = (CNTLR_OPCODE) uptr->OP; + +result = dl_service_controller (&mac_cntlr, uptr); /* service the controller */ + +switch ((CNTLR_PHASE) uptr->PHASE) { /* dispatch the current phase */ + + case start_phase: /* most controller operations */ + case end_phase: /* start and end on the same phase */ + switch (opcode) { /* dispatch the current operation */ + + case Request_Status: + case Request_Sector_Address: + case Address_Record: + case Request_Syndrome: + case Load_TIO_Register: + case Request_Disc_Address: + case End: + break; /* complete the operation without setting the flag */ + + + case Clear: + case Set_File_Mask: + case Wakeup: + ds_io (&ds_dib, ioENF, 0); /* complete the operation and set the flag */ + break; + + + default: /* we were entered with an invalid state */ + result = SCPE_IERR; /* return an internal (programming) error */ + break; + } /* end of operation dispatch */ + break; /* end of start and end phase handlers */ + + + case data_phase: + switch (opcode) { /* dispatch the current operation */ + + case Seek: /* operations that accept parameters */ + case Verify: + case Address_Record: + case Read_With_Offset: + case Load_TIO_Register: + buffer [mac_cntlr.index++] = fifo_unload (); /* unload the next word from the FIFO */ + mac_cntlr.length--; /* count it */ + + if (mac_cntlr.length) /* are there more words to transfer? */ + ds_io (&ds_dib, ioENF, 0); /* set the flag to request the next one */ + + else { /* all parameters have been received */ + uptr->PHASE = end_phase; /* set the end phase */ + + if (opcode == Read_With_Offset) /* a Read With Offset command sets the flag */ + ds_io (&ds_dib, ioENF, 0); /* to indicate that offsetting is complete */ + + start_command (); /* the command is now ready to execute */ + } + break; + + + case Request_Status: /* operations that supply parameters */ + case Request_Sector_Address: + case Request_Syndrome: + case Request_Disc_Address: + if (mac_cntlr.length) { /* are there more words to return? */ + fifo_load (buffer [mac_cntlr.index++]); /* load the next word into the FIFO */ + mac_cntlr.length--; /* count it */ + + ds_io (&ds_dib, ioENF, 0); /* set the flag to request pickup by the CPU */ + } + + else { /* all parameters have been sent */ + uptr->PHASE = end_phase; /* set the end phase */ + uptr->wait = mac_cntlr.cmd_time; /* schedule the controller */ + activate_unit (uptr); /* to complete the command */ + } + break; + + + default: /* we were entered with an invalid state */ + result = SCPE_IERR; /* return an internal (programming) error */ + break; + } /* end of operation dispatch */ + break; /* end of data phase handlers */ + } /* end of phase dispatch */ + + +if (result == SCPE_IERR && DEBUG_PRI (ds_dev, DEB_RWSC)) /* did an internal error occur? */ + fprintf (sim_deb, ">>DS rwsc: Controller %s command %s phase service not handled\n", + dl_opcode_name (MAC, opcode), dl_phase_name ((CNTLR_PHASE) uptr->PHASE)); + + +if (mac_cntlr.state != cntlr_busy) { /* has the controller stopped? */ + poll_interface (); /* poll the interface for the next command */ + poll_drives (); /* poll the drives for Attention status */ + + if (DEBUG_PRI (ds_dev, DEB_RWSC)) + fprintf (sim_deb, ">>DS rwsc: Controller %s command completed\n", + dl_opcode_name (MAC, opcode)); + } + +return result; /* return the result of the service */ +} + + +/* Service the command wait timer unit. + + The command wait timer service routine is called if the command wait timer + expires. The library is called to reset the file mask and idle the + controller. Then the interface is polled for a command and the drives are + polled for Attention status. +*/ + +t_stat ds_service_timer (UNIT *uptr) +{ +t_stat result; + +result = dl_service_timer (&mac_cntlr, uptr); /* service the timer */ + +poll_interface (); /* poll the interface for the next command */ +poll_drives (); /* poll the drives for Attention status */ + +return result; /* return the result of the service */ +} + + +/* Reset the simulator. + + In hardware, the PON signal clears the Interface Selected flip-flop, + disconnecting the interface from the disc controller. In simulation, the + interface always remains connected to the controller, so no special action is + needed. + + + Implementation notes: + + 1. During a power-on reset, a pointer to the FIFO simulation register is + saved to allow access to the "qptr" field during FIFO loading and + unloading. This enables SCP to view the FIFO as a circular queue, so + that the bottom word of the FIFO is always displayed as FIFO[0], + regardless of where it is in the actual FIFO array. + + 2. SRQ is denied because neither IFIN nor IFOUT is asserted when the + interface is not selected. +*/ + +t_stat ds_reset (DEVICE *dptr) +{ +uint32 unit; + +if (sim_switches & SWMASK ('P')) { /* is this a power-on reset? */ + ds.fifo_reg = find_reg ("FIFO", NULL, dptr); /* find the FIFO register entry */ + + if (ds.fifo_reg == NULL) /* if it cannot be found, */ + return SCPE_IERR; /* report a programming error */ + + else { /* found it */ + ds.fifo_reg->qptr = 0; /* so reset the FIFO bottom index */ + ds.fifo_count = 0; /* and clear the FIFO */ + } + + for (unit = 0; unit < dptr->numunits; unit++) { /* loop through all of the units */ + sim_cancel (dptr->units + unit); /* cancel activation */ + dptr->units [unit].CYL = 0; /* reset the head position to cylinder 0 */ + dptr->units [unit].pos = 0; /* (irrelevant for the controller and timer) */ + } + } + +IOPRESET (&ds_dib); /* PRESET the device */ +ds.srq = CLEAR; /* clear SRQ */ + +return SCPE_OK; +} + + +/* Attach a drive unit. + + The specified file is attached to the indicated drive unit. The library + attach routine will load the heads. This will set the First Status and + Attention bits in the drive status, so we poll the drives to ensure that the + CPU is notified that the drive is now online. + + + Implementation notes: + + 1. If we are called during a RESTORE command, the drive status will not be + changed, so polling the drives will have no effect. +*/ + +t_stat ds_attach (UNIT *uptr, char *cptr) +{ +t_stat result; + +result = dl_attach (&mac_cntlr, uptr, cptr); /* attach the drive */ + +if (result == SCPE_OK) /* was the attach successful? */ + poll_drives (); /* poll the drives to notify the CPU */ + +return result; +} + + +/* Detach a drive unit. + + The specified file is detached from the indicated drive unit. The library + detach routine will unload the heads. This will set the Attention bit in the + drive status, so we poll the drives to ensure that the CPU is notified that + the drive is now offline. +*/ + +t_stat ds_detach (UNIT *uptr) +{ +t_stat result; + +result = dl_detach (&mac_cntlr, uptr); /* detach the drive */ + +if (result == SCPE_OK) /* was the detach successful? */ + poll_drives (); /* poll the drives to notify the CPU */ + +return result; +} + + +/* Boot a MAC disc drive. + + The MAC disc bootstrap program is loaded from the HP 12992B Boot Loader ROM + into memory, the I/O instructions are configured for the interface card's + select code, and the program is run to boot from the specified unit. The + loader supports booting from cylinder 0 of drive unit 0 only. Before + execution, the S register is automatically set as follows: + + 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 + ------ ------ ---------------------- --------- --------- + ROM # 0 1 select code reserved head + + The boot routine sets bits 15-6 of the S register to appropriate values. + Bits 5-3 and 1-0 retain their original values, so S should be set before + booting. These bits are typically set to 0, although bit 5 is set for an RTE + reconfiguration boot, and bits 1-0 may be set if booting from a head other + than 0 is desired. + + + Implementation notes: + + 1. The Loader ROMs manual indicates that bits 2-0 select the head to use, + implying that heads 0-7 are valid. However, Table 5 has entries only for + heads 0-3, and the boot loader code will malfunction if heads 4-7 are + specified. The code masks the head number to three bits but forms the + Cold Load Read command by shifting the head number six bits to the left. + As the head field in the command is only two bits wide, specifying heads + 4-7 will result in bit 2 being shifted into the opcode field, resulting + in a Recalibrate command. +*/ + + +const BOOT_ROM ds_rom = { + 0017727, /* START JSB STAT GET STATUS */ + 0002021, /* SSA,RSS IS DRIVE READY ? */ + 0027742, /* JMP DMA YES, SET UP DMA */ + 0013714, /* AND B20 NO, CHECK STATUS BITS */ + 0002002, /* SZA IS DRIVE FAULTY OR HARD DOWN ? */ + 0102030, /* HLT 30B YES, HALT 30B, "RUN" TO TRY AGAIN */ + 0027700, /* JMP START NO, TRY AGAIN FOR DISC READY */ + 0102011, /* ADDR1 OCT 102011 */ + 0102055, /* ADDR2 OCT 102055 */ + 0164000, /* CNT DEC -6144 */ + 0000007, /* D7 OCT 7 */ + 0001400, /* STCMD OCT 1400 */ + 0000020, /* B20 OCT 20 */ + 0017400, /* STMSK OCT 17400 */ + 0000000, /* NOP */ + 0000000, /* NOP */ + 0000000, /* NOP */ + 0000000, /* NOP */ + 0000000, /* NOP */ + 0000000, /* NOP */ + 0000000, /* NOP */ + 0000000, /* NOP */ + 0000000, /* NOP */ + 0000000, /* STAT NOP STATUS CHECK SUBROUTINE */ + 0107710, /* CLC DC,C SET STATUS COMMAND MODE */ + 0063713, /* LDA STCMD GET STATUS COMMAND */ + 0102610, /* OTA DC OUTPUT STATUS COMMAND */ + 0102310, /* SFS DC WAIT FOR STATUS#1 WORD */ + 0027733, /* JMP *-1 */ + 0107510, /* LIB DC,C B-REG = STATUS#1 WORD */ + 0102310, /* SFS DC WAIT FOR STATUS#2 WORD */ + 0027736, /* JMP *-1 */ + 0103510, /* LIA DC,C A-REG = STATUS#2 WORD */ + 0127727, /* JMP STAT,I RETURN */ + 0067776, /* DMA LDB DMACW GET DMA CONTROL WORD */ + 0106606, /* OTB 6 OUTPUT DMA CONTROL WORD */ + 0067707, /* LDB ADDR1 GET MEMORY ADDRESS */ + 0106702, /* CLC 2 SET MEMORY ADDRESS INPUT MODE */ + 0106602, /* OTB 2 OUTPUT MEMORY ADDRESS TO DMA */ + 0102702, /* STC 2 SET WORD COUNT INPUT MODE */ + 0067711, /* LDB CNT GET WORD COUNT */ + 0106602, /* OTB 2 OUTPUT WORD COUNT TO DMA */ + 0106710, /* CLDLD CLC DC SET COMMAND INPUT MODE */ + 0102501, /* LIA 1 LOAD SWITCH */ + 0106501, /* LIB 1 REGISTER SETTINGS */ + 0013712, /* AND D7 ISOLATE HEAD NUMBER */ + 0005750, /* BLF,CLE,SLB BIT 12=0? */ + 0027762, /* JMP *+3 NO,MANUAL BOOT */ + 0002002, /* SZA YES,RPL BOOT. HEAD#=0? */ + 0001000, /* ALS NO,HEAD#1, MAKE HEAD#=2 */ + 0001720, /* ALF,ALS FORM COLD LOAD */ + 0001000, /* ALS COMMAND WORD */ + 0103706, /* STC 6,C ACTIVATE DMA */ + 0103610, /* OTA DC,C OUTPUT COLD LOAD COMMAND */ + 0102310, /* SFS DC IS COLD LOAD COMPLETED ? */ + 0027766, /* JMP *-1 NO, WAIT */ + 0017727, /* JSB STAT YES, GET STATUS */ + 0060001, /* LDA 1 */ + 0013715, /* AND STMSK A-REG = STATUS BITS OF STATUS#1 WD */ + 0002002, /* SZA IS TRANSFER OK ? */ + 0027700, /* JMP START NO,TRY AGAIN */ + 0117710, /* EXIT JSB ADDR2,I YES, EXEC LOADED PROGRAM _@ 2055B */ + 0000010, /* DMACW ABS DC */ + 0170100, /* ABS -START */ + }; + +t_stat ds_boot (int32 unitno, DEVICE *dptr) +{ +if (unitno != 0) /* boot supported on drive unit 0 only */ + return SCPE_NOFNC; /* report "Command not allowed" if attempted */ + +if (ibl_copy (ds_rom, ds_dib.select_code, /* copy the boot ROM to memory and configure */ + IBL_OPT | IBL_DS_HEAD, /* the S register accordingly */ + IBL_DS | IBL_MAN | IBL_SET_SC (ds_dib.select_code))) + return SCPE_IERR; /* return an internal error if the copy failed */ +else + return SCPE_OK; +} + + + +/* MAC disc global SCP routines */ + + +/* Load or unload the drive heads. + + The SCP command SET DSn UNLOADED simulates setting the hardware RUN/STOP + switch to STOP. The heads are unloaded, and the drive is spun down. + + The SET DSn LOADED command simulates setting the switch to RUN. The drive is + spun up, and the heads are loaded. + + The library handles command validation and setting the appropriate drive unit + status. +*/ + +t_stat ds_load_unload (UNIT *uptr, int32 value, char *cptr, void *desc) +{ +const t_bool load = (value != UNIT_UNLOAD); /* true if the heads are loading */ + +return dl_load_unload (&mac_cntlr, uptr, load); /* load or unload the heads */ +} + + + +/* MAC disc local utility routines */ + + +/* Start a command. + + The previously prepared command is executed by calling the corresponding + library routine. On entry, the controller's opcode field contains the + command to start, and the buffer contains the command word in element 0 and + the parameters required by the command, if any, beginning in element 1. + + If the command started, the returned pointer will point at the unit to + activate (if that unit's "wait" field is non-zero). If the returned pointer + is NULL, the command failed to start, and the controller status has been set + to indicate the reason. The interface flag is set to notify the CPU of the + failure. + + + Implementation notes: + + 1. If a command that accesses the drive is attempted on a drive currently + seeking, the returned pointer will be valid, but the unit's "wait" time + will be zero. The unit must not be activated (as it already is active). + When the seek completes, the command will be executed automatically. + + If a Seek or Cold Load Read command is attempted on a drive currently + seeking, seek completion will occur normally, but Seek Check status will + be set. + + 2. For debug printouts, we want to print the name of the command (Seek or + Recalibrate) in progress when a new command is started. However, when + the library routine returns, the unit operation and controller opcode + have been changed to reflect the new command. Therefore, we must record + the operation in progress before calling the library. + + The problem is in determining which unit's operation code to record. We + cannot blindly use the unit field from the new command, as recorded in + the controller, as preparation has ensured only that the target unit + number is legal but not necessarily valid. Therefore, we must validate + the unit number before accessing the unit's operation code. + + If the unit number is invalid, the command will not start, but the + compiler does not know this. Therefore, we must ensure that the saved + operation code is initialized, or a "variable used uninitialized" warning + will occur. +*/ + +static void start_command (void) +{ +int32 unit, time; +UNIT *uptr; +CNTLR_OPCODE drive_command; + +unit = GET_S1UNIT (mac_cntlr.spd_unit); /* get the (prepared) unit from the command */ + +if (unit <= DL_MAXDRIVE) /* is the unit number valid? */ + drive_command = (CNTLR_OPCODE) ds_unit [unit].OP; /* get the opcode from the unit that will be used */ +else /* the unit is invalid, so the command will not start */ + drive_command = End; /* but the compiler doesn't know this! */ + +uptr = dl_start_command (&mac_cntlr, ds_unit, DL_MAXDRIVE); /* ask the controller to start the command */ + +if (uptr) { /* did the command start? */ + time = uptr->wait; /* save the activation time */ + + if (time) /* was the unit scheduled? */ + activate_unit (uptr); /* activate it (and clear the "wait" field) */ + + if (DEBUG_PRI (ds_dev, DEB_RWSC)) { + unit = uptr - ds_unit; /* get the unit number */ + + if (time == 0) /* was the unit busy? */ + fprintf (sim_deb, ">>DS rwsc: Unit %d %s in progress\n", + unit, dl_opcode_name (MAC, drive_command)); + + fputs (">>DS rwsc: ", sim_deb); + + if (unit > DL_MAXDRIVE) + fputs ("Controller ", sim_deb); + else + fprintf (sim_deb, "Unit %d position %" T_ADDR_FMT "d ", unit, uptr->pos); + + fprintf (sim_deb, "%s command initiated\n", + dl_opcode_name (MAC, mac_cntlr.opcode)); + } + } + +else /* the command failed to start */ + ds_io (&ds_dib, ioENF, 0); /* so set the flag to notify the CPU */ + +return; +} + + +/* Poll the interface for a new command. + + If a new command is available, and the controller is not busy, prepare the + command for execution. If preparation succeeded, and the command needs + parameters before executing, set the flag to request the first one from the + CPU. If no parameters are needed, the command is ready to execute. + + If preparation failed, set the flag to notify the CPU. The controller + status contains the reason for the failure. +*/ + +static void poll_interface (void) +{ +if (ds.cmrdy == SET && mac_cntlr.state != cntlr_busy) { /* are the interface and controller ready? */ + buffer [0] = fifo_unload (); /* unload the command into the buffer */ + + if (dl_prepare_command (&mac_cntlr, ds_unit, DL_MAXDRIVE)) { /* prepare the command; did it succeed? */ + if (mac_cntlr.length) /* does the command require parameters? */ + ds_io (&ds_dib, ioENF, 0); /* set the flag to request the first one */ + else /* if not waiting for parameters */ + start_command (); /* start the command */ + } + + else /* preparation failed */ + ds_io (&ds_dib, ioENF, 0); /* so set the flag to notify the CPU */ + + ds.cmrdy = CLEAR; /* flush the command from the interface */ + } + +return; +} + + +/* Poll the drives for attention requests. + + If the controller is idle and interrupts are allowed, the drives are polled + to see if any drive is requesting attention. If one is found, the controller + resets that drive's Attention status, saves the drive's unit number, sets + Drive Attention status, and waits for a command from the CPU. The interface + sets the flag to notify the CPU. +*/ + +static void poll_drives (void) +{ +if (mac_cntlr.state == cntlr_idle && ds.control == SET) /* is the controller idle and interrupts are allowed? */ + if (dl_poll_drives (&mac_cntlr, ds_unit, DL_MAXDRIVE)) /* poll the drives; was Attention seen? */ + ds_io (&ds_dib, ioENF, 0); /* request an interrupt */ +return; +} + + +/* Load a word into the FIFO. + + A word is loaded into the next available location in the FIFO, and the FIFO + occupancy count is incremented. If the FIFO is full on entry, the load is + ignored. + + + Implementation notes: + + 1. The FIFO is implemented as circular queue to take advantage of REG_CIRC + EXAMINE semantics. REG->qptr is the index of the first word currently in + the FIFO. By specifying REG_CIRC, examining FIFO[0-n] will always + display the words in load order, regardless of the actual array index of + the start of the list. The number of words currently present in the FIFO + is kept in fifo_count (0 = empty, 1-16 = number of words available). + + If fifo_count < FIFO_SIZE, (REG->qptr + fifo_count) mod FIFO_SIZE is the + index of the new word location. Loading stores the word there and then + increments fifo_count. + + 2. Because the load and unload routines need access to qptr in the REG + structure for the FIFO array, a pointer to the REG is stored in the + fifo_reg variable during device reset. +*/ + +static void fifo_load (uint16 data) +{ +uint32 index; + +if (FIFO_FULL) { /* is the FIFO already full? */ + if (DEBUG_PRI (ds_dev, DEB_BUF)) + fprintf (sim_deb, ">>DS buf: Attempted load to full FIFO, data %06o\n", data); + + return; /* return with the load ignored */ + } + +index = (ds.fifo_reg->qptr + ds.fifo_count) % FIFO_SIZE; /* calculate the index of the next available location */ + +ds.fifo [index] = data; /* store the word in the FIFO */ +ds.fifo_count = ds.fifo_count + 1; /* increment the count of words stored */ + +if (DEBUG_PRI (ds_dev, DEB_BUF)) + fprintf (sim_deb, ">>DS buf: Data %06o loaded into FIFO (%d)\n", + data, ds.fifo_count); + +return; +} + + +/* Unload a word from the FIFO. + + A word is unloaded from the first location in the FIFO, and the FIFO + occupancy count is decremented. If the FIFO is empty on entry, the unload + returns dummy data. + + + Implementation notes: + + 1. If fifo_count > 0, REG->qptr is the index of the word to remove. Removal + gets the word and then increments qptr (mod FIFO_SIZE) and decrements + fifo_count. +*/ + +static uint16 fifo_unload (void) +{ +uint16 data; + +if (FIFO_EMPTY) { /* is the FIFO already empty? */ + if (DEBUG_PRI (ds_dev, DEB_BUF)) + fputs (">>DS buf: Attempted unload from empty FIFO\n", sim_deb); + + return 0; /* return with no data */ + } + +data = ds.fifo [ds.fifo_reg->qptr]; /* get the word from the FIFO */ + +ds.fifo_reg->qptr = (ds.fifo_reg->qptr + 1) % FIFO_SIZE; /* update the FIFO queue pointer */ +ds.fifo_count = ds.fifo_count - 1; /* decrement the count of words stored */ + +if (DEBUG_PRI (ds_dev, DEB_BUF)) + fprintf (sim_deb, ">>DS buf: Data %06o unloaded from FIFO (%d)\n", + data, ds.fifo_count); + +return data; +} + + +/* Clear the FIFO. + + The FIFO is cleared by setting the occupancy counter to zero. +*/ + +static void fifo_clear (void) +{ +ds.fifo_count = 0; /* clear the FIFO */ + +if (DEBUG_PRI (ds_dev, DEB_BUF)) + fputs (">>DS buf: FIFO cleared\n", sim_deb); + +return; +} + + +/* Activate the unit. + + The specified unit is activated using the unit's "wait" time. If debugging + is enabled, the activation is logged to the debug file. +*/ + +static t_stat activate_unit (UNIT *uptr) +{ +int32 unit; +t_stat result; + +if (DEBUG_PRI (ds_dev, DEB_SERV)) { + unit = uptr - ds_unit; /* calculate the unit number */ + + if (uptr == &ds_cntlr) + fprintf (sim_deb, ">>DS serv: Controller delay %d service scheduled\n", + uptr->wait); + else + fprintf (sim_deb, ">>DS serv: Unit %d delay %d service scheduled\n", + unit, uptr->wait); + } + +result = sim_activate (uptr, uptr->wait); /* activate the unit */ +uptr->wait = 0; /* reset the activation time */ + +return result; /* return the activation status */ +} diff --git a/HP2100/hp2100_fp.c b/HP2100/hp2100_fp.c index 10331795..20ea6c47 100644 --- a/HP2100/hp2100_fp.c +++ b/HP2100/hp2100_fp.c @@ -1,408 +1,410 @@ -/* hp2100_fp.c: HP 2100 floating point instructions - - Copyright (c) 2002-2008, Robert M. Supnik - - 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 - ROBERT M SUPNIK 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 Robert M Supnik shall not be - used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from Robert M Supnik. - - 21-Jan-08 JDB Corrected fp_unpack mantissa high-word return - (from Mark Pizzolato) - 01-Dec-06 JDB Reworked FFP helpers for 1000-F support, deleted f_pwr2 - 22-Jul-05 RMS Fixed compiler warning in Solaris (from Doug Glyn) - 25-Feb-05 JDB Added FFP helpers f_pack, f_unpack, f_pwr2 - 11-Feb-05 JDB Fixed missing negative overflow renorm in StoreFP - 26-Dec-04 RMS Separated A/B from M[0/1] for DMA IO (from Dave Bryan) - 15-Jul-03 RMS Fixed signed/unsigned warning - 21-Oct-02 RMS Recoded for compatibility with 21MX microcode algorithms - - - The HP2100 uses a unique binary floating point format: - - 15 14 0 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - |S | fraction high | : A - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - | fraction low | exponent |XS| : A + 1 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - 15 8 7 1 0 - - where S = 0 for plus fraction, 1 for minus fraction - fraction = s.bbbbb..., 24 binary digits - exponent = 2**+/-n - XS = 0 for plus exponent, 1 for minus exponent - - Numbers can be normalized or unnormalized but are always normalized - when loaded. - - Unpacked floating point numbers are stored in structure ufp - - exp = exponent, 2's complement - h'l = fraction, 2's comp, left justified - - This routine tries to reproduce the algorithms of the 2100/21MX - microcode in order to achieve 'bug-for-bug' compatibility. In - particular, - - - The FIX code produces various results in B. - - The fraction multiply code uses 16b x 16b multiplies to produce - a 31b result. It always loses the low order bit of the product. - - The fraction divide code is an approximation that may produce - an error of 1 LSB. - - Signs are tracked implicitly as part of the fraction. Unnormalized - inputs may cause the packup code to produce the wrong sign. - - "Unclean" zeros (zero fraction, non-zero exponent) are processed - like normal operands. - - Implementation notes: - - 1. The 2100/1000-M/E Fast FORTRAN Processor (FFP) and 1000 F-Series Floating - Point Processor (FPP) simulations require that the host compiler support - 64-bit integers and the HAVE_INT64 symbol be defined during compilation. - If this symbol is defined, two-word floating-point operations are handled - in the FPP code, and this module is not used. If it is not defined, then - FFP and FPP operations are not available, and this module provides the - floating-point support. -*/ - -#include "hp2100_defs.h" -#include "hp2100_cpu.h" -#include "hp2100_cpu1.h" -#include "hp2100_fp.h" - -#if !defined (HAVE_INT64) /* int64 support unavailable */ - -struct ufp { /* unpacked fp */ - int32 exp; /* exp */ - uint32 fr; /* frac */ - }; - -#define FP_V_SIGN 31 /* sign */ -#define FP_M_SIGN 01 -#define FP_V_FR 8 /* fraction */ -#define FP_M_FR 077777777 -#define FP_V_EXP 1 /* exponent */ -#define FP_M_EXP 0177 -#define FP_V_EXPS 0 /* exp sign */ -#define FP_M_EXPS 01 -#define FP_SIGN (FP_M_SIGN << FP_V_SIGN) -#define FP_FR (FP_M_FR << FP_V_FR) -#define FP_EXP (FP_M_EXP << FP_V_EXP) -#define FP_EXPS (FP_M_EXPS << FP_V_EXPS) -#define FP_GETSIGN(x) (((x) >> FP_V_SIGN) & FP_M_SIGN) -#define FP_GETEXP(x) (((x) >> FP_V_EXP) & FP_M_EXP) -#define FP_GETEXPS(x) (((x) >> FP_V_EXPS) & FP_M_EXPS) - -#define FP_NORM (1 << (FP_V_SIGN - 1)) /* normalized */ -#define FP_LOW (1 << FP_V_FR) -#define FP_RNDP (1 << (FP_V_FR - 1)) /* round for plus */ -#define FP_RNDM (FP_RNDP - 1) /* round for minus */ - -#define FPAB ((((uint32) AR) << 16) | ((uint32) BR)) - -/* Fraction shift; 0 < shift < 32 */ - -#define FR_ARS(v,s) (((v) >> (s)) | (((v) & FP_SIGN)? \ - (((uint32) DMASK32) << (32 - (s))): 0)) & DMASK32 - -#define FR_NEG(v) ((~(v) + 1) & DMASK32) - -uint32 UnpackFP (struct ufp *fop, uint32 opnd); -void NegFP (struct ufp *fop); -void NormFP (struct ufp *fop); -uint32 PackFP (struct ufp *fop); -uint32 StoreFP (struct ufp *fop); - -/* Floating to integer conversion */ - -uint32 f_fix (void) -{ -struct ufp fop; -uint32 res = 0; - -UnpackFP (&fop, FPAB); /* unpack op */ -if (fop.exp < 0) { /* exp < 0? */ - AR = 0; /* result = 0 */ - return 0; /* B unchanged */ - } -if (fop.exp > 15) { /* exp > 15? */ - BR = AR; /* B has high bits */ - AR = 077777; /* result = 77777 */ - return 1; /* overflow */ - } -if (fop.exp < 15) { /* if not aligned */ - res = FR_ARS (fop.fr, 15 - fop.exp); /* shift right */ - AR = (res >> 16) & DMASK; /* AR gets result */ - } -BR = AR; -if ((AR & SIGN) && ((fop.fr | res) & DMASK)) /* any low bits lost? */ - AR = (AR + 1) & DMASK; /* round up */ -return 0; -} - -/* Integer to floating conversion */ - -uint32 f_flt (void) -{ -struct ufp res = { 15, 0 }; /* +, 2**15 */ - -res.fr = ((uint32) AR) << 16; /* left justify */ -StoreFP (&res); /* store result */ -return 0; /* clr overflow */ -} - -/* Floating point add/subtract */ - -uint32 f_as (uint32 opnd, t_bool sub) -{ -struct ufp fop1, fop2, t; -int32 ediff; - -UnpackFP (&fop1, FPAB); /* unpack A-B */ -UnpackFP (&fop2, opnd); /* get op */ -if (sub) { /* subtract? */ - fop2.fr = FR_NEG (fop2.fr); /* negate frac */ - if (fop2.fr == ((uint32) FP_SIGN)) { /* -1/2? */ - fop2.fr = fop2.fr >> 1; /* special case */ - fop2.exp = fop2.exp + 1; - } - } -if (fop1.fr == 0) fop1 = fop2; /* op1 = 0? res = op2 */ -else if (fop2.fr != 0) { /* op2 = 0? no add */ - if (fop1.exp < fop2.exp) { /* |op1| < |op2|? */ - t = fop2; /* swap operands */ - fop2 = fop1; - fop1 = t; - } - ediff = fop1.exp - fop2.exp; /* get exp diff */ - if (ediff <= 24) { - if (ediff) fop2.fr = FR_ARS (fop2.fr, ediff); /* denorm, signed */ - if ((fop1.fr ^ fop2.fr) & FP_SIGN) /* unlike signs? */ - fop1.fr = fop1.fr + fop2.fr; /* eff subtract */ - else { /* like signs */ - fop1.fr = fop1.fr + fop2.fr; /* eff add */ - if (fop2.fr & FP_SIGN) { /* both -? */ - if ((fop1.fr & FP_SIGN) == 0) { /* overflow? */ - fop1.fr = FP_SIGN | (fop1.fr >> 1); /* renormalize */ - fop1.exp = fop1.exp + 1; /* incr exp */ - } - } - else if (fop1.fr & FP_SIGN) { /* both +, cry out? */ - fop1.fr = fop1.fr >> 1; /* renormalize */ - fop1.exp = fop1.exp + 1; /* incr exp */ - } - } /* end else like */ - } /* end if ediff */ - } /* end if fop2 */ -return StoreFP (&fop1); /* store result */ -} - -/* Floating point multiply - passes diagnostic */ - -uint32 f_mul (uint32 opnd) -{ -struct ufp fop1, fop2; -struct ufp res = { 0, 0 }; -int32 shi1, shi2, t1, t2, t3, t4, t5; - -UnpackFP (&fop1, FPAB); /* unpack A-B */ -UnpackFP (&fop2, opnd); /* unpack op */ -if (fop1.fr && fop2.fr) { /* if both != 0 */ - res.exp = fop1.exp + fop2.exp + 1; /* exp = sum */ - shi1 = SEXT (fop1.fr >> 16); /* mpy hi */ - shi2 = SEXT (fop2.fr >> 16); /* mpc hi */ - t1 = shi2 * ((int32) ((fop1.fr >> 1) & 077600)); /* mpc hi * (mpy lo/2) */ - t2 = shi1 * ((int32) ((fop2.fr >> 1) & 077600)); /* mpc lo * (mpy hi/2) */ - t3 = t1 + t2; /* cross product */ - t4 = (shi1 * shi2) & ~1; /* mpy hi * mpc hi */ - t5 = (SEXT (t3 >> 16)) << 1; /* add in cross */ - res.fr = (t4 + t5) & DMASK32; /* bit<0> is lost */ - } -return StoreFP (&res); /* store */ -} - -/* Floating point divide - reverse engineered from diagnostic */ - -uint32 divx (uint32 ba, uint32 dvr, uint32 *rem) -{ -int32 sdvd = 0, sdvr = 0; -uint32 q, r; - -if (ba & FP_SIGN) sdvd = 1; /* 32b/16b signed dvd */ -if (dvr & SIGN) sdvr = 1; /* use old-fashioned */ -if (sdvd) ba = (~ba + 1) & DMASK32; /* unsigned divides, */ -if (sdvr) dvr = (~dvr + 1) & DMASK; /* as results may ovflo */ -q = ba / dvr; -r = ba % dvr; -if (sdvd ^ sdvr) q = (~q + 1) & DMASK; -if (sdvd) r = (~r + 1) & DMASK; -if (rem) *rem = r; -return q; -} - -uint32 f_div (uint32 opnd) -{ -struct ufp fop1, fop2; -struct ufp quo = { 0, 0 }; -uint32 ba, q0, q1, q2, dvrh; - -UnpackFP (&fop1, FPAB); /* unpack A-B */ -UnpackFP (&fop2, opnd); /* unpack op */ -dvrh = (fop2.fr >> 16) & DMASK; /* high divisor */ -if (dvrh == 0) { /* div by zero? */ - AR = 0077777; /* return most pos */ - BR = 0177776; - return 1; - } -if (fop1.fr) { /* dvd != 0? */ - quo.exp = fop1.exp - fop2.exp + 1; /* exp = diff */ - ba = FR_ARS (fop1.fr, 2); /* prevent ovflo */ - q0 = divx (ba, dvrh, &ba); /* Q0 = dvd / dvrh */ - ba = (ba & ~1) << 16; /* remainder */ - ba = FR_ARS (ba, 1); /* prevent ovflo */ - q1 = divx (ba, dvrh, NULL); /* Q1 = rem / dvrh */ - ba = (fop2.fr & 0xFF00) << 13; /* dvrl / 8 */ - q2 = divx (ba, dvrh, NULL); /* dvrl / dvrh */ - ba = -(SEXT (q2)) * (SEXT (q0)); /* -Q0 * Q2 */ - ba = (ba >> 16) & 0xFFFF; /* save ms half */ - if (q1 & SIGN) quo.fr = quo.fr - 0x00010000; /* Q1 < 0? -1 */ - if (ba & SIGN) quo.fr = quo.fr - 0x00010000; /* -Q0*Q2 < 0? */ - quo.fr = quo.fr + ((ba << 2) & 0xFFFF) + q1; /* rest prod, add Q1 */ - quo.fr = quo.fr << 1; /* shift result */ - quo.fr = quo.fr + (q0 << 16); /* add Q0 */ - } /* end if fop1.h */ -return StoreFP (&quo); /* store result */ -} - -/* Utility routines */ - -/* Unpack operand */ - -uint32 UnpackFP (struct ufp *fop, uint32 opnd) -{ -fop->fr = opnd & FP_FR; /* get frac */ -fop->exp = FP_GETEXP (opnd); /* get exp */ -if (FP_GETEXPS (opnd)) fop->exp = fop->exp | ~FP_M_EXP; /* < 0? sext */ -return FP_GETSIGN (opnd); /* return sign */ -} - -/* Normalize unpacked floating point number */ - -void NormFP (struct ufp *fop) -{ -if (fop->fr) { /* any fraction? */ - uint32 test = (fop->fr >> 1) & FP_NORM; - while ((fop->fr & FP_NORM) == test) { /* until norm */ - fop->exp = fop->exp - 1; - fop->fr = (fop->fr << 1); - } - } -else fop->exp = 0; /* clean 0 */ -return; -} - -/* Pack fp number */ - -uint32 PackFP (struct ufp *fop) -{ -return (fop->fr & FP_FR) | /* merge frac */ - ((fop->exp & FP_M_EXP) << FP_V_EXP) | /* and exp */ - ((fop->exp < 0)? (1 << FP_V_EXPS): 0); /* add exp sign */ -} - -/* Round fp number, store, generate overflow */ - -uint32 StoreFP (struct ufp *fop) -{ -uint32 sign, svfr, hi, ov = 0; - -NormFP (fop); /* normalize */ -svfr = fop->fr; /* save fraction */ -sign = FP_GETSIGN (fop->fr); /* save sign */ -fop->fr = (fop->fr + (sign? FP_RNDM: FP_RNDP)) & FP_FR; /* round */ -if ((fop->fr ^ svfr) & FP_SIGN) { /* sign change? */ - fop->fr = fop->fr >> 1; /* renormalize */ - fop->exp = fop->exp + 1; - } -else NormFP (fop); /* check for norm */ -if (fop->fr == 0) hi = 0; /* result 0? */ -else if (fop->exp < -(FP_M_EXP + 1)) { /* underflow? */ - hi = 0; /* store clean 0 */ - ov = 1; - } -else if (fop->exp > FP_M_EXP) { /* overflow? */ - hi = 0x7FFFFFFE; /* all 1's */ - ov = 1; - } -else hi = PackFP (fop); /* pack mant and exp */ -AR = (hi >> 16) & DMASK; -BR = hi & DMASK; -return ov; -} - - -/* Single-precision Fast FORTRAN Processor helpers. */ - -/* Pack mantissa and exponent and return fp value. */ - -uint32 fp_pack (OP *result, OP mantissa, int32 exponent, OPSIZE precision) -{ -struct ufp fop; -uint32 val; - -fop.fr = ((uint32) mantissa.fpk[0] << 16) | mantissa.fpk[1]; -fop.exp = exponent; -val = PackFP (&fop); -result->fpk[0] = (int16) (val >> 16); -result->fpk[1] = (int16) val; -return 0; -} - -/* Normalize, round, and pack mantissa and exponent and return fp value. */ - -uint32 fp_nrpack (OP *result, OP mantissa, int32 exponent, OPSIZE precision) -{ -struct ufp fop; -uint32 ovf; - -fop.fr = ((uint32) mantissa.fpk[0] << 16) | mantissa.fpk[1]; -fop.exp = exponent; -ovf = StoreFP (&fop); -result->fpk[0] = AR; -result->fpk[1] = BR; -return ovf; -} - -/* Unpack fp number in into mantissa and exponent. */ - -uint32 fp_unpack (OP *mantissa, int32 *exponent, OP packed, OPSIZE precision) -{ -struct ufp fop; -uint32 operand; - -operand = ((uint32) packed.fpk[0] << 16) | packed.fpk[1]; -UnpackFP (&fop, operand); -mantissa->fpk[0] = (uint16) (fop.fr >> 16); -mantissa->fpk[1] = (uint16) fop.fr; -*exponent = fop.exp; -return 0; -} - -#endif /* int64 support unavailable */ +/* hp2100_fp.c: HP 2100 floating point instructions + + Copyright (c) 2002-2015, Robert M. Supnik + + 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 + ROBERT M SUPNIK 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 Robert M Supnik shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + + 03-Jan-15 JDB Made the utility routines static + 21-Jan-08 JDB Corrected fp_unpack mantissa high-word return + (from Mark Pizzolato) + 01-Dec-06 JDB Reworked FFP helpers for 1000-F support, deleted f_pwr2 + 22-Jul-05 RMS Fixed compiler warning in Solaris (from Doug Glyn) + 25-Feb-05 JDB Added FFP helpers f_pack, f_unpack, f_pwr2 + 11-Feb-05 JDB Fixed missing negative overflow renorm in StoreFP + 26-Dec-04 RMS Separated A/B from M[0/1] for DMA IO (from Dave Bryan) + 15-Jul-03 RMS Fixed signed/unsigned warning + 21-Oct-02 RMS Recoded for compatibility with 21MX microcode algorithms + + + The HP2100 uses a unique binary floating point format: + + 15 14 0 + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + |S | fraction high | : A + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + | fraction low | exponent |XS| : A + 1 + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + 15 8 7 1 0 + + where S = 0 for plus fraction, 1 for minus fraction + fraction = s.bbbbb..., 24 binary digits + exponent = 2**+/-n + XS = 0 for plus exponent, 1 for minus exponent + + Numbers can be normalized or unnormalized but are always normalized + when loaded. + + Unpacked floating point numbers are stored in structure ufp + + exp = exponent, 2's complement + h'l = fraction, 2's comp, left justified + + This routine tries to reproduce the algorithms of the 2100/21MX + microcode in order to achieve 'bug-for-bug' compatibility. In + particular, + + - The FIX code produces various results in B. + - The fraction multiply code uses 16b x 16b multiplies to produce + a 31b result. It always loses the low order bit of the product. + - The fraction divide code is an approximation that may produce + an error of 1 LSB. + - Signs are tracked implicitly as part of the fraction. Unnormalized + inputs may cause the packup code to produce the wrong sign. + - "Unclean" zeros (zero fraction, non-zero exponent) are processed + like normal operands. + + Implementation notes: + + 1. The 2100/1000-M/E Fast FORTRAN Processor (FFP) and 1000 F-Series Floating + Point Processor (FPP) simulations require that the host compiler support + 64-bit integers and the HAVE_INT64 symbol be defined during compilation. + If this symbol is defined, two-word floating-point operations are handled + in the FPP code, and this module is not used. If it is not defined, then + FFP and FPP operations are not available, and this module provides the + floating-point support. +*/ + +#include "hp2100_defs.h" +#include "hp2100_cpu.h" +#include "hp2100_cpu1.h" +#include "hp2100_fp.h" + +#if !defined (HAVE_INT64) /* int64 support unavailable */ + +struct ufp { /* unpacked fp */ + int32 exp; /* exp */ + uint32 fr; /* frac */ + }; + +#define FP_V_SIGN 31 /* sign */ +#define FP_M_SIGN 01 +#define FP_V_FR 8 /* fraction */ +#define FP_M_FR 077777777 +#define FP_V_EXP 1 /* exponent */ +#define FP_M_EXP 0177 +#define FP_V_EXPS 0 /* exp sign */ +#define FP_M_EXPS 01 +#define FP_SIGN (FP_M_SIGN << FP_V_SIGN) +#define FP_FR (FP_M_FR << FP_V_FR) +#define FP_EXP (FP_M_EXP << FP_V_EXP) +#define FP_EXPS (FP_M_EXPS << FP_V_EXPS) +#define FP_GETSIGN(x) (((x) >> FP_V_SIGN) & FP_M_SIGN) +#define FP_GETEXP(x) (((x) >> FP_V_EXP) & FP_M_EXP) +#define FP_GETEXPS(x) (((x) >> FP_V_EXPS) & FP_M_EXPS) + +#define FP_NORM (1 << (FP_V_SIGN - 1)) /* normalized */ +#define FP_LOW (1 << FP_V_FR) +#define FP_RNDP (1 << (FP_V_FR - 1)) /* round for plus */ +#define FP_RNDM (FP_RNDP - 1) /* round for minus */ + +#define FPAB ((((uint32) AR) << 16) | ((uint32) BR)) + +/* Fraction shift; 0 < shift < 32 */ + +#define FR_ARS(v,s) (((v) >> (s)) | (((v) & FP_SIGN)? \ + (((uint32) DMASK32) << (32 - (s))): 0)) & DMASK32 + +#define FR_NEG(v) ((~(v) + 1) & DMASK32) + +/* Utility routines */ + +static uint32 UnpackFP (struct ufp *fop, uint32 opnd); +static void NormFP (struct ufp *fop); +static uint32 PackFP (struct ufp *fop); +static uint32 StoreFP (struct ufp *fop); + +/* Floating to integer conversion */ + +uint32 f_fix (void) +{ +struct ufp fop; +uint32 res = 0; + +UnpackFP (&fop, FPAB); /* unpack op */ +if (fop.exp < 0) { /* exp < 0? */ + AR = 0; /* result = 0 */ + return 0; /* B unchanged */ + } +if (fop.exp > 15) { /* exp > 15? */ + BR = AR; /* B has high bits */ + AR = 077777; /* result = 77777 */ + return 1; /* overflow */ + } +if (fop.exp < 15) { /* if not aligned */ + res = FR_ARS (fop.fr, 15 - fop.exp); /* shift right */ + AR = (res >> 16) & DMASK; /* AR gets result */ + } +BR = AR; +if ((AR & SIGN) && ((fop.fr | res) & DMASK)) /* any low bits lost? */ + AR = (AR + 1) & DMASK; /* round up */ +return 0; +} + +/* Integer to floating conversion */ + +uint32 f_flt (void) +{ +struct ufp res = { 15, 0 }; /* +, 2**15 */ + +res.fr = ((uint32) AR) << 16; /* left justify */ +StoreFP (&res); /* store result */ +return 0; /* clr overflow */ +} + +/* Floating point add/subtract */ + +uint32 f_as (uint32 opnd, t_bool sub) +{ +struct ufp fop1, fop2, t; +int32 ediff; + +UnpackFP (&fop1, FPAB); /* unpack A-B */ +UnpackFP (&fop2, opnd); /* get op */ +if (sub) { /* subtract? */ + fop2.fr = FR_NEG (fop2.fr); /* negate frac */ + if (fop2.fr == ((uint32) FP_SIGN)) { /* -1/2? */ + fop2.fr = fop2.fr >> 1; /* special case */ + fop2.exp = fop2.exp + 1; + } + } +if (fop1.fr == 0) fop1 = fop2; /* op1 = 0? res = op2 */ +else if (fop2.fr != 0) { /* op2 = 0? no add */ + if (fop1.exp < fop2.exp) { /* |op1| < |op2|? */ + t = fop2; /* swap operands */ + fop2 = fop1; + fop1 = t; + } + ediff = fop1.exp - fop2.exp; /* get exp diff */ + if (ediff <= 24) { + if (ediff) fop2.fr = FR_ARS (fop2.fr, ediff); /* denorm, signed */ + if ((fop1.fr ^ fop2.fr) & FP_SIGN) /* unlike signs? */ + fop1.fr = fop1.fr + fop2.fr; /* eff subtract */ + else { /* like signs */ + fop1.fr = fop1.fr + fop2.fr; /* eff add */ + if (fop2.fr & FP_SIGN) { /* both -? */ + if ((fop1.fr & FP_SIGN) == 0) { /* overflow? */ + fop1.fr = FP_SIGN | (fop1.fr >> 1); /* renormalize */ + fop1.exp = fop1.exp + 1; /* incr exp */ + } + } + else if (fop1.fr & FP_SIGN) { /* both +, cry out? */ + fop1.fr = fop1.fr >> 1; /* renormalize */ + fop1.exp = fop1.exp + 1; /* incr exp */ + } + } /* end else like */ + } /* end if ediff */ + } /* end if fop2 */ +return StoreFP (&fop1); /* store result */ +} + +/* Floating point multiply - passes diagnostic */ + +uint32 f_mul (uint32 opnd) +{ +struct ufp fop1, fop2; +struct ufp res = { 0, 0 }; +int32 shi1, shi2, t1, t2, t3, t4, t5; + +UnpackFP (&fop1, FPAB); /* unpack A-B */ +UnpackFP (&fop2, opnd); /* unpack op */ +if (fop1.fr && fop2.fr) { /* if both != 0 */ + res.exp = fop1.exp + fop2.exp + 1; /* exp = sum */ + shi1 = SEXT (fop1.fr >> 16); /* mpy hi */ + shi2 = SEXT (fop2.fr >> 16); /* mpc hi */ + t1 = shi2 * ((int32) ((fop1.fr >> 1) & 077600)); /* mpc hi * (mpy lo/2) */ + t2 = shi1 * ((int32) ((fop2.fr >> 1) & 077600)); /* mpc lo * (mpy hi/2) */ + t3 = t1 + t2; /* cross product */ + t4 = (shi1 * shi2) & ~1; /* mpy hi * mpc hi */ + t5 = (SEXT (t3 >> 16)) << 1; /* add in cross */ + res.fr = (t4 + t5) & DMASK32; /* bit<0> is lost */ + } +return StoreFP (&res); /* store */ +} + +/* Floating point divide - reverse engineered from diagnostic */ + +static uint32 divx (uint32 ba, uint32 dvr, uint32 *rem) +{ +int32 sdvd = 0, sdvr = 0; +uint32 q, r; + +if (ba & FP_SIGN) sdvd = 1; /* 32b/16b signed dvd */ +if (dvr & SIGN) sdvr = 1; /* use old-fashioned */ +if (sdvd) ba = (~ba + 1) & DMASK32; /* unsigned divides, */ +if (sdvr) dvr = (~dvr + 1) & DMASK; /* as results may ovflo */ +q = ba / dvr; +r = ba % dvr; +if (sdvd ^ sdvr) q = (~q + 1) & DMASK; +if (sdvd) r = (~r + 1) & DMASK; +if (rem) *rem = r; +return q; +} + +uint32 f_div (uint32 opnd) +{ +struct ufp fop1, fop2; +struct ufp quo = { 0, 0 }; +uint32 ba, q0, q1, q2, dvrh; + +UnpackFP (&fop1, FPAB); /* unpack A-B */ +UnpackFP (&fop2, opnd); /* unpack op */ +dvrh = (fop2.fr >> 16) & DMASK; /* high divisor */ +if (dvrh == 0) { /* div by zero? */ + AR = 0077777; /* return most pos */ + BR = 0177776; + return 1; + } +if (fop1.fr) { /* dvd != 0? */ + quo.exp = fop1.exp - fop2.exp + 1; /* exp = diff */ + ba = FR_ARS (fop1.fr, 2); /* prevent ovflo */ + q0 = divx (ba, dvrh, &ba); /* Q0 = dvd / dvrh */ + ba = (ba & ~1) << 16; /* remainder */ + ba = FR_ARS (ba, 1); /* prevent ovflo */ + q1 = divx (ba, dvrh, NULL); /* Q1 = rem / dvrh */ + ba = (fop2.fr & 0xFF00) << 13; /* dvrl / 8 */ + q2 = divx (ba, dvrh, NULL); /* dvrl / dvrh */ + ba = -(SEXT (q2)) * (SEXT (q0)); /* -Q0 * Q2 */ + ba = (ba >> 16) & 0xFFFF; /* save ms half */ + if (q1 & SIGN) quo.fr = quo.fr - 0x00010000; /* Q1 < 0? -1 */ + if (ba & SIGN) quo.fr = quo.fr - 0x00010000; /* -Q0*Q2 < 0? */ + quo.fr = quo.fr + ((ba << 2) & 0xFFFF) + q1; /* rest prod, add Q1 */ + quo.fr = quo.fr << 1; /* shift result */ + quo.fr = quo.fr + (q0 << 16); /* add Q0 */ + } /* end if fop1.h */ +return StoreFP (&quo); /* store result */ +} + +/* Utility routines */ + +/* Unpack operand */ + +static uint32 UnpackFP (struct ufp *fop, uint32 opnd) +{ +fop->fr = opnd & FP_FR; /* get frac */ +fop->exp = FP_GETEXP (opnd); /* get exp */ +if (FP_GETEXPS (opnd)) fop->exp = fop->exp | ~FP_M_EXP; /* < 0? sext */ +return FP_GETSIGN (opnd); /* return sign */ +} + +/* Normalize unpacked floating point number */ + +static void NormFP (struct ufp *fop) +{ +if (fop->fr) { /* any fraction? */ + uint32 test = (fop->fr >> 1) & FP_NORM; + while ((fop->fr & FP_NORM) == test) { /* until norm */ + fop->exp = fop->exp - 1; + fop->fr = (fop->fr << 1); + } + } +else fop->exp = 0; /* clean 0 */ +return; +} + +/* Pack fp number */ + +static uint32 PackFP (struct ufp *fop) +{ +return (fop->fr & FP_FR) | /* merge frac */ + ((fop->exp & FP_M_EXP) << FP_V_EXP) | /* and exp */ + ((fop->exp < 0)? (1 << FP_V_EXPS): 0); /* add exp sign */ +} + +/* Round fp number, store, generate overflow */ + +static uint32 StoreFP (struct ufp *fop) +{ +uint32 sign, svfr, hi, ov = 0; + +NormFP (fop); /* normalize */ +svfr = fop->fr; /* save fraction */ +sign = FP_GETSIGN (fop->fr); /* save sign */ +fop->fr = (fop->fr + (sign? FP_RNDM: FP_RNDP)) & FP_FR; /* round */ +if ((fop->fr ^ svfr) & FP_SIGN) { /* sign change? */ + fop->fr = fop->fr >> 1; /* renormalize */ + fop->exp = fop->exp + 1; + } +else NormFP (fop); /* check for norm */ +if (fop->fr == 0) hi = 0; /* result 0? */ +else if (fop->exp < -(FP_M_EXP + 1)) { /* underflow? */ + hi = 0; /* store clean 0 */ + ov = 1; + } +else if (fop->exp > FP_M_EXP) { /* overflow? */ + hi = 0x7FFFFFFE; /* all 1's */ + ov = 1; + } +else hi = PackFP (fop); /* pack mant and exp */ +AR = (hi >> 16) & DMASK; +BR = hi & DMASK; +return ov; +} + + +/* Single-precision Fast FORTRAN Processor helpers. */ + +/* Pack mantissa and exponent and return fp value. */ + +uint32 fp_pack (OP *result, OP mantissa, int32 exponent, OPSIZE precision) +{ +struct ufp fop; +uint32 val; + +fop.fr = ((uint32) mantissa.fpk[0] << 16) | mantissa.fpk[1]; +fop.exp = exponent; +val = PackFP (&fop); +result->fpk[0] = (int16) (val >> 16); +result->fpk[1] = (int16) val; +return 0; +} + +/* Normalize, round, and pack mantissa and exponent and return fp value. */ + +uint32 fp_nrpack (OP *result, OP mantissa, int32 exponent, OPSIZE precision) +{ +struct ufp fop; +uint32 ovf; + +fop.fr = ((uint32) mantissa.fpk[0] << 16) | mantissa.fpk[1]; +fop.exp = exponent; +ovf = StoreFP (&fop); +result->fpk[0] = AR; +result->fpk[1] = BR; +return ovf; +} + +/* Unpack fp number in into mantissa and exponent. */ + +uint32 fp_unpack (OP *mantissa, int32 *exponent, OP packed, OPSIZE precision) +{ +struct ufp fop; +uint32 operand; + +operand = ((uint32) packed.fpk[0] << 16) | packed.fpk[1]; +UnpackFP (&fop, operand); +mantissa->fpk[0] = (uint16) (fop.fr >> 16); +mantissa->fpk[1] = (uint16) fop.fr; +*exponent = fop.exp; +return 0; +} + +#endif /* int64 support unavailable */ diff --git a/HP2100/hp2100_fp.h b/HP2100/hp2100_fp.h index 4809da49..a3d5b33a 100644 --- a/HP2100/hp2100_fp.h +++ b/HP2100/hp2100_fp.h @@ -1,47 +1,48 @@ -/* hp2100_fp.h: HP 2100/21MX floating point definitions - - Copyright (c) 2002-2006, Robert M. Supnik - - 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 - ROBERT M SUPNIK 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 Robert M Supnik shall not be - used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from Robert M Supnik. - - 01-Dec-06 JDB Reworked FFP helpers for 1000-F support, deleted f_pwr2 - 26-Sep-06 JDB Moved from hp2100_fp.c to simplify extensions -*/ - -#ifndef _HP2100_FP_H_ -#define _HP2100_FP_H_ - -/* Firmware floating-point routines */ - -uint32 f_as (uint32 op, t_bool sub); /* FAD/FSB */ -uint32 f_mul (uint32 op); /* FMP */ -uint32 f_div (uint32 op); /* FDV */ -uint32 f_fix (void); /* FIX */ -uint32 f_flt (void); /* FLT */ - -/* Firmware FFP helpers */ - -uint32 fp_pack (OP *result, OP mantissa, int32 exponent, OPSIZE precision); -uint32 fp_nrpack (OP *result, OP mantissa, int32 exponent, OPSIZE precision); -uint32 fp_unpack (OP *mantissa, int32 *exponent, OP packed, OPSIZE precision); - -#endif +/* hp2100_fp.h: HP 2100/21MX floating point definitions + + Copyright (c) 2002-2013, Robert M. Supnik + + 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 + ROBERT M SUPNIK 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 Robert M Supnik shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + + 14-Mar-13 MP Changed guard macro name to avoid reserved namespace + 01-Dec-06 JDB Reworked FFP helpers for 1000-F support, deleted f_pwr2 + 26-Sep-06 JDB Moved from hp2100_fp.c to simplify extensions +*/ + +#ifndef HP2100_FP_H_ +#define HP2100_FP_H_ + +/* Firmware floating-point routines */ + +uint32 f_as (uint32 op, t_bool sub); /* FAD/FSB */ +uint32 f_mul (uint32 op); /* FMP */ +uint32 f_div (uint32 op); /* FDV */ +uint32 f_fix (void); /* FIX */ +uint32 f_flt (void); /* FLT */ + +/* Firmware FFP helpers */ + +uint32 fp_pack (OP *result, OP mantissa, int32 exponent, OPSIZE precision); +uint32 fp_nrpack (OP *result, OP mantissa, int32 exponent, OPSIZE precision); +uint32 fp_unpack (OP *mantissa, int32 *exponent, OP packed, OPSIZE precision); + +#endif diff --git a/HP2100/hp2100_fp1.c b/HP2100/hp2100_fp1.c index 94ce633a..47d24b84 100644 --- a/HP2100/hp2100_fp1.c +++ b/HP2100/hp2100_fp1.c @@ -1,1458 +1,1461 @@ -/* hp2100_fp1.c: HP 1000 multiple-precision floating point routines - - Copyright (c) 2005-2012, J. David Bryan - - 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 - THE AUTHOR 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 the author shall not be used - in advertising or otherwise to promote the sale, use or other dealings in - this Software without prior written authorization from the author. - - 06-Feb-12 JDB Added missing precision on constant "one" in fp_trun - 21-Jun-11 JDB Completed the comments for divide; no code changes - 08-Jun-08 JDB Quieted bogus gcc warning in fp_exec - 10-May-08 JDB Fixed uninitialized return in fp_accum when setting - 19-Mar-08 JDB Reworked "complement" to avoid inlining bug in gcc-4.x - 01-Dec-06 JDB Reworked into generalized multiple-precision ops for FPP - 12-Oct-06 JDB Altered x_trun for F-Series FFP compatibility - Added F-Series ..TCM FFP helpers - - Primary references: - - HP 1000 M/E/F-Series Computers Engineering and Reference Documentation - (92851-90001, Mar-1981) - - HP 1000 M/E/F-Series Computers Technical Reference Handbook - (5955-0282, Mar-1980) - - DOS/RTE Relocatable Library Reference Manual - (24998-90001, Oct-1981) - - - This module implements multiple-precision floating-point operations to - support the 1000 F-Series hardware Floating Point Processor. It employs - 64-bit integer arithmetic for speed and simplicity of implementation. The - host compiler must support 64-bit integers, and the HAVE_INT64 symbol must be - defined during compilation. If this symbol is not defined, then FPP support - is not available. - - HP 2100/1000 computers used a proprietary floating-point format. The 2100 - had optional firmware that provided two-word floating-point add, subtract, - multiply, and divide, as well as single-integer fix and float. The 1000-M/E - provided the same two-word firmware operations as standard equipment. - Three-word extended-precision instructions for the 2100 and 1000-M/E were - provided by the optional Fast FORTRAN Processor firmware. - - The 1000-F substituted a hardware floating point processor for the firmware - in previous machines. In addition to the two- and three-word formats, the - F-Series introduced a four-word double-precision format. A five-word format - that provided extra range in the exponent by unpacking it from the mantissa - was also provided, although this capability was not documented in the user - manual. In addition, the FPP improved the accuracy of floating-point - calculations, as the firmware versions sacrificed a few bits of precision to - gain speed. Consequently, operations on the F-Series may return results that - differ slightly from the same operations on the M/E-Series or the 2100. - - F-Series units after date code 1920 also provided two-word double-integer - instructions in firmware, as well as double-integer fix and float operations. - - The original 32-bit floating-point format is as follows: - - 15 14 0 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - |MS| mantissa high | : M - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - | mantissa low | exponent |XS| : M + 1 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - 15 8 7 1 0 - - Both 23-bit mantissa and 7-bit exponent are in twos-complement form. The - exponent sign bit has been rotated into the LSB of the second word. - - The extended-precision floating-point format is a 48-bit extension of the - 32-bit format used for single precision. A packed extended-precision value - consists of a 39-bit mantissa and a 7-bit exponent. The format is as - follows: - - 15 14 0 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - |MS| mantissa high | : M - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - | mantissa middle | : M + 1 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - | mantissa low | exponent |XS| : M + 2 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - 15 8 7 1 0 - - The double-precision floating-point format is similar to the 48-bit - extended-precision format, although with a 55-bit mantissa: - - 15 14 0 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - |MS| mantissa high | : M - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - | mantissa middle high | : M + 1 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - | mantissa middle low | : M + 2 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - | mantissa low | exponent |XS| : M + 3 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - 15 8 7 1 0 - - The FPP also supports a special five-word expanded-exponent format: - - 15 14 0 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - |MS| mantissa high | : M - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - | mantissa middle high | : M + 1 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - | mantissa middle low | : M + 2 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - | mantissa low | : M + 3 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - | exponent |XS| : M + 4 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - 15 8 7 1 0 - - The exponent is a full 16-bit twos-complement value, but the allowed range is - only 10 bits, i.e., -512 to +511. - - In a normalized value, the sign and MSB of the mantissa differ. Zero is - represented by all words = 0. - - Internally, unpacked floating-point values are contained in a structure - having a signed 64-bit mantissa and a signed 32-bit exponent. Mantissas are - left-justified with the unused bits masked to zero. Exponents are - right-justified. The precision is indicated by the value of a structure - field. - - HP terminology for the three-word floating-point format is confused. Some - documents refer to it as "double precision," while others use "extended - precision." The instruction mnemonics begin with "X" (e.g., .XADD), - suggesting the extended-precision term. - - HP apparently intended that the four-word double-precision format would be - called "triple-precision," as the instruction mnemonics begin with "T" (e.g., - ".TADD" for the four-word add instruction). The source files for the - software simulations of these instructions for the M/E-Series also explicitly - refer to "triple precision math." However, the engineering documentation and - the F-Series reference manual both use the double-precision term. - - This module adopts the single/extended/double terminology and uses the - initial letters of the instructions (F/X/T) to indicate the precision used. - - The FPP hardware consisted of two circuit boards that interfaced to the main - CPU via the Microprogrammable Processor Port (MPP) that had been introduced - with the 1000 E-Series. One board contained argument registers and ALUs, - split into separate mantissa and exponent parts. The other contained a state - machine sequencer. FPP results were copied automatically to the argument - registers in addition to being available over the MPP, so that chained - operations could be executed from these "accumulators" without reloading. - - The FPP operated independently of the CPU. An opcode, specifying one of the - six operations (add, subtract, multiply, divide, fix, or float) was sent to - the FPP, and a start command was given. Operands of appropriate precision - were then supplied to the FPP. Once the operands were received, the FPP - would execute and set a flag when the operation was complete. The result - would then be retrieved from the FPP. The floating-point instruction - firmware in the CPU initiated the desired FPP operation and handled operand - reads from and result writes to main memory. - - Under simulation, "fp_exec" provides the six arithmetic operations analogous - to FPP execution. The remainder of the functions are helpers that were - provided by firmware in the 1000-F but that can reuse code needed to simulate - the FPP hardware. As with the hardware, "fp_exec" retains the last result - in an internal accumulator that may be referenced in subsequent operations. - - NOTE: this module also provides the floating-point support for the firmware - single-precision 1000-M/E base set and extended-precision FFP instructions. - Because the firmware and hardware implementations returned slightly different - results, particularly with respect to round-off, conditional checks are - implemented in the arithmetic routines. In some cases, entirely different - algorithms are used to ensure fidelity with the real machines. Functionally, - this means that the 2100/1000-M/E and 1000-F floating-point diagnostics are - not interchangeable, and failures are to be expected if a diagnostic is run - on the wrong machine. -*/ - -#include "hp2100_defs.h" -#include "hp2100_cpu.h" -#include "hp2100_cpu1.h" -#include "hp2100_fp1.h" - - -#if defined (HAVE_INT64) /* we need int64 support */ - -/* Field widths. */ - -#define IN_W_SIGN 1 -#define IN_W_SMAGN 15 -#define IN_W_DMAGN 31 - -#define FP_W_MSIGN 1 -#define FP_W_FMANT 23 -#define FP_W_XMANT 39 -#define FP_W_TMANT 55 -#define FP_W_EMANT 55 -#define FP_W_EXPANDEXP 9 -#define FP_W_EXP 7 -#define FP_W_ESIGN 1 - -/* Starting bit numbers. */ - -#define IN_V_SIGN (64 - IN_W_SIGN) -#define IN_V_SNUM (64 - IN_W_SIGN - IN_W_SMAGN) -#define IN_V_DNUM (64 - IN_W_SIGN - IN_W_DMAGN) - -#define FP_V_FNUM (64 - FP_W_MSIGN - FP_W_FMANT - FP_W_EXP - FP_W_ESIGN) -#define FP_V_XNUM (64 - FP_W_MSIGN - FP_W_XMANT - FP_W_EXP - FP_W_ESIGN) -#define FP_V_TNUM (64 - FP_W_MSIGN - FP_W_TMANT - FP_W_EXP - FP_W_ESIGN) -#define FP_V_ENUM (64 - FP_W_MSIGN - FP_W_EMANT - FP_W_EXP - FP_W_ESIGN) - -#define FP_V_MSIGN (64 - FP_W_MSIGN) -#define FP_V_FMANT (64 - FP_W_MSIGN - FP_W_FMANT) -#define FP_V_XMANT (64 - FP_W_MSIGN - FP_W_XMANT) -#define FP_V_TMANT (64 - FP_W_MSIGN - FP_W_TMANT) -#define FP_V_EMANT (64 - FP_W_MSIGN - FP_W_EMANT) -#define FP_V_EXP 1 -#define FP_V_ESIGN 0 - -/* Right-aligned field masks. */ - -#define IN_M_SIGN (((t_uint64) 1 << IN_W_SIGN) - 1) -#define IN_M_SMAGN (((t_uint64) 1 << IN_W_SMAGN) - 1) -#define IN_M_DMAGN (((t_uint64) 1 << IN_W_DMAGN) - 1) - -#define FP_M_MSIGN (((t_uint64) 1 << FP_W_MSIGN) - 1) -#define FP_M_FMANT (((t_uint64) 1 << FP_W_FMANT) - 1) -#define FP_M_XMANT (((t_uint64) 1 << FP_W_XMANT) - 1) -#define FP_M_TMANT (((t_uint64) 1 << FP_W_TMANT) - 1) -#define FP_M_EMANT (((t_uint64) 1 << FP_W_EMANT) - 1) - -#define FP_M_EXPANDEXP ((1 << FP_W_EXPANDEXP) - 1) -#define FP_M_EXP ((1 << FP_W_EXP) - 1) -#define FP_M_ESIGN ((1 << FP_W_ESIGN) - 1) - -/* In-place field masks. */ - -#define IN_SIGN (IN_M_SIGN << IN_V_SIGN) -#define IN_SMAGN (IN_M_SMAGN << IN_V_SNUM) -#define IN_DMAGN (IN_M_DMAGN << IN_V_DNUM) - -#define FP_MSIGN (FP_M_MSIGN << FP_V_MSIGN) -#define FP_FMANT (FP_M_FMANT << FP_V_FMANT) -#define FP_XMANT (FP_M_XMANT << FP_V_XMANT) -#define FP_TMANT (FP_M_TMANT << FP_V_TMANT) -#define FP_EMANT (FP_M_EMANT << FP_V_EMANT) -#define FP_EXP (FP_M_EXP << FP_V_EXP) -#define FP_ESIGN (FP_M_ESIGN << FP_V_ESIGN) - -/* In-place record masks. */ - -#define IN_SSMAGN (IN_SIGN | IN_SMAGN) -#define IN_SDMAGN (IN_SIGN | IN_DMAGN) - -#define FP_SFMANT (FP_MSIGN | FP_FMANT) -#define FP_SXMANT (FP_MSIGN | FP_XMANT) -#define FP_STMANT (FP_MSIGN | FP_TMANT) -#define FP_SEMANT (FP_MSIGN | FP_EMANT) -#define FP_SEXP (FP_ESIGN | FP_EXP) - -/* Minima and maxima. */ - -#define FP_ONEHALF ((t_int64) 1 << (FP_V_MSIGN - 1)) /* mantissa = 0.5 */ -#define FP_MAXPMANT ((t_int64) FP_EMANT) /* maximum pos mantissa */ -#define FP_MAXNMANT ((t_int64) FP_MSIGN) /* maximum neg mantissa */ -#define FP_MAXPEXP (FP_M_EXPANDEXP) /* maximum pos expanded exponent */ -#define FP_MAXNEXP (-(FP_MAXPEXP + 1)) /* maximum neg expanded exponent */ - -/* Floating-point helpers. */ - -#define DENORM(x) ((((x) ^ (x) << 1) & FP_MSIGN) == 0) - -#define TO_EXP(e) (int8) ((e >> FP_V_EXP & FP_M_EXP) | \ - (e & FP_M_ESIGN ? ~FP_M_EXP : 0)) - -/* Property constants. */ - -static const t_int64 p_half_lsb[6] = { ((t_int64) 1 << IN_V_SNUM) - 1, /* different than FP! */ - ((t_int64) 1 << IN_V_DNUM) - 1, /* different than FP! */ - (t_int64) 1 << (FP_V_FMANT - 1), - (t_int64) 1 << (FP_V_XMANT - 1), - (t_int64) 1 << (FP_V_TMANT - 1), - (t_int64) 1 << (FP_V_EMANT - 1) }; - -static const t_int64 n_half_lsb[6] = { 0, - 0, - ((t_int64) 1 << (FP_V_FMANT - 1)) - 1, - ((t_int64) 1 << (FP_V_XMANT - 1)) - 1, - ((t_int64) 1 << (FP_V_TMANT - 1)) - 1, - ((t_int64) 1 << (FP_V_EMANT - 1)) - 1 }; - -static const uint32 op_start[6] = { IN_V_SNUM, - IN_V_DNUM, - FP_V_FMANT, - FP_V_XMANT, - FP_V_TMANT, - FP_V_EMANT }; - -static const t_int64 mant_mask[6] = { IN_SSMAGN, - IN_SDMAGN, - FP_SFMANT, - FP_SXMANT, - FP_STMANT, - FP_SEMANT }; - -static const uint32 op_bits[6] = { IN_W_SMAGN, - IN_W_DMAGN, - FP_W_FMANT + FP_W_MSIGN, - FP_W_XMANT + FP_W_MSIGN, - FP_W_TMANT + FP_W_MSIGN, - FP_W_EMANT + FP_W_MSIGN }; - -static const t_int64 op_mask[6] = { ~(t_int64) 0 << IN_V_SNUM, - ~(t_int64) 0 << IN_V_DNUM, - ~(t_int64) 0 << FP_V_FNUM, - ~(t_int64) 0 << FP_V_XNUM, - ~(t_int64) 0 << FP_V_TNUM, - ~(t_int64) 0 << FP_V_ENUM }; - -static const uint32 int_p_max[2] = { IN_M_SMAGN, - IN_M_DMAGN }; - - -/* Internal unpacked floating-point representation. */ - -typedef struct { - t_int64 mantissa; - int32 exponent; - OPSIZE precision; - } FPU; - - - -/* Low-level helper routines. */ - - -/* Arithmetic shift right for mantissa only. - - Returns TRUE if any one-bits are shifted out (for F-series only). -*/ - -static t_bool asr (FPU *operand, int32 shift) -{ -t_uint64 mask; -t_bool bits_lost; - -if (UNIT_CPU_MODEL == UNIT_1000_F) { /* F-series? */ - mask = ((t_uint64) 1 << shift) - 1; /* mask for lost bits */ - bits_lost = ((operand->mantissa & mask) != 0); /* flag if any lost */ - } -else - bits_lost = FALSE; - -operand->mantissa = operand->mantissa >> shift; /* mantissa is int, so ASR */ -return bits_lost; -} - - -/* Logical shift right for mantissa and exponent. - - Shifts mantissa and corrects exponent for mantissa overflow. - Returns TRUE if any one-bits are shifted out (for F-series only). -*/ - -static t_bool lsrx (FPU *operand, int32 shift) -{ -t_uint64 mask; -t_bool bits_lost; - -if (UNIT_CPU_MODEL == UNIT_1000_F) { /* F-series? */ - mask = ((t_uint64) 1 << shift) - 1; /* mask for lost bits */ - bits_lost = ((operand->mantissa & mask) != 0); /* flag if any lost */ - } -else - bits_lost = FALSE; - -operand->mantissa = (t_uint64) operand->mantissa >> shift; /* uint, so LSR */ -operand->exponent = operand->exponent + shift; /* correct exponent */ -return bits_lost; -} - - -/* Unpack an operand into a long integer. - - Returns a left-aligned integer or mantissa. Does not mask to precision; this - should be done subsequently if desired. -*/ - -static t_int64 unpack_int (OP packed, OPSIZE precision) -{ -uint32 i; -t_uint64 unpacked = 0; - -if (precision == in_s) - unpacked = (t_uint64) packed.word << 48; /* unpack single integer */ - -else if (precision == in_d) - unpacked = (t_uint64) packed.dword << 32; /* unpack double integer */ - -else { - if (precision == fp_e) /* five word operand? */ - precision = fp_t; /* only four mantissa words */ - - for (i = 0; i < 4; i++) /* unpack fp 2 to 4 words */ - if (i < TO_COUNT (precision)) - unpacked = unpacked << 16 | packed.fpk[i]; - else - unpacked = unpacked << 16; - } - -return (t_int64) unpacked; -} - - -/* Unpack a packed operand. - - The packed value is split into separate mantissa and exponent variables. The - multiple words of the mantissa are concatenated into a single 64-bit signed - value, and the exponent is shifted with recovery of the sign. -*/ - -static FPU unpack (OP packed, OPSIZE precision) -{ -FPU unpacked; - -unpacked.precision = precision; /* set value's precision */ - -unpacked.mantissa = /* unpack and mask mantissa */ - unpack_int (packed, precision) & mant_mask[precision]; - -switch (precision) { - - case fp_f: - case fp_x: - case fp_t: - unpacked.exponent = /* unpack exponent from correct word */ - TO_EXP (packed.fpk[(uint32) precision - 1]); - break; - - case fp_e: - unpacked.exponent = /* unpack expanded exponent */ - (int16) (packed.fpk[4] >> FP_V_EXP | /* rotate sign into place */ - (packed.fpk[4] & 1 ? SIGN : 0)); - break; - - case fp_a: /* no action for value in accum */ - case in_s: /* integers don't use exponent */ - case in_d: /* integers don't use exponent */ - default: - unpacked.exponent = 0; - break; - } - -return unpacked; -} - - -/* Pack a long integer into an operand. */ - -static OP pack_int (t_int64 unpacked, OPSIZE precision) -{ -int32 i; -OP packed; - -if (precision == in_s) - packed.word = (uint16) (unpacked >> 48) & DMASK; /* pack single integer */ - -else if (precision == in_d) - packed.dword = (uint32) (unpacked >> 32) & DMASK32; /* pack double integer */ - -else { - if (precision == fp_e) /* five word operand? */ - precision = fp_t; /* only four mantissa words */ - - for (i = 3; i >= 0; i--) { /* pack fp 2 to 4 words */ - packed.fpk[i] = (uint16) unpacked & DMASK; - unpacked = unpacked >> 16; - } - } - -return packed; -} - - -/* Pack an unpacked floating-point number. - - The 64-bit mantissa is split into the appropriate number of 16-bit words. - The exponent is rotated to incorporate the sign bit and merged into the - appropriate word. -*/ - -static OP pack (FPU unpacked) -{ -OP packed; -uint8 exp; - -packed = pack_int (unpacked.mantissa, unpacked.precision); /* pack mantissa */ - -exp = ((uint8) unpacked.exponent << FP_V_EXP) | /* rotate exponent */ - ((unpacked.exponent < 0) << FP_V_ESIGN); - -switch (unpacked.precision) { /* merge exponent into correct word */ - - case in_s: /* no action for integers */ - case in_d: - break; - - case fp_f: /* merge into last word */ - case fp_x: - case fp_t: - packed.fpk[(uint32) unpacked.precision - 1] = - (packed.fpk[(uint32) unpacked.precision - 1] & ~FP_SEXP) | exp; - break; - - case fp_e: /* place in separate word */ - packed.fpk[4] = ((uint16) unpacked.exponent << FP_V_EXP) | - ((unpacked.exponent < 0) << FP_V_ESIGN); - break; - - case fp_a: /* no action for value in accum */ - break; - } - -return packed; -} - - -/* Normalize an unpacked floating-point number. - - Floating-point numbers are in normal form if the sign bit and the MSB of the - mantissa differ. Unnormalized numbers are shifted as needed with appropriate - exponent modification. -*/ - -static void normalize (FPU *unpacked) -{ - -if (unpacked->mantissa) /* non-zero? */ - while (DENORM (unpacked->mantissa)) { /* normal form? */ - unpacked->exponent = unpacked->exponent - 1; /* no, so left shift */ - unpacked->mantissa = unpacked->mantissa << 1; - } -else - unpacked->exponent = 0; /* clean for zero */ -return; -} - - -/* Round an unpacked floating-point number and check for overflow. - - An unpacked floating-point number is rounded by adding one-half of the LSB - value, maintaining symmetry around zero. If rounding resulted in a mantissa - overflow, the result logically is shifted to the right with an appropriate - exponent modification. Finally, the result is checked for exponent underflow - or overflow, and the appropriate approximation (zero or infinity) is - returned. - - Rounding in hardware involves a special mantissa extension register that - holds three "guard" bits and one "sticky" bit. These represent the value of - bits right-shifted out the mantissa register. Under simulation, we track - such right-shifts and utilize the lower eight bits of the 64-bit mantissa - value to simulate the extension register. - - Overflow depends on whether the FPP expanded-exponent form is being used - (this expands the exponent range by two bits). If overflow is detected, the - value representing infinity is dependent on whether the operation is on - behalf of the Fast FORTRAN Processor. The F-Series FPP returns positive - infinity on both positive and negative overflow for all precisions. The 2100 - and M/E-Series FFPs return negative infinity on negative overflow of - extended-precision values. Single-precision overflows on these machines - always return positive infinity. - - The number to be rounded must be normalized upon entry. -*/ - -static uint32 roundovf (FPU *unpacked, t_bool expand) -{ -uint32 overflow; -t_bool sign; - -sign = (unpacked->mantissa < 0); /* save mantissa sign */ - -if (sign) /* round and mask the number */ - unpacked->mantissa = - (unpacked->mantissa + n_half_lsb[unpacked->precision]) & - mant_mask[unpacked->precision]; -else - unpacked->mantissa = - (unpacked->mantissa + p_half_lsb[unpacked->precision]) & - mant_mask[unpacked->precision]; - -if (sign != (unpacked->mantissa < 0)) /* mantissa overflow? */ - lsrx (unpacked, 1); /* correct by shifting */ -else - normalize (unpacked); /* renorm may be needed */ - -if (unpacked->mantissa == 0) { /* result zero? */ - unpacked->mantissa = 0; /* return zero */ - unpacked->exponent = 0; - overflow = 0; /* with overflow clear */ - } -else if (unpacked->exponent < /* result underflow? */ - (FP_MAXNEXP >> (expand ? 0 : 2))) { - unpacked->mantissa = 0; /* return zero */ - unpacked->exponent = 0; - overflow = 1; /* and set overflow */ - } -else if (unpacked->exponent > /* result overflow? */ - (FP_MAXPEXP >> (expand ? 0 : 2))) { - if (sign && /* negative value? */ - (unpacked->precision == fp_x) && /* extended precision? */ - (UNIT_CPU_MODEL != UNIT_1000_F)) { /* not F-series? */ - unpacked->mantissa = FP_MAXNMANT; /* return negative infinity */ - unpacked->exponent = FP_MAXPEXP & FP_M_EXP; - } - else { - unpacked->mantissa = FP_MAXPMANT; /* return positive infinity */ - unpacked->exponent = FP_MAXPEXP & FP_M_EXP; - } - overflow = 1; /* and set overflow */ - } -else - overflow = 0; /* value is in range */ - -return overflow; -} - - -/* Normalize, round, and pack an unpacked floating-point number. */ - -static uint32 nrpack (OP *packed, FPU unpacked, t_bool expand) -{ -uint32 overflow; - -normalize (&unpacked); /* normalize for rounding */ -overflow = roundovf (&unpacked, expand); /* round and check for overflow */ -*packed = pack (unpacked); /* pack result */ - -return overflow; -} - - - -/* Low-level arithmetic routines. */ - - -/* Complement an unpacked number. */ - -static void complement (FPU *result) -{ -if (result->mantissa == FP_MAXNMANT) { /* maximum negative? */ - result->mantissa = FP_ONEHALF; /* complement of -1.0 * 2 ^ n */ - result->exponent = result->exponent + 1; /* is 0.5 * 2 ^ (n + 1) */ - } -else - result->mantissa = -result->mantissa; /* negate mantissa */ -return; -} - - -/* Add two unpacked numbers. - - The mantissas are first aligned if necessary by scaling the smaller of the - two operands. If the magnitude of the difference between the exponents is - greater than the number of significant bits, then the smaller number has been - scaled to zero (swamped), and so the sum is simply the larger operand. - Otherwise, the sum is computed and checked for overflow, which has occurred - if the signs of the operands are the same but differ from that of the result. - Scaling and renormalization is performed if overflow occurred. -*/ - -static void add (FPU *sum, FPU augend, FPU addend) -{ -int32 magn; -t_bool bits_lost; - -if (augend.mantissa == 0) - *sum = addend; /* X + 0 = X */ - -else if (addend.mantissa == 0) - *sum = augend; /* 0 + X = X */ - -else { - magn = augend.exponent - addend.exponent; /* difference exponents */ - - if (magn > 0) { /* addend smaller? */ - *sum = augend; /* preset augend */ - bits_lost = asr (&addend, magn); /* align addend */ - } - else { /* augend smaller? */ - *sum = addend; /* preset addend */ - magn = -magn; /* make difference positive */ - bits_lost = asr (&augend, magn); /* align augend */ - } - - if (magn <= (int32) op_bits[augend.precision]) { /* value swamped? */ - sum->mantissa = /* no, add mantissas */ - addend.mantissa + augend.mantissa; - - if (((addend.mantissa < 0) == (augend.mantissa < 0)) && /* mantissa overflow? */ - ((addend.mantissa < 0) != (sum->mantissa < 0))) { - bits_lost = bits_lost | lsrx (sum, 1); /* restore value */ - sum->mantissa = /* restore sign */ - sum-> mantissa | (addend.mantissa & FP_MSIGN); - } - - if (bits_lost) /* any bits lost? */ - sum->mantissa = sum->mantissa | 1; /* include one for rounding */ - } - } -return; -} - - -/* Multiply two unpacked numbers. - - The single-precision firmware (FMP) operates differently from the firmware - extended-precision (.XMPY) and the hardware multiplies of any precision. - Firmware implementations use the MPY micro-order to form 16-bit x 16-bit = - 32-bit partial products and sum them to form the result. The hardware uses a - series of shifts and adds. This means that firmware FMP and hardware FMP - return slightly different values, as may be seen by attempting to run the - firmware FMP diagnostic on the FPP. - - The FMP microcode calls a signed multiply routine to calculate three partial - products (all but LSB * LSB). Because the LSBs are unsigned, i.e., all bits - significant, the two MSB * LSB products are calculated using LSB/2. The - unsigned right-shift ensures a positive LSB with no significant bits lost, - because the lower eight bits are unused (they held the vacated exponent). In - order to sum the partial products, the LSB of the result of MSB * MSB is also - right-shifted before addition. Note, though, that this loses a significant - bit. After summation, the result is left-shifted to correct for the original - right shifts. - - The .XMPY microcode negates both operands as necessary to produce positive - values and then forms six of the nine 16-bit x 16-bit = 32-bit unsigned - multiplications required for a full 96-bit product. Given a 48-bit - multiplicand "a1a2a3" and a 48-bit multiplier "b1b2b3", the firmware performs - these calculations to develop a 48-bit product: - - a1 a2 a3 - +-------+-------+-------+ - b1 b2 b3 - +-------+-------+-------+ - _________________________ - - a1 * b3 [p1] - +-------+-------+ - a2 * b2 [p2] - +-------+-------+ - a1 * b2 [p3] - +-------+-------+ - a3 * b1 [p4] - +-------+-------+ - a2 * b1 [p5] - +-------+-------+ - a1 * b1 [p6] - +-------+-------+ - _________________________________ - - product - +-------+-------+-------+ - - The least-significant words of partial products [p1], [p2], and [p4] are used - only to develop a carry bit into the 48-bit sum. The product is complemented - as necessary to restore the sign. - - The basic FPP hardware algorithm scans the multiplier and adds a shifted copy - of the multiplicand whenever a one-bit is detected. To avoid successive adds - when a string of ones is encountered (because adds are more expensive than - shifts), the hardware instead adds the multiplicand shifted by N + 1 + P and - subtracts the multiplicand shifted by P to obtain the equivalent value with a - maximum of two operations. - - Instead of implementing either the .XMPY firmware algorithm or the hardware - shift-and-add algorithm directly, it is more efficient under simulation to - use 32 x 32 = 64-bit multiplications, thereby reducing the number required - from six to four (64-bit "c1c2" x 64-bit "d1d2"): - - ah al - +-------+-------+ - bh bl - +-------+-------+ - _________________ - - al * bl [ll] - +-------+-------+ - ah * bl [hl] - +-------+-------+ - al * bh [lh] - +-------+-------+ - ah * bh [hh] - +-------+-------+ - _________________________________ - - product - +-------+-------+ - - However, the FMP algorithm is implemented directly from the microcode to - preserve the fidelity of the simulation, i.e., to lose the same amount - of precision. -*/ - -static void multiply (FPU *product, FPU multiplicand, FPU multiplier) -{ -uint32 ah, al, bh, bl, sign = 0; -t_uint64 hh, hl, lh, ll, carry; -int16 ch, cl, dh, dl; -t_bool firmware; - -product->precision = multiplicand.precision; /* set precision */ - -if ((multiplicand.mantissa == 0) || /* 0 * X = 0 */ - (multiplier.mantissa == 0)) /* X * 0 = 0 */ - product->mantissa = product->exponent = 0; - -else { - firmware = (UNIT_CPU_MODEL != UNIT_1000_F); /* set firmware flag */ - - if (!firmware || (product->precision != fp_f)) { /* hardware? */ - if (multiplicand.mantissa < 0) { /* negative? */ - complement (&multiplicand); /* complement operand */ - sign = ~sign; /* track sign */ - } - if (multiplier.mantissa < 0) { /* negative? */ - complement (&multiplier); /* complement operand */ - sign = ~sign; /* track sign */ - } - } - - product->exponent = /* compute exponent */ - multiplicand.exponent + multiplier.exponent + 1; - - ah = (uint32) (multiplicand.mantissa >> 32); /* split multiplicand */ - al = (uint32) (multiplicand.mantissa & DMASK32); /* into high and low parts */ - bh = (uint32) (multiplier.mantissa >> 32); /* split multiplier */ - bl = (uint32) (multiplier.mantissa & DMASK32); /* into high and low parts */ - - if (firmware && (product->precision == fp_f)) { /* single-precision firmware? */ - ch = (int16) (ah >> 16) & DMASK; /* split 32-bit multiplicand */ - cl = (int16) (ah & 0xfffe); /* into high and low parts */ - dh = (int16) (bh >> 16) & DMASK; /* split 32-bit multiplier */ - dl = (int16) (bh & 0xfffe); /* into high and low parts */ - - hh = (t_uint64) (((int32) ch * dh) & ~1); /* form cross products */ - hl = (t_uint64) (((t_int64) ch * (t_int64) (uint16) dl + - (t_int64) dh * (t_int64) (uint16) cl) & - 0xfffffffffffe0000); - - product->mantissa = (t_uint64) (((t_int64) hh << 32) + /* sum partials */ - ((t_int64) hl << 16)); - } - - else { - hh = ((t_uint64) ah * bh); /* form four cross products */ - hl = ((t_uint64) ah * bl); /* using 32 x 32 = */ - lh = ((t_uint64) al * bh); /* 64-bit multiplies */ - ll = ((t_uint64) al * bl); - - carry = ((ll >> 32) + (uint32) hl + (uint32) lh) >> 32; /* form carry */ - - product->mantissa = hh + (hl >> 32) + (lh >> 32) + carry; /* sum partials */ - - if (sign) /* negate if required */ - complement (product); - } - } -return; -} - - -/* Divide two unpacked numbers. - - As with multiply, the single-precision firmware (FDV) operates differently - from the firmware extended-precision (.XDIV) and the hardware divisions of - any precision. Firmware implementations use the DIV micro-order to form - 32-bit / 16-bit = 16-bit quotients and 16-bit remainders. These are used in - a "divide and correct" algorithm, wherein the quotient is estimated and then - corrected by comparing the dividend to the product of the quotient and the - divisor. The hardware uses a series of shifts and subtracts. This means - that firmware FDV and hardware FDV once again return slightly different - values. - - Under simulation, the classic divide-and-correct method is employed, using - 64-bit / 32-bit = 32-bit divisions. This method considers the 64-bit - dividend and divisor each to consist of two 32-bit "digits." The 64-bit - dividend "a1a2a3a4" is divided by the first 32-bit digit "b1b2" of the 64-bit - divisor "b1b2b3b4", yielding a 32-bit trial quotient digit and a 32-bit - remainder digit. A correction is developed by subtracting the product of the - second 32-bit digit "b3b4" of the divisor and the trial quotient digit from - the remainder (we take advantage of the eight bits vacated by the exponent - during unpacking to ensure that this product will not overflow into the sign - bit). If the remainder is negative, the trial quotient is too large, so it - is decremented, and the (full 64-bit) divisor is added to the correction. - This is repeated until the correction is non-negative, indicating that the - first quotient digit is correct. The process is then repeated using the - remainder as the dividend to develop the second 32-bit digit of the quotient. - The two digits are then concatenated for produce the final 64-bit value. - - (See, "Divide-and-Correct Methods for Multiple Precision Division" by Marvin - L. Stein, Communications of the ACM, August 1964 for background.) - - The microcoded single-precision division avoids overflows by right-shifting - some values, which leads to a loss of precision in the LSBs. We duplicate - the firmware algorithm here to preserve the fidelity of the simulation. -*/ - -static void divide (FPU *quotient, FPU dividend, FPU divisor) -{ -uint32 sign = 0; -t_int64 bh, bl, r1, r0, p1, p0; -t_uint64 q, q1, q0; -t_bool firmware; -int32 ah, div, cp; -int16 dh, dl, pq1, pq2, cq; - -quotient->precision = dividend.precision; /* set precision */ - -if (divisor.mantissa == 0) { /* division by zero? */ - if (dividend.mantissa < 0) - quotient->mantissa = FP_MSIGN; /* return minus infinity */ - else - quotient->mantissa = ~FP_MSIGN; /* or plus infinity */ - quotient->exponent = FP_MAXPEXP + 1; - } - -else if (dividend.mantissa == 0) /* dividend zero? */ - quotient->mantissa = quotient->exponent = 0; /* yes; result is zero */ - -else { - firmware = (UNIT_CPU_MODEL != UNIT_1000_F); /* set firmware flag */ - - if (!firmware || (quotient->precision != fp_f)) { /* hardware or FFP? */ - if (dividend.mantissa < 0) { /* negative? */ - complement (÷nd); /* complement operand */ - sign = ~sign; /* track sign */ - } - if (divisor.mantissa < 0) { /* negative? */ - complement (&divisor); /* complement operand */ - sign = ~sign; /* track sign */ - } - } - - quotient->exponent = /* division subtracts exponents */ - dividend.exponent - divisor.exponent; - - bh = divisor.mantissa >> 32; /* split divisor */ - bl = divisor.mantissa & DMASK32; /* into high and low parts */ - - if (firmware && (quotient->precision == fp_f)) { /* single-precision firmware? */ - quotient->exponent = quotient->exponent + 1; /* fix exponent */ - - ah = (int32) (dividend.mantissa >> 32); /* split dividend */ - dh = (int16) (bh >> 16); /* split divisor again */ - dl = (int16) bh; - - div = ah >> 2; /* ASR 2 to prevent overflow */ - - pq1 = div / dh; /* form first partial quotient */ - div = ((div % dh) & ~1) << 15; /* ASR 1, move rem to upper */ - pq2 = div / dh; /* form second partial quotient */ - - div = (uint16) dl << 13; /* move divisor LSB to upper, LSR 3 */ - cq = div / dh; /* form correction quotient */ - cp = -cq * pq1; /* and correction product */ - - cp = (((cp >> 14) & ~3) + (int32) pq2) << 1; /* add corr prod and 2nd partial quo */ - quotient->mantissa = /* add 1st partial quo and align */ - (t_uint64) (((int32) pq1 << 16) + cp) << 32; - } - - else { /* hardware or FFP */ - q1 = (t_uint64) (dividend.mantissa / bh); /* form 1st trial quotient */ - r1 = dividend.mantissa % bh; /* and remainder */ - p1 = (r1 << 24) - (bl >> 8) * q1; /* calculate correction */ - - while (p1 < 0) { /* correction needed? */ - q1 = q1 - 1; /* trial quotient too large */ - p1 = p1 + (divisor.mantissa >> 8); /* increase remainder */ - } - - q0 = (t_uint64) ((p1 << 8) / bh); /* form 2nd trial quotient */ - r0 = (p1 << 8) % bh; /* and remainder */ - p0 = (r0 << 24) - (bl >> 8) * q0; /* calculate correction */ - - while (p0 < 0) { /* correction needed? */ - q0 = q0 - 1; /* trial quotient too large */ - p0 = p0 + (divisor.mantissa >> 8); /* increase remainder */ - } - - q = (q1 << 32) + q0; /* sum quotient digits */ - - if (q1 & 0xffffffff00000000) { /* did we lose MSB? */ - q = (q >> 1) | 0x8000000000000000; /* shift right and replace bit */ - quotient->exponent = quotient->exponent + 1;/* bump exponent for shift */ - } - - if (q & 0x8000000000000000) /* lose normalization? */ - q = q >> 1; /* correct */ - - quotient->mantissa = (t_int64) q; - } - - if (sign) - complement (quotient); /* negate if required */ - } -return; -} - - -/* Fix an unpacked number. - - A floating-point value is converted to an integer. The desired precision of - the result (single or double integer) must be set before calling. - - Values less than 0.5 (i.e., with negative exponents) underflow to zero. If - the value exceeds the specified integer range, the maximum integer value is - returned and overflow is set. Otherwise, the floating-point value is - right-shifted to zero the exponent. The result is then rounded. -*/ - -static uint32 fix (FPU *result, FPU operand) -{ -uint32 overflow; -t_bool bits_lost; - -if (operand.exponent < 0) { /* value < 0.5? */ - result->mantissa = 0; /* result rounds to zero */ - overflow = 0; /* clear for underflow */ - } - -else if (operand.exponent > /* value > integer size? */ - (int32) op_bits[result->precision]) { - result->mantissa = /* return max int value */ - (t_uint64) int_p_max[result->precision] << - op_start[result->precision]; - overflow = 1; /* and set overflow */ - } - -else { /* value in range */ - bits_lost = asr (&operand, /* shift to zero exponent */ - op_bits[result->precision] - operand.exponent); - - if (operand.mantissa < 0) { /* value negative? */ - if (bits_lost) /* bits lost? */ - operand.mantissa = operand.mantissa | 1; /* include one for rounding */ - - operand.mantissa = operand.mantissa + /* round result */ - p_half_lsb[result->precision]; - } - - result->mantissa = operand.mantissa & /* mask to precision */ - op_mask[result->precision]; - overflow = 0; - } - -result->exponent = 0; /* tidy up for integer value */ -return overflow; -} - - -/* Float an integer to an unpacked number. - - An integer is converted to a floating-point value. The desired precision of - the result must be set before calling. - - Conversion is simply a matter of copying the integer value, setting an - exponent that reflects the right-aligned position of the bits, and - normalizing. -*/ - -static void ffloat (FPU *result, FPU operand) -{ -result->mantissa = operand.mantissa; /* set value */ -result->exponent = op_bits[operand.precision]; /* set exponent */ -normalize (result); /* normalize */ -return; -} - - - -/* High-level floating-point routines. */ - - -/* Determine operand precisions. - - The precisions of the operands and result are determined by decoding an - operation opcode and returned to the caller. Pass NULL for both of the - operands if only the result precision is wanted. Pass NULL for the result if - only the operand precisions are wanted. - - Implementation note: - - 1. gcc-4.3.0 complains at -O3 that operand_l/r may not be initialized. - Because of the mask, the switch statement covers all cases, but gcc - doesn't realize this. The "default" case is redundant but eliminates the - warning. -*/ - -void fp_prec (uint16 opcode, OPSIZE *operand_l, OPSIZE *operand_r, OPSIZE *result) -{ -OPSIZE fp_size, int_size; - -fp_size = (OPSIZE) ((opcode & 0003) + 2); /* fp_f, fp_x, fp_t, fp_e */ -int_size = (OPSIZE) ((opcode & 0004) >> 2); /* in_s, in_d */ - -if (operand_l && operand_r) { /* want operand precisions? */ - switch (opcode & 0120) { /* mask out opcode bit 5 */ - case 0000: /* add/mpy */ - case 0020: /* sub/div */ - *operand_l = fp_size; /* assume first op is fp */ - - if (opcode & 0004) /* operand internal? */ - *operand_r = fp_a; /* second op is accum */ - else - *operand_r = fp_size; /* second op is fp */ - break; - - case 0100: /* fix/accum as integer */ - *operand_l = fp_size; /* first op is fp */ - *operand_r = fp_a; /* second op is always null */ - break; - - case 0120: /* flt/accum as float */ - default: /* keeps compiler quiet for uninit warning */ - *operand_l = int_size; /* first op is integer */ - *operand_r = fp_a; /* second op is always null */ - break; - } - - if (opcode & 0010) /* operand internal? */ - *operand_l = fp_a; /* first op is accum */ - } - -if (result) /* want result precision? */ - if ((opcode & 0120) == 0100) /* fix? */ - *result = int_size; /* result is integer */ - else /* all others */ - *result = fp_size; /* result is fp */ - -return; -} - - -/* Floating Point Processor executor. - - The executor simulates the MPP interface between the CPU and the FPP. The - operation to be performed is specified by the supplied opcode, which conforms - to the FPP hardware interface, as follows: - - Bits Value Action - ---- ----- ---------------------------------------------- - 7 0 Exponent range is standard (+/-127) - 1 Exponent range is expanded (+/-511) - - 6-4 000 Add - 001 Subtract - 010 Multiply - 011 Divide - 100 Fix - 101 Float - 110 (diagnostic) - 111 (diagnostic) - - 3 0 Left operand is supplied - 1 Left operand in accumulator - - 2 0 Right operand is supplied (ADD/SUB/MPY/DIV) - Single integer operation (FIX/FLT) - 1 Right operand in accumulator (ADD/SUB/MPY/DIV) - Double integer operation (FIX/FLT) - - 1-0 00 2-word operation - 01 3-word operation - 10 4-word operation - 11 5-word operation - - If the opcode specifies that the left (or right) operand is in the - accumulator, then the value supplied for that parameter is not used. All - results are automatically left in the accumulator. If the result is not - needed externally, then NULL may be passed for the result parameter. - - To support accumulator set/get operations under simulation, the opcode is - expanded to include a special mode, indicated by bit 15 = 1. In this mode, - if the result parameter is NULL, then the accumulator is set from the value - passed as operand_l. If the result parameter is not null, then the - accumulator value is returned as the result, and operand_l is ignored. The - precision of the operation is performed as specified by the OPSIZE value - passed in bits 2-0 of the opcode. - - The function returns 1 if the operation overflows and 0 if not. -*/ - -uint32 fp_exec (uint16 opcode, OP *result, OP operand_l, OP operand_r) -{ -static FPU accumulator; -FPU uoperand_l, uoperand_r; -OPSIZE op_l_prec, op_r_prec, rslt_prec; -uint32 overflow; - -if (opcode & SIGN) { /* accumulator mode? */ - rslt_prec = (OPSIZE) (opcode & 0017); /* get operation precision */ - - if (result) { /* get accumulator? */ - op_l_prec = accumulator.precision; /* save accum prec temp */ - accumulator.precision = rslt_prec; /* set desired precision */ - *result = pack (accumulator); /* pack accumulator */ - accumulator.precision = op_l_prec; /* restore correct prec */ - } - else /* set accumulator */ - accumulator = unpack (operand_l, rslt_prec); /* unpack from operand */ - - return 0; /* no overflow from accum ops */ - } - -fp_prec (opcode, &op_l_prec, &op_r_prec, &rslt_prec); /* calc precs from opcode */ - -if (op_l_prec == fp_a) /* left operand in accum? */ - uoperand_l = accumulator; /* copy it */ -else /* operand supplied */ - uoperand_l = unpack (operand_l, op_l_prec); /* unpack from parameter */ - -if (op_r_prec == fp_a) /* right operand in accum? */ - uoperand_r = accumulator; /* copy it */ -else /* operand supplied */ - uoperand_r = unpack (operand_r, op_r_prec); /* unpack from parameter */ - - -switch (opcode & 0160) { /* dispatch operation */ - - case 0000: /* add */ - add (&accumulator, uoperand_l, uoperand_r); - break; - - case 0020: /* subtract */ - complement (&uoperand_r); - add (&accumulator, uoperand_l, uoperand_r); - break; - - case 0040: /* multiply */ - multiply (&accumulator, uoperand_l, uoperand_r); - break; - - case 0060: /* divide */ - divide (&accumulator, uoperand_l, uoperand_r); - break; - - case 0100: /* fix */ - accumulator.precision = rslt_prec; - overflow = fix (&accumulator, uoperand_l); - - if (result) /* result wanted? */ - *result = pack_int (accumulator.mantissa, /* pack integer */ - rslt_prec); - return overflow; - - case 0120: /* float */ - accumulator.precision = rslt_prec; - ffloat (&accumulator, uoperand_l); - - if (result) /* result wanted? */ - *result = pack (accumulator); /* pack FP (FLT does not round) */ - return 0; - - case 0140: /* (diagnostic) */ - case 0160: /* (diagnostic) */ - return 0; - } - -if (UNIT_CPU_MODEL != UNIT_1000_F) /* firmware implementation? */ - accumulator.mantissa = accumulator.mantissa & /* mask to precision */ - op_mask[accumulator.precision]; - -normalize (&accumulator); /* normalize */ -overflow = roundovf (&accumulator, opcode & 0200); /* round and check for overflow */ - -if (result) /* result wanted? */ - *result = pack (accumulator); /* pack result */ - -return overflow; -} - - -/* Set or get accumulator at desired precision. - - This function provides access to the FPP accumulator. In hardware, the - accumulator may be read at a given precision by sending the FPP an opcode - encoded with the desired precision and then reading words from the FPP - /without/ initiating the operation, i.e., without starting the processor. - - Under simulation, pass this function a NULL operand and the desired - precision to read the accumulator. Pass a pointer to an operand and the - desired precision to set the accumulator; the return value in this case is - not defined. -*/ - -OP fp_accum (const OP *operand, OPSIZE precision) -{ -OP result = NOP; -uint16 opcode = (uint16) precision | SIGN; /* add special mode bit */ - -if (operand) - fp_exec (opcode, NULL, *operand, NOP); /* set accum */ -else - fp_exec (opcode, &result, NOP, NOP); /* get accum */ -return result; -} - - -/* Pack an unpacked floating-point number. - - An unpacked mantissa is passed as a "packed" number with an unused exponent. - The mantissa and separately-passed exponent are packed into the in-memory - floating-point format. Note that all bits are significant in the mantissa - (no masking is done). -*/ - -uint32 fp_pack (OP *result, OP mantissa, int32 exponent, OPSIZE precision) -{ -FPU unpacked; - -unpacked.mantissa = unpack_int (mantissa, precision); /* unpack mantissa */ -unpacked.exponent = exponent; /* set exponent */ -unpacked.precision = precision; /* set precision */ -*result = pack (unpacked); /* pack them */ -return 0; -} - - -/* Normalize, round, and pack an unpacked floating-point number. - - An unpacked mantissa is passed as a "packed" number with an unused exponent. - The mantissa and separately-passed exponent are normalized, rounded, and - packed into the in-memory floating-point format. Note that all bits are - significant in the mantissa (no masking is done). -*/ - -uint32 fp_nrpack (OP *result, OP mantissa, int32 exponent, OPSIZE precision) -{ -FPU unpacked; - -unpacked.mantissa = unpack_int (mantissa, precision); /* unpack mantissa */ -unpacked.exponent = exponent; /* set exponent */ -unpacked.precision = precision; /* set precision */ -return nrpack (result, unpacked, FALSE); /* norm/rnd/pack them */ -} - - -/* Unpack a packed floating-point number. - - A floating-point number, packed into the in-memory format, is unpacked into - separate mantissa and exponent values. The unpacked mantissa is returned in - a "packed" structure with an exponent of zero. Mantissa or exponent may be - null if that part isn't wanted. -*/ - -uint32 fp_unpack (OP *mantissa, int32 *exponent, OP packed, OPSIZE precision) - -{ -FPU unpacked; - -unpacked = unpack (packed, precision); /* unpack mantissa and exponent */ - -if (exponent) /* exponent wanted? */ - *exponent = unpacked.exponent; /* return exponent */ - -if (mantissa) /* mantissa wanted? */ - *mantissa = pack_int (unpacked.mantissa, fp_t); /* return full-size mantissa */ -return 0; -} - - -/* Complement an unpacked mantissa. - - An unpacked mantissa is passed as a "packed" number with a zero exponent. - The exponent increment, i.e., either zero or one, depending on whether a - renormalization was required, is returned. Note that all bits are - significant in the mantissa. -*/ - -uint32 fp_ucom (OP *mantissa, OPSIZE precision) -{ -FPU unpacked; - -unpacked.mantissa = unpack_int (*mantissa, precision); /* unpack mantissa */ -unpacked.exponent = 0; /* clear undefined exponent */ -unpacked.precision = precision; /* set precision */ -complement (&unpacked); /* negate it */ -*mantissa = pack_int (unpacked.mantissa, precision); /* replace mantissa */ -return (uint32) unpacked.exponent; /* return exponent increment */ -} - - -/* Complement a floating-point number. */ - -uint32 fp_pcom (OP *packed, OPSIZE precision) -{ -FPU unpacked; - -unpacked = unpack (*packed, precision); /* unpack the number */ -complement (&unpacked); /* negate it */ -return nrpack (packed, unpacked, FALSE); /* and norm/rnd/pack */ -} - - -/* Truncate a floating-point number. */ - -uint32 fp_trun (OP *result, OP source, OPSIZE precision) -{ -t_bool bits_lost; -FPU unpacked; -FPU one = { FP_ONEHALF, 1, fp_t }; /* 0.5 * 2 ** 1 = 1.0 */ -OP zero = { { 0, 0, 0, 0, 0 } }; /* 0.0 */ -t_uint64 mask = mant_mask[precision] & ~FP_MSIGN; - -unpacked = unpack (source, precision); -if (unpacked.exponent < 0) /* number < 0.5? */ - *result = zero; /* return 0 */ -else if (unpacked.exponent >= (int32) op_bits[precision]) /* no fractional bits? */ - *result = source; /* already integer */ -else { - mask = (mask >> unpacked.exponent) & mask; /* mask fractional bits */ - bits_lost = ((unpacked.mantissa & mask) != 0); /* flag if bits lost */ - unpacked.mantissa = unpacked.mantissa & ~mask; /* mask off fraction */ - if ((unpacked.mantissa < 0) && bits_lost) /* negative? */ - add (&unpacked, unpacked, one); /* truncate toward zero */ - nrpack (result, unpacked, FALSE); /* (overflow cannot occur) */ - } -return 0; /* clear overflow on return */ -} - - -/* Convert a floating-point number from one precision to another. */ - -uint32 fp_cvt (OP *result, OPSIZE source_precision, OPSIZE dest_precision) -{ -FPU unpacked; - -unpacked = unpack (*result, source_precision); -unpacked.precision = dest_precision; -return nrpack (result, unpacked, FALSE); /* norm/rnd/pack */ -} - - -#endif /* end of int64 support */ +/* hp2100_fp1.c: HP 1000 multiple-precision floating point routines + + Copyright (c) 2005-2014, J. David Bryan + + 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 + THE AUTHOR 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 the author shall not be used + in advertising or otherwise to promote the sale, use or other dealings in + this Software without prior written authorization from the author. + + 24-Dec-14 JDB Added casts for explicit downward conversions + Changed fp_ucom return from uint32 to uint16 + 18-Mar-13 JDB Changed type of mantissa masks array to to unsigned + 06-Feb-12 JDB Added missing precision on constant "one" in fp_trun + 21-Jun-11 JDB Completed the comments for divide; no code changes + 08-Jun-08 JDB Quieted bogus gcc warning in fp_exec + 10-May-08 JDB Fixed uninitialized return in fp_accum when setting + 19-Mar-08 JDB Reworked "complement" to avoid inlining bug in gcc-4.x + 01-Dec-06 JDB Reworked into generalized multiple-precision ops for FPP + 12-Oct-06 JDB Altered x_trun for F-Series FFP compatibility + Added F-Series ..TCM FFP helpers + + Primary references: + - HP 1000 M/E/F-Series Computers Engineering and Reference Documentation + (92851-90001, Mar-1981) + - HP 1000 M/E/F-Series Computers Technical Reference Handbook + (5955-0282, Mar-1980) + - DOS/RTE Relocatable Library Reference Manual + (24998-90001, Oct-1981) + + + This module implements multiple-precision floating-point operations to + support the 1000 F-Series hardware Floating Point Processor. It employs + 64-bit integer arithmetic for speed and simplicity of implementation. The + host compiler must support 64-bit integers, and the HAVE_INT64 symbol must be + defined during compilation. If this symbol is not defined, then FPP support + is not available. + + HP 2100/1000 computers used a proprietary floating-point format. The 2100 + had optional firmware that provided two-word floating-point add, subtract, + multiply, and divide, as well as single-integer fix and float. The 1000-M/E + provided the same two-word firmware operations as standard equipment. + Three-word extended-precision instructions for the 2100 and 1000-M/E were + provided by the optional Fast FORTRAN Processor firmware. + + The 1000-F substituted a hardware floating point processor for the firmware + in previous machines. In addition to the two- and three-word formats, the + F-Series introduced a four-word double-precision format. A five-word format + that provided extra range in the exponent by unpacking it from the mantissa + was also provided, although this capability was not documented in the user + manual. In addition, the FPP improved the accuracy of floating-point + calculations, as the firmware versions sacrificed a few bits of precision to + gain speed. Consequently, operations on the F-Series may return results that + differ slightly from the same operations on the M/E-Series or the 2100. + + F-Series units after date code 1920 also provided two-word double-integer + instructions in firmware, as well as double-integer fix and float operations. + + The original 32-bit floating-point format is as follows: + + 15 14 0 + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + |MS| mantissa high | : M + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + | mantissa low | exponent |XS| : M + 1 + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + 15 8 7 1 0 + + Both 23-bit mantissa and 7-bit exponent are in twos-complement form. The + exponent sign bit has been rotated into the LSB of the second word. + + The extended-precision floating-point format is a 48-bit extension of the + 32-bit format used for single precision. A packed extended-precision value + consists of a 39-bit mantissa and a 7-bit exponent. The format is as + follows: + + 15 14 0 + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + |MS| mantissa high | : M + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + | mantissa middle | : M + 1 + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + | mantissa low | exponent |XS| : M + 2 + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + 15 8 7 1 0 + + The double-precision floating-point format is similar to the 48-bit + extended-precision format, although with a 55-bit mantissa: + + 15 14 0 + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + |MS| mantissa high | : M + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + | mantissa middle high | : M + 1 + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + | mantissa middle low | : M + 2 + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + | mantissa low | exponent |XS| : M + 3 + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + 15 8 7 1 0 + + The FPP also supports a special five-word expanded-exponent format: + + 15 14 0 + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + |MS| mantissa high | : M + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + | mantissa middle high | : M + 1 + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + | mantissa middle low | : M + 2 + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + | mantissa low | : M + 3 + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + | exponent |XS| : M + 4 + +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + 15 8 7 1 0 + + The exponent is a full 16-bit twos-complement value, but the allowed range is + only 10 bits, i.e., -512 to +511. + + In a normalized value, the sign and MSB of the mantissa differ. Zero is + represented by all words = 0. + + Internally, unpacked floating-point values are contained in a structure + having a signed 64-bit mantissa and a signed 32-bit exponent. Mantissas are + left-justified with the unused bits masked to zero. Exponents are + right-justified. The precision is indicated by the value of a structure + field. + + HP terminology for the three-word floating-point format is confused. Some + documents refer to it as "double precision," while others use "extended + precision." The instruction mnemonics begin with "X" (e.g., .XADD), + suggesting the extended-precision term. + + HP apparently intended that the four-word double-precision format would be + called "triple-precision," as the instruction mnemonics begin with "T" (e.g., + ".TADD" for the four-word add instruction). The source files for the + software simulations of these instructions for the M/E-Series also explicitly + refer to "triple precision math." However, the engineering documentation and + the F-Series reference manual both use the double-precision term. + + This module adopts the single/extended/double terminology and uses the + initial letters of the instructions (F/X/T) to indicate the precision used. + + The FPP hardware consisted of two circuit boards that interfaced to the main + CPU via the Microprogrammable Processor Port (MPP) that had been introduced + with the 1000 E-Series. One board contained argument registers and ALUs, + split into separate mantissa and exponent parts. The other contained a state + machine sequencer. FPP results were copied automatically to the argument + registers in addition to being available over the MPP, so that chained + operations could be executed from these "accumulators" without reloading. + + The FPP operated independently of the CPU. An opcode, specifying one of the + six operations (add, subtract, multiply, divide, fix, or float) was sent to + the FPP, and a start command was given. Operands of appropriate precision + were then supplied to the FPP. Once the operands were received, the FPP + would execute and set a flag when the operation was complete. The result + would then be retrieved from the FPP. The floating-point instruction + firmware in the CPU initiated the desired FPP operation and handled operand + reads from and result writes to main memory. + + Under simulation, "fp_exec" provides the six arithmetic operations analogous + to FPP execution. The remainder of the functions are helpers that were + provided by firmware in the 1000-F but that can reuse code needed to simulate + the FPP hardware. As with the hardware, "fp_exec" retains the last result + in an internal accumulator that may be referenced in subsequent operations. + + NOTE: this module also provides the floating-point support for the firmware + single-precision 1000-M/E base set and extended-precision FFP instructions. + Because the firmware and hardware implementations returned slightly different + results, particularly with respect to round-off, conditional checks are + implemented in the arithmetic routines. In some cases, entirely different + algorithms are used to ensure fidelity with the real machines. Functionally, + this means that the 2100/1000-M/E and 1000-F floating-point diagnostics are + not interchangeable, and failures are to be expected if a diagnostic is run + on the wrong machine. +*/ + +#include "hp2100_defs.h" +#include "hp2100_cpu.h" +#include "hp2100_cpu1.h" +#include "hp2100_fp1.h" + + +#if defined (HAVE_INT64) /* we need int64 support */ + +/* Field widths. */ + +#define IN_W_SIGN 1 +#define IN_W_SMAGN 15 +#define IN_W_DMAGN 31 + +#define FP_W_MSIGN 1 +#define FP_W_FMANT 23 +#define FP_W_XMANT 39 +#define FP_W_TMANT 55 +#define FP_W_EMANT 55 +#define FP_W_EXPANDEXP 9 +#define FP_W_EXP 7 +#define FP_W_ESIGN 1 + +/* Starting bit numbers. */ + +#define IN_V_SIGN (64 - IN_W_SIGN) +#define IN_V_SNUM (64 - IN_W_SIGN - IN_W_SMAGN) +#define IN_V_DNUM (64 - IN_W_SIGN - IN_W_DMAGN) + +#define FP_V_FNUM (64 - FP_W_MSIGN - FP_W_FMANT - FP_W_EXP - FP_W_ESIGN) +#define FP_V_XNUM (64 - FP_W_MSIGN - FP_W_XMANT - FP_W_EXP - FP_W_ESIGN) +#define FP_V_TNUM (64 - FP_W_MSIGN - FP_W_TMANT - FP_W_EXP - FP_W_ESIGN) +#define FP_V_ENUM (64 - FP_W_MSIGN - FP_W_EMANT - FP_W_EXP - FP_W_ESIGN) + +#define FP_V_MSIGN (64 - FP_W_MSIGN) +#define FP_V_FMANT (64 - FP_W_MSIGN - FP_W_FMANT) +#define FP_V_XMANT (64 - FP_W_MSIGN - FP_W_XMANT) +#define FP_V_TMANT (64 - FP_W_MSIGN - FP_W_TMANT) +#define FP_V_EMANT (64 - FP_W_MSIGN - FP_W_EMANT) +#define FP_V_EXP 1 +#define FP_V_ESIGN 0 + +/* Right-aligned field masks. */ + +#define IN_M_SIGN (((t_uint64) 1 << IN_W_SIGN) - 1) +#define IN_M_SMAGN (((t_uint64) 1 << IN_W_SMAGN) - 1) +#define IN_M_DMAGN (((t_uint64) 1 << IN_W_DMAGN) - 1) + +#define FP_M_MSIGN (((t_uint64) 1 << FP_W_MSIGN) - 1) +#define FP_M_FMANT (((t_uint64) 1 << FP_W_FMANT) - 1) +#define FP_M_XMANT (((t_uint64) 1 << FP_W_XMANT) - 1) +#define FP_M_TMANT (((t_uint64) 1 << FP_W_TMANT) - 1) +#define FP_M_EMANT (((t_uint64) 1 << FP_W_EMANT) - 1) + +#define FP_M_EXPANDEXP ((1 << FP_W_EXPANDEXP) - 1) +#define FP_M_EXP ((1 << FP_W_EXP) - 1) +#define FP_M_ESIGN ((1 << FP_W_ESIGN) - 1) + +/* In-place field masks. */ + +#define IN_SIGN (IN_M_SIGN << IN_V_SIGN) +#define IN_SMAGN (IN_M_SMAGN << IN_V_SNUM) +#define IN_DMAGN (IN_M_DMAGN << IN_V_DNUM) + +#define FP_MSIGN (FP_M_MSIGN << FP_V_MSIGN) +#define FP_FMANT (FP_M_FMANT << FP_V_FMANT) +#define FP_XMANT (FP_M_XMANT << FP_V_XMANT) +#define FP_TMANT (FP_M_TMANT << FP_V_TMANT) +#define FP_EMANT (FP_M_EMANT << FP_V_EMANT) +#define FP_EXP (FP_M_EXP << FP_V_EXP) +#define FP_ESIGN (FP_M_ESIGN << FP_V_ESIGN) + +/* In-place record masks. */ + +#define IN_SSMAGN (IN_SIGN | IN_SMAGN) +#define IN_SDMAGN (IN_SIGN | IN_DMAGN) + +#define FP_SFMANT (FP_MSIGN | FP_FMANT) +#define FP_SXMANT (FP_MSIGN | FP_XMANT) +#define FP_STMANT (FP_MSIGN | FP_TMANT) +#define FP_SEMANT (FP_MSIGN | FP_EMANT) +#define FP_SEXP (FP_ESIGN | FP_EXP) + +/* Minima and maxima. */ + +#define FP_ONEHALF ((t_int64) 1 << (FP_V_MSIGN - 1)) /* mantissa = 0.5 */ +#define FP_MAXPMANT ((t_int64) FP_EMANT) /* maximum pos mantissa */ +#define FP_MAXNMANT ((t_int64) FP_MSIGN) /* maximum neg mantissa */ +#define FP_MAXPEXP (FP_M_EXPANDEXP) /* maximum pos expanded exponent */ +#define FP_MAXNEXP (-(FP_MAXPEXP + 1)) /* maximum neg expanded exponent */ + +/* Floating-point helpers. */ + +#define DENORM(x) ((((x) ^ (x) << 1) & FP_MSIGN) == 0) + +#define TO_EXP(e) (int8) ((e >> FP_V_EXP & FP_M_EXP) | \ + (e & FP_M_ESIGN ? ~FP_M_EXP : 0)) + +/* Property constants. */ + +static const t_int64 p_half_lsb[6] = { ((t_int64) 1 << IN_V_SNUM) - 1, /* different than FP! */ + ((t_int64) 1 << IN_V_DNUM) - 1, /* different than FP! */ + (t_int64) 1 << (FP_V_FMANT - 1), + (t_int64) 1 << (FP_V_XMANT - 1), + (t_int64) 1 << (FP_V_TMANT - 1), + (t_int64) 1 << (FP_V_EMANT - 1) }; + +static const t_int64 n_half_lsb[6] = { 0, + 0, + ((t_int64) 1 << (FP_V_FMANT - 1)) - 1, + ((t_int64) 1 << (FP_V_XMANT - 1)) - 1, + ((t_int64) 1 << (FP_V_TMANT - 1)) - 1, + ((t_int64) 1 << (FP_V_EMANT - 1)) - 1 }; + +static const uint32 op_start[6] = { IN_V_SNUM, + IN_V_DNUM, + FP_V_FMANT, + FP_V_XMANT, + FP_V_TMANT, + FP_V_EMANT }; + +static const t_uint64 mant_mask[6] = { IN_SSMAGN, + IN_SDMAGN, + FP_SFMANT, + FP_SXMANT, + FP_STMANT, + FP_SEMANT }; + +static const uint32 op_bits[6] = { IN_W_SMAGN, + IN_W_DMAGN, + FP_W_FMANT + FP_W_MSIGN, + FP_W_XMANT + FP_W_MSIGN, + FP_W_TMANT + FP_W_MSIGN, + FP_W_EMANT + FP_W_MSIGN }; + +static const t_int64 op_mask[6] = { ~(t_int64) 0 << IN_V_SNUM, + ~(t_int64) 0 << IN_V_DNUM, + ~(t_int64) 0 << FP_V_FNUM, + ~(t_int64) 0 << FP_V_XNUM, + ~(t_int64) 0 << FP_V_TNUM, + ~(t_int64) 0 << FP_V_ENUM }; + +static const uint32 int_p_max[2] = { IN_M_SMAGN, + IN_M_DMAGN }; + + +/* Internal unpacked floating-point representation. */ + +typedef struct { + t_int64 mantissa; + int32 exponent; + OPSIZE precision; + } FPU; + + + +/* Low-level helper routines. */ + + +/* Arithmetic shift right for mantissa only. + + Returns TRUE if any one-bits are shifted out (for F-series only). +*/ + +static t_bool asr (FPU *operand, int32 shift) +{ +t_uint64 mask; +t_bool bits_lost; + +if (UNIT_CPU_MODEL == UNIT_1000_F) { /* F-series? */ + mask = ((t_uint64) 1 << shift) - 1; /* mask for lost bits */ + bits_lost = ((operand->mantissa & mask) != 0); /* flag if any lost */ + } +else + bits_lost = FALSE; + +operand->mantissa = operand->mantissa >> shift; /* mantissa is int, so ASR */ +return bits_lost; +} + + +/* Logical shift right for mantissa and exponent. + + Shifts mantissa and corrects exponent for mantissa overflow. + Returns TRUE if any one-bits are shifted out (for F-series only). +*/ + +static t_bool lsrx (FPU *operand, int32 shift) +{ +t_uint64 mask; +t_bool bits_lost; + +if (UNIT_CPU_MODEL == UNIT_1000_F) { /* F-series? */ + mask = ((t_uint64) 1 << shift) - 1; /* mask for lost bits */ + bits_lost = ((operand->mantissa & mask) != 0); /* flag if any lost */ + } +else + bits_lost = FALSE; + +operand->mantissa = (t_uint64) operand->mantissa >> shift; /* uint, so LSR */ +operand->exponent = operand->exponent + shift; /* correct exponent */ +return bits_lost; +} + + +/* Unpack an operand into a long integer. + + Returns a left-aligned integer or mantissa. Does not mask to precision; this + should be done subsequently if desired. +*/ + +static t_int64 unpack_int (OP packed, OPSIZE precision) +{ +uint32 i; +t_uint64 unpacked = 0; + +if (precision == in_s) + unpacked = (t_uint64) packed.word << 48; /* unpack single integer */ + +else if (precision == in_d) + unpacked = (t_uint64) packed.dword << 32; /* unpack double integer */ + +else { + if (precision == fp_e) /* five word operand? */ + precision = fp_t; /* only four mantissa words */ + + for (i = 0; i < 4; i++) /* unpack fp 2 to 4 words */ + if (i < TO_COUNT (precision)) + unpacked = unpacked << 16 | packed.fpk[i]; + else + unpacked = unpacked << 16; + } + +return (t_int64) unpacked; +} + + +/* Unpack a packed operand. + + The packed value is split into separate mantissa and exponent variables. The + multiple words of the mantissa are concatenated into a single 64-bit signed + value, and the exponent is shifted with recovery of the sign. +*/ + +static FPU unpack (OP packed, OPSIZE precision) +{ +FPU unpacked; + +unpacked.precision = precision; /* set value's precision */ + +unpacked.mantissa = /* unpack and mask mantissa */ + unpack_int (packed, precision) & (t_int64) mant_mask[precision]; + +switch (precision) { + + case fp_f: + case fp_x: + case fp_t: + unpacked.exponent = /* unpack exponent from correct word */ + TO_EXP (packed.fpk[(uint32) precision - 1]); + break; + + case fp_e: + unpacked.exponent = /* unpack expanded exponent */ + (int16) (packed.fpk[4] >> FP_V_EXP | /* rotate sign into place */ + (packed.fpk[4] & 1 ? SIGN : 0)); + break; + + case fp_a: /* no action for value in accum */ + case in_s: /* integers don't use exponent */ + case in_d: /* integers don't use exponent */ + default: + unpacked.exponent = 0; + break; + } + +return unpacked; +} + + +/* Pack a long integer into an operand. */ + +static OP pack_int (t_int64 unpacked, OPSIZE precision) +{ +int32 i; +OP packed; + +if (precision == in_s) + packed.word = (uint16) (unpacked >> 48) & DMASK; /* pack single integer */ + +else if (precision == in_d) + packed.dword = (uint32) (unpacked >> 32) & DMASK32; /* pack double integer */ + +else { + if (precision == fp_e) /* five word operand? */ + precision = fp_t; /* only four mantissa words */ + + for (i = 3; i >= 0; i--) { /* pack fp 2 to 4 words */ + packed.fpk[i] = (uint16) unpacked & DMASK; + unpacked = unpacked >> 16; + } + } + +return packed; +} + + +/* Pack an unpacked floating-point number. + + The 64-bit mantissa is split into the appropriate number of 16-bit words. + The exponent is rotated to incorporate the sign bit and merged into the + appropriate word. +*/ + +static OP pack (FPU unpacked) +{ +OP packed; +uint8 exp; + +packed = pack_int (unpacked.mantissa, unpacked.precision); /* pack mantissa */ + +exp = (uint8) (unpacked.exponent << FP_V_EXP | /* rotate exponent */ + (unpacked.exponent < 0) << FP_V_ESIGN); + +switch (unpacked.precision) { /* merge exponent into correct word */ + + case in_s: /* no action for integers */ + case in_d: + break; + + case fp_f: /* merge into last word */ + case fp_x: + case fp_t: + packed.fpk[(uint32) unpacked.precision - 1] = + (packed.fpk[(uint32) unpacked.precision - 1] & ~FP_SEXP) | exp; + break; + + case fp_e: /* place in separate word */ + packed.fpk[4] = (uint16) (unpacked.exponent << FP_V_EXP | + (unpacked.exponent < 0) << FP_V_ESIGN); + break; + + case fp_a: /* no action for value in accum */ + break; + } + +return packed; +} + + +/* Normalize an unpacked floating-point number. + + Floating-point numbers are in normal form if the sign bit and the MSB of the + mantissa differ. Unnormalized numbers are shifted as needed with appropriate + exponent modification. +*/ + +static void normalize (FPU *unpacked) +{ + +if (unpacked->mantissa) /* non-zero? */ + while (DENORM (unpacked->mantissa)) { /* normal form? */ + unpacked->exponent = unpacked->exponent - 1; /* no, so left shift */ + unpacked->mantissa = unpacked->mantissa << 1; + } +else + unpacked->exponent = 0; /* clean for zero */ +return; +} + + +/* Round an unpacked floating-point number and check for overflow. + + An unpacked floating-point number is rounded by adding one-half of the LSB + value, maintaining symmetry around zero. If rounding resulted in a mantissa + overflow, the result logically is shifted to the right with an appropriate + exponent modification. Finally, the result is checked for exponent underflow + or overflow, and the appropriate approximation (zero or infinity) is + returned. + + Rounding in hardware involves a special mantissa extension register that + holds three "guard" bits and one "sticky" bit. These represent the value of + bits right-shifted out the mantissa register. Under simulation, we track + such right-shifts and utilize the lower eight bits of the 64-bit mantissa + value to simulate the extension register. + + Overflow depends on whether the FPP expanded-exponent form is being used + (this expands the exponent range by two bits). If overflow is detected, the + value representing infinity is dependent on whether the operation is on + behalf of the Fast FORTRAN Processor. The F-Series FPP returns positive + infinity on both positive and negative overflow for all precisions. The 2100 + and M/E-Series FFPs return negative infinity on negative overflow of + extended-precision values. Single-precision overflows on these machines + always return positive infinity. + + The number to be rounded must be normalized upon entry. +*/ + +static uint32 roundovf (FPU *unpacked, t_bool expand) +{ +uint32 overflow; +t_bool sign; + +sign = (unpacked->mantissa < 0); /* save mantissa sign */ + +if (sign) /* round and mask the number */ + unpacked->mantissa = + (unpacked->mantissa + n_half_lsb[unpacked->precision]) & + (t_int64) mant_mask[unpacked->precision]; +else + unpacked->mantissa = + (unpacked->mantissa + p_half_lsb[unpacked->precision]) & + (t_int64) mant_mask[unpacked->precision]; + +if (sign != (unpacked->mantissa < 0)) /* mantissa overflow? */ + lsrx (unpacked, 1); /* correct by shifting */ +else + normalize (unpacked); /* renorm may be needed */ + +if (unpacked->mantissa == 0) { /* result zero? */ + unpacked->mantissa = 0; /* return zero */ + unpacked->exponent = 0; + overflow = 0; /* with overflow clear */ + } +else if (unpacked->exponent < /* result underflow? */ + (FP_MAXNEXP >> (expand ? 0 : 2))) { + unpacked->mantissa = 0; /* return zero */ + unpacked->exponent = 0; + overflow = 1; /* and set overflow */ + } +else if (unpacked->exponent > /* result overflow? */ + (FP_MAXPEXP >> (expand ? 0 : 2))) { + if (sign && /* negative value? */ + (unpacked->precision == fp_x) && /* extended precision? */ + (UNIT_CPU_MODEL != UNIT_1000_F)) { /* not F-series? */ + unpacked->mantissa = FP_MAXNMANT; /* return negative infinity */ + unpacked->exponent = FP_MAXPEXP & FP_M_EXP; + } + else { + unpacked->mantissa = FP_MAXPMANT; /* return positive infinity */ + unpacked->exponent = FP_MAXPEXP & FP_M_EXP; + } + overflow = 1; /* and set overflow */ + } +else + overflow = 0; /* value is in range */ + +return overflow; +} + + +/* Normalize, round, and pack an unpacked floating-point number. */ + +static uint32 nrpack (OP *packed, FPU unpacked, t_bool expand) +{ +uint32 overflow; + +normalize (&unpacked); /* normalize for rounding */ +overflow = roundovf (&unpacked, expand); /* round and check for overflow */ +*packed = pack (unpacked); /* pack result */ + +return overflow; +} + + + +/* Low-level arithmetic routines. */ + + +/* Complement an unpacked number. */ + +static void complement (FPU *result) +{ +if (result->mantissa == FP_MAXNMANT) { /* maximum negative? */ + result->mantissa = FP_ONEHALF; /* complement of -1.0 * 2 ^ n */ + result->exponent = result->exponent + 1; /* is 0.5 * 2 ^ (n + 1) */ + } +else + result->mantissa = -result->mantissa; /* negate mantissa */ +return; +} + + +/* Add two unpacked numbers. + + The mantissas are first aligned if necessary by scaling the smaller of the + two operands. If the magnitude of the difference between the exponents is + greater than the number of significant bits, then the smaller number has been + scaled to zero (swamped), and so the sum is simply the larger operand. + Otherwise, the sum is computed and checked for overflow, which has occurred + if the signs of the operands are the same but differ from that of the result. + Scaling and renormalization is performed if overflow occurred. +*/ + +static void add (FPU *sum, FPU augend, FPU addend) +{ +int32 magn; +t_bool bits_lost; + +if (augend.mantissa == 0) + *sum = addend; /* X + 0 = X */ + +else if (addend.mantissa == 0) + *sum = augend; /* 0 + X = X */ + +else { + magn = augend.exponent - addend.exponent; /* difference exponents */ + + if (magn > 0) { /* addend smaller? */ + *sum = augend; /* preset augend */ + bits_lost = asr (&addend, magn); /* align addend */ + } + else { /* augend smaller? */ + *sum = addend; /* preset addend */ + magn = -magn; /* make difference positive */ + bits_lost = asr (&augend, magn); /* align augend */ + } + + if (magn <= (int32) op_bits[augend.precision]) { /* value swamped? */ + sum->mantissa = /* no, add mantissas */ + addend.mantissa + augend.mantissa; + + if (((addend.mantissa < 0) == (augend.mantissa < 0)) && /* mantissa overflow? */ + ((addend.mantissa < 0) != (sum->mantissa < 0))) { + bits_lost = bits_lost | lsrx (sum, 1); /* restore value */ + sum->mantissa = /* restore sign */ + sum-> mantissa | (addend.mantissa & FP_MSIGN); + } + + if (bits_lost) /* any bits lost? */ + sum->mantissa = sum->mantissa | 1; /* include one for rounding */ + } + } +return; +} + + +/* Multiply two unpacked numbers. + + The single-precision firmware (FMP) operates differently from the firmware + extended-precision (.XMPY) and the hardware multiplies of any precision. + Firmware implementations use the MPY micro-order to form 16-bit x 16-bit = + 32-bit partial products and sum them to form the result. The hardware uses a + series of shifts and adds. This means that firmware FMP and hardware FMP + return slightly different values, as may be seen by attempting to run the + firmware FMP diagnostic on the FPP. + + The FMP microcode calls a signed multiply routine to calculate three partial + products (all but LSB * LSB). Because the LSBs are unsigned, i.e., all bits + significant, the two MSB * LSB products are calculated using LSB/2. The + unsigned right-shift ensures a positive LSB with no significant bits lost, + because the lower eight bits are unused (they held the vacated exponent). In + order to sum the partial products, the LSB of the result of MSB * MSB is also + right-shifted before addition. Note, though, that this loses a significant + bit. After summation, the result is left-shifted to correct for the original + right shifts. + + The .XMPY microcode negates both operands as necessary to produce positive + values and then forms six of the nine 16-bit x 16-bit = 32-bit unsigned + multiplications required for a full 96-bit product. Given a 48-bit + multiplicand "a1a2a3" and a 48-bit multiplier "b1b2b3", the firmware performs + these calculations to develop a 48-bit product: + + a1 a2 a3 + +-------+-------+-------+ + b1 b2 b3 + +-------+-------+-------+ + _________________________ + + a1 * b3 [p1] + +-------+-------+ + a2 * b2 [p2] + +-------+-------+ + a1 * b2 [p3] + +-------+-------+ + a3 * b1 [p4] + +-------+-------+ + a2 * b1 [p5] + +-------+-------+ + a1 * b1 [p6] + +-------+-------+ + _________________________________ + + product + +-------+-------+-------+ + + The least-significant words of partial products [p1], [p2], and [p4] are used + only to develop a carry bit into the 48-bit sum. The product is complemented + as necessary to restore the sign. + + The basic FPP hardware algorithm scans the multiplier and adds a shifted copy + of the multiplicand whenever a one-bit is detected. To avoid successive adds + when a string of ones is encountered (because adds are more expensive than + shifts), the hardware instead adds the multiplicand shifted by N + 1 + P and + subtracts the multiplicand shifted by P to obtain the equivalent value with a + maximum of two operations. + + Instead of implementing either the .XMPY firmware algorithm or the hardware + shift-and-add algorithm directly, it is more efficient under simulation to + use 32 x 32 = 64-bit multiplications, thereby reducing the number required + from six to four (64-bit "c1c2" x 64-bit "d1d2"): + + ah al + +-------+-------+ + bh bl + +-------+-------+ + _________________ + + al * bl [ll] + +-------+-------+ + ah * bl [hl] + +-------+-------+ + al * bh [lh] + +-------+-------+ + ah * bh [hh] + +-------+-------+ + _________________________________ + + product + +-------+-------+ + + However, the FMP algorithm is implemented directly from the microcode to + preserve the fidelity of the simulation, i.e., to lose the same amount + of precision. +*/ + +static void multiply (FPU *product, FPU multiplicand, FPU multiplier) +{ +uint32 ah, al, bh, bl, sign = 0; +t_uint64 hh, hl, lh, ll, carry; +int16 ch, cl, dh, dl; +t_bool firmware; + +product->precision = multiplicand.precision; /* set precision */ + +if ((multiplicand.mantissa == 0) || /* 0 * X = 0 */ + (multiplier.mantissa == 0)) /* X * 0 = 0 */ + product->mantissa = product->exponent = 0; + +else { + firmware = (UNIT_CPU_MODEL != UNIT_1000_F); /* set firmware flag */ + + if (!firmware || (product->precision != fp_f)) { /* hardware? */ + if (multiplicand.mantissa < 0) { /* negative? */ + complement (&multiplicand); /* complement operand */ + sign = ~sign; /* track sign */ + } + if (multiplier.mantissa < 0) { /* negative? */ + complement (&multiplier); /* complement operand */ + sign = ~sign; /* track sign */ + } + } + + product->exponent = /* compute exponent */ + multiplicand.exponent + multiplier.exponent + 1; + + ah = (uint32) (multiplicand.mantissa >> 32); /* split multiplicand */ + al = (uint32) (multiplicand.mantissa & DMASK32); /* into high and low parts */ + bh = (uint32) (multiplier.mantissa >> 32); /* split multiplier */ + bl = (uint32) (multiplier.mantissa & DMASK32); /* into high and low parts */ + + if (firmware && (product->precision == fp_f)) { /* single-precision firmware? */ + ch = (int16) (ah >> 16) & DMASK; /* split 32-bit multiplicand */ + cl = (int16) (ah & 0xfffe); /* into high and low parts */ + dh = (int16) (bh >> 16) & DMASK; /* split 32-bit multiplier */ + dl = (int16) (bh & 0xfffe); /* into high and low parts */ + + hh = (t_uint64) (((int32) ch * dh) & ~1); /* form cross products */ + hl = (t_uint64) (((t_int64) ch * (t_int64) (uint16) dl + + (t_int64) dh * (t_int64) (uint16) cl) & + 0xfffffffffffe0000); + + product->mantissa = (t_uint64) (((t_int64) hh << 32) + /* sum partials */ + ((t_int64) hl << 16)); + } + + else { + hh = ((t_uint64) ah * bh); /* form four cross products */ + hl = ((t_uint64) ah * bl); /* using 32 x 32 = */ + lh = ((t_uint64) al * bh); /* 64-bit multiplies */ + ll = ((t_uint64) al * bl); + + carry = ((ll >> 32) + (uint32) hl + (uint32) lh) >> 32; /* form carry */ + + product->mantissa = hh + (hl >> 32) + (lh >> 32) + carry; /* sum partials */ + + if (sign) /* negate if required */ + complement (product); + } + } +return; +} + + +/* Divide two unpacked numbers. + + As with multiply, the single-precision firmware (FDV) operates differently + from the firmware extended-precision (.XDIV) and the hardware divisions of + any precision. Firmware implementations use the DIV micro-order to form + 32-bit / 16-bit = 16-bit quotients and 16-bit remainders. These are used in + a "divide and correct" algorithm, wherein the quotient is estimated and then + corrected by comparing the dividend to the product of the quotient and the + divisor. The hardware uses a series of shifts and subtracts. This means + that firmware FDV and hardware FDV once again return slightly different + values. + + Under simulation, the classic divide-and-correct method is employed, using + 64-bit / 32-bit = 32-bit divisions. This method considers the 64-bit + dividend and divisor each to consist of two 32-bit "digits." The 64-bit + dividend "a1a2a3a4" is divided by the first 32-bit digit "b1b2" of the 64-bit + divisor "b1b2b3b4", yielding a 32-bit trial quotient digit and a 32-bit + remainder digit. A correction is developed by subtracting the product of the + second 32-bit digit "b3b4" of the divisor and the trial quotient digit from + the remainder (we take advantage of the eight bits vacated by the exponent + during unpacking to ensure that this product will not overflow into the sign + bit). If the remainder is negative, the trial quotient is too large, so it + is decremented, and the (full 64-bit) divisor is added to the correction. + This is repeated until the correction is non-negative, indicating that the + first quotient digit is correct. The process is then repeated using the + remainder as the dividend to develop the second 32-bit digit of the quotient. + The two digits are then concatenated for produce the final 64-bit value. + + (See, "Divide-and-Correct Methods for Multiple Precision Division" by Marvin + L. Stein, Communications of the ACM, August 1964 for background.) + + The microcoded single-precision division avoids overflows by right-shifting + some values, which leads to a loss of precision in the LSBs. We duplicate + the firmware algorithm here to preserve the fidelity of the simulation. +*/ + +static void divide (FPU *quotient, FPU dividend, FPU divisor) +{ +uint32 sign = 0; +t_int64 bh, bl, r1, r0, p1, p0; +t_uint64 q, q1, q0; +t_bool firmware; +int32 ah, div, cp; +int16 dh, dl, pq1, pq2, cq; + +quotient->precision = dividend.precision; /* set precision */ + +if (divisor.mantissa == 0) { /* division by zero? */ + if (dividend.mantissa < 0) + quotient->mantissa = FP_MSIGN; /* return minus infinity */ + else + quotient->mantissa = ~FP_MSIGN; /* or plus infinity */ + quotient->exponent = FP_MAXPEXP + 1; + } + +else if (dividend.mantissa == 0) /* dividend zero? */ + quotient->mantissa = quotient->exponent = 0; /* yes; result is zero */ + +else { + firmware = (UNIT_CPU_MODEL != UNIT_1000_F); /* set firmware flag */ + + if (!firmware || (quotient->precision != fp_f)) { /* hardware or FFP? */ + if (dividend.mantissa < 0) { /* negative? */ + complement (÷nd); /* complement operand */ + sign = ~sign; /* track sign */ + } + if (divisor.mantissa < 0) { /* negative? */ + complement (&divisor); /* complement operand */ + sign = ~sign; /* track sign */ + } + } + + quotient->exponent = /* division subtracts exponents */ + dividend.exponent - divisor.exponent; + + bh = divisor.mantissa >> 32; /* split divisor */ + bl = divisor.mantissa & DMASK32; /* into high and low parts */ + + if (firmware && (quotient->precision == fp_f)) { /* single-precision firmware? */ + quotient->exponent = quotient->exponent + 1; /* fix exponent */ + + ah = (int32) (dividend.mantissa >> 32); /* split dividend */ + dh = (int16) (bh >> 16); /* split divisor again */ + dl = (int16) bh; + + div = ah >> 2; /* ASR 2 to prevent overflow */ + + pq1 = (int16) (div / dh); /* form first partial quotient */ + div = ((div % dh) & ~1) << 15; /* ASR 1, move rem to upper */ + pq2 = (int16) (div / dh); /* form second partial quotient */ + + div = (uint16) dl << 13; /* move divisor LSB to upper, LSR 3 */ + cq = (int16) (div / dh); /* form correction quotient */ + cp = -cq * pq1; /* and correction product */ + + cp = (((cp >> 14) & ~3) + (int32) pq2) << 1; /* add corr prod and 2nd partial quo */ + quotient->mantissa = /* add 1st partial quo and align */ + (t_uint64) (((int32) pq1 << 16) + cp) << 32; + } + + else { /* hardware or FFP */ + q1 = (t_uint64) (dividend.mantissa / bh); /* form 1st trial quotient */ + r1 = dividend.mantissa % bh; /* and remainder */ + p1 = (r1 << 24) - (bl >> 8) * q1; /* calculate correction */ + + while (p1 < 0) { /* correction needed? */ + q1 = q1 - 1; /* trial quotient too large */ + p1 = p1 + (divisor.mantissa >> 8); /* increase remainder */ + } + + q0 = (t_uint64) ((p1 << 8) / bh); /* form 2nd trial quotient */ + r0 = (p1 << 8) % bh; /* and remainder */ + p0 = (r0 << 24) - (bl >> 8) * q0; /* calculate correction */ + + while (p0 < 0) { /* correction needed? */ + q0 = q0 - 1; /* trial quotient too large */ + p0 = p0 + (divisor.mantissa >> 8); /* increase remainder */ + } + + q = (q1 << 32) + q0; /* sum quotient digits */ + + if (q1 & 0xffffffff00000000) { /* did we lose MSB? */ + q = (q >> 1) | 0x8000000000000000; /* shift right and replace bit */ + quotient->exponent = quotient->exponent + 1;/* bump exponent for shift */ + } + + if (q & 0x8000000000000000) /* lose normalization? */ + q = q >> 1; /* correct */ + + quotient->mantissa = (t_int64) q; + } + + if (sign) + complement (quotient); /* negate if required */ + } +return; +} + + +/* Fix an unpacked number. + + A floating-point value is converted to an integer. The desired precision of + the result (single or double integer) must be set before calling. + + Values less than 0.5 (i.e., with negative exponents) underflow to zero. If + the value exceeds the specified integer range, the maximum integer value is + returned and overflow is set. Otherwise, the floating-point value is + right-shifted to zero the exponent. The result is then rounded. +*/ + +static uint32 fix (FPU *result, FPU operand) +{ +uint32 overflow; +t_bool bits_lost; + +if (operand.exponent < 0) { /* value < 0.5? */ + result->mantissa = 0; /* result rounds to zero */ + overflow = 0; /* clear for underflow */ + } + +else if (operand.exponent > /* value > integer size? */ + (int32) op_bits[result->precision]) { + result->mantissa = /* return max int value */ + (t_uint64) int_p_max[result->precision] << + op_start[result->precision]; + overflow = 1; /* and set overflow */ + } + +else { /* value in range */ + bits_lost = asr (&operand, /* shift to zero exponent */ + op_bits[result->precision] - operand.exponent); + + if (operand.mantissa < 0) { /* value negative? */ + if (bits_lost) /* bits lost? */ + operand.mantissa = operand.mantissa | 1; /* include one for rounding */ + + operand.mantissa = operand.mantissa + /* round result */ + p_half_lsb[result->precision]; + } + + result->mantissa = operand.mantissa & /* mask to precision */ + op_mask[result->precision]; + overflow = 0; + } + +result->exponent = 0; /* tidy up for integer value */ +return overflow; +} + + +/* Float an integer to an unpacked number. + + An integer is converted to a floating-point value. The desired precision of + the result must be set before calling. + + Conversion is simply a matter of copying the integer value, setting an + exponent that reflects the right-aligned position of the bits, and + normalizing. +*/ + +static void ffloat (FPU *result, FPU operand) +{ +result->mantissa = operand.mantissa; /* set value */ +result->exponent = op_bits[operand.precision]; /* set exponent */ +normalize (result); /* normalize */ +return; +} + + + +/* High-level floating-point routines. */ + + +/* Determine operand precisions. + + The precisions of the operands and result are determined by decoding an + operation opcode and returned to the caller. Pass NULL for both of the + operands if only the result precision is wanted. Pass NULL for the result if + only the operand precisions are wanted. + + Implementation note: + + 1. gcc-4.3.0 complains at -O3 that operand_l/r may not be initialized. + Because of the mask, the switch statement covers all cases, but gcc + doesn't realize this. The "default" case is redundant but eliminates the + warning. +*/ + +void fp_prec (uint16 opcode, OPSIZE *operand_l, OPSIZE *operand_r, OPSIZE *result) +{ +OPSIZE fp_size, int_size; + +fp_size = (OPSIZE) ((opcode & 0003) + 2); /* fp_f, fp_x, fp_t, fp_e */ +int_size = (OPSIZE) ((opcode & 0004) >> 2); /* in_s, in_d */ + +if (operand_l && operand_r) { /* want operand precisions? */ + switch (opcode & 0120) { /* mask out opcode bit 5 */ + case 0000: /* add/mpy */ + case 0020: /* sub/div */ + *operand_l = fp_size; /* assume first op is fp */ + + if (opcode & 0004) /* operand internal? */ + *operand_r = fp_a; /* second op is accum */ + else + *operand_r = fp_size; /* second op is fp */ + break; + + case 0100: /* fix/accum as integer */ + *operand_l = fp_size; /* first op is fp */ + *operand_r = fp_a; /* second op is always null */ + break; + + case 0120: /* flt/accum as float */ + default: /* keeps compiler quiet for uninit warning */ + *operand_l = int_size; /* first op is integer */ + *operand_r = fp_a; /* second op is always null */ + break; + } + + if (opcode & 0010) /* operand internal? */ + *operand_l = fp_a; /* first op is accum */ + } + +if (result) /* want result precision? */ + if ((opcode & 0120) == 0100) /* fix? */ + *result = int_size; /* result is integer */ + else /* all others */ + *result = fp_size; /* result is fp */ + +return; +} + + +/* Floating Point Processor executor. + + The executor simulates the MPP interface between the CPU and the FPP. The + operation to be performed is specified by the supplied opcode, which conforms + to the FPP hardware interface, as follows: + + Bits Value Action + ---- ----- ---------------------------------------------- + 7 0 Exponent range is standard (+/-127) + 1 Exponent range is expanded (+/-511) + + 6-4 000 Add + 001 Subtract + 010 Multiply + 011 Divide + 100 Fix + 101 Float + 110 (diagnostic) + 111 (diagnostic) + + 3 0 Left operand is supplied + 1 Left operand in accumulator + + 2 0 Right operand is supplied (ADD/SUB/MPY/DIV) + Single integer operation (FIX/FLT) + 1 Right operand in accumulator (ADD/SUB/MPY/DIV) + Double integer operation (FIX/FLT) + + 1-0 00 2-word operation + 01 3-word operation + 10 4-word operation + 11 5-word operation + + If the opcode specifies that the left (or right) operand is in the + accumulator, then the value supplied for that parameter is not used. All + results are automatically left in the accumulator. If the result is not + needed externally, then NULL may be passed for the result parameter. + + To support accumulator set/get operations under simulation, the opcode is + expanded to include a special mode, indicated by bit 15 = 1. In this mode, + if the result parameter is NULL, then the accumulator is set from the value + passed as operand_l. If the result parameter is not null, then the + accumulator value is returned as the result, and operand_l is ignored. The + precision of the operation is performed as specified by the OPSIZE value + passed in bits 2-0 of the opcode. + + The function returns 1 if the operation overflows and 0 if not. +*/ + +uint32 fp_exec (uint16 opcode, OP *result, OP operand_l, OP operand_r) +{ +static FPU accumulator; +FPU uoperand_l, uoperand_r; +OPSIZE op_l_prec, op_r_prec, rslt_prec; +uint32 overflow; + +if (opcode & SIGN) { /* accumulator mode? */ + rslt_prec = (OPSIZE) (opcode & 0017); /* get operation precision */ + + if (result) { /* get accumulator? */ + op_l_prec = accumulator.precision; /* save accum prec temp */ + accumulator.precision = rslt_prec; /* set desired precision */ + *result = pack (accumulator); /* pack accumulator */ + accumulator.precision = op_l_prec; /* restore correct prec */ + } + else /* set accumulator */ + accumulator = unpack (operand_l, rslt_prec); /* unpack from operand */ + + return 0; /* no overflow from accum ops */ + } + +fp_prec (opcode, &op_l_prec, &op_r_prec, &rslt_prec); /* calc precs from opcode */ + +if (op_l_prec == fp_a) /* left operand in accum? */ + uoperand_l = accumulator; /* copy it */ +else /* operand supplied */ + uoperand_l = unpack (operand_l, op_l_prec); /* unpack from parameter */ + +if (op_r_prec == fp_a) /* right operand in accum? */ + uoperand_r = accumulator; /* copy it */ +else /* operand supplied */ + uoperand_r = unpack (operand_r, op_r_prec); /* unpack from parameter */ + + +switch (opcode & 0160) { /* dispatch operation */ + + case 0000: /* add */ + add (&accumulator, uoperand_l, uoperand_r); + break; + + case 0020: /* subtract */ + complement (&uoperand_r); + add (&accumulator, uoperand_l, uoperand_r); + break; + + case 0040: /* multiply */ + multiply (&accumulator, uoperand_l, uoperand_r); + break; + + case 0060: /* divide */ + divide (&accumulator, uoperand_l, uoperand_r); + break; + + case 0100: /* fix */ + accumulator.precision = rslt_prec; + overflow = fix (&accumulator, uoperand_l); + + if (result) /* result wanted? */ + *result = pack_int (accumulator.mantissa, /* pack integer */ + rslt_prec); + return overflow; + + case 0120: /* float */ + accumulator.precision = rslt_prec; + ffloat (&accumulator, uoperand_l); + + if (result) /* result wanted? */ + *result = pack (accumulator); /* pack FP (FLT does not round) */ + return 0; + + case 0140: /* (diagnostic) */ + case 0160: /* (diagnostic) */ + return 0; + } + +if (UNIT_CPU_MODEL != UNIT_1000_F) /* firmware implementation? */ + accumulator.mantissa = accumulator.mantissa & /* mask to precision */ + op_mask[accumulator.precision]; + +normalize (&accumulator); /* normalize */ +overflow = roundovf (&accumulator, opcode & 0200); /* round and check for overflow */ + +if (result) /* result wanted? */ + *result = pack (accumulator); /* pack result */ + +return overflow; +} + + +/* Set or get accumulator at desired precision. + + This function provides access to the FPP accumulator. In hardware, the + accumulator may be read at a given precision by sending the FPP an opcode + encoded with the desired precision and then reading words from the FPP + /without/ initiating the operation, i.e., without starting the processor. + + Under simulation, pass this function a NULL operand and the desired + precision to read the accumulator. Pass a pointer to an operand and the + desired precision to set the accumulator; the return value in this case is + not defined. +*/ + +OP fp_accum (const OP *operand, OPSIZE precision) +{ +OP result = NOP; +uint16 opcode = (uint16) precision | SIGN; /* add special mode bit */ + +if (operand) + fp_exec (opcode, NULL, *operand, NOP); /* set accum */ +else + fp_exec (opcode, &result, NOP, NOP); /* get accum */ +return result; +} + + +/* Pack an unpacked floating-point number. + + An unpacked mantissa is passed as a "packed" number with an unused exponent. + The mantissa and separately-passed exponent are packed into the in-memory + floating-point format. Note that all bits are significant in the mantissa + (no masking is done). +*/ + +uint32 fp_pack (OP *result, OP mantissa, int32 exponent, OPSIZE precision) +{ +FPU unpacked; + +unpacked.mantissa = unpack_int (mantissa, precision); /* unpack mantissa */ +unpacked.exponent = exponent; /* set exponent */ +unpacked.precision = precision; /* set precision */ +*result = pack (unpacked); /* pack them */ +return 0; +} + + +/* Normalize, round, and pack an unpacked floating-point number. + + An unpacked mantissa is passed as a "packed" number with an unused exponent. + The mantissa and separately-passed exponent are normalized, rounded, and + packed into the in-memory floating-point format. Note that all bits are + significant in the mantissa (no masking is done). +*/ + +uint32 fp_nrpack (OP *result, OP mantissa, int32 exponent, OPSIZE precision) +{ +FPU unpacked; + +unpacked.mantissa = unpack_int (mantissa, precision); /* unpack mantissa */ +unpacked.exponent = exponent; /* set exponent */ +unpacked.precision = precision; /* set precision */ +return nrpack (result, unpacked, FALSE); /* norm/rnd/pack them */ +} + + +/* Unpack a packed floating-point number. + + A floating-point number, packed into the in-memory format, is unpacked into + separate mantissa and exponent values. The unpacked mantissa is returned in + a "packed" structure with an exponent of zero. Mantissa or exponent may be + null if that part isn't wanted. +*/ + +uint32 fp_unpack (OP *mantissa, int32 *exponent, OP packed, OPSIZE precision) + +{ +FPU unpacked; + +unpacked = unpack (packed, precision); /* unpack mantissa and exponent */ + +if (exponent) /* exponent wanted? */ + *exponent = unpacked.exponent; /* return exponent */ + +if (mantissa) /* mantissa wanted? */ + *mantissa = pack_int (unpacked.mantissa, fp_t); /* return full-size mantissa */ +return 0; +} + + +/* Complement an unpacked mantissa. + + An unpacked mantissa is passed as a "packed" number with a zero exponent. + The exponent increment, i.e., either zero or one, depending on whether a + renormalization was required, is returned. Note that all bits are + significant in the mantissa. +*/ + +uint16 fp_ucom (OP *mantissa, OPSIZE precision) +{ +FPU unpacked; + +unpacked.mantissa = unpack_int (*mantissa, precision); /* unpack mantissa */ +unpacked.exponent = 0; /* clear undefined exponent */ +unpacked.precision = precision; /* set precision */ +complement (&unpacked); /* negate it */ +*mantissa = pack_int (unpacked.mantissa, precision); /* replace mantissa */ +return (uint16) unpacked.exponent; /* return exponent increment */ +} + + +/* Complement a floating-point number. */ + +uint32 fp_pcom (OP *packed, OPSIZE precision) +{ +FPU unpacked; + +unpacked = unpack (*packed, precision); /* unpack the number */ +complement (&unpacked); /* negate it */ +return nrpack (packed, unpacked, FALSE); /* and norm/rnd/pack */ +} + + +/* Truncate a floating-point number. */ + +uint32 fp_trun (OP *result, OP source, OPSIZE precision) +{ +t_bool bits_lost; +FPU unpacked; +FPU one = { FP_ONEHALF, 1, fp_t }; /* 0.5 * 2 ** 1 = 1.0 */ +OP zero = { { 0, 0, 0, 0, 0 } }; /* 0.0 */ +t_uint64 mask = mant_mask[precision] & ~FP_MSIGN; + +unpacked = unpack (source, precision); +if (unpacked.exponent < 0) /* number < 0.5? */ + *result = zero; /* return 0 */ +else if (unpacked.exponent >= (int32) op_bits[precision]) /* no fractional bits? */ + *result = source; /* already integer */ +else { + mask = (mask >> unpacked.exponent) & mask; /* mask fractional bits */ + bits_lost = ((unpacked.mantissa & mask) != 0); /* flag if bits lost */ + unpacked.mantissa = unpacked.mantissa & ~mask; /* mask off fraction */ + if ((unpacked.mantissa < 0) && bits_lost) /* negative? */ + add (&unpacked, unpacked, one); /* truncate toward zero */ + nrpack (result, unpacked, FALSE); /* (overflow cannot occur) */ + } +return 0; /* clear overflow on return */ +} + + +/* Convert a floating-point number from one precision to another. */ + +uint32 fp_cvt (OP *result, OPSIZE source_precision, OPSIZE dest_precision) +{ +FPU unpacked; + +unpacked = unpack (*result, source_precision); +unpacked.precision = dest_precision; +return nrpack (result, unpacked, FALSE); /* norm/rnd/pack */ +} + + +#endif /* end of int64 support */ diff --git a/HP2100/hp2100_fp1.h b/HP2100/hp2100_fp1.h index 4649c09a..4b25da83 100644 --- a/HP2100/hp2100_fp1.h +++ b/HP2100/hp2100_fp1.h @@ -1,53 +1,55 @@ -/* hp2100_fp1.h: HP 2100/1000 multiple-precision floating point definitions - - Copyright (c) 2005-2006, J. David Bryan - - 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 - THE AUTHOR 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 the author shall not be used - in advertising or otherwise to promote the sale, use or other dealings in - this Software without prior written authorization from the author. - - 16-Oct-06 JDB Generalized FP calling sequences for F-Series - 12-Oct-06 JDB Altered x_trun for F-Series FFP compatibility -*/ - -#ifndef _HP2100_FP1_H_ -#define _HP2100_FP1_H_ 0 - - -/* Special operands. */ - -#define ACCUM NULL /* result not returned */ -static const OP NOP = { { 0, 0, 0, 0, 0 } }; /* unneeded operand */ - - -/* Generalized floating-point handlers. */ - -void fp_prec (uint16 opcode, OPSIZE *operand_l, OPSIZE *operand_r, OPSIZE *result); -uint32 fp_exec (uint16 opcode, OP *result, OP operand_l, OP operand_r); -OP fp_accum (const OP *operand, OPSIZE precision); -uint32 fp_pack (OP *result, OP mantissa, int32 exponent, OPSIZE precision); -uint32 fp_nrpack (OP *result, OP mantissa, int32 exponent, OPSIZE precision); -uint32 fp_unpack (OP *mantissa, int32 *exponent, OP packed, OPSIZE precision); -uint32 fp_ucom (OP *mantissa, OPSIZE precision); -uint32 fp_pcom (OP *packed, OPSIZE precision); -uint32 fp_trun (OP *result, OP source, OPSIZE precision); -uint32 fp_cvt (OP *result, OPSIZE source_precision, OPSIZE dest_precision); - -#endif +/* hp2100_fp1.h: HP 2100/1000 multiple-precision floating point definitions + + Copyright (c) 2005-2014, J. David Bryan + + 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 + THE AUTHOR 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 the author shall not be used + in advertising or otherwise to promote the sale, use or other dealings in + this Software without prior written authorization from the author. + + 24-Dec-14 JDB Changed fp_ucom return from uint32 to uint16 + 14-Mar-13 MP Changed guard macro name to avoid reserved namespace + 16-Oct-06 JDB Generalized FP calling sequences for F-Series + 12-Oct-06 JDB Altered x_trun for F-Series FFP compatibility +*/ + +#ifndef HP2100_FP1_H_ +#define HP2100_FP1_H_ 0 + + +/* Special operands. */ + +#define ACCUM NULL /* result not returned */ +static const OP NOP = { { 0, 0, 0, 0, 0 } }; /* unneeded operand */ + + +/* Generalized floating-point handlers. */ + +void fp_prec (uint16 opcode, OPSIZE *operand_l, OPSIZE *operand_r, OPSIZE *result); +uint32 fp_exec (uint16 opcode, OP *result, OP operand_l, OP operand_r); +OP fp_accum (const OP *operand, OPSIZE precision); +uint32 fp_pack (OP *result, OP mantissa, int32 exponent, OPSIZE precision); +uint32 fp_nrpack (OP *result, OP mantissa, int32 exponent, OPSIZE precision); +uint32 fp_unpack (OP *mantissa, int32 *exponent, OP packed, OPSIZE precision); +uint16 fp_ucom (OP *mantissa, OPSIZE precision); +uint32 fp_pcom (OP *packed, OPSIZE precision); +uint32 fp_trun (OP *result, OP source, OPSIZE precision); +uint32 fp_cvt (OP *result, OPSIZE source_precision, OPSIZE dest_precision); + +#endif diff --git a/HP2100/hp2100_ipl.c b/HP2100/hp2100_ipl.c index 595d47e9..61c785a8 100644 --- a/HP2100/hp2100_ipl.c +++ b/HP2100/hp2100_ipl.c @@ -1,782 +1,795 @@ -/* hp2100_ipl.c: HP 2000 interprocessor link simulator - - Copyright (c) 2002-2012, Robert M Supnik - - 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 - ROBERT M SUPNIK 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 Robert M Supnik shall not be - used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from Robert M Supnik. - - IPLI, IPLO 12875A interprocessor link - - 10-Feb-12 JDB Deprecated DEVNO in favor of SC - Added CARD_INDEX casts to dib.card_index - 07-Apr-11 JDB A failed STC may now be retried - 28-Mar-11 JDB Tidied up signal handling - 27-Mar-11 JDB Consolidated reporting of consecutive CRS signals - 29-Oct-10 JDB Revised for new multi-card paradigm - 26-Oct-10 JDB Changed I/O signal handler for revised signal model - 07-Sep-08 JDB Changed Telnet poll to connect immediately after reset or attach - 15-Jul-08 JDB Revised EDT handler to refine completion delay conditions - 09-Jul-08 JDB Revised ipl_boot to use ibl_copy - 26-Jun-08 JDB Rewrote device I/O to model backplane signals - 01-Mar-07 JDB IPLI EDT delays DMA completion interrupt for TSB - Added debug printouts - 28-Dec-06 JDB Added ioCRS state to I/O decoders - 16-Aug-05 RMS Fixed C++ declaration and cast problems - 07-Oct-04 JDB Fixed enable/disable from either device - 26-Apr-04 RMS Fixed SFS x,C and SFC x,C - Implemented DMA SRQ (follows FLG) - 21-Dec-03 RMS Adjusted ipl_ptime for TSB (from Mike Gemeny) - 09-May-03 RMS Added network device flag - 31-Jan-03 RMS Links are full duplex (found by Mike Gemeny) - - Reference: - - 12875A Processor Interconnect Kit Operating and Service Manual - (12875-90002, Jan-1974) - - - The 12875A Processor Interconnect Kit consists four 12566A Microcircuit - Interface cards. Two are used in each processor. One card in each system is - used to initiate transmissions to the other, and the second card is used to - receive transmissions from the other. Each pair of cards forms a - bidirectional link, as the sixteen data lines are cross-connected, so that - data sent and status returned are supported. In each processor, data is sent - on the lower priority card and received on the higher priority card. Two - sets of cards are used to support simultaneous transmission in both - directions. -*/ - - -#include "hp2100_defs.h" -#include "hp2100_cpu.h" -#include "sim_sock.h" -#include "sim_tmxr.h" - -typedef enum { ipli, iplo } CARD_INDEX; /* card index number */ - -#define CARD_COUNT 2 /* count of cards supported */ - -#define UNIT_V_DIAG (UNIT_V_UF + 0) /* diagnostic mode */ -#define UNIT_V_ACTV (UNIT_V_UF + 1) /* making connection */ -#define UNIT_V_ESTB (UNIT_V_UF + 2) /* connection established */ -#define UNIT_V_HOLD (UNIT_V_UF + 3) /* character holding */ -#define UNIT_DIAG (1 << UNIT_V_DIAG) -#define UNIT_ACTV (1 << UNIT_V_ACTV) -#define UNIT_ESTB (1 << UNIT_V_ESTB) -#define UNIT_HOLD (1 << UNIT_V_HOLD) -#define IBUF buf /* input buffer */ -#define OBUF wait /* output buffer */ -#define DSOCKET u3 /* data socket */ -#define LSOCKET u4 /* listening socket */ - -/* Debug flags */ - -#define DEB_CMDS (1 << 0) /* Command initiation and completion */ -#define DEB_CPU (1 << 1) /* CPU I/O */ -#define DEB_XFER (1 << 2) /* Socket receive and transmit */ - -extern DIB ptr_dib; /* need PTR select code for boot */ - -int32 ipl_edtdelay = 1; /* EDT delay (msec) */ -int32 ipl_ptime = 31; /* polling interval */ -int32 ipl_stopioe = 0; /* stop on error */ - -typedef struct { - FLIP_FLOP control; /* control flip-flop */ - FLIP_FLOP flag; /* flag flip-flop */ - FLIP_FLOP flagbuf; /* flag buffer flip-flop */ - int32 hold; /* holding character */ - } CARD_STATE; - -CARD_STATE ipl [CARD_COUNT]; /* per-card state */ - -IOHANDLER iplio; - -t_stat ipl_svc (UNIT *uptr); -t_stat ipl_reset (DEVICE *dptr); -t_stat ipl_attach (UNIT *uptr, char *cptr); -t_stat ipl_detach (UNIT *uptr); -t_stat ipl_boot (int32 unitno, DEVICE *dptr); -t_stat ipl_dscln (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat ipl_setdiag (UNIT *uptr, int32 val, char *cptr, void *desc); -t_bool ipl_check_conn (UNIT *uptr); - -/* Debug flags table */ - -DEBTAB ipl_deb [] = { - { "CMDS", DEB_CMDS }, - { "CPU", DEB_CPU }, - { "XFER", DEB_XFER }, - { NULL, 0 } }; - -/* Common structures */ - -DEVICE ipli_dev, iplo_dev; - -static DEVICE *dptrs [] = { &ipli_dev, &iplo_dev }; - - -UNIT ipl_unit [] = { - { UDATA (&ipl_svc, UNIT_ATTABLE, 0) }, - { UDATA (&ipl_svc, UNIT_ATTABLE, 0) } - }; - -#define ipli_unit ipl_unit [ipli] -#define iplo_unit ipl_unit [iplo] - - -DIB ipl_dib [] = { - { &iplio, IPLI, 0 }, - { &iplio, IPLO, 1 } - }; - -#define ipli_dib ipl_dib [ipli] -#define iplo_dib ipl_dib [iplo] - - -/* IPLI data structures - - ipli_dev IPLI device descriptor - ipli_unit IPLI unit descriptor - ipli_reg IPLI register list -*/ - -REG ipli_reg [] = { - { ORDATA (IBUF, ipli_unit.IBUF, 16) }, - { ORDATA (OBUF, ipli_unit.OBUF, 16) }, - { FLDATA (CTL, ipl [ipli].control, 0) }, - { FLDATA (FLG, ipl [ipli].flag, 0) }, - { FLDATA (FBF, ipl [ipli].flagbuf, 0) }, - { ORDATA (HOLD, ipl [ipli].hold, 8) }, - { DRDATA (TIME, ipl_ptime, 24), PV_LEFT }, - { FLDATA (STOP_IOE, ipl_stopioe, 0) }, - { ORDATA (SC, ipli_dib.select_code, 6), REG_HRO }, - { ORDATA (DEVNO, ipli_dib.select_code, 6), REG_HRO }, - { NULL } - }; - -MTAB ipl_mod [] = { - { UNIT_DIAG, UNIT_DIAG, "diagnostic mode", "DIAG", &ipl_setdiag }, - { UNIT_DIAG, 0, "link mode", "LINK", &ipl_setdiag }, - { MTAB_XTD | MTAB_VDV, 0, NULL, "DISCONNECT", - &ipl_dscln, NULL, NULL }, - { MTAB_XTD | MTAB_VDV, 1, "SC", "SC", &hp_setsc, &hp_showsc, &ipli_dev }, - { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &ipli_dev }, - { 0 } - }; - -DEVICE ipli_dev = { - "IPLI", &ipli_unit, ipli_reg, ipl_mod, - 1, 10, 31, 1, 16, 16, - &tmxr_ex, &tmxr_dep, &ipl_reset, - &ipl_boot, &ipl_attach, &ipl_detach, - &ipli_dib, DEV_NET | DEV_DISABLE | DEV_DIS | DEV_DEBUG, - 0, ipl_deb, NULL, NULL - }; - -/* IPLO data structures - - iplo_dev IPLO device descriptor - iplo_unit IPLO unit descriptor - iplo_reg IPLO register list -*/ - -REG iplo_reg [] = { - { ORDATA (IBUF, iplo_unit.IBUF, 16) }, - { ORDATA (OBUF, iplo_unit.OBUF, 16) }, - { FLDATA (CTL, ipl [iplo].control, 0) }, - { FLDATA (FLG, ipl [iplo].flag, 0) }, - { FLDATA (FBF, ipl [iplo].flagbuf, 0) }, - { ORDATA (HOLD, ipl [iplo].hold, 8) }, - { DRDATA (TIME, ipl_ptime, 24), PV_LEFT }, - { ORDATA (SC, iplo_dib.select_code, 6), REG_HRO }, - { ORDATA (DEVNO, iplo_dib.select_code, 6), REG_HRO }, - { NULL } - }; - -DEVICE iplo_dev = { - "IPLO", &iplo_unit, iplo_reg, ipl_mod, - 1, 10, 31, 1, 16, 16, - &tmxr_ex, &tmxr_dep, &ipl_reset, - &ipl_boot, &ipl_attach, &ipl_detach, - &iplo_dib, DEV_NET | DEV_DISABLE | DEV_DIS | DEV_DEBUG, - 0, ipl_deb, NULL, NULL - }; - - -/* I/O signal handler for the IPLI and IPLO devices. - - In the link mode, the IPLI and IPLO devices are linked via network - connections to the corresponding cards in another CPU instance. In the - diagnostic mode, we simulate the attachment of the interprocessor cable - between IPLI and IPLO in this machine. - - Implementation notes: - - 1. 2000 Access has a race condition that manifests itself by an apparently - normal boot and operational system console but no PLEASE LOG IN response - to terminals connected to the multiplexer. The frequency of occurrence - is higher on multiprocessor host systems, where the SP and IOP instances - may execute concurrently. - - The cause is this code in the SP disc loader source (2883.asm, 7900.asm, - 790X.asm, 79X3.asm, and 79XX.asm): - - LDA SDVTR REQUEST - JSB IOPMA,I DEVICE TABLE - [...] - STC DMAHS,C TURN ON DMA - SFS DMAHS WAIT FOR - JMP *-1 DEVICE TABLE - STC CH2,C SET CORRECT - CLC CH2 FLAG DIRECTION - - The STC/CLC normally would cause a second "request device table" command - to be recognized by the IOP, except that the IOP DMA setup routine - "DMAXF" (in D61.asm) has specified an end-of-block CLC that holds off the - IPL interrupt, and the completion interrupt routine "DMACP" ends with a - STC,C that clears the IPL flag. - - In hardware, the two CPUs are essentially interlocked by the DMA - transfer, and DMA completion interrupts occur almost simultaneously. - Therefore, the STC/CLC in the SP is guaranteed to occur before the STC,C - in the IOP. Under simulation, and especially on multiprocessor hosts, - that guarantee does not hold. If the STC/CLC occurs after the STC,C, - then the IOP starts a second device table DMA transfer, which the SP is - not expecting. The IOP never processes the subsequent "start - timesharing" command, and the muxtiplexer is non-reponsive. - - We employ a workaround that decreases the incidence of the problem: DMA - output completion interrupts are delayed to allow the other SIMH instance - a chance to process its own DMA completion. We do this by processing the - EDT (End Data Transfer) I/O backplane signal and "sleep"ing for a short - time if the transfer was an output transfer to the input channel, i.e., - a data response to the SP. This improves the race condition by delaying - the IOP until the SP has a chance to receive the last word, recognize its - own DMA input completion, drop out of the SFS loop, and execute the - STC/CLC. - - The condition is only improved, and not solved, because "sleep"ing the - IOP doesn't guarantee that the SP will actually execute. It's possible - that a higher-priority host process will preempt the SP, and that at the - sleep expiration, the SP still has not executed the STC/CLC. Still, in - testing, the incidence dropped dramatically, so the problem is much less - intrusive. - - 2. The operating manual for the 12920A Terminal Multiplexer says that "at - least 100 milliseconds of CLC 0s must be programmed" by systems employing - the multiplexer to ensure that the multiplexer resets. In practice, such - systems issue 128K CLC 0 instructions. As we provide debug logging of - IPL resets, a CRS counter is used to ensure that only one debug line is - printed in response to these 128K CRS invocations. - - 3. The STC handler may return "Unit not attached", "I/O error", or "No - connection on interprocessor link" status if the link fails or is - improperly configured. If the error is corrected, the operation may be - retried by resuming simulated execution. -*/ - -uint32 iplio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) -{ -CARD_INDEX card = (CARD_INDEX) dibptr->card_index; /* set card selector */ -UNIT *const uptr = &(ipl_unit [card]); /* associated unit pointer */ -const char *iotype [] = { "Status", "Command" }; -int32 sta; -char msg [2]; -static uint32 crs_count [CARD_COUNT] = { 0, 0 }; /* per-card cntrs for ioCRS repeat */ -IOSIGNAL signal; -IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ - -if (crs_count [card] && !(signal_set & ioCRS)) { /* counting CRSes and not present? */ - if (DEBUG_PRJ (dptrs [card], DEB_CMDS)) /* report reset count */ - fprintf (sim_deb, ">>%s cmds: [CRS] Control cleared %d times\n", - dptrs [card]->name, crs_count [card]); - - crs_count [card] = 0; /* clear counter */ - } - -while (working_set) { - signal = IONEXT (working_set); /* isolate next signal */ - - switch (signal) { /* dispatch I/O signal */ - - case ioCLF: /* clear flag flip-flop */ - ipl [card].flag = ipl [card].flagbuf = CLEAR; - break; - - - case ioSTF: /* set flag flip-flop */ - case ioENF: /* enable flag */ - ipl [card].flag = ipl [card].flagbuf = SET; - break; - - - case ioSFC: /* skip if flag is clear */ - setstdSKF (ipl [card]); - break; - - - case ioSFS: /* skip if flag is set */ - setstdSKF (ipl [card]); - break; - - - case ioIOI: /* I/O data input */ - stat_data = IORETURN (SCPE_OK, uptr->IBUF); /* get return data */ - - if (DEBUG_PRJ (dptrs [card], DEB_CPU)) - fprintf (sim_deb, ">>%s cpu: [LIx] %s = %06o\n", dptrs [card]->name, iotype [card ^ 1], uptr->IBUF); - break; - - - case ioIOO: /* I/O data output */ - uptr->OBUF = IODATA (stat_data); /* clear supplied status */ - - if (DEBUG_PRJ (dptrs [card], DEB_CPU)) - fprintf (sim_deb, ">>%s cpu: [OTx] %s = %06o\n", dptrs [card]->name, iotype [card], uptr->OBUF); - break; - - - case ioPOPIO: /* power-on preset to I/O */ - ipl [card].flag = ipl [card].flagbuf = SET; /* set flag buffer and flag */ - uptr->OBUF = 0; /* clear output buffer */ - break; - - - case ioCRS: /* control reset */ - if (crs_count [card] == 0) /* first reset? */ - ipl [card].control = CLEAR; /* clear control */ - - crs_count [card] = crs_count [card] + 1; /* increment count */ - break; - - - case ioCLC: /* clear control flip-flop */ - ipl [card].control = CLEAR; /* clear ctl */ - - if (DEBUG_PRJ (dptrs [card], DEB_CMDS)) - fprintf (sim_deb, ">>%s cmds: [CLC] Control cleared\n", dptrs [card]->name); - break; - - - case ioSTC: /* set control flip-flop */ - if (DEBUG_PRJ (dptrs [card], DEB_CMDS)) - fprintf (sim_deb, ">>%s cmds: [STC] Control set\n", dptrs [card]->name); - - if (uptr->flags & UNIT_ATT) { /* attached? */ - if (!ipl_check_conn (uptr)) /* not established? */ - return IORETURN (STOP_NOCONN, 0); /* lose */ - - msg [0] = (uptr->OBUF >> 8) & 0377; - msg [1] = uptr->OBUF & 0377; - sta = sim_write_sock (uptr->DSOCKET, msg, 2); - - if (DEBUG_PRJ (dptrs [card], DEB_XFER)) - fprintf (sim_deb, - ">>%s xfer: [STC] Socket write = %06o, status = %d\n", - dptrs [card]->name, uptr->OBUF, sta); - - if (sta == SOCKET_ERROR) { - printf ("IPL socket write error\n"); - return IORETURN (SCPE_IOERR, 0); - } - - ipl [card].control = SET; /* set ctl */ - - sim_os_sleep (0); - } - - else if (uptr->flags & UNIT_DIAG) { /* diagnostic mode? */ - ipl [card].control = SET; /* set ctl */ - ipl_unit [card ^ 1].IBUF = uptr->OBUF; /* output to other */ - iplio ((DIB *) dptrs [card ^ 1]->ctxt, ioENF, 0); /* set other flag */ - } - - else - return IORETURN (SCPE_UNATT, 0); /* lose */ - break; - - - case ioEDT: /* end data transfer */ - if ((cpu_unit.flags & UNIT_IOP) && /* are we the IOP? */ - (signal_set & ioIOO) && /* and doing output? */ - (card == ipli)) { /* on the input card? */ - - if (DEBUG_PRJ (dptrs [card], DEB_CMDS)) - fprintf (sim_deb, - ">>%s cmds: [EDT] Delaying DMA completion interrupt for %d msec\n", - dptrs [card]->name, ipl_edtdelay); - - sim_os_ms_sleep (ipl_edtdelay); /* delay completion */ - } - break; - - - case ioSIR: /* set interrupt request */ - setstdPRL (ipl [card]); - setstdIRQ (ipl [card]); - setstdSRQ (ipl [card]); - break; - - - case ioIAK: /* interrupt acknowledge */ - ipl [card].flagbuf = CLEAR; - break; - - - default: /* all other signals */ - break; /* are ignored */ - } - - working_set = working_set & ~signal; /* remove current signal from set */ - } - -return stat_data; -} - - -/* Unit service - poll for input */ - -t_stat ipl_svc (UNIT *uptr) -{ -CARD_INDEX card; -int32 nb; -char msg [2]; - -if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */ - return SCPE_OK; - -sim_activate (uptr, ipl_ptime); /* reactivate */ - -if (!ipl_check_conn (uptr)) /* check for conn */ - return SCPE_OK; /* not connected */ - -nb = sim_read_sock (uptr->DSOCKET, msg, ((uptr->flags & UNIT_HOLD)? 1: 2)); - -if (nb < 0) { /* connection closed? */ - printf ("IPL socket read error\n"); - return SCPE_IOERR; - } - -else if (nb == 0) /* no data? */ - return SCPE_OK; - -card = (CARD_INDEX) (uptr == &iplo_unit); /* set card selector */ - -if (uptr->flags & UNIT_HOLD) { /* holdover byte? */ - uptr->IBUF = (ipl [card].hold << 8) | (((int32) msg [0]) & 0377); - uptr->flags = uptr->flags & ~UNIT_HOLD; - } -else if (nb == 1) { - ipl [card].hold = ((int32) msg [0]) & 0377; - uptr->flags = uptr->flags | UNIT_HOLD; - } -else - uptr->IBUF = ((((int32) msg [0]) & 0377) << 8) | (((int32) msg [1]) & 0377); - -iplio ((DIB *) dptrs [card]->ctxt, ioENF, 0); /* set flag */ - -if (DEBUG_PRJ (dptrs [card], DEB_XFER)) - fprintf (sim_deb, ">>%s xfer: Socket read = %06o, status = %d\n", - dptrs [card]->name, uptr->IBUF, nb); - -return SCPE_OK; -} - - -t_bool ipl_check_conn (UNIT *uptr) -{ -SOCKET sock; - -if (uptr->flags & UNIT_ESTB) /* established? */ - return TRUE; - -if (uptr->flags & UNIT_ACTV) { /* active connect? */ - if (sim_check_conn (uptr->DSOCKET, 0) <= 0) - return FALSE; - } - -else { - sock = sim_accept_conn (uptr->LSOCKET, NULL); /* poll connect */ - - if (sock == INVALID_SOCKET) /* got a live one? */ - return FALSE; - - uptr->DSOCKET = sock; /* save data socket */ - } - -uptr->flags = uptr->flags | UNIT_ESTB; /* conn established */ -return TRUE; -} - - -/* Reset routine. - - Implementation notes: - - 1. We set up the first poll for socket connections to occur "immediately" - upon execution, so that clients will be connected before execution - begins. Otherwise, a fast program may access the IPL before the poll - service routine activates. -*/ - -t_stat ipl_reset (DEVICE *dptr) -{ -UNIT *uptr = dptr->units; -DIB *dibptr = (DIB *) dptr->ctxt; /* DIB pointer */ -CARD_INDEX card = (CARD_INDEX) dibptr->card_index; /* card number */ - -hp_enbdis_pair (dptr, dptrs [card ^ 1]); /* make pair cons */ - -if (sim_switches & SWMASK ('P')) /* initialization reset? */ - uptr->IBUF = uptr->OBUF = 0; /* clr buffers */ - -IOPRESET (dibptr); /* PRESET device (does not use PON) */ - -if (uptr->flags & UNIT_ATT) /* socket attached? */ - sim_activate (uptr, POLL_FIRST); /* activate first poll "immediately" */ -else - sim_cancel (uptr); /* deactivate unit */ - -uptr->flags = uptr->flags & ~UNIT_HOLD; /* clear holding flag */ -return SCPE_OK; -} - - -/* Attach routine - - attach -l - listen for connection on port - attach -c - connect to ip address and port -*/ - -t_stat ipl_attach (UNIT *uptr, char *cptr) -{ -SOCKET newsock; -uint32 i, t, ipa, ipp, oldf; -char *tptr; -t_stat r; - -r = get_ipaddr (cptr, &ipa, &ipp); -if ((r != SCPE_OK) || (ipp == 0)) - return SCPE_ARG; -oldf = uptr->flags; -if (oldf & UNIT_ATT) - ipl_detach (uptr); -if ((sim_switches & SWMASK ('C')) || - ((sim_switches & SIM_SW_REST) && (oldf & UNIT_ACTV))) { - if (ipa == 0) - ipa = 0x7F000001; - newsock = sim_connect_sock (ipa, ipp); - if (newsock == INVALID_SOCKET) - return SCPE_IOERR; - printf ("Connecting to IP address %d.%d.%d.%d, port %d\n", - (ipa >> 24) & 0xff, (ipa >> 16) & 0xff, - (ipa >> 8) & 0xff, ipa & 0xff, ipp); - if (sim_log) - fprintf (sim_log, - "Connecting to IP address %d.%d.%d.%d, port %d\n", - (ipa >> 24) & 0xff, (ipa >> 16) & 0xff, - (ipa >> 8) & 0xff, ipa & 0xff, ipp); - uptr->flags = uptr->flags | UNIT_ACTV; - uptr->LSOCKET = 0; - uptr->DSOCKET = newsock; - } -else { - if (ipa != 0) - return SCPE_ARG; - newsock = sim_master_sock (ipp); - if (newsock == INVALID_SOCKET) - return SCPE_IOERR; - printf ("Listening on port %d\n", ipp); - if (sim_log) - fprintf (sim_log, "Listening on port %d\n", ipp); - uptr->flags = uptr->flags & ~UNIT_ACTV; - uptr->LSOCKET = newsock; - uptr->DSOCKET = 0; - } -uptr->IBUF = uptr->OBUF = 0; -uptr->flags = (uptr->flags | UNIT_ATT) & ~(UNIT_ESTB | UNIT_HOLD); -tptr = (char *) malloc (strlen (cptr) + 1); /* get string buf */ -if (tptr == NULL) { /* no memory? */ - ipl_detach (uptr); /* close sockets */ - return SCPE_MEM; - } -strcpy (tptr, cptr); /* copy ipaddr:port */ -uptr->filename = tptr; /* save */ -sim_activate (uptr, POLL_FIRST); /* activate first poll "immediately" */ -if (sim_switches & SWMASK ('W')) { /* wait? */ - for (i = 0; i < 30; i++) { /* check for 30 sec */ - if (t = ipl_check_conn (uptr)) /* established? */ - break; - if ((i % 10) == 0) /* status every 10 sec */ - printf ("Waiting for connnection\n"); - sim_os_sleep (1); /* sleep 1 sec */ - } - if (t) - printf ("Connection established\n"); - } -return SCPE_OK; -} - -/* Detach routine */ - -t_stat ipl_detach (UNIT *uptr) -{ -if (!(uptr->flags & UNIT_ATT)) /* attached? */ - return SCPE_OK; - -if (uptr->flags & UNIT_ACTV) - sim_close_sock (uptr->DSOCKET, 1); - -else { - if (uptr->flags & UNIT_ESTB) /* if established, */ - sim_close_sock (uptr->DSOCKET, 0); /* close data socket */ - sim_close_sock (uptr->LSOCKET, 1); /* closen listen socket */ - } - -free (uptr->filename); /* free string */ -uptr->filename = NULL; -uptr->LSOCKET = 0; -uptr->DSOCKET = 0; -uptr->flags = uptr->flags & ~(UNIT_ATT | UNIT_ACTV | UNIT_ESTB); -sim_cancel (uptr); /* don't poll */ -return SCPE_OK; -} - -/* Disconnect routine */ - -t_stat ipl_dscln (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -if (cptr) - return SCPE_ARG; -if (((uptr->flags & UNIT_ATT) == 0) || - (uptr->flags & UNIT_ACTV) || - ((uptr->flags & UNIT_ESTB) == 0)) - return SCPE_NOFNC; -sim_close_sock (uptr->DSOCKET, 0); -uptr->DSOCKET = 0; -uptr->flags = uptr->flags & ~UNIT_ESTB; -return SCPE_OK; -} - -/* Diagnostic/normal mode routine */ - -t_stat ipl_setdiag (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -if (val) { - ipli_unit.flags = ipli_unit.flags | UNIT_DIAG; - iplo_unit.flags = iplo_unit.flags | UNIT_DIAG; - } -else { - ipli_unit.flags = ipli_unit.flags & ~UNIT_DIAG; - iplo_unit.flags = iplo_unit.flags & ~UNIT_DIAG; - } -return SCPE_OK; -} - -/* Interprocessor link bootstrap routine (HP Access Manual) */ - -#define MAX_BASE 073 -#define IPL_PNTR 074 -#define PTR_PNTR 075 -#define IPL_DEVA 076 -#define PTR_DEVA 077 - -static const BOOT_ROM ipl_rom = { - 0163774, /*BBL LDA ICK,I ; IPL sel code */ - 0027751, /* JMP CFG ; go configure */ - 0107700, /*ST CLC 0,C ; intr off */ - 0002702, /* CLA,CCE,SZA ; skip in */ - 0063772, /*CN LDA M26 ; feed frame */ - 0002307, /*EOC CCE,INA,SZA,RSS ; end of file? */ - 0027760, /* JMP EOT ; yes */ - 0017736, /* JSB READ ; get #char */ - 0007307, /* CMB,CCE,INB,SZB,RSS ; 2's comp; null? */ - 0027705, /* JMP EOC ; read next */ - 0077770, /* STB WC ; word in rec */ - 0017736, /* JSB READ ; get feed frame */ - 0017736, /* JSB READ ; get address */ - 0074000, /* STB 0 ; init csum */ - 0077771, /* STB AD ; save addr */ - 0067771, /*CK LDB AD ; check addr */ - 0047773, /* ADB MAXAD ; below loader */ - 0002040, /* SEZ ; E =0 => OK */ - 0102055, /* HLT 55 */ - 0017736, /* JSB READ ; get word */ - 0040001, /* ADA 1 ; cont checksum */ - 0177771, /* STB AD,I ; store word */ - 0037771, /* ISZ AD */ - 0000040, /* CLE ; force wd read */ - 0037770, /* ISZ WC ; block done? */ - 0027717, /* JMP CK ; no */ - 0017736, /* JSB READ ; get checksum */ - 0054000, /* CPB 0 ; ok? */ - 0027704, /* JMP CN ; next block */ - 0102011, /* HLT 11 ; bad csum */ - 0000000, /*RD 0 */ - 0006600, /* CLB,CME ; E reg byte ptr */ - 0103700, /*IO1 STC RDR,C ; start reader */ - 0102300, /*IO2 SFS RDR ; wait */ - 0027741, /* JMP *-1 */ - 0106400, /*IO3 MIB RDR ; get byte */ - 0002041, /* SEZ,RSS ; E set? */ - 0127736, /* JMP RD,I ; no, done */ - 0005767, /* BLF,CLE,BLF ; shift byte */ - 0027740, /* JMP IO1 ; again */ - 0163775, /* LDA PTR,I ; get ptr code */ - 0043765, /*CFG ADA SFS ; config IO */ - 0073741, /* STA IO2 */ - 0043766, /* ADA STC */ - 0073740, /* STA IO1 */ - 0043767, /* ADA MIB */ - 0073743, /* STA IO3 */ - 0027702, /* JMP ST */ - 0063777, /*EOT LDA PSC ; put select codes */ - 0067776, /* LDB ISC ; where xloader wants */ - 0102077, /* HLT 77 */ - 0027702, /* JMP ST */ - 0000000, /* NOP */ - 0102300, /*SFS SFS 0 */ - 0001400, /*STC 1400 */ - 0002500, /*MIB 2500 */ - 0000000, /*WC 0 */ - 0000000, /*AD 0 */ - 0177746, /*M26 -26 */ - 0000000, /*MAX -BBL */ - 0007776, /*ICK ISC */ - 0007777, /*PTR IPT */ - 0000000, /*ISC 0 */ - 0000000 /*IPT 0 */ - }; - -t_stat ipl_boot (int32 unitno, DEVICE *dptr) -{ -const int32 devi = ipli_dib.select_code; -const int32 devp = ptr_dib.select_code; - -ibl_copy (ipl_rom, devi); /* copy bootstrap to memory */ -SR = (devi << IBL_V_DEV) | devp; /* set SR */ -WritePW (PC + MAX_BASE, (~PC + 1) & DMASK); /* fix ups */ -WritePW (PC + IPL_PNTR, ipl_rom [IPL_PNTR] | PC); -WritePW (PC + PTR_PNTR, ipl_rom [PTR_PNTR] | PC); -WritePW (PC + IPL_DEVA, devi); -WritePW (PC + PTR_DEVA, devp); -return SCPE_OK; -} +/******************************************************************************* + * * + * WARNING: THE 4.0 VERSION OF THIS FILE IS DIFFERENT (SOCKET API CHANGED)!!! * + * * + *******************************************************************************/ + +/* hp2100_ipl.c: HP 2000 interprocessor link simulator + + Copyright (c) 2002-2014, Robert M Supnik + + 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 + ROBERT M SUPNIK 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 Robert M Supnik shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + + IPLI, IPLO 12875A interprocessor link + + 30-Dec-14 JDB Added S-register parameters to ibl_copy + 25-Oct-12 JDB Removed DEV_NET to allow restoration of listening ports + 09-May-12 JDB Separated assignments from conditional expressions + 10-Feb-12 JDB Deprecated DEVNO in favor of SC + Added CARD_INDEX casts to dib.card_index + 07-Apr-11 JDB A failed STC may now be retried + 28-Mar-11 JDB Tidied up signal handling + 27-Mar-11 JDB Consolidated reporting of consecutive CRS signals + 29-Oct-10 JDB Revised for new multi-card paradigm + 26-Oct-10 JDB Changed I/O signal handler for revised signal model + 07-Sep-08 JDB Changed Telnet poll to connect immediately after reset or attach + 15-Jul-08 JDB Revised EDT handler to refine completion delay conditions + 09-Jul-08 JDB Revised ipl_boot to use ibl_copy + 26-Jun-08 JDB Rewrote device I/O to model backplane signals + 01-Mar-07 JDB IPLI EDT delays DMA completion interrupt for TSB + Added debug printouts + 28-Dec-06 JDB Added ioCRS state to I/O decoders + 16-Aug-05 RMS Fixed C++ declaration and cast problems + 07-Oct-04 JDB Fixed enable/disable from either device + 26-Apr-04 RMS Fixed SFS x,C and SFC x,C + Implemented DMA SRQ (follows FLG) + 21-Dec-03 RMS Adjusted ipl_ptime for TSB (from Mike Gemeny) + 09-May-03 RMS Added network device flag + 31-Jan-03 RMS Links are full duplex (found by Mike Gemeny) + + Reference: + - 12875A Processor Interconnect Kit Operating and Service Manual + (12875-90002, Jan-1974) + + + The 12875A Processor Interconnect Kit consists four 12566A Microcircuit + Interface cards. Two are used in each processor. One card in each system is + used to initiate transmissions to the other, and the second card is used to + receive transmissions from the other. Each pair of cards forms a + bidirectional link, as the sixteen data lines are cross-connected, so that + data sent and status returned are supported. In each processor, data is sent + on the lower priority card and received on the higher priority card. Two + sets of cards are used to support simultaneous transmission in both + directions. +*/ + + +#include "hp2100_defs.h" +#include "hp2100_cpu.h" +#include "sim_sock.h" +#include "sim_tmxr.h" + +typedef enum { ipli, iplo } CARD_INDEX; /* card index number */ + +#define CARD_COUNT 2 /* count of cards supported */ + +#define UNIT_V_DIAG (UNIT_V_UF + 0) /* diagnostic mode */ +#define UNIT_V_ACTV (UNIT_V_UF + 1) /* making connection */ +#define UNIT_V_ESTB (UNIT_V_UF + 2) /* connection established */ +#define UNIT_V_HOLD (UNIT_V_UF + 3) /* character holding */ +#define UNIT_DIAG (1 << UNIT_V_DIAG) +#define UNIT_ACTV (1 << UNIT_V_ACTV) +#define UNIT_ESTB (1 << UNIT_V_ESTB) +#define UNIT_HOLD (1 << UNIT_V_HOLD) +#define IBUF buf /* input buffer */ +#define OBUF wait /* output buffer */ +#define DSOCKET u3 /* data socket */ +#define LSOCKET u4 /* listening socket */ + +/* Debug flags */ + +#define DEB_CMDS (1 << 0) /* Command initiation and completion */ +#define DEB_CPU (1 << 1) /* CPU I/O */ +#define DEB_XFER (1 << 2) /* Socket receive and transmit */ + +extern DIB ptr_dib; /* need PTR select code for boot */ + +int32 ipl_edtdelay = 1; /* EDT delay (msec) */ +int32 ipl_ptime = 31; /* polling interval */ +int32 ipl_stopioe = 0; /* stop on error */ + +typedef struct { + FLIP_FLOP control; /* control flip-flop */ + FLIP_FLOP flag; /* flag flip-flop */ + FLIP_FLOP flagbuf; /* flag buffer flip-flop */ + int32 hold; /* holding character */ + } CARD_STATE; + +CARD_STATE ipl [CARD_COUNT]; /* per-card state */ + +IOHANDLER iplio; + +t_stat ipl_svc (UNIT *uptr); +t_stat ipl_reset (DEVICE *dptr); +t_stat ipl_attach (UNIT *uptr, char *cptr); +t_stat ipl_detach (UNIT *uptr); +t_stat ipl_boot (int32 unitno, DEVICE *dptr); +t_stat ipl_dscln (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat ipl_setdiag (UNIT *uptr, int32 val, char *cptr, void *desc); +t_bool ipl_check_conn (UNIT *uptr); + +/* Debug flags table */ + +DEBTAB ipl_deb [] = { + { "CMDS", DEB_CMDS }, + { "CPU", DEB_CPU }, + { "XFER", DEB_XFER }, + { NULL, 0 } + }; + +/* Common structures */ + +DEVICE ipli_dev, iplo_dev; + +static DEVICE *dptrs [] = { &ipli_dev, &iplo_dev }; + + +UNIT ipl_unit [] = { + { UDATA (&ipl_svc, UNIT_ATTABLE, 0) }, + { UDATA (&ipl_svc, UNIT_ATTABLE, 0) } + }; + +#define ipli_unit ipl_unit [ipli] +#define iplo_unit ipl_unit [iplo] + + +DIB ipl_dib [] = { + { &iplio, IPLI, 0 }, + { &iplio, IPLO, 1 } + }; + +#define ipli_dib ipl_dib [ipli] +#define iplo_dib ipl_dib [iplo] + + +/* IPLI data structures + + ipli_dev IPLI device descriptor + ipli_unit IPLI unit descriptor + ipli_reg IPLI register list +*/ + +REG ipli_reg [] = { + { ORDATA (IBUF, ipli_unit.IBUF, 16) }, + { ORDATA (OBUF, ipli_unit.OBUF, 16) }, + { FLDATA (CTL, ipl [ipli].control, 0) }, + { FLDATA (FLG, ipl [ipli].flag, 0) }, + { FLDATA (FBF, ipl [ipli].flagbuf, 0) }, + { ORDATA (HOLD, ipl [ipli].hold, 8) }, + { DRDATA (TIME, ipl_ptime, 24), PV_LEFT }, + { FLDATA (STOP_IOE, ipl_stopioe, 0) }, + { ORDATA (SC, ipli_dib.select_code, 6), REG_HRO }, + { ORDATA (DEVNO, ipli_dib.select_code, 6), REG_HRO }, + { NULL } + }; + +MTAB ipl_mod [] = { + { UNIT_DIAG, UNIT_DIAG, "diagnostic mode", "DIAG", &ipl_setdiag }, + { UNIT_DIAG, 0, "link mode", "LINK", &ipl_setdiag }, + { MTAB_XTD | MTAB_VDV, 0, NULL, "DISCONNECT", + &ipl_dscln, NULL, NULL }, + { MTAB_XTD | MTAB_VDV, 1, "SC", "SC", &hp_setsc, &hp_showsc, &ipli_dev }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &ipli_dev }, + { 0 } + }; + +DEVICE ipli_dev = { + "IPLI", &ipli_unit, ipli_reg, ipl_mod, + 1, 10, 31, 1, 16, 16, + &tmxr_ex, &tmxr_dep, &ipl_reset, + &ipl_boot, &ipl_attach, &ipl_detach, + &ipli_dib, DEV_DISABLE | DEV_DIS | DEV_DEBUG, + 0, ipl_deb, NULL, NULL + }; + +/* IPLO data structures + + iplo_dev IPLO device descriptor + iplo_unit IPLO unit descriptor + iplo_reg IPLO register list +*/ + +REG iplo_reg [] = { + { ORDATA (IBUF, iplo_unit.IBUF, 16) }, + { ORDATA (OBUF, iplo_unit.OBUF, 16) }, + { FLDATA (CTL, ipl [iplo].control, 0) }, + { FLDATA (FLG, ipl [iplo].flag, 0) }, + { FLDATA (FBF, ipl [iplo].flagbuf, 0) }, + { ORDATA (HOLD, ipl [iplo].hold, 8) }, + { DRDATA (TIME, ipl_ptime, 24), PV_LEFT }, + { ORDATA (SC, iplo_dib.select_code, 6), REG_HRO }, + { ORDATA (DEVNO, iplo_dib.select_code, 6), REG_HRO }, + { NULL } + }; + +DEVICE iplo_dev = { + "IPLO", &iplo_unit, iplo_reg, ipl_mod, + 1, 10, 31, 1, 16, 16, + &tmxr_ex, &tmxr_dep, &ipl_reset, + &ipl_boot, &ipl_attach, &ipl_detach, + &iplo_dib, DEV_DISABLE | DEV_DIS | DEV_DEBUG, + 0, ipl_deb, NULL, NULL + }; + + +/* I/O signal handler for the IPLI and IPLO devices. + + In the link mode, the IPLI and IPLO devices are linked via network + connections to the corresponding cards in another CPU instance. In the + diagnostic mode, we simulate the attachment of the interprocessor cable + between IPLI and IPLO in this machine. + + Implementation notes: + + 1. 2000 Access has a race condition that manifests itself by an apparently + normal boot and operational system console but no PLEASE LOG IN response + to terminals connected to the multiplexer. The frequency of occurrence + is higher on multiprocessor host systems, where the SP and IOP instances + may execute concurrently. + + The cause is this code in the SP disc loader source (2883.asm, 7900.asm, + 790X.asm, 79X3.asm, and 79XX.asm): + + LDA SDVTR REQUEST + JSB IOPMA,I DEVICE TABLE + [...] + STC DMAHS,C TURN ON DMA + SFS DMAHS WAIT FOR + JMP *-1 DEVICE TABLE + STC CH2,C SET CORRECT + CLC CH2 FLAG DIRECTION + + The STC/CLC normally would cause a second "request device table" command + to be recognized by the IOP, except that the IOP DMA setup routine + "DMAXF" (in D61.asm) has specified an end-of-block CLC that holds off the + IPL interrupt, and the completion interrupt routine "DMACP" ends with a + STC,C that clears the IPL flag. + + In hardware, the two CPUs are essentially interlocked by the DMA + transfer, and DMA completion interrupts occur almost simultaneously. + Therefore, the STC/CLC in the SP is guaranteed to occur before the STC,C + in the IOP. Under simulation, and especially on multiprocessor hosts, + that guarantee does not hold. If the STC/CLC occurs after the STC,C, + then the IOP starts a second device table DMA transfer, which the SP is + not expecting. The IOP never processes the subsequent "start + timesharing" command, and the muxtiplexer is non-reponsive. + + We employ a workaround that decreases the incidence of the problem: DMA + output completion interrupts are delayed to allow the other SIMH instance + a chance to process its own DMA completion. We do this by processing the + EDT (End Data Transfer) I/O backplane signal and "sleep"ing for a short + time if the transfer was an output transfer to the input channel, i.e., + a data response to the SP. This improves the race condition by delaying + the IOP until the SP has a chance to receive the last word, recognize its + own DMA input completion, drop out of the SFS loop, and execute the + STC/CLC. + + The condition is only improved, and not solved, because "sleep"ing the + IOP doesn't guarantee that the SP will actually execute. It's possible + that a higher-priority host process will preempt the SP, and that at the + sleep expiration, the SP still has not executed the STC/CLC. Still, in + testing, the incidence dropped dramatically, so the problem is much less + intrusive. + + 2. The operating manual for the 12920A Terminal Multiplexer says that "at + least 100 milliseconds of CLC 0s must be programmed" by systems employing + the multiplexer to ensure that the multiplexer resets. In practice, such + systems issue 128K CLC 0 instructions. As we provide debug logging of + IPL resets, a CRS counter is used to ensure that only one debug line is + printed in response to these 128K CRS invocations. + + 3. The STC handler may return "Unit not attached", "I/O error", or "No + connection on interprocessor link" status if the link fails or is + improperly configured. If the error is corrected, the operation may be + retried by resuming simulated execution. +*/ + +uint32 iplio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) +{ +CARD_INDEX card = (CARD_INDEX) dibptr->card_index; /* set card selector */ +UNIT *const uptr = &(ipl_unit [card]); /* associated unit pointer */ +const char *iotype [] = { "Status", "Command" }; +int32 sta; +char msg [2]; +static uint32 crs_count [CARD_COUNT] = { 0, 0 }; /* per-card cntrs for ioCRS repeat */ +IOSIGNAL signal; +IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ + +if (crs_count [card] && !(signal_set & ioCRS)) { /* counting CRSes and not present? */ + if (DEBUG_PRJ (dptrs [card], DEB_CMDS)) /* report reset count */ + fprintf (sim_deb, ">>%s cmds: [CRS] Control cleared %d times\n", + dptrs [card]->name, crs_count [card]); + + crs_count [card] = 0; /* clear counter */ + } + +while (working_set) { + signal = IONEXT (working_set); /* isolate next signal */ + + switch (signal) { /* dispatch I/O signal */ + + case ioCLF: /* clear flag flip-flop */ + ipl [card].flag = ipl [card].flagbuf = CLEAR; + break; + + + case ioSTF: /* set flag flip-flop */ + case ioENF: /* enable flag */ + ipl [card].flag = ipl [card].flagbuf = SET; + break; + + + case ioSFC: /* skip if flag is clear */ + setstdSKF (ipl [card]); + break; + + + case ioSFS: /* skip if flag is set */ + setstdSKF (ipl [card]); + break; + + + case ioIOI: /* I/O data input */ + stat_data = IORETURN (SCPE_OK, uptr->IBUF); /* get return data */ + + if (DEBUG_PRJ (dptrs [card], DEB_CPU)) + fprintf (sim_deb, ">>%s cpu: [LIx] %s = %06o\n", dptrs [card]->name, iotype [card ^ 1], uptr->IBUF); + break; + + + case ioIOO: /* I/O data output */ + uptr->OBUF = IODATA (stat_data); /* clear supplied status */ + + if (DEBUG_PRJ (dptrs [card], DEB_CPU)) + fprintf (sim_deb, ">>%s cpu: [OTx] %s = %06o\n", dptrs [card]->name, iotype [card], uptr->OBUF); + break; + + + case ioPOPIO: /* power-on preset to I/O */ + ipl [card].flag = ipl [card].flagbuf = SET; /* set flag buffer and flag */ + uptr->OBUF = 0; /* clear output buffer */ + break; + + + case ioCRS: /* control reset */ + if (crs_count [card] == 0) /* first reset? */ + ipl [card].control = CLEAR; /* clear control */ + + crs_count [card] = crs_count [card] + 1; /* increment count */ + break; + + + case ioCLC: /* clear control flip-flop */ + ipl [card].control = CLEAR; /* clear ctl */ + + if (DEBUG_PRJ (dptrs [card], DEB_CMDS)) + fprintf (sim_deb, ">>%s cmds: [CLC] Control cleared\n", dptrs [card]->name); + break; + + + case ioSTC: /* set control flip-flop */ + if (DEBUG_PRJ (dptrs [card], DEB_CMDS)) + fprintf (sim_deb, ">>%s cmds: [STC] Control set\n", dptrs [card]->name); + + if (uptr->flags & UNIT_ATT) { /* attached? */ + if (!ipl_check_conn (uptr)) /* not established? */ + return IORETURN (STOP_NOCONN, 0); /* lose */ + + msg [0] = (uptr->OBUF >> 8) & 0377; + msg [1] = uptr->OBUF & 0377; + sta = sim_write_sock (uptr->DSOCKET, msg, 2); + + if (DEBUG_PRJ (dptrs [card], DEB_XFER)) + fprintf (sim_deb, + ">>%s xfer: [STC] Socket write = %06o, status = %d\n", + dptrs [card]->name, uptr->OBUF, sta); + + if (sta == SOCKET_ERROR) { + printf ("IPL socket write error\n"); + return IORETURN (SCPE_IOERR, 0); + } + + ipl [card].control = SET; /* set ctl */ + + sim_os_sleep (0); + } + + else if (uptr->flags & UNIT_DIAG) { /* diagnostic mode? */ + ipl [card].control = SET; /* set ctl */ + ipl_unit [card ^ 1].IBUF = uptr->OBUF; /* output to other */ + iplio ((DIB *) dptrs [card ^ 1]->ctxt, ioENF, 0); /* set other flag */ + } + + else + return IORETURN (SCPE_UNATT, 0); /* lose */ + break; + + + case ioEDT: /* end data transfer */ + if ((cpu_unit.flags & UNIT_IOP) && /* are we the IOP? */ + (signal_set & ioIOO) && /* and doing output? */ + (card == ipli)) { /* on the input card? */ + + if (DEBUG_PRJ (dptrs [card], DEB_CMDS)) + fprintf (sim_deb, + ">>%s cmds: [EDT] Delaying DMA completion interrupt for %d msec\n", + dptrs [card]->name, ipl_edtdelay); + + sim_os_ms_sleep (ipl_edtdelay); /* delay completion */ + } + break; + + + case ioSIR: /* set interrupt request */ + setstdPRL (ipl [card]); + setstdIRQ (ipl [card]); + setstdSRQ (ipl [card]); + break; + + + case ioIAK: /* interrupt acknowledge */ + ipl [card].flagbuf = CLEAR; + break; + + + default: /* all other signals */ + break; /* are ignored */ + } + + working_set = working_set & ~signal; /* remove current signal from set */ + } + +return stat_data; +} + + +/* Unit service - poll for input */ + +t_stat ipl_svc (UNIT *uptr) +{ +CARD_INDEX card; +int32 nb; +char msg [2]; + +if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */ + return SCPE_OK; + +sim_activate (uptr, ipl_ptime); /* reactivate */ + +if (!ipl_check_conn (uptr)) /* check for conn */ + return SCPE_OK; /* not connected */ + +nb = sim_read_sock (uptr->DSOCKET, msg, ((uptr->flags & UNIT_HOLD)? 1: 2)); + +if (nb < 0) { /* connection closed? */ + printf ("IPL socket read error\n"); + return SCPE_IOERR; + } + +else if (nb == 0) /* no data? */ + return SCPE_OK; + +card = (CARD_INDEX) (uptr == &iplo_unit); /* set card selector */ + +if (uptr->flags & UNIT_HOLD) { /* holdover byte? */ + uptr->IBUF = (ipl [card].hold << 8) | (((int32) msg [0]) & 0377); + uptr->flags = uptr->flags & ~UNIT_HOLD; + } +else if (nb == 1) { + ipl [card].hold = ((int32) msg [0]) & 0377; + uptr->flags = uptr->flags | UNIT_HOLD; + } +else + uptr->IBUF = ((((int32) msg [0]) & 0377) << 8) | (((int32) msg [1]) & 0377); + +iplio ((DIB *) dptrs [card]->ctxt, ioENF, 0); /* set flag */ + +if (DEBUG_PRJ (dptrs [card], DEB_XFER)) + fprintf (sim_deb, ">>%s xfer: Socket read = %06o, status = %d\n", + dptrs [card]->name, uptr->IBUF, nb); + +return SCPE_OK; +} + + +t_bool ipl_check_conn (UNIT *uptr) +{ +SOCKET sock; + +if (uptr->flags & UNIT_ESTB) /* established? */ + return TRUE; + +if (uptr->flags & UNIT_ACTV) { /* active connect? */ + if (sim_check_conn (uptr->DSOCKET, 0) <= 0) + return FALSE; + } + +else { + sock = sim_accept_conn (uptr->LSOCKET, NULL); /* poll connect */ + + if (sock == INVALID_SOCKET) /* got a live one? */ + return FALSE; + + uptr->DSOCKET = sock; /* save data socket */ + } + +uptr->flags = uptr->flags | UNIT_ESTB; /* conn established */ +return TRUE; +} + + +/* Reset routine. + + Implementation notes: + + 1. We set up the first poll for socket connections to occur "immediately" + upon execution, so that clients will be connected before execution + begins. Otherwise, a fast program may access the IPL before the poll + service routine activates. +*/ + +t_stat ipl_reset (DEVICE *dptr) +{ +UNIT *uptr = dptr->units; +DIB *dibptr = (DIB *) dptr->ctxt; /* DIB pointer */ +CARD_INDEX card = (CARD_INDEX) dibptr->card_index; /* card number */ + +hp_enbdis_pair (dptr, dptrs [card ^ 1]); /* make pair cons */ + +if (sim_switches & SWMASK ('P')) /* initialization reset? */ + uptr->IBUF = uptr->OBUF = 0; /* clr buffers */ + +IOPRESET (dibptr); /* PRESET device (does not use PON) */ + +if (uptr->flags & UNIT_ATT) /* socket attached? */ + sim_activate (uptr, POLL_FIRST); /* activate first poll "immediately" */ +else + sim_cancel (uptr); /* deactivate unit */ + +uptr->flags = uptr->flags & ~UNIT_HOLD; /* clear holding flag */ +return SCPE_OK; +} + + +/* Attach routine + + attach -l - listen for connection on port + attach -c - connect to ip address and port +*/ + +t_stat ipl_attach (UNIT *uptr, char *cptr) +{ +SOCKET newsock; +uint32 i, t, ipa, ipp, oldf; +char *tptr; +t_stat r; + +r = get_ipaddr (cptr, &ipa, &ipp); +if ((r != SCPE_OK) || (ipp == 0)) + return SCPE_ARG; +oldf = uptr->flags; +if (oldf & UNIT_ATT) + ipl_detach (uptr); +if ((sim_switches & SWMASK ('C')) || + ((sim_switches & SIM_SW_REST) && (oldf & UNIT_ACTV))) { + if (ipa == 0) + ipa = 0x7F000001; + newsock = sim_connect_sock (ipa, ipp); + if (newsock == INVALID_SOCKET) + return SCPE_IOERR; + printf ("Connecting to IP address %d.%d.%d.%d, port %d\n", + (ipa >> 24) & 0xff, (ipa >> 16) & 0xff, + (ipa >> 8) & 0xff, ipa & 0xff, ipp); + if (sim_log) + fprintf (sim_log, + "Connecting to IP address %d.%d.%d.%d, port %d\n", + (ipa >> 24) & 0xff, (ipa >> 16) & 0xff, + (ipa >> 8) & 0xff, ipa & 0xff, ipp); + uptr->flags = uptr->flags | UNIT_ACTV; + uptr->LSOCKET = 0; + uptr->DSOCKET = newsock; + } +else { + if (ipa != 0) + return SCPE_ARG; + newsock = sim_master_sock (ipp); + if (newsock == INVALID_SOCKET) + return SCPE_IOERR; + printf ("Listening on port %d\n", ipp); + if (sim_log) + fprintf (sim_log, "Listening on port %d\n", ipp); + uptr->flags = uptr->flags & ~UNIT_ACTV; + uptr->LSOCKET = newsock; + uptr->DSOCKET = 0; + } +uptr->IBUF = uptr->OBUF = 0; +uptr->flags = (uptr->flags | UNIT_ATT) & ~(UNIT_ESTB | UNIT_HOLD); +tptr = (char *) malloc (strlen (cptr) + 1); /* get string buf */ +if (tptr == NULL) { /* no memory? */ + ipl_detach (uptr); /* close sockets */ + return SCPE_MEM; + } +strcpy (tptr, cptr); /* copy ipaddr:port */ +uptr->filename = tptr; /* save */ +sim_activate (uptr, POLL_FIRST); /* activate first poll "immediately" */ +if (sim_switches & SWMASK ('W')) { /* wait? */ + for (i = 0; i < 30; i++) { /* check for 30 sec */ + t = ipl_check_conn (uptr); + if (t) /* established? */ + break; + if ((i % 10) == 0) /* status every 10 sec */ + printf ("Waiting for connnection\n"); + sim_os_sleep (1); /* sleep 1 sec */ + } + if (t) /* if connected (set by "ipl_check_conn" above) */ + printf ("Connection established\n"); /* then report */ + } +return SCPE_OK; +} + +/* Detach routine */ + +t_stat ipl_detach (UNIT *uptr) +{ +if (!(uptr->flags & UNIT_ATT)) /* attached? */ + return SCPE_OK; + +if (uptr->flags & UNIT_ACTV) + sim_close_sock (uptr->DSOCKET, 1); + +else { + if (uptr->flags & UNIT_ESTB) /* if established, */ + sim_close_sock (uptr->DSOCKET, 0); /* close data socket */ + sim_close_sock (uptr->LSOCKET, 1); /* closen listen socket */ + } + +free (uptr->filename); /* free string */ +uptr->filename = NULL; +uptr->LSOCKET = 0; +uptr->DSOCKET = 0; +uptr->flags = uptr->flags & ~(UNIT_ATT | UNIT_ACTV | UNIT_ESTB); +sim_cancel (uptr); /* don't poll */ +return SCPE_OK; +} + +/* Disconnect routine */ + +t_stat ipl_dscln (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +if (cptr) + return SCPE_ARG; +if (((uptr->flags & UNIT_ATT) == 0) || + (uptr->flags & UNIT_ACTV) || + ((uptr->flags & UNIT_ESTB) == 0)) + return SCPE_NOFNC; +sim_close_sock (uptr->DSOCKET, 0); +uptr->DSOCKET = 0; +uptr->flags = uptr->flags & ~UNIT_ESTB; +return SCPE_OK; +} + +/* Diagnostic/normal mode routine */ + +t_stat ipl_setdiag (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +if (val) { + ipli_unit.flags = ipli_unit.flags | UNIT_DIAG; + iplo_unit.flags = iplo_unit.flags | UNIT_DIAG; + } +else { + ipli_unit.flags = ipli_unit.flags & ~UNIT_DIAG; + iplo_unit.flags = iplo_unit.flags & ~UNIT_DIAG; + } +return SCPE_OK; +} + +/* Interprocessor link bootstrap routine (HP Access Manual) */ + +#define MAX_BASE 073 +#define IPL_PNTR 074 +#define PTR_PNTR 075 +#define IPL_DEVA 076 +#define PTR_DEVA 077 + +static const BOOT_ROM ipl_rom = { + 0163774, /*BBL LDA ICK,I ; IPL sel code */ + 0027751, /* JMP CFG ; go configure */ + 0107700, /*ST CLC 0,C ; intr off */ + 0002702, /* CLA,CCE,SZA ; skip in */ + 0063772, /*CN LDA M26 ; feed frame */ + 0002307, /*EOC CCE,INA,SZA,RSS ; end of file? */ + 0027760, /* JMP EOT ; yes */ + 0017736, /* JSB READ ; get #char */ + 0007307, /* CMB,CCE,INB,SZB,RSS ; 2's comp; null? */ + 0027705, /* JMP EOC ; read next */ + 0077770, /* STB WC ; word in rec */ + 0017736, /* JSB READ ; get feed frame */ + 0017736, /* JSB READ ; get address */ + 0074000, /* STB 0 ; init csum */ + 0077771, /* STB AD ; save addr */ + 0067771, /*CK LDB AD ; check addr */ + 0047773, /* ADB MAXAD ; below loader */ + 0002040, /* SEZ ; E =0 => OK */ + 0102055, /* HLT 55 */ + 0017736, /* JSB READ ; get word */ + 0040001, /* ADA 1 ; cont checksum */ + 0177771, /* STB AD,I ; store word */ + 0037771, /* ISZ AD */ + 0000040, /* CLE ; force wd read */ + 0037770, /* ISZ WC ; block done? */ + 0027717, /* JMP CK ; no */ + 0017736, /* JSB READ ; get checksum */ + 0054000, /* CPB 0 ; ok? */ + 0027704, /* JMP CN ; next block */ + 0102011, /* HLT 11 ; bad csum */ + 0000000, /*RD 0 */ + 0006600, /* CLB,CME ; E reg byte ptr */ + 0103700, /*IO1 STC RDR,C ; start reader */ + 0102300, /*IO2 SFS RDR ; wait */ + 0027741, /* JMP *-1 */ + 0106400, /*IO3 MIB RDR ; get byte */ + 0002041, /* SEZ,RSS ; E set? */ + 0127736, /* JMP RD,I ; no, done */ + 0005767, /* BLF,CLE,BLF ; shift byte */ + 0027740, /* JMP IO1 ; again */ + 0163775, /* LDA PTR,I ; get ptr code */ + 0043765, /*CFG ADA SFS ; config IO */ + 0073741, /* STA IO2 */ + 0043766, /* ADA STC */ + 0073740, /* STA IO1 */ + 0043767, /* ADA MIB */ + 0073743, /* STA IO3 */ + 0027702, /* JMP ST */ + 0063777, /*EOT LDA PSC ; put select codes */ + 0067776, /* LDB ISC ; where xloader wants */ + 0102077, /* HLT 77 */ + 0027702, /* JMP ST */ + 0000000, /* NOP */ + 0102300, /*SFS SFS 0 */ + 0001400, /*STC 1400 */ + 0002500, /*MIB 2500 */ + 0000000, /*WC 0 */ + 0000000, /*AD 0 */ + 0177746, /*M26 -26 */ + 0000000, /*MAX -BBL */ + 0007776, /*ICK ISC */ + 0007777, /*PTR IPT */ + 0000000, /*ISC 0 */ + 0000000 /*IPT 0 */ + }; + +t_stat ipl_boot (int32 unitno, DEVICE *dptr) +{ +const int32 devi = ipli_dib.select_code; +const int32 devp = ptr_dib.select_code; + +if (ibl_copy (ipl_rom, devi, IBL_S_CLR, /* copy the boot ROM to memory and configure */ + IBL_SET_SC (devi) | devp)) /* the S register accordingly */ + return SCPE_IERR; /* return an internal error if the copy failed */ + +WritePW (PC + MAX_BASE, (~PC + 1) & DMASK); /* fix ups */ +WritePW (PC + IPL_PNTR, ipl_rom [IPL_PNTR] | PC); +WritePW (PC + PTR_PNTR, ipl_rom [PTR_PNTR] | PC); +WritePW (PC + IPL_DEVA, devi); +WritePW (PC + PTR_DEVA, devp); +return SCPE_OK; +} diff --git a/HP2100/hp2100_mpx.c b/HP2100/hp2100_mpx.c index a4d91dd9..f8b2b1f5 100644 --- a/HP2100/hp2100_mpx.c +++ b/HP2100/hp2100_mpx.c @@ -1,2690 +1,2704 @@ -/* hp2100_mpx.c: HP 12792C eight-channel asynchronous multiplexer simulator - - Copyright (c) 2008-2012, J. David Bryan - - 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 - THE AUTHOR 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 the author shall not be - used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from the author. - - MPX 12792C 8-channel multiplexer card - - 10-Feb-12 JDB Deprecated DEVNO in favor of SC - 28-Mar-11 JDB Tidied up signal handling - 26-Oct-10 JDB Changed I/O signal handler for revised signal model - 25-Nov-08 JDB Revised for new multiplexer library SHOW routines - 14-Nov-08 JDB Cleaned up VC++ size mismatch warnings for zero assignments - 03-Oct-08 JDB Fixed logic for ENQ/XOFF transmit wait - 07-Sep-08 JDB Changed Telnet poll to connect immediately after reset or attach - 10-Aug-08 JDB Added REG_FIT to register variables < 32-bit size - 26-Jun-08 JDB Rewrote device I/O to model backplane signals - 26-May-08 JDB Created MPX device - - References: - - HP 12792B 8-Channel Asynchronous Multiplexer Subsystem Installation and - Reference Manual (12792-90020, Jul-1984) - - HP 12792B/C 8-Channel Asynchronous Multiplexer Subsystem User's Manual - (5955-8867, Jun-1993) - - HP 12792B/C 8-Channel Asynchronous Multiplexer Subsystem Configuration Guide - (5955-8868, Jun-1993) - - HP 1000 series 8-channel Multiplexer Firmware External Reference Specification - (October 19, 1982) - - HP 12792/12040 Multiplexer Firmware Source (24999-18312, revision C) - - Zilog Components Data Book (00-2034-04, 1985) - - - The 12792A/B/C/D was an eight-line asynchronous serial multiplexer that - connected terminals, modems, serial line printers, and "black box" devices - that used the RS-232 standard to the CPU. It used an on-board microprocessor - and provided input and output buffering to support block-mode reads from HP - 264x and 262x terminals at speeds up to 19.2K baud. The card handled - character editing, echoing, ENQ/ACK handshaking, and read terminator - detection, substantially reducing the load on the CPU over the earlier 12920 - multiplexer. It was supported by HP under RTE-MIII, RTE-IVB, and RTE-6/VM. - Under simulation, it connects with HP terminal emulators via Telnet to a - user-specified port. - - The single interface card contained a Z80 CPU, DMA controller, CTC, four - two-channel SIO UARTs, 16K of RAM, 8K of ROM, and I/O backplane latches and - control circuitry. The card executed a high-level command set, and data - transfer to and from the CPU was via the on-board DMA controller and the DCPC - in the CPU. - - The 12792 for the M/E/F series and the 12040 multiplexer for the A/L series - differed only in backplane design. Early ROMs were card-specific, but later - ones were interchangeable; the code would determine whether it was executing - on an MEF card or an AL card. - - Four major firmware revisions were made. These were labelled "A", "B", "C", - and "D". The A, B, and C revisions were interchangeable from the perspective - of the OS driver; the D was different and required an updated driver. - Specifically: - - Op. Sys. Driver Part Number Rev - -------- ------ -------------------- --- - RTE-MIII DVM00 12792-16002 Rev.2032 A - RTE-IVB DVM00 12792-16002 Rev.5000 ABC - - RTE-6/VM DVM00 12792-16002 Rev.5000 ABC - RTE-6/VM DV800 92084-15068 Rev.6000 D - - RTE-A IDM00 92077-16754 Rev.5020 ABC - RTE-A ID800 92077-16887 Rev.6200 D - - Revisions A-C have an upward-compatible command set that partitions each OS - request into several sub-commands. Each command is initiated by setting the - control flip-flop on the card, which causes a non-maskable interrupt (NMI) on - the card's Z80 processor. - - The D-revision firmware uses a completely different command set. The - commands are slightly modified versions of the original EXEC calls (read, - write, and control) and are generally passed to the card directly for action. - - This simulation supports the C revision. D-revision support may be added - later. - - Twelve programmable baud rates are supported by the multiplexer. These - "realistic" rates are simulated by scheduling I/O service based on the - appropriate number of 1000 E-Series instructions for the rate selected. - - The simulation provides both the "realistic timing" described above, as well - as an optimized "fast timing" option. Optimization makes three improvements: - - 1. Buffered characters are transferred in blocks. - - 2. ENQ/ACK handshaking is done locally without involving the client. - - 3. BS and DEL respond visually more like prior RTE terminal drivers. - - HP did not offer a functional diagnostic for the 12792. Instead, a Z80 - program that tested the operation of the hardware was downloaded to the card, - and a "go/no-go" status was returned to indicate the hardware condition. - Because this is a functional simulation of the multiplexer and not a Z80 - emulation, the diagnostic cannot be used to test the implementation. - - Implementation notes: - - 1. The 12792 had two baud-rate generators that were assigned to lines by the - wiring configuration in the I/O cable connector hood. Two of the four - CTC counters were used to implement the BRGs for all eight lines. Only - subsets of the configurable rates were allowed for lines connected to the - same BRG, and assigning mutually incompatible rates caused corruption of - the rates on lines assigned earlier. Under simulation, any baud rate may - be assigned to any line without interaction, and assignments of lines to - BRGs is not implemented. - - 2. Revisions B and C added support for the 37214A Systems Modem subsystem - and the RTE-A Virtual Control Panel (VCP). Under simulation, the modem - commands return status codes indicating that no modems are present, and - the VCP commands are not implemented. -*/ - - -#include - -#include "hp2100_defs.h" -#include "sim_sock.h" -#include "sim_tmxr.h" - - -/* Bitfield constructor. - - Given a bitfield starting bit number and width in bits, declare two - constants: one for the starting bit number, and one for the positioned field - mask. That is, given a definition such as: - - BITFIELD(SMALLFIELD,5,2) - - ...this macro produces: - - static const uint32 SMALLFIELD_V = 5; - static const uint32 SMALLFIELD = ((1 << (2)) - 1) << (5); - - The latter reduces to 3 << 5, or 0x00000060. - - Note: C requires constant expressions in initializers for objects with static - storage duration, so initializing a static object with a BITFIELD value is - illegal (a "static const" object is not a constant!). -*/ - -#define BITFIELD(NAME,STARTBIT,BITWIDTH) \ - static const uint32 NAME ## _V = STARTBIT; \ - static const uint32 NAME = ((1 << (BITWIDTH)) - 1) << (STARTBIT); - - -/* Program constants */ - -#define MPX_DATE_CODE 2416 /* date code for C firmware */ - -#define RD_BUF_SIZE 514 /* read buffer size */ -#define WR_BUF_SIZE 514 /* write buffer size */ - -#define RD_BUF_LIMIT 254 /* read buffer limit */ -#define WR_BUF_LIMIT 254 /* write buffer limit */ - -#define KEY_DEFAULT 255 /* default port key */ - - -/* Service times: - - DATA_DELAY = 1.25 us (Z80 DMA data word transfer time) - PARAM_DELAY = 25 us (STC to STF for first word of two-word command) - CMD_DELAY = 400 us (STC to STF for one or two-word command execution) -*/ - -#define DATA_DELAY 2 /* data transfer time */ -#define PARAM_DELAY 40 /* parameter request time */ -#define CMD_DELAY 630 /* command completion time */ - - -/* Unit references */ - -#define MPX_PORTS 8 /* number of visible units */ -#define MPX_CNTLS 2 /* number of control units */ - -#define mpx_cntl (mpx_unit [MPX_PORTS + 0]) /* controller unit */ -#define mpx_poll (mpx_unit [MPX_PORTS + 1]) /* Telnet polling unit */ - - -/* Character constants */ - -#define EOT '\004' -#define ENQ '\005' -#define ACK '\006' -#define BS '\010' -#define LF '\012' -#define CR '\015' -#define DC1 '\021' -#define DC2 '\022' -#define DC3 '\023' -#define ESC '\033' -#define RS '\036' -#define DEL '\177' - -#define XON DC1 -#define XOFF DC3 - - -/* Device flags */ - -#define DEV_V_REV_D (DEV_V_UF + 0) /* firmware revision D (not implemented) */ - -#define DEV_REV_D (1 << DEV_V_REV_D) - - -/* Unit flags */ - -#define UNIT_V_FASTTIME (UNIT_V_UF + 0) /* fast timing mode */ -#define UNIT_V_CAPSLOCK (UNIT_V_UF + 1) /* caps lock mode */ - -#define UNIT_FASTTIME (1 << UNIT_V_FASTTIME) -#define UNIT_CAPSLOCK (1 << UNIT_V_CAPSLOCK) - - -/* Debug flags */ - -#define DEB_CMDS (1 << 0) /* commands and status */ -#define DEB_CPU (1 << 1) /* CPU I/O */ -#define DEB_BUF (1 << 2) /* buffer gets and puts */ -#define DEB_XFER (1 << 3) /* character reads and writes */ - - -/* Multiplexer commands for revisions A/B/C. - - Commands are either one or two words in length. The one-word format is: - - +-------------------------------+-------------------------------+ - | 0 . 1 | command opcode | command parameter | - +-------------------------------+-------------------------------+ - 15 - 8 7 - 0 - - The two-word format is: - - +-------------------------------+-------------------------------+ - | 1 . 1 | command opcode | command value | - +-------------------------------+-------------------------------+ - | command parameter | - +---------------------------------------------------------------+ - 15 - 8 7 - 0 - - Commands implemented by firmware revision: - - Rev Cmd Value Operation Status Value(s) Returned - --- --- ----- ------------------------------- ------------------------------- - ABC 100 - No operation 000000 - ABC 101 - Reset to power-on defaults 100000 - ABC 102 - Enable unsolicited input None, unless UI pending - ABC 103 1 Disable unsolicited interrupts 000000 - ABC 103 2 Abort DMA transfer 000000 - ABC 104 - Acknowledge Second word of UI status - ABC 105 key Cancel first receive buffer 000000 - ABC 106 key Cancel all received buffers 000000 - ABC 107 - Fast binary read (none) - - -BC 140 chr VCP put byte 000000 - -BC 141 - VCP put buffer 000000 - -BC 142 - VCP get byte Character from port 0 - -BC 143 - VCP get buffer 000120 - -BC 144 - Exit VCP mode 000000 - -BC 157 - Enter VCP mode 000000 - - ABC 300 - No operation 000000 - ABC 301 key Request write buffer 000000 or 000376 - ABC 302 key Write data to buffer (none) - ABC 303 key Set port key 000000 or date code of firmware - ABC 304 key Set receive type 000000 - ABC 305 key Set character count 000000 - ABC 306 key Set flow control 000000 - ABC 307 key Read data from buffer (none) - ABC 310 - Download executable (none) - - -BC 311 key Connect line 000000 or 140000 if no modem - -BC 312 key Disconnect line 000000 or 140000 if no modem - -BC 315 key Get modem/port status modem status or 000200 if no modem - -BC 316 key Enable/disable modem loopback 000000 or 140000 if no modem - -BC 320 key Terminate active receive buffer 000000 -*/ - - -/* One-word command codes */ - -#define CMD_NOP 0100 /* No operation */ -#define CMD_RESET 0101 /* Reset firmware to power-on defaults */ -#define CMD_ENABLE_UI 0102 /* Enable unsolicited input */ -#define CMD_DISABLE 0103 /* Disable interrupts / Abort DMA Transfer */ -#define CMD_ACK 0104 /* Acknowledge */ -#define CMD_CANCEL 0105 /* Cancel first receive buffer */ -#define CMD_CANCEL_ALL 0106 /* Cancel all received buffers */ -#define CMD_BINARY_READ 0107 /* Fast binary read */ - -#define CMD_VCP_PUT 0140 /* VCP put byte */ -#define CMD_VCP_PUT_BUF 0141 /* VCP put buffer */ -#define CMD_VCP_GET 0142 /* VCP get byte */ -#define CMD_VCP_GET_BUF 0143 /* VCP get buffer */ -#define CMD_VCP_EXIT 0144 /* Exit VCP mode */ -#define CMD_VCP_ENTER 0157 /* Enter VCP mode */ - - -/* Two-word command codes */ - -#define CMD_REQ_WRITE 0301 /* Request write buffer */ -#define CMD_WRITE 0302 /* Write data to buffer */ -#define CMD_SET_KEY 0303 /* Set port key */ -#define CMD_SET_RCV 0304 /* Set receive type */ -#define CMD_SET_COUNT 0305 /* Set character count */ -#define CMD_SET_FLOW 0306 /* Set flow control */ -#define CMD_READ 0307 /* Read data from buffer */ -#define CMD_DL_EXEC 0310 /* Download executable */ - -#define CMD_CN_LINE 0311 /* Connect line */ -#define CMD_DC_LINE 0312 /* Disconnect line */ -#define CMD_GET_STATUS 0315 /* Get modem/port status */ -#define CMD_LOOPBACK 0316 /* Enable/disable modem loopback */ -#define CMD_TERM_BUF 0320 /* Terminate active receive buffer */ - - -/* Sub-command codes */ - -#define SUBCMD_UI 1 /* Disable unsolicited interrupts */ -#define SUBCMD_DMA 2 /* Abort DMA transfer */ - -#define CMD_TWO_WORDS 0200 /* two-word command flag */ - - -/* Unsolicited interrupt reasons */ - -#define UI_REASON_V 8 /* interrupt reason */ -#define UI_REASON (((1 << 8) - 1) << (UI_REASON_V)) /* (UI_REASON_V must be a constant!) */ - -BITFIELD (UI_PORT, 0, 3) /* interrupt port number */ - -#define UI_WRBUF_AVAIL (1 << UI_REASON_V) /* Write buffer available */ -#define UI_LINE_CONN (2 << UI_REASON_V) /* Modem line connected */ -#define UI_LINE_DISC (3 << UI_REASON_V) /* Modem line disconnected */ -#define UI_BRK_RECD (4 << UI_REASON_V) /* Break received */ -#define UI_RDBUF_AVAIL (5 << UI_REASON_V) /* Read buffer available */ - - -/* Return status to CPU */ - -#define ST_OK 0000000 /* Command OK */ -#define ST_DIAG_OK 0000015 /* Diagnostic passes */ -#define ST_VCP_SIZE 0000120 /* VCP buffer size = 80 chars */ -#define ST_NO_SYSMDM 0000200 /* No systems modem card */ -#define ST_TEST_OK 0100000 /* Self test OK */ -#define ST_NO_MODEM 0140000 /* No modem card on port */ -#define ST_BAD_KEY 0135320 /* Bad port key = 0xBAD0 */ - - -/* Bit flags */ - -#define RS_OVERFLOW 0040000 /* Receive status: buffer overflow occurred */ -#define RS_PARTIAL 0020000 /* Receive status: buffer is partial */ -#define RS_ETC_RS 0014000 /* Receive status: terminated by RS */ -#define RS_ETC_DC2 0010000 /* Receive status: terminated by DC2 */ -#define RS_ETC_CR 0004000 /* Receive status: terminated by CR */ -#define RS_ETC_EOT 0000000 /* Receive status: terminated by EOT */ -#define RS_CHAR_COUNT 0003777 /* Receive status: character count */ - -#define WR_NO_ENQACK 0020000 /* Write: no ENQ/ACK this xfer */ -#define WR_ADD_CRLF 0010000 /* Write: add CR/LF if not '_' */ -#define WR_PARTIAL 0004000 /* Write: write is partial */ -#define WR_LENGTH 0003777 /* Write: write length in bytes */ - -#define RT_END_ON_CR 0000200 /* Receive type: end xfer on CR */ -#define RT_END_ON_RS 0000100 /* Receive type: end xfer on RS */ -#define RT_END_ON_EOT 0000040 /* Receive type: end xfer on EOT */ -#define RT_END_ON_DC2 0000020 /* Receive type: end xfer on DC2 */ -#define RT_END_ON_CNT 0000010 /* Receive type: end xfer on count */ -#define RT_END_ON_CHAR 0000004 /* Receive type: end xfer on character */ -#define RT_ENAB_EDIT 0000002 /* Receive type: enable input editing */ -#define RT_ENAB_ECHO 0000001 /* Receive type: enable input echoing */ - -#define FC_FORCE_XON 0000002 /* Flow control: force XON */ -#define FC_XONXOFF 0000001 /* Flow control: enable XON/XOFF */ - -#define CL_GUARD 0000040 /* Connect line: guard tone off or on */ -#define CL_STANDARD 0000020 /* Connect line: standard 212 or V.22 */ -#define CL_BITS 0000010 /* Connect line: bits 10 or 9 */ -#define CL_MODE 0000004 /* Connect line: mode originate or answer */ -#define CL_DIAL 0000002 /* Connect line: dial manual or automatic */ -#define CL_SPEED 0000001 /* Connect line: speed low or high */ - -#define DL_AUTO_ANSWER 0000001 /* Disconnect line: auto-answer enable or disable */ - -#define LB_SPEED 0000004 /* Loopback test: speed low or high */ -#define LB_MODE 0000002 /* Loopback test: mode analog or digital */ -#define LB_TEST 0000001 /* Loopback test: test disable or enable */ - -#define GS_NO_SYSMDM 0000200 /* Get status: systems modem present or absent */ -#define GS_SYSMDM_TO 0000100 /* Get status: systems modem OK or timed out */ -#define GS_NO_MODEM 0000040 /* Get status: modem present or absent */ -#define GS_SPEED 0000020 /* Get status: speed low or high */ -#define GS_LINE 0000001 /* Get status: line disconnected or connected */ - - -/* Bit fields (name, starting bit, bit width) */ - -BITFIELD (CMD_OPCODE, 8, 8) /* Command: opcode */ -BITFIELD (CMD_KEY, 0, 8) /* Command: key */ - -BITFIELD (SK_BPC, 14, 2) /* Set key: bits per character */ -BITFIELD (SK_MODEM, 13, 1) /* Set key: hardwired or modem */ -BITFIELD (SK_BRG, 12, 1) /* Set key: baud rate generator 0/1 */ -BITFIELD (SK_STOPBITS, 10, 2) /* Set key: stop bits */ -BITFIELD (SK_PARITY, 8, 2) /* Set key: parity select */ -BITFIELD (SK_ENQACK, 7, 1) /* Set key: disable or enable ENQ/ACK */ -BITFIELD (SK_BAUDRATE, 3, 4) /* Set key: port baud rate */ -BITFIELD (SK_PORT, 0, 3) /* Set key: port number */ - -BITFIELD (FL_ALERT, 11, 1) /* Port flags: alert for terminate recv buffer */ -BITFIELD (FL_XOFF, 10, 1) /* Port flags: XOFF stopped transmission */ -BITFIELD (FL_BREAK, 9, 1) /* Port flags: UI / break detected */ -BITFIELD (FL_HAVEBUF, 8, 1) /* Port flags: UI / read buffer available */ -BITFIELD (FL_WANTBUF, 7, 1) /* Port flags: UI / write buffer available */ -BITFIELD (FL_RDOVFLOW, 6, 1) /* Port flags: read buffers overflowed */ -BITFIELD (FL_RDFILL, 5, 1) /* Port flags: read buffer is filling */ -BITFIELD (FL_RDEMPT, 4, 1) /* Port flags: read buffer is emptying */ -BITFIELD (FL_WRFILL, 3, 1) /* Port flags: write buffer is filling */ -BITFIELD (FL_WREMPT, 2, 1) /* Port flags: write buffer is emptying */ -BITFIELD (FL_WAITACK, 1, 1) /* Port flags: ENQ sent, waiting for ACK */ -BITFIELD (FL_DO_ENQACK, 0, 1) /* Port flags: do ENQ/ACK handshake */ - -#define SK_BRG_1 SK_BRG -#define SK_BRG_0 0 - -#define FL_RDFLAGS (FL_RDEMPT | FL_RDFILL | FL_RDOVFLOW) -#define FL_WRFLAGS (FL_WREMPT | FL_WRFILL) -#define FL_UI_PENDING (FL_WANTBUF | FL_HAVEBUF | FL_BREAK) - -#define ACK_LIMIT 1000 /* poll timeout for ACK response */ -#define ENQ_LIMIT 80 /* output chars before ENQ */ - - -/* Packed field values */ - -#define SK_BPC_5 (0 << SK_BPC_V) -#define SK_BPC_6 (1 << SK_BPC_V) -#define SK_BPC_7 (2 << SK_BPC_V) -#define SK_BPC_8 (3 << SK_BPC_V) - -#define SK_STOP_1 (1 << SK_STOPBITS_V) -#define SK_STOP_15 (2 << SK_STOPBITS_V) -#define SK_STOP_2 (3 << SK_STOPBITS_V) - -#define SK_BAUD_NOCHG (0 << SK_BAUDRATE_V) -#define SK_BAUD_50 (1 << SK_BAUDRATE_V) -#define SK_BAUD_75 (2 << SK_BAUDRATE_V) -#define SK_BAUD_110 (3 << SK_BAUDRATE_V) -#define SK_BAUD_1345 (4 << SK_BAUDRATE_V) -#define SK_BAUD_150 (5 << SK_BAUDRATE_V) -#define SK_BAUD_300 (6 << SK_BAUDRATE_V) -#define SK_BAUD_1200 (7 << SK_BAUDRATE_V) -#define SK_BAUD_1800 (8 << SK_BAUDRATE_V) -#define SK_BAUD_2400 (9 << SK_BAUDRATE_V) -#define SK_BAUD_4800 (10 << SK_BAUDRATE_V) -#define SK_BAUD_9600 (11 << SK_BAUDRATE_V) -#define SK_BAUD_19200 (12 << SK_BAUDRATE_V) - - -/* Default values */ - -#define SK_PWRUP_0 (SK_BPC_8 | SK_BRG_0 | SK_STOP_1 | SK_BAUD_9600) -#define SK_PWRUP_1 (SK_BPC_8 | SK_BRG_1 | SK_STOP_1 | SK_BAUD_9600) - -#define RT_PWRUP (RT_END_ON_CR | RT_END_ON_CHAR | RT_ENAB_EDIT | RT_ENAB_ECHO) - - -/* Command helpers */ - -#define GET_OPCODE(w) (((w) & CMD_OPCODE) >> CMD_OPCODE_V) -#define GET_KEY(w) (((w) & CMD_KEY) >> CMD_KEY_V) -#define GET_BPC(w) (((w) & SK_BPC) >> SK_BPC_V) -#define GET_BAUDRATE(w) (((w) & SK_BAUDRATE) >> SK_BAUDRATE_V) -#define GET_PORT(w) (((w) & SK_PORT) >> SK_PORT_V) -#define GET_UIREASON(w) (((w) & UI_REASON) >> UI_REASON_V) -#define GET_UIPORT(w) (((w) & UI_PORT) >> UI_PORT_V) - - -/* Multiplexer controller state variables */ - -typedef enum { idle, cmd, param, exec } STATE; - -STATE mpx_state = idle; /* controller state */ - -uint16 mpx_ibuf = 0; /* status/data in */ -uint16 mpx_obuf = 0; /* command/data out */ - -uint32 mpx_cmd = 0; /* current command */ -uint32 mpx_param = 0; /* current parameter */ -uint32 mpx_port = 0; /* current port number for R/W */ -uint32 mpx_portkey = 0; /* current port's key */ - int32 mpx_iolen = 0; /* length of current I/O xfer */ - -t_bool mpx_uien = FALSE; /* unsolicited interrupts enabled */ -uint32 mpx_uicode = 0; /* unsolicited interrupt reason and port */ - -struct { - FLIP_FLOP control; /* control flip-flop */ - FLIP_FLOP flag; /* flag flip-flop */ - FLIP_FLOP flagbuf; /* flag buffer flip-flop */ - } mpx = { CLEAR, CLEAR, CLEAR }; - -/* Multiplexer per-line state variables */ - -uint8 mpx_key [MPX_PORTS]; /* port keys */ -uint16 mpx_config [MPX_PORTS]; /* port configuration */ -uint16 mpx_rcvtype [MPX_PORTS]; /* receive type */ -uint16 mpx_charcnt [MPX_PORTS]; /* character count */ -uint16 mpx_flowcntl [MPX_PORTS]; /* flow control */ -uint8 mpx_enq_cntr [MPX_PORTS]; /* ENQ character counter */ -uint16 mpx_ack_wait [MPX_PORTS]; /* ACK wait timer */ -uint16 mpx_flags [MPX_PORTS]; /* line state flags */ - -/* Multiplexer buffer selectors */ - -typedef enum { ioread, iowrite } IO_OPER; /* I/O operation */ -typedef enum { get, put } BUF_SELECT; /* buffer selector */ - -static const char *const io_op [] = { "read", /* operation names */ - "write" }; - -static const uint32 buf_size [] = { RD_BUF_SIZE, /* buffer sizes */ - WR_BUF_SIZE }; - -static uint32 emptying_flags [2]; /* buffer emptying flags [IO_OPER] */ -static uint32 filling_flags [2]; /* buffer filling flags [IO_OPER] */ - - -/* Multiplexer per-line buffer variables */ - -typedef uint16 BUF_INDEX [MPX_PORTS] [2]; /* buffer index (read and write) */ - -BUF_INDEX mpx_put; /* read/write buffer add index */ -BUF_INDEX mpx_sep; /* read/write buffer separator index */ -BUF_INDEX mpx_get; /* read/write buffer remove index */ - -uint8 mpx_rbuf [MPX_PORTS] [RD_BUF_SIZE]; /* read buffer */ -uint8 mpx_wbuf [MPX_PORTS] [WR_BUF_SIZE]; /* write buffer */ - - -/* Multiplexer local routines */ - -static t_bool exec_command (void); -static void poll_connection (void); -static void controller_reset (void); -static uint32 service_time (uint16 control_word); -static int32 key_to_port (uint32 key); - -static void buf_init (IO_OPER rw, uint32 port); -static uint8 buf_get (IO_OPER rw, uint32 port); -static void buf_put (IO_OPER rw, uint32 port, uint8 ch); -static void buf_remove (IO_OPER rw, uint32 port); -static void buf_term (IO_OPER rw, uint32 port, uint8 header); -static void buf_free (IO_OPER rw, uint32 port); -static void buf_cancel (IO_OPER rw, uint32 port, BUF_SELECT which); -static uint32 buf_len (IO_OPER rw, uint32 port, BUF_SELECT which); -static uint32 buf_avail (IO_OPER rw, uint32 port); - - -/* Multiplexer global routines */ - -IOHANDLER mpx_io; - -t_stat mpx_line_svc (UNIT *uptr); -t_stat mpx_cntl_svc (UNIT *uptr); -t_stat mpx_poll_svc (UNIT *uptr); -t_stat mpx_reset (DEVICE *dptr); -t_stat mpx_attach (UNIT *uptr, char *cptr); -t_stat mpx_detach (UNIT *uptr); -t_stat mpx_status (FILE *st, UNIT *uptr, int32 val, void *desc); -t_stat mpx_set_frev (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat mpx_show_frev (FILE *st, UNIT *uptr, int32 val, void *desc); - - -/* MPX data structures. - - mpx_order MPX line connection order table - mpx_ldsc MPX terminal multiplexer line descriptors - mpx_desc MPX terminal multiplexer device descriptor - mpx_dib MPX device information block - mpx_unit MPX unit list - mpx_reg MPX register list - mpx_mod MPX modifier list - mpx_deb MPX debug list - mpx_dev MPX device descriptor - - The first eight units correspond to the eight multiplexer line ports. These - handle character I/O via the Telnet library. A ninth unit acts as the card - controller, executing commands and transferring data to and from the I/O - buffers. A tenth unit is responsible for polling for connections and socket - I/O. It also holds the master socket. - - The character I/O service routines run only when there are characters to read - or write. They operate at the approximate baud rates of the terminals (in - CPU instructions per second) in order to be compatible with the OS drivers. - The controller service routine runs only when a command is executing or a - data transfer to or from the CPU is in progress. The Telnet poll must run - continuously, but it may operate much more slowly, as the only requirement is - that it must not present a perceptible lag to human input. To be compatible - with CPU idling, it is co-scheduled with the master poll timer, which uses a - ten millisecond period. - - The controller and poll units are hidden by disabling them, so as to present - a logical picture of the multiplexer to the user. -*/ - -DEVICE mpx_dev; - -int32 mpx_order [MPX_PORTS] = { -1 }; /* connection order */ -TMLN mpx_ldsc [MPX_PORTS] = { { 0 } }; /* line descriptors */ -TMXR mpx_desc = { MPX_PORTS, 0, 0, mpx_ldsc, mpx_order }; /* device descriptor */ - -DIB mpx_dib = { &mpx_io, MPX }; - -UNIT mpx_unit [] = { - { UDATA (&mpx_line_svc, UNIT_FASTTIME, 0) }, /* terminal I/O line 0 */ - { UDATA (&mpx_line_svc, UNIT_FASTTIME, 0) }, /* terminal I/O line 1 */ - { UDATA (&mpx_line_svc, UNIT_FASTTIME, 0) }, /* terminal I/O line 2 */ - { UDATA (&mpx_line_svc, UNIT_FASTTIME, 0) }, /* terminal I/O line 3 */ - { UDATA (&mpx_line_svc, UNIT_FASTTIME, 0) }, /* terminal I/O line 4 */ - { UDATA (&mpx_line_svc, UNIT_FASTTIME, 0) }, /* terminal I/O line 5 */ - { UDATA (&mpx_line_svc, UNIT_FASTTIME, 0) }, /* terminal I/O line 6 */ - { UDATA (&mpx_line_svc, UNIT_FASTTIME, 0) }, /* terminal I/O line 7 */ - { UDATA (&mpx_cntl_svc, UNIT_DIS, 0) }, /* controller unit */ - { UDATA (&mpx_poll_svc, UNIT_ATTABLE | UNIT_DIS, POLL_FIRST) } /* Telnet poll unit */ - }; - -REG mpx_reg [] = { - { DRDATA (STATE, mpx_state, 3) }, - { ORDATA (IBUF, mpx_ibuf, 16), REG_FIT }, - { ORDATA (OBUF, mpx_obuf, 16), REG_FIT }, - - { ORDATA (CMD, mpx_cmd, 8) }, - { ORDATA (PARAM, mpx_param, 16) }, - - { DRDATA (PORT, mpx_port, 8), PV_LEFT }, - { DRDATA (PORTKEY, mpx_portkey, 8), PV_LEFT }, - { DRDATA (IOLEN, mpx_iolen, 16), PV_LEFT }, - - { FLDATA (UIEN, mpx_uien, 0) }, - { GRDATA (UIPORT, mpx_uicode, 10, 3, 0) }, - { GRDATA (UICODE, mpx_uicode, 10, 3, UI_REASON_V) }, - - { BRDATA (KEYS, mpx_key, 10, 8, MPX_PORTS) }, - { BRDATA (PCONFIG, mpx_config, 8, 16, MPX_PORTS) }, - { BRDATA (RCVTYPE, mpx_rcvtype, 8, 16, MPX_PORTS) }, - { BRDATA (CHARCNT, mpx_charcnt, 8, 16, MPX_PORTS) }, - { BRDATA (FLOWCNTL, mpx_flowcntl, 8, 16, MPX_PORTS) }, - - { BRDATA (ENQCNTR, mpx_enq_cntr, 10, 7, MPX_PORTS) }, - { BRDATA (ACKWAIT, mpx_ack_wait, 10, 10, MPX_PORTS) }, - { BRDATA (PFLAGS, mpx_flags, 2, 12, MPX_PORTS) }, - - { BRDATA (RBUF, mpx_rbuf, 8, 8, MPX_PORTS * RD_BUF_SIZE) }, - { BRDATA (WBUF, mpx_wbuf, 8, 8, MPX_PORTS * WR_BUF_SIZE) }, - - { BRDATA (GET, mpx_get, 10, 10, MPX_PORTS * 2) }, - { BRDATA (SEP, mpx_sep, 10, 10, MPX_PORTS * 2) }, - { BRDATA (PUT, mpx_put, 10, 10, MPX_PORTS * 2) }, - - { FLDATA (CTL, mpx.control, 0) }, - { FLDATA (FLG, mpx.flag, 0) }, - { FLDATA (FBF, mpx.flagbuf, 0) }, - { ORDATA (SC, mpx_dib.select_code, 6), REG_HRO }, - { ORDATA (DEVNO, mpx_dib.select_code, 6), REG_HRO }, - - { BRDATA (CONNORD, mpx_order, 10, 32, MPX_PORTS), REG_HRO }, - { NULL } - }; - -MTAB mpx_mod [] = { - { UNIT_FASTTIME, UNIT_FASTTIME, "fast timing", "FASTTIME", NULL, NULL, NULL }, - { UNIT_FASTTIME, 0, "realistic timing", "REALTIME", NULL, NULL, NULL }, - - { UNIT_CAPSLOCK, UNIT_CAPSLOCK, "CAPS LOCK down", "CAPSLOCK", NULL, NULL, NULL }, - { UNIT_CAPSLOCK, 0, "CAPS LOCK up", "NOCAPSLOCK", NULL, NULL, NULL }, - - { MTAB_XTD | MTAB_VDV, 0, "REV", NULL, &mpx_set_frev, &mpx_show_frev, NULL }, - { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "LINEORDER", "LINEORDER", &tmxr_set_lnorder, &tmxr_show_lnorder, &mpx_desc }, - - { MTAB_XTD | MTAB_VUN | MTAB_NC, 0, "LOG", "LOG", &tmxr_set_log, &tmxr_show_log, &mpx_desc }, - { MTAB_XTD | MTAB_VUN | MTAB_NC, 0, NULL, "NOLOG", &tmxr_set_nolog, NULL, &mpx_desc }, - - { MTAB_XTD | MTAB_VDV, 0, "", NULL, NULL, &mpx_status, &mpx_desc }, - { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "CONNECTIONS", NULL, NULL, &tmxr_show_cstat, &mpx_desc }, - { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "STATISTICS", NULL, NULL, &tmxr_show_cstat, &mpx_desc }, - { MTAB_XTD | MTAB_VDV, 1, NULL, "DISCONNECT", &tmxr_dscln, NULL, &mpx_desc }, - { MTAB_XTD | MTAB_VDV, 0, "SC", "SC", &hp_setsc, &hp_showsc, &mpx_dev }, - { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &mpx_dev }, - - { 0 } - }; - -DEBTAB mpx_deb [] = { - { "CMDS", DEB_CMDS }, - { "CPU", DEB_CPU }, - { "BUF", DEB_BUF }, - { "XFER", DEB_XFER }, - { NULL, 0 } - }; - -DEVICE mpx_dev = { - "MPX", /* device name */ - mpx_unit, /* unit array */ - mpx_reg, /* register array */ - mpx_mod, /* modifier array */ - MPX_PORTS + MPX_CNTLS, /* number of units */ - 10, /* address radix */ - 31, /* address width */ - 1, /* address increment */ - 8, /* data radix */ - 8, /* data width */ - &tmxr_ex, /* examine routine */ - &tmxr_dep, /* deposit routine */ - &mpx_reset, /* reset routine */ - NULL, /* boot routine */ - &mpx_attach, /* attach routine */ - &mpx_detach, /* detach routine */ - &mpx_dib, /* device information block */ - DEV_DEBUG | DEV_DISABLE, /* device flags */ - 0, /* debug control flags */ - mpx_deb, /* debug flag name table */ - NULL, /* memory size change routine */ - NULL }; /* logical device name */ - - -/* I/O signal handler. - - Commands are sent to the card via an OTA/B. Issuing an STC SC,C causes the - mux to accept the word (STC causes a NMI on the card). If the command uses - one word, command execution will commence, and the flag will set on - completion. If the command uses two words, the flag will be set, indicating - that the second word should be output via an OTA/B. Command execution will - commence upon receipt, and the flag will set on completion. - - When the flag sets for command completion, status or data may be read from - the card via an LIA/B. If additional status or data words are expected, the - flag will set when they are available. - - A command consists of an opcode in the high byte, and a port key or command - parameter in the low byte. Undefined commands are treated as NOPs. - - The card firmware executes commands as part of a twelve-event round-robin - scheduling poll. The card NMI service routine simply sets a flag that is - interrogated during polling. The poll sequence is advanced after each - command. This implies that successive commands incur a delay of at least one - poll-loop's execution time. On an otherwise quiescent card, this delay is - approximately 460 Z80 instructions, or about 950 usec. The average command - initiation time is half of that, or roughly 425 usec. - - If a detected command requires a second word, the card sits in a tight loop, - waiting for the OTx that indicates that the parameter is available. Command - initiation from parameter receipt is about 25 usec. - - For reads and writes to card buffers, the on-board DMA controller is used. - The CPU uses DCPC to handle the transfer, but the data transfer time is - limited by the Z80 DMA, which can process a word in about 1.25 usec. - - For most cards, the hardware POPIO signal sets the flag buffer and flag - flip-flops, while CRS clears the control flip-flop. For this card, the - control and flags are cleared together by CRS, and POPIO is not used. - - Implementation notes: - - 1. "Enable unsolicited input" is the only command that does not set the - device flag upon completion. Therefore, the CPU has no way of knowing - when the command has completed. Because the command in the input latch - is recorded in the NMI handler, but actual execution only begins when the - scheduler polls for the command indication, it is possible for another - command to be sent to the card before the "Enable unsolicited input" - command is recognized. In this case, the second command overwrites the - first and is executed by the scheduler poll. Under simulation, this - condition occurs when the OTx and STC processors are entered with - mpx_state = cmd. - - 2. The "Fast binary read" command inhibits all other commands until the card - is reset. -*/ - -uint32 mpx_io (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) -{ -static const char *output_state [] = { "Command", "Command override", "Parameter", "Data" }; -static const char *input_state [] = { "Status", "Invalid status", "Parameter", "Data" }; -const char *hold_or_clear = (signal_set & ioCLF ? ",C" : ""); -int32 delay; -IOSIGNAL signal; -IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ - -while (working_set) { - signal = IONEXT (working_set); /* isolate next signal */ - - switch (signal) { /* dispatch I/O signal */ - - case ioCLF: /* clear flag flip-flop */ - mpx.flag = mpx.flagbuf = CLEAR; /* clear flag and flag buffer */ - - if (DEBUG_PRI (mpx_dev, DEB_CMDS)) - fputs (">>MPX cmds: [CLF] Flag cleared\n", sim_deb); - break; - - - case ioSTF: /* set flag flip-flop */ - if (DEBUG_PRI (mpx_dev, DEB_CMDS)) - fputs (">>MPX cmds: [STF] Flag set\n", sim_deb); - /* fall into ENF */ - - case ioENF: /* enable flag */ - mpx.flag = mpx.flagbuf = SET; /* set flag and flag buffer */ - break; - - - case ioSFC: /* skip if flag is clear */ - setstdSKF (mpx); - break; - - - case ioSFS: /* skip if flag is set */ - setstdSKF (mpx); - break; - - - case ioIOI: /* I/O data input */ - stat_data = IORETURN (SCPE_OK, mpx_ibuf); /* return info */ - - if (DEBUG_PRI (mpx_dev, DEB_CPU)) - fprintf (sim_deb, ">>MPX cpu: [LIx%s] %s = %06o\n", - hold_or_clear, input_state [mpx_state], mpx_ibuf); - - if (mpx_state == exec) /* if this is input data word */ - sim_activate (&mpx_cntl, DATA_DELAY); /* continue transmission */ - break; - - - case ioIOO: /* I/O data output */ - mpx_obuf = IODATA (stat_data); /* save word */ - - if (DEBUG_PRI (mpx_dev, DEB_CPU)) - fprintf (sim_deb, ">>MPX cpu: [OTx%s] %s = %06o\n", - hold_or_clear, output_state [mpx_state], mpx_obuf); - - if (mpx_state == param) { /* if this is parameter word */ - sim_activate (&mpx_cntl, CMD_DELAY); /* do command now */ - - if (DEBUG_PRI (mpx_dev, DEB_CMDS)) - fprintf (sim_deb, ">>MPX cmds: [OTx%s] Command %03o parameter %06o scheduled, " - "time = %d\n", hold_or_clear, mpx_cmd, mpx_obuf, CMD_DELAY); - } - - else if (mpx_state == exec) /* else if this is output data word */ - sim_activate (&mpx_cntl, DATA_DELAY); /* then do transmission */ - break; - - - case ioCRS: /* control reset */ - controller_reset (); /* reset firmware to power-on defaults */ - mpx_obuf = 0; /* clear output buffer */ - - mpx.control = CLEAR; /* clear control */ - mpx.flagbuf = CLEAR; /* clear flag buffer */ - mpx.flag = CLEAR; /* clear flag */ - - if (DEBUG_PRI (mpx_dev, DEB_CMDS)) - fputs (">>MPX cmds: [CRS] Controller reset\n", sim_deb); - break; - - - case ioCLC: /* clear control flip-flop */ - mpx.control = CLEAR; /* clear control */ - - if (DEBUG_PRI (mpx_dev, DEB_CMDS)) - fprintf (sim_deb, ">>MPX cmds: [CLC%s] Control cleared\n", hold_or_clear); - break; - - - case ioSTC: /* set control flip-flop */ - mpx.control = SET; /* set control */ - - if (mpx_cmd == CMD_BINARY_READ) /* executing fast binary read? */ - break; /* further command execution inhibited */ - - mpx_cmd = GET_OPCODE (mpx_obuf); /* get command opcode */ - mpx_portkey = GET_KEY (mpx_obuf); /* get port key */ - - if (mpx_state == cmd) /* already scheduled? */ - sim_cancel (&mpx_cntl); /* cancel to get full delay */ - - mpx_state = cmd; /* set command state */ - - if (mpx_cmd & CMD_TWO_WORDS) /* two-word command? */ - delay = PARAM_DELAY; /* specify parameter wait */ - else /* one-word command */ - delay = CMD_DELAY; /* specify command wait */ - - sim_activate (&mpx_cntl, delay); /* schedule command */ - - if (DEBUG_PRI (mpx_dev, DEB_CMDS)) - fprintf (sim_deb, ">>MPX cmds: [STC%s] Command %03o key %d scheduled, " - "time = %d\n", hold_or_clear, mpx_cmd, mpx_portkey, delay); - break; - - - case ioEDT: /* end data transfer */ - if (DEBUG_PRI (mpx_dev, DEB_CPU)) - fputs (">>MPX cpu: [EDT] DCPC transfer ended\n", sim_deb); - break; - - - case ioSIR: /* set interrupt request */ - setstdPRL (mpx); /* set standard PRL signal */ - setstdIRQ (mpx); /* set standard IRQ signal */ - setstdSRQ (mpx); /* set standard SRQ signal */ - break; - - - case ioIAK: /* interrupt acknowledge */ - mpx.flagbuf = CLEAR; /* clear flag buffer */ - break; - - - default: /* all other signals */ - break; /* are ignored */ - } - - working_set = working_set & ~signal; /* remove current signal from set */ - } - -return stat_data; -} - - -/* Command executor. - - We are called by the controller service routine to process one- and two-word - commands. For two-word commands, the parameter word is present in mpx_param. - The return value indicates whether the card flag should be set upon - completion. - - Most commands execute and complete directly. The read and write commands, - however, transition to the execution state to simulate the DMA transfer, and - the "Download executable" command does the same to receive the download from - the CPU. - - Several commands were added for the B firmware revision, and the various - revisions of the RTE drivers sent some commands that were never implemented - in the mux firmware. The command protocol treated unknown commands as NOPs, - meaning that the command (and parameter, if it was a two-word command) was - absorbed and the card flag was set as though the command completed normally. - This allowed interoperability between firmware and driver revisions. - - Commands that refer to ports do so indirectly by passing a port key, rather - than a port number. The key-to-port translation is established by the "Set - port key" command. If a key is not found in the table, the command is not - executed, and the status return is ST_BAD_KEY, which in hex is "BAD0". - - Implementation notes: - - 1. The "Reset to power-on defaults" command causes the firmware to disable - interrupts and jump to the power-on initialization routine, exactly as - though the Z80 had received a hardware reset. - - 2. The "Abort DMA transfer" command works because STC causes NMI, so the - command is executed even in the middle of a DMA transfer. The OTx of the - command will be sent to the buffer if a "Write data to buffer" command is - in progress, but the STC will cause this routine to be called, which will - cancel the buffer and return the controller to the idle state. Note that - this command might be sent with no transfer in progress, in which case - nothing is done. - - 3. In response to an "Enable unsolicited interrupts" command, the controller - service is scheduled to check for a pending UI. If one is found, the - first UI status word is placed in the input buffer, and an interrupt is - generated by setting the flag. This causes entry to the driver, which - issues an "Acknowledge" command to obtain the second status word. - - It is possible, however, for the interrupt to be ignored. For example, - the driver may be waiting for a "write buffer available" UI when it is - called to begin a write to a different port. If the flag is set by - the UI after RTE has been entered, the interrupt will be held off, and - the STC sc,C instruction that begins the command sequence will clear the - flag, removing the interrupt entirely. In this case, the controller will - reissue the UI when the next "Enable unsolicited interrupts" command is - sent. - - Note that the firmware reissues the same UI, rather than recomputing UIs - and potentially selecting a different one of higher priority. - - 4. The "Fast binary read" command apparently was intended to facilitate - booting from a 264x tape drive, although no boot loader ROM for the - multiplexer was ever released. It sends the fast binary read escape - sequence (ESC e) to the terminal and then packs each pair of characters - received into a word and sends it to the CPU, accompanied by the device - flag. - - The multiplexer firmware disables interrupts and then manipulates the SIO - for port 0 directly. Significantly, it does no interpretation of the - incoming data and sits in an endless I/O loop, so the only way to exit - the command is to reset the card with a CRS (front panel PRESET or CLC 0 - instruction execution). Sending a command will not work; although the - NMI will interrupt the fast binary read, the NMI handler simply sets a - flag that is tested by the scheduler poll. Because the processor is in - an endless loop, control never returns to the scheduler, so the command - is never seen. - - 5. The "Terminate active receive buffer" behavior is a bit tricky. If the - read buffer has characters, the buffer is terminated as though a - "terminate on count" condition occurred. If the buffer is empty, - however, a "terminate on count = 1" condition is established. When a - character is received, the buffer is terminated, and the buffer - termination count is reset to 254. -*/ - -static t_bool exec_command (void) -{ -int32 port; -uint32 svc_time; -t_bool set_flag = TRUE; /* flag is normally set on completion */ -STATE next_state = idle; /* command normally executes to completion */ - -mpx_ibuf = ST_OK; /* return status is normally OK */ - -switch (mpx_cmd) { - - case CMD_NOP: /* no operation */ - break; /* just ignore */ - - - case CMD_RESET: /* reset firmware */ - controller_reset (); /* reset program variables */ - mpx_ibuf = ST_TEST_OK; /* return self-test OK code */ - break; - - - case CMD_ENABLE_UI: - mpx_uien = TRUE; /* enable unsolicited interrupts */ - sim_activate (&mpx_cntl, CMD_DELAY); /* and schedule controller for UI check */ - - if (DEBUG_PRI (mpx_dev, DEB_CMDS)) - fprintf (sim_deb, ">>MPX cmds: Controller status check scheduled, " - "time = %d\n", CMD_DELAY); - - set_flag = FALSE; /* do not set the flag at completion */ - break; - - - case CMD_DISABLE: - switch (mpx_portkey) { - case SUBCMD_UI: - mpx_uien = FALSE; /* disable unsolicited interrupts */ - break; - - case SUBCMD_DMA: - if (mpx_flags [mpx_port] & FL_WRFILL) /* write buffer xfer in progress? */ - buf_cancel (iowrite, mpx_port, put); /* cancel it */ - else if (mpx_flags [mpx_port] & FL_RDEMPT) /* read buffer xfer in progress? */ - buf_cancel (ioread, mpx_port, get); /* cancel it */ - break; - } - break; - - - case CMD_ACK: /* acknowledge unsolicited interrupt */ - switch (mpx_uicode & UI_REASON) { - - case UI_WRBUF_AVAIL: /* write buffer notification */ - mpx_flags [mpx_port] &= ~FL_WANTBUF; /* clear flag */ - mpx_ibuf = WR_BUF_LIMIT; /* report write buffer available */ - break; - - case UI_RDBUF_AVAIL: /* read buffer notification */ - mpx_flags [mpx_port] &= ~FL_HAVEBUF; /* clear flag */ - - mpx_ibuf = buf_get (ioread, mpx_port) << 8 | /* get header value and position */ - buf_len (ioread, mpx_port, get); /* and include buffer length */ - - if (mpx_flags [mpx_port] & FL_RDOVFLOW) { /* did a buffer overflow? */ - mpx_ibuf = mpx_ibuf | RS_OVERFLOW; /* report it */ - mpx_flags [mpx_port] &= ~FL_RDOVFLOW; /* clear overflow flag */ - } - break; - - case UI_BRK_RECD: /* break received */ - mpx_flags [mpx_port] &= ~FL_BREAK; /* clear flag */ - mpx_ibuf = 0; /* 2nd word is zero */ - break; - } - - mpx_uicode = 0; /* clear notification code */ - break; - - - case CMD_CANCEL: /* cancel first read buffer */ - port = key_to_port (mpx_portkey); /* get port */ - - if (port >= 0) /* port defined? */ - buf_cancel (ioread, port, get); /* cancel get buffer */ - - if ((buf_avail (ioread, port) == 1) && /* one buffer remaining? */ - !(mpx_flags [port] & FL_RDFILL)) /* and not filling it? */ - mpx_flags [port] |= FL_HAVEBUF; /* indicate buffer availability */ - break; - - - case CMD_CANCEL_ALL: /* cancel all read buffers */ - port = key_to_port (mpx_portkey); /* get port */ - - if (port >= 0) /* port defined? */ - buf_init (ioread, port); /* reinitialize read buffers */ - break; - - - case CMD_BINARY_READ: /* fast binary read */ - for (port = 0; port < MPX_PORTS; port++) - sim_cancel (&mpx_unit [port]); /* cancel I/O on all lines */ - - mpx_flags [0] = 0; /* clear port 0 state flags */ - mpx_enq_cntr [0] = 0; /* clear port 0 ENQ counter */ - mpx_ack_wait [0] = 0; /* clear port 0 ACK wait timer */ - - tmxr_putc_ln (&mpx_ldsc [0], ESC); /* send fast binary read */ - tmxr_putc_ln (&mpx_ldsc [0], 'e'); /* escape sequence to port 0 */ - tmxr_poll_tx (&mpx_desc); /* flush output */ - - next_state = exec; /* set execution state */ - break; - - - case CMD_REQ_WRITE: /* request write buffer */ - port = key_to_port (mpx_portkey); /* get port */ - - if (port >= 0) /* port defined? */ - if (buf_avail (iowrite, port) > 0) /* is a buffer available? */ - mpx_ibuf = WR_BUF_LIMIT; /* report write buffer limit */ - - else { - mpx_ibuf = 0; /* report none available */ - mpx_flags [port] |= FL_WANTBUF; /* set buffer request */ - } - break; - - - case CMD_WRITE: /* write to buffer */ - port = key_to_port (mpx_portkey); /* get port */ - - if (port >= 0) { /* port defined? */ - mpx_port = port; /* save port number */ - mpx_iolen = mpx_param & WR_LENGTH; /* save request length */ - next_state = exec; /* set execution state */ - } - break; - - - case CMD_SET_KEY: /* set port key and configuration */ - port = GET_PORT (mpx_param); /* get target port number */ - mpx_key [port] = (uint8) mpx_portkey; /* set port key */ - mpx_config [port] = mpx_param; /* set port configuration word */ - - svc_time = service_time (mpx_param); /* get service time for baud rate */ - - if (svc_time) /* want to change? */ - mpx_unit [port].wait = svc_time; /* set service time */ - - mpx_ibuf = MPX_DATE_CODE; /* return firmware date code */ - break; - - - case CMD_SET_RCV: /* set receive type */ - port = key_to_port (mpx_portkey); /* get port */ - - if (port >= 0) /* port defined? */ - mpx_rcvtype [port] = mpx_param; /* save port receive type */ - break; - - - case CMD_SET_COUNT: /* set character count */ - port = key_to_port (mpx_portkey); /* get port */ - - if (port >= 0) /* port defined? */ - mpx_charcnt [port] = mpx_param; /* save port character count */ - break; - - - case CMD_SET_FLOW: /* set flow control */ - port = key_to_port (mpx_portkey); /* get port */ - - if (port >= 0) /* port defined? */ - mpx_flowcntl [port] = mpx_param & FC_XONXOFF; /* save port flow control */ - - if (mpx_param & FC_FORCE_XON) /* force XON? */ - mpx_flags [port] &= ~FL_XOFF; /* resume transmission if suspended */ - break; - - - case CMD_READ: /* read from buffer */ - port = key_to_port (mpx_portkey); /* get port */ - - if (port >= 0) { /* port defined? */ - mpx_port = port; /* save port number */ - mpx_iolen = mpx_param; /* save request length */ - - sim_activate (&mpx_cntl, DATA_DELAY); /* schedule the transfer */ - next_state = exec; /* set execution state */ - set_flag = FALSE; /* no flag until word ready */ - } - break; - - - case CMD_DL_EXEC: /* Download executable */ - mpx_iolen = mpx_param; /* save request length */ - next_state = exec; /* set execution state */ - break; - - - case CMD_CN_LINE: /* connect modem line */ - case CMD_DC_LINE: /* disconnect modem line */ - case CMD_LOOPBACK: /* enable/disable modem loopback */ - mpx_ibuf = ST_NO_MODEM; /* report "no modem installed" */ - break; - - - case CMD_GET_STATUS: /* get modem status */ - mpx_ibuf = ST_NO_SYSMDM; /* report "no systems modem card" */ - break; - - - case CMD_TERM_BUF: /* terminate active receive buffer */ - port = key_to_port (mpx_portkey); /* get port */ - - if (port >= 0) /* port defined? */ - if (buf_len (ioread, port, put) > 0) { /* any chars in buffer? */ - buf_term (ioread, port, 0); /* terminate buffer and set header */ - - if (buf_avail (ioread, port) == 1) /* first read buffer? */ - mpx_flags [port] |= FL_HAVEBUF; /* indicate availability */ - } - - else { /* buffer is empty */ - mpx_charcnt [port] = 1; /* set to terminate on one char */ - mpx_flags [port] |= FL_ALERT; /* set alert flag */ - } - break; - - - case CMD_VCP_PUT: /* VCP put byte */ - case CMD_VCP_PUT_BUF: /* VCP put buffer */ - case CMD_VCP_GET: /* VCP get byte */ - case CMD_VCP_GET_BUF: /* VCP get buffer */ - case CMD_VCP_EXIT: /* Exit VCP mode */ - case CMD_VCP_ENTER: /* Enter VCP mode */ - - default: /* unknown command */ - if (DEBUG_PRI (mpx_dev, DEB_CMDS)) - fprintf (sim_deb, ">>MPX cmds: Unknown command %03o ignored\n", mpx_cmd); - } - -mpx_state = next_state; -return set_flag; -} - - -/* Multiplexer controller service. - - The controller service handles commands and data transfers to and from the - CPU. The delay in scheduling the controller service represents the firmware - command or data execution time. The controller may be in one of four states - upon entry: idle, first word of command received (cmd), command parameter - received (param), or data transfer (exec). - - Entry in the command state causes execution of one-word commands and - solicitation of command parameters for two-word commands, which are executed - when entering in the parameter state. - - Entry in the data transfer state moves one word between the CPU and a read or - write buffer. For writes, the write buffer is filled with words from the - CPU. Once the indicated number of words have been transferred, the - appropriate line service is scheduled to send the characters. For reads, - characters are unloaded from the read buffer to the CPU; an odd-length - transfer is padded with a blank. A read of fewer characters than are present - in the buffer will return the remaining characters when the next read is - performed. - - Each read or write is terminated by the CPU sending one additional word (the - RTE drivers send -1). The command completes when this word is acknowledged - by the card setting the device flag. For zero-length writes, this additional - word will be the only word sent. - - Data transfer is also used by the "Download executable" command to absorb the - downloaded program. The firmware jumps to location 5100 hex in the - downloaded program upon completion of reception. It is the responsibility of - the program to return to the multiplexer firmware and to return to the CPU - whatever status is appropriate when it is done. Under simulation, we simply - "sink" the program and return status compatible with the multiplexer - diagnostic program to simulate a passing test. - - Entry in the idle state checks for unsolicited interrupts. UIs are sent to - the host when the controller is idle, UIs have been enabled, and a UI - condition exists. If a UI is not acknowledged, it will remain pending and - will be reissued the next time the controller is idle and UIs have been - enabled. - - UI conditions are kept in the per-port flags. The UI conditions are write - buffer available, read buffer available, break received, modem line - connected, and modem line disconnected. The latter two conditions are not - implemented in this simulation. If a break condition occurs at the same time - as a read buffer completion, the break has priority; the buffer UI will occur - after the break UI is acknowledged. - - The firmware checks for UI condition flags as part of the scheduler polling - loop. Under simulation, though, UIs can occur only in two places: the point - of origin (e.g., termination of a read buffer), or the "Enable unsolicited - input" command executor. UIs will be generated at the point of origin only - if the simulator is idle. If the simulator is not idle, it is assumed that - UIs have been disabled to execute the current command and will be reenabled - when the command sequence is complete. - - When the multiplexer is reset, and before the port keys are set, all ports - enter "echoplex" mode. In this mode, characters received are echoed back as - a functional test. Each port terminates buffers on CR reception. We detect - this condition, cancel the buffer, and discard the buffer termination UI. - - Implementation notes: - - 1. The firmware transfers the full amount requested by the CPU, even if the - transfer is longer than the buffer. Also, zero-length transfers program - the card DMA chip to transfer 0 bytes; this results in a transfer of 217 - bytes, per the Zilog databook. Under simulation, writes beyond the - buffer are accepted from the CPU but discarded, and reads beyond the - buffer return blanks. - - 2. We should never return from this routine in the "cmd" state, so debugging - will report "internal error!" if we do. -*/ - -t_stat mpx_cntl_svc (UNIT *uptr) -{ -uint8 ch; -uint32 i; -t_bool add_crlf; -t_bool set_flag = TRUE; -STATE last_state = mpx_state; - -static const char *cmd_state [] = { "complete", "internal error!", "waiting for parameter", "executing" }; - - -switch (mpx_state) { /* dispatch on current state */ - - case idle: /* controller idle */ - set_flag = FALSE; /* assume no UI */ - - if (mpx_uicode) { /* unacknowledged UI? */ - if (mpx_uien == TRUE) { /* interrupts enabled? */ - mpx_port = GET_UIPORT (mpx_uicode); /* get port number */ - mpx_portkey = mpx_key [mpx_port]; /* get port key */ - mpx_ibuf = mpx_uicode & UI_REASON | mpx_portkey; /* report UI reason and port key */ - set_flag = TRUE; /* reissue host interrupt */ - mpx_uien = FALSE; /* disable UI */ - - if (DEBUG_PRI (mpx_dev, DEB_CMDS)) - fprintf (sim_deb, ">>MPX cmds: Port %d key %d unsolicited interrupt reissued, " - "reason = %d\n", mpx_port, mpx_portkey, GET_UIREASON (mpx_uicode)); - } - } - - else { /* no unacknowledged UI */ - for (i = 0; i < MPX_PORTS; i++) { /* check all ports for UIs */ - if (mpx_flags [i] & FL_UI_PENDING) { /* pending UI? */ - mpx_portkey = mpx_key [i]; /* get port key */ - - if (mpx_portkey == KEY_DEFAULT) { /* key defined? */ - if (mpx_flags [i] & FL_HAVEBUF) /* no, is this read buffer avail? */ - buf_cancel (ioread, i, get); /* cancel buffer */ - - mpx_flags [i] &= ~FL_UI_PENDING; /* cancel pending UI */ - } - - else if (mpx_uien == TRUE) { /* interrupts enabled? */ - if ((mpx_flags [i] & FL_WANTBUF) && /* port wants a write buffer? */ - (buf_avail (iowrite, i) > 0)) /* and one is available? */ - mpx_uicode = UI_WRBUF_AVAIL; /* set UI reason */ - - else if (mpx_flags [i] & FL_BREAK) /* received a line BREAK? */ - mpx_uicode = UI_BRK_RECD; /* set UI reason */ - - else if (mpx_flags [i] & FL_HAVEBUF) /* have a read buffer ready? */ - mpx_uicode = UI_RDBUF_AVAIL; /* set UI reason */ - - if (mpx_uicode) { /* UI to send? */ - mpx_port = i; /* set port number for Acknowledge */ - mpx_ibuf = mpx_uicode | mpx_portkey; /* merge UI reason and port key */ - mpx_uicode = mpx_uicode | mpx_port; /* save UI reason and port */ - set_flag = TRUE; /* interrupt host */ - mpx_uien = FALSE; /* disable UI */ - - if (DEBUG_PRI (mpx_dev, DEB_CMDS)) - fprintf (sim_deb, ">>MPX cmds: Port %d key %d unsolicited interrupt generated, " - "reason = %d\n", i, mpx_portkey, GET_UIREASON (mpx_uicode)); - - break; /* quit after first UI */ - } - } - } - } - } - break; - - - case cmd: /* command state */ - if (mpx_cmd & CMD_TWO_WORDS) /* two-word command? */ - mpx_state = param; /* look for parameter before executing */ - else - set_flag = exec_command (); /* execute one-word command */ - break; - - - case param: /* parameter get state */ - mpx_param = mpx_obuf; /* save parameter */ - set_flag = exec_command (); /* execute two-word command */ - break; - - - case exec: /* execution state */ - switch (mpx_cmd) { - - case CMD_BINARY_READ: /* fast binary read */ - mpx_flags [0] &= ~FL_HAVEBUF; /* data word was picked up by CPU */ - set_flag = FALSE; /* suppress device flag */ - break; - - - case CMD_WRITE: /* transfer data to buffer */ - if (mpx_iolen <= 0) { /* last (or only) entry? */ - mpx_state = idle; /* idle controller */ - - if (mpx_iolen < 0) /* tie-off for buffer complete? */ - break; /* we're done */ - } - - add_crlf = ((mpx_param & /* CRLF should be added */ - (WR_ADD_CRLF | WR_PARTIAL)) == WR_ADD_CRLF); - - for (i = 0; i < 2; i++) /* output one or two chars */ - if (mpx_iolen > 0) { /* more to do? */ - if (i) /* high or low byte? */ - ch = (uint8) (mpx_obuf & 0377); /* low byte */ - else - ch = mpx_obuf >> 8; /* high byte */ - - if ((mpx_iolen == 1) && /* final char? */ - (ch == '_') && add_crlf) { /* underscore and asking for CRLF? */ - - add_crlf = FALSE; /* suppress CRLF */ - - if (DEBUG_PRI (mpx_dev, DEB_BUF)) - fprintf (sim_deb, ">>MPX buf: Port %d character '_' " - "suppressed CR/LF\n", mpx_port); - } - - else if (buf_len (iowrite, mpx_port, put) < WR_BUF_LIMIT) - buf_put (iowrite, mpx_port, ch); /* add char to buffer if space avail */ - - mpx_iolen = mpx_iolen - 1; /* drop remaining count */ - } - - if (mpx_iolen == 0) { /* buffer done? */ - if (add_crlf) { /* want CRLF? */ - buf_put (iowrite, mpx_port, CR); /* add CR to buffer */ - buf_put (iowrite, mpx_port, LF); /* add LF to buffer */ - } - - buf_term (iowrite, mpx_port, mpx_param >> 8); /* terminate buffer */ - mpx_iolen = -1; /* mark as done */ - } - - if (DEBUG_PRI (mpx_dev, DEB_CMDS) && - (sim_is_active (&mpx_unit [mpx_port]) == 0)) - fprintf (sim_deb, ">>MPX cmds: Port %d service scheduled, " - "time = %d\n", mpx_port, mpx_unit [mpx_port].wait); - - sim_activate (&mpx_unit [mpx_port], /* start line service */ - mpx_unit [mpx_port].wait); - break; - - - case CMD_READ: /* transfer data from buffer */ - if (mpx_iolen < 0) { /* input complete? */ - if (mpx_obuf == 0177777) { /* "tie-off" word received? */ - if (buf_len (ioread, mpx_port, get) == 0) { /* buffer now empty? */ - buf_free (ioread, mpx_port); /* free buffer */ - - if (buf_avail (ioread, mpx_port) == 1) /* another buffer available? */ - mpx_flags [mpx_port] |= FL_HAVEBUF; /* indicate availability */ - } - - mpx_state = idle; /* idle controller */ - } - - else - set_flag = FALSE; /* ignore word */ - - break; - } - - for (i = 0; i < 2; i++) /* input one or two chars */ - if (mpx_iolen > 0) { /* more to transfer? */ - if (buf_len (ioread, mpx_port, get) > 0) /* more chars available? */ - ch = buf_get (ioread, mpx_port); /* get char from buffer */ - else /* buffer exhausted */ - ch = ' '; /* pad with blank */ - - if (i) /* high or low byte? */ - mpx_ibuf = mpx_ibuf | ch; /* low byte */ - else - mpx_ibuf = ch << 8; /* high byte */ - - mpx_iolen = mpx_iolen - 1; /* drop count */ - } - - else /* odd number of chars */ - mpx_ibuf = mpx_ibuf | ' '; /* pad last with blank */ - - if (mpx_iolen == 0) /* end of host xfer? */ - mpx_iolen = -1; /* mark as done */ - - break; - - - case CMD_DL_EXEC: /* sink data from host */ - if (mpx_iolen <= 0) { /* final entry? */ - mpx_state = idle; /* idle controller */ - mpx_ibuf = ST_DIAG_OK; /* return diag passed status */ - } - - else { - if (mpx_iolen > 0) /* more from host? */ - mpx_iolen = mpx_iolen - 2; /* sink two bytes */ - - if (mpx_iolen <= 0) /* finished download? */ - sim_activate (&mpx_cntl, CMD_DELAY); /* schedule completion */ - - if (DEBUG_PRI (mpx_dev, DEB_CMDS)) - fprintf (sim_deb, ">>MPX cmds: Download completion scheduled, " - "time = %d\n", CMD_DELAY); - } - - break; - - - default: /* no other entries allowed */ - return SCPE_IERR; /* simulator error! */ - } - break; - } - - -if (DEBUG_PRI (mpx_dev, DEB_CMDS) && /* debug print? */ - (last_state != mpx_state)) { /* and state change? */ - fprintf (sim_deb, ">>MPX cmds: Command %03o ", mpx_cmd); - - if ((mpx_cmd & CMD_TWO_WORDS) && (mpx_state != param)) - fprintf (sim_deb, "parameter %06o ", mpx_param); - - fputs (cmd_state [mpx_state], sim_deb); - fputc ('\n', sim_deb); - } - -if (set_flag) { - mpx_io (&mpx_dib, ioENF, 0); /* set device flag */ - - if (DEBUG_PRI (mpx_dev, DEB_CMDS)) - fputs (">>MPX cmds: Flag set\n", sim_deb); - } - -return SCPE_OK; -} - - -/* Multiplexer line service. - - The line service routine is used to transmit and receive characters. It is - started when a buffer is ready for output or when the Telnet poll routine - determines that there are characters ready for input, and it is stopped when - there are no more characters to output or input. When a line is quiescent, - this routine does not run. Service times are selected to approximate the - baud rate setting of the multiplexer port. - - "Fast timing" mode enables three optimizations. First, buffered characters - are transferred via Telnet in blocks, rather than a character at a time; this - reduces network traffic and decreases simulator overhead (there is only one - service routine entry per block, rather than one per character). Second, - ENQ/ACK handshaking is done locally, without involving the Telnet client. - Third, when editing and echo is enabled, entering BS echoes a backspace, a - space, and a backspace, and entering DEL echoes a backslash, a carriage - return, and a line feed, providing better compatibility with prior RTE - terminal drivers. - - Each read and write buffer begins with a reserved header byte that stores - per-buffer information, such as whether handshaking should be suppressed - during output, or the specific cause of termination for input. Buffer - termination sets the header byte with the appropriate flags. - - For output, a character counter is maintained and is incremented if ENQ/ACK - handshaking is enabled for the current port and request. If the counter - limit is reached, an ENQ is sent, and a flag is set to suspend transmission - until an ACK is received. If the last character of the buffer is sent, the - write buffer is freed, and a UI check is made if the controller is idle, in - case a write buffer request is pending. - - For input, the character is retrieved from the Telnet buffer. If a BREAK was - received, break status is set, and the character is discarded (the current - multiplexer library implementation always returns a NUL with a BREAK - indication). If the character is an XOFF, and XON/XOFF pacing is enabled, a - flag is set, and transmission is suspended until a corresponding XON is - received. If the character is an ACK and is in response to a previously sent - ENQ, it is discarded, and transmission is reenabled. - - If editing is enabled, a BS will delete the last character in the read - buffer, and a DEL will delete the entire buffer. Otherwise, buffer - termination conditions are checked (end on character, end on count, or - buffer full), and if observed, the read buffer is terminated, and a read - buffer available UI condition is signalled. - - Implementation notes: - - 1. The firmware echoes an entered BS before checking the buffer count to see - if there are any characters to delete. Under simulation, we only echo if - the buffer is not empty. - - 2. The "Fast binary read" command inhibits the normal transmit and receive - processing. Instead, a pair of characters are sought on line 0 to fill - the input buffer. When they are received, the device flag is set. The - CPU will do a LIx sc,C to retrieve the data and reset the flag. -*/ - -t_stat mpx_line_svc (UNIT *uptr) -{ -const int32 port = uptr - mpx_unit; /* port number */ -const uint16 rt = mpx_rcvtype [port]; /* receive type for port */ -const uint32 data_bits = 5 + GET_BPC (mpx_config [port]); /* number of data bits */ -const uint32 data_mask = (1 << data_bits) - 1; /* mask for data bits */ -const t_bool fast_timing = (uptr->flags & UNIT_FASTTIME) != 0; /* port is set for fast timing */ -const t_bool fast_binary_read = (mpx_cmd == CMD_BINARY_READ); /* fast binary read in progress */ - -uint8 ch; -int32 chx; -uint16 read_length; -t_stat status = SCPE_OK; -t_bool recv_loop = !fast_binary_read; /* bypass if fast binary read */ -t_bool xmit_loop = !(fast_binary_read || /* bypass if fast read or output suspended */ - (mpx_flags [port] & (FL_WAITACK | FL_XOFF))); - - -/* Transmission service */ - -while (xmit_loop && (buf_len (iowrite, port, get) > 0)) { /* character available to output? */ - if ((mpx_flags [port] & FL_WREMPT) == 0) { /* has buffer started emptying? */ - chx = buf_get (iowrite, port) << 8; /* get header value and position */ - - if (fast_timing || (chx & WR_NO_ENQACK) || /* do we want handshake? */ - !(mpx_config [port] & SK_ENQACK)) /* and configured for handshake? */ - mpx_flags [port] &= ~FL_DO_ENQACK; /* no, so clear flag */ - else - mpx_flags [port] |= FL_DO_ENQACK; /* yes, so set flag */ - - continue; /* "continue" for zero-length write */ - } - - if (mpx_flags [port] & FL_DO_ENQACK) /* do handshake for this buffer? */ - mpx_enq_cntr [port] = mpx_enq_cntr [port] + 1; /* bump character counter */ - - if (mpx_enq_cntr [port] > ENQ_LIMIT) { /* ready for ENQ? */ - mpx_enq_cntr [port] = 0; /* clear ENQ counter */ - mpx_ack_wait [port] = 0; /* clear ACK wait timer */ - - mpx_flags [port] |= FL_WAITACK; /* set wait for ACK */ - ch = ENQ; - status = tmxr_putc_ln (&mpx_ldsc [port], ch); /* transmit ENQ */ - xmit_loop = FALSE; /* stop further transmission */ - } - - else { /* not ready for ENQ */ - ch = buf_get (iowrite, port) & data_mask; /* get char and mask to bit width */ - status = tmxr_putc_ln (&mpx_ldsc [port], ch); /* transmit the character */ - xmit_loop = (status == SCPE_OK) && fast_timing; /* continue transmission? */ - } - - if ((status == SCPE_OK) && /* transmitted OK? */ - DEBUG_PRI (mpx_dev, DEB_XFER)) - fprintf (sim_deb, ">>MPX xfer: Port %d character %s transmitted\n", - port, fmt_char (ch)); - - else - xmit_loop = FALSE; - - if (buf_len (iowrite, port, get) == 0) { /* buffer complete? */ - buf_free (iowrite, port); /* free buffer */ - - if (mpx_state == idle) /* controller idle? */ - mpx_cntl_svc (&mpx_cntl); /* check for UI */ - } - } - - -/* Reception service */ - -while (recv_loop && /* OK to process? */ - (chx = tmxr_getc_ln (&mpx_ldsc [port]))) { /* and new char available? */ - - if (chx & SCPE_BREAK) { /* break detected? */ - mpx_flags [port] |= FL_BREAK; /* set break status */ - - if (DEBUG_PRI (mpx_dev, DEB_XFER)) - fputs (">>MPX xfer: Break detected\n", sim_deb); - - if (mpx_state == idle) /* controller idle? */ - mpx_cntl_svc (&mpx_cntl); /* check for UI */ - - continue; /* discard NUL that accompanied BREAK */ - } - - ch = chx & data_mask; /* mask to bits per char */ - - if ((ch == XOFF) && /* XOFF? */ - (mpx_flowcntl [port] & FC_XONXOFF)) { /* and handshaking enabled? */ - mpx_flags [port] |= FL_XOFF; /* suspend transmission */ - - if (DEBUG_PRI (mpx_dev, DEB_XFER)) - fprintf (sim_deb, ">>MPX xfer: Port %d character XOFF " - "suspends transmission\n", port); - - recv_loop = fast_timing; /* set to loop if fast mode */ - continue; - } - - else if ((ch == XON) && /* XON? */ - (mpx_flags [port] & FL_XOFF)) { /* and currently suspended? */ - mpx_flags [port] &= ~FL_XOFF; /* resume transmission */ - - if (DEBUG_PRI (mpx_dev, DEB_XFER)) - fprintf (sim_deb, ">>MPX xfer: Port %d character XON " - "resumes transmission\n", port); - - recv_loop = fast_timing; /* set to loop if fast mode */ - continue; - } - - if (DEBUG_PRI (mpx_dev, DEB_XFER)) - fprintf (sim_deb, ">>MPX xfer: Port %d character %s received\n", - port, fmt_char (ch)); - - if ((ch == ACK) && (mpx_flags [port] & FL_WAITACK)) { /* ACK and waiting for it? */ - mpx_flags [port] = mpx_flags [port] & ~FL_WAITACK; /* clear wait flag */ - recv_loop = FALSE; /* absorb character */ - } - - else if ((buf_avail (ioread, port) == 0) && /* no free buffer available for char? */ - !(mpx_flags [port] & FL_RDFILL)) { /* and not filling last buffer? */ - mpx_flags [port] |= FL_RDOVFLOW; /* set buffer overflow flag */ - recv_loop = fast_timing; /* continue loop if fast mode */ - } - - else { /* buffer is available */ - if (rt & RT_ENAB_EDIT) /* editing enabled? */ - if (ch == BS) { /* backspace? */ - if (buf_len (ioread, port, put) > 0) /* at least one character in buffer? */ - buf_remove (ioread, port); /* remove last char */ - - if (rt & RT_ENAB_ECHO) { /* echo enabled? */ - tmxr_putc_ln (&mpx_ldsc [port], BS); /* echo BS */ - - if (fast_timing) { /* fast timing mode? */ - tmxr_putc_ln (&mpx_ldsc [port], ' '); /* echo space */ - tmxr_putc_ln (&mpx_ldsc [port], BS); /* echo BS */ - } - } - - continue; - } - - else if (ch == DEL) { /* delete line? */ - buf_cancel (ioread, port, put); /* cancel put buffer */ - - if (rt & RT_ENAB_ECHO) { /* echo enabled? */ - if (fast_timing) /* fast timing mode? */ - tmxr_putc_ln (&mpx_ldsc [port], '\\'); /* echo backslash */ - - tmxr_putc_ln (&mpx_ldsc [port], CR); /* echo CR */ - tmxr_putc_ln (&mpx_ldsc [port], LF); /* and LF */ - } - - continue; - } - - if (uptr->flags & UNIT_CAPSLOCK) /* caps lock mode? */ - ch = toupper (ch); /* convert to upper case if lower */ - - if (rt & RT_ENAB_ECHO) /* echo enabled? */ - tmxr_putc_ln (&mpx_ldsc [port], ch); /* echo the char */ - - if (rt & RT_END_ON_CHAR) { /* end on character? */ - recv_loop = FALSE; /* assume termination */ - - if ((ch == CR) && (rt & RT_END_ON_CR)) { - if (rt & RT_ENAB_ECHO) /* echo enabled? */ - tmxr_putc_ln (&mpx_ldsc [port], LF); /* send LF */ - mpx_param = RS_ETC_CR; /* set termination condition */ - } - - else if ((ch == RS) && (rt & RT_END_ON_RS)) - mpx_param = RS_ETC_RS; /* set termination condition */ - - else if ((ch == EOT) && (rt & RT_END_ON_EOT)) - mpx_param = RS_ETC_EOT; /* set termination condition */ - - else if ((ch == DC2) && (rt & RT_END_ON_DC2)) - mpx_param = RS_ETC_DC2; /* set termination condition */ - - else - recv_loop = TRUE; /* no termination */ - } - - if (recv_loop) /* no termination condition? */ - buf_put (ioread, port, ch); /* put character in buffer */ - - read_length = buf_len (ioread, port, put); /* get current buffer length */ - - if ((rt & RT_END_ON_CNT) && /* end on count */ - (read_length == mpx_charcnt [port])) { /* and count reached? */ - recv_loop = FALSE; /* set termination */ - mpx_param = 0; /* no extra termination info */ - - if (mpx_flags [port] & FL_ALERT) { /* was this alert for term rcv buffer? */ - mpx_flags [port] &= ~FL_ALERT; /* clear alert flag */ - mpx_charcnt [port] = RD_BUF_LIMIT; /* reset character count */ - } - } - - else if (read_length == RD_BUF_LIMIT) { /* buffer now full? */ - recv_loop = FALSE; /* set termination */ - mpx_param = mpx_param | RS_PARTIAL; /* and partial buffer flag */ - } - - if (recv_loop) /* no termination condition? */ - recv_loop = fast_timing; /* set to loop if fast mode */ - - else { /* termination occurred */ - if (DEBUG_PRI (mpx_dev, DEB_XFER)) { - fprintf (sim_deb, ">>MPX xfer: Port %d read terminated on ", port); - - if (mpx_param & RS_PARTIAL) - fputs ("buffer full\n", sim_deb); - else if (rt & RT_END_ON_CHAR) - fprintf (sim_deb, "character %s\n", fmt_char (ch)); - else - fprintf (sim_deb, "count = %d\n", mpx_charcnt [port]); - } - - if (buf_len (ioread, port, put) == 0) { /* zero-length read? */ - buf_put (ioread, port, 0); /* dummy put to reserve header */ - buf_remove (ioread, port); /* back out dummy char leaving header */ - } - - buf_term (ioread, port, mpx_param >> 8); /* terminate buffer and set header */ - - if (buf_avail (ioread, port) == 1) /* first read buffer? */ - mpx_flags [port] |= FL_HAVEBUF; /* indicate availability */ - - if (mpx_state == idle) /* controller idle? */ - mpx_cntl_svc (&mpx_cntl); /* check for UI */ - } - } - } - - -/* Housekeeping */ - -if (fast_binary_read) { /* fast binary read in progress? */ - if (port == 0) { /* on port 0? */ - chx = tmxr_getc_ln (&mpx_ldsc [0]); /* see if a character is ready */ - - if (chx && !(mpx_flags [0] & FL_HAVEBUF)) { /* character ready and buffer empty? */ - if (mpx_flags [0] & FL_WANTBUF) { /* second character? */ - mpx_ibuf = mpx_ibuf | (chx & DMASK8); /* merge it into word */ - mpx_flags [0] |= FL_HAVEBUF; /* mark buffer as ready */ - - mpx_io (&mpx_dib, ioENF, 0); /* set device flag */ - - if (DEBUG_PRI (mpx_dev, DEB_CMDS)) - fputs (">>MPX cmds: Flag and SRQ set\n", sim_deb); - } - - else /* first character */ - mpx_ibuf = (chx & DMASK8) << 8; /* put in top half of word */ - - mpx_flags [0] ^= FL_WANTBUF; /* toggle byte flag */ - } - - sim_activate (uptr, uptr->wait); /* reschedule service for fast response */ - } - } - -else { /* normal service */ - tmxr_poll_tx (&mpx_desc); /* output any accumulated characters */ - - if ((buf_avail (iowrite, port) < 2) && /* more to transmit? */ - !(mpx_flags [port] & (FL_WAITACK | FL_XOFF)) || /* and transmission not suspended */ - tmxr_rqln (&mpx_ldsc [port])) /* or more to receive? */ - sim_activate (uptr, uptr->wait); /* reschedule service */ - else - if (DEBUG_PRI (mpx_dev, DEB_CMDS)) - fprintf (sim_deb, ">>MPX cmds: Port %d service stopped\n", port); - } - -return SCPE_OK; -} - - -/* Telnet poll service. - - This service routine is used to poll for Telnet connections and incoming - characters. It starts when the socket is attached and stops when the socket - is detached. - - Each line is then checked for a pending ENQ/ACK handshake. If one is - pending, the ACK counter is incremented, and if it times out, another ENQ is - sent to avoid stalls. Lines are also checked for available characters, and - the corresponding line I/O service routine is scheduled if needed. -*/ - -t_stat mpx_poll_svc (UNIT *uptr) -{ -uint32 i; -t_stat status = SCPE_OK; - -poll_connection (); /* check for new connection */ - -tmxr_poll_rx (&mpx_desc); /* poll for input */ - -for (i = 0; i < MPX_PORTS; i++) { /* check lines */ - if (mpx_flags [i] & FL_WAITACK) { /* waiting for ACK? */ - mpx_ack_wait [i] = mpx_ack_wait [i] + 1; /* increment ACK wait timer */ - - if (mpx_ack_wait [i] > ACK_LIMIT) { /* has wait timed out? */ - mpx_ack_wait [i] = 0; /* reset counter */ - status = tmxr_putc_ln (&mpx_ldsc [i], ENQ); /* send ENQ again */ - tmxr_poll_tx (&mpx_desc); /* transmit it */ - - if ((status == SCPE_OK) && /* transmitted OK? */ - DEBUG_PRI (mpx_dev, DEB_XFER)) - fprintf (sim_deb, ">>MPX xfer: Port %d character ENQ retransmitted\n", i); - } - } - - if (tmxr_rqln (&mpx_ldsc [i])) /* chars available? */ - sim_activate (&mpx_unit [i], mpx_unit [i].wait); /* activate I/O service */ - } - -if (uptr->wait == POLL_FIRST) /* first poll? */ - uptr->wait = sync_poll (INITIAL); /* initial synchronization */ -else /* not first */ - uptr->wait = sync_poll (SERVICE); /* continue synchronization */ - -sim_activate (uptr, uptr->wait); /* continue polling */ - -return SCPE_OK; -} - - -/* Simulator reset routine. - - The hardware CRS signal generates a reset signal to the Z80 and its - peripherals. This causes execution of the power up initialization code. - - The CRS signal also has these hardware effects: - - clears control - - clears flag - - clears flag buffer - - clears backplane ready - - clears the output buffer register - - Implementation notes: - - 1. Under simulation, we also clear the input buffer register, even though - the hardware doesn't. - - 2. We set up the first poll for Telnet connections to occur "immediately" - upon execution, so that clients will be connected before execution - begins. Otherwise, a fast program may access the multiplexer before the - poll service routine activates. - - 3. We must set the "emptying_flags" and "filling_flags" values here, because - they cannot be initialized statically, even though the values are - constant. -*/ - -t_stat mpx_reset (DEVICE *dptr) -{ -if (sim_switches & SWMASK ('P')) { /* power-on reset? */ - emptying_flags [ioread] = FL_RDEMPT; /* initialize buffer flags constants */ - emptying_flags [iowrite] = FL_WREMPT; - filling_flags [ioread] = FL_RDFILL; - filling_flags [iowrite] = FL_WRFILL; - } - -IOPRESET (&mpx_dib); /* PRESET device (does not use PON) */ - -mpx_ibuf = 0; /* clear input buffer */ - -if (mpx_poll.flags & UNIT_ATT) { /* network attached? */ - mpx_poll.wait = POLL_FIRST; /* set up poll */ - sim_activate (&mpx_poll, mpx_poll.wait); /* start Telnet poll immediately */ - } -else - sim_cancel (&mpx_poll); /* else stop Telnet poll */ - -return SCPE_OK; -} - - -/* Attach the multiplexer to a Telnet port. - - We are called by the ATTACH MPX command to attach the multiplexer to - the listening port indicated by . Logically, it is the multiplexer - device that is attached; however, SIMH only allows units to be attached. - This makes sense for devices such as tape drives, where the attached media is - a property of a specific drive. In our case, though, the listening port is a - property of the multiplexer card, not of any given serial line. As ATTACH - MPX is equivalent to ATTACH MPX0, the port would, by default, be attached to - the first serial line and be reported there in a SHOW MPX command. - - To preserve the logical picture, we attach the port to the Telnet poll unit, - which is normally disabled to inhibit its display. Attaching to a disabled - unit is not allowed, so we first enable the unit, then attach it, then - disable it again. Attachment is reported by the "mpx_status" routine below. - - The Telnet poll service routine is synchronized with the other input polling - devices in the simulator to facilitate idling. -*/ - -t_stat mpx_attach (UNIT *uptr, char *cptr) -{ -t_stat status = SCPE_OK; - -if (uptr != mpx_unit) /* not unit 0? */ - return SCPE_NOATT; /* can't attach */ - -mpx_poll.flags = mpx_poll.flags & ~UNIT_DIS; /* enable unit */ -status = tmxr_attach (&mpx_desc, &mpx_poll, cptr); /* attach to socket */ -mpx_poll.flags = mpx_poll.flags | UNIT_DIS; /* disable unit */ - -if (status == SCPE_OK) { - mpx_poll.wait = POLL_FIRST; /* set up poll */ - sim_activate (&mpx_poll, mpx_poll.wait); /* start poll immediately */ - } -return status; -} - - -/* Detach the multiplexer. - - Normally, we are called by the DETACH MPX command, which is equivalent to - DETACH MPX0. However, we may be called with other units in two cases. - - A DETACH ALL command will call us for unit 9 (the poll unit) if it is - attached. Also, during simulator shutdown, we will be called for units 0-8 - (detach_all in scp.c calls the detach routines of all units that do NOT have - UNIT_ATTABLE), as well as for unit 9 if it is attached. In both cases, it is - imperative that we return SCPE_OK, otherwise any remaining device detaches - will not be performed. -*/ - -t_stat mpx_detach (UNIT *uptr) -{ -t_stat status = SCPE_OK; -int32 i; - -if ((uptr == mpx_unit) || (uptr == &mpx_poll)) { /* base unit or poll unit? */ - status = tmxr_detach (&mpx_desc, &mpx_poll); /* detach socket */ - - for (i = 0; i < MPX_PORTS; i++) { - mpx_ldsc [i].rcve = 0; /* disable line reception */ - sim_cancel (&mpx_unit [i]); /* cancel any scheduled I/O */ - } - - sim_cancel (&mpx_poll); /* stop Telnet poll */ - } - -return status; -} - - -/* Show multiplexer status */ - -t_stat mpx_status (FILE *st, UNIT *uptr, int32 val, void *desc) -{ -if (mpx_poll.flags & UNIT_ATT) /* attached to socket? */ - fprintf (st, "attached to port %s, ", mpx_poll.filename); -else - fprintf (st, "not attached, "); - -tmxr_show_summ (st, uptr, val, desc); /* report connection count */ -return SCPE_OK; -} - - -/* Set firmware revision. - - Currently, we support only revision C, so the MTAB entry does not have an - "mstring" entry. When we add revision D support, an "mstring" entry of "REV" - will enable changing the firmware revision. -*/ - -t_stat mpx_set_frev (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -if ((cptr == NULL) || /* no parameter? */ - (*cptr < 'C') || (*cptr > 'D') || /* or not C or D? */ - (*(cptr + 1) != '\0')) /* or not just one character? */ - return SCPE_ARG; /* bad argument */ - -else { - if (*cptr == 'C') /* setting revision C? */ - mpx_dev.flags = mpx_dev.flags & ~DEV_REV_D; /* clear 'D' flag */ - else if (*cptr == 'D') /* setting revision D? */ - mpx_dev.flags = mpx_dev.flags | DEV_REV_D; /* set 'D' flag */ - - return SCPE_OK; - } -} - - -/* Show firmware revision */ - -t_stat mpx_show_frev (FILE *st, UNIT *uptr, int32 val, void *desc) -{ -if (mpx_dev.flags & DEV_REV_D) - fputs ("12792D", st); -else - fputs ("12792C", st); -return SCPE_OK; -} - - -/* Local routines */ - - -/* Poll for new Telnet connections */ - -static void poll_connection (void) -{ -int32 new_line; - -new_line = tmxr_poll_conn (&mpx_desc); /* check for new connection */ - -if (new_line >= 0) /* new connection established? */ - mpx_ldsc [new_line].rcve = 1; /* enable line to receive */ - -return; -} - - -/* Controller reset. - - This is the card microprocessor reset, not the simulator reset routine. It - simulates a power-on restart of the Z80 firmware. When it is called from the - simulator reset routine, that routine will take care of setting the card - flip-flops appropriately. -*/ - -static void controller_reset (void) -{ -uint32 i; - -mpx_state = idle; /* idle state */ - -mpx_cmd = 0; /* clear command */ -mpx_param = 0; /* clear parameter */ -mpx_uien = FALSE; /* disable interrupts */ - -for (i = 0; i < MPX_PORTS; i++) { /* clear per-line variables */ - buf_init (iowrite, i); /* initialize write buffers */ - buf_init (ioread, i); /* initialize read buffers */ - - mpx_key [i] = KEY_DEFAULT; /* clear port key to default */ - - if (i == 0) /* default port configurations */ - mpx_config [0] = SK_PWRUP_0; /* port 0 is separate from 1-7 */ - else - mpx_config [i] = SK_PWRUP_1 | i; - - mpx_rcvtype [i] = RT_PWRUP; /* power on config for echoplex */ - mpx_charcnt [i] = 0; /* default character count */ - mpx_flowcntl [i] = 0; /* default flow control */ - mpx_flags [i] = 0; /* clear state flags */ - mpx_enq_cntr [i] = 0; /* clear ENQ counter */ - mpx_ack_wait [i] = 0; /* clear ACK wait timer */ - mpx_unit [i].wait = service_time (mpx_config [i]); /* set terminal I/O time */ - - sim_cancel (&mpx_unit [i]); /* cancel line I/O */ - } - -sim_cancel (&mpx_cntl); /* cancel controller */ - -return; -} - - -/* Calculate service time from baud rate. - - Service times are based on 1580 instructions per millisecond, which is the - 1000 E-Series execution speed. Baud rate 0 means "don't change" and is - handled by the "Set port key" command executor. - - Baud rate settings of 13-15 are marked as "reserved" in the user manual, but - the firmware defines these as 38400, 9600, and 9600 baud, respectively. -*/ - -static uint32 service_time (uint16 control_word) -{ -/* Baud Rates 0- 7 : --, 50, 75, 110, 134.5, 150, 300, 1200, */ -/* Baud Rates 8-15 : 1800, 2400, 4800, 9600, 19200, 38400, 9600, 9600 */ -static const int32 ticks [] = { 0, 316000, 210667, 143636, 117472, 105333, 52667, 13167, - 8778, 6583, 3292, 1646, 823, 411, 1646, 1646 }; - -return ticks [GET_BAUDRATE (control_word)]; /* return service time for indicated rate */ -} - - -/* Translate port key to port number. - - Port keys are scanned in reverse port order, so if more than one port has the - same port key, commands specifying that key will affect the highest numbered - port. - - If a port key is the reserved value 255, then the port key has not been set. - In this case, set the input buffer to 0xBAD0 and return -1 to indicate - failure. -*/ - -static int32 key_to_port (uint32 key) -{ -int32 i; - -for (i = MPX_PORTS - 1; i >= 0; i--) /* scan in reverse order */ - if (mpx_key [i] == key) /* key found? */ - return i; /* return port number */ - -mpx_ibuf = ST_BAD_KEY; /* key not found: set status */ -return -1; /* return failure code */ -} - - -/* Buffer manipulation routines. - - The 12792 hardware provides 16K bytes of RAM to the microprocessor. From - this pool, the firmware allocates per-port read/write buffers and state - variables, global variables, and the system stack. Allocations are static - and differ between firmware revisions. - - The A/B/C revisions allocate two 254-byte read buffers and two 254-byte write - buffers per port. Assuming an idle condition, the first write to a port - transfers characters to the first write buffer. When the transfer completes, - the SIO begins transmitting. During transmission, a second write can be - initiated, which transfers characters to the second write buffer. If a third - write is attempted before the first buffer has been released, it will be - denied until the SIO completes transmission; then, if enabled, an unsolicited - interrupt will occur to announce buffer availability. The "active" (filling) - buffer alternates between the two. - - At idle, characters received will fill the first read buffer. When the read - completes according to the previously set termination criteria, an - unsolicited interrupt will occur (if enabled) to announce buffer - availability. If more characters are received before the first buffer has - been transferred to the CPU, they will fill the second buffer. If that read - also completes, additional characters will be discarded until the first - buffer has been emptied. The "active" (emptying) buffer alternates between - the two. - - With this configuration, two one-character writes or reads will allocate both - available buffers, even though each was essentially empty. - - The D revision allocates one 1024-byte FIFO read buffer and one 892-byte - write buffer per port. As with the A/B/C revisions, the first write to a - port transfers characters to the write buffer, and serial transmission begins - when the write completes. However, the write buffer is not a FIFO, so the - host is not permitted another write request until the entire buffer has been - transmitted. - - The read buffer is a FIFO. Characters received are placed into the FIFO as a - stream. Unlike the A/B/C revisions, character editing and termination - conditions are not evaluated until the buffer is read. Therefore, a full - 1024 characters may be received before additional characters would be - discarded. - - When the first character is received, an unsolicited interrupt occurs (if - enabled) to announce data reception. A host read may then be initiated. The - write buffer is used temporarily to process characters from the read buffer. - Characters are copied from the read to the write buffer while editing as - directed by the configuration accompanying the read request (e.g., deleting - the character preceding a BS, stripping CR/LF, etc.). When the termination - condition is found, the read command completes. Incoming characters may be - added to the FIFO while this is occurring. - - In summary, the revision differences in buffer handling are: - - Revisions A/B/C: - - two 254-byte receive buffers - - a buffer is "full" when the terminator character or count is received - - termination type must be established before the corresponding read - - data is echoed as it is received - - Revision D: - - one 1024-byte receive buffer - - buffer is "full" only when 1024 characters are received - - the concept of a buffer terminator does not apply, as the data is not - examined until a read is requested and characters are retrieved from the - FIFO. - - data is not echoed until it is read - - To implement the C revision behavior, while preserving the option of reusing - the buffer handlers for future D revision support, the dual 254-byte buffers - are implemented as a single 514-byte circular FIFO with capacity limited to - 254 bytes per buffer. This reserves space for a CR and LF and for a header - byte in each buffer. The header byte preserves per-buffer state information. - - In this implementation, the buffer "put" index points at the next free - location, and the buffer "get" index points at the next character to - retrieve. In addition to "put" and "get" indexes, a third "separator" index - is maintained to divide the FIFO into two areas corresponding to the two - buffers, and a "buffer filling" flag is maintained for each FIFO that is set - by the fill (put) routine and cleared by the terminate buffer routine. - - Graphically, the implementation is as follows for buffer "B[]", get "G", put - "P", and separator "S" indexes: - - 1. Initialize: 2. Fill first buffer: - G = S = P = 0 B[P] = char; Incr (P) - - |------------------------------| |---------|--------------------| - G G P --> - S S - P - - 3. Terminate first buffer: 4. Fill second buffer: - if S == G then S = P else nop B[P] = char; Incr (P) - - |------------|-----------------| |------------|------|----------| - G /---> S G S P --> - * ----/ P - - 5. Terminate second buffer: 6. Empty first buffer: - if S == G then S = P else nop char = B[G]; Incr (G) - - |------------|------------|----| |----|-------|------------|----| - G S P G --> S P - - 7. First buffer is empty: 8. Free first buffer: - G == S if !filling then S = P else nop - - |------------|------------|----| |------------|------------|----| - G P G /---> S - S * ----/ P - - 9. Empty second buffer: 10. Second buffer empty: - char = B[G]; Incr (G) G == S - - |----------------|--------|----| |-------------------------|----| - G --> S G - P S - P - 11. Free second buffer: - if !filling then S = P else nop - - |-------------------------|----| - G - S - P - - We also provide the following utility routines: - - - Remove Character: Decr (P) - - - Cancel Buffer: if S == G then P = G else G = S - - - Buffer Length: if S < G then return S + BUFSIZE - G else return S - G - - - Buffers Available: if G == P then return 2 else if G != S != P then return - 0 else return 1 - - The "buffer filling" flag is necessary for the "free" routine to decide - whether to advance the separator index. If the first buffer is to be freed, - then G == S and S != P. If the second buffer is already filled, then S = P. - However, if the buffer is still filling, then S must remain at G. This - cannot be determined from G, S, and P alone. - - A "buffer emptying" flag is also employed to record whether the per-buffer - header has been obtained. This allows the buffer length to exclude the - header and reflect only the characters present. -*/ - - -/* Increment a buffer index with wraparound */ - -static uint16 buf_incr (BUF_INDEX index, uint32 port, IO_OPER rw, int increment) -{ -index [port] [rw] = - (index [port] [rw] + buf_size [rw] + increment) % buf_size [rw]; - -return index [port] [rw]; -} - - -/* Initialize the buffer. - - Initialization sets the three indexes to zero and clears the buffer state - flags. -*/ - -static void buf_init (IO_OPER rw, uint32 port) -{ -mpx_get [port] [rw] = 0; /* clear indexes */ -mpx_sep [port] [rw] = 0; -mpx_put [port] [rw] = 0; - -if (rw == ioread) - mpx_flags [mpx_port] &= ~(FL_RDFLAGS); /* clear read buffer flags */ -else - mpx_flags [mpx_port] &= ~(FL_WRFLAGS); /* clear write buffer flags */ -return; -} - - -/* Get a character from the buffer. - - The character indicated by the "get" index is retrieved from the buffer, and - the index is incremented with wraparound. If the buffer is now empty, the - "buffer emptying" flag is cleared. Otherwise, it is set to indicate that - characters have been removed from the buffer. -*/ - -static uint8 buf_get (IO_OPER rw, uint32 port) -{ -uint8 ch; -uint32 index = mpx_get [port] [rw]; /* current get index */ - -if (rw == ioread) - ch = mpx_rbuf [port] [index]; /* get char from read buffer */ -else - ch = mpx_wbuf [port] [index]; /* get char from write buffer */ - -buf_incr (mpx_get, port, rw, +1); /* increment circular get index */ - -if (DEBUG_PRI (mpx_dev, DEB_BUF)) - if (mpx_flags [port] & emptying_flags [rw]) - fprintf (sim_deb, ">>MPX buf: Port %d character %s get from %s buffer " - "[%d]\n", port, fmt_char (ch), io_op [rw], index); - else - fprintf (sim_deb, ">>MPX buf: Port %d header %03o get from %s buffer " - "[%d]\n", port, ch, io_op [rw], index); - -if (mpx_get [port] [rw] == mpx_sep [port] [rw]) /* buffer now empty? */ - mpx_flags [port] &= ~emptying_flags [rw]; /* clear "buffer emptying" flag */ -else - mpx_flags [port] |= emptying_flags [rw]; /* set "buffer emptying" flag */ - -return ch; -} - - -/* Put a character to the buffer. - - The character is written to the buffer in the slot indicated by the "put" - index, and the index is incremented with wraparound. The first character put - to a new buffer reserves space for the header and sets the "buffer filling" - flag. -*/ - -static void buf_put (IO_OPER rw, uint32 port, uint8 ch) -{ -uint32 index; - -if ((mpx_flags [port] & filling_flags [rw]) == 0) { /* first put to this buffer? */ - mpx_flags [port] |= filling_flags [rw]; /* set buffer filling flag */ - index = mpx_put [port] [rw]; /* get current put index */ - buf_incr (mpx_put, port, rw, +1); /* reserve space for header */ - - if (DEBUG_PRI (mpx_dev, DEB_BUF)) - fprintf (sim_deb, ">>MPX buf: Port %d reserved header " - "for %s buffer [%d]\n", port, io_op [rw], index); - } - -index = mpx_put [port] [rw]; /* get current put index */ - -if (rw == ioread) - mpx_rbuf [port] [index] = ch; /* put char in read buffer */ -else - mpx_wbuf [port] [index] = ch; /* put char in write buffer */ - -buf_incr (mpx_put, port, rw, +1); /* increment circular put index */ - -if (DEBUG_PRI (mpx_dev, DEB_BUF)) - fprintf (sim_deb, ">>MPX buf: Port %d character %s put to %s buffer " - "[%d]\n", port, fmt_char (ch), io_op [rw], index); -return; -} - - -/* Remove the last character put to the buffer. - - The most-recent character put to the buffer is removed by decrementing the - "put" index with wraparound. -*/ - -static void buf_remove (IO_OPER rw, uint32 port) -{ -uint8 ch; -uint32 index; - -index = buf_incr (mpx_put, port, rw, -1); /* decrement circular put index */ - -if (DEBUG_PRI (mpx_dev, DEB_BUF)) { - if (rw == ioread) - ch = mpx_rbuf [port] [index]; /* pick up char from read buffer */ - else - ch = mpx_wbuf [port] [index]; /* pick up char from write buffer */ - - fprintf (sim_deb, ">>MPX buf: Port %d character %s removed from %s buffer " - "[%d]\n", port, fmt_char (ch), io_op [rw], index); - } -return; -} - - -/* Terminate the buffer. - - The buffer is marked to indicate that filling is complete and that the next - "put" operation should begin a new buffer. The header value is stored in - first byte of buffer, which is reserved, and the "buffer filling" flag is - cleared. -*/ - -static void buf_term (IO_OPER rw, uint32 port, uint8 header) -{ -uint32 index = mpx_sep [port] [rw]; /* separator index */ - -if (rw == ioread) - mpx_rbuf [port] [index] = header; /* put header in read buffer */ -else - mpx_wbuf [port] [index] = header; /* put header in write buffer */ - -mpx_flags [port] = mpx_flags [port] & ~filling_flags [rw]; /* clear filling flag */ - -if (mpx_get [port] [rw] == index) /* reached separator? */ - mpx_sep [port] [rw] = mpx_put [port] [rw]; /* move sep to end of next buffer */ - -if (DEBUG_PRI (mpx_dev, DEB_BUF)) - fprintf (sim_deb, ">>MPX buf: Port %d header %03o terminated %s buffer\n", - port, header, io_op [rw]); -return; -} - - -/* Free the buffer. - - The buffer is marked to indicate that it is available for reuse, and the - "buffer emptying" flag is reset. -*/ - -static void buf_free (IO_OPER rw, uint32 port) -{ -if ((mpx_flags [port] & filling_flags [rw]) == 0) /* not filling next buffer? */ - mpx_sep [port] [rw] = mpx_put [port] [rw]; /* move separator to end of next buffer */ - /* else it will be moved when terminated */ -mpx_flags [port] = mpx_flags [port] & ~emptying_flags [rw]; /* clear emptying flag */ - -if (DEBUG_PRI (mpx_dev, DEB_BUF)) - fprintf (sim_deb, ">>MPX buf: Port %d released %s buffer\n", port, io_op [rw]); -return; -} - - -/* Cancel the selected buffer. - - The selected buffer is marked to indicate that it is empty. Either the "put" - buffer or the "get" buffer may be selected. -*/ - -static void buf_cancel (IO_OPER rw, uint32 port, BUF_SELECT which) -{ -if (which == put) { /* cancel put buffer? */ - mpx_put [port] [rw] = mpx_sep [port] [rw]; /* move put back to separator */ - mpx_flags [port] &= ~filling_flags [rw]; /* clear filling flag */ - } - -else { /* cancel get buffer */ - if (mpx_sep [port] [rw] == mpx_get [port] [rw]) { /* filling first buffer? */ - mpx_put [port] [rw] = mpx_get [port] [rw]; /* cancel first buffer */ - mpx_flags [port] &= ~filling_flags [rw]; /* clear filling flag */ - } - - else { /* not filling first buffer */ - mpx_get [port] [rw] = mpx_sep [port] [rw]; /* cancel first buffer */ - - if ((mpx_flags [port] & filling_flags [rw]) == 0) /* not filling second buffer? */ - mpx_sep [port] [rw] = mpx_put [port] [rw]; /* move separator to end of next buffer */ - } - - mpx_flags [port] &= ~emptying_flags [rw]; /* clear emptying flag */ - } - -if (DEBUG_PRI (mpx_dev, DEB_BUF)) - fprintf (sim_deb, ">>MPX buf: Port %d cancelled %s buffer\n", port, io_op [rw]); -return; -} - - -/* Get the buffer length. - - The current length of the selected buffer (put or get) is returned. For ease - of use, the returned length does NOT include the header byte, i.e., it - reflects only the characters contained in the buffer. - - If the put buffer is selected, and the buffer is filling, or the get buffer - is selected, and the buffer is not emptying, then subtract one from the - length for the allocated header. -*/ - -static uint32 buf_len (IO_OPER rw, uint32 port, BUF_SELECT which) -{ -int32 length; - -if (which == put) - length = mpx_put [port] [rw] - mpx_sep [port] [rw] - /* calculate length */ - ((mpx_flags [port] & filling_flags [rw]) != 0); /* account for allocated header */ - -else { - length = mpx_sep [port] [rw] - mpx_get [port] [rw]; /* calculate length */ - - if (length && !(mpx_flags [port] & emptying_flags [rw])) /* not empty and not yet emptying? */ - length = length - 1; /* account for allocated header */ - } - -if (length < 0) /* is length negative? */ - return length + buf_size [rw]; /* account for wraparound */ -else - return length; -} - - -/* Return the number of free buffers available. - - Either 0, 1, or 2 free buffers will be available. A buffer is available if - it contains no characters (including the header byte). -*/ - -static uint32 buf_avail (IO_OPER rw, uint32 port) -{ -if (mpx_get [port] [rw] == mpx_put [port] [rw]) /* get and put indexes equal? */ - return 2; /* all buffers are free */ - -else if ((mpx_get [port] [rw] != mpx_sep [port] [rw]) && /* get, separator, and put */ - (mpx_sep [port] [rw] != mpx_put [port] [rw])) /* all different? */ - return 0; /* no buffers are free */ - -else - return 1; /* one buffer free */ -} +/* hp2100_mpx.c: HP 12792C eight-channel asynchronous multiplexer simulator + + Copyright (c) 2008-2014, J. David Bryan + + 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 + THE AUTHOR 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 the author shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from the author. + + MPX 12792C 8-channel multiplexer card + + 24-Dec-14 JDB Added casts for explicit downward conversions + 10-Jan-13 MP Added DEV_MUX and additional DEVICE field values + 28-Dec-12 JDB Allow direct attach to the poll unit only when restoring + 10-Feb-12 JDB Deprecated DEVNO in favor of SC + Removed DEV_NET to allow restoration of listening port + 28-Mar-11 JDB Tidied up signal handling + 26-Oct-10 JDB Changed I/O signal handler for revised signal model + 25-Nov-08 JDB Revised for new multiplexer library SHOW routines + 14-Nov-08 JDB Cleaned up VC++ size mismatch warnings for zero assignments + 03-Oct-08 JDB Fixed logic for ENQ/XOFF transmit wait + 07-Sep-08 JDB Changed Telnet poll to connect immediately after reset or attach + 10-Aug-08 JDB Added REG_FIT to register variables < 32-bit size + 26-Jun-08 JDB Rewrote device I/O to model backplane signals + 26-May-08 JDB Created MPX device + + References: + - HP 12792B 8-Channel Asynchronous Multiplexer Subsystem Installation and + Reference Manual (12792-90020, Jul-1984) + - HP 12792B/C 8-Channel Asynchronous Multiplexer Subsystem User's Manual + (5955-8867, Jun-1993) + - HP 12792B/C 8-Channel Asynchronous Multiplexer Subsystem Configuration Guide + (5955-8868, Jun-1993) + - HP 1000 series 8-channel Multiplexer Firmware External Reference Specification + (October 19, 1982) + - HP 12792/12040 Multiplexer Firmware Source (24999-18312, revision C) + - Zilog Components Data Book (00-2034-04, 1985) + + + The 12792A/B/C/D was an eight-line asynchronous serial multiplexer that + connected terminals, modems, serial line printers, and "black box" devices + that used the RS-232 standard to the CPU. It used an on-board microprocessor + and provided input and output buffering to support block-mode reads from HP + 264x and 262x terminals at speeds up to 19.2K baud. The card handled + character editing, echoing, ENQ/ACK handshaking, and read terminator + detection, substantially reducing the load on the CPU over the earlier 12920 + multiplexer. It was supported by HP under RTE-MIII, RTE-IVB, and RTE-6/VM. + Under simulation, it connects with HP terminal emulators via Telnet to a + user-specified port. + + The single interface card contained a Z80 CPU, DMA controller, CTC, four + two-channel SIO UARTs, 16K of RAM, 8K of ROM, and I/O backplane latches and + control circuitry. The card executed a high-level command set, and data + transfer to and from the CPU was via the on-board DMA controller and the DCPC + in the CPU. + + The 12792 for the M/E/F series and the 12040 multiplexer for the A/L series + differed only in backplane design. Early ROMs were card-specific, but later + ones were interchangeable; the code would determine whether it was executing + on an MEF card or an AL card. + + Four major firmware revisions were made. These were labelled "A", "B", "C", + and "D". The A, B, and C revisions were interchangeable from the perspective + of the OS driver; the D was different and required an updated driver. + Specifically: + + Op. Sys. Driver Part Number Rev + -------- ------ -------------------- --- + RTE-MIII DVM00 12792-16002 Rev.2032 A + RTE-IVB DVM00 12792-16002 Rev.5000 ABC + + RTE-6/VM DVM00 12792-16002 Rev.5000 ABC + RTE-6/VM DV800 92084-15068 Rev.6000 D + + RTE-A IDM00 92077-16754 Rev.5020 ABC + RTE-A ID800 92077-16887 Rev.6200 D + + Revisions A-C have an upward-compatible command set that partitions each OS + request into several sub-commands. Each command is initiated by setting the + control flip-flop on the card, which causes a non-maskable interrupt (NMI) on + the card's Z80 processor. + + The D-revision firmware uses a completely different command set. The + commands are slightly modified versions of the original EXEC calls (read, + write, and control) and are generally passed to the card directly for action. + + This simulation supports the C revision. D-revision support may be added + later. + + Twelve programmable baud rates are supported by the multiplexer. These + "realistic" rates are simulated by scheduling I/O service based on the + appropriate number of 1000 E-Series instructions for the rate selected. + + The simulation provides both the "realistic timing" described above, as well + as an optimized "fast timing" option. Optimization makes three improvements: + + 1. Buffered characters are transferred in blocks. + + 2. ENQ/ACK handshaking is done locally without involving the client. + + 3. BS and DEL respond visually more like prior RTE terminal drivers. + + HP did not offer a functional diagnostic for the 12792. Instead, a Z80 + program that tested the operation of the hardware was downloaded to the card, + and a "go/no-go" status was returned to indicate the hardware condition. + Because this is a functional simulation of the multiplexer and not a Z80 + emulation, the diagnostic cannot be used to test the implementation. + + Implementation notes: + + 1. The 12792 had two baud-rate generators that were assigned to lines by the + wiring configuration in the I/O cable connector hood. Two of the four + CTC counters were used to implement the BRGs for all eight lines. Only + subsets of the configurable rates were allowed for lines connected to the + same BRG, and assigning mutually incompatible rates caused corruption of + the rates on lines assigned earlier. Under simulation, any baud rate may + be assigned to any line without interaction, and assignments of lines to + BRGs is not implemented. + + 2. Revisions B and C added support for the 37214A Systems Modem subsystem + and the RTE-A Virtual Control Panel (VCP). Under simulation, the modem + commands return status codes indicating that no modems are present, and + the VCP commands are not implemented. +*/ + + +#include + +#include "hp2100_defs.h" +#include "sim_tmxr.h" + + +/* Bitfield constructor. + + Given a bitfield starting bit number and width in bits, declare two + constants: one for the starting bit number, and one for the positioned field + mask. That is, given a definition such as: + + BITFIELD(SMALLFIELD,5,2) + + ...this macro produces: + + static const uint32 SMALLFIELD_V = 5; + static const uint32 SMALLFIELD = ((1 << (2)) - 1) << (5); + + The latter reduces to 3 << 5, or 0x00000060. + + Note: C requires constant expressions in initializers for objects with static + storage duration, so initializing a static object with a BITFIELD value is + illegal (a "static const" object is not a constant!). +*/ + +#define BITFIELD(NAME,STARTBIT,BITWIDTH) \ + static const uint32 NAME ## _V = STARTBIT; \ + static const uint32 NAME = ((1 << (BITWIDTH)) - 1) << (STARTBIT); + + +/* Program constants */ + +#define MPX_DATE_CODE 2416 /* date code for C firmware */ + +#define RD_BUF_SIZE 514 /* read buffer size */ +#define WR_BUF_SIZE 514 /* write buffer size */ + +#define RD_BUF_LIMIT 254 /* read buffer limit */ +#define WR_BUF_LIMIT 254 /* write buffer limit */ + +#define KEY_DEFAULT 255 /* default port key */ + + +/* Service times: + + DATA_DELAY = 1.25 us (Z80 DMA data word transfer time) + PARAM_DELAY = 25 us (STC to STF for first word of two-word command) + CMD_DELAY = 400 us (STC to STF for one or two-word command execution) +*/ + +#define DATA_DELAY 2 /* data transfer time */ +#define PARAM_DELAY 40 /* parameter request time */ +#define CMD_DELAY 630 /* command completion time */ + + +/* Unit references */ + +#define MPX_PORTS 8 /* number of visible units */ +#define MPX_CNTLS 2 /* number of control units */ + +#define mpx_cntl (mpx_unit [MPX_PORTS + 0]) /* controller unit */ +#define mpx_poll (mpx_unit [MPX_PORTS + 1]) /* Telnet polling unit */ + + +/* Character constants */ + +#define EOT '\004' +#define ENQ '\005' +#define ACK '\006' +#define BS '\010' +#define LF '\012' +#define CR '\015' +#define DC1 '\021' +#define DC2 '\022' +#define DC3 '\023' +#define ESC '\033' +#define RS '\036' +#define DEL '\177' + +#define XON DC1 +#define XOFF DC3 + + +/* Device flags */ + +#define DEV_V_REV_D (DEV_V_UF + 0) /* firmware revision D (not implemented) */ + +#define DEV_REV_D (1 << DEV_V_REV_D) + + +/* Unit flags */ + +#define UNIT_V_FASTTIME (UNIT_V_UF + 0) /* fast timing mode */ +#define UNIT_V_CAPSLOCK (UNIT_V_UF + 1) /* caps lock mode */ + +#define UNIT_FASTTIME (1 << UNIT_V_FASTTIME) +#define UNIT_CAPSLOCK (1 << UNIT_V_CAPSLOCK) + + +/* Debug flags */ + +#define DEB_CMDS (1 << 0) /* commands and status */ +#define DEB_CPU (1 << 1) /* CPU I/O */ +#define DEB_BUF (1 << 2) /* buffer gets and puts */ +#define DEB_XFER (1 << 3) /* character reads and writes */ + + +/* Multiplexer commands for revisions A/B/C. + + Commands are either one or two words in length. The one-word format is: + + +-------------------------------+-------------------------------+ + | 0 . 1 | command opcode | command parameter | + +-------------------------------+-------------------------------+ + 15 - 8 7 - 0 + + The two-word format is: + + +-------------------------------+-------------------------------+ + | 1 . 1 | command opcode | command value | + +-------------------------------+-------------------------------+ + | command parameter | + +---------------------------------------------------------------+ + 15 - 8 7 - 0 + + Commands implemented by firmware revision: + + Rev Cmd Value Operation Status Value(s) Returned + --- --- ----- ------------------------------- ------------------------------- + ABC 100 - No operation 000000 + ABC 101 - Reset to power-on defaults 100000 + ABC 102 - Enable unsolicited input None, unless UI pending + ABC 103 1 Disable unsolicited interrupts 000000 + ABC 103 2 Abort DMA transfer 000000 + ABC 104 - Acknowledge Second word of UI status + ABC 105 key Cancel first receive buffer 000000 + ABC 106 key Cancel all received buffers 000000 + ABC 107 - Fast binary read (none) + + -BC 140 chr VCP put byte 000000 + -BC 141 - VCP put buffer 000000 + -BC 142 - VCP get byte Character from port 0 + -BC 143 - VCP get buffer 000120 + -BC 144 - Exit VCP mode 000000 + -BC 157 - Enter VCP mode 000000 + + ABC 300 - No operation 000000 + ABC 301 key Request write buffer 000000 or 000376 + ABC 302 key Write data to buffer (none) + ABC 303 key Set port key 000000 or date code of firmware + ABC 304 key Set receive type 000000 + ABC 305 key Set character count 000000 + ABC 306 key Set flow control 000000 + ABC 307 key Read data from buffer (none) + ABC 310 - Download executable (none) + + -BC 311 key Connect line 000000 or 140000 if no modem + -BC 312 key Disconnect line 000000 or 140000 if no modem + -BC 315 key Get modem/port status modem status or 000200 if no modem + -BC 316 key Enable/disable modem loopback 000000 or 140000 if no modem + -BC 320 key Terminate active receive buffer 000000 +*/ + + +/* One-word command codes */ + +#define CMD_NOP 0100 /* No operation */ +#define CMD_RESET 0101 /* Reset firmware to power-on defaults */ +#define CMD_ENABLE_UI 0102 /* Enable unsolicited input */ +#define CMD_DISABLE 0103 /* Disable interrupts / Abort DMA Transfer */ +#define CMD_ACK 0104 /* Acknowledge */ +#define CMD_CANCEL 0105 /* Cancel first receive buffer */ +#define CMD_CANCEL_ALL 0106 /* Cancel all received buffers */ +#define CMD_BINARY_READ 0107 /* Fast binary read */ + +#define CMD_VCP_PUT 0140 /* VCP put byte */ +#define CMD_VCP_PUT_BUF 0141 /* VCP put buffer */ +#define CMD_VCP_GET 0142 /* VCP get byte */ +#define CMD_VCP_GET_BUF 0143 /* VCP get buffer */ +#define CMD_VCP_EXIT 0144 /* Exit VCP mode */ +#define CMD_VCP_ENTER 0157 /* Enter VCP mode */ + + +/* Two-word command codes */ + +#define CMD_REQ_WRITE 0301 /* Request write buffer */ +#define CMD_WRITE 0302 /* Write data to buffer */ +#define CMD_SET_KEY 0303 /* Set port key */ +#define CMD_SET_RCV 0304 /* Set receive type */ +#define CMD_SET_COUNT 0305 /* Set character count */ +#define CMD_SET_FLOW 0306 /* Set flow control */ +#define CMD_READ 0307 /* Read data from buffer */ +#define CMD_DL_EXEC 0310 /* Download executable */ + +#define CMD_CN_LINE 0311 /* Connect line */ +#define CMD_DC_LINE 0312 /* Disconnect line */ +#define CMD_GET_STATUS 0315 /* Get modem/port status */ +#define CMD_LOOPBACK 0316 /* Enable/disable modem loopback */ +#define CMD_TERM_BUF 0320 /* Terminate active receive buffer */ + + +/* Sub-command codes */ + +#define SUBCMD_UI 1 /* Disable unsolicited interrupts */ +#define SUBCMD_DMA 2 /* Abort DMA transfer */ + +#define CMD_TWO_WORDS 0200 /* two-word command flag */ + + +/* Unsolicited interrupt reasons */ + +#define UI_REASON_V 8 /* interrupt reason */ +#define UI_REASON (((1 << 8) - 1) << (UI_REASON_V)) /* (UI_REASON_V must be a constant!) */ + +BITFIELD (UI_PORT, 0, 3) /* interrupt port number */ + +#define UI_WRBUF_AVAIL (1 << UI_REASON_V) /* Write buffer available */ +#define UI_LINE_CONN (2 << UI_REASON_V) /* Modem line connected */ +#define UI_LINE_DISC (3 << UI_REASON_V) /* Modem line disconnected */ +#define UI_BRK_RECD (4 << UI_REASON_V) /* Break received */ +#define UI_RDBUF_AVAIL (5 << UI_REASON_V) /* Read buffer available */ + + +/* Return status to CPU */ + +#define ST_OK 0000000 /* Command OK */ +#define ST_DIAG_OK 0000015 /* Diagnostic passes */ +#define ST_VCP_SIZE 0000120 /* VCP buffer size = 80 chars */ +#define ST_NO_SYSMDM 0000200 /* No systems modem card */ +#define ST_TEST_OK 0100000 /* Self test OK */ +#define ST_NO_MODEM 0140000 /* No modem card on port */ +#define ST_BAD_KEY 0135320 /* Bad port key = 0xBAD0 */ + + +/* Bit flags */ + +#define RS_OVERFLOW 0040000 /* Receive status: buffer overflow occurred */ +#define RS_PARTIAL 0020000 /* Receive status: buffer is partial */ +#define RS_ETC_RS 0014000 /* Receive status: terminated by RS */ +#define RS_ETC_DC2 0010000 /* Receive status: terminated by DC2 */ +#define RS_ETC_CR 0004000 /* Receive status: terminated by CR */ +#define RS_ETC_EOT 0000000 /* Receive status: terminated by EOT */ +#define RS_CHAR_COUNT 0003777 /* Receive status: character count */ + +#define WR_NO_ENQACK 0020000 /* Write: no ENQ/ACK this xfer */ +#define WR_ADD_CRLF 0010000 /* Write: add CR/LF if not '_' */ +#define WR_PARTIAL 0004000 /* Write: write is partial */ +#define WR_LENGTH 0003777 /* Write: write length in bytes */ + +#define RT_END_ON_CR 0000200 /* Receive type: end xfer on CR */ +#define RT_END_ON_RS 0000100 /* Receive type: end xfer on RS */ +#define RT_END_ON_EOT 0000040 /* Receive type: end xfer on EOT */ +#define RT_END_ON_DC2 0000020 /* Receive type: end xfer on DC2 */ +#define RT_END_ON_CNT 0000010 /* Receive type: end xfer on count */ +#define RT_END_ON_CHAR 0000004 /* Receive type: end xfer on character */ +#define RT_ENAB_EDIT 0000002 /* Receive type: enable input editing */ +#define RT_ENAB_ECHO 0000001 /* Receive type: enable input echoing */ + +#define FC_FORCE_XON 0000002 /* Flow control: force XON */ +#define FC_XONXOFF 0000001 /* Flow control: enable XON/XOFF */ + +#define CL_GUARD 0000040 /* Connect line: guard tone off or on */ +#define CL_STANDARD 0000020 /* Connect line: standard 212 or V.22 */ +#define CL_BITS 0000010 /* Connect line: bits 10 or 9 */ +#define CL_MODE 0000004 /* Connect line: mode originate or answer */ +#define CL_DIAL 0000002 /* Connect line: dial manual or automatic */ +#define CL_SPEED 0000001 /* Connect line: speed low or high */ + +#define DL_AUTO_ANSWER 0000001 /* Disconnect line: auto-answer enable or disable */ + +#define LB_SPEED 0000004 /* Loopback test: speed low or high */ +#define LB_MODE 0000002 /* Loopback test: mode analog or digital */ +#define LB_TEST 0000001 /* Loopback test: test disable or enable */ + +#define GS_NO_SYSMDM 0000200 /* Get status: systems modem present or absent */ +#define GS_SYSMDM_TO 0000100 /* Get status: systems modem OK or timed out */ +#define GS_NO_MODEM 0000040 /* Get status: modem present or absent */ +#define GS_SPEED 0000020 /* Get status: speed low or high */ +#define GS_LINE 0000001 /* Get status: line disconnected or connected */ + + +/* Bit fields (name, starting bit, bit width) */ + +BITFIELD (CMD_OPCODE, 8, 8) /* Command: opcode */ +BITFIELD (CMD_KEY, 0, 8) /* Command: key */ + +BITFIELD (SK_BPC, 14, 2) /* Set key: bits per character */ +BITFIELD (SK_MODEM, 13, 1) /* Set key: hardwired or modem */ +BITFIELD (SK_BRG, 12, 1) /* Set key: baud rate generator 0/1 */ +BITFIELD (SK_STOPBITS, 10, 2) /* Set key: stop bits */ +BITFIELD (SK_PARITY, 8, 2) /* Set key: parity select */ +BITFIELD (SK_ENQACK, 7, 1) /* Set key: disable or enable ENQ/ACK */ +BITFIELD (SK_BAUDRATE, 3, 4) /* Set key: port baud rate */ +BITFIELD (SK_PORT, 0, 3) /* Set key: port number */ + +BITFIELD (FL_ALERT, 11, 1) /* Port flags: alert for terminate recv buffer */ +BITFIELD (FL_XOFF, 10, 1) /* Port flags: XOFF stopped transmission */ +BITFIELD (FL_BREAK, 9, 1) /* Port flags: UI / break detected */ +BITFIELD (FL_HAVEBUF, 8, 1) /* Port flags: UI / read buffer available */ +BITFIELD (FL_WANTBUF, 7, 1) /* Port flags: UI / write buffer available */ +BITFIELD (FL_RDOVFLOW, 6, 1) /* Port flags: read buffers overflowed */ +BITFIELD (FL_RDFILL, 5, 1) /* Port flags: read buffer is filling */ +BITFIELD (FL_RDEMPT, 4, 1) /* Port flags: read buffer is emptying */ +BITFIELD (FL_WRFILL, 3, 1) /* Port flags: write buffer is filling */ +BITFIELD (FL_WREMPT, 2, 1) /* Port flags: write buffer is emptying */ +BITFIELD (FL_WAITACK, 1, 1) /* Port flags: ENQ sent, waiting for ACK */ +BITFIELD (FL_DO_ENQACK, 0, 1) /* Port flags: do ENQ/ACK handshake */ + +#define SK_BRG_1 SK_BRG +#define SK_BRG_0 0 + +#define FL_RDFLAGS (FL_RDEMPT | FL_RDFILL | FL_RDOVFLOW) +#define FL_WRFLAGS (FL_WREMPT | FL_WRFILL) +#define FL_UI_PENDING (FL_WANTBUF | FL_HAVEBUF | FL_BREAK) + +#define ACK_LIMIT 1000 /* poll timeout for ACK response */ +#define ENQ_LIMIT 80 /* output chars before ENQ */ + + +/* Packed field values */ + +#define SK_BPC_5 (0 << SK_BPC_V) +#define SK_BPC_6 (1 << SK_BPC_V) +#define SK_BPC_7 (2 << SK_BPC_V) +#define SK_BPC_8 (3 << SK_BPC_V) + +#define SK_STOP_1 (1 << SK_STOPBITS_V) +#define SK_STOP_15 (2 << SK_STOPBITS_V) +#define SK_STOP_2 (3 << SK_STOPBITS_V) + +#define SK_BAUD_NOCHG (0 << SK_BAUDRATE_V) +#define SK_BAUD_50 (1 << SK_BAUDRATE_V) +#define SK_BAUD_75 (2 << SK_BAUDRATE_V) +#define SK_BAUD_110 (3 << SK_BAUDRATE_V) +#define SK_BAUD_1345 (4 << SK_BAUDRATE_V) +#define SK_BAUD_150 (5 << SK_BAUDRATE_V) +#define SK_BAUD_300 (6 << SK_BAUDRATE_V) +#define SK_BAUD_1200 (7 << SK_BAUDRATE_V) +#define SK_BAUD_1800 (8 << SK_BAUDRATE_V) +#define SK_BAUD_2400 (9 << SK_BAUDRATE_V) +#define SK_BAUD_4800 (10 << SK_BAUDRATE_V) +#define SK_BAUD_9600 (11 << SK_BAUDRATE_V) +#define SK_BAUD_19200 (12 << SK_BAUDRATE_V) + + +/* Default values */ + +#define SK_PWRUP_0 (SK_BPC_8 | SK_BRG_0 | SK_STOP_1 | SK_BAUD_9600) +#define SK_PWRUP_1 (SK_BPC_8 | SK_BRG_1 | SK_STOP_1 | SK_BAUD_9600) + +#define RT_PWRUP (RT_END_ON_CR | RT_END_ON_CHAR | RT_ENAB_EDIT | RT_ENAB_ECHO) + + +/* Command helpers */ + +#define GET_OPCODE(w) (((w) & CMD_OPCODE) >> CMD_OPCODE_V) +#define GET_KEY(w) (((w) & CMD_KEY) >> CMD_KEY_V) +#define GET_BPC(w) (((w) & SK_BPC) >> SK_BPC_V) +#define GET_BAUDRATE(w) (((w) & SK_BAUDRATE) >> SK_BAUDRATE_V) +#define GET_PORT(w) (((w) & SK_PORT) >> SK_PORT_V) +#define GET_UIREASON(w) (((w) & UI_REASON) >> UI_REASON_V) +#define GET_UIPORT(w) (((w) & UI_PORT) >> UI_PORT_V) + + +/* Multiplexer controller state variables */ + +typedef enum { idle, cmd, param, exec } STATE; + +STATE mpx_state = idle; /* controller state */ + +uint16 mpx_ibuf = 0; /* status/data in */ +uint16 mpx_obuf = 0; /* command/data out */ + +uint32 mpx_cmd = 0; /* current command */ +uint32 mpx_param = 0; /* current parameter */ +uint32 mpx_port = 0; /* current port number for R/W */ +uint32 mpx_portkey = 0; /* current port's key */ + int32 mpx_iolen = 0; /* length of current I/O xfer */ + +t_bool mpx_uien = FALSE; /* unsolicited interrupts enabled */ +uint32 mpx_uicode = 0; /* unsolicited interrupt reason and port */ + +struct { + FLIP_FLOP control; /* control flip-flop */ + FLIP_FLOP flag; /* flag flip-flop */ + FLIP_FLOP flagbuf; /* flag buffer flip-flop */ + } mpx = { CLEAR, CLEAR, CLEAR }; + +/* Multiplexer per-line state variables */ + +uint8 mpx_key [MPX_PORTS]; /* port keys */ +uint16 mpx_config [MPX_PORTS]; /* port configuration */ +uint16 mpx_rcvtype [MPX_PORTS]; /* receive type */ +uint16 mpx_charcnt [MPX_PORTS]; /* character count */ +uint16 mpx_flowcntl [MPX_PORTS]; /* flow control */ +uint8 mpx_enq_cntr [MPX_PORTS]; /* ENQ character counter */ +uint16 mpx_ack_wait [MPX_PORTS]; /* ACK wait timer */ +uint16 mpx_flags [MPX_PORTS]; /* line state flags */ + +/* Multiplexer buffer selectors */ + +typedef enum { ioread, iowrite } IO_OPER; /* I/O operation */ +typedef enum { get, put } BUF_SELECT; /* buffer selector */ + +static const char *const io_op [] = { "read", /* operation names */ + "write" }; + +static const uint16 buf_size [] = { RD_BUF_SIZE, /* buffer sizes */ + WR_BUF_SIZE }; + +static uint32 emptying_flags [2]; /* buffer emptying flags [IO_OPER] */ +static uint32 filling_flags [2]; /* buffer filling flags [IO_OPER] */ + + +/* Multiplexer per-line buffer variables */ + +typedef uint16 BUF_INDEX [MPX_PORTS] [2]; /* buffer index (read and write) */ + +BUF_INDEX mpx_put; /* read/write buffer add index */ +BUF_INDEX mpx_sep; /* read/write buffer separator index */ +BUF_INDEX mpx_get; /* read/write buffer remove index */ + +uint8 mpx_rbuf [MPX_PORTS] [RD_BUF_SIZE]; /* read buffer */ +uint8 mpx_wbuf [MPX_PORTS] [WR_BUF_SIZE]; /* write buffer */ + + +/* Multiplexer local routines */ + +static t_bool exec_command (void); +static void poll_connection (void); +static void controller_reset (void); +static uint32 service_time (uint16 control_word); +static int32 key_to_port (uint32 key); + +static void buf_init (IO_OPER rw, uint32 port); +static uint8 buf_get (IO_OPER rw, uint32 port); +static void buf_put (IO_OPER rw, uint32 port, uint8 ch); +static void buf_remove (IO_OPER rw, uint32 port); +static void buf_term (IO_OPER rw, uint32 port, uint8 header); +static void buf_free (IO_OPER rw, uint32 port); +static void buf_cancel (IO_OPER rw, uint32 port, BUF_SELECT which); +static uint16 buf_len (IO_OPER rw, uint32 port, BUF_SELECT which); +static uint32 buf_avail (IO_OPER rw, uint32 port); + + +/* Multiplexer global routines */ + +IOHANDLER mpx_io; + +t_stat mpx_line_svc (UNIT *uptr); +t_stat mpx_cntl_svc (UNIT *uptr); +t_stat mpx_poll_svc (UNIT *uptr); +t_stat mpx_reset (DEVICE *dptr); +t_stat mpx_attach (UNIT *uptr, char *cptr); +t_stat mpx_detach (UNIT *uptr); +t_stat mpx_status (FILE *st, UNIT *uptr, int32 val, void *desc); +t_stat mpx_set_frev (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat mpx_show_frev (FILE *st, UNIT *uptr, int32 val, void *desc); + + +/* MPX data structures. + + mpx_order MPX line connection order table + mpx_ldsc MPX terminal multiplexer line descriptors + mpx_desc MPX terminal multiplexer device descriptor + mpx_dib MPX device information block + mpx_unit MPX unit list + mpx_reg MPX register list + mpx_mod MPX modifier list + mpx_deb MPX debug list + mpx_dev MPX device descriptor + + The first eight units correspond to the eight multiplexer line ports. These + handle character I/O via the Telnet library. A ninth unit acts as the card + controller, executing commands and transferring data to and from the I/O + buffers. A tenth unit is responsible for polling for connections and socket + I/O. It also holds the master socket. + + The character I/O service routines run only when there are characters to read + or write. They operate at the approximate baud rates of the terminals (in + CPU instructions per second) in order to be compatible with the OS drivers. + The controller service routine runs only when a command is executing or a + data transfer to or from the CPU is in progress. The Telnet poll must run + continuously, but it may operate much more slowly, as the only requirement is + that it must not present a perceptible lag to human input. To be compatible + with CPU idling, it is co-scheduled with the master poll timer, which uses a + ten millisecond period. + + The controller and poll units are hidden by disabling them, so as to present + a logical picture of the multiplexer to the user. +*/ + +DEVICE mpx_dev; + +int32 mpx_order [MPX_PORTS] = { -1 }; /* connection order */ +TMLN mpx_ldsc [MPX_PORTS] = { { 0 } }; /* line descriptors */ +TMXR mpx_desc = { MPX_PORTS, 0, 0, mpx_ldsc, mpx_order }; /* device descriptor */ + +DIB mpx_dib = { &mpx_io, MPX }; + +UNIT mpx_unit [] = { + { UDATA (&mpx_line_svc, UNIT_FASTTIME, 0) }, /* terminal I/O line 0 */ + { UDATA (&mpx_line_svc, UNIT_FASTTIME, 0) }, /* terminal I/O line 1 */ + { UDATA (&mpx_line_svc, UNIT_FASTTIME, 0) }, /* terminal I/O line 2 */ + { UDATA (&mpx_line_svc, UNIT_FASTTIME, 0) }, /* terminal I/O line 3 */ + { UDATA (&mpx_line_svc, UNIT_FASTTIME, 0) }, /* terminal I/O line 4 */ + { UDATA (&mpx_line_svc, UNIT_FASTTIME, 0) }, /* terminal I/O line 5 */ + { UDATA (&mpx_line_svc, UNIT_FASTTIME, 0) }, /* terminal I/O line 6 */ + { UDATA (&mpx_line_svc, UNIT_FASTTIME, 0) }, /* terminal I/O line 7 */ + { UDATA (&mpx_cntl_svc, UNIT_DIS, 0) }, /* controller unit */ + { UDATA (&mpx_poll_svc, UNIT_ATTABLE | UNIT_DIS, POLL_FIRST) } /* Telnet poll unit */ + }; + +REG mpx_reg [] = { + { DRDATA (STATE, mpx_state, 3) }, + { ORDATA (IBUF, mpx_ibuf, 16), REG_FIT }, + { ORDATA (OBUF, mpx_obuf, 16), REG_FIT }, + + { ORDATA (CMD, mpx_cmd, 8) }, + { ORDATA (PARAM, mpx_param, 16) }, + + { DRDATA (PORT, mpx_port, 8), PV_LEFT }, + { DRDATA (PORTKEY, mpx_portkey, 8), PV_LEFT }, + { DRDATA (IOLEN, mpx_iolen, 16), PV_LEFT }, + + { FLDATA (UIEN, mpx_uien, 0) }, + { GRDATA (UIPORT, mpx_uicode, 10, 3, 0) }, + { GRDATA (UICODE, mpx_uicode, 10, 3, UI_REASON_V) }, + + { BRDATA (KEYS, mpx_key, 10, 8, MPX_PORTS) }, + { BRDATA (PCONFIG, mpx_config, 8, 16, MPX_PORTS) }, + { BRDATA (RCVTYPE, mpx_rcvtype, 8, 16, MPX_PORTS) }, + { BRDATA (CHARCNT, mpx_charcnt, 8, 16, MPX_PORTS) }, + { BRDATA (FLOWCNTL, mpx_flowcntl, 8, 16, MPX_PORTS) }, + + { BRDATA (ENQCNTR, mpx_enq_cntr, 10, 7, MPX_PORTS) }, + { BRDATA (ACKWAIT, mpx_ack_wait, 10, 10, MPX_PORTS) }, + { BRDATA (PFLAGS, mpx_flags, 2, 12, MPX_PORTS) }, + + { BRDATA (RBUF, mpx_rbuf, 8, 8, MPX_PORTS * RD_BUF_SIZE) }, + { BRDATA (WBUF, mpx_wbuf, 8, 8, MPX_PORTS * WR_BUF_SIZE) }, + + { BRDATA (GET, mpx_get, 10, 10, MPX_PORTS * 2) }, + { BRDATA (SEP, mpx_sep, 10, 10, MPX_PORTS * 2) }, + { BRDATA (PUT, mpx_put, 10, 10, MPX_PORTS * 2) }, + + { FLDATA (CTL, mpx.control, 0) }, + { FLDATA (FLG, mpx.flag, 0) }, + { FLDATA (FBF, mpx.flagbuf, 0) }, + { ORDATA (SC, mpx_dib.select_code, 6), REG_HRO }, + { ORDATA (DEVNO, mpx_dib.select_code, 6), REG_HRO }, + + { BRDATA (CONNORD, mpx_order, 10, 32, MPX_PORTS), REG_HRO }, + { NULL } + }; + +MTAB mpx_mod [] = { + { UNIT_FASTTIME, UNIT_FASTTIME, "fast timing", "FASTTIME", NULL, NULL, NULL }, + { UNIT_FASTTIME, 0, "realistic timing", "REALTIME", NULL, NULL, NULL }, + + { UNIT_CAPSLOCK, UNIT_CAPSLOCK, "CAPS LOCK down", "CAPSLOCK", NULL, NULL, NULL }, + { UNIT_CAPSLOCK, 0, "CAPS LOCK up", "NOCAPSLOCK", NULL, NULL, NULL }, + + { MTAB_XTD | MTAB_VDV, 0, "REV", NULL, &mpx_set_frev, &mpx_show_frev, NULL }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "LINEORDER", "LINEORDER", &tmxr_set_lnorder, &tmxr_show_lnorder, &mpx_desc }, + + { MTAB_XTD | MTAB_VUN | MTAB_NC, 0, "LOG", "LOG", &tmxr_set_log, &tmxr_show_log, &mpx_desc }, + { MTAB_XTD | MTAB_VUN | MTAB_NC, 0, NULL, "NOLOG", &tmxr_set_nolog, NULL, &mpx_desc }, + + { MTAB_XTD | MTAB_VDV, 0, "", NULL, NULL, &mpx_status, &mpx_desc }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "CONNECTIONS", NULL, NULL, &tmxr_show_cstat, &mpx_desc }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "STATISTICS", NULL, NULL, &tmxr_show_cstat, &mpx_desc }, + { MTAB_XTD | MTAB_VDV, 1, NULL, "DISCONNECT", &tmxr_dscln, NULL, &mpx_desc }, + { MTAB_XTD | MTAB_VDV, 0, "SC", "SC", &hp_setsc, &hp_showsc, &mpx_dev }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &mpx_dev }, + + { 0 } + }; + +DEBTAB mpx_deb [] = { + { "CMDS", DEB_CMDS }, + { "CPU", DEB_CPU }, + { "BUF", DEB_BUF }, + { "XFER", DEB_XFER }, + { NULL, 0 } + }; + +DEVICE mpx_dev = { + "MPX", /* device name */ + mpx_unit, /* unit array */ + mpx_reg, /* register array */ + mpx_mod, /* modifier array */ + MPX_PORTS + MPX_CNTLS, /* number of units */ + 10, /* address radix */ + 31, /* address width */ + 1, /* address increment */ + 8, /* data radix */ + 8, /* data width */ + &tmxr_ex, /* examine routine */ + &tmxr_dep, /* deposit routine */ + &mpx_reset, /* reset routine */ + NULL, /* boot routine */ + &mpx_attach, /* attach routine */ + &mpx_detach, /* detach routine */ + &mpx_dib, /* device information block */ + DEV_DEBUG | DEV_DISABLE | DEV_MUX, /* device flags */ + 0, /* debug control flags */ + mpx_deb, /* debug flag name table */ + NULL, /* memory size change routine */ + NULL, /* logical device name */ + NULL, /* help routine */ + NULL, /* help attach routine*/ + (void *) &mpx_desc /* help context */ + }; + + +/* I/O signal handler. + + Commands are sent to the card via an OTA/B. Issuing an STC SC,C causes the + mux to accept the word (STC causes a NMI on the card). If the command uses + one word, command execution will commence, and the flag will set on + completion. If the command uses two words, the flag will be set, indicating + that the second word should be output via an OTA/B. Command execution will + commence upon receipt, and the flag will set on completion. + + When the flag sets for command completion, status or data may be read from + the card via an LIA/B. If additional status or data words are expected, the + flag will set when they are available. + + A command consists of an opcode in the high byte, and a port key or command + parameter in the low byte. Undefined commands are treated as NOPs. + + The card firmware executes commands as part of a twelve-event round-robin + scheduling poll. The card NMI service routine simply sets a flag that is + interrogated during polling. The poll sequence is advanced after each + command. This implies that successive commands incur a delay of at least one + poll-loop's execution time. On an otherwise quiescent card, this delay is + approximately 460 Z80 instructions, or about 950 usec. The average command + initiation time is half of that, or roughly 425 usec. + + If a detected command requires a second word, the card sits in a tight loop, + waiting for the OTx that indicates that the parameter is available. Command + initiation from parameter receipt is about 25 usec. + + For reads and writes to card buffers, the on-board DMA controller is used. + The CPU uses DCPC to handle the transfer, but the data transfer time is + limited by the Z80 DMA, which can process a word in about 1.25 usec. + + For most cards, the hardware POPIO signal sets the flag buffer and flag + flip-flops, while CRS clears the control flip-flop. For this card, the + control and flags are cleared together by CRS, and POPIO is not used. + + Implementation notes: + + 1. "Enable unsolicited input" is the only command that does not set the + device flag upon completion. Therefore, the CPU has no way of knowing + when the command has completed. Because the command in the input latch + is recorded in the NMI handler, but actual execution only begins when the + scheduler polls for the command indication, it is possible for another + command to be sent to the card before the "Enable unsolicited input" + command is recognized. In this case, the second command overwrites the + first and is executed by the scheduler poll. Under simulation, this + condition occurs when the OTx and STC processors are entered with + mpx_state = cmd. + + 2. The "Fast binary read" command inhibits all other commands until the card + is reset. +*/ + +uint32 mpx_io (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) +{ +static const char *output_state [] = { "Command", "Command override", "Parameter", "Data" }; +static const char *input_state [] = { "Status", "Invalid status", "Parameter", "Data" }; +const char *hold_or_clear = (signal_set & ioCLF ? ",C" : ""); +int32 delay; +IOSIGNAL signal; +IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ + +while (working_set) { + signal = IONEXT (working_set); /* isolate next signal */ + + switch (signal) { /* dispatch I/O signal */ + + case ioCLF: /* clear flag flip-flop */ + mpx.flag = mpx.flagbuf = CLEAR; /* clear flag and flag buffer */ + + if (DEBUG_PRI (mpx_dev, DEB_CMDS)) + fputs (">>MPX cmds: [CLF] Flag cleared\n", sim_deb); + break; + + + case ioSTF: /* set flag flip-flop */ + if (DEBUG_PRI (mpx_dev, DEB_CMDS)) + fputs (">>MPX cmds: [STF] Flag set\n", sim_deb); + /* fall into ENF */ + + case ioENF: /* enable flag */ + mpx.flag = mpx.flagbuf = SET; /* set flag and flag buffer */ + break; + + + case ioSFC: /* skip if flag is clear */ + setstdSKF (mpx); + break; + + + case ioSFS: /* skip if flag is set */ + setstdSKF (mpx); + break; + + + case ioIOI: /* I/O data input */ + stat_data = IORETURN (SCPE_OK, mpx_ibuf); /* return info */ + + if (DEBUG_PRI (mpx_dev, DEB_CPU)) + fprintf (sim_deb, ">>MPX cpu: [LIx%s] %s = %06o\n", + hold_or_clear, input_state [mpx_state], mpx_ibuf); + + if (mpx_state == exec) /* if this is input data word */ + sim_activate (&mpx_cntl, DATA_DELAY); /* continue transmission */ + break; + + + case ioIOO: /* I/O data output */ + mpx_obuf = IODATA (stat_data); /* save word */ + + if (DEBUG_PRI (mpx_dev, DEB_CPU)) + fprintf (sim_deb, ">>MPX cpu: [OTx%s] %s = %06o\n", + hold_or_clear, output_state [mpx_state], mpx_obuf); + + if (mpx_state == param) { /* if this is parameter word */ + sim_activate (&mpx_cntl, CMD_DELAY); /* do command now */ + + if (DEBUG_PRI (mpx_dev, DEB_CMDS)) + fprintf (sim_deb, ">>MPX cmds: [OTx%s] Command %03o parameter %06o scheduled, " + "time = %d\n", hold_or_clear, mpx_cmd, mpx_obuf, CMD_DELAY); + } + + else if (mpx_state == exec) /* else if this is output data word */ + sim_activate (&mpx_cntl, DATA_DELAY); /* then do transmission */ + break; + + + case ioCRS: /* control reset */ + controller_reset (); /* reset firmware to power-on defaults */ + mpx_obuf = 0; /* clear output buffer */ + + mpx.control = CLEAR; /* clear control */ + mpx.flagbuf = CLEAR; /* clear flag buffer */ + mpx.flag = CLEAR; /* clear flag */ + + if (DEBUG_PRI (mpx_dev, DEB_CMDS)) + fputs (">>MPX cmds: [CRS] Controller reset\n", sim_deb); + break; + + + case ioCLC: /* clear control flip-flop */ + mpx.control = CLEAR; /* clear control */ + + if (DEBUG_PRI (mpx_dev, DEB_CMDS)) + fprintf (sim_deb, ">>MPX cmds: [CLC%s] Control cleared\n", hold_or_clear); + break; + + + case ioSTC: /* set control flip-flop */ + mpx.control = SET; /* set control */ + + if (mpx_cmd == CMD_BINARY_READ) /* executing fast binary read? */ + break; /* further command execution inhibited */ + + mpx_cmd = GET_OPCODE (mpx_obuf); /* get command opcode */ + mpx_portkey = GET_KEY (mpx_obuf); /* get port key */ + + if (mpx_state == cmd) /* already scheduled? */ + sim_cancel (&mpx_cntl); /* cancel to get full delay */ + + mpx_state = cmd; /* set command state */ + + if (mpx_cmd & CMD_TWO_WORDS) /* two-word command? */ + delay = PARAM_DELAY; /* specify parameter wait */ + else /* one-word command */ + delay = CMD_DELAY; /* specify command wait */ + + sim_activate (&mpx_cntl, delay); /* schedule command */ + + if (DEBUG_PRI (mpx_dev, DEB_CMDS)) + fprintf (sim_deb, ">>MPX cmds: [STC%s] Command %03o key %d scheduled, " + "time = %d\n", hold_or_clear, mpx_cmd, mpx_portkey, delay); + break; + + + case ioEDT: /* end data transfer */ + if (DEBUG_PRI (mpx_dev, DEB_CPU)) + fputs (">>MPX cpu: [EDT] DCPC transfer ended\n", sim_deb); + break; + + + case ioSIR: /* set interrupt request */ + setstdPRL (mpx); /* set standard PRL signal */ + setstdIRQ (mpx); /* set standard IRQ signal */ + setstdSRQ (mpx); /* set standard SRQ signal */ + break; + + + case ioIAK: /* interrupt acknowledge */ + mpx.flagbuf = CLEAR; /* clear flag buffer */ + break; + + + default: /* all other signals */ + break; /* are ignored */ + } + + working_set = working_set & ~signal; /* remove current signal from set */ + } + +return stat_data; +} + + +/* Command executor. + + We are called by the controller service routine to process one- and two-word + commands. For two-word commands, the parameter word is present in mpx_param. + The return value indicates whether the card flag should be set upon + completion. + + Most commands execute and complete directly. The read and write commands, + however, transition to the execution state to simulate the DMA transfer, and + the "Download executable" command does the same to receive the download from + the CPU. + + Several commands were added for the B firmware revision, and the various + revisions of the RTE drivers sent some commands that were never implemented + in the mux firmware. The command protocol treated unknown commands as NOPs, + meaning that the command (and parameter, if it was a two-word command) was + absorbed and the card flag was set as though the command completed normally. + This allowed interoperability between firmware and driver revisions. + + Commands that refer to ports do so indirectly by passing a port key, rather + than a port number. The key-to-port translation is established by the "Set + port key" command. If a key is not found in the table, the command is not + executed, and the status return is ST_BAD_KEY, which in hex is "BAD0". + + Implementation notes: + + 1. The "Reset to power-on defaults" command causes the firmware to disable + interrupts and jump to the power-on initialization routine, exactly as + though the Z80 had received a hardware reset. + + 2. The "Abort DMA transfer" command works because STC causes NMI, so the + command is executed even in the middle of a DMA transfer. The OTx of the + command will be sent to the buffer if a "Write data to buffer" command is + in progress, but the STC will cause this routine to be called, which will + cancel the buffer and return the controller to the idle state. Note that + this command might be sent with no transfer in progress, in which case + nothing is done. + + 3. In response to an "Enable unsolicited interrupts" command, the controller + service is scheduled to check for a pending UI. If one is found, the + first UI status word is placed in the input buffer, and an interrupt is + generated by setting the flag. This causes entry to the driver, which + issues an "Acknowledge" command to obtain the second status word. + + It is possible, however, for the interrupt to be ignored. For example, + the driver may be waiting for a "write buffer available" UI when it is + called to begin a write to a different port. If the flag is set by + the UI after RTE has been entered, the interrupt will be held off, and + the STC sc,C instruction that begins the command sequence will clear the + flag, removing the interrupt entirely. In this case, the controller will + reissue the UI when the next "Enable unsolicited interrupts" command is + sent. + + Note that the firmware reissues the same UI, rather than recomputing UIs + and potentially selecting a different one of higher priority. + + 4. The "Fast binary read" command apparently was intended to facilitate + booting from a 264x tape drive, although no boot loader ROM for the + multiplexer was ever released. It sends the fast binary read escape + sequence (ESC e) to the terminal and then packs each pair of characters + received into a word and sends it to the CPU, accompanied by the device + flag. + + The multiplexer firmware disables interrupts and then manipulates the SIO + for port 0 directly. Significantly, it does no interpretation of the + incoming data and sits in an endless I/O loop, so the only way to exit + the command is to reset the card with a CRS (front panel PRESET or CLC 0 + instruction execution). Sending a command will not work; although the + NMI will interrupt the fast binary read, the NMI handler simply sets a + flag that is tested by the scheduler poll. Because the processor is in + an endless loop, control never returns to the scheduler, so the command + is never seen. + + 5. The "Terminate active receive buffer" behavior is a bit tricky. If the + read buffer has characters, the buffer is terminated as though a + "terminate on count" condition occurred. If the buffer is empty, + however, a "terminate on count = 1" condition is established. When a + character is received, the buffer is terminated, and the buffer + termination count is reset to 254. +*/ + +static t_bool exec_command (void) +{ +int32 port; +uint32 svc_time; +t_bool set_flag = TRUE; /* flag is normally set on completion */ +STATE next_state = idle; /* command normally executes to completion */ + +mpx_ibuf = ST_OK; /* return status is normally OK */ + +switch (mpx_cmd) { + + case CMD_NOP: /* no operation */ + break; /* just ignore */ + + + case CMD_RESET: /* reset firmware */ + controller_reset (); /* reset program variables */ + mpx_ibuf = ST_TEST_OK; /* return self-test OK code */ + break; + + + case CMD_ENABLE_UI: + mpx_uien = TRUE; /* enable unsolicited interrupts */ + sim_activate (&mpx_cntl, CMD_DELAY); /* and schedule controller for UI check */ + + if (DEBUG_PRI (mpx_dev, DEB_CMDS)) + fprintf (sim_deb, ">>MPX cmds: Controller status check scheduled, " + "time = %d\n", CMD_DELAY); + + set_flag = FALSE; /* do not set the flag at completion */ + break; + + + case CMD_DISABLE: + switch (mpx_portkey) { + case SUBCMD_UI: + mpx_uien = FALSE; /* disable unsolicited interrupts */ + break; + + case SUBCMD_DMA: + if (mpx_flags [mpx_port] & FL_WRFILL) /* write buffer xfer in progress? */ + buf_cancel (iowrite, mpx_port, put); /* cancel it */ + else if (mpx_flags [mpx_port] & FL_RDEMPT) /* read buffer xfer in progress? */ + buf_cancel (ioread, mpx_port, get); /* cancel it */ + break; + } + break; + + + case CMD_ACK: /* acknowledge unsolicited interrupt */ + switch (mpx_uicode & UI_REASON) { + + case UI_WRBUF_AVAIL: /* write buffer notification */ + mpx_flags [mpx_port] &= ~FL_WANTBUF; /* clear flag */ + mpx_ibuf = WR_BUF_LIMIT; /* report write buffer available */ + break; + + case UI_RDBUF_AVAIL: /* read buffer notification */ + mpx_flags [mpx_port] &= ~FL_HAVEBUF; /* clear flag */ + + mpx_ibuf = (uint16) (buf_get (ioread, mpx_port) << 8 | /* get header value and position */ + buf_len (ioread, mpx_port, get)); /* and include buffer length */ + + if (mpx_flags [mpx_port] & FL_RDOVFLOW) { /* did a buffer overflow? */ + mpx_ibuf = mpx_ibuf | RS_OVERFLOW; /* report it */ + mpx_flags [mpx_port] &= ~FL_RDOVFLOW; /* clear overflow flag */ + } + break; + + case UI_BRK_RECD: /* break received */ + mpx_flags [mpx_port] &= ~FL_BREAK; /* clear flag */ + mpx_ibuf = 0; /* 2nd word is zero */ + break; + } + + mpx_uicode = 0; /* clear notification code */ + break; + + + case CMD_CANCEL: /* cancel first read buffer */ + port = key_to_port (mpx_portkey); /* get port */ + + if (port >= 0) /* port defined? */ + buf_cancel (ioread, port, get); /* cancel get buffer */ + + if ((buf_avail (ioread, port) == 1) && /* one buffer remaining? */ + !(mpx_flags [port] & FL_RDFILL)) /* and not filling it? */ + mpx_flags [port] |= FL_HAVEBUF; /* indicate buffer availability */ + break; + + + case CMD_CANCEL_ALL: /* cancel all read buffers */ + port = key_to_port (mpx_portkey); /* get port */ + + if (port >= 0) /* port defined? */ + buf_init (ioread, port); /* reinitialize read buffers */ + break; + + + case CMD_BINARY_READ: /* fast binary read */ + for (port = 0; port < MPX_PORTS; port++) + sim_cancel (&mpx_unit [port]); /* cancel I/O on all lines */ + + mpx_flags [0] = 0; /* clear port 0 state flags */ + mpx_enq_cntr [0] = 0; /* clear port 0 ENQ counter */ + mpx_ack_wait [0] = 0; /* clear port 0 ACK wait timer */ + + tmxr_putc_ln (&mpx_ldsc [0], ESC); /* send fast binary read */ + tmxr_putc_ln (&mpx_ldsc [0], 'e'); /* escape sequence to port 0 */ + tmxr_poll_tx (&mpx_desc); /* flush output */ + + next_state = exec; /* set execution state */ + break; + + + case CMD_REQ_WRITE: /* request write buffer */ + port = key_to_port (mpx_portkey); /* get port */ + + if (port >= 0) /* port defined? */ + if (buf_avail (iowrite, port) > 0) /* is a buffer available? */ + mpx_ibuf = WR_BUF_LIMIT; /* report write buffer limit */ + + else { + mpx_ibuf = 0; /* report none available */ + mpx_flags [port] |= FL_WANTBUF; /* set buffer request */ + } + break; + + + case CMD_WRITE: /* write to buffer */ + port = key_to_port (mpx_portkey); /* get port */ + + if (port >= 0) { /* port defined? */ + mpx_port = port; /* save port number */ + mpx_iolen = mpx_param & WR_LENGTH; /* save request length */ + next_state = exec; /* set execution state */ + } + break; + + + case CMD_SET_KEY: /* set port key and configuration */ + port = GET_PORT (mpx_param); /* get target port number */ + mpx_key [port] = (uint8) mpx_portkey; /* set port key */ + mpx_config [port] = (uint16) mpx_param; /* set port configuration word */ + + svc_time = service_time (mpx_config [port]); /* get service time for baud rate */ + + if (svc_time) /* want to change? */ + mpx_unit [port].wait = svc_time; /* set service time */ + + mpx_ibuf = MPX_DATE_CODE; /* return firmware date code */ + break; + + + case CMD_SET_RCV: /* set receive type */ + port = key_to_port (mpx_portkey); /* get port */ + + if (port >= 0) /* port defined? */ + mpx_rcvtype [port] = (uint16) mpx_param; /* save port receive type */ + break; + + + case CMD_SET_COUNT: /* set character count */ + port = key_to_port (mpx_portkey); /* get port */ + + if (port >= 0) /* port defined? */ + mpx_charcnt [port] = (uint16) mpx_param; /* save port character count */ + break; + + + case CMD_SET_FLOW: /* set flow control */ + port = key_to_port (mpx_portkey); /* get port */ + + if (port >= 0) /* port defined? */ + mpx_flowcntl [port] = mpx_param & FC_XONXOFF; /* save port flow control */ + + if (mpx_param & FC_FORCE_XON) /* force XON? */ + mpx_flags [port] &= ~FL_XOFF; /* resume transmission if suspended */ + break; + + + case CMD_READ: /* read from buffer */ + port = key_to_port (mpx_portkey); /* get port */ + + if (port >= 0) { /* port defined? */ + mpx_port = port; /* save port number */ + mpx_iolen = mpx_param; /* save request length */ + + sim_activate (&mpx_cntl, DATA_DELAY); /* schedule the transfer */ + next_state = exec; /* set execution state */ + set_flag = FALSE; /* no flag until word ready */ + } + break; + + + case CMD_DL_EXEC: /* Download executable */ + mpx_iolen = mpx_param; /* save request length */ + next_state = exec; /* set execution state */ + break; + + + case CMD_CN_LINE: /* connect modem line */ + case CMD_DC_LINE: /* disconnect modem line */ + case CMD_LOOPBACK: /* enable/disable modem loopback */ + mpx_ibuf = ST_NO_MODEM; /* report "no modem installed" */ + break; + + + case CMD_GET_STATUS: /* get modem status */ + mpx_ibuf = ST_NO_SYSMDM; /* report "no systems modem card" */ + break; + + + case CMD_TERM_BUF: /* terminate active receive buffer */ + port = key_to_port (mpx_portkey); /* get port */ + + if (port >= 0) /* port defined? */ + if (buf_len (ioread, port, put) > 0) { /* any chars in buffer? */ + buf_term (ioread, port, 0); /* terminate buffer and set header */ + + if (buf_avail (ioread, port) == 1) /* first read buffer? */ + mpx_flags [port] |= FL_HAVEBUF; /* indicate availability */ + } + + else { /* buffer is empty */ + mpx_charcnt [port] = 1; /* set to terminate on one char */ + mpx_flags [port] |= FL_ALERT; /* set alert flag */ + } + break; + + + case CMD_VCP_PUT: /* VCP put byte */ + case CMD_VCP_PUT_BUF: /* VCP put buffer */ + case CMD_VCP_GET: /* VCP get byte */ + case CMD_VCP_GET_BUF: /* VCP get buffer */ + case CMD_VCP_EXIT: /* Exit VCP mode */ + case CMD_VCP_ENTER: /* Enter VCP mode */ + + default: /* unknown command */ + if (DEBUG_PRI (mpx_dev, DEB_CMDS)) + fprintf (sim_deb, ">>MPX cmds: Unknown command %03o ignored\n", mpx_cmd); + } + +mpx_state = next_state; +return set_flag; +} + + +/* Multiplexer controller service. + + The controller service handles commands and data transfers to and from the + CPU. The delay in scheduling the controller service represents the firmware + command or data execution time. The controller may be in one of four states + upon entry: idle, first word of command received (cmd), command parameter + received (param), or data transfer (exec). + + Entry in the command state causes execution of one-word commands and + solicitation of command parameters for two-word commands, which are executed + when entering in the parameter state. + + Entry in the data transfer state moves one word between the CPU and a read or + write buffer. For writes, the write buffer is filled with words from the + CPU. Once the indicated number of words have been transferred, the + appropriate line service is scheduled to send the characters. For reads, + characters are unloaded from the read buffer to the CPU; an odd-length + transfer is padded with a blank. A read of fewer characters than are present + in the buffer will return the remaining characters when the next read is + performed. + + Each read or write is terminated by the CPU sending one additional word (the + RTE drivers send -1). The command completes when this word is acknowledged + by the card setting the device flag. For zero-length writes, this additional + word will be the only word sent. + + Data transfer is also used by the "Download executable" command to absorb the + downloaded program. The firmware jumps to location 5100 hex in the + downloaded program upon completion of reception. It is the responsibility of + the program to return to the multiplexer firmware and to return to the CPU + whatever status is appropriate when it is done. Under simulation, we simply + "sink" the program and return status compatible with the multiplexer + diagnostic program to simulate a passing test. + + Entry in the idle state checks for unsolicited interrupts. UIs are sent to + the host when the controller is idle, UIs have been enabled, and a UI + condition exists. If a UI is not acknowledged, it will remain pending and + will be reissued the next time the controller is idle and UIs have been + enabled. + + UI conditions are kept in the per-port flags. The UI conditions are write + buffer available, read buffer available, break received, modem line + connected, and modem line disconnected. The latter two conditions are not + implemented in this simulation. If a break condition occurs at the same time + as a read buffer completion, the break has priority; the buffer UI will occur + after the break UI is acknowledged. + + The firmware checks for UI condition flags as part of the scheduler polling + loop. Under simulation, though, UIs can occur only in two places: the point + of origin (e.g., termination of a read buffer), or the "Enable unsolicited + input" command executor. UIs will be generated at the point of origin only + if the simulator is idle. If the simulator is not idle, it is assumed that + UIs have been disabled to execute the current command and will be reenabled + when the command sequence is complete. + + When the multiplexer is reset, and before the port keys are set, all ports + enter "echoplex" mode. In this mode, characters received are echoed back as + a functional test. Each port terminates buffers on CR reception. We detect + this condition, cancel the buffer, and discard the buffer termination UI. + + Implementation notes: + + 1. The firmware transfers the full amount requested by the CPU, even if the + transfer is longer than the buffer. Also, zero-length transfers program + the card DMA chip to transfer 0 bytes; this results in a transfer of 217 + bytes, per the Zilog databook. Under simulation, writes beyond the + buffer are accepted from the CPU but discarded, and reads beyond the + buffer return blanks. + + 2. We should never return from this routine in the "cmd" state, so debugging + will report "internal error!" if we do. +*/ + +t_stat mpx_cntl_svc (UNIT *uptr) +{ +uint8 ch; +uint32 i; +t_bool add_crlf; +t_bool set_flag = TRUE; +STATE last_state = mpx_state; + +static const char *cmd_state [] = { "complete", "internal error!", "waiting for parameter", "executing" }; + + +switch (mpx_state) { /* dispatch on current state */ + + case idle: /* controller idle */ + set_flag = FALSE; /* assume no UI */ + + if (mpx_uicode) { /* unacknowledged UI? */ + if (mpx_uien == TRUE) { /* interrupts enabled? */ + mpx_port = GET_UIPORT (mpx_uicode); /* get port number */ + mpx_portkey = mpx_key [mpx_port]; /* get port key */ + mpx_ibuf = (uint16) (mpx_uicode & UI_REASON | mpx_portkey); /* report UI reason and port key */ + set_flag = TRUE; /* reissue host interrupt */ + mpx_uien = FALSE; /* disable UI */ + + if (DEBUG_PRI (mpx_dev, DEB_CMDS)) + fprintf (sim_deb, ">>MPX cmds: Port %d key %d unsolicited interrupt reissued, " + "reason = %d\n", mpx_port, mpx_portkey, GET_UIREASON (mpx_uicode)); + } + } + + else { /* no unacknowledged UI */ + for (i = 0; i < MPX_PORTS; i++) { /* check all ports for UIs */ + if (mpx_flags [i] & FL_UI_PENDING) { /* pending UI? */ + mpx_portkey = mpx_key [i]; /* get port key */ + + if (mpx_portkey == KEY_DEFAULT) { /* key defined? */ + if (mpx_flags [i] & FL_HAVEBUF) /* no, is this read buffer avail? */ + buf_cancel (ioread, i, get); /* cancel buffer */ + + mpx_flags [i] &= ~FL_UI_PENDING; /* cancel pending UI */ + } + + else if (mpx_uien == TRUE) { /* interrupts enabled? */ + if ((mpx_flags [i] & FL_WANTBUF) && /* port wants a write buffer? */ + (buf_avail (iowrite, i) > 0)) /* and one is available? */ + mpx_uicode = UI_WRBUF_AVAIL; /* set UI reason */ + + else if (mpx_flags [i] & FL_BREAK) /* received a line BREAK? */ + mpx_uicode = UI_BRK_RECD; /* set UI reason */ + + else if (mpx_flags [i] & FL_HAVEBUF) /* have a read buffer ready? */ + mpx_uicode = UI_RDBUF_AVAIL; /* set UI reason */ + + if (mpx_uicode) { /* UI to send? */ + mpx_port = i; /* set port number for Acknowledge */ + mpx_ibuf = (uint16) (mpx_uicode | mpx_portkey); /* merge UI reason and port key */ + mpx_uicode = mpx_uicode | mpx_port; /* save UI reason and port */ + set_flag = TRUE; /* interrupt host */ + mpx_uien = FALSE; /* disable UI */ + + if (DEBUG_PRI (mpx_dev, DEB_CMDS)) + fprintf (sim_deb, ">>MPX cmds: Port %d key %d unsolicited interrupt generated, " + "reason = %d\n", i, mpx_portkey, GET_UIREASON (mpx_uicode)); + + break; /* quit after first UI */ + } + } + } + } + } + break; + + + case cmd: /* command state */ + if (mpx_cmd & CMD_TWO_WORDS) /* two-word command? */ + mpx_state = param; /* look for parameter before executing */ + else + set_flag = exec_command (); /* execute one-word command */ + break; + + + case param: /* parameter get state */ + mpx_param = mpx_obuf; /* save parameter */ + set_flag = exec_command (); /* execute two-word command */ + break; + + + case exec: /* execution state */ + switch (mpx_cmd) { + + case CMD_BINARY_READ: /* fast binary read */ + mpx_flags [0] &= ~FL_HAVEBUF; /* data word was picked up by CPU */ + set_flag = FALSE; /* suppress device flag */ + break; + + + case CMD_WRITE: /* transfer data to buffer */ + if (mpx_iolen <= 0) { /* last (or only) entry? */ + mpx_state = idle; /* idle controller */ + + if (mpx_iolen < 0) /* tie-off for buffer complete? */ + break; /* we're done */ + } + + add_crlf = ((mpx_param & /* CRLF should be added */ + (WR_ADD_CRLF | WR_PARTIAL)) == WR_ADD_CRLF); + + for (i = 0; i < 2; i++) /* output one or two chars */ + if (mpx_iolen > 0) { /* more to do? */ + if (i) /* high or low byte? */ + ch = (uint8) (mpx_obuf & 0377); /* low byte */ + else + ch = mpx_obuf >> 8; /* high byte */ + + if ((mpx_iolen == 1) && /* final char? */ + (ch == '_') && add_crlf) { /* underscore and asking for CRLF? */ + + add_crlf = FALSE; /* suppress CRLF */ + + if (DEBUG_PRI (mpx_dev, DEB_BUF)) + fprintf (sim_deb, ">>MPX buf: Port %d character '_' " + "suppressed CR/LF\n", mpx_port); + } + + else if (buf_len (iowrite, mpx_port, put) < WR_BUF_LIMIT) + buf_put (iowrite, mpx_port, ch); /* add char to buffer if space avail */ + + mpx_iolen = mpx_iolen - 1; /* drop remaining count */ + } + + if (mpx_iolen == 0) { /* buffer done? */ + if (add_crlf) { /* want CRLF? */ + buf_put (iowrite, mpx_port, CR); /* add CR to buffer */ + buf_put (iowrite, mpx_port, LF); /* add LF to buffer */ + } + + buf_term (iowrite, mpx_port, (uint8) (mpx_param >> 8)); /* terminate buffer */ + mpx_iolen = -1; /* mark as done */ + } + + if (DEBUG_PRI (mpx_dev, DEB_CMDS) && + (sim_is_active (&mpx_unit [mpx_port]) == 0)) + fprintf (sim_deb, ">>MPX cmds: Port %d service scheduled, " + "time = %d\n", mpx_port, mpx_unit [mpx_port].wait); + + sim_activate (&mpx_unit [mpx_port], /* start line service */ + mpx_unit [mpx_port].wait); + break; + + + case CMD_READ: /* transfer data from buffer */ + if (mpx_iolen < 0) { /* input complete? */ + if (mpx_obuf == 0177777) { /* "tie-off" word received? */ + if (buf_len (ioread, mpx_port, get) == 0) { /* buffer now empty? */ + buf_free (ioread, mpx_port); /* free buffer */ + + if (buf_avail (ioread, mpx_port) == 1) /* another buffer available? */ + mpx_flags [mpx_port] |= FL_HAVEBUF; /* indicate availability */ + } + + mpx_state = idle; /* idle controller */ + } + + else + set_flag = FALSE; /* ignore word */ + + break; + } + + for (i = 0; i < 2; i++) /* input one or two chars */ + if (mpx_iolen > 0) { /* more to transfer? */ + if (buf_len (ioread, mpx_port, get) > 0) /* more chars available? */ + ch = buf_get (ioread, mpx_port); /* get char from buffer */ + else /* buffer exhausted */ + ch = ' '; /* pad with blank */ + + if (i) /* high or low byte? */ + mpx_ibuf = mpx_ibuf | ch; /* low byte */ + else + mpx_ibuf = (uint16) (ch << 8); /* high byte */ + + mpx_iolen = mpx_iolen - 1; /* drop count */ + } + + else /* odd number of chars */ + mpx_ibuf = mpx_ibuf | ' '; /* pad last with blank */ + + if (mpx_iolen == 0) /* end of host xfer? */ + mpx_iolen = -1; /* mark as done */ + + break; + + + case CMD_DL_EXEC: /* sink data from host */ + if (mpx_iolen <= 0) { /* final entry? */ + mpx_state = idle; /* idle controller */ + mpx_ibuf = ST_DIAG_OK; /* return diag passed status */ + } + + else { + if (mpx_iolen > 0) /* more from host? */ + mpx_iolen = mpx_iolen - 2; /* sink two bytes */ + + if (mpx_iolen <= 0) /* finished download? */ + sim_activate (&mpx_cntl, CMD_DELAY); /* schedule completion */ + + if (DEBUG_PRI (mpx_dev, DEB_CMDS)) + fprintf (sim_deb, ">>MPX cmds: Download completion scheduled, " + "time = %d\n", CMD_DELAY); + } + + break; + + + default: /* no other entries allowed */ + return SCPE_IERR; /* simulator error! */ + } + break; + } + + +if (DEBUG_PRI (mpx_dev, DEB_CMDS) && /* debug print? */ + (last_state != mpx_state)) { /* and state change? */ + fprintf (sim_deb, ">>MPX cmds: Command %03o ", mpx_cmd); + + if ((mpx_cmd & CMD_TWO_WORDS) && (mpx_state != param)) + fprintf (sim_deb, "parameter %06o ", mpx_param); + + fputs (cmd_state [mpx_state], sim_deb); + fputc ('\n', sim_deb); + } + +if (set_flag) { + mpx_io (&mpx_dib, ioENF, 0); /* set device flag */ + + if (DEBUG_PRI (mpx_dev, DEB_CMDS)) + fputs (">>MPX cmds: Flag set\n", sim_deb); + } + +return SCPE_OK; +} + + +/* Multiplexer line service. + + The line service routine is used to transmit and receive characters. It is + started when a buffer is ready for output or when the Telnet poll routine + determines that there are characters ready for input, and it is stopped when + there are no more characters to output or input. When a line is quiescent, + this routine does not run. Service times are selected to approximate the + baud rate setting of the multiplexer port. + + "Fast timing" mode enables three optimizations. First, buffered characters + are transferred via Telnet in blocks, rather than a character at a time; this + reduces network traffic and decreases simulator overhead (there is only one + service routine entry per block, rather than one per character). Second, + ENQ/ACK handshaking is done locally, without involving the Telnet client. + Third, when editing and echo is enabled, entering BS echoes a backspace, a + space, and a backspace, and entering DEL echoes a backslash, a carriage + return, and a line feed, providing better compatibility with prior RTE + terminal drivers. + + Each read and write buffer begins with a reserved header byte that stores + per-buffer information, such as whether handshaking should be suppressed + during output, or the specific cause of termination for input. Buffer + termination sets the header byte with the appropriate flags. + + For output, a character counter is maintained and is incremented if ENQ/ACK + handshaking is enabled for the current port and request. If the counter + limit is reached, an ENQ is sent, and a flag is set to suspend transmission + until an ACK is received. If the last character of the buffer is sent, the + write buffer is freed, and a UI check is made if the controller is idle, in + case a write buffer request is pending. + + For input, the character is retrieved from the Telnet buffer. If a BREAK was + received, break status is set, and the character is discarded (the current + multiplexer library implementation always returns a NUL with a BREAK + indication). If the character is an XOFF, and XON/XOFF pacing is enabled, a + flag is set, and transmission is suspended until a corresponding XON is + received. If the character is an ACK and is in response to a previously sent + ENQ, it is discarded, and transmission is reenabled. + + If editing is enabled, a BS will delete the last character in the read + buffer, and a DEL will delete the entire buffer. Otherwise, buffer + termination conditions are checked (end on character, end on count, or + buffer full), and if observed, the read buffer is terminated, and a read + buffer available UI condition is signalled. + + Implementation notes: + + 1. The firmware echoes an entered BS before checking the buffer count to see + if there are any characters to delete. Under simulation, we only echo if + the buffer is not empty. + + 2. The "Fast binary read" command inhibits the normal transmit and receive + processing. Instead, a pair of characters are sought on line 0 to fill + the input buffer. When they are received, the device flag is set. The + CPU will do a LIx sc,C to retrieve the data and reset the flag. +*/ + +t_stat mpx_line_svc (UNIT *uptr) +{ +const int32 port = uptr - mpx_unit; /* port number */ +const uint16 rt = mpx_rcvtype [port]; /* receive type for port */ +const uint32 data_bits = 5 + GET_BPC (mpx_config [port]); /* number of data bits */ +const uint32 data_mask = (1 << data_bits) - 1; /* mask for data bits */ +const t_bool fast_timing = (uptr->flags & UNIT_FASTTIME) != 0; /* port is set for fast timing */ +const t_bool fast_binary_read = (mpx_cmd == CMD_BINARY_READ); /* fast binary read in progress */ + +uint8 ch; +int32 chx; +uint16 read_length; +t_stat status = SCPE_OK; +t_bool recv_loop = !fast_binary_read; /* bypass if fast binary read */ +t_bool xmit_loop = !(fast_binary_read || /* bypass if fast read or output suspended */ + (mpx_flags [port] & (FL_WAITACK | FL_XOFF))); + + +/* Transmission service */ + +while (xmit_loop && (buf_len (iowrite, port, get) > 0)) { /* character available to output? */ + if ((mpx_flags [port] & FL_WREMPT) == 0) { /* has buffer started emptying? */ + chx = buf_get (iowrite, port) << 8; /* get header value and position */ + + if (fast_timing || (chx & WR_NO_ENQACK) || /* do we want handshake? */ + !(mpx_config [port] & SK_ENQACK)) /* and configured for handshake? */ + mpx_flags [port] &= ~FL_DO_ENQACK; /* no, so clear flag */ + else + mpx_flags [port] |= FL_DO_ENQACK; /* yes, so set flag */ + + continue; /* "continue" for zero-length write */ + } + + if (mpx_flags [port] & FL_DO_ENQACK) /* do handshake for this buffer? */ + mpx_enq_cntr [port] = mpx_enq_cntr [port] + 1; /* bump character counter */ + + if (mpx_enq_cntr [port] > ENQ_LIMIT) { /* ready for ENQ? */ + mpx_enq_cntr [port] = 0; /* clear ENQ counter */ + mpx_ack_wait [port] = 0; /* clear ACK wait timer */ + + mpx_flags [port] |= FL_WAITACK; /* set wait for ACK */ + ch = ENQ; + status = tmxr_putc_ln (&mpx_ldsc [port], ch); /* transmit ENQ */ + xmit_loop = FALSE; /* stop further transmission */ + } + + else { /* not ready for ENQ */ + ch = buf_get (iowrite, port) & data_mask; /* get char and mask to bit width */ + status = tmxr_putc_ln (&mpx_ldsc [port], ch); /* transmit the character */ + xmit_loop = (status == SCPE_OK) && fast_timing; /* continue transmission? */ + } + + if ((status == SCPE_OK) && /* transmitted OK? */ + DEBUG_PRI (mpx_dev, DEB_XFER)) + fprintf (sim_deb, ">>MPX xfer: Port %d character %s transmitted\n", + port, fmt_char (ch)); + + else + xmit_loop = FALSE; + + if (buf_len (iowrite, port, get) == 0) { /* buffer complete? */ + buf_free (iowrite, port); /* free buffer */ + + if (mpx_state == idle) /* controller idle? */ + mpx_cntl_svc (&mpx_cntl); /* check for UI */ + } + } + + +/* Reception service */ + +while (recv_loop) { /* OK to process? */ + chx = tmxr_getc_ln (&mpx_ldsc [port]); /* get a new character */ + + if (chx == 0) /* if there are no more characters available */ + break; /* then quit the reception loop */ + + if (chx & SCPE_BREAK) { /* break detected? */ + mpx_flags [port] |= FL_BREAK; /* set break status */ + + if (DEBUG_PRI (mpx_dev, DEB_XFER)) + fputs (">>MPX xfer: Break detected\n", sim_deb); + + if (mpx_state == idle) /* controller idle? */ + mpx_cntl_svc (&mpx_cntl); /* check for UI */ + + continue; /* discard NUL that accompanied BREAK */ + } + + ch = (uint8) (chx & data_mask); /* mask to bits per char */ + + if ((ch == XOFF) && /* XOFF? */ + (mpx_flowcntl [port] & FC_XONXOFF)) { /* and handshaking enabled? */ + mpx_flags [port] |= FL_XOFF; /* suspend transmission */ + + if (DEBUG_PRI (mpx_dev, DEB_XFER)) + fprintf (sim_deb, ">>MPX xfer: Port %d character XOFF " + "suspends transmission\n", port); + + recv_loop = fast_timing; /* set to loop if fast mode */ + continue; + } + + else if ((ch == XON) && /* XON? */ + (mpx_flags [port] & FL_XOFF)) { /* and currently suspended? */ + mpx_flags [port] &= ~FL_XOFF; /* resume transmission */ + + if (DEBUG_PRI (mpx_dev, DEB_XFER)) + fprintf (sim_deb, ">>MPX xfer: Port %d character XON " + "resumes transmission\n", port); + + recv_loop = fast_timing; /* set to loop if fast mode */ + continue; + } + + if (DEBUG_PRI (mpx_dev, DEB_XFER)) + fprintf (sim_deb, ">>MPX xfer: Port %d character %s received\n", + port, fmt_char (ch)); + + if ((ch == ACK) && (mpx_flags [port] & FL_WAITACK)) { /* ACK and waiting for it? */ + mpx_flags [port] = mpx_flags [port] & ~FL_WAITACK; /* clear wait flag */ + recv_loop = FALSE; /* absorb character */ + } + + else if ((buf_avail (ioread, port) == 0) && /* no free buffer available for char? */ + !(mpx_flags [port] & FL_RDFILL)) { /* and not filling last buffer? */ + mpx_flags [port] |= FL_RDOVFLOW; /* set buffer overflow flag */ + recv_loop = fast_timing; /* continue loop if fast mode */ + } + + else { /* buffer is available */ + if (rt & RT_ENAB_EDIT) /* editing enabled? */ + if (ch == BS) { /* backspace? */ + if (buf_len (ioread, port, put) > 0) /* at least one character in buffer? */ + buf_remove (ioread, port); /* remove last char */ + + if (rt & RT_ENAB_ECHO) { /* echo enabled? */ + tmxr_putc_ln (&mpx_ldsc [port], BS); /* echo BS */ + + if (fast_timing) { /* fast timing mode? */ + tmxr_putc_ln (&mpx_ldsc [port], ' '); /* echo space */ + tmxr_putc_ln (&mpx_ldsc [port], BS); /* echo BS */ + } + } + + continue; + } + + else if (ch == DEL) { /* delete line? */ + buf_cancel (ioread, port, put); /* cancel put buffer */ + + if (rt & RT_ENAB_ECHO) { /* echo enabled? */ + if (fast_timing) /* fast timing mode? */ + tmxr_putc_ln (&mpx_ldsc [port], '\\'); /* echo backslash */ + + tmxr_putc_ln (&mpx_ldsc [port], CR); /* echo CR */ + tmxr_putc_ln (&mpx_ldsc [port], LF); /* and LF */ + } + + continue; + } + + if (uptr->flags & UNIT_CAPSLOCK) /* caps lock mode? */ + ch = (uint8) toupper (ch); /* convert to upper case if lower */ + + if (rt & RT_ENAB_ECHO) /* echo enabled? */ + tmxr_putc_ln (&mpx_ldsc [port], ch); /* echo the char */ + + if (rt & RT_END_ON_CHAR) { /* end on character? */ + recv_loop = FALSE; /* assume termination */ + + if ((ch == CR) && (rt & RT_END_ON_CR)) { + if (rt & RT_ENAB_ECHO) /* echo enabled? */ + tmxr_putc_ln (&mpx_ldsc [port], LF); /* send LF */ + mpx_param = RS_ETC_CR; /* set termination condition */ + } + + else if ((ch == RS) && (rt & RT_END_ON_RS)) + mpx_param = RS_ETC_RS; /* set termination condition */ + + else if ((ch == EOT) && (rt & RT_END_ON_EOT)) + mpx_param = RS_ETC_EOT; /* set termination condition */ + + else if ((ch == DC2) && (rt & RT_END_ON_DC2)) + mpx_param = RS_ETC_DC2; /* set termination condition */ + + else + recv_loop = TRUE; /* no termination */ + } + + if (recv_loop) /* no termination condition? */ + buf_put (ioread, port, ch); /* put character in buffer */ + + read_length = buf_len (ioread, port, put); /* get current buffer length */ + + if ((rt & RT_END_ON_CNT) && /* end on count */ + (read_length == mpx_charcnt [port])) { /* and count reached? */ + recv_loop = FALSE; /* set termination */ + mpx_param = 0; /* no extra termination info */ + + if (mpx_flags [port] & FL_ALERT) { /* was this alert for term rcv buffer? */ + mpx_flags [port] &= ~FL_ALERT; /* clear alert flag */ + mpx_charcnt [port] = RD_BUF_LIMIT; /* reset character count */ + } + } + + else if (read_length == RD_BUF_LIMIT) { /* buffer now full? */ + recv_loop = FALSE; /* set termination */ + mpx_param = mpx_param | RS_PARTIAL; /* and partial buffer flag */ + } + + if (recv_loop) /* no termination condition? */ + recv_loop = fast_timing; /* set to loop if fast mode */ + + else { /* termination occurred */ + if (DEBUG_PRI (mpx_dev, DEB_XFER)) { + fprintf (sim_deb, ">>MPX xfer: Port %d read terminated on ", port); + + if (mpx_param & RS_PARTIAL) + fputs ("buffer full\n", sim_deb); + else if (rt & RT_END_ON_CHAR) + fprintf (sim_deb, "character %s\n", fmt_char (ch)); + else + fprintf (sim_deb, "count = %d\n", mpx_charcnt [port]); + } + + if (buf_len (ioread, port, put) == 0) { /* zero-length read? */ + buf_put (ioread, port, 0); /* dummy put to reserve header */ + buf_remove (ioread, port); /* back out dummy char leaving header */ + } + + buf_term (ioread, port, (uint8) (mpx_param >> 8)); /* terminate buffer and set header */ + + if (buf_avail (ioread, port) == 1) /* first read buffer? */ + mpx_flags [port] |= FL_HAVEBUF; /* indicate availability */ + + if (mpx_state == idle) /* controller idle? */ + mpx_cntl_svc (&mpx_cntl); /* check for UI */ + } + } + } + + +/* Housekeeping */ + +if (fast_binary_read) { /* fast binary read in progress? */ + if (port == 0) { /* on port 0? */ + chx = tmxr_getc_ln (&mpx_ldsc [0]); /* see if a character is ready */ + + if (chx && !(mpx_flags [0] & FL_HAVEBUF)) { /* character ready and buffer empty? */ + if (mpx_flags [0] & FL_WANTBUF) { /* second character? */ + mpx_ibuf = mpx_ibuf | (chx & DMASK8); /* merge it into word */ + mpx_flags [0] |= FL_HAVEBUF; /* mark buffer as ready */ + + mpx_io (&mpx_dib, ioENF, 0); /* set device flag */ + + if (DEBUG_PRI (mpx_dev, DEB_CMDS)) + fputs (">>MPX cmds: Flag and SRQ set\n", sim_deb); + } + + else /* first character */ + mpx_ibuf = (uint16) ((chx & DMASK8) << 8); /* put in top half of word */ + + mpx_flags [0] ^= FL_WANTBUF; /* toggle byte flag */ + } + + sim_activate (uptr, uptr->wait); /* reschedule service for fast response */ + } + } + +else { /* normal service */ + tmxr_poll_tx (&mpx_desc); /* output any accumulated characters */ + + if ((buf_avail (iowrite, port) < 2) && /* more to transmit? */ + !(mpx_flags [port] & (FL_WAITACK | FL_XOFF)) || /* and transmission not suspended */ + tmxr_rqln (&mpx_ldsc [port])) /* or more to receive? */ + sim_activate (uptr, uptr->wait); /* reschedule service */ + else + if (DEBUG_PRI (mpx_dev, DEB_CMDS)) + fprintf (sim_deb, ">>MPX cmds: Port %d service stopped\n", port); + } + +return SCPE_OK; +} + + +/* Telnet poll service. + + This service routine is used to poll for Telnet connections and incoming + characters. It starts when the socket is attached and stops when the socket + is detached. + + Each line is then checked for a pending ENQ/ACK handshake. If one is + pending, the ACK counter is incremented, and if it times out, another ENQ is + sent to avoid stalls. Lines are also checked for available characters, and + the corresponding line I/O service routine is scheduled if needed. +*/ + +t_stat mpx_poll_svc (UNIT *uptr) +{ +uint32 i; +t_stat status = SCPE_OK; + +poll_connection (); /* check for new connection */ + +tmxr_poll_rx (&mpx_desc); /* poll for input */ + +for (i = 0; i < MPX_PORTS; i++) { /* check lines */ + if (mpx_flags [i] & FL_WAITACK) { /* waiting for ACK? */ + mpx_ack_wait [i] = mpx_ack_wait [i] + 1; /* increment ACK wait timer */ + + if (mpx_ack_wait [i] > ACK_LIMIT) { /* has wait timed out? */ + mpx_ack_wait [i] = 0; /* reset counter */ + status = tmxr_putc_ln (&mpx_ldsc [i], ENQ); /* send ENQ again */ + tmxr_poll_tx (&mpx_desc); /* transmit it */ + + if ((status == SCPE_OK) && /* transmitted OK? */ + DEBUG_PRI (mpx_dev, DEB_XFER)) + fprintf (sim_deb, ">>MPX xfer: Port %d character ENQ retransmitted\n", i); + } + } + + if (tmxr_rqln (&mpx_ldsc [i])) /* chars available? */ + sim_activate (&mpx_unit [i], mpx_unit [i].wait); /* activate I/O service */ + } + +if (uptr->wait == POLL_FIRST) /* first poll? */ + uptr->wait = sync_poll (INITIAL); /* initial synchronization */ +else /* not first */ + uptr->wait = sync_poll (SERVICE); /* continue synchronization */ + +sim_activate (uptr, uptr->wait); /* continue polling */ + +return SCPE_OK; +} + + +/* Simulator reset routine. + + The hardware CRS signal generates a reset signal to the Z80 and its + peripherals. This causes execution of the power up initialization code. + + The CRS signal also has these hardware effects: + - clears control + - clears flag + - clears flag buffer + - clears backplane ready + - clears the output buffer register + + Implementation notes: + + 1. Under simulation, we also clear the input buffer register, even though + the hardware doesn't. + + 2. We set up the first poll for Telnet connections to occur "immediately" + upon execution, so that clients will be connected before execution + begins. Otherwise, a fast program may access the multiplexer before the + poll service routine activates. + + 3. We must set the "emptying_flags" and "filling_flags" values here, because + they cannot be initialized statically, even though the values are + constant. +*/ + +t_stat mpx_reset (DEVICE *dptr) +{ +if (sim_switches & SWMASK ('P')) { /* power-on reset? */ + emptying_flags [ioread] = FL_RDEMPT; /* initialize buffer flags constants */ + emptying_flags [iowrite] = FL_WREMPT; + filling_flags [ioread] = FL_RDFILL; + filling_flags [iowrite] = FL_WRFILL; + } + +IOPRESET (&mpx_dib); /* PRESET device (does not use PON) */ + +mpx_ibuf = 0; /* clear input buffer */ + +if (mpx_poll.flags & UNIT_ATT) { /* network attached? */ + mpx_poll.wait = POLL_FIRST; /* set up poll */ + sim_activate (&mpx_poll, mpx_poll.wait); /* start Telnet poll immediately */ + } +else + sim_cancel (&mpx_poll); /* else stop Telnet poll */ + +return SCPE_OK; +} + + +/* Attach the multiplexer to a Telnet port. + + We are called by the ATTACH MPX command to attach the multiplexer to + the listening port indicated by . Logically, it is the multiplexer + device that is attached; however, SIMH only allows units to be attached. + This makes sense for devices such as tape drives, where the attached media is + a property of a specific drive. In our case, though, the listening port is a + property of the multiplexer card, not of any given serial line. As ATTACH + MPX is equivalent to ATTACH MPX0, the port would, by default, be attached to + the first serial line and be reported there in a SHOW MPX command. + + To preserve the logical picture, we attach the port to the Telnet poll unit, + which is normally disabled to inhibit its display. Attaching to a disabled + unit is not allowed, so we first enable the unit, then attach it, then + disable it again. Attachment is reported by the "mpx_status" routine below. + + A direct attach to the poll unit is only allowed when restoring a previously + saved session. + + The Telnet poll service routine is synchronized with the other input polling + devices in the simulator to facilitate idling. +*/ + +t_stat mpx_attach (UNIT *uptr, char *cptr) +{ +t_stat status = SCPE_OK; + +if (uptr != mpx_unit /* not unit 0? */ + && (uptr != &mpx_poll || !(sim_switches & SIM_SW_REST))) /* and not restoring the poll unit? */ + return SCPE_NOATT; /* can't attach */ + +mpx_poll.flags = mpx_poll.flags & ~UNIT_DIS; /* enable unit */ +status = tmxr_attach (&mpx_desc, &mpx_poll, cptr); /* attach to socket */ +mpx_poll.flags = mpx_poll.flags | UNIT_DIS; /* disable unit */ + +if (status == SCPE_OK) { + mpx_poll.wait = POLL_FIRST; /* set up poll */ + sim_activate (&mpx_poll, mpx_poll.wait); /* start poll immediately */ + } +return status; +} + + +/* Detach the multiplexer. + + Normally, we are called by the DETACH MPX command, which is equivalent to + DETACH MPX0. However, we may be called with other units in two cases. + + A DETACH ALL command will call us for unit 9 (the poll unit) if it is + attached. Also, during simulator shutdown, we will be called for units 0-8 + (detach_all in scp.c calls the detach routines of all units that do NOT have + UNIT_ATTABLE), as well as for unit 9 if it is attached. In both cases, it is + imperative that we return SCPE_OK, otherwise any remaining device detaches + will not be performed. +*/ + +t_stat mpx_detach (UNIT *uptr) +{ +t_stat status = SCPE_OK; +int32 i; + +if ((uptr == mpx_unit) || (uptr == &mpx_poll)) { /* base unit or poll unit? */ + status = tmxr_detach (&mpx_desc, &mpx_poll); /* detach socket */ + + for (i = 0; i < MPX_PORTS; i++) { + mpx_ldsc [i].rcve = 0; /* disable line reception */ + sim_cancel (&mpx_unit [i]); /* cancel any scheduled I/O */ + } + + sim_cancel (&mpx_poll); /* stop Telnet poll */ + } + +return status; +} + + +/* Show multiplexer status */ + +t_stat mpx_status (FILE *st, UNIT *uptr, int32 val, void *desc) +{ +if (mpx_poll.flags & UNIT_ATT) /* attached to socket? */ + fprintf (st, "attached to port %s, ", mpx_poll.filename); +else + fprintf (st, "not attached, "); + +tmxr_show_summ (st, uptr, val, desc); /* report connection count */ +return SCPE_OK; +} + + +/* Set firmware revision. + + Currently, we support only revision C, so the MTAB entry does not have an + "mstring" entry. When we add revision D support, an "mstring" entry of "REV" + will enable changing the firmware revision. +*/ + +t_stat mpx_set_frev (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +if ((cptr == NULL) || /* no parameter? */ + (*cptr < 'C') || (*cptr > 'D') || /* or not C or D? */ + (*(cptr + 1) != '\0')) /* or not just one character? */ + return SCPE_ARG; /* bad argument */ + +else { + if (*cptr == 'C') /* setting revision C? */ + mpx_dev.flags = mpx_dev.flags & ~DEV_REV_D; /* clear 'D' flag */ + else if (*cptr == 'D') /* setting revision D? */ + mpx_dev.flags = mpx_dev.flags | DEV_REV_D; /* set 'D' flag */ + + return SCPE_OK; + } +} + + +/* Show firmware revision */ + +t_stat mpx_show_frev (FILE *st, UNIT *uptr, int32 val, void *desc) +{ +if (mpx_dev.flags & DEV_REV_D) + fputs ("12792D", st); +else + fputs ("12792C", st); +return SCPE_OK; +} + + +/* Local routines */ + + +/* Poll for new Telnet connections */ + +static void poll_connection (void) +{ +int32 new_line; + +new_line = tmxr_poll_conn (&mpx_desc); /* check for new connection */ + +if (new_line >= 0) /* new connection established? */ + mpx_ldsc [new_line].rcve = 1; /* enable line to receive */ + +return; +} + + +/* Controller reset. + + This is the card microprocessor reset, not the simulator reset routine. It + simulates a power-on restart of the Z80 firmware. When it is called from the + simulator reset routine, that routine will take care of setting the card + flip-flops appropriately. +*/ + +static void controller_reset (void) +{ +uint32 i; + +mpx_state = idle; /* idle state */ + +mpx_cmd = 0; /* clear command */ +mpx_param = 0; /* clear parameter */ +mpx_uien = FALSE; /* disable interrupts */ + +for (i = 0; i < MPX_PORTS; i++) { /* clear per-line variables */ + buf_init (iowrite, i); /* initialize write buffers */ + buf_init (ioread, i); /* initialize read buffers */ + + mpx_key [i] = KEY_DEFAULT; /* clear port key to default */ + + if (i == 0) /* default port configurations */ + mpx_config [0] = SK_PWRUP_0; /* port 0 is separate from 1-7 */ + else + mpx_config [i] = (uint16) (SK_PWRUP_1 | i); + + mpx_rcvtype [i] = RT_PWRUP; /* power on config for echoplex */ + mpx_charcnt [i] = 0; /* default character count */ + mpx_flowcntl [i] = 0; /* default flow control */ + mpx_flags [i] = 0; /* clear state flags */ + mpx_enq_cntr [i] = 0; /* clear ENQ counter */ + mpx_ack_wait [i] = 0; /* clear ACK wait timer */ + mpx_unit [i].wait = service_time (mpx_config [i]); /* set terminal I/O time */ + + sim_cancel (&mpx_unit [i]); /* cancel line I/O */ + } + +sim_cancel (&mpx_cntl); /* cancel controller */ + +return; +} + + +/* Calculate service time from baud rate. + + Service times are based on 1580 instructions per millisecond, which is the + 1000 E-Series execution speed. Baud rate 0 means "don't change" and is + handled by the "Set port key" command executor. + + Baud rate settings of 13-15 are marked as "reserved" in the user manual, but + the firmware defines these as 38400, 9600, and 9600 baud, respectively. +*/ + +static uint32 service_time (uint16 control_word) +{ +/* Baud Rates 0- 7 : --, 50, 75, 110, 134.5, 150, 300, 1200, */ +/* Baud Rates 8-15 : 1800, 2400, 4800, 9600, 19200, 38400, 9600, 9600 */ +static const int32 ticks [] = { 0, 316000, 210667, 143636, 117472, 105333, 52667, 13167, + 8778, 6583, 3292, 1646, 823, 411, 1646, 1646 }; + +return ticks [GET_BAUDRATE (control_word)]; /* return service time for indicated rate */ +} + + +/* Translate port key to port number. + + Port keys are scanned in reverse port order, so if more than one port has the + same port key, commands specifying that key will affect the highest numbered + port. + + If a port key is the reserved value 255, then the port key has not been set. + In this case, set the input buffer to 0xBAD0 and return -1 to indicate + failure. +*/ + +static int32 key_to_port (uint32 key) +{ +int32 i; + +for (i = MPX_PORTS - 1; i >= 0; i--) /* scan in reverse order */ + if (mpx_key [i] == key) /* key found? */ + return i; /* return port number */ + +mpx_ibuf = ST_BAD_KEY; /* key not found: set status */ +return -1; /* return failure code */ +} + + +/* Buffer manipulation routines. + + The 12792 hardware provides 16K bytes of RAM to the microprocessor. From + this pool, the firmware allocates per-port read/write buffers and state + variables, global variables, and the system stack. Allocations are static + and differ between firmware revisions. + + The A/B/C revisions allocate two 254-byte read buffers and two 254-byte write + buffers per port. Assuming an idle condition, the first write to a port + transfers characters to the first write buffer. When the transfer completes, + the SIO begins transmitting. During transmission, a second write can be + initiated, which transfers characters to the second write buffer. If a third + write is attempted before the first buffer has been released, it will be + denied until the SIO completes transmission; then, if enabled, an unsolicited + interrupt will occur to announce buffer availability. The "active" (filling) + buffer alternates between the two. + + At idle, characters received will fill the first read buffer. When the read + completes according to the previously set termination criteria, an + unsolicited interrupt will occur (if enabled) to announce buffer + availability. If more characters are received before the first buffer has + been transferred to the CPU, they will fill the second buffer. If that read + also completes, additional characters will be discarded until the first + buffer has been emptied. The "active" (emptying) buffer alternates between + the two. + + With this configuration, two one-character writes or reads will allocate both + available buffers, even though each was essentially empty. + + The D revision allocates one 1024-byte FIFO read buffer and one 892-byte + write buffer per port. As with the A/B/C revisions, the first write to a + port transfers characters to the write buffer, and serial transmission begins + when the write completes. However, the write buffer is not a FIFO, so the + host is not permitted another write request until the entire buffer has been + transmitted. + + The read buffer is a FIFO. Characters received are placed into the FIFO as a + stream. Unlike the A/B/C revisions, character editing and termination + conditions are not evaluated until the buffer is read. Therefore, a full + 1024 characters may be received before additional characters would be + discarded. + + When the first character is received, an unsolicited interrupt occurs (if + enabled) to announce data reception. A host read may then be initiated. The + write buffer is used temporarily to process characters from the read buffer. + Characters are copied from the read to the write buffer while editing as + directed by the configuration accompanying the read request (e.g., deleting + the character preceding a BS, stripping CR/LF, etc.). When the termination + condition is found, the read command completes. Incoming characters may be + added to the FIFO while this is occurring. + + In summary, the revision differences in buffer handling are: + + Revisions A/B/C: + - two 254-byte receive buffers + - a buffer is "full" when the terminator character or count is received + - termination type must be established before the corresponding read + - data is echoed as it is received + + Revision D: + - one 1024-byte receive buffer + - buffer is "full" only when 1024 characters are received + - the concept of a buffer terminator does not apply, as the data is not + examined until a read is requested and characters are retrieved from the + FIFO. + - data is not echoed until it is read + + To implement the C revision behavior, while preserving the option of reusing + the buffer handlers for future D revision support, the dual 254-byte buffers + are implemented as a single 514-byte circular FIFO with capacity limited to + 254 bytes per buffer. This reserves space for a CR and LF and for a header + byte in each buffer. The header byte preserves per-buffer state information. + + In this implementation, the buffer "put" index points at the next free + location, and the buffer "get" index points at the next character to + retrieve. In addition to "put" and "get" indexes, a third "separator" index + is maintained to divide the FIFO into two areas corresponding to the two + buffers, and a "buffer filling" flag is maintained for each FIFO that is set + by the fill (put) routine and cleared by the terminate buffer routine. + + Graphically, the implementation is as follows for buffer "B[]", get "G", put + "P", and separator "S" indexes: + + 1. Initialize: 2. Fill first buffer: + G = S = P = 0 B[P] = char; Incr (P) + + |------------------------------| |---------|--------------------| + G G P --> + S S + P + + 3. Terminate first buffer: 4. Fill second buffer: + if S == G then S = P else nop B[P] = char; Incr (P) + + |------------|-----------------| |------------|------|----------| + G /---> S G S P --> + * ----/ P + + 5. Terminate second buffer: 6. Empty first buffer: + if S == G then S = P else nop char = B[G]; Incr (G) + + |------------|------------|----| |----|-------|------------|----| + G S P G --> S P + + 7. First buffer is empty: 8. Free first buffer: + G == S if !filling then S = P else nop + + |------------|------------|----| |------------|------------|----| + G P G /---> S + S * ----/ P + + 9. Empty second buffer: 10. Second buffer empty: + char = B[G]; Incr (G) G == S + + |----------------|--------|----| |-------------------------|----| + G --> S G + P S + P + 11. Free second buffer: + if !filling then S = P else nop + + |-------------------------|----| + G + S + P + + We also provide the following utility routines: + + - Remove Character: Decr (P) + + - Cancel Buffer: if S == G then P = G else G = S + + - Buffer Length: if S < G then return S + BUFSIZE - G else return S - G + + - Buffers Available: if G == P then return 2 else if G != S != P then return + 0 else return 1 + + The "buffer filling" flag is necessary for the "free" routine to decide + whether to advance the separator index. If the first buffer is to be freed, + then G == S and S != P. If the second buffer is already filled, then S = P. + However, if the buffer is still filling, then S must remain at G. This + cannot be determined from G, S, and P alone. + + A "buffer emptying" flag is also employed to record whether the per-buffer + header has been obtained. This allows the buffer length to exclude the + header and reflect only the characters present. +*/ + + +/* Increment a buffer index with wraparound */ + +static uint16 buf_incr (BUF_INDEX index, uint32 port, IO_OPER rw, int increment) +{ +index [port] [rw] = + (index [port] [rw] + buf_size [rw] + increment) % buf_size [rw]; + +return index [port] [rw]; +} + + +/* Initialize the buffer. + + Initialization sets the three indexes to zero and clears the buffer state + flags. +*/ + +static void buf_init (IO_OPER rw, uint32 port) +{ +mpx_get [port] [rw] = 0; /* clear indexes */ +mpx_sep [port] [rw] = 0; +mpx_put [port] [rw] = 0; + +if (rw == ioread) + mpx_flags [mpx_port] &= ~(FL_RDFLAGS); /* clear read buffer flags */ +else + mpx_flags [mpx_port] &= ~(FL_WRFLAGS); /* clear write buffer flags */ +return; +} + + +/* Get a character from the buffer. + + The character indicated by the "get" index is retrieved from the buffer, and + the index is incremented with wraparound. If the buffer is now empty, the + "buffer emptying" flag is cleared. Otherwise, it is set to indicate that + characters have been removed from the buffer. +*/ + +static uint8 buf_get (IO_OPER rw, uint32 port) +{ +uint8 ch; +uint32 index = mpx_get [port] [rw]; /* current get index */ + +if (rw == ioread) + ch = mpx_rbuf [port] [index]; /* get char from read buffer */ +else + ch = mpx_wbuf [port] [index]; /* get char from write buffer */ + +buf_incr (mpx_get, port, rw, +1); /* increment circular get index */ + +if (DEBUG_PRI (mpx_dev, DEB_BUF)) + if (mpx_flags [port] & emptying_flags [rw]) + fprintf (sim_deb, ">>MPX buf: Port %d character %s get from %s buffer " + "[%d]\n", port, fmt_char (ch), io_op [rw], index); + else + fprintf (sim_deb, ">>MPX buf: Port %d header %03o get from %s buffer " + "[%d]\n", port, ch, io_op [rw], index); + +if (mpx_get [port] [rw] == mpx_sep [port] [rw]) /* buffer now empty? */ + mpx_flags [port] &= ~emptying_flags [rw]; /* clear "buffer emptying" flag */ +else + mpx_flags [port] |= emptying_flags [rw]; /* set "buffer emptying" flag */ + +return ch; +} + + +/* Put a character to the buffer. + + The character is written to the buffer in the slot indicated by the "put" + index, and the index is incremented with wraparound. The first character put + to a new buffer reserves space for the header and sets the "buffer filling" + flag. +*/ + +static void buf_put (IO_OPER rw, uint32 port, uint8 ch) +{ +uint32 index; + +if ((mpx_flags [port] & filling_flags [rw]) == 0) { /* first put to this buffer? */ + mpx_flags [port] |= filling_flags [rw]; /* set buffer filling flag */ + index = mpx_put [port] [rw]; /* get current put index */ + buf_incr (mpx_put, port, rw, +1); /* reserve space for header */ + + if (DEBUG_PRI (mpx_dev, DEB_BUF)) + fprintf (sim_deb, ">>MPX buf: Port %d reserved header " + "for %s buffer [%d]\n", port, io_op [rw], index); + } + +index = mpx_put [port] [rw]; /* get current put index */ + +if (rw == ioread) + mpx_rbuf [port] [index] = ch; /* put char in read buffer */ +else + mpx_wbuf [port] [index] = ch; /* put char in write buffer */ + +buf_incr (mpx_put, port, rw, +1); /* increment circular put index */ + +if (DEBUG_PRI (mpx_dev, DEB_BUF)) + fprintf (sim_deb, ">>MPX buf: Port %d character %s put to %s buffer " + "[%d]\n", port, fmt_char (ch), io_op [rw], index); +return; +} + + +/* Remove the last character put to the buffer. + + The most-recent character put to the buffer is removed by decrementing the + "put" index with wraparound. +*/ + +static void buf_remove (IO_OPER rw, uint32 port) +{ +uint8 ch; +uint32 index; + +index = buf_incr (mpx_put, port, rw, -1); /* decrement circular put index */ + +if (DEBUG_PRI (mpx_dev, DEB_BUF)) { + if (rw == ioread) + ch = mpx_rbuf [port] [index]; /* pick up char from read buffer */ + else + ch = mpx_wbuf [port] [index]; /* pick up char from write buffer */ + + fprintf (sim_deb, ">>MPX buf: Port %d character %s removed from %s buffer " + "[%d]\n", port, fmt_char (ch), io_op [rw], index); + } +return; +} + + +/* Terminate the buffer. + + The buffer is marked to indicate that filling is complete and that the next + "put" operation should begin a new buffer. The header value is stored in + first byte of buffer, which is reserved, and the "buffer filling" flag is + cleared. +*/ + +static void buf_term (IO_OPER rw, uint32 port, uint8 header) +{ +uint32 index = mpx_sep [port] [rw]; /* separator index */ + +if (rw == ioread) + mpx_rbuf [port] [index] = header; /* put header in read buffer */ +else + mpx_wbuf [port] [index] = header; /* put header in write buffer */ + +mpx_flags [port] = mpx_flags [port] & ~filling_flags [rw]; /* clear filling flag */ + +if (mpx_get [port] [rw] == index) /* reached separator? */ + mpx_sep [port] [rw] = mpx_put [port] [rw]; /* move sep to end of next buffer */ + +if (DEBUG_PRI (mpx_dev, DEB_BUF)) + fprintf (sim_deb, ">>MPX buf: Port %d header %03o terminated %s buffer\n", + port, header, io_op [rw]); +return; +} + + +/* Free the buffer. + + The buffer is marked to indicate that it is available for reuse, and the + "buffer emptying" flag is reset. +*/ + +static void buf_free (IO_OPER rw, uint32 port) +{ +if ((mpx_flags [port] & filling_flags [rw]) == 0) /* not filling next buffer? */ + mpx_sep [port] [rw] = mpx_put [port] [rw]; /* move separator to end of next buffer */ + /* else it will be moved when terminated */ +mpx_flags [port] = mpx_flags [port] & ~emptying_flags [rw]; /* clear emptying flag */ + +if (DEBUG_PRI (mpx_dev, DEB_BUF)) + fprintf (sim_deb, ">>MPX buf: Port %d released %s buffer\n", port, io_op [rw]); +return; +} + + +/* Cancel the selected buffer. + + The selected buffer is marked to indicate that it is empty. Either the "put" + buffer or the "get" buffer may be selected. +*/ + +static void buf_cancel (IO_OPER rw, uint32 port, BUF_SELECT which) +{ +if (which == put) { /* cancel put buffer? */ + mpx_put [port] [rw] = mpx_sep [port] [rw]; /* move put back to separator */ + mpx_flags [port] &= ~filling_flags [rw]; /* clear filling flag */ + } + +else { /* cancel get buffer */ + if (mpx_sep [port] [rw] == mpx_get [port] [rw]) { /* filling first buffer? */ + mpx_put [port] [rw] = mpx_get [port] [rw]; /* cancel first buffer */ + mpx_flags [port] &= ~filling_flags [rw]; /* clear filling flag */ + } + + else { /* not filling first buffer */ + mpx_get [port] [rw] = mpx_sep [port] [rw]; /* cancel first buffer */ + + if ((mpx_flags [port] & filling_flags [rw]) == 0) /* not filling second buffer? */ + mpx_sep [port] [rw] = mpx_put [port] [rw]; /* move separator to end of next buffer */ + } + + mpx_flags [port] &= ~emptying_flags [rw]; /* clear emptying flag */ + } + +if (DEBUG_PRI (mpx_dev, DEB_BUF)) + fprintf (sim_deb, ">>MPX buf: Port %d cancelled %s buffer\n", port, io_op [rw]); +return; +} + + +/* Get the buffer length. + + The current length of the selected buffer (put or get) is returned. For ease + of use, the returned length does NOT include the header byte, i.e., it + reflects only the characters contained in the buffer. + + If the put buffer is selected, and the buffer is filling, or the get buffer + is selected, and the buffer is not emptying, then subtract one from the + length for the allocated header. +*/ + +static uint16 buf_len (IO_OPER rw, uint32 port, BUF_SELECT which) +{ +int16 length; + +if (which == put) + length = mpx_put [port] [rw] - mpx_sep [port] [rw] - /* calculate length */ + ((mpx_flags [port] & filling_flags [rw]) != 0); /* account for allocated header */ + +else { + length = mpx_sep [port] [rw] - mpx_get [port] [rw]; /* calculate length */ + + if (length && !(mpx_flags [port] & emptying_flags [rw])) /* not empty and not yet emptying? */ + length = length - 1; /* account for allocated header */ + } + +if (length < 0) /* is length negative? */ + return length + buf_size [rw]; /* account for wraparound */ +else + return length; +} + + +/* Return the number of free buffers available. + + Either 0, 1, or 2 free buffers will be available. A buffer is available if + it contains no characters (including the header byte). +*/ + +static uint32 buf_avail (IO_OPER rw, uint32 port) +{ +if (mpx_get [port] [rw] == mpx_put [port] [rw]) /* get and put indexes equal? */ + return 2; /* all buffers are free */ + +else if ((mpx_get [port] [rw] != mpx_sep [port] [rw]) && /* get, separator, and put */ + (mpx_sep [port] [rw] != mpx_put [port] [rw])) /* all different? */ + return 0; /* no buffers are free */ + +else + return 1; /* one buffer free */ +} diff --git a/HP2100/hp2100_ms.c b/HP2100/hp2100_ms.c index c78c5e0c..916c0fc4 100644 --- a/HP2100/hp2100_ms.c +++ b/HP2100/hp2100_ms.c @@ -1,1276 +1,1372 @@ -/* hp2100_ms.c: HP 2100 13181A/13183A magnetic tape simulator - - Copyright (c) 1993-2012, Robert M. Supnik - - 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 - ROBERT M SUPNIK 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 Robert M Supnik shall not be - used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from Robert M Supnik. - - MS 13181A 7970B 800bpi nine track magnetic tape - 13183A 7970E 1600bpi nine track magnetic tape - - 10-Feb-12 JDB Deprecated DEVNO in favor of SC - Added CNTLR_TYPE cast to ms_settype - 28-Mar-11 JDB Tidied up signal handling - 26-Oct-10 JDB Changed I/O signal handler for revised signal model - 11-Aug-08 JDB Revised to use AR instead of saved_AR in boot - 26-Jun-08 JDB Rewrote device I/O to model backplane signals - 28-Dec-06 JDB Added ioCRS state to I/O decoders - 18-Sep-06 JDB Fixed 2nd CLR after WC causing another write - Improve debug reporting, add debug flags - 14-Sep-06 JDB Removed local BOT flag, now uses sim_tape_bot - 30-Aug-06 JDB Added erase gap support, improved tape lib err reporting - 07-Jul-06 JDB Added CAPACITY as alternate for REEL - Fixed EOT test for unlimited reel size - 16-Feb-06 RMS Revised for new EOT test - 22-Jul-05 RMS Fixed compiler warning on Solaris (from Doug Glyn) - 01-Mar-05 JDB Added SET OFFLINE; rewind/offline now does not detach - 07-Oct-04 JDB Fixed enable/disable from either device - 14-Aug-04 JDB Fixed many functional and timing problems (from Dave Bryan) - - fixed erroneous execution of rejected command - - fixed erroneous execution of select-only command - - fixed erroneous execution of clear command - - fixed odd byte handling for read - - fixed spurious odd byte status on 13183A EOF - - modified handling of end of medium - - added detailed timing, with fast and realistic modes - - added reel sizes to simulate end of tape - - added debug printouts - 06-Jul-04 RMS Fixed spurious timing error after CLC (found by Dave Bryan) - 26-Apr-04 RMS Fixed SFS x,C and SFC x,C - Fixed SR setting in IBL - Revised IBL loader - Implemented DMA SRQ (follows FLG) - 25-Apr-03 RMS Revised for extended file support - 28-Mar-03 RMS Added multiformat support - 28-Feb-03 RMS Revised for magtape library - 18-Oct-02 RMS Added BOOT command, added 13183A support - 30-Sep-02 RMS Revamped error handling - 29-Aug-02 RMS Added end of medium support - 30-May-02 RMS Widened POS to 32b - 22-Apr-02 RMS Added maximum record length test - - References: - - 13181B Digital Magnetic Tape Unit Interface Kit Operating and Service Manual - (13181-90901, Nov-1982) - - 13183B Digital Magnetic Tape Unit Interface Kit Operating and Service Manual - (13183-90901, Nov-1983) - - SIMH Magtape Representation and Handling (Bob Supnik, 30-Aug-2006) -*/ - - -#include "hp2100_defs.h" -#include "hp2100_cpu.h" -#include "sim_tape.h" - -#define UNIT_V_OFFLINE (MTUF_V_UF + 0) /* unit offline */ -#define UNIT_OFFLINE (1 << UNIT_V_OFFLINE) - -#define MS_NUMDR 4 /* number of drives */ -#define DB_N_SIZE 16 /* max data buf */ -#define DBSIZE (1 << DB_N_SIZE) /* max data cmd */ -#define FNC u3 /* function */ -#define UST u4 /* unit status */ -#define REEL u5 /* tape reel size */ - -#define BPI_13181 800 /* 800 bpi for 13181 cntlr */ -#define BPI_13183 1600 /* 1600 bpi for 13183 cntlr */ -#define GAP_13181 48 /* gap is 4.8 inches for 13181 cntlr */ -#define GAP_13183 30 /* gap is 3.0 inches for 13183 cntlr */ -#define TCAP (300 * 12 * 800) /* 300 ft capacity at 800 bpi */ - -/* Debug flags */ - -#define DEB_CMDS (1 << 0) /* command init and compl */ -#define DEB_CPU (1 << 1) /* CPU I/O */ -#define DEB_RWS (1 << 2) /* tape reads, writes, status */ - -/* Command - msc_fnc */ - -#define FNC_CLR 00110 /* clear */ -#define FNC_GAP 00015 /* write gap */ -#define FNC_GFM 00215 /* gap+file mark */ -#define FNC_RC 00023 /* read */ -#define FNC_WC 00031 /* write */ -#define FNC_FSR 00003 /* forward space */ -#define FNC_BSR 00041 /* backward space */ -#define FNC_FSF 00203 /* forward file */ -#define FNC_BSF 00241 /* backward file */ -#define FNC_REW 00101 /* rewind */ -#define FNC_RWS 00105 /* rewind and offline */ -#define FNC_WFM 00211 /* write file mark */ -#define FNC_RFF 00223 /* read file fwd (diag) */ -#define FNC_RRR 00061 /* read record rev (diag) */ -#define FNC_CMPL 00400 /* completion state */ -#define FNC_V_SEL 9 /* select */ -#define FNC_M_SEL 017 -#define FNC_GETSEL(x) (((x) >> FNC_V_SEL) & FNC_M_SEL) - -#define FNF_MOT 00001 /* motion */ -#define FNF_OFL 00004 -#define FNF_WRT 00010 /* write */ -#define FNF_REV 00040 /* reverse */ -#define FNF_RWD 00100 /* rewind */ -#define FNF_CHS 00400 /* change select */ - -#define FNC_SEL ((FNC_M_SEL << FNC_V_SEL) | FNF_CHS) - -/* Status - stored in msc_sta, unit.UST (u), or dynamic (d) */ - -#define STA_PE 0100000 /* 1600 bpi (d) */ -#define STA_V_SEL 13 /* unit sel (d) */ -#define STA_M_SEL 03 -#define STA_SEL (STA_M_SEL << STA_V_SEL) -#define STA_ODD 0004000 /* odd bytes */ -#define STA_REW 0002000 /* rewinding (u) */ -#define STA_TBSY 0001000 /* transport busy (d) */ -#define STA_BUSY 0000400 /* ctrl busy */ -#define STA_EOF 0000200 /* end of file */ -#define STA_BOT 0000100 /* beg of tape (d) */ -#define STA_EOT 0000040 /* end of tape (d) */ -#define STA_TIM 0000020 /* timing error */ -#define STA_REJ 0000010 /* programming error */ -#define STA_WLK 0000004 /* write locked (d) */ -#define STA_PAR 0000002 /* parity error */ -#define STA_LOCAL 0000001 /* local (d) */ -#define STA_DYN (STA_PE | STA_SEL | STA_TBSY | STA_BOT | \ - STA_EOT | STA_WLK | STA_LOCAL) - -/* Controller types */ - -typedef enum { - A13181, - A13183 - } CNTLR_TYPE; - -CNTLR_TYPE ms_ctype = A13181; /* ctrl type */ -int32 ms_timing = 1; /* timing type */ - -struct { - FLIP_FLOP control; /* control flip-flop */ - FLIP_FLOP flag; /* flag flip-flop */ - FLIP_FLOP flagbuf; /* flag buffer flip-flop */ - } msc = { CLEAR, CLEAR, CLEAR }; - -int32 msc_sta = 0; /* status */ -int32 msc_buf = 0; /* buffer */ -int32 msc_usl = 0; /* unit select */ -int32 msc_1st = 0; /* first service */ -int32 msc_stopioe = 1; /* stop on error */ - -struct { - FLIP_FLOP control; /* control flip-flop */ - FLIP_FLOP flag; /* flag flip-flop */ - FLIP_FLOP flagbuf; /* flag buffer flip-flop */ - } msd = { CLEAR, CLEAR, CLEAR }; - -int32 msd_buf = 0; /* data buffer */ -uint8 msxb[DBSIZE] = { 0 }; /* data buffer */ -t_mtrlnt ms_ptr = 0, ms_max = 0; /* buffer ptrs */ - -/* Hardware timing at 45 IPS 13181 13183 - (based on 1580 instr/msec) instr msec SCP instr msec SCP - -------------------- -------------------- - - BOT start delay : btime = 161512 102.22 184 252800 160.00 288 - - motion cmd start delay : ctime = 14044 8.89 16 17556 11.11 20 - - GAP traversal time : gtime = 175553 111.11 200 105333 66.67 120 - - IRG traversal time : itime = 24885 15.75 - 27387 17.33 - - - rewind initiation time : rtime = 878 0.56 1 878 0.56 1 - - data xfer time / word : xtime = 88 55.56us - 44 27.78us - - - NOTE: The 13181-60001 Rev. 1629 tape diagnostic fails test 17B subtest 6 with - "E116 BYTE TIME SHORT" if the correct data transfer time is used for - 13181A interface. Set "xtime" to 115 (instructions) to pass that - diagnostic. Rev. 2040 of the tape diagnostic fixes this problem and - passes with the correct data transfer time. -*/ - -int32 msc_btime = 0; /* BOT start delay */ -int32 msc_ctime = 0; /* motion cmd start delay */ -int32 msc_gtime = 0; /* GAP traversal time */ -int32 msc_itime = 0; /* IRG traversal time */ -int32 msc_rtime = 0; /* rewind initiation time */ -int32 msc_xtime = 0; /* data xfer time / word */ - -typedef int32 TIMESET[6]; /* set of controller times */ - -int32 *const timers[] = { &msc_btime, &msc_ctime, &msc_gtime, - &msc_itime, &msc_rtime, &msc_xtime }; - -const TIMESET msc_times[3] = { - { 161512, 14044, 175553, 24885, 878, 88 }, /* 13181A */ - { 252800, 17556, 105333, 27387, 878, 44 }, /* 13183A */ - { 1, 1000, 1, 1, 100, 10 } /* FAST */ - }; - -DEVICE msd_dev, msc_dev; - -IOHANDLER msdio; -IOHANDLER mscio; - -t_stat msc_svc (UNIT *uptr); -t_stat msc_reset (DEVICE *dptr); -t_stat msc_attach (UNIT *uptr, char *cptr); -t_stat msc_detach (UNIT *uptr); -t_stat msc_online (UNIT *uptr, int32 value, char *cptr, void *desc); -t_stat msc_boot (int32 unitno, DEVICE *dptr); -t_stat ms_write_gap (UNIT *uptr); -t_stat ms_map_err (UNIT *uptr, t_stat st); -t_stat ms_settype (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat ms_showtype (FILE *st, UNIT *uptr, int32 val, void *desc); -t_stat ms_set_timing (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat ms_show_timing (FILE *st, UNIT *uptr, int32 val, void *desc); -t_stat ms_set_reelsize (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat ms_show_reelsize (FILE *st, UNIT *uptr, int32 val, void *desc); -void ms_config_timing (void); -char *ms_cmd_name (uint32 cmd); -t_stat ms_clear (void); - - -/* MSD data structures - - msd_dev MSD device descriptor - msd_unit MSD unit list - msd_reg MSD register list -*/ - -DIB ms_dib[] = { - { &msdio, MSD }, - { &mscio, MSC } - }; - -#define msd_dib ms_dib[0] -#define msc_dib ms_dib[1] - -UNIT msd_unit = { UDATA (NULL, 0, 0) }; - -REG msd_reg[] = { - { ORDATA (BUF, msd_buf, 16) }, - { FLDATA (CTL, msd.control, 0) }, - { FLDATA (FLG, msd.flag, 0) }, - { FLDATA (FBF, msd.flagbuf, 0) }, - { BRDATA (DBUF, msxb, 8, 8, DBSIZE) }, - { DRDATA (BPTR, ms_ptr, DB_N_SIZE + 1) }, - { DRDATA (BMAX, ms_max, DB_N_SIZE + 1) }, - { ORDATA (SC, msd_dib.select_code, 6), REG_HRO }, - { ORDATA (DEVNO, msd_dib.select_code, 6), REG_HRO }, - { NULL } - }; - -MTAB msd_mod[] = { - { MTAB_XTD | MTAB_VDV, 1, "SC", "SC", &hp_setsc, &hp_showsc, &msd_dev }, - { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &msd_dev }, - { 0 } - }; - -DEVICE msd_dev = { - "MSD", &msd_unit, msd_reg, msd_mod, - 1, 10, DB_N_SIZE, 1, 8, 8, - NULL, NULL, &msc_reset, - NULL, NULL, NULL, - &msd_dib, DEV_DISABLE - }; - -/* MSC data structures - - msc_dev MSC device descriptor - msc_unit MSC unit list - msc_reg MSC register list - msc_mod MSC modifier list - msc_deb MSC debug flags -*/ - -UNIT msc_unit[] = { - { UDATA (&msc_svc, UNIT_ATTABLE | UNIT_ROABLE | - UNIT_DISABLE | UNIT_OFFLINE, 0) }, - { UDATA (&msc_svc, UNIT_ATTABLE | UNIT_ROABLE | - UNIT_DISABLE | UNIT_OFFLINE, 0) }, - { UDATA (&msc_svc, UNIT_ATTABLE | UNIT_ROABLE | - UNIT_DISABLE | UNIT_OFFLINE, 0) }, - { UDATA (&msc_svc, UNIT_ATTABLE | UNIT_ROABLE | - UNIT_DISABLE | UNIT_OFFLINE, 0) } - }; - -REG msc_reg[] = { - { ORDATA (STA, msc_sta, 12) }, - { ORDATA (BUF, msc_buf, 16) }, - { ORDATA (USEL, msc_usl, 2) }, - { FLDATA (FSVC, msc_1st, 0) }, - { FLDATA (CTL, msc.control, 0) }, - { FLDATA (FLG, msc.flag, 0) }, - { FLDATA (FBF, msc.flagbuf, 0) }, - { URDATA (POS, msc_unit[0].pos, 10, T_ADDR_W, 0, MS_NUMDR, PV_LEFT) }, - { URDATA (FNC, msc_unit[0].FNC, 8, 8, 0, MS_NUMDR, REG_HRO) }, - { URDATA (UST, msc_unit[0].UST, 8, 12, 0, MS_NUMDR, REG_HRO) }, - { URDATA (REEL, msc_unit[0].REEL, 10, 2, 0, MS_NUMDR, REG_HRO) }, - { DRDATA (BTIME, msc_btime, 24), REG_NZ + PV_LEFT }, - { DRDATA (CTIME, msc_ctime, 24), REG_NZ + PV_LEFT }, - { DRDATA (GTIME, msc_gtime, 24), REG_NZ + PV_LEFT }, - { DRDATA (ITIME, msc_itime, 24), REG_NZ + PV_LEFT }, - { DRDATA (RTIME, msc_rtime, 24), REG_NZ + PV_LEFT }, - { DRDATA (XTIME, msc_xtime, 24), REG_NZ + PV_LEFT }, - { FLDATA (TIMING, ms_timing, 0), REG_HRO }, - { FLDATA (STOP_IOE, msc_stopioe, 0) }, - { FLDATA (CTYPE, ms_ctype, 0), REG_HRO }, - { ORDATA (SC, msc_dib.select_code, 6), REG_HRO }, - { ORDATA (DEVNO, msc_dib.select_code, 6), REG_HRO }, - { NULL } - }; - -MTAB msc_mod[] = { - { UNIT_OFFLINE, UNIT_OFFLINE, "offline", "OFFLINE", NULL }, - { UNIT_OFFLINE, 0, "online", "ONLINE", msc_online }, - { MTUF_WLK, 0, "write enabled", "WRITEENABLED", NULL }, - { MTUF_WLK, MTUF_WLK, "write locked", "LOCKED", NULL }, - { MTAB_XTD | MTAB_VUN, 0, "CAPACITY", "CAPACITY", - &ms_set_reelsize, &ms_show_reelsize, NULL }, - { MTAB_XTD | MTAB_VUN | MTAB_NMO, 1, "REEL", "REEL", - &ms_set_reelsize, &ms_show_reelsize, NULL }, - { MTAB_XTD | MTAB_VUN, 0, "FORMAT", "FORMAT", - &sim_tape_set_fmt, &sim_tape_show_fmt, NULL }, - { MTAB_XTD | MTAB_VDV, 0, NULL, "13181A", - &ms_settype, NULL, NULL }, - { MTAB_XTD | MTAB_VDV, 1, NULL, "13183A", - &ms_settype, NULL, NULL }, - { MTAB_XTD | MTAB_VDV, 0, "TYPE", NULL, - NULL, &ms_showtype, NULL }, - { MTAB_XTD | MTAB_VDV, 0, NULL, "REALTIME", - &ms_set_timing, NULL, NULL }, - { MTAB_XTD | MTAB_VDV, 1, NULL, "FASTTIME", - &ms_set_timing, NULL, NULL }, - { MTAB_XTD | MTAB_VDV, 0, "TIMING", NULL, - NULL, &ms_show_timing, NULL }, - { MTAB_XTD | MTAB_VDV, 1, "SC", "SC", &hp_setsc, &hp_showsc, &msd_dev }, - { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &msd_dev }, - { 0 } - }; - -DEBTAB msc_deb[] = { - { "CMDS", DEB_CMDS }, - { "CPU", DEB_CPU }, - { "RWS", DEB_RWS }, - { NULL, 0 } - }; - -DEVICE msc_dev = { - "MSC", msc_unit, msc_reg, msc_mod, - MS_NUMDR, 10, 31, 1, 8, 8, - NULL, NULL, &msc_reset, - &msc_boot, &msc_attach, &msc_detach, - &msc_dib, DEV_DISABLE | DEV_DEBUG, - 0, msc_deb, NULL, NULL - }; - - -/* Data channel I/O signal handler */ - -uint32 msdio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) -{ -IOSIGNAL signal; -IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ - -while (working_set) { - signal = IONEXT (working_set); /* isolate next signal */ - - switch (signal) { /* dispatch I/O signal */ - case ioCLF: /* clear flag flip-flop */ - msd.flag = msd.flagbuf = CLEAR; - break; - - case ioSTF: /* set flag flip-flop */ - case ioENF: /* enable flag */ - msd.flag = msd.flagbuf = SET; - break; - - case ioSFC: /* skip if flag is clear */ - setstdSKF (msd); - break; - - case ioSFS: /* skip if flag is set */ - setstdSKF (msd); - break; - - case ioIOI: /* I/O data input */ - stat_data = IORETURN (SCPE_OK, msd_buf); /* merge in return status */ - break; - - case ioIOO: /* I/O data output */ - msd_buf = IODATA (stat_data); /* store data */ - break; - - case ioPOPIO: /* power-on preset to I/O */ - ms_clear (); /* issue CLR to controller */ - break; - - case ioCRS: /* control reset */ - msd.flag = msd.flagbuf = SET; /* set flag and flag buffer */ - /* fall into CLC handler */ - case ioCLC: /* clear control flip-flop */ - msd.control = CLEAR; - break; - - case ioSTC: /* set control flip-flop */ - msd.control = SET; - break; - - case ioEDT: /* end data transfer */ - msd.flag = msd.flagbuf = CLEAR; /* same as CLF */ - break; - - case ioSIR: /* set interrupt request */ - setstdPRL (msd); /* set standard PRL signal */ - setstdIRQ (msd); /* set standard IRQ signal */ - setstdSRQ (msd); /* set standard SRQ signal */ - break; - - case ioIAK: /* interrupt acknowledge */ - msd.flagbuf = CLEAR; - break; - - default: /* all other signals */ - break; /* are ignored */ - } - - working_set = working_set & ~signal; /* remove current signal from set */ - } - -return stat_data; -} - - -/* Command channel I/O signal handler. - - Implementation notes: - - 1. Commands are usually initiated with an STC cc,C instruction. The CLR - command completes immediately and sets the flag. This requires that we - ignore the CLF part (but still process the SIR). - - 2. The command channel card clears its flag and flag buffer on EDT, but as - it never asserts SRQ, it will never get EDT. Under simulation, we omit - the EDT handler. - - 3. In hardware, the command channel card passes PRH to PRL. The data card - actually drives PRL with both channels' control and flag states. That - is, the priority chain is broken at the data card, even when the command - card is interrupting. This works in hardware, but we must break PRL at - the command card under simulation to allow the command card to interrupt. -*/ - -uint32 mscio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) -{ -static const uint8 map_sel[16] = { - 0, 0, 1, 1, 2, 2, 2, 2, - 3, 3, 3, 3, 3, 3, 3, 3 - }; -uint16 data; -int32 sched_time; -UNIT *uptr = msc_dev.units + msc_usl; - -IOSIGNAL signal; -IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ - -while (working_set) { - signal = IONEXT (working_set); /* isolate next signal */ - - switch (signal) { /* dispatch I/O signal */ - - case ioCLF: /* clear flag flip-flop */ - msc.flag = msc.flagbuf = CLEAR; - break; - - - case ioSTF: /* set flag flip-flop */ - case ioENF: /* enable flag */ - msc.flag = msc.flagbuf = SET; - break; - - - case ioSFC: /* skip if flag is clear */ - setstdSKF (msc); - break; - - - case ioSFS: /* skip if flag is set */ - setstdSKF (msc); - break; - - - case ioIOI: /* I/O data input */ - data = msc_sta & ~STA_DYN; /* get card status */ - - if ((uptr->flags & UNIT_OFFLINE) == 0) { /* online? */ - data = data | uptr->UST; /* add unit status */ - - if (sim_tape_bot (uptr)) /* BOT? */ - data = data | STA_BOT; - - if (sim_is_active (uptr) && /* TBSY unless RWD at BOT */ - !((uptr->FNC & FNF_RWD) && sim_tape_bot (uptr))) - data = data | STA_TBSY; - - if (sim_tape_wrp (uptr)) /* write prot? */ - data = data | STA_WLK; - - if (sim_tape_eot (uptr)) /* EOT? */ - data = data | STA_EOT; - } - - else - data = data | STA_TBSY | STA_LOCAL; - - if (ms_ctype == A13183) /* 13183A? */ - data = data | STA_PE | (msc_usl << STA_V_SEL); - - if (DEBUG_PRI (msc_dev, DEB_CPU)) - fprintf (sim_deb, ">>MSC LIx: Status = %06o\n", data); - - stat_data = IORETURN (SCPE_OK, data); /* merge in return status */ - break; - - - case ioIOO: /* I/O data output */ - msc_buf = IODATA (stat_data); /* clear supplied status */ - - if (DEBUG_PRI (msc_dev, DEB_CPU)) - fprintf (sim_deb, ">>MSC OTx: Command = %06o\n", msc_buf); - - msc_sta = msc_sta & ~STA_REJ; /* clear reject */ - - if ((msc_buf & 0377) == FNC_CLR) /* clear always ok */ - break; - - if (msc_sta & STA_BUSY) { /* busy? reject */ - msc_sta = msc_sta | STA_REJ; /* dont chg select */ - break; - } - - if (msc_buf & FNF_CHS) { /* select change */ - msc_usl = map_sel[FNC_GETSEL (msc_buf)]; /* is immediate */ - uptr = msc_dev.units + msc_usl; - if (DEBUG_PRI (msc_dev, DEB_CMDS)) - fprintf (sim_deb, ">>MSC OTx: Unit %d selected\n", msc_usl); - } - - if (((msc_buf & FNF_MOT) && sim_is_active (uptr)) || - ((msc_buf & FNF_REV) && sim_tape_bot (uptr)) || - ((msc_buf & FNF_WRT) && sim_tape_wrp (uptr))) - msc_sta = msc_sta | STA_REJ; /* reject? */ - - break; - - - case ioCRS: /* control reset */ - msc.flag = msc.flagbuf = SET; /* set flag and flag buffer */ - /* fall into CLC handler */ - - case ioCLC: /* clear control flip-flop */ - msc.control = CLEAR; - break; - - - case ioSTC: /* set control flip-flop */ - if (!(msc_sta & STA_REJ)) { /* last cmd rejected? */ - if ((msc_buf & 0377) == FNC_CLR) { /* clear? */ - ms_clear (); /* issue CLR to controller */ - - msc.control = SET; /* set CTL for STC */ - msc.flag = msc.flagbuf = SET; /* set FLG for completion */ - - working_set = working_set & ~ioCLF; /* eliminate possible CLF */ - - if (DEBUG_PRI (msc_dev, DEB_CMDS)) - fputs (">>MSC STC: Controller cleared\n", sim_deb); - - break; /* command completes immediately */ - } - - uptr->FNC = msc_buf & 0377; /* save function */ - - if (uptr->FNC & FNF_RWD) { /* rewind? */ - if (!sim_tape_bot (uptr)) /* not at BOT? */ - uptr->UST = STA_REW; /* set rewinding */ - - sched_time = msc_rtime; /* set response time */ - } - - else { - if (sim_tape_bot (uptr)) /* at BOT? */ - sched_time = msc_btime; /* use BOT start time */ - - else if ((uptr->FNC == FNC_GAP) || (uptr->FNC == FNC_GFM)) - sched_time = msc_gtime; /* use gap traversal time */ - - else sched_time = 0; - - if (uptr->FNC != FNC_GAP) - sched_time += msc_ctime; /* add base command time */ - } - - if (msc_buf & ~FNC_SEL) { /* NOP for unit sel alone */ - sim_activate (uptr, sched_time); /* else schedule op */ - - if (DEBUG_PRI (msc_dev, DEB_CMDS)) - fprintf (sim_deb, - ">>MSC STC: Unit %d command %03o (%s) scheduled, " - "pos = %d, time = %d\n", - msc_usl, uptr->FNC, ms_cmd_name (uptr->FNC), - uptr->pos, sched_time); - } - - else if (DEBUG_PRI (msc_dev, DEB_CMDS)) - fputs (">>MSC STC: Unit select (NOP)\n", sim_deb); - - msc_sta = STA_BUSY; /* ctrl is busy */ - msc_1st = 1; - msc.control = SET; /* go */ - } - break; - - - case ioSIR: /* set interrupt request */ - setstdPRL (msc); /* set standard PRL signal */ - setstdIRQ (msc); /* set standard IRQ signal */ - setstdSRQ (msc); /* set standard SRQ signal */ - break; - - - case ioIAK: /* interrupt acknowledge */ - msc.flagbuf = CLEAR; - break; - - - default: /* all other signals */ - break; /* are ignored */ - } - - working_set = working_set & ~signal; /* remove current signal from set */ - } - -return stat_data; -} - - -/* Unit service - - If rewind done, reposition to start of tape, set status - else, do operation, set done, interrupt. - - In addition to decreasing the timing intervals, the FASTTIME option enables - two additional optimizations: WFM for GFM substitution, and BOT gap - elimination. If FASTTIME is selected, gap and file mark (GFM) commands are - processed as WFM (write file mark) commands. That is, the preceding GAP is - not performed. Also, the initial gap that normally precedes the first data - record or EOF mark at the beginning of the tape is omitted. These omissions - result in smaller tape image files. If REALTIME is selected, the gaps are - included. Note that the gaps (and realistic timing) are necessary to pass - the 7970 diagnostics. -*/ - -t_stat msc_svc (UNIT *uptr) -{ -int32 unum; -t_mtrlnt tbc; -t_stat st, r = SCPE_OK; - -unum = uptr - msc_unit; /* get unit number */ - -if ((uptr->FNC != FNC_RWS) && (uptr->flags & UNIT_OFFLINE)) { /* offline? */ - msc_sta = (msc_sta | STA_REJ) & ~STA_BUSY; /* reject */ - mscio (&msc_dib, ioENF, 0); /* set flag */ - return IOERROR (msc_stopioe, SCPE_UNATT); - } - -switch (uptr->FNC) { /* case on function */ - - case FNC_RWS: /* rewind offline */ - sim_tape_rewind (uptr); /* rewind tape */ - uptr->flags = uptr->flags | UNIT_OFFLINE; /* set offline */ - uptr->UST = 0; /* clear REW status */ - break; /* we're done */ - - case FNC_REW: /* rewind */ - if (uptr->UST & STA_REW) { /* rewind in prog? */ - uptr->FNC |= FNC_CMPL; /* set compl state */ - sim_activate (uptr, msc_ctime); /* sched completion */ - } - break; /* anyway, ctrl done */ - - case FNC_REW | FNC_CMPL: /* complete rewind */ - sim_tape_rewind (uptr); /* rewind tape */ - uptr->UST = 0; /* clear REW status */ - return SCPE_OK; /* drive is free */ - - case FNC_GFM: /* gap + file mark */ - if (ms_timing == 1) /* fast timing? */ - goto DO_WFM; /* do plain file mark */ - /* else fall into GAP */ - case FNC_GAP: /* erase gap */ - if (DEBUG_PRI (msc_dev, DEB_RWS)) - fprintf (sim_deb, - ">>MSC svc: Unit %d wrote gap\n", - unum); - if ((r = ms_write_gap (uptr)) || /* write tape gap; error? */ - (uptr->FNC != FNC_GFM)) /* not GFM? */ - break; /* bail out now */ - /* else drop into WFM */ - case FNC_WFM: /* write file mark */ - if ((ms_timing == 0) && sim_tape_bot (uptr)) { /* realistic timing + BOT? */ - if (DEBUG_PRI (msc_dev, DEB_RWS)) - fprintf (sim_deb, - ">>MSC svc: Unit %d wrote initial gap\n", - unum); - if (st = ms_write_gap (uptr)) { /* write initial gap; error? */ - r = ms_map_err (uptr, st); /* map error */ - break; /* terminate operation */ - } - } - DO_WFM: - if (DEBUG_PRI (msc_dev, DEB_RWS)) - fprintf (sim_deb, - ">>MSC svc: Unit %d wrote file mark\n", - unum); - if (st = sim_tape_wrtmk (uptr)) /* write tmk, err? */ - r = ms_map_err (uptr, st); /* map error */ - msc_sta = STA_EOF; /* set EOF status */ - break; - - case FNC_FSR: /* space forward */ - if (st = sim_tape_sprecf (uptr, &tbc)) /* space rec fwd, err? */ - r = ms_map_err (uptr, st); /* map error */ - if (tbc & 1) - msc_sta = msc_sta | STA_ODD; - else msc_sta = msc_sta & ~STA_ODD; - break; - - case FNC_BSR: /* space reverse */ - if (st = sim_tape_sprecr (uptr, &tbc)) /* space rec rev, err? */ - r = ms_map_err (uptr, st); /* map error */ - if (tbc & 1) - msc_sta = msc_sta | STA_ODD; - else msc_sta = msc_sta & ~STA_ODD; - break; - - case FNC_FSF: /* space fwd file */ - while ((st = sim_tape_sprecf (uptr, &tbc)) == MTSE_OK) { - if (sim_tape_eot (uptr)) break; /* EOT stops */ - } - r = ms_map_err (uptr, st); /* map error */ - break; - - case FNC_BSF: /* space rev file */ - while ((st = sim_tape_sprecr (uptr, &tbc)) == MTSE_OK) ; - r = ms_map_err (uptr, st); /* map error */ - break; - - case FNC_RFF: /* diagnostic read */ - case FNC_RC: /* read */ - if (msc_1st) { /* first svc? */ - msc_1st = ms_ptr = ms_max = 0; /* clr 1st flop */ - st = sim_tape_rdrecf (uptr, msxb, &ms_max, DBSIZE); /* read rec */ - if (DEBUG_PRI (msc_dev, DEB_RWS)) - fprintf (sim_deb, - ">>MSC svc: Unit %d read %d word record\n", - unum, ms_max / 2); - if (st == MTSE_RECE) msc_sta = msc_sta | STA_PAR; /* rec in err? */ - else if (st != MTSE_OK) { /* other error? */ - r = ms_map_err (uptr, st); /* map error */ - if (r == SCPE_OK) { /* recoverable? */ - sim_activate (uptr, msc_itime); /* sched IRG */ - uptr->FNC |= FNC_CMPL; /* set completion */ - return SCPE_OK; - } - break; /* err, done */ - } - if (ms_ctype == A13183) - msc_sta = msc_sta | STA_ODD; /* set ODD for 13183A */ - } - if (msd.control && (ms_ptr < ms_max)) { /* DCH on, more data? */ - if (msd.flag) msc_sta = msc_sta | STA_TIM | STA_PAR; - msd_buf = ((uint16) msxb[ms_ptr] << 8) | - ((ms_ptr + 1 == ms_max) ? 0 : msxb[ms_ptr + 1]); - ms_ptr = ms_ptr + 2; - msdio (&msd_dib, ioENF, 0); /* set flag */ - sim_activate (uptr, msc_xtime); /* re-activate */ - return SCPE_OK; - } - if (ms_max & 1) /* set ODD by rec len */ - msc_sta = msc_sta | STA_ODD; - else msc_sta = msc_sta & ~STA_ODD; - sim_activate (uptr, msc_itime); /* sched IRG */ - if (uptr->FNC == FNC_RFF) msc_1st = 1; /* diagnostic? */ - else uptr->FNC |= FNC_CMPL; /* set completion */ - return SCPE_OK; - - case FNC_RFF | FNC_CMPL: /* diagnostic read completion */ - case FNC_RC | FNC_CMPL: /* read completion */ - break; - - case FNC_WC: /* write */ - if (msc_1st) { /* first service? */ - msc_1st = ms_ptr = 0; /* no data xfer on first svc */ - if ((ms_timing == 0) && sim_tape_bot (uptr)) { /* realistic timing + BOT? */ - if (DEBUG_PRI (msc_dev, DEB_RWS)) - fprintf (sim_deb, - ">>MSC svc: Unit %d wrote initial gap\n", - unum); - if (st = ms_write_gap (uptr)) { /* write initial gap; error? */ - r = ms_map_err (uptr, st); /* map error */ - break; /* terminate operation */ - } - } - } - else { /* not 1st, next char */ - if (ms_ptr < DBSIZE) { /* room in buffer? */ - msxb[ms_ptr] = msd_buf >> 8; /* store 2 char */ - msxb[ms_ptr + 1] = msd_buf & 0377; - ms_ptr = ms_ptr + 2; - } - else msc_sta = msc_sta | STA_PAR; - } - if (msd.control) { /* xfer flop set? */ - msdio (&msd_dib, ioENF, 0); /* set flag */ - sim_activate (uptr, msc_xtime); /* re-activate */ - return SCPE_OK; - } - if (ms_ptr) { /* any data? write */ - if (DEBUG_PRI (msc_dev, DEB_RWS)) - fprintf (sim_deb, - ">>MSC svc: Unit %d wrote %d word record\n", - unum, ms_ptr / 2); - if (st = sim_tape_wrrecf (uptr, msxb, ms_ptr)) { /* write, err? */ - r = ms_map_err (uptr, st); /* map error */ - break; - } - } - sim_activate (uptr, msc_itime); /* sched IRG */ - uptr->FNC |= FNC_CMPL; /* set completion */ - return SCPE_OK; - - case FNC_WC | FNC_CMPL: /* write completion */ - break; - - case FNC_RRR: /* not supported */ - default: /* unknown command */ - if (DEBUG_PRI (msc_dev, DEB_CMDS)) - fprintf (sim_deb, - ">>MSC svc: Unit %d command %03o is unknown (NOP)\n", - unum, uptr->FNC); - break; - } - -mscio (&msc_dib, ioENF, 0); /* set flag */ -msc_sta = msc_sta & ~STA_BUSY; /* update status */ -if (DEBUG_PRI (msc_dev, DEB_CMDS)) - fprintf (sim_deb, - ">>MSC svc: Unit %d command %03o (%s) complete\n", - unum, uptr->FNC & 0377, ms_cmd_name (uptr->FNC)); -return r; -} - - -/* Write an erase gap */ - -t_stat ms_write_gap (UNIT *uptr) -{ -t_stat st; -uint32 gap_len = ms_ctype ? GAP_13183 : GAP_13181; /* establish gap length */ -uint32 tape_bpi = ms_ctype ? BPI_13183 : BPI_13181; /* establish nominal bpi */ - -if (st = sim_tape_wrgap (uptr, gap_len, tape_bpi)) /* write gap */ - return ms_map_err (uptr, st); /* map error if failure */ -else - return SCPE_OK; -} - - -/* Map tape error status */ - -t_stat ms_map_err (UNIT *uptr, t_stat st) -{ -int32 unum = uptr - msc_unit; /* get unit number */ - -if (DEBUG_PRI (msc_dev, DEB_RWS)) - fprintf (sim_deb, - ">>MSC err: Unit %d tape library status = %d\n", - unum, st); - -switch (st) { - - case MTSE_FMT: /* illegal fmt */ - msc_sta = msc_sta | STA_REJ; /* reject cmd */ - return SCPE_FMT; /* format error */ - - case MTSE_UNATT: /* unattached */ - msc_detach (uptr); /* resync status (ignore rtn) */ - msc_sta = msc_sta | STA_REJ; /* reject cmd */ - return SCPE_UNATT; /* unit unattached */ - - case MTSE_OK: /* no error */ - return SCPE_IERR; /* never get here! */ - - case MTSE_EOM: /* end of medium */ - case MTSE_TMK: /* end of file */ - msc_sta = msc_sta | STA_EOF; - - if (ms_ctype == A13181) - msc_sta = msc_sta | STA_ODD; /* EOF also sets ODD for 13181A */ - break; - - case MTSE_INVRL: /* invalid rec lnt */ - msc_sta = msc_sta | STA_PAR; - return SCPE_MTRLNT; - - case MTSE_IOERR: /* IO error */ - msc_sta = msc_sta | STA_PAR; /* error */ - if (msc_stopioe) return SCPE_IOERR; - break; - - case MTSE_RECE: /* record in error */ - msc_sta = msc_sta | STA_PAR; /* error */ - break; - - case MTSE_WRP: /* write protect */ - msc_sta = msc_sta | STA_REJ; /* reject */ - break; - } - -return SCPE_OK; -} - - -/* Controller clear */ - -t_stat ms_clear (void) -{ -int32 i; -t_stat st; -UNIT *uptr; - -for (i = 0; i < MS_NUMDR; i++) { /* look for write in progr */ - uptr = &msc_unit [i]; /* get pointer to unit */ - - if (sim_is_active (uptr) && /* unit active? */ - (uptr->FNC == FNC_WC) && /* and last cmd write? */ - (ms_ptr > 0)) { /* and partial buffer? */ - if (DEBUG_PRI (msc_dev, DEB_RWS)) - fprintf (sim_deb, - ">>MSC rws: Unit %d wrote %d word partial record\n", i, ms_ptr / 2); - - if (st = sim_tape_wrrecf (uptr, msxb, ms_ptr | MTR_ERF)) - ms_map_err (uptr, st); /* discard any error */ - - ms_ptr = 0; /* clear partial */ - } - - if ((uptr->UST & STA_REW) == 0) - sim_cancel (uptr); /* stop if not rew */ - } - -msc_sta = msc_1st = 0; /* clr ctlr status */ - -return SCPE_OK; -} - - -/* Reset routine */ - -t_stat msc_reset (DEVICE *dptr) -{ -int32 i; -UNIT *uptr; -DIB *dibptr = (DIB *) dptr->ctxt; /* DIB pointer */ - -hp_enbdis_pair (dptr, /* make pair cons */ - (dptr == &msd_dev) ? &msc_dev : &msd_dev); - -if (sim_switches & SWMASK ('P')) /* initialization reset? */ - ms_config_timing (); - -IOPRESET (dibptr); /* PRESET device (does not use PON) */ - -msc_buf = msd_buf = 0; -msc_sta = msc_usl = 0; -msc_1st = 0; - -for (i = 0; i < MS_NUMDR; i++) { - uptr = msc_dev.units + i; - sim_tape_reset (uptr); - sim_cancel (uptr); - uptr->UST = 0; - } - -return SCPE_OK; -} - - -/* Attach routine */ - -t_stat msc_attach (UNIT *uptr, char *cptr) -{ -t_stat r; - -r = sim_tape_attach (uptr, cptr); /* attach unit */ -if (r == SCPE_OK) - uptr->flags = uptr->flags & ~UNIT_OFFLINE; /* set online */ -return r; -} - -/* Detach routine */ - -t_stat msc_detach (UNIT* uptr) -{ -uptr->UST = 0; /* clear status */ -uptr->flags = uptr->flags | UNIT_OFFLINE; /* set offline */ -return sim_tape_detach (uptr); /* detach unit */ -} - -/* Online routine */ - -t_stat msc_online (UNIT *uptr, int32 value, char *cptr, void *desc) -{ -if (uptr->flags & UNIT_ATT) return SCPE_OK; -else return SCPE_UNATT; -} - -/* Configure timing */ - -void ms_config_timing (void) -{ -uint32 i, tset; - -tset = (ms_timing << 1) | (ms_timing ? 0 : ms_ctype); /* select timing set */ -for (i = 0; i < (sizeof (timers) / sizeof (timers[0])); i++) - *timers[i] = msc_times[tset][i]; /* assign times */ -} - -/* Set controller timing */ - -t_stat ms_set_timing (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -if ((val < 0) || (val > 1) || (cptr != NULL)) return SCPE_ARG; -ms_timing = val; -ms_config_timing (); -return SCPE_OK; -} - -/* Show controller timing */ - -t_stat ms_show_timing (FILE *st, UNIT *uptr, int32 val, void *desc) -{ -if (ms_timing) fputs ("fast timing", st); -else fputs ("realistic timing", st); -return SCPE_OK; -} - -/* Set controller type */ - -t_stat ms_settype (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -int32 i; - -if ((val < 0) || (val > 1) || (cptr != NULL)) return SCPE_ARG; -for (i = 0; i < MS_NUMDR; i++) { - if (msc_unit[i].flags & UNIT_ATT) return SCPE_ALATT; - } -ms_ctype = (CNTLR_TYPE) val; -ms_config_timing (); /* update for new type */ -return SCPE_OK; -} - -/* Show controller type */ - -t_stat ms_showtype (FILE *st, UNIT *uptr, int32 val, void *desc) -{ -if (ms_ctype == A13183) - fprintf (st, "13183A"); -else - fprintf (st, "13181A"); -return SCPE_OK; -} - -/* Set unit reel size - - val = 0 -> SET MSCn CAPACITY=n - val = 1 -> SET MSCn REEL=n */ - -t_stat ms_set_reelsize (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -int32 reel; -t_stat status; - -if (val == 0) { - status = sim_tape_set_capac (uptr, val, cptr, desc); - if (status == SCPE_OK) uptr->REEL = 0; - return status; - } - -if (cptr == NULL) return SCPE_ARG; -reel = (int32) get_uint (cptr, 10, 2400, &status); -if (status != SCPE_OK) return status; -else switch (reel) { - - case 0: - uptr->REEL = 0; /* type 0 = unlimited/custom */ - break; - - case 600: - uptr->REEL = 1; /* type 1 = 600 foot */ - break; - - case 1200: - uptr->REEL = 2; /* type 2 = 1200 foot */ - break; - - case 2400: - uptr->REEL = 3; /* type 3 = 2400 foot */ - break; - - default: - return SCPE_ARG; - } - -uptr->capac = uptr->REEL ? (TCAP << uptr->REEL) << ms_ctype : 0; -return SCPE_OK; -} - -/* Show unit reel size - - val = 0 -> SHOW MSC or SHOW MSCn or SHOW MSCn CAPACITY - val = 1 -> SHOW MSCn REEL */ - -t_stat ms_show_reelsize (FILE *st, UNIT *uptr, int32 val, void *desc) -{ -t_stat status = SCPE_OK; - -if (uptr->REEL == 0) status = sim_tape_show_capac (st, uptr, val, desc); -else fprintf (st, "%4d foot reel", 300 << uptr->REEL); -if (val == 1) fputc ('\n', st); /* MTAB_NMO omits \n */ -return status; -} - -/* Translate command to mnemonic for debug logging - - The command names and descriptions are taken from the 13181 interface - manual. */ - -char *ms_cmd_name (uint32 cmd) -{ - -switch (cmd & 0377) { - case FNC_WC: return "WCC"; /* Write command */ - case FNC_WFM: return "WFM"; /* Write file mark */ - case FNC_RC: return "RRF"; /* Read record forward */ - case FNC_FSR: return "FSR"; /* Forward space record */ - case FNC_FSF: return "FSF"; /* Forward space file */ - case FNC_GAP: return "GAP"; /* Write gap */ - case FNC_BSR: return "BSR"; /* Backspace record */ - case FNC_BSF: return "BSF"; /* Backspace file */ - case FNC_REW: return "REW"; /* Rewind */ - case FNC_RWS: return "RWO"; /* Rewind off-line */ - case FNC_CLR: return "CLR"; /* Clear controller */ - case FNC_GFM: return "GFM"; /* Gap file mark */ - case FNC_RFF: return "RFF"; /* Read forward until file mark (diag) */ - case FNC_RRR: return "RRR"; /* Read record in reverse (diag) */ - - default: return "???"; /* Unknown command */ - } -} - -/* 7970B/7970E bootstrap routine (HP 12992D ROM) */ - -const BOOT_ROM ms_rom = { - 0106501, /*ST LIB 1 ; read sw */ - 0006011, /* SLB,RSS ; bit 0 set? */ - 0027714, /* JMP RD ; no read */ - 0003004, /* CMA,INA ; A is ctr */ - 0073775, /* STA WC ; save */ - 0067772, /* LDA SL0RW ; sel 0, rew */ - 0017762, /*FF JSB CMD ; do cmd */ - 0102311, /* SFS CC ; done? */ - 0027707, /* JMP *-1 ; wait */ - 0067774, /* LDB FFC ; get file fwd */ - 0037775, /* ISZ WC ; done files? */ - 0027706, /* JMP FF ; no */ - 0067773, /*RD LDB RDCMD ; read cmd */ - 0017762, /* JSB CMD ; do cmd */ - 0103710, /* STC DC,C ; start dch */ - 0102211, /* SFC CC ; read done? */ - 0027752, /* JMP STAT ; no, get stat */ - 0102310, /* SFS DC ; any data? */ - 0027717, /* JMP *-3 ; wait */ - 0107510, /* LIB DC,C ; get rec cnt */ - 0005727, /* BLF,BLF ; move to lower */ - 0007000, /* CMB ; make neg */ - 0077775, /* STA WC ; save */ - 0102211, /* SFC CC ; read done? */ - 0027752, /* JMP STAT ; no, get stat */ - 0102310, /* SFS DC ; any data? */ - 0027727, /* JMP *-3 ; wait */ - 0107510, /* LIB DC,C ; get load addr */ - 0074000, /* STB 0 ; start csum */ - 0077762, /* STA CMD ; save address */ - 0027742, /* JMP *+4 */ - 0177762, /*NW STB CMD,I ; store data */ - 0040001, /* ADA 1 ; add to csum */ - 0037762, /* ISZ CMD ; adv addr ptr */ - 0102310, /* SFS DC ; any data? */ - 0027742, /* JMP *-1 ; wait */ - 0107510, /* LIB DC,C ; get word */ - 0037775, /* ISZ WC ; done? */ - 0027737, /* JMP NW ; no */ - 0054000, /* CPB 0 ; csum ok? */ - 0027717, /* JMP RD+3 ; yes, cont */ - 0102011, /* HLT 11 ; no, halt */ - 0102511, /*ST LIA CC ; get status */ - 0001727, /* ALF,ALF ; get eof bit */ - 0002020, /* SSA ; set? */ - 0102077, /* HLT 77 ; done */ - 0001727, /* ALF,ALF ; put status back */ - 0001310, /* RAR,SLA ; read ok? */ - 0102000, /* HLT 0 ; no */ - 0027714, /* JMP RD ; read next */ - 0000000, /*CMD 0 */ - 0106611, /* OTB CC ; output cmd */ - 0102511, /* LIA CC ; check for reject */ - 0001323, /* RAR,RAR */ - 0001310, /* RAR,SLA */ - 0027763, /* JMP CMD+1 ; try again */ - 0103711, /* STC CC,C ; start command */ - 0127762, /* JMP CMD,I ; exit */ - 0001501, /*SL0RW 001501 ; select 0, rewind */ - 0001423, /*RDCMD 001423 ; read record */ - 0000203, /*FFC 000203 ; space forward file */ - 0000000, /*WC 000000 */ - 0000000, - 0000000 - }; - -t_stat msc_boot (int32 unitno, DEVICE *dptr) -{ -int32 dev; - -if (unitno != 0) return SCPE_NOFNC; /* only unit 0 */ -dev = msd_dib.select_code; /* get data chan dev */ -if (ibl_copy (ms_rom, dev)) return SCPE_IERR; /* copy boot to memory */ -SR = (SR & IBL_OPT) | IBL_MS | (dev << IBL_V_DEV); /* set SR */ -if ((sim_switches & SWMASK ('S')) && AR) SR = SR | 1; /* skip? */ -return SCPE_OK; -} +/* hp2100_ms.c: HP 2100 13181A/13183A magnetic tape simulator + + Copyright (c) 1993-2014, Robert M. Supnik + + 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 + ROBERT M SUPNIK 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 Robert M Supnik shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + + MS 13181A 7970B 800bpi nine track magnetic tape + 13183A 7970E 1600bpi nine track magnetic tape + + 30-Dec-14 JDB Added S-register parameters to ibl_copy + 24-Dec-14 JDB Use T_ADDR_FMT with t_addr values for 64-bit compatibility + Added casts for explicit downward conversions + 11-Dec-14 JDB Updated for new erase gap API, added CRCC/LRCC support + 10-Jan-13 MP Added DEV_TAPE to DEVICE flags + 09-May-12 JDB Separated assignments from conditional expressions + 10-Feb-12 JDB Deprecated DEVNO in favor of SC + Added CNTLR_TYPE cast to ms_settype + 28-Mar-11 JDB Tidied up signal handling + 26-Oct-10 JDB Changed I/O signal handler for revised signal model + 11-Aug-08 JDB Revised to use AR instead of saved_AR in boot + 26-Jun-08 JDB Rewrote device I/O to model backplane signals + 28-Dec-06 JDB Added ioCRS state to I/O decoders + 18-Sep-06 JDB Fixed 2nd CLR after WC causing another write + Improve debug reporting, add debug flags + 14-Sep-06 JDB Removed local BOT flag, now uses sim_tape_bot + 30-Aug-06 JDB Added erase gap support, improved tape lib err reporting + 07-Jul-06 JDB Added CAPACITY as alternate for REEL + Fixed EOT test for unlimited reel size + 16-Feb-06 RMS Revised for new EOT test + 22-Jul-05 RMS Fixed compiler warning on Solaris (from Doug Glyn) + 01-Mar-05 JDB Added SET OFFLINE; rewind/offline now does not detach + 07-Oct-04 JDB Fixed enable/disable from either device + 14-Aug-04 JDB Fixed many functional and timing problems (from Dave Bryan) + - fixed erroneous execution of rejected command + - fixed erroneous execution of select-only command + - fixed erroneous execution of clear command + - fixed odd byte handling for read + - fixed spurious odd byte status on 13183A EOF + - modified handling of end of medium + - added detailed timing, with fast and realistic modes + - added reel sizes to simulate end of tape + - added debug printouts + 06-Jul-04 RMS Fixed spurious timing error after CLC (found by Dave Bryan) + 26-Apr-04 RMS Fixed SFS x,C and SFC x,C + Fixed SR setting in IBL + Revised IBL loader + Implemented DMA SRQ (follows FLG) + 25-Apr-03 RMS Revised for extended file support + 28-Mar-03 RMS Added multiformat support + 28-Feb-03 RMS Revised for magtape library + 18-Oct-02 RMS Added BOOT command, added 13183A support + 30-Sep-02 RMS Revamped error handling + 29-Aug-02 RMS Added end of medium support + 30-May-02 RMS Widened POS to 32b + 22-Apr-02 RMS Added maximum record length test + + References: + - 13181B Digital Magnetic Tape Unit Interface Kit Operating and Service Manual + (13181-90901, Nov-1982) + - 13183B Digital Magnetic Tape Unit Interface Kit Operating and Service Manual + (13183-90901, Nov-1983) + - SIMH Magtape Representation and Handling (Bob Supnik, 30-Aug-2006) +*/ + + +#include "hp2100_defs.h" +#include "hp2100_cpu.h" +#include "sim_tape.h" + +#define UNIT_V_OFFLINE (MTUF_V_UF + 0) /* unit offline */ +#define UNIT_OFFLINE (1 << UNIT_V_OFFLINE) + +#define MS_NUMDR 4 /* number of drives */ +#define DB_N_SIZE 16 /* max data buf */ +#define DBSIZE (1 << DB_N_SIZE) /* max data cmd */ +#define FNC u3 /* function */ +#define UST u4 /* unit status */ +#define REEL u5 /* tape reel size */ + +#define BPI_13181 MT_DENS_800 /* 800 bpi for 13181 cntlr */ +#define BPI_13183 MT_DENS_1600 /* 1600 bpi for 13183 cntlr */ +#define GAP_13181 48 /* gap is 4.8 inches for 13181 cntlr */ +#define GAP_13183 30 /* gap is 3.0 inches for 13183 cntlr */ +#define TCAP (300 * 12 * 800) /* 300 ft capacity at 800 bpi */ + +/* Debug flags */ + +#define DEB_CMDS (1 << 0) /* command init and compl */ +#define DEB_CPU (1 << 1) /* CPU I/O */ +#define DEB_RWS (1 << 2) /* tape reads, writes, status */ + +/* Command - msc_fnc */ + +#define FNC_CLR 00110 /* clear */ +#define FNC_GAP 00015 /* write gap */ +#define FNC_GFM 00215 /* gap+file mark */ +#define FNC_RC 00023 /* read */ +#define FNC_WC 00031 /* write */ +#define FNC_FSR 00003 /* forward space */ +#define FNC_BSR 00041 /* backward space */ +#define FNC_FSF 00203 /* forward file */ +#define FNC_BSF 00241 /* backward file */ +#define FNC_REW 00101 /* rewind */ +#define FNC_RWS 00105 /* rewind and offline */ +#define FNC_WFM 00211 /* write file mark */ +#define FNC_RFF 00223 /* read file fwd (diag) */ +#define FNC_RRR 00061 /* read record rev (diag) */ +#define FNC_CMPL 00400 /* completion state */ +#define FNC_V_SEL 9 /* select */ +#define FNC_M_SEL 017 +#define FNC_GETSEL(x) (((x) >> FNC_V_SEL) & FNC_M_SEL) + +#define FNF_MOT 00001 /* motion */ +#define FNF_OFL 00004 +#define FNF_WRT 00010 /* write */ +#define FNF_REV 00040 /* reverse */ +#define FNF_RWD 00100 /* rewind */ +#define FNF_CHS 00400 /* change select */ + +#define FNC_SEL ((FNC_M_SEL << FNC_V_SEL) | FNF_CHS) + +/* Status - stored in msc_sta, unit.UST (u), or dynamic (d) */ + +#define STA_PE 0100000 /* 1600 bpi (d) */ +#define STA_V_SEL 13 /* unit sel (d) */ +#define STA_M_SEL 03 +#define STA_SEL (STA_M_SEL << STA_V_SEL) +#define STA_ODD 0004000 /* odd bytes */ +#define STA_REW 0002000 /* rewinding (u) */ +#define STA_TBSY 0001000 /* transport busy (d) */ +#define STA_BUSY 0000400 /* ctrl busy */ +#define STA_EOF 0000200 /* end of file */ +#define STA_BOT 0000100 /* beg of tape (d) */ +#define STA_EOT 0000040 /* end of tape (d) */ +#define STA_TIM 0000020 /* timing error */ +#define STA_REJ 0000010 /* programming error */ +#define STA_WLK 0000004 /* write locked (d) */ +#define STA_PAR 0000002 /* parity error */ +#define STA_LOCAL 0000001 /* local (d) */ +#define STA_DYN (STA_PE | STA_SEL | STA_TBSY | STA_BOT | \ + STA_EOT | STA_WLK | STA_LOCAL) + +/* Controller types */ + +typedef enum { + A13181, + A13183 + } CNTLR_TYPE; + +CNTLR_TYPE ms_ctype = A13181; /* ctrl type */ +int32 ms_timing = 1; /* timing type */ + +struct { + FLIP_FLOP control; /* control flip-flop */ + FLIP_FLOP flag; /* flag flip-flop */ + FLIP_FLOP flagbuf; /* flag buffer flip-flop */ + } msc = { CLEAR, CLEAR, CLEAR }; + +int32 msc_sta = 0; /* status */ +int32 msc_buf = 0; /* buffer */ +int32 msc_usl = 0; /* unit select */ +int32 msc_1st = 0; /* first service */ +int32 msc_stopioe = 1; /* stop on error */ + +struct { + FLIP_FLOP control; /* control flip-flop */ + FLIP_FLOP flag; /* flag flip-flop */ + FLIP_FLOP flagbuf; /* flag buffer flip-flop */ + } msd = { CLEAR, CLEAR, CLEAR }; + +int32 msd_buf = 0; /* data buffer */ +uint8 msxb[DBSIZE] = { 0 }; /* data buffer */ +t_mtrlnt ms_ptr = 0, ms_max = 0; /* buffer ptrs */ +t_bool ms_crc = FALSE; /* buffer ready for CRC calc */ + + +/* Hardware timing at 45 IPS 13181 13183 + (based on 1580 instr/msec) instr msec SCP instr msec SCP + -------------------- -------------------- + - BOT start delay : btime = 161512 102.22 184 252800 160.00 288 + - motion cmd start delay : ctime = 14044 8.89 16 17556 11.11 20 + - GAP traversal time : gtime = 175553 111.11 200 105333 66.67 120 + - IRG traversal time : itime = 24885 15.75 - 27387 17.33 - + - rewind initiation time : rtime = 878 0.56 1 878 0.56 1 + - data xfer time / word : xtime = 88 55.56us - 44 27.78us - + + NOTE: The 13181-60001 Rev. 1629 tape diagnostic fails test 17B subtest 6 with + "E116 BYTE TIME SHORT" if the correct data transfer time is used for + 13181A interface. Set "xtime" to 115 (instructions) to pass that + diagnostic. Rev. 2040 of the tape diagnostic fixes this problem and + passes with the correct data transfer time. +*/ + +int32 msc_btime = 0; /* BOT start delay */ +int32 msc_ctime = 0; /* motion cmd start delay */ +int32 msc_gtime = 0; /* GAP traversal time */ +int32 msc_itime = 0; /* IRG traversal time */ +int32 msc_rtime = 0; /* rewind initiation time */ +int32 msc_xtime = 0; /* data xfer time / word */ + +typedef int32 TIMESET[6]; /* set of controller times */ + +int32 *const timers[] = { &msc_btime, &msc_ctime, &msc_gtime, + &msc_itime, &msc_rtime, &msc_xtime }; + +const TIMESET msc_times[3] = { + { 161512, 14044, 175553, 24885, 878, 88 }, /* 13181A */ + { 252800, 17556, 105333, 27387, 878, 44 }, /* 13183A */ + { 1, 1000, 1, 1, 100, 10 } /* FAST */ + }; + +DEVICE msd_dev, msc_dev; + +IOHANDLER msdio; +IOHANDLER mscio; + +t_stat msc_svc (UNIT *uptr); +t_stat msc_reset (DEVICE *dptr); +t_stat msc_attach (UNIT *uptr, char *cptr); +t_stat msc_detach (UNIT *uptr); +t_stat msc_online (UNIT *uptr, int32 value, char *cptr, void *desc); +t_stat msc_boot (int32 unitno, DEVICE *dptr); +t_stat ms_write_gap (UNIT *uptr); +t_stat ms_map_err (UNIT *uptr, t_stat st); +t_stat ms_settype (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat ms_showtype (FILE *st, UNIT *uptr, int32 val, void *desc); +t_stat ms_set_timing (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat ms_show_timing (FILE *st, UNIT *uptr, int32 val, void *desc); +t_stat ms_set_reelsize (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat ms_show_reelsize (FILE *st, UNIT *uptr, int32 val, void *desc); +void ms_config_timing (void); +char *ms_cmd_name (uint32 cmd); +t_stat ms_clear (void); +static uint32 calc_crc_lrc (uint8 *buffer, t_mtrlnt length); + + +/* MSD data structures + + msd_dev MSD device descriptor + msd_unit MSD unit list + msd_reg MSD register list +*/ + +DIB ms_dib[] = { + { &msdio, MSD }, + { &mscio, MSC } + }; + +#define msd_dib ms_dib[0] +#define msc_dib ms_dib[1] + +UNIT msd_unit = { UDATA (NULL, 0, 0) }; + +REG msd_reg[] = { + { ORDATA (BUF, msd_buf, 16) }, + { FLDATA (CTL, msd.control, 0) }, + { FLDATA (FLG, msd.flag, 0) }, + { FLDATA (FBF, msd.flagbuf, 0) }, + { BRDATA (DBUF, msxb, 8, 8, DBSIZE) }, + { DRDATA (BPTR, ms_ptr, DB_N_SIZE + 1) }, + { DRDATA (BMAX, ms_max, DB_N_SIZE + 1) }, + { ORDATA (SC, msd_dib.select_code, 6), REG_HRO }, + { ORDATA (DEVNO, msd_dib.select_code, 6), REG_HRO }, + { NULL } + }; + +MTAB msd_mod[] = { + { MTAB_XTD | MTAB_VDV, 1, "SC", "SC", &hp_setsc, &hp_showsc, &msd_dev }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &msd_dev }, + { 0 } + }; + +DEVICE msd_dev = { + "MSD", &msd_unit, msd_reg, msd_mod, + 1, 10, DB_N_SIZE, 1, 8, 8, + NULL, NULL, &msc_reset, + NULL, NULL, NULL, + &msd_dib, DEV_DISABLE + }; + +/* MSC data structures + + msc_dev MSC device descriptor + msc_unit MSC unit list + msc_reg MSC register list + msc_mod MSC modifier list + msc_deb MSC debug flags +*/ + +UNIT msc_unit[] = { + { UDATA (&msc_svc, UNIT_ATTABLE | UNIT_ROABLE | + UNIT_DISABLE | UNIT_OFFLINE, 0) }, + { UDATA (&msc_svc, UNIT_ATTABLE | UNIT_ROABLE | + UNIT_DISABLE | UNIT_OFFLINE, 0) }, + { UDATA (&msc_svc, UNIT_ATTABLE | UNIT_ROABLE | + UNIT_DISABLE | UNIT_OFFLINE, 0) }, + { UDATA (&msc_svc, UNIT_ATTABLE | UNIT_ROABLE | + UNIT_DISABLE | UNIT_OFFLINE, 0) } + }; + +REG msc_reg[] = { + { ORDATA (STA, msc_sta, 12) }, + { ORDATA (BUF, msc_buf, 16) }, + { ORDATA (USEL, msc_usl, 2) }, + { FLDATA (FSVC, msc_1st, 0) }, + { FLDATA (CTL, msc.control, 0) }, + { FLDATA (FLG, msc.flag, 0) }, + { FLDATA (FBF, msc.flagbuf, 0) }, + { URDATA (POS, msc_unit[0].pos, 10, T_ADDR_W, 0, MS_NUMDR, PV_LEFT) }, + { URDATA (FNC, msc_unit[0].FNC, 8, 8, 0, MS_NUMDR, REG_HRO) }, + { URDATA (UST, msc_unit[0].UST, 8, 12, 0, MS_NUMDR, REG_HRO) }, + { URDATA (REEL, msc_unit[0].REEL, 10, 2, 0, MS_NUMDR, REG_HRO) }, + { DRDATA (BTIME, msc_btime, 24), REG_NZ + PV_LEFT }, + { DRDATA (CTIME, msc_ctime, 24), REG_NZ + PV_LEFT }, + { DRDATA (GTIME, msc_gtime, 24), REG_NZ + PV_LEFT }, + { DRDATA (ITIME, msc_itime, 24), REG_NZ + PV_LEFT }, + { DRDATA (RTIME, msc_rtime, 24), REG_NZ + PV_LEFT }, + { DRDATA (XTIME, msc_xtime, 24), REG_NZ + PV_LEFT }, + { FLDATA (TIMING, ms_timing, 0), REG_HRO }, + { FLDATA (STOP_IOE, msc_stopioe, 0) }, + { FLDATA (CTYPE, ms_ctype, 0), REG_HRO }, + { ORDATA (SC, msc_dib.select_code, 6), REG_HRO }, + { ORDATA (DEVNO, msc_dib.select_code, 6), REG_HRO }, + { NULL } + }; + +MTAB msc_mod[] = { + { UNIT_OFFLINE, UNIT_OFFLINE, "offline", "OFFLINE", NULL }, + { UNIT_OFFLINE, 0, "online", "ONLINE", msc_online }, + { MTUF_WLK, 0, "write enabled", "WRITEENABLED", NULL }, + { MTUF_WLK, MTUF_WLK, "write locked", "LOCKED", NULL }, + { MTAB_XTD | MTAB_VUN, 0, "CAPACITY", "CAPACITY", + &ms_set_reelsize, &ms_show_reelsize, NULL }, + { MTAB_XTD | MTAB_VUN | MTAB_NMO, 1, "REEL", "REEL", + &ms_set_reelsize, &ms_show_reelsize, NULL }, + { MTAB_XTD | MTAB_VUN, 0, "FORMAT", "FORMAT", + &sim_tape_set_fmt, &sim_tape_show_fmt, NULL }, + { MTAB_XTD | MTAB_VDV, 0, NULL, "13181A", + &ms_settype, NULL, NULL }, + { MTAB_XTD | MTAB_VDV, 1, NULL, "13183A", + &ms_settype, NULL, NULL }, + { MTAB_XTD | MTAB_VDV, 0, "TYPE", NULL, + NULL, &ms_showtype, NULL }, + { MTAB_XTD | MTAB_VDV, 0, NULL, "REALTIME", + &ms_set_timing, NULL, NULL }, + { MTAB_XTD | MTAB_VDV, 1, NULL, "FASTTIME", + &ms_set_timing, NULL, NULL }, + { MTAB_XTD | MTAB_VDV, 0, "TIMING", NULL, + NULL, &ms_show_timing, NULL }, + { MTAB_XTD | MTAB_VDV, 1, "SC", "SC", &hp_setsc, &hp_showsc, &msd_dev }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &msd_dev }, + { 0 } + }; + +DEBTAB msc_deb[] = { + { "CMDS", DEB_CMDS }, + { "CPU", DEB_CPU }, + { "RWS", DEB_RWS }, + { NULL, 0 } + }; + +DEVICE msc_dev = { + "MSC", msc_unit, msc_reg, msc_mod, + MS_NUMDR, 10, 31, 1, 8, 8, + NULL, NULL, &msc_reset, + &msc_boot, &msc_attach, &msc_detach, + &msc_dib, DEV_DISABLE | DEV_DEBUG | DEV_TAPE, + 0, msc_deb, NULL, NULL + }; + + +/* Data channel I/O signal handler */ + +uint32 msdio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) +{ +uint32 check; +IOSIGNAL signal; +IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ + +while (working_set) { + signal = IONEXT (working_set); /* isolate next signal */ + + switch (signal) { /* dispatch I/O signal */ + case ioCLF: /* clear flag flip-flop */ + msd.flag = msd.flagbuf = CLEAR; + break; + + case ioSTF: /* set flag flip-flop */ + case ioENF: /* enable flag */ + msd.flag = msd.flagbuf = SET; + break; + + case ioSFC: /* skip if flag is clear */ + setstdSKF (msd); + break; + + case ioSFS: /* skip if flag is set */ + setstdSKF (msd); + break; + + case ioIOI: /* I/O data input */ + if (ms_crc) { /* ready for CRC? */ + check = calc_crc_lrc (msxb, ms_max); /* calculate CRCC and LRCC */ + msd_buf = check >> 8 & 0177400 /* position CRCC in upper byte */ + | check & 0377; /* and LRCC in lower byte */ + } + + stat_data = IORETURN (SCPE_OK, msd_buf); /* merge in return status */ + break; + + case ioIOO: /* I/O data output */ + msd_buf = IODATA (stat_data); /* store data */ + break; + + case ioPOPIO: /* power-on preset to I/O */ + ms_clear (); /* issue CLR to controller */ + break; + + case ioCRS: /* control reset */ + msd.flag = msd.flagbuf = SET; /* set flag and flag buffer */ + /* fall into CLC handler */ + case ioCLC: /* clear control flip-flop */ + msd.control = CLEAR; + break; + + case ioSTC: /* set control flip-flop */ + ms_crc = FALSE; /* reset CRC ready */ + msd.control = SET; + break; + + case ioEDT: /* end data transfer */ + msd.flag = msd.flagbuf = CLEAR; /* same as CLF */ + break; + + case ioSIR: /* set interrupt request */ + setstdPRL (msd); /* set standard PRL signal */ + setstdIRQ (msd); /* set standard IRQ signal */ + setstdSRQ (msd); /* set standard SRQ signal */ + break; + + case ioIAK: /* interrupt acknowledge */ + msd.flagbuf = CLEAR; + break; + + default: /* all other signals */ + break; /* are ignored */ + } + + working_set = working_set & ~signal; /* remove current signal from set */ + } + +return stat_data; +} + + +/* Command channel I/O signal handler. + + Implementation notes: + + 1. Commands are usually initiated with an STC cc,C instruction. The CLR + command completes immediately and sets the flag. This requires that we + ignore the CLF part (but still process the SIR). + + 2. The command channel card clears its flag and flag buffer on EDT, but as + it never asserts SRQ, it will never get EDT. Under simulation, we omit + the EDT handler. + + 3. In hardware, the command channel card passes PRH to PRL. The data card + actually drives PRL with both channels' control and flag states. That + is, the priority chain is broken at the data card, even when the command + card is interrupting. This works in hardware, but we must break PRL at + the command card under simulation to allow the command card to interrupt. +*/ + +uint32 mscio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) +{ +static const uint8 map_sel[16] = { + 0, 0, 1, 1, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 3 + }; +uint16 data; +int32 sched_time; +UNIT *uptr = msc_dev.units + msc_usl; + +IOSIGNAL signal; +IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ + +while (working_set) { + signal = IONEXT (working_set); /* isolate next signal */ + + switch (signal) { /* dispatch I/O signal */ + + case ioCLF: /* clear flag flip-flop */ + msc.flag = msc.flagbuf = CLEAR; + break; + + + case ioSTF: /* set flag flip-flop */ + case ioENF: /* enable flag */ + msc.flag = msc.flagbuf = SET; + break; + + + case ioSFC: /* skip if flag is clear */ + setstdSKF (msc); + break; + + + case ioSFS: /* skip if flag is set */ + setstdSKF (msc); + break; + + + case ioIOI: /* I/O data input */ + data = (uint16) (msc_sta & ~STA_DYN); /* get card status */ + + if ((uptr->flags & UNIT_OFFLINE) == 0) { /* online? */ + data = data | (uint16) uptr->UST; /* add unit status */ + + if (sim_tape_bot (uptr)) /* BOT? */ + data = data | STA_BOT; + + if (sim_is_active (uptr) && /* TBSY unless RWD at BOT */ + !((uptr->FNC & FNF_RWD) && sim_tape_bot (uptr))) + data = data | STA_TBSY; + + if (sim_tape_wrp (uptr)) /* write prot? */ + data = data | STA_WLK; + + if (sim_tape_eot (uptr)) /* EOT? */ + data = data | STA_EOT; + } + + else + data = data | STA_TBSY | STA_LOCAL; + + if (ms_ctype == A13183) /* 13183A? */ + data = data | STA_PE | (uint16) (msc_usl << STA_V_SEL); + + if (DEBUG_PRI (msc_dev, DEB_CPU)) + fprintf (sim_deb, ">>MSC LIx: Status = %06o\n", data); + + stat_data = IORETURN (SCPE_OK, data); /* merge in return status */ + break; + + + case ioIOO: /* I/O data output */ + msc_buf = IODATA (stat_data); /* clear supplied status */ + + if (DEBUG_PRI (msc_dev, DEB_CPU)) + fprintf (sim_deb, ">>MSC OTx: Command = %06o\n", msc_buf); + + msc_sta = msc_sta & ~STA_REJ; /* clear reject */ + + if ((msc_buf & 0377) == FNC_CLR) /* clear always ok */ + break; + + if (msc_sta & STA_BUSY) { /* busy? reject */ + msc_sta = msc_sta | STA_REJ; /* dont chg select */ + break; + } + + if (msc_buf & FNF_CHS) { /* select change */ + msc_usl = map_sel[FNC_GETSEL (msc_buf)]; /* is immediate */ + uptr = msc_dev.units + msc_usl; + if (DEBUG_PRI (msc_dev, DEB_CMDS)) + fprintf (sim_deb, ">>MSC OTx: Unit %d selected\n", msc_usl); + } + + if (((msc_buf & FNF_MOT) && sim_is_active (uptr)) || + ((msc_buf & FNF_REV) && sim_tape_bot (uptr)) || + ((msc_buf & FNF_WRT) && sim_tape_wrp (uptr))) + msc_sta = msc_sta | STA_REJ; /* reject? */ + + break; + + + case ioCRS: /* control reset */ + msc.flag = msc.flagbuf = SET; /* set flag and flag buffer */ + /* fall into CLC handler */ + + case ioCLC: /* clear control flip-flop */ + msc.control = CLEAR; + break; + + + case ioSTC: /* set control flip-flop */ + if (!(msc_sta & STA_REJ)) { /* last cmd rejected? */ + if ((msc_buf & 0377) == FNC_CLR) { /* clear? */ + ms_clear (); /* issue CLR to controller */ + + msc.control = SET; /* set CTL for STC */ + msc.flag = msc.flagbuf = SET; /* set FLG for completion */ + + working_set = working_set & ~ioCLF; /* eliminate possible CLF */ + + if (DEBUG_PRI (msc_dev, DEB_CMDS)) + fputs (">>MSC STC: Controller cleared\n", sim_deb); + + break; /* command completes immediately */ + } + + uptr->FNC = msc_buf & 0377; /* save function */ + + if (uptr->FNC & FNF_RWD) { /* rewind? */ + if (!sim_tape_bot (uptr)) /* not at BOT? */ + uptr->UST = STA_REW; /* set rewinding */ + + sched_time = msc_rtime; /* set response time */ + } + + else { + if (sim_tape_bot (uptr)) /* at BOT? */ + sched_time = msc_btime; /* use BOT start time */ + + else if ((uptr->FNC == FNC_GAP) || (uptr->FNC == FNC_GFM)) + sched_time = msc_gtime; /* use gap traversal time */ + + else sched_time = 0; + + if (uptr->FNC != FNC_GAP) + sched_time += msc_ctime; /* add base command time */ + } + + if (msc_buf & ~FNC_SEL) { /* NOP for unit sel alone */ + sim_activate (uptr, sched_time); /* else schedule op */ + + if (DEBUG_PRI (msc_dev, DEB_CMDS)) + fprintf (sim_deb, + ">>MSC STC: Unit %d command %03o (%s) scheduled, " + "pos = %" T_ADDR_FMT "d, time = %d\n", + msc_usl, uptr->FNC, ms_cmd_name (uptr->FNC), + uptr->pos, sched_time); + } + + else if (DEBUG_PRI (msc_dev, DEB_CMDS)) + fputs (">>MSC STC: Unit select (NOP)\n", sim_deb); + + msc_sta = STA_BUSY; /* ctrl is busy */ + msc_1st = 1; + msc.control = SET; /* go */ + } + break; + + + case ioSIR: /* set interrupt request */ + setstdPRL (msc); /* set standard PRL signal */ + setstdIRQ (msc); /* set standard IRQ signal */ + setstdSRQ (msc); /* set standard SRQ signal */ + break; + + + case ioIAK: /* interrupt acknowledge */ + msc.flagbuf = CLEAR; + break; + + + default: /* all other signals */ + break; /* are ignored */ + } + + working_set = working_set & ~signal; /* remove current signal from set */ + } + +return stat_data; +} + + +/* Unit service + + If rewind done, reposition to start of tape, set status + else, do operation, set done, interrupt. + + In addition to decreasing the timing intervals, the FASTTIME option enables + two additional optimizations: WFM for GFM substitution, and BOT gap + elimination. If FASTTIME is selected, gap and file mark (GFM) commands are + processed as WFM (write file mark) commands. That is, the preceding GAP is + not performed. Also, the initial gap that normally precedes the first data + record or EOF mark at the beginning of the tape is omitted. These omissions + result in smaller tape image files. If REALTIME is selected, the gaps are + included. Note that the gaps (and realistic timing) are necessary to pass + the 7970 diagnostics. +*/ + +t_stat msc_svc (UNIT *uptr) +{ +int32 unum; +t_mtrlnt tbc; +t_stat st, r = SCPE_OK; + +unum = uptr - msc_unit; /* get unit number */ + +if ((uptr->FNC != FNC_RWS) && (uptr->flags & UNIT_OFFLINE)) { /* offline? */ + msc_sta = (msc_sta | STA_REJ) & ~STA_BUSY; /* reject */ + mscio (&msc_dib, ioENF, 0); /* set flag */ + return IOERROR (msc_stopioe, SCPE_UNATT); + } + +switch (uptr->FNC) { /* case on function */ + + case FNC_RWS: /* rewind offline */ + sim_tape_rewind (uptr); /* rewind tape */ + uptr->flags = uptr->flags | UNIT_OFFLINE; /* set offline */ + uptr->UST = 0; /* clear REW status */ + break; /* we're done */ + + case FNC_REW: /* rewind */ + if (uptr->UST & STA_REW) { /* rewind in prog? */ + uptr->FNC |= FNC_CMPL; /* set compl state */ + sim_activate (uptr, msc_ctime); /* sched completion */ + } + break; /* anyway, ctrl done */ + + case FNC_REW | FNC_CMPL: /* complete rewind */ + sim_tape_rewind (uptr); /* rewind tape */ + uptr->UST = 0; /* clear REW status */ + return SCPE_OK; /* drive is free */ + + case FNC_GFM: /* gap + file mark */ + if (ms_timing == 1) /* fast timing? */ + goto DO_WFM; /* do plain file mark */ + /* else fall into GAP */ + case FNC_GAP: /* erase gap */ + if (DEBUG_PRI (msc_dev, DEB_RWS)) + fprintf (sim_deb, + ">>MSC svc: Unit %d wrote gap\n", + unum); + r = ms_write_gap (uptr); /* write tape gap*/ + + if (r || (uptr->FNC != FNC_GFM)) /* if error or not GFM */ + break; /* then bail out now */ + /* else drop into WFM */ + case FNC_WFM: /* write file mark */ + if ((ms_timing == 0) && sim_tape_bot (uptr)) { /* realistic timing + BOT? */ + if (DEBUG_PRI (msc_dev, DEB_RWS)) + fprintf (sim_deb, + ">>MSC svc: Unit %d wrote initial gap\n", + unum); + st = ms_write_gap (uptr); /* write initial gap*/ + if (st != MTSE_OK) { /* error? */ + r = ms_map_err (uptr, st); /* map error */ + break; /* terminate operation */ + } + } + DO_WFM: + if (DEBUG_PRI (msc_dev, DEB_RWS)) + fprintf (sim_deb, + ">>MSC svc: Unit %d wrote file mark\n", + unum); + st = sim_tape_wrtmk (uptr); /* write tmk */ + if (st != MTSE_OK) /* error? */ + r = ms_map_err (uptr, st); /* map error */ + msc_sta = STA_EOF; /* set EOF status */ + break; + + case FNC_FSR: /* space forward */ + st = sim_tape_sprecf (uptr, &tbc); /* space rec fwd */ + if (st != MTSE_OK) /* error? */ + r = ms_map_err (uptr, st); /* map error */ + if (tbc & 1) + msc_sta = msc_sta | STA_ODD; + else msc_sta = msc_sta & ~STA_ODD; + break; + + case FNC_BSR: /* space reverse */ + st = sim_tape_sprecr (uptr, &tbc); /* space rec rev*/ + if (st != MTSE_OK) /* error? */ + r = ms_map_err (uptr, st); /* map error */ + if (tbc & 1) + msc_sta = msc_sta | STA_ODD; + else msc_sta = msc_sta & ~STA_ODD; + break; + + case FNC_FSF: /* space fwd file */ + while ((st = sim_tape_sprecf (uptr, &tbc)) == MTSE_OK) { + if (sim_tape_eot (uptr)) break; /* EOT stops */ + } + r = ms_map_err (uptr, st); /* map error */ + break; + + case FNC_BSF: /* space rev file */ + while ((st = sim_tape_sprecr (uptr, &tbc)) == MTSE_OK) ; + r = ms_map_err (uptr, st); /* map error */ + break; + + case FNC_RFF: /* diagnostic read */ + case FNC_RC: /* read */ + if (msc_1st) { /* first svc? */ + msc_1st = ms_ptr = ms_max = 0; /* clr 1st flop */ + st = sim_tape_rdrecf (uptr, msxb, &ms_max, DBSIZE); /* read rec */ + if (DEBUG_PRI (msc_dev, DEB_RWS)) + fprintf (sim_deb, + ">>MSC svc: Unit %d read %d word record\n", + unum, ms_max / 2); + if (st == MTSE_RECE) msc_sta = msc_sta | STA_PAR; /* rec in err? */ + else if (st != MTSE_OK) { /* other error? */ + r = ms_map_err (uptr, st); /* map error */ + if (r == SCPE_OK) { /* recoverable? */ + sim_activate (uptr, msc_itime); /* sched IRG */ + uptr->FNC |= FNC_CMPL; /* set completion */ + return SCPE_OK; + } + break; /* err, done */ + } + if (ms_ctype == A13183) + msc_sta = msc_sta | STA_ODD; /* set ODD for 13183A */ + } + if (msd.control && (ms_ptr < ms_max)) { /* DCH on, more data? */ + if (msd.flag) msc_sta = msc_sta | STA_TIM | STA_PAR; + msd_buf = ((uint16) msxb[ms_ptr] << 8) | + ((ms_ptr + 1 == ms_max) ? 0 : msxb[ms_ptr + 1]); + ms_ptr = ms_ptr + 2; + msdio (&msd_dib, ioENF, 0); /* set flag */ + sim_activate (uptr, msc_xtime); /* re-activate */ + return SCPE_OK; + } + if (ms_max & 1) /* set ODD by rec len */ + msc_sta = msc_sta | STA_ODD; + else msc_sta = msc_sta & ~STA_ODD; + sim_activate (uptr, msc_itime); /* sched IRG */ + if (uptr->FNC == FNC_RFF) /* diagnostic? */ + msc_1st = 1; /* restart */ + else { + uptr->FNC |= FNC_CMPL; /* set completion */ + ms_crc = TRUE; /* and CRC ready */ + } + return SCPE_OK; + + case FNC_RFF | FNC_CMPL: /* diagnostic read completion */ + case FNC_RC | FNC_CMPL: /* read completion */ + break; + + case FNC_WC: /* write */ + if (msc_1st) { /* first service? */ + msc_1st = ms_ptr = 0; /* no data xfer on first svc */ + if ((ms_timing == 0) && sim_tape_bot (uptr)) { /* realistic timing + BOT? */ + if (DEBUG_PRI (msc_dev, DEB_RWS)) + fprintf (sim_deb, + ">>MSC svc: Unit %d wrote initial gap\n", + unum); + st = ms_write_gap (uptr); /* write initial gap */ + if (st != MTSE_OK) { /* error? */ + r = ms_map_err (uptr, st); /* map error */ + break; /* terminate operation */ + } + } + } + else { /* not 1st, next char */ + if (ms_ptr < DBSIZE) { /* room in buffer? */ + msxb[ms_ptr] = (uint8) (msd_buf >> 8); /* store 2 char */ + msxb[ms_ptr + 1] = msd_buf & 0377; + ms_ptr = ms_ptr + 2; + } + else msc_sta = msc_sta | STA_PAR; + } + if (msd.control) { /* xfer flop set? */ + msdio (&msd_dib, ioENF, 0); /* set flag */ + sim_activate (uptr, msc_xtime); /* re-activate */ + return SCPE_OK; + } + if (ms_ptr) { /* any data? write */ + if (DEBUG_PRI (msc_dev, DEB_RWS)) + fprintf (sim_deb, + ">>MSC svc: Unit %d wrote %d word record\n", + unum, ms_ptr / 2); + st = sim_tape_wrrecf (uptr, msxb, ms_ptr); /* write */ + if (st != MTSE_OK) { + r = ms_map_err (uptr, st); /* map error */ + break; + } + } + sim_activate (uptr, msc_itime); /* sched IRG */ + uptr->FNC |= FNC_CMPL; /* set completion */ + ms_max = ms_ptr; /* indicate buffer complete */ + ms_crc = TRUE; /* and CRC may be generated */ + return SCPE_OK; + + case FNC_WC | FNC_CMPL: /* write completion */ + break; + + case FNC_RRR: /* not supported */ + default: /* unknown command */ + if (DEBUG_PRI (msc_dev, DEB_CMDS)) + fprintf (sim_deb, + ">>MSC svc: Unit %d command %03o is unknown (NOP)\n", + unum, uptr->FNC); + break; + } + +mscio (&msc_dib, ioENF, 0); /* set flag */ +msc_sta = msc_sta & ~STA_BUSY; /* update status */ +if (DEBUG_PRI (msc_dev, DEB_CMDS)) + fprintf (sim_deb, + ">>MSC svc: Unit %d command %03o (%s) complete\n", + unum, uptr->FNC & 0377, ms_cmd_name (uptr->FNC)); +return r; +} + + +/* Write an erase gap */ + +t_stat ms_write_gap (UNIT *uptr) +{ +t_stat st; +uint32 gap_len = ms_ctype ? GAP_13183 : GAP_13181; /* establish gap length */ + +st = sim_tape_wrgap (uptr, gap_len); /* write gap */ + +if (st != MTSE_OK) + return ms_map_err (uptr, st); /* map error if failure */ +else + return SCPE_OK; +} + + +/* Map tape error status */ + +t_stat ms_map_err (UNIT *uptr, t_stat st) +{ +int32 unum = uptr - msc_unit; /* get unit number */ + +if (DEBUG_PRI (msc_dev, DEB_RWS)) + fprintf (sim_deb, + ">>MSC err: Unit %d tape library status = %d\n", + unum, st); + +switch (st) { + + case MTSE_FMT: /* illegal fmt */ + msc_sta = msc_sta | STA_REJ; /* reject cmd */ + return SCPE_FMT; /* format error */ + + case MTSE_UNATT: /* unattached */ + msc_detach (uptr); /* resync status (ignore rtn) */ + msc_sta = msc_sta | STA_REJ; /* reject cmd */ + return SCPE_UNATT; /* unit unattached */ + + case MTSE_OK: /* no error */ + return SCPE_IERR; /* never get here! */ + + case MTSE_EOM: /* end of medium */ + case MTSE_TMK: /* end of file */ + msc_sta = msc_sta | STA_EOF; + + if (ms_ctype == A13181) + msc_sta = msc_sta | STA_ODD; /* EOF also sets ODD for 13181A */ + break; + + case MTSE_INVRL: /* invalid rec lnt */ + msc_sta = msc_sta | STA_PAR; + return SCPE_MTRLNT; + + case MTSE_IOERR: /* IO error */ + msc_sta = msc_sta | STA_PAR; /* error */ + if (msc_stopioe) return SCPE_IOERR; + break; + + case MTSE_RECE: /* record in error */ + msc_sta = msc_sta | STA_PAR; /* error */ + break; + + case MTSE_WRP: /* write protect */ + msc_sta = msc_sta | STA_REJ; /* reject */ + break; + } + +return SCPE_OK; +} + + +/* Controller clear */ + +t_stat ms_clear (void) +{ +int32 i; +t_stat st; +UNIT *uptr; + +for (i = 0; i < MS_NUMDR; i++) { /* look for write in progr */ + uptr = &msc_unit [i]; /* get pointer to unit */ + + if (sim_is_active (uptr) && /* unit active? */ + (uptr->FNC == FNC_WC) && /* and last cmd write? */ + (ms_ptr > 0)) { /* and partial buffer? */ + if (DEBUG_PRI (msc_dev, DEB_RWS)) + fprintf (sim_deb, + ">>MSC rws: Unit %d wrote %d word partial record\n", i, ms_ptr / 2); + + st = sim_tape_wrrecf (uptr, msxb, ms_ptr | MTR_ERF); + + if (st != MTSE_OK) + ms_map_err (uptr, st); /* discard any error */ + + ms_ptr = 0; /* clear partial */ + } + + if ((uptr->UST & STA_REW) == 0) + sim_cancel (uptr); /* stop if not rew */ + } + +msc_sta = msc_1st = 0; /* clr ctlr status */ + +return SCPE_OK; +} + + +/* Reset routine */ + +t_stat msc_reset (DEVICE *dptr) +{ +int32 i; +UNIT *uptr; +DIB *dibptr = (DIB *) dptr->ctxt; /* DIB pointer */ + +hp_enbdis_pair (dptr, /* make pair cons */ + (dptr == &msd_dev) ? &msc_dev : &msd_dev); + +if (sim_switches & SWMASK ('P')) /* initialization reset? */ + ms_config_timing (); + +IOPRESET (dibptr); /* PRESET device (does not use PON) */ + +msc_buf = msd_buf = 0; +msc_sta = msc_usl = 0; +msc_1st = 0; + +for (i = 0; i < MS_NUMDR; i++) { + uptr = msc_dev.units + i; + sim_tape_reset (uptr); + sim_cancel (uptr); + uptr->UST = 0; + + if (sim_switches & SWMASK ('P')) /* if this is an initialization reset */ + sim_tape_set_dens (uptr, /* then tell the tape library the density in use */ + ms_ctype ? BPI_13183 : BPI_13181, + NULL, NULL); + } + +return SCPE_OK; +} + + +/* Attach routine */ + +t_stat msc_attach (UNIT *uptr, char *cptr) +{ +t_stat r; + +r = sim_tape_attach (uptr, cptr); /* attach unit */ +if (r == SCPE_OK) + uptr->flags = uptr->flags & ~UNIT_OFFLINE; /* set online */ +return r; +} + +/* Detach routine */ + +t_stat msc_detach (UNIT* uptr) +{ +uptr->UST = 0; /* clear status */ +uptr->flags = uptr->flags | UNIT_OFFLINE; /* set offline */ +return sim_tape_detach (uptr); /* detach unit */ +} + +/* Online routine */ + +t_stat msc_online (UNIT *uptr, int32 value, char *cptr, void *desc) +{ +if (uptr->flags & UNIT_ATT) return SCPE_OK; +else return SCPE_UNATT; +} + +/* Configure timing */ + +void ms_config_timing (void) +{ +uint32 i, tset; + +tset = (ms_timing << 1) | (ms_timing ? 0 : ms_ctype); /* select timing set */ +for (i = 0; i < (sizeof (timers) / sizeof (timers[0])); i++) + *timers[i] = msc_times[tset][i]; /* assign times */ +} + +/* Set controller timing */ + +t_stat ms_set_timing (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +if ((val < 0) || (val > 1) || (cptr != NULL)) return SCPE_ARG; +ms_timing = val; +ms_config_timing (); +return SCPE_OK; +} + +/* Show controller timing */ + +t_stat ms_show_timing (FILE *st, UNIT *uptr, int32 val, void *desc) +{ +if (ms_timing) fputs ("fast timing", st); +else fputs ("realistic timing", st); +return SCPE_OK; +} + +/* Set controller type */ + +t_stat ms_settype (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +int32 i; + +if ((val < 0) || (val > 1) || (cptr != NULL)) return SCPE_ARG; +for (i = 0; i < MS_NUMDR; i++) { + if (msc_unit[i].flags & UNIT_ATT) return SCPE_ALATT; + } +ms_ctype = (CNTLR_TYPE) val; +ms_config_timing (); /* update for new type */ + +sim_tape_set_dens (uptr, ms_ctype ? BPI_13183 : BPI_13181, /* tell the tape library the density in use */ + NULL, NULL); + +return SCPE_OK; +} + +/* Show controller type */ + +t_stat ms_showtype (FILE *st, UNIT *uptr, int32 val, void *desc) +{ +if (ms_ctype == A13183) + fprintf (st, "13183A"); +else + fprintf (st, "13181A"); +return SCPE_OK; +} + +/* Set unit reel size + + val = 0 -> SET MSCn CAPACITY=n + val = 1 -> SET MSCn REEL=n */ + +t_stat ms_set_reelsize (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +int32 reel; +t_stat status; + +if (val == 0) { + status = sim_tape_set_capac (uptr, val, cptr, desc); + if (status == SCPE_OK) uptr->REEL = 0; + return status; + } + +if (cptr == NULL) return SCPE_ARG; +reel = (int32) get_uint (cptr, 10, 2400, &status); +if (status != SCPE_OK) return status; +else switch (reel) { + + case 0: + uptr->REEL = 0; /* type 0 = unlimited/custom */ + break; + + case 600: + uptr->REEL = 1; /* type 1 = 600 foot */ + break; + + case 1200: + uptr->REEL = 2; /* type 2 = 1200 foot */ + break; + + case 2400: + uptr->REEL = 3; /* type 3 = 2400 foot */ + break; + + default: + return SCPE_ARG; + } + +uptr->capac = uptr->REEL ? (TCAP << uptr->REEL) << ms_ctype : 0; +return SCPE_OK; +} + +/* Show unit reel size + + val = 0 -> SHOW MSC or SHOW MSCn or SHOW MSCn CAPACITY + val = 1 -> SHOW MSCn REEL */ + +t_stat ms_show_reelsize (FILE *st, UNIT *uptr, int32 val, void *desc) +{ +t_stat status = SCPE_OK; + +if (uptr->REEL == 0) status = sim_tape_show_capac (st, uptr, val, desc); +else fprintf (st, "%4d foot reel", 300 << uptr->REEL); +if (val == 1) fputc ('\n', st); /* MTAB_NMO omits \n */ +return status; +} + +/* Translate command to mnemonic for debug logging + + The command names and descriptions are taken from the 13181 interface + manual. */ + +char *ms_cmd_name (uint32 cmd) +{ + +switch (cmd & 0377) { + case FNC_WC: return "WCC"; /* Write command */ + case FNC_WFM: return "WFM"; /* Write file mark */ + case FNC_RC: return "RRF"; /* Read record forward */ + case FNC_FSR: return "FSR"; /* Forward space record */ + case FNC_FSF: return "FSF"; /* Forward space file */ + case FNC_GAP: return "GAP"; /* Write gap */ + case FNC_BSR: return "BSR"; /* Backspace record */ + case FNC_BSF: return "BSF"; /* Backspace file */ + case FNC_REW: return "REW"; /* Rewind */ + case FNC_RWS: return "RWO"; /* Rewind off-line */ + case FNC_CLR: return "CLR"; /* Clear controller */ + case FNC_GFM: return "GFM"; /* Gap file mark */ + case FNC_RFF: return "RFF"; /* Read forward until file mark (diag) */ + case FNC_RRR: return "RRR"; /* Read record in reverse (diag) */ + + default: return "???"; /* Unknown command */ + } +} + +/* 7970B/7970E bootstrap routine (HP 12992D ROM) */ + +const BOOT_ROM ms_rom = { + 0106501, /*ST LIB 1 ; read sw */ + 0006011, /* SLB,RSS ; bit 0 set? */ + 0027714, /* JMP RD ; no read */ + 0003004, /* CMA,INA ; A is ctr */ + 0073775, /* STA WC ; save */ + 0067772, /* LDA SL0RW ; sel 0, rew */ + 0017762, /*FF JSB CMD ; do cmd */ + 0102311, /* SFS CC ; done? */ + 0027707, /* JMP *-1 ; wait */ + 0067774, /* LDB FFC ; get file fwd */ + 0037775, /* ISZ WC ; done files? */ + 0027706, /* JMP FF ; no */ + 0067773, /*RD LDB RDCMD ; read cmd */ + 0017762, /* JSB CMD ; do cmd */ + 0103710, /* STC DC,C ; start dch */ + 0102211, /* SFC CC ; read done? */ + 0027752, /* JMP STAT ; no, get stat */ + 0102310, /* SFS DC ; any data? */ + 0027717, /* JMP *-3 ; wait */ + 0107510, /* LIB DC,C ; get rec cnt */ + 0005727, /* BLF,BLF ; move to lower */ + 0007000, /* CMB ; make neg */ + 0077775, /* STA WC ; save */ + 0102211, /* SFC CC ; read done? */ + 0027752, /* JMP STAT ; no, get stat */ + 0102310, /* SFS DC ; any data? */ + 0027727, /* JMP *-3 ; wait */ + 0107510, /* LIB DC,C ; get load addr */ + 0074000, /* STB 0 ; start csum */ + 0077762, /* STA CMD ; save address */ + 0027742, /* JMP *+4 */ + 0177762, /*NW STB CMD,I ; store data */ + 0040001, /* ADA 1 ; add to csum */ + 0037762, /* ISZ CMD ; adv addr ptr */ + 0102310, /* SFS DC ; any data? */ + 0027742, /* JMP *-1 ; wait */ + 0107510, /* LIB DC,C ; get word */ + 0037775, /* ISZ WC ; done? */ + 0027737, /* JMP NW ; no */ + 0054000, /* CPB 0 ; csum ok? */ + 0027717, /* JMP RD+3 ; yes, cont */ + 0102011, /* HLT 11 ; no, halt */ + 0102511, /*ST LIA CC ; get status */ + 0001727, /* ALF,ALF ; get eof bit */ + 0002020, /* SSA ; set? */ + 0102077, /* HLT 77 ; done */ + 0001727, /* ALF,ALF ; put status back */ + 0001310, /* RAR,SLA ; read ok? */ + 0102000, /* HLT 0 ; no */ + 0027714, /* JMP RD ; read next */ + 0000000, /*CMD 0 */ + 0106611, /* OTB CC ; output cmd */ + 0102511, /* LIA CC ; check for reject */ + 0001323, /* RAR,RAR */ + 0001310, /* RAR,SLA */ + 0027763, /* JMP CMD+1 ; try again */ + 0103711, /* STC CC,C ; start command */ + 0127762, /* JMP CMD,I ; exit */ + 0001501, /*SL0RW 001501 ; select 0, rewind */ + 0001423, /*RDCMD 001423 ; read record */ + 0000203, /*FFC 000203 ; space forward file */ + 0000000, /*WC 000000 */ + 0000000, + 0000000 + }; + +t_stat msc_boot (int32 unitno, DEVICE *dptr) +{ +const int32 dev = msd_dib.select_code; /* get data chan device no */ + +if (unitno != 0) /* boot supported on drive unit 0 only */ + return SCPE_NOFNC; /* report "Command not allowed" if attempted */ + +if (ibl_copy (ms_rom, dev, IBL_OPT, /* copy the boot ROM to memory and configure */ + IBL_MS | IBL_SET_SC (dev))) /* the S register accordingly */ + return SCPE_IERR; /* return an internal error if the copy failed */ + +if ((sim_switches & SWMASK ('S')) && AR) /* if -S is specified and the A register is non-zero */ + SR = SR | 1; /* then set to skip to the file number in A */ + +return SCPE_OK; +} + +/* Calculate tape record CRC and LRC characters */ + +#define E 0400 /* parity bit for odd parity */ +#define O 0000 /* parity bit for odd parity */ + +static const uint16 odd_parity [256] = { /* parity table */ + E, O, O, E, O, E, E, O, O, E, E, O, E, O, O, E, /* 000-017 */ + O, E, E, O, E, O, O, E, E, O, O, E, O, E, E, O, /* 020-037 */ + O, E, E, O, E, O, O, E, E, O, O, E, O, E, E, O, /* 040-067 */ + E, O, O, E, O, E, E, O, O, E, E, O, E, O, O, E, /* 060-077 */ + O, E, E, O, E, O, O, E, E, O, O, E, O, E, E, O, /* 100-117 */ + E, O, O, E, O, E, E, O, O, E, E, O, E, O, O, E, /* 120-137 */ + E, O, O, E, O, E, E, O, O, E, E, O, E, O, O, E, /* 140-157 */ + O, E, E, O, E, O, O, E, E, O, O, E, O, E, E, O, /* 160-177 */ + O, E, E, O, E, O, O, E, E, O, O, E, O, E, E, O, /* 200-217 */ + E, O, O, E, O, E, E, O, O, E, E, O, E, O, O, E, /* 220-237 */ + E, O, O, E, O, E, E, O, O, E, E, O, E, O, O, E, /* 240-267 */ + O, E, E, O, E, O, O, E, E, O, O, E, O, E, E, O, /* 260-277 */ + E, O, O, E, O, E, E, O, O, E, E, O, E, O, O, E, /* 300-317 */ + O, E, E, O, E, O, O, E, E, O, O, E, O, E, E, O, /* 320-337 */ + O, E, E, O, E, O, O, E, E, O, O, E, O, E, E, O, /* 340-357 */ + E, O, O, E, O, E, E, O, O, E, E, O, E, O, O, E /* 360-377 */ + }; + +static uint32 calc_crc_lrc (uint8 *buffer, t_mtrlnt length) +{ +uint32 i; +uint16 byte, crc, lrc; + +lrc = crc = 0; + +for (i = 0; i < length; i++) { + byte = odd_parity [buffer [i]] | buffer [i]; + + crc = crc ^ byte; + lrc = lrc ^ byte; + + if (crc & 1) + crc = crc >> 1 ^ 0474; + else + crc = crc >> 1; + } + +crc = crc ^ 0727; +lrc = lrc ^ crc; + +return (uint32) crc << 16 | lrc; +} diff --git a/HP2100/hp2100_mt.c b/HP2100/hp2100_mt.c index 72066de9..c1c67061 100644 --- a/HP2100/hp2100_mt.c +++ b/HP2100/hp2100_mt.c @@ -1,689 +1,697 @@ -/* hp2100_mt.c: HP 2100 12559A magnetic tape simulator - - Copyright (c) 1993-2012, Robert M. Supnik - - 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 - ROBERT M SUPNIK 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 Robert M Supnik shall not be - used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from Robert M Supnik. - - MT 12559A 3030 nine track magnetic tape - - 25-Mar-12 JDB Removed redundant MTAB_VUN from "format" MTAB entry - 10-Feb-12 JDB Deprecated DEVNO in favor of SC - 28-Mar-11 JDB Tidied up signal handling - 29-Oct-10 JDB Fixed command scanning error in mtcio ioIOO handler - 26-Oct-10 JDB Changed I/O signal handler for revised signal model - 04-Sep-08 JDB Fixed missing flag after CLR command - 02-Sep-08 JDB Moved write enable and format commands from MTD to MTC - 26-Jun-08 JDB Rewrote device I/O to model backplane signals - 28-Dec-06 JDB Added ioCRS state to I/O decoders - 07-Oct-04 JDB Allow enable/disable from either device - 14-Aug-04 RMS Modified handling of end of medium (suggested by Dave Bryan) - 06-Jul-04 RMS Fixed spurious timing error after CLC (found by Dave Bryan) - 26-Apr-04 RMS Fixed SFS x,C and SFC x,C - Implemented DMA SRQ (follows FLG) - 21-Dec-03 RMS Adjusted msc_ctime for TSB (from Mike Gemeny) - 25-Apr-03 RMS Revised for extended file support - 28-Mar-03 RMS Added multiformat support - 28-Feb-03 RMS Revised for magtape library - 30-Sep-02 RMS Revamped error handling - 28-Aug-02 RMS Added end of medium support - 30-May-02 RMS Widened POS to 32b - 22-Apr-02 RMS Added maximum record length test - 20-Jan-02 RMS Fixed bug on last character write - 03-Dec-01 RMS Added read only unit, extended SET/SHOW support - 07-Sep-01 RMS Moved function prototypes - 30-Nov-00 RMS Made variable names unique - 04-Oct-98 RMS V2.4 magtape format - - References: - - 12559A 9-Track Magnetic Tape Unit Interface Kit Operating and Service Manual - (12559-9001, Jul-1970) - - SIMH Magtape Representation and Handling (Bob Supnik, 30-Aug-2006) - - - The 3030 was one of HP's earliest tape drives. The 12559A controller - supported a single 800 bpi, 9-track drive, operating at 75 inches per second. - It had two unusual characteristics: - - - The controller accepted only one byte per I/O word, rather than packing - two bytes per word. - - - The drive could not read or write fewer than 12 bytes per record. - - The first behavior meant that DMA operation required the byte-unpacking - feature of the 12578A DMA card for the 2116 computer. The second meant that - software drivers had to pad short records with blanks or nulls. - - Implementation notes: - - 1. The HP 3030 Magnetic Tape Subsystem diagnostic, part number 20433-60001, - has never been located, so this simulator has not been fully tested. It - does pass a functional test under DOS-III using driver DVR22. -*/ - - -#include "hp2100_defs.h" -#include "sim_tape.h" - -#define DB_V_SIZE 16 /* max data buf */ -#define DBSIZE (1 << DB_V_SIZE) /* max data cmd */ - -/* Command - mtc_fnc */ - -#define FNC_CLR 0300 /* clear */ -#define FNC_WC 0031 /* write */ -#define FNC_RC 0023 /* read */ -#define FNC_GAP 0011 /* write gap */ -#define FNC_FSR 0003 /* forward space */ -#define FNC_BSR 0041 /* backward space */ -#define FNC_REW 0201 /* rewind */ -#define FNC_RWS 0101 /* rewind and offline */ -#define FNC_WFM 0035 /* write file mark */ - -/* Status - stored in mtc_sta, (d) = dynamic */ - -#define STA_LOCAL 0400 /* local (d) */ -#define STA_EOF 0200 /* end of file */ -#define STA_BOT 0100 /* beginning of tape */ -#define STA_EOT 0040 /* end of tape */ -#define STA_TIM 0020 /* timing error */ -#define STA_REJ 0010 /* programming error */ -#define STA_WLK 0004 /* write locked (d) */ -#define STA_PAR 0002 /* parity error */ -#define STA_BUSY 0001 /* busy (d) */ - -struct { - FLIP_FLOP flag; /* flag flip-flop */ - FLIP_FLOP flagbuf; /* flag buffer flip-flop */ - } mtd = { CLEAR, CLEAR }; - -struct { - FLIP_FLOP control; /* control flip-flop */ - FLIP_FLOP flag; /* flag flip-flop */ - FLIP_FLOP flagbuf; /* flag buffer flip-flop */ - } mtc = { CLEAR, CLEAR, CLEAR }; - -int32 mtc_fnc = 0; /* function */ -int32 mtc_sta = 0; /* status register */ -int32 mtc_dtf = 0; /* data xfer flop */ -int32 mtc_1st = 0; /* first svc flop */ -int32 mtc_ctime = 40; /* command wait */ -int32 mtc_gtime = 1000; /* gap stop time */ -int32 mtc_xtime = 15; /* data xfer time */ -int32 mtc_stopioe = 1; /* stop on error */ -uint8 mtxb[DBSIZE] = { 0 }; /* data buffer */ -t_mtrlnt mt_ptr = 0, mt_max = 0; /* buffer ptrs */ -static const uint32 mtc_cmd[] = { - FNC_WC, FNC_RC, FNC_GAP, FNC_FSR, FNC_BSR, FNC_REW, FNC_RWS, FNC_WFM }; -static const uint32 mtc_cmd_count = sizeof (mtc_cmd) / sizeof (mtc_cmd[0]); - -DEVICE mtd_dev, mtc_dev; - -IOHANDLER mtdio; -IOHANDLER mtcio; - -t_stat mtc_svc (UNIT *uptr); -t_stat mt_reset (DEVICE *dptr); -t_stat mtc_attach (UNIT *uptr, char *cptr); -t_stat mtc_detach (UNIT *uptr); -t_stat mt_map_err (UNIT *uptr, t_stat st); -t_stat mt_clear (void); - -/* MTD data structures - - mtd_dev MTD device descriptor - mtd_unit MTD unit list - mtd_reg MTD register list -*/ - -DIB mt_dib[] = { - { &mtdio, MTD }, - { &mtcio, MTC } - }; - -#define mtd_dib mt_dib[0] -#define mtc_dib mt_dib[1] - -UNIT mtd_unit = { UDATA (NULL, 0, 0) }; - -REG mtd_reg[] = { - { FLDATA (FLG, mtd.flag, 0) }, - { FLDATA (FBF, mtd.flagbuf, 0) }, - { BRDATA (DBUF, mtxb, 8, 8, DBSIZE) }, - { DRDATA (BPTR, mt_ptr, DB_V_SIZE + 1) }, - { DRDATA (BMAX, mt_max, DB_V_SIZE + 1) }, - { ORDATA (SC, mtd_dib.select_code, 6), REG_HRO }, - { ORDATA (DEVNO, mtd_dib.select_code, 6), REG_HRO }, - { NULL } - }; - -MTAB mtd_mod[] = { - { MTAB_XTD | MTAB_VDV, 1, "SC", "SC", &hp_setsc, &hp_showsc, &mtd_dev }, - { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &mtd_dev }, - { 0 } - }; - -DEVICE mtd_dev = { - "MTD", &mtd_unit, mtd_reg, mtd_mod, - 1, 10, 16, 1, 8, 8, - NULL, NULL, &mt_reset, - NULL, NULL, NULL, - &mtd_dib, DEV_DISABLE | DEV_DIS - }; - -/* MTC data structures - - mtc_dev MTC device descriptor - mtc_unit MTC unit list - mtc_reg MTC register list - mtc_mod MTC modifier list -*/ - -UNIT mtc_unit = { UDATA (&mtc_svc, UNIT_ATTABLE + UNIT_ROABLE, 0) }; - -REG mtc_reg[] = { - { ORDATA (FNC, mtc_fnc, 8) }, - { ORDATA (STA, mtc_sta, 9) }, - { ORDATA (BUF, mtc_unit.buf, 8) }, - { FLDATA (CTL, mtc.control, 0) }, - { FLDATA (FLG, mtc.flag, 0) }, - { FLDATA (FBF, mtc.flagbuf, 0) }, - { FLDATA (DTF, mtc_dtf, 0) }, - { FLDATA (FSVC, mtc_1st, 0) }, - { DRDATA (POS, mtc_unit.pos, T_ADDR_W), PV_LEFT }, - { DRDATA (CTIME, mtc_ctime, 24), REG_NZ + PV_LEFT }, - { DRDATA (GTIME, mtc_gtime, 24), REG_NZ + PV_LEFT }, - { DRDATA (XTIME, mtc_xtime, 24), REG_NZ + PV_LEFT }, - { FLDATA (STOP_IOE, mtc_stopioe, 0) }, - { ORDATA (SC, mtc_dib.select_code, 6), REG_HRO }, - { ORDATA (DEVNO, mtc_dib.select_code, 6), REG_HRO }, - { NULL } - }; - -MTAB mtc_mod[] = { - { MTUF_WLK, 0, "write enabled", "WRITEENABLED", NULL }, - { MTUF_WLK, MTUF_WLK, "write locked", "LOCKED", NULL }, - { MTAB_XTD | MTAB_VDV, 0, "FORMAT", "FORMAT", - &sim_tape_set_fmt, &sim_tape_show_fmt, NULL }, - { MTAB_XTD | MTAB_VDV, 1, "SC", "SC", &hp_setsc, &hp_showsc, &mtd_dev }, - { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &mtd_dev }, - { 0 } - }; - -DEVICE mtc_dev = { - "MTC", &mtc_unit, mtc_reg, mtc_mod, - 1, 10, 31, 1, 8, 8, - NULL, NULL, &mt_reset, - NULL, &mtc_attach, &mtc_detach, - &mtc_dib, DEV_DISABLE | DEV_DIS - }; - - -/* Data channel I/O signal handler - - The 12559A data channel interface has a number of non-standard features: - - - The card does not drive PRL or IRQ. - - The card does not respond to IAK. - - There is no control flip-flop; CLC resets the data transfer flip-flop. - - POPIO issues a CLR command and clears the flag and flag buffer flip-flops. - - CRS is not used. - - Implementation notes: - - 1. The data channel has a flag buffer flip-flop (necessary for the proper - timing of the flag flip-flop), but the data channel does not interrupt, - so the flag buffer serves no other purpose. -*/ - -uint32 mtdio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) -{ -IOSIGNAL signal; -IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ - -while (working_set) { - signal = IONEXT (working_set); /* isolate next signal */ - - switch (signal) { /* dispatch I/O signal */ - - case ioCLF: /* clear flag flip-flop */ - mtd.flag = mtd.flagbuf = CLEAR; - break; - - case ioSTF: /* set flag flip-flop */ - case ioENF: /* enable flag */ - mtd.flag = mtd.flagbuf = SET; - break; - - case ioSFC: /* skip if flag is clear */ - setstdSKF (mtd); - break; - - case ioSFS: /* skip if flag is set */ - setstdSKF (mtd); - break; - - case ioIOI: /* I/O data input */ - stat_data = IORETURN (SCPE_OK, mtc_unit.buf); /* merge in return status */ - break; - - case ioIOO: /* I/O data output */ - mtc_unit.buf = IODATA (stat_data) & DMASK8; /* store data */ - break; - - case ioPOPIO: /* power-on preset to I/O */ - mt_clear (); /* issue CLR to controller */ - mtd.flag = mtd.flagbuf = CLEAR; /* clear flag and flag buffer */ - break; - - case ioCLC: /* clear control flip-flop */ - mtc_dtf = 0; /* clr xfer flop */ - mtd.flag = mtd.flagbuf = CLEAR; /* clear flag and flag buffer */ - break; - - case ioSIR: /* set interrupt request */ - setstdSRQ (mtd); /* set standard SRQ signal */ - break; - - default: /* all other signals */ - break; /* are ignored */ - } - - working_set = working_set & ~signal; /* remove current signal from set */ - } - -return stat_data; -} - - -/* Command channel I/O signal handler. - - The 12559A command interface is reasonably standard, although POPIO clears, - rather than sets, the flag and flag buffer flip-flops. One unusual feature - is that commands are initiated when they are output to the interface with - OTA/B, rather than waiting until control is set with STC. STC simply enables - command-channel interrupts. - - Implementation notes: - - 1. In hardware, the command channel card passes PRH to PRL. The data card - actually drives PRL with the command channel's control and flag states. - That is, the priority chain is broken at the data card, although the - command card is interrupting. This works in hardware, but we must break - PRL at the command card under simulation to allow the command card to - interrupt. - - 2. In hardware, the CLR command takes 5 milliseconds to complete. During - this time, the BUSY bit is set in the status word. Under simulation, we - complete immediately, and the BUSY bit never sets.. -*/ - -uint32 mtcio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) -{ -uint16 data; -uint32 i; -int32 valid; -IOSIGNAL signal; -IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ - -while (working_set) { - signal = IONEXT (working_set); /* isolate next signal */ - - switch (signal) { /* dispatch I/O signal */ - - case ioCLF: /* clear flag flip-flop */ - mtc.flag = mtc.flagbuf = CLEAR; - break; - - - case ioSTF: /* set flag flip-flop */ - case ioENF: /* enable flag */ - mtc.flag = mtc.flagbuf = SET; - break; - - - case ioSFC: /* skip if flag is clear */ - setstdSKF (mtc); - break; - - - case ioSFS: /* skip if flag is set */ - setstdSKF (mtc); - break; - - - case ioIOI: /* I/O data input */ - data = mtc_sta & ~(STA_LOCAL | STA_WLK | STA_BUSY); - - if (mtc_unit.flags & UNIT_ATT) { /* construct status */ - if (sim_is_active (&mtc_unit)) - data = data | STA_BUSY; - - if (sim_tape_wrp (&mtc_unit)) - data = data | STA_WLK; - } - else - data = data | STA_BUSY | STA_LOCAL; - - stat_data = IORETURN (SCPE_OK, data); /* merge in return status */ - break; - - - case ioIOO: /* I/O data output */ - data = IODATA (stat_data) & DMASK8; - mtc_sta = mtc_sta & ~STA_REJ; /* clear reject */ - - if (data == FNC_CLR) { /* clear? */ - mt_clear (); /* send CLR to controller */ - - mtd.flag = mtd.flagbuf = CLEAR; /* clear data flag and flag buffer */ - mtc.flag = mtc.flagbuf = SET; /* set command flag and flag buffer */ - break; /* command completes immediately */ - } - - for (i = valid = 0; i < mtc_cmd_count; i++) /* is fnc valid? */ - if (data == mtc_cmd[i]) { - valid = 1; - break; - } - - if (!valid || sim_is_active (&mtc_unit) || /* is cmd valid? */ - ((mtc_sta & STA_BOT) && (data == FNC_BSR)) || - (sim_tape_wrp (&mtc_unit) && - ((data == FNC_WC) || (data == FNC_GAP) || (data == FNC_WFM)))) - mtc_sta = mtc_sta | STA_REJ; - - else { - sim_activate (&mtc_unit, mtc_ctime); /* start tape */ - mtc_fnc = data; /* save function */ - mtc_sta = STA_BUSY; /* unit busy */ - mt_ptr = 0; /* init buffer ptr */ - - mtcio (&mtc_dib, ioCLF, 0); /* clear flags */ - mtcio (&mtd_dib, ioCLF, 0); - - mtc_1st = 1; /* set 1st flop */ - mtc_dtf = 1; /* set xfer flop */ - } - break; - - - case ioPOPIO: /* power-on preset to I/O */ - mtc.flag = mtc.flagbuf = CLEAR; /* clear flag and flag buffer */ - break; - - - case ioCRS: /* control reset */ - case ioCLC: /* clear control flip-flop */ - mtc.control = CLEAR; - break; - - - case ioSTC: /* set control flip-flop */ - mtc.control = SET; - break; - - - case ioSIR: /* set interrupt request */ - setstdPRL (mtc); /* set standard PRL signal */ - setstdIRQ (mtc); /* set standard IRQ signal */ - setstdSRQ (mtc); /* set standard SRQ signal */ - break; - - case ioIAK: /* interrupt acknowledge */ - mtc.flagbuf = CLEAR; - break; - - - default: /* all other signals */ - break; /* are ignored */ - } - - working_set = working_set & ~signal; /* remove current signal from set */ - } - -return stat_data; -} - - -/* Unit service - - If rewind done, reposition to start of tape, set status - else, do operation, set done, interrupt - - Can't be write locked, can only write lock detached unit -*/ - -t_stat mtc_svc (UNIT *uptr) -{ -t_mtrlnt tbc; -t_stat st, r = SCPE_OK; - -if ((mtc_unit.flags & UNIT_ATT) == 0) { /* offline? */ - mtc_sta = STA_LOCAL | STA_REJ; /* rejected */ - mtcio (&mtc_dib, ioENF, 0); /* set cch flg */ - return IOERROR (mtc_stopioe, SCPE_UNATT); - } - -switch (mtc_fnc) { /* case on function */ - - case FNC_REW: /* rewind */ - sim_tape_rewind (uptr); /* BOT */ - mtc_sta = STA_BOT; /* update status */ - break; - - case FNC_RWS: /* rewind and offline */ - sim_tape_rewind (uptr); /* clear position */ - return sim_tape_detach (uptr); /* don't set cch flg */ - - case FNC_WFM: /* write file mark */ - if (st = sim_tape_wrtmk (uptr)) /* write tmk, err? */ - r = mt_map_err (uptr, st); /* map error */ - mtc_sta = STA_EOF; /* set EOF status */ - break; - - case FNC_GAP: /* erase gap */ - break; - - case FNC_FSR: /* space forward */ - if (st = sim_tape_sprecf (uptr, &tbc)) /* space rec fwd, err? */ - r = mt_map_err (uptr, st); /* map error */ - break; - - case FNC_BSR: /* space reverse */ - if (st = sim_tape_sprecr (uptr, &tbc)) /* space rec rev, err? */ - r = mt_map_err (uptr, st); /* map error */ - break; - - case FNC_RC: /* read */ - if (mtc_1st) { /* first svc? */ - mtc_1st = mt_ptr = 0; /* clr 1st flop */ - st = sim_tape_rdrecf (uptr, mtxb, &mt_max, DBSIZE); /* read rec */ - if (st == MTSE_RECE) mtc_sta = mtc_sta | STA_PAR; /* rec in err? */ - else if (st != MTSE_OK) { /* other error? */ - r = mt_map_err (uptr, st); /* map error */ - if (r == SCPE_OK) { /* recoverable? */ - sim_activate (uptr, mtc_gtime); /* sched IRG */ - mtc_fnc = 0; /* NOP func */ - return SCPE_OK; - } - break; /* non-recov, done */ - } - if (mt_max < 12) { /* record too short? */ - mtc_sta = mtc_sta | STA_PAR; /* set flag */ - break; - } - } - if (mtc_dtf && (mt_ptr < mt_max)) { /* more chars? */ - if (mtd.flag) mtc_sta = mtc_sta | STA_TIM; - mtc_unit.buf = mtxb[mt_ptr++]; /* fetch next */ - mtdio (&mtd_dib, ioENF, 0); /* set dch flg */ - sim_activate (uptr, mtc_xtime); /* re-activate */ - return SCPE_OK; - } - sim_activate (uptr, mtc_gtime); /* schedule gap */ - mtc_fnc = 0; /* nop */ - return SCPE_OK; - - case FNC_WC: /* write */ - if (mtc_1st) mtc_1st = 0; /* no xfr on first */ - else { - if (mt_ptr < DBSIZE) { /* room in buffer? */ - mtxb[mt_ptr++] = mtc_unit.buf; - mtc_sta = mtc_sta & ~STA_BOT; /* clear BOT */ - } - else mtc_sta = mtc_sta | STA_PAR; - } - if (mtc_dtf) { /* xfer flop set? */ - mtdio (&mtd_dib, ioENF, 0); /* set dch flg */ - sim_activate (uptr, mtc_xtime); /* re-activate */ - return SCPE_OK; - } - if (mt_ptr) { /* write buffer */ - if (st = sim_tape_wrrecf (uptr, mtxb, mt_ptr)) { /* write, err? */ - r = mt_map_err (uptr, st); /* map error */ - break; /* done */ - } - } - sim_activate (uptr, mtc_gtime); /* schedule gap */ - mtc_fnc = 0; /* nop */ - return SCPE_OK; - - default: /* unknown */ - break; - } - -mtcio (&mtc_dib, ioENF, 0); /* set cch flg */ -mtc_sta = mtc_sta & ~STA_BUSY; /* not busy */ -return r; -} - -/* Map tape error status */ - -t_stat mt_map_err (UNIT *uptr, t_stat st) -{ -switch (st) { - - case MTSE_FMT: /* illegal fmt */ - case MTSE_UNATT: /* unattached */ - mtc_sta = mtc_sta | STA_REJ; /* reject */ - case MTSE_OK: /* no error */ - return SCPE_IERR; /* never get here! */ - - case MTSE_EOM: /* end of medium */ - case MTSE_TMK: /* end of file */ - mtc_sta = mtc_sta | STA_EOF; /* eof */ - break; - - case MTSE_IOERR: /* IO error */ - mtc_sta = mtc_sta | STA_PAR; /* error */ - if (mtc_stopioe) return SCPE_IOERR; - break; - - case MTSE_INVRL: /* invalid rec lnt */ - mtc_sta = mtc_sta | STA_PAR; - return SCPE_MTRLNT; - - case MTSE_RECE: /* record in error */ - mtc_sta = mtc_sta | STA_PAR; /* error */ - break; - - case MTSE_BOT: /* reverse into BOT */ - mtc_sta = mtc_sta | STA_BOT; /* set status */ - break; - - case MTSE_WRP: /* write protect */ - mtc_sta = mtc_sta | STA_REJ; /* reject */ - break; - } - -return SCPE_OK; -} - - -/* Controller clear */ - -t_stat mt_clear (void) -{ -t_stat st; - -if (sim_is_active (&mtc_unit) && /* write in prog? */ - (mtc_fnc == FNC_WC) && (mt_ptr > 0)) { /* yes, bad rec */ - if (st = sim_tape_wrrecf (&mtc_unit, mtxb, mt_ptr | MTR_ERF)) - mt_map_err (&mtc_unit, st); - } - -if (((mtc_fnc == FNC_REW) || (mtc_fnc == FNC_RWS)) && sim_is_active (&mtc_unit)) - sim_cancel (&mtc_unit); - -mtc_1st = mtc_dtf = 0; -mtc_sta = mtc_sta & STA_BOT; - -return SCPE_OK; -} - - -/* Reset routine */ - -t_stat mt_reset (DEVICE *dptr) -{ -DIB *dibptr = (DIB *) dptr->ctxt; /* DIB pointer */ - -hp_enbdis_pair (dptr, /* make pair cons */ - (dptr == &mtd_dev) ? &mtc_dev : &mtd_dev); - -IOPRESET (dibptr); /* PRESET device (does not use PON) */ - -mtc_fnc = 0; -mtc_1st = mtc_dtf = 0; - -sim_cancel (&mtc_unit); /* cancel activity */ -sim_tape_reset (&mtc_unit); - -if (mtc_unit.flags & UNIT_ATT) - mtc_sta = (sim_tape_bot (&mtc_unit)? STA_BOT: 0) | - (sim_tape_wrp (&mtc_unit)? STA_WLK: 0); -else - mtc_sta = STA_LOCAL | STA_BUSY; - -return SCPE_OK; -} - - -/* Attach routine */ - -t_stat mtc_attach (UNIT *uptr, char *cptr) -{ -t_stat r; - -r = sim_tape_attach (uptr, cptr); /* attach unit */ -if (r != SCPE_OK) return r; /* update status */ -mtc_sta = STA_BOT; -return r; -} - -/* Detach routine */ - -t_stat mtc_detach (UNIT* uptr) -{ -mtc_sta = 0; /* update status */ -return sim_tape_detach (uptr); /* detach unit */ -} +/* hp2100_mt.c: HP 2100 12559A magnetic tape simulator + + Copyright (c) 1993-2014, Robert M. Supnik + + 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 + ROBERT M SUPNIK 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 Robert M Supnik shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + + MT 12559A 3030 nine track magnetic tape + + 24-Dec-14 JDB Added casts for explicit downward conversions + 10-Jan-13 MP Added DEV_TAPE to DEVICE flags + 09-May-12 JDB Separated assignments from conditional expressions + 25-Mar-12 JDB Removed redundant MTAB_VUN from "format" MTAB entry + 10-Feb-12 JDB Deprecated DEVNO in favor of SC + 28-Mar-11 JDB Tidied up signal handling + 29-Oct-10 JDB Fixed command scanning error in mtcio ioIOO handler + 26-Oct-10 JDB Changed I/O signal handler for revised signal model + 04-Sep-08 JDB Fixed missing flag after CLR command + 02-Sep-08 JDB Moved write enable and format commands from MTD to MTC + 26-Jun-08 JDB Rewrote device I/O to model backplane signals + 28-Dec-06 JDB Added ioCRS state to I/O decoders + 07-Oct-04 JDB Allow enable/disable from either device + 14-Aug-04 RMS Modified handling of end of medium (suggested by Dave Bryan) + 06-Jul-04 RMS Fixed spurious timing error after CLC (found by Dave Bryan) + 26-Apr-04 RMS Fixed SFS x,C and SFC x,C + Implemented DMA SRQ (follows FLG) + 21-Dec-03 RMS Adjusted msc_ctime for TSB (from Mike Gemeny) + 25-Apr-03 RMS Revised for extended file support + 28-Mar-03 RMS Added multiformat support + 28-Feb-03 RMS Revised for magtape library + 30-Sep-02 RMS Revamped error handling + 28-Aug-02 RMS Added end of medium support + 30-May-02 RMS Widened POS to 32b + 22-Apr-02 RMS Added maximum record length test + 20-Jan-02 RMS Fixed bug on last character write + 03-Dec-01 RMS Added read only unit, extended SET/SHOW support + 07-Sep-01 RMS Moved function prototypes + 30-Nov-00 RMS Made variable names unique + 04-Oct-98 RMS V2.4 magtape format + + References: + - 12559A 9-Track Magnetic Tape Unit Interface Kit Operating and Service Manual + (12559-9001, Jul-1970) + - SIMH Magtape Representation and Handling (Bob Supnik, 30-Aug-2006) + + + The 3030 was one of HP's earliest tape drives. The 12559A controller + supported a single 800 bpi, 9-track drive, operating at 75 inches per second. + It had two unusual characteristics: + + - The controller accepted only one byte per I/O word, rather than packing + two bytes per word. + + - The drive could not read or write fewer than 12 bytes per record. + + The first behavior meant that DMA operation required the byte-unpacking + feature of the 12578A DMA card for the 2116 computer. The second meant that + software drivers had to pad short records with blanks or nulls. + + Implementation notes: + + 1. The HP 3030 Magnetic Tape Subsystem diagnostic, part number 20433-60001, + has never been located, so this simulator has not been fully tested. It + does pass a functional test under DOS-III using driver DVR22. +*/ + + +#include "hp2100_defs.h" +#include "sim_tape.h" + +#define DB_V_SIZE 16 /* max data buf */ +#define DBSIZE (1 << DB_V_SIZE) /* max data cmd */ + +/* Command - mtc_fnc */ + +#define FNC_CLR 0300 /* clear */ +#define FNC_WC 0031 /* write */ +#define FNC_RC 0023 /* read */ +#define FNC_GAP 0011 /* write gap */ +#define FNC_FSR 0003 /* forward space */ +#define FNC_BSR 0041 /* backward space */ +#define FNC_REW 0201 /* rewind */ +#define FNC_RWS 0101 /* rewind and offline */ +#define FNC_WFM 0035 /* write file mark */ + +/* Status - stored in mtc_sta, (d) = dynamic */ + +#define STA_LOCAL 0400 /* local (d) */ +#define STA_EOF 0200 /* end of file */ +#define STA_BOT 0100 /* beginning of tape */ +#define STA_EOT 0040 /* end of tape */ +#define STA_TIM 0020 /* timing error */ +#define STA_REJ 0010 /* programming error */ +#define STA_WLK 0004 /* write locked (d) */ +#define STA_PAR 0002 /* parity error */ +#define STA_BUSY 0001 /* busy (d) */ + +struct { + FLIP_FLOP flag; /* flag flip-flop */ + FLIP_FLOP flagbuf; /* flag buffer flip-flop */ + } mtd = { CLEAR, CLEAR }; + +struct { + FLIP_FLOP control; /* control flip-flop */ + FLIP_FLOP flag; /* flag flip-flop */ + FLIP_FLOP flagbuf; /* flag buffer flip-flop */ + } mtc = { CLEAR, CLEAR, CLEAR }; + +int32 mtc_fnc = 0; /* function */ +int32 mtc_sta = 0; /* status register */ +int32 mtc_dtf = 0; /* data xfer flop */ +int32 mtc_1st = 0; /* first svc flop */ +int32 mtc_ctime = 40; /* command wait */ +int32 mtc_gtime = 1000; /* gap stop time */ +int32 mtc_xtime = 15; /* data xfer time */ +int32 mtc_stopioe = 1; /* stop on error */ +uint8 mtxb[DBSIZE] = { 0 }; /* data buffer */ +t_mtrlnt mt_ptr = 0, mt_max = 0; /* buffer ptrs */ +static const uint32 mtc_cmd[] = { + FNC_WC, FNC_RC, FNC_GAP, FNC_FSR, FNC_BSR, FNC_REW, FNC_RWS, FNC_WFM }; +static const uint32 mtc_cmd_count = sizeof (mtc_cmd) / sizeof (mtc_cmd[0]); + +DEVICE mtd_dev, mtc_dev; + +IOHANDLER mtdio; +IOHANDLER mtcio; + +t_stat mtc_svc (UNIT *uptr); +t_stat mt_reset (DEVICE *dptr); +t_stat mtc_attach (UNIT *uptr, char *cptr); +t_stat mtc_detach (UNIT *uptr); +t_stat mt_map_err (UNIT *uptr, t_stat st); +t_stat mt_clear (void); + +/* MTD data structures + + mtd_dev MTD device descriptor + mtd_unit MTD unit list + mtd_reg MTD register list +*/ + +DIB mt_dib[] = { + { &mtdio, MTD }, + { &mtcio, MTC } + }; + +#define mtd_dib mt_dib[0] +#define mtc_dib mt_dib[1] + +UNIT mtd_unit = { UDATA (NULL, 0, 0) }; + +REG mtd_reg[] = { + { FLDATA (FLG, mtd.flag, 0) }, + { FLDATA (FBF, mtd.flagbuf, 0) }, + { BRDATA (DBUF, mtxb, 8, 8, DBSIZE) }, + { DRDATA (BPTR, mt_ptr, DB_V_SIZE + 1) }, + { DRDATA (BMAX, mt_max, DB_V_SIZE + 1) }, + { ORDATA (SC, mtd_dib.select_code, 6), REG_HRO }, + { ORDATA (DEVNO, mtd_dib.select_code, 6), REG_HRO }, + { NULL } + }; + +MTAB mtd_mod[] = { + { MTAB_XTD | MTAB_VDV, 1, "SC", "SC", &hp_setsc, &hp_showsc, &mtd_dev }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &mtd_dev }, + { 0 } + }; + +DEVICE mtd_dev = { + "MTD", &mtd_unit, mtd_reg, mtd_mod, + 1, 10, 16, 1, 8, 8, + NULL, NULL, &mt_reset, + NULL, NULL, NULL, + &mtd_dib, DEV_DISABLE | DEV_DIS + }; + +/* MTC data structures + + mtc_dev MTC device descriptor + mtc_unit MTC unit list + mtc_reg MTC register list + mtc_mod MTC modifier list +*/ + +UNIT mtc_unit = { UDATA (&mtc_svc, UNIT_ATTABLE + UNIT_ROABLE, 0) }; + +REG mtc_reg[] = { + { ORDATA (FNC, mtc_fnc, 8) }, + { ORDATA (STA, mtc_sta, 9) }, + { ORDATA (BUF, mtc_unit.buf, 8) }, + { FLDATA (CTL, mtc.control, 0) }, + { FLDATA (FLG, mtc.flag, 0) }, + { FLDATA (FBF, mtc.flagbuf, 0) }, + { FLDATA (DTF, mtc_dtf, 0) }, + { FLDATA (FSVC, mtc_1st, 0) }, + { DRDATA (POS, mtc_unit.pos, T_ADDR_W), PV_LEFT }, + { DRDATA (CTIME, mtc_ctime, 24), REG_NZ + PV_LEFT }, + { DRDATA (GTIME, mtc_gtime, 24), REG_NZ + PV_LEFT }, + { DRDATA (XTIME, mtc_xtime, 24), REG_NZ + PV_LEFT }, + { FLDATA (STOP_IOE, mtc_stopioe, 0) }, + { ORDATA (SC, mtc_dib.select_code, 6), REG_HRO }, + { ORDATA (DEVNO, mtc_dib.select_code, 6), REG_HRO }, + { NULL } + }; + +MTAB mtc_mod[] = { + { MTUF_WLK, 0, "write enabled", "WRITEENABLED", NULL }, + { MTUF_WLK, MTUF_WLK, "write locked", "LOCKED", NULL }, + { MTAB_XTD | MTAB_VDV, 0, "FORMAT", "FORMAT", + &sim_tape_set_fmt, &sim_tape_show_fmt, NULL }, + { MTAB_XTD | MTAB_VDV, 1, "SC", "SC", &hp_setsc, &hp_showsc, &mtd_dev }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &mtd_dev }, + { 0 } + }; + +DEVICE mtc_dev = { + "MTC", &mtc_unit, mtc_reg, mtc_mod, + 1, 10, 31, 1, 8, 8, + NULL, NULL, &mt_reset, + NULL, &mtc_attach, &mtc_detach, + &mtc_dib, DEV_DISABLE | DEV_DIS | DEV_TAPE + }; + + +/* Data channel I/O signal handler + + The 12559A data channel interface has a number of non-standard features: + + - The card does not drive PRL or IRQ. + - The card does not respond to IAK. + - There is no control flip-flop; CLC resets the data transfer flip-flop. + - POPIO issues a CLR command and clears the flag and flag buffer flip-flops. + - CRS is not used. + + Implementation notes: + + 1. The data channel has a flag buffer flip-flop (necessary for the proper + timing of the flag flip-flop), but the data channel does not interrupt, + so the flag buffer serves no other purpose. +*/ + +uint32 mtdio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) +{ +IOSIGNAL signal; +IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ + +while (working_set) { + signal = IONEXT (working_set); /* isolate next signal */ + + switch (signal) { /* dispatch I/O signal */ + + case ioCLF: /* clear flag flip-flop */ + mtd.flag = mtd.flagbuf = CLEAR; + break; + + case ioSTF: /* set flag flip-flop */ + case ioENF: /* enable flag */ + mtd.flag = mtd.flagbuf = SET; + break; + + case ioSFC: /* skip if flag is clear */ + setstdSKF (mtd); + break; + + case ioSFS: /* skip if flag is set */ + setstdSKF (mtd); + break; + + case ioIOI: /* I/O data input */ + stat_data = IORETURN (SCPE_OK, mtc_unit.buf); /* merge in return status */ + break; + + case ioIOO: /* I/O data output */ + mtc_unit.buf = IODATA (stat_data) & DMASK8; /* store data */ + break; + + case ioPOPIO: /* power-on preset to I/O */ + mt_clear (); /* issue CLR to controller */ + mtd.flag = mtd.flagbuf = CLEAR; /* clear flag and flag buffer */ + break; + + case ioCLC: /* clear control flip-flop */ + mtc_dtf = 0; /* clr xfer flop */ + mtd.flag = mtd.flagbuf = CLEAR; /* clear flag and flag buffer */ + break; + + case ioSIR: /* set interrupt request */ + setstdSRQ (mtd); /* set standard SRQ signal */ + break; + + default: /* all other signals */ + break; /* are ignored */ + } + + working_set = working_set & ~signal; /* remove current signal from set */ + } + +return stat_data; +} + + +/* Command channel I/O signal handler. + + The 12559A command interface is reasonably standard, although POPIO clears, + rather than sets, the flag and flag buffer flip-flops. One unusual feature + is that commands are initiated when they are output to the interface with + OTA/B, rather than waiting until control is set with STC. STC simply enables + command-channel interrupts. + + Implementation notes: + + 1. In hardware, the command channel card passes PRH to PRL. The data card + actually drives PRL with the command channel's control and flag states. + That is, the priority chain is broken at the data card, although the + command card is interrupting. This works in hardware, but we must break + PRL at the command card under simulation to allow the command card to + interrupt. + + 2. In hardware, the CLR command takes 5 milliseconds to complete. During + this time, the BUSY bit is set in the status word. Under simulation, we + complete immediately, and the BUSY bit never sets.. +*/ + +uint32 mtcio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) +{ +uint16 data; +uint32 i; +int32 valid; +IOSIGNAL signal; +IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ + +while (working_set) { + signal = IONEXT (working_set); /* isolate next signal */ + + switch (signal) { /* dispatch I/O signal */ + + case ioCLF: /* clear flag flip-flop */ + mtc.flag = mtc.flagbuf = CLEAR; + break; + + + case ioSTF: /* set flag flip-flop */ + case ioENF: /* enable flag */ + mtc.flag = mtc.flagbuf = SET; + break; + + + case ioSFC: /* skip if flag is clear */ + setstdSKF (mtc); + break; + + + case ioSFS: /* skip if flag is set */ + setstdSKF (mtc); + break; + + + case ioIOI: /* I/O data input */ + data = mtc_sta & ~(STA_LOCAL | STA_WLK | STA_BUSY); + + if (mtc_unit.flags & UNIT_ATT) { /* construct status */ + if (sim_is_active (&mtc_unit)) + data = data | STA_BUSY; + + if (sim_tape_wrp (&mtc_unit)) + data = data | STA_WLK; + } + else + data = data | STA_BUSY | STA_LOCAL; + + stat_data = IORETURN (SCPE_OK, data); /* merge in return status */ + break; + + + case ioIOO: /* I/O data output */ + data = IODATA (stat_data) & DMASK8; + mtc_sta = mtc_sta & ~STA_REJ; /* clear reject */ + + if (data == FNC_CLR) { /* clear? */ + mt_clear (); /* send CLR to controller */ + + mtd.flag = mtd.flagbuf = CLEAR; /* clear data flag and flag buffer */ + mtc.flag = mtc.flagbuf = SET; /* set command flag and flag buffer */ + break; /* command completes immediately */ + } + + for (i = valid = 0; i < mtc_cmd_count; i++) /* is fnc valid? */ + if (data == mtc_cmd[i]) { + valid = 1; + break; + } + + if (!valid || sim_is_active (&mtc_unit) || /* is cmd valid? */ + ((mtc_sta & STA_BOT) && (data == FNC_BSR)) || + (sim_tape_wrp (&mtc_unit) && + ((data == FNC_WC) || (data == FNC_GAP) || (data == FNC_WFM)))) + mtc_sta = mtc_sta | STA_REJ; + + else { + sim_activate (&mtc_unit, mtc_ctime); /* start tape */ + mtc_fnc = data; /* save function */ + mtc_sta = STA_BUSY; /* unit busy */ + mt_ptr = 0; /* init buffer ptr */ + + mtcio (&mtc_dib, ioCLF, 0); /* clear flags */ + mtcio (&mtd_dib, ioCLF, 0); + + mtc_1st = 1; /* set 1st flop */ + mtc_dtf = 1; /* set xfer flop */ + } + break; + + + case ioPOPIO: /* power-on preset to I/O */ + mtc.flag = mtc.flagbuf = CLEAR; /* clear flag and flag buffer */ + break; + + + case ioCRS: /* control reset */ + case ioCLC: /* clear control flip-flop */ + mtc.control = CLEAR; + break; + + + case ioSTC: /* set control flip-flop */ + mtc.control = SET; + break; + + + case ioSIR: /* set interrupt request */ + setstdPRL (mtc); /* set standard PRL signal */ + setstdIRQ (mtc); /* set standard IRQ signal */ + setstdSRQ (mtc); /* set standard SRQ signal */ + break; + + case ioIAK: /* interrupt acknowledge */ + mtc.flagbuf = CLEAR; + break; + + + default: /* all other signals */ + break; /* are ignored */ + } + + working_set = working_set & ~signal; /* remove current signal from set */ + } + +return stat_data; +} + + +/* Unit service + + If rewind done, reposition to start of tape, set status + else, do operation, set done, interrupt + + Can't be write locked, can only write lock detached unit +*/ + +t_stat mtc_svc (UNIT *uptr) +{ +t_mtrlnt tbc; +t_stat st, r = SCPE_OK; + +if ((mtc_unit.flags & UNIT_ATT) == 0) { /* offline? */ + mtc_sta = STA_LOCAL | STA_REJ; /* rejected */ + mtcio (&mtc_dib, ioENF, 0); /* set cch flg */ + return IOERROR (mtc_stopioe, SCPE_UNATT); + } + +switch (mtc_fnc) { /* case on function */ + + case FNC_REW: /* rewind */ + sim_tape_rewind (uptr); /* BOT */ + mtc_sta = STA_BOT; /* update status */ + break; + + case FNC_RWS: /* rewind and offline */ + sim_tape_rewind (uptr); /* clear position */ + return sim_tape_detach (uptr); /* don't set cch flg */ + + case FNC_WFM: /* write file mark */ + st = sim_tape_wrtmk (uptr); /* write tmk */ + if (st != MTSE_OK) /* error? */ + r = mt_map_err (uptr, st); /* map error */ + mtc_sta = STA_EOF; /* set EOF status */ + break; + + case FNC_GAP: /* erase gap */ + break; + + case FNC_FSR: /* space forward */ + st = sim_tape_sprecf (uptr, &tbc); /* space rec fwd */ + if (st != MTSE_OK) /* error? */ + r = mt_map_err (uptr, st); /* map error */ + break; + + case FNC_BSR: /* space reverse */ + st = sim_tape_sprecr (uptr, &tbc); /* space rec rev */ + if (st != MTSE_OK) /* error? */ + r = mt_map_err (uptr, st); /* map error */ + break; + + case FNC_RC: /* read */ + if (mtc_1st) { /* first svc? */ + mtc_1st = mt_ptr = 0; /* clr 1st flop */ + st = sim_tape_rdrecf (uptr, mtxb, &mt_max, DBSIZE); /* read rec */ + if (st == MTSE_RECE) mtc_sta = mtc_sta | STA_PAR; /* rec in err? */ + else if (st != MTSE_OK) { /* other error? */ + r = mt_map_err (uptr, st); /* map error */ + if (r == SCPE_OK) { /* recoverable? */ + sim_activate (uptr, mtc_gtime); /* sched IRG */ + mtc_fnc = 0; /* NOP func */ + return SCPE_OK; + } + break; /* non-recov, done */ + } + if (mt_max < 12) { /* record too short? */ + mtc_sta = mtc_sta | STA_PAR; /* set flag */ + break; + } + } + if (mtc_dtf && (mt_ptr < mt_max)) { /* more chars? */ + if (mtd.flag) mtc_sta = mtc_sta | STA_TIM; + mtc_unit.buf = mtxb[mt_ptr++]; /* fetch next */ + mtdio (&mtd_dib, ioENF, 0); /* set dch flg */ + sim_activate (uptr, mtc_xtime); /* re-activate */ + return SCPE_OK; + } + sim_activate (uptr, mtc_gtime); /* schedule gap */ + mtc_fnc = 0; /* nop */ + return SCPE_OK; + + case FNC_WC: /* write */ + if (mtc_1st) mtc_1st = 0; /* no xfr on first */ + else { + if (mt_ptr < DBSIZE) { /* room in buffer? */ + mtxb[mt_ptr++] = (uint8) mtc_unit.buf; + mtc_sta = mtc_sta & ~STA_BOT; /* clear BOT */ + } + else mtc_sta = mtc_sta | STA_PAR; + } + if (mtc_dtf) { /* xfer flop set? */ + mtdio (&mtd_dib, ioENF, 0); /* set dch flg */ + sim_activate (uptr, mtc_xtime); /* re-activate */ + return SCPE_OK; + } + if (mt_ptr) { /* write buffer */ + st = sim_tape_wrrecf (uptr, mtxb, mt_ptr); /* write */ + if (st != MTSE_OK) { /* error? */ + r = mt_map_err (uptr, st); /* map error */ + break; /* done */ + } + } + sim_activate (uptr, mtc_gtime); /* schedule gap */ + mtc_fnc = 0; /* nop */ + return SCPE_OK; + + default: /* unknown */ + break; + } + +mtcio (&mtc_dib, ioENF, 0); /* set cch flg */ +mtc_sta = mtc_sta & ~STA_BUSY; /* not busy */ +return r; +} + +/* Map tape error status */ + +t_stat mt_map_err (UNIT *uptr, t_stat st) +{ +switch (st) { + + case MTSE_FMT: /* illegal fmt */ + case MTSE_UNATT: /* unattached */ + mtc_sta = mtc_sta | STA_REJ; /* reject */ + case MTSE_OK: /* no error */ + return SCPE_IERR; /* never get here! */ + + case MTSE_EOM: /* end of medium */ + case MTSE_TMK: /* end of file */ + mtc_sta = mtc_sta | STA_EOF; /* eof */ + break; + + case MTSE_IOERR: /* IO error */ + mtc_sta = mtc_sta | STA_PAR; /* error */ + if (mtc_stopioe) return SCPE_IOERR; + break; + + case MTSE_INVRL: /* invalid rec lnt */ + mtc_sta = mtc_sta | STA_PAR; + return SCPE_MTRLNT; + + case MTSE_RECE: /* record in error */ + mtc_sta = mtc_sta | STA_PAR; /* error */ + break; + + case MTSE_BOT: /* reverse into BOT */ + mtc_sta = mtc_sta | STA_BOT; /* set status */ + break; + + case MTSE_WRP: /* write protect */ + mtc_sta = mtc_sta | STA_REJ; /* reject */ + break; + } + +return SCPE_OK; +} + + +/* Controller clear */ + +t_stat mt_clear (void) +{ +t_stat st; + +if (sim_is_active (&mtc_unit) && /* write in prog? */ + (mtc_fnc == FNC_WC) && (mt_ptr > 0)) { /* yes, bad rec */ + st = sim_tape_wrrecf (&mtc_unit, mtxb, mt_ptr | MTR_ERF); + if (st != MTSE_OK) + mt_map_err (&mtc_unit, st); + } + +if (((mtc_fnc == FNC_REW) || (mtc_fnc == FNC_RWS)) && sim_is_active (&mtc_unit)) + sim_cancel (&mtc_unit); + +mtc_1st = mtc_dtf = 0; +mtc_sta = mtc_sta & STA_BOT; + +return SCPE_OK; +} + + +/* Reset routine */ + +t_stat mt_reset (DEVICE *dptr) +{ +DIB *dibptr = (DIB *) dptr->ctxt; /* DIB pointer */ + +hp_enbdis_pair (dptr, /* make pair cons */ + (dptr == &mtd_dev) ? &mtc_dev : &mtd_dev); + +IOPRESET (dibptr); /* PRESET device (does not use PON) */ + +mtc_fnc = 0; +mtc_1st = mtc_dtf = 0; + +sim_cancel (&mtc_unit); /* cancel activity */ +sim_tape_reset (&mtc_unit); + +if (mtc_unit.flags & UNIT_ATT) + mtc_sta = (sim_tape_bot (&mtc_unit)? STA_BOT: 0) | + (sim_tape_wrp (&mtc_unit)? STA_WLK: 0); +else + mtc_sta = STA_LOCAL | STA_BUSY; + +return SCPE_OK; +} + + +/* Attach routine */ + +t_stat mtc_attach (UNIT *uptr, char *cptr) +{ +t_stat r; + +r = sim_tape_attach (uptr, cptr); /* attach unit */ +if (r != SCPE_OK) return r; /* update status */ +mtc_sta = STA_BOT; +return r; +} + +/* Detach routine */ + +t_stat mtc_detach (UNIT* uptr) +{ +mtc_sta = 0; /* update status */ +return sim_tape_detach (uptr); /* detach unit */ +} diff --git a/HP2100/hp2100_mux.c b/HP2100/hp2100_mux.c index f341a51d..e098166b 100644 --- a/HP2100/hp2100_mux.c +++ b/HP2100/hp2100_mux.c @@ -1,1392 +1,1406 @@ -/* hp2100_mux.c: HP 2100 12920A terminal multiplexor simulator - - Copyright (c) 2002-2012, Robert M Supnik - - 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 - ROBERT M SUPNIK 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 Robert M Supnik shall not be - used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from Robert M Supnik. - - MUX,MUXL,MUXM 12920A terminal multiplexor - - 10-Feb-12 JDB Deprecated DEVNO in favor of SC - 28-Mar-11 JDB Tidied up signal handling - 26-Oct-10 JDB Changed I/O signal handler for revised signal model - 25-Nov-08 JDB Revised for new multiplexer library SHOW routines - 09-Oct-08 JDB "muxl_unit" defined one too many units (17 instead of 16) - 10-Sep-08 JDB SHOW MUX CONN/STAT with SET MUX DIAG is no longer disallowed - 07-Sep-08 JDB Changed Telnet poll to connect immediately after reset or attach - 27-Aug-08 JDB Added LINEORDER support - 12-Aug-08 JDB Added BREAK deferral to allow RTE break-mode to work - 26-Jun-08 JDB Rewrote device I/O to model backplane signals - 16-Apr-08 JDB Sync mux poll with console poll for idle compatibility - 06-Mar-07 JDB Corrected "mux_sta" size from 16 to 21 elements - Fixed "muxc_reset" to clear lines 16-20 - 26-Feb-07 JDB Added debug printouts - Fixed control card OTx to set current channel number - Fixed to set "muxl_ibuf" in response to a transmit interrupt - Changed "mux_xbuf", "mux_rbuf" declarations from 8 to 16 bits - Fixed to set "mux_rchp" when a line break is received - Fixed incorrect "odd_par" table values - Reversed test in "RCV_PAR" to return "LIL_PAR" on odd parity - Fixed mux reset (ioCRS) to clear port parameters - Fixed to use PUT_DCH instead of PUT_CCH for data channel status - 10-Feb-07 JDB Added DIAG/TERM modifiers to implement diagnostic mode - 28-Dec-06 JDB Added ioCRS state to I/O decoders - 02-Jun-06 JDB Fixed compiler warning for mux_ldsc init - 22-Nov-05 RMS Revised for new terminal processing routines - 29-Jun-05 RMS Added SET MUXLn DISCONNECT - 07-Oct-04 JDB Allow enable/disable from any device - 26-Apr-04 RMS Fixed SFS x,C and SFC x,C - Implemented DMA SRQ (follows FLG) - 05-Jan-04 RMS Revised for tmxr library changes - 21-Dec-03 RMS Added invalid character screening for TSB (from Mike Gemeny) - 09-May-03 RMS Added network device flag - 01-Nov-02 RMS Added 7B/8B support - 22-Aug-02 RMS Updated for changes to sim_tmxr - - Reference: - - 12920A Asynchronous Multiplexer Interface Kits Operating and Service Manual - (12920-90001, Oct-1972) - - - The 12920A was a 16-channel asynchronous terminal multiplexer. It supported - direct-connected terminals as well as modems at speeds up to 2400 baud. It - was the primary terminal multiplexer for the HP 2000 series of Time-Shared - BASIC systems. - - The multiplexer was implemented as a three-card set consisting of a lower - data card, an upper data card, and a modem control card. Under simulation, - these are implemented by three devices: - - MUXL lower data card (lines) - MUX upper data card (scanner) - MUXM control card (modem control) - - The lower and upper data cards must be in adjacent I/O slots. The control - card may be placed in any slot, although in practice it was placed in the - slot above the upper data card, so that all three cards were physically - together. - - The 12920A supported one or two control cards (two cards were used with - 801-type automatic dialers). Under simulation, only one control card is - supported. - - Implementation notes: - - 1. If a BREAK is detected during an input poll, and we are not in diagnostic - mode, we defer recognition until either a character is output or a second - successive input poll occurs. This is necessary for RTE break-mode - operation. Without this deferral, a BREAK during output would be ignored - by the RTE driver, making it impossible to stop a long listing. - - The problem is due to timing differences between simulated and real time. - The RTE multiplexer driver is a privileged driver. Privileged drivers - bypass RTE to provide rapid interrupt handling. To inform RTE that an - operation is complete, e.g., that a line has been written, the interrupt - section of the driver sets a device timeout of one clock tick (10 - milliseconds). When that timeout occurs, RTE is entered normally to - complete the I/O transaction. While the completion timeout is pending, - the driver ignores any further interrupts from the multiplexer line. - - The maximum communication rate for the multiplexer is 2400 baud, or - approximately 4.2 milliseconds per character transferred. A typical line - of 20 characters would therefore take ~85 milliseconds, plus the 10 - millisecond completion timeout, or about 95 milliseconds total. BREAK - recognition would be ignored for roughly 10% of that time. At lower baud - rates, recognition would be ignored for a correspondingly smaller - percentage of the time. - - However, SIMH uses an optimized timing of 500 instructions per character - transfer, rather than the ~6600 instructions that a character transfer - should take, and so a typical 20-character line will take about 11,000 - instructions. On the other hand, the clock tick is calibrated to real - time, and 10 milliseconds of real time takes about 420,000 instructions - on a 2.0 GHz PC. To be recognized, then, the BREAK key must be pressed - in a window that is open for about 2.5% of the time. Therefore, the - BREAK key will be ignored about 97.5% of the time, and RTE break-mode - effectively will not work. - - Deferring BREAK recognition until the next character is output ensures - that the BREAK interrupt will be accepted (the simulator delivers input - interrupts before output interrupts, so the BREAK interrupt arrives - before the output character transmit interrupt). If an output operation - is not in progress, then the BREAK will be recognized at the next input - poll. -*/ - - -#include - -#include "hp2100_defs.h" -#include "sim_sock.h" -#include "sim_tmxr.h" - - -/* Unit references */ - -#define MUX_LINES 16 /* number of user lines */ -#define MUX_ILINES 5 /* number of diag rcv only lines */ - - -/* Service times */ - -#define MUXL_WAIT 500 - - -/* Unit flags */ - -#define UNIT_V_MDM (TTUF_V_UF + 0) /* modem control */ -#define UNIT_V_DIAG (TTUF_V_UF + 1) /* loopback diagnostic */ -#define UNIT_MDM (1 << UNIT_V_MDM) -#define UNIT_DIAG (1 << UNIT_V_DIAG) - -/* Debug flags */ - -#define DEB_CMDS (1 << 0) /* Command initiation and completion */ -#define DEB_CPU (1 << 1) /* CPU I/O */ -#define DEB_XFER (1 << 2) /* Socket receive and transmit */ - -/* Channel number (OTA upper, LIA lower or upper) */ - -#define MUX_V_CHAN 10 /* channel num */ -#define MUX_M_CHAN 037 -#define MUX_CHAN(x) (((x) >> MUX_V_CHAN) & MUX_M_CHAN) - -/* OTA, lower = parameters or data */ - -#define OTL_P 0100000 /* parameter */ -#define OTL_TX 0040000 /* transmit */ -#define OTL_ENB 0020000 /* enable */ -#define OTL_TPAR 0010000 /* xmt parity */ -#define OTL_ECHO 0010000 /* rcv echo */ -#define OTL_DIAG 0004000 /* diagnose */ -#define OTL_SYNC 0004000 /* sync */ -#define OTL_V_LNT 8 /* char length */ -#define OTL_M_LNT 07 -#define OTL_LNT(x) (((x) >> OTL_V_LNT) & OTL_M_LNT) -#define OTL_V_BAUD 0 /* baud rate */ -#define OTL_M_BAUD 0377 -#define OTL_BAUD(x) (((x) >> OTL_V_BAUD) & OTL_M_BAUD) -#define OTL_CHAR 03777 /* char mask */ -#define OTL_PAR 0200 /* char parity */ - -/* LIA, lower = received data */ - -#define LIL_PAR 0100000 /* parity */ -#define PUT_DCH(x) (((x) & MUX_M_CHAN) << MUX_V_CHAN) -#define LIL_CHAR 01777 /* character */ - -/* LIA, upper = status */ - -#define LIU_SEEK 0100000 /* seeking NI */ -#define LIU_DG 0000010 /* diagnose */ -#define LIU_BRK 0000004 /* break */ -#define LIU_LOST 0000002 /* char lost */ -#define LIU_TR 0000001 /* trans/rcv */ - -/* OTA, control */ - -#define OTC_SCAN 0100000 /* scan */ -#define OTC_UPD 0040000 /* update */ -#define OTC_V_CHAN 10 /* channel */ -#define OTC_M_CHAN 017 -#define OTC_CHAN(x) (((x) >> OTC_V_CHAN) & OTC_M_CHAN) -#define OTC_EC2 0000200 /* enable Cn upd */ -#define OTC_EC1 0000100 -#define OTC_C2 0000040 /* Cn flops */ -#define OTC_C1 0000020 -#define OTC_V_C 4 /* S1 to C1 */ -#define OTC_ES2 0000010 /* enb comparison */ -#define OTC_ES1 0000004 -#define OTC_V_ES 2 -#define OTC_SS2 0000002 /* SSn flops */ -#define OTC_SS1 0000001 -#define OTC_RW (OTC_ES2|OTC_ES1|OTC_SS2|OTC_SS1) -#define RTS OCT_C2 /* C2 = rts */ -#define DTR OTC_C1 /* C1 = dtr */ - -/* LIA, control */ - -#define LIC_MBO 0140000 /* always set */ -#define LIC_V_CHAN 10 /* channel */ -#define LIC_M_CHAN 017 -#define PUT_CCH(x) (((x) & OTC_M_CHAN) << OTC_V_CHAN) -#define LIC_I2 0001000 /* change flags */ -#define LIC_I1 0000400 -#define LIC_S2 0000002 /* Sn flops */ -#define LIC_S1 0000001 -#define LIC_V_I 8 /* S1 to I1 */ -#define CDET LIC_S2 /* S2 = cdet */ -#define DSR LIC_S1 /* S1 = dsr */ - -#define LIC_TSTI(ch) (((muxc_lia[ch] ^ muxc_ota[ch]) & \ - ((muxc_ota[ch] & (OTC_ES2|OTC_ES1)) >> OTC_V_ES)) \ - << LIC_V_I) - - -/* Program constants */ - -static const uint8 odd_par [256] = { - 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 000-017 */ - 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, /* 020-037 */ - 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, /* 040-067 */ - 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 060-077 */ - 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, /* 100-117 */ - 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 120-137 */ - 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 140-157 */ - 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, /* 160-177 */ - 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, /* 200-217 */ - 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 220-237 */ - 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 240-267 */ - 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, /* 260-277 */ - 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 300-317 */ - 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, /* 320-337 */ - 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, /* 340-357 */ - 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1 /* 360-377 */ - }; - -#define RCV_PAR(x) (odd_par[(x) & 0377] ? 0 : LIL_PAR) -#define XMT_PAR(x) (odd_par[(x) & 0377] ? 0 : OTL_PAR) - - -/* Multiplexer controller state variables */ - -struct { - FLIP_FLOP control; /* control flip-flop */ - FLIP_FLOP flag; /* flag flip-flop */ - FLIP_FLOP flagbuf; /* flag buffer flip-flop */ - } muxl = { CLEAR, CLEAR, CLEAR }; - -uint32 muxl_ibuf = 0; /* low in: rcv data */ -uint32 muxl_obuf = 0; /* low out: param */ - -uint32 muxu_ibuf = 0; /* upr in: status */ -uint32 muxu_obuf = 0; /* upr out: chan */ - -struct { - FLIP_FLOP control; /* control flip-flop */ - FLIP_FLOP flag; /* flag flip-flop */ - FLIP_FLOP flagbuf; /* flag buffer flip-flop */ - } muxc = { CLEAR, CLEAR, CLEAR }; - -uint32 muxc_chan = 0; /* ctrl chan */ -uint32 muxc_scan = 0; /* ctrl scan */ - - -/* Multiplexer per-line state variables */ - -uint16 mux_sta [MUX_LINES + MUX_ILINES]; /* line status */ -uint16 mux_rpar [MUX_LINES + MUX_ILINES]; /* rcv param */ -uint16 mux_xpar [MUX_LINES]; /* xmt param */ -uint8 mux_rchp [MUX_LINES + MUX_ILINES]; /* rcv chr pend */ -uint8 mux_xdon [MUX_LINES]; /* xmt done */ -uint8 muxc_ota [MUX_LINES]; /* ctrl: Cn,ESn,SSn */ -uint8 muxc_lia [MUX_LINES]; /* ctrl: Sn */ -uint8 mux_defer [MUX_LINES]; /* break deferred flags */ - - -/* Multiplexer per-line buffer variables */ - -uint16 mux_rbuf[MUX_LINES + MUX_ILINES]; /* rcv buf */ -uint16 mux_xbuf[MUX_LINES]; /* xmt buf */ - - -/* Multiplexer local routines */ - -void mux_receive (int32 ln, int32 c, t_bool diag); -void mux_data_int (void); -void mux_ctrl_int (void); -void mux_diag (int32 c); - - -/* Multiplexer global routines */ - -IOHANDLER muxlio; -IOHANDLER muxuio; -IOHANDLER muxcio; - -t_stat muxi_svc (UNIT *uptr); -t_stat muxo_svc (UNIT *uptr); -t_stat muxc_reset (DEVICE *dptr); -t_stat mux_attach (UNIT *uptr, char *cptr); -t_stat mux_detach (UNIT *uptr); -t_stat mux_setdiag (UNIT *uptr, int32 val, char *cptr, void *desc); - - -/* MUXL/MUXU device information block. - - The DIBs of adjacent cards must be contained in an array, so they are defined - here and referenced in the lower and upper card device structures. -*/ - -DIB mux_dib[] = { - { &muxlio, MUXL }, - { &muxuio, MUXU } - }; - -#define muxl_dib mux_dib[0] -#define muxu_dib mux_dib[1] - - -/* MUXL data structures. - - muxl_dib MUXL device information block - muxl_unit MUXL unit list - muxl_reg MUXL register list - muxl_mod MUXL modifier list - muxl_dev MUXL device descriptor -*/ - -TMXR mux_desc; - -DEVICE muxl_dev; - -UNIT muxl_unit[] = { - { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT }, - { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT }, - { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT }, - { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT }, - { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT }, - { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT }, - { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT }, - { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT }, - { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT }, - { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT }, - { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT }, - { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT }, - { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT }, - { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT }, - { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT }, - { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT } - }; - -REG muxl_reg[] = { - { FLDATA (CTL, muxl.control, 0) }, - { FLDATA (FLG, muxl.flag, 0) }, - { FLDATA (FBF, muxl.flagbuf, 0) }, - { BRDATA (STA, mux_sta, 8, 16, MUX_LINES + MUX_ILINES) }, - { BRDATA (RPAR, mux_rpar, 8, 16, MUX_LINES + MUX_ILINES) }, - { BRDATA (XPAR, mux_xpar, 8, 16, MUX_LINES) }, - { BRDATA (RBUF, mux_rbuf, 8, 16, MUX_LINES + MUX_ILINES) }, - { BRDATA (XBUF, mux_xbuf, 8, 16, MUX_LINES) }, - { BRDATA (RCHP, mux_rchp, 8, 1, MUX_LINES + MUX_ILINES) }, - { BRDATA (XDON, mux_xdon, 8, 1, MUX_LINES) }, - { BRDATA (BDFR, mux_defer, 8, 1, MUX_LINES) }, - { URDATA (TIME, muxl_unit[0].wait, 10, 24, 0, - MUX_LINES, REG_NZ + PV_LEFT) }, - { ORDATA (SC, muxl_dib.select_code, 6), REG_HRO }, - { ORDATA (DEVNO, muxl_dib.select_code, 6), REG_HRO }, - { NULL } - }; - -MTAB muxl_mod[] = { - { TT_MODE, TT_MODE_UC, "UC", "UC", NULL, NULL, NULL }, - { TT_MODE, TT_MODE_7B, "7b", "7B", NULL, NULL, NULL }, - { TT_MODE, TT_MODE_8B, "8b", "8B", NULL, NULL, NULL }, - { TT_MODE, TT_MODE_7P, "7p", "7P", NULL, NULL, NULL }, - - { UNIT_MDM, UNIT_MDM, "dataset", "DATASET", NULL, NULL, NULL }, - { UNIT_MDM, 0, "no dataset", "NODATASET", NULL, NULL, NULL }, - - { MTAB_XTD | MTAB_VUN | MTAB_NC, 0, "LOG", "LOG", &tmxr_set_log, &tmxr_show_log, &mux_desc }, - { MTAB_XTD | MTAB_VUN | MTAB_NC, 0, NULL, "NOLOG", &tmxr_set_nolog, NULL, &mux_desc }, - - { MTAB_XTD | MTAB_VUN, 0, NULL, "DISCONNECT", &tmxr_dscln, NULL, &mux_desc }, - { MTAB_XTD | MTAB_VDV, 1, "SC", "SC", &hp_setsc, &hp_showsc, &muxl_dev }, - { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &muxl_dev }, - - { 0 } - }; - -DEVICE muxl_dev = { - "MUXL", /* device name */ - muxl_unit, /* unit array */ - muxl_reg, /* register array */ - muxl_mod, /* modifier array */ - MUX_LINES, /* number of units */ - 10, /* address radix */ - 31, /* address width */ - 1, /* address increment */ - 8, /* data radix */ - 8, /* data width */ - NULL, /* examine routine */ - NULL, /* deposit routine */ - &muxc_reset, /* reset routine */ - NULL, /* boot routine */ - NULL, /* attach routine */ - NULL, /* detach routine */ - &muxl_dib, /* device information block */ - DEV_DISABLE, /* device flags */ - 0, /* debug control flags */ - NULL, /* debug flag name table */ - NULL, /* memory size change routine */ - NULL }; /* logical device name */ - - -/* MUXU data structures - - mux_order MUX line connection order table - mux_ldsc MUX terminal multiplexer line descriptors - mux_desc MUX terminal multiplexer device descriptor - - muxu_dib MUXU device information block - muxu_unit MUXU unit list - muxu_reg MUXU register list - muxu_mod MUXU modifier list - muxu_deb MUXU debug list - muxu_dev MUXU device descriptor -*/ - -DEVICE muxu_dev; - -int32 mux_order [MUX_LINES] = { -1 }; /* connection order */ -TMLN mux_ldsc [MUX_LINES] = { { 0 } }; /* line descriptors */ -TMXR mux_desc = { MUX_LINES, 0, 0, mux_ldsc, mux_order }; /* device descriptor */ - -UNIT muxu_unit = { UDATA (&muxi_svc, UNIT_ATTABLE, 0), POLL_FIRST }; - -REG muxu_reg[] = { - { ORDATA (IBUF, muxu_ibuf, 16) }, - { ORDATA (OBUF, muxu_obuf, 16) }, - { ORDATA (SC, muxu_dib.select_code, 6), REG_HRO }, - { ORDATA (DEVNO, muxu_dib.select_code, 6), REG_HRO }, - { NULL } - }; - -MTAB muxu_mod[] = { - { UNIT_DIAG, UNIT_DIAG, "diagnostic mode", "DIAG", &mux_setdiag, NULL, NULL }, - { UNIT_DIAG, 0, "terminal mode", "TERM", &mux_setdiag, NULL, NULL }, - { UNIT_ATT, UNIT_ATT, "", NULL, NULL, &tmxr_show_summ, &mux_desc }, - - { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "LINEORDER", "LINEORDER", &tmxr_set_lnorder, &tmxr_show_lnorder, &mux_desc }, - - { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "CONNECTIONS", NULL, NULL, &tmxr_show_cstat, &mux_desc }, - { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "STATISTICS", NULL, NULL, &tmxr_show_cstat, &mux_desc }, - { MTAB_XTD | MTAB_VDV, 1, NULL, "DISCONNECT", &tmxr_dscln, NULL, &mux_desc }, - { MTAB_XTD | MTAB_VDV, 1, "SC", "SC", &hp_setsc, &hp_showsc, &muxl_dev }, - { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &muxl_dev }, - - { 0 } - }; - -DEBTAB muxu_deb [] = { - { "CMDS", DEB_CMDS }, - { "CPU", DEB_CPU }, - { "XFER", DEB_XFER }, - { NULL, 0 } - }; - -DEVICE muxu_dev = { - "MUX", /* device name */ - &muxu_unit, /* unit array */ - muxu_reg, /* register array */ - muxu_mod, /* modifier array */ - 1, /* number of units */ - 10, /* address radix */ - 31, /* address width */ - 1, /* address increment */ - 8, /* data radix */ - 8, /* data width */ - &tmxr_ex, /* examine routine */ - &tmxr_dep, /* deposit routine */ - &muxc_reset, /* reset routine */ - NULL, /* boot routine */ - &mux_attach, /* attach routine */ - &mux_detach, /* detach routine */ - &muxu_dib, /* device information block */ - DEV_DISABLE | DEV_DEBUG, /* device flags */ - 0, /* debug control flags */ - muxu_deb, /* debug flag name table */ - NULL, /* memory size change routine */ - NULL }; /* logical device name */ - - -/* MUXC data structures. - - muxc_dib MUXC device information block - muxc_unit MUXC unit list - muxc_reg MUXC register list - muxc_mod MUXC modifier list - muxc_dev MUXC device descriptor -*/ - -DEVICE muxc_dev; - -DIB muxc_dib = { &muxcio, MUXC }; - -UNIT muxc_unit = { UDATA (NULL, 0, 0) }; - -REG muxc_reg[] = { - { FLDATA (CTL, muxc.control, 0) }, - { FLDATA (FLG, muxc.flag, 0) }, - { FLDATA (FBF, muxc.flagbuf, 0) }, - { FLDATA (SCAN, muxc_scan, 0) }, - { ORDATA (CHAN, muxc_chan, 4) }, - { BRDATA (DSO, muxc_ota, 8, 6, MUX_LINES) }, - { BRDATA (DSI, muxc_lia, 8, 2, MUX_LINES) }, - { ORDATA (SC, muxc_dib.select_code, 6), REG_HRO }, - { ORDATA (DEVNO, muxc_dib.select_code, 6), REG_HRO }, - { NULL } - }; - -MTAB muxc_mod[] = { - { MTAB_XTD | MTAB_VDV, 0, "SC", "SC", &hp_setsc, &hp_showsc, &muxc_dev }, - { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &muxc_dev }, - { 0 } - }; - -DEVICE muxc_dev = { - "MUXM", /* device name */ - &muxc_unit, /* unit array */ - muxc_reg, /* register array */ - muxc_mod, /* modifier array */ - 1, /* number of units */ - 10, /* address radix */ - 31, /* address width */ - 1, /* address increment */ - 8, /* data radix */ - 8, /* data width */ - NULL, /* examine routine */ - NULL, /* deposit routine */ - &muxc_reset, /* reset routine */ - NULL, /* boot routine */ - NULL, /* attach routine */ - NULL, /* detach routine */ - &muxc_dib, /* device information block */ - DEV_DISABLE, /* device flags */ - 0, /* debug control flags */ - NULL, /* debug flag name table */ - NULL, /* memory size change routine */ - NULL }; /* logical device name */ - - -/* Lower data card I/O signal handler. - - Implementation notes: - - 1. The operating manual says that "at least 100 milliseconds of CLC 0s must - be programmed" by systems employing the multiplexer to ensure that the - multiplexer resets. In practice, such systems issue 128K CLC 0 - instructions. As we provide debug logging of multiplexer resets, a CRS - counter is used to ensure that only one debug line is printed in response - to these 128K CRS invocations. -*/ - -uint32 muxlio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) -{ -int32 ln; -const char *hold_or_clear = (signal_set & ioCLF ? ",C" : ""); -static uint32 crs_count = 0; /* cntr for ioCRS repeat */ -IOSIGNAL signal; -IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ - -if (crs_count && !(signal_set & ioCRS)) { /* counting CRSes and not present? */ - if (DEBUG_PRI (muxu_dev, DEB_CMDS)) /* report reset count */ - fprintf (sim_deb, ">>MUXl cmds: [CRS] Multiplexer reset %d times\n", - crs_count); - - crs_count = 0; /* clear counter */ - } - -while (working_set) { - signal = IONEXT (working_set); /* isolate next signal */ - - switch (signal) { /* dispatch I/O signal */ - - case ioCLF: /* clear flag flip-flop */ - muxl.flag = muxl.flagbuf = CLEAR; - - if (DEBUG_PRI (muxu_dev, DEB_CMDS)) - fputs (">>MUXl cmds: [CLF] Flag cleared\n", sim_deb); - - mux_data_int (); /* look for new int */ - break; - - - case ioSTF: /* set flag flip-flop */ - case ioENF: /* enable flag */ - muxl.flag = muxl.flagbuf = SET; - - if (DEBUG_PRI (muxu_dev, DEB_CMDS)) - fputs (">>MUXl cmds: [STF] Flag set\n", sim_deb); - break; - - - case ioSFC: /* skip if flag is clear */ - setstdSKF (muxl); - break; - - - case ioSFS: /* skip if flag is set */ - setstdSKF (muxl); - break; - - - case ioIOI: /* I/O data input */ - stat_data = IORETURN (SCPE_OK, muxl_ibuf); /* merge in return status */ - - if (DEBUG_PRI (muxu_dev, DEB_CPU)) - fprintf (sim_deb, ">>MUXl cpu: [LIx%s] Data = %06o\n", hold_or_clear, muxl_ibuf); - break; - - - case ioIOO: /* I/O data output */ - muxl_obuf = IODATA (stat_data); /* store data */ - - if (DEBUG_PRI (muxu_dev, DEB_CPU)) - if (muxl_obuf & OTL_P) - fprintf (sim_deb, ">>MUXl cpu: [OTx%s] Parameter = %06o\n", hold_or_clear, muxl_obuf); - else - fprintf (sim_deb, ">>MUXl cpu: [OTx%s] Data = %06o\n", hold_or_clear, muxl_obuf); - break; - - - case ioPOPIO: /* power-on preset to I/O */ - muxl.flag = muxl.flagbuf = SET; /* set flag andflag buffer */ - break; - - - case ioCRS: /* control reset */ - if (crs_count == 0) { /* first reset? */ - muxl.control = CLEAR; /* clear control flip-flop */ - - for (ln = 0; ln < MUX_LINES; ln++) { /* clear transmit info */ - mux_xbuf[ln] = mux_xpar[ln] = 0; - muxc_ota[ln] = muxc_lia[ln] = mux_xdon[ln] = 0; - } - - for (ln = 0; ln < (MUX_LINES + MUX_ILINES); ln++) { - mux_rbuf[ln] = mux_rpar[ln] = 0; /* clear receive info */ - mux_sta[ln] = mux_rchp[ln] = 0; - } - } - - crs_count = crs_count + 1; /* increment count */ - break; - - - case ioCLC: /* clear control flip-flop */ - muxl.control = CLEAR; - - if (DEBUG_PRI (muxu_dev, DEB_CMDS)) - fprintf (sim_deb, ">>MUXl cmds: [CLC%s] Data interrupt inhibited\n", hold_or_clear); - break; - - - case ioSTC: /* set control flip-flop */ - muxl.control = SET; /* set control */ - - ln = MUX_CHAN (muxu_obuf); /* get chan # */ - - if (muxl_obuf & OTL_TX) { /* transmit? */ - if (ln < MUX_LINES) { /* line valid? */ - if (muxl_obuf & OTL_P) { /* parameter? */ - mux_xpar[ln] = muxl_obuf; /* store param value */ - if (DEBUG_PRI (muxu_dev, DEB_CMDS)) - fprintf (sim_deb, - ">>MUXl cmds: [STC%s] Transmit channel %d parameter %06o stored\n", - hold_or_clear, ln, muxl_obuf); - } - - else { /* data */ - if (mux_xpar[ln] & OTL_TPAR) /* parity requested? */ - muxl_obuf = /* add parity bit */ - muxl_obuf & ~OTL_PAR | - XMT_PAR(muxl_obuf); - mux_xbuf[ln] = muxl_obuf; /* load buffer */ - - if (sim_is_active (&muxl_unit[ln])) { /* still working? */ - mux_sta[ln] = mux_sta[ln] | LIU_LOST; /* char lost */ - if (DEBUG_PRI (muxu_dev, DEB_CMDS)) - fprintf (sim_deb, ">>MUXl cmds: [STC%s] Transmit channel %d data overrun\n", - hold_or_clear, ln); - } - else { - if (muxu_unit.flags & UNIT_DIAG) /* loopback? */ - mux_ldsc[ln].conn = 1; /* connect this line */ - sim_activate (&muxl_unit[ln], muxl_unit[ln].wait); - if (DEBUG_PRI (muxu_dev, DEB_CMDS)) - fprintf (sim_deb, ">>MUXl cmds: [STC%s] Transmit channel %d data %06o scheduled\n", - hold_or_clear, ln, muxl_obuf); - } - } - } - else if (DEBUG_PRI (muxu_dev, DEB_CMDS)) /* line invalid */ - fprintf (sim_deb, ">>MUXl cmds: [STC%s] Transmit channel %d invalid\n", hold_or_clear, ln); - } - - else /* receive */ - if (ln < (MUX_LINES + MUX_ILINES)) { /* line valid? */ - if (muxl_obuf & OTL_P) { /* parameter? */ - mux_rpar[ln] = muxl_obuf; /* store param value */ - if (DEBUG_PRI (muxu_dev, DEB_CMDS)) - fprintf (sim_deb, - ">>MUXl cmds: [STC%s] Receive channel %d parameter %06o stored\n", - hold_or_clear, ln, muxl_obuf); - } - - else if (DEBUG_PRI (muxu_dev, DEB_CMDS)) /* data (invalid action) */ - fprintf (sim_deb, - ">>MUXl cmds: [STC%s] Receive channel %d parameter %06o invalid action\n", - hold_or_clear, ln, muxl_obuf); - } - - else if (DEBUG_PRI (muxu_dev, DEB_CMDS)) /* line invalid */ - fprintf (sim_deb, ">>MUXl cmds: [STC%s] Receive channel %d invalid\n", hold_or_clear, ln); - break; - - - case ioSIR: /* set interrupt request */ - setstdPRL (muxl); /* set standard PRL signal */ - setstdIRQ (muxl); /* set standard IRQ signal */ - setstdSRQ (muxl); /* set standard SRQ signal */ - break; - - - case ioIAK: /* interrupt acknowledge */ - muxl.flagbuf = CLEAR; - break; - - - default: /* all other signals */ - break; /* are ignored */ - } - - working_set = working_set & ~signal; /* remove current signal from set */ - } - -return stat_data; -} - - -/* Upper data card I/O signal handler. - - The upper data card does not have a control, flag, or flag buffer flip-flop. - It does not drive the IRQ or SRQ lines, so the I/O dispatcher does not handle - the ioSIR signal. - - Implementation notes: - - 1. The upper and lower data card hardware takes a number of actions in - response to the CRS signal. Under simulation, these actions are taken by - the lower data card CRS handler. -*/ - -uint32 muxuio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) -{ -IOSIGNAL signal; -IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ - -while (working_set) { - signal = IONEXT (working_set); /* isolate next signal */ - - switch (signal) { /* dispatch I/O signal */ - - case ioIOI: /* I/O data input */ - stat_data = IORETURN (SCPE_OK, muxu_ibuf); /* merge in return status */ - - if (DEBUG_PRI (muxu_dev, DEB_CPU)) - fprintf (sim_deb, ">>MUXu cpu: [LIx] Status = %06o, channel = %d\n", - muxu_ibuf, MUX_CHAN(muxu_ibuf)); - break; - - - case ioIOO: /* I/O data output */ - muxu_obuf = IODATA (stat_data); /* store data */ - - if (DEBUG_PRI (muxu_dev, DEB_CPU)) - fprintf (sim_deb, ">>MUXu cpu: [OTx] Data channel = %d\n", MUX_CHAN(muxu_obuf)); - break; - - - default: /* all other signals */ - break; /* are ignored */ - } - - working_set = working_set & ~signal; /* remove current signal from set */ - } - -return stat_data; -} - - -/* Control card I/O signal handler. - - In diagnostic mode, the control signals C1 and C2 are looped back to status - signals S1 and S2. Changing the control signals may cause an interrupt, so a - test is performed after IOO processing. -*/ - -uint32 muxcio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) -{ -const char *hold_or_clear = (signal_set & ioCLF ? ",C" : ""); -uint16 data; -int32 ln, old; -IOSIGNAL signal; -IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ - -while (working_set) { - signal = IONEXT (working_set); /* isolate next signal */ - - switch (signal) { /* dispatch I/O signal */ - - case ioCLF: /* clear flag flip-flop */ - muxc.flag = muxc.flagbuf = CLEAR; - - if (DEBUG_PRI (muxu_dev, DEB_CMDS)) - fputs (">>MUXc cmds: [CLF] Flag cleared\n", sim_deb); - - mux_ctrl_int (); /* look for new int */ - break; - - - case ioSTF: /* set flag flip-flop */ - case ioENF: /* enable flag */ - muxc.flag = muxc.flagbuf = SET; - - if (DEBUG_PRI (muxu_dev, DEB_CMDS)) - fputs (">>MUXc cmds: [STF] Flag set\n", sim_deb); - break; - - - case ioSFC: /* skip if flag is clear */ - setstdSKF (muxc); - break; - - - case ioSFS: /* skip if flag is set */ - setstdSKF (muxc); - break; - - - case ioIOI: /* I/O data input */ - data = LIC_MBO | PUT_CCH (muxc_chan) | /* mbo, chan num */ - LIC_TSTI (muxc_chan) | /* I2, I1 */ - (muxc_ota[muxc_chan] & (OTC_ES2 | OTC_ES1)) | /* ES2, ES1 */ - (muxc_lia[muxc_chan] & (LIC_S2 | LIC_S1)); /* S2, S1 */ - - if (DEBUG_PRI (muxu_dev, DEB_CPU)) - fprintf (sim_deb, ">>MUXc cpu: [LIx%s] Status = %06o, channel = %d\n", - hold_or_clear, data, muxc_chan); - - muxc_chan = (muxc_chan + 1) & LIC_M_CHAN; /* incr channel */ - stat_data = IORETURN (SCPE_OK, data); /* merge in return status */ - break; - - - case ioIOO: /* I/O data output */ - data = IODATA (stat_data); /* clear supplied status */ - ln = muxc_chan = OTC_CHAN (data); /* set channel */ - - if (data & OTC_SCAN) muxc_scan = 1; /* set scan flag */ - else muxc_scan = 0; - - if (data & OTC_UPD) { /* update? */ - old = muxc_ota[ln]; /* save prior val */ - muxc_ota[ln] = /* save ESn,SSn */ - (muxc_ota[ln] & ~OTC_RW) | (data & OTC_RW); - - if (data & OTC_EC2) /* if EC2, upd C2 */ - muxc_ota[ln] = - (muxc_ota[ln] & ~OTC_C2) | (data & OTC_C2); - - if (data & OTC_EC1) /* if EC1, upd C1 */ - muxc_ota[ln] = - (muxc_ota[ln] & ~OTC_C1) | (data & OTC_C1); - - if (muxu_unit.flags & UNIT_DIAG) /* loopback? */ - muxc_lia[ln ^ 1] = /* set S1, S2 to C1, C2 */ - (muxc_lia[ln ^ 1] & ~(LIC_S2 | LIC_S1)) | - (muxc_ota[ln] & (OTC_C1 | OTC_C2)) >> OTC_V_C; - - else if ((muxl_unit[ln].flags & UNIT_MDM) && /* modem ctrl? */ - (old & DTR) && /* DTR drop? */ - !(muxc_ota[ln] & DTR)) { - tmxr_linemsg (&mux_ldsc[ln], "\r\nLine hangup\r\n"); - tmxr_reset_ln (&mux_ldsc[ln]); /* reset line */ - muxc_lia[ln] = 0; /* dataset off */ - } - } /* end update */ - - if (DEBUG_PRI (muxu_dev, DEB_CPU)) - fprintf (sim_deb, ">>MUXc cpu: [OTx%s] Parameter = %06o, channel = %d\n", - hold_or_clear, data, ln); - - if ((muxu_unit.flags & UNIT_DIAG) && (!muxc.flag)) /* loopback and flag clear? */ - mux_ctrl_int (); /* status chg may interrupt */ - break; - - - case ioPOPIO: /* power-on preset to I/O */ - muxc.flag = muxc.flagbuf = SET; /* set flag and flag buffer */ - break; - - - case ioCRS: /* control reset */ - case ioCLC: /* clear control flip-flop */ - muxc.control = CLEAR; - break; - - - case ioSTC: /* set control flip-flop */ - muxc.control = SET; - break; - - - case ioSIR: /* set interrupt request */ - setstdPRL (muxc); /* set standard PRL signal */ - setstdIRQ (muxc); /* set standard IRQ signal */ - setstdSRQ (muxc); /* set standard SRQ signal */ - break; - - - case ioIAK: /* interrupt acknowledge */ - muxc.flagbuf = CLEAR; - break; - - - default: /* all other signals */ - break; /* are ignored */ - } - - working_set = working_set & ~signal; /* remove current signal from set */ - } - -return stat_data; -} - - -/* Unit service - receive side - - Poll for new connections - Poll all active lines for input -*/ - -t_stat muxi_svc (UNIT *uptr) -{ -int32 ln, c; -t_bool loopback; - -loopback = ((muxu_unit.flags & UNIT_DIAG) != 0); /* diagnostic mode? */ - -if (!loopback) { /* terminal mode? */ - if (uptr->wait == POLL_FIRST) /* first poll? */ - uptr->wait = sync_poll (INITIAL); /* initial synchronization */ - else /* not first */ - uptr->wait = sync_poll (SERVICE); /* continue synchronization */ - - sim_activate (uptr, uptr->wait); /* continue polling */ - - ln = tmxr_poll_conn (&mux_desc); /* look for connect */ - - if (ln >= 0) { /* got one? */ - if ((muxl_unit[ln].flags & UNIT_MDM) && /* modem ctrl? */ - (muxc_ota[ln] & DTR)) /* DTR? */ - muxc_lia[ln] = muxc_lia[ln] | CDET; /* set cdet */ - muxc_lia[ln] = muxc_lia[ln] | DSR; /* set dsr */ - mux_ldsc[ln].rcve = 1; /* rcv enabled */ - } - tmxr_poll_rx (&mux_desc); /* poll for input */ - } - -for (ln = 0; ln < MUX_LINES; ln++) { /* loop thru lines */ - if (mux_ldsc[ln].conn) { /* connected? */ - if (loopback) { /* diagnostic mode? */ - c = mux_xbuf[ln ^ 1] & OTL_CHAR; /* get char from xmit line */ - if (c == 0) /* all char bits = 0? */ - c = c | SCPE_BREAK; /* set break flag */ - mux_ldsc[ln].conn = 0; /* clear connection */ - } - - else if (mux_defer[ln]) /* break deferred? */ - c = SCPE_BREAK; /* supply it now */ - - else - c = tmxr_getc_ln (&mux_ldsc[ln]); /* get char from Telnet */ - - if (c) /* valid char? */ - mux_receive (ln, c, loopback); /* process it */ - } - - else /* not connected */ - if (!loopback) /* terminal mode? */ - muxc_lia[ln] = 0; /* line disconnected */ - } - -if (!muxl.flag) mux_data_int (); /* scan for data int */ -if (!muxc.flag) mux_ctrl_int (); /* scan modem */ -return SCPE_OK; -} - - -/* Unit service - transmit side */ - -t_stat muxo_svc (UNIT *uptr) -{ -int32 c, fc, ln, altln; -t_bool loopback; - -ln = uptr - muxl_unit; /* line # */ -altln = ln ^ 1; /* alt. line for diag mode */ - -fc = mux_xbuf[ln] & OTL_CHAR; /* full character data */ -c = fc & 0377; /* Telnet character data */ - -loopback = ((muxu_unit.flags & UNIT_DIAG) != 0); /* diagnostic mode? */ - -if (mux_ldsc[ln].conn) { /* connected? */ - if (mux_ldsc[ln].xmte) { /* xmt enabled? */ - if (loopback) /* diagnostic mode? */ - mux_ldsc[ln].conn = 0; /* clear connection */ - - else if (mux_defer[ln]) /* break deferred? */ - mux_receive (ln, SCPE_BREAK, loopback); /* process it now */ - - if ((mux_xbuf[ln] & OTL_SYNC) == 0) { /* start bit 0? */ - TMLN *lp = &mux_ldsc[ln]; /* get line */ - c = sim_tt_outcvt (c, TT_GET_MODE (muxl_unit[ln].flags)); - - if (mux_xpar[ln] & OTL_DIAG) /* xmt diagnose? */ - mux_diag (fc); /* before munge */ - - if (loopback) { /* diagnostic mode? */ - mux_ldsc[altln].conn = 1; /* set recv connection */ - sim_activate (&muxu_unit, 1); /* schedule receive */ - } - - else { /* no loopback */ - if (c >= 0) /* valid? */ - tmxr_putc_ln (lp, c); /* output char */ - tmxr_poll_tx (&mux_desc); /* poll xmt */ - } - } - - mux_xdon[ln] = 1; /* set for xmit irq */ - - if (DEBUG_PRI (muxu_dev, DEB_XFER) && (loopback | (c >= 0))) - fprintf (sim_deb, ">>MUXl xfer: Line %d character %s sent\n", - ln, fmt_char ((uint8) (loopback ? fc : c))); - } - - else { /* buf full */ - tmxr_poll_tx (&mux_desc); /* poll xmt */ - sim_activate (uptr, muxl_unit[ln].wait); /* wait */ - return SCPE_OK; - } - } - -if (!muxl.flag) mux_data_int (); /* scan for int */ -return SCPE_OK; -} - - -/* Process a character received from a multiplexer port */ - -void mux_receive (int32 ln, int32 c, t_bool diag) -{ -if (c & SCPE_BREAK) { /* break? */ - if (mux_defer[ln] || diag) { /* break deferred or diagnostic mode? */ - mux_defer[ln] = 0; /* process now */ - mux_rbuf[ln] = 0; /* break returns NUL */ - mux_sta[ln] = mux_sta[ln] | LIU_BRK; /* set break status */ - - if (DEBUG_PRI (muxu_dev, DEB_XFER)) - if (diag) - fputs (">>MUXl xfer: Break detected\n", sim_deb); - else - fputs (">>MUXl xfer: Deferred break processed\n", sim_deb); - } - - else { - mux_defer[ln] = 1; /* defer break */ - - if (DEBUG_PRI (muxu_dev, DEB_XFER)) - fputs (">>MUXl xfer: Break detected and deferred\n", sim_deb); - - return; - } - } -else { /* normal */ - if (mux_rchp[ln]) /* char already pending? */ - mux_sta[ln] = mux_sta[ln] | LIU_LOST; - - if (!diag) { /* terminal mode? */ - c = sim_tt_inpcvt (c, TT_GET_MODE (muxl_unit[ln].flags)); - if (mux_rpar[ln] & OTL_ECHO) { /* echo? */ - TMLN *lp = &mux_ldsc[ln]; /* get line */ - tmxr_putc_ln (lp, c); /* output char */ - tmxr_poll_tx (&mux_desc); /* poll xmt */ - } - } - mux_rbuf[ln] = c; /* save char */ - } - -mux_rchp[ln] = 1; /* char pending */ - -if (DEBUG_PRI (muxu_dev, DEB_XFER)) - fprintf (sim_deb, ">>MUXl xfer: Line %d character %s received\n", - ln, fmt_char ((uint8) c)); - -if (mux_rpar[ln] & OTL_DIAG) /* diagnose this line? */ - mux_diag (c); /* do diagnosis */ - -return; -} - - -/* Look for data interrupt */ - -void mux_data_int (void) -{ -int32 i; - -for (i = 0; i < MUX_LINES; i++) { /* rcv lines */ - if ((mux_rpar[i] & OTL_ENB) && mux_rchp[i]) { /* enabled, char? */ - muxl_ibuf = PUT_DCH (i) | /* lo buf = char */ - mux_rbuf[i] & LIL_CHAR | - RCV_PAR (mux_rbuf[i]); - muxu_ibuf = PUT_DCH (i) | mux_sta[i]; /* hi buf = stat */ - mux_rchp[i] = 0; /* clr char, stat */ - mux_sta[i] = 0; - - if (DEBUG_PRI (muxu_dev, DEB_CMDS)) - fprintf (sim_deb, ">>MUXl cmds: Receive channel %d interrupt requested\n", i); - - muxlio (&muxl_dib, ioENF, 0); /* interrupt */ - return; - } - } -for (i = 0; i < MUX_LINES; i++) { /* xmt lines */ - if ((mux_xpar[i] & OTL_ENB) && mux_xdon[i]) { /* enabled, done? */ - muxl_ibuf = PUT_DCH (i) | /* lo buf = last rcv char */ - mux_rbuf[i] & LIL_CHAR | - RCV_PAR (mux_rbuf[i]); - muxu_ibuf = PUT_DCH (i) | mux_sta[i] | LIU_TR; /* hi buf = stat */ - mux_xdon[i] = 0; /* clr done, stat */ - mux_sta[i] = 0; - - if (DEBUG_PRI (muxu_dev, DEB_CMDS)) - fprintf (sim_deb, ">>MUXl cmds: Transmit channel %d interrupt requested\n", i); - - muxlio (&muxl_dib, ioENF, 0); /* interrupt */ - return; - } - } -for (i = MUX_LINES; i < (MUX_LINES + MUX_ILINES); i++) { /* diag lines */ - if ((mux_rpar[i] & OTL_ENB) && mux_rchp[i]) { /* enabled, char? */ - muxl_ibuf = PUT_DCH (i) | /* lo buf = char */ - mux_rbuf[i] & LIL_CHAR | - RCV_PAR (mux_rbuf[i]); - muxu_ibuf = PUT_DCH (i) | mux_sta[i] | LIU_DG; /* hi buf = stat */ - mux_rchp[i] = 0; /* clr char, stat */ - mux_sta[i] = 0; - - if (DEBUG_PRI (muxu_dev, DEB_CMDS)) - fprintf (sim_deb, ">>MUXl cmds: Receive channel %d interrupt requested\n", i); - - muxlio (&muxl_dib, ioENF, 0); /* interrupt */ - return; - } - } -return; -} - - -/* Look for control interrupt - - If either of the incoming status bits does not match the stored status, and - the corresponding mismatch is enabled, a control interrupt request is - generated. Depending on the scan flag, we check either all 16 lines or just - the current line. If an interrupt is requested, the channel counter - indicates the interrupting channel. -*/ - -void mux_ctrl_int (void) -{ -int32 i, line_count; - -line_count = (muxc_scan ? MUX_LINES : 1); /* check one or all lines */ - -for (i = 0; i < line_count; i++) { - if (muxc_scan) /* scanning? */ - muxc_chan = (muxc_chan + 1) & LIC_M_CHAN; /* step channel */ - if (LIC_TSTI (muxc_chan)) { /* status change? */ - - if (DEBUG_PRI (muxu_dev, DEB_CMDS)) - fprintf (sim_deb, - ">>MUXc cmds: Control channel %d interrupt requested (poll = %d)\n", - muxc_chan, i + 1); - - muxcio (&muxc_dib, ioENF, 0); /* set flag */ - break; - } - } -return; -} - - -/* Set diagnostic lines for given character */ - -void mux_diag (int32 c) -{ -int32 i; - -for (i = MUX_LINES; i < (MUX_LINES + MUX_ILINES); i++) { - if (c & SCPE_BREAK) { /* break? */ - mux_sta[i] = mux_sta[i] | LIU_BRK; - mux_rbuf[i] = 0; /* no char */ - } - else { - if (mux_rchp[i]) mux_sta[i] = mux_sta[i] | LIU_LOST; - mux_rchp[i] = 1; - mux_rbuf[i] = c; - } - } -return; -} - - -/* Reset an individual line */ - -void mux_reset_ln (int32 i) -{ -mux_rbuf[i] = mux_xbuf[i] = 0; /* clear state */ -mux_rpar[i] = mux_xpar[i] = 0; -mux_rchp[i] = mux_xdon[i] = 0; -mux_sta[i] = mux_defer[i] = 0; -muxc_ota[i] = muxc_lia[i] = 0; /* clear modem */ -if (mux_ldsc[i].conn && /* connected? */ - ((muxu_unit.flags & UNIT_DIAG) == 0)) /* term mode? */ - muxc_lia[i] = muxc_lia[i] | DSR | /* cdet, dsr */ - (muxl_unit[i].flags & UNIT_MDM? CDET: 0); -sim_cancel (&muxl_unit[i]); -return; -} - - -/* Reset routine for lower data, upper data, and control cards */ - -t_stat muxc_reset (DEVICE *dptr) -{ -int32 i; -DIB *dibptr = (DIB *) dptr->ctxt; /* DIB pointer */ - -if (dptr == &muxc_dev) { /* make all consistent */ - hp_enbdis_pair (dptr, &muxl_dev); - hp_enbdis_pair (dptr, &muxu_dev); - } -else if (dptr == &muxl_dev) { - hp_enbdis_pair (dptr, &muxc_dev); - hp_enbdis_pair (dptr, &muxu_dev); - } -else { - hp_enbdis_pair (dptr, &muxc_dev); - hp_enbdis_pair (dptr, &muxl_dev); - } - -IOPRESET (dibptr); /* PRESET device (does not use PON) */ - -muxc_chan = muxc_scan = 0; /* init modem scan */ - -if (muxu_unit.flags & UNIT_ATT) { /* master att? */ - muxu_unit.wait = POLL_FIRST; /* set up poll */ - sim_activate (&muxu_unit, muxu_unit.wait); /* start Telnet poll immediately */ - } -else - sim_cancel (&muxu_unit); /* else stop */ - -for (i = 0; i < MUX_LINES; i++) - mux_reset_ln (i); /* reset lines 0-15 */ - -for (i = MUX_LINES; i < (MUX_LINES + MUX_ILINES); i++) /* reset lines 16-20 */ - mux_rbuf[i] = mux_rpar[i] = mux_sta[i] = mux_rchp[i] = 0; - -return SCPE_OK; -} - - -/* Attach master unit */ - -t_stat mux_attach (UNIT *uptr, char *cptr) -{ -t_stat status = SCPE_OK; - -if (muxu_unit.flags & UNIT_DIAG) /* diag mode? */ - return SCPE_NOFNC; /* command not allowed */ - -status = tmxr_attach (&mux_desc, uptr, cptr); /* attach */ - -if (status == SCPE_OK) { - muxu_unit.wait = POLL_FIRST; /* set up poll */ - sim_activate (&muxu_unit, muxu_unit.wait); /* start Telnet poll immediately */ - } - -return status; -} - - -/* Detach master unit */ - -t_stat mux_detach (UNIT *uptr) -{ -int32 i; -t_stat r; - -r = tmxr_detach (&mux_desc, uptr); /* detach */ -for (i = 0; i < MUX_LINES; i++) mux_ldsc[i].rcve = 0; /* disable rcv */ -sim_cancel (uptr); /* stop poll */ -return r; -} - - -/* Diagnostic/normal mode routine, - - Diagnostic testing wants to exercise as much of the regular simulation code - as possible to ensure good test coverage. Normally, input polling and output - transmission only occurs on connected lines. In diagnostic mode, line - connection flags are set selectively to enable processing on the lines under - test. The alternative to this would require duplicating the send/receive - code; the diagnostic would then test the copy but not the actual code used - for normal character transfers, which is undesirable. - - Therefore, to enable diagnostic mode, we must force a disconnect of the - master socket and any connected Telnet lines, which clears the connection - flags on all lines. Then we set the "transmission enabled" flags on all - lines to enable output character processing for the diagnostic. (Normally, - all of the flags are set when the multiplexer is first attached. Until then, - the enable flags default to "not enabled," so we enable them explicitly - here.) -*/ - -t_stat mux_setdiag (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -int32 ln; - -if (val) { /* set diag? */ - mux_detach (uptr); /* detach lines */ - for (ln = 0; ln < MUX_LINES; ln++) /* enable transmission */ - mux_ldsc[ln].xmte = 1; /* on all lines */ - } -else { /* set term */ - for (ln = 0; ln < MUX_LINES; ln++) /* clear connections */ - mux_ldsc[ln].conn = 0; /* on all lines */ - } -return SCPE_OK; -} +/* hp2100_mux.c: HP 2100 12920A terminal multiplexor simulator + + Copyright (c) 2002-2014, Robert M Supnik + + 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 + ROBERT M SUPNIK 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 Robert M Supnik shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + + MUX,MUXL,MUXM 12920A terminal multiplexor + + 24-Dec-14 JDB Added casts for explicit downward conversions + 10-Jan-13 MP Added DEV_MUX and additional DEVICE field values + 10-Feb-12 JDB Deprecated DEVNO in favor of SC + Removed DEV_NET to allow restoration of listening port + 28-Mar-11 JDB Tidied up signal handling + 26-Oct-10 JDB Changed I/O signal handler for revised signal model + 25-Nov-08 JDB Revised for new multiplexer library SHOW routines + 09-Oct-08 JDB "muxl_unit" defined one too many units (17 instead of 16) + 10-Sep-08 JDB SHOW MUX CONN/STAT with SET MUX DIAG is no longer disallowed + 07-Sep-08 JDB Changed Telnet poll to connect immediately after reset or attach + 27-Aug-08 JDB Added LINEORDER support + 12-Aug-08 JDB Added BREAK deferral to allow RTE break-mode to work + 26-Jun-08 JDB Rewrote device I/O to model backplane signals + 16-Apr-08 JDB Sync mux poll with console poll for idle compatibility + 06-Mar-07 JDB Corrected "mux_sta" size from 16 to 21 elements + Fixed "muxc_reset" to clear lines 16-20 + 26-Feb-07 JDB Added debug printouts + Fixed control card OTx to set current channel number + Fixed to set "muxl_ibuf" in response to a transmit interrupt + Changed "mux_xbuf", "mux_rbuf" declarations from 8 to 16 bits + Fixed to set "mux_rchp" when a line break is received + Fixed incorrect "odd_par" table values + Reversed test in "RCV_PAR" to return "LIL_PAR" on odd parity + Fixed mux reset (ioCRS) to clear port parameters + Fixed to use PUT_DCH instead of PUT_CCH for data channel status + 10-Feb-07 JDB Added DIAG/TERM modifiers to implement diagnostic mode + 28-Dec-06 JDB Added ioCRS state to I/O decoders + 02-Jun-06 JDB Fixed compiler warning for mux_ldsc init + 22-Nov-05 RMS Revised for new terminal processing routines + 29-Jun-05 RMS Added SET MUXLn DISCONNECT + 07-Oct-04 JDB Allow enable/disable from any device + 26-Apr-04 RMS Fixed SFS x,C and SFC x,C + Implemented DMA SRQ (follows FLG) + 05-Jan-04 RMS Revised for tmxr library changes + 21-Dec-03 RMS Added invalid character screening for TSB (from Mike Gemeny) + 09-May-03 RMS Added network device flag + 01-Nov-02 RMS Added 7B/8B support + 22-Aug-02 RMS Updated for changes to sim_tmxr + + Reference: + - 12920A Asynchronous Multiplexer Interface Kits Operating and Service Manual + (12920-90001, Oct-1972) + + + The 12920A was a 16-channel asynchronous terminal multiplexer. It supported + direct-connected terminals as well as modems at speeds up to 2400 baud. It + was the primary terminal multiplexer for the HP 2000 series of Time-Shared + BASIC systems. + + The multiplexer was implemented as a three-card set consisting of a lower + data card, an upper data card, and a modem control card. Under simulation, + these are implemented by three devices: + + MUXL lower data card (lines) + MUX upper data card (scanner) + MUXM control card (modem control) + + The lower and upper data cards must be in adjacent I/O slots. The control + card may be placed in any slot, although in practice it was placed in the + slot above the upper data card, so that all three cards were physically + together. + + The 12920A supported one or two control cards (two cards were used with + 801-type automatic dialers). Under simulation, only one control card is + supported. + + Implementation notes: + + 1. If a BREAK is detected during an input poll, and we are not in diagnostic + mode, we defer recognition until either a character is output or a second + successive input poll occurs. This is necessary for RTE break-mode + operation. Without this deferral, a BREAK during output would be ignored + by the RTE driver, making it impossible to stop a long listing. + + The problem is due to timing differences between simulated and real time. + The RTE multiplexer driver is a privileged driver. Privileged drivers + bypass RTE to provide rapid interrupt handling. To inform RTE that an + operation is complete, e.g., that a line has been written, the interrupt + section of the driver sets a device timeout of one clock tick (10 + milliseconds). When that timeout occurs, RTE is entered normally to + complete the I/O transaction. While the completion timeout is pending, + the driver ignores any further interrupts from the multiplexer line. + + The maximum communication rate for the multiplexer is 2400 baud, or + approximately 4.2 milliseconds per character transferred. A typical line + of 20 characters would therefore take ~85 milliseconds, plus the 10 + millisecond completion timeout, or about 95 milliseconds total. BREAK + recognition would be ignored for roughly 10% of that time. At lower baud + rates, recognition would be ignored for a correspondingly smaller + percentage of the time. + + However, SIMH uses an optimized timing of 500 instructions per character + transfer, rather than the ~6600 instructions that a character transfer + should take, and so a typical 20-character line will take about 11,000 + instructions. On the other hand, the clock tick is calibrated to real + time, and 10 milliseconds of real time takes about 420,000 instructions + on a 2.0 GHz PC. To be recognized, then, the BREAK key must be pressed + in a window that is open for about 2.5% of the time. Therefore, the + BREAK key will be ignored about 97.5% of the time, and RTE break-mode + effectively will not work. + + Deferring BREAK recognition until the next character is output ensures + that the BREAK interrupt will be accepted (the simulator delivers input + interrupts before output interrupts, so the BREAK interrupt arrives + before the output character transmit interrupt). If an output operation + is not in progress, then the BREAK will be recognized at the next input + poll. +*/ + + +#include + +#include "hp2100_defs.h" +#include "sim_tmxr.h" + + +/* Unit references */ + +#define MUX_LINES 16 /* number of user lines */ +#define MUX_ILINES 5 /* number of diag rcv only lines */ + + +/* Service times */ + +#define MUXL_WAIT 500 + + +/* Unit flags */ + +#define UNIT_V_MDM (TTUF_V_UF + 0) /* modem control */ +#define UNIT_V_DIAG (TTUF_V_UF + 1) /* loopback diagnostic */ +#define UNIT_MDM (1 << UNIT_V_MDM) +#define UNIT_DIAG (1 << UNIT_V_DIAG) + +/* Debug flags */ + +#define DEB_CMDS (1 << 0) /* Command initiation and completion */ +#define DEB_CPU (1 << 1) /* CPU I/O */ +#define DEB_XFER (1 << 2) /* Socket receive and transmit */ + +/* Channel number (OTA upper, LIA lower or upper) */ + +#define MUX_V_CHAN 10 /* channel num */ +#define MUX_M_CHAN 037 +#define MUX_CHAN(x) (((x) >> MUX_V_CHAN) & MUX_M_CHAN) + +/* OTA, lower = parameters or data */ + +#define OTL_P 0100000 /* parameter */ +#define OTL_TX 0040000 /* transmit */ +#define OTL_ENB 0020000 /* enable */ +#define OTL_TPAR 0010000 /* xmt parity */ +#define OTL_ECHO 0010000 /* rcv echo */ +#define OTL_DIAG 0004000 /* diagnose */ +#define OTL_SYNC 0004000 /* sync */ +#define OTL_V_LNT 8 /* char length */ +#define OTL_M_LNT 07 +#define OTL_LNT(x) (((x) >> OTL_V_LNT) & OTL_M_LNT) +#define OTL_V_BAUD 0 /* baud rate */ +#define OTL_M_BAUD 0377 +#define OTL_BAUD(x) (((x) >> OTL_V_BAUD) & OTL_M_BAUD) +#define OTL_CHAR 03777 /* char mask */ +#define OTL_PAR 0200 /* char parity */ + +/* LIA, lower = received data */ + +#define LIL_PAR 0100000 /* parity */ +#define PUT_DCH(x) (((x) & MUX_M_CHAN) << MUX_V_CHAN) +#define LIL_CHAR 01777 /* character */ + +/* LIA, upper = status */ + +#define LIU_SEEK 0100000 /* seeking NI */ +#define LIU_DG 0000010 /* diagnose */ +#define LIU_BRK 0000004 /* break */ +#define LIU_LOST 0000002 /* char lost */ +#define LIU_TR 0000001 /* trans/rcv */ + +/* OTA, control */ + +#define OTC_SCAN 0100000 /* scan */ +#define OTC_UPD 0040000 /* update */ +#define OTC_V_CHAN 10 /* channel */ +#define OTC_M_CHAN 017 +#define OTC_CHAN(x) (((x) >> OTC_V_CHAN) & OTC_M_CHAN) +#define OTC_EC2 0000200 /* enable Cn upd */ +#define OTC_EC1 0000100 +#define OTC_C2 0000040 /* Cn flops */ +#define OTC_C1 0000020 +#define OTC_V_C 4 /* S1 to C1 */ +#define OTC_ES2 0000010 /* enb comparison */ +#define OTC_ES1 0000004 +#define OTC_V_ES 2 +#define OTC_SS2 0000002 /* SSn flops */ +#define OTC_SS1 0000001 +#define OTC_RW (OTC_ES2|OTC_ES1|OTC_SS2|OTC_SS1) +#define RTS OCT_C2 /* C2 = rts */ +#define DTR OTC_C1 /* C1 = dtr */ + +/* LIA, control */ + +#define LIC_MBO 0140000 /* always set */ +#define LIC_V_CHAN 10 /* channel */ +#define LIC_M_CHAN 017 +#define PUT_CCH(x) (((x) & OTC_M_CHAN) << OTC_V_CHAN) +#define LIC_I2 0001000 /* change flags */ +#define LIC_I1 0000400 +#define LIC_S2 0000002 /* Sn flops */ +#define LIC_S1 0000001 +#define LIC_V_I 8 /* S1 to I1 */ +#define CDET LIC_S2 /* S2 = cdet */ +#define DSR LIC_S1 /* S1 = dsr */ + +#define LIC_TSTI(ch) (((muxc_lia[ch] ^ muxc_ota[ch]) & \ + ((muxc_ota[ch] & (OTC_ES2|OTC_ES1)) >> OTC_V_ES)) \ + << LIC_V_I) + + +/* Program constants */ + +static const uint8 odd_par [256] = { + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 000-017 */ + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, /* 020-037 */ + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, /* 040-067 */ + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 060-077 */ + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, /* 100-117 */ + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 120-137 */ + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 140-157 */ + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, /* 160-177 */ + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, /* 200-217 */ + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 220-237 */ + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 240-267 */ + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, /* 260-277 */ + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 300-317 */ + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, /* 320-337 */ + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, /* 340-357 */ + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1 /* 360-377 */ + }; + +#define RCV_PAR(x) (odd_par[(x) & 0377] ? 0 : LIL_PAR) +#define XMT_PAR(x) (odd_par[(x) & 0377] ? 0 : OTL_PAR) + + +/* Multiplexer controller state variables */ + +struct { + FLIP_FLOP control; /* control flip-flop */ + FLIP_FLOP flag; /* flag flip-flop */ + FLIP_FLOP flagbuf; /* flag buffer flip-flop */ + } muxl = { CLEAR, CLEAR, CLEAR }; + +uint32 muxl_ibuf = 0; /* low in: rcv data */ +uint32 muxl_obuf = 0; /* low out: param */ + +uint32 muxu_ibuf = 0; /* upr in: status */ +uint32 muxu_obuf = 0; /* upr out: chan */ + +struct { + FLIP_FLOP control; /* control flip-flop */ + FLIP_FLOP flag; /* flag flip-flop */ + FLIP_FLOP flagbuf; /* flag buffer flip-flop */ + } muxc = { CLEAR, CLEAR, CLEAR }; + +uint32 muxc_chan = 0; /* ctrl chan */ +uint32 muxc_scan = 0; /* ctrl scan */ + + +/* Multiplexer per-line state variables */ + +uint16 mux_sta [MUX_LINES + MUX_ILINES]; /* line status */ +uint16 mux_rpar [MUX_LINES + MUX_ILINES]; /* rcv param */ +uint16 mux_xpar [MUX_LINES]; /* xmt param */ +uint8 mux_rchp [MUX_LINES + MUX_ILINES]; /* rcv chr pend */ +uint8 mux_xdon [MUX_LINES]; /* xmt done */ +uint8 muxc_ota [MUX_LINES]; /* ctrl: Cn,ESn,SSn */ +uint8 muxc_lia [MUX_LINES]; /* ctrl: Sn */ +uint8 mux_defer [MUX_LINES]; /* break deferred flags */ + + +/* Multiplexer per-line buffer variables */ + +uint16 mux_rbuf[MUX_LINES + MUX_ILINES]; /* rcv buf */ +uint16 mux_xbuf[MUX_LINES]; /* xmt buf */ + + +/* Multiplexer local routines */ + +void mux_receive (int32 ln, int32 c, t_bool diag); +void mux_data_int (void); +void mux_ctrl_int (void); +void mux_diag (int32 c); + + +/* Multiplexer global routines */ + +IOHANDLER muxlio; +IOHANDLER muxuio; +IOHANDLER muxcio; + +t_stat muxi_svc (UNIT *uptr); +t_stat muxo_svc (UNIT *uptr); +t_stat muxc_reset (DEVICE *dptr); +t_stat mux_attach (UNIT *uptr, char *cptr); +t_stat mux_detach (UNIT *uptr); +t_stat mux_setdiag (UNIT *uptr, int32 val, char *cptr, void *desc); + + +/* MUXL/MUXU device information block. + + The DIBs of adjacent cards must be contained in an array, so they are defined + here and referenced in the lower and upper card device structures. +*/ + +DIB mux_dib[] = { + { &muxlio, MUXL }, + { &muxuio, MUXU } + }; + +#define muxl_dib mux_dib[0] +#define muxu_dib mux_dib[1] + + +/* MUXL data structures. + + muxl_dib MUXL device information block + muxl_unit MUXL unit list + muxl_reg MUXL register list + muxl_mod MUXL modifier list + muxl_dev MUXL device descriptor +*/ + +TMXR mux_desc; + +DEVICE muxl_dev; + +UNIT muxl_unit[] = { + { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT } + }; + +REG muxl_reg[] = { + { FLDATA (CTL, muxl.control, 0) }, + { FLDATA (FLG, muxl.flag, 0) }, + { FLDATA (FBF, muxl.flagbuf, 0) }, + { BRDATA (STA, mux_sta, 8, 16, MUX_LINES + MUX_ILINES) }, + { BRDATA (RPAR, mux_rpar, 8, 16, MUX_LINES + MUX_ILINES) }, + { BRDATA (XPAR, mux_xpar, 8, 16, MUX_LINES) }, + { BRDATA (RBUF, mux_rbuf, 8, 16, MUX_LINES + MUX_ILINES) }, + { BRDATA (XBUF, mux_xbuf, 8, 16, MUX_LINES) }, + { BRDATA (RCHP, mux_rchp, 8, 1, MUX_LINES + MUX_ILINES) }, + { BRDATA (XDON, mux_xdon, 8, 1, MUX_LINES) }, + { BRDATA (BDFR, mux_defer, 8, 1, MUX_LINES) }, + { URDATA (TIME, muxl_unit[0].wait, 10, 24, 0, + MUX_LINES, REG_NZ + PV_LEFT) }, + { ORDATA (SC, muxl_dib.select_code, 6), REG_HRO }, + { ORDATA (DEVNO, muxl_dib.select_code, 6), REG_HRO }, + { NULL } + }; + +MTAB muxl_mod[] = { + { TT_MODE, TT_MODE_UC, "UC", "UC", NULL, NULL, NULL }, + { TT_MODE, TT_MODE_7B, "7b", "7B", NULL, NULL, NULL }, + { TT_MODE, TT_MODE_8B, "8b", "8B", NULL, NULL, NULL }, + { TT_MODE, TT_MODE_7P, "7p", "7P", NULL, NULL, NULL }, + + { UNIT_MDM, UNIT_MDM, "dataset", "DATASET", NULL, NULL, NULL }, + { UNIT_MDM, 0, "no dataset", "NODATASET", NULL, NULL, NULL }, + + { MTAB_XTD | MTAB_VUN | MTAB_NC, 0, "LOG", "LOG", &tmxr_set_log, &tmxr_show_log, &mux_desc }, + { MTAB_XTD | MTAB_VUN | MTAB_NC, 0, NULL, "NOLOG", &tmxr_set_nolog, NULL, &mux_desc }, + + { MTAB_XTD | MTAB_VUN, 0, NULL, "DISCONNECT", &tmxr_dscln, NULL, &mux_desc }, + { MTAB_XTD | MTAB_VDV, 1, "SC", "SC", &hp_setsc, &hp_showsc, &muxl_dev }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &muxl_dev }, + + { 0 } + }; + +DEVICE muxl_dev = { + "MUXL", /* device name */ + muxl_unit, /* unit array */ + muxl_reg, /* register array */ + muxl_mod, /* modifier array */ + MUX_LINES, /* number of units */ + 10, /* address radix */ + 31, /* address width */ + 1, /* address increment */ + 8, /* data radix */ + 8, /* data width */ + NULL, /* examine routine */ + NULL, /* deposit routine */ + &muxc_reset, /* reset routine */ + NULL, /* boot routine */ + NULL, /* attach routine */ + NULL, /* detach routine */ + &muxl_dib, /* device information block */ + DEV_DISABLE, /* device flags */ + 0, /* debug control flags */ + NULL, /* debug flag name table */ + NULL, /* memory size change routine */ + NULL, /* logical device name */ + NULL, /* help routine */ + NULL, /* help attach routine*/ + NULL /* help context */ + }; + + +/* MUXU data structures + + mux_order MUX line connection order table + mux_ldsc MUX terminal multiplexer line descriptors + mux_desc MUX terminal multiplexer device descriptor + + muxu_dib MUXU device information block + muxu_unit MUXU unit list + muxu_reg MUXU register list + muxu_mod MUXU modifier list + muxu_deb MUXU debug list + muxu_dev MUXU device descriptor +*/ + +DEVICE muxu_dev; + +int32 mux_order [MUX_LINES] = { -1 }; /* connection order */ +TMLN mux_ldsc [MUX_LINES] = { { 0 } }; /* line descriptors */ +TMXR mux_desc = { MUX_LINES, 0, 0, mux_ldsc, mux_order }; /* device descriptor */ + +UNIT muxu_unit = { UDATA (&muxi_svc, UNIT_ATTABLE, 0), POLL_FIRST }; + +REG muxu_reg[] = { + { ORDATA (IBUF, muxu_ibuf, 16) }, + { ORDATA (OBUF, muxu_obuf, 16) }, + { ORDATA (SC, muxu_dib.select_code, 6), REG_HRO }, + { ORDATA (DEVNO, muxu_dib.select_code, 6), REG_HRO }, + { NULL } + }; + +MTAB muxu_mod[] = { + { UNIT_DIAG, UNIT_DIAG, "diagnostic mode", "DIAG", &mux_setdiag, NULL, NULL }, + { UNIT_DIAG, 0, "terminal mode", "TERM", &mux_setdiag, NULL, NULL }, + { UNIT_ATT, UNIT_ATT, "", NULL, NULL, &tmxr_show_summ, &mux_desc }, + + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "LINEORDER", "LINEORDER", &tmxr_set_lnorder, &tmxr_show_lnorder, &mux_desc }, + + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "CONNECTIONS", NULL, NULL, &tmxr_show_cstat, &mux_desc }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "STATISTICS", NULL, NULL, &tmxr_show_cstat, &mux_desc }, + { MTAB_XTD | MTAB_VDV, 1, NULL, "DISCONNECT", &tmxr_dscln, NULL, &mux_desc }, + { MTAB_XTD | MTAB_VDV, 1, "SC", "SC", &hp_setsc, &hp_showsc, &muxl_dev }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &muxl_dev }, + + { 0 } + }; + +DEBTAB muxu_deb [] = { + { "CMDS", DEB_CMDS }, + { "CPU", DEB_CPU }, + { "XFER", DEB_XFER }, + { NULL, 0 } + }; + +DEVICE muxu_dev = { + "MUX", /* device name */ + &muxu_unit, /* unit array */ + muxu_reg, /* register array */ + muxu_mod, /* modifier array */ + 1, /* number of units */ + 10, /* address radix */ + 31, /* address width */ + 1, /* address increment */ + 8, /* data radix */ + 8, /* data width */ + &tmxr_ex, /* examine routine */ + &tmxr_dep, /* deposit routine */ + &muxc_reset, /* reset routine */ + NULL, /* boot routine */ + &mux_attach, /* attach routine */ + &mux_detach, /* detach routine */ + &muxu_dib, /* device information block */ + DEV_DISABLE | DEV_DEBUG | DEV_MUX, /* device flags */ + 0, /* debug control flags */ + muxu_deb, /* debug flag name table */ + NULL, /* memory size change routine */ + NULL, /* logical device name */ + NULL, /* help routine */ + NULL, /* help attach routine*/ + (void *) &mux_desc /* help context */ + }; + + +/* MUXC data structures. + + muxc_dib MUXC device information block + muxc_unit MUXC unit list + muxc_reg MUXC register list + muxc_mod MUXC modifier list + muxc_dev MUXC device descriptor +*/ + +DEVICE muxc_dev; + +DIB muxc_dib = { &muxcio, MUXC }; + +UNIT muxc_unit = { UDATA (NULL, 0, 0) }; + +REG muxc_reg[] = { + { FLDATA (CTL, muxc.control, 0) }, + { FLDATA (FLG, muxc.flag, 0) }, + { FLDATA (FBF, muxc.flagbuf, 0) }, + { FLDATA (SCAN, muxc_scan, 0) }, + { ORDATA (CHAN, muxc_chan, 4) }, + { BRDATA (DSO, muxc_ota, 8, 6, MUX_LINES) }, + { BRDATA (DSI, muxc_lia, 8, 2, MUX_LINES) }, + { ORDATA (SC, muxc_dib.select_code, 6), REG_HRO }, + { ORDATA (DEVNO, muxc_dib.select_code, 6), REG_HRO }, + { NULL } + }; + +MTAB muxc_mod[] = { + { MTAB_XTD | MTAB_VDV, 0, "SC", "SC", &hp_setsc, &hp_showsc, &muxc_dev }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &muxc_dev }, + { 0 } + }; + +DEVICE muxc_dev = { + "MUXM", /* device name */ + &muxc_unit, /* unit array */ + muxc_reg, /* register array */ + muxc_mod, /* modifier array */ + 1, /* number of units */ + 10, /* address radix */ + 31, /* address width */ + 1, /* address increment */ + 8, /* data radix */ + 8, /* data width */ + NULL, /* examine routine */ + NULL, /* deposit routine */ + &muxc_reset, /* reset routine */ + NULL, /* boot routine */ + NULL, /* attach routine */ + NULL, /* detach routine */ + &muxc_dib, /* device information block */ + DEV_DISABLE, /* device flags */ + 0, /* debug control flags */ + NULL, /* debug flag name table */ + NULL, /* memory size change routine */ + NULL, /* logical device name */ + NULL, /* help routine */ + NULL, /* help attach routine*/ + NULL /* help context */ + }; + + +/* Lower data card I/O signal handler. + + Implementation notes: + + 1. The operating manual says that "at least 100 milliseconds of CLC 0s must + be programmed" by systems employing the multiplexer to ensure that the + multiplexer resets. In practice, such systems issue 128K CLC 0 + instructions. As we provide debug logging of multiplexer resets, a CRS + counter is used to ensure that only one debug line is printed in response + to these 128K CRS invocations. +*/ + +uint32 muxlio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) +{ +int32 ln; +const char *hold_or_clear = (signal_set & ioCLF ? ",C" : ""); +static uint32 crs_count = 0; /* cntr for ioCRS repeat */ +IOSIGNAL signal; +IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ + +if (crs_count && !(signal_set & ioCRS)) { /* counting CRSes and not present? */ + if (DEBUG_PRI (muxu_dev, DEB_CMDS)) /* report reset count */ + fprintf (sim_deb, ">>MUXl cmds: [CRS] Multiplexer reset %d times\n", + crs_count); + + crs_count = 0; /* clear counter */ + } + +while (working_set) { + signal = IONEXT (working_set); /* isolate next signal */ + + switch (signal) { /* dispatch I/O signal */ + + case ioCLF: /* clear flag flip-flop */ + muxl.flag = muxl.flagbuf = CLEAR; + + if (DEBUG_PRI (muxu_dev, DEB_CMDS)) + fputs (">>MUXl cmds: [CLF] Flag cleared\n", sim_deb); + + mux_data_int (); /* look for new int */ + break; + + + case ioSTF: /* set flag flip-flop */ + case ioENF: /* enable flag */ + muxl.flag = muxl.flagbuf = SET; + + if (DEBUG_PRI (muxu_dev, DEB_CMDS)) + fputs (">>MUXl cmds: [STF] Flag set\n", sim_deb); + break; + + + case ioSFC: /* skip if flag is clear */ + setstdSKF (muxl); + break; + + + case ioSFS: /* skip if flag is set */ + setstdSKF (muxl); + break; + + + case ioIOI: /* I/O data input */ + stat_data = IORETURN (SCPE_OK, muxl_ibuf); /* merge in return status */ + + if (DEBUG_PRI (muxu_dev, DEB_CPU)) + fprintf (sim_deb, ">>MUXl cpu: [LIx%s] Data = %06o\n", hold_or_clear, muxl_ibuf); + break; + + + case ioIOO: /* I/O data output */ + muxl_obuf = IODATA (stat_data); /* store data */ + + if (DEBUG_PRI (muxu_dev, DEB_CPU)) + if (muxl_obuf & OTL_P) + fprintf (sim_deb, ">>MUXl cpu: [OTx%s] Parameter = %06o\n", hold_or_clear, muxl_obuf); + else + fprintf (sim_deb, ">>MUXl cpu: [OTx%s] Data = %06o\n", hold_or_clear, muxl_obuf); + break; + + + case ioPOPIO: /* power-on preset to I/O */ + muxl.flag = muxl.flagbuf = SET; /* set flag andflag buffer */ + break; + + + case ioCRS: /* control reset */ + if (crs_count == 0) { /* first reset? */ + muxl.control = CLEAR; /* clear control flip-flop */ + + for (ln = 0; ln < MUX_LINES; ln++) { /* clear transmit info */ + mux_xbuf[ln] = mux_xpar[ln] = 0; + muxc_ota[ln] = muxc_lia[ln] = mux_xdon[ln] = 0; + } + + for (ln = 0; ln < (MUX_LINES + MUX_ILINES); ln++) { + mux_rbuf[ln] = mux_rpar[ln] = 0; /* clear receive info */ + mux_sta[ln] = mux_rchp[ln] = 0; + } + } + + crs_count = crs_count + 1; /* increment count */ + break; + + + case ioCLC: /* clear control flip-flop */ + muxl.control = CLEAR; + + if (DEBUG_PRI (muxu_dev, DEB_CMDS)) + fprintf (sim_deb, ">>MUXl cmds: [CLC%s] Data interrupt inhibited\n", hold_or_clear); + break; + + + case ioSTC: /* set control flip-flop */ + muxl.control = SET; /* set control */ + + ln = MUX_CHAN (muxu_obuf); /* get chan # */ + + if (muxl_obuf & OTL_TX) { /* transmit? */ + if (ln < MUX_LINES) { /* line valid? */ + if (muxl_obuf & OTL_P) { /* parameter? */ + mux_xpar[ln] = (uint16) muxl_obuf; /* store param value */ + if (DEBUG_PRI (muxu_dev, DEB_CMDS)) + fprintf (sim_deb, + ">>MUXl cmds: [STC%s] Transmit channel %d parameter %06o stored\n", + hold_or_clear, ln, muxl_obuf); + } + + else { /* data */ + if (mux_xpar[ln] & OTL_TPAR) /* parity requested? */ + muxl_obuf = /* add parity bit */ + muxl_obuf & ~OTL_PAR | + XMT_PAR(muxl_obuf); + mux_xbuf[ln] = (uint16) muxl_obuf; /* load buffer */ + + if (sim_is_active (&muxl_unit[ln])) { /* still working? */ + mux_sta[ln] = mux_sta[ln] | LIU_LOST; /* char lost */ + if (DEBUG_PRI (muxu_dev, DEB_CMDS)) + fprintf (sim_deb, ">>MUXl cmds: [STC%s] Transmit channel %d data overrun\n", + hold_or_clear, ln); + } + else { + if (muxu_unit.flags & UNIT_DIAG) /* loopback? */ + mux_ldsc[ln].conn = 1; /* connect this line */ + sim_activate (&muxl_unit[ln], muxl_unit[ln].wait); + if (DEBUG_PRI (muxu_dev, DEB_CMDS)) + fprintf (sim_deb, ">>MUXl cmds: [STC%s] Transmit channel %d data %06o scheduled\n", + hold_or_clear, ln, muxl_obuf); + } + } + } + else if (DEBUG_PRI (muxu_dev, DEB_CMDS)) /* line invalid */ + fprintf (sim_deb, ">>MUXl cmds: [STC%s] Transmit channel %d invalid\n", hold_or_clear, ln); + } + + else /* receive */ + if (ln < (MUX_LINES + MUX_ILINES)) { /* line valid? */ + if (muxl_obuf & OTL_P) { /* parameter? */ + mux_rpar[ln] = (uint16) muxl_obuf; /* store param value */ + if (DEBUG_PRI (muxu_dev, DEB_CMDS)) + fprintf (sim_deb, + ">>MUXl cmds: [STC%s] Receive channel %d parameter %06o stored\n", + hold_or_clear, ln, muxl_obuf); + } + + else if (DEBUG_PRI (muxu_dev, DEB_CMDS)) /* data (invalid action) */ + fprintf (sim_deb, + ">>MUXl cmds: [STC%s] Receive channel %d parameter %06o invalid action\n", + hold_or_clear, ln, muxl_obuf); + } + + else if (DEBUG_PRI (muxu_dev, DEB_CMDS)) /* line invalid */ + fprintf (sim_deb, ">>MUXl cmds: [STC%s] Receive channel %d invalid\n", hold_or_clear, ln); + break; + + + case ioSIR: /* set interrupt request */ + setstdPRL (muxl); /* set standard PRL signal */ + setstdIRQ (muxl); /* set standard IRQ signal */ + setstdSRQ (muxl); /* set standard SRQ signal */ + break; + + + case ioIAK: /* interrupt acknowledge */ + muxl.flagbuf = CLEAR; + break; + + + default: /* all other signals */ + break; /* are ignored */ + } + + working_set = working_set & ~signal; /* remove current signal from set */ + } + +return stat_data; +} + + +/* Upper data card I/O signal handler. + + The upper data card does not have a control, flag, or flag buffer flip-flop. + It does not drive the IRQ or SRQ lines, so the I/O dispatcher does not handle + the ioSIR signal. + + Implementation notes: + + 1. The upper and lower data card hardware takes a number of actions in + response to the CRS signal. Under simulation, these actions are taken by + the lower data card CRS handler. +*/ + +uint32 muxuio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) +{ +IOSIGNAL signal; +IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ + +while (working_set) { + signal = IONEXT (working_set); /* isolate next signal */ + + switch (signal) { /* dispatch I/O signal */ + + case ioIOI: /* I/O data input */ + stat_data = IORETURN (SCPE_OK, muxu_ibuf); /* merge in return status */ + + if (DEBUG_PRI (muxu_dev, DEB_CPU)) + fprintf (sim_deb, ">>MUXu cpu: [LIx] Status = %06o, channel = %d\n", + muxu_ibuf, MUX_CHAN(muxu_ibuf)); + break; + + + case ioIOO: /* I/O data output */ + muxu_obuf = IODATA (stat_data); /* store data */ + + if (DEBUG_PRI (muxu_dev, DEB_CPU)) + fprintf (sim_deb, ">>MUXu cpu: [OTx] Data channel = %d\n", MUX_CHAN(muxu_obuf)); + break; + + + default: /* all other signals */ + break; /* are ignored */ + } + + working_set = working_set & ~signal; /* remove current signal from set */ + } + +return stat_data; +} + + +/* Control card I/O signal handler. + + In diagnostic mode, the control signals C1 and C2 are looped back to status + signals S1 and S2. Changing the control signals may cause an interrupt, so a + test is performed after IOO processing. +*/ + +uint32 muxcio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) +{ +const char *hold_or_clear = (signal_set & ioCLF ? ",C" : ""); +uint16 data; +int32 ln, old; +IOSIGNAL signal; +IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ + +while (working_set) { + signal = IONEXT (working_set); /* isolate next signal */ + + switch (signal) { /* dispatch I/O signal */ + + case ioCLF: /* clear flag flip-flop */ + muxc.flag = muxc.flagbuf = CLEAR; + + if (DEBUG_PRI (muxu_dev, DEB_CMDS)) + fputs (">>MUXc cmds: [CLF] Flag cleared\n", sim_deb); + + mux_ctrl_int (); /* look for new int */ + break; + + + case ioSTF: /* set flag flip-flop */ + case ioENF: /* enable flag */ + muxc.flag = muxc.flagbuf = SET; + + if (DEBUG_PRI (muxu_dev, DEB_CMDS)) + fputs (">>MUXc cmds: [STF] Flag set\n", sim_deb); + break; + + + case ioSFC: /* skip if flag is clear */ + setstdSKF (muxc); + break; + + + case ioSFS: /* skip if flag is set */ + setstdSKF (muxc); + break; + + + case ioIOI: /* I/O data input */ + data = (uint16) (LIC_MBO | PUT_CCH (muxc_chan) | /* mbo, chan num */ + LIC_TSTI (muxc_chan) | /* I2, I1 */ + (muxc_ota[muxc_chan] & (OTC_ES2 | OTC_ES1)) | /* ES2, ES1 */ + (muxc_lia[muxc_chan] & (LIC_S2 | LIC_S1))); /* S2, S1 */ + + if (DEBUG_PRI (muxu_dev, DEB_CPU)) + fprintf (sim_deb, ">>MUXc cpu: [LIx%s] Status = %06o, channel = %d\n", + hold_or_clear, data, muxc_chan); + + muxc_chan = (muxc_chan + 1) & LIC_M_CHAN; /* incr channel */ + stat_data = IORETURN (SCPE_OK, data); /* merge in return status */ + break; + + + case ioIOO: /* I/O data output */ + data = IODATA (stat_data); /* clear supplied status */ + ln = muxc_chan = OTC_CHAN (data); /* set channel */ + + if (data & OTC_SCAN) muxc_scan = 1; /* set scan flag */ + else muxc_scan = 0; + + if (data & OTC_UPD) { /* update? */ + old = muxc_ota[ln]; /* save prior val */ + muxc_ota[ln] = /* save ESn,SSn */ + (muxc_ota[ln] & ~OTC_RW) | (data & OTC_RW); + + if (data & OTC_EC2) /* if EC2, upd C2 */ + muxc_ota[ln] = + (muxc_ota[ln] & ~OTC_C2) | (data & OTC_C2); + + if (data & OTC_EC1) /* if EC1, upd C1 */ + muxc_ota[ln] = + (muxc_ota[ln] & ~OTC_C1) | (data & OTC_C1); + + if (muxu_unit.flags & UNIT_DIAG) /* loopback? */ + muxc_lia[ln ^ 1] = /* set S1, S2 to C1, C2 */ + (muxc_lia[ln ^ 1] & ~(LIC_S2 | LIC_S1)) | + (muxc_ota[ln] & (OTC_C1 | OTC_C2)) >> OTC_V_C; + + else if ((muxl_unit[ln].flags & UNIT_MDM) && /* modem ctrl? */ + (old & DTR) && /* DTR drop? */ + !(muxc_ota[ln] & DTR)) { + tmxr_linemsg (&mux_ldsc[ln], "\r\nLine hangup\r\n"); + tmxr_reset_ln (&mux_ldsc[ln]); /* reset line */ + muxc_lia[ln] = 0; /* dataset off */ + } + } /* end update */ + + if (DEBUG_PRI (muxu_dev, DEB_CPU)) + fprintf (sim_deb, ">>MUXc cpu: [OTx%s] Parameter = %06o, channel = %d\n", + hold_or_clear, data, ln); + + if ((muxu_unit.flags & UNIT_DIAG) && (!muxc.flag)) /* loopback and flag clear? */ + mux_ctrl_int (); /* status chg may interrupt */ + break; + + + case ioPOPIO: /* power-on preset to I/O */ + muxc.flag = muxc.flagbuf = SET; /* set flag and flag buffer */ + break; + + + case ioCRS: /* control reset */ + case ioCLC: /* clear control flip-flop */ + muxc.control = CLEAR; + break; + + + case ioSTC: /* set control flip-flop */ + muxc.control = SET; + break; + + + case ioSIR: /* set interrupt request */ + setstdPRL (muxc); /* set standard PRL signal */ + setstdIRQ (muxc); /* set standard IRQ signal */ + setstdSRQ (muxc); /* set standard SRQ signal */ + break; + + + case ioIAK: /* interrupt acknowledge */ + muxc.flagbuf = CLEAR; + break; + + + default: /* all other signals */ + break; /* are ignored */ + } + + working_set = working_set & ~signal; /* remove current signal from set */ + } + +return stat_data; +} + + +/* Unit service - receive side + + Poll for new connections + Poll all active lines for input +*/ + +t_stat muxi_svc (UNIT *uptr) +{ +int32 ln, c; +t_bool loopback; + +loopback = ((muxu_unit.flags & UNIT_DIAG) != 0); /* diagnostic mode? */ + +if (!loopback) { /* terminal mode? */ + if (uptr->wait == POLL_FIRST) /* first poll? */ + uptr->wait = sync_poll (INITIAL); /* initial synchronization */ + else /* not first */ + uptr->wait = sync_poll (SERVICE); /* continue synchronization */ + + sim_activate (uptr, uptr->wait); /* continue polling */ + + ln = tmxr_poll_conn (&mux_desc); /* look for connect */ + + if (ln >= 0) { /* got one? */ + if ((muxl_unit[ln].flags & UNIT_MDM) && /* modem ctrl? */ + (muxc_ota[ln] & DTR)) /* DTR? */ + muxc_lia[ln] = muxc_lia[ln] | CDET; /* set cdet */ + muxc_lia[ln] = muxc_lia[ln] | DSR; /* set dsr */ + mux_ldsc[ln].rcve = 1; /* rcv enabled */ + } + tmxr_poll_rx (&mux_desc); /* poll for input */ + } + +for (ln = 0; ln < MUX_LINES; ln++) { /* loop thru lines */ + if (mux_ldsc[ln].conn) { /* connected? */ + if (loopback) { /* diagnostic mode? */ + c = mux_xbuf[ln ^ 1] & OTL_CHAR; /* get char from xmit line */ + if (c == 0) /* all char bits = 0? */ + c = c | SCPE_BREAK; /* set break flag */ + mux_ldsc[ln].conn = 0; /* clear connection */ + } + + else if (mux_defer[ln]) /* break deferred? */ + c = SCPE_BREAK; /* supply it now */ + + else + c = tmxr_getc_ln (&mux_ldsc[ln]); /* get char from Telnet */ + + if (c) /* valid char? */ + mux_receive (ln, c, loopback); /* process it */ + } + + else /* not connected */ + if (!loopback) /* terminal mode? */ + muxc_lia[ln] = 0; /* line disconnected */ + } + +if (!muxl.flag) mux_data_int (); /* scan for data int */ +if (!muxc.flag) mux_ctrl_int (); /* scan modem */ +return SCPE_OK; +} + + +/* Unit service - transmit side */ + +t_stat muxo_svc (UNIT *uptr) +{ +int32 c, fc, ln, altln; +t_bool loopback; + +ln = uptr - muxl_unit; /* line # */ +altln = ln ^ 1; /* alt. line for diag mode */ + +fc = mux_xbuf[ln] & OTL_CHAR; /* full character data */ +c = fc & 0377; /* Telnet character data */ + +loopback = ((muxu_unit.flags & UNIT_DIAG) != 0); /* diagnostic mode? */ + +if (mux_ldsc[ln].conn) { /* connected? */ + if (mux_ldsc[ln].xmte) { /* xmt enabled? */ + if (loopback) /* diagnostic mode? */ + mux_ldsc[ln].conn = 0; /* clear connection */ + + else if (mux_defer[ln]) /* break deferred? */ + mux_receive (ln, SCPE_BREAK, loopback); /* process it now */ + + if ((mux_xbuf[ln] & OTL_SYNC) == 0) { /* start bit 0? */ + TMLN *lp = &mux_ldsc[ln]; /* get line */ + c = sim_tt_outcvt (c, TT_GET_MODE (muxl_unit[ln].flags)); + + if (mux_xpar[ln] & OTL_DIAG) /* xmt diagnose? */ + mux_diag (fc); /* before munge */ + + if (loopback) { /* diagnostic mode? */ + mux_ldsc[altln].conn = 1; /* set recv connection */ + sim_activate (&muxu_unit, 1); /* schedule receive */ + } + + else { /* no loopback */ + if (c >= 0) /* valid? */ + tmxr_putc_ln (lp, c); /* output char */ + tmxr_poll_tx (&mux_desc); /* poll xmt */ + } + } + + mux_xdon[ln] = 1; /* set for xmit irq */ + + if (DEBUG_PRI (muxu_dev, DEB_XFER) && (loopback | (c >= 0))) + fprintf (sim_deb, ">>MUXl xfer: Line %d character %s sent\n", + ln, fmt_char ((uint8) (loopback ? fc : c))); + } + + else { /* buf full */ + tmxr_poll_tx (&mux_desc); /* poll xmt */ + sim_activate (uptr, muxl_unit[ln].wait); /* wait */ + return SCPE_OK; + } + } + +if (!muxl.flag) mux_data_int (); /* scan for int */ +return SCPE_OK; +} + + +/* Process a character received from a multiplexer port */ + +void mux_receive (int32 ln, int32 c, t_bool diag) +{ +if (c & SCPE_BREAK) { /* break? */ + if (mux_defer[ln] || diag) { /* break deferred or diagnostic mode? */ + mux_defer[ln] = 0; /* process now */ + mux_rbuf[ln] = 0; /* break returns NUL */ + mux_sta[ln] = mux_sta[ln] | LIU_BRK; /* set break status */ + + if (DEBUG_PRI (muxu_dev, DEB_XFER)) + if (diag) + fputs (">>MUXl xfer: Break detected\n", sim_deb); + else + fputs (">>MUXl xfer: Deferred break processed\n", sim_deb); + } + + else { + mux_defer[ln] = 1; /* defer break */ + + if (DEBUG_PRI (muxu_dev, DEB_XFER)) + fputs (">>MUXl xfer: Break detected and deferred\n", sim_deb); + + return; + } + } +else { /* normal */ + if (mux_rchp[ln]) /* char already pending? */ + mux_sta[ln] = mux_sta[ln] | LIU_LOST; + + if (!diag) { /* terminal mode? */ + c = sim_tt_inpcvt (c, TT_GET_MODE (muxl_unit[ln].flags)); + if (mux_rpar[ln] & OTL_ECHO) { /* echo? */ + TMLN *lp = &mux_ldsc[ln]; /* get line */ + tmxr_putc_ln (lp, c); /* output char */ + tmxr_poll_tx (&mux_desc); /* poll xmt */ + } + } + mux_rbuf[ln] = (uint16) c; /* save char */ + } + +mux_rchp[ln] = 1; /* char pending */ + +if (DEBUG_PRI (muxu_dev, DEB_XFER)) + fprintf (sim_deb, ">>MUXl xfer: Line %d character %s received\n", + ln, fmt_char ((uint8) c)); + +if (mux_rpar[ln] & OTL_DIAG) /* diagnose this line? */ + mux_diag (c); /* do diagnosis */ + +return; +} + + +/* Look for data interrupt */ + +void mux_data_int (void) +{ +int32 i; + +for (i = 0; i < MUX_LINES; i++) { /* rcv lines */ + if ((mux_rpar[i] & OTL_ENB) && mux_rchp[i]) { /* enabled, char? */ + muxl_ibuf = PUT_DCH (i) | /* lo buf = char */ + mux_rbuf[i] & LIL_CHAR | + RCV_PAR (mux_rbuf[i]); + muxu_ibuf = PUT_DCH (i) | mux_sta[i]; /* hi buf = stat */ + mux_rchp[i] = 0; /* clr char, stat */ + mux_sta[i] = 0; + + if (DEBUG_PRI (muxu_dev, DEB_CMDS)) + fprintf (sim_deb, ">>MUXl cmds: Receive channel %d interrupt requested\n", i); + + muxlio (&muxl_dib, ioENF, 0); /* interrupt */ + return; + } + } +for (i = 0; i < MUX_LINES; i++) { /* xmt lines */ + if ((mux_xpar[i] & OTL_ENB) && mux_xdon[i]) { /* enabled, done? */ + muxl_ibuf = PUT_DCH (i) | /* lo buf = last rcv char */ + mux_rbuf[i] & LIL_CHAR | + RCV_PAR (mux_rbuf[i]); + muxu_ibuf = PUT_DCH (i) | mux_sta[i] | LIU_TR; /* hi buf = stat */ + mux_xdon[i] = 0; /* clr done, stat */ + mux_sta[i] = 0; + + if (DEBUG_PRI (muxu_dev, DEB_CMDS)) + fprintf (sim_deb, ">>MUXl cmds: Transmit channel %d interrupt requested\n", i); + + muxlio (&muxl_dib, ioENF, 0); /* interrupt */ + return; + } + } +for (i = MUX_LINES; i < (MUX_LINES + MUX_ILINES); i++) { /* diag lines */ + if ((mux_rpar[i] & OTL_ENB) && mux_rchp[i]) { /* enabled, char? */ + muxl_ibuf = PUT_DCH (i) | /* lo buf = char */ + mux_rbuf[i] & LIL_CHAR | + RCV_PAR (mux_rbuf[i]); + muxu_ibuf = PUT_DCH (i) | mux_sta[i] | LIU_DG; /* hi buf = stat */ + mux_rchp[i] = 0; /* clr char, stat */ + mux_sta[i] = 0; + + if (DEBUG_PRI (muxu_dev, DEB_CMDS)) + fprintf (sim_deb, ">>MUXl cmds: Receive channel %d interrupt requested\n", i); + + muxlio (&muxl_dib, ioENF, 0); /* interrupt */ + return; + } + } +return; +} + + +/* Look for control interrupt + + If either of the incoming status bits does not match the stored status, and + the corresponding mismatch is enabled, a control interrupt request is + generated. Depending on the scan flag, we check either all 16 lines or just + the current line. If an interrupt is requested, the channel counter + indicates the interrupting channel. +*/ + +void mux_ctrl_int (void) +{ +int32 i, line_count; + +line_count = (muxc_scan ? MUX_LINES : 1); /* check one or all lines */ + +for (i = 0; i < line_count; i++) { + if (muxc_scan) /* scanning? */ + muxc_chan = (muxc_chan + 1) & LIC_M_CHAN; /* step channel */ + if (LIC_TSTI (muxc_chan)) { /* status change? */ + + if (DEBUG_PRI (muxu_dev, DEB_CMDS)) + fprintf (sim_deb, + ">>MUXc cmds: Control channel %d interrupt requested (poll = %d)\n", + muxc_chan, i + 1); + + muxcio (&muxc_dib, ioENF, 0); /* set flag */ + break; + } + } +return; +} + + +/* Set diagnostic lines for given character */ + +void mux_diag (int32 c) +{ +int32 i; + +for (i = MUX_LINES; i < (MUX_LINES + MUX_ILINES); i++) { + if (c & SCPE_BREAK) { /* break? */ + mux_sta[i] = mux_sta[i] | LIU_BRK; + mux_rbuf[i] = 0; /* no char */ + } + else { + if (mux_rchp[i]) mux_sta[i] = mux_sta[i] | LIU_LOST; + mux_rchp[i] = 1; + mux_rbuf[i] = (uint16) c; + } + } +return; +} + + +/* Reset an individual line */ + +static void mux_reset_ln (int32 i) +{ +mux_rbuf[i] = mux_xbuf[i] = 0; /* clear state */ +mux_rpar[i] = mux_xpar[i] = 0; +mux_rchp[i] = mux_xdon[i] = 0; +mux_sta[i] = mux_defer[i] = 0; +muxc_ota[i] = muxc_lia[i] = 0; /* clear modem */ +if (mux_ldsc[i].conn && /* connected? */ + ((muxu_unit.flags & UNIT_DIAG) == 0)) /* term mode? */ + muxc_lia[i] = muxc_lia[i] | DSR | /* cdet, dsr */ + (muxl_unit[i].flags & UNIT_MDM? CDET: 0); +sim_cancel (&muxl_unit[i]); +return; +} + + +/* Reset routine for lower data, upper data, and control cards */ + +t_stat muxc_reset (DEVICE *dptr) +{ +int32 i; +DIB *dibptr = (DIB *) dptr->ctxt; /* DIB pointer */ + +if (dptr == &muxc_dev) { /* make all consistent */ + hp_enbdis_pair (dptr, &muxl_dev); + hp_enbdis_pair (dptr, &muxu_dev); + } +else if (dptr == &muxl_dev) { + hp_enbdis_pair (dptr, &muxc_dev); + hp_enbdis_pair (dptr, &muxu_dev); + } +else { + hp_enbdis_pair (dptr, &muxc_dev); + hp_enbdis_pair (dptr, &muxl_dev); + } + +IOPRESET (dibptr); /* PRESET device (does not use PON) */ + +muxc_chan = muxc_scan = 0; /* init modem scan */ + +if (muxu_unit.flags & UNIT_ATT) { /* master att? */ + muxu_unit.wait = POLL_FIRST; /* set up poll */ + sim_activate (&muxu_unit, muxu_unit.wait); /* start Telnet poll immediately */ + } +else + sim_cancel (&muxu_unit); /* else stop */ + +for (i = 0; i < MUX_LINES; i++) + mux_reset_ln (i); /* reset lines 0-15 */ + +for (i = MUX_LINES; i < (MUX_LINES + MUX_ILINES); i++) /* reset lines 16-20 */ + mux_rbuf[i] = mux_rpar[i] = mux_sta[i] = mux_rchp[i] = 0; + +return SCPE_OK; +} + + +/* Attach master unit */ + +t_stat mux_attach (UNIT *uptr, char *cptr) +{ +t_stat status = SCPE_OK; + +if (muxu_unit.flags & UNIT_DIAG) /* diag mode? */ + return SCPE_NOFNC; /* command not allowed */ + +status = tmxr_attach (&mux_desc, uptr, cptr); /* attach */ + +if (status == SCPE_OK) { + muxu_unit.wait = POLL_FIRST; /* set up poll */ + sim_activate (&muxu_unit, muxu_unit.wait); /* start Telnet poll immediately */ + } + +return status; +} + + +/* Detach master unit */ + +t_stat mux_detach (UNIT *uptr) +{ +int32 i; +t_stat r; + +r = tmxr_detach (&mux_desc, uptr); /* detach */ +for (i = 0; i < MUX_LINES; i++) mux_ldsc[i].rcve = 0; /* disable rcv */ +sim_cancel (uptr); /* stop poll */ +return r; +} + + +/* Diagnostic/normal mode routine, + + Diagnostic testing wants to exercise as much of the regular simulation code + as possible to ensure good test coverage. Normally, input polling and output + transmission only occurs on connected lines. In diagnostic mode, line + connection flags are set selectively to enable processing on the lines under + test. The alternative to this would require duplicating the send/receive + code; the diagnostic would then test the copy but not the actual code used + for normal character transfers, which is undesirable. + + Therefore, to enable diagnostic mode, we must force a disconnect of the + master socket and any connected Telnet lines, which clears the connection + flags on all lines. Then we set the "transmission enabled" flags on all + lines to enable output character processing for the diagnostic. (Normally, + all of the flags are set when the multiplexer is first attached. Until then, + the enable flags default to "not enabled," so we enable them explicitly + here.) +*/ + +t_stat mux_setdiag (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +int32 ln; + +if (val) { /* set diag? */ + mux_detach (uptr); /* detach lines */ + for (ln = 0; ln < MUX_LINES; ln++) /* enable transmission */ + mux_ldsc[ln].xmte = 1; /* on all lines */ + } +else { /* set term */ + for (ln = 0; ln < MUX_LINES; ln++) /* clear connections */ + mux_ldsc[ln].conn = 0; /* on all lines */ + } +return SCPE_OK; +} diff --git a/HP2100/hp2100_stddev.c b/HP2100/hp2100_stddev.c index 92208b00..dbd8cb41 100644 --- a/HP2100/hp2100_stddev.c +++ b/HP2100/hp2100_stddev.c @@ -1,1207 +1,1218 @@ -/* hp2100_stddev.c: HP2100 standard devices simulator - - Copyright (c) 1993-2012, Robert M. Supnik - - 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 - ROBERT M SUPNIK 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 Robert M Supnik shall not be - used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from Robert M Supnik. - - PTR 12597A-002 paper tape reader interface - PTP 12597A-005 paper tape punch interface - TTY 12531C buffered teleprinter interface - CLK 12539C time base generator - - 12-Feb-12 JDB Add TBG as a logical name for the CLK device - 10-Feb-12 JDB Deprecated DEVNO in favor of SC - 28-Mar-11 JDB Tidied up signal handling - 26-Oct-10 JDB Changed I/O signal handler for revised signal model - 26-Jun-08 JDB Rewrote device I/O to model backplane signals - 25-Apr-08 JDB Changed TTY output wait from 100 to 200 for MSU BASIC - 18-Apr-08 JDB Removed redundant control char handling definitions - 14-Apr-08 JDB Changed TTY console poll to 10 msec. real time - Synchronized CLK with TTY if set for 10 msec. - Added UNIT_IDLE to TTY and CLK - 09-Jan-08 JDB Fixed PTR trailing null counter for tape re-read - 31-Dec-07 JDB Added IPTICK register to CLK to display CPU instr/tick - Corrected and verified ioCRS actions - 28-Dec-06 JDB Added ioCRS state to I/O decoders - 22-Nov-05 RMS Revised for new terminal processing routines - 13-Sep-04 JDB Added paper tape loop mode, DIAG/READER modifiers to PTR - Added PV_LEFT to PTR TRLLIM register - Modified CLK to permit disable - 15-Aug-04 RMS Added tab to control char set (from Dave Bryan) - 14-Jul-04 RMS Generalized handling of control char echoing - (from Dave Bryan) - 26-Apr-04 RMS Fixed SFS x,C and SFC x,C - Fixed SR setting in IBL - Fixed input behavior during typeout for RTE-IV - Suppressed nulls on TTY output for RTE-IV - Implemented DMA SRQ (follows FLG) - 29-Mar-03 RMS Added support for console backpressure - 25-Apr-03 RMS Added extended file support - 22-Dec-02 RMS Added break support - 01-Nov-02 RMS Revised BOOT command for IBL ROMs - Fixed bug in TTY reset, TTY starts in input mode - Fixed bug in TTY mode OTA, stores data as well - Fixed clock to add calibration, proper start/stop - Added UC option to TTY output - 30-May-02 RMS Widened POS to 32b - 22-Mar-02 RMS Revised for dynamically allocated memory - 03-Nov-01 RMS Changed DEVNO to use extended SET/SHOW - 29-Nov-01 RMS Added read only unit support - 24-Nov-01 RMS Changed TIME to an array - 07-Sep-01 RMS Moved function prototypes - 21-Nov-00 RMS Fixed flag, buffer power up state - Added status input for ptp, tty - 15-Oct-00 RMS Added dynamic device number support - - References: - - 2748B Tape Reader Operating and Service Manual (02748-90041, Oct-1977) - - 12597A 8-Bit Duplex Register Interface Kit Operating and Service Manual - (12597-9002, Sep-1974) - - 12531C Buffered Teleprinter Interface Kit Operating and Service Manual - (12531-90033, Nov-1972) - - 12539C Time Base Generator Interface Kit Operating and Service Manual - (12539-90008, Jan-1975) - - - The reader and punch, like most HP devices, have a command flop. The - teleprinter and clock do not. - - Reader diagnostic mode simulates a tape loop by rewinding the tape image file - upon EOF. Normal mode EOF action is to supply TRLLIM nulls and then either - return SCPE_IOERR or SCPE_OK without setting the device flag. - - To support CPU idling, the teleprinter interface (which doubles as the - simulator console) polls for input using a calibrated timer with a ten - millisecond period. Other polled-keyboard input devices (multiplexers and - the BACI card) synchronize with the console poll to ensure maximum available - idle time. The console poll is guaranteed to run, as the TTY device cannot - be disabled. - - The clock (time base generator) autocalibrates. If the CLK is set to a ten - millisecond period (e.g., as under RTE), it is synchronized to the console - poll. Otherwise (e.g., as under DOS or TSB, which use 100 millisecond - periods), it runs asynchronously. If the specified clock frequency is below - 10Hz, the clock service routine runs at 10Hz and counts down a repeat counter - before generating an interrupt. Autocalibration will not work if the clock - is running at 1Hz or less. - - Clock diagnostic mode corresponds to inserting jumper W2 on the 12539C. - This turns off autocalibration and divides the longest time intervals down - by 10**3. The clk_time values were chosen to allow the diagnostic to - pass its clock calibration test. -*/ - -#include "hp2100_defs.h" - -#define TTY_OUT_WAIT 200 /* TTY output wait */ - -#define UNIT_V_DIAG (TTUF_V_UF + 0) /* diag mode */ -#define UNIT_V_AUTOLF (TTUF_V_UF + 1) /* auto linefeed */ -#define UNIT_DIAG (1 << UNIT_V_DIAG) -#define UNIT_AUTOLF (1 << UNIT_V_AUTOLF) - -#define PTP_LOW 0000040 /* low tape */ -#define TM_MODE 0100000 /* mode change */ -#define TM_KBD 0040000 /* enable keyboard */ -#define TM_PRI 0020000 /* enable printer */ -#define TM_PUN 0010000 /* enable punch */ -#define TP_BUSY 0100000 /* busy */ - -#define CLK_V_ERROR 4 /* clock overrun */ -#define CLK_ERROR (1 << CLK_V_ERROR) - -struct { - FLIP_FLOP control; /* control flip-flop */ - FLIP_FLOP flag; /* flag flip-flop */ - FLIP_FLOP flagbuf; /* flag buffer flip-flop */ - } ptr = { CLEAR, CLEAR, CLEAR }; - -int32 ptr_stopioe = 0; /* stop on error */ -int32 ptr_trlcnt = 0; /* trailer counter */ -int32 ptr_trllim = 40; /* trailer to add */ - -struct { - FLIP_FLOP control; /* control flip-flop */ - FLIP_FLOP flag; /* flag flip-flop */ - FLIP_FLOP flagbuf; /* flag buffer flip-flop */ - } ptp = { CLEAR, CLEAR, CLEAR }; - -int32 ptp_stopioe = 0; - -struct { - FLIP_FLOP control; /* control flip-flop */ - FLIP_FLOP flag; /* flag flip-flop */ - FLIP_FLOP flagbuf; /* flag buffer flip-flop */ - } tty = { CLEAR, CLEAR, CLEAR }; - -int32 ttp_stopioe = 0; -int32 tty_buf = 0; /* tty buffer */ -int32 tty_mode = 0; /* tty mode */ -int32 tty_shin = 0377; /* tty shift in */ -int32 tty_lf = 0; /* lf flag */ - -struct { - FLIP_FLOP control; /* control flip-flop */ - FLIP_FLOP flag; /* flag flip-flop */ - FLIP_FLOP flagbuf; /* flag buffer flip-flop */ - } clk = { CLEAR, CLEAR, CLEAR }; - -int32 clk_select = 0; /* clock time select */ -int32 clk_error = 0; /* clock error */ -int32 clk_ctr = 0; /* clock counter */ -int32 clk_time[8] = { /* clock intervals */ - 155, 1550, 15500, 155000, 155000, 155000, 155000, 155000 - }; -int32 clk_tps[8] = { /* clock tps */ - 10000, 1000, 100, 10, 10, 10, 10, 10 - }; -int32 clk_rpt[8] = { /* number of repeats */ - 1, 1, 1, 1, 10, 100, 1000, 10000 - }; -uint32 clk_tick = 0; /* instructions per tick */ - -DEVICE ptr_dev, ptp_dev, tty_dev, clk_dev; - -IOHANDLER ptrio; -t_stat ptr_svc (UNIT *uptr); -t_stat ptr_attach (UNIT *uptr, char *cptr); -t_stat ptr_reset (DEVICE *dptr); -t_stat ptr_boot (int32 unitno, DEVICE *dptr); - -IOHANDLER ptpio; -t_stat ptp_svc (UNIT *uptr); -t_stat ptp_reset (DEVICE *dptr); - -IOHANDLER ttyio; -t_stat tti_svc (UNIT *uptr); -t_stat tto_svc (UNIT *uptr); -t_stat tty_reset (DEVICE *dptr); -t_stat tty_set_opt (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat tty_set_alf (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat tto_out (int32 c); -t_stat ttp_out (int32 c); - -IOHANDLER clkio; -t_stat clk_svc (UNIT *uptr); -t_stat clk_reset (DEVICE *dptr); -int32 clk_delay (int32 flg); - -/* PTR data structures - - ptr_dev PTR device descriptor - ptr_unit PTR unit descriptor - ptr_mod PTR modifiers - ptr_reg PTR register list -*/ - -DIB ptr_dib = { &ptrio, PTR }; - -UNIT ptr_unit = { - UDATA (&ptr_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE, 0), - SERIAL_IN_WAIT - }; - -REG ptr_reg[] = { - { ORDATA (BUF, ptr_unit.buf, 8) }, - { FLDATA (CTL, ptr.control, 0) }, - { FLDATA (FLG, ptr.flag, 0) }, - { FLDATA (FBF, ptr.flagbuf, 0) }, - { DRDATA (TRLCTR, ptr_trlcnt, 8), REG_HRO }, - { DRDATA (TRLLIM, ptr_trllim, 8), PV_LEFT }, - { DRDATA (POS, ptr_unit.pos, T_ADDR_W), PV_LEFT }, - { DRDATA (TIME, ptr_unit.wait, 24), PV_LEFT }, - { FLDATA (STOP_IOE, ptr_stopioe, 0) }, - { ORDATA (SC, ptr_dib.select_code, 6), REG_HRO }, - { ORDATA (DEVNO, ptr_dib.select_code, 6), REG_HRO }, - { NULL } - }; - -MTAB ptr_mod[] = { - { UNIT_DIAG, UNIT_DIAG, "diagnostic mode", "DIAG", NULL }, - { UNIT_DIAG, 0, "reader mode", "READER", NULL }, - { MTAB_XTD | MTAB_VDV, 0, "SC", "SC", &hp_setsc, &hp_showsc, &ptr_dev }, - { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &ptr_dev }, - { 0 } - }; - -DEVICE ptr_dev = { - "PTR", &ptr_unit, ptr_reg, ptr_mod, - 1, 10, 31, 1, 8, 8, - NULL, NULL, &ptr_reset, - &ptr_boot, &ptr_attach, NULL, - &ptr_dib, DEV_DISABLE - }; - -/* PTP data structures - - ptp_dev PTP device descriptor - ptp_unit PTP unit descriptor - ptp_mod PTP modifiers - ptp_reg PTP register list -*/ - -DIB ptp_dib = { &ptpio, PTP }; - -UNIT ptp_unit = { - UDATA (&ptp_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT - }; - -REG ptp_reg[] = { - { ORDATA (BUF, ptp_unit.buf, 8) }, - { FLDATA (CTL, ptp.control, 0) }, - { FLDATA (FLG, ptp.flag, 0) }, - { FLDATA (FBF, ptp.flagbuf, 0) }, - { DRDATA (POS, ptp_unit.pos, T_ADDR_W), PV_LEFT }, - { DRDATA (TIME, ptp_unit.wait, 24), PV_LEFT }, - { FLDATA (STOP_IOE, ptp_stopioe, 0) }, - { ORDATA (SC, ptp_dib.select_code, 6), REG_HRO }, - { ORDATA (DEVNO, ptp_dib.select_code, 6), REG_HRO }, - { NULL } - }; - -MTAB ptp_mod[] = { - { MTAB_XTD | MTAB_VDV, 0, "SC", "SC", &hp_setsc, &hp_showsc, &ptp_dev }, - { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &ptp_dev }, - { 0 } - }; - -DEVICE ptp_dev = { - "PTP", &ptp_unit, ptp_reg, ptp_mod, - 1, 10, 31, 1, 8, 8, - NULL, NULL, &ptp_reset, - NULL, NULL, NULL, - &ptp_dib, DEV_DISABLE - }; - -/* TTY data structures - - tty_dev TTY device descriptor - tty_unit TTY unit descriptor - tty_reg TTY register list - tty_mod TTy modifiers list -*/ - -#define TTI 0 -#define TTO 1 -#define TTP 2 - -DIB tty_dib = { &ttyio, TTY }; - -UNIT tty_unit[] = { - { UDATA (&tti_svc, UNIT_IDLE | TT_MODE_UC, 0), POLL_WAIT }, - { UDATA (&tto_svc, TT_MODE_UC, 0), TTY_OUT_WAIT }, - { UDATA (&tto_svc, UNIT_SEQ | UNIT_ATTABLE | TT_MODE_8B, 0), SERIAL_OUT_WAIT } - }; - -REG tty_reg[] = { - { ORDATA (BUF, tty_buf, 8) }, - { ORDATA (MODE, tty_mode, 16) }, - { ORDATA (SHIN, tty_shin, 8), REG_HRO }, - { FLDATA (CTL, tty.control, 0) }, - { FLDATA (FLG, tty.flag, 0) }, - { FLDATA (FBF, tty.flagbuf, 0) }, - { FLDATA (KLFP, tty_lf, 0), REG_HRO }, - { DRDATA (KPOS, tty_unit[TTI].pos, T_ADDR_W), PV_LEFT }, - { DRDATA (KTIME, tty_unit[TTI].wait, 24), REG_NZ + PV_LEFT }, - { DRDATA (TPOS, tty_unit[TTO].pos, T_ADDR_W), PV_LEFT }, - { DRDATA (TTIME, tty_unit[TTO].wait, 24), REG_NZ + PV_LEFT }, - { DRDATA (PPOS, tty_unit[TTP].pos, T_ADDR_W), PV_LEFT }, - { FLDATA (STOP_IOE, ttp_stopioe, 0) }, - { ORDATA (SC, tty_dib.select_code, 6), REG_HRO }, - { ORDATA (DEVNO, tty_dib.select_code, 6), REG_HRO }, - { NULL } - }; - -MTAB tty_mod[] = { - { TT_MODE, TT_MODE_UC, "UC", "UC", &tty_set_opt }, - { TT_MODE, TT_MODE_7B, "7b", "7B", &tty_set_opt }, - { TT_MODE, TT_MODE_8B, "8b", "8B", &tty_set_opt }, - { TT_MODE, TT_MODE_7P, "7p", "7P", &tty_set_opt }, - { UNIT_AUTOLF, UNIT_AUTOLF, "autolf", "AUTOLF", &tty_set_alf }, - { UNIT_AUTOLF, 0 , NULL, "NOAUTOLF", &tty_set_alf }, - { MTAB_XTD | MTAB_VDV, 0, "SC", "SC", &hp_setsc, &hp_showsc, &tty_dev }, - { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &tty_dev }, - { 0 } - }; - -DEVICE tty_dev = { - "TTY", tty_unit, tty_reg, tty_mod, - 3, 10, 31, 1, 8, 8, - NULL, NULL, &tty_reset, - NULL, NULL, NULL, - &tty_dib, 0 - }; - -/* CLK data structures - - clk_dev CLK device descriptor - clk_unit CLK unit descriptor - clk_mod CLK modifiers - clk_reg CLK register list -*/ - -DIB clk_dib = { &clkio, CLK }; - -UNIT clk_unit = { UDATA (&clk_svc, UNIT_IDLE, 0) }; - -REG clk_reg[] = { - { ORDATA (SEL, clk_select, 3) }, - { DRDATA (CTR, clk_ctr, 14) }, - { FLDATA (CTL, clk.control, 0) }, - { FLDATA (FLG, clk.flag, 0) }, - { FLDATA (FBF, clk.flagbuf, 0) }, - { FLDATA (ERR, clk_error, CLK_V_ERROR) }, - { BRDATA (TIME, clk_time, 10, 24, 8) }, - { DRDATA (IPTICK, clk_tick, 24), PV_RSPC | REG_RO }, - { ORDATA (SC, clk_dib.select_code, 6), REG_HRO }, - { ORDATA (DEVNO, clk_dib.select_code, 6), REG_HRO }, - { NULL } - }; - -MTAB clk_mod[] = { - { UNIT_DIAG, UNIT_DIAG, "diagnostic mode", "DIAG", NULL }, - { UNIT_DIAG, 0, "calibrated", "CALIBRATED", NULL }, - { MTAB_XTD | MTAB_VDV, 0, "SC", "SC", &hp_setsc, &hp_showsc, &clk_dev }, - { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &clk_dev }, - { 0 } - }; - -DEVICE clk_dev = { - "CLK", &clk_unit, clk_reg, clk_mod, - 1, 0, 0, 0, 0, 0, - NULL, NULL, &clk_reset, - NULL, NULL, NULL, - &clk_dib, DEV_DISABLE, - 0, NULL, NULL, "TBG" - }; - - -/* Paper tape reader I/O signal handler. - - Implementation notes: - - 1. The 12597A duplex register card is used to interface the paper tape - reader to the computer. This card has a device command flip-flop, which - supplies the READ signal to the tape reader. Under simulation, this - state is implied by the activation of the PTR unit. - - 2. The POPIO signal clears the output buffer of the duplex card. However, - the buffer outputs are not used by the paper tape reader. Under - simulation, we omit the buffer clear. -*/ - -uint32 ptrio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) -{ -IOSIGNAL signal; -IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ - -while (working_set) { - signal = IONEXT (working_set); /* isolate next signal */ - - switch (signal) { /* dispatch I/O signal */ - - case ioCLF: /* clear flag flip-flop */ - ptr.flag = ptr.flagbuf = CLEAR; - break; - - - case ioSTF: /* set flag flip-flop */ - case ioENF: /* enable flag */ - ptr.flag = ptr.flagbuf = SET; - break; - - - case ioSFC: /* skip if flag is clear */ - setstdSKF (ptr); - break; - - - case ioSFS: /* skip if flag is set */ - setstdSKF (ptr); - break; - - - case ioIOI: /* I/O data input */ - stat_data = IORETURN (SCPE_OK, ptr_unit.buf); /* merge in return status */ - break; - - - case ioPOPIO: /* power-on preset to I/O */ - ptr.flag = ptr.flagbuf = SET; /* set flag and flag buffer */ - break; - - - case ioCRS: /* control reset */ - case ioCLC: /* clear control flip-flop */ - ptr.control = CLEAR; - break; - - - case ioSTC: /* set control flip-flop */ - ptr.control = SET; - sim_activate (&ptr_unit, ptr_unit.wait); - break; - - - case ioSIR: /* set interrupt request */ - setstdPRL (ptr); /* set standard PRL signal */ - setstdIRQ (ptr); /* set standard IRQ signal */ - setstdSRQ (ptr); /* set standard SRQ signal */ - break; - - - case ioIAK: /* interrupt acknowledge */ - ptr.flagbuf = CLEAR; - break; - - - default: /* all other signals */ - break; /* are ignored */ - } - - working_set = working_set & ~signal; /* remove current signal from set */ - } - -return stat_data; -} - - -/* Unit service */ - -t_stat ptr_svc (UNIT *uptr) -{ -int32 temp; - -if ((ptr_unit.flags & UNIT_ATT) == 0) /* attached? */ - return IOERROR (ptr_stopioe, SCPE_UNATT); -while ((temp = getc (ptr_unit.fileref)) == EOF) { /* read byte, error? */ - if (feof (ptr_unit.fileref)) { /* end of file? */ - if ((ptr_unit.flags & UNIT_DIAG) && (ptr_unit.pos > 0)) { - rewind (ptr_unit.fileref); /* rewind if loop mode */ - ptr_unit.pos = 0; - } - else { - if (ptr_trlcnt >= ptr_trllim) { /* added all trailer? */ - if (ptr_stopioe) { /* stop on error? */ - printf ("PTR end of file\n"); - return SCPE_IOERR; - } - else return SCPE_OK; /* no, just hang */ - } - ptr_trlcnt++; /* count trailer */ - temp = 0; /* read a zero */ - break; - } - } - else { /* no, real error */ - perror ("PTR I/O error"); - clearerr (ptr_unit.fileref); - return SCPE_IOERR; - } - } - -ptrio (&ptr_dib, ioENF, 0); /* set flag */ - -ptr_unit.buf = temp & 0377; /* put byte in buf */ -ptr_unit.pos = ftell (ptr_unit.fileref); - -if (temp) /* character non-null? */ - ptr_trlcnt = 0; /* clear trailing null counter */ - -return SCPE_OK; -} - - -/* Attach routine - clear the trailer counter */ - -t_stat ptr_attach (UNIT *uptr, char *cptr) -{ -ptr_trlcnt = 0; -return attach_unit (uptr, cptr); -} - - -/* Reset routine - called from SCP */ - -t_stat ptr_reset (DEVICE *dptr) -{ -IOPRESET (&ptr_dib); /* PRESET device (does not use PON) */ -sim_cancel (&ptr_unit); /* deactivate unit */ -return SCPE_OK; -} - - -/* Paper tape reader bootstrap routine (HP 12992K ROM) */ - -const BOOT_ROM ptr_rom = { - 0107700, /*ST CLC 0,C ; intr off */ - 0002401, /* CLA,RSS ; skip in */ - 0063756, /*CN LDA M11 ; feed frame */ - 0006700, /* CLB,CCE ; set E to rd byte */ - 0017742, /* JSB READ ; get #char */ - 0007306, /* CMB,CCE,INB,SZB ; 2's comp */ - 0027713, /* JMP *+5 ; non-zero byte */ - 0002006, /* INA,SZA ; feed frame ctr */ - 0027703, /* JMP *-3 */ - 0102077, /* HLT 77B ; stop */ - 0027700, /* JMP ST ; next */ - 0077754, /* STA WC ; word in rec */ - 0017742, /* JSB READ ; get feed frame */ - 0017742, /* JSB READ ; get address */ - 0074000, /* STB 0 ; init csum */ - 0077755, /* STB AD ; save addr */ - 0067755, /*CK LDB AD ; check addr */ - 0047777, /* ADB MAXAD ; below loader */ - 0002040, /* SEZ ; E =0 => OK */ - 0027740, /* JMP H55 */ - 0017742, /* JSB READ ; get word */ - 0040001, /* ADA 1 ; cont checksum */ - 0177755, /* STA AD,I ; store word */ - 0037755, /* ISZ AD */ - 0000040, /* CLE ; force wd read */ - 0037754, /* ISZ WC ; block done? */ - 0027720, /* JMP CK ; no */ - 0017742, /* JSB READ ; get checksum */ - 0054000, /* CPB 0 ; ok? */ - 0027702, /* JMP CN ; next block */ - 0102011, /* HLT 11 ; bad csum */ - 0027700, /* JMP ST ; next */ - 0102055, /*H55 HALT 55 ; bad address */ - 0027700, /* JMP ST ; next */ - 0000000, /*RD 0 */ - 0006600, /* CLB,CME ; E reg byte ptr */ - 0103710, /* STC RDR,C ; start reader */ - 0102310, /* SFS RDR ; wait */ - 0027745, /* JMP *-1 */ - 0106410, /* MIB RDR ; get byte */ - 0002041, /* SEZ,RSS ; E set? */ - 0127742, /* JMP RD,I ; no, done */ - 0005767, /* BLF,CLE,BLF ; shift byte */ - 0027744, /* JMP RD+2 ; again */ - 0000000, /*WC 000000 ; word count */ - 0000000, /*AD 000000 ; address */ - 0177765, /*M11 -11 ; feed count */ - 0, 0, 0, 0, 0, 0, 0, 0, /* unused */ - 0, 0, 0, 0, 0, 0, 0, /* unused */ - 0000000 /*MAXAD -ST ; max addr */ - }; - -t_stat ptr_boot (int32 unitno, DEVICE *dptr) -{ -int32 dev; - -dev = ptr_dib.select_code; /* get device no */ -if (ibl_copy (ptr_rom, dev)) return SCPE_IERR; /* copy boot to memory */ -SR = (SR & IBL_OPT) | IBL_PTR | (dev << IBL_V_DEV); /* set SR */ -return SCPE_OK; -} - - -/* Paper tape punch I/O signal handler. - - Implementation notes: - - 1. The 12597A duplex register card is used to interface the paper tape - punch to the computer. This card has a device command flip-flop, which - supplies the PUNCH signal to the tape reader. Under simulation, this - state is implied by the activation of the PTP unit. -*/ - -uint32 ptpio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) -{ -IOSIGNAL signal; -IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ - -while (working_set) { - signal = IONEXT (working_set); /* isolate next signal */ - - switch (signal) { /* dispatch I/O signal */ - - case ioCLF: /* clear flag flip-flop */ - ptp.flag = ptp.flagbuf = CLEAR; - break; - - - case ioSTF: /* set flag flip-flop */ - case ioENF: /* enable flag */ - ptp.flag = ptp.flagbuf = SET; - break; - - - case ioSFC: /* skip if flag is clear */ - setstdSKF (ptp); - break; - - - case ioSFS: /* skip if flag is set */ - setstdSKF (ptp); - break; - - - case ioIOI: /* I/O data input */ - if ((ptp_unit.flags & UNIT_ATT) == 0) /* not attached? */ - stat_data = IORETURN (SCPE_OK, PTP_LOW); /* report as out of tape */ - else - stat_data = IORETURN (SCPE_OK, 0); - break; - - - case ioIOO: /* I/O data output */ - ptp_unit.buf = IODATA (stat_data); /* clear supplied status */ - break; - - - case ioPOPIO: /* power-on preset to I/O */ - ptp.flag = ptp.flagbuf = SET; /* set flag and flag buffer */ - ptp_unit.buf = 0; /* clear output buffer */ - break; - - - case ioCRS: /* control reset */ - case ioCLC: /* clear control flip-flop */ - ptp.control = CLEAR; - break; - - - case ioSTC: /* set control flip-flop */ - ptp.control = SET; - sim_activate (&ptp_unit, ptp_unit.wait); - break; - - - case ioSIR: /* set interrupt request */ - setstdPRL (ptp); /* set standard PRL signal */ - setstdIRQ (ptp); /* set standard IRQ signal */ - setstdSRQ (ptp); /* set standard SRQ signal */ - break; - - - case ioIAK: /* interrupt acknowledge */ - ptp.flagbuf = CLEAR; - break; - - - default: /* all other signals */ - break; /* are ignored */ - } - - working_set = working_set & ~signal; /* remove current signal from set */ - } - -return stat_data; -} - - -/* Unit service */ - -t_stat ptp_svc (UNIT *uptr) -{ -ptpio (&ptp_dib, ioENF, 0); /* set flag */ - -if ((ptp_unit.flags & UNIT_ATT) == 0) /* attached? */ - return IOERROR (ptp_stopioe, SCPE_UNATT); -if (putc (ptp_unit.buf, ptp_unit.fileref) == EOF) { /* output byte */ - perror ("PTP I/O error"); - clearerr (ptp_unit.fileref); - return SCPE_IOERR; - } -ptp_unit.pos = ftell (ptp_unit.fileref); /* update position */ -return SCPE_OK; -} - - -/* Reset routine */ - -t_stat ptp_reset (DEVICE *dptr) -{ -IOPRESET (&ptp_dib); /* PRESET device (does not use PON) */ -sim_cancel (&ptp_unit); /* deactivate unit */ -return SCPE_OK; -} - - -/* Terminal I/O signal handler */ - -uint32 ttyio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) -{ -uint16 data; -IOSIGNAL signal; -IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ - -while (working_set) { - signal = IONEXT (working_set); /* isolate next signal */ - - switch (signal) { /* dispatch I/O signal */ - - case ioCLF: /* clear flag flip-flop */ - tty.flag = tty.flagbuf = CLEAR; - break; - - - case ioSTF: /* set flag flip-flop */ - case ioENF: /* enable flag */ - tty.flag = tty.flagbuf = SET; - break; - - - case ioSFC: /* skip if flag is clear */ - setstdSKF (tty); - break; - - - case ioSFS: /* skip if flag is set */ - setstdSKF (tty); - break; - - - case ioIOI: /* I/O data input */ - data = tty_buf; - - if (!(tty_mode & TM_KBD) && sim_is_active (&tty_unit[TTO])) - data = data | TP_BUSY; - - stat_data = IORETURN (SCPE_OK, data); /* merge in return status */ - break; - - - case ioIOO: /* I/O data output */ - data = IODATA (stat_data); /* clear supplied status */ - - if (data & TM_MODE) - tty_mode = data & (TM_KBD|TM_PRI|TM_PUN); - - tty_buf = data & 0377; - break; - - - case ioCRS: /* control reset */ - tty.control = CLEAR; /* clear control */ - tty.flag = tty.flagbuf = SET; /* set flag and flag buffer */ - tty_mode = TM_KBD; /* set tty, clear print/punch */ - tty_shin = 0377; /* input inactive */ - tty_lf = 0; /* no lf pending */ - break; - - - case ioCLC: /* clear control flip-flop */ - tty.control = CLEAR; - break; - - - case ioSTC: /* set control flip-flop */ - tty.control = SET; - - if (!(tty_mode & TM_KBD)) /* output? */ - sim_activate (&tty_unit[TTO], tty_unit[TTO].wait); - break; - - - case ioSIR: /* set interrupt request */ - setstdPRL (tty); /* set standard PRL signal */ - setstdIRQ (tty); /* set standard IRQ signal */ - setstdSRQ (tty); /* set standard SRQ signal */ - break; - - - case ioIAK: /* interrupt acknowledge */ - tty.flagbuf = CLEAR; - break; - - - default: /* all other signals */ - break; /* are ignored */ - } - - working_set = working_set & ~signal; /* remove current signal from set */ - } - -return stat_data; -} - - -/* TTY input service routine. - - The console input poll routine is scheduled with a ten millisecond period - using a calibrated timer, which is the source of event timing for all of the - keyboard polling routines. Synchronizing other keyboard polls with the - console poll ensures maximum idle time. - - Several HP operating systems require a CR and LF sequence for line - termination. This is awkward on a PC, as there is no LF key (CTRL+J is - needed instead). We provide an AUTOLF mode to add a LF automatically to each - CR input. When this mode is set, entering CR will set a flag, which will - cause a LF to be supplied automatically at the next input poll. - - The 12531C teleprinter interface and the later 12880A CRT interface provide a - clever mechanism to detect a keypress during output. This is used by DOS and - RTE to allow the user to interrupt lengthy output operations to enter system - commands. - - Referring to the 12531C schematic, the terminal input enters on pin X - ("DATA FROM EIA COMPATIBLE DEVICE"). The signal passes through four - transistor inversions (Q8, Q1, Q2, and Q3) to appear on pin 12 of NAND gate - U104C. If the flag flip-flop is not set, the terminal input passes to the - (inverted) output of U104C and thence to the D input of the first of the - flip-flops forming the data register. - - In the idle condition (no key pressed), the terminal input line is marking - (voltage negative), so in passing through a total of five inversions, a - logic one is presented at the serial input of the data register. During an - output operation, the register is parallel loaded and serially shifted, - sending the output data through the register to the device and -- this is - the crux -- filling the register with logic ones from U104C. - - At the end of the output operation, the card flag is set, an interrupt - occurs, and the RTE driver is entered. The driver then does an LIA SC to - read the contents of the data register. If no key has been pressed during - the output operation, the register will read as all ones (octal 377). If, - however, any key was struck, at least one zero bit will be present. If the - register value doesn't equal 377, the driver sets the system "operator - attention" flag, which will cause DOS or RTE to output an asterisk prompt and - initiate a terminal read when the current output line is completed. -*/ - -t_stat tti_svc (UNIT *uptr) -{ -int32 c; - -uptr->wait = sim_rtcn_calb (POLL_RATE, TMR_POLL); /* calibrate poll timer */ -sim_activate (uptr, uptr->wait); /* continue poll */ - -tty_shin = 0377; /* assume inactive */ -if (tty_lf) { /* auto lf pending? */ - c = 012; /* force lf */ - tty_lf = 0; - } -else { - if ((c = sim_poll_kbd ()) < SCPE_KFLAG) return c; /* no char or error? */ - if (c & SCPE_BREAK) c = 0; /* break? */ - else c = sim_tt_inpcvt (c, TT_GET_MODE (uptr->flags)); - tty_lf = ((c & 0177) == 015) && (uptr->flags & UNIT_AUTOLF); - } -if (tty_mode & TM_KBD) { /* keyboard enabled? */ - tty_buf = c; /* put char in buf */ - uptr->pos = uptr->pos + 1; - - ttyio (&tty_dib, ioENF, 0); /* set flag */ - - if (c) { - tto_out (c); /* echo? */ - return ttp_out (c); /* punch? */ - } - } -else tty_shin = c; /* no, char shifts in */ -return SCPE_OK; -} - - -/* TTY output service routine */ - -t_stat tto_svc (UNIT *uptr) -{ -int32 c; -t_stat r; - -c = tty_buf; /* get char */ -tty_buf = tty_shin; /* shift in */ -tty_shin = 0377; /* line inactive */ -if ((r = tto_out (c)) != SCPE_OK) { /* output; error? */ - sim_activate (uptr, uptr->wait); /* retry */ - return ((r == SCPE_STALL)? SCPE_OK: r); /* !stall? report */ - } - -ttyio (&tty_dib, ioENF, 0); /* set flag */ - -return ttp_out (c); /* punch if enabled */ -} - - -t_stat tto_out (int32 c) -{ -t_stat r; - -if (tty_mode & TM_PRI) { /* printing? */ - c = sim_tt_outcvt (c, TT_GET_MODE (tty_unit[TTO].flags)); - if (c >= 0) { /* valid? */ - if (r = sim_putchar_s (c)) return r; /* output char */ - tty_unit[TTO].pos = tty_unit[TTO].pos + 1; - } - } -return SCPE_OK; -} - - -t_stat ttp_out (int32 c) -{ -if (tty_mode & TM_PUN) { /* punching? */ - if ((tty_unit[TTP].flags & UNIT_ATT) == 0) /* attached? */ - return IOERROR (ttp_stopioe, SCPE_UNATT); - if (putc (c, tty_unit[TTP].fileref) == EOF) { /* output char */ - perror ("TTP I/O error"); - clearerr (tty_unit[TTP].fileref); - return SCPE_IOERR; - } - tty_unit[TTP].pos = ftell (tty_unit[TTP].fileref); - } -return SCPE_OK; -} - - -/* TTY reset routine */ - -t_stat tty_reset (DEVICE *dptr) -{ -if (sim_switches & SWMASK ('P')) /* initialization reset? */ - tty_buf = 0; /* clear buffer */ - -IOPRESET (&tty_dib); /* PRESET device (does not use PON) */ - -tty_unit[TTI].wait = POLL_WAIT; /* reset initial poll */ -sim_rtcn_init (tty_unit[TTI].wait, TMR_POLL); /* init poll timer */ -sim_activate (&tty_unit[TTI], tty_unit[TTI].wait); /* activate poll */ -sim_cancel (&tty_unit[TTO]); /* cancel output */ -return SCPE_OK; -} - - -t_stat tty_set_opt (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -int32 u = uptr - tty_unit; - -if (u > TTO) return SCPE_NOFNC; -if ((u == TTI) && (val == TT_MODE_7P)) - val = TT_MODE_7B; -tty_unit[u].flags = (tty_unit[u].flags & ~TT_MODE) | val; -return SCPE_OK; -} - - -t_stat tty_set_alf (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -int32 u = uptr - tty_unit; - -if (u != TTI) return SCPE_NOFNC; -return SCPE_OK; -} - - -/* Synchronize polling. - - Return an event time corresponding either with the amount of time remaining - in the current poll (mode = INITIAL) or the amount of time in a full poll - period (mode = SERVICE). If the former call is made when the device service - routine is started, then making the latter call during unit service will - ensure that the polls remain synchronized. - */ - -int32 sync_poll (POLLMODE poll_mode) -{ -int32 poll_time; - - if (poll_mode == INITIAL) { - poll_time = sim_is_active (&tty_unit[TTI]); - - if (poll_time) - return poll_time; - else - return POLL_WAIT; - } - else - return tty_unit[TTI].wait; -} - - -/* Clock I/O signal handler. - - The time base generator (CLK) provides periodic interrupts from 100 - microseconds to 1000 seconds. The CLK uses a calibrated timer to provide the - time base. For periods ranging from 1 to 1000 seconds, a 100 millisecond - timer is used, and 10 to 10000 ticks are counted before setting the device - flag to indicate that the period has expired. - - If the period is set to ten milliseconds, the console poll timer is used - instead of an independent timer. This is to maximize the idle period. - - In diagnostic mode, the clock period is set to the expected number of CPU - instructions, rather than wall-clock time, so that the diagnostic executes as - expected. -*/ - -uint32 clkio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) -{ -IOSIGNAL signal; -IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ - -while (working_set) { - signal = IONEXT (working_set); /* isolate next signal */ - - switch (signal) { /* dispatch I/O signal */ - - case ioCLF: /* clear flag flip-flop */ - clk.flag = clk.flagbuf = CLEAR; - break; - - - case ioSTF: /* set flag flip-flop */ - case ioENF: /* enable flag */ - clk.flag = clk.flagbuf = SET; - break; - - - case ioSFC: /* skip if flag is clear */ - setstdSKF (clk); - break; - - - case ioSFS: /* skip if flag is set */ - setstdSKF (clk); - break; - - - case ioIOI: /* I/O data input */ - stat_data = IORETURN (SCPE_OK, clk_error); /* merge in return status */ - break; - - - case ioIOO: /* I/O data output */ - clk_select = IODATA (stat_data) & 07; /* save select */ - sim_cancel (&clk_unit); /* stop the clock */ - clk.control = CLEAR; /* clear control */ - working_set = working_set | ioSIR; /* set interrupt request (IOO normally doesn't) */ - break; - - - case ioPOPIO: /* power-on preset to I/O */ - clk.flag = clk.flagbuf = SET; /* set flag and flag buffer */ - break; - - - case ioCRS: /* control reset */ - case ioCLC: /* clear control flip-flop */ - clk.control = CLEAR; - sim_cancel (&clk_unit); /* deactivate unit */ - break; - - - case ioSTC: /* set control flip-flop */ - clk.control = SET; - if (clk_unit.flags & UNIT_DIAG) /* diag mode? */ - clk_unit.flags = clk_unit.flags & ~UNIT_IDLE; /* not calibrated */ - else - clk_unit.flags = clk_unit.flags | UNIT_IDLE; /* is calibrated */ - - if (!sim_is_active (&clk_unit)) { /* clock running? */ - clk_tick = clk_delay (0); /* get tick count */ - - if ((clk_unit.flags & UNIT_DIAG) == 0) /* calibrated? */ - if (clk_select == 2) /* 10 msec. interval? */ - clk_tick = sync_poll (INITIAL); /* sync poll */ - else - sim_rtcn_init (clk_tick, TMR_CLK); /* initialize timer */ - - sim_activate (&clk_unit, clk_tick); /* start clock */ - clk_ctr = clk_delay (1); /* set repeat ctr */ - } - clk_error = 0; /* clear error */ - break; - - - case ioSIR: /* set interrupt request */ - setstdPRL (clk); /* set standard PRL signal */ - setstdIRQ (clk); /* set standard IRQ signal */ - setstdSRQ (clk); /* set standard SRQ signal */ - break; - - - case ioIAK: /* interrupt acknowledge */ - clk.flagbuf = CLEAR; - break; - - - default: /* all other signals */ - break; /* are ignored */ - } - - working_set = working_set & ~signal; /* remove current signal from set */ - } - -return stat_data; -} - - -/* CLK unit service. - - As with the I/O handler, if the time base period is set to ten milliseconds, - the console poll timer is used instead of an independent timer. -*/ - -t_stat clk_svc (UNIT *uptr) -{ -if (!clk.control) /* control clear? */ - return SCPE_OK; /* done */ - -if (clk_unit.flags & UNIT_DIAG) /* diag mode? */ - clk_tick = clk_delay (0); /* get fixed delay */ -else if (clk_select == 2) /* 10 msec period? */ - clk_tick = sync_poll (SERVICE); /* sync poll */ -else - clk_tick = sim_rtcn_calb (clk_tps[clk_select], TMR_CLK); /* calibrate delay */ - -sim_activate (uptr, clk_tick); /* reactivate */ -clk_ctr = clk_ctr - 1; /* decrement counter */ -if (clk_ctr <= 0) { /* end of interval? */ - if (clk.flag) - clk_error = CLK_ERROR; /* overrun? error */ - else - clkio (&clk_dib, ioENF, 0); /* set flag */ - clk_ctr = clk_delay (1); /* reset counter */ - } -return SCPE_OK; -} - - -/* Reset routine */ - -t_stat clk_reset (DEVICE *dptr) -{ -if (sim_switches & SWMASK ('P')) { /* initialization reset? */ - clk_error = 0; /* clear error */ - clk_select = 0; /* clear select */ - clk_ctr = 0; /* clear counter */ - } - -IOPRESET (&clk_dib); /* PRESET device (does not use PON) */ - -return SCPE_OK; -} - - -/* Clock delay routine */ - -int32 clk_delay (int32 flg) -{ -int32 sel = clk_select; - -if ((clk_unit.flags & UNIT_DIAG) && (sel >= 4)) sel = sel - 3; -if (flg) return clk_rpt[sel]; -else return clk_time[sel]; -} +/* hp2100_stddev.c: HP2100 standard devices simulator + + Copyright (c) 1993-2014, Robert M. Supnik + + 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 + ROBERT M SUPNIK 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 Robert M Supnik shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + + PTR 12597A-002 paper tape reader interface + PTP 12597A-005 paper tape punch interface + TTY 12531C buffered teleprinter interface + TBG 12539C time base generator + + 30-Dec-14 JDB Added S-register parameters to ibl_copy + 24-Dec-14 JDB Added casts for explicit downward conversions + 28-Dec-12 JDB Allocate the TBG logical name during power-on reset + 18-Dec-12 MP Now calls sim_activate_time to get remaining poll time + 09-May-12 JDB Separated assignments from conditional expressions + 12-Feb-12 JDB Add TBG as a logical name for the CLK device + 10-Feb-12 JDB Deprecated DEVNO in favor of SC + 28-Mar-11 JDB Tidied up signal handling + 26-Oct-10 JDB Changed I/O signal handler for revised signal model + 26-Jun-08 JDB Rewrote device I/O to model backplane signals + 25-Apr-08 JDB Changed TTY output wait from 100 to 200 for MSU BASIC + 18-Apr-08 JDB Removed redundant control char handling definitions + 14-Apr-08 JDB Changed TTY console poll to 10 msec. real time + Synchronized CLK with TTY if set for 10 msec. + Added UNIT_IDLE to TTY and CLK + 09-Jan-08 JDB Fixed PTR trailing null counter for tape re-read + 31-Dec-07 JDB Added IPTICK register to CLK to display CPU instr/tick + Corrected and verified ioCRS actions + 28-Dec-06 JDB Added ioCRS state to I/O decoders + 22-Nov-05 RMS Revised for new terminal processing routines + 13-Sep-04 JDB Added paper tape loop mode, DIAG/READER modifiers to PTR + Added PV_LEFT to PTR TRLLIM register + Modified CLK to permit disable + 15-Aug-04 RMS Added tab to control char set (from Dave Bryan) + 14-Jul-04 RMS Generalized handling of control char echoing + (from Dave Bryan) + 26-Apr-04 RMS Fixed SFS x,C and SFC x,C + Fixed SR setting in IBL + Fixed input behavior during typeout for RTE-IV + Suppressed nulls on TTY output for RTE-IV + Implemented DMA SRQ (follows FLG) + 29-Mar-03 RMS Added support for console backpressure + 25-Apr-03 RMS Added extended file support + 22-Dec-02 RMS Added break support + 01-Nov-02 RMS Revised BOOT command for IBL ROMs + Fixed bug in TTY reset, TTY starts in input mode + Fixed bug in TTY mode OTA, stores data as well + Fixed clock to add calibration, proper start/stop + Added UC option to TTY output + 30-May-02 RMS Widened POS to 32b + 22-Mar-02 RMS Revised for dynamically allocated memory + 03-Nov-01 RMS Changed DEVNO to use extended SET/SHOW + 29-Nov-01 RMS Added read only unit support + 24-Nov-01 RMS Changed TIME to an array + 07-Sep-01 RMS Moved function prototypes + 21-Nov-00 RMS Fixed flag, buffer power up state + Added status input for ptp, tty + 15-Oct-00 RMS Added dynamic device number support + + References: + - 2748B Tape Reader Operating and Service Manual (02748-90041, Oct-1977) + - 12597A 8-Bit Duplex Register Interface Kit Operating and Service Manual + (12597-9002, Sep-1974) + - 12531C Buffered Teleprinter Interface Kit Operating and Service Manual + (12531-90033, Nov-1972) + - 12539C Time Base Generator Interface Kit Operating and Service Manual + (12539-90008, Jan-1975) + + + The reader and punch, like most HP devices, have a command flop. The + teleprinter and clock do not. + + Reader diagnostic mode simulates a tape loop by rewinding the tape image file + upon EOF. Normal mode EOF action is to supply TRLLIM nulls and then either + return SCPE_IOERR or SCPE_OK without setting the device flag. + + To support CPU idling, the teleprinter interface (which doubles as the + simulator console) polls for input using a calibrated timer with a ten + millisecond period. Other polled-keyboard input devices (multiplexers and + the BACI card) synchronize with the console poll to ensure maximum available + idle time. The console poll is guaranteed to run, as the TTY device cannot + be disabled. + + The clock (time base generator) autocalibrates. If the TBG is set to a ten + millisecond period (e.g., as under RTE), it is synchronized to the console + poll. Otherwise (e.g., as under DOS or TSB, which use 100 millisecond + periods), it runs asynchronously. If the specified clock frequency is below + 10Hz, the clock service routine runs at 10Hz and counts down a repeat counter + before generating an interrupt. Autocalibration will not work if the clock + is running at 1Hz or less. + + Clock diagnostic mode corresponds to inserting jumper W2 on the 12539C. + This turns off autocalibration and divides the longest time intervals down + by 10**3. The clk_time values were chosen to allow the diagnostic to + pass its clock calibration test. +*/ + +#include "hp2100_defs.h" + +#define TTY_OUT_WAIT 200 /* TTY output wait */ + +#define UNIT_V_DIAG (TTUF_V_UF + 0) /* diag mode */ +#define UNIT_V_AUTOLF (TTUF_V_UF + 1) /* auto linefeed */ +#define UNIT_DIAG (1 << UNIT_V_DIAG) +#define UNIT_AUTOLF (1 << UNIT_V_AUTOLF) + +#define PTP_LOW 0000040 /* low tape */ +#define TM_MODE 0100000 /* mode change */ +#define TM_KBD 0040000 /* enable keyboard */ +#define TM_PRI 0020000 /* enable printer */ +#define TM_PUN 0010000 /* enable punch */ +#define TP_BUSY 0100000 /* busy */ + +#define CLK_V_ERROR 4 /* clock overrun */ +#define CLK_ERROR (1 << CLK_V_ERROR) + +struct { + FLIP_FLOP control; /* control flip-flop */ + FLIP_FLOP flag; /* flag flip-flop */ + FLIP_FLOP flagbuf; /* flag buffer flip-flop */ + } ptr = { CLEAR, CLEAR, CLEAR }; + +int32 ptr_stopioe = 0; /* stop on error */ +int32 ptr_trlcnt = 0; /* trailer counter */ +int32 ptr_trllim = 40; /* trailer to add */ + +struct { + FLIP_FLOP control; /* control flip-flop */ + FLIP_FLOP flag; /* flag flip-flop */ + FLIP_FLOP flagbuf; /* flag buffer flip-flop */ + } ptp = { CLEAR, CLEAR, CLEAR }; + +int32 ptp_stopioe = 0; + +struct { + FLIP_FLOP control; /* control flip-flop */ + FLIP_FLOP flag; /* flag flip-flop */ + FLIP_FLOP flagbuf; /* flag buffer flip-flop */ + } tty = { CLEAR, CLEAR, CLEAR }; + +int32 ttp_stopioe = 0; +int32 tty_buf = 0; /* tty buffer */ +int32 tty_mode = 0; /* tty mode */ +int32 tty_shin = 0377; /* tty shift in */ +int32 tty_lf = 0; /* lf flag */ + +struct { + FLIP_FLOP control; /* control flip-flop */ + FLIP_FLOP flag; /* flag flip-flop */ + FLIP_FLOP flagbuf; /* flag buffer flip-flop */ + } clk = { CLEAR, CLEAR, CLEAR }; + +int32 clk_select = 0; /* clock time select */ +int32 clk_error = 0; /* clock error */ +int32 clk_ctr = 0; /* clock counter */ +int32 clk_time[8] = { /* clock intervals */ + 155, 1550, 15500, 155000, 155000, 155000, 155000, 155000 + }; +int32 clk_tps[8] = { /* clock tps */ + 10000, 1000, 100, 10, 10, 10, 10, 10 + }; +int32 clk_rpt[8] = { /* number of repeats */ + 1, 1, 1, 1, 10, 100, 1000, 10000 + }; +uint32 clk_tick = 0; /* instructions per tick */ + +DEVICE ptr_dev, ptp_dev, tty_dev, clk_dev; + +IOHANDLER ptrio; +t_stat ptr_svc (UNIT *uptr); +t_stat ptr_attach (UNIT *uptr, char *cptr); +t_stat ptr_reset (DEVICE *dptr); +t_stat ptr_boot (int32 unitno, DEVICE *dptr); + +IOHANDLER ptpio; +t_stat ptp_svc (UNIT *uptr); +t_stat ptp_reset (DEVICE *dptr); + +IOHANDLER ttyio; +t_stat tti_svc (UNIT *uptr); +t_stat tto_svc (UNIT *uptr); +t_stat tty_reset (DEVICE *dptr); +t_stat tty_set_opt (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat tty_set_alf (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat tto_out (int32 c); +t_stat ttp_out (int32 c); + +IOHANDLER clkio; +t_stat clk_svc (UNIT *uptr); +t_stat clk_reset (DEVICE *dptr); +int32 clk_delay (int32 flg); + +/* PTR data structures + + ptr_dev PTR device descriptor + ptr_unit PTR unit descriptor + ptr_mod PTR modifiers + ptr_reg PTR register list +*/ + +DIB ptr_dib = { &ptrio, PTR }; + +UNIT ptr_unit = { + UDATA (&ptr_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE, 0), + SERIAL_IN_WAIT + }; + +REG ptr_reg[] = { + { ORDATA (BUF, ptr_unit.buf, 8) }, + { FLDATA (CTL, ptr.control, 0) }, + { FLDATA (FLG, ptr.flag, 0) }, + { FLDATA (FBF, ptr.flagbuf, 0) }, + { DRDATA (TRLCTR, ptr_trlcnt, 8), REG_HRO }, + { DRDATA (TRLLIM, ptr_trllim, 8), PV_LEFT }, + { DRDATA (POS, ptr_unit.pos, T_ADDR_W), PV_LEFT }, + { DRDATA (TIME, ptr_unit.wait, 24), PV_LEFT }, + { FLDATA (STOP_IOE, ptr_stopioe, 0) }, + { ORDATA (SC, ptr_dib.select_code, 6), REG_HRO }, + { ORDATA (DEVNO, ptr_dib.select_code, 6), REG_HRO }, + { NULL } + }; + +MTAB ptr_mod[] = { + { UNIT_DIAG, UNIT_DIAG, "diagnostic mode", "DIAG", NULL }, + { UNIT_DIAG, 0, "reader mode", "READER", NULL }, + { MTAB_XTD | MTAB_VDV, 0, "SC", "SC", &hp_setsc, &hp_showsc, &ptr_dev }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &ptr_dev }, + { 0 } + }; + +DEVICE ptr_dev = { + "PTR", &ptr_unit, ptr_reg, ptr_mod, + 1, 10, 31, 1, 8, 8, + NULL, NULL, &ptr_reset, + &ptr_boot, &ptr_attach, NULL, + &ptr_dib, DEV_DISABLE + }; + +/* PTP data structures + + ptp_dev PTP device descriptor + ptp_unit PTP unit descriptor + ptp_mod PTP modifiers + ptp_reg PTP register list +*/ + +DIB ptp_dib = { &ptpio, PTP }; + +UNIT ptp_unit = { + UDATA (&ptp_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT + }; + +REG ptp_reg[] = { + { ORDATA (BUF, ptp_unit.buf, 8) }, + { FLDATA (CTL, ptp.control, 0) }, + { FLDATA (FLG, ptp.flag, 0) }, + { FLDATA (FBF, ptp.flagbuf, 0) }, + { DRDATA (POS, ptp_unit.pos, T_ADDR_W), PV_LEFT }, + { DRDATA (TIME, ptp_unit.wait, 24), PV_LEFT }, + { FLDATA (STOP_IOE, ptp_stopioe, 0) }, + { ORDATA (SC, ptp_dib.select_code, 6), REG_HRO }, + { ORDATA (DEVNO, ptp_dib.select_code, 6), REG_HRO }, + { NULL } + }; + +MTAB ptp_mod[] = { + { MTAB_XTD | MTAB_VDV, 0, "SC", "SC", &hp_setsc, &hp_showsc, &ptp_dev }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &ptp_dev }, + { 0 } + }; + +DEVICE ptp_dev = { + "PTP", &ptp_unit, ptp_reg, ptp_mod, + 1, 10, 31, 1, 8, 8, + NULL, NULL, &ptp_reset, + NULL, NULL, NULL, + &ptp_dib, DEV_DISABLE + }; + +/* TTY data structures + + tty_dev TTY device descriptor + tty_unit TTY unit descriptor + tty_reg TTY register list + tty_mod TTy modifiers list +*/ + +#define TTI 0 +#define TTO 1 +#define TTP 2 + +DIB tty_dib = { &ttyio, TTY }; + +UNIT tty_unit[] = { + { UDATA (&tti_svc, UNIT_IDLE | TT_MODE_UC, 0), POLL_WAIT }, + { UDATA (&tto_svc, TT_MODE_UC, 0), TTY_OUT_WAIT }, + { UDATA (&tto_svc, UNIT_SEQ | UNIT_ATTABLE | TT_MODE_8B, 0), SERIAL_OUT_WAIT } + }; + +REG tty_reg[] = { + { ORDATA (BUF, tty_buf, 8) }, + { ORDATA (MODE, tty_mode, 16) }, + { ORDATA (SHIN, tty_shin, 8), REG_HRO }, + { FLDATA (CTL, tty.control, 0) }, + { FLDATA (FLG, tty.flag, 0) }, + { FLDATA (FBF, tty.flagbuf, 0) }, + { FLDATA (KLFP, tty_lf, 0), REG_HRO }, + { DRDATA (KPOS, tty_unit[TTI].pos, T_ADDR_W), PV_LEFT }, + { DRDATA (KTIME, tty_unit[TTI].wait, 24), REG_NZ + PV_LEFT }, + { DRDATA (TPOS, tty_unit[TTO].pos, T_ADDR_W), PV_LEFT }, + { DRDATA (TTIME, tty_unit[TTO].wait, 24), REG_NZ + PV_LEFT }, + { DRDATA (PPOS, tty_unit[TTP].pos, T_ADDR_W), PV_LEFT }, + { FLDATA (STOP_IOE, ttp_stopioe, 0) }, + { ORDATA (SC, tty_dib.select_code, 6), REG_HRO }, + { ORDATA (DEVNO, tty_dib.select_code, 6), REG_HRO }, + { NULL } + }; + +MTAB tty_mod[] = { + { TT_MODE, TT_MODE_UC, "UC", "UC", &tty_set_opt }, + { TT_MODE, TT_MODE_7B, "7b", "7B", &tty_set_opt }, + { TT_MODE, TT_MODE_8B, "8b", "8B", &tty_set_opt }, + { TT_MODE, TT_MODE_7P, "7p", "7P", &tty_set_opt }, + { UNIT_AUTOLF, UNIT_AUTOLF, "autolf", "AUTOLF", &tty_set_alf }, + { UNIT_AUTOLF, 0 , NULL, "NOAUTOLF", &tty_set_alf }, + { MTAB_XTD | MTAB_VDV, 0, "SC", "SC", &hp_setsc, &hp_showsc, &tty_dev }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &tty_dev }, + { 0 } + }; + +DEVICE tty_dev = { + "TTY", tty_unit, tty_reg, tty_mod, + 3, 10, 31, 1, 8, 8, + NULL, NULL, &tty_reset, + NULL, NULL, NULL, + &tty_dib, 0 + }; + +/* CLK data structures + + clk_dev CLK device descriptor + clk_unit CLK unit descriptor + clk_mod CLK modifiers + clk_reg CLK register list +*/ + +DIB clk_dib = { &clkio, CLK }; + +UNIT clk_unit = { UDATA (&clk_svc, UNIT_IDLE, 0) }; + +REG clk_reg[] = { + { ORDATA (SEL, clk_select, 3) }, + { DRDATA (CTR, clk_ctr, 14) }, + { FLDATA (CTL, clk.control, 0) }, + { FLDATA (FLG, clk.flag, 0) }, + { FLDATA (FBF, clk.flagbuf, 0) }, + { FLDATA (ERR, clk_error, CLK_V_ERROR) }, + { BRDATA (TIME, clk_time, 10, 24, 8) }, + { DRDATA (IPTICK, clk_tick, 24), PV_RSPC | REG_RO }, + { ORDATA (SC, clk_dib.select_code, 6), REG_HRO }, + { ORDATA (DEVNO, clk_dib.select_code, 6), REG_HRO }, + { NULL } + }; + +MTAB clk_mod[] = { + { UNIT_DIAG, UNIT_DIAG, "diagnostic mode", "DIAG", NULL }, + { UNIT_DIAG, 0, "calibrated", "CALIBRATED", NULL }, + { MTAB_XTD | MTAB_VDV, 0, "SC", "SC", &hp_setsc, &hp_showsc, &clk_dev }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &clk_dev }, + { 0 } + }; + +DEVICE clk_dev = { + "CLK", &clk_unit, clk_reg, clk_mod, + 1, 0, 0, 0, 0, 0, + NULL, NULL, &clk_reset, + NULL, NULL, NULL, + &clk_dib, DEV_DISABLE, + 0, NULL, NULL, NULL + }; + + +/* Paper tape reader I/O signal handler. + + Implementation notes: + + 1. The 12597A duplex register card is used to interface the paper tape + reader to the computer. This card has a device command flip-flop, which + supplies the READ signal to the tape reader. Under simulation, this + state is implied by the activation of the PTR unit. + + 2. The POPIO signal clears the output buffer of the duplex card. However, + the buffer outputs are not used by the paper tape reader. Under + simulation, we omit the buffer clear. +*/ + +uint32 ptrio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) +{ +IOSIGNAL signal; +IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ + +while (working_set) { + signal = IONEXT (working_set); /* isolate next signal */ + + switch (signal) { /* dispatch I/O signal */ + + case ioCLF: /* clear flag flip-flop */ + ptr.flag = ptr.flagbuf = CLEAR; + break; + + + case ioSTF: /* set flag flip-flop */ + case ioENF: /* enable flag */ + ptr.flag = ptr.flagbuf = SET; + break; + + + case ioSFC: /* skip if flag is clear */ + setstdSKF (ptr); + break; + + + case ioSFS: /* skip if flag is set */ + setstdSKF (ptr); + break; + + + case ioIOI: /* I/O data input */ + stat_data = IORETURN (SCPE_OK, ptr_unit.buf); /* merge in return status */ + break; + + + case ioPOPIO: /* power-on preset to I/O */ + ptr.flag = ptr.flagbuf = SET; /* set flag and flag buffer */ + break; + + + case ioCRS: /* control reset */ + case ioCLC: /* clear control flip-flop */ + ptr.control = CLEAR; + break; + + + case ioSTC: /* set control flip-flop */ + ptr.control = SET; + sim_activate (&ptr_unit, ptr_unit.wait); + break; + + + case ioSIR: /* set interrupt request */ + setstdPRL (ptr); /* set standard PRL signal */ + setstdIRQ (ptr); /* set standard IRQ signal */ + setstdSRQ (ptr); /* set standard SRQ signal */ + break; + + + case ioIAK: /* interrupt acknowledge */ + ptr.flagbuf = CLEAR; + break; + + + default: /* all other signals */ + break; /* are ignored */ + } + + working_set = working_set & ~signal; /* remove current signal from set */ + } + +return stat_data; +} + + +/* Unit service */ + +t_stat ptr_svc (UNIT *uptr) +{ +int32 temp; + +if ((ptr_unit.flags & UNIT_ATT) == 0) /* attached? */ + return IOERROR (ptr_stopioe, SCPE_UNATT); +while ((temp = getc (ptr_unit.fileref)) == EOF) { /* read byte, error? */ + if (feof (ptr_unit.fileref)) { /* end of file? */ + if ((ptr_unit.flags & UNIT_DIAG) && (ptr_unit.pos > 0)) { + rewind (ptr_unit.fileref); /* rewind if loop mode */ + ptr_unit.pos = 0; + } + else { + if (ptr_trlcnt >= ptr_trllim) { /* added all trailer? */ + if (ptr_stopioe) { /* stop on error? */ + printf ("PTR end of file\n"); + return SCPE_IOERR; + } + else return SCPE_OK; /* no, just hang */ + } + ptr_trlcnt++; /* count trailer */ + temp = 0; /* read a zero */ + break; + } + } + else { /* no, real error */ + perror ("PTR I/O error"); + clearerr (ptr_unit.fileref); + return SCPE_IOERR; + } + } + +ptrio (&ptr_dib, ioENF, 0); /* set flag */ + +ptr_unit.buf = temp & 0377; /* put byte in buf */ +ptr_unit.pos = ftell (ptr_unit.fileref); + +if (temp) /* character non-null? */ + ptr_trlcnt = 0; /* clear trailing null counter */ + +return SCPE_OK; +} + + +/* Attach routine - clear the trailer counter */ + +t_stat ptr_attach (UNIT *uptr, char *cptr) +{ +ptr_trlcnt = 0; +return attach_unit (uptr, cptr); +} + + +/* Reset routine - called from SCP */ + +t_stat ptr_reset (DEVICE *dptr) +{ +IOPRESET (&ptr_dib); /* PRESET device (does not use PON) */ +sim_cancel (&ptr_unit); /* deactivate unit */ +return SCPE_OK; +} + + +/* Paper tape reader bootstrap routine (HP 12992K ROM) */ + +const BOOT_ROM ptr_rom = { + 0107700, /*ST CLC 0,C ; intr off */ + 0002401, /* CLA,RSS ; skip in */ + 0063756, /*CN LDA M11 ; feed frame */ + 0006700, /* CLB,CCE ; set E to rd byte */ + 0017742, /* JSB READ ; get #char */ + 0007306, /* CMB,CCE,INB,SZB ; 2's comp */ + 0027713, /* JMP *+5 ; non-zero byte */ + 0002006, /* INA,SZA ; feed frame ctr */ + 0027703, /* JMP *-3 */ + 0102077, /* HLT 77B ; stop */ + 0027700, /* JMP ST ; next */ + 0077754, /* STA WC ; word in rec */ + 0017742, /* JSB READ ; get feed frame */ + 0017742, /* JSB READ ; get address */ + 0074000, /* STB 0 ; init csum */ + 0077755, /* STB AD ; save addr */ + 0067755, /*CK LDB AD ; check addr */ + 0047777, /* ADB MAXAD ; below loader */ + 0002040, /* SEZ ; E =0 => OK */ + 0027740, /* JMP H55 */ + 0017742, /* JSB READ ; get word */ + 0040001, /* ADA 1 ; cont checksum */ + 0177755, /* STA AD,I ; store word */ + 0037755, /* ISZ AD */ + 0000040, /* CLE ; force wd read */ + 0037754, /* ISZ WC ; block done? */ + 0027720, /* JMP CK ; no */ + 0017742, /* JSB READ ; get checksum */ + 0054000, /* CPB 0 ; ok? */ + 0027702, /* JMP CN ; next block */ + 0102011, /* HLT 11 ; bad csum */ + 0027700, /* JMP ST ; next */ + 0102055, /*H55 HALT 55 ; bad address */ + 0027700, /* JMP ST ; next */ + 0000000, /*RD 0 */ + 0006600, /* CLB,CME ; E reg byte ptr */ + 0103710, /* STC RDR,C ; start reader */ + 0102310, /* SFS RDR ; wait */ + 0027745, /* JMP *-1 */ + 0106410, /* MIB RDR ; get byte */ + 0002041, /* SEZ,RSS ; E set? */ + 0127742, /* JMP RD,I ; no, done */ + 0005767, /* BLF,CLE,BLF ; shift byte */ + 0027744, /* JMP RD+2 ; again */ + 0000000, /*WC 000000 ; word count */ + 0000000, /*AD 000000 ; address */ + 0177765, /*M11 -11 ; feed count */ + 0, 0, 0, 0, 0, 0, 0, 0, /* unused */ + 0, 0, 0, 0, 0, 0, 0, /* unused */ + 0000000 /*MAXAD -ST ; max addr */ + }; + +t_stat ptr_boot (int32 unitno, DEVICE *dptr) +{ +const int32 dev = ptr_dib.select_code; /* get device no */ + +if (ibl_copy (ptr_rom, dev, IBL_OPT, /* copy the boot ROM to memory and configure */ + IBL_PTR | IBL_SET_SC (dev))) /* the S register accordingly */ + return SCPE_IERR; /* return an internal error if the copy failed */ +else + return SCPE_OK; +} + + +/* Paper tape punch I/O signal handler. + + Implementation notes: + + 1. The 12597A duplex register card is used to interface the paper tape + punch to the computer. This card has a device command flip-flop, which + supplies the PUNCH signal to the tape reader. Under simulation, this + state is implied by the activation of the PTP unit. +*/ + +uint32 ptpio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) +{ +IOSIGNAL signal; +IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ + +while (working_set) { + signal = IONEXT (working_set); /* isolate next signal */ + + switch (signal) { /* dispatch I/O signal */ + + case ioCLF: /* clear flag flip-flop */ + ptp.flag = ptp.flagbuf = CLEAR; + break; + + + case ioSTF: /* set flag flip-flop */ + case ioENF: /* enable flag */ + ptp.flag = ptp.flagbuf = SET; + break; + + + case ioSFC: /* skip if flag is clear */ + setstdSKF (ptp); + break; + + + case ioSFS: /* skip if flag is set */ + setstdSKF (ptp); + break; + + + case ioIOI: /* I/O data input */ + if ((ptp_unit.flags & UNIT_ATT) == 0) /* not attached? */ + stat_data = IORETURN (SCPE_OK, PTP_LOW); /* report as out of tape */ + else + stat_data = IORETURN (SCPE_OK, 0); + break; + + + case ioIOO: /* I/O data output */ + ptp_unit.buf = IODATA (stat_data); /* clear supplied status */ + break; + + + case ioPOPIO: /* power-on preset to I/O */ + ptp.flag = ptp.flagbuf = SET; /* set flag and flag buffer */ + ptp_unit.buf = 0; /* clear output buffer */ + break; + + + case ioCRS: /* control reset */ + case ioCLC: /* clear control flip-flop */ + ptp.control = CLEAR; + break; + + + case ioSTC: /* set control flip-flop */ + ptp.control = SET; + sim_activate (&ptp_unit, ptp_unit.wait); + break; + + + case ioSIR: /* set interrupt request */ + setstdPRL (ptp); /* set standard PRL signal */ + setstdIRQ (ptp); /* set standard IRQ signal */ + setstdSRQ (ptp); /* set standard SRQ signal */ + break; + + + case ioIAK: /* interrupt acknowledge */ + ptp.flagbuf = CLEAR; + break; + + + default: /* all other signals */ + break; /* are ignored */ + } + + working_set = working_set & ~signal; /* remove current signal from set */ + } + +return stat_data; +} + + +/* Unit service */ + +t_stat ptp_svc (UNIT *uptr) +{ +ptpio (&ptp_dib, ioENF, 0); /* set flag */ + +if ((ptp_unit.flags & UNIT_ATT) == 0) /* attached? */ + return IOERROR (ptp_stopioe, SCPE_UNATT); +if (putc (ptp_unit.buf, ptp_unit.fileref) == EOF) { /* output byte */ + perror ("PTP I/O error"); + clearerr (ptp_unit.fileref); + return SCPE_IOERR; + } +ptp_unit.pos = ftell (ptp_unit.fileref); /* update position */ +return SCPE_OK; +} + + +/* Reset routine */ + +t_stat ptp_reset (DEVICE *dptr) +{ +IOPRESET (&ptp_dib); /* PRESET device (does not use PON) */ +sim_cancel (&ptp_unit); /* deactivate unit */ +return SCPE_OK; +} + + +/* Terminal I/O signal handler */ + +uint32 ttyio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) +{ +uint16 data; +IOSIGNAL signal; +IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ + +while (working_set) { + signal = IONEXT (working_set); /* isolate next signal */ + + switch (signal) { /* dispatch I/O signal */ + + case ioCLF: /* clear flag flip-flop */ + tty.flag = tty.flagbuf = CLEAR; + break; + + + case ioSTF: /* set flag flip-flop */ + case ioENF: /* enable flag */ + tty.flag = tty.flagbuf = SET; + break; + + + case ioSFC: /* skip if flag is clear */ + setstdSKF (tty); + break; + + + case ioSFS: /* skip if flag is set */ + setstdSKF (tty); + break; + + + case ioIOI: /* I/O data input */ + data = (uint16) tty_buf; + + if (!(tty_mode & TM_KBD) && sim_is_active (&tty_unit[TTO])) + data = data | TP_BUSY; + + stat_data = IORETURN (SCPE_OK, data); /* merge in return status */ + break; + + + case ioIOO: /* I/O data output */ + data = IODATA (stat_data); /* clear supplied status */ + + if (data & TM_MODE) + tty_mode = data & (TM_KBD|TM_PRI|TM_PUN); + + tty_buf = data & 0377; + break; + + + case ioCRS: /* control reset */ + tty.control = CLEAR; /* clear control */ + tty.flag = tty.flagbuf = SET; /* set flag and flag buffer */ + tty_mode = TM_KBD; /* set tty, clear print/punch */ + tty_shin = 0377; /* input inactive */ + tty_lf = 0; /* no lf pending */ + break; + + + case ioCLC: /* clear control flip-flop */ + tty.control = CLEAR; + break; + + + case ioSTC: /* set control flip-flop */ + tty.control = SET; + + if (!(tty_mode & TM_KBD)) /* output? */ + sim_activate (&tty_unit[TTO], tty_unit[TTO].wait); + break; + + + case ioSIR: /* set interrupt request */ + setstdPRL (tty); /* set standard PRL signal */ + setstdIRQ (tty); /* set standard IRQ signal */ + setstdSRQ (tty); /* set standard SRQ signal */ + break; + + + case ioIAK: /* interrupt acknowledge */ + tty.flagbuf = CLEAR; + break; + + + default: /* all other signals */ + break; /* are ignored */ + } + + working_set = working_set & ~signal; /* remove current signal from set */ + } + +return stat_data; +} + + +/* TTY input service routine. + + The console input poll routine is scheduled with a ten millisecond period + using a calibrated timer, which is the source of event timing for all of the + keyboard polling routines. Synchronizing other keyboard polls with the + console poll ensures maximum idle time. + + Several HP operating systems require a CR and LF sequence for line + termination. This is awkward on a PC, as there is no LF key (CTRL+J is + needed instead). We provide an AUTOLF mode to add a LF automatically to each + CR input. When this mode is set, entering CR will set a flag, which will + cause a LF to be supplied automatically at the next input poll. + + The 12531C teleprinter interface and the later 12880A CRT interface provide a + clever mechanism to detect a keypress during output. This is used by DOS and + RTE to allow the user to interrupt lengthy output operations to enter system + commands. + + Referring to the 12531C schematic, the terminal input enters on pin X + ("DATA FROM EIA COMPATIBLE DEVICE"). The signal passes through four + transistor inversions (Q8, Q1, Q2, and Q3) to appear on pin 12 of NAND gate + U104C. If the flag flip-flop is not set, the terminal input passes to the + (inverted) output of U104C and thence to the D input of the first of the + flip-flops forming the data register. + + In the idle condition (no key pressed), the terminal input line is marking + (voltage negative), so in passing through a total of five inversions, a + logic one is presented at the serial input of the data register. During an + output operation, the register is parallel loaded and serially shifted, + sending the output data through the register to the device and -- this is + the crux -- filling the register with logic ones from U104C. + + At the end of the output operation, the card flag is set, an interrupt + occurs, and the RTE driver is entered. The driver then does an LIA SC to + read the contents of the data register. If no key has been pressed during + the output operation, the register will read as all ones (octal 377). If, + however, any key was struck, at least one zero bit will be present. If the + register value doesn't equal 377, the driver sets the system "operator + attention" flag, which will cause DOS or RTE to output an asterisk prompt and + initiate a terminal read when the current output line is completed. +*/ + +t_stat tti_svc (UNIT *uptr) +{ +int32 c; + +uptr->wait = sim_rtcn_calb (POLL_RATE, TMR_POLL); /* calibrate poll timer */ +sim_activate (uptr, uptr->wait); /* continue poll */ + +tty_shin = 0377; /* assume inactive */ +if (tty_lf) { /* auto lf pending? */ + c = 012; /* force lf */ + tty_lf = 0; + } +else { + if ((c = sim_poll_kbd ()) < SCPE_KFLAG) return c; /* no char or error? */ + if (c & SCPE_BREAK) c = 0; /* break? */ + else c = sim_tt_inpcvt (c, TT_GET_MODE (uptr->flags)); + tty_lf = ((c & 0177) == 015) && (uptr->flags & UNIT_AUTOLF); + } +if (tty_mode & TM_KBD) { /* keyboard enabled? */ + tty_buf = c; /* put char in buf */ + uptr->pos = uptr->pos + 1; + + ttyio (&tty_dib, ioENF, 0); /* set flag */ + + if (c) { + tto_out (c); /* echo? */ + return ttp_out (c); /* punch? */ + } + } +else tty_shin = c; /* no, char shifts in */ +return SCPE_OK; +} + + +/* TTY output service routine */ + +t_stat tto_svc (UNIT *uptr) +{ +int32 c; +t_stat r; + +c = tty_buf; /* get char */ +tty_buf = tty_shin; /* shift in */ +tty_shin = 0377; /* line inactive */ +if ((r = tto_out (c)) != SCPE_OK) { /* output; error? */ + sim_activate (uptr, uptr->wait); /* retry */ + return ((r == SCPE_STALL)? SCPE_OK: r); /* !stall? report */ + } + +ttyio (&tty_dib, ioENF, 0); /* set flag */ + +return ttp_out (c); /* punch if enabled */ +} + + +t_stat tto_out (int32 c) +{ +t_stat r; + +if (tty_mode & TM_PRI) { /* printing? */ + c = sim_tt_outcvt (c, TT_GET_MODE (tty_unit[TTO].flags)); + if (c >= 0) { /* valid? */ + r = sim_putchar_s (c); /* output char */ + if (r != SCPE_OK) + return r; + tty_unit[TTO].pos = tty_unit[TTO].pos + 1; + } + } +return SCPE_OK; +} + + +t_stat ttp_out (int32 c) +{ +if (tty_mode & TM_PUN) { /* punching? */ + if ((tty_unit[TTP].flags & UNIT_ATT) == 0) /* attached? */ + return IOERROR (ttp_stopioe, SCPE_UNATT); + if (putc (c, tty_unit[TTP].fileref) == EOF) { /* output char */ + perror ("TTP I/O error"); + clearerr (tty_unit[TTP].fileref); + return SCPE_IOERR; + } + tty_unit[TTP].pos = ftell (tty_unit[TTP].fileref); + } +return SCPE_OK; +} + + +/* TTY reset routine */ + +t_stat tty_reset (DEVICE *dptr) +{ +if (sim_switches & SWMASK ('P')) /* initialization reset? */ + tty_buf = 0; /* clear buffer */ + +IOPRESET (&tty_dib); /* PRESET device (does not use PON) */ + +tty_unit[TTI].wait = POLL_WAIT; /* reset initial poll */ +sim_rtcn_init (tty_unit[TTI].wait, TMR_POLL); /* init poll timer */ +sim_activate (&tty_unit[TTI], tty_unit[TTI].wait); /* activate poll */ +sim_cancel (&tty_unit[TTO]); /* cancel output */ +return SCPE_OK; +} + + +t_stat tty_set_opt (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +int32 u = uptr - tty_unit; + +if (u > TTO) return SCPE_NOFNC; +if ((u == TTI) && (val == TT_MODE_7P)) + val = TT_MODE_7B; +tty_unit[u].flags = (tty_unit[u].flags & ~TT_MODE) | val; +return SCPE_OK; +} + + +t_stat tty_set_alf (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +int32 u = uptr - tty_unit; + +if (u != TTI) return SCPE_NOFNC; +return SCPE_OK; +} + + +/* Synchronize polling. + + Return an event time corresponding either with the amount of time remaining + in the current poll (mode = INITIAL) or the amount of time in a full poll + period (mode = SERVICE). If the former call is made when the device service + routine is started, then making the latter call during unit service will + ensure that the polls remain synchronized. + */ + +int32 sync_poll (POLLMODE poll_mode) +{ +int32 poll_time; + + if (poll_mode == INITIAL) { + poll_time = sim_activate_time (&tty_unit[TTI]); + + if (poll_time) + return poll_time; + else + return POLL_WAIT; + } + else + return tty_unit[TTI].wait; +} + + +/* Clock I/O signal handler. + + The time base generator (CLK) provides periodic interrupts from 100 + microseconds to 1000 seconds. The CLK uses a calibrated timer to provide the + time base. For periods ranging from 1 to 1000 seconds, a 100 millisecond + timer is used, and 10 to 10000 ticks are counted before setting the device + flag to indicate that the period has expired. + + If the period is set to ten milliseconds, the console poll timer is used + instead of an independent timer. This is to maximize the idle period. + + In diagnostic mode, the clock period is set to the expected number of CPU + instructions, rather than wall-clock time, so that the diagnostic executes as + expected. +*/ + +uint32 clkio (DIB *dibptr, IOCYCLE signal_set, uint32 stat_data) +{ +IOSIGNAL signal; +IOCYCLE working_set = IOADDSIR (signal_set); /* add ioSIR if needed */ + +while (working_set) { + signal = IONEXT (working_set); /* isolate next signal */ + + switch (signal) { /* dispatch I/O signal */ + + case ioCLF: /* clear flag flip-flop */ + clk.flag = clk.flagbuf = CLEAR; + break; + + + case ioSTF: /* set flag flip-flop */ + case ioENF: /* enable flag */ + clk.flag = clk.flagbuf = SET; + break; + + + case ioSFC: /* skip if flag is clear */ + setstdSKF (clk); + break; + + + case ioSFS: /* skip if flag is set */ + setstdSKF (clk); + break; + + + case ioIOI: /* I/O data input */ + stat_data = IORETURN (SCPE_OK, clk_error); /* merge in return status */ + break; + + + case ioIOO: /* I/O data output */ + clk_select = IODATA (stat_data) & 07; /* save select */ + sim_cancel (&clk_unit); /* stop the clock */ + clk.control = CLEAR; /* clear control */ + working_set = working_set | ioSIR; /* set interrupt request (IOO normally doesn't) */ + break; + + + case ioPOPIO: /* power-on preset to I/O */ + clk.flag = clk.flagbuf = SET; /* set flag and flag buffer */ + break; + + + case ioCRS: /* control reset */ + case ioCLC: /* clear control flip-flop */ + clk.control = CLEAR; + sim_cancel (&clk_unit); /* deactivate unit */ + break; + + + case ioSTC: /* set control flip-flop */ + clk.control = SET; + if (clk_unit.flags & UNIT_DIAG) /* diag mode? */ + clk_unit.flags = clk_unit.flags & ~UNIT_IDLE; /* not calibrated */ + else + clk_unit.flags = clk_unit.flags | UNIT_IDLE; /* is calibrated */ + + if (!sim_is_active (&clk_unit)) { /* clock running? */ + clk_tick = clk_delay (0); /* get tick count */ + + if ((clk_unit.flags & UNIT_DIAG) == 0) /* calibrated? */ + if (clk_select == 2) /* 10 msec. interval? */ + clk_tick = sync_poll (INITIAL); /* sync poll */ + else + sim_rtcn_init (clk_tick, TMR_CLK); /* initialize timer */ + + sim_activate (&clk_unit, clk_tick); /* start clock */ + clk_ctr = clk_delay (1); /* set repeat ctr */ + } + clk_error = 0; /* clear error */ + break; + + + case ioSIR: /* set interrupt request */ + setstdPRL (clk); /* set standard PRL signal */ + setstdIRQ (clk); /* set standard IRQ signal */ + setstdSRQ (clk); /* set standard SRQ signal */ + break; + + + case ioIAK: /* interrupt acknowledge */ + clk.flagbuf = CLEAR; + break; + + + default: /* all other signals */ + break; /* are ignored */ + } + + working_set = working_set & ~signal; /* remove current signal from set */ + } + +return stat_data; +} + + +/* CLK unit service. + + As with the I/O handler, if the time base period is set to ten milliseconds, + the console poll timer is used instead of an independent timer. +*/ + +t_stat clk_svc (UNIT *uptr) +{ +if (!clk.control) /* control clear? */ + return SCPE_OK; /* done */ + +if (clk_unit.flags & UNIT_DIAG) /* diag mode? */ + clk_tick = clk_delay (0); /* get fixed delay */ +else if (clk_select == 2) /* 10 msec period? */ + clk_tick = sync_poll (SERVICE); /* sync poll */ +else + clk_tick = sim_rtcn_calb (clk_tps[clk_select], TMR_CLK); /* calibrate delay */ + +sim_activate (uptr, clk_tick); /* reactivate */ +clk_ctr = clk_ctr - 1; /* decrement counter */ +if (clk_ctr <= 0) { /* end of interval? */ + if (clk.flag) + clk_error = CLK_ERROR; /* overrun? error */ + else + clkio (&clk_dib, ioENF, 0); /* set flag */ + clk_ctr = clk_delay (1); /* reset counter */ + } +return SCPE_OK; +} + + +/* Reset routine */ + +t_stat clk_reset (DEVICE *dptr) +{ +if (sim_switches & SWMASK ('P')) { /* initialization reset? */ + clk_error = 0; /* clear error */ + clk_select = 0; /* clear select */ + clk_ctr = 0; /* clear counter */ + + if (clk_dev.lname == NULL) /* logical name unassigned? */ + clk_dev.lname = strdup ("TBG"); /* allocate and initialize the name */ + } + +IOPRESET (&clk_dib); /* PRESET device (does not use PON) */ + +return SCPE_OK; +} + + +/* Clock delay routine */ + +int32 clk_delay (int32 flg) +{ +int32 sel = clk_select; + +if ((clk_unit.flags & UNIT_DIAG) && (sel >= 4)) sel = sel - 3; +if (flg) return clk_rpt[sel]; +else return clk_time[sel]; +} diff --git a/HP2100/hp2100_sys.c b/HP2100/hp2100_sys.c index c6cd201c..4f0ff61e 100644 --- a/HP2100/hp2100_sys.c +++ b/HP2100/hp2100_sys.c @@ -1,856 +1,895 @@ -/* hp2100_sys.c: HP 2100 simulator interface - - Copyright (c) 1993-2012, Robert M. Supnik - - 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 - ROBERT M SUPNIK 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 Robert M Supnik shall not be - used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from Robert M Supnik. - - 10-Feb-12 JDB Deprecated DEVNO in favor of SC - Added hp_setsc, hp_showsc functions to support SC modifier - 15-Dec-11 JDB Added DA and dummy DC devices - 29-Oct-10 JDB DMA channels renamed from 0,1 to 1,2 to match documentation - 26-Oct-10 JDB Changed DIB access for revised signal model - 03-Sep-08 JDB Fixed IAK instruction dual-use mnemonic display - 07-Aug-08 JDB Moved hp_setdev, hp_showdev from hp2100_cpu.c - Changed sim_load to use WritePW instead of direct M[] access - 18-Jun-08 JDB Added PIF device - 17-Jun-08 JDB Moved fmt_char() function from hp2100_baci.c - 26-May-08 JDB Added MPX device - 24-Apr-08 JDB Changed fprint_sym to handle step with irq pending - 07-Dec-07 JDB Added BACI device - 27-Nov-07 JDB Added RTE OS/VMA/EMA mnemonics - 21-Dec-06 JDB Added "fwanxm" external for sim_load check - 19-Nov-04 JDB Added STOP_OFFLINE, STOP_PWROFF messages - 25-Sep-04 JDB Added memory protect device - Fixed display of CCA/CCB/CCE instructions - 01-Jun-04 RMS Added latent 13037 support - 19-Apr-04 RMS Recognize SFS x,C and SFC x,C - 22-Mar-02 RMS Revised for dynamically allocated memory - 14-Feb-02 RMS Added DMS instructions - 04-Feb-02 RMS Fixed bugs in alter/skip display and parsing - 01-Feb-02 RMS Added terminal multiplexor support - 16-Jan-02 RMS Added additional device support - 17-Sep-01 RMS Removed multiconsole support - 27-May-01 RMS Added multiconsole support - 14-Mar-01 RMS Revised load/dump interface (again) - 30-Oct-00 RMS Added examine to file support - 15-Oct-00 RMS Added dynamic device number support - 27-Oct-98 RMS V2.4 load interface -*/ - -#include "hp2100_defs.h" -#include "hp2100_cpu.h" -#include - -extern DEVICE cpu_dev; -extern UNIT cpu_unit; -extern REG cpu_reg[]; - -extern DEVICE mp_dev; -extern DEVICE dma1_dev, dma2_dev; -extern DEVICE ptr_dev, ptp_dev; -extern DEVICE tty_dev, clk_dev; -extern DEVICE lps_dev; -extern DEVICE lpt_dev; -extern DEVICE baci_dev; -extern DEVICE mpx_dev; -extern DEVICE mtd_dev, mtc_dev; -extern DEVICE msd_dev, msc_dev; -extern DEVICE dpd_dev, dpc_dev; -extern DEVICE dqd_dev, dqc_dev; -extern DEVICE drd_dev, drc_dev; -extern DEVICE ds_dev; -extern DEVICE muxl_dev, muxu_dev, muxc_dev; -extern DEVICE ipli_dev, iplo_dev; -extern DEVICE pif_dev; -extern DEVICE da_dev, dc_dev; - -/* SCP data structures and interface routines - - sim_name simulator name string - sim_PC pointer to saved PC register descriptor - sim_emax maximum number of words for examine/deposit - sim_devices array of pointers to simulated devices - sim_stop_messages array of pointers to stop messages - sim_load binary loader -*/ - -char sim_name[] = "HP 2100"; - -char halt_msg[] = "HALT instruction xxxxxx"; - -REG *sim_PC = &cpu_reg[0]; - -int32 sim_emax = 3; - -DEVICE *sim_devices[] = { - &cpu_dev, - &mp_dev, - &dma1_dev, &dma2_dev, - &ptr_dev, - &ptp_dev, - &tty_dev, - &clk_dev, - &lps_dev, - &lpt_dev, - &baci_dev, - &mpx_dev, - &dpd_dev, &dpc_dev, - &dqd_dev, &dqc_dev, - &drd_dev, &drc_dev, - &ds_dev, - &mtd_dev, &mtc_dev, - &msd_dev, &msc_dev, - &muxl_dev, &muxu_dev, &muxc_dev, - &ipli_dev, &iplo_dev, - &pif_dev, - &da_dev, &dc_dev, - NULL - }; - -const char *sim_stop_messages[] = { - "Unknown error", - "Unimplemented instruction", - "Non-existent I/O device", - halt_msg, - "Breakpoint", - "Indirect address loop", - "Indirect address interrupt (should not happen!)", - "No connection on interprocessor link", - "Device/unit offline", - "Device/unit powered off" - }; - -/* Binary loader - - The binary loader consists of blocks preceded and trailed by zero frames. - A block consists of 16b words (punched big endian), as follows: - - count'xxx - origin - word 0 - : - word count-1 - checksum - - The checksum includes the origin but not the count. -*/ - -int32 fgetw (FILE *fileref) -{ -int c1, c2; - -if ((c1 = fgetc (fileref)) == EOF) return -1; -if ((c2 = fgetc (fileref)) == EOF) return -1; -return ((c1 & 0377) << 8) | (c2 & 0377); -} - -t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag) -{ -int32 origin, csum, zerocnt, count, word, i; - -if ((*cptr != 0) || (flag != 0)) return SCPE_ARG; -for (zerocnt = 1;; zerocnt = -10) { /* block loop */ - for (;; zerocnt++) { /* skip 0's */ - if ((count = fgetc (fileref)) == EOF) return SCPE_OK; - else if (count) break; - else if (zerocnt == 0) return SCPE_OK; - } - if (fgetc (fileref) == EOF) return SCPE_FMT; - if ((origin = fgetw (fileref)) < 0) return SCPE_FMT; - csum = origin; /* seed checksum */ - for (i = 0; i < count; i++) { /* get data words */ - if ((word = fgetw (fileref)) < 0) return SCPE_FMT; - WritePW (origin, word); - origin = origin + 1; - csum = csum + word; - } - if ((word = fgetw (fileref)) < 0) return SCPE_FMT; - if ((word ^ csum) & DMASK) return SCPE_CSUM; - } -} - -/* Symbol tables */ - -#define I_V_FL 16 /* flag start */ -#define I_M_FL 017 /* flag mask */ -#define I_V_NPN 0 /* no operand */ -#define I_V_NPC 1 /* no operand + C */ -#define I_V_MRF 2 /* mem ref */ -#define I_V_ASH 3 /* alter/skip, shift */ -#define I_V_ESH 4 /* extended shift */ -#define I_V_EMR 5 /* extended mem ref */ -#define I_V_IO1 6 /* I/O + HC */ -#define I_V_IO2 7 /* I/O only */ -#define I_V_EGZ 010 /* ext grp, 1 op + 0 */ -#define I_V_EG2 011 /* ext grp, 2 op */ -#define I_V_ALT 012 /* alternate use instr */ -#define I_NPN (I_V_NPN << I_V_FL) -#define I_NPC (I_V_NPC << I_V_FL) -#define I_MRF (I_V_MRF << I_V_FL) -#define I_ASH (I_V_ASH << I_V_FL) -#define I_ESH (I_V_ESH << I_V_FL) -#define I_EMR (I_V_EMR << I_V_FL) -#define I_IO1 (I_V_IO1 << I_V_FL) -#define I_IO2 (I_V_IO2 << I_V_FL) -#define I_EGZ (I_V_EGZ << I_V_FL) -#define I_EG2 (I_V_EG2 << I_V_FL) -#define I_ALT (I_V_ALT << I_V_FL) - -static const int32 masks[] = { - 0177777, 0176777, 0074000, 0170000, - 0177760, 0177777, 0176700, 0177700, - 0177777, 0177777, 0177777 - }; - -static const char *opcode[] = { - -/* These mnemonics are used by debug printouts, so put them first. */ - - "$LIBR", "$LIBX", ".TICK", ".TNAM", /* RTE-6/VM OS firmware */ - ".STIO", ".FNW", ".IRT", ".LLS", - ".SIP", ".YLD", ".CPM", ".ETEQ", - ".ENTN", "$OTST", ".ENTC", ".DSPI", - "$DCPC", "$MPV", "$DEV", "$TBG", /* alternates for dual-use */ - - ".PMAP", "$LOC", "$VTST",/* --- */ /* RTE-6/VM VMA firmware */ -/* --- --- --- --- */ - ".IMAP", ".IMAR", ".JMAP", ".JMAR", - ".LPXR", ".LPX", ".LBPR", ".LBP", - - ".EMIO", "MMAP", "$ETST",/* --- */ /* RTE-IV EMA firmware */ -/* --- --- --- --- */ -/* --- --- --- --- */ -/* --- --- --- */ ".EMAP", - -/* Regular mnemonics. */ - - "NOP", "NOP", "AND", "JSB", - "XOR", "JMP", "IOR", "ISZ", - "ADA", "ADB" ,"CPA", "CPB", - "LDA", "LDB", "STA", "STB", - "DIAG", "ASL", "LSL", "TIMER", - "RRL", "ASR", "LSR", "RRR", - "MPY", "DIV", "DLD", "DST", - "FAD", "FSB", "FMP", "FDV", - "FIX", "FLT", - "STO", "CLO", "SOC", "SOS", - "HLT", "STF", "CLF", - "SFC", "SFS", "MIA", "MIB", - "LIA", "LIB", "OTA", "OTB", - "STC", "CLC", - "SYA", "USA", "PAA", "PBA", - "XMA", - "XLA", "XSA", "XCA", "LFA", - "RSA", "RVA", - "MBI", "MBF", - "MBW", "MWI", "MWF", "MWW", - "SYB", "USB", "PAB", "PBB", - "SSM", "JRS", - "XMM", "XMS", "XMB", - "XLB", "XSB", "XCB", "LFB", - "RSB", "RVB", "DJP", "DJS", - "SJP", "SJS", "UJP", "UJS", - "SAX", "SBX", "CAX", "CBX", - "LAX", "LBX", "STX", - "CXA", "CXB", "LDX", - "ADX", "XAX", "XBX", - "SAY", "SBY", "CAY", "CBY", - "LAY", "LBY", "STY", - "CYA", "CYB", "LDY", - "ADY", "XAY", "XBY", - "ISX", "DSX", "JLY", "LBT", - "SBT", "MBT", "CBT", "SBT", - "ISY", "DSY", "JPY", "SBS", - "CBS", "TBS", "CMW", "MVW", - NULL, /* decode only */ - NULL - }; - -static const int32 opc_val[] = { - 0105340+I_NPN, 0105341+I_NPN, 0105342+I_NPN, 0105343+I_NPN, /* RTE-6/VM OS */ - 0105344+I_NPN, 0105345+I_NPN, 0105346+I_NPN, 0105347+I_NPN, - 0105350+I_NPN, 0105351+I_NPN, 0105352+I_NPN, 0105353+I_NPN, - 0105354+I_ALT, 0105355+I_ALT, 0105356+I_ALT, 0105357+I_ALT, - 0105354+I_NPN, 0105355+I_NPN, 0105356+I_NPN, 0105357+I_NPN, /* alternates */ - - 0105240+I_ALT, 0105241+I_ALT, 0105242+I_ALT, /* --- */ /* RTE-6/VM VMA */ -/* --- --- --- --- */ - 0105250+I_NPN, 0105251+I_NPN, 0105252+I_NPN, 0105253+I_NPN, - 0105254+I_NPN, 0105255+I_NPN, 0105256+I_NPN, 0105257+I_ALT, - - 0105240+I_NPN, 0105241+I_NPN, 0105242+I_NPN, /* RTE-IV EMA */ -/* --- --- --- --- */ -/* --- --- --- --- */ -/* --- --- --- */ 0105257+I_NPN, - - 0000000+I_NPN, 0002000+I_NPN, 0010000+I_MRF, 0014000+I_MRF, - 0020000+I_MRF, 0024000+I_MRF, 0030000+I_MRF, 0034000+I_MRF, - 0040000+I_MRF, 0044000+I_MRF, 0050000+I_MRF, 0054000+I_MRF, - 0060000+I_MRF, 0064000+I_MRF, 0070000+I_MRF, 0074000+I_MRF, - 0100000+I_NPN, 0100020+I_ESH, 0100040+I_ESH, 0100060+I_NPN, - 0100100+I_ESH, 0101020+I_ESH, 0101040+I_ESH, 0101100+I_ESH, - 0100200+I_EMR, 0100400+I_EMR, 0104200+I_EMR, 0104400+I_EMR, - 0105000+I_EMR, 0105020+I_EMR, 0105040+I_EMR, 0105060+I_EMR, - 0105100+I_NPN, 0105120+I_NPN, - 0102101+I_NPN, 0103101+I_NPN, 0102201+I_NPC, 0102301+I_NPC, - 0102000+I_IO1, 0102100+I_IO2, 0103100+I_IO2, - 0102200+I_IO1, 0102300+I_IO1, 0102400+I_IO1, 0106400+I_IO1, - 0102500+I_IO1, 0106500+I_IO1, 0102600+I_IO1, 0106600+I_IO1, - 0102700+I_IO1, 0106700+I_IO1, - 0101710+I_NPN, 0101711+I_NPN, 0101712+I_NPN, 0101713+I_NPN, - 0101722+I_NPN, - 0101724+I_EMR, 0101725+I_EMR, 0101726+I_EMR, 0101727+I_NPN, - 0101730+I_NPN, 0101731+I_NPN, - 0105702+I_NPN, 0105703+I_NPN, - 0105704+I_NPN, 0105705+I_NPN, 0105706+I_NPN, 0105707+I_NPN, - 0105710+I_NPN, 0105711+I_NPN, 0105712+I_NPN, 0105713+I_NPN, - 0105714+I_EMR, 0105715+I_EG2, - 0105720+I_NPN, 0105721+I_NPN, 0105722+I_NPN, - 0105724+I_EMR, 0105725+I_EMR, 0105726+I_EMR, 0105727+I_NPN, - 0105730+I_NPN, 0105731+I_NPN, 0105732+I_EMR, 0105733+I_EMR, - 0105734+I_EMR, 0105735+I_EMR, 0105736+I_EMR, 0105737+I_EMR, - 0101740+I_EMR, 0105740+I_EMR, 0101741+I_NPN, 0105741+I_NPN, - 0101742+I_EMR, 0105742+I_EMR, 0105743+I_EMR, - 0101744+I_NPN, 0105744+I_NPN, 0105745+I_EMR, - 0105746+I_EMR, 0101747+I_NPN, 0105747+I_NPN, - 0101750+I_EMR, 0105750+I_EMR, 0101751+I_NPN, 0105751+I_NPN, - 0101752+I_EMR, 0105752+I_EMR, 0105753+I_EMR, - 0101754+I_NPN, 0105754+I_NPN, 0105755+I_EMR, - 0105756+I_EMR, 0101757+I_NPN, 0105757+I_NPN, - 0105760+I_NPN, 0105761+I_NPN, 0105762+I_EMR, 0105763+I_NPN, - 0105764+I_NPN, 0105765+I_EGZ, 0105766+I_EGZ, 0105767+I_NPN, - 0105770+I_NPN, 0105771+I_NPN, 0105772+I_EMR, 0105773+I_EG2, - 0105774+I_EG2, 0105775+I_EG2, 0105776+I_EGZ, 0105777+I_EGZ, - 0000000+I_ASH, /* decode only */ - -1 - }; - -/* Decode tables for shift and alter/skip groups */ - -static const char *stab[] = { - "ALS", "ARS", "RAL", "RAR", "ALR", "ERA", "ELA", "ALF", - "BLS", "BRS", "RBL", "RBR", "BLR", "ERB", "ELB", "BLF", - "CLA", "CMA", "CCA", "CLB", "CMB", "CCB", - "SEZ", "CLE", "CLE", "CME", "CCE", - "SSA", "SSB", "SLA", "SLB", - "ALS", "ARS", "RAL", "RAR", "ALR", "ERA", "ELA", "ALF", - "BLS", "BRS", "RBL", "RBR", "BLR", "ERB", "ELB", "BLF", - "INA", "INB", "SZA", "SZB", "RSS", - NULL - }; - -static const int32 mtab[] = { - 0007700, 0007700, 0007700, 0007700, 0007700, 0007700, 0007700, 0007700, - 0007700, 0007700, 0007700, 0007700, 0007700, 0007700, 0007700, 0007700, - 0007400, 0007400, 0007400, 0007400, 0007400, 0007400, - 0002040, 0002040, 0002300, 0002300, 0002300, - 0006020, 0006020, 0004010, 0004010, - 0006027, 0006027, 0006027, 0006027, 0006027, 0006027, 0006027, 0006027, - 0006027, 0006027, 0006027, 0006027, 0006027, 0006027, 0006027, 0006027, - 0006004, 0006004, 0006002, 0006002, 0002001, - 0 - }; - -static const int32 vtab[] = { - 0001000, 0001100, 0001200, 0001300, 0001400, 0001500, 0001600, 0001700, - 0005000, 0005100, 0005200, 0005300, 0005400, 0005500, 0005600, 0005700, - 0002400, 0003000, 0003400, 0006400, 0007000, 0007400, - 0002040, 0000040, 0002100, 0002200, 0002300, - 0002020, 0006020, 0000010, 0004010, - 0000020, 0000021, 0000022, 0000023, 0000024, 0000025, 0000026, 0000027, - 0004020, 0004021, 0004022, 0004023, 0004024, 0004025, 0004026, 0004027, - 0002004, 0006004, 0002002, 0006002, 0002001, - -1 - }; - -/* Symbolic decode - - Inputs: - *of = output stream - addr = current PC - *val = pointer to data - *uptr = pointer to unit - sw = switches - Outputs: - return = status code -*/ - -#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 cflag, cm, i, j, inst, disp; -uint32 irq; - -cflag = (uptr == NULL) || (uptr == &cpu_unit); -inst = val[0]; -if (sw & SWMASK ('A')) { /* ASCII? */ - if (inst > 0377) return SCPE_ARG; - fprintf (of, FMTASC (inst & 0177)); - return SCPE_OK; - } -if (sw & SWMASK ('C')) { /* characters? */ - fprintf (of, FMTASC ((inst >> 8) & 0177)); - fprintf (of, FMTASC (inst & 0177)); - return SCPE_OK; - } -if (!(sw & SWMASK ('M'))) return SCPE_ARG; - -/* If we are being called as a result of a VM stop to display the next - instruction to be executed, check to see if an interrupt is pending and not - deferred. If so, then display the interrupt source and the trap cell - instruction as the instruction to be executed, rather than the instruction at - the current PC. -*/ - -if (sw & SIM_SW_STOP) { /* simulator stop? */ - irq = calc_int (); /* check interrupt */ - - if (irq && (!ion_defer || !calc_defer())) { /* pending interrupt and not deferred? */ - addr = irq; /* set display address to trap cell */ - inst = val[0] = ReadIO (irq, SMAP); /* load trap cell instruction */ - val[1] = ReadIO (irq + 1, SMAP); /* might be multi-word */ - val[2] = ReadIO (irq + 2, SMAP); /* although it's unlikely */ - fprintf (of, "IAK %2o: ", irq); /* report acknowledged interrupt */ - } - } - -for (i = 0; opc_val[i] >= 0; i++) { /* loop thru ops */ - j = (opc_val[i] >> I_V_FL) & I_M_FL; /* get class */ - if ((opc_val[i] & DMASK) == (inst & masks[j])) { /* match? */ - switch (j) { /* case on class */ - - case I_V_NPN: /* no operands */ - fprintf (of, "%s", opcode[i]); /* opcode */ - break; - - case I_V_NPC: /* no operands + C */ - fprintf (of, "%s", opcode[i]); - if (inst & I_HC) fprintf (of, " C"); - break; - - case I_V_MRF: /* mem ref */ - disp = inst & I_DISP; /* displacement */ - fprintf (of, "%s ", opcode[i]); /* opcode */ - if (inst & I_CP) { /* current page? */ - if (cflag) fprintf (of, "%-o", (addr & I_PAGENO) | disp); - else fprintf (of, "C %-o", disp); - } - else fprintf (of, "%-o", disp); /* page zero */ - if (inst & I_IA) fprintf (of, ",I"); - break; - - case I_V_ASH: /* shift, alter-skip */ - cm = FALSE; - for (i = 0; mtab[i] != 0; i++) { - if ((inst & mtab[i]) == vtab[i]) { - inst = inst & ~(vtab[i] & 01777); - if (cm) fprintf (of, ","); - cm = TRUE; - fprintf (of, "%s", stab[i]); - } - } - if (!cm) return SCPE_ARG; /* nothing decoded? */ - break; - - case I_V_ESH: /* extended shift */ - disp = inst & 017; /* shift count */ - if (disp == 0) disp = 16; - fprintf (of, "%s %d", opcode[i], disp); - break; - - case I_V_EMR: /* extended mem ref */ - fprintf (of, "%s %-o", opcode[i], val[1] & VAMASK); - if (val[1] & I_IA) fprintf (of, ",I"); - return -1; /* extra word */ - - case I_V_IO1: /* IOT with H/C */ - fprintf (of, "%s %-o", opcode[i], inst & I_DEVMASK); - if (inst & I_HC) fprintf (of, ",C"); - break; - - case I_V_IO2: /* IOT */ - fprintf (of, "%s %-o", opcode[i], inst & I_DEVMASK); - break; - - case I_V_EGZ: /* ext grp 1 op + 0 */ - fprintf (of, "%s %-o", opcode[i], val[1] & VAMASK); - if (val[1] & I_IA) fprintf (of, ",I"); - return -2; /* extra words */ - - case I_V_EG2: /* ext grp 2 op */ - fprintf (of, "%s %-o", opcode[i], val[1] & VAMASK); - if (val[1] & I_IA) fprintf (of, ",I"); - fprintf (of, " %-o", val[2] & VAMASK); - if (val[2] & I_IA) fprintf (of, ",I"); - return -2; /* extra words */ - - case I_V_ALT: /* alternate use instr */ - if ((inst >= 0105354) && - (inst <= 0105357) && /* RTE-6/VM OS range? */ - (addr >= 2) && - (addr <= 077)) /* in trap cell? */ - continue; /* use alternate mnemonic */ - - else if ((inst >= 0105240) && /* RTE-6/VM VMA range? */ - (inst <= 0105257) && - (cpu_unit.flags & UNIT_EMA)) /* EMA enabled? */ - continue; /* use EMA mnemonics */ - - else - fprintf (of, "%s", opcode[i]); /* print opcode */ - break; - } - - return SCPE_OK; - } /* end if */ - } /* end for */ -return SCPE_ARG; -} - -/* Get address with indirection - - Inputs: - *cptr = pointer to input string - Outputs: - val = address - -1 if error -*/ - -int32 get_addr (char *cptr) -{ -int32 d; -t_stat r; -char gbuf[CBUFSIZE]; - -cptr = get_glyph (cptr, gbuf, ','); /* get next field */ -d = get_uint (gbuf, 8, VAMASK, &r); /* construe as addr */ -if (r != SCPE_OK) return -1; -if (*cptr != 0) { /* more? */ - cptr = get_glyph (cptr, gbuf, 0); /* look for indirect */ - if (*cptr != 0) return -1; /* should be done */ - if (strcmp (gbuf, "I")) return -1; /* I? */ - d = d | I_IA; - } -return d; -} - -/* Symbolic input - - Inputs: - *iptr = 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 (char *iptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw) -{ -int32 cflag, d, i, j, k, clef, tbits; -t_stat r, ret; -char *cptr, gbuf[CBUFSIZE]; - -cflag = (uptr == NULL) || (uptr == &cpu_unit); -while (isspace (*iptr)) iptr++; /* absorb spaces */ -if ((sw & SWMASK ('A')) || ((*iptr == '\'') && iptr++)) { /* ASCII char? */ - if (iptr[0] == 0) return SCPE_ARG; /* must have 1 char */ - val[0] = (t_value) iptr[0] & 0177; - return SCPE_OK; - } -if ((sw & SWMASK ('C')) || ((*iptr == '"') && iptr++)) { /* char string? */ - if (iptr[0] == 0) return SCPE_ARG; /* must have 1 char */ - val[0] = (((t_value) iptr[0] & 0177) << 8) | - ((t_value) iptr[1] & 0177); - return SCPE_OK; - } - -ret = SCPE_OK; -cptr = get_glyph (iptr, gbuf, 0); /* get opcode */ -for (i = 0; (opcode[i] != NULL) && (strcmp (opcode[i], gbuf) != 0) ; i++) ; -if (opcode[i]) { /* found opcode? */ - val[0] = opc_val[i] & DMASK; /* get value */ - j = (opc_val[i] >> I_V_FL) & I_M_FL; /* get class */ - switch (j) { /* case on class */ - - case I_V_NPN: /* no operand */ - break; - - case I_V_NPC: /* no operand + C */ - if (*cptr != 0) { - cptr = get_glyph (cptr, gbuf, 0); - if (strcmp (gbuf, "C")) return SCPE_ARG; - val[0] = val[0] | I_HC; - } - break; - - case I_V_MRF: /* mem ref */ - cptr = get_glyph (cptr, gbuf, 0); /* get next field */ - if (k = (strcmp (gbuf, "C") == 0)) { /* C specified? */ - val[0] = val[0] | I_CP; - cptr = get_glyph (cptr, gbuf, 0); - } - else if (k = (strcmp (gbuf, "Z") == 0)) { /* Z specified? */ - cptr = get_glyph (cptr, gbuf, ','); - } - if ((d = get_addr (gbuf)) < 0) return SCPE_ARG; - if ((d & VAMASK) <= I_DISP) val[0] = val[0] | d; - else if (cflag && !k && (((addr ^ d) & I_PAGENO) == 0)) - val[0] = val[0] | (d & (I_IA | I_DISP)) | I_CP; - else return SCPE_ARG; - break; - - case I_V_ESH: /* extended shift */ - cptr = get_glyph (cptr, gbuf, 0); - d = get_uint (gbuf, 10, 16, &r); - if ((r != SCPE_OK) || (d == 0)) return SCPE_ARG; - val[0] = val[0] | (d & 017); - break; - - case I_V_EMR: /* extended mem ref */ - cptr = get_glyph (cptr, gbuf, 0); /* get next field */ - if ((d = get_addr (gbuf)) < 0) return SCPE_ARG; - val[1] = d; - ret = -1; - break; - - case I_V_IO1: /* IOT + optional C */ - cptr = get_glyph (cptr, gbuf, ','); /* get device */ - d = get_uint (gbuf, 8, I_DEVMASK, &r); - if (r != SCPE_OK) return SCPE_ARG; - val[0] = val[0] | d; - if (*cptr != 0) { - cptr = get_glyph (cptr, gbuf, 0); - if (strcmp (gbuf, "C")) return SCPE_ARG; - val[0] = val[0] | I_HC; - } - break; - - case I_V_IO2: /* IOT */ - cptr = get_glyph (cptr, gbuf, 0); /* get device */ - d = get_uint (gbuf, 8, I_DEVMASK, &r); - if (r != SCPE_OK) return SCPE_ARG; - val[0] = val[0] | d; - break; - - case I_V_EGZ: /* ext grp 1 op + 0 */ - cptr = get_glyph (cptr, gbuf, 0); /* get next field */ - if ((d = get_addr (gbuf)) < 0) return SCPE_ARG; - val[1] = d; - val[2] = 0; - ret = -2; - break; - - case I_V_EG2: /* ext grp 2 op */ - cptr = get_glyph (cptr, gbuf, 0); /* get next field */ - if ((d = get_addr (gbuf)) < 0) return SCPE_ARG; - cptr = get_glyph (cptr, gbuf, 0); /* get next field */ - if ((k = get_addr (gbuf)) < 0) return SCPE_ARG; - val[1] = d; - val[2] = k; - ret = -2; - break; - } /* end case */ - - if (*cptr != 0) return SCPE_ARG; /* junk at end? */ - return ret; - } /* end if opcode */ - -/* Shift or alter-skip - - Each opcode is matched by a mask, specifiying the bits affected, and - the value, specifying the value. As opcodes are processed, the mask - values are used to specify which fields have already been filled in. - - The mask has two subfields, the type bits (A/B and A/S), and the field - bits. The type bits, once specified by any instruction, must be - consistent in all other instructions. The mask bits assure that no - field is filled in twice. - - Two special cases: - - 1. The dual shift field in shift requires checking how much of the - target word has been filled in before assigning the shift value. - To implement this, shifts are listed twice is the decode table. - If the current subopcode is a shift in the first part of the table - (entries 0..15), and CLE has been seen or the first shift field is - filled in, the code forces a mismatch. The glyph will match in - the second part of the table. - - 2. CLE processing must be deferred until the instruction can be - classified as shift or alter-skip, since it has two different - bit values in the two classes. To implement this, CLE seen is - recorded as a flag and processed after all other subopcodes. -*/ - -clef = FALSE; -tbits = 0; -val[0] = 0; -for (cptr = get_glyph (iptr, gbuf, ','); gbuf[0] != 0; - cptr = get_glyph (cptr, gbuf, ',')) { /* loop thru glyphs */ - if (strcmp (gbuf, "CLE") == 0) { /* CLE? */ - if (clef) return SCPE_ARG; /* already seen? */ - clef = TRUE; /* set flag */ - continue; - } - for (i = 0; stab[i] != NULL; i++) { /* find subopcode */ - if ((strcmp (gbuf, stab[i]) == 0) && - ((i >= 16) || (!clef && ((val[0] & 001710) == 0)))) break; - } - if (stab[i] == NULL) return SCPE_ARG; - if (tbits & mtab[i] & (I_AB | I_ASKP) & (vtab[i] ^ val[0])) - return SCPE_ARG; - if (tbits & mtab[i] & ~(I_AB | I_ASKP)) return SCPE_ARG; - tbits = tbits | mtab[i]; /* fill type+mask */ - val[0] = val[0] | vtab[i]; /* fill value */ - } -if (clef) { /* CLE seen? */ - if (val[0] & I_ASKP) { /* alter-skip? */ - if (tbits & 0100) return SCPE_ARG; /* already filled in? */ - else val[0] = val[0] | 0100; - } - else val[0] = val[0] | 040; /* fill in shift */ - } -return ret; -} - - -/* Format a character into a printable string. - - Control characters are translated to readable strings. Printable characters - retain their original form but are enclosed in single quotes. Characters - outside of the ASCII range are represented as escaped octal values. -*/ - -const char *fmt_char (uint8 ch) -{ -static const char *const ctl [] = { "NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL", - "BS", "HT", "LF", "VT", "FF", "CR", "SO", "SI", - "DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB", - "CAN", "EM", "SUB", "ESC", "FS", "GS", "RS", "US" }; -static char rep [5]; - -if (ch <= '\037') /* ASCII control character? */ - return ctl [ch]; /* return string representation */ - -else if (ch == '\177') /* ASCII delete? */ - return "DEL"; /* return string representation */ - -else if (ch > '\177') { /* beyond printable range? */ - sprintf (rep, "\\%03o", ch); /* format value */ - return rep; /* return escaped octal code */ - } - -else { /* printable character */ - rep [0] = '\''; /* form string */ - rep [1] = ch; /* containing character */ - rep [2] = '\''; - rep [3] = '\0'; - return rep; /* return quoted character */ - } -} - - -/* Set select code */ - -t_stat hp_setsc (UNIT *uptr, int32 num, char *cptr, void *desc) -{ -DEVICE *dptr = (DEVICE *) desc; -DIB *dibptr; -int32 i, newdev; -t_stat r; - -if (cptr == NULL) - return SCPE_ARG; - -if ((desc == NULL) || (num > 1)) - return SCPE_IERR; - -dibptr = (DIB *) dptr->ctxt; - -if (dibptr == NULL) - return SCPE_IERR; - -newdev = get_uint (cptr, 8, I_DEVMASK - num, &r); - -if (r != SCPE_OK) - return r; - -if (newdev < VARDEV) - return SCPE_ARG; - -for (i = 0; i <= num; i++, dibptr++) - dibptr->select_code = newdev + i; - -return SCPE_OK; -} - - -/* Show select code */ - -t_stat hp_showsc (FILE *st, UNIT *uptr, int32 num, void *desc) -{ -DEVICE *dptr = (DEVICE *) desc; -DIB *dibptr; -int32 i; - -if ((desc == NULL) || (num > 1)) - return SCPE_IERR; - -dibptr = (DIB *) dptr->ctxt; - -if (dibptr == NULL) - return SCPE_IERR; - -fprintf (st, "select code=%o", dibptr->select_code); - -for (i = 1; i <= num; i++) - fprintf (st, "/%o", dibptr->select_code + i); - -return SCPE_OK; -} - - -/* Set device number */ - -t_stat hp_setdev (UNIT *uptr, int32 num, char *cptr, void *desc) -{ -return hp_setsc (uptr, num, cptr, desc); -} - - -/* Show device number */ - -t_stat hp_showdev (FILE *st, UNIT *uptr, int32 num, void *desc) -{ -t_stat result; - -result = hp_showsc (st, uptr, num, desc); - -if (result == SCPE_OK) - fputc ('\n', st); - -return result; -} +/* hp2100_sys.c: HP 2100 simulator interface + + Copyright (c) 1993-2014, Robert M. Supnik + + 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 + ROBERT M SUPNIK 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 Robert M Supnik shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + + 24-Dec-14 JDB Added casts to t_addr and t_value for 64-bit compatibility + Made local routines static + 05-Feb-13 JDB Added hp_fprint_stopped to handle HLT instruction message + 18-Mar-13 JDB Moved CPU state variable declarations to hp2100_cpu.h + 09-May-12 JDB Quieted warnings for assignments in conditional expressions + 10-Feb-12 JDB Deprecated DEVNO in favor of SC + Added hp_setsc, hp_showsc functions to support SC modifier + 15-Dec-11 JDB Added DA and dummy DC devices + 29-Oct-10 JDB DMA channels renamed from 0,1 to 1,2 to match documentation + 26-Oct-10 JDB Changed DIB access for revised signal model + 03-Sep-08 JDB Fixed IAK instruction dual-use mnemonic display + 07-Aug-08 JDB Moved hp_setdev, hp_showdev from hp2100_cpu.c + Changed sim_load to use WritePW instead of direct M[] access + 18-Jun-08 JDB Added PIF device + 17-Jun-08 JDB Moved fmt_char() function from hp2100_baci.c + 26-May-08 JDB Added MPX device + 24-Apr-08 JDB Changed fprint_sym to handle step with irq pending + 07-Dec-07 JDB Added BACI device + 27-Nov-07 JDB Added RTE OS/VMA/EMA mnemonics + 21-Dec-06 JDB Added "fwanxm" external for sim_load check + 19-Nov-04 JDB Added STOP_OFFLINE, STOP_PWROFF messages + 25-Sep-04 JDB Added memory protect device + Fixed display of CCA/CCB/CCE instructions + 01-Jun-04 RMS Added latent 13037 support + 19-Apr-04 RMS Recognize SFS x,C and SFC x,C + 22-Mar-02 RMS Revised for dynamically allocated memory + 14-Feb-02 RMS Added DMS instructions + 04-Feb-02 RMS Fixed bugs in alter/skip display and parsing + 01-Feb-02 RMS Added terminal multiplexor support + 16-Jan-02 RMS Added additional device support + 17-Sep-01 RMS Removed multiconsole support + 27-May-01 RMS Added multiconsole support + 14-Mar-01 RMS Revised load/dump interface (again) + 30-Oct-00 RMS Added examine to file support + 15-Oct-00 RMS Added dynamic device number support + 27-Oct-98 RMS V2.4 load interface +*/ + +#include "hp2100_defs.h" +#include "hp2100_cpu.h" +#include + + +extern DEVICE mp_dev; +extern DEVICE dma1_dev, dma2_dev; +extern DEVICE ptr_dev, ptp_dev; +extern DEVICE tty_dev, clk_dev; +extern DEVICE lps_dev; +extern DEVICE lpt_dev; +extern DEVICE baci_dev; +extern DEVICE mpx_dev; +extern DEVICE mtd_dev, mtc_dev; +extern DEVICE msd_dev, msc_dev; +extern DEVICE dpd_dev, dpc_dev; +extern DEVICE dqd_dev, dqc_dev; +extern DEVICE drd_dev, drc_dev; +extern DEVICE ds_dev; +extern DEVICE muxl_dev, muxu_dev, muxc_dev; +extern DEVICE ipli_dev, iplo_dev; +extern DEVICE pif_dev; +extern DEVICE da_dev, dc_dev; + +/* SCP data structures and interface routines + + sim_name simulator name string + sim_PC pointer to saved PC register descriptor + sim_emax maximum number of words for examine/deposit + sim_devices array of pointers to simulated devices + sim_stop_messages array of pointers to stop messages + sim_load binary loader +*/ + +char sim_name[] = "HP 2100"; + +REG *sim_PC = &cpu_reg[0]; + +int32 sim_emax = 3; + +DEVICE *sim_devices[] = { + &cpu_dev, + &mp_dev, + &dma1_dev, &dma2_dev, + &ptr_dev, + &ptp_dev, + &tty_dev, + &clk_dev, + &lps_dev, + &lpt_dev, + &baci_dev, + &mpx_dev, + &dpd_dev, &dpc_dev, + &dqd_dev, &dqc_dev, + &drd_dev, &drc_dev, + &ds_dev, + &mtd_dev, &mtc_dev, + &msd_dev, &msc_dev, + &muxl_dev, &muxu_dev, &muxc_dev, + &ipli_dev, &iplo_dev, + &pif_dev, + &da_dev, &dc_dev, + NULL + }; + +const char *sim_stop_messages[] = { + "Unknown error", + "Unimplemented instruction", + "Non-existent I/O device", + "HALT instruction", + "Breakpoint", + "Indirect address loop", + "Indirect address interrupt (should not happen!)", + "No connection on interprocessor link", + "Device/unit offline", + "Device/unit powered off" + }; + + +/* Print additional information for simulator stops. + + The HP 21xx/1000 halt instruction ("HLT") opcode includes select code and + device flag hold/clear bit fields. In practice, these are not used to affect + the device interface; rather, they communicate to the operator the + significance of the particular halt encountered. + + Under simulation, the halt opcode must be communicated to the user as part of + the stop message. To so do, we define a sim_vm_fprint_stopped handler that + is called for all VM stops. When called for a STOP_HALT, the halt message + has been printed, and we add the opcode value in the T register before + returning TRUE, so that SCP will add the program counter value. For example: + + HALT instruction 102077, P: 00101 (NOP) + + Reasons other than STOP_HALT need no additional information. + + Implementation notes: + + 1. The octal halt instruction will always be of the form 10x0xx. We take + advantage of this to request 19 bits printed with leading spaces. This + adds a leading space to separate the value from the message. +*/ + +t_bool hp_fprint_stopped (FILE *st, t_stat reason) +{ +if (reason == STOP_HALT) + fprint_val (st, TR, 8, 19, PV_RSPC); + +return TRUE; +} + + +/* Binary loader + + The binary loader consists of blocks preceded and trailed by zero frames. + A block consists of 16b words (punched big endian), as follows: + + count'xxx + origin + word 0 + : + word count-1 + checksum + + The checksum includes the origin but not the count. +*/ + +static int32 fgetw (FILE *fileref) +{ +int c1, c2; + +if ((c1 = fgetc (fileref)) == EOF) return -1; +if ((c2 = fgetc (fileref)) == EOF) return -1; +return ((c1 & 0377) << 8) | (c2 & 0377); +} + +t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag) +{ +int32 origin, csum, zerocnt, count, word, i; + +if ((*cptr != 0) || (flag != 0)) return SCPE_ARG; +for (zerocnt = 1;; zerocnt = -10) { /* block loop */ + for (;; zerocnt++) { /* skip 0's */ + if ((count = fgetc (fileref)) == EOF) return SCPE_OK; + else if (count) break; + else if (zerocnt == 0) return SCPE_OK; + } + if (fgetc (fileref) == EOF) return SCPE_FMT; + if ((origin = fgetw (fileref)) < 0) return SCPE_FMT; + csum = origin; /* seed checksum */ + for (i = 0; i < count; i++) { /* get data words */ + if ((word = fgetw (fileref)) < 0) return SCPE_FMT; + WritePW (origin, word); + origin = origin + 1; + csum = csum + word; + } + if ((word = fgetw (fileref)) < 0) return SCPE_FMT; + if ((word ^ csum) & DMASK) return SCPE_CSUM; + } +} + +/* Symbol tables */ + +#define I_V_FL 16 /* flag start */ +#define I_M_FL 017 /* flag mask */ +#define I_V_NPN 0 /* no operand */ +#define I_V_NPC 1 /* no operand + C */ +#define I_V_MRF 2 /* mem ref */ +#define I_V_ASH 3 /* alter/skip, shift */ +#define I_V_ESH 4 /* extended shift */ +#define I_V_EMR 5 /* extended mem ref */ +#define I_V_IO1 6 /* I/O + HC */ +#define I_V_IO2 7 /* I/O only */ +#define I_V_EGZ 010 /* ext grp, 1 op + 0 */ +#define I_V_EG2 011 /* ext grp, 2 op */ +#define I_V_ALT 012 /* alternate use instr */ +#define I_NPN (I_V_NPN << I_V_FL) +#define I_NPC (I_V_NPC << I_V_FL) +#define I_MRF (I_V_MRF << I_V_FL) +#define I_ASH (I_V_ASH << I_V_FL) +#define I_ESH (I_V_ESH << I_V_FL) +#define I_EMR (I_V_EMR << I_V_FL) +#define I_IO1 (I_V_IO1 << I_V_FL) +#define I_IO2 (I_V_IO2 << I_V_FL) +#define I_EGZ (I_V_EGZ << I_V_FL) +#define I_EG2 (I_V_EG2 << I_V_FL) +#define I_ALT (I_V_ALT << I_V_FL) + +static const int32 masks[] = { + 0177777, 0176777, 0074000, 0170000, + 0177760, 0177777, 0176700, 0177700, + 0177777, 0177777, 0177777 + }; + +static const char *opcode[] = { + +/* These mnemonics are used by debug printouts, so put them first. */ + + "$LIBR", "$LIBX", ".TICK", ".TNAM", /* RTE-6/VM OS firmware */ + ".STIO", ".FNW", ".IRT", ".LLS", + ".SIP", ".YLD", ".CPM", ".ETEQ", + ".ENTN", "$OTST", ".ENTC", ".DSPI", + "$DCPC", "$MPV", "$DEV", "$TBG", /* alternates for dual-use */ + + ".PMAP", "$LOC", "$VTST",/* --- */ /* RTE-6/VM VMA firmware */ +/* --- --- --- --- */ + ".IMAP", ".IMAR", ".JMAP", ".JMAR", + ".LPXR", ".LPX", ".LBPR", ".LBP", + + ".EMIO", "MMAP", "$ETST",/* --- */ /* RTE-IV EMA firmware */ +/* --- --- --- --- */ +/* --- --- --- --- */ +/* --- --- --- */ ".EMAP", + +/* Regular mnemonics. */ + + "NOP", "NOP", "AND", "JSB", + "XOR", "JMP", "IOR", "ISZ", + "ADA", "ADB" ,"CPA", "CPB", + "LDA", "LDB", "STA", "STB", + "DIAG", "ASL", "LSL", "TIMER", + "RRL", "ASR", "LSR", "RRR", + "MPY", "DIV", "DLD", "DST", + "FAD", "FSB", "FMP", "FDV", + "FIX", "FLT", + "STO", "CLO", "SOC", "SOS", + "HLT", "STF", "CLF", + "SFC", "SFS", "MIA", "MIB", + "LIA", "LIB", "OTA", "OTB", + "STC", "CLC", + "SYA", "USA", "PAA", "PBA", + "XMA", + "XLA", "XSA", "XCA", "LFA", + "RSA", "RVA", + "MBI", "MBF", + "MBW", "MWI", "MWF", "MWW", + "SYB", "USB", "PAB", "PBB", + "SSM", "JRS", + "XMM", "XMS", "XMB", + "XLB", "XSB", "XCB", "LFB", + "RSB", "RVB", "DJP", "DJS", + "SJP", "SJS", "UJP", "UJS", + "SAX", "SBX", "CAX", "CBX", + "LAX", "LBX", "STX", + "CXA", "CXB", "LDX", + "ADX", "XAX", "XBX", + "SAY", "SBY", "CAY", "CBY", + "LAY", "LBY", "STY", + "CYA", "CYB", "LDY", + "ADY", "XAY", "XBY", + "ISX", "DSX", "JLY", "LBT", + "SBT", "MBT", "CBT", "SBT", + "ISY", "DSY", "JPY", "SBS", + "CBS", "TBS", "CMW", "MVW", + NULL, /* decode only */ + NULL + }; + +static const int32 opc_val[] = { + 0105340+I_NPN, 0105341+I_NPN, 0105342+I_NPN, 0105343+I_NPN, /* RTE-6/VM OS */ + 0105344+I_NPN, 0105345+I_NPN, 0105346+I_NPN, 0105347+I_NPN, + 0105350+I_NPN, 0105351+I_NPN, 0105352+I_NPN, 0105353+I_NPN, + 0105354+I_ALT, 0105355+I_ALT, 0105356+I_ALT, 0105357+I_ALT, + 0105354+I_NPN, 0105355+I_NPN, 0105356+I_NPN, 0105357+I_NPN, /* alternates */ + + 0105240+I_ALT, 0105241+I_ALT, 0105242+I_ALT, /* --- */ /* RTE-6/VM VMA */ +/* --- --- --- --- */ + 0105250+I_NPN, 0105251+I_NPN, 0105252+I_NPN, 0105253+I_NPN, + 0105254+I_NPN, 0105255+I_NPN, 0105256+I_NPN, 0105257+I_ALT, + + 0105240+I_NPN, 0105241+I_NPN, 0105242+I_NPN, /* RTE-IV EMA */ +/* --- --- --- --- */ +/* --- --- --- --- */ +/* --- --- --- */ 0105257+I_NPN, + + 0000000+I_NPN, 0002000+I_NPN, 0010000+I_MRF, 0014000+I_MRF, + 0020000+I_MRF, 0024000+I_MRF, 0030000+I_MRF, 0034000+I_MRF, + 0040000+I_MRF, 0044000+I_MRF, 0050000+I_MRF, 0054000+I_MRF, + 0060000+I_MRF, 0064000+I_MRF, 0070000+I_MRF, 0074000+I_MRF, + 0100000+I_NPN, 0100020+I_ESH, 0100040+I_ESH, 0100060+I_NPN, + 0100100+I_ESH, 0101020+I_ESH, 0101040+I_ESH, 0101100+I_ESH, + 0100200+I_EMR, 0100400+I_EMR, 0104200+I_EMR, 0104400+I_EMR, + 0105000+I_EMR, 0105020+I_EMR, 0105040+I_EMR, 0105060+I_EMR, + 0105100+I_NPN, 0105120+I_NPN, + 0102101+I_NPN, 0103101+I_NPN, 0102201+I_NPC, 0102301+I_NPC, + 0102000+I_IO1, 0102100+I_IO2, 0103100+I_IO2, + 0102200+I_IO1, 0102300+I_IO1, 0102400+I_IO1, 0106400+I_IO1, + 0102500+I_IO1, 0106500+I_IO1, 0102600+I_IO1, 0106600+I_IO1, + 0102700+I_IO1, 0106700+I_IO1, + 0101710+I_NPN, 0101711+I_NPN, 0101712+I_NPN, 0101713+I_NPN, + 0101722+I_NPN, + 0101724+I_EMR, 0101725+I_EMR, 0101726+I_EMR, 0101727+I_NPN, + 0101730+I_NPN, 0101731+I_NPN, + 0105702+I_NPN, 0105703+I_NPN, + 0105704+I_NPN, 0105705+I_NPN, 0105706+I_NPN, 0105707+I_NPN, + 0105710+I_NPN, 0105711+I_NPN, 0105712+I_NPN, 0105713+I_NPN, + 0105714+I_EMR, 0105715+I_EG2, + 0105720+I_NPN, 0105721+I_NPN, 0105722+I_NPN, + 0105724+I_EMR, 0105725+I_EMR, 0105726+I_EMR, 0105727+I_NPN, + 0105730+I_NPN, 0105731+I_NPN, 0105732+I_EMR, 0105733+I_EMR, + 0105734+I_EMR, 0105735+I_EMR, 0105736+I_EMR, 0105737+I_EMR, + 0101740+I_EMR, 0105740+I_EMR, 0101741+I_NPN, 0105741+I_NPN, + 0101742+I_EMR, 0105742+I_EMR, 0105743+I_EMR, + 0101744+I_NPN, 0105744+I_NPN, 0105745+I_EMR, + 0105746+I_EMR, 0101747+I_NPN, 0105747+I_NPN, + 0101750+I_EMR, 0105750+I_EMR, 0101751+I_NPN, 0105751+I_NPN, + 0101752+I_EMR, 0105752+I_EMR, 0105753+I_EMR, + 0101754+I_NPN, 0105754+I_NPN, 0105755+I_EMR, + 0105756+I_EMR, 0101757+I_NPN, 0105757+I_NPN, + 0105760+I_NPN, 0105761+I_NPN, 0105762+I_EMR, 0105763+I_NPN, + 0105764+I_NPN, 0105765+I_EGZ, 0105766+I_EGZ, 0105767+I_NPN, + 0105770+I_NPN, 0105771+I_NPN, 0105772+I_EMR, 0105773+I_EG2, + 0105774+I_EG2, 0105775+I_EG2, 0105776+I_EGZ, 0105777+I_EGZ, + 0000000+I_ASH, /* decode only */ + -1 + }; + +/* Decode tables for shift and alter/skip groups */ + +static const char *stab[] = { + "ALS", "ARS", "RAL", "RAR", "ALR", "ERA", "ELA", "ALF", + "BLS", "BRS", "RBL", "RBR", "BLR", "ERB", "ELB", "BLF", + "CLA", "CMA", "CCA", "CLB", "CMB", "CCB", + "SEZ", "CLE", "CLE", "CME", "CCE", + "SSA", "SSB", "SLA", "SLB", + "ALS", "ARS", "RAL", "RAR", "ALR", "ERA", "ELA", "ALF", + "BLS", "BRS", "RBL", "RBR", "BLR", "ERB", "ELB", "BLF", + "INA", "INB", "SZA", "SZB", "RSS", + NULL + }; + +static const int32 mtab[] = { + 0007700, 0007700, 0007700, 0007700, 0007700, 0007700, 0007700, 0007700, + 0007700, 0007700, 0007700, 0007700, 0007700, 0007700, 0007700, 0007700, + 0007400, 0007400, 0007400, 0007400, 0007400, 0007400, + 0002040, 0002040, 0002300, 0002300, 0002300, + 0006020, 0006020, 0004010, 0004010, + 0006027, 0006027, 0006027, 0006027, 0006027, 0006027, 0006027, 0006027, + 0006027, 0006027, 0006027, 0006027, 0006027, 0006027, 0006027, 0006027, + 0006004, 0006004, 0006002, 0006002, 0002001, + 0 + }; + +static const int32 vtab[] = { + 0001000, 0001100, 0001200, 0001300, 0001400, 0001500, 0001600, 0001700, + 0005000, 0005100, 0005200, 0005300, 0005400, 0005500, 0005600, 0005700, + 0002400, 0003000, 0003400, 0006400, 0007000, 0007400, + 0002040, 0000040, 0002100, 0002200, 0002300, + 0002020, 0006020, 0000010, 0004010, + 0000020, 0000021, 0000022, 0000023, 0000024, 0000025, 0000026, 0000027, + 0004020, 0004021, 0004022, 0004023, 0004024, 0004025, 0004026, 0004027, + 0002004, 0006004, 0002002, 0006002, 0002001, + -1 + }; + +/* Symbolic decode + + Inputs: + *of = output stream + addr = current PC + *val = pointer to data + *uptr = pointer to unit + sw = switches + Outputs: + return = status code +*/ + +#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 cflag, cm, i, j, inst, disp; +uint32 irq; + +cflag = (uptr == NULL) || (uptr == &cpu_unit); +inst = (int32) val[0]; +if (sw & SWMASK ('A')) { /* ASCII? */ + if (inst > 0377) return SCPE_ARG; + fprintf (of, FMTASC (inst & 0177)); + return SCPE_OK; + } +if (sw & SWMASK ('C')) { /* characters? */ + fprintf (of, FMTASC ((inst >> 8) & 0177)); + fprintf (of, FMTASC (inst & 0177)); + return SCPE_OK; + } +if (!(sw & SWMASK ('M'))) return SCPE_ARG; + +/* If we are being called as a result of a VM stop to display the next + instruction to be executed, check to see if an interrupt is pending and not + deferred. If so, then display the interrupt source and the trap cell + instruction as the instruction to be executed, rather than the instruction at + the current PC. +*/ + +if (sw & SIM_SW_STOP) { /* simulator stop? */ + irq = calc_int (); /* check interrupt */ + + if (irq && (!ion_defer || !calc_defer())) { /* pending interrupt and not deferred? */ + addr = irq; /* set display address to trap cell */ + val[0] = inst = ReadIO (irq, SMAP); /* load trap cell instruction */ + val[1] = ReadIO (irq + 1, SMAP); /* might be multi-word */ + val[2] = ReadIO (irq + 2, SMAP); /* although it's unlikely */ + fprintf (of, "IAK %2o: ", irq); /* report acknowledged interrupt */ + } + } + +for (i = 0; opc_val[i] >= 0; i++) { /* loop thru ops */ + j = (opc_val[i] >> I_V_FL) & I_M_FL; /* get class */ + if ((opc_val[i] & DMASK) == (inst & masks[j])) { /* match? */ + switch (j) { /* case on class */ + + case I_V_NPN: /* no operands */ + fprintf (of, "%s", opcode[i]); /* opcode */ + break; + + case I_V_NPC: /* no operands + C */ + fprintf (of, "%s", opcode[i]); + if (inst & I_HC) fprintf (of, " C"); + break; + + case I_V_MRF: /* mem ref */ + disp = inst & I_DISP; /* displacement */ + fprintf (of, "%s ", opcode[i]); /* opcode */ + if (inst & I_CP) { /* current page? */ + if (cflag) + fprintf (of, "%-o", ((uint32) addr & I_PAGENO) | disp); + else + fprintf (of, "C %-o", disp); + } + else fprintf (of, "%-o", disp); /* page zero */ + if (inst & I_IA) fprintf (of, ",I"); + break; + + case I_V_ASH: /* shift, alter-skip */ + cm = FALSE; + for (i = 0; mtab[i] != 0; i++) { + if ((inst & mtab[i]) == vtab[i]) { + inst = inst & ~(vtab[i] & 01777); + if (cm) fprintf (of, ","); + cm = TRUE; + fprintf (of, "%s", stab[i]); + } + } + if (!cm) return SCPE_ARG; /* nothing decoded? */ + break; + + case I_V_ESH: /* extended shift */ + disp = inst & 017; /* shift count */ + if (disp == 0) disp = 16; + fprintf (of, "%s %d", opcode[i], disp); + break; + + case I_V_EMR: /* extended mem ref */ + fprintf (of, "%s %-o", opcode[i], (uint32) val[1] & VAMASK); + if (val[1] & I_IA) fprintf (of, ",I"); + return -1; /* extra word */ + + case I_V_IO1: /* IOT with H/C */ + fprintf (of, "%s %-o", opcode[i], inst & I_DEVMASK); + if (inst & I_HC) fprintf (of, ",C"); + break; + + case I_V_IO2: /* IOT */ + fprintf (of, "%s %-o", opcode[i], inst & I_DEVMASK); + break; + + case I_V_EGZ: /* ext grp 1 op + 0 */ + fprintf (of, "%s %-o", opcode[i], (uint32) val[1] & VAMASK); + if (val[1] & I_IA) fprintf (of, ",I"); + return -2; /* extra words */ + + case I_V_EG2: /* ext grp 2 op */ + fprintf (of, "%s %-o", opcode[i], (uint32) val[1] & VAMASK); + if (val[1] & I_IA) fprintf (of, ",I"); + fprintf (of, " %-o", (uint32) val[2] & VAMASK); + if (val[2] & I_IA) fprintf (of, ",I"); + return -2; /* extra words */ + + case I_V_ALT: /* alternate use instr */ + if ((inst >= 0105354) && + (inst <= 0105357) && /* RTE-6/VM OS range? */ + (addr >= 2) && + (addr <= 077)) /* in trap cell? */ + continue; /* use alternate mnemonic */ + + else if ((inst >= 0105240) && /* RTE-6/VM VMA range? */ + (inst <= 0105257) && + (cpu_unit.flags & UNIT_EMA)) /* EMA enabled? */ + continue; /* use EMA mnemonics */ + + else + fprintf (of, "%s", opcode[i]); /* print opcode */ + break; + } + + return SCPE_OK; + } /* end if */ + } /* end for */ +return SCPE_ARG; +} + +/* Get address with indirection + + Inputs: + *cptr = pointer to input string + Outputs: + val = address + -1 if error +*/ + +static int32 get_addr (char *cptr) +{ +int32 d; +t_stat r; +char gbuf[CBUFSIZE]; + +cptr = get_glyph (cptr, gbuf, ','); /* get next field */ +d = (int32) get_uint (gbuf, 8, VAMASK, &r); /* construe as addr */ +if (r != SCPE_OK) return -1; +if (*cptr != 0) { /* more? */ + cptr = get_glyph (cptr, gbuf, 0); /* look for indirect */ + if (*cptr != 0) return -1; /* should be done */ + if (strcmp (gbuf, "I")) return -1; /* I? */ + d = d | I_IA; + } +return d; +} + +/* Symbolic input + + Inputs: + *iptr = 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 (char *iptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw) +{ +int32 cflag, d, i, j, k, clef, tbits; +t_stat r, ret; +char *cptr, gbuf[CBUFSIZE]; + +cflag = (uptr == NULL) || (uptr == &cpu_unit); +while (isspace (*iptr)) iptr++; /* absorb spaces */ +if ((sw & SWMASK ('A')) || ((*iptr == '\'') && iptr++)) { /* ASCII char? */ + if (iptr[0] == 0) return SCPE_ARG; /* must have 1 char */ + val[0] = (t_value) iptr[0] & 0177; + return SCPE_OK; + } +if ((sw & SWMASK ('C')) || ((*iptr == '"') && iptr++)) { /* char string? */ + if (iptr[0] == 0) return SCPE_ARG; /* must have 1 char */ + val[0] = (((t_value) iptr[0] & 0177) << 8) | + ((t_value) iptr[1] & 0177); + return SCPE_OK; + } + +ret = SCPE_OK; +cptr = get_glyph (iptr, gbuf, 0); /* get opcode */ +for (i = 0; (opcode[i] != NULL) && (strcmp (opcode[i], gbuf) != 0) ; i++) ; +if (opcode[i]) { /* found opcode? */ + val[0] = opc_val[i] & DMASK; /* get value */ + j = (opc_val[i] >> I_V_FL) & I_M_FL; /* get class */ + switch (j) { /* case on class */ + + case I_V_NPN: /* no operand */ + break; + + case I_V_NPC: /* no operand + C */ + if (*cptr != 0) { + cptr = get_glyph (cptr, gbuf, 0); + if (strcmp (gbuf, "C")) return SCPE_ARG; + val[0] = val[0] | I_HC; + } + break; + + case I_V_MRF: /* mem ref */ + cptr = get_glyph (cptr, gbuf, 0); /* get next field */ + k = strcmp (gbuf, "C"); + if (k == 0) { /* C specified? */ + val[0] = val[0] | I_CP; + cptr = get_glyph (cptr, gbuf, 0); + } + else { + k = strcmp (gbuf, "Z"); + if (k == 0) /* Z specified? */ + cptr = get_glyph (cptr, gbuf, ','); + } + if ((d = get_addr (gbuf)) < 0) return SCPE_ARG; + if ((d & VAMASK) <= I_DISP) val[0] = val[0] | d; + else if (cflag && !k && (((addr ^ d) & I_PAGENO) == 0)) + val[0] = val[0] | (d & (I_IA | I_DISP)) | I_CP; + else return SCPE_ARG; + break; + + case I_V_ESH: /* extended shift */ + cptr = get_glyph (cptr, gbuf, 0); + d = (int32) get_uint (gbuf, 10, 16, &r); + if ((r != SCPE_OK) || (d == 0)) return SCPE_ARG; + val[0] = val[0] | (d & 017); + break; + + case I_V_EMR: /* extended mem ref */ + cptr = get_glyph (cptr, gbuf, 0); /* get next field */ + if ((d = get_addr (gbuf)) < 0) return SCPE_ARG; + val[1] = d; + ret = -1; + break; + + case I_V_IO1: /* IOT + optional C */ + cptr = get_glyph (cptr, gbuf, ','); /* get device */ + d = (int32) get_uint (gbuf, 8, I_DEVMASK, &r); + if (r != SCPE_OK) return SCPE_ARG; + val[0] = val[0] | d; + if (*cptr != 0) { + cptr = get_glyph (cptr, gbuf, 0); + if (strcmp (gbuf, "C")) return SCPE_ARG; + val[0] = val[0] | I_HC; + } + break; + + case I_V_IO2: /* IOT */ + cptr = get_glyph (cptr, gbuf, 0); /* get device */ + d = (int32) get_uint (gbuf, 8, I_DEVMASK, &r); + if (r != SCPE_OK) return SCPE_ARG; + val[0] = val[0] | d; + break; + + case I_V_EGZ: /* ext grp 1 op + 0 */ + cptr = get_glyph (cptr, gbuf, 0); /* get next field */ + if ((d = get_addr (gbuf)) < 0) return SCPE_ARG; + val[1] = d; + val[2] = 0; + ret = -2; + break; + + case I_V_EG2: /* ext grp 2 op */ + cptr = get_glyph (cptr, gbuf, 0); /* get next field */ + if ((d = get_addr (gbuf)) < 0) return SCPE_ARG; + cptr = get_glyph (cptr, gbuf, 0); /* get next field */ + if ((k = get_addr (gbuf)) < 0) return SCPE_ARG; + val[1] = d; + val[2] = k; + ret = -2; + break; + } /* end case */ + + if (*cptr != 0) return SCPE_ARG; /* junk at end? */ + return ret; + } /* end if opcode */ + +/* Shift or alter-skip + + Each opcode is matched by a mask, specifiying the bits affected, and + the value, specifying the value. As opcodes are processed, the mask + values are used to specify which fields have already been filled in. + + The mask has two subfields, the type bits (A/B and A/S), and the field + bits. The type bits, once specified by any instruction, must be + consistent in all other instructions. The mask bits assure that no + field is filled in twice. + + Two special cases: + + 1. The dual shift field in shift requires checking how much of the + target word has been filled in before assigning the shift value. + To implement this, shifts are listed twice is the decode table. + If the current subopcode is a shift in the first part of the table + (entries 0..15), and CLE has been seen or the first shift field is + filled in, the code forces a mismatch. The glyph will match in + the second part of the table. + + 2. CLE processing must be deferred until the instruction can be + classified as shift or alter-skip, since it has two different + bit values in the two classes. To implement this, CLE seen is + recorded as a flag and processed after all other subopcodes. +*/ + +clef = FALSE; +tbits = 0; +val[0] = 0; +for (cptr = get_glyph (iptr, gbuf, ','); gbuf[0] != 0; + cptr = get_glyph (cptr, gbuf, ',')) { /* loop thru glyphs */ + if (strcmp (gbuf, "CLE") == 0) { /* CLE? */ + if (clef) return SCPE_ARG; /* already seen? */ + clef = TRUE; /* set flag */ + continue; + } + for (i = 0; stab[i] != NULL; i++) { /* find subopcode */ + if ((strcmp (gbuf, stab[i]) == 0) && + ((i >= 16) || (!clef && ((val[0] & 001710) == 0)))) break; + } + if (stab[i] == NULL) return SCPE_ARG; + if (tbits & mtab[i] & (I_AB | I_ASKP) & (vtab[i] ^ val[0])) + return SCPE_ARG; + if (tbits & mtab[i] & ~(I_AB | I_ASKP)) return SCPE_ARG; + tbits = tbits | mtab[i]; /* fill type+mask */ + val[0] = val[0] | vtab[i]; /* fill value */ + } +if (clef) { /* CLE seen? */ + if (val[0] & I_ASKP) { /* alter-skip? */ + if (tbits & 0100) return SCPE_ARG; /* already filled in? */ + else val[0] = val[0] | 0100; + } + else val[0] = val[0] | 040; /* fill in shift */ + } +return ret; +} + + +/* Format a character into a printable string. + + Control characters are translated to readable strings. Printable characters + retain their original form but are enclosed in single quotes. Characters + outside of the ASCII range are represented as escaped octal values. +*/ + +const char *fmt_char (uint8 ch) +{ +static const char *const ctl [] = { "NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL", + "BS", "HT", "LF", "VT", "FF", "CR", "SO", "SI", + "DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB", + "CAN", "EM", "SUB", "ESC", "FS", "GS", "RS", "US" }; +static char rep [5]; + +if (ch <= '\037') /* ASCII control character? */ + return ctl [ch]; /* return string representation */ + +else if (ch == '\177') /* ASCII delete? */ + return "DEL"; /* return string representation */ + +else if (ch > '\177') { /* beyond printable range? */ + sprintf (rep, "\\%03o", ch); /* format value */ + return rep; /* return escaped octal code */ + } + +else { /* printable character */ + rep [0] = '\''; /* form string */ + rep [1] = ch; /* containing character */ + rep [2] = '\''; + rep [3] = '\0'; + return rep; /* return quoted character */ + } +} + + +/* Set select code */ + +t_stat hp_setsc (UNIT *uptr, int32 num, char *cptr, void *desc) +{ +DEVICE *dptr = (DEVICE *) desc; +DIB *dibptr; +int32 i, newdev; +t_stat r; + +if (cptr == NULL) + return SCPE_ARG; + +if ((desc == NULL) || (num > 1)) + return SCPE_IERR; + +dibptr = (DIB *) dptr->ctxt; + +if (dibptr == NULL) + return SCPE_IERR; + +newdev = (int32) get_uint (cptr, 8, I_DEVMASK - num, &r); + +if (r != SCPE_OK) + return r; + +if (newdev < VARDEV) + return SCPE_ARG; + +for (i = 0; i <= num; i++, dibptr++) + dibptr->select_code = newdev + i; + +return SCPE_OK; +} + + +/* Show select code */ + +t_stat hp_showsc (FILE *st, UNIT *uptr, int32 num, void *desc) +{ +DEVICE *dptr = (DEVICE *) desc; +DIB *dibptr; +int32 i; + +if ((desc == NULL) || (num > 1)) + return SCPE_IERR; + +dibptr = (DIB *) dptr->ctxt; + +if (dibptr == NULL) + return SCPE_IERR; + +fprintf (st, "select code=%o", dibptr->select_code); + +for (i = 1; i <= num; i++) + fprintf (st, "/%o", dibptr->select_code + i); + +return SCPE_OK; +} + + +/* Set device number */ + +t_stat hp_setdev (UNIT *uptr, int32 num, char *cptr, void *desc) +{ +return hp_setsc (uptr, num, cptr, desc); +} + + +/* Show device number */ + +t_stat hp_showdev (FILE *st, UNIT *uptr, int32 num, void *desc) +{ +t_stat result; + +result = hp_showsc (st, uptr, num, desc); + +if (result == SCPE_OK) + fputc ('\n', st); + +return result; +} diff --git a/HP2100/hp_disclib.c b/HP2100/hp_disclib.c index 02a1173d..869363b0 100644 --- a/HP2100/hp_disclib.c +++ b/HP2100/hp_disclib.c @@ -1,6 +1,6 @@ /* hp_disclib.c: HP MAC/ICD disc controller simulator library - Copyright (c) 2011-2012, J. David Bryan + Copyright (c) 2011-2014, J. David Bryan Copyright (c) 2004-2011, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a @@ -24,6 +24,11 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from the authors. + 24-Dec-14 JDB Added casts for explicit downward conversions + 27-Oct-14 JDB Corrected the relative movement calculation in start_seek + 20-Dec-12 JDB sim_is_active() now returns t_bool + 24-Oct-12 JDB Changed CNTLR_OPCODE to title case to avoid name clash + 07-May-12 JDB Corrected end-of-track delay time logic 02-May-12 JDB First release 09-Nov-11 JDB Created disc controller common library from DS simulator @@ -307,8 +312,8 @@ #define GET_HEAD(p) (((p) >> DL_V_HEAD) & DL_M_HEAD) #define GET_SECTOR(p) (((p) >> DL_V_SECTOR) & DL_M_SECTOR) -#define SET_HEAD(c) (((c)->head & DL_M_HEAD) << DL_V_HEAD) -#define SET_SECTOR(c) (((c)->sector & DL_M_SECTOR) << DL_V_SECTOR) +#define SET_HEAD(c) (uint16) (((c)->head & DL_M_HEAD) << DL_V_HEAD) +#define SET_SECTOR(c) (uint16) (((c)->sector & DL_M_SECTOR) << DL_V_SECTOR) /* Drive properties table. @@ -593,8 +598,8 @@ set_timer (cvptr, CLEAR); /* stop the command wait opcode = GET_OPCODE (cvptr->buffer [0]); /* get the opcode from the command */ -if (opcode > last_opcode) /* is the opcode invalid? */ - props = &cmd_props [invalid_opcode]; /* undefined commands clear prior status */ +if (opcode > Last_Opcode) /* is the opcode invalid? */ + props = &cmd_props [Invalid_Opcode]; /* undefined commands clear prior status */ else /* the opcode is potentially valid */ props = &cmd_props [opcode]; /* get the command properties */ @@ -771,7 +776,7 @@ else if (uptr) { /* otherwise, we have a uptr->wait = cvptr->cmd_time; /* most commands use the command delay */ if (props->unit_access) { /* does the command access the unit? */ - is_seeking = sim_is_active (uptr) != 0; /* see if the unit is busy */ + is_seeking = sim_is_active (uptr); /* see if the unit is busy */ if (is_seeking) /* if a seek is in progress, */ uptr->wait = 0; /* set for no unit activation */ @@ -793,7 +798,7 @@ cvptr->eod = CLEAR; /* clear the end of data switch (cvptr->opcode) { /* dispatch the command */ - case cold_load_read: + case Cold_Load_Read: cvptr->cylinder = 0; /* set the cylinder address to 0 */ cvptr->head = GET_CHEAD (cvptr->buffer [0]); /* set the head */ cvptr->sector = GET_CSECT (cvptr->buffer [0]); /* and sector from the command */ @@ -801,7 +806,7 @@ switch (cvptr->opcode) { /* dispatch the command if (is_seeking) { /* if a seek is in progress, */ uptr->STAT |= DL_S2SC; /* a Seek Check occurs */ cvptr->file_mask = DL_FSPEN; /* enable sparing */ - uptr->OP = read; /* start the read on the seek completion */ + uptr->OP = Read; /* start the read on the seek completion */ uptr->PHASE = start_phase; /* and reset the command phase */ return uptr; /* to allow the seek to complete normally */ } @@ -812,7 +817,7 @@ switch (cvptr->opcode) { /* dispatch the command break; - case seek: + case Seek: cvptr->cylinder = cvptr->buffer [1]; /* get the supplied cylinder */ cvptr->head = GET_HEAD (cvptr->buffer [2]); /* and head */ cvptr->sector = GET_SECTOR (cvptr->buffer [2]); /* and sector addresses */ @@ -826,9 +831,9 @@ switch (cvptr->opcode) { /* dispatch the command break; - case request_status: - cvptr->buffer [0] = /* set the Status-1 value */ - cvptr->spd_unit | SET_S1STAT (cvptr->status); /* into the buffer */ + case Request_Status: + cvptr->buffer [0] = (uint16) (cvptr->spd_unit /* set the Status-1 value */ + | SET_S1STAT (cvptr->status)); /* into the buffer */ if (cvptr->type == MAC) /* is this a MAC controller? */ if (unit > unit_limit) /* if the unit number is invalid */ @@ -853,12 +858,12 @@ switch (cvptr->opcode) { /* dispatch the command break; - case request_disc_address: + case Request_Disc_Address: set_address (cvptr, 0); /* return the CHS values in buffer 0-1 */ break; - case request_sector_address: + case Request_Sector_Address: if (unit > unit_limit) /* if the unit number is invalid */ rptr = NULL; /* it does not correspond to a unit */ else /* otherwise, the unit is valid */ @@ -871,9 +876,9 @@ switch (cvptr->opcode) { /* dispatch the command break; - case request_syndrome: - cvptr->buffer [0] = /* return the Status-1 value in buffer 0 */ - cvptr->spd_unit | SET_S1STAT (cvptr->status); + case Request_Syndrome: + cvptr->buffer [0] = (uint16) (cvptr->spd_unit /* return the Status-1 value */ + | SET_S1STAT (cvptr->status)); /* in buffer 0 */ set_address (cvptr, 1); /* return the CHS values in buffer 1-2 */ @@ -884,7 +889,7 @@ switch (cvptr->opcode) { /* dispatch the command break; - case address_record: + case Address_Record: cvptr->cylinder = cvptr->buffer [1]; /* get the supplied cylinder */ cvptr->head = GET_HEAD (cvptr->buffer [2]); /* and head */ cvptr->sector = GET_SECTOR (cvptr->buffer [2]); /* and sector addresses */ @@ -892,7 +897,7 @@ switch (cvptr->opcode) { /* dispatch the command break; - case set_file_mask: + case Set_File_Mask: cvptr->file_mask = GET_FMASK (cvptr->buffer [0]); /* get the supplied file mask */ if (cvptr->type == MAC) /* if this is a MAC controller, */ @@ -900,14 +905,14 @@ switch (cvptr->opcode) { /* dispatch the command break; - case initialize: + case Initialize: if (uptr) /* if the unit is valid, */ cvptr->spd_unit |= /* merge the SPD flags */ SET_S1SPD (GET_SPD (cvptr->buffer [0])); /* from the command word */ break; - case verify: + case Verify: cvptr->verify_count = cvptr->buffer [1]; /* get the supplied sector count */ break; @@ -1077,35 +1082,35 @@ switch ((CNTLR_PHASE) uptr->PHASE) { /* dispatch the phase */ case start_phase: switch (opcode) { /* dispatch the current operation */ - case recalibrate: - case seek: + case Recalibrate: + case Seek: if (start_seek (cvptr, uptr, opcode, end_phase) /* start the seek; if it succeeded, */ && (cvptr->type == MAC)) /* and this a MAC controller, */ dl_idle_controller (cvptr); /* then go idle until it completes */ break; - case cold_load_read: - if (start_seek (cvptr, uptr, read, start_phase)) /* start the seek; did it succeed? */ + case Cold_Load_Read: + if (start_seek (cvptr, uptr, Read, start_phase)) /* start the seek; did it succeed? */ cvptr->file_mask = DL_FSPEN; /* set sparing enabled now */ break; - case read: - case read_with_offset: - case read_without_verify: + case Read: + case Read_With_Offset: + case Read_Without_Verify: cvptr->length = DL_WPSEC; /* transfer just the data */ result = start_read (cvptr, uptr); /* start the sector read */ break; - case read_full_sector: + case Read_Full_Sector: cvptr->length = DL_WPFSEC; /* transfer the header/data/trailer */ result = start_read (cvptr, uptr); /* start the sector read */ break; - case verify: + case Verify: cvptr->length = 0; /* no data transfer needed */ result = start_read (cvptr, uptr); /* start the sector read */ @@ -1117,29 +1122,29 @@ switch ((CNTLR_PHASE) uptr->PHASE) { /* dispatch the phase */ break; - case write: - case initialize: + case Write: + case Initialize: cvptr->length = DL_WPSEC; /* transfer just the data */ start_write (cvptr, uptr); /* start the sector write */ break; - case write_full_sector: + case Write_Full_Sector: cvptr->length = DL_WPFSEC; /* transfer the header/data/trailer */ start_write (cvptr, uptr); /* start the sector write */ break; - case request_status: - case request_sector_address: - case clear: - case address_record: - case request_syndrome: - case set_file_mask: - case load_tio_register: - case request_disc_address: - case end: - case wakeup: + case Request_Status: + case Request_Sector_Address: + case Clear: + case Address_Record: + case Request_Syndrome: + case Set_File_Mask: + case Load_TIO_Register: + case Request_Disc_Address: + case End: + case Wakeup: dl_service_controller (cvptr, uptr); /* the controller service handles these */ break; @@ -1153,13 +1158,13 @@ switch ((CNTLR_PHASE) uptr->PHASE) { /* dispatch the phase */ case data_phase: switch (opcode) { /* dispatch the current operation */ - case read: - case read_full_sector: - case read_with_offset: - case read_without_verify: - case write: - case write_full_sector: - case initialize: + case Read: + case Read_Full_Sector: + case Read_With_Offset: + case Read_Without_Verify: + case Write: + case Write_Full_Sector: + case Initialize: break; /* data transfers are handled by the caller */ @@ -1173,8 +1178,8 @@ switch ((CNTLR_PHASE) uptr->PHASE) { /* dispatch the phase */ case end_phase: switch (opcode) { /* dispatch the operation command */ - case recalibrate: - case seek: + case Recalibrate: + case Seek: if (cvptr->type == ICD) /* is this an ICD controller? */ dl_end_command (cvptr, drive_attention); /* seeks end with Drive Attention status */ else /* if not an ICD controller, */ @@ -1182,22 +1187,22 @@ switch ((CNTLR_PHASE) uptr->PHASE) { /* dispatch the phase */ break; - case read: - case read_full_sector: - case read_with_offset: + case Read: + case Read_Full_Sector: + case Read_With_Offset: end_read (cvptr, uptr); /* end the sector read */ break; - case read_without_verify: + case Read_Without_Verify: if (cvptr->sector == 0) /* have we reached the end of the track? */ - uptr->OP = read; /* begin verifying the next time */ + uptr->OP = Read; /* begin verifying the next time */ end_read (cvptr, uptr); /* end the sector read */ break; - case verify: + case Verify: cvptr->verify_count = /* decrement the count */ (cvptr->verify_count - 1) & DMASK; /* modulo 65536 */ @@ -1208,16 +1213,16 @@ switch ((CNTLR_PHASE) uptr->PHASE) { /* dispatch the phase */ break; - case write: - case write_full_sector: - case initialize: + case Write: + case Write_Full_Sector: + case Initialize: result = end_write (cvptr, uptr); /* end the sector write */ break; - case request_status: - case request_sector_address: - case request_disc_address: + case Request_Status: + case Request_Sector_Address: + case Request_Disc_Address: dl_service_controller (cvptr, uptr); /* the controller service handles these */ break; @@ -1277,33 +1282,33 @@ switch ((CNTLR_PHASE) uptr->PHASE) { /* dispatch the phase */ case start_phase: case end_phase: switch (opcode) { /* dispatch the current operation */ - case request_status: + case Request_Status: dl_end_command (cvptr, cvptr->status); /* the command completes with no status change */ break; - case clear: + case Clear: dl_clear_controller (cvptr, uptr, soft_clear); /* clear the controller */ dl_end_command (cvptr, normal_completion); /* the command is complete */ break; - case request_sector_address: - case address_record: - case request_syndrome: - case set_file_mask: - case load_tio_register: - case request_disc_address: + case Request_Sector_Address: + case Address_Record: + case Request_Syndrome: + case Set_File_Mask: + case Load_TIO_Register: + case Request_Disc_Address: dl_end_command (cvptr, normal_completion); /* the command is complete */ break; - case end: + case End: dl_idle_controller (cvptr); /* the command completes with the controller idle */ break; - case wakeup: + case Wakeup: dl_end_command (cvptr, unit_available); /* the command completes with Unit Available status */ break; @@ -1318,11 +1323,11 @@ switch ((CNTLR_PHASE) uptr->PHASE) { /* dispatch the phase */ case data_phase: switch (opcode) { /* dispatch the current operation */ - case seek: - case verify: - case address_record: - case read_with_offset: - case load_tio_register: + case Seek: + case Verify: + case Address_Record: + case Read_With_Offset: + case Load_TIO_Register: if (cvptr->length > 1) /* at least one more parameter to input? */ set_timer (cvptr, SET); /* restart the timer for the next parameter */ else /* this is the last one */ @@ -1330,10 +1335,10 @@ switch ((CNTLR_PHASE) uptr->PHASE) { /* dispatch the phase */ break; - case request_status: - case request_sector_address: - case request_syndrome: - case request_disc_address: + case Request_Status: + case Request_Sector_Address: + case Request_Syndrome: + case Request_Disc_Address: if (cvptr->length > 0) /* at least one more to parameter output? */ set_timer (cvptr, SET); /* restart the timer for the next parameter */ else /* this is the last one */ @@ -1504,8 +1509,8 @@ for (unit = 0; unit < unit_count; unit++) { /* loop through the unit if (!(uptr->flags & UNIT_DIS)) { /* is the unit enabled? */ if (clear_type == hard_clear /* a hard clear cancels */ - && uptr->OP != seek /* only if not seeking */ - && uptr->OP != recalibrate) /* or recalibrating */ + && uptr->OP != Seek /* only if not seeking */ + && uptr->OP != Recalibrate) /* or recalibrating */ sim_cancel (uptr); /* cancel the service */ uptr->STAT &= ~DL_S2CPS; /* do "Controller Preset" for the unit */ @@ -1596,7 +1601,7 @@ return SCPE_OK; CNTLR_CLASS dl_classify (CNTLR_VARS cntlr) { if (cntlr.type <= last_type /* if the controller type is legal */ - && cntlr.opcode <= last_opcode /* and the opcode is legal */ + && cntlr.opcode <= Last_Opcode /* and the opcode is legal */ && cmd_props [cntlr.opcode].valid [cntlr.type]) /* and is defined for this controller, */ return cmd_props [cntlr.opcode].classification; /* then return the command classification */ else /* the type or opcode is illegal */ @@ -1614,7 +1619,7 @@ else /* the type or opcode is const char *dl_opcode_name (CNTLR_TYPE controller, CNTLR_OPCODE opcode) { if (controller <= last_type /* if the controller type is legal */ - && opcode <= last_opcode /* and the opcode is legal */ + && opcode <= Last_Opcode /* and the opcode is legal */ && cmd_props [opcode].valid [controller]) /* and is defined for this controller, */ return opcode_name [opcode]; /* then return the opcode name */ else /* the type or opcode is illegal, */ @@ -1775,7 +1780,7 @@ if (cvptr->eod == SET) { /* is the end of data in return SCPE_OK; } -if (opcode == read_full_sector) { /* are we starting a Read Full Sector command? */ +if (opcode == Read_Full_Sector) { /* are we starting a Read Full Sector command? */ if (cvptr->type == ICD) /* is this an ICD controller? */ cvptr->buffer [0] = 0100377; /* ICD does not support ECC */ else @@ -1788,7 +1793,7 @@ if (opcode == read_full_sector) { /* are we starting a Rea else { /* it's another read command */ offset = 0; /* data starts at the beginning */ - verify = (opcode != read_without_verify); /* set for address verification unless it's a RWV */ + verify = (opcode != Read_Without_Verify); /* set for address verification unless it's a RWV */ } if (! position_sector (cvptr, uptr, verify)) /* position the sector */ @@ -1817,7 +1822,7 @@ return SCPE_OK; /* the read was successf On entry, the end-of-data flag is checked. If it is set, the current read is completed. Otherwise, the command phase is reset to start the next sector, - and the disc service is scheduled to allow for the intersector delay. + and the disc service is set to allow for the intersector delay. Implementation notes: @@ -1832,30 +1837,46 @@ return SCPE_OK; /* the read was successf of the next sector, or the drive will begin the data transfer. Normally, this is not a problem, as the driver clears the FIFO of any - received data after DCPC completion. However, if the file mask disables - auto-seeking (or the last sector on the drive had been read), then the - controller will indicate an End of Cylinder error if the untalk does not - precede the start of the next sector. + received data after DCPC completion. However, if the read terminates + after the last sector of a track, and accessing the next sector would + require an intervening seek, and the file mask disables auto-seeking or + an enabled seek would move the positioner beyond the drive limits, then + the controller will indicate an End of Cylinder error if the untalk does + not arrive before the seek is initiated. The RTE driver (DVA32) and various utilities that manage the disc - directly (e.g., SWTCH) do not appear to account for these bogus errors. - Therefore, we work around the issue by extending the intersector delay - to allow time for an potential untalk whenever the next access will - require an auto-seek. + directly (e.g., SWTCH) do not appear to account for these bogus errors, + so the ICD controller hardware must avoid them in some unknown manner. + We work around the issue by extending the intersector delay to allow time + for a potential untalk whenever the next access would otherwise fail. + + Note that this issue does not occur with writes because DCPC completion + asserts EOI concurrently with the final data byte to terminate the + command. */ static void end_read (CVPTR cvptr, UNIT *uptr) { +uint32 limit; + if (cvptr->eod == SET) /* is the end of data indicated? */ dl_end_command (cvptr, normal_completion); /* complete the command */ else { /* reading continues */ uptr->PHASE = start_phase; /* reset to the start phase */ - - if (cvptr->eoc && cvptr->type) /* at the end of the cylinder and ICD controller? */ - uptr->wait = DL_EOC_TIME; /* delay for the end-of-cylinder time */ - else /* not at EOC or not an ICD controller */ - uptr->wait = cvptr->sector_time; /* delay for the intersector time */ + uptr->wait = cvptr->sector_time; /* delay for the intersector time */ + + if (cvptr->eoc == SET && cvptr->type == ICD) { /* seek will be required and controller is ICD? */ + if (!(cvptr->file_mask & DL_FAUTSK)) /* if auto-seek is disabled */ + limit = cvptr->cylinder; /* then the limit is the current cylinder */ + else if (cvptr->file_mask & DL_FDECR) /* else if enabled and decremental seek */ + limit = 0; /* then the limit is cylinder 0 */ + else /* else the enabled limit is the last cylinder */ + limit = drive_props [GET_MODEL (uptr->flags)].cylinders; + + if (cvptr->cylinder == limit) /* is positioner at the limit? */ + uptr->wait = cvptr->eot_time; /* seek will fail; delay to allow CPU to untalk */ + } } return; @@ -1894,7 +1915,7 @@ return; static void start_write (CVPTR cvptr, UNIT *uptr) { -const t_bool verify = (CNTLR_OPCODE) uptr->OP == write; /* only Write verifies the sector address */ +const t_bool verify = (CNTLR_OPCODE) uptr->OP == Write; /* only Write verifies the sector address */ if ((uptr->flags & UNIT_WPROT) /* is the unit write protected, */ || !verify && !(uptr->flags & UNIT_FMT)) /* or is formatting required but not enabled? */ @@ -1942,7 +1963,7 @@ static t_stat end_write (CVPTR cvptr, UNIT *uptr) uint32 count; uint16 pad; const CNTLR_OPCODE opcode = (CNTLR_OPCODE) uptr->OP; -const uint32 offset = (opcode == write_full_sector ? 3 : 0); +const uint32 offset = (opcode == Write_Full_Sector ? 3 : 0); if (uptr->flags & UNIT_UNLOAD) { /* if the drive is not ready, */ dl_end_command (cvptr, access_not_ready); /* terminate the command with an error */ @@ -1981,12 +2002,12 @@ return SCPE_OK; /* Position the disc image file at the current sector. - The image file is positioned at the byte address corresponding to the - controller's current cylinder, head, and sector address. Positioning may - involve an auto-seek if a prior read or write addressed the final sector in a - cylinder. If a seek is initiated or an error is detected, the routine - returns FALSE to indicate that the positioning was not performed. If the - file was positioned, the routine returns TRUE. + The image file is positioned at the byte address corresponding to the drive's + current cylinder and the controller's current head and sector addresses. + Positioning may involve an auto-seek if a prior read or write addressed the + final sector of a cylinder. If a seek is initiated or an error is detected, + the routine returns FALSE to indicate that the positioning was not performed. + If the file was positioned, the routine returns TRUE. On entry, if the controller's end-of-cylinder flag is set, a prior read or write addressed the final sector in the current cylinder. If the file mask @@ -2000,21 +2021,23 @@ return SCPE_OK; seek completion and the command state unchanged. When the service is reentered, the read or write will continue on the new cylinder. - If the EOC flag was not set, the drive position is checked against the - controller position. If they are different (as may occur with an Address - Record command that specified a different location than the last Seek - command), a seek is started to the correct cylinder, and the routine returns - with the disc service scheduled for seek completion as above. + If the EOC flag was not set, the drive's position is checked against the + controller's position if address verification is requested. If they are + different (as may occur with an Address Record command that specified a + different location than the last Seek command), a seek is started to the + correct cylinder, and the routine returns with the disc service scheduled for + seek completion as above. - If the drive and controller positions agree, the controller CHS address is - validated against the drive limits. If they are invalid, Seek Check status - is set, and the command is terminated with an error. + If the drive and controller positions agree or verification is not requested, + the CHS addresses are validated against the drive limits. If they are + invalid, Seek Check status is set, and the command is terminated with an + error. - If the address is valid, the drive is checked to ensure that it is ready for - positioning. If it is, the the byte offset in the image file is calculated - from the CHS address, and the file is positioned. The disc service is - scheduled to begin the data transfer, and the routine returns TRUE to - indicate that the file position was set. + If the addresses are valid, the drive is checked to ensure that it is ready + for positioning. If it is, the the byte offset in the image file is + calculated from the CHS address, and the file is positioned. The disc + service is scheduled to begin the data transfer, and the routine returns TRUE + to indicate that the file position was set. Implementation notes: @@ -2181,7 +2204,7 @@ if (uptr->flags & UNIT_UNLOAD) { /* are the heads unloade return FALSE; /* as the drive was not ready */ } -if ((CNTLR_OPCODE) uptr->OP == recalibrate) /* is the unit recalibrating? */ +if ((CNTLR_OPCODE) uptr->OP == Recalibrate) /* is the unit recalibrating? */ target_cylinder = 0; /* seek to cylinder 0 and don't reset the EOC flag */ else { /* it's a Seek command or an auto-seek request */ @@ -2195,7 +2218,7 @@ if (target_cylinder >= drive_props [model].cylinders) { /* is the cylinder out o } else { /* the cylinder value is OK */ - delta = abs (uptr->CYL - target_cylinder); /* calculate the relative movement */ + delta = abs (uptr->CYL - (int32) target_cylinder); /* calculate the relative movement */ uptr->CYL = target_cylinder; /* and move the positioner */ if ((cvptr->head >= drive_props [model].heads) /* if the head */ @@ -2267,8 +2290,12 @@ return SCPE_IOERR; /* return an I/O error t static void set_address (CVPTR cvptr, uint32 index) { -cvptr->buffer [index] = cvptr->cylinder + (cvptr->eoc == SET ? 1 : 0); /* update the cylinder if EOC is set */ -cvptr->buffer [index + 1] = SET_HEAD (cvptr) | SET_SECTOR (cvptr); /* merge the head and sector */ +cvptr->buffer [index] = (uint16) cvptr->cylinder /* update the cylinder if EOC is set */ + + (cvptr->eoc == SET ? 1 : 0); + +cvptr->buffer [index + 1] = SET_HEAD (cvptr) /* merge the head and sector */ + | SET_SECTOR (cvptr); + return; } @@ -2339,8 +2366,8 @@ uint32 model; if (uptr == NULL) /* if the unit is invalid */ return DL_S2ERR | DL_S2NR; /* then it does not respond */ -model = GET_MODEL (uptr->flags); /* get the drive model */ -status = drive_props [model].type | uptr->STAT; /* start with the drive type and unit status */ +model = GET_MODEL (uptr->flags); /* get the drive model */ +status = (uint16) (drive_props [model].type | uptr->STAT); /* start with the drive type and unit status */ if (uptr->flags & UNIT_WPROT) /* is the write protect switch set? */ status |= DL_S2RO; /* set the Protected status bit */ diff --git a/HP2100/hp_disclib.h b/HP2100/hp_disclib.h index b2f860c5..fb5d6ef8 100644 --- a/HP2100/hp_disclib.h +++ b/HP2100/hp_disclib.h @@ -24,6 +24,8 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from the authors. + 24-Oct-12 JDB Changed CNTLR_OPCODE to title case to avoid name clash + 07-May-12 JDB Added end-of-track delay time as a controller variable 02-May-12 JDB First release 09-Nov-11 JDB Created disc controller common library from DS simulator @@ -53,7 +55,7 @@ /* Default controller times */ -#define DL_EOC_TIME 160 /* end-of-cylinder delay time */ +#define DL_EOT_TIME 160 /* end-of-track delay time */ #define DL_SEEK_TIME 100 /* seek delay time (per cylinder) */ #define DL_SECTOR_TIME 27 /* intersector delay time */ #define DL_CMD_TIME 3 /* command start delay time */ @@ -205,29 +207,29 @@ typedef enum { /* Controller opcodes */ typedef enum { - cold_load_read = 000, - recalibrate = 001, - seek = 002, - request_status = 003, - request_sector_address = 004, - read = 005, - read_full_sector = 006, - verify = 007, - write = 010, - write_full_sector = 011, - clear = 012, - initialize = 013, - address_record = 014, - request_syndrome = 015, - read_with_offset = 016, - set_file_mask = 017, - invalid_opcode = 020, - read_without_verify = 022, - load_tio_register = 023, - request_disc_address = 024, - end = 025, - wakeup = 026, - last_opcode = wakeup /* last valid opcode */ + Cold_Load_Read = 000, + Recalibrate = 001, + Seek = 002, + Request_Status = 003, + Request_Sector_Address = 004, + Read = 005, + Read_Full_Sector = 006, + Verify = 007, + Write = 010, + Write_Full_Sector = 011, + Clear = 012, + Initialize = 013, + Address_Record = 014, + Request_Syndrome = 015, + Read_With_Offset = 016, + Set_File_Mask = 017, + Invalid_Opcode = 020, + Read_Without_Verify = 022, + Load_TIO_Register = 023, + Request_Disc_Address = 024, + End = 025, + Wakeup = 026, + Last_Opcode = Wakeup /* last valid opcode */ } CNTLR_OPCODE; #define DL_OPCODE_MASK 037 @@ -331,6 +333,7 @@ typedef struct { uint32 index; /* data buffer current index */ uint32 length; /* data buffer valid length */ UNIT *aux; /* MAC auxiliary units (controller and timer) */ + int32 eot_time; /* end-of-track read delay time */ int32 seek_time; /* per-cylinder seek delay time */ int32 sector_time; /* intersector delay time */ int32 cmd_time; /* command response time */ @@ -351,11 +354,11 @@ typedef CNTLR_VARS *CVPTR; /* pointer to controller */ #define CNTLR_INIT(ctype,bufptr,auxptr) \ - (ctype), cntlr_idle, end, normal_completion, \ + (ctype), cntlr_idle, End, normal_completion, \ CLEAR, CLEAR, \ 0, 0, 0, 0, 0, 0, 0, 0, \ (bufptr), 0, 0, (auxptr), \ - DL_SEEK_TIME, DL_SECTOR_TIME, \ + DL_EOT_TIME, DL_SEEK_TIME, DL_SECTOR_TIME, \ DL_CMD_TIME, DL_DATA_TIME, DL_WAIT_TIME diff --git a/I1401/i1401_cd.c b/I1401/i1401_cd.c index 0c7eaa5b..a0b8b401 100644 --- a/I1401/i1401_cd.c +++ b/I1401/i1401_cd.c @@ -1,6 +1,6 @@ /* i1401_cd.c: IBM 1402 card reader/punch - Copyright (c) 1993-2010, Robert M. Supnik + Copyright (c) 1993-2015, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -35,6 +35,7 @@ Cards are represented as ASCII text streams terminated by newlines. This allows cards to be created and edited as normal files. + 28-Feb-15 RMS Added read from console 24-Mar-09 RMS Fixed read stacker operation in column binary mode Fixed punch stacker operation (Van Snyder) 28-Jun-07 RMS Added support for SS overlap modifiers @@ -50,11 +51,47 @@ 13-Apr-01 RMS Revised for register arrays */ +/* Read from console was requested by the 1401 restoration team at the + Computer History Museum. It allows small programs to be entered + quickly, without creating card files. Unfortunately, if input is + coming from the keyboard, then the card reader is not attached, + and it won't boot. + + To deal with this problem, the card reader must keep various + unit flags in a consistent state: + + ATTABLE? ATT? DFLT? state + + 0 0 0 impossible + 0 0 1 input from console + 0 1 0 impossible + 0 1 1 impossible + 1 0 0 waiting for file + 1 0 1 impossible + 1 1 0 input from file + 1 1 1 input from file, + default to console + after detach + + To maintain this state, starting from 100, means the + following: + + SET CDR DFLT set default flag + if !ATT, clear ATTABLE + SET CDR NODFLT clear default flag + ATTACH CDR set ATTABLE, attach + if error && DFLT, clear ATTABLE + DETACH CDR detach + if DFLT, clear ATTABLE +*/ + #include "i1401_defs.h" #include #define UNIT_V_PCH (UNIT_V_UF + 0) /* output conv */ #define UNIT_PCH (1 << UNIT_V_PCH) +#define UNIT_V_CONS (UNIT_V_UF + 1) /* input from console */ +#define UNIT_CONS (1 << UNIT_V_CONS) extern uint8 M[]; extern int32 ind[64], ssa, iochk; @@ -68,13 +105,19 @@ int32 cdp_buf_full = 0; /* punch buf full? */ t_stat cdr_svc (UNIT *uptr); t_stat cdr_boot (int32 unitno, DEVICE *dptr); t_stat cdr_attach (UNIT *uptr, char *cptr); +t_stat cdr_detach (UNIT *uptr); t_stat cdp_attach (UNIT *uptr, char *cptr); t_stat cdp_detach (UNIT *uptr); t_stat cdp_npr (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat cd_reset (DEVICE *dptr); +t_stat cdr_read_file (char *buf, int32 sz); +t_stat cdr_read_cons (char *buf, int32 sz); +t_stat cdr_chg_cons (UNIT *uptr, int32 val, char *cptr, void *desc); int32 bcd2asc (int32 c, UNIT *uptr); char colbin_to_bcd (uint32 cb); +extern void inq_puts (char *cptr); + /* Card reader data structures cdr_dev CDR descriptor @@ -97,11 +140,17 @@ REG cdr_reg[] = { { NULL } }; +MTAB cdr_mod[] = { + { UNIT_CONS, UNIT_CONS, "default to console", "DEFAULT", &cdr_chg_cons }, + { UNIT_CONS, 0 , "no default device", "NODEFAULT", &cdr_chg_cons }, + { 0 } + }; + DEVICE cdr_dev = { - "CDR", &cdr_unit, cdr_reg, NULL, + "CDR", &cdr_unit, cdr_reg, cdr_mod, 1, 10, 31, 1, 8, 7, NULL, NULL, &cd_reset, - &cdr_boot, &cdr_attach, NULL + &cdr_boot, &cdr_attach, &cdr_detach }; /* CDP data structures @@ -130,7 +179,6 @@ MTAB cdp_mod[] = { { UNIT_PCH, UNIT_PCH, "Fortran set", "FORTRAN" }, { MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, NULL, "NPR", &cdp_npr, NULL }, - { 0 } }; @@ -179,7 +227,7 @@ DEVICE stack_dev = { t_stat read_card (int32 ilnt, int32 mod) { -int32 i, cbn, c1, c2; +int32 i, cbn, c1, c2, cbufsz; t_stat r; if (sim_is_active (&cdr_unit)) { /* busy? */ @@ -187,32 +235,19 @@ if (sim_is_active (&cdr_unit)) { /* busy? */ if (r = cdr_svc (&cdr_unit)) /* process */ return r; } -if ((cdr_unit.flags & UNIT_ATT) == 0) /* attached? */ - return SCPE_UNATT; ind[IN_READ] = ind[IN_LST] = s1sel = s2sel = 0; /* default stacker */ cbn = ((ilnt == 2) || (ilnt == 5)) && (mod == BCD_C); /* col binary? */ +cbufsz = (cbn)? 2 * CBUFSIZE: CBUFSIZE; /* buffer size */ for (i = 0; i < (2 * CBUFSIZE) + 1; i++) /* clear extended buf */ cdr_buf[i] = 0; -fgets (cdr_buf, (cbn)? 2 * CBUFSIZE: CBUFSIZE, /* rd bin/char card */ - cdr_unit.fileref); -if (feof (cdr_unit.fileref)) /* eof? */ - return STOP_NOCD; -if (ferror (cdr_unit.fileref)) { /* error? */ - ind[IN_READ] = 1; - perror ("Card reader I/O error"); - clearerr (cdr_unit.fileref); - if (iochk) - return SCPE_IOERR; - return SCPE_OK; - } -cdr_unit.pos = ftell (cdr_unit.fileref); /* update position */ -if (ssa) { /* if last cd on */ - getc (cdr_unit.fileref); /* see if more */ - if (feof (cdr_unit.fileref)) /* eof? set flag */ - ind[IN_LST] = 1; - fseek (cdr_unit.fileref, cdr_unit.pos, SEEK_SET); - } -if (cbn) { /* column binary */ +if ((cdr_unit.flags & UNIT_ATT) != 0) /* attached? */ + r = cdr_read_file (cdr_buf, cbufsz); /* read from file */ +else if ((cdr_unit.flags & UNIT_CONS) != 0) /* default to console? */ + r = cdr_read_cons (cdr_buf, cbufsz); /* read from console */ +else return SCPE_UNATT; /* else can't read */ +if (r != SCPE_OK) /* read error? */ + return r; /* can't read */ +if (cbn) { /* column binary? */ for (i = 0; i < CDR_WIDTH; i++) { if (conv_old) { c1 = ascii2bcd (cdr_buf[i]); @@ -225,7 +260,7 @@ if (cbn) { /* column binary */ M[CD_CBUF1 + i] = (M[CD_CBUF1 + i] & WM) | c1; M[CD_CBUF2 + i] = (M[CD_CBUF2 + i] & WM) | c2; M[CDR_BUF + i] = colbin_to_bcd ((c1 << 6) | c2); - } /* end for i */ + } } /* end if col bin */ else { /* normal read */ for (i = 0; i < CDR_WIDTH; i++) { /* cvt to BCD */ @@ -369,6 +404,64 @@ else if (mod == BCD_EIGHT) return SCPE_OK; } +/* Read card from file */ + +t_stat cdr_read_file (char *buf, int32 sz) +{ +fgets (buf, sz, cdr_unit.fileref); /* rd bin/char card */ +if (feof (cdr_unit.fileref)) /* eof? */ + return STOP_NOCD; +if (ferror (cdr_unit.fileref)) { /* error? */ + ind[IN_READ] = 1; + perror ("Card reader I/O error"); + clearerr (cdr_unit.fileref); + if (iochk) + return SCPE_IOERR; + return SCPE_OK; + } +cdr_unit.pos = ftell (cdr_unit.fileref); /* update position */ +if (ssa) { /* if last cd on */ + getc (cdr_unit.fileref); /* see if more */ + if (feof (cdr_unit.fileref)) /* eof? set flag */ + ind[IN_LST] = 1; + fseek (cdr_unit.fileref, cdr_unit.pos, SEEK_SET); + } +return SCPE_OK; +} + +/* Read card from console */ + +t_stat cdr_read_cons (char *buf, int32 sz) +{ +int32 i, t; + +inq_puts ("[Enter card]\r\n"); +for (i = 0; i < sz; ) { + while (((t = sim_poll_kbd ()) == SCPE_OK) || /* wait for char */ + (t & SCPE_BREAK)) { + if (stop_cpu) /* stop? */ + return t; + } + if (t < SCPE_KFLAG) /* error? */ + return t; + t = t & 0177; + if ((t == '\r') || (t == '\n')) /* eol? */ + break; + if (t == 0177) { /* rubout? */ + if (i != 0) { /* anything? */ + buf[--i] = 0; + sim_putchar ('\\'); + } + } + else { + sim_putchar (t); + buf[i++] = t; + } + } +inq_puts ("\r\n"); +return SCPE_OK; +} + /* Card reader/punch reset */ t_stat cd_reset (DEVICE *dptr) @@ -379,12 +472,45 @@ sim_cancel (&cdr_unit); /* clear reader event */ return SCPE_OK; } +/* Set/clear default to console flag + + Caller will do actual bit field update on successful return */ + +t_stat cdr_chg_cons (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +if (val == 0) /* clear? */ + cdr_unit.flags |= UNIT_ATTABLE; /* attachable on */ +else if ((cdr_unit.flags & UNIT_ATT) == 0) /* set, unattached? */ + cdr_unit.flags &= ~UNIT_ATTABLE; /* attachable off */ +return SCPE_OK; +} + /* Card reader attach */ t_stat cdr_attach (UNIT *uptr, char *cptr) { +t_stat r; + ind[IN_LST] = ind[IN_READ] = 0; /* clear last card */ -return attach_unit (uptr, cptr); +cdr_unit.flags |= UNIT_ATTABLE; /* must be attachable */ +r = attach_unit (uptr, cptr); /* do attach */ +if ((r != SCPE_OK) && ((cdr_unit.flags & UNIT_CONS) != 0)) /* failed, default? */ + cdr_unit.flags &= ~UNIT_ATTABLE; /* clear attachable */ +return r; +} + +/* Card reader detach */ + +t_stat cdr_detach (UNIT *uptr) +{ +t_stat r; + +cdr_unit.flags |= UNIT_ATTABLE; /* must be attachable */ +r = detach_unit (uptr); /* detach */ +if (((cdr_unit.flags & UNIT_ATT) == 0) && /* attached clear? */ + ((cdr_unit.flags & UNIT_CONS) != 0)) /* default on? */ + cdr_unit.flags &= ~UNIT_ATTABLE; /* clear attachable */ +return r; } /* Bootstrap routine */ diff --git a/I1401/i1401_cpu.c b/I1401/i1401_cpu.c index 0be4b054..a1a28140 100644 --- a/I1401/i1401_cpu.c +++ b/I1401/i1401_cpu.c @@ -37,7 +37,7 @@ 22-May-06 RMS Fixed format error in CPU history (Peter Schorn) 06-Mar-06 RMS Fixed bug in divide (Van Snyder) 22-Sep-05 RMS Fixed declarations (Sterling Garwood) - 01-Sep-05 RMS Removed error stops in MCE + 01-Sep-05 RMS Removed error stops in MCE 16-Aug-05 RMS Fixed C++ declaration and cast problems 02-Jun-05 RMS Fixed SSB-SSG clearing on RESET (Ralph Reinke) 14-Nov-04 WVS Added column binary support, debug support @@ -206,11 +206,7 @@ int32 hst_lnt = 0; /* history length */ InstHistory *hst = NULL; /* instruction history */ t_bool conv_old = 0; /* old conversions */ -extern int32 sim_int_char; extern int32 sim_emax; -extern t_value *sim_eval; -extern FILE *sim_deb; -extern uint32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw); @@ -238,8 +234,6 @@ extern t_stat inq_io (int32 flag, int32 mod); extern t_stat mt_io (int32 unit, int32 flag, int32 mod); extern t_stat dp_io (int32 fnc, int32 flag, int32 mod); extern t_stat mt_func (int32 unit, int32 flag, int32 mod); -extern t_stat sim_activate (UNIT *uptr, int32 delay); -extern t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, UNIT *uptr, int32 sw); /* CPU data structures @@ -526,7 +520,6 @@ static const int32 mtf_mod[] = { t_stat sim_instr (void) { -extern int32 sim_interval; int32 IS, ilnt, flags; int32 op, xa, t, wm, ioind, dev, unit; int32 a, b, i, k, asave, bsave; @@ -1919,8 +1912,6 @@ char *cptr = (char *) desc; t_value sim_eval[MAX_L + 1]; t_stat r; InstHistory *h; -extern t_stat fprint_sym (FILE *ofile, t_addr addr, t_value *val, - UNIT *uptr, int32 sw); if (hst_lnt == 0) /* enabled? */ return SCPE_NOFNC; diff --git a/I1401/i1401_defs.h b/I1401/i1401_defs.h index 65affa25..680e9823 100644 --- a/I1401/i1401_defs.h +++ b/I1401/i1401_defs.h @@ -39,8 +39,8 @@ in answering questions, gathering source material, and debugging. */ -#ifndef _I1401_DEFS_H_ -#define _I1401_DEFS_H_ 0 +#ifndef I1401_DEFS_H_ +#define I1401_DEFS_H_ 0 #include "sim_defs.h" diff --git a/I1401/i1401_iq.c b/I1401/i1401_iq.c index e0fa7eb9..ed4d7514 100644 --- a/I1401/i1401_iq.c +++ b/I1401/i1401_iq.c @@ -1,6 +1,6 @@ /* i1401_iq.c: IBM 1407 inquiry terminal - Copyright (c) 1993-2008, Robert M. Supnik + Copyright (c) 1993-2015, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,7 @@ inq 1407 inquiry terminal + 08-Mar-15 RMS Renamed puts_tty to inq_puts 20-Sep-05 RMS Revised for new code tables 22-Dec-02 RMS Added break support 07-Sep-01 RMS Moved function prototypes @@ -47,7 +48,7 @@ int32 inq_char = 033; /* request inq */ t_stat inq_svc (UNIT *uptr); t_stat inq_reset (DEVICE *dptr); -void puts_tty (char *cptr); +void inq_puts (char *cptr); /* INQ data structures @@ -96,7 +97,7 @@ switch (mod) { /* case on mod */ /* if (ind[IN_INR] == 0) /* return SCPE_OK; /* return if no req */ ind[IN_INR] = 0; /* clear req */ - puts_tty ("[Enter]\r\n"); /* prompt */ + inq_puts ("[Enter]\r\n"); /* prompt */ for (i = 0; M[BS] != (BCD_GRPMRK + WM); i++) { /* until GM + WM */ while (((t = sim_poll_kbd ()) == SCPE_OK) || (t & SCPE_BREAK)) { @@ -110,11 +111,11 @@ switch (mod) { /* case on mod */ break; if (t == inq_char) { /* cancel? */ ind[IN_INC] = 1; /* set indicator */ - puts_tty ("\r\n[Canceled]\r\n"); + inq_puts ("\r\n[Canceled]\r\n"); return SCPE_OK; } if (i && ((i % INQ_WIDTH) == 0)) - puts_tty ("\r\n"); + inq_puts ("\r\n"); sim_putchar (t); /* echo */ if (flag == MD_WM) { /* word mark mode? */ if ((t == '~') && (wm_seen == 0)) @@ -132,7 +133,7 @@ switch (mod) { /* case on mod */ return STOP_NXM; } } - puts_tty ("\r\n"); + inq_puts ("\r\n"); M[BS++] = BCD_GRPMRK + WM; break; @@ -140,20 +141,20 @@ switch (mod) { /* case on mod */ for (i = 0; (t = M[BS++]) != (BCD_GRPMRK + WM); i++) { if ((flag == MD_WM) && (t & WM)) { if (i && ((i % INQ_WIDTH) == 0)) - puts_tty ("\r\n"); + inq_puts ("\r\n"); if (conv_old) sim_putchar ('~'); else sim_putchar ('`'); } if (i && ((i % INQ_WIDTH) == 0)) - puts_tty ("\r\n"); + inq_puts ("\r\n"); sim_putchar (bcd2ascii (t & CHAR, use_h)); if (ADDR_ERR (BS)) { BS = BA | (BS % MAXMEMSIZE); return STOP_NXM; } } - puts_tty ("\r\n"); + inq_puts ("\r\n"); break; default: /* invalid mod */ @@ -179,7 +180,7 @@ return SCPE_OK; /* Output multiple characters */ -void puts_tty (char *cptr) +void inq_puts (char *cptr) { if (cptr == NULL) return; diff --git a/I1401/i1401_lp.c b/I1401/i1401_lp.c index cec020da..64dd2522 100644 --- a/I1401/i1401_lp.c +++ b/I1401/i1401_lp.c @@ -1,6 +1,6 @@ /* i1401_lp.c: IBM 1403 line printer simulator - Copyright (c) 1993-2013, Robert M. Supnik + Copyright (c) 1993-2015, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,7 @@ lpt 1403 line printer + 08-Mar-15 RMS Added print to console option 16-Apr-13 RMS Fixed printer chain selection 19-Jan-07 RMS Added UNIT_TEXT flag 07-Mar-05 RMS Fixed bug in write_line (Van Snyder) @@ -48,6 +49,9 @@ int32 cctlnt = 66, cctptr = 0, lines = 0, lflag = 0; t_stat lpt_reset (DEVICE *dptr); t_stat lpt_attach (UNIT *uptr, char *cptr); t_stat space (int32 lines, int32 lflag); +t_stat lpt_puts (char *buf); + +extern void inq_puts (char *buf); char *pch_table_old[4] = { bcd_to_ascii_old, bcd_to_ascii_old, bcd_to_pca, bcd_to_pch @@ -58,8 +62,10 @@ char *pch_table[4] = { #define UNIT_V_FT (UNIT_V_UF + 0) #define UNIT_V_48 (UNIT_V_UF + 1) +#define UNIT_V_CONS (UNIT_V_UF + 2) #define UNIT_FT (1 << UNIT_V_FT) #define UNIT_48 (1 << UNIT_V_48) +#define UNIT_CONS (1 << UNIT_V_CONS) #define GET_PCHAIN(x) (((x) >> UNIT_V_FT) & 03) #define CHP(ch,val) ((val) & (1 << (ch))) @@ -89,6 +95,8 @@ MTAB lpt_mod[] = { { UNIT_48, 0, "64 character chain", "64" }, { UNIT_FT, UNIT_FT, "Fortran set", "FORTRAN" }, { UNIT_FT, 0, "business set", "BUSINESS" }, + { UNIT_CONS, UNIT_CONS, "default to console", "DEFAULT" }, + { UNIT_CONS, 0 , "no default device", "NODEFAULT" }, { UNIT_FT|UNIT_48, 0, NULL, "PCF" }, /* obsolete */ { UNIT_FT|UNIT_48, UNIT_48, NULL, "PCA" }, { UNIT_FT|UNIT_48, UNIT_FT|UNIT_48, NULL, "PCH" }, @@ -113,10 +121,9 @@ t_stat write_line (int32 ilnt, int32 mod) { int32 i, t, wm, sup; char *bcd2asc; +t_stat r; static char lbuf[LPT_WIDTH + 1]; /* + null */ -if ((lpt_unit.flags & UNIT_ATT) == 0) /* attached? */ - return SCPE_UNATT; wm = ((ilnt == 2) || (ilnt == 5)) && (mod == BCD_SQUARE); sup = ((ilnt == 2) || (ilnt == 5)) && (mod == BCD_S); ind[IN_LPT] = 0; /* clear error */ @@ -133,24 +140,15 @@ for (i = 0; i < LPT_WIDTH; i++) { /* convert print buf */ lbuf[LPT_WIDTH] = 0; /* trailing null */ for (i = LPT_WIDTH - 1; (i >= 0) && (lbuf[i] == ' '); i--) lbuf[i] = 0; -fputs (lbuf, lpt_unit.fileref); /* write line */ +if ((r = lpt_puts (lbuf)) != SCPE_OK) /* write line */ + return r; /* error? */ if (lines) /* cc action? do it */ - space (lines, lflag); + r = space (lines, lflag); else if (sup == 0) /* default? 1 line */ - space (1, FALSE); -else { - fputc ('\r', lpt_unit.fileref); /* sup -> overprint */ - lpt_unit.pos = ftell (lpt_unit.fileref); /* update position */ - } + r = space (1, FALSE); +else r = lpt_puts ("\r"); /* sup -> overprint */ lines = lflag = 0; /* clear cc action */ -if (ferror (lpt_unit.fileref)) { /* error? */ - ind[IN_LPT] = 1; - perror ("Line printer I/O error"); - clearerr (lpt_unit.fileref); - if (iochk) - return SCPE_IOERR; - } -return SCPE_OK; +return r; } /* Carriage control routine @@ -221,20 +219,51 @@ return SCPE_OK; t_stat space (int32 count, int32 sflag) { int32 i; +t_stat r; -if ((lpt_unit.flags & UNIT_ATT) == 0) - return SCPE_UNATT; cctptr = (cctptr + count) % cctlnt; /* adv cct, mod lnt */ if (sflag && CHP (0, cct[cctptr])) /* skip, top of form? */ - fputs ("\n\f", lpt_unit.fileref); /* nl, ff */ + r = lpt_puts ("\n\f"); /* nl, ff */ else { - for (i = 0; i < count; i++) - fputc ('\n', lpt_unit.fileref); + for (i = 0; (i < count); i++) + if ((r = lpt_puts ("\n")) != SCPE_OK) + break; } -lpt_unit.pos = ftell (lpt_unit.fileref); /* update position */ ind[IN_CC9] = CHP (9, cct[cctptr]) != 0; /* set indicators */ ind[IN_CC12] = CHP (12, cct[cctptr]) != 0; -return SCPE_OK; +return r; +} + + +/* Centralized string print routine + Prints to either a file or the console + + Note that if printing to the console, newline must be converted to crlf */ + +t_stat lpt_puts (char *buf) +{ +if ((lpt_unit.flags & UNIT_ATT) != 0) { /* attached? */ + fputs (buf, lpt_unit.fileref); /* print string */ + if (ferror (lpt_unit.fileref)) { /* error? */ + ind[IN_LPT] = 1; + perror ("Line printer I/O error"); + clearerr (lpt_unit.fileref); + if (iochk) + return SCPE_IOERR; + } + lpt_unit.pos = ftell (lpt_unit.fileref); /* update position */ + return SCPE_OK; + } +if ((lpt_unit.flags & UNIT_CONS) != 0) { /* default to cons? */ + if (buf[0] == '\n') { /* bare lf? */ + inq_puts ("\r"); /* cvt to crlf */ + lpt_unit.pos = lpt_unit.pos + 1; + } + inq_puts (buf); + lpt_unit.pos = lpt_unit.pos + strlen (buf); + return SCPE_OK; + } +return SCPE_UNATT; } /* Reset routine */ diff --git a/I1401/i1401_mt.c b/I1401/i1401_mt.c index 0ac21bf0..1f0ae4fe 100644 --- a/I1401/i1401_mt.c +++ b/I1401/i1401_mt.c @@ -114,7 +114,6 @@ extern uint8 M[]; /* memory */ extern int32 ind[64]; extern int32 BS, iochk; extern UNIT cpu_unit; -extern FILE *sim_deb; t_stat mt_reset (DEVICE *dptr); t_stat mt_boot (int32 unitno, DEVICE *dptr); @@ -472,7 +471,6 @@ return SCPE_OK; t_stat mt_boot (int32 unitno, DEVICE *dptr) { extern int32 saved_IS; -extern int32 sim_switches; if ((sim_switches & SWMASK ('N')) == 0) /* unless -n */ sim_tape_rewind (&mt_unit[unitno]); /* force rewind */ diff --git a/I1401/i1401_sys.c b/I1401/i1401_sys.c index a99c6639..11e45cb2 100644 --- a/I1401/i1401_sys.c +++ b/I1401/i1401_sys.c @@ -52,7 +52,6 @@ extern REG cpu_reg[]; extern uint8 M[]; extern char ascii_to_bcd_old[128], ascii_to_bcd[128]; extern char bcd_to_ascii_old[64], bcd_to_ascii_a[64], bcd_to_ascii_h[64]; -extern char *get_glyph (char *cptr, char *gbuf, char term); extern int32 store_addr_h (int32 addr); extern int32 store_addr_t (int32 addr); extern int32 store_addr_u (int32 addr); @@ -300,7 +299,7 @@ if (ilnt > 2) { /* A address? */ fprintf (of, " %%%c%c", bcd2ascii (val[2], use_h), bcd2ascii (val[3], sw)); else fprint_addr (of, &val[1]); - } + } if (ilnt > 5) /* B address? */ fprint_addr (of, &val[4]); if ((ilnt == 2) || (ilnt == 5) || (ilnt >= 8)) /* d character? */ @@ -384,7 +383,7 @@ if ((sw & SWMASK ('C')) || (sw & SWMASK ('S')) || (*cptr == wmch) || wm_seen = 0; } else val[i++] = t; - } + } if ((i == 0) || wm_seen) return SCPE_ARG; return -(i - 1); diff --git a/I1620/i1620_cd.c b/I1620/i1620_cd.c index 3604fead..e27b1cf5 100644 --- a/I1620/i1620_cd.c +++ b/I1620/i1620_cd.c @@ -1,6 +1,6 @@ /* i1620_cd.c: IBM 1622 card reader/punch - Copyright (c) 2002-2013, Robert M. Supnik + Copyright (c) 2002-2015, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -26,6 +26,7 @@ cdr 1622 card reader cdp 1622 card punch + 31-Jan-15 TFM Changes to translation tables (Tom McBride) 10-Dec-13 RMS Fixed WA card punch translations (Bob Armstrong) Fixed card reader EOL processing (Bob Armstrong) 19-Mar-12 RMS Fixed declarations of saved_pc, io_stop (Mark Pizzolato) @@ -107,11 +108,39 @@ DEVICE cdp_dev = { }; /* Data tables. The card reader presents unusual problems. - - Unique codes needed for 11-2-8 (uses !) and 12-7-8 (uses ") . - - Can punch both 11 (-) and 11-0 (uses ]). - On input, the nul and nl generated by C are converted to - spaces; tabs and line feeds are also converted to spaces. + Some of these translations may seem strange. The 1620 could + read and punch cards numerically (one 1620 storage location + per card column) or alphabetically (two 1620 storage locations + per card column). Even though a card might have contained any + possible character (digit, letter, special character), it + could still be read numerically. In this case, some characters + behaved the same as numbers or as record marks. The results + are well defined in IBM documentation. + + In order to make it possible to prepare card decks for input + using normal text editors, ASCII characters have been assigned + to represent 1620 characters that could appear on cards. In most + cases, this was easy since the letters, digits and punctuation + characters all have equivalent ASCII assignments. Five 1620 + characters do not have equivalent ASCII graphics and are + assigned as follows: + + ] is used to represent a flagged zero + | is used to represent a record mark + ! is used to represent a flagged record mark + } is used to represent a group mark + " is used to represent a flagged group mark + + As a concession to some editors, ASCII nul, nl, tab, and lf + characters are accepted and converted to blanks. Also, for + the same reason, lower case letters are treated the same as + upper case on input. All other ASCII characters not in the + 1620 character set are treated as errors. + + (Tom McBride) + +*/ /* Card reader (ASCII) to numeric (one digit) */ const int8 cdr_to_num[128] = { @@ -119,36 +148,47 @@ const int8 cdr_to_num[128] = { -1, 0x00, 0x00, -1, -1, 0x00, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 10 */ -1, -1, -1, -1, -1, -1, -1, -1, - 0x00, 0x1A, 0x0F, 0x0B, 0x1B, 0x0C, 0x00, 0x0C, /* !"#$%&' */ - 0x0C, 0x0C, 0x1C, 0x00, 0x0B, 0x10, 0x1B, 0x01, /* ()*+,-./ */ + 0x00, 0x1A, 0x1F, -1, 0x1B, -1, -1, -1, /* !" $ */ + 0x0C, 0x0C, 0x1C, 0x00, 0x0B, 0x10, 0x0B, 0x01, /* ()*+,-./ */ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 01234567 */ - 0x08, 0x09, 0x00, 0x1E, 0x1E, 0x0B, 0x0E, 0x1A, /* 89:;<=>? */ + 0x08, 0x09, -1, -1, -1, 0x0B, -1, -1, /* 89 = */ 0x0C, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* @ABCDEFG */ 0x08, 0x09, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, /* HIJKLMNO */ 0x17, 0x18, 0x19, 0x02, 0x03, 0x04, 0x05, 0x06, /* PQRSTUVW */ - 0x07, 0x08, 0x09, 0x00, 0x0E, 0x10, 0x0A, 0x1F, /* XYZ[\]^_ */ + 0x07, 0x08, 0x09, -1, -1, 0x10, -1, -1, /* XYZ ] */ -1, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* `abcdefg */ 0x08, 0x09, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, /* hijklmno */ 0x17, 0x18, 0x19, 0x02, 0x03, 0x04, 0x05, 0x06, /* pqrstuvw */ - 0x07, 0x08, 0x09, 0x0F, 0x0A, 0x1F, 0x00, -1 /* xyz{|}~ */ + 0x07, 0x08, 0x09, -1, 0x0A, 0x0F, -1, -1 /* xyz |} */ }; /* Numeric (flag + digit) to card punch (ASCII) */ +/* Note that all valid digits produce different + codes except that both numeric blanks and flagged + numeric blanks both produce a blank column. (tfm) */ + const int8 num_to_cdp[32] = { '0', '1', '2', '3', '4', '5', '6', '7', /* 0 */ - '8', '9', '|', ',', ' ', '"', ' ', '"', + '8', '9', '|', -1, ' ', -1, -1, '}', ']', 'J', 'K', 'L', 'M', 'N', 'O', 'P', /* F + 0 */ - 'Q', 'R', '!', '$', -1, -1, -1, '"' + 'Q', 'R', '!', -1, ' ', -1, -1, '"' }; /* Card reader (ASCII) to alphameric (two digits) - 11-2-8 (!) reads as 5A - 11-7-8 (_) reads as 5F - 12-2-8 (?) reads inconsistently (here 02) - 12-6-8 (<) reads inconsistently (here 5E) - 12-7-8 (}) reads as 5F + ] reads as 50 (flagged zero) + | reads as 0A (record mark) + ! reads as 5A (flagged record mark) + } reads as 0F (group mark) + " reads as 5F (flagged group mark) + + As a concession to some editors, ASCII nul, nl, tab, and lf + characters are accepted and converted to blanks. Also, for + the same reason, lower case letters are treated the same as + upper case on input. All other ASCII characters not in the + 1620 character set are treated as errors. + */ const int8 cdr_to_alp[128] = { @@ -156,63 +196,58 @@ const int8 cdr_to_alp[128] = { -1, 0x00, 0x00, -1, -1, 0x00, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 10 */ -1, -1, -1, -1, -1, -1, -1, -1, - 0x00, 0x5A, 0x0F, 0x33, 0x13, 0x24, 0x10, 0x34, /* !"#$%&' */ + 0x00, 0x5A, 0x5F, -1, 0x13, -1, -1, -1, /* !" $ */ 0x24, 0x04, 0x14, 0x10, 0x23, 0x20, 0x03, 0x21, /* ()*+,-./ */ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 01234567 */ - 0x78, 0x79, 0x70, 0x5E, 0x5E, 0x33, 0x0E, 0x02, /* 89:;<=>? */ + 0x78, 0x79, -1, -1, -1, 0x33, -1, -1, /* 89 = */ 0x34, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* @ABCDEFG */ 0x48, 0x49, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, /* HIJKLMNO */ 0x57, 0x58, 0x59, 0x62, 0x63, 0x64, 0x65, 0x66, /* PQRSTUVW */ - 0x67, 0x68, 0x69, 0x40, 0x0E, 0x50, 0x0A, 0x5F, /* XYZ[\]^_ */ - 0x50, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* `abcdefg */ + 0x67, 0x68, 0x69, -1, -1, 0x50, -1, -1, /* XYZ ] */ + -1, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* abcdefg */ 0x48, 0x49, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, /* hijklmno */ 0x57, 0x58, 0x59, 0x62, 0x63, 0x64, 0x65, 0x66, /* pqrstuvw */ - 0x67, 0x68, 0x69, 0x0F, 0x0A, 0x5F, 0x60, -1 /* xyz{|}~ */ + 0x67, 0x68, 0x69, -1, 0x0A, 0x0F, -1, -1 /* xyz |} */ }; -/* Alphameric (two digits) to card punch (ASCII). Oddities: +/* Alphameric (two digits) to card punch (ASCII). - 02 -> 12-2-8 (?), symmetric - 07 -> 12-7-8 (}), reads as 5F - 12 -> 11-2-8 (!), reads as 5A - 15 -> 11,0 (`), reads as 50 - 22 -> 0-2-8 (|), reads as 0A - 32 -> 2-8 (^), reads as 0A - 5B -> 11-3-8 (=), reads as 13 - 6A -> 0-2-8 (|), reads as 0A - 6B -> 0-3-8 (,), reads as 23 - AA -> 0-2-8 (|), reads as 0A - - There is no way to punch 0-5-8 (~), 0-6-8 (\), - 11-5-8 (]), 11-6-8 (;), 11-7-8 (_), - 12-5-8 ([), or 12-6-8 (<) - -According to Bob Armstrong, - the FORTRAN compiler is sneaky and actually punches numeric - data (i.e. data that it knows will be read back using RNCD) - in alphameric mode with WACD. Because of that there are some + All 1620 compilers are know to punch numeric data + (i.e. data that it knows will be read back using RNCD) + in alphameric mode with WACD. Because of that, there are some alpha to ASCII translations that absolutely MUST work out right - or otherwise we won't be able to load FORTRAN object decks. + or otherwise we won't be able to load the object decks. - 50 - must "punch" as ] (flagged zero) (used to be "_") - 0A - must "punch" as | (record mark) (used to be "'") + 50 - punches as ] (flagged zero) + 0A - punches as | (record mark) + 0F - punches as } (group mark) + + If a program punches alphameric data that includes a flagged + record mark or flagged group mark, they will be punched + as below. No known IBM compiler punches any of these but + some application programs do. The mapping of characters for + the card reader and punch is such that a card deck can be + duplicated with a RACD, WACD loop. + + 5A - punches as ! (flagged record mark) + 5F - punches as " (flagged group mark) */ -const char alp_to_cdp[256] = { - ' ', -1, '?', '.', ')', -1, -1, '}', /* 00 */ - -1, -1, '|', -1, -1, -1, -1, '"', - '+', -1, '!', '$', '*', ']', -1, -1, /* 10 */ +const int8 alp_to_cdp[256] = { + ' ', -1, -1, '.', ')', -1, -1, -1, /* 00 */ + -1, -1, '|', -1, -1, -1, -1, '}', + '+', -1, -1, '$', '*', -1, -1, -1, /* 10 */ -1, -1, -1, -1, -1, -1, -1, -1, - '-', '/', '|', ',', '(', -1, -1, -1, /* 20 */ + '-', '/', -1, ',', '(', -1, -1, -1, /* 20 */ + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, '=', '@', -1, -1, -1, /* 30 */ -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, '^', '=', '@', ':', ' ', -1, /* 30 */ - -1, -1, '|', -1, -1, -1, -1, '"', -1, 'A', 'B', 'C', 'D', 'E', 'F', 'G', /* 40 */ 'H', 'I', -1, -1, -1, -1, -1, -1, ']', 'J', 'K', 'L', 'M', 'N', 'O', 'P', /* 50 */ - 'Q', 'R', '?', '=', -1, -1, -1, '}', + 'Q', 'R', '!', -1, -1, -1, -1, '"', -1, '/', 'S', 'T', 'U', 'V', 'W', 'X', /* 60 */ - 'Y', 'Z', '|', ',', -1, -1, -1, -1, + 'Y', 'Z', -1, -1, -1, -1, -1, -1, '0', '1', '2', '3', '4', '5', '6', '7', /* 70 */ '8', '9', -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 80 */ @@ -220,7 +255,7 @@ const char alp_to_cdp[256] = { -1, -1, -1, -1, -1, -1, -1, -1, /* 90 */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* A0 */ - -1, -1, '|', -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* B0 */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* C0 */ @@ -395,12 +430,38 @@ uint8 z, d; switch (op) { /* decode op */ case OP_DN: - return cdp_num (pa, 20000 - (pa % 20000), TRUE);/* dump numeric */ + + /* DN punches all characters the same as WN except that a flagged + zero is punched as a hypehen (-) instead of a flagged + zero ([). Punching begins at the P address and continues until + the last digit of the storage module containing the P address + has been punched. If the amount of data to be punched is an + exact multiple of 80, the operation ends there. If the last + character of the module does not fill out the card, additional + characters from the next higher addresses (addressing wraps to + back to zero if the operation started in the highest module) are + used to fill out the card. (Tom McBride) */ + + return cdp_num (pa, /* dump numeric */ + ((20000 - (pa % 20000) + 79) / 80) * 80, + TRUE); case OP_WN: + + /* WN always punches exactly 80 characters. If the highest address + in the machine is reached before the card is full, addressing + wraps around to zero and continues. The PP function handles + this correctly. (Tom McBride) */ + return cdp_num (pa, CD_LEN, FALSE); /* write numeric */ - case OP_WA: + case OP_WA: /* write alphanumerically */ + + /* WA always punches exactly 80 characters. If the highest address + in the machine is reached before the card is full, addressing + wraps around to zero and continues. The ADDR_A function handles + this correctly. (Tom McBride) */ + for (i = 0; i < CD_LEN; i++) { /* one card */ d = M[pa] & DIGIT; /* get digit pair */ z = M[pa - 1] & DIGIT; @@ -437,8 +498,8 @@ while (ncd-- >= 0) { /* until done */ break; for (i = 0; i < len; i++) { /* one card */ d = M[pa] & (FLAG | DIGIT); /* get char */ - if (dump && (d == FLAG)) /* dump? F+0 is diff */ - cdc = '-'; + if (dump && (d == FLAG)) /* dump? F+0 is diff .. */ + cdc = '-'; /* .. punch as hyphen */ else cdc = num_to_cdp[d]; /* translate */ if (cdc < 0) { /* bad char? */ ind[IN_WRCHK] = 1; /* set write check */ diff --git a/I1620/i1620_cpu.c b/I1620/i1620_cpu.c index 227e8a01..1f2c6ea8 100644 --- a/I1620/i1620_cpu.c +++ b/I1620/i1620_cpu.c @@ -26,6 +26,8 @@ This CPU module incorporates code and comments from the 1620 simulator by Geoff Kuenning, with his permission. + 07-May-15 RMS Added missing TFL instruction (Tom McBride) + 28-Mar-15 RMS Revised to use sim_printf 26-Mar-15 RMS Separated compare from add/sub flows (Tom McBride) Removed ADD_SIGNC return from add/sub flows 10-Dec-13 RMS Fixed several bugs in add and compare (Bob Armstrong) @@ -135,11 +137,6 @@ int32 hst_lnt = 0; /* history length */ InstHistory *hst = NULL; /* instruction history */ uint8 ind[NUM_IND] = { 0 }; /* indicators */ -extern int32 sim_int_char; -extern int32 sim_interval; -extern uint32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ -extern FILE *sim_log; - t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw); t_stat cpu_reset (DEVICE *dptr); @@ -496,14 +493,14 @@ while (reason == 0) { /* loop until halted */ saved_PC = PC; /* commit prev instr */ if (sim_interval <= 0) { /* check clock queue */ - if (reason = sim_process_event ()) + if ((reason = sim_process_event ())) break; } if (sim_brk_summ && sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */ reason = STOP_IBKPT; /* stop simulation */ break; - } + } sim_interval = sim_interval - 1; @@ -573,6 +570,12 @@ while (reason == 0) { /* loop until halted */ reason = xmt_field (PAR, QAR, 1); /* xmit field */ break; +/* Transmit floating - P,Q are valid */ + + case OP_TFL: + reason = xmt_field (PAR, QAR, 3); /* xmit field */ + break; + /* Transmit record - P,Q are valid */ case OP_TR: @@ -888,7 +891,7 @@ while (reason == 0) { /* loop until halted */ reason = STOP_OVERFL; if ((ind[IN_EZ] == 0) && (sta == ADD_NOCRY)) { /* ~z, ~c, ~sign chg? */ BRANCH (PAR); /* branch */ - } + } break; case OP_BCXM: @@ -902,7 +905,7 @@ while (reason == 0) { /* loop until halted */ reason = STOP_OVERFL; if ((ind[IN_EZ] == 0) && (sta == ADD_NOCRY)) { /* ~z, ~c, ~sign chg? */ BRANCH (PAR); /* branch */ - } + } break; /* Branch and select - P is valid */ @@ -928,7 +931,7 @@ while (reason == 0) { /* loop until halted */ default: reason = STOP_INVSEL; /* undefined */ break; - } + } BRANCH (PAR); break; @@ -1391,7 +1394,7 @@ if (comp && !cry && !ind[IN_EZ]) { /* recomp needed? */ ind[IN_HP] = ind[IN_HP] ^ 1; /* flip indicator */ for (cry = 0, dp = dsv; dp != d; ) { /* rescan */ dst = M[dp] & DIGIT; /* get dst digit */ - dst = (dp == dsv)? (10 - dst): (9 - dst); /* 10 or 9s comp */ + dst = (dp == dsv)? (10 - dst): (9 - dst); /* 10 or 9s comp */ res = add_one_digit (0, dst, &cry); /* "add" */ M[dp] = (M[dp] & FLAG) | res; /* store */ MM (dp); /* decr dst addr */ @@ -2170,9 +2173,7 @@ return SCPE_OK; t_stat cpu_set_opt1 (UNIT *uptr, int32 val, char *cptr, void *desc) { if (cpu_unit.flags & IF_MII) { - printf ("Feature is standard on 1620 Model 2\n"); - if (sim_log) - fprintf (sim_log, "Feature is standard on 1620 Model 2\n"); + sim_printf ("Feature is standard on 1620 Model 2\n"); return SCPE_NOFNC; } return SCPE_OK; @@ -2183,9 +2184,7 @@ return SCPE_OK; t_stat cpu_set_opt2 (UNIT *uptr, int32 val, char *cptr, void *desc) { if (!(cpu_unit.flags & IF_MII)) { - printf ("Feature is not available on 1620 Model 1\n"); - if (sim_log) - fprintf (sim_log, "Feature is not available on 1620 Model 1\n"); + sim_printf ("Feature is not available on 1620 Model 1\n"); return SCPE_NOFNC; } return SCPE_OK; diff --git a/I1620/i1620_defs.h b/I1620/i1620_defs.h index d4183c78..521b5a66 100644 --- a/I1620/i1620_defs.h +++ b/I1620/i1620_defs.h @@ -1,6 +1,6 @@ /* i1620_defs.h: IBM 1620 simulator definitions - Copyright (c) 2002-2010, Robert M. Supnik + Copyright (c) 2002-2015, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -27,12 +27,13 @@ I am grateful to Al Kossow, the Computer History Museum, and the IBM Corporate Archives for their help in gathering documentation about the IBM 1620. + 05-Feb-15 TFM Added definitions for flagged RM, GM, NB 22-May-10 RMS Added check for 64b definitions 18-Oct-02 RMS Fixed bug in ADDR_S macro (found by Hans Pufal) */ -#ifndef _I1620_DEFS_H_ -#define _I1620_DEFS_H_ 0 +#ifndef I1620_DEFS_H_ +#define I1620_DEFS_H_ 0 #include "sim_defs.h" /* simulator defns */ @@ -158,6 +159,9 @@ #define REC_MARK 0xA #define NUM_BLANK 0xC #define GRP_MARK 0xF +#define FLG_REC_MARK 0x1A +#define FLG_NUM_BLANK 0x1C +#define FLG_GRP_MARK 0x1F #define BAD_DIGIT(x) ((x) > 9) /* Instruction format */ diff --git a/I1620/i1620_dp.c b/I1620/i1620_dp.c index 1f8390cb..a78e7344 100644 --- a/I1620/i1620_dp.c +++ b/I1620/i1620_dp.c @@ -1,6 +1,6 @@ /* i1620_dp.c: IBM 1311 disk simulator - Copyright (c) 2002-2008, Robert M. Supnik + Copyright (c) 2002-2015, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/I1620/i1620_lp.c b/I1620/i1620_lp.c index 147b8e8e..e23e57ef 100644 --- a/I1620/i1620_lp.c +++ b/I1620/i1620_lp.c @@ -1,6 +1,6 @@ /* i1620_lp.c: IBM 1443 line printer simulator - Copyright (c) 2002-2013, Robert M. Supnik + Copyright (c) 2002-2015, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,7 @@ lpt 1443 line printer + 31-Jan-15 TFM Fixed various problems ... see comments in code 10-Dec-13 RMS Fixed DN wraparound (Bob Armstrong) Fixed test on VFU 10 (Bob Armstrong) 19-Jan-07 RMS Added UNIT_TEXT flag @@ -58,7 +59,7 @@ t_stat lpt_svc (UNIT *uptr); t_stat lpt_reset (DEVICE *dptr); t_stat lpt_attach (UNIT *uptr, char *cptr); void lpt_buf_init (void); -t_stat lpt_num (uint32 pa, uint32 len, uint32 f1, t_bool dump); +t_stat lpt_num(uint32 pa, uint32 f1, t_bool dump); /* tfm: length parameter removed, not needed */ t_stat lpt_print (void); t_stat lpt_space (int32 lines, int32 lflag); @@ -101,29 +102,29 @@ DEVICE lpt_dev = { /* Numeric (flag plus digit) to lineprinter (ASCII) */ -const char num_to_lpt[32] = { - '0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', '|', ' ', '@', ':', ' ', 'G', +const int8 num_to_lpt[32] = { + '0', '1', '2', '3', '4', '5', '6', '7', /* tfm: All invalid char treated as errors */ + '8', '9', '|', -1, '@', -1, -1, 'G', /* tfm: @, G only print on DN; else NB is blank */ '-', 'J', 'K', 'L', 'M', 'N', 'O', 'P', - 'Q', 'R', 'W', ' ', '*', ' ', -1, 'X' + 'Q', 'R', 'W', -1, '*', -1, -1, 'X' /* tfm: W, *, X only print on DN */ }; /* Alphameric (digit pair) to lineprinter (ASCII) */ -const char alp_to_lpt[256] = { - ' ', -1, '?', '.', ')', -1, -1, -1, /* 00 */ +const int8 alp_to_lpt[256] = { /* tfm: invalid codes 02, 12, 15, 32, 35, 61 removed */ + ' ', -1, -1, '.', ')', -1, -1, -1, /* 00 */ -1, -1, -1, -1, -1, -1, -1, -1, - '+', -1, '!', '$', '*', ' ', -1, -1, /* 10 */ + '+', -1, -1, '$', '*', -1, -1, -1, /* 10 */ -1, -1, -1, -1, -1, -1, -1, -1, '-', '/', '|', ',', '(', -1, -1, -1, /* 20 */ -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, '0', '=', '@', ':', -1, -1, /* 30 */ + -1, -1, -1, '=', '@', -1, -1, -1, /* 30 */ -1, -1, -1, -1, -1, -1, -1, -1, -1, 'A', 'B', 'C', 'D', 'E', 'F', 'G', /* 40 */ 'H', 'I', -1, -1, -1, -1, -1, -1, '-', 'J', 'K', 'L', 'M', 'N', 'O', 'P', /* 50 */ 'Q', 'R', -1, -1, -1, -1, -1, -1, - -1, '/', 'S', 'T', 'U', 'V', 'W', 'X', /* 60 */ + -1, -1, 'S', 'T', 'U', 'V', 'W', 'X', /* 60 */ 'Y', 'Z', -1, -1, -1, -1, -1, -1, '0', '1', '2', '3', '4', '5', '6', '7', /* 70 */ '8', '9', -1, -1, -1, -1, -1, -1, @@ -171,10 +172,10 @@ switch (op) { /* decode op */ break; case OP_DN: - return lpt_num (pa, 20000 - (pa % 20000), f1, TRUE); /* dump numeric */ + return lpt_num (pa, f1, TRUE); /* dump numeric (tfm: removed len parm ) */ case OP_WN: - return lpt_num (pa, 0, f1, FALSE); /* write numeric */ + return lpt_num (pa, f1, FALSE); /* write numeric (tfm: removed len parm ) */ case OP_WA: for ( ; lpt_bptr < LPT_BSIZE; lpt_bptr++) { /* only fill buf */ @@ -207,7 +208,7 @@ return SCPE_OK; /* Print numeric */ -t_stat lpt_num (uint32 pa, uint32 len, uint32 f1, t_bool dump) +t_stat lpt_num (uint32 pa, uint32 f1, t_bool dump) /* tfm: removed len parm and reorganized code */ { uint8 d; int8 lpc; @@ -215,17 +216,20 @@ t_stat r, sta; sta = SCPE_OK; for ( ; lpt_bptr < LPT_BSIZE; lpt_bptr++) { /* only fill buf */ - d = M[pa]; /* get digit */ - if (dump? (len-- == 0): /* end reached? */ - ((d & REC_MARK) == REC_MARK)) + d = M[pa]; /* get data char */ + if (!dump && /* not dumping? */ + ((d & REC_MARK) == REC_MARK)) /* quit on RM or GM */ break; - lpc = num_to_lpt[d]; /* translate */ + lpc = num_to_lpt[d]; /* translate digit */ + if (!dump && /* if not dumping */ + ((d & DIGIT) == NUM_BLANK)) /* translate numeric blank */ + lpc = ' '; /* to normal space */ if (lpc < 0) { /* bad char? */ ind[IN_WRCHK] = ind[IN_PRCHK] = 1; /* wr chk */ if (io_stop) /* set return status */ sta = STOP_INVCHR; } - lpt_buf[lpt_bptr++] = lpc & 0x7F; /* fill buffer */ + lpt_buf[lpt_bptr] = lpc & 0x7F; /* put char into buffer (tfm: correct increment)*/ PP (pa); /* incr mem addr */ } if ((f1 & 1) == 0) { /* print now? */ diff --git a/I1620/i1620_pt.c b/I1620/i1620_pt.c index dc352f80..96b939cf 100644 --- a/I1620/i1620_pt.c +++ b/I1620/i1620_pt.c @@ -1,6 +1,6 @@ /* i1620_pt.c: IBM 1621/1624 paper tape reader/punch simulator - Copyright (c) 2002-2013, Robert M Supnik + Copyright (c) 2002-2015, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -26,6 +26,9 @@ ptr 1621 paper tape reader ptp 1624 paper tape punch + 23-Feb-15 TFM Fixed RA, RBPT to preserve flags on RM at end (Tom McBride) + 09-Feb-15 TFM Fixed numerous translation problems (Tom McBride) + 09-Feb-15 TFM Fixed pack/unpack errors in binary r/w (Tom McBride) 21-Dec-13 RMS Fixed translation of paper tape code X0C 10-Dec-13 RMS Fixed DN wraparound (Bob Armstrong) 19-Mar-12 RMS Fixed declaration of io_stop (Mark Pizzolato) @@ -117,75 +120,73 @@ const int8 bad_par[128] = { /* Paper tape read (7b) to numeric (one digit) */ const int8 ptr_to_num[128] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* - */ - 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x00, 0x0E, 0x0F, - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* C */ - 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x00, 0x0E, 0x0F, - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* O */ - 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x00, 0x0E, 0x0F, - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* OC */ - 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x00, 0x0E, 0x0F, - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* X */ - 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x10, 0x1E, 0x1F, - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* XC */ - 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x10, 0x1E, 0x1F, - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* XO */ - 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x00, 0x0E, 0x0F, - 0x10, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* XOC */ - 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x00, 0x0E, 0x0F + -1, 0x01, 0x02, -1, 0x04, -1, -1, 0x07, /* - */ + 0x08, -1, -1, 0x0B, -1, -1, -1, -1, + 0x00, -1, -1, 0x03, -1, 0x05, 0x06, -1, /* C */ + -1, 0x09, -1, -1, 0x0C, -1, -1, -1, + 0x00, -1, -1, 0x03, -1, 0x05, 0x06, -1, /* O */ + -1, 0x09, 0x0A, -1, 0x0C, -1, -1, 0x0F, + -1, 0x01, 0x02, -1, 0x04, -1, -1, 0x07, /* OC */ + 0x08, -1, -1, 0x0B, -1, -1, -1, -1, + 0x10, -1, -1, 0x13, -1, 0x15, 0x16, -1, /* X */ + -1, 0x19, 0x1A, -1, 0x1C, -1, -1, 0x1F, + -1, 0x11, 0x12, -1, 0x14, -1, -1, 0x17, /* XC */ + 0x18, -1, -1, 0x1B, -1, -1, -1, -1, + -1, 0x01, 0x02, -1, 0x04, -1, -1, 0x07, /* XO */ + 0x08, -1, -1, 0x0B, -1, -1, -1, -1, + 0x10, -1, -1, 0x03, -1, 0x05, 0x06, -1, /* XOC */ + -1, 0x09, 0x0A, -1, 0x0C, -1, -1, -1 /* X0C82 is not defined but will treat as RM (tfm) */ }; -/* Paper tape read (7b) to alphameric (two digits) - Codes XO82, 82, XO842, 842 do not have consistent translations -*/ +/* Paper tape read (7b) to alphameric (two digits) */ const int8 ptr_to_alp[128] = { 0x00, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* - */ - 0x78, 0x79, -1, 0x33, 0x34, 0x70, -1, 0x0F, + 0x78, 0x79, -1, 0x33, 0x34, -1, -1, -1, 0x00, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* C */ - 0x78, 0x79, -1, 0x33, 0x34, 0x70, -1, 0x0F, - 0x70, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* O */ - 0x68, 0x69, 0x0A, 0x23, 0x24, 0x60, 0x0E, 0x0F, - 0x70, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* OC */ - 0x68, 0x69, 0x0A, 0x23, 0x24, 0x60, 0x0E, 0x0F, + 0x78, 0x79, -1, 0x33, 0x34, -1, -1, -1, + 0x70, 0x21, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* O */ + 0x68, 0x69, 0x0A, 0x23, 0x24, -1, -1, 0x0F, + 0x70, 0x21, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* OC */ + 0x68, 0x69, 0x0A, 0x23, 0x24, -1, -1, 0x0F, 0x20, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* X */ - 0x58, 0x59, 0x5A, 0x13, 0x14, 0x50, 0x5E, 0x5F, + 0x58, 0x59, 0x5A, 0x13, 0x14, -1, -1, 0x5F, 0x20, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* XC */ - 0x58, 0x59, 0x5A, 0x13, 0x14, 0x50, 0x5E, 0x5F, + 0x58, 0x59, 0x5A, 0x13, 0x14, -1, -1, 0x5F, 0x10, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* XO */ - 0x48, 0x49, -1, 0x03, 0x04, 0x40, -1, 0x7F, + 0x48, 0x49, -1, 0x03, 0x04, -1, -1, -1, 0x10, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* XOC */ - 0x48, 0x49, -1, 0x03, 0x04, 0x40, -1, 0x7F + 0x48, 0x49, -1, 0x03, 0x04, -1, -1, -1 }; /* Numeric (flag + digit) to paper tape punch */ const int8 num_to_ptp[32] = { 0x20, 0x01, 0x02, 0x13, 0x04, 0x15, 0x16, 0x07, /* 0 */ - 0x08, 0x19, 0x2A, 0x3B, 0x1C, 0x0D, 0x3E, 0x3F, + 0x08, 0x19, 0x2A, -1, 0x1C, -1, -1, 0x2F, 0x40, 0x51, 0x52, 0x43, 0x54, 0x45, 0x46, 0x57, /* F + 0 */ - 0x58, 0x49, 0x4A, 0x5B, 0x4C, 0x5D, 0x5E, 0x4F + 0x58, 0x49, 0x4A, -1, 0x4C, -1, -1, 0x4F }; /* Alphameric (two digits) to paper tape punch */ const int8 alp_to_ptp[256] = { - 0x10, -1, 0x7A, 0x6B, 0x7C, -1, -1, 0x7F, /* 00 */ - -1, -1, 0x2A, -1, -1, -1, -1, 0x1F, - 0x70, -1, 0x4A, 0x5B, 0x4C, -1, -1, -1, /* 10 */ + 0x10, -1, -1, 0x6B, 0x7C, -1, -1, -1, /* 00 */ -1, -1, -1, -1, -1, -1, -1, -1, - 0x40, 0x31, 0x2A, 0x3B, 0x2C, -1, -1, -1, /* 20 */ + 0x70, -1, -1, 0x5B, 0x4C, -1, -1, -1, /* 10 */ -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 0x1A, 0x0B, 0x1C, 0x0D, 0x0E, -1, /* 30 */ + 0x40, 0x31, -1, 0x3B, 0x2C, -1, -1, -1, /* 20 */ + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 0x0B, 0x1C, -1, -1, -1, /* 30 */ -1, -1, -1, -1, -1, -1, -1, -1, -1, 0x61, 0x62, 0x73, 0x64, 0x75, 0x76, 0x67, /* 40 */ 0x68, 0x79, -1, -1, -1, -1, -1, -1, 0x40, 0x51, 0x52, 0x43, 0x54, 0x45, 0x46, 0x57, /* 50 */ - 0x58, 0x49, 0x4A, -1, -1, -1, -1, 0x4F, - -1, 0x31, 0x32, 0x23, 0x34, 0x25, 0x26, 0x37, /* 60 */ + 0x58, 0x49, -1, -1, -1, -1, -1, -1, + -1, -1, 0x32, 0x23, 0x34, 0x25, 0x26, 0x37, /* 60 */ 0x38, 0x29, -1, -1, -1, -1, -1, -1, 0x20, 0x01, 0x02, 0x13, 0x04, 0x15, 0x16, 0x07, /* 70 */ - 0x08, 0x19, 0x7A, -1, -1, -1, -1, 0x7F, + 0x08, 0x19, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 80 */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 90 */ @@ -214,7 +215,7 @@ const int8 alp_to_ptp[256] = { t_stat ptr (uint32 op, uint32 pa, uint32 f0, uint32 f1) { -uint32 i, q = 0; +uint32 i = 0; int8 mc; uint8 ptc; t_stat r, sta; @@ -231,15 +232,14 @@ switch (op) { /* case on op */ M[pa] = REC_MARK; /* store rec mark */ return sta; /* done */ } - if (pa == 18976) - q++; - if (bad_par[ptc]) { /* bad parity? */ + mc = ptr_to_num[ptc]; /* translate char */ + if ((bad_par[ptc]) || (mc < 0)) { /* bad par. or char? */ ind[IN_RDCHK] = 1; /* set read check */ if (io_stop) /* set return status */ sta = STOP_INVCHR; M[pa] = 0; /* store zero */ } - else M[pa] = ptr_to_num[ptc]; /* translate, store */ + else M[pa] = mc; /* stor translated char */ PP (pa); /* incr mem addr */ } break; @@ -250,8 +250,8 @@ switch (op) { /* case on op */ if (r != SCPE_OK) /* error? */ return r; if (ptc & PT_EL) { /* end record? */ - M[pa] = REC_MARK; /* store rec mark */ - M[pa - 1] = 0; + M[pa] = (M[pa] & FLAG) | REC_MARK; /* store alpha RM .. */ + M[pa - 1] = M[pa - 1] & FLAG; /* ..and preserve flags */ return sta; /* done */ } mc = ptr_to_alp[ptc]; /* translate */ @@ -294,8 +294,8 @@ switch (op) { /* case on op */ if (r != SCPE_OK) /* error? */ return r; if (ptc & PT_EL) { /* end record? */ - M[pa] = REC_MARK; /* store rec mark */ - M[pa - 1] = 0; + M[pa] = (M[pa] & FLAG) | REC_MARK; /* store alpha RM .. */ + M[pa - 1] = M[pa - 1] & FLAG; /* ..and preserve flags */ return sta; /* done */ } if (bad_par[ptc]) { /* bad parity? */ @@ -305,7 +305,7 @@ switch (op) { /* case on op */ } M[pa] = (M[pa] & FLAG) | (ptc & 07); /* store 2 digits */ M[pa - 1] = (M[pa - 1] & FLAG) | - (((ptc >> 5) & 06) | ((ptc >> 3) & 1)); + (((ptc >> 4) & 06) | ((ptc >> 3) & 1)); pa = ADDR_A (pa, 2); /* incr mem addr */ } break; @@ -332,7 +332,7 @@ do { if ((temp = getc (ptr_unit.fileref)) == EOF) { /* read char */ ind[IN_RDCHK] = 1; /* err, rd chk */ if (feof (ptr_unit.fileref)) - printf ("PTR end of file\n"); + sim_printf ("PTR end of file\n"); else perror ("PTR I/O error"); clearerr (ptr_unit.fileref); return SCPE_IOERR; @@ -352,14 +352,8 @@ return SCPE_OK; /* Bootstrap routine */ -const static uint8 boot_rom[] = { - 4, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* NOP */ - 3, 6, 0, 0, 0, 3, 1, 0, 0, 3, 0, 0, /* RNPT 31 */ - 2, 5, 0, 0, 0, 7, 1, 0, 0, 0, 0, 0, /* TD 71,loc */ - 3, 6, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, /* RNPT loc1 */ - 2, 6, 0, 0, 0, 6, 6, 0, 0, 0, 3, 5, /* TF 66,35 */ - 1, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* TDM loc2,loc3 */ - 4, 9, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0 /* BR 12 */ +static const uint8 boot_rom[] = { + 3, 6, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, /* RNPT 0 */ }; #define BOOT_START 0 @@ -367,7 +361,7 @@ const static uint8 boot_rom[] = { t_stat ptr_boot (int32 unitno, DEVICE *dptr) { -int32 i; +size_t i; extern uint32 saved_PC; for (i = 0; i < BOOT_LEN; i++) @@ -441,7 +435,7 @@ switch (op) { /* decode op */ z = M[pa - 1] & DIGIT; /* get zone */ if ((d & REC_MARK) == REC_MARK) /* 8-2 char? */ return ptp_write (PT_EL); /* end record */ - ptc = ((z & 06) << 5) | ((z & 01) << 3) | (d & 07); + ptc = ((z & 06) << 4) | ((z & 01) << 3) | (d & 07); if (bad_par[ptc]) /* set parity */ ptc = ptc | PT_C; r = ptp_write (ptc); /* write char */ @@ -465,13 +459,19 @@ t_stat ptp_num (uint32 pa, uint32 len, t_bool dump) t_stat r; uint8 d; uint32 i; +int8 ptc; for (i = 0; i < MEMSIZE; i++) { /* stop runaway */ d = M[pa] & (FLAG | DIGIT); /* get char */ if (dump? (len-- == 0): /* dump: end reached? */ ((d & REC_MARK) == REC_MARK)) /* write: rec mark? */ return ptp_write (PT_EL); /* end record */ - r = ptp_write (num_to_ptp[d]); /* write */ + ptc = num_to_ptp[d]; /* translate digit */ + if (ptc < 0) { /* bad char? */ + ind[IN_WRCHK] = 1; /* write check */ + CRETIOE(io_stop, STOP_INVCHR); + } + r = ptp_write(ptc); /* write char */ if (r != SCPE_OK) /* error? */ return r; PP (pa); /* incr mem addr */ diff --git a/I1620/i1620_sys.c b/I1620/i1620_sys.c index dc218d52..90290bc1 100644 --- a/I1620/i1620_sys.c +++ b/I1620/i1620_sys.c @@ -1,6 +1,6 @@ /* i1620_sys.c: IBM 1620 simulator interface - Copyright (c) 2002-2008, Robert M. Supnik + Copyright (c) 2002-2015, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -39,7 +39,7 @@ extern DEVICE dp_dev; extern UNIT cpu_unit; extern REG cpu_reg[]; extern uint8 M[MAXMEMSIZE]; -extern char cdr_to_alp[128], alp_to_cdp[256]; +extern int8 cdr_to_alp[128], alp_to_cdp[256]; /* SCP data structures and interface routines @@ -474,7 +474,8 @@ return SCPE_OK; t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw) { int32 i, qv, opfl, last; -char t, la, *fptr, gbuf[CBUFSIZE]; +char la, *fptr, gbuf[CBUFSIZE]; +int8 t; while (isspace (*cptr)) /* absorb spaces */ cptr++; diff --git a/I1620/i1620_tty.c b/I1620/i1620_tty.c index ce9d64bb..d2a029cf 100644 --- a/I1620/i1620_tty.c +++ b/I1620/i1620_tty.c @@ -1,6 +1,6 @@ /* i1620_tty.c: IBM 1620 typewriter - Copyright (c) 2002-2014, Robert M. Supnik + Copyright (c) 2002-2015, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,8 @@ tty console typewriter + 21-Feb-15 TFM Option to provide single digit numeric output + 05-Feb-15 TFM Changes to translate tables and valid input char. 02-Jan-14 RMS Added variable tab stops 10-Dec-13 RMS Fixed DN wraparound (Bob Armstrong) 21-Sep-05 RMS Revised translation tables for 7094/1401 compatibility @@ -33,7 +35,11 @@ #include "i1620_defs.h" +#define NUM_1_DIGIT TRUE /* Indicate numeric output will use single digit format (tfm) */ + #define TTO_COLMAX 80 +#define UF_V_1DIG (UNIT_V_UF) +#define UF_1DIG (1 << UF_V_1DIG) int32 tto_col = 0; uint8 tto_tabs[TTO_COLMAX + 1] = { @@ -89,6 +95,8 @@ MTAB tty_mod[] = { &tty_set_fixtabs, NULL, NULL }, { MTAB_XTD|MTAB_VDV, 8, NULL, "DEFAULTTABS", &tty_set_fixtabs, NULL, NULL }, + { UF_1DIG, UF_1DIG, "combined digits and flags", "1DIGIT", NULL }, + { UF_1DIG, 0 , "separate digits and flags", "2DIGIT", NULL }, { 0 } }; @@ -103,7 +111,39 @@ DEVICE tty_dev = { /* Keyboard to numeric */ -const char *tti_to_num = "0123456789|=@:;}"; +/* The following constant is a list of valid 1620 numeric characters + that can be entered from the keyboard. They are the digits 0-9, + record mark(|), numeric blank(@) and group mark(}). All others + are cosidered invalid. When entering data, these characters may + all be preceeded by tilde(~) or accent(`) to indicate that the + following character should be entered into storage with a flag. + + Alternatively, ] can be entered for flagged 0, + J-R or j-r can be entered for flagged 1-9, + ! for flagged RM, * for flagged numeric blank, + " for flagged GM. + + These different methods of entering numeric data represent + compromises since there is no practical way to exactly emulate + the 1620 typewriter capability of entering a flag but not + spacing the carriage. Entering a flag symbol in front of a + character is easier and sometimes more readable; using the + letters j-r is useful if column alignment is important on + the screen or when copying data that has printed letters in + place of flagged digits. This also matches the output of WN + or DN to the line printer. + + *tti_to_num is the string of valid characters + tti_position_to_internal[] are the matching internal codes + (Tom McBride)*/ + +const char *tti_to_num = "0123456789|@}]jklmnopqr!*\"JKLMNOPQR"; +const char tti_position_to_internal[35] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, REC_MARK, NUM_BLANK, GRP_MARK, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, + FLG_REC_MARK, FLG_NUM_BLANK, FLG_GRP_MARK, + 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19 +}; /* Keyboard to alphameric (digit pair) - translates LC to UC */ @@ -112,43 +152,55 @@ const int8 tti_to_alp[128] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 10 */ -1, -1, -1, -1, -1, -1, -1, -1, - 0x00, 0x02, -1, 0x33, 0x13, 0x24, 0x10, 0x34, /* !"#$%&' */ + 0x00, 0x5A, 0x5F, -1, 0x13, -1, -1, -1, /* !"#$%&' */ 0x24, 0x04, 0x14, 0x10, 0x23, 0x20, 0x03, 0x21, /* ()*+,-./ */ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 01234567 */ 0x78, 0x79, -1, -1, -1, 0x33, -1, -1, /* 89:;<=>? */ 0x34, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* @ABCDEFG */ 0x48, 0x49, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, /* HIJKLMNO */ 0x57, 0x58, 0x59, 0x62, 0x63, 0x64, 0x65, 0x66, /* PQRSTUVW */ - 0x67, 0x68, 0x69, -1, -1, -1, -1, -1, /* XYZ[\]^_ */ + 0x67, 0x68, 0x69, -1, -1, 0x50, -1, -1, /* XYZ[\]^_ */ -1, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* `abcdefg */ 0x48, 0x49, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, /* hijklmno */ 0x57, 0x58, 0x59, 0x62, 0x63, 0x64, 0x65, 0x66, /* pqrstuvw */ - 0x67, 0x68, 0x69, -1, -1, 0x0F, -1, -1 /* xyz{|}~ */ + 0x67, 0x68, 0x69, -1, 0x0A, 0x0F, -1, -1 /* xyz{|}~ */ }; /* Numeric (digit) to typewriter */ -const char num_to_tto[16] = { +/* Digits with values of 11, 13 and 14 should never occur and will be typed as :'s + if they ever do. These are really errors. (Tom McBride) */ + +/* If flagged digits are being printed with preceeding ` characters only the first + half of this table is actually used. If digits are being printed one char per + digit the whole table is used. (Tom McBride) */ + +const char num_to_tto[32] = { '0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', '|', '=', '@', ':', ';', '}' + '8', '9', '|', ':', '@', ':', ':', '}', + + ']', 'J', 'K', 'L', 'M', 'N', 'O', 'P', + 'Q', 'R', '!', ':', '*', ':', ':', '"' }; /* Alphameric (digit pair) to typewriter */ +/* Characters not in 1620 set have been removed from table (tfm) */ + const char alp_to_tto[256] = { - ' ', -1, '?', '.', ')', -1, -1, -1, /* 00 */ + ' ', -1, -1, '.', ')', -1, -1, -1, /* 00 */ -1, -1, -1, -1, -1, -1, -1, -1, - '+', -1, '!', '$', '*', ' ', -1, -1, /* 10 */ + '+', -1, -1, '$', '*', -1, -1, -1, /* 10 */ -1, -1, -1, -1, -1, -1, -1, -1, - '-', '/', '|', ',', '(', -1, -1, -1, /* 20 */ + '-', '/', -1, ',', '(', -1, -1, -1, /* 20 */ -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, '0', '=', '@', ':', -1, -1, /* 30 */ + -1, -1, -1, '=', '@', -1, -1, -1, /* 30 */ -1, -1, -1, -1, -1, -1, -1, -1, -1, 'A', 'B', 'C', 'D', 'E', 'F', 'G', /* 40 */ 'H', 'I', -1, -1, -1, -1, -1, -1, '-', 'J', 'K', 'L', 'M', 'N', 'O', 'P', /* 50 */ 'Q', 'R', -1, -1, -1, -1, -1, -1, - -1, '/', 'S', 'T', 'U', 'V', 'W', 'X', /* 60 */ + -1, -1, 'S', 'T', 'U', 'V', 'W', 'X', /* 60 */ 'Y', 'Z', -1, -1, -1, -1, -1, -1, '0', '1', '2', '3', '4', '5', '6', '7', /* 70 */ '8', '9', -1, -1, -1, -1, -1, -1, @@ -250,7 +302,7 @@ switch (op) { /* case on op */ case OP_WA: for (i = 0; i < MEMSIZE; i = i + 2) { /* stop runaway */ d = M[pa] & DIGIT; /* get digit */ - if ((d & 0xA) == REC_MARK) /* 8-2 char? done */ + if ((d & REC_MARK) == REC_MARK) /* 8-2 char? done */ return sta; d = ((M[pa - 1] & DIGIT) << 4) | d; /* get digit pair */ ttc = alp_to_tto[d]; /* translate */ @@ -276,7 +328,7 @@ return STOP_RWRAP; t_stat tti_rnum (int8 *c) { int8 raw, flg = 0; -char *cp; +const char *cp; t_stat r; *c = -1; /* no char yet */ @@ -288,8 +340,8 @@ do { *c = 0x7F; else if ((raw == '~') || (raw == '`')) /* flag? mark */ flg = FLAG; - else if (cp = strchr (tti_to_num, raw)) /* legal? */ - *c = ((int8) (cp - tti_to_num)) | flg; /* assemble char */ + else if ((cp = strchr (tti_to_num, raw)) != 0) /* legal? */ + *c = tti_position_to_internal[(cp - tti_to_num)] | flg; /* assemble char */ else raw = 007; /* beep! */ tto_write (raw); /* echo */ } while (*c == -1); @@ -326,7 +378,7 @@ int32 t; do { t = sim_poll_kbd (); /* get character */ - } while ((t == SCPE_OK) || (t & SCPE_BREAK)); /* ignore break */ + } while ((t == SCPE_OK) || (t & SCPE_BREAK)); /* ignore break */ if (t < SCPE_KFLAG) /* error? */ return t; *c = t & 0177; /* store character */ @@ -346,10 +398,14 @@ for (i = 0; i < MEMSIZE; i++) { /* (stop runaway) */ if (dump? (len-- == 0): /* dump: end reached? */ ((d & REC_MARK) == REC_MARK)) /* write: rec mark? */ return SCPE_OK; /* end operation */ - if (d & FLAG) /* flag? */ - tto_write ('`'); - r = tto_write (num_to_tto[d & DIGIT]); /* write */ - if (r != SCPE_OK) /* error? */ + if (tty_unit.flags & UF_1DIG) /* how display flagged digits? */ + r = tto_write (num_to_tto[d]); /* single digit display */ + else { + if (d & FLAG) /* flag? */ + tto_write ('`'); /* write flag indicator */ + r = tto_write (num_to_tto[d & DIGIT]); /* write the digit */ + } + if (r != SCPE_OK) /* write error? */ return r; PP (pa); /* incr mem addr */ } diff --git a/I7094/i7094_binloader.c b/I7094/i7094_binloader.c index 86c7d5cd..a6939307 100644 --- a/I7094/i7094_binloader.c +++ b/I7094/i7094_binloader.c @@ -30,37 +30,37 @@ * Changes: * 10/20/03 DGP Original. * 12/28/04 DGP Changed for new object formats. -* +* ***********************************************************************/ -#define IBSYSSYM '$' /* Marks end of object file */ -#define WORDPERREC 5 /* Object words per record */ -#define LOADADDR 0200 /* Default load address */ -#define OBJRECLEN 80 /* Object record length */ -#define CHARWORD 12 /* Characters per word */ +#define IBSYSSYM '$' /* Marks end of object file */ +#define WORDPERREC 5 /* Object words per record */ +#define LOADADDR 0200 /* Default load address */ +#define OBJRECLEN 80 /* Object record length */ +#define CHARWORD 12 /* Characters per word */ /* ** Object tags */ -#define IDT_TAG '0' /* 0SSSSSS0LLLLL */ -#define ABSENTRY_TAG '1' /* 10000000AAAAA */ -#define RELENTRY_TAG '2' /* 20000000RRRRR */ -#define ABSEXTRN_TAG '3' /* 3SSSSSS0AAAAA */ -#define RELEXTRN_TAG '4' /* 4SSSSSS0RRRRR */ -#define ABSGLOBAL_TAG '5' /* 5SSSSSS0AAAAA */ -#define RELGLOBAL_TAG '6' /* 6SSSSSS0RRRRR */ -#define ABSORG_TAG '7' /* 70000000AAAAA */ -#define RELORG_TAG '8' /* 80000000RRRRR */ -#define ABSDATA_TAG '9' /* 9AAAAAAAAAAAA */ -#define RELADDR_TAG 'A' /* AAAAAAAARRRRR */ -#define RELDECR_TAG 'B' /* BARRRRRAAAAAA */ -#define RELBOTH_TAG 'C' /* CARRRRRARRRRR */ -#define BSS_TAG 'D' /* D0000000PPPPP */ -#define ABSXFER_TAG 'E' /* E0000000RRRRR */ -#define RELXFER_TAG 'F' /* F0000000RRRRR */ -#define EVEN_TAG 'G' /* G0000000RRRRR */ -#define FAPCOMMON_TAG 'H' /* H0000000AAAAA */ +#define IDT_TAG '0' /* 0SSSSSS0LLLLL */ +#define ABSENTRY_TAG '1' /* 10000000AAAAA */ +#define RELENTRY_TAG '2' /* 20000000RRRRR */ +#define ABSEXTRN_TAG '3' /* 3SSSSSS0AAAAA */ +#define RELEXTRN_TAG '4' /* 4SSSSSS0RRRRR */ +#define ABSGLOBAL_TAG '5' /* 5SSSSSS0AAAAA */ +#define RELGLOBAL_TAG '6' /* 6SSSSSS0RRRRR */ +#define ABSORG_TAG '7' /* 70000000AAAAA */ +#define RELORG_TAG '8' /* 80000000RRRRR */ +#define ABSDATA_TAG '9' /* 9AAAAAAAAAAAA */ +#define RELADDR_TAG 'A' /* AAAAAAAARRRRR */ +#define RELDECR_TAG 'B' /* BARRRRRAAAAAA */ +#define RELBOTH_TAG 'C' /* CARRRRRARRRRR */ +#define BSS_TAG 'D' /* D0000000PPPPP */ +#define ABSXFER_TAG 'E' /* E0000000RRRRR */ +#define RELXFER_TAG 'F' /* F0000000RRRRR */ +#define EVEN_TAG 'G' /* G0000000RRRRR */ +#define FAPCOMMON_TAG 'H' /* H0000000AAAAA */ /* Where: * SSSSSS - Symbol @@ -115,96 +115,92 @@ binloader (FILE *fd, char *file, int loadpt) char *op = inbuf; int i; - if (*op == IBSYSSYM) /* End of object marker */ + if (*op == IBSYSSYM) /* End of object marker */ break; for (i = 0; i < WORDPERREC; i++) { - char otag; - char item[16]; - t_uint64 ldata; + char otag; + char item[16]; + t_uint64 ldata; - otag = *op++; - if (otag == ' ') - break; - strncpy (item, op, CHARWORD); - item[CHARWORD] = '\0'; -#ifdef WIN32 - sscanf (item, "%I64o", &ldata); -#else - sscanf (item, "%llo", &ldata); -#endif + otag = *op++; + if (otag == ' ') + break; + strncpy (item, op, CHARWORD); + item[CHARWORD] = '\0'; + sscanf (item, "%" LL_FMT "o", &ldata); #ifdef DEBUGLOADER - fprintf (lfd, "loadaddr = %05o, curraddr = %05o\n", - loadaddr, curraddr); - fprintf (lfd, " otag = %c, item = %s\n", otag, item); - fprintf (lfd, " ldata = %12.12o\n", ldata); + fprintf (lfd, "loadaddr = %05o, curraddr = %05o\n", + loadaddr, curraddr); + fprintf (lfd, " otag = %c, item = %s\n", otag, item); + fprintf (lfd, " ldata = %12.12o\n", ldata); #endif - switch (otag) - { - case IDT_TAG: - break; + switch (otag) + { + case IDT_TAG: + break; - case ABSORG_TAG: - curraddr = loadaddr = (int32) ldata & AMASK; - break; + case ABSORG_TAG: + curraddr = loadaddr = (int32) ldata & AMASK; + break; - case RELORG_TAG: - curraddr = (int32) (ldata + loadaddr) & AMASK; - break; + case RELORG_TAG: + curraddr = (int32) (ldata + loadaddr) & AMASK; + break; - case BSS_TAG: - curraddr = (int32) (curraddr + ldata) & AMASK; - break; + case BSS_TAG: + curraddr = (int32) (curraddr + ldata) & AMASK; + break; - case RELBOTH_TAG: - ldata = ldata + loadaddr + (loadaddr << INST_V_DEC); - goto STORE; + case RELBOTH_TAG: + ldata = ldata + loadaddr + (loadaddr << INST_V_DEC); + goto STORE; - case RELDECR_TAG: - ldata = ldata + (loadaddr << INST_V_DEC); - goto STORE; + case RELDECR_TAG: + ldata = ldata + (loadaddr << INST_V_DEC); + goto STORE; - case RELADDR_TAG: - ldata = ldata + loadaddr; + case RELADDR_TAG: + ldata = ldata + loadaddr; - case ABSDATA_TAG: - STORE: + case ABSDATA_TAG: + STORE: #ifdef DEBUGLOADER - fprintf (lfd, " M[%05o] = %12.12o\n", curraddr, ldata); + fprintf (lfd, " M[%05o] = %12.12o\n", curraddr, ldata); #endif - M[curraddr] = ldata & DMASK; - curraddr++; - break; + M[curraddr] = ldata & DMASK; + curraddr++; + break; - case ABSXFER_TAG: - transfer = TRUE; - case ABSENTRY_TAG: - PC = (uint32) ldata & AMASK; + case ABSXFER_TAG: + transfer = TRUE; + case ABSENTRY_TAG: + PC = (uint32) ldata & AMASK; #ifdef DEBUGLOADER - fprintf (lfd, " PC = %05o\n", PC); + fprintf (lfd, " PC = %05o\n", PC); #endif - if (transfer) + if (transfer) goto GOSTART; - break; + break; - case RELXFER_TAG: - transfer = TRUE; - case RELENTRY_TAG: - ldata = (ldata + loadaddr) & AMASK; - PC = (uint32) ldata & AMASK; + case RELXFER_TAG: + transfer = TRUE; + case RELENTRY_TAG: + ldata = (ldata + loadaddr) & AMASK; + PC = (uint32) ldata & AMASK; #ifdef DEBUGLOADER - fprintf (lfd, " PC = %05o\n", PC); + fprintf (lfd, " PC = %05o\n", PC); #endif - if (transfer) + if (transfer) goto GOSTART; - break; + break; - default: ; - } - op += CHARWORD; + default: ; + } + op += CHARWORD; } } diff --git a/I7094/i7094_cd.c b/I7094/i7094_cd.c index cbdcf458..9b286653 100644 --- a/I7094/i7094_cd.c +++ b/I7094/i7094_cd.c @@ -88,7 +88,6 @@ t_stat cd_attach (UNIT *uptr, char *cptr); t_stat cd_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc); char colbin_to_bcd (uint32 cb); -extern int32 sim_switches; extern uint32 PC; extern uint32 ind_ioc; extern char bcd_to_ascii_a[64]; @@ -292,11 +291,11 @@ return SCPE_OK; #define BOOT_SIZE (sizeof (boot_rom) / sizeof (t_uint64)) static const t_uint64 boot_rom[] = { - 00762000001000 + U_CDR, /* RDSA CDR */ - 00544000000000 + BOOT_START + 4, /* LCHA *+3 */ - 00544000000000, /* LCHA 0 */ - 00021000000001, /* TTR 1 */ - 05000030000000, /* IOCT 3,,0 */ + INT64_C(00762000001000) + U_CDR, /* RDSA CDR */ + INT64_C(00544000000000) + BOOT_START + 4, /* LCHA *+3 */ + INT64_C(00544000000000), /* LCHA 0 */ + INT64_C(00021000000001), /* TTR 1 */ + INT64_C(05000030000000), /* IOCT 3,,0 */ }; t_stat cdr_boot (int32 unitno, DEVICE *dptr) diff --git a/I7094/i7094_clk.c b/I7094/i7094_clk.c index d3020093..311757fb 100644 --- a/I7094/i7094_clk.c +++ b/I7094/i7094_clk.c @@ -74,7 +74,8 @@ if ((clk_dev.flags & DEV_DIS) == 0) { /* clock enabled? */ WriteP (CLK_CTR, ctr); if (ctr == 0) /* overflow? req trap */ chtr_clk = 1; - sim_activate (uptr, sim_rtcn_calb (CLK_TPS, TMR_CLK)); /* reactivate unit */ + sim_rtcn_calb (CLK_TPS, TMR_CLK); /* calibrate clock */ + sim_activate_after (uptr, 1000000/CLK_TPS); /* reactivate unit */ } return SCPE_OK; } diff --git a/I7094/i7094_com.c b/I7094/i7094_com.c index b5c7b29d..94d0c3df 100644 --- a/I7094/i7094_com.c +++ b/I7094/i7094_com.c @@ -114,8 +114,8 @@ /* Communications output */ -#define COMO_LIN12B 0200000000000 /* line is 12b */ -#define COMO_LINCTL 0100000000000 /* control msg */ +#define COMO_LIN12B INT64_C(0200000000000) /* line is 12b */ +#define COMO_LINCTL INT64_C(0100000000000) /* control msg */ #define COMO_GETLN(x) (((uint32) ((x) >> 24)) & 0777) #define COMO_CTLRST 00000 /* control reset */ #define COMO_BITRPT 03777 /* bit repeat */ @@ -125,20 +125,20 @@ /* Status word (60b) */ -#define COMS_PCHK 004000000000000000000 /* prog check */ -#define COMS_DCHK 002000000000000000000 /* data check */ -#define COMS_EXCC 001000000000000000000 /* exc cond */ -#define COMS_MLNT 000040000000000000000 /* message length check */ -#define COMS_CHNH 000020000000000000000 /* channel hold */ -#define COMS_CHNQ 000010000000000000000 /* channel queue full */ -#define COMS_ITMO 000000100000000000000 /* interface timeout */ -#define COMS_DATR 000000004000000000000 /* data message ready */ -#define COMS_INBF 000000002000000000000 /* input buffer free */ -#define COMS_SVCR 000000001000000000000 /* service message ready */ -#define COMS_PALL 000000000000000000000 -#define COMS_DALL 000000000000000000000 -#define COMS_EALL 000000000000000000000 -#define COMS_DYN 000000007000000000000 +#define COMS_PCHK INT64_C(004000000000000000000) /* prog check */ +#define COMS_DCHK INT64_C(002000000000000000000) /* data check */ +#define COMS_EXCC INT64_C(001000000000000000000) /* exc cond */ +#define COMS_MLNT INT64_C(000040000000000000000) /* message length check */ +#define COMS_CHNH INT64_C(000020000000000000000) /* channel hold */ +#define COMS_CHNQ INT64_C(000010000000000000000) /* channel queue full */ +#define COMS_ITMO INT64_C(000000100000000000000) /* interface timeout */ +#define COMS_DATR INT64_C(000000004000000000000) /* data message ready */ +#define COMS_INBF INT64_C(000000002000000000000) /* input buffer free */ +#define COMS_SVCR INT64_C(000000001000000000000) /* service message ready */ +#define COMS_PALL INT64_C(000000000000000000000) +#define COMS_DALL INT64_C(000000000000000000000) +#define COMS_EALL INT64_C(000000000000000000000) +#define COMS_DYN INT64_C(000000007000000000000) /* Report variables */ @@ -183,10 +183,10 @@ uint32 com_chob_v = 0; /* valid flag */ t_uint64 com_buf[COM_BUFSIZ]; /* channel buffer */ LISTHD com_free; /* free list */ uint32 com_not_ret[COM_TLINES] = { 0 }; /* chars not returned */ -LISTHD com_inpq[COM_TLINES] = { 0 }; /* input queues */ -LISTHD com_outq[COM_TLINES] = { 0 }; /* output queues */ +LISTHD com_inpq[COM_TLINES] = { {0} }; /* input queues */ +LISTHD com_outq[COM_TLINES] = { {0} }; /* output queues */ LISTENT com_pkt[COM_PKTSIZ]; /* character packets */ -TMLN com_ldsc[COM_MLINES] = { 0 }; /* line descriptors */ +TMLN com_ldsc[COM_MLINES] = { {0} }; /* line descriptors */ TMXR com_desc = { COM_MLINES, 0, 0, com_ldsc }; /* mux descriptor */ /* Even parity truth table */ @@ -338,7 +338,7 @@ MTAB com_mod[] = { NULL, &com_show_ctrl, 0 }, { MTAB_XTD | MTAB_VDV | MTAB_NMO, COMR_OQ, "OUTQ", NULL, NULL, &com_show_ctrl, 0 }, - { MTAB_XTD | MTAB_VDV | MTAB_NMO, -1, "ALL", NULL, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0xFFFFFFFF, "ALL", NULL, NULL, &com_show_ctrl, 0 }, { 0 } }; @@ -348,7 +348,7 @@ DEVICE com_dev = { 3, 10, 31, 1, 16, 8, &tmxr_ex, &tmxr_dep, &com_reset, NULL, &com_attach, &com_detach, - &com_dib, DEV_NET | DEV_DIS + &com_dib, DEV_MUX | DEV_DIS }; /* COML data structures @@ -558,7 +558,7 @@ switch (com_sta) { /* case on state */ case CHSL_WRS|CHSL_2ND: /* write first word */ dat = com_getob (com_ch); /* get word? */ - if (dat == 0777777777777) { /* turn on? */ + if (dat == INT64_C(0777777777777)) { /* turn on? */ com_enab = 1; /* enable 7750 */ com_msgn = 0; /* init message # */ com_end (com_ch, 0, CHSL_WRS|CHSL_4TH); /* end, last state */ @@ -1175,7 +1175,7 @@ char name[20]; ln = uptr - coml_dev.units; sprintf (name, val? "Output queue %d": "Input queue %d", ln); lh = val? &com_outq[ln]: &com_inpq[ln]; -if (entc = com_show_qsumm (st, lh, name)) { +if ((entc = com_show_qsumm (st, lh, name))) { for (i = 0, next = lh->head; next != 0; i++, next = com_pkt[next].next) { if ((i % 8) == 0) diff --git a/I7094/i7094_cpu.c b/I7094/i7094_cpu.c index f1d46462..64c406db 100644 --- a/I7094/i7094_cpu.c +++ b/I7094/i7094_cpu.c @@ -211,11 +211,6 @@ extern uint32 ch_sta[NUM_CHAN]; extern uint32 ch_flags[NUM_CHAN]; extern DEVICE mt_dev[NUM_CHAN]; extern DEVICE ch_dev[NUM_CHAN]; -extern FILE *sim_deb; -extern int32 sim_int_char; -extern int32 sim_interval; -extern int32 sim_switches; -extern uint32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ /* Forward and external declarations */ @@ -664,14 +659,14 @@ while (reason == SCPE_OK) { /* loop until error */ } if (sim_interval <= 0) { /* intv cnt expired? */ - if (reason = sim_process_event ()) /* process events */ + if ((reason = sim_process_event ())) /* process events */ break; chtr_pend = chtr_eval (NULL); /* eval chan traps */ } for (i = 0; ch_req && (i < NUM_CHAN); i++) { /* loop thru channels */ if (ch_req & REQ_CH (i)) { /* channel request? */ - if (reason = ch_proc (i)) + if ((reason = ch_proc (i))) break; } chtr_pend = chtr_eval (NULL); @@ -980,7 +975,7 @@ while (reason == SCPE_OK) { /* loop until error */ if (!Read (ea, &SR)) break; AC = (AC & AC_S) | ((AC >> 6) & 0017777777777) | - (SR & 0770000000000); + (SR & INT64_C(0770000000000)); sc--; } if ((sc == 0) && (IR & INST_T_CXR1)) @@ -1973,13 +1968,13 @@ while (reason == SCPE_OK) { /* loop until error */ t_stat r; for (i = 0; (i < HALT_IO_LIMIT) && !ch_qidle (); i++) { sim_interval = 0; - if (r = sim_process_event ()) /* process events */ + if ((r = sim_process_event ())) /* process events */ return r; chtr_pend = chtr_eval (NULL); /* eval chan traps */ while (ch_req) { /* until no ch req */ for (j = 0; j < NUM_CHAN; j++) { /* loop thru channels */ if (ch_req & REQ_CH (j)) { /* channel request? */ - if (r = ch_proc (j)) + if ((r = ch_proc (j))) return r; } chtr_pend = chtr_eval (NULL); @@ -2406,13 +2401,11 @@ t_stat cpu_fprint_one_inst (FILE *st, uint32 pc, uint32 rpt, uint32 ea, { int32 ch; t_value sim_eval; -extern t_stat fprint_sym (FILE *ofile, t_addr addr, t_value *val, - UNIT *uptr, int32 sw); sim_eval = ir; if (pc & HIST_PC) { /* instruction? */ fputs ("CPU ", st); - fprintf (st, "%05o ", pc & AMASK); + fprintf (st, "%05o ", (int)(pc & AMASK)); if (rpt == 0) fprintf (st, " "); else if (rpt < 1000000) @@ -2438,11 +2431,11 @@ if (pc & HIST_PC) { /* instruction? */ } fputc ('\n', st); /* end line */ } /* end if instruction */ -else if (ch = HIST_CH (pc)) { /* channel? */ +else if ((ch = HIST_CH (pc))) { /* channel? */ fprintf (st, "CH%c ", 'A' + ch - 1); - fprintf (st, "%05o ", pc & AMASK); + fprintf (st, "%05o ", (int)(pc & AMASK)); fputs (" ", st); - fprintf (st, "%05o ", ea & AMASK); + fprintf (st, "%05o ", (int)(ea & AMASK)); if (fprint_sym (st, pc & AMASK, &sim_eval, &cpu_unit, (ch_dev[ch - 1].flags & DEV_7909)? SWMASK ('N'): SWMASK ('I')) > 0) { fputs ("(undefined) ", st); diff --git a/I7094/i7094_defs.h b/I7094/i7094_defs.h index b100989e..ae7c7346 100644 --- a/I7094/i7094_defs.h +++ b/I7094/i7094_defs.h @@ -33,8 +33,8 @@ */ -#ifndef _I7094_DEFS_H_ -#define _I7094_DEFS_H_ 0 +#ifndef I7094_DEFS_H_ +#define I7094_DEFS_H_ 0 #include "sim_defs.h" /* simulator defns */ @@ -124,25 +124,25 @@ typedef struct { /* Integer */ -#define DMASK 0777777777777 /* data mask */ -#define SIGN 0400000000000 /* sign */ -#define MMASK 0377777777777 /* magnitude mask */ -#define LMASK 0777777000000 /* left mask */ -#define RMASK 0000000777777 /* right mask */ -#define PMASK 0700000000000 /* prefix */ -#define XMASK 0077777000000 /* decrement */ -#define TMASK 0000000700000 /* tag */ -#define AMASK 0000000077777 /* address */ -#define SCMASK 0000000000377 /* shift count mask */ -#define B1 0200000000000 /* bit 1 */ -#define B9 0000400000000 /* bit 9 */ +#define DMASK INT64_C(0777777777777) /* data mask */ +#define SIGN INT64_C(0400000000000) /* sign */ +#define MMASK INT64_C(0377777777777) /* magnitude mask */ +#define LMASK INT64_C(0777777000000) /* left mask */ +#define RMASK INT64_C(0000000777777) /* right mask */ +#define PMASK INT64_C(0700000000000) /* prefix */ +#define XMASK INT64_C(0077777000000) /* decrement */ +#define TMASK INT64_C(0000000700000) /* tag */ +#define AMASK INT64_C(0000000077777) /* address */ +#define SCMASK INT64_C(0000000000377) /* shift count mask */ +#define B1 INT64_C(0200000000000) /* bit 1 */ +#define B9 INT64_C(0000400000000) /* bit 9 */ /* Accumulator is actually 38b wide */ -#define AC_S 02000000000000 /* sign */ -#define AC_Q 01000000000000 /* Q */ -#define AC_P 00400000000000 /* P */ -#define AC_MMASK 01777777777777 /* Q+P+magnitude */ +#define AC_S INT64_C(02000000000000) /* sign */ +#define AC_Q INT64_C(01000000000000) /* Q */ +#define AC_P INT64_C(00400000000000) /* P */ +#define AC_MMASK INT64_C(01777777777777) /* Q+P+magnitude */ /* Floating point */ @@ -159,8 +159,8 @@ typedef struct { /* Instruction format */ -#define INST_T_DEC 0300000000000 /* if nz, takes decr */ -#define INST_T_CXR1 0000000100000 /* if nz, update XR1 */ +#define INST_T_DEC INT64_C(0300000000000) /* if nz, takes decr */ +#define INST_T_CXR1 INT64_C(0000000100000) /* if nz, update XR1 */ #define INST_V_OPD 33 /* decrement opcode */ #define INST_M_OPD 07 #define INST_V_DEC 18 /* decrement */ @@ -177,8 +177,8 @@ typedef struct { #define INST_M_TAG 07 #define INST_V_ADDR 0 #define INST_M_ADDR 077777 -#define INST_V_4B 0 -#define INST_M_4B 017 +#define INST_V_4B 0 +#define INST_M_4B 017 #define GET_OPD(x) ((uint32) (((x) >> INST_V_OPD) & INST_M_OPD)) #define GET_DEC(x) ((uint32) (((x) >> INST_V_DEC) & INST_M_DEC)) @@ -419,8 +419,8 @@ typedef struct { #define CHF_V_LCC 30 /* loop ctrl counter */ #define CHF_M_LCC 077 -#define CHF_CLR_7909 07775000177 /* 7909 clear flags */ -#define CHF_SDC_7909 07777600000 /* 7909 SDC flags */ +#define CHF_CLR_7909 INT64_C(07775000177) /* 7909 clear flags */ +#define CHF_SDC_7909 INT64_C(07777600000) /* 7909 SDC flags */ /* Channel characteristics (in dev.flags) */ diff --git a/I7094/i7094_dsk.c b/I7094/i7094_dsk.c index 4c605c81..d5b30c3d 100644 --- a/I7094/i7094_dsk.c +++ b/I7094/i7094_dsk.c @@ -143,12 +143,12 @@ /* Track/record structure */ #define THA2 0 /* home address 2 */ -#define HA2_MASK 0777700000000 /* two chars checked */ +#define HA2_MASK INT64_C(0777700000000) /* two chars checked */ #define T1STREC 1 /* start of records */ #define RLNT 0 /* record length */ #define RADDR 1 /* record address */ #define RDATA 2 /* start of data */ -#define REC_MASK 0171717177777 /* 4 digits, 2 chars */ +#define REC_MASK INT64_C(0171717177777) /* 4 digits, 2 chars */ /* Command word (60b) - 10 BCD digits */ @@ -167,27 +167,27 @@ /* Status word (60b) */ -#define DSKS_PCHK 004000000000000000000 /* prog check */ -#define DSKS_DCHK 002000000000000000000 /* data check */ -#define DSKS_EXCC 001000000000000000000 /* exc cond */ -#define DSKS_INVS 000200000000000000000 /* invalid seq */ -#define DSKS_INVC 000040000000000000000 /* invalid opcode */ -#define DSKS_FMTC 000020000000000000000 /* format check */ -#define DSKS_NRCF 000010000000000000000 /* no record found */ -#define DSKS_INVA 000002000000000000000 /* invalid address */ -#define DSKS_RSPC 000000400000000000000 /* response check */ -#define DSKS_CMPC 000000200000000000000 /* compare check */ -#define DSKS_PARC 000000100000000000000 /* parity check */ -#define DSKS_ACCI 000000020000000000000 /* access inoperative */ -#define DSKS_ACCN 000000004000000000000 /* access not ready */ -#define DSKS_DSKE 000000002000000000000 /* disk error */ -#define DSKS_FILE 000000001000000000000 /* file error */ -#define DSKS_6B 000000000040000000000 /* six bit mode */ -#define DSKS_ATN0 000000000002000000000 /* attention start */ -#define DSKS_PALL 000777000000000000000 -#define DSKS_DALL 000000740000000000000 -#define DSKS_EALL 000000037000000000000 -#define DSKS_ALLERR 007777777000000000000 +#define DSKS_PCHK INT64_C(004000000000000000000) /* prog check */ +#define DSKS_DCHK INT64_C(002000000000000000000) /* data check */ +#define DSKS_EXCC INT64_C(001000000000000000000) /* exc cond */ +#define DSKS_INVS INT64_C(000200000000000000000) /* invalid seq */ +#define DSKS_INVC INT64_C(000040000000000000000) /* invalid opcode */ +#define DSKS_FMTC INT64_C(000020000000000000000) /* format check */ +#define DSKS_NRCF INT64_C(000010000000000000000) /* no record found */ +#define DSKS_INVA INT64_C(000002000000000000000) /* invalid address */ +#define DSKS_RSPC INT64_C(000000400000000000000) /* response check */ +#define DSKS_CMPC INT64_C(000000200000000000000) /* compare check */ +#define DSKS_PARC INT64_C(000000100000000000000) /* parity check */ +#define DSKS_ACCI INT64_C(000000020000000000000) /* access inoperative */ +#define DSKS_ACCN INT64_C(000000004000000000000) /* access not ready */ +#define DSKS_DSKE INT64_C(000000002000000000000) /* disk error */ +#define DSKS_FILE INT64_C(000000001000000000000) /* file error */ +#define DSKS_6B INT64_C(000000000040000000000) /* six bit mode */ +#define DSKS_ATN0 INT64_C(000000000002000000000) /* attention start */ +#define DSKS_PALL INT64_C(000777000000000000000) +#define DSKS_DALL INT64_C(000000740000000000000) +#define DSKS_EALL INT64_C(000000037000000000000) +#define DSKS_ALLERR INT64_C(007777777000000000000) /* Commands - opcode 0 */ @@ -210,7 +210,7 @@ /* CTSS record structure */ -#define CTSS_HA2 0676767676767 /* =HXXXXXX */ +#define CTSS_HA2 INT64_C(0676767676767) /* =HXXXXXX */ #define CTSS_RLNT 435 /* data record */ #define CTSS_D1LNT 31 /* padding */ #define CTSS_D2LNT 14 @@ -485,7 +485,7 @@ else { case CHSL_CTL: /* control */ dsk_cmd = val << 24; - if (val & 0100000000000) { /* need 2nd word? */ + if (val & INT64_C(0100000000000)) { /* need 2nd word? */ ch_req |= REQ_CH (ch); /* req ch for 2nd */ dsk_sta = CHSL_CTL|CHSL_2ND; /* next state */ return SCPE_OK; @@ -693,14 +693,14 @@ trk = uaptr->TRK; /* get access track */ switch (dsk_sta) { /* case on state */ case CHSL_RDS: /* read start */ - if (r = dsk_init_trk (udptr, trk)) { /* read track, err? */ + if ((r = dsk_init_trk (udptr, trk))) { /* read track, err? */ return ((r == ERR_NRCF)? SCPE_OK: r); /* rec not fnd ok */ } dsk_sta = CHSL_RDS|CHSL_2ND; /* next state */ break; case CHSL_RDS|CHSL_2ND: /* read data transmit */ - if (r = dsk_xfer_done (uaptr, dtyp)) { /* transfer done? */ + if ((r = dsk_xfer_done (uaptr, dtyp))) { /* transfer done? */ if (r != ERR_ENDRC) /* error? */ return r; dsk_sta = CHSL_RDS|CHSL_3RD; /* next state */ @@ -721,7 +721,7 @@ switch (dsk_sta) { /* case on state */ break; case CHSL_WRS: /* write start */ - if (r = dsk_init_trk (udptr, trk)) { /* read track, err? */ + if ((r = dsk_init_trk (udptr, trk))) { /* read track, err? */ return ((r == ERR_NRCF)? SCPE_OK: r); /* rec not fnd ok */ } ch_req |= REQ_CH (dsk_ch); /* first request */ @@ -742,7 +742,7 @@ switch (dsk_sta) { /* case on state */ else dsk_buf[dsk_rptr++] = dsk_chob; /* write, store word */ if (dsk_rptr == T1STREC) /* if THA, skip after HA */ dsk_rptr++; - if (r = dsk_xfer_done (uaptr, dtyp)) { /* transfer done? */ + if ((r = dsk_xfer_done (uaptr, dtyp))) { /* transfer done? */ if (r != ERR_ENDRC) /* error? */ return r; dsk_sta = CHSL_WRS|CHSL_3RD; /* next state */ @@ -755,7 +755,7 @@ switch (dsk_sta) { /* case on state */ case CHSL_WRS|CHSL_3RD: /* write done */ if (!dsk_wchk) { /* if write */ - if (r = dsk_wr_trk (udptr, trk)) /* write track; err? */ + if ((r = dsk_wr_trk (udptr, trk))) /* write track; err? */ return r; } if (dsk_qdone (dsk_ch)) /* done? exit */ @@ -846,7 +846,7 @@ switch (dsk_sta) { /* case on state */ if (!dsk_wchk) { /* actual write? */ trk = trk - (trk % dsk_tab[dtyp].trkpc); /* cyl start */ for (i = 0; i < dsk_tab[dtyp].trkpc; i++) { /* do all tracks */ - if (r = dsk_wr_trk (udptr, trk + i)) /* wr track; err? */ + if ((r = dsk_wr_trk (udptr, trk + i))) /* wr track; err? */ return r; } } @@ -1189,7 +1189,7 @@ for (a = 0, ctss = TRUE; a < dsk_tab[dtyp].accpm; a++) { fprintf (st, "Invalid record length %d, unit = %d, access = %d, track = %d, record = %d\n", rlnt, u, a, t, rec); return SCPE_OK; - } + } if (rlnt > maxrsz) maxrsz = rlnt; if (rlnt < minrsz) diff --git a/I7094/i7094_io.c b/I7094/i7094_io.c index e4e81d13..92e2b367 100644 --- a/I7094/i7094_io.c +++ b/I7094/i7094_io.c @@ -88,7 +88,6 @@ extern DEVICE mt_dev[NUM_CHAN]; extern DEVICE drm_dev; extern DEVICE dsk_dev; extern DEVICE com_dev; -extern uint32 sim_brk_summ; t_stat ch_reset (DEVICE *dptr); t_stat ch6_svc (UNIT *uptr); @@ -111,7 +110,6 @@ t_stat ch9_wr_getw (uint32 ch); void ch9_eval_int (uint32 ch, uint32 iflags); DEVICE *ch_map_flags (uint32 ch, int32 fl); -extern CTAB *sim_vm_cmd; extern t_stat ch_bkpt (uint32 ch, uint32 clc); const uint32 col_masks[12] = { /* row 9,8,..,0,11,12 */ @@ -132,8 +130,8 @@ const t_uint64 bit_masks[36] = { 0000010000000, 0000020000000, 0000040000000, 0000100000000, 0000200000000, 0000400000000, 0001000000000, 0002000000000, 0004000000000, - 0010000000000, 0020000000000, 0040000000000, - 0100000000000, 0200000000000, 0400000000000 + INT64_C(0010000000000), INT64_C(0020000000000), INT64_C(0040000000000), + INT64_C(0100000000000), INT64_C(0200000000000), INT64_C(0400000000000) }; const DEV_CHAR dev_table[] = { @@ -795,7 +793,7 @@ switch (ch_sta[ch]) { /* case on chan state */ if (ch_dev[ch].flags & DEV_7289) { /* drum channel? */ ir = ReadP (clc); /* read addr */ ch_clc[ch] = CHAINC (clc); /* incr chan pc */ - if (r = ch9_wr (ch, ir, 0)) /* write to dev */ + if ((r = ch9_wr (ch, ir, 0))) /* write to dev */ return r; } else ch_clc[ch] = clc; /* set clc */ @@ -983,7 +981,7 @@ if (ch_dev[ch].flags & DEV_7909) { /* 7909 */ case CH9_ICCA: csel = CH9D_COND (ch_wc[ch]); /* get C */ if (csel == 0) ch_ar[ch] = /* C = 0? read SMS */ - (ch_ar[ch] & 0777777770000) | ((t_uint64) ch_sms[ch]); + (ch_ar[ch] & INT64_C(0777777770000)) | ((t_uint64) ch_sms[ch]); else if (csel < 7) { /* else read cond cntr */ sc = 6 * (6 - csel); ch_ar[ch] = (ch_ar[ch] & ~(((t_uint64) 077) << sc)) | @@ -1003,7 +1001,7 @@ if (ch_dev[ch].flags & DEV_7909) { /* 7909 */ return SCPE_OK; case CH9_SNS: /* sense */ - if (r = ch9_sel (ch, CHSL_SNS)) /* send sense to dev */ + if ((r = ch9_sel (ch, CHSL_SNS))) /* send sense to dev */ return r; ch_flags[ch] |= CHF_PRD; /* prepare to read */ break; /* next command */ @@ -1019,13 +1017,13 @@ if (ch_dev[ch].flags & DEV_7909) { /* 7909 */ } ch_flags[ch] &= ~CHF_EOR; /* clear end */ if (ch_op[ch] == CH9_CTLR) { /* CTLR? */ - if (r = ch9_sel (ch, CHSL_RDS)) /* send read sel */ + if ((r = ch9_sel (ch, CHSL_RDS))) /* send read sel */ return r; ch_flags[ch] |= CHF_PRD; /* prep to read */ ch_idf[ch] = 0; } else if (ch_op[ch] == CH9_CTLW) { /* CTLW? */ - if (r = ch9_sel (ch, CHSL_WRS)) /* end write sel */ + if ((r = ch9_sel (ch, CHSL_WRS))) /* end write sel */ return r; ch_flags[ch] |= CHF_PWR; /* prep to write */ } @@ -1035,7 +1033,7 @@ if (ch_dev[ch].flags & DEV_7909) { /* 7909 */ if ((ch_wc[ch] == 0) || (ch_flags[ch] & CHF_EOR)) { /* wc == 0 or EOR? */ if (ch_flags[ch] & (CHF_PRD|CHF_PWR|CHF_RDS|CHF_WRS)) { ch_flags[ch] &= ~(CHF_PRD|CHF_PWR|CHF_RDS|CHF_WRS); - if (r = ch9_wr (ch, 0, CH9DF_STOP)) /* send stop */ + if ((r = ch9_wr (ch, 0, CH9DF_STOP))) /* send stop */ return r; } if (ch_flags[ch] & CHF_EOR) { /* EOR? */ @@ -1055,7 +1053,7 @@ if (ch_dev[ch].flags & DEV_7909) { /* 7909 */ ch_flags[ch] &= ~CHF_EOR; /* ignore */ else if (ch_flags[ch] & CHF_RDS) /* read? */ ch9_rd_putw (ch); - else if (r = ch9_wr_getw (ch)) /* no, write */ + else if ((r = ch9_wr_getw (ch))) /* no, write */ return r; if (ch_wc[ch] == 0) /* done? get next */ break; @@ -1164,7 +1162,7 @@ else { /* 7607 write */ case CH6_IOCD: /* IOCD */ if (ch_wc[ch]) { /* wc > 0? */ - if (r = ch6_wr_getw (ch, TRUE)) /* send wd to dev; err? */ + if ((r = ch6_wr_getw (ch, TRUE))) /* send wd to dev; err? */ return r; if (ch_wc[ch]) /* more to do? */ return SCPE_OK; @@ -1174,7 +1172,7 @@ else { /* 7607 write */ case CH6_IOCP: /* IOCP */ case CH6_IOSP: /* IOSP */ if (ch_wc[ch]) { /* wc > 0? */ - if (r = ch6_wr_getw (ch, FALSE)) /* send wd to dev; err? */ + if ((r = ch6_wr_getw (ch, FALSE))) /* send wd to dev; err? */ return r; if (ch_wc[ch]) /* more to do? */ return SCPE_OK; @@ -1184,7 +1182,7 @@ else { /* 7607 write */ case CH6_IOCT: /* IOCT */ case CH6_IOST: /* IOST */ if (ch_wc[ch]) { /* wc > 0? */ - if (r = ch6_wr_getw (ch, FALSE)) /* send wd to dev; err? */ + if ((r = ch6_wr_getw (ch, FALSE))) /* send wd to dev; err? */ return r; if (ch_wc[ch]) /* more to do? */ return SCPE_OK; @@ -1193,7 +1191,7 @@ else { /* 7607 write */ case CH6_IORP: /* IORP */ if (!(ch_flags[ch] & CHF_EOR) && ch_wc[ch]) { /* not EOR? (cdp, lpt) */ - if (r = ch6_wr_getw (ch, TRUE)) /* send wd to dev; err? */ + if ((r = ch6_wr_getw (ch, TRUE))) /* send wd to dev; err? */ return r; if (ch_wc[ch]) /* more to do? */ return SCPE_OK; @@ -1203,7 +1201,7 @@ else { /* 7607 write */ case CH6_IORT: /* IORT */ if (!(ch_flags[ch] & CHF_EOR) && ch_wc[ch]) { /* not EOR? (cdp, lpt) */ - if (r = ch6_wr_getw (ch, TRUE)) /* send wd to dev; err? */ + if ((r = ch6_wr_getw (ch, TRUE))) /* send wd to dev; err? */ return r; if (ch_wc[ch]) /* more to do? */ return SCPE_OK; diff --git a/I7094/i7094_mt.c b/I7094/i7094_mt.c index edf1d06b..4c9731af 100644 --- a/I7094/i7094_mt.c +++ b/I7094/i7094_mt.c @@ -72,7 +72,6 @@ static const char *tape_stat[] = { extern uint32 PC; extern uint32 cpu_model; extern uint32 ind_ioc; -extern FILE *sim_deb; extern const char *sel_name[]; t_stat mt_chsel (uint32 ch, uint32 sel, uint32 unit); @@ -368,7 +367,7 @@ DEVICE mt_dev[NUM_CHAN] = { MT_NUMDR + 1, 10, 31, 1, 8, 8, NULL, NULL, &mt_reset, &mt_boot, &mt_attach, &sim_tape_detach, - &mt_dib, DEV_DEBUG + &mt_dib, DEV_DEBUG | DEV_TAPE }, { "MTB", mtb_unit, mtb_reg, mt_mod, @@ -564,7 +563,7 @@ switch (uptr->UST) { /* case on state */ bc = chrono_rd (xb, MT_MAXFR); /* read clock */ else { /* real tape */ r = sim_tape_rdrecf (uptr, xb, &bc, MT_MAXFR); /* read record */ - if (r = mt_map_err (uptr, r)) /* map status */ + if ((r = mt_map_err (uptr, r))) /* map status */ return r; if (mt_unit[ch] == 0) /* disconnected? */ return SCPE_OK; @@ -736,7 +735,7 @@ if (mt_bptr[ch]) { /* any data? */ if (xb == NULL) return SCPE_IERR; r = sim_tape_wrrecf (uptr, xb, mt_bptr[ch]); /* write record */ - if (r = mt_map_err (uptr, r)) /* map error */ + if ((r = mt_map_err (uptr, r))) /* map error */ return r; } uptr->UST = CHSL_WRS|CHSL_3RD; /* next state */ @@ -845,11 +844,11 @@ return sim_tape_attach (uptr, cptr); #define BOOT_START 01000 static const t_uint64 boot_rom[5] = { - 0076200000000 + U_MTBIN - 1, /* RDS MT_binary */ - 0054000000000 + BOOT_START + 4, /* RCHA *+3 */ - 0054400000000, /* LCHA 0 */ - 0002100000001, /* TTR 1 */ - 0500003000000, /* IOCT 0,,3 */ + INT64_C(0076200000000) + U_MTBIN - 1, /* RDS MT_binary */ + INT64_C(0054000000000) + BOOT_START + 4, /* RCHA *+3 */ + INT64_C(0054400000000), /* LCHA 0 */ + INT64_C(0002100000001), /* TTR 1 */ + INT64_C(0500003000000), /* IOCT 0,,3 */ }; t_stat mt_boot (int32 unitno, DEVICE *dptr) diff --git a/I7094/i7094_sys.c b/I7094/i7094_sys.c index 0b757f91..5aa432a6 100644 --- a/I7094/i7094_sys.c +++ b/I7094/i7094_sys.c @@ -142,23 +142,23 @@ return SCPE_NOFNC; #define I_V_FL 39 /* inst class */ #define I_M_FL 017 /* class mask */ -#define I_NOP 0000000000000000 /* no operand */ -#define I_MXR 0010000000000000 /* addr(tag) */ -#define I_MXN 0020000000000000 /* *addr(tag) */ -#define I_MXV 0030000000000000 /* var mul/div */ -#define I_MXC 0040000000000000 /* convert */ -#define I_DNP 0050000000000000 /* decr, no oper */ -#define I_DEC 0060000000000000 /* decrement */ -#define I_SNS 0070000000000000 /* sense */ -#define I_IMM 0100000000000000 /* 18b immediate */ -#define I_TAG 0110000000000000 /* tag only */ -#define I_IOX 0120000000000000 /* IO channel */ -#define I_TCH 0130000000000000 /* transfer channel */ -#define I_I9N 0140000000000000 /* 7909 with nostore */ -#define I_I9S 0150000000000000 /* 7909 */ -#define I_SPX 0160000000000000 /* SPU, SPR */ -#define IFAKE_7607 0001000000000000 /* fake op extensions */ -#define IFAKE_7909 0002000000000000 +#define I_NOP INT64_C(0000000000000000) /* no operand */ +#define I_MXR INT64_C(0010000000000000) /* addr(tag) */ +#define I_MXN INT64_C(0020000000000000) /* *addr(tag) */ +#define I_MXV INT64_C(0030000000000000) /* var mul/div */ +#define I_MXC INT64_C(0040000000000000) /* convert */ +#define I_DNP INT64_C(0050000000000000) /* decr, no oper */ +#define I_DEC INT64_C(0060000000000000) /* decrement */ +#define I_SNS INT64_C(0070000000000000) /* sense */ +#define I_IMM INT64_C(0100000000000000) /* 18b immediate */ +#define I_TAG INT64_C(0110000000000000) /* tag only */ +#define I_IOX INT64_C(0120000000000000) /* IO channel */ +#define I_TCH INT64_C(0130000000000000) /* transfer channel */ +#define I_I9N INT64_C(0140000000000000) /* 7909 with nostore */ +#define I_I9S INT64_C(0150000000000000) /* 7909 */ +#define I_SPX INT64_C(0160000000000000) /* SPU, SPR */ +#define IFAKE_7607 INT64_C(0001000000000000) /* fake op extensions */ +#define IFAKE_7909 INT64_C(0002000000000000) #define DFAKE (DMASK|IFAKE_7607|IFAKE_7909) #define I_N_NOP 000 #define I_N_MXR 001 @@ -183,14 +183,14 @@ return SCPE_NOFNC; #define INST_P_PNT 4 /* print if nz, term */ static const t_uint64 masks[15] = { - 03777700000000, 03777700000000, - 03777700000000, 03777700000000, - 03777400000000, 03700000000000, - 03700000000000, 03777700077777, - 03777700000000, 03777700000000, - 03700000200000, 03700000200000, - 03760000200000, 03740000200000, - 03777700077760 }; + INT64_C(03777700000000), INT64_C(03777700000000), + INT64_C(03777700000000), INT64_C(03777700000000), + INT64_C(03777400000000), INT64_C(03700000000000), + INT64_C(03700000000000), INT64_C(03777700077777), + INT64_C(03777700000000), INT64_C(03777700000000), + INT64_C(03700000200000), INT64_C(03700000200000), + INT64_C(03760000200000), INT64_C(03740000200000), + INT64_C(03777700077760) }; static const uint32 fld_max[15][3] = { /* addr,tag,decr limit */ { INST_M_ADDR, INST_M_TAG, 0 }, @@ -406,174 +406,174 @@ static const char *opcode[] = { }; static const t_uint64 opc_v[] = { - 0100000000000+I_DEC, 0200000000000+I_DEC, 0300000000000+I_DEC, - 0500000000000+I_DNP, 0600000000000+I_DEC, 0700000000000+I_DEC, - 0000000000000+I_MXN, 0002000000000+I_MXN, 0002100000000+I_MXN, + INT64_C(0100000000000)+I_DEC, INT64_C(0200000000000)+I_DEC, INT64_C(0300000000000)+I_DEC, + INT64_C(0500000000000)+I_DNP, INT64_C(0600000000000)+I_DEC, INT64_C(0700000000000)+I_DEC, + INT64_C(0000000000000)+I_MXN, INT64_C(0002000000000)+I_MXN, INT64_C(0002100000000)+I_MXN, - 0076000000000+I_SNS, 0076000000001+I_SNS, 0076000000002+I_SNS, - 0076000000003+I_SNS, 0076000000004+I_SNS, 0076000000005+I_SNS, - 0076000000006+I_SNS, 0076000000007+I_SNS, 0076000000010+I_SNS, - 0076000000011+I_SNS, 0076000000012+I_SNS, 0076000000014+I_SNS, - 0076000000016+I_SNS, 0076000000140+I_SNS, 0076000000141+I_SNS, - 0076000000142+I_SNS, 0076000000143+I_SNS, 0076000000144+I_SNS, - 0076000000161+I_SNS, 0076000000162+I_SNS, 0076000000163+I_SNS, - 0076000000164+I_SNS, 0076000000165+I_SNS, 0076000000166+I_SNS, - 0076000001000+I_SNS, 0076000002000+I_SNS, 0076000003000+I_SNS, - 0076000004000+I_SNS, 0076000005000+I_SNS, 0076000006000+I_SNS, - 0076000007000+I_SNS, 0076000010000+I_SNS, - 0076000001350+I_SNS, 0076000002350+I_SNS, 0076000003350+I_SNS, - 0076000004350+I_SNS, 0076000005350+I_SNS, 0076000006350+I_SNS, - 0076000007350+I_SNS, 0076000010350+I_SNS, - 0076000001352+I_SNS, 0076000002352+I_SNS, 0076000003352+I_SNS, - 0076000004352+I_SNS, 0076000005352+I_SNS, 0076000006352+I_SNS, - 0076000007352+I_SNS, 0076000010352+I_SNS, - 0076000001340+I_SNS, 0076000002340+I_SNS, 0076000003340+I_SNS, - 0076000004340+I_SNS, 0076000005340+I_SNS, 0076000006340+I_SNS, - 0076000007340+I_SNS, 0076000010340+I_SNS, - 0076000001360+I_SNS, 0076000002360+I_SNS, 0076000003360+I_SNS, - 0076000004360+I_SNS, 0076000005360+I_SNS, 0076000006360+I_SNS, - 0076000007360+I_SNS, 0076000010360+I_SNS, - 0076000001360+I_SNS, 0076000002360+I_SNS, 0076000003360+I_SNS, - 0076000004360+I_SNS, 0076000005360+I_SNS, 0076000006360+I_SNS, - 0076000007360+I_SNS, 0076000010360+I_SNS, + INT64_C(0076000000000)+I_SNS, INT64_C(0076000000001)+I_SNS, INT64_C(0076000000002)+I_SNS, + INT64_C(0076000000003)+I_SNS, INT64_C(0076000000004)+I_SNS, INT64_C(0076000000005)+I_SNS, + INT64_C(0076000000006)+I_SNS, INT64_C(0076000000007)+I_SNS, INT64_C(0076000000010)+I_SNS, + INT64_C(0076000000011)+I_SNS, INT64_C(0076000000012)+I_SNS, INT64_C(0076000000014)+I_SNS, + INT64_C(0076000000016)+I_SNS, INT64_C(0076000000140)+I_SNS, INT64_C(0076000000141)+I_SNS, + INT64_C(0076000000142)+I_SNS, INT64_C(0076000000143)+I_SNS, INT64_C(0076000000144)+I_SNS, + INT64_C(0076000000161)+I_SNS, INT64_C(0076000000162)+I_SNS, INT64_C(0076000000163)+I_SNS, + INT64_C(0076000000164)+I_SNS, INT64_C(0076000000165)+I_SNS, INT64_C(0076000000166)+I_SNS, + INT64_C(0076000001000)+I_SNS, INT64_C(0076000002000)+I_SNS, INT64_C(0076000003000)+I_SNS, + INT64_C(0076000004000)+I_SNS, INT64_C(0076000005000)+I_SNS, INT64_C(0076000006000)+I_SNS, + INT64_C(0076000007000)+I_SNS, INT64_C(0076000010000)+I_SNS, + INT64_C(0076000001350)+I_SNS, INT64_C(0076000002350)+I_SNS, INT64_C(0076000003350)+I_SNS, + INT64_C(0076000004350)+I_SNS, INT64_C(0076000005350)+I_SNS, INT64_C(0076000006350)+I_SNS, + INT64_C(0076000007350)+I_SNS, INT64_C(0076000010350)+I_SNS, + INT64_C(0076000001352)+I_SNS, INT64_C(0076000002352)+I_SNS, INT64_C(0076000003352)+I_SNS, + INT64_C(0076000004352)+I_SNS, INT64_C(0076000005352)+I_SNS, INT64_C(0076000006352)+I_SNS, + INT64_C(0076000007352)+I_SNS, INT64_C(0076000010352)+I_SNS, + INT64_C(0076000001340)+I_SNS, INT64_C(0076000002340)+I_SNS, INT64_C(0076000003340)+I_SNS, + INT64_C(0076000004340)+I_SNS, INT64_C(0076000005340)+I_SNS, INT64_C(0076000006340)+I_SNS, + INT64_C(0076000007340)+I_SNS, INT64_C(0076000010340)+I_SNS, + INT64_C(0076000001360)+I_SNS, INT64_C(0076000002360)+I_SNS, INT64_C(0076000003360)+I_SNS, + INT64_C(0076000004360)+I_SNS, INT64_C(0076000005360)+I_SNS, INT64_C(0076000006360)+I_SNS, + INT64_C(0076000007360)+I_SNS, INT64_C(0076000010360)+I_SNS, + INT64_C(0076000001360)+I_SNS, INT64_C(0076000002360)+I_SNS, INT64_C(0076000003360)+I_SNS, + INT64_C(0076000004360)+I_SNS, INT64_C(0076000005360)+I_SNS, INT64_C(0076000006360)+I_SNS, + INT64_C(0076000007360)+I_SNS, INT64_C(0076000010360)+I_SNS, - 0002200000000+I_MXN, 0002400000000+I_MXN, - 0002600000000+I_MXN, 0002700000000+I_MXN, - 0003000000000+I_MXN, 0003100000000+I_MXN, - 0003200000000+I_MXN, 0003300000000+I_MXN, - 0004000000000+I_MXN, 0004100000000+I_NOP, 0004200000000+I_MXR, - 0004300000000+I_NOP, 0004400000000+I_NOP, 0004600000000+I_MXR, - 0005100000000+I_IMM, 0005400000000+I_IMM, 0005500000000+I_IMM, - 0005600000000+I_IMM, 0005700000000+I_IMM, - 0006000000000+I_MXN, 0006100000000+I_MXN, 0006200000000+I_MXN, - 0006300000000+I_MXN, 0006400000000+I_MXN, 0006500000000+I_MXN, - 0006600000000+I_MXN, 0006700000000+I_MXN, 0007400000000+I_MXR, - 0010000000000+I_MXN, 0011400000000+I_MXC, 0012000000000+I_MXN, - 0013100000000+I_NOP, 0014000000000+I_MXN, - 0016100000000+I_MXN, 0016200000000+I_MXN, - 0020000000000+I_MXN, 0020400000000+I_MXV, 0020500000000+I_MXV, - 0022000000000+I_MXN, 0022100000000+I_MXN, - 0022400000000+I_MXV, 0022500000000+I_MXV, - 0022600000000+I_MXV, 0022700000000+I_MXV, - 0024000000000+I_MXN, 0024100000000+I_MXN, - 0026000000000+I_MXN, 0026100000000+I_MXN, - 0030000000000+I_MXN, 0030100000000+I_MXN, - 0030200000000+I_MXN, 0030300000000+I_MXN, - 0030400000000+I_MXN, 0030500000000+I_MXN, - 0030600000000+I_MXN, 0030700000000+I_MXN, - 0032000000000+I_MXN, 0032200000000+I_MXN, - 0034000000000+I_MXN, 0036100000000+I_MXN, - 0040000000000+I_MXN, 0040100000000+I_MXN, - 0040200000000+I_MXN, 0440000000000+I_MXN, - 0042000000000+I_NOP, 0044000000000+I_MXN, 0044100000000+I_MXN, - 0044200000000+I_MXN, 0044300000000+I_MXN, 0044400000000+I_MXN, - 0044500000000+I_MXN, 0044600000000+I_MXN, - 0050000000000+I_MXN, 0050200000000+I_MXN, - 0052000000000+I_MXN, 0052200000000+I_MXN, - 0053400000000+I_MXR, 0053500000000+I_MXR, - 0054000000000+I_MXN, 0054100000000+I_MXN, - 0054200000000+I_MXN, 0054300000000+I_MXN, - 0054400000000+I_MXN, 0054500000000+I_MXN, - 0054600000000+I_MXN, 0054700000000+I_MXN, - 0054000000000+I_MXN, 0054100000000+I_MXN, - 0054200000000+I_MXN, 0054300000000+I_MXN, - 0054400000000+I_MXN, 0054500000000+I_MXN, - 0054600000000+I_MXN, 0054700000000+I_MXN, - 0056000000000+I_MXN, 0056400000000+I_MXN, - 0060000000000+I_MXN, 0060100000000+I_MXN, 0060200000000+I_MXN, - 0060400000000+I_MXN, 0062100000000+I_MXN, 0062200000000+I_MXN, - 0062500000000+I_MXN, 0063000000000+I_MXN, - 0063400000000+I_MXR, 0063600000000+I_MXR, - 0064000000000+I_MXN, 0064000000000+I_MXN, - 0064200000000+I_MXN, 0064300000000+I_MXN, - 0064400000000+I_MXN, 0064500000000+I_MXN, - 0064600000000+I_MXN, 0064700000000+I_MXN, - 0073400000000+I_TAG, 0073700000000+I_TAG, - 0075400000000+I_TAG, 0075600000000+I_TAG, - 0076000000000+I_MXR, 0076100000000+I_NOP, 0076200000000+I_MXR, - 0076300000000+I_MXR, 0076400000000+I_MXR, 0076500000000+I_MXR, - 0076600000000+I_MXR, 0076700000000+I_MXR, 0077000000000+I_MXR, - 0077100000000+I_MXR, 0077200000000+I_MXR, 0077400000000+I_MXR, - 0077600000000+I_MXR, + INT64_C(0002200000000)+I_MXN, INT64_C(0002400000000)+I_MXN, + INT64_C(0002600000000)+I_MXN, INT64_C(0002700000000)+I_MXN, + INT64_C(0003000000000)+I_MXN, INT64_C(0003100000000)+I_MXN, + INT64_C(0003200000000)+I_MXN, INT64_C(0003300000000)+I_MXN, + INT64_C(0004000000000)+I_MXN, INT64_C(0004100000000)+I_NOP, INT64_C(0004200000000)+I_MXR, + INT64_C(0004300000000)+I_NOP, INT64_C(0004400000000)+I_NOP, INT64_C(0004600000000)+I_MXR, + INT64_C(0005100000000)+I_IMM, INT64_C(0005400000000)+I_IMM, INT64_C(0005500000000)+I_IMM, + INT64_C(0005600000000)+I_IMM, INT64_C(0005700000000)+I_IMM, + INT64_C(0006000000000)+I_MXN, INT64_C(0006100000000)+I_MXN, INT64_C(0006200000000)+I_MXN, + INT64_C(0006300000000)+I_MXN, INT64_C(0006400000000)+I_MXN, INT64_C(0006500000000)+I_MXN, + INT64_C(0006600000000)+I_MXN, INT64_C(0006700000000)+I_MXN, INT64_C(0007400000000)+I_MXR, + INT64_C(0010000000000)+I_MXN, INT64_C(0011400000000)+I_MXC, INT64_C(0012000000000)+I_MXN, + INT64_C(0013100000000)+I_NOP, INT64_C(0014000000000)+I_MXN, + INT64_C(0016100000000)+I_MXN, INT64_C(0016200000000)+I_MXN, + INT64_C(0020000000000)+I_MXN, INT64_C(0020400000000)+I_MXV, INT64_C(0020500000000)+I_MXV, + INT64_C(0022000000000)+I_MXN, INT64_C(0022100000000)+I_MXN, + INT64_C(0022400000000)+I_MXV, INT64_C(0022500000000)+I_MXV, + INT64_C(0022600000000)+I_MXV, INT64_C(0022700000000)+I_MXV, + INT64_C(0024000000000)+I_MXN, INT64_C(0024100000000)+I_MXN, + INT64_C(0026000000000)+I_MXN, INT64_C(0026100000000)+I_MXN, + INT64_C(0030000000000)+I_MXN, INT64_C(0030100000000)+I_MXN, + INT64_C(0030200000000)+I_MXN, INT64_C(0030300000000)+I_MXN, + INT64_C(0030400000000)+I_MXN, INT64_C(0030500000000)+I_MXN, + INT64_C(0030600000000)+I_MXN, INT64_C(0030700000000)+I_MXN, + INT64_C(0032000000000)+I_MXN, INT64_C(0032200000000)+I_MXN, + INT64_C(0034000000000)+I_MXN, INT64_C(0036100000000)+I_MXN, + INT64_C(0040000000000)+I_MXN, INT64_C(0040100000000)+I_MXN, + INT64_C(0040200000000)+I_MXN, INT64_C(0440000000000)+I_MXN, + INT64_C(0042000000000)+I_NOP, INT64_C(0044000000000)+I_MXN, INT64_C(0044100000000)+I_MXN, + INT64_C(0044200000000)+I_MXN, INT64_C(0044300000000)+I_MXN, INT64_C(0044400000000)+I_MXN, + INT64_C(0044500000000)+I_MXN, INT64_C(0044600000000)+I_MXN, + INT64_C(0050000000000)+I_MXN, INT64_C(0050200000000)+I_MXN, + INT64_C(0052000000000)+I_MXN, INT64_C(0052200000000)+I_MXN, + INT64_C(0053400000000)+I_MXR, INT64_C(0053500000000)+I_MXR, + INT64_C(0054000000000)+I_MXN, INT64_C(0054100000000)+I_MXN, + INT64_C(0054200000000)+I_MXN, INT64_C(0054300000000)+I_MXN, + INT64_C(0054400000000)+I_MXN, INT64_C(0054500000000)+I_MXN, + INT64_C(0054600000000)+I_MXN, INT64_C(0054700000000)+I_MXN, + INT64_C(0054000000000)+I_MXN, INT64_C(0054100000000)+I_MXN, + INT64_C(0054200000000)+I_MXN, INT64_C(0054300000000)+I_MXN, + INT64_C(0054400000000)+I_MXN, INT64_C(0054500000000)+I_MXN, + INT64_C(0054600000000)+I_MXN, INT64_C(0054700000000)+I_MXN, + INT64_C(0056000000000)+I_MXN, INT64_C(0056400000000)+I_MXN, + INT64_C(0060000000000)+I_MXN, INT64_C(0060100000000)+I_MXN, INT64_C(0060200000000)+I_MXN, + INT64_C(0060400000000)+I_MXN, INT64_C(0062100000000)+I_MXN, INT64_C(0062200000000)+I_MXN, + INT64_C(0062500000000)+I_MXN, INT64_C(0063000000000)+I_MXN, + INT64_C(0063400000000)+I_MXR, INT64_C(0063600000000)+I_MXR, + INT64_C(0064000000000)+I_MXN, INT64_C(0064000000000)+I_MXN, + INT64_C(0064200000000)+I_MXN, INT64_C(0064300000000)+I_MXN, + INT64_C(0064400000000)+I_MXN, INT64_C(0064500000000)+I_MXN, + INT64_C(0064600000000)+I_MXN, INT64_C(0064700000000)+I_MXN, + INT64_C(0073400000000)+I_TAG, INT64_C(0073700000000)+I_TAG, + INT64_C(0075400000000)+I_TAG, INT64_C(0075600000000)+I_TAG, + INT64_C(0076000000000)+I_MXR, INT64_C(0076100000000)+I_NOP, INT64_C(0076200000000)+I_MXR, + INT64_C(0076300000000)+I_MXR, INT64_C(0076400000000)+I_MXR, INT64_C(0076500000000)+I_MXR, + INT64_C(0076600000000)+I_MXR, INT64_C(0076700000000)+I_MXR, INT64_C(0077000000000)+I_MXR, + INT64_C(0077100000000)+I_MXR, INT64_C(0077200000000)+I_MXR, INT64_C(0077400000000)+I_MXR, + INT64_C(0077600000000)+I_MXR, - 0476000000000+I_SNS, 0476000000001+I_SNS, 0476000000002+I_SNS, - 0476000000003+I_SNS, 0476000000004+I_SNS, 0476000000005+I_SNS, - 0476000000006+I_SNS, 0476000000007+I_SNS, 0476000000010+I_SNS, - 0476000000016+I_SNS, 0476000000141+I_SNS, 0476000000142+I_SNS, - 0476000000143+I_SNS, 0476000000144+I_SNS, - 0476000001000+I_SNS, 0476000002000+I_SNS, 0476000003000+I_SNS, - 0476000004000+I_SNS, 0476000005000+I_SNS, 0476000006000+I_SNS, - 0476000007000+I_SNS, 0476000010000+I_SNS, + INT64_C(0476000000000)+I_SNS, INT64_C(0476000000001)+I_SNS, INT64_C(0476000000002)+I_SNS, + INT64_C(0476000000003)+I_SNS, INT64_C(0476000000004)+I_SNS, INT64_C(0476000000005)+I_SNS, + INT64_C(0476000000006)+I_SNS, INT64_C(0476000000007)+I_SNS, INT64_C(0476000000010)+I_SNS, + INT64_C(0476000000016)+I_SNS, INT64_C(0476000000141)+I_SNS, INT64_C(0476000000142)+I_SNS, + INT64_C(0476000000143)+I_SNS, INT64_C(0476000000144)+I_SNS, + INT64_C(0476000001000)+I_SNS, INT64_C(0476000002000)+I_SNS, INT64_C(0476000003000)+I_SNS, + INT64_C(0476000004000)+I_SNS, INT64_C(0476000005000)+I_SNS, INT64_C(0476000006000)+I_SNS, + INT64_C(0476000007000)+I_SNS, INT64_C(0476000010000)+I_SNS, - 0402100000000+I_MXN, - 0402200000000+I_MXN, 0402400000000+I_MXN, - 0402600000000+I_MXN, 0402700000000+I_MXN, - 0403000000000+I_MXN, 0403100000000+I_MXN, - 0403200000000+I_MXN, 0403300000000+I_MXN, - 0404200000000+I_NOP, 0404600000000+I_NOP, - 0405100000000+I_IMM, 0405400000000+I_IMM, 0405500000000+I_IMM, - 0405600000000+I_IMM, 0405700000000+I_IMM, - 0406000000000+I_MXN, 0406100000000+I_MXN, 0406200000000+I_MXN, - 0406300000000+I_MXN, 0406400000000+I_MXN, 0406500000000+I_MXN, - 0406600000000+I_MXN, 0406700000000+I_MXN, - 0410000000000+I_MXN, 0411400000000+I_MXC, 0412000000000+I_MXN, - 0413000000000+I_NOP, 0414000000000+I_MXN, 0415400000000+I_MXC, - 0420000000000+I_MXN, 0424000000000+I_MXN, 0424100000000+I_MXN, - 0426000000000+I_MXN, 0426100000000+I_MXN, - 0430000000000+I_MXN, 0430100000000+I_MXN, - 0430200000000+I_MXN, 0430300000000+I_MXN, - 0430400000000+I_MXN, 0430500000000+I_MXN, - 0430600000000+I_MXN, 0430700000000+I_MXN, - 0432000000000+I_MXN, 0434000000000+I_MXN, - 0450000000000+I_MXN, 0450100000000+I_MXN, 0452000000000+I_MXN, - 0453400000000+I_MXR, 0453500000000+I_MXR, - 0454000000000+I_MXN, 0454100000000+I_MXN, - 0454200000000+I_MXN, 0454300000000+I_MXN, - 0454400000000+I_MXN, 0454500000000+I_MXN, - 0454600000000+I_MXN, 0454700000000+I_MXN, - 0454000000000+I_MXN, 0454100000000+I_MXN, - 0454200000000+I_MXN, 0454300000000+I_MXN, - 0454400000000+I_MXN, 0454500000000+I_MXN, - 0454600000000+I_MXN, 0454700000000+I_MXN, - 0460000000000+I_MXN, 0460100000000+I_MXN, 0460200000000+I_MXN, 0460300000000+I_MXN, - 0460400000000+I_MXN, - 0462000000000+I_MXN, 0462500000000+I_MXN, - 0463400000000+I_MXR, 0463600000000+I_MXR, - 0464000000000+I_MXN, 0464000000000+I_MXN, - 0464200000000+I_MXN, 0464300000000+I_MXN, - 0464400000000+I_MXN, 0464500000000+I_MXN, - 0464600000000+I_MXN, 0464700000000+I_MXN, - 0473400000000+I_TAG, 0473700000000+I_TAG, - 0475400000000+I_TAG, 0475600000000+I_TAG, - 0476000000000+I_MXR, 0476300000000+I_MXR, 0476400000000+I_MXR, - 0476500000000+I_MXR, 0477300000000+I_MXR, 0477200000000+I_MXR, - 0477400000000+I_MXR, + INT64_C(0402100000000)+I_MXN, + INT64_C(0402200000000)+I_MXN, INT64_C(0402400000000)+I_MXN, + INT64_C(0402600000000)+I_MXN, INT64_C(0402700000000)+I_MXN, + INT64_C(0403000000000)+I_MXN, INT64_C(0403100000000)+I_MXN, + INT64_C(0403200000000)+I_MXN, INT64_C(0403300000000)+I_MXN, + INT64_C(0404200000000)+I_NOP, INT64_C(0404600000000)+I_NOP, + INT64_C(0405100000000)+I_IMM, INT64_C(0405400000000)+I_IMM, INT64_C(0405500000000)+I_IMM, + INT64_C(0405600000000)+I_IMM, INT64_C(0405700000000)+I_IMM, + INT64_C(0406000000000)+I_MXN, INT64_C(0406100000000)+I_MXN, INT64_C(0406200000000)+I_MXN, + INT64_C(0406300000000)+I_MXN, INT64_C(0406400000000)+I_MXN, INT64_C(0406500000000)+I_MXN, + INT64_C(0406600000000)+I_MXN, INT64_C(0406700000000)+I_MXN, + INT64_C(0410000000000)+I_MXN, INT64_C(0411400000000)+I_MXC, INT64_C(0412000000000)+I_MXN, + INT64_C(0413000000000)+I_NOP, INT64_C(0414000000000)+I_MXN, INT64_C(0415400000000)+I_MXC, + INT64_C(0420000000000)+I_MXN, INT64_C(0424000000000)+I_MXN, INT64_C(0424100000000)+I_MXN, + INT64_C(0426000000000)+I_MXN, INT64_C(0426100000000)+I_MXN, + INT64_C(0430000000000)+I_MXN, INT64_C(0430100000000)+I_MXN, + INT64_C(0430200000000)+I_MXN, INT64_C(0430300000000)+I_MXN, + INT64_C(0430400000000)+I_MXN, INT64_C(0430500000000)+I_MXN, + INT64_C(0430600000000)+I_MXN, INT64_C(0430700000000)+I_MXN, + INT64_C(0432000000000)+I_MXN, INT64_C(0434000000000)+I_MXN, + INT64_C(0450000000000)+I_MXN, INT64_C(0450100000000)+I_MXN, INT64_C(0452000000000)+I_MXN, + INT64_C(0453400000000)+I_MXR, INT64_C(0453500000000)+I_MXR, + INT64_C(0454000000000)+I_MXN, INT64_C(0454100000000)+I_MXN, + INT64_C(0454200000000)+I_MXN, INT64_C(0454300000000)+I_MXN, + INT64_C(0454400000000)+I_MXN, INT64_C(0454500000000)+I_MXN, + INT64_C(0454600000000)+I_MXN, INT64_C(0454700000000)+I_MXN, + INT64_C(0454000000000)+I_MXN, INT64_C(0454100000000)+I_MXN, + INT64_C(0454200000000)+I_MXN, INT64_C(0454300000000)+I_MXN, + INT64_C(0454400000000)+I_MXN, INT64_C(0454500000000)+I_MXN, + INT64_C(0454600000000)+I_MXN, INT64_C(0454700000000)+I_MXN, + INT64_C(0460000000000)+I_MXN, INT64_C(0460100000000)+I_MXN, INT64_C(0460200000000)+I_MXN, INT64_C(0460300000000)+I_MXN, + INT64_C(0460400000000)+I_MXN, + INT64_C(0462000000000)+I_MXN, INT64_C(0462500000000)+I_MXN, + INT64_C(0463400000000)+I_MXR, INT64_C(0463600000000)+I_MXR, + INT64_C(0464000000000)+I_MXN, INT64_C(0464000000000)+I_MXN, + INT64_C(0464200000000)+I_MXN, INT64_C(0464300000000)+I_MXN, + INT64_C(0464400000000)+I_MXN, INT64_C(0464500000000)+I_MXN, + INT64_C(0464600000000)+I_MXN, INT64_C(0464700000000)+I_MXN, + INT64_C(0473400000000)+I_TAG, INT64_C(0473700000000)+I_TAG, + INT64_C(0475400000000)+I_TAG, INT64_C(0475600000000)+I_TAG, + INT64_C(0476000000000)+I_MXR, INT64_C(0476300000000)+I_MXR, INT64_C(0476400000000)+I_MXR, + INT64_C(0476500000000)+I_MXR, INT64_C(0477300000000)+I_MXR, INT64_C(0477200000000)+I_MXR, + INT64_C(0477400000000)+I_MXR, - 0010100000000+I_MXN, 0410100000000+I_MXN, - 0056200000000+I_MXN, 0456400000000+I_MXN, - 0476100000041+I_SNS, 0476100000042+I_SNS, - 0476100000043+I_SNS, 0476100000044+I_SNS, + INT64_C(0010100000000)+I_MXN, INT64_C(0410100000000)+I_MXN, + INT64_C(0056200000000)+I_MXN, INT64_C(0456400000000)+I_MXN, + INT64_C(0476100000041)+I_SNS, INT64_C(0476100000042)+I_SNS, + INT64_C(0476100000043)+I_SNS, INT64_C(0476100000044)+I_SNS, - 01000000000000+I_IOX, 01000000200000+I_IOX, 01100000000000+I_TCH, - 01200000000000+I_IOX, 01200000200000+I_IOX, - 01300000000000+I_IOX, 01300000200000+I_IOX, - 01400000000000+I_IOX, 01400000200000+I_IOX, - 01500000000000+I_IOX, 01500000200000+I_IOX, - 01600000000000+I_IOX, 01600000200000+I_IOX, - 01700000000000+I_IOX, 01700000200000+I_IOX, + INT64_C(01000000000000)+I_IOX, INT64_C(01000000200000)+I_IOX, INT64_C(01100000000000)+I_TCH, + INT64_C(01200000000000)+I_IOX, INT64_C(01200000200000)+I_IOX, + INT64_C(01300000000000)+I_IOX, INT64_C(01300000200000)+I_IOX, + INT64_C(01400000000000)+I_IOX, INT64_C(01400000200000)+I_IOX, + INT64_C(01500000000000)+I_IOX, INT64_C(01500000200000)+I_IOX, + INT64_C(01600000000000)+I_IOX, INT64_C(01600000200000)+I_IOX, + INT64_C(01700000000000)+I_IOX, INT64_C(01700000200000)+I_IOX, - 02000000000000+I_TCH, 02000000200000+I_IOX, - 02100000000000+I_TCH, 02100000200000+I_TCH, - 02200000000000+I_I9N, 02220000000000+I_TCH, - 02200000200000+I_I9N, 02220000200000+I_TCH, - 02240000000000+I_I9N, 02260000000000+I_TCH, - 02240000200000+I_I9N, - 02300000000000+I_I9S, 02300000200000+I_I9S, - 02340000000000+I_I9S, - 02400000000000+I_IOX, - 02500000000000+I_IOX, 02500000200000+I_IOX, - 02600000200000+I_I9S, 02640000000000+I_I9S, 02640000200000+I_I9S, - 02700000000000+I_I9S, 02700000200000+I_IOX, + INT64_C(02000000000000)+I_TCH, INT64_C(02000000200000)+I_IOX, + INT64_C(02100000000000)+I_TCH, INT64_C(02100000200000)+I_TCH, + INT64_C(02200000000000)+I_I9N, INT64_C(02220000000000)+I_TCH, + INT64_C(02200000200000)+I_I9N, INT64_C(02220000200000)+I_TCH, + INT64_C(02240000000000)+I_I9N, INT64_C(02260000000000)+I_TCH, + INT64_C(02240000200000)+I_I9N, + INT64_C(02300000000000)+I_I9S, INT64_C(02300000200000)+I_I9S, + INT64_C(02340000000000)+I_I9S, + INT64_C(02400000000000)+I_IOX, + INT64_C(02500000000000)+I_IOX, INT64_C(02500000200000)+I_IOX, + INT64_C(02600000200000)+I_I9S, INT64_C(02640000000000)+I_I9S, INT64_C(02640000200000)+I_I9S, + INT64_C(02700000000000)+I_I9S, INT64_C(02700000200000)+I_IOX, 0 }; diff --git a/Interdata/id16_cpu.c b/Interdata/id16_cpu.c index f3ec00ad..c67545da 100644 --- a/Interdata/id16_cpu.c +++ b/Interdata/id16_cpu.c @@ -193,7 +193,7 @@ uint32 GREG[16] = { 0 }; /* general registers */ uint16 *M = NULL; /* memory */ uint32 *R = &GREG[0]; /* register set ptr */ uint32 F[8] = { 0 }; /* sp fp registers */ -dpr_t D[8] = { 0 }; /* dp fp registers */ +dpr_t D[8] = { {0, 0} }; /* dp fp registers */ uint32 PSW = 0; /* processor status word */ uint32 psw_mask = PSW_x16; /* PSW mask */ uint32 PC = 0; /* program counter */ @@ -223,11 +223,6 @@ InstHistory *hst = NULL; /* instruction history * struct BlockIO blk_io; /* block I/O status */ uint32 (*dev_tab[DEVNO])(uint32 dev, uint32 op, uint32 datout) = { NULL }; -extern int32 sim_interval; -extern int32 sim_int_char; -extern uint32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ -extern t_bool sim_idle_enab; - uint32 ReadB (uint32 loc); uint32 ReadH (uint32 loc); void WriteB (uint32 loc, uint32 val); @@ -604,7 +599,7 @@ while (reason == 0) { /* loop until halted */ int32 sr, st; if (sim_interval <= 0) { /* check clock queue */ - if (reason = sim_process_event ()) + if ((reason = sim_process_event ())) break; int_eval (); } @@ -650,9 +645,7 @@ while (reason == 0) { /* loop until halted */ } if (PSW & PSW_WAIT) { /* wait state? */ - if (sim_idle_enab) /* idling enabled? */ - sim_idle (TMR_LFC, TRUE); - else sim_interval = sim_interval - 1; /* no, count cycle */ + sim_idle (TMR_LFC, TRUE); /* idling */ continue; } @@ -664,7 +657,7 @@ while (reason == 0) { /* loop until halted */ if (sim_brk_summ && sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */ reason = STOP_IBKPT; /* stop simulation */ break; - } + } sim_interval = sim_interval - 1; @@ -1642,7 +1635,7 @@ do { if (DEV_ACC (dev)) { /* dev exist? */ by = ReadB ((vec + CCB16_IOC) & VAMASK);/* read OC byte */ dev_tab[dev] (dev, IO_OC, by); /* send to dev */ - } + } break; /* and exit */ } } @@ -1955,7 +1948,7 @@ if (!(val & UNIT_816E) && (MEMSIZE > MAXMEMSIZE16)) { MEMSIZE = MAXMEMSIZE16; for (i = MEMSIZE; i < MAXMEMSIZE16E; i = i + 2) M[i >> 1] = 0; - printf ("Reducing memory to 64KB\n"); + sim_printf ("Reducing memory to 64KB\n"); } return SCPE_OK; } @@ -2011,8 +2004,6 @@ char *cptr = (char *) desc; t_value sim_eval[2]; t_stat r; InstHistory *h; -extern t_stat fprint_sym (FILE *ofile, t_addr addr, t_value *val, - UNIT *uptr, int32 sw); if (hst_lnt == 0) /* enabled? */ return SCPE_NOFNC; diff --git a/Interdata/id16_sys.c b/Interdata/id16_sys.c index 9489d0c6..358cc666 100644 --- a/Interdata/id16_sys.c +++ b/Interdata/id16_sys.c @@ -352,9 +352,8 @@ return -1; t_stat fprint_sym_m (FILE *of, t_addr addr, t_value *val) { -uint32 i, j, inst, r1, r2, ea, vp; +uint32 i, j, inst, r1, r2, ea; -vp = 0; inst = val[0]; /* first 16b */ ea = val[1]; /* second 16b */ for (i = 0; opcode[i] != NULL; i++) { /* loop thru ops */ @@ -570,7 +569,7 @@ return -1; t_stat parse_sym_m (char *cptr, t_addr addr, t_value *val) { uint32 i, j, t, df, db, inst; -int32 st, r1, r2; +int32 r1, r2; t_stat r; char *tptr, gbuf[CBUFSIZE]; @@ -627,7 +626,6 @@ switch (j) { /* case on class */ r = get_addr (gbuf, &tptr, &t, addr); /* get addr */ if ((r != SCPE_OK) || (t & 1) || *tptr) /* error if odd */ return SCPE_ARG; - st = t; /* signed version */ db = (addr - t) & 0x1F; /* back displ */ df = (t - addr) & 0x1F; /* fwd displ */ if ((t == ((addr - db) & VAMASK16)) && /* back work and */ diff --git a/Interdata/id32_cpu.c b/Interdata/id32_cpu.c index 7af43c61..f9eb0416 100644 --- a/Interdata/id32_cpu.c +++ b/Interdata/id32_cpu.c @@ -28,7 +28,7 @@ 28-Apr-07 RMS Removed clock initialization 27-Oct-06 RMS Added idle support Removed separate PASLA clock - 09-Mar-06 RMS Added 8 register bank support for 8/32 + 09-Mar-06 RMS Added 8 register bank support for 8/32 06-Feb-06 RMS Fixed bug in DH (Mark Hittinger) 22-Sep-05 RMS Fixed declarations (Sterling Garwood) 16-Aug-05 RMS Fixed C++ declaration and cast problems @@ -222,7 +222,7 @@ uint32 GREG[16 * NRSETS] = { 0 }; /* general registers */ uint32 *M = NULL; /* memory */ uint32 *R = &GREG[0]; /* working reg set */ uint32 F[8] = { 0 }; /* sp fp registers */ -dpr_t D[8] = { 0 }; /* dp fp registers */ +dpr_t D[8] = { {0} }; /* dp fp registers */ uint32 PSW = 0; /* processor status word */ uint32 PC = 0; /* program counter */ uint32 oPC = 0; /* PC at inst start */ @@ -253,12 +253,6 @@ jmp_buf save_env; /* abort handler */ struct BlockIO blk_io; /* block I/O status */ uint32 (*dev_tab[DEVNO])(uint32 dev, uint32 op, uint32 datout) = { NULL }; -extern int32 sim_interval; -extern int32 sim_int_char; -extern uint32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ -extern t_bool sim_idle_enab; -extern FILE *sim_deb; - uint32 ReadB (uint32 loc, uint32 rel); uint32 ReadH (uint32 loc, uint32 rel); void WriteB (uint32 loc, uint32 val, uint32 rel); @@ -664,7 +658,7 @@ while (reason == 0) { /* loop until halted */ int32 sr, st; if (sim_interval <= 0) { /* check clock queue */ - if (reason = sim_process_event ()) + if ((reason = sim_process_event ())) break; int_eval (); } @@ -714,9 +708,7 @@ while (reason == 0) { /* loop until halted */ } if (PSW & PSW_WAIT) { /* wait state? */ - if (sim_idle_enab) /* idling enabled? */ - sim_idle (TMR_LFC, TRUE); - else sim_interval = sim_interval - 1; /* no, count cycle */ + sim_idle (TMR_LFC, TRUE); /* idling */ continue; } @@ -2293,7 +2285,7 @@ if ((sw & SWMASK ('V')) && (PSW & PSW_REL)) { int32 cc = RelocT (addr, MAC_BASE, P, &addr); if (cc & (CC_C | CC_V)) return SCPE_NXM; - } + } if (addr >= MEMSIZE) return SCPE_NXM; if (vptr != NULL) @@ -2309,7 +2301,7 @@ if ((sw & SWMASK ('V')) && (PSW & PSW_REL)) { int32 cc = RelocT (addr, MAC_BASE, P, &addr); if (cc & (CC_C | CC_V)) return SCPE_NXM; - } + } if (addr >= MEMSIZE) return SCPE_NXM; IOWriteH (addr, val); @@ -2323,7 +2315,7 @@ t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc) uint32 mc = 0; uint32 i; -if ((val <= 0) || (val > MAXMEMSIZE32) || ((val & 0xFFFF) != 0)) +if ((val <= 0) || (((unsigned)val) > MAXMEMSIZE32) || ((val & 0xFFFF) != 0)) return SCPE_ARG; for (i = val; i < MEMSIZE; i = i + 4) mc = mc | M[i >> 2]; @@ -2339,7 +2331,6 @@ return SCPE_OK; void set_r_display (uint32 *rbase) { -extern REG *find_reg (char *cptr, char **optr, DEVICE *dptr); REG *rptr; int32 i; @@ -2400,8 +2391,6 @@ char *cptr = (char *) desc; t_value sim_eval[3]; t_stat r; InstHistory *h; -extern t_stat fprint_sym (FILE *ofile, t_addr addr, t_value *val, - UNIT *uptr, int32 sw); if (hst_lnt == 0) /* enabled? */ return SCPE_NOFNC; diff --git a/Interdata/id32_dboot.c b/Interdata/id32_dboot.c index 40ee4167..133f59e2 100644 --- a/Interdata/id32_dboot.c +++ b/Interdata/id32_dboot.c @@ -288,7 +288,6 @@ t_stat id_dboot (int32 u, DEVICE *dptr) { extern DIB ttp_dib, sch_dib; extern uint32 PC; -extern int32 sim_switches; uint32 i, typ, ctlno, off, add, cap, sch_dev; UNIT *uptr; diff --git a/Interdata/id32_sys.c b/Interdata/id32_sys.c index 7f85fa83..288fd890 100644 --- a/Interdata/id32_sys.c +++ b/Interdata/id32_sys.c @@ -669,12 +669,11 @@ return -3; t_stat parse_sym_m (char *cptr, t_addr addr, t_value *val) { -uint32 i, j, df, db, t, inst, vp; +uint32 i, j, df, db, t, inst; int32 st, r1, r2, rx2; t_stat r; char *tptr, gbuf[CBUFSIZE]; -vp = 0; cptr = get_glyph (cptr, gbuf, 0); /* get opcode */ for (i = 0; (opcode[i] != NULL) && (strcmp (opcode[i], gbuf) != 0) ; i++) ; if (opcode[i] == NULL) diff --git a/Interdata/id_defs.h b/Interdata/id_defs.h index 2afd3446..d2e82866 100644 --- a/Interdata/id_defs.h +++ b/Interdata/id_defs.h @@ -36,8 +36,8 @@ 28-Feb-03 RMS Changed magtape device default to 0x85 */ -#ifndef _ID_DEFS_H_ -#define _ID_DEFS_H_ 0 +#ifndef ID_DEFS_H_ +#define ID_DEFS_H_ 0 #include "sim_defs.h" /* simulator defns */ diff --git a/Interdata/id_dp.c b/Interdata/id_dp.c index a62bf33f..792c37e8 100644 --- a/Interdata/id_dp.c +++ b/Interdata/id_dp.c @@ -139,7 +139,6 @@ static struct drvtyp drv_tab[] = { }; extern uint32 int_req[INTSZ], int_enb[INTSZ]; -extern FILE *sim_deb; uint8 dpxb[DP_NUMBY]; /* xfer buffer */ uint32 dp_bptr = 0; /* buffer ptr */ @@ -393,7 +392,6 @@ t_stat dp_svc (UNIT *uptr) uint32 u = uptr - dp_dev.units; /* get unit number */ int32 cyl = uptr->CYL; /* get cylinder */ uint32 dtype = GET_DTYPE (uptr->flags); /* get drive type */ -uint32 t; t_stat r; if (uptr->STD & STD_MOV) { /* seek? */ @@ -419,10 +417,10 @@ switch (dp_cmd & 0x7) { /* case on func */ if (sch_actv (dp_dib.sch, dp_dib.dno)) { /* sch transfer? */ if (dp_dter (uptr, dp_1st)) /* check xfr err */ return SCPE_OK; - if (r = dp_rds (uptr)) /* read sec, err? */ + if ((r = dp_rds (uptr))) /* read sec, err? */ return r; dp_1st = 0; - t = sch_wrmem (dp_dib.sch, dpxb, DP_NUMBY); /* write to memory */ + sch_wrmem (dp_dib.sch, dpxb, DP_NUMBY); /* write to memory */ if (sch_actv (dp_dib.sch, dp_dib.dno)) { /* more to do? */ sim_activate (uptr, dp_rtime); /* reschedule */ return SCPE_OK; @@ -438,7 +436,7 @@ switch (dp_cmd & 0x7) { /* case on func */ return SCPE_OK; dp_bptr = sch_rdmem (dp_dib.sch, dpxb, DP_NUMBY); /* read from mem */ dp_db = dpxb[dp_bptr - 1]; /* last byte */ - if (r = dp_wds (uptr)) /* write sec, err? */ + if ((r = dp_wds (uptr))) /* write sec, err? */ return r; dp_1st = 0; if (sch_actv (dp_dib.sch, dp_dib.dno)) { /* more to do? */ @@ -498,9 +496,9 @@ uint32 dtype = GET_DTYPE (uptr->flags); /* get drive type */ if (((uptr->flags & UNIT_ATT) == 0) || /* not attached? */ ((uptr->flags & UNIT_WPRT) && (dp_cmd == CMC_WR))) { - dp_done (STC_DTE); /* error, done */ - return TRUE; - } + dp_done (STC_DTE); /* error, done */ + return TRUE; + } hd = GET_SRF (dp_hdsc); /* get head */ sc = GET_SEC (dp_hdsc); /* get sector */ if (dp_cyl != (uint32) uptr->CYL) { /* wrong cylinder? */ diff --git a/Interdata/id_fd.c b/Interdata/id_fd.c index 10e83fc0..d4944394 100644 --- a/Interdata/id_fd.c +++ b/Interdata/id_fd.c @@ -116,7 +116,7 @@ uint32 fd_cmd = 0; /* command */ uint32 fd_db = 0; /* data buffer */ uint32 fd_bptr = 0; /* buffer pointer */ uint8 fdxb[FD_NUMBY] = { 0 }; /* sector buffer */ -uint8 fd_es[FD_NUMDR][ES_SIZE] = { 0 }; /* ext status */ +uint8 fd_es[FD_NUMDR][ES_SIZE] = { {0} }; /* ext status */ uint32 fd_lrn = 0; /* log rec # */ uint32 fd_wdv = 0; /* wd valid */ uint32 fd_stopioe = 1; /* stop on error */ @@ -227,7 +227,7 @@ switch (op) { /* case IO op */ fd_sta = fd_sta | STA_BSY; /* set busy */ } else fd_bptr = 0; /* just wrap */ - } + } if ((ctab[fnc] & C_RD) && fd_arm) /* if rd & arm, */ SET_INT (v_FD); /* interrupt */ return fd_db; /* return buf */ @@ -367,7 +367,7 @@ switch (fnc) { /* case on function */ if ((uptr->flags & UNIT_BUF) == 0) { /* not attached? */ fd_es[u][0] = fd_es[u][0] | ES0_FLT; /* set err */ fd_es[u][1] = fd_es[u][1] | ES1_NRDY; - } + } for (i = 0; i < ES_SIZE; i++) /* copy to buf */ fdxb[i] = fd_es[u][i]; for (i = ES_SIZE; i < FD_NUMBY; i++) @@ -378,7 +378,7 @@ switch (fnc) { /* case on function */ if ((uptr->flags & UNIT_BUF) == 0) { /* not attached? */ fd_done (u, STA_ERR, ES0_ERR | ES0_FLT, ES1_NRDY); return SCPE_OK; - } + } for (i = 0; i < FD_NUMBY; i++) fdxb[i] = 0; /* clr buf */ tk = GET_TRK (uptr->LRN); /* get track */ sc = GET_SEC (uptr->LRN); /* get sector */ diff --git a/Interdata/id_idc.c b/Interdata/id_idc.c index 38854d1c..42a9b02a 100644 --- a/Interdata/id_idc.c +++ b/Interdata/id_idc.c @@ -96,7 +96,7 @@ /* Drive status, ^ = dynamic, * = in unit status */ #define STD_WRP 0x80 /* ^write prot */ -/* 0x40 /* unused */ +/* 0x40 *//* unused */ #define STD_ACH 0x20 /* alt chan busy NI */ #define STD_UNS 0x10 /* *unsafe */ #define STD_NRDY 0x08 /* ^not ready */ @@ -503,7 +503,6 @@ t_stat idc_svc (UNIT *uptr) int32 diff; uint32 f, u = uptr - idc_dev.units; /* get unit number */ uint32 dtype = GET_DTYPE (uptr->flags); /* get drive type */ -uint32 t; t_stat r; if (uptr->FNC & CMC_DRV) { /* drive cmd? */ @@ -561,7 +560,7 @@ if (uptr->FNC & CMC_DRV) { /* drive cmd? */ } } /* end else p1 */ return SCPE_OK; /* end if drv */ - } + } switch (uptr->FNC & CMC_MASK) { /* case on func */ @@ -576,10 +575,10 @@ switch (uptr->FNC & CMC_MASK) { /* case on func */ if (sch_actv (idc_dib.sch, idc_dib.dno)) { /* sch transfer? */ if (idc_dter (uptr, idc_1st)) /* dte? done */ return SCPE_OK; - if (r = idc_rds (uptr)) /* read sec, err? */ + if ((r = idc_rds (uptr))) /* read sec, err? */ return r; idc_1st = 0; - t = sch_wrmem (idc_dib.sch, idcxb, IDC_NUMBY); /* write mem */ + sch_wrmem (idc_dib.sch, idcxb, IDC_NUMBY); /* write mem */ if (sch_actv (idc_dib.sch, idc_dib.dno)) { /* more to do? */ sim_activate (uptr, idc_rtime); /* reschedule */ return SCPE_OK; @@ -595,7 +594,7 @@ switch (uptr->FNC & CMC_MASK) { /* case on func */ return SCPE_OK; idc_bptr = sch_rdmem (idc_dib.sch, idcxb, IDC_NUMBY); /* read mem */ idc_db = idcxb[idc_bptr - 1]; /* last byte */ - if (r = idc_wds (uptr)) /* write sec, err? */ + if ((r = idc_wds (uptr))) /* write sec, err? */ return r; idc_1st = 0; if (sch_actv (idc_dib.sch, idc_dib.dno)) { /* more to do? */ @@ -693,7 +692,7 @@ uint32 hd, sc, sa; uint32 dtype = GET_DTYPE (uptr->flags); /* get drive type */ if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */ - idc_done (STC_DTE); /* error, done */ + idc_done (STC_DTE); /* error, done */ return TRUE; } if ((uptr->flags & UNIT_WPRT) && (uptr->FNC == CMC_WR)) { diff --git a/Interdata/id_io.c b/Interdata/id_io.c index 86228eda..a97cf813 100644 --- a/Interdata/id_io.c +++ b/Interdata/id_io.c @@ -66,8 +66,6 @@ extern uint32 int_req[INTSZ], int_enb[INTSZ]; extern uint32 (*dev_tab[DEVNO])(uint32 dev, uint32 op, uint32 datout); extern uint32 pawidth; extern UNIT cpu_unit; -extern FILE *sim_log; -extern DEVICE *sim_devices[]; uint32 sch_max = 2; /* sch count */ uint32 sch_sa[SCH_NUMCH] = { 0 }; /* start addr */ @@ -358,14 +356,11 @@ if ((r != SCPE_OK) || (newmax == sch_max)) /* err or no chg? */ if (newmax == 0) /* must be > 0 */ return SCPE_ARG; if (newmax < sch_max) { /* reducing? */ - for (i = 0; dptr = sim_devices[i]; i++) { /* loop thru dev */ + for (i = 0; (dptr = sim_devices[i]); i++) { /* loop thru dev */ dibp = (DIB *) dptr->ctxt; /* get DIB */ if (dibp && (dibp->sch >= (int32) newmax)) { /* dev using chan? */ - printf ("Device %02X uses channel %d\n", + sim_printf ("Device %02X uses channel %d\n", dibp->dno, dibp->sch); - if (sim_log) - fprintf (sim_log, "Device %02X uses channel %d\n", - dibp->dno, dibp->sch); return SCPE_OK; } } @@ -439,7 +434,7 @@ int32 i, j, t; uint32 r; for (i = t = 0; i < INTSZ; i++) { /* loop thru array */ - if (r = int_req[i] & int_enb[i]) { /* find nz int wd */ + if ((r = int_req[i] & int_enb[i])) { /* find nz int wd */ for (j = 0; j < 32; t++, j++) { if (r & (1u << j)) { int_req[i] = int_req[i] & ~(1u << j); /* clr request */ @@ -630,7 +625,7 @@ for (i = 0; i < (DEVNO / 32); i++) /* Test each device for conflict; add to map; init tables */ -for (i = 0; dptr = sim_devices[i]; i++) { /* loop thru devices */ +for (i = 0; (dptr = sim_devices[i]); i++) { /* loop thru devices */ dibp = (DIB *) dptr->ctxt; /* get DIB */ if ((dibp == NULL) || (dptr->flags & DEV_DIS)) /* exist, enabled? */ continue; @@ -645,9 +640,7 @@ for (i = 0; dptr = sim_devices[i]; i++) { /* loop thru devices */ dmsk = 1u << (t & 0x1F); /* bit to test */ doff = t / 32; /* word to test */ if (dmap[doff] & dmsk) { /* in use? */ - printf ("Device number conflict, devno = %02X\n", t); - if (sim_log) - fprintf (sim_log, "Device number conflict, devno = %02X\n", t); + sim_printf ("Device number conflict, devno = %02X\n", t); return TRUE; } dmap[doff] = dmap[doff] | dmsk; diff --git a/Interdata/id_mt.c b/Interdata/id_mt.c index fce949fa..f9209d82 100644 --- a/Interdata/id_mt.c +++ b/Interdata/id_mt.c @@ -168,7 +168,7 @@ DEVICE mt_dev = { MT_NUMDR, 10, 31, 1, 16, 8, NULL, NULL, &mt_reset, &mt_boot, &mt_attach, &mt_detach, - &mt_dib, DEV_DISABLE + &mt_dib, DEV_DISABLE | DEV_TAPE }; /* Magtape: IO routine */ @@ -368,13 +368,13 @@ switch (uptr->UCMD) { /* case on function */ } if (mt_bptr) { /* any chars? */ - if (st = sim_tape_wrrecf (uptr, mtxb, mt_bptr)) /* write, err? */ + if ((st = sim_tape_wrrecf (uptr, mtxb, mt_bptr)))/* write, err? */ r = mt_map_err (uptr, st); /* map error */ } break; /* record done */ case MTC_WEOF: /* write eof */ - if (st = sim_tape_wrtmk (uptr)) /* write tmk, err? */ + if ((st = sim_tape_wrtmk (uptr))) /* write tmk, err? */ r = mt_map_err (uptr, st); /* map error */ mt_sta = mt_sta | STA_EOF; /* set eof */ if (mt_arm[u]) /* set intr */ @@ -402,7 +402,7 @@ switch (uptr->UCMD) { /* case on function */ break; case MTC_SPCR: /* backspace */ - if (st = sim_tape_sprecr (uptr, &tbc)) /* skip rec rev, err? */ + if ((st = sim_tape_sprecr (uptr, &tbc))) /* skip rec rev, err? */ r = mt_map_err (uptr, st); /* map error */ break; } /* end case */ diff --git a/Interdata/id_pas.c b/Interdata/id_pas.c index ad3672b2..9874b7df 100644 --- a/Interdata/id_pas.c +++ b/Interdata/id_pas.c @@ -104,7 +104,7 @@ uint8 pas_xarm[PAS_LINES]; /* xmt int armed */ uint8 pas_rchp[PAS_LINES]; /* rcvr chr pend */ uint8 pas_tplte[PAS_LINES * 2 + 1]; /* template */ -TMLN pas_ldsc[PAS_LINES] = { 0 }; /* line descriptors */ +TMLN pas_ldsc[PAS_LINES] = { {0} }; /* line descriptors */ TMXR pas_desc = { 8, 0, 0, pas_ldsc }; /* mux descriptor */ #define PAS_ENAB pas_desc.lines @@ -166,7 +166,7 @@ DEVICE pas_dev = { 1, 10, 31, 1, 16, 8, &tmxr_ex, &tmxr_dep, &pas_reset, NULL, &pas_attach, &pas_detach, - &pas_dib, DEV_NET | DEV_DISABLE + &pas_dib, DEV_MUX | DEV_DISABLE }; /* PASL data structures @@ -335,7 +335,7 @@ if (ln >= 0) { /* got one? */ tmxr_poll_rx (&pas_desc); /* poll for input */ for (ln = 0; ln < PAS_ENAB; ln++) { /* loop thru lines */ if (pas_ldsc[ln].conn) { /* connected? */ - if (c = tmxr_getc_ln (&pas_ldsc[ln])) { /* any char? */ + if ((c = tmxr_getc_ln (&pas_ldsc[ln]))) { /* any char? */ pas_sta[ln] = pas_sta[ln] & ~(STA_FR | STA_PF); if (pas_rchp[ln]) pas_sta[ln] = pas_sta[ln] | STA_OVR; @@ -527,7 +527,7 @@ if (newln < PAS_ENAB) { if (pas_ldsc[i].conn) { tmxr_linemsg (&pas_ldsc[i], "\r\nOperator disconnected line\r\n"); tmxr_reset_ln (&pas_ldsc[i]); /* reset line */ - } + } pasl_unit[i].flags = pasl_unit[i].flags | UNIT_DIS; pas_reset_ln (i); } diff --git a/Interdata/id_pt.c b/Interdata/id_pt.c index 0dc89bfd..01caa9bc 100644 --- a/Interdata/id_pt.c +++ b/Interdata/id_pt.c @@ -204,7 +204,7 @@ if ((temp = getc (uptr->fileref)) == EOF) { /* error? */ if (feof (uptr->fileref)) { /* eof? */ pt_sta = pt_sta | STA_DU; /* set DU */ if (ptr_stopioe) - printf ("PTR end of file\n"); + sim_printf ("PTR end of file\n"); else return SCPE_OK; } else perror ("PTR I/O error"); diff --git a/Interdata/id_ttp.c b/Interdata/id_ttp.c index 660fd469..eb9fd393 100644 --- a/Interdata/id_ttp.c +++ b/Interdata/id_ttp.c @@ -130,7 +130,7 @@ DEVICE ttp_dev = { uint32 ttp (uint32 dev, uint32 op, uint32 dat) { int32 xmt = dev & 1; -int32 t, old_cmd; +int32 t; switch (op) { /* case IO op */ @@ -160,7 +160,6 @@ switch (op) { /* case IO op */ return t; case IO_OC: /* command */ - old_cmd = ttp_cmd; /* old cmd */ if (dat & CMD_TYP) { /* type 1? */ ttp_cmd = (ttp_cmd & 0xFF) | (dat << 8); if (ttp_cmd & CMD_WRT) /* write? */ diff --git a/Interdata/id_uvc.c b/Interdata/id_uvc.c index 7ccc070a..0d1d9451 100644 --- a/Interdata/id_uvc.c +++ b/Interdata/id_uvc.c @@ -358,7 +358,7 @@ int32 lfc_cosched (int32 wait) { int32 t; -t = sim_is_active (&lfc_unit); +t = sim_activate_time (&lfc_unit); return (t? t - 1: wait); } diff --git a/LGP/lgp_cpu.c b/LGP/lgp_cpu.c index 6b969306..b91d6b82 100644 --- a/LGP/lgp_cpu.c +++ b/LGP/lgp_cpu.c @@ -147,11 +147,6 @@ int16 pcq[PCQ_SIZE] = { 0 }; /* PC queue */ int32 pcq_p = 0; /* PC queue ptr */ REG *pcq_r = NULL; /* PC queue reg ptr */ -extern int32 sim_interval; -extern int32 sim_int_char; -extern uint32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ -extern int32 sim_step; - t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw); t_stat cpu_reset (DEVICE *dptr); @@ -288,7 +283,7 @@ if (lgp21_sov) { /* stop sense pending? * do { if (sim_interval <= 0) { /* check clock queue */ - if (r = sim_process_event ()) + if ((r = sim_process_event ())) break; } @@ -308,7 +303,7 @@ do { PC = (PC + 1) & AMASK; /* increment PC */ sim_interval = sim_interval - 1; - if (r = cpu_one_inst (oPC, IR)) { /* one instr; error? */ + if ((r = cpu_one_inst (oPC, IR))) { /* one instr; error? */ if (r == STOP_STALL) { /* stall? */ PC = oPC; /* back up PC */ delay = r = 0; /* no delay */ @@ -744,7 +739,7 @@ if (cptr) { else inst = IR; while ((r = cpu_one_inst (PC, inst)) == STOP_STALL) { sim_interval = 0; - if (r = sim_process_event ()) + if ((r = sim_process_event ())) return r; } return r; diff --git a/LGP/lgp_defs.h b/LGP/lgp_defs.h index ebe442ed..fdff4d02 100644 --- a/LGP/lgp_defs.h +++ b/LGP/lgp_defs.h @@ -26,8 +26,8 @@ 22-May-10 RMS Added check for 64b definitions */ -#ifndef _LGP_DEFS_H_ -#define _LGP_DEFS_H_ 0 +#ifndef LGP_DEFS_H_ +#define LGP_DEFS_H_ 0 #include "sim_defs.h" /* simulator defns */ diff --git a/LGP/lgp_stddev.c b/LGP/lgp_stddev.c index 2dba6cc1..80657ab1 100644 --- a/LGP/lgp_stddev.c +++ b/LGP/lgp_stddev.c @@ -48,7 +48,6 @@ extern uint32 A; extern uint32 inp_strt, inp_done; extern uint32 out_strt, out_done; extern UNIT cpu_unit; -extern int32 sim_switches; t_stat tti_svc (UNIT *uptr); t_stat ttr_svc (UNIT *uptr); @@ -394,7 +393,7 @@ t_stat ttr_svc (UNIT *uptr) { t_stat r; -if (r = read_reader (uptr, ttr_stopioe, (int32 *) &tti_buf)) +if ((r = read_reader (uptr, ttr_stopioe, (int32 *) &tti_buf))) return r; if (!(uptr->flags & UNIT_NOCS) && /* cstop enable? */ (tti_buf == FLEX_CSTOP)) /* cond stop? */ @@ -415,7 +414,7 @@ t_stat ptr_svc (UNIT *uptr) { t_stat r; -if (r = read_reader (uptr, ptr_stopioe, &uptr->buf)) +if ((r = read_reader (uptr, ptr_stopioe, &uptr->buf))) return r; if (uptr->buf == FLEX_CSTOP) /* cond stop? */ inp_done = 1; @@ -502,7 +501,7 @@ do { if ((ch = getc (uptr->fileref)) == EOF) { /* read char */ if (feof (uptr->fileref)) { /* err or eof? */ if (stop) - printf ("Reader end of file\n"); + sim_printf ("Reader end of file\n"); else return SCPE_OK; } else perror ("Reader I/O error"); @@ -517,7 +516,7 @@ do { if ((d1 == EOF) || (d2 == EOF)) { /* error? */ if (feof (uptr->fileref)) { /* eof? */ if (stop) - printf ("Reader end of file\n"); + sim_printf ("Reader end of file\n"); else return SCPE_OK; } else perror ("Reader I/O error"); @@ -548,7 +547,7 @@ else { ch = '\b'; else ch = flex_to_ascii[flex | (tto_uc << 6)]; /* cvt flex to ascii */ if (ch > 0) { /* legit? */ - if (r = sim_putchar_s (ch)) /* write char */ + if ((r = sim_putchar_s (ch))) /* write char */ return r; tto_unit[0].pos = tto_unit[0].pos + 1; if (flex == FLEX_CR) { /* cr? */ diff --git a/LGP/lgp_sys.c b/LGP/lgp_sys.c index f445e202..a5047d7b 100644 --- a/LGP/lgp_sys.c +++ b/LGP/lgp_sys.c @@ -40,12 +40,8 @@ extern REG cpu_reg[]; extern uint32 M[]; extern uint32 PC; extern uint32 ts_flag; -extern int32 sim_switches; extern int32 flex_to_ascii[128], ascii_to_flex[128]; -extern void (*sim_vm_fprint_addr) (FILE *st, DEVICE *dptr, t_addr addr); -extern t_addr (*sim_vm_parse_addr) (DEVICE *dptr, char *cptr, char **tptr); - /* SCP data structures and interface routines sim_name simulator name string @@ -297,7 +293,7 @@ if (uptr && (uptr != &cpu_unit)) /* must be CPU */ return SCPE_ARG; if ((sw & SWMASK ('M')) && /* symbolic decode? */ ((inst & ~(SIGN|I_OP|I_EA)) == 0)) { - op = I_GETOP (inst); + op = I_GETOP (inst); ea = I_GETEA (inst); if (inst & SIGN) fputc ('-', of); @@ -363,7 +359,7 @@ if ((sw & SWMASK ('L')) || /* LGP hex? */ return SCPE_OK; if (islower (c)) c = toupper (c); - if (tptr = strchr (hex_decode, c)) + if ((tptr = strchr (hex_decode, c))) val[0] = (val[0] << 4) | (tptr - hex_decode); else return SCPE_ARG; } @@ -388,7 +384,7 @@ else sgn = 0; cptr = get_glyph (cptr, gbuf, 0); /* get opcode */ if (gbuf[1] != 0) return SCPE_ARG; -if (tptr = strchr (opcode, gbuf[0])) +if ((tptr = strchr (opcode, gbuf[0]))) val[0] = ((tptr - opcode) << I_V_OP) | sgn; /* merge opcode */ else return SCPE_ARG; cptr = get_glyph (cptr, gbuf, 0); /* get address */ diff --git a/NOVA/eclipse_cpu.c b/NOVA/eclipse_cpu.c index 2a70b789..c2ec12e1 100644 --- a/NOVA/eclipse_cpu.c +++ b/NOVA/eclipse_cpu.c @@ -3,7 +3,7 @@ Modified from the original NOVA simulator by Robert Supnik. Copyright (c) 1998-2012, Charles E Owen - Portions Copyright (c) 1993-2002, Robert M Supnik + Portions Copyright (c) 1993-2015, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -28,6 +28,7 @@ cpu Eclipse central processor + 30-Mar-15 RMS Fixed typo in DIVS 25-Mar-12 RMS Fixed declarations (Mark Pizzolato) 07-Jun-06 RMS Fixed bug in DIVS (Mark Hittinger) 22-Sep-05 RMS Fixed declarations (Sterling Garwood) @@ -495,9 +496,6 @@ FILE *Trace; t_stat reason; -extern int32 sim_int_char; -extern uint32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ -extern DEVICE *sim_devices[]; t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw); @@ -516,9 +514,6 @@ int32 PutMap(int32 addr, int32 data); int32 Debug_Entry(int32 PC, int32 inst, int32 inst2, int32 AC0, int32 AC1, int32 AC2, int32 AC3, int32 flags); t_stat build_devtab (void); -extern t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, - UNIT *uptr, int32 sw); - /* CPU data structures cpu_dev CPU device descriptor @@ -699,7 +694,6 @@ DEVICE pit_dev = { t_stat sim_instr (void) { -extern int32 sim_interval; register int32 PC, IR, i, t, MA, j, k, tac; register uint32 mddata, uAC0, uAC1, uAC2, uAC3; int16 sAC0, sAC1, sAC2; @@ -744,7 +738,7 @@ if (MapInit == 0) { while (reason == 0) { /* loop until halted */ if (sim_interval <= 0) { /* check clock queue */ - if (reason = sim_process_event ()) + if ((reason = sim_process_event ())) break; } @@ -1666,7 +1660,7 @@ if ((IR & 0100017) == 0100010) { /* This pattern for all continue; } if (IR == 0157710) { /* DIVS: Signed Divide */ - if ((AC[0] == 0) || + if ((AC[2] == 0) || ((AC[0] == 0100000) && (AC[1] == 0) && (AC[2] == 0177777))) C = 0200000; else { @@ -5932,7 +5926,7 @@ static const int32 boot_rom[] = { t_stat cpu_boot (int32 unitno, DEVICE *dptr) { -int32 i; +size_t i; extern int32 saved_PC; for (i = 0; i < BOOT_LEN; i++) M[BOOT_START + i] = boot_rom[i]; diff --git a/NOVA/nova_clk.c b/NOVA/nova_clk.c index 0f9bbdb3..59bc0af9 100644 --- a/NOVA/nova_clk.c +++ b/NOVA/nova_clk.c @@ -140,7 +140,7 @@ if ( DEV_IS_BUSY(INT_CLK) ) DEV_UPDATE_INTR ; } t = sim_rtc_calb (clk_tps[clk_sel]); /* calibrate delay */ -sim_activate (&clk_unit, t); /* reactivate unit */ +sim_activate_after (uptr, 1000000/clk_tps[clk_sel]); /* reactivate unit */ if (clk_adj[clk_sel] > 0) /* clk >= 60Hz? */ tmxr_poll = t * clk_adj[clk_sel]; /* poll is longer */ else @@ -153,6 +153,7 @@ return SCPE_OK; t_stat clk_reset (DEVICE *dptr) { +sim_register_clock_unit (&clk_unit); /* declare clock unit */ clk_sel = 0; DEV_CLR_BUSY( INT_CLK ) ; DEV_CLR_DONE( INT_CLK ) ; diff --git a/NOVA/nova_cpu.c b/NOVA/nova_cpu.c index 209f16da..16b83b15 100644 --- a/NOVA/nova_cpu.c +++ b/NOVA/nova_cpu.c @@ -244,14 +244,12 @@ #define STK_CHECK(x,y) if (((x) & 0377) < (y)) \ int_req = int_req | INT_STK #define IND_STEP(x) M[x] & A_IND; /* return next level indicator */ \ - if (((x) <= AUTO_TOP) && ((x) >= AUTO_INC)) { \ - if ( (x) < AUTO_DEC ) { \ - M[x] = (M[x] + 1) & DMASK; \ - } \ - else { \ - M[x] = (M[x] - 1) & DMASK; \ - } \ - } \ + if ( ((x) <= AUTO_TOP) && ((x) >= AUTO_INC) ) { \ + if ( (x) < AUTO_DEC ) \ + M[x] = (M[x] + 1) & DMASK; \ + else \ + M[x] = (M[x] - 1) & DMASK; \ + } \ x = M[x] & AMASK #define INCREMENT_PC PC = (PC + 1) & AMASK /* increment PC */ @@ -259,12 +257,12 @@ #define UNIT_V_MDV (UNIT_V_UF + 0) /* MDV present */ #define UNIT_V_STK (UNIT_V_UF + 1) /* stack instr */ #define UNIT_V_BYT (UNIT_V_UF + 2) /* byte instr */ -#define UNIT_V_64KW (UNIT_V_UF + 3) /* 64KW mem support */ +#define UNIT_V_64KW (UNIT_V_UF + 3) /* 64KW mem support */ #define UNIT_V_MSIZE (UNIT_V_UF + 4) /* dummy mask */ #define UNIT_MDV (1 << UNIT_V_MDV) #define UNIT_STK (1 << UNIT_V_STK) #define UNIT_BYT (1 << UNIT_V_BYT) -#define UNIT_64KW (1 << UNIT_V_64KW) +#define UNIT_64KW (1 << UNIT_V_64KW) #define UNIT_MSIZE (1 << UNIT_V_MSIZE) #define UNIT_IOPT (UNIT_MDV | UNIT_STK | UNIT_BYT | UNIT_64KW) #define UNIT_NOVA3 (UNIT_MDV | UNIT_STK) @@ -334,14 +332,6 @@ char * devBitNames( int32 flags, char * ptr, char * sepStr ) ; void mask_out (int32 mask); -extern int32 sim_interval; -extern int32 sim_int_char; -extern uint32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ -extern DEVICE * sim_devices[]; -extern t_stat fprint_sym(FILE *ofile, t_addr addr, t_value *val, UNIT *uptr, int32 sw); - - - /* CPU data structures cpu_dev CPU device descriptor @@ -398,7 +388,6 @@ MTAB cpu_mod[] = { { UNIT_MSIZE, (24 * 1024), NULL, "24K", &cpu_set_size }, { UNIT_MSIZE, (28 * 1024), NULL, "28K", &cpu_set_size }, { UNIT_MSIZE, (32 * 1024), NULL, "32K", &cpu_set_size }, - { UNIT_MSIZE, (36 * 1024), NULL, "36K", &cpu_set_size }, { UNIT_MSIZE, (40 * 1024), NULL, "40K", &cpu_set_size }, { UNIT_MSIZE, (44 * 1024), NULL, "44K", &cpu_set_size }, @@ -487,7 +476,7 @@ while (reason == 0) { /* loop until halted */ IR = M[PC]; /* fetch instr */ if ( hist_cnt ) { - hist_save( PC, IR ) ; /* PC, int_req unchanged */ + hist_save( PC, IR ) ; /* PC, int_req unchanged */ } INCREMENT_PC ; @@ -983,15 +972,15 @@ while (reason == 0) { /* loop until halted */ else if (device == DEV_CPU) { /* CPU control */ switch (code) { /* decode IR<5:7> */ - case ioNIO: /* NIOP CPU ? */ - if ( pulse == iopP ) - if ( MODE_64K ) + case ioNIO: /* NIOP CPU ? */ + if ( pulse == iopP ) + if ( MODE_64K ) { - /* Keronix/Point4/SCI/INI/IDP (and others) */ - /* 64 KW memory extension: */ - /* NIOP - set memory mode (32/64 KW) per AC: */ - /* B15: 0 = 32 KW, 1 = 64 KW mode */ - AMASK = (AC[dstAC] & 0x0001) ? 0177777 : 077777 ; + /* Keronix/Point4/SCI/INI/IDP (and others) */ + /* 64 KW memory extension: */ + /* NIOP - set memory mode (32/64 KW) per AC: */ + /* B15: 0 = 32 KW, 1 = 64 KW mode */ + AMASK = (AC[dstAC] & 0x0001) ? 0177777 : 077777 ; } break ; @@ -1213,11 +1202,11 @@ return SCPE_OK; * - The Binary Loader was in turn used to load tapes in the usual DG 'absolute binary' format. */ -#define BOOT_START 00000 -#define BOOT_LEN (sizeof(boot_rom) / sizeof(int32)) +#define BOOT_START 00000 +#define BOOT_LEN (sizeof(boot_rom) / sizeof(int32)) static const int32 boot_rom[] = { - 0062677, /* IORST ;reset all I/O */ + 0062677, /* IORST ;reset all I/O */ 0060477, /* READS 0 ;read SR into AC0 */ 0024026, /* LDA 1,C77 ;get dev mask */ 0107400, /* AND 0,1 ;isolate dev code */ @@ -1256,7 +1245,7 @@ static const int32 boot_rom[] = { t_stat cpu_boot (int32 unitno, DEVICE *dptr) { -int32 i; +size_t i; for (i = 0; i < BOOT_LEN; i++) M[BOOT_START + i] = boot_rom[i]; saved_PC = BOOT_START; @@ -1363,7 +1352,7 @@ if ( (r != SCPE_OK) || (lnt && (lnt < HIST_MIN)) ) } hist_p = 0; if ( hist_cnt ) - { + { free( hist ) ; hist_cnt = 0 ; hist = NULL ; diff --git a/NOVA/nova_defs.h b/NOVA/nova_defs.h index 5f5f6ffa..207c1c69 100644 --- a/NOVA/nova_defs.h +++ b/NOVA/nova_defs.h @@ -46,8 +46,8 @@ the NOVA. */ -#ifndef _NOVA_DEFS_H_ -#define _NOVA_DEFS_H_ 0 +#ifndef NOVA_DEFS_H_ +#define NOVA_DEFS_H_ 0 #include "sim_defs.h" /* simulator defns */ @@ -56,7 +56,7 @@ #endif /* Simulator stop codes */ - + #define STOP_RSRV 1 /* must be 1 */ #define STOP_HALT 2 /* HALT */ #define STOP_IBKPT 3 /* breakpoint */ @@ -284,7 +284,7 @@ typedef struct { #define INT_ION (1 << INT_V_ION) #define INT_DEV ((1 << INT_V_STK) - 1) /* device ints */ #define INT_PENDING INT_ION+INT_NO_ION_PENDING -#define INT_TRAP (1 << INT_V_TRAP) +#define INT_TRAP (1 << INT_V_TRAP) /* PI disable bits */ diff --git a/NOVA/nova_dkp.c b/NOVA/nova_dkp.c index 34e4269c..c9d50cec 100644 --- a/NOVA/nova_dkp.c +++ b/NOVA/nova_dkp.c @@ -148,7 +148,7 @@ /* (Warning: no sector or surface masking is done!) */ -#define DKP_UPDATE_USSC( type, count, surf, sect ) \ +#define DKP_UPDATE_USSC( type, count, surf, sect ) \ dkp_ussc = (dkp_ussc & USSC_UNIT) \ | ((dkp_ussc + count) & USSC_M_COUNT) \ | ((drv_tab[dtype].newf)? \ @@ -344,7 +344,7 @@ int32 dkp_swait = 100; /* seek latency */ int32 dkp_rwait = 100; /* rotate latency */ int32 dkp_diagmode = 0; /* diagnostic mode */ -int32 dkp_trace = 0 ; +int32 dkp_trace = 0 ; DEVICE dkp_dev; int32 dkp (int32 pulse, int32 code, int32 AC); @@ -526,7 +526,7 @@ if ( DKP_TRACE(0) ) switch (code) { /* decode IR<5:7> */ case ioDIA: /* DIA */ - dkp_sta = dkp_sta & (~STA_DRDY) ; /* keep error flags */ + dkp_sta = dkp_sta & (~STA_DRDY) ; /* keep error flags */ if (uptr->flags & UNIT_ATT) /* update ready */ dkp_sta = dkp_sta | STA_DRDY; if (uptr->CYL >= drv_tab[dtype].cyl) @@ -543,10 +543,10 @@ switch (code) { /* decode IR<5:7> */ dkp_fccy = AC; /* save cmd, cyl */ dkp_sta = dkp_sta & ~(AC & FCCY_FLAGS); } - DEV_CLR_DONE( INT_DKP ) ; /* assume done flags 0 */ - if ( dkp_sta & STA_DFLGS ) /* done flags = 0? */ - DEV_SET_DONE( INT_DKP ) ; /* nope - set done */ - DEV_UPDATE_INTR ; /* update intr */ + DEV_CLR_DONE( INT_DKP ); /* assume done flags 0 */ + if ( dkp_sta & STA_DFLGS ) /* done flags = 0? */ + DEV_SET_DONE( INT_DKP ) ; /* nope - set done */ + DEV_UPDATE_INTR ; /* update intr */ break; case ioDIB: /* DIB */ @@ -569,18 +569,18 @@ switch (code) { /* decode IR<5:7> */ break; case ioDOC: /* DOC */ - if ((dev_busy & INT_DKP) == 0) /* if device is not busy */ - dkp_ussc = AC ; /* save unit, sect */ - if (((dtype == TYPE_6099) || /* (BKR: don't forget 6097) */ + if ((dev_busy & INT_DKP) == 0) /* if device is not busy */ + dkp_ussc = AC ; /* save unit, sect */ + if (((dtype == TYPE_6099) || /* (BKR: don't forget 6097) */ (dtype == TYPE_6097) || /* for 6099 and 6103 */ (dtype == TYPE_6103)) && /* if data<0> set, */ (AC & 010000) ) - dkp_diagmode = 1; /* set diagnostic mode */ + dkp_diagmode = 1; /* set diagnostic mode */ break; } /* end switch code */ u = GET_UNIT(dkp_ussc); /* update current unit */ -uptr = dkp_dev.units + u ; /* select unit */ +uptr = dkp_dev.units + u ; /* select unit */ dtype = GET_DTYPE (uptr->flags); /* get drive type */ if ( DKP_TRACE(0) ) @@ -606,7 +606,7 @@ switch (pulse) { /* decode IR<8:9> */ dkp_ussc = 010003; } else { /* normal mode ... */ - if (dkp_go (pulse)) /* do command */ + if (dkp_go (pulse)) /* do command */ break ; /* break if no error */ } DEV_CLR_BUSY( INT_DKP ) ; /* clear busy */ @@ -645,8 +645,8 @@ switch (pulse) { /* decode IR<8:9> */ break; /* no error - do not set done and status */ } - DEV_SET_DONE( INT_DKP ) ; /* set done */ - DEV_UPDATE_INTR ; /* update ints */ + DEV_SET_DONE( INT_DKP ) ; /* set done */ + DEV_UPDATE_INTR ; /* update ints */ dkp_sta = dkp_sta | (STA_SKDN0 >> u); /* set controller seek done */ break; } /* end case pulse */ @@ -661,8 +661,8 @@ return rval; t_stat dkp_go ( int32 pulse ) { -UNIT * uptr; -int32 oldCyl, u, dtype; +UNIT *uptr; +int32 oldCyl, u, dtype; dkp_sta = dkp_sta & ~STA_EFLGS; /* clear errors */ u = GET_UNIT (dkp_ussc); /* get unit number */ @@ -686,38 +686,38 @@ uptr->FUNC = GET_CMD (dkp_fccy, dtype) ; /* save command */ uptr->CYL = GET_CYL (dkp_fccy, dtype) ; if ( DKP_TRACE(1) ) - { - int32 xSect ; - int32 xSurf ; - int32 xCyl ; - int32 xCnt ; + { + int32 xSect ; + int32 xSurf ; + int32 xCyl ; + int32 xCnt ; - xSect = GET_SECT(dkp_ussc, dtype) ; - xSurf = GET_SURF(dkp_ussc, dtype) ; - xCyl = GET_CYL (dkp_fccy, dtype) ; - xCnt = 16 - (GET_COUNT(dkp_ussc)) ; + xSect = GET_SECT(dkp_ussc, dtype) ; + xSurf = GET_SURF(dkp_ussc, dtype) ; + xCyl = GET_CYL (dkp_fccy, dtype) ; + xCnt = 16 - (GET_COUNT(dkp_ussc)) ; - fprintf( DKP_TRACE_FP, - " [%s:%c %-5s: %3d / %2d / %2d %2d %06o ] \r\n", - "DKP", - (char) (u + '0'), - ((uptr->FUNC == FCCY_READ) ? - "read" - : ((uptr->FUNC == FCCY_WRITE) ? - "write" - : ((uptr->FUNC == FCCY_SEEK) ? - "seek" - : "" - ) - ) - ), - (unsigned) xCyl, - (unsigned) xSurf, - (unsigned) xSect, - (unsigned) (16 - xCnt), - (unsigned) (dkp_ma & 0xFFFF) /* show all 16-bits in case DCH B */ - ) ; - } + fprintf( DKP_TRACE_FP, + " [%s:%c %-5s: %3d / %2d / %2d %2d %06o ] \r\n", + "DKP", + (char) (u + '0'), + ((uptr->FUNC == FCCY_READ) ? + "read" + : ((uptr->FUNC == FCCY_WRITE) ? + "write" + : ((uptr->FUNC == FCCY_SEEK) ? + "seek" + : "" + ) + ) + ), + (unsigned) xCyl, + (unsigned) xSurf, + (unsigned) xSect, + (unsigned) (16 - xCnt), + (unsigned) (dkp_ma & 0xFFFF) /* show all 16-bits in case DCH B */ + ) ; + } switch (uptr->FUNC) { /* decode command */ @@ -727,7 +727,7 @@ switch (uptr->FUNC) { /* decode command */ if (((uptr->flags & UNIT_ATT) == 0) || /* not attached? */ ((uptr->flags & UNIT_WPRT) && (uptr->FUNC == FCCY_WRITE))) { - dkp_sta = dkp_sta | STA_DONE | STA_ERR; /* error */ + dkp_sta = dkp_sta | STA_DONE | STA_ERR; /* error */ } else if ( uptr->CYL >= drv_tab[dtype].cyl ) /* bad cylinder */ { @@ -736,7 +736,7 @@ switch (uptr->FUNC) { /* decode command */ else if ( GET_SURF(dkp_ussc, dtype) >= drv_tab[dtype].surf ) /* bad surface */ { dkp_sta = dkp_sta | STA_DONE | STA_ERR | STA_UNS; /* older drives may not even do this... */ - /* dkp_sta = dkp_sta | STA_DONE | STA_ERR | STA_XCY ; /- newer disks give this error */ + /* dkp_sta = dkp_sta | STA_DONE | STA_ERR | STA_XCY ; /- newer disks give this error */ } else if ( GET_SECT(dkp_ussc, dtype) >= drv_tab[dtype].sect ) /* or bad sector? */ { @@ -811,7 +811,7 @@ u = uptr - dkp_dev.units; /* get unit number */ if (uptr->FUNC == FCCY_SEEK) { /* seek? */ if ( ! (uptr->flags & UNIT_ATT) ) /* not attached? */ { - dkp_sta = dkp_sta | STA_DONE | STA_ERR; /* error (changed during queue time?) */ + dkp_sta = dkp_sta | STA_DONE | STA_ERR; /* error (changed during queue time?) */ } else if ( uptr->CYL >= drv_tab[dtype].cyl ) /* bad cylinder? */ { @@ -838,7 +838,7 @@ if (uptr->FUNC == FCCY_SEEK) { /* seek? */ if (((uptr->flags & UNIT_ATT) == 0) || /* not attached? */ ((uptr->flags & UNIT_WPRT) && (uptr->FUNC == FCCY_WRITE))) { - dkp_sta = dkp_sta | STA_DONE | STA_ERR; /* error */ + dkp_sta = dkp_sta | STA_DONE | STA_ERR; /* error */ } else if ( uptr->CYL >= drv_tab[dtype].cyl ) /* bad cylinder */ { @@ -856,7 +856,7 @@ else if ( GET_SURF(dkp_ussc, dtype) >= drv_tab[dtype].surf ) /* bad surface */ } else if ( GET_SECT(dkp_ussc, dtype) >= drv_tab[dtype].sect ) /* or bad sector? */ { -/* dkp_sta = dkp_sta | STA_DONE | STA_ERR | STA_UNS; /- older DG drives do not even give error(!), but we do */ +/* dkp_sta = dkp_sta | STA_DONE | STA_ERR | STA_UNS; /- older DG drives do not even give error(!), but we do */ dkp_sta = dkp_sta | STA_DONE | STA_ERR | STA_XCY ; /* newer disks give this error */ } else { @@ -909,7 +909,7 @@ do { if (uptr->FUNC == FCCY_READ) { /* read? */ awc = fxread (tbuf, sizeof(uint16), DKP_NUMWD, uptr->fileref); for ( ; awc < DKP_NUMWD; awc++) tbuf[awc] = 0; - if (err = ferror (uptr->fileref)) + if ((err = ferror (uptr->fileref))) break; for (dx = 0; dx < DKP_NUMWD; dx++) { /* loop thru buffer */ pa = MapAddr (dkp_map, (dkp_ma & AMASK)); @@ -925,7 +925,7 @@ do { dkp_ma = (dkp_ma + 1) & AMASK; } fxwrite (tbuf, sizeof(int16), DKP_NUMWD, uptr->fileref); - if (err = ferror (uptr->fileref)) + if ((err = ferror (uptr->fileref))) break; } @@ -937,8 +937,8 @@ do { } newsect = GET_SECT (dkp_ussc, dtype) + 1 ; /* update next sector */ -newsurf = GET_SURF (dkp_ussc, dtype) ; /* and next head */ - /* (count set below) */ +newsurf = GET_SURF (dkp_ussc, dtype) ; /* and next head */ + /* (count set below) */ DKP_UPDATE_USSC( type, 1, newsurf, newsect ) } /* end read/write loop */ @@ -973,9 +973,9 @@ t_stat dkp_reset (DEVICE *dptr) int32 u; UNIT *uptr; -DEV_CLR_BUSY( INT_DKP ) ; /* clear busy */ -DEV_CLR_DONE( INT_DKP ) ; /* clear done */ -DEV_UPDATE_INTR ; /* update ints */ +DEV_CLR_BUSY( INT_DKP ) ; /* clear busy */ +DEV_CLR_DONE( INT_DKP ) ; /* clear done */ +DEV_UPDATE_INTR ; /* update ints */ dkp_fccy = dkp_ussc = dkp_ma = dkp_sta = 0; /* clear registers */ dkp_diagmode = 0; /* clear diagnostic mode */ dkp_map = 0; @@ -1085,7 +1085,7 @@ static const int32 boot_rom[] = { t_stat dkp_boot (int32 unitno, DEVICE *dptr) { -int32 i; +size_t i; for (i = 0; i < BOOT_LEN; i++) M[BOOT_START + i] = (uint16) boot_rom[i]; diff --git a/NOVA/nova_dsk.c b/NOVA/nova_dsk.c index af4d3f6e..75e83800 100644 --- a/NOVA/nova_dsk.c +++ b/NOVA/nova_dsk.c @@ -298,7 +298,7 @@ static const int32 boot_rom[] = { t_stat dsk_boot (int32 unitno, DEVICE *dptr) { -int32 i; +size_t i; for (i = 0; i < BOOT_LEN; i++) M[BOOT_START + i] = (uint16) boot_rom[i]; saved_PC = BOOT_START; diff --git a/NOVA/nova_mta.c b/NOVA/nova_mta.c index 787c37ab..2305e770 100644 --- a/NOVA/nova_mta.c +++ b/NOVA/nova_mta.c @@ -139,22 +139,22 @@ #define STA_PEM 0000001 /* *PE mode */ #define STA_EFLGS1 (STA_DLT | STA_ILL | STA_DAE | STA_EOT | \ - STA_EOF | STA_BOT | STA_BAT | STA_ODD) + STA_EOF | STA_BOT | STA_BAT | STA_ODD) #define STA_EFLGS2 (STA_FGP | STA_CDL | STA_BDS | STA_OVS | \ - STA_CRC | STA_FPR | STA_FPR) /* set error 2 */ + STA_CRC | STA_FPR | STA_FPR) /* set error 2 */ #define STA_CLR ((020 << 16) | 0010000) /* always clear */ #define STA_SET (STA_HDN | STA_9TK) /* always set */ #define STA_DYN (STA_REW | STA_EOT | STA_EOF | STA_BOT | \ - STA_WLK | STA_RDY | STA_PEM) /* kept in USTAT */ + STA_WLK | STA_RDY | STA_PEM) /* kept in USTAT */ #define STA_MON (STA_REW | STA_BOT | STA_WLK | STA_RDY | \ - STA_PEM) /* set status chg */ + STA_PEM) /* set status chg */ -extern uint16 M[]; -extern UNIT cpu_unit; -extern int32 int_req, dev_busy, dev_done, dev_disable; -extern int32 SR, AMASK; +extern uint16 M[]; +extern UNIT cpu_unit; +extern int32 int_req, dev_busy, dev_done, dev_disable; +extern int32 SR, AMASK; -extern t_stat cpu_boot(int32 unitno, DEVICE * dptr ) ; +extern t_stat cpu_boot(int32 unitno, DEVICE * dptr ) ; int32 mta_ma = 0; /* memory address */ @@ -236,7 +236,7 @@ DEVICE mta_dev = { MTA_NUMDR, 10, 31, 1, 8, 8, NULL, NULL, &mta_reset, &mta_boot, &mta_attach, &mta_detach, - &mta_dib, DEV_DISABLE + &mta_dib, DEV_DISABLE | DEV_TAPE }; /* IOT routine */ @@ -363,9 +363,9 @@ if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */ } else switch (c) { /* case on command */ - case CU_CMODE: /* controller mode */ - mta_ep = mta_cu & CU_EP; - break; + case CU_CMODE: /* controller mode */ + mta_ep = mta_cu & CU_EP; + break; case CU_DMODE: /* drive mode */ if (!sim_tape_bot (uptr)) /* must be BOT */ @@ -412,7 +412,7 @@ else switch (c) { /* case on command */ mtxb[p++] = M[pa] & 0377; mta_ma = (mta_ma + 1) & AMASK; } - if (st = sim_tape_wrrecf (uptr, mtxb, tbc)) { /* write rec, err? */ + if ((st = sim_tape_wrrecf (uptr, mtxb, tbc))) { /* write rec, err? */ r = mta_map_err (uptr, st); /* map error */ mta_ma = (mta_ma - wc) & AMASK; /* restore wc */ } @@ -421,7 +421,7 @@ else switch (c) { /* case on command */ break; case CU_WREOF: /* write eof */ - if (st = sim_tape_wrtmk (uptr)) /* write tmk, err? */ + if ((st = sim_tape_wrtmk (uptr))) /* write tmk, err? */ r = mta_map_err (uptr, st); /* map error */ else mta_upddsta (uptr, uptr->USTAT | STA_EOF | STA_RDY); break; @@ -435,7 +435,7 @@ else switch (c) { /* case on command */ case CU_SPACEF: /* space forward */ do { mta_wc = (mta_wc + 1) & DMASK; /* incr wc */ - if (st = sim_tape_sprecf (uptr, &tbc)) { /* space rec fwd, err? */ + if ((st = sim_tape_sprecf (uptr, &tbc))) { /* space rec fwd, err? */ r = mta_map_err (uptr, st); /* map error */ break; } @@ -447,7 +447,7 @@ else switch (c) { /* case on command */ case CU_SPACER: /* space reverse */ do { mta_wc = (mta_wc + 1) & DMASK; /* incr wc */ - if (st = sim_tape_sprecr (uptr, &tbc)) { /* space rec rev, err? */ + if ((st = sim_tape_sprecr (uptr, &tbc))) { /* space rec rev, err? */ r = mta_map_err (uptr, st); /* map error */ break; } @@ -493,10 +493,10 @@ if ((uptr->flags & UNIT_ATT) == 0) /* offline? */ change = (uptr->USTAT ^ newsta) & STA_MON; /* changes? */ uptr->USTAT = newsta & STA_DYN; /* update status */ if (change) { -/* if (mta_ep) { /* if polling */ -/* u = uptr - mta_dev.units; /* unit num */ -/* mta_sta = (mta_sta & ~STA_UNIT) | (u << STA_V_UNIT); -/* set polling interupt... +/* if (mta_ep) { *//* if polling */ +/* u = uptr - mta_dev.units; *//* unit num */ +/* mta_sta = (mta_sta & ~STA_UNIT) | (u << STA_V_UNIT); */ +/* set polling interupt... */ /* } */ mta_sta = mta_sta | STA_CHG; /* flag change */ } @@ -577,9 +577,9 @@ for (u = 0; u < MTA_NUMDR; u++) { /* loop thru units */ sim_tape_reset (uptr); /* clear pos flag */ sim_cancel (uptr); /* cancel activity */ if (uptr->flags & UNIT_ATT) uptr->USTAT = STA_RDY | - (uptr->USTAT & STA_PEM) | - (sim_tape_wrp (uptr)? STA_WLK: 0) | - (sim_tape_bot (uptr)? STA_BOT: 0); + (uptr->USTAT & STA_PEM) | + (sim_tape_wrp (uptr)? STA_WLK: 0) | + (sim_tape_bot (uptr)? STA_BOT: 0); else uptr->USTAT = 0; } mta_updcsta (&mta_unit[0]); /* update status */ @@ -629,17 +629,17 @@ return SCPE_OK; /* Boot routine */ t_stat mta_boot (int32 unitno, DEVICE *dptr) - { - sim_tape_rewind( &mta_unit[unitno] ) ; - /* - use common rewind/reset code - device reset - rewind 'tape' file - device - unit - controller - */ - cpu_boot( unitno, dptr ) ; - SR = 0100000 + DEV_MTA ; - return ( SCPE_OK ); - } /* end of 'mta_boot' */ + { + sim_tape_rewind( &mta_unit[unitno] ) ; + /* + use common rewind/reset code + device reset + rewind 'tape' file + device + unit + controller + */ + cpu_boot( unitno, dptr ) ; + SR = 0100000 + DEV_MTA ; + return ( SCPE_OK ); + } /* end of 'mta_boot' */ diff --git a/NOVA/nova_plt.c b/NOVA/nova_plt.c index 9375e182..d24d6a97 100644 --- a/NOVA/nova_plt.c +++ b/NOVA/nova_plt.c @@ -54,7 +54,7 @@ t_stat plt_svc (UNIT *uptr); t_stat plt_reset (DEVICE *dptr); - /* 7 or 8 bit data mask support for either device */ +/* 7 or 8 bit data mask support for either device */ #define UNIT_V_8B (UNIT_V_UF + 0) /* 8b output */ #define UNIT_8B (1 << UNIT_V_8B) diff --git a/NOVA/nova_pt.c b/NOVA/nova_pt.c index 2d7dff4b..c4517edb 100644 --- a/NOVA/nova_pt.c +++ b/NOVA/nova_pt.c @@ -1,6 +1,6 @@ /* nova_pt.c: NOVA paper tape read/punch simulator - Copyright (c) 1993-2008, Robert M. Supnik + Copyright (c) 1993-2015, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -26,6 +26,7 @@ ptr paper tape reader ptp paper tape punch + 28-Mar-15 RMS Revised to use sim_printf 04-Jul-07 BKR added PTR and PTP device DISABLE capability, added 7B/8B support PTR and PTP (default is 8B), DEV_SET/CLR macros now used, @@ -45,10 +46,10 @@ Notes: #include "nova_defs.h" -extern int32 int_req, dev_busy, dev_done, dev_disable ; -extern int32 SR ; +extern int32 int_req, dev_busy, dev_done, dev_disable ; +extern int32 SR ; -extern t_stat cpu_boot(int32 unitno, DEVICE * dptr ) ; +extern t_stat cpu_boot(int32 unitno, DEVICE * dptr ) ; int32 ptr_stopioe = 0, ptp_stopioe = 0; /* stop on error */ @@ -62,7 +63,7 @@ t_stat ptp_reset (DEVICE *dptr); t_stat ptr_boot (int32 unitno, DEVICE *dptr); - /* 7 or 8 bit data mask support for either device */ +/* 7 or 8 bit data mask support for either device */ #define UNIT_V_8B (UNIT_V_UF + 0) /* 8b output */ #define UNIT_8B (1 << UNIT_V_8B) @@ -193,7 +194,7 @@ if ((ptr_unit.flags & UNIT_ATT) == 0) /* attached? */ if ((temp = getc (ptr_unit.fileref)) == EOF) { /* end of file? */ if (feof (ptr_unit.fileref)) { if (ptr_stopioe) - printf ("PTR end of file\n"); + sim_printf ("PTR end of file\n"); else return SCPE_OK; } else perror ("PTR I/O error"); diff --git a/NOVA/nova_qty.c b/NOVA/nova_qty.c index 1e5f3c1f..5e03e74a 100644 --- a/NOVA/nova_qty.c +++ b/NOVA/nova_qty.c @@ -1,6 +1,6 @@ /* nova_qty.c: NOVA multiplexor (QTY/ALM) simulator - Copyright (c) 2000-2013, Robert M. Supnik + Copyright (c) 2000-2015, Robert M. Supnik Written by Bruce Ray and used with his gracious permission. Permission is hereby granted, free of charge, to any person obtaining a @@ -26,6 +26,7 @@ qty multiplexor: QTY = 4060, ALM = 42xx + 28-Mar-15 RMS Revised to use sim_printf 14-Mar-12 RMS Fixed dangling else clauses 04-Jul-07 BKR Fixed QTY output line number calculation (affected higher line numbers), 25-Mar-04 RMS Updated for V3.2 @@ -106,8 +107,6 @@ extern int32 int_req, dev_busy, dev_done, dev_disable ; -extern int32 sim_switches ; -extern FILE * sim_log ; extern int32 tmxr_poll ; /* calibrated delay */ t_stat qty_setnl ( UNIT * uptr, int32 val, char * cptr, void * desc ) ; @@ -136,7 +135,7 @@ int32 qty_auto = 0 ; /* QTY auto disconnect int32 qty_polls = 0 ; /* total 'qty_svc' polls */ -TMLN qty_ldsc[ QTY_MAX ] = { 0 } ; /* QTY line descriptors */ +TMLN qty_ldsc[ QTY_MAX ] = { {0} } ; /* QTY line descriptors */ TMXR qty_desc = { QTY_MAX, 0, 0, qty_ldsc } ; /* mux descriptor */ int32 qty_status[ QTY_MAX ] = { 0 } ; /* QTY line status */ /* (must be at least 32 bits) */ @@ -194,7 +193,7 @@ DEVICE qty_dev = 1, 10, 31, 1, 8, 8, NULL, NULL, &qty_reset, NULL, &qty_attach, &qty_detach, - &qty_dib, (DEV_DISABLE | DEV_DIS | DEV_NET) + &qty_dib, (DEV_DISABLE | DEV_DIS | DEV_MUX) }; #define DG_RETURN( status, data ) (int32)(((status) << IOT_V_REASON) | ((data) & 0x0FFFF) ) @@ -223,7 +222,7 @@ DEVICE qty_dev = #define QTY_LINE_RX_CHAR( line ) (qty_status[ (line) ] & QTY_S_DMASK) #define QTY_UNIT_ACTIVE( unitp ) ( (unitp)->conn ) -#define QTY_LINE_BITS( line, bits ) qty_status[ (line) ] & bits +#define QTY_LINE_BITS( line, bits ) (qty_status[ (line) ] & bits) #define QTY_LINE_SET_BIT( line, bit ) qty_status[ (line) ] |= (bit) ; #define QTY_LINE_CLEAR_BIT( line, bit ) qty_status[ (line) ] &= ~(bit) ; @@ -492,13 +491,11 @@ t_stat qty_attach( UNIT * unitp, char * cptr ) if ( sim_switches & SWMASK('M') ) /* modem control? */ { qty_mdm = 1; - printf( "Modem control activated\n" ) ; - if ( sim_log ) fprintf( sim_log, "Modem control activated\n" ) ; + sim_printf( "Modem control activated\n" ) ; if ( sim_switches & SWMASK ('A') ) /* autodisconnect? */ { qty_auto = 1 ; - printf( "Auto disconnect activated\n" ) ; - if ( sim_log ) fprintf( sim_log, "Auto disconnect activated\n" ) ; + sim_printf( "Auto disconnect activated\n" ) ; } } qty_polls = 0 ; @@ -608,14 +605,17 @@ t_stat qty_common_svc( DIB * dibp, UNIT * unitp ) { if ( newln >= qty_max ) { - return SCPE_IERR; /* WTF - sanity check failed, over? */ + return SCPE_IERR; /* WTF - sanity check failed, over? */ + } + else + { + line = newln ; /* handle modem control */ + tmlnp =&qty_ldsc[ line ] ; + tmlnp->rcve = tmlnp->xmte = 1 ; + /* do QTY_LINE_ bit fiddling and state machine + * manipulation with modem control signals + */ } - line = newln ; /* handle modem control */ - tmlnp =&qty_ldsc[ line ] ; - tmlnp->rcve = tmlnp->xmte = 1 ; - /* do QTY_LINE_ bit fiddling and state machine - * manipulation with modem control signals - */ } tmxr_poll_rx( &qty_desc ) ; /* poll input */ diff --git a/NOVA/nova_sys.c b/NOVA/nova_sys.c index 36a4cf22..716300ba 100644 --- a/NOVA/nova_sys.c +++ b/NOVA/nova_sys.c @@ -79,9 +79,6 @@ extern int32 MapStat; #endif -extern int32 sim_switches; - - /* SCP data structures sim_name simulator name string @@ -179,11 +176,11 @@ internal state machine: t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag) { -int32 data, csum, count, state, i; -int32 origin; -int pos ; -int block_start ; -int done ; +int32 data, csum, count, state, i; +int32 origin; +int pos ; +int block_start ; +int done ; if ((*cptr != 0) || (flag != 0)) return ( SCPE_ARG ) ; @@ -226,11 +223,11 @@ for ( pos = 0 ; (! done) && ((i=getc(fileref)) != EOF) ; ++pos ) /* do any auto-start check or inhibit check */ saved_PC = (origin & 077777) ; /* 0B0 = auto-start program */ /* 1B0 = do not auto start */ - state = 0 ; /* indicate okay state */ - done = 1 ; /* we're done! */ + state = 0 ; /* indicate okay state */ + done = 1 ; /* we're done! */ if ( ! (origin & 0x8000) ) { - printf( "auto start @ %05o \n", (origin & 0x7FFF) ) ; + sim_printf( "auto start @ %05o \n", (origin & 0x7FFF) ) ; } break ; } @@ -278,8 +275,8 @@ for ( pos = 0 ; (! done) && ((i=getc(fileref)) != EOF) ; ++pos ) if (count == 0) { if ( csum ) { - printf( "checksum error: block start at %d [0x%x] \n", block_start, block_start ) ; - printf( "calculated: 0%o [0x%4x]\n", csum, csum ) ; + sim_printf( "checksum error: block start at %d [0x%x] \n", block_start, block_start ) ; + sim_printf( "calculated: 0%o [0x%4x]\n", csum, csum ) ; if ( ! (sim_switches & SWMASK('I')) ) return SCPE_CSUM; } diff --git a/NOVA/nova_tt.c b/NOVA/nova_tt.c index 59491d5c..3d4e25aa 100644 --- a/NOVA/nova_tt.c +++ b/NOVA/nova_tt.c @@ -1,6 +1,6 @@ /* nova_tt.c: NOVA console terminal simulator - Copyright (c) 1993-2008, Robert M. Supnik + Copyright (c) 1993-2015, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -26,6 +26,7 @@ tti terminal input tto terminal output + 31-Mar-15 RMS Backported parity capability from GitHub master 04-Jul-07 BKR fixed Dasher CR/LF swap function in 'tti_svc()', DEV_SET/CLR macros now used, TTO device may now be DISABLED @@ -40,17 +41,15 @@ 31-May-01 RMS Added multiconsole support Notes: - - TTO output is always masked to 7 bits in this rev - TTO "Dasher" attribute sends '\b' to console instead of '\031' - TTO may be disabled - - TTI input is always masked to 7 bits in this rev - TTI "Dasher" attribute swaps and - TTI may not be disabled */ #include "nova_defs.h" -#define UNIT_V_DASHER (UNIT_V_UF + 0) /* Dasher mode */ +#define UNIT_V_DASHER (TTUF_V_UF) /* Dasher mode */ #define UNIT_DASHER (1 << UNIT_V_DASHER) extern int32 int_req, dev_busy, dev_done, dev_disable; @@ -62,6 +61,7 @@ t_stat tto_svc (UNIT *uptr); t_stat tti_reset (DEVICE *dptr); t_stat tto_reset (DEVICE *dptr); t_stat ttx_setmod (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat ttx_setpar (UNIT *uptr, int32 val, char *cptr, void *desc); /* TTI data structures @@ -89,6 +89,10 @@ REG tti_reg[] = { MTAB ttx_mod[] = { { UNIT_DASHER, 0, "ANSI", "ANSI", &ttx_setmod }, { UNIT_DASHER, UNIT_DASHER, "Dasher", "DASHER", &ttx_setmod }, + { TT_PAR, TT_PAR_EVEN, "even parity", "EVEN", &ttx_setpar }, + { TT_PAR, TT_PAR_ODD, "odd parity", "ODD", &ttx_setpar }, + { TT_PAR, TT_PAR_MARK, "mark parity", "MARK", &ttx_setpar }, + { TT_PAR, TT_PAR_SPACE, "no parity", "NONE", &ttx_setpar }, { 0 } } ; @@ -175,6 +179,7 @@ if (tti_unit.flags & UNIT_DASHER) { else if (tti_unit.buf == '\n') tti_unit.buf = '\r' ; /* Dasher: nl -> cr */ } +tti_unit.buf = sim_tt_inpcvt (tti_unit.buf, TT_GET_MODE (uptr->flags)); DEV_CLR_BUSY( INT_TTI ) ; DEV_SET_DONE( INT_TTI ) ; DEV_UPDATE_INTR ; @@ -260,3 +265,10 @@ tti_unit.flags = (tti_unit.flags & ~UNIT_DASHER) | val; tto_unit.flags = (tto_unit.flags & ~UNIT_DASHER) | val; return SCPE_OK; } + +t_stat ttx_setpar (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +tti_unit.flags = (tti_unit.flags & ~TT_PAR) | val; +tto_unit.flags = (tto_unit.flags & ~TT_PAR) | val; +return SCPE_OK; +} diff --git a/NOVA/nova_tt1.c b/NOVA/nova_tt1.c index 0b495651..5cb969b8 100644 --- a/NOVA/nova_tt1.c +++ b/NOVA/nova_tt1.c @@ -108,7 +108,7 @@ DEVICE tti1_dev = { 1, 10, 31, 1, 8, 8, &tmxr_ex, &tmxr_dep, &tti1_reset, NULL, &tti1_attach, &tti1_detach, - &tti1_dib, DEV_NET | DEV_DISABLE + &tti1_dib, DEV_MUX | DEV_DISABLE }; /* TTO1 data structures @@ -148,7 +148,7 @@ DEVICE tto1_dev = { 1, 10, 31, 1, 8, 8, NULL, NULL, &tto1_reset, NULL, NULL, NULL, - &tto1_dib, DEV_DISABLE + &tto1_dib, DEV_DISABLE | DEV_MUX }; /* Terminal input: IOT routine */ @@ -184,7 +184,7 @@ int32 temp, newln; if (tt1_ldsc.conn) { /* connected? */ tmxr_poll_rx (&tt_desc); /* poll for input */ - if (temp = tmxr_getc_ln (&tt1_ldsc)) { /* get char */ + if ((temp = tmxr_getc_ln (&tt1_ldsc))) { /* get char */ uptr->buf = temp & 0177; if ((uptr->flags & UNIT_DASHER) && (uptr->buf == '\r')) diff --git a/PDP1/pdp1_clk.c b/PDP1/pdp1_clk.c index 9e3914fd..94d4124a 100644 --- a/PDP1/pdp1_clk.c +++ b/PDP1/pdp1_clk.c @@ -89,7 +89,7 @@ int32 used, incr; if (clk_dev.flags & DEV_DIS) /* disabled? */ return (stop_inst << IOT_V_REASON) | dat; /* illegal inst */ -used = tmxr_poll - (sim_is_active (&clk_unit) - 1); +used = tmxr_poll - (sim_activate_time (&clk_unit) - 1); incr = (used * CLK_CNTS) / tmxr_poll; return clk_cntr + incr; } @@ -101,7 +101,7 @@ t_stat clk_svc (UNIT *uptr) if (clk_dev.flags & DEV_DIS) /* disabled? */ return SCPE_OK; tmxr_poll = sim_rtcn_calb (CLK_TPS, TMR_CLK); /* calibrate clock */ -sim_activate (&clk_unit, tmxr_poll); /* reactivate unit */ +sim_activate_after (uptr, 1000000/CLK_TPS); /* reactivate unit */ clk_cntr = clk_cntr + CLK_CNTS; /* incr counter */ if ((clk_cntr % CLK_C32MS) == 0) /* 32ms interval? */ dev_req_int (clk32ms_sbs); /* req intr */ @@ -118,6 +118,7 @@ t_stat clk_reset (DEVICE *dptr) { if (clk_dev.flags & DEV_DIS) sim_cancel (&clk_unit); /* disabled? */ else { + sim_register_clock_unit (&clk_unit); /* declare clock unit */ tmxr_poll = sim_rtcn_init (clk_unit.wait, TMR_CLK); sim_activate_abs (&clk_unit, tmxr_poll); /* activate unit */ } diff --git a/PDP1/pdp1_cpu.c b/PDP1/pdp1_cpu.c index 4e9920e4..2a9953bb 100644 --- a/PDP1/pdp1_cpu.c +++ b/PDP1/pdp1_cpu.c @@ -1,6 +1,6 @@ /* pdp1_cpu.c: PDP-1 CPU simulator - Copyright (c) 1993-2012, Robert M. Supnik + Copyright (c) 1993-2015, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,7 @@ cpu PDP-1 central processor + 27-Mar-15 RMS Backported changed from GitHub master 21-Mar-12 RMS Fixed & vs && in Ea_ch (Michael Bloom) 30-May-07 RMS Fixed typo in SBS clear (Norm Lastovica) 28-Dec-06 RMS Added 16-channel SBS support, PDP-1D support @@ -32,6 +33,7 @@ 22-Sep-05 RMS Fixed declarations (Sterling Garwood) 16-Aug-05 RMS Fixed C++ declaration and cast problems 09-Nov-04 RMS Added instruction history + 08-Feb-04 PLB Added display device spacewar/test switches 07-Sep-03 RMS Added additional explanation on I/O simulation 01-Sep-03 RMS Added address switches for hardware readin 23-Jul-03 RMS Revised to detect I/O wait hang @@ -335,10 +337,6 @@ int32 hst_p = 0; /* history pointer */ int32 hst_lnt = 0; /* history length */ InstHistory *hst = NULL; /* inst history */ -extern UNIT *sim_clock_queue; -extern int32 sim_int_char; -extern uint32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ - t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw); t_stat cpu_reset (DEVICE *dptr); @@ -364,6 +362,10 @@ extern int32 dt (int32 inst, int32 dev, int32 dat); extern int32 drm (int32 inst, int32 dev, int32 dat); extern int32 clk (int32 inst, int32 dev, int32 dat); extern int32 dcs (int32 inst, int32 dev, int32 dat); +#ifdef USE_DISPLAY +extern int32 dpy (int32 inst, int32 dev, int32 dat, int32 dat2); +extern int32 spacewar (int32 inst, int32 dev, int32 dat); +#endif const int32 sc_map[512] = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, /* 00000xxxx */ @@ -503,7 +505,6 @@ DEVICE cpu_dev = { t_stat sim_instr (void) { -extern int32 sim_interval; int32 IR, op, i, t, xct_count; int32 sign, signd, v, sbs_lvl, byno; int32 dev, pulse, io_data, sc, skip; @@ -546,7 +547,7 @@ reason = 0; while (reason == 0) { /* loop until halted */ if (sim_interval <= 0) { /* check clock queue */ - if (reason = sim_process_event ()) + if ((reason = sim_process_event ())) break; sbs_lvl = sbs_eval (); /* eval sbs system */ } @@ -610,25 +611,25 @@ while (reason == 0) { /* loop until halted */ /* Logical, load, store instructions */ case 001: /* AND */ - if (reason = Ea (IR)) /* MA <- eff addr */ + if ((reason = Ea (IR))) /* MA <- eff addr */ break; - if (reason = Read ()) /* MB <- data */ + if ((reason = Read ())) /* MB <- data */ break; AC = AC & MB; break; case 002: /* IOR */ - if (reason = Ea (IR)) /* MA <- eff addr */ + if ((reason = Ea (IR))) /* MA <- eff addr */ break; - if (reason = Read ()) /* MB <- data */ + if ((reason = Read ())) /* MB <- data */ break; AC = AC | MB; break; case 003: /* XOR */ - if (reason = Ea (IR)) /* MA <- eff addr */ + if ((reason = Ea (IR))) /* MA <- eff addr */ break; - if (reason = Read ()) /* MB <- data */ + if ((reason = Read ())) /* MB <- data */ break; AC = AC ^ MB; break; @@ -638,9 +639,9 @@ while (reason == 0) { /* loop until halted */ reason = STOP_XCT; break; } - if (reason = Ea (IR)) /* MA <- eff addr */ + if ((reason = Ea (IR))) /* MA <- eff addr */ break; - if (reason = Read ()) /* MB <- data */ + if ((reason = Read ())) /* MB <- data */ break; xct_count = xct_count + 1; /* count XCT's */ IR = MB; /* get instruction */ @@ -648,9 +649,9 @@ while (reason == 0) { /* loop until halted */ case 005: /* LCH */ if (cpu_unit.flags & UNIT_1D) { /* PDP-1D? */ - if (reason = Ea_ch (IR, &byno)) /* MA <- eff addr */ + if ((reason = Ea_ch (IR, &byno))) /* MA <- eff addr */ break; - if (reason = Read ()) /* MB <- data */ + if ((reason = Read ())) /* MB <- data */ break; AC = (MB << byt_shf[byno]) & 0770000; /* extract byte */ } @@ -659,9 +660,9 @@ while (reason == 0) { /* loop until halted */ case 006: /* DCH */ if (cpu_unit.flags & UNIT_1D) { /* PDP-1D? */ - if (reason = Ea_ch (IR, &byno)) /* MA <- eff addr */ + if ((reason = Ea_ch (IR, &byno))) /* MA <- eff addr */ break; - if (reason = Read ()) /* MB <- data */ + if ((reason = Read ())) /* MB <- data */ break; MB = (MB & ~(0770000 >> byt_shf[byno])) | /* insert byte */ ((AC & 0770000) >> byt_shf[byno]); @@ -683,55 +684,55 @@ while (reason == 0) { /* loop until halted */ break; case 010: /* LAC */ - if (reason = Ea (IR)) /* MA <- eff addr */ + if ((reason = Ea (IR))) /* MA <- eff addr */ break; - if (reason = Read ()) /* MB <- data */ + if ((reason = Read ())) /* MB <- data */ break; AC = MB; break; case 011: /* LIO */ - if (reason = Ea (IR)) /* MA <- eff addr */ + if ((reason = Ea (IR))) /* MA <- eff addr */ break; - if (reason = Read ()) /* MB <- data */ + if ((reason = Read ())) /* MB <- data */ break; IO = MB; break; case 012: /* DAC */ - if (reason = Ea (IR)) /* MA <- eff addr */ + if ((reason = Ea (IR))) /* MA <- eff addr */ break; MB = AC; reason = Write (); break; case 013: /* DAP */ - if (reason = Ea (IR)) /* MA <- eff addr */ + if ((reason = Ea (IR))) /* MA <- eff addr */ break; - if (reason = Read ()) /* MB <- data */ + if ((reason = Read ())) /* MB <- data */ break; MB = (AC & DAMASK) | (MB & ~DAMASK); reason = Write (); break; case 014: /* DIP */ - if (reason = Ea (IR)) /* MA <- eff addr */ + if ((reason = Ea (IR))) /* MA <- eff addr */ break; - if (reason = Read ()) /* MB <- data */ + if ((reason = Read ())) /* MB <- data */ break; MB = (AC & ~DAMASK) | (MB & DAMASK); reason = Write (); break; case 015: /* DIO */ - if (reason = Ea (IR)) /* MA <- eff addr */ + if ((reason = Ea (IR))) /* MA <- eff addr */ break; MB = IO; reason = Write (); break; case 016: /* DZM */ - if (reason = Ea (IR)) /* MA <- eff addr */ + if ((reason = Ea (IR))) /* MA <- eff addr */ break; MB = 0; reason = Write (); @@ -755,9 +756,9 @@ while (reason == 0) { /* loop until halted */ case 017: /* TAD */ if (cpu_unit.flags & UNIT_1D) { /* PDP-1D? */ - if (reason = Ea (IR)) /* MA <- eff addr */ + if ((reason = Ea (IR))) /* MA <- eff addr */ break; - if (reason = Read ()) /* MB <- data */ + if ((reason = Read ())) /* MB <- data */ break; AC = AC + MB + ((PF & PF_L)? 1: 0); /* AC + opnd + L */ if (AC > DMASK) /* carry? set L */ @@ -769,9 +770,9 @@ while (reason == 0) { /* loop until halted */ break; case 020: /* ADD */ - if (reason = Ea (IR)) /* MA <- eff addr */ + if ((reason = Ea (IR))) /* MA <- eff addr */ break; - if (reason = Read ()) /* MB <- data */ + if ((reason = Read ())) /* MB <- data */ break; t = AC; AC = AC + MB; @@ -784,9 +785,9 @@ while (reason == 0) { /* loop until halted */ break; case 021: /* SUB */ - if (reason = Ea (IR)) /* MA <- eff addr */ + if ((reason = Ea (IR))) /* MA <- eff addr */ break; - if (reason = Read ()) /* MB <- data */ + if ((reason = Read ())) /* MB <- data */ break; t = AC ^ DMASK; /* complement AC */ AC = t + MB; /* -AC + MB */ @@ -798,9 +799,9 @@ while (reason == 0) { /* loop until halted */ break; case 022: /* IDX */ - if (reason = Ea (IR)) /* MA <- eff addr */ + if ((reason = Ea (IR))) /* MA <- eff addr */ break; - if (reason = Read ()) /* MB <- data */ + if ((reason = Read ())) /* MB <- data */ break; AC = MB + 1; if (AC >= DMASK) @@ -810,9 +811,9 @@ while (reason == 0) { /* loop until halted */ break; case 023: /* ISP */ - if (reason = Ea (IR)) /* MA <- eff addr */ + if ((reason = Ea (IR))) /* MA <- eff addr */ break; - if (reason = Read ()) /* MB <- data */ + if ((reason = Read ())) /* MB <- data */ break; AC = MB + 1; if (AC >= DMASK) @@ -824,18 +825,18 @@ while (reason == 0) { /* loop until halted */ break; case 024: /* SAD */ - if (reason = Ea (IR)) /* MA <- eff addr */ + if ((reason = Ea (IR))) /* MA <- eff addr */ break; - if (reason = Read ()) /* MB <- data */ + if ((reason = Read ())) /* MB <- data */ break; if (AC != MB) PC = INCR_ADDR (PC); break; case 025: /* SAS */ - if (reason = Ea (IR)) /* MA <- eff addr */ + if ((reason = Ea (IR))) /* MA <- eff addr */ break; - if (reason = Read ()) /* MB <- data */ + if ((reason = Read ())) /* MB <- data */ break; if (AC == MB) PC = INCR_ADDR (PC); @@ -863,7 +864,7 @@ while (reason == 0) { /* loop until halted */ hst[hst_p].ea = PC; } else { /* normal JMP */ - if (reason = Ea (IR)) /* MA <- eff addr */ + if ((reason = Ea (IR))) /* MA <- eff addr */ break; PCQ_ENTRY; PC = MA; @@ -871,7 +872,7 @@ while (reason == 0) { /* loop until halted */ break; case 031: /* JSP */ - if (reason = Ea (IR)) /* MA <- eff addr */ + if ((reason = Ea (IR))) /* MA <- eff addr */ break; AC = EPC_WORD; PCQ_ENTRY; @@ -889,9 +890,9 @@ while (reason == 0) { /* loop until halted */ */ case 026: /* MUL */ - if (reason = Ea (IR)) /* MA <- eff addr */ + if ((reason = Ea (IR))) /* MA <- eff addr */ break; - if (reason = Read ()) /* MB <- data */ + if ((reason = Read ())) /* MB <- data */ break; if (cpu_unit.flags & UNIT_MDV) { /* hardware? */ sign = AC ^ MB; /* result sign */ @@ -919,9 +920,9 @@ while (reason == 0) { /* loop until halted */ break; case 027: /* DIV */ - if (reason = Ea (IR)) /* MA <- eff addr */ + if ((reason = Ea (IR))) /* MA <- eff addr */ break; - if (reason = Read ()) /* MB <- data */ + if ((reason = Read ())) /* MB <- data */ break; if (cpu_unit.flags & UNIT_MDV) { /* hardware */ sign = AC ^ MB; /* result sign */ @@ -1208,6 +1209,11 @@ while (reason == 0) { /* loop until halted */ io_data = ptp (IR, dev, IO); break; +#ifdef USE_DISPLAY + case 007: /* display */ + io_data = dpy (IR, dev, IO, AC); + break; +#endif case 010: /* leave ring mode */ if (cpu_unit.flags & UNIT_1D) PF = PF & ~PF_RNG; @@ -1217,7 +1223,12 @@ while (reason == 0) { /* loop until halted */ case 011: /* enter ring mode */ if (cpu_unit.flags & UNIT_1D) PF = PF | PF_RNG; - else reason = stop_inst; + else +#ifdef USE_DISPLAY + io_data = spacewar (IR, dev, IO); +#else + reason = stop_inst; +#endif break; case 022: /* data comm sys */ @@ -1362,13 +1373,13 @@ t_stat r; MA = (PC & EPCMASK) | (IR & DAMASK); /* direct address */ if (IR & IA) { /* indirect addr? */ if (extm) { /* extend? */ - if (r = Read ()) /* read; err? */ + if ((r = Read ())) /* read; err? */ return r; MA = MB & AMASK; /* one level */ } else { /* multi-level */ for (i = 0; i < ind_max; i++) { /* count indirects */ - if (r = Read ()) /* get ind word */ + if ((r = Read ())) /* get ind word */ return r; MA = (PC & EPCMASK) | (MB & DAMASK); if ((MB & IA) == 0) @@ -1392,12 +1403,12 @@ t_stat r; MA = (PC & EPCMASK) | (IR & DAMASK); /* direct address */ if (extm) { /* extend? */ - if (r = Read ()) /* read; err? */ + if ((r = Read ())) /* read; err? */ return r; } else { /* multi-level */ for (i = 0; i < ind_max; i++) { /* count indirects */ - if (r = Read ()) /* get ind word */ + if ((r = Read ())) /* get ind word */ return r; if ((MB & IA) == 0) break; @@ -1596,7 +1607,7 @@ t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc) int32 mc = 0; uint32 i; -if ((val <= 0) || (val > MAXMEMSIZE) || ((val & 07777) != 0)) +if ((val <= 0) || (((size_t)val) > MAXMEMSIZE) || ((val & 07777) != 0)) return SCPE_ARG; for (i = val; i < MEMSIZE; i++) mc = mc | M[i]; @@ -1656,8 +1667,6 @@ char *cptr = (char *) desc; t_stat r; t_value sim_eval; InstHistory *h; -extern t_stat fprint_sym (FILE *ofile, t_addr addr, t_value *val, - UNIT *uptr, int32 sw); if (hst_lnt == 0) /* enabled? */ return SCPE_NOFNC; @@ -1692,3 +1701,18 @@ for (k = 0; k < lnt; k++) { /* print specified */ } /* end for */ return SCPE_OK; } + +#ifdef USE_DISPLAY +/* set "test switches"; from display code */ + +void cpu_set_switches(unsigned long bits) +{ +/* just what we want; smaller CPUs might want to shift down? */ +TW = bits; +} + +unsigned long cpu_get_switches(void) +{ +return TW; +} +#endif diff --git a/PDP1/pdp1_dcs.c b/PDP1/pdp1_dcs.c index 66de9e35..190477fb 100644 --- a/PDP1/pdp1_dcs.c +++ b/PDP1/pdp1_dcs.c @@ -49,7 +49,7 @@ uint8 dcs_buf[DCS_LINES]; /* line bufffers */ extern int32 iosta, stop_inst; extern int32 tmxr_poll; -TMLN dcs_ldsc[DCS_LINES] = { 0 }; /* line descriptors */ +TMLN dcs_ldsc[DCS_LINES] = { {0} }; /* line descriptors */ TMXR dcs_desc = { DCS_LINES, 0, 0, dcs_ldsc }; /* mux descriptor */ t_stat dcsi_svc (UNIT *uptr); @@ -102,7 +102,7 @@ DEVICE dcs_dev = { 1, 10, 31, 1, 8, 8, &tmxr_ex, &tmxr_dep, &dcs_reset, NULL, &dcs_attach, &dcs_detach, - NULL, DEV_NET | DEV_DISABLE | DEV_DIS + NULL, DEV_MUX | DEV_DISABLE | DEV_DIS }; /* DCSL data structures @@ -173,7 +173,7 @@ DEVICE dcsl_dev = { DCS_LINES, 10, 31, 1, 8, 8, NULL, NULL, &dcs_reset, NULL, NULL, NULL, - NULL, DEV_DIS + NULL, DEV_DIS | DEV_MUX }; /* DCS IOT routine */ @@ -252,7 +252,7 @@ if (ln >= 0) { /* got one? */ tmxr_poll_rx (&dcs_desc); /* poll for input */ for (ln = 0; ln < DCS_NUMLIN; ln++) { /* loop thru lines */ if (dcs_ldsc[ln].conn) { /* connected? */ - if (c = tmxr_getc_ln (&dcs_ldsc[ln])) { /* get char */ + if ((c = tmxr_getc_ln (&dcs_ldsc[ln]))) { /* get char */ if (c & SCPE_BREAK) /* break? */ c = 0; else c = sim_tt_inpcvt (c, TT_GET_MODE (dcsl_unit[ln].flags)|TTUF_KSR); diff --git a/PDP1/pdp1_defs.h b/PDP1/pdp1_defs.h index ed051342..5313bcee 100644 --- a/PDP1/pdp1_defs.h +++ b/PDP1/pdp1_defs.h @@ -49,8 +49,8 @@ Microtape (DECtape) control Type 550 */ -#ifndef _PDP1_DEFS_H_ -#define _PDP1_DEFS_H_ 0 +#ifndef PDP1_DEFS_H_ +#define PDP1_DEFS_H_ 0 #include "sim_defs.h" diff --git a/PDP1/pdp1_drm.c b/PDP1/pdp1_drm.c index aeaae3c6..1b9104ac 100644 --- a/PDP1/pdp1_drm.c +++ b/PDP1/pdp1_drm.c @@ -296,7 +296,7 @@ for (i = 0; i < DRM_NUMWDS; i++, da++) { /* do transfer */ if ((drm_wlk >> (drm_da >> 4)) & 1) drm_err = 1; else { /* not locked */ - fbuf[da] = M[drm_ma]; /* write word */ + fbuf[da] = M[drm_ma]; /* write word */ if (da >= uptr->hwmark) uptr->hwmark = da + 1; } diff --git a/PDP1/pdp1_dt.c b/PDP1/pdp1_dt.c index 2c902f62..f9bd69a5 100644 --- a/PDP1/pdp1_dt.c +++ b/PDP1/pdp1_dt.c @@ -1,6 +1,6 @@ /* pdp1_dt.c: 18b DECtape simulator - Copyright (c) 1993-2008, Robert M Supnik + Copyright (c) 1993-2015, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,7 @@ dt Type 550/555 DECtape + 28-Mar-15 RMS Revised to use sim_printf 21-Dec-06 RMS Added 16-channel SBS support 23-Jun-06 RMS Fixed conflict in ATTACH switches Revised header format @@ -250,9 +251,6 @@ extern int32 M[]; extern int32 stop_inst; extern UNIT cpu_unit; -extern int32 sim_switches; -extern int32 sim_is_running; -extern FILE *sim_deb; int32 dtsa = 0; /* status A */ int32 dtsb = 0; /* status B */ @@ -377,7 +375,7 @@ if (pulse == 003) { /* MSE */ dt_deselect (dtsa); dtsa = (dtsa & ~DTA_UNIT) | (dat & DTA_UNIT); dtsb = dtsb & ~(DTB_DTF | DTB_BEF | DTB_ERF | DTB_ALLERR); - } + } if (pulse == 004) { /* MLC */ dtsa = (dtsa & ~DTA_RW) | (dat & DTA_RW); /* load dtsa */ dtsb = dtsb & ~(DTB_DTF | DTB_BEF | DTB_ERF | DTB_ALLERR); @@ -619,7 +617,7 @@ switch (fnc) { /* case function */ if ((fnc == FNC_WRIT) || (fnc == FNC_WALL)) { /* write function? */ dtsb = dtsb | DTB_DTF; /* set data flag */ DT_UPDINT; - } + } sim_activate (uptr, ABS (newpos - ((int32) uptr->pos)) * dt_ltime); return; } @@ -681,13 +679,13 @@ if (mot & DTS_DIR) /* update pos */ else uptr->pos = uptr->pos + delta; if (((int32) uptr->pos < 0) || ((int32) uptr->pos > (DTU_FWDEZ (uptr) + DT_EZLIN))) { - detach_unit (uptr); /* off reel? */ - uptr->STATE = uptr->pos = 0; - unum = (int32) (uptr - dt_dev.units); - if (unum == DTA_GETUNIT (dtsa)) /* if selected, */ - dt_seterr (uptr, DTB_SEL); /* error */ - return TRUE; - } + detach_unit (uptr); /* off reel? */ + uptr->STATE = uptr->pos = 0; + unum = (int32) (uptr - dt_dev.units); + if (unum == DTA_GETUNIT (dtsa)) /* if selected, */ + dt_seterr (uptr, DTB_SEL); /* error */ + return TRUE; + } return FALSE; } @@ -1014,13 +1012,13 @@ if (uptr->filebuf == NULL) { /* can't alloc? */ return SCPE_MEM; } fbuf = (uint32 *) uptr->filebuf; /* file buffer */ -printf ("%s%d: ", sim_dname (&dt_dev), u); +sim_printf ("%s%d: ", sim_dname (&dt_dev), u); if (uptr->flags & UNIT_8FMT) - printf ("12b format"); + sim_printf ("12b format"); else if (uptr->flags & UNIT_11FMT) - printf ("16b format"); -else printf ("18b/36b format"); -printf (", buffering file in memory\n"); + sim_printf ("16b format"); +else sim_printf ("18b/36b format"); +sim_printf (", buffering file in memory\n"); if (uptr->flags & UNIT_8FMT) { /* 12b? */ for (ba = 0; ba < uptr->capac; ) { /* loop thru file */ k = fxread (pdp8b, sizeof (uint16), D8_NBSIZE, uptr->fileref); @@ -1081,12 +1079,12 @@ if (sim_is_active (uptr)) { if ((u == DTA_GETUNIT (dtsa)) && (dtsa & DTA_STSTP)) { dtsb = dtsb | DTB_ERF | DTB_SEL | DTB_DTF; DT_UPDINT; - } + } uptr->STATE = uptr->pos = 0; } fbuf = (uint32 *) uptr->filebuf; /* file buffer */ if (uptr->hwmark && ((uptr->flags & UNIT_RO) == 0)) { /* any data? */ - printf ("%s%d: writing buffer to file\n", sim_dname (&dt_dev), u); + sim_printf ("%s%d: writing buffer to file\n", sim_dname (&dt_dev), u); rewind (uptr->fileref); /* start of file */ if (uptr->flags & UNIT_8FMT) { /* 12b? */ for (ba = 0; ba < uptr->hwmark; ) { /* loop thru file */ diff --git a/PDP1/pdp1_lp.c b/PDP1/pdp1_lp.c index a4c49d16..ae5fe6c1 100644 --- a/PDP1/pdp1_lp.c +++ b/PDP1/pdp1_lp.c @@ -115,7 +115,7 @@ if ((inst & 07000) == 01000) { /* fill buf */ lpt_buf[i] = lpt_trans[(dat >> 12) & 077]; lpt_buf[i + 1] = lpt_trans[(dat >> 6) & 077]; lpt_buf[i + 2] = lpt_trans[dat & 077]; - } + } lpt_bptr = (lpt_bptr + 1) & BPTR_MASK; return dat; } diff --git a/PDP1/pdp1_stddev.c b/PDP1/pdp1_stddev.c index 1d1586dc..6c16d9b7 100644 --- a/PDP1/pdp1_stddev.c +++ b/PDP1/pdp1_stddev.c @@ -1,6 +1,6 @@ /* pdp1_stddev.c: PDP-1 standard devices - Copyright (c) 1993-2012, Robert M. Supnik + Copyright (c) 1993-2015, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -28,6 +28,7 @@ tti keyboard tto teleprinter + 28-Mar-15 RMS Revised to use sim_printf 21-Mar-12 RMS Fixed unitialized variable in tto_svc (Michael Bloom) 21-Dec-06 RMS Added 16-channel sequence break support 29-Oct-03 RMS Added PTR FIODEC-to-ASCII translation (Phil Budne) @@ -342,7 +343,7 @@ if (temp == EOF) { /* end of file? */ ptr_wait = ioh = 0; if (feof (uptr->fileref)) { if ((cpls & CPLS_PTR) || ptr_stopioe) - printf ("PTR end of file\n"); + sim_printf ("PTR end of file\n"); else return SCPE_OK; } else perror ("PTR I/O error"); diff --git a/PDP1/pdp1_sys.c b/PDP1/pdp1_sys.c index d8985cd9..e0be5725 100644 --- a/PDP1/pdp1_sys.c +++ b/PDP1/pdp1_sys.c @@ -1,6 +1,6 @@ /* pdp1_sys.c: PDP-1 simulator interface - Copyright (c) 1993-2008, Robert M. Supnik + Copyright (c) 1993-2015, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -23,6 +23,7 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 27-Mar-15 RMS Backported changes from GitHub master 03-Jan-07 RMS Fixed bugs in block loader, char input 21-Dec-06 RMS Added 16-channel sequence break support, PDP-1D support 06-Apr-04 RMS Fixed bug in binary loader (found by Mark Crispin) @@ -58,14 +59,15 @@ extern DEVICE dt_dev; extern DEVICE drm_dev; extern DEVICE drp_dev; extern DEVICE dcs_dev, dcsl_dev; +#if defined(USE_DISPLAY) extern DEVICE dpy_dev; +#endif extern UNIT cpu_unit; extern REG cpu_reg[]; extern int32 M[]; extern int32 PC; extern int32 ascii_to_fiodec[], fiodec_to_ascii[]; extern int32 sc_map[]; -extern int32 sim_switches; /* SCP data structures and interface routines @@ -96,7 +98,9 @@ DEVICE *sim_devices[] = { &drp_dev, &dcs_dev, &dcsl_dev, -/* &dpy_dev, */ +#if defined(USE_DISPLAY) + &dpy_dev, +#endif NULL }; diff --git a/PDP10/pdp10_cpu.c b/PDP10/pdp10_cpu.c index d5c9fc10..862bfcab 100644 --- a/PDP10/pdp10_cpu.c +++ b/PDP10/pdp10_cpu.c @@ -151,6 +151,10 @@ typedef struct { d10 ac; } InstHistory; +extern a10 fe_xct; /* Front-end forced XCT */ +extern DEVICE pag_dev; +extern t_stat pag_reset (DEVICE *dptr); + d10 *M = NULL; /* memory */ d10 acs[AC_NBLK * AC_NUM] = { 0 }; /* AC blocks */ d10 *ac_cur, *ac_prv; /* AC cur, prv (dyn) */ @@ -197,10 +201,7 @@ jmp_buf save_env; int32 hst_p = 0; /* history pointer */ int32 hst_lnt = 0; /* history length */ InstHistory *hst = NULL; /* instruction history */ - -extern int32 sim_int_char; -extern int32 sim_interval; -extern uint32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ +int32 apr_serial = -1; /* CPU Serial number */ /* Forward and external declarations */ @@ -209,6 +210,9 @@ t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw); t_stat cpu_reset (DEVICE *dptr); t_stat cpu_set_hist (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc); +t_stat cpu_set_serial (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat cpu_show_serial (FILE *st, UNIT *uptr, int32 val, void *desc); + d10 adjsp (d10 val, a10 ea); void ibp (a10 ea, int32 pflgs); d10 ldb (a10 ea, int32 pflgs); @@ -332,7 +336,7 @@ extern t_stat tim_set_mod (UNIT *uptr, int32 val, char *cptr, void *desc); cpu_mod CPU modifier list */ -UNIT cpu_unit = { UDATA (NULL, UNIT_FIX, MAXMEMSIZE) }; +UNIT cpu_unit = { UDATA (NULL, UNIT_FIX + UNIT_BINK, MAXMEMSIZE) }; REG cpu_reg[] = { { ORDATA (PC, saved_PC, VASIZE) }, @@ -404,6 +408,7 @@ MTAB cpu_mod[] = { NULL, &show_iospace }, { MTAB_XTD|MTAB_VDV|MTAB_NMO|MTAB_SHP, 0, "HISTORY", "HISTORY", &cpu_set_hist, &cpu_show_hist }, + { MTAB_XTD|MTAB_VDV, 0, "SERIAL", "SERIAL", &cpu_set_serial, &cpu_show_serial }, { 0 } }; @@ -432,16 +437,16 @@ const int32 pi_m2lvl[128] = { }; const d10 bytemask[64] = { 0, - 01, 03, 07, 017, 037, 077, - 0177, 0377, 0777, 01777, 03777, 07777, - 017777, 037777, 077777, - 0177777, 0377777, 0777777, - 01777777, 03777777, 07777777, - 017777777, 037777777, 077777777, - 0177777777, 0377777777, 0777777777, - 01777777777, 03777777777, 07777777777, - 017777777777, 037777777777, 077777777777, - 0177777777777, 0377777777777, 0777777777777, + INT64_C(01), INT64_C(03), INT64_C(07), INT64_C(017), INT64_C(037), INT64_C(077), + INT64_C(0177), INT64_C(0377), INT64_C(0777), INT64_C(01777), INT64_C(03777), INT64_C(07777), + INT64_C(017777), INT64_C(037777), INT64_C(077777), + INT64_C(0177777), INT64_C(0377777), INT64_C(0777777), + INT64_C(01777777), INT64_C(03777777), INT64_C(07777777), + INT64_C(017777777), INT64_C(037777777), INT64_C(077777777), + INT64_C(0177777777), INT64_C(0377777777), INT64_C(0777777777), + INT64_C(01777777777), INT64_C(03777777777), INT64_C(07777777777), + INT64_C(017777777777), INT64_C(037777777777), INT64_C(077777777777), + INT64_C(0177777777777), INT64_C(0377777777777), INT64_C(0777777777777), ONES, ONES, ONES, ONES, ONES, ONES, ONES, ONES, ONES, ONES, ONES, ONES, ONES, ONES, ONES, ONES, ONES, ONES, ONES, ONES, ONES, ONES, ONES, ONES, ONES, ONES, ONES @@ -620,6 +625,11 @@ static t_stat jrst_tab[16] = { #define POPF if (LRZ (AC(ac)) == RMASK) SETF (F_T2) #define DMOVNF if (rs[1] == 0) { MOVNF (rs[0]); } +t_value pdp10_pc_value (void) +{ +return (t_value)pager_PC; +} + t_stat sim_instr (void) { a10 PC; /* set by setjmp */ @@ -705,21 +715,56 @@ pager_tc = FALSE; /* not in trap cycle */ pflgs = 0; /* not in PXCT */ xct_cnt = 0; /* count XCT's */ if (sim_interval <= 0) { /* check clock queue */ - if (i = sim_process_event ()) /* error? stop sim */ + /* make sure all useful state is in simh registers while processing events */ + saved_PC = pager_PC & AMASK; /* failing instr PC */ + set_ac_display (ac_cur); /* set up AC display */ + pcq_r->qptr = pcq_p; /* update pc q ptr */ + + if ((i = sim_process_event ())) /* error? stop sim */ ABORT (i); + if (fe_xct) + qintr = -1; + else pi_eval (); /* eval pi system */ } /* PI interrupt (Unibus or system flags). On the KS10, only JSR and XPCW are allowed as interrupt instructions. Because of exec mode addressing, and unconditional processing of flags, - they are explicitly emulated here. + they are explicitly emulated here. Note that the KS microcode does not + perform an EA calc on interrupt instructions, which this emulation does. + This is an implementation restriction of the KS. The KS does not restrict + the CONSOLE EXECUTE function which is merged into this path in SimH. + + On a keep-alive failure, the console (fe) forces the CPU 'XCT' the + instruction at exec 71. This is close enough to an interrupt that it is + treated as one here. TOPS-10 and TOPS-20 use JSR or XPCW, which are + really the only sensible instructions, as diagnosing a KAF requires the + PC/FLAGS of the fault. + On a reload-request from the OS, the fe loads the bootstrap code and sets + saved_PC. Here, the CPU is partially reset and redirected. (Preserving + PC history, among other things.) The FE has already reset IO. */ if (qintr) { int32 vec, uba; pager_pi = TRUE; /* flag in pi seq */ - if (vec = pi_ub_vec (qintr, &uba)) { /* Unibus interrupt? */ + if (fe_xct) { /* Console forced execute? */ + qintr = 0; + if (fe_xct == 1) { /* Forced reload */ + PC = saved_PC; /* Bootstrap PC */ + pager_pi = FALSE; + ebr = ubr = 0; /* Exec mode, paging & PI off */ + pag_reset (&pag_dev); + pi_on = pi_enb = pi_act= pi_prq = + apr_enb = apr_flg = apr_lvl = its_1pr = 0; + rlog = 0; + set_newflags (0, FALSE); + fe_xct = 0; + continue; + } + inst = ReadE(fe_xct); /* Exec address of instruction */ + } else if ((vec = pi_ub_vec (qintr, &uba))) { /* Unibus interrupt? */ mb = ReadP (epta + EPT_UBIT + uba); /* get dispatch table */ if (mb == 0) /* invalid? stop */ ABORT (STOP_ZERINT); @@ -735,23 +780,35 @@ if (qintr) { its_1pr = 0; /* clear 1-proc */ } if (op == OP_JSR) { /* JSR? */ - ea = calc_ea (inst, MM_CUR); /* calc ea, cur mode */ - WriteE (ea, FLPC); /* save flags+PC, exec */ - JUMP (INCA (ea)); /* PC = ea + 1 */ + d10 flpc = FLPC; + set_newflags (0, FALSE); /* set new flags */ + ea = calc_ea (inst, MM_CUR); /* calc ea, cur mode */ + WriteE (ea, flpc); /* save flags+PC, exec */ + JUMP (INCA (ea)); /* PC = ea + 1 */ } else if ((op == OP_JRST) && (ac == AC_XPCW)) { /* XPCW? */ + d10 flz = XWD (flags, 0); + + set_newflags (0, FALSE); /* set exec flags */ ea = calc_ea (inst, MM_CUR); /* calc ea, cur mode */ - WriteE (ea, XWD (flags, 0)); /* write flags, exec */ + WriteE (ea, flz); /* write flags, exec */ WriteE (ADDA (ea, 1), PC); /* write PC, exec */ rs[0] = ReadE (ADDA (ea, 2)); /* read new flags */ rs[1] = ReadE (ADDA (ea, 3)); /* read new PC */ JUMP (rs[1]); /* set new PC */ set_newflags (rs[0], FALSE); /* set new flags */ } - else ABORT (STOP_ILLINT); /* invalid instr */ + else { + fe_xct = 0; + ABORT (STOP_ILLINT); /* invalid instr */ + } + if (fe_xct) + fe_xct = 0; + else { pi_act = pi_act | pi_l2bit[qintr]; /* set level active */ pi_eval (); /* eval pi system */ + } pager_pi = FALSE; /* end of sequence */ if (sim_interval) /* charge for instr */ sim_interval--; @@ -865,8 +922,8 @@ case 0037: Write (040, UUOWORD, MM_CUR); /* store op, ac, ea */ /* Floating point, bytes, multiple precision (0100 - 0177) */ -/* case 0100: MUUO /* UJEN */ -/* case 0101: MUUO /* unassigned */ +/* case 0100: MUUO *//* UJEN */ +/* case 0101: MUUO *//* unassigned */ case 0102: if (Q_ITS && !TSTF (F_USR)) { /* GFAD (KL), XCTRI (ITS) */ inst = Read (ea, MM_OPND); pflgs = pflgs | ac; @@ -879,10 +936,10 @@ case 0103: if (Q_ITS && !TSTF (F_USR)) { /* GFSB (KL), XCTR (ITS) goto XCT; } goto MUUO; -/* case 0104: MUUO /* JSYS (T20) */ +/* case 0104: MUUO *//* JSYS (T20) */ case 0105: AC(ac) = adjsp (AC(ac), ea); break; /* ADJSP */ -/* case 0106: MUUO /* GFMP (KL)*/ -/* case 0107: MUUO /* GFDV (KL) */ +/* case 0106: MUUO *//* GFMP (KL)*/ +/* case 0107: MUUO *//* GFDV (KL) */ case 0110: RD2; dfad (ac, rs, 0); break; /* DFAD */ case 0111: RD2; dfad (ac, rs, 1); break; /* DFSB */ case 0112: RD2; dfmp (ac, rs); break; /* DFMP */ @@ -909,8 +966,8 @@ case 0124: G2AC; WR2; break; /* DMOVEM */ case 0125: G2AC; DMOVN (rs); WR2; DMOVNF; break; /* DMOVNM */ case 0126: RD; fix (ac, mb, 1); break; /* FIXR */ case 0127: RD; AC(ac) = fltr (mb); break; /* FLTR */ -/* case 0130: MUUO /* UFA */ -/* case 0131: MUUO /* DFN */ +/* case 0130: MUUO *//* UFA */ +/* case 0131: MUUO *//* DFN */ case 0132: AC(ac) = fsc (AC(ac), ea); break; /* FSC */ case 0133: if (!ac) /* IBP */ ibp (ea, pflgs); @@ -920,7 +977,7 @@ case 0135: LDB; break; /* LDB */ case 0136: CIBP; DPB; CLRF (F_FPD); break; /* IDBP */ case 0137: DPB; break; /* DPB */ case 0140: RD; AC(ac) = FAD (mb); break; /* FAD */ -/* case 0141: MUUO /* FADL */ +/* case 0141: MUUO *//* FADL */ case 0142: RM; mb = FAD (mb); WR; break; /* FADM */ case 0143: RM; AC(ac) = FAD (mb); WRAC; break; /* FADB */ case 0144: RD; AC(ac) = FADR (mb); break; /* FADR */ @@ -928,7 +985,7 @@ case 0145: AC(ac) = FADR (IMS); break; /* FADRI */ case 0146: RM; mb = FADR (mb); WR; break; /* FADRM */ case 0147: RM; AC(ac) = FADR (mb); WRAC; break; /* FADRB */ case 0150: RD; AC(ac) = FSB (mb); break; /* FSB */ -/* case 0151: MUUO /* FSBL */ +/* case 0151: MUUO *//* FSBL */ case 0152: RM; mb = FSB (mb); WR; break; /* FSBM */ case 0153: RM; AC(ac) = FSB (mb); WRAC; break; /* FSBB */ case 0154: RD; AC(ac) = FSBR (mb); break; /* FSBR */ @@ -936,7 +993,7 @@ case 0155: AC(ac) = FSBR (IMS); break; /* FSBRI */ case 0156: RM; mb = FSBR (mb); WR; break; /* FSBRM */ case 0157: RM; AC(ac) = FSBR (mb); WRAC; break; /* FSBRB */ case 0160: RD; AC(ac) = FMP (mb); break; /* FMP */ -/* case 0161: MUUO /* FMPL */ +/* case 0161: MUUO *//* FMPL */ case 0162: RM; mb = FMP (mb); WR; break; /* FMPM */ case 0163: RM; AC(ac) = FMP (mb); WRAC; break; /* FMPB */ case 0164: RD; AC(ac) = FMPR (mb); break; /* FMPR */ @@ -944,7 +1001,7 @@ case 0165: AC(ac) = FMPR (IMS); break; /* FMPRI */ case 0166: RM; mb = FMPR (mb); WR; break; /* FMPRM */ case 0167: RM; AC(ac) = FMPR (mb); WRAC; break; /* FMPRB */ case 0170: RD; if (FDV (mb)) S1AC; break; /* FDV */ -/* case 0171: MUUO /* FDVL */ +/* case 0171: MUUO *//* FDVL */ case 0172: RM; if (FDV (mb)) WR1; break; /* FDVM */ case 0173: RM; if (FDV (mb)) { S1AC; WRAC; } break; /* FDVB */ case 0174: RD; if (FDVR (mb)) S1AC; break; /* FDVR */ @@ -1008,7 +1065,7 @@ case 0250: RM; WRAC; AC(ac) = mb; break; /* EXCH */ case 0251: blt (ac, ea, pflgs); break; /* BLT */ case 0252: AOBAC; if (TGE (AC(ac))) JUMP (ea); break; /* AOBJP */ case 0253: AOBAC; if (TL (AC(ac))) JUMP (ea); break; /* AOBJN */ -/* case 0254: /* shown later /* JRST */ +/* case 0254: *//* shown later *//* JRST */ case 0255: if (flags & (ac << 14)) { /* JFCL */ JUMP (ea); CLRF (ac << 14); @@ -1972,10 +2029,10 @@ return; /* I/O block transfers - byte to Unibus (0) and Unibus to byte (1) */ -#define BYTE1 0776000000000 -#define BYTE2 0001774000000 -#define BYTE3 0000003770000 -#define BYTE4 0000000007760 +#define BYTE1 INT64_C(0776000000000) +#define BYTE2 INT64_C(0001774000000) +#define BYTE3 INT64_C(0000003770000) +#define BYTE4 INT64_C(0000000007760) /* unused 0000000000017 */ void bltu (int32 ac, a10 ea, int32 pflgs, int dir) @@ -2019,7 +2076,7 @@ int32 test_int (void) int32 t; if (sim_interval <= 0) { /* check queue */ - if (t = sim_process_event ()) /* IO event? */ + if ((t = sim_process_event ())) /* IO event? */ return t; if (pi_eval ()) /* interrupt? */ return (INTERRUPT); @@ -2108,7 +2165,14 @@ return; t_bool aprid (a10 ea, int32 prv) { -Write (ea, (Q_ITS)? UC_AIDITS: UC_AIDDEC, prv); +d10 value = (Q_ITS)? UC_AIDITS: UC_AIDDEC; + +if( (apr_serial == -1) || (!Q_ITS && apr_serial < 4096) ) + value |= (Q_ITS)? UC_SERITS: UC_SERDEC; +else + value |= apr_serial; + +Write (ea, value, prv); return FALSE; } @@ -2341,7 +2405,6 @@ return SCPE_OK; void set_ac_display (d10 *acbase) { -extern REG *find_reg (char *cptr, char **optr, DEVICE *dptr); REG *rptr; int i; @@ -2393,8 +2456,6 @@ char *cptr = (char *) desc; t_stat r; t_value sim_eval; InstHistory *h; -extern t_stat fprint_sym (FILE *ofile, t_addr addr, t_value *val, - UNIT *uptr, int32 sw); if (hst_lnt == 0) /* enabled? */ return SCPE_NOFNC; @@ -2425,3 +2486,34 @@ for (k = 0; k < lnt; k++) { /* print specified */ } /* end for */ return SCPE_OK; } + +/* Set serial */ + +t_stat cpu_set_serial (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +int32 lnt; +t_stat r; + +if (cptr == NULL) { + apr_serial = -1; + return SCPE_OK; + } +lnt = (int32) get_uint (cptr, 10, 077777, &r); +if ((r != SCPE_OK) || (lnt <= 0) || (!Q_ITS && lnt < 4096)) + return SCPE_ARG; +apr_serial = lnt & 077777; +return SCPE_OK; +} + +/* Show serial */ + +t_stat cpu_show_serial (FILE *st, UNIT *uptr, int32 val, void *desc) +{ +fprintf (st, "Serial: " ); +if( (apr_serial == -1) || (!Q_ITS && apr_serial < 4096) ) { + fprintf (st, "%d (default)", (Q_ITS)? UC_SERITS: UC_SERDEC); + return SCPE_OK; + } +fprintf (st, "%d", apr_serial); +return SCPE_OK; +} diff --git a/PDP10/pdp10_defs.h b/PDP10/pdp10_defs.h index 86d72ecd..d76ccd31 100644 --- a/PDP10/pdp10_defs.h +++ b/PDP10/pdp10_defs.h @@ -42,8 +42,8 @@ 19-May-01 RMS Added workaround for TOPS-20 V4.1 boot bug */ -#ifndef _PDP10_DEFS_H_ -#define _PDP10_DEFS_H_ 0 +#ifndef PDP10_DEFS_H_ +#define PDP10_DEFS_H_ 0 #ifndef VM_PDP10 #define VM_PDP10 0 @@ -115,7 +115,9 @@ typedef t_int64 d10; /* PDP-10 data (36b) */ #define STOP_XCT 9 /* XCT loop */ #define STOP_ILLIOC 10 /* invalid UBA num */ #define STOP_ASTOP 11 /* address stop */ -#define STOP_UNKNOWN 12 /* unknown stop */ +#define STOP_CONSOLE 12 /* FE halt */ +#define STOP_IOALIGN 13 /* DMA word access to odd address */ +#define STOP_UNKNOWN 14 /* unknown stop */ #define PAGE_FAIL -1 /* page fail */ #define INTERRUPT -2 /* interrupt */ #define ABORT(x) longjmp (save_env, (x)) /* abort */ @@ -150,16 +152,16 @@ typedef t_int64 d10; /* PDP-10 data (36b) */ #define MEM_ADDR_NXM(x) ((x) >= MEMSIZE) #define VASIZE 18 /* virtual addr width */ #define AMASK ((1 << VASIZE) - 1) /* virtual addr mask */ -#define LMASK 0777777000000 /* left mask */ -#define LSIGN 0400000000000 /* left sign */ -#define RMASK 0000000777777 /* right mask */ -#define RSIGN 0000000400000 /* right sign */ -#define DMASK 0777777777777 /* data mask */ -#define SIGN 0400000000000 /* sign */ -#define MMASK 0377777777777 /* magnitude mask */ -#define ONES 0777777777777 -#define MAXPOS 0377777777777 -#define MAXNEG 0400000000000 +#define LMASK INT64_C(0777777000000) /* left mask */ +#define LSIGN INT64_C(0400000000000) /* left sign */ +#define RMASK INT64_C(0000000777777) /* right mask */ +#define RSIGN INT64_C(0000000400000) /* right sign */ +#define DMASK INT64_C(0777777777777) /* data mask */ +#define SIGN INT64_C(0400000000000) /* sign */ +#define MMASK INT64_C(0377777777777) /* magnitude mask */ +#define ONES INT64_C(0777777777777) +#define MAXPOS INT64_C(0377777777777) +#define MAXNEG INT64_C(0400000000000) /* Instruction format */ @@ -186,11 +188,11 @@ typedef t_int64 d10; /* PDP-10 data (36b) */ /* Byte pointer format */ #define BP_V_P 30 /* position */ -#define BP_M_P 077 -#define BP_P 0770000000000 +#define BP_M_P INT64_C(077) +#define BP_P INT64_C(0770000000000) #define BP_V_S 24 /* size */ -#define BP_M_S 077 -#define BP_S 0007700000000 +#define BP_M_S INT64_C(077) +#define BP_S INT64_C(0007700000000) #define GET_P(x) ((int32) (((x) >> BP_V_P) & BP_M_P)) #define GET_S(x) ((int32) (((x) >> BP_V_S) & BP_M_S)) #define PUT_P(b,x) (((b) & ~BP_P) | ((((t_int64) (x)) & BP_M_P) << BP_V_P)) @@ -291,15 +293,15 @@ typedef t_int64 d10; /* PDP-10 data (36b) */ /* Page table entry, TOPS-20 paging */ -#define PTE_T20_V_TYP 33 /* T20: pointer type */ -#define PTE_T20_M_TYP 07 +#define PTE_T20_V_TYP INT64_C(33) /* T20: pointer type */ +#define PTE_T20_M_TYP INT64_C(07) #define T20_NOA 0 /* no access */ #define T20_IMM 1 /* immediate */ #define T20_SHR 2 /* shared */ #define T20_IND 3 /* indirect */ -#define PTE_T20_W 0020000000000 /* T20: writeable */ -#define PTE_T20_C 0004000000000 /* T20: cacheable */ -#define PTE_T20_STM 0000077000000 /* T20: storage medium */ +#define PTE_T20_W INT64_C(0020000000000) /* T20: writeable */ +#define PTE_T20_C INT64_C(0004000000000) /* T20: cacheable */ +#define PTE_T20_STM INT64_C(0000077000000) /* T20: storage medium */ #define PTE_T20_V_PMI 18 /* page map index */ #define PTE_T20_M_PMI 0777 #define T20_GETTYP(x) ((int32) (((x) >> PTE_T20_V_TYP) & PTE_T20_M_TYP)) @@ -307,27 +309,27 @@ typedef t_int64 d10; /* PDP-10 data (36b) */ /* CST entry, TOPS-20 paging */ -#define CST_AGE 0770000000000 /* age field */ -#define CST_M 0000000000001 /* modified */ +#define CST_AGE INT64_C(0770000000000) /* age field */ +#define CST_M INT64_C(0000000000001) /* modified */ /* Page fail word, DEC paging */ -#define PF_USER 0400000000000 /* user mode */ -#define PF_HARD 0200000000000 /* nx I/O reg */ -#define PF_NXM 0370000000000 /* nx memory */ -#define PF_T10_A 0100000000000 /* T10: pte A bit */ -#define PF_T10_W 0040000000000 /* T10: pte W bit */ -#define PF_T10_S 0020000000000 /* T10: pte S bit */ -#define PF_T20_DN 0100000000000 /* T20: eval done */ -#define PF_T20_M 0040000000000 /* T20: modified */ -#define PF_T20_W 0020000000000 /* T20: writeable */ -#define PF_WRITE 0010000000000 /* write reference */ -#define PF_PUB 0004000000000 /* pte public bit */ -#define PF_C 0002000000000 /* pte C bit */ -#define PF_VIRT 0001000000000 /* pfl: virt ref */ -#define PF_NXMP 0001000000000 /* nxm: phys ref */ -#define PF_IO 0000200000000 /* I/O reference */ -#define PF_BYTE 0000020000000 /* I/O byte ref */ +#define PF_USER INT64_C(0400000000000) /* user mode */ +#define PF_HARD INT64_C(0200000000000) /* nx I/O reg */ +#define PF_NXM INT64_C(0370000000000) /* nx memory */ +#define PF_T10_A INT64_C(0100000000000) /* T10: pte A bit */ +#define PF_T10_W INT64_C(0040000000000) /* T10: pte W bit */ +#define PF_T10_S INT64_C(0020000000000) /* T10: pte S bit */ +#define PF_T20_DN INT64_C(0100000000000) /* T20: eval done */ +#define PF_T20_M INT64_C(0040000000000) /* T20: modified */ +#define PF_T20_W INT64_C(0020000000000) /* T20: writeable */ +#define PF_WRITE INT64_C(0010000000000) /* write reference */ +#define PF_PUB INT64_C(0004000000000) /* pte public bit */ +#define PF_C INT64_C(0002000000000) /* pte C bit */ +#define PF_VIRT INT64_C(0001000000000) /* pfl: virt ref */ +#define PF_NXMP INT64_C(0001000000000) /* nxm: phys ref */ +#define PF_IO INT64_C(0000200000000) /* I/O reference */ +#define PF_BYTE INT64_C(0000020000000) /* I/O byte ref */ /* Virtual address, ITS paging */ @@ -359,7 +361,7 @@ typedef t_int64 d10; /* PDP-10 data (36b) */ /* Page fail word, ITS paging */ -#define PF_ITS_WRITE 0010000000000 /* write reference */ +#define PF_ITS_WRITE INT64_C(0010000000000) /* write reference */ #define PF_ITS_V_ACC 28 /* access from PTE */ /* Page table fill operations */ @@ -371,16 +373,16 @@ typedef t_int64 d10; /* PDP-10 data (36b) */ /* User base register */ -#define UBR_SETACB 0400000000000 /* set AC blocks */ -#define UBR_SETUBR 0100000000000 /* set UBR */ +#define UBR_SETACB INT64_C(0400000000000) /* set AC blocks */ +#define UBR_SETUBR INT64_C(0100000000000) /* set UBR */ #define UBR_V_CURAC 27 /* current AC block */ #define UBR_V_PRVAC 24 /* previous AC block */ #define UBR_M_AC 07 -#define UBR_ACBMASK 0007700000000 +#define UBR_ACBMASK INT64_C(0007700000000) #define UBR_V_UBR 0 /* user base register */ #define UBR_N_UBR 11 #define UBR_M_UBR 03777 -#define UBR_UBRMASK 0000000003777 +#define UBR_UBRMASK INT64_C(0000000003777) #define UBR_GETCURAC(x) ((int32) (((x) >> UBR_V_CURAC) & UBR_M_AC)) #define UBR_GETPRVAC(x) ((int32) (((x) >> UBR_V_PRVAC) & UBR_M_AC)) #define UBR_GETUBR(x) ((int32) (((x) >> UBR_V_UBR) & PAG_M_PPN)) @@ -468,17 +470,18 @@ typedef t_int64 d10; /* PDP-10 data (36b) */ /* Microcode constants */ -#define UC_INHCST 0400000000000 /* inhibit CST update */ -#define UC_UBABLT 0040000000000 /* BLTBU and BLTUB */ -#define UC_KIPAGE 0020000000000 /* "KI" paging */ -#define UC_KLPAGE 0010000000000 /* "KL" paging */ +#define UC_INHCST INT64_C(0400000000000) /* inhibit CST update */ +#define UC_UBABLT INT64_C(0040000000000) /* BLTBU and BLTUB */ +#define UC_KIPAGE INT64_C(0020000000000) /* "KI" paging */ +#define UC_KLPAGE INT64_C(0010000000000) /* "KL" paging */ #define UC_VERDEC (0130 << 18) /* ucode version */ #define UC_VERITS (262u << 18) #define UC_SERDEC 4097 /* serial number */ #define UC_SERITS 1729 #define UC_AIDDEC (UC_INHCST | UC_UBABLT | UC_KIPAGE | UC_KLPAGE | \ - UC_VERDEC | UC_SERDEC) -#define UC_AIDITS (UC_KIPAGE | UC_VERITS | UC_SERITS) + UC_VERDEC) +#define UC_AIDITS (UC_KIPAGE | UC_VERITS) + #define UC_HSBDEC 0376000 /* DEC initial HSB */ #define UC_HSBITS 0000500 /* ITS initial HSB */ @@ -588,9 +591,9 @@ typedef t_int64 d10; /* PDP-10 data (36b) */ /* Unibus I/O constants */ #define READ 0 /* PDP11 compatible */ -/* #define READC 1 /* console read */ +/* #define READC 1 *//* console read */ #define WRITE 2 -/* #define WRITEC 3 /* console write */ +/* #define WRITEC 3 *//* console write */ #define WRITEB 4 #define IO_V_UBA 18 /* UBA in I/O addr */ #define IO_N_UBA 16 /* max num of UBA's */ @@ -612,14 +615,22 @@ struct pdp_dib { int32 vloc; /* locator */ int32 vec; /* value */ int32 (*ack[VEC_DEVMAX])(void); /* ack routines */ + uint32 flags; /* Special flags */ }; +#define DIB_M_REGSIZE 03 /* Device register size */ +#define DIB_REG16BIT 00 +#define DIB_REG18BIT 01 + typedef struct pdp_dib DIB; /* I/O system parameters */ #define DZ_MUXES 4 /* max # of muxes */ #define DZ_LINES 8 /* lines per mux */ +#define KMC_UNITS 1 /* max # of KMCs */ +#define INITIAL_KMCS 0 /* Number initially enabled */ +#define DUP_LINES 4 /* max # of DUP11's */ #define DIB_MAX 100 /* max DIBs */ #define DEV_V_UBUS (DEV_V_UF + 0) /* Unibus */ @@ -659,8 +670,6 @@ typedef struct pdp_dib DIB; #define IOLN_UBCS3 001 #define IOBA_UBMNT3 (IO_UBA3 + 0763101) /* Unibus 3 maint reg */ #define IOLN_UBMNT3 001 -#define IOBA_XU (IO_UBA3 + 0774510) /* DEUNA/DELUA */ -#define IOLN_XU 010 #define IOBA_CR (IO_UBA3 + 0777160) /* CD/CR/CM */ #define IOLN_CR 010 #define IOBA_RY (IO_UBA3 + 0777170) /* RX211 */ @@ -698,7 +707,10 @@ typedef struct pdp_dib DIB; #define INT_V_RP 6 /* RH11/RP,RM drives */ #define INT_V_TU 7 /* RH11/TM03/TU45 */ -#define INT_V_XU 15 /* DEUNA/DELUA */ +#define INT_V_KMCA 8 /* KMC11 */ +#define INT_V_KMCB 9 +#define INT_V_DMCRX 10 /* DMC11/DMR11 */ +#define INT_V_DMCTX 11 #define INT_V_DZRX 16 /* DZ11 */ #define INT_V_DZTX 17 #define INT_V_RY 18 /* RX211 */ @@ -706,9 +718,15 @@ typedef struct pdp_dib DIB; #define INT_V_PTP 25 #define INT_V_LP20 26 /* LPT20 */ #define INT_V_CR 27 /* CD20 (CD11) */ +#define INT_V_DUPRX 28 /* DUP11 */ +#define INT_V_DUPTX 29 #define INT_RP (1u << INT_V_RP) #define INT_TU (1u << INT_V_TU) +#define INT_KMCA (1u << INT_V_KMCA) +#define INT_KMCB (1u << INT_V_KMCB) +#define INT_DMCRX (1u << INT_V_DMCRX) +#define INT_DMCTX (1u << INT_V_DMCTX) #define INT_XU (1u << INT_V_XU) #define INT_DZRX (1u << INT_V_DZRX) #define INT_DZTX (1u << INT_V_DZTX) @@ -717,13 +735,20 @@ typedef struct pdp_dib DIB; #define INT_PTP (1u << INT_V_PTP) #define INT_LP20 (1u << INT_V_LP20) #define INT_CR (1u << INT_V_CR) +#define INT_DUPRX (1u << INT_V_DUPRX) +#define INT_DUPTX (1u << INT_V_DUPTX) #define IPL_RP 6 /* int levels */ #define IPL_TU 6 -#define IPL_XU 5 +#define IPL_KMCA 5 +#define IPL_KMCB 5 +#define IPL_DMCRX 5 +#define IPL_DMCTX 5 #define IPL_DZRX 5 #define IPL_DZTX 5 #define IPL_RY 5 +#define IPL_DUPRX 5 +#define IPL_DUPTX 5 #define IPL_PTR 4 #define IPL_PTP 4 #define IPL_LP20 4 @@ -758,8 +783,13 @@ typedef struct pdp_dib DIB; int32 Map_ReadB (uint32 ba, int32 bc, uint8 *buf); int32 Map_ReadW (uint32 ba, int32 bc, uint16 *buf); +int32 Map_ReadW18 (uint32 ba, int32 bc, uint32 *buf); int32 Map_WriteB (uint32 ba, int32 bc, uint8 *buf); int32 Map_WriteW (uint32 ba, int32 bc, uint16 *buf); +int32 Map_WriteW18 (uint32 ba, int32 bc, uint32 *buf); +void uba_debug_dma_in (uint32 ba, a10 pa_start, a10 pa_end); +void uba_debug_dma_out (uint32 ba, a10 pa_start, a10 pa_end); +void uba_debug_dma_nxm (const char *msg, a10 pa10, uint32 ba, int32 bc); t_stat set_addr (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat set_addr_flt (UNIT *uptr, int32 val, char *cptr, void *desc); diff --git a/PDP10/pdp10_fe.c b/PDP10/pdp10_fe.c index 97cbb20d..4ae17f46 100644 --- a/PDP10/pdp10_fe.c +++ b/PDP10/pdp10_fe.c @@ -1,6 +1,6 @@ /* pdp10_fe.c: PDP-10 front end (console terminal) simulator - Copyright (c) 1993-2012, Robert M Supnik + Copyright (c) 1993-2015, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,7 @@ fe KS10 console front end + 02-Apr-15 RMS Backported keepalive mechanism 18-Apr-12 RMS Added clock coscheduling 18-Jun-07 RMS Added UNIT_IDLE flag to console input 17-Oct-06 RMS Synced keyboard to clock for idling @@ -46,9 +47,15 @@ extern int32 apr_flg; extern int32 tmxr_poll; t_stat fei_svc (UNIT *uptr); t_stat feo_svc (UNIT *uptr); +static t_stat kaf_svc (UNIT *uptr); t_stat fe_reset (DEVICE *dptr); t_stat fe_stop_os (UNIT *uptr, int32 val, char *cptr, void *desc); +a10 fe_xct = 0; +uint32 fe_bootrh = 0; +int32 fe_bootunit = -1; +extern DIB *dib_tab[]; + /* FE data structures fe_dev FE device descriptor @@ -58,10 +65,12 @@ t_stat fe_stop_os (UNIT *uptr, int32 val, char *cptr, void *desc); #define fei_unit fe_unit[0] #define feo_unit fe_unit[1] +#define kaf_unit fe_unit[2] UNIT fe_unit[] = { { UDATA (&fei_svc, UNIT_IDLE, 0), 0 }, - { UDATA (&feo_svc, 0, 0), SERIAL_OUT_WAIT } + { UDATA (&feo_svc, 0, 0), SERIAL_OUT_WAIT }, + { UDATA (&kaf_svc, 0, 0), (1*1000*1000) } }; REG fe_reg[] = { @@ -71,6 +80,8 @@ REG fe_reg[] = { { ORDATA (OBUF, feo_unit.buf, 8) }, { DRDATA (OCOUNT, feo_unit.pos, T_ADDR_W), REG_RO + PV_LEFT }, { DRDATA (OTIME, feo_unit.wait, 24), REG_NZ + PV_LEFT }, + { ORDATA (FEXCT, fe_xct, 9), REG_HIDDEN }, + { ORDATA (KPACNT, kaf_unit.u4, 9), REG_HRO }, { NULL } }; @@ -81,7 +92,7 @@ MTAB fe_mod[] = { DEVICE fe_dev = { "FE", fe_unit, fe_reg, fe_mod, - 2, 10, 31, 1, 8, 8, + 3, 10, 31, 1, 8, 8, NULL, NULL, &fe_reset, NULL, NULL, NULL }; @@ -112,6 +123,48 @@ DEVICE fe_dev = { input character). */ +/* Here is the definition of the communications area: +XPP RLWORD,31 ;RELOAD WORD [FE_KEEPA] + KSRLD==1B4 ;RELOAD REQUEST (8080 will reload -10 if this is set) + KPACT==1B5 ;KEEP ALIVE ACTIVE (8080 reloads -10 if KPALIV doesn't change) + KLACT==1B6 ;KLINIK ACTIVE (Remote diagnosis line enabled) + PAREN==1B7 ;PARITY ERROR DETECT ENABLED + CRMPAR==1B8 ;CRAM PAR ERR DETECT ENABLED + DRMPAR==1B9 ;DRAM PAR ERR DETECT ENABLED + CASHEN==1B10 ;CACHE ENABLED + MILSEN==1B11 ;1MSEC ENABLED + TRPENA==1B12 ;TRAPS ENABLED + MFGMOD==1B13 ;MANUFACTURING MODE + KPALIV==377B27 ;KEEP ALIVE WORD CHECKED EVERY 1 SEC, AFTER 15, FAIL + ; Why reload (8080->10) + AUTOBT==1B32 ;BOOT SWITCH OR POWER UP CONDITION + PWRFAL==1B33 ;POWER FAIL restart (Start at 70) + FORREL==1B34 ;FORCED RELOAD + KEPFAL==1B35 ;KEEP ALIVE FAILURE (XCT exec 71) + +XPP CTYIWD,32 ;CTY INPUT WORD [FE_CTYIN] + CTYICH==377B35 ;CTY INPUT CHARACTER + CTYIVL==1B27 ;INPUT VALID BIT (Actually, this is an 8-bit function code) + +XPP CTYOWD,33 ;CTY OUTPUT WORD [FE_CTYOUT] + CTYOCH==377B35 ;CTY OUTPUT CHARACTER + CTYOVL==1B27 ;OUTPUT VALID FLAG + +XPP KLIIWD,34 ;KLINIK INPUT WORD [FE_KLININ] + KLIICH==377B35 ;KLINIK INPUT CHARACTER + KLIIVL==1B27 ;KLINIK INPUT VALID (Historical) + KLICHR==1B27 ;KLINIK CHARACTER + KLIINI==2B27 ;KLINIK INITED + KLICAR==3B27 ;CARRIER LOST + + +XPP KLIOWD,35 ;KLINIK OUTPUT WORD [FE_KLINOUT] + KLIOCH==377B35 ;KLINIK OUTPUT CHARACTER + KLIOVL==1B27 ;KLINIK OUTPUT VALID (Historical) + KLOCHR==1B27 ;KLINIK CHARACTER AVAILABLE + KLIHUP==2B27 ;KLINIK HANGUP REQUEST +*/ + void fe_intr (void) { if (M[FE_CTYOUT] & FE_CVALID) { /* char to print? */ @@ -156,14 +209,103 @@ apr_flg = apr_flg | APRF_CON; /* interrupt KS10 */ return SCPE_OK; } +/* Keep-alive service + * If the 8080 detects the 'force reload' bit, it initiates a disk + * boot. IO is reset, but memory is preserved. + * + * If the keep-alive enable bit is set, the -10 updates the keep-alive + * count field every second. The 8080 also checks the word every second. + * If the 8080 finds that the count hasn't changed for 15 consecutive seconds, + * a Keep-Alive Failure is declared. This forces the -10 to execute the + * contents of exec location 71 to collect status and initiate error recovery. + */ + +static t_stat kaf_svc (UNIT *uptr) +{ +if (M[FE_KEEPA] & INT64_C(0020000000000)) { /* KSRLD - "Forced" (actually, requested) reload */ + uint32 oldsw = sim_switches; + DEVICE *bdev = NULL; + int32 i; + + sim_switches &= ~SWMASK ('P'); + reset_all (4); /* RESET IO starting with UBA */ + sim_switches = oldsw; + + M[FE_KEEPA] &= ~INT64_C(0030000177777); /* Clear KAF, RLD, KPALIV & reason + * 8080 ucode actually clears HW + * status too, but that's a bug. */ + M[FE_KEEPA] |= 02; /* Reason = FORREL */ + fei_unit.buf = feo_unit.buf = 0; + M[FE_CTYIN] = M[FE_CTYOUT] = 0; + M[FE_KLININ] = M[FE_KLINOUT] = 0; + + /* The 8080 has the disk RH address & unit in its memory, even if + * the previous boot was from tape. It has no NVM, so the last opr + * selection will do here. The case of DS MT would require a + * SET FE command. It's not a common case. + */ + + /* The device may have been detached, disabled or reconfigured since boot time. + * Therefore, search for it by CSR address & validate that it's bootable. + * If there are problems, the processor is halted. + */ + + for (i = 0; fe_bootrh && ((bdev = sim_devices[i]) != NULL); i++ ) { + DIB *dibp = (DIB *)bdev->ctxt; + if (dibp && (fe_bootrh >= dibp->ba) && + (fe_bootrh < (dibp->ba + dibp->lnt))) { + break; + } + } + + fe_xct = 2; + if ((bdev != NULL) && (fe_bootunit >= 0) && (fe_bootunit < (int32) bdev->numunits)) { + UNIT *bunit = bdev->units + fe_bootunit; + + if (!(bunit->flags & UNIT_DIS) && (bunit->flags & UNIT_ATTABLE) && (bunit->flags & UNIT_ATT)) { + if (bdev->boot (fe_bootunit, bdev) == SCPE_OK) /* boot the device */ + fe_xct = 1; + } + } + } +else if (M[FE_KEEPA] & INT64_C(0010000000000)) { /* KPACT */ + d10 kav = M[FE_KEEPA] & INT64_C(0000000177400); /* KPALIV */ + if (kaf_unit.u3 != (int32)kav) { /* change? */ + kaf_unit.u3 = (int32)kav; /* start over */ + kaf_unit.u4 = 0; + } + else if (++kaf_unit.u4 >= 15) { + kaf_unit.u4 = 0; + M[FE_KEEPA] = (M[FE_KEEPA] & ~INT64_C(0000000000377)) | 01; /* RSN = KAF (leaves enabled) */ + fei_unit.buf = feo_unit.buf = 0; + M[FE_CTYIN] = M[FE_CTYOUT] = 0; + M[FE_KLININ] = M[FE_KLINOUT] = 0; + fe_xct = 071; + } + } + +sim_activate_after (&kaf_unit, kaf_unit.wait); +if (fe_xct == 2) { + fe_xct = 0; + return STOP_CONSOLE; + } +return SCPE_OK; +} + /* Reset */ t_stat fe_reset (DEVICE *dptr) { fei_unit.buf = feo_unit.buf = 0; M[FE_CTYIN] = M[FE_CTYOUT] = 0; +M[FE_KLININ] = M[FE_KLINOUT] = 0; + +M[FE_KEEPA] = INT64_C(0003740000000); /* PARITY STOP, CRM, DP PAREN, CACHE EN, 1MSTMR, TRAPEN */ +kaf_unit.u3 = 0; +kaf_unit.u4 = 0; apr_flg = apr_flg & ~(APRF_ITC | APRF_CON); sim_activate (&fei_unit, KBD_WAIT (fei_unit.wait, tmxr_poll)); +sim_activate_after (&kaf_unit, kaf_unit.wait); return SCPE_OK; } @@ -171,6 +313,6 @@ return SCPE_OK; t_stat fe_stop_os (UNIT *uptr, int32 val, char *cptr, void *desc) { -M[FE_SWITCH] = IOBA_RP; /* tell OS to stop */ +M[FE_SWITCH] = IOBA_RP; /* tell OS to stop */ return SCPE_OK; } diff --git a/PDP10/pdp10_ksio.c b/PDP10/pdp10_ksio.c index 7807016d..397ab9f7 100644 --- a/PDP10/pdp10_ksio.c +++ b/PDP10/pdp10_ksio.c @@ -44,7 +44,8 @@ The KS10 uses the PDP-11 Unibus for its I/O, via adapters. While nominally four adapters are supported, in practice only 1 and 3 are implemented. The disks are placed on adapter 1, the rest of - the I/O devices on adapter 3. + the I/O devices on adapter 3. (adapter 4 IS used in some supported + configurations, but those devices haven't been emulated yet.) In theory, we should maintain completely separate Unibuses, with distinct PI systems. In practice, this simulator has so few devices @@ -72,25 +73,33 @@ #include "pdp10_defs.h" #include +#include +#include #include "sim_sock.h" #include "sim_tmxr.h" +#define UBMPAGE(x) (x & (PAG_VPN<<2)) /* UBA Map page field of 11 address */ #define XBA_MBZ 0400000 /* ba mbz */ #define eaRB (ea & ~1) #define GETBYTE(ea,x) ((((ea) & 1)? (x) >> 8: (x)) & 0377) #define UBNXM_FAIL(pa,op) \ - n = iocmap[GET_IOUBA (pa)]; \ + n = ADDR2UBA (pa); \ if (n >= 0) \ ubcs[n] = ubcs[n] | UBCS_TMO | UBCS_NXD; \ pager_word = PF_HARD | PF_VIRT | PF_IO | \ ((op == WRITEB)? PF_BYTE: 0) | \ (TSTF (F_USR)? PF_USER: 0) | (pa); \ ABORT (PAGE_FAIL) +/* Is Unibus address mapped to -10 memory */ +#define TEN_MAPPED(ub,ba) ((ubmap[ub][PAG_GETVPN(((ba) & 0777777) >> 2)] & UMAP_VLD) != 0) + +/* Translate UBA number in a PA to UBA index. 1,,* -> ubmap[0], all others -> ubmap[1] */ +#define ADDR2UBA(x) (iocmap[GET_IOUBA (x)]) /* Unibus adapter data */ int32 ubcs[UBANUM] = { 0 }; /* status registers */ -int32 ubmap[UBANUM][UMAP_MEMSIZE] = { 0 }; /* Unibus maps */ +int32 ubmap[UBANUM][UMAP_MEMSIZE] = {{ 0 }}; /* Unibus maps */ int32 int_req = 0; /* interrupt requests */ /* Map IO controller numbers to Unibus adapters: -1 = non-existent */ @@ -105,7 +114,33 @@ static const int32 ubabr76[UBANUM] = { static const int32 ubabr54[UBANUM] = { INT_UB1 & (INT_IPL5 | INT_IPL4), INT_UB3 & (INT_IPL5 | INT_IPL4) }; -static const int32 ubashf[4] = { 18, 26, 0, 8 }; + +/* Masks for Unibus quantities */ +#define M_BYTE (0xFF) +#define M_WORD (0xFFFF) +#define M_WORD18 (0777777) +#define M_LH (0777777000000) +#define M_RH (0000000777777) + +/* Bits to shift for each Unibus byte */ +#define V_BYTE0 (18) +#define V_BYTE1 (26) +#define V_BYTE2 (0) +#define V_BYTE3 (8) + +#define V_WORD0 V_BYTE0 +#define V_WORD1 V_BYTE2 + +/* Bits to preserve when writing each Unibus byte. + * This excludes the XX bits so they are cleared. + */ +#define M_BYTE0 (~INT64_C (0000377000000)) /* Clear byte 0 */ +#define M_BYTE1 (~INT64_C (0777400000000)) /* Clear byte 1 + XX */ +#define M_BYTE2 (~INT64_C (0000000000377)) /* Clear byte 2 */ +#define M_BYTE3 (~INT64_C (0000000777400)) /* Clear byte 3 + XX */ + +#define M_WORD0 (~INT64_C (0777777000000)) /* Clear word 0 + XX */ +#define M_WORD1 (~INT64_C (0000000777777)) /* Clear word 1 + XX */ extern d10 *M; /* main memory */ extern d10 *ac_cur; @@ -113,9 +148,7 @@ extern d10 pager_word; extern int32 flags; extern const int32 pi_l2bit[8]; extern UNIT cpu_unit; -extern FILE *sim_log; extern jmp_buf save_env; -extern DEVICE *sim_devices[]; extern int32 pi_eval (void); extern int32 rp_inta (void); @@ -133,6 +166,8 @@ t_stat wr_nop (int32 data, int32 addr, int32 access); t_stat uba_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); t_stat uba_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw); t_stat uba_reset (DEVICE *dptr); +void uba_debug_dma_in (uint32 ba, a10 pa_start, a10 pa_end); +void uba_debug_dma_out (uint32 ba, a10 pa_start, a10 pa_end); d10 ReadIO (a10 ea); void WriteIO (a10 ea, d10 val, int32 mode); @@ -163,12 +198,23 @@ REG uba_reg[] = { { NULL } }; +#define DBG_DMA_IN 0x0001 /* trace dma input transfers */ +#define DBG_DMA_OUT 0x0002 /* trace dma output transfers */ +#define DBG_DMA_NXM 0x0004 /* trace dma nxm errors */ + +DEBTAB uba_debug[] = { + {"IN", DBG_DMA_IN}, + {"OUT", DBG_DMA_OUT}, + {"NXM", DBG_DMA_NXM}, + {0} + }; + DEVICE uba_dev = { "UBA", uba_unit, uba_reg, NULL, UBANUM, 8, UMAP_ASIZE, 1, 8, 32, &uba_ex, &uba_dep, &uba_reset, NULL, NULL, NULL, - NULL, 0 + NULL, DEV_DEBUG, 0, uba_debug }; /* PDP-11 I/O structures */ @@ -243,7 +289,7 @@ return ReadIO (ea); /* RDIO, IORD */ void io713 (d10 val, a10 ea) { -WriteIO (ea, val & 0177777, WRITE); /* WRIO, IOWR */ +WriteIO (ea, val, WRITE); /* WRIO, IOWR */ return; } @@ -255,7 +301,6 @@ void io714 (d10 val, a10 ea) { d10 temp; -val = val & 0177777; if (Q_ITS) /* IOWRI */ WriteIO (IO_UBA3 | ea, val, WRITE); else { @@ -274,7 +319,6 @@ void io715 (d10 val, a10 ea) { d10 temp; -val = val & 0177777; if (Q_ITS) /* IOWRQ */ WriteIO (IO_UBA1 | ea, val, WRITE); else { @@ -347,7 +391,7 @@ return GETBYTE (ea, val); void io723 (d10 val, a10 ea) { -WriteIO (ea, val & 0377, WRITEB); /* WRIOB, IOWRB */ +WriteIO (ea, val & M_BYTE, WRITEB); /* WRIOB, IOWRB */ return; } @@ -359,7 +403,7 @@ void io724 (d10 val, a10 ea) { d10 temp; -val = val & 0377; +val = val & M_BYTE; if (Q_ITS) /* IOWRBI */ WriteIO (IO_UBA3 | ea, val, WRITEB); else { @@ -379,7 +423,7 @@ void io725 (d10 val, a10 ea) { d10 temp; -val = val & 0377; +val = val & M_BYTE; if (Q_ITS) /* IOWRBQ */ WriteIO (IO_UBA1 | ea, val, WRITEB); else { @@ -396,138 +440,1094 @@ return; simulator and the 32b world of the device simulators. */ +/* UBReadIO and UBWriteIO handle the device lookup and access + * These are used for all IO space accesses. They return status. + * + * ReadIO and WriteIO are used by the CPU instructions, and generate + * UBA NXM page fails for unassigned IO addresses. + */ + +static t_stat UBReadIO (int32 *data, int32 ba, int32 access) +{ +uint32 pa = (uint32) ba; +int32 i, val; +DIB *dibp; + +for (i = 0; (dibp = dib_tab[i]); i++ ) { + if ((pa >= dibp->ba) && + (pa < (dibp->ba + dibp->lnt))) { + dibp->rd (&val, pa, access); + pi_eval (); + *data = val; + return SCPE_OK; + } + } +return SCPE_NXM; +} + d10 ReadIO (a10 ea) { uint32 pa = (uint32) ea; -int32 i, n, val; +int32 n, val; + + if (UBReadIO (&val, pa, READ) == SCPE_OK) + return ((d10) val); + UBNXM_FAIL (pa, READ); +} + + +static t_stat UBWriteIO (int32 data, int32 ba, int32 access) +{ +uint32 pa = (uint32) ba; +int32 i; DIB *dibp; -for (i = 0; dibp = dib_tab[i]; i++ ) { +for (i = 0; (dibp = dib_tab[i]); i++ ) { if ((pa >= dibp->ba) && (pa < (dibp->ba + dibp->lnt))) { - dibp->rd (&val, pa, READ); + if ((dibp->flags & DIB_M_REGSIZE) == DIB_REG16BIT) { + data &= M_WORD; + } + dibp->wr (data, ba, access); pi_eval (); - return ((d10) val); - } + return SCPE_OK; + } } -UBNXM_FAIL (pa, READ); +return SCPE_NXM; } void WriteIO (a10 ea, d10 val, int32 mode) { uint32 pa = (uint32) ea; -int32 i, n; -DIB *dibp; +int32 n; -for (i = 0; dibp = dib_tab[i]; i++ ) { - if ((pa >= dibp->ba) && - (pa < (dibp->ba + dibp->lnt))) { - dibp->wr ((int32) val, pa, mode); - pi_eval (); - return; - } - } +if (UBWriteIO ((int32) val, (int32) pa, mode) == SCPE_OK) + return; UBNXM_FAIL (pa, mode); } /* Mapped read and write routines - used by standard Unibus devices on Unibus 1 - The only devices that use these routines are standard 16b Unibus devices. - 18b Unibus devices (the RP and TU) do their own reads and writes. + * I/O space accesses will work. Note that Unibus addresses with bit 17 set can + * not be mapped by the UBA, so I/O space (and more) can not be mapped to -10 memory. + */ - These routines would be more efficient if Map_Addr10 was only called - at a page boundary, but I don't think it's worth the added complexity. - - The upper two bits of the 18b halfword are not preserved on writes to memory. */ - -a10 Map_Addr10 (a10 ba, int32 ub) +static a10 Map_Addr10 (a10 ba, int32 ub, int32 *ubmp) { a10 pa10; int32 vpn = PAG_GETVPN (ba >> 2); /* get PDP-10 page number */ +int32 ubm; -if ((vpn >= UMAP_MEMSIZE) || (ba & XBA_MBZ) || /* invalid map? */ - ((ubmap[ub][vpn] & UMAP_VLD) == 0)) +if ((vpn >= UMAP_MEMSIZE) || (ba & XBA_MBZ)) { /* Validate bus address */ + if (ubmp) + *ubmp = 0; return -1; -pa10 = (ubmap[ub][vpn] + PAG_GETOFF (ba >> 2)) & PAMASK; +} +ubm = ubmap[ub][vpn]; +if (ubmp) + *ubmp = ubm; + +if ((ubm & UMAP_VLD) == 0) /* Ensure map entry is valid */ + return -1; +pa10 = (ubm + PAG_GETOFF (ba >> 2)) & PAMASK; return pa10; } +/* Routines for Bytes, Words (16-bit) and Words (18-bit). + * + * Note that the byte count argument is always BYTES, even if + * the unit transfered is a word. This is for compatibility with + * the 11/VAX system Unibus; these routines abstract DMA for all + * U/Q device simulations. + * + * All return the number of bytes NOT transferred; 0 means success. + * A non-zero return implies a NXM was encountered. + * + * Unaligned accesses to 16/18-bit words in IOSPACE are a STOP condition. + * (Should be in memory too, but some devices are lazy.) + * + * Unibus memory is mapped into 36-bit words so that 16-bit + * values appear in 18-bit half-words, and PDP10 byte pointers will + * increment through 16-bit (but not 8-bit) data. Viewed as bytes or + * words from the PDP10, memory looks like this: + * + * +-----+-----------+------------+-------+------------+------------+ + * | 0 1 | 2 9 | 10 17 | 18 19 | 20 27| 28 35 | PDP10 bits + * +-----+-----------+------------+-------+------------+------------+ + * | X X | BYTE 1<01>| BYTE 0<00> | X X | BYTE 3<11> | BYTE 2<10> | PDP11 bytes + * +-----+-----------+------------+-------+------------+------------+ + * | X X | WORD 0 <00> | X X | WORD 1 <10> | PDP11 words + * +-----+-----------+------------+-------+------------+------------+ + * + * are the values of the two low-order address bits as viewed on + * the Unibus. + * + * The bits marked XX are written as zero for 8 and 16 bit transfers + * and with data from the Unibus parity lines for 18 bit transfers. + * In a -10 read-modify-write cycle, they are cleared if the high byte + * of the adjacent word is written, and preserved otherwise. + * + * Unibus addressing does not change with 18-bit transfers; they are + * accounted for as 2 bytes. <0:1> are bits <17:16> of word 0; + * <18:19> are bits <17:16> of word 1. + * + * Normal writes assume that DMA will access sequential Unibus addresses. + * The UBA optimizes this by writing NPR data to <00> addresses + * without preserving the rest of the -10 word. This allows a memory + * write cycle, rather than the read-modify-write cycle required to + * preserve the rest of the word. The 'read reverse' bit in the UBA + * map forces a read-modify-write on all addresses. + * + * 16-bit transfers (the d18 bit in the map selects) write 0s into + * the correspnding X bits when <00> or <10> are written. + * + * Address mapping uses bits <1:0> of the Unibus address to select + * the byte as indicated above. Bits <10:2> are the offset within + * the PDP10 page; thus Unibus addressing assumes 4 bytes/PDP10 word. + * + * 9 bits = 512 words/PDP10 page = 2048 bytes / Unibus page + * + * Bits 16:11 select a UBA mapping register, which indicates whether + * PDP10 memory at that address is accessible, and if so, provides + * PDP10 bus address bits that replace and extend the Unibus bits. + * + * Unibus addresses with bit 17 set do not map PDP10 memory. The + * high end is reserved for Unibus IO space. The rest is used for + * UBA maintenance modes (not simulated). + * + * IO space accesses may have side effects in the device; an aligned + * read of two bytes is NOT equivalent to two one byte reads of the + * same addresses. + * + * The memory access in these routines is optimized to minimize UBA + * page table lookups and shift/merge operations with PDP10 memory. + * + * Memory transfers happen in up to 3 pieces: + * head : 0-3 bytes to an aligned PDP10 word (UB address 000b) + * body : As many PDP10 whole words as possible (4 bytes 32/36 bits) + * tail : 0-3 bytes remaining after the body. + */ + int32 Map_ReadB (uint32 ba, int32 bc, uint8 *buf) { -uint32 lim; -a10 pa10; +uint32 ea, ofs, cp, np; +int32 seg; +a10 pa10 = ~0u; +d10 m; +uint32 dpy_ba = ba; +a10 dpy_pa10 = ~0u; -lim = ba + bc; -for ( ; ba < lim; ba++) { /* by bytes */ - pa10 = Map_Addr10 (ba, 1); /* map addr */ - if ((pa10 < 0) || MEM_ADDR_NXM (pa10)) { /* inv map or NXM? */ - ubcs[1] = ubcs[1] | UBCS_TMO; /* UBA times out */ - return (lim - ba); /* return bc */ +if ((ba & ~((IO_M_UBA<> 8) & 0xff): csr & 0xff; + ba++; + bc--; } - *buf++ = (uint8) ((M[pa10] >> ubashf[ba & 3]) & 0377); + return bc; } + +/* Memory */ + +if (bc == 0) + return 0; + +cp = ~ba; +ofs = ba & 3; +seg = (4 - ofs) & 3; + +if (seg) { /* Unaligned head */ + if (seg > bc) + seg = bc; + cp = UBMPAGE (ba); /* Only one word, can't cross page */ + dpy_pa10 = pa10 = Map_Addr10 (ba, 1, NULL); /* map addr */ + if ((pa10 < 0) || MEM_ADDR_NXM (pa10)) { /* inv map or NXM? */ + ubcs[1] = ubcs[1] | UBCS_TMO; /* UBA timeout */ + uba_debug_dma_nxm ("Read Byte", pa10, ba, bc); + return bc; /* return bc */ + } + m = M[pa10++]; + ba += seg; + bc -= seg; + switch (ofs) { + case 1: + *buf++ = (uint8) ((m >> V_BYTE1) & M_BYTE); + if (!--seg) + break; + case 2: + *buf++ = (uint8) (m & M_BYTE); /* V_BYTE2 */ + if (!--seg) + break; + case 3: + *buf++ = (uint8) ((m >> V_BYTE3) & M_BYTE); + --seg; + break; + default: + assert (FALSE); + } + if (bc == 0) { + uba_debug_dma_out (dpy_ba, dpy_pa10, pa10); + return 0; + } + } /* Head */ + +/* At this point, ba is aligned. Therefore, ea<1:0> are the tail's length */ +ea = ba + bc; +seg = bc - (ea & 3); + +if (seg > 0) { /* Body: Whole PDP-10 words, 4 bytes */ + assert (((seg & 3) == 0) && (bc >= seg)); + dpy_ba = ba; + bc -= seg; + for ( ; seg; seg -= 4, ba += 4) { /* aligned longwords */ + np = UBMPAGE (ba); + if (np != cp) { /* New (or first) page? */ + uba_debug_dma_out (dpy_ba, dpy_pa10, pa10); + dpy_pa10 = pa10 = Map_Addr10 (ba, 1, NULL);/* map addr */ + dpy_ba = ba; + if ((pa10 < 0) || MEM_ADDR_NXM (pa10)) { /* inv map or NXM? */ + ubcs[1] = ubcs[1] | UBCS_TMO; /* UBA timeout */ + uba_debug_dma_nxm ("Read Byte", pa10, ba, bc); + return (bc + seg); /* return bc */ + } + cp = np; + } + m = M[pa10++]; /* Next word from -10 */ + buf[2] = (uint8) (m & M_BYTE); /* Byte 2 */ + m >>= 8; + buf[3] = (uint8) (m & M_BYTE); /* Byte 3 */ + m >>= 10; + buf[0] = (uint8) (m & M_BYTE); /* Byte 0 */ + m >>= 8; + buf[1] = (uint8) (m & M_BYTE); /* Byte 1 */ + buf += 4; + } + } /* Body */ + + /* Tail: partial -10 word, must be aligned. 1-3 bytes */ +assert ((bc >= 0) && ((ba & 3) == 0)); +if (bc) { + assert (bc <= 3); + np = UBMPAGE (ba); /* Only one word, last possible page crossing */ + if (np != cp) { /* New (or first) page? */ + uba_debug_dma_out (dpy_ba, dpy_pa10, pa10); + dpy_pa10 = pa10 = Map_Addr10 (ba, 1, NULL);/* map addr */ + dpy_ba = ba; + if ((pa10 < 0) || MEM_ADDR_NXM (pa10)) {/* inv map or NXM? */ + ubcs[1] = ubcs[1] | UBCS_TMO; /* UBA timeout */ + uba_debug_dma_nxm ("Read Byte", pa10, ba, bc); + return (bc); /* return bc */ + } + } + m = M[pa10++]; + switch (bc) { + case 3: + buf[2] = (uint8) (m & M_BYTE); /* V_BYTE2 */ + case 2: + buf[1] = (uint8) ((m >> V_BYTE1) & M_BYTE); + case 1: + buf[0] = (uint8) ((m >> V_BYTE0) & M_BYTE); + break; + default: + assert (FALSE); + } + } + +uba_debug_dma_out (dpy_ba, dpy_pa10, pa10); return 0; } int32 Map_ReadW (uint32 ba, int32 bc, uint16 *buf) { -uint32 lim; -a10 pa10; +uint32 ea, cp, np; +int32 seg; +a10 pa10 = ~0u; +d10 m; +uint32 dpy_ba = ba; +a10 dpy_pa10 = ~0u; -ba = ba & ~01; /* align start */ -lim = ba + (bc & ~01); -for ( ; ba < lim; ba = ba + 2) { /* by words */ - pa10 = Map_Addr10 (ba, 1); /* map addr */ - if ((pa10 < 0) || MEM_ADDR_NXM (pa10)) { /* inv map or NXM? */ - ubcs[1] = ubcs[1] | UBCS_TMO; /* UBA times out */ - return (lim - ba); /* return bc */ +if ((ba & ~((IO_M_UBA<> ((ba & 2)? 0: 18)) & 0177777); + return bc; } + +/* Memory */ + +if (bc == 0) +return 0; + +ba &= ~1; +if (bc & 1) + ABORT (STOP_IOALIGN); + +cp = ~ba; +seg = (4 - (ba & 3)) & 3; + +if (seg) { /* Unaligned head, can only be WORD1 */ + assert ((ba & 2) && (seg == 2)); + if (seg > bc) + seg = bc; + cp = UBMPAGE (ba); /* Only one word, can't cross page */ + dpy_pa10 = pa10 = Map_Addr10 (ba, 1, NULL); /* map addr */ + dpy_ba = ba; + if ((pa10 < 0) || MEM_ADDR_NXM (pa10)) { /* inv map or NXM? */ + ubcs[1] = ubcs[1] | UBCS_TMO; /* UBA timeout */ + uba_debug_dma_nxm ("Read Word", pa10, ba, bc); + return bc; /* return bc */ + } + ba += seg; + *buf++ = (uint16) (M[pa10++] & M_WORD); + if ((bc -= seg) == 0) { + uba_debug_dma_out (dpy_ba, dpy_pa10, pa10); return 0; } + } /* Head */ + +ea = ba + bc; +seg = bc - (ea & 3); + +if (seg > 0) { + assert (((seg & 3) == 0) && (bc >= seg)); + bc -= seg; + for ( ; seg; seg -= 4, ba += 4) { /* aligned longwords */ + np = UBMPAGE (ba); + if (np != cp) { /* New (or first) page? */ + uba_debug_dma_out (dpy_ba, dpy_pa10, pa10); + dpy_pa10 = pa10 = Map_Addr10 (ba, 1, NULL);/* map addr */ + dpy_ba = ba; + if ((pa10 < 0) || MEM_ADDR_NXM (pa10)) { /* inv map or NXM? */ + ubcs[1] = ubcs[1] | UBCS_TMO; /* UBA timeout */ + uba_debug_dma_nxm ("Read Word", pa10, ba, bc); + return (bc + seg); /* return bc */ + } + cp = np; + } + m = M[pa10++]; /* Next word from -10 */ + buf[1] = (uint16) (m & M_WORD); /* Bytes 3,,2 */ + m >>= 18; + buf[0] = (uint16) (m & M_WORD); /* Bytes 1,,0 */ + buf += 2; +} + } /* Body */ + +/* Tail: partial word, must be aligned, can only be WORD0 */ +assert ((bc >= 0) && ((ba & 3) == 0)); +if (bc) { + assert (bc == 2); + np = UBMPAGE (ba); /* Only one word, last possible page crossing */ + if (np != cp) { /* New (or first) page? */ + uba_debug_dma_out (dpy_ba, dpy_pa10, pa10); + dpy_pa10 = pa10 = Map_Addr10 (ba, 1, NULL);/* map addr */ + dpy_ba = ba; + if ((pa10 < 0) || MEM_ADDR_NXM (pa10)) {/* inv map or NXM? */ + ubcs[1] = ubcs[1] | UBCS_TMO; /* UBA timeout */ + uba_debug_dma_nxm ("Read Word", pa10, ba, bc); + return (bc); /* return bc */ + } + } + *buf = (uint16) ((M[pa10++] >> V_WORD0) & M_WORD); +} + +uba_debug_dma_out (dpy_ba, dpy_pa10, pa10); +return 0; +} + +/* Word reads returning 18-bit data + * + * Identical to 16-bit reads except that buffer is uint32 + * and masked to 18 bits. +*/ + +int32 Map_ReadW18 (uint32 ba, int32 bc, uint32 *buf) +{ +uint32 ea, cp, np; +int32 seg; +a10 pa10 = ~0u; +d10 m; +uint32 dpy_ba = ba; +a10 dpy_pa10 = ~0u; + +if ((ba & ~((IO_M_UBA< bc) + seg = bc; + cp = UBMPAGE (ba); /* Only one word, can't cross page */ + dpy_pa10 = pa10 = Map_Addr10 (ba, 1, NULL); /* map addr */ + dpy_ba = ba; + if ((pa10 < 0) || MEM_ADDR_NXM (pa10)) { /* inv map or NXM? */ + ubcs[1] = ubcs[1] | UBCS_TMO; /* UBA timeout */ + uba_debug_dma_nxm ("Read 18b Word", pa10, ba, bc); + return bc; /* return bc */ +} + ba += seg; + *buf++ = (uint32) (M[pa10++] & M_RH); + if ((bc -= seg) == 0) { + uba_debug_dma_out (dpy_ba, dpy_pa10, pa10); + return 0; +} + } /* Head */ + +ea = ba + bc; +seg = bc - (ea & 3); + +if (seg > 0) { + assert (((seg & 3) == 0) && (bc >= seg)); + bc -= seg; + for ( ; seg; seg -= 4, ba += 4) { /* aligned longwords */ + np = UBMPAGE (ba); + if (np != cp) { /* New (or first) page? */ + uba_debug_dma_out (dpy_ba, dpy_pa10, pa10); + dpy_pa10 = pa10 = Map_Addr10 (ba, 1, NULL);/* map addr */ + dpy_ba = ba; + if ((pa10 < 0) || MEM_ADDR_NXM (pa10)) {/* inv map or NXM? */ + ubcs[1] = ubcs[1] | UBCS_TMO; /* UBA timeout */ + uba_debug_dma_nxm ("Read 18b Word", pa10, ba, bc); + return (bc + seg); /* return bc */ + } + cp = np; +} + m = M[pa10++]; /* Next word from -10 */ + buf[1] = (uint32) (m & M_RH); /* Bytes 3,,2 */ + m >>= 18; + buf[0] = (uint32) (m & M_RH); /* Bytes 1,,0 */ + buf += 2; +} + } /* Body */ + +/* Tail: partial word, must be aligned */ +assert ((bc >= 0) && ((ba & 3) == 0)); +if (bc) { + assert (bc == 2); + np = UBMPAGE (ba); /* Only one word, last possible page crossing */ + if (np != cp) { /* New (or first) page? */ + uba_debug_dma_out (dpy_ba, dpy_pa10, pa10); + dpy_pa10 = pa10 = Map_Addr10 (ba, 1, NULL);/* map addr */ + dpy_ba = ba; + if ((pa10 < 0) || MEM_ADDR_NXM (pa10)) { /* inv map or NXM? */ + ubcs[1] = ubcs[1] | UBCS_TMO; /* UBA timeout */ + uba_debug_dma_nxm ("Read 18b Word", pa10, ba, bc); + return (bc); /* return bc */ +} + } + *buf++ = (uint32) ((M[pa10++] >> V_WORD0) & M_RH); + } + +uba_debug_dma_out (dpy_ba, dpy_pa10, pa10); +return 0; +} + +/* Word reads returning 36-bit data + * + * Identical to 16-bit reads except that buffer is d10 + * and masked to 36 bits. + */ + +int32 Map_ReadW36 (uint32 ba, int32 bc, d10 *buf) +{ +uint32 ea, cp, np; +int32 seg; +a10 pa10 = ~0u; +int32 ub = ADDR2UBA (ba); +uint32 dpy_ba = ba; +a10 dpy_pa10 = ~0u; + +if ((ba & ~((IO_M_UBA< 0) { + assert (((seg & 3) == 0) && (bc >= seg)); + bc -= seg; + for ( ; seg; seg -= 4, ba += 4) { /* aligned longwords */ + np = UBMPAGE (ba); + if (np != cp) { /* New (or first) page? */ + uba_debug_dma_out (dpy_ba, dpy_pa10, pa10); + dpy_pa10 = pa10 = Map_Addr10 (ba, ub, NULL);/* map addr */ + dpy_ba = ba; + if ((pa10 < 0) || MEM_ADDR_NXM (pa10)) {/* inv map or NXM? */ + ubcs[ub] |= UBCS_TMO; /* UBA timeout */ + uba_debug_dma_nxm ("Read 36b Word", pa10, ba, bc); + return (bc + seg); /* return bc */ + } + cp = np; + } + *buf++ = M[pa10++]; /* Next word from -10 */ + } + } /* Body */ + + +uba_debug_dma_out (dpy_ba, dpy_pa10, pa10); +return 0; +} + +/* Byte-mode writes */ int32 Map_WriteB (uint32 ba, int32 bc, uint8 *buf) { -uint32 lim; -a10 pa10; -d10 mask; +uint32 ea, ofs, cp, np; +int32 seg, ubm = 0; +a10 pa10 = ~0u; +d10 m; +uint32 dpy_ba = ba; +a10 dpy_pa10 = ~0u; -lim = ba + bc; -for ( ; ba < lim; ba++) { /* by bytes */ - pa10 = Map_Addr10 (ba, 1); /* map addr */ - if ((pa10 < 0) || MEM_ADDR_NXM (pa10)) { /* inv map or NXM? */ - ubcs[1] = ubcs[1] | UBCS_TMO; /* UBA times out */ - return (lim - ba); /* return bc */ +if ((ba & ~((IO_M_UBA< bc) + seg = bc; + cp = UBMPAGE (ba); /* Only one word, can't cross page */ + dpy_pa10 = pa10 = Map_Addr10 (ba, 1, &ubm); /* map addr */ + dpy_ba = ba; + if ((pa10 < 0) || MEM_ADDR_NXM (pa10)) { /* inv map or NXM? */ + ubcs[1] = ubcs[1] | UBCS_TMO; /* UBA timeout */ + uba_debug_dma_nxm ("Write Byte", pa10, ba, bc); + return bc; /* return bc */ + } + m = M[pa10]; + ba += seg; + bc -= seg; + switch (ofs) { + case 1: + m = (m & M_BYTE1) | (((d10) (*buf++)) << V_BYTE1); + if (!--seg) + break; + case 2: + m = (m & M_BYTE2) | ((d10) (*buf++)); /* V_BYTE2 */ + if (!--seg) + break; + case 3: + m = (m & M_BYTE3) | (((d10) (*buf++)) << V_BYTE3); + --seg; + break; + default: + assert (FALSE); + } + M[pa10++] = m; + if (bc == 0) { + uba_debug_dma_in (dpy_ba, dpy_pa10, pa10-dpy_pa10); + return 0; + } + } /* Head */ + +ea = ba + bc; +seg = bc - (ea & 3); + +if (seg > 0) { + assert (((seg & 3) == 0) && (bc >= seg)); + bc -= seg; + for ( ; seg; seg -= 4, ba += 4) { /* aligned longwords */ + np = UBMPAGE (ba); + if (np != cp) { /* New (or first) page? */ + uba_debug_dma_in (dpy_ba, dpy_pa10, pa10); + dpy_pa10 = pa10 = Map_Addr10 (ba, 1, &ubm);/* map addr */ + dpy_ba = ba; + if ((pa10 < 0) || MEM_ADDR_NXM (pa10)) {/* inv map or NXM? */ + ubcs[1] = ubcs[1] | UBCS_TMO; /* UBA timeout */ + uba_debug_dma_nxm ("Write Byte", pa10, ba, bc); + return (bc + seg); /* return bc */ + } + cp = np; + } + M[pa10++] = (((d10)((buf[1] << 8) | buf[0])) << 18) | /* <0:1,18:19> = 0 */ + ((buf[3] << 8) | buf[2]); + buf += 4; + } + } /* Body */ + +/* Tail: partial word, must be aligned */ + +assert ((bc >= 0) && ((ba & 3) == 0)); +if (bc) { + assert (bc <= 3); + np = UBMPAGE (ba); /* Only one word, last possible page crossing */ + if (np != cp) { /* New (or first) page? */ + uba_debug_dma_in (dpy_ba, dpy_pa10, pa10); + dpy_pa10 = pa10 = Map_Addr10 (ba, 1, &ubm);/* map addr */ + dpy_ba = ba; + if ((pa10 < 0) || MEM_ADDR_NXM (pa10)) { /* inv map or NXM? */ + ubcs[1] = ubcs[1] | UBCS_TMO; /* UBA timeout */ + uba_debug_dma_nxm ("Write Byte", pa10, ba, bc); + return (bc); /* return bc */ + } + } + m = M[pa10]; + if ((ubm & UMAP_RRV )) { /* RMW */ + switch (bc) { + case 3: + m = (m & M_BYTE2) | ((d10) (buf[2])); /* V_BYTE2 */ + case 2: + m = (m & M_BYTE1) | (((d10) (buf[1])) << V_BYTE1); + case 1: + m = (m & M_BYTE0) | (((d10) (buf[0])) << V_BYTE0); + break; + default: + assert (FALSE); + } + } + else { + switch (bc) { /* Write byte 0 + RMW bytes 1 & 2 */ + case 3: + m = (((d10) (buf[1])) << V_BYTE1) | (((d10) (buf[0])) << V_BYTE0) | + ((d10) (buf[2])); /* V_BYTE2 */ + break; + case 2: + m = (((d10) (buf[1])) << V_BYTE1) | (((d10) (buf[0])) << V_BYTE0); + break; + case 1: + m = ((d10) (buf[0])) << V_BYTE0; + break; + default: + assert (FALSE); + } + } + M[pa10++] = m; + } + +uba_debug_dma_in (dpy_ba, dpy_pa10, pa10); return 0; } +/* Word mode writes; 16-bit data */ + int32 Map_WriteW (uint32 ba, int32 bc, uint16 *buf) { -uint32 lim; -a10 pa10; -d10 val; +uint32 ea, cp, np; +int32 seg, ubm = 0; +a10 pa10 = ~0u; +uint32 dpy_ba = ba; +a10 dpy_pa10 = ~0u; -ba = ba & ~01; /* align start */ -lim = ba + (bc & ~01); -for ( ; ba < lim; ba = ba + 2) { /* by words */ - pa10 = Map_Addr10 (ba, 1); /* map addr */ - if ((pa10 < 0) || MEM_ADDR_NXM (pa10)) { /* inv map or NXM? */ - ubcs[1] = ubcs[1] | UBCS_TMO; /* UBA times out */ - return (lim - ba); /* return bc */ +if ((ba & ~((IO_M_UBA< bc) + seg = bc; + cp = UBMPAGE (ba); /* Only one word, can't cross page */ + dpy_pa10 = pa10 = Map_Addr10 (ba, 1, &ubm); /* map addr */ + dpy_ba = ba; + if ((pa10 < 0) || MEM_ADDR_NXM (pa10)) { /* inv map or NXM? */ + ubcs[1] = ubcs[1] | UBCS_TMO; /* UBA timeout */ + uba_debug_dma_nxm ("Write Word", pa10, ba, bc); + return bc; /* return bc */ + } + M[pa10] = (M[pa10] & M_WORD1) | ((d10) (*buf++)); + pa10++; + + if ((bc -= seg) == 0) { + uba_debug_dma_in (dpy_ba, dpy_pa10, pa10-dpy_pa10); + return 0; + } + ba += seg; + } /* Head */ + +ea = ba + bc; +seg = bc - (ea & 3); + +if (seg > 0) { + assert (((seg & 3) == 0) && (bc >= seg)); + bc -= seg; + for ( ; seg; seg -= 4, ba += 4) { /* aligned longwords */ + np = UBMPAGE (ba); + if (np != cp) { /* New (or first) page? */ + uba_debug_dma_in (dpy_ba, dpy_pa10, pa10); + dpy_pa10 = pa10 = Map_Addr10 (ba, 1, &ubm);/* map addr */ + dpy_ba = ba; + if ((pa10 < 0) || MEM_ADDR_NXM (pa10)) {/* inv map or NXM? */ + ubcs[1] = ubcs[1] | UBCS_TMO; /* UBA timeout */ + uba_debug_dma_nxm ("Write Word", pa10, ba, bc); + return (bc + seg); /* return bc */ + } + cp = np; + } + M[pa10++] = (((d10)(buf[0])) << V_WORD0) | buf[1];/* <0:1,18:19> = 0 + * V_WORD1 + */ + buf += 2; + } + } /* Body */ + +/* Tail: partial word, must be aligned, can only be WORD0 */ +assert ((bc >= 0) && ((ba & 3) == 0)); +if (bc) { + assert (bc == 2); + np = UBMPAGE (ba); /* Only one word, last possible page crossing */ + if (np != cp) { /* New (or first) page? */ + uba_debug_dma_in (dpy_ba, dpy_pa10, pa10); + dpy_pa10 = pa10 = Map_Addr10 (ba, 1, &ubm);/* map addr */ + dpy_ba = ba; + if ((pa10 < 0) || MEM_ADDR_NXM (pa10)) { /* inv map or NXM? */ + ubcs[1] = ubcs[1] | UBCS_TMO; /* UBA timeout */ + uba_debug_dma_nxm ("Write Word", pa10, ba, bc); + return (bc); /* return bc */ + } + } + if (ubm & UMAP_RRV ) /* Read reverse preserves RH */ + M[pa10] = (((d10)(buf[0])) << V_WORD0) | (M[pa10] & M_WORD0); + else + M[pa10] = ((d10)(buf[0])) << V_WORD0; + pa10++; + } + +uba_debug_dma_in (dpy_ba, dpy_pa10, pa10); return 0; } + +/* Word mode writes; 18-bit data */ + +int32 Map_WriteW18 (uint32 ba, int32 bc, uint32 *buf) +{ +uint32 ea, cp, np; +int32 seg, ubm = 0; +a10 pa10 = ~0u; +uint32 dpy_ba = ba; +a10 dpy_pa10 = ~0u; + +if ((ba & ~((IO_M_UBA< bc) + seg = bc; + cp = UBMPAGE (ba); /* Only one word, can't cross page */ + dpy_pa10 = pa10 = Map_Addr10 (ba, 1, &ubm); /* map addr */ + dpy_ba = ba; + if ((pa10 < 0) || MEM_ADDR_NXM (pa10)) { /* inv map or NXM? */ + ubcs[1] = ubcs[1] | UBCS_TMO; /* UBA timeout */ + uba_debug_dma_nxm ("Write 18b Word", pa10, ba, bc); + return bc; /* return bc */ + } + M[pa10] = (M[pa10] & M_WORD1) | ((d10) (M_WORD18 & *buf++)); /* V_WORD1 */ + pa10++; + + if ((bc -= seg) == 0) { + uba_debug_dma_in (dpy_ba, dpy_pa10, pa10-dpy_pa10); + return 0; + } + ba += seg; + } /* Head */ + +ea = ba + bc; +seg = bc - (ea & 3); + +if (seg > 0) { + assert (((seg & 3) == 0) && (bc >= seg)); + bc -= seg; + for ( ; seg; seg -= 4, ba += 4) { /* aligned longwords */ + np = UBMPAGE (ba); + if (np != cp) { /* New (or first) page? */ + uba_debug_dma_in (dpy_ba, dpy_pa10, pa10); + dpy_pa10 = pa10 = Map_Addr10 (ba, 1, &ubm);/* map addr */ + dpy_ba = ba; + if ((pa10 < 0) || MEM_ADDR_NXM (pa10)) {/* inv map or NXM? */ + ubcs[1] = ubcs[1] | UBCS_TMO; /* UBA timeout */ + uba_debug_dma_nxm ("Write 18b Word", pa10, ba, bc); + return (bc + seg); /* return bc */ + } + cp = np; + } + M[pa10++] = (((d10)(M_WORD18 & buf[0])) << V_WORD0) | (M_WORD18 & buf[1]);/* V_WORD1 */ + buf += 2; + } + } /* Body */ + +/* Tail: partial word, must be aligned */ +assert ((bc >= 0) && ((ba & 3) == 0)); +if (bc) { + assert (bc == 2); + np = UBMPAGE (ba); /* Only one word, last possible page crossing */ + if (np != cp) { /* New (or first) page? */ + uba_debug_dma_in (dpy_ba, dpy_pa10, pa10); + dpy_pa10 = pa10 = Map_Addr10 (ba, 1, &ubm);/* map addr */ + dpy_ba = ba; + if ((pa10 < 0) || MEM_ADDR_NXM (pa10)) { /* inv map or NXM? */ + ubcs[1] = ubcs[1] | UBCS_TMO; /* UBA timeout */ + uba_debug_dma_nxm ("Write 18b Word", pa10, ba, bc); + return (bc); /* return bc */ + } + } + if (ubm & UMAP_RRV ) /* Read reverse preserves RH */ + M[pa10] = (M[pa10] & M_WORD0) | (((d10)(M_WORD18 & buf[0])) << V_WORD0); + else + M[pa10] = ((d10)(M_WORD18 & buf[0])) << V_WORD0; + pa10++; + } + +uba_debug_dma_in (dpy_ba, dpy_pa10, pa10); +return 0; +} + +/* Word mode writes; 36-bit data */ + +int32 Map_WriteW36 (uint32 ba, int32 bc, a10 *buf) +{ +uint32 ea, cp, np; +int32 seg, ubm = 0; +a10 pa10 = ~0u; +uint32 dpy_ba = ba; +a10 dpy_pa10 = ~0u; + +if ((ba & ~((IO_M_UBA< 0) { + assert (((seg & 3) == 0) && (bc >= seg)); + bc -= seg; + for ( ; seg; seg -= 4, ba += 4) { /* aligned longwords */ + np = UBMPAGE (ba); + if (np != cp) { /* New (or first) page? */ + uba_debug_dma_in (dpy_ba, dpy_pa10, pa10); + dpy_pa10 = pa10 = Map_Addr10 (ba, 1, &ubm);/* map addr */ + dpy_ba = ba; + if ((pa10 < 0) || MEM_ADDR_NXM (pa10)) {/* inv map or NXM? */ + ubcs[1] = ubcs[1] | UBCS_TMO; /* UBA timeout */ + uba_debug_dma_nxm ("Write 18b Word", pa10, ba, bc); + return (bc + seg); /* return bc */ + } + cp = np; + } + M[pa10++] = (((d10)(M_WORD18 & buf[0])) << V_WORD0) | (M_WORD18 & buf[1]);/* V_WORD1 */ + buf += 2; + } + } /* Body */ + +uba_debug_dma_in (dpy_ba, dpy_pa10, pa10); +return 0; +} + +void +uba_debug_dma (int32 mask, uint32 ba, a10 pa_start, a10 pa_end) +{ +int32 i; +int32 wc = (int32)(pa_end - pa_start); + +if ((!wc) || (!(sim_deb && (uba_dev.dctrl & mask)))) + return; +sim_debug (mask, &uba_dev, "DMA Bus Address: 0%o, Memory Address: %07o of %o word%s\n", ba, pa_start, wc, (wc>1) ? "s" : ""); +for (i=0; i>V_WORD0)&M_WORD18), + (int)((d>>V_WORD1)&M_WORD18)); + sprintf (words, "0x%05X: %04X,,%04X", pa_start+i, (int)((d>>V_WORD0)&M_WORD), + (int)((d>>V_WORD1)&M_WORD)); + sprintf (bytes, "%02X %02X %02X %02X", (int)(((d&~M_BYTE0)>>V_BYTE0)&M_BYTE), + (int)(((d&~M_BYTE1)>>V_BYTE1)&M_BYTE), + (int)(((d&~M_BYTE2)>>V_BYTE2)&M_BYTE), + (int)(((d&~M_BYTE3)>>V_BYTE3)&M_BYTE)); + strcpy (ascii, "'.....'"); + for (j=1; j<=5; j++) + { + c = 0x7F&(d>>(36-(j*7))); + if (isprint(c)) + ascii[j] = c; + } + strcpy (sixbit, "'.....'"); + for (j=1; j<=6; j++) + { + c = 0x3F&(d>>(36-(j*6))); + sixbit[j] = c + 32; + } + sim_debug (mask, &uba_dev, "%s | %s | %s | %s | %s\n", octal, words, bytes, ascii, sixbit); + } +} + +void +uba_debug_dma_in (uint32 ba, a10 pa_start, a10 pa_end) +{ +uba_debug_dma (DBG_DMA_IN, ba, pa_start, pa_end); +} + +void +uba_debug_dma_out (uint32 ba, a10 pa_start, a10 pa_end) +{ +uba_debug_dma (DBG_DMA_OUT, ba, pa_start, pa_end); +} + +void +uba_debug_dma_nxm (const char *msg, a10 pa10, uint32 ba, int32 bc) +{ +sim_debug (DBG_DMA_NXM, &uba_dev, "%s Error at address=%7o, ba=%o, bc=%o\n", msg, pa10, ba, bc); +} + /* Evaluate Unibus priority interrupts */ int32 pi_ub_eval () @@ -619,7 +1619,23 @@ int32 n = iocmap[GET_IOUBA (pa)]; if (n < 0) ABORT (STOP_ILLIOC); if (val & UBCS_INI) { - reset_all (5); /* start after UBA */ + DEVICE *dptr; + int i; + + for (i=0; (dptr = sim_devices[i]) != NULL; i++) { + if (dptr == &uba_dev) { + ++i; /* start after UBA */ + break; + } + } + /* Now find the devices which are attached to this UBA and reset them */ + for (; (dptr = sim_devices[i]) != NULL; i++) { + DIB *dibp = (DIB *)dptr->ctxt; + + if ((n == iocmap[GET_IOUBA (dibp->ba)]) && + (dptr->reset != NULL)) + dptr->reset (dptr); + } ubcs[n] = val & UBCS_DXF; } else ubcs[n] = val & UBCS_RDW; @@ -722,7 +1738,10 @@ dptr = find_dev_from_unit (uptr); if (dptr == NULL) return SCPE_IERR; dibp = (DIB *) dptr->ctxt; -if ((dibp == NULL) || (dibp->ba <= IOPAGEBASE)) +if (dibp == NULL) + return SCPE_IERR; +if (((dibp->ba>>IO_V_UBA) != 1) && + ((dibp->ba>>IO_V_UBA) != 3)) return SCPE_IERR; fprintf (st, "address=%07o", dibp->ba); if (dibp->lnt > 1) @@ -817,10 +1836,7 @@ for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { /* loop thru dev */ (curr->ba < (dibp->ba + dibp->lnt))) || ((end >= dibp->ba) && /* overlap end? */ (end < (dibp->ba + dibp->lnt)))) { - printf ("Device %s address conflict at %08o\n", - sim_dname (dptr), dibp->ba); - if (sim_log) - fprintf (sim_log, "Device %s address conflict at %08o\n", + sim_printf ("Device %s address conflict at %08o\n", sim_dname (dptr), dibp->ba); return TRUE; } @@ -849,7 +1865,7 @@ DIB *dibp; for (i = 0; i < 32; i++) { /* clear intr tables */ int_vec[i] = 0; int_ack[i] = NULL; - } + } for (i = j = 0; (dptr = sim_devices[i]) != NULL; i++) { /* loop thru dev */ dibp = (DIB *) dptr->ctxt; /* get DIB */ if (dibp && !(dptr->flags & DEV_DIS)) { /* defined, enabled? */ @@ -898,6 +1914,8 @@ while (done == 0) { /* sort ascending */ } } } /* end while */ +fprintf (st, " Address Vector BR Device\n" + "----------------- -------- -- ------\n"); for (i = 0; dib_tab[i] != NULL; i++) { /* print table */ for (j = 0, dptr = NULL; sim_devices[j] != NULL; j++) { if (((DIB*) sim_devices[j]->ctxt) == dib_tab[i]) { @@ -905,9 +1923,24 @@ for (i = 0; dib_tab[i] != NULL; i++) { /* print table */ break; } } - fprintf (st, "%07o - %07o\t%s\n", dib_tab[i]->ba, - dib_tab[i]->ba + dib_tab[i]->lnt - 1, - dptr? sim_dname (dptr): "CPU"); + fprintf (st, "%07o - %07o ", dib_tab[i]->ba, + dib_tab[i]->ba + dib_tab[i]->lnt - 1); + if (dib_tab[i]->vec == 0) + fprintf (st, " "); + else { + fprintf (st, "%03o", dib_tab[i]->vec); + if (dib_tab[i]->vnum > 1) + fprintf (st, "-%03o", dib_tab[i]->vec + (4 * (dib_tab[i]->vnum - 1))); + else + fprintf (st, " "); + } + if (dib_tab[i]->vec || dib_tab[i]->vloc) + fprintf (st, " %2u ", (dib_tab[i]->vloc<=3)? 7: + (dib_tab[i]->vloc<=7)? 6: + (dib_tab[i]->vloc<=19)? 5: 4); + else + fprintf (st, " "); + fprintf (st, " %s\n", (dptr? sim_dname (dptr): "CPU")); } return SCPE_OK; } diff --git a/PDP10/pdp10_lp20.c b/PDP10/pdp10_lp20.c index 64f2ccba..10662e09 100644 --- a/PDP10/pdp10_lp20.c +++ b/PDP10/pdp10_lp20.c @@ -25,6 +25,10 @@ lp20 line printer + 23-Jun-13 TL Add optical VFU support and fix some inconsistencies + with the hardware. Add documentation. + 29-May-13 TL Force append when an existing file is attached. + Previously over-wrote file from the top. 19-Jan-07 RMS Added UNIT_TEXT flag 04-Sep-05 RMS Fixed missing return (found by Peter Schorn) 07-Jul-05 RMS Removed extraneous externs @@ -37,31 +41,59 @@ 30-May-02 RMS Widened POS to 32b 06-Jan-02 RMS Added enable/disable support 30-Nov-01 RMS Added extended SET/SHOW support + + References: + EK-LP20-TM-004 LP20 LINE PRINTER SYSTEM MANUAL + B-TC-LP20-0-1 MP0006 LP20 Field Maintenance Print Set + DpC255137D Dataproducts Corp Maintenance Guide Vol. I + 300LPM/600 LPM Line Printers. + LP2SER.MAC TOPS-10 Device driver + LPKSDV.MAC TOPS-20 Device driver + LP20.MAC TOPS-10/20 VFU/RAM utility + LPTSPL/LPTSUB.MAC TOPS-10/20 GALAXY spooler */ #include "pdp10_defs.h" +#include + +/* Time (seconds) of idleness before data flushed to attached file. */ +#ifndef LP20_IDLE_TIME +#define LP20_IDLE_TIME (10) +#endif + +/* The LP20 has the following CSR assignments: + * Unit No. 1: 775400, Vector: 754 + * Unit No. 2: 775420, Vector: 750 + * + * Note that the KS only supported one LP20. + * Note also that the vector assigned to unit 2 is lower than unit 1's. + */ #define UNIT_DUMMY (1 << UNIT_V_UF) #define LP_WIDTH 132 /* printer width */ - +#define DEFAULT_LPI 6 /* default lines-per-inch of LPT */ /* DAVFU RAM */ #define DV_SIZE 143 /* DAVFU size */ #define DV_DMASK 077 /* data mask per byte */ #define DV_TOF 0 /* top of form channel */ +#define DV_BOF 11 /* bottom of form channel */ #define DV_MAX 11 /* max channel number */ +#define MIN_VFU_LEN 2 /* minimum VFU length (in inches) */ +#define VFU_LEN_VALID(lines, lpi) ((lines) >= (lpi * MIN_VFU_LEN)) /* Translation RAM */ #define TX_SIZE 256 /* translation RAM */ #define TX_AMASK (TX_SIZE - 1) -#define TX_DMASK 07777 +#define TX_DMASK 007777 +#define TX_PARITY 010000 /* Parity bit (emulated: 'valid'; unwritten has bad 'parity') */ #define TX_V_FL 8 /* flags */ #define TX_M_FL 017 -/* define TX_INTR 04000 /* interrupt */ +/* define TX_INTR 04000 *//* interrupt */ #define TX_DELH 02000 /* delimiter */ -/* define TX_XLAT 01000 /* translate */ -/* define TX_DVFU 00400 /* DAVFU */ +/* define TX_XLAT 01000 *//* translate */ +/* define TX_DVFU 00400 *//* DAVFU */ #define TX_SLEW 00020 /* chan vs slew */ #define TX_VMASK 00017 /* spacing mask */ #define TX_CHR 0 /* states: pr char */ @@ -104,13 +136,13 @@ #define CSB_GOE 0000001 /* go error */ #define CSB_DTE 0000002 /* DEM timing error NI */ #define CSB_MTE 0000004 /* MSYN error (Ubus timeout) */ -#define CSB_RPE 0000010 /* RAM parity error NI */ +#define CSB_RPE 0000010 /* RAM parity error */ #define CSB_MPE 0000020 /* MEM parity error NI */ #define CSB_LPE 0000040 /* LPT parity error NI */ #define CSB_DVOF 0000100 /* DAVFU not ready */ #define CSB_OFFL 0000200 /* offline */ #define CSB_TEST 0003400 /* test mode */ -#define CSB_OVFU 0004000 /* optical VFU NI */ +#define CSB_OVFU 0004000 /* optical VFU */ #define CSB_PBIT 0010000 /* data parity bit NI */ #define CSB_NRDY 0020000 /* printer error NI */ #define CSB_LA180 0040000 /* LA180 printer NI */ @@ -118,7 +150,7 @@ #define CSB_ECLR (CSB_GOE | CSB_DTE | CSB_MTE | CSB_RPE | CSB_MPE | CSB_LPE) #define CSB_ERR (CSB_ECLR | CSB_DVOF | CSB_OFFL) #define CSB_RW CSB_TEST -#define CSB_MBZ (CSB_DTE | CSB_RPE | CSB_MPE | CSB_LPE | CSB_OVFU |\ +#define CSB_MBZ (CSB_DTE | CSB_RPE | CSB_MPE | CSB_LPE | \ CSB_PBIT | CSB_NRDY | CSB_LA180 | CSB_VLD) /* LPBA (765404) */ @@ -139,39 +171,126 @@ /* LPCSUM/LPPDAT (765516) */ -extern d10 *M; /* main memory */ extern int32 int_req; -int32 lpcsa = 0; /* control/status A */ -int32 lpcsb = 0; /* control/status B */ -int32 lpba = 0; /* bus address */ -int32 lpbc = 0; /* byte count */ -int32 lppagc = 0; /* page count */ -int32 lprdat = 0; /* RAM data */ -int32 lpcbuf = 0; /* character buffer */ -int32 lpcolc = 0; /* column count */ -int32 lppdat = 0; /* printer data */ -int32 lpcsum = 0; /* checksum */ -int32 dvptr = 0; /* davfu pointer */ -int32 dvlnt = 0; /* davfu length */ -int32 lp20_irq = 0; /* int request */ -int32 lp20_stopioe = 0; /* stop on error */ -int16 txram[TX_SIZE] = { 0 }; /* translation RAM */ -int16 davfu[DV_SIZE] = { 0 }; /* DAVFU */ +static int32 lpcsa = 0; /* control/status A */ +static int32 lpcsb = CSB_DVOF; /* control/status B */ +static int32 lpba = 0; /* bus address */ +static int32 lpbc = 0; /* byte count */ +static int32 lppagc = 0; /* page count */ +static int32 lprdat = 0; /* RAM data */ +static int32 lpcbuf = 0; /* character buffer */ +static int32 lpcolc = 0; /* column count */ +static int32 lppdat = 0; /* printer data */ +static int32 lpcsum = 0; /* checksum */ +static int32 dvptr = 0; /* davfu pointer */ +static int32 dvlnt = 0; /* davfu length */ +static int32 lp20_irq = 0; /* int request */ +static int32 lp20_stopioe = 0; /* stop on error */ +static int32 dvld = 0; +static int32 dvld_hold = 0; +static int32 lpi = DEFAULT_LPI; /* Printer's LPI. */ +static int16 txram[TX_SIZE] = { 0 }; /* translation RAM */ +static int16 davfu[DV_SIZE] = { 0 }; /* DAVFU */ DEVICE lp20_dev; -t_stat lp20_rd (int32 *data, int32 pa, int32 access); -t_stat lp20_wr (int32 data, int32 pa, int32 access); -int32 lp20_inta (void); -t_stat lp20_svc (UNIT *uptr); -t_stat lp20_reset (DEVICE *dptr); -t_stat lp20_attach (UNIT *uptr, char *ptr); -t_stat lp20_detach (UNIT *uptr); -t_stat lp20_clear_vfu (UNIT *uptr, int32 val, char *cptr, void *desc); -t_bool lp20_print (int32 c); -t_bool lp20_adv (int32 c, t_bool advdvu); -t_bool lp20_davfu (int32 c); -void update_lpcs (int32 flg); +static t_stat lp20_rd (int32 *data, int32 pa, int32 access); +static t_stat lp20_wr (int32 data, int32 pa, int32 access); +static int32 lp20_inta (void); +static t_stat lp20_svc (UNIT *uptr); +static t_stat lp20_reset (DEVICE *dptr); +static t_stat lp20_init (DEVICE *dptr); +static t_stat lp20_attach (UNIT *uptr, char *ptr); +static t_stat lp20_detach (UNIT *uptr); +static t_stat lp20_set_lpi (UNIT *uptr, int32 val, char *cptr, void *desc); +static t_stat lp20_show_lpi (FILE *st, UNIT *up, int32 v, void *dp); +static t_stat lp20_set_vfu_type (UNIT *uptr, int32 val, char *cptr, void *desc); +static t_stat lp20_show_vfu_type (FILE *st, UNIT *up, int32 v, void *dp); +static t_stat lp20_show_vfu (FILE *st, UNIT *up, int32 v, void *dp); +static t_stat lp20_set_tof (UNIT *uptr, int32 val, char *cptr, void *desc); +static t_stat lp20_clear_vfu (UNIT *uptr, int32 val, char *cptr, void *desc); +static t_bool lp20_print (int32 c); +static t_bool lp20_adv (int32 c, t_bool advdvu); +static t_bool lp20_davfu (int32 c); +static void update_lpcs (int32 flg); +static void change_rdy (int32 setrdy, int32 clrrdy); +static int16 evenbits (int16 value); +static t_stat lp20_help (FILE *st, struct sim_device *dptr, + struct sim_unit *uptr, int32 flag, const char *cptr); +static const char *lp20_description (DEVICE *dptr); + +/* DEC standard VFU tape for 'optical' VFU default. + * Note that this must be <= DV_SIZE as we copy it into the DAVFU. + */ +static const int16 defaultvfu[] = { /* Generated by vfu.pl per DEC HRM */ + /* 66 line page with 6 line margin */ + 00377, /* Line 0 8 7 6 5 4 3 2 1 */ + 00220, /* Line 1 8 5 */ + 00224, /* Line 2 8 5 3 */ + 00230, /* Line 3 8 5 4 */ + 00224, /* Line 4 8 5 3 */ + 00220, /* Line 5 8 5 */ + 00234, /* Line 6 8 5 4 3 */ + 00220, /* Line 7 8 5 */ + 00224, /* Line 8 8 5 3 */ + 00230, /* Line 9 8 5 4 */ + 00264, /* Line 10 8 6 5 3 */ + 00220, /* Line 11 8 5 */ + 00234, /* Line 12 8 5 4 3 */ + 00220, /* Line 13 8 5 */ + 00224, /* Line 14 8 5 3 */ + 00230, /* Line 15 8 5 4 */ + 00224, /* Line 16 8 5 3 */ + 00220, /* Line 17 8 5 */ + 00234, /* Line 18 8 5 4 3 */ + 00220, /* Line 19 8 5 */ + 00364, /* Line 20 8 7 6 5 3 */ + 00230, /* Line 21 8 5 4 */ + 00224, /* Line 22 8 5 3 */ + 00220, /* Line 23 8 5 */ + 00234, /* Line 24 8 5 4 3 */ + 00220, /* Line 25 8 5 */ + 00224, /* Line 26 8 5 3 */ + 00230, /* Line 27 8 5 4 */ + 00224, /* Line 28 8 5 3 */ + 00220, /* Line 29 8 5 */ + 00276, /* Line 30 8 6 5 4 3 2 */ + 00220, /* Line 31 8 5 */ + 00224, /* Line 32 8 5 3 */ + 00230, /* Line 33 8 5 4 */ + 00224, /* Line 34 8 5 3 */ + 00220, /* Line 35 8 5 */ + 00234, /* Line 36 8 5 4 3 */ + 00220, /* Line 37 8 5 */ + 00224, /* Line 38 8 5 3 */ + 00230, /* Line 39 8 5 4 */ + 00364, /* Line 40 8 7 6 5 3 */ + 00220, /* Line 41 8 5 */ + 00234, /* Line 42 8 5 4 3 */ + 00220, /* Line 43 8 5 */ + 00224, /* Line 44 8 5 3 */ + 00230, /* Line 45 8 5 4 */ + 00224, /* Line 46 8 5 3 */ + 00220, /* Line 47 8 5 */ + 00234, /* Line 48 8 5 4 3 */ + 00220, /* Line 49 8 5 */ + 00264, /* Line 50 8 6 5 3 */ + 00230, /* Line 51 8 5 4 */ + 00224, /* Line 52 8 5 3 */ + 00220, /* Line 53 8 5 */ + 00234, /* Line 54 8 5 4 3 */ + 00220, /* Line 55 8 5 */ + 00224, /* Line 56 8 5 3 */ + 00230, /* Line 57 8 5 4 */ + 00224, /* Line 58 8 5 3 */ + 00220, /* Line 59 8 5 */ + 00020, /* Line 60 5 */ + 00020, /* Line 61 5 */ + 00020, /* Line 62 5 */ + 00020, /* Line 63 5 */ + 00020, /* Line 64 5 */ + 04020, /* Line 65 12 5 */ +}; /* LP data structures @@ -180,28 +299,65 @@ void update_lpcs (int32 flg); lp20_reg LPT register list */ -DIB lp20_dib = { +static DIB lp20_dib = { IOBA_LP20, IOLN_LP20, &lp20_rd, &lp20_wr, 1, IVCL (LP20), VEC_LP20, { &lp20_inta } }; -UNIT lp20_unit = { +/* Actual device timing varies depending on the printer. + * Printers used with the LP20 include both drum and band printers. + * Nominal speeds ranged from 200 LPM to 1250 LPM. Besides speed, + * the major variants were: Optical vs DAVFU, 64 vs. 96 character + * band/drum, and scientific vs. EDP fonts. Scientific used slashed + * Z and 0; EDP did not. All supported 132 colum output at a pitch + * of 10 CPI. Some had operator switch-selectable vertical pitches + * for either 6 or 8 LPI. Paper and ribbon are hit by a hammer onto + * the rotating drum when the desired character is in front of the + * hammer. Thus, a line that contains all the characters on a drum + * would take one full revolution to print, plus paper motion time. + * (Assuming no overstrikes.) At 100 RPM, this translates to 16.7 ms + * printing + 41 ms motion for the LP05. The math works out to 1,040 + * LPM, but the rated speeds account for slew in the margins and some + * overstrikes (most commonly underline.) One could construct data + * patterns that overlapped some paper motion with unused character + * time on the drum. So the LP10, with 14 ms line advance could + * print the alphabet using 1/2 a rotation and move the paper in the + * other half - about 50% faster than rated speed. Bands move the + * characters horizontally (similar to chain/train printers), but + * the basic timing constraints are similar. + * + * Timing for several printers: a/b is 64/96 character set value. + * LP05 LP07 LP10 LP14 + * Line advance: 41 ms 12.5 ms 14 ms 20 ms + * Slew: 20 ips 60 ips 35 ips 22.5 @8LPi/30 @6 + * Drum Rotation: 1000/600 RPM band 1800/1200 1280/857 + * Rated LPM: 230/300 1220/905 1250/925 890/650 + * Weight lb/kg 340/154 800/363 800/363 420/191 + * + * There is a variant that was designed to drive an LA180 with either + * a 7 or 8 bit parallel interface. The prints label it 'not a standard + * product'. It's not implemented in this emulation. + */ + +static UNIT lp20_unit = { UDATA (&lp20_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_TEXT, 0), SERIAL_OUT_WAIT }; -REG lp20_reg[] = { +static REG lp20_reg[] = { { ORDATA (LPCSA, lpcsa, 16) }, { ORDATA (LPCSB, lpcsb, 16) }, { ORDATA (LPBA, lpba, 16) }, { ORDATA (LPBC, lpbc, 12) }, { ORDATA (LPPAGC, lppagc, 12) }, - { ORDATA (LPRDAT, lprdat, 12) }, + { ORDATA (LPRDAT, lprdat, 13) }, { ORDATA (LPCBUF, lpcbuf, 8) }, { ORDATA (LPCOLC, lpcolc, 8) }, { ORDATA (LPPDAT, lppdat, 8) }, { ORDATA (LPCSUM, lpcsum, 8) }, { ORDATA (DVPTR, dvptr, 7) }, { ORDATA (DVLNT, dvlnt, 7), REG_RO + REG_NZ }, + { ORDATA (DVLD, dvld, 2), REG_RO | REG_HIDDEN }, + { ORDATA (DVLDH, dvld_hold, 6), REG_RO | REG_HIDDEN }, { FLDATA (INT, int_req, INT_V_LP20) }, { FLDATA (IRQ, lp20_irq, 0) }, { FLDATA (ERR, lpcsa, CSR_V_ERR) }, @@ -210,19 +366,29 @@ REG lp20_reg[] = { { DRDATA (POS, lp20_unit.pos, T_ADDR_W), PV_LEFT }, { DRDATA (TIME, lp20_unit.wait, 24), PV_LEFT }, { FLDATA (STOP_IOE, lp20_stopioe, 0) }, - { BRDATA (TXRAM, txram, 8, 12, TX_SIZE) }, + { BRDATA (TXRAM, txram, 8, 13, TX_SIZE) }, { BRDATA (DAVFU, davfu, 8, 12, DV_SIZE) }, + { DRDATA (LPI, lpi, 8), REG_RO | REG_HIDDEN }, { ORDATA (DEVADDR, lp20_dib.ba, 32), REG_HRO }, { ORDATA (DEVVEC, lp20_dib.vec, 16), REG_HRO }, { NULL } }; -MTAB lp20_mod[] = { - { UNIT_DUMMY, 0, NULL, "VFUCLEAR", &lp20_clear_vfu }, +static MTAB lp20_mod[] = { { MTAB_XTD|MTAB_VDV, 004, "ADDRESS", "ADDRESS", &set_addr, &show_addr, NULL }, { MTAB_XTD|MTAB_VDV, 0, "VECTOR", "VECTOR", &set_vec, &show_vec, NULL }, + { MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "VFU", NULL, NULL, &lp20_show_vfu, + NULL, "Display VFU tape/contents" }, + { MTAB_XTD|MTAB_VDV|MTAB_NC, 0, "VFUTYPE", "VFUTYPE={DAVFU|OPTICAL{=tapefile}}", + &lp20_set_vfu_type, &lp20_show_vfu_type, NULL, NULL }, + { MTAB_XTD|MTAB_VDV, 0, "LPI", "LPI={6-LPI|8-LPI}", &lp20_set_lpi, &lp20_show_lpi, + NULL, "Printer vertical lines per inch" }, + { UNIT_DUMMY, 0, NULL, "TOPOFFORM", &lp20_set_tof, NULL, + NULL, "Advance to top-of-form" }, + { UNIT_DUMMY, 0, NULL, "VFUCLEAR", &lp20_clear_vfu, NULL, + NULL, "Clear the VFU & Translation RAM" }, { 0 } }; @@ -231,7 +397,7 @@ DEVICE lp20_dev = { 1, 10, 31, 1, 8, 8, NULL, NULL, &lp20_reset, NULL, &lp20_attach, &lp20_detach, - &lp20_dib, DEV_DISABLE | DEV_UBUS + &lp20_dib, DEV_DISABLE | DEV_UBUS, 0 }; /* Line printer routines @@ -244,17 +410,21 @@ DEVICE lp20_dev = { lp20_detach process detach */ -t_stat lp20_rd (int32 *data, int32 pa, int32 access) +static t_stat lp20_rd (int32 *data, int32 pa, int32 access) { update_lpcs (0); /* update csr's */ switch ((pa >> 1) & 07) { /* case on PA<3:1> */ case 00: /* LPCSA */ *data = lpcsa = lpcsa & ~CSA_MBZ; + if (lpcsb & CSB_OVFU) /* Optical: no DAVFU present */ + *data &= ~CSA_DVON; break; case 01: /* LPCSB */ *data = lpcsb = lpcsb & ~CSB_MBZ; + if (lpcsb & CSB_OVFU) + *data &= ~CSB_DVOF; break; case 02: /* LPBA */ @@ -270,7 +440,11 @@ switch ((pa >> 1) & 07) { /* case on PA<3:1> */ break; case 05: /* LPRDAT */ - *data = lprdat = lprdat & RDAT_MASK; + *data = lprdat & RDAT_MASK; + if (evenbits((int16)*data)) + *data |= TX_PARITY; + if (((lprdat & TX_PARITY) == 0) && (lpcsa & CSA_PAR)) /* Data invalid & parity checked? */ + *data ^= TX_PARITY; /* Invalid: Provide bad parity */ break; case 06: /* LPCOLC/LPCBUF */ @@ -285,7 +459,7 @@ switch ((pa >> 1) & 07) { /* case on PA<3:1> */ return SCPE_OK; } -t_stat lp20_wr (int32 data, int32 pa, int32 access) +static t_stat lp20_wr (int32 data, int32 pa, int32 access) { update_lpcs (0); /* update csr's */ switch ((pa >> 1) & 07) { /* case on PA<3:1> */ @@ -293,13 +467,18 @@ switch ((pa >> 1) & 07) { /* case on PA<3:1> */ case 00: /* LPCSA */ if (access == WRITEB) data = (pa & 1)? (lpcsa & 0377) | (data << 8): (lpcsa & ~0377) | data; + /* In hardware, a write that sets GO must not change any other + * bits in CSRA due to timing restrictions. Modifying any bits in + * CSRA while GO is set "may destroy the contents of the checksum register + * and produce other undesirable effects." + */ if (data & CSA_ECLR) { /* error clear? */ lpcsa = (lpcsa | CSA_DONE) & ~CSA_GO; /* set done, clr go */ lpcsb = lpcsb & ~CSB_ECLR; /* clear err */ sim_cancel (&lp20_unit); /* cancel I/O */ } if (data & CSA_INIT) /* init? */ - lp20_reset (&lp20_dev); + lp20_init (&lp20_dev); if (data & CSA_GO) { /* go set? */ if ((lpcsa & CSA_GO) == 0) { /* not set before? */ if (lpcsb & CSB_ERR) @@ -310,6 +489,10 @@ switch ((pa >> 1) & 07) { /* case on PA<3:1> */ } else sim_cancel (&lp20_unit); /* go clr, stop DMA */ lpcsa = (lpcsa & ~CSA_RW) | (data & CSA_RW); + if (dvld && (CSA_GETFNC (lpcsa) != FNC_DVU)) { /* DVU load aborted */ + change_rdy (0, CSA_DVON); /* Mark DVU off-line and empty */ + dvlnt = 0; + } break; case 01: /* LPCSB */ @@ -332,13 +515,14 @@ switch ((pa >> 1) & 07) { /* case on PA<3:1> */ if (access == WRITEB) data = (pa & 1)? (lppagc & 0377) | (data << 8): (lppagc & ~0377) | data; lppagc = data & PAGC_MASK; + lpcsa &= ~CSA_PZRO; /* Note that even if at TOF, PZRO does not set */ break; case 05: /* LPRDAT */ if (access == WRITEB) data = (pa & 1)? (lprdat & 0377) | (data << 8): (lprdat & ~0377) | data; lprdat = data & RDAT_MASK; - txram[lpcbuf & TX_AMASK] = lprdat; /* load RAM */ + txram[lpcbuf & TX_AMASK] = (int16)(lprdat | TX_PARITY);/* load RAM and mark valid */ break; case 06: /* LPCOLC/LPCBUF */ @@ -374,23 +558,22 @@ return SCPE_OK; else if (paper) davfu_action; else print_xlate; - } + } else if (paper) { if (xlate || delim || delim_hold) davfu_action; else print_input; - } + } else { if (xlate || delim || delim_hold) print_xlate; else print_input; - } + } */ -t_stat lp20_svc (UNIT *uptr) +static t_stat lp20_svc (UNIT *uptr) { -int32 fnc, i, tbc, temp, txst; -int32 dvld = -2; /* must be even */ +int32 fnc, i, tbc, txst; uint16 wd10; t_bool cont; a10 ba; @@ -410,7 +593,7 @@ if (((fnc & FNC_INTERNAL) == 0) && ((lp20_unit.flags & UNIT_ATT) == 0)) { update_lpcs (CSA_ERR); return IORETURN (lp20_stopioe, SCPE_UNATT); } -if ((fnc == FNC_PR) && (dvlnt == 0)) { +if ((fnc == FNC_PR) && (lpcsb & CSB_DVOF)) { update_lpcs (CSA_ERR); return SCPE_OK; } @@ -428,37 +611,76 @@ for (i = 0, cont = TRUE; (i < tbc) && cont; ba++, i++) { /* Translation RAM load */ case FNC_RAM: /* RAM load */ - txram[(i >> 1) & TX_AMASK] = wd10 & TX_DMASK; + txram[(i >> 1) & TX_AMASK] = (wd10 & TX_DMASK) | TX_PARITY; break; /* DAVFU RAM load. The DAVFU RAM is actually loaded in bytes, delimited by a start (354 to 356) and stop (357) byte pair. If the number of bytes loaded is odd, or no bytes are loaded, the DAVFU is invalid. + Thus, with DVU load mode set in CSRA, there are three states: + 0) Inactive 2) Start code seen,even byte 3) Start code seen, odd byte. + Normally, only a start or a stop code should be seen in (0), but any other + code that is received is ignored. A stop without a corresponding start is + legal, and specified to reset the current line pointer to 0 without + modifying the content of the RAM. + The DAVFU is physically in the printer, so printers with an optical + VFU see load data as normal data to be printed. The LP20 logic inhibits + the translation RAM in this mode, so any translation will not occur. + This is an unexpected condition; the OS/User should check the optical + VFU bit before attempting to load a DAVFU. */ case FNC_DVU: /* DVU load */ - if ((lpcbuf >= 0354) && (lpcbuf <= 0356)) /* start DVU load? */ - dvld = dvlnt = 0; /* reset lnt */ + if (lpcsb & CSB_OVFU) { + /* OS should not attempt to load VFU if printer has Optical VFU. + * The DAVFU is in the printer, so it will see the attempted load + * as print data. The LP20 inhibits translation. + */ + cont = lp20_print (lpcbuf); + break; + } + if ((lpcbuf >= 0354) && (lpcbuf <= 0356)) { /* start DVU load? */ + dvlnt = 0; /* reset lnt */ + dvld = 2; /* Load is active, even */ + if (lpcbuf == 0354) + lpi = 6; + else if (lpcbuf == 0355) + lpi = 8; + } else if (lpcbuf == 0357) { /* stop DVU load? */ dvptr = 0; /* reset ptr */ - if (dvld & 1) /* if odd, invalid */ - dvlnt = 0; - } - else if (dvld == 0) { /* even state? */ - temp = lpcbuf & DV_DMASK; - dvld = 1; - } - else if (dvld == 1) { /* odd state? */ - if (dvlnt < DV_SIZE) - davfu[dvlnt++] = temp | ((lpcbuf & DV_DMASK) << 6); dvld = 0; + if ((dvld & 1) || !VFU_LEN_VALID(dvlnt, lpi)) { /* if odd or invalid length */ + dvlnt = 0; + change_rdy (0, CSA_DVON); + } + else change_rdy(CSA_DVON, 0); + } + else if (dvld == 2) { /* even state? */ + dvld_hold = lpcbuf & DV_DMASK; + dvld = 3; + } + else if (dvld == 3) { /* odd state? */ + if (dvlnt < DV_SIZE) { + davfu[dvlnt++] = (int16)(dvld_hold | ((lpcbuf & DV_DMASK) << 6)); + dvld = 2; + } + else { + change_rdy (0, CSA_DVON); + dvlnt = dvld = 0; + } } break; -/* Print characters */ +/* Print characters through the translation RAM */ case FNC_PR: /* print */ lprdat = txram[lpcbuf]; /* get RAM char */ + if (((lprdat & TX_PARITY) == 0) && (lpcsa & CSA_PAR)) { /* Check for valid */ + lpcsb |= CSB_RPE; /* Declare RAM parity error */ + cont = FALSE; + break; + } txst = (TX_GETFL (lprdat) << 1) | /* get state */ ((lpcsa & CSA_DELH)? 1: 0); /* plus delim hold */ if (lprdat & TX_DELH) @@ -515,7 +737,7 @@ return SCPE_OK; Return TRUE to continue printing, FALSE to stop */ -t_bool lp20_print (int32 c) +static t_bool lp20_print (int32 c) { t_bool r = TRUE; int32 i, rpt = 1; @@ -528,7 +750,7 @@ if (lppdat == 012) /* LF? adv carriage */ if (lppdat == 014) /* FF? top of form */ return lp20_davfu (DV_TOF); if (lppdat == 015) /* CR? reset col cntr */ - lpcolc = 0; + lpcolc = -1; else if (lppdat == 011) { /* TAB? simulate */ lppdat = ' '; /* with spaces */ if (lpcolc >= 128) { @@ -545,40 +767,55 @@ else { } for (i = 0; i < rpt; i++) fputc (lppdat, lp20_unit.fileref); -lp20_unit.pos = ftell (lp20_unit.fileref); +lp20_unit.pos = (t_addr)sim_ftell (lp20_unit.fileref); lpcolc = lpcolc + rpt; return r; } -t_bool lp20_adv (int32 cnt, t_bool dvuadv) +static t_bool lp20_adv (int32 cnt, t_bool dvuadv) { int32 i; +int stoppc = FALSE; if (cnt == 0) return TRUE; + +if (lpcsb & CSB_DVOF) + return FALSE; + +/* This logic has changed because it did not account for the case of more than one TOF + * occuring in the advance. Consider a tape with odd/even pages, and a slew channel that + * stops on the even. If we slew from the bottom of the even, we will pass the TOF of the + * odd page and stop on the odd; seeing a second TOF. + */ + lpcolc = 0; /* reset col cntr */ -for (i = 0; i < cnt; i++) +for (i = 0; i < cnt; i++) { /* print 'n' newlines; each can complete a page */ fputc ('\n', lp20_unit.fileref); -lp20_unit.pos = ftell (lp20_unit.fileref); /* print 'n' newlines */ -if (dvuadv) /* update DAVFU ptr */ + if (dvuadv) { /* update DAVFU ptr */ dvptr = (dvptr + cnt) % dvlnt; if (davfu[dvptr] & (1 << DV_TOF)) { /* at top of form? */ - if (lppagc = (lppagc - 1) & PAGC_MASK) { /* decr page cntr */ - lpcsa = lpcsa & ~CSA_PZRO; /* update status */ - return TRUE; - } - else { + lppagc = (lppagc - 1) & PAGC_MASK; /* decr page cntr */ + if (lppagc == 0) { lpcsa = lpcsa | CSA_PZRO; /* stop if zero */ - return FALSE; + stoppc = TRUE; } + } /* At TOF */ + } /* update pointer */ } +lp20_unit.pos = (t_addr)sim_ftell (lp20_unit.fileref); +if (stoppc) /* Crossed one or more TOFs? */ + return FALSE; + return TRUE; } -t_bool lp20_davfu (int32 cnt) +static t_bool lp20_davfu (int32 cnt) { int i; +if (lpcsb & CSB_DVOF) + return FALSE; if (cnt > DV_MAX) /* inval chan? */ cnt = 7; for (i = 0; i < dvlnt; i++) { /* search DAVFU */ @@ -591,72 +828,134 @@ for (i = 0; i < dvlnt; i++) { /* search DAVFU */ if (lpcolc) /* TOF, need newline? */ lp20_adv (1, FALSE); fputc ('\f', lp20_unit.fileref); /* print form feed */ - lp20_unit.pos = ftell (lp20_unit.fileref); - if (lppagc = (lppagc - 1) & PAGC_MASK) { /* decr page cntr */ - lpcsa = lpcsa & ~CSA_PZRO; /* update status */ + lp20_unit.pos = (t_addr)sim_ftell (lp20_unit.fileref); + lppagc = (lppagc - 1) & PAGC_MASK; /* decr page cntr */ + if (lppagc != 0) return TRUE; - } else { lpcsa = lpcsa | CSA_PZRO; /* stop if zero */ return FALSE; } } } /* end for */ -dvlnt = 0; /* DAVFU error */ +change_rdy (0,CSA_DVON); /* Code to channel with no channel stop */ return FALSE; } /* Update LPCSA, optionally request interrupt */ -void update_lpcs (int32 flg) +static void update_lpcs (int32 flg) { if (flg) /* set int req */ lp20_irq = 1; -lpcsa = (lpcsa | flg) & ~(CSA_MBZ | CSA_ERR | CSA_ONL | CSA_DVON); -lpcsb = (lpcsb | CSB_OFFL | CSB_DVOF) & ~CSB_MBZ; +lpcsa = (lpcsa | flg) & ~(CSA_MBZ | CSA_ERR | CSA_ONL); +lpcsb = (lpcsb | CSB_OFFL) & ~CSB_MBZ; if (lp20_unit.flags & UNIT_ATT) { lpcsa = lpcsa | CSA_ONL; lpcsb = lpcsb & ~CSB_OFFL; } else lpcsa = lpcsa & ~CSA_DONE; -if (dvlnt) { - lpcsa = lpcsa | CSA_DVON; - lpcsb = lpcsb & ~CSB_DVOF; - } if (lpcsb & CSB_ERR) lpcsa = lpcsa | CSA_ERR; if ((lpcsa & CSA_IE) && lp20_irq) - int_req = int_req | INT_LP20; -else int_req = int_req & ~INT_LP20; + SET_INT (LP20); +else CLR_INT (LP20); return; } +/* Set and clear READY bits in csa. + * used for bits where a transition should cause an interrupt. + * also updates corresponding bits in csb. + */ +static void change_rdy (int32 setrdy, int32 clrrdy) +{ +int32 newcsa = (lpcsa | setrdy) & ~clrrdy; + +if ((newcsa ^ lpcsa) & (CSA_ONL | CSA_DVON) && !sim_is_active (&lp20_unit)) { + lp20_irq |= 1; + if (newcsa & CSA_IE) + SET_INT(LP20); + } +/* CSA_ERR is handled in update_csa */ + +if (newcsa & CSA_DVON) + lpcsb &= ~CSB_DVOF; +else + lpcsb |= CSB_DVOF; +if (newcsa & CSA_ONL) + lpcsb &= ~CSB_OFFL; +else + lpcsb |= CSB_OFFL; + +lpcsa = newcsa; +} + /* Acknowledge interrupt (clear internal request) */ -int32 lp20_inta (void) +static int32 lp20_inta (void) { lp20_irq = 0; /* clear int req */ return lp20_dib.vec; } + +/* Simulator RESET + * Note that this does not reset the printer's DAVFU or the + * translation RAM, which survive system bootstraps. + * (SET VFUCLEAR will do that.) + * + */ + t_stat lp20_reset (DEVICE *dptr) { -lpcsa = CSA_DONE; -lpcsb = 0; + /* On power-up reset, clear DAVFU & RAM. Set DAVFU off-line. */ +if (sim_switches & SWMASK ('P')) { + memset (davfu, 0, sizeof(davfu)); + memset (txram, 0, sizeof(txram)); + dvlnt = dvptr = dvld= 0; + lpcsa &= ~CSA_DVON; + lpcsb |= CSB_DVOF; + lpi = DEFAULT_LPI; +} + +return lp20_init (dptr); +} + +/* Local init does NOT initialize the DAVFU/TRANSLATION RAMs. + * They are in the printer, which reset does not reach. + */ + +t_stat lp20_init (DEVICE *dptr) +{ +lpcsa = (lpcsa & CSA_DVON) | CSA_DONE; +lpcsb = lpcsb & (CSB_OVFU | CSB_DVOF); lpba = lpbc = lppagc = lpcolc = 0; /* clear registers */ lprdat = lppdat = lpcbuf = lpcsum = 0; lp20_irq = 0; /* clear int req */ -dvptr = 0; /* reset davfu ptr */ sim_cancel (&lp20_unit); /* deactivate unit */ update_lpcs (0); /* update status */ return SCPE_OK; } -t_stat lp20_attach (UNIT *uptr, char *cptr) +static t_stat lp20_attach (UNIT *uptr, char *cptr) { t_stat reason; reason = attach_unit (uptr, cptr); /* attach file */ +if (reason == SCPE_OK) { + sim_fseek (uptr->fileref, 0, SEEK_END); + uptr->pos = (t_addr)sim_ftell (uptr->fileref); + } +if (lpcsa & CSA_DVON) { + int i; + for (i = 0; i < dvlnt; i++) { /* Align VFU with new file */ + if (davfu[dvptr] & (1 << DV_TOF)) + break; + dvptr = (dvptr +1) % dvlnt; + } + if (!(davfu[dvptr] & (1 << DV_TOF))) /* No TOP channel -> bad VFU */ + change_rdy (0, CSA_DVON); +} if (lpcsa & CSA_ONL) /* just file chg? */ return reason; if (sim_is_active (&lp20_unit)) /* busy? no int */ @@ -665,7 +964,7 @@ else update_lpcs (CSA_MBZ); /* interrupt */ return reason; } -t_stat lp20_detach (UNIT *uptr) +static t_stat lp20_detach (UNIT *uptr) { t_stat reason; @@ -678,15 +977,258 @@ update_lpcs (CSA_MBZ); return reason; } -t_stat lp20_clear_vfu (UNIT *uptr, int32 val, char *cptr, void *desc) +static t_stat lp20_set_vfu_type (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +char *fname, *cp; +FILE *vfile; +int sum = 0; + +if (!cptr || !*cptr) + return SCPE_ARG; + +fname = strchr (cptr, '='); +if (fname) + *fname++ = '\0'; + +for (cp = cptr; *cp; cp++) + *cp = (char)toupper (*cp); + +if (strncmp (cptr, "DAVFU", strlen(cptr)) == 0) { /* set lp20 vfutype=davfu: Switch to DAVFU, empty */ + if (fname && *fname) + return SCPE_ARG; + if (!(lpcsb & CSB_OVFU)) /* No change */ + return SCPE_OK; + if (uptr->flags & UNIT_ATT) + return SCPE_NOATT; + + lpcsb &= ~CSB_OVFU; + change_rdy (0, CSA_DVON); + dvptr = 0; + dvlnt = 0; + return SCPE_OK; +} + +if (strncmp (cptr, "OPTICAL", strlen(cptr)) != 0) + return SCPE_ARG; + +if (!fname || !*fname) { /* set lp20 vfutype=optical */ + if ((uptr->flags & UNIT_ATT) && !(lpcsb & CSB_OVFU)) + return SCPE_NOATT; + + lpcsb |= CSB_OVFU; + change_rdy (CSA_DVON, 0); + memcpy (davfu, defaultvfu, sizeof defaultvfu); + dvlnt = sizeof (defaultvfu) / sizeof (defaultvfu[0]); + dvptr = 0; + return SCPE_OK; +} + +/* set lp20 vfutype=optical=file + * This is OK when attached, so long as not changing from DAVFU. + * Read an optical tape file. These are line-oriented ASCII files: + * # ! ; comment + * lno: [ch [ch]...] Define line lno (0-length-1 with punches in + * channel(s) ch (1-12) + * Not required to be in order, if a lno appears more than once, the entries + * are ORed. (You can't unpunch a tape.) + * The highest lno defines the VFU length. Note that there is confusion about + * whether line numbers start at one or at zero. The HRM uses 0. Some of the + * utilitites use 1. We stick with 0 here.. + */ + +if (!(lpcsb & CSB_OVFU) && (uptr->flags & UNIT_ATT)) /* Changing device out from under OS */ + return SCPE_NOATT; + +vfile = sim_fopen( fname, "r" ); +if (vfile == NULL) { + return SCPE_OPENERR; +} +memset (davfu, 0, sizeof davfu); +dvptr = dvlnt = 0; + +while (!feof(vfile)) { + int32 line, hole; + int c; + + /* Discard comments */ + c = fgetc(vfile); + if (c == EOF) + break; + if ((c == '#') || (c == ';') || (c == '!')) { + while (!feof(vfile) && (c != '\n')) + c = fgetc(vfile); + continue; + } + ungetc(c, vfile); + + /* Read a line number */ + c = fscanf (vfile, " %u:", &line); + if (c == EOF) + break; + if ((c < 1) || (line < 0) || (((size_t)line) >= (sizeof (davfu)/sizeof davfu[0]))) + goto fmt_err; + if (line+1 > dvlnt) + dvlnt = line+1; + + /* Read channel numbers for current line */ + while (!feof(vfile)) { + do { + c = fgetc (vfile); + } while (isspace(c) && (c != '\n')); + if ((c == '\n') || (c == EOF)) + break; + ungetc(c, vfile); + c = fscanf (vfile, "%u", &hole); + if ((c == EOF) || (c < 1) || (c > 12)) + goto fmt_err; + sum |= (davfu[line] |= 1 << (hole -1)); + } /* End of line */ + } /* EOF */ + +/* Validate VFU content */ +if (!(sum & (1 << DV_TOF))) /* Verify that at least one punch is in the TOF channel. */ + goto fmt_err; +if (!VFU_LEN_VALID(dvlnt, lpi)) /* Verify VFU has minimum number of lines */ + goto fmt_err; + +fclose(vfile); +lpcsb |= CSB_OVFU; +change_rdy (CSA_DVON, 0); +return SCPE_OK; + +fmt_err: +dvlnt = 0; +change_rdy (0, CSA_DVON); +fclose(vfile); +return SCPE_FMT; +} + +static t_stat lp20_show_vfu_type (FILE *st, UNIT *up, int32 v, void *dp) +{ +if (lpcsb & CSB_OVFU) + fprintf (st, "optical VFU"); +else + fprintf (st, "DAVFU"); + +if (lpcsa & CSA_DVON) + fprintf (st, " loaded: %u lines, %.1f in", dvlnt, (((double)dvlnt)/lpi)); +else + fprintf (st, " not ready"); + +return SCPE_OK; +} + +static t_stat lp20_set_lpi (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +int32 newlpi; + +if (uptr->flags & UNIT_ATT) + return SCPE_NOATT; + +if (!cptr || !*cptr) + newlpi = DEFAULT_LPI; +else if (!strcmp (cptr, "6") || !strcmp (cptr, "6-LPI")) + newlpi = 6; +else if (!strcmp (cptr, "8") || !strcmp (cptr, "8-LPI")) + newlpi = 8; +else + return SCPE_ARG; + +if ((lpcsa & CSA_DVON) && !VFU_LEN_VALID(dvlnt, newlpi)) + return SCPE_ARG; + +lpi = newlpi; +return SCPE_OK; +} + +static t_stat lp20_show_lpi (FILE *st, UNIT *up, int32 v, void *dp) +{ +fprintf (st, "%u LPI", lpi); + +return SCPE_OK; +} + +static t_stat lp20_show_vfu (FILE *st, UNIT *up, int32 v, void *dp) +{ +int l, c, sum; + +if (lpcsb & CSB_OVFU) + fprintf (st, "Tape"); +else + fprintf (st, "DAFVU"); + +if (lpcsb & CSB_DVOF) { + fprintf (st, " is not loaded\n"); + return SCPE_OK; + } + +fprintf (st, " contains:\n" + " 1 1 1\n" + "line 2 1 0 9 8 7 6 5 4 3 2 1\n" + "---- - - - - - - - - - - - -\n"); +sum = 0; +for (l = 0; l < dvlnt; l++) { + if ( l && !(l % 5) ) + fputc ('\n', st); + fprintf (st, "%4u", l); + for (c = DV_MAX; c >= 0; c--) + fprintf (st, " %c", (davfu[l] & (1 << c))? ((c >= 9)? 'X': '1'+c) : ' '); + fputc ('\n', st); + sum |= davfu[l]; + } + +if (!(sum & (1 << DV_TOF))) { + fprintf (st, "? No stop in channel %u (Top-of-Form)\n", DV_TOF+1); + } +if (!(sum & (1 << DV_BOF))) { + fprintf (st, "%% No stop in channel %u (Bottom-of-Form)\n", DV_BOF+1); + } + +return SCPE_OK; +} +static t_stat lp20_set_tof (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +int32 s_lpcsa = lpcsa; +int32 s_lppagc = lppagc; + +if (cptr && *cptr) + return SCPE_ARG; + +if (!(uptr->flags & UNIT_ATT)) + return SCPE_NOATT; + +if (lpcsb & CSB_DVOF) + return SCPE_INCOMP; + +lp20_davfu (DV_TOF); +lppagc = s_lppagc; +lpcsa = s_lpcsa; + +return SCPE_OK; +} + +static int16 evenbits (int16 value) +{ +int16 even = 1; +while (value) { + even ^= 1; + value &= value-1; + } +return even; +} + +static t_stat lp20_clear_vfu (UNIT *uptr, int32 val, char *cptr, void *desc) { int i; -if (!get_yn ("Clear DAVFU? [N]", FALSE)) +if (!get_yn ("Clear DAVFU & RAM? [N]", FALSE)) return SCPE_OK; for (i = 0; i < DV_SIZE; i++) davfu[i] = 0; -dvlnt = dvptr = 0; +for (i = 0; i < TX_SIZE; i++) + txram[i] = 0; +dvlnt = dvptr = dvld= 0; +change_rdy (0, CSA_DVON); update_lpcs (0); return SCPE_OK; } diff --git a/PDP10/pdp10_mdfp.c b/PDP10/pdp10_mdfp.c index 2aab8688..0caa5624 100644 --- a/PDP10/pdp10_mdfp.c +++ b/PDP10/pdp10_mdfp.c @@ -119,14 +119,14 @@ typedef struct { /* unpacked fp number */ #define FP_BIAS 0200 /* exponent bias */ #define FP_N_FHI 27 /* # of hi frac bits */ #define FP_V_FHI 0 /* must be zero */ -#define FP_M_FHI 0000777777777 +#define FP_M_FHI INT64_C(0000777777777) #define FP_N_EXP 8 /* # of exp bits */ #define FP_V_EXP (FP_V_FHI + FP_N_FHI) #define FP_M_EXP 0377 #define FP_V_SIGN (FP_V_EXP + FP_N_EXP) /* sign */ #define FP_N_FLO 35 /* # of lo frac bits */ #define FP_V_FLO 0 /* must be zero */ -#define FP_M_FLO 0377777777777 +#define FP_M_FLO INT64_C(0377777777777) #define GET_FPSIGN(x) ((int32) (((x) >> FP_V_SIGN) & 1)) #define GET_FPEXP(x) ((int32) (((x) >> FP_V_EXP) & FP_M_EXP)) #define GET_FPHI(x) ((x) & FP_M_FHI) @@ -141,14 +141,14 @@ typedef struct { /* unpacked fp number */ #define FP_V_URNDS (FP_V_UFHI - 1) /* sp round bit */ #define FP_V_UCRY (FP_V_UFHI + FP_N_FHI) /* <63> */ #define FP_V_UNORM (FP_V_UCRY - 1) /* normalized bit */ -#define FP_UFHI 0x7FFFFFF000000000 -#define FP_UFLO 0x0000000FFFFFFFFE -#define FP_UFRAC 0x7FFFFFFFFFFFFFFE -#define FP_URNDD 0x0000000000000001 -#define FP_URNDS 0x0000000800000000 -#define FP_UNORM 0x4000000000000000 -#define FP_UCRY 0x8000000000000000 -#define FP_ONES 0xFFFFFFFFFFFFFFFF +#define FP_UFHI INT64_C(0x7FFFFFF000000000) +#define FP_UFLO INT64_C(0x0000000FFFFFFFFE) +#define FP_UFRAC INT64_C(0x7FFFFFFFFFFFFFFE) +#define FP_URNDD INT64_C(0x0000000000000001) +#define FP_URNDS INT64_C(0x0000000800000000) +#define FP_UNORM INT64_C(0x4000000000000000) +#define FP_UCRY INT64_C(0x8000000000000000) +#define FP_ONES INT64_C(0xFFFFFFFFFFFFFFFF) #define UNEG(x) ((~x) + 1) #define DUNEG(x) x.flo = UNEG (x.flo); x.fhi = ~x.fhi + (x.flo == 0) @@ -493,7 +493,7 @@ if (a.fhi >= 2 * b.fhi) { /* will divide work? */ SETF (F_AOV | F_DCK | F_FOV | F_T1); return FALSE; } -if (savhi = a.fhi) { /* dvd = 0? quo = 0 */ +if ((savhi = a.fhi)) { /* dvd = 0? quo = 0 */ a.sign = a.sign ^ b.sign; /* result sign */ a.exp = a.exp - b.exp + FP_BIAS + 1; /* result exponent */ a.fhi = a.fhi / (b.fhi >> (FP_N_FHI + 1)); /* do divide */ @@ -728,7 +728,7 @@ if (r->sign) { r->fhi = r->fhi | FP_UCRY; else { r->exp = r->exp + 1; - r->fhi = FP_UCRY | FP_UNORM; + r->fhi = (t_uint64)(FP_UCRY | FP_UNORM); } } else { /* abs frac */ @@ -756,7 +756,7 @@ static int32 normtab[7] = { 1, 2, 4, 8, 16, 32, 63 }; extern a10 pager_PC; if (a->fhi & FP_UCRY) { /* carry set? */ - printf ("%%PDP-10 FP: carry bit set at normalization, PC = %o\n", pager_PC); + sim_printf ("%%PDP-10 FP: carry bit set at normalization, PC = %o\n", pager_PC); a->flo = (a->flo >> 1) | ((a->fhi & 1) << 63); /* try to recover */ a->fhi = a->fhi >> 1; /* but root cause */ a->exp = a->exp + 1; /* should be fixed! */ @@ -803,7 +803,7 @@ if (r->sign) { /* negate? */ if (fdvneg) { /* fdvr special? */ val[1] = ~val[1] & MMASK; /* 1's comp */ val[0] = ~val[0] & DMASK; - } + } else { /* 2's comp */ DMOVN (val); } diff --git a/PDP10/pdp10_pag.c b/PDP10/pdp10_pag.c index 3b0fd445..8bf3b0a5 100644 --- a/PDP10/pdp10_pag.c +++ b/PDP10/pdp10_pag.c @@ -429,7 +429,7 @@ else { /* TOPS-20 paging */ int32 pmi, vpn, xpte; int32 flg, t; t_bool stop; - a10 pa, csta; + a10 pa, csta = 0; d10 ptr, cste; d10 acc = PTE_T20_W | PTE_T20_C; /* init access bits */ @@ -762,7 +762,7 @@ t_bool wrcstm (a10 ea, int32 prv) { cstm = Read (ea, prv); if ((cpu_unit.flags & UNIT_T20) && (ea == 040127)) - cstm = 0770000000000; + cstm = INT64_C(0770000000000); return FALSE; } diff --git a/PDP10/pdp10_rp.c b/PDP10/pdp10_rp.c index f16320e7..8788d0ad 100644 --- a/PDP10/pdp10_rp.c +++ b/PDP10/pdp10_rp.c @@ -72,12 +72,14 @@ #include "pdp10_defs.h" #include +#include #define RP_NUMDR 8 /* #drives */ #define RP_NUMWD 128 /* 36b words/sector */ #define RP_MAXFR 32768 /* max transfer */ +#define SPINUP_DLY (1000*1000) /* Spinup delay, usec */ #define GET_SECTOR(x,d) ((int) fmod (sim_gtime() / ((double) (x)), \ - ((double) drv_tab[d].sect))) + ((double) drv_tab[d].sect))) #define MBA_RP_CTRL 0 /* RP drive */ #define MBA_RM_CTRL 1 /* RM drive */ @@ -87,7 +89,9 @@ #define UNIT_V_DTYPE (UNIT_V_UF + 1) /* disk type */ #define UNIT_M_DTYPE 7 #define UNIT_V_AUTO (UNIT_V_UF + 4) /* autosize */ -#define UNIT_V_DUMMY (UNIT_V_UF + 5) /* dummy flag */ +#define UNIT_V_UTS (UNIT_V_UF + 5) /* Up to speed */ +#define UNIT_UTS (1u << UNIT_V_UTS) +#define UNIT_V_DUMMY (UNIT_V_UF + 6) /* dummy flag */ #define UNIT_WLK (1 << UNIT_V_WLK) #define UNIT_DTYPE (UNIT_M_DTYPE << UNIT_V_DTYPE) #define UNIT_AUTO (1 << UNIT_V_AUTO) @@ -240,9 +244,9 @@ #define GET_DA(c,fs,d) ((((GET_CY (c) * drv_tab[d].surf) + \ GET_SF (fs)) * drv_tab[d].sect) + GET_SC (fs)) -/* RPCC - 176736 - current cylinder */ -/* RPER2 - 176740 - error status 2 - drive unsafe conditions - unimplemented */ -/* RPER3 - 176742 - error status 3 - more unsafe conditions - unimplemented */ +/* RPCC - 176736 - current cylinder */ +/* RPER2 - 176740 - error status 2 - drive unsafe conditions */ +/* RPER3 - 176742 - error status 3 - more unsafe conditions */ /* RPEC1 - 176744 - ECC status 1 - unimplemented */ /* RPEC2 - 176746 - ECC status 2 - unimplemented */ @@ -333,6 +337,8 @@ extern int32 int_req; extern int32 ubmap[UBANUM][UMAP_MEMSIZE]; /* Unibus maps */ extern int32 ubcs[UBANUM]; extern UNIT cpu_unit; +extern uint32 fe_bootrh; +extern int32 fe_bootunit; int32 rpcs1 = 0; /* control/status 1 */ int32 rpwc = 0; /* word count */ @@ -368,7 +374,7 @@ t_stat rp_reset (DEVICE *dptr); t_stat rp_boot (int32 unitno, DEVICE *dptr); t_stat rp_attach (UNIT *uptr, char *cptr); t_stat rp_detach (UNIT *uptr); -void set_rper (int32 flag, int32 drv); +void set_rper (int16 flag, int32 drv); void update_rpcs (int32 flags, int32 drv); void rp_go (int32 drv, int32 fnc); t_stat rp_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); @@ -611,12 +617,11 @@ return SCPE_OK; t_stat rp_wr (int32 data, int32 PA, int32 access) { -int32 cs1f, drv, dtype, i, j; +int32 cs1f, drv, i, j; UNIT *uptr; cs1f = 0; /* no int on cs1 upd */ drv = GET_UNIT (rpcs2); /* get current unit */ -dtype = GET_DTYPE (rp_unit[drv].flags); /* get drive type */ uptr = rp_dev.units + drv; /* get unit */ j = (PA >> 1) & 037; /* get reg offset */ if (reg_in_drive[j] && (rp_unit[drv].flags & UNIT_DIS)) { /* nx disk */ @@ -624,12 +629,12 @@ if (reg_in_drive[j] && (rp_unit[drv].flags & UNIT_DIS)) { /* nx disk */ update_rpcs (CS1_SC, drv); /* request intr */ return SCPE_OK; } -if (reg_in_drive[j] && sim_is_active (&rp_unit[drv])) { /* unit busy? */ +if (reg_in_drive[j] && sim_is_active (uptr) && (uptr->flags & UNIT_UTS)) { /* unit busy? */ set_rper (ER1_RMR, drv); /* won't write */ update_rpcs (0, drv); return SCPE_OK; } -rmhr[drv] = data; +rmhr[drv] = (uint16)data; switch (j) { /* decode PA<5:1> */ @@ -652,7 +657,7 @@ switch (j) { /* decode PA<5:1> */ rpcs2 = rpcs2 | CS2_NED; /* set error flag */ cs1f = CS1_SC; /* req interrupt */ } - else if (sim_is_active (uptr)) + else if (sim_is_active (uptr) && (uptr->flags & UNIT_UTS)) set_rper (ER1_RMR, drv); /* won't write */ else if (data & CS1_GO) { /* start op */ uptr->FUNC = GET_FNC (data); /* set func */ @@ -681,7 +686,7 @@ switch (j) { /* decode PA<5:1> */ case 003: /* RPDA */ if ((access == WRITEB) && (PA & 1)) data = data << 8; - rpda[drv] = data & ~DA_MBZ; + rpda[drv] = (uint16)(data & ~DA_MBZ); break; case 004: /* RPCS2 */ @@ -702,7 +707,7 @@ switch (j) { /* decode PA<5:1> */ case 006: /* RPER1 */ if ((access == WRITEB) && (PA & 1)) data = data << 8; - rper1[drv] = data; + rper1[drv] = (uint16)data; break; case 007: /* RPAS */ @@ -723,17 +728,17 @@ switch (j) { /* decode PA<5:1> */ case 012: /* RPMR */ if ((access == WRITEB) && (PA & 1)) data = data << 8; - rpmr[drv] = data; + rpmr[drv] = (uint16)data; break; case 015: /* RPOF */ - rpof[drv] = data & ~OF_MBZ; + rpof[drv] = (uint16)(data & ~OF_MBZ); break; case 016: /* RPDC */ if ((access == WRITEB) && (PA & 1)) data = data << 8; - rpdc[drv] = data & ~DC_MBZ; + rpdc[drv] = (uint16)(data & ~DC_MBZ); break; case 005: /* RPDS */ @@ -795,12 +800,16 @@ switch (fnc) { /* case on function */ rpda[drv] = 0; rpof[drv] = 0; /* clear offset */ case FNC_PACK: /* pack acknowledge */ + if ((uptr->flags & UNIT_UTS) == 0) { /* not attached? */ + set_rper (ER1_UNS, drv); /* unsafe */ + break; + } rpds[drv] = rpds[drv] | DS_VV; /* set volume valid */ return; case FNC_OFFSET: /* offset mode */ case FNC_RETURN: - if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */ + if ((uptr->flags & UNIT_UTS) == 0) { /* not attached? */ set_rper (ER1_UNS, drv); /* unsafe */ break; } @@ -809,18 +818,11 @@ switch (fnc) { /* case on function */ return; case FNC_UNLOAD: /* unload */ - if (drv_tab[dtype].ctrl == MBA_RM_CTRL) { /* RM? */ - set_rper (ER1_ILF, drv); /* not supported */ - break; - } - rp_detach (uptr); /* detach unit */ - return; - case FNC_RECAL: /* recalibrate */ dc = 0; /* seek to 0 */ case FNC_SEEK: /* seek */ case FNC_SEARCH: /* search */ - if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */ + if ((uptr->flags & UNIT_UTS) == 0) { /* not attached? */ set_rper (ER1_UNS, drv); /* unsafe */ break; } @@ -843,7 +845,7 @@ switch (fnc) { /* case on function */ case FNC_WCHK: /* write check */ case FNC_READ: /* read */ case FNC_READH: /* read headers */ - if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */ + if ((uptr->flags & UNIT_UTS) == 0) { /* not attached? */ set_rper (ER1_UNS, drv); /* unsafe */ break; } @@ -886,6 +888,13 @@ static d10 dbuf[RP_MAXFR]; dtype = GET_DTYPE (uptr->flags); /* get drive type */ drv = (int32) (uptr - rp_dev.units); /* get drv number */ +if ((uptr->flags & UNIT_UTS) == 0) { /* Transition to up-to-speed */ + uptr->flags |= UNIT_UTS; + rpds[drv] = DS_ATA | DS_MOL | DS_DPR | DS_RDY | + ((uptr->flags & UNIT_WPRT)? DS_WRL: 0); + update_rpcs (CS1_SC, drv); + return SCPE_OK; + } rpds[drv] = (rpds[drv] & ~DS_PIP) | DS_RDY; /* change drive status */ switch (uptr->FUNC) { /* case on function */ @@ -902,6 +911,8 @@ switch (uptr->FUNC) { /* case on function */ case FNC_UNLOAD: /* unload */ rp_detach (uptr); /* detach unit */ + rpds[drv] &= ~DS_ATA; /* Unload does not interrupt */ + update_rpcs (0, drv); break; case FNC_RECAL: /* recalibrate */ @@ -960,7 +971,7 @@ switch (uptr->FUNC) { /* case on function */ if ((rpcs2 & CS2_UAI) == 0) ba = ba + 4; } - if (fc10 = twc10 & (RP_NUMWD - 1)) { /* fill? */ + if ((fc10 = twc10 & (RP_NUMWD - 1))) { /* fill? */ fc10 = RP_NUMWD - fc10; for (i = 0; i < fc10; i++) dbuf[twc10 + i] = 0; @@ -1007,10 +1018,10 @@ switch (uptr->FUNC) { /* case on function */ if (da >= drv_tab[dtype].size) rpds[drv] = rpds[drv] | DS_LST; da = da / RP_NUMWD; - rpda[drv] = da % drv_tab[dtype].sect; + rpda[drv] = (uint16)(da % drv_tab[dtype].sect); da = da / drv_tab[dtype].sect; - rpda[drv] = rpda[drv] | ((da % drv_tab[dtype].surf) << DA_V_SF); - rpdc[drv] = da / drv_tab[dtype].surf; + rpda[drv] = (uint16)(rpda[drv] | ((da % drv_tab[dtype].surf) << DA_V_SF)); + rpdc[drv] = (uint16)(da / drv_tab[dtype].surf); if (err != 0) { /* error? */ set_rper (ER1_PAR, drv); /* set drive error */ @@ -1030,7 +1041,7 @@ return SCPE_OK; /* Set drive error */ -void set_rper (int32 flag, int32 drv) +void set_rper (int16 flag, int32 drv) { rper1[drv] = rper1[drv] | flag; rpds[drv] = rpds[drv] | DS_ATA; @@ -1057,7 +1068,7 @@ uptr = rp_dev.units + drv; /* get unit */ if (rp_unit[drv].flags & UNIT_DIS) rpds[drv] = rper1[drv] = 0; else rpds[drv] = (rpds[drv] | DS_DPR) & ~DS_PGM; -if (rp_unit[drv].flags & UNIT_ATT) +if (rp_unit[drv].flags & UNIT_UTS) rpds[drv] = rpds[drv] | DS_MOL; else rpds[drv] = rpds[drv] & ~(DS_MOL | DS_VV | DS_RDY); if (rper1[drv] | rper2[drv] | rper3[drv]) @@ -1066,15 +1077,17 @@ else rpds[drv] = rpds[drv] & ~DS_ERR; rpcs1 = (rpcs1 & ~(CS1_SC | CS1_MCPE | CS1_MBZ | CS1_DRV)) | CS1_DVA | flag; rpcs1 = rpcs1 | (uptr->FUNC << CS1_V_FNC); -if (sim_is_active (uptr)) +if (sim_is_active (uptr) && (uptr->flags & UNIT_UTS)) rpcs1 = rpcs1 | CS1_GO; if (rpcs2 & CS2_ERR) rpcs1 = rpcs1 | CS1_TRE | CS1_SC; else if (rpcs1 & CS1_TRE) rpcs1 = rpcs1 | CS1_SC; for (i = 0; i < RP_NUMDR; i++) { - if (rpds[i] & DS_ATA) + if (rpds[i] & DS_ATA) { rpcs1 = rpcs1 | CS1_SC; + break; + } } if (rpiff || ((rpcs1 & CS1_SC) && (rpcs1 & CS1_DONE) && (rpcs1 & CS1_IE))) int_req = int_req | INT_RP; @@ -1105,14 +1118,23 @@ rpiff = 0; /* clear CSTB INTR */ int_req = int_req & ~INT_RP; /* clear intr req */ for (i = 0; i < RP_NUMDR; i++) { uptr = rp_dev.units + i; - sim_cancel (uptr); uptr->CYL = uptr->FUNC = 0; if (uptr->flags & UNIT_ATT) + if (uptr->flags & UNIT_UTS) { + sim_cancel (uptr); rpds[i] = (rpds[i] & DS_VV) | DS_DPR | DS_RDY | DS_MOL | ((uptr->flags & UNIT_WPRT)? DS_WRL: 0); - else if (uptr->flags & UNIT_DIS) + } else { + if (!sim_is_active (uptr)) + sim_activate (uptr, SPINUP_DLY); + rpds[i] = DS_DPR | ((uptr->flags & UNIT_WPRT)? DS_WRL: 0); + } + else { + sim_cancel (uptr); + if (uptr->flags & UNIT_DIS) rpds[i] = 0; else rpds[i] = DS_DPR; + } rper1[i] = 0; rper2[i] = 0; rper3[i] = 0; @@ -1132,19 +1154,16 @@ return SCPE_OK; t_stat rp_attach (UNIT *uptr, char *cptr) { -int32 drv, i, p; +int32 i, p; t_stat r; uptr->capac = drv_tab[GET_DTYPE (uptr->flags)].size; r = attach_unit (uptr, cptr); if (r != SCPE_OK) return r; -drv = (int32) (uptr - rp_dev.units); /* get drv number */ -rpds[drv] = DS_ATA | DS_MOL | DS_RDY | DS_DPR | - ((uptr->flags & UNIT_WPRT)? DS_WRL: 0); -rper1[drv] = 0; -update_rpcs (CS1_SC, drv); - +sim_cancel (uptr); +uptr->flags &= ~UNIT_UTS; +sim_activate (uptr, SPINUP_DLY); if ((uptr->flags & UNIT_AUTO) == 0) /* autosize? */ return SCPE_OK; if ((p = sim_fsize (uptr->fileref)) == 0) @@ -1156,6 +1175,7 @@ for (i = 0; drv_tab[i].sect != 0; i++) { return SCPE_OK; } } +/* File is larger than max known disk. This should probably fail. */ return SCPE_OK; } @@ -1164,7 +1184,6 @@ return SCPE_OK; t_stat rp_detach (UNIT *uptr) { int32 drv; -extern int32 sim_is_running; if (!(uptr->flags & UNIT_ATT)) /* attached? */ return SCPE_OK; @@ -1173,12 +1192,14 @@ rpds[drv] = (rpds[drv] & ~(DS_MOL | DS_RDY | DS_WRL | DS_VV | DS_OF)) | DS_ATA; if (sim_is_active (uptr)) { /* unit active? */ sim_cancel (uptr); /* cancel operation */ + if (uptr->flags & UNIT_UTS) { rper1[drv] = rper1[drv] | ER1_OPI; /* set drive error */ if (uptr->FUNC >= FNC_WCHK) /* data transfer? */ rpcs1 = rpcs1 | CS1_DONE | CS1_TRE; /* set done, err */ } -if (!sim_is_running) /* from console? */ - update_rpcs (CS1_SC, drv); /* request intr */ + } +uptr->flags &= ~UNIT_UTS; +update_rpcs (0, drv); /* request intr */ return detach_unit (uptr); } @@ -1194,111 +1215,164 @@ uptr->capac = drv_tab[dtype].size; return SCPE_OK; } -/* Device bootstrap */ +/* Device bootstrap + * The DEC and ITS versions are word-for-word identical, except that + * the DEC RDIO/WRIO are replaced by IORDQ and IOWRQ. This is hand + * assembled code, so please always make changes in both. + * Due to a typo in the KS Console rom, block 010 is read for the + * alternate HOM block. The correct block is 012. For compatibiliy, + * we will do what the hardware did first, what's right if it fails (as it will). + */ #define BOOT_START 0377000 /* start */ #define BOOT_LEN (sizeof (boot_rom_dec) / sizeof (d10)) static const d10 boot_rom_dec[] = { - 0515040000001, /* boot:hrlzi 1,1 ; uba # */ - 0201000140001, /* movei 0,140001 ; vld,fst,pg 1 */ - 0713001000000+(IOBA_UBMAP+1 & RMASK), /* wrio 0,763001(1); set ubmap */ - 0435040000000+(IOBA_RP & RMASK), /* iori 1,776700 ; rh addr */ - 0202040000000+FE_RHBASE, /* movem 1,FE_RHBASE */ - 0201000000040, /* movei 0,40 ; ctrl reset */ - 0713001000010, /* wrio 0,10(1) ; ->RPCS2 */ - 0201000000021, /* movei 0,21 ; preset */ - 0713001000000, /* wrio 0,0(1) ; ->RPCS1 */ - 0201100000001, /* movei 2,1 ; blk #1 */ - 0265740377032, /* jsp 17,rdbl ; read */ - 0204140001000, /* movs 3,1000 ; id word */ - 0306140505755, /* cain 3,sixbit /HOM/ */ - 0254000377023, /* jrst .+6 ; match */ - 0201100000010, /* movei 2,10 ; blk #10 */ - 0265740377032, /* jsp 17,rdbl ; read */ - 0204140001000, /* movs 3,1000 ; id word */ - 0302140505755, /* caie 3,sixbit /HOM/ */ - 0254200377022, /* halt . ; inv home */ - 0336100001103, /* skipn 2,1103 ; pg of ptrs */ - 0254200377024, /* halt . ; inv ptr */ - 0265740377032, /* jsp 17,rdbl ; read */ - 0336100001004, /* skipn 2,1004 ; mon boot */ - 0254200377027, /* halt . ; inv ptr */ - 0265740377032, /* jsp 17,rdbl ; read */ - 0254000001000, /* jrst 1000 ; start */ - 0201140176000, /* rdbl:movei 3,176000 ; wd cnt */ - 0201200004000, /* movei 4,4000 ; addr */ - 0200240000000+FE_UNIT, /* move 5,FE_UNIT ; unit */ - 0200300000002, /* move 6,2 */ - 0242300777750, /* lsh 6,-24. ; cyl */ - 0713141000002, /* wrio 3,2(1) ; ->RPWC */ - 0713201000004, /* wrio 4,4(1) ; ->RPBA */ - 0713101000006, /* wrio 2,6(1) ; ->RPDA */ - 0713241000010, /* wrio 5,10(1) ; ->RPCS2 */ - 0713301000034, /* wrio 6,34(1) ; ->RPDC */ - 0201000000071, /* movei 0,71 ; read+go */ - 0713001000000, /* wrio 0,0(1) ; ->RPCS1 */ - 0712341000000, /* rdio 7,0(1) ; read csr */ - 0606340000200, /* trnn 7,200 ; test rdy */ - 0254000377046, /* jrst .-2 ; loop */ - 0602340100000, /* trne 7,100000 ; test err */ - 0254200377052, /* halt */ - 0254017000000, /* jrst 0(17) ; return */ + INT64_C(0510040000000)+FE_RHBASE, /* boot:hllz 1,FE_RHBASE ; uba # */ + INT64_C(0201000140001), /* movei 0,140001 ; vld,fst,pg 1 */ + INT64_C(0713001000000)+((IOBA_UBMAP+1) & RMASK), /* wrio 0,763001(1); set ubmap */ + INT64_C(0200040000000)+FE_RHBASE, /* move 1,FE_RHBASE */ + INT64_C(0201000000040), /* movei 0,40 ; ctrl reset */ + INT64_C(0713001000010), /* wrio 0,10(1) ; ->RPCS2 */ + INT64_C(0200240000000)+FE_UNIT, /* move 5,FE_UNIT ; unit */ + INT64_C(0713241000010), /* wrio 5,10(1) ; select ->RPCS2 */ + + INT64_C(0712001000012), /*10 rdio 0,12(1) ; RPDS */ + INT64_C(0640000010600), /* trc 0,10600 ; MOL + DPR + RDY */ + INT64_C(0642000010600), /* trce 0,10600 ; */ + INT64_C(0254000377010), /* jrst .-3 ; wait */ + INT64_C(0201000000377), /* movei 0,377 ; All units */ + INT64_C(0713001000016), /* wrio 0,16(1) ; Clear on-line attns */ + INT64_C(0201000000021), /* movei 0,21 ; preset */ + INT64_C(0713001000000), /* wrio 0,0(1) ; ->RPCS1 */ + + INT64_C(0201100000001), /*20 movei 2,1 ; blk #1 */ + INT64_C(0265740377041), /* jsp 17,rdbl ; read */ + INT64_C(0204140001000), /* movs 3,1000 ; id word */ + INT64_C(0306140505755), /* cain 3,sixbit /HOM/ */ + INT64_C(0254000377032), /* jrst pg ; match */ + INT64_C(0201100000010), /* movei 2,10 ; blk #10 */ + INT64_C(0265740377041), /* jsp 17,rdbl ; read */ + INT64_C(0204140001000), /* movs 3,1000 ; id word */ + + INT64_C(0302140505755), /*30 caie 3,sixbit /HOM/ */ + INT64_C(0254000377061), /* jrst alt2 ; inv home */ + INT64_C(0336100001103), /* pg: skipn 2,1103 ; pg of ptrs */ + INT64_C(0254200377033), /* halt . ; inv ptr */ + INT64_C(0265740377041), /* jsp 17,rdbl ; read */ + INT64_C(0336100001004), /* skipn 2,1004 ; mon boot */ + INT64_C(0254200377036), /* halt . ; inv ptr */ + INT64_C(0265740377041), /* jsp 17,rdbl ; read */ + + INT64_C(0254000001000), /*40 jrst 1000 ; start */ + INT64_C(0201140176000), /* rdbl:movei 3,176000 ; wd cnt 1P = -512*2 */ + INT64_C(0201200004000), /* movei 4,4000 ; 11 addr => M[1000] */ + INT64_C(0200300000002), /* move 6,2 */ + INT64_C(0242300777750), /* lsh 6,-24. ; cyl */ + INT64_C(0713141000002), /* wrio 3,2(1) ; ->RPWC */ + INT64_C(0713201000004), /* wrio 4,4(1) ; ->RPBA */ + INT64_C(0713101000006), /* wrio 2,6(1) ; ->RPDA */ + + INT64_C(0713301000034), /*50 wrio 6,34(1) ; ->RPDC */ + INT64_C(0201000000071), /* movei 0,71 ; read+go */ + INT64_C(0713001000000), /* wrio 0,0(1) ; ->RPCS1 */ + INT64_C(0712341000000), /* rdio 7,0(1) ; read csr */ + INT64_C(0606340000200), /* trnn 7,200 ; test rdy */ + INT64_C(0254000377053), /* jrst .-2 ; loop */ + INT64_C(0602340100000), /* trne 7,100000 ; test err */ + INT64_C(0254200377057), /* halt . */ + + INT64_C(0254017000000), /*60 jrst 0(17) ; return */ + INT64_C(0201100000012), /*alt2: movei 2,10. ; blk #10. */ + INT64_C(0265740377041), /* jsp 17,rdbl ; read */ + INT64_C(0204140001000), /* movs 3,1000 ; id word */ + INT64_C(0302140505755), /* caie 3,sixbit /HOM/ */ + INT64_C(0254200377065), /* halt . ; inv home */ + INT64_C(0254000377032), /* jrst pg ; Read ptrs */ }; static const d10 boot_rom_its[] = { - 0515040000001, /* boot:hrlzi 1,1 ; uba # */ - 0201000140001, /* movei 0,140001 ; vld,fst,pg 1 */ - 0715000000000+(IOBA_UBMAP+1 & RMASK), /* iowrq 0,763001 ; set ubmap */ - 0435040000000+(IOBA_RP & RMASK), /* iori 1,776700 ; rh addr */ - 0202040000000+FE_RHBASE, /* movem 1,FE_RHBASE */ - 0201000000040, /* movei 0,40 ; ctrl reset */ - 0715001000010, /* iowrq 0,10(1) ; ->RPCS2 */ - 0201000000021, /* movei 0,21 ; preset */ - 0715001000000, /* iowrq 0,0(1) ; ->RPCS1 */ - 0201100000001, /* movei 2,1 ; blk #1 */ - 0265740377032, /* jsp 17,rdbl ; read */ - 0204140001000, /* movs 3,1000 ; id word */ - 0306140505755, /* cain 3,sixbit /HOM/ */ - 0254000377023, /* jrst .+6 ; match */ - 0201100000010, /* movei 2,10 ; blk #10 */ - 0265740377032, /* jsp 17,rdbl ; read */ - 0204140001000, /* movs 3,1000 ; id word */ - 0302140505755, /* caie 3,sixbit /HOM/ */ - 0254200377022, /* halt . ; inv home */ - 0336100001103, /* skipn 2,1103 ; pg of ptrs */ - 0254200377024, /* halt . ; inv ptr */ - 0265740377032, /* jsp 17,rdbl ; read */ - 0336100001004, /* skipn 2,1004 ; mon boot */ - 0254200377027, /* halt . ; inv ptr */ - 0265740377032, /* jsp 17,rdbl ; read */ - 0254000001000, /* jrst 1000 ; start */ - 0201140176000, /* rdbl:movei 3,176000 ; wd cnt */ - 0201200004000, /* movei 4,4000 ; addr */ - 0200240000000+FE_UNIT, /* move 5,FE_UNIT ; unit */ - 0200300000002, /* move 6,2 */ - 0242300777750, /* lsh 6,-24. ; cyl */ - 0715141000002, /* iowrq 3,2(1) ; ->RPWC */ - 0715201000004, /* iowrq 4,4(1) ; ->RPBA */ - 0715101000006, /* iowrq 2,6(1) ; ->RPDA */ - 0715241000010, /* iowrq 5,10(1) ; ->RPCS2 */ - 0715301000034, /* iowrq 6,34(1) ; ->RPDC */ - 0201000000071, /* movei 0,71 ; read+go */ - 0715001000000, /* iowrq 0,0(1) ; ->RPCS1 */ - 0711341000000, /* iordq 7,0(1) ; read csr */ - 0606340000200, /* trnn 7,200 ; test rdy */ - 0254000377046, /* jrst .-2 ; loop */ - 0602340100000, /* trne 7,100000 ; test err */ - 0254200377052, /* halt */ - 0254017000000, /* jrst 0(17) ; return */ + INT64_C(0510040000001)+FE_RHBASE, /* boot:hllzi 1,FE_RHBASE ; uba # */ + INT64_C(0201000140001), /* movei 0,140001 ; vld,fst,pg 1 */ + INT64_C(0715000000000)+((IOBA_UBMAP+1) & RMASK), /* iowrq 0,763001 ; set ubmap */ + INT64_C(0200040000000)+FE_RHBASE, /* move 1,FE_RHBASE */ + INT64_C(0201000000040), /* movei 0,40 ; ctrl reset */ + INT64_C(0715001000010), /* iowrq 0,10(1) ; ->RPCS2 */ + INT64_C(0200240000000)+FE_UNIT, /* move 5,FE_UNIT ; unit */ + INT64_C(0715241000010), /* iowrq 5,10(1) ; ->RPCS2 */ + + INT64_C(0711001000012), /*10 iordq 0,12(1) ; RPDS */ + INT64_C(0640000010600), /* trc 0,10600 ; MOL + DPR + RDY */ + INT64_C(0642000010600), /* trce 0,10600 ; */ + INT64_C(0254000377010), /* jrst .-3 ; wait */ + INT64_C(0201000000377), /* movei 0,377 ; All units */ + INT64_C(0715001000016), /* iowrq 0,16(1) ; Clear on-line attns */ + INT64_C(0201000000021), /* movei 0,21 ; preset */ + INT64_C(0715001000000), /* iowrq 0,0(1) ; ->RPCS1 */ + + INT64_C(0201100000001), /*20 movei 2,1 ; blk #1 */ + INT64_C(0265740377041), /* jsp 17,rdbl ; read */ + INT64_C(0204140001000), /* movs 3,1000 ; id word */ + INT64_C(0306140505755), /* cain 3,sixbit /HOM/ */ + INT64_C(0254000377032), /* jrst pg ; match */ + INT64_C(0201100000010), /* movei 2,10 ; blk #10 */ + INT64_C(0265740377041), /* jsp 17,rdbl ; read */ + INT64_C(0204140001000), /* movs 3,1000 ; id word */ + + INT64_C(0302140505755), /*30 caie 3,sixbit /HOM/ */ + INT64_C(0254000377061), /* jrst alt2 ; inv home */ + INT64_C(0336100001103), /* pg: skipn 2,1103 ; pg of ptrs */ + INT64_C(0254200377033), /* halt . ; inv ptr */ + INT64_C(0265740377041), /* jsp 17,rdbl ; read */ + INT64_C(0336100001004), /* skipn 2,1004 ; mon boot */ + INT64_C(0254200377036), /* halt . ; inv ptr */ + INT64_C(0265740377041), /* jsp 17,rdbl ; read */ + + INT64_C(0254000001000), /*40 jrst 1000 ; start */ + INT64_C(0201140176000), /* rdbl:movei 3,176000 ; wd cnt 1P = -512 *2 */ + INT64_C(0201200004000), /* movei 4,4000 ; addr */ + INT64_C(0200300000002), /* move 6,2 */ + INT64_C(0242300777750), /* lsh 6,-24. ; cyl */ + INT64_C(0715141000002), /* iowrq 3,2(1) ; ->RPWC */ + INT64_C(0715201000004), /* iowrq 4,4(1) ; ->RPBA */ + INT64_C(0715101000006), /* iowrq 2,6(1) ; ->RPDA */ + + INT64_C(0715301000034), /*50 iowrq 6,34(1) ; ->RPDC */ + INT64_C(0201000000071), /* movei 0,71 ; read+go */ + INT64_C(0715001000000), /* iowrq 0,0(1) ; ->RPCS1 */ + INT64_C(0711341000000), /* iordq 7,0(1) ; read csr */ + INT64_C(0606340000200), /* trnn 7,200 ; test rdy */ + INT64_C(0254000377053), /* jrst .-2 ; loop */ + INT64_C(0602340100000), /* trne 7,100000 ; test err */ + INT64_C(0254200377057), /* halt */ + + INT64_C(0254017000000), /*60 jrst 0(17) ; return */ + INT64_C(0201100000012), /* alt2:movei 2,10. ; blk #10. */ + INT64_C(0265740377041), /* jsp 17,rdbl ; read */ + INT64_C(0204140001000), /* movs 3,1000 ; id word */ + INT64_C(0302140505755), /* caie 3,sixbit /HOM/ */ + INT64_C(0254200377065), /* halt . ; inv home */ + INT64_C(0254000377032), /* jrst pg ; Read ptrs */ }; t_stat rp_boot (int32 unitno, DEVICE *dptr) { -int32 i; +size_t i; extern a10 saved_PC; +UNIT *uptr; + +unitno &= CS2_M_UNIT; +uptr = rp_dev.units + unitno; +if (!(uptr->flags & UNIT_ATT)) + return SCPE_NOATT; + +M[FE_RHBASE] = fe_bootrh = rp_dib.ba; +M[FE_UNIT] = fe_bootunit = unitno; + +assert (sizeof(boot_rom_dec) == sizeof(boot_rom_its)); + +M[FE_KEEPA] = (M[FE_KEEPA] & ~INT64_C(0xFF)) | ((sim_switches & SWMASK ('A'))? 010 : 0); -M[FE_UNIT] = unitno & CS2_M_UNIT; for (i = 0; i < BOOT_LEN; i++) M[BOOT_START + i] = Q_ITS? boot_rom_its[i]: boot_rom_dec[i]; saved_PC = BOOT_START; diff --git a/PDP10/pdp10_sys.c b/PDP10/pdp10_sys.c index 061f0e40..af3f71bb 100644 --- a/PDP10/pdp10_sys.c +++ b/PDP10/pdp10_sys.c @@ -106,6 +106,8 @@ const char *sim_stop_messages[] = { "Nested XCT limit exceeded", "Invalid I/O controller", "Address stop", + "Console FE halt", + "Unaligned DMA", "Panic stop" }; @@ -118,7 +120,7 @@ const char *sim_stop_messages[] = { #define EXE_DIR 01776 /* EXE directory */ #define EXE_VEC 01775 /* EXE entry vec */ #define EXE_PDV 01774 /* EXE ignored */ -#define EXE_END 01777 /* EXE end +#define EXE_END 01777 /* EXE end */ /* RIM10 loader @@ -338,7 +340,6 @@ t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag) { d10 data; int32 wc, fmt; -extern int32 sim_switches; fmt = 0; /* no fmt */ if (sim_switches & SWMASK ('R')) /* -r? */ @@ -376,7 +377,7 @@ switch (fmt) { /* case fmt */ return load_exe (fileref); } -printf ("Can't determine load file format\n"); +sim_printf ("Can't determine load file format\n"); return SCPE_FMT; } @@ -384,17 +385,17 @@ return SCPE_FMT; #define I_V_FL 39 /* inst class */ #define I_M_FL 03 /* class mask */ -#define I_ITS 004000000000000 /* ITS flag */ -#define I_AC 000000000000000 /* AC, address */ -#define I_OP 010000000000000 /* address only */ -#define I_IO 020000000000000 /* classic I/O */ +#define I_ITS INT64_C(004000000000000) /* ITS flag */ +#define I_AC INT64_C(000000000000000) /* AC, address */ +#define I_OP INT64_C(010000000000000) /* address only */ +#define I_IO INT64_C(020000000000000) /* classic I/O */ #define I_V_AC 00 #define I_V_OP 01 #define I_V_IO 02 static const d10 masks[] = { - 0777000000000, 0777740000000, - 0700340000000, 0777777777777 + INT64_C(0777000000000), INT64_C(0777740000000), + INT64_C(0700340000000), INT64_C(0777777777777) }; static const char *opcode[] = { @@ -502,171 +503,171 @@ NULL }; static const d10 opc_val[] = { - 0102000000000+I_AC+I_ITS, 0103000000000+I_AC+I_ITS, - 0710000000000+I_AC+I_ITS, 0711000000000+I_AC+I_ITS, 0712000000000+I_AC+I_ITS, - 0713000000000+I_AC+I_ITS, 0714000000000+I_AC+I_ITS, 0715000000000+I_AC+I_ITS, - 0720000000000+I_AC+I_ITS, 0721000000000+I_AC+I_ITS, 0722000000000+I_AC+I_ITS, - 0723000000000+I_AC+I_ITS, 0724000000000+I_AC+I_ITS, 0725000000000+I_AC+I_ITS, - 0701000000000+I_OP+I_ITS, 0701440000000+I_OP+I_ITS, 0701540000000+I_OP+I_ITS, - 0702000000000+I_OP+I_ITS, 0702040000000+I_OP+I_ITS, - 0702100000000+I_OP+I_ITS, 0702140000000+I_OP+I_ITS, 0702340000000+I_OP+I_ITS, - 0702400000000+I_OP+I_ITS, 0702440000000+I_OP+I_ITS, - 0702500000000+I_OP+I_ITS, 0702540000000+I_OP+I_ITS, 0702740000000+I_OP+I_ITS, + INT64_C(0102000000000)+I_AC+I_ITS, INT64_C(0103000000000)+I_AC+I_ITS, + INT64_C(0710000000000)+I_AC+I_ITS, INT64_C(0711000000000)+I_AC+I_ITS, INT64_C(0712000000000)+I_AC+I_ITS, + INT64_C(0713000000000)+I_AC+I_ITS, INT64_C(0714000000000)+I_AC+I_ITS, INT64_C(0715000000000)+I_AC+I_ITS, + INT64_C(0720000000000)+I_AC+I_ITS, INT64_C(0721000000000)+I_AC+I_ITS, INT64_C(0722000000000)+I_AC+I_ITS, + INT64_C(0723000000000)+I_AC+I_ITS, INT64_C(0724000000000)+I_AC+I_ITS, INT64_C(0725000000000)+I_AC+I_ITS, + INT64_C(0701000000000)+I_OP+I_ITS, INT64_C(0701440000000)+I_OP+I_ITS, INT64_C(0701540000000)+I_OP+I_ITS, + INT64_C(0702000000000)+I_OP+I_ITS, INT64_C(0702040000000)+I_OP+I_ITS, + INT64_C(0702100000000)+I_OP+I_ITS, INT64_C(0702140000000)+I_OP+I_ITS, INT64_C(0702340000000)+I_OP+I_ITS, + INT64_C(0702400000000)+I_OP+I_ITS, INT64_C(0702440000000)+I_OP+I_ITS, + INT64_C(0702500000000)+I_OP+I_ITS, INT64_C(0702540000000)+I_OP+I_ITS, INT64_C(0702740000000)+I_OP+I_ITS, - 0254040000000+I_OP, 0254100000000+I_OP, - 0254200000000+I_OP, 0254240000000+I_OP, 0254300000000+I_OP, 0254340000000+I_OP, - 0254500000000+I_OP, 0254600000000+I_OP, 0254640000000+I_OP, 0133000000000+I_OP, - 0255040000000+I_OP, 0255100000000+I_OP, 0255200000000+I_OP, 0255300000000+I_OP, - 0255400000000+I_OP, + INT64_C(0254040000000)+I_OP, INT64_C(0254100000000)+I_OP, + INT64_C(0254200000000)+I_OP, INT64_C(0254240000000)+I_OP, INT64_C(0254300000000)+I_OP, INT64_C(0254340000000)+I_OP, + INT64_C(0254500000000)+I_OP, INT64_C(0254600000000)+I_OP, INT64_C(0254640000000)+I_OP, INT64_C(0133000000000)+I_OP, + INT64_C(0255040000000)+I_OP, INT64_C(0255100000000)+I_OP, INT64_C(0255200000000)+I_OP, INT64_C(0255300000000)+I_OP, + INT64_C(0255400000000)+I_OP, - 0700000000000+I_OP, 0700200000000+I_OP, 0700240000000+I_OP, 0700600000000+I_OP, - 0700640000000+I_OP, 0701040000000+I_OP, 0701100000000+I_OP, 0701140000000+I_OP, - 0701200000000+I_OP, 0701240000000+I_OP, - 0702000000000+I_OP, 0702040000000+I_OP, 0702100000000+I_OP, 0702140000000+I_OP, - 0702200000000+I_OP, 0702240000000+I_OP, 0702300000000+I_OP, - 0702400000000+I_OP, 0702440000000+I_OP, 0702500000000+I_OP, 0702540000000+I_OP, - 0702600000000+I_OP, 0702640000000+I_OP, 0702700000000+I_OP, + INT64_C(0700000000000)+I_OP, INT64_C(0700200000000)+I_OP, INT64_C(0700240000000)+I_OP, INT64_C(0700600000000)+I_OP, + INT64_C(0700640000000)+I_OP, INT64_C(0701040000000)+I_OP, INT64_C(0701100000000)+I_OP, INT64_C(0701140000000)+I_OP, + INT64_C(0701200000000)+I_OP, INT64_C(0701240000000)+I_OP, + INT64_C(0702000000000)+I_OP, INT64_C(0702040000000)+I_OP, INT64_C(0702100000000)+I_OP, INT64_C(0702140000000)+I_OP, + INT64_C(0702200000000)+I_OP, INT64_C(0702240000000)+I_OP, INT64_C(0702300000000)+I_OP, + INT64_C(0702400000000)+I_OP, INT64_C(0702440000000)+I_OP, INT64_C(0702500000000)+I_OP, INT64_C(0702540000000)+I_OP, + INT64_C(0702600000000)+I_OP, INT64_C(0702640000000)+I_OP, INT64_C(0702700000000)+I_OP, - 0001000000000+I_AC, 0002000000000+I_AC, 0003000000000+I_AC, - 0004000000000+I_AC, 0005000000000+I_AC, 0006000000000+I_AC, 0007000000000+I_AC, - 0010000000000+I_AC, 0011000000000+I_AC, 0012000000000+I_AC, 0013000000000+I_AC, - 0014000000000+I_AC, 0015000000000+I_AC, 0016000000000+I_AC, 0017000000000+I_AC, - 0020000000000+I_AC, 0021000000000+I_AC, 0022000000000+I_AC, 0023000000000+I_AC, - 0024000000000+I_AC, 0025000000000+I_AC, 0026000000000+I_AC, 0027000000000+I_AC, - 0030000000000+I_AC, 0031000000000+I_AC, 0032000000000+I_AC, 0033000000000+I_AC, - 0034000000000+I_AC, 0035000000000+I_AC, 0036000000000+I_AC, 0037000000000+I_AC, - 0040000000000+I_AC, 0041000000000+I_AC, 0042000000000+I_AC, 0043000000000+I_AC, - 0044000000000+I_AC, 0045000000000+I_AC, 0046000000000+I_AC, 0047000000000+I_AC, - 0050000000000+I_AC, 0051000000000+I_AC, 0052000000000+I_AC, 0053000000000+I_AC, - 0054000000000+I_AC, 0055000000000+I_AC, 0056000000000+I_AC, 0057000000000+I_AC, - 0060000000000+I_AC, 0061000000000+I_AC, 0062000000000+I_AC, 0063000000000+I_AC, - 0064000000000+I_AC, 0065000000000+I_AC, 0066000000000+I_AC, 0067000000000+I_AC, - 0070000000000+I_AC, 0071000000000+I_AC, 0072000000000+I_AC, 0073000000000+I_AC, - 0074000000000+I_AC, 0075000000000+I_AC, 0076000000000+I_AC, 0077000000000+I_AC, + INT64_C(0001000000000)+I_AC, INT64_C(0002000000000)+I_AC, INT64_C(0003000000000)+I_AC, + INT64_C(0004000000000)+I_AC, INT64_C(0005000000000)+I_AC, INT64_C(0006000000000)+I_AC, INT64_C(0007000000000)+I_AC, + INT64_C(0010000000000)+I_AC, INT64_C(0011000000000)+I_AC, INT64_C(0012000000000)+I_AC, INT64_C(0013000000000)+I_AC, + INT64_C(0014000000000)+I_AC, INT64_C(0015000000000)+I_AC, INT64_C(0016000000000)+I_AC, INT64_C(0017000000000)+I_AC, + INT64_C(0020000000000)+I_AC, INT64_C(0021000000000)+I_AC, INT64_C(0022000000000)+I_AC, INT64_C(0023000000000)+I_AC, + INT64_C(0024000000000)+I_AC, INT64_C(0025000000000)+I_AC, INT64_C(0026000000000)+I_AC, INT64_C(0027000000000)+I_AC, + INT64_C(0030000000000)+I_AC, INT64_C(0031000000000)+I_AC, INT64_C(0032000000000)+I_AC, INT64_C(0033000000000)+I_AC, + INT64_C(0034000000000)+I_AC, INT64_C(0035000000000)+I_AC, INT64_C(0036000000000)+I_AC, INT64_C(0037000000000)+I_AC, + INT64_C(0040000000000)+I_AC, INT64_C(0041000000000)+I_AC, INT64_C(0042000000000)+I_AC, INT64_C(0043000000000)+I_AC, + INT64_C(0044000000000)+I_AC, INT64_C(0045000000000)+I_AC, INT64_C(0046000000000)+I_AC, INT64_C(0047000000000)+I_AC, + INT64_C(0050000000000)+I_AC, INT64_C(0051000000000)+I_AC, INT64_C(0052000000000)+I_AC, INT64_C(0053000000000)+I_AC, + INT64_C(0054000000000)+I_AC, INT64_C(0055000000000)+I_AC, INT64_C(0056000000000)+I_AC, INT64_C(0057000000000)+I_AC, + INT64_C(0060000000000)+I_AC, INT64_C(0061000000000)+I_AC, INT64_C(0062000000000)+I_AC, INT64_C(0063000000000)+I_AC, + INT64_C(0064000000000)+I_AC, INT64_C(0065000000000)+I_AC, INT64_C(0066000000000)+I_AC, INT64_C(0067000000000)+I_AC, + INT64_C(0070000000000)+I_AC, INT64_C(0071000000000)+I_AC, INT64_C(0072000000000)+I_AC, INT64_C(0073000000000)+I_AC, + INT64_C(0074000000000)+I_AC, INT64_C(0075000000000)+I_AC, INT64_C(0076000000000)+I_AC, INT64_C(0077000000000)+I_AC, - 0100000000000+I_AC, 0102000000000+I_AC, 0103000000000+I_AC, - 0104000000000+I_AC, 0105000000000+I_AC, 0106000000000+I_AC, 0107000000000+I_AC, - 0110000000000+I_AC, 0111000000000+I_AC, 0112000000000+I_AC, 0113000000000+I_AC, - 0114000000000+I_AC, 0115000000000+I_AC, 0116000000000+I_AC, 0117000000000+I_AC, - 0120000000000+I_AC, 0121000000000+I_AC, 0122000000000+I_AC, 0123000000000+I_AC, - 0124000000000+I_AC, 0125000000000+I_AC, 0126000000000+I_AC, 0127000000000+I_AC, - 0130000000000+I_AC, 0131000000000+I_AC, 0132000000000+I_AC, 0133000000000+I_AC, - 0134000000000+I_AC, 0135000000000+I_AC, 0136000000000+I_AC, 0137000000000+I_AC, - 0140000000000+I_AC, 0141000000000+I_AC, 0142000000000+I_AC, 0143000000000+I_AC, - 0144000000000+I_AC, 0145000000000+I_AC, 0146000000000+I_AC, 0147000000000+I_AC, - 0150000000000+I_AC, 0151000000000+I_AC, 0152000000000+I_AC, 0153000000000+I_AC, - 0154000000000+I_AC, 0155000000000+I_AC, 0156000000000+I_AC, 0157000000000+I_AC, - 0160000000000+I_AC, 0161000000000+I_AC, 0162000000000+I_AC, 0163000000000+I_AC, - 0164000000000+I_AC, 0165000000000+I_AC, 0166000000000+I_AC, 0167000000000+I_AC, - 0170000000000+I_AC, 0171000000000+I_AC, 0172000000000+I_AC, 0173000000000+I_AC, - 0174000000000+I_AC, 0175000000000+I_AC, 0176000000000+I_AC, 0177000000000+I_AC, + INT64_C(0100000000000)+I_AC, INT64_C(0102000000000)+I_AC, INT64_C(0103000000000)+I_AC, + INT64_C(0104000000000)+I_AC, INT64_C(0105000000000)+I_AC, INT64_C(0106000000000)+I_AC, INT64_C(0107000000000)+I_AC, + INT64_C(0110000000000)+I_AC, INT64_C(0111000000000)+I_AC, INT64_C(0112000000000)+I_AC, INT64_C(0113000000000)+I_AC, + INT64_C(0114000000000)+I_AC, INT64_C(0115000000000)+I_AC, INT64_C(0116000000000)+I_AC, INT64_C(0117000000000)+I_AC, + INT64_C(0120000000000)+I_AC, INT64_C(0121000000000)+I_AC, INT64_C(0122000000000)+I_AC, INT64_C(0123000000000)+I_AC, + INT64_C(0124000000000)+I_AC, INT64_C(0125000000000)+I_AC, INT64_C(0126000000000)+I_AC, INT64_C(0127000000000)+I_AC, + INT64_C(0130000000000)+I_AC, INT64_C(0131000000000)+I_AC, INT64_C(0132000000000)+I_AC, INT64_C(0133000000000)+I_AC, + INT64_C(0134000000000)+I_AC, INT64_C(0135000000000)+I_AC, INT64_C(0136000000000)+I_AC, INT64_C(0137000000000)+I_AC, + INT64_C(0140000000000)+I_AC, INT64_C(0141000000000)+I_AC, INT64_C(0142000000000)+I_AC, INT64_C(0143000000000)+I_AC, + INT64_C(0144000000000)+I_AC, INT64_C(0145000000000)+I_AC, INT64_C(0146000000000)+I_AC, INT64_C(0147000000000)+I_AC, + INT64_C(0150000000000)+I_AC, INT64_C(0151000000000)+I_AC, INT64_C(0152000000000)+I_AC, INT64_C(0153000000000)+I_AC, + INT64_C(0154000000000)+I_AC, INT64_C(0155000000000)+I_AC, INT64_C(0156000000000)+I_AC, INT64_C(0157000000000)+I_AC, + INT64_C(0160000000000)+I_AC, INT64_C(0161000000000)+I_AC, INT64_C(0162000000000)+I_AC, INT64_C(0163000000000)+I_AC, + INT64_C(0164000000000)+I_AC, INT64_C(0165000000000)+I_AC, INT64_C(0166000000000)+I_AC, INT64_C(0167000000000)+I_AC, + INT64_C(0170000000000)+I_AC, INT64_C(0171000000000)+I_AC, INT64_C(0172000000000)+I_AC, INT64_C(0173000000000)+I_AC, + INT64_C(0174000000000)+I_AC, INT64_C(0175000000000)+I_AC, INT64_C(0176000000000)+I_AC, INT64_C(0177000000000)+I_AC, - 0200000000000+I_AC, 0201000000000+I_AC, 0202000000000+I_AC, 0203000000000+I_AC, - 0204000000000+I_AC, 0205000000000+I_AC, 0206000000000+I_AC, 0207000000000+I_AC, - 0210000000000+I_AC, 0211000000000+I_AC, 0212000000000+I_AC, 0213000000000+I_AC, - 0214000000000+I_AC, 0215000000000+I_AC, 0216000000000+I_AC, 0217000000000+I_AC, - 0220000000000+I_AC, 0221000000000+I_AC, 0222000000000+I_AC, 0223000000000+I_AC, - 0224000000000+I_AC, 0225000000000+I_AC, 0226000000000+I_AC, 0227000000000+I_AC, - 0230000000000+I_AC, 0231000000000+I_AC, 0232000000000+I_AC, 0233000000000+I_AC, - 0234000000000+I_AC, 0235000000000+I_AC, 0236000000000+I_AC, 0237000000000+I_AC, - 0240000000000+I_AC, 0241000000000+I_AC, 0242000000000+I_AC, 0243000000000+I_AC, - 0244000000000+I_AC, 0245000000000+I_AC, 0246000000000+I_AC, 0247000000000+I_AC+I_ITS, - 0250000000000+I_AC, 0251000000000+I_AC, 0252000000000+I_AC, 0253000000000+I_AC, - 0254000000000+I_AC, 0255000000000+I_AC, 0256000000000+I_AC, 0257000000000+I_AC, - 0260000000000+I_AC, 0261000000000+I_AC, 0262000000000+I_AC, 0263000000000+I_AC, - 0264000000000+I_AC, 0265000000000+I_AC, 0266000000000+I_AC, 0267000000000+I_AC, - 0270000000000+I_AC, 0271000000000+I_AC, 0272000000000+I_AC, 0273000000000+I_AC, - 0274000000000+I_AC, 0275000000000+I_AC, 0276000000000+I_AC, 0277000000000+I_AC, + INT64_C(0200000000000)+I_AC, INT64_C(0201000000000)+I_AC, INT64_C(0202000000000)+I_AC, INT64_C(0203000000000)+I_AC, + INT64_C(0204000000000)+I_AC, INT64_C(0205000000000)+I_AC, INT64_C(0206000000000)+I_AC, INT64_C(0207000000000)+I_AC, + INT64_C(0210000000000)+I_AC, INT64_C(0211000000000)+I_AC, INT64_C(0212000000000)+I_AC, INT64_C(0213000000000)+I_AC, + INT64_C(0214000000000)+I_AC, INT64_C(0215000000000)+I_AC, INT64_C(0216000000000)+I_AC, INT64_C(0217000000000)+I_AC, + INT64_C(0220000000000)+I_AC, INT64_C(0221000000000)+I_AC, INT64_C(0222000000000)+I_AC, INT64_C(0223000000000)+I_AC, + INT64_C(0224000000000)+I_AC, INT64_C(0225000000000)+I_AC, INT64_C(0226000000000)+I_AC, INT64_C(0227000000000)+I_AC, + INT64_C(0230000000000)+I_AC, INT64_C(0231000000000)+I_AC, INT64_C(0232000000000)+I_AC, INT64_C(0233000000000)+I_AC, + INT64_C(0234000000000)+I_AC, INT64_C(0235000000000)+I_AC, INT64_C(0236000000000)+I_AC, INT64_C(0237000000000)+I_AC, + INT64_C(0240000000000)+I_AC, INT64_C(0241000000000)+I_AC, INT64_C(0242000000000)+I_AC, INT64_C(0243000000000)+I_AC, + INT64_C(0244000000000)+I_AC, INT64_C(0245000000000)+I_AC, INT64_C(0246000000000)+I_AC, INT64_C(0247000000000)+I_AC+I_ITS, + INT64_C(0250000000000)+I_AC, INT64_C(0251000000000)+I_AC, INT64_C(0252000000000)+I_AC, INT64_C(0253000000000)+I_AC, + INT64_C(0254000000000)+I_AC, INT64_C(0255000000000)+I_AC, INT64_C(0256000000000)+I_AC, INT64_C(0257000000000)+I_AC, + INT64_C(0260000000000)+I_AC, INT64_C(0261000000000)+I_AC, INT64_C(0262000000000)+I_AC, INT64_C(0263000000000)+I_AC, + INT64_C(0264000000000)+I_AC, INT64_C(0265000000000)+I_AC, INT64_C(0266000000000)+I_AC, INT64_C(0267000000000)+I_AC, + INT64_C(0270000000000)+I_AC, INT64_C(0271000000000)+I_AC, INT64_C(0272000000000)+I_AC, INT64_C(0273000000000)+I_AC, + INT64_C(0274000000000)+I_AC, INT64_C(0275000000000)+I_AC, INT64_C(0276000000000)+I_AC, INT64_C(0277000000000)+I_AC, - 0300000000000+I_AC, 0301000000000+I_AC, 0302000000000+I_AC, 0303000000000+I_AC, - 0304000000000+I_AC, 0305000000000+I_AC, 0306000000000+I_AC, 0307000000000+I_AC, - 0310000000000+I_AC, 0311000000000+I_AC, 0312000000000+I_AC, 0313000000000+I_AC, - 0314000000000+I_AC, 0315000000000+I_AC, 0316000000000+I_AC, 0317000000000+I_AC, - 0320000000000+I_AC, 0321000000000+I_AC, 0322000000000+I_AC, 0323000000000+I_AC, - 0324000000000+I_AC, 0325000000000+I_AC, 0326000000000+I_AC, 0327000000000+I_AC, - 0330000000000+I_AC, 0331000000000+I_AC, 0332000000000+I_AC, 0333000000000+I_AC, - 0334000000000+I_AC, 0335000000000+I_AC, 0336000000000+I_AC, 0337000000000+I_AC, - 0340000000000+I_AC, 0341000000000+I_AC, 0342000000000+I_AC, 0343000000000+I_AC, - 0344000000000+I_AC, 0345000000000+I_AC, 0346000000000+I_AC, 0347000000000+I_AC, - 0350000000000+I_AC, 0351000000000+I_AC, 0352000000000+I_AC, 0353000000000+I_AC, - 0354000000000+I_AC, 0355000000000+I_AC, 0356000000000+I_AC, 0357000000000+I_AC, - 0360000000000+I_AC, 0361000000000+I_AC, 0362000000000+I_AC, 0363000000000+I_AC, - 0364000000000+I_AC, 0365000000000+I_AC, 0366000000000+I_AC, 0367000000000+I_AC, - 0370000000000+I_AC, 0371000000000+I_AC, 0372000000000+I_AC, 0373000000000+I_AC, - 0374000000000+I_AC, 0375000000000+I_AC, 0376000000000+I_AC, 0377000000000+I_AC, + INT64_C(0300000000000)+I_AC, INT64_C(0301000000000)+I_AC, INT64_C(0302000000000)+I_AC, INT64_C(0303000000000)+I_AC, + INT64_C(0304000000000)+I_AC, INT64_C(0305000000000)+I_AC, INT64_C(0306000000000)+I_AC, INT64_C(0307000000000)+I_AC, + INT64_C(0310000000000)+I_AC, INT64_C(0311000000000)+I_AC, INT64_C(0312000000000)+I_AC, INT64_C(0313000000000)+I_AC, + INT64_C(0314000000000)+I_AC, INT64_C(0315000000000)+I_AC, INT64_C(0316000000000)+I_AC, INT64_C(0317000000000)+I_AC, + INT64_C(0320000000000)+I_AC, INT64_C(0321000000000)+I_AC, INT64_C(0322000000000)+I_AC, INT64_C(0323000000000)+I_AC, + INT64_C(0324000000000)+I_AC, INT64_C(0325000000000)+I_AC, INT64_C(0326000000000)+I_AC, INT64_C(0327000000000)+I_AC, + INT64_C(0330000000000)+I_AC, INT64_C(0331000000000)+I_AC, INT64_C(0332000000000)+I_AC, INT64_C(0333000000000)+I_AC, + INT64_C(0334000000000)+I_AC, INT64_C(0335000000000)+I_AC, INT64_C(0336000000000)+I_AC, INT64_C(0337000000000)+I_AC, + INT64_C(0340000000000)+I_AC, INT64_C(0341000000000)+I_AC, INT64_C(0342000000000)+I_AC, INT64_C(0343000000000)+I_AC, + INT64_C(0344000000000)+I_AC, INT64_C(0345000000000)+I_AC, INT64_C(0346000000000)+I_AC, INT64_C(0347000000000)+I_AC, + INT64_C(0350000000000)+I_AC, INT64_C(0351000000000)+I_AC, INT64_C(0352000000000)+I_AC, INT64_C(0353000000000)+I_AC, + INT64_C(0354000000000)+I_AC, INT64_C(0355000000000)+I_AC, INT64_C(0356000000000)+I_AC, INT64_C(0357000000000)+I_AC, + INT64_C(0360000000000)+I_AC, INT64_C(0361000000000)+I_AC, INT64_C(0362000000000)+I_AC, INT64_C(0363000000000)+I_AC, + INT64_C(0364000000000)+I_AC, INT64_C(0365000000000)+I_AC, INT64_C(0366000000000)+I_AC, INT64_C(0367000000000)+I_AC, + INT64_C(0370000000000)+I_AC, INT64_C(0371000000000)+I_AC, INT64_C(0372000000000)+I_AC, INT64_C(0373000000000)+I_AC, + INT64_C(0374000000000)+I_AC, INT64_C(0375000000000)+I_AC, INT64_C(0376000000000)+I_AC, INT64_C(0377000000000)+I_AC, - 0400000000000+I_AC, 0401000000000+I_AC, 0402000000000+I_AC, 0403000000000+I_AC, - 0404000000000+I_AC, 0405000000000+I_AC, 0406000000000+I_AC, 0407000000000+I_AC, - 0410000000000+I_AC, 0411000000000+I_AC, 0412000000000+I_AC, 0413000000000+I_AC, - 0414000000000+I_AC, 0415000000000+I_AC, 0416000000000+I_AC, 0417000000000+I_AC, - 0420000000000+I_AC, 0421000000000+I_AC, 0422000000000+I_AC, 0423000000000+I_AC, - 0424000000000+I_AC, 0425000000000+I_AC, 0426000000000+I_AC, 0427000000000+I_AC, - 0430000000000+I_AC, 0431000000000+I_AC, 0432000000000+I_AC, 0433000000000+I_AC, - 0434000000000+I_AC, 0435000000000+I_AC, 0436000000000+I_AC, 0437000000000+I_AC, - 0440000000000+I_AC, 0441000000000+I_AC, 0442000000000+I_AC, 0443000000000+I_AC, - 0444000000000+I_AC, 0445000000000+I_AC, 0446000000000+I_AC, 0447000000000+I_AC, - 0450000000000+I_AC, 0451000000000+I_AC, 0452000000000+I_AC, 0453000000000+I_AC, - 0454000000000+I_AC, 0455000000000+I_AC, 0456000000000+I_AC, 0457000000000+I_AC, - 0460000000000+I_AC, 0461000000000+I_AC, 0462000000000+I_AC, 0463000000000+I_AC, - 0464000000000+I_AC, 0465000000000+I_AC, 0466000000000+I_AC, 0467000000000+I_AC, - 0470000000000+I_AC, 0471000000000+I_AC, 0472000000000+I_AC, 0473000000000+I_AC, - 0474000000000+I_AC, 0475000000000+I_AC, 0476000000000+I_AC, 0477000000000+I_AC, + INT64_C(0400000000000)+I_AC, INT64_C(0401000000000)+I_AC, INT64_C(0402000000000)+I_AC, INT64_C(0403000000000)+I_AC, + INT64_C(0404000000000)+I_AC, INT64_C(0405000000000)+I_AC, INT64_C(0406000000000)+I_AC, INT64_C(0407000000000)+I_AC, + INT64_C(0410000000000)+I_AC, INT64_C(0411000000000)+I_AC, INT64_C(0412000000000)+I_AC, INT64_C(0413000000000)+I_AC, + INT64_C(0414000000000)+I_AC, INT64_C(0415000000000)+I_AC, INT64_C(0416000000000)+I_AC, INT64_C(0417000000000)+I_AC, + INT64_C(0420000000000)+I_AC, INT64_C(0421000000000)+I_AC, INT64_C(0422000000000)+I_AC, INT64_C(0423000000000)+I_AC, + INT64_C(0424000000000)+I_AC, INT64_C(0425000000000)+I_AC, INT64_C(0426000000000)+I_AC, INT64_C(0427000000000)+I_AC, + INT64_C(0430000000000)+I_AC, INT64_C(0431000000000)+I_AC, INT64_C(0432000000000)+I_AC, INT64_C(0433000000000)+I_AC, + INT64_C(0434000000000)+I_AC, INT64_C(0435000000000)+I_AC, INT64_C(0436000000000)+I_AC, INT64_C(0437000000000)+I_AC, + INT64_C(0440000000000)+I_AC, INT64_C(0441000000000)+I_AC, INT64_C(0442000000000)+I_AC, INT64_C(0443000000000)+I_AC, + INT64_C(0444000000000)+I_AC, INT64_C(0445000000000)+I_AC, INT64_C(0446000000000)+I_AC, INT64_C(0447000000000)+I_AC, + INT64_C(0450000000000)+I_AC, INT64_C(0451000000000)+I_AC, INT64_C(0452000000000)+I_AC, INT64_C(0453000000000)+I_AC, + INT64_C(0454000000000)+I_AC, INT64_C(0455000000000)+I_AC, INT64_C(0456000000000)+I_AC, INT64_C(0457000000000)+I_AC, + INT64_C(0460000000000)+I_AC, INT64_C(0461000000000)+I_AC, INT64_C(0462000000000)+I_AC, INT64_C(0463000000000)+I_AC, + INT64_C(0464000000000)+I_AC, INT64_C(0465000000000)+I_AC, INT64_C(0466000000000)+I_AC, INT64_C(0467000000000)+I_AC, + INT64_C(0470000000000)+I_AC, INT64_C(0471000000000)+I_AC, INT64_C(0472000000000)+I_AC, INT64_C(0473000000000)+I_AC, + INT64_C(0474000000000)+I_AC, INT64_C(0475000000000)+I_AC, INT64_C(0476000000000)+I_AC, INT64_C(0477000000000)+I_AC, - 0500000000000+I_AC, 0501000000000+I_AC, 0502000000000+I_AC, 0503000000000+I_AC, - 0504000000000+I_AC, 0505000000000+I_AC, 0506000000000+I_AC, 0507000000000+I_AC, - 0510000000000+I_AC, 0511000000000+I_AC, 0512000000000+I_AC, 0513000000000+I_AC, - 0514000000000+I_AC, 0515000000000+I_AC, 0516000000000+I_AC, 0517000000000+I_AC, - 0520000000000+I_AC, 0521000000000+I_AC, 0522000000000+I_AC, 0523000000000+I_AC, - 0524000000000+I_AC, 0525000000000+I_AC, 0526000000000+I_AC, 0527000000000+I_AC, - 0530000000000+I_AC, 0531000000000+I_AC, 0532000000000+I_AC, 0533000000000+I_AC, - 0534000000000+I_AC, 0535000000000+I_AC, 0536000000000+I_AC, 0537000000000+I_AC, - 0540000000000+I_AC, 0541000000000+I_AC, 0542000000000+I_AC, 0543000000000+I_AC, - 0544000000000+I_AC, 0545000000000+I_AC, 0546000000000+I_AC, 0547000000000+I_AC, - 0550000000000+I_AC, 0551000000000+I_AC, 0552000000000+I_AC, 0553000000000+I_AC, - 0554000000000+I_AC, 0555000000000+I_AC, 0556000000000+I_AC, 0557000000000+I_AC, - 0560000000000+I_AC, 0561000000000+I_AC, 0562000000000+I_AC, 0563000000000+I_AC, - 0564000000000+I_AC, 0565000000000+I_AC, 0566000000000+I_AC, 0567000000000+I_AC, - 0570000000000+I_AC, 0571000000000+I_AC, 0572000000000+I_AC, 0573000000000+I_AC, - 0574000000000+I_AC, 0575000000000+I_AC, 0576000000000+I_AC, 0577000000000+I_AC, + INT64_C(0500000000000)+I_AC, INT64_C(0501000000000)+I_AC, INT64_C(0502000000000)+I_AC, INT64_C(0503000000000)+I_AC, + INT64_C(0504000000000)+I_AC, INT64_C(0505000000000)+I_AC, INT64_C(0506000000000)+I_AC, INT64_C(0507000000000)+I_AC, + INT64_C(0510000000000)+I_AC, INT64_C(0511000000000)+I_AC, INT64_C(0512000000000)+I_AC, INT64_C(0513000000000)+I_AC, + INT64_C(0514000000000)+I_AC, INT64_C(0515000000000)+I_AC, INT64_C(0516000000000)+I_AC, INT64_C(0517000000000)+I_AC, + INT64_C(0520000000000)+I_AC, INT64_C(0521000000000)+I_AC, INT64_C(0522000000000)+I_AC, INT64_C(0523000000000)+I_AC, + INT64_C(0524000000000)+I_AC, INT64_C(0525000000000)+I_AC, INT64_C(0526000000000)+I_AC, INT64_C(0527000000000)+I_AC, + INT64_C(0530000000000)+I_AC, INT64_C(0531000000000)+I_AC, INT64_C(0532000000000)+I_AC, INT64_C(0533000000000)+I_AC, + INT64_C(0534000000000)+I_AC, INT64_C(0535000000000)+I_AC, INT64_C(0536000000000)+I_AC, INT64_C(0537000000000)+I_AC, + INT64_C(0540000000000)+I_AC, INT64_C(0541000000000)+I_AC, INT64_C(0542000000000)+I_AC, INT64_C(0543000000000)+I_AC, + INT64_C(0544000000000)+I_AC, INT64_C(0545000000000)+I_AC, INT64_C(0546000000000)+I_AC, INT64_C(0547000000000)+I_AC, + INT64_C(0550000000000)+I_AC, INT64_C(0551000000000)+I_AC, INT64_C(0552000000000)+I_AC, INT64_C(0553000000000)+I_AC, + INT64_C(0554000000000)+I_AC, INT64_C(0555000000000)+I_AC, INT64_C(0556000000000)+I_AC, INT64_C(0557000000000)+I_AC, + INT64_C(0560000000000)+I_AC, INT64_C(0561000000000)+I_AC, INT64_C(0562000000000)+I_AC, INT64_C(0563000000000)+I_AC, + INT64_C(0564000000000)+I_AC, INT64_C(0565000000000)+I_AC, INT64_C(0566000000000)+I_AC, INT64_C(0567000000000)+I_AC, + INT64_C(0570000000000)+I_AC, INT64_C(0571000000000)+I_AC, INT64_C(0572000000000)+I_AC, INT64_C(0573000000000)+I_AC, + INT64_C(0574000000000)+I_AC, INT64_C(0575000000000)+I_AC, INT64_C(0576000000000)+I_AC, INT64_C(0577000000000)+I_AC, - 0600000000000+I_AC, 0601000000000+I_AC, 0602000000000+I_AC, 0603000000000+I_AC, - 0604000000000+I_AC, 0605000000000+I_AC, 0606000000000+I_AC, 0607000000000+I_AC, - 0610000000000+I_AC, 0611000000000+I_AC, 0612000000000+I_AC, 0613000000000+I_AC, - 0614000000000+I_AC, 0615000000000+I_AC, 0616000000000+I_AC, 0617000000000+I_AC, - 0620000000000+I_AC, 0621000000000+I_AC, 0622000000000+I_AC, 0623000000000+I_AC, - 0624000000000+I_AC, 0625000000000+I_AC, 0626000000000+I_AC, 0627000000000+I_AC, - 0630000000000+I_AC, 0631000000000+I_AC, 0632000000000+I_AC, 0633000000000+I_AC, - 0634000000000+I_AC, 0635000000000+I_AC, 0636000000000+I_AC, 0637000000000+I_AC, - 0640000000000+I_AC, 0641000000000+I_AC, 0642000000000+I_AC, 0643000000000+I_AC, - 0644000000000+I_AC, 0645000000000+I_AC, 0646000000000+I_AC, 0647000000000+I_AC, - 0650000000000+I_AC, 0651000000000+I_AC, 0652000000000+I_AC, 0653000000000+I_AC, - 0654000000000+I_AC, 0655000000000+I_AC, 0656000000000+I_AC, 0657000000000+I_AC, - 0660000000000+I_AC, 0661000000000+I_AC, 0662000000000+I_AC, 0663000000000+I_AC, - 0664000000000+I_AC, 0665000000000+I_AC, 0666000000000+I_AC, 0667000000000+I_AC, - 0670000000000+I_AC, 0671000000000+I_AC, 0672000000000+I_AC, 0673000000000+I_AC, - 0674000000000+I_AC, 0675000000000+I_AC, 0676000000000+I_AC, 0677000000000+I_AC, + INT64_C(0600000000000)+I_AC, INT64_C(0601000000000)+I_AC, INT64_C(0602000000000)+I_AC, INT64_C(0603000000000)+I_AC, + INT64_C(0604000000000)+I_AC, INT64_C(0605000000000)+I_AC, INT64_C(0606000000000)+I_AC, INT64_C(0607000000000)+I_AC, + INT64_C(0610000000000)+I_AC, INT64_C(0611000000000)+I_AC, INT64_C(0612000000000)+I_AC, INT64_C(0613000000000)+I_AC, + INT64_C(0614000000000)+I_AC, INT64_C(0615000000000)+I_AC, INT64_C(0616000000000)+I_AC, INT64_C(0617000000000)+I_AC, + INT64_C(0620000000000)+I_AC, INT64_C(0621000000000)+I_AC, INT64_C(0622000000000)+I_AC, INT64_C(0623000000000)+I_AC, + INT64_C(0624000000000)+I_AC, INT64_C(0625000000000)+I_AC, INT64_C(0626000000000)+I_AC, INT64_C(0627000000000)+I_AC, + INT64_C(0630000000000)+I_AC, INT64_C(0631000000000)+I_AC, INT64_C(0632000000000)+I_AC, INT64_C(0633000000000)+I_AC, + INT64_C(0634000000000)+I_AC, INT64_C(0635000000000)+I_AC, INT64_C(0636000000000)+I_AC, INT64_C(0637000000000)+I_AC, + INT64_C(0640000000000)+I_AC, INT64_C(0641000000000)+I_AC, INT64_C(0642000000000)+I_AC, INT64_C(0643000000000)+I_AC, + INT64_C(0644000000000)+I_AC, INT64_C(0645000000000)+I_AC, INT64_C(0646000000000)+I_AC, INT64_C(0647000000000)+I_AC, + INT64_C(0650000000000)+I_AC, INT64_C(0651000000000)+I_AC, INT64_C(0652000000000)+I_AC, INT64_C(0653000000000)+I_AC, + INT64_C(0654000000000)+I_AC, INT64_C(0655000000000)+I_AC, INT64_C(0656000000000)+I_AC, INT64_C(0657000000000)+I_AC, + INT64_C(0660000000000)+I_AC, INT64_C(0661000000000)+I_AC, INT64_C(0662000000000)+I_AC, INT64_C(0663000000000)+I_AC, + INT64_C(0664000000000)+I_AC, INT64_C(0665000000000)+I_AC, INT64_C(0666000000000)+I_AC, INT64_C(0667000000000)+I_AC, + INT64_C(0670000000000)+I_AC, INT64_C(0671000000000)+I_AC, INT64_C(0672000000000)+I_AC, INT64_C(0673000000000)+I_AC, + INT64_C(0674000000000)+I_AC, INT64_C(0675000000000)+I_AC, INT64_C(0676000000000)+I_AC, INT64_C(0677000000000)+I_AC, - 0704000000000+I_AC, 0705000000000+I_AC, - 0710000000000+I_AC, 0711000000000+I_AC, 0712000000000+I_AC, 0713000000000+I_AC, - 0714000000000+I_AC, 0715000000000+I_AC, 0716000000000+I_AC, 0717000000000+I_AC, - 0720000000000+I_AC, 0721000000000+I_AC, 0722000000000+I_AC, 0723000000000+I_AC, - 0724000000000+I_AC, 0725000000000+I_AC, + INT64_C(0704000000000)+I_AC, INT64_C(0705000000000)+I_AC, + INT64_C(0710000000000)+I_AC, INT64_C(0711000000000)+I_AC, INT64_C(0712000000000)+I_AC, INT64_C(0713000000000)+I_AC, + INT64_C(0714000000000)+I_AC, INT64_C(0715000000000)+I_AC, INT64_C(0716000000000)+I_AC, INT64_C(0717000000000)+I_AC, + INT64_C(0720000000000)+I_AC, INT64_C(0721000000000)+I_AC, INT64_C(0722000000000)+I_AC, INT64_C(0723000000000)+I_AC, + INT64_C(0724000000000)+I_AC, INT64_C(0725000000000)+I_AC, - 0700000000000+I_IO, 0700040000000+I_IO, 0700100000000+I_IO, 0700140000000+I_IO, - 0700200000000+I_IO, 0700240000000+I_IO, 0700300000000+I_IO, 0700340000000+I_IO, + INT64_C(0700000000000)+I_IO, INT64_C(0700040000000)+I_IO, INT64_C(0700100000000)+I_IO, INT64_C(0700140000000)+I_IO, + INT64_C(0700200000000)+I_IO, INT64_C(0700240000000)+I_IO, INT64_C(0700300000000)+I_IO, INT64_C(0700340000000)+I_IO, - 0400000000000+I_AC, 0401000000000+I_AC, 0402000000000+I_AC, 0403000000000+I_AC, - 0434000000000+I_AC, 0435000000000+I_AC, 0436000000000+I_AC, 0437000000000+I_AC, - 0415000000000+I_AC, 0501000000000+I_AC, + INT64_C(0400000000000)+I_AC, INT64_C(0401000000000)+I_AC, INT64_C(0402000000000)+I_AC, INT64_C(0403000000000)+I_AC, + INT64_C(0434000000000)+I_AC, INT64_C(0435000000000)+I_AC, INT64_C(0436000000000)+I_AC, INT64_C(0437000000000)+I_AC, + INT64_C(0415000000000)+I_AC, INT64_C(0501000000000)+I_AC, - 0001000000000+I_AC, 0002000000000+I_AC, 0003000000000+I_AC, - 0004000000000+I_AC, 0005000000000+I_AC, 0006000000000+I_AC, 0007000000000+I_AC, - 0010000000000+I_AC, 0011000000000+I_AC, 0012000000000+I_AC, 0013000000000+I_AC, - 0014000000000+I_AC, 0015000000000+I_AC, 0016000000000+I_AC, 0017000000000+I_AC, - 0020000000000+I_AC, 0021000000000+I_AC, 0022000000000+I_AC, 0023000000000+I_AC, - 0024000000000+I_AC, 0025000000000+I_AC, 0026000000000+I_AC, 0027000000000+I_AC, - 0030000000000+I_AC, 0031000000000+I_AC, - -1 + INT64_C(0001000000000)+I_AC, INT64_C(0002000000000)+I_AC, INT64_C(0003000000000)+I_AC, + INT64_C(0004000000000)+I_AC, INT64_C(0005000000000)+I_AC, INT64_C(0006000000000)+I_AC, INT64_C(0007000000000)+I_AC, + INT64_C(0010000000000)+I_AC, INT64_C(0011000000000)+I_AC, INT64_C(0012000000000)+I_AC, INT64_C(0013000000000)+I_AC, + INT64_C(0014000000000)+I_AC, INT64_C(0015000000000)+I_AC, INT64_C(0016000000000)+I_AC, INT64_C(0017000000000)+I_AC, + INT64_C(0020000000000)+I_AC, INT64_C(0021000000000)+I_AC, INT64_C(0022000000000)+I_AC, INT64_C(0023000000000)+I_AC, + INT64_C(0024000000000)+I_AC, INT64_C(0025000000000)+I_AC, INT64_C(0026000000000)+I_AC, INT64_C(0027000000000)+I_AC, + INT64_C(0030000000000)+I_AC, INT64_C(0031000000000)+I_AC, + -INT64_C(1) }; #define NUMDEV 6 @@ -693,11 +694,10 @@ static const char *devnam[NUMDEV] = { t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, UNIT *uptr, int32 sw) { -int32 i, j, c, cflag, ac, xr, y, dev; +int32 i, j, c, ac, xr, y, dev; d10 inst; inst = val[0]; -cflag = (uptr == NULL) || (uptr == &cpu_unit); if (sw & SWMASK ('A')) { /* ASCII? */ if (inst > 0377) return SCPE_ARG; @@ -708,14 +708,14 @@ if (sw & SWMASK ('C')) { /* character? */ for (i = 30; i >= 0; i = i - 6) { c = (int32) ((inst >> i) & 077); fprintf (of, "%c", SIXTOASC (c)); - } + } return SCPE_OK; } if (sw & SWMASK ('P')) { /* packed? */ for (i = 29; i >= 0; i = i - 7) { c = (int32) ((inst >> i) & 0177); fprintf (of, FMTASC (c)); - } + } return SCPE_OK; } if (!(sw & SWMASK ('M'))) @@ -820,12 +820,11 @@ return (ind | (xr << 18) | val); t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw) { -int32 cflag, i, j; +int32 i, j; t_value ac, dev; t_stat r; char gbuf[CBUFSIZE]; -cflag = (uptr == NULL) || (uptr == &cpu_unit); while (isspace (*cptr)) cptr++; for (i = 0; i < 6; i++) { if (cptr[i] == 0) { diff --git a/PDP10/pdp10_tim.c b/PDP10/pdp10_tim.c index c15cd503..0f410361 100644 --- a/PDP10/pdp10_tim.c +++ b/PDP10/pdp10_tim.c @@ -1,6 +1,6 @@ /* pdp10_tim.c: PDP-10 tim subsystem simulator - Copyright (c) 1993-2012, Robert M Supnik + Copyright (c) 1993-2015, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -39,44 +39,105 @@ */ #include "pdp10_defs.h" +#include #include +/* The KS timer works off a 4.100 MHz (243.9024 nsec) oscillator that + * is independent of all other system timing. + * + * Two pieces of timekeeping hardware are exposed to the OS. + * o The interval timer, which can interrupt at a programmed interval. + * o The timebase, which records time (71 bits). + * + * The clock is architecturally readable in units of 243.9024 nsec via + * the timebase. The implementation is somewhat different. + * + * The instructions that update the clocks specify time in these units. + * + * However, both timekeepers are incremented by the microcode when + * a 12 bit counter overflows; e.g. at a period of 999.0244 usec. + * Thus, the granularity of timer interrupts is approximately 1 msec. + * + * The OS programs the interval timer to interrupt as though the + * the 12 least significant bits mattered. Thus, for a (roughly) + * 1 msec interval, it would program 1 * 4096 into the interval timer. + * The sign bit is not used, so 35-12 = 23 bits for the maximum interval, + * which is 139.674 minutes. If any of the least significant bits + * are non-zero, the interval is extended by 1 * 4096 counts. + * + * The timer merely sets the INTERVAL DONE flag in the APR flags. + * Whether that actually causes an interrupt is controlled by the + * APR interrupt enable for the flag and by the PI system. + * + * The flag is readable as an APR condition by RDAPR, and CONSO/Z APR,. + * The flag is cleared by WRAPR 1b22!1b30 (clear, count done). + * + * The timebase is maintained with the 12 LSB zero in a workspace + * register. When read by the OS, the actual value of the 10 MSB of + * the hardware counter is inserted into those bits, providing increased + * resolution. Although the system reference manual says otherwise, the + * two LSB of the counter are read as zero by the microcode (DPM2), so + * bits <70:71> of the timebase are also read as zero by software. + * + * When the OS sets the timebase, the 12 LSB that it supplies are ignored. + * + * The timebase is typically used for accurate time of day and CPU runtime + * accounting. The simulator adjusts the equivalent of the 12-bit counter, + * so CPU time will reflect simulator wall clock, not simulated machine cycles. + * Since time of day must be accurate, this may result in the OS reporting + * CPU times that are unrealistically faster - or slower - than on the + * real hardware. + * + * This module also implements the TCU, a battery backed-up TOY clock + * that was supported by TOPS-10, but not sold by DEC. + */ + /* Invariants */ #define TIM_HW_FREQ 4100000 /* 4.1Mhz */ -#define TIM_HWRE_MASK 07777 +#define TIM_HWRE_MASK 07777 /* Timer field of timebase */ +#define TIM_BASE_RAZ 03 /* Timer bits read as zero by ucode */ #define UNIT_V_Y2K (UNIT_V_UF + 0) /* Y2K compliant OS */ #define UNIT_Y2K (1u << UNIT_V_Y2K) +#define TIM_TMXR_FREQ 60 /* Target frequency (HZ) for tmxr polls */ + + /* Estimate of simulator instructions/sec for initialization and fixed timing. + * This came from prior magic constant of 8000 at 60 tics/sec. + * The machine was marketed as ~ 300KIPs, which would imply 3 usec/instr. + * So 8,000 instructions should take ~24 msec. This would indicate that + * the simulator from which this came was ~1.4 x the speed of the real + * hardware. Current milage will vary. + */ +#define TIM_WAIT_IPS 480000 + /* Clock mode TOPS-10/ITS */ -#define TIM_TPS_T10 60 -#define TIM_WAIT_T10 8000 -#define TIM_MULT_T10 1 -#define TIM_ITS_QUANT (TIM_HW_FREQ / TIM_TPS_T10) +#define TIM_TPS_T10 60 /* Initial frequency guess for TOPS-10 (close, not exact) */ +#define TIM_ITS_QUANT (TIM_HW_FREQ / TIM_TPS_T10) /* ITS PC sampling and user runtime interval */ /* Clock mode TOPS-20/KLAD */ -#define TIM_TPS_T20 1001 -#define TIM_WAIT_T20 500 -#define TIM_MULT_T20 16 +#define TIM_TPS_T20 1000 /* Initial estimate for TOPS-20 - 1msec seems fast? */ /* Probability function for TOPS-20 idlelock */ #define PROB(x) (((rand() * 100) / RAND_MAX) >= (x)) -d10 tim_base[2] = { 0, 0 }; /* 71b timebase */ -d10 tim_ttg = 0; /* time to go */ -d10 tim_period = 0; /* period */ +static d10 tim_base[2] = { 0, 0 }; /* 71b timebase */ +static d10 tim_interval = 0; /* value programmed into the clock */ +static d10 tim_period = 0; /* period in HW ticks adjusted for non-zero LSBs */ +static d10 tim_new_period = 0; /* period for the next interval */ +static int32 tim_mult; /* Multiple of interval timer period at which tmxr is polled */ + d10 quant = 0; /* ITS quantum */ -int32 tim_mult = TIM_MULT_T10; /* tmxr poll mult */ -int32 tim_t20_prob = 33; /* TOPS-20 prob */ +static int32 tim_t20_prob = 33; /* TOPS-20 prob */ -/* Exported variables */ +/* Exported variables - initialized by set CPU model and reset */ -int32 clk_tps = TIM_TPS_T10; /* clock ticks/sec */ -int32 tmr_poll = TIM_WAIT_T10; /* clock poll */ -int32 tmxr_poll = TIM_WAIT_T10 * TIM_MULT_T10; /* term mux poll */ +int32 clk_tps; /* Interval clock ticks/sec */ +int32 tmr_poll; /* SimH instructions/clock service */ +int32 tmxr_poll; /* SimH instructions/term mux poll */ extern int32 apr_flg, pi_act; extern UNIT cpu_unit; @@ -85,10 +146,11 @@ extern a10 pager_PC; extern int32 t20_idlelock; DEVICE tim_dev; -t_stat tcu_rd (int32 *data, int32 PA, int32 access); -t_stat tim_svc (UNIT *uptr); -t_stat tim_reset (DEVICE *dptr); -void tim_incr_base (d10 *base, d10 incr); +static t_stat tcu_rd (int32 *data, int32 PA, int32 access); +static t_stat tim_svc (UNIT *uptr); +static t_stat tim_reset (DEVICE *dptr); +static t_bool update_interval (d10 new_interval); +static void tim_incr_base (d10 *base, d10 incr); extern d10 Read (a10 ea, int32 prv); extern d10 ReadM (a10 ea, int32 prv); @@ -106,11 +168,10 @@ extern t_stat wr_nop (int32 data, int32 PA, int32 access); DIB tcu_dib = { IOBA_TCU, IOLN_TCU, &tcu_rd, &wr_nop, 0 }; -UNIT tim_unit = { UDATA (&tim_svc, UNIT_IDLE, 0), TIM_WAIT_T10 }; +static UNIT tim_unit = { UDATA (&tim_svc, UNIT_IDLE, 0), 0 }; -REG tim_reg[] = { +static REG tim_reg[] = { { BRDATA (TIMEBASE, tim_base, 8, 36, 2) }, - { ORDATA (TTG, tim_ttg, 36) }, { ORDATA (PERIOD, tim_period, 36) }, { ORDATA (QUANT, quant, 36) }, { DRDATA (TIME, tim_unit.wait, 24), REG_NZ + PV_LEFT }, @@ -122,7 +183,7 @@ REG tim_reg[] = { { NULL } }; -MTAB tim_mod[] = { +static MTAB tim_mod[] = { { UNIT_Y2K, 0, "non Y2K OS", "NOY2K", NULL }, { UNIT_Y2K, UNIT_Y2K, "Y2K OS", "Y2K", NULL }, { MTAB_XTD|MTAB_VDV, 000, "ADDRESS", NULL, @@ -140,26 +201,53 @@ DEVICE tim_dev = { /* Timer instructions */ -/* Timer - if the timer is running at less than hardware frequency, - need to interpolate the value by calculating how much of the current - clock tick has elapsed, and what that equates to in msec. */ +/* Timebase - the timer is always running at less than hardware frequency, + * need to interpolate the value by calculating how much of the current + * clock tick has elapsed, and what that equates to in sysfreq units. + */ t_bool rdtim (a10 ea, int32 prv) { -d10 tempbase[2]; +double fract; /* Fraction of current interval completed */ +d10 tempbase[2]; /* Local copy of tempbase to interpolate */ +int32 used; /* Used part of curr intv, in hw ticks */ +d10 incr; /* Interpolated increment for timebase */ -ReadM (INCA (ea), prv); /* check 2nd word */ tempbase[0] = tim_base[0]; /* copy time base */ tempbase[1] = tim_base[1]; -if (tim_mult != TIM_MULT_T20) { /* interpolate? */ - int32 used; - d10 incr; - used = tmr_poll - (sim_is_active (&tim_unit) - 1); - incr = (d10) (((double) used * TIM_HW_FREQ) / - ((double) tmr_poll * (double) clk_tps)); - tim_incr_base (tempbase, incr); - } -tempbase[0] = tempbase[0] & ~((d10) TIM_HWRE_MASK); /* clear low 12b */ + +used = tmr_poll - (sim_activate_time (&tim_unit) - 1); +fract = ((double)used) / ((double)tmr_poll); + +/* + * incr is approximate number of HW ticks to add to the timebase + * value returned. This does NOT update the timebase. + */ +incr = (d10)(fract * (double)tim_period); +tim_incr_base (tempbase, incr); + +/* Although the two LSB of the counter contribute carry to the + * value, they are read as zero by microcode, and thus cleared here. + * + * The reason that these bits are forced to zero in the hardware is + * that the counter is in a different clock domain from the microcode. + * To make the domain crossing, the microcode reads the counter + * until two consecutive values match. + * + * Since the microcode cycle time is 300 nsec, the LSBs of the + * counter run too fast (244 nsec) for the strategy to work. + * Ignoring the two LSB ensures that the value can't change any + * faster than ~976 nsec, which guarantees a stable value can be + * obtained in at most three attempts. + */ +tempbase[1] &= ~((d10) TIM_BASE_RAZ); + +/* If the destination is arranged so that the first word is OK, but + * the second pagefaults, the value will be half-written. As we + * expect the PFH to restart the instruction, the both halves will + * be written the second time. We could read and write back both + * halves to avoid this, but the hardware doesn't seem to either. + */ Write (ea, tempbase[0], prv); Write (INCA(ea), tempbase[1], prv); return FALSE; @@ -168,39 +256,77 @@ return FALSE; t_bool wrtim (a10 ea, int32 prv) { tim_base[0] = Read (ea, prv); -tim_base[1] = CLRS (Read (INCA (ea), prv)); +tim_base[1] = CLRS (Read (INCA (ea), prv) & ~((d10) TIM_HWRE_MASK)); return FALSE; } t_bool rdint (a10 ea, int32 prv) { -Write (ea, tim_period, prv); +Write (ea, tim_interval, prv); return FALSE; } +/* write a new interval timer period (in timer ticks). + * This does not clear the harware counter, so the first + * completion can come up to ~1 msc later than the new + * period. + */ + t_bool wrint (a10 ea, int32 prv) { -tim_period = Read (ea, prv); -tim_ttg = tim_period; +tim_interval = CLRS (Read (ea, prv)); +return update_interval (tim_interval); +} + +static t_bool update_interval (d10 new_interval) +{ +/* + * The value provided is in hardware clicks. For a frequency of 4.1 + * MHz, that means that dividing by 4096 (shifting 12 to the right) we get + * the aproximate value in millisenconds. If any of rhe rightmost bits is + * one, we add one unit (4096 ticks ). Reference: + * AA-H391A-TK_DECsystem-10_DECSYSTEM-20_Processor_Reference_Jun1982.pdf + * (page 4-37) + */ +tim_new_period = new_interval & ~TIM_HWRE_MASK; +if (new_interval & TIM_HWRE_MASK) tim_new_period += 010000; + +/* clk_tps is the new number of clocks ticks per second */ +clk_tps = (int32) ceil((double)TIM_HW_FREQ /(double)tim_new_period); + +/* tmxr is polled every tim_mult clks. Compute the divisor matching the target. */ +tim_mult = (clk_tps <= TIM_TMXR_FREQ) ? 1 : (clk_tps / TIM_TMXR_FREQ) ; + +/* Estimate instructions/tick for fixed timing - just for KLAD */ +tim_unit.wait = TIM_WAIT_IPS / clk_tps; +tmxr_poll = tim_unit.wait * tim_mult; + +/* The next tim_svc will update the activation time. + * + */ return FALSE; } -/* Timer service - the timer is only serviced when the 'ttg' register - has reached 0 based on the expected frequency of clock interrupts. */ +/* Timer service - the timer is only serviced when the interval + * programmed in tim_period by wrint expires. If the interval + * changes, the timebase update is based on the previous interval. + * The interval calibration is based on what the new interval will be. + */ -t_stat tim_svc (UNIT *uptr) +static t_stat tim_svc (UNIT *uptr) { if (cpu_unit.flags & UNIT_KLAD) /* diags? */ tmr_poll = uptr->wait; /* fixed clock */ else tmr_poll = sim_rtc_calb (clk_tps); /* else calibrate */ + sim_activate (uptr, tmr_poll); /* reactivate unit */ tmxr_poll = tmr_poll * tim_mult; /* set mux poll */ -tim_incr_base (tim_base, tim_period); /* incr time base */ -tim_ttg = tim_period; /* reload */ +tim_incr_base (tim_base, tim_period); /* incr time base based on period of expired interval */ +tim_period = tim_new_period; /* If interval has changed, update period */ apr_flg = apr_flg | APRF_TIM; /* request interrupt */ if (Q_ITS) { /* ITS? */ if (pi_act == 0) - quant = (quant + TIM_ITS_QUANT) & DMASK; + quant = (quant + TIM_ITS_QUANT) & DMASK; if (TSTS (pcst)) { /* PC sampling? */ WriteP ((a10) pcst & AMASK, pager_PC); /* store sample */ pcst = AOB (pcst); /* add 1,,1 */ @@ -217,13 +343,11 @@ int32 clk_cosched (int32 wait) { int32 t; -if (tim_mult == TIM_MULT_T20) - return wait; t = sim_is_active (&tim_unit); return (t? t - 1: wait); } -void tim_incr_base (d10 *base, d10 incr) +static void tim_incr_base (d10 *base, d10 incr) { base[1] = base[1] + incr; /* add on incr */ base[0] = base[0] + (base[1] >> 35); /* carry to high */ @@ -234,11 +358,28 @@ return; /* Timer reset */ -t_stat tim_reset (DEVICE *dptr) +static t_stat tim_reset (DEVICE *dptr) { -tim_period = 0; /* clear timer */ -tim_ttg = 0; +sim_register_clock_unit (&tim_unit); /* declare clock unit */ + +tim_base[0] = tim_base[1] = 0; /* clear timebase (HW does) */ +/* HW does not initialize the interval timer, so the rate at which the timer flag + * sets is random. No sensible user would enable interrupts or check the flag without + * setting an interval. The timebase is intialized to zero by microcode intialization. + * It increments based on the overflow, so it would be reasonable for a user to just + * read it twice and subtract the values to determine elapsed time. + * + * Simply to keep the simulator overhead down until the interval timer is initialized + * by the OS or diagnostic, we will set the internal interval to ~17 msec here. + * This allows the service routine to increment the timebase, and gives RDTIME an + * baseline for its interpolation. + */ +tim_interval = 0; +clk_tps = 60; +update_interval(17*4096); + apr_flg = apr_flg & ~APRF_TIM; /* clear interrupt */ + tmr_poll = sim_rtc_init (tim_unit.wait); /* init timer */ sim_activate (&tim_unit, tmr_poll); /* activate unit */ tmxr_poll = tmr_poll * tim_mult; /* set mux poll */ @@ -251,27 +392,32 @@ t_stat tim_set_mod (UNIT *uptr, int32 val, char *cptr, void *desc) { if (val & (UNIT_T20|UNIT_KLAD)) { clk_tps = TIM_TPS_T20; - uptr->wait = TIM_WAIT_T20; - tmr_poll = TIM_WAIT_T20; - tim_mult = TIM_MULT_T20; + update_interval(((d10)(1000*4096))/clk_tps); + tmr_poll = tim_unit.wait; uptr->flags = uptr->flags | UNIT_Y2K; } else { clk_tps = TIM_TPS_T10; - uptr->wait = TIM_WAIT_T10; - tmr_poll = TIM_WAIT_T10; - tim_mult = TIM_MULT_T10; + update_interval (((d10)(1000*4096))/clk_tps); + tmr_poll = tim_unit.wait; if (Q_ITS) uptr->flags = uptr->flags | UNIT_Y2K; else uptr->flags = uptr->flags & ~UNIT_Y2K; } -tmxr_poll = tmr_poll * tim_mult; return SCPE_OK; } -/* Time of year clock */ +/* Time of year clock + * + * The hardware clock was never sold by DEC, but support for it exists + * in TOPS-10. Code was also available for RSX20F to read and report the + * to the OS via its20F's SETSPD task. This implements only the read functions. + * + * The manufacturer's manual can be found at + * http://bitsavers.trailing-edge.com/pdf/digitalPathways/tcu-150.pdf + */ -t_stat tcu_rd (int32 *data, int32 PA, int32 access) +static t_stat tcu_rd (int32 *data, int32 PA, int32 access) { time_t curtim; struct tm *tptr; diff --git a/PDP10/pdp10_tu.c b/PDP10/pdp10_tu.c index 198c380b..af08ac43 100644 --- a/PDP10/pdp10_tu.c +++ b/PDP10/pdp10_tu.c @@ -93,6 +93,7 @@ #include "pdp10_defs.h" #include "sim_tape.h" +#include #define TU_NUMFM 1 /* #formatters */ #define TU_NUMDR 8 /* #drives */ @@ -100,6 +101,9 @@ #define UDENS u4 /* unit density */ #define UD_UNK 0 /* unknown */ #define MT_MAXFR (1 << 16) /* max data buf */ +#define TU_STATEFLAGS u5 /* Simulator state flags */ +#define TUS_ATTPENDING 0000001 /* Attach pending */ +#define SPINUPDLY 100*1000 /* 100 msec */ /* MTCS1 - 172440 - control/status 1 */ @@ -298,8 +302,6 @@ extern int32 int_req; extern int32 ubmap[UBANUM][UMAP_MEMSIZE]; /* Unibus map */ extern int32 ubcs[UBANUM]; extern UNIT cpu_unit; -extern int32 sim_switches; -extern FILE *sim_deb; int32 tucs1 = 0; /* control/status 1 */ int32 tuwc = 0; /* word count */ @@ -416,7 +418,7 @@ DEVICE tu_dev = { TU_NUMDR, 10, 31, 1, 8, 8, NULL, NULL, &tu_reset, &tu_boot, &tu_attach, &tu_detach, - &tu_dib, DEV_UBUS | DEV_DEBUG + &tu_dib, DEV_UBUS | DEV_DEBUG | DEV_TAPE }; /* I/O dispatch routine, I/O addresses 17772440 - 17772472 */ @@ -668,13 +670,18 @@ switch (fnc) { /* case on function */ tuer = 0; /* clear errors */ tutc = tutc & ~TC_FCS; /* clear fc status */ tufs = tufs & ~(FS_SAT | FS_SSC | FS_ID | FS_ERR); - sim_cancel (uptr); /* reset drive */ + if (!(uptr->TU_STATEFLAGS & TUS_ATTPENDING)) + sim_cancel (uptr); /* stop motion, not on-line delay */ uptr->USTAT = 0; case FNC_NOP: tucs1 = tucs1 & ~CS1_GO; /* no operation */ return; case FNC_RIP: /* read-in preset */ + if ((tufs & FS_MOL) == 0) { /* unattached? */ + set_tuer (ER_UNS); + break; + } tutc = TC_RIP; /* density = 800 */ sim_tape_rewind (&tu_unit[0]); /* rewind unit 0 */ tu_unit[0].USTAT = 0; @@ -683,7 +690,7 @@ switch (fnc) { /* case on function */ return; case FNC_UNLOAD: /* unload */ - if ((uptr->flags & UNIT_ATT) == 0) { /* unattached? */ + if ((tufs & FS_MOL) == 0) { /* unattached? */ set_tuer (ER_UNS); break; } @@ -695,7 +702,7 @@ switch (fnc) { /* case on function */ return; case FNC_REWIND: - if ((uptr->flags & UNIT_ATT) == 0) { /* unattached? */ + if ((tufs & FS_MOL) == 0) { /* unattached? */ set_tuer (ER_UNS); break; } @@ -706,7 +713,7 @@ switch (fnc) { /* case on function */ return; case FNC_SPACEF: - if ((uptr->flags & UNIT_ATT) == 0) { /* unattached? */ + if ((tufs & FS_MOL) == 0) { /* unattached? */ set_tuer (ER_UNS); break; } @@ -718,7 +725,7 @@ switch (fnc) { /* case on function */ goto GO_XFER; case FNC_SPACER: - if ((uptr->flags & UNIT_ATT) == 0) { /* unattached? */ + if ((tufs & FS_MOL) == 0) { /* unattached? */ set_tuer (ER_UNS); break; } @@ -731,7 +738,7 @@ switch (fnc) { /* case on function */ case FNC_WREOF: /* write tape mark */ case FNC_ERASE: /* erase */ - if ((uptr->flags & UNIT_ATT) == 0) { /* unattached? */ + if ((tufs & FS_MOL) == 0) { /* unattached? */ set_tuer (ER_UNS); break; } @@ -765,7 +772,7 @@ switch (fnc) { /* case on function */ case FNC_WCHKF: /* wchk = read */ case FNC_READF: /* read */ DATA_XFER: - if ((uptr->flags & UNIT_ATT) == 0) { /* unattached? */ + if ((tufs & FS_MOL) == 0) { /* unattached? */ set_tuer (ER_UNS); break; } @@ -804,12 +811,23 @@ return; t_stat tu_svc (UNIT *uptr) { int32 fnc, fmt, i, j, k, wc10, ba10; -int32 ba, fc, wc, drv, mpa10, vpn; +int32 ba, fc, wc, drv, mpa10 = 0, vpn; d10 val, v[4]; t_mtrlnt tbc; t_stat st, r = SCPE_OK; drv = (int32) (uptr - tu_dev.units); /* get drive # */ + +/* Set MOL for a delayed attach */ +if (uptr->TU_STATEFLAGS & TUS_ATTPENDING) { + uptr->TU_STATEFLAGS &= ~TUS_ATTPENDING; /* Allow transition to on-line */ + tufs = tufs | FS_ATA | FS_SSC; /* set attention */ + if ((GET_FMTR (tucs2) == 0) && (GET_DRV (tutc) == drv)) /* selected drive? */ + tufs = tufs | FS_SAT; /* set slave attn */ + update_tucs (CS1_SC, drv); /* update status */ + return SCPE_OK; +} + if (uptr->USTAT & FS_REW) { /* rewind or unload? */ sim_tape_rewind (uptr); /* rewind tape */ uptr->USTAT = 0; /* clear status */ @@ -834,7 +852,7 @@ switch (fnc) { /* case on function */ case FNC_SPACEF: /* space forward */ do { tufc = (tufc + 1) & 0177777; /* incr fc */ - if (st = sim_tape_sprecf (uptr, &tbc)) { /* space rec fwd, err? */ + if ((st = sim_tape_sprecf (uptr, &tbc))) { /* space rec fwd, err? */ r = tu_map_err (uptr, st, 0); /* map error */ break; } @@ -848,7 +866,7 @@ switch (fnc) { /* case on function */ case FNC_SPACER: /* space reverse */ do { tufc = (tufc + 1) & 0177777; /* incr wc */ - if (st = sim_tape_sprecr (uptr, &tbc)) { /* space rec rev, err? */ + if ((st = sim_tape_sprecr (uptr, &tbc))) { /* space rec rev, err? */ r = tu_map_err (uptr, st, 0); /* map error */ break; } @@ -860,7 +878,7 @@ switch (fnc) { /* case on function */ break; case FNC_WREOF: /* write end of file */ - if (st = sim_tape_wrtmk (uptr)) /* write tmk, err? */ + if ((st = sim_tape_wrtmk (uptr))) /* write tmk, err? */ r = tu_map_err (uptr, st, 0); /* map error */ tufs = tufs | FS_ATA; break; @@ -890,7 +908,7 @@ switch (fnc) { /* case on function */ if ((uptr->UDENS == TC_1600) && sim_tape_bot (uptr)) tufs = tufs | FS_ID; /* PE BOT? ID burst */ TXFR (ba, wc, 0); /* validate transfer */ - if (st = sim_tape_rdrecf (uptr, xbuf, &tbc, MT_MAXFR)) { /* read fwd */ + if ((st = sim_tape_rdrecf (uptr, xbuf, &tbc, MT_MAXFR))) {/* read fwd */ if (st == MTSE_TMK) /* TMK also sets FCE */ set_tuer (ER_FCE); r = tu_map_err (uptr, st, 1); /* map error */ @@ -937,7 +955,7 @@ switch (fnc) { /* case on function */ } /* end for */ if (j < fc) /* short record? */ fc = j; - if (st = sim_tape_wrrecf (uptr, xbuf, fc)) /* write rec, err? */ + if ((st = sim_tape_wrrecf (uptr, xbuf, fc))) /* write rec, err? */ r = tu_map_err (uptr, st, 1); /* map error */ else { tufc = (tufc + fc) & 0177777; @@ -952,7 +970,7 @@ switch (fnc) { /* case on function */ case FNC_WCHKR: /* wcheck = read */ tufc = 0; /* clear frame count */ TXFR (ba, wc, 1); /* validate xfer rev */ - if (st = sim_tape_rdrecr (uptr, xbuf + 4, &tbc, MT_MAXFR)) { /* read rev */ + if ((st = sim_tape_rdrecr (uptr, xbuf + 4, &tbc, MT_MAXFR))) {/* read rev */ if (st == MTSE_TMK) /* TMK also sets FCE */ set_tuer (ER_FCE); r = tu_map_err (uptr, st, 1); /* map error */ @@ -1016,12 +1034,15 @@ return; void update_tucs (int32 flag, int32 drv) { -int32 act = sim_is_active (&tu_unit[drv]); +int32 act = sim_activate_time (&tu_unit[drv]); if ((flag & ~tucs1) & CS1_DONE) /* DONE 0 to 1? */ tuiff = (tucs1 & CS1_IE)? 1: 0; /* CSTB INTR <- IE */ if (GET_FMTR (tucs2) == 0) { /* formatter present? */ tufs = (tufs & ~FS_DYN) | FS_FPR; + if (tu_unit[drv].TU_STATEFLAGS & TUS_ATTPENDING) /* Delayed on-line timer running? */ + act = 0; /* Not a tape motion op */ + else { if (tu_unit[drv].flags & UNIT_ATT) { tufs = tufs | FS_MOL | tu_unit[drv].USTAT; if (tu_unit[drv].UDENS == TC_1600) @@ -1035,6 +1056,7 @@ if (GET_FMTR (tucs2) == 0) { /* formatter present? */ tufs = tufs | FS_EOT; } } + } if (tuer) tufs = tufs | FS_ERR; } @@ -1142,7 +1164,11 @@ int_req = int_req & ~INT_TU; /* clear interrupt */ for (u = 0; u < TU_NUMDR; u++) { /* loop thru units */ uptr = tu_dev.units + u; sim_tape_reset (uptr); /* clear pos flag */ + if (!uptr->TU_STATEFLAGS & TUS_ATTPENDING) /* Delayed on-line must survive massbus clear */ sim_cancel (uptr); /* cancel activity */ + else if (!sim_is_active(uptr) ) + sim_activate (uptr, SPINUPDLY); + uptr->USTAT = 0; } if (xbuf == NULL) @@ -1164,10 +1190,20 @@ if (r != SCPE_OK) return r; uptr->USTAT = 0; /* clear unit status */ uptr->UDENS = UD_UNK; /* unknown density */ +/* Delay setting MOL since we may have just detached a previous file. + * In that case, the OS must see MOL clear, so that it will know that the + * drive was off-line. This ensures that the OS will detect a tape change. + * 100 msec should suffice - though a real operator would take longer! + * Here, we ensure that the off-line transition from detach causes an attention + * interrupt. The on-line transition will happen later. + */ tufs = tufs | FS_ATA | FS_SSC; /* set attention */ if ((GET_FMTR (tucs2) == 0) && (GET_DRV (tutc) == drv)) /* selected drive? */ tufs = tufs | FS_SAT; /* set slave attn */ +uptr->TU_STATEFLAGS |= TUS_ATTPENDING; update_tucs (CS1_SC, drv); /* update status */ +sim_cancel(uptr); +sim_activate (uptr,SPINUPDLY); return r; } @@ -1182,104 +1218,173 @@ if (!(uptr->flags & UNIT_ATT)) /* attached? */ if (sim_is_active (uptr)) { /* unit active? */ sim_cancel (uptr); /* cancel operation */ tuer = tuer | ER_UNS; /* set formatter error */ - if ((uptr->USTAT & FS_REW) == 0) /* data transfer? */ + if (uptr->TU_STATEFLAGS & TUS_ATTPENDING) + uptr->TU_STATEFLAGS &= ~TUS_ATTPENDING; + else if ((uptr->USTAT & FS_REW) == 0) /* data transfer? */ tucs1 = tucs1 | CS1_DONE | CS1_TRE; /* set done, err */ } uptr->USTAT = 0; /* clear status flags */ tufs = tufs | FS_ATA | FS_SSC; /* set attention */ +if ((GET_FMTR (tucs2) == 0) && (GET_DRV (tutc) == drv)) /* selected drive? */ + tufs = tufs | FS_SAT; /* set slave attn */ +uptr->flags &= ~UNIT_ATT; /* Ensure MOL is cleared */ update_tucs (CS1_SC, drv); /* update status */ +uptr->flags |= UNIT_ATT; return sim_tape_detach (uptr); } /* Device bootstrap */ +/* Note that the dec and ITS boot code is word for word identical, + * except for the IO instructions. The ITS instructions encode the + * UBA number. No attempt is made to allow UBA selection under ITS, + * though it should work with the DEC rom. + * The sequence is: + * controller clear - to clear controller errors + * formatter select - to gain access to the formatter registers. (since only + * one formatter is supported, and it's assumed to be zero, this isn't strictly + * necessary. But maybe someday...) + * wait for MOL to appear. + * Drive clear - to clear any errors in the transport, including attention from on-line. + * Space forward one file - this is the KS CPU microcode, which the simulator doesn't + * use. + * Read the preboot (next level bootstrap) from the tape into page 1. + * Each operation produces erors - for one, the frame count is not exact. + * They are cleared, and the expected ones ignored. If no unexpected + * errors are encountered, control is transferred to the preboot. + */ #define BOOT_START 0377000 /* start */ #define BOOT_LEN (sizeof (boot_rom_dec) / sizeof (d10)) static const d10 boot_rom_dec[] = { - 0515040000003, /* boot:hrlzi 1,3 ; uba # */ - 0201000040001, /* movei 0,40001 ; vld,pg 1 */ - 0713001000000+(IOBA_UBMAP+1 & RMASK), /* wrio 0,763001(1); set ubmap */ - 0435040000000+(IOBA_TU & RMASK), /* iori 1,772440 ; rh addr */ - 0202040000000+FE_RHBASE, /* movem 1,FE_RHBASE */ - 0201000000040, /* movei 0,40 ; ctrl reset */ - 0713001000010, /* wrio 0,10(1) ; ->MTFS */ - 0201100000031, /* movei 2,31 ; space f */ - 0265740377014, /* jsp 17,tpop ; skip ucode */ - 0201100000071, /* movei 2,71 ; read f */ - 0265740377014, /* jsp 17,tpop ; read boot */ - 0254000001000, /* jrst 1000 ; start */ - 0200000000000+FE_MTFMT, /* tpop:move 0,FE_MTFMT ; den,fmt,slv */ - 0713001000032, /* wrio 0,32(1) ; ->MTTC */ - 0201000000011, /* movei 0,11 ; clr+go */ - 0713001000000, /* wrio 0,0(1) ; ->MTCS1 */ - 0201140176000, /* movei 3,176000 ; wd cnt */ - 0201200004000, /* movei 4,4000 ; addr */ - 0200240000000+FE_MTFMT, /* move 5,FE_MTFMT ; unit */ - 0201300000000, /* movei 6,0 ; fmtr */ - 0713141000002, /* wrio 3,2(1) ; ->MTWC */ - 0713201000004, /* wrio 4,4(1) ; ->MTBA */ - 0713301000006, /* wrio 6,6(1) ; ->MTFC */ - 0713301000010, /* wrio 6,10(1) ; ->MTFS */ - 0713241000032, /* wrio 5,32(1) ; ->MTTC */ - 0713101000000, /* wrio 2,0(1) ; ->MTCS1 */ - 0712341000012, /* rdio 7,12(1) ; read FS */ - 0606340000200, /* trnn 7,200 ; test rdy */ - 0254000377032, /* jrst .-2 ; loop */ - 0606340040000, /* trnn 7,40000 ; test err */ - 0254017000000, /* jrst 0(17) ; return */ - 0712341000014, /* rdio 7,14(1) ; read err */ - 0302340001000, /* caie 7,1000 ; fce? */ - 0254200377052, /* halt */ - 0254017000000, /* jrst 0(17) ; return */ + INT64_C(0510040000000)+FE_RHBASE, /* boot:hllz 1,FE_RHBASE ; uba # */ + INT64_C(0201000040001), /* movei 0,40001 ; vld,pg 1 */ + INT64_C(0713001000000)+((IOBA_UBMAP+1) & RMASK), /* wrio 0,763001(1); set ubmap */ + INT64_C(0200040000000)+FE_RHBASE, /* move 1,FE_RHBASE */ + INT64_C(0201000000040), /* movei 0,40 ; ctrl reset */ + INT64_C(0713001000010), /* wrio 0,10(1) ; ->MTFS */ + INT64_C(0200300000000)+FE_UNIT, /* move 6,FE_UNIT ; fmtr */ + INT64_C(0713301000010), /* wrio 6,10(1) ; ->MTCS2 */ + + INT64_C(0200240000000)+FE_MTFMT, /*10 move 5,FE_MTFMT ; slave, dens, fmt */ + INT64_C(0713241000032), /* wrio 5,32(1) ; ->MTTC */ + INT64_C(0712001000012), /* rdio 0,12(1) ; MTFS */ + INT64_C(0640000010600), /* trc 0,10600 ; MOL + DPR + RDY */ + INT64_C(0642000010600), /* trce 0,10600 ; */ + INT64_C(0254000377012), /* jrst .-3 ; wait */ + INT64_C(0201000000011), /* movei 0,11 ; clr+go */ + INT64_C(0713001000000), /* wrio 0,0(1) ; ->MTCS1 */ + + INT64_C(0201000000377), /*20 movei 0,1 ; Formatter */ + INT64_C(0242006000000), /* lsh 0,(6) ; attn bit */ + INT64_C(0713001000016), /* wrio 0,16(1) ; Clear on-line attn */ + INT64_C(0201100000031), /* movei 2,31 ; space f */ + INT64_C(0265740377030), /* jsp 17,tpop ; skip ucode */ + INT64_C(0201100000071), /* movei 2,71 ; read f */ + INT64_C(0265740377030), /* jsp 17,tpop ; read boot */ + INT64_C(0254000001000), /* jrst 1000 ; start */ + + /*30 */ + INT64_C(0713241000032), /* tpop:wrio 5,32(1) ; ->MTTC */ + INT64_C(0201000000011), /* movei 0,11 ; clr+go */ + INT64_C(0713001000000), /* wrio 0,0(1) ; ->MTCS1 */ + INT64_C(0201140176000), /* movei 3,176000 ; wd cnt */ + INT64_C(0713141000002), /* wrio 3,2(1) ; ->MTWC */ + INT64_C(0201200004000), /* movei 4,4000 ; addr */ + INT64_C(0713201000004), /* wrio 4,4(1) ; ->MTBA */ + INT64_C(0400400000000), /* setz 10, ; max fc */ + + INT64_C(0713401000006), /*40 wrio 10,6(1) ; ->MTFC */ + INT64_C(0713301000010), /* wrio 6,10(1) ; ->MTCS2 reset errs */ + INT64_C(0713241000032), /* wrio 5,32(1) ; ->MTTC reset errs */ + INT64_C(0713101000000), /* wrio 2,0(1) ; OP ->MTCS1 */ + INT64_C(0712341000012), /* rdio 7,12(1) ; read FS */ + INT64_C(0606340000200), /* trnn 7,200 ; test rdy */ + INT64_C(0254000377044), /* jrst .-2 ; loop */ + INT64_C(0606340040000), /* trnn 7,40000 ; test err */ + + INT64_C(0254017000000), /*50 jrst 0(17) ; return */ + INT64_C(0712341000014), /* rdio 7,14(1) ; read err */ + INT64_C(0302340001000), /* caie 7,1000 ; fce? */ + INT64_C(0254200377053), /* halt . */ + INT64_C(0254017000000), /* jrst 0(17) ; return */ }; static const d10 boot_rom_its[] = { - 0515040000003, /* boot:hrlzi 1,3 ; uba # - not used */ - 0201000040001, /* movei 0,40001 ; vld,pg 1 */ - 0714000000000+(IOBA_UBMAP+1 & RMASK), /* iowri 0,763001 ; set ubmap */ - 0435040000000+(IOBA_TU & RMASK), /* iori 1,772440 ; rh addr */ - 0202040000000+FE_RHBASE, /* movem 1,FE_RHBASE */ - 0201000000040, /* movei 0,40 ; ctrl reset */ - 0714001000010, /* iowri 0,10(1) ; ->MTFS */ - 0201100000031, /* movei 2,31 ; space f */ - 0265740377014, /* jsp 17,tpop ; skip ucode */ - 0201100000071, /* movei 2,71 ; read f */ - 0265740377014, /* jsp 17,tpop ; read boot */ - 0254000001000, /* jrst 1000 ; start */ - 0200000000000+FE_MTFMT, /* tpop:move 0,FE_MTFMT ; den,fmt,slv */ - 0714001000032, /* iowri 0,32(1) ; ->MTTC */ - 0201000000011, /* movei 0,11 ; clr+go */ - 0714001000000, /* iowri 0,0(1) ; ->MTCS1 */ - 0201140176000, /* movei 3,176000 ; wd cnt */ - 0201200004000, /* movei 4,4000 ; addr */ - 0200240000000+FE_MTFMT, /* move 5,FE_MTFMT ; unit */ - 0201300000000, /* movei 6,0 ; fmtr */ - 0714141000002, /* iowri 3,2(1) ; ->MTWC */ - 0714201000004, /* iowri 4,4(1) ; ->MTBA */ - 0714301000006, /* iowri 6,6(1) ; ->MTFC */ - 0714301000010, /* iowri 6,10(1) ; ->MTFS */ - 0714241000032, /* iowri 5,32(1) ; ->MTTC */ - 0714101000000, /* iowri 2,0(1) ; ->MTCS1 */ - 0710341000012, /* iordi 7,12(1) ; read FS */ - 0606340000200, /* trnn 7,200 ; test rdy */ - 0254000377032, /* jrst .-2 ; loop */ - 0606340040000, /* trnn 7,40000 ; test err */ - 0254017000000, /* jrst 0(17) ; return */ - 0710341000014, /* iordi 7,14(1) ; read err */ - 0302340001000, /* caie 7,1000 ; fce? */ - 0254200377052, /* halt */ - 0254017000000, /* jrst 0(17) ; return */ + INT64_C(0510040000000)+FE_RHBASE, /* boot:hllz 1,FE_RHBASE ; uba # - not used */ + INT64_C(0201000040001), /* movei 0,40001 ; vld,pg 1 */ + INT64_C(0714000000000)+((IOBA_UBMAP+1) & RMASK), /* iowri 0,763001 ; set ubmap */ + INT64_C(0200040000000)+FE_RHBASE, /* move 1,FE_RHBASE */ + INT64_C(0201000000040), /* movei 0,40 ; ctrl reset */ + INT64_C(0714001000010), /* iowri 0,10(1) ; ->MTFS */ + INT64_C(0200300000000)+FE_UNIT, /* move 6,FE_UNIT ; fmtr */ + INT64_C(0714301000010), /* iowri 6,10(1) ; ->MTFS */ + + INT64_C(0200240000000)+FE_MTFMT, /*20 move 5,FE_MTFMT ; slave, dens, fmt */ + INT64_C(0714241000032), /* iowri 5,32(1) ; ->MTTC */ + INT64_C(0710001000012), /* iordi 0,12(1) ; read FS */ + INT64_C(0640000010600), /* trc 0,10600 ; MOL + DPR + RDY */ + INT64_C(0642000010600), /* trce 0,10600 ; */ + INT64_C(0254000377012), /* jrst .-3 ; wait */ + INT64_C(0201000000011), /* movei 0,11 ; clr+go */ + INT64_C(0714001000000), /* iowri 0,0(1) ; ->MTCS1 */ + + INT64_C(0201000000377), /*30 movei 0,1 ; Formatter */ + INT64_C(0242006000000), /* lsh 0,(6) ; attn bit */ + INT64_C(0714001000016), /* iowri 0,16(1) ; Clear on-line attn */ + INT64_C(0201100000031), /* movei 2,31 ; space f */ + INT64_C(0265740377030), /* jsp 17,tpop ; skip ucode */ + INT64_C(0201100000071), /* movei 2,71 ; read f */ + INT64_C(0265740377030), /* jsp 17,tpop ; read boot */ + INT64_C(0254000001000), /* jrst 1000 ; start */ + + /*30 */ + INT64_C(0714241000032), /* tpop:iowri 5,32(1) ; ->MTTC */ + INT64_C(0201000000011), /* movei 0,11 ; clr+go */ + INT64_C(0714001000000), /* iowri 0,0(1) ; ->MTCS1 */ + INT64_C(0201140176000), /* movei 3,176000 ; wd cnt */ + INT64_C(0714141000002), /* iowri 3,2(1) ; ->MTWC */ + INT64_C(0201200004000), /* movei 4,4000 ; addr */ + INT64_C(0714201000004), /* iowri 4,4(1) ; ->MTBA */ + INT64_C(0400400000000), /* setz 10, ; max fc */ + + INT64_C(0714401000006), /*40 iowri 10,6(1) ; ->MTFC */ + INT64_C(0714301000010), /* iowri 6,10(1) ; ->MTFS */ + INT64_C(0714241000032), /* iowri 5,32(1) ; ->MTTC */ + INT64_C(0714101000000), /* iowri 2,0(1) ; ->MTCS1 */ + INT64_C(0710341000012), /* iordi 7,12(1) ; read FS */ + INT64_C(0606340000200), /* trnn 7,200 ; test rdy */ + INT64_C(0254000377044), /* jrst .-2 ; loop */ + INT64_C(0606340040000), /* trnn 7,40000 ; test err */ + + INT64_C(0254017000000), /*50 jrst 0(17) ; return */ + INT64_C(0710341000014), /* iordi 7,14(1) ; read err */ + INT64_C(0302340001000), /* caie 7,1000 ; fce? */ + INT64_C(0254200377053), /* halt . */ + INT64_C(0254017000000), /* jrst 0(17) ; return */ }; t_stat tu_boot (int32 unitno, DEVICE *dptr) { -int32 i; +size_t i; extern a10 saved_PC; +UNIT *uptr; + +unitno &= TC_M_UNIT; +uptr = tu_unit + unitno; +if (!(uptr->flags & UNIT_ATT)) + return SCPE_NOATT; + +M[FE_RHBASE] = tu_dib.ba; +M[FE_UNIT] = 0; /* Only one formatter in this implementation */ + +assert (sizeof(boot_rom_dec) == sizeof(boot_rom_its)); -M[FE_UNIT] = 0; M[FE_MTFMT] = (unitno & TC_M_UNIT) | (TC_1600 << TC_V_DEN) | (TC_10C << TC_V_FMT); tu_unit[unitno].pos = 0; + +M[FE_KEEPA] = (M[FE_KEEPA] & ~INT64_C(0xFF)) | ((sim_switches & SWMASK ('A'))? 010 : 0); + for (i = 0; i < BOOT_LEN; i++) M[BOOT_START + i] = Q_ITS? boot_rom_its[i]: boot_rom_dec[i]; saved_PC = BOOT_START; diff --git a/PDP10/pdp10_xtnd.c b/PDP10/pdp10_xtnd.c index a73a9619..f60a4512 100644 --- a/PDP10/pdp10_xtnd.c +++ b/PDP10/pdp10_xtnd.c @@ -89,10 +89,10 @@ /* Translation control */ -#define XT_LFLG 0400000000000 /* L flag */ -#define XT_SFLG 0400000000000 /* S flag */ -#define XT_NFLG 0200000000000 /* N flag */ -#define XT_MFLG 0100000000000 /* M flag */ +#define XT_LFLG INT64_C(0400000000000) /* L flag */ +#define XT_SFLG INT64_C(0400000000000) /* S flag */ +#define XT_NFLG INT64_C(0200000000000) /* N flag */ +#define XT_MFLG INT64_C(0100000000000) /* M flag */ /* Translation table */ @@ -104,10 +104,10 @@ /* AC masks */ -#define XLNTMASK 0000777777777 /* length */ -#define XFLGMASK 0700000000000 /* flags */ -#define XT_MBZ 0777000000000 /* must be zero */ -#define XT_MBZE 0047777000000 /* must be zero, edit */ +#define XLNTMASK INT64_C(0000777777777) /* length */ +#define XFLGMASK INT64_C(0700000000000) /* flags */ +#define XT_MBZ INT64_C(0777000000000) /* must be zero */ +#define XT_MBZE INT64_C(0047777000000) /* must be zero, edit */ /* Register change log */ @@ -122,7 +122,7 @@ #define ED_V_PBYN 30 /* pattern byte # */ #define ED_M_PBYN 03 -#define ED_PBYNO 0040000000000 /* overflow bit */ +#define ED_PBYNO INT64_C(0040000000000) /* overflow bit */ #define ED_GETPBYN(x) ((int32) (((x) >> ED_V_PBYN) & ED_M_PBYN)) #define ED_V_POPC 6 /* pattern byte opcode */ #define ED_M_PAT 0777 /* pattern byte mask */ @@ -155,41 +155,41 @@ d10 xlate (d10 by, a10 tblad, d10 *xflgs, int32 pflgs); void filldst (d10 fill, int32 ac, d10 cnt, int32 pflgs); static const d10 pwrs10[23][2] = { - 0, 0, - 0, 1, - 0, 10, - 0, 100, - 0, 1000, - 0, 10000, - 0, 100000, - 0, 1000000, - 0, 10000000, - 0, 100000000, - 0, 1000000000, - 0, 10000000000, - 2, 31280523264, - 29, 3567587328, - 291, 1316134912, - 2910, 13161349120, - 29103, 28534276096, - 291038, 10464854016, - 2910383, 1569325056, - 29103830, 15693250560, - 291038304, 19493552128, - 2910383045, 23136829440, - 29103830456, 25209864192 +{ INT64_C(0), INT64_C(0),}, +{ INT64_C(0), INT64_C(1),}, +{ INT64_C(0), INT64_C(10),}, +{ INT64_C(0), INT64_C(100),}, +{ INT64_C(0), INT64_C(1000),}, +{ INT64_C(0), INT64_C(10000),}, +{ INT64_C(0), INT64_C(100000),}, +{ INT64_C(0), INT64_C(1000000),}, +{ INT64_C(0), INT64_C(10000000),}, +{ INT64_C(0), INT64_C(100000000),}, +{ INT64_C(0), INT64_C(1000000000),}, +{ INT64_C(0), INT64_C(10000000000),}, +{ INT64_C(2), INT64_C(31280523264),}, +{ INT64_C(29), INT64_C(3567587328),}, +{ INT64_C(291), INT64_C(1316134912),}, +{ INT64_C(2910), INT64_C(13161349120),}, +{ INT64_C(29103), INT64_C(28534276096),}, +{ INT64_C(291038), INT64_C(10464854016),}, +{ INT64_C(2910383), INT64_C(1569325056),}, +{ INT64_C(29103830), INT64_C(15693250560),}, +{ INT64_C(291038304), INT64_C(19493552128),}, +{ INT64_C(2910383045), INT64_C(23136829440),}, +{ INT64_C(29103830456), INT64_C(25209864192),}, }; int xtend (int32 ac, int32 ea, int32 pflgs) { d10 b1, b2, ppi; -d10 xinst, xoff, digit, f1, f2, rs[2]; +d10 xinst, xoff = 0, digit, f1, f2, rs[2]; d10 xflgs = 0; -a10 e1, entad; +a10 e1 = 0, entad; int32 p1 = ADDAC (ac, 1); int32 p3 = ADDAC (ac, 3); int32 p4 = ADDAC (ac, 4); -int32 flg, i, s2, t, pp, pat, xop, xac, ret; +int32 flg, i, s2 = 0, t, pp, pat, xop, xac, ret; xinst = Read (ea, MM_OPND); /* get extended instr */ xop = GET_OP (xinst); /* get opcode */ diff --git a/PDP11/pdp11_cis.c b/PDP11/pdp11_cis.c index 881c7fab..1cc76c26 100644 --- a/PDP11/pdp11_cis.c +++ b/PDP11/pdp11_cis.c @@ -170,14 +170,12 @@ typedef struct { uint32 val[DSTRLNT]; } DSTR; -static DSTR Dstr0 = { 0, 0, 0, 0, 0 }; +static DSTR Dstr0 = { 0, {0, 0, 0, 0} }; extern int32 isenable, dsenable; extern int32 N, Z, V, C, fpd, ipl; extern int32 R[8], trap_req; -extern int32 sim_interval; extern uint32 cpu_type; -extern FILE *sim_deb; int32 ReadDstr (int32 *dscr, DSTR *dec, int32 flag); void WriteDstr (int32 *dscr, DSTR *dec, int32 flag); @@ -205,96 +203,96 @@ extern int32 calc_ints (int32 nipl, int32 trq); /* Table of instruction operands */ static int32 opntab[128][MAXOPN] = { - 0, 0, 0, 0, 0, 0, 0, 0, /* 000 - 007 */ - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, /* 010 - 017 */ - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, /* LD2R */ - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, /* MOVC */ - 0, 0, 0, 0, /* MOVRC */ - 0, 0, 0, 0, /* MOVTC */ - 0, 0, 0, 0, /* 033 */ - 0, 0, 0, 0, 0, 0, 0, 0, /* 034 - 037 */ - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, /* LOCC */ - 0, 0, 0, 0, /* SKPC */ - 0, 0, 0, 0, /* SCANC */ - 0, 0, 0, 0, /* SPANC */ - 0, 0, 0, 0, /* CMPC */ - 0, 0, 0, 0, /* MATC */ - 0, 0, 0, 0, 0, 0, 0, 0, /* 046 - 047 */ - R0_DESC, R2_DESC, R4_DESC, 0, /* ADDN */ - R0_DESC, R2_DESC, R4_DESC, 0, /* SUBN */ - R0_DESC, R2_DESC, 0, 0, /* CMPN */ - R0_DESC, 0, 0, 0, /* CVTNL */ - R0_DESC, R2_DESC, 0, 0, /* CVTPN */ - R0_DESC, R2_DESC, 0, 0, /* CVTNP */ - R0_DESC, R2_DESC, R4_ARG, 0, /* ASHN */ - R0_DESC, 0, 0, 0, /* CVTLN */ - 0, 0, 0, 0, 0, 0, 0, 0, /* LD3R */ - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - R0_DESC, R2_DESC, R4_DESC, 0, /* ADDP */ - R0_DESC, R2_DESC, R4_DESC, 0, /* SUBP */ - R0_DESC, R2_DESC, 0, 0, /* CMPP */ - R0_DESC, 0, 0, 0, /* CVTPL */ - R0_DESC, R2_DESC, R4_DESC, 0, /* MULP */ - R0_DESC, R2_DESC, R4_DESC, 0, /* DIVP */ - R0_DESC, R2_DESC, R4_ARG, 0, /* ASHP */ - R0_DESC, 0, 0, 0, /* CVTLP */ - 0, 0, 0, 0, 0, 0, 0, 0, /* 100 - 107 */ - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, /* 110 - 117 */ - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, /* 120 - 127 */ - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - IN_DESC, IN_DESC, IN_ARG, 0, /* MOVCI */ - IN_DESC, IN_DESC, IN_ARG, 0, /* MOVRCI */ - IN_DESC, IN_DESC, IN_ARG, IN_ARG, /* MOVTCI */ - 0, 0, 0, 0, /* 133 */ - 0, 0, 0, 0, 0, 0, 0, 0, /* 134 - 137 */ - 0, 0, 0, 0, 0, 0, 0, 0, - IN_DESC, IN_ARG, 0, 0, /* LOCCI */ - IN_DESC, IN_ARG, 0, 0, /* SKPCI */ - IN_DESC, IN_DESC, 0, 0, /* SCANCI */ - IN_DESC, IN_DESC, 0, 0, /* SPANCI */ - IN_DESC, IN_DESC, IN_ARG, 0, /* CMPCI */ - IN_DESC, IN_DESC, 0, 0, /* MATCI */ - 0, 0, 0, 0, 0, 0, 0, 0, /* 146 - 147 */ - IN_DESC, IN_DESC, IN_DESC, 0, /* ADDNI */ - IN_DESC, IN_DESC, IN_DESC, 0, /* SUBNI */ - IN_DESC, IN_DESC, 0, 0, /* CMPNI */ - IN_DESC, IN_ARG, 0, 0, /* CVTNLI */ - IN_DESC, IN_DESC, 0, 0, /* CVTPNI */ - IN_DESC, IN_DESC, 0, 0, /* CVTNPI */ - IN_DESC, IN_DESC, IN_ARG, 0, /* ASHNI */ - IN_DESC, IN_DESC, 0, 0, /* CVTLNI */ - 0, 0, 0, 0, 0, 0, 0, 0, /* 160 - 167 */ - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - IN_DESC, IN_DESC, IN_DESC, 0, /* ADDPI */ - IN_DESC, IN_DESC, IN_DESC, 0, /* SUBPI */ - IN_DESC, IN_DESC, 0, 0, /* CMPPI */ - IN_DESC, IN_ARG, 0, 0, /* CVTPLI */ - IN_DESC, IN_DESC, IN_DESC, 0, /* MULPI */ - IN_DESC, IN_DESC, IN_DESC, 0, /* DIVPI */ - IN_DESC, IN_DESC, IN_ARG, 0, /* ASHPI */ - IN_DESC, IN_DESC, 0, 0 /* CVTLPI */ + {0, 0, 0, 0}, {0, 0, 0, 0}, /* 000 - 007 */ + {0, 0, 0, 0}, {0, 0, 0, 0}, + {0, 0, 0, 0}, {0, 0, 0, 0}, + {0, 0, 0, 0}, {0, 0, 0, 0}, + {0, 0, 0, 0}, {0, 0, 0, 0}, /* 010 - 017 */ + {0, 0, 0, 0}, {0, 0, 0, 0}, + {0, 0, 0, 0}, {0, 0, 0, 0}, + {0, 0, 0, 0}, {0, 0, 0, 0}, + {0, 0, 0, 0}, {0, 0, 0, 0}, /* LD2R */ + {0, 0, 0, 0}, {0, 0, 0, 0}, + {0, 0, 0, 0}, {0, 0, 0, 0}, + {0, 0, 0, 0}, {0, 0, 0, 0}, + {0, 0, 0, 0}, /* MOVC */ + {0, 0, 0, 0}, /* MOVRC */ + {0, 0, 0, 0}, /* MOVTC */ + {0, 0, 0, 0}, /* 033 */ + {0, 0, 0, 0}, {0, 0, 0, 0}, /* 034 - 037 */ + {0, 0, 0, 0}, {0, 0, 0, 0}, + {0, 0, 0, 0}, /* LOCC */ + {0, 0, 0, 0}, /* SKPC */ + {0, 0, 0, 0}, /* SCANC */ + {0, 0, 0, 0}, /* SPANC */ + {0, 0, 0, 0}, /* CMPC */ + {0, 0, 0, 0}, /* MATC */ + {0, 0, 0, 0}, {0, 0, 0, 0}, /* 046 - 047 */ + {R0_DESC, R2_DESC, R4_DESC, 0}, /* ADDN */ + {R0_DESC, R2_DESC, R4_DESC, 0}, /* SUBN */ + {R0_DESC, R2_DESC, 0, 0}, /* CMPN */ + {R0_DESC, 0, 0, 0}, /* CVTNL */ + {R0_DESC, R2_DESC, 0, 0}, /* CVTPN */ + {R0_DESC, R2_DESC, 0, 0}, /* CVTNP */ + {R0_DESC, R2_DESC, R4_ARG, 0}, /* ASHN */ + {R0_DESC, 0, 0, 0}, /* CVTLN */ + {0, 0, 0, 0}, {0, 0, 0, 0}, /* LD3R */ + {0, 0, 0, 0}, {0, 0, 0, 0}, + {0, 0, 0, 0}, {0, 0, 0, 0}, + {0, 0, 0, 0}, {0, 0, 0, 0}, + {R0_DESC, R2_DESC, R4_DESC, 0}, /* ADDP */ + {R0_DESC, R2_DESC, R4_DESC, 0}, /* SUBP */ + {R0_DESC, R2_DESC, 0, 0}, /* CMPP */ + {R0_DESC, 0, 0, 0}, /* CVTPL */ + {R0_DESC, R2_DESC, R4_DESC, 0}, /* MULP */ + {R0_DESC, R2_DESC, R4_DESC, 0}, /* DIVP */ + {R0_DESC, R2_DESC, R4_ARG, 0}, /* ASHP */ + {R0_DESC, 0, 0, 0}, /* CVTLP */ + {0, 0, 0, 0}, {0, 0, 0, 0}, /* 100 - 107 */ + {0, 0, 0, 0}, {0, 0, 0, 0}, + {0, 0, 0, 0}, {0, 0, 0, 0}, + {0, 0, 0, 0}, {0, 0, 0, 0}, + {0, 0, 0, 0}, {0, 0, 0, 0}, /* 110 - 117 */ + {0, 0, 0, 0}, {0, 0, 0, 0}, + {0, 0, 0, 0}, {0, 0, 0, 0}, + {0, 0, 0, 0}, {0, 0, 0, 0}, + {0, 0, 0, 0}, {0, 0, 0, 0}, /* 120 - 127 */ + {0, 0, 0, 0}, {0, 0, 0, 0}, + {0, 0, 0, 0}, {0, 0, 0, 0}, + {0, 0, 0, 0}, {0, 0, 0, 0}, + {IN_DESC, IN_DESC, IN_ARG, 0}, /* MOVCI */ + {IN_DESC, IN_DESC, IN_ARG, 0}, /* MOVRCI */ + {IN_DESC, IN_DESC, IN_ARG, IN_ARG}, /* MOVTCI */ + {0, 0, 0, 0}, /* 133 */ + {0, 0, 0, 0}, {0, 0, 0, 0}, /* 134 - 137 */ + {0, 0, 0, 0}, {0, 0, 0, 0}, + {IN_DESC, IN_ARG, 0, 0}, /* LOCCI */ + {IN_DESC, IN_ARG, 0, 0}, /* SKPCI */ + {IN_DESC, IN_DESC, 0, 0}, /* SCANCI */ + {IN_DESC, IN_DESC, 0, 0}, /* SPANCI */ + {IN_DESC, IN_DESC, IN_ARG, 0}, /* CMPCI */ + {IN_DESC, IN_DESC, 0, 0}, /* MATCI */ + {0, 0, 0, 0}, {0, 0, 0, 0}, /* 146 - 147 */ + {IN_DESC, IN_DESC, IN_DESC, 0}, /* ADDNI */ + {IN_DESC, IN_DESC, IN_DESC, 0}, /* SUBNI */ + {IN_DESC, IN_DESC, 0, 0}, /* CMPNI */ + {IN_DESC, IN_ARG, 0, 0}, /* CVTNLI */ + {IN_DESC, IN_DESC, 0, 0}, /* CVTPNI */ + {IN_DESC, IN_DESC, 0, 0}, /* CVTNPI */ + {IN_DESC, IN_DESC, IN_ARG, 0}, /* ASHNI */ + {IN_DESC, IN_DESC, 0, 0}, /* CVTLNI */ + {0, 0, 0, 0}, {0, 0, 0, 0}, /* 160 - 167 */ + {0, 0, 0, 0}, {0, 0, 0, 0}, + {0, 0, 0, 0}, {0, 0, 0, 0}, + {0, 0, 0, 0}, {0, 0, 0, 0}, + {IN_DESC, IN_DESC, IN_DESC, 0}, /* ADDPI */ + {IN_DESC, IN_DESC, IN_DESC, 0}, /* SUBPI */ + {IN_DESC, IN_DESC, 0, 0}, /* CMPPI */ + {IN_DESC, IN_ARG, 0, 0}, /* CVTPLI */ + {IN_DESC, IN_DESC, IN_DESC, 0}, /* MULPI */ + {IN_DESC, IN_DESC, IN_DESC, 0}, /* DIVPI */ + {IN_DESC, IN_DESC, IN_ARG, 0}, /* ASHPI */ + {IN_DESC, IN_DESC, 0, 0} /* CVTLPI */ }; /* ASCII to overpunch table: sign is <7>, digit is <4:0> */ @@ -321,14 +319,12 @@ static int32 overbin[128] = { /* Overpunch to ASCII table: indexed by sign and digit */ static int32 binover[2][16] = { - '{', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', - '0', '0', '0', '0', '0', '0', - '}', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', - '0', '0', '0', '0', '0', '0' + {'{', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', + '0', '0', '0', '0', '0', '0'}, + {'}', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', + '0', '0', '0', '0', '0', '0'} }; -static unsigned char movbuf[65536]; - /* CIS emulator */ t_stat cis11 (int32 IR) @@ -342,7 +338,7 @@ uint32 nc, digit, result; t_stat st; static DSTR accum, src1, src2, dst; static DSTR mptable[10]; -static DSTR Dstr1 = { 0, 0x10, 0, 0, 0 }; +static DSTR Dstr1 = { 0, {0x10, 0, 0, 0} }; old_PC = (PC - 2) & 0177777; /* original PC */ op = IR & 0177; /* IR <6:0> */ @@ -1134,7 +1130,7 @@ switch (op) { /* case on opcode */ result = (A2ADR << 16) | A2LNT; /* op in VAX format */ CVTLx: dst = Dstr0; /* clear result */ - if (dst.sign = GET_SIGN_L (result)) + if ((dst.sign = GET_SIGN_L (result))) result = (~result + 1) & 0xFFFFFFFF; for (i = 1; (i < (DSTRLNT * 8)) && result; i++) { digit = result % 10; @@ -1178,7 +1174,7 @@ return SCPE_OK; int32 ReadDstr (int32 *dscr, DSTR *src, int32 flag) { -int32 c, i, end, lnt, type, t; +int32 c, i, end, lnt, type, t = 0; *src = Dstr0; /* clear result */ type = GET_DTYP (dscr[0]); /* get type */ @@ -1267,7 +1263,7 @@ for (i = 0; i < DSTRLNT; i++) { /* loop thru value */ mask = 0xFFFFFFFF; if (dst->val[i] & mask) /* test for ovflo */ V = 1; - if (dst->val[i] = dst->val[i] & ~mask) /* test nz */ + if ((dst->val[i] = dst->val[i] & ~mask)) /* test nz */ Z = 0; } dst->sign = dst->sign & ~unsignedtab[type] & ~(Z & ~V); @@ -1523,7 +1519,7 @@ uint32 NibbleRshift (DSTR *dsrc, int32 sc, uint32 cin) { int32 i, s, nc; -if (s = sc * 4) { +if ((s = sc * 4)) { for (i = DSTRMAX; i >= 0; i--) { nc = (dsrc->val[i] << (32 - s)) & 0xFFFFFFFF; dsrc->val[i] = ((dsrc->val[i] >> s) | @@ -1548,7 +1544,7 @@ int32 i, s; uint32 nc, cin; cin = 0; -if (s = sc * 4) { +if ((s = sc * 4)) { for (i = 0; i < DSTRLNT; i++) { nc = dsrc->val[i] >> (32 - s); dsrc->val[i] = ((dsrc->val[i] << s) | cin) & 0xFFFFFFFF; diff --git a/PDP11/pdp11_cpu.c b/PDP11/pdp11_cpu.c index 39de9eab..6ad63be6 100644 --- a/PDP11/pdp11_cpu.c +++ b/PDP11/pdp11_cpu.c @@ -256,10 +256,8 @@ typedef struct { /* Global state */ -extern FILE *sim_log; - uint16 *M = NULL; /* memory */ -int32 REGFILE[6][2] = { 0 }; /* R0-R5, two sets */ +int32 REGFILE[6][2] = { {0} }; /* R0-R5, two sets */ int32 STACKFILE[4] = { 0 }; /* SP, four modes */ int32 saved_PC = 0; /* program counter */ int32 R[8] = { 0 }; /* working registers */ @@ -276,7 +274,7 @@ int32 trap_req = 0; /* trap requests */ int32 int_req[IPL_HLVL] = { 0 }; /* interrupt requests */ int32 PIRQ = 0; /* programmed int req */ int32 STKLIM = 0; /* stack limit */ -fpac_t FR[6] = { 0 }; /* fp accumulators */ +fpac_t FR[6] = { {0} }; /* fp accumulators */ int32 FPS = 0; /* fp status */ int32 FEC = 0; /* fp exception code */ int32 FEA = 0; /* fp exception addr */ @@ -307,12 +305,6 @@ int32 dsmask[4] = { MMR3_KDS, MMR3_SDS, 0, MMR3_UDS }; /* dspace enables */ t_addr cpu_memsize = INIMEMSIZE; /* last mem addr */ extern int32 CPUERR, MAINT; -extern int32 sim_interval; -extern int32 sim_int_char; -extern int32 sim_switches; -extern uint32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ -extern t_bool sim_idle_enab; -extern DEVICE *sim_devices[]; extern CPUTAB cpu_tab[]; /* Function declarations */ @@ -609,6 +601,7 @@ MTAB cpu_mod[] = { { UNIT_MSIZE, 524288, NULL, "512K", &cpu_set_size}, { UNIT_MSIZE, 786432, NULL, "768K", &cpu_set_size}, { UNIT_MSIZE, 1048576, NULL, "1024K", &cpu_set_size}, + { UNIT_MSIZE, 1572864, NULL, "1536K", &cpu_set_size}, { UNIT_MSIZE, 2097152, NULL, "2048K", &cpu_set_size}, { UNIT_MSIZE, 3145728, NULL, "3072K", &cpu_set_size}, { UNIT_MSIZE, 4186112, NULL, "4096K", &cpu_set_size}, @@ -736,7 +729,7 @@ while (reason == 0) { if (trap_req) { /* check traps, ints */ trapea = 0; /* assume srch fails */ - if (t = trap_req & TRAP_ALL) { /* if a trap */ + if ((t = trap_req & TRAP_ALL)) { /* if a trap */ for (trapnum = 0; trapnum < TRAP_V_MAX; trapnum++) { if ((t >> trapnum) & 1) { /* trap set? */ trapea = trap_vec[trapnum]; /* get vec, clr */ @@ -808,11 +801,7 @@ while (reason == 0) { if (tbit) setTRAP (TRAP_TRC); if (wait_state) { /* wait state? */ - if (sim_idle_enab) /* idle enabled? */ - sim_idle (TMR_CLK, TRUE); - else if (wait_enable) /* old style idle? */ - sim_interval = 0; /* force check */ - else sim_interval = sim_interval - 1; /* count cycle */ + sim_idle (TMR_CLK, TRUE); continue; } @@ -1251,7 +1240,7 @@ while (reason == 0) { else dst = R[dstspec]; } else { - i = ((cm == pm) && (cm == MD_USR))? calc_ds (pm): calc_is (pm); + i = ((cm == pm) && (cm == MD_USR))? (int32)calc_ds (pm): (int32)calc_is (pm); dst = ReadW ((GeteaW (dstspec) & 0177777) | i); } N = GET_SIGN_W (dst); @@ -1513,7 +1502,7 @@ while (reason == 0) { Z = V = C = 1; /* N = 0, Z = 1 */ break; } - if ((src == 020000000000) && (src2 == 0177777)) { + if ((((uint32)src) == 020000000000) && (src2 == 0177777)) { V = 1; /* J11,11/70 compat */ N = Z = C = 0; /* N = Z = 0 */ break; @@ -3082,7 +3071,6 @@ return iopageW ((int32) val, addr, WRITEC); void set_r_display (int32 rs, int32 cm) { -extern REG *find_reg (char *cptr, char **optr, DEVICE *dptr); REG *rptr; int32 i; @@ -3135,8 +3123,6 @@ char *cptr = (char *) desc; t_value sim_eval[HIST_ILNT]; t_stat r; InstHistory *h; -extern t_stat fprint_sym (FILE *ofile, t_addr addr, t_value *val, - UNIT *uptr, int32 sw); if (hst_lnt == 0) /* enabled? */ return SCPE_NOFNC; diff --git a/PDP11/pdp11_cpumod.c b/PDP11/pdp11_cpumod.c index 171f51b1..80263765 100644 --- a/PDP11/pdp11_cpumod.c +++ b/PDP11/pdp11_cpumod.c @@ -85,13 +85,11 @@ static int32 clk_tps_map[4] = { 60, 60, 50, 800 }; extern uint16 *M; extern int32 R[8]; -extern DEVICE cpu_dev, *sim_devices[]; +extern DEVICE cpu_dev; extern UNIT cpu_unit; -extern FILE *sim_log; extern int32 STKLIM, PIRQ; extern uint32 cpu_model, cpu_type, cpu_opt; extern int32 clk_fie, clk_fnxm, clk_tps, clk_default; -extern int32 sim_switches; t_stat CPU24_rd (int32 *data, int32 addr, int32 access); t_stat CPU24_wr (int32 data, int32 addr, int32 access); @@ -1076,7 +1074,7 @@ t_stat r; for (i = 0; cnf_tab[i].dib != NULL; i++) { /* loop thru config tab */ if (((cnf_tab[i].cpum == 0) || (cpu_type & cnf_tab[i].cpum)) && ((cnf_tab[i].optm == 0) || (cpu_opt & cnf_tab[i].optm))) { - if (r = build_ubus_tab (&cpu_dev, cnf_tab[i].dib)) /* add to dispatch tab */ + if ((r = build_ubus_tab (&cpu_dev, cnf_tab[i].dib)))/* add to dispatch tab */ return r; } } @@ -1160,7 +1158,7 @@ if ((mc != 0) && !get_yn ("Really truncate memory [N]?", FALSE)) nM = (uint16 *) calloc (val >> 1, sizeof (uint16)); if (nM == NULL) return SCPE_MEM; -clim = (((t_addr) val) < MEMSIZE)? val: MEMSIZE; +clim = (((t_addr) val) < MEMSIZE)? (uint32)val: MEMSIZE; for (i = 0; i < clim; i = i + 2) nM[i >> 1] = M[i >> 1]; free (M); @@ -1187,9 +1185,7 @@ for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { if ((dptr->flags & DEV_DISABLE) && /* disable-able? */ !(dptr->flags & DEV_DIS) && /* enabled? */ ((dptr->flags & mask) == 0)) { /* not allowed? */ - printf ("Disabling %s\n", sim_dname (dptr)); - if (sim_log) - fprintf (sim_log, "Disabling %s\n", sim_dname (dptr)); + sim_printf ("Disabling %s\n", sim_dname (dptr)); dptr->flags = dptr->flags | DEV_DIS; } } diff --git a/PDP11/pdp11_cpumod.h b/PDP11/pdp11_cpumod.h index b1851313..ba8fb178 100644 --- a/PDP11/pdp11_cpumod.h +++ b/PDP11/pdp11_cpumod.h @@ -27,8 +27,8 @@ 30-Aug-05 RMS Added additional 11/60 registers */ -#ifndef _PDP11_CPUMOD_H_ -#define _PDP11_CPUMOD_H_ 0 +#ifndef PDP11_CPUMOD_H_ +#define PDP11_CPUMOD_H_ 0 #define SOP_1103 (BUS_Q) #define OPT_1103 (OPT_EIS|OPT_FIS) diff --git a/PDP11/pdp11_cr.c b/PDP11/pdp11_cr.c index 699c63f1..b8898c58 100644 --- a/PDP11/pdp11_cr.c +++ b/PDP11/pdp11_cr.c @@ -1,4 +1,4 @@ -/* pdp11_cr.c: CR/CM/CD-11 card reader simulator +/* pdp11_cr.c: CR/CM/CD-11/CD20 card reader simulator Copyright (c) 2005-2010, John A. Dundas III Portions derived from work by Douglas W. Jones, jones@cs.uiowa.edu @@ -28,7 +28,7 @@ ------------------------------------------------------------------------------ - cr CR11/CD11 punched and mark sense card reader for SIMH + cr CR11/CD11/CD20 punched and mark sense card reader for SIMH The CR11 controller is also compatible with the CM11-F, CME11, and CMS11. Information necessary to create this simulation was gathered from @@ -51,8 +51,16 @@ http://www.cs.uiowa.edu/~jones/cards/ Paul Mattes' x026 keypunch simulator http://x3270.bgp.nu/x026.html - CD2SER.MAC - TOPS card reader driver source + CD2SER.MAC - TOPS-10 card reader driver source http://pdp-10.trailing-edge.com/custsupcuspmar86_bb-x130b-sb/02/cd2ser.mac + CDRIVE.MAC - TOPS GALAXY card reader spooler + http://pdp-10.trailing-edge.com/BB-BT99U-BB_1990/03/10,7/galaxy/cdrive/cdrive.mac + SPRINT.MAC - TOPS GALAXY control card interpreter + http://pdp-10.trailing-edge.com/BB-H138C-BM/01/galaxy-sources/sprint.mac + CDKSDV.MAC - TOPS-20 card reader driver source + http://pdp-10.trailing-edge.com/BB-Y393K-SM/01/monitor-sources/cdksdv.mac + PROKS.MAC - TOPS-20 bit definitions + http://pdp-10.trailing-edge.com/BB-Y393K-SM/01/monitor-sources/proks.mac The Card Image format code and documentation is adapted from Prof. Jones's site, with his permission. Please see his site for additional @@ -80,14 +88,26 @@ For RSX there exists a CR/CM task handler. Is there a CD handler? + To-do (RSX): The CR11 unit works as a regular device (ie, + you can PIP from it) but it does not work well as a job + input device (it works just once, somwhow the CRP processor + gets stuck). + Don't have any information about Unix or Ultrix-11 yet. Same for VAX Unices. - TOPS: only the CD11 is supported, under the name CD20. + TOPS: only the CD20 variant of the CD11 is supported. CD20 implies + ECOs (at least) for Data Buffer status and augmented image mode. Revision History: - - 06-Jun-13 RMS Default start state is disabled + 30-Mar-15 RMS Backported from GitHub master; removed extended + help and Qbus support + 23-Feb-13 JGP Added DEC version of the 026 codepage + Fixed the handling of the CR11 error bits after + a control register write. + Added logic reset after RESET button press + Commented and reestructured code (to supress + dangling elses) 03-Jan-10 JAD Eliminate gcc warnings 01-Feb-07 RMS Added PDP-10 support 12-May-06 JAD Modify the DEBUG code to use the SIMH DEBUG_x @@ -165,29 +185,51 @@ 08-Jan-05 JAD Original creation and testing */ +/* Configuration notes: + * Keep VM_arch symbols here and use them only to select features. + * CR attributes use generic symbols so device support is easy to change, + * e.g. if software is discovered that uses a previously unsupported option. + * Conventions: + * *_ONLY (AND *_req) means feature * is unconditionally present/required. + * *_OK means feature * is selectable at runtime. + * neither means feature is not present. + * To support only one controller model, define _ONLY. + * To support more than one, define them all as _OK. + * Don't mix "_ONLY" and "_OK" for the same feature. You won't like it. + * + * The CD/CR will work on any UNIBUS, and the CR will also work on a QBUS. + * The configuration options used here are more restrictive to reflect + * known software support, as this reduces user configuration errors/confusion. + */ + #if defined (VM_PDP10) /* PDP10 version */ #include "pdp10_defs.h" extern int32 int_req; #define DFLT_DIS (DEV_DIS) -#define DFLT_CR11 (0) /* CD11 only */ -#define DFLT_CPM 1000 - +#define DFLT_TYPE (UNIT_CD20) /* CD20 (CD11) only */ +#define CD20_ONLY (1) +#define DFLT_CPM 1200 +#define AIECO_REQ (1) /* Requires Augmented Image ECO */ #elif defined (VM_VAX) /* VAX version */ #include "vax_defs.h" extern int32 int_req[IPL_HLVL]; -#define DFLT_DIS (0) -#define DFLT_CR11 (UNIT_CR11) +#define DFLT_DIS (DEV_QBUS) /* CR11 is programmed I/O only, Qbus OK */ +#define DFLT_TYPE (UNIT_CR11) /* CR11 only */ +#define CR11_ONLY (1) #define DFLT_CPM 285 - #else /* PDP-11 version */ #include "pdp11_defs.h" extern int32 int_req[IPL_HLVL]; -#define DFLT_DIS (DEV_DIS) -#define DFLT_CR11 (UNIT_CR11) +#define DFLT_DIS (DEV_QBUS) /* CR11 is programmed I/O only, Qbus OK */ +#define DFLT_TYPE (UNIT_CR11) /* Default, but changable */ #define DFLT_CPM 285 +#define CD20_OK (1) +#define AIECO_OK (1) /* Augmented Image ECO optional */ +#define CR11_OK (1) +#define CD11_OK (1) #endif -extern FILE *sim_deb; /* sim_console.c */ +/* **** No VM_xxx macros should be referenced after this line **** */ /* create a int32 constant from four characters */ #define I4C(a,b,c,d) (((a) << 24) | ((b) << 16) | ((c) << 8) | (d)) @@ -196,10 +238,46 @@ extern FILE *sim_deb; /* sim_console.c */ #define I4C_H82 I4C ('H','8','2',' ') #define I4C_H40 I4C ('H','4','0',' ') -#define UNIT_V_CR11 (UNIT_V_UF + 0) -#define UNIT_CR11 (1u << UNIT_V_CR11) -#define UNIT_V_AUTOEOF (UNIT_V_UF + 1) +#define UNIT_V_TYPE (UNIT_V_UF + 0) /* Bit-encoded 2-bit field */ +#define UNIT_TYPE (3u << UNIT_V_TYPE) +#define UNIT_CR11 (1u << UNIT_V_TYPE) +#define UNIT_CD20 (2u << UNIT_V_TYPE) + +#define UNIT_V_AUTOEOF (UNIT_V_UF + 2) #define UNIT_AUTOEOF (1u << UNIT_V_AUTOEOF) +#define UNIT_V_RDCHECK (UNIT_V_UF + 3) +#define UNIT_RDCHECK (1u << UNIT_V_RDCHECK) +#define UNIT_V_AIECO (UNIT_V_UF + 4) +#define UNIT_AIECO (1u << UNIT_V_AIECO) + +/* Tests for which device is being emulated. + * Note that CD20 is a CD11 + mandatory ECOs. CD11_CTL will be true for both. + */ +#if defined (CD11_ONLY) || defined (CD20_ONLY) +#define CR11_CTL(up) (0) +#define CD11_CTL(up) (1) +#elif defined (CR11_ONLY) +#define CR11_CTL(up) (1) +#define CD11_CTL(up) (0) +#else +#define CR11_CTL(up) ((up)->flags & UNIT_CR11) +#define CD11_CTL(up) (!CR11_CTL(up)) +#endif + +#if defined (CD20_ONLY) +#define CD20_CTL(up) (1) +#elif defined (CD20_OK) +#define CD20_CTL(up) ((up)->flags & UNIT_CD20) +#else +#define CD20_CTL(up) (0) +#endif + +/* Configuration */ +#if defined (AIECO_REQ) +#define DFLT_AIECO (UNIT_AIECO) +#else +#define DFLT_AIECO (0) +#endif #include #define ERROR (00404) @@ -247,19 +325,22 @@ extern FILE *sim_deb; /* sim_console.c */ /* CD */ /* also use CSR_ERR, CSR_IE, and CSR_GO */ -#define CDCSR_V_RDRCHK 14 /* reader check */ +/* ERR */ +#define CDCSR_V_RDRCHK 14 /* reader check: HOPPER,STACK,PICK,READ */ #define CDCSR_V_EOF 13 /* CD11-E EOF button */ #define CDCSR_V_OFFLINE 12 /* off line */ -#define CDCSR_V_DATAERR 11 /* data error */ +#define CDCSR_V_DATAERR 11 /* data packing error */ #define CDCSR_V_LATE 10 /* data late */ #define CDCSR_V_NXM 9 /* non-existent memory */ #define CDCSR_V_PWRCLR 8 /* power clear */ #define CDCSR_V_RDY 7 /* ready */ -#define CDCSR_V_XBA17 5 +/* IE */ +#define CDCSR_V_XBA17 5 /* NPR bus address bits<17:16> */ #define CDCSR_V_XBA16 4 #define CDCSR_V_ONLINE 3 /* on line transition */ #define CDCSR_V_HOPPER 2 /* hopper check */ #define CDCSR_V_PACK 1 /* data packing */ +/* GO */ #define CDCSR_RDRCHK (1u << CDCSR_V_RDRCHK) #define CDCSR_EOF (1u << CDCSR_V_EOF) @@ -275,6 +356,8 @@ extern FILE *sim_deb; /* sim_console.c */ #define CDCSR_HOPPER (1u << CDCSR_V_HOPPER) #define CDCSR_PACK (1u << CDCSR_V_PACK) +#define CDCSR_ANYERR (CDCSR_RDRCHK | CDCSR_EOF | CDCSR_OFFLINE | CDCSR_DATAERR | CDCSR_LATE | CDCSR_NXM) + #define CDCSR_IMP (CSR_ERR | CDCSR_RDRCHK | CDCSR_EOF | CDCSR_OFFLINE | \ CDCSR_DATAERR | CDCSR_LATE | CDCSR_NXM | \ CDCSR_PWRCLR | CDCSR_RDY | CSR_IE | \ @@ -284,6 +367,23 @@ extern FILE *sim_deb; /* sim_console.c */ #define CDCSR_RW (CDCSR_PWRCLR | CSR_IE | CDCSR_XBA17 | CDCSR_XBA16 | \ CDCSR_PACK | CSR_GO) +/* CD11 second status register bits. Valid only when not busy. All + * also set CDCSR_RDRCK (and CSR_ERR) + */ + +#define CDDB_V_READ 14 /* Read check (extra punches, not readER check) */ +#define CDDB_V_PICK 13 /* Pick check (card present, not grabbed) */ +#define CDDB_V_STACK 12 /* Card did not arrive in stacker */ + +/* N.B. Per TOPS-20 driver, which references CD11 manual and printset: + * Stacker full is indicated by: + * CDCSR_RDRCHK && !(CDDB_READ|CDDB_PICK|CDDB_STACK) + */ +#define CDDB_READ (1U << CDDB_V_READ) +#define CDDB_PICK (1u << CDDB_V_PICK) +#define CDDB_STACK (1u << CDDB_V_STACK) + + /* Blower state values */ #define BLOW_OFF (0) /* steady state off */ #define BLOW_START (1) /* starting up */ @@ -291,51 +391,79 @@ extern FILE *sim_deb; /* sim_console.c */ #define BLOW_STOP (3) /* shutting down */ /* Card Reader state */ -static char *cardFormat = "unknown"; -static t_bool (*readRtn)(FILE *, int16 *, char *, char *); +static const char *cardFormat = "unknown"; +static t_bool (*readRtn)(UNIT *, int16 *, char *, char *); static char ascii_code[4096]; /* 2^12 possible values */ static int currCol; /* current column when reading */ static int colStart; /* starting column */ static int colEnd; /* ending column */ -static int table = 3; /* character translation table */ -static const int *codeTbl = o29_code; /* punch translation table */ +static const int *codeTbl = /* punch translation table */ +#if defined(CD20_ONLY) || (defined(DFLT_TYPE) && (DFLT_TYPE == UNIT_CD20)) + o29_decascii_code; +#else + o29_code; +#endif +static struct trans { + const char *const name; + const int *table; +} transcodes[] = { + { "DEFAULT", o29_code, }, + { "026", o26_dec_code, }, + { "026FTN", o26_ftn_code, }, + { "026DECASCII", o26_decascii_code, }, + { "029", o29_code, }, + { "EBCDIC", EBCDIC_code, }, + { "026DEC", o26_dec_code, }, + { "029DECASCII", o29_decascii_code }, +}; +#define NTRANS (sizeof transcodes /sizeof transcodes[0]) + static int32 blowerState = BLOW_OFF; /* reader vacuum/blower motor */ -static int32 spinUp = 3000; /* blower spin-up time: 3 seconds */ -static int32 spinDown = 2000; /* blower spin-down time: 2 seconds */ -static t_bool EOFcard = FALSE; /* played special card yet? */ +static int32 spinUp = 3000000; /* blower spin-up time: 3 seconds (usec) */ +static int32 spinDown = 2000000; /* blower spin-down time: 2 seconds (usec) */ +static int EOFcard = 0; /* played special card yet? */ +static t_bool eofPending = FALSE; /* Manual EOF switch pressed */ static int32 cpm = DFLT_CPM; /* reader rate: cards per minute */ +static int schedule_svc=0; /* Re-schedule service if true */ /* card image in various formats */ static int16 hcard[82]; /* Hollerith format */ static char ccard[82]; /* DEC compressed format */ static char acard[82]; /* ASCII format */ /* CR/CM registers */ -static int32 crs = 0; /* control/status */ +static int32 crs = CSR_ERR | CRCSR_OFFLINE | CRCSR_SUPPLY; /* control/status */ static int32 crb1 = 0; /* 12-bit Hollerith characters */ static int32 crb2 = 0; /* 8-bit compressed characters */ static int32 crm = 0; /* CMS maintenance register */ /* CD registers */ -static int32 cdst = 0; /* control/status */ +static int32 cdst = CSR_ERR | CDCSR_OFFLINE | CDCSR_HOPPER; /* Control/status - off-line until attached */ static int32 cdcc = 0; /* column count */ static int32 cdba = 0; /* current address, low 16 bits */ static int32 cddb = 0; /* data, 2nd status */ +static int32 cddbs = 0; /* second status bits (or with cddb) */ /* forward references */ -DEVICE cr_dev; static void setupCardFile (UNIT *, int32); t_stat cr_rd (int32 *, int32, int32); t_stat cr_wr (int32, int32, int32); +int32 cr_intac(void); t_stat cr_svc (UNIT *); t_stat cr_reset (DEVICE *); t_stat cr_attach (UNIT *, char *); t_stat cr_detach (UNIT *); t_stat cr_set_type (UNIT *, int32, char *, void *); +t_stat cr_set_aieco (UNIT *, int32, char *, void *); t_stat cr_show_format (FILE *, UNIT *, int32, void *); t_stat cr_set_rate (UNIT *, int32, char *, void *); t_stat cr_show_rate (FILE *, UNIT *, int32, void *); t_stat cr_set_reset (UNIT *, int32, char *, void *); t_stat cr_set_stop (UNIT *, int32, char *, void *); +t_stat cr_set_eof (UNIT *, int32, char *, void *); +t_stat cr_show_eof (FILE *, UNIT *, int32, void *); t_stat cr_set_trans (UNIT *, int32, char*, void *); t_stat cr_show_trans (FILE *, UNIT *, int32, void *); +static t_stat cr_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr); +const char *cr_description (DEVICE *dptr); + /* CR data structures @@ -347,50 +475,84 @@ t_stat cr_show_trans (FILE *, UNIT *, int32, void *); */ static DIB cr_dib = { IOBA_CR, IOLN_CR, &cr_rd, &cr_wr, - 1, IVCL (CR), VEC_CR, { NULL } }; + 1, IVCL (CR), VEC_CR, { cr_intac } }; static UNIT cr_unit = { UDATA (&cr_svc, UNIT_ATTABLE+UNIT_SEQ+UNIT_ROABLE+UNIT_DISABLE+ - DFLT_CR11+UNIT_AUTOEOF, 0), - (60 * 1000) / DFLT_CPM }; + DFLT_TYPE+UNIT_AUTOEOF+UNIT_RDCHECK+DFLT_AIECO, 0), + (60 * 1000000) / (DFLT_CPM * 80) }; -static const REG cr_reg[] = { - { GRDATA (BUF, cr_unit.buf, DEV_RDX, 8, 0) }, - { GRDATA (CRS, crs, DEV_RDX, 16, 0) }, - { GRDATA (CRB1, crb1, DEV_RDX, 16, 0) }, - { GRDATA (CRB2, crb2, DEV_RDX, 16, 0) }, - { GRDATA (CRM, crm, DEV_RDX, 16, 0) }, - { GRDATA (CDST, cdst, DEV_RDX, 16, 0) }, - { GRDATA (CDCC, cdcc, DEV_RDX, 16, 0) }, - { GRDATA (CDBA, cdba, DEV_RDX, 16, 0) }, - { GRDATA (CDDB, cddb, DEV_RDX, 16, 0) }, - { GRDATA (BLOWER, blowerState, DEV_RDX, 2, 0) }, - { FLDATA (INT, IREQ (CR), INT_V_CR) }, - { FLDATA (ERR, crs, CSR_V_ERR) }, - { FLDATA (IE, crs, CSR_V_IE) }, - { DRDATA (POS, cr_unit.pos, T_ADDR_W), PV_LEFT }, - { DRDATA (TIME, cr_unit.wait, 24), PV_LEFT }, - { GRDATA (DEVADDR, cr_dib.ba, DEV_RDX, 32, 0), REG_HRO }, - { GRDATA (DEVVEC, cr_dib.vec, DEV_RDX, 16, 0), REG_HRO }, +static REG cr_reg[] = { + { GRDATA (BUF, cr_unit.buf, DEV_RDX, 8, 0) }, +#if defined (CR11_OK) || defined (CR11_ONLY) + { GRDATA (CRS, crs, DEV_RDX, 16, 0) }, + { GRDATA (CRB1, crb1, DEV_RDX, 16, 0) }, + { GRDATA (CRB2, crb2, DEV_RDX, 16, 0) }, + { GRDATA (CRM, crm, DEV_RDX, 16, 0) }, +#endif +#if defined (CD11_OK) || defined (CD11_ONLY) || defined (CD20_OK) || defined (CD20_ONLY) + { GRDATA (CDST, cdst, DEV_RDX, 16, 0) }, + { GRDATA (CDCC, cdcc, DEV_RDX, 16, 0) }, + { GRDATA (CDBA, cdba, DEV_RDX, 16, 0) }, + { GRDATA (CDDB, cddb, DEV_RDX, 16, 0) }, +#endif + { GRDATA (BLOWER, blowerState, DEV_RDX, 2, 0) }, + { FLDATA (INT, IREQ (CR), INT_V_CR) }, + { FLDATA (ERR, crs, CSR_V_ERR) }, + { FLDATA (IE, crs, CSR_V_IE) }, + { DRDATA (POS, cr_unit.pos, T_ADDR_W), PV_LEFT }, + { DRDATA (TIME, cr_unit.wait, 24), PV_LEFT }, + { GRDATA (DEVADDR, cr_dib.ba, DEV_RDX, 32, 0), REG_HRO }, + { GRDATA (DEVVEC, cr_dib.vec, DEV_RDX, 16, 0), REG_HRO }, { NULL } }; -static const MTAB cr_mod[] = { -#if defined (VM_PDP11) - { UNIT_CR11, UNIT_CR11, "CR11", "CR11", &cr_set_type }, - { UNIT_CR11, 0, "CD11", "CD11", &cr_set_type }, -#else - { UNIT_CR11, UNIT_CR11, "CR11", NULL }, - { UNIT_CR11, 0, "CD11", NULL }, +static char *translation_help = NULL; +static MTAB cr_mod[] = { +#if defined (CR11_OK) + { UNIT_TYPE, UNIT_CR11, "CR11", "CR11", + &cr_set_type, NULL, NULL }, #endif - { UNIT_AUTOEOF, UNIT_AUTOEOF, "auto EOF", "AUTOEOF", NULL }, - { UNIT_AUTOEOF, 0, "no auto EOF", "NOAUTOEOF", NULL }, +#if defined (CD11_OK) + { UNIT_TYPE, 0, "CD11", "CD11", + &cr_set_type, NULL, NULL }, +#endif +#if defined (CD20_OK) + { UNIT_TYPE, UNIT_CD20, "CD20", "CD20", + &cr_set_type, NULL, NULL }, +#endif +#if defined (CR11_ONLY) || defined (CD11_ONLY) || defined (CD20_ONLY) + { UNIT_TYPE, UNIT_CR11, "CR11", NULL, }, + { UNIT_TYPE, 0, "CD11", NULL, }, + { UNIT_TYPE, UNIT_CD20, "CD20", NULL, }, +#endif +#if defined (AIECO_OK) + { (UNIT_TYPE|UNIT_AIECO), (UNIT_CD20|UNIT_AIECO), "augmented image ECO", "AIECO", + &cr_set_aieco, NULL, NULL }, + { (UNIT_TYPE|UNIT_AIECO), (UNIT_CD20|0), "standard", "NOAIECO", + &cr_set_aieco, NULL, NULL }, +#endif + { UNIT_AUTOEOF, UNIT_AUTOEOF, "auto EOF", "AUTOEOF", + NULL, NULL, NULL }, + { UNIT_AUTOEOF, 0, "no auto EOF", "NOAUTOEOF", + NULL, NULL, NULL }, +#if !defined (CR11_ONLY) + { UNIT_RDCHECK, UNIT_RDCHECK, "read check", "RDCHECK", + NULL, NULL, NULL }, + { UNIT_RDCHECK, 0, "no read check", "NORDCHECK", + NULL, NULL, NULL }, +#endif + /* card reader STOP switch */ + { MTAB_XTD|MTAB_VDV, 0, NULL, "STOP", + &cr_set_stop, NULL, NULL }, /* card reader RESET switch */ { MTAB_XTD|MTAB_VDV, 0, NULL, "RESET", &cr_set_reset, NULL, NULL }, - /* card reader STOP switch */ - { MTAB_XTD|MTAB_VDV, 0, NULL, "STOP", - &cr_set_stop, NULL, NULL }, +#if !defined (CR11_ONLY) + /* card reader EOF switch */ + { MTAB_XTD|MTAB_VDV, MTAB_XTD|MTAB_VDV, "EOF pending", "EOF", + &cr_set_eof, &cr_show_eof, NULL }, +#endif { MTAB_XTD|MTAB_VUN, 0, "FORMAT", NULL, NULL, &cr_show_format, NULL }, { MTAB_XTD|MTAB_VDV, 006, "ADDRESS", "ADDRESS", @@ -400,7 +562,7 @@ static const MTAB cr_mod[] = { { MTAB_XTD|MTAB_VDV, 0, "RATE", "RATE={DEFAULT|200..1200}", &cr_set_rate, &cr_show_rate, NULL }, { MTAB_XTD|MTAB_VDV, 0, "TRANSLATION", - "TRANSLATION={DEFAULT|026|026FTN|029|EBCDIC}", + NULL, &cr_set_trans, &cr_show_trans, NULL }, { 0 } }; @@ -409,7 +571,8 @@ DEVICE cr_dev = { 1, 10, 31, 1, DEV_RDX, 8, NULL, NULL, &cr_reset, NULL, &cr_attach, &cr_detach, - &cr_dib, DEV_DISABLE | DFLT_DIS | DEV_UBUS | DEV_DEBUG }; + &cr_dib, DEV_DISABLE | DFLT_DIS | DEV_UBUS | DEV_DEBUG + }; /* Utility routines */ @@ -424,6 +587,12 @@ TRUE if a card was read (possibly with errors) and FALSE if the "hopper is empty" (EOF) or fatal file errors prevented any portion of a card from being read. +Note that the hopper becomes empty when the last card moves to the +read station. Thus hopper empty without an error means that data +from that card is valid. Thus hopper empty is first signalled when +the NEXT card read would return EOF. Reads after that will return +some error bit. + Errors other than EOF are signaled out of band in the controller state variables. Possible errors are data in columns 0 or 81 (signalled as read check; currently these columns are ignored), or @@ -434,144 +603,146 @@ check". Retry 3 times. After that, give up with error. */ -static t_bool readCardImage ( FILE *fp, +/* Common handling for end of file and errors on input */ + +static t_bool fileEOF ( UNIT *uptr, + int16 *hcard, + char *ccard, + char *acard, + int32 cddbsBits ) +{ + int col; + + if (DEBUG_PRS (cr_dev)) + fprintf (sim_deb, "hopper empty-eof\n"); + + if (!EOFcard && (uptr->flags & UNIT_AUTOEOF) && !ferror(uptr->fileref)) { + EOFcard = -1; + /* Generate EOD card, which empties the hopper */ + for (col = 1; col <= 8; col++) { + hcard[col] = PUNCH_EOD; + ccard[col] = (char)h2c_code[PUNCH_EOD]; + acard[col] = ' '; + } + while (col <= colEnd) { + hcard[col] = PUNCH_SPACE; + ccard[col] = PUNCH_SPACE; + acard[col] = ' '; + col++; + } + /* The CR11 doesn't set SUPPPLY at this time, but waits until the EOF card is done. */ + cdst |= CDCSR_HOPPER; + return (TRUE); + } + + /* Not auto EOF, or EOF already handled. This is an attempt to read + * with an empty hopper. Report a pick, read or stacker check as well + * as hopper empty to indicate that no data was transfered. One might + * think that cdcc unchanged would be sufficient, but that's not what + * the OSs check. + */ + + crs |= CSR_ERR | CRCSR_SUPPLY | CRCSR_OFFLINE; + crs &= ~(CRCSR_COLRDY | CRCSR_ONLINE); + + cdst |= CSR_ERR | CDCSR_RDRCHK | CDCSR_HOPPER; + cddbs |= cddbsBits; + + if (((uptr->flags & UNIT_AUTOEOF) || eofPending) && !ferror(uptr->fileref)) { + cdst |= CDCSR_EOF; + eofPending = FALSE; + } + return (FALSE); +} + +static t_bool readCardImage ( UNIT *uptr, int16 *hcard, char *ccard, char *acard ) { int c1, c2, c3, col; + FILE *fp = uptr->fileref; if (DEBUG_PRS (cr_dev)) fprintf (sim_deb, "readCardImage pos %d\n", (int) ftell (fp)); - /* get card header bytes */ - c1 = fgetc (fp); - c2 = fgetc (fp); - c3 = fgetc (fp); - cr_unit.pos = ftell (fp); - /* check for EOF */ - if (c1 == EOF) { - if (DEBUG_PRS (cr_dev)) - fprintf (sim_deb, "hopper empty\n"); - if (!EOFcard && (cr_unit.flags & UNIT_AUTOEOF)) { - EOFcard = TRUE; - for (col = 1; col <= 8; col++) { - hcard[col] = PUNCH_EOD; - ccard[col] = h2c_code[PUNCH_EOD]; - acard[col] = ' '; - } - while (col <= colEnd) { - hcard[col] = PUNCH_SPACE; - ccard[col] = PUNCH_SPACE; - acard[col] = ' '; - col++; - } - return (TRUE); - } - crs |= CSR_ERR | CRCSR_RDCHK | CRCSR_SUPPLY | CRCSR_OFFLINE; - crs &= ~(CRCSR_COLRDY | CRCSR_ONLINE); - cdst |= CSR_ERR | CDCSR_RDRCHK | CDCSR_HOPPER; - if (cr_unit.flags & UNIT_AUTOEOF) - cdst |= CDCSR_EOF; - blowerState = BLOW_STOP; - return (FALSE); - } - /* check for valid header */ - if ((c2 == EOF) || (c3 == EOF) || ((c1 & 0x80) == 0) || - ((c2 & 0x80) == 0) || ((c3 & 0x80) == 0)) { - if (DEBUG_PRS (cr_dev)) - fprintf (sim_deb, "header error\n"); - /* unexpected EOF or format problems */ - crs |= CSR_ERR | CRCSR_RDCHK | CRCSR_OFFLINE; - crs &= ~CRCSR_ONLINE; - cdst |= CSR_ERR | CDCSR_RDRCHK; - blowerState = BLOW_STOP; - return (FALSE); - } - assert (colStart < colEnd); - assert (colStart >= 0); - assert (colEnd <= 81); - for (col = colStart; col < colEnd; ) { - int16 i; - /* get 3 bytes */ + do { + /* get card header bytes */ c1 = fgetc (fp); c2 = fgetc (fp); c3 = fgetc (fp); - cr_unit.pos = ftell (fp); - if (ferror (fp) || feof (fp)) { - if (DEBUG_PRS (cr_dev)) - fprintf (sim_deb, "file error\n"); -/* signal error; unexpected EOF, format problems, or file error(s) */ - crs |= CSR_ERR | CRCSR_RDCHK | CRCSR_OFFLINE; - crs &= ~CRCSR_ONLINE; - cdst |= CSR_ERR | CDCSR_RDRCHK; - blowerState = BLOW_STOP; - return (FALSE); - } - /* convert to 2 columns */ - i = ((c1 << 4) | ( c2 >> 4)) & 0xFFF; - hcard[col] = i; - ccard[col] = h2c_code[i]; - acard[col] = ascii_code[i]; - col++; + uptr->pos = ftell (fp); + /* check for EOF */ + if (c1 == EOF) + return fileEOF (uptr, hcard, ccard, acard, CDDB_PICK); + + /* check for valid card header */ + if ((c2 == EOF) || (c3 == EOF) || ((c1 & c2 & c3 & 0x80) == 0) ) { + if (DEBUG_PRS (cr_dev)) + fprintf (sim_deb, "header error\n"); + /* unexpected EOF or format problems */ + return fileEOF (uptr, hcard, ccard, acard, CDDB_READ); + } + + /* Read card image into internal buffer */ + + assert (colStart < colEnd); + assert (colStart >= 0); + assert (colEnd <= 81); + for (col = colStart; col < colEnd; ) { + int16 i; + int c1, c2, c3; + /* get 3 bytes */ + c1 = fgetc (fp); + c2 = fgetc (fp); + c3 = fgetc (fp); + uptr->pos = ftell (fp); + if (ferror (fp) || (c1 == EOF) || (c2 == EOF) || (c3 == EOF)) { + if (DEBUG_PRS (cr_dev)) + fprintf (sim_deb, "file error\n"); + /* signal error; unexpected EOF, format problems, or file error(s) */ + return fileEOF (uptr, hcard, ccard, acard, ferror(fp)? CDDB_READ: CDDB_PICK); + } + /* convert to 2 columns */ + i = ((c1 << 4) | ( c2 >> 4)) & 0xFFF; + hcard[col] = i; + ccard[col] = (char)h2c_code[i]; + acard[col] = ascii_code[i]; + col++; + + i = (((c2 & 017) << 8) | c3) & 0xFFF; + hcard[col] = i; + ccard[col] = (char)h2c_code[i]; + acard[col] = ascii_code[i]; + col++; + } + } while ((c3 & 0x3f) == 0x3f); /* Skip metacards (Revised Jones spec) */ - i = (((c2 & 017) << 8) | c3) & 0xFFF; - hcard[col] = i; - ccard[col] = h2c_code[i]; - acard[col] = ascii_code[i]; - col++; - } if (DEBUG_PRS (cr_dev)) fprintf (sim_deb, "successfully loaded card\n"); return (TRUE); } -static t_bool readColumnBinary ( FILE *fp, +static t_bool readColumnBinary ( UNIT *uptr, int16 *hcard, char *ccard, char *acard ) { int col; + FILE *fp = uptr->fileref; for (col = colStart; col <= colEnd; col++) { - int16 i; - i = fgetc (fp) & 077; - i |= ((fgetc (fp) & 077) << 6); - cr_unit.pos = ftell (fp); - if (feof (fp)) { - if (!EOFcard && (cr_unit.flags & UNIT_AUTOEOF)) { - EOFcard = TRUE; - for (col = 1; col <= 8; col++) { - hcard[col] = PUNCH_EOD; - ccard[col] = h2c_code[PUNCH_EOD]; - acard[col] = ' '; - } - while (col <= colEnd) { - hcard[col] = PUNCH_SPACE; - ccard[col] = PUNCH_SPACE; - acard[col] = ' '; - col++; - } - return (TRUE); - } - crs |= CSR_ERR | CRCSR_RDCHK | CRCSR_SUPPLY | - CRCSR_OFFLINE; - crs &= ~(CRCSR_COLRDY | CRCSR_ONLINE); - cdst |= CSR_ERR | CDCSR_RDRCHK | CDCSR_HOPPER; - if (cr_unit.flags & UNIT_AUTOEOF) - cdst |= CDCSR_EOF; - blowerState = BLOW_STOP; - return (FALSE); - } - if (ferror (fp)) { - /* signal error */ - crs |= CSR_ERR | CRCSR_RDCHK | CRCSR_OFFLINE; - crs &= ~CRCSR_ONLINE; - cdst |= CSR_ERR | CDCSR_RDRCHK; - blowerState = BLOW_STOP; - return (FALSE); - } + int c1, c2; + uint16 i; + c1 = fgetc (fp); + c2 = fgetc (fp); + uptr->pos = ftell (fp); + if (c1 == EOF) + return fileEOF (uptr, hcard, ccard, acard, CDDB_PICK); + if ((c2 == EOF) || ferror(fp)) + return fileEOF (uptr, hcard, ccard, acard, CDDB_READ); + i = (c1 & 077) | ((c2 & 077) << 6); hcard[col] = i; - ccard[col] = h2c_code[i]; + ccard[col] = (char)h2c_code[i]; acard[col] = ascii_code[i]; } return (TRUE); @@ -581,16 +752,17 @@ static t_bool readColumnBinary ( FILE *fp, Should this routine perform special handling of non-printable, (e.g., control) characters or characters that have no encoded -representation? +representation? (In DEC026/DEC029 they all do...) */ -static t_bool readCardASCII ( FILE *fp, +static t_bool readCardASCII ( UNIT *uptr, int16 *hcard, char *ccard, char *acard ) { - int c, col; + int c = 0, col, peek; + FILE *fp = uptr->fileref; assert (colStart < colEnd); assert (colStart >= 1); @@ -602,40 +774,26 @@ static t_bool readCardASCII ( FILE *fp, switch (c = fgetc (fp)) { case EOF: if (ferror (fp)) { - /* signal error */ - crs |= CSR_ERR | CRCSR_RDCHK | CRCSR_OFFLINE; - crs &= ~CRCSR_ONLINE; - cdst |= CSR_ERR | CDCSR_RDRCHK; - blowerState = BLOW_STOP; - cr_unit.pos = ftell (fp); - return (FALSE); + uptr->pos = ftell (fp); + return fileEOF (uptr, hcard, ccard, acard, CDDB_READ); } if (col == colStart) { if (DEBUG_PRS (cr_dev)) fprintf (sim_deb, "hopper empty\n"); - if (!EOFcard && (cr_unit.flags & UNIT_AUTOEOF)) { - EOFcard = TRUE; - for (col = 1; col <= 8; col++) { - hcard[col] = PUNCH_EOD; - ccard[col] = h2c_code[PUNCH_EOD]; - acard[col] = ' '; - } - c = '\n'; - goto fill_card; - } - crs |= CSR_ERR | CRCSR_RDCHK | CRCSR_SUPPLY | CRCSR_OFFLINE; - crs &= ~(CRCSR_COLRDY | CRCSR_ONLINE); - cdst |= CSR_ERR | CDCSR_RDRCHK | CDCSR_HOPPER; - if (cr_unit.flags & UNIT_AUTOEOF) - cdst |= CDCSR_EOF; - blowerState = BLOW_STOP; - cr_unit.pos = ftell (fp); - return (FALSE); + uptr->pos = ftell (fp); + return fileEOF (uptr, hcard, ccard, acard, CDDB_PICK); } /* fall through */ case '\r': + peek = fgetc (uptr->fileref); + if ((peek != EOF) && (peek != '\n')) + ungetc (peek, uptr->fileref); + goto fill; case '\n': - fill_card: + peek = fgetc (uptr->fileref); + if ((peek != EOF) && (peek != '\r')) + ungetc (peek, uptr->fileref); + fill: while (col <= colEnd) { hcard[col] = PUNCH_SPACE; ccard[col] = PUNCH_SPACE; @@ -652,31 +810,41 @@ static t_bool readCardASCII ( FILE *fp, } while (((col & 07) != 1) && (col <= colEnd)); break; default: - hcard[col] = codeTbl[c & 0177]; + hcard[col] = (uint16)codeTbl[c & 0177]; /* check for unrepresentable ASCII characters */ if (hcard[col] == ERROR) { cdst |= CDCSR_DATAERR; if (DEBUG_PRS (cr_dev)) fprintf (sim_deb, - "error character at column %d\n", - col); + "error character at column %d (%c)\n", + col, c & 0177); } - ccard[col] = h2c_code[hcard[col]]; - acard[col] = c; + ccard[col] = (char)h2c_code[hcard[col]]; + acard[col] = (char)c; col++; break; } } /* silently truncate/flush long lines, or flag over-length card? */ - if (c != '\n') { + if (c != '\n' && c != '\r') { if (DEBUG_PRS (cr_dev)) fprintf (sim_deb, "truncating card\n"); - do c = fgetc (fp); - while ((c != EOF) && (c != '\n') && (c != '\r')); + c = fgetc (fp); + while (c != EOF) { + if ((c == '\n') || (c == '\r')) { + peek = fgetc (uptr->fileref); + if (peek == EOF) + break; + if (((c == '\n') && (peek != '\r')) || ((c == '\r') && (peek != '\n'))) + ungetc (peek, uptr->fileref); + break; + } + c = fgetc (fp); + } } if (DEBUG_PRS (cr_dev)) fprintf (sim_deb, "successfully loaded card\n"); - cr_unit.pos = ftell (fp); + uptr->pos = ftell (fp); return (TRUE); } @@ -692,34 +860,8 @@ static void initTranslation (void) int32 i; memset (ascii_code, '~', sizeof (ascii_code)); - switch (table) { - case 1: - codeTbl = o26_comm_code; - for (i = ' '; i < '`'; i++) - ascii_code[o26_comm_code[i]] = i; - break; - case 2: - codeTbl = o26_ftn_code; - for (i = ' '; i < '`'; i++) - ascii_code[o26_ftn_code[i]] = i; - break; - case 3: - codeTbl = o29_code; - for (i = ' '; i < '`'; i++) - ascii_code[o29_code[i]] = i; - break; - case 4: - codeTbl = EBCDIC_code; - for (i = 0; i < 0177; i++) - ascii_code[EBCDIC_code[i]] = i; - break; - default: - /* can't happen */ - if (DEBUG_PRS (cr_dev)) - fprintf (sim_deb, - "bad CR translation initialization value\n"); - break; - } + for (i = 0; i < 0177; i++) + ascii_code[codeTbl[i]] = (char)i; } /* @@ -809,11 +951,11 @@ t_stat cr_rd ( int32 *data, { switch ((PA >> 1) & 03) { case 0: /* CSR */ - if (cdst & (077000)) + if (cdst & (CDCSR_ANYERR)) cdst |= CSR_ERR; else cdst &= ~CSR_ERR; - *data = (cr_unit.flags & UNIT_CR11) ? + *data = (CR11_CTL(&cr_unit)) ? crs & CRCSR_IMP : cdst & CDCSR_IMP; /* CR: if error removed, clear 15, 14, 11, 10 */ if (DEBUG_PRS (cr_dev)) @@ -821,37 +963,41 @@ t_stat cr_rd ( int32 *data, crs, cdst); break; case 1: - *data = (cr_unit.flags & UNIT_CR11) ? crb1 : cdcc; + /* Get word of data from crb1 (Hollerith code) or CD11 CC */ + *data = (CR11_CTL(&cr_unit)) ? crb1 : cdcc; + crs &= ~CRCSR_COLRDY; + if (DEBUG_PRS (cr_dev)) { + if (CR11_CTL(&cr_unit)) + fprintf (sim_deb, "cr_rd crb1 %06o '%c' %d\n", + crb1, cr_unit.buf, cr_unit.buf); + else + fprintf (sim_deb, "cr_rd cdcc %06o\n", cdcc); + } /* Does crb1 clear after read? Implied by VMS driver. */ crb1 = 0; - crs &= ~CRCSR_COLRDY; - if (DEBUG_PRS (cr_dev)) { - if (cr_unit.flags & UNIT_CR11) - fprintf (sim_deb, "cr_rd crb1 %06o '%c' %d\n", - crb1, cr_unit.buf, cr_unit.buf); - else - fprintf (sim_deb, "cr_rd cdcc %06o\n", cdcc); - } break; case 2: - *data = (cr_unit.flags & UNIT_CR11) ? crb2 : cdba; - crb2 = 0; /* see note for crb1 */ + /* Get word of data from crb2 (DEC Compressed) or CD11 BA */ + *data = (CR11_CTL(&cr_unit)) ? crb2 : cdba; crs &= ~CRCSR_COLRDY; if (DEBUG_PRS (cr_dev)) { - if (cr_unit.flags & UNIT_CR11) + if (CR11_CTL(&cr_unit)) fprintf (sim_deb, "cr_rd crb2 %06o\n", crb2); else fprintf (sim_deb, "\r\ncr_rd cdba %06o\n", cdba); } - break; + crb2 = 0; /* see note for crb1 */ + break; case 3: default: - if (cr_unit.flags & UNIT_CR11) + if (CR11_CTL(&cr_unit)) /* CR11 maintenance */ *data = crm; - else - *data = 0100000 | (cdst & CDCSR_RDRCHK) | - (cdst & CDCSR_OFFLINE) ? - cddb & 0777 : 0777; + else /* CD11 data buffer/status. Note this implementation returns extended + * status even while busy (rather than the zone). Might be wrong. + */ + *data = 0100000 | (cddbs & (CDDB_READ|CDDB_PICK|CDDB_STACK)) | + ((crs & CRCSR_BUSY) ? + cddb & 0777 : 0777); if (DEBUG_PRS (cr_dev)) fprintf (sim_deb, "cr_rd crm %06o cddb %06o data %06o\n", crm, cddb, *data); @@ -864,9 +1010,11 @@ t_stat cr_wr ( int32 data, int32 PA, int32 access ) { + int curr_crs = crs; /* Save current crs to recover status */ + switch ((PA >> 1) & 03) { case 0: - if (cr_unit.flags & UNIT_CR11) { + if (CR11_CTL(&cr_unit)) { /* ignore high-byte writes */ if (PA & 1) break; @@ -876,63 +1024,119 @@ t_stat cr_wr ( int32 data, if (!(data & CSR_IE)) CLR_INT (CR); crs = (crs & ~CRCSR_RW) | (data & CRCSR_RW); - crs &= ~(CSR_ERR | CRCSR_CRDDONE | CRCSR_TIMERR); + /* Clear status bits after CSR load */ + crs &= ~(CSR_ERR | CRCSR_ONLINE | CRCSR_CRDDONE | CRCSR_TIMERR); + if (crs & CRCSR_OFFLINE) + crs |= CSR_ERR; + /* + * Read card requested: + * Check if there was any error which required an operator + * intervention, and if so, reassert the corresponding + * error bits and assert interrupt. + * (Expected by the VMS CRDRIVER) + */ + if (data & CSR_GO) { + if (curr_crs & (CRCSR_SUPPLY | CRCSR_RDCHK | CRCSR_OFFLINE)) { + crs |= CSR_ERR | (curr_crs & (CRCSR_SUPPLY | CRCSR_RDCHK | + CRCSR_OFFLINE)); + if (crs & CSR_IE) SET_INT(CR); + } + if (blowerState != BLOW_ON) { + blowerState = BLOW_START; + sim_activate (&cr_unit, spinUp); + } else { + sim_activate (&cr_unit, cr_unit.wait); + } + } if (DEBUG_PRS (cr_dev)) fprintf (sim_deb, "cr_wr data %06o crs %06o\n", - data, crs); - if (data & CSR_GO) { - if (blowerState != BLOW_ON) { - sim_activate (&cr_unit, spinUp); - blowerState = BLOW_START; - } else - sim_activate (&cr_unit, cr_unit.wait); - } - } else { + data, crs); + } else { /* CD11 */ + if (access == WRITEB) + data = (PA & 1)? (((data & 0xff)<<8) | (cdst & 0x00ff)): + ((data & 0x00ff) | (cdst & 0xFF00)); + if (data & CDCSR_PWRCLR) { CLR_INT (CR); sim_cancel (&cr_unit); - cdst &= ~(CDCSR_RDRCHK |CDCSR_OFFLINE | - CDCSR_RDY | CDCSR_HOPPER); - cdst |= CDCSR_RDY; cdcc = 0; cdba = 0; + cddb = 0; + cddbs = 0; + if (!(cr_unit.flags & UNIT_ATT)) { /* Clear troublesome bits, but leave error/offline */ + cdst &= ~(CSR_IE | CDCSR_DATAERR | CDCSR_LATE | CDCSR_NXM | CDCSR_RDY | + CDCSR_XBA17 | CDCSR_XBA16 | CDCSR_ONLINE | CDCSR_PACK); + cdst |= CSR_ERR | CDCSR_OFFLINE | CDCSR_RDRCHK; + cddbs |= CDDB_STACK; + break; + } + + crs &= ~CRCSR_BUSY; + cdst &= (CDCSR_OFFLINE | CDCSR_RDY | CDCSR_HOPPER); + if( (cr_unit.flags & UNIT_ATT) && !feof(cr_unit.fileref) && !ferror(cr_unit.fileref) ) + cdst &= ~(CDCSR_HOPPER); + if (cdst & (CDCSR_ANYERR)) + cdst |= CSR_ERR; + cdst |= CDCSR_RDY; break; } - if (!(data & CSR_IE)) + + if (data & CSR_GO) { + /* To simplify the service code, don't start if CDCC == 0. + * In the hardware, it's not sensible... + */ + if ((crs & CRCSR_BUSY) || (cdcc == 0)) { + cdst |= (CDCSR_RDRCHK | CDCSR_HOPPER | CSR_ERR); + } else { + cdst &= ~(CDCSR_RDRCHK | CDCSR_DATAERR | CDCSR_LATE | CDCSR_NXM | CDCSR_RDY | CDCSR_ONLINE); + cdst = (cdst & ~(CDCSR_EOF | CSR_IE | CDCSR_XBA17 | CDCSR_XBA16 | CDCSR_PACK | CDCSR_HOPPER)) + | (data & (CDCSR_EOF | CSR_IE | CDCSR_XBA17 | CDCSR_XBA16 | CDCSR_PACK)); + cddbs &= ~(CDDB_READ|CDDB_PICK|CDDB_STACK); + + /* Always attempt to start. If not attached, errors will set after delay */ + if (!(cdst & CDCSR_HOPPER) ) + cdst &= ~(CSR_ERR); + if (blowerState != BLOW_ON) { + blowerState = BLOW_START; + sim_activate (&cr_unit, spinUp); + } else { + sim_activate (&cr_unit, cr_unit.wait); + } + } + } else { + cdst = (cdst & ~(CSR_ERR | CDCSR_RDRCHK | CDCSR_EOF | CDCSR_DATAERR | CDCSR_LATE | + CDCSR_NXM | CSR_IE | CDCSR_XBA17 | CDCSR_XBA16 | CDCSR_ONLINE | CDCSR_PACK)) + |(data & (CSR_ERR | CDCSR_RDRCHK | CDCSR_EOF | CDCSR_DATAERR | CDCSR_LATE | + CDCSR_NXM | CSR_IE | CDCSR_XBA17 | CDCSR_XBA16 | CDCSR_ONLINE | CDCSR_PACK)); + } + /* Apparently the hardware does not SET_INT if ready/online are already set. If it did, TOPS-10's driver wouldn't work */ + if (!(cdst & CSR_IE)) CLR_INT (CR); - cdst = (cdst & ~CDCSR_RW) | (data & CDCSR_RW); + if (DEBUG_PRS (cr_dev)) fprintf (sim_deb, "cr_wr data %06o cdst %06o\n", data, cdst); - if (data & CSR_GO) { - if (blowerState != BLOW_ON) { - sim_activate (&cr_unit, spinUp); - blowerState = BLOW_START; - } else - sim_activate (&cr_unit, cr_unit.wait); - } } break; case 1: if (DEBUG_PRS (cr_dev)) fprintf (sim_deb, "cr_wr cdcc %06o\n", data); - if (cr_unit.flags & UNIT_CR11) - break; - cdcc = data & 0177777; + if (CD11_CTL(&cr_unit)) + cdcc = data & 0177777; break; case 2: if (DEBUG_PRS (cr_dev)) fprintf (sim_deb, "cr_wr crba %06o\n", data); - if (cr_unit.flags & UNIT_CR11) - break; - cdba = data & 0177777; + if (CD11_CTL(&cr_unit)) + cdba = data & 0177777; break; case 3: if (DEBUG_PRS (cr_dev)) fprintf (sim_deb, "cr_wr cddb/crm %06o\n", data); /* ignore writes to cddb */ - if (!(cr_unit.flags & UNIT_CR11)) + if (CD11_CTL(&cr_unit)) break; + /* fixup data for byte writes and read-modify-write */ if (access == WRITEB) data = (PA & 1) ? @@ -958,58 +1162,183 @@ t_stat cr_wr ( int32 data, return (SCPE_OK); } +/* + * Interrupt acknowledge routine + * Reschedule service routine if needed (based on + * schedule_svc flag). + * Do the actual scheduling just for the CR11 (VAX/PDP11). The PDP10 does + * not seem to call this entry point. + */ + +int32 cr_intac() { + if CR11_CTL(&cr_unit) { + if (schedule_svc) { + sim_activate (&cr_unit, cr_unit.wait); + schedule_svc = 0; + } + } + return cr_dib.vec; /* Constant interrupt vector */ +} + /* Enter the service routine once for each column read from the card. CR state bits drive this primarily (see _BUSY and _CRDDONE). However, when in CD mode, also execute one column of DMA input. - */ - t_stat cr_svc ( UNIT *uptr ) { uint32 pa; uint8 c; - uint16 w; + uint16 w; + int n; + /* Blower stopping: set it to OFF and do nothing */ if (blowerState == BLOW_STOP) { blowerState = BLOW_OFF; return (SCPE_OK); } + /* Blower starting: set it to ON and do regular service */ if (blowerState == BLOW_START) blowerState = BLOW_ON; - /* (almost) anything we do now will cause a CR interrupt */ - if (crs & CSR_IE) - SET_INT (CR); - if (!(uptr->flags & UNIT_ATT) || (crs & CSR_ERR) || (cdst & CSR_ERR)) - return (SCPE_OK); - if ((crs & CRCSR_BUSY) && (currCol > colEnd)) { - crs &= ~(CRCSR_BUSY | CSR_GO | CRCSR_COLRDY); - crs |= CRCSR_CRDDONE; - if (cdst & (CDCSR_DATAERR | CDCSR_LATE | CDCSR_NXM)) - cdst |= CSR_ERR; - if (cdst & CSR_IE) - SET_INT (CR); - if (DEBUG_PRS (cr_dev)) - fprintf (sim_deb, "cr_svc card done\n"); + + /* (almost) anything we do now will cause a CR (But not a CD) interrupt */ + if ((CR11_CTL(uptr)) && (crs & CSR_IE)) + SET_INT (CR); + + /* Unit not attached, or error status while idle */ + if (!(uptr->flags & UNIT_ATT) || (!(crs & CRCSR_BUSY) && ((CR11_CTL(uptr)?crs : cdst) & CSR_ERR))) { + if (CD11_CTL(uptr)) { + if (!(uptr->flags & UNIT_ATT)){ + cdst |= (CDCSR_HOPPER | CDCSR_RDRCHK | CDCSR_OFFLINE | CSR_ERR); + cddbs |= CDDB_STACK; + } + if (cdst & CSR_IE) + SET_INT (CR); + } return (SCPE_OK); } + + /* End of card: unit busy and column past end column */ + if ((crs & CRCSR_BUSY) && (currCol > colEnd)) { + /* clear busy state and set card done bit */ + crs &= ~(CRCSR_BUSY | CRCSR_COLRDY); + crs |= CRCSR_CRDDONE; + + if (DEBUG_PRS (cr_dev)) + fprintf (sim_deb, "cr_svc card done\n"); + + /* Check CD11 error status that stops transfers */ + if (CD11_CTL(uptr) && (cdst & (CDCSR_LATE | CDCSR_NXM))) { + cdst |= CSR_ERR | CDCSR_OFFLINE | CDCSR_RDY | CDCSR_RDRCHK; + SET_INT (CR); + return (SCPE_OK); + } + + if (CR11_CTL(uptr)) + return (SCPE_OK); + + /* If a CD11 gets this far, an interrupt is required. If CDCC != 0, + * continue reading the next card. + */ + SET_INT (CR); + if (cdcc == 0) + return (SCPE_OK); + } + + /* If unit is not busy: try to read a card */ if (!(crs & CRCSR_BUSY)) { - /* try to read a card */ - /* crs &= ~CRCSR_CRDDONE; */ - if (!readRtn (uptr->fileref, hcard, ccard, acard)) { + crs &= ~CRCSR_CRDDONE; /* This line WAS commented out - JGP 2013.02.05 */ + + /* Call the appropriate read card routine. + * If no card is read (FALSE return), we tried to read with an empty hopper. + * The card read routine set the appropriate error bits. Shutdown. + */ + if (!readRtn (uptr, hcard, ccard, acard)) { + blowerState = BLOW_STOP; + if (CD11_CTL(uptr)) { +readFault: + cdst |= CDCSR_RDY; + if (cdst & (CDCSR_RDRCHK | CDCSR_HOPPER)) + cdst |= CSR_ERR | CDCSR_OFFLINE; + if (cdst & CSR_IE) + SET_INT (CR); + + } else { + /* + * CR11 handling: assert SUPPLY and ERROR bits, + * put de device offline and DO NOT TRIGGER AN INTERRUPT + * (if the interrupt is asserted RSX and VMS will get 80 + * bytes of garbage, and RSX could crash). + */ + if (crs & (CRCSR_RDCHK | CRCSR_SUPPLY)) { + crs |= CSR_ERR | CRCSR_OFFLINE; + crs &= ~(CRCSR_ONLINE | CRCSR_BUSY | CRCSR_CRDDONE); + CLR_INT(CR); + } + } sim_activate (uptr, spinDown); return (SCPE_OK); } + + /* Card read: reset column counter and assert BUSY */ currCol = colStart; - crs |= CRCSR_BUSY; /* indicate reader busy */ + crs |= CRCSR_BUSY; + + /* Update status if this read emptied hopper. + * The CR11 doesn't set SUPPLY until after the last card is read. + */ + + /* I/O error status bits have been set during read. + * Look ahead to see if another card is in file. + */ + n = feof (uptr->fileref); + if (n) + n = EOF; + else { + n = fgetc (uptr->fileref); + if (n != EOF) + ungetc (n, uptr->fileref); + } + + if ((n == EOF) && ((EOFcard > 0) || !(uptr->flags & UNIT_AUTOEOF))) { + /* EOF and generated EOFcard sent or not an autoEOF unit. + * Set status to reflect last card taken. + */ + cdst |= (CDCSR_RDRCHK | CSR_ERR | CDCSR_OFFLINE | CDCSR_HOPPER); + if (eofPending) { + cdst |= CDCSR_EOF; + eofPending = FALSE; + } + } + + if (EOFcard) + EOFcard = 1; + + + if (CD11_CTL(uptr)) { + /* Handle read check: punches in col 0 or 81/last (DEC only did 80 cols, but...) */ + if ((uptr->flags & UNIT_RDCHECK) && + (((colStart == 0) && (hcard[0] != 0)) || ((colEnd & 1) && (hcard[colEnd] != 0)))) { + cdst |= (CDCSR_RDRCHK | CSR_ERR); + cddbs |= CDDB_READ; + if (1) /* 0 if read check should transfer card */ + goto readFault; + } + /* CDDB_PICK, CDDB_STACK, flags & UNIT_CR11) && (crs & CRCSR_COLRDY)) + if (CR11_CTL(uptr) && (crs & CRCSR_COLRDY)) crs |= CSR_ERR | CRCSR_TIMERR; - crb1 = hcard[currCol] & 07777; - crb2 = ccard[currCol] & 0377; - uptr->buf = acard[currCol] & 0377; /* helpful for debugging */ - if (!(uptr->flags & UNIT_CR11)) { + + /* Update the "buffer" registers with current column */ + crb1 = hcard[currCol] & 07777; /* Hollerith value */ + crb2 = ccard[currCol] & 0377; /* DEC compressed hollerith value */ + uptr->buf = acard[currCol] & 0377; /* Helpful for debug: ASCII value */ + + /* CD11 specific code follows */ + if (CD11_CTL(uptr)) { pa = cdba | ((cdst & 060) << 12); /* The implementation of _NXM here is not quite the same as I interpret @@ -1022,32 +1351,69 @@ code detects and flags the NXM condition but allows attempts at subsequent memory writes, thus insuring the address registers are incremented properly. If this causes problems, I'll fix it. */ - if (cdst & CDCSR_PACK) { - c = cddb = ccard[currCol] & 0377; - if (Map_WriteB (pa, 1, &c)) - cdst |= CDCSR_NXM; - pa = (pa + 1) & 0777777; - } else { - w = cddb = hcard[currCol] & 07777; - if (Map_WriteW (pa, 2, &w)) - cdst |= CDCSR_NXM; - pa = (pa + 2) & 0777777; + if (cdst & CDCSR_PACK) + cddb = c = ccard[currCol] & 0377; + else + cddb = w = hcard[currCol] & 07777; /* Punched zones: <12><11><0><1><2><3><4><5><6><7><8><9> */ + + if (cdcc == 0) /* Transfer requires CC non-zero */ + cdst |= CDCSR_LATE; + else { + if (cdst & CDCSR_PACK) { + if (Map_WriteB (pa, 1, &c)) + cdst |= CDCSR_NXM; + pa = (pa + 1) & 0777777; + } else { + /* "Augmented Image" - provides full column binary and packed encoding in 15 bits. + * Bits <14:12> encode which zone, if any, of 1-7 is punched. 0 => none, otherwise zone #. + * Bit 15 set indicates that more than one punch occured in zones 1-7; in this case the packed + * encoding is not valid. (Card may be binary data.) + * This was probably an ECO to the CD11. TOPS-10/20 depend on it, so it's definitely in the CD20. + */ + if (uptr->flags & UNIT_AIECO) { + uint16 z; + w |= ((ccard[currCol] & 07) << 12); /* Encode zones 1..7 - same as 'packed' format */ + z = w & 0774; + if ((z & -z) != z) /* More than one punch in 1..7 */ + w |= 0100000; /* sets Hollerith (encoding) failure (not an error) */ + } + if (Map_WriteW (pa, 2, &w)) + cdst |= CDCSR_NXM; + pa = (pa + 2) & 0777777; + } + cdba = pa & 0177777; + cdst = (cdst & ~(CDCSR_XBA17|CDCSR_XBA16)) | + ((pa & 0600000) >> 12); + cdcc = (cdcc + 1) & 0177777; + /* Interrupt at end of buffer; read continues to end of card. + * If this is the last column, defer interrupt so end doesn't interrupt again. + */ + if ((cdcc == 0) && (cdst & CSR_IE) && (currCol < colEnd)) + SET_INT (CR); } - cdba = pa & 0177777; - cdst = (cdst & ~(CDCSR_XBA17|CDCSR_XBA16)) | - ((pa & 0600000) >> 12); - cdcc = (cdcc + 1) & 0177777; -#if 0 - if (!(cdst & CSR_IE) && !(crs & CRCSR_CRDDONE)) + } else { /* CR11 */ + /* Handle EJECT bit: if set DO NOT assert COLRDY */ + /* nor interrupt */ + if ((crs & CRCSR_EJECT)) { CLR_INT (CR); -#endif + } else { + crs |= CRCSR_COLRDY; + } } + + /* CD11 and CR11 */ currCol++; /* advance the column counter */ - if (!(crs & CRCSR_EJECT)) - crs |= CRCSR_COLRDY; - else - CLR_INT (CR); - sim_activate (uptr, uptr->wait); + + /* Schedule next service cycle */ + /* CR11 (VAX/PDP11): just raise the schedule_svc flag; the intack + * routine will do the actual rescheduling. + * CD11/20 (PDP10): Do the rescheduling (the intack seems to do nothing) + */ + if (CD11_CTL(uptr)) { + sim_activate (uptr, uptr->wait); + } else { + schedule_svc = 1; + } return (SCPE_OK); } @@ -1055,10 +1421,33 @@ t_stat cr_reset ( DEVICE *dptr ) { if (DEBUG_PRS (cr_dev)) fprintf (sim_deb, "cr_reset\n"); + + if (!translation_help) { + size_t i; + const char trans_hlp[] = "TRANSLATION={"; + size_t size = sizeof(trans_hlp) +1; + + for ( i = 0; i < NTRANS; i++ ) + size += strlen (transcodes[i].name)+1; + translation_help = (char *)malloc (size ); + strcpy(translation_help, trans_hlp); + for (i = 0; i < NTRANS; i++) { + strcat(translation_help, transcodes[i].name); + strcat(translation_help,"|"); + } + strcpy(translation_help+strlen(translation_help)-1, "}"); + for (i = 0; i < (sizeof cr_mod / sizeof cr_mod[0]); i++ ) + if (cr_mod[i].pstring && !strcmp(cr_mod[i].pstring, "TRANSLATION")) { + cr_mod[i].mstring = translation_help; + break; + } + } cr_unit.buf = 0; currCol = 1; crs &= ~(CSR_ERR|CRCSR_CRDDONE|CRCSR_TIMERR|CRCSR_ONLINE|CRCSR_BUSY| CRCSR_COLRDY|CSR_IE|CRCSR_EJECT|CSR_GO); + if (crs & (CRCSR_OFFLINE)) + crs |= CSR_ERR; crb1 = 0; crb2 = 0; crm = 0; @@ -1066,27 +1455,35 @@ t_stat cr_reset ( DEVICE *dptr ) CDCSR_NXM|CSR_IE|CDCSR_XBA17|CDCSR_XBA16|CDCSR_ONLINE| CDCSR_PACK|CSR_GO); cdst |= CDCSR_RDY; + if (cdst & CDCSR_ANYERR) + cdst |= CSR_ERR; cdcc = 0; cdba = 0; cddb = 0; + /* ATTACHed doesn't mean ONLINE; set CR reset (pushing the reset switch) + * is what puts the reader on-line. Reset doesn't control fingers. + */ if ((cr_unit.flags & UNIT_ATT) && !feof (cr_unit.fileref)) { - crs |= CRCSR_ONLINE; /* non-standard */ - crs &= ~(CRCSR_RDCHK | CRCSR_SUPPLY | CRCSR_OFFLINE); + if (!(crs & CRCSR_OFFLINE)) + crs |= CRCSR_ONLINE; /* non-standard */ + crs &= ~(CRCSR_RDCHK | CRCSR_SUPPLY ); cdst &= ~(CDCSR_RDRCHK | CDCSR_HOPPER); + cddbs = 0; } else { cdst |= CSR_ERR | CDCSR_RDRCHK | CDCSR_HOPPER; - crs = CSR_ERR | CRCSR_RDCHK | CRCSR_SUPPLY | CRCSR_OFFLINE; + cddbs |= CDDB_STACK; + crs |= CSR_ERR | CRCSR_RDCHK | CRCSR_SUPPLY; } sim_cancel (&cr_unit); /* deactivate unit */ if (blowerState != BLOW_OFF) { blowerState = BLOW_STOP; sim_activate (&cr_unit, spinDown); } - EOFcard = FALSE; + EOFcard = 0; CLR_INT (CR); /* TBD: flush current card */ /* init uptr->wait ? */ - return (SCPE_OK); + return auto_config (dptr->name, 1); } /* @@ -1097,37 +1494,34 @@ globals correctly. #define MASK (SWMASK('A')|SWMASK('B')|SWMASK('I')|SWMASK('R')) +/* Attach unit */ +/* This should simulate physically putting a stack of cards into the hopper */ +/* No bits should change, nor an interrupt should be asserted */ +/* This is a change of behaviour respect to the previous code */ t_stat cr_attach ( UNIT *uptr, char *cptr ) { t_stat reason; - extern int32 sim_switches; if (sim_switches & ~MASK) return (SCPE_INVSW); /* file must previously exist; kludge */ sim_switches |= SWMASK ('R'); reason = attach_unit (uptr, cptr); - if (!(uptr->flags & UNIT_ATT)) { - crs &= ~CRCSR_ONLINE; - crs |= CSR_ERR | CRCSR_OFFLINE | CRCSR_RDCHK | CRCSR_SUPPLY; - cdst |= CSR_ERR | CDCSR_RDRCHK | CDCSR_HOPPER; - } else { - setupCardFile (uptr, sim_switches); - crs |= CRCSR_ONLINE; - crs &= ~(CSR_ERR | CRCSR_OFFLINE | CRCSR_RDCHK | CRCSR_SUPPLY); - cdst &= ~(CDCSR_RDRCHK | CDCSR_HOPPER); - EOFcard = FALSE; + if(uptr->flags & UNIT_ATT) { + setupCardFile(uptr, sim_switches); } + return (reason); } +/* Detach unit: assert SUPPLY and OFFLINE bits (and ERR) */ t_stat cr_detach ( UNIT *uptr ) { - crs |= CSR_ERR | CRCSR_RDCHK | CRCSR_SUPPLY | CRCSR_OFFLINE; + crs |= CSR_ERR | CRCSR_SUPPLY | CRCSR_OFFLINE; /* interrupt? */ crs &= ~CRCSR_ONLINE; - cdst |= CSR_ERR | CDCSR_RDRCHK | CDCSR_HOPPER | CDCSR_OFFLINE; + cdst |= CSR_ERR | CDCSR_HOPPER | CDCSR_OFFLINE; cardFormat = "unknown"; if (blowerState != BLOW_OFF) { blowerState = BLOW_STOP; @@ -1136,18 +1530,42 @@ t_stat cr_detach ( UNIT *uptr ) return (detach_unit (uptr)); } +#if defined (CR11_OK) || defined (CD11_OK) || defined (CD20_OK) t_stat cr_set_type ( UNIT *uptr, int32 val, char *cptr, void *desc ) { + DEVICE *dptr = find_dev_from_unit (uptr); + /* disallow type change if currently attached */ + if (uptr->flags & UNIT_ATT) return (SCPE_NOFNC); - cpm = (val & UNIT_CR11) ? 285 : 1000; - uptr->wait = (60 * 1000) / cpm; + cpm = (val & UNIT_CR11) ? 285 : ((val & UNIT_CD20)? 1200 :1000); + uptr->wait = (60 * 1000000) / (cpm * 80); /* Time between columns in usec. + * Readers are rated in card/min for 80 column cards */ + transcodes[0].table = (val & UNIT_CD20)? o29_decascii_code : o29_code; + return (SCPE_OK); } +#endif + +#if defined (AIECO_OK) +t_stat cr_set_aieco ( UNIT *uptr, + int32 val, + char *cptr, + void *desc ) +{ + /* disallow eco change if currently attached or not CD20 */ + + if (uptr->flags & UNIT_ATT || !CD20_CTL(uptr)) + return (SCPE_NOFNC); + + uptr->flags = (uptr->flags & ~UNIT_AIECO) | (val & UNIT_AIECO); + return (SCPE_OK); +} +#endif t_stat cr_show_format ( FILE *st, UNIT *uptr, @@ -1169,7 +1587,7 @@ t_stat cr_set_rate ( UNIT *uptr, if (!cptr) return (SCPE_MISVAL); if (strcmp (cptr, "DEFAULT") == 0) - i = (uptr->flags & UNIT_CR11) ? 285 : 1000; + i = CR11_CTL(uptr) ? 285 : (CD20_CTL(uptr)? 1200 :1000); else i = (int32) get_uint (cptr, 10, 0xFFFFFFFF, &status); if (status == SCPE_OK) { @@ -1177,7 +1595,8 @@ t_stat cr_set_rate ( UNIT *uptr, status = SCPE_ARG; else { cpm = i; - uptr->wait = (60 * 1000) / cpm; + uptr->wait = (60 * 1000000) / (cpm * 80); /* Time between columns in usec. + * Readers are rated in card/min for 80 column cards */ } } return (status); @@ -1192,7 +1611,10 @@ t_stat cr_show_rate ( FILE *st, return (SCPE_OK); } -/* simulate pressing the card reader RESET button */ +/* simulate pressing the card reader RESET button */ +/* Per CR11 docs, transition to ONLINE, reset card */ +/* reader logic. */ +/* RESET is somewhat of a misnomer; START is the function */ t_stat cr_set_reset ( UNIT *uptr, int32 val, @@ -1202,26 +1624,49 @@ t_stat cr_set_reset ( UNIT *uptr, if (DEBUG_PRS (cr_dev)) fprintf (sim_deb, "cr_set_reset\n"); /* -Ignore the RESET switch while a read cycle is in progress or the -unit simply is not attached. -*/ + Ignore the RESET switch while a read cycle is in progress or the + unit simply is not attached. + */ if ((crs & CRCSR_BUSY) || !(uptr->flags & UNIT_ATT)) return (SCPE_OK); + /* if no errors, signal transition to on line */ crs |= CRCSR_ONLINE; + /* Clear error bits */ crs &= ~(CSR_ERR|CRCSR_CRDDONE|CRCSR_SUPPLY|CRCSR_RDCHK|CRCSR_TIMERR| - CRCSR_BUSY|CRCSR_COLRDY|CRCSR_EJECT|CSR_GO); + CRCSR_OFFLINE|CRCSR_BUSY|CRCSR_COLRDY|CRCSR_EJECT|CSR_GO); cdst |= CDCSR_ONLINE; cdst &= ~(CSR_ERR | CDCSR_OFFLINE | CDCSR_RDRCHK | CDCSR_HOPPER | CDCSR_EOF); - if ((crs & CSR_IE) || (cdst & CSR_IE)) { + /* I don't think the hardware clears these errors, but TOPS-10 seems to expect it. + * Since we know the reader is idle, and this is OPR intervention, it seems safe. + */ + cdst &= ~(CDCSR_LATE | CDCSR_NXM); + + /* Assert interrupt if interrupts enabled */ + if ((CR11_CTL(uptr)?crs : cdst) & CSR_IE) { SET_INT (CR); if (DEBUG_PRS (cr_dev)) fprintf (sim_deb, "cr_set_reset setting interrupt\n"); } - /* start up the blower if the hopper is not empty */ - if (blowerState != BLOW_ON) + + /* Reset controller status */ + cr_unit.buf = 0; + currCol = 1; + crb1 = 0; + crb2 = 0; + cdcc = 0; + cdba = 0; + cddb = 0; + cddbs = 0; + EOFcard = 0; + + /* start up the blower if the hopper is not empty + if (blowerState != BLOW_ON) { blowerState = BLOW_START; + sim_activate (uptr, spinUp); + } + */ return (SCPE_OK); } @@ -1236,42 +1681,56 @@ t_stat cr_set_stop ( UNIT *uptr, fprintf (sim_deb, "set_stop\n"); crs &= ~CRCSR_ONLINE; crs |= CSR_ERR | CRCSR_OFFLINE; - cdst |= CDCSR_OFFLINE; + cdst |= CSR_ERR | CDCSR_OFFLINE; /* CD11 does not appear to interrupt on STOP. */ - if (crs & CSR_IE) + if (CR11_CTL(uptr) && (crs & CSR_IE)) SET_INT (CR); if (blowerState != BLOW_OFF) { blowerState = BLOW_STOP; - /* set timer to turn it off completely */ - sim_activate (uptr, spinDown); } return (SCPE_OK); } -static const char * const trans[] = { - "unknown", "026", "026FTN", "029", "EBCDIC" -}; +/* simulate pressing the card reader EOF button */ + +t_stat cr_set_eof ( UNIT *uptr, + int32 val, + char *cptr, + void *desc ) +{ + if (DEBUG_PRS (cr_dev)) + fprintf (sim_deb, "set_eof\n"); + eofPending = 1; + + return (SCPE_OK); +} + +t_stat cr_show_eof ( FILE *st, + UNIT *uptr, + int32 val, + void *desc ) +{ + fprintf (st, (eofPending? "EOF pending": "no EOF pending")); + return (SCPE_OK); +} t_stat cr_set_trans ( UNIT *uptr, int32 val, char *cptr, void *desc ) { - int i; + size_t i; if (!cptr) return (SCPE_MISVAL); - if (strcmp (cptr, "DEFAULT") == 0) - i = 3; - else { - for (i = 1; i < 5; i++) { - if (strcmp (cptr, trans[i]) == 0) - break; - } + + for (i = 0; i < NTRANS; i++) { + if (strcmp (cptr, transcodes[i].name) == 0) + break; } - if (i < 1 || i > 4) + if (i >= NTRANS) return (SCPE_ARG); - table = i; + codeTbl = transcodes[i].table; initTranslation (); /* reinitialize tables */ return (SCPE_OK); } @@ -1281,6 +1740,13 @@ t_stat cr_show_trans ( FILE *st, int32 val, void *desc ) { - fprintf (st, "translation %s", trans[table]); + size_t i; + + for (i = 1; i < NTRANS; i++ ) + if (transcodes[i].table == codeTbl) { + fprintf (st, "translation=%s", transcodes[i].name); + return SCPE_OK; + } + fprintf (st, "translation=%s", transcodes[0].name); return (SCPE_OK); } diff --git a/PDP11/pdp11_cr_dat.h b/PDP11/pdp11_cr_dat.h index 18aaa4d1..2dce182a 100644 --- a/PDP11/pdp11_cr_dat.h +++ b/PDP11/pdp11_cr_dat.h @@ -10,14 +10,16 @@ * * author: Douglas Jones, jones@cs.uiowa.edu * revisions: - * March 5, 1996 - * Feb 18, 1997 to add 026 and EBCDIC converstion tables - * Jan 10, 2005, (JAD) Added 'static const' to the array - * definitions. - * Jan 11, 2005, (JAD) Create the h2c_code array. - * Jan 14, 2005, (JAD) Added the special DEC code for 'end of deck' - * (12-11-0-1-6-7-8-9) to the o29_code array at position 26. (^Z). - * Should I add this to the other arrays? + * March 5, 1996 + * Feb 18, 1997 to add 026 and EBCDIC converstion tables + * Jan 10, 2005, (JAD) Added 'static const' to the array + * definitions. + * Jan 11, 2005, (JAD) Create the h2c_code array. + * Jan 14, 2005, (JAD) Added the special DEC code for 'end of deck' + * (12-11-0-1-6-7-8-9) to the o29_code array at position 26. (^Z). + * Should I add this to the other arrays? + * Feb 24, 2007, (JGP) Added the DEC version of the 026 codepage and + * fixed some DEC029 codes. */ /* DEC's version of the IBM 029 kepunch encoding, (thus avoiding IBM's @@ -26,597 +28,655 @@ translate lower case to upper case. As a result of this modification, inversion of this table should be done with care! */ static const int o29_code[] = { - ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR, /* control */ - ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR, /* chars */ - ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR, /* control */ - ERROR,ERROR,07417,ERROR,ERROR,ERROR,ERROR,ERROR, /* chars */ - 00000,02202,00006,00102,02102,01042,04000,00022, /* !"#$%&' */ - 04022,02022,02042,04012,01102,02000,04102,01400, /* ()*+,-./ */ - 01000,00400,00200,00100,00040,00020,00010,00004, /* 01234567 */ - 00002,00001,00202,02012,04042,00012,01012,01006, /* 89:;<=>? */ - 00042,04400,04200,04100,04040,04020,04010,04004, /* @ABCDEFG */ - 04002,04001,02400,02200,02100,02040,02020,02010, /* HIJKLMNO */ - 02004,02002,02001,01200,01100,01040,01020,01010, /* PQRSTUVW */ - 01004,01002,01001,04202,02006,01202,04006,01022, /* XYZ[\]^_ */ - ERROR,04400,04200,04100,04040,04020,04010,04004, /* `abcdefg */ - 04002,04001,02400,02200,02100,02040,02020,02010, /* hijklmno */ - 02004,02002,02001,01200,01100,01040,01020,01010, /* pqrstuvw */ - 01004,01002,01001,ERROR,ERROR,ERROR,ERROR,ERROR /* xyz{|}~ */ - }; + ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR, /* control */ + ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR, /* chars */ + ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR, /* control */ + ERROR,ERROR,07417,ERROR,ERROR,ERROR,ERROR,ERROR, /* chars */ + 00000,04006,00006,00102,02102,01042,04000,00022, /* !"#$%&' */ + 04022,02022,02042,04012,01102,02000,04102,01400, /* ()*+,-./ */ + 01000,00400,00200,00100,00040,00020,00010,00004, /* 01234567 */ + 00002,00001,00202,02012,04042,00012,01012,01006, /* 89:;<=>? */ + 00042,04400,04200,04100,04040,04020,04010,04004, /* @ABCDEFG */ + 04002,04001,02400,02200,02100,02040,02020,02010, /* HIJKLMNO */ + 02004,02002,02001,01200,01100,01040,01020,01010, /* PQRSTUVW */ + 01004,01002,01001,04202,02006,02202,04006,01022, /* XYZ[\]^_ */ + ERROR,04400,04200,04100,04040,04020,04010,04004, /* `abcdefg */ + 04002,04001,02400,02200,02100,02040,02020,02010, /* hijklmno */ + 02004,02002,02001,01200,01100,01040,01020,01010, /* pqrstuvw */ + 01004,01002,01001,04000,ERROR,02000,ERROR,ERROR /* xyz{|}~ */ + }; /* Bare bones 026 kepunch encodings */ static const int o26_ftn_code[] = { - ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR, /* control */ - ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR, /* chars */ - ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR, /* control */ - ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR, /* chars */ - 00000,ERROR,ERROR,ERROR,02102,ERROR,ERROR,00042, /* !"#$%&' */ - 01042,04042,02042,04000,01102,02000,04102,01400, /* ()*+,-./ */ - 01000,00400,00200,00100,00040,00020,00010,00004, /* 01234567 */ - 00002,00001,ERROR,ERROR,ERROR,00102,ERROR,ERROR, /* 89:;<=>? */ - ERROR,04400,04200,04100,04040,04020,04010,04004, /* @ABCDEFG */ - 04002,04001,02400,02200,02100,02040,02020,02010, /* HIJKLMNO */ - 02004,02002,02001,01200,01100,01040,01020,01010, /* PQRSTUVW */ - 01004,01002,01001,ERROR,ERROR,ERROR,ERROR,ERROR, /* XYZ[\]^_ */ - ERROR,04400,04200,04100,04040,04020,04010,04004, /* `abcdefg */ - 04002,04001,02400,02200,02100,02040,02020,02010, /* hijklmno */ - 02004,02002,02001,01200,01100,01040,01020,01010, /* pqrstuvw */ - 01004,01002,01001,ERROR,ERROR,ERROR,ERROR,ERROR /* xyz{|}~ */ - }; + ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR, /* control */ + ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR, /* chars */ + ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR, /* control */ + ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR, /* chars */ + 00000,ERROR,ERROR,ERROR,02102,ERROR,ERROR,00042, /* !"#$%&' */ + 01042,04042,02042,04000,01102,02000,04102,01400, /* ()*+,-./ */ + 01000,00400,00200,00100,00040,00020,00010,00004, /* 01234567 */ + 00002,00001,ERROR,ERROR,ERROR,00102,ERROR,ERROR, /* 89:;<=>? */ + ERROR,04400,04200,04100,04040,04020,04010,04004, /* @ABCDEFG */ + 04002,04001,02400,02200,02100,02040,02020,02010, /* HIJKLMNO */ + 02004,02002,02001,01200,01100,01040,01020,01010, /* PQRSTUVW */ + 01004,01002,01001,ERROR,ERROR,ERROR,ERROR,ERROR, /* XYZ[\]^_ */ + ERROR,04400,04200,04100,04040,04020,04010,04004, /* `abcdefg */ + 04002,04001,02400,02200,02100,02040,02020,02010, /* hijklmno */ + 02004,02002,02001,01200,01100,01040,01020,01010, /* pqrstuvw */ + 01004,01002,01001,ERROR,ERROR,ERROR,ERROR,ERROR /* xyz{|}~ */ + }; static const int o26_comm_code[] = { - ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR, /* control */ - ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR, /* chars */ - ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR, /* control */ - ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR, /* chars */ - 00000,ERROR,ERROR,00102,02102,01042,04000,ERROR, /* !"#$%&' */ - ERROR,ERROR,02042,ERROR,01102,02000,04102,01400, /* ()*+,-./ */ - 01000,00400,00200,00100,00040,00020,00010,00004, /* 01234567 */ - 00002,00001,ERROR,ERROR,04042,ERROR,ERROR,ERROR, /* 89:;<=>? */ - 00042,04400,04200,04100,04040,04020,04010,04004, /* @ABCDEFG */ - 04002,04001,02400,02200,02100,02040,02020,02010, /* HIJKLMNO */ - 02004,02002,02001,01200,01100,01040,01020,01010, /* PQRSTUVW */ - 01004,01002,01001,ERROR,ERROR,ERROR,ERROR,ERROR, /* XYZ[\]^_ */ - ERROR,04400,04200,04100,04040,04020,04010,04004, /* `abcdefg */ - 04002,04001,02400,02200,02100,02040,02020,02010, /* hijklmno */ - 02004,02002,02001,01200,01100,01040,01020,01010, /* pqrstuvw */ - 01004,01002,01001,ERROR,ERROR,ERROR,ERROR,ERROR /* xyz{|}~ */ - }; + ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR, /* control */ + ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR, /* chars */ + ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR, /* control */ + ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR, /* chars */ + 00000,ERROR,ERROR,00102,02102,01042,04000,ERROR, /* !"#$%&' */ + ERROR,ERROR,02042,ERROR,01102,02000,04102,01400, /* ()*+,-./ */ + 01000,00400,00200,00100,00040,00020,00010,00004, /* 01234567 */ + 00002,00001,ERROR,ERROR,04042,ERROR,ERROR,ERROR, /* 89:;<=>? */ + 00042,04400,04200,04100,04040,04020,04010,04004, /* @ABCDEFG */ + 04002,04001,02400,02200,02100,02040,02020,02010, /* HIJKLMNO */ + 02004,02002,02001,01200,01100,01040,01020,01010, /* PQRSTUVW */ + 01004,01002,01001,ERROR,ERROR,ERROR,ERROR,ERROR, /* XYZ[\]^_ */ + ERROR,04400,04200,04100,04040,04020,04010,04004, /* `abcdefg */ + 04002,04001,02400,02200,02100,02040,02020,02010, /* hijklmno */ + 02004,02002,02001,01200,01100,01040,01020,01010, /* pqrstuvw */ + 01004,01002,01001,ERROR,ERROR,ERROR,ERROR,ERROR /* xyz{|}~ */ + }; + +/* 026DEC translation, according to RSX-11M-PLUS and Micro/RSX */ +/* I/O Drivers Reference manual - AA-JS11A-TC */ +static const int o26_dec_code[] = { + ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR, /* control */ + ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR, /* chars */ + ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR, /* control */ + ERROR,ERROR,07417,ERROR,ERROR,ERROR,ERROR,ERROR, /* chars */ + 00000,04006,01022,01102,02102,01006,02006,00012, /* !"#$%&' */ + 01042,04042,02042,04000,01102,02000,04102,01400, /* ()*+,-./ */ + 01000,00400,00200,00100,00040,00020,00010,00004, /* 01234567 */ + 00002,00001,02202,01202,04012,00102,02012,04202, /* 89:;<=>? */ + 00042,04400,04200,04100,04040,04020,04010,04004, /* @ABCDEFG */ + 04002,04001,02400,02200,02100,02040,02020,02010, /* HIJKLMNO */ + 02004,02002,02001,01200,01100,01040,01020,01010, /* PQRSTUVW */ + 01004,01002,01001,02022,00006,04022,00022,00202, /* XYZ[\]^_ */ + ERROR,04400,04200,04100,04040,04020,04010,04004, /* `abcdefg */ + 04002,04001,02400,02200,02100,02040,02020,02010, /* hijklmno */ + 02004,02002,02001,01200,01100,01040,01020,01010, /* pqrstuvw */ + 01004,01002,01001,04000,ERROR,02000,ERROR,ERROR /* xyz{|}~ */ + }; /* FULL EBCDIC, from Appendix C of System 360 Programming by Alex Thomas, 1977, Reinhart Press, San Francisco. Codes not in that table have been left compatable with DEC's 029 table. Some control codes have been left out */ static const int EBCDIC_code[] = { - 05403,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR, /* control */ - 02011,04021,01021,ERROR,04041,02021,ERROR,ERROR, /* chars */ - ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR, /* control */ - ERROR,ERROR,ERROR,ERROR,01201,ERROR,ERROR,ERROR, /* chars */ - 00000,02202,00006,00102,02102,01042,04000,00022, /* !"#$%&' */ - 04022,02022,02042,04012,01102,02000,04102,01400, /* ()*+,-./ */ - 01000,00400,00200,00100,00040,00020,00010,00004, /* 01234567 */ - 00002,00001,00202,02012,04042,00012,01012,01006, /* 89:;<=>? */ - 00042,04400,04200,04100,04040,04020,04010,04004, /* @ABCDEFG */ - 04002,04001,02400,02200,02100,02040,02020,02010, /* HIJKLMNO */ - 02004,02002,02001,01200,01100,01040,01020,01010, /* PQRSTUVW */ - 01004,01002,01001,04202,02006,01202,04006,01022, /* XYZ[\]^_ */ - ERROR,05400,05200,05100,05040,05020,05010,05004, /* `abcdefg */ - 05002,05001,06400,06200,06100,06040,06020,06010, /* hijklmno */ - 06004,06002,06001,03200,03100,03040,03020,03010, /* pqrstuvw */ - 03004,03002,03001,ERROR,ERROR,ERROR,ERROR,ERROR /* xyz{|}~ */ - }; - -static const int h2c_code[4096] = { - 0000, 0020, 0010, 0030, 0007, 0027, 0017, 0037, - 0006, 0026, 0016, 0036, 0007, 0027, 0017, 0037, - 0005, 0025, 0015, 0035, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0004, 0024, 0014, 0034, 0007, 0027, 0017, 0037, - 0006, 0026, 0016, 0036, 0007, 0027, 0017, 0037, - 0005, 0025, 0015, 0035, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0003, 0023, 0013, 0033, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0002, 0022, 0012, 0032, 0007, 0027, 0017, 0037, - 0006, 0026, 0016, 0036, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0006, 0026, 0016, 0036, 0007, 0027, 0017, 0037, - 0006, 0026, 0016, 0036, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0003, 0023, 0013, 0033, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0001, 0021, 0011, 0031, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0005, 0025, 0015, 0035, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0005, 0025, 0015, 0035, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0005, 0025, 0015, 0035, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0003, 0023, 0013, 0033, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0003, 0023, 0013, 0033, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0003, 0023, 0013, 0033, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0040, 0060, 0050, 0070, 0047, 0067, 0057, 0077, - 0046, 0066, 0056, 0076, 0047, 0067, 0057, 0077, - 0045, 0065, 0055, 0075, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0044, 0064, 0054, 0074, 0047, 0067, 0057, 0077, - 0046, 0066, 0056, 0076, 0047, 0067, 0057, 0077, - 0045, 0065, 0055, 0075, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0043, 0063, 0053, 0073, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0042, 0062, 0052, 0072, 0047, 0067, 0057, 0077, - 0046, 0066, 0056, 0076, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0046, 0066, 0056, 0076, 0047, 0067, 0057, 0077, - 0046, 0066, 0056, 0076, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0043, 0063, 0053, 0073, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0041, 0061, 0051, 0071, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0045, 0065, 0055, 0075, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0045, 0065, 0055, 0075, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0045, 0065, 0055, 0075, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0043, 0063, 0053, 0073, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0043, 0063, 0053, 0073, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0043, 0063, 0053, 0073, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0100, 0120, 0110, 0130, 0107, 0127, 0117, 0137, - 0106, 0126, 0116, 0136, 0107, 0127, 0117, 0137, - 0105, 0125, 0115, 0135, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0104, 0124, 0114, 0134, 0107, 0127, 0117, 0137, - 0106, 0126, 0116, 0136, 0107, 0127, 0117, 0137, - 0105, 0125, 0115, 0135, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0103, 0123, 0113, 0133, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0102, 0122, 0112, 0132, 0107, 0127, 0117, 0137, - 0106, 0126, 0116, 0136, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0106, 0126, 0116, 0136, 0107, 0127, 0117, 0137, - 0106, 0126, 0116, 0136, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0103, 0123, 0113, 0133, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0101, 0121, 0111, 0131, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0105, 0125, 0115, 0135, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0105, 0125, 0115, 0135, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0105, 0125, 0115, 0135, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0103, 0123, 0113, 0133, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0103, 0123, 0113, 0133, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0103, 0123, 0113, 0133, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0140, 0160, 0150, 0170, 0147, 0167, 0157, 0177, - 0146, 0166, 0156, 0176, 0147, 0167, 0157, 0177, - 0145, 0165, 0155, 0175, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0144, 0164, 0154, 0174, 0147, 0167, 0157, 0177, - 0146, 0166, 0156, 0176, 0147, 0167, 0157, 0177, - 0145, 0165, 0155, 0175, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0143, 0163, 0153, 0173, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0142, 0162, 0152, 0172, 0147, 0167, 0157, 0177, - 0146, 0166, 0156, 0176, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0146, 0166, 0156, 0176, 0147, 0167, 0157, 0177, - 0146, 0166, 0156, 0176, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0143, 0163, 0153, 0173, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0141, 0161, 0151, 0171, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0145, 0165, 0155, 0175, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0145, 0165, 0155, 0175, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0145, 0165, 0155, 0175, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0143, 0163, 0153, 0173, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0143, 0163, 0153, 0173, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0143, 0163, 0153, 0173, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0200, 0220, 0210, 0230, 0207, 0227, 0217, 0237, - 0206, 0226, 0216, 0236, 0207, 0227, 0217, 0237, - 0205, 0225, 0215, 0235, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0204, 0224, 0214, 0234, 0207, 0227, 0217, 0237, - 0206, 0226, 0216, 0236, 0207, 0227, 0217, 0237, - 0205, 0225, 0215, 0235, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0203, 0223, 0213, 0233, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0202, 0222, 0212, 0232, 0207, 0227, 0217, 0237, - 0206, 0226, 0216, 0236, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0206, 0226, 0216, 0236, 0207, 0227, 0217, 0237, - 0206, 0226, 0216, 0236, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0203, 0223, 0213, 0233, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0201, 0221, 0211, 0231, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0205, 0225, 0215, 0235, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0205, 0225, 0215, 0235, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0205, 0225, 0215, 0235, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0203, 0223, 0213, 0233, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0203, 0223, 0213, 0233, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0203, 0223, 0213, 0233, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0240, 0260, 0250, 0270, 0247, 0267, 0257, 0277, - 0246, 0266, 0256, 0276, 0247, 0267, 0257, 0277, - 0245, 0265, 0255, 0275, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0244, 0264, 0254, 0274, 0247, 0267, 0257, 0277, - 0246, 0266, 0256, 0276, 0247, 0267, 0257, 0277, - 0245, 0265, 0255, 0275, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0243, 0263, 0253, 0273, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0242, 0262, 0252, 0272, 0247, 0267, 0257, 0277, - 0246, 0266, 0256, 0276, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0246, 0266, 0256, 0276, 0247, 0267, 0257, 0277, - 0246, 0266, 0256, 0276, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0243, 0263, 0253, 0273, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0241, 0261, 0251, 0271, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0245, 0265, 0255, 0275, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0245, 0265, 0255, 0275, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0245, 0265, 0255, 0275, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0243, 0263, 0253, 0273, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0243, 0263, 0253, 0273, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0243, 0263, 0253, 0273, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0300, 0320, 0310, 0330, 0307, 0327, 0317, 0337, - 0306, 0326, 0316, 0336, 0307, 0327, 0317, 0337, - 0305, 0325, 0315, 0335, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0304, 0324, 0314, 0334, 0307, 0327, 0317, 0337, - 0306, 0326, 0316, 0336, 0307, 0327, 0317, 0337, - 0305, 0325, 0315, 0335, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0303, 0323, 0313, 0333, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0302, 0322, 0312, 0332, 0307, 0327, 0317, 0337, - 0306, 0326, 0316, 0336, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0306, 0326, 0316, 0336, 0307, 0327, 0317, 0337, - 0306, 0326, 0316, 0336, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0303, 0323, 0313, 0333, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0301, 0321, 0311, 0331, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0305, 0325, 0315, 0335, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0305, 0325, 0315, 0335, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0305, 0325, 0315, 0335, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0303, 0323, 0313, 0333, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0303, 0323, 0313, 0333, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0303, 0323, 0313, 0333, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0340, 0360, 0350, 0370, 0347, 0367, 0357, 0377, - 0346, 0366, 0356, 0376, 0347, 0367, 0357, 0377, - 0345, 0365, 0355, 0375, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0344, 0364, 0354, 0374, 0347, 0367, 0357, 0377, - 0346, 0366, 0356, 0376, 0347, 0367, 0357, 0377, - 0345, 0365, 0355, 0375, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0343, 0363, 0353, 0373, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0342, 0362, 0352, 0372, 0347, 0367, 0357, 0377, - 0346, 0366, 0356, 0376, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0346, 0366, 0356, 0376, 0347, 0367, 0357, 0377, - 0346, 0366, 0356, 0376, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0343, 0363, 0353, 0373, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0341, 0361, 0351, 0371, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0345, 0365, 0355, 0375, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0345, 0365, 0355, 0375, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0345, 0365, 0355, 0375, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0343, 0363, 0353, 0373, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0343, 0363, 0353, 0373, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0343, 0363, 0353, 0373, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 05403,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR, /* control */ + 02011,04021,01021,ERROR,04041,02021,ERROR,ERROR, /* chars */ + ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR,ERROR, /* control */ + ERROR,ERROR,ERROR,ERROR,01201,ERROR,ERROR,ERROR, /* chars */ + 00000,02202,00006,00102,02102,01042,04000,00022, /* !"#$%&' */ + 04022,02022,02042,04012,01102,02000,04102,01400, /* ()*+,-./ */ + 01000,00400,00200,00100,00040,00020,00010,00004, /* 01234567 */ + 00002,00001,00202,02012,04042,00012,01012,01006, /* 89:;<=>? */ + 00042,04400,04200,04100,04040,04020,04010,04004, /* @ABCDEFG */ + 04002,04001,02400,02200,02100,02040,02020,02010, /* HIJKLMNO */ + 02004,02002,02001,01200,01100,01040,01020,01010, /* PQRSTUVW */ + 01004,01002,01001,04202,02006,01202,04006,01022, /* XYZ[\]^_ */ + ERROR,05400,05200,05100,05040,05020,05010,05004, /* `abcdefg */ + 05002,05001,06400,06200,06100,06040,06020,06010, /* hijklmno */ + 06004,06002,06001,03200,03100,03040,03020,03010, /* pqrstuvw */ + 03004,03002,03001,ERROR,ERROR,ERROR,ERROR,ERROR /* xyz{|}~ */ + }; +/* DEC's 026 code extended to full 7-bit ASCII, as used in the DECsystem-10. */ +static const int o26_decascii_code[] = { + 05403, 04401, 04201, 04101, 00005, 01023, 01013, 01007, + 02011, 04021, 01021, 04103, 04043, 04023, 04013, 04007, + 06403, 02401, 02201, 02101, 00043, 00023, 00201, 01011, + 02003, 02403, 00007, 01005, 02043, 02023, 02013, 02007, + 00000, 04006, 01022, 01012, 02102, 01006, 02006, 00012, + 01042, 04042, 02042, 04000, 01102, 02000, 04102, 01400, + 01000, 00400, 00200, 00100, 00040, 00020, 00010, 00004, + 00002, 00001, 02202, 01202, 04012, 00102, 02012, 04202, + 00042, 04400, 04200, 04100, 04040, 04020, 04010, 04004, + 04002, 04001, 02400, 02200, 02100, 02040, 02020, 02010, + 02004, 02002, 02001, 01200, 01100, 01040, 01020, 01010, + 01004, 01002, 01001, 02022, 00006, 04022, 00022, 00202, + 00402, 05400, 05200, 05100, 05040, 05020, 05010, 05004, + 05002, 05001, 06400, 06200, 06100, 06040, 06020, 06010, + 06004, 06002, 06001, 03200, 03100, 03040, 03020, 03010, + 03004, 03002, 03001, 05000, 06000, 03000, 03400, 04005, +}; +/* DEC's 029 code extended to full 7-bit ASCII, as used in the DECsystem-10. */ +static const int o29_decascii_code[] = { + 05403, 04401, 04201, 04101, 00005, 01023, 01013, 01007, + 02011, 04021, 01021, 04103, 04043, 04023, 04013, 04007, + 06403, 02401, 02201, 02101, 00043, 00023, 00201, 01011, + 02003, 02403, 00007, 01005, 02043, 02023, 02013, 02007, + 00000, 04006, 00006, 00102, 02102, 01042, 04000, 00022, + 04022, 02022, 02042, 04012, 01102, 02000, 04102, 01400, + 01000, 00400, 00200, 00100, 00040, 00020, 00010, 00004, + 00002, 00001, 00202, 02012, 04042, 00012, 01012, 01006, + 00042, 04400, 04200, 04100, 04040, 04020, 04010, 04004, + 04002, 04001, 02400, 02200, 02100, 02040, 02020, 02010, + 02004, 02002, 02001, 01200, 01100, 01040, 01020, 01010, + 01004, 01002, 01001, 04202, 01202, 02202, 02006, 01022, + 00402, 05400, 05200, 05100, 05040, 05020, 05010, 05004, + 05002, 05001, 06400, 06200, 06100, 06040, 06020, 06010, + 06004, 06002, 06001, 03200, 03100, 03040, 03020, 03010, + 03004, 03002, 03001, 05000, 06000, 03000, 03400, 04005, +}; +static const int h2c_code[4096] = { + 0000, 0020, 0010, 0030, 0007, 0027, 0017, 0037, + 0006, 0026, 0016, 0036, 0007, 0027, 0017, 0037, + 0005, 0025, 0015, 0035, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0004, 0024, 0014, 0034, 0007, 0027, 0017, 0037, + 0006, 0026, 0016, 0036, 0007, 0027, 0017, 0037, + 0005, 0025, 0015, 0035, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0003, 0023, 0013, 0033, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0002, 0022, 0012, 0032, 0007, 0027, 0017, 0037, + 0006, 0026, 0016, 0036, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0006, 0026, 0016, 0036, 0007, 0027, 0017, 0037, + 0006, 0026, 0016, 0036, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0003, 0023, 0013, 0033, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0001, 0021, 0011, 0031, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0005, 0025, 0015, 0035, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0005, 0025, 0015, 0035, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0005, 0025, 0015, 0035, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0003, 0023, 0013, 0033, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0003, 0023, 0013, 0033, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0003, 0023, 0013, 0033, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, + 0040, 0060, 0050, 0070, 0047, 0067, 0057, 0077, + 0046, 0066, 0056, 0076, 0047, 0067, 0057, 0077, + 0045, 0065, 0055, 0075, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0044, 0064, 0054, 0074, 0047, 0067, 0057, 0077, + 0046, 0066, 0056, 0076, 0047, 0067, 0057, 0077, + 0045, 0065, 0055, 0075, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0043, 0063, 0053, 0073, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0042, 0062, 0052, 0072, 0047, 0067, 0057, 0077, + 0046, 0066, 0056, 0076, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0046, 0066, 0056, 0076, 0047, 0067, 0057, 0077, + 0046, 0066, 0056, 0076, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0043, 0063, 0053, 0073, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0041, 0061, 0051, 0071, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0045, 0065, 0055, 0075, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0045, 0065, 0055, 0075, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0045, 0065, 0055, 0075, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0043, 0063, 0053, 0073, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0043, 0063, 0053, 0073, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0043, 0063, 0053, 0073, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, + 0100, 0120, 0110, 0130, 0107, 0127, 0117, 0137, + 0106, 0126, 0116, 0136, 0107, 0127, 0117, 0137, + 0105, 0125, 0115, 0135, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0104, 0124, 0114, 0134, 0107, 0127, 0117, 0137, + 0106, 0126, 0116, 0136, 0107, 0127, 0117, 0137, + 0105, 0125, 0115, 0135, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0103, 0123, 0113, 0133, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0102, 0122, 0112, 0132, 0107, 0127, 0117, 0137, + 0106, 0126, 0116, 0136, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0106, 0126, 0116, 0136, 0107, 0127, 0117, 0137, + 0106, 0126, 0116, 0136, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0103, 0123, 0113, 0133, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0101, 0121, 0111, 0131, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0105, 0125, 0115, 0135, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0105, 0125, 0115, 0135, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0105, 0125, 0115, 0135, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0103, 0123, 0113, 0133, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0103, 0123, 0113, 0133, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0103, 0123, 0113, 0133, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, + 0140, 0160, 0150, 0170, 0147, 0167, 0157, 0177, + 0146, 0166, 0156, 0176, 0147, 0167, 0157, 0177, + 0145, 0165, 0155, 0175, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0144, 0164, 0154, 0174, 0147, 0167, 0157, 0177, + 0146, 0166, 0156, 0176, 0147, 0167, 0157, 0177, + 0145, 0165, 0155, 0175, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0143, 0163, 0153, 0173, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0142, 0162, 0152, 0172, 0147, 0167, 0157, 0177, + 0146, 0166, 0156, 0176, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0146, 0166, 0156, 0176, 0147, 0167, 0157, 0177, + 0146, 0166, 0156, 0176, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0143, 0163, 0153, 0173, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0141, 0161, 0151, 0171, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0145, 0165, 0155, 0175, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0145, 0165, 0155, 0175, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0145, 0165, 0155, 0175, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0143, 0163, 0153, 0173, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0143, 0163, 0153, 0173, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0143, 0163, 0153, 0173, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, + 0200, 0220, 0210, 0230, 0207, 0227, 0217, 0237, + 0206, 0226, 0216, 0236, 0207, 0227, 0217, 0237, + 0205, 0225, 0215, 0235, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0204, 0224, 0214, 0234, 0207, 0227, 0217, 0237, + 0206, 0226, 0216, 0236, 0207, 0227, 0217, 0237, + 0205, 0225, 0215, 0235, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0203, 0223, 0213, 0233, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0202, 0222, 0212, 0232, 0207, 0227, 0217, 0237, + 0206, 0226, 0216, 0236, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0206, 0226, 0216, 0236, 0207, 0227, 0217, 0237, + 0206, 0226, 0216, 0236, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0203, 0223, 0213, 0233, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0201, 0221, 0211, 0231, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0205, 0225, 0215, 0235, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0205, 0225, 0215, 0235, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0205, 0225, 0215, 0235, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0203, 0223, 0213, 0233, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0203, 0223, 0213, 0233, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0203, 0223, 0213, 0233, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, + 0240, 0260, 0250, 0270, 0247, 0267, 0257, 0277, + 0246, 0266, 0256, 0276, 0247, 0267, 0257, 0277, + 0245, 0265, 0255, 0275, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0244, 0264, 0254, 0274, 0247, 0267, 0257, 0277, + 0246, 0266, 0256, 0276, 0247, 0267, 0257, 0277, + 0245, 0265, 0255, 0275, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0243, 0263, 0253, 0273, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0242, 0262, 0252, 0272, 0247, 0267, 0257, 0277, + 0246, 0266, 0256, 0276, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0246, 0266, 0256, 0276, 0247, 0267, 0257, 0277, + 0246, 0266, 0256, 0276, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0243, 0263, 0253, 0273, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0241, 0261, 0251, 0271, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0245, 0265, 0255, 0275, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0245, 0265, 0255, 0275, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0245, 0265, 0255, 0275, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0243, 0263, 0253, 0273, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0243, 0263, 0253, 0273, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0243, 0263, 0253, 0273, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, + 0300, 0320, 0310, 0330, 0307, 0327, 0317, 0337, + 0306, 0326, 0316, 0336, 0307, 0327, 0317, 0337, + 0305, 0325, 0315, 0335, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0304, 0324, 0314, 0334, 0307, 0327, 0317, 0337, + 0306, 0326, 0316, 0336, 0307, 0327, 0317, 0337, + 0305, 0325, 0315, 0335, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0303, 0323, 0313, 0333, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0302, 0322, 0312, 0332, 0307, 0327, 0317, 0337, + 0306, 0326, 0316, 0336, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0306, 0326, 0316, 0336, 0307, 0327, 0317, 0337, + 0306, 0326, 0316, 0336, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0303, 0323, 0313, 0333, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0301, 0321, 0311, 0331, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0305, 0325, 0315, 0335, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0305, 0325, 0315, 0335, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0305, 0325, 0315, 0335, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0303, 0323, 0313, 0333, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0303, 0323, 0313, 0333, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0303, 0323, 0313, 0333, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, + 0340, 0360, 0350, 0370, 0347, 0367, 0357, 0377, + 0346, 0366, 0356, 0376, 0347, 0367, 0357, 0377, + 0345, 0365, 0355, 0375, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 0344, 0364, 0354, 0374, 0347, 0367, 0357, 0377, + 0346, 0366, 0356, 0376, 0347, 0367, 0357, 0377, + 0345, 0365, 0355, 0375, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 0343, 0363, 0353, 0373, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 0342, 0362, 0352, 0372, 0347, 0367, 0357, 0377, + 0346, 0366, 0356, 0376, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 0346, 0366, 0356, 0376, 0347, 0367, 0357, 0377, + 0346, 0366, 0356, 0376, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 0343, 0363, 0353, 0373, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 0341, 0361, 0351, 0371, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 0345, 0365, 0355, 0375, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 0345, 0365, 0355, 0375, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 0345, 0365, 0355, 0375, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 0343, 0363, 0353, 0373, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 0343, 0363, 0353, 0373, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 0343, 0363, 0353, 0373, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, + 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, }; diff --git a/PDP11/pdp11_dc.c b/PDP11/pdp11_dc.c index 15c40bf4..62a4c3fe 100644 --- a/PDP11/pdp11_dc.c +++ b/PDP11/pdp11_dc.c @@ -87,7 +87,7 @@ uint32 dci_ireq = 0; uint16 dco_csr[DCX_LINES] = { 0 }; /* control/status */ uint8 dco_buf[DCX_LINES] = { 0 }; uint32 dco_ireq = 0; -TMLN dcx_ldsc[DCX_LINES] = { 0 }; /* line descriptors */ +TMLN dcx_ldsc[DCX_LINES] = { {0} }; /* line descriptors */ TMXR dcx_desc = { DCX_LINES, 0, 0, dcx_ldsc }; /* mux descriptor */ static const uint8 odd_par[] = { @@ -154,7 +154,7 @@ DIB dci_dib = { 2, IVCL (DCI), VEC_DCI, { &dci_iack, &dco_iack } }; -UNIT dci_unit = { UDATA (&dci_svc, 0, 0), KBD_POLL_WAIT }; +UNIT dci_unit = { UDATA (&dci_svc, 0, 0), SERIAL_IN_WAIT }; REG dci_reg[] = { { BRDATA (BUF, dci_buf, DEV_RDX, 8, DCX_LINES) }, @@ -266,7 +266,7 @@ int32 ln = ((PA - dci_dib.ba) >> 3) & DCX_MASK; switch ((PA >> 1) & 03) { /* decode PA<2:1> */ case 00: /* dci csr */ - if (dci_csr[ln] & DCICSR_ALLERR) + if (dci_csr[ln] & DCICSR_ALLERR) dci_csr[ln] |= DCICSR_ERR; else dci_csr[ln] &= ~DCICSR_ERR; *data = dci_csr[ln] & DCICSR_RD; @@ -276,6 +276,7 @@ switch ((PA >> 1) & 03) { /* decode PA<2:1> */ case 01: /* dci buf */ dci_clr_int (ln); *data = dci_buf[ln]; + sim_activate_abs (&dci_unit, dci_unit.wait); return SCPE_OK; case 02: /* dco csr */ @@ -397,7 +398,7 @@ for (ln = 0; ln < DCX_LINES; ln++) { /* loop thru lines */ c = (c & 0177) | odd_par[c & 0177]; else if (dco_unit[ln].flags & DCX_EPAR) /* even parity */ c = (c & 0177) | (odd_par[c & 0177] ^ 0200); - dci_buf[ln] = c; + dci_buf[ln] = (uint8)c; if ((c & 0200) == odd_par[c & 0177]) /* odd par? */ dci_csr[ln] |= DCICSR_PAR; else dci_csr[ln] &= ~DCICSR_PAR; diff --git a/PDP11/pdp11_defs.h b/PDP11/pdp11_defs.h index 8bd0b974..2de2c95d 100644 --- a/PDP11/pdp11_defs.h +++ b/PDP11/pdp11_defs.h @@ -75,8 +75,8 @@ 10-Feb-01 RMS Added DECtape support */ -#ifndef _PDP11_DEFS_H -#define _PDP11_DEFS_H 0 +#ifndef PDP11_DEFS_H +#define PDP11_DEFS_H 0 #ifndef VM_PDP11 #define VM_PDP11 0 @@ -537,8 +537,8 @@ typedef struct pdp_dib DIB; #define IOLN_UBM (UBM_LNT_LW * sizeof (int32)) #define IOBA_RS (IOPAGEBASE + 012040) /* RHC: RS03/RS04 */ #define IOLN_RS 040 -#define IOBA_KG (IOPAGEBASE + 010700) /* KG11-A */ -#define IOLN_KG 006 +#define IOBA_KG (IOPAGEBASE + 010700) /* KG11-A */ +#define IOLN_KG 006 #define IOBA_RQ (IOPAGEBASE + 012150) /* RQDX3 */ #define IOLN_RQ 004 #define IOBA_SUP (IOPAGEBASE + 012200) /* supervisor APR's */ diff --git a/PDP11/pdp11_dl.c b/PDP11/pdp11_dl.c index f6b500dc..4e2646c2 100644 --- a/PDP11/pdp11_dl.c +++ b/PDP11/pdp11_dl.c @@ -88,7 +88,7 @@ uint32 dli_ireq[2] = { 0, 0}; uint16 dlo_csr[DLX_LINES] = { 0 }; /* control/status */ uint8 dlo_buf[DLX_LINES] = { 0 }; uint32 dlo_ireq = 0; -TMLN dlx_ldsc[DLX_LINES] = { 0 }; /* line descriptors */ +TMLN dlx_ldsc[DLX_LINES] = { {0} }; /* line descriptors */ TMXR dlx_desc = { DLX_LINES, 0, 0, dlx_ldsc }; /* mux descriptor */ t_stat dlx_rd (int32 *data, int32 PA, int32 access); @@ -120,11 +120,12 @@ DIB dli_dib = { 2, IVCL (DLI), VEC_DLI, { &dli_iack, &dlo_iack } }; -UNIT dli_unit = { UDATA (&dli_svc, 0, 0), KBD_POLL_WAIT }; +UNIT dli_unit = { UDATA (&dli_svc, 0, 0), SERIAL_IN_WAIT }; REG dli_reg[] = { { BRDATA (BUF, dli_buf, DEV_RDX, 16, DLX_LINES) }, { BRDATA (CSR, dli_csr, DEV_RDX, 16, DLX_LINES) }, + { DRDATA (TIME, dli_unit.wait, 24), PV_LEFT }, { GRDATA (IREQ, dli_ireq[DLI_RCI], DEV_RDX, DLX_LINES, 0) }, { GRDATA (DSI, dli_ireq[DLI_DSI], DEV_RDX, DLX_LINES, 0) }, { DRDATA (LINES, dlx_desc.lines, 6), REG_HRO }, @@ -240,6 +241,7 @@ switch ((PA >> 1) & 03) { /* decode PA<2:1> */ *data = dli_buf[ln] & DLIBUF_RD; dli_csr[ln] &= ~CSR_DONE; /* clr rcv done */ dli_clr_int (ln, DLI_RCI); /* clr rcv int req */ + sim_activate_abs (&dli_unit, dli_unit.wait); return SCPE_OK; case 02: /* tto csr */ @@ -347,7 +349,7 @@ if (ln >= 0) { /* got one? rcv enb */ tmxr_poll_rx (&dlx_desc); /* poll for input */ for (ln = 0; ln < DLX_LINES; ln++) { /* loop thru lines */ if (dlx_ldsc[ln].conn) { /* connected? */ - if (temp = tmxr_getc_ln (&dlx_ldsc[ln])) { /* get char */ + if ((temp = tmxr_getc_ln (&dlx_ldsc[ln]))) { /* get char */ if (temp & SCPE_BREAK) /* break? */ c = DLIBUF_ERR|DLIBUF_RBRK; else c = sim_tt_inpcvt (temp, TT_GET_MODE (dlo_unit[ln].flags)); @@ -356,7 +358,7 @@ for (ln = 0; ln < DLX_LINES; ln++) { /* loop thru lines */ else dli_csr[ln] |= CSR_DONE; if (dli_csr[ln] & CSR_IE) dli_set_int (ln, DLI_RCI); - dli_buf[ln] = c; + dli_buf[ln] = (uint16)c; } } else if (dlo_unit[ln].flags & DLX_MDM) { /* discpnn & modem? */ diff --git a/PDP11/pdp11_fp.c b/PDP11/pdp11_fp.c index 1f0c98a6..1526c305 100644 --- a/PDP11/pdp11_fp.c +++ b/PDP11/pdp11_fp.c @@ -461,7 +461,7 @@ switch ((IR >> 8) & 017) { /* decode IR<11:8> */ else fac.l = ReadI (GeteaFP (dstspec, leni), dstspec, leni); fac.h = 0; if (fac.l) { - if (sign = GET_SIGN_L (fac.l)) + if ((sign = GET_SIGN_L (fac.l))) fac.l = (fac.l ^ 0xFFFFFFFF) + 1; for (i = 0; GET_SIGN_L (fac.l) == 0; i++) fac.l = fac.l << 1; diff --git a/PDP11/pdp11_hk.c b/PDP11/pdp11_hk.c index 647f18d7..03c6e7c5 100644 --- a/PDP11/pdp11_hk.c +++ b/PDP11/pdp11_hk.c @@ -177,7 +177,7 @@ extern uint16 *M; #define CS2_MBZ (CS2_CLR) #define CS2_RW 0000037 #define CS2_ERR (CS2_UFE | CS2_MDS | CS2_PGE | CS2_NEM | \ - CS2_NED | CS2_PE | CS2_WCE | CS2_DLT ) + CS2_NED | CS2_PE | CS2_WCE | CS2_DLT ) #define GET_UNIT(x) (((x) >> CS2_V_UNIT) & CS2_M_UNIT) /* HKDS - 177452 - drive status ^ = calculated dynamically */ @@ -328,7 +328,6 @@ extern uint16 *M; #define HKDEB_RWR 004 /* reg writes */ extern int32 int_req[IPL_HLVL]; -extern FILE *sim_deb; uint16 *hkxb = NULL; /* xfer buffer */ int32 hkcs1 = 0; /* control/status 1 */ @@ -362,7 +361,6 @@ static const char* reg_name[] = { "HKDC", "spare", "HKDB", "HKMR", "HKEC1", "HKEC2", "HKMR2", "HKMR3" }; -DEVICE hk_dev; t_stat hk_rd (int32 *data, int32 PA, int32 access); t_stat hk_wr (int32 data, int32 PA, int32 access); t_stat hk_svc (UNIT *uptr); @@ -587,10 +585,8 @@ return SCPE_OK; t_stat hk_wr (int32 data, int32 PA, int32 access) { int32 drv, i, j; -UNIT *uptr; drv = GET_UNIT (hkcs2); /* get current unit */ -uptr = hk_dev.units + drv; /* get unit */ j = (PA >> 1) & 017; /* get reg offset */ if (reg_in_drive[j] && (hk_unit[drv].flags & UNIT_DIS)) { /* nx disk */ hk_err (CS1_ERR|CS1_DONE, CS2_NED, 0, drv); /* set err, stop op */ @@ -742,9 +738,9 @@ if (fnc_rdy[fnc] && sim_is_active (uptr)) /* need inactive? */ if (fnc_cyl[fnc] && /* need valid cyl */ ((GET_CY (hkdc) >= HK_CYL (uptr)) || /* bad cylinder */ (GET_SF (hkda) >= HK_NUMSF))) { /* bad surface */ - hk_err (CS1_ERR|CS1_DONE, 0, ER_SKI|ER_IAE, drv); /* set err, no op */ - return; - } + hk_err (CS1_ERR|CS1_DONE, 0, ER_SKI|ER_IAE, drv); /* set err, no op */ + return; + } hkcs1 = (hkcs1 | CS1_GO) & ~CS1_DONE; /* set go, clear done */ hkci = hkdi = hkei = 0; /* clear all intr */ @@ -1366,7 +1362,7 @@ static const uint16 boot_rom[] = { t_stat hk_boot (int32 unitno, DEVICE *dptr) { -int32 i; +size_t i; for (i = 0; i < BOOT_LEN; i++) M[(BOOT_START >> 1) + i] = boot_rom[i]; diff --git a/PDP11/pdp11_io.c b/PDP11/pdp11_io.c index d768662d..2a197622 100644 --- a/PDP11/pdp11_io.c +++ b/PDP11/pdp11_io.c @@ -60,8 +60,7 @@ extern int32 trap_req, ipl; extern int32 cpu_log; extern int32 autcon_enb; extern int32 uba_last; -extern FILE *sim_log; -extern DEVICE *sim_devices[], cpu_dev; +extern DEVICE cpu_dev; extern t_addr cpu_memsize; int32 calc_ints (int32 nipl, int32 trq); @@ -373,17 +372,17 @@ init_ubus_tab (); /* init Unibus tables */ init_mbus_tab (); /* init Massbus tables */ for (i = 0; i < 7; i++) /* seed PIRQ intr */ int_vec[i + 1][pirq_bit[i]] = VEC_PIRQ; -if (r = cpu_build_dib ()) /* build CPU entries */ +if ((r = cpu_build_dib ())) /* build CPU entries */ return r; for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { /* loop thru dev */ dibp = (DIB *) dptr->ctxt; /* get DIB */ if (dibp && !(dptr->flags & DEV_DIS)) { /* defined, enabled? */ if (dptr->flags & DEV_MBUS) { /* Massbus? */ - if (r = build_mbus_tab (dptr, dibp)) /* add to Mbus tab */ + if ((r = build_mbus_tab (dptr, dibp))) /* add to Mbus tab */ return r; } else { /* no, Unibus */ - if (r = build_ubus_tab (dptr, dibp)) /* add to Unibus tab */ + if ((r = build_ubus_tab (dptr, dibp))) /* add to Unibus tab */ return r; } } /* end if enabled */ diff --git a/PDP11/pdp11_io_lib.c b/PDP11/pdp11_io_lib.c index 7ca23fb9..82860d14 100644 --- a/PDP11/pdp11_io_lib.c +++ b/PDP11/pdp11_io_lib.c @@ -36,8 +36,6 @@ #include "sim_sock.h" #include "sim_tmxr.h" -extern FILE *sim_log; -extern DEVICE *sim_devices[]; extern int32 autcon_enb; extern int32 int_vec[IPL_HLVL][32]; extern int32 (*int_ack[IPL_HLVL][32])(void); @@ -104,6 +102,7 @@ t_stat show_addr (FILE *st, UNIT *uptr, int32 val, void *desc) { DEVICE *dptr; DIB *dibp; +uint32 radix = DEV_RDX; if (uptr == NULL) return SCPE_IERR; @@ -113,11 +112,25 @@ if (dptr == NULL) dibp = (DIB *) dptr->ctxt; if ((dibp == NULL) || (dibp->ba <= IOPAGEBASE)) return SCPE_IERR; +if (sim_switches & SWMASK ('H')) + radix = 16; +if (sim_switches & SWMASK ('O')) + radix = 8; fprintf (st, "address="); fprint_val (st, (t_value) dibp->ba, DEV_RDX, 32, PV_LEFT); +if (radix != DEV_RDX) { + fprintf (st, "("); + fprint_val (st, (t_value) dibp->ba, radix, 32, PV_LEFT); + fprintf (st, ")"); + } if (dibp->lnt > 1) { fprintf (st, "-"); fprint_val (st, (t_value) dibp->ba + dibp->lnt - 1, DEV_RDX, 32, PV_LEFT); + if (radix != DEV_RDX) { + fprintf (st, "("); + fprint_val (st, (t_value) dibp->ba + dibp->lnt - 1, radix, 32, PV_LEFT); + fprintf (st, ")"); + } } if (dptr->flags & DEV_FLTA) fprintf (st, "*"); @@ -177,7 +190,7 @@ t_stat show_vec (FILE *st, UNIT *uptr, int32 arg, void *desc) { DEVICE *dptr; DIB *dibp; -uint32 vec, numvec; +uint32 vec, numvec, radix = DEV_RDX; if (uptr == NULL) return SCPE_IERR; @@ -187,6 +200,10 @@ if (dptr == NULL) dibp = (DIB *) dptr->ctxt; if (dibp == NULL) return SCPE_IERR; +if (sim_switches & SWMASK ('H')) + radix = 16; +if (sim_switches & SWMASK ('O')) + radix = 8; vec = dibp->vec; if (arg) numvec = arg; @@ -196,9 +213,19 @@ if (vec == 0) else { fprintf (st, "vector="); fprint_val (st, (t_value) vec, DEV_RDX, 16, PV_LEFT); + if (radix != DEV_RDX) { + fprintf (st, "("); + fprint_val (st, (t_value) vec, radix, 16, PV_LEFT); + fprintf (st, ")"); + } if (numvec > 1) { fprintf (st, "-"); fprint_val (st, (t_value) vec + (4 * (numvec - 1)), DEV_RDX, 16, PV_LEFT); + if (radix != DEV_RDX) { + fprintf (st, "("); + fprint_val (st, (t_value) vec + (4 * (numvec - 1)), radix, 16, PV_LEFT); + fprintf (st, ")"); + } } } return SCPE_OK; @@ -219,7 +246,7 @@ return show_vec (st, uptr, ((mp->lines * 2) / arg), desc); void init_ubus_tab (void) { -int32 i, j; +size_t i, j; for (i = 0; i < IPL_HLVL; i++) { /* clear intr tab */ for (j = 0; j < 32; j++) { @@ -254,11 +281,8 @@ for (i = 0; i < dibp->vnum; i++) { /* loop thru vec */ (int_ack[ilvl][ibit] != dibp->ack[i])) || (int_vec[ilvl][ibit] && vec && (int_vec[ilvl][ibit] != vec))) { - printf ("Device %s interrupt slot conflict at %d\n", - sim_dname (dptr), idx); - if (sim_log) - fprintf (sim_log, "Device %s interrupt slot conflict at %d\n", - sim_dname (dptr), idx); + sim_printf ("Device %s interrupt slot conflict at %d\n", + sim_dname (dptr), idx); return SCPE_STOP; } if (dibp->ack[i]) diff --git a/PDP11/pdp11_io_lib.h b/PDP11/pdp11_io_lib.h index f12bbda0..80533ea2 100644 --- a/PDP11/pdp11_io_lib.h +++ b/PDP11/pdp11_io_lib.h @@ -24,8 +24,8 @@ in this Software without prior written authorization from Robert M Supnik. */ -#ifndef _PDP11_IO_LIB_H_ -#define _PDP11_IO_LIB_H_ 0 +#ifndef PDP11_IO_LIB_H_ +#define PDP11_IO_LIB_H_ 0 t_stat set_autocon (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat show_autocon (FILE *st, UNIT *uptr, int32 val, void *desc); diff --git a/PDP11/pdp11_ke.c b/PDP11/pdp11_ke.c index 711c1c30..d71e836f 100644 --- a/PDP11/pdp11_ke.c +++ b/PDP11/pdp11_ke.c @@ -38,13 +38,13 @@ /* KE11A I/O address offsets 0177300 - 0177316 */ #define KE_DIV 000 /* divide */ -#define KE_AC 002 /* accumulator */ -#define KE_MQ 004 /* MQ */ -#define KE_MUL 006 /* multiply */ -#define KE_SC 010 /* step counter */ -#define KE_NOR 012 /* normalize */ -#define KE_LSH 014 /* logical shift */ -#define KE_ASH 016 /* arithmetic shift */ +#define KE_AC 002 /* accumulator */ +#define KE_MQ 004 /* MQ */ +#define KE_MUL 006 /* multiply */ +#define KE_SC 010 /* step counter */ +#define KE_NOR 012 /* normalize */ +#define KE_LSH 014 /* logical shift */ +#define KE_ASH 016 /* arithmetic shift */ /* Status register */ @@ -65,7 +65,6 @@ uint32 ke_MQ = 0; uint32 ke_SC = 0; uint32 ke_SR = 0; -DEVICE ke_dev; t_stat ke_rd (int32 *data, int32 PA, int32 access); t_stat ke_wr (int32 data, int32 PA, int32 access); t_stat ke_reset (DEVICE *dptr); @@ -74,7 +73,7 @@ uint32 ke_set_SR (void); DIB ke_dib = { IOBA_KE, IOLN_KE, &ke_rd, &ke_wr, 0 }; UNIT ke_unit = { - UDATA (NULL, UNIT_DISABLE, 0) + UDATA (NULL, UNIT_DISABLE, 0) }; REG ke_reg[] = { @@ -235,9 +234,9 @@ switch (PA & 017) { /* decode PA<3:0> */ case KE_NOR: /* normalize */ for (ke_SC = 0; ke_SC < 31; ke_SC++) { /* max 31 shifts */ - if (((ke_AC == 0140000) && (ke_MQ == 0)) || /* special case? */ + if (((ke_AC == 0140000) && (ke_MQ == 0)) || /* special case? */ (GET_SIGN_W (ke_AC ^ (ke_AC << 1)))) /* AC<15> != AC<14>? */ - break; + break; ke_AC = ((ke_AC << 1) | (ke_MQ >> 15)) & DMASK; ke_MQ = (ke_MQ << 1) & DMASK; } @@ -252,7 +251,7 @@ switch (PA & 017) { /* decode PA<3:0> */ data = data & 077; /* 6b shift count */ if (data != 0) { t32 = (ke_AC << 16) | ke_MQ; /* 32b operand */ - if (sign = GET_SIGN_W (ke_AC)) /* sext operand */ + if ((sign = GET_SIGN_W (ke_AC))) /* sext operand */ t32 = t32 | ~017777777777; if (data < 32) { /* [1,31] - left */ sout = (t32 >> (32 - data)) | (-sign << data); @@ -282,7 +281,7 @@ switch (PA & 017) { /* decode PA<3:0> */ data = data & 077; /* 6b shift count */ if (data != 0) { t32 = (ke_AC << 16) | ke_MQ; /* 32b operand */ - if (sign = GET_SIGN_W (ke_AC)) /* sext operand */ + if ((sign = GET_SIGN_W (ke_AC))) /* sext operand */ t32 = t32 | ~017777777777; if (data < 32) { /* [1,31] - left */ sout = (t32 >> (31 - data)) | (-sign << data); diff --git a/PDP11/pdp11_kg.c b/PDP11/pdp11_kg.c index 6597250f..7fb2f75e 100644 --- a/PDP11/pdp11_kg.c +++ b/PDP11/pdp11_kg.c @@ -95,7 +95,6 @@ #endif #include "pdp11_defs.h" -extern FILE *sim_deb; extern REG cpu_reg[]; extern int32 R[]; @@ -459,7 +458,7 @@ static void do_poly (int unit, t_bool step) static t_stat set_units (UNIT *u, int32 val, char *s, void *desc) { - int32 i, units; + uint32 i, units; t_stat stat; if (s == NULL) @@ -467,6 +466,10 @@ static t_stat set_units (UNIT *u, int32 val, char *s, void *desc) units = get_uint (s, 10, KG_UNITS, &stat); if (stat != SCPE_OK) return (stat); + if (units == 0) + return SCPE_ARG; + if (units == kg_dev.numunits) + return SCPE_OK; for (i = 0; i < KG_UNITS; i++) { if (i < units) kg_unit[i].flags &= ~UNIT_DIS; @@ -474,5 +477,6 @@ static t_stat set_units (UNIT *u, int32 val, char *s, void *desc) kg_unit[i].flags |= UNIT_DIS; } kg_dev.numunits = units; + kg_reset (&kg_dev); return (SCPE_OK); } diff --git a/PDP11/pdp11_lp.c b/PDP11/pdp11_lp.c index c535daed..750b0f17 100644 --- a/PDP11/pdp11_lp.c +++ b/PDP11/pdp11_lp.c @@ -56,7 +56,6 @@ extern int32 int_req[IPL_HLVL]; int32 lpt_csr = 0; /* control/status */ int32 lpt_stopioe = 0; /* stop on error */ -DEVICE lpt_dev; t_stat lpt_rd (int32 *data, int32 PA, int32 access); t_stat lpt_wr (int32 data, int32 PA, int32 access); t_stat lpt_svc (UNIT *uptr); diff --git a/PDP11/pdp11_mscp.h b/PDP11/pdp11_mscp.h index 4e3c9698..224fdce0 100644 --- a/PDP11/pdp11_mscp.h +++ b/PDP11/pdp11_mscp.h @@ -24,12 +24,13 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 24-Oct-12 MB Added working map base address 09-Jan-03 RMS Tape read/write end pkt is longer than disk read/write 20-Sep-02 RMS Merged TMSCP definitions */ -#ifndef _PDP11_MSCP_H_ -#define _PDP11_MSCP_H_ 0 +#ifndef PDP11_MSCP_H_ +#define PDP11_MSCP_H_ 0 /* Misc constants */ @@ -84,6 +85,7 @@ #define MD_ACL 0x0002 /* t avl: all class NI */ #define MD_NXU 0x0001 /* b gus: next unit */ #define MD_RIP 0x0001 /* d onl: allow rip NI */ +#define MD_SPD 0x0001 /* d avl: spin-down */ /* End flags */ @@ -210,7 +212,7 @@ #define CMD_REFL 2 /* ref # */ #define CMD_REFH 3 #define CMD_UN 4 /* unit # */ -/* 5 /* reserved */ +/* 5 *//* reserved */ #define CMD_OPC 6 /* opcode */ #define CMD_MOD 7 /* modifier */ @@ -255,14 +257,14 @@ /* Flush - 10 W status (8 undefined) */ #define FLU_LNT 32 -/* 8 - 15 /* reserved */ +/* 8 - 15 *//* reserved */ #define FLU_POSL 16 /* position */ #define FLU_POSH 17 /* Write tape mark - 10W status (8 undefined) */ #define WTM_LNT 32 -/* 8 - 15 /* reserved */ +/* 8 - 15 *//* reserved */ #define WTM_POSL 16 /* position */ #define WTM_POSH 17 @@ -398,8 +400,8 @@ #define RW_BAH 11 #define RW_MAPL 12 /* map table */ #define RW_MAPH 13 -/* 14 /* reserved */ -/* 15 /* reserved */ +/* 14 *//* reserved */ +/* 15 *//* reserved */ /* Disk specific parameters */ @@ -411,6 +413,8 @@ #define RW_WBAH 21 #define RW_WBLL 22 /* working lbn */ #define RW_WBLH 23 +#define RW_WMPL 24 /* working map */ +#define RW_WMPH 25 /* Tape specific status */ diff --git a/PDP11/pdp11_pclk.c b/PDP11/pdp11_pclk.c index f83f5e83..d8fc48ed 100644 --- a/PDP11/pdp11_pclk.c +++ b/PDP11/pdp11_pclk.c @@ -136,7 +136,6 @@ uint32 pclk_ctr = 0; /* counter */ static uint32 rate[4] = { 100000, 10000, 60, 10 }; /* ticks per second */ static uint32 xtim[4] = { 10, 100, 16667, 100000 }; /* nominal time delay */ -DEVICE pclk_dev; t_stat pclk_rd (int32 *data, int32 PA, int32 access); t_stat pclk_wr (int32 data, int32 PA, int32 access); t_stat pclk_svc (UNIT *uptr); diff --git a/PDP11/pdp11_pt.c b/PDP11/pdp11_pt.c index 62a6d46d..6281bfcc 100644 --- a/PDP11/pdp11_pt.c +++ b/PDP11/pdp11_pt.c @@ -58,7 +58,6 @@ int32 ptr_stopioe = 0; /* stop on error */ int32 ptp_csr = 0; /* control/status */ int32 ptp_stopioe = 0; /* stop on error */ -DEVICE ptr_dev, ptp_dev; t_stat ptr_rd (int32 *data, int32 PA, int32 access); t_stat ptr_wr (int32 data, int32 PA, int32 access); t_stat ptr_svc (UNIT *uptr); @@ -100,7 +99,8 @@ REG ptr_reg[] = { { DRDATA (POS, ptr_unit.pos, T_ADDR_W), PV_LEFT }, { DRDATA (TIME, ptr_unit.wait, 24), PV_LEFT }, { FLDATA (STOP_IOE, ptr_stopioe, 0) }, - { FLDATA (DEVDIS, ptr_dev.flags, DEV_V_DIS), REG_HRO }, + { GRDATA (DEVADDR, ptr_dib.ba, DEV_RDX, 32, 0), REG_HRO }, + { GRDATA (DEVVEC, ptr_dib.vec, DEV_RDX, 16, 0), REG_HRO }, { NULL } }; @@ -146,6 +146,8 @@ REG ptp_reg[] = { { DRDATA (POS, ptp_unit.pos, T_ADDR_W), PV_LEFT }, { DRDATA (TIME, ptp_unit.wait, 24), PV_LEFT }, { FLDATA (STOP_IOE, ptp_stopioe, 0) }, + { GRDATA (DEVADDR, ptp_dib.ba, DEV_RDX, 32, 0), REG_HRO }, + { GRDATA (DEVVEC, ptp_dib.vec, DEV_RDX, 16, 0), REG_HRO }, { NULL } }; @@ -226,7 +228,7 @@ if ((ptr_unit.flags & UNIT_ATT) == 0) if ((temp = getc (ptr_unit.fileref)) == EOF) { if (feof (ptr_unit.fileref)) { if (ptr_stopioe) - printf ("PTR end of file\n"); + sim_printf ("PTR end of file\n"); else return SCPE_OK; } else perror ("PTR I/O error"); diff --git a/PDP11/pdp11_rc.c b/PDP11/pdp11_rc.c index ec14279a..ec125acf 100644 --- a/PDP11/pdp11_rc.c +++ b/PDP11/pdp11_rc.c @@ -148,7 +148,6 @@ ((double) RC_NUMWD))) extern int32 int_req[IPL_HLVL]; -extern FILE *sim_deb; extern int32 R[]; static uint32 rc_la = 0; /* look-ahead */ @@ -165,7 +164,6 @@ static uint32 rc_stopioe = 1; /* stop on error */ /* forward references */ -DEVICE rc_dev; static t_stat rc_rd (int32 *, int32, int32); static t_stat rc_wr (int32, int32, int32); static t_stat rc_svc (UNIT *); @@ -438,7 +436,7 @@ static uint32 sectorCRC (const uint16 *data) static t_stat rc_svc (UNIT *uptr) { - uint32 ma, da, t, u_old, u_new, last_da; + uint32 ma, da, t, u_old, u_new, last_da = 0; uint16 dat; uint16 *fbuf = (uint16 *) uptr->filebuf; diff --git a/PDP11/pdp11_rf.c b/PDP11/pdp11_rf.c index 96c093cb..b84d96d1 100644 --- a/PDP11/pdp11_rf.c +++ b/PDP11/pdp11_rf.c @@ -26,7 +26,8 @@ rf RF11 fixed head disk 23-Oct-13 RMS Revised for new boot setup routine - 03-Sep-13 RMS Added WC to debug printout + 03-Sep-13 RMS Added explicit void * cast + Added WC to debug printout 19-Mar-12 RMS Fixed bug in updating mem addr extension (Peter Schorn) 25-Dec-06 RMS Fixed bug in unit mask (John Dundas) 26-Jun-06 RMS Cloned from RF08 simulator @@ -112,7 +113,6 @@ extern uint16 *M; extern int32 int_req[IPL_HLVL]; -extern FILE *sim_deb; uint32 rf_cs = 0; /* status register */ uint32 rf_cma = 0; @@ -126,7 +126,6 @@ uint32 rf_time = 10; /* inter-word time */ uint32 rf_burst = 1; /* burst mode flag */ uint32 rf_stopioe = 1; /* stop on error */ -DEVICE rf_dev; t_stat rf_rd (int32 *data, int32 PA, int32 access); t_stat rf_wr (int32 data, int32 PA, int32 access); int32 rf_inta (void); @@ -367,7 +366,7 @@ do { update_rfcs (0, RFDAE_NXM); break; } - fbuf[da] = dat; /* write word */ + fbuf[da] = dat; /* write word */ rf_dbr = dat; if (da >= uptr->hwmark) uptr->hwmark = da + 1; @@ -463,7 +462,7 @@ static const uint16 boot_rom[] = { t_stat rf_boot (int32 unitno, DEVICE *dptr) { -int32 i; +size_t i; for (i = 0; i < BOOT_LEN; i++) M[(BOOT_START >> 1) + i] = boot_rom[i]; diff --git a/PDP11/pdp11_rh.c b/PDP11/pdp11_rh.c index ce7d0a73..102fc643 100644 --- a/PDP11/pdp11_rh.c +++ b/PDP11/pdp11_rh.c @@ -165,9 +165,6 @@ extern int32 cpu_bme; extern uint16 *M; extern int32 int_req[IPL_HLVL]; extern t_addr cpu_memsize; -extern FILE *sim_deb; -extern FILE *sim_log; -extern int32 sim_switches; t_stat mba_reset (DEVICE *dptr); t_stat mba_rd (int32 *val, int32 pa, int32 access); @@ -182,7 +179,7 @@ void mba_clr_int (uint32 mb); void mba_upd_cs1 (uint32 set, uint32 clr, uint32 mb); void mba_set_cs2 (uint32 flg, uint32 mb); int32 mba_map_pa (int32 pa, int32 *ofs); -DEVICE mba0_dev, mba1_dev; + extern uint32 Map_Addr (uint32 ba); @@ -839,11 +836,15 @@ return SCPE_OK; void mba_set_enbdis (uint32 mb, t_bool dis) { +t_bool orig; if (mb >= MBA_NUM) /* valid MBA? */ return; +orig = mba_dev[mb].flags & DEV_DIS; if (dis) mba_dev[mb].flags |= DEV_DIS; else mba_dev[mb].flags &= ~DEV_DIS; +if (orig ^ dis) + mba_reset (&mba_dev[mb]); /* reset on change */ return; } @@ -894,11 +895,8 @@ if ((mbregR[idx] && dibp->rd && /* conflict? */ (mbregW[idx] != dibp->wr)) || (mbabort[idx] && dibp->ack[0] && (mbabort[idx] != dibp->ack[0]))) { - printf ("Massbus %s assignment conflict at %d\n", - sim_dname (dptr), dibp->ba); - if (sim_log) - fprintf (sim_log, "Massbus %s assignment conflict at %d\n", - sim_dname (dptr), dibp->ba); + sim_printf ("Massbus %s assignment conflict at %d\n", + sim_dname (dptr), dibp->ba); return SCPE_STOP; } if (dibp->rd) /* set rd dispatch */ diff --git a/PDP11/pdp11_rk.c b/PDP11/pdp11_rk.c index 57140ad3..1ace4b90 100644 --- a/PDP11/pdp11_rk.c +++ b/PDP11/pdp11_rk.c @@ -433,9 +433,9 @@ if (((uptr->flags & UNIT_ATT) == 0) || /* not att or busy? */ } if ((rkcs & RKCS_FMT) && /* format and */ (func != RKCS_READ) && (func != RKCS_WRITE)) { /* not read or write? */ - rk_set_done (RKER_PGE); - return; - } + rk_set_done (RKER_PGE); + return; + } if ((func == RKCS_WRITE) && /* write and locked? */ (uptr->flags & UNIT_WPRT)) { rk_set_done (RKER_WLK); @@ -539,7 +539,7 @@ if (wc && (err == 0)) { /* seek ok? */ wc = i; /* trim transfer */ break; } - rkxb[i] = ((cda / RK_NUMWD) / (RK_NUMSF * RK_NUMSC)) << RKDA_V_CYL; + rkxb[i] = (uint16)(((cda / RK_NUMWD) / (RK_NUMSF * RK_NUMSC)) << RKDA_V_CYL); cda = cda + RK_NUMWD; /* next sector */ } /* end for wc */ } /* end if format */ @@ -550,13 +550,13 @@ if (wc && (err == 0)) { /* seek ok? */ rkxb[i] = 0; } if (rkcs & RKCS_INH) { /* incr inhibit? */ - if (t = Map_WriteW (ma, 2, &rkxb[wc - 1])) { /* store last */ + if ((t = Map_WriteW (ma, 2, &rkxb[wc - 1]))) {/* store last */ rker = rker | RKER_NXM; /* NXM? set flag */ wc = 0; /* no transfer */ } } else { /* normal store */ - if (t = Map_WriteW (ma, wc << 1, rkxb)) { /* store buf */ + if ((t = Map_WriteW (ma, wc << 1, rkxb))) { /* store buf */ rker = rker | RKER_NXM; /* NXM? set flag */ wc = wc - t; /* adj wd cnt */ } @@ -565,7 +565,7 @@ if (wc && (err == 0)) { /* seek ok? */ case RKCS_WRITE: /* write */ if (rkcs & RKCS_INH) { /* incr inhibit? */ - if (t = Map_ReadW (ma, 2, &comp)) { /* get 1st word */ + if ((t = Map_ReadW (ma, 2, &comp))) { /* get 1st word */ rker = rker | RKER_NXM; /* NXM? set flag */ wc = 0; /* no transfer */ } @@ -573,7 +573,7 @@ if (wc && (err == 0)) { /* seek ok? */ rkxb[i] = comp; } else { /* normal fetch */ - if (t = Map_ReadW (ma, wc << 1, rkxb)) { /* get buf */ + if ((t = Map_ReadW (ma, wc << 1, rkxb))) { /* get buf */ rker = rker | RKER_NXM; /* NXM? set flg */ wc = wc - t; /* adj wd cnt */ } @@ -589,7 +589,7 @@ if (wc && (err == 0)) { /* seek ok? */ case RKCS_WCHK: /* write check */ i = fxread (rkxb, sizeof (int16), wc, uptr->fileref); - if (err = ferror (uptr->fileref)) { /* read error? */ + if ((err = ferror (uptr->fileref))) { /* read error? */ wc = 0; /* no transfer */ break; } @@ -653,7 +653,7 @@ if (error != 0) { rkcs = rkcs | RKCS_ERR; if (rker & RKER_HARD) rkcs = rkcs | RKCS_HERR; - } + } if (rkcs & CSR_IE) { /* int enable? */ rkintq = rkintq | RK_CTLI; /* set ctrl int */ SET_INT (RK); /* request int */ @@ -680,8 +680,9 @@ int32 i; for (i = 0; i <= RK_NUMDR; i++) { /* loop thru intq */ if (rkintq & (1u << i)) { /* bit i set? */ rkintq = rkintq & ~(1u << i); /* clear bit i */ - if (rkintq) /* queue next */ + if (rkintq) { /* queue next */ SET_INT (RK); + } rkds = (rkds & ~RKDS_ID) | /* id drive */ (((i == 0)? last_drv: i - 1) << RKDS_V_ID); return rk_dib.vec; /* return vector */ @@ -751,7 +752,7 @@ static const uint16 boot_rom[] = { t_stat rk_boot (int32 unitno, DEVICE *dptr) { -int32 i; +size_t i; for (i = 0; i < BOOT_LEN; i++) M[(BOOT_START >> 1) + i] = boot_rom[i]; diff --git a/PDP11/pdp11_rl.c b/PDP11/pdp11_rl.c index 75690b6b..2b02d674 100644 --- a/PDP11/pdp11_rl.c +++ b/PDP11/pdp11_rl.c @@ -40,7 +40,7 @@ SET RLn ONLINE/OFFLINE SET RL RLV11/RLV12 (PDP-11 only) SET RL DEBUG/NODEBUG - 22-Sep-05 RMS Fixed declarations (from Sterling Garwood) + 22-Sep-05 RMS Fixed declarations (Sterling Garwood) 16-Aug-05 RMS Fixed C++ declaration and cast problems 07-Jul-05 RMS Removed extraneous externs 30-Sep-04 RMS Revised Unibus interface @@ -176,7 +176,7 @@ extern UNIT cpu_unit; #define RLCS_WRITE (5) #define RLCS_READ (6) #define RLCS_RNOHDR (7) -#define RLCS_SPECIAL (8) /* internal function, drive state */ +#define RLCS_SPECIAL (8) /* internal function, drive state */ #define RLCS_V_FUNC (1) #define RLCS_M_MEX (03) /* memory extension */ #define RLCS_V_MEX (4) @@ -228,20 +228,18 @@ extern UNIT cpu_unit; #define RLBAE_IMP (0000077) /* implemented */ extern int32 int_req[IPL_HLVL]; -extern FILE *sim_deb; uint16 *rlxb = NULL; /* xfer buffer */ int32 rlcs = 0; /* control/status */ int32 rlba = 0; /* memory address */ int32 rlbae = 0; /* mem addr extension */ int32 rlda = 0; /* disk addr */ -int32 rlmp = 0, rlmp1 = 0, rlmp2 = 0; /* mp register queue */ +uint16 rlmp = 0, rlmp1 = 0, rlmp2 = 0; /* mp register queue */ int32 rl_swait = 10; /* seek wait */ int32 rl_rwait = 10; /* rotate wait */ int32 rl_stopioe = 1; /* stop on error */ /* forward references */ -DEVICE rl_dev; t_stat rl_rd (int32 *data, int32 PA, int32 access); t_stat rl_wr (int32 data, int32 PA, int32 access); t_stat rl_svc (UNIT *uptr); @@ -358,11 +356,11 @@ static const char * const state[] = { /* I/O dispatch routines, I/O addresses 17774400 - 17774411 - 17774400 RLCS read/write - 17774402 RLBA read/write - 17774404 RLDA read/write - 17774406 RLMP read/write - 17774410 RLBAE read/write + 17774400 RLCS read/write + 17774402 RLBA read/write + 17774404 RLDA read/write + 17774406 RLMP read/write + 17774410 RLBAE read/write */ t_stat rl_rd (int32 *data, int32 PA, int32 access) @@ -372,7 +370,7 @@ UNIT *uptr; switch ((PA >> 1) & 07) { /* decode PA<2:1> */ case 0: /* RLCS */ - rlcs = (rlcs & ~RLCS_MEX) | ((rlbae & RLCS_M_MEX) << RLCS_V_MEX); + rlcs = (rlcs & ~RLCS_MEX) | ((rlbae & RLCS_M_MEX) << RLCS_V_MEX); /* The DRDY signal is sent by the selected drive to indicate that it is ready to read or write or seek. It is sent when the heads are @@ -490,7 +488,7 @@ bit is cleared by software. If set, check for interrupts and return. if (newc != curr) uptr->STAT = (uptr->STAT & ~RLDS_M_STATE) | RLDS_SEEK; /* move the positioner */ /* TBD: if a head switch, sector should be RL_NUMSC/2? */ - uptr->TRK = (newc << RLDA_V_CYL) | /* put on track */ + uptr->TRK = (newc << RLDA_V_CYL) | /* put on track */ ((rlda & RLDA_SK_HD)? RLDA_HD1: RLDA_HD0); /* Real timing: @@ -519,7 +517,7 @@ max 17ms for 1 track seek w/head switch if (rlda & RLDA_GS_CLR) /* reset errors? */ uptr->STAT &= ~RLDS_ERR; /* develop drive state */ - rlmp = uptr->STAT | (uptr->TRK & RLDS_HD); + rlmp = (uint16)(uptr->STAT | (uptr->TRK & RLDS_HD)); if (uptr->flags & UNIT_RL02) rlmp |= RLDS_RL02; if (uptr->flags & UNIT_WPRT) @@ -582,7 +580,7 @@ says, bit 0 can be written and read (as 1) on an RLV12 (verified case 3: /* RLMP */ if (access == WRITEB) data = (PA & 1)? (rlmp & 0377) | (data << 8): (rlmp & ~0377) | data; - rlmp = rlmp1 = rlmp2 = data; + rlmp = rlmp1 = rlmp2 = (uint16)data; if (DEBUG_PRS (rl_dev)) fprintf (sim_deb, ">>RL wr: RLMP %06o\n", rlmp); break; @@ -605,7 +603,7 @@ return SCPE_OK; } /* CRC16 as implemented by the DEC 9401 chip */ -static uint32 calcCRC (const int wc, const uint16 *data) +static uint16 calcCRC (const int wc, const uint16 *data) { uint32 crc, j, d; int32 i; @@ -620,7 +618,7 @@ static uint32 calcCRC (const int wc, const uint16 *data) d >>= 1; } } - return (crc); + return (uint16)crc; } /* @@ -674,12 +672,12 @@ static void rlv_maint (void) rlba = ma & RLBA_IMP; /* lower 16b */ /* 4: check the CRC of (DAR + 3) */ - w = rlda; + w = (uint16)rlda; rlxb[0] = calcCRC (1, &w); /* calculate CRC */ rlda = (rlda & ~0377) | ((rlda + 1) & 0377); /* 5: check the CRC of (DAR + 4) */ - w = rlda; + w = (uint16)rlda; rlxb[1] = calcCRC (1, &w); /* calculate CRC */ rlda = (rlda & ~0377) | ((rlda + 1) & 0377); @@ -759,7 +757,7 @@ was removed in a later ECO. uptr->STAT = (uptr->STAT & ~RLDS_M_STATE) | RLDS_BRUSH; } else { uptr->STAT |= RLDS_BHO; - uptr->STAT = (uptr->STAT & ~RLDS_M_STATE) | RLDS_HLOAD; + uptr->STAT = (uptr->STAT & ~RLDS_M_STATE) | RLDS_HLOAD; } sim_activate (uptr, 200 * rl_swait); break; @@ -787,7 +785,7 @@ Initiated by depressing the Run (LOAD) switch. */ case RLDS_UNL: /* unload pressed, heads unloaded, spin down */ uptr->STAT = (uptr->STAT & ~RLDS_M_STATE) | RLDS_DOWN; - uptr->STAT &= ~RLDS_HDO; /* retract heads */ + uptr->STAT &= ~RLDS_HDO; /* retract heads */ /* actual time is ~30 seconds */ sim_activate (uptr, 200 * rl_swait); break; @@ -843,7 +841,7 @@ if (uptr->FNC == RLCS_RNOHDR) { } else { /* bad cyl or sector? */ if (((uptr->TRK & RLDA_CYL) != (rlda & RLDA_CYL)) || (GET_SECT (rlda) >= RL_NUMSC)) { - rl_set_done (RLCS_ERR | RLCS_HDE | RLCS_INCMP); /* wrong cylinder? */ + rl_set_done (RLCS_ERR | RLCS_HDE | RLCS_INCMP); /* wrong cylinder? */ return (SCPE_OK); } da = GET_DA (rlda) * RL_NUMWD; /* get disk addr */ @@ -1094,7 +1092,7 @@ t_stat rl_show_dstate (FILE *st, UNIT *uptr, int32 val, void *desc) (uptr->STAT & RLDS_WGE) ? '1' : '0', (uptr->STAT & RLDS_SPE) ? '1' : '0'); if (uptr->flags & UNIT_ATT) { - if ((cnt = sim_is_active (uptr)) != 0) + if ((cnt = sim_activate_time (uptr)) != 0) fprintf (st, "FNC: %d, %d\n", uptr->FNC, cnt); else fputs ("FNC: none\n", st); @@ -1124,8 +1122,8 @@ t_stat rl_set_ctrl (UNIT *uptr, int32 val, char *cptr, void *desc) /* SHOW RL will display the controller type */ t_stat rl_show_ctrl (FILE *st, UNIT *uptr, int32 val, void *desc) { - char *s = "RLV12"; - + const char *s = "RLV12"; + if (UNIBUS) s = "RL11"; else if (rl_dev.flags & DEV_RLV11) @@ -1188,7 +1186,7 @@ static const uint16 boot_rom[] = { t_stat rl_boot (int32 unitno, DEVICE *dptr) { -int32 i; +size_t i; extern uint16 *M; for (i = 0; i < BOOT_LEN; i++) diff --git a/PDP11/pdp11_rp.c b/PDP11/pdp11_rp.c index f18b410a..d037270d 100644 --- a/PDP11/pdp11_rp.c +++ b/PDP11/pdp11_rp.c @@ -29,7 +29,7 @@ 08-Dec-12 RMS UNLOAD shouldn't set ATTN (Mark Pizzolato) 17-May-07 RMS CS1 DVA resides in device, not MBA 21-Nov-05 RMS Enable/disable device also enables/disables Massbus adapter - 12-Nov-05 RMS Fixed DriveClear, does not clear disk address + 12-Nov-05 RMS Fixed DriveClear, does not clear disk address 16-Aug-05 RMS Fixed C++ declaration and cast problems 18-Mar-05 RMS Added attached test to detach routine 12-Sep-04 RMS Cloned from pdp11_rp.c @@ -348,7 +348,7 @@ uint16 rper3[RP_NUMDR] = { 0 }; /* error status 3 */ uint16 rpec1[RP_NUMDR] = { 0 }; /* ECC correction 1 */ uint16 rpec2[RP_NUMDR] = { 0 }; /* ECC correction 2 */ int32 rp_stopioe = 1; /* stop on error */ -int32 rp_swait = 10; /* seek time */ +int32 rp_swait = 26; /* seek time */ int32 rp_rwait = 10; /* rotate time */ static const char *rp_fname[CS1_N_FNC] = { "NOP", "UNLD", "SEEK", "RECAL", "DCLR", "RLS", "OFFS", "RETN", @@ -357,8 +357,6 @@ static const char *rp_fname[CS1_N_FNC] = { "WRITE", "WRHDR", "32", "33", "READ", "RDHDR", "36", "37" }; -extern FILE *sim_deb; - t_stat rp_mbrd (int32 *data, int32 ofs, int32 drv); t_stat rp_mbwr (int32 data, int32 ofs, int32 drv); t_stat rp_svc (UNIT *uptr); diff --git a/PDP11/pdp11_rq.c b/PDP11/pdp11_rq.c index bab58713..aa8b9552 100644 --- a/PDP11/pdp11_rq.c +++ b/PDP11/pdp11_rq.c @@ -224,7 +224,7 @@ struct rqpkt { RD52 17 8 512 8 1 4*8 60480 RD32 17 6 820 6 1 4*8 83204 x RD33 17 7 1170 ? ? ? 138565 - RD53 17 7 1024 7 1 5*8 138672 + RD53 17 8 1024 8 1 5*8 138672 RD54 17 15 1225 15 1 7*8 311200 The simulator also supports larger drives that only existed @@ -565,9 +565,6 @@ static struct drvtyp drv_tab[] = { extern int32 int_req[IPL_HLVL]; extern int32 tmr_poll, clk_tps; extern UNIT cpu_unit; -extern FILE *sim_deb; -extern uint32 sim_taddr_64; -extern int32 sim_switches; uint16 *rqxb = NULL; /* xfer buffer */ int32 rq_itime = 200; /* init time, except */ @@ -1207,7 +1204,7 @@ if (cp->csta < CST_UP) { /* still init? */ if ((cp->saw & SA_S4H_LF) && cp->perr) rq_plf (cp, cp->perr); cp->perr = 0; - } + } break; } /* end switch */ @@ -1424,9 +1421,9 @@ if ((uptr = rq_getucb (cp, lu)) && /* valid lu? */ (tpkt = uptr->cpkt) && /* queued pkt? */ (GETP32 (tpkt, CMD_REFL) == ref) && /* match ref? */ (GETP (tpkt, CMD_OPC, OPC) >= OP_ACC)) { /* rd/wr cmd? */ - cp->pak[pkt].d[GCS_STSL] = cp->pak[tpkt].d[RW_WBCL]; - cp->pak[pkt].d[GCS_STSH] = cp->pak[tpkt].d[RW_WBCH]; - } + cp->pak[pkt].d[GCS_STSL] = cp->pak[tpkt].d[RW_WBCL]; + cp->pak[pkt].d[GCS_STSH] = cp->pak[tpkt].d[RW_WBCH]; + } else { cp->pak[pkt].d[GCS_STSL] = 0; /* return 0 */ cp->pak[pkt].d[GCS_STSH] = 0; diff --git a/PDP11/pdp11_rs.c b/PDP11/pdp11_rs.c index 82093f90..798a040c 100644 --- a/PDP11/pdp11_rs.c +++ b/PDP11/pdp11_rs.c @@ -60,7 +60,7 @@ #define UNIT_V_DTYPE (UNIT_V_UF + 0) /* disk type */ #define RS03_DTYPE (0) -#define RS04_DTYPE (1) +#define RS04_DTYPE (1) #define UNIT_V_AUTO (UNIT_V_UF + 1) /* autosize */ #define UNIT_V_WLK (UNIT_V_UF + 2) /* write lock */ #define UNIT_DTYPE (1 << UNIT_V_DTYPE) @@ -173,8 +173,6 @@ static const char *rs_fname[CS1_N_FNC] = { "WRITE", "31", "32", "33", "READ", "35", "36", "37" }; -extern FILE *sim_deb; - t_stat rs_mbrd (int32 *data, int32 ofs, int32 drv); t_stat rs_mbwr (int32 data, int32 ofs, int32 drv); t_stat rs_svc (UNIT *uptr); @@ -328,7 +326,6 @@ return SCPE_OK; t_stat rs_mbwr (int32 data, int32 ofs, int32 drv) { -int32 dtype; UNIT *uptr; uptr = rs_dev.units + drv; /* get unit */ @@ -339,7 +336,6 @@ if ((ofs != RS_AS_OF) && sim_is_active (uptr)) { /* unit busy? */ rs_update_ds (0, drv); return SCPE_OK; } -dtype = GET_DTYPE (uptr->flags); /* get drive type */ ofs = ofs & MBA_RMASK; /* mask offset */ switch (ofs) { /* decode PA<5:1> */ @@ -351,7 +347,7 @@ switch (ofs) { /* decode PA<5:1> */ break; case RS_DA_OF: /* RSDA */ - rsda[drv] = data; + rsda[drv] = (uint16)data; break; case RS_AS_OF: /* RSAS */ @@ -359,7 +355,7 @@ switch (ofs) { /* decode PA<5:1> */ break; case RS_MR_OF: /* RSMR */ - rsmr[drv] = data; + rsmr[drv] = (uint16)data; break; case RS_ER_OF: /* RSER */ @@ -380,7 +376,7 @@ return SCPE_OK; t_stat rs_go (int32 drv) { -int32 fnc, dtype, t; +int32 fnc, t; UNIT *uptr; fnc = GET_FNC (rscs1[drv]); /* get function */ @@ -389,7 +385,6 @@ if (DEBUG_PRS (rs_dev)) drv, rs_fname[fnc], rsds[drv], rsda[drv], rser[drv]); uptr = rs_dev.units + drv; /* get unit */ rs_clr_as (AS_U0 << drv); /* clear attention */ -dtype = GET_DTYPE (uptr->flags); /* get drive type */ if ((fnc != FNC_DCLR) && (rsds[drv] & DS_ERR)) { /* err & ~clear? */ rs_set_er (ER_ILF, drv); /* not allowed */ rs_update_ds (DS_ATA, drv); /* set attention */ @@ -513,7 +508,7 @@ switch (fnc) { /* case on function */ da = da + wc + (RS_NUMWD (dtype) - 1); if (da >= RS_SIZE (dtype)) rsds[drv] = rsds[drv] | DS_LST; - rsda[drv] = da / RS_NUMWD (dtype); + rsda[drv] = (uint16)(da / RS_NUMWD (dtype)); mba_set_don (rs_dib.ba); /* set done */ rs_update_ds (0, drv); /* update ds */ break; @@ -630,7 +625,6 @@ return SCPE_OK; t_stat rs_detach (UNIT *uptr) { int32 drv; -extern int32 sim_is_running; if (!(uptr->flags & UNIT_ATT)) /* attached? */ return SCPE_OK; @@ -686,9 +680,8 @@ static const uint16 boot_rom[] = { t_stat rs_boot (int32 unitno, DEVICE *dptr) { -int32 i; +size_t i; extern uint16 *M; -UNIT *uptr = rs_dev.units + unitno; for (i = 0; i < BOOT_LEN; i++) M[(BOOT_START >> 1) + i] = boot_rom[i]; diff --git a/PDP11/pdp11_rx.c b/PDP11/pdp11_rx.c index 4bef3e34..ce4192cd 100644 --- a/PDP11/pdp11_rx.c +++ b/PDP11/pdp11_rx.c @@ -126,7 +126,6 @@ uint8 rx_buf[RX_NUMBY] = { 0 }; /* sector buffer */ int32 rx_bptr = 0; /* buffer pointer */ int32 rx_enb = 1; /* device enable */ -DEVICE rx_dev; t_stat rx_rd (int32 *data, int32 PA, int32 access); t_stat rx_wr (int32 data, int32 PA, int32 access); t_stat rx_svc (UNIT *uptr); @@ -351,7 +350,7 @@ switch (rx_state) { /* case on state */ break; case FILL: /* fill buffer */ - rx_buf[rx_bptr] = rx_dbr; /* write next */ + rx_buf[rx_bptr] = (uint8)rx_dbr; /* write next */ rx_bptr = rx_bptr + 1; if (rx_bptr < RX_NUMBY) /* more? set xfer */ rx_csr = rx_csr | RXCS_TR; @@ -524,7 +523,7 @@ static const uint16 boot_rom[] = { t_stat rx_boot (int32 unitno, DEVICE *dptr) { -int32 i; +size_t i; extern uint16 *M; for (i = 0; i < BOOT_LEN; i++) diff --git a/PDP11/pdp11_ry.c b/PDP11/pdp11_ry.c index 9acf609b..abf78326 100644 --- a/PDP11/pdp11_ry.c +++ b/PDP11/pdp11_ry.c @@ -157,7 +157,6 @@ int32 ry_swait = 10; /* seek, per track */ int32 ry_xwait = 1; /* tr set time */ uint8 rx2xb[RY_NUMBY] = { 0 }; /* sector buffer */ -DEVICE ry_dev; t_stat ry_rd (int32 *data, int32 PA, int32 access); t_stat ry_wr (int32 data, int32 PA, int32 access); t_stat ry_svc (UNIT *uptr); @@ -182,9 +181,9 @@ DIB ry_dib = { UNIT ry_unit[] = { { UDATA (&ry_svc, UNIT_DEN+UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+UNIT_MUSTBUF, - RY_SIZE) }, + RY_SIZE) }, { UDATA (&ry_svc, UNIT_DEN+UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+UNIT_MUSTBUF, - RY_SIZE) } + RY_SIZE) } }; REG ry_reg[] = { @@ -475,59 +474,59 @@ switch (ry_state) { /* case on state */ sim_activate (uptr, ry_cwait * 100); /* schedule operation */ break; - case SDXFR: /* erase disk */ - for (i = 0; i < (int32) uptr->capac; i++) + case SDXFR: /* erase disk */ + for (i = 0; i < (int32) uptr->capac; i++) fbuf[i] = 0; - uptr->hwmark = (uint32) uptr->capac; - if (ry_csr & RYCS_DEN) + uptr->hwmark = (uint32) uptr->capac; + if (ry_csr & RYCS_DEN) uptr->flags = uptr->flags | UNIT_DEN; - else uptr->flags = uptr->flags & ~UNIT_DEN; - ry_done (0, 0); - break; + else uptr->flags = uptr->flags & ~UNIT_DEN; + ry_done (0, 0); + break; - case ESBA: - ry_ba = ry_dbr; /* save WC */ - ry_state = ESXFR; /* next state */ - sim_activate (uptr, ry_cwait); /* schedule xfer */ - return SCPE_OK; + case ESBA: + ry_ba = ry_dbr; /* save WC */ + ry_state = ESXFR; /* next state */ + sim_activate (uptr, ry_cwait); /* schedule xfer */ + return SCPE_OK; - case ESXFR: - estat[0] = ry_ecode; /* fill 8B status */ - estat[1] = ry_wc; - estat[2] = ry_unit[0].TRACK; - estat[3] = ry_unit[1].TRACK; - estat[4] = ry_track; - estat[5] = ry_sector; - estat[6] = ((ry_csr & RYCS_DRV)? 0200: 0) | - ((ry_unit[1].flags & UNIT_DEN)? 0100: 0) | + case ESXFR: + estat[0] = ry_ecode; /* fill 8B status */ + estat[1] = ry_wc; + estat[2] = (uint8)ry_unit[0].TRACK; + estat[3] = (uint8)ry_unit[1].TRACK; + estat[4] = ry_track; + estat[5] = ry_sector; + estat[6] = ((ry_csr & RYCS_DRV)? 0200: 0) | + ((ry_unit[1].flags & UNIT_DEN)? 0100: 0) | ((uptr->flags & UNIT_ATT)? 0040: 0) | ((ry_unit[0].flags & UNIT_DEN)? 0020: 0) | ((ry_csr & RYCS_DEN)? 0001: 0); - estat[7] = uptr->TRACK; - t = Map_WriteB (ba, 8, estat); /* DMA to memory */ - ry_done (t? RYES_NXM: 0, 0); /* done */ - break; + estat[7] = (uint8)uptr->TRACK; + t = Map_WriteB (ba, 8, estat); /* DMA to memory */ + ry_done (t? RYES_NXM: 0, 0); /* done */ + break; - case CMD_COMPLETE: /* command complete */ - ry_done (0, 0); - break; + case CMD_COMPLETE: /* command complete */ + ry_done (0, 0); + break; - case INIT_COMPLETE: /* init complete */ - ry_unit[0].TRACK = 1; /* drive 0 to trk 1 */ - ry_unit[1].TRACK = 0; /* drive 1 to trk 0 */ - if ((uptr->flags & UNIT_BUF) == 0) { /* not buffered? */ - ry_done (RYES_ID, 0010); /* init done, error */ - break; - } - da = CALC_DA (1, 1, bps); /* track 1, sector 1 */ - for (i = 0; i < bps; i++) /* read sector */ - rx2xb[i] = fbuf[da + i]; - ry_done (RYES_ID, 0); /* set done */ - if ((ry_unit[1].flags & UNIT_ATT) == 0) + case INIT_COMPLETE: /* init complete */ + ry_unit[0].TRACK = 1; /* drive 0 to trk 1 */ + ry_unit[1].TRACK = 0; /* drive 1 to trk 0 */ + if ((uptr->flags & UNIT_BUF) == 0) { /* not buffered? */ + ry_done (RYES_ID, 0010); /* init done, error */ + break; + } + da = CALC_DA (1, 1, bps); /* track 1, sector 1 */ + for (i = 0; i < bps; i++) /* read sector */ + rx2xb[i] = fbuf[da + i]; + ry_done (RYES_ID, 0); /* set done */ + if ((ry_unit[1].flags & UNIT_ATT) == 0) ry_ecode = 0020; - break; - } /* end case state */ + break; + } /* end case state */ return SCPE_OK; } @@ -680,7 +679,7 @@ static const uint16 boot_rom[] = { t_stat ry_boot (int32 unitno, DEVICE *dptr) { -int32 i; +size_t i; extern uint16 *M; if ((ry_unit[unitno & RX_M_NUMDR].flags & UNIT_DEN) == 0) diff --git a/PDP11/pdp11_stddev.c b/PDP11/pdp11_stddev.c index c20a0168..206b9de6 100644 --- a/PDP11/pdp11_stddev.c +++ b/PDP11/pdp11_stddev.c @@ -29,7 +29,7 @@ 18-Apr-12 RMS Modified to use clock coscheduling 20-May-08 RMS Standardized clock delay at 1mips 18-Jun-07 RMS Added UNIT_IDLE flag to console input, clock - 29-Oct-06 RMS Synced keyboard and clock + 29-Oct-06 RMS Synced keyboard and clock Added clock coscheduling support 05-Jul-06 RMS Added UC only support for early DOS/RSTS 22-Nov-05 RMS Revised for new terminal processing routines @@ -255,6 +255,7 @@ switch ((PA >> 1) & 01) { /* decode PA<1> */ tti_csr = tti_csr & ~CSR_DONE; CLR_INT (TTI); *data = tti_unit.buf & 0377; + sim_activate_abs (&tti_unit, KBD_WAIT (tti_unit.wait, tmr_poll)); /* check soon for more input */ return SCPE_OK; } /* end switch PA */ diff --git a/PDP11/pdp11_sys.c b/PDP11/pdp11_sys.c index 085dde21..8accbff4 100644 --- a/PDP11/pdp11_sys.c +++ b/PDP11/pdp11_sys.c @@ -23,7 +23,7 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. - 02-Sep-13 RMS Added third Massbus, RS03/RS04 + 02-Sep-13 RMS Added third Massbus, RS03/RS04 29-Apr-12 RMS Fixed compiler warning (Mark Pizzolato) 19-Nov-08 RMS Moved I/O support routines to I/O library 15-May-08 RMS Added KE11-A, DC11 support @@ -252,8 +252,8 @@ do { /* block loop */ if (org >= MEMSIZE) /* invalid addr? */ return SCPE_NXM; M[org >> 1] = (org & 1)? /* store data */ - (M[org >> 1] & 0377) | (d << 8): - (M[org >> 1] & 0177400) | d; + (M[org >> 1] & 0377) | (uint16)(d << 8): + (M[org >> 1] & 0177400) | (uint16)d; org = (org + 1) & 0177777; /* inc origin */ } if ((d = getc (fileref)) == EOF) /* get csum */ @@ -801,7 +801,7 @@ return tptr; t_stat get_spec (char *cptr, t_addr addr, int32 n1, int32 *sptr, t_value *dptr, int32 cflag, int32 iflag) { -int32 reg, indir, pflag, disp; +int32 reg, indir, pflag, disp = 0; indir = 0; /* no indirect */ pflag = 0; @@ -1075,7 +1075,8 @@ switch (j) { /* case on class */ for (cptr = get_glyph (cptr, gbuf, 0); gbuf[0] != 0; cptr = get_glyph (cptr, gbuf, 0)) { for (i = 0; (opcode[i] != NULL) && - (strcmp (opcode[i], gbuf) != 0) ; i++) ; + (strcmp (opcode[i], gbuf) != 0) ; i++) + ; if ((((opc_val[i] >> I_V_CL) & I_M_CL) != j) || (opcode[i] == NULL)) return SCPE_ARG; diff --git a/PDP11/pdp11_ta.c b/PDP11/pdp11_ta.c index 3c9876d3..dbded024 100644 --- a/PDP11/pdp11_ta.c +++ b/PDP11/pdp11_ta.c @@ -109,7 +109,6 @@ #define UST_GAP 01 /* last op hit gap */ extern int32 int_req[IPL_HLVL]; -extern FILE *sim_deb; uint32 ta_cs = 0; /* control/status */ uint32 ta_idb = 0; /* input data buf */ @@ -126,7 +125,6 @@ static uint8 ta_fnc_tab[TACS_M_FNC + 1] = { OP_REV , OP_FWD, OP_FWD, 0 }; -DEVICE ta_dev; t_stat ta_rd (int32 *data, int32 PA, int32 access); t_stat ta_wr (int32 data, int32 PA, int32 access); t_stat ta_svc (UNIT *uptr); @@ -393,7 +391,7 @@ switch (uptr->FNC) { /* case on function */ else { if ((ta_bptr < TA_MAXFR) && /* room in buf? */ ((uptr->pos + ta_bptr) < uptr->capac)) /* room on tape? */ - ta_xb[ta_bptr++] = ta_odb; /* store char */ + ta_xb[ta_bptr++] = (uint8)ta_odb; /* store char */ ta_set_tr (); /* set tra req */ sim_activate (uptr, ta_ctime); /* sched next char */ } @@ -401,13 +399,13 @@ switch (uptr->FNC) { /* case on function */ case TACS_WRITE|TACS_3RD: /* write CRC */ if (ta_bptr) { /* anything to write? */ - if (st = sim_tape_wrrecf (uptr, ta_xb, ta_bptr)) /* write, err? */ + if ((st = sim_tape_wrrecf (uptr, ta_xb, ta_bptr)))/* write, err? */ r = ta_map_err (uptr, st); /* map error */ } break; /* op done */ case TACS_WFG: /* write file gap */ - if (st = sim_tape_wrtmk (uptr)) /* write tmk, err? */ + if ((st = sim_tape_wrtmk (uptr))) /* write tmk, err? */ r = ta_map_err (uptr, st); /* map error */ break; @@ -417,7 +415,7 @@ switch (uptr->FNC) { /* case on function */ break; case TACS_SRB: /* space rev blk */ - if (st = sim_tape_sprecr (uptr, &tbc)) /* space rev, err? */ + if ((st = sim_tape_sprecr (uptr, &tbc))) /* space rev, err? */ r = ta_map_err (uptr, st); /* map error */ break; @@ -429,7 +427,7 @@ switch (uptr->FNC) { /* case on function */ break; case TACS_SFB: /* space fwd blk */ - if (st = sim_tape_sprecf (uptr, &tbc)) /* space rev, err? */ + if ((st = sim_tape_sprecf (uptr, &tbc))) /* space rev, err? */ r = ta_map_err (uptr, st); /* map error */ ta_cs |= TACS_CRC; /* CRC sets, no err */ break; @@ -655,7 +653,7 @@ static const uint16 boot_rom[] = { t_stat ta_boot (int32 unitno, DEVICE *dptr) { -int32 i; +size_t i; extern uint16 *M; for (i = 0; i < BOOT_LEN; i++) diff --git a/PDP11/pdp11_tc.c b/PDP11/pdp11_tc.c index 7ef02818..3a52bfae 100644 --- a/PDP11/pdp11_tc.c +++ b/PDP11/pdp11_tc.c @@ -26,7 +26,7 @@ tc TC11/TU56 DECtape 23-Oct-13 RMS Revised for new boot setup routine - 23-Jun-06 RMS Fixed switch conflict in ATTACH + 23-Jun-06 RMS Fixed switch conflict in ATTACH 10-Feb-06 RMS READ sets extended data bits in TCST (Alan Frisbie) 16-Aug-05 RMS Fixed C++ declaration and cast problems 07-Jul-05 RMS Removed extraneous externs @@ -266,17 +266,15 @@ #define LOG_BL 0x4 #define DT_SETDONE tccm = tccm | CSR_DONE; \ - if (tccm & CSR_IE) \ + if (tccm & CSR_IE) \ SET_INT (DTA) #define DT_CLRDONE tccm = tccm & ~CSR_DONE; \ - CLR_INT (DTA) + CLR_INT (DTA) #define ABS(x) (((x) < 0)? (-(x)): (x)) extern uint16 *M; /* memory */ extern int32 int_req[IPL_HLVL]; extern UNIT cpu_unit; -extern int32 sim_switches; -extern FILE *sim_deb; int32 tcst = 0; /* status */ int32 tccm = 0; /* command */ @@ -290,7 +288,6 @@ int32 dt_substate = 0; int32 dt_logblk = 0; int32 dt_stopoffr = 0; -DEVICE dt_dev; t_stat dt_rd (int32 *data, int32 PA, int32 access); t_stat dt_wr (int32 data, int32 PA, int32 access); t_stat dt_svc (UNIT *uptr); @@ -309,7 +306,6 @@ void dt_stopunit (UNIT *uptr); int32 dt_comobv (int32 val); int32 dt_csum (UNIT *uptr, int32 blk); int32 dt_gethdr (UNIT *uptr, int32 blk, int32 relpos); -extern int32 sim_is_running; /* DT data structures @@ -710,7 +706,7 @@ switch (fnc) { /* case function */ if (dir) newpos = DT_BLK2LN (blk + 1, uptr) - DT_CSMLN - DT_WSIZE; else newpos = DT_BLK2LN (blk, uptr) + DT_CSMLN + (DT_WSIZE - 1); - } + } if (fnc == FNC_WALL) sim_activate /* write all? */ (&dt_dev.units[DT_TIMER], dt_ctime); /* sched done */ if (DEBUG_PRI (dt_dev, LOG_RW) || @@ -750,7 +746,7 @@ t_bool dt_setpos (UNIT *uptr) { uint32 new_time, ut, ulin, udelt; int32 mot = DTS_GETMOT (uptr->STATE); -int32 unum, delta; +int32 unum, delta = 0; new_time = sim_grtime (); /* current time */ ut = new_time - uptr->LASTT; /* elapsed time */ @@ -785,13 +781,13 @@ if (mot & DTS_DIR) /* update pos */ else uptr->pos = uptr->pos + delta; if (((int32) uptr->pos < 0) || ((int32) uptr->pos > (DTU_FWDEZ (uptr) + DT_EZLIN))) { - detach_unit (uptr); /* off reel? */ - uptr->STATE = uptr->pos = 0; - unum = (int32) (uptr - dt_dev.units); - if ((unum == CSR_GETUNIT (tccm)) && (CSR_GETFNC (tccm) != FNC_STOP)) - dt_seterr (uptr, STA_SEL); /* error */ - return TRUE; - } + detach_unit (uptr); /* off reel? */ + uptr->STATE = uptr->pos = 0; + unum = (int32) (uptr - dt_dev.units); + if ((unum == CSR_GETUNIT (tccm)) && (CSR_GETFNC (tccm) != FNC_STOP)) + dt_seterr (uptr, STA_SEL); /* error */ + return TRUE; + } return FALSE; } @@ -993,7 +989,7 @@ switch (fnc) { /* at speed, check fnc * if (ba >= uptr->hwmark) uptr->hwmark = ba + 1; } -/* else /* ignore hdr */ +/* else *//* ignore hdr */ sim_activate (uptr, DT_WSIZE * dt_ltime); DT_SETDONE; /* set done */ break; @@ -1184,7 +1180,7 @@ static const uint16 boot_rom[] = { t_stat dt_boot (int32 unitno, DEVICE *dptr) { -int32 i; +size_t i; dt_unit[unitno].pos = DT_EZLIN; for (i = 0; i < BOOT_LEN; i++) @@ -1235,13 +1231,13 @@ if (uptr->filebuf == NULL) { /* can't alloc? */ return SCPE_MEM; } fbuf = (uint32 *) uptr->filebuf; /* file buffer */ -printf ("%s%d: ", sim_dname (&dt_dev), u); +sim_printf ("%s%d: ", sim_dname (&dt_dev), u); if (uptr->flags & UNIT_8FMT) - printf ("12b format"); + sim_printf ("12b format"); else if (uptr->flags & UNIT_11FMT) - printf ("16b format"); -else printf ("18b/36b format"); -printf (", buffering file in memory\n"); + sim_printf ("16b format"); +else sim_printf ("18b/36b format"); +sim_printf (", buffering file in memory\n"); if (uptr->flags & UNIT_8FMT) { /* 12b? */ for (ba = 0; ba < uptr->capac; ) { /* loop thru file */ k = fxread (pdp8b, sizeof (int16), D8_NBSIZE, uptr->fileref); @@ -1304,12 +1300,12 @@ if (sim_is_active (uptr)) { /* active? cancel op */ tccm = tccm | CSR_ERR | CSR_DONE; if (tccm & CSR_IE) SET_INT (DTA); - } + } uptr->STATE = uptr->pos = 0; } fbuf = (uint32 *) uptr->filebuf; /* file buffer */ if (uptr->hwmark && ((uptr->flags & UNIT_RO) == 0)) { /* any data? */ - printf ("%s%d: writing buffer to file\n", sim_dname (&dt_dev), u); + sim_printf ("%s%d: writing buffer to file\n", sim_dname (&dt_dev), u); rewind (uptr->fileref); /* start of file */ if (uptr->flags & UNIT_8FMT) { /* 12b? */ for (ba = 0; ba < uptr->hwmark; ) { /* loop thru file */ diff --git a/PDP11/pdp11_tm.c b/PDP11/pdp11_tm.c index 9bbbaea6..a0d85ad5 100644 --- a/PDP11/pdp11_tm.c +++ b/PDP11/pdp11_tm.c @@ -155,7 +155,6 @@ extern uint16 *M; /* memory */ extern int32 int_req[IPL_HLVL]; -extern FILE *sim_deb; uint8 *tmxb = NULL; /* xfer buffer */ int32 tm_sta = 0; /* status register */ @@ -167,7 +166,6 @@ int32 tm_rdl = 0; /* read lines */ int32 tm_time = 10; /* record latency */ int32 tm_stopioe = 1; /* stop on error */ -DEVICE tm_dev; t_stat tm_rd (int32 *data, int32 PA, int32 access); t_stat tm_wr (int32 data, int32 PA, int32 access); t_stat tm_svc (UNIT *uptr); @@ -378,7 +376,7 @@ if (f == MTC_UNLOAD) { /* unload? */ } else if (f == MTC_REWIND) /* rewind */ uptr->USTAT = uptr->USTAT | STA_REW; /* rewinding */ -/* else /* uncomment this else if rewind/unload don't set done */ +/* else *//* uncomment this else if rewind/unload don't set done */ tm_cmd = tm_cmd & ~MTC_DONE; /* clear done */ CLR_INT (TM); /* clear int */ sim_activate (uptr, tm_time); /* start io */ @@ -440,7 +438,7 @@ switch (f) { /* case on function */ tm_sta = tm_sta | STA_RLE; if (tbc < cbc) /* use smaller */ cbc = tbc; - if (t = Map_WriteB (xma, cbc, tmxb)) { /* copy buf to mem */ + if ((t = Map_WriteB (xma, cbc, tmxb))) { /* copy buf to mem */ tm_sta = tm_sta | STA_NXM; /* NXM, set err */ cbc = cbc - t; /* adj byte cnt */ } @@ -450,13 +448,13 @@ switch (f) { /* case on function */ case MTC_WRITE: /* write */ case MTC_WREXT: /* write ext gap */ - if (t = Map_ReadB (xma, cbc, tmxb)) { /* copy mem to buf */ + if ((t = Map_ReadB (xma, cbc, tmxb))) { /* copy mem to buf */ tm_sta = tm_sta | STA_NXM; /* NXM, set err */ cbc = cbc - t; /* adj byte cnt */ if (cbc == 0) /* no xfr? done */ break; } - if (st = sim_tape_wrrecf (uptr, tmxb, cbc)) /* write rec, err? */ + if ((st = sim_tape_wrrecf (uptr, tmxb, cbc))) /* write rec, err? */ r = tm_map_err (uptr, st); /* map error */ else { xma = (xma + cbc) & 0777777; /* inc bus addr */ @@ -465,14 +463,14 @@ switch (f) { /* case on function */ break; case MTC_WREOF: /* write eof */ - if (st = sim_tape_wrtmk (uptr)) /* write tmk, err? */ + if ((st = sim_tape_wrtmk (uptr))) /* write tmk, err? */ r = tm_map_err (uptr, st); /* map error */ break; case MTC_SPACEF: /* space forward */ do { tm_bc = (tm_bc + 1) & 0177777; /* incr wc */ - if (st = sim_tape_sprecf (uptr, &tbc)) { /* spc rec fwd, err? */ + if ((st = sim_tape_sprecf (uptr, &tbc))) { /* spc rec fwd, err? */ r = tm_map_err (uptr, st); /* map error */ break; } @@ -482,7 +480,7 @@ switch (f) { /* case on function */ case MTC_SPACER: /* space reverse */ do { tm_bc = (tm_bc + 1) & 0177777; /* incr wc */ - if (st = sim_tape_sprecr (uptr, &tbc)) { /* spc rec rev, err? */ + if ((st = sim_tape_sprecr (uptr, &tbc))) { /* spc rec rev, err? */ r = tm_map_err (uptr, st); /* map error */ break; } @@ -639,7 +637,7 @@ int32 u = uptr - tm_dev.units; if ((uptr->flags & UNIT_ATT) && (val || sim_tape_wrp (uptr))) - uptr->USTAT = uptr->USTAT | STA_WLK; + uptr->USTAT = uptr->USTAT | STA_WLK; else uptr->USTAT = uptr->USTAT & ~STA_WLK; if (u == GET_UNIT (tm_cmd)) tm_updcsta (uptr); @@ -712,8 +710,7 @@ static const uint16 boot2_rom[] = { t_stat tm_boot (int32 unitno, DEVICE *dptr) { -int32 i; -extern int32 sim_switches; +size_t i; sim_tape_rewind (&tm_unit[unitno]); if (sim_switches & SWMASK ('O')) { @@ -724,7 +721,7 @@ else { for (i = 0; i < BOOT2_LEN; i++) M[(BOOT_START >> 1) + i] = boot2_rom[i]; } -M[BOOT_UNIT >> 1] = unitno; +M[BOOT_UNIT >> 1] = (uint16)unitno; M[BOOT_CSR >> 1] = (tm_dib.ba & DMASK) + 06; cpu_set_boot (BOOT_ENTRY); return SCPE_OK; diff --git a/PDP11/pdp11_tq.c b/PDP11/pdp11_tq.c index c594129c..1f540d36 100644 --- a/PDP11/pdp11_tq.c +++ b/PDP11/pdp11_tq.c @@ -240,8 +240,6 @@ static struct drvtyp drv_tab[] = { extern int32 int_req[IPL_HLVL]; extern int32 tmr_poll, clk_tps; -extern FILE *sim_deb; -extern uint32 sim_taddr_64; uint8 *tqxb = NULL; /* xfer buffer */ uint32 tq_sa = 0; /* status, addr */ diff --git a/PDP11/pdp11_ts.c b/PDP11/pdp11_ts.c index 83a46337..abd7157f 100644 --- a/PDP11/pdp11_ts.c +++ b/PDP11/pdp11_ts.c @@ -270,7 +270,6 @@ extern uint32 cpu_opt; extern int32 int_req[IPL_HLVL]; extern UNIT cpu_unit; -extern FILE *sim_deb; uint8 *tsxb = NULL; /* xfer buffer */ int32 tssr = 0; /* status register */ @@ -286,7 +285,6 @@ int32 ts_bcmd = 0; /* boot cmd */ int32 ts_time = 10; /* record latency */ static uint16 cpy_buf[MAX_PLNT]; /* copy buffer */ -DEVICE ts_dev; t_stat ts_rd (int32 *data, int32 PA, int32 access); t_stat ts_wr (int32 data, int32 PA, int32 access); t_stat ts_svc (UNIT *uptr); @@ -492,7 +490,7 @@ do { fc = (fc - 1) & DMASK; /* decr wc */ if (upd) msgrfc = fc; - if (st = sim_tape_sprecf (uptr, &tbc)) /* space rec fwd, err? */ + if ((st = sim_tape_sprecf (uptr, &tbc))) /* space rec fwd, err? */ return ts_map_status (st); /* map status */ msgxs0 = msgxs0 | XS0_MOT; /* tape has moved */ } while (fc != 0); @@ -535,7 +533,7 @@ do { fc = (fc - 1) & DMASK; /* decr wc */ if (upd) msgrfc = fc; - if (st = sim_tape_sprecr (uptr, &tbc)) /* space rec rev, err? */ + if ((st = sim_tape_sprecr (uptr, &tbc))) /* space rec rev, err? */ return ts_map_status (st); /* map status */ msgxs0 = msgxs0 | XS0_MOT; /* tape has moved */ } while (fc != 0); @@ -668,7 +666,7 @@ else { return TC5; } } -if (st = sim_tape_wrrecf (uptr, tsxb, fc)) /* write rec, err? */ +if ((st = sim_tape_wrrecf (uptr, tsxb, fc))) /* write rec, err? */ return ts_map_status (st); /* return status */ msgxs0 = msgxs0 | XS0_MOT; /* tape has moved */ msgrfc = 0; @@ -681,7 +679,7 @@ int32 ts_wtmk (UNIT *uptr) { t_stat st; -if (st = sim_tape_wrtmk (uptr)) /* write tmk, err? */ +if ((st = sim_tape_wrtmk (uptr))) /* write tmk, err? */ return ts_map_status (st); /* return status */ msgxs0 = msgxs0 | XS0_MOT; /* tape has moved */ if (sim_tape_eot (&ts_unit)) /* EOT on write? */ @@ -1152,7 +1150,7 @@ static const uint16 boot_rom[] = { t_stat ts_boot (int32 unitno, DEVICE *dptr) { -int32 i; +size_t i; extern uint16 *M; sim_tape_rewind (&ts_unit); diff --git a/PDP11/pdp11_tu.c b/PDP11/pdp11_tu.c index 31f43813..0b1e7fe6 100644 --- a/PDP11/pdp11_tu.c +++ b/PDP11/pdp11_tu.c @@ -240,9 +240,6 @@ static char *tu_fname[CS1_N_FNC] = { "WRITE", "31", "32", "33", "READF", "35", "36" "READR" }; -extern int32 sim_switches; -extern FILE *sim_deb; - t_stat tu_mbrd (int32 *data, int32 PA, int32 fmtr); t_stat tu_mbwr (int32 data, int32 PA, int32 fmtr); t_stat tu_svc (UNIT *uptr); @@ -648,7 +645,7 @@ switch (fnc) { /* case on function */ case FNC_SPACEF: /* space forward */ do { tufc = (tufc + 1) & 0177777; /* incr fc */ - if (st = sim_tape_sprecf (uptr, &tbc)) { /* space rec fwd, err? */ + if ((st = sim_tape_sprecf (uptr, &tbc))) { /* space rec fwd, err? */ r = tu_map_err (drv, st, 0); /* map error */ break; } @@ -661,7 +658,7 @@ switch (fnc) { /* case on function */ case FNC_SPACER: /* space reverse */ do { tufc = (tufc + 1) & 0177777; /* incr wc */ - if (st = sim_tape_sprecr (uptr, &tbc)) { /* space rec rev, err? */ + if ((st = sim_tape_sprecr (uptr, &tbc))) { /* space rec rev, err? */ r = tu_map_err (drv, st, 0); /* map error */ break; } @@ -672,7 +669,7 @@ switch (fnc) { /* case on function */ break; case FNC_WREOF: /* write end of file */ - if (st = sim_tape_wrtmk (uptr)) /* write tmk, err? */ + if ((st = sim_tape_wrtmk (uptr))) /* write tmk, err? */ r = tu_map_err (drv, st, 0); /* map error */ break; @@ -688,7 +685,7 @@ switch (fnc) { /* case on function */ tufc = 0; /* clear frame count */ if ((uptr->UDENS == TC_1600) && sim_tape_bot (uptr)) tufs = tufs | FS_ID; /* PE BOT? ID burst */ - if (st = sim_tape_rdrecf (uptr, xbuf, &tbc, MT_MAXFR)) { /* read fwd */ + if ((st = sim_tape_rdrecf (uptr, xbuf, &tbc, MT_MAXFR))) {/* read fwd */ if (st == MTSE_TMK) /* tmk also sets FCE */ tu_set_er (ER_FCE); r = tu_map_err (drv, st, 1); /* map error */ @@ -737,10 +734,10 @@ switch (fnc) { /* case on function */ for (i = j = 0; j < xbc; j = j + 1) { xbuf[i++] = wbuf[j] & 0377; xbuf[i++] = (wbuf[j] >> 8) & 0377; - } + } tbc = xbc; } - if (st = sim_tape_wrrecf (uptr, xbuf, tbc)) /* write rec, err? */ + if ((st = sim_tape_wrrecf (uptr, xbuf, tbc))) /* write rec, err? */ r = tu_map_err (drv, st, 1); /* map error */ else { tufc = (tufc + tbc) & 0177777; @@ -752,7 +749,7 @@ switch (fnc) { /* case on function */ case FNC_READR: /* read reverse */ case FNC_WCHKR: /* wcheck = read */ tufc = 0; /* clear frame count */ - if (st = sim_tape_rdrecr (uptr, xbuf + 4, &tbc, MT_MAXFR)) { /* read rev */ + if ((st = sim_tape_rdrecr (uptr, xbuf + 4, &tbc, MT_MAXFR))) {/* read rev */ if (st == MTSE_TMK) /* tmk also sets FCE */ tu_set_er (ER_FCE); r = tu_map_err (drv, st, 1); /* map error */ @@ -794,7 +791,7 @@ if (DEBUG_PRS (tu_dev)) { fprintf (sim_deb, ">>TU%d DONE: fnc=%s, fc=%06o, fs=%06o, er=%06o, pos=", drv, tu_fname[fnc], tufc, tufs, tuer); fprint_val (sim_deb, uptr->pos, 10, T_ADDR_W, PV_LEFT); - fprintf (sim_deb, "\n"); + fprintf (sim_deb, ", r=%d\n", r); } return SCPE_OK; } @@ -1037,7 +1034,7 @@ static const uint16 boot_rom[] = { t_stat tu_boot (int32 unitno, DEVICE *dptr) { -int32 i; +size_t i; extern uint16 *M; for (i = 0; i < BOOT_LEN; i++) diff --git a/PDP11/pdp11_uqssp.h b/PDP11/pdp11_uqssp.h index b995949a..a5848c25 100644 --- a/PDP11/pdp11_uqssp.h +++ b/PDP11/pdp11_uqssp.h @@ -27,8 +27,8 @@ 30-Aug-02 RMS Added TMSCP support */ -#ifndef _PDP11_UQSSP_H_ -#define _PDP11_UQSSP_H_ 0 +#ifndef PDP11_UQSSP_H_ +#define PDP11_UQSSP_H_ 0 /* IP register - initialization and polling diff --git a/PDP11/pdp11_vh.c b/PDP11/pdp11_vh.c index d4ae0a63..e44f12d1 100644 --- a/PDP11/pdp11_vh.c +++ b/PDP11/pdp11_vh.c @@ -34,6 +34,7 @@ of lines available to be 8, 16, 24, or 32. Fixed performance issue avoiding redundant polling 03-Jan-10 JAD Eliminate gcc warnings + 24-Nov-08 JDB Removed tmxr_send_buffered_data declaration (now in sim_tmxr.h) 19-Nov-08 RMS Revised for common TMXR show routines 18-Jun-07 RMS Added UNIT_IDLE flag 29-Oct-06 RMS Synced poll and clock @@ -82,7 +83,6 @@ extern int32 int_req[IPL_HLVL]; extern uint32 cpu_opt; #endif -#include "sim_sock.h" #include "sim_tmxr.h" /* imports from pdp11_stddev.c: */ @@ -713,7 +713,7 @@ static void vh_getc ( int32 vh ) uint32 i, c; TMLX *lp; - for (i = 0; i < VH_LINES; i++) { + for (i = 0; i < (uint32)VH_LINES; i++) { lp = &vh_parm[(vh * VH_LINES) + i]; while ((c = tmxr_getc_ln (lp->tmln)) != 0) { if (c & SCPE_BREAK) { diff --git a/PDP11/pdp11_xq.c b/PDP11/pdp11_xq.c index f22aac6d..3dcabbe6 100644 --- a/PDP11/pdp11_xq.c +++ b/PDP11/pdp11_xq.c @@ -323,7 +323,7 @@ struct xq_device xqb = { /* SIMH device structures */ DIB xqa_dib = { IOBA_XQ, IOLN_XQ, &xq_rd, &xq_wr, - 1, IVCL (XQ), 0, { &xq_int } }; + 1, IVCL (XQ), 0, { &xq_int } }; UNIT xqa_unit[] = { { UDATA (&xq_svc, UNIT_IDLE|UNIT_ATTABLE|UNIT_DISABLE, 2047) }, /* receive timer */ @@ -379,7 +379,7 @@ REG xqa_reg[] = { }; DIB xqb_dib = { IOBA_XQB, IOLN_XQB, &xq_rd, &xq_wr, - 1, IVCL (XQ), 0, { &xq_int } }; + 1, IVCL (XQ), 0, { &xq_int } }; UNIT xqb_unit[] = { { UDATA (&xq_svc, UNIT_IDLE|UNIT_ATTABLE|UNIT_DISABLE, 2047) }, /* receive timer */ @@ -435,10 +435,10 @@ REG xqb_reg[] = { }; MTAB xq_mod[] = { - { MTAB_XTD|MTAB_VDV, 004, "ADDRESS", NULL, - NULL, &show_addr, NULL }, - { MTAB_XTD|MTAB_VDV, 0, "VECTOR", NULL, - NULL, &show_vec, NULL }, + { MTAB_XTD|MTAB_VDV, 004, "ADDRESS", NULL, + NULL, &show_addr, NULL }, + { MTAB_XTD|MTAB_VDV, 0, "VECTOR", NULL, + NULL, &show_vec, NULL }, { MTAB_XTD | MTAB_VDV, 0, "MAC", "MAC=xx:xx:xx:xx:xx:xx", &xq_setmac, &xq_showmac, NULL }, { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "ETH", "ETH", @@ -1342,7 +1342,7 @@ t_stat xq_process_xbdl(CTLR* xq) else { if (xq->var->coalesce_latency == 0) xq_svc(&xq->unit[0]); /* service any received data */ - } + } sim_debug(DBG_WRN, xq->dev, "XBDL completed processing write\n"); } /* loopback/non-loopback */ diff --git a/PDP11/pdp11_xu.c b/PDP11/pdp11_xu.c index bf43cd84..d4e5c6e2 100644 --- a/PDP11/pdp11_xu.c +++ b/PDP11/pdp11_xu.c @@ -56,7 +56,7 @@ probably need to be converted to Map_ReadW and Map_WriteW calls. 4) Some jerkiness seen during interactive I/O with remote systems; this is probably attributable to changed polling times from when - the poll duration was standardized for idling support. + the poll duration was standardized for idling support. ------------------------------------------------------------------------------ @@ -172,7 +172,7 @@ MTAB xu_mod[] = { }; REG xua_reg[] = { - { NULL } }; + { NULL } }; DEBTAB xu_debug[] = { {"TRACE", DBG_TRC}, @@ -186,11 +186,11 @@ DEBTAB xu_debug[] = { DEVICE xu_dev = { - "XU", xua_unit, xua_reg, xu_mod, - 2, XU_RDX, 8, 1, XU_RDX, 8, - &xu_ex, &xu_dep, &xu_reset, - NULL, &xu_attach, &xu_detach, - &xua_dib, DEV_FLTA | DEV_DISABLE | DEV_DIS | DEV_UBUS | DEV_DEBUG, + "XU", xua_unit, xua_reg, xu_mod, + 2, XU_RDX, 8, 1, XU_RDX, 8, + &xu_ex, &xu_dep, &xu_reset, + NULL, &xu_attach, &xu_detach, + &xua_dib, DEV_FLTA | DEV_DISABLE | DEV_DIS | DEV_UBUS | DEV_DEBUG, 0, xu_debug }; @@ -199,7 +199,7 @@ DEVICE xu_dev = { #if defined(IOBA_XUB) DIB xub_dib = { IOBA_XUB, IOLN_XUB, &xu_rd, &xu_wr, - 1, IVCL (XU), 0, { &xu_int } }; + 1, IVCL (XU), 0, { &xu_int } }; UNIT xub_unit[] = { { UDATA (&xu_svc, UNIT_IDLE|UNIT_ATTABLE|UNIT_DISABLE, 0) } /* receive timer */ @@ -213,7 +213,7 @@ struct xu_device xub = { }; REG xub_reg[] = { - { NULL } }; + { NULL } }; DEVICE xub_dev = { "XUB", xub_unit, xub_reg, xu_mod, @@ -468,7 +468,7 @@ t_stat xu_process_local (CTLR* xu, ETH_PACK* pack) void xu_read_callback(CTLR* xu, int status) { if (DBG_PCK & xu->dev->dctrl) - eth_packet_trace_ex(xu->var->etherface, xu->var->read_buffer.msg, xu->var->read_buffer.len, "xu-recvd", DBG_DAT & xu->dev->dctrl, DBG_PCK); + eth_packet_trace_ex(xu->var->etherface, xu->var->read_buffer.msg, xu->var->read_buffer.len, "xu-recvd", DBG_DAT & xu->dev->dctrl, DBG_PCK); /* process any packets locally that can be */ status = xu_process_local (xu, &xu->var->read_buffer); @@ -767,19 +767,19 @@ int32 xu_command(CTLR* xu) case FC_NOOP: break; - case FC_RDPA: /* read default physical address */ + case FC_RDPA: /* read default physical address */ wstatus = Map_WriteB(xu->var->pcbb + 2, 6, xu->var->mac); if (wstatus) return PCSR0_PCEI + 1; break; - case FC_RPA: /* read current physical address */ + case FC_RPA: /* read current physical address */ wstatus = Map_WriteB(xu->var->pcbb + 2, 6, (uint8*)&xu->var->setup.macs[0]); if (wstatus) return PCSR0_PCEI + 1; break; - case FC_WPA: /* write current physical address */ + case FC_WPA: /* write current physical address */ rstatus = Map_ReadB(xu->var->pcbb + 2, 6, (uint8*)&xu->var->setup.macs[0]); if (xu->var->pcb[1] & 1) return PCSR0_PCEI; @@ -814,7 +814,7 @@ int32 xu_command(CTLR* xu) } break; - case FC_RRF: /* read ring format */ + case FC_RRF: /* read ring format */ if ((xu->var->pcb[1] & 1) || (xu->var->pcb[2] & 0374)) return PCSR0_PCEI; xu->var->udb[0] = xu->var->tdrb & 0177776; @@ -831,7 +831,7 @@ int32 xu_command(CTLR* xu) return PCSR0_PCEI+1; break; - case FC_WRF: /* write ring format */ + case FC_WRF: /* write ring format */ if ((xu->var->pcb[1] & 1) || (xu->var->pcb[2] & 0374)) return PCSR0_PCEI; if ((xu->var->pcsr1 & PCSR1_STATE) == STATE_RUNNING) @@ -915,14 +915,14 @@ int32 xu_command(CTLR* xu) memset(stats, 0, sizeof(struct xu_stats)); break; - case FC_RMODE: /* read mode register */ + case FC_RMODE: /* read mode register */ value = xu->var->mode; wstatus = Map_WriteW(xu->var->pcbb+2, 2, &value); if (wstatus) return PCSR0_PCEI + 1; break; - case FC_WMODE: /* write mode register */ + case FC_WMODE: /* write mode register */ value = xu->var->mode; xu->var->mode = xu->var->pcb[1]; sim_debug(DBG_TRC, xu->dev, "FC_WMODE: mode=%04x\n", xu->var->mode); @@ -938,8 +938,8 @@ int32 xu_command(CTLR* xu) xu->var->setup.promiscuous); break; - case FC_RSTAT: /* read extended status */ - case FC_RCSTAT: /* read and clear extended status */ + case FC_RSTAT: /* read extended status */ + case FC_RCSTAT: /* read and clear extended status */ value = xu->var->stat; wstatus = Map_WriteW(xu->var->pcbb+2, 2, &value); value = 10; @@ -950,7 +950,7 @@ int32 xu_command(CTLR* xu) return PCSR0_PCEI + 1; if (fnc == FC_RCSTAT) - xu->var->stat &= 0377; /* clear high byte */ + xu->var->stat &= 0377; /* clear high byte */ break; case FC_RSID: /* read system id parameters */ @@ -1019,7 +1019,7 @@ int32 xu_command(CTLR* xu) return PCSR0_PCEI + 1; break; - default: /* Unknown (unimplemented) command. */ + default: /* Unknown (unimplemented) command. */ printf("%s: unknown ancilliary command 0%o requested !\n", xu->dev->name, fnc); return PCSR0_PCEI; break; @@ -1100,7 +1100,7 @@ void xu_process_receive(CTLR* xu) if (item->packet.len < ETH_MIN_PACKET) { int len = item->packet.len; memset (&item->packet.msg[len], 0, ETH_MIN_PACKET - len); - item->packet.len = ETH_MIN_PACKET; + item->packet.len = ETH_MIN_PACKET; } } @@ -1283,7 +1283,7 @@ void xu_process_transmit(CTLR* xu) wstatus = eth_write(xu->var->etherface, &xu->var->write_buffer, xu->var->wcallback); if (wstatus) xu->var->pcsr0 |= PCSR0_PCEI; - else + else if (DBG_PCK & xu->dev->dctrl) eth_packet_trace_ex(xu->var->etherface, xu->var->write_buffer.msg, xu->var->write_buffer.len, "xu-write", DBG_DAT & xu->dev->dctrl, DBG_PCK); } @@ -1371,35 +1371,35 @@ void xu_port_command (CTLR* xu) sim_debug(DBG_TRC, xu->dev, "xu_port_command(), Command = %s [0%o]\n", commands[command], command); switch (command) { /* cases in order of most used to least used */ - case CMD_PDMD: /* POLLING DEMAND */ + case CMD_PDMD: /* POLLING DEMAND */ /* process transmit buffers, receive buffers are done in the service timer */ xu_process_transmit(xu); xu->var->pcsr0 |= PCSR0_DNI; break; - case CMD_GETCMD: /* GET COMMAND */ + case CMD_GETCMD: /* GET COMMAND */ xu_command(xu); xu->var->pcsr0 |= PCSR0_DNI; break; - case CMD_GETPCBB: /* GET PCB-BASE */ + case CMD_GETPCBB: /* GET PCB-BASE */ xu->var->pcbb = (xu->var->pcsr3 << 16) | xu->var->pcsr2; xu->var->pcsr0 |= PCSR0_DNI; break; - case CMD_SELFTEST: /* SELFTEST */ + case CMD_SELFTEST: /* SELFTEST */ /* - SELFTEST is a <=15-second self diagnostic test, setting various - error flags and the DONE (DNI) flag when complete. For simulation - purposes, signal completion immediately with no errors. This - inexact behavior could be incompatible with any guest machine - diagnostics that are expecting to be able to monitor the - controller's progress through the diagnostic testing. - */ + SELFTEST is a <=15-second self diagnostic test, setting various + error flags and the DONE (DNI) flag when complete. For simulation + purposes, signal completion immediately with no errors. This + inexact behavior could be incompatible with any guest machine + diagnostics that are expecting to be able to monitor the + controller's progress through the diagnostic testing. + */ xu->var->pcsr0 |= PCSR0_DNI; break; - case CMD_START: /* START */ + case CMD_START: /* START */ if (state == STATE_READY) { xu->var->pcsr1 &= ~PCSR1_STATE; xu->var->pcsr1 |= STATE_RUNNING; @@ -1423,7 +1423,7 @@ void xu_port_command (CTLR* xu) xu->var->pcsr0 |= PCSR0_PCEI; break; - case CMD_STOP: /* STOP */ + case CMD_STOP: /* STOP */ if (state == STATE_RUNNING) { xu->var->pcsr1 &= ~PCSR1_STATE; xu->var->pcsr1 |= STATE_READY; @@ -1510,7 +1510,7 @@ t_stat xu_wr(int32 data, int32 PA, int32 access) sim_debug(DBG_REG, xu->dev, "xu_wr(), PCSR%d, data=%08x, PA=%08x, access=%d[%s]\n", reg, data, PA, access, desc); switch (reg) { case 00: - /* Clear write-one-to-clear interrupt bits */ + /* Clear write-one-to-clear interrupt bits */ if (access == WRITEB) { data &= 0377; if (PA & 1) { @@ -1557,11 +1557,11 @@ t_stat xu_wr(int32 data, int32 PA, int32 access) break; case 02: - xu->var->pcsr2 = data & 0177776; /* store word, but not MBZ LSB */ + xu->var->pcsr2 = data & 0177776; /* store word, but not MBZ LSB */ break; case 03: - xu->var->pcsr3 = data & 0000003; /* store significant bits */ + xu->var->pcsr3 = data & 0000003; /* store significant bits */ break; } return SCPE_OK; @@ -1680,7 +1680,7 @@ void xu_dump_rxring (CTLR* xu) for (i=0; ivar->rdrb + (xu->var->relen * 2) * i; - t_stat rstatus = Map_ReadW (ba, 8, rxhdr); /* get rxring entry[i] */ + t_stat rstatus = Map_ReadW (ba, 8, rxhdr); /* get rxring entry[i] */ int own = (rxhdr[2] & RXR_OWN) >> 15; int len = rxhdr[0]; uint32 addr = rxhdr[1] + ((rxhdr[2] & 3) << 16); @@ -1696,7 +1696,7 @@ void xu_dump_txring (CTLR* xu) for (i=0; ivar->tdrb + (xu->var->telen * 2) * i; - t_stat tstatus = Map_ReadW (ba, 8, txhdr); /* get rxring entry[i] */ + t_stat tstatus = Map_ReadW (ba, 8, txhdr); /* get rxring entry[i] */ int own = (txhdr[2] & RXR_OWN) >> 15; int len = txhdr[0]; uint32 addr = txhdr[1] + ((txhdr[2] & 3) << 16); diff --git a/PDP18B/pdp18b_cpu.c b/PDP18B/pdp18b_cpu.c index d9473ac3..ba9ca582 100644 --- a/PDP18B/pdp18b_cpu.c +++ b/PDP18B/pdp18b_cpu.c @@ -1,6 +1,6 @@ /* pdp18b_cpu.c: 18b PDP CPU simulator - Copyright (c) 1993-2008, Robert M Supnik + Copyright (c) 1993-2015, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,7 @@ cpu PDP-4/7/9/15 central processor + 28-Mar-15 RMS Revised to use sim_printf 28-Apr-07 RMS Removed clock initialization 26-Dec-06 RMS Fixed boundary test in KT15/XVM (Andrew Warkentin) 30-Oct-06 RMS Added idle and infinite loop detection @@ -379,13 +380,6 @@ int32 hst_p = 0; /* history pointer */ int32 hst_lnt = 0; /* history length */ InstHistory *hst = NULL; /* instruction history */ -extern int32 sim_int_char; -extern int32 sim_interval; -extern uint32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ -extern t_bool sim_idle_enab; -extern DEVICE *sim_devices[]; -extern FILE *sim_log; - t_bool build_dev_tab (void); t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw); @@ -604,7 +598,7 @@ while (reason == 0) { /* loop until halted */ int32 link_init, fill; if (sim_interval <= 0) { /* check clock queue */ - if (reason = sim_process_event ()) + if ((reason = sim_process_event ())) break; api_int = api_eval (&int_pend); /* eval API */ } @@ -734,7 +728,7 @@ while (reason == 0) { /* loop until halted */ if (sim_brk_summ && sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */ reason = STOP_IBKPT; /* stop simulation */ break; - } + } if (!usmd_defer) /* no IOT? load usmd */ usmd = usmd_buf; else usmd_defer = 0; /* cancel defer */ @@ -2058,15 +2052,15 @@ if (MMR & MM_RDIS) /* reloc disabled? */ else if ((MMR & MM_SH) && /* shared enabled and */ (ma >= g_base[gmode]) && /* >= shared base and */ (ma < (g_base[gmode] + slr_lnt[slr]))) { /* < shared end? */ - if (ma & 017400) { /* ESAS? */ - if ((rc == REL_W) && (MMR & MM_WP)) { /* write and protected? */ - prvn = trap_pending = 1; /* set flag, trap */ - return -1; - } - pa = (((MMR & MM_SBR_MASK) << 8) + ma) & DMASK; /* ESAS reloc */ - } - else pa = RR + (ma & 0377); /* no, ISAS reloc */ - } + if (ma & 017400) { /* ESAS? */ + if ((rc == REL_W) && (MMR & MM_WP)) { /* write and protected? */ + prvn = trap_pending = 1; /* set flag, trap */ + return -1; + } + pa = (((MMR & MM_SBR_MASK) << 8) + ma) & DMASK; /* ESAS reloc */ + } + else pa = RR + (ma & 0377); /* no, ISAS reloc */ + } else { if (ma > (BR | 0377)) { /* normal reloc, viol? */ if (rc != REL_C) /* set flag, trap */ @@ -2255,10 +2249,10 @@ static const uint8 std_dev[] = for (i = 0; i < DEV_MAX; i++) { /* clr tables */ dev_tab[i] = NULL; dev_iors[i] = NULL; - } + } for (i = 0; i < ((uint32) sizeof (std_dev)); i++) /* std entries */ dev_tab[std_dev[i]] = &bad_dev; -for (i = p = 0; (dptr = sim_devices[i]) != NULL; i++) { /* add devices */ +for (i = p = 0; (dptr = sim_devices[i]) != NULL; i++) { /* add devices */ dibp = (DIB *) dptr->ctxt; /* get DIB */ if (dibp && !(dptr->flags & DEV_DIS)) { /* enabled? */ if (dibp->iors) /* if IORS, add */ @@ -2266,11 +2260,8 @@ for (i = p = 0; (dptr = sim_devices[i]) != NULL; i++) { /* add devices * for (j = 0; j < dibp->num; j++) { /* loop thru disp */ if (dibp->dsp[j]) { /* any dispatch? */ if (dev_tab[dibp->dev + j]) { /* already filled? */ - printf ("%s device number conflict at %02o\n", + sim_printf ("%s device number conflict at %02o\n", sim_dname (dptr), dibp->dev + j); - if (sim_log) - fprintf (sim_log, "%s device number conflict at %02o\n", - sim_dname (dptr), dibp->dev + j); return TRUE; } dev_tab[dibp->dev + j] = dibp->dsp[j]; /* fill */ @@ -2321,8 +2312,6 @@ char *cptr = (char *) desc; t_value sim_eval[2]; t_stat r; InstHistory *h; -extern t_stat fprint_sym (FILE *ofile, t_addr addr, t_value *val, - UNIT *uptr, int32 sw); if (hst_lnt == 0) /* enabled? */ return SCPE_NOFNC; diff --git a/PDP18B/pdp18b_defs.h b/PDP18B/pdp18b_defs.h index 9a997886..61f4faeb 100644 --- a/PDP18B/pdp18b_defs.h +++ b/PDP18B/pdp18b_defs.h @@ -50,8 +50,8 @@ Al Kossow and Max Burnet in making documentation and software available. */ -#ifndef _PDP18B_DEFS_H_ -#define _PDP18B_DEFS_H_ 0 +#ifndef PDP18B_DEFS_H_ +#define PDP18B_DEFS_H_ 0 #include "sim_defs.h" /* simulator defns */ diff --git a/PDP18B/pdp18b_drm.c b/PDP18B/pdp18b_drm.c index dd5a0912..d0448003 100644 --- a/PDP18B/pdp18b_drm.c +++ b/PDP18B/pdp18b_drm.c @@ -241,11 +241,11 @@ static const int32 boot_rom[] = { 0706101, /* DRSF ; wait for done */ 0602003, /* JMP .-1 */ 0600000 /* JMP 0 ; enter boot */ - }; + }; t_stat drm_boot (int32 unitno, DEVICE *dptr) { -int32 i; +size_t i; extern int32 PC; if (drm_dib.dev != DEV_DRM) /* non-std addr? */ diff --git a/PDP18B/pdp18b_dt.c b/PDP18B/pdp18b_dt.c index 844c15f8..821b7fa1 100644 --- a/PDP18B/pdp18b_dt.c +++ b/PDP18B/pdp18b_dt.c @@ -1,6 +1,6 @@ /* pdp18b_dt.c: 18b DECtape simulator - Copyright (c) 1993-2008, Robert M Supnik + Copyright (c) 1993-2015, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -27,8 +27,9 @@ (PDP-9) TC02/TU55 DECtape (PDP-15) TC15/TU56 DECtape - 23-Jun-06 RMS Fixed switch conflict in ATTACH - Revised Type 550 header based on DECTOG formatter + 28-Mar-15 RMS Revised to use sim_printf + 23-Jun-06 RMS Fixed switch conflict in ATTACH + Revised Type 550 header based on DECTOG formatter 13-Jun-06 RMS Fixed checksum calculation bug in Type 550 16-Aug-05 RMS Fixed C++ declaration and cast problems 25-Jan-04 RMS Revised for device debug support @@ -327,9 +328,6 @@ extern int32 M[]; extern int32 int_hwre[API_HLVL+1]; extern UNIT cpu_unit; -extern int32 sim_switches; -extern int32 sim_is_running; -extern FILE *sim_deb; int32 dtsa = 0; /* status A */ int32 dtsb = 0; /* status B */ @@ -558,7 +556,7 @@ else if ((pulse & 044) == 004) { /* MMLC */ ((fnc == FNC_WALL) && (uptr->flags & UNIT_WLK))) dt_seterr (uptr, DTB_SEL); /* select err */ else dt_newsa (dtsa); - } + } DT_UPDINT; return dat; } @@ -859,13 +857,13 @@ if (mot & DTS_DIR) /* update pos */ else uptr->pos = uptr->pos + delta; if (((int32) uptr->pos < 0) || ((int32) uptr->pos > (DTU_FWDEZ (uptr) + DT_EZLIN))) { - detach_unit (uptr); /* off reel? */ - uptr->STATE = uptr->pos = 0; - unum = (int32) (uptr - dt_dev.units); - if (unum == DTA_GETUNIT (dtsa)) /* if selected, */ - dt_seterr (uptr, DTB_SEL); /* error */ - return TRUE; - } + detach_unit (uptr); /* off reel? */ + uptr->STATE = uptr->pos = 0; + unum = (int32) (uptr - dt_dev.units); + if (unum == DTA_GETUNIT (dtsa)) /* if selected, */ + dt_seterr (uptr, DTB_SEL); /* error */ + return TRUE; + } return FALSE; } @@ -1039,7 +1037,7 @@ switch (fnc) { /* at speed, check fnc * if (dtsb & DTB_DTF) { /* DTF set? */ dt_seterr (uptr, DTB_TIM); /* timing error */ return SCPE_OK; - } + } if (DEBUG_PRI (dt_dev, LOG_RW) || (DEBUG_PRI (dt_dev, LOG_BL) && (blk == dt_logblk))) fprintf (sim_deb, ">>DT%d: writing block %d %s%s\n", unum, blk, @@ -1436,13 +1434,13 @@ if (uptr->filebuf == NULL) { /* can't alloc? */ return SCPE_MEM; } fbuf = (uint32 *) uptr->filebuf; /* file buffer */ -printf ("%s%d: ", sim_dname (&dt_dev), u); +sim_printf ("%s%d: ", sim_dname (&dt_dev), u); if (uptr->flags & UNIT_8FMT) - printf ("12b format"); + sim_printf ("12b format"); else if (uptr->flags & UNIT_11FMT) - printf ("16b format"); -else printf ("18b/36b format"); -printf (", buffering file in memory\n"); + sim_printf ("16b format"); +else sim_printf ("18b/36b format"); +sim_printf (", buffering file in memory\n"); if (uptr->flags & UNIT_8FMT) { /* 12b? */ for (ba = 0; ba < uptr->capac; ) { /* loop thru file */ k = fxread (pdp8b, sizeof (uint16), D8_NBSIZE, uptr->fileref); @@ -1459,7 +1457,7 @@ if (uptr->flags & UNIT_8FMT) { /* 12b? */ } } /* end file loop */ uptr->hwmark = ba; - } /* end if */ + } /* end if */ else if (uptr->flags & UNIT_11FMT) { /* 16b? */ for (ba = 0; ba < uptr->capac; ) { /* loop thru file */ k = fxread (pdp11b, sizeof (uint16), D18_BSIZE, uptr->fileref); @@ -1503,12 +1501,12 @@ if (sim_is_active (uptr)) { if ((u == DTA_GETUNIT (dtsa)) && (dtsa & DTA_STSTP)) { dtsb = dtsb | DTB_ERF | DTB_SEL | DTB_DTF; DT_UPDINT; - } + } uptr->STATE = uptr->pos = 0; } fbuf = (uint32 *) uptr->filebuf; /* file buffer */ if (uptr->hwmark && ((uptr->flags & UNIT_RO) == 0)) { /* any data? */ - printf ("%s%d: writing buffer to file\n", sim_dname (&dt_dev), u); + sim_printf ("%s%d: writing buffer to file\n", sim_dname (&dt_dev), u); rewind (uptr->fileref); /* start of file */ if (uptr->flags & UNIT_8FMT) { /* 12b? */ for (ba = 0; ba < uptr->hwmark; ) { /* loop thru file */ @@ -1518,7 +1516,7 @@ if (uptr->hwmark && ((uptr->flags & UNIT_RO) == 0)) { /* any data? */ ((fbuf[ba + 1] >> 12) & 077); pdp8b[k + 2] = fbuf[ba + 1] & 07777; ba = ba + 2; - } /* end loop blk */ + } /* end loop blk */ fxwrite (pdp8b, sizeof (uint16), D8_NBSIZE, uptr->fileref); if (ferror (uptr->fileref)) break; diff --git a/PDP18B/pdp18b_fpp.c b/PDP18B/pdp18b_fpp.c index d1a098a6..0f2f8a04 100644 --- a/PDP18B/pdp18b_fpp.c +++ b/PDP18B/pdp18b_fpp.c @@ -253,7 +253,7 @@ switch (fop) { /* case on subop */ break; case FOP_SUB: /* subtract */ - if (sta = fp15_opnd (fir, ar, &fmb)) /* fetch op to FMB */ + if ((sta = fp15_opnd (fir, ar, &fmb))) /* fetch op to FMB */ break; if (fir & FI_FP) /* fp? */ sta = fp15_fadd (fir, &fma, &fmb, 1); /* yes, fp sub */ @@ -262,7 +262,7 @@ switch (fop) { /* case on subop */ case FOP_RSUB: /* reverse sub */ fmb = fma; /* FMB <- FMA */ - if (sta = fp15_opnd (fir, ar, &fma)) /* fetch op to FMA */ + if ((sta = fp15_opnd (fir, ar, &fma))) /* fetch op to FMA */ break; if (fir & FI_FP) /* fp? */ sta = fp15_fadd (fir, &fma, &fmb, 1); /* yes, fp sub */ @@ -270,7 +270,7 @@ switch (fop) { /* case on subop */ break; case FOP_MUL: /* multiply */ - if (sta = fp15_opnd (fir, ar, &fmb)) /* fetch op to FMB */ + if ((sta = fp15_opnd (fir, ar, &fmb))) /* fetch op to FMB */ break; if (fir & FI_FP) /* fp? */ sta = fp15_fmul (fir, &fma, &fmb); /* yes, fp mul */ @@ -278,9 +278,9 @@ switch (fop) { /* case on subop */ break; case FOP_DIV: /* divide */ - if (sta = fp15_opnd (fir, ar, &fmb)) /* fetch op to FMB */ + if ((sta = fp15_opnd (fir, ar, &fmb))) /* fetch op to FMB */ break; - if (sta = fp15_opnd (fir, ar, &fmb)) break; /* fetch op to FMB */ + if ((sta = fp15_opnd (fir, ar, &fmb)))break; /* fetch op to FMB */ if (fir & FI_FP) /* fp? */ sta = fp15_fdiv (fir, &fma, &fmb); /* yes, fp div */ else sta = fp15_idiv (fir, &fma, &fmb); /* no, int div */ @@ -288,7 +288,7 @@ switch (fop) { /* case on subop */ case FOP_RDIV: /* reverse divide */ fmb = fma; /* FMB <- FMA */ - if (sta = fp15_opnd (fir, ar, &fma)) /* fetch op to FMA */ + if ((sta = fp15_opnd (fir, ar, &fma))) /* fetch op to FMA */ break; if (fir & FI_FP) /* fp? */ sta = fp15_fdiv (fir, &fma, &fmb); /* yes, fp div */ @@ -296,7 +296,7 @@ switch (fop) { /* case on subop */ break; case FOP_LD: /* load */ - if (sta = fp15_opnd (fir, ar, &fma)) /* fetch op to FMA */ + if ((sta = fp15_opnd (fir, ar, &fma))) /* fetch op to FMA */ break; fp15_asign (fir, &fma); /* modify A sign */ if (fir & FI_FP) /* fp? */ @@ -309,7 +309,7 @@ switch (fop) { /* case on subop */ break; case FOP_FLT: /* float */ - if (sta = fp15_opnd (fir, ar, &fma)) /* fetch op to FMA */ + if ((sta = fp15_opnd (fir, ar, &fma))) /* fetch op to FMA */ break; fma.exp = 35; fp15_asign (fir, &fma); /* adjust A sign */ @@ -317,13 +317,13 @@ switch (fop) { /* case on subop */ break; case FOP_FIX: /* fix */ - if (sta = fp15_opnd (fir, ar, &fma)) /* fetch op to FMA */ + if ((sta = fp15_opnd (fir, ar, &fma))) /* fetch op to FMA */ break; sta = fp15_fix (fir, &fma); /* fix */ break; case FOP_LFMQ: /* load FMQ */ - if (sta = fp15_opnd (fir, ar, &fma)) /* fetch op to FMA */ + if ((sta = fp15_opnd (fir, ar, &fma))) /* fetch op to FMA */ break; dp_swap (&fma, &fmq); /* swap FMA, FMQ */ fp15_asign (fir, &fma); /* adjust A sign */ @@ -337,7 +337,7 @@ switch (fop) { /* case on subop */ sta = Write (ar, dat, WR); } else { /* no, load */ - if (sta = Read (ar, &dat, RD)) + if ((sta = Read (ar, &dat, RD))) break; fguard = (dat >> JEA_V_GUARD) & 1; jea = dat & JEA_EAMASK; @@ -345,7 +345,7 @@ switch (fop) { /* case on subop */ break; case FOP_ADD: /* add */ - if (sta = fp15_opnd (fir, ar, &fmb)) /* fetch op to FMB */ + if ((sta = fp15_opnd (fir, ar, &fmb))) /* fetch op to FMB */ break; if (fir & FI_FP) /* fp? */ sta = fp15_fadd (fir, &fma, &fmb, 0); /* yes, fp add */ @@ -429,7 +429,7 @@ t_stat sta; fguard = 0; /* clear guard */ if (ir & FI_FP) { /* fp? */ - if (sta = fp15_norm (ir, a, NULL, 0)) /* normalize */ + if ((sta = fp15_norm (ir, a, NULL, 0))) /* normalize */ return sta; if (ir & FI_DP) { /* dp? */ wd[0] = a->exp & DMASK; /* exponent */ diff --git a/PDP18B/pdp18b_mt.c b/PDP18B/pdp18b_mt.c index 22d190cf..7f552741 100644 --- a/PDP18B/pdp18b_mt.c +++ b/PDP18B/pdp18b_mt.c @@ -127,7 +127,6 @@ extern int32 M[]; extern int32 int_hwre[API_HLVL+1]; extern UNIT cpu_unit; -extern FILE *sim_deb; int32 mt_cu = 0; /* command/unit */ int32 mt_sta = 0; /* status register */ @@ -199,7 +198,7 @@ DEVICE mt_dev = { MT_NUMDR, 10, 31, 1, 8, 8, NULL, NULL, &mt_reset, NULL, &mt_attach, &mt_detach, - &mt_dib, DEV_DISABLE | DEV_DEBUG + &mt_dib, DEV_DISABLE | DEV_DEBUG | DEV_TAPE }; /* IOT routine */ @@ -353,7 +352,7 @@ switch (f) { /* case on function */ mtxb[p++] = M[xma] & 0377; } } /* end for */ - if (st = sim_tape_wrrecf (uptr, mtxb, tbc)) /* write rec, err? */ + if ((st = sim_tape_wrrecf (uptr, mtxb, tbc))) /* write rec, err? */ r = mt_map_err (uptr, st); /* map error */ else { M[MT_CA] = (M[MT_CA] + wc) & DMASK; /* advance mem addr */ @@ -363,7 +362,7 @@ switch (f) { /* case on function */ break; case FN_WREOF: - if (st = sim_tape_wrtmk (uptr)) /* write tmk, err? */ + if ((st = sim_tape_wrtmk (uptr))) /* write tmk, err? */ r = mt_map_err (uptr, st); /* map error */ else uptr->USTAT = STA_EOF; mt_cu = mt_cu & ~CU_ERASE; /* clear erase flag */ @@ -372,7 +371,7 @@ switch (f) { /* case on function */ case FN_SPACEF: /* space forward */ do { M[MT_WC] = (M[MT_WC] + 1) & DMASK; /* inc WC */ - if (st = sim_tape_sprecf (uptr, &tbc)) { /* space rec fwd, err? */ + if ((st = sim_tape_sprecf (uptr, &tbc))) { /* space rec fwd, err? */ r = mt_map_err (uptr, st); /* map error */ break; } @@ -382,7 +381,7 @@ switch (f) { /* case on function */ case FN_SPACER: /* space reverse */ do { M[MT_WC] = (M[MT_WC] + 1) & DMASK; /* inc WC */ - if (st = sim_tape_sprecr (uptr, &tbc)) { /* space rec rev, err? */ + if ((st = sim_tape_sprecr (uptr, &tbc))) { /* space rec rev, err? */ r = mt_map_err (uptr, st); /* map error */ break; } diff --git a/PDP18B/pdp18b_rb.c b/PDP18B/pdp18b_rb.c index ff2fec5e..b9db8ec2 100644 --- a/PDP18B/pdp18b_rb.c +++ b/PDP18B/pdp18b_rb.c @@ -204,9 +204,9 @@ int32 s = rb_set_bcd (bcd_s); /* bin sector */ if ((t >= RB_NUMTR) || (t < 0) || /* invalid? */ (s >= RB_NUMSC) || (s < 0)) { - rb_updsta (RBS_ILA); /* error */ - return old_da; /* don't change */ - } + rb_updsta (RBS_ILA); /* error */ + return old_da; /* don't change */ + } else return (((t * RB_NUMSC) + s) * RB_NUMWD); /* new da */ } diff --git a/PDP18B/pdp18b_rf.c b/PDP18B/pdp18b_rf.c index a075c4a0..9f78c285 100644 --- a/PDP18B/pdp18b_rf.c +++ b/PDP18B/pdp18b_rf.c @@ -101,11 +101,11 @@ #define RFS_CLR 0000170 /* always clear */ #define RFS_EFLGS (RFS_HDW | RFS_APE | RFS_MXF | RFS_WCE | \ - RFS_DPE | RFS_WLO | RFS_NED ) /* error flags */ + RFS_DPE | RFS_WLO | RFS_NED ) /* error flags */ #define RFS_FR (RFS_FNC|RFS_IE) #define GET_FNC(x) (((x) >> RFS_V_FNC) & RFS_M_FNC) #define GET_POS(x) ((int) fmod (sim_gtime () / ((double) (x)), \ - ((double) RF_NUMWD))) + ((double) RF_NUMWD))) #define RF_BUSY (sim_is_active (&rf_unit)) extern int32 M[]; @@ -295,7 +295,7 @@ do { break; } else { /* not locked */ - fbuf[rf_da] = M[pa]; /* write word */ + fbuf[rf_da] = M[pa]; /* write word */ if (((uint32) rf_da) >= uptr->hwmark) uptr->hwmark = rf_da + 1; } diff --git a/PDP18B/pdp18b_rp.c b/PDP18B/pdp18b_rp.c index e6cf8a75..e1a0755d 100644 --- a/PDP18B/pdp18b_rp.c +++ b/PDP18B/pdp18b_rp.c @@ -90,7 +90,7 @@ #define STA_RW 0777000 /* read/write */ #define STA_EFLGS (STA_WPE | STA_NXC | STA_NXF | STA_NXS | \ - STA_HNF | STA_SUSI) /* error flags */ + STA_HNF | STA_SUSI) /* error flags */ #define STA_DYN (STA_SUWP | STA_SUSI) /* per unit status */ #define GET_UNIT(x) (((x) >> STA_V_UNIT) & STA_M_UNIT) #define GET_FUNC(x) (((x) >> STA_V_FUNC) & STA_M_FUNC) @@ -111,7 +111,7 @@ #define STB_SUNR 0000001 /* sel unit not rdy */ #define STB_EFLGS (STB_SUFU | STB_PGE | STB_EOP | STB_TME | STB_FME | \ - STB_WCE | STB_WPE | STB_LON ) /* error flags */ + STB_WCE | STB_WPE | STB_LON ) /* error flags */ #define STB_DYN (STB_SUFU | STB_SUSU | STB_SUNR) /* per unit */ /* Disk address */ diff --git a/PDP18B/pdp18b_stddev.c b/PDP18B/pdp18b_stddev.c index 966b6dd1..da709b85 100644 --- a/PDP18B/pdp18b_stddev.c +++ b/PDP18B/pdp18b_stddev.c @@ -1,6 +1,6 @@ /* pdp18b_stddev.c: 18b PDP's standard devices - Copyright (c) 1993-2012, Robert M Supnik + Copyright (c) 1993-2015, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -29,6 +29,7 @@ tto teleprinter clk clock + 28-Mar-15 RMS Revised to use sim_printf 18-Apr-12 RMS Added clk_cosched routine Revised clk and tti scheduling 18-Jun-07 RMS Added UNIT_IDLE to console input, clock @@ -85,8 +86,6 @@ extern int32 M[]; extern int32 int_hwre[API_HLVL+1], PC, ASW; -extern int32 sim_switches; -extern int32 sim_is_running; extern UNIT cpu_unit; int32 clk_state = 0; @@ -428,7 +427,7 @@ int32 t; t = sim_rtc_calb (clk_tps); /* calibrate clock */ tmxr_poll = t; /* set mux poll */ -sim_activate (&clk_unit, t); /* reactivate unit */ +sim_activate_after (uptr, 1000000/clk_tps); /* reactivate unit */ #if defined (PDP15) clk_task_upd (FALSE); /* update task timer */ #endif @@ -453,7 +452,6 @@ int32 clk_task_upd (t_bool clr) { uint32 delta, val, iusec10; uint32 cur = sim_grtime (); -uint32 old = clk_task_timer; double usec10; if (cur > clk_task_last) @@ -495,6 +493,7 @@ t_stat clk_reset (DEVICE *dptr) { int32 t; +sim_register_clock_unit (&clk_unit); /* declare clock unit */ CLR_INT (CLK); /* clear flag */ if (!sim_is_running) { /* RESET (not CAF)? */ t = sim_rtc_init (clk_unit.wait); /* init calibration */ @@ -584,7 +583,7 @@ if ((temp = getc (ptr_unit.fileref)) == EOF) { /* end of file? */ #endif if (feof (ptr_unit.fileref)) { if (ptr_stopioe) - printf ("PTR end of file\n"); + sim_printf ("PTR end of file\n"); else return SCPE_OK; } else perror ("PTR I/O error"); @@ -594,7 +593,7 @@ if ((temp = getc (ptr_unit.fileref)) == EOF) { /* end of file? */ if (ptr_state == 0) { /* ASCII */ if (ptr_unit.flags & UNIT_RASCII) { /* want parity? */ ptr_unit.buf = temp = temp & 0177; /* parity off */ - while (temp = temp & (temp - 1)) + while ((temp = temp & (temp - 1))) ptr_unit.buf = ptr_unit.buf ^ 0200; /* count bits */ ptr_unit.buf = ptr_unit.buf ^ 0200; /* set even parity */ } @@ -861,8 +860,8 @@ static const int32 boot_rom[] = { t_stat ptr_boot (int32 unitno, DEVICE *dptr) { -int32 i, mask, wd; -extern int32 sim_switches; +size_t i; +int32 mask, wd; #if defined (PDP7) if (sim_switches & SWMASK ('H')) /* hardware RIM load? */ @@ -994,7 +993,7 @@ if (pulse & 001) { /* KSF */ } if (pulse & 002) { /* KRS/KRB */ CLR_INT (TTI); /* clear flag */ - dat = dat | tti_unit.buf & TTI_MASK; /* return buffer */ + dat = dat | (tti_unit.buf & TTI_MASK); /* return buffer */ #if defined (PDP15) if (pulse & 020) /* KRS? */ tti_fdpx = 1; diff --git a/PDP18B/pdp18b_sys.c b/PDP18B/pdp18b_sys.c index 97adc3cf..239af0a0 100644 --- a/PDP18B/pdp18b_sys.c +++ b/PDP18B/pdp18b_sys.c @@ -345,8 +345,6 @@ return SCPE_OK; t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag) { -extern int32 sim_switches; - if (flag != 0) return SCPE_NOFNC; if (sim_switches & SWMASK ('S')) /* RIM format? */ @@ -1009,7 +1007,7 @@ for (i = 0; opc_val[i] >= 0; i++) { /* loop thru ops */ break; case I_V_OPR: /* operate */ - if (sp = (inst & 03730)) + if ((sp = (inst & 03730))) fprintf (of, "%s", opcode[i]); fprint_opr (of, inst & 014047, I_V_OPR, sp); break; diff --git a/PDP18B/pdp18b_tt1.c b/PDP18B/pdp18b_tt1.c index 1e60bb79..5340ceef 100644 --- a/PDP18B/pdp18b_tt1.c +++ b/PDP18B/pdp18b_tt1.c @@ -58,7 +58,7 @@ uint32 ttix_done = 0; /* input flags */ uint32 ttox_done = 0; /* output flags */ uint8 ttix_buf[TTX_MAXL] = { 0 }; /* input buffers */ uint8 ttox_buf[TTX_MAXL] = { 0 }; /* output buffers */ -TMLN ttx_ldsc[TTX_MAXL] = { 0 }; /* line descriptors */ +TMLN ttx_ldsc[TTX_MAXL] = { {0} }; /* line descriptors */ TMXR ttx_desc = { 1, 0, 0, ttx_ldsc }; /* mux descriptor */ #define ttx_lines ttx_desc.lines /* current number of lines */ @@ -129,7 +129,7 @@ DEVICE tti1_dev = { 1, 10, 31, 1, 8, 8, &tmxr_ex, &tmxr_dep, &ttx_reset, NULL, &ttx_attach, &ttx_detach, - &ttix_dib, DEV_NET | DEV_DISABLE + &ttix_dib, DEV_MUX | DEV_DISABLE }; /* TTOx data structures @@ -223,7 +223,7 @@ if (ln >= 0) /* got one? rcv enab */ tmxr_poll_rx (&ttx_desc); /* poll for input */ for (ln = 0; ln < TTX_MAXL; ln++) { /* loop thru lines */ if (ttx_ldsc[ln].conn) { /* connected? */ - if (temp = tmxr_getc_ln (&ttx_ldsc[ln])) { /* get char */ + if ((temp = tmxr_getc_ln (&ttx_ldsc[ln]))) { /* get char */ if (temp & SCPE_BREAK) /* break? */ c = 0; else c = sim_tt_inpcvt (temp, TT_GET_MODE (ttox_unit[ln].flags) | TTUF_KSR); @@ -259,7 +259,7 @@ if (ttix_done) { } else { CLR_INT (TTI1); - } + } return; } @@ -438,7 +438,7 @@ if (newln < ttx_lines) { if (ttx_ldsc[i].conn) { tmxr_linemsg (&ttx_ldsc[i], "\r\nOperator disconnected line\r\n"); tmxr_reset_ln (&ttx_ldsc[i]); /* reset line */ - } + } ttox_unit[i].flags = ttox_unit[i].flags | UNIT_DIS; ttx_reset_ln (i); } diff --git a/PDP8/pdp8_clk.c b/PDP8/pdp8_clk.c index 968ac229..e3cc3a73 100644 --- a/PDP8/pdp8_clk.c +++ b/PDP8/pdp8_clk.c @@ -44,8 +44,6 @@ extern int32 int_req, int_enable, dev_done, stop_inst; int32 clk_tps = 60; /* ticks/second */ int32 tmxr_poll = 16000; /* term mux poll */ -extern int32 sim_is_running; - int32 clk (int32 IR, int32 AC); t_stat clk_svc (UNIT *uptr); t_stat clk_reset (DEVICE *dptr); @@ -148,8 +146,8 @@ int32 t; dev_done = dev_done | INT_CLK; /* set done */ int_req = INT_UPDATE; /* update interrupts */ t = sim_rtcn_calb (clk_tps, TMR_CLK); /* calibrate clock */ -sim_activate (&clk_unit, t); /* reactivate unit */ tmxr_poll = t; /* set mux poll */ +sim_activate_after (uptr, 1000000/clk_tps); /* reactivate unit */ return SCPE_OK; } @@ -169,6 +167,7 @@ t_stat clk_reset (DEVICE *dptr) { int32 t; +sim_register_clock_unit (&clk_unit); /* declare clock unit */ dev_done = dev_done & ~INT_CLK; /* clear done, int */ int_req = int_req & ~INT_CLK; int_enable = int_enable & ~INT_CLK; /* clear enable */ diff --git a/PDP8/pdp8_cpu.c b/PDP8/pdp8_cpu.c index 5da8b55e..4d790ea9 100644 --- a/PDP8/pdp8_cpu.c +++ b/PDP8/pdp8_cpu.c @@ -241,12 +241,6 @@ int32 hst_p = 0; /* history pointer */ int32 hst_lnt = 0; /* history length */ InstHistory *hst = NULL; /* instruction history */ -extern int32 sim_interval; -extern int32 sim_int_char; -extern uint32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ -extern DEVICE *sim_devices[]; -extern FILE *sim_log; -extern t_bool sim_idle_enab; t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw); @@ -346,7 +340,7 @@ reason = 0; while (reason == 0) { /* loop until halted */ if (sim_interval <= 0) { /* check clock queue */ - if (reason = sim_process_event ()) + if ((reason = sim_process_event ())) break; } @@ -360,12 +354,18 @@ while (reason == 0) { /* loop until halted */ } MA = IF | PC; /* form PC */ - if (sim_brk_summ && sim_brk_test (MA, SWMASK ('E'))) { /* breakpoint? */ + if (sim_brk_summ && + sim_brk_test (MA, (1u << SIM_BKPT_V_SPC) | SWMASK ('E'))) { /* breakpoint? */ reason = STOP_IBKPT; /* stop simulation */ break; - } + } IR = M[MA]; /* fetch instruction */ + if (sim_brk_summ && + sim_brk_test (IR, (2u << SIM_BKPT_V_SPC) | SWMASK ('I'))) { /* breakpoint? */ + reason = STOP_OPBKPT; /* stop simulation */ + break; + } PC = (PC + 1) & 07777; /* increment PC */ int_req = int_req | INT_NO_ION_PENDING; /* clear ION delay */ sim_interval = sim_interval - 1; @@ -1371,7 +1371,8 @@ pcq_r = find_reg ("PCQ", NULL, dptr); if (pcq_r) pcq_r->qptr = 0; else return SCPE_IERR; -sim_brk_types = sim_brk_dflt = SWMASK ('E'); +sim_brk_types = SWMASK ('E') | SWMASK('I'); +sim_brk_dflt = SWMASK ('E'); return SCPE_OK; } @@ -1499,12 +1500,9 @@ for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { /* add devices */ for (j = 0; j < dibp->num; j++) { /* loop thru disp */ if (dibp->dsp[j]) { /* any dispatch? */ if (dev_tab[dibp->dev + j]) { /* already filled? */ - printf ("%s device number conflict at %02o\n", - sim_dname (dptr), dibp->dev + j); - if (sim_log) - fprintf (sim_log, "%s device number conflict at %02o\n", - sim_dname (dptr), dibp->dev + j); - return TRUE; + sim_printf ("%s device number conflict at %02o\n", + sim_dname (dptr), dibp->dev + j); + return TRUE; } dev_tab[dibp->dev + j] = dibp->dsp[j]; /* fill */ } /* end if dsp */ @@ -1554,8 +1552,6 @@ char *cptr = (char *) desc; t_stat r; t_value sim_eval; InstHistory *h; -extern t_stat fprint_sym (FILE *ofile, t_addr addr, t_value *val, - UNIT *uptr, int32 sw); if (hst_lnt == 0) /* enabled? */ return SCPE_NOFNC; diff --git a/PDP8/pdp8_ct.c b/PDP8/pdp8_ct.c index abef6ec6..f35c0f88 100644 --- a/PDP8/pdp8_ct.c +++ b/PDP8/pdp8_ct.c @@ -28,7 +28,7 @@ 17-Sep-07 RMS Changed to use central set_bootpc routine 13-Aug-07 RMS Fixed handling of BEOT 06-Aug-07 RMS Foward op at BOT skips initial file gap - 30-May007 RMS Fixed typo (Norm Lastovica) + 30-May-07 RMS Fixed typo (Norm Lastovica) Magnetic tapes are represented as a series of variable records of the form: @@ -139,7 +139,6 @@ extern int32 int_req, stop_inst; extern UNIT cpu_unit; -extern FILE *sim_deb; uint32 ct_sra = 0; /* status reg A */ uint32 ct_srb = 0; /* status reg B */ @@ -227,7 +226,7 @@ DEVICE ct_dev = { CT_NUMDR, 10, 31, 1, 8, 8, NULL, NULL, &ct_reset, &ct_boot, &ct_attach, &ct_detach, - &ct_dib, DEV_DISABLE | DEV_DIS | DEV_DEBUG + &ct_dib, DEV_DISABLE | DEV_DIS | DEV_DEBUG | DEV_TAPE }; /* IOT routines */ @@ -271,7 +270,7 @@ switch (IR & 07) { /* decode IR<9:11> */ case 6: /* KGOA */ ct_df = 0; /* clear data flag */ - if (uptr = ct_busy ()) /* op in progress? */ + if ((uptr = ct_busy ())) /* op in progress? */ AC = ct_go_cont (uptr, AC); /* yes */ else AC = ct_go_start (AC); /* no, start */ ct_updsta (NULL); @@ -434,7 +433,7 @@ switch (uptr->FNC) { /* case on function */ case SRA_CRC: /* CRC */ if (ct_write) { /* write? */ - if (st = sim_tape_wrrecf (uptr, ct_xb, ct_bptr)) /* write, err? */ + if ((st = sim_tape_wrrecf (uptr, ct_xb, ct_bptr)))/* write, err? */ r = ct_map_err (uptr, st); /* map error */ break; /* write done */ } @@ -453,7 +452,7 @@ switch (uptr->FNC) { /* case on function */ break; /* read done */ case SRA_WFG: /* write file gap */ - if (st = sim_tape_wrtmk (uptr)) /* write tmk, err? */ + if ((st = sim_tape_wrtmk (uptr))) /* write tmk, err? */ r = ct_map_err (uptr, st); /* map error */ break; @@ -463,7 +462,7 @@ switch (uptr->FNC) { /* case on function */ break; case SRA_SRB: /* space rev blk */ - if (st = sim_tape_sprecr (uptr, &tbc)) /* space rev, err? */ + if ((st = sim_tape_sprecr (uptr, &tbc))) /* space rev, err? */ r = ct_map_err (uptr, st); /* map error */ break; @@ -719,7 +718,7 @@ static const uint16 boot_rom[] = { t_stat ct_boot (int32 unitno, DEVICE *dptr) { -int32 i; +size_t i; extern uint16 M[]; if ((ct_dib.dev != DEV_CT) || unitno) /* only std devno */ diff --git a/PDP8/pdp8_defs.h b/PDP8/pdp8_defs.h index 2aee89e8..867d1f8a 100644 --- a/PDP8/pdp8_defs.h +++ b/PDP8/pdp8_defs.h @@ -45,8 +45,8 @@ and Bill Haygood in resolving questions about the PDP-8 */ -#ifndef _PDP8_DEFS_H_ -#define _PDP8_DEFS_H_ 0 +#ifndef PDP8_DEFS_H_ +#define PDP8_DEFS_H_ 0 #include "sim_defs.h" /* simulator defns */ @@ -59,9 +59,10 @@ #define STOP_RSRV 1 /* must be 1 */ #define STOP_HALT 2 /* HALT */ #define STOP_IBKPT 3 /* breakpoint */ -#define STOP_NOTSTD 4 /* non-std devno */ -#define STOP_DTOFF 5 /* DECtape off reel */ -#define STOP_LOOP 6 /* infinite loop */ +#define STOP_OPBKPT 4 /* Opcode/Instruction breakpoint */ +#define STOP_NOTSTD 5 /* non-std devno */ +#define STOP_DTOFF 6 /* DECtape off reel */ +#define STOP_LOOP 7 /* infinite loop */ /* Memory */ diff --git a/PDP8/pdp8_df.c b/PDP8/pdp8_df.c index ede45928..368167b2 100644 --- a/PDP8/pdp8_df.c +++ b/PDP8/pdp8_df.c @@ -131,7 +131,7 @@ DIB df_dib = { DEV_DF, 3, { &df60, &df61, &df62 } }; UNIT df_unit = { UDATA (&df_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+UNIT_MUSTBUF, - DF_DKSIZE) + DF_DKSIZE) }; REG df_reg[] = { @@ -266,7 +266,7 @@ do { if (da >= uptr->capac) { /* nx disk addr? */ df_sta = df_sta | DFS_NXD; break; - } + } M[DF_WC] = (M[DF_WC] + 1) & 07777; /* incr word count */ M[DF_MA] = (M[DF_MA] + 1) & 07777; /* incr mem addr */ pa = mex | M[DF_MA]; /* add extension */ @@ -278,7 +278,7 @@ do { if ((df_wlk >> t) & 1) /* locked? set err */ df_sta = df_sta | DFS_WLS; else { /* not locked */ - fbuf[da] = M[pa]; /* write word */ + fbuf[da] = M[pa]; /* write word */ if (da >= uptr->hwmark) uptr->hwmark = da + 1; } } @@ -336,8 +336,7 @@ static const uint16 dm4_rom[] = { t_stat df_boot (int32 unitno, DEVICE *dptr) { -int32 i; -extern int32 sim_switches, saved_PC; +size_t i; if (sim_switches & SWMASK ('D')) { for (i = 0; i < DM4_LEN; i = i + 2) diff --git a/PDP8/pdp8_dt.c b/PDP8/pdp8_dt.c index e6b88a15..38faaa78 100644 --- a/PDP8/pdp8_dt.c +++ b/PDP8/pdp8_dt.c @@ -26,7 +26,7 @@ dt TC08/TU56 DECtape 17-Sep-13 RMS Changed to use central set_bootpc routine - 23-Jun-06 RMS Fixed switch conflict in ATTACH + 23-Jun-06 RMS Fixed switch conflict in ATTACH 07-Jan-06 RMS Fixed unaligned register access bug (Doug Carman) 16-Aug-05 RMS Fixed C++ declaration and cast problems 25-Jan-04 RMS Revised for device debug support @@ -266,8 +266,6 @@ extern uint16 M[]; extern int32 int_req; extern UNIT cpu_unit; -extern int32 sim_switches; -extern FILE *sim_deb; int32 dtsa = 0; /* status A */ int32 dtsb = 0; /* status B */ @@ -294,7 +292,6 @@ void dt_seterr (UNIT *uptr, int32 e); int32 dt_comobv (int32 val); int32 dt_csum (UNIT *uptr, int32 blk); int32 dt_gethdr (UNIT *uptr, int32 blk, int32 relpos, int32 dir); -extern int32 sim_is_running; /* DT data structures @@ -683,13 +680,13 @@ if (mot & DTS_DIR) /* update pos */ else uptr->pos = uptr->pos + delta; if (((int32) uptr->pos < 0) || ((int32) uptr->pos > (DTU_FWDEZ (uptr) + DT_EZLIN))) { - detach_unit (uptr); /* off reel? */ - uptr->STATE = uptr->pos = 0; - unum = (int32) (uptr - dt_dev.units); - if (unum == DTA_GETUNIT (dtsa)) /* if selected, */ - dt_seterr (uptr, DTB_SEL); /* error */ - return TRUE; - } + detach_unit (uptr); /* off reel? */ + uptr->STATE = uptr->pos = 0; + unum = (int32) (uptr - dt_dev.units); + if (unum == DTA_GETUNIT (dtsa)) /* if selected, */ + dt_seterr (uptr, DTB_SEL); /* error */ + return TRUE; + } return FALSE; } @@ -797,7 +794,7 @@ switch (fnc) { /* at speed, check fnc * if (dtsb & DTB_DTF) { /* DTF set? */ dt_seterr (uptr, DTB_TIM); /* timing error */ return SCPE_OK; - } + } if (DEBUG_PRI (dt_dev, LOG_RW) || (DEBUG_PRI (dt_dev, LOG_BL) && (blk == dt_logblk))) fprintf (sim_deb, ">>DT%d: reading block %d %s%s\n", @@ -950,7 +947,7 @@ switch (fnc) { /* at speed, check fnc * if (dtsb & DTB_DTF) { /* DTF set? */ dt_seterr (uptr, DTB_TIM); /* timing error */ return SCPE_OK; - } + } relpos = DT_LIN2OF (uptr->pos, uptr); /* cur pos in blk */ M[DT_WC] = (M[DT_WC] + 1) & 07777; /* incr WC, CA */ M[DT_CA] = (M[DT_CA] + 1) & 07777; @@ -965,7 +962,7 @@ switch (fnc) { /* at speed, check fnc * fbuf[ba] = dat; /* write word */ if (ba >= uptr->hwmark) uptr->hwmark = ba + 1; - } + } /* /* ignore hdr */ sim_activate (uptr, DT_WSIZE * dt_ltime); if (M[DT_WC] == 0) @@ -1181,8 +1178,7 @@ static const uint16 boot_rom[] = { t_stat dt_boot (int32 unitno, DEVICE *dptr) { -int32 i; -extern int32 saved_PC; +size_t i; if (unitno) /* only unit 0 */ return SCPE_ARG; @@ -1235,13 +1231,13 @@ if (uptr->filebuf == NULL) { /* can't alloc? */ return SCPE_MEM; } fbuf = (uint16 *) uptr->filebuf; /* file buffer */ -printf ("%s%d: ", sim_dname (&dt_dev), u); +sim_printf ("%s%d: ", sim_dname (&dt_dev), u); if (uptr->flags & UNIT_8FMT) - printf ("12b format"); + sim_printf ("12b format"); else if (uptr->flags & UNIT_11FMT) - printf ("16b format"); -else printf ("18b/36b format"); -printf (", buffering file in memory\n"); + sim_printf ("16b format"); +else sim_printf ("18b/36b format"); +sim_printf (", buffering file in memory\n"); if (uptr->flags & UNIT_8FMT) /* 12b? */ uptr->hwmark = fxread (uptr->filebuf, sizeof (uint16), uptr->capac, uptr->fileref); @@ -1300,7 +1296,7 @@ if (sim_is_active (uptr)) { } fbuf = (uint16 *) uptr->filebuf; /* file buffer */ if (uptr->hwmark && ((uptr->flags & UNIT_RO)== 0)) { /* any data? */ - printf ("%s%d: writing buffer to file\n", sim_dname (&dt_dev), u); + sim_printf ("%s%d: writing buffer to file\n", sim_dname (&dt_dev), u); rewind (uptr->fileref); /* start of file */ if (uptr->flags & UNIT_8FMT) /* PDP8? */ fxwrite (uptr->filebuf, sizeof (uint16), /* write file */ diff --git a/PDP8/pdp8_fpp.c b/PDP8/pdp8_fpp.c index 6845dbe8..01636e37 100644 --- a/PDP8/pdp8_fpp.c +++ b/PDP8/pdp8_fpp.c @@ -96,8 +96,6 @@ #include "pdp8_defs.h" extern int32 int_req; -extern int32 sim_switches; -extern int32 sim_interval; extern uint16 M[]; extern int32 stop_inst; extern UNIT cpu_unit; diff --git a/PDP8/pdp8_mt.c b/PDP8/pdp8_mt.c index 914c8619..f42fb83e 100644 --- a/PDP8/pdp8_mt.c +++ b/PDP8/pdp8_mt.c @@ -120,7 +120,7 @@ #define STA_CPE (00002 << 12) /* compare error */ #define STA_ILL (00001 << 12) /* illegal */ #define STA_9TK 00040 /* 9 track */ -/* #define STA_BAD 00020 /* bad tape?? */ +/* #define STA_BAD 00020 *//* bad tape?? */ #define STA_INC 00010 /* increment error */ #define STA_LAT 00004 /* lateral par error */ #define STA_CRC 00002 /* CRC error */ @@ -128,7 +128,7 @@ #define STA_CLR (FN_RMASK | 00020) /* always clear */ #define STA_DYN (STA_REW | STA_BOT | STA_REM | STA_EOF | \ - STA_EOT | STA_WLK) /* kept in USTAT */ + STA_EOT | STA_WLK) /* kept in USTAT */ extern uint16 M[]; extern int32 int_req, stop_inst; @@ -217,7 +217,7 @@ DEVICE mt_dev = { MT_NUMDR, 10, 31, 1, 8, 8, NULL, NULL, &mt_reset, NULL, &mt_attach, &mt_detach, - &mt_dib, DEV_DISABLE + &mt_dib, DEV_DISABLE | DEV_TAPE }; /* IOT routines */ @@ -453,7 +453,7 @@ switch (f) { /* case on function */ mtxb[p++] = M[xma] & 077; } } - if (st = sim_tape_wrrecf (uptr, mtxb, tbc)) { /* write rec, err? */ + if ((st = sim_tape_wrrecf (uptr, mtxb, tbc))) { /* write rec, err? */ r = mt_map_err (uptr, st); /* map error */ xma = GET_EMA (mt_cu) + mt_ca; /* restore xma */ } @@ -461,14 +461,14 @@ switch (f) { /* case on function */ break; case FN_WREOF: - if (st = sim_tape_wrtmk (uptr)) /* write tmk, err? */ + if ((st = sim_tape_wrtmk (uptr))) /* write tmk, err? */ r = mt_map_err (uptr, st); /* map error */ break; case FN_SPACEF: /* space forward */ do { mt_wc = (mt_wc + 1) & 07777; /* incr wc */ - if (st = sim_tape_sprecf (uptr, &tbc)) { /* space rec fwd, err? */ + if ((st = sim_tape_sprecf (uptr, &tbc))) { /* space rec fwd, err? */ r = mt_map_err (uptr, st); /* map error */ break; /* stop */ } @@ -478,7 +478,7 @@ switch (f) { /* case on function */ case FN_SPACER: /* space reverse */ do { mt_wc = (mt_wc + 1) & 07777; /* incr wc */ - if (st = sim_tape_sprecr (uptr, &tbc)) { /* space rec rev, err? */ + if ((st = sim_tape_sprecr (uptr, &tbc))) { /* space rec rev, err? */ r = mt_map_err (uptr, st); /* map error */ break; /* stop */ } diff --git a/PDP8/pdp8_pt.c b/PDP8/pdp8_pt.c index 6ec915bc..0d84c526 100644 --- a/PDP8/pdp8_pt.c +++ b/PDP8/pdp8_pt.c @@ -164,7 +164,7 @@ if ((ptr_unit.flags & UNIT_ATT) == 0) /* attached? */ if ((temp = getc (ptr_unit.fileref)) == EOF) { if (feof (ptr_unit.fileref)) { if (ptr_stopioe) - printf ("PTR end of file\n"); + sim_printf ("PTR end of file\n"); else return SCPE_OK; } else perror ("PTR I/O error"); @@ -217,9 +217,9 @@ switch (IR & 07) { /* decode IR<9:11> */ sim_activate (&ptp_unit, ptp_unit.wait); /* activate unit */ return AC; - default: - return (stop_inst << IOT_V_REASON) + AC; - } /* end switch */ + default: + return (stop_inst << IOT_V_REASON) + AC; + } /* end switch */ } /* Unit service */ @@ -279,8 +279,7 @@ static const uint16 boot_rom[] = { t_stat ptr_boot (int32 unitno, DEVICE *dptr) { -int32 i; -extern int32 saved_PC; +size_t i; extern uint16 M[]; if (ptr_dib.dev != DEV_PTR) /* only std devno */ diff --git a/PDP8/pdp8_rf.c b/PDP8/pdp8_rf.c index 170954d0..bd75b3a4 100644 --- a/PDP8/pdp8_rf.c +++ b/PDP8/pdp8_rf.c @@ -332,7 +332,7 @@ do { if ((rf_wlk >> t) & 1) /* write locked? */ rf_sta = rf_sta | RFS_WLS; else { /* not locked */ - fbuf[rf_da] = M[pa]; /* write word */ + fbuf[rf_da] = M[pa]; /* write word */ if (((uint32) rf_da) >= uptr->hwmark) uptr->hwmark = rf_da + 1; } @@ -400,8 +400,7 @@ static const uint16 dm4_rom[] = { t_stat rf_boot (int32 unitno, DEVICE *dptr) { -int32 i; -extern int32 sim_switches, saved_PC; +size_t i; if (rf_dib.dev != DEV_RF) /* only std devno */ return STOP_NOTSTD; diff --git a/PDP8/pdp8_rk.c b/PDP8/pdp8_rk.c index f68057f0..ef057a0b 100644 --- a/PDP8/pdp8_rk.c +++ b/PDP8/pdp8_rk.c @@ -452,8 +452,7 @@ static const uint16 boot_rom[] = { t_stat rk_boot (int32 unitno, DEVICE *dptr) { -int32 i; -extern int32 saved_PC; +size_t i; if (rk_dib.dev != DEV_RK) /* only std devno */ return STOP_NOTSTD; diff --git a/PDP8/pdp8_rl.c b/PDP8/pdp8_rl.c index 8efe79cb..d078a9de 100644 --- a/PDP8/pdp8_rl.c +++ b/PDP8/pdp8_rl.c @@ -690,8 +690,7 @@ static const uint16 boot_rom[] = { t_stat rl_boot (int32 unitno, DEVICE *dptr) { -int32 i; -extern int32 saved_PC; +size_t i; if (unitno) /* only unit 0 */ return SCPE_ARG; diff --git a/PDP8/pdp8_rx.c b/PDP8/pdp8_rx.c index efa3f06e..490a8473 100644 --- a/PDP8/pdp8_rx.c +++ b/PDP8/pdp8_rx.c @@ -735,8 +735,7 @@ static const uint16 boot2_rom[] = { t_stat rx_boot (int32 unitno, DEVICE *dptr) { -int32 i; -extern int32 saved_PC; +size_t i; extern uint16 M[]; if (rx_dib.dev != DEV_RX) /* only std devno */ diff --git a/PDP8/pdp8_sys.c b/PDP8/pdp8_sys.c index b12a16ff..ef308605 100644 --- a/PDP8/pdp8_sys.c +++ b/PDP8/pdp8_sys.c @@ -66,7 +66,6 @@ extern DEVICE mt_dev, ct_dev; extern DEVICE ttix_dev, ttox_dev; extern REG cpu_reg[]; extern uint16 M[]; -extern int32 sim_switches; t_stat fprint_sym_fpp (FILE *of, t_value *val); t_stat parse_sym_fpp (char *cptr, t_value *val); @@ -120,6 +119,7 @@ const char *sim_stop_messages[] = { "Unimplemented instruction", "HALT instruction", "Breakpoint", + "Opcode Breakpoint", "Non-standard device number", "DECtape off reel", "Infinite loop" @@ -191,34 +191,49 @@ t_stat sim_load_bin (FILE *fi) { int32 hi, lo, wd, csum, t; uint32 field, newf, origin; +int32 sections_read = 0; -csum = origin = field = newf = 0; /* init */ -do { /* skip leader */ - if ((hi = sim_bin_getc (fi, &newf)) == EOF) - return SCPE_FMT; - } while ((hi == 0) || (hi >= 0200)); -for (;;) { /* data blocks */ - if ((lo = sim_bin_getc (fi, &newf)) == EOF) /* low char */ - return SCPE_FMT; - wd = (hi << 6) | lo; /* form word */ - t = hi; /* save for csum */ - if ((hi = sim_bin_getc (fi, &newf)) == EOF) /* next char */ - return SCPE_FMT; - if (hi == 0200) { /* end of tape? */ - if ((csum - wd) & 07777) /* valid csum? */ - return SCPE_CSUM; - return SCPE_OK; +for (;;) { + csum = origin = field = newf = 0; /* init */ + do { /* skip leader */ + if ((hi = sim_bin_getc (fi, &newf)) == EOF) { + if (sections_read != 0) { + sim_printf ("%d sections sucessfully read\n\r", sections_read); + return SCPE_OK; + } + else + return SCPE_FMT; + } + } while ((hi == 0) || (hi >= 0200)); + for (;;) { /* data blocks */ + if ((lo = sim_bin_getc (fi, &newf)) == EOF) /* low char */ + return SCPE_FMT; + wd = (hi << 6) | lo; /* form word */ + t = hi; /* save for csum */ + if ((hi = sim_bin_getc (fi, &newf)) == EOF) /* next char */ + return SCPE_FMT; + if (hi == 0200) { /* end of tape? */ + if ((csum - wd) & 07777) { /* valid csum? */ + if (sections_read != 0) + sim_printf ("%d sections sucessfully read\n\r", sections_read); + return SCPE_CSUM; + } + if (!(sim_switches & SWMASK ('A'))) /* Load all sections? */ + return SCPE_OK; + sections_read++; + break; + } + csum = csum + t + lo; /* add to csum */ + if (wd > 07777) /* chan 7 set? */ + origin = wd & 07777; /* new origin */ + else { /* no, data */ + if ((field | origin) >= MEMSIZE) + return SCPE_NXM; + M[field | origin] = wd; + origin = (origin + 1) & 07777; + } + field = newf; /* update field */ } - csum = csum + t + lo; /* add to csum */ - if (wd > 07777) /* chan 7 set? */ - origin = wd & 07777; /* new origin */ - else { /* no, data */ - if ((field | origin) >= MEMSIZE) - return SCPE_NXM; - M[field | origin] = wd; - origin = (origin + 1) & 07777; - } - field = newf; /* update field */ } return SCPE_IERR; } diff --git a/PDP8/pdp8_td.c b/PDP8/pdp8_td.c index 48fdf7cb..e49f2644 100644 --- a/PDP8/pdp8_td.c +++ b/PDP8/pdp8_td.c @@ -30,7 +30,7 @@ 17-Sep-13 RMS Changed to use central set_bootpc routine 23-Mar-11 RMS Fixed SDLC to clear AC (from Dave Gesswein) - 23-Jun-06 RMS Fixed switch conflict in ATTACH + 23-Jun-06 RMS Fixed switch conflict in ATTACH 16-Aug-05 RMS Fixed C++ declaration and cast problems 09-Jan-04 RMS Changed sim_fsize calling sequence, added STOP_OFFR @@ -209,8 +209,6 @@ int32 td_set_mtk (int32 code, int32 u, int32 k); t_stat td_show_pos (FILE *st, UNIT *uptr, int32 val, void *desc); extern uint16 M[]; -extern int32 sim_switches; -extern int32 sim_is_running; /* TD data structures @@ -375,16 +373,16 @@ if (new_mving && !prev_mving) { /* start from stop? */ if ((prev_mving && !new_mving) || /* stop from moving? */ (prev_dir != new_dir)) { /* dir chg while moving? */ - if (uptr->STATE >= STA_ACC) { /* not stopping? */ - if (td_setpos (uptr)) /* update pos */ + if (uptr->STATE >= STA_ACC) { /* not stopping? */ + if (td_setpos (uptr)) /* update pos */ return TRUE; - sim_cancel (uptr); /* stop current */ - sim_activate (uptr, td_dctime); /* schedule decel */ - uptr->STATE = STA_DEC | prev_dir; /* set status */ - td_slf = td_qlf = td_qlctr = 0; /* clear state */ - } - return FALSE; - } + sim_cancel (uptr); /* stop current */ + sim_activate (uptr, td_dctime); /* schedule decel */ + uptr->STATE = STA_DEC | prev_dir; /* set status */ + td_slf = td_qlf = td_qlctr = 0; /* clear state */ + } + return FALSE; + } return FALSE; } @@ -445,10 +443,10 @@ if (uptr->STATE & STA_DIR) /* update pos */ else uptr->pos = uptr->pos + delta; if (((int32) uptr->pos < 0) || ((int32) uptr->pos > (DTU_FWDEZ (uptr) + DT_EZLIN))) { - detach_unit (uptr); /* off reel */ - sim_cancel (uptr); /* no timing pulses */ - return TRUE; - } + detach_unit (uptr); /* off reel */ + sim_cancel (uptr); /* no timing pulses */ + return TRUE; + } return FALSE; } @@ -743,8 +741,7 @@ static const uint16 boot_rom[] = { t_stat td_boot (int32 unitno, DEVICE *dptr) { -int32 i; -extern int32 saved_PC; +size_t i; if (unitno) return SCPE_ARG; /* only unit 0 */ @@ -799,13 +796,14 @@ if (uptr->filebuf == NULL) { /* can't alloc? */ return SCPE_MEM; } fbuf = (uint16 *) uptr->filebuf; /* file buffer */ -printf ("%s%d: ", sim_dname (&td_dev), u); +sim_printf ("%s%d: ", sim_dname (&td_dev), u); if (uptr->flags & UNIT_8FMT) - printf ("12b format"); + sim_printf ("12b format"); else if (uptr->flags & UNIT_11FMT) - printf ("16b format"); -else printf ("18b/36b format"); -printf (", buffering file in memory\n"); + sim_printf ("16b format"); +else sim_printf ("18b/36b format"); +sim_printf (", buffering file in memory\n"); + if (uptr->flags & UNIT_8FMT) /* 12b? */ uptr->hwmark = fxread (uptr->filebuf, sizeof (uint16), uptr->capac, uptr->fileref); @@ -871,7 +869,7 @@ if (!(uptr->flags & UNIT_ATT)) return SCPE_OK; fbuf = (uint16 *) uptr->filebuf; /* file buffer */ if (uptr->hwmark && ((uptr->flags & UNIT_RO)== 0)) { /* any data? */ - printf ("%s%d: writing buffer to file\n", sim_dname (&td_dev), u); + sim_printf ("%s%d: writing buffer to file\n", sim_dname (&td_dev), u); rewind (uptr->fileref); /* start of file */ if (uptr->flags & UNIT_8FMT) /* PDP8? */ fxwrite (uptr->filebuf, sizeof (uint16), /* write file */ diff --git a/PDP8/pdp8_tt.c b/PDP8/pdp8_tt.c index 9f39b5d1..aaac733f 100644 --- a/PDP8/pdp8_tt.c +++ b/PDP8/pdp8_tt.c @@ -1,6 +1,6 @@ /* pdp8_tt.c: PDP-8 console terminal simulator - Copyright (c) 1993-2012, Robert M Supnik + Copyright (c) 1993-2015, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,7 @@ tti,tto KL8E terminal input/output + 27-Mar-15 RMS Backported Dave Gesswein's fix to prevent data loss 18-Apr-12 RMS Revised to use clock coscheduling 18-Jun-07 RMS Added UNIT_IDLE flag to console input 18-Oct-06 RMS Synced keyboard to clock @@ -45,7 +46,7 @@ #include extern int32 int_req, int_enable, dev_done, stop_inst; -extern int32 tmxr_poll, sim_is_running; +extern int32 tmxr_poll; int32 tti (int32 IR, int32 AC); int32 tto (int32 IR, int32 AC); @@ -163,6 +164,7 @@ switch (IR & 07) { /* decode IR<9:11> */ case 6: /* KRB */ dev_done = dev_done & ~INT_TTI; /* clear flag */ int_req = int_req & ~INT_TTI; + sim_activate_abs (&tti_unit, KBD_WAIT (tti_unit.wait, tmxr_poll)); /* check soon for more input */ return (tti_unit.buf); /* return buffer */ default: @@ -178,6 +180,8 @@ int32 c; sim_activate (uptr, KBD_WAIT (uptr->wait, clk_cosched (tmxr_poll))); /* continue poll */ +if (dev_done & INT_TTI) /* prior character still pending? */ + return SCPE_OK; if ((c = sim_poll_kbd ()) < SCPE_KFLAG) /* no char or error? */ return c; if (c & SCPE_BREAK) /* break? */ diff --git a/PDP8/pdp8_ttx.c b/PDP8/pdp8_ttx.c index ffac280a..81fb9295 100644 --- a/PDP8/pdp8_ttx.c +++ b/PDP8/pdp8_ttx.c @@ -1,6 +1,6 @@ /* pdp8_ttx.c: PDP-8 additional terminals simulator - Copyright (c) 1993-2013, Robert M Supnik + Copyright (c) 1993-2015, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,7 @@ ttix,ttox PT08/KL8JA terminal input/output + 27-Mar-15 RMS Backported Dave Gesswein's fix to prevent data loss 11-Oct-13 RMS Poll TTIX immediately to pick up initial connect (Mark Pizzolato) 18-Apr-12 RMS Revised to use clock coscheduling 19-Nov-08 RMS Revised for common TMXR show routines @@ -62,12 +63,12 @@ #define TTX_GETLN(x) (((x) >> 4) & TTX_MASK) extern int32 int_req, int_enable, dev_done, stop_inst; -extern int32 tmxr_poll, sim_is_running; +extern int32 tmxr_poll; uint8 ttix_buf[TTX_LINES] = { 0 }; /* input buffers */ uint8 ttox_buf[TTX_LINES] = { 0 }; /* output buffers */ int32 ttx_tps = 100; /* polls per second */ -TMLN ttx_ldsc[TTX_LINES] = { 0 }; /* line descriptors */ +TMLN ttx_ldsc[TTX_LINES] = { {0} }; /* line descriptors */ TMXR ttx_desc = { TTX_LINES, 0, 0, ttx_ldsc }; /* mux descriptor */ DEVICE ttix_dev, ttox_dev; @@ -195,6 +196,7 @@ switch (pulse) { /* case IR<9:11> */ case 2: /* KCC */ dev_done = dev_done & ~itti; /* clear flag */ int_req = int_req & ~itti; + sim_activate_abs (&ttix_unit, ttix_unit.wait); /* check soon for more input */ return 0; /* clear AC */ case 4: /* KRS */ @@ -210,6 +212,7 @@ switch (pulse) { /* case IR<9:11> */ case 6: /* KRB */ dev_done = dev_done & ~itti; /* clear flag */ int_req = int_req & ~itti; + sim_activate_abs (&ttix_unit, ttix_unit.wait); /* check soon for more input */ return ttix_buf[ln]; /* return buf */ default: @@ -234,7 +237,9 @@ if (ln >= 0) /* got one? rcv enb*/ tmxr_poll_rx (&ttx_desc); /* poll for input */ for (ln = 0; ln < TTX_LINES; ln++) { /* loop thru lines */ if (ttx_ldsc[ln].conn) { /* connected? */ - if (temp = tmxr_getc_ln (&ttx_ldsc[ln])) { /* get char */ + if (dev_done & (INT_TTI1 << ln)) /* Last character still pending? */ + continue; + if ((temp = tmxr_getc_ln (&ttx_ldsc[ln]))) { /* get char */ if (temp & SCPE_BREAK) /* break? */ c = 0; else c = sim_tt_inpcvt (temp, TT_GET_MODE (ttox_unit[ln].flags)); diff --git a/S3/s3_cd.c b/S3/s3_cd.c index 7ec0e2ab..9dd3a93e 100644 --- a/S3/s3_cd.c +++ b/S3/s3_cd.c @@ -264,7 +264,7 @@ int32 crd (int32 op, int32 m, int32 n, int32 data) default: break; } - printf (">>CRD non-existent function %d\n", op); + sim_printf (">>CRD non-existent function %d\n", op); return SCPE_OK; } @@ -346,7 +346,7 @@ int32 i; if (s2sel) uptr = &stack_unit[0]; /* stacker 1? */ else uptr = &stack_unit[0]; /* then default */ if ((uptr -> flags & UNIT_ATT) == 0) return SCPE_OK; /* attached? */ -for (i = 0; i < CDR_WIDTH; i++) rbuf[i] = ebcdic_to_ascii[rbuf[i]]; +for (i = 0; (size_t)i < CDR_WIDTH; i++) rbuf[i] = ebcdic_to_ascii[rbuf[i]]; for (i = CDR_WIDTH - 1; (i >= 0) && (rbuf[i] == ' '); i--) rbuf[i] = 0; rbuf[CDR_WIDTH] = 0; /* null at end */ fputs (rbuf, uptr -> fileref); /* write card */ diff --git a/S3/s3_cpu.c b/S3/s3_cpu.c index b4696484..84de92f2 100644 --- a/S3/s3_cpu.c +++ b/S3/s3_cpu.c @@ -382,8 +382,6 @@ int32 saved_PC; /* Saved (old) PC) */ int32 debug_reg = 0; /* set for debug/trace */ int32 debug_flag = 0; /* 1 when trace.log open */ FILE *trace; -extern int32 sim_int_char; -extern uint32 sim_brk_types, sim_brk_dflt, sim_brk_summ;/* breakpoint info */ t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw); @@ -396,9 +394,6 @@ extern int32 lpt (int32 op, int32 m, int32 n, int32 data); extern int32 dsk1 (int32 op, int32 m, int32 n, int32 data); extern int32 dsk2 (int32 op, int32 m, int32 n, int32 data); extern int32 cpu (int32 op, int32 m, int32 n, int32 data); -extern t_stat sim_activate (UNIT *uptr, int32 delay); -extern int32 fprint_sym (FILE *of, int32 addr, uint32 *val, - UNIT *uptr, int32 sw); int32 nulldev (int32 opcode, int32 m, int32 n, int32 data); int32 add_zoned (int32 addr1, int32 len1, int32 addr2, int32 len2); int32 subtract_zoned (int32 addr1, int32 len1, int32 addr2, int32 len2); @@ -507,7 +502,6 @@ DEVICE cpu_dev = { t_stat sim_instr (void) { -extern int32 sim_interval; register int32 PC, IR; int32 i, j, carry, zero, op1, op2; int32 opcode = 0, qbyte = 0, rbyte = 0; @@ -615,12 +609,12 @@ if (opaddr == 0xf0) { /* Is it command format? if (qbyte & 0x01) display[2][3] = '|' ; if (rbyte & 0x01) display[2][7] = '|' ; /* Print display segment array */ - printf("\n\r"); + sim_printf("\n"); for (i = 0; i < 3; i++) { for (j = 0; j < 9; j++) { - printf ("%c", display[i][j]); + sim_printf ("%c", display[i][j]); } - printf ("\n\r"); + sim_printf ("\n"); } reason = STOP_HALT; break; @@ -1321,7 +1315,7 @@ int32 PutMem(int32 addr, int32 data) /* Check the condition register against the qbyte and return 1 if true */ -int32 condition(int32 qbyte) +static int32 condition(int32 qbyte) { int32 r = 0, t, q; t = (qbyte & 0xf0) >> 4; @@ -1351,7 +1345,7 @@ return (r); condition register initial state in parameter 3 */ -int32 compare(int32 byte1, int32 byte2, int32 cond) +static int32 compare(int32 byte1, int32 byte2, int32 cond) { int32 r; diff --git a/S3/s3_disk.c b/S3/s3_disk.c index d3588cfd..1faea2e5 100644 --- a/S3/s3_disk.c +++ b/S3/s3_disk.c @@ -298,7 +298,7 @@ int32 dsk (int32 disk, int32 op, int32 m, int32 n, int32 data) addr++; } - if ((sect == 55) ) { /* HJS MODS */ + if (sect == 55) { /* HJS MODS */ S = sect; N = nsects - i - 2; if (N > -1) diskerr[disk] |= 0x0020; /* end of cyl. */ @@ -349,7 +349,7 @@ int32 dsk (int32 disk, int32 op, int32 m, int32 n, int32 data) diskerr[disk] |= 0x0800; break; } - if ((sect == 55) ) { /* HJS MODS */ + if (sect == 55) { /* HJS MODS */ S = sect; N = nsects - i - 2; if (N > -1) diskerr[disk] |= 0x0020; /* end of cyl. */ @@ -392,7 +392,7 @@ int32 dsk (int32 disk, int32 op, int32 m, int32 n, int32 data) diskerr[disk] |= 0x0400; break; } - if ((sect == 55) ) { /* HJS MODS */ + if (sect == 55) { /* HJS MODS */ S = sect; N = nsects - i - 2; if (N > -1) diskerr[disk] |= 0x0020; /* end of cyl. */ @@ -434,7 +434,7 @@ int32 dsk (int32 disk, int32 op, int32 m, int32 n, int32 data) diskerr[disk] |= 0x0400; break; } - if ((sect == 55) ) { + if (sect == 55) { S = sect; N = nsects - i - 2; if (N > 0) diskerr[disk] |= 0x0020; @@ -486,7 +486,7 @@ int32 dsk (int32 disk, int32 op, int32 m, int32 n, int32 data) found[disk] = 1; if (res == data) break; - if ((sect == 55) ) { /* HJS MODS */ + if (sect == 55) { /* HJS MODS */ S = sect; N = nsects - i - 2; if (N > -1) diskerr[disk] |= 0x0020; /* end of cyl. */ @@ -610,7 +610,7 @@ int32 dsk (int32 disk, int32 op, int32 m, int32 n, int32 data) default: break; } - printf (">>DSK%d non-existent function %d\n", disk, op); + sim_printf (">>DSK%d non-existent function %d\n", disk, op); return SCPE_OK; } diff --git a/S3/s3_lp.c b/S3/s3_lp.c index 99f85af4..a0507f50 100644 --- a/S3/s3_lp.c +++ b/S3/s3_lp.c @@ -203,7 +203,7 @@ int32 lpt (int32 op, int32 m, int32 n, int32 data) default: break; } - printf (">>LPT non-existent function %d\n", op); + sim_printf (">>LPT non-existent function %d\n", op); return SCPE_OK; } diff --git a/S3/s3_pkb.c b/S3/s3_pkb.c index 0ba62090..7dcdd4d4 100644 --- a/S3/s3_pkb.c +++ b/S3/s3_pkb.c @@ -35,8 +35,6 @@ extern int32 int_req, dev_busy, dev_done, dev_disable; t_stat pkb_svc (UNIT *uptr); t_stat pkb_reset (DEVICE *dptr); -extern t_stat sim_poll_kbd (void); -extern t_stat sim_putchar (int32 out); extern int32 IAR[], level; extern int32 debug_reg; @@ -233,7 +231,7 @@ int32 pkb (int32 op, int32 m, int32 n, int32 data) default: break; } - printf (">>PKB non-existent function %d\n", op); + sim_printf (">>PKB non-existent function %d\n", op); return SCPE_OK; } diff --git a/S3/s3_sys.c b/S3/s3_sys.c index 39cec895..bce75722 100644 --- a/S3/s3_sys.c +++ b/S3/s3_sys.c @@ -44,9 +44,9 @@ extern REG cpu_reg[]; extern unsigned char M[]; extern int32 saved_PC, IAR[]; extern unsigned char ebcdic_to_ascii[]; -char *parse_addr(char *cptr, char *gbuf, int32 *addr, int32 *addrtype); +char *parse_addr(char *cptr, char *gbuf, t_addr *addr, int32 *addrtype); -int32 printf_sym (FILE *of, char *strg, int32 addr, uint32 *val, +int32 printf_sym (FILE *of, char *strg, t_addr addr, uint32 *val, UNIT *uptr, int32 sw); /* SCP data structures @@ -122,81 +122,81 @@ const char *sim_stop_messages[] = { int32 nopcode = 75; struct opdef opcode[75] = { - "HPL", 0x00,0,0,0, /* Halt Program Level */ - "A", 0x06,0,1,3, /* Add to Register: A R,AADD */ - "ST", 0x04,0,1,3, /* Store Register */ - "L", 0x05,0,1,3, /* Load Register */ - "LA", 0x02,0,1,1, /* Load Address */ - "ZAZ", 0x04,0,2,2, /* Zero and Add Zoned */ - "AZ", 0x06,0,2,2, /* Add Zoned Decimal */ - "SZ", 0x07,0,2,2, /* Subtract Zoned Decimal */ - "ALC", 0x0E,0,2,2, /* Add Logical: ALC BADD,AADD,LEN */ - "SLC", 0x0F,0,2,2, /* Sub Logical: SLC BADD,AADD,LEN */ - "MVC", 0x0C,0,2,2, /* Move Chars MVX BADD,AADD,LEN */ - "ED", 0x0A,0,2,2, /* Edit: ED BADD,AADD,LEN */ - "ITC", 0x0B,0,2,2, /* Insert Chars: ITC BADD,AADD,LEN */ - "CLC", 0x0D,0,2,2, /* Compare Logical: CLC BADD,AADD,LEN */ - "MVI", 0x0C,0,3,3, /* Move Immediate */ - "SBN", 0x0A,0,3,3, /* Set Bits On */ - "SBF", 0x0B,0,3,3, /* Set Bits Off */ - "CLI", 0x0D,0,3,3, /* Compare Immediate */ - "TBN", 0x08,0,3,3, /* Test Bits On */ - "TBF", 0x09,0,3,3, /* Test Bits Off */ - "APL", 0x01,0,4,0, /* Advance Program Level */ - "SIO", 0x03,0,5,0, /* Start I/O */ - "SNS", 0x00,0,6,3, /* Sense I/O */ - "LIO", 0x01,0,6,3, /* Load I/O */ - "TIO", 0x01,0,6,1, /* Test I/O */ - "J", 0x02,0,7,0, /* Jump Unconditional */ - "J", 0x02,0x87,7,0, /* Alternate J */ - "JH", 0x02,132,7,0, /* Jump if High */ - "JL", 0x02,130,7,0, /* Jump if Low */ - "JE", 0x02,129,7,0, /* Jump if Equal */ - "JNH", 0x02,4,7,0, /* Jump if Not High */ - "JNL", 0x02,2,7,0, /* Jump if Not Low */ - "JNE", 0x02,1,7,0, /* Jump if Not Equal */ - "JOZ", 0x02,136,7,0, /* Jump if Overflow Zoned */ - "JOL", 0x02,160,7,0, /* Jump if Overflow Logical */ - "JNOZ", 0x02,8,7,0, /* Jump if No Overflow Zoned */ - "JNOL", 0x02,32,7,0, /* Jump if No Overflow Logical */ - "JT", 0x02,16,7,0, /* Jump if True */ - "JF", 0x02,144,7,0, /* Jump if False */ - "JP", 0x02,132,7,0, /* Jump if Plus */ - "JM", 0x02,130,7,0, /* Jump if Minus */ - "JZ", 0x02,129,7,0, /* Jump if Zero */ - "JNP", 0x02,4,7,0, /* Jump if Not Plus */ - "JNM", 0x02,2,7,0, /* Jump if Not Minus */ - "JNZ", 0x02,1,7,0, /* Jump if Not Zero */ - "NOPJ", 0x02,0x80,7,0, /* Never Jump - NOP */ - "B", 0x00,0x00,8,1, /* Branch Unconditional */ - "B", 0x00,0x87,8,1, /* Alternate B */ - "BH", 0x00,0x84,8,1, /* Branch if High */ - "BL", 0x00,0x82,8,1, /* Branch if Low */ - "BE", 0x00,0x81,8,1, /* Branch if Equal */ - "BNH", 0x00,0x04,8,1, /* Branch if Not High */ - "BNL", 0x00,0x02,8,1, /* Branch if Not Low */ - "BNE", 0x00,0x01,8,1, /* Branch if Not Equal */ - "BOZ", 0x00,0x88,8,1, /* Branch if Overflow Zoned */ - "BOL", 0x00,0xA0,8,1, /* Branch if Overflow Logical */ - "BNOZ", 0x00,0x08,8,1, /* Branch if No Overflow Zoned */ - "BNOL", 0x00,0x20,8,1, /* Branch if No Overflow Logical */ - "BT", 0x00,0x10,8,1, /* Branch if True */ - "BF", 0x00,0x90,8,1, /* Branch if False */ - "BP", 0x00,0x84,8,1, /* Branch if Plus */ - "BM", 0x00,0x82,8,1, /* Branch if Minus */ - "BZ", 0x00,0x81,8,1, /* Branch if Zero */ - "BNP", 0x00,0x04,8,1, /* Branch if Not Plus */ - "BNM", 0x00,0x02,8,1, /* Branch if Not Minus */ - "BNZ", 0x00,0x01,8,1, /* Branch if Not Zero */ - "NOPB", 0x00,0x80,8,1, /* Never Branch - NOP */ - "MZZ", 0x08,0,9,2, /* Move Zone to Zone */ - "MNZ", 0x08,1,9,2, /* Move Numeric to Zone */ - "MZN", 0x08,2,9,2, /* Move Zone to Numeric */ - "MNN", 0x08,3,9,2, /* Move Numeric to Numeric */ - "MVX", 0x08,0,2,2, /* Move Hex: MVX BADD,AADD,CODE */ - "JC", 0x02,0,3,0, /* Jump on Specified Condition bits */ - "BC", 0x00,0,3,1, /* Branch on Specified Condition */ - "***", 0x00,0,0,0 + {"HPL", 0x00,0,0,0}, /** Halt Program Level */ + {"A", 0x06,0,1,3}, /** Add to Register: A R,AADD */ + {"ST", 0x04,0,1,3}, /** Store Register */ + {"L", 0x05,0,1,3}, /** Load Register */ + {"LA", 0x02,0,1,1}, /** Load Address */ + {"ZAZ", 0x04,0,2,2}, /** Zero and Add Zoned */ + {"AZ", 0x06,0,2,2}, /** Add Zoned Decimal */ + {"SZ", 0x07,0,2,2}, /** Subtract Zoned Decimal */ + {"ALC", 0x0E,0,2,2}, /** Add Logical: ALC BADD,AADD,LEN */ + {"SLC", 0x0F,0,2,2}, /** Sub Logical: SLC BADD,AADD,LEN */ + {"MVC", 0x0C,0,2,2}, /** Move Chars MVX BADD,AADD,LEN */ + {"ED", 0x0A,0,2,2}, /** Edit: ED BADD,AADD,LEN */ + {"ITC", 0x0B,0,2,2}, /** Insert Chars: ITC BADD,AADD,LEN */ + {"CLC", 0x0D,0,2,2}, /** Compare Logical: CLC BADD,AADD,LEN */ + {"MVI", 0x0C,0,3,3}, /** Move Immediate */ + {"SBN", 0x0A,0,3,3}, /** Set Bits On */ + {"SBF", 0x0B,0,3,3}, /** Set Bits Off */ + {"CLI", 0x0D,0,3,3}, /** Compare Immediate */ + {"TBN", 0x08,0,3,3}, /** Test Bits On */ + {"TBF", 0x09,0,3,3}, /** Test Bits Off */ + {"APL", 0x01,0,4,0}, /** Advance Program Level */ + {"SIO", 0x03,0,5,0}, /** Start I/O */ + {"SNS", 0x00,0,6,3}, /** Sense I/O */ + {"LIO", 0x01,0,6,3}, /** Load I/O */ + {"TIO", 0x01,0,6,1}, /** Test I/O */ + {"J", 0x02,0,7,0}, /** Jump Unconditional */ + {"J", 0x02,0x87,7,0}, /* Alternate J */ + {"JH", 0x02,132,7,0}, /* Jump if High */ + {"JL", 0x02,130,7,0}, /* Jump if Low */ + {"JE", 0x02,129,7,0}, /* Jump if Equal */ + {"JNH", 0x02,4,7,0}, /** Jump if Not High */ + {"JNL", 0x02,2,7,0}, /** Jump if Not Low */ + {"JNE", 0x02,1,7,0}, /** Jump if Not Equal */ + {"JOZ", 0x02,136,7,0}, /* Jump if Overflow Zoned */ + {"JOL", 0x02,160,7,0}, /* Jump if Overflow Logical */ + {"JNOZ", 0x02,8,7,0}, /** Jump if No Overflow Zoned */ + {"JNOL", 0x02,32,7,0}, /* Jump if No Overflow Logical */ + {"JT", 0x02,16,7,0}, /* Jump if True */ + {"JF", 0x02,144,7,0}, /* Jump if False */ + {"JP", 0x02,132,7,0}, /* Jump if Plus */ + {"JM", 0x02,130,7,0}, /* Jump if Minus */ + {"JZ", 0x02,129,7,0}, /* Jump if Zero */ + {"JNP", 0x02,4,7,0}, /** Jump if Not Plus */ + {"JNM", 0x02,2,7,0}, /** Jump if Not Minus */ + {"JNZ", 0x02,1,7,0}, /** Jump if Not Zero */ + {"NOPJ", 0x02,0x80,7,0}, /* Never Jump - NOP */ + {"B", 0x00,0x00,8,1}, /* Branch Unconditional */ + {"B", 0x00,0x87,8,1}, /* Alternate B */ + {"BH", 0x00,0x84,8,1}, /* Branch if High */ + {"BL", 0x00,0x82,8,1}, /* Branch if Low */ + {"BE", 0x00,0x81,8,1}, /* Branch if Equal */ + {"BNH", 0x00,0x04,8,1}, /* Branch if Not High */ + {"BNL", 0x00,0x02,8,1}, /* Branch if Not Low */ + {"BNE", 0x00,0x01,8,1}, /* Branch if Not Equal */ + {"BOZ", 0x00,0x88,8,1}, /* Branch if Overflow Zoned */ + {"BOL", 0x00,0xA0,8,1}, /* Branch if Overflow Logical */ + {"BNOZ", 0x00,0x08,8,1}, /* Branch if No Overflow Zoned */ + {"BNOL", 0x00,0x20,8,1}, /* Branch if No Overflow Logical */ + {"BT", 0x00,0x10,8,1}, /* Branch if True */ + {"BF", 0x00,0x90,8,1}, /* Branch if False */ + {"BP", 0x00,0x84,8,1}, /* Branch if Plus */ + {"BM", 0x00,0x82,8,1}, /* Branch if Minus */ + {"BZ", 0x00,0x81,8,1}, /* Branch if Zero */ + {"BNP", 0x00,0x04,8,1}, /* Branch if Not Plus */ + {"BNM", 0x00,0x02,8,1}, /* Branch if Not Minus */ + {"BNZ", 0x00,0x01,8,1}, /* Branch if Not Zero */ + {"NOPB", 0x00,0x80,8,1}, /* Never Branch - NOP */ + {"MZZ", 0x08,0,9,2}, /** Move Zone to Zone */ + {"MNZ", 0x08,1,9,2}, /** Move Numeric to Zone */ + {"MZN", 0x08,2,9,2}, /** Move Zone to Numeric */ + {"MNN", 0x08,3,9,2}, /** Move Numeric to Numeric */ + {"MVX", 0x08,0,2,2}, /** Move Hex: MVX BADD,AADD,CODE */ + {"JC", 0x02,0,3,0}, /** Jump on Specified Condition bits */ + {"BC", 0x00,0,3,1}, /** Branch on Specified Condition */ + {"***", 0x00,0,0,0} }; int32 regcode[15] = { 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, @@ -225,7 +225,7 @@ char regname[15][8] = { "(P2IAR)", load starts at the current value of the P1IAR. */ -int32 sim_load (FILE *fileref, char *cptr, char *fnam, int flag) +t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag) { int32 i, addr = 0, cnt = 0; @@ -252,7 +252,7 @@ return (SCPE_OK); status = error code */ -int32 fprint_sym (FILE *of, int32 addr, uint32 *val, +t_stat fprint_sym (FILE *of, t_addr addr, uint32 *val, UNIT *uptr, int32 sw) { int32 r; @@ -267,16 +267,15 @@ int32 fprint_sym (FILE *of, int32 addr, uint32 *val, return (r); } -int32 printf_sym (FILE *of, char *strg, int32 addr, uint32 *val, +t_stat printf_sym (FILE *of, char *strg, t_addr addr, uint32 *val, UNIT *uptr, int32 sw) { -int32 cflag, c1, c2, group, len1, len2, inst, aaddr, baddr; +int32 c1, c2, group, len1, len2, inst, aaddr, baddr; int32 oplen, groupno, i, j, vpos, qbyte, da, m, n; char bld[128], bldaddr[32], boperand[32], aoperand[32]; int32 blk[16], blt[16]; int32 blkadd; -cflag = (uptr == NULL) || (uptr == &cpu_unit); c1 = val[0] & 0xff; if (sw & SWMASK ('A')) { for (i = 0; i < 16; i++) { @@ -502,7 +501,7 @@ return -(oplen - 1); status = error status */ -int32 parse_sym (char *cptr, int32 addr, UNIT *uptr, uint32 *val, int32 sw) +t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw) { int32 cflag, i = 0, j, r, oplen, addtyp, saveaddr, vptr; char gbuf[CBUFSIZE]; @@ -924,7 +923,7 @@ switch (opcode[j].form) { /* Get operands based on return (-(oplen-1)); } -char *parse_addr(char *cptr, char *gbuf, int32 *addr, int32 *addrtype) +char *parse_addr(char *cptr, char *gbuf, t_addr *addr, int32 *addrtype) { int32 nybble = 0; char temp[32]; diff --git a/SDS/sds_cpu.c b/SDS/sds_cpu.c index a8f87db7..cde5196b 100644 --- a/SDS/sds_cpu.c +++ b/SDS/sds_cpu.c @@ -39,8 +39,9 @@ X<0:23> X (index) register OV overflow indicator P<0:13> program counter - nml_mode compatible (1) vs 940 (0) mode - usr_mode user (1) vs monitor (0) mode + cpu_mode SDS 930 normal (compatible) mode (0) + SDS 940 monitor mode (1) + SDS 940 user mode (2) RL1<0:23> user map low RL2<0:23> user map high RL4<12:23> monitor map high @@ -168,8 +169,7 @@ uint32 int_reqhi = 0; /* highest int request * uint32 api_lvl = 0; /* api active */ uint32 api_lvlhi = 0; /* highest api active */ t_bool chan_req; /* chan request */ -uint32 nml_mode = 1; /* normal mode */ -uint32 usr_mode = 0; /* user mode */ +uint32 cpu_mode = NML_MODE; /* normal mode */ uint32 mon_usr_trap = 0; /* mon-user trap */ uint32 EM2 = 2, EM3 = 3; /* extension registers */ uint32 RL1, RL2, RL4; /* relocation maps */ @@ -190,13 +190,11 @@ int32 pcq_p = 0; /* PC queue ptr */ REG *pcq_r = NULL; /* PC queue reg ptr */ int32 hst_p = 0; /* history pointer */ int32 hst_lnt = 0; /* history length */ +uint32 hst_exclude = BAD_MODE; /* cpu_mode excluded from history */ InstHistory *hst = NULL; /* instruction history */ int32 rtc_pie = 0; /* rtc pulse ie */ int32 rtc_tps = 60; /* rtc ticks/sec */ -extern int32 sim_int_char; -extern uint32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ - t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw); t_stat cpu_reset (DEVICE *dptr); @@ -217,7 +215,7 @@ void Mul48 (uint32 mplc, uint32 mplr); void Div48 (uint32 dvdh, uint32 dvdl, uint32 dvr); void RotR48 (uint32 sc); void ShfR48 (uint32 sc, uint32 sgn); -t_stat one_inst (uint32 inst, uint32 pc, uint32 mode); +t_stat one_inst (uint32 inst, uint32 pc, uint32 mode, uint32 *trappc); void inst_hist (uint32 inst, uint32 pc, uint32 typ); t_stat rtc_inst (uint32 inst); t_stat rtc_svc (UNIT *uptr); @@ -254,8 +252,7 @@ REG cpu_reg[] = { { ORDATA (RL1, RL1, 24) }, { ORDATA (RL2, RL2, 24) }, { ORDATA (RL4, RL4, 12) }, - { FLDATA (NML, nml_mode, 0) }, - { FLDATA (USR, usr_mode, 0) }, + { ORDATA (MODE, cpu_mode, 2) }, { FLDATA (MONUSR, mon_usr_trap, 0) }, { FLDATA (ION, ion, 0) }, { FLDATA (INTDEF, ion_defer, 0) }, @@ -359,8 +356,7 @@ static const uint32 int_vec[32] = { t_stat sim_instr (void) { -extern int32 sim_interval; -uint32 inst, tinst, pa, save_P, save_mode; +uint32 inst, tinst, pa, save_P, save_mode, trap_P, tmp; t_stat reason, tr; /* Restore register state */ @@ -385,14 +381,14 @@ while (reason == 0) { /* loop until halted */ } if (sim_interval <= 0) { /* event queue? */ - if (reason = sim_process_event ()) /* process */ + if ((reason = sim_process_event ())) /* process */ break; int_reqhi = api_findreq (); /* recalc int req */ chan_req = chan_testact (); /* recalc chan act */ } if (chan_req) { /* channel request? */ - if (reason = chan_process ()) /* process */ + if ((reason = chan_process ())) /* process */ break; int_reqhi = api_findreq (); /* recalc int req */ chan_req = chan_testact (); /* recalc chan act */ @@ -406,14 +402,14 @@ while (reason == 0) { /* loop until halted */ break; } tinst = ReadP (pa); /* get inst */ - save_mode = usr_mode; /* save mode */ - usr_mode = 0; /* switch to mon */ + save_mode = cpu_mode; /* save mode */ + cpu_mode = MON_MODE; /* switch to mon */ if (hst_lnt) /* record inst */ inst_hist (tinst, P, HIST_INT); if (pa != VEC_RTCP) { /* normal intr? */ - tr = one_inst (tinst, P, save_mode); /* exec intr inst */ + tr = one_inst (tinst, P, save_mode, &tmp); /* exec intr inst */ if (tr) { /* stop code? */ - usr_mode = save_mode; /* restore mode */ + cpu_mode = save_mode; /* restore mode */ reason = (tr > 0)? tr: STOP_MMINT; break; } @@ -422,7 +418,7 @@ while (reason == 0) { /* loop until halted */ } else { /* clock intr */ tr = rtc_inst (tinst); /* exec RTC inst */ - usr_mode = save_mode; /* restore mode */ + cpu_mode = save_mode; /* restore mode */ if (tr) { /* stop code? */ reason = (tr > 0)? tr: STOP_MMINT; break; @@ -432,9 +428,31 @@ while (reason == 0) { /* loop until halted */ int_reqhi = api_findreq (); /* recalc int req */ } else { /* normal instr */ - if (sim_brk_summ && sim_brk_test (P, SWMASK ('E'))) { /* breakpoint? */ - reason = STOP_IBKPT; /* stop simulation */ - break; + if (sim_brk_summ) { + static uint32 bmask[] = {SWMASK ('E') | SWMASK ('N'), + SWMASK ('E') | SWMASK ('M'), + SWMASK ('E') | SWMASK ('U')}; + uint32 btyp; + + btyp = sim_brk_test (P, bmask[cpu_mode]); + if (btyp) { + if (btyp & SWMASK ('E')) /* unqualified breakpoint? */ + reason = STOP_IBKPT; /* stop simulation */ + // else if (btyp & BRK_TYP_DYN_STEPOVER) /* stepover breakpoint? */ + // reason = STOP_DBKPT; /* stop simulation */ + else switch (btyp) { /* qualified breakpoint */ + case SWMASK ('M'): /* monitor mode */ + reason = STOP_MBKPT; /* stop simulation */ + break; + case SWMASK ('N'): /* normal (SDS 930) mode */ + reason = STOP_NBKPT; /* stop simulation */ + break; + case SWMASK ('U'): /* user mode */ + reason = STOP_UBKPT; /* stop simulation */ + break; + } + break; + } } reason = Read (save_P = P, &inst); /* get instr */ P = (P + 1) & VA_MASK; /* incr PC */ @@ -442,7 +460,7 @@ while (reason == 0) { /* loop until halted */ ion_defer = 0; /* clear ion */ if (hst_lnt) inst_hist (inst, save_P, HIST_XCT); - reason = one_inst (inst, save_P, usr_mode); /* exec inst */ + reason = one_inst (inst, save_P, cpu_mode, &trap_P); /* exec inst */ if (reason > 0) { /* stop code? */ if (reason != STOP_HALT) P = save_P; @@ -451,25 +469,35 @@ while (reason == 0) { /* loop until halted */ } } /* end if r == 0 */ if (reason < 0) { /* mm (fet or ex)? */ + int8 op; pa = -reason; /* get vector */ - reason = 0; /* defang */ + if (reason == MM_MONUSR) /* record P of user-mode */ + save_P = P; /* transition point */ tinst = ReadP (pa); /* get inst */ - if (I_GETOP (tinst) != BRM) { /* not BRM? */ + op = I_GETOP (tinst); + if (op != BRM && op != BRU) { /* not BRM or BRU? */ reason = STOP_TRPINS; /* fatal err */ break; } - save_mode = usr_mode; /* save mode */ - usr_mode = 0; /* switch to mon */ + save_mode = cpu_mode; /* save mode */ + cpu_mode = MON_MODE; /* switch to mon */ mon_usr_trap = 0; if (hst_lnt) inst_hist (tinst, save_P, HIST_TRP); - tr = one_inst (tinst, save_P, save_mode); /* trap inst */ + + /* Use previously recorded trap address if memory acccess trap. + Will differ from save_P if trapped instruction was a branch. + See page 17 of 940 reference manual for additional info. + */ + tr = one_inst (tinst, (reason == MM_NOACC)? + trap_P: save_P, save_mode, &tmp); /* trap address */ if (tr) { /* stop code? */ - usr_mode = save_mode; /* restore mode */ + cpu_mode = save_mode; /* restore mode */ P = save_P; /* restore PC */ reason = (tr > 0)? tr: STOP_MMTRP; break; } + reason = 0; /* defang */ } /* end if reason */ } /* end else int */ } /* end while */ @@ -482,38 +510,42 @@ return reason; /* Simulate one instruction */ -t_stat one_inst (uint32 inst, uint32 pc, uint32 mode) +t_stat one_inst (uint32 inst, uint32 pc, uint32 mode, uint32 *trappc) { uint32 op, shf_op, va, dat; uint32 old_A, old_B, old_X; int32 i, exu_cnt, sc; t_stat r; +*trappc = pc; /* default trap pc to pc */ exu_cnt = 0; /* init EXU count */ EXU_LOOP: op = I_GETOP (inst); /* get opcode */ if (inst & I_POP) { /* POP? */ dat = (EM3 << 18) | (EM2 << 15) | I_IND | pc; /* data to save */ - if (nml_mode) { /* normal mode? */ + switch (cpu_mode) + { + case NML_MODE: dat = (OV << 23) | dat; /* ov in <0> */ WriteP (0, dat); - } - else if (usr_mode) { /* user mode? */ + break; + case USR_MODE: if (inst & I_USR) { /* SYSPOP? */ dat = I_USR | (OV << 21) | dat; /* ov in <2> */ WriteP (0, dat); - usr_mode = 0; /* set mon mode */ + cpu_mode = MON_MODE; /* set mon mode */ } else { /* normal POP */ dat = (OV << 23) | dat; /* ov in <0> */ - if (r = Write (0, dat)) + if ((r = Write (0, dat))) return r; } - } - else { /* mon mode */ + break; + case MON_MODE: dat = (OV << 21) | dat; /* ov in <2> */ WriteP (0, dat); /* store return */ - } + break; + } PCQ_ENTRY; /* save PC */ P = 0100 | op; /* new PC */ OV = 0; /* clear ovflo */ @@ -525,61 +557,61 @@ switch (op) { /* case on opcode */ /* Loads and stores */ case LDA: - if (r = Ea (inst, &va)) /* decode eff addr */ + if ((r = Ea (inst, &va))) /* decode eff addr */ return r; - if (r = Read (va, &A)) /* get operand */ + if ((r = Read (va, &A))) /* get operand */ return r; break; case LDB: - if (r = Ea (inst, &va)) /* decode eff addr */ + if ((r = Ea (inst, &va))) /* decode eff addr */ return r; - if (r = Read (va, &B)) /* get operand */ + if ((r = Read (va, &B))) /* get operand */ return r; break; case LDX: - if (r = Ea (inst, &va)) /* decode eff addr */ + if ((r = Ea (inst, &va))) /* decode eff addr */ return r; - if (r = Read (va, &X)) /* get operand */ + if ((r = Read (va, &X))) /* get operand */ return r; break; case STA: - if (r = Ea (inst, &va)) /* decode eff addr */ + if ((r = Ea (inst, &va))) /* decode eff addr */ return r; - if (r = Write (va, A)) /* write operand */ + if ((r = Write (va, A))) /* write operand */ return r; break; case STB: - if (r = Ea (inst, &va)) /* decode eff addr */ + if ((r = Ea (inst, &va))) /* decode eff addr */ return r; - if (r = Write (va, B)) /* write operand */ + if ((r = Write (va, B))) /* write operand */ return r; break; case STX: - if (r = Ea (inst, &va)) /* decode eff addr */ + if ((r = Ea (inst, &va))) /* decode eff addr */ return r; - if (r = Write (va, X)) /* write operand */ + if ((r = Write (va, X))) /* write operand */ return r; break; case EAX: - if (r = Ea (inst, &va)) /* decode eff addr */ + if ((r = Ea (inst, &va))) /* decode eff addr */ return r; - if (nml_mode || usr_mode) /* normal or user? */ + if (cpu_mode != MON_MODE) /* normal or user? */ X = (X & ~VA_MASK) | (va & VA_MASK); /* only 14b */ else X = (X & ~XVA_MASK) | (va & XVA_MASK); /* mon, 15b */ break; case XMA: - if (r = Ea (inst, &va)) /* decode eff addr */ + if ((r = Ea (inst, &va))) /* decode eff addr */ return r; - if (r = Read (va, &dat)) /* get operand */ + if ((r = Read (va, &dat))) /* get operand */ return r; - if (r = Write (va, A)) /* write A */ + if ((r = Write (va, A))) /* write A */ return r; A = dat; /* load A */ break; @@ -587,95 +619,95 @@ switch (op) { /* case on opcode */ /* Arithmetic and logical */ case ADD: - if (r = Ea (inst, &va)) /* decode eff addr */ + if ((r = Ea (inst, &va))) /* decode eff addr */ return r; - if (r = Read (va, &dat)) /* get operand */ + if ((r = Read (va, &dat))) /* get operand */ return r; A = Add24 (A, dat, 0); /* add */ break; case ADC: - if (r = Ea (inst, &va)) /* decode eff addr */ + if ((r = Ea (inst, &va))) /* decode eff addr */ return r; - if (r = Read (va, &dat)) /* get operand */ + if ((r = Read (va, &dat))) /* get operand */ return r; OV = 0; /* clear overflow */ A = Add24 (A, dat, X >> 23); /* add with carry */ break; case SUB: - if (r = Ea (inst, &va)) /* decode eff addr */ + if ((r = Ea (inst, &va))) /* decode eff addr */ return r; - if (r = Read (va, &dat)) /* get operand */ + if ((r = Read (va, &dat))) /* get operand */ return r; A = Add24 (A, dat ^ DMASK, 1); /* subtract */ break; case SUC: - if (r = Ea (inst, &va)) /* decode eff addr */ + if ((r = Ea (inst, &va))) /* decode eff addr */ return r; - if (r = Read (va, &dat)) /* get operand */ + if ((r = Read (va, &dat))) /* get operand */ return r; OV = 0; /* clear overflow */ A = Add24 (A, dat ^ DMASK, X >> 23); /* sub with carry */ break; case ADM: - if (r = Ea (inst, &va)) /* decode eff addr */ + if ((r = Ea (inst, &va))) /* decode eff addr */ return r; - if (r = Read (va, &dat)) /* get operand */ + if ((r = Read (va, &dat))) /* get operand */ return r; dat = AddM24 (dat, A); /* mem + A */ - if (r = Write (va, dat)) /* rewrite */ + if ((r = Write (va, dat))) /* rewrite */ return r; break; case MIN: - if (r = Ea (inst, &va)) /* decode eff addr */ + if ((r = Ea (inst, &va))) /* decode eff addr */ return r; - if (r = Read (va, &dat)) /* get operand */ + if ((r = Read (va, &dat))) /* get operand */ return r; dat = AddM24 (dat, 1); /* mem + 1 */ - if (r = Write (va, dat)) /* rewrite */ + if ((r = Write (va, dat))) /* rewrite */ return r; break; case MUL: - if (r = Ea (inst, &va)) /* decode eff addr */ + if ((r = Ea (inst, &va))) /* decode eff addr */ return r; - if (r = Read (va, &dat)) /* get operand */ + if ((r = Read (va, &dat))) /* get operand */ return r; Mul48 (A, dat); /* multiply */ break; case DIV: - if (r = Ea (inst, &va)) /* decode eff addr */ + if ((r = Ea (inst, &va))) /* decode eff addr */ return r; - if (r = Read (va, &dat)) /* get operand */ + if ((r = Read (va, &dat))) /* get operand */ return r; Div48 (A, B, dat); /* divide */ break; case ETR: - if (r = Ea (inst, &va)) /* decode eff addr */ + if ((r = Ea (inst, &va))) /* decode eff addr */ return r; - if (r = Read (va, &dat)) /* get operand */ + if ((r = Read (va, &dat))) /* get operand */ return r; A = A & dat; /* and */ break; case MRG: - if (r = Ea (inst, &va)) /* decode eff addr */ + if ((r = Ea (inst, &va))) /* decode eff addr */ return r; - if (r = Read (va, &dat)) /* get operand */ + if ((r = Read (va, &dat))) /* get operand */ return r; A = A | dat; /* or */ break; case EOR: - if (r = Ea (inst, &va)) /* decode eff addr */ + if ((r = Ea (inst, &va))) /* decode eff addr */ return r; - if (r = Read (va, &dat)) /* get operand */ + if ((r = Read (va, &dat))) /* get operand */ return r; A = A ^ dat; /* xor */ break; @@ -683,75 +715,75 @@ switch (op) { /* case on opcode */ /* Skips */ case SKE: - if (r = Ea (inst, &va)) /* decode eff addr */ + if ((r = Ea (inst, &va))) /* decode eff addr */ return r; - if (r = Read (va, &dat)) /* get operand */ + if ((r = Read (va, &dat))) /* get operand */ return r; if (A == dat) /* if A = op, skip */ P = (P + 1) & VA_MASK; break; case SKG: - if (r = Ea (inst, &va)) /* decode eff addr */ + if ((r = Ea (inst, &va))) /* decode eff addr */ return r; - if (r = Read (va, &dat)) /* get operand */ + if ((r = Read (va, &dat))) /* get operand */ return r; if (SXT (A) > SXT (dat)) /* if A > op, skip */ P = (P + 1) & VA_MASK; break; case SKM: - if (r = Ea (inst, &va)) /* decode eff addr */ + if ((r = Ea (inst, &va))) /* decode eff addr */ return r; - if (r = Read (va, &dat)) /* get operand */ + if ((r = Read (va, &dat))) /* get operand */ return r; if (((A ^ dat) & B) == 0) /* if A = op masked */ P = (P + 1) & VA_MASK; break; case SKA: - if (r = Ea (inst, &va)) /* decode eff addr */ + if ((r = Ea (inst, &va))) /* decode eff addr */ return r; - if (r = Read (va, &dat)) /* get operand */ + if ((r = Read (va, &dat))) /* get operand */ return r; if ((A & dat) == 0) /* if !(A & op), skip */ P = (P + 1) & VA_MASK; break; case SKB: - if (r = Ea (inst, &va)) /* decode eff addr */ + if ((r = Ea (inst, &va))) /* decode eff addr */ return r; - if (r = Read (va, &dat)) /* get operand */ + if ((r = Read (va, &dat))) /* get operand */ return r; if ((B & dat) == 0) /* if !(B & op), skip */ P = (P + 1) & VA_MASK; break; case SKN: - if (r = Ea (inst, &va)) /* decode eff addr */ + if ((r = Ea (inst, &va))) /* decode eff addr */ return r; - if (r = Read (va, &dat)) /* get operand */ + if ((r = Read (va, &dat))) /* get operand */ return r; if (dat & SIGN) /* if op < 0, skip */ P = (P + 1) & VA_MASK; break; case SKR: - if (r = Ea (inst, &va)) /* decode eff addr */ + if ((r = Ea (inst, &va))) /* decode eff addr */ return r; - if (r = Read (va, &dat)) /* get operand */ + if ((r = Read (va, &dat))) /* get operand */ return r; dat = AddM24 (dat, DMASK); /* decr operand */ - if (r = Write (va, dat)) /* rewrite */ + if ((r = Write (va, dat))) /* rewrite */ return r; if (dat & SIGN) /* if op < 0, skip */ P = (P + 1) & VA_MASK; break; case SKD: - if (r = Ea (inst, &va)) /* decode eff addr */ + if ((r = Ea (inst, &va))) /* decode eff addr */ return r; - if (r = Read (va, &dat)) /* get operand */ + if ((r = Read (va, &dat))) /* get operand */ return r; if (SXT_EXP (B) < SXT_EXP (dat)) { /* B < dat? */ X = (dat - B) & DMASK; /* X = dat - B */ @@ -766,7 +798,7 @@ switch (op) { /* case on opcode */ break; case HLT: - if (!nml_mode && usr_mode) /* priv inst */ + if (cpu_mode == USR_MODE) /* priv inst */ return MM_PRVINS; return STOP_HALT; /* halt CPU */ @@ -774,59 +806,91 @@ switch (op) { /* case on opcode */ exu_cnt = exu_cnt + 1; /* count chained EXU */ if (exu_cnt > exu_lim) /* too many? */ return STOP_EXULIM; - if (r = Ea (inst, &va)) /* decode eff addr */ + if ((r = Ea (inst, &va))) /* decode eff addr */ return r; - if (r = Read (va, &dat)) /* get operand */ + if ((r = Read (va, &dat))) /* get operand */ return r; inst = dat; goto EXU_LOOP; - + case BRU: - if (nml_mode && (inst & I_IND)) api_dismiss (); /* normal BRU*, dism */ - if (r = Ea (inst, &va)) /* decode eff addr */ + if ((cpu_mode == NML_MODE) && (inst & I_IND)) + api_dismiss (); /* normal-mode BRU*, dism */ + if ((r = Ea (inst, &va))) /* decode eff addr */ return r; - if (r = Read (va, &dat)) /* get operand */ + if ((r = Read (va, &dat))) /* get operand */ + { + if (r == MM_NOACC) + *trappc = va & VA_MASK; /* use target as trap adr */ return r; + } PCQ_ENTRY; P = va & VA_MASK; /* branch */ + if ((va & VA_USR) && (cpu_mode == MON_MODE)) { /* user ref from mon. mode? */ + cpu_mode = USR_MODE; /* transition to user mode */ + if (mon_usr_trap) + return MM_MONUSR; + } break; case BRX: - if (r = Ea (inst, &va)) /* decode eff addr */ + if ((r = Ea (inst, &va))) /* decode eff addr */ return r; X = (X + 1) & DMASK; /* incr X */ if (X & I_IND) { /* bit 9 set? */ - if (r = Read (va, &dat)) /* test dest access */ + if ((r = Read (va, &dat))) /* test dest access */ + { + if (r == MM_NOACC) + *trappc = va & VA_MASK; /* use target as trap adr */ return r; + } PCQ_ENTRY; P = va & VA_MASK; /* branch */ + if ((va & VA_USR) && (cpu_mode == MON_MODE)) { /* user ref from mon. mode? */ + cpu_mode = USR_MODE; /* transition to user mode */ + if (mon_usr_trap) + return MM_MONUSR; + } } break; case BRM: - if (r = Ea (inst, &va)) /* decode eff addr */ + if ((r = Ea (inst, &va))) /* decode eff addr */ return r; dat = (EM3 << 18) | (EM2 << 15) | pc; /* form return word */ - if (!nml_mode && !usr_mode) /* monitor mode? */ - dat = dat | (mode << 23) | (OV << 21); + if (cpu_mode == MON_MODE) /* monitor mode? */ + dat = dat | ((mode == USR_MODE) << 23) | (OV << 21); else dat = dat | (OV << 23); /* normal or user */ - if (r = Write (va, dat)) /* write ret word */ + if ((r = Write (va, dat))) /* write ret word */ + { + if (r == MM_NOACC) + *trappc = va & VA_MASK; /* use target as trap adr */ return r; + } PCQ_ENTRY; P = (va + 1) & VA_MASK; /* branch */ + if ((va & VA_USR) && (cpu_mode == MON_MODE)) { /* user ref from mon. mode? */ + cpu_mode = USR_MODE; /* transition to user mode */ + if (mon_usr_trap) + return MM_MONUSR; + } break; case BRR: - if (r = Ea (inst, &va)) /* decode eff addr */ + if ((r = Ea (inst, &va))) /* decode eff addr */ return r; - if (r = Read (va, &dat)) /* get operand */ + if ((r = Read (va, &dat))) /* get operand */ + { + if (r == MM_NOACC) + *trappc = va & VA_MASK; /* use target as trap adr */ return r; + } PCQ_ENTRY; P = (dat + 1) & VA_MASK; /* branch */ - if (!nml_mode && !usr_mode) { /* monitor mode? */ + if (cpu_mode == MON_MODE) { /* monitor mode? */ OV = OV | ((dat >> 21) & 1); /* restore OV */ if ((va & VA_USR) | (dat & I_USR)) { /* mode change? */ - usr_mode = 1; + cpu_mode = USR_MODE; if (mon_usr_trap) return MM_MONUSR; } @@ -835,19 +899,23 @@ switch (op) { /* case on opcode */ break; case BRI: - if (!nml_mode && usr_mode) /* priv inst */ + if (cpu_mode == USR_MODE) /* priv inst */ return MM_PRVINS; - if (r = Ea (inst, &va)) /* decode eff addr */ + if ((r = Ea (inst, &va))) /* decode eff addr */ return r; - if (r = Read (va, &dat)) /* get operand */ + if ((r = Read (va, &dat))) /* get operand */ + { + if (r == MM_NOACC) + *trappc = va & VA_MASK; /* use target as trap adr */ return r; + } api_dismiss (); /* dismiss hi api */ PCQ_ENTRY; P = dat & VA_MASK; /* branch */ - if (!nml_mode) { /* monitor mode? */ + if (cpu_mode == MON_MODE) { /* monitor mode? */ OV = (dat >> 21) & 1; /* restore OV */ if ((va & VA_USR) | (dat & I_USR)) { /* mode change? */ - usr_mode = 1; + cpu_mode = USR_MODE; if (mon_usr_trap) return MM_MONUSR; } @@ -898,7 +966,7 @@ switch (op) { /* case on opcode */ /* Overflow instruction */ case OVF: - if ((inst & 0100) & OV) + if ((inst & 0100) && !OV) P = (P + 1) & VA_MASK; if (inst & 0001) OV = 0; @@ -909,7 +977,7 @@ switch (op) { /* case on opcode */ /* Shifts */ case RSH: - if (r = EaSh (inst, &va)) /* decode eff addr */ + if ((r = EaSh (inst, &va))) /* decode eff addr */ return r; shf_op = I_GETSHFOP (va); /* get eff op */ sc = va & I_SHFMSK; /* get eff count */ @@ -934,7 +1002,7 @@ switch (op) { /* case on opcode */ break; case LSH: - if (r = EaSh (inst, &va)) /* decode eff addr */ + if ((r = EaSh (inst, &va))) /* decode eff addr */ return r; shf_op = I_GETSHFOP (va); /* get eff op */ sc = va & I_SHFMSK; /* get eff count */ @@ -987,35 +1055,35 @@ switch (op) { /* case on opcode */ /* I/O instructions */ case MIW: case MIY: - if (!nml_mode && usr_mode) /* priv inst */ + if (cpu_mode == USR_MODE) /* priv inst */ return MM_PRVINS; - if (r = Ea (inst, &va)) /* decode eff addr */ + if ((r = Ea (inst, &va))) /* decode eff addr */ return r; - if (r = Read (va, &dat)) /* get operand */ + if ((r = Read (va, &dat))) /* get operand */ return r; - if (r = op_miwy (inst, dat)) /* process inst */ + if ((r = op_miwy (inst, dat))) /* process inst */ return r; int_reqhi = api_findreq (); /* recalc int req */ chan_req = chan_testact (); /* recalc chan act */ break; case WIM: case YIM: - if (!nml_mode && usr_mode) /* priv inst */ + if (cpu_mode == USR_MODE) /* priv inst */ return MM_PRVINS; - if (r = Ea (inst, &va)) /* decode eff addr */ + if ((r = Ea (inst, &va))) /* decode eff addr */ return r; - if (r = op_wyim (inst, &dat)) /* process inst */ + if ((r = op_wyim (inst, &dat))) /* process inst */ return r; - if (r = Write (va, dat)) + if ((r = Write (va, dat))) return r; /* write result */ int_reqhi = api_findreq (); /* recalc int req */ chan_req = chan_testact (); /* recalc chan act */ break; case EOM: case EOD: - if (!nml_mode && usr_mode) /* priv inst */ + if (cpu_mode == USR_MODE) /* priv inst */ return MM_PRVINS; - if (r = op_eomd (inst)) /* process inst */ + if ((r = op_eomd (inst))) /* process inst */ return r; int_reqhi = api_findreq (); /* recalc int req */ chan_req = chan_testact (); /* recalc chan act */ @@ -1023,42 +1091,42 @@ switch (op) { /* case on opcode */ break; case POT: - if (!nml_mode && usr_mode) /* priv inst */ + if (cpu_mode == USR_MODE) /* priv inst */ return MM_PRVINS; - if (r = Ea (inst, &va)) /* decode eff addr */ + if ((r = Ea (inst, &va))) /* decode eff addr */ return r; - if (r = Read (va, &dat)) /* get operand */ + if ((r = Read (va, &dat))) /* get operand */ return r; - if (r = op_pot (dat)) /* process inst */ + if ((r = op_pot (dat))) /* process inst */ return r; int_reqhi = api_findreq (); /* recalc int req */ chan_req = chan_testact (); /* recalc chan act */ break; case PIN: - if (!nml_mode && usr_mode) /* priv inst */ + if (cpu_mode == USR_MODE) /* priv inst */ return MM_PRVINS; - if (r = Ea (inst, &va)) /* decode eff addr */ + if ((r = Ea (inst, &va))) /* decode eff addr */ return r; - if (r = op_pin (&dat)) /* process inst */ + if ((r = op_pin (&dat))) /* process inst */ return r; - if (r = Write (va, dat)) /* write result */ + if ((r = Write (va, dat))) /* write result */ return r; int_reqhi = api_findreq (); /* recalc int req */ chan_req = chan_testact (); /* recalc chan act */ break; case SKS: - if (!nml_mode && usr_mode) /* priv inst */ + if (cpu_mode == USR_MODE) /* priv inst */ return MM_PRVINS; - if (r = op_sks (inst, &dat)) /* process inst */ + if ((r = op_sks (inst, &dat))) /* process inst */ return r; if (dat) P = (P + 1) & VA_MASK; break; default: - if (!nml_mode && usr_mode) /* priv inst */ + if (cpu_mode == USR_MODE) /* priv inst */ return MM_PRVINS; CRETINS; /* invalid inst */ break; @@ -1085,7 +1153,7 @@ for (i = 0; i < ind_lim; i++) { /* count indirects */ hst[hst_p].ea = *addr; return SCPE_OK; } - if (r = Read (va, &wd)) /* read ind; fails? */ + if ((r = Read (va, &wd))) /* read ind; fails? */ return r; va = (va & VA_USR) | (wd & XVA_MASK); } @@ -1112,7 +1180,7 @@ for (i = 0; i < ind_lim; i++) { /* count indirects */ } if (wd & I_IDX) va = (va & VA_USR) | ((va + X) & VA_MASK); - if (r = Read (va, &wd)) /* read ind; fails? */ + if ((r = Read (va, &wd))) /* read ind; fails? */ return r; va = (va & VA_USR) | (wd & XVA_MASK); } @@ -1125,7 +1193,7 @@ t_stat Read (uint32 va, uint32 *dat) { uint32 pgn, map, pa; -if (nml_mode) { /* normal? */ +if (cpu_mode == NML_MODE) { /* normal? */ va = va & VA_MASK; /* ignore user */ if (va < 020000) /* first 8K: 1 for 1 */ pa = va; @@ -1133,7 +1201,7 @@ if (nml_mode) { /* normal? */ pa = va + em2_dyn; else pa = va + em3_dyn; /* next 4K: ext EM3 */ } -else if (usr_mode || (va & VA_USR)) { /* user mapping? */ +else if ((cpu_mode == USR_MODE) || (va & VA_USR)) { /* user mapping? */ pgn = VA_GETPN (va); /* get page no */ map = usr_map[pgn]; /* get map entry */ if (map == MAP_PROT) /* prot? no access */ @@ -1157,7 +1225,7 @@ t_stat Write (uint32 va, uint32 dat) { uint32 pgn, map, pa; -if (nml_mode) { /* normal? */ +if (cpu_mode == NML_MODE) { /* normal? */ va = va & VA_MASK; /* ignore user */ if (va < 020000) /* first 8K: 1 for 1 */ pa = va; @@ -1165,7 +1233,7 @@ if (nml_mode) { /* normal? */ pa = va + em2_dyn; else pa = va + em3_dyn; /* next 4K: ext EM3 */ } -else if (usr_mode || (va & VA_USR)) { /* user mapping? */ +else if ((cpu_mode == USR_MODE) || (va & VA_USR)) { /* user mapping? */ pgn = VA_GETPN (va); /* get page no */ map = usr_map[pgn]; /* get map entry */ if (map & MAP_PROT) { /* protected page? */ @@ -1191,21 +1259,20 @@ return SCPE_OK; uint32 RelocC (int32 va, int32 sw) { -uint32 nml = nml_mode, usr = usr_mode; +uint32 mode = cpu_mode; uint32 pa, pgn, map; if (sw & SWMASK ('N')) /* -n: normal */ - nml = 1; + mode = NML_MODE; else if (sw & SWMASK ('X')) /* -x: mon */ - nml = usr = 0; + mode = MON_MODE; else if (sw & SWMASK ('U')) { /* -u: user */ - nml = 0; - usr = 1; + mode = USR_MODE; } else if (!(sw & SWMASK ('V'))) /* -v: curr */ return va; set_dyn_map (); -if (nml) { /* normal? */ +if (mode == NML_MODE) { /* normal? */ if (va < 020000) /* first 8K: 1 for 1 */ pa = va; else if (va < 030000) /* next 4K: ext EM2 */ @@ -1214,7 +1281,7 @@ if (nml) { /* normal? */ } else { pgn = VA_GETPN (va); /* get page no */ - map = usr? usr_map[pgn]: mon_map[pgn]; /* get map entry */ + map = (mode == USR_MODE)? usr_map[pgn]: mon_map[pgn]; /* get map entry */ if (map == MAP_PROT) /* no access page? */ return MAXMEMSIZE + 1; pa = (map & ~MAP_PROT) | (va & VA_POFF); /* map address */ @@ -1273,7 +1340,7 @@ return; /* Divide - the SDS 940 uses a non-restoring divide. The algorithm runs even for overflow cases. Hence it must be emulated precisely - to give the right answers for diagnostics. If the dividend is + to give the right answers for diagnostics. If the dividend is negative, AB are 2's complemented starting at B<22>, and B<23> is unchanged. */ @@ -1341,7 +1408,7 @@ if (sc >= 24) { A = sgn; } else { - B = ((B >> sc) | (A << (24 - sc)) & DMASK); + B = ((B >> sc) | (A << (24 - sc))) & DMASK; A = ((A >> sc) | (sgn << (24 - sc))) & DMASK; } return; @@ -1448,8 +1515,7 @@ EM2 = 2; EM3 = 3; RL1 = RL2 = RL4 = 0; ion = ion_defer = 0; -nml_mode = 1; -usr_mode = 0; +cpu_mode = NML_MODE; mon_usr_trap = 0; int_req = 0; int_reqhi = 0; @@ -1460,7 +1526,8 @@ pcq_r = find_reg ("PCQ", NULL, dptr); if (pcq_r) pcq_r->qptr = 0; else return SCPE_IERR; -sim_brk_types = sim_brk_dflt = SWMASK ('E'); +sim_brk_dflt = SWMASK ('E'); +sim_brk_types = SWMASK ('E') | SWMASK ('M') | SWMASK ('N') | SWMASK ('U'); return SCPE_OK; } @@ -1552,7 +1619,8 @@ t_stat rtc_svc (UNIT *uptr) { if (rtc_pie) /* set pulse intr */ int_req = int_req | INT_RTCP; -sim_activate (&rtc_unit, sim_rtcn_calb (rtc_tps, TMR_RTC)); /* reactivate */ +rtc_unit.wait = sim_rtcn_calb (rtc_tps, TMR_RTC); /* calibrate */ +sim_activate (&rtc_unit, rtc_unit.wait); /* reactivate */ return SCPE_OK; } @@ -1569,14 +1637,14 @@ if (op == MIN) /* incr */ else if (op == SKR) /* decr */ val = DMASK; else return STOP_RTCINS; /* can't do it */ -if (r = Ea (inst, &va)) /* decode eff addr */ +if ((r = Ea (inst, &va))) /* decode eff addr */ return r; -if (r = Read (va, &dat)) /* get operand */ +if ((r = Read (va, &dat))) /* get operand */ return r; dat = AddM24 (dat, val); /* mem +/- 1 */ -if (r = Write (va, dat)) /* rewrite */ +if ((r = Write (va, dat))) /* rewrite */ return r; -if (dat == 0) /* set clk sync int */ +if ((op == MIN && dat == 0) || (dat & SIGN)) /* set clk sync int */ int_req = int_req | INT_RTCS; return SCPE_OK; } @@ -1586,6 +1654,7 @@ return SCPE_OK; t_stat rtc_reset (DEVICE *dptr) { rtc_pie = 0; /* disable pulse */ +rtc_unit.wait = sim_rtcn_init (rtc_unit.wait, TMR_RTC); /* initialize clock calibration */ sim_activate (&rtc_unit, rtc_unit.wait); /* activate unit */ return SCPE_OK; } @@ -1614,10 +1683,12 @@ return SCPE_OK; void inst_hist (uint32 ir, uint32 pc, uint32 tp) { +if (cpu_mode == hst_exclude) + return; hst_p = (hst_p + 1); /* next entry */ if (hst_p >= hst_lnt) hst_p = 0; -hst[hst_p].typ = tp | (OV << 4); +hst[hst_p].typ = tp | (OV << 4) | (cpu_mode << 5); hst[hst_p].pc = pc; hst[hst_p].ir = ir; hst[hst_p].a = A; @@ -1644,6 +1715,14 @@ lnt = (int32) get_uint (cptr, 10, HIST_MAX, &r); if ((r != SCPE_OK) || (lnt && (lnt < HIST_MIN))) return SCPE_ARG; hst_p = 0; +if (sim_switches & SWMASK('M')) + hst_exclude = MON_MODE; +else if (sim_switches & SWMASK('N')) + hst_exclude = NML_MODE; +else if (sim_switches & SWMASK('U')) + hst_exclude = USR_MODE; +else + hst_exclude = BAD_MODE; if (hst_lnt) { free (hst); hst_lnt = 0; @@ -1667,9 +1746,8 @@ char *cptr = (char *) desc; t_stat r; t_value sim_eval; InstHistory *h; -extern t_stat fprint_sym (FILE *ofile, t_addr addr, t_value *val, - UNIT *uptr, int32 sw); static char *cyc[] = { " ", " ", "INT", "TRP" }; +static char *modes = "NMU?"; if (hst_lnt == 0) /* enabled? */ return SCPE_NOFNC; @@ -1682,13 +1760,13 @@ else lnt = hst_lnt; di = hst_p - lnt; /* work forward */ if (di < 0) di = di + hst_lnt; -fprintf (st, "CYC PC OV A B X EA IR\n\n"); +fprintf (st, "CYC PC MD OV A B X EA IR\n\n"); for (k = 0; k < lnt; k++) { /* print specified */ h = &hst[(++di) % hst_lnt]; /* entry pointer */ if (h->typ) { /* instruction? */ ov = (h->typ >> 4) & 1; /* overflow */ - fprintf (st, "%s %05o %o %08o %08o %08o ", cyc[h->typ & 3], - h->pc, ov, h->a, h->b, h->x); + fprintf (st, "%s %05o %c %o %08o %08o %08o ", cyc[h->typ & 3], + h->pc, modes[(h->typ >> 5) & 3], ov, h->a, h->b, h->x); if (h->ea & HIST_NOEA) fprintf (st, " "); else fprintf (st, "%05o ", h->ea); diff --git a/SDS/sds_defs.h b/SDS/sds_defs.h index a74ec36f..6654a73b 100644 --- a/SDS/sds_defs.h +++ b/SDS/sds_defs.h @@ -1,4 +1,4 @@ -/* sds_defs.h: SDS 940 simulator definitions +/* sds_defs.h: SDS 940 simulator definitions Copyright (c) 2001-2010, Robert M. Supnik @@ -27,8 +27,8 @@ 25-Apr-03 RMS Revised for extended file support */ -#ifndef _SDS_DEFS_H_ -#define _SDS_DEFS_H_ 0 +#ifndef SDS_DEFS_H_ +#define SDS_DEFS_H_ 0 #include "sim_defs.h" /* simulator defns */ @@ -48,10 +48,15 @@ #define STOP_EXULIM 8 /* EXU limit */ #define STOP_MMINT 9 /* mm in intr */ #define STOP_MMTRP 10 /* mm in trap */ -#define STOP_TRPINS 11 /* trap inst not BRM */ -#define STOP_RTCINS 12 /* rtc inst not MIN/SKR */ +#define STOP_TRPINS 11 /* trap inst not BRM or BRU */ +#define STOP_RTCINS 12 /* rtc inst not MIN or SKR */ #define STOP_ILLVEC 13 /* zero vector */ #define STOP_CCT 14 /* runaway CCT */ +#define STOP_MBKPT 15 /* monitor-mode breakpoint */ +#define STOP_NBKPT 16 /* normal-mode breakpoint */ +#define STOP_UBKPT 17 /* user-mode breakpoint */ +#define STOP_DBKPT 18 /* step-over (dynamic) breakpoint */ + /* Trap codes */ @@ -78,6 +83,13 @@ #define SXT_EXP(x) ((int32) (((x) & EXPS)? ((x) | ~EXPMASK): \ ((x) & EXPMASK))) +/* CPU modes */ + +#define NML_MODE 0 +#define MON_MODE 1 +#define USR_MODE 2 +#define BAD_MODE 3 + /* Memory */ #define MAXMEMSIZE (1 << 16) /* max memory size */ diff --git a/SDS/sds_dsk.c b/SDS/sds_dsk.c index cf9d41ea..22d0a7a3 100644 --- a/SDS/sds_dsk.c +++ b/SDS/sds_dsk.c @@ -204,7 +204,7 @@ switch (fnc) { /* case on function */ case IO_READ: xfr_req = xfr_req & ~XFR_DSK; /* clr xfr req */ if (dsk_bptr >= dsk_blnt) { /* no more data? */ - if (r = dsk_read_buf (inst)) /* read sector */ + if ((r = dsk_read_buf (inst))) /* read sector */ return r; } dsk_wptr = dsk_bptr >> 2; /* word pointer */ @@ -219,7 +219,7 @@ switch (fnc) { /* case on function */ case IO_WRITE: xfr_req = xfr_req & ~XFR_DSK; /* clr xfr req */ if (dsk_bptr >= (DSK_NUMWD * 4)) { /* full? */ - if (r = dsk_write_buf (inst)) /* write sector */ + if ((r = dsk_write_buf (inst))) /* write sector */ return r; } dsk_wptr = dsk_bptr >> 2; /* word pointer */ diff --git a/SDS/sds_io.c b/SDS/sds_io.c index 4e4dd22b..dd55afa0 100644 --- a/SDS/sds_io.c +++ b/SDS/sds_io.c @@ -55,7 +55,7 @@ #define I_GETDEV3(x) ((((x) & 020046000) != 020046000)? ((x) & DEV_MASK): DEV_MASK) -#define TST_XFR(d,c) (xfr_req && dev_map[d][c]) +#define TST_XFR(d,c) (xfr_req & dev_map[d][c]) #define SET_XFR(d,c) xfr_req = xfr_req | dev_map[d][c] #define CLR_XFR(d,c) xfr_req = xfr_req & ~dev_map[d][c] #define INV_DEV(d,c) (dev_dsp[d][c] == NULL) @@ -81,13 +81,11 @@ extern uint32 int_req; /* int req */ extern uint32 xfr_req; /* xfer req */ extern uint32 alert; /* pin/pot alert */ extern uint32 X, EM2, EM3, OV, ion, bpt; -extern uint32 nml_mode, usr_mode; +extern uint32 cpu_mode; extern int32 rtc_pie; extern int32 stop_invins, stop_invdev, stop_inviop; extern uint32 mon_usr_trap; extern UNIT cpu_unit; -extern FILE *sim_log; -extern DEVICE *sim_devices[]; t_stat chan_reset (DEVICE *dptr); t_stat chan_read (int32 ch); @@ -150,7 +148,7 @@ extern void set_dyn_map (void); Channels could, optionally, handle 12b or 24b characters. The simulator can support all widths. */ - + t_stat chan_show_reg (FILE *st, UNIT *uptr, int32 val, void *desc); struct aldisp { @@ -224,7 +222,7 @@ uint32 dev_map[64][NUM_CHAN]; /* dev_dsp maps device and channel numbers to dispatch routines */ -t_stat (*dev_dsp[64][NUM_CHAN])() = { NULL }; +t_stat (*dev_dsp[64][NUM_CHAN])() = { {NULL} }; /* dev3_dsp maps system device numbers to dispatch routines */ @@ -235,11 +233,11 @@ t_stat (*dev3_dsp[64])() = { NULL }; struct aldisp dev_alt[] = { { NULL, NULL }, { NULL, &pot_ilc }, { NULL, &pot_ilc }, - { NULL, &pot_ilc }, { NULL, &pot_ilc }, { NULL, &pot_ilc }, { NULL, &pot_ilc }, - { NULL, &pot_ilc }, { NULL, &pot_ilc }, + { NULL, &pot_ilc }, { NULL, &pot_ilc }, + { NULL, &pot_ilc }, { NULL, &pot_ilc }, + { NULL, &pot_dcr }, { NULL, &pot_dcr }, { NULL, &pot_dcr }, { NULL, &pot_dcr }, - { NULL, &pot_dcr }, { NULL, &pot_dcr }, { NULL, &pot_dcr }, { NULL, &pot_dcr }, { NULL, &pot_dcr }, { NULL, &pot_dcr }, { &pin_adr, NULL }, { &pin_adr, NULL }, @@ -332,15 +330,22 @@ switch (mod) { if (INV_DEV (dev, ch)) /* inv dev? err */ CRETDEV; chan_war[ch] = chan_cnt[ch] = 0; /* init chan */ - chan_flag[ch] = chan_dcr[ch] = 0; - chan_mode[ch] = chan_uar[ch] = 0; - if (ch >= CHAN_E) - chan_mode[ch] = CHM_CE; - if (r = dev_dsp[dev][ch] (IO_CONN, inst, NULL)) /* connect */ + chan_dcr[ch] = 0; + chan_uar[ch] = 0; + if (!(chan_flag[ch] & CHF_ILCE) && /* ignore if ilc */ + !QAILCE (alert)) { /* already alerted */ + chan_flag[ch] = chan_mode[ch] = 0; + if (ch >= CHAN_E) + chan_mode[ch] = CHM_CE; + } + if ((r = dev_dsp[dev][ch] (IO_CONN, inst, NULL)))/* connect */ return r; - if ((inst & I_IND) || (ch >= CHAN_C)) { /* C-H? alert ilc */ - alert = POT_ILCY + ch; - chan_mar[ch] = chan_wcr[ch] = 0; + if (!(chan_flag[ch] & CHF_ILCE) && /* ignore if ilc */ + !QAILCE (alert)) { /* already alerted */ + if ((inst & I_IND) || (ch >= CHAN_C)) { /* C-H? alert ilc */ + alert = POT_ILCY + ch; + chan_mar[ch] = chan_wcr[ch] = 0; + } } if (chan_flag[ch] & CHF_24B) /* 24B? 1 ch/wd */ chan_cpw[ch] = 0; @@ -392,7 +397,7 @@ switch (mod) { } /* end else change scan */ } /* end else term output */ } /* end else chan EOM */ - break; + break; case 2: /* internal */ if (ch >= CHAN_E) { /* EOD? */ @@ -426,7 +431,7 @@ switch (mod) { else if (inst & 01000) /* alert RL2 */ alert = POT_RL2; if (inst & 02000) { /* nml to mon */ - nml_mode = usr_mode = 0; + cpu_mode = MON_MODE; if (inst & 00400) mon_usr_trap = 1; } @@ -434,6 +439,8 @@ switch (mod) { case 3: /* special */ dev = I_GETDEV3 (inst); /* special device */ + if (dev == DEV3_SMUX && !(cpu_unit.flags & UNIT_GENIE)) + dev = DEV3_GMUX; if (dev3_dsp[dev]) /* defined? */ return dev3_dsp[dev] (IO_CONN, inst, NULL); CRETINS; @@ -495,8 +502,10 @@ switch (mod) { case 3: /* special */ dev = I_GETDEV3 (inst); /* special device */ + if (dev == DEV3_SMUX && !(cpu_unit.flags & UNIT_GENIE)) + dev = DEV3_GMUX; if (dev3_dsp[dev]) - dev3_dsp[dev] (IO_SKS, inst, dat); + dev3_dsp[dev] (IO_SKS, inst, dat); else CRETINS; } /* end case */ @@ -542,9 +551,9 @@ return SCPE_OK; t_stat pot_fork (uint32 num, uint32 *dat) { uint32 igrp = SYI_GETGRP (*dat); /* get group */ -uint32 fbit = (1 << (VEC_FORK & 017)); /* bit in group */ +uint32 fbit = (0100000 >> (VEC_FORK & 017)); /* bit in group */ -if (igrp == (VEC_FORK / 020)) { /* right group? */ +if (igrp == ((VEC_FORK-0200) / 020)) { /* right group? */ if ((*dat & SYI_ARM) && (*dat & fbit)) /* arm, bit set? */ int_req = int_req | INT_FORK; if ((*dat & SYI_DIS) && !(*dat & fbit)) /* disarm, bit clr? */ @@ -570,7 +579,7 @@ return SCPE_OK; Note that the channel can be disconnected if CHN_EOR is set, but must not be if XFR_REQ is set */ - + t_stat chan_read (int32 ch) { uint32 dat = 0; @@ -628,7 +637,7 @@ if (TST_EOR (ch)) { /* end record? */ } /* end else if cnt */ return chan_eor (ch); /* eot/eor int */ } -return r; +return r; } void chan_write_mem (int32 ch) @@ -958,7 +967,7 @@ for (i = 0; i < NUM_CHAN; i++) { /* Test each device for conflict; add to map; init tables */ -for (i = 0; dptr = sim_devices[i]; i++) { /* loop thru devices */ +for (i = 0; (dptr = sim_devices[i]); i++) { /* loop thru devices */ dibp = (DIB *) dptr->ctxt; /* get DIB */ if ((dibp == NULL) || (dptr->flags & DEV_DIS)) /* exist, enabled? */ continue; @@ -973,11 +982,8 @@ for (i = 0; dptr = sim_devices[i]; i++) { /* loop thru devices */ for (j = 0; j < tplp->num; j++) { /* repeat as needed */ doff = dev + tplp->off + j; /* get offset dnum */ if (dev_map[doff][ch]) { /* slot in use? */ - printf ("Device number conflict, chan = %s, devno = %02o\n", - chname[ch], doff); - if (sim_log) - fprintf (sim_log, "Device number conflict, chan = %s, dev = %02o\n", - chname[ch], doff); + sim_printf ("Device number conflict, chan = %s, devno = %02o\n", + chname[ch], doff); return TRUE; } dev_map[doff][ch] = dibp->xfr; /* set xfr flag */ diff --git a/SDS/sds_lp.c b/SDS/sds_lp.c index 0de82e70..1462bd88 100644 --- a/SDS/sds_lp.c +++ b/SDS/sds_lp.c @@ -40,7 +40,6 @@ #define SET_EOR 2 /* print, set eor */ #define SET_SPC 4 /* space */ -extern char sds_to_ascii[64]; extern uint32 xfr_req; extern int32 stop_invins, stop_invdev, stop_inviop; int32 lpt_spc = 0; /* space instr */ @@ -69,6 +68,7 @@ t_stat lpt_status (UNIT *uptr); t_stat lpt_bufout (UNIT *uptr); void lpt_end_op (int32 fl); t_stat lpt (uint32 fnc, uint32 inst, uint32 *dat); +int8 sds_to_ascii(int8 c); /* LPT data structures @@ -177,12 +177,12 @@ switch (fnc) { /* case function */ t = I_GETSKCND (inst); /* sks cond */ if (((t == 020) && (!CHP (7, lpt_cct[lpt_ccp]))) || /* 14062: !ch 7 */ ((t == 010) && (lpt_unit.flags & UNIT_ATT)) || /* 12062: !online */ - (t == 004) && !lpt_err) /* 11062: !err */ + ((t == 004) && !lpt_err)) /* 11062: !err */ *dat = 1; break; case IO_WRITE: /* write */ - asc = sds_to_ascii[(*dat) & 077]; /* convert data */ + asc = sds_to_ascii(*dat); /* convert data */ xfr_req = xfr_req & ~XFR_LPT; /* clr xfr flag */ if (lpt_bptr < LPT_WIDTH) /* store data */ lpt_buf[lpt_bptr++] = asc; diff --git a/SDS/sds_mt.c b/SDS/sds_mt.c index 163d7d23..f7fc56d4 100644 --- a/SDS/sds_mt.c +++ b/SDS/sds_mt.c @@ -168,7 +168,7 @@ DEVICE mt_dev = { MT_NUMDR, 10, 31, 1, 8, 8, NULL, NULL, &mt_reset, &mt_boot, &mt_attach, NULL, - &mt_dib, DEV_DISABLE + &mt_dib, DEV_DISABLE | DEV_TAPE }; /* Mag tape routine @@ -235,14 +235,14 @@ switch (fnc) { /* case function */ case IO_DISC: /* disconnect */ sim_cancel (uptr); /* no more xfr's */ if (inst & DEV_OUT) { /* write? */ - if (r = mt_wrend (inst)) /* end record */ + if ((r = mt_wrend (inst))) /* end record */ return r; } break; case IO_WREOR: /* write eor */ chan_set_flag (mt_dib.chan, CHF_EOR); /* set eor flg */ - if (r = mt_wrend (inst)) /* end record */ + if ((r = mt_wrend (inst))) /* end record */ return r; mt_gap = 1; /* in gap */ sim_activate (uptr, mt_gtime); /* start timer */ diff --git a/SDS/sds_mux.c b/SDS/sds_mux.c index ef6203fd..64e22794 100644 --- a/SDS/sds_mux.c +++ b/SDS/sds_mux.c @@ -50,10 +50,11 @@ #define MUX_SCANMAX (MUX_LINES * MUX_FLAGS) /* flags to scan */ #define MUX_SCANMASK (MUX_SCANMAX - 1) #define MUX_INIT_POLL 8000 -#define MUXL_WAIT 500 +#define MUXL_WAIT 250 #define MUX_SETFLG(l,x) mux_flags[((l) * MUX_FLAGS) + (x)] = 1 #define MUX_SETINT(x) int_req = int_req | (INT_MUXR >> (x)) #define MUX_CLRINT(x) int_req = int_req & ~(INT_MUXR >> (x)) +#define MUX_CHKINT(x) (int_req & (INT_MUXR >> (x))) /* PIN/POT */ @@ -112,7 +113,7 @@ uint32 mux_tps = 100; /* polls/second */ uint32 mux_scan = 0; /* scanner */ uint32 mux_slck = 0; /* scanner locked */ -TMLN mux_ldsc[MUX_LINES] = { 0 }; /* line descriptors */ +TMLN mux_ldsc[MUX_LINES] = { {0} }; /* line descriptors */ TMXR mux_desc = { MUX_LINES, 0, 0, mux_ldsc }; /* mux descriptor */ t_stat mux (uint32 fnc, uint32 inst, uint32 *dat); @@ -169,7 +170,7 @@ DEVICE mux_dev = { 1, 10, 31, 1, 8, 8, &tmxr_ex, &tmxr_dep, &mux_reset, NULL, &mux_attach, &mux_detach, - &mux_dib, DEV_NET | DEV_DISABLE + &mux_dib, DEV_MUX | DEV_DISABLE }; /* MUXL data structures @@ -274,7 +275,7 @@ switch (fnc) { ((inst & SKS_DSR) && !(mux_sta[ln] & MUX_SDSR))) *dat = 0; /* no skip if fail */ } - else CRETINS; + else CRETINS; default: return SCPE_IERR; @@ -290,6 +291,8 @@ t_stat pin_mux (uint32 num, uint32 *dat) uint32 ln = mux_scan >> 2; uint32 flag = mux_scan & MUX_FLAGMASK; +if (!mux_slck) /* scanner must be locked */ + return SCPE_IERR; mux_scan = mux_scan & MUX_SCANMASK; /* mask scan */ mux_flags[mux_scan] = 0; /* clear flag */ if (flag == MUX_FRCV) { /* rcv event? */ @@ -333,6 +336,12 @@ else { /* enabled */ else mux_sta[ln] = mux_sta[ln] & ~MUX_SXIE; mux_sta[ln] = mux_sta[ln] | MUX_SLNE; /* line is enabled */ mux_ldsc[ln].rcve = 1; + if ((*dat & POT_NOX) && /* if no transmit char && */ + (mux_sta[ln] & MUX_SXIE) && /* line enabled && */ + !sim_is_active (&muxl_unit[ln])) { /* tx buffer empty */ + MUX_SETFLG (ln, MUX_FXMT); /* then set flag to request */ + mux_scan_next (); /* a tx interrupt */ + } } return SCPE_OK; } @@ -363,7 +372,7 @@ if (ln >= 0) { /* got one? */ tmxr_poll_rx (&mux_desc); /* poll for input */ for (ln = 0; ln < MUX_NUMLIN; ln++) { /* loop thru lines */ if (mux_ldsc[ln].conn) { /* connected? */ - if (c = tmxr_getc_ln (&mux_ldsc[ln])) { /* get char */ + if ((c = tmxr_getc_ln (&mux_ldsc[ln]))) { /* get char */ if (mux_sta[ln] & MUX_SCHP) /* already got one? */ mux_sta[ln] = mux_sta[ln] | MUX_SOVR; /* overrun */ else mux_sta[ln] = mux_sta[ln] | MUX_SCHP; /* char pending */ @@ -407,7 +416,23 @@ if (mux_sta[ln] & MUX_SXIE) { return SCPE_OK; } -/* Kick scanner */ +/* Kick scanner +* +* Per 940 Ref Man: +* If more than one raised flag is encountered by the scanner, only +* the one of highest priority will result in an interrupt. The others +* will be ignored until the scanner has completed scanning all other +* channels. The receive flag will be given highest priority, followed +* by the transmit flag, the carrier-on flag, and the carrier-off flag. +* +* To implement, advance mux_scan to last flag of current channel (by +* merging MUX_FLAGMASK) so scan loop commences with receive flag of next +* channel. +* +* When two or more channels are active, do not queue an interrupt +* request if the same interrupt is already requesting. To do so will +* cause an interrupt to be lost. +*/ void mux_scan_next (void) { @@ -415,9 +440,12 @@ int32 i; if (mux_slck) /* locked? */ return; +mux_scan |= MUX_FLAGMASK; /* last flag of current ch. */ + /* will be Rx flag of next ch. */ for (i = 0; i < MUX_SCANMAX; i++) { /* scan flags */ mux_scan = (mux_scan + 1) & MUX_SCANMASK; /* next flag */ - if (mux_flags[mux_scan]) { /* flag set? */ + if (mux_flags[mux_scan] && /* flag set */ + !MUX_CHKINT (mux_scan & MUX_FLAGMASK)) { /* and not requesting int? */ mux_slck = 1; /* lock scanner */ MUX_SETINT (mux_scan & MUX_FLAGMASK); /* request int */ return; diff --git a/SDS/sds_rad.c b/SDS/sds_rad.c index 4194c755..b8d4e228 100644 --- a/SDS/sds_rad.c +++ b/SDS/sds_rad.c @@ -36,6 +36,7 @@ /* Constants */ +#define RAD_CHAN CHAN_E /* Connected I/O controller */ #define RAD_NUMWD 64 /* words/sector */ #define RAD_NUMSC 64 /* sectors/track */ #define RAD_NUMTR 64 /* tracks/log unit */ @@ -69,6 +70,7 @@ DSPT rad_tplt[] = { /* template */ DEVICE rad_dev; t_stat rad_svc (UNIT *uptr); t_stat rad_reset (DEVICE *dptr); +t_stat rad_boot (int32 unitno, DEVICE *dptr); t_stat rad_fill (int32 sba); void rad_end_op (int32 fl); int32 rad_adjda (int32 sba, int32 inc); @@ -76,12 +78,13 @@ t_stat rad (uint32 fnc, uint32 inst, uint32 *dat); /* RAD data structures + rad_dib device information block rad_dev device descriptor rad_unit unit descriptor rad_reg register list */ -DIB rad_dib = { CHAN_E, DEV_RAD, XFR_RAD, rad_tplt, &rad }; +DIB rad_dib = { RAD_CHAN, DEV_RAD, XFR_RAD, rad_tplt, &rad }; UNIT rad_unit = { UDATA (&rad_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+UNIT_MUSTBUF, @@ -111,12 +114,12 @@ DEVICE rad_dev = { "RAD", &rad_unit, rad_reg, rad_mod, 1, 8, 21, 1, 8, 24, NULL, NULL, &rad_reset, - NULL, NULL, NULL, + &rad_boot, NULL, NULL, &rad_dib, DEV_DISABLE }; /* Fixed head disk routine - + conn - inst = EOM0, dat = NULL eom1 - inst = EOM1, dat = NULL sks - inst = SKS, dat = ptr to result @@ -157,7 +160,7 @@ switch (fnc) { /* case function */ if (new_ch != rad_dib.chan) /* wrong chan? */ return SCPE_IERR; if ((inst & 00600) == 00200) /* alert for sec */ - alert = POT_RADS; + alert = POT_RADS; else if ((inst & 06600) == 0) { /* alert for addr */ if (sim_is_active (&rad_unit)) /* busy? */ rad_err = 1; @@ -287,7 +290,7 @@ if (rad_sba >= (RAD_NUMWD * 2)) { /* next sector? */ ((rad_da + 1) & RAD_SCMASK); else rad_da = (rad_da & ~RAD_TRSCMASK) + /* cross band */ ((rad_da + 1) & RAD_TRSCMASK); - sba = 0; /* start new sec */ + sba = 1; /* start new sec */ } return sba; } @@ -319,3 +322,22 @@ xfr_req = xfr_req & ~XFR_RAD; /* clr xfr req */ sim_cancel (&rad_unit); /* deactivate */ return SCPE_OK; } + +/* Boot routine - simulate FILL console command */ + +t_stat rad_boot (int32 unitno, DEVICE *dptr) +{ +extern uint32 P, M[]; + +if (unitno) /* only unit 0 */ + return SCPE_ARG; +if (rad_dib.chan != CHAN_W) /* only on W channel */ + return SCPE_IOERR; +M[0] = 077777771; /* -7B */ +M[1] = 007100000; /* LDX 0 */ +M[2] = 000203226; /* EOM 3226B */ +M[3] = 003200002; /* WIM 2 */ +M[4] = 000100002; /* BRU 2 */ +P = 1; /* start at 1 */ +return SCPE_OK; +} diff --git a/SDS/sds_stddev.c b/SDS/sds_stddev.c index 7899228b..bb563e73 100644 --- a/SDS/sds_stddev.c +++ b/SDS/sds_stddev.c @@ -41,7 +41,7 @@ extern uint32 xfr_req; extern int32 stop_invins, stop_invdev, stop_inviop; int32 ptr_sor = 0; /* start of rec */ -int32 ptr_stopioe = 1; /* stop on err */ +int32 ptr_stopioe = 0; /* no stop on err */ int32 ptp_ldr = 0; /* no leader */ int32 ptp_stopioe = 1; DSPT std_tplt[] = { { 1, 0 }, { 0, 0 } }; /* template */ @@ -63,10 +63,9 @@ t_stat tti_reset (DEVICE *dptr); t_stat tto (uint32 fnc, uint32 inst, uint32 *dat); t_stat tto_svc (UNIT *uptr); t_stat tto_reset (DEVICE *dptr); - -extern const char ascii_to_sds[128]; -extern const char sds_to_ascii[64]; -extern const char odd_par[64]; +int8 ascii_to_sds(int8 ch); +int8 sds_to_ascii(int8 ch); +extern const int8 odd_par[64]; /* PTR data structures @@ -277,7 +276,7 @@ if ((temp = getc (ptr_unit.fileref)) == EOF) { /* end of file? */ ptr_set_err (); /* yes, err, disc */ if (feof (ptr_unit.fileref)) { /* end of file? */ if (ptr_stopioe) - printf ("PTR end of file\n"); + sim_printf ("PTR end of file\n"); else return SCPE_OK; } else perror ("PTR I/O error"); /* I/O error */ @@ -395,7 +394,7 @@ t_stat r = SCPE_OK; if (ptp_ldr) { /* need leader? */ for (i = 0; i < 12; i++) { /* punch leader */ - if (r = ptp_out (0)) + if ((r = ptp_out (0))) break; } } @@ -505,8 +504,8 @@ if (temp & SCPE_BREAK) /* ignore break */ return SCPE_OK; temp = temp & 0177; tti_unit.pos = tti_unit.pos + 1; -if (ascii_to_sds[temp] >= 0) { - tti_unit.buf = ascii_to_sds[temp]; /* internal rep */ +if (ascii_to_sds(temp) >= 0) { + tti_unit.buf = ascii_to_sds(temp); /* internal rep */ sim_putchar (temp); /* echo */ if (temp == '\r') /* lf after cr */ sim_putchar ('\n'); @@ -588,7 +587,7 @@ else if (uptr->buf == TT_BS) asc = '\b'; else if (uptr->buf == TT_TB) asc = '\t'; -else asc = sds_to_ascii[uptr->buf]; /* translate */ +else asc = sds_to_ascii(uptr->buf); /* translate */ if ((r = sim_putchar_s (asc)) != SCPE_OK) { /* output; error? */ sim_activate (uptr, uptr->wait); /* retry */ return ((r == SCPE_STALL)? SCPE_OK: r); /* !stall? report */ diff --git a/SDS/sds_sys.c b/SDS/sds_sys.c index 44f98173..8d216a80 100644 --- a/SDS/sds_sys.c +++ b/SDS/sds_sys.c @@ -45,6 +45,7 @@ extern DEVICE mt_dev; extern DEVICE mux_dev, muxl_dev; extern UNIT cpu_unit; extern REG cpu_reg[]; +extern uint32 cpu_mode; extern uint32 M[MAXMEMSIZE]; /* SCP data structures and interface routines @@ -93,15 +94,19 @@ const char *sim_stop_messages[] = { "Nested EXU's exceed limit", "Memory management trap during interrupt", "Memory management trap during trap", - "Trap instruction not BRM", + "Trap instruction not BRM or BRU", "RTC instruction not MIN or SKR", "Interrupt vector zero", - "Runaway carriage control tape" + "Runaway carriage control tape", + "Monitor-mode Breakpoint", + "Normal-mode Breakpoint", + "User-mode Breakpoint", + "Next expired" }; -/* Character conversion tables */ +/* SDS 930 character conversion tables. Per 930 Ref Man Appendix A */ -const char sds_to_ascii[64] = { +const int8 sds930_to_ascii[64] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ' ', '=', '\'', ':', '>', '%', /* 17 = check mark */ '+', 'A', 'B', 'C', 'D', 'E', 'F', 'G', @@ -112,8 +117,8 @@ const char sds_to_ascii[64] = { 'Y', 'Z', '?', ',', '(', '~', '\\', '#' /* 72 = rec mark */ }; /* 75 = squiggle, 77 = del */ -const char ascii_to_sds[128] = { - -1, -1, -1, -1, -1, -1, -1, -1, /* 0 - 37 */ +const int8 ascii_to_sds930[128] = { + -1, -1, -1, -1, -1, -1, -1, -1, /* 00 - 37 */ 032, 072, -1, -1, -1, 052, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, @@ -125,13 +130,45 @@ const char ascii_to_sds[128] = { 030, 031, 041, 042, 043, 044, 045, 046, 047, 050, 051, 062, 063, 064, 065, 066, 067, 070, 071, 035, 076, 055, 057, 060, - 000, 021, 022, 023, 024, 025, 026, 027, /* 140 - 177 */ - 030, 031, 041, 042, 043, 044, 045, 046, + -1, 021, 022, 023, 024, 025, 026, 027, /* 140 - 177 */ + 030, 031, 041, 042, 043, 044, 045, 046, /* fold lower case to upper */ 047, 050, 051, 062, 063, 064, 065, 066, 067, 070, 071, -1, -1, -1, -1, -1 }; -const char odd_par[64] = { +/* SDS 940 character conversion tables. Per 940 Ref Man Appendix A */ + +const int8 sds940_to_ascii[64] = { + ' ', '!', '"', '#', '$', '%', '&', '\'', /* 00 - 17 */ + '(', ')', '*', '+', ',', '-', '.', '/', + '0', '1', '2', '3', '4', '5', '6', '7', /* 20 - 37 */ + '8', '9', ':', ';', '<', '=', '>', '?', + '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', /* 40 - 57 */ + 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', /* 60 - 77 */ + 'X', 'Y', 'Z', '[', '\\', ']', '^', '_' + }; + +const int8 ascii_to_sds940[128] = { + -1, 141, 142, 143, 144, 145, 146, 147, /* 00 - 37 */ + -1, 151, 152, 153, 154, 155, -1, -1, + -1, 161, 162, 163, 164, 165, 166, 167, + 170, 171, 172, -1, -1, -1, -1, -1, + 000, 001, 002, 003, 004, 005, 006, 007, /* 40 - 77 */ + 010, 011, 012, 013, 014, 015, 016, 017, + 020, 021, 022, 023, 024, 025, 026, 027, + 030, 031, 032, 033, 034, 035, 036, 037, + 040, 041, 042, 043, 044, 045, 046, 047, /* 100 - 137 */ + 050, 051, 052, 053, 054, 055, 056, 057, + 060, 061, 062, 063, 064, 065, 066, 067, + 070, 071, 072, 073, 074, 075, 076, 077, + -1, 041, 042, 043, 044, 045, 046, 047, /* 140 - 177 */ + 050, 051, 052, 053, 054, 055, 056, 057, /* fold lower case to upper */ + 060, 061, 062, 063, 064, 065, 066, 067, + 070, 071, 072, -1, -1, -1, -1, -1 + }; + +const int8 odd_par[64] = { 0100, 0001, 0002, 0103, 0004, 0105, 0106, 0007, 0010, 0111, 0112, 0013, 0114, 0015, 0016, 0117, 0020, 0121, 0122, 0023, 0124, 0025, 0026, 0127, @@ -212,12 +249,11 @@ for (i = wd = 0; i < 4; ) { } return wd; } - + t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag) { int32 i, wd, buf[8]; int32 ldr = 1; -extern int32 sim_switches; extern uint32 P; if ((*cptr != 0) || (flag != 0)) @@ -228,11 +264,11 @@ for (i = 0; i < 8; i++) { /* read boot */ if ((wd = get_word (fileref, &ldr)) < 0) return SCPE_FMT; buf[i] = wd; - } + } if ((buf[0] != 023200012) || /* 2 = WIM 12,2 */ (buf[1] != 004100002) || /* 3 = BRX 2 */ (buf[2] != 007100011) || /* 4 = LDX 11 */ - (buf[3] != 023200000) || /* 5 = WIM 0,2 */ + ((buf[3] & ~VA_MASK) != 023200000) || /* 5 = WIM xxxxx,2 */ (buf[4] != 004021000) || /* 6 = SKS 21000 */ (buf[5] != 004100005)) /* 7 = BRX 5 */ return SCPE_FMT; @@ -240,7 +276,7 @@ for (i = 0; i < 8; i++) /* copy boot */ M[i + 2] = buf[i]; if (I_GETOP (buf[6]) == BRU) P = buf[6] & VA_MASK; -for (i = buf[7] & VA_MASK; i <= VA_MASK; i++) { /* load data */ +for (i = (buf[3]+buf[7]) & VA_MASK; i <= VA_MASK; i++) {/* load data */ if ((wd = get_word (fileref, &ldr)) < 0) return SCPE_OK; M[i] = wd; @@ -258,26 +294,51 @@ return SCPE_NXM; #define I_V_MRF 003 /* memory reference */ #define I_V_REG 004 /* register change */ #define I_V_SHF 005 /* shift */ -#define I_V_OPO 006 /* opcode only */ +#define I_V_OPO 006 /* operand optional */ #define I_V_CHC 007 /* chan cmd */ #define I_V_CHT 010 /* chan test */ -#define I_NPN (I_V_NPN << I_V_FL) -#define I_PPO (I_V_PPO << I_V_FL) -#define I_IOI (I_V_IOI << I_V_FL) -#define I_MRF (I_V_MRF << I_V_FL) -#define I_REG (I_V_REG << I_V_FL) -#define I_SHF (I_V_SHF << I_V_FL) +#define I_V_SPP 011 /* system POP */ +#define I_NPN (I_V_NPN << I_V_FL) +#define I_PPO (I_V_PPO << I_V_FL) +#define I_IOI (I_V_IOI << I_V_FL) +#define I_MRF (I_V_MRF << I_V_FL) +#define I_REG (I_V_REG << I_V_FL) +#define I_SHF (I_V_SHF << I_V_FL) #define I_OPO (I_V_OPO << I_V_FL) #define I_CHC (I_V_CHC << I_V_FL) -#define I_CHT (I_V_CHT << I_V_FL) +#define I_CHT (I_V_CHT << I_V_FL) +#define I_SPP (I_V_SPP << I_V_FL) static const int32 masks[] = { - 037777777, 010000000, 017700000, - 017740000, 017700000, 017774000, - 017700000, 017377677, 027737677 + 037777777, 010000000, 017700000, /* NPN, PPO, IOI */ + 017740000, 017700000, 017774000, /* MRF, REG, SHF */ + 017740000, 017377677, 027737677, /* OPO, CHC, CHT */ + 057740000 /* SPP */ }; -static const char *opcode[] = { +static const char *opcode[] = { /* Note: syspops must preceed generic pop */ + "WSI", "SWI", "BKPT","STO", + "WCD", "STI", "GCD", "SIC", + "ISC", "DBI", "DBO", "DWI", + "DWO", "LAS", "SAS", "IST", + "OST", "EXS", "FDV", "FMP", + "FSB", "FAD", "WCI", "WIO", + "CIO", "SKSG","SKSE","WCH", + "GCI", "LDP", "STP", "SBRM", + "SBRR","CTRL","BRS", "TCI", + "TCO", "BIO", + + "WSI*", "SWI*", "BKPT*","STO*", + "WCD*", "STI*", "GCD*", "SIC*", + "ISC*", "DBI*", "DBO*", "DWI*", + "DWO*", "LAS*", "SAS*", "IST*", + "OST*", "EXS*", "FDV*", "FMP*", + "FSB*", "FAD*", "WCI*", "WIO*", + "CIO*", "SKSG*","SKSE*","WCH*", + "GCI*", "LDP*", "STP*", "SBRM*", + "SBRR*","CTRL*","BRS*", "TCI*", + "TCO*", "BIO*", + "POP", "EIR", "DIR", "ROV", "REO", "OTO", "OVT", "IDT", "IET", @@ -300,10 +361,10 @@ static const char *opcode[] = { "SKM", "LDX", "SKA", "SKG", "SKD", "LDB", "LDA", "EAX", - "BRU*", + "BRU*", "MIY*", "BRI*", "MIW*", "POT*", "ETR*", "MRG*", "EOR*", - "EXU*", + "NOP*", "EXU*", "YIM*", "WIM*", "PIN*", "STA*", "STB*", "STX*", "BRX*", "BRM*", @@ -329,53 +390,75 @@ static const char *opcode[] = { }; static const int32 opc_val[] = { - 010000000+I_PPO, 000220002+I_NPN, 000220004+I_NPN, - 002200001+I_NPN, 002200010+I_NPN, 002200100+I_NPN, 002200101+I_NPN, - 004020002+I_NPN, 004020004+I_NPN, - 004020040+I_NPN, 004020100+I_NPN, 004020200+I_NPN, 004020400+I_NPN, - 004600003+I_NPN, 004600005+I_NPN, 004600012+I_NPN, 004600014+I_NPN, - 004600060+I_NPN, 004600122+I_NPN, 004600140+I_NPN, 004600160+I_NPN, - 024600003+I_NPN, + 050000000+I_SPP, 050100000+I_SPP, 053300000+I_SPP, 053400000+I_SPP, /* WSI, SWI, BKPT, STO, */ + 053500000+I_SPP, 053600000+I_SPP, 053700000+I_SPP, 054000000+I_SPP, /* WCD, STI, GCD, SIC, */ + 054100000+I_SPP, 054200000+I_SPP, 054300000+I_SPP, 054400000+I_SPP, /* ISC, DBI, DBO, DWI, */ + 054500000+I_SPP, 054600000+I_SPP, 054700000+I_SPP, 055000000+I_SPP, /* DWO, LAS, SAS, IST, */ + 055100000+I_SPP, 055200000+I_SPP, 055300000+I_SPP, 055400000+I_SPP, /* OST, EXS, FDV, FMP, */ + 055500000+I_SPP, 055600000+I_SPP, 055700000+I_SPP, 056000000+I_SPP, /* FSB, FAD, WCI, WIO, */ + 056100000+I_SPP, 056200000+I_SPP, 056300000+I_SPP, 056400000+I_SPP, /* CIO, SKSG, SKSE, WCH, */ + 056500000+I_SPP, 056600000+I_SPP, 056700000+I_SPP, 057000000+I_SPP, /* GCI, LDP, STP, SBRM,*/ + 057100000+I_SPP, 057200000+I_SPP, 057300000+I_SPP, 057400000+I_SPP, /* SBRR, CTRL, BRS, TCI, */ + 057500000+I_SPP, 057600000+I_SPP, /* TCO, BIO, */ - 000000000+I_NPN, 000100000+I_MRF, 000200000+I_IOI, 000600000+I_IOI, - 001000000+I_MRF, 001100000+I_MRF, 001200000+I_MRF, 001300000+I_MRF, - 001400000+I_MRF, 001600000+I_MRF, 001700000+I_MRF, - 002000000+I_OPO, 002300000+I_MRF, - 003000000+I_MRF, 003200000+I_MRF, 003300000+I_MRF, - 003500000+I_MRF, 003600000+I_MRF, 003700000+I_MRF, - 004000000+I_IOI, 004100000+I_MRF, 004300000+I_MRF, - 005000000+I_MRF, 005100000+I_MRF, 005200000+I_MRF, 005300000+I_MRF, - 005400000+I_MRF, 005500000+I_MRF, 005600000+I_MRF, 005700000+I_MRF, - 006000000+I_MRF, 006100000+I_MRF, 006200000+I_MRF, 006300000+I_MRF, - 006400000+I_MRF, 006500000+I_MRF, - 007000000+I_MRF, 007100000+I_MRF, 007200000+I_MRF, 007300000+I_MRF, - 007400000+I_MRF, 007500000+I_MRF, 007600000+I_MRF, 007700000+I_MRF, + 054000000+I_SPP, 050140000+I_SPP, 053340000+I_SPP, 053440000+I_SPP, /* WSI*, SWI*, BKPT*, STO*, */ + 053540000+I_SPP, 053640000+I_SPP, 053740000+I_SPP, 054400000+I_SPP, /* WCD*, STI*, GCD*, SIC*, */ + 054140000+I_SPP, 054240000+I_SPP, 054340000+I_SPP, 054440000+I_SPP, /* ISC*, DBI*, DBO*, DWI*, */ + 054540000+I_SPP, 054640000+I_SPP, 054740000+I_SPP, 055400000+I_SPP, /* DWO*, LAS*, SAS*, IST*, */ + 055140000+I_SPP, 055240000+I_SPP, 055340000+I_SPP, 055440000+I_SPP, /* OST*, EXS*, FDV*, FMP*, */ + 055540000+I_SPP, 055640000+I_SPP, 055740000+I_SPP, 056400000+I_SPP, /* FSB*, FAD*, WCI*, WIO*, */ + 056140000+I_SPP, 056240000+I_SPP, 056340000+I_SPP, 056440000+I_SPP, /* CIO*, SKSG*, SKSE*, WCH*, */ + 056540000+I_SPP, 056640000+I_SPP, 056740000+I_SPP, 057400000+I_SPP, /* GCI*, LDP*, STP*, SBRM*,*/ + 057140000+I_SPP, 057240000+I_SPP, 057340000+I_SPP, 057440000+I_SPP, /* SBRR*, CTRL*, BRS*, TCI*, */ + 057540000+I_SPP, 057640000+I_SPP, /* TCO*, BIO*, */ - 000140000+I_MRF, - 001040000+I_MRF, 001140000+I_MRF, 001240000+I_MRF, 001340000+I_MRF, - 001440000+I_MRF, 001640000+I_MRF, 001740000+I_MRF, - 002340000+I_MRF, - 003040000+I_MRF, 003240000+I_MRF, 003340000+I_MRF, - 003540000+I_MRF, 003640000+I_MRF, 003740000+I_MRF, - 004140000+I_MRF, 004340000+I_MRF, - 005040000+I_MRF, 005140000+I_MRF, 005240000+I_MRF, 005340000+I_MRF, - 005440000+I_MRF, 005540000+I_MRF, 005640000+I_MRF, 005740000+I_MRF, - 006040000+I_MRF, 006140000+I_MRF, 006240000+I_MRF, 006340000+I_MRF, - 006440000+I_MRF, 006540000+I_MRF, - 007040000+I_MRF, 007140000+I_MRF, 007240000+I_MRF, 007340000+I_MRF, - 007440000+I_MRF, 007540000+I_MRF, 007640000+I_MRF, 007740000+I_MRF, + 010000000+I_PPO, 000220002+I_NPN, 000220004+I_NPN, /* POP, EIR, DIR, */ + 002200001+I_NPN, 002200010+I_NPN, 002200100+I_NPN, 002200101+I_NPN, /* ROV, REO, OTO, OVT, */ + 004020002+I_NPN, 004020004+I_NPN, /* IDT, IET, */ + 004020040+I_NPN, 004020100+I_NPN, 004020200+I_NPN, 004020400+I_NPN, /* BPT4, BPT3, BPT2, BPT1, */ + 004600003+I_NPN, 004600005+I_NPN, 004600012+I_NPN, 004600014+I_NPN, /* CLAB, ABC, BAC, XAB, */ + 004600060+I_NPN, 004600122+I_NPN, 004600140+I_NPN, 004600160+I_NPN, /* XXB, STE, LDE, XEE, */ + 024600003+I_NPN, /* CLEAR, */ - 006600000+I_SHF, 006620000+I_SHF, 006624000+I_SHF, - 006700000+I_SHF, 006710000+I_SHF, 006720000+I_SHF, - 006640000+I_MRF, 006740000+I_MRF, + 000000000+I_NPN, 000100000+I_MRF, 000200000+I_IOI, 000600000+I_IOI, /* HLT, BRU, EOM, EOD, */ + 001000000+I_MRF, 001100000+I_MRF, 001200000+I_MRF, 001300000+I_MRF, /* MIY, BRI, MIW, POT, */ + 001400000+I_MRF, 001600000+I_MRF, 001700000+I_MRF, /* ETR, MRG, EOR, */ + 002000000+I_OPO, 002300000+I_MRF, /* NOP, EXU, */ + 003000000+I_MRF, 003200000+I_MRF, 003300000+I_MRF, /* YIM, WIM, PIN, */ + 003500000+I_MRF, 003600000+I_MRF, 003700000+I_MRF, /* STA, STB, STX, */ + 004000000+I_IOI, 004100000+I_MRF, 004300000+I_MRF, /* SKS, BRX, BRM, */ + 005000000+I_MRF, 005100000+I_MRF, 005200000+I_MRF, 005300000+I_MRF, /* SKE, BRR, SKB, SKN, */ + 005400000+I_MRF, 005500000+I_MRF, 005600000+I_MRF, 005700000+I_MRF, /* SUB, ADD, SUC, ADC, */ + 006000000+I_MRF, 006100000+I_MRF, 006200000+I_MRF, 006300000+I_MRF, /* SKR, MIN, XMA, ADM, */ + 006400000+I_MRF, 006500000+I_MRF, /* MUL, DIV, */ + 007000000+I_MRF, 007100000+I_MRF, 007200000+I_MRF, 007300000+I_MRF, /* SKM, LDX, SKA, SKG, */ + 007400000+I_MRF, 007500000+I_MRF, 007600000+I_MRF, 007700000+I_MRF, /* SKD, LDB, LDA, EAX, */ - 000250000+I_CHC, 000200000+I_CHC, 000212000+I_CHC, 000214000+I_CHC, - 004014000+I_CHT, 004011000+I_CHT, 004012000+I_CHT, 004010400+I_CHT, + 000140000+I_MRF, /* BRU*, */ + 001040000+I_MRF, 001140000+I_MRF, 001240000+I_MRF, 001340000+I_MRF, /* MIY*, BRI*, MIW*, POT*, */ + 001440000+I_MRF, 001640000+I_MRF, 001740000+I_MRF, /* ETR*, MRG*, EOR*, */ + 002040000+I_OPO, 002340000+I_MRF, /* NOP*, EXU*, */ + 003040000+I_MRF, 003240000+I_MRF, 003340000+I_MRF, /* YIM*, WIM*, PIN*, */ + 003540000+I_MRF, 003640000+I_MRF, 003740000+I_MRF, /* STA*, STB*, STX*, */ + 004140000+I_MRF, 004340000+I_MRF, /* BRX*, BRM*, */ + 005040000+I_MRF, 005140000+I_MRF, 005240000+I_MRF, 005340000+I_MRF, /* SKE*, BRR*, SKB*, SKN*, */ + 005440000+I_MRF, 005540000+I_MRF, 005640000+I_MRF, 005740000+I_MRF, /* SUB*, ADD*, SUC*, ADC*, */ + 006040000+I_MRF, 006140000+I_MRF, 006240000+I_MRF, 006340000+I_MRF, /* SKR*, MIN*, XMA*, ADM*, */ + 006440000+I_MRF, 006540000+I_MRF, /* MUL*, DIV*, */ + 007040000+I_MRF, 007140000+I_MRF, 007240000+I_MRF, 007340000+I_MRF, /* SKM*, LDX*, SKA*, SKG*, */ + 007440000+I_MRF, 007540000+I_MRF, 007640000+I_MRF, 007740000+I_MRF, /* SKD*, LDB*, LDA*, EAX*, */ - 004600001+I_REG, 004600002+I_REG, 004600004+I_REG, - 004600010+I_REG, 004600020+I_REG, 004600040+I_REG, - 004600100+I_REG, 004600200+I_REG, 004600400+I_REG, - 004601000+I_REG, 024600000+I_REG, 004600000+I_REG, + 006600000+I_SHF, 006620000+I_SHF, 006624000+I_SHF, /* RSH, RCY, LRSH, */ + 006700000+I_SHF, 006710000+I_SHF, 006720000+I_SHF, /* LSH, NOD, LCY, */ + 006640000+I_MRF, 006740000+I_MRF, /* RSH*, LSH*, */ + + 000250000+I_CHC, 000200000+I_CHC, 000212000+I_CHC, 000214000+I_CHC, /* ALC, DSC, ASC, TOP, */ + 004014000+I_CHT, 004011000+I_CHT, 004012000+I_CHT, 004010400+I_CHT, /* CAT, CET, CZT, CIT, */ + + 004600001+I_REG, 004600002+I_REG, 004600004+I_REG, /* CLA, CLB, CAB, */ + 004600010+I_REG, 004600020+I_REG, 004600040+I_REG, /* CBA, CBX, CXB, */ + 004600100+I_REG, 004600200+I_REG, 004600400+I_REG, /* XPO, CXA, CAX, */ + 004601000+I_REG, 024600000+I_REG, 004600000+I_REG, /* CNA, CLX, NULL, */ -1 }; @@ -406,6 +489,26 @@ for (i = sp = 0; opc_val[i] >= 0; i++) { /* loop thru ops */ return; } +/* Convert from SDS internal character code to ASCII depending upon cpu mode. */ +int8 sds_to_ascii(int8 ch) +{ + ch &= 077; + if (cpu_mode == NML_MODE) + return sds930_to_ascii[ch]; + else + return sds940_to_ascii[ch]; +} + +/* Convert from ASCII to SDS internal character code depending upon cpu mode. */ +int8 ascii_to_sds(int8 ch) +{ + ch &= 0177; + if (cpu_mode == NML_MODE) + return ascii_to_sds930[ch]; + else + return ascii_to_sds940[ch]; +} + /* Symbolic decode Inputs: @@ -431,17 +534,20 @@ va = inst & VA_MASK; shf = inst & I_SHFMSK; nonop = inst & 077777; -if (sw & SWMASK ('A')) { /* ASCII? */ - if (inst > 0377) - return SCPE_ARG; - fprintf (of, FMTASC (inst & 0177)); +if (sw & SWMASK ('A')) { /* SDS internal ASCII? */ + for (i = 16; i >= 0; i -= 8) { + ch = (inst >> i) & 0377; /* map printable chars */ + if (ch <= 0137) + ch += 040; /* from int. to ext. ASCII */ + else + ch = '.'; /* or indicate not displayable */ + fprintf (of, "%c", ch); + } return SCPE_OK; } -if (sw & SWMASK ('C')) { /* character? */ - fprintf (of, "%c", sds_to_ascii[(inst >> 18) & 077]); - fprintf (of, "%c", sds_to_ascii[(inst >> 12) & 077]); - fprintf (of, "%c", sds_to_ascii[(inst >> 6) & 077]); - fprintf (of, "%c", sds_to_ascii[inst & 077]); +if (sw & SWMASK ('C')) { /* six-bit character? */ + for (i = 18; i >= 0; i -= 6) + fprintf (of, "%c", sds_to_ascii(inst >> i)); return SCPE_OK; } if (!(sw & SWMASK ('M'))) return SCPE_ARG; @@ -454,8 +560,7 @@ for (i = 0; opc_val[i] >= 0; i++) { /* loop thru ops */ switch (j) { /* case on class */ - case I_V_NPN: /* no operands */ - case I_V_OPO: /* opcode only */ + case I_V_NPN: /* no operand */ fprintf (of, "%s", opcode[i]); /* opcode */ break; @@ -465,6 +570,12 @@ for (i = 0; opc_val[i] >= 0; i++) { /* loop thru ops */ fprintf (of, ",%-o", tag); break; + case I_V_SPP: /* syspop */ + fprintf (of, "%s %-o", opcode[i], va); + if (tag & 2) + fprintf (of, ",2"); + break; + case I_V_PPO: /* pop */ fprintf (of, "POP %-o,%-o", op, nonop); if (tag) @@ -477,6 +588,13 @@ for (i = 0; opc_val[i] >= 0; i++) { /* loop thru ops */ fprintf (of, ",%-o", tag); break; + case I_V_OPO: /* operand optional */ + if (!tag && !va) + { + fprintf (of, "%s", opcode[i]); /* opcode only */ + break; + } /* or fall through to MRF */ + case I_V_MRF: /* mem ref */ fprintf (of, "%s %-o", opcode[i], va); if (tag) @@ -540,7 +658,7 @@ return cptr; /* no change */ t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw) { -int32 i, j, k; +int32 i, j, k, ch; t_value d, tag; t_stat r; char gbuf[CBUFSIZE]; @@ -555,16 +673,27 @@ for (i = 1; (i < 4) && (cptr[i] != 0); i++) { if ((sw & SWMASK ('A')) || ((*cptr == '\'') && cptr++)) { /* ASCII char? */ if (cptr[0] == 0) /* must have 1 char */ return SCPE_ARG; - val[0] = (t_value) cptr[0] | 0200; + for (i = j = 0, val[0] = 0; i < 3; i++) { + if (cptr[i] == 0) /* latch str end */ + j = 1; + ch = cptr[i] & 0377; + if (ch <= 037 || ch >= 0200) + k = -1; + else + k = ch - 040; /* map ext. to int. ASCII */ + if (j || (k < 0)) /* bad, end? spc */ + k = 0; + val[0] = (val[0] << 8) | k; + } return SCPE_OK; } -if ((sw & SWMASK ('C')) || ((*cptr == '"') && cptr++)) { /* string? */ +if ((sw & SWMASK ('C')) || ((*cptr == '"') && cptr++)) { /* string of 6-bit chars? */ if (cptr[0] == 0) /* must have 1 char */ return SCPE_ARG; for (i = j = 0, val[0] = 0; i < 4; i++) { if (cptr[i] == 0) /* latch str end */ j = 1; - k = ascii_to_sds[cptr[i] & 0177]; /* cvt char */ + k = ascii_to_sds(cptr[i]); /* cvt char */ if (j || (k < 0)) /* bad, end? spc */ k = 0; val[0] = (val[0] << 6) | k; @@ -581,7 +710,7 @@ j = (opc_val[i] >> I_V_FL) & I_M_FL; /* get class */ switch (j) { /* case on class */ - case I_V_NPN: case I_V_OPO: /* opcode only */ + case I_V_NPN: /* no operand */ break; case I_V_SHF: /* shift */ @@ -609,8 +738,12 @@ switch (j) { /* case on class */ val[0] = val[0] | d | tag; break; + case I_V_OPO: /* operand optional */ + case I_V_SPP: /* syspop */ case I_V_MRF: /* mem ref */ cptr = get_glyph (cptr, gbuf, ','); /* get next field */ + if (gbuf[0]=='\0' && j==I_V_OPO) /* operand optional */ + break; d = get_uint (gbuf, 8, VA_MASK, &r); /* virt address */ if (r != SCPE_OK) return SCPE_ARG; diff --git a/VAX/vax780_defs.h b/VAX/vax780_defs.h index c47b32dc..62abae1b 100644 --- a/VAX/vax780_defs.h +++ b/VAX/vax780_defs.h @@ -1,6 +1,6 @@ /* vax780_defs.h: VAX 780 model-specific definitions file - Copyright (c) 2004-2014, Robert M Supnik + Copyright (c) 2004-2015, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -23,6 +23,8 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 29-Mar-15 RMS Added model specific IPR max + 16-Dec-14 RMS Removed TQ boot code (780 VMB doesn't support tape boot) 05-Sep-14 RMS Fixed SBR test (found by Mark Pizzolato) 29-Nov-13 RMS Added system-specific unaligned routines 12-Dec-12 RMS Fixed IO base address for RQB, RQC, RQD @@ -53,8 +55,8 @@ #define FULL_VAX 1 #endif -#ifndef _VAX_780_DEFS_H_ -#define _VAX_780_DEFS_H_ 1 +#ifndef VAX_780_DEFS_H_ +#define VAX_780_DEFS_H_ 1 /* Microcode constructs */ @@ -123,6 +125,7 @@ #define MT_SBITA 53 /* SBI timeout addr */ #define MT_SBIQC 54 /* SBI timeout clear */ #define MT_MBRK 60 /* microbreak */ +#define MT_MAX 63 /* last valid IPR */ /* Machine specific reserved operand tests */ @@ -226,7 +229,7 @@ #define DZ_MUXES 4 /* max # of DZV muxes */ #define DZ_LINES 8 /* lines per DZV mux */ -#define VH_MUXES 4 /* max # of DHQ muxes */ +#define VH_MUXES 4 /* max # of DHU muxes */ #define DLX_LINES 16 /* max # of KL11/DL11's */ #define DCX_LINES 16 /* max # of DC11's */ #define MT_MAXFR (1 << 16) /* magtape max rec */ @@ -410,7 +413,6 @@ typedef struct { #define BOOT_HK 1 /* for VMB */ #define BOOT_RL 2 #define BOOT_UDA 17 -#define BOOT_TK 18 /* Function prototypes for virtual memory interface */ diff --git a/VAX/vax780_fload.c b/VAX/vax780_fload.c index d8c2ed3e..fc304f74 100644 --- a/VAX/vax780_fload.c +++ b/VAX/vax780_fload.c @@ -68,10 +68,10 @@ /* RT11 directory entry offsets */ #define DE_STATUS 0 /* status (odd byte) */ -#define TENTAT 001 /* tentative */ -#define EMPTY 002 -#define PERM 004 -#define ENDSEG 010 /* end of segment */ +#define TENTAT 001 /* tentative */ +#define EMPTY 002 +#define PERM 004 +#define ENDSEG 010 /* end of segment */ #define DE_NAME 1 /* file name */ #define DE_FLNT 4 /* file length */ #define DE_SIZE 7 /* entry size in words */ @@ -88,7 +88,7 @@ uint32 rtfile_find (uint32 block, uint32 sector); /* FLOAD file_name {file_origin} */ -t_stat vax780_fload (int flag, char *cptr) +t_stat vax780_fload (int32 flag, char *cptr) { char gbuf[CBUFSIZE]; uint16 file_name[3], blkbuf[BLK_SIZE]; diff --git a/VAX/vax780_sbi.c b/VAX/vax780_sbi.c index c33204eb..9798a8da 100644 --- a/VAX/vax780_sbi.c +++ b/VAX/vax780_sbi.c @@ -1,6 +1,6 @@ /* vax780_sbi.c: VAX 11/780 SBI - Copyright (c) 2004-2011, Robert M Supnik + Copyright (c) 2004-2015, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -27,7 +27,10 @@ sbi bus controller + 29-Mar-2015 RMS Added in-exception test to machine check + 16-Dec-2014 RMS Removed TQ boot entry (VMB doesn't support tape boot) 21-Mar-2011 RMS Added autoreboot capability (Mark Pizzalato) + 04-Feb-2011 MP Added RQB, RQC, and RQD as bootable controllers 31-May-2008 RMS Fixed machine_check calling sequence (Peter Schorn) 03-May-2006 RMS Fixed writes to ACCS 28-May-2008 RMS Inlined physical memory routines @@ -111,7 +114,9 @@ static struct boot_dev boot_tab[] = { { "HK", BOOT_HK, 0 }, { "RL", BOOT_RL, 0 }, { "RQ", BOOT_UDA, 1 << 24 }, - { "TQ", BOOT_TK, 1 << 24 }, + { "RQB", BOOT_UDA, 1 << 24 }, + { "RQC", BOOT_UDA, 1 << 24 }, + { "RQD", BOOT_UDA, 1 << 24 }, { NULL } }; @@ -125,10 +130,6 @@ extern int32 crd_err, mem_err, hlt_pin; extern int32 tmr_int, tti_int, tto_int; extern jmp_buf save_env; extern int32 p1; -extern int32 sim_switches; -extern DEVICE *sim_devices[]; -extern FILE *sim_log; -extern CTAB *sim_vm_cmd; t_stat sbi_reset (DEVICE *dptr); void sbi_set_tmo (int32 pa); @@ -137,7 +138,7 @@ t_stat vax780_boot (int32 flag, char *ptr); t_stat vax780_boot_parse (int32 flag, char *ptr); t_stat cpu_boot (int32 unitno, DEVICE *dptr); -extern t_stat vax780_fload (int flag, char *cptr); +extern t_stat vax780_fload (int32 flag, char *cptr); extern int32 intexc (int32 vec, int32 cc, int32 ipl, int ei); extern int32 iccs_rd (void); extern int32 nicr_rd (void); @@ -488,7 +489,7 @@ return; longword of data */ -int32 ReadReg (int32 pa, int32 lnt) +int32 ReadReg (uint32 pa, int32 lnt) { int32 nexus, val; @@ -515,7 +516,7 @@ return 0; none */ -void WriteReg (int32 pa, int32 val, int32 lnt) +void WriteReg (uint32 pa, int32 val, int32 lnt) { int32 nexus; @@ -571,6 +572,8 @@ int32 machine_check (int32 p1, int32 opc, int32 cc, int32 delta) { int32 acc, err; +if (in_ie) /* in exc? panic */ + ABORT (STOP_INIE); err = (GET_TRAP (trpirq) << 4) | (pme << 3) | ASTLVL; /* error word */ cc = intexc (SCB_MCHK, cc, 0, IE_SVE); /* take exception */ acc = ACC_MASK (KERN); /* in kernel mode */ @@ -601,9 +604,7 @@ if ((cpu_boot_cmd[0] == 0) || /* saved boot cmd? */ (reset_all (0) != SCPE_OK) || /* reset the world */ (cpu_boot (0, NULL) != SCPE_OK)) /* set up boot code */ ABORT (STOP_BOOT); /* any error? */ -printf ("Rebooting...\n"); -if (sim_log) - fprintf (sim_log, "Rebooting...\n"); +sim_printf ("Rebooting...\n"); return cc; } @@ -637,8 +638,10 @@ UNIT *uptr; DIB *dibp; t_stat r; +if (!ptr || !*ptr) + return SCPE_2FARG; regptr = get_glyph (ptr, gbuf, 0); /* get glyph */ -if (slptr = strchr (gbuf, '/')) { /* found slash? */ +if ((slptr = strchr (gbuf, '/'))) { /* found slash? */ regptr = strchr (ptr, '/'); /* locate orig */ *slptr = 0; /* zero in string */ } @@ -686,9 +689,7 @@ t_stat cpu_boot (int32 unitno, DEVICE *dptr) { t_stat r; -printf ("Loading boot code from vmb.exe\n"); -if (sim_log) - fprintf (sim_log, "Loading boot code from vmb.exe\n"); +sim_printf ("Loading boot code from vmb.exe\n"); r = load_cmd (0, "-O vmb.exe 200"); if (r != SCPE_OK) return r; @@ -756,9 +757,7 @@ if ((nexusR[idx] && dibp->rd && /* conflict? */ (nexusR[idx] != dibp->rd)) || (nexusW[idx] && dibp->wr && (nexusW[idx] != dibp->wr))) { - printf ("Nexus %s conflict at %d\n", sim_dname (dptr), dibp->ba); - if (sim_log) - fprintf (sim_log, "Nexus %s conflict at %d\n", sim_dname (dptr), dibp->ba); + sim_printf ("Nexus %s conflict at %d\n", sim_dname (dptr), dibp->ba); return SCPE_STOP; } if (dibp->rd) /* set rd dispatch */ @@ -784,15 +783,15 @@ for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { /* loop thru dev */ dibp = (DIB *) dptr->ctxt; /* get DIB */ if (dibp && !(dptr->flags & DEV_DIS)) { /* defined, enabled? */ if (dptr->flags & DEV_NEXUS) { /* Nexus? */ - if (r = build_nexus_tab (dptr, dibp)) /* add to dispatch table */ + if ((r = build_nexus_tab (dptr, dibp))) /* add to dispatch table */ return r; } else if (dptr->flags & DEV_MBUS) { /* Massbus? */ - if (r = build_mbus_tab (dptr, dibp)) + if ((r = build_mbus_tab (dptr, dibp))) return r; } else { /* no, Unibus device */ - if (r = build_ubus_tab (dptr, dibp)) /* add to dispatch tab */ + if ((r = build_ubus_tab (dptr, dibp))) /* add to dispatch tab */ return r; } /* end else */ } /* end if enabled */ diff --git a/VAX/vax780_stddev.c b/VAX/vax780_stddev.c index 5ac7271d..b3aa7027 100644 --- a/VAX/vax780_stddev.c +++ b/VAX/vax780_stddev.c @@ -1,6 +1,6 @@ /* vax780_stddev.c: VAX 11/780 standard I/O devices - Copyright (c) 1998-2012, Robert M Supnik + Copyright (c) 1998-2015, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -29,6 +29,7 @@ todr TODR clock tmr interval timer + 03-Apr-15 RMS TODR only increments if != 0 18-Apr-12 RMS Revised to use clock coscheduling 21-Mar-11 RMS Added reboot capability 17-Aug-08 RMS Resync TODR on any clock reset @@ -188,7 +189,6 @@ int32 fl_bptr = 0; /* buffer pointer */ uint8 comm_region[COMM_LNT] = { 0 }; /* comm region */ -extern int32 sim_switches; extern jmp_buf save_env; t_stat tti_svc (UNIT *uptr); @@ -218,7 +218,7 @@ extern int32 con_halt (int32 code, int32 cc); tti_reg TTI register list */ -UNIT tti_unit = { UDATA (&tti_svc, TT_MODE_8B, 0), 0 }; +UNIT tti_unit = { UDATA (&tti_svc, UNIT_IDLE|TT_MODE_8B, 0), SERIAL_IN_WAIT }; REG tti_reg[] = { { HRDATA (RXDB, tti_buf, 16) }, @@ -378,7 +378,7 @@ return (tti_csr & RXCS_RD); void rxcs_wr (int32 data) { if ((data & CSR_IE) == 0) - tto_int = 0; + tti_int = 0; else if ((tti_csr & (CSR_DONE + CSR_IE)) == CSR_DONE) tti_int = 1; tti_csr = (tti_csr & ~RXCS_WR) | (data & RXCS_WR); @@ -389,9 +389,12 @@ int32 rxdb_rd (void) { int32 t = tti_buf; /* char + error */ -tti_csr = tti_csr & ~CSR_DONE; /* clr done */ -tti_buf = tti_buf & BMASK; /* clr errors */ -tti_int = 0; +if (tti_csr & CSR_DONE) { /* Input pending ? */ + tti_csr = tti_csr & ~CSR_DONE; /* clr done */ + tti_buf = tti_buf & BMASK; /* clr errors */ + tti_int = 0; + sim_activate_abs (&tti_unit, tti_unit.wait); /* check soon for more input */ + } return t; } @@ -558,7 +561,7 @@ if (interp || (tmr_iccs & TMR_CSR_RUN)) { /* interp, running? */ return tmr_icr; } -int32 nicr_rd () +int32 nicr_rd (void) { return tmr_nicr; } @@ -573,9 +576,10 @@ tmr_nicr = val; t_stat clk_svc (UNIT *uptr) { tmr_poll = sim_rtcn_calb (clk_tps, TMR_CLK); /* calibrate clock */ -sim_activate (&clk_unit, tmr_poll); /* reactivate unit */ +sim_activate_after (uptr, 1000000/clk_tps); /* reactivate unit */ tmxr_poll = tmr_poll * TMXR_MULT; /* set mux poll */ -todr_reg = todr_reg + 1; /* incr TODR */ +if (todr_reg) /* not zero? */ + todr_reg = todr_reg + 1; /* incr TODR */ if ((tmr_iccs & TMR_CSR_RUN) && tmr_use_100hz) /* timer on, std intvl? */ tmr_incr (TMR_INC); /* do timer service */ return SCPE_OK; @@ -645,6 +649,7 @@ return (t? t - 1: wait); t_stat clk_reset (DEVICE *dptr) { +sim_register_clock_unit (&clk_unit); /* declare clock unit */ tmr_poll = sim_rtcn_init (clk_unit.wait, TMR_CLK); /* init 100Hz timer */ sim_activate (&clk_unit, tmr_poll); /* activate 100Hz unit */ tmxr_poll = tmr_poll * TMXR_MULT; /* set mux poll */ diff --git a/VAX/vax780_syslist.c b/VAX/vax780_syslist.c index aad58dbd..85d42165 100644 --- a/VAX/vax780_syslist.c +++ b/VAX/vax780_syslist.c @@ -54,7 +54,6 @@ extern DEVICE tu_dev; extern DEVICE dz_dev; extern DEVICE xu_dev, xub_dev; -extern int32 sim_switches; extern UNIT cpu_unit; extern void WriteB (uint32 pa, int32 val); extern void rom_wr_B (int32 pa, int32 val); diff --git a/VAX/vax780_uba.c b/VAX/vax780_uba.c index bb6105fe..d390a013 100644 --- a/VAX/vax780_uba.c +++ b/VAX/vax780_uba.c @@ -179,11 +179,8 @@ int32 autcon_enb = 1; /* autoconfig enable */ extern int32 trpirq; extern int32 autcon_enb; extern jmp_buf save_env; -extern DEVICE *sim_devices[]; extern UNIT cpu_unit; extern uint32 nexus_req[NEXUS_HLVL]; -extern int32 sim_switches; -extern FILE *sim_log, *sim_deb; t_stat uba_svc (UNIT *uptr); t_stat uba_reset (DEVICE *dptr); @@ -303,7 +300,7 @@ t_stat uba_rdreg (int32 *val, int32 pa, int32 lnt) int32 idx, ofs; if ((pa & 3) || (lnt != L_LONG)) { /* unaligned or not lw? */ - printf (">>UBA: invalid adapter read mask, pa = %X, lnt = %d\r\n", pa, lnt); + sim_printf (">>UBA: invalid adapter read mask, pa = %X, lnt = %d\r\n", pa, lnt); sbi_set_errcnf (); /* err confirmation */ return SCPE_OK; } @@ -392,7 +389,7 @@ t_stat uba_wrreg (int32 val, int32 pa, int32 lnt) int32 idx, ofs, old_cr; if ((pa & 3) || (lnt != L_LONG)) { /* unaligned or not lw? */ - printf (">>UBA: invalid adapter write mask, pa = %X, lnt = %d\r\n", pa, lnt); + sim_printf (">>UBA: invalid adapter write mask, pa = %X, lnt = %d\r\n", pa, lnt); sbi_set_errcnf (); /* err confirmation */ return SCPE_OK; } @@ -525,7 +522,7 @@ if ((lnt == L_BYTE) || /* byte? */ iod = iod << 16; } else { - printf (">>UBA: invalid read mask, pa = %x, lnt = %d\n", pa, lnt); + sim_printf (">>UBA: invalid read mask, pa = %x, lnt = %d\n", pa, lnt); sbi_set_errcnf (); /* err confirmation */ iod = 0; } @@ -550,7 +547,7 @@ if (lnt == L_BYTE) /* byte? DATOB */ else if ((lnt == L_WORD) && ((pa & 1) == 0)) /* aligned word? */ WriteUb (pa, val, WRITE); /* DATO */ else { - printf (">>UBA: invalid write mask, pa = %x, lnt = %d\n", pa, lnt); + sim_printf (">>UBA: invalid write mask, pa = %x, lnt = %d\n", pa, lnt); sbi_set_errcnf (); /* err confirmation */ } SET_IRQL; /* update ints */ diff --git a/VAX/vax_cis.c b/VAX/vax_cis.c index e75a53b8..e15eb23b 100644 --- a/VAX/vax_cis.c +++ b/VAX/vax_cis.c @@ -71,8 +71,8 @@ typedef struct { uint32 val[DSTRLNT]; } DSTR; -static DSTR Dstr_zero = { 0, 0, 0, 0, 0 }; -static DSTR Dstr_one = { 0, 0x10, 0, 0, 0 }; +static DSTR Dstr_zero = { 0, {0, 0, 0, 0} }; +static DSTR Dstr_one = { 0, {0x10, 0, 0, 0} }; extern int32 R[16]; extern int32 PSL; @@ -80,7 +80,6 @@ extern int32 trpirq; extern int32 p1; extern int32 fault_PC; extern int32 ibcnt, ppc; -extern int32 sim_interval; extern jmp_buf save_env; int32 ReadDstr (int32 lnt, int32 addr, DSTR *dec, int32 acc); @@ -331,7 +330,7 @@ switch (opc) { /* case on opcode */ R[3] = (R[3] + 1) & LMASK; /* next string char */ if (i >= sim_interval) { /* done with interval? */ sim_interval = 0; - if (r = sim_process_event ()) { /* presumably WRU */ + if ((r = sim_process_event ())) { /* presumably WRU */ PC = fault_PC; /* backup up PC */ ABORT (r); /* abort flushes IB */ } @@ -1225,8 +1224,8 @@ for (i = 0; i <= end; i++) { /* loop thru string */ } if ((i == end) && ((lnt & 1) == 0)) c = c & 0xF; -/* if (((c & 0xF0) > 0x90) || /* check hi digit */ -/* ((c & 0x0F) > 0x09)) /* check lo digit */ +/* if (((c & 0xF0) > 0x90) || *//* check hi digit */ +/* ((c & 0x0F) > 0x09)) *//* check lo digit */ /* RSVD_OPND_FAULT; */ src->val[i / 4] = src->val[i / 4] | (c << ((i % 4) * 8)); } /* end for */ @@ -1550,7 +1549,7 @@ uint32 NibbleRshift (DSTR *dsrc, int32 sc, uint32 cin) { int32 i, s, nc; -if (s = sc * 4) { +if ((s = sc * 4)) { for (i = DSTRMAX; i >= 0; i--) { nc = (dsrc->val[i] << (32 - s)) & LMASK; dsrc->val[i] = ((dsrc->val[i] >> s) | @@ -1574,7 +1573,7 @@ uint32 NibbleLshift (DSTR *dsrc, int32 sc, uint32 cin) { int32 i, s, nc; -if (s = sc * 4) { +if ((s = sc * 4)) { for (i = 0; i < DSTRLNT; i++) { nc = dsrc->val[i] >> (32 - s); dsrc->val[i] = ((dsrc->val[i] << s) | diff --git a/VAX/vax_cmode.c b/VAX/vax_cmode.c index 24c7f8ac..72ce6302 100644 --- a/VAX/vax_cmode.c +++ b/VAX/vax_cmode.c @@ -59,8 +59,6 @@ extern int32 recqptr; /* recq pointer */ extern int32 pcq[]; extern int32 pcq_p; extern int32 ibcnt, ppc; -extern int32 sim_interval; -extern uint32 sim_brk_summ; extern jmp_buf save_env; int32 GeteaB (int32 spec); @@ -597,7 +595,7 @@ switch ((IR >> 12) & 017) { /* decode IR<15:12> */ cc = CC_V | CC_C; /* set cc's */ break; /* done */ } - if ((src == LSIGN) && (src2 == WMASK)) { /* -2^31 / -1? */ + if (((uint32)src == LSIGN) && ((uint32)src2 == WMASK)) { /* -2^31 / -1? */ cc = CC_V; /* overflow */ break; /* done */ } @@ -621,7 +619,7 @@ switch ((IR >> 12) & 017) { /* decode IR<15:12> */ else src2 = RdMemW (GeteaW (dstspec)); src2 = src2 & 077; src = RdRegW (srcspec); /* get src */ - if (sign = ((src & WSIGN)? 1: 0)) + if ((sign = ((src & WSIGN)? 1: 0))) src = src | ~WMASK; if (src2 == 0) { /* [0] */ dst = src; /* result */ @@ -669,7 +667,7 @@ switch ((IR >> 12) & 017) { /* decode IR<15:12> */ dst = ((uint32) src) << src2; i = ((src >> (32 - src2)) | (-sign << src2)) & LMASK; oc = (i & 1)? CC_C: 0; - if ((dst & LSIGN)? (i != LMASK): (i != 0)) + if ((dst & LSIGN)? ((uint32)i != LMASK): (i != 0)) oc = oc | CC_V; } else if (src2 == 32) { /* [32] = -32 */ diff --git a/VAX/vax_cpu.c b/VAX/vax_cpu.c index a0aa2466..f7c9d527 100644 --- a/VAX/vax_cpu.c +++ b/VAX/vax_cpu.c @@ -1,6 +1,6 @@ /* vax_cpu.c: VAX CPU - Copyright (c) 1998-2012, Robert M Supnik + Copyright (c) 1998-2015, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -25,6 +25,7 @@ cpu VAX central processor + 29-Mar-15 RMS Moved in-exception test to model-specific machine checks 20-Sep-11 MP Fixed idle conditions for various versions of Ultrix, Quasijarus-4.3BSD, NetBSD and OpenBSD. Note: Since NetBSD and OpenBSD are still actively @@ -308,12 +309,6 @@ const uint32 align[4] = { /* External and forward references */ -extern int32 sim_interval; -extern int32 sim_int_char; -extern int32 sim_switches; -extern uint32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ -extern t_bool sim_idle_enab; - extern t_stat build_dib_tab (void); extern UNIT rom_unit, nvr_unit; extern int32 op_ashq (int32 *opnd, int32 *rh, int32 *flg); @@ -508,7 +503,7 @@ DEVICE cpu_dev = { t_stat sim_instr (void) { -volatile int32 opc, cc; /* used by setjmp */ +volatile int32 opc = 0, cc; /* used by setjmp */ volatile int32 acc; /* set by setjmp */ int abortval; t_stat r; @@ -594,8 +589,6 @@ else if (abortval < 0) { /* mm or rsrv or int */ break; case SCB_MCHK: /* machine check */ - if (in_ie) /* in exc? panic */ - ABORT (STOP_INIE); cc = machine_check (p1, opc, cc, delta); /* system specific */ in_ie = 0; GET_CUR; /* PSL changed */ @@ -642,7 +635,7 @@ for ( ;; ) { */ if (trpirq) { /* trap or interrupt? */ - if (temp = GET_TRAP (trpirq)) { /* trap? */ + if ((temp = GET_TRAP (trpirq))) { /* trap? */ cc = intexc (SCB_ARITH, cc, 0, IE_EXC); /* take, clear trap */ GET_CUR; /* set cur mode */ in_ie = 1; @@ -650,7 +643,7 @@ for ( ;; ) { SP = SP - 4; in_ie = 0; } - else if (temp = GET_IRQL (trpirq)) { /* interrupt? */ + else if ((temp = GET_IRQL (trpirq))) { /* interrupt? */ int32 vec; if (temp == IPL_HLTPIN) { /* console halt? */ hlt_pin = 0; /* clear intr */ @@ -1462,7 +1455,7 @@ for ( ;; ) { default: RSVD_ADDR_FAULT; /* end case idxspec */ - } + } switch (disp & (DR_ACMASK|DR_SPFLAG|DR_LNMASK)) { /* case acc+lnt */ case VB: @@ -1948,7 +1941,8 @@ for ( ;; ) { temp = CC_V; SET_TRAP (TRAP_DIVZRO); } - else if ((op0 == LMASK) && (op1 == LSIGN)) { /* overflow? */ + else if ((((uint32)op0) == LMASK) && + (((uint32)op1) == LSIGN)) { /* overflow? */ r = op1; temp = CC_V; INTOV; @@ -2187,6 +2181,7 @@ for ( ;; ) { BRANCHB (brdisp); if (((PSL & PSL_IS) != 0) && /* on IS? */ (PSL_GETIPL (PSL) == 0x1F) && /* at IPL 31 */ + (mapen == 0) && /* Running from ROM */ (fault_PC == 0x2004361B)) /* Boot ROM Character Prompt */ cpu_idle(); } @@ -2934,7 +2929,7 @@ for ( ;; ) { if (op7 < 0) { Read (op8, L_BYTE, WA); Read ((op8 + 7) & LMASK, L_BYTE, WA); - } + } if (op5 >= 0) R[op5] = temp; else Write (op6, temp, L_LONG, WA); @@ -2950,7 +2945,7 @@ for ( ;; ) { if (op7 < 0) { Read (op8, L_BYTE, WA); Read ((op8 + 7) & LMASK, L_BYTE, WA); - } + } if (op5 >= 0) R[op5] = temp; else Write (op6, temp, L_LONG, WA); @@ -3131,8 +3126,7 @@ return; t_stat cpu_idle_svc (UNIT *uptr) { -if (sim_idle_enab) - sim_idle (TMR_CLK, FALSE); +sim_idle (TMR_CLK, TRUE); return SCPE_OK; } @@ -3212,7 +3206,7 @@ return SCPE_NXM; t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc) { int32 mc = 0; -uint32 i, clim; +uint32 i, clim, uval = (uint32)val; uint32 *nM = NULL; if ((val <= 0) || (val > MAXMEMSIZE_X)) @@ -3221,15 +3215,16 @@ for (i = val; i < MEMSIZE; i = i + 4) mc = mc | M[i >> 2]; if ((mc != 0) && !get_yn ("Really truncate memory [N]?", FALSE)) return SCPE_OK; -nM = (uint32 *) calloc (val >> 2, sizeof (uint32)); +nM = (uint32 *) calloc (uval >> 2, sizeof (uint32)); if (nM == NULL) return SCPE_MEM; -clim = (uint32) ((((uint32) val) < MEMSIZE)? val: MEMSIZE); +clim = (uint32)((uval < MEMSIZE)? uval: MEMSIZE); for (i = 0; i < clim; i = i + 4) nM[i >> 2] = M[i >> 2]; free (M); M = nM; -MEMSIZE = val; +MEMSIZE = uval; +reset_all (0); return SCPE_OK; } @@ -3326,8 +3321,6 @@ t_stat r; InstHistory *h; extern const char *opcode[]; extern t_value *sim_eval; -extern t_stat fprint_sym (FILE *ofile, t_addr addr, t_value *val, - UNIT *uptr, int32 sw); if (hst_lnt == 0) /* enabled? */ return SCPE_NOFNC; diff --git a/VAX/vax_cpu1.c b/VAX/vax_cpu1.c index 8d02ca17..2ed53b84 100644 --- a/VAX/vax_cpu1.c +++ b/VAX/vax_cpu1.c @@ -1,6 +1,6 @@ /* vax_cpu1.c: VAX complex instructions - Copyright (c) 1998-2012, Robert M Supnik + Copyright (c) 1998-2015, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -23,6 +23,7 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 29-Mar-15 RMS Added model-specific IPR max 15-Mar-12 RMS Fixed potential integer overflow in LDPCTX (Mark Pizzolato) 25-Nov-11 RMS Added VEC_QBUS test in interrupt handler 23-Mar-11 RMS Revised idle design (Mark Pizzolato) @@ -99,9 +100,7 @@ extern int32 fault_PC; extern int32 pcq[PCQ_SIZE]; extern int32 pcq_p; extern int32 in_ie; -extern int32 sim_interval; extern int32 ibcnt, ppc; -extern FILE *sim_deb; extern DEVICE cpu_dev; extern int32 Test (uint32 va, int32 acc, int32 *status); @@ -1445,7 +1444,7 @@ int32 cc; if (PSL & PSL_CUR) /* must be kernel */ RSVD_INST_FAULT; -if (prn > 63) /* reg# > 63? fault */ +if (prn > MT_MAX) /* reg# > max? fault */ RSVD_OPND_FAULT; CC_IIZZ_L (val); /* set cc's */ switch (prn) { /* case on reg # */ @@ -1572,7 +1571,7 @@ int32 val; if (PSL & PSL_CUR) /* must be kernel */ RSVD_INST_FAULT; -if (prn > 63) /* reg# > 63? fault */ +if (prn > MT_MAX) /* reg# > max? fault */ RSVD_OPND_FAULT; switch (prn) { /* case on reg# */ diff --git a/VAX/vax_defs.h b/VAX/vax_defs.h index 608f8662..9e5bacf5 100644 --- a/VAX/vax_defs.h +++ b/VAX/vax_defs.h @@ -40,8 +40,8 @@ 30-Apr-02 RMS Added CLR_TRAPS macro */ -#ifndef _VAX_DEFS_H -#define _VAX_DEFS_H 0 +#ifndef VAX_DEFS_H +#define VAX_DEFS_H 0 #ifndef VM_VAX #define VM_VAX 0 @@ -473,7 +473,7 @@ #define PR_PACV 2 /* pte ACV (780) */ #define PR_PLNV 3 /* pte len viol */ #define PR_TNV 4 /* TNV */ -/* #define PR_TB 5 /* impossible */ +/* #define PR_TB 5 *//* impossible */ #define PR_PTNV 6 /* pte TNV */ #define PR_OK 7 /* ok */ #define MM_PARAM(w,p) (((w)? 4: 0) | ((p) & 3)) /* fault param */ diff --git a/VAX/vax_io.c b/VAX/vax_io.c index 10206dd4..e3294dbe 100644 --- a/VAX/vax_io.c +++ b/VAX/vax_io.c @@ -118,9 +118,6 @@ extern int32 PSL, SISR, trpirq, mem_err, crd_err, hlt_pin; extern int32 p1; extern int32 ssc_bto; extern jmp_buf save_env; -extern int32 sim_switches; -extern DEVICE *sim_devices[]; -extern FILE *sim_log; t_stat dbl_rd (int32 *data, int32 addr, int32 access); t_stat dbl_wr (int32 data, int32 addr, int32 access); @@ -476,7 +473,7 @@ if (lnt < L_LONG) { int32 t = cqbic_rd (pa); nval = ((val & mask) << sc) | (t & ~(mask << sc)); val = val << sc; - } + } else nval = val; switch (rg) { @@ -723,7 +720,7 @@ if ((ba | bc) & 03) { /* check alignment */ if (!qba_map_addr (ba + i, &ma)) /* inv or NXM? */ return (bc - i); } - *buf = ReadB (ma); + *buf = (uint8)ReadB (ma); ma = ma + 1; } } @@ -757,7 +754,7 @@ if ((ba | bc) & 03) { /* check alignment */ if (!qba_map_addr (ba + i, &ma)) /* inv or NXM? */ return (bc - i); } - *buf = ReadW (ma); + *buf = (uint16)ReadW (ma); ma = ma + 2; } } @@ -883,7 +880,7 @@ init_ubus_tab (); /* init bus tables */ for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { /* loop thru dev */ dibp = (DIB *) dptr->ctxt; /* get DIB */ if (dibp && !(dptr->flags & DEV_DIS)) { /* defined, enabled? */ - if (r = build_ubus_tab (dptr, dibp)) /* add to bus tab */ + if ((r = build_ubus_tab (dptr, dibp))) /* add to bus tab */ return r; } /* end if enabled */ } /* end for */ diff --git a/VAX/vax_mmu.c b/VAX/vax_mmu.c index 864085c7..483fcb73 100644 --- a/VAX/vax_mmu.c +++ b/VAX/vax_mmu.c @@ -581,7 +581,7 @@ return; void zap_tb (int stb) { -int32 i; +size_t i; for (i = 0; i < VA_TBSIZE; i++) { ptlb[i].tag = ptlb[i].pte = -1; @@ -622,7 +622,7 @@ return FALSE; t_stat tlb_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw) { int32 tlbn = uptr - tlb_unit; -int32 idx = (uint32) addr >> 1; +uint32 idx = (uint32) addr >> 1; if (idx >= VA_TBSIZE) return SCPE_NXM; @@ -637,7 +637,7 @@ return SCPE_OK; t_stat tlb_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw) { int32 tlbn = uptr - tlb_unit; -int32 idx = (uint32) addr >> 1; +uint32 idx = (uint32) addr >> 1; if (idx >= VA_TBSIZE) return SCPE_NXM; @@ -656,7 +656,7 @@ return SCPE_OK; t_stat tlb_reset (DEVICE *dptr) { -int32 i; +size_t i; for (i = 0; i < VA_TBSIZE; i++) stlb[i].tag = ptlb[i].tag = stlb[i].pte = ptlb[i].pte = -1; diff --git a/VAX/vax_octa.c b/VAX/vax_octa.c index efb1a99c..c46b2718 100644 --- a/VAX/vax_octa.c +++ b/VAX/vax_octa.c @@ -187,7 +187,7 @@ switch (opc) { break; case MOVH: - if (r = op_tsth (opnd[0])) { /* test for 0 */ + if ((r = op_tsth (opnd[0]))) { /* test for 0 */ h_write_o (spec, va, opnd, acc); /* nz, write result */ CC_IIZP_FP (r); /* set cc's */ } @@ -198,7 +198,7 @@ switch (opc) { break; case MNEGH: - if (r = op_tsth (opnd[0])) { /* test for 0 */ + if ((r = op_tsth (opnd[0]))) { /* test for 0 */ opnd[0] = opnd[0] ^ FPSIGN; /* nz, invert sign */ h_write_o (spec, va, opnd, acc); /* write result */ CC_IIZZ_FP (opnd[0]); /* set cc's */ diff --git a/VAX/vax_stddev.c b/VAX/vax_stddev.c index a3c2b692..ec9f831e 100644 --- a/VAX/vax_stddev.c +++ b/VAX/vax_stddev.c @@ -1,6 +1,6 @@ /* vax_stddev.c: VAX 3900 standard I/O devices - Copyright (c) 1998-2012, Robert M Supnik + Copyright (c) 1998-2015, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -27,6 +27,7 @@ tto terminal output clk 100Hz and TODR clock + 03-Apr-15 RMS TODR only increments if != 0 18-Apr-12 RMS Revised TTI to use clock coscheduling and remove IORESET bug 17-Aug-08 RMS Resync TODR on any clock reset @@ -63,7 +64,6 @@ extern int32 int_req[IPL_HLVL]; extern int32 hlt_pin; -extern int32 sim_switches, sim_is_running; int32 tti_csr = 0; /* control/status */ int32 tto_csr = 0; /* control/status */ @@ -93,7 +93,7 @@ extern int32 sysd_hlt_enb (void); DIB tti_dib = { 0, 0, NULL, NULL, 1, IVCL (TTI), SCB_TTI, { NULL } }; -UNIT tti_unit = { UDATA (&tti_svc, UNIT_IDLE|TT_MODE_8B, 0), 0 }; +UNIT tti_unit = { UDATA (&tti_svc, UNIT_IDLE|TT_MODE_8B, 0), SERIAL_IN_WAIT }; REG tti_reg[] = { { HRDATA (BUF, tti_unit.buf, 16) }, @@ -225,9 +225,12 @@ int32 rxdb_rd (void) { int32 t = tti_unit.buf; /* char + error */ -tti_csr = tti_csr & ~CSR_DONE; /* clr done */ -tti_unit.buf = tti_unit.buf & 0377; /* clr errors */ -CLR_INT (TTI); +if (tti_csr & CSR_DONE) { /* Input pending ? */ + tti_csr = tti_csr & ~CSR_DONE; /* clr done */ + tti_unit.buf = tti_unit.buf & 0377; /* clr errors */ + CLR_INT (TTI); + sim_activate_abs (&tti_unit, tti_unit.wait); /* check soon for more input */ + } return t; } @@ -365,10 +368,10 @@ int32 t; if (clk_csr & CSR_IE) SET_INT (CLK); t = sim_rtcn_calb (clk_tps, TMR_CLK); /* calibrate clock */ -sim_activate (&clk_unit, t); /* reactivate unit */ +sim_activate_after (&clk_unit, 1000000/clk_tps); /* reactivate unit */ tmr_poll = t; /* set tmr poll */ tmxr_poll = t * TMXR_MULT; /* set mux poll */ -if (!todr_blow) /* incr TODR */ +if (!todr_blow && todr_reg) /* incr TODR */ todr_reg = todr_reg + 1; return SCPE_OK; } @@ -412,12 +415,13 @@ t_stat clk_reset (DEVICE *dptr) { int32 t; +sim_register_clock_unit (&clk_unit); todr_resync (); /* resync clock */ clk_csr = 0; CLR_INT (CLK); if (!sim_is_running) { /* RESET (not IORESET)? */ t = sim_rtcn_init (clk_unit.wait, TMR_CLK); /* init timer */ - sim_activate (&clk_unit, t); /* activate unit */ + sim_activate_after (&clk_unit, 1000000/clk_tps); /* activate unit */ tmr_poll = t; /* set tmr poll */ tmxr_poll = t * TMXR_MULT; /* set mux poll */ } diff --git a/VAX/vax_sys.c b/VAX/vax_sys.c index 149f67d9..a7fffc58 100644 --- a/VAX/vax_sys.c +++ b/VAX/vax_sys.c @@ -57,7 +57,6 @@ extern UNIT cpu_unit; extern REG cpu_reg[]; extern int32 saved_PC; extern int32 PSL; -extern int32 sim_switches; t_stat fprint_sym_m (FILE *of, uint32 addr, t_value *val); int32 fprint_sym_qoimm (FILE *of, t_value *val, int32 vp, int32 lnt); @@ -115,518 +114,518 @@ const char *sim_stop_messages[] = { */ const uint16 drom[NUM_INST][MAX_SPEC + 1] = { -0, 0, 0, 0, 0, 0, 0, /* HALT */ -0, 0, 0, 0, 0, 0, 0, /* NOP */ -0, 0, 0, 0, 0, 0, 0, /* REI */ -0, 0, 0, 0, 0, 0, 0, /* BPT */ -0, 0, 0, 0, 0, 0, 0, /* RET */ -0, 0, 0, 0, 0, 0, 0, /* RSB */ -0, 0, 0, 0, 0, 0, 0, /* LDPCTX */ -0, 0, 0, 0, 0, 0, 0, /* SVPCTX */ -4+DR_F, RW, AB, RW, AB, 0, 0, /* CVTPS */ -4+DR_F, RW, AB, RW, AB, 0, 0, /* CVTSP */ -6, RL, RL, RL, RL, RL, WL, /* INDEX */ -4+DR_F, AB, RL, RW, AB, 0, 0, /* CRC */ -3, RB, RW, AB, 0, 0, 0, /* PROBER */ -3, RB, RW, AB, 0, 0, 0, /* PROBEW */ -2, AB, AB, 0, 0, 0, 0, /* INSQUE */ -2, AB, WL, 0, 0, 0, 0, /* REMQUE */ -1, BB, 0, 0, 0, 0, 0, /* BSBB */ -1, BB, 0, 0, 0, 0, 0, /* BRB */ -1, BB, 0, 0, 0, 0, 0, /* BNEQ */ -1, BB, 0, 0, 0, 0, 0, /* BEQL */ -1, BB, 0, 0, 0, 0, 0, /* BGTR */ -1, BB, 0, 0, 0, 0, 0, /* BLEQ */ -1, AB, 0, 0, 0, 0, 0, /* JSB */ -1, AB, 0, 0, 0, 0, 0, /* JMP */ -1, BB, 0, 0, 0, 0, 0, /* BGEQ */ -1, BB, 0, 0, 0, 0, 0, /* BLSS */ -1, BB, 0, 0, 0, 0, 0, /* BGTRU */ -1, BB, 0, 0, 0, 0, 0, /* BLEQU */ -1, BB, 0, 0, 0, 0, 0, /* BVC */ -1, BB, 0, 0, 0, 0, 0, /* BVS */ -1, BB, 0, 0, 0, 0, 0, /* BCC */ -1, BB, 0, 0, 0, 0, 0, /* BCS */ -4+DR_F, RW, AB, RW, AB, 0, 0, /* ADDP4 */ -6+DR_F, RW, AB, RW, AB, RW, AB, /* ADDP6 */ -4+DR_F, RW, AB, RW, AB, 0, 0, /* SUBP4 */ -6+DR_F, RW, AB, RW, AB, RW, AB, /* SUBP6 */ -5+DR_F, RW, AB, AB, RW, AB, 0, /* CVTPT */ -6+DR_F, RW, AB, RW, AB, RW, AB, /* MULP6 */ -5+DR_F, RW, AB, AB, RW, AB, 0, /* CVTTP */ -6+DR_F, RW, AB, RW, AB, RW, AB, /* DIVP6 */ -3+DR_F, RW, AB, AB, 0, 0, 0, /* MOVC3 */ -3+DR_F, RW, AB, AB, 0, 0, 0, /* CMPC3 */ -4+DR_F, RW, AB, AB, RB, 0, 0, /* SCANC */ -4+DR_F, RW, AB, AB, RB, 0, 0, /* SPANC */ -5+DR_F, RW, AB, RB, RW, AB, 0, /* MOVC5 */ -5+DR_F, RW, AB, RB, RW, AB, 0, /* CMPC5 */ -6+DR_F, RW, AB, RB, AB, RW, AB, /* MOVTC */ -6+DR_F, RW, AB, RB, AB, RW, AB, /* MOVTUC */ -1, BW, 0, 0, 0, 0, 0, /* BSBW */ -1, BW, 0, 0, 0, 0, 0, /* BRW */ -2, RW, WL, 0, 0, 0, 0, /* CVTWL */ -2, RW, WB, 0, 0, 0, 0, /* CVTWB */ -3+DR_F, RW, AB, AB, 0, 0, 0, /* MOVP */ -3+DR_F, RW, AB, AB, 0, 0, 0, /* CMPP3 */ -3+DR_F, RW, AB, WL, 0, 0, 0, /* CVTPL */ -4+DR_F, RW, AB, RW, AB, 0, 0, /* CMPP4 */ -4+DR_F, RW, AB, AB, AB, 0, 0, /* EDITPC */ -4+DR_F, RW, AB, RW, AB, 0, 0, /* MATCHC */ -3+DR_F, RB, RW, AB, 0, 0, 0, /* LOCC */ -3+DR_F, RB, RW, AB, 0, 0, 0, /* SKPC */ -2, RW, WL, 0, 0, 0, 0, /* MOVZWL */ -4, RW, RW, MW, BW, 0, 0, /* ACBW */ -2, AW, WL, 0, 0, 0, 0, /* MOVAW */ -1, AW, 0, 0, 0, 0, 0, /* PUSHAW */ -2, RF, ML, 0, 0, 0, 0, /* ADDF2 */ -3, RF, RF, WL, 0, 0, 0, /* ADDF3 */ -2, RF, ML, 0, 0, 0, 0, /* SUBF2 */ -3, RF, RF, WL, 0, 0, 0, /* SUBF3 */ -2, RF, ML, 0, 0, 0, 0, /* MULF2 */ -3, RF, RF, WL, 0, 0, 0, /* MULF3 */ -2, RF, ML, 0, 0, 0, 0, /* DIVF2 */ -3, RF, RF, WL, 0, 0, 0, /* DIVF3 */ -2, RF, WB, 0, 0, 0, 0, /* CVTFB */ -2, RF, WW, 0, 0, 0, 0, /* CVTFW */ -2, RF, WL, 0, 0, 0, 0, /* CVTFL */ -2, RF, WL, 0, 0, 0, 0, /* CVTRFL */ -2, RB, WL, 0, 0, 0, 0, /* CVTBF */ -2, RW, WL, 0, 0, 0, 0, /* CVTWF */ -2, RL, WL, 0, 0, 0, 0, /* CVTLF */ -4, RF, RF, ML, BW, 0, 0, /* ACBF */ -2, RF, WL, 0, 0, 0, 0, /* MOVF */ -2, RF, RF, 0, 0, 0, 0, /* CMPF */ -2, RF, WL, 0, 0, 0, 0, /* MNEGF */ -1, RF, 0, 0, 0, 0, 0, /* TSTF */ -5, RF, RB, RF, WL, WL, 0, /* EMODF */ -3, RF, RW, AB, 0, 0, 0, /* POLYF */ -2, RF, WQ, 0, 0, 0, 0, /* CVTFD */ -0, 0, 0, 0, 0, 0, 0, /* reserved */ -2, RW, WW, 0, 0, 0, 0, /* ADAWI */ -0, 0, 0, 0, 0, 0, 0, /* reserved */ -0, 0, 0, 0, 0, 0, 0, /* reserved */ -0, 0, 0, 0, 0, 0, 0, /* reserved */ -2, AB, AQ, 0, 0, 0, 0, /* INSQHI */ -2, AB, AQ, 0, 0, 0, 0, /* INSQTI */ -2, AQ, WL, 0, 0, 0, 0, /* REMQHI */ -2, AQ, WL, 0, 0, 0, 0, /* REMQTI */ -2, RD, MQ, 0, 0, 0, 0, /* ADDD2 */ -3, RD, RD, WQ, 0, 0, 0, /* ADDD3 */ -2, RD, MQ, 0, 0, 0, 0, /* SUBD2 */ -3, RD, RD, WQ, 0, 0, 0, /* SUBD3 */ -2, RD, MQ, 0, 0, 0, 0, /* MULD2 */ -3, RD, RD, WQ, 0, 0, 0, /* MULD3 */ -2, RD, MQ, 0, 0, 0, 0, /* DIVD2 */ -3, RD, RD, WQ, 0, 0, 0, /* DIVD3 */ -2, RD, WB, 0, 0, 0, 0, /* CVTDB */ -2, RD, WW, 0, 0, 0, 0, /* CVTDW */ -2, RD, WL, 0, 0, 0, 0, /* CVTDL */ -2, RD, WL, 0, 0, 0, 0, /* CVTRDL */ -2, RB, WQ, 0, 0, 0, 0, /* CVTBD */ -2, RW, WQ, 0, 0, 0, 0, /* CVTWD */ -2, RL, WQ, 0, 0, 0, 0, /* CVTLD */ -4, RD, RD, MQ, BW, 0, 0, /* ACBD */ -2, RD, WQ, 0, 0, 0, 0, /* MOVD */ -2, RD, RD, 0, 0, 0, 0, /* CMPD */ -2, RD, WQ, 0, 0, 0, 0, /* MNEGD */ -1, RD, 0, 0, 0, 0, 0, /* TSTD */ -5, RD, RB, RD, WL, WQ, 0, /* EMODD */ -3, RD, RW, AB, 0, 0, 0, /* POLYD */ -2, RD, WL, 0, 0, 0, 0, /* CVTDF */ -0, 0, 0, 0, 0, 0, 0, /* reserved */ -3, RB, RL, WL, 0, 0, 0, /* ASHL */ -3, RB, RQ, WQ, 0, 0, 0, /* ASHQ */ -4, RL, RL, RL, WQ, 0, 0, /* EMUL */ -4, RL, RQ, WL, WL, 0, 0, /* EDIV */ -1, WQ, 0, 0, 0, 0, 0, /* CLRQ */ -2, RQ, WQ, 0, 0, 0, 0, /* MOVQ */ -2, AQ, WL, 0, 0, 0, 0, /* MOVAQ */ -1, AQ, 0, 0, 0, 0, 0, /* PUSHAQ */ -2, RB, MB, 0, 0, 0, 0, /* ADDB2 */ -3, RB, RB, WB, 0, 0, 0, /* ADDB3 */ -2, RB, MB, 0, 0, 0, 0, /* SUBB2 */ -3, RB, RB, WB, 0, 0, 0, /* SUBB3 */ -2, RB, MB, 0, 0, 0, 0, /* MULB2 */ -3, RB, RB, WB, 0, 0, 0, /* MULB3 */ -2, RB, MB, 0, 0, 0, 0, /* DIVB2 */ -3, RB, RB, WB, 0, 0, 0, /* DIVB3 */ -2, RB, MB, 0, 0, 0, 0, /* BISB2 */ -3, RB, RB, WB, 0, 0, 0, /* BISB3 */ -2, RB, MB, 0, 0, 0, 0, /* BICB2 */ -3, RB, RB, WB, 0, 0, 0, /* BICB3 */ -2, RB, MB, 0, 0, 0, 0, /* XORB2 */ -3, RB, RB, WB, 0, 0, 0, /* XORB3 */ -2, RB, WB, 0, 0, 0, 0, /* MNEGB */ -3, RB, RB, RB, 0, 0, 0, /* CASEB */ -2, RB, WB, 0, 0, 0, 0, /* MOVB */ -2, RB, RB, 0, 0, 0, 0, /* CMPB */ -2, RB, WB, 0, 0, 0, 0, /* MCOMB */ -2, RB, RB, 0, 0, 0, 0, /* BITB */ -1, WB, 0, 0, 0, 0, 0, /* CLRB */ -1, RB, 0, 0, 0, 0, 0, /* TSTB */ -1, MB, 0, 0, 0, 0, 0, /* INCB */ -1, MB, 0, 0, 0, 0, 0, /* DECB */ -2, RB, WL, 0, 0, 0, 0, /* CVTBL */ -2, RB, WW, 0, 0, 0, 0, /* CVTBW */ -2, RB, WL, 0, 0, 0, 0, /* MOVZBL */ -2, RB, WW, 0, 0, 0, 0, /* MOVZBW */ -3, RB, RL, WL, 0, 0, 0, /* ROTL */ -4, RB, RB, MB, BW, 0, 0, /* ACBB */ -2, AB, WL, 0, 0, 0, 0, /* MOVAB */ -1, AB, 0, 0, 0, 0, 0, /* PUSHAB */ -2, RW, MW, 0, 0, 0, 0, /* ADDW2 */ -3, RW, RW, WW, 0, 0, 0, /* ADDW3 */ -2, RW, MW, 0, 0, 0, 0, /* SUBW2 */ -3, RW, RW, WW, 0, 0, 0, /* SUBW3 */ -2, RW, MW, 0, 0, 0, 0, /* MULW2 */ -3, RW, RW, WW, 0, 0, 0, /* MULW3 */ -2, RW, MW, 0, 0, 0, 0, /* DIVW2 */ -3, RW, RW, WW, 0, 0, 0, /* DIVW3 */ -2, RW, MW, 0, 0, 0, 0, /* BISW2 */ -3, RW, RW, WW, 0, 0, 0, /* BISW3 */ -2, RW, MW, 0, 0, 0, 0, /* BICW2 */ -3, RW, RW, WW, 0, 0, 0, /* BICW3 */ -2, RW, MW, 0, 0, 0, 0, /* XORW2 */ -3, RW, RW, WW, 0, 0, 0, /* XORW3 */ -2, RW, WW, 0, 0, 0, 0, /* MNEGW */ -3, RW, RW, RW, 0, 0, 0, /* CASEW */ -2, RW, WW, 0, 0, 0, 0, /* MOVW */ -2, RW, RW, 0, 0, 0, 0, /* CMPW */ -2, RW, WW, 0, 0, 0, 0, /* MCOMW */ -2, RW, RW, 0, 0, 0, 0, /* BITW */ -1, WW, 0, 0, 0, 0, 0, /* CLRW */ -1, RW, 0, 0, 0, 0, 0, /* TSTW */ -1, MW, 0, 0, 0, 0, 0, /* INCW */ -1, MW, 0, 0, 0, 0, 0, /* DECW */ -1, RW, 0, 0, 0, 0, 0, /* BISPSW */ -1, RW, 0, 0, 0, 0, 0, /* BICPSW */ -1, RW, 0, 0, 0, 0, 0, /* POPR */ -1, RW, 0, 0, 0, 0, 0, /* PUSHR */ -1, RW, 0, 0, 0, 0, 0, /* CHMK */ -1, RW, 0, 0, 0, 0, 0, /* CHME */ -1, RW, 0, 0, 0, 0, 0, /* CHMS */ -1, RW, 0, 0, 0, 0, 0, /* CHMU */ -2, RL, ML, 0, 0, 0, 0, /* ADDL2 */ -3, RL, RL, WL, 0, 0, 0, /* ADDL3 */ -2, RL, ML, 0, 0, 0, 0, /* SUBL2 */ -3, RL, RL, WL, 0, 0, 0, /* SUBL3 */ -2, RL, ML, 0, 0, 0, 0, /* MULL2 */ -3, RL, RL, WL, 0, 0, 0, /* MULL3 */ -2, RL, ML, 0, 0, 0, 0, /* DIVL2 */ -3, RL, RL, WL, 0, 0, 0, /* DIVL3 */ -2, RL, ML, 0, 0, 0, 0, /* BISL2 */ -3, RL, RL, WL, 0, 0, 0, /* BISL3 */ -2, RL, ML, 0, 0, 0, 0, /* BICL2 */ -3, RL, RL, WL, 0, 0, 0, /* BICL3 */ -2, RL, ML, 0, 0, 0, 0, /* XORL2 */ -3, RL, RL, WL, 0, 0, 0, /* XORL3 */ -2, RL, WL, 0, 0, 0, 0, /* MNEGL */ -3, RL, RL, RL, 0, 0, 0, /* CASEL */ -2, RL, WL, 0, 0, 0, 0, /* MOVL */ -2, RL, RL, 0, 0, 0, 0, /* CMPL */ -2, RL, WL, 0, 0, 0, 0, /* MCOML */ -2, RL, RL, 0, 0, 0, 0, /* BITL */ -1, WL, 0, 0, 0, 0, 0, /* CLRL */ -1, RL, 0, 0, 0, 0, 0, /* TSTL */ -1, ML, 0, 0, 0, 0, 0, /* INCL */ -1, ML, 0, 0, 0, 0, 0, /* DECL */ -2, RL, ML, 0, 0, 0, 0, /* ADWC */ -2, RL, ML, 0, 0, 0, 0, /* SBWC */ -2, RL, RL, 0, 0, 0, 0, /* MTPR */ -2, RL, WL, 0, 0, 0, 0, /* MFPR */ -1, WL, 0, 0, 0, 0, 0, /* MOVPSL */ -1, RL, 0, 0, 0, 0, 0, /* PUSHL */ -2, AL, WL, 0, 0, 0, 0, /* MOVAL */ -1, AL, 0, 0, 0, 0, 0, /* PUSHAL */ -3, RL, VB, BB, 0, 0, 0, /* BBS */ -3, RL, VB, BB, 0, 0, 0, /* BBC */ -3, RL, VB, BB, 0, 0, 0, /* BBSS */ -3, RL, VB, BB, 0, 0, 0, /* BBCS */ -3, RL, VB, BB, 0, 0, 0, /* BBSC */ -3, RL, VB, BB, 0, 0, 0, /* BBCC */ -3, RL, VB, BB, 0, 0, 0, /* BBSSI */ -3, RL, VB, BB, 0, 0, 0, /* BBCCI */ -2, RL, BB, 0, 0, 0, 0, /* BLBS */ -2, RL, BB, 0, 0, 0, 0, /* BLBC */ -4, RL, RB, VB, WL, 0, 0, /* FFS */ -4, RL, RB, VB, WL, 0, 0, /* FFC */ -4, RL, RB, VB, RL, 0, 0, /* CMPV */ -4, RL, RB, VB, RL, 0, 0, /* CMPZV */ -4, RL, RB, VB, WL, 0, 0, /* EXTV */ -4, RL, RB, VB, WL, 0, 0, /* EXTZV */ -4, RL, RL, RB, VB, 0, 0, /* INSV */ -4, RL, RL, ML, BW, 0, 0, /* ACBL */ -3, RL, ML, BB, 0, 0, 0, /* AOBLSS */ -3, RL, ML, BB, 0, 0, 0, /* AOBLEQ */ -2, ML, BB, 0, 0, 0, 0, /* SOBGEQ */ -2, ML, BB, 0, 0, 0, 0, /* SOBGTR */ -2, RL, WB, 0, 0, 0, 0, /* CVTLB */ -2, RL, WW, 0, 0, 0, 0, /* CVTLW */ -6+DR_F, RB, RW, AB, RB, RW, AB, /* ASHP */ -3+DR_F, RL, RW, AB, 0, 0, 0, /* CVTLP */ -2, AB, AB, 0, 0, 0, 0, /* CALLG */ -2, RL, AB, 0, 0, 0, 0, /* CALLS */ -0, 0, 0, 0, 0, 0, 0, /* XFC */ -0, 0, 0, 0, 0, 0, 0, /* 0FD */ -0, 0, 0, 0, 0, 0, 0, /* 0FE */ -0, 0, 0, 0, 0, 0, 0, /* 0FF */ -0, 0, 0, 0, 0, 0, 0, /* 100-10F */ -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, /* 110-11F */ -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, /* 120-12F */ -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, /* 130-13F */ -0, 0, 0, 0, 0, 0, 0, -ODC(2), RD, WO, 0, 0, 0, 0, /* CVTDH */ -2, RG, WL, 0, 0, 0, 0, /* CVTGF */ -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -2, RG, MQ, 0, 0, 0, 0, /* ADDG2 */ -3, RG, RG, WQ, 0, 0, 0, /* ADDG3 */ -2, RG, MQ, 0, 0, 0, 0, /* SUBG2 */ -3, RG, RG, WQ, 0, 0, 0, /* SUBG3 */ -2, RG, MQ, 0, 0, 0, 0, /* MULG2 */ -3, RG, RG, WQ, 0, 0, 0, /* MULG3 */ -2, RG, MQ, 0, 0, 0, 0, /* DIVG2 */ -3, RG, RG, WQ, 0, 0, 0, /* DIVG3 */ -2, RG, WB, 0, 0, 0, 0, /* CVTGB */ -2, RG, WW, 0, 0, 0, 0, /* CVTGW */ -2, RG, WL, 0, 0, 0, 0, /* CVTGL */ -2, RG, WL, 0, 0, 0, 0, /* CVTRGL */ -2, RB, WQ, 0, 0, 0, 0, /* CVTBG */ -2, RW, WQ, 0, 0, 0, 0, /* CVTWG */ -2, RL, WQ, 0, 0, 0, 0, /* CVTLG */ -4, RG, RG, MQ, BW, 0, 0, /* ACBG */ -2, RG, WQ, 0, 0, 0, 0, /* MOVG */ -2, RG, RG, 0, 0, 0, 0, /* CMPG */ -2, RG, WQ, 0, 0, 0, 0, /* MNEGG */ -1, RG, 0, 0, 0, 0, 0, /* TSTG */ -5, RG, RW, RG, WL, WQ, 0, /* EMODG */ -3, RG, RW, AB, 0, 0, 0, /* POLYG */ -ODC(2), RG, WO, 0, 0, 0, 0, /* CVTGH */ -0, 0, 0, 0, 0, 0, 0, /* reserved */ -0, 0, 0, 0, 0, 0, 0, /* reserved */ -0, 0, 0, 0, 0, 0, 0, /* reserved */ -0, 0, 0, 0, 0, 0, 0, /* reserved */ -0, 0, 0, 0, 0, 0, 0, /* reserved */ -0, 0, 0, 0, 0, 0, 0, /* reserved */ -0, 0, 0, 0, 0, 0, 0, /* reserved */ -0, 0, 0, 0, 0, 0, 0, /* reserved */ -0, 0, 0, 0, 0, 0, 0, /* reserved */ -ODC(2), RH, MO, 0, 0, 0, 0, /* ADDH2 */ -ODC(3), RH, RH, WO, 0, 0, 0, /* ADDH3 */ -ODC(2), RH, MO, 0, 0, 0, 0, /* SUBH2 */ -ODC(3), RH, RH, WO, 0, 0, 0, /* SUBH3 */ -ODC(2), RH, MO, 0, 0, 0, 0, /* MULH2 */ -ODC(3), RH, RH, WO, 0, 0, 0, /* MULH3 */ -ODC(2), RH, MO, 0, 0, 0, 0, /* DIVH2 */ -ODC(3), RH, RH, WO, 0, 0, 0, /* DIVH3 */ -ODC(2), RH, WB, 0, 0, 0, 0, /* CVTHB */ -ODC(2), RH, WW, 0, 0, 0, 0, /* CVTHW */ -ODC(2), RH, WL, 0, 0, 0, 0, /* CVTHL */ -ODC(2), RH, WL, 0, 0, 0, 0, /* CVTRHL */ -ODC(2), RB, WO, 0, 0, 0, 0, /* CVTBH */ -ODC(2), RW, WO, 0, 0, 0, 0, /* CVTWH */ -ODC(2), RL, WO, 0, 0, 0, 0, /* CVTLH */ -ODC(4), RH, RH, MO, BW, 0, 0, /* ACBH */ -ODC(2), RH, RO, 0, 0, 0, 0, /* MOVH */ -ODC(2), RH, RH, 0, 0, 0, 0, /* CMPH */ -ODC(2), RH, WO, 0, 0, 0, 0, /* MNEGH */ -ODC(1), RH, 0, 0, 0, 0, 0, /* TSTH */ -ODC(5), RH, RW, RH, WL, WO, 0, /* EMODH */ -ODC(3), RH, RW, AB, 0, 0, 0, /* POLYH */ -ODC(2), RH, WQ, 0, 0, 0, 0, /* CVTHG */ -0, 0, 0, 0, 0, 0, 0, /* reserved */ -0, 0, 0, 0, 0, 0, 0, /* reserved */ -0, 0, 0, 0, 0, 0, 0, /* reserved */ -0, 0, 0, 0, 0, 0, 0, /* reserved */ -0, 0, 0, 0, 0, 0, 0, /* reserved */ -ODC(1), WO, 0, 0, 0, 0, 0, /* CLRO */ -ODC(2), RO, RO, 0, 0, 0, 0, /* MOVO */ -ODC(2), AO, WL, 0, 0, 0, 0, /* MOVAO*/ -ODC(1), AO, 0, 0, 0, 0, 0, /* PUSHAO*/ -0, 0, 0, 0, 0, 0, 0, /* 180-18F */ -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, /* 190-19F */ -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -ODC(2), RF, WO, 0, 0, 0, 0, /* CVTFH */ -2, RF, WQ, 0, 0, 0, 0, /* CVTFG */ -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, /* 1A0-1AF */ -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, /* 1B0-1BF */ -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, /* 1C0-1CF */ -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, /* 1D0-1DF */ -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, /* 1E0-1EF */ -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, /* 1F0-1FF */ -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -ODC(2), RH, WL, 0, 0, 0, 0, /* CVTHF */ -ODC(2), RH, WQ, 0, 0, 0, 0, /* CVTHD */ -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0 +{0, 0, 0, 0, 0, 0, 0}, /* HALT */ +{0, 0, 0, 0, 0, 0, 0}, /* NOP */ +{0, 0, 0, 0, 0, 0, 0}, /* REI */ +{0, 0, 0, 0, 0, 0, 0}, /* BPT */ +{0, 0, 0, 0, 0, 0, 0}, /* RET */ +{0, 0, 0, 0, 0, 0, 0}, /* RSB */ +{0, 0, 0, 0, 0, 0, 0}, /* LDPCTX */ +{0, 0, 0, 0, 0, 0, 0}, /* SVPCTX */ +{4+DR_F, RW, AB, RW, AB, 0, 0}, /* CVTPS */ +{4+DR_F, RW, AB, RW, AB, 0, 0}, /* CVTSP */ +{6, RL, RL, RL, RL, RL, WL}, /* INDEX */ +{4+DR_F, AB, RL, RW, AB, 0, 0}, /* CRC */ +{3, RB, RW, AB, 0, 0, 0}, /* PROBER */ +{3, RB, RW, AB, 0, 0, 0}, /* PROBEW */ +{2, AB, AB, 0, 0, 0, 0}, /* INSQUE */ +{2, AB, WL, 0, 0, 0, 0}, /* REMQUE */ +{1, BB, 0, 0, 0, 0, 0}, /* BSBB */ +{1, BB, 0, 0, 0, 0, 0}, /* BRB */ +{1, BB, 0, 0, 0, 0, 0}, /* BNEQ */ +{1, BB, 0, 0, 0, 0, 0}, /* BEQL */ +{1, BB, 0, 0, 0, 0, 0}, /* BGTR */ +{1, BB, 0, 0, 0, 0, 0}, /* BLEQ */ +{1, AB, 0, 0, 0, 0, 0}, /* JSB */ +{1, AB, 0, 0, 0, 0, 0}, /* JMP */ +{1, BB, 0, 0, 0, 0, 0}, /* BGEQ */ +{1, BB, 0, 0, 0, 0, 0}, /* BLSS */ +{1, BB, 0, 0, 0, 0, 0}, /* BGTRU */ +{1, BB, 0, 0, 0, 0, 0}, /* BLEQU */ +{1, BB, 0, 0, 0, 0, 0}, /* BVC */ +{1, BB, 0, 0, 0, 0, 0}, /* BVS */ +{1, BB, 0, 0, 0, 0, 0}, /* BCC */ +{1, BB, 0, 0, 0, 0, 0}, /* BCS */ +{4+DR_F, RW, AB, RW, AB, 0, 0}, /* ADDP4 */ +{6+DR_F, RW, AB, RW, AB, RW, AB}, /* ADDP6 */ +{4+DR_F, RW, AB, RW, AB, 0, 0}, /* SUBP4 */ +{6+DR_F, RW, AB, RW, AB, RW, AB}, /* SUBP6 */ +{5+DR_F, RW, AB, AB, RW, AB, 0}, /* CVTPT */ +{6+DR_F, RW, AB, RW, AB, RW, AB}, /* MULP6 */ +{5+DR_F, RW, AB, AB, RW, AB, 0}, /* CVTTP */ +{6+DR_F, RW, AB, RW, AB, RW, AB}, /* DIVP6 */ +{3+DR_F, RW, AB, AB, 0, 0, 0}, /* MOVC3 */ +{3+DR_F, RW, AB, AB, 0, 0, 0}, /* CMPC3 */ +{4+DR_F, RW, AB, AB, RB, 0, 0}, /* SCANC */ +{4+DR_F, RW, AB, AB, RB, 0, 0}, /* SPANC */ +{5+DR_F, RW, AB, RB, RW, AB, 0}, /* MOVC5 */ +{5+DR_F, RW, AB, RB, RW, AB, 0}, /* CMPC5 */ +{6+DR_F, RW, AB, RB, AB, RW, AB}, /* MOVTC */ +{6+DR_F, RW, AB, RB, AB, RW, AB}, /* MOVTUC */ +{1, BW, 0, 0, 0, 0, 0}, /* BSBW */ +{1, BW, 0, 0, 0, 0, 0}, /* BRW */ +{2, RW, WL, 0, 0, 0, 0}, /* CVTWL */ +{2, RW, WB, 0, 0, 0, 0}, /* CVTWB */ +{3+DR_F, RW, AB, AB, 0, 0, 0}, /* MOVP */ +{3+DR_F, RW, AB, AB, 0, 0, 0}, /* CMPP3 */ +{3+DR_F, RW, AB, WL, 0, 0, 0}, /* CVTPL */ +{4+DR_F, RW, AB, RW, AB, 0, 0}, /* CMPP4 */ +{4+DR_F, RW, AB, AB, AB, 0, 0}, /* EDITPC */ +{4+DR_F, RW, AB, RW, AB, 0, 0}, /* MATCHC */ +{3+DR_F, RB, RW, AB, 0, 0, 0}, /* LOCC */ +{3+DR_F, RB, RW, AB, 0, 0, 0}, /* SKPC */ +{2, RW, WL, 0, 0, 0, 0}, /* MOVZWL */ +{4, RW, RW, MW, BW, 0, 0}, /* ACBW */ +{2, AW, WL, 0, 0, 0, 0}, /* MOVAW */ +{1, AW, 0, 0, 0, 0, 0}, /* PUSHAW */ +{2, RF, ML, 0, 0, 0, 0}, /* ADDF2 */ +{3, RF, RF, WL, 0, 0, 0}, /* ADDF3 */ +{2, RF, ML, 0, 0, 0, 0}, /* SUBF2 */ +{3, RF, RF, WL, 0, 0, 0}, /* SUBF3 */ +{2, RF, ML, 0, 0, 0, 0}, /* MULF2 */ +{3, RF, RF, WL, 0, 0, 0}, /* MULF3 */ +{2, RF, ML, 0, 0, 0, 0}, /* DIVF2 */ +{3, RF, RF, WL, 0, 0, 0}, /* DIVF3 */ +{2, RF, WB, 0, 0, 0, 0}, /* CVTFB */ +{2, RF, WW, 0, 0, 0, 0}, /* CVTFW */ +{2, RF, WL, 0, 0, 0, 0}, /* CVTFL */ +{2, RF, WL, 0, 0, 0, 0}, /* CVTRFL */ +{2, RB, WL, 0, 0, 0, 0}, /* CVTBF */ +{2, RW, WL, 0, 0, 0, 0}, /* CVTWF */ +{2, RL, WL, 0, 0, 0, 0}, /* CVTLF */ +{4, RF, RF, ML, BW, 0, 0}, /* ACBF */ +{2, RF, WL, 0, 0, 0, 0}, /* MOVF */ +{2, RF, RF, 0, 0, 0, 0}, /* CMPF */ +{2, RF, WL, 0, 0, 0, 0}, /* MNEGF */ +{1, RF, 0, 0, 0, 0, 0}, /* TSTF */ +{5, RF, RB, RF, WL, WL, 0}, /* EMODF */ +{3, RF, RW, AB, 0, 0, 0}, /* POLYF */ +{2, RF, WQ, 0, 0, 0, 0}, /* CVTFD */ +{0, 0, 0, 0, 0, 0, 0}, /* reserved */ +{2, RW, WW, 0, 0, 0, 0}, /* ADAWI */ +{0, 0, 0, 0, 0, 0, 0}, /* reserved */ +{0, 0, 0, 0, 0, 0, 0}, /* reserved */ +{0, 0, 0, 0, 0, 0, 0}, /* reserved */ +{2, AB, AQ, 0, 0, 0, 0}, /* INSQHI */ +{2, AB, AQ, 0, 0, 0, 0}, /* INSQTI */ +{2, AQ, WL, 0, 0, 0, 0}, /* REMQHI */ +{2, AQ, WL, 0, 0, 0, 0}, /* REMQTI */ +{2, RD, MQ, 0, 0, 0, 0}, /* ADDD2 */ +{3, RD, RD, WQ, 0, 0, 0}, /* ADDD3 */ +{2, RD, MQ, 0, 0, 0, 0}, /* SUBD2 */ +{3, RD, RD, WQ, 0, 0, 0}, /* SUBD3 */ +{2, RD, MQ, 0, 0, 0, 0}, /* MULD2 */ +{3, RD, RD, WQ, 0, 0, 0}, /* MULD3 */ +{2, RD, MQ, 0, 0, 0, 0}, /* DIVD2 */ +{3, RD, RD, WQ, 0, 0, 0}, /* DIVD3 */ +{2, RD, WB, 0, 0, 0, 0}, /* CVTDB */ +{2, RD, WW, 0, 0, 0, 0}, /* CVTDW */ +{2, RD, WL, 0, 0, 0, 0}, /* CVTDL */ +{2, RD, WL, 0, 0, 0, 0}, /* CVTRDL */ +{2, RB, WQ, 0, 0, 0, 0}, /* CVTBD */ +{2, RW, WQ, 0, 0, 0, 0}, /* CVTWD */ +{2, RL, WQ, 0, 0, 0, 0}, /* CVTLD */ +{4, RD, RD, MQ, BW, 0, 0}, /* ACBD */ +{2, RD, WQ, 0, 0, 0, 0}, /* MOVD */ +{2, RD, RD, 0, 0, 0, 0}, /* CMPD */ +{2, RD, WQ, 0, 0, 0, 0}, /* MNEGD */ +{1, RD, 0, 0, 0, 0, 0}, /* TSTD */ +{5, RD, RB, RD, WL, WQ, 0}, /* EMODD */ +{3, RD, RW, AB, 0, 0, 0}, /* POLYD */ +{2, RD, WL, 0, 0, 0, 0}, /* CVTDF */ +{0, 0, 0, 0, 0, 0, 0}, /* reserved */ +{3, RB, RL, WL, 0, 0, 0}, /* ASHL */ +{3, RB, RQ, WQ, 0, 0, 0}, /* ASHQ */ +{4, RL, RL, RL, WQ, 0, 0}, /* EMUL */ +{4, RL, RQ, WL, WL, 0, 0}, /* EDIV */ +{1, WQ, 0, 0, 0, 0, 0}, /* CLRQ */ +{2, RQ, WQ, 0, 0, 0, 0}, /* MOVQ */ +{2, AQ, WL, 0, 0, 0, 0}, /* MOVAQ */ +{1, AQ, 0, 0, 0, 0, 0}, /* PUSHAQ */ +{2, RB, MB, 0, 0, 0, 0}, /* ADDB2 */ +{3, RB, RB, WB, 0, 0, 0}, /* ADDB3 */ +{2, RB, MB, 0, 0, 0, 0}, /* SUBB2 */ +{3, RB, RB, WB, 0, 0, 0}, /* SUBB3 */ +{2, RB, MB, 0, 0, 0, 0}, /* MULB2 */ +{3, RB, RB, WB, 0, 0, 0}, /* MULB3 */ +{2, RB, MB, 0, 0, 0, 0}, /* DIVB2 */ +{3, RB, RB, WB, 0, 0, 0}, /* DIVB3 */ +{2, RB, MB, 0, 0, 0, 0}, /* BISB2 */ +{3, RB, RB, WB, 0, 0, 0}, /* BISB3 */ +{2, RB, MB, 0, 0, 0, 0}, /* BICB2 */ +{3, RB, RB, WB, 0, 0, 0}, /* BICB3 */ +{2, RB, MB, 0, 0, 0, 0}, /* XORB2 */ +{3, RB, RB, WB, 0, 0, 0}, /* XORB3 */ +{2, RB, WB, 0, 0, 0, 0}, /* MNEGB */ +{3, RB, RB, RB, 0, 0, 0}, /* CASEB */ +{2, RB, WB, 0, 0, 0, 0}, /* MOVB */ +{2, RB, RB, 0, 0, 0, 0}, /* CMPB */ +{2, RB, WB, 0, 0, 0, 0}, /* MCOMB */ +{2, RB, RB, 0, 0, 0, 0}, /* BITB */ +{1, WB, 0, 0, 0, 0, 0}, /* CLRB */ +{1, RB, 0, 0, 0, 0, 0}, /* TSTB */ +{1, MB, 0, 0, 0, 0, 0}, /* INCB */ +{1, MB, 0, 0, 0, 0, 0}, /* DECB */ +{2, RB, WL, 0, 0, 0, 0}, /* CVTBL */ +{2, RB, WW, 0, 0, 0, 0}, /* CVTBW */ +{2, RB, WL, 0, 0, 0, 0}, /* MOVZBL */ +{2, RB, WW, 0, 0, 0, 0}, /* MOVZBW */ +{3, RB, RL, WL, 0, 0, 0}, /* ROTL */ +{4, RB, RB, MB, BW, 0, 0}, /* ACBB */ +{2, AB, WL, 0, 0, 0, 0}, /* MOVAB */ +{1, AB, 0, 0, 0, 0, 0}, /* PUSHAB */ +{2, RW, MW, 0, 0, 0, 0}, /* ADDW2 */ +{3, RW, RW, WW, 0, 0, 0}, /* ADDW3 */ +{2, RW, MW, 0, 0, 0, 0}, /* SUBW2 */ +{3, RW, RW, WW, 0, 0, 0}, /* SUBW3 */ +{2, RW, MW, 0, 0, 0, 0}, /* MULW2 */ +{3, RW, RW, WW, 0, 0, 0}, /* MULW3 */ +{2, RW, MW, 0, 0, 0, 0}, /* DIVW2 */ +{3, RW, RW, WW, 0, 0, 0}, /* DIVW3 */ +{2, RW, MW, 0, 0, 0, 0}, /* BISW2 */ +{3, RW, RW, WW, 0, 0, 0}, /* BISW3 */ +{2, RW, MW, 0, 0, 0, 0}, /* BICW2 */ +{3, RW, RW, WW, 0, 0, 0}, /* BICW3 */ +{2, RW, MW, 0, 0, 0, 0}, /* XORW2 */ +{3, RW, RW, WW, 0, 0, 0}, /* XORW3 */ +{2, RW, WW, 0, 0, 0, 0}, /* MNEGW */ +{3, RW, RW, RW, 0, 0, 0}, /* CASEW */ +{2, RW, WW, 0, 0, 0, 0}, /* MOVW */ +{2, RW, RW, 0, 0, 0, 0}, /* CMPW */ +{2, RW, WW, 0, 0, 0, 0}, /* MCOMW */ +{2, RW, RW, 0, 0, 0, 0}, /* BITW */ +{1, WW, 0, 0, 0, 0, 0}, /* CLRW */ +{1, RW, 0, 0, 0, 0, 0}, /* TSTW */ +{1, MW, 0, 0, 0, 0, 0}, /* INCW */ +{1, MW, 0, 0, 0, 0, 0}, /* DECW */ +{1, RW, 0, 0, 0, 0, 0}, /* BISPSW */ +{1, RW, 0, 0, 0, 0, 0}, /* BICPSW */ +{1, RW, 0, 0, 0, 0, 0}, /* POPR */ +{1, RW, 0, 0, 0, 0, 0}, /* PUSHR */ +{1, RW, 0, 0, 0, 0, 0}, /* CHMK */ +{1, RW, 0, 0, 0, 0, 0}, /* CHME */ +{1, RW, 0, 0, 0, 0, 0}, /* CHMS */ +{1, RW, 0, 0, 0, 0, 0}, /* CHMU */ +{2, RL, ML, 0, 0, 0, 0}, /* ADDL2 */ +{3, RL, RL, WL, 0, 0, 0}, /* ADDL3 */ +{2, RL, ML, 0, 0, 0, 0}, /* SUBL2 */ +{3, RL, RL, WL, 0, 0, 0}, /* SUBL3 */ +{2, RL, ML, 0, 0, 0, 0}, /* MULL2 */ +{3, RL, RL, WL, 0, 0, 0}, /* MULL3 */ +{2, RL, ML, 0, 0, 0, 0}, /* DIVL2 */ +{3, RL, RL, WL, 0, 0, 0}, /* DIVL3 */ +{2, RL, ML, 0, 0, 0, 0}, /* BISL2 */ +{3, RL, RL, WL, 0, 0, 0}, /* BISL3 */ +{2, RL, ML, 0, 0, 0, 0}, /* BICL2 */ +{3, RL, RL, WL, 0, 0, 0}, /* BICL3 */ +{2, RL, ML, 0, 0, 0, 0}, /* XORL2 */ +{3, RL, RL, WL, 0, 0, 0}, /* XORL3 */ +{2, RL, WL, 0, 0, 0, 0}, /* MNEGL */ +{3, RL, RL, RL, 0, 0, 0}, /* CASEL */ +{2, RL, WL, 0, 0, 0, 0}, /* MOVL */ +{2, RL, RL, 0, 0, 0, 0}, /* CMPL */ +{2, RL, WL, 0, 0, 0, 0}, /* MCOML */ +{2, RL, RL, 0, 0, 0, 0}, /* BITL */ +{1, WL, 0, 0, 0, 0, 0}, /* CLRL */ +{1, RL, 0, 0, 0, 0, 0}, /* TSTL */ +{1, ML, 0, 0, 0, 0, 0}, /* INCL */ +{1, ML, 0, 0, 0, 0, 0}, /* DECL */ +{2, RL, ML, 0, 0, 0, 0}, /* ADWC */ +{2, RL, ML, 0, 0, 0, 0}, /* SBWC */ +{2, RL, RL, 0, 0, 0, 0}, /* MTPR */ +{2, RL, WL, 0, 0, 0, 0}, /* MFPR */ +{1, WL, 0, 0, 0, 0, 0}, /* MOVPSL */ +{1, RL, 0, 0, 0, 0, 0}, /* PUSHL */ +{2, AL, WL, 0, 0, 0, 0}, /* MOVAL */ +{1, AL, 0, 0, 0, 0, 0}, /* PUSHAL */ +{3, RL, VB, BB, 0, 0, 0}, /* BBS */ +{3, RL, VB, BB, 0, 0, 0}, /* BBC */ +{3, RL, VB, BB, 0, 0, 0}, /* BBSS */ +{3, RL, VB, BB, 0, 0, 0}, /* BBCS */ +{3, RL, VB, BB, 0, 0, 0}, /* BBSC */ +{3, RL, VB, BB, 0, 0, 0}, /* BBCC */ +{3, RL, VB, BB, 0, 0, 0}, /* BBSSI */ +{3, RL, VB, BB, 0, 0, 0}, /* BBCCI */ +{2, RL, BB, 0, 0, 0, 0}, /* BLBS */ +{2, RL, BB, 0, 0, 0, 0}, /* BLBC */ +{4, RL, RB, VB, WL, 0, 0}, /* FFS */ +{4, RL, RB, VB, WL, 0, 0}, /* FFC */ +{4, RL, RB, VB, RL, 0, 0}, /* CMPV */ +{4, RL, RB, VB, RL, 0, 0}, /* CMPZV */ +{4, RL, RB, VB, WL, 0, 0}, /* EXTV */ +{4, RL, RB, VB, WL, 0, 0}, /* EXTZV */ +{4, RL, RL, RB, VB, 0, 0}, /* INSV */ +{4, RL, RL, ML, BW, 0, 0}, /* ACBL */ +{3, RL, ML, BB, 0, 0, 0}, /* AOBLSS */ +{3, RL, ML, BB, 0, 0, 0}, /* AOBLEQ */ +{2, ML, BB, 0, 0, 0, 0}, /* SOBGEQ */ +{2, ML, BB, 0, 0, 0, 0}, /* SOBGTR */ +{2, RL, WB, 0, 0, 0, 0}, /* CVTLB */ +{2, RL, WW, 0, 0, 0, 0}, /* CVTLW */ +{6+DR_F, RB, RW, AB, RB, RW, AB}, /* ASHP */ +{3+DR_F, RL, RW, AB, 0, 0, 0}, /* CVTLP */ +{2, AB, AB, 0, 0, 0, 0}, /* CALLG */ +{2, RL, AB, 0, 0, 0, 0}, /* CALLS */ +{0, 0, 0, 0, 0, 0, 0}, /* XFC */ +{0, 0, 0, 0, 0, 0, 0}, /* 0FD */ +{0, 0, 0, 0, 0, 0, 0}, /* 0FE */ +{0, 0, 0, 0, 0, 0, 0}, /* 0FF */ +{0, 0, 0, 0, 0, 0, 0}, /* 100-10F */ +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, /* 110-11F */ +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, /* 120-12F */ +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, /* 130-13F */ +{0, 0, 0, 0, 0, 0, 0}, +{ODC(2), RD, WO, 0, 0, 0, 0}, /* CVTDH */ +{2, RG, WL, 0, 0, 0, 0}, /* CVTGF */ +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{2, RG, MQ, 0, 0, 0, 0}, /* ADDG2 */ +{3, RG, RG, WQ, 0, 0, 0}, /* ADDG3 */ +{2, RG, MQ, 0, 0, 0, 0}, /* SUBG2 */ +{3, RG, RG, WQ, 0, 0, 0}, /* SUBG3 */ +{2, RG, MQ, 0, 0, 0, 0}, /* MULG2 */ +{3, RG, RG, WQ, 0, 0, 0}, /* MULG3 */ +{2, RG, MQ, 0, 0, 0, 0}, /* DIVG2 */ +{3, RG, RG, WQ, 0, 0, 0}, /* DIVG3 */ +{2, RG, WB, 0, 0, 0, 0}, /* CVTGB */ +{2, RG, WW, 0, 0, 0, 0}, /* CVTGW */ +{2, RG, WL, 0, 0, 0, 0}, /* CVTGL */ +{2, RG, WL, 0, 0, 0, 0}, /* CVTRGL */ +{2, RB, WQ, 0, 0, 0, 0}, /* CVTBG */ +{2, RW, WQ, 0, 0, 0, 0}, /* CVTWG */ +{2, RL, WQ, 0, 0, 0, 0}, /* CVTLG */ +{4, RG, RG, MQ, BW, 0, 0}, /* ACBG */ +{2, RG, WQ, 0, 0, 0, 0}, /* MOVG */ +{2, RG, RG, 0, 0, 0, 0}, /* CMPG */ +{2, RG, WQ, 0, 0, 0, 0}, /* MNEGG */ +{1, RG, 0, 0, 0, 0, 0}, /* TSTG */ +{5, RG, RW, RG, WL, WQ, 0}, /* EMODG */ +{3, RG, RW, AB, 0, 0, 0}, /* POLYG */ +{ODC(2), RG, WO, 0, 0, 0, 0}, /* CVTGH */ +{0, 0, 0, 0, 0, 0, 0}, /* reserved */ +{0, 0, 0, 0, 0, 0, 0}, /* reserved */ +{0, 0, 0, 0, 0, 0, 0}, /* reserved */ +{0, 0, 0, 0, 0, 0, 0}, /* reserved */ +{0, 0, 0, 0, 0, 0, 0}, /* reserved */ +{0, 0, 0, 0, 0, 0, 0}, /* reserved */ +{0, 0, 0, 0, 0, 0, 0}, /* reserved */ +{0, 0, 0, 0, 0, 0, 0}, /* reserved */ +{0, 0, 0, 0, 0, 0, 0}, /* reserved */ +{ODC(2), RH, MO, 0, 0, 0, 0}, /* ADDH2 */ +{ODC(3), RH, RH, WO, 0, 0, 0}, /* ADDH3 */ +{ODC(2), RH, MO, 0, 0, 0, 0}, /* SUBH2 */ +{ODC(3), RH, RH, WO, 0, 0, 0}, /* SUBH3 */ +{ODC(2), RH, MO, 0, 0, 0, 0}, /* MULH2 */ +{ODC(3), RH, RH, WO, 0, 0, 0}, /* MULH3 */ +{ODC(2), RH, MO, 0, 0, 0, 0}, /* DIVH2 */ +{ODC(3), RH, RH, WO, 0, 0, 0}, /* DIVH3 */ +{ODC(2), RH, WB, 0, 0, 0, 0}, /* CVTHB */ +{ODC(2), RH, WW, 0, 0, 0, 0}, /* CVTHW */ +{ODC(2), RH, WL, 0, 0, 0, 0}, /* CVTHL */ +{ODC(2), RH, WL, 0, 0, 0, 0}, /* CVTRHL */ +{ODC(2), RB, WO, 0, 0, 0, 0}, /* CVTBH */ +{ODC(2), RW, WO, 0, 0, 0, 0}, /* CVTWH */ +{ODC(2), RL, WO, 0, 0, 0, 0}, /* CVTLH */ +{ODC(4), RH, RH, MO, BW, 0, 0}, /* ACBH */ +{ODC(2), RH, RO, 0, 0, 0, 0}, /* MOVH */ +{ODC(2), RH, RH, 0, 0, 0, 0}, /* CMPH */ +{ODC(2), RH, WO, 0, 0, 0, 0}, /* MNEGH */ +{ODC(1), RH, 0, 0, 0, 0, 0}, /* TSTH */ +{ODC(5), RH, RW, RH, WL, WO, 0}, /* EMODH */ +{ODC(3), RH, RW, AB, 0, 0, 0}, /* POLYH */ +{ODC(2), RH, WQ, 0, 0, 0, 0}, /* CVTHG */ +{0, 0, 0, 0, 0, 0, 0}, /* reserved */ +{0, 0, 0, 0, 0, 0, 0}, /* reserved */ +{0, 0, 0, 0, 0, 0, 0}, /* reserved */ +{0, 0, 0, 0, 0, 0, 0}, /* reserved */ +{0, 0, 0, 0, 0, 0, 0}, /* reserved */ +{ODC(1), WO, 0, 0, 0, 0, 0}, /* CLRO */ +{ODC(2), RO, RO, 0, 0, 0, 0}, /* MOVO */ +{ODC(2), AO, WL, 0, 0, 0, 0}, /* MOVAO*/ +{ODC(1), AO, 0, 0, 0, 0, 0}, /* PUSHAO*/ +{0, 0, 0, 0, 0, 0, 0}, /* 180-18F */ +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, /* 190-19F */ +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{ODC(2), RF, WO, 0, 0, 0, 0}, /* CVTFH */ +{2, RF, WQ, 0, 0, 0, 0}, /* CVTFG */ +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, /* 1A0-1AF */ +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, /* 1B0-1BF */ +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, /* 1C0-1CF */ +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, /* 1D0-1DF */ +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, /* 1E0-1EF */ +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, /* 1F0-1FF */ +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{ODC(2), RH, WL, 0, 0, 0, 0}, /* CVTHF */ +{ODC(2), RH, WQ, 0, 0, 0, 0}, /* CVTHD */ +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0}, +{0, 0, 0, 0, 0, 0, 0} }; /* Opcode mnemonics table */ @@ -765,7 +764,7 @@ if ((sw & SWMASK ('A')) || (sw & SWMASK ('C'))) { /* char format? */ for (vp = lnt - 1; vp >= 0; vp--) { c = (int32) val[vp] & 0x7F; fprintf (of, (c < 0x20)? "<%02X>": "%c", c); - } + } return -(lnt - 1); /* return # chars */ } @@ -1173,7 +1172,7 @@ const char *force[] = { "S^", "I^", "B^", "W^", "L^", NULL }; *r = SCPE_OK; /* assume ok */ M1C ('@', SP_IND); /* look for @ */ -if (tptr = parse_rnum (cptr, &rn)) { /* look for Rn */ +if ((tptr = parse_rnum (cptr, &rn))) { /* look for Rn */ if (*cptr == '[') { /* look for [Rx] */ cptr = parse_rnum (++cptr, &index); if ((cptr == NULL) || (*cptr++ != ']')) @@ -1425,6 +1424,7 @@ int32 i, lnt; t_value regnum; char *tptr; +*rn = 0; for (i = 15; i >= 0; i--) { /* chk named reg */ lnt = strlen (regname[i]); if (strncmp (cptr, regname[i], lnt) == 0) { diff --git a/VAX/vax_syscm.c b/VAX/vax_syscm.c index 46225523..5bd8a429 100644 --- a/VAX/vax_syscm.c +++ b/VAX/vax_syscm.c @@ -27,7 +27,7 @@ 22-May-10 RMS Fixed t_addr printouts for 64b big-endian systems (Mark Pizzolato) 12-Nov-06 RMS Fixed operand order in EIS instructions (W.F.J. Mueller) - 27-Sep-05 RMS Fixed warnings compiling with 64b addresses + 27-Sep-05 RMS Fixed warnings compiling with 64b addresses 15-Sep-04 RMS Cloned from pdp11_sys.c */ @@ -464,7 +464,7 @@ return tptr; t_stat get_spec (char *cptr, int32 addr, int32 n1, int32 *sptr, int32 *dptr) { -int32 reg, indir, pflag, disp; +int32 reg, indir, pflag, disp = 0; indir = 0; /* no indirect */ pflag = 0; @@ -686,6 +686,6 @@ if (*cptr != 0) return SCPE_ARG; /* junk at end? */ for (i = j = 0; i < 3; i++, j = j + 2) { bytes[j] = val[i] & BMASK; bytes[j + 1] = (val[i] >> 8) & BMASK; - } + } return ((2 * (n1 + n2)) - 1); } diff --git a/VAX/vax_sysdev.c b/VAX/vax_sysdev.c index f12cf97b..c8e1f552 100644 --- a/VAX/vax_sysdev.c +++ b/VAX/vax_sysdev.c @@ -30,6 +30,7 @@ nvr non-volatile ROM (no registers) csi console storage input cso console storage output + cmctl memory controller sysd system devices (SSC miscellany) 20-Dec-13 RMS Added unaligned register space access routines @@ -187,7 +188,6 @@ extern UNIT cpu_unit; extern UNIT clk_unit; extern jmp_buf save_env; extern int32 p1; -extern int32 sim_switches; extern int32 MSER; extern int32 tmr_poll; @@ -925,7 +925,7 @@ return; struct reglink { /* register linkage */ uint32 low; /* low addr */ uint32 high; /* high addr */ - t_stat (*read)(int32 pa); /* read routine */ + int32 (*read)(int32 pa); /* read routine */ void (*write)(int32 pa, int32 val, int32 lnt); /* write routine */ }; @@ -1529,6 +1529,8 @@ int32 machine_check (int32 p1, int32 opc, int32 cc, int32 delta) { int32 i, st1, st2, p2, hsir, acc; +if (in_ie) /* in exc? panic */ + ABORT (STOP_INIE); if (p1 & 0x80) /* mref? set v/p */ p1 = p1 + mchk_ref; p2 = mchk_va + 4; /* save vap */ @@ -1579,8 +1581,6 @@ return 0; /* new cc = 0 */ t_stat cpu_boot (int32 unitno, DEVICE *dptr) { -extern t_stat load_cmd (int32 flag, char *cptr); -extern FILE *sim_log; t_stat r; PC = ROMBASE; @@ -1590,9 +1590,7 @@ conpsl = PSL_IS | PSL_IPL1F | CON_PWRUP; if (rom == NULL) return SCPE_IERR; if (*rom == 0) { /* no boot? */ - printf ("Loading boot code from ka655x.bin\n"); - if (sim_log) - fprintf (sim_log, "Loading boot code from ka655x.bin\n"); + sim_printf ("Loading boot code from ka655x.bin\n"); r = load_cmd (0, "-R ka655x.bin"); if (r != SCPE_OK) return r; diff --git a/VAX/vax_syslist.c b/VAX/vax_syslist.c index 054c5e43..41d1752a 100644 --- a/VAX/vax_syslist.c +++ b/VAX/vax_syslist.c @@ -44,7 +44,6 @@ extern DEVICE lpt_dev; extern DEVICE clk_dev; extern DEVICE rq_dev, rqb_dev, rqc_dev, rqd_dev; extern DEVICE rl_dev; -extern DEVICE ry_dev; extern DEVICE ts_dev; extern DEVICE tq_dev; extern DEVICE dz_dev; @@ -52,7 +51,6 @@ extern DEVICE csi_dev, cso_dev; extern DEVICE xq_dev, xqb_dev; extern DEVICE vh_dev; -extern int32 sim_switches; extern void WriteB (uint32 pa, int32 val); extern void rom_wr_B (int32 pa, int32 val); extern UNIT cpu_unit; @@ -78,7 +76,6 @@ DEVICE *sim_devices[] = { &rqb_dev, &rqc_dev, &rqd_dev, - &ry_dev, &ts_dev, &tq_dev, &xq_dev, diff --git a/VAX/vaxmod_defs.h b/VAX/vaxmod_defs.h index 34360446..499f03bf 100644 --- a/VAX/vaxmod_defs.h +++ b/VAX/vaxmod_defs.h @@ -1,6 +1,6 @@ /* vaxmod_defs.h: VAX model-specific definitions file - Copyright (c) 1998-2013, Robert M Supnik + Copyright (c) 1998-2015, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -23,6 +23,7 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 29-Mar-15 RMS Added model-specific IPR max 20-Dec-13 RMS Added prototypes for unaligned IO and register handling 12-Dec-12 RMS Fixed IO base address for RQB, RQC, RQD 11-Dec-11 RMS Moved all Qbus devices to BR4; deleted RP definitions @@ -71,8 +72,8 @@ #undef FULL_VAX #endif -#ifndef _VAXMOD_DEFS_H_ -#define _VAXMOD_DEFS_H_ 1 +#ifndef VAXMOD_DEFS_H_ +#define VAXMOD_DEFS_H_ 1 /* Microcode constructs */ @@ -98,6 +99,7 @@ #define MT_CONPC 42 #define MT_CONPSL 43 #define MT_IORESET 55 +#define MT_MAX 63 /* last valid IPR */ /* Memory system error register */ diff --git a/doc/altairz80_doc.pdf b/doc/altairz80_doc.pdf index a09c74bd..3497e9b3 100644 Binary files a/doc/altairz80_doc.pdf and b/doc/altairz80_doc.pdf differ diff --git a/scp.c b/scp.c index afe333ac..ad849d14 100644 --- a/scp.c +++ b/scp.c @@ -1,6 +1,6 @@ /* scp.c: simulator control program - Copyright (c) 1993-2012, Robert M Supnik + Copyright (c) 1993-2015, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -23,6 +23,19 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 28-Mar-15 RMS Added sim_printf from GitHub master (Mark Pizzolato) + 28-Dec-14 JDB [4.0] Moved sim_load and sim_emax declarations to scp.h + 14-Dec-14 JDB [4.0] Added sim_activate_time + [4.0] Changed sim_is_active to return t_bool + 10-Nov-14 JDB Added ATTACH -N + 02-Jul-14 JDB [4.0] Added sim_error_text + 01-Mar-13 JDB Fixed SHOW RADIX, etc. for a device that has no modifiers + Modified SET and SHOW invalid entry messages for consistency + Correct fprintf parameter errors reported by clang + 26-Feb-13 JDB Moved EX_* and SSH_* constants to scp.h + 24-Feb-13 JDB Added REG_VMAD check in fprint_stopped_gen for VM address call + Added SIM_SW_STOP to examine call in fprint_stopped_gen + 05-Feb-13 JDB Added sim_vm_fprint_stopped for VM-specific stop messages 08-May-12 RMS Fixed memory leaks in save/restore (Peter Schorn) 20-Mar-12 MP Fixes to "SHOW SHOW" commands 06-Jan-12 JDB Fixed "SHOW DEVICE" with only one enabled unit (Dave Bryan) @@ -195,9 +208,8 @@ #include #endif -#define EX_D 0 /* deposit */ -#define EX_E 1 /* examine */ -#define EX_I 2 /* interactive */ +/* Search definitions */ + #define SCH_OR 0 /* search logicals */ #define SCH_AND 1 #define SCH_XOR 2 @@ -209,9 +221,6 @@ #define SCH_NE 5 #define SCH_GE 6 #define SCH_LE 7 -#define SSH_ST 0 /* set */ -#define SSH_SH 1 /* show */ -#define SSH_CL 2 /* clear */ #define DO_NEST_LVL 10 /* DO cmd nesting level */ #define SRBSIZ 1024 /* save/restore buffer */ @@ -253,20 +262,6 @@ else if (sim_switches & SWMASK ('H')) val = 16; \ else val = dft; -/* VM interface */ - -extern char sim_name[]; -extern DEVICE *sim_devices[]; -extern REG *sim_PC; -extern const char *sim_stop_messages[]; -extern t_stat sim_instr (void); -extern t_stat sim_load (FILE *ptr, char *cptr, char *fnam, int32 flag); -extern int32 sim_emax; -extern t_stat fprint_sym (FILE *ofile, t_addr addr, t_value *val, - UNIT *uptr, int32 sw); -extern t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, - int32 sw); - /* The per-simulator init routine is a weak global that defaults to NULL The other per-simulator pointers can be overrriden by the init routine */ @@ -276,6 +271,7 @@ void (*sim_vm_post) (t_bool from_scp) = NULL; CTAB *sim_vm_cmd = NULL; void (*sim_vm_fprint_addr) (FILE *st, DEVICE *dptr, t_addr addr) = NULL; t_addr (*sim_vm_parse_addr) (DEVICE *dptr, char *cptr, char **tptr) = NULL; +t_bool (*sim_vm_fprint_stopped) (FILE *st, t_stat reason) = NULL; /* Prototypes */ @@ -392,7 +388,6 @@ static uint32 sim_rtime; static int32 noqueue_time; volatile int32 stop_cpu = 0; t_value *sim_eval = NULL; -int32 sim_deb_close = 0; /* 1 = close debug */ FILE *sim_log = NULL; /* log file */ FILE *sim_deb = NULL; /* debug file */ static SCHTAB sim_stab; @@ -593,6 +588,74 @@ static CTAB cmd_table[] = { { NULL, NULL, 0 } }; +/* SET command tables */ + +static CTAB set_glob_tab[] = { + { "CONSOLE", &sim_set_console, 0 }, + { "BREAK", &brk_cmd, SSH_ST }, + { "NOBREAK", &brk_cmd, SSH_CL }, + { "TELNET", &sim_set_telnet, 0 }, /* deprecated */ + { "NOTELNET", &sim_set_notelnet, 0 }, /* deprecated */ + { "LOG", &sim_set_logon, 0 }, /* deprecated */ + { "NOLOG", &sim_set_logoff, 0 }, /* deprecated */ + { "DEBUG", &sim_set_debon, 0 }, /* deprecated */ + { "NODEBUG", &sim_set_deboff, 0 }, /* deprecated */ + { "THROTTLE", &sim_set_throt, 1 }, + { "NOTHROTTLE", &sim_set_throt, 0 }, + { NULL, NULL, 0 } + }; + +static C1TAB set_dev_tab[] = { + { "OCTAL", &set_dev_radix, 8 }, + { "DECIMAL", &set_dev_radix, 10 }, + { "HEX", &set_dev_radix, 16 }, + { "ENABLED", &set_dev_enbdis, 1 }, + { "DISABLED", &set_dev_enbdis, 0 }, + { "DEBUG", &set_dev_debug, 1 }, + { "NODEBUG", &set_dev_debug, 0 }, + { NULL, NULL, 0 } + }; + +static C1TAB set_unit_tab[] = { + { "ENABLED", &set_unit_enbdis, 1 }, + { "DISABLED", &set_unit_enbdis, 0 }, + { NULL, NULL, 0 } + }; + +/* SHOW command tables */ + +static SHTAB show_glob_tab[] = { + { "CONFIGURATION", &show_config, 0 }, + { "DEVICES", &show_config, 1 }, + { "QUEUE", &show_queue, 0 }, + { "TIME", &show_time, 0 }, + { "MODIFIERS", &show_mod_names, 0 }, + { "NAMES", &show_log_names, 0 }, + { "SHOW", &show_show_commands, 0 }, + { "VERSION", &show_version, 1 }, + { "CONSOLE", &sim_show_console, 0 }, + { "BREAK", &show_break, 0 }, + { "LOG", &sim_show_log, 0 }, /* deprecated */ + { "TELNET", &sim_show_telnet, 0 }, /* deprecated */ + { "DEBUG", &sim_show_debug, 0 }, /* deprecated */ + { "THROTTLE", &sim_show_throt, 0 }, + { "CLOCKS", &sim_show_timers, 0 }, + { NULL, NULL, 0 } + }; + +static SHTAB show_dev_tab[] = { + { "RADIX", &show_dev_radix, 0 }, + { "DEBUG", &show_dev_debug, 0 }, + { "MODIFIERS", &show_dev_modifiers, 1 }, /* 1 = return error if no mods */ + { "NAMES", &show_dev_logicals, 0 }, + { "SHOW", &show_dev_show_commands, 0 }, + { NULL, NULL, 0 } + }; + +static SHTAB show_unit_tab[] = { + { NULL, NULL, 0 } + }; + /* Main command loop */ int main (int argc, char *argv[]) @@ -704,11 +767,8 @@ while (stat != SCPE_EXIT) { /* in case exit */ if (cmdp = find_cmd (gbuf)) /* lookup command */ stat = cmdp->action (cmdp->arg, cptr); /* if found, exec */ else stat = SCPE_UNK; - if (stat >= SCPE_BASE) { /* error? */ - printf ("%s\n", scp_error_messages[stat - SCPE_BASE]); - if (sim_log) - fprintf (sim_log, "%s\n", scp_error_messages[stat - SCPE_BASE]); - } + if (stat >= SCPE_BASE) /* error? */ + sim_printf ("%s\n", scp_error_messages[stat - SCPE_BASE]); if (sim_vm_post != NULL) (*sim_vm_post) (TRUE); } /* end while */ @@ -768,11 +828,8 @@ if (*cptr) { cptr = get_glyph (cptr, gbuf, 0); if (*cptr) return SCPE_2MARG; - if (cmdp = find_cmd (gbuf)) { - fputs (cmdp->help, stdout); - if (sim_log) - fputs (cmdp->help, sim_log); - } + if (cmdp = find_cmd (gbuf)) + sim_printf ("%s", cmdp->help); else return SCPE_ARG; } else { @@ -810,9 +867,7 @@ return SCPE_OK; t_stat echo_cmd (int32 flag, char *cptr) { -puts (cptr); -if (sim_log) - fprintf (sim_log, "%s\n", cptr); +sim_printf ("%s\n", cptr); return SCPE_OK; } @@ -906,9 +961,7 @@ do { if (*cptr == 0) /* ignore blank */ continue; if (echo) /* echo if -v */ - printf("do> %s\n", cptr); - if (echo && sim_log) - fprintf (sim_log, "do> %s\n", cptr); + sim_printf("do> %s\n", cptr); cptr = get_glyph (cptr, gbuf, 0); /* get command glyph */ sim_switches = 0; /* init switches */ isdo = FALSE; @@ -929,18 +982,13 @@ do { (stat != SCPE_STEP)) { if (!echo && !sim_quiet && /* report if not echoing */ (!isdo || (stat & SCPE_DOFAILED))) { /* and not from DO return */ - printf("%s> %s\n", do_arg[0], ocptr); - if (sim_log) - fprintf (sim_log, "%s> %s\n", do_arg[0], ocptr); + sim_printf("%s> %s\n", do_arg[0], ocptr); } stat = stat & ~SCPE_DOFAILED; /* remove possible flag */ } if ((staying || !interactive) && /* report error if staying */ - (stat >= SCPE_BASE)) { /* or in cmdline file */ - printf ("%s\n", scp_error_messages[stat - SCPE_BASE]); - if (sim_log) - fprintf (sim_log, "%s\n", scp_error_messages[stat - SCPE_BASE]); - } + (stat >= SCPE_BASE)) /* or in cmdline file */ + sim_printf ("%s\n", scp_error_messages[stat - SCPE_BASE]); if (sim_vm_post != NULL) (*sim_vm_post) (TRUE); } while (staying); @@ -1055,38 +1103,6 @@ MTAB *mptr; CTAB *gcmdp; C1TAB *ctbr, *glbr; -static CTAB set_glob_tab[] = { - { "CONSOLE", &sim_set_console, 0 }, - { "BREAK", &brk_cmd, SSH_ST }, - { "NOBREAK", &brk_cmd, SSH_CL }, - { "TELNET", &sim_set_telnet, 0 }, /* deprecated */ - { "NOTELNET", &sim_set_notelnet, 0 }, /* deprecated */ - { "LOG", &sim_set_logon, 0 }, /* deprecated */ - { "NOLOG", &sim_set_logoff, 0 }, /* deprecated */ - { "DEBUG", &sim_set_debon, 0 }, /* deprecated */ - { "NODEBUG", &sim_set_deboff, 0 }, /* deprecated */ - { "THROTTLE", &sim_set_throt, 1 }, - { "NOTHROTTLE", &sim_set_throt, 0 }, - { NULL, NULL, 0 } - }; - -static C1TAB set_dev_tab[] = { - { "OCTAL", &set_dev_radix, 8 }, - { "DECIMAL", &set_dev_radix, 10 }, - { "HEX", &set_dev_radix, 16 }, - { "ENABLED", &set_dev_enbdis, 1 }, - { "DISABLED", &set_dev_enbdis, 0 }, - { "DEBUG", &set_dev_debug, 1 }, - { "NODEBUG", &set_dev_debug, 0 }, - { NULL, NULL, 0 } - }; - -static C1TAB set_unit_tab[] = { - { "ENABLED", &set_unit_enbdis, 1 }, - { "DISABLED", &set_unit_enbdis, 0 }, - { NULL, NULL, 0 } - }; - GET_SWITCHES (cptr); /* get switches */ if (*cptr == 0) /* must be more */ return SCPE_2FARG; @@ -1309,43 +1325,13 @@ return r; t_stat show_cmd_fi (FILE *ofile, int32 flag, char *cptr) { int32 lvl; +t_stat r; char gbuf[CBUFSIZE], *cvptr; DEVICE *dptr; UNIT *uptr; MTAB *mptr; SHTAB *shtb, *shptr; -static SHTAB show_glob_tab[] = { - { "CONFIGURATION", &show_config, 0 }, - { "DEVICES", &show_config, 1 }, - { "QUEUE", &show_queue, 0 }, - { "TIME", &show_time, 0 }, - { "MODIFIERS", &show_mod_names, 0 }, - { "NAMES", &show_log_names, 0 }, - { "SHOW", &show_show_commands, 0 }, - { "VERSION", &show_version, 1 }, - { "CONSOLE", &sim_show_console, 0 }, - { "BREAK", &show_break, 0 }, - { "LOG", &sim_show_log, 0 }, /* deprecated */ - { "TELNET", &sim_show_telnet, 0 }, /* deprecated */ - { "DEBUG", &sim_show_debug, 0 }, /* deprecated */ - { "THROTTLE", &sim_show_throt, 0 }, - { NULL, NULL, 0 } - }; - -static SHTAB show_dev_tab[] = { - { "RADIX", &show_dev_radix, 0 }, - { "DEBUG", &show_dev_debug, 0 }, - { "MODIFIERS", &show_dev_modifiers, 0 }, - { "NAMES", &show_dev_logicals, 0 }, - { "SHOW", &show_dev_show_commands, 0 }, - { NULL, NULL, 0 } - }; - -static SHTAB show_unit_tab[] = { - { NULL, NULL, 0 } - }; - GET_SWITCHES (cptr); /* get switches */ if (*cptr == 0) /* must be more */ return SCPE_2FARG; @@ -1373,14 +1359,12 @@ if (*cptr == 0) { /* now eol? */ show_device (ofile, dptr, 0): show_unit (ofile, dptr, uptr, -1); } -if (dptr->modifiers == NULL) /* any modifiers? */ - return SCPE_NOPARAM; while (*cptr != 0) { /* do all mods */ cptr = get_glyph (cptr, gbuf, ','); /* get modifier */ if (cvptr = strchr (gbuf, '=')) /* = value? */ *cvptr++ = 0; - for (mptr = dptr->modifiers; mptr->mask != 0; mptr++) { + for (mptr = dptr->modifiers; mptr && (mptr->mask != 0); mptr++) { if (((mptr->mask & MTAB_XTD)? /* right level? */ (mptr->mask & lvl): (MTAB_VUN & lvl)) && ((mptr->disp && mptr->pstring && /* named disp? */ @@ -1396,10 +1380,16 @@ while (*cptr != 0) { /* do all mods */ break; } /* end if */ } /* end for */ - if (mptr->mask == 0) { /* no match? */ - if (shptr = find_shtab (shtb, gbuf)) /* global match? */ - shptr->action (ofile, dptr, uptr, shptr->arg, cptr); - else return SCPE_ARG; + if (!mptr || (mptr->mask == 0)) { /* no match? */ + if (shptr = find_shtab (shtb, gbuf)) { /* global match? */ + r = shptr->action (ofile, dptr, uptr, shptr->arg, cptr); + if (r != SCPE_OK) + return r; + } + else if (!dptr->modifiers) /* no modifiers? */ + return SCPE_NOPARAM; + else + return SCPE_NXPAR; } /* end if */ } /* end while */ return SCPE_OK; @@ -1682,6 +1672,8 @@ if (!enb && (dptr->flags & DEV_DISABLE)) { } if (any) fprintf (st, "\n"); +else if (flag == 1) + return SCPE_NOPARAM; if ((dptr->flags & DEV_DEBUG) && dptr->debflags) { fprintf (st, "%s\tDEBUG=", sim_dname (dptr)); for (dep = dptr->debflags; dep->name != NULL; dep++) @@ -2031,7 +2023,14 @@ if (sim_switches & SWMASK ('R')) { /* read only? */ return attach_err (uptr, SCPE_OPENERR); /* yes, error */ uptr->flags = uptr->flags | UNIT_RO; /* set rd only */ if (!sim_quiet) - printf ("%s: unit is read only\n", sim_dname (dptr)); + sim_printf ("%s: unit is read only\n", sim_dname (dptr)); + } +else if (sim_switches & SWMASK ('N')) { /* new file only? */ + uptr->fileref = sim_fopen (cptr, "wb+"); /* open new file */ + if (uptr->fileref == NULL) /* open fail? */ + return attach_err (uptr, SCPE_OPENERR); /* yes, error */ + if (!sim_quiet) + sim_printf ("%s: creating new file\n", sim_dname (dptr)); } else { /* normal */ uptr->fileref = sim_fopen (cptr, "rb+"); /* open r/w */ @@ -2044,7 +2043,7 @@ else { /* normal */ return attach_err (uptr, SCPE_OPENERR); /* yes, error */ uptr->flags = uptr->flags | UNIT_RO; /* set rd only */ if (!sim_quiet) - printf ("%s: unit is read only\n", sim_dname (dptr)); + sim_printf ("%s: unit is read only\n", sim_dname (dptr)); } else { /* doesn't exist */ if (sim_switches & SWMASK ('E')) /* must exist? */ @@ -2052,7 +2051,8 @@ else { /* normal */ uptr->fileref = sim_fopen (cptr, "wb+"); /* open new file */ if (uptr->fileref == NULL) /* open fail? */ return attach_err (uptr, SCPE_OPENERR); /* yes, error */ - if (!sim_quiet) printf ("%s: creating new file\n", sim_dname (dptr)); + if (!sim_quiet) + sim_printf ("%s: creating new file\n", sim_dname (dptr)); } } /* end if null */ } /* end else */ @@ -2062,7 +2062,8 @@ if (uptr->flags & UNIT_BUFABLE) { /* buffer? */ uptr->filebuf = calloc (cap, SZ_D (dptr)); /* allocate */ if (uptr->filebuf == NULL) /* no buffer? */ return attach_err (uptr, SCPE_MEM); /* error */ - if (!sim_quiet) printf ("%s: buffering file in memory\n", sim_dname (dptr)); + if (!sim_quiet) + sim_printf ("%s: buffering file in memory\n", sim_dname (dptr)); uptr->hwmark = (uint32)sim_fread (uptr->filebuf, /* read file */ SZ_D (dptr), cap, uptr->fileref); uptr->flags = uptr->flags | UNIT_BUF; /* set buffered */ @@ -2172,7 +2173,7 @@ if (uptr->flags & UNIT_BUF) { uint32 cap = (uptr->hwmark + dptr->aincr - 1) / dptr->aincr; if (uptr->hwmark && ((uptr->flags & UNIT_RO) == 0)) { if (!sim_quiet) - printf ("%s: writing buffer to file\n", sim_dname (dptr)); + sim_printf ("%s: writing buffer to file\n", sim_dname (dptr)); rewind (uptr->fileref); sim_fwrite (uptr->filebuf, SZ_D (dptr), cap, uptr->fileref); if (ferror (uptr->fileref)) @@ -2319,7 +2320,7 @@ for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { /* loop thru devices */ WRITE_I (dptr->flags); /* [V2.10] flags */ for (j = 0; j < dptr->numunits; j++) { uptr = dptr->units + j; - t = sim_is_active (uptr); + t = sim_activate_time (uptr); WRITE_I (j); /* unit number */ WRITE_I (t); /* activation time */ WRITE_I (uptr->u3); /* unit specific */ @@ -2345,10 +2346,8 @@ for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { /* loop thru devices */ for (l = 0; (l < SRBSIZ) && (k < high); l++, k = k + (dptr->aincr)) { /* check for 0 block */ r = dptr->examine (&val, k, uptr, SIM_SW_REST); - if (r != SCPE_OK) { - free (mbuf); + if (r != SCPE_OK) return r; - } if (val) zeroflg = FALSE; SZ_STORE (sz, val, mbuf, l); } /* end for l */ @@ -2434,23 +2433,23 @@ if (strcmp (buf, save_vercur) == 0) /* version 3.5? */ else if (strcmp (buf, save_ver32) == 0) /* version 3.2? */ v32 = TRUE; else if (strcmp (buf, save_ver30) != 0) { /* version 3.0? */ - printf ("Invalid file version: %s\n", buf); + sim_printf ("Invalid file version: %s\n", buf); return SCPE_INCOMP; } READ_S (buf); /* read sim name */ if (strcmp (buf, sim_name)) { /* name match? */ - printf ("Wrong system type: %s\n", buf); + sim_printf ("Wrong system type: %s\n", buf); return SCPE_INCOMP; } if (v35) { /* [V3.5+] options */ READ_S (buf); /* integer size */ if (strcmp (buf, sim_si64) != 0) { - printf ("Incompatible integer size, save file = %s\n", buf); + sim_printf ("Incompatible integer size, save file = %s\n", buf); return SCPE_INCOMP; } READ_S (buf); /* address size */ if (strcmp (buf, sim_sa64) != 0) { - printf ("Incompatible address size, save file = %s\n", buf); + sim_printf ("Incompatible address size, save file = %s\n", buf); return SCPE_INCOMP; } READ_S (buf); /* Ethernet */ @@ -2467,7 +2466,7 @@ for ( ;; ) { /* device loop */ if (buf[0] == 0) /* last? */ break; if ((dptr = find_dev (buf)) == NULL) { /* locate device */ - printf ("Invalid device name: %s\n", buf); + sim_printf ("Invalid device name: %s\n", buf); return SCPE_INCOMP; } READ_S (buf); /* [V3.0+] logical name */ @@ -2487,7 +2486,7 @@ for ( ;; ) { /* device loop */ if (unitno < 0) /* end units? */ break; if ((uint32) unitno >= dptr->numunits) { /* too big? */ - printf ("Invalid unit number: %s%d\n", sim_dname (dptr), unitno); + sim_printf ("Invalid unit number: %s%d\n", sim_dname (dptr), unitno); return SCPE_INCOMP; } READ_I (time); /* event time */ @@ -2531,7 +2530,7 @@ for ( ;; ) { /* device loop */ if (high > 0) { /* [V2.5+] any memory? */ if (((uptr->flags & (UNIT_FIX + UNIT_ATTABLE)) != UNIT_FIX) || (dptr->deposit == NULL)) { - printf ("Can't restore memory: %s%d\n", sim_dname (dptr), unitno); + sim_printf ("Can't restore memory: %s%d\n", sim_dname (dptr), unitno); return SCPE_INCOMP; } if (high != old_capac) { /* size change? */ @@ -2539,39 +2538,32 @@ for ( ;; ) { /* device loop */ if ((dptr->flags & DEV_DYNM) && ((dptr->msize == NULL) || (dptr->msize (uptr, (int32) high, NULL, NULL) != SCPE_OK))) { - printf ("Can't change memory size: %s%d\n", + sim_printf ("Can't change memory size: %s%d\n", sim_dname (dptr), unitno); return SCPE_INCOMP; } uptr->capac = high; /* new memory size */ - printf ("Memory size changed: %s%d = ", sim_dname (dptr), unitno); + sim_printf ("Memory size changed: %s%d = ", sim_dname (dptr), unitno); fprint_capac (stdout, dptr, uptr); - printf ("\n"); + sim_printf ("\n"); } sz = SZ_D (dptr); /* allocate buffer */ if ((mbuf = calloc (SRBSIZ, sz)) == NULL) return SCPE_MEM; for (k = 0; k < high; ) { /* loop thru mem */ - if (sim_fread (&blkcnt, sizeof (blkcnt), 1, rfile) == 0) { - free (mbuf); /* read blk cnt */ - return SCPE_IOERR; - } + READ_I (blkcnt); /* block count */ if (blkcnt < 0) /* compressed? */ limit = -blkcnt; else limit = sim_fread (mbuf, sz, blkcnt, rfile); - if (limit <= 0) { /* invalid or err? */ - free (mbuf); + if (limit <= 0) /* invalid or err? */ return SCPE_IOERR; - } for (j = 0; j < limit; j++, k = k + (dptr->aincr)) { if (blkcnt < 0) /* compressed? */ val = 0; else SZ_LOAD (sz, val, mbuf, j); /* saved value */ r = dptr->deposit (val, k, uptr, SIM_SW_REST); - if (r != SCPE_OK) { - free (mbuf); + if (r != SCPE_OK) return r; - } } /* end for j */ } /* end for k */ free (mbuf); /* dealloc buffer */ @@ -2583,20 +2575,20 @@ for ( ;; ) { /* device loop */ break; READ_I (depth); /* [V2.10+] depth */ if ((rptr = find_reg (buf, NULL, dptr)) == NULL) { - printf ("Invalid register name: %s %s\n", sim_dname (dptr), buf); + sim_printf ("Invalid register name: %s %s\n", sim_dname (dptr), buf); for (us = 0; us < depth; us++) { /* skip values */ READ_I (val); } continue; } if (depth != rptr->depth) /* [V2.10+] mismatch? */ - printf ("Register depth mismatch: %s %s, file = %d, sim = %d\n", + sim_printf ("Register depth mismatch: %s %s, file = %d, sim = %d\n", sim_dname (dptr), buf, depth, rptr->depth); mask = width_mask[rptr->width]; /* get mask */ for (us = 0; us < depth; us++) { /* loop thru values */ READ_I (val); /* read value */ if (val > mask) /* value ok? */ - printf ("Invalid register value: %s %s\n", sim_dname (dptr), buf); + sim_printf ("Invalid register value: %s %s\n", sim_dname (dptr), buf); else if (us < rptr->depth) /* in range? */ put_rval (rptr, us, val); } @@ -2739,7 +2731,7 @@ for (i = 1; (dptr = sim_devices[i]) != NULL; i++) { /* flush attached files } } #if defined (VMS) -printf ("\n"); +sim_printf ("\n"); #endif fprint_stopped (stdout, r); /* print msg */ if (sim_log) /* log if enabled */ @@ -2758,7 +2750,13 @@ sim_clock_queue = NULL; return reset_all (0); } -/* Print stopped message */ +/* Print stopped message. + + For VM stops, if a VM-specific "sim_vm_fprint_stopped" pointer is defined, + call the indicated routine to print additional information after the message + and before the PC value is printed. If the routine returns FALSE, skip + printing the PC. +*/ void fprint_stopped_gen (FILE *st, t_stat v, REG *pc, DEVICE *dptr) { @@ -2767,19 +2765,31 @@ t_stat r = 0; t_addr k; t_value pcval; -if (v >= SCPE_BASE) - fprintf (st, "\n%s, %s: ", scp_error_messages[v - SCPE_BASE], pc->name); -else fprintf (st, "\n%s, %s: ", sim_stop_messages[v], pc->name); +fputc ('\n', st); /* skip a line */ + +if (v >= SCPE_BASE) /* SCP error? */ + fputs (sim_error_text (v), st); /* print it from the SCP list */ + +else { /* VM error */ + fputs (sim_stop_messages [v], st); /* print the VM-specific message */ + + if (sim_vm_fprint_stopped != NULL /* if a VM-specific stop handler is defined */ + && !sim_vm_fprint_stopped (st, v)) /* call it; if it returned FALSE, */ + return; /* we're done */ + } + +fprintf (st, ", %s: ", pc->name); /* print the name of the PC register */ + pcval = get_rval (pc, 0); -if (sim_vm_fprint_addr) - sim_vm_fprint_addr (st, dptr, (t_addr) pcval); -else fprint_val (st, pcval, pc->radix, pc->width, - pc->flags & REG_FMT); +if ((pc->flags & REG_VMAD) && sim_vm_fprint_addr) /* if reg wants VM-specific printer */ + sim_vm_fprint_addr (st, dptr, (t_addr) pcval); /* call it to print the PC address */ +else fprint_val (st, pcval, pc->radix, pc->width, /* otherwise, print as a numeric value */ + pc->flags & REG_FMT); /* with the radix and formatting specified */ if ((dptr != NULL) && (dptr->examine != NULL)) { for (i = 0; i < sim_emax; i++) sim_eval[i] = 0; for (i = 0, k = (t_addr) pcval; i < sim_emax; i++, k = k + dptr->aincr) { - if ((r = dptr->examine (&sim_eval[i], k, dptr->units, SWMASK ('V'))) != SCPE_OK) + if ((r = dptr->examine (&sim_eval[i], k, dptr->units, SWMASK ('V')|SIM_SW_STOP)) != SCPE_OK) break; } if ((r == SCPE_OK) || (i > 0)) { @@ -3114,7 +3124,7 @@ if (rptr->flags & REG_RO) if (flag & EX_I) { cptr = read_line (gbuf, CBUFSIZE, stdin); if (sim_log) - fprintf (sim_log, (cptr? "%s\n": "\n"), cptr); + fprintf (sim_log, "%s\n", cptr? cptr: ""); /* fix clang error */ if (cptr == NULL) /* force exit */ return 1; if (*cptr == 0) /* success */ @@ -3332,7 +3342,7 @@ if (dptr == NULL) if (flag & EX_I) { cptr = read_line (gbuf, CBUFSIZE, stdin); if (sim_log) - fprintf (sim_log, (cptr? "%s\n": "\n"), cptr); + fprintf (sim_log, "%s\n", cptr? cptr: ""); /* fix clang error */ if (cptr == NULL) /* force exit */ return 1; if (*cptr == 0) /* success */ @@ -3406,10 +3416,10 @@ if ((r = parse_sym (cptr, 0, dptr->units, sim_eval, sim_switches)) > 0) { } lim = 1 - r; for (i = a = 0; a < lim; ) { - printf ("%d:\t", a); + sim_printf ("%d:\t", a); if ((r = fprint_sym (stdout, a, &sim_eval[i], dptr->units, sim_switches)) > 0) r = fprint_val (stdout, sim_eval[i], rdx, dptr->dwidth, PV_RZRO); - printf ("\n"); + sim_printf ("\n"); if (sim_log) { fprintf (sim_log, "%d\t", i); if ((r = fprint_sym (sim_log, a, &sim_eval[i], dptr->units, sim_switches)) > 0) @@ -3596,7 +3606,7 @@ t_stat get_yn (char *ques, t_stat deflt) { char cbuf[CBUFSIZE], *cptr; -printf ("%s ", ques); +sim_printf ("%s ", ques); cptr = read_line (cbuf, CBUFSIZE, stdin); if ((cptr == NULL) || (*cptr == 0)) return deflt; @@ -4267,6 +4277,59 @@ if (fputs (&dbuf[d], stream) == EOF) return SCPE_OK; } +/* Print message to stdout and sim_log (if enabled) + + Inputs: + fmt = printf style format string + ... = variable argument list + Output: + none + + If this is called from a running simulator, it will + interpolate \r in front of bare \n. +*/ + +void sim_printf (const char* fmt, ...) +{ +char buf[STACKBUFSIZE]; +int32 bufsize = STACKBUFSIZE; +int32 len; +va_list arglist; + +va_start (arglist, fmt); +len = VSNPRINTF (buf, bufsize - 1, fmt, arglist); +va_end (arglist); +buf[bufsize - 1] = '\0'; +if ((len < 0) || (len >= bufsize - 1)) { + printf ("%%TRUNCATED!\a "); + if (sim_log) + fprintf (sim_log, "%%TRUNCATED!\a "); + } + +if (sim_is_running) { + char *c, *remnant = buf; + while ((c = strchr(remnant, '\n'))) { + if ((c != buf) && (*(c - 1) != '\r')) + printf("%.*s\r\n", (int)(c - remnant), remnant); + else printf ("%.*s\n", (int)(c - remnant), remnant); + remnant = c + 1; + } + printf("%s", remnant); + } +else printf ("%s", buf); +if (sim_log) + fprintf (sim_log, "%s", buf); +return; +} + +void sim_perror (char *msg) +{ +int saved_errno = errno; + +//perror (msg); +sim_printf ("%s: %s\n", msg, strerror (saved_errno)); +} + /* Event queue package sim_activate add entry to event queue @@ -4615,7 +4678,8 @@ t_stat sim_brk_set (t_addr loc, int32 sw, int32 ncnt, char *act) { BRKTAB *bp; -if (sw == 0) sw = sim_brk_dflt; +if (sw == 0) + sw = sim_brk_dflt; if ((sim_brk_types & sw) == 0) return SCPE_NOFNC; bp = sim_brk_fnd (loc); /* present? */ @@ -4670,7 +4734,8 @@ t_stat sim_brk_clrall (int32 sw) { BRKTAB *bp; -if (sw == 0) sw = SIM_BRK_ALLTYP; +if (sw == 0) + sw = SIM_BRK_ALLTYP; for (bp = sim_brk_tab; bp < (sim_brk_tab + sim_brk_ent); ) { if (bp->typ & sw) sim_brk_clr (bp->addr, sw); @@ -4809,6 +4874,16 @@ if (spc < SIM_BKPT_N_SPC) { return; } +/* Message Text */ + +const char *sim_error_text (t_stat stat) +{ +if (stat >= SCPE_BASE) /* SCP error? */ + return scp_error_messages [stat - SCPE_BASE]; /* return it from the SCP list */ +else /* VM error */ + return sim_stop_messages [stat]; /* return the VM-specific message */ +} + /* Debug printout routines, from Dave Hittner */ const char* debug_bstates = "01_^"; diff --git a/scp.h b/scp.h index cdb2c33a..0127ea9b 100644 --- a/scp.h +++ b/scp.h @@ -1,6 +1,6 @@ /* scp.h: simulator control program headers - Copyright (c) 1993-2008, Robert M Supnik + Copyright (c) 1993-2014, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -23,6 +23,13 @@ be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 28-Dec-14 JDB [4.0] Moved sim_load and sim_emax declarations from scp.c + 14-Dec-14 JDB [4.0] Added sim_activate_time + [4.0] Changed sim_is_active to return t_bool + [4.0] Added data externals + 02-Jul-14 JDB [4.0] Added sim_error_text + 26-Feb-13 JDB [4.0] Moved EX_* and SSH_* constants from scp.c + 05-Dec-10 MP Added macro invocation of sim_debug 09-Aug-06 JDB Added assign_device and deassign_device 14-Jul-06 RMS Added sim_activate_abs 06-Jan-06 RMS Added fprint_stopped_gen @@ -33,8 +40,8 @@ 02-Jan-04 RMS Split out from SCP */ -#ifndef _SIM_SCP_H_ -#define _SIM_SCP_H_ 0 +#ifndef SIM_SCP_H_ +#define SIM_SCP_H_ 0 /* run_cmd parameters */ @@ -44,6 +51,18 @@ #define RU_CONT 3 /* continue */ #define RU_BOOT 4 /* boot */ +/* exdep_cmd parameters */ + +#define EX_D 0 /* deposit */ +#define EX_E 1 /* examine */ +#define EX_I 2 /* interactive */ + +/* brk_cmd parameters */ + +#define SSH_ST 0 /* set */ +#define SSH_SH 1 /* show */ +#define SSH_CL 2 /* clear */ + /* get_sim_opt parameters */ #define CMD_OPT_SW 001 /* switches */ @@ -79,8 +98,10 @@ t_stat echo_cmd (int32 flag, char *ptr); t_stat sim_process_event (void); t_stat sim_activate (UNIT *uptr, int32 interval); t_stat sim_activate_abs (UNIT *uptr, int32 interval); +const char *sim_error_text (t_stat stat); t_stat sim_cancel (UNIT *uptr); -int32 sim_is_active (UNIT *uptr); +t_bool sim_is_active (UNIT *uptr); +int32 sim_activate_time (UNIT *uptr); double sim_gtime (void); uint32 sim_grtime (void); int32 sim_qcount (void); @@ -118,5 +139,67 @@ void sim_debug_u16 (uint32 dbits, DEVICE* dptr, const char* const* bitdefs, uint16 before, uint16 after, int terminate); void sim_debug (uint32 dbits, DEVICE* dptr, const char* fmt, ...); void fprint_stopped_gen (FILE *st, t_stat v, REG *pc, DEVICE *dptr); +void sim_printf (const char *fmt, ...); + +/* Global data */ + +extern DEVICE *sim_dflt_dev; +extern int32 sim_interval; +extern int32 sim_switches; +extern int32 sim_quiet; +extern int32 sim_step; +extern FILE *sim_log; /* log file */ +extern FILE *sim_deb; /* debug file */ +extern UNIT *sim_clock_queue; +extern int32 sim_is_running; +extern t_value *sim_eval; +extern volatile int32 stop_cpu; +extern uint32 sim_brk_types; /* breakpoint info */ +extern uint32 sim_brk_dflt; +extern uint32 sim_brk_summ; + +/* VM interface */ + +extern char sim_name[]; +extern DEVICE *sim_devices[]; +extern REG *sim_PC; +extern const char *sim_stop_messages[]; +extern t_stat sim_instr (void); +extern t_stat sim_load (FILE *ptr, char *cptr, char *fnam, int flag); +extern int32 sim_emax; +extern t_stat fprint_sym (FILE *ofile, t_addr addr, t_value *val, + UNIT *uptr, int32 sw); +extern t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, + int32 sw); + +/* The per-simulator init routine is a weak global that defaults to NULL + The other per-simulator pointers can be overrriden by the init routine */ + +extern void (*sim_vm_init) (void); +extern char* (*sim_vm_read) (char *ptr, int32 size, FILE *stream); +extern void (*sim_vm_post) (t_bool from_scp); +extern CTAB *sim_vm_cmd; +extern void (*sim_vm_fprint_addr) (FILE *st, DEVICE *dptr, t_addr addr); +extern t_addr (*sim_vm_parse_addr) (DEVICE *dptr, char *cptr, char **tptr); +extern t_bool (*sim_vm_fprint_stopped) (FILE *st, t_stat reason); + +/* vsnprintf hassles for various compilers - missing in old DEC C */ + +#if defined (__DECC) && defined (__VMS) && (defined (__VAX) || (__CRTL_VER <= 70311000)) + +#define VSNPRINTF(a,b,c,d) vsprintf (a, c, d) +#define STACKBUFSIZE 16384 + +#else + +#define VSNPRINTF(a,b,c,d) vsnprintf (a, b, c, d) +#define STACKBUFSIZE 2048 + +#endif + +/* V4 compatibility */ + +#define sim_activate_time(u) sim_is_active (u) +void sim_perror (char *msg); #endif diff --git a/sigma/Design Notes on the Sigma 7.doc b/sigma/Design Notes on the Sigma 7.doc new file mode 100644 index 00000000..21a67694 Binary files /dev/null and b/sigma/Design Notes on the Sigma 7.doc differ diff --git a/sigma/sigma_bugs.txt b/sigma/sigma_bugs.txt new file mode 100644 index 00000000..faa14e70 --- /dev/null +++ b/sigma/sigma_bugs.txt @@ -0,0 +1,149 @@ +1. CPU: register pointer was being loaded from PSW1 instead of PSW2. +2. CPU: register pointer was not preserved on an XPSD 0. +3. CPU: some decode points were taking unimplemented rather than non-existent + instruction traps. +4. CPU: BDR branches on result >=0, instead of > 0. +5. CPU: PSD change instructions were not saving old PC in PC queue. +6. CPU: illegal register pointer does not stop the system on the Sigma 5-7; + instead, registers read as 0's, and writes are ignored. +7. CPU: traps were setting the Sigma 9 vector field unconditionally. +8. CPU: CH does not SEXT Rn<16:31>. +9. CPU: MTW and MTH overflow traps not implemented. +10. CPU: MTH condition code calculations not implemented correctly. +11. CPU: illegal shift opcodes on the Sigma 5-7 are treated as arithmetic + single (according to the AUTO diagnostic). +12. FP: SF did not calculate condition codes correctly. +13. FP: SF left did not detect normalized if the count reached zero. +14. FP: SF right was retaining a guard digit incorrectly. +15. FP: SF right test was not taking into account single/double precision. +16. FP: fp_unpack killed the operand sign before testing it. +17. FP: fp_pack did not recomplement a negative operand. +18. CPU: DW overflow test was incorrect. +19. IO: device status bit field was incorrectly defined. +20. IO: AIO was testing for == 0 instead of != 0. +21. TT: input keyboard character mappings were incorrect. +22. SYS: shifts were not displaying or accepting an index register. +23. CPU: mapping from pulse interrupt number to counter interrupt number + was incorrect. +24. CPU, CIS: handling of instructions aborts was incorrect. +25. CPU: CC2,4 set incorrectly on aborted stack instruction. +26. CPU: CC2,4 set incorrectly on MSP,0 instruction. +27. CPU: PLW not converting operand address to byte address. +28. CPU: PSM, PLM not converting limit operand address to byte address correctly. +29. CPU: PLM wrote registers in inverse order. +30. Definitions: number of virtual, physical pages derived incorrectly. +31. MAP: MMC control set wrap incorrect. +32. MAP: MMC register update of Rn|1 incorrect. +33. CPU: CBS set CC's incorrectly on unequal. +34. CPU: TTBS set CC's incorrectly on early exit. +35. IO: chan_proc_epilog and four other routines extracted device address incorrectly. +36. CPU: DW was fetching halfwords instead of words. +37. CPU: multiples were not setting condition codes on 0 operands. +38. FP: floating add zero test on second operand was inverted. +39. FP: floating add zero cases failed to set the result variable. +40. FP: floating add zero cases failed to go through postnormalization logic. +41. FP: double precision add macro lost high carry out. +42. FP: double precision add macro had an undocumented restriction about operands. +43. FP: all double precision instructions unpacked the wrong low order memory operand. +44. FP: normalization failed to decrement the exponent. +45. FP: in single precision, removing the guard digit created a spurious low-order digit. +46. FP: denormalization failed to clear the low word (single precision). +47. FP: denormalization failed to clear the guard digit (double precision). +48. FP: add/subtract failed to treat abnormal 0's as normal numbers. +49. CIS: WriteDecA set local rather than global condition codes. +50. CIS: Illegal digit check missed byte 0. +51. CIS: Overflow check set wrong condition codes. +52. CIS: NibbleLShift routine overflow check was (also broken in VAX, PDP11). +53. CIS: WordLShift routine overflow check was wrong (also broken in VAX, PDP11). +54. CIS: WordLShift had signed/unsigned variable conflict in compare. +55. CIS: WriteDecA not setting correct condition codes for -0. +55. CIS: WriteDECA not clearing CC3/4 before setting. +56. CIS: DM shift-and-test loop did 14 iterations instead of 15. +57. CIS: DM final shift of 16 done outside non-zero case instead of inside. +58. CIS: DD put quotient and remainder in wrong registers. +59. CIS: DD did not shift remainder to proper place, based on dividend/divisor widths. +60. CIS: DD overflow test missed exact 16 digit quotient case. +61. CIS: algorithm to compute length of operand failed for certain lengths (also broken + in VAX, PDP11). +62. CIS: DM and DD answer was wrong on restart cases. [NOT FIXED YET] +63. CIS: EBS fetched pattern from wrong address pointer. +64. CIS: EBS field separator wrote wrong byte. +65. MAP: Access codes defined incorrectly for access protection check. +66. CPU: LPSD fetching operands with write check rather than read check. +67. CPU: Illegal instruction stop (and other trap stops) weren't rolling back the PC. +68. CPU: History routine merged CC's into history array incorrectly. +69. CPU: History routine stored incremented rather than actualy PC. +70. CPU: History reporting routine printed wrong operand value, due to colliding declarations. +71. IO: Power up/down interrupts should not be implemented. +72. IO: WD was not recalculating int_hiact. +73. IO: Interrupt chain was not linked at powerup. +74. IO: Interrupt chain link algorithm was wrong. +75. IO: WD processing was spanning [beg,end) rather than [beg,end]. +76. RTC: RTC interrupts were happening at the wrong level. +77. PTR: leader skip was testing for channel end. +78. PTR: leader skip was testing per command instead of per reel/file. +79. PTR: end of file was treated as fatal error instead of channel end + length error. +80. PTR, PTP: units were not marked UNIT_SEQ. +81. LPT: unit was not marked UNIT_SEQ. +82. IO: device address set/show updated/displayed wrong field in single unit devices. +83. CPU: address calculation for MTx in interrupt location used incorrect length. +84. LPT: print, format opcode definitions inverted. +85. LPT: wrong index used to count buffer fill loop. +86. IO: CPU/IOP communications through 20/21 were not modelled. +87. CIS: Multiply algorithm incorrect, multiply restart not modelled. +88. CIS: Divide algorithm incorrect, divide restart not modelled. +89. IO: WD .44 not recognized as effective NOP. +90. CPU: Sigma 5 (uniquely) does not implement CVA or CVS. +91. IO: AIO merging status incorrectly. +92. IO: system for returning status byte from IO was muddled; rewrite required. +93. RAD: 7232 track shift offset was incorrectly defined. +94. CPU: MTX for interrupts returned wrong value. +95. CPU: Counter overflow trigger equation was incorrect. +96. CPU: MTX interrupts not recalculating interrupt summary values. +97. RTC: SET/SHOW C1-C4 routines were broken. +98. DP: comparison for sector field overflow was incorrect. +99. DP: cross-cylinder incorrectly set on read to end of cylinder. +100. DP: seek never executed. +101. DP: seek followon state codes set incorrectly. +102. DP: cylinder offset defined incorrectly. +103. DP: SIO not initing unit thread properly for non-zero units. +104. MUX: Line enable must be remembered for lines that are not currently connected. +105. RAD: write check was reading words off disk instead of bytes. +106. RAD: end of transfer routine checking for address error incorrectly. +107. DK: end of transfer routine checking for address error incorrectly. + + +Diagnostic Notes +---------------- + +1. PATTERN paper tape (SA = 60, end pass = 1AC), SET CPU RBLKS=32. + Break at 60 is triggered once during loading process. +2. VERIFY paper tape (SA = 140, end pass = 8E6). +3. AUTO paper tape (SA = 105), SET CPU LASLMS to suppress spurious error message. + AUTO magtape runs correctly with no messages. +4. SUFFIX magtape (SA = 100, end pass = 115), no printouts. +5. FLOAT magtape. +6. DECIMAL paper tape (SA = EE). +7. PROTECT paper tape (SA = F9), long runtime until printout. +8. MAP paper tape (SA = 7C). +9. MEDIC paper tape (SA = 68), set SSW2 after breakpoint, long runtime. +10. INT magtape, stops after M6, set SSW2 and continue, + enters pattern generator and loops forever, as expected. +11. RTC paper tape, clocks must be 500Mhz, reports clocks as "too slow" due + to faster simulation speed. + Runs correctly with SET THROTTLE 500K. + + + + + + + + + + + + + + + diff --git a/sigma/sigma_cis.c b/sigma/sigma_cis.c new file mode 100644 index 00000000..3205ac05 --- /dev/null +++ b/sigma/sigma_cis.c @@ -0,0 +1,990 @@ +/* sigma_cis.c: Sigma decimal instructions + + Copyright (c) 2007-2008, Robert M Supnik + + 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 + ROBERT M SUPNIK 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 Robert M Supnik shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + + Questions: + + 1. On the Sigma 9, in ASCII mode, is an ASCII blank used in EBS? +*/ + +#include "sigma_defs.h" + +/* Decimal string structure */ + +#define DSTRLNT 4 /* words per dec string */ +#define DECA 12 /* first dec accum reg */ + +/* Standard characters */ + +#define ZONE_E 0xF0 /* EBCDIC zone bits */ +#define ZONE_A 0x30 /* ASCII zone bits */ +#define ZONE ((PSW1 & PSW1_AS)? ZONE_A: ZONE_E) +#define PKPLUS_E 0xC /* EBCDIC preferred plus */ +#define PKPLUS_A 0xA /* ASCII preferred plus */ +#define PKPLUS ((PSW1 & PSW1_AS)? PKPLUS_A: PKPLUS_E) +#define BLANK_E 0x40 /* EBCDIC blank */ +#define BLANK_A 0x20 /* ASCII blank */ +#define BLANK ((PSW1 & PSW1_AS)? BLANK_A: BLANK_E) + +/* Edit special characters */ + +#define ED_DS 0x20 /* digit select */ +#define ED_SS 0x21 /* start significance */ +#define ED_FS 0x22 /* field separator */ +#define ED_SI 0x23 /* immediate significance */ + +/* Decimal strings run low order (word 0/R15) to high order (word 3/R12) */ + +typedef struct { + uint32 sign; + uint32 val[DSTRLNT]; + } dstr_t; + +/* Copy decimal accumulator to decimal string, no validation or sign separation */ + +#define ReadDecA(src) for (i = 0; i < DSTRLNT; i++) \ + src.val[DSTRLNT - 1 - i] = R[DECA + i]; + +static dstr_t Dstr_zero = { 0, 0, 0, 0, 0 }; + +extern uint32 *R; +extern uint32 CC; +extern uint32 PSW1; +extern uint32 bvamqrx; +extern uint32 cpu_model; + +uint32 ReadDstr (uint32 lnt, uint32 addr, dstr_t *dec); +uint32 WriteDstr (uint32 lnt, uint32 addr, dstr_t *dec); +void WriteDecA (dstr_t *dec, t_bool cln); +void SetCC2Dstr (uint32 lnt, dstr_t *dst); +uint32 TestDstrValid (dstr_t *src); +uint32 DstrInvd (void); +uint32 AddDstr (dstr_t *src1, dstr_t *src2, dstr_t *dst, uint32 cin); +void SubDstr (dstr_t *src1, dstr_t *src2, dstr_t *dst); +int32 CmpDstr (dstr_t *src1, dstr_t *src2); +uint32 LntDstr (dstr_t *dsrc); +uint32 NibbleLshift (dstr_t *dsrc, uint32 sc, uint32 cin); +uint32 NibbleRshift (dstr_t *dsrc, uint32 sc, uint32 cin); +t_bool GenLshift (dstr_t *dsrc, uint32 sc); +void GenRshift (dstr_t *dsrc, uint32 sc); +uint32 ed_getsrc (uint32 sa, uint32 *c, uint32 *d); +void ed_advsrc (uint32 rn, uint32 c); +t_bool cis_test_int (dstr_t *src1, uint32 *kint); +void cis_dm_int (dstr_t *src, dstr_t *dst, uint32 kint); +void cis_dd_int (dstr_t *src, dstr_t *dst, uint32 t, uint32 *kint); + +/* Decimal instructions */ + +uint32 cis_dec (uint32 op, uint32 lnt, uint32 bva) +{ +dstr_t src1, src2, src2x, dst; +uint32 i, t, kint, ldivr, ldivd, ad, c, d, end; +int32 sc; +uint32 tr; + +if (lnt == 0) /* adjust length */ + lnt = 16; +CC &= ~(CC1|CC2); /* clear CC1, CC2 */ + +switch (op) { /* case on opcode */ + + case OP_DL: /* decimal load */ + if ((tr = ReadDstr (lnt, bva, &dst)) != 0) /* read mem string */ + return tr; + WriteDecA (&dst, FALSE); /* store result */ + break; + + case OP_DST: /* decimal store */ + ReadDecA (dst); /* read dec accum */ + if ((tr = TestDstrValid (&dst)) != 0) /* valid? */ + return tr; + if ((tr = WriteDstr (lnt, bva, &dst)) != 0) /* write to mem */ + return tr; + break; + + case OP_DS: /* decimal subtract */ + case OP_DA: /* decimal add */ + ReadDecA (src1); /* read dec accum */ + if ((tr = TestDstrValid (&src1)) != 0) /* valid? */ + return tr; + if ((tr = ReadDstr (lnt, bva, &src2)) != 0) /* read mem string */ + return tr; + if (op == OP_DS) /* sub? invert sign */ + src2.sign = src2.sign ^ 1; + if (src1.sign ^ src2.sign) { /* opp signs? sub */ + if (CmpDstr (&src1, &src2) < 0) { /* src1 < src2? */ + SubDstr (&src1, &src2, &dst); /* src2 - src1 */ + dst.sign = src2.sign; /* sign = src2 */ + } + else { + SubDstr (&src2, &src1, &dst); /* src1 - src2 */ + dst.sign = src1.sign; /* sign = src1 */ + } + } + else { /* addition */ + if (AddDstr (&src1, &src2, &dst, 0)) { /* add, overflow? */ + CC |= CC2; /* set CC2 */ + return (PSW1 & PSW1_DM)? TR_DEC: 0; /* trap if enabled */ + } + dst.sign = src1.sign; /* set result sign */ + } + WriteDecA (&dst, TRUE); /* store result */ + break; + + case OP_DC: /* decimal compare */ + ReadDecA ( src1); /* read dec accum */ + if ((tr = TestDstrValid (&src1)) != 0) /* valid? */ + return tr; + if ((tr = ReadDstr (lnt, bva, &src2)) != 0) /* read mem string */ + return tr; + LntDstr (&src1); /* clean -0 */ + LntDstr (&src2); + if (src1.sign ^ src2.sign) /* signs differ? */ + CC = src1.sign? CC4: CC3; /* set < or > */ + else { /* same signs */ + t = CmpDstr (&src1, &src2); /* compare strings */ + if (t < 0) + CC = (src1.sign? CC3: CC4); + else if (t > 0) + CC = (src1.sign? CC4: CC3); + else CC = 0; + } + break; + +/* Decimal multiply - algorithm from George Plue. + + The Sigma does decimal multiply one digit at a time, using the multiplicand + and a doubled copy of the multiplicand. Multiplying by digits 1-5 is + synthesized by 1-3 adds; multiplying by digits 6-9 is synthesized by 1-2 + subtractions, and adding 1 to the next multiplier digit. (That is, + multiplying by 7 is done by multiplying by "10 - 3".) This requires at + most one extra add to fixup the last digit, and minimizes the overall + number of adds (average 1.5 adds per multiplier digit). Note that + multiplication proceeds from right to left. + + The Sigma 5-9 allowed decimal multiply to be interrupted; the 5X0 series + did not. An interrupted multiply uses a sign digit in R12 and R13 as the + divider between the remaining multiplier (to the left of the sign, and + in the low-order digit of R15) and the partial product (to the right of + the sign). Because the partial product may be negative, leading 0x99's + may have been stripped and need to be restored. + + The real Sigma's probably didn't run a validty test after separation of + the partial product and multiplier, but it doesn't hurt, and prevents + certain corner cases from causing errors. */ + + case OP_DM: /* decimal multiply */ + if (lnt >= 9) /* invalid length? */ + return DstrInvd (); + ReadDecA (src1); /* get dec accum */ + if ((tr = ReadDstr (lnt, bva, &src2)) != 0) /* read mem string */ + return tr; + dst = Dstr_zero; /* clear result */ + kint = 0; /* assume no int */ + if (!QCPU_5X0 && /* S5-9? */ + (cis_test_int (&src1, &kint))) /* interrupted? */ + cis_dm_int (&src1, &dst, kint); /* restore */ + else if ((tr = TestDstrValid (&src1)) != 0) /* mpyr valid? */ + return tr; + if (LntDstr (&src1) && LntDstr (&src2)) { /* both opnds != 0? */ + dst.sign = src1.sign ^ src2.sign; /* sign of result */ + AddDstr (&src2, &src2, &src2x, 0); /* get 2*mplcnd */ + for (i = 1; i <= 16; i++) { /* 16 iterations */ + if (i >= kint) { /* past int point? */ + NibbleRshift (&src1, 1, 0); /* mpyr right 4 */ + d = src1.val[0] & 0xF; /* get digit */ + switch (d) { /* case */ + case 5: /* + 2 + 2 + 1 */ + AddDstr (&src2x, &dst, &dst, 0); + case 3: /* + 2 + 1 */ + AddDstr (&src2x, &dst, &dst, 0); + case 1: /* + 1 */ + AddDstr (&src2, &dst, &dst, 0); + case 0: + break; + case 4: /* + 2 + 2 */ + AddDstr (&src2x, &dst, &dst, 0); + case 2: /* + 2 */ + AddDstr (&src2x, &dst, &dst, 0); + break; + case 6: /* - 2 - 2 + 10 */ + SubDstr (&src2x, &dst, &dst); + case 8: /* - 2 + 10 */ + SubDstr (&src2x, &dst, &dst); + src1.val[0] += 0x10; /* + 10 */ + break; + case 7: /* -2 - 1 + 10 */ + SubDstr (&src2x, &dst, &dst); + case 9: /* -1 + 10 */ + SubDstr (&src2, &dst, &dst); + default: /* + 10 */ + src1.val[0] += 0x10; + } /* end switch */ + } /* end if >= kint */ + NibbleLshift (&src2, 1, 0); /* shift mplcnds */ + NibbleLshift (&src2x, 1, 0); + } /* end for */ + } /* end if != 0 */ + WriteDecA (&dst, TRUE); /* store result */ + break; + +/* Decimal divide overflow calculation - if the dividend has true length d, + and the divisor true length r, then the quotient will have (d - r) or + (d - r + 1) digits. Therefore, if (d - r) > 15, the quotient will not + fit. However, if (d - r) == 15, it may or may not fit, depending on + whether the first subtract succeeds. Therefore, it's necessary to test + after the divide to see if the quotient has one extra digit. */ + + case OP_DD: /* decimal divide */ + if (lnt >= 9) /* invalid length? */ + return DstrInvd (); + ReadDecA (src1); /* read dec accum */ + if ((tr = ReadDstr (lnt, bva, &src2)) != 0) /* read mem string */ + return tr; + dst = Dstr_zero; /* clear result */ + kint = 0; /* no interrupt */ + if (!QCPU_5X0 && /* S5-9? */ + (cis_test_int (&src1, &t))) { /* interrupted? */ + cis_dd_int (&src1, &dst, t, &kint); /* restore */ + t = t - 1; + } + else { /* normal start? */ + if ((tr = TestDstrValid (&src1)) != 0) /* divd valid? */ + return tr; + ldivr = LntDstr (&src2); /* divr lnt */ + ldivd = LntDstr (&src1); /* divd lnt */ + if ((ldivr == 0) || /* div by zero? */ + (ldivd > (ldivr + 15))) { /* quo too big? */ + CC |= CC2; /* divide check */ + return (PSW1 & PSW1_DM)? TR_DEC: 0; /* trap if enabled */ + } + if (CmpDstr (&src1, &src2) < 0) { /* no divide? */ + R[12] = src1.val[1]; /* remainder */ + R[13] = src1.val[0] | (PKPLUS + src1.sign); + R[14] = 0; /* quotient */ + R[15] = PKPLUS; + CC = 0; + return SCPE_OK; + } + t = ldivd - ldivr; + } + dst.sign = src1.sign ^ src2.sign; /* calculate sign */ + GenLshift (&src2, t); /* align */ + for (i = 0; i <= t; i++) { /* divide loop */ + for (d = kint; /* find digit */ + (d < 10) && (CmpDstr (&src1, &src2) >= 0); + d++) + SubDstr (&src2, &src1, &src1); + dst.val[0] = (dst.val[0] & ~0xF) | d; /* insert quo dig */ + NibbleLshift (&dst, 1, 0); /* shift quotient */ + NibbleRshift (&src2, 1, 0); /* shift divisor */ + kint = 0; /* no more int */ + } /* end divide loop */ + if (dst.val[2]) { /* quotient too big? */ + CC |= CC2; /* divide check */ + return (PSW1 & PSW1_DM)? TR_DEC: 0; /* trap if enabled */ + } + CC = dst.sign? CC4: CC3; /* set CC's */ + R[12] = src1.val[1]; /* remainder */ + R[13] = src1.val[0] | (PKPLUS + src1.sign); + R[14] = dst.val[1]; /* quotient */ + R[15] = dst.val[0] | (PKPLUS + dst.sign); + break; + + case OP_DSA: /* decimal shift */ + ReadDecA (dst); /* read dec accum */ + if ((tr = TestDstrValid (&dst)) != 0) /* valid? */ + return tr; + CC = 0; /* clear CC's */ + sc = SEXT_H_W (bva >> 2); /* shift count */ + if (sc > 31) /* sc in [-31,31] */ + sc = 31; + if (sc < -31) + sc = -31; + if (sc < 0) { /* right shift? */ + sc = -sc; /* |shift| */ + GenRshift (&dst, sc); /* do shift */ + dst.val[0] = dst.val[0] & ~0xF; /* clear sign */ + } /* end right shift */ + else if (sc) { /* left shift? */ + if (GenLshift (&dst, sc)) /* do shift */ + CC |= CC2; + } /* end left shift */ + WriteDecA (&dst, FALSE); /* store result */ + break; + + case OP_PACK: /* zoned to packed */ + dst = Dstr_zero; /* clear result */ + end = (2 * lnt) - 1; /* zoned length */ + for (i = 1; i <= end; i++) { /* loop thru char */ + ad = (bva + end - i) & bvamqrx; /* zoned character */ + if ((tr = ReadB (ad, &c, VR)) != 0) /* read char */ + return tr; + if (i == 1) { /* sign + digit? */ + uint32 s; + s = (c >> 4) & 0xF; /* get sign */ + if (s < 0xA) + return DstrInvd (); + if ((s == 0xB) || (s == 0xD)) /* negative */ + dst.sign = 1; + } + d = c & 0xF; /* get digit */ + if (d > 0x9) + return DstrInvd (); + dst.val[i / 8] = dst.val[i / 8] | (d << ((i % 8) * 4)); + } + WriteDecA (&dst, FALSE); /* write result */ + break; + + case OP_UNPK: /* packed to zoned */ + ReadDecA (dst); /* read dec accum */ + if ((tr = TestDstrValid (&dst)) != 0) /* valid? */ + return tr; + end = (2 * lnt) - 1; /* zoned length */ + if ((tr = ReadB (bva, &c, VW)) != 0) /* prove writeable */ + return tr; + for (i = 1; i <= end; i++) { /* loop thru chars */ + c = (dst.val[i / 8] >> ((i % 8) * 4)) & 0xF; /* get digit */ + if (i == 1) /* first? */ + c |= ((PKPLUS + dst.sign) << 4); /* or in sign */ + else c |= ZONE; /* no, or in zone */ + ad = (bva + end - i) & bvamqrx; + if ((tr = WriteB (ad, c, VW)) != 0) /* write to memory */ + return tr; + } + SetCC2Dstr (lnt, &dst); /* see if too long */ + break; + } +return 0; +} + +/* Test for interrupted multiply or divide */ + +t_bool cis_test_int (dstr_t *src, uint32 *kint) +{ +int32 i; +uint32 wd, sc, d; + +for (i = 15; i >= 1; i--) { /* test 15 nibbles */ + wd = (DSTRLNT/2) + (i / 8); + sc = (i % 8) * 4; + d = (src->val[wd] >> sc) & 0xF; + if (d >= 0xA) { + *kint = (uint32) i; + return TRUE; + } + } +return FALSE; +} + +/* Resume interrupted multiply + + The sign that was found is the "fence" between the the remaining multiplier + and the partial product: + R val + +--+--+--+--+--+--+--+--+ + | mpyer |sn|pp| 12 3 + +--+--+--+--+--+--+--+--+ + | partial product | 13 2 + +--+--+--+--+--+--+--+--+ + | partial product | 14 1 + +--+--+--+--+--+--+--+--+ + | partial product |mp| 15 0 + +--+--+--+--+--+--+--+--+ + + This routine separates the multiplier and partial product, returns the + multiplier as a valid decimal string in src, and the partial product + as a value with no sign in dst */ + +void cis_dm_int (dstr_t *src, dstr_t *dst, uint32 kint) +{ +uint32 ppneg, wd, sc, d, curd; +int32 k; + +*dst = *src; /* copy input */ +wd = (DSTRLNT/2) + (kint / 8); +sc = (kint % 8) * 4; +d = (src->val[wd] >> sc) & 0xF; /* get sign fence */ +ppneg = ((d >> 2) & 1) ^ 1; /* partial prod neg? */ +curd = (src->val[0] & 0xF) + ppneg; /* bias cur digit */ +src->val[wd] = (src->val[wd] & ~(0xF << sc)) | /* replace sign */ + (curd << sc); /* with digit */ +GenRshift (src, kint + 15); /* right justify */ +src->sign = ((d == 0xB) || (d == 0xD))? 1: 0; /* set mpyr sign */ +src->val[0] = src->val[0] & ~0xF; /* clear sign pos */ + +/* Mask out multiplier */ + +for (k = DSTRLNT - 1; k >= (int32) wd; k--) /* words hi to lo */ + dst->val[k] &= ~(0xFFFFFFFFu << + ((k > (int32) wd)? 0: sc)); + +/* Recreate missing high order digits for negative partial product */ + +if (ppneg) { /* negative? */ + for (k = (DSTRLNT * 4) - 1; k != 0; k--) { /* bytes hi to lo */ + wd = k / 4; + sc = (k % 4) * 8; + if (((dst->val[wd] >> sc) & 0xFF) != 0) + break; + dst->val[wd] |= (0x99 << sc); /* repl 00 with 99 */ + } /* end for */ + } +dst->val[0] &= ~0xF; /* clear pp sign */ +return; +} + +/* Resume interrupted divide + + The sign that was found is the "fence" between the the quotient and the + remaining dividend product: + R val + +--+--+--+--+--+--+--+--+ + | quotient |sn|dv| 12 3 + +--+--+--+--+--+--+--+--+ + | dividend | 13 2 + +--+--+--+--+--+--+--+--+ + | dividend | 14 1 + +--+--+--+--+--+--+--+--+ + | dividend |qu| 15 0 + +--+--+--+--+--+--+--+--+ + + This routine separates the quotient and the remaining dividend, returns + the dividend as a valid decimal string, the quotient as a decimal string + without sign, and kint is the partial value of the last quotient digit. */ + +void cis_dd_int (dstr_t *src, dstr_t *dst, uint32 nib, uint32 *kint) +{ +uint32 wd, sc, d, curd; +int32 k; + +wd = (DSTRLNT/2) + (nib / 8); +sc = (nib % 8) * 4; +curd = src->val[0] & 0xF; /* last quo digit */ +*dst = *src; /* copy input */ +GenRshift (dst, nib + 16); /* right justify quo */ +d = dst->val[0] & 0xF; /* get sign fence */ +dst->val[0] = (dst->val[0] & ~0xF) | curd; /* repl with digit */ +*kint = curd; + +/* Mask out quotient */ + +for (k = DSTRLNT - 1; k >= (int32) wd; k--) /* words hi to lo */ + src->val[k] &= ~(0xFFFFFFFFu << + ((k > (int32) wd)? 0: sc)); +src->sign = ((d == 0xB) || (d == 0xD))? 1: 0; /* set divd sign */ +src->val[0] = src->val[0] & ~0xF; /* clr sign digit */ +return; +} + +/* Get packed decimal string from memory + + Arguments: + lnt = decimal string length + adr = decimal string address + src = decimal string structure + Output: + trap or abort signal + + Per the Sigma spec, bad digits or signs cause a fault or abort */ + +uint32 ReadDstr (uint32 lnt, uint32 adr, dstr_t *src) +{ +uint32 i, c, bva; +uint32 tr; + +*src = Dstr_zero; /* clear result */ +for (i = 0; i < lnt; i++) { /* loop thru string */ + bva = (adr + lnt - i - 1) & bvamqrx; /* from low to high */ + if ((tr = ReadB (bva, &c, VR)) != 0) /* read byte */ + return tr; + src->val[i / 4] = src->val[i / 4] | (c << ((i % 4) * 8)); + } /* end for */ +return TestDstrValid (src); +} + +/* Separate sign, validate sign and digits of decimal string */ + +uint32 TestDstrValid (dstr_t *src) +{ +uint32 i, j, s, t; + +s = src->val[0] & 0xF; /* get sign */ +if (s < 0xA) /* valid? */ + return DstrInvd (); +if ((s == 0xB) || (s == 0xD)) /* negative? */ + src->sign = 1; +else src->sign = 0; +src->val[0] &= ~0xF; /* clear sign */ + +for (i = 0; i < DSTRLNT; i++) { /* check 4 words */ + for (j = 0; j < 8; j++) { /* 8 digit/word */ + t = (src->val[i] >> (28 - (j * 4))) & 0xF; /* get digit */ + if (t > 0x9) /* invalid digit? */ + return DstrInvd (); /* exception */ + } + } +return 0; +} + +/* Invalid digit or sign: set CC1, trap or abort instruction */ + +uint32 DstrInvd (void) +{ +CC |= CC1; /* set CC1 */ +if (PSW1 & PSW1_DM) /* if enabled, trap */ + return TR_DEC; +return WSIGN; /* otherwise, abort */ +} + +/* Store decimal string + + Arguments: + lnt = decimal string length + adr = decimal string address + dst = decimal string structure + + Returns memory management traps (if any) + Bad digits and invalid sign are impossible +*/ + +uint32 WriteDstr (uint32 lnt, uint32 adr, dstr_t *dst) +{ +uint32 i, bva, c; +uint32 tr; + +dst->val[0] = dst->val[0] | (PKPLUS + dst->sign); /* set sign */ +if ((tr = ReadB (adr, &c, VW)) != 0) /* prove writeable */ + return tr; +for (i = 0; i < lnt; i++) { /* loop thru bytes */ + c = (dst->val[i / 4] >> ((i % 4) * 8)) & 0xFF; /* from low to high */ + bva = (adr + lnt - i - 1) & bvamqrx; + if ((tr = WriteB (bva, c, VW)) != 0) /* store byte */ + return tr; + } /* end for */ +SetCC2Dstr (lnt, dst); /* check overflow */ +return 0; +} + +/* Store result in decimal accumulator + + Arguments: + dst = decimal string structure + cln = clean -0 if true + + Sets condition codes CC3 and CC4 + Bad digits and invalid sign are impossible */ + +void WriteDecA (dstr_t *dst, t_bool cln) +{ +uint32 i, nz; + +CC &= ~(CC3|CC4); /* assume zero */ +for (i = 0, nz = 0; i < DSTRLNT; i++) { /* save 32 digits */ + R[DECA + i] = dst->val[DSTRLNT - 1 - i]; + nz |= dst->val[DSTRLNT - 1 - i]; + } +if (nz) /* non-zero? */ + CC |= (dst->sign)? CC4: CC3; /* set CC3 or CC4 */ +else if (cln) /* zero, clean? */ + dst->sign = 0; /* clear sign */ +R[DECA + DSTRLNT - 1] |= (PKPLUS + dst->sign); /* or in sign */ +return; +} + +/* Set CC2 for decimal string store + + Arguments: + lnt = string length + dst = decimal string structure + Output: + sets CC2 if information won't fit */ + +void SetCC2Dstr (uint32 lnt, dstr_t *dst) +{ +uint32 i, limit, mask; +static uint32 masktab[8] = { + 0xFFFFFFF0, 0xFFFFFF00, 0xFFFFF000, 0xFFFF0000, + 0xFFF00000, 0xFF000000, 0xF0000000, 0x00000000 + }; + +lnt = (lnt * 2) - 1; /* number of digits */ +mask = 0; /* can't ovflo */ +limit = lnt / 8; /* limit for test */ +for (i = 0; i < DSTRLNT; i++) { /* loop thru value */ + if (i == limit) /* @limit, get mask */ + mask = masktab[lnt % 8]; + else if (i > limit) /* >limit, test all */ + mask = 0xFFFFFFFF; + if (dst->val[i] & mask) /* test for ovflo */ + CC |= CC2; + } +return; +} + +/* Add decimal string magnitudes + + Arguments: + s1 = src1 decimal string + s2 = src2 decimal string + ds = dest decimal string + cy = carry in + Output: + 1 if carry, 0 if no carry + + This algorithm courtesy Anton Chernoff, circa 1992 or even earlier. + + We trace the history of a pair of adjacent digits to see how the + carry is fixed; each parenthesized item is a 4b digit. + + Assume we are adding: + + (a)(b) I + + (x)(y) J + + First compute I^J: + + (a^x)(b^y) TMP + + Note that the low bit of each digit is the same as the low bit of + the sum of the digits, ignoring the carry, since the low bit of the + sum is the xor of the bits. + + Now compute I+J+66 to get decimal addition with carry forced left + one digit: + + (a+x+6+carry mod 16)(b+y+6 mod 16) SUM + + Note that if there was a carry from b+y+6, then the low bit of the + left digit is different from the expected low bit from the xor. + If we xor this SUM into TMP, then the low bit of each digit is 1 + if there was a carry, and 0 if not. We need to subtract 6 from each + digit that did not have a carry, so take ~(SUM ^ TMP) & 0x11, shift + it right 4 to the digits that are affected, and subtract 6*adjustment + (actually, shift it right 3 and subtract 3*adjustment). +*/ + +uint32 AddDstr (dstr_t *s1, dstr_t *s2, dstr_t *ds, uint32 cy) +{ +uint32 i; +uint32 sm1, sm2, tm1, tm2, tm3, tm4; + +for (i = 0; i < DSTRLNT; i++) { /* loop low to high */ + tm1 = s1->val[i] ^ (s2->val[i] + cy); /* xor operands */ + sm1 = s1->val[i] + (s2->val[i] + cy); /* sum operands */ + sm2 = sm1 + 0x66666666; /* force carry out */ + cy = ((sm1 < s1->val[i]) || (sm2 < sm1)); /* check for ovflo */ + tm2 = tm1 ^ sm2; /* get carry flags */ + tm3 = (tm2 >> 3) | (cy << 29); /* compute adjust */ + tm4 = 0x22222222 & ~tm3; /* clrr where carry */ + ds->val[i] = (sm2 - (3 * tm4)) & WMASK; /* final result */ + } +return cy; +} + +/* Subtract decimal string magnitudes + + Arguments: + s1 = src1 decimal string + s2 = src2 decimal string + ds = dest decimal string + + Note: the routine assumes that s1 <= s2 + +*/ + +void SubDstr (dstr_t *s1, dstr_t *s2, dstr_t *ds) +{ +uint32 i; +dstr_t compl; + +for (i = 0; i < DSTRLNT; i++) /* 9's comp s2 */ + compl.val[i] = 0x99999999 - s1->val[i]; +AddDstr (&compl, s2, ds, 1); /* s1 + ~s2 + 1 */ +return; +} + +/* Compare decimal string magnitudes + + Arguments: + s1 = src1 decimal string + s2 = src2 decimal string + Output: + 1 if >, 0 if =, -1 if < +*/ + +int32 CmpDstr (dstr_t *s1, dstr_t *s2) +{ +int32 i; + +for (i = DSTRLNT - 1; i >=0; i--) { + if (s1->val[i] > s2->val[i]) + return 1; + if (s1->val[i] < s2->val[i]) + return -1; + } +return 0; +} + +/* Get exact length of decimal string, clean -0 + + Arguments: + dst = decimal string structure + Output: + number of non-zero digits +*/ + +uint32 LntDstr (dstr_t *dst) +{ +int32 nz, i; + +for (nz = DSTRLNT - 1; nz >= 0; nz--) { + if (dst->val[nz]) { + for (i = 7; i >= 0; i--) { + if ((dst->val[nz] >> (i * 4)) & 0xF) + return (nz * 8) + i; + } + } + } +dst->sign = 0; +return 0; +} + +/* Word shift right + + Arguments: + dsrc = decimal string structure + sc = shift count in nibbles +*/ + +void GenRshift (dstr_t *dsrc, uint32 cnt) +{ +uint32 i, sc, sc1; + +sc = cnt / 8; +sc1 = cnt % 8; +if (sc) { + for (i = 0; i < DSTRLNT; i++) { + if ((i + sc) < DSTRLNT) + dsrc->val[i] = dsrc->val[i + sc]; + else dsrc->val[i] = 0; + } + } +if (sc1) + NibbleRshift (dsrc, sc1, 0); +return; +} + +/* General shift left + + Arguments: + dsrc = decimal string structure + cnt = shift count in nibbles +*/ + +t_bool GenLshift (dstr_t *dsrc, uint32 cnt) +{ +t_bool i, c, sc, sc1; + +c = 0; +sc = cnt / 8; +sc1 = cnt % 8; +if (sc) { + for (i = DSTRLNT - 1; (int32) i >= 0; i--) { + if (i >= sc) + dsrc->val[i] = dsrc->val[i - sc]; + else { + c |= dsrc->val[i]; + dsrc->val[i] = 0; + } + } + } +if (sc1) + c |= NibbleLshift (dsrc, sc1, 0); +return (c? TRUE: FALSE); +} + +/* Nibble shift right + + Arguments: + dsrc = decimal string structure + sc = shift count in nibbles + cin = carry in +*/ + +uint32 NibbleRshift (dstr_t *dsrc, uint32 sc, uint32 cin) +{ +int32 i; +uint32 s, nc; + +if (s = sc * 4) { + for (i = DSTRLNT - 1; (int32) i >= 0; i--) { + nc = (dsrc->val[i] << (32 - s)) & WMASK; + dsrc->val[i] = ((dsrc->val[i] >> s) | + cin) & WMASK; + cin = nc; + } + return cin; + } +return 0; +} + +/* Nibble shift left + + Arguments: + dsrc = decimal string structure + sc = shift count in nibbles + cin = carry in +*/ + +uint32 NibbleLshift (dstr_t *dsrc, uint32 sc, uint32 cin) +{ +uint32 i, s, nc; + +if (s = sc * 4) { + for (i = 0; i < DSTRLNT; i++) { + nc = dsrc->val[i] >> (32 - s); + dsrc->val[i] = ((dsrc->val[i] << s) | + cin) & WMASK; + cin = nc; + } + return cin; + } +return 0; +} +/* Edit instruction */ + +uint32 cis_ebs (uint32 rn, uint32 disp) +{ +uint32 sa, da, c, d, dst, fill, pat; +uint32 tr; + +disp = SEXT_LIT_W (disp) & WMASK; /* sext operand */ +fill = S_GETMCNT (R[rn]); /* fill char */ +while (S_GETMCNT (R[rn|1])) { /* while pattern */ + sa = (disp + R[rn]) & bvamqrx; /* dec str addr */ + da = R[rn|1] & bvamqrx; /* pattern addr */ + if ((tr = ReadB (da, &pat, VR)) != 0) /* get pattern byte */ + return tr; + switch (pat) { /* case on pattern */ + + case ED_DS: /* digit select */ + if ((tr = ed_getsrc (sa, &c, &d)) != 0) /* get src digit */ + return tr; + if (CC & CC4) /* signif? unpack */ + dst = ZONE | d; + else if (d) { /* non-zero? */ + R[1] = da; /* save addr */ + dst = ZONE | d; /* unpack */ + CC |= CC4; /* set signif */ + } + else dst = fill; /* otherwise fill */ + if ((tr = WriteB (da, dst, VW)) != 0) /* overwrite dst */ + return tr; + ed_advsrc (rn, c); /* next src digit */ + break; + + case ED_SS: /* signif start */ + if ((tr = ed_getsrc (sa, &c, &d)) != 0) /* get src digit */ + return tr; + if (CC & CC4) /* signif? unpack */ + dst = ZONE | d; + else if (d) { /* non-zero? */ + R[1] = da; /* save addr */ + dst = ZONE | d; /* unpack */ + } + else { /* otherwise */ + R[1] = da + 1; /* save next */ + dst = fill; /* fill */ + } + CC |= CC4; /* set signif */ + if ((tr = WriteB (da, dst, VW)) != 0) /* overwrite dst */ + return tr; + ed_advsrc (rn, c); /* next src digit */ + break; + + case ED_SI: /* signif immediate */ + if ((tr = ed_getsrc (sa, &c, &d)) != 0) /* get src digit */ + return tr; + R[1] = da; /* save addr */ + dst = ZONE | d; /* unpack */ + CC |= CC4; /* set signif */ + if ((tr = WriteB (da, dst, VW)) != 0) /* overwrite dst */ + return tr; + ed_advsrc (rn, c); /* next src digit */ + break; + + case ED_FS: /* field separator */ + CC &= ~(CC1|CC3|CC4); /* clr all exc CC2 */ + if ((tr = WriteB (da, fill, VW)) != 0) /* overwrite dst */ + return tr; + break; + + default: /* all others */ + if ((CC & CC4) == 0) { /* signif off? */ + dst = (CC & CC1)? BLANK: fill; /* blank or fill */ + if ((tr = WriteB (da, dst, VW)) != 0) /* overwrite dst */ + return tr; + } + break; + } /* end switch dst */ + R[rn|1] = (R[rn|1] + S_ADDRINC) & WMASK; /* next pattern */ + } /* end while */ +return 0; +} + +/* Routine to get and validate the next source digit */ + +uint32 ed_getsrc (uint32 sa, uint32 *c, uint32 *d) +{ +uint32 tr; + +if ((tr = ReadB (sa, c, VR)) != 0) /* read source byte */ + return tr; +*d = ((CC & CC2)? *c: *c >> 4) & 0xF; /* isolate digit */ +if (*d > 0x9) /* invalid? */ + return TR_DEC; +if (*d) /* non-zero? */ + CC |= CC3; +return 0; +} + +/* Routine to advance source string */ + +void ed_advsrc (uint32 rn, uint32 c) +{ +c = c & 0xF; /* get low digit */ +if (((CC & CC2) == 0) && (c > 0x9)) { /* sel left, with sign? */ + if ((c == 0xB) || (c == 0xD)) /* minus? */ + CC = CC | (CC1|CC4); /* CC1, CC4 */ + else CC = (CC | CC1) & ~CC4; /* no, CC1, ~CC4 */ + R[rn] = R[rn] + 1; /* skip two digits */ + } +else { /* adv 1 digit */ + if (CC & CC2) + R[rn] = R[rn] + 1; + CC = CC ^ CC2; + } +return; +} diff --git a/sigma/sigma_coc.c b/sigma/sigma_coc.c new file mode 100644 index 00000000..800fbee8 --- /dev/null +++ b/sigma/sigma_coc.c @@ -0,0 +1,620 @@ +/* sigma_coc.c: Sigma character-oriented communications subsystem simulator + + Copyright (c) 2007-2008, Robert M Supnik + + 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 substanXIAl 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 + ROBERT M SUPNIK 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 Robert M Supnik shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + + coc 7611 communications multiplexor + +*/ + +#include "sigma_io_defs.h" +#include "sim_sock.h" +#include "sim_tmxr.h" +#include + +/* Constants */ + +#define MUX_LINES 64 /* max lines */ +#define MUX_LINES_DFLT 8 /* default lines */ +#define MUX_INIT_POLL 8000 +#define MUXL_WAIT 500 +#define MUX_NUMLIN mux_desc.lines /* curr # lines */ + +#define MUXC 0 /* channel thread */ +#define MUXI 1 /* input thread */ + +/* Line status */ + +#define MUXL_XIA 0x01 /* xmt intr armed */ +#define MUXL_XIR 0x02 /* xmt intr req */ +#define MUXL_REP 0x04 /* rcv enable pend */ +#define MUXL_RBP 0x10 /* rcv break pend */ + +/* Channel state */ + +#define MUXC_IDLE 0 /* idle */ +#define MUXC_INIT 1 /* init */ +#define MUXC_RCV 2 /* receive */ +#define MUXC_END 3 /* end */ + +/* DIO address */ + +#define MUXDIO_V_FNC 0 /* function */ +#define MUXDIO_M_FNC 0xF +#define MUXDIO_V_COC 4 /* ctlr num */ +#define MUXDIO_M_COC 0xF +#define MUXDIO_GETFNC(x) (((x) >> MUXDIO_V_FNC) & MUXDIO_M_FNC) +#define MUXDIO_GETCOC(x) (((x) >> MUXDIO_V_COC) & MUXDIO_M_COC) + +#define MUXDAT_V_LIN 0 /* line num */ +#define MUXDAT_M_LIN (MUX_LINES - 1) +#define MUXDAT_V_CHR 8 /* output char */ +#define MUXDAT_M_CHR 0xFF +#define MUXDAT_GETLIN(x) (((x) >> MUXDAT_V_LIN) & MUXDAT_M_LIN) +#define MUXDAT_GETCHR(x) (((x) >> MUXDAT_V_CHR) & MUXDAT_M_CHR) + +uint8 mux_rbuf[MUX_LINES]; /* rcv buf */ +uint8 mux_xbuf[MUX_LINES]; /* xmt buf */ +uint8 mux_sta[MUX_LINES]; /* status */ +uint32 mux_tps = RTC_HZ_50; /* polls/second */ +uint32 mux_scan = 0; /* scanner */ +uint32 mux_slck = 0; /* scanner locked */ +uint32 muxc_cmd = MUXC_IDLE; /* channel state */ +uint32 mux_rint = INTV (INTG_E2, 0); +uint32 mux_xint = INTV (INTG_E2, 1); + +TMLN mux_ldsc[MUX_LINES] = { 0 }; /* line descrs */ +TMXR mux_desc = { MUX_LINES_DFLT, 0, 0, mux_ldsc }; /* mux descrr */ + +extern uint32 chan_ctl_time; +extern uint32 CC; +extern uint32 *R; + +uint32 mux_disp (uint32 op, uint32 dva, uint32 *dvst); +uint32 mux_dio (uint32 op, uint32 rn, uint32 ad); +uint32 mux_tio_status (void); +t_stat mux_chan_err (uint32 st); +t_stat muxc_svc (UNIT *uptr); +t_stat muxo_svc (UNIT *uptr); +t_stat muxi_rtc_svc (UNIT *uptr); +t_stat mux_reset (DEVICE *dptr); +t_stat mux_attach (UNIT *uptr, char *cptr); +t_stat mux_detach (UNIT *uptr); +t_stat mux_vlines (UNIT *uptr, int32 val, char *cptr, void *desc); +void mux_reset_ln (int32 ln); +void mux_scan_next (t_bool clr); +t_stat muxi_put_char (uint32 c, uint32 ln); + +/* MUX data structures + + mux_dev MUX device descriptor + mux_unit MUX unit descriptor + mux_reg MUX register list + mux_mod MUX modifiers list +*/ + +dib_t mux_dib = { DVA_MUX, &mux_disp, DIO_MUX, &mux_dio }; + +UNIT mux_unit[] = { + { UDATA (&muxc_svc, UNIT_ATTABLE, 0) }, + { UDATA (&muxi_rtc_svc, UNIT_DIS, 0) } + }; + +REG mux_reg[] = { + { BRDATA (STA, mux_sta, 16, 8, MUX_LINES) }, + { BRDATA (RBUF, mux_rbuf, 16, 8, MUX_LINES) }, + { BRDATA (XBUF, mux_xbuf, 16, 8, MUX_LINES) }, + { DRDATA (SCAN, mux_scan, 6) }, + { FLDATA (SLCK, mux_slck, 0) }, + { DRDATA (CMD, muxc_cmd, 2) }, + { DRDATA (TPS, mux_tps, 8), REG_HRO }, + { NULL } + }; + +MTAB mux_mod[] = { + { MTAB_XTD | MTAB_VDV, 1, NULL, "DISCONNECT", + &tmxr_dscln, NULL, &mux_desc }, + { UNIT_ATT, UNIT_ATT, "summary", NULL, + NULL, &tmxr_show_summ, (void *) &mux_desc }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "CONNECTIONS", NULL, + NULL, &tmxr_show_cstat, (void *) &mux_desc }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "STATISTICS", NULL, + NULL, &tmxr_show_cstat, (void *) &mux_desc }, + { MTAB_XTD|MTAB_VDV, 0, "CHAN", "CHAN", + &io_set_dvc, &io_show_dvc, NULL }, + { MTAB_XTD|MTAB_VDV, 0, "DVA", "DVA", + &io_set_dva, &io_show_dva, NULL }, + { MTAB_XTD | MTAB_VDV, 0, "LINES", "LINES", + &mux_vlines, &tmxr_show_lines, (void *) &mux_desc }, + { MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "CSTATE", NULL, + NULL, &io_show_cst, NULL }, + { MTAB_XTD|MTAB_VDV|MTAB_NMO, RTC_COC, "POLL", "POLL", + &rtc_set_tps, &rtc_show_tps, (void *) &mux_tps }, + { 0 } + }; + +DEVICE mux_dev = { + "MUX", mux_unit, mux_reg, mux_mod, + 2, 10, 31, 1, 16, 8, + &tmxr_ex, &tmxr_dep, &mux_reset, + NULL, &mux_attach, &mux_detach, + &mux_dib, DEV_NET | DEV_DISABLE + }; + +/* MUXL data structures + + muxl_dev MUXL device descriptor + muxl_unit MUXL unit descriptor + muxl_reg MUXL register list + muxl_mod MUXL modifiers list +*/ + +UNIT muxl_unit[] = { + { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT }, + { UDATA (&muxo_svc, TT_MODE_UC|UNIT_DIS, 0), MUXL_WAIT } + }; + +MTAB muxl_mod[] = { + { TT_MODE, TT_MODE_UC, "UC", "UC", NULL }, + { TT_MODE, TT_MODE_7B, "7b", "7B", NULL }, + { TT_MODE, TT_MODE_8B, "8b", "8B", NULL }, + { TT_MODE, TT_MODE_7P, "7p", "7P", NULL }, + { MTAB_XTD|MTAB_VUN, 0, NULL, "DISCONNECT", + &tmxr_dscln, NULL, &mux_desc }, + { MTAB_XTD|MTAB_VUN|MTAB_NC, 0, "LOG", "LOG", + &tmxr_set_log, &tmxr_show_log, &mux_desc }, + { MTAB_XTD|MTAB_VUN|MTAB_NC, 0, NULL, "NOLOG", + &tmxr_set_nolog, NULL, &mux_desc }, + { 0 } + }; + +REG muxl_reg[] = { + { URDATA (TIME, muxl_unit[0].wait, 10, 24, 0, + MUX_LINES, REG_NZ + PV_LEFT) }, + { NULL } + }; + +DEVICE muxl_dev = { + "MUXL", muxl_unit, muxl_reg, muxl_mod, + MUX_LINES, 10, 31, 1, 8, 8, + NULL, NULL, &mux_reset, + NULL, NULL, NULL, + NULL, 0 + }; + +/* MUX: IO dispatch routine */ + +uint32 mux_disp (uint32 op, uint32 dva, uint32 *dvst) +{ +switch (op) { /* case on op */ + + case OP_SIO: /* start I/O */ + *dvst = mux_tio_status (); /* get status */ + if ((*dvst & DVS_CST) == 0) { /* ctrl idle? */ + muxc_cmd = MUXC_INIT; /* start dev thread */ + sim_activate (&mux_unit[MUXC], chan_ctl_time); + } + break; + + case OP_TIO: /* test status */ + *dvst = mux_tio_status (); /* return status */ + break; + + case OP_TDV: /* test status */ + *dvst = 0; /* no status */ + break; + + case OP_HIO: /* halt I/O */ + *dvst = mux_tio_status (); /* get status */ + muxc_cmd = MUXC_IDLE; /* stop dev thread */ + sim_cancel (&mux_unit[MUXC]); + io_sclr_req (mux_rint, 0); /* clr rcv int */ + io_sclr_req (mux_xint, 0); + break; + + case OP_AIO: /* acknowledge int */ + *dvst = 0; /* no status */ + break; + + default: + *dvst = 0; + return SCPE_IERR; + } + +return 0; +} + +/* MUX: DIO dispatch routine */ + +uint32 mux_dio (uint32 op, uint32 rn, uint32 ad) +{ +int32 ln; +uint32 fnc = MUXDIO_GETFNC (ad); +uint32 coc = MUXDIO_GETCOC (ad); + +if (op == OP_RD) { /* read direct */ + if (coc != 0) /* nx COC? */ + return 0; + R[rn] = mux_scan | 0x40; /* return line num */ + mux_sta[mux_scan] &= ~MUXL_XIR; /* clear int req */ + return 0; + } +ln = MUXDAT_GETLIN (R[rn]); /* get line num */ +if (fnc & 0x4) { /* transmit */ + if ((coc != 0) || /* nx COC or */ + (ln >= MUX_NUMLIN)) { /* nx line? */ + CC |= CC4; + return 0; + } + if ((fnc & 0x7) == 0x5) { /* send char? */ + if (fnc & 0x8) /* space? */ + mux_xbuf[ln] = 0; + else mux_xbuf[ln] = MUXDAT_GETCHR (R[rn]); /* no, get char */ + sim_activate (&muxl_unit[ln], muxl_unit[ln].wait); + mux_sta[ln] = (mux_sta[ln] | MUXL_XIA) & ~MUXL_XIR; + mux_scan_next (1); /* unlock scanner */ + } + else if (fnc == 0x06) { /* stop transmit */ + mux_sta[ln] &= ~MUXL_XIA|MUXL_XIR; /* disable int */ + mux_scan_next (1); /* unlock scanner */ + } + else if (fnc == 0x07) { /* disconnect */ + tmxr_reset_ln (&mux_ldsc[ln]); /* reset line */ + mux_reset_ln (ln); /* reset state */ + } + CC = (sim_is_active (&muxl_unit[ln])? 0: CC4) | + (mux_ldsc[ln].conn? CC3: 0); + } +else { /* receive */ + if ((coc != 0) || /* nx COC or */ + (ln >= MUX_NUMLIN)) /* nx line */ + return 0; + if (fnc == 0x01) { /* set rcv enable */ + if (mux_ldsc[ln].conn) /* connected? */ + mux_ldsc[ln].rcve = 1; /* just enable */ + else mux_sta[ln] |= MUXL_REP; /* enable pending */ + } + else if (fnc == 0x02) { /* clr rcv enable */ + mux_ldsc[ln].rcve = 0; + mux_sta[ln] &= ~MUXL_REP; + } + else if (fnc == 0x03) { /* disconnect */ + tmxr_reset_ln (&mux_ldsc[ln]); /* reset line */ + mux_reset_ln (ln); /* reset state */ + } + if (mux_sta[ln] & MUXL_RBP) /* break pending? */ + CC = CC3|CC4; + else CC = mux_ldsc[ln].rcve? CC4: CC3; + } +return 0; +} + +/* Unit service - channel overhead */ + +t_stat muxc_svc (UNIT *uptr) +{ +uint32 st; +uint32 cmd; + +if (muxc_cmd == MUXC_INIT) { /* init state? */ + st = chan_get_cmd (mux_dib.dva, &cmd); /* get command */ + if (CHS_IFERR (st)) /* channel error? */ + mux_chan_err (st); /* go idle */ + else muxc_cmd = MUXC_RCV; /* no, receive */ + } +else if (muxc_cmd == MUXC_END) { /* end state? */ + st = chan_end (mux_dib.dva); /* set channel end */ + if (CHS_IFERR (st)) /* channel error? */ + mux_chan_err (st); /* go idle */ + else if (st == CHS_CCH) { /* command chain? */ + muxc_cmd = MUXC_INIT; /* restart thread */ + sim_activate (uptr, chan_ctl_time); /* schedule soon */ + } + else muxc_cmd = MUXC_IDLE; /* else idle */ + } +return SCPE_OK; +} + +/* Unit service - polled input - called from rtc scheduler + + Poll for new connections + Poll all connected lines for input +*/ + +t_stat muxi_rtc_svc (UNIT *uptr) +{ +t_stat r; +int32 newln, ln, c; + +if ((mux_unit[MUXC].flags & UNIT_ATT) == 0) /* attached? */ + return SCPE_OK; +newln = tmxr_poll_conn (&mux_desc); /* look for connect */ +if ((newln >= 0) && (mux_sta[newln] & MUXL_REP)) { /* rcv enb pending? */ + mux_ldsc[newln].rcve = 1; /* enable rcv */ + mux_sta[newln] &= ~MUXL_REP; /* clr pending */ + } +tmxr_poll_rx (&mux_desc); /* poll for input */ +for (ln = 0; ln < MUX_NUMLIN; ln++) { /* loop thru lines */ + if (mux_ldsc[ln].conn) { /* connected? */ + if (c = tmxr_getc_ln (&mux_ldsc[ln])) { /* get char */ + if (c & SCPE_BREAK) /* break? */ + mux_sta[ln] |= MUXL_RBP; /* set rcv brk */ + else { /* normal char */ + mux_sta[ln] &= ~MUXL_RBP; /* clr rcv brk */ + c = sim_tt_inpcvt (c, TT_GET_MODE (muxl_unit[ln].flags)); + mux_rbuf[ln] = c; /* save char */ + if ((muxc_cmd == MUXC_RCV) && /* chan active? */ + (r = muxi_put_char (c, ln))) /* char to chan */ + return r; + } /* end else char */ + } /* end if char */ + } /* end if conn */ + else mux_sta[ln] &= ~MUXL_RBP; /* disconnected */ + } /* end for */ +return SCPE_OK; +} + +/* Put character and line number in memory via channel */ + +t_stat muxi_put_char (uint32 c, uint32 ln) +{ +uint32 st; + +st = chan_WrMemB (mux_dib.dva, c); /* write char */ +if (CHS_IFERR (st)) /* channel error? */ + return mux_chan_err (st); +st = chan_WrMemB (mux_dib.dva, ln); /* write line */ +if (CHS_IFERR (st)) /* channel error? */ + return mux_chan_err (st); +if (st == CHS_ZBC) { /* bc == 0? */ + muxc_cmd = MUXC_END; /* end state */ + sim_activate (&mux_unit[MUXC], chan_ctl_time); /* quick schedule */ + } +io_sclr_req (mux_rint, 1); /* req ext intr */ +return SCPE_OK; +} + +/* Channel error */ + +t_stat mux_chan_err (uint32 st) +{ +chan_uen (mux_dib.dva); /* uend */ +muxc_cmd = MUXC_IDLE; /* go idle */ +if (st < CHS_ERR) + return st; +return 0; +} + +/* Unit service - transmit side */ + +t_stat muxo_svc (UNIT *uptr) +{ +int32 c; +uint32 ln = uptr - muxl_unit; /* line # */ + +if (mux_ldsc[ln].conn) { /* connected? */ + if (mux_ldsc[ln].xmte) { /* xmt enabled? */ + c = sim_tt_outcvt (mux_xbuf[ln], TT_GET_MODE (muxl_unit[ln].flags)); + if (c >= 0) + tmxr_putc_ln (&mux_ldsc[ln], c); /* output char */ + tmxr_poll_tx (&mux_desc); /* poll xmt */ + if (mux_sta[ln] & MUXL_XIA) { /* armed? */ + mux_sta[ln] |= MUXL_XIR; /* req intr */ + mux_scan_next (0); /* kick scanner */ + } + } + else { /* buf full */ + tmxr_poll_tx (&mux_desc); /* poll xmt */ + sim_activate (uptr, muxl_unit[ln].wait); /* wait */ + return SCPE_OK; + } + } +return SCPE_OK; +} + +/* MUX status routine */ + +uint32 mux_tio_status (void) +{ +if (muxc_cmd == MUXC_IDLE) /* idle? */ + return DVS_AUTO; +else return (DVS_AUTO|DVS_CBUSY|DVS_DBUSY|(CC2 << DVT_V_CC)); +} + +/* Kick scanner */ + +void mux_scan_next (t_bool clr) +{ +int32 i; + +if (clr) /* unlock? */ + mux_slck = 0; +else if (mux_slck) /* locked? */ + return; +for (i = 0; i < MUX_NUMLIN; i++) { /* scan lines */ + mux_scan = mux_scan + 1; /* next line */ + if (mux_scan >= (uint32) MUX_NUMLIN) + mux_scan = 0; + if (mux_sta[mux_scan] & MUXL_XIR) { /* flag set? */ + mux_slck = 1; /* lock scanner */ + io_sclr_req (mux_xint, 1); /* req ext int */ + return; + } + } +return; +} + +/* Reset routine */ + +t_stat mux_reset (DEVICE *dptr) +{ +int32 i; + +if (mux_dev.flags & DEV_DIS) /* master disabled? */ + muxl_dev.flags = muxl_dev.flags | DEV_DIS; /* disable lines */ +else muxl_dev.flags = muxl_dev.flags & ~DEV_DIS; +if (mux_unit[MUXC].flags & UNIT_ATT) /* master att? */ + rtc_register (RTC_COC, mux_tps, &mux_unit[MUXI]); /* register timer */ +else rtc_register (RTC_COC, RTC_HZ_OFF, NULL); /* else dereg */ +for (i = 0; i < MUX_LINES; i++) /* reset lines */ + mux_reset_ln (i); +return SCPE_OK; +} + +/* Attach master unit */ + +t_stat mux_attach (UNIT *uptr, char *cptr) +{ +t_stat r; + +r = tmxr_attach (&mux_desc, uptr, cptr); /* attach */ +if (r != SCPE_OK) /* error */ + return r; +rtc_register (RTC_COC, mux_tps, &mux_unit[MUXC]); /* register timer */ +return SCPE_OK; +} + +/* Detach master unit */ + +t_stat mux_detach (UNIT *uptr) +{ +int32 i; +t_stat r; + +r = tmxr_detach (&mux_desc, uptr); /* detach */ +for (i = 0; i < MUX_LINES; i++) /* disable rcv */ + mux_reset_ln (i); +rtc_register (RTC_COC, RTC_HZ_OFF, NULL); /* dereg */ +return r; +} + + +/* Change number of lines */ + +t_stat mux_vlines (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +int32 newln, i, t; +t_stat r; + +if (cptr == NULL) + return SCPE_ARG; +newln = get_uint (cptr, 10, MUX_LINES, &r); +if ((r != SCPE_OK) || (newln == MUX_NUMLIN)) + return r; +if (newln == 0) return SCPE_ARG; +if (newln < MUX_NUMLIN) { + for (i = newln, t = 0; i < MUX_NUMLIN; i++) t = t | mux_ldsc[i].conn; + if (t && !get_yn ("This will disconnect users; proceed [N]?", FALSE)) + return SCPE_OK; + for (i = newln; i < MUX_NUMLIN; i++) { + if (mux_ldsc[i].conn) { + tmxr_linemsg (&mux_ldsc[i], "\r\nOperator disconnected line\r\n"); + tmxr_reset_ln (&mux_ldsc[i]); /* reset line */ + } + muxl_unit[i].flags = muxl_unit[i].flags | UNIT_DIS; + mux_reset_ln (i); + } + } +else { + for (i = MUX_NUMLIN; i < newln; i++) { + muxl_unit[i].flags = muxl_unit[i].flags & ~UNIT_DIS; + mux_reset_ln (i); + } + } +MUX_NUMLIN = newln; +return SCPE_OK; +} + +/* Reset an individual line */ + +void mux_reset_ln (int32 ln) +{ +sim_cancel (&muxl_unit[ln]); +mux_sta[ln] = 0; +mux_rbuf[ln] = 0; +mux_xbuf[ln] = 0; +mux_ldsc[ln].rcve = 0; +return; +} diff --git a/sigma/sigma_cpu.c b/sigma/sigma_cpu.c new file mode 100644 index 00000000..51fc9c0d --- /dev/null +++ b/sigma/sigma_cpu.c @@ -0,0 +1,2841 @@ +/* sigma_cpu.c: XDS Sigma CPU simulator + + Copyright (c) 2007-2008, Robert M Supnik + + 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 + ROBERT M SUPNIK 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 Robert M Supnik shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + + cpu central processor + + The system state for the Sigma CPU is as follows: + + RF[0:15][0:31]<0:31> register blocks + PSW1<0:31> processor status word 1 + CC<0:3> condition codes + PC<0:17> program counter (called IA in Sigma documentation) + PSW2<0:31> processor status word 2 + PSW2_WLK<0:3> write key (2b on S5-9) + PSW4<0:31> processor status word 4 (5X0 only) + MAP[0:511]<0:10> memory map (8b on S5-8) + WLK[0:2047]<0:3> write locks (256 2b entries on S5-9) + SSW<0:3> sense switches + PDF processor detected fault flag (S8-9, 5X0 only) + + Notes on features not documented in the Reference Manuals: + + 1. Memory mapping was available for the Sigma 5 (see map diagnostic). + 2. The Sigma 6/7 were field retrofitted with the LAS/LMS instructions + (see auto diagnostic). + 3. The Sigma 8/9 returned different results for WD .45 (see Telefile + System exerciser). + 4. Expanded memory beyond 128KB was retrofitted to the Sigma 5/6/7, + creating the so-called "Big 5/6/7." As a minimum, these systems + also included the "mode altered" feature and the 11b relocation map. + + The Sigma CPU has two instruction formats, memory reference and immediate. + The memory reference format is: + + 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 + 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |I| | | | | + |N| opcode | R | X | address | memory + |D| | | | | reference + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + where + + IND = indirect flag + opcode = operation code + R = source/destination register + X = index register (0 if none) + address = operand address + + The immediate format is: + + 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 + 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | | | | + |0| opcode | R | immediate | immediate + | | | | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + This routine is the instruction decode routine for the Sigma CPU. + It is called from the simulator control program to execute + instructions in simulated memory, starting at the simulated PC. + It runs until 'reason' is set non-zero. + + General notes: + + 1. Reasons to stop. The simulator can be stopped by: + + HALT instruction + breakpoint encountered + invalid instruction and stop_op flag set + I/O error in I/O simulator + EXU loop exceeding limit + illegal interrupt or trap instruction + illegal register pointer + illegal vector + + 2. Interrupts. The interrupt structure consists of the following: + Each interrupt is part of a group that determines its priority. + The interrupt group is either controlled by a PSW inhibit or is + unconditional. Interrupts can be armed or disarmed (which controls + whether they are recognized at all) and enabled or disabled (which + controls whether they occur). See the sigma_io.c module for details. + + 3. Channels. The Sigma system has a channel-based I/O structure. Each + channel is represented by a set of registers. Channels test the + I/O transfer requests from devices. + + 4. Non-existent memory. On the Sigma, accesses to non-existent memory + trap. + + 5. Adding I/O devices. These modules must be modified: + + sigma_defs.h add definitions + sigma_io.c add dispatches + sigma_sys.c add pointer to data structures to sim_devices +*/ + +#include "sigma_io_defs.h" + +#define CPUF_V_MODEL (UNIT_V_UF + 6) /* CPU model */ +#define CPUF_M_MODEL 0x7 +#define CPUF_MODEL (CPUF_M_MODEL << CPUF_V_MODEL) +#define CPUF_S5 (CPU_V_S5 << CPUF_V_MODEL) +#define CPUF_S6 (CPU_V_S6 << CPUF_V_MODEL) +#define CPUF_S7 (CPU_V_S7 << CPUF_V_MODEL) +#define CPUF_S8 (CPU_V_S8 << CPUF_V_MODEL) +#define CPUF_S7B (CPU_V_S7B << CPUF_V_MODEL) +#define CPUF_S9 (CPU_V_S9 << CPUF_V_MODEL) +#define CPUF_550 (CPU_V_550 << CPUF_V_MODEL) +#define CPUF_560 (CPU_V_560 << CPUF_V_MODEL) +#define CPUF_GETMOD(x) (((x) >> CPUF_V_MODEL) & CPUF_M_MODEL) + +#define PCQ_SIZE 64 /* must be 2**n */ +#define PCQ_MASK (PCQ_SIZE - 1) +#define PCQ_ENTRY pcq[pcq_p = (pcq_p - 1) & PCQ_MASK] = real_pc; + +#define HIST_MIN 64 +#define HIST_MAX (1u << 20) +#define H_INST 0x00800000 +#define H_CHAN 0x00400000 +#define H_ITRP 0x00200000 +#define H_ABRT 0x00100000 + +typedef struct { + uint32 typ_cc_pc; + uint32 ir; + uint32 rn; + uint32 rn1; + uint32 x; /* unused */ + uint32 ea; + uint32 op; + uint32 op1; + } InstHistory; + +uint32 cpu_model = CPU_V_S7; /* CPU model */ +uint32 *M; /* memory */ +uint32 rf[RF_NBLK * RF_NUM] = { 0 }; /* register files */ +uint32 *R = rf; /* cur reg file */ +uint32 PSW1 = PSW1_DFLT; /* PSD */ +uint32 PSW2 = PSW2_DFLT; +uint32 PSW4 = 0; /* 5X0 only */ +uint32 CC; +uint32 PC; +uint32 PSW2_WLK = 0; /* write lock key */ +uint32 PSW_QRX9; /* Sigma 9 real extended */ +uint32 bvamqrx = BVAMASK; /* BVA mask, 17b/20b */ +uint32 SSW = 0; /* sense switches */ +uint32 cpu_pdf = 0; /* proc detected fault */ +uint32 cons_alarm = 0; /* console alarm */ +uint32 cons_alarm_enb = 0; /* alarm enable */ +uint32 cons_pcf = 0; +uint32 rf_bmax = 4; /* num reg blocks */ +uint32 exu_lim = 32; /* nested EXU limit */ +uint32 stop_op = 0; /* stop on ill op */ +uint32 cpu_astop = 0; /* address stop */ +uint32 pcq[PCQ_SIZE] = { 0 }; /* PC queue */ +int32 pcq_p = 0; /* PC queue ptr */ +REG *pcq_r = NULL; /* PC queue reg ptr */ +int32 hst_p = 0; /* history pointer */ +int32 hst_lnt = 0; /* history length */ +InstHistory *hst = NULL; /* inst history */ + +extern uint32 int_hiact; /* highest act int */ +extern uint32 int_hireq; /* highest int req */ + +t_stat cpu_svc (UNIT *uptr); +t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); +t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw); +t_stat cpu_reset (DEVICE *dptr); +t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat cpu_set_type (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat cpu_set_opt (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat cpu_clr_opt (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat cpu_set_rblks (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat cpu_show_rblks (FILE *st, UNIT *uptr, int32 val, void *desc); +t_stat cpu_set_hist (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc); +t_stat cpu_set_alarm (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat cpu_show_alarm (FILE *st, UNIT *uptr, int32 val, void *desc); +t_stat cpu_show_addr (FILE *st, UNIT *uptr, int32 val, void *desc); +void set_rf_display (uint32 *rfbase); +void inst_hist (uint32 ir, uint32 pc, uint32 typ); +uint32 cpu_one_inst (uint32 real_pc, uint32 IR); +uint32 ImmOp (uint32 ir, uint32 *imm); +uint32 EaP20 (uint32 IR, uint32 *bva, uint32 lnt); +uint32 EaSh (uint32 ir, uint32 *stype, uint32 *sc); +uint32 Add32 (uint32 s1, uint32 s2, uint32 cin); +uint32 SMul64 (uint32 a, uint32 b, uint32 *lo); +t_bool SDiv64 (uint32 dvdh, uint32 dvdl, uint32 dvr, uint32 *res, uint32 *rem); +uint32 Cmp32 (uint32 a, uint32 b); +uint32 Shift (uint32 rn, uint32 stype, uint32 sc); +uint32 TestSP1 (uint32 sp1, int32 mod); +uint32 ModWrSP (uint32 bva, uint32 sp, uint32 sp1, int32 mod); +uint32 cpu_int_mtx (uint32 vec, uint32 *cc); +uint32 cpu_trap_or_int (uint32 vec); +uint32 cpu_xpsd (uint32 ir, uint32 bva, uint32 ra); +uint32 cpu_pss (uint32 ir, uint32 bva, uint32 acc); +uint32 cpu_pls (uint32 IR); +void cpu_assemble_PSD (void); +uint32 cpu_new_PSD (uint32 lrp, uint32 p1, uint32 p2); +uint32 cpu_new_RP (uint32 rp); +uint32 cpu_new_PC (uint32 bva); +uint32 cpu_add_PC (uint32 pc, uint32 val); +t_stat cpu_bad_rblk (UNIT *uptr); +void cpu_fprint_one_inst (FILE *st, uint32 tcp, uint32 ir, uint32 rn, + uint32 rn1, uint32 ea, uint32 op, uint32 op1); + +extern uint32 fp (uint32 op, uint32 rn, uint32 bva); +extern uint32 cis_dec (uint32 op, uint32 rn, uint32 bva); +extern uint32 cis_ebs (uint32 rn, uint32 disp); +extern void ShiftF (uint32 rn, uint32 stype, uint32 sc); +extern uint32 map_mmc (uint32 rn, uint32 map); +extern uint32 map_lra (uint32 rn, uint32 inst); +extern uint32 map_las (uint32 rn, uint32 bva); +extern uint32 map_lms (uint32 rn, uint32 bva); +extern t_stat io_init (void); +extern uint32 io_eval_int (void); +extern uint32 io_actv_int (void); +extern t_bool io_poss_int (void); +extern uint32 io_ackn_int (uint32 hireq); +extern uint32 io_rels_int (uint32 hiact, t_bool arm); +extern uint32 io_rwd (uint32 op, uint32 rn, uint32 bva); +extern uint32 io_sio (uint32 rn, uint32 bva); +extern uint32 io_tio (uint32 rn, uint32 bva); +extern uint32 io_tdv (uint32 rn, uint32 bva); +extern uint32 io_hio (uint32 rn, uint32 bva); +extern uint32 io_aio (uint32 rn, uint32 bva); +extern uint32 int_reset (DEVICE *dev); +extern void io_set_eimax (uint32 lnt); +extern void io_sclr_req (uint32 inum, uint32 val); +extern void io_sclr_arm (uint32 inum, uint32 val); +extern t_stat io_set_nchan (UNIT *uptr, int32 val, char *cptr, void *desc); +extern t_stat io_show_nchan (FILE *st, UNIT *uptr, int32 val, void *desc); + +/* CPU data structures + + cpu_dev CPU device descriptor + cpu_unit CPU unit + cpu_reg CPU register list + cpu_mod CPU modifier list +*/ + +UNIT cpu_unit = { + UDATA (&cpu_svc, UNIT_FIX+CPUF_S7+CPUF_ALLOPT+UNIT_BINK, MAXMEMSIZE), + }; + +UNIT cpu_rblk_unit = { + UDATA (&cpu_bad_rblk, UNIT_DIS, 0) + }; + +REG cpu_reg[] = { + { GRDATA (PC, PSW1, 16, VASIZE, PSW1_V_PC) }, + { HRDATA (R0, rf[0], 32) }, /* addr in memory */ + { HRDATA (R1, rf[1], 32) }, /* modified at exit */ + { HRDATA (R2, rf[2], 32) }, /* to SCP */ + { HRDATA (R3, rf[3], 32) }, + { HRDATA (R4, rf[4], 32) }, + { HRDATA (R5, rf[5], 32) }, + { HRDATA (R6, rf[6], 32) }, + { HRDATA (R7, rf[7], 32) }, + { HRDATA (R8, rf[8], 32) }, + { HRDATA (R9, rf[9], 32) }, + { HRDATA (R10, rf[10], 32) }, + { HRDATA (R11, rf[11], 32) }, + { HRDATA (R12, rf[12], 32) }, + { HRDATA (R13, rf[13], 32) }, + { HRDATA (R14, rf[14], 32) }, + { HRDATA (R15, rf[15], 32) }, + { HRDATA (PSW1, PSW1, 32) }, + { HRDATA (PSW2, PSW2, 32) }, + { HRDATA (PSW4, PSW4, 32) }, + { GRDATA (CC, PSW1, 16, 4, PSW1_V_CC) }, + { GRDATA (RP, PSW2, 16, 4, PSW2_V_RP) }, + { FLDATA (SSW1, SSW, 3) }, + { FLDATA (SSW2, SSW, 2) }, + { FLDATA (SSW3, SSW, 1) }, + { FLDATA (SSW4, SSW, 0) }, + { FLDATA (PDF, cpu_pdf, 0) }, + { FLDATA (ALARM, cons_alarm, 0) }, + { FLDATA (ALENB, cons_alarm_enb, 0), REG_HRO }, + { FLDATA (PCF, cons_pcf, 0) }, + { DRDATA (EXULIM, exu_lim, 8), PV_LEFT + REG_NZ }, + { FLDATA (STOP_ILL, stop_op, 0) }, + { BRDATA (REG, rf, 16, 32, RF_NUM * RF_NBLK) }, + { DRDATA (RBLKS, rf_bmax, 5), REG_HRO }, + { BRDATA (PCQ, pcq, 16, VASIZE, PCQ_SIZE), REG_RO+REG_CIRC }, + { DRDATA (PCQP, pcq_p, 6), REG_HRO }, + { HRDATA (WRU, sim_int_char, 8) }, + { NULL } + }; + +MTAB cpu_mod[] = { + { CPUF_MODEL, CPUF_S5, "Sigma 5", "SIGMA5", &cpu_set_type }, + { CPUF_MODEL, CPUF_S6, "Sigma 6", "SIGMA6", &cpu_set_type }, + { CPUF_MODEL, CPUF_S7, "Sigma 7", "SIGMA7", &cpu_set_type }, +// { CPUF_MODEL, CPUF_S8, "Sigma 8", "SIGMA8", &cpu_set_type }, +// { CPUF_MODEL, CPUF_S9, "Sigma 9", "SIGMA9", &cpu_set_type }, +// { CPUF_MODEL, CPUF_550, "550", "550", &cpu_set_type }, +// { CPUF_MODEL, CPUF_560, "560", "560", &cpu_set_type }, + { MTAB_XTD|MTAB_VDV, 0, "register blocks", "RBLKS", + &cpu_set_rblks, &cpu_show_rblks }, + { MTAB_XTD|MTAB_VDV, 0, "channels", "CHANNELS", + &io_set_nchan, &io_show_nchan }, + { CPUF_FP, CPUF_FP, "floating point", "FP", &cpu_set_opt }, + { CPUF_FP, 0, "no floating point", NULL }, + { MTAB_XTD|MTAB_VDV, CPUF_FP, NULL, "NOFP", &cpu_clr_opt }, + { CPUF_DEC, CPUF_DEC, "decimal", "DECIMAL", &cpu_set_opt }, + { CPUF_DEC, 0, "no decimal", NULL }, + { MTAB_XTD|MTAB_VDV, CPUF_DEC, NULL, "NODECIMAL", &cpu_clr_opt }, + { CPUF_LAMS, CPUF_LAMS, "LAS/LMS", "LASLMS", &cpu_set_opt }, + { CPUF_LAMS, 0, "no LAS/LMS", NULL }, + { MTAB_XTD|MTAB_VDV, CPUF_LAMS, NULL, "NOLASLMS", &cpu_clr_opt }, + { CPUF_MAP, CPUF_MAP, "map", "MAP", &cpu_set_opt }, + { CPUF_MAP, 0, "no map", NULL }, + { MTAB_XTD|MTAB_VDV, CPUF_MAP, NULL, "NOMAP", &cpu_clr_opt }, + { CPUF_WLK, CPUF_WLK, "write lock", "WRITELOCK", &cpu_set_opt }, + { CPUF_WLK, 0, "no write lock", NULL }, + { MTAB_XTD|MTAB_VDV, CPUF_WLK, NULL, "NOWRITELOCK", &cpu_clr_opt }, + { MTAB_XTD|MTAB_VDV|MTAB_NMO, 1, "ALARM", "ALON", &cpu_set_alarm, &cpu_show_alarm }, + { MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, NULL, "ALOFF", & cpu_set_alarm }, + { CPUF_MSIZE, (1u << 15), NULL, "32K", &cpu_set_size }, + { CPUF_MSIZE, (1u << 16), NULL, "64K", &cpu_set_size }, + { CPUF_MSIZE, (1u << 17), NULL, "128K", &cpu_set_size }, + { CPUF_MSIZE, (1u << 18), NULL, "256K", &cpu_set_size }, + { CPUF_MSIZE, (1u << 19), NULL, "512K", &cpu_set_size }, + { CPUF_MSIZE, (1u << 20), NULL, "1M", &cpu_set_size }, + { MTAB_XTD|MTAB_VDV|MTAB_NMO|MTAB_SHP, BY, "BA", NULL, + NULL, &cpu_show_addr }, + { MTAB_XTD|MTAB_VDV|MTAB_NMO|MTAB_SHP, HW, "HA", NULL, + NULL, &cpu_show_addr }, + { MTAB_XTD|MTAB_VDV|MTAB_NMO|MTAB_SHP, WD, "WA", NULL, + NULL, &cpu_show_addr }, + { MTAB_XTD|MTAB_VDV|MTAB_NMO|MTAB_SHP, DW, "DA", NULL, + NULL, &cpu_show_addr }, + { MTAB_XTD|MTAB_VDV|MTAB_NMO|MTAB_SHP, 0, "HISTORY", "HISTORY", + &cpu_set_hist, &cpu_show_hist }, + { 0 } + }; + +DEVICE cpu_dev = { + "CPU", &cpu_unit, cpu_reg, cpu_mod, + 1, 16, 20, 1, 16, 32, + &cpu_ex, &cpu_dep, &cpu_reset, + NULL, NULL, NULL, + }; + +static uint8 anlz_tab[128] = { + 0x9, 0x9, 0x9, 0x9, 0x8, 0x8, 0x8, 0x8, /* 00 - 0F */ + 0xC, 0xC, 0xC, 0xC, 0xC, 0xC, 0xC, 0xC, + 0xC, 0xC, 0xC, 0xC, 0xC, 0xC, 0xC, 0xC, /* 10 - 1F */ + 0xC, 0xC, 0xC, 0xC, 0xC, 0xC, 0xC, 0xC, + 0x9, 0x9, 0x9, 0x9, 0x8, 0x8, 0x8, 0x8, /* 20 - 2F */ + 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, + 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, /* 30 - 3F */ + 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, + 0x1, 0x1, 0x1, 0x1, 0x8, 0x8, 0x8, 0x8, /* 40 - 4F */ + 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, + 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, /* 50 - 5F */ + 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, + 0x1, 0x1, 0x1, 0x1, 0x8, 0x8, 0x8, 0x8, /* 60 - 6F */ + 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, /* 70 - 7F */ + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 + }; + +cpu_var_t cpu_tab[] = { + +/* psw1_mbz psw2_mbz m_map1 pamask eint chan + cc standard optional */ + { 0x080E0000, 0xC8FFFE0F, 0x0FC, PAMASK17, 14, 8, /* S5 */ + CC1|CC2, 0, CPUF_MAP|CPUF_WLK|CPUF_FP }, + { 0x080E0000, 0xC8FFFE0F, 0x0FC, PAMASK17, 14, 8, /* S6 */ + CC1|CC2, CPUF_STR|CPUF_MAP|CPUF_WLK|CPUF_DEC, CPUF_FP|CPUF_LAMS }, + { 0x080E0000, 0xC8FFFE0F, 0x0FC, PAMASK17, 14, 8, /* S7 */ + CC1|CC2, CPUF_STR|CPUF_MAP|CPUF_WLK, CPUF_FP|CPUF_DEC|CPUF_LAMS }, + { 0x084E0000, 0xC8FF00C7, 0x0FC, PAMASK17, 14, 8, /* S8 */ + CC1|CC2|CC3, CPUF_STR|CPUF_FP|CPUF_WLK|CPUF_LAMS, 0 }, + { 0x08060000, 0xC8400007, 0x0FC, PAMASK22, 14, 8, /* S9 */ + CC1|CC2|CC3, CPUF_STR|CPUF_MAP|CPUF_WLK|CPUF_DEC|CPUF_FP|CPUF_LAMS, 0 }, + { 0x002E0000, 0x080FFFC3, 0x7FE, PAMASK20, 4, 4, /* 550 */ + CC1|CC2|CC3|CC4, CPUF_MAP|CPUF_WLK|CPUF_LAMS, CPUF_FP }, + { 0x000E0000, 0x080FFFC3, 0x7FE, PAMASK20, 4, 4, /* 560 */ + CC1|CC2|CC3|CC4, CPUF_STR|CPUF_MAP|CPUF_WLK|CPUF_DEC|CPUF_FP|CPUF_LAMS, 0 } + }; + +/* Simulation loop */ + +t_stat sim_instr (void) +{ +uint32 ir, rpc, old_PC; +t_stat reason, tr, tr2; + +/* Restore register state */ + +if (io_init ()) /* init IO; conflict? */ + return STOP_INVIOC; +reason = 0; +if (cpu_new_PSD (1, PSW1, PSW2)) /* restore PSD, RP etc */ + return STOP_INVPSD; +int_hireq = io_eval_int (); + +/* Main instruction fetch/decode loop */ + +while (reason == 0) { /* loop until stop */ + + PSW2 &= ~PSW2_RA; /* clr reg altered */ + if (cpu_astop) { /* debug stop? */ + cpu_astop = 0; + return STOP_ASTOP; + } + + if (sim_interval <= 0) { /* event queue? */ + if (reason = sim_process_event ()) /* process */ + break; + int_hireq = io_eval_int (); /* re-evaluate intr */ + } + sim_interval = sim_interval - 1; /* count down */ + + if (int_hireq < NO_INT) { /* interrupt req? */ + uint32 sav_hi, vec, wd, op; + + vec = io_ackn_int (sav_hi = int_hireq); /* get vector */ + if (vec == 0) { /* illegal vector? */ + reason = STOP_ILLVEC; /* something wrong */ + break; + } + ReadPW (vec, &wd); /* read vector */ + op = I_GETOP (wd); /* get opcode */ + if ((op == OP_MTB) || (op == OP_MTH) || (op == OP_MTW)) { + uint32 res; + tr2 = cpu_int_mtx (vec, &res); /* do single cycle */ + io_sclr_req (sav_hi, 0); /* clear request */ + io_sclr_arm (sav_hi, 1); /* set armed */ + if ((res == 0) && /* count overflow */ + ((vec >= VEC_C1P) && (vec <= VEC_C4P))) /* on clock? */ + io_sclr_req (INTV (INTG_CTR, vec - VEC_C1P), 1); + int_hiact = io_actv_int (); /* re-eval active */ + int_hireq = io_eval_int (); /* re-eval intr */ + } + else tr2 = cpu_trap_or_int (vec); /* XPSD/PSS intr */ + if (tr2 & TR_FL) { /* trap? */ + if (QCPU_S89_5X0) /* S89 or 5X0? */ + tr2 = cpu_trap_or_int (tr2); /* try again */ + reason = (tr2 == TR_INVTRP)? STOP_ILLTRP: STOP_TRPT; + } + else reason = tr2; /* normal status code */ + } + else { /* normal instruction */ + if (sim_brk_summ && + sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */ + reason = STOP_IBKPT; /* stop simulation */ + break; + } + if (PSW_QRX9 && (PC & PSW1_XA)) /* S9 real ext && ext? */ + rpc = (PSW2 & PSW2_EA) | (PC & ~PSW1_XA); /* 22b phys address */ + else rpc = PC; /* standard 17b PC */ + PC = cpu_add_PC (old_PC = PC, 1); /* increment PC */ + if (((tr = ReadW (rpc << 2, &ir, VI)) != 0) || /* fetch inst, err? */ + ((tr = cpu_one_inst (rpc, ir)) != 0)) { /* exec inst, error? */ + if (tr & TR_FL) { /* trap? */ + PC = old_PC; /* roll back PC */ + tr2 = cpu_trap_or_int (tr); /* do trap */ + if (tr2 & TR_FL) { /* trap? */ + if (QCPU_S89_5X0) /* S89 or 5X0? */ + tr2 = cpu_trap_or_int (tr2); /* try again */ + reason = (tr2 == TR_INVTRP)? STOP_ILLTRP: STOP_TRPT; + } /* end if trap-in-trap */ + else reason = tr2; /* normal status */ + } /* end if trap */ + else reason = tr; /* normal status */ + if ((reason >= STOP_ROLLBACK) && /* roll back PC? */ + (reason <= STOP_MAX)) + PC = old_PC; + } /* end if abnormal status */ + } /* end else normal */ + } /* end while */ + +/* Simulation halted */ + +pcq_r->qptr = pcq_p; /* update pc q ptr */ +cpu_assemble_PSD (); /* visible PSD */ +set_rf_display (R); /* visible registers */ +return reason; +} + +/* Execute one instruction */ + +uint32 cpu_one_inst (uint32 real_pc, uint32 IR) +{ +uint32 op, rn, bva, opnd, opnd1, opnd2, t; +uint32 res, res1, tr, stype, sc, cnt; +uint32 sa, da, mask, c, c1, i, lim, aop, exu_cnt; +int32 sop, sop1; +t_bool mprot; + +exu_cnt = 0; /* init EXU count */ +EXU_LOOP: +if (hst_lnt) /* history? record */ + inst_hist (IR, real_pc, H_INST); +op = I_GETOP (IR); /* get opcode */ +rn = I_GETRN (IR); /* get reg num */ +switch (op) { + +/* Loads and stores */ + + case OP_LI: /* load immediate */ + if ((tr = ImmOp (IR, &opnd)) != 0) /* get immed opnd */ + return tr; + opnd = SEXT_LIT_W (opnd) & WMASK; /* sext to 32b */ + CC34_W (opnd); /* set cc's */ + R[rn] = opnd; /* store result */ + break; + + case OP_LB: /* load byte */ + if ((tr = Ea (IR, &bva, VR, BY)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadB (bva, &opnd, VR)) != 0) /* read byte */ + return tr; + CC34_W (opnd); /* set cc's */ + R[rn] = opnd; /* store result */ + break; + + case OP_LH: /* load halfword */ + if ((tr = Ea (IR, &bva, VR, HW)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadH (bva, &opnd, VR)) != 0) /* read halfword */ + return tr; + opnd = SEXT_H_W (opnd) & WMASK; /* sext to 32b */ + CC34_W (opnd); /* set cc's */ + R[rn] = opnd; /* store result */ + break; + + case OP_LCH: /* load comp hw */ + if ((tr = Ea (IR, &bva, VR, HW)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadH (bva, &opnd, VR)) != 0) /* read halfword */ + return tr; + opnd = SEXT_H_W (opnd); /* sext to 32b */ + opnd = NEG_W (opnd); /* negate */ + CC34_W (opnd); /* set cc's */ + R[rn] = opnd; /* store result */ + break; + + case OP_LAH: /* load abs hw */ + if ((tr = Ea (IR, &bva, VR, HW)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadH (bva, &opnd, VR)) != 0) /* read halfword */ + return tr; + if (opnd & HSIGN) /* negative? */ + opnd = NEG_W (opnd) & HMASK; /* negate */ + CC34_W (opnd); /* set cc's */ + R[rn] = opnd; /* store result */ + break; + + case OP_LW: /* load word */ + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadW (bva, &opnd, VR)) != 0) /* read word */ + return tr; + CC34_W (opnd); /* set cc's */ + R[rn] = opnd; /* store result */ + break; + + case OP_LCW: /* load comp word */ + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadW (bva, &opnd, VR)) != 0) /* read word */ + return tr; + opnd = NEG_W (opnd); /* negate */ + CC34_W (opnd); /* set cc's */ + R[rn] = opnd; /* store result */ + if (opnd == WSIGN) { /* overflow? */ + CC |= CC2; /* set CC2 */ + if (PSW1 & PSW1_AM) /* trap if enabled */ + return TR_FIX; + } + else CC &= ~CC2; /* no, clear CC2 */ + break; + + case OP_LAW: /* load abs word */ + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadW (bva, &opnd, VR)) != 0) /* read word */ + return tr; + if (opnd & WSIGN) /* negative? */ + opnd = NEG_W (opnd); /* take abs value */ + CC34_W (opnd); /* set cc's */ + R[rn] = opnd; /* store result */ + if (opnd == WSIGN) { /* overflow? */ + CC |= CC2; /* set CC2 */ + if (PSW1 & PSW1_AM) /* trap if enabled */ + return TR_FIX; + } + else CC &= ~CC2; /* no, clear CC2 */ + break; + + case OP_LS: /* load selective */ + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadW (bva, &opnd, VR)) != 0) /* read word */ + return tr; + res = (R[rn] & ~R[rn|1]) | (opnd & R[rn|1]); /* load under mask */ + CC34_W (res); /* set cc's */ + R[rn] = res; /* store result */ + break; + + case OP_LAS: /* load and set */ + if ((cpu_unit.flags & CPUF_LAMS) == 0) /* not included? */ + return TR_NXI; + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = map_las (rn, bva)) != 0) /* do instruction */ + return tr; + CC34_W (R[rn]); /* set CC's */ + break; + + case OP_LVAW: /* load virt addr */ + if (!QCPU_5X0) /* 5X0 only */ + return TR_NXI; + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + R[rn] = bva >> 2; /* store */ + break; + + case OP_LD: /* load doubleword */ + if ((tr = Ea (IR, &bva, VR, DW)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadD (bva, &opnd, &opnd1, VR)) != 0) /* read doubleword */ + return tr; + if ((opnd == 0) && (opnd1 != 0)) /* 0'non-zero? */ + CC = (CC & ~CC4) | CC3; /* set CC3 */ + else CC34_W (opnd); /* else hi sets CC */ + R[rn|1] = opnd1; /* store result */ + R[rn] = opnd; + break; + + case OP_LCD: /* load comp double */ + if ((tr = Ea (IR, &bva, VR, DW)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadD (bva, &opnd, &opnd1, VR)) != 0) /* read doubleword */ + return tr; + NEG_D (opnd, opnd1); /* negate */ + if ((opnd == 0) && (opnd1 != 0)) /* 0'non-zero? */ + CC = (CC & ~CC4) | CC3; /* set CC3 */ + else CC34_W (opnd); /* else hi sets CC */ + R[rn|1] = opnd1; /* store result */ + R[rn] = opnd; + if ((opnd == WSIGN) && (opnd1 == 0)) { /* overflow? */ + CC |= CC2; /* set CC2 */ + if (PSW1 & PSW1_AM) /* trap if enabled */ + return TR_FIX; + } + else CC &= ~CC2; /* no, clear CC2 */ + break; + + case OP_LAD: /* load abs double */ + if ((tr = Ea (IR, &bva, VR, DW)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadD (bva, &opnd, &opnd1, VR)) != 0) /* read doubleword */ + return tr; + if (opnd & WSIGN) /* negative? */ + NEG_D (opnd, opnd1); /* take abs value */ + if ((opnd == 0) && (opnd1 != 0)) /* 0'non-zero? */ + CC = (CC & ~CC4) | CC3; /* set CC3 */ + else CC34_W (opnd); /* else hi sets CC */ + R[rn|1] = opnd1; /* store result */ + R[rn] = opnd; + if ((opnd == WSIGN) && (opnd1 == 0)) { /* overflow? */ + CC |= CC2; /* set CC2 */ + if (PSW1 & PSW1_AM) /* trap if enabled */ + return TR_FIX; + } + else CC &= ~CC2; /* no, clear CC2 */ + break; + +/* Note: the Sigma 7 does not prove the instruction can execute successfully + before starting to load registers; the Sigma 9 (and the simulator) do. */ + + case OP_LM: /* load multiple */ + lim = CC? CC: 16; /* CC sets count */ + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadW ((bva + ((lim - 1) << 2)) & bvamqrx, &opnd, VR)) != 0) + return tr; /* test readability */ + for (i = 0; i < lim; i++) { /* loop thru reg */ + if ((tr = ReadW (bva, &opnd, VR)) != 0) /* read next */ + return tr; + R[rn] = opnd; /* store in reg */ + bva = (bva + 4) & bvamqrx; /* next word */ + rn = (rn + 1) & RNMASK; /* next reg */ + PSW2 |= PSW2_RA; /* reg altered */ + } + break; + + case OP_LCFI: /* load cc, flt immed */ + if ((tr = ImmOp (IR, &opnd)) != 0) /* get immed opnd */ + return tr; + if (IR & IRB(10)) /* load CC's? */ + CC = (opnd >> 4) & 0xF; + if (IR & IRB(11)) /* load FP ctrls? */ + PSW1 = ((PSW1 & ~PSW1_FPC) | /* set ctrls */ + ((opnd & PSW1_M_FPC) << PSW1_V_FPC)) & + ~cpu_tab[cpu_model].psw1_mbz; /* clear mbz */ + break; + + case OP_LCF: /* load cc, flt */ + if ((tr = Ea (IR, &bva, VR, BY)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadB (bva, &opnd, VR)) != 0) /* get byte */ + return tr; + if (IR & IRB(10)) /* load CC's? */ + CC = (opnd >> 4) & 0xF; + if (IR & IRB(11)) /* load FP ctrls? */ + PSW1 = ((PSW1 & ~PSW1_FPC) | /* set ctrls */ + ((opnd & PSW1_M_FPC) << PSW1_V_FPC)) & + ~cpu_tab[cpu_model].psw1_mbz; /* clear mbz */ + break; + + case OP_XW: /* exchange word */ + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadW (bva, &opnd, VR)) != 0) /* read word */ + return tr; + if ((tr = WriteW (bva, R[rn], VW)) != 0) /* write reg */ + return tr; + CC34_W (opnd); /* set cc's */ + R[rn] = opnd; /* store result */ + break; + + case OP_STB: /* store byte */ + if ((tr = Ea (IR, &bva, VR, BY)) != 0) /* get eff addr */ + return tr; + if ((tr = WriteB (bva, R[rn], VW)) != 0) /* store */ + return tr; + break; + + case OP_STH: /* store halfword */ + if ((tr = Ea (IR, &bva, VR, HW)) != 0) /* get eff addr */ + return tr; + if ((tr = WriteH (bva, R[rn], VW)) != 0) /* store */ + return tr; + if (R[rn] == (SEXT_H_W (R[rn]) & WMASK)) /* rn a sext hw? */ + CC &= ~CC2; /* yes, clr CC2 */ + else CC |= CC2; + break; + + case OP_STW: /* store word */ + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = WriteW (bva, R[rn], VW)) != 0) /* store */ + return tr; + break; + + case OP_STD: /* store doubleword */ + if ((tr = Ea (IR, &bva, VR, DW)) != 0) /* get eff addr */ + return tr; + if ((tr = WriteD (bva, R[rn], R[rn|1], VW)) != 0) /* store */ + return tr; + break; + + case OP_STS: /* store selective */ + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadW (bva, &opnd, VR)) != 0) /* read word */ + return tr; + res = (opnd & ~R[rn|1]) | (R[rn] & R[rn|1]); /* set under mask */ + if ((tr = WriteW (bva, res, VW)) != 0) /* store */ + return tr; + break; + +/* Note: the Sigma 7 does not prove the instruction can execute successfully + before starting to store registers; the Sigma 9 (and the simulator) do. */ + + case OP_STM: /* store multiple */ + lim = CC? CC: 16; /* CC sets count */ + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadW ((bva + ((lim - 1) << 2)) & bvamqrx, &opnd, VW)) != 0) + return tr; /* test writeability */ + for (i = 0; i < lim; i++) { /* loop thru reg */ + if ((tr = WriteW (bva, R[rn], VW)) != 0) /* write reg */ + return tr; + bva = (bva + 4) & bvamqrx; /* next address */ + rn = (rn + 1) & RNMASK; /* next register */ + } + break; + + case OP_STCF: /* store cc, flt */ + if ((tr = Ea (IR, &bva, VR, BY)) != 0) /* get eff addr */ + return tr; + res = (CC << 4) | ((PSW1 >> PSW1_V_FPC) & PSW1_M_FPC); + if ((tr = WriteB (bva, res, VW)) != 0) /* store */ + return tr; + break; + +/* Analyze: Sigma 9 uses <5:7> for trap codes, the 5X0 uses <1:3> */ + + case OP_ANLZ: /* analyze */ + mprot = ((PSW1 & (PSW1_MS|PSW1_MM)) == PSW1_MM) && + ((PSW2 & (PSW2_MA9|PSW2_MA5X0)) != 0); /* mstr prot */ + sc = QCPU_5X0? 4: 0; /* 5X0 vs S9 */ + if ((tr = Ea (IR, &bva, VR, WD)) != 0) { /* get eff address */ + if (mprot && QCPU_S9) { /* S9 mprot? */ + R[rn] = 0x07000000 | (bva >> 2); /* show failure */ + break; + } + return tr; /* others trap */ + } + if ((tr = ReadW (bva, &opnd, VR)) != 0) { /* get word */ + if (mprot) { /* trap, mprot? */ + R[rn] = (0x30000000 >> sc) | (bva >> 2); /* show failure */ + break; + } + return tr; /* others trap */ + } + aop = I_GETOP (opnd); /* get opcode */ + CC = anlz_tab[aop] & (CC1|CC2|CC4); /* set CC1,CC2,CC4 */ + if (TST_IND (opnd)) /* indirect? */ + CC |= CC3; /* set CC3 */ + if ((anlz_tab[aop] & CC4) == 0) { /* mem ref? */ + uint32 aln = anlz_tab[aop] >> 2; /* get length */ + if ((tr = Ea (opnd, &bva, VR, aln)) != 0) { /* get eff addr */ + if (mprot) { /* trap, mprot? */ + R[rn] = (0x10000000 >> sc) | (bva >> 2); /* show failure */ + break; + } + return tr; /* others trap */ + } + R[rn] = bva >> aln; /* cvt addr */ + } + break; + +/* Interpret */ + + case OP_INT: /* interpret */ + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadW (bva, &opnd, VR)) != 0) /* get word */ + return tr; + CC = (opnd >> 28) & 0xF; /* <0:3> -> CC */ + R[rn] = (opnd >> 16) & 0xFFF; /* <4:15> -> Rn */ + R[rn|1] = opnd & 0xFFFF; /* <16:31> -> Rn|1 */ + break; + +/* Arithmetic */ + + case OP_AI: /* add immediate */ + if ((tr = ImmOp (IR, &opnd)) != 0) /* get immed opnd */ + return tr; + opnd = SEXT_LIT_W (opnd) & WMASK; /* sext to 32b */ + res = Add32 (R[rn], opnd, 0); /* add, set CC's */ + R[rn] = res; /* store result */ + if ((CC & CC2) && (PSW1 & PSW1_AM)) /* ovfo, enabled? */ + return TR_FIX; + break; + + case OP_AH: /* add halfword */ + if ((tr = Ea (IR, &bva, VR, HW)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadH (bva, &opnd, VR)) != 0) /* read halfword */ + return tr; + opnd = SEXT_H_W (opnd) & WMASK; /* sext to 32b */ + res = Add32 (R[rn], opnd, 0); /* add, set CC's */ + R[rn] = res; /* store result */ + if ((CC & CC2) && (PSW1 & PSW1_AM)) /* ovflo, enabled? */ + return TR_FIX; + break; + + case OP_AW: /* add word */ + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadW (bva, &opnd, VR)) != 0) /* read word */ + return tr; + res = Add32 (R[rn], opnd, 0); /* add, set CC's */ + R[rn] = res; /* store result */ + if ((CC & CC2) && (PSW1 & PSW1_AM)) /* ovflo, enabled? */ + return TR_FIX; + break; + + case OP_AD: /* add doubleword */ + if (QCPU_S89_5X0 && (rn & 1)) /* invalid reg? */ + return TR_INVREG; + if ((tr = Ea (IR, &bva, VR, DW)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadD (bva, &opnd, &opnd1, VR)) != 0) /* read doubleword */ + return tr; + res1 = Add32 (R[rn|1], opnd1, 0); /* add low, high */ + res = Add32 (R[rn], opnd, (CC & CC1) != 0); + if ((res == 0) && (res1 != 0)) /* 0'non-zero? */ + CC = (CC & ~CC4) | CC3; /* set CC3 */ + R[rn|1] = res1; /* store */ + R[rn] = res; + if ((CC & CC2) && (PSW1 & PSW1_AM)) /* ovflo, enabled? */ + return TR_FIX; + break; + + case OP_AWM: /* add word to memory */ + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadW (bva, &opnd, VR)) != 0) /* read word */ + return tr; + res = Add32 (R[rn], opnd, 0); /* add, set CC's */ + if ((tr = WriteW (bva, res, VW)) != 0) /* store */ + return tr; + if ((CC & CC2) && (PSW1 & PSW1_AM)) /* ovflo, enabled? */ + return TR_FIX; + break; + + case OP_SH: /* subtract halfword */ + if ((tr = Ea (IR, &bva, VR, HW)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadH (bva, &opnd, VR)) != 0) /* read halfword */ + return tr; + opnd = SEXT_H_W (opnd) & WMASK; /* sext to 32b */ + res = Add32 (R[rn], opnd ^ WMASK, 1); /* subtract, set CC's */ + R[rn] = res; /* store */ + if ((CC & CC2) && (PSW1 & PSW1_AM)) /* ovflo, enabled? */ + return TR_FIX; + break; + + case OP_SW: /* subtract word */ + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadW (bva, &opnd, VR)) != 0) /* read word */ + return tr; + res = Add32 (R[rn], opnd ^ WMASK, 1); /* subtract */ + R[rn] = res; /* store */ + if ((CC & CC2) && (PSW1 & PSW1_AM)) /* ovflo, enabled? */ + return TR_FIX; + break; + + case OP_SD: /* subtract doubleword */ + if (QCPU_S89_5X0 && (rn & 1)) /* invalid reg? */ + return TR_INVREG; + if ((tr = Ea (IR, &bva, VR, DW)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadD (bva, &opnd, &opnd1, VR)) != 0) /* read doubleword */ + return tr; + res1 = Add32 (R[rn|1], opnd1 ^ WMASK, 1); /* sub low, high */ + res = Add32 (R[rn], opnd ^ WMASK, (CC & CC1) != 0); + if ((res == 0) && (res1 != 0)) /* 0'non-zero? */ + CC = (CC & ~CC4) | CC3; /* set CC3 */ + R[rn|1] = res1; /* store */ + R[rn] = res; + if ((CC & CC2) && (PSW1 & PSW1_AM)) /* ovflo, enabled? */ + return TR_FIX; + break; + + case OP_MI: /* multiply immed */ + if ((tr = ImmOp (IR, &opnd)) != 0) /* get immed opnd */ + return tr; + opnd = SEXT_LIT_W (opnd) & WMASK; /* sext to 32b */ + res = SMul64 (R[rn|1], opnd, &res1); /* 64b product */ + R[rn] = res; /* store */ + R[rn|1] = res1; + break; + + case OP_MH: /* multiply half */ + if ((tr = Ea (IR, &bva, VR, HW)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadH (bva, &opnd, VR)) != 0) /* read halfword */ + return tr; + sop = (int32) SEXT_H_W (R[rn]); /* sext operands */ + sop1 = (int32) SEXT_H_W (opnd); + res = (uint32) ((sop * sop1) & WMASK); /* product */ + CC34_W (res); /* set CC's */ + R[rn|1] = res; /* store */ + break; + + case OP_MW: /* multiply word */ + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadW (bva, &opnd, VR)) != 0) /* read word */ + return tr; + res = SMul64 (R[rn|1], opnd, &res1); /* 64b product */ + R[rn] = res; /* store */ + R[rn|1] = res1; + break; + + case OP_DH: /* divide halfword */ + if ((tr = Ea (IR, &bva, VR, HW)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadH (bva, &opnd, VR)) != 0) /* read halfword */ + return tr; + sop = (int32) R[rn]; /* sext operands */ + sop1 = (int32) SEXT_H_W (opnd); + if ((opnd == 0) || /* div by zero? */ + ((R[rn] == WSIGN) && /* -2^31 / -1? */ + (opnd == HMASK))) { + CC |= CC2; /* overflow */ + if (PSW1 & PSW1_AM) /* trap if enabled */ + return TR_FIX; + } + else { + res = (uint32) ((sop / sop1) & WMASK); /* quotient */ + CC &= ~CC2; /* no overflow */ + CC34_W (res); /* set CC's */ + R[rn] = res; /* store */ + } + break; + + case OP_DW: /* divide word */ + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadW (bva, &opnd2, VR)) != 0) /* get divisor */ + return tr; + if (rn & 1) /* odd reg? */ + opnd = (R[rn] & WSIGN)? WMASK: 0; /* high is sext low */ + else opnd = R[rn]; + opnd1 = R[rn|1]; /* low divd */ + if (SDiv64 (opnd, opnd1, opnd2, &res, &res1)) { /* 64b/32b divide */ + CC |= CC2; /* overflow, set CC2 */ + if (PSW1 & PSW1_AM) /* trap if enabled */ + return TR_FIX; + } + else { + CC &= ~CC2; /* clear CC2 */ + CC34_W (res); /* set CC's from quo */ + R[rn] = res1; /* store */ + R[rn|1] = res; + } + break; + + case OP_MTB: /* mod and test byte */ + if ((tr = Ea (IR, &bva, VR, BY)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadB (bva, &opnd, VR)) != 0) /* read byte */ + return tr; + opnd1 = SEXT_RN_W (rn) & BMASK; /* mod is sext rn */ + res = (opnd + opnd1) & BMASK; /* do zext add */ + if (res < opnd) /* carry out? */ + CC = CC1; + else CC = 0; + CC34_W (res); /* set cc's */ + if (rn && /* any mod? */ + ((tr = WriteB (bva, res, VW)) != 0)) /* rewrite */ + return tr; + break; + + case OP_MTH: /* mod and test half */ + if ((tr = Ea (IR, &bva, VR, HW)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadH (bva, &opnd, VR)) != 0) /* read halfword */ + return tr; + opnd = opnd & HMASK; /* 16 operands */ + opnd1 = SEXT_RN_W (rn) & HMASK; /* mod is sext rn */ + res = opnd + opnd1; /* 16b add */ + if ((res & HMASK) == 0) /* 16b CC tests */ + CC = 0; + else if (res & HSIGN) + CC = CC4; + else CC = CC3; + if ((res & ~HMASK) != 0) /* carry? */ + CC |= CC1; + if (((opnd ^ ~opnd1) & (opnd ^ res)) & HSIGN) /* set overflow */ + CC |= CC2; + if (rn && /* any mod? */ + ((tr = WriteH (bva, res, VW)) != 0)) /* rewrite */ + return tr; + if ((CC & CC2) && (PSW1 & PSW1_AM)) /* ovflo, enabled? */ + return TR_FIX; + break; + + case OP_MTW: /* mod and test word */ + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadW (bva, &opnd, VR)) != 0) /* get word */ + return tr; + opnd1 = SEXT_RN_W (rn) & WMASK; /* mod is sext rn */ + res = Add32 (opnd, opnd1, 0); /* do add */ + if (rn && /* any mod? */ + ((tr = WriteW (bva, res, VW)) != 0)) /* rewrite */ + return tr; + if ((CC & CC2) && (PSW1 & PSW1_AM)) /* ovflo, enabled? */ + return TR_FIX; + break; + +/* Logical */ + + case OP_AND: /* and */ + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadW (bva, &opnd, VR)) != 0) /* get word */ + return tr; + res = R[rn] & opnd; + CC34_W (res); /* set CC's */ + R[rn] = res; /* store */ + break; + + case OP_OR: /* or */ + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadW (bva, &opnd, VR)) != 0) /* get word */ + return tr; + res = R[rn] | opnd; + CC34_W (res); /* set CC's */ + R[rn] = res; /* store */ + break; + + case OP_EOR: /* xor */ + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadW (bva, &opnd, VR)) != 0) /* get word */ + return tr; + res = R[rn] ^ opnd; + CC34_W (res); /* set CC's */ + R[rn] = res; /* store */ + break; + +/* Compares */ + + case OP_CI: /* compare immed */ + if ((tr = ImmOp (IR, &opnd)) != 0) /* get immed opnd */ + return tr; + opnd = SEXT_LIT_W (opnd) & WMASK; /* sext to 32b */ + CC234_CMP (R[rn], opnd); /* set CC's */ + break; + + case OP_CB: /* compare byte */ + if ((tr = Ea (IR, &bva, VR, BY)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadB (bva, &opnd, VR)) != 0) /* read byte */ + return tr; + opnd1 = R[rn] & BMASK; /* zext operand */ + CC234_CMP (opnd1, opnd); /* set CC's */ + break; + + case OP_CH: /* compare halfword */ + if ((tr = Ea (IR, &bva, VR, HW)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadH (bva, &opnd, VR)) != 0) /* read halfword */ + return tr; + opnd = SEXT_H_W (opnd) & WMASK; /* sext to 32b */ + CC234_CMP (R[rn], opnd); /* set CC's */ + break; + + case OP_CW: /* compare word */ + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadW (bva, &opnd, VR)) != 0) /* read word */ + return tr; + CC234_CMP (R[rn], opnd); /* set CC's */ + break; + + case OP_CD: /* compare double */ + if ((tr = Ea (IR, &bva, VR, DW)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadD (bva, &opnd, &opnd1, VR)) != 0) /* read doubleword */ + return tr; + CC &= ~(CC3|CC4); + if (R[rn] != opnd) /* hi unequal? */ + CC |= Cmp32 (R[rn], opnd); + else if (R[rn|1] != opnd1) /* low unequal? */ + CC |= (R[rn|1] < opnd1)? CC4: CC3; /* like signs */ + break; + + case OP_CS: /* compare select */ + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadW (bva, &opnd, VR)) != 0) /* read word */ + return tr; + opnd1 = R[rn] & R[rn|1]; /* mask operands */ + opnd = opnd & R[rn|1]; + if (opnd1 < opnd) /* unsigned compare */ + CC = (CC & ~CC3) | CC4; + else if (opnd1 > opnd) + CC = (CC & ~CC4) | CC3; + else CC &= ~(CC3|CC4); + break; + + case OP_CLR: /* compare limit reg */ + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadW (bva, &opnd, VR)) != 0) /* read word */ + return tr; + CC = Cmp32 (R[rn], opnd) | /* compare high reg */ + (Cmp32 (R[rn|1], opnd) << 2); /* compare low reg */ + break; + + case OP_CLM: /* compare limit mem */ + if ((tr = Ea (IR, &bva, VR, DW)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadD (bva, &opnd, &opnd1, VR)) != 0) /* get doubleword */ + return tr; + CC = Cmp32 (R[rn], opnd) | /* compare high mem */ + (Cmp32 (R[rn], opnd1) << 2); /* compare low mem */ + break; + +/* Shift and convert instructions */ + + case OP_S: /* shift */ + if ((tr = EaSh (IR, &stype, &sc)) != 0) /* get type, count */ + return tr; + if ((stype >= 0x6) && QCPU_S567) /* invalid, S5-7? */ + stype = 0x4; /* treat as arith */ + CC = (CC & ~(CC1|CC2|CC4)) | /* shift, set CC's */ + Shift (rn, stype, sc); + break; + + case OP_SF: /* shift floating */ + if ((tr = EaSh (IR, &stype, &sc)) != 0) /* get type, count */ + return tr; + ShiftF (rn, stype & 1, sc); /* shift, set CC's */ + break; + + case OP_CVA: /* cvt by addition */ + if (QCPU_S5) /* not on Sigma 5 */ + return TR_NXI; + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + CC &= ~CC1; /* clear CC1 (carry) */ + for (i = 0, res = 0; i < 32; i++) { /* 32 iterations */ + if ((R[rn|1] >> (31 - i)) & 1) { /* bit set? */ + uint32 ad = (bva + (i << 2)) & bvamqrx; /* table offset */ + if ((tr = ReadW (ad, &opnd, VR)) != 0) + return tr; /* read table word */ + res = (res + opnd) & WMASK; /* add into result */ + if (res < opnd) /* carry? set CC1 */ + CC |= CC1; + } /* end bit set */ + } /* end for */ + CC34_W (res); /* set CC's */ + R[rn] = res; /* store */ + break; + + case OP_CVS: /* cvt by subtraction */ + if (QCPU_S5) /* not on Sigma 5 */ + return TR_NXI; + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + for (i = 0, res = R[rn], res1 = 0; i < 32; i++) { /* 32 iterations */ + uint32 ad = (bva + (i << 2)) & bvamqrx; /* table offset */ + if ((tr = ReadW (ad, &opnd, VR)) != 0) /* read table word */ + return tr; + if (opnd <= res) { /* residue >= entry? */ + res = (res - opnd) & WMASK; /* subtract entry */ + res1 |= 1u << (31 - i); /* set bit */ + } + } + CC34_W (res1); /* set CC's */ + R[rn] = res; /* store */ + R[rn|1] = res1; + break; + +/* Push down instructions */ + + case OP_PSW: /* push word */ + if ((tr = Ea (IR, &bva, VR, DW)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadD (bva, &opnd, &opnd1, VW)) != 0) /* read stack ptr */ + return tr; + if ((tr = TestSP1 (opnd1, 1)) != 0) /* will push work? */ + return ((tr & WSIGN)? 0: tr); + if ((tr = WriteW (((opnd + 1) << 2) & bvamqrx, R[rn], VW)) != 0) + return tr; /* push word */ + if ((tr = ModWrSP (bva, opnd, opnd1, 1)) != 0) /* mod, rewrite sp */ + return tr; + break; + + case OP_PLW: /* pull word */ + if ((tr = Ea (IR, &bva, VR, DW)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadD (bva, &opnd, &opnd1, VW)) != 0) /* read stack ptr */ + return tr; + if ((tr = TestSP1 (opnd1, -1)) != 0) /* will pull work? */ + return ((tr & WSIGN)? 0: tr); + if ((tr = ReadW (opnd << 2, &res, VR)) != 0) /* pull word */ + return tr; + if ((tr = ModWrSP (bva, opnd, opnd1, -1)) != 0) /* mod, rewrite sp */ + return tr; + R[rn] = res; + break; + + case OP_PSM: /* push multiple */ + if ((tr = Ea (IR, &bva, VR, DW)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadD (bva, &opnd, &opnd1, VW)) != 0) /* read stack ptr */ + return tr; + lim = CC? CC: 16; /* words to push */ + if ((tr = TestSP1 (opnd1, lim)) != 0) /* will push work? */ + return ((tr & WSIGN)? 0: tr); + if ((tr = ReadW (((opnd + lim) << 2) & bvamqrx, &res, VW)) != 0) + return tr; /* will last work? */ + for (i = 0; i < lim; i++) { /* loop thru reg */ + if ((tr = WriteW (((opnd + i + 1) << 2) & bvamqrx, R[rn], VW)) != 0) + return tr; /* push word */ + rn = (rn + 1) & RNMASK; + } + if ((tr = ModWrSP (bva, opnd, opnd1, lim)) != 0) /* mod, rewrite sp */ + return tr; + break; + + case OP_PLM: /* pull multiple */ + if ((tr = Ea (IR, &bva, VR, DW)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadD (bva, &opnd, &opnd1, VW)) != 0) /* read stack ptr */ + return tr; + lim = CC? CC: 16; /* words to pull */ + if ((tr = TestSP1 (opnd1, -((int32)lim))) != 0) /* will pull work? */ + return ((tr & WSIGN)? 0: tr); + rn = (rn + lim - 1) & RNMASK; + if ((tr = ReadW (((opnd - (lim - 1)) << 2) & bvamqrx, &res, VR)) != 0) + return tr; /* will last work? */ + for (i = 0; i < lim; i++) { /* loop thru reg */ + if ((tr = ReadW (((opnd - i) << 2) & bvamqrx, &res, VR)) != 0) + return tr; /* pull word */ + R[rn] = res; + rn = (rn - 1) & RNMASK; + } + if ((tr = ModWrSP (bva, opnd, opnd1, -((int32) lim))) != 0) + return tr; + break; + + case OP_MSP: /* modify stack ptr */ + if ((tr = Ea (IR, &bva, VR, DW)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadD (bva, &opnd, &opnd1, VW)) != 0) /* read stack ptr */ + return tr; + sop = SEXT_H_W (R[rn]); /* get modifier */ + if ((tr = TestSP1 (opnd1, sop)) != 0) /* will mod work? */ + return ((tr & WSIGN)? 0: tr); + if ((tr = ModWrSP (bva, opnd, opnd1, sop)) != 0) /* mod, rewrite sp */ + return tr; + break; + +/* Control instructions */ + + case OP_EXU: /* execute */ + if (exu_cnt++ > exu_lim) /* too many? */ + return STOP_EXULIM; + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadW (bva, &opnd, VR)) != 0) /* read word */ + return tr; + IR = opnd; /* new instruction */ + goto EXU_LOOP; + + case OP_BCS: /* branch cond set */ + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((CC & rn) != 0) { /* branch taken? */ + if ((tr = ReadW (bva, &opnd, VI)) != 0) /* new PC readable? */ + return tr; + PCQ_ENTRY; + PC = cpu_new_PC (bva); /* branch */ + } + break; + + case OP_BCR: /* branch cond reset */ + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((CC & rn) == 0) { /* branch taken? */ + if ((tr = ReadW (bva, &opnd, VI)) != 0) /* new PC readable? */ + return tr; + PCQ_ENTRY; + PC = cpu_new_PC (bva); /* branch */ + } + break; + + case OP_BIR: /* branch incr reg */ + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + res = (R[rn] + 1) & WMASK; /* ++R[rn] */ + if ((res & WSIGN) != 0) { /* < 0? */ + if ((tr = ReadW (bva, &opnd, VI)) != 0) /* new PC readable? */ + return tr; + PCQ_ENTRY; + PC = cpu_new_PC (bva); /* branch */ + } + R[rn] = res; /* actual increment */ + break; + + case OP_BDR: /* branch decr reg */ + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + res = (R[rn] - 1) & WMASK; /* --R[rn] */ + if (((res & WSIGN) == 0) && (res != 0)) { /* > 0? */ + if ((tr = ReadW (bva, &opnd, VI)) != 0) /* new PC readable? */ + return tr; + PCQ_ENTRY; + PC = cpu_new_PC (bva); /* branch */ + } + R[rn] = res; /* actual decrement */ + break; + + case OP_BAL: /* branch and link */ + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadW (bva, &opnd, VI)) != 0) /* new PC readable? */ + return tr; + R[rn] = cpu_add_PC (real_pc, 1); /* save incr PC */ + PCQ_ENTRY; + PC = cpu_new_PC (bva); /* branch */ + break; + + case OP_CAL1: /* CALL 1 */ + return TR_C1 (rn); + + case OP_CAL2: /* CALL 2 */ + return TR_C2 (rn); + + case OP_CAL3: /* CALL 3 */ + return TR_C3 (rn); + + case OP_CAL4: /* CALL 4 */ + return TR_C4 (rn); + +/* Privileged instructions */ + + case OP_MMC: /* MMC */ + if (PSW1 & PSW1_MS) /* slave mode? */ + return TR_PRV; + if (TST_IND (IR) && /* indirect? */ + ((tr = ReadW (I_GETADDR (IR) << 2, &opnd, VNT)) != 0)) + return tr; + return map_mmc (rn, I_GETXR (IR)); + + case OP_LPSD: /* load PSD */ + if (PSW1 & PSW1_MS) /* slave mode? */ + return TR_PRV; + if ((tr = Ea (IR, &bva, VR, DW)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadD (bva, &opnd, &opnd1, VR)) != 0) /* read stack ptr */ + return tr; + if ((tr = cpu_new_PSD (IR & IRB (8), opnd, opnd1)) != 0) + return tr; + PCQ_ENTRY; /* no traps, upd PCQ */ + if (IR & IRB (10)) /* clr hi pri int? */ + int_hireq = io_rels_int (int_hiact, IR & IRB (11)); + else if (IR & IRB (11)) /* clr PDF flag? */ + cpu_pdf = 0; + break; + + case OP_XPSD: /* exchange PSD */ + if (PSW1 & PSW1_MS) /* slave mode? */ + return TR_PRV; + if ((tr = Ea (IR, &bva, VR, DW)) != 0) /* get eff addr */ + return tr; + if ((tr = cpu_xpsd (IR & ~IRB (11), bva, VR)) != 0) /* do XPSD */ + return tr; + PCQ_ENTRY; /* no traps, upd PCQ */ + break; + + case OP_LRP: + if (PSW1 & PSW1_MS) /* slave mode? */ + return TR_PRV; + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = ReadW (bva, &opnd, VR)) != 0) /* read word */ + return tr; + return cpu_new_RP (opnd); /* update RP */ + + case OP_RD: /* direct I/O */ + case OP_WD: + if (PSW1 & PSW1_MS) /* slave mode? */ + return TR_PRV; + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = io_rwd (op, rn, bva)) != 0) /* do direct I/O */ + return tr; + int_hiact = io_actv_int (); /* re-eval active */ + int_hireq = io_eval_int (); /* re-eval intr */ + break; + + case OP_WAIT: /* wait for int */ + if (PSW1 & PSW1_MS) /* slave mode? */ + return TR_PRV; + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if (!io_poss_int ()) /* intr possible? */ + return STOP_WAITNOINT; /* machine is hung */ +// put idle here + int_hireq = io_eval_int (); /* re-eval intr */ + break; + + case OP_AIO: /* acknowledge int */ + if (PSW1 & PSW1_MS) /* slave mode? */ + return TR_PRV; + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = io_aio (rn, bva)) != 0) /* do AIO */ + return tr; + int_hireq = io_eval_int (); /* re-eval intr */ + break; + + case OP_SIO: /* start IO */ + if (PSW1 & PSW1_MS) /* slave mode? */ + return TR_PRV; + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = io_sio (rn, bva)) != 0) /* do SIO */ + return tr; + int_hireq = io_eval_int (); /* re-eval intr */ + break; + + case OP_HIO: /* halt IO */ + if (PSW1 & PSW1_MS) /* slave mode? */ + return TR_PRV; + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = io_hio (rn, bva)) != 0) /* do HIO */ + return tr; + int_hireq = io_eval_int (); /* re-eval intr */ + break; + + case OP_TIO: /* test IO */ + if (PSW1 & PSW1_MS) /* slave mode? */ + return TR_PRV; + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = io_tio (rn, bva)) != 0) /* do AIO */ + return tr; + int_hireq = io_eval_int (); /* re-eval intr */ + break; + + case OP_TDV: /* test device */ + if (PSW1 & PSW1_MS) /* slave mode? */ + return TR_PRV; + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if ((tr = io_tdv (rn, bva)) != 0) /* do I/O */ + return tr; + int_hireq = io_eval_int (); /* re-eval intr */ + break; + + case OP_LRA: /* load real addr */ + if (QCPU_S89_5X0) { /* late models only */ + if (PSW1 & PSW1_MS) /* slave mode? */ + return TR_PRV; + return map_lra (rn, IR); /* in map */ + } + return (PSW1 & PSW1_MS)? TR_NXI|TR_PRV: TR_NXI; + + case OP_LMS: /* load mem system */ + if ((cpu_unit.flags & CPUF_LAMS) == 0) /* implemented? */ + return (PSW1 & PSW1_MS)? TR_NXI|TR_PRV: TR_NXI; + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + if (QCPU_S567) /* old CPU? */ + R[rn] = IR; /* loads inst to IR */ + else if (PSW1 & PSW1_MS) /* slave mode? */ + return TR_PRV; + else return map_lms (rn, bva); /* in map */ + break; + + case OP_PSS: /* push status */ + if (QCPU_5X0) { /* 5X0 only */ + if (PSW1 & PSW1_MS) /* slave mode? */ + return TR_PRV; + if ((tr = Ea (IR, &bva, VR, DW)) != 0) /* get eff addr */ + return tr; + if ((tr = cpu_pss (IR, bva, VR)) != 0) /* push status */ + return tr; + PCQ_ENTRY; + break; + } + return (PSW1 & PSW1_MS)? TR_NXI|TR_PRV: TR_NXI; + + case OP_PLS: /* pull status */ + if (QCPU_5X0) { /* 5X0 only */ + if (PSW1 & PSW1_MS) /* slave mode? */ + return TR_PRV; + if ((tr = cpu_pls (IR)) != 0) /* pull status */ + return tr; + PCQ_ENTRY; + break; + } + return (PSW1 & PSW1_MS)? TR_NXI|TR_PRV: TR_NXI; + +/* String instructions */ + + case OP_MBS: /* move byte string */ + if ((cpu_unit.flags & CPUF_STR) == 0) /* not implemented? */ + return TR_UNI; + if ((tr = ImmOp (IR, &opnd)) != 0) /* get immed opnd */ + return tr; + opnd = SEXT_LIT_W (opnd) & WMASK; /* sign extend */ + if ((cnt = S_GETMCNT (R[rn|1])) != 0) { /* any move? */ + sa = (opnd + (rn? R[rn] + cnt - 1: 0)) & bvamqrx; /* last src addr */ + da = (R[rn|1] + cnt - 1) & bvamqrx; /* last dst addr */ + if (((tr = ReadB (sa, &c, VR)) != 0) || /* test last bytes */ + ((tr = ReadB (da, &c, VW)) != 0)) + return tr; + } + while (S_GETMCNT (R[rn|1])) { /* while count */ + sa = (opnd + (rn? R[rn]: 0)) & bvamqrx; /* src addr */ + da = R[rn|1] & bvamqrx; /* dst addr */ + if ((tr = ReadB (sa, &c, VR)) != 0) /* read src */ + return tr; + if ((tr = WriteB (da, c, VW)) != 0) /* write dst */ + return tr; + if (rn && !(rn & 1)) /* rn even, > 0? */ + R[rn] = (R[rn] + 1) & WMASK; /* inc saddr */ + R[rn|1] = (R[rn|1] + S_ADDRINC) & WMASK; /* inc daddr, dec cnt */ + } + break; + + case OP_CBS: /* compare byte str */ + if ((cpu_unit.flags & CPUF_STR) == 0) /* not implemented? */ + return TR_UNI; + if ((tr = ImmOp (IR, &opnd)) != 0) /* get immed opnd */ + return tr; + opnd = SEXT_LIT_W (opnd) & WMASK; /* sign extend */ + if ((cnt = S_GETMCNT (R[rn|1])) != 0) { /* any compare? */ + sa = (opnd + (rn? R[rn] + cnt - 1: 0)) & bvamqrx; /* last src addr */ + da = (R[rn|1] + cnt - 1) & bvamqrx; /* last dst addr */ + if (((tr = ReadB (sa, &c, VR)) != 0) || /* test last bytes */ + ((tr = ReadB (da, &c, VR)) != 0)) + return tr; + } + CC = CC & ~(CC3|CC4); /* assume equal */ + while (S_GETMCNT (R[rn|1])) { /* while count */ + sa = (opnd + (rn? R[rn]: 0)) & bvamqrx; /* src addr */ + da = R[rn|1] & bvamqrx; /* dst addr */ + if ((tr = ReadB (sa, &c, VR)) != 0) /* read src */ + return tr; + if ((tr = ReadB (da, &c1, VR)) != 0) /* read dst */ + return tr; + if (c != c1) { /* not a match */ + CC |= ((c < c1)? CC4: CC3); + break; /* set CC's, done */ + } + if (rn && !(rn & 1)) /* rn even, > 0? */ + R[rn] = (R[rn] + 1) & WMASK; /* inc saddr */ + R[rn|1] = (R[rn|1] + S_ADDRINC) & WMASK; /* inc daddr, dec cnt */ + } + break; + + case OP_TBS: /* xlate byte string */ + if ((cpu_unit.flags & CPUF_STR) == 0) /* not implemented? */ + return TR_UNI; + if (QCPU_S89_5X0 && (rn & 1)) /* invalid reg? */ + return TR_INVREG; + if ((tr = ImmOp (IR, &opnd)) != 0) /* get immed opnd */ + return tr; + opnd = SEXT_LIT_W (opnd) & WMASK; /* sign extend */ + if ((cnt = S_GETMCNT (R[rn|1])) != 0) { /* any translate? */ + da = (R[rn] + cnt - 1) & bvamqrx; /* last dst addr */ + if ((tr = ReadB (da, &c, VW)) != 0) /* test last byte */ + return tr; + } + while (S_GETMCNT (R[rn|1])) { /* while count */ + sa = (opnd + (rn? R[rn]: 0)) & bvamqrx; /* src addr */ + da = R[rn|1] & bvamqrx; /* dst addr */ + if ((tr = ReadB (da, &c, VR)) != 0) /* read dst */ + return tr; + if ((tr = ReadB ((sa + c) & bvamqrx, &c1, VR)) != 0) + return tr; /* translate byte */ + if ((tr = WriteB (da, c1, VW)) != 0) /* write dst */ + return tr; + R[rn|1] = (R[rn|1] + S_ADDRINC) & WMASK; /* inc daddr, dec cnt */ + } + break; + + case OP_TTBS: /* xlate, test string */ + if ((cpu_unit.flags & CPUF_STR) == 0) /* not implemented? */ + return TR_UNI; + if (QCPU_S89_5X0 && (rn & 1)) /* invalid reg? */ + return TR_INVREG; + if ((tr = ImmOp (IR, &opnd)) != 0) /* get immed opnd */ + return tr; + opnd = SEXT_LIT_W (opnd) & WMASK; /* sign extend */ + mask = rn? S_GETMCNT (R[rn]): 0xFF; /* get mask */ + if ((cnt = S_GETMCNT (R[rn|1])) != 0) { /* any translate? */ + da = (R[rn] + cnt - 1) & bvamqrx; /* last dst addr */ + if ((tr = ReadB (da, &c, VR)) != 0) /* test last byte */ + return tr; + } + CC &= ~CC4; /* clear CC4 */ + while (S_GETMCNT (R[rn|1])) { /* while count */ + sa = (opnd + (rn? R[rn]: 0)) & bvamqrx; /* src addr */ + da = R[rn|1] & bvamqrx; /* dst addr */ + if ((tr = ReadB (da, &c, VR)) != 0) /* read dst */ + return tr; + if ((tr = ReadB ((sa + c) & bvamqrx, &c1, VR)) != 0) + return tr; /* translate byte */ + if ((t = c1 & mask) != 0) { /* byte & mask != 0? */ + if (rn) /* if !r0, repl mask */ + R[rn] = (R[rn] & ~S_MCNT) | (t << S_V_MCNT); + CC |= CC4; /* set CC4, stop */ + break; + } + R[rn|1] = (R[rn|1] + S_ADDRINC) & WMASK; /* inc daddr, dec cnt */ + } + break; + +/* Optional floating point instructions */ + + case OP_FAS: + case OP_FSS: + case OP_FMS: + case OP_FDS: /* short fp */ + if((cpu_unit.flags & CPUF_FP) == 0) /* option present? */ + return TR_UNI; + if ((tr = Ea (IR, &bva, VR, WD)) != 0) /* get eff addr */ + return tr; + return fp (op, rn, bva); /* go process */ + + case OP_FAL: + case OP_FSL: + case OP_FML: + case OP_FDL: /* long fp */ + if (QCPU_S89_5X0 && (rn & 1)) /* invalid reg? */ + return TR_INVREG; + if((cpu_unit.flags & CPUF_FP) == 0) /* option present? */ + return TR_UNI; + if ((tr = Ea (IR, &bva, VR, DW)) != 0) /* get eff addr */ + return tr; + return fp (op, rn, bva); /* go process */ + +/* Optional decimal instructions */ + + case OP_DL: + case OP_DST: + case OP_DA: + case OP_DS: + case OP_DM: + case OP_DD: + case OP_DC: + case OP_DSA: + case OP_PACK: + case OP_UNPK: /* decimal */ + if((cpu_unit.flags & CPUF_DEC) == 0) /* option present? */ + return TR_UNI; + if ((tr = Ea (IR, &bva, VR, BY)) != 0) /* get eff addr */ + return tr; + if ((tr = cis_dec (op, rn, bva)) & WSIGN) /* process, abort? */ + return 0; + else return tr; + + case OP_EBS: /* edit byte string */ + if ((tr = ImmOp (IR, &opnd)) != 0) /* get immed opnd */ + return tr; + if ((cpu_unit.flags & CPUF_DEC) == 0) /* option present? */ + return TR_UNI; + if (QCPU_S89_5X0 && ((rn == 0) || (rn & 1))) /* invalid reg? */ + return TR_INVREG; + if ((tr = cis_ebs (rn, opnd)) & WSIGN) /* process, abort? */ + return 0; + else return tr; + + default: /* undefined inst */ + return (stop_op? STOP_ILLEG: TR_NXI); + } +return 0; +} + +/* Execute MTx in an interrupt location + + Sigma 5/6/7/8 - 17b virtual or real addressing + Sigma 9/5X0 - 17b virtual or 20b real addressing, no indexing + + acc is either PH (physical) or VNT (no traps) + Memory map traps are suppressed, NXM's cause undefined behavior + (returns a nested trap fault) */ + +uint32 cpu_int_mtx (uint32 vec, uint32 *res) +{ +uint32 IR, bva, wd, op, rn, lnt, acc; + +ReadPW (vec, &IR); /* get instruction */ +op = I_GETOP (IR); /* get op */ +lnt = 3 - (op >> 5); /* 73, 53, 33 */ +acc = (vec == VEC_C4P)? VNT: PH; /* access */ +rn = I_GETRN (IR); /* register */ +if (hst_lnt) /* if history */ + inst_hist (IR, PC, H_ITRP); /* record inst */ +if ((acc || QCPU_S567)? /* virt or S5-7? */ + (Ea (IR, &bva, acc, lnt) != 0): /* get eff addr */ + (EaP20 (IR, &bva, lnt) != 0)) /* get real addr */ + return TR_NESTED; + + switch (lnt) { + case BY: + if (ReadB (bva, &wd, acc) != 0) /* read byte */ + return TR_NESTED; + wd = (wd + SEXT_RN_W (rn)) & BMASK; /* modify */ + if (rn && (WriteB (bva, wd, acc) != 0)) /* if mod, rewrite */ + return TR_NESTED; + break; + case HW: + if (ReadH (bva, &wd, acc) != 0) /* read halfword */ + return TR_NESTED; + wd = (wd + SEXT_RN_W (rn)) & HMASK; /* modify */ + if (rn && (WriteB (bva, wd, acc) != 0)) /* if mod, rewrite */ + return TR_NESTED; + break; + case WD: + if (ReadW (bva, &wd, acc) != 0) /* read word */ + return TR_NESTED; + wd = (wd + SEXT_RN_W (rn)) & WMASK; /* modify */ + if (rn && (WriteW (bva, wd, acc) != 0)) /* if mod, rewrite */ + return TR_NESTED; + break; + } + +*res = wd; +return 0; +} + +/* Execute XSPD or PSS in trap or interrupt location */ + +uint32 cpu_trap_or_int (uint32 vec) +{ +uint32 IR, op, bva, acc, cc; + +ReadPW (TR_GETVEC (vec), &IR); /* read vector */ +op = I_GETOP (IR); /* get op */ +if (hst_lnt) { /* if history */ + if (vec & TR_FL) /* trap? */ + hst[hst_p].typ_cc_pc |= H_ABRT; /* mark prev abt */ + inst_hist (IR, PC, H_ITRP); /* record inst */ + } +if (vec & TR_FL) { /* trap? */ + if (QCPU_S89) /* Sigma 89? */ + PSW2 = (PSW2 & ~PSW2_TSF) | ((vec & PSW2_M_TSF) << PSW2_V_TSF); + if (vec == TR_INVRPN) /* non-trap reg ptr? */ + vec = TR_INVRPT; /* cvt to trapped */ + if (vec & TR_PDF) /* trap sets PDF? */ + cpu_pdf = 1; + } +if (op == OP_XPSD) { /* XPSD? */ + acc = (IR & IRB (10))? VNT: PH; /* virt vs phys */ + if ((acc || QCPU_S567)? /* virt or S5-7? */ + (Ea (IR, &bva, acc, DW) != 0): /* get eff addr */ + (EaP20 (IR, &bva, DW) != 0)) /* get real addr */ + return TR_NESTED; + if (cpu_xpsd (IR, bva, acc) != 0) /* do XPSD */ + return TR_NESTED; + if ((cc = TR_GETCC (vec)) != 0) { /* modify CC's? */ + CC = CC | cc; /* modify new CC's */ + if (IR & IRB (9)) /* and maybe new PC */ + PC = cpu_add_PC (PC, cc); + } + return 0; + } +if (QCPU_5X0 && (op == OP_PSS)) { /* 5X0 PSS? */ + if (EaP20 (IR, &bva, DW) != 0) /* get real addr */ + return TR_NESTED; + if (cpu_pss (IR, bva, PH)) /* do PSS */ + return TR_NESTED; + } +return TR_INVTRP; +} + +/* Immediate operand */ + +uint32 ImmOp (uint32 IR, uint32 *imm) +{ +if (TST_IND (IR)) /* indirect traps */ + return TR_NXI; +*imm = I_GETLIT (IR); +if (hst_lnt) /* record history */ + hst[hst_p].ea = hst[hst_p].op = *imm; +return 0; +} + +/* Calculate effective address for normal instructions + Note that in the event of a failure reading the ind addr, + Ea must return that value in bva (for ANLZ) */ + +uint32 Ea (uint32 IR, uint32 *bva, uint32 acc, uint32 lnt) +{ +uint32 ad, xr, wd; +uint32 tr; + +xr = I_GETXR (IR); /* get index reg */ +ad = I_GETADDR (IR) << 2; /* get byte address */ +if (TST_IND (IR)) { /* indirect */ + if ((tr = ReadW (ad, &wd, acc)) != 0) { /* read ind word */ + *bva = ad; /* err? return addr */ + return tr; + } + if (PSW_QRX9 && (wd & WSIGN)) { /* S9 real ext special? */ + wd = wd & VAMASK; /* use only 17b */ + ad = (wd & PSW1_XA)? /* extended word? */ + (PSW2 & PSW2_EA) | (wd & ~PSW1_XA): wd; + ad = ad << 2; + } + else ad = (wd & bvamqrx) << 2; /* get byte address */ + } +*bva = (ad + (xr? (R[xr] << lnt): 0)) & bvamqrx; /* index, mask */ +if (hst_lnt) { /* history? */ + hst[hst_p].ea = *bva; + ReadHist (*bva, &hst[hst_p].op, &hst[hst_p].op1, acc? VNT: PH, lnt); + } +return 0; +} + +/* Calculate effective address for 20b interrupt/trap instructions */ + +uint32 EaP20 (uint32 IR, uint32 *bva, uint32 lnt) +{ +uint32 pa, wd; + +pa = I_GETADDR20 (IR); /* get 20b ref addr */ +if (TST_IND (IR)) { /* indirect? */ + if (ReadPW (pa, &wd)) { /* valid? */ + *bva = pa << 2; + return TR_NXM; + } + pa = wd & cpu_tab[cpu_model].pamask; /* get indirect */ + } +*bva = pa << 2; +if (hst_lnt) { /* history? */ + hst[hst_p].ea = *bva; + ReadHist (*bva, &hst[hst_p].op, &hst[hst_p].op1, PH, lnt); + } +return 0; +} + +/* Calculate effective address for shift */ + +uint32 EaSh (uint32 IR, uint32 *stype, uint32 *sc) +{ +uint32 ad, xr, wd, tr; + +xr = I_GETXR (IR); /* get index reg */ +ad = I_GETADDR (IR); /* get word addr */ +if (TST_IND (IR)) { /* indirect? */ + if ((tr = ReadW (ad << 2, &wd, VR)) != 0) /* read ind word */ + return tr; + ad = I_GETADDR (wd); /* get word addr */ + } +if (xr) + ad = (ad & ~SHF_M_SC) | ((ad + R[xr]) & SHF_M_SC); /* indexing? */ +*stype = SHF_GETSOP (ad); /* extract type */ +*sc = SHF_GETSC (ad); /* extract count */ +if (hst_lnt) { + hst[hst_p].ea = ad << 2; + hst[hst_p].op = ad; + } +return 0; +} + +/* Shift routines */ + +uint32 Shift (uint32 rn, uint32 stype, uint32 sc) +{ +uint32 i, opnd, opnd1, t, cc; + +opnd = R[rn]; /* get operand(s) */ +opnd1 = R[rn|1]; +cc = CC & CC4; + +if (sc & SCSIGN) { /* right? */ + sc = SHF_M_SC + 1 - sc; + switch (stype) { + + case 0x0: /* right log sgl */ + if (sc > 31) /* >31? res = 0 */ + R[rn] = 0; + else R[rn] = R[rn] >> sc; + break; + + case 0x1: /* right log dbl */ + if (sc > 63) /* >63? res = 0 */ + opnd = opnd1 = 0; + else if (sc > 31) { /* >31? */ + sc = sc - 32; + opnd1 = opnd >> sc; + opnd = 0; + } + else { + opnd1 = ((opnd1 >> sc) | (opnd << (32 - sc))) & WMASK; + opnd = opnd >> sc; + } + R[rn|1] = opnd1; + R[rn] = opnd; + break; + + case 0x2: /* right circ sgl */ + sc = sc % 32; /* mod 32 */ + R[rn] = ((R[rn] >> sc) | (R[rn] << (32 - sc))) & WMASK; + break; + + case 0x3: /* right circ dbl */ + sc = sc % 64; /* mod 64 */ + t = opnd; + if (sc > 31) { /* >31? */ + sc = sc - 32; + opnd = ((opnd1 >> sc) | (opnd << (32 - sc))) & WMASK; + opnd1 = ((t >> sc) | (opnd1 << (32 - sc))) & WMASK; + } + else { + opnd = ((opnd >> sc) | (opnd1 << (32 - sc))) & WMASK; + opnd1 = ((opnd1 >> sc) | (t << (32 - sc))) & WMASK; + } + R[rn|1] = opnd1; + R[rn] = opnd; + break; + + case 0x4: /* right arith sgl */ + t = (R[rn] & WSIGN)? WMASK: 0; + if (sc > 31) /* >31? res = sign */ + R[rn] = t; + else R[rn] = ((R[rn] >> sc) | (t << (32 - sc))) & WMASK; + break; + + case 0x5: /* right arith dbl */ + t = (R[rn] & WSIGN)? WMASK: 0; + if (sc > 63) /* >63? res = sign */ + opnd = opnd1 = t; + else if (sc > 31) { /* >31? */ + sc = sc - 32; + opnd1 = ((opnd >> sc) | (t << (32 - sc))) & WMASK; + opnd = t; + } + else { + opnd1 = ((opnd1 >> sc) | (opnd << (32 - sc))) & WMASK; + opnd = ((opnd >> sc) | (t << (32 - sc))) & WMASK; + } + R[rn|1] = opnd1; + R[rn] = opnd; + break; + + case 0x6: /* right search sgl */ + for (i = 0; (i < sc) && !(opnd & WSIGN); i++) { + opnd = ((opnd >> 1) | (opnd << 31)) & WMASK; + } + cc = (opnd & WSIGN)? (cc | CC4): (cc & ~CC4); + R[rn] = opnd; + R[1] = sc - i; + break; + + case 0x7: /* right search dbl */ + for (i = 0; (i < sc) & !(opnd & WSIGN); i++) { + t = opnd; + opnd = ((opnd >> 1) | (opnd1 << 31)) & WMASK; + opnd1 = ((opnd1 >> 1) | (t << 31)) & WMASK; + } + cc = (opnd & WSIGN)? (cc | CC4): (cc & ~CC4); + R[rn|1] = opnd1; + R[rn] = opnd; + R[1] = sc - i; + break; + } + } /* end if */ + +else { /* left shift */ + switch (stype) { /* switch on type */ + + case 0x0: /* left log sgl */ + case 0x4: /* left arith sgl */ + for (i = 0; i < sc; i++) { + if (opnd & WSIGN) /* count 1's */ + cc = cc ^ CC1; + opnd = (opnd << 1) & WMASK; + if ((opnd ^ R[rn]) & WSIGN) /* sign change? */ + cc |= CC2; + } + R[rn] = opnd; + break; + + case 0x1: /* left log dbl */ + case 0x5: /* left arith dbl */ + for (i = 0; i < sc; i++) { + if (opnd & WSIGN) /* count 1's */ + cc = cc ^ CC1; + opnd = ((opnd << 1) | (opnd1 >> 31)) & WMASK; + opnd1 = (opnd1 << 1) & WMASK; + if ((opnd ^ R[rn]) & WSIGN) /* sign change? */ + cc |= CC2; + } + R[rn|1] = opnd1; + R[rn] = opnd; + break; + + case 0x2: /* left circ sgl */ + for (i = 0; i < sc; i++) { + if (opnd & WSIGN) /* count 1's */ + cc = cc ^ CC1; + opnd = ((opnd << 1) | (opnd >> 31)) & WMASK; + if ((opnd ^ R[rn]) & WSIGN) /* sign change? */ + cc |= CC2; + } + R[rn] = opnd; + break; + + case 0x3: /* left circ dbl */ + for (i = 0; i < sc; i++) { + if ((t = opnd & WSIGN) != 0) /* count 1's */ + cc = cc ^ CC1; + opnd = ((opnd << 1) | (opnd1 >> 31)) & WMASK; + opnd1 = ((opnd1 << 1) | (t >> 31)) & WMASK; + if ((opnd ^ R[rn]) & WSIGN) /* sign change? */ + cc |= CC2; + } + R[rn|1] = opnd1; + R[rn] = opnd; + break; + + case 0x6: /* left search sgl */ + for (i = 0; (i < sc) & !(opnd & WSIGN); i++) { + opnd = ((opnd << 1) | (opnd >> 31)) & WMASK; + if ((opnd ^ R[rn]) & WSIGN) /* sign change? */ + cc |= CC2; + } + cc = (opnd & WSIGN)? (cc | CC4): (cc & ~CC4); + R[rn] = opnd; + R[1] = sc - i; + break; + + case 0x7: /* left search dbl */ + for (i = 0; (i < sc) & !(opnd & WSIGN); i++) { + t = opnd; + opnd = ((opnd << 1) | (opnd1 >> 31)) & WMASK; + opnd1 = ((opnd1 << 1) | (t >> 31)) & WMASK; + if ((opnd ^ R[rn]) & WSIGN) /* sign change? */ + cc |= CC2; + } + cc = (opnd & WSIGN)? (cc | CC4): (cc & ~CC4); + R[rn|1] = opnd1; + R[rn] = opnd; + R[1] = sc - i; + break; + } /* end switch */ + } /* end else */ +return cc; +} + +/* Arithmetic routines */ + +uint32 Add32 (uint32 s1, uint32 s2, uint32 cin) +{ +uint32 t = (s1 + s2 + cin) & WMASK; /* add + carry in */ + +if (t & WSIGN) /* set CC34 */ + CC = CC4; +else if (t != 0) + CC = CC3; +else CC = 0; +if (cin? (t <= s1): (t < s1)) /* set carry out */ + CC |= CC1; +if (((s1 ^ ~s2) & (s1 ^ t)) & WSIGN) /* set overflow */ + CC |= CC2; +return t; +} + +uint32 SMul64 (uint32 a, uint32 b, uint32 *lo) +{ +uint32 ah, bh, al, bl, rhi, rlo, rmid1, rmid2, sign; + +CC &= CC1; /* clr CC2-4 */ +if ((a == 0) || (b == 0)) { /* zero argument? */ + *lo = 0; /* result is zero */ + return 0; + } +sign = a ^ b; /* sign of result */ +if (a & WSIGN) /* |a|, |b| */ + a = NEG_W (a); +if (b & WSIGN) + b = NEG_W (b); +ah = (a >> 16) & HMASK; /* split operands */ +bh = (b >> 16) & HMASK; /* into 16b chunks */ +al = a & HMASK; +bl = b & HMASK; +rhi = ah * bh; /* high result */ +rmid1 = ah * bl; +rmid2 = al * bh; +rlo = al * bl; +rhi = rhi + ((rmid1 >> 16) & HMASK) + ((rmid2 >> 16) & HMASK); +rmid1 = (rlo + (rmid1 << 16)) & WMASK; /* add mid1 to lo */ +if (rmid1 < rlo) /* carry? incr hi */ + rhi = rhi + 1; +rmid2 = (rmid1 + (rmid2 << 16)) & WMASK; /* add mid2 to to */ +if (rmid2 < rmid1) /* carry? incr hi */ + rhi = rhi + 1; +rhi = rhi & WMASK; +if (sign & WSIGN) /* neg result? */ + NEG_D (rhi, rmid2); +if (rhi & WSIGN) /* < 0, set CC4 */ + CC |= CC4; +else if (rhi || rmid2) /* > 0, set CC3 */ + CC |= CC3; +if (rhi != ((rmid2 & WSIGN)? WMASK: 0)) /* fit in 32b? */ + CC |= CC2; /* set CC2 */ +*lo = rmid2; +return rhi; +} + +t_bool SDiv64 (uint32 dvdh, uint32 dvdl, uint32 dvr, uint32 *res, uint32 *rem) +{ +uint32 i, quo, quos, rems; + +quos = dvdh ^ dvr; +rems = dvdh; +if (dvdh & WSIGN) { /* |dividend| */ + NEG_D (dvdh, dvdl); + } +if (dvr & WSIGN) /* |divisor| */ + dvr = NEG_W (dvr); +if (dvdh >= dvr) /* divide work? */ + return TRUE; +for (i = quo = 0; i < 32; i++) { /* 32 iterations */ + quo = (quo << 1) & WMASK; /* shift quotient */ + dvdh = ((dvdh << 1) | (dvdl >> 31)) & WMASK; /* shift dividend */ + dvdl = (dvdl << 1) & WMASK; + if (dvdh >= dvr) { /* step work? */ + dvdh = (dvdh - dvr) & WMASK; /* subtract dvr */ + quo = quo + 1; + } + } +if (quo & WSIGN) /* quotient ovflo? */ + return TRUE; +*rem = (rems & WSIGN)? NEG_W (dvdh): dvdh; /* sign of rem */ +*res = (quos & WSIGN)? NEG_W (quo): quo; +return FALSE; /* no overflow */ +} + +uint32 Cmp32 (uint32 a, uint32 b) +{ +if (a == b) /* ==? */ + return 0; +if ((a ^ b) & WSIGN) /* unlike signs? */ + return (a & WSIGN)? CC4: CC3; +return (a < b)? CC4: CC3; /* like signs */ +} + +/* Test stack pointer space/words to see if it can be modified - + returns special abort status (WSIGN) */ + +uint32 TestSP1 (uint32 sp1, int32 mod) +{ +int32 spc, wds; +uint32 cc; + +cc = 0; +spc = (int32) SP_GETSPC (sp1); /* get space */ +wds = (int32) SP_GETWDS (sp1); /* get words */ +if (((wds + mod) > SP_M_WDS) || ((wds + mod) < 0)) { /* words overflow? */ + if ((sp1 & SP_TW) == 0) /* trap if enabled */ + return TR_PSH; + cc |= CC3; + } +if (((spc - mod) > SP_M_WDS) || ((spc - mod) < 0)) { /* space overflow? */ + if ((sp1 & SP_TS) == 0) /* trap if enabled */ + return TR_PSH; + cc |= CC1; + } +CC = cc; +if (cc || (mod == 0)) { /* mod fails? */ + CC |= ((spc? 0: CC2) | (wds? 0: CC4)); + return WSIGN; + } +return 0; +} + +/* Actually modify stack pointer space/words and set CC's, + used by PSW/PLW/PSM/PLM */ + +uint32 ModWrSP (uint32 bva, uint32 sp, uint32 sp1, int32 mod) +{ +uint32 tr; + +sp = (sp + mod) & WMASK; +sp1 = (sp1 & (SP_TS|SP_TW)) | + (((SP_GETSPC (sp1) - mod) & SP_M_SPC) << SP_V_SPC) | + (((SP_GETWDS (sp1) + mod) & SP_M_WDS) << SP_V_WDS); +if ((tr = WriteD (bva, sp, sp1, VW)) != 0) + return tr; +if ((mod > 0) && SP_GETSPC (sp1) == 0) + CC |= CC2; +if ((mod < 0) && SP_GETWDS (sp1) == 0) + CC |= CC4; +return 0; +} + +/* XPSD instruction */ + +uint32 cpu_xpsd (uint32 IR, uint32 bva, uint32 ra) +{ +uint32 wa, wd, wd1, wd3; +uint32 tr; + +if (ra == VR) /* virtual? */ + wa = VW; /* set write virt */ +else wa = ra; /* no, phys */ +cpu_assemble_PSD (); +wd = PSW1; /* no more changes */ +wd1 = PSW2; +wd3 = PSW4; +if ((tr = WriteD (bva, wd, wd1, wa)) != 0) /* write curr PSD */ + return tr; +bva = bva + 8; +if (QCPU_5X0 && (IR & IRB (11))) { /* extra words? */ + if ((tr = WriteW (bva | 4, wd3, VW)) != 0) + return tr; + bva = bva + 8; + } +if ((tr = ReadD (bva, &wd, &wd1, ra)) != 0) /* read new PSD */ + return tr; +wd1 = (wd1 & ~(cpu_tab[cpu_model].psw2_mbz)) | /* merge inhibits */ + (PSW2 & PSW2_ALLINH); +if ((tr = cpu_new_PSD (IR & IRB (8), wd, wd1)) != 0) /* update PSD */ + return tr; +return 0; +} + +/* PSS instruction */ + +uint32 cpu_pss (uint32 IR, uint32 bva, uint32 acc) +{ +uint32 i, wd, wd1, tos, swc; +uint32 tr; + +cpu_assemble_PSD (); /* get old PSD */ +if ((tr = ReadD (bva, &wd, &wd1, acc)) != 0) /* read new PSD */ + return tr; +ReadPW (SSP_TOS, &tos); /* read system SP */ +ReadPW (SSP_SWC, &swc); +for (i = 0; i < RF_NUM; i++) { /* push registers */ + if (WritePW (tos + SSP_FR_RN + i + 1, R[i])) + return TR_NXM; + } +if (WritePW (tos + SSP_FR_PSW1 + 1, PSW1) || /* push PSD */ + WritePW (tos + SSP_FR_PSW2 + 1, PSW2)) + return TR_NXM; +WritePW (SSP_TOS, (tos + SSP_FR_LNT) & WMASK); /* tos + 28 */ +swc = (swc & (SP_TS|SP_TW)) | /* spc-28, wds+28 */ + (((SP_GETWDS (swc) + SSP_FR_LNT) & SP_M_WDS) << SP_V_WDS) | + (((SP_GETSPC (swc) - SSP_FR_LNT) & SP_M_SPC) << SP_V_SPC); +if (SP_GETWDS (swc) < SSP_FR_LNT) /* wds overflow? */ + swc |= SP_TW; /* set sticky bit */ +WritePW (SSP_SWC, swc); +wd1 = (wd1 & ~(cpu_tab[cpu_model].psw2_mbz)) | /* merge inhibits */ + (PSW2 & PSW2_ALLINH); +if ((tr = cpu_new_PSD (IR & IRB (8), wd, wd1)) != 0) /* update PSD */ + return tr; +return 0; +} + +/* PLS instruction */ + +uint32 cpu_pls (uint32 IR) +{ +uint32 i, wd, wd1, tos, swc, spc; +uint32 tr; + +ReadPW (SSP_TOS, &tos); /* read system SP */ +ReadPW (SSP_SWC, &swc); +spc = SP_GETSPC (swc); /* space left */ +if (spc == 0) { /* none? */ + ReadPW (SSP_DFLT_PSW1, &wd); /* use default PSD */ + ReadPW (SSP_DFLT_PSW2, &wd1); + } +else if (spc < SSP_FR_LNT) /* not enough? */ + return TR_INVSSP; +else { + tos = (tos - SSP_FR_LNT) & WMASK; /* modify TOS */ + for (i = 0; i < RF_NUM; i++) { /* pull registers */ + if (ReadPW (tos + SSP_FR_RN + i + 1, &wd)) + return TR_NXM; + R[i] = wd; + } + if (ReadPW (tos + SSP_FR_PSW1 + 1, &wd) || /* pull new PSD */ + ReadPW (tos + SSP_FR_PSW2 + 1, &wd1)) + return TR_NXM; + WritePW (SSP_TOS, tos); /* rewrite SP */ + swc = (swc & (SP_TS|SP_TW)) | /* spc+28, wds-28 */ + (((SP_GETWDS (swc) - SSP_FR_LNT) & SP_M_WDS) << SP_V_WDS) | + (((SP_GETSPC (swc) + SSP_FR_LNT) & SP_M_SPC) << SP_V_SPC); + if (SP_GETSPC (swc) < SSP_FR_LNT) /* spc overflow? */ + swc |= SP_TS; /* set sticky bit */ + WritePW (SSP_SWC, swc); + } +wd1 = (wd1 & ~(cpu_tab[cpu_model].psw2_mbz)) | /* merge inhibits */ + (PSW2 & PSW2_ALLINH); +if ((tr = cpu_new_PSD (IR & IRB (8), wd, wd1)) != 0) /* update PSD */ + return tr; +if (IR & IRB (10)) /* clr hi pri int? */ + int_hireq = io_rels_int (int_hiact, IR & IRB (11)); +else if (IR & IRB (11)) /* clr PDF flag? */ + cpu_pdf = 0; + +return 0; +} + +/* Load new PSD */ + +uint32 cpu_new_PSD (uint32 lrp, uint32 p1, uint32 p2) +{ +uint32 tr; + +PSW1 = p1 & ~cpu_tab[cpu_model].psw1_mbz; /* clear mbz bits */ +PSW2 = ((p2 & ~PSW2_RP) | (PSW2 & PSW2_RP)) & /* save reg ptr */ + ~cpu_tab[cpu_model].psw2_mbz; +if (lrp && /* load reg ptr? */ + ((tr = cpu_new_RP (p2)) != 0)) /* invalid? */ + return tr; /* trap */ +CC = PSW1_GETCC (PSW1); /* extract CC's */ +PC = PSW1_GETPC (PSW1); /* extract PC */ +PSW2_WLK = PSW2_GETWLK (PSW2); /* extract lock */ +int_hireq = io_eval_int (); /* update intr */ +if ((PSW1 & PSW1_MM) || /* mapped or */ + ((PSW2 & (PSW2_MA9|PSW2_MA5X0)) == 0)) { /* not real ext? */ + bvamqrx = BVAMASK; /* 17b masks */ + PSW_QRX9 = 0; + } +else { /* phys real ext */ + if ((PSW_QRX9 = PSW2 & PSW2_MA9) != 0) /* Sigma 9? */ + bvamqrx = BPAMASK22; /* yes, 22b masks */ + else bvamqrx = BPAMASK20; /* no, 20b masks */ + } +return 0; +} + +/* Load new RP */ + +uint32 cpu_new_RP (uint32 rp) +{ +uint32 rp1, j; + +PSW2 = (PSW2 & ~PSW2_RP) | (rp & PSW2_RP); /* merge to PSW2 */ +PSW2 = PSW2 & ~cpu_tab[cpu_model].psw2_mbz; /* clear nx bits */ +rp1 = PSW2_GETRP (rp); +if (rp1 >= rf_bmax) { /* nx reg file? */ + if (QCPU_S89) + return TR_INVRPN; + if (QCPU_5X0) + return TR_INVREG; + for (j = 0; j < RF_NUM; j++) /* clear nx set */ + rf[(rp1 * RF_NUM) + j] = 0; + sim_activate (&cpu_rblk_unit, 1); /* sched cleaner */ + } +R = rf + (rp1 * RF_NUM); +return 0; +} + +/* This routine is scheduled if the current registr block doesn't exist */ + +t_stat cpu_bad_rblk (UNIT *uptr) +{ +uint32 rp1, j; + +rp1 = PSW2_GETRP (PSW2); /* get reg ptr */ +if (rp1 >= rf_bmax) { /* still bad? */ + for (j = 0; j < RF_NUM; j++) /* clear nx set */ + rf[(rp1 * RF_NUM) + j] = 0; + sim_activate (uptr, 1); /* sched again */ + } +return SCPE_OK; +} + +/* Load new PC for branch instruction */ + +uint32 cpu_new_PC (uint32 bva) +{ +uint32 npc = bva >> 2; + +if (PSW_QRX9 && (npc & PSW1_XA)) /* S9 real ext, XA? */ + PSW2 = (PSW2 & ~PSW2_EA) | (npc & PSW2_EA); /* change PSW2 EA */ +return npc & BVAMASK; +} + +/* Add value to PC for fetch, BAL, trap */ + +uint32 cpu_add_PC (uint32 pc, uint32 inc) +{ +if (PSW_QRX9) /* S9 real ext? */ + return ((pc & ~(PSW1_M_PC & ~PSW1_XA)) | /* modulo 16b inc */ + ((pc + inc) & (PSW1_M_PC & ~PSW1_XA))); +return ((pc + inc) & BVAMASK); /* no, mod 17b inc */ +} + +/* Assemble PSD */ + +void cpu_assemble_PSD (void) +{ +PSW1 = (PSW1 & ~(PSW1_CCMASK|PSW1_PCMASK|cpu_tab[cpu_model].psw1_mbz)) | + (CC << PSW1_V_CC) | (PC << PSW1_V_PC); +PSW2 = (PSW2 & ~(PSW2_WLKMASK|cpu_tab[cpu_model].psw2_mbz)) | + (PSW2_WLK << PSW2_V_WLK); +return; +} + +/* Reset routine */ + +t_stat cpu_reset (DEVICE *dptr) +{ +cpu_new_PSD (1, PSW1_DFLT | (PSW1 & PSW1_PCMASK), PSW2_DFLT); +cpu_pdf = 0; +cons_alarm = 0; +cons_pcf = 0; +set_rf_display (R); +if (M == NULL) + M = (uint32 *) calloc (MAXMEMSIZE, sizeof (uint32)); +if (M == NULL) + return SCPE_MEM; +pcq_r = find_reg ("PCQ", NULL, dptr); +if (pcq_r) pcq_r->qptr = 0; +else return SCPE_IERR; +sim_brk_types = sim_brk_dflt = SWMASK ('E'); +rtc_register (RTC_ALARM, RTC_HZ_2, &cpu_unit); +return int_reset (dptr); +} + +/* Memory examine */ + +t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw) +{ +uint32 lnt; + +if (sw & SWMASK ('C')) + lnt = 2; +else if ((sw & SWMASK ('B')) || (sw & SWMASK ('A')) || (sw & SWMASK ('E'))) + lnt = 0; +else if (sw & SWMASK ('H')) + lnt = 1; +else lnt = 2; +if (sw & SWMASK ('V')) { + if (ReadW (addr << lnt, vptr, VNT) != 0) + return SCPE_REL; + } +else if (ReadW (addr << lnt, vptr, PH) != 0) + return SCPE_NXM; +return SCPE_OK; +} + +/* Memory deposit */ + +t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw) +{ +uint32 lnt; + +if (sw & SWMASK ('C')) + lnt = 2; +else if ((sw & SWMASK ('B')) || (sw & SWMASK ('A')) || (sw & SWMASK ('E'))) + lnt = 0; +else if (sw & SWMASK ('H')) + lnt = 1; +else lnt = 2; +if (sw & SWMASK ('V')) { + if (WriteW (addr << lnt, val, VNT) != 0) + return SCPE_REL; + } +else if (WriteW (addr << lnt, val, PH) != 0) + return SCPE_NXM; +return SCPE_OK; +} + +/* CPU configuration management + + These routines (for type, memory size, options, number of reg blocks, + number of external int blocks) must generate a consistent result. + To assure this, all changes (except memory size) reset the CPU. */ + +/* Set CPU type */ + +t_stat cpu_set_type (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +uint32 model = CPUF_GETMOD (val); + +if (model == cpu_model) /* no change? */ + return SCPE_OK; +cpu_reset (&cpu_dev); +if (MEMSIZE > (cpu_tab[cpu_model].pamask + 1)) + cpu_set_size (uptr, cpu_tab[cpu_model].pamask + 1, NULL, (void *) uptr); +cpu_model = model; +cpu_unit.flags = (cpu_unit.flags | cpu_tab[model].std) & ~cpu_tab[model].opt; +rf_bmax = RF_DFLT; +io_set_eimax (EIGRP_DFLT); +return SCPE_OK; +} + +/* Set memory size */ + +t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +uint32 mc = 0; +uint32 i; + +if ((val <= 0) || (val > (int32)(cpu_tab[cpu_model].pamask + 1))) + return SCPE_ARG; +if (!desc) { /* force trunc? */ + for (i = val; i < MEMSIZE; i++) + mc = mc | M[i]; + if ((mc != 0) && (!get_yn ("Really truncate memory [N]?", FALSE))) + return SCPE_OK; + } +MEMSIZE = val; +for (i = MEMSIZE; i < MAXMEMSIZE; i++) + M[i] = 0; +return SCPE_OK; +} + +/* Set and clear options */ + +t_stat cpu_set_opt (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +if ((val & (cpu_tab[cpu_model].std | cpu_tab[cpu_model].opt)) == 0) + return SCPE_NOFNC; +cpu_unit.flags |= val; +return SCPE_OK; +} + +t_stat cpu_clr_opt (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +if (val & cpu_tab[cpu_model].std) + return SCPE_NOFNC; +cpu_unit.flags &= ~val; +return SCPE_OK; +} + +/* Set/show register blocks */ + +t_stat cpu_set_rblks (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +int32 invmask, lnt, i, j; +t_stat r; + +if (QCPU_5X0) /* 5X0 fixed */ + return SCPE_NOFNC; +if (cptr == NULL) + return SCPE_ARG; +invmask = PSW2_GETRP (cpu_tab[cpu_model].psw2_mbz); +if (QCPU_S89) + invmask |= 0x10; +lnt = (int32) get_uint (cptr, 10, RF_NBLK, &r); +if ((r != SCPE_OK) || (lnt == 0) || (lnt & invmask)) + return SCPE_ARG; +cpu_reset (&cpu_dev); +rf_bmax = lnt; +for (i = rf_bmax; i < RF_NBLK; i++) { /* zero unused */ + for (j = 0; j < RF_NUM; j++) + rf[(i * RF_NUM) + j] = 0; + } +return SCPE_OK; +} + +t_stat cpu_show_rblks (FILE *st, UNIT *uptr, int32 val, void *desc) +{ +fprintf (st, "register blocks=%d", rf_bmax); +return SCPE_OK; +} + +/* Set current register file pointers for SCP */ + +void set_rf_display (uint32 *rfbase) +{ +REG *rptr; +uint32 i; + +rptr = find_reg ("R0", NULL, &cpu_dev); +if (rptr == NULL) return; +for (i = 0; i < RF_NUM; i++, rptr++) + rptr->loc = (void *) (rfbase + i); +return; +} + +/* Front panael alarm */ + +t_stat cpu_set_alarm (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +cons_alarm_enb = val; +return SCPE_OK; +} + +t_stat cpu_show_alarm (FILE *st, UNIT *uptr, int32 val, void *desc) +{ +fputs (cons_alarm_enb? "alarm enabled\n": "alarm disabled\n", st); +return SCPE_OK; +} + +t_stat cpu_svc (UNIT *uptr) +{ +if (cons_alarm && cons_alarm_enb) + sim_putchar ('\a'); +return SCPE_OK; +} + +/* Address converter and display */ + +/* Virtual address translation */ + +t_stat cpu_show_addr (FILE *of, UNIT *uptr, int32 val, void *desc) +{ +t_stat r; +char *cptr = (char *) desc; +uint32 ad, bpa, dlnt, virt; +static const char *lnt_str[] = { + "byte", + "halfword", + "word", + "doubleword", + }; +extern uint32 map_reloc (uint32 bva, uint32 acc, uint32 *bpa); + +if ((val < 0) || (val > DW)) + return SCPE_IERR; +virt = (sim_switches & SWMASK ('V'))? 1: 0; +if (cptr) { + ad = (uint32) get_uint (cptr, 16, virt? VAMASK: PAMASK22, &r); + if (r == SCPE_OK) { + if (sim_switches & SWMASK ('B')) + dlnt = 0; + else if (sim_switches & SWMASK ('H')) + dlnt = 1; + else if (sim_switches & SWMASK ('D')) + dlnt = 3; + else dlnt = 2; + bpa = ad << val; + if (virt && map_reloc (bpa, VNT, &bpa)) + fprintf (of, "Virtual address %-X: memory management error\n"); + else fprintf (of, "%s %s %-X: physical %s %-X\n", + ((virt)? "Virtual": "Physical"), lnt_str[val], ad, lnt_str[dlnt], bpa >> dlnt); + return SCPE_OK; + } + } +fprintf (of, "Invalid argument\n"); +return SCPE_OK; +} + +/* Record history */ + +void inst_hist (uint32 ir, uint32 pc, uint32 tp) +{ +uint32 rn = I_GETRN (ir); + +hst_p = (hst_p + 1); /* next entry */ +if (hst_p >= hst_lnt) + hst_p = 0; +hst[hst_p].typ_cc_pc = (CC << PSW1_V_CC) | pc | tp; +hst[hst_p].ir = ir; +hst[hst_p].rn = R[rn]; +hst[hst_p].rn1 = R[rn|1]; +return; +} + +/* Set history */ + +t_stat cpu_set_hist (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +int32 i, lnt; +t_stat r; + +if (cptr == NULL) { + for (i = 0; i < hst_lnt; i++) + hst[i].typ_cc_pc = 0; + hst_p = 0; + return SCPE_OK; + } +lnt = (int32) get_uint (cptr, 10, HIST_MAX, &r); +if ((r != SCPE_OK) || (lnt && (lnt < HIST_MIN))) + return SCPE_ARG; +hst_p = 0; +if (hst_lnt) { + free (hst); + hst_lnt = 0; + hst = NULL; + } +if (lnt) { + hst = (InstHistory *) calloc (lnt, sizeof (InstHistory)); + if (hst == NULL) + return SCPE_MEM; + hst_lnt = lnt; + } +return SCPE_OK; +} + +/* Print one instruction */ + +void cpu_fprint_one_inst (FILE *st, uint32 tcp, uint32 ir, uint32 rn, uint32 rn1, + uint32 ea, uint32 opnd, uint32 opnd1) +{ +t_value sim_val; + +if (tcp & (H_INST|H_ITRP)) { /* instr or trap? */ + uint32 op = I_GETOP (ir); + uint32 cc = PSW1_GETCC (tcp); + uint32 pc = tcp & PAMASK20; + uint8 fl = anlz_tab[op]; + + fprintf (st, "%c %05X %X %08X %08X ", /* standard fields */ + ((tcp & H_INST)? ' ': 'T'), pc, cc, rn, rn1); + if (tcp & H_ABRT) /* aborted? */ + fputs ("aborted ", st); + else { + if (fl & CC4) /* immediate? */ + fprintf (st, "%05X ", ea); + else if ((fl >> 2) != DW) /* byte/half/word? */ + fprintf (st, "%05X %08X ", ea >> 2, opnd); + else fprintf (st, "%05X %08X %08X ", ea >> 2, opnd, opnd1); + } + sim_val = ir; + if ((fprint_sym (st, pc, &sim_val, NULL, SWMASK ('M'))) > 0) + fprintf (st, "(undefined) %08X", ir); + fputc ('\n', st); /* end line */ + } +return; +} + +/* Show history */ + +t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc) +{ +int32 k, di, lnt; +t_stat r; +char *cptr = (char *) desc; +InstHistory *h; + +if (hst_lnt == 0) /* enabled? */ + return SCPE_NOFNC; +if (cptr) { + lnt = (int32) get_uint (cptr, 10, hst_lnt, &r); + if ((r != SCPE_OK) || (lnt == 0)) return SCPE_ARG; + } +else lnt = hst_lnt; +di = hst_p - lnt; /* work forward */ +if (di < 0) di = di + hst_lnt; +fprintf (st, " PC CC Rn Rn|1 EA operand operand1 IR\n\n"); +for (k = 0; k < lnt; k++) { /* print specified */ + h = &hst[(++di) % hst_lnt]; /* entry pointer */ + if (h->typ_cc_pc) /* instruction? */ + cpu_fprint_one_inst (st, h->typ_cc_pc, h->ir, h->rn, h->rn1, h->ea, h->op, h->op1); + } /* end for */ +return SCPE_OK; +} diff --git a/sigma/sigma_defs.h b/sigma/sigma_defs.h new file mode 100644 index 00000000..12e31ad2 --- /dev/null +++ b/sigma/sigma_defs.h @@ -0,0 +1,478 @@ +/* sigma_defs.h: XDS Sigma simulator definitions + + Copyright (c) 2007-2010, Robert M Supnik + + 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 + ROBERT M SUPNIK 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 Robert M Supnik shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + + The author gratefullly acknowledges the help of George Plue, who provided + answers to many puzzling questions about how the Sigma series worked. + + 22-May-10 RMS Added check for 64b definitions +*/ + +#ifndef SIGMA_DEFS_H_ +#define SIGMA_DEFS_H_ 0 + +#include "sim_defs.h" /* simulator defns */ + +#if defined(USE_INT64) || defined(USE_ADDR64) +#error "Sigma 32b does not support 64b values!" +#endif + +/* Simulator stops */ + +#define STOP_INVIOC 1 /* invalid IO config */ +#define STOP_IBKPT 2 /* breakpoint */ +#define STOP_ASTOP 3 /* address stop */ +#define STOP_WAITNOINT 4 /* WAIT, no intr */ +#define STOP_INVPSD 5 /* invalid PSD */ +#define STOP_ROLLBACK 6 /* >= here, rollback PC */ +#define STOP_EXULIM 6 /* EXU loop */ +#define STOP_ILLEG 7 /* illegal instr */ +#define STOP_ILLTRP 8 /* illegal trap inst */ +#define STOP_ILLVEC 9 /* illegal vector */ +#define STOP_TRPT 10 /* trap inside int/trap */ +#define STOP_MAX 15 /* <= here for all stops */ + +/* Timers */ + +#define TMR_RTC 0 /* clocks */ + +/* Architectural constants */ + +#define PASIZE17 17 /* phys addr width, S5-8 */ +#define PASIZE20 20 /* phys addr width, 5X0 */ +#define PASIZE22 22 /* phys addr width, S9 */ +#define PAMASK17 ((1u << PASIZE17) - 1) +#define BPAMASK17 ((1u << (PASIZE17 + 2)) - 1) +#define PAMASK20 ((1u << PASIZE20) - 1) +#define BPAMASK20 ((1u << (PASIZE20 + 2)) - 1) +#define PAMASK22 ((1u << PASIZE22) - 1) +#define BPAMASK22 ((1u << (PASIZE22 + 2)) - 1) +#define MAXMEMSIZE (1u << PASIZE20) /* maximum memory */ +#define MEMSIZE (cpu_unit.capac) +#define MEM_IS_NXM(x) ((x) >= MEMSIZE) +#define BPA_IS_NXM(x) (((x) >> 2) >= MEMSIZE) +#define VASIZE 17 /* virtual addr width */ +#define VAMASK ((1u << VASIZE) - 1) /* virtual addr mask */ +#define BVAMASK ((1u << (VASIZE + 2)) - 1) /* byte virtual addr mask */ +#define RF_NUM 16 /* number of registers */ +#define RF_NBLK 32 /* max number reg blocks */ +#define RF_DFLT 4 /* default reg blocks */ + +/* CPU models, options, and variable data */ + +#define CPUF_STR (1u << (UNIT_V_UF + 0)) /* byte string */ +#define CPUF_DEC (1u << (UNIT_V_UF + 1)) /* decimal */ +#define CPUF_FP (1u << (UNIT_V_UF + 2)) /* floating point */ +#define CPUF_MAP (1u << (UNIT_V_UF + 3)) /* memory map */ +#define CPUF_WLK (1u << (UNIT_V_UF + 4)) /* write lock protect */ +#define CPUF_LAMS (1u << (UNIT_V_UF + 5)) /* LAS/LMS */ +#define CPUF_ALLOPT (CPUF_STR|CPUF_DEC|CPUF_FP|CPUF_MAP|CPUF_WLK|CPUF_LAMS) +#define CPUF_MSIZE (1u << (UNIT_V_UF + 6)) /* dummy for memory */ + +#define CPU_V_S5 0 +#define CPU_V_S6 1 +#define CPU_V_S7 2 +#define CPU_V_S8 3 /* not supported */ +#define CPU_V_S9 4 /* not supported */ +#define CPU_V_550 5 /* not supported */ +#define CPU_V_560 6 /* not supported */ +#define CPU_S5 (1u << CPU_V_S5) +#define CPU_S6 (1u << CPU_V_S6) +#define CPU_S7 (1u << CPU_V_S7) +#define CPU_S7B (1u << CPU_V_S7B) +#define CPU_S8 (1u << CPU_V_S8) +#define CPU_S9 (1u << CPU_V_S9) +#define CPU_550 (1u << CPU_V_550) +#define CPU_560 (1u << CPU_V_560) + +#define QCPU_S5 (cpu_model == CPU_V_S5) +#define QCPU_S9 (cpu_model == CPU_V_S9) +#define QCPU_5X0 ((1u << cpu_model) & (CPU_550|CPU_560)) +#define QCPU_S567 ((1u << cpu_model) & (CPU_S5|CPU_S6|CPU_S7)) +#define QCPU_S89 ((1u << cpu_model) & (CPU_S8|CPU_S9)) +#define QCPU_S89_5X0 ((1u << cpu_model) & (CPU_S8|CPU_S9|CPU_550|CPU_560)) +#define QCPU_BIGM ((1u << cpu_model) & (CPU_S9|CPU_550|CPU_560)) + +#define CPU_MUNIT_SIZE (1u << 15) /* mem unit size */ + +typedef struct { + uint32 psw1_mbz; /* PSW1 mbz */ + uint32 psw2_mbz; /* PSW2 mbz */ + uint32 mmc_cm_map1; /* MMC mode 1 cmask */ + uint32 pamask; /* physical addr mask */ + uint32 eigrp_max; /* max num ext int groups */ + uint32 chan_max; /* max num channels */ + uint32 iocc; /* IO instr CC bits */ + uint32 std; /* required options */ + uint32 opt; /* variable options */ + } cpu_var_t; + +/* Instruction format */ + +#define INST_V_IND 31 /* indirect */ +#define INST_IND (1u << INST_V_IND) +#define INST_V_OP 24 /* opcode */ +#define INST_M_OP 0x7F +#define INST_V_RN 20 /* register */ +#define INST_M_RN 0xF +#define INST_V_XR 17 /* index */ +#define INST_M_XR 0x7 +#define INST_V_ADDR 0 /* 17b addr */ +#define INST_M_ADDR 0x1FFFF +#define INST_V_LIT 0 /* 20b literal or addr */ +#define INST_M_LIT 0xFFFFF +#define TST_IND(x) ((x) & INST_IND) +#define I_GETOP(x) (((x) >> INST_V_OP) & INST_M_OP) +#define I_GETRN(x) (((x) >> INST_V_RN) & INST_M_RN) +#define I_GETXR(x) (((x) >> INST_V_XR) & INST_M_XR) +#define I_GETADDR(x) (((x) >> INST_V_ADDR) & INST_M_ADDR) +#define I_GETADDR20(x) (((x) >> INST_V_ADDR) & PAMASK20) +#define I_GETLIT(x) (((x) >> INST_V_LIT) & INST_M_LIT) +#define IRB(x) (1u << (31 - (x))) + +/* Shift instructions */ + +#define SHF_V_SOP 8 /* shift operation */ +#define SHF_M_SOP 0x7 +#define SHF_V_SC 0 /* shift count */ +#define SHF_M_SC 0x7F +#define SCSIGN 0x40 +#define SHF_GETSOP(x) (((x) >> SHF_V_SOP) & SHF_M_SOP) +#define SHF_GETSC(x) (((x) >> SHF_V_SC) & SHF_M_SC) + +/* String instructions */ + +#define S_V_MCNT 24 /* string mask/count */ +#define S_M_MCNT 0xFF +#define S_MCNT (S_M_MCNT << S_V_MCNT) +#define S_GETMCNT(x) (((x) >> S_V_MCNT) & S_M_MCNT) +#define S_ADDRINC (S_MCNT + 1) + +/* Data types */ + +#define WMASK 0xFFFFFFFF /* word */ +#define WSIGN 0x80000000 /* word sign */ +#define LITMASK (INST_M_LIT) /* literal */ +#define LITSIGN 0x80000 /* literal sign */ +#define HMASK 0xFFFF /* halfword mask */ +#define HSIGN 0x8000 /* halfword sign */ +#define BMASK 0xFF /* byte */ +#define BSIGN 0x80 /* byte sign */ +#define RNMASK (INST_M_RN) /* reg lit */ +#define RNSIGN 0x08 /* reg lit sign */ + +#define FP_V_SIGN 31 /* sign */ +#define FP_SIGN (1u << FP_V_SIGN) +#define FP_V_EXP 24 /* exponent */ +#define FP_M_EXP 0x7F +#define FP_BIAS 0x40 /* exponent bias */ +#define FP_V_FRHI 0 /* high fraction */ +#define FP_M_FRHI 0x00FFFFFF +#define FP_NORM 0x00F00000 +#define FP_M_FRLO 0xFFFFFFFF /* low fraction */ +#define FP_GETSIGN(x) (((x) >> FP_V_SIGN) & 1) +#define FP_GETEXP(x) (((x) >> FP_V_EXP) & FP_M_EXP) +#define FP_GETFRHI(x) (((x) >> FP_V_FRHI) & FP_M_FRHI) +#define FP_GETFRLO(x) ((x) & FP_M_FRLO) + +/* PSW1 fields */ + +#define PSW1_V_CC 28 /* cond codes */ +#define PSW1_M_CC 0xF +#define CC1 0x8 +#define CC2 0x4 +#define CC3 0x2 +#define CC4 0x1 +#define PSW1_V_FR 27 /* fp mode controls */ +#define PSW1_V_FS 26 +#define PSW1_V_FZ 25 +#define PSW1_V_FN 24 +#define PSW1_V_FPC 24 /* as a group */ +#define PSW1_M_FPC 0xF +#define PSW1_FPC (PSW1_M_FPC << PSW1_V_FPC) +#define PSW1_V_MS 23 /* master/slave */ +#define PSW1_V_MM 22 /* memory map */ +#define PSW1_V_DM 21 /* decimal trap */ +#define PSW1_V_AM 20 /* arithmetic trap */ +#define PSW1_V_AS 19 /* EBCDIC/ASCII, S9 */ +#define PSW1_V_XA 15 /* ext addr flag, S9 */ +#define PSW1_V_PC 0 /* PC */ +#define PSW1_M_PC (VAMASK) +#define PSW1_FR (1u << PSW1_V_FR) +#define PSW1_FS (1u << PSW1_V_FS) +#define PSW1_FZ (1u << PSW1_V_FZ) +#define PSW1_FN (1u << PSW1_V_FN) +#define PSW1_MS (1u << PSW1_V_MS) +#define PSW1_MM (1u << PSW1_V_MM) +#define PSW1_DM (1u << PSW1_V_DM) +#define PSW1_AM (1u << PSW1_V_AM) +#define PSW1_AS (1u << PSW1_V_AS) +#define PSW1_XA (1u << PSW1_V_XA) +#define PSW1_CCMASK (PSW1_M_CC << PSW1_V_CC) +#define PSW1_PCMASK (PSW1_M_PC << PSW1_V_PC) +#define PSW1_GETCC(x) (((x) >> PSW1_V_CC) & PSW1_M_CC) +#define PSW1_GETPC(x) (((x) >> PSW1_V_PC) & PSW1_M_PC) +#define PSW1_DFLT 0 + +/* PSW2 fields */ + +#define PSW2_V_WLK 28 /* write key */ +#define PSW2_M_WLK 0xF +#define PSW2_V_CI 26 /* counter int inhibit */ +#define PSW2_V_II 25 /* IO int inhibit */ +#define PSW2_V_EI 24 /* external int inhibit */ +#define PSW2_V_INH (PSW2_V_EI) /* inhibits as a group */ +#define PSW2_M_INH 0x7 +#define PSW2_V_MA9 23 /* mode altered, S9 */ +#define PSW2_V_EA 16 /* ext addr, S9 */ +#define PSW2_M_EA 0x3F +#define PSW2_EA (PSW2_M_EA << PSW2_V_EA) +#define PSW2_V_TSF 8 /* trapped status, S9 */ +#define PSW2_M_TSF 0xFF +#define PSW2_TSF (PSW2_M_TSF << PSW2_V_TSF) +#define PSW2_V_RP 4 /* register block ptr */ +#define PSW2_M_RP5B 0x1F +#define PSW2_M_RP4B 0xF +#define PSW2_RP ((QCPU_S567? PSW2_M_RP5B: PSW2_M_RP4B) << PSW2_V_RP) +#define PSW2_V_RA 3 /* reg altered, 9,5X0 */ +#define PSW2_V_MA5X0 2 /* mode altered, 5X0 */ +#define PSW2_CI (1u << PSW2_V_CI) +#define PSW2_II (1u << PSW2_V_II) +#define PSW2_EI (1u << PSW2_V_EI) +#define PSW2_ALLINH (PSW2_CI|PSW2_II|PSW2_EI) /* all inhibits */ +#define PSW2_MA9 (1u << PSW2_V_MA9) +#define PSW2_RA (1u << PSW2_V_RA) +#define PSW2_MA5X0 (1u << PSW2_V_MA5X0) +#define PSW2_WLKMASK (PSW2_M_WLK << PSW2_V_WLK) +#define PSW2_RPMASK (PSW2_M_RP << PSW2_V_RP) +#define PSW2_GETINH(x) (((x) >> PSW2_V_INH) & PSW2_M_INH); +#define PSW2_GETWLK(x) (((x) >> PSW2_V_WLK) & PSW2_M_WLK) +#define PSW2_GETRP(x) (((x) & PSW2_RP) >> PSW2_V_RP) +#define PSW2_DFLT 0 + +/* Stack pointers */ + +#define SP_V_TS 31 /* space trap enable */ +#define SP_TS (1u << SP_V_TS) +#define SP_V_SPC 16 /* space */ +#define SP_M_SPC 0x7FFF +#define SP_V_TW 15 /* words trap enable */ +#define SP_TW (1u << SP_V_TW) +#define SP_V_WDS 0 /* words */ +#define SP_M_WDS 0x7FFF +#define SP_GETSPC(x) (((x) >> SP_V_SPC) & SP_M_SPC) +#define SP_GETWDS(x) (((x) >> SP_V_WDS) & SP_M_WDS) + +/* System stack pointer (5X0 only) */ + +#define SSP_TOS 0 /* system stack */ +#define SSP_SWC 1 /* space/word count */ +#define SSP_DFLT_PSW1 2 /* default PSD */ +#define SSP_DFLT_PSW2 3 +#define SSP_FR_LNT 28 /* frame length */ +#define SSP_FR_RN 0 /* registers */ +#define SSP_FR_PSW1 24 /* PSD */ +#define SSP_FR_PSW2 25 +#define SSP_FR_PSW4 27 + +/* The Sigma series had word addressable memory, but byte addressable + data. Virtual addresses in the simulator are BYTE addresses, and + these definitions are in terms of a byte address (word << 2). */ + +#define VA_NUM_PAG (1 << (VASIZE - (BVA_V_PAG - 2))) +#define PA_NUM_PAG (1 << (PASIZE22 - (BVA_V_PAG - 2))) +#define BVA_V_OFF 0 /* offset */ +#define BVA_M_OFF 0x7FF +#define BVA_V_PAG 11 /* page */ +#define BVA_M_PAG 0xFF +#define BVA_GETOFF(x) (((x) >> BVA_V_OFF) & BVA_M_OFF) +#define BVA_GETPAG(x) (((x) >> BVA_V_PAG) & BVA_M_PAG) +#define BPA_V_PAG (BVA_V_PAG) /* phys page */ +#define BPA_M_PAG 0x1FFF +#define BPA_GETPAG(x) (((x) >> BPA_V_PAG) & BPA_M_PAG) + +/* Memory maps */ + +#define MMC_V_CNT 24 /* count */ +#define MMC_M_CNT 0xFF +#define MMC_CNT (MMC_M_CNT << MMC_V_CNT) +#define MMC_V_CS 9 /* start of page */ +/* /* map 1: 2b locks, per model */ +#define MMC_M_CS2 0xFC /* map 2: access controls */ +#define MMC_M_CS3 0x7FE /* map 3: 4b locks */ +#define MMC_M_CS4 0xFF /* map 4: 8b relocation */ +#define MMC_M_CS5 0xFF /* map 5: 13b relocation */ +#define MMC_GETCNT(x) (((x) >> MMC_V_CNT) & MMC_M_CNT) +#define MMC_L_CS1 (VA_NUM_PAG) /* map lengths */ +#define MMC_L_CS2 (VA_NUM_PAG) +#define MMC_L_CS3 (PA_NUM_PAG) +#define MMC_L_CS4 (VA_NUM_PAG) +#define MMC_L_CS5 (VA_NUM_PAG) + +/* Trap codes */ + +#define TR_V_FL 17 /* trap flag */ +#define TR_FL (1u << TR_V_FL) +#define TR_V_PDF 16 /* proc detected fault */ +#define TR_PDF (1u << TR_V_FL) +#define TR_V_CC 12 /* or'd to CC/addr offset */ +#define TR_M_CC 0xF +#define TR_V_VEC 0 /* trap address */ +#define TR_M_VEC 0xFFF +#define TR_GETVEC(x) (((x) >> TR_V_VEC) & TR_M_VEC) +#define TR_GETCC(x) (((x) >> TR_V_CC) & TR_M_CC) + +#define TR_NXI (TR_FL|0x8040) /* non-existent inst */ +#define TR_NXM (TR_FL|0x4040) /* non-existent memory */ +#define TR_PRV (TR_FL|0x2040) /* privileged inst */ +#define TR_MPR (TR_FL|0x1040) /* mem protect violation */ +#define TR_WLK (TR_FL|0x3040) /* write lock (5x0 only) */ +#define TR_UNI (TR_FL|0x0041) /* unimplemented inst */ +#define TR_PSH (TR_FL|0x0042) /* pushdown overflow */ +#define TR_FIX (TR_FL|0x0043) /* fixed point arith */ +#define TR_FLT (TR_FL|0x0044) /* floating point arith */ +#define TR_DEC (TR_FL|0x0045) /* decimal arithmetic */ +#define TR_WAT (TR_FL|0x0046) /* watchdog timer */ +#define TR_47 (TR_FL|0x0047) /* 5X0 - WD trap */ +#define TR_C1(x) (TR_FL|0x0048|((x) << TR_V_CC)) /* call instruction */ +#define TR_C2(x) (TR_FL|0x0049|((x) << TR_V_CC)) /* call instruction */ +#define TR_C3(x) (TR_FL|0x004A|((x) << TR_V_CC)) /* call instruction */ +#define TR_C4(x) (TR_FL|0x004B|((x) << TR_V_CC)) /* call instruction */ +#define TR_NESTED (TR_FL|TR_PDF|0xF04D) /* 9,5X0 - fault in inv/trap */ +#define TR_INVTRP (TR_FL|TR_PDF|0xC04D) /* 9,5X0 - inv int/trap inst */ +#define TR_INVRPT (TR_FL|TR_PDF|0x804D) /* 9 - inv new RP in trap */ +#define TR_INVSSP (TR_FL|TR_PDF|0x404D) /* 5X0 - inv SSP for PLS */ +#define TR_INVMMC (TR_FL|TR_PDF|0x204D) /* 9,5X0 - inv MMC config */ +#define TR_INVREG (TR_FL|0x104D) /* 9,5x0 - inv reg num */ +#define TR_INVRPN (TR_FL|TR_PDF|0x004D) /* 9 - inv new RP, non-trap */ + +/* Effective address and memory access routines interface + + The access types are defined to make the following equation work: + + trap if ((access_type != 0) && (access_control >= access_type)) + + The length codes are defined so that length in bytes = 1 << length_code */ + +#define PH 0x0 /* physical */ +#define VW 0x1 /* write */ +#define VI 0x2 /* instruction */ +#define VR 0x3 /* read */ +#define VNT 0x4 /* no traps */ + +#define BY 0x0 /* byte */ +#define HW 0x1 /* halfword */ +#define WD 0x2 /* word */ +#define DW 0x3 /* doubleword */ + +/* Interrupt groups - the Sigma's have flexibly configured interrupt groups + of various widths that map non-uniformly to control register bits */ + +typedef struct { + uint32 psw2_inh; /* PSW2 inhibit */ + uint32 nbits; /* number of bits */ + uint32 vecbase; /* vector base */ + uint32 rwgroup; /* RWdirect group */ + uint32 regbit; /* RWdirect reg bit */ + } int_grp_t; + +#define INTG_MAX 17 /* max # int groups */ +#define EIGRP_DFLT 1 /* dflt # ei groups */ +#define INTG_OVR 0 /* override group */ +#define INTG_CTR 1 /* counter group */ +#define INTG_IO 2 /* I/O group */ +#define INTGIO_IO 0x2 /* I/O interrupt */ +#define INTGIO_PANEL 0x1 /* panel interrupt */ +#define INTG_E2 3 /* ext group 2 */ +#define INTG_E3 4 /* ext group 3 */ + +#define INT_V_GRP 4 /* interrupt group */ +#define INT_M_GRP 0x1F +#define INT_V_BIT 0 /* interrupt bit */ +#define INT_M_BIT 0xF +#define INT_GETGRP(x) (((x) >> INT_V_GRP) & INT_M_GRP) +#define INT_GETBIT(x) (((x) >> INT_V_BIT) & INT_M_BIT) +#define INTV(x,y) (((x) << INT_V_GRP) | ((y) << INT_V_BIT)) +#define NO_INT (INTV (INTG_MAX, 0)) + +#define VEC_C1P 0x52 /* clock pulse vectors */ +#define VEC_C4P 0x55 +#define VEC_C1Z 0x58 /* clock zero vector */ + +/* Integer data operations and condition codes */ + +#define SEXT_RN_W(x) (((x) & RNSIGN)? ((x) | ~RNMASK): ((x) & RNMASK)) +#define SEXT_H_W(x) (((x) & HSIGN)? ((x) | ~HMASK): ((x) & HMASK)) +#define SEXT_LIT_W(x) (((x) & LITSIGN)? ((x) | ~LITMASK): ((x) & LITMASK)) +#define NEG_W(x) ((~(x) + 1) & WMASK) +#define NEG_D(x,y) do { y = NEG_W(y); x = (~(x) + ((y) == 0)) & WMASK; } while (0) +#define CC34_W(x) CC = (((x) & WSIGN)? \ + ((CC & ~CC3) | CC4): \ + (((x) != 0)? \ + ((CC & ~CC4) | CC3): \ + (CC & ~(CC3|CC4)))) +#define CC234_CMP(x,y) CC = (CC & CC1) | Cmp32 ((x), (y)) | \ + (((x) & (y))? CC2: 0) + +/* Instructions */ + +enum opcodes { + OP_00, OP_01, OP_LCFI, OP_03, OP_CAL1, OP_CAL2, OP_CAL3, OP_CAL4, + OP_PLW, OP_PSW, OP_PLM, OP_PSM, OP_PLS, OP_PSS, OP_LPSD, OP_XPSD, + OP_AD, OP_CD, OP_LD, OP_MSP, OP_14, OP_STD, OP_16, OP_17, + OP_SD, OP_CLM, OP_LCD, OP_LAD, OP_FSL, OP_FAL, OP_FDL, OP_FML, + OP_AI, OP_CI, OP_LI, OP_MI, OP_SF, OP_S, OP_LAS, OP_27, + OP_CVS, OP_CVA, OP_LM, OP_STM, OP_LRA, OP_LMS, OP_WAIT, OP_LRP, + OP_AW, OP_CW, OP_LW, OP_MTW, OP_LVAW, OP_STW, OP_DW, OP_MW, + OP_SW, OP_CLR, OP_LCW, OP_LAW, OP_FSS, OP_FAS, OP_FDS, OP_FMS, + OP_TTBS, OP_TBS, OP_42, OP_43, OP_ANLZ, OP_CS, OP_XW, OP_STS, + OP_EOR, OP_OR, OP_LS, OP_AND, OP_SIO, OP_TIO, OP_TDV, OP_HIO, + OP_AH, OP_CH, OP_LH, OP_MTH, OP_54, OP_STH, OP_DH, OP_MH, + OP_SH, OP_59, OP_LCH, OP_LAH, OP_5C, OP_5D, OP_5E, OP_5F, + OP_CBS, OP_MBS, OP_62, OP_EBS, OP_BDR, OP_BIR, OP_AWM, OP_EXU, + OP_BCR, OP_BCS, OP_BAL, OP_INT, OP_RD, OP_WD, OP_AIO, OP_MMC, + OP_LCF, OP_CB, OP_LB, OP_MTB, OP_STCF, OP_STB, OP_PACK, OP_UNPK, + OP_DS, OP_DA, OP_DD, OP_DM, OP_DSA, OP_DC, OP_DL, OP_DST + }; + +/* Function prototypes */ + +uint32 Ea (uint32 ir, uint32 *bva, uint32 acc, uint32 lnt); +uint32 ReadB (uint32 bva, uint32 *dat, uint32 acc); +uint32 ReadH (uint32 bva, uint32 *dat, uint32 acc); +uint32 ReadW (uint32 bva, uint32 *dat, uint32 acc); +uint32 ReadD (uint32 bva, uint32 *dat, uint32 *dat1, uint32 acc); +uint32 WriteB (uint32 bva, uint32 dat, uint32 acc); +uint32 WriteH (uint32 bva, uint32 dat, uint32 acc); +uint32 WriteW (uint32 bva, uint32 dat, uint32 acc); +uint32 WriteD (uint32 bva, uint32 dat, uint32 dat1, uint32 acc); +uint32 ReadMemVW (uint32 bva, uint32 *dat, uint32 acc); +uint32 WriteMemVW (uint32 bva, uint32 dat, uint32 acc); +uint32 ReadPB (uint32 ba, uint32 *dat); +uint32 WritePB (uint32 ba, uint32 dat); +uint32 ReadPW (uint32 pa, uint32 *dat); +uint32 WritePW (uint32 pa, uint32 dat); +uint32 ReadHist (uint32 bva, uint32 *dat, uint32 *dat1, uint32 acc, uint32 lnt); + +#endif \ No newline at end of file diff --git a/sigma/sigma_disks.txt b/sigma/sigma_disks.txt new file mode 100644 index 00000000..c8256270 --- /dev/null +++ b/sigma/sigma_disks.txt @@ -0,0 +1,193 @@ +Notes for the Sigma Disk Controllers + +Two patterns of disk controllers - "10 byte" sense controllers and "16 byte" sense controllers +All disks have 1024B (256W) sectors + + +model units/cylinders/heads/sectors type + +7240/7242 8 / 203 (3 spare) / 20 / 6 10 byte 24360 +7260/7261 15 / 203 (3 spare) / 20 / 11 16 byte 44660 +7270/7271 8 / 406 (6 spare) / 20 / 6 10 byte 48720 +7275/7276 15 / 411 (7 spare) / 19 / 11 16 byte 85899 +7265/7266 15 / 411 (7 spare) / 20 / 11 16 byte 90420 + +T3281/T3282 15 / 815 / 19 / 11 16 byte 170335 +T3281/T3283 15 / 815 / 19 / 17 16 byte 263245 +T3281/T3286 15 / 555 / 30 / 17 (16?) 16 byte +T3281/T3286F 15 / 555 / 60 / 17 (16?) 16 byte +T3281/T3288 15 / 822 / 5 / 17 16 byte 69870 + +header format 7240 726X/727X/T3281 + +bytes 0-3 flaw / 0 / C / H flaw / 0'CH / C / H +bytes 4-7 S / alt C / alt H / 0 S / alt CH / alt CL'alt H / 0 + + +sense status 7240/7270 + +bytes 0-3 0'CH / C / H / S most recent address +bytes 4-7 M'CS / diag / diag / diag seek intr + current sector +bytes 8-11 stat / stat + + 726X/7275 + +bytes 0-3 W'0'CH / C / H / S W = write protect, most recent address +bytes 4-7 M'R'CS / cnf / stat / 0 M = modifier, R = reserve/release mode +bytes 8-11 stat / stat / modi / fiers +bytes 12-15 check / bytes / 0'dh / dl 14-15 = difference + +sense byte 5-6 + + 7240,7270 + +0-15 header parity check bytes + + 726X, 7275, T3281 + +0 1 for dual access +1-3 device type + 5 = 7261 + 6 = 7266 + 7 = 7276, T3286 +4-7 device physical addr (cable position) + +0 device fault +1 write fault +2 loss of on cylinder +3 offset polarity +4 airflow loss +5 parity error on device ID byte +6 spindle speed fault +7 positioning servo faulT + +sense byte 7 + + 7240, 7270 726X, 7275 T3281 + +0-7 LSB of difference 0 physical address (unique) + +sense bytes 8-9 + + 7240, 7270 726X, 7275, T3281 + +0 data parity error check write error +1 check write error data check error +2 sector verif error IOP parity error +3 head verif error data overrun +4 cylinder verif error head addr incr err +5 sec addr !=0 @ hdr wr arm in motion err +6 diff sent to device order parity err +7 sector sel to device test mode err + +0 ctrl sel to device seek transfer err +1 head sel to device device unavailable +2 cyl sel sent to device head addr ver err +3 seek forward set sector addr ver err +4 read gate to device cyl addr ver err +5 write/erase to device 726X, 7275: 0 + T3281: ctrl overtemp +6 read cyl sel to device channel addr err +7 7240: not used missing on sect + 7270: MSB of diff + +sense bytes 10+ + +10-11 modifier bits +12-13 check bytes +14 0'diff high +15 diff low (absolute value) + + +operations 7240 726X + 7270 7275 + T3281 + +01 write x x +02 read 2 x x +03 seek x x +04 sense x x +05 check-write x x +07 reserve x +09 header write x x +0A header read x x +0F condition rls intr x +12 read 1 x x +13 select test mode x x +17 release x +1F condition rls intr x +23 release x +33 restore x x +83 seek with interrupt x x +B3 restore with interrupt x + + +TIO, SIO, HIO status + + all + +0 interrupt pending +1-2 device state + 00 = ready + 01 = not operational + 10 = reserved + 11 = busy +3 1 (automatic) +4 unusual end +5-6 controller state + 00 = ready + 01,10 = n/a + 11 = busy +7 0 + +TDV status + + 7240, 7270 726X,7275 T3281 + +0 data overrun 0 error corrected +1 flaw mark flaw mark flaw mark +2 sector unavailable programming err programming err +3 0 write prot err write prot err +4 header verif error IOP parity err IOP parity err +5 on cylinder operational err operational err +6 seek timeout error verification err verification err +7 header parity error header parity err header parity err + +AIO status + + 7240, 7270 726X, 7275, T3281 + +0 data overrun data overrun +1 0 attn int ack +2 0 rls int ack +3 0 0 +4 on sector interrupt on sector intr +5 on cylinder 0 +6 seek timeout error seek timeout error +7 0 0 + +operational status byte (SIO, HIO, TIO, TDV) + + all + +8 incorrect lnt +9 xmit data error +10 xmit memory err +11 mem addr err +12 IOP memory err +13 IOP ctrl err +14 IOP halt +15 0 + +operational status byte (AIO) + + all + +8 incorrect lnt +9 xmit data error +10 zero byte cnt intr +11 channel end intr +12 unusual end intr +13-15 0 + + diff --git a/sigma/sigma_dk.c b/sigma/sigma_dk.c new file mode 100644 index 00000000..728c8a2a --- /dev/null +++ b/sigma/sigma_dk.c @@ -0,0 +1,470 @@ +/* sigma_dk.c: 7250/7251-7252 cartridge disk simulator + + Copyright (c) 2007-2008, Robert M Supnik + + 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 + ROBERT M SUPNIK 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 Robert M Supnik shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + + dk 7250/7251-7252 cartridge disk + + Transfers are always done a sector at a time. +*/ + +#include "sigma_io_defs.h" +#include + +#define UNIT_V_HWLK (UNIT_V_UF + 0) /* hwre write lock */ +#define UNIT_HWLK (1u << UNIT_V_HWLK) +#define UNIT_WPRT (UNIT_HWLK|UNIT_RO) /* write prot */ +#define UTRK u3 /* current track */ + +/* Constants */ + +#define DK_NUMDR 8 /* drives/ctlr */ +#define DK_WDSC 90 /* words/sector */ +#define DK_SCTK 16 /* sectors/track */ +#define DK_TKUN 408 /* tracks/unit */ +#define DK_WDUN (DK_WDSC*DK_SCTK*DK_TKUN) /* words/unit */ + +/* Address bytes */ + +#define DKA_V_TK 4 /* track offset */ +#define DKA_M_TK 0x1FF +#define DKA_V_SC 0 /* sector offset */ +#define DKA_M_SC 0xF +#define DKA_GETTK(x) (((x) >> DKA_V_TK) & DKA_M_TK) +#define DKA_GETSC(x) (((x) >> DKA_V_SC) & DKA_M_SC) + +/* Status byte 3 is current sector */ + +#define DKS_NBY 3 + +/* Device state */ + +#define DKS_INIT 0x101 +#define DKS_END 0x102 +#define DKS_WRITE 0x01 +#define DKS_READ 0x02 +#define DKS_SEEK 0x03 +#define DKS_SEEK2 0x103 +#define DKS_SENSE 0x04 +#define DKS_CHECK 0x05 +#define DKS_RDEES 0x12 +#define DKS_TEST 0x13 + +/* Device status */ + +#define DKV_OVR 0x80 /* overrun - NI */ +#define DKV_BADS 0x20 /* bad track */ +#define DKV_WPE 0x10 + +#define GET_PSC(x) ((int32) fmod (sim_gtime() / ((double) (x * DK_WDSC)), \ + ((double) DK_SCTK))) + +uint32 dk_cmd = 0; /* state */ +uint32 dk_flags = 0; /* status flags */ +uint32 dk_ad = 0; /* disk address */ +uint32 dk_time = 5; /* inter-word time */ +uint32 dk_stime = 20; /* inter-track time */ +uint32 dk_stopioe = 1; /* stop on I/O error */ + +extern uint32 chan_ctl_time; + +uint32 dk_disp (uint32 op, uint32 dva, uint32 *dvst); +uint32 dk_tio_status (uint32 un); +uint32 dk_tdv_status (uint32 un); +t_stat dk_chan_err (uint32 st); +t_stat dk_svc (UNIT *uptr); +t_stat dk_reset (DEVICE *dptr); +t_bool dk_inv_ad (uint32 *da); +t_bool dk_inc_ad (void); +t_bool dk_end_sec (UNIT *uptr, uint32 lnt, uint32 exp, uint32 st); + +/* DK data structures + + dk_dev DK device descriptor + dk_unit DK unit descriptor + dk_reg DK register list +*/ + +dib_t dk_dib = { DVA_DK, &dk_disp }; + +UNIT dk_unit[] = { + { UDATA (&dk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_BUFABLE+UNIT_MUSTBUF, DK_WDUN) }, + { UDATA (&dk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_BUFABLE+UNIT_MUSTBUF, DK_WDUN) }, + { UDATA (&dk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_BUFABLE+UNIT_MUSTBUF, DK_WDUN) }, + { UDATA (&dk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_BUFABLE+UNIT_MUSTBUF, DK_WDUN) }, + { UDATA (&dk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_BUFABLE+UNIT_MUSTBUF, DK_WDUN) }, + { UDATA (&dk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_BUFABLE+UNIT_MUSTBUF, DK_WDUN) }, + { UDATA (&dk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_BUFABLE+UNIT_MUSTBUF, DK_WDUN) }, + { UDATA (&dk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_BUFABLE+UNIT_MUSTBUF, DK_WDUN) } + }; + +REG dk_reg[] = { + { HRDATA (CMD, dk_cmd, 9) }, + { HRDATA (FLAGS, dk_flags, 8) }, + { HRDATA (ADDR, dk_ad, 8) }, + { DRDATA (TIME, dk_time, 24), PV_LEFT+REG_NZ }, + { DRDATA (STIME, dk_stime, 24), PV_LEFT+REG_NZ }, + { FLDATA (STOPIOE, dk_stopioe, 0) }, + { HRDATA (DEVNO, dk_dib.dva, 12), REG_HRO }, + { NULL } + }; + +MTAB dk_mod[] = { + { UNIT_HWLK, 0, "write enabled", "WRITEENABLED", NULL }, + { UNIT_HWLK, UNIT_HWLK, "write locked", "LOCKED", NULL }, + { MTAB_XTD|MTAB_VDV, 0, "CHAN", "CHAN", + &io_set_dvc, &io_show_dvc, NULL }, + { MTAB_XTD|MTAB_VDV, 0, "DVA", "DVA", + &io_set_dva, &io_show_dva, NULL }, + { MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "CSTATE", NULL, + NULL, &io_show_cst, NULL }, + { 0 } + }; + +DEVICE dk_dev = { + "DK", dk_unit, dk_reg, dk_mod, + DK_NUMDR, 16, 22, 1, 16, 32, + NULL, NULL, &dk_reset, + NULL, NULL, NULL, + &dk_dib, DEV_DISABLE + }; + +/* DK: IO dispatch routine */ + +uint32 dk_disp (uint32 op, uint32 dva, uint32 *dvst) +{ +uint32 i; +uint32 un = DVA_GETUNIT (dva); +UNIT *uptr; + +if ((un >= DK_NUMDR) || /* inv unit num? */ + (dk_unit[un].flags & UNIT_DIS)) /* disabled unit? */ + return DVT_NODEV; +switch (op) { /* case on op */ + + case OP_SIO: /* start I/O */ + *dvst = dk_tio_status (un); /* get status */ + if ((*dvst & (DVS_CST|DVS_DST)) == 0) { /* ctrl + dev idle? */ + dk_cmd = DKS_INIT; /* start dev thread */ + sim_activate (&dk_unit[un], chan_ctl_time); + } + break; + + case OP_TIO: /* test status */ + *dvst = dk_tio_status (un); /* return status */ + break; + + case OP_TDV: /* test status */ + *dvst = dk_tdv_status (un); /* return status */ + break; + + case OP_HIO: /* halt I/O */ + chan_clr_chi (dk_dib.dva); /* clr int */ + *dvst = dk_tio_status (un); /* get status */ + if ((*dvst & DVS_CST) != 0) { /* ctrl busy? */ + for (i = 0; i < DK_NUMDR; i++) { /* find busy unit */ + uptr = &dk_unit[i]; + if (sim_is_active (uptr)) { /* active? */ + sim_cancel (uptr); /* stop */ + chan_uen (dk_dib.dva); /* uend */ + } /* end if active */ + } /* end for */ + } + break; + + case OP_AIO: /* acknowledge int */ + chan_clr_chi (dk_dib.dva); /* clr int */ + *dvst = dk_tdv_status (un); /* status like TDV */ + break; + + default: + *dvst = 0; + return SCPE_IERR; + } + +return 0; +} + +/* Unit service */ + +t_stat dk_svc (UNIT *uptr) +{ +uint32 i, sc, da, wd, wd1, cmd, c[3]; +uint32 *fbuf = (uint32 *) uptr->filebuf; +int32 t, dc; +uint32 st; + +switch (dk_cmd) { + + case DKS_INIT: /* init state */ + st = chan_get_cmd (dk_dib.dva, &cmd); /* get command */ + if (CHS_IFERR (st)) /* channel error? */ + return dk_chan_err (st); + if ((cmd == 0) || /* invalid cmd? */ + ((cmd > DKS_CHECK) && (cmd != DKS_RDEES) && (cmd != DKS_TEST))) { + chan_uen (dk_dib.dva); /* uend */ + return SCPE_OK; + } + dk_flags = 0; /* clear status */ + dk_cmd = cmd & 0x17; /* next state */ + if ((cmd == DKS_SEEK) || /* fast cmd? */ + (cmd == DKS_SENSE) || + (cmd == DKS_TEST)) + sim_activate (uptr, chan_ctl_time); /* schedule soon */ + else { /* data transfer */ + sc = DKA_GETSC (dk_ad); /* new sector */ + t = sc - GET_PSC (dk_time); /* delta to new */ + if (t < 0) /* wrap around? */ + t = t + DK_SCTK; + sim_activate (uptr, t * dk_time * DK_WDSC); /* schedule op */ + } + return SCPE_OK; + + case DKS_END: /* end state */ + st = chan_end (dk_dib.dva); /* set channel end */ + if (CHS_IFERR (st)) /* channel error? */ + return dk_chan_err (st); + if (st == CHS_CCH) { /* command chain? */ + dk_cmd = DKS_INIT; /* restart thread */ + sim_activate (uptr, chan_ctl_time); + } + return SCPE_OK; /* done */ + + case DKS_SEEK: /* seek */ + c[0] = c[1] = 0; + for (i = 0, st = 0; (i < 2) && (st != CHS_ZBC); i++) { + st = chan_RdMemB (dk_dib.dva, &c[i]); /* get byte */ + if (CHS_IFERR (st)) /* channel error? */ + return dk_chan_err (st); + } + dk_ad = ((c[0] & 0x7F) << 8) | c[1]; /* new address */ + if (((i != 2) || (st != CHS_ZBC)) && /* length error? */ + chan_set_chf (dk_dib.dva, CHF_LNTE)) /* care? */ + return SCPE_OK; + dc = DKA_GETTK (dk_ad); /* desired track */ + t = abs (uptr->UTRK - dc); /* get track diff */ + if (t == 0) + t = 1; + sim_activate (uptr, t * dk_stime); + uptr->UTRK = dc; /* put on track */ + dk_cmd = DKS_SEEK2; + return SCPE_OK; + + case DKS_SEEK2: /* seek complete */ + if (uptr->UTRK >= DK_TKUN) { + dk_flags |= DKV_BADS; + chan_uen (dk_dib.dva); + return SCPE_OK; + } + break; /* seek done */ + + case DKS_SENSE: /* sense */ + c[0] = ((dk_ad >> 8) & 0x7F) | ((uptr->flags & UNIT_RO)? 0x80: 0); + c[1] = dk_ad & 0xFF; /* address */ + c[2] = GET_PSC (dk_time); /* curr sector */ + for (i = 0, st = 0; (i < DKS_NBY) && (st != CHS_ZBC); i++) { + st = chan_WrMemB (dk_dib.dva, c[i]); /* store char */ + if (CHS_IFERR (st)) /* channel error? */ + return dk_chan_err (st); + } + if (((i != DKS_NBY) || (st != CHS_ZBC)) && + chan_set_chf (dk_dib.dva, CHF_LNTE)) /* length error? */ + return SCPE_OK; + break; + + case DKS_WRITE: /* write */ + if (uptr->flags & UNIT_RO) { /* write locked? */ + dk_flags |= DKV_WPE; /* set status */ + chan_uen (dk_dib.dva); /* uend */ + return SCPE_OK; + } + if (dk_inv_ad (&da)) { /* invalid addr? */ + chan_uen (dk_dib.dva); /* uend */ + return SCPE_OK; + } + for (i = 0, st = 0; i < DK_WDSC; da++, i++) { /* sector loop */ + if (st != CHS_ZBC) { /* chan not done? */ + st = chan_RdMemW (dk_dib.dva, &wd); /* read word */ + if (CHS_IFERR (st)) { /* channel error? */ + dk_inc_ad (); /* da increments */ + return dk_chan_err (st); + } + } + else wd = 0; + fbuf[da] = wd; /* store in buffer */ + if (da >= uptr->hwmark) /* update length */ + uptr->hwmark = da + 1; + } + if (dk_end_sec (uptr, i, DK_WDSC, st)) /* transfer done? */ + return SCPE_OK; /* err or cont */ + break; + +/* Must be done by bytes to get precise miscompare */ + + case DKS_CHECK: /* write check */ + if (dk_inv_ad (&da)) { /* invalid addr? */ + chan_uen (dk_dib.dva); /* uend */ + return SCPE_OK; + } + for (i = 0, st = 0; (i < (DK_WDSC * 4)) && (st != CHS_ZBC); ) { + st = chan_RdMemB (dk_dib.dva, &wd); /* read byte */ + if (CHS_IFERR (st)) { /* channel error? */ + dk_inc_ad (); /* da increments */ + return dk_chan_err (st); + } + wd1 = (fbuf[da] >> (24 - ((i % 4) * 8))) & 0xFF; /* byte */ + if (wd != wd1) { /* check error? */ + dk_inc_ad (); /* da increments */ + chan_set_chf (dk_dib.dva, CHF_XMDE); /* set xmt err flag */ + chan_uen (dk_dib.dva); /* force uend */ + return SCPE_OK; + } + da = da + ((++i % 4) == 0); /* every 4th byte */ + } + if (dk_end_sec (uptr, i, DK_WDSC * 4, st)) /* transfer done? */ + return SCPE_OK; /* err or cont */ + break; + + case DKS_READ: /* read */ + if (dk_inv_ad (&da)) { /* invalid addr? */ + chan_uen (dk_dib.dva); /* uend */ + return SCPE_OK; + } + for (i = 0, st = 0; (i < DK_WDSC) && (st != CHS_ZBC); da++, i++) { + st = chan_WrMemW (dk_dib.dva, fbuf[da]); /* store in mem */ + if (CHS_IFERR (st)) { /* channel error? */ + dk_inc_ad (); /* da increments */ + return dk_chan_err (st); + } + } + if (dk_end_sec (uptr, i, DK_WDSC, st)) /* transfer done? */ + return SCPE_OK; /* err or cont */ + break; + } + +dk_cmd = DKS_END; /* op done, next state */ +sim_activate (uptr, chan_ctl_time); +return SCPE_OK; +} + +/* Common read/write sector end routine + + case 1 - more to transfer, not end disk - reschedule, return TRUE + case 2 - more to transfer, end disk - uend, return TRUE + case 3 - transfer done, length error - uend, return TRUE + case 4 - transfer done, no length error - return FALSE (sched end state) +*/ + +t_bool dk_end_sec (UNIT *uptr, uint32 lnt, uint32 exp, uint32 st) +{ +if (st != CHS_ZBC) { /* end record? */ + if (dk_inc_ad ()) /* inc addr, ovf? */ + chan_uen (dk_dib.dva); /* uend */ + else sim_activate (uptr, dk_time * 16); /* no, next sector */ + return TRUE; + } +dk_inc_ad (); /* just incr addr */ +if ((lnt != exp) && /* length error? */ + chan_set_chf (dk_dib.dva, CHF_LNTE)) /* do we care? */ + return TRUE; +return FALSE; /* cmd done */ +} + +/* DK status routine */ + +uint32 dk_tio_status (uint32 un) +{ +uint32 i; + +for (i = 0; i < DK_NUMDR; i++) { /* loop thru units */ + if (sim_is_active (&dk_unit[i])) /* active? */ + return (DVS_AUTO | DVS_CBUSY | (CC2 << DVT_V_CC) | + ((i == un)? DVS_DBUSY: 0)); + } +return DVS_AUTO; +} + +uint32 dk_tdv_status (uint32 un) +{ +return dk_flags | (dk_inv_ad (NULL)? DKV_BADS: 0); +} + +/* Validate disk address */ + +t_bool dk_inv_ad (uint32 *da) +{ +uint32 tk = DKA_GETTK (dk_ad); +uint32 sc = DKA_GETSC (dk_ad); + +if (tk >= DK_TKUN) /* badtrk? */ + return TRUE; +if (da) /* return word addr */ + *da = ((tk * DK_SCTK) + sc) * DK_WDSC; +return FALSE; +} + +/* Increment disk address */ + +t_bool dk_inc_ad (void) +{ +uint32 tk = DKA_GETTK (dk_ad); +uint32 sc = DKA_GETSC (dk_ad); + +sc = sc + 1; /* sector++ */ +if (sc >= DK_SCTK) { /* overflow? */ + sc = 0; /* wrap sector */ + tk = tk + 1; /* track++ */ + } +dk_ad = ((tk << DKA_V_TK) | /* rebuild dk_ad */ + (sc << DKA_V_SC)); +if (tk >= DK_TKUN) /* invalid addr? */ + return TRUE; +return FALSE; +} + +/* Channel error */ + +t_stat dk_chan_err (uint32 st) +{ +chan_uen (dk_dib.dva); /* uend */ +if (st < CHS_ERR) + return st; +return SCPE_OK; +} + +/* Reset routine */ + +t_stat dk_reset (DEVICE *dptr) +{ +uint32 i; + +for (i = 0; i < DK_NUMDR; i++) { + sim_cancel (&dk_unit[i]); /* stop dev thread */ + dk_unit[i].UTRK = 0; + } +dk_cmd = 0; +dk_flags = 0; +dk_ad = 0; +chan_reset_dev (dk_dib.dva); /* clr int, active */ +return SCPE_OK; +} diff --git a/sigma/sigma_dp.c b/sigma/sigma_dp.c new file mode 100644 index 00000000..322a1b42 --- /dev/null +++ b/sigma/sigma_dp.c @@ -0,0 +1,1278 @@ +/* sigma_dp.c: 7270/T3281 disk pack controller + + Copyright (c) 2008, Robert M Supnik + + 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 + ROBERT M SUPNIK 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 Robert M Supnik shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + + dp 7270/T3281 disk pack controller + + Transfers are always done a sector at a time. +*/ + +#include "sigma_io_defs.h" +#include + +#define UNIT_V_HWLK (UNIT_V_UF + 0) /* hwre write lock */ +#define UNIT_HWLK (1u << UNIT_V_HWLK) +#define UNIT_WPRT (UNIT_HWLK|UNIT_RO) /* write prot */ +#define UNIT_V_AUTO (UNIT_V_UF + 1) /* autosize */ +#define UNIT_AUTO (1u << UNIT_V_AUTO) +#define UNIT_V_DTYPE (UNIT_V_UF + 2) /* drive type */ +#define UNIT_M_DTYPE 0x7 +#define UNIT_DTYPE (UNIT_M_DTYPE << UNIT_V_DTYPE) +#define UDA u3 /* disk addr */ +#define UCMD u4 /* current command */ +#define UCTX u5 /* ctrl/ctx index */ +#define GET_DTYPE(x) (((x) >> UNIT_V_DTYPE) & UNIT_M_DTYPE) + +/* Constants */ + +#define DP_NUMCTL 2 /* number of controllers */ +#define DP_C7270 0 /* 7270 ctrl */ +#define DP_C3281 1 /* 3281 ctrl */ +#define DP_NUMDR_7270 8 /* drives/ctrl */ +#define DP_NUMDR_3281 15 +#define DP_CONT DP_NUMDR_3281 /* ctrl's drive # */ +#define DP_WDSC 256 /* words/sector */ +#define DP_BYHD 8 /* byte/header */ +#define DP_NUMDR ((uint32) ((ctx->dp_ctype == DP_C7270)? DP_NUMDR_7270: DP_NUMDR_3281)) +#define DP_SEEK (DP_CONT + 1) + +/* Address bytes */ + +#define DPA_V_CY 16 /* cylinder offset */ +#define DPA_M_CY 0x3FF +#define DPA_V_HD 8 /* head offset */ +#define DPA_M_HD 0x1F +#define DPA_V_SC 0 /* sector offset */ +#define DPA_M_SC 0x1F +#define DPA_GETCY(x) (((x) >> DPA_V_CY) & DPA_M_CY) +#define DPA_GETHD(x) (((x) >> DPA_V_HD) & DPA_M_HD) +#define DPA_GETSC(x) (((x) >> DPA_V_SC) & DPA_M_SC) + +/* Sense order */ + +#define DPS_NBY_7270 10 +#define DPS_NBY_3281 16 +#define DPS_NBY ((uint32) ((ctx->dp_ctype == DP_C7270)? DPS_NBY_7270: DPS_NBY_3281)) + +/* Test mode */ + +#define DPT_NBY_7270 1 /* bytes/test mode spec */ +#define DPT_NBY_3281 2 +#define DPT_NBY ((uint32) ((ctx->dp_ctype == DP_C7270)? DPT_NBY_7270: DPT_NBY_3281)) + +/* Commands */ + +#define DPS_INIT 0x100 +#define DPS_END 0x101 +#define DPS_WRITE 0x01 +#define DPS_READ 0x02 +#define DPS_SEEK 0x03 +#define DPS_SEEKI 0x83 +#define DPS_SENSE 0x04 +#define DPS_CHECK 0x05 +#define DPS_RSRV 0x07 +#define DPS_WHDR 0x09 +#define DPS_RHDR 0x0A +#define DPS_CRIOF 0x0F +#define DPS_RDEES 0x12 +#define DPS_TEST 0x13 +#define DPS_RLS 0x17 +#define DPS_CRION 0x1F +#define DPS_RLSA 0x23 +#define DPS_RECAL 0x33 +#define DPS_RECALI 0xB3 + +/* Seek completion states */ + +#define DSC_SEEK 0x00 /* seeking */ +#define DSC_SEEKI 0x80 /* seeking, then int */ +#define DSC_SEEKW 0x01 /* waiting to int */ + +/* Device status - note that these are device independent */ + +#define DPF_V_WCHK 0 +#define DPF_V_DPE 1 +#define DPF_V_SNZ 2 +#define DPF_V_EOC 3 +#define DPF_V_IVA 4 +#define DPF_V_PGE 5 +#define DPF_V_WPE 6 +#define DPF_V_AIM 7 +#define DPF_WCHK (1u << DPF_V_WCHK) /* wrt chk error */ +#define DPF_DPE (1u << DPF_V_DPE) /* data error */ +#define DPF_SNZ (1u << DPF_V_SNZ) /* sec# != 0 */ +#define DPF_EOC (1u << DPF_V_EOC) /* end cylinder */ +#define DPF_IVA (1u << DPF_V_IVA) /* invalid addr */ +#define DPF_PGE (1u << DPF_V_PGE) /* prog error */ +#define DPF_WPE (1u << DPF_V_WPE) /* wrt prot err */ +#define DPF_AIM (1u << DPF_V_AIM) /* arm in motion */ +#define DPF_V_DIFF 16 +#define DPF_M_DIFF 0xFFFFu +#define DPF_DIFF (DPF_M_DIFF << DPF_V_DIFF) + +/* Drive types */ + +/* These controllers support many different disk drive types: + + type #sectors/ #surfaces/ #cylinders/ + surface cylinder drive + + 7242 6 20 204 + 7261 11 20 204 + 7271 6 20 408 + 3288 17 5 823 =67MB + 7275 11 19 411 =88MB + 7276 11 19 815 =176MB + 3283 17 18 815 + + In theory, each drive can be a different type. The size field in + each unit selects the drive capacity for each drive and thus the + drive type. DISKS MUST BE DECLARED IN ASCENDING SIZE. +*/ + +#define DP_SZ(x) ((DPCY_##x) * (DPHD_##x) * (DPSC_##x) * DP_WDSC) +#define DP_ENT(x,y) (DP_##x), (DPCY_##x), (DPHD_##x), (DPSC_##x), (DP_C##y), (DPSZ_##x) + +#define DP_7242 0 +#define DPCY_7242 204 +#define DPHD_7242 20 +#define DPSC_7242 6 +#define DPSZ_7242 DP_SZ(7242) + +#define DP_7261 1 +#define DPCY_7261 204 +#define DPHD_7261 20 +#define DPSC_7261 11 +#define DPSZ_7261 DP_SZ(7261) + +#define DP_7271 2 +#define DPCY_7271 408 +#define DPHD_7271 20 +#define DPSC_7271 6 +#define DPSZ_7271 DP_SZ(7271) + +#define DP_3288 3 +#define DPCY_3288 822 +#define DPHD_3288 5 +#define DPSC_3288 17 +#define DPSZ_3288 DP_SZ(3288) + +#define DP_7275 4 +#define DPCY_7275 411 +#define DPHD_7275 19 +#define DPSC_7275 11 +#define DPSZ_7275 DP_SZ(7275) + +#define DP_7276 5 +#define DPCY_7276 815 +#define DPHD_7276 19 +#define DPSC_7276 11 +#define DPSZ_7276 DP_SZ(7276) + +#define DP_3283 6 +#define DPCY_3283 815 +#define DPHD_3283 19 +#define DPSC_3283 17 +#define DPSZ_3283 DP_SZ(3283) + +#define GET_PSC(x,s) ((int32) fmod (sim_gtime() / ((double) (x * DP_WDSC)), \ + ((double) (s)))) + +typedef struct { + uint32 dp_ctype; /* controller type */ + uint32 dp_flags; /* status flags */ + uint32 dp_ski; /* seek interrupts */ + uint32 dp_time; /* inter-word time */ + uint32 dp_stime; /* inter-track time */ + uint32 dp_stopioe; /* stop on I/O error */ + uint32 dp_test; /* test mode */ + } DP_CTX; + +typedef struct { + uint32 dtype; /* drive type */ + uint32 cy; /* cylinders */ + uint32 hd; /* heads */ + uint32 sc; /* sectors */ + uint32 ctype; /* controller */ + uint32 capac; /* capacity */ + } DP_TYPE; + +typedef struct { + uint32 byte; /* offset in array */ + uint32 mask; /* test mask */ + uint32 fpos; /* from position */ + uint32 tpos; /* to position */ + } DP_SNSTAB; + +static uint32 dp_buf[DP_WDSC]; + +extern uint32 chan_ctl_time; + +uint32 dpa_disp (uint32 op, uint32 dva, uint32 *dvst); +uint32 dpb_disp (uint32 op, uint32 dva, uint32 *dvst); +uint32 dp_disp (uint32 cidx, uint32 op, uint32 dva, uint32 *dvst); +uint32 dp_tio_status (uint32 cidx, uint32 un); +uint32 dp_tdv_status (uint32 cidx, uint32 un); +uint32 dp_aio_status (uint32 cidx, uint32 un); +void dp_set_sense (UNIT *uptr, uint32 *c); +t_stat dp_chan_err (uint32 dva, uint32 st); +t_stat dp_svc (UNIT *uptr); +t_stat dps_svc (UNIT *uptr); +t_stat dp_reset (DEVICE *dptr); +t_bool dp_inv_ad (UNIT *uptr, uint32 *da); +t_bool dp_inc_ad (UNIT *uptr); +t_stat dp_read (UNIT *uptr, uint32 da); +t_stat dp_write (UNIT *uptr, uint32 da); +t_stat dp_ioerr (UNIT *uptr); +t_bool dp_test_mode (uint32 cidx); +t_bool dp_end_sec (UNIT *uptr, uint32 lnt, uint32 exp, uint32 st); +int32 dp_clr_int (uint32 cidx); +void dp_set_ski (uint32 cidx, uint32 un); +void dp_clr_ski (uint32 cidx, uint32 un); +t_stat dp_attach (UNIT *uptr, char *cptr); +t_stat dp_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat dp_set_ctl (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat dp_show_ctl (FILE *st, UNIT *uptr, int32 val, void *desc); + +static DP_TYPE dp_tab[] = { + { DP_ENT (7242, 7270) }, + { DP_ENT (7261, 3281) }, + { DP_ENT (7271, 7270) }, + { DP_ENT (3288, 3281) }, + { DP_ENT (7275, 3281) }, + { DP_ENT (7276, 3281) }, + { DP_ENT (3283, 3281) }, + { 0, 0, 0, 0, 0, 0 }, + }; + +static DP_SNSTAB dp_sense_7270[] = { + { 8, DPF_WCHK, DPF_V_WCHK, 6 }, + { 8, DPF_SNZ, DPF_V_SNZ, 2 }, + { 9, 0x01000000, 24, 0 }, + { 0, 0, 0, 0 } + }; + +static DP_SNSTAB dp_sense_3281[] = { + { 8, DPF_WCHK, DPF_V_WCHK, 7 }, + { 8, DPF_EOC, DPF_V_EOC, 3}, + { 8, DPF_AIM, DPF_V_AIM, 2}, + { 14, 0xFF000000, 24, 0 }, + { 15, 0x00FF0000, 16, 0 }, + { 0, 0, 0, 0 } + }; + +/* Command table, indexed by command */ + +#define C_7270 (1u << DP_C7270) +#define C_3281 (1u << DP_C3281) +#define C_B (C_7270|C_3281) +#define C_F (1u << 2) /* fast */ +#define C_C (1u << 3) /* ctrl cmd */ + +static uint8 dp_cmd[256] = { + 0, C_B, C_B, C_B, C_B|C_F, C_B, 0, C_3281|C_F, + 0, C_B, C_B, 0, 0, 0, 0, C_3281|C_F|C_C, + 0, 0, C_B, C_B|C_F, 0, 0, 0, C_3281|C_F, + 0, 0, 0, 0, 0, 0, 0, C_3281|C_F|C_C, + 0, 0, 0, C_7270|C_F, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, C_B, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, C_B, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, C_3281, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 + }; + +/* DP data structures + + dp_dev DP device descriptor + dp_unit DP unit descriptor + dp_reg DP register list +*/ + +dib_t dp_dib[] = { + { DVA_DPA, &dpa_disp }, + { DVA_DPB, &dpb_disp } + }; + +DP_CTX dp_ctx[] = { + { DP_C7270 }, + { DP_C3281 } + }; + +UNIT dpa_unit[] = { + { UDATA (&dp_svc, (DP_7271 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DPSZ_7271) }, + { UDATA (&dp_svc, (DP_7271 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DPSZ_7271) }, + { UDATA (&dp_svc, (DP_7271 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DPSZ_7271) }, + { UDATA (&dp_svc, (DP_7271 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DPSZ_7271) }, + { UDATA (&dp_svc, (DP_7271 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DPSZ_7271) }, + { UDATA (&dp_svc, (DP_7271 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DPSZ_7271) }, + { UDATA (&dp_svc, (DP_7271 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DPSZ_7271) }, + { UDATA (&dp_svc, (DP_7271 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DPSZ_7271) }, + { UDATA (&dp_svc, (DP_7271 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DIS, DPSZ_7271) }, + { UDATA (&dp_svc, (DP_7271 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DIS, DPSZ_7271) }, + { UDATA (&dp_svc, (DP_7271 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DIS, DPSZ_7271) }, + { UDATA (&dp_svc, (DP_7271 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DIS, DPSZ_7271) }, + { UDATA (&dp_svc, (DP_7271 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DIS, DPSZ_7271) }, + { UDATA (&dp_svc, (DP_7271 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DIS, DPSZ_7271) }, + { UDATA (&dp_svc, (DP_7271 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DIS, DPSZ_7271) }, + { UDATA (&dp_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + }; + +UNIT dpb_unit[] = { + { UDATA (&dp_svc, (DP_7276 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DPSZ_7276) }, + { UDATA (&dp_svc, (DP_7276 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DPSZ_7276) }, + { UDATA (&dp_svc, (DP_7276 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DPSZ_7276) }, + { UDATA (&dp_svc, (DP_7276 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DPSZ_7276) }, + { UDATA (&dp_svc, (DP_7276 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DPSZ_7276) }, + { UDATA (&dp_svc, (DP_7276 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DPSZ_7276) }, + { UDATA (&dp_svc, (DP_7276 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DPSZ_7276) }, + { UDATA (&dp_svc, (DP_7276 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DPSZ_7276) }, + { UDATA (&dp_svc, (DP_7276 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_DIS, DPSZ_7276) }, + { UDATA (&dp_svc, (DP_7276 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_DIS, DPSZ_7276) }, + { UDATA (&dp_svc, (DP_7276 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_DIS, DPSZ_7276) }, + { UDATA (&dp_svc, (DP_7276 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_DIS, DPSZ_7276) }, + { UDATA (&dp_svc, (DP_7276 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_DIS, DPSZ_7276) }, + { UDATA (&dp_svc, (DP_7276 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_DIS, DPSZ_7276) }, + { UDATA (&dp_svc, (DP_7276 << UNIT_V_DTYPE)+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_DIS, DPSZ_7276) }, + { UDATA (&dp_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + { UDATA (&dps_svc, UNIT_DIS, 0) }, + }; + +REG dpa_reg[] = { + { HRDATA (CTYPE, dp_ctx[0].dp_ctype, 1), REG_HRO }, + { HRDATA (FLAGS, dp_ctx[0].dp_flags, 8) }, + { GRDATA (DIFF, dp_ctx[0].dp_flags, 16, 16, 16) }, + { HRDATA (SKI, dp_ctx[0].dp_ski, 16) }, + { HRDATA (TEST, dp_ctx[0].dp_test, 16) }, + { URDATA (ADDR, dpa_unit[0].UDA, 16, 32, 0, DP_NUMDR_3281, 0) }, + { URDATA (CMD, dpa_unit[0].UCMD, 16, 10, 0, DP_NUMDR_3281, 0) }, + { DRDATA (TIME, dp_ctx[0].dp_time, 24), PV_LEFT+REG_NZ }, + { DRDATA (STIME, dp_ctx[0].dp_stime, 24), PV_LEFT+REG_NZ }, + { FLDATA (STOP_IOE, dp_ctx[0].dp_stopioe, 0) }, + { HRDATA (DEVNO, dp_dib[0].dva, 12), REG_HRO }, + { NULL } + }; + +REG dpb_reg[] = { + { HRDATA (CTYPE, dp_ctx[1].dp_ctype, 1), REG_HRO }, + { HRDATA (FLAGS, dp_ctx[1].dp_flags, 8) }, + { GRDATA (DIFF, dp_ctx[1].dp_flags, 16, 16, 16) }, + { HRDATA (SKI, dp_ctx[1].dp_ski, 16) }, + { HRDATA (TEST, dp_ctx[1].dp_test, 16) }, + { URDATA (ADDR, dpa_unit[1].UDA, 16, 32, 0, DP_NUMDR_3281, 0) }, + { URDATA (CMD, dpa_unit[1].UCMD, 16, 10, 0, DP_NUMDR_3281, 0) }, + { DRDATA (TIME, dp_ctx[1].dp_time, 24), PV_LEFT+REG_NZ }, + { DRDATA (STIME, dp_ctx[1].dp_stime, 24), PV_LEFT+REG_NZ }, + { FLDATA (STOP_IOE, dp_ctx[1].dp_stopioe, 0) }, + { HRDATA (DEVNO, dp_dib[1].dva, 12), REG_HRO }, + { NULL } + }; + +MTAB dp_mod[] = { + { MTAB_XTD|MTAB_VDV, DP_C7270, "C7270", "C7270", + &dp_set_ctl, &dp_show_ctl, NULL }, + { MTAB_XTD|MTAB_VDV, DP_C3281, "C3281", "C3281", + &dp_set_ctl, &dp_show_ctl, NULL }, + { (UNIT_DTYPE+UNIT_ATT), (DP_7242 << UNIT_V_DTYPE) + UNIT_ATT, + "7242", NULL, NULL }, + { (UNIT_DTYPE+UNIT_ATT), (DP_7261 << UNIT_V_DTYPE) + UNIT_ATT, + "7261", NULL, NULL }, + { (UNIT_DTYPE+UNIT_ATT), (DP_7271 << UNIT_V_DTYPE) + UNIT_ATT, + "7271", NULL, NULL }, + { (UNIT_DTYPE+UNIT_ATT), (DP_3288 << UNIT_V_DTYPE) + UNIT_ATT, + "3288", NULL, NULL }, + { (UNIT_DTYPE+UNIT_ATT), (DP_7275 << UNIT_V_DTYPE) + UNIT_ATT, + "7275", NULL, NULL }, + { (UNIT_DTYPE+UNIT_ATT), (DP_7276 << UNIT_V_DTYPE) + UNIT_ATT, + "7276", NULL, NULL }, + { (UNIT_DTYPE+UNIT_ATT), (DP_3283 << UNIT_V_DTYPE) + UNIT_ATT, + "3283", NULL, NULL }, + { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (DP_7242 << UNIT_V_DTYPE), + "7242", NULL, NULL }, + { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (DP_7261 << UNIT_V_DTYPE), + "7261", NULL, NULL }, + { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (DP_7271 << UNIT_V_DTYPE), + "7271", NULL, NULL }, + { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (DP_3288 << UNIT_V_DTYPE), + "3288", NULL, NULL }, + { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (DP_7275 << UNIT_V_DTYPE), + "7275", NULL, NULL }, + { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (DP_7276 << UNIT_V_DTYPE), + "7276", NULL, NULL }, + { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (DP_3283 << UNIT_V_DTYPE), + "3283", NULL, NULL }, + { (UNIT_AUTO+UNIT_ATT), UNIT_AUTO, "autosize", NULL, NULL }, + { UNIT_AUTO, UNIT_AUTO, NULL, "AUTOSIZE", NULL }, + { (UNIT_AUTO+UNIT_DTYPE), (DP_7242 << UNIT_V_DTYPE), + NULL, "7242", &dp_set_size }, + { (UNIT_AUTO+UNIT_DTYPE), (DP_7261 << UNIT_V_DTYPE), + NULL, "7261", &dp_set_size }, + { (UNIT_AUTO+UNIT_DTYPE), (DP_7271 << UNIT_V_DTYPE), + NULL, "7271", &dp_set_size }, + { (UNIT_AUTO+UNIT_DTYPE), (DP_3288 << UNIT_V_DTYPE), + NULL, "3288", &dp_set_size }, + { (UNIT_AUTO+UNIT_DTYPE), (DP_7275 << UNIT_V_DTYPE), + NULL, "7275", &dp_set_size }, + { (UNIT_AUTO+UNIT_DTYPE), (DP_7276 << UNIT_V_DTYPE), + NULL, "7276", &dp_set_size }, + { (UNIT_AUTO+UNIT_DTYPE), (DP_7276 << UNIT_V_DTYPE), + NULL, "3282", &dp_set_size }, + { (UNIT_AUTO+UNIT_DTYPE), (DP_3283 << UNIT_V_DTYPE), + NULL, "3283", &dp_set_size }, + { UNIT_HWLK, 0, "write enabled", "WRITEENABLED", NULL }, + { UNIT_HWLK, UNIT_HWLK, "write locked", "LOCKED", NULL }, + { MTAB_XTD|MTAB_VDV, 0, "CHAN", "CHAN", + &io_set_dvc, &io_show_dvc, NULL }, + { MTAB_XTD|MTAB_VDV, 0, "DVA", "DVA", + &io_set_dva, &io_show_dva, NULL }, + { MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "CSTATE", NULL, + NULL, &io_show_cst, NULL }, + { 0 } + }; + +DEVICE dp_dev[] = { + { + "DPA", dpa_unit, dpa_reg, dp_mod, + (2 * DP_NUMDR_3281) + 1, 16, 28, 1, 16, 32, + NULL, NULL, &dp_reset, + &io_boot, &dp_attach, NULL, + &dp_dib[0], DEV_DISABLE + }, + { + "DPB", dpb_unit, dpb_reg, dp_mod, + (2 * DP_NUMDR_3281) + 1, 16, 28, 1, 16, 32, + NULL, NULL, &dp_reset, + &io_boot, &dp_attach, NULL, + &dp_dib[1], DEV_DISABLE + } + }; + +/* DP: IO dispatch routine */ + +uint32 dpa_disp (uint32 op, uint32 dva, uint32 *dvst) +{ +return dp_disp (0, op, dva, dvst); +} + +uint32 dpb_disp (uint32 op, uint32 dva, uint32 *dvst) +{ +return dp_disp (1, op, dva, dvst); +} + +uint32 dp_disp (uint32 cidx, uint32 op, uint32 dva, uint32 *dvst) +{ +uint32 un = DVA_GETUNIT (dva); +UNIT *dp_unit = dp_dev[cidx].units; +UNIT *uptr = dp_unit + un; +int32 iu; +uint32 i; +DP_CTX *ctx; + +if (cidx >= DP_NUMCTL) /* inv ctrl num? */ + return DVT_NODEV; +ctx = &dp_ctx[cidx]; +if ((un >= DP_NUMDR) || /* inv unit num? */ + ((uptr->flags & UNIT_DIS) && /* disabled unit? */ + ((un != 0xF) || (ctx->dp_ctype != C_3281)))) /* not 3281 unit F? */ + return DVT_NODEV; + +switch (op) { /* case on op */ + + case OP_SIO: /* start I/O */ + *dvst = dp_tio_status (cidx, un); /* get status */ + if ((*dvst & (DVS_CST|DVS_DST)) == 0) { /* ctrl + dev idle? */ + uptr->UCMD = DPS_INIT; /* start dev thread */ + sim_activate (uptr, chan_ctl_time); + } + break; + + case OP_TIO: /* test status */ + *dvst = dp_tio_status (cidx, un); /* return status */ + break; + + case OP_TDV: /* test status */ + *dvst = dp_tdv_status (cidx, un); /* return status */ + break; + + case OP_HIO: /* halt I/O */ + *dvst = dp_tio_status (cidx, un); /* return status */ + if (un != 0xF) { /* not controller */ + if ((int32) un == chan_chk_chi (dva)) /* halt active ctlr int? */ + chan_clr_chi (dva); /* clear ctlr int */ + if (sim_is_active (uptr)) { /* chan active? */ + sim_cancel (uptr); /* stop unit */ + chan_uen (dva); /* uend */ + } + dp_clr_ski (cidx, un); /* clear seek int */ + sim_cancel (uptr + DP_SEEK); /* cancel seek compl */ + } + else { + for (i = 0; i < DP_NUMDR; i++) { /* do every unit */ + if (sim_is_active (&dp_unit[i])) { /* chan active? */ + sim_cancel (&dp_unit[i]); /* cancel */ + chan_uen (dva); /* uend */ + } + dp_clr_ski (cidx, i); /* clear seek int */ + sim_cancel (&dp_unit[i] + DP_SEEK); /* cancel seek compl */ + } + chan_clr_chi (dva); /* clear chan int */ + } + break; + + case OP_AIO: /* acknowledge int */ + iu = dp_clr_int (cidx); /* clear int */ + *dvst = dp_aio_status (cidx, iu) | /* get status */ + (iu << DVT_V_UN); + break; + + default: + *dvst = 0; + return SCPE_IERR; + } + +return 0; +} + +/* Unit service */ + +t_stat dp_svc (UNIT *uptr) +{ +uint32 i, da, wd, wd1, c[DPS_NBY_3281]; +uint32 cidx = uptr->UCTX; +uint32 dva = dp_dib[cidx].dva; +uint32 dtype = GET_DTYPE (uptr->flags); +UNIT *dp_unit = dp_dev[cidx].units; +uint32 un = uptr - dp_unit; +DP_CTX *ctx = &dp_ctx[cidx]; +int32 t, dc; +uint32 st, cmd, sc; +t_stat r; + +if (uptr->UCMD == DPS_INIT) { /* init state? */ + st = chan_get_cmd (dva, &cmd); /* get command */ + if (CHS_IFERR (st)) /* channel error? */ + return dp_chan_err (dva, st); + ctx->dp_flags = 0; /* clear status */ + if (!(dp_cmd[cmd] & (1u << ctx->dp_ctype))) { /* cmd valid for dev? */ + ctx->dp_flags |= DPF_PGE; + chan_uen (dva); /* uend */ + return SCPE_OK; + } + if ((un == 0xF) && /* to controller? */ + !(dp_cmd[cmd] & C_C)) { /* not valid? */ + ctx->dp_flags |= DPF_PGE; + chan_uen (dva); /* uend */ + return SCPE_OK; + } + uptr->UCMD = cmd; /* save state */ + if (dp_cmd[cmd] & C_F) /* fast command? */ + sim_activate_abs (uptr, chan_ctl_time); /* schedule soon */ + else { /* data transfer */ + sc = DPA_GETSC (uptr->UDA); /* new sector */ + t = sc - GET_PSC (ctx->dp_time, dp_tab[dtype].sc); /* delta to new */ + if (t < 0) /* wrap around? */ + t = t + dp_tab[dtype].sc; + sim_activate_abs (uptr, t * ctx->dp_time * DP_WDSC); /* schedule op */ + } + sim_cancel (uptr + DP_SEEK); /* cancel rest of seek */ + return SCPE_OK; + } +else if (uptr->UCMD == DPS_END) { /* end state? */ + st = chan_end (dva); /* set channel end */ + if (CHS_IFERR (st)) /* channel error? */ + return dp_chan_err (dva, st); + if (st == CHS_CCH) { /* command chain? */ + uptr->UCMD = DPS_INIT; /* restart thread */ + sim_activate (uptr, chan_ctl_time); + } + return SCPE_OK; /* done */ + } + +da = 0; +dc = 0; +switch (uptr->UCMD) { + + case DPS_SEEK: /* seek */ + case DPS_SEEKI: + for (i = 0; i < 4; i++) + c[i] = 0; + for (i = 0, st = 0; (i < 4) && (st != CHS_ZBC); i++) { + st = chan_RdMemB (dva, &c[i]); /* get byte */ + if (CHS_IFERR (st)) /* channel error? */ + return dp_chan_err (dva, st); + } + da = (c[0] << 24) | (c[1] << 16) | (c[2] << 8) | c[3]; + if (c[0] & 0xFC) /* hi 6b non-zero? */ + ctx->dp_flags |= DPF_PGE; /* set prog err */ + if (((i != 4) || (st != CHS_ZBC)) && /* length error? */ + chan_set_chf (dva, CHF_LNTE)) { /* care? */ + ctx->dp_flags |= DPF_PGE; /* set prog err */ + return SCPE_OK; + } + if (i < 4) { /* at least 4? */ + chan_uen (dva); + return SCPE_OK; + } + dc = DPA_GETCY (da); /* desired cyl */ + case DPS_RECAL: + case DPS_RECALI: + t = DPA_GETCY (uptr->UDA) - dc; /* get cyl diff */ + ctx->dp_flags = (ctx->dp_flags & ~DPF_DIFF) | + ((t & DPF_M_DIFF) << DPF_V_DIFF); /* save difference */ + if (t == 0) + t = 1; + else t = abs (t); + uptr->UDA = da; /* save addr */ + sim_activate (uptr + DP_SEEK, t * ctx->dp_stime); + dp_unit[un + DP_SEEK].UCMD = /* sched seek */ + (chan_tst_cmf (dva, CMF_CCH)? DSC_SEEK: uptr->UCMD & 0x80); + break; /* sched end */ + + case DPS_SENSE: /* sense */ + for (i = 0; i < DPS_NBY_3281; i++) + c[i] = 0; + c[0] = (uptr->UDA >> 24) & 0xFF; + c[1] = (uptr->UDA >> 16) & 0xFF; + c[2] = (uptr->UDA >> 8) & 0xFF; + c[3] = uptr->UDA & 0xFF; + c[4] = GET_PSC (ctx->dp_time, dp_tab[dtype].sc) | /* curr sector */ + ((sim_is_active (uptr) && ((uptr->UCMD & 0x7F) == DPS_SEEK))? 0x80: 0); + if (ctx->dp_ctype == DP_C3281) { + c[5] = c[7] = un; + c[10] = (ctx->dp_ski >> 8) & 0xFF; + c[11] = ctx->dp_ski & 0xFF; + } + dp_set_sense (uptr, &c[0]); + for (i = 0, st = 0; (i < DPS_NBY) && (st != CHS_ZBC); i++) { + st = chan_WrMemB (dva, c[i]); /* store char */ + if (CHS_IFERR (st)) /* channel error? */ + return dp_chan_err (dva, st); + } + if ((i != DPS_NBY) || (st != CHS_ZBC)) { /* length error? */ + ctx->dp_flags |= DPF_PGE; /* set prog err */ + if (chan_set_chf (dva, CHF_LNTE)) /* do we care? */ + return SCPE_OK; + } + break; + + case DPS_WRITE: /* write */ + if (uptr->flags & UNIT_RO) { /* write locked? */ + ctx->dp_flags |= DPF_WPE; + chan_uen (dva); /* uend */ + return SCPE_OK; + } + if (dp_inv_ad (uptr, &da)) { /* invalid addr? */ + chan_uen (dva); /* uend */ + return SCPE_OK; + } + for (i = 0, st = 0; i < DP_WDSC; i++) { /* sector loop */ + if (st != CHS_ZBC) { /* chan not done? */ + st = chan_RdMemW (dva, &wd); /* read word */ + if (CHS_IFERR (st)) { /* channel error? */ + dp_inc_ad (uptr); /* da increments */ + return dp_chan_err (dva, st); + } + } + else wd = 0; + dp_buf[i] = wd; /* store in buffer */ + } + if (r = dp_write (uptr, da)) /* write buf, err? */ + return r; + if (dp_end_sec (uptr, DP_WDSC, DP_WDSC, st)) /* transfer done? */ + return SCPE_OK; /* err or cont */ + break; + +/* Write header "writes" eight bytes per sector and throws them in the bit bucket */ + + case DPS_WHDR: + if (uptr->flags & UNIT_RO) { /* write locked? */ + ctx->dp_flags |= DPF_WPE; + chan_uen (dva); /* uend */ + return SCPE_OK; + } + if (dp_inv_ad (uptr, &da)) { /* invalid addr? */ + chan_uen (dva); /* uend */ + return SCPE_OK; + } + if (DPA_GETSC (uptr->UDA) != 0) { + ctx->dp_flags |= DPF_SNZ; + chan_uen (dva); + return SCPE_OK; + } + for (i = 0, st = 0; (i < 8) && (st != CHS_ZBC); i++) { /* sector loop */ + if (st != CHS_ZBC) { /* chan not done? */ + st = chan_RdMemB (dva, &wd); /* read word */ + if (CHS_IFERR (st)) { /* channel error? */ + dp_inc_ad (uptr); /* da increments */ + return dp_chan_err (dva, st); + } + } + } + if (dp_end_sec (uptr, i, 8, st)) /* transfer done? */ + return SCPE_OK; /* err or cont */ + +/* Write check must be done by bytes to get precise miscompare */ + + case DPS_CHECK: /* write check */ + if (dp_inv_ad (uptr, &da)) { /* invalid addr? */ + chan_uen (dva); /* uend */ + return SCPE_OK; + } + if (r = dp_read (uptr, da)) /* read buf, error? */ + return r; + for (i = 0, st = 0; (i < (DP_WDSC * 4)) && (st != CHS_ZBC); i++) { + st = chan_RdMemB (dva, &wd); /* read byte */ + if (CHS_IFERR (st)) { /* channel error? */ + dp_inc_ad (uptr); /* da increments */ + return dp_chan_err (dva, st); + } + wd1 = (dp_buf[i >> 2] >> (24 - ((i % 4) * 8))) & 0xFF; /* byte */ + if (wd != wd1) { /* check error? */ + dp_inc_ad (uptr); /* da increments */ + ctx->dp_flags |= DPF_WCHK; /* set status */ + chan_uen (dva); /* force uend */ + return SCPE_OK; + } + } + if (dp_end_sec (uptr, i, DP_WDSC * 4, st)) /* transfer done? */ + return SCPE_OK; /* err or cont */ + break; + + case DPS_READ: /* read */ + if (dp_inv_ad (uptr, &da)) { /* invalid addr? */ + chan_uen (dva); /* uend */ + return SCPE_OK; + } + if (r = dp_read (uptr, da)) /* read buf, error? */ + return r; + for (i = 0, st = 0; (i < DP_WDSC) && (st != CHS_ZBC); i++) { + st = chan_WrMemW (dva, dp_buf[i]); /* store in mem */ + if (CHS_IFERR (st)) { /* channel error? */ + dp_inc_ad (uptr); /* da increments */ + return dp_chan_err (dva, st); + } + } + if (dp_end_sec (uptr, i, DP_WDSC, st)) /* transfer done? */ + return SCPE_OK; /* err or cont */ + break; + +/* Read header reads 8 bytes per sector */ + + case DPS_RHDR: /* read header */ + if (dp_inv_ad (uptr, &da)) { /* invalid addr? */ + chan_uen (dva); /* uend */ + return SCPE_OK; + } + c[0] = c[5] = c[6] = c[7] = 0; + wd = DPA_GETCY (uptr->UDA); + c[1] = (wd >> 8) & 0xFF; + c[2] = wd & 0xFF; + c[3] = DPA_GETHD (uptr->UDA); + c[4] = DPA_GETSC (uptr->UDA); + for (i = 0, st = 0; (i < 8) && (st != CHS_ZBC); i++) { + st = chan_WrMemB (dva, c[i]); /* store in mem */ + if (CHS_IFERR (st)) { /* channel error? */ + dp_inc_ad (uptr); /* da increments */ + return dp_chan_err (dva, st); + } + } + if (dp_end_sec (uptr, i, 8, st)) /* transfer done? */ + return SCPE_OK; /* err or cont */ + break; + +/* Test mode is not really implemented */ + + case DPS_TEST: /* test mode */ + if (!dp_test_mode (cidx)) /* enter test mode */ + return SCPE_OK; + break; + + case DPS_RSRV: /* reserve */ + case DPS_RLS: /* release */ + case DPS_RLSA: /* release */ + break; /* nop */ + } + +uptr->UCMD = DPS_END; /* op done, next state */ +sim_activate (uptr, chan_ctl_time); +return SCPE_OK; +} + +/* Seek completion service */ + +t_stat dps_svc (UNIT *uptr) +{ +uint32 cidx = uptr->UCTX; +DP_CTX *ctx = &dp_ctx[cidx]; +UNIT *dp_unit = dp_dev[cidx].units; +uint32 un = uptr - dp_unit - DP_SEEK; +uint32 dtype = GET_DTYPE (dp_unit[un].flags); + +if (uptr->UCMD != DSC_SEEK) { /* int? */ + if (chan_chk_chi (dp_dib[cidx].dva) >= 0) { /* ctl int pending? */ + sim_activate (uptr, ctx->dp_time * dp_tab[dtype].sc); + uptr->UCMD = DSC_SEEKW; + } + else dp_set_ski (cidx, un); + } +return SCPE_OK; +} + +/* Common read/write sector end routine + + case 1 - more to transfer, not end cylinder - reschedule, return TRUE + case 2 - more to transfer, end cylinder - uend, return TRUE + case 3 - transfer done, length error - uend, return TRUE + case 4 - transfer done, no length error - return FALSE (sched end state) +*/ + +t_bool dp_end_sec (UNIT *uptr, uint32 lnt, uint32 exp, uint32 st) +{ +uint32 cidx = uptr->UCTX; +uint32 dva = dp_dib[cidx].dva; +uint32 dtype = GET_DTYPE (uptr->flags); +DP_CTX *ctx = &dp_ctx[cidx]; + +if (st != CHS_ZBC) { /* end record? */ + if (dp_inc_ad (uptr)) { /* inc addr, cross cyl? */ + ctx->dp_flags |= (DPF_IVA | DPF_EOC); + chan_uen (dva); /* uend */ + } + else sim_activate (uptr, ctx->dp_time * 16); /* no, next sector */ + return TRUE; + } +dp_inc_ad (uptr); /* just incr addr */ +if (lnt != exp) { /* length error at end? */ + if (exp == 8) /* hdr op? */ + ctx->dp_flags |= DPF_PGE; /* set PGE */ + if (chan_set_chf (dva, CHF_LNTE)) /* do we care? */ + return TRUE; + } +return FALSE; /* cmd done */ +} + +/* DP status routine */ + +uint32 dp_tio_status (uint32 cidx, uint32 un) +{ +uint32 i; +DP_CTX *ctx = &dp_ctx[cidx]; +UNIT *dp_unit = dp_dev[cidx].units; + +for (i = 0; i < DP_NUMDR; i++) { + if (sim_is_active (&dp_unit[i])) + return (DVS_AUTO|DVS_CBUSY|DVS_DBUSY|(CC2 << DVT_V_CC)); + } +for (i = 0; i < DP_NUMDR; i++) { + if (sim_is_active (&dp_unit[i + DP_SEEK]) && + (dp_unit[i + DP_SEEK].UCMD != DSC_SEEKW)) + return (DVS_AUTO|DVS_DBUSY|(CC2 << DVT_V_CC)); + } +return DVS_AUTO; +} + +uint32 dp_tdv_status (uint32 cidx, uint32 un) +{ +uint32 st; +DP_CTX *ctx = &dp_ctx[cidx]; +UNIT *dp_unit = dp_dev[cidx].units; +t_bool on_cyl; + +st = 0; +on_cyl = !sim_is_active (&dp_unit[un + DP_SEEK]) || + (dp_unit[un + DP_SEEK].UCMD == DSC_SEEKW); +if (dp_ctx[cidx].dp_ctype == DP_C7270) + st = ((dp_ctx[cidx].dp_flags & DPF_IVA)? 0x20: 0) | + (on_cyl? 0x04: 0); +else st = ((dp_ctx[cidx].dp_flags & DPF_PGE)? 0x20: 0) | + ((dp_ctx[cidx].dp_flags & DPF_WPE)? 0x08: 0); +return st; +} + +uint32 dp_aio_status (uint32 cidx, uint32 un) +{ +uint32 st; +DP_CTX *ctx = &dp_ctx[cidx]; +UNIT *dp_unit = dp_dev[cidx].units; +t_bool on_cyl; + +st = 0; +on_cyl = !sim_is_active (&dp_unit[un + DP_SEEK]) || + (dp_unit[un + DP_SEEK].UCMD == DSC_SEEKW); +if ((dp_ctx[cidx].dp_ctype == DP_C7270) && on_cyl) + st |= 0x04; +if (chan_chk_chi (dp_dib[cidx].dva) < 0) + st |= 0x08; +return st; +} + +/* Set sense status */ + +void dp_set_sense (UNIT *uptr, uint32 *c) +{ +uint32 cidx = uptr->UCTX; +UNIT *sptr = uptr + DP_SEEK; +DP_CTX *ctx = &dp_ctx[cidx]; +uint8 data; +DP_SNSTAB *tptr; + +if (sim_is_active (sptr) && + (sptr->UCMD != DSC_SEEKW)) + ctx->dp_flags |= DPF_AIM; +else ctx->dp_flags &= ~DPF_AIM; +if (ctx->dp_ctype == DP_C7270) + tptr = dp_sense_7270; +else tptr = dp_sense_3281; +while (tptr->byte != 0) { + if (ctx->dp_flags & tptr->mask) { + data = (uint8) ((ctx->dp_flags & tptr->mask) >> tptr->fpos); + c[tptr->byte] |= (data << tptr->tpos); + } + } +return; +} + +/* Validate disk address */ + +t_bool dp_inv_ad (UNIT *uptr, uint32 *da) +{ +uint32 dtype = GET_DTYPE (uptr->flags); +uint32 cy = DPA_GETCY (uptr->UDA); +uint32 hd = DPA_GETHD (uptr->UDA); +uint32 sc = DPA_GETSC (uptr->UDA); + +if ((cy >= dp_tab[dtype].cy) || + (hd >= dp_tab[dtype].hd) || + (sc >= dp_tab[dtype].sc)) + return TRUE; +if (da) /* return word addr */ + *da = ((((cy * dp_tab[dtype].hd) + hd) * dp_tab[dtype].sc) + sc) * DP_WDSC; +return FALSE; +} + +/* Increment disk address */ + +t_bool dp_inc_ad (UNIT *uptr) +{ +uint32 dtype = GET_DTYPE (uptr->flags); +uint32 cy = DPA_GETCY (uptr->UDA); +uint32 hd = DPA_GETHD (uptr->UDA); +uint32 sc = DPA_GETSC (uptr->UDA); + +sc = sc + 1; /* sector++ */ +if (sc >= dp_tab[dtype].sc) { /* overflow? */ + sc = 0; /* wrap sector */ + hd = hd + 1; /* head++ */ + if (hd >= dp_tab[dtype].hd) /* overflow? */ + hd = 0; /* wrap heads */ + } +uptr->UDA = (cy << DPA_V_CY) | (hd << DPA_V_HD) | (sc << DPA_V_SC); +if ((hd == 0) && (sc == 0)) + return TRUE; +return FALSE; +} + +/* Read and write sector */ + +t_stat dp_read (UNIT *uptr, uint32 da) +{ +int32 err, awc; + +err = fseek (uptr->fileref, da * sizeof (int32), SEEK_SET); +if (err == 0) { + awc = fxread (dp_buf, sizeof (uint32), DP_WDSC, uptr->fileref); + err = ferror (uptr->fileref); + for (; awc < DP_WDSC; awc++) /* fill buf */ + dp_buf[awc] = 0; + } +if (err != 0) + return dp_ioerr (uptr); +return SCPE_OK; +} + +t_stat dp_write (UNIT *uptr, uint32 da) +{ +int32 err; + +err = fseek (uptr->fileref, da * sizeof (int32), SEEK_SET); +if (err == 0) { + fxwrite (dp_buf, sizeof (uint32), DP_WDSC, uptr->fileref); + err = ferror (uptr->fileref); + } +if (err != 0) + return dp_ioerr (uptr); +return SCPE_OK; +} + +t_stat dp_ioerr (UNIT *uptr) +{ +uint32 cidx = uptr->UCTX; +uint32 dva = dp_dib[cidx].dva; + +perror ("DP I/O error"); +clearerr (uptr->fileref); +dp_ctx[cidx].dp_flags |= DPF_DPE; /* set DPE flag */ +chan_set_chf (dva, CHF_XMDE); +chan_uen (dva); /* force uend */ +return SCPE_IOERR; +} + +/* Test mode */ + +t_bool dp_test_mode (uint32 cidx) +{ +DP_CTX *ctx = &dp_ctx[cidx]; +uint32 dva = dp_dib[cidx].dva; +uint32 i, st, wd; + +ctx->dp_test = 0; +for (i = 0, st = 0; i < DPT_NBY; i++) { /* sector loop */ + if (st != CHS_ZBC) { /* chan not done? */ + st = chan_RdMemB (dva, &wd); /* read word */ + if (CHS_IFERR (st)) { + dp_chan_err (dva, st); + return FALSE; + } + } + else wd = 0; + ctx->dp_test |= (wd & 0xFF) << (i * 8); + } +return TRUE; +} + +/* Channel error */ + +t_stat dp_chan_err (uint32 dva, uint32 st) +{ +chan_uen (dva); /* uend */ +if (st < CHS_ERR) return st; +return SCPE_OK; +} + +/* Clear controller/device interrupt */ + +int32 dp_clr_int (uint32 cidx) +{ +int32 iu; +DP_CTX *ctx = &dp_ctx[cidx]; + +if ((iu = chan_clr_chi (dp_dib[cidx].dva)) >= 0) { /* chan int? clear */ + if (ctx->dp_ski != 0) /* more int? */ + chan_set_dvi (dp_dib[cidx].dva); /* set INP */ + return iu; + } +for (iu = 0; iu < (int32) DP_NUMDR; iu++) { /* seek int? */ + if (ctx->dp_ski & (1u << iu)) { + dp_clr_ski (cidx, iu); /* clear */ + return iu; + } + } +return 0; +} + +/* Set seek interrupt */ + +void dp_set_ski (uint32 cidx, uint32 un) +{ +dp_ctx[cidx].dp_ski |= (1u << un); +chan_set_dvi (dp_dib[cidx].dva); /* set INP */ +return; +} + +/* Clear seek interrupt */ + +void dp_clr_ski (uint32 cidx, uint32 un) +{ +dp_ctx[cidx].dp_ski &= ~(1u << un); /* clear */ +if (dp_ctx[cidx].dp_ski != 0) /* more int? */ + chan_set_dvi (dp_dib[cidx].dva); /* set INP */ +else if (chan_chk_chi (dp_dib[cidx].dva) < 0) /* any int? */ + chan_clr_chi (dp_dib[cidx].dva); /* clr INP */ +return; +} + +/* Reset routine */ + +t_stat dp_reset (DEVICE *dptr) +{ +uint32 i; +uint32 cidx = dptr - dp_dev; +UNIT *dp_unit; +DP_CTX *ctx; + +if (cidx >= DP_NUMCTL) + return SCPE_IERR; +dp_unit = dptr->units; +ctx = &dp_ctx[cidx]; +for (i = 0; i < DP_NUMDR; i++) { + sim_cancel (&dp_unit[i]); /* stop dev thread */ + dp_unit[i].UDA = 0; + dp_unit[i].UCMD = 0; + dp_unit[i].UCTX = cidx; + } +ctx->dp_flags = 0; +ctx->dp_ski = 0; +ctx->dp_test = 0; +chan_reset_dev (dp_dib[cidx].dva); /* clr int, active */ +return SCPE_OK; +} + +/* Device attach */ + +t_stat dp_attach (UNIT *uptr, char *cptr) +{ +uint32 i, p; +t_stat r; + +uptr->capac = dp_tab[GET_DTYPE (uptr->flags)].capac; +r = attach_unit (uptr, cptr); /* attach unit */ +if (r != SCPE_OK) /* error? */ + return r; +if ((uptr->flags & UNIT_AUTO) == 0) /* autosize? */ + return SCPE_OK; +p = sim_fsize (uptr->fileref); +for (i = 0; dp_tab[i].sc != 0; i++) { + if (p <= (dp_tab[i].capac * (uint32) sizeof (int32))) { + uptr->flags = (uptr->flags & ~UNIT_DTYPE) | (i << UNIT_V_DTYPE); + uptr->capac = dp_tab[i].capac; + return SCPE_OK; + } + } +return SCPE_OK; +} + +/* Set drive type command validation routine */ + +t_stat dp_set_size (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +uint32 dtype = GET_DTYPE (val); +uint32 cidx = uptr->UCTX; + +if (cidx >= DP_NUMCTL) /* valid ctrl idx? */ + return SCPE_IERR; +if (uptr->flags & UNIT_ATT) /* unattached? */ + return SCPE_ALATT; +if (dp_tab[dtype].ctype != dp_ctx[cidx].dp_ctype) /* valid for curr ctrl? */ + return SCPE_NOFNC; +uptr->capac = dp_tab[dtype].capac; +return SCPE_OK; +} + +/* Set controller type command validation routine */ + +t_stat dp_set_ctl (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +uint32 i, cidx = uptr->UCTX; +DP_CTX *ctx = &dp_ctx[cidx]; +UNIT *dp_unit = dp_dev[cidx].units; + +if ((cidx >= DP_NUMCTL) || (val >= DP_NUMCTL)) /* valid ctrl idx? */ + return SCPE_IERR; +if (val == dp_ctx[cidx].dp_ctype) + return SCPE_OK; +for (i = 0; i < DP_NUMDR; i++) { /* all units detached? */ + if (dp_unit[i].flags & UNIT_ATT) + return SCPE_ALATT; + } +for (i = 0; i < DP_NUMDR; i++) { + if (val == DP_C7270) { /* changing to 7270? */ + dp_unit[i].flags = (dp_unit[i].flags & ~UNIT_DTYPE) | + (DP_7271 << UNIT_V_DTYPE); + dp_unit[i].capac = DPSZ_7271; + if (i >= DP_NUMDR_7270) + dp_unit[i].flags = (dp_unit[i].flags | UNIT_DIS) & ~UNIT_DISABLE; + } + else { + dp_unit[i].flags = (dp_unit[i].flags & ~UNIT_DTYPE) | + (DP_7275 << UNIT_V_DTYPE); + dp_unit[i].capac = DPSZ_7275; + if (i >= DP_NUMDR_7270) + dp_unit[i].flags = dp_unit[i].flags | UNIT_DISABLE; + } + } +return SCPE_OK; +} + +t_stat dp_show_ctl (FILE *st, UNIT *uptr, int32 val, void *desc) +{ +uint32 cidx = uptr->UCTX; + +if (cidx >= DP_NUMCTL) /* valid ctrl idx? */ + return SCPE_IERR; +if (dp_ctx[cidx].dp_ctype == DP_C7270) + fprintf (st, "7270 controller"); +else fprintf (st, "3281 controller"); +return SCPE_OK; +} diff --git a/sigma/sigma_fp.c b/sigma/sigma_fp.c new file mode 100644 index 00000000..a82f6516 --- /dev/null +++ b/sigma/sigma_fp.c @@ -0,0 +1,421 @@ +/* sigma_fp.c: XDS Sigma floating point simulator + + Copyright (c) 2007-2008, Robert M Supnik + + 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 + ROBERT M SUPNIK 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 Robert M Supnik shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. +*/ + +#include "sigma_defs.h" + +#define UFP_V_GUARD 4 +#define UFP_NORM (FP_NORM << UFP_V_GUARD) +#define UFP_CARRY (UFP_NORM << 4) +#define UFP_FRHI (UFP_CARRY|UFP_NORM|FP_M_FRHI) +#define UFP_FRLO 0xFFFFFFFF + +/* Double precision fraction add/subtract/compare */ +/* Note: UFP_ADD (s, r, r) will not work!!! */ + +#define UFP_ADD(s1,s2,d) do { \ + d.l = (s1.l + s2.l) & UFP_FRLO; \ + d.h = (s1.h + s2.h + (d.l < s2.l)) & UFP_FRHI; \ + } while (0) + +#define UFP_SUB(s1,s2,d) do { \ + d.h = (s1.h - s2.h - (s1.l < s2.l)) & UFP_FRHI; \ + d.l = (s1.l - s2.l) & UFP_FRLO; \ + } while (0) + +#define UFP_GE(s1,s2) ((s1.h > s2.h) || \ + ((s1.h == s2.h) && (s1.l >= s2.l))) + +/* Variable and constant shifts; for constants, 0 < k < 32 */ + +#define UFP_RSH_V(v,s) do { \ + if ((s) < 32) { \ + v.l = ((v.l >> (s)) | \ + ( v.h << (32 - (s)))) & UFP_FRLO; \ + v.h = v.h >> (s); \ + } \ + else if ((s) < 64) { \ + v.l = v.h >> ((s) - 32); \ + v.h = 0; \ + } \ + else v.l = v.h = 0; \ + } while (0) + +#define UFP_RSH_K(v,s) do { \ + v.l = ((v.l >> (s)) | \ + (v.h << (32 - (s)))) & UFP_FRLO; \ + v.h = v.h >> (s); \ + } while (0) + +#define UFP_LSH_K(v,s) do { \ + v.h = ((v.h << (s)) | \ + (v.l >> (32 - (s)))) & UFP_FRHI; \ + v.l = (v.l << (s)) & UFP_FRLO; \ + } while (0) + +#define UFP_RSH_KP(v,s) do { \ + v->l = ((v->l >> (s)) | \ + (v->h << (32 - (s)))) & UFP_FRLO; \ + v->h = v->h >> (s); \ + } while (0) + +#define UFP_LSH_KP(v,s) do { \ + v->h = ((v->h << (s)) | \ + (v->l >> (32 - (s)))) & UFP_FRHI; \ + v->l = (v->l << (s)) & UFP_FRLO; \ + } while (0) + +typedef struct { + uint32 sign; + int32 exp; + uint32 h; + uint32 l; + } ufp_t; + +extern uint32 *R; +extern uint32 PSW1; +extern uint32 CC; + +void fp_unpack (uint32 hi, uint32 lo, ufp_t *dst); +t_bool fp_clnzro (ufp_t *src, t_bool abnorm); +uint32 fp_pack (ufp_t *src, uint32 rn, t_bool dbl, t_bool rndtrap); +uint32 fp_norm (ufp_t *src); + +uint32 fp (uint32 op, uint32 rn, uint32 bva) +{ +uint32 rh, rl, mh, ml, i, ediff, nsh; +t_bool s1nz, s2nz; +t_bool dbl = ((op & 0x20) == 0); +ufp_t fop1, fop2, t; +ufp_t res = { 0, 0, 0, 0 }; +uint32 tr; + +if (dbl) { /* double prec? */ + rh = R[rn]; /* get reg operands */ + rl = R[rn|1]; + if ((tr = ReadD (bva, &mh, &ml, VR)) != 0) /* get mem word */ + return tr; + } +else { /* single precision */ + rh = R[rn]; /* pad to double */ + rl = 0; + if ((tr = ReadW (bva, &mh, VR)) != 0) + return tr; + ml = 0; + } +fp_unpack (rh, rl, &fop1); /* unpack, test */ +fp_unpack (mh, ml, &fop2); +CC = 0; + +switch (op) { /* case on opcode */ + + case OP_FSS: /* subtract */ + case OP_FSL: + fop2.sign = fop2.sign ^ 1; /* invert mem sign */ + /* fall through */ + case OP_FAS: /* add */ + case OP_FAL: + s1nz = fp_clnzro (&fop1, TRUE); /* test, clean op1 */ + s2nz = fp_clnzro (&fop2, TRUE); + if (!s1nz) /* op1 = 0? res = op2 */ + res = fop2; + else if (!s2nz) /* op2 = 0? res = op1 */ + res = fop1; + else { /* both non-zero */ + if (fop1.exp < fop2.exp) { /* exp1 < exp2? */ + t = fop2; /* swap operands */ + fop2 = fop1; + fop1 = t; + } + ediff = fop1.exp - fop2.exp; /* exp difference */ + res.sign = fop1.sign; /* result sign, exp */ + res.exp = fop1.exp; + if (ediff) { /* any difference? */ + UFP_RSH_V (fop2, ediff * 4); /* shift frac */ + if (dbl) { /* double? */ + if ((PSW1 & PSW1_FR) == 0) /* rounding off? */ + fop2.l &= ~0xF; /* no guard */ + } + else fop2.l = 0; /* single? clr lo */ + } + if (fop1.sign ^ fop2.sign) { /* eff subtract */ + if (UFP_GE (fop1, fop2)) { /* fop1 >= fop2? */ + UFP_SUB (fop1, fop2, res); /* sub fractions */ + } + else { /* fop2 > fop1 */ + UFP_SUB (fop2, fop1, res); /* rev subtract */ + res.sign = fop2.sign; /* change signs */ + } + } /* end subtract */ + else { /* eff add */ + UFP_ADD (fop1, fop2, res); /* add fractions */ + if (res.h & UFP_CARRY) { /* carry out? */ + UFP_RSH_K (res, 4); /* renormalize */ + res.exp = res.exp + 1; /* incr exp */ + } + } /* end add */ + } /* end nz operands */ + if (!dbl) /* single? clr lo */ + res.l = 0; + if ((PSW1 & PSW1_FN) == 0) { /* postnormalize? */ + if ((res.h | res.l) == 0) { /* result zero? */ + CC = CC1; /* set signif flag */ + if (PSW1 & PSW1_FS) /* trap enabled? */ + return TR_FLT; + return fp_pack (&res, rn, dbl, FALSE); /* pack up */ + } + nsh = fp_norm (&res); /* normalize */ + if ((res.exp < 0) && /* underflow? */ + !(PSW1 & PSW1_FZ) && /* !FN */ + (PSW1 & PSW1_FS) && /* FS */ + (nsh > 2)) { /* shifts > 2? */ + CC = CC1 | (res.sign? CC4: CC3); /* signif CC's */ + return TR_FLT; /* trap */ + } /* end if underflow */ + else if (nsh > 2) { /* shifts > 2? */ + CC |= CC1 | (res.sign? CC4: CC3); /* set CC1 */ + if (PSW1 & PSW1_FS) /* trap enabled? */ + return TR_FLT; + } + } /* end if postnorm */ + return fp_pack (&res, rn, dbl, TRUE); /* pack result */ + + case OP_FMS: + case OP_FML: /* floating multiply */ + s1nz = fp_clnzro (&fop1, FALSE); /* test, clean op1 */ + s2nz = fp_clnzro (&fop2, FALSE); + if (s1nz && s2nz) { /* both non-zero? */ + fp_norm (&fop1); /* prenormalize */ + fp_norm (&fop2); + UFP_RSH_K (fop2, 4); /* undo guard */ + res.sign = fop1.sign ^ fop2.sign; /* result sign */ + res.exp = fop1.exp + fop2.exp - FP_BIAS; /* result exp */ + if (!dbl) { /* 24b x 24b? */ + for (i = 0; i < 24; i++) { /* 24 iterations */ + if (fop2.h & 1) + res.h = res.h + fop1.h; /* add hi only */ + UFP_RSH_K (res, 1); /* shift dp res */ + fop2.h = fop2.h >> 1; + } + res.l = 0; /* single prec */ + } + else { /* some low 0's */ + for (i = 0; i < 56; i++) { /* 56 iterations */ + if (fop2.l & 1) { + UFP_ADD (res, fop1, res); + } + UFP_RSH_K (res, 1); + UFP_RSH_K (fop2, 1); + } + } + fp_norm (&res); /* normalize result */ + } + return fp_pack (&res, rn, dbl, TRUE); /* pack result */ + + case OP_FDS: + case OP_FDL: /* floating divide */ + s1nz = fp_clnzro (&fop1, FALSE); /* test, clean op1 */ + s2nz = fp_clnzro (&fop2, FALSE); + if (!s2nz) { /* divide by zero? */ + CC = CC2; /* set CC2 */ + return TR_FLT; /* trap */ + } + if (s1nz) { /* divd non-zero? */ + fp_norm (&fop1); /* prenormalize */ + fp_norm (&fop2); + res.sign = fop1.sign ^ fop2.sign; /* result sign */ + res.exp = fop1.exp - fop2.exp + FP_BIAS; /* result exp */ + if (!UFP_GE (fop1, fop2)) { + UFP_LSH_K (fop1, 4); /* ensure success */ + } + else res.exp = res.exp + 1; /* incr exponent */ + for (i = 0; i < (uint32)(dbl? 15: 7); i++) {/* 7/15 hex digits */ + UFP_LSH_K (res, 4); /* shift quotient */ + while (UFP_GE (fop1, fop2)) { /* while sub works */ + UFP_SUB (fop1, fop2, fop1); /* decrement */ + res.l = res.l + 1; /* add quo bit */ + } + UFP_LSH_K (fop1, 4); /* shift divd */ + } /* end hex loop */ + if (!dbl) { /* single? */ + res.h = res.l; /* move quotient */ + res.l = 0; + } + fp_norm (&res); /* normalize result */ + } + return fp_pack (&res, rn, dbl, TRUE); /* pack result */ + } /* end case */ + +return SCPE_IERR; +} + +void ShiftF (uint32 rn, uint32 stype, uint32 sc) +{ +uint32 opnd, opnd1; +ufp_t src; + +opnd = R[rn]; /* get operands */ +opnd1 = stype? R[rn|1]: 0; /* zextend single */ +fp_unpack (opnd, opnd1, &src); /* unpack */ + +CC = 0; +if (sc & SCSIGN) { /* right? */ + sc = SHF_M_SC + 1 - sc; + while (sc > 0) { /* while count */ + UFP_RSH_K (src, 4); /* shift right hex */ + if (stype) /* zero guard */ + src.l &= ~0xF; + else src.h &= ~0xF; + src.exp++; /* incr exp */ + sc--; + if (src.exp > FP_M_EXP) { /* overflow? */ + CC |= CC2; /* set CC2, stop */ + break; + } + } /* end while */ + if ((src.h | src.l) == 0) { /* result 0? */ + if (stype) /* result is true 0 */ + R[rn|1] = 0; + R[rn] = 0; + CC = 0; + return; + } + } +else { /* left */ + if ((src.h | src.l) == 0) { /* fraction 0? */ + if (stype) /* result is true 0 */ + R[rn|1] = 0; + R[rn] = 0; + CC = CC1; + return; + } + while ((sc > 0) && ((src.h & UFP_NORM) == 0)) { /* while count & !norm */ + UFP_LSH_K (src, 4); /* hex shift left */ + src.exp--; /* decr exp */ + sc--; + if (src.exp < 0) { /* underflow? */ + CC |= CC2; /* set CC2, stop */ + break; + } + } /* end while */ + if (src.h & UFP_NORM) /* normalized? */ + CC |= CC1; /* set CC1 */ + } +fp_pack (&src, rn, stype, FALSE); /* pack result */ +return; +} + +void fp_unpack (uint32 hi, uint32 lo, ufp_t *dst) +{ +dst->sign = FP_GETSIGN (hi); /* get sign */ +if (dst->sign) /* negative? */ + NEG_D (hi, lo); /* 2's compl */ +dst->h = FP_GETFRHI (hi); /* get fraction */ +dst->l = FP_GETFRLO (lo); +dst->exp = FP_GETEXP (hi); /* get exp */ +UFP_LSH_KP (dst, 4); /* guard result */ +return; +} + +/* Test for and clean a floating point zero + abnorm defines whether to allow "abnormal" zeros */ + +t_bool fp_clnzro (ufp_t *src, t_bool abnorm) +{ +if (((src->h | src->l) == 0) && /* frac zero and */ + (!abnorm || (src->exp == 0))) { /* exp zero or !ab */ + src->sign = 0; /* true zero */ + src->exp = 0; + return FALSE; + } +return TRUE; /* non-zero */ +} + +uint32 fp_pack (ufp_t *src, uint32 rn, t_bool dbl, t_bool rndtrap) +{ +static ufp_t fp_zero = { 0, 0, 0, 0}; +uint32 opnd, opnd1; + +if (src->h || (dbl && src->l)) { /* result != 0? */ + CC |= (src->sign? CC4: CC3); /* set CC's */ + if (rndtrap) { /* round, trap? */ + if (PSW1 & PSW1_FR) { /* round? */ + if (dbl) { /* double prec? */ + src->l = (src->l + 0x8) & UFP_FRLO; + src->h = src->h + (src->l < 0x8); + } + else src->h = src->h + 0x8; /* no, single */ + if (src->h & UFP_CARRY) { /* carry out? */ + UFP_RSH_KP (src, 4); /* renormalize */ + src->exp = src->exp + 1; + } + } /* end if round */ + if (src->exp > FP_M_EXP) { /* overflow? */ + CC |= CC2; /* flag */ + return TR_FLT; + } + else if (src->exp < 0) { /* underflow? */ + if (PSW1 & PSW1_FZ) { /* trap enabled? */ + CC |= CC1 | CC2; /* flag */ + return TR_FLT; + } + *src = fp_zero; /* result 0 */ + CC = CC1|CC2; /* special CC's */ + } + } /* end rnd trap */ + UFP_RSH_KP (src, 4); /* remove guard */ + if (!dbl) /* single? lose lower */ + src->l = 0; + if ((src->h | src->l) == 0) /* result now 0? */ + src->exp = src->sign = 0; + } +else *src = fp_zero; +opnd = ((src->exp & FP_M_EXP) << FP_V_EXP) | /* repack */ + ((src->h & FP_M_FRHI) << FP_V_FRHI); +opnd1 = src->l & FP_M_FRLO; +if (src->sign) /* negative? */ + NEG_D (opnd, opnd1); +R[rn] = opnd; /* store result */ +if (dbl && ((rn & 1) == 0)) + R[rn|1] = opnd1; +return 0; +} + +uint32 fp_norm (ufp_t *src) +{ +uint32 nsh; + +nsh = 0; +src->h &= UFP_FRHI; +if (src->h || src->l) { /* if non-zero */ + while ((src->h & UFP_NORM) == 0) { /* until normalized */ + UFP_LSH_KP (src, 4); /* hex shift left */ + src->exp--; /* decr exponent */ + nsh++; /* count shifts */ + } + } +return nsh; +} + diff --git a/sigma/sigma_io.c b/sigma/sigma_io.c new file mode 100644 index 00000000..c24d063d --- /dev/null +++ b/sigma/sigma_io.c @@ -0,0 +1,1486 @@ +/* sigma_io.c: XDS Sigma IO simulator + + Copyright (c) 2007-2008, Robert M Supnik + + 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 + ROBERT M SUPNIK 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 Robert M Supnik shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. +*/ + +#include "sigma_io_defs.h" + +#define VALID_DVA(c,d) \ + (((c) < chan_num) && ((d) < CHAN_N_DEV) && (chan[c].disp[d] != NULL)) + +uint32 int_hiact = NO_INT; /* hi act int */ +uint32 int_hireq = NO_INT; /* hi int req */ +uint32 chan_ctl_time = 5; +uint32 ei_bmax = EIGRP_DFLT; /* ext int grps */ +uint32 s9_snap = 0; +uint32 s9_marg = 0; +uint32 chan_num = CHAN_DFLT; /* num chan */ +uint32 s5x0_ireg[] = { 0 }; +uint16 int_arm[INTG_MAX]; /* int grps: arm */ +uint16 int_enb[INTG_MAX]; /* enable */ +uint16 int_req[INTG_MAX]; /* request */ +uint8 int_lnk[INTG_MAX] = { /* pri chain */ + INTG_OVR, INTG_CTR, INTG_IO, 0 + }; + +/* Interrupt group priority chain templates */ + +#define I_STD 0x80 + +static uint8 igrp_dflt_5x0[] = { + I_STD|INTG_OVR, I_STD|INTG_CTR, I_STD|INTG_IO, INTG_E2, + INTG_E3, INTG_E3+1, INTG_E3+2, 0 + }; + +static uint8 igrp_dflt_S56789[] = { + I_STD|INTG_OVR, I_STD|INTG_CTR, I_STD|INTG_IO, INTG_E2, + INTG_E3, INTG_E3+1, INTG_E3+2, INTG_E3+3, + INTG_E3+4, INTG_E3+5, INTG_E3+6, INTG_E3+7, + INTG_E3+9, INTG_E3+9, INTG_E3+10, INTG_E3+11, + INTG_E3+12, 0 + }; + +chan_t chan[CHAN_N_CHAN]; +uint32 (*dio_disp[DIO_N_MOD])(uint32, uint32, uint32); + +int_grp_t int_tab[INTG_MAX] = { +/* PSW inh #bits vec grp regbit */ + { 0, 6, 0x052, 0x0, 16 }, + { PSW2_CI, 4, 0x058, 0x0, 22 }, + { PSW2_II, 2, 0x05C, 0x0, 26 }, + { PSW2_EI, 16, 0x060, 0x2, 16 }, + { PSW2_EI, 16, 0x070, 0x3, 16 }, + { PSW2_EI, 16, 0x080, 0x4, 16 }, + { PSW2_EI, 16, 0x090, 0x5, 16 }, + { PSW2_EI, 16, 0x0A0, 0x6, 16 }, + { PSW2_EI, 16, 0x0B0, 0x7, 16 }, + { PSW2_EI, 16, 0x0C0, 0x8, 16 }, + { PSW2_EI, 16, 0x0D0, 0x9, 16 }, + { PSW2_EI, 16, 0x0E0, 0xA, 16 }, + { PSW2_EI, 16, 0x0F0, 0xB, 16 }, + { PSW2_EI, 16, 0x100, 0xC, 16 }, + { PSW2_EI, 16, 0x110, 0xD, 16 }, + { PSW2_EI, 16, 0x120, 0xE, 16 }, + { PSW2_EI, 16, 0x130, 0xF, 16 } + }; + +extern uint32 *R; +extern uint32 PSW1, PSW2; +extern uint32 CC, SSW; +extern uint32 stop_op; +extern uint32 cpu_model; +extern uint32 cons_alarm, cons_pcf; +extern UNIT cpu_unit; +extern cpu_var_t cpu_tab[]; + +void io_eval_ioint (void); +t_bool io_init_inst (uint32 ad, uint32 rn, uint32 ch, uint32 dev, uint32 r0); +uint32 io_set_status (uint32 rn, uint32 ch, uint32 dev, uint32 dvst, t_bool tdv); +uint32 io_rwd_m0 (uint32 op, uint32 rn, uint32 ad); +uint32 io_rwd_m1 (uint32 op, uint32 rn, uint32 ad); +t_stat io_set_eiblks (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat io_show_eiblks (FILE *st, UNIT *uptr, int32 val, void *desc); +t_stat int_reset (DEVICE *dptr); +t_stat chan_reset (DEVICE *dptr); +uint32 chan_new_cmd (uint32 ch, uint32 dev, uint32 clc); +void io_set_eimax (uint32 max); +uint32 chan_proc_prolog (uint32 dva, uint32 *ch, uint32 *dev); +uint32 chan_proc_epilog (uint32 dva, int32 cnt); + +extern uint32 cpu_new_PSD (uint32 lrp, uint32 p1, uint32 p2); + +/* IO data structures + + io_dev IO device descriptor + io_unit IO unit + io_reg IO register list + io_mod IO modifier list +*/ + +dib_t int_dib = { 0, NULL, 1, io_rwd_m1 }; + +UNIT int_unit = { UDATA (NULL, 0, 0) }; + +REG int_reg[] = { + { HRDATA (IHIACT, int_hiact, 9) }, + { HRDATA (IHIREQ, int_hireq, 9) }, + { BRDATA (IREQ, int_req, 16, 16, INTG_MAX) }, + { BRDATA (IENB, int_enb, 16, 16, INTG_MAX) }, + { BRDATA (IARM, int_arm, 16, 16, INTG_MAX) }, + { BRDATA (ILNK, int_lnk, 10, 8, INTG_MAX), REG_HRO }, + { DRDATA (EIBLKS, ei_bmax, 4), REG_HRO }, + { HRDATA (S9_SNAP, s9_snap, 32) }, + { HRDATA (S9_MARG, s9_marg, 32) }, + { BRDATA (S5X0_IREG, s5x0_ireg, 16, 32, 32) }, + { NULL } + }; + +MTAB int_mod[] = { + { MTAB_XTD|MTAB_VDV, 0, "EIBLKS", "EIBLKS", + &io_set_eiblks, &io_show_eiblks }, + { 0 } + }; + +DEVICE int_dev = { + "INT", &int_unit, int_reg, int_mod, + 1, 16, 16, 1, 16, 32, + NULL, NULL, &int_reset, + NULL, NULL, NULL, + &int_dib, 0 + }; + +/* Channel data structures */ + +UNIT chan_unit[] = { + { UDATA (NULL, 0, 0) }, + { UDATA (NULL, 0, 0) }, + { UDATA (NULL, 0, 0) }, + { UDATA (NULL, 0, 0) }, + { UDATA (NULL, 0, 0) }, + { UDATA (NULL, 0, 0) }, + { UDATA (NULL, 0, 0) }, + { UDATA (NULL, 0, 0) } + }; + +REG chana_reg[] = { + { BRDATA (CLC, chan[0].clc, 16, 20, CHAN_N_DEV) }, + { BRDATA (CMD, chan[0].cmd, 16, 8, CHAN_N_DEV) }, + { BRDATA (CMF, chan[0].cmf, 16, 8, CHAN_N_DEV) }, + { BRDATA (BA, chan[0].ba, 16, 24, CHAN_N_DEV) }, + { BRDATA (BC, chan[0].bc, 16, 16, CHAN_N_DEV) }, + { BRDATA (CHF, chan[0].chf, 16, 16, CHAN_N_DEV) }, + { BRDATA (CHI, chan[0].chi, 16, 8, CHAN_N_DEV) }, + { BRDATA (CHSF, chan[0].chsf, 16, 8, CHAN_N_DEV) }, + { NULL } + }; + +REG chanb_reg[] = { + { BRDATA (CLC, chan[1].clc, 16, 20, CHAN_N_DEV) }, + { BRDATA (CMD, chan[1].cmd, 16, 8, CHAN_N_DEV) }, + { BRDATA (CMF, chan[1].cmf, 16, 8, CHAN_N_DEV) }, + { BRDATA (BA, chan[1].ba, 16, 24, CHAN_N_DEV) }, + { BRDATA (BC, chan[1].bc, 16, 16, CHAN_N_DEV) }, + { BRDATA (CHF, chan[1].chf, 16, 16, CHAN_N_DEV) }, + { BRDATA (CHI, chan[1].chi, 16, 8, CHAN_N_DEV) }, + { BRDATA (CHSF, chan[1].chsf, 16, 8, CHAN_N_DEV) }, + { NULL } + }; + +REG chanc_reg[] = { + { BRDATA (CLC, chan[2].clc, 16, 20, CHAN_N_DEV) }, + { BRDATA (CMD, chan[2].cmd, 16, 8, CHAN_N_DEV) }, + { BRDATA (CMF, chan[2].cmf, 16, 8, CHAN_N_DEV) }, + { BRDATA (BA, chan[2].ba, 16, 24, CHAN_N_DEV) }, + { BRDATA (BC, chan[2].bc, 16, 16, CHAN_N_DEV) }, + { BRDATA (CHF, chan[2].chf, 16, 16, CHAN_N_DEV) }, + { BRDATA (CHI, chan[2].chi, 16, 8, CHAN_N_DEV) }, + { BRDATA (CHSF, chan[2].chsf, 16, 8, CHAN_N_DEV) }, + { NULL } + }; + +REG chand_reg[] = { + { BRDATA (CLC, chan[3].clc, 16, 20, CHAN_N_DEV) }, + { BRDATA (CMD, chan[3].cmd, 16, 8, CHAN_N_DEV) }, + { BRDATA (CMF, chan[3].cmf, 16, 8, CHAN_N_DEV) }, + { BRDATA (BA, chan[3].ba, 16, 24, CHAN_N_DEV) }, + { BRDATA (BC, chan[3].bc, 16, 16, CHAN_N_DEV) }, + { BRDATA (CHF, chan[3].chf, 16, 16, CHAN_N_DEV) }, + { BRDATA (CHI, chan[3].chi, 16, 8, CHAN_N_DEV) }, + { BRDATA (CHSF, chan[3].chsf, 16, 8, CHAN_N_DEV) }, + { NULL } + }; + +REG chane_reg[] = { + { BRDATA (CLC, chan[4].clc, 16, 20, CHAN_N_DEV) }, + { BRDATA (CMD, chan[4].cmd, 16, 8, CHAN_N_DEV) }, + { BRDATA (CMF, chan[4].cmf, 16, 8, CHAN_N_DEV) }, + { BRDATA (BA, chan[4].ba, 16, 24, CHAN_N_DEV) }, + { BRDATA (BC, chan[4].bc, 16, 16, CHAN_N_DEV) }, + { BRDATA (CHF, chan[4].chf, 16, 16, CHAN_N_DEV) }, + { BRDATA (CHI, chan[4].chi, 16, 8, CHAN_N_DEV) }, + { BRDATA (CHSF, chan[4].chsf, 16, 8, CHAN_N_DEV) }, + { NULL } + }; + +REG chanf_reg[] = { + { BRDATA (CLC, chan[5].clc, 16, 20, CHAN_N_DEV) }, + { BRDATA (CMD, chan[5].cmd, 16, 8, CHAN_N_DEV) }, + { BRDATA (CMF, chan[5].cmf, 16, 8, CHAN_N_DEV) }, + { BRDATA (BA, chan[5].ba, 16, 24, CHAN_N_DEV) }, + { BRDATA (BC, chan[5].bc, 16, 16, CHAN_N_DEV) }, + { BRDATA (CHF, chan[5].chf, 16, 16, CHAN_N_DEV) }, + { BRDATA (CHI, chan[5].chi, 16, 8, CHAN_N_DEV) }, + { BRDATA (CHSF, chan[5].chsf, 16, 8, CHAN_N_DEV) }, + { NULL } + }; + +REG chang_reg[] = { + { BRDATA (CLC, chan[6].clc, 16, 20, CHAN_N_DEV) }, + { BRDATA (CMD, chan[6].cmd, 16, 8, CHAN_N_DEV) }, + { BRDATA (CMF, chan[6].cmf, 16, 8, CHAN_N_DEV) }, + { BRDATA (BA, chan[6].ba, 16, 24, CHAN_N_DEV) }, + { BRDATA (BC, chan[6].bc, 16, 16, CHAN_N_DEV) }, + { BRDATA (CHF, chan[6].chf, 16, 16, CHAN_N_DEV) }, + { BRDATA (CHI, chan[6].chi, 16, 8, CHAN_N_DEV) }, + { BRDATA (CHSF, chan[6].chsf, 16, 8, CHAN_N_DEV) }, + { NULL } + }; + +REG chanh_reg[] = { + { BRDATA (CLC, chan[7].clc, 16, 20, CHAN_N_DEV) }, + { BRDATA (CMD, chan[7].cmd, 16, 8, CHAN_N_DEV) }, + { BRDATA (CMF, chan[7].cmf, 16, 8, CHAN_N_DEV) }, + { BRDATA (BA, chan[7].ba, 16, 24, CHAN_N_DEV) }, + { BRDATA (BC, chan[7].bc, 16, 16, CHAN_N_DEV) }, + { BRDATA (CHF, chan[7].chf, 16, 16, CHAN_N_DEV) }, + { BRDATA (CHI, chan[7].chi, 16, 8, CHAN_N_DEV) }, + { BRDATA (CHSF, chan[7].chsf, 16, 8, CHAN_N_DEV) }, + { NULL } + }; + +DEVICE chan_dev[] = { + { + "CHANA", &chan_unit[0], chana_reg, NULL, + 1, 16, 16, 1, 16, 32, + NULL, NULL, &chan_reset, + NULL, NULL, NULL, + NULL, CHAN_MIOP, 0 + }, + { + "CHANB", &chan_unit[1], chanb_reg, NULL, + 1, 16, 16, 1, 16, 32, + NULL, NULL, &chan_reset, + NULL, NULL, NULL, + NULL, CHAN_MIOP, 0 + }, + { + "CHANC", &chan_unit[2], chanc_reg, NULL, + 1, 16, 16, 1, 16, 32, + NULL, NULL, &chan_reset, + NULL, NULL, NULL, + NULL, CHAN_SIOP, 0 + }, + { + "CHAND", &chan_unit[3], chand_reg, NULL, + 1, 16, 16, 1, 16, 32, + NULL, NULL, &chan_reset, + NULL, NULL, NULL, + NULL, CHAN_SIOP, 0 + }, + { + "CHANE", &chan_unit[4], chane_reg, NULL, + 1, 16, 16, 1, 16, 32, + NULL, NULL, &chan_reset, + NULL, NULL, NULL, + NULL, CHAN_SIOP|DEV_DIS, 0 + }, + { + "CHANF", &chan_unit[5], chanf_reg, NULL, + 1, 16, 16, 1, 16, 32, + NULL, NULL, &chan_reset, + NULL, NULL, NULL, + NULL, CHAN_SIOP|DEV_DIS, 0 + }, + { + "CHANG", &chan_unit[6], chang_reg, NULL, + 1, 16, 16, 1, 16, 32, + NULL, NULL, &chan_reset, + NULL, NULL, NULL, + NULL, CHAN_SIOP|DEV_DIS, 0 + }, + { + "CHANH", &chan_unit[7], chanh_reg, NULL, + 1, 16, 16, 1, 16, 32, + NULL, NULL, &chan_reset, + NULL, NULL, NULL, + NULL, CHAN_SIOP|DEV_DIS, 0 + } + }; + + +/* Read direct */ + +uint32 io_rwd (uint32 op, uint32 rn, uint32 bva) +{ +uint32 ad = bva >> 2; +uint32 mode = DIO_GETMOD (ad); /* mode */ + +if (dio_disp[mode] != NULL) /* if defined */ + return dio_disp[mode] (op, rn, ad); /* dispatch */ +return (stop_op)? STOP_ILLEG: 0; /* ill inst */ +} + +/* Start IO */ + +uint32 io_sio (uint32 rn, uint32 bva) +{ +uint32 ad = bva >> 2; +uint32 ch, dev, dvst; +uint32 st; + +CC &= ~cpu_tab[cpu_model].iocc; /* clear CC's */ +ch = DVA_GETCHAN (ad); /* get chan, dev */ +dev = DVA_GETDEV (ad); +if (!io_init_inst (rn, ad, ch, dev, R[0])) { /* valid inst? */ + CC |= CC1|CC2; + return 0; + } +if (chan[ch].chf[dev] & CHF_INP) { /* int pending? */ + chan[ch].disp[dev] (OP_TIO, ad, &dvst); /* get status */ + CC |= (CC2 | io_set_status (rn, ch, dev, dvst, 0)); /* set status */ + return 0; + } +st = chan[ch].disp[dev] (OP_SIO, ad, &dvst); /* start I/O */ +CC |= io_set_status (rn, ch, dev, dvst, 0); /* set status */ +if (CC & cpu_tab[cpu_model].iocc) /* error? */ + return 0; +chan[ch].chf[dev] = 0; /* clear flags */ +chan[ch].chi[dev] = 0; /* clear intrs */ +chan[ch].chsf[dev] |= CHSF_ACT; /* set chan active */ +chan_new_cmd (ch, dev, R[0]); /* new command */ +return st; +} + +/* Test IO */ + +uint32 io_tio (uint32 rn, uint32 bva) +{ +uint32 ad = bva >> 2; +uint32 ch, dev, dvst; +uint32 st; + +CC &= ~cpu_tab[cpu_model].iocc; /* clear CC's */ +ch = DVA_GETCHAN (ad); /* get chan, dev */ +dev = DVA_GETDEV (ad); +if (!io_init_inst (rn, ad, ch, dev, 0)) { /* valid inst? */ + CC |= CC1|CC2; + return 0; + } +st = chan[ch].disp[dev] (OP_TIO, ad, &dvst); /* test status */ +CC |= io_set_status (rn, ch, dev, dvst, 0); /* set status */ +return st; +} + +/* Test device status */ + +uint32 io_tdv (uint32 rn, uint32 bva) +{ +uint32 ad = bva >> 2; +uint32 ch, dev, dvst; +uint32 st; + +CC &= ~cpu_tab[cpu_model].iocc; /* clear CC's */ +ch = DVA_GETCHAN (ad); /* get chan, dev */ +dev = DVA_GETDEV (ad); +if (!io_init_inst (rn, ad, ch, dev, 0)) { /* valid inst? */ + CC |= CC1|CC2; + return 0; + } +st = chan[ch].disp[dev] (OP_TDV, ad, &dvst); /* test status */ +CC |= io_set_status (rn, ch, dev, dvst, 1); /* set status */ +return st; +} + +/* Halt IO */ + +uint32 io_hio (uint32 rn, uint32 bva) +{ +uint32 ad = bva >> 2; +uint32 ch, dev, subop, dvst; +uint32 st; + +CC &= ~cpu_tab[cpu_model].iocc; +ad = bva >> 2; +ch = DVA_GETCHAN (ad); /* get chan, dev */ +dev = DVA_GETDEV (ad); +subop = (ad >> 13) & 0x7; +if (subop) { /* extended fnc? */ + if (!QCPU_S89_5X0 || (subop > 3)) /* S9, 5X0 only */ + return (stop_op? STOP_ILLEG: 0); + if (ch >= chan_num) { /* valid channel? */ + CC |= CC1|CC2; + return 0; + } + switch (subop) { + + case 1: /* reset channel */ + chan_reset (&chan_dev[ch]); + break; + + case 2: case 3: /* poll processor */ + if (rn) /* NI */ + R[rn] = 0; + break; + } + } +else { /* normal HIO */ + if (!io_init_inst (rn, ad, ch, dev, 0)) { /* valid inst? */ + CC |= CC1|CC2; + return 0; + } + st = chan[ch].disp[dev] (OP_HIO, ad, &dvst); /* halt IO */ + CC |= io_set_status (rn, ch, dev, dvst, 0); /* set status */ + } +return st; +} + +/* Acknowledge interrupt (ignores device address) */ + +uint32 io_aio (uint32 rn, uint32 bva) +{ +uint32 i, j, dva, dvst; +uint32 st; + +if (DVA_GETCHAN (bva >> 2) != 0) /* non std I/O addr? */ + return (stop_op? STOP_ILLEG: 0); +CC = CC & ~cpu_tab[cpu_model].iocc; /* clear CC's */ +for (i = 0; i < chan_num; i++) { /* loop thru chan */ + for (j = 0; j < CHAN_N_DEV; j++) { /* loop thru dev */ + if (chan[i].chf[j] & CHF_INP) { /* intr pending? */ + if (chan[i].disp[j] == NULL) { /* false interrupt? */ + chan[i].chf[j] &= ~CHF_INP; /* clear intr */ + continue; + } + dva = (i << DVA_V_CHAN) | /* chan number */ + ((chan[i].chsf[j] & CHSF_MU)? /* device number */ + ((j << DVA_V_DEVMU) | DVA_MU): + (j << DVA_V_DEVSU)); + st = chan[i].disp[j] (OP_AIO, dva, &dvst); /* get AIO status */ + dva |= DVT_GETUN (dvst); /* finish dev addr */ + if (rn) /* want status? */ + R[rn] = (DVT_GETDVS (dvst) << 24) | /* device status */ + ((uint32) ((chan[i].chf[j] & (CHF_LNTE|CHF_XMDE)) | + CHI_GETINT (chan[i].chi[j])) << 16) | dva; + if (chan[i].chi[j] & CHI_UEN) /* unusual end? */ + CC |= CC2; /* set CC2 */ + return st; + } + } /* end for dev */ + } /* end for chan */ +CC |= CC1|CC2; /* no recognition */ +return 0; +} + +/* Initiate I/O instruction */ + +t_bool io_init_inst (uint32 rn, uint32 ad, uint32 ch, uint32 dev, uint32 r0) +{ +uint32 loc20; + +if (ch >= chan_num) /* bad chan? */ + return FALSE; +loc20 = ((ad & 0xFF) << 24) | /* <0:7> = dev ad */ + ((rn & 1) | (rn? 3: 0) << 22) | /* <8:9> = reg ind */ + (r0 & (cpu_tab[cpu_model].pamask >> 1)); /* <14/16:31> = r0 */ +WritePW (0x20, loc20); +return (chan[ch].disp[dev] != NULL)? TRUE: FALSE; +} + +/* Set status for I/O instruction */ + +uint32 io_set_status (uint32 rn, uint32 ch, uint32 dev, uint32 dvst, t_bool tdv) +{ +uint32 mrgst; +uint32 odd = rn & 1; + +if ((rn != 0) && !(dvst & DVT_NOST)) { /* return status? */ + if (tdv) + mrgst = (DVT_GETDVS (dvst) << 8) | (chan[ch].chf[dev] & 0xFF); + else mrgst = ((DVT_GETDVS(dvst) << 8) & ~CHF_ALL) | (chan[ch].chf[dev] & CHF_ALL); + R[rn] = chan[ch].clc[dev]; /* even reg */ + if (!odd) /* even pair? */ + WritePW (0x20, R[rn]); /* write to 20 */ + R[rn|1] = (mrgst << 16) | chan[ch].bc[dev]; /* odd reg */ + WritePW (0x20 + odd, R[rn|1]); /* write to 20/21 */ + } +return DVT_GETCC (dvst); +} + +/* Channel support routines */ + +/* Get new command */ + +uint32 chan_get_cmd (uint32 dva, uint32 *cmd) +{ +uint32 ch, dev; +t_stat st; + +if ((st = chan_proc_prolog (dva, &ch, &dev)) != 0) /* valid, active? */ + return st; +*cmd = chan[ch].cmd[dev]; /* return cmd */ +return 0; +} + +/* Channel end */ + +uint32 chan_end (uint32 dva) +{ +uint32 ch, dev; +uint32 st; + +if ((st = chan_proc_prolog (dva, &ch, &dev)) != 0) /* valid, active? */ + return st; +if (chan[ch].cmf[dev] & CMF_ICE) /* int on chan end? */ + chan_set_chi (dva, CHI_END); +if ((chan[ch].cmf[dev] & CMF_CCH) && /* command chain? */ + !chan_new_cmd (ch, dev, chan[ch].clc[dev] + 1)) /* next command? */ + return CHS_CCH; +else chan[ch].chsf[dev] &= ~CHSF_ACT; /* channel inactive */ +return 0; +} + +/* Channel error */ + +uint32 chan_set_chf (uint32 dva, uint32 fl) +{ +uint32 ch, dev; + +ch = DVA_GETCHAN (dva); /* get chan, dev */ +dev = DVA_GETDEV (dva); +if (!VALID_DVA (ch, dev)) /* valid? */ + return SCPE_IERR; +fl &= ~CHF_INP; /* ignore int pend */ +chan[ch].chf[dev] |= fl; +if ((fl & CHF_LNTE) && /* length error */ + ((chan[ch].cmf[dev] & CMF_SIL) || /* suppressed? */ + !(chan[ch].cmf[dev] & CMF_HTE))) /* or don't stop? */ + fl &= ~CHF_LNTE; /* ignore it */ +if ((fl & CHF_XMDE) && /* data error? */ + !(chan[ch].cmf[dev] & CMF_HTE)) /* don't stop? */ + fl &= ~CHF_XMDE; /* ignore it */ +if ((fl & CHF_XMME) && /* memory error? */ + !(chan[ch].cmf[dev] & CMF_HTE)) /* don't stop? */ + fl &= ~CHF_XMME; /* ignore it */ +if (fl) /* fatal error? */ + return chan_uen (dva); /* unusual end */ +return 0; +} + +/* Channel test command flags */ + +t_bool chan_tst_cmf (uint32 dva, uint32 fl) +{ +uint32 ch, dev; + +ch = DVA_GETCHAN (dva); /* get chan, dev */ +dev = DVA_GETDEV (dva); +if (VALID_DVA (ch, dev) && /* valid? */ + (chan[ch].cmf[dev] & fl)) + return TRUE; +return FALSE; +} + +/* Channel unusual end */ + +uint32 chan_uen (uint32 dva) +{ +uint32 ch, dev; + +ch = DVA_GETCHAN (dva); /* get chan, dev */ +dev = DVA_GETDEV (dva); +if (!VALID_DVA (ch, dev)) /* valid? */ + return SCPE_IERR; +if (chan[ch].cmf[dev] & CMF_IUE) /* int on uend? */ + chan_set_chi (dva, CHI_UEN); +chan[ch].chf[dev] |= CHF_UEN; /* flag uend */ +chan[ch].chsf[dev] &= ~CHSF_ACT; +return CHS_INACTV; /* done */ +} + +/* Channel read processes */ + +uint32 chan_RdMemB (uint32 dva, uint32 *dat) +{ +uint32 ch, dev; +uint32 st; + +if ((st = chan_proc_prolog (dva, &ch, &dev)) != 0) /* valid, active? */ + return st; +if (chan[ch].cmf[dev] & CMF_SKP) /* skip? */ + *dat = 0; +else if (ReadPB (chan[ch].ba[dev], dat)) { /* read data, nxm? */ + chan[ch].chf[dev] |= CHF_XMAE; /* addr error */ + return CHS_NXM; /* dev will uend */ + } +return chan_proc_epilog (dva, 1); /* adjust counts */ +} + +uint32 chan_RdMemW (uint32 dva, uint32 *dat) +{ +uint32 ch, dev; +uint32 st; + +if ((st = chan_proc_prolog (dva, &ch, &dev)) != 0) /* valid, active? */ + return st; +if (chan[ch].cmf[dev] & CMF_SKP) /* skip? */ + *dat = 0; +else if ((chan[ch].bc[dev] < 4) || /* unaligned? */ + ((chan[ch].ba[dev] & 0x3) != 0)) { + uint32 i, wd; + for (i = 0, *dat = 0, wd = 0; i < 4; i++) { /* up to 4 bytes */ + st = chan_RdMemB (dva, &wd); /* get byte */ + *dat |= ((wd & 0xFF) << (24 - (i * 8))); /* pack */ + if (st != 0) /* stop if error */ + return st; + } + return 0; + } +else if (ReadPW (chan[ch].ba[dev] >> 2, dat)) { /* read word, nxm? */ + chan[ch].chf[dev] |= CHF_XMAE; /* addr error */ + return CHS_NXM; /* dev will uend */ + } +return chan_proc_epilog (dva, 4); /* adjust counts */ +} + +/* Channel write processes */ + +uint32 chan_WrMemB (uint32 dva, uint32 dat) +{ +uint32 ch, dev; +uint32 st; + +if ((st = chan_proc_prolog (dva, &ch, &dev)) != 0) /* valid, active? */ + return st; +if (((chan[ch].cmf[dev] & CMF_SKP) == 0) && /* skip? */ + WritePB (chan[ch].ba[dev], dat)) { /* write data, nxm? */ + chan[ch].chf[dev] |= CHF_XMAE; /* addr error */ + return CHS_NXM; /* dev will uend */ + } +return chan_proc_epilog (dva, 1); /* adjust counts */ +} + +uint32 chan_WrMemBR (uint32 dva, uint32 dat) +{ +uint32 ch, dev; +uint32 st; + +if ((st = chan_proc_prolog (dva, &ch, &dev)) != 0) /* valid, active? */ + return st; +if (((chan[ch].cmf[dev] & CMF_SKP) == 0) && /* skip? */ + WritePB (chan[ch].ba[dev], dat)) { /* write data, nxm? */ + chan[ch].chf[dev] |= CHF_XMAE; /* addr error */ + return CHS_NXM; /* dev will uend */ + } +return chan_proc_epilog (dva, -1); /* adjust counts */ +} + +uint32 chan_WrMemW (uint32 dva, uint32 dat) +{ +uint32 ch, dev; +uint32 st; + +if ((st = chan_proc_prolog (dva, &ch, &dev)) != 0) /* valid, active? */ + return st; +if ((chan[ch].bc[dev] < 4) || /* unaligned? */ + ((chan[ch].ba[dev] & 0x3) != 0)) { + uint32 i, wd; + for (i = 0; i < 4; i++) { /* up to 4 bytes */ + wd = (dat >> (24 - (i * 8))) & 0xFF; /* get byte */ + if ((st = chan_WrMemB (dva, wd)) != 0) /* write */ + return st; /* stop if error */ + } + return 0; + } +if (((chan[ch].cmf[dev] & CMF_SKP) == 0) && /* skip? */ + WritePW (chan[ch].ba[dev] >> 2, dat)) { /* write word, nxm? */ + chan[ch].chf[dev] |= CHF_XMAE; /* addr error */ + return CHS_NXM; /* dev will uend */ + } +return chan_proc_epilog (dva, 4); /* adjust counts */ +} + +/* Channel process common code */ + +uint32 chan_proc_prolog (uint32 dva, uint32 *ch, uint32 *dev) +{ +*ch = DVA_GETCHAN (dva); /* get chan, dev */ +*dev = DVA_GETDEV (dva); +if (!VALID_DVA (*ch, *dev)) /* valid? */ + return SCPE_IERR; +if ((chan[*ch].chsf[*dev] & CHSF_ACT) == 0) /* active? */ + return CHS_INACTV; +return 0; +} + +uint32 chan_proc_epilog (uint32 dva, int32 cnt) +{ +uint32 ch = DVA_GETCHAN (dva); /* get ch, dev */ +uint32 dev = DVA_GETDEV (dva); + +chan[ch].ba[dev] = (chan[ch].ba[dev] + cnt) & CHBA_MASK; +chan[ch].bc[dev] = (chan[ch].bc[dev] - abs (cnt)) & CHBC_MASK; +if (chan[ch].bc[dev] != 0) /* more to do? */ + return 0; +if (chan[ch].cmf[dev] & CMF_IZC) /* int on zero?*/ + chan_set_chi (dva, CHI_ZBC); +if (chan[ch].cmf[dev] & CMF_DCH) { /* data chaining? */ + if (chan_new_cmd (ch, dev, chan[ch].clc[dev] + 1)) + return CHS_ZBC; + return 0; + } +return CHS_ZBC; +} + +/* New channel command */ + +uint32 chan_new_cmd (uint32 ch, uint32 dev, uint32 clc) +{ +uint32 i, ccw1, ccw2, cmd; + +for (i = 0; i < 2; i++) { /* max twice */ + clc = clc & (cpu_tab[cpu_model].pamask >> 1); /* mask clc */ + chan[ch].clc[dev] = clc; /* and save */ + if (ReadPW (clc << 1, &ccw1)) { /* get ccw1, nxm? */ + chan[ch].chf[dev] |= CHF_IOME; /* memory error */ + chan[ch].chsf[dev] &= ~CHSF_ACT; /* stop channel */ + return CHS_INACTV; + } + ReadPW ((clc << 1) + 1, &ccw2); /* get ccw2 */ + cmd = CCW1_GETCMD (ccw1); /* get chan cmd */ + if ((cmd & 0xF) == CMD_TIC) /* transfer? */ + clc = ccw1; /* try again */ + else { + chan[ch].cmd[dev] = cmd; /* decompose CCW */ + chan[ch].ba[dev] = CCW1_GETBA (ccw1); + chan[ch].cmf[dev] = CCW2_GETCMF (ccw2); + chan[ch].bc[dev] = CCW2_GETBC (ccw2); + return 0; + } + } +chan[ch].chf[dev] |= CHF_IOCE; /* control error */ +chan[ch].chsf[dev] &= ~CHSF_ACT; /* stop channel */ +return CHS_INACTV; +} + +/* Set, clear, test channel interrupt */ + +void chan_set_chi (uint32 dva, uint32 fl) +{ +uint32 ch = DVA_GETCHAN (dva); /* get ch, dev */ +uint32 dev = DVA_GETDEV (dva); +uint32 un = DVA_GETUNIT (dva); /* get unit */ + +chan[ch].chf[dev] |= CHF_INP; /* int pending */ +chan[ch].chi[dev] = (chan[ch].chi[dev] & CHI_FLAGS) | /* update status */ + fl | CHI_CTL | un; /* save unit */ +return; +} + +int32 chan_clr_chi (uint32 dva) +{ +uint32 ch = DVA_GETCHAN (dva); /* get ch, dev */ +uint32 dev = DVA_GETDEV (dva); +uint32 old_chi = chan[ch].chi[dev]; + +chan[ch].chf[dev] &= ~CHF_INP; /* clr int pending */ +chan[ch].chi[dev] &= CHI_FLAGS; /* clr ctl int */ +if (old_chi & CHI_CTL) + return CHI_GETUN (old_chi); +else return -1; +} + +int32 chan_chk_chi (uint32 dva) +{ +uint32 ch = DVA_GETCHAN (dva); /* get ch, dev */ +uint32 dev = DVA_GETDEV (dva); + +if (chan[ch].chi[dev] & CHI_CTL) /* ctl int pending? */ + return CHI_GETUN (chan[ch].chi[dev]); +else return -1; +} + +/* Set device interrupt */ + +void chan_set_dvi (uint32 dva) +{ +uint32 ch = DVA_GETCHAN (dva); /* get ch, dev */ +uint32 dev = DVA_GETDEV (dva); + +chan[ch].chf[dev] |= CHF_INP; /* int pending */ +return; +} + +/* Called by device reset to reset channel registers */ + +t_stat chan_reset_dev (uint32 dva) +{ +uint32 ch, dev; + +ch = DVA_GETCHAN (dva); /* get chan, dev */ +dev = DVA_GETDEV (dva); +if (!VALID_DVA (ch, dev)) /* valid? */ + return SCPE_IERR; +chan[ch].chf[dev] &= ~CHF_INP; /* clear intr */ +chan[ch].chsf[dev] &= ~CHSF_ACT; /* clear active */ +return SCPE_OK; +} + +/* Find highest priority pending interrupt + Question: must an interrupt be armed to be recognized? + Answer: yes; req'arm = 11 signifies waiting state */ + +uint32 io_eval_int (void) +{ +uint32 i, j, t, curr, mask, newi; + +if (int_arm[INTG_IO] & INTGIO_IO) /* I/O armed? */ + io_eval_ioint (); /* eval I/O interrupt */ +for (i = 0, curr = 0; i < INTG_MAX; i++) { /* loop thru groups */ + t = int_req[curr] & int_arm[curr] & int_enb[curr]; /* req, armed, enb */ + if ((t != 0) && /* any waiting req? */ + ((PSW2 & int_tab[curr].psw2_inh) == 0)) { /* group not inh? */ + for (j = 0; j < int_tab[curr].nbits; j++) { /* loop thru reqs */ + mask = 1u << (int_tab[curr].nbits - j - 1); + if (t & mask) { /* request active? */ + newi = INTV (curr, j); /* get int number */ + if (newi < int_hiact) /* higher priority? */ + return newi; /* new highest actv */ + return NO_INT; /* no pending intr */ + } + } + sim_printf ("%%int eval consistency error = %X\r\n", t); + int_req[curr] = 0; /* "impossible" */ + } + if (curr == INT_GETGRP (int_hiact)) /* at active group? */ + return NO_INT; /* no pending intr */ + curr = int_lnk[curr]; /* next group */ + if (curr == 0) /* end of list? */ + return NO_INT; /* no pending intr */ + } +sim_printf ("%%int eval consistency error, list end not found\r\n"); +return NO_INT; +} + +/* See if any interrupt is possible (used by WAIT) */ + +t_bool io_poss_int (void) +{ +uint32 i, curr; + +for (i = 0, curr = 0; i < INTG_MAX; i++) { /* loop thru groups */ + if (((int_arm[curr] & int_enb[curr]) != 0) && + ((PSW2 & int_tab[curr].psw2_inh) == 0)) /* group not inh? */ + return TRUE; /* int can occur */ + curr = int_lnk[curr]; /* next group */ + if (curr == 0) /* end of list? */ + return FALSE; /* no int possible */ + } +sim_printf ("%%int possible consistency error, list end not found\r\n"); +return FALSE; +} + +/* Evaluate I/O interrupts */ + +void io_eval_ioint (void) +{ +uint32 i, j; + +for (i = 0; i < chan_num; i++) { /* loop thru chan */ + for (j = 0; j < CHAN_N_DEV; j++) { /* loop thru dev */ + if (chan[i].chf[j] & CHF_INP) { /* intr pending? */ + int_req[INTG_IO] |= INTGIO_IO; /* set I/O intr */ + return; + } /* end if int pend */ + } /* end for dev */ + } /* end for chan */ +return; +} + +/* Find highest priority active interrupt + Question: is an inhibited or disabled interrupt recognized? + Answer: yes; req'arm = 10 signifies active state */ + +uint32 io_actv_int (void) +{ +uint32 i, j, t, curr, mask; + +for (i = 0, curr = 0; i < INTG_MAX; i++) { /* loop thru groups */ + if ((t = int_req[curr] & ~int_arm[curr]) != 0) { /* req active? */ + for (j = 0; j < int_tab[curr].nbits; j++) { /* loop thru reqs */ + mask = 1u << (int_tab[curr].nbits - j - 1); + if (t & mask) /* req active? */ + return INTV (curr, j); /* return int num */ + } + sim_printf ("%%int actv consistency error = %X\r\n", t); + int_req[curr] = 0; /* "impossible" */ + } + curr = int_lnk[curr]; /* next group */ + if (curr == 0) /* end of list? */ + return NO_INT; /* no pending interupt */ + } +sim_printf ("%%int actv consistency error, list end not found\r\n"); +return NO_INT; +} + +/* Acknowledge interrupt and get vector */ + +uint32 io_ackn_int (uint32 hireq) +{ +uint32 grp, bit, mask; + +if (hireq >= NO_INT) /* none pending? */ + return 0; +grp = INT_GETGRP (hireq); /* get grp, bit */ +bit = INT_GETBIT (hireq); +if (bit >= int_tab[grp].nbits) { /* validate bit */ + sim_printf ("%%int ack consistency error, hireq=%X\r\n", hireq); + return 0; + } +mask = 1u << (int_tab[grp].nbits - bit - 1); +int_arm[grp] &= ~mask; /* clear armed */ +int_hiact = hireq; /* now active */ +int_hireq = io_eval_int (); /* paranoia */ +if (int_hireq != NO_INT) + sim_printf ("%%int ack consistency error, post iack req=%X\r\n", int_hireq); +return int_tab[grp].vecbase + bit; +} + +/* Release interrupt and set new armed/disarmed state */ + +extern uint32 io_rels_int (uint32 hiact, t_bool arm) +{ +uint32 grp, bit, mask; + +if (hiact < NO_INT) { /* intr active? */ + grp = INT_GETGRP (hiact); /* get grp, bit */ + bit = INT_GETBIT (hiact); + if (bit >= int_tab[grp].nbits) { /* validate bit */ + sim_printf ("%%int release consistency error, hiact=%X\r\n", hiact); + return 0; + } + mask = 1u << (int_tab[grp].nbits - bit - 1); + int_req[grp] &= ~mask; /* clear req */ + if (arm) /* rearm? */ + int_arm[grp] |= mask; + else int_arm[grp] &= ~mask; + } +int_hiact = io_actv_int (); /* new highest actv */ +return io_eval_int (); /* new request */ +} + +/* Set panel interrupt */ + +t_stat io_set_pint (void) +{ +int_req[INTG_IO] |= INTGIO_PANEL; +return SCPE_OK; +} + +/* Set or clear interrupt status flags */ + +void io_sclr_req (uint32 inum, uint32 val) +{ +uint32 grp, bit, mask; + +if (inum < NO_INT) { /* valid? */ + grp = INT_GETGRP (inum); /* get grp, bit */ + bit = INT_GETBIT (inum); + if (bit >= int_tab[grp].nbits) { /* validate bit */ + sim_printf ("%%intreq set/clear consistency error, inum=%X\r\n", inum); + return; + } + mask = 1u << (int_tab[grp].nbits - bit - 1); + if (val) { /* set req? */ + if (int_arm[grp] & mask) /* must be armed */ + int_req[grp] |= mask; + } + else int_req[grp] &= ~mask; /* clr req */ + } +return; +} + +void io_sclr_arm (uint32 inum, uint32 val) +{ +uint32 grp, bit, mask; + +if (inum < NO_INT) { /* valid? */ + grp = INT_GETGRP (inum); /* get grp, bit */ + bit = INT_GETBIT (inum); + if (bit >= int_tab[grp].nbits) { /* validate bit */ + sim_printf ("%%intarm set/clear consistency error, inum=%X\r\n", inum); + return; + } + mask = 1u << (int_tab[grp].nbits - bit - 1); + if (val) /* set or clr arm */ + int_arm[grp] |= mask; + else int_arm[grp] &= ~mask; + } +return; +} + +/* Read/write direct mode 0 - processor miscellaneous */ + +uint32 io_rwd_m0 (uint32 op, uint32 rn, uint32 ad) +{ +uint32 wd; +uint32 fnc = DIO_GET0FNC (ad); +uint32 dat = rn? R[rn]: 0; + +if (op == OP_RD) { /* read direct? */ + if (fnc == 0x000) { /* copy SSW to SC */ + CC = SSW; + } + else if (fnc == 0x010) { /* read mem fault */ + if (rn) + R[rn] = 0; + CC = SSW; + } + else if (QCPU_S89_5X0 && (fnc == 0x040)) { /* S89, 5X0 only */ + if (rn) /* read inhibits */ + R[rn] = PSW2_GETINH (PSW2); + } + else if (QCPU_S89 && (fnc == 0x045)) { /* S89 only */ + if (rn) + R[rn] = s9_marg & 0x00C00000 | /* <8,9> = margins */ + (QCPU_S9? 0x00100000: 0x00200000); /* S8 sets 10, S9 11 */ + } + else if (QCPU_S89 && (fnc == 0x049)) { /* S89 only */ + if (rn) /* read snapshot */ + R[rn] = s9_snap; + } + else if (QCPU_5X0 && ((fnc & 0xFC0) == 0x100)) { /* 5X0 only */ + ReadPW (fnc & 0x1F, &wd); /* read low mem */ + if (rn) + R[rn] = wd; + } + else if (QCPU_5X0 && ((fnc & 0xFC0) == 0x300)) { /* 5X0 only */ + if (rn) /* read int reg */ + R[rn] = s5x0_ireg[fnc & 0x1F]; + } + else return (stop_op)? STOP_ILLEG: 0; + } +else { /* write direct */ + if (QCPU_5X0 && (fnc == 0x000)) /* 5X0 only */ + SSW = dat & 0xF; /* write SSW */ + else if (QCPU_5X0 && (fnc == 0x002)) /* 5X0 only */ + return TR_47; /* trap to 47 */ + else if ((fnc & 0xFF0) == 0x020) /* bit clear inh */ + PSW2 &= ~((ad & PSW2_M_INH) << PSW2_V_INH); + else if ((fnc & 0xFF0) == 0x030) /* bit set inh */ + PSW2 |= ((ad & PSW2_M_INH) << PSW2_V_INH); + else if (fnc == 0x040) /* alarm off */ + cons_alarm = 0; + else if (fnc == 0x041) /* alarm on */ + cons_alarm = 1; + else if (fnc == 0x042) { /* toggle freq */ + cons_alarm = 0; + cons_pcf ^= 1; + } + else if (fnc == 0x044) ; /* S5 reset IIOP */ + else if (QCPU_S89 && (fnc == 0x045)) /* S89 only */ + s9_marg = dat; /* write margins */ + else if (QCPU_S89_5X0 && (fnc == 0x046)) /* S89, 5X0 only */ + PSW2 &= ~(PSW2_MA9|PSW2_MA5X0); /* clr mode altered */ + else if (QCPU_S9 && (fnc == 0x047)) /* S9 set mode alt */ + PSW2 |= PSW2_MA9; + else if (QCPU_5X0 && (fnc == 0x047)) /* 5X0 set mode alt */ + PSW2 |= PSW2_MA5X0; + else if (QCPU_S89 && (fnc == 0x049)) /* S9 only */ + s9_snap = dat; /* write snapshot */ + else if (QCPU_5X0 && ((fnc & 0xFC0) == 0x100)) /* 5X0 only */ + WritePW (fnc & 0x1F, dat); /* write low mem */ + else if (QCPU_5X0 && ((fnc & 0xFC0) == 0x300)) /* 5X0 only */ + s5x0_ireg[fnc & 0x1F] = dat; /* write int reg */ + else return (stop_op)? STOP_ILLEG: 0; + } +return 0; +} + +/* Read/write direct mode 1 - interrupt flags + This is the only routine that has to map between architecturally + defined interrupts groups and the internal representation. */ + +uint32 io_rwd_m1 (uint32 op, uint32 rn, uint32 ad) +{ +uint32 i, beg, end, mask, sc; +uint32 grp = DIO_GET1GRP (ad); +uint32 fnc = DIO_GET1FNC (ad); + +if (grp == 0) { /* overrides? */ + beg = INTG_OVR; + end = INTG_IO; + } +else if (grp == 1) /* group 1? */ + return 0; /* not there */ +else beg = end = grp + 1; + +if (op == OP_RD) { /* read direct? */ + if (!QCPU_S89_5X0) /* S89, 5X0 only */ + return (stop_op? STOP_ILLEG: 0); + if (rn == 0) /* want result? */ + return 0; + R[rn] = 0; /* clear reg */ + } +for (i = beg; i <= end; i++) { /* loop thru grps */ + mask = (1u << int_tab[i].nbits) - 1; + sc = 32 - int_tab[i].regbit - int_tab[i].nbits; + if (op == OP_RD) { /* read direct? */ + if (fnc & 0x1) + R[rn] |= ((mask & int_arm[i]) << sc); + if (fnc & 0x2) + R[rn] |= ((mask & int_req[i]) << sc); + if (fnc & 0x4) + R[rn] |= ((mask & int_enb[i]) << sc); + } + else { /* write direct */ + mask = (R[rn] >> sc) & mask; + switch (fnc) { + + case 0x0: /* armed||wait->act */ + if (QCPU_S89_5X0) { + int_req[i] |= (mask & int_arm[i]); + int_arm[i] &= mask; + } + else return (stop_op? STOP_ILLEG: 0); + break; + + case 0x1: /* disarm, clr req */ + int_arm[i] &= ~mask; + int_req[i] &= ~mask; + break; + + case 0x2: /* arm, enb, clr req */ + int_arm[i] |= mask; + int_enb[i] |= mask; + int_req[i] &= ~mask; + break; + + case 0x3: /* arm, dsb, clr req */ + int_arm[i] |= mask; + int_enb[i] &= ~mask; + int_req[i] &= ~mask; + break; + + case 0x4: /* enable */ + int_enb[i] |= mask; + break; + + case 0x5: /* disable */ + int_enb[i] &= ~mask; + break; + + case 0x6: /* direct set enb */ + int_enb[i] = mask; + break; + + case 0x7: /* armed->waiting */ + int_req[i] |= (mask & int_arm[i]); + } + } + } +return 0; +} + +/* Reset routines */ + +t_stat int_reset (DEVICE *dptr) +{ +uint32 i; + +if (int_lnk[0] == 0) /* int chain not set up? */ + io_set_eimax (ei_bmax); +for (i = 0; i < INTG_MAX; i++) { + int_arm[i] = 0; + int_enb[i] = 0; + int_req[i] = 0; + } +int_hiact = NO_INT; +int_hireq = NO_INT; +return SCPE_OK; +} + +t_stat chan_reset (DEVICE *dptr) +{ +uint32 ch = dptr - &chan_dev[0]; +uint32 i, j; +DEVICE *devp; + +if (ch >= CHAN_N_CHAN) + return SCPE_IERR; +for (i = 0; i < CHAN_N_DEV; i++) { + chan[ch].clc[i] = 0; + chan[ch].cmd[i] = 0; + chan[ch].cmf[i] = 0; + chan[ch].ba[i] = 0; + chan[ch].bc[i] = 0; + chan[ch].chf[i] = 0; + chan[ch].chi[i] = 0; + chan[ch].chsf[i] &= ~CHSF_ACT; + for (j = 0; (devp = sim_devices[j]) != NULL; j++) { /* loop thru dev */ + if (devp->ctxt != NULL) { + dib_t *dibp = (dib_t *) devp->ctxt; + if ((DVA_GETCHAN (dibp->dva) == ch) && (devp->reset)) + devp->reset (devp); + } + } + } +return SCPE_OK; +} + +/* Universal boot routine */ + +static uint32 boot_rom[] = { + 0x00000000, 0x00000000, 0x020000A8, 0x0E000058, + 0x00000011, 0x00000000, 0x32000024, 0xCC000025, + 0xCD000025, 0x69C00028, 0x00000000, 0x00000000 + }; + +t_stat io_boot (int32 u, DEVICE *dptr) +{ +uint32 i; +dib_t *dibp = (dib_t *) dptr->ctxt; + +for (i = 0; i < MEMSIZE; i++) /* boot clrs mem */ + WritePW (i, 0); +if ((dibp == NULL) || + ((u != 0) && + ((dibp->dva & DVA_MU) == 0))) + return SCPE_ARG; +for (i = 0; i < BOOT_LNT; i++) + WritePW (BOOT_SA + i, boot_rom[i]); +WritePW (BOOT_DEV, dibp->dva | u); +cpu_new_PSD (1, BOOT_PC, 0); +return SCPE_OK; +} + +/* I/O table initialization routine */ + +t_stat io_init (void) +{ +uint32 i, j, ch, dev, dio; +DEVICE *dptr; +dib_t *dibp; + +for (i = 0; i < CHAN_N_CHAN; i++) { + for (j = 0; j < CHAN_N_DEV; j++) { + chan[i].chsf[j] &= ~CHSF_MU; + chan[i].disp[j] = NULL; + } + } +dio_disp[0] = &io_rwd_m0; +for (i = 1; i < DIO_N_MOD; i++) + dio_disp[i] = NULL; + +for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { + if ((dibp = (dib_t *) dptr->ctxt) != NULL) { + ch = DVA_GETCHAN (dibp->dva); + dev = DVA_GETDEV (dibp->dva); + dio = dibp->dio; + if ((ch >= chan_num) || + (dev >= CHAN_N_DEV) || + (dio >= DIO_N_MOD)) { + sim_printf ("%s: invalid device address, chan = %d, dev = %X, dio = %X\n", + sim_dname (dptr), ch, DVA_GETDEV (dibp->dva), dio); + return SCPE_STOP; + } + if ((dibp->disp != NULL) && (chan[ch].disp[dev] != NULL)) { + sim_printf ("%s: device address conflict, chan = %d, dev = %X\n", + sim_dname (dptr), ch, DVA_GETDEV (dibp->dva)); + return SCPE_STOP; + } + if ((dibp->dio_disp != NULL) && (dio_disp[dio] != NULL)) { + sim_printf ("%s: direct I/O address conflict, dio = %X\n", + sim_dname (dptr), dio); + return SCPE_STOP; + } + if (dibp->disp) + chan[ch].disp[dev] = dibp->disp; + if (dibp->dio_disp) + dio_disp[dio] = dibp->dio_disp; + if (dibp->dva & DVA_MU) + chan[ch].chsf[dev] |= CHSF_MU; + } + } +return SCPE_OK; +} + +/* Set/show external interrupt blocks */ + +t_stat io_set_eiblks (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +int32 lnt; +t_stat r; + +if (cptr == NULL) + return SCPE_ARG; +lnt = (int32) get_uint (cptr, 10, cpu_tab[cpu_model].eigrp_max, &r); +if ((r != SCPE_OK) || (lnt == 0)) + return SCPE_ARG; +int_reset (&int_dev); +io_set_eimax (lnt); +return SCPE_OK; +} + +t_stat io_show_eiblks (FILE *st, UNIT *uptr, int32 val, void *desc) +{ +fprintf (st, "eiblks=%d", ei_bmax); +return SCPE_OK; +} + +/* Change the number of external I/O blocks, and restore the default + chain configuration */ + +void io_set_eimax (uint32 max) +{ +uint32 i, curr, ngrp; +uint8 *dflt_p; + +ei_bmax = max; +if (QCPU_5X0) + dflt_p = igrp_dflt_5x0; +else dflt_p = igrp_dflt_S56789; +curr = dflt_p[0] & ~I_STD; +for (i = 1, ngrp = 0; dflt_p[i] != 0; i++) { + if (dflt_p[i] & I_STD) { + int_lnk[curr] = dflt_p[i] & ~I_STD; + curr = int_lnk[curr]; + } + else if (ngrp < ei_bmax) { + int_lnk[curr] = dflt_p[i]; + curr = int_lnk[curr]; + ngrp++; + } + else int_lnk[curr] = 0; + } +return; +} + +/* Set or show number of channels */ + +t_stat io_set_nchan (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +int32 i, num; +t_stat r; + +if (cptr == NULL) + return SCPE_ARG; +num = (int32) get_uint (cptr, 10, cpu_tab[cpu_model].chan_max, &r); +if ((r != SCPE_OK) || (num == 0)) + return SCPE_ARG; +chan_num = num; +for (i = 0; i < CHAN_N_CHAN; i++) { + if (i < num) + chan_dev[i].flags &= ~DEV_DIS; + else chan_dev[i].flags |= DEV_DIS; + chan_reset (&chan_dev[i]); + } +return SCPE_OK; +} + +t_stat io_show_nchan (FILE *st, UNIT *uptr, int32 val, void *desc) +{ +fprintf (st, "channels=%d", chan_num); +return SCPE_OK; +} + +/* Set or show device channel assignment */ + +t_stat io_set_dvc (UNIT* uptr, int32 val, char *cptr, void *desc) +{ +int32 num; +DEVICE *dptr; +dib_t *dibp; + +if (((dptr = find_dev_from_unit (uptr)) == NULL) || + ((dibp = (dib_t *) dptr->ctxt) == NULL)) + return SCPE_IERR; +if ((cptr == NULL) || (*cptr == 0) || (*(cptr + 1) != 0)) + return SCPE_ARG; +num = *cptr - 'A'; +if ((num < 0) || (num >= (int32) chan_num)) + return SCPE_ARG; +dibp->dva = (dibp->dva & ~DVA_CHAN) | (num << DVA_V_CHAN); +return SCPE_OK; +} + +t_stat io_show_dvc (FILE *st, UNIT *uptr, int32 val, void *desc) +{ +DEVICE *dptr; +dib_t *dibp; + +if (((dptr = find_dev_from_unit (uptr)) == NULL) || + ((dibp = (dib_t *) dptr->ctxt) == NULL)) + return SCPE_IERR; +fprintf (st, "channel=%c", DVA_GETCHAN (dibp->dva) + 'A'); +return SCPE_OK; +} + +/* Set or show device address */ + +t_stat io_set_dva (UNIT* uptr, int32 val, char *cptr, void *desc) +{ +int32 num; +DEVICE *dptr; +dib_t *dibp; +t_stat r; + +if (((dptr = find_dev_from_unit (uptr)) == NULL) || + ((dibp = (dib_t *) dptr->ctxt) == NULL)) + return SCPE_IERR; +if (cptr == NULL) + return SCPE_ARG; +num = (int32) get_uint (cptr, 16, CHAN_N_DEV, &r); +if (r != SCPE_OK) + return SCPE_ARG; +if (dibp->dva & DVA_MU) + dibp->dva = (dibp->dva & ~DVA_DEVMU) | ((num & DVA_M_DEVMU) << DVA_V_DEVMU); +else dibp->dva = (dibp->dva & ~DVA_DEVSU) | ((num & DVA_M_DEVSU) << DVA_V_DEVSU); +return SCPE_OK; +} + +t_stat io_show_dva (FILE *st, UNIT *uptr, int32 val, void *desc) +{ +DEVICE *dptr; +dib_t *dibp; + +if (((dptr = find_dev_from_unit (uptr)) == NULL) || + ((dibp = (dib_t *) dptr->ctxt) == NULL)) + return SCPE_IERR; +fprintf (st, "address=%02X", DVA_GETDEV (dibp->dva)); +return SCPE_OK; +} + +/* Show channel state */ + +t_stat io_show_cst (FILE *st, UNIT *uptr, int32 val, void *desc) +{ +DEVICE *dptr; +dib_t *dibp; +uint32 ch, dva; + +if (((dptr = find_dev_from_unit (uptr)) == NULL) || + ((dibp = (dib_t *) dptr->ctxt) == NULL)) + return SCPE_IERR; +ch = DVA_GETCHAN (dibp->dva); +dva = DVA_GETDEV (dibp->dva); +fprintf (st, "Status for device %s, channel=%02X, address=%02X:\n", + sim_dname(dptr), ch, dva); +fprintf (st, "CLC:\t%06X\nBA:\t%06X\nBC:\t%04X\nCMD:\t%02X\n", + chan[ch].clc[dva], chan[ch].ba[dva], + chan[ch].bc[dva], chan[ch].cmd[dva]); +fprintf (st, "CMF:\t%02X\nCHF\t%04X\nCHI:\t%02X\nCHSF:\t%02X\n", + chan[ch].cmf[dva], chan[ch].chf[dva], + chan[ch].chi[dva], chan[ch].chsf[dva]); +return SCPE_OK; +} diff --git a/sigma/sigma_io_defs.h b/sigma/sigma_io_defs.h new file mode 100644 index 00000000..0a24b810 --- /dev/null +++ b/sigma/sigma_io_defs.h @@ -0,0 +1,276 @@ +/* sigma_io_defs.h: XDS Sigma I/O device simulator definitions + + Copyright (c) 2007-2008, Robert M Supnik + + 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 + ROBERT M SUPNIK 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 Robert M Supnik shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. +*/ + +#ifndef SIGMA_IO_DEFS_H_ +#define SIGMA_IO_DEFS_H_ 0 + +#include "sim_defs.h" /* simulator defns */ +#include "sigma_defs.h" + +/* Channel constants */ + +#define CHAN_N_CHAN 8 /* max # channels */ +#define CHAN_DFLT 4 /* default # chan */ +#define CHAN_N_DEV 32 /* max dev per chan */ +#define CHAN_V_IOPT (DEV_V_UF + 0) /* channel type */ +#define CHAN_MIOP (0 << CHAN_V_IOPT) +#define CHAN_SIOP (1 << CHAN_V_IOPT) + +/* I/O device definition block */ + +typedef struct { + uint32 dva; /* dev addr (chan+dev) */ + uint32 (*disp)(uint32 op, uint32 dva, uint32 *dvst); + uint32 dio; /* dev addr (direct IO) */ + uint32 (*dio_disp)(uint32 op, uint32 rn, uint32 dva); + } dib_t; + +/* Channel data structure */ + +typedef struct { + uint32 clc[CHAN_N_DEV]; /* location counter */ + uint32 ba[CHAN_N_DEV]; /* mem addr */ + uint16 bc[CHAN_N_DEV]; /* byte count */ + uint8 cmd[CHAN_N_DEV]; /* command */ + uint8 cmf[CHAN_N_DEV]; /* command flags */ + uint16 chf[CHAN_N_DEV]; /* channel flags */ + uint8 chi[CHAN_N_DEV]; /* interrupts */ + uint8 chsf[CHAN_N_DEV]; /* simulator flags */ + uint32 (*disp[CHAN_N_DEV])(uint32 op, uint32 dva, uint32 *dvst); + } chan_t; + +/* Channel command words */ + +#define CCW1_V_CMD 24 /* command */ +#define CCW1_M_CMD 0xFF +#define CCW1_V_BA 0 +#define CCW1_M_BA ((cpu_tab[cpu_model].pamask << 2) | 0x3) +#define CHBA_MASK (CCW1_M_BA << CCW1_V_BA) +#define CCW2_V_CMF 24 /* cmd flags */ +#define CCW2_M_CMF 0xFF +#define CCW2_V_BC 0 +#define CCW2_M_BC 0xFFFF +#define CHBC_MASK (CCW2_M_BC << CCW2_V_BC) +#define CCW1_GETCMD(x) (((x) >> CCW1_V_CMD) & CCW1_M_CMD) +#define CCW1_GETBA(x) (((x) >> CCW1_V_BA) & CCW1_M_BA) +#define CCW2_GETCMF(x) (((x) >> CCW2_V_CMF) & CCW2_M_CMF) +#define CCW2_GETBC(x) (((x) >> CCW2_V_BC) & CCW2_M_BC) + +/* Channel commands */ + +#define CMD_TIC 0x8 /* transfer */ + +/* Channel command flags */ + +#define CMF_DCH 0x80 /* data chain */ +#define CMF_IZC 0x40 /* int on zero cnt */ +#define CMF_CCH 0x20 /* command chain */ +#define CMF_ICE 0x10 /* int on chan end */ +#define CMF_HTE 0x08 /* hlt on xmit err */ +#define CMF_IUE 0x04 /* int on uend */ +#define CMF_SIL 0x02 /* suppress lnt err */ +#define CMF_SKP 0x01 /* skip */ + +/* Channel flags */ + +#define CHF_INP 0x8000 /* int pending */ +#define CHF_UEN 0x0400 /* unusual end */ +#define CHF_LNTE 0x0080 /* length error */ +#define CHF_XMDE 0x0040 /* xmit data error */ +#define CHF_XMME 0x0020 /* xmit mem error */ +#define CHF_XMAE 0x0010 /* xmit addr error */ +#define CHF_IOME 0x0008 /* IOP mem error */ +#define CHF_IOCE 0x0004 /* IOP ctrl error */ +#define CHF_IOHE 0x0002 /* IOP halted */ +#define CHF_ALL (CHF_INP|CHF_UEN|0xFF) + +/* Channel interrupts */ + +#define CHI_F_SHF 1 /* flag shift */ +#define CHI_CTL (0x40 << CHI_F_SHF) /* ctl int (fake) */ +#define CHI_ZBC (0x20 << CHI_F_SHF) /* zero by cnt int */ +#define CHI_END (0x10 << CHI_F_SHF) /* channel end int */ +#define CHI_UEN (0x08 << CHI_F_SHF) /* unusual end int */ +#define CHI_FLAGS (CHI_ZBC|CHI_END|CHI_UEN) +#define CHI_V_UN 0 +#define CHI_M_UN 0xF +#define CHI_GETUN(x) (((x) >> CHI_V_UN) & CHI_M_UN) +#define CHI_GETINT(x) (((x) & CHI_FLAGS) >> CHI_F_SHF) + +/* Internal simulator flags */ + +#define CHSF_ACT 0x0001 /* channel active */ +#define CHSF_MU 0x0002 /* multi-unit dev */ + +/* Dispatch routine status return value */ + +#define DVT_V_UN 24 /* unit addr (AIO only) */ +#define DVT_M_UN 0xF +#define DVT_V_CC 16 /* cond codes */ +#define DVT_M_CC 0xF +#define DVT_V_DVS 0 /* device status */ +#define DVT_M_DVS 0xFF +#define DVS_V_DST 5 /* device status */ +#define DVS_M_DST 0x3 +#define DVS_DST (DVS_M_DST << DVS_V_DST) +#define DVS_DOFFL (0x1 << DVS_V_DST) +#define DVS_DBUSY (0x3 << DVS_V_DST) +#define DVS_AUTO 0x10 /* manual/automatic */ +#define DVS_V_CST 1 /* ctrl status */ +#define DVS_M_CST 0x3 +#define DVS_CBUSY (0x3 << DVS_V_CST) +#define DVS_CST (DVS_M_CST << DVS_V_CST) +#define DVT_GETUN(x) (((x) >> DVT_V_UN) & DVT_M_UN) +#define DVT_GETCC(x) (((x) >> DVT_V_CC) & DVT_M_CC) +#define DVT_GETDVS(x) (((x) >> DVT_V_DVS) & DVT_M_DVS) +#define DVT_NOST (CC1 << DVT_V_CC) /* no status */ +#define DVT_NODEV ((CC1|CC2) < DVT_V_CC) /* no device */ + +/* Read and write direct address format */ + +#define DIO_V_MOD 12 /* mode */ +#define DIO_M_MOD 0xF +#define DIO_V_0FNC 0 /* mode 0 func */ +#define DIO_M_0FNC 0xFFF +#define DIO_V_1FNC 8 /* mode 1 int func */ +#define DIO_M_1FNC 0x7 +#define DIO_V_1GRP 0 /* int group */ +#define DIO_M_1GRP 0xF +#define DIO_GETMOD(x) (((x) >> DIO_V_MOD) & DIO_M_MOD) +#define DIO_GET0FNC(x) (((x) >> DIO_V_0FNC) & DIO_M_0FNC) +#define DIO_GET1FNC(x) (((x) >> DIO_V_1FNC) & DIO_M_1FNC) +#define DIO_GET1GRP(x) (((x) >> DIO_V_1GRP) & DIO_M_1GRP) +#define DIO_N_MOD (DIO_M_MOD + 1) /* # DIO "modes" */ + +/* I/O instruction address format */ + +#define DVA_V_CHAN 8 /* channel */ +#define DVA_M_CHAN (CHAN_N_CHAN - 1) +#define DVA_CHAN (DVA_M_CHAN << DVA_V_CHAN) +#define DVA_V_DEVSU 0 /* dev, 1 unit */ +#define DVA_M_DEVSU 0x7F +#define DVA_DEVSU (DVA_M_DEVSU << DVA_V_DEVSU) +#define DVA_MU 0x80 /* multi-unit flg */ +#define DVA_V_DEVMU 4 /* dev, multi */ +#define DVA_M_DEVMU 0x7 +#define DVA_DEVMU (DVA_M_DEVMU << DVA_V_DEVMU) +#define DVA_V_UNIT 0 /* unit number */ +#define DVA_M_UNIT 0xF +#define DVA_GETCHAN(x) (((x) >> DVA_V_CHAN) & DVA_M_CHAN) +#define DVA_GETDEV(x) (((x) & DVA_MU)? \ + (((x) >> DVA_V_DEVMU) & DVA_M_DEVMU): \ + (((x) >> DVA_V_DEVSU) & DVA_M_DEVSU)) +#define DVA_GETUNIT(x) (((x) & DVA_MU)? \ + (((x) >> DVA_V_UNIT) & DVA_M_UNIT): 0) + +/* Default I/O device addresses */ + +#define DVA_TT 0x001 +#define DVA_LP 0x002 +#define DVA_CR 0x003 +#define DVA_CP 0x004 +#define DVA_PT 0x005 +#define DVA_MUX 0x006 +#define DIO_MUX 0x3 +#define DVA_MT 0x080 +#define DVA_RAD 0x180 +#define DVA_DK 0x190 +#define DVA_DPA 0x280 +#define DVA_DPB 0x380 + +/* Channel routine status codes */ + +#define CHS_ERR 0x4000 /* any error */ +#define CHS_INF 0x8000 /* information */ +#define CHS_IFERR(x) (((x) != 0) && ((x) < CHS_INF)) + +#define CHS_INACTV (CHS_ERR + 0) +#define CHS_NXM (CHS_ERR + 1) +#define CHS_SEQ (CHS_ERR + 2) + +#define CHS_ZBC (CHS_INF + 1) /* zero byte count */ +#define CHS_CCH (CHS_INF + 2) /* command chain */ + +/* Boot ROM */ + +#define BOOT_SA 0x20 +#define BOOT_LNT 12 +#define BOOT_DEV 0x25 +#define BOOT_PC 0x26 + +/* Internal real-time scheduler */ + +#define RTC_C1 0 +#define RTC_C2 1 +#define RTC_C3 2 +#define RTC_C4 3 +#define RTC_NUM_CNTRS 4 +#define RTC_TTI (RTC_NUM_CNTRS + 0) +#define RTC_COC (RTC_NUM_CNTRS + 1) +#define RTC_ALARM (RTC_NUM_CNTRS + 2) +#define RTC_NUM_EVNTS (RTC_NUM_CNTRS + 3) + +#define RTC_HZ_OFF 0 +#define RTC_HZ_500 1 +#define RTC_HZ_50 2 +#define RTC_HZ_60 3 +#define RTC_HZ_100 4 +#define RTC_HZ_2 5 +#define RTC_NUM_HZ 6 + +/* Function prototypes */ + +uint32 chan_get_cmd (uint32 dva, uint32 *cmd); +uint32 chan_set_chf (uint32 dva, uint32 fl); +t_bool chan_tst_cmf (uint32 dva, uint32 fl); +void chan_set_chi (uint32 dva, uint32 fl); +void chan_set_dvi (uint32 dva); +int32 chan_clr_chi (uint32 dva); +int32 chan_chk_chi (uint32 dva); +uint32 chan_end (uint32 dva); +uint32 chan_uen (uint32 dva); +uint32 chan_RdMemB (uint32 dva, uint32 *dat); +uint32 chan_WrMemB (uint32 dva, uint32 dat); +uint32 chan_WrMemBR (uint32 dva, uint32 dat); +uint32 chan_RdMemW (uint32 dva, uint32 *dat); +uint32 chan_WrMemW (uint32 dva, uint32 dat); +t_stat chan_reset_dev (uint32 dva); +void io_sclr_req (uint32 inum, uint32 val); +void io_sclr_arm (uint32 inum, uint32 val); +t_stat io_set_dvc (UNIT* uptr, int32 val, char *cptr, void *desc); +t_stat io_show_dvc (FILE *st, UNIT *uptr, int32 val, void *desc); +t_stat io_set_dva (UNIT* uptr, int32 val, char *cptr, void *desc); +t_stat io_show_dva (FILE *st, UNIT *uptr, int32 val, void *desc); +t_stat io_show_cst (FILE *st, UNIT *uptr, int32 val, void *desc); +t_stat io_boot (int32 u, DEVICE *dptr); + +/* Internal real-time event scheduler */ + +t_stat rtc_set_tps (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat rtc_show_tps (FILE *of, UNIT *uptr, int32 val, void *desc); +t_stat rtc_register (uint32 tm, uint32 idx, UNIT *uptr); + +#endif \ No newline at end of file diff --git a/sigma/sigma_lp.c b/sigma/sigma_lp.c new file mode 100644 index 00000000..48794286 --- /dev/null +++ b/sigma/sigma_lp.c @@ -0,0 +1,530 @@ +/* sigma_lp.c: Sigma 7440/7450 line printer + + Copyright (c) 2007-2008, Robert M. Supnik + + 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 + ROBERT M SUPNIK 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 Robert M Supnik shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + + lp 7440/7445 or 7450 line printer +*/ + +#include "sigma_io_defs.h" + +/* Device definitions */ + +#define CCT_LNT 256 /* carriage ctl max */ +#define BUF_LNT4 132 /* line lengths */ +#define BUF_LNT5 128 + +#define LP_7440 0 /* models */ +#define LP_7450 1 + +/* Device states */ + +#define LPS_INIT 0x101 +#define LPS_END 0x102 +#define LPS_PRI 0x1 +#define LPS_FMT 0x3 +#define LPS_FMTP 0x5 +#define LPS_INT 0x40 + +/* Device status */ + +#define LPDV_ODD 0x40 /* odd */ +#define LPDV_TOF 0x10 /* top of form */ +#define LPDV_MOV 0x08 /* paper moving */ +#define LPDV_V_RUN 2 /* runaway CCT */ +#define LPDV_RUN (1u << LPDV_V_RUN) +#define LPDV_WT2 0x02 /* waiting for 2nd */ + +/* Format characters */ + +#define FMT_INH 0x60 +#define FMT_SPC 0xC0 +#define FMT_SKP 0xF0 + +#define FMT_MSPC4 15 /* max space cmd */ +#define FMT_MSPC5 7 +#define SPC_MASK ((lp_model == LP_7440)? FMT_MSPC4: FMT_MSPC5) +#define FMT_MCH4 7 /* max CCT channel */ +#define FMT_MCH5 1 +#define CCH_MASK ((lp_model == LP_7440)? FMT_MCH5: FMT_MCH4) + +#define CH_BOF 0 /* CCT bot of form */ +#define CH_TOF 1 /* CCT top of form */ + +#define CHP(ch,val) ((val) & (1 << (ch))) + +uint32 lp_cmd = 0; +uint32 lp_stopioe = 1; +uint32 lp_cctp = 0; /* CCT position */ +uint32 lp_cctl = 1; /* CCT length */ +uint32 lp_lastcmd = 0; /* last command */ +uint32 lp_pass = 0; /* 7450 print pass */ +uint32 lp_inh = 0; /* space inhibit */ +uint32 lp_run = 0; /* CCT runaway */ +uint32 lp_model = LP_7440; +uint8 lp_buf[BUF_LNT4]; /* print buffer */ +uint8 lp_cct[CCT_LNT] = { 0xFF }; /* carriage ctl tape */ +uint8 lp_to_ascii[64] = { + ' ', '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', '^', ',', '%', '_', '>', '?', + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', ':', '#', '@', '\'', '=', '"' + }; + +extern uint32 chan_ctl_time; + +uint32 lp_disp (uint32 op, uint32 dva, uint32 *dvst); +uint32 lp_tio_status (void); +uint32 lp_tdv_status (void); +t_stat lp_chan_err (uint32 st); +t_stat lp_svc (UNIT *uptr); +t_stat lp_reset (DEVICE *dptr); +t_stat lp_attach (UNIT *uptr, char *cptr); +t_stat lp_settype (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat lp_showtype (FILE *st, UNIT *uptr, int32 val, void *desc); +t_stat lp_load_cct (UNIT *uptr, int32 val, char *cptr, void *desc); +uint32 lp_fmt (UNIT *uptr); +uint32 lp_skip (UNIT *uptr, uint32 ch); +uint32 lp_space (UNIT *uptr, uint32 lines, t_bool skp); +uint32 lp_print (UNIT *uptr); + +/* LP data structures + + lp_dev LP device descriptor + lp_unit LP unit descriptors + lp_reg LP register list + lp_mod LP modifiers list +*/ + +dib_t lp_dib = { DVA_LP, lp_disp, 0, NULL }; + +UNIT lp_unit = { UDATA (&lp_svc, UNIT_ATTABLE+UNIT_SEQ, 0), SERIAL_OUT_WAIT }; + +REG lp_reg[] = { + { HRDATA (CMD, lp_cmd, 9) }, + { BRDATA (BUF, lp_buf, 16, 7, BUF_LNT4) }, + { FLDATA (PASS, lp_pass, 0) }, + { FLDATA (INH, lp_inh, 0) }, + { FLDATA (RUNAWAY, lp_run, LPDV_V_RUN) }, + { BRDATA (CCT, lp_cct, 8, 8, CCT_LNT) }, + { DRDATA (CCTP, lp_cctp, 8), PV_LEFT }, + { DRDATA (CCTL, lp_cctl, 8), PV_LEFT + REG_HRO + REG_NZ }, + { DRDATA (POS, lp_unit.pos, T_ADDR_W), PV_LEFT }, + { DRDATA (TIME, lp_unit.wait, 24), PV_LEFT }, + { FLDATA (STOP_IOE, lp_stopioe, 0) }, + { HRDATA (LASTC, lp_lastcmd, 8), REG_HIDDEN }, + { FLDATA (MODEL, lp_model, 0), REG_HRO }, + { HRDATA (DEVNO, lp_dib.dva, 12), REG_HRO }, + { NULL } + }; + +MTAB lp_mod[] = { + { MTAB_XTD | MTAB_VDV, LP_7440, NULL, "7440", + &lp_settype, NULL, NULL }, + { MTAB_XTD | MTAB_VDV, LP_7450, NULL, "7450", + &lp_settype, NULL, NULL }, + { MTAB_XTD | MTAB_VDV, 0, "TYPE", NULL, + NULL, &lp_showtype, NULL }, + { MTAB_XTD | MTAB_VDV | MTAB_NC, 0, NULL, "CCT", + &lp_load_cct, NULL, NULL }, + { MTAB_XTD|MTAB_VDV, 0, "CHAN", "CHAN", + &io_set_dvc, &io_show_dvc, NULL }, + { MTAB_XTD|MTAB_VDV, 0, "DVA", "DVA", + &io_set_dva, &io_show_dva, NULL }, + { MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "CSTATE", NULL, + NULL, &io_show_cst, NULL }, + { 0 } + }; + +DEVICE lp_dev = { + "LP", &lp_unit, lp_reg, lp_mod, + 1, 10, 31, 1, 16, 8, + NULL, NULL, &lp_reset, + NULL, &lp_attach, NULL, + &lp_dib, 0 + }; + +/* Line printer: IO dispatch routine */ + +uint32 lp_disp (uint32 op, uint32 dva, uint32 *dvst) +{ +switch (op) { /* case on op */ + + case OP_SIO: /* start I/O */ + *dvst = lp_tio_status (); /* get status */ + if ((*dvst & DVS_DST) == 0) { /* idle? */ + lp_cmd = LPS_INIT; /* start dev thread */ + sim_activate (&lp_unit, chan_ctl_time); + } + break; + + case OP_TIO: /* test status */ + *dvst = lp_tio_status (); /* return status */ + break; + + case OP_TDV: /* test status */ + *dvst = lp_tdv_status (); /* return status */ + break; + + case OP_HIO: /* halt I/O */ + chan_clr_chi (lp_dib.dva); /* clear int */ + *dvst = lp_tio_status (); /* get status */ + if ((*dvst & DVS_DST) != 0) { /* busy? */ + sim_cancel (&lp_unit); /* stop dev thread */ + chan_uen (lp_dib.dva); /* uend */ + } + break; + + case OP_AIO: /* acknowledge int */ + chan_clr_chi (lp_dib.dva); /* clear int */ + *dvst = lp_lastcmd & LPS_INT; /* int requested */ + lp_lastcmd = 0; + break; + + default: + *dvst = 0; + return SCPE_IERR; + } + +return 0; +} + +/* Service routine */ + +t_stat lp_svc (UNIT *uptr) +{ +uint32 cmd; +uint32 st; + +switch (lp_cmd) { /* case on state */ + + case LPS_INIT: /* I/O init */ + st = chan_get_cmd (lp_dib.dva, &cmd); /* get command */ + if (CHS_IFERR (st)) /* channel error? */ + return lp_chan_err (st); + lp_inh = 0; /* clear inhibit, */ + lp_run = 0; /* runaway */ + lp_cmd = lp_lastcmd = cmd; /* save command */ + sim_activate (uptr, chan_ctl_time); /* continue thread */ + break; + + case LPS_FMT: + case LPS_FMT|LPS_INT: /* format only */ + sim_activate (uptr, uptr->wait); /* continue thread */ + if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */ + return lp_stopioe? SCPE_UNATT: SCPE_OK; + st = lp_fmt (uptr); /* format */ + if (CHS_IFERR (st)) /* error? */ + return lp_chan_err (st); + if ((lp_model == LP_7440) && /* 7440? lnt chk */ + (st != CHS_ZBC) && + chan_set_chf (lp_dib.dva, CHF_LNTE)) /* not ignored? */ + return lp_chan_err (SCPE_OK); /* force uend */ + lp_cmd = LPS_END; /* actual print */ + break; + + case LPS_FMTP: + case LPS_FMTP|LPS_INT: /* format and print */ + sim_activate (uptr, uptr->wait); /* continue thread */ + if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */ + return lp_stopioe? SCPE_UNATT: SCPE_OK; + st = lp_fmt (uptr); /* format */ + if (CHS_IFERR (st)) /* error? */ + return lp_chan_err (st); + if (st == CHS_ZBC) { /* command done? */ + if ((lp_model == LP_7440) && /* 7440? lnt err */ + chan_set_chf (lp_dib.dva, CHF_LNTE)) /* not ignored? */ + return lp_chan_err (SCPE_OK); + } + else { /* more to do */ + st = lp_print (uptr); /* print */ + if (CHS_IFERR (st)) /* error */ + return lp_chan_err (st); + } + break; + + case LPS_PRI: + case LPS_PRI|LPS_INT: /* print only */ + sim_activate (uptr, uptr->wait); /* continue thread */ + if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */ + return lp_stopioe? SCPE_UNATT: SCPE_OK; + st = lp_print (uptr); /* print */ + if (CHS_IFERR (st)) /* error? */ + return lp_chan_err (st); + break; + + case LPS_END: /* command done */ + if ((lp_lastcmd & LPS_INT) && !lp_pass) /* int requested? */ + chan_set_chi (lp_dib.dva, 0); + st = chan_end (lp_dib.dva); /* set channel end */ + if (CHS_IFERR (st)) /* channel error? */ + return lp_chan_err (st); + if (st == CHS_CCH) { /* command chain? */ + lp_cmd = LPS_INIT; /* restart thread */ + sim_activate (uptr, chan_ctl_time); + } + break; + + default: /* invalid cmd */ + chan_uen (lp_dib.dva); /* uend */ + break; + } + +return SCPE_OK; +} + +/* Format routine */ + +uint32 lp_fmt (UNIT *uptr) +{ +uint32 c, i; +uint32 st; + +st = chan_RdMemB (lp_dib.dva, &c); /* get char */ +if (CHS_IFERR (st)) /* channel error? */ + return st; /* caller handles */ +if (lp_pass) /* only on pass 1 */ + return 0; +if ((c & 0x7F) == FMT_INH) /* inhibit? */ + lp_inh = 1; +else if ((c & ~(((lp_model == LP_7450)? 0x20: 0) | SPC_MASK)) == FMT_SPC) { + c = c & SPC_MASK; /* space? */ + for (i = 1; i <= c; i++) { /* look for BOF */ + if (CHP (CH_BOF, lp_cct[(lp_cctp + i) % lp_cctl])) + return lp_skip (uptr, CH_TOF); /* found, TOF */ + } + return lp_space (uptr, c, FALSE); /* space */ + } +else if ((c & ~CCH_MASK) == FMT_SKP) /* skip? */ + return lp_skip (uptr, c & CCH_MASK); /* skip to chan */ +return 0; +} + +/* Skip to channel */ + +uint32 lp_skip (UNIT *uptr, uint32 ch) +{ +uint32 i; + +for (i = 1; i < (lp_cctl + 1); i++) { /* sweep thru CCT */ + if (CHP (ch, lp_cct[(lp_cctp + i) % lp_cctl])) /* channel punched? */ + return lp_space (uptr, i, TRUE); /* space to chan */ + } +lp_run = LPDV_RUN; /* runaway CCT */ +return lp_space (uptr, lp_cctl, TRUE); /* space max */ +} + +/* Space routine */ + +uint32 lp_space (UNIT *uptr, uint32 cnt, t_bool skp) +{ +uint32 i; + +lp_cctp = (lp_cctp + cnt) % lp_cctl; /* adv cct, mod lnt */ +if (skp && CHP (CH_TOF, lp_cct[lp_cctp])) /* skip, TOF? */ + fputs ("\f", uptr->fileref); /* ff */ + else { /* space */ + for (i = 0; i < cnt; i++) + fputc ('\n', uptr->fileref); + } +uptr->pos = ftell (uptr->fileref); /* update position */ +if (ferror (uptr->fileref)) { /* error? */ + perror ("Line printer I/O error"); + clearerr (uptr->fileref); + chan_set_chf (lp_dib.dva, CHF_XMDE); + return SCPE_IOERR; + } +return 0; +} + +/* Print routine */ + +uint32 lp_print (UNIT *uptr) +{ +uint32 i, bp, c; +uint32 max = (lp_model == LP_7440)? BUF_LNT4: BUF_LNT5; +uint32 st; + +if (lp_pass == 0) { /* pass 1? clr buf */ + for (i = 0; i < BUF_LNT4; i++) lp_buf[i] = ' '; + } +for (bp = 0, st = 0; (bp < max) && !st; bp++) { /* fill buffer */ + st = chan_RdMemB (lp_dib.dva, &c); /* get char */ + if (CHS_IFERR (st)) /* channel error? */ + return st; /* caller handles */ + if ((lp_model == LP_7440) || /* 7440 or */ + ((bp & 1) == lp_pass)) /* correct pass? */ + lp_buf[bp] = lp_to_ascii[c & 0x3F]; + } +if ((lp_model == LP_7440) || lp_pass) { /* ready to print? */ + lp_pass = 0; + for (i = BUF_LNT4; (i > 0) && (lp_buf[i - 1] == ' '); i--) ; /* trim */ + if (i) /* write line */ + sim_fwrite (lp_buf, 1, i, uptr->fileref); + fputc (lp_inh? '\r': '\n', uptr->fileref); /* cr or nl */ + uptr->pos = ftell (uptr->fileref); /* update position */ + if (ferror (uptr->fileref)) { /* error? */ + perror ("Line printer I/O error"); + clearerr (uptr->fileref); + chan_set_chf (lp_dib.dva, CHF_XMDE); + return SCPE_IOERR; + } + if ((lp_model == LP_7440) && /* 7440? */ + ((bp != BUF_LNT4) || (st != CHS_ZBC)) && /* check lnt err */ + chan_set_chf (lp_dib.dva, CHF_LNTE)) + return CHS_INACTV; /* stop if asked */ + } +else lp_pass = 1; /* 7450 pass 2 */ +lp_cmd = LPS_END; /* end state */ +return 0; +} + +/* LP status routine */ + +uint32 lp_tio_status (void) +{ +uint32 st; + +st = (lp_unit.flags & UNIT_ATT)? DVS_AUTO: 0; /* auto? */ +if (sim_is_active (&lp_unit)) /* busy? */ + st |= (DVS_CBUSY | DVS_DBUSY | (CC2 << DVT_V_CC)); +return st; +} + +uint32 lp_tdv_status (void) +{ +uint32 st; + +st = lp_run; /* runaway flag */ +if ((lp_unit.flags & UNIT_ATT) == 0) /* fault? */ + st |= (CC2 << DVT_V_CC); +if (lp_cmd == LPS_END) /* end state? */ + st |= LPDV_MOV; /* printing */ +if (lp_pass && (lp_model == LP_7450)) { /* 7450 pass 2? */ + st |= LPDV_ODD; /* odd state */ + if (lp_cmd == LPS_INIT) /* wait for cmd? */ + st |= LPDV_WT2; + } +return st; +} + +/* Channel error */ + +t_stat lp_chan_err (uint32 st) +{ +sim_cancel (&lp_unit); /* stop dev thread */ +chan_uen (lp_dib.dva); /* uend */ +if (st < CHS_ERR) + return st; +return SCPE_OK; +} + +/* Reset routine */ + +t_stat lp_reset (DEVICE *dptr) +{ +sim_cancel (&lp_unit); /* stop dev thread */ +lp_cmd = 0; +lp_lastcmd = 0; +lp_pass = 0; +lp_inh = 0; +lp_run = 0; +chan_reset_dev (lp_dib.dva); /* clr int, active */ +return SCPE_OK; +} + +/* Attach routine */ + +t_stat lp_attach (UNIT *uptr, char *cptr) +{ +lp_cctp = 0; /* clear cct ptr */ +lp_pass = 0; +return attach_unit (uptr, cptr); +} + +/* Set carriage control tape */ + +t_stat lp_load_cct (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +uint32 col, rpt, ptr, mask; +uint8 cctbuf[CCT_LNT]; +t_stat r; +char cbuf[CBUFSIZE], gbuf[CBUFSIZE]; +FILE *cfile; + +if ((cptr == NULL) || (*cptr == 0)) return SCPE_ARG; +if ((cfile = fopen (cptr, "r")) == NULL) + return SCPE_OPENERR; +ptr = 0; +for ( ; (cptr = fgets (cbuf, CBUFSIZE, cfile)) != NULL; ) { + mask = 0; + if (*cptr == '(') { /* repeat count? */ + cptr = get_glyph (cptr + 1, gbuf, ')'); /* get 1st field */ + rpt = get_uint (gbuf, 10, CCT_LNT, &r); /* repeat count */ + if (r != SCPE_OK) + return SCPE_FMT; + } + else rpt = 1; + while (*cptr != 0) { /* get col no's */ + cptr = get_glyph (cptr, gbuf, ','); /* get next field */ + col = get_uint (gbuf, 10, FMT_MCH4, &r); /* column number */ + if (r != SCPE_OK) + return SCPE_FMT; + mask = mask | (1 << col); /* set bit */ + } + for ( ; rpt > 0; rpt--) { /* store vals */ + if (ptr >= CCT_LNT) + return SCPE_FMT; + cctbuf[ptr++] = mask; + } + } +if (ptr == 0) + return SCPE_FMT; +lp_cctl = ptr; +lp_cctp = 0; +for (rpt = 0; rpt < lp_cctl; rpt++) + lp_cct[rpt] = cctbuf[rpt]; +fclose (cfile); +return SCPE_OK; +} + +/* Set controller type */ + +t_stat lp_settype (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +lp_model = val; +lp_reset (&lp_dev); +return SCPE_OK; +} + +/* Show controller type */ + +t_stat lp_showtype (FILE *st, UNIT *uptr, int32 val, void *desc) +{ +fprintf (st, lp_model? "7450": "7440"); +return SCPE_OK; +} diff --git a/sigma/sigma_map.c b/sigma/sigma_map.c new file mode 100644 index 00000000..8458b240 --- /dev/null +++ b/sigma/sigma_map.c @@ -0,0 +1,591 @@ +/* sigma_map.c: XDS Sigma memory access routines + + Copyright (c) 2007, Robert M Supnik + + 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 + ROBERT M SUPNIK 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 Robert M Supnik shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. +*/ + +#include "sigma_defs.h" + +#define BVA_REG (RF_NUM << 2) +#define BPAMASK ((cpu_tab[cpu_model].pamask << 2) | 0x3) +#define NUM_MUNITS (MAXMEMSIZE / CPU_MUNIT_SIZE) + +/* Sigma 8-9 memory status words */ + +#define S89_SR0_BADLMS 0x00800000 /* bad LMS */ +#define S89_SR0_RD (S89_SR0_BADLMS) +#define S89_SR0_V_PORTS 12 + +#define S89_SR1_FIXED 0x50C40000 /* always 1 */ +#define S89_SR1_M_MEMU 0xF /* mem unit */ +#define S89_SR1_V_MEMU 24 +#define S89_SR1_MARG 0x00F80000 /* margin write */ +#define S89_SR1_MAROFF 2 /* offset to read */ + +/* 5X0 memory status words */ + +#define S5X0_SR0_FIXED 0x40000000 +#define S5X0_SR0_BADLMS 0x00000004 /* bad LMS */ +#define S5X0_SR0_RD (S5X0_SR0_BADLMS) +#define S5X0_SR0_V_PORTS 21 + +#define S5X0_SR1_FIXED 0xB0000000 /* fixed */ +#define S5X0_SR1_M_MEMU 0x7 /* mem unit */ +#define S5X0_SR1_V_MEMU 25 +#define S5X0_SR1_V_SA 18 /* start addr */ + +#define S8 + +typedef struct { + uint32 width; /* item width */ + uint32 dmask; /* data mask */ + uint32 cmask; /* control start mask */ + uint32 lnt; /* array length */ + uint32 opt; /* option control */ + } mmc_ctl_t; + +uint16 mmc_rel[VA_NUM_PAG]; +uint8 mmc_acc[VA_NUM_PAG]; +uint8 mmc_wlk[PA_NUM_PAG]; + +uint32 mem_sr0[NUM_MUNITS]; +uint32 mem_sr1[NUM_MUNITS]; + +mmc_ctl_t mmc_tab[8] = { + { 0, 0, 0, 0 }, + { 2, 0x003, 0, MMC_L_CS1, CPUF_WLK }, /* map 1: 2b locks */ + { 2, 0x003, MMC_M_CS2, MMC_L_CS2, CPUF_MAP }, /* map 2: 2b access ctls */ + { 4, 0x00F, MMC_M_CS3, MMC_L_CS3, CPUF_WLK }, /* map 3: 4b locks */ + { 8, 0x0FF, MMC_M_CS4, MMC_L_CS4, CPUF_MAP }, /* map 4: 8b relocation */ + { 16, 0x7FF, MMC_M_CS5, MMC_L_CS5, CPUF_MAP }, /* map 5: 16b relocation */ + { 0, 0, 0, 0 }, + { 0, 0, 0, 0 } + }; + +extern uint32 *R; +extern uint32 *M; +extern uint32 PSW1, PSW2, PSW4; +extern uint32 CC, PSW2_WLK; +extern uint32 stop_op; +extern uint32 cpu_model; +extern uint32 chan_num; +extern UNIT cpu_unit; +extern cpu_var_t cpu_tab[]; + +uint32 map_reloc (uint32 bva, uint32 acc, uint32 *bpa); +uint32 map_viol (uint32 bva, uint32 bpa, uint32 tr); +t_stat map_reset (DEVICE *dptr); +uint32 map_las (uint32 rn, uint32 bva); + +/* Map data structures + + map_dev map device descriptor + map_unit map units + map_reg map register list +*/ + +UNIT map_unit = { UDATA (NULL, 0, 0) }; + +REG map_reg[] = { + { BRDATA (REL, mmc_rel, 16, 13, VA_NUM_PAG) }, + { BRDATA (ACC, mmc_acc, 16, 2, VA_NUM_PAG) }, + { BRDATA (WLK, mmc_wlk, 16, 4, PA_NUM_PAG) }, + { BRDATA (SR0, mem_sr0, 16, 32, NUM_MUNITS) }, + { BRDATA (SR1, mem_sr1, 16, 32, NUM_MUNITS) }, + { NULL } + }; + +DEVICE map_dev = { + "MAP", &map_unit, map_reg, NULL, + 1, 16, 16, 1, 16, 32, + NULL, NULL, &map_reset, + NULL, NULL, NULL, + NULL, 0 + }; + +/* Read and write virtual routines - per length */ + +uint32 ReadB (uint32 bva, uint32 *dat, uint32 acc) +{ +uint32 bpa, sc, tr; + +sc = 24 - ((bva & 3) << 3); +if (bva < BVA_REG) /* register access */ + *dat = (R[bva >> 2] >> sc) & BMASK; +else { /* memory access */ + if ((tr = map_reloc (bva, acc, &bpa)) != 0) /* relocate addr */ + return tr; + *dat = (M[bpa >> 2] >> sc) & BMASK; + } /* end else memory */ +return 0; +} + +uint32 ReadH (uint32 bva, uint32 *dat, uint32 acc) +{ +uint32 bpa, tr; + +if (bva < BVA_REG) { /* register access */ + if (bva & 2) + *dat = R[bva >> 2] & HMASK; + else *dat = (R[bva >> 2] >> 16) & HMASK; + } +else { /* memory access */ + if ((tr = map_reloc (bva, acc, &bpa)) != 0) /* relocate addr */ + return tr; + if (bva & 2) + *dat = M[bpa >> 2] & HMASK; + else *dat = (M[bpa >> 2] >> 16) & HMASK; + } /* end else memory */ +return 0; +} + +uint32 ReadW (uint32 bva, uint32 *dat, uint32 acc) +{ +uint32 bpa, tr; + +if (bva < BVA_REG) /* register access */ + *dat = R[bva >> 2]; +else { /* memory access */ + if ((tr = map_reloc (bva, acc, &bpa)) != 0) /* relocate addr */ + return tr; + *dat = M[bpa >> 2]; + } /* end else memory */ +return 0; +} + +uint32 ReadD (uint32 bva, uint32 *dat, uint32 *dat1, uint32 acc) +{ +uint32 bpa, tr; + +if (bva < BVA_REG) { /* register access */ + *dat = R[(bva >> 2) & ~1]; /* force alignment */ + *dat1 = R[(bva >> 2) | 1]; + } +else { /* memory access */ + if ((tr = map_reloc (bva, acc, &bpa)) != 0) /* relocate addr */ + return tr; + *dat = M[(bpa >> 2) & ~1]; /* force alignment */ + *dat1 = M[(bpa >> 2) | 1]; + } /* end else memory */ + +return 0; +} + +uint32 WriteB (uint32 bva, uint32 dat, uint32 acc) +{ +uint32 bpa, sc, tr; + +sc = 24 - ((bva & 3) << 3); +if (bva < BVA_REG) /* register access */ + R[bva >> 2] = (R[bva >> 2] & ~(BMASK << sc)) | ((dat & BMASK) << sc); +else { /* memory access */ + if ((tr = map_reloc (bva, acc, &bpa)) != 0) /* relocate addr */ + return tr; + M[bpa >> 2] = (M[bpa >> 2] & ~(BMASK << sc)) | ((dat & BMASK) << sc); + } /* end else memory */ +PSW2 |= PSW2_RA; /* state altered */ +return 0; +} + +uint32 WriteH (uint32 bva, uint32 dat, uint32 acc) +{ +uint32 bpa, tr; + +if (bva < BVA_REG) { /* register access */ + if (bva & 2) + R[bva >> 2] = (R[bva >> 2] & ~HMASK) | (dat & HMASK); + else R[bva >> 2] = (R[bva >> 2] & HMASK) | ((dat & HMASK) << 16); + } /* end if register */ +else { /* memory access */ + if ((tr = map_reloc (bva, acc, &bpa)) != 0) /* relocate addr */ + return tr; + if (bva & 2) + M[bpa >> 2] = (M[bpa >> 2] & ~HMASK) | (dat & HMASK); + else M[bpa >> 2] = (M[bpa >> 2] & HMASK) | ((dat & HMASK) << 16); + } /* end else memory */ +PSW2 |= PSW2_RA; /* state altered */ +return 0; +} + +uint32 WriteW (uint32 bva, uint32 dat, uint32 acc) +{ +uint32 bpa, tr; + +if (bva < BVA_REG) /* register access */ + R[bva >> 2] = dat & WMASK; +else { /* memory access */ + if ((tr = map_reloc (bva, acc, &bpa)) != 0) /* relocate addr */ + return tr; + M[bpa >> 2] = dat & WMASK; + } /* end else memory */ +PSW2 |= PSW2_RA; /* state altered */ +return 0; +} + +uint32 WriteD (uint32 bva, uint32 dat, uint32 dat1, uint32 acc) +{ +uint32 bpa, tr; + +if (bva < BVA_REG) { /* register access */ + R[(bva >> 2) & ~1] = dat & WMASK; /* force alignment */ + R[(bva >> 2) | 1] = dat1 & WMASK; + } +else { /* memory access */ + if ((tr = map_reloc (bva, acc, &bpa)) != 0) /* relocate addr */ + return tr; + M[(bpa >> 2) & ~1] = dat & WMASK; /* force alignment */ + M[(bpa >> 2) | 1] = dat1 & WMASK; + } /* end else memory */ +PSW2 |= PSW2_RA; /* state altered */ +return 0; +} + +/* General virtual read for instruction history */ + +uint32 ReadHist (uint32 bva, uint32 *dat, uint32 *dat1, uint32 acc, uint32 lnt) +{ +switch (lnt) { /* case on length */ + + case BY: /* byte */ + return ReadB (bva, dat, acc); + + case HW: /* halfword */ + return ReadH (bva, dat, acc); + + case WD: /* word */ + return ReadW (bva, dat, acc); + + case DW: /* doubleword first */ + return ReadD (bva, dat, dat1, acc); + } /* end case length */ + +return SCPE_IERR; +} + +/* Specialized virtual read and write word routines - + treats all addresses as memory addresses */ + +uint32 ReadMemVW (uint32 bva, uint32 *dat, uint32 acc) +{ +uint32 bpa; +uint32 tr; + +if ((tr = map_reloc (bva, acc, &bpa)) != 0) /* relocate addr */ + return tr; +*dat = M[bpa >> 2] & WMASK; +return 0; +} + +uint32 WriteMemVW (uint32 bva, uint32 dat, uint32 acc) +{ +uint32 bpa; +uint32 tr; + +if ((tr = map_reloc (bva, acc, &bpa)) != 0) /* relocate addr */ + return tr; +M[bpa >> 2] = dat & WMASK; +return 0; +} + +/* Relocation routine */ + +uint32 map_reloc (uint32 bva, uint32 acc, uint32 *bpa) +{ +if ((acc != 0) && (PSW1 & PSW1_MM)) { /* virt, map on? */ + uint32 vpag = BVA_GETPAG (bva); /* virt page num */ + *bpa = ((mmc_rel[vpag] << BVA_V_PAG) + BVA_GETOFF (bva)) & BPAMASK; + if (((PSW1 & PSW1_MS) || /* slave mode? */ + (PSW2 & (PSW2_MA9|PSW2_MA5X0))) && /* master prot? */ + (mmc_acc[vpag] >= acc)) /* access viol? */ + return map_viol (bva, *bpa, TR_MPR); + } +else *bpa = bva; /* no, physical */ +if ((acc == VW) && PSW2_WLK) { /* write check? */ + uint32 ppag = BPA_GETPAG (*bpa); /* phys page num */ + if (PSW2_WLK && mmc_wlk[ppag] && /* lock, key != 0 */ + (PSW2_WLK != mmc_wlk[ppag])) /* lock != key? */ + return map_viol (bva, *bpa, TR_WLK); + } +if (BPA_IS_NXM (*bpa)) /* memory exist? */ + return TR_NXM; /* don't set TSF */ +return 0; +} + +/* Memory management error */ + +uint32 map_viol (uint32 bva, uint32 bpa, uint32 tr) +{ +uint32 vpag = BVA_GETPAG (bva); /* virt page num */ + +if (QCPU_S9) /* Sigma 9? */ + PSW2 = (PSW2 & ~PSW2_TSF) | (vpag << PSW2_V_TSF); /* save address */ +PSW4 = bva >> 2; /* 5X0 address */ +if ((tr == TR_WLK) && !QCPU_5X0) /* wlock on S5-9? */ + tr = TR_MPR; /* mem prot trap */ +if (BPA_IS_NXM (bpa)) /* also check NXM */ + tr |= TR_NXM; /* on MPR or WLK */ +return tr; +} + +/* Physical byte access routines */ + +uint32 ReadPB (uint32 ba, uint32 *wd) +{ +uint32 sc; + +ba = ba & BPAMASK; +if (BPA_IS_NXM (ba)) + return TR_NXM; +sc = 24 - ((ba & 3) << 3); +*wd = (M[ba >> 2] >> sc) & BMASK; +return 0; +} + +uint32 WritePB (uint32 ba, uint32 wd) +{ +uint32 sc; + +ba = ba & BPAMASK; +if (BPA_IS_NXM (ba)) + return TR_NXM; +sc = 24 - ((ba & 3) << 3); +M[ba >> 2] = (M[ba >> 2] & ~(BMASK << sc)) | ((wd & BMASK) << sc); +return 0; +} + +/* Physical word access routines */ + +uint32 ReadPW (uint32 pa, uint32 *wd) +{ +pa = pa & cpu_tab[cpu_model].pamask; +if (MEM_IS_NXM (pa)) + return TR_NXM; +*wd = M[pa]; +return 0; +} + +uint32 WritePW (uint32 pa, uint32 wd) +{ +pa = pa & cpu_tab[cpu_model].pamask; +if (MEM_IS_NXM (pa)) + return TR_NXM; +M[pa] = wd; +return 0; +} + +/* LRA - load real address (extended memory systems only) */ + +uint32 map_lra (uint32 rn, uint32 IR) +{ +uint32 lnt, bva, bpa, vpag, ppag; +uint32 tr; + +lnt = CC >> 2; /* length */ +CC = 0; /* clear */ +if ((tr = Ea (IR, &bva, VR, lnt)) != 0) { /* get eff addr */ + if (tr == TR_NXM) /* NXM trap? */ + CC = CC1|CC2; + R[rn] = bva >> 2; /* fails */ + } +else if (bva < BVA_REG) { /* reg ref? */ + CC = CC1|CC2; + R[rn] = bva >> 2; /* fails */ + } +else { + vpag = BVA_GETPAG (bva); /* virt page num */ + bpa = ((mmc_rel[vpag] << BVA_V_PAG) + BVA_GETOFF (bva)) & BPAMASK; + ppag = BPA_GETPAG (bpa); /* phys page num */ + if (MEM_IS_NXM (bpa)) /* NXM? */ + CC = CC1|CC2; + R[rn] = (QCPU_S9? (mmc_wlk[ppag] << 24): 0) | /* result */ + (bpa >> lnt); + CC |= mmc_acc[vpag]; /* access prot */ + } +return 0; +} + +/* MMC - load memory map control */ + +uint32 map_mmc (uint32 rn, uint32 map) +{ +uint32 tr; +uint32 wd, i, map_width, maps_per_word, map_cmask, cs; + +map_width = mmc_tab[map].width; /* width in bits */ +maps_per_word = 32 / map_width; +if (map != 1) /* maps 2-7? */ + map_cmask = mmc_tab[map].cmask; /* std ctl mask */ +else map_cmask = cpu_tab[cpu_model].mmc_cm_map1; /* model based */ +if ((map_width == 0) || /* validate map */ + ((cpu_unit.flags & mmc_tab[map].opt) == 0) || + ((map == 3) && !QCPU_5X0) || + ((map == 5) && !QCPU_BIGM)) { + if (QCPU_S89_5X0) /* S89, 5X0 trap */ + return TR_INVMMC; + return stop_op? STOP_ILLEG: 0; + } +do { + cs = (R[rn|1] >> MMC_V_CS) & map_cmask; /* ptr into map */ + if ((tr = ReadW ((R[rn] << 2) & BVAMASK, &wd, VR)) != 0) + return tr; + for (i = 0; i < maps_per_word; i++) { /* loop thru word */ + wd = ((wd << map_width) | (wd >> (32 - map_width))) & WMASK; + switch (map) { + + case 1: case 3: /* write locks */ + mmc_wlk[cs] = wd & mmc_tab[map].dmask; + break; + + case 2: /* access ctls */ + mmc_acc[cs] = wd & mmc_tab[map].dmask; + break; + + case 4: case 5: /* relocation */ + mmc_rel[cs] = wd & mmc_tab[map].dmask; + break; + }; + cs = (cs + 1) % mmc_tab[map].lnt; /* incr mod lnt */ + } /* end for */ + R[rn] = (R[rn] + 1) & WMASK; /* incr mem ptr */ + R[rn|1] = (R[rn|1] & ~(MMC_CNT | (map_cmask << MMC_V_CS))) | + (((MMC_GETCNT (R[rn|1]) - 1) & MMC_M_CNT) << MMC_V_CNT) | + ((cs & map_cmask) << MMC_V_CS); + } while (MMC_GETCNT (R[rn|1]) != 0); +return SCPE_OK; +} + +/* LAS instruction (reused by LMS), without condition code settings */ + +uint32 map_las (uint32 rn, uint32 bva) +{ +uint32 opnd, tr; + +if ((bva < (RF_NUM << 2)) && QCPU_5X0) /* on 5X0, reg */ + ReadW (bva, &opnd, VR); /* refs ignored */ +else { /* go to mem */ + if ((tr = ReadMemVW (bva, &opnd, VR)) != 0) /* read word */ + return tr; + if ((tr = WriteMemVW (bva, opnd | WSIGN, VW)) != 0) /* set bit */ + return tr; + } +R[rn] = opnd; /* store */ +return 0; +} + +/* Load memory status */ + +uint32 map_lms (uint32 rn, uint32 bva) +{ +uint32 tr, wd, low, ppag; +uint32 memu = (bva >> 2) / CPU_MUNIT_SIZE; + +if (CC == 0) /* LAS */ + return map_las (rn, bva); +if (CC == 1) { /* read no par */ + if ((tr = ReadW (bva, &wd, PH)) != 0) + return tr; + R[rn] = wd; + for (CC = CC3; wd != 0; CC ^= CC3) { /* calc odd par */ + low = wd & -((int32) wd); + wd = wd & ~low; + } + return 0; + } + +ppag = BPA_GETPAG (bva); /* phys page num */ +wd = mem_sr0[memu]; /* save sr0 */ +if (QCPU_S89) + switch (CC) { /* Sigma 8-9 */ + case 0x2: /* read bad par */ + if ((tr = ReadW (bva, &wd, VR)) != 0) + return tr; + R[rn] = wd; + break; + case 0x7: /* set margins */ + mem_sr1[memu] = S89_SR1_FIXED | + ((memu & S89_SR1_M_MEMU) << S89_SR1_V_MEMU) | + ((R[rn] & S89_SR1_MARG) >> S89_SR1_MAROFF); + break; + case 0xB: /* read sr0, clr */ + mem_sr0[memu] = mem_sr1[memu] = 0; + case 0x8: /* read sr0 */ + R[rn] = (wd & S89_SR0_RD) | + (((1u << (chan_num + 1)) - 1) << (S89_SR0_V_PORTS - (chan_num + 1))); + break; + case 0x9: /* read sr1 */ + R[rn] = mem_sr1[memu]; + break; + case 0xA: case 0xE: /* read sr2 */ + R[rn] = 0; + break; + case 0xF: /* clear word */ + return WriteW (bva, 0, VW); + break; + default: + mem_sr0[memu] |= S89_SR0_BADLMS; + break; + } +else switch (CC) { /* 5X0 */ + case 0x2: /* clear word */ + return WriteW (bva, 0, VW); + case 0x6: /* read wlk */ + R[rn] = (mmc_wlk[ppag & ~1] << 4) | mmc_wlk[ppag | 1]; + break; + case 0x7: /* write wlk */ + mmc_wlk[ppag & ~1] = (R[rn] >> 4) & 0xF; + mmc_wlk[ppag | 1] = R[rn] & 0xF; + break; + case 0xC: /* read sr0, clr */ + mem_sr0[memu] = 0; + case 0x8: /* read sr0 */ + R[rn] = S5X0_SR0_FIXED | (wd & S5X0_SR0_RD) | + (((1u << (chan_num + 1)) - 1) << (S5X0_SR0_V_PORTS - (chan_num + 1))); + break; + case 0xA: /* read sr1 */ + R[rn] = S5X0_SR1_FIXED | + ((memu & S5X0_SR1_M_MEMU) << S5X0_SR1_V_MEMU) | + (memu << S5X0_SR1_V_SA); + break; + case 0xE: /* trash mem */ + return WriteW (bva, R[rn] & ~0xFF, VW); + default: + mem_sr0[memu] |= S5X0_SR0_BADLMS; + break; + } +return 0; +} + +/* Device reset */ + +t_stat map_reset (DEVICE *dptr) +{ +uint32 i; + +for (i = 0; i < VA_NUM_PAG; i++) { /* clear mmc arrays */ + mmc_rel[i] = 0; + mmc_acc[i] = 0; + } +for (i = 0; i < PA_NUM_PAG; i++) + mmc_wlk[i] = 0; +return SCPE_OK; +} diff --git a/sigma/sigma_mt.c b/sigma/sigma_mt.c new file mode 100644 index 00000000..17d76612 --- /dev/null +++ b/sigma/sigma_mt.c @@ -0,0 +1,647 @@ +/* sigma_mt.c: Sigma 732X 9-track magnetic tape + + Copyright (c) 2007-2008, Robert M. Supnik + + 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 + ROBERT M SUPNIK 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 Robert M Supnik shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + + mt 7320 and 7322/7323 magnetic tape + + Magnetic tapes are represented as a series of variable records + of the form: + + 32b byte count + byte 0 + byte 1 + : + byte n-2 + byte n-1 + 32 byte count + + If the byte count is odd, the record is padded with an extra byte + of junk. File marks are represented by a byte count of 0. +*/ + +#include "sigma_io_defs.h" +#include "sim_tape.h" + +/* Device definitions */ + +#define MT_NUMDR 8 /* #drives */ +#define MT_REW (MT_NUMDR) /* rewind threads */ +#define UST u3 /* unit status */ +#define UCMD u4 /* unit command */ +#define MT_MAXFR (1 << 16) /* max record lnt */ + +/* Unit commands */ + +#define MCM_INIT 0x100 +#define MCM_END 0x101 +#define MCM_WRITE 0x01 +#define MCM_READ 0x02 +#define MCM_SETC 0x03 +#define MCM_SENSE 0x04 +#define MCM_RDBK 0x0C +#define MCM_RWI 0x13 +#define MCM_RWU 0x23 +#define MCM_REW 0x33 +#define MCM_SFWR 0x43 +#define MCM_SBKR 0x4B +#define MCM_SFWF 0x53 +#define MCM_SBKF 0x5B +#define MCM_ERS 0x63 +#define MCM_WTM 0x73 + +/* Command flags */ + +#define O_ATT 0x01 /* req attached */ +#define O_WRE 0x02 /* req write enb */ +#define O_REV 0x04 /* reverse oper */ +#define O_NMT 0x10 /* no motion */ + +/* Device status in UST, ^ = dynamic */ + +#define MTDV_OVR 0x80 /* overrun - NI */ +#define MTDV_WRE 0x40 /* write enabled^ */ +#define MTDV_WLE 0x20 /* write lock err */ +#define MTDV_EOF 0x10 /* end of file */ +#define MTDV_DTE 0x08 /* data error */ +#define MTDV_BOT 0x04 /* begin of tape */ +#define MTDV_EOT 0x02 /* end of tape^ */ +#define MTDV_REW 0x01 /* rewinding^ */ + +#define MTAI_MASK (MTDV_OVR|MTDV_WLE|MTDV_EOF|MTDV_DTE) +#define MTAI_V_INT 6 +#define MTAI_INT (1u << MTAI_V_INT) + +uint32 mt_stopioe = 1; +int32 mt_rwtime = 10000; /* rewind latency */ +int32 mt_ctime = 100; /* command latency */ +int32 mt_time = 10; /* record latency */ +uint32 mt_rwi = 0; /* rewind interrupts */ +t_mtrlnt mt_bptr; +t_mtrlnt mt_blim; +uint8 mt_xb[MT_MAXFR]; /* transfer buffer */ +uint8 mt_op[128] = { + 0, O_ATT|O_WRE, O_ATT, O_NMT, O_NMT, 0, 0, 0, /* wr, rd, set, sense */ + 0, 0, 0, 0, O_ATT|O_REV, 0, 0, 0, /* rd rev */ + 0, 0, 0, O_ATT, 0, 0, 0, 0, /* rewind & int */ + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, O_ATT, 0, 0, 0, 0, /* rewind offline */ + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, O_ATT, 0, 0, 0, 0, /* rewind */ + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, O_ATT, 0, 0, 0, 0, /* space fwd rec */ + 0, 0, 0, O_ATT|O_REV, 0, 0, 0, 0, /* space bk rec */ + 0, 0, 0, O_ATT, 0, 0, 0, 0, /* space fwd file */ + 0, 0, 0, O_ATT|O_REV, 0, 0, 0, 0, /* space bk file */ + 0, 0, 0, O_NMT, 0, 0, 0, 0, /* set erase */ + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, O_ATT|O_WRE, 0, 0, 0, 0, /* write tmk */ + 0, 0, 0, 0, 0, 0, 0, 0 + }; + +extern uint32 chan_ctl_time; +extern uint8 ascii_to_ebcdic[128]; +extern uint8 ebcdic_to_ascii[256]; + +uint32 mt_disp (uint32 op, uint32 dva, uint32 *dvst); +uint32 mt_tio_status (uint32 un); +uint32 mt_tdv_status (uint32 un); +t_stat mt_chan_err (uint32 st); +t_stat mtu_svc (UNIT *uptr); +t_stat mtr_svc (UNIT *uptr); +t_stat mt_reset (DEVICE *dptr); +t_stat mt_attach (UNIT *uptr, char *cptr); +t_stat mt_detach (UNIT *uptr); +t_stat mt_flush_buf (UNIT *uptr); +t_stat mt_map_err (UNIT *uptr, t_stat r); +int32 mt_clr_int (uint32 dva); +void mt_set_rwi (uint32 un); +void mt_clr_rwi (uint32 un); + +/* MT data structures + + mt_dev MT device descriptor + mt_unit MT unit descriptors + mt_reg MT register list + mt_mod MT modifiers list +*/ + +dib_t mt_dib = { DVA_MT, mt_disp }; + +/* First 'n' units are tape drives; second 'n' are rewind threads */ + +UNIT mt_unit[] = { + { UDATA (&mtu_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, + { UDATA (&mtu_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, + { UDATA (&mtu_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, + { UDATA (&mtu_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, + { UDATA (&mtu_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, + { UDATA (&mtu_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, + { UDATA (&mtu_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, + { UDATA (&mtu_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, + { UDATA (&mtr_svc, UNIT_DIS, 0) }, + { UDATA (&mtr_svc, UNIT_DIS, 0) }, + { UDATA (&mtr_svc, UNIT_DIS, 0) }, + { UDATA (&mtr_svc, UNIT_DIS, 0) }, + { UDATA (&mtr_svc, UNIT_DIS, 0) }, + { UDATA (&mtr_svc, UNIT_DIS, 0) }, + { UDATA (&mtr_svc, UNIT_DIS, 0) }, + { UDATA (&mtr_svc, UNIT_DIS, 0) } + }; + +REG mt_reg[] = { + { BRDATA (BUF, mt_xb, 16, 8, MT_MAXFR) }, + { DRDATA (BPTR, mt_bptr, 17) }, + { DRDATA (BLNT, mt_blim, 17) }, + { HRDATA (RWINT, mt_rwi, MT_NUMDR) }, + { DRDATA (TIME, mt_time, 24), PV_LEFT+REG_NZ }, + { DRDATA (CTIME, mt_ctime, 24), PV_LEFT+REG_NZ }, + { DRDATA (RWTIME, mt_rwtime, 24), PV_LEFT+REG_NZ }, + { URDATA (UST, mt_unit[0].UST, 16, 8, 0, MT_NUMDR, 0) }, + { URDATA (UCMD, mt_unit[0].UCMD, 16, 8, 0, 2 * MT_NUMDR, 0) }, + { URDATA (POS, mt_unit[0].pos, 10, T_ADDR_W, 0, + MT_NUMDR, PV_LEFT | REG_RO) }, + { FLDATA (STOP_IOE, mt_stopioe, 0) }, + { HRDATA (DEVNO, mt_dib.dva, 12), REG_HRO }, + { NULL } + }; + +MTAB mt_mod[] = { + { MTUF_WLK, 0, "write enabled", "WRITEENABLED", NULL }, + { MTUF_WLK, MTUF_WLK, "write locked", "LOCKED", NULL }, + { MTAB_XTD|MTAB_VUN, 0, "FORMAT", "FORMAT", + &sim_tape_set_fmt, &sim_tape_show_fmt, NULL }, + { MTAB_XTD|MTAB_VUN, 0, "CAPACITY", "CAPACITY", + &sim_tape_set_capac, &sim_tape_show_capac, NULL }, + { MTAB_XTD|MTAB_VDV, 0, "CHAN", "CHAN", + &io_set_dvc, &io_show_dvc, NULL }, + { MTAB_XTD|MTAB_VDV, 0, "DVA", "DVA", + &io_set_dva, &io_show_dva, NULL }, + { MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "CSTATE", NULL, + NULL, &io_show_cst, NULL }, + { 0 } + }; + +DEVICE mt_dev = { + "MT", mt_unit, mt_reg, mt_mod, + MT_NUMDR * 2, 10, T_ADDR_W, 1, 16, 8, + NULL, NULL, &mt_reset, + &io_boot, &mt_attach, &mt_detach, + &mt_dib, DEV_DISABLE | DEV_TAPE + }; + +/* Magtape: IO dispatch routine */ + +uint32 mt_disp (uint32 op, uint32 dva, uint32 *dvst) +{ +uint32 un = DVA_GETUNIT (dva); +UNIT *uptr = &mt_unit[un]; + +if ((un >= MT_NUMDR) || /* inv unit num? */ + (uptr-> flags & UNIT_DIS)) /* disabled unit? */ + return DVT_NODEV; +switch (op) { /* case on op */ + + case OP_SIO: /* start I/O */ + *dvst = mt_tio_status (un); /* get status */ + if ((*dvst & (DVS_CST|DVS_DST)) == 0) { /* ctrl + dev idle? */ + uptr->UCMD = MCM_INIT; /* start dev thread */ + sim_activate (uptr, chan_ctl_time); + } + break; + + case OP_TIO: /* test status */ + *dvst = mt_tio_status (un); /* return status */ + break; + + case OP_TDV: /* test status */ + *dvst = mt_tdv_status (un); /* return status */ + break; + + case OP_HIO: /* halt I/O */ + *dvst = mt_tio_status (un); /* get status */ + if ((int32) un == chan_chk_chi (dva)) /* halt active ctlr int? */ + chan_clr_chi (dva); /* clear ctlr int */ + if (sim_is_active (uptr)) { /* chan active? */ + sim_cancel (uptr); /* stop unit */ + chan_uen (dva); /* uend */ + } + mt_clr_rwi (un); /* clear rewind int */ + sim_cancel (uptr + MT_REW); /* cancel rewind */ + break; + + case OP_AIO: /* acknowledge int */ + un = mt_clr_int (mt_dib.dva); /* clr int, get unit */ + *dvst = (mt_tdv_status (un) & MTAI_MASK) | /* device status */ + (un & MTAI_INT) | /* device int flag */ + ((un & DVA_M_UNIT) << DVT_V_UN); /* unit number */ + break; + + default: + *dvst = 0; + return SCPE_IERR; + } + +return 0; +} + +/* Unit service */ + +t_stat mtu_svc (UNIT *uptr) +{ +uint32 cmd = uptr->UCMD; +uint32 un = uptr - mt_unit; +uint32 c; +uint32 st; +int32 t; +t_mtrlnt tbc; +t_stat r; + +if (cmd == MCM_INIT) { /* init state */ + if ((t = sim_activate_time (uptr + MT_REW)) != 0) { /* rewinding? */ + sim_activate (uptr, t); /* retry later */ + return SCPE_OK; + } + st = chan_get_cmd (mt_dib.dva, &cmd); /* get command */ + if (CHS_IFERR (st)) /* channel error? */ + return mt_chan_err (st); + if ((cmd & 0x80) || /* invalid cmd? */ + (mt_op[cmd] == 0)) { + uptr->UCMD = MCM_END; /* end state */ + sim_activate (uptr, chan_ctl_time); /* resched ctlr */ + return SCPE_OK; + } + else { /* valid cmd */ + if ((mt_op[cmd] & O_REV) && /* reverse op */ + (mt_unit[un].UST & MTDV_BOT)) { /* at load point? */ + chan_uen (mt_dib.dva); /* channel end */ + return SCPE_OK; + } + uptr->UCMD = cmd; /* unit state */ + if (!(mt_op[cmd] & O_NMT)) /* motion? */ + uptr->UST = 0; /* clear status */ + } + mt_blim = 0; /* no buffer yet */ + sim_activate (uptr, chan_ctl_time); /* continue thread */ + return SCPE_OK; /* done */ + } + +if (cmd == MCM_END) { /* end state */ + st = chan_end (mt_dib.dva); /* set channel end */ + if (CHS_IFERR (st)) /* channel error? */ + return mt_chan_err (st); + if (st == CHS_CCH) { /* command chain? */ + uptr->UCMD = MCM_INIT; /* restart thread */ + sim_activate (uptr, chan_ctl_time); + } + else uptr->UCMD = 0; /* ctlr idle */ + return SCPE_OK; /* done */ + } + +if ((mt_op[cmd] & O_ATT) && /* op req att and */ + ((uptr->flags & UNIT_ATT) == 0)) { /* not attached? */ + sim_activate (uptr, mt_ctime); /* retry */ + return mt_stopioe? SCPE_UNATT: SCPE_OK; + } +if ((mt_op[cmd] & O_WRE) && /* write op and */ + sim_tape_wrp (uptr)) { /* write protected? */ + uptr->UST |= MTDV_WLE; /* set status */ + chan_uen (mt_dib.dva); /* unusual end */ + return SCPE_OK; + } + +r = SCPE_OK; +switch (cmd) { /* case on command */ + + case MCM_SFWR: /* space forward */ + if (r = sim_tape_sprecf (uptr, &tbc)) /* spc rec fwd, err? */ + r = mt_map_err (uptr, r); /* map error */ + break; + + case MCM_SBKR: /* space reverse */ + if (r = sim_tape_sprecr (uptr, &tbc)) /* spc rec rev, err? */ + r = mt_map_err (uptr, r); /* map error */ + break; + + case MCM_SFWF: /* space fwd file */ + while ((r = sim_tape_sprecf (uptr, &tbc)) == MTSE_OK) ; + if (r != MTSE_TMK) /* stopped by tmk? */ + r = mt_map_err (uptr, r); /* no, map error */ + else r = SCPE_OK; + break; + + case MCM_SBKF: /* space rev file */ + while ((r = sim_tape_sprecr (uptr, &tbc)) == MTSE_OK) ; + if (r != MTSE_TMK) /* stopped by tmk? */ + r = mt_map_err (uptr, r); /* no, map error */ + else r = SCPE_OK; + break; + + case MCM_WTM: /* write eof */ + if (r = sim_tape_wrtmk (uptr)) /* write tmk, err? */ + r = mt_map_err (uptr, r); /* map error */ + uptr->UST |= MTDV_EOF; /* set eof */ + break; + + case MCM_RWU: /* rewind unload */ + r = detach_unit (uptr); + break; + + case MCM_REW: /* rewind */ + case MCM_RWI: /* rewind and int */ + if (r = sim_tape_rewind (uptr)) /* rewind */ + r = mt_map_err (uptr, r); /* map error */ + mt_unit[un + MT_REW].UCMD = uptr->UCMD; /* copy command */ + sim_activate (uptr + MT_REW, mt_rwtime); /* sched compl */ + break; + + case MCM_READ: /* read */ + if (mt_blim == 0) { /* first read? */ + r = sim_tape_rdrecf (uptr, mt_xb, &mt_blim, MT_MAXFR); + if (r != MTSE_OK) { /* tape error? */ + r = mt_map_err (uptr, r); /* map error */ + break; + } + mt_bptr = 0; /* init rec ptr */ + } + c = mt_xb[mt_bptr++]; /* get char */ + st = chan_WrMemB (mt_dib.dva, c); /* write to memory */ + if (CHS_IFERR (st)) /* channel error? */ + return mt_chan_err (st); + if ((st != CHS_ZBC) && (mt_bptr != mt_blim)) { /* not done? */ + sim_activate (uptr, mt_time); /* continue thread */ + return SCPE_OK; + } + if (((st == CHS_ZBC) ^ (mt_bptr == mt_blim)) && /* length err? */ + chan_set_chf (mt_dib.dva, CHF_LNTE)) /* uend taken? */ + return SCPE_OK; /* finished */ + break; /* normal end */ + + case MCM_RDBK: /* read reverse */ + if (mt_blim == 0) { /* first read? */ + r = sim_tape_rdrecr (uptr, mt_xb, &mt_blim, MT_MAXFR); + if (r != MTSE_OK) { /* tape error? */ + r = mt_map_err (uptr, r); /* map error */ + break; + } + mt_bptr = mt_blim; /* init rec ptr */ + } + c = mt_xb[--mt_bptr]; /* get char */ + st = chan_WrMemBR (mt_dib.dva, c); /* write mem rev */ + if (CHS_IFERR (st)) /* channel error? */ + return mt_chan_err (st); + if ((st != CHS_ZBC) && (mt_bptr != 0)) { /* not done? */ + sim_activate (uptr, mt_time); /* continue thread */ + return SCPE_OK; + } + if (((st == CHS_ZBC) ^ (mt_bptr == 0)) && /* length err? */ + chan_set_chf (mt_dib.dva, CHF_LNTE)) /* uend taken? */ + return SCPE_OK; /* finished */ + break; /* normal end */ + + case MCM_WRITE: /* write */ + st = chan_RdMemB (mt_dib.dva, &c); /* read char */ + if (CHS_IFERR (st)) { /* channel error? */ + mt_flush_buf (uptr); /* flush buffer */ + return mt_chan_err (st); + } + mt_xb[mt_blim++] = c; /* store in buffer */ + if (st != CHS_ZBC) { /* end record? */ + sim_activate (uptr, mt_time); /* continue thread */ + return SCPE_OK; + } + r = mt_flush_buf (uptr); /* flush buffer */ + break; + } + +if (r != SCPE_OK) /* error? abort */ + return CHS_IFERR(r)? SCPE_OK: r; +uptr->UCMD = MCM_END; /* end state */ +sim_activate (uptr, mt_ctime); /* sched ctlr */ +return SCPE_OK; +} + +/* Rewind completion - set BOT, interrupt if desired */ + +t_stat mtr_svc (UNIT *uptr) +{ +uint32 un = uptr - mt_unit - MT_REW; + +mt_unit[un].UST |= MTDV_BOT; /* set BOT */ +if (uptr->UCMD == MCM_RWI) /* int wanted? */ + mt_set_rwi (un); /* interrupt */ +return SCPE_OK; +} + +t_stat mt_flush_buf (UNIT *uptr) +{ +t_stat st; + +if (mt_blim == 0) /* any output? */ + return SCPE_OK; +if (st = sim_tape_wrrecf (uptr, mt_xb, mt_blim)) /* write, err? */ + return mt_map_err (uptr, st); /* map error */ +return SCPE_OK; +} + +/* Map tape error status - returns chan error or SCP status */ + +t_stat mt_map_err (UNIT *uptr, t_stat st) +{ +int32 u = uptr - mt_dev.units; + +switch (st) { + + case MTSE_FMT: /* illegal fmt */ + case MTSE_UNATT: /* not attached */ + case MTSE_WRP: /* write protect */ + chan_set_chf (mt_dib.dva, CHF_XMME); + case MTSE_OK: /* no error */ + chan_uen (mt_dib.dva); /* uend */ + return SCPE_IERR; + + case MTSE_TMK: /* end of file */ + uptr->UST |= MTDV_EOF; /* set eof flag */ + chan_uen (mt_dib.dva); /* uend */ + return CHS_INACTV; + + case MTSE_IOERR: /* IO error */ + uptr->UST |= MTDV_DTE; /* set DTE flag */ + chan_set_chf (mt_dib.dva, CHF_XMDE); + chan_uen (mt_dib.dva); /* force uend */ + return SCPE_IOERR; + + case MTSE_INVRL: /* invalid rec lnt */ + uptr->UST |= MTDV_DTE; /* set DTE flag */ + chan_set_chf (mt_dib.dva, CHF_XMDE); + chan_uen (mt_dib.dva); /* force uend */ + return SCPE_MTRLNT; + + case MTSE_RECE: /* record in error */ + case MTSE_EOM: /* end of medium */ + uptr->UST |= MTDV_DTE; /* set DTE flag */ + return chan_set_chf (mt_dib.dva, CHF_XMDE); /* possible error */ + + case MTSE_BOT: /* reverse into BOT */ + uptr->UST |= MTDV_BOT; /* set BOT */ + chan_uen (mt_dib.dva); /* uend */ + return CHS_INACTV; + } /* end switch */ + +return SCPE_OK; +} + +/* MT status routine */ + +uint32 mt_tio_status (uint32 un) +{ +uint32 i, st; +UNIT *uptr = &mt_unit[un]; + +st = (uptr->flags & UNIT_ATT)? DVS_AUTO: 0; /* AUTO */ +if (sim_is_active (uptr) || /* unit busy */ + sim_is_active (uptr + MT_REW)) /* or rewinding? */ + st |= DVS_DBUSY; +for (i = 0; i < MT_NUMDR; i++) { /* loop thru units */ + if (sim_is_active (&mt_unit[i])) { /* active? */ + st |= (DVS_CBUSY | (CC2 << DVT_V_CC)); /* ctrl is busy */ + } + } +return st; +} + +uint32 mt_tdv_status (uint32 un) +{ +uint32 st; +UNIT *uptr = &mt_unit[un]; + +if (uptr->flags & UNIT_ATT) { /* attached? */ + st = uptr->UST; /* unit stat */ + if (sim_tape_eot (uptr)) /* at EOT? */ + st |= MTDV_EOT; + if (!sim_tape_wrp (uptr)) /* not wlock? */ + st |= MTDV_WRE; + } +else st = (CC2 << DVT_V_CC); +if (sim_is_active (uptr + MT_REW)) /* unit rewinding? */ + st |= (MTDV_REW | (CC2 << DVT_V_CC)); +return st; +} + + +/* Channel error */ + +t_stat mt_chan_err (uint32 st) +{ +chan_uen (mt_dib.dva); /* uend */ +if (st < CHS_ERR) + return st; +return SCPE_OK; +} + +/* Clear controller/device interrupt, return active unit */ + +int32 mt_clr_int (uint32 dva) +{ +int32 iu; + +if ((iu = chan_clr_chi (dva)) >= 0) { /* chan int? clear */ + if (mt_rwi != 0) /* dev ints? */ + chan_set_dvi (dva); /* set them */ + return iu; + } +for (iu = 0; iu < MT_NUMDR; iu++) { /* rewind int? */ + if (mt_rwi & (1u << iu)) { + mt_clr_rwi ((uint32) iu); + return (iu | MTAI_INT); + } + } +return 0; +} + +/* Set rewind interrupt */ + +void mt_set_rwi (uint32 un) +{ +mt_rwi |= (1u << un); +chan_set_dvi (mt_dib.dva); /* set INP */ +return; +} + +/* Clear rewind interrupt */ + +void mt_clr_rwi (uint32 un) +{ +mt_rwi &= ~(1u << un); /* clear */ +if (mt_rwi != 0) /* more? */ + chan_set_dvi (mt_dib.dva); +else if (chan_chk_chi (mt_dib.dva) < 0) /* any int? */ + chan_clr_chi (mt_dib.dva); /* clr INP */ +return; +} + +/* Reset routine */ + +t_stat mt_reset (DEVICE *dptr) +{ +uint32 i; + +for (i = 0; i < MT_NUMDR; i++) { + sim_cancel (&mt_unit[i]); /* stop unit */ + sim_cancel (&mt_unit[i + MT_REW]); /* stop rewind */ + mt_unit[i].UST = 0; + mt_unit[i].UCMD = 0; + } +mt_rwi = 0; +mt_bptr = 0; +mt_blim = 0; +chan_reset_dev (mt_dib.dva); /* clr int, active */ +for (i = 0; i < MT_MAXFR; i++) + mt_xb[i] = 0; +return SCPE_OK; +} + +/* Attach routine */ + +t_stat mt_attach (UNIT *uptr, char *cptr) +{ +t_stat r; + +r = sim_tape_attach (uptr, cptr); +if (r != SCPE_OK) return r; +uptr->UST = MTDV_BOT; +return r; +} + +/* Detach routine */ + +t_stat mt_detach (UNIT* uptr) +{ +uint32 un = uptr - mt_dev.units; + +if (!(uptr->flags & UNIT_ATTABLE)) + return SCPE_NOATT; +uptr->UST = 0; +sim_cancel (uptr + MT_REW); +return sim_tape_detach (uptr); +} \ No newline at end of file diff --git a/sigma/sigma_pt.c b/sigma/sigma_pt.c new file mode 100644 index 00000000..f5507f6b --- /dev/null +++ b/sigma/sigma_pt.c @@ -0,0 +1,297 @@ +/* sigma_pt.c: Sigma 7060 paper tape reader/punch + + Copyright (c) 2007-2008, Robert M. Supnik + + 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 + ROBERT M SUPNIK 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 Robert M Supnik shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + + pt 7060 paper-tape reader/punch +*/ + +#include "sigma_io_defs.h" + +/* Device definitions */ + +#define PTR 0 +#define PTP 1 + +/* Device states */ + +#define PTS_INIT 0x101 +#define PTS_END 0x102 +#define PTS_WRITE 0x1 +#define PTS_READ 0x2 +#define PTS_READI 0x82 + +/* Device status */ + +#define PTDV_PMAN 0x20 +#define PTDV_RMAN 0x10 + +uint32 pt_cmd = 0; +uint32 ptr_nzc = 0; +uint32 ptr_stopioe = 1; +uint32 ptp_stopioe = 1; + +extern uint32 chan_ctl_time; +extern uint8 ascii_to_ebcdic[128]; +extern uint8 ebcdic_to_ascii[256]; + +uint32 pt_disp (uint32 op, uint32 dva, uint32 *dvst); +uint32 pt_tio_status (void); +uint32 pt_tdv_status (void); +t_stat pt_chan_err (uint32 st); +t_stat pt_svc (UNIT *uptr); +t_stat pt_reset (DEVICE *dptr); +t_stat pt_attach (UNIT *uptr, char *cptr); + +/* PT data structures + + pt_dev PT device descriptor + pt_unit PT unit descriptors + pt_reg PT register list + pt_mod PT modifiers list +*/ + +dib_t pt_dib = { DVA_PT, pt_disp }; + +UNIT pt_unit[] = { + { UDATA (&pt_svc, UNIT_ATTABLE+UNIT_SEQ+UNIT_ROABLE, 0), SERIAL_IN_WAIT }, + { UDATA (&pt_svc, UNIT_ATTABLE+UNIT_SEQ, 0), SERIAL_OUT_WAIT } + }; + +REG pt_reg[] = { + { HRDATA (CMD, pt_cmd, 9) }, + { FLDATA (NZC, ptr_nzc,0) }, + { DRDATA (RPOS, pt_unit[PTR].pos, T_ADDR_W), PV_LEFT }, + { DRDATA (RTIME, pt_unit[PTR].wait, 24), PV_LEFT }, + { FLDATA (RSTOP_IOE, ptr_stopioe, 0) }, + { DRDATA (PPOS, pt_unit[PTP].pos, T_ADDR_W), PV_LEFT }, + { DRDATA (PTIME, pt_unit[PTP].wait, 24), REG_NZ + PV_LEFT }, + { FLDATA (PSTOP_IOE, ptp_stopioe, 0) }, + { HRDATA (DEVNO, pt_dib.dva, 12), REG_HRO }, + { NULL } + }; + +MTAB pt_mod[] = { + { MTAB_XTD|MTAB_VDV, 0, "CHAN", "CHAN", + &io_set_dvc, &io_show_dvc, NULL }, + { MTAB_XTD|MTAB_VDV, 0, "DVA", "DVA", + &io_set_dva, &io_show_dva, NULL }, + { MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "CSTATE", NULL, + NULL, &io_show_cst, NULL }, + { 0 } + }; + +DEVICE pt_dev = { + "PT", pt_unit, pt_reg, pt_mod, + 2, 10, 31, 1, 16, 8, + NULL, NULL, &pt_reset, + &io_boot, &pt_attach, NULL, + &pt_dib, DEV_DISABLE + }; + +/* Reader/punch: IO dispatch routine */ + +uint32 pt_disp (uint32 op, uint32 dva, uint32 *dvst) +{ +switch (op) { /* case on op */ + + case OP_SIO: /* start I/O */ + *dvst = pt_tio_status (); /* get status */ + if ((*dvst & DVS_DST) == 0) { /* idle? */ + pt_cmd = PTS_INIT; /* start dev thread */ + sim_activate (&pt_unit[PTR], chan_ctl_time); + } + break; + + case OP_TIO: /* test status */ + *dvst = pt_tio_status (); /* return status */ + break; + + case OP_TDV: /* test status */ + *dvst = pt_tdv_status (); /* return status */ + break; + + case OP_HIO: /* halt I/O */ + chan_clr_chi (pt_dib.dva); /* clr int*/ + *dvst = pt_tio_status (); /* get status */ + if ((*dvst & DVS_DST) != 0) { /* busy? */ + sim_cancel (&pt_unit[PTR]); /* stop dev thread */ + chan_uen (pt_dib.dva); /* uend */ + } + break; + + case OP_AIO: /* acknowledge int */ + chan_clr_chi (pt_dib.dva); /* clr int*/ + *dvst = 0; /* no status */ + break; + + default: + *dvst = 0; + return SCPE_IERR; + } + +return 0; +} + +/* Service routine */ + +t_stat pt_svc (UNIT *uptr) +{ +int32 c; +uint32 cmd; +uint32 st; + +switch (pt_cmd) { /* case on state */ + + case PTS_INIT: /* I/O init */ + st = chan_get_cmd (pt_dib.dva, &cmd); /* get command */ + if (CHS_IFERR (st)) /* channel error? */ + return pt_chan_err (st); + if ((cmd == PTS_WRITE) || /* valid command? */ + ((cmd & 0x7F) == PTS_READ)) + pt_cmd = cmd; /* next state */ + else pt_cmd = PTS_END; /* no, end state */ + sim_activate (uptr, chan_ctl_time); /* continue thread */ + break; + + case PTS_READ: + case PTS_READI: + sim_activate (uptr, uptr->wait); /* continue thread */ + if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */ + return ptr_stopioe? SCPE_UNATT: SCPE_OK; + if ((c = getc (uptr->fileref)) == EOF) { /* read char */ + if (feof (uptr->fileref)) { /* end of file? */ + chan_set_chf (pt_dib.dva, CHF_LNTE); /* length error */ + pt_cmd = PTS_END; /* end state */ + break; + } + else { /* real error */ + perror ("PTR I/O error"); + clearerr (uptr->fileref); + chan_set_chf (pt_dib.dva, CHF_XMDE); /* data error */ + return pt_chan_err (SCPE_IOERR); /* force uend */ + } + } + uptr->pos = uptr->pos + 1; + if (c != 0) /* leader done? */ + ptr_nzc = 1; /* set flag */ + if ((pt_cmd == PTS_READI) || ptr_nzc) { + st = chan_WrMemB (pt_dib.dva, c); /* write to memory */ + if (CHS_IFERR (st)) /* channel error? */ + return pt_chan_err (st); + if (st == CHS_ZBC) /* bc == 0? */ + pt_cmd = PTS_END; /* end state */ + } + break; + + case PTS_WRITE: /* write */ + sim_activate (uptr, pt_unit[PTP].wait); /* continue thread */ + if ((pt_unit[PTP].flags & UNIT_ATT) == 0) /* not attached? */ + return ptp_stopioe? SCPE_UNATT: SCPE_OK; + st = chan_RdMemB (pt_dib.dva, &c); /* read from channel */ + if (CHS_IFERR (st)) /* channel error? */ + return pt_chan_err (st); + if (putc (c, pt_unit[PTP].fileref) == EOF) { + perror ("PTP I/O error"); + clearerr (pt_unit[PTP].fileref); + chan_set_chf (pt_dib.dva, CHF_XMDE); /* data error */ + return pt_chan_err (SCPE_IOERR); /* force uend */ + } + pt_unit[PTP].pos = pt_unit[PTP].pos + 1; + if (st == CHS_ZBC) /* bc == 0? */ + pt_cmd = PTS_END; /* end state */ + break; + + case PTS_END: /* command done */ + st = chan_end (pt_dib.dva); /* set channel end */ + if (CHS_IFERR (st)) /* channel error? */ + return pt_chan_err (st); + if (st == CHS_CCH) { /* command chain? */ + pt_cmd = PTS_INIT; /* restart thread */ + sim_activate (uptr, chan_ctl_time); + } + break; + } + +return SCPE_OK; +} + +/* PT status routine */ + +uint32 pt_tio_status (void) +{ +uint32 st; + +if (((pt_unit[PTR].flags & UNIT_ATT) == 0) || /* rdr not att? */ + ((pt_unit[PTP].flags & UNIT_ATT) == 0)) /* pun not att? */ + st = 0; +else st = DVS_AUTO; /* otherwise ok */ +if (sim_is_active (&pt_unit[PTR])) /* dev busy? */ + st |= (DVS_CBUSY | DVS_DBUSY | (CC2 << DVT_V_CC)); +return st; +} + +uint32 pt_tdv_status (void) +{ +uint32 st; + +st = 0; +if ((pt_unit[PTR].flags & UNIT_ATT) == 0) /* rdr not att? */ + st |= PTDV_RMAN; +if ((pt_unit[PTP].flags & UNIT_ATT) == 0) /* pun not att? */ + st |= PTDV_PMAN; +return st; +} + +/* Channel error */ + +t_stat pt_chan_err (uint32 st) +{ +sim_cancel (&pt_unit[PTR]); /* stop dev thread */ +chan_uen (pt_dib.dva); /* uend */ +if (st < CHS_ERR) + return st; +return SCPE_OK; +} + +/* Reset routine */ + +t_stat pt_reset (DEVICE *dptr) +{ +sim_cancel (&pt_unit[PTR]); /* stop dev thread */ +pt_cmd = 0; +chan_reset_dev (pt_dib.dva); /* clr int, active */ +return SCPE_OK; +} + +/* Attach routine */ + +t_stat pt_attach (UNIT *uptr, char *cptr) +{ +t_stat st; + +st = attach_unit (uptr, cptr); +if ((uptr == &pt_unit[PTR]) && (st == SCPE_OK)) + ptr_nzc = 0; +return st; +} \ No newline at end of file diff --git a/sigma/sigma_rad.c b/sigma/sigma_rad.c new file mode 100644 index 00000000..1b904a44 --- /dev/null +++ b/sigma/sigma_rad.c @@ -0,0 +1,532 @@ +/* sigma_rad.c: Sigma 7211/7212 or 7231/7232 fixed head disk simulator + + Copyright (c) 2007-2008, Robert M Supnik + + 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 + ROBERT M SUPNIK 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 Robert M Supnik shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + + rad 7211/7212 or 7231/7232 fixed head disk + + The RAD is a head-per-track disk. To minimize overhead, the entire RAD + is buffered in memory. + + Transfers are always done a sector at a time. +*/ + +#include "sigma_io_defs.h" +#include + +/* Constants */ + +#define RAD_7212 0 /* ctlr type */ +#define RAD_7232 1 +#define RAD_NUMDR 4 /* drives/ctlr */ +#define RAD_WDSC 256 /* words/sector */ +#define RAD_WDMASK (RAD_WDSC - 1) +#define RAD_SCTK1 82 /* sectors/track */ +#define RAD_SCTK3 12 +#define RAD_TKUN1 64 /* tracks/unit */ +#define RAD_TKUN3 512 +#define RAD_WDUNDF (RAD_WDSC*RAD_SCTK1*RAD_TKUN1) /* dflt words/unit */ +#define RAD_WDUN (RAD_WDSC*rad_tab[rad_model].sctk*rad_tab[rad_model].tkun) +#define RAD_N_WLK 16 /* num wlk switches */ + +/* Address bytes */ + +#define RADA_V_TK1 7 /* track offset */ +#define RADA_M_TK1 0xFF +#define RADA_V_SC1 0 /* sector offset */ +#define RADA_M_SC1 0x7F +#define RADA_V_TK3 4 +#define RADA_M_TK3 0x3FF +#define RADA_V_SC3 0 +#define RADA_M_SC3 0xF +#define RADA_GETTK(x) (((x) >> rad_tab[rad_model].tk_v) & rad_tab[rad_model].tk_m) +#define RADA_GETSC(x) (((x) >> rad_tab[rad_model].sc_v) & rad_tab[rad_model].sc_m) + +/* Address bad flag */ + +#define RADA_INV 0x80 + +/* Status byte 3 is current sector */ +/* Status byte 4 (7212 only) is failing sector */ + +#define RADS_NBY1 4 /* num status bytes */ +#define RADS_NBY3 3 + +/* Device state */ + +#define RADS_INIT 0x101 +#define RADS_END 0x102 +#define RADS_WRITE 0x01 +#define RADS_READ 0x02 +#define RADS_SEEK 0x03 +#define RADS_SENSE 0x04 +#define RADS_CHECK 0x05 +#define RADS_RDEES 0x12 + +/* Device status */ + +#define RADV_OVR 0x80 /* overrun - NI */ +#define RADV_BADS 0x20 /* bad sector */ +#define RADV_WPE 0x10 + +#define GET_PSC(x) ((int32) fmod (sim_gtime() / ((double) (x * RAD_WDSC)), \ + ((double) rad_tab[rad_model].sctk))) + +/* Model table */ + +typedef struct { + uint32 tk_v; /* track extract */ + uint32 tk_m; + uint32 sc_v; /* sector extract */ + uint32 sc_m; + uint32 sctk; /* sectors/track */ + uint32 tkun; /* tracks/unit */ + uint32 nbys; /* bytes of status */ + } rad_t; + +static rad_t rad_tab[] = { + { RADA_V_TK1, RADA_M_TK1, RADA_V_SC1, RADA_M_SC1, RAD_SCTK1, RAD_TKUN1, RADS_NBY1 }, + { RADA_V_TK3, RADA_M_TK3, RADA_V_SC3, RADA_M_SC3, RAD_SCTK3, RAD_TKUN3, RADS_NBY3 } + }; + +uint32 rad_model = RAD_7212; /* model */ +uint32 rad_cmd = 0; /* state */ +uint32 rad_flags = 0; /* status flags */ +uint32 rad_ad = 0; /* rad address */ +uint32 rad_wlk = 0; /* write lock */ +uint32 rad_time = 2; /* inter-word time */ + +extern uint32 chan_ctl_time; + +uint32 rad_disp (uint32 op, uint32 dva, uint32 *dvst); +uint32 rad_tio_status (uint32 un); +uint32 rad_tdv_status (uint32 un); +t_stat rad_chan_err (uint32 st); +t_stat rad_svc (UNIT *uptr); +t_stat rad_reset (DEVICE *dptr); +t_stat rad_settype (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat rad_showtype (FILE *st, UNIT *uptr, int32 val, void *desc); +t_bool rad_inv_ad (uint32 *da); +t_bool rad_inc_ad (void); +t_bool rad_end_sec (UNIT *uptr, uint32 lnt, uint32 exp, uint32 st); + +/* RAD data structures + + rad_dev RAD device descriptor + rad_unit RAD unit descriptor + rad_reg RAD register list +*/ + +dib_t rad_dib = { DVA_RAD, &rad_disp }; + +UNIT rad_unit[] = { + { UDATA (&rad_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+ + UNIT_MUSTBUF+UNIT_DISABLE, RAD_WDUNDF) }, + { UDATA (&rad_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+ + UNIT_MUSTBUF+UNIT_DISABLE+UNIT_DIS, RAD_WDUNDF) }, + { UDATA (&rad_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+ + UNIT_MUSTBUF+UNIT_DISABLE+UNIT_DIS, RAD_WDUNDF) }, + { UDATA (&rad_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+ + UNIT_MUSTBUF+UNIT_DISABLE+UNIT_DIS, RAD_WDUNDF) } + }; + +REG rad_reg[] = { + { HRDATA (CMD, rad_cmd, 9) }, + { HRDATA (FLAGS, rad_flags, 8) }, + { HRDATA (ADDR, rad_ad, 15) }, + { HRDATA (WLK, rad_wlk, RAD_N_WLK) }, + { DRDATA (TIME, rad_time, 24), PV_LEFT }, + { FLDATA (MODEL, rad_model, 0), REG_HRO }, + { HRDATA (DEVNO, rad_dib.dva, 12), REG_HRO }, + { NULL } + }; + +MTAB rad_mod[] = { + { MTAB_XTD | MTAB_VDV, RAD_7212, NULL, "7211", + &rad_settype, NULL, NULL }, + { MTAB_XTD | MTAB_VDV, RAD_7212, NULL, "7212", + &rad_settype, NULL, NULL }, + { MTAB_XTD | MTAB_VDV, RAD_7232, NULL, "7231", + &rad_settype, NULL, NULL }, + { MTAB_XTD | MTAB_VDV, RAD_7232, NULL, "7232", + &rad_settype, NULL, NULL }, + { MTAB_XTD | MTAB_VDV, 0, "TYPE", NULL, + NULL, &rad_showtype, NULL }, + { MTAB_XTD|MTAB_VDV, 0, "CHAN", "CHAN", + &io_set_dvc, &io_show_dvc, NULL }, + { MTAB_XTD|MTAB_VDV, 0, "DVA", "DVA", + &io_set_dva, &io_show_dva, NULL }, + { MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "CSTATE", NULL, + NULL, &io_show_cst, NULL }, + { 0 } + }; + +DEVICE rad_dev = { + "RAD", rad_unit, rad_reg, rad_mod, + RAD_NUMDR, 16, 21, 1, 16, 32, + NULL, NULL, &rad_reset, + &io_boot, NULL, NULL, + &rad_dib, DEV_DISABLE + }; + +/* RAD: IO dispatch routine */ + +uint32 rad_disp (uint32 op, uint32 dva, uint32 *dvst) +{ +uint32 i; +uint32 un = DVA_GETUNIT (dva); +UNIT *uptr; + +if ((un >= RAD_NUMDR) || /* inv unit num? */ + (rad_unit[un].flags & UNIT_DIS)) /* disabled unit? */ + return DVT_NODEV; +switch (op) { /* case on op */ + + case OP_SIO: /* start I/O */ + *dvst = rad_tio_status (un); /* get status */ + if ((*dvst & (DVS_CST|DVS_DST)) == 0) { /* ctrl + dev idle? */ + rad_cmd = RADS_INIT; /* start dev thread */ + sim_activate (&rad_unit[un], chan_ctl_time); + } + break; + + case OP_TIO: /* test status */ + *dvst = rad_tio_status (un); /* return status */ + break; + + case OP_TDV: /* test status */ + *dvst = rad_tdv_status (un); /* return status */ + break; + + case OP_HIO: /* halt I/O */ + chan_clr_chi (rad_dib.dva); /* clr int*/ + *dvst = rad_tio_status (un); /* get status */ + if ((*dvst & DVS_CST) != 0) { /* ctrl busy? */ + for (i = 0; i < RAD_NUMDR; i++) { /* find busy unit */ + uptr = &rad_unit[i]; + if (sim_is_active (uptr)) { /* active? */ + sim_cancel (uptr); /* stop */ + chan_uen (rad_dib.dva); /* uend */ + } /* end if active */ + } /* end for */ + } + break; + + case OP_AIO: /* acknowledge int */ + chan_clr_chi (rad_dib.dva); /* clr int */ + *dvst = rad_tdv_status (0); /* status like TDV */ + break; + + default: + *dvst = 0; + return SCPE_IERR; + } + +return 0; +} + +/* Unit service - this code assumes the entire disk is buffered */ + +t_stat rad_svc (UNIT *uptr) +{ +uint32 i, sc, da, cmd, wd, wd1, c[4], gp; +uint32 *fbuf = (uint32 *) uptr->filebuf; +uint32 st; +int32 t; + +switch (rad_cmd) { + + case RADS_INIT: /* init state */ + st = chan_get_cmd (rad_dib.dva, &cmd); /* get command */ + if (CHS_IFERR (st)) /* channel error? */ + return rad_chan_err (st); + if ((cmd == 0) || /* invalid cmd? */ + ((cmd > RADS_CHECK) && (cmd != RADS_RDEES))) { + chan_uen (rad_dib.dva); /* uend */ + return SCPE_OK; + } + rad_flags = 0; /* clear status */ + rad_cmd = cmd & 0x7; /* next state */ + if ((cmd == RADS_SEEK) || (cmd == RADS_SENSE)) /* seek or sense? */ + sim_activate (uptr, chan_ctl_time); /* schedule soon */ + else { /* data transfer */ + sc = RADA_GETSC (rad_ad); /* new sector */ + t = sc - GET_PSC (rad_time); /* delta to new */ + if (t < 0) /* wrap around? */ + t = t + rad_tab[rad_model].sctk; + sim_activate (uptr, t * rad_time * RAD_WDSC); /* schedule op */ + } + return SCPE_OK; + + case RADS_END: /* end state */ + st = chan_end (rad_dib.dva); /* set channel end */ + if (CHS_IFERR (st)) /* channel error? */ + return rad_chan_err (st); + if (st == CHS_CCH) { /* command chain? */ + rad_cmd = RADS_INIT; /* restart thread */ + sim_activate (uptr, chan_ctl_time); + } + return SCPE_OK; /* done */ + + case RADS_SEEK: /* seek */ + c[0] = c[1] = 0; + for (i = 0, st = 0; (i < 2) && (st != CHS_ZBC); i++) { + st = chan_RdMemB (rad_dib.dva, &c[i]); /* get byte */ + if (CHS_IFERR (st)) /* channel error? */ + return rad_chan_err (st); + } + rad_ad = ((c[0] & 0x7F) << 8) | c[1]; /* new address */ + if (((i != 2) || (st != CHS_ZBC)) && /* length error? */ + chan_set_chf (rad_dib.dva, CHF_LNTE)) /* care? */ + return SCPE_OK; + break; + + case RADS_SENSE: /* sense */ + c[0] = ((rad_ad >> 8) & 0x7F) | (rad_inv_ad (NULL)? RADA_INV: 0); + c[1] = rad_ad & 0xFF; /* address */ + c[2] = GET_PSC (rad_time); /* curr sector */ + c[3] = 0; + for (i = 0, st = 0; (i < rad_tab[rad_model].nbys) && (st != CHS_ZBC); i++) { + st = chan_WrMemB (rad_dib.dva, c[i]); /* store char */ + if (CHS_IFERR (st)) /* channel error? */ + return rad_chan_err (st); + } + if (((i != rad_tab[rad_model].nbys) || (st != CHS_ZBC)) && + chan_set_chf (rad_dib.dva, CHF_LNTE)) /* length error? */ + return SCPE_OK; + break; + + case RADS_WRITE: /* write */ + gp = (RADA_GETSC (rad_ad) * RAD_N_WLK) / /* write lock group */ + rad_tab[rad_model].tkun; + if ((rad_wlk >> gp) & 1) { /* write lock set? */ + rad_flags |= RADV_WPE; /* set status */ + chan_uen (rad_dib.dva); /* uend */ + return SCPE_OK; + } /* fall through */ + if (rad_inv_ad (&da)) { /* invalid addr? */ + chan_uen (rad_dib.dva); /* uend */ + return SCPE_OK; + } + for (i = 0, st = 0; i < RAD_WDSC; da++, i++) { /* write */ + if (st != CHS_ZBC) { /* chan active? */ + st = chan_RdMemW (rad_dib.dva, &wd); /* get data */ + if (CHS_IFERR (st)) { /* channel error? */ + rad_inc_ad (); /* da increments */ + return rad_chan_err (st); + } + } + else wd = 0; + fbuf[da] = wd; /* store in buffer */ + if (da >= uptr->hwmark) /* update length */ + uptr->hwmark = da + 1; + } + if (rad_end_sec (uptr, i, RAD_WDSC, st)) /* transfer done? */ + return SCPE_OK; + break; + +/* Must be done by bytes to get precise miscompare */ + + case RADS_CHECK: /* write check */ + if (rad_inv_ad (&da)) { /* invalid addr? */ + chan_uen (rad_dib.dva); /* uend */ + return SCPE_OK; + } + for (i = 0, st = 0; (i < (RAD_WDSC * 4)) && (st != CHS_ZBC); ) { + st = chan_RdMemB (rad_dib.dva, &wd); /* read sector */ + if (CHS_IFERR (st)) { /* channel error? */ + rad_inc_ad (); /* da increments */ + return rad_chan_err (st); + } + wd1 = (fbuf[da] >> (24 - ((i % 4) * 8))) & 0xFF; /* byte */ + if (wd != wd1) { /* check error? */ + rad_inc_ad (); /* da increments */ + chan_set_chf (rad_dib.dva, CHF_XMDE); /* set xmt err flag */ + chan_uen (rad_dib.dva); /* force uend */ + return SCPE_OK; + } + da = da + ((++i % 4) == 0); /* every 4th byte */ + } + if (rad_end_sec (uptr, i, RAD_WDSC * 4, st)) /* transfer done? */ + return SCPE_OK; + break; + + case RADS_READ: /* read */ + if (rad_inv_ad (&da)) { /* invalid addr? */ + chan_uen (rad_dib.dva); /* uend */ + return SCPE_OK; + } + for (i = 0, st = 0; (i < RAD_WDSC) && (st != CHS_ZBC); da++, i++) { + st = chan_WrMemW (rad_dib.dva, fbuf[da]); /* store in mem */ + if (CHS_IFERR (st)) { /* channel error? */ + rad_inc_ad (); /* da increments */ + return rad_chan_err (st); + } + } + if (rad_end_sec (uptr, i, RAD_WDSC, st)) /* transfer done? */ + return SCPE_OK; + break; + } + +rad_cmd = RADS_END; /* op done, next state */ +sim_activate (uptr, chan_ctl_time); +return SCPE_OK; +} + +/* Common read/write sector end routine + + case 1 - more to transfer, not end disk - reschedule, return TRUE + case 2 - more to transfer, end disk - uend, return TRUE + case 3 - transfer done, length error - uend, return TRUE + case 4 - transfer done, no length error - return FALSE (sched end state) +*/ + +t_bool rad_end_sec (UNIT *uptr, uint32 lnt, uint32 exp, uint32 st) +{ +if (st != CHS_ZBC) { /* end record? */ + if (rad_inc_ad ()) /* inc addr, ovf? */ + chan_uen (rad_dib.dva); /* uend */ + else sim_activate (uptr, rad_time * 16); /* no, next sector */ + return TRUE; + } +rad_inc_ad (); /* just incr addr */ +if ((lnt != exp) && /* length error? */ + chan_set_chf (rad_dib.dva, CHF_LNTE)) /* do we care? */ + return TRUE; +return FALSE; /* cmd done */ +} + +/* RAD status routine */ + +uint32 rad_tio_status (uint32 un) +{ +uint32 i, st; + +st = DVS_AUTO; /* flags */ +if (sim_is_active (&rad_unit[un])) /* active => busy */ + st |= DVS_DBUSY; +else if ((rad_unit[un].flags & UNIT_ATT) == 0) /* not att => offl */ + st |= DVS_DOFFL; +for (i = 0; i < RAD_NUMDR; i++) { /* loop thru units */ + if (sim_is_active (&rad_unit[i])) { /* active? */ + st |= (DVS_CBUSY |(CC2 << DVT_V_CC)); /* ctrl is busy */ + return st; + } + } +return st; +} + +uint32 rad_tdv_status (uint32 un) +{ +uint32 st; + +st = rad_flags; +if (rad_inv_ad (NULL)) /* bad address? */ + st |= RADV_BADS; +return st; +} + +/* Validate disk address */ + +t_bool rad_inv_ad (uint32 *da) +{ +uint32 tk = RADA_GETTK (rad_ad); +uint32 sc = RADA_GETSC (rad_ad); + +if ((tk >= rad_tab[rad_model].tkun) || /* bad sec or trk? */ + (sc >= rad_tab[rad_model].sctk)) { + return TRUE; + } +if (da) /* return word addr */ + *da = ((tk * rad_tab[rad_model].sctk) + sc) * RAD_WDSC; +return FALSE; +} + +/* Increment disk address */ + +t_bool rad_inc_ad (void) +{ +uint32 tk = RADA_GETTK (rad_ad); +uint32 sc = RADA_GETSC (rad_ad); + +sc = sc + 1; /* sector++ */ +if (sc >= rad_tab[rad_model].sctk) { /* overflow? */ + sc = 0; /* wrap sector */ + tk = tk + 1; /* track++ */ + } +rad_ad = ((tk << rad_tab[rad_model].tk_v) | /* rebuild rad_ad */ + (sc << rad_tab[rad_model].sc_v)); +if (tk >= rad_tab[rad_model].tkun) /* overflow? */ + return TRUE; +return FALSE; +} + +/* Channel error */ + +t_stat rad_chan_err (uint32 st) +{ +chan_uen (rad_dib.dva); /* uend */ +if (st < CHS_ERR) + return st; +return SCPE_OK; +} + +/* Reset routine */ + +t_stat rad_reset (DEVICE *dptr) +{ +uint32 i; + +for (i = 0; i < RAD_NUMDR; i++) + sim_cancel (&rad_unit[i]); /* stop dev thread */ +rad_cmd = 0; +rad_flags = 0; +rad_ad = 0; +chan_reset_dev (rad_dib.dva); /* clr int, active */ +return SCPE_OK; +} + +/* Set controller type */ + +t_stat rad_settype (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +uint32 i; + +for (i = 0; i < RAD_NUMDR; i++) { /* all units unatt? */ + if (rad_unit[i].flags & UNIT_ATT) + return SCPE_ALATT; + } +rad_model = val; /* update model */ +rad_reset (&rad_dev); /* reset */ +for (i = 0; i < RAD_NUMDR; i++) /* update capacity */ + rad_unit[i].capac = RAD_WDUN; +return SCPE_OK; +} + +/* Show controller type */ + +t_stat rad_showtype (FILE *st, UNIT *uptr, int32 val, void *desc) +{ +fprintf (st, (rad_model == RAD_7212)? "7211/7212": "7231/7232"); +return SCPE_OK; +} diff --git a/sigma/sigma_rtc.c b/sigma/sigma_rtc.c new file mode 100644 index 00000000..34982fa3 --- /dev/null +++ b/sigma/sigma_rtc.c @@ -0,0 +1,267 @@ +/* sigma_rtc.c: Sigma clocks + + Copyright (c) 2007, Robert M. Supnik + + 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 + ROBERT M SUPNIK 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 Robert M Supnik shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + + rtc clocks + + The real-time clock includes an internal scheduler for events which need to + be driven at multiples of the clock frequency, such as console and multiplexor + polling. Other devices can "register" with the clock module to receive service + callbacks at a timed interval. This replaces the standard SimH event queue + mechanism for real-time synchronous events. +*/ + +#include "sigma_io_defs.h" + +#define RTC_HZ_BASE 500 +#define RTC_TICKS_DFLT 500 + +/* Timed events data structures */ + +uint8 rtc_indx[RTC_NUM_EVNTS]; /* index into rtc_tab */ +uint8 rtc_cntr[RTC_NUM_EVNTS]; /* timer ticks left */ +uint8 rtc_xtra[RTC_NUM_EVNTS]; /* extra counter */ +UNIT *rtc_usrv[RTC_NUM_EVNTS]; /* unit servers */ + +/* Real-time clock counter frequencies */ + +uint16 rtc_tps[RTC_NUM_CNTRS] = { + RTC_HZ_OFF, RTC_HZ_OFF, RTC_HZ_500, RTC_HZ_500 + }; + +/* Frequency descriptors. The base clock runs at 500Hz. To get submultiples, + an event uses a tick counter. If the frequency is not an even submultiple, the + event can specify an "extra" counter. Every "extra" ticks of the event counter, + the event counter is increased by one. Thus, 60Hz counts as 8-8-9, providing + 3 clock ticks for every 25 base timer ticks. */ + +typedef struct { + uint32 hz; + uint32 cntr_reset; + uint32 xtra_reset; + } rtcdef_t; + +static rtcdef_t rtc_tab[RTC_NUM_HZ] = { + { 0, 0, 0 }, + { 500, 1, 0 }, + { 50, 10, 0 }, + { 60, 8, 3 }, + { 100, 5, 0 }, + { 2, 250, 0 }, + }; + +t_stat rtc_svc (UNIT *uptr); +t_stat rtc_cntr_svc (UNIT *uptr); +t_stat rtc_reset (DEVICE *dptr); +t_stat rtc_show_events (FILE *of, UNIT *uptr, int32 val, void *desc); + +/* Clock data structures + + rtc_dev RTC device descriptor + rtc_unit RTC unit + rtc_reg RTC register list +*/ + +UNIT rtc_unit = { UDATA (&rtc_svc, 0, 0), RTC_TICKS_DFLT }; + +UNIT rtc_cntr_unit[RTC_NUM_CNTRS] = { + { UDATA (&rtc_cntr_svc, 0, 0) }, + { UDATA (&rtc_cntr_svc, 0, 0) }, + { UDATA (&rtc_cntr_svc, 0, 0) }, + { UDATA (&rtc_cntr_svc, 0, 0) } + }; + +REG rtc_reg[] = { + { BRDATA (TPS, rtc_tps, 10, 10, RTC_NUM_CNTRS), REG_HRO }, + { BRDATA (INDX, rtc_indx, 10, 4, RTC_NUM_EVNTS), REG_HRO }, + { BRDATA (CNTR, rtc_cntr, 10, 6, RTC_NUM_EVNTS), REG_HRO }, + { BRDATA (XTRA, rtc_xtra, 10, 6, RTC_NUM_EVNTS), REG_HRO }, + { NULL } + }; + +MTAB rtc_mod[] = { + { MTAB_XTD|MTAB_VDV|MTAB_NMO, RTC_C1, "C1", "C1", + &rtc_set_tps, &rtc_show_tps, NULL }, + { MTAB_XTD|MTAB_VDV|MTAB_NMO, RTC_C2, "C2", "C2", + &rtc_set_tps, &rtc_show_tps, NULL }, + { MTAB_XTD|MTAB_VDV|MTAB_NMO, RTC_C3, "C3", "C3", + &rtc_set_tps, &rtc_show_tps, NULL }, + { MTAB_XTD|MTAB_VDV|MTAB_NMO, RTC_C4, "C4", NULL, + NULL, &rtc_show_tps, NULL }, + { MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "EVENTS", NULL, + NULL, &rtc_show_events, NULL }, + { 0 } + }; + +DEVICE rtc_dev = { + "RTC", &rtc_unit, rtc_reg, rtc_mod, + 1, 16, 8, 1, 16, 8, + NULL, NULL, &rtc_reset, + NULL, NULL, NULL + }; + +/* Master timer service routine */ + +t_stat rtc_svc (UNIT *uptr) +{ +uint32 i, idx; +int32 t; +t_stat st; + +t = sim_rtcn_calb (RTC_HZ_BASE, TMR_RTC); /* calibrate clock */ +sim_activate (uptr, t); /* reactivate unit */ +for (i = 0; i < RTC_NUM_EVNTS; i++) { /* loop thru events */ + if (rtc_cntr[i] != 0) { /* event active? */ + rtc_cntr[i] = rtc_cntr[i] - 1; /* decrement */ + if (rtc_cntr[i] == 0) { /* expired? */ + idx = rtc_indx[i]; + rtc_cntr[i] = rtc_tab[idx].cntr_reset; /* reset counter */ + if (rtc_xtra[i] != 0) { /* fudge factor? */ + rtc_xtra[i] = rtc_xtra[i] - 1; /* decr fudge cntr */ + if (rtc_xtra[i] == 0) { /* expired? */ + rtc_cntr[i]++; /* extra tick */ + rtc_xtra[i] = rtc_tab[idx].xtra_reset; /* reset fudge cntr */ + } /* end fudge = 0 */ + } /* end fudge active */ + if ((rtc_usrv[i] == NULL) || /* registered? */ + (rtc_usrv[i]->action == NULL)) + return SCPE_IERR; /* should be */ + st = rtc_usrv[i]->action (rtc_usrv[i]); /* callback */ + if (st != SCPE_OK) /* error */ + return st; + } /* end cntr = 0 */ + } /* end event active */ + } /* end event loop */ +return SCPE_OK; +} + +/* Callback for a system timer */ + +t_stat rtc_cntr_svc (UNIT *uptr) +{ +uint32 cn = uptr - rtc_cntr_unit; + +io_sclr_req (INTV (INTG_OVR, cn), 1); /* set cntr intr */ +return SCPE_OK; +} + +/* Register a timer */ + +t_stat rtc_register (uint32 tm, uint32 idx, UNIT *uptr) +{ +if ((tm >= RTC_NUM_EVNTS) || /* validate params */ + (idx >= RTC_NUM_HZ) || + (uptr == NULL) || + (uptr->action == NULL)) + return SCPE_IERR; +rtc_usrv[tm] = uptr; +rtc_indx[tm] = idx; +rtc_cntr[tm] = rtc_tab[idx].cntr_reset; /* init event */ +rtc_xtra[tm] = rtc_tab[idx].xtra_reset; +return SCPE_OK; +} + +/* Set timer ticks */ + +t_stat rtc_set_tps (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +uint32 newval, i; +t_stat r; + +if (val >= RTC_NUM_EVNTS) /* validate params */ + return SCPE_IERR; +if (cptr == NULL) /* must have arg */ + return SCPE_ARG; +newval = get_uint (cptr, 10, 10000, &r); +if ((r != SCPE_OK) || /* error? */ + ((newval == 0) && (val >= 2))) /* can't turn off 3,4 */ + return SCPE_ARG; +for (i = 0; i < RTC_NUM_HZ; i++) { /* loop thru freqs */ + if (newval == rtc_tab[i].hz) { /* found freq? */ + rtc_tps[val] = i; + rtc_indx[val] = i; /* save event vals */ + rtc_cntr[val] = rtc_tab[i].cntr_reset; + rtc_xtra[val] = rtc_tab[i].xtra_reset; + return SCPE_OK; + } + } +return SCPE_ARG; +} + +/* Show timer ticks */ + +t_stat rtc_show_tps (FILE *of, UNIT *uptr, int32 val, void *desc) +{ +uint32 idx; + +if (val >= RTC_NUM_EVNTS) + return SCPE_IERR; +idx = rtc_tps[val]; /* ptr to clk defs */ +if (rtc_tab[idx].hz == 0) + fprintf (of, "off\n"); +else fprintf (of, "%dHz\n", rtc_tab[idx].hz); +return SCPE_OK; +} + + +/* Reset routine */ + +t_stat rtc_reset (DEVICE *dptr) +{ +uint32 i; + +sim_rtcn_init (rtc_unit.wait, TMR_RTC); /* init base clock */ +sim_activate_abs (&rtc_unit, rtc_unit.wait); /* activate unit */ + +for (i = 0; i < RTC_NUM_EVNTS; i++) { /* clear counters */ + if (i < RTC_NUM_CNTRS) { + rtc_cntr[i] = 0; + rtc_xtra[i] = 0; + rtc_indx[i] = 0; + rtc_usrv[i] = NULL; + if (rtc_register (i, rtc_tps[i], &rtc_cntr_unit[i]) != SCPE_OK) + return SCPE_IERR; + } + else if ((rtc_usrv[i] != NULL) && + (rtc_register (i, rtc_indx[i], rtc_usrv[i]) != SCPE_OK)) + return SCPE_IERR; + } +return SCPE_OK; +} + +/* Show events */ + +t_stat rtc_show_events (FILE *of, UNIT *uptr, int32 val, void *desc) +{ +uint32 i; + +fprintf (of, "Event Status Frequency Ticks Extra\n"); +for (i = 0; i < RTC_NUM_EVNTS; i++) { + if (rtc_cntr[i]) + fprintf (of, " %d on %3dHz %3d %d\n", + i, rtc_tab[rtc_indx[i]].hz, rtc_cntr[i], rtc_xtra[i]); + else fprintf (of, " %d off\n", i); + } +return SCPE_OK; +} \ No newline at end of file diff --git a/sigma/sigma_sys.c b/sigma/sigma_sys.c new file mode 100644 index 00000000..c334af7e --- /dev/null +++ b/sigma/sigma_sys.c @@ -0,0 +1,613 @@ +/* sigma_sys.c: Sigma system interface + + Copyright (c) 2007-2008, Robert M Supnik + + 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 + ROBERT M SUPNIK 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 Robert M Supnik shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. +*/ + +#include "sigma_defs.h" +#include + +#define FMTASC(x) ((x) < 0x20)? "<%02X>": "%c", (x) + +extern DEVICE cpu_dev; +extern DEVICE map_dev; +extern DEVICE int_dev; +extern DEVICE chan_dev[]; +extern DEVICE rtc_dev; +extern DEVICE tt_dev; +extern DEVICE pt_dev; +extern DEVICE lp_dev; +extern DEVICE rad_dev; +extern DEVICE dk_dev; +extern DEVICE dp_dev[]; +extern DEVICE mt_dev; +extern DEVICE mux_dev, muxl_dev; +extern REG cpu_reg[]; +extern uint32 *M; +extern UNIT cpu_unit; + +t_stat fprint_sym_m (FILE *of, uint32 inst); +t_stat parse_sym_m (char *cptr, t_value *val); +void fprint_ebcdic (FILE *of, uint32 c); + +/* 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[] = "XDS Sigma"; + +REG *sim_PC = &cpu_reg[0]; + +int32 sim_emax = 1; + +DEVICE *sim_devices[] = { + &cpu_dev, + &map_dev, + &int_dev, + &chan_dev[0], + &chan_dev[1], + &chan_dev[2], + &chan_dev[3], + &chan_dev[4], + &chan_dev[5], + &chan_dev[6], + &chan_dev[7], + &rtc_dev, /* must be first */ + &tt_dev, + &pt_dev, + &lp_dev, + &mt_dev, + &rad_dev, + &dk_dev, + &dp_dev[0], + &dp_dev[1], + &mux_dev, + &muxl_dev, + NULL + }; + +const char *sim_stop_messages[] = { + "Unknown error", + "Invalid I/O configuration", + "Breakpoint", + "Address stop", + "Wait, interrupts off", + "Invalid PSD", + "Nested EXU's exceed limit", + "Undefined instruction", + "Illegal trap or interrupt instruction", + "Invalid interrupt vector", + "Nested traps", + }; + +/* Character conversion tables (from Sigma 7 manual) */ + +uint8 ascii_to_ebcdic[128] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x09, 0x06, 0x07, /* 00 - 1F */ + 0x08, 0x05, 0x15, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x0A, 0x16, 0x17, + 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, + 0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D, /* 20 - 3F */ + 0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61, + 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, + 0xF8, 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F, + 0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, /* 40 - 5F */ + 0xC8, 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, + 0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, + 0xE7, 0xE8, 0xE9, 0xB4, 0xB1, 0xB5, 0x6A, 0x6D, + 0x4A, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 60- 7F */ + 0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, + 0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, + 0xA7, 0xA8, 0xA9, 0xB2, 0x4F, 0xB3, 0x5F, 0xFF + }; + +uint8 ebcdic_to_ascii[256] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x09, 0x06, 0x07, /* 00 - 1F */ + 0x08, 0x05, 0x15, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x0A, 0x16, 0x17, + 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 20 - 3F */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ' ', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 40 - 5F */ + 0x00, 0x00, '`', '.', '<', '(', '+', '|', + '&', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, '!', '$', '*', ')', ';', '~', + '-', '/', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 60 - 7F */ + 0x00, 0x00, '^', ',', '%', '_', '>', '?', + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, ':', '#', '@', '\'', '=', '"', + 0x00, 'a', 'b', 'c', 'd', 'e', 'f', 'g', /* 80 - 9F */ + 'h', 'i', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 'j', 'k', 'l', 'm', 'n', 'o', 'p', + 'q', 'r', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 's', 't', 'u', 'v', 'w', 'x', /* A0 - BF */ + 'y', 'z', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, '\\', '{', '}', '[', ']', 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 'A', 'B', 'C', 'D', 'E', 'F', 'G', /* C0 - DF */ + 'H', 'I', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 'J', 'K', 'L', 'M', 'N', 'O', 'P', + 'Q', 'R', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 'S', 'T', 'U', 'V', 'W', 'X', /* E0 - FF */ + 'Y', 'Z', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, + }; + +/* Binary loader */ + +t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag) +{ +return SCPE_NOFNC; +} + +/* Symbol and format tables */ + +#define IC_V_CL 17 /* class */ +#define IC_M_CL 0x1F +#define IC_V_RN 16 /* takes rn */ +#define IC_RN (1u << IC_V_RN) +#define IC_V_IND 15 /* takes ind */ +#define IC_IND (1u << IC_V_IND) +#define IC_V_XR 13 /* takes xr */ +#define IC_M_XR 0x3 +#define IC_NONE 0 +#define IC_XR 1 +#define IC_CTL 2 +#define IC_V_AW 7 /* addr width */ +#define IC_M_AW 0x3F +#define IC_V_AP 2 /* addr position */ +#define IC_M_AP 0x1F +#define IC_V_SGN 1 /* sign allowed */ +#define IC_SGN (1u << IC_V_SGN) +#define IC_V_AOP 0 /* addr optional */ +#define IC_AOP (1u << IC_V_AOP) + +#define ID1_07 0 /* decode 1-7 */ +#define ID1_11 1 /* decode 1-11 */ +#define IDSHFT 2 /* shift */ +#define IDSHFF 3 /* shift floating */ +#define IDMMCX 4 /* MMC ext */ + +#define I_C(c,r,i,w,s,x,sn,ao) \ + (((c) << IC_V_CL) | ((r) << IC_V_RN) | ((i) << IC_V_IND)|\ + ((w) << IC_V_AW) | ((s) << IC_V_AP) | ((x) << IC_V_XR) |\ + ((sn) << IC_V_SGN) | ((ao) << IC_V_AOP)) + +/* decode R I wd ps x sn ao */ +#define IC_MRF I_C(ID1_07,1,1,17, 0,1, 0, 0) /* mem ref */ +#define IC_IMM I_C(ID1_07,1,0,20, 0,0, 1, 0) /* immediate */ +#define IC_LCFI I_C(ID1_07,0,0, 8, 0,2, 0, 0) /* LCFI */ +#define IC_LFI I_C(ID1_11,0,0, 4, 0,0, 0, 0) /* LFI */ +#define IC_LCI I_C(ID1_11,0,0, 4, 4,0, 0, 0) /* LCI */ +#define IC_SHFT I_C(IDSHFT,1,0, 7, 0,1, 1, 0) /* shift */ +#define IC_SHFF I_C(IDSHFF,1,0, 7, 0,1, 1, 0) /* floating shift */ +#define IC_MNOR I_C(ID1_07,0,1,17, 0,1, 0, 0) /* mem ref, no reg */ +#define IC_MNOX I_C(ID1_11,0,1,17, 0,1, 0, 0) /* mef ref ext */ +#define IC_NOP I_C(ID1_07,1,0, 0, 0,0, 0, 0) /* no operand */ +#define IC_NOPX I_C(ID1_11,1,0, 0, 0,0, 0, 0) /* no operand ext */ +#define IC_MMC I_C(ID1_07,1,1, 3,17,0, 0, 0) /* MMC */ +#define IC_MMCX I_C(IDMMCX,1,0, 0, 0,0, 0, 0) /* MMC extended */ +#define IC_MNRI I_C(ID1_11,0,0, 0, 0,0, 0, 0) /* no operands */ +#define IC_MNRO I_C(ID1_07,0,1,17, 0,1, 0, 1) /* mem ref, addr opt */ + +#define IC_GETCL(x) (((x) >> IC_V_CL) & IC_M_CL) +#define IC_GETXR(x) (((x) >> IC_V_XR) & IC_M_XR) +#define IC_GETAW(x) (((x) >> IC_V_AW) & IC_M_AW) +#define IC_GETAP(x) (((x) >> IC_V_AP) & IC_M_AP) + +static const uint32 masks[] = { + 0x7F000000, 0x7FF00000, 0x7F000700, 0x7F000100, + 0x7F0E0000 + }; + +/* Opcode tables - extended mnemonics must precede standard mnemonics */ + +static const uint32 opc_val[] = { + 0x02100000, IC_LFI, 0x02200000, IC_LCI, 0x70100000, IC_MNOX, 0x70200000, IC_MNOX, + 0x25000000, IC_SHFT, 0x25000100, IC_SHFT, 0x25000200, IC_SHFT, 0x25000000, IC_SHFT, + 0x25000400, IC_SHFT, 0x25000500, IC_SHFT, 0x25000600, IC_SHFT, 0x25000700, IC_SHFT, + 0x24000000, IC_SHFT, 0x24000100, IC_SHFT, + 0x68000000, IC_MNOX, 0x68100000, IC_MNOX, 0x68200000, IC_MNOX, 0x68300000, IC_MNOX, + 0x68400000, IC_MNOX, 0x68800000, IC_MNOX, + 0x69000000, IC_MNOX, 0x69100000, IC_MNOX, 0x69200000, IC_MNOX, 0x69300000, IC_MNOX, + 0x69400000, IC_MNOX, 0x69800000, IC_MNOX, + 0x6F020000, IC_MMCX, 0x6F040000, IC_MMCX, 0x6F060000, IC_MMCX, 0x6F080000, IC_MMCX, + 0x6F080000, IC_MMCX, 0x02000000, IC_MNRI, + + 0x02000000, IC_LCFI, + 0x04000000, IC_MRF, 0x05000000, IC_MRF, 0x06000000, IC_MRF, 0x07000000, IC_MRF, + 0x08000000, IC_MRF, 0x09000000, IC_MRF, 0x0A000000, IC_MRF, 0x0B000000, IC_MRF, + 0x0C000000, IC_MRF, 0x0D000000, IC_NOP, 0x0E000000, IC_MRF, 0x0F000000, IC_MRF, + 0x10000000, IC_MRF, 0x11000000, IC_MRF, 0x12000000, IC_MRF, 0x13000000, IC_MRF, + 0x15000000, IC_MRF, + 0x18000000, IC_MRF, 0x19000000, IC_MRF, 0x1A000000, IC_MRF, 0x1B000000, IC_MRF, + 0x1C000000, IC_MRF, 0x1D000000, IC_MRF, 0x1E000000, IC_MRF, 0x1F000000, IC_MRF, + 0x20000000, IC_IMM, 0x21000000, IC_IMM, 0x22000000, IC_IMM, 0x23000000, IC_IMM, + 0x24000000, IC_MRF, 0x25000000, IC_MRF, 0x26000000, IC_MRF, + 0x28000000, IC_MRF, 0x29000000, IC_MRF, 0x2A000000, IC_MRF, 0x2B000000, IC_MRF, + 0x2C000000, IC_MRF, 0x2D000000, IC_MRF, 0x2E000000, IC_MNRO, 0x2F000000, IC_MRF, + 0x30000000, IC_MRF, 0x31000000, IC_MRF, 0x32000000, IC_MRF, 0x33000000, IC_MRF, + 0x34000000, IC_MRF, 0x35000000, IC_MRF, 0x36000000, IC_MRF, 0x37000000, IC_MRF, + 0x38000000, IC_MRF, 0x39000000, IC_MRF, 0x3A000000, IC_MRF, 0x3B000000, IC_MRF, + 0x3C000000, IC_MRF, 0x3D000000, IC_MRF, 0x3E000000, IC_MRF, 0x3F000000, IC_MRF, + 0x40000000, IC_IMM, 0x41000000, IC_IMM, + 0x44000000, IC_MRF, 0x45000000, IC_MRF, 0x46000000, IC_MRF, 0x47000000, IC_MRF, + 0x48000000, IC_MRF, 0x49000000, IC_MRF, 0x4A000000, IC_MRF, 0x4B000000, IC_MRF, + 0x4C000000, IC_MRF, 0x4D000000, IC_MRF, 0x4E000000, IC_MRF, 0x4F000000, IC_MRF, + 0x50000000, IC_MRF, 0x51000000, IC_MRF, 0x52000000, IC_MRF, 0x53000000, IC_MRF, + 0x55000000, IC_MRF, 0x56000000, IC_MRF, 0x57000000, IC_MRF, + 0x58000000, IC_MRF, 0x5A000000, IC_MRF, 0x5B000000, IC_MRF, + + 0x60000000, IC_IMM, 0x61000000, IC_IMM, 0x63000000, IC_IMM, + 0x64000000, IC_MRF, 0x65000000, IC_MRF, 0x66000000, IC_MRF, 0x67000000, IC_MNOR, + 0x68000000, IC_MRF, 0x69000000, IC_MRF, 0x6A000000, IC_MRF, 0x6B000000, IC_MRF, + 0x6C000000, IC_MRF, 0x6D000000, IC_MRF, 0x6E000000, IC_MRF, 0x6F000000, IC_MMC, + 0x70000000, IC_MRF, 0x71000000, IC_MRF, 0x72000000, IC_MRF, 0x73000000, IC_MRF, + 0x74000000, IC_MNOR, 0x75000000, IC_MRF, 0x76000000, IC_MRF, 0x77000000, IC_MRF, + 0x78000000, IC_MRF, 0x79000000, IC_MRF, 0x7A000000, IC_MRF, 0x7B000000, IC_MRF, + 0x7C000000, IC_MNOR, 0x7D000000, IC_MRF, 0x7E000000, IC_MRF, 0x7F000000, IC_MRF, + 0xFFFFFFFF, 0 + }; + +static const char *opcode[] = { + "LFI", "LCI", "LF", "LC", /* extended mmenomics */ + "SLS", "SLD", "SCS", "SCD", + "SAS", "SAD", "SSS", "SSD", + "SFS", "SFL", + "B", "BGE", "BLE", "BE", + "BNOV", "BNC", + "BNVR", "BL", "BG", "BNE", + "BOV", "BC", + "LLOCKS", "LPC", "LLOCKSE", "LMAP", + "LMAPRE", "NOP", + + "LCFI", /* 00 */ + "CAL1", "CAL2", "CAL3", "CAL4", + "PLW", "PSW", "PLM", "PSM", + "PLS", "PSS", "LPSD", "XPSD", + "AD", "CD", "LD", "MSP", /* 10 */ + "STD", + "SD", "CLM", "LCD", "LAD", + "FSL", "FAL", "FDL", "FML", + "AI", "CI", "LI", "MI", /* 20 */ + "SF", "S", "LAS", + "CVS", "CVA", "LM", "STM", + "LRA", "LMS", "WAIT", "LRP", + "AW", "CW", "LW", "MTW", /* 30 */ + "LVAW", "STW", "DW", "MW", + "SW", "CLR", "LCW", "LAW", + "FSS", "FAS", "FDS", "FMS", + "TTBS", "TBS", /* 40 */ + "ANLZ", "CS", "XW", "STS", + "EOR", "OR", "LS", "AND", + "SIO", "TIO", "TDV", "HIO", + "AH", "CH", "LH", "MTH", /* 50 */ + "STH", "DH", "MH", + "SH", "LCH", "LAH", + + "CBS", "MBS", "EBS", /* 60 */ + "BDR", "BIR", "AWM", "EXU", + "BCR", "BCS", "BAL", "INT", + "RD", "WD", "AIO", "MMC", + "LCF", "CB", "LB", "MTB", /* 70 */ + "STCF", "STB", "PACK", "UNPK", + "DS", "DA", "DD", "DM", + "DSA", "DC", "DL", "DST", + NULL + }; + +/* 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) +{ +uint32 inst, sc, rdx, c; +DEVICE *dptr; + +inst = val[0]; /* get inst */ +if (uptr == NULL) /* anon = CPU */ + uptr = &cpu_unit; +else if (uptr != &cpu_unit) /* CPU only */ + return SCPE_ARG; +dptr = find_dev_from_unit (uptr); /* find dev */ +if (dptr == NULL) + return SCPE_IERR; +if (sw & SWMASK ('D')) /* get radix */ + rdx = 10; +else if (sw & SWMASK ('O')) + rdx = 8; +else if (sw & SWMASK ('X')) + rdx = 16; +else rdx = dptr->dradix; + +if (sw & SWMASK ('C')) { /* char format? */ + for (sc = 0; sc < 32; sc = sc + 8) { /* print string */ + c = (inst >> (24 - sc)) & BMASK; + if (sw & SWMASK ('A')) + fprintf (of, FMTASC (c & 0x7F)); + else fprint_ebcdic (of, c); + } + return 0; /* return # chars */ + } +if (sw & SWMASK ('A')) { /* ASCII? */ + sc = 24 - ((addr & 0x3) * 8); /* shift count */ + c = (inst >> sc) & 0x7F; + fprintf (of, "%c", FMTASC (c)); + return 0; + } +if (sw & SWMASK ('E')) { /* EBCDIC? */ + sc = 24 - ((addr & 0x3) * 8); /* shift count */ + c = (inst >> sc) & BMASK; + fprint_ebcdic (of, c); + return 0; + } +if (sw & SWMASK ('B')) { /* byte? */ + sc = 24 - ((addr & 0x3) * 8); /* shift count */ + c = (inst >> sc) & BMASK; + fprintf (of, "%02X", c); + return 0; + } +if (sw & SWMASK ('H')) { /* halfword? */ + c = ((addr & 1)? inst: inst >> 16) & HMASK; + fprintf (of, "%04X", c); + return 0; + } +if ((sw & SWMASK ('M')) && /* inst format? */ + !fprint_sym_m (of, inst)) /* decode inst */ + return 0; + +fprint_val (of, inst, rdx, 32, PV_RZRO); +return 0; +} + +/* Instruction decode */ + +t_stat fprint_sym_m (FILE *of, uint32 inst) +{ +uint32 i, j; + +for (i = 0; opc_val[i] < 0xFFFFFFFF; i = i + 2) { /* loop thru ops */ + j = IC_GETCL (opc_val[i + 1]); /* get class */ + if (opc_val[i] == (inst & masks[j])) { /* match? */ + uint32 fl = opc_val[i + 1]; /* get format */ + uint32 aw = IC_GETAW (fl); + uint32 ap = IC_GETAP (fl); + uint32 xr = IC_GETXR (fl); + uint32 rn = I_GETRN (inst); /* get fields */ + uint32 xn = I_GETXR (inst); + uint32 mask = (1u << aw) - 1; + uint32 ad = (inst >> ap) & mask; + + fprintf (of, "%s", opcode[i >> 1]); /* opcode */ + if (fl & IC_RN) /* rn? */ + fprintf (of, ",%d", rn); + if (TST_IND (inst) || aw || xr) { /* anything else? */ + fputs (TST_IND (inst)? " *": " ", of); /* space{*} */ + if (aw) { /* any value? */ + if ((fl & IC_SGN) && /* signed and */ + (ad & (1u << (aw - 1)))) /* negative? */ + fprintf (of, "-%X", (mask + 1) - ad); + else fprintf (of, "%X", ad); + if ((xr == IC_XR) && xn) /* any index? */ + fprintf (of, ",%d", xn); + else if (xr == IC_CTL) /* or control? */ + fprintf (of, ",%X", rn); + } + } + return SCPE_OK; + } + } +return SCPE_ARG; +} + +void fprint_ebcdic (FILE *of, uint32 c) +{ +uint32 cv = ebcdic_to_ascii[c]; +if ((cv < 0040) || (cv >= 0177)) + fprintf (of, "<%02X>", c); +else fputc (cv, of); +return; +} + +/* 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 (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw) +{ +t_value num; +uint32 i, sc, rdx, c; +t_stat r; +DEVICE *dptr; + +if (uptr == NULL) /* anon = CPU */ + uptr = &cpu_unit; +else if (uptr != &cpu_unit) /* CPU only */ + return SCPE_ARG; +dptr = find_dev_from_unit (uptr); /* find dev */ +if (dptr == NULL) + return SCPE_IERR; +if (sw & SWMASK ('D')) /* get radix */ + rdx = 10; +else if (sw & SWMASK ('O')) + rdx = 8; +else if (sw & SWMASK ('X')) + rdx = 16; +else rdx = dptr->dradix; + +if ((sw & SWMASK ('C')) || ((*cptr == '"') && cptr++)) { /* chars? */ + if (cptr[0] == 0) /* must have 1 char */ + return SCPE_ARG; + for (i = 0; i < 4; i++) { + if (cptr[i] == 0) + break; + sc = 24 - (i * 8); + c = (sw & SWMASK ('A'))? + cptr[i] & 0x7F: + ascii_to_ebcdic[cptr[i]]; + val[0] = (val[0] & ~(BMASK << sc)) | (c << sc); + } + return 0; + } +if ((sw & SWMASK ('A')) || ((*cptr == '#') && cptr++)) { /* ASCII char? */ + if (cptr[0] == 0) /* must have 1 char */ + return SCPE_ARG; + sc = 24 - (addr & 0x3) * 8; /* shift count */ + val[0] = (val[0] & ~(BMASK << sc)) | (cptr[0] << sc); + return 0; + } +if ((sw & SWMASK ('E')) || ((*cptr == '\'') && cptr++)) { /* EBCDIC char? */ + if (cptr[0] == 0) /* must have 1 char */ + return SCPE_ARG; + sc = 24 - (addr & 0x3) * 8; /* shift count */ + val[0] = (val[0] & ~(BMASK << sc)) | (ascii_to_ebcdic[cptr[0]] << sc); + return 0; + } +if (sw & SWMASK ('B')) { /* byte? */ + num = get_uint (cptr, rdx, BMASK, &r); /* get byte */ + if (r != SCPE_OK) + return SCPE_ARG; + sc = 24 - (addr & 0x3) * 8; /* shift count */ + val[0] = (val[0] & ~(BMASK << sc)) | (num << sc); + return 0; + } +if (sw & SWMASK ('H')) { /* halfword? */ + num = get_uint (cptr, rdx, HMASK, &r); /* get half word */ + if (r != SCPE_OK) + return SCPE_ARG; + sc = addr & 1? 0: 16; + val[0] = (val[0] & ~(HMASK << sc)) | (num << sc); + return 0; + } +if (!parse_sym_m (cptr, val)) + return 0; + +val[0] = get_uint (cptr, rdx, WMASK, &r); /* get number */ +if (r != SCPE_OK) + return r; +return 0; +} + +t_stat parse_sym_m (char *cptr, t_value *val) +{ +uint32 i, sgn; +t_stat r; +char *sep; +char gbuf[CBUFSIZE]; + +cptr = get_glyph (cptr, gbuf, 0); /* get opcode+reg*/ +if (sep = strchr (gbuf, ',')) /* , in middle? */ + *sep++ = 0; /* split strings */ +for (i = 0; opcode[i] != NULL; i++) { /* loop thru ops */ + if (strcmp (opcode[i], gbuf) == 0) { /* string match? */ + uint32 rn, xn, ad; + uint32 k = i << 1; /* index to opval */ + uint32 fl = opc_val[k + 1]; + uint32 aw = IC_GETAW (fl); + uint32 ap = IC_GETAP (fl); + uint32 xr = IC_GETXR (fl); + uint32 mask = (1u << aw) - 1; + + val[0] = opc_val[k]; + if (fl & IC_RN) { /* need rn? */ + if (sep == NULL) + return SCPE_ARG; + rn = get_uint (sep, 10, INST_M_RN, &r); + if (r != SCPE_OK) + return SCPE_ARG; + val[0] |= rn << INST_V_RN; + } + else if (sep) /* rn & not wanted */ + return SCPE_ARG; + if (aw) { /* more? */ + if (*cptr == 0) + return (fl & IC_AOP)? SCPE_OK: SCPE_ARG; + if ((fl & IC_IND) && (*cptr == '*')) { /* indirect? */ + val[0] |= INST_IND; + cptr++; + } + if ((fl & IC_SGN) && /* signed val? */ + strchr ("+-", *cptr) && /* with sign? */ + (*cptr++ == '-')) /* and minus? */ + sgn = 1; + else sgn = 0; /* else + */ + cptr = get_glyph (cptr, gbuf, 0); /* get rest */ + if (sep = strchr (gbuf, ',')) /* , in middle? */ + *sep++ = 0; /* split strings */ + ad = get_uint (gbuf, 16, mask, &r); + if (r != SCPE_OK) + return r; + if (sgn && ad) /* negative, nz? */ + ad = (mask + 1) - ad; /* complement */ + val[0] |= (ad << ap); + if ((xr == IC_XR) && sep) { /* index? */ + xn = get_uint (sep, 10, 7, &r); + if (r != SCPE_OK) + return r; + val[0] |= (xn << INST_V_XR); + } + else if (xr == IC_CTL) { /* control? */ + if (sep == NULL) + return SCPE_ARG; + xn = get_uint (gbuf, 16, INST_M_RN, &r); + if (r != SCPE_OK) + return r; + val[0] |= (xn << INST_V_RN); + } + else if (sep) + return SCPE_ARG; + } + if (*cptr != 0) + return SCPE_ARG; + return SCPE_OK; + } + } +return SCPE_ARG; +} diff --git a/sigma/sigma_tt.c b/sigma/sigma_tt.c new file mode 100644 index 00000000..97d32d3c --- /dev/null +++ b/sigma/sigma_tt.c @@ -0,0 +1,331 @@ +/* sigma_tt.c: Sigma 7012 console teletype + + Copyright (c) 2007-2008, Robert M. Supnik + + 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 + ROBERT M SUPNIK 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 Robert M Supnik shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + + tt 7012 console + + The 7012 has the following special cases on input and output: + + CR input, mapped to NEWLINE and echoes CR-LF + ^H input, mapped to EOM and not echoed + HT input or output, simulates tabbing with fixed 8 character stops +*/ + +#include "sigma_io_defs.h" +#include + +/* Device definitions */ + +#define TTI 0 +#define TTO 1 + +/* Device states */ + +#define TTS_IDLE 0x0 +#define TTS_INIT 0x1 +#define TTS_END 0x2 +#define TTS_WRITE 0x5 +#define TTS_READ 0x6 +#define TTS_READS 0x86 + +/* EBCDIC special characters for input */ + +#define E_EOM 0x08 /* end of medium */ +#define E_HT 0x05 /* tab */ +#define E_NL 0x15 /* new line */ + +uint32 tt_cmd = TTS_IDLE; +uint32 tti_tps = RTC_HZ_100; +uint32 tti_panel = 020; /* panel int char */ +uint32 tto_pos = 0; /* char position */ + +extern uint32 chan_ctl_time; +extern uint8 ascii_to_ebcdic[128]; +extern uint8 ebcdic_to_ascii[256]; + +uint32 tt_disp (uint32 op, uint32 dva, uint32 *dvst); +uint32 tt_tio_status (void); +t_stat tt_chan_err (uint32 st); +t_stat tti_rtc_svc (uint32 tm); +t_stat tti_svc (UNIT *uptr); +t_stat tto_svc (UNIT *uptr); +t_stat tt_reset (DEVICE *dptr); +t_stat tt_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc); +void tto_echo (int32 c); + +extern t_stat io_set_pint (void); + +/* TT data structures + + tt_dev TT device descriptor + tt_unit TT unit descriptors + tt_reg TT register list + tt_mod TT modifiers list +*/ + +dib_t tt_dib = { DVA_TT, tt_disp }; + +UNIT tt_unit[] = { + { UDATA (&tti_svc, TT_MODE_UC, 0), 0 }, + { UDATA (&tto_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT } + }; + +REG tt_reg[] = { + { HRDATA (CMD, tt_cmd, 9) }, + { DRDATA (KPOS, tt_unit[TTI].pos, T_ADDR_W), PV_LEFT }, + { DRDATA (KTPS, tti_tps, 8), REG_HRO }, + { DRDATA (TPOS, tt_unit[TTO].pos, T_ADDR_W), PV_LEFT }, + { DRDATA (TTIME, tt_unit[TTO].wait, 24), REG_NZ + PV_LEFT }, + { HRDATA (PANEL, tti_panel, 8) }, + { HRDATA (DEVNO, tt_dib.dva, 12), REG_HRO }, + { NULL } + }; + +MTAB tt_mod[] = { + { TT_MODE, TT_MODE_UC, "UC", "UC", &tt_set_mode }, + { TT_MODE, TT_MODE_7P, "7p", "7P", &tt_set_mode }, + { MTAB_XTD|MTAB_VDV|MTAB_NMO, RTC_TTI, "POLL", "POLL", + &rtc_set_tps, &rtc_show_tps, (void *) &tti_tps }, + { MTAB_XTD|MTAB_VDV, 0, "CHAN", "CHAN", + &io_set_dvc, &io_show_dvc, NULL }, + { MTAB_XTD|MTAB_VDV, 0, "DVA", "DVA", + &io_set_dva, &io_show_dva, NULL }, + { MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "CSTATE", NULL, + NULL, &io_show_cst, NULL }, + { 0 } + }; + +DEVICE tt_dev = { + "TT", tt_unit, tt_reg, tt_mod, + 2, 10, 31, 1, 16, 8, + NULL, NULL, &tt_reset, + NULL, NULL, NULL, + &tt_dib, 0 + }; + +/* Terminal: IO dispatch routine */ + +uint32 tt_disp (uint32 op, uint32 dva, uint32 *dvst) +{ +switch (op) { /* case on op */ + + case OP_SIO: /* start I/O */ + *dvst = tt_tio_status (); /* get status */ + if ((*dvst & DVS_DST) == 0) { /* idle? */ + tt_cmd = TTS_INIT; /* start dev thread */ + sim_activate (&tt_unit[TTO], chan_ctl_time); + } + break; + + case OP_TIO: /* test status */ + *dvst = tt_tio_status (); /* return status */ + break; + + case OP_HIO: /* halt I/O */ + chan_clr_chi (tt_dib.dva); /* clr int*/ + *dvst = tt_tio_status (); /* get status */ + if ((*dvst & DVS_DST) != 0) { /* busy? */ + sim_cancel (&tt_unit[TTO]); /* stop dev thread */ + tt_cmd = TTS_IDLE; + chan_uen (tt_dib.dva); /* uend */ + } + break; + + case OP_AIO: /* acknowledge int */ + chan_clr_chi (tt_dib.dva); /* clr int*/ + case OP_TDV: /* test status */ + *dvst = 0; /* no status */ + break; + + default: + *dvst = 0; + return SCPE_IERR; + } + +return 0; +} + +/* Timed input service routine - runs continuously + Only accepts input in TTS_READx state */ + +t_stat tti_svc (UNIT *uptr) +{ +int32 c, ebcdic; +uint32 st; + +if ((c = sim_poll_kbd ()) < SCPE_KFLAG) /* no char or err? */ + return c; +if (c & SCPE_BREAK) { /* break? */ + if (tt_cmd == TTS_WRITE) { /* during write? */ + tt_cmd = TTS_IDLE; + sim_cancel (&tt_unit[TTO]); /* cancel write */ + chan_uen (tt_dib.dva); /* uend */ + } + return SCPE_OK; + } +c = c & 0x7F; +if (c == tti_panel) /* panel interrupt? */ + return io_set_pint (); +uptr->pos = uptr->pos + 1; /* incr count */ +if (c == '\r') /* map CR to NL */ + c = '\n'; +if (c == 0x7F) /* map ^H back */ + c = 0x08; +c = sim_tt_inpcvt (c, TT_GET_MODE (uptr->flags)); /* input conversion */ +ebcdic = ascii_to_ebcdic[c]; /* then to EBCDIC */ +tto_echo (c); /* echo character */ +if ((tt_cmd & 0x7F) == TTS_READ) { /* waiting for input? */ + st = chan_WrMemB (tt_dib.dva, ebcdic); /* write to memory */ + if (CHS_IFERR (st)) /* channel error? */ + return tt_chan_err (st); + if ((st == CHS_ZBC) || (ebcdic == E_EOM) || /* channel end? */ + ((tt_cmd == TTS_READS) && ((ebcdic == E_HT) || (ebcdic == E_NL)))) { + tt_cmd = TTS_END; /* new state */ + sim_activate (&tt_unit[TTO], chan_ctl_time); /* start dev thread */ + } + } +return SCPE_OK; +} + +/* Output service routine - also acts as overall device thread + Because of possible retry, channel status and converted character + must be preserved across calls. */ + +t_stat tto_svc (UNIT *uptr) +{ +int32 c, cmd; +uint32 st; + +switch (tt_cmd) { /* case on state */ + + case TTS_INIT: /* I/O init */ + st = chan_get_cmd (tt_dib.dva, &cmd); /* get command */ + if (CHS_IFERR (st)) /* channel error? */ + return tt_chan_err (st); + if ((cmd == TTS_WRITE) || /* valid command? */ + ((cmd & 0x7F) == TTS_READ)) + tt_cmd = cmd; /* next state */ + else tt_cmd = TTS_END; /* no, end state */ + sim_activate (uptr, chan_ctl_time); /* continue thread */ + break; + + case TTS_WRITE: /* char output */ + st = chan_RdMemB (tt_dib.dva, &c); /* get char */ + if (CHS_IFERR (st)) /* channel error? */ + return tt_chan_err (st); + c = ebcdic_to_ascii[c & 0xFF]; /* convert to ASCII */ + tto_echo (c); /* echo character */ + sim_activate (uptr, uptr->wait); /* continue thread */ + if (st == CHS_ZBC) /* st = zbc? */ + tt_cmd = TTS_END; /* next is end */ + else tt_cmd = TTS_WRITE; /* next is write */ + break; + + case TTS_END: /* command done */ + st = chan_end (tt_dib.dva); /* set channel end */ + if (CHS_IFERR (st)) /* channel error? */ + return tt_chan_err (st); + if (st == CHS_CCH) { /* command chain? */ + tt_cmd = TTS_INIT; /* restart thread */ + sim_activate (uptr, chan_ctl_time); + } + else tt_cmd = TTS_IDLE; /* all done */ + break; + } + +return SCPE_OK; +} + +/* Actual tty output routines; simulates horizontal tabs */ + +void tto_echo (int32 c) +{ +uint32 cnt; + +cnt = 1; +if (c == '\r') + tto_pos = 0; +else if (c == '\n') { + tto_pos = 0; + sim_putchar ('\r'); + tt_unit[TTO].pos = tt_unit[TTO].pos + 1; + } +else if (c == '\t') { + c = ' '; + cnt = 8 - (tto_pos % 8); + } +else c = sim_tt_outcvt (c, TT_GET_MODE (tt_unit[TTO].flags)); +if (c >= 0) { + while (cnt-- > 0) { + sim_putchar (c); + tto_pos++; + tt_unit[TTO].pos = tt_unit[TTO].pos + 1; + } + } +return; +} + +/* TTY status routine */ + +uint32 tt_tio_status (void) +{ +if (tt_cmd == TTS_IDLE) + return DVS_AUTO; +return (CC2 << DVT_V_CC) | DVS_DBUSY | DVS_CBUSY | DVS_AUTO; +} + +/* Channel error */ + +t_stat tt_chan_err (uint32 st) +{ +tt_cmd = TTS_IDLE; +sim_cancel (&tt_unit[TTO]); /* stop dev thread */ +chan_uen (tt_dib.dva); /* uend */ +if (st < CHS_ERR) + return st; +return SCPE_OK; +} + +/* Reset routine */ + +t_stat tt_reset (DEVICE *dptr) +{ +rtc_register (RTC_TTI, tti_tps, &tt_unit[TTI]); /* register timer */ +sim_cancel (&tt_unit[TTO]); /* stop dev thread */ +tt_cmd = TTS_IDLE; /* idle */ +chan_reset_dev (tt_dib.dva); /* clr int, active */ +tto_pos = 0; +return SCPE_OK; +} + +/* Make mode flags uniform */ + +t_stat tt_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +tt_unit[TTO].flags = (tt_unit[TTO].flags & ~TT_MODE) | val; +if (val == TT_MODE_7P) + val = TT_MODE_7B; +tt_unit[TTI].flags = (tt_unit[TTI].flags & ~TT_MODE) | val; +return SCPE_OK; +} diff --git a/sim_console.c b/sim_console.c index 16b2acb0..fedc21ee 100644 --- a/sim_console.c +++ b/sim_console.c @@ -1,6 +1,6 @@ /* sim_console.c: simulator console I/O library - Copyright (c) 1993-2014, Robert M Supnik + Copyright (c) 1993-2015, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -23,6 +23,8 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 31-Mar-15 RMS Backported parity feature from GitHub master + 10-Nov-14 JDB Added -N option to SET CONSOLE LOG and SET CONSOLE DEBUG 02-Jan-14 RMS Added tab stop routines 18-Mar-12 RMS Removed unused reference to sim_switches (Dave Bryan) 20-Jan-11 MP Added support for BREAK key on Windows @@ -45,7 +47,7 @@ Added MacOS sleep (Peter Schorn) 14-Jul-02 RMS Added Windows priority control (Mark Pizzolato) 20-May-02 RMS Added Windows VT support (Fischer Franz) - 01-Feb-02 RMS Added VAX fix from Robert Alan Byer + 01-Feb-02 RMS Added VAX fix (Robert Alan Byer) 19-Sep-01 RMS More MacOS changes 31-Aug-01 RMS Changed int64 to t_int64 for Windoze 20-Jul-01 RMS Added MacOS support (Louis Chretien, Peter Schorn, Ben Supnik) @@ -105,11 +107,6 @@ int32 sim_del_char = 0177; TMLN sim_con_ldsc = { 0 }; /* console line descr */ TMXR sim_con_tmxr = { 1, 0, 0, &sim_con_ldsc }; /* console line mux */ -extern volatile int32 stop_cpu; -extern int32 sim_quiet, sim_deb_close; -extern FILE *sim_log, *sim_deb; -extern DEVICE *sim_devices[]; - /* Set/show data structures */ static CTAB set_con_tab[] = { @@ -163,10 +160,10 @@ if ((cptr == NULL) || (*cptr == 0)) return SCPE_2FARG; while (*cptr != 0) { /* do all mods */ cptr = get_glyph_nc (cptr, gbuf, ','); /* get modifier */ - if (cvptr = strchr (gbuf, '=')) /* = value? */ + if ((cvptr = strchr (gbuf, '='))) /* = value? */ *cvptr++ = 0; get_glyph (gbuf, gbuf, 0); /* modifier to UC */ - if (ctptr = find_ctab (set_con_tab, gbuf)) { /* match? */ + if ((ctptr = find_ctab (set_con_tab, gbuf))) { /* match? */ r = ctptr->action (ctptr->arg, cvptr); /* do the rest */ if (r != SCPE_OK) return r; @@ -191,7 +188,7 @@ if (*cptr == 0) { /* show all */ } while (*cptr != 0) { cptr = get_glyph (cptr, gbuf, ','); /* get modifier */ - if (shptr = find_shtab (show_con_tab, gbuf)) + if ((shptr = find_shtab (show_con_tab, gbuf))) shptr->action (st, dptr, uptr, shptr->arg, cptr); else return SCPE_NOPARAM; } @@ -269,8 +266,12 @@ if ((cptr == NULL) || (*cptr == 0)) /* need arg */ cptr = get_glyph_nc (cptr, gbuf, 0); /* get file name */ if (*cptr != 0) /* now eol? */ return SCPE_2MARG; -sim_set_logoff (0, NULL); /* close cur log */ -sim_log = sim_fopen (gbuf, "a"); /* open log */ + +if (sim_switches & SWMASK ('N')) /* if a new log file is requested */ + sim_log = sim_fopen (gbuf, "w"); /* then open an empty file for writing */ +else /* otherwise */ + sim_log = sim_fopen (gbuf, "a"); /* open an existing file for appending */ + if (sim_log == NULL) /* error? */ return SCPE_OPENERR; if (!sim_quiet) @@ -330,10 +331,14 @@ else if (strcmp (gbuf, "STDERR") == 0) /* debug to stderr? */ sim_deb = stderr; else { cptr = get_glyph_nc (cptr, gbuf, 0); /* reparse */ - sim_deb = sim_fopen (gbuf, "a"); /* open debug */ + + if (sim_switches & SWMASK ('N')) /* if a new log file is requested */ + sim_deb = sim_fopen (gbuf, "w"); /* then open an empty file for writing */ + else /* otherwise */ + sim_deb = sim_fopen (gbuf, "a"); /* open an existing file for appending */ + if (sim_deb == NULL) /* error? */ return SCPE_OPENERR; - sim_deb_close = 1; /* need close */ } if (!sim_quiet) printf ("Debug output to \"%s\"\n", gbuf); @@ -348,15 +353,13 @@ t_stat sim_set_deboff (int32 flag, char *cptr) { if (cptr && (*cptr != 0)) /* now eol? */ return SCPE_2MARG; -if (sim_deb == NULL) /* no log? */ +if (sim_deb == NULL) /* no debug? */ return SCPE_OK; if (!sim_quiet) printf ("Debug output disabled\n"); if (sim_log) fprintf (sim_log, "Debug output disabled\n"); -if (sim_deb_close) /* close if needed */ - fclose (sim_deb); -sim_deb_close = 0; +fclose (sim_deb); sim_deb = NULL; return SCPE_OK; } @@ -484,7 +487,8 @@ t_stat sim_putchar_s (int32 c) { t_stat r; -if (sim_log) fputc (c, sim_log); /* log file? */ +if (sim_log) /* log file? */ + fputc (c, sim_log); if (sim_con_tmxr.master == 0) /* not Telnet? */ return sim_os_putchar (c); /* in-window version */ if (sim_con_ldsc.conn == 0) /* no Telnet conn? */ @@ -503,6 +507,10 @@ int32 sim_tt_inpcvt (int32 c, uint32 mode) uint32 md = mode & TTUF_M_MODE; if (md != TTUF_MODE_8B) { + uint32 par_bit = 0; + uint32 par_mode = (mode >> TTUF_W_MODE) & TTUF_M_PAR; + static int32 nibble_even_parity = 0x699600; /* bit array indicating the even parity for each index (offset by 8) */ + c = c & 0177; if (md == TTUF_MODE_UC) { if (islower (c)) @@ -510,6 +518,17 @@ if (md != TTUF_MODE_8B) { if (mode & TTUF_KSR) c = c | 0200; } + switch (par_mode) { + case TTUF_PAR_EVEN: + c |= (((nibble_even_parity >> ((c & 0xF) + 1)) ^ (nibble_even_parity >> (((c >> 4) & 0xF) + 1))) & 0x80); + break; + case TTUF_PAR_ODD: + c |= ((~((nibble_even_parity >> ((c & 0xF) + 1)) ^ (nibble_even_parity >> (((c >> 4) & 0xF) + 1)))) & 0x80); + break; + case TTUF_PAR_MARK: + c = c | 0x80; + break; + } } else c = c & 0377; return c; @@ -561,7 +580,7 @@ for (i = 0; i < val; i++) temptabs[i] = 0; do { cptr = get_glyph (cptr, gbuf, ';'); - d = get_uint (gbuf, 10, val, &r); + d = (int32) get_uint (gbuf, 10, val, &r); if ((r != SCPE_OK) || (d == 0)) { free (temptabs); return SCPE_ARG; @@ -725,6 +744,13 @@ static HANDLE std_input; static HANDLE std_output; static DWORD saved_mode; +/* Note: This routine catches all the potential events which some aspect + of the windows system can generate. The CTRL_C_EVENT won't be + generated by a user typing in a console session since that + session is in RAW mode. In general, Ctrl-C on a simulator's + console terminal is a useful character to be passed to the + simulator. This code does nothing to disable or affect that. */ + static BOOL WINAPI ControlHandler(DWORD dwCtrlType) { diff --git a/sim_console.h b/sim_console.h index c395a697..eec11408 100644 --- a/sim_console.h +++ b/sim_console.h @@ -1,6 +1,6 @@ /* sim_console.h: simulator console I/O library headers - Copyright (c) 1993-2014, Robert M Supnik + Copyright (c) 1993-2015, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -23,6 +23,7 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 14-Dec-14 JDB [4.0] Added sim_*_char externals 02-Jan-14 RMS Added tab stop routines 22-Jun-06 RMS Implemented SET/SHOW PCHAR 22-Nov-05 RMS Added central input/output conversion support @@ -31,8 +32,8 @@ 02-Jan-04 RMS Removed timer routines, added Telnet console routines */ -#ifndef _SIM_CONSOLE_H_ -#define _SIM_CONSOLE_H_ 0 +#ifndef SIM_CONSOLE_H_ +#define SIM_CONSOLE_H_ 0 #define TTUF_V_MODE (UNIT_V_UF + 0) #define TTUF_W_MODE 2 @@ -40,16 +41,31 @@ #define TTUF_MODE_8B 1 #define TTUF_MODE_UC 2 #define TTUF_MODE_7P 3 -#define TTUF_KSR (1u << TTUF_W_MODE) #define TTUF_M_MODE ((1u << TTUF_W_MODE) - 1) -#define TTUF_V_UF (TTUF_V_MODE + TTUF_W_MODE) +#define TTUF_V_PAR (TTUF_V_MODE + TTUF_W_MODE) +#define TTUF_W_PAR 2 +#define TTUF_PAR_SPACE 0 +#define TTUF_PAR_MARK 1 +#define TTUF_PAR_EVEN 2 +#define TTUF_PAR_ODD 3 +#define TTUF_M_PAR ((1u << TTUF_W_PAR) - 1) +#define TTUF_KSR (1u << (TTUF_W_MODE + TTUF_W_PAR)) +#define TTUF_V_UF (TTUF_V_MODE + TTUF_W_MODE + TTUF_W_PAR) #define TT_MODE (TTUF_M_MODE << TTUF_V_MODE) #define TT_MODE_7B (TTUF_MODE_7B << TTUF_V_MODE) #define TT_MODE_8B (TTUF_MODE_8B << TTUF_V_MODE) #define TT_MODE_UC (TTUF_MODE_UC << TTUF_V_MODE) #define TT_MODE_7P (TTUF_MODE_7P << TTUF_V_MODE) #define TT_MODE_KSR (TT_MODE_UC) -#define TT_GET_MODE(x) (((x) >> TTUF_V_MODE) & TTUF_M_MODE) +/* 7 bit modes allow for an 8th bit parity mode */ +#define TT_PAR (TTUF_M_PAR << TTUF_V_PAR) +#define TT_PAR_SPACE (TTUF_PAR_SPACE << TTUF_V_PAR) +#define TT_PAR_MARK (TTUF_PAR_MARK << TTUF_V_PAR) +#define TT_PAR_EVEN (TTUF_PAR_EVEN << TTUF_V_PAR) +#define TT_PAR_ODD (TTUF_PAR_ODD << TTUF_V_PAR) +/* TT_GET_MODE returns both the TT_MODE and TT_PAR fields + since they together are passed into sim_tt_inpcvt() */ +#define TT_GET_MODE(x) (((x) >> TTUF_V_MODE) & (TTUF_M_MODE | (TTUF_M_PAR << TTUF_W_MODE))) t_stat sim_set_console (int32 flag, char *cptr); t_stat sim_set_kmap (int32 flag, char *cptr); @@ -81,4 +97,9 @@ int32 sim_tt_outcvt (int32 c, uint32 mode); t_stat sim_tt_settabs (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat sim_tt_showtabs (FILE *st, UNIT *uptr, int32 val, void *desc); +extern int32 sim_int_char; /* interrupt character */ +extern int32 sim_brk_char; /* break character */ +extern int32 sim_tt_pchar; /* printable character mask */ +extern int32 sim_del_char; /* delete character */ + #endif diff --git a/sim_defs.h b/sim_defs.h index 598a5068..5ce87238 100644 --- a/sim_defs.h +++ b/sim_defs.h @@ -1,6 +1,6 @@ /* sim_defs.h: simulator definitions - Copyright (c) 1993-2008, Robert M Supnik + Copyright (c) 1993-2014, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -23,6 +23,9 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 24-Dec-14 JDB [4.0] Added T_ADDR_FMT + 14-Dec-14 JDB [4.0] Extended sim_device for compatibility + 04-Nov-14 JDB [4.0] Added UNIT.dynflags field for tape density support 21-Jul-08 RMS Removed inlining support 28-May-08 RMS Added inlining support 28-Jun-07 RMS Added IA64 VMS support (from Norm Lastovica) @@ -157,11 +160,19 @@ typedef uint32 t_value; #if defined (USE_INT64) && defined (USE_ADDR64) /* 64b address */ typedef t_uint64 t_addr; #define T_ADDR_W 64 +#define T_ADDR_FMT LL_FMT #else /* 32b address */ typedef uint32 t_addr; #define T_ADDR_W 32 +#define T_ADDR_FMT "" #endif /* end 64b address */ +#if defined (_WIN32) +#define LL_FMT "I64" +#else +#define LL_FMT "ll" +#endif + /* Stubs for inlining */ #define SIM_INLINE @@ -300,6 +311,10 @@ struct sim_device { t_stat (*msize)(struct sim_unit *up, int32 v, char *cp, void *dp); /* mem size routine */ char *lname; /* logical name */ + void *help; /* (4.0 dummy) help routine */ + void *attach_help; /* (4.0 dummy) help attach routine*/ + void *help_context; /* (4.0 dummy) help context */ + void *description; /* (4.0 dummy) description */ }; /* Device flags */ @@ -323,6 +338,12 @@ struct sim_device { #define DEV_RAW (1 << DEV_V_RAW) #define DEV_RAWONLY (1 << DEV_V_RAWONLY) +#define DEV_DISK 0 /* (4.0 dummy) */ +#define DEV_TAPE 0 /* (4.0 dummy) */ +#define DEV_MUX (DEV_NET) /* (4.0 dummy) */ +#define DEV_DISPLAY 0 /* (4.0 dummy) */ +#define DEV_ETHER 0 /* (4.0 dummy) */ + #define DEV_UFMASK_31 (((1u << DEV_V_RSV) - 1) & ~((1u << DEV_V_UF_31) - 1)) #define DEV_UFMASK (((1u << DEV_V_RSV) - 1) & ~((1u << DEV_V_UF) - 1)) #define DEV_RFLAGS (DEV_UFMASK|DEV_DIS) /* restored flags */ @@ -345,6 +366,7 @@ struct sim_unit { uint32 hwmark; /* high water mark */ int32 time; /* time out */ uint32 flags; /* flags */ + uint32 dynflags; /* dynamic flags */ t_addr capac; /* capacity */ t_addr pos; /* file position */ int32 buf; /* buffer */ @@ -353,6 +375,8 @@ struct sim_unit { int32 u4; /* device specific */ int32 u5; /* device specific */ int32 u6; /* device specific */ + void *up7; /* (4.0 dummy) */ + void *up8; /* (4.0 dummy) */ }; /* Unit flags */ @@ -381,6 +405,13 @@ struct sim_unit { #define UNIT_UFMASK (((1u << UNIT_V_RSV) - 1) & ~((1u << UNIT_V_UF) - 1)) #define UNIT_RFLAGS (UNIT_UFMASK|UNIT_DIS) /* restored flags */ +/* Unit dynamic flags (dynflags) (from 4.0) */ + +/* These flags are only set dynamically */ + +#define UNIT_V_DF_TAPE 3 /* Bit offset for Tape Density reservation */ +#define UNIT_W_DF_TAPE 3 /* Bits Reserved for Tape Density */ + /* Register data structure */ struct sim_reg { @@ -445,6 +476,7 @@ struct sim_mtab { void *desc; /* value descriptor */ /* REG * if MTAB_VAL */ /* int * if not */ + void *help; /* (4.0 dummy) */ }; #define MTAB_XTD (1u << UNIT_V_RSV) /* ext entry flag */ @@ -487,7 +519,7 @@ struct sim_debtab { /* The following macros define structure contents */ -#define UDATA(act,fl,cap) NULL,act,NULL,NULL,NULL,0,0,(fl),(cap),0,0 +#define UDATA(act,fl,cap) NULL,act,NULL,NULL,NULL,0,0,(fl),0,(cap),0,0 #if defined (__STDC__) || defined (_WIN32) #define ORDATA(nm,loc,wd) #nm, &(loc), 8, (wd), 0, 1 @@ -529,4 +561,44 @@ typedef struct sim_debtab DEBTAB; #include "sim_timer.h" #include "sim_fio.h" +/* V4 compatibility definitions */ + +#if defined (__STDC__) || defined (_WIN32) +#define ORDATAD(nm,loc,wd,desc) #nm, &(loc), 8, (wd), 0, 1 +#define DRDATAD(nm,loc,wd,desc) #nm, &(loc), 10, (wd), 0, 1 +#define HRDATAD(nm,loc,wd,desc) #nm, &(loc), 16, (wd), 0, 1 +#define FLDATAD(nm,loc,pos,desc) #nm, &(loc), 2, 1, (pos), 1 +#define GRDATAD(nm,loc,rdx,wd,pos,desc) #nm, &(loc), (rdx), (wd), (pos), 1 +#define BRDATAD(nm,loc,rdx,wd,dep,desc) #nm, (loc), (rdx), (wd), 0, (dep) +#define URDATAD(nm,loc,rdx,wd,off,dep,fl,desc) \ + #nm, &(loc), (rdx), (wd), (off), (dep), ((fl) | REG_UNIT) +#define ORDATADF(nm,loc,wd,desc) #nm, &(loc), 8, (wd), 0, 1 +#define DRDATADF(nm,loc,wd,desc) #nm, &(loc), 10, (wd), 0, 1 +#define HRDATADF(nm,loc,wd,desc) #nm, &(loc), 16, (wd), 0, 1 +#define FLDATADF(nm,loc,pos,desc) #nm, &(loc), 2, 1, (pos), 1 +#define GRDATADF(nm,loc,rdx,wd,pos,desc) #nm, &(loc), (rdx), (wd), (pos), 1 +#define BRDATADF(nm,loc,rdx,wd,dep,desc) #nm, (loc), (rdx), (wd), 0, (dep) +#define URDATADF(nm,loc,rdx,wd,off,dep,fl,desc) \ + #nm, &(loc), (rdx), (wd), (off), (dep), ((fl) | REG_UNIT) +#else +#define ORDATAD(nm,loc,wd) "nm", &(loc), 8, (wd), 0, 1 +#define DRDATAD(nm,loc,wd) "nm", &(loc), 10, (wd), 0, 1 +#define HRDATAD(nm,loc,wd) "nm", &(loc), 16, (wd), 0, 1 +#define FLDATAD(nm,loc,pos) "nm", &(loc), 2, 1, (pos), 1 +#define GRDATAD(nm,loc,rdx,wd,pos) "nm", &(loc), (rdx), (wd), (pos), 1 +#define BRDATAD(nm,loc,rdx,wd,dep) "nm", (loc), (rdx), (wd), 0, (dep) +#define URDATAD(nm,loc,rdx,wd,off,dep,fl) \ + "nm", &(loc), (rdx), (wd), (off), (dep), ((fl) | REG_UNIT) +#define ORDATADF(nm,loc,wd) "nm", &(loc), 8, (wd), 0, 1 +#define DRDATADF(nm,loc,wd) "nm", &(loc), 10, (wd), 0, 1 +#define HRDATADF(nm,loc,wd) "nm", &(loc), 16, (wd), 0, 1 +#define FLDATADF(nm,loc,pos) "nm", &(loc), 2, 1, (pos), 1 +#define GRDATADF(nm,loc,rdx,wd,pos) "nm", &(loc), (rdx), (wd), (pos), 1 +#define BRDATADF(nm,loc,rdx,wd,dep) "nm", (loc), (rdx), (wd), 0, (dep) +#define URDATADF(nm,loc,rdx,wd,off,dep,fl) \ + "nm", &(loc), (rdx), (wd), (off), (dep), ((fl) | REG_UNIT) +#endif + +#define INT64_C(x) (x) + #endif diff --git a/sim_ether.c b/sim_ether.c index c8278cfc..31a715d2 100644 --- a/sim_ether.c +++ b/sim_ether.c @@ -1130,11 +1130,11 @@ int pcap_sendpacket(pcap_t* handle, const u_char* msg, int len) #if defined(_WIN32) || defined(__CYGWIN__) /* extracted from WinPcap's Packet32.h */ struct _PACKET_OID_DATA { - uint32 Oid; ///< OID code. See the Microsoft DDK documentation or the file ntddndis.h - ///< for a complete list of valid codes. - uint32 Length; ///< Length of the data field - uint8 Data[1]; ///< variable-lenght field that contains the information passed to or received - ///< from the adapter. + uint32 Oid; ///< OID code. See the Microsoft DDK documentation or the file ntddndis.h + ///< for a complete list of valid codes. + uint32 Length; ///< Length of the data field + uint8 Data[1]; ///< variable-lenght field that contains the information passed to or received + ///< from the adapter. }; typedef struct _PACKET_OID_DATA PACKET_OID_DATA, *PPACKET_OID_DATA; typedef void **LPADAPTER; diff --git a/sim_fio.c b/sim_fio.c index 70b2800a..23989705 100644 --- a/sim_fio.c +++ b/sim_fio.c @@ -1,6 +1,6 @@ /* sim_fio.c: simulator file I/O library - Copyright (c) 1993-2008, Robert M Supnik + Copyright (c) 1993-2015, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -23,6 +23,7 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 02-Apr-15 RMS Backported from GitHub master 28-Jun-07 RMS Added VMS IA64 support (from Norm Lastovica) 10-Jul-06 RMS Fixed linux conditionalization (from Chaskiel Grundman) 15-May-06 RMS Added sim_fsize_name @@ -35,22 +36,27 @@ This library includes: - sim_finit - initialize package - sim_fopen - open file - sim_fread - endian independent read (formerly fxread) - sim_write - endian independent write (formerly fxwrite) - sim_fseek - extended (>32b) seek (formerly fseek_ext) - sim_fsize - get file size + sim_finit initialize package + sim_fopen open file + sim_fread endian independent read (formerly fxread) + sim_write endian independent write (formerly fxwrite) + sim_fseek (now a macro using fseeko) + sim_fseeko extended seek (>32b if available) + sim_ftell extended tell (>32b if available) + sim_fsize (now a macro using sim_fsize_ex) + sim_fsize_name (now a macro using sim_fsize_ex) + sim_fsize_ex get file size as a t_offset + sim_fsize_name get file size as a t_offset of named file - sim_fopen and sim_fseek are OS-dependent. The other routines are not. - sim_fsize is always a 32b routine (it is used only with small capacity random - access devices like fixed head disks and DECtapes). + sim_fopen, sim_fseeko, sim_ftell are OS-dependent. The other routines are not. */ #include "sim_defs.h" static unsigned char sim_flip[FLIP_SIZE]; -int32 sim_end = 1; /* 1 = little */ +t_bool sim_end; /* TRUE = little endian, FALSE = big endian */ +t_bool sim_taddr_64; /* t_addr is > 32b and large file support available */ +t_bool sim_toffset_64; /* large file (>2GB) support available */ /* OS-independent, endian independent binary I/O package @@ -74,7 +80,9 @@ int32 sim_finit (void) union {int32 i; char c[sizeof (int32)]; } end_test; end_test.i = 1; /* test endian-ness */ -sim_end = end_test.c[0]; +sim_end = (end_test.c[0] != 0); +sim_toffset_64 = (sizeof(t_offset) > sizeof(int32)); /* large file (>2GB) support */ +sim_taddr_64 = sim_toffset_64 && (sizeof(t_addr) > sizeof(int32)); return sim_end; } @@ -134,113 +142,70 @@ return total; /* Get file size */ -uint32 sim_fsize_name (char *fname) +t_offset sim_fsize_ex (FILE *fp) +{ +t_offset pos, sz; + +if (fp == NULL) + return 0; +pos = sim_ftell (fp); +sim_fseek (fp, 0, SEEK_END); +sz = sim_ftell (fp); +sim_fseeko (fp, pos, SEEK_SET); +return sz; +} + +t_offset sim_fsize_name_ex (char *fname) { FILE *fp; -uint32 sz; +t_offset sz; if ((fp = sim_fopen (fname, "rb")) == NULL) return 0; -sz = sim_fsize (fp); +sz = sim_fsize_ex (fp); fclose (fp); return sz; } -uint32 sim_fsize (FILE *fp) -{ -uint32 pos, sz; - -if (fp == NULL) - return 0; -pos = ftell (fp); -fseek (fp, 0, SEEK_END); -sz = ftell (fp); -fseek (fp, pos, SEEK_SET); -return sz; -} /* OS-dependent routines */ -/* Optimized file open */ +/* Optimized file open + + VMS - specify extra goodies + Linux, HP/UX, AIX - use a 64b open if necessary + Others - ordinary open works for 32b or 64b */ FILE *sim_fopen (const char *file, const char *mode) { #if defined (VMS) return fopen (file, mode, "ALQ=32", "DEQ=4096", "MBF=6", "MBC=127", "FOP=cbt,tef", "ROP=rah,wbh", "CTX=stm"); -#elif defined (USE_INT64) && defined (USE_ADDR64) && defined (__linux) +#elif (defined (__linux) || defined (__linux__) || defined (__hpux) || defined (_AIX)) && !defined (DONT_DO_LARGEFILE) return fopen64 (file, mode); #else return fopen (file, mode); #endif } -/* Long seek */ +/* Now define sim_fseeko and sim_ftell */ -#if defined (USE_INT64) && defined (USE_ADDR64) +#if !defined (DONT_DO_LARGEFILE) -/* 64b VMS */ +/* 64b VMS or Solaris */ -#if (defined (__ALPHA) || defined (__ia64)) && defined (VMS) /* 64b VMS */ -#define _SIM_IO_FSEEK_EXT_ 1 +#if ((defined (__ALPHA) || defined (__ia64)) && defined (VMS) && (__DECC_VER >= 60590001)) || \ + ((defined(__sun) || defined(__sun__)) && defined(_LARGEFILE_SOURCE)) +#define S_SIM_IO_FSEEK_EXT_ 1 -static t_int64 fpos_t_to_int64 (fpos_t *pos) +int sim_fseeko (FILE *st, t_offset offset, int whence) { -unsigned short *w = (unsigned short *) pos; /* endian dep! */ -t_int64 result; - -result = w[1]; -result <<= 16; -result += w[0]; -result <<= 9; -result += w[2]; -return result; +return fseeko (st, (off_t)offset, whence); } -static void int64_to_fpos_t (t_int64 ipos, fpos_t *pos, size_t mbc) +t_offset sim_ftell (FILE *st) { -unsigned short *w = (unsigned short *) pos; -int bufsize = mbc << 9; - -w[3] = 0; -w[2] = (unsigned short) (ipos % bufsize); -ipos -= w[2]; -ipos >>= 9; -w[0] = (unsigned short) ipos; -ipos >>= 16; -w[1] = (unsigned short) ipos; -if ((w[2] == 0) && (w[0] || w[1])) { - w[2] = bufsize; - w[0] -= mbc; - } -return; -} - -int sim_fseek (FILE *st, t_addr offset, int whence) -{ -t_addr fileaddr; -fpos_t filepos; - -switch (whence) { - - case SEEK_SET: - fileaddr = offset; - break; - - case SEEK_CUR: - if (fgetpos (st, &filepos)) - return (-1); - fileaddr = fpos_t_to_int64 (&filepos); - fileaddr = fileaddr + offset; - break; - - default: - errno = EINVAL; - return (-1); - } - -int64_to_fpos_t (fileaddr, &filepos, 127); -return fsetpos (st, &filepos); +return (t_offset)(ftello (st)); } #endif @@ -248,30 +213,42 @@ return fsetpos (st, &filepos); /* Alpha UNIX - natively 64b */ #if defined (__ALPHA) && defined (__unix__) /* Alpha UNIX */ -#define _SIM_IO_FSEEK_EXT_ 1 +#define S_SIM_IO_FSEEK_EXT_ 1 -int sim_fseek (FILE *st, t_addr offset, int whence) +int sim_fseeko (FILE *st, t_offset offset, int whence) { return fseek (st, offset, whence); } +t_offset sim_ftell (FILE *st) +{ +return (t_offset)(ftell (st)); +} + #endif /* Windows */ #if defined (_WIN32) -#define _SIM_IO_FSEEK_EXT_ 1 +#define S_SIM_IO_FSEEK_EXT_ 1 +#include -int sim_fseek (FILE *st, t_addr offset, int whence) +int sim_fseeko (FILE *st, t_offset offset, int whence) { fpos_t fileaddr; +struct _stati64 statb; switch (whence) { case SEEK_SET: - fileaddr = offset; + fileaddr = (fpos_t)offset; break; + case SEEK_END: + if (_fstati64 (_fileno (st), &statb)) + return (-1); + fileaddr = statb.st_size + offset; + break; case SEEK_CUR: if (fgetpos (st, &fileaddr)) return (-1); @@ -286,44 +263,62 @@ switch (whence) { return fsetpos (st, &fileaddr); } +t_offset sim_ftell (FILE *st) +{ +fpos_t fileaddr; +if (fgetpos (st, &fileaddr)) + return (-1); +return (t_offset)fileaddr; +} + #endif /* end Windows */ -/* Linux */ +/* Linux, HP/UX, and AIX */ -#if defined (__linux) -#define _SIM_IO_FSEEK_EXT_ 1 +#if defined (__linux) || defined (__linux__) || defined (__hpux) || defined (_AIX) +#define S_SIM_IO_FSEEK_EXT_ 1 -int sim_fseek (FILE *st, t_addr xpos, int origin) +int sim_fseeko (FILE *st, t_offset xpos, int origin) { -return fseeko64 (st, xpos, origin); +return fseeko64 (st, (off64_t)xpos, origin); +} + +t_offset sim_ftell (FILE *st) +{ +return (t_offset)(ftello64 (st)); } #endif /* end Linux with LFS */ -/* Apple OS/X */ +/* Apple OS/X and the BSD family */ -#if defined (__APPLE__) || defined (__FreeBSD__) -#define _SIM_IO_FSEEK_EXT_ 1 +#if defined (__APPLE__) || defined (__FreeBSD__) || defined(__NetBSD__) || defined (__OpenBSD__) +#define S_SIM_IO_FSEEK_EXT_ 1 -int sim_fseek (FILE *st, t_addr xpos, int origin) +int sim_fseeko (FILE *st, t_offset xpos, int origin) { -return fseeko (st, xpos, origin); +return fseeko (st, (off_t)xpos, origin); +} + +t_offset sim_ftell (FILE *st) +{ +return (t_offset)(ftello (st)); } #endif /* end Apple OS/X */ - -#endif /* end 64b seek defs */ +#endif /* !DONT_DO_LARGEFILE */ /* Default: no OS-specific routine has been defined */ -#if !defined (_SIM_IO_FSEEK_EXT_) -#define _SIM_IO_FSEEK_EXT_ 0 - -int sim_fseek (FILE *st, t_addr xpos, int origin) +#if !defined (S_SIM_IO_FSEEK_EXT_) +int sim_fseeko (FILE *st, t_offset xpos, int origin) { -return fseek (st, (int32) xpos, origin); +return fseek (st, (long) xpos, origin); } +t_offset sim_ftell (FILE *st) +{ +return (t_offset)(ftell (st)); +} #endif -uint32 sim_taddr_64 = _SIM_IO_FSEEK_EXT_; diff --git a/sim_fio.h b/sim_fio.h index 264ea971..56a87d19 100644 --- a/sim_fio.h +++ b/sim_fio.h @@ -1,6 +1,6 @@ /* sim_fio.h: simulator file I/O library headers - Copyright (c) 1993-2008, Robert M Supnik + Copyright (c) 1993-2015, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -23,24 +23,54 @@ be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 02-Apr-15 RMS Backported features from GitHub master 15-May-06 RMS Added sim_fsize_name 16-Aug-05 RMS Fixed C++ declaration and cast problems 02-Jan-04 RMS Split out from SCP */ -#ifndef _SIM_FIO_H_ -#define _SIM_FIO_H_ 0 +#ifndef SIM_FIO_H_ +#define SIM_FIO_H_ 0 #define FLIP_SIZE (1 << 16) /* flip buf size */ + +/* Conditionals to decide whether 64b file support is available. Can be overriden + in build by defining DONT_DO_LARGEFILE */ + +#if (defined (__linux) || defined (__linux__) || defined (__hpux) || defined (_AIX) || \ + (defined (VMS) && (defined (__ALPHA) || defined (__ia64)) && (__DECC_VER >= 60590001)) || \ + ((defined(__sun) || defined(__sun__)) && defined(_LARGEFILE_SOURCE)) || \ + defined (_WIN32) || defined (__APPLE__) || \ + defined (__FreeBSD__) || defined(__NetBSD__) || defined (__OpenBSD__)) && !defined (DONT_DO_LARGEFILE) +typedef t_int64 t_offset; +#else +typedef int32 t_offset; +#if !defined (DONT_DO_LARGEFILE) +#define DONT_DO_LARGEFILE 1 +#endif +#endif + +/* Old interfaces redefined as macros to new interfaces */ + #define fxread(a,b,c,d) sim_fread (a, b, c, d) #define fxwrite(a,b,c,d) sim_fwrite (a, b, c, d) +#define sim_fseek(s,o,w) sim_fseeko (s, (t_offset)o, w) +#define sim_fsize(f) (uint32)sim_fsize_ex(f) +#define sim_fsize_name(f) (uint32)sim_fsize_name_ex(f) + +/* Prototypes and globals */ int32 sim_finit (void); FILE *sim_fopen (const char *file, const char *mode); -int sim_fseek (FILE *st, t_addr offset, int whence); +int sim_fseeko (FILE *st, t_offset offset, int whence); size_t sim_fread (void *bptr, size_t size, size_t count, FILE *fptr); size_t sim_fwrite (void *bptr, size_t size, size_t count, FILE *fptr); -uint32 sim_fsize (FILE *fptr); -uint32 sim_fsize_name (char *fname); +t_offset sim_ftell (FILE *st); +t_offset sim_fsize_ex (FILE *fptr); +t_offset sim_fsize_name_ex (char *fname); + +extern t_bool sim_taddr_64; /* t_addr is > 32b and Large File Support available */ +extern t_bool sim_toffset_64; /* Large File (>2GB) support */ +extern t_bool sim_end; /* TRUE = little endian, FALSE = big endian */ #endif diff --git a/sim_rev.h b/sim_rev.h index c0e8a5d3..5a0a47f3 100644 --- a/sim_rev.h +++ b/sim_rev.h @@ -28,15 +28,63 @@ #define _SIM_REV_H_ 0 #define SIM_MAJOR 3 -#define SIM_MINOR 9 +#define SIM_MINOR 10 #define SIM_PATCH 0 #define SIM_DELTA 0 +/* V3.10 revision history + + V3.10 backports an enormous number of modules and features from + the SimH 4.x master branch, as well as some unique new features. + The revision history will be restarted with patch level 1. + +patch date module(s) and fix(es) + + 0 tbd scp.c and supporting libraries + - added sim_printf + - added v4 compatibility macros + + All simulator families + - revised to use sim_printf + + Eclipse/Nova + - fixed bug in Eclipse signed divide + - revised to use sim_printf + + H316 + - numerous fixes from Bob Armstrong + + HP2100 + - latest version from Dave Bryan + + i1401 + - read cards from and print to the console window + + i1620 + - numerous fixes from Tom McBride and Bob Armstrong + + PDP8 + - added multi-segment loader and new breakpoints + from Dave Gesswein + + PDP10 + - numerous fixes from Tim Litt + + PDP11 + - fixes to CR11 + + SDS + - bug fixes from ??? + + VAX + - minor modularization improvements per 4.X +*/ + /* V3.9 revision history patch date module(s) and fix(es) - 1 tbd sim_console.h, sim_console.c: + 1 not released sim_console.h, sim_console.c: - added tab stop routines h316_stddev.c: @@ -46,6 +94,9 @@ patch date module(s) and fix(es) - added symbolic names for IO devices - fixed handling of SMK and OTK + i1401_cpu.c: + - fixed treatment of overflow (Ken Shirriff) + i1401_lp.c: - fixed printer chain selection @@ -57,9 +108,13 @@ patch date module(s) and fix(es) - fixed end of line processing on read (Bob Armstrong) 1620_cpu.c: + - fixed compare flows (Tom McBride) - fixed several bugs in add and compare (Bob Armstrong) - fixed handling of P field in K instruction (Bob Armstrong) + 1620_fp.c: + - revised for simplified add_field + i1620_lp.c: - fixed DN wraparound (Bob Armstrong) - fixed test on VFU 10 (Bob Armstrong) @@ -174,11 +229,16 @@ patch date module(s) and fix(es) - added support for unaligned register space references vax780_defs.h, vaxmod_defs.h: + - removed boot code for TQ (tape boot not supported) - fixed base address for RQB, RQC, RQD + - reverted broken MBZ test for 11/780 vax780_mba.c: - block interrupt if data transfer in progress (Mark Pizzolato) + vax780_sbi.c: + - removed boot table entry for TQ (tape boot not supported) + 0 01-May-2012 scp.c: - added *nix READLINE support (Mark Pizzolato) @@ -352,7 +412,7 @@ patch date module(s) and fix(es) pdp11_io.c: - fixed Qbus interrupts to treat all IO devices (except clock) as BR4 - - fixed order of int_internal (Jordi Guillaumes i Pons) + - fixed order of int_internal (Jordi Guillaumes i Pons) ppd11_rf.c - fixed bug in updating mem addr extension (Peter Schorn) @@ -380,6 +440,7 @@ patch date module(s) and fix(es) pdp11_ts.c: - fixed t_addr printouts for 64b big-endian systems (Mark Pizzolato) + - fixed bug in read forward byte swapped (Mark Pizzolato) pdp11_tu.c: - fixed t_addr printouts for 64b big-endian systems (Mark Pizzolato) diff --git a/sim_sock.h b/sim_sock.h index 5d469519..db23deda 100644 --- a/sim_sock.h +++ b/sim_sock.h @@ -40,8 +40,8 @@ 16-Sep-01 RMS Added Macintosh support from Peter Schorn */ -#ifndef _SIM_SOCK_H_ -#define _SIM_SOCK_H_ 0 +#ifndef SIM_SOCK_H_ +#define SIM_SOCK_H_ 0 #if defined (_WIN32) /* Windows */ #undef INT_PTR /* hack, hack */ diff --git a/sim_tape.c b/sim_tape.c index c3a0c9b2..4db5378e 100644 --- a/sim_tape.c +++ b/sim_tape.c @@ -1,6 +1,6 @@ /* sim_tape.c: simulator tape support library - Copyright (c) 1993-2008, Robert M Supnik + Copyright (c) 1993-2014, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -26,6 +26,13 @@ Ultimately, this will be a place to hide processing of various tape formats, as well as OS-specific direct hardware access. + 15-Dec-14 JDB Changed sim_tape_set_dens to check validity of density change + 04-Nov-14 JDB Restrict sim_tape_set_fmt to unit unattached + 31-Oct-14 JDB Fixed gap skip on reverse read + Fixed write EOM bug (should not update position) + Added set/show density functions, changed sim_tape_wrgap API + Buffered forward/reverse gap skip to improve execution time + 22-Sep-14 JDB Added tape runaway support 08-Jun-08 JDB Fixed signed/unsigned warning in sim_tape_set_fmt 23-Jan-07 JDB Fixed backspace over gap at BOT 22-Jan-07 RMS Fixed bug in P7B format read reclnt rev (found by Rich Cornwell) @@ -63,6 +70,8 @@ sim_tape_show_fmt show tape format sim_tape_set_capac set tape capacity sim_tape_show_capac show tape capacity + sim_tape_set_dens set tape density + sim_tape_show_dens show tape density */ #include "sim_defs.h" @@ -83,6 +92,17 @@ static struct sim_tape_fmt fmts[MTUF_N_FMT] = { { NULL, 0, 0 } }; +static const uint32 bpi [] = { /* tape density table, indexed by MT_DENS constants */ + 0, /* 0 = MT_DENS_NONE -- density not set */ + 200, /* 1 = MT_DENS_200 -- 200 bpi NRZI */ + 556, /* 2 = MT_DENS_556 -- 556 bpi NRZI */ + 800, /* 3 = MT_DENS_800 -- 800 bpi NRZI */ + 1600, /* 4 = MT_DENS_1600 -- 1600 bpi PE */ + 6250 /* 5 = MT_DENS_6250 -- 6250 bpi GCR */ + }; + +#define BPI_COUNT (sizeof (bpi) / sizeof (bpi [0])) /* count of density table entries */ + extern int32 sim_switches; t_stat sim_tape_ioerr (UNIT *uptr); @@ -90,6 +110,7 @@ t_stat sim_tape_wrdata (UNIT *uptr, uint32 dat); uint32 sim_tape_tpc_map (UNIT *uptr, t_addr *map); t_addr sim_tape_tpc_fnd (UNIT *uptr, t_addr *map); + /* Attach tape unit */ t_stat sim_tape_attach (UNIT *uptr, char *cptr) @@ -168,15 +189,73 @@ return SCPE_OK; Outputs: status = operation status - exit condition position - + exit condition tape position + ------------------ ------------------------------------------- unit unattached unchanged read error unchanged, PNU set end of file/medium unchanged, PNU set tape mark updated + tape runaway updated data record updated, sim_fread will read record forward - See notes at "sim_tape_wrgap" regarding erase gap implementation. + This routine is called to set up a record read or spacing in the forward + direction. On return, status is MTSE_OK and the tape is positioned at the + first data byte if a record was encountered, or status is an MTSE error code + giving the reason that the operation did not succeed and the tape position is + as indicated above. + + The ANSI standards for magnetic tape recording (X3.32, X3.39, and X3.54) and + the equivalent ECMA standard (ECMA-62) specify a maximum erase gap length of + 25 feet (7.6 meters). While gaps of any length may be written, gaps longer + than this are non-standard and may indicate that an unrecorded or erased tape + is being read. + + If the tape density has been set via a previous "sim_tape_set_dens" call, + then the length is monitored when skipping over erase gaps. If the length + reaches 25 feet, motion is terminated, and MTSE_RUNAWAY status is returned. + Runaway status is also returned if an end-of-medium marker or the physical + end of file is encountered while spacing over a gap. + + If the density has not been set, then a gap of any length is skipped, and + MTSE_RUNAWAY status is never returned. In effect, erase gaps present in the + tape image file will be transparent to the caller. + + Erase gaps are currently supported only in SIMH (MTUF_F_STD) tape format. + Because gaps may be partially overwritten with data records, gap metadata + must be examined marker-by-marker. To reduce the number of file read calls, + a buffer of metadata elements is used. The buffer size is initially + established at 256 elements but may be set to any size desired. To avoid a + large read for the typical case where an erase gap is not present, the first + read is of a single metadatum marker. If that is a gap marker, then + additional buffered reads are performed. + + See the notes at "sim_tape_wrgap" regarding the erase gap implementation. + + Implementation notes: + + 1. For programming convenience, erase gap processing is performed for both + SIMH standard and E11 tape formats, although the latter will never + contain erase gaps, as the "sim_tape_wrgap" call takes no action for the + E11 format. + + 2. The "feof" call cannot return a non-zero value on the first pass through + the loop, because the "sim_fseek" call resets the internal end-of-file + indicator. Subsequent passes only occur if an erase gap is present, so + a non-zero return indicates an EOF was seen while reading through a gap. + + 3. The dynamic start/stop test of the HP 3000 magnetic tape diagnostic + heavily exercises the erase gap scanning code. Sample test execution + times for various buffer sizes on a 2 GHz host platform are: + + buffer size execution time + (elements) (CPU seconds) + ----------- -------------- + 1 7200 + 32 783 + 128 237 + 256 203 + 512 186 + 1024 171 */ t_stat sim_tape_rdlntf (UNIT *uptr, t_mtrlnt *bc) @@ -186,38 +265,106 @@ t_bool all_eof; uint32 f = MT_GET_FMT (uptr); t_mtrlnt sbc; t_tpclnt tpcbc; +t_mtrlnt buffer [256]; /* local tape buffer */ +uint32 bufcntr, bufcap; /* buffer counter and capacity */ +int32 runaway_counter, sizeof_gap; /* bytes remaining before runaway and bytes per gap */ -MT_CLR_PNU (uptr); -if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */ - return MTSE_UNATT; -sim_fseek (uptr->fileref, uptr->pos, SEEK_SET); /* set tape pos */ -switch (f) { /* switch on fmt */ +MT_CLR_PNU (uptr); /* clear the position-not-updated flag */ - case MTUF_F_STD: case MTUF_F_E11: - do { - sim_fread (bc, sizeof (t_mtrlnt), 1, uptr->fileref); /* read rec lnt */ - sbc = MTR_L (*bc); /* save rec lnt */ - if (ferror (uptr->fileref)) { /* error? */ - MT_SET_PNU (uptr); /* pos not upd */ - return sim_tape_ioerr (uptr); - } - if (feof (uptr->fileref) || (*bc == MTR_EOM)) { /* eof or eom? */ - MT_SET_PNU (uptr); /* pos not upd */ - return MTSE_EOM; - } - uptr->pos = uptr->pos + sizeof (t_mtrlnt); /* spc over rec lnt */ - if (*bc == MTR_TMK) /* tape mark? */ - return MTSE_TMK; - if (*bc == MTR_FHGAP) { /* half gap? */ - uptr->pos = uptr->pos + sizeof (t_mtrlnt) / 2; /* half space fwd */ - sim_fseek (uptr->fileref, uptr->pos, SEEK_SET); /* resync */ - } - else if (*bc != MTR_GAP) - uptr->pos = uptr->pos + sizeof (t_mtrlnt) + /* spc over record */ - ((f == MTUF_F_STD)? ((sbc + 1) & ~1): sbc); +if ((uptr->flags & UNIT_ATT) == 0) /* if the unit is not attached */ + return MTSE_UNATT; /* then quit with an error */ + +sim_fseek (uptr->fileref, uptr->pos, SEEK_SET); /* set the initial tape position */ + +switch (f) { /* the read method depends on the tape format */ + + case MTUF_F_STD: + case MTUF_F_E11: + runaway_counter = 25 * 12 * bpi [MT_DENS (uptr->dynflags)]; /* set the largest legal gap size in bytes */ + + if (runaway_counter == 0) { /* if tape density has not been not set */ + sizeof_gap = 0; /* then disable runaway detection */ + runaway_counter = INT_MAX; /* to allow gaps of any size */ } - while ((*bc == MTR_GAP) || (*bc == MTR_FHGAP)); - break; + else /* otherwise */ + sizeof_gap = sizeof (t_mtrlnt); /* set the size of the gap */ + + bufcntr = 0; /* force an initial read */ + bufcap = 0; /* but of just one metadata marker */ + + do { /* loop until a record, gap, or error seen */ + if (bufcntr == bufcap) { /* if the buffer is empty then refill it */ + if (feof (uptr->fileref)) /* if we hit the EOF while reading gaps */ + if (sizeof_gap > 0) /* then if detection is enabled */ + return MTSE_RUNAWAY; /* then report a tape runaway */ + else /* otherwise report the physical EOF */ + return MTSE_EOM; /* as the end-of-medium */ + + else if (bufcap == 0) /* otherwise if this is the initial read */ + bufcap = 1; /* then start with just one marker */ + + else /* otherwise reset the capacity */ + bufcap = sizeof (buffer) /* to the full size of the buffer */ + / sizeof (buffer [0]); + + bufcap = sim_fread (buffer, /* fill the buffer */ + sizeof (t_mtrlnt), /* with tape metadata */ + bufcap, + uptr->fileref); + + if (ferror (uptr->fileref)) { /* if a file I/O error occurred */ + MT_SET_PNU (uptr); /* then set position not updated */ + return sim_tape_ioerr (uptr); /* report the error and quit */ + } + + else if (bufcap == 0) { /* otherwise if nothing was read */ + MT_SET_PNU (uptr); /* then set position not updated */ + return MTSE_EOM; /* report the end of medium and quit */ + } + + else /* otherwise reset the index */ + bufcntr = 0; /* to the start of the buffer */ + } + + *bc = buffer [bufcntr++]; /* store the metadata marker value */ + + if (*bc == MTR_EOM) { /* if an end-of-medium marker is seen */ + MT_SET_PNU (uptr); /* then set position not updated */ + return MTSE_EOM; /* report the end of medium and quit */ + } + + uptr->pos = uptr->pos + sizeof (t_mtrlnt); /* space over the marker */ + + if (*bc == MTR_TMK) /* if the value is a tape mark */ + return MTSE_TMK; /* then quit with tape mark status */ + + else if (*bc == MTR_GAP) /* otherwise if the value is a full gap */ + runaway_counter -= sizeof_gap; /* then decrement the gap counter */ + + else if (*bc == MTR_FHGAP) { /* otherwise if the value if a half gap */ + uptr->pos = uptr->pos - sizeof (t_mtrlnt) / 2; /* then back up */ + sim_fseek (uptr->fileref, uptr->pos, SEEK_SET); /* to resync */ + bufcntr = bufcap; /* mark the buffer as invalid to force a read */ + + *bc = MTR_GAP; /* reset the marker */ + runaway_counter -= sizeof_gap / 2; /* and decrement the gap counter */ + } + + else { /* otherwise it's a record marker */ + if (bufcntr < bufcap) /* if the position is within the buffer */ + sim_fseek (uptr->fileref, uptr->pos, SEEK_SET); /* then seek to the data area */ + + sbc = MTR_L (*bc); /* extract the record length */ + uptr->pos = uptr->pos + sizeof (t_mtrlnt) /* position to the start */ + + (f == MTUF_F_STD ? (sbc + 1) & ~1 : sbc); /* of the record */ + } + } + while (*bc == MTR_GAP && runaway_counter > 0); /* continue until data or runaway occurs */ + + if (runaway_counter <= 0) /* if a tape runaway occurred */ + return MTSE_RUNAWAY; /* then report it */ + + break; /* otherwise the operation succeeded */ case MTUF_F_TPC: sim_fread (&tpcbc, sizeof (t_tpclnt), 1, uptr->fileref); @@ -275,17 +422,25 @@ return MTSE_OK; Outputs: status = operation status - exit condition position - + exit condition tape position + ------------------ ------------------------------------------- unit unattached unchanged beginning of tape unchanged read error unchanged end of file unchanged end of medium updated tape mark updated + tape runaway updated data record updated, sim_fread will read record forward - See notes at "sim_tape_wrgap" regarding erase gap implementation. + This routine is called to set up a record read or spacing in the reverse + direction. On return, status is MTSE_OK and the tape is positioned at the + first data byte if a record was encountered, or status is an MTSE error code + giving the reason that the operation did not succeed and the tape position is + as indicated above. + + See the notes at "sim_tape_rdlntf" and "sim_tape_wrgap" regarding tape + runaway and the erase gap implementation, respectively. */ t_stat sim_tape_rdlntr (UNIT *uptr, t_mtrlnt *bc) @@ -296,42 +451,94 @@ uint32 f = MT_GET_FMT (uptr); t_addr ppos; t_mtrlnt sbc; t_tpclnt tpcbc; +t_mtrlnt buffer [256]; /* local tape buffer */ +uint32 bufcntr, bufcap; /* buffer counter and capacity */ +int32 runaway_counter, sizeof_gap; /* bytes remaining before runaway and bytes per gap */ -MT_CLR_PNU (uptr); -if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */ - return MTSE_UNATT; -if (sim_tape_bot (uptr)) /* at BOT? */ - return MTSE_BOT; -switch (f) { /* switch on fmt */ +MT_CLR_PNU (uptr); /* clear the position-not-updated flag */ - case MTUF_F_STD: case MTUF_F_E11: - do { - sim_fseek (uptr->fileref, uptr->pos - sizeof (t_mtrlnt), SEEK_SET); - sim_fread (bc, sizeof (t_mtrlnt), 1, uptr->fileref); /* read rec lnt */ - sbc = MTR_L (*bc); - if (ferror (uptr->fileref)) /* error? */ - return sim_tape_ioerr (uptr); - if (feof (uptr->fileref)) /* eof? */ - return MTSE_EOM; - uptr->pos = uptr->pos - sizeof (t_mtrlnt); /* spc over rec lnt */ - if (*bc == MTR_EOM) /* eom? */ - return MTSE_EOM; - if (*bc == MTR_TMK) /* tape mark? */ - return MTSE_TMK; - if ((*bc & MTR_M_RHGAP) == MTR_RHGAP) { /* half gap? */ - uptr->pos = uptr->pos + sizeof (t_mtrlnt) / 2; /* half space rev */ - sim_fseek (uptr->fileref, uptr->pos, SEEK_SET); /* resync */ +if ((uptr->flags & UNIT_ATT) == 0) /* if the unit is not attached */ + return MTSE_UNATT; /* then quit with an error */ + +if (sim_tape_bot (uptr)) /* if the unit is positioned at the BOT */ + return MTSE_BOT; /* then reading backward is not possible */ + +switch (f) { /* the read method depends on the tape format */ + + case MTUF_F_STD: + case MTUF_F_E11: + runaway_counter = 25 * 12 * bpi [MT_DENS (uptr->dynflags)]; /* set largest legal gap size in bytes */ + + if (runaway_counter == 0) { /* if tape density has not been not set */ + sizeof_gap = 0; /* then disable runaway detection */ + runaway_counter = INT_MAX; /* to allow gaps of any size */ + } + + else /* otherwise */ + sizeof_gap = sizeof (t_mtrlnt); /* set the size of the gap */ + + bufcntr = 0; /* force an initial read */ + bufcap = 1; /* but of just one metadata marker */ + + do { /* loop until a record, gap, or error seen */ + if (bufcntr == 0) { /* if the buffer is empty then refill it */ + if (sim_tape_bot (uptr)) /* if the search has backed into the BOT */ + return MTSE_BOT; /* then quit with an error */ + + else if (uptr->pos < sizeof (buffer)) /* if less than a full buffer remains */ + bufcap = (uint32) uptr->pos /* then reduce the capacity accordingly */ + / sizeof (t_mtrlnt); + + sim_fseek (uptr->fileref, /* seek back to the location */ + uptr->pos - bufcap * sizeof (t_mtrlnt), /* corresponding to the start */ + SEEK_SET); /* of the buffer */ + + bufcntr = sim_fread (buffer, sizeof (t_mtrlnt), /* fill the buffer */ + bufcap, uptr->fileref); /* with tape metadata */ + + if (ferror (uptr->fileref)) { /* if a file I/O error occurred */ + MT_SET_PNU (uptr); /* then set position not updated */ + return sim_tape_ioerr (uptr); /* report the error and quit */ + } + + else /* otherwise reset the capacity */ + bufcap = sizeof (buffer) /* to the full size of the buffer */ + / sizeof (buffer [0]); } - else if (*bc != MTR_GAP) { - uptr->pos = uptr->pos - sizeof (t_mtrlnt) - /* spc over record */ - ((f == MTUF_F_STD)? ((sbc + 1) & ~1): sbc); - sim_fseek (uptr->fileref, uptr->pos + sizeof (t_mtrlnt), SEEK_SET); + + *bc = buffer [--bufcntr]; /* store the metadata marker value */ + + uptr->pos = uptr->pos - sizeof (t_mtrlnt); /* backspace over the marker */ + + if (*bc == MTR_TMK) /* if the marker is a tape mark */ + return MTSE_TMK; /* then quit with tape mark status */ + + else if (*bc == MTR_GAP) /* otherwise if the marker is a full gap */ + runaway_counter -= sizeof_gap; /* then decrement the gap counter */ + + else if ((*bc & MTR_M_RHGAP) == MTR_RHGAP /* otherwise if the marker */ + || *bc == MTR_RRGAP) { /* is a half gap */ + uptr->pos = uptr->pos + sizeof (t_mtrlnt) / 2; /* then position forward to resync */ + bufcntr = 0; /* mark the buffer as invalid to force a read */ + + *bc = MTR_GAP; /* reset the marker */ + runaway_counter -= sizeof_gap / 2; /* and decrement the gap counter */ } - else if (sim_tape_bot (uptr)) /* backed into BOT? */ - return MTSE_BOT; - } - while ((*bc == MTR_GAP) || (*bc == MTR_RHGAP)); - break; + + else { /* otherwise it's a record marker */ + sbc = MTR_L (*bc); /* extract the record length */ + uptr->pos = uptr->pos - sizeof (t_mtrlnt) /* position to the start */ + - (f == MTUF_F_STD ? (sbc + 1) & ~1 : sbc); /* of the record */ + sim_fseek (uptr->fileref, /* seek to the data area */ + uptr->pos + sizeof (t_mtrlnt), SEEK_SET); + } + } + while (*bc == MTR_GAP && runaway_counter > 0); /* continue until data or runaway occurs */ + + if (runaway_counter <= 0) /* if a tape runaway occurred */ + return MTSE_RUNAWAY; /* then report it */ + + break; /* otherwise the operation succeeded */ case MTUF_F_TPC: ppos = sim_tape_tpc_fnd (uptr, (t_addr *) uptr->filebuf); /* find prev rec */ @@ -563,9 +770,17 @@ return sim_tape_wrdata (uptr, MTR_TMK); t_stat sim_tape_wreom (UNIT *uptr) { +t_stat result; + if (MT_GET_FMT (uptr) == MTUF_F_P7B) /* cant do P7B */ return MTSE_FMT; -return sim_tape_wrdata (uptr, MTR_EOM); + +result = sim_tape_wrdata (uptr, MTR_EOM); /* write the EOM marker */ + +uptr->pos = uptr->pos - sizeof (t_mtrlnt); /* restore original tape position */ +MT_SET_PNU (uptr); /* indicate that position was not updated */ + +return result; } /* Write erase gap @@ -573,7 +788,6 @@ return sim_tape_wrdata (uptr, MTR_EOM); Inputs: uptr = pointer to tape unit gaplen = length of gap in tenths of an inch - bpi = current recording density in bytes per inch Outputs: status = operation status @@ -592,8 +806,8 @@ return sim_tape_wrdata (uptr, MTR_EOM); value. This value is chosen so that it is still recognizable even if it has been "cut in half" by a subsequent data overwrite that does not end on a metadatum-sized boundary. In addition, a range of metadata values are - reserved for detection in the reverse direction. Erase gaps are supported - only in SIMH tape format. + reserved for detection in the reverse direction. Erase gaps are currently + supported only in SIMH (MTUF_F_STD) tape format. This implementation supports erasing gaps in the middle of a populated tape image and will always produce a valid image. It also produces valid images @@ -608,8 +822,8 @@ return sim_tape_wrdata (uptr, MTR_EOM); problematic if the density setting is not the same as that used during recording. There is no way to establish a gap of a certain length unequivocally in an image file, so this implementation establishes a gap of a - certain number of bytes that reflect the desired gap length at the bpi used - during writing. + certain number of bytes that reflect the desired gap length at the tape + density in bits per inch used during writing. To write an erase gap, the implementation uses one of two approaches, depending on whether or not the current tape position is at EOM. Erasing at @@ -624,12 +838,14 @@ return sim_tape_wrdata (uptr, MTR_EOM); Because the smallest legal tape record requires space for two metadata markers plus two data bytes, an erasure that would leave less than that is increased to consume the entire record. Otherwise, the final record is - truncated appropriately. + truncated appropriately by rewriting the leading and trailing length words + appropriately. When reading in either direction, gap metadata markers are ignored (skipped) until a record length header, EOF marker, EOM marker, or physical EOF is encountered. Thus, tape images containing gap metadata are transparent to - the calling simulator. + the calling simulator (unless tape runaway support is enabled -- see the + notes at "sim_tape_rdlntf" for details). The permissibility of data record lengths that are not multiples of the metadatum size presents a difficulty when reading. If such an "odd length" @@ -655,28 +871,47 @@ return sim_tape_wrdata (uptr, MTR_EOM); 0xFFFEFFFF - reserved (indicates half-gap in forward reads) 0xFFFF0000:0xFFFF00FF - reserved (indicates half-gap in reverse reads) 0xFFFF8000:0xFFFF80FF - reserved (indicates half-gap in reverse reads) - */ -t_stat sim_tape_wrgap (UNIT *uptr, uint32 gaplen, uint32 bpi) + If the tape density has been set via a previous sim_tape_set_dens call, and + the tape format is set to SIMH format, then this routine will write a gap of + the appropriate size. If the density has not been set, then no action will + be taken, and either MTSE_IOERR or MTSE_OK status will be returned, depending + on whether SIMH or another format is selected, respectively. A simulator + that calls this routine must set the density beforehand; failure to do so is + an error. However, calling while another format is enabled is OK and is + treated as a no-operation. This allows a device simulator that supports + writing erase gaps to use the same code without worrying about the tape + format currently selected by the user. +*/ + +t_stat sim_tape_wrgap (UNIT *uptr, uint32 gaplen) { t_stat st; t_mtrlnt meta, sbc, new_len, rec_size; t_addr gap_pos = uptr->pos; -uint32 file_size, marker_count; -uint32 format = MT_GET_FMT (uptr); -uint32 gap_alloc = 0; /* gap allocated from tape */ -int32 gap_needed = (gaplen * bpi) / 10; /* gap remainder still needed */ +uint32 file_size, marker_count, tape_density; +int32 gap_needed; +uint32 gap_alloc = 0; /* gap currently allocated from the tape */ +const uint32 format = MT_GET_FMT (uptr); /* tape format */ const uint32 meta_size = sizeof (t_mtrlnt); /* bytes per metadatum */ const uint32 min_rec_size = 2 + sizeof (t_mtrlnt) * 2; /* smallest data record size */ MT_CLR_PNU (uptr); -if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */ - return MTSE_UNATT; -if (format != MTUF_F_STD) /* not SIMH fmt? */ - return MTSE_FMT; -if (sim_tape_wrp (uptr)) /* write protected? */ - return MTSE_WRP; +if ((uptr->flags & UNIT_ATT) == 0) /* if the unit is not attached */ + return MTSE_UNATT; /* then we cannot proceed */ + +else if (sim_tape_wrp (uptr)) /* otherwise if the unit is write protected */ + return MTSE_WRP; /* then we cannot write */ + +tape_density = bpi [MT_DENS (uptr->dynflags)]; /* get the density of the tape */ + +if (format != MTUF_F_STD) /* if erase gaps aren't supported by the format */ + return MTSE_OK; /* then take no action */ +else if (tape_density == 0) /* otherwise if the density is not set */ + return MTSE_IOERR; /* then report an I/O error */ +else /* otherwise */ + gap_needed = (gaplen * tape_density) / 10; /* determine the gap size needed in bytes */ file_size = sim_fsize (uptr->fileref); /* get file size */ sim_fseek (uptr->fileref, uptr->pos, SEEK_SET); /* position tape */ @@ -720,7 +955,7 @@ do { gap_needed = gap_needed - meta_size / 2; /* reduce requirement */ } - else if (uptr->pos + + else if (uptr->pos + MTR_L (meta) + meta_size > file_size) { /* rec len out of range? */ gap_alloc = gap_alloc + gap_needed; /* presume overwritten tape */ gap_needed = 0; /* allocate remainder */ @@ -876,6 +1111,8 @@ t_stat sim_tape_set_fmt (UNIT *uptr, int32 val, char *cptr, void *desc) { uint32 f; +if (uptr->flags & UNIT_ATT) + return SCPE_ALATT; if (uptr == NULL) return SCPE_IERR; if (cptr == NULL) @@ -953,7 +1190,6 @@ return ((p == 0)? map[p]: map[p - 1]); t_stat sim_tape_set_capac (UNIT *uptr, int32 val, char *cptr, void *desc) { -extern uint32 sim_taddr_64; t_addr cap; t_stat r; @@ -982,3 +1218,81 @@ if (uptr->capac) { else fprintf (st, "unlimited capacity"); return SCPE_OK; } + +/* Set the tape density. + + Set the density of the specified tape unit either to the value supplied or to + the value represented by the supplied character string. + + If "desc" is NULL, then "val" must be set to one of the MT_DENS_* constants + in sim_tape.h other than MT_DENS_NONE; the supplied value is used as the tape + density, and the character string is ignored. Otherwise, "desc" must point + at an int32 value containing a set of allowed densities constructed as a + bitwise OR of the appropriate MT_*_VALID values. In this case, the string + pointed to by "cptr" will be parsed for a decimal value corresponding to the + desired density in bits per inch and validated against the set of allowed + values. + + In either case, SCPE_ARG is returned if the density setting is not valid or + allowed. If the setting is OK, the new density is set into the unit + structure, and SCPE_OK is returned. +*/ + +t_stat sim_tape_set_dens (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +uint32 density, new_bpi; +t_stat result = SCPE_OK; + +if (uptr == NULL) /* if the unit pointer is null */ + return SCPE_IERR; /* then the caller has screwed up */ + +else if (desc == NULL) /* otherwise if a validation set was not supplied */ + if (val > 0 && val < (int32) BPI_COUNT) /* then if a valid density code was supplied */ + uptr->dynflags = uptr->dynflags & ~MTVF_DENS_MASK /* then insert the code */ + | val << UNIT_V_DF_TAPE; /* in the unit flags */ + else /* otherwise the code is invalid */ + return SCPE_ARG; /* so report a bad argument */ + +else { /* otherwise a validation set was supplied */ + if (cptr == NULL || *cptr == 0) /* but if no value is present */ + return SCPE_MISVAL; /* then report a missing value */ + + new_bpi = (uint32) get_uint (cptr, 10, UINT_MAX, &result); /* convert the string value */ + + if (result != SCPE_OK) /* if the conversion failed */ + result = SCPE_ARG; /* then report a bad argument */ + + else for (density = 0; density < BPI_COUNT; density++) /* otherwise validate the density */ + if (new_bpi == bpi [density] /* if it matches a value in the list */ + && ((1 << density) & *(int32 *) desc)) { /* and it's an allowed value */ + uptr->dynflags = uptr->dynflags & ~MTVF_DENS_MASK /* then store the index of the value */ + | density << UNIT_V_DF_TAPE; /* in the unit flags */ + return SCPE_OK; /* and return success */ + } + + result = SCPE_ARG; /* if no match, then report a bad argument */ + } + +return result; /* return the result of the operation */ +} + +/* Show the tape density */ + +t_stat sim_tape_show_dens (FILE *st, UNIT *uptr, int32 val, void *desc) +{ +uint32 tape_density; + +if (uptr == NULL) /* if the unit pointer is null */ + return SCPE_IERR; /* then the caller has screwed up */ + +else { /* otherwise get the density */ + tape_density = bpi [MT_DENS (uptr->dynflags)]; /* of the tape from the unit flags */ + + if (tape_density) /* if it's set */ + fprintf (st, "density=%d bpi", tape_density); /* then report it */ + else /* otherwise */ + fprintf (st, "density not set"); /* it was never set by the caller */ + } + +return SCPE_OK; +} diff --git a/sim_tape.h b/sim_tape.h index 22eb4aac..f8132f34 100644 --- a/sim_tape.h +++ b/sim_tape.h @@ -1,6 +1,6 @@ /* sim_tape.h: simulator tape support library definitions - Copyright (c) 1993-2008, Robert M Supnik + Copyright (c) 1993-2014, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -23,6 +23,10 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 15-Dec-14 JDB Added tape density validity flags + 04-Nov-14 JDB Added tape density flags + 11-Oct-14 JDB Added reverse read half gap, set/show density + 22-Sep-14 JDB Added tape runaway support 30-Aug-06 JDB Added erase gap support 14-Feb-06 RMS Added variable tape capacity 17-Dec-05 RMS Added write support for Paul Pierce 7b format @@ -39,6 +43,7 @@ typedef uint32 t_mtrlnt; /* magtape rec lnt */ #define MTR_TMK 0x00000000 /* tape mark */ #define MTR_EOM 0xFFFFFFFF /* end of medium */ #define MTR_GAP 0xFFFFFFFE /* primary gap */ +#define MTR_RRGAP 0xFFFFFFFF /* reverse read half gap */ #define MTR_FHGAP 0xFFFEFFFF /* fwd half gap (overwrite) */ #define MTR_RHGAP 0xFFFF0000 /* rev half gap (overwrite) */ #define MTR_M_RHGAP (~0x000080FF) /* range mask for rev gap */ @@ -91,6 +96,23 @@ typedef uint16 t_tpclnt; /* magtape rec lnt */ #define MT_TST_PNU(u) ((u)->flags & MTUF_PNU) #define MT_GET_FMT(u) (((u)->flags >> MTUF_V_FMT) & MTUF_M_FMT) +#define MT_DENS_NONE 0 /* density not set */ +#define MT_DENS_200 1 /* 200 bpi NRZI */ +#define MT_DENS_556 2 /* 556 bpi NRZI */ +#define MT_DENS_800 3 /* 800 bpi NRZI */ +#define MT_DENS_1600 4 /* 1600 bpi PE */ +#define MT_DENS_6250 5 /* 6250 bpi GCR */ + +#define MTVF_DENS_MASK (((1u << UNIT_W_DF_TAPE) - 1) << UNIT_V_DF_TAPE) +#define MT_DENS(f) (((f) & MTVF_DENS_MASK) >> UNIT_V_DF_TAPE) + +#define MT_NONE_VALID (1u << MT_DENS_NONE) /* density not set is valid */ +#define MT_200_VALID (1u << MT_DENS_200) /* 200 bpi is valid */ +#define MT_556_VALID (1u << MT_DENS_556) /* 556 bpi is valid */ +#define MT_800_VALID (1u << MT_DENS_800) /* 800 bpi is valid */ +#define MT_1600_VALID (1u << MT_DENS_1600) /* 1600 bpi is valid */ +#define MT_6250_VALID (1u << MT_DENS_6250) /* 6250 bpi is valid */ + /* Return status codes */ #define MTSE_OK 0 /* no error */ @@ -103,6 +125,7 @@ typedef uint16 t_tpclnt; /* magtape rec lnt */ #define MTSE_EOM 7 /* end of medium */ #define MTSE_RECE 8 /* error in record */ #define MTSE_WRP 9 /* write protected */ +#define MTSE_RUNAWAY 10 /* tape runaway */ /* Prototypes */ @@ -113,7 +136,7 @@ t_stat sim_tape_rdrecr (UNIT *uptr, uint8 *buf, t_mtrlnt *bc, t_mtrlnt max); t_stat sim_tape_wrrecf (UNIT *uptr, uint8 *buf, t_mtrlnt bc); t_stat sim_tape_wrtmk (UNIT *uptr); t_stat sim_tape_wreom (UNIT *uptr); -t_stat sim_tape_wrgap (UNIT *uptr, uint32 gaplen, uint32 bpi); +t_stat sim_tape_wrgap (UNIT *uptr, uint32 gaplen); t_stat sim_tape_sprecf (UNIT *uptr, t_mtrlnt *bc); t_stat sim_tape_sprecr (UNIT *uptr, t_mtrlnt *bc); t_stat sim_tape_rewind (UNIT *uptr); @@ -125,5 +148,7 @@ t_stat sim_tape_set_fmt (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat sim_tape_show_fmt (FILE *st, UNIT *uptr, int32 val, void *desc); t_stat sim_tape_set_capac (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat sim_tape_show_capac (FILE *st, UNIT *uptr, int32 val, void *desc); +t_stat sim_tape_set_dens (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat sim_tape_show_dens (FILE *st, UNIT *uptr, int32 val, void *desc); #endif diff --git a/sim_timer.c b/sim_timer.c index 79120fe8..164a084a 100644 --- a/sim_timer.c +++ b/sim_timer.c @@ -1,6 +1,6 @@ /* sim_timer.c: simulator timer library - Copyright (c) 1993-2010, Robert M Supnik + Copyright (c) 1993-2015, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -23,6 +23,7 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 28-Mar-15 RMS Revised to use sim_printf 29-Dec-10 MP Fixed clock resolution determination for Unix platforms 22-Sep-08 RMS Added "stability threshold" for idle routine 27-May-08 RMS Fixed bug in Linux idle routines (from Walter Mueller) @@ -35,17 +36,20 @@ This library includes the following routines: - sim_timer_init - initialize timing system - sim_rtc_init - initialize calibration - sim_rtc_calb - calibrate clock - sim_timer_init - initialize timing system - sim_idle - virtual machine idle - sim_os_msec - return elapsed time in msec - sim_os_sleep - sleep specified number of seconds - sim_os_ms_sleep - sleep specified number of milliseconds + sim_timer_init initialize timing system + sim_rtc_init initialize calibration + sim_rtc_calb calibrate clock + sim_timer_init initialize timing system + sim_activate_after activate for specified number of microseconds + sim_idle virtual machine idle + sim_os_msec return elapsed time in msec + sim_os_sleep sleep specified number of seconds + sim_os_ms_sleep sleep specified number of milliseconds The calibration, idle, and throttle routines are OS-independent; the _os_ routines are not. + + The timer library assumes that timer[0] is the master system timer. */ #include "sim_defs.h" @@ -61,8 +65,7 @@ static uint32 sim_throt_type = 0; static uint32 sim_throt_val = 0; static uint32 sim_throt_state = 0; static int32 sim_throt_wait = 0; -extern int32 sim_interval, sim_switches; -extern FILE *sim_log; +static UNIT *sim_clock_unit = NULL; extern UNIT *sim_clock_queue; t_stat sim_throt_svc (UNIT *uptr); @@ -337,18 +340,21 @@ static int32 rtc_ticks[SIM_NTIMERS] = { 0 }; /* ticks */ static int32 rtc_hz[SIM_NTIMERS] = { 0 }; /* tick rate */ static uint32 rtc_rtime[SIM_NTIMERS] = { 0 }; /* real time */ static uint32 rtc_vtime[SIM_NTIMERS] = { 0 }; /* virtual time */ +static double rtc_gtime[SIM_NTIMERS] = { 0 }; /* instruction time */ static uint32 rtc_nxintv[SIM_NTIMERS] = { 0 }; /* next interval */ static int32 rtc_based[SIM_NTIMERS] = { 0 }; /* base delay */ static int32 rtc_currd[SIM_NTIMERS] = { 0 }; /* current delay */ static int32 rtc_initd[SIM_NTIMERS] = { 0 }; /* initial delay */ static uint32 rtc_elapsed[SIM_NTIMERS] = { 0 }; /* sec since init */ +static uint32 rtc_calibrations[SIM_NTIMERS] = { 0 }; /* calibration count */ void sim_rtcn_init_all (void) { uint32 i; for (i = 0; i < SIM_NTIMERS; i++) { - if (rtc_initd[i] != 0) sim_rtcn_init (rtc_initd[i], i); + if (rtc_initd[i] != 0) + sim_rtcn_init (rtc_initd[i], i); } return; } @@ -361,6 +367,7 @@ if ((tmr < 0) || (tmr >= SIM_NTIMERS)) return time; rtc_rtime[tmr] = sim_os_msec (); rtc_vtime[tmr] = rtc_rtime[tmr]; +rtc_gtime[tmr] = 0.0; rtc_nxintv[tmr] = 1000; rtc_ticks[tmr] = 0; rtc_hz[tmr] = 0; @@ -368,6 +375,7 @@ rtc_based[tmr] = time; rtc_currd[tmr] = time; rtc_initd[tmr] = time; rtc_elapsed[tmr] = 0; +rtc_calibrations[tmr] = 0; return time; } @@ -391,11 +399,15 @@ if (new_rtime < rtc_rtime[tmr]) { /* time running backward rtc_rtime[tmr] = new_rtime; /* reset wall time */ return rtc_currd[tmr]; /* can't calibrate */ } +++rtc_calibrations[tmr]; /* count calibrations */ delta_rtime = new_rtime - rtc_rtime[tmr]; /* elapsed wtime */ rtc_rtime[tmr] = new_rtime; /* adv wall time */ rtc_vtime[tmr] = rtc_vtime[tmr] + 1000; /* adv sim time */ -if (delta_rtime > 30000) /* gap too big? */ +rtc_gtime[tmr] = sim_gtime (); /* save inst time */ +if (delta_rtime > 30000) { /* gap too big? */ + rtc_currd[tmr] = rtc_initd[tmr]; return rtc_initd[tmr]; /* can't calibr */ + } if (delta_rtime == 0) /* gap too small? */ rtc_based[tmr] = rtc_based[tmr] * ticksper; /* slew wide */ else rtc_based[tmr] = (int32) (((double) rtc_based[tmr] * (double) rtc_nxintv[tmr]) / @@ -455,7 +467,8 @@ static uint32 cyc_ms = 0; uint32 w_ms, w_idle, act_ms; int32 act_cyc; -if ((sim_clock_queue == NULL) || /* clock queue empty? */ +if ((!sim_idle_enab) || /* idling disabled */ + (sim_clock_queue == NULL) || /* clock queue empty? */ ((sim_clock_queue->flags & UNIT_IDLE) == 0) || /* event not idle-able? */ (rtc_elapsed[tmr] < sim_idle_stable)) { /* timer not stable? */ if (sin_cyc) @@ -504,9 +517,7 @@ if (cptr) { sim_idle_enab = TRUE; if (sim_throt_type != SIM_THROT_NONE) { sim_set_throt (0, NULL); - printf ("Throttling disabled\n"); - if (sim_log) - fprintf (sim_log, "Throttling disabled\n"); + sim_printf ("Throttling disabled\n"); } return SCPE_OK; } @@ -559,9 +570,7 @@ else { sim_throt_type = SIM_THROT_PCT; else return SCPE_ARG; if (sim_idle_enab) { - printf ("Idling disabled\n"); - if (sim_log) - fprintf (sim_log, "Idling disabled\n"); + sim_printf ("Idling disabled\n"); sim_clr_idle (NULL, 0, NULL, NULL); } sim_throt_val = (uint32) val; @@ -680,3 +689,79 @@ switch (sim_throt_state) { sim_activate (uptr, sim_throt_wait); /* reschedule */ return SCPE_OK; } + +/* v4 compatibility routines */ + +/* Timer based on current execution rates */ + +double sim_timer_inst_per_sec (void) +{ +double inst_per_sec; + +inst_per_sec = ((double)rtc_currd[0]) * rtc_hz[0]; +if (inst_per_sec == 0) + inst_per_sec = 50000.0; +return inst_per_sec; +} + +t_stat sim_activate_after (UNIT *uptr, int32 usec_delay) +{ +int32 inst_delay; +double inst_per_sec; + +if (sim_is_active (uptr)) /* already active? */ + return SCPE_OK; +inst_per_sec = sim_timer_inst_per_sec (); +inst_delay = (int32)((inst_per_sec * usec_delay) / 1000000.0); +return sim_activate (uptr, inst_delay); /* queue it now */ +} + +/* sim_show_timers - show running timer information */ + +t_stat sim_show_timers (FILE* st, DEVICE *dptr, UNIT* uptr, int32 val, char* desc) +{ +int tmr, clocks; + +for (tmr = clocks = 0; tmr < SIM_NTIMERS; tmr++) { + if (rtc_initd[tmr] == 0) + continue; + else clocks++; + + if (rtc_hz[tmr]) { + fprintf (st, "Calibrated Timer %d: \n", tmr); + fprintf (st, " Running at: %dhz\n", rtc_hz[tmr]); + fprintf (st, " Ticks in current second: %d\n", rtc_ticks[tmr]); + } + else fprintf (st, "Uncalibrated Timer %d:\n", tmr); + fprintf (st, " Seconds Running: %u\n", rtc_elapsed[tmr]); + fprintf (st, " Calibrations: %u\n", rtc_calibrations[tmr]); + fprintf (st, " Last Calibration Time: %.0f\n", rtc_gtime[tmr]); + fprintf (st, " Real Time: %u\n", rtc_rtime[tmr]); + fprintf (st, " Virtual Time: %u\n", rtc_vtime[tmr]); + fprintf (st, " Next Interval: %u\n", rtc_nxintv[tmr]); + fprintf (st, " Base Tick Delay: %d\n", rtc_based[tmr]); + fprintf (st, " Initial Insts per Tick: %d\n", rtc_initd[tmr]); + fprintf (st, " Current Insts per Tick: %d\n", rtc_currd[tmr]); + } +if (clocks == 0) + fprintf (st, "No calibrated clock devices\n"); +return SCPE_OK; +} + +/* Clock coscheduling routines - v4 */ + +t_stat sim_register_clock_unit (UNIT *uptr) +{ +sim_clock_unit = uptr; +return SCPE_OK; +} + +t_stat sim_clock_coschedule (UNIT *uptr, int32 interval) +{ +if (sim_clock_unit == NULL) + return sim_activate (uptr, interval); +else { + int32 t = sim_activate_time (sim_clock_unit); + return sim_activate (uptr, t? t - 1: interval); + } +} diff --git a/sim_timer.h b/sim_timer.h index 8447cbdd..abfcff65 100644 --- a/sim_timer.h +++ b/sim_timer.h @@ -1,6 +1,6 @@ /* sim_timer.h: simulator timer library headers - Copyright (c) 1993-2008, Robert M Supnik + Copyright (c) 1993-2014, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -23,6 +23,7 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 14-Dec-14 JDB [4.0] Added data externals 28-Apr-07 RMS Added sim_rtc_init_all 17-Oct-06 RMS Added idle support 02-Jan-04 RMS Split out from SCP @@ -56,12 +57,14 @@ void sim_rtcn_init_all (void); int32 sim_rtcn_calb (int32 ticksper, int32 tmr); int32 sim_rtc_init (int32 time); int32 sim_rtc_calb (int32 ticksper); +t_stat sim_activate_after (UNIT *uptr, int32 usec_delay); t_bool sim_idle (uint32 tmr, t_bool sin_cyc); t_stat sim_set_throt (int32 arg, char *cptr); t_stat sim_show_throt (FILE *st, DEVICE *dnotused, UNIT *unotused, int32 flag, char *cptr); t_stat sim_set_idle (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat sim_clr_idle (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat sim_show_idle (FILE *st, UNIT *uptr, int32 val, void *desc); +t_stat sim_show_timers (FILE* st, DEVICE *dptr, UNIT* uptr, int32 val, char* desc); void sim_throt_sched (void); void sim_throt_cancel (void); uint32 sim_os_msec (void); @@ -69,4 +72,11 @@ void sim_os_sleep (unsigned int sec); uint32 sim_os_ms_sleep (unsigned int msec); uint32 sim_os_ms_sleep_init (void); +extern t_bool sim_idle_enab; /* idle enabled flag */ +extern volatile t_bool sim_idle_wait; /* idle waiting flag */ + +/* v4 compatibility */ + +t_stat sim_register_clock_unit (UNIT *uptr); + #endif diff --git a/sim_tmxr.c b/sim_tmxr.c index a52335da..99ff0138 100644 --- a/sim_tmxr.c +++ b/sim_tmxr.c @@ -1,6 +1,6 @@ /* sim_tmxr.c: Telnet terminal multiplexor library - Copyright (c) 2001-2011, Robert M Supnik + Copyright (c) 2001-2015, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -26,6 +26,7 @@ Based on the original DZ11 simulator by Thord Nilson, as updated by Arthur Krewat. + 28-Mar-15 RMS Revised to use sim_printf 16-Jan-11 MP Made option negotiation more reliable 20-Nov-08 RMS Added three new standardized SHOW routines 30-Sep-08 JDB Reverted tmxr_find_ldsc to original implementation @@ -130,9 +131,7 @@ void tmxr_rmvrc (TMLN *lp, int32 p); int32 tmxr_send_buffered_data (TMLN *lp); TMLN *tmxr_find_ldsc (UNIT *uptr, int32 val, TMXR *mp); -extern int32 sim_switches; extern char sim_name[]; -extern FILE *sim_log; extern uint32 sim_os_msec (void); /* Poll for new connection @@ -554,9 +553,7 @@ if ((r != SCPE_OK) || (port == 0)) sock = sim_master_sock (port); /* make master socket */ if (sock == INVALID_SOCKET) /* open error */ return SCPE_OPENERR; -printf ("Listening on port %d (socket %d)\n", port, sock); -if (sim_log) - fprintf (sim_log, "Listening on port %d (socket %d)\n", port, sock); +sim_printf ("Listening on port %d (socket %d)\n", port, sock); mp->port = port; /* save port */ mp->master = sock; /* save master socket */ for (i = 0; i < mp->lines; i++) { /* initialize lines */ diff --git a/sim_tmxr.h b/sim_tmxr.h index 55399840..cfba7c13 100644 --- a/sim_tmxr.h +++ b/sim_tmxr.h @@ -1,6 +1,6 @@ /* sim_tmxr.h: terminal multiplexor definitions - Copyright (c) 2001-2008, Robert M Supnik + Copyright (c) 2001-2014, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -26,6 +26,7 @@ Based on the original DZ11 simulator by Thord Nilson, as updated by Arthur Krewat. + 14-Dec-14 JDB [4.0] Added include of "sim_sock.h" for SOCKET, etc. 20-Nov-08 RMS Added three new standardized SHOW routines 27-May-08 JDB Added lnorder to TMXR structure, added tmxr_set_lnorder and tmxr_set_lnorder @@ -40,8 +41,10 @@ added tmxr_rqln, tmxr_tqln */ -#ifndef _SIM_TMXR_H_ -#define _SIM_TMXR_H_ 0 +#ifndef SIM_TMXR_H_ +#define SIM_TMXR_H_ 0 + +#include "sim_sock.h" #define TMXR_V_VALID 15 #define TMXR_VALID (1 << TMXR_V_VALID) diff --git a/swtp6800/common/bootrom.c b/swtp6800/common/bootrom.c index 608ecae0..c3ecc6e8 100644 --- a/swtp6800/common/bootrom.c +++ b/swtp6800/common/bootrom.c @@ -144,7 +144,7 @@ t_stat BOOTROM_config (UNIT *uptr, int32 val, char *cptr, void *desc) if (val == UNIT_NONE) BOOTROM_unit.capac = 0; /* set EPROM size */ else - BOOTROM_unit.capac = 0x200 << (val >> UNIT_V_MSIZE) - 1; /* set EPROM size */ + BOOTROM_unit.capac = 0x200 << ((val >> UNIT_V_MSIZE) - 1); /* set EPROM size */ if (BOOTROM_unit.filebuf) { /* free buffer */ free (BOOTROM_unit.filebuf); BOOTROM_unit.filebuf = NULL; @@ -161,9 +161,9 @@ t_stat BOOTROM_config (UNIT *uptr, int32 val, char *cptr, void *desc) t_stat BOOTROM_reset (DEVICE *dptr) { - int j, c; + t_addr j; + int c; FILE *fp; - t_stat r; if (BOOTROM_dev.dctrl & DEBUG_flow) printf("BOOTROM_reset: \n"); @@ -195,7 +195,7 @@ t_stat BOOTROM_reset (DEVICE *dptr) j = 0; /* load EPROM file */ c = fgetc(fp); while (c != EOF) { - *(uint8 *)(BOOTROM_unit.filebuf + j++) = c & 0xFF; + *((uint8 *)(BOOTROM_unit.filebuf) + j++) = c & 0xFF; c = fgetc(fp); if (j > BOOTROM_unit.capac) { printf("\tImage is too large - Load truncated!!!\n"); @@ -222,7 +222,7 @@ int32 BOOTROM_get_mbyte(int32 offset) } if (BOOTROM_dev.dctrl & DEBUG_read) printf("BOOTROM_get_mbyte: offset=%04X\n", offset); - val = *(uint8 *)(BOOTROM_unit.filebuf + offset) & 0xFF; + val = *((uint8 *)(BOOTROM_unit.filebuf) + offset) & 0xFF; if (BOOTROM_dev.dctrl & DEBUG_read) printf("BOOTROM_get_mbyte: Normal val=%02X\n", val); return val; diff --git a/swtp6800/common/dc-4.c b/swtp6800/common/dc-4.c index d4379808..204d40a8 100644 --- a/swtp6800/common/dc-4.c +++ b/swtp6800/common/dc-4.c @@ -32,19 +32,19 @@ The floppy controller is interfaced to the CPU by use of 5 memory addreses. These are SS-30 slot numbers 5 and 6 (0x8014-0x801B). - Address Mode Function - ------- ---- -------- + Address Mode Function + ------- ---- -------- - 0x8014 Read Returns FDC interrupt status - 0x8014 Write Selects the drive/head/motor control - 0x8018 Read Returns status of FDC - 0x8018 Write FDC command register - 0x8019 Read Returns FDC track register - 0x8019 Write Set FDC track register - 0x801A Read Returns FDC sector register - 0x801A Write Set FDC sector register - 0x801B Read Read data - 0x801B Write Write data + 0x8014 Read Returns FDC interrupt status + 0x8014 Write Selects the drive/head/motor control + 0x8018 Read Returns status of FDC + 0x8018 Write FDC command register + 0x8019 Read Returns FDC track register + 0x8019 Write Set FDC track register + 0x801A Read Returns FDC sector register + 0x801A Write Set FDC sector register + 0x801B Read Read data + 0x801B Write Write data Drive Select Read (0x8014): @@ -181,28 +181,28 @@ A FLEX disk is defined as follows: - Track Sector Use - 0 1 Boot sector - 0 2 Boot sector (cont) - 0 3 Unused - 0 4 System Identity Record (explained below) - 0 5 Unused - 0 6-last Directory - 10 entries/sector (explained below) - 1 1 First available data sector - last-1 last Last available data sector + Track Sector Use + 0 1 Boot sector + 0 2 Boot sector (cont) + 0 3 Unused + 0 4 System Identity Record (explained below) + 0 5 Unused + 0 6-last Directory - 10 entries/sector (explained below) + 1 1 First available data sector + last-1 last Last available data sector System Identity Record - Byte Use - 0x00 Two bytes of zeroes (Clears forward link) - 0x10 Volume name in ASCII(11 bytes) - 0x1B Volume number in binary (2 bytes) - 0x1D Address of first free data sector (Track-Sector) (2 bytes) - 0x1F Address of last free data sector (Track-Sector) (2 bytes) - 0x21 Total number of data sectors in binary (2 bytes) - 0x23 Current date (Month-Day-Year) in binary - 0x26 Highest track number on disk in binary (byte) - 0x27 Highest sector number on a track in binary (byte) + Byte Use + 0x00 Two bytes of zeroes (Clears forward link) + 0x10 Volume name in ASCII(11 bytes) + 0x1B Volume number in binary (2 bytes) + 0x1D Address of first free data sector (Track-Sector) (2 bytes) + 0x1F Address of last free data sector (Track-Sector) (2 bytes) + 0x21 Total number of data sectors in binary (2 bytes) + 0x23 Current date (Month-Day-Year) in binary + 0x26 Highest track number on disk in binary (byte) + 0x27 Highest sector number on a track in binary (byte) The following unit registers are used by this controller emulation: @@ -224,7 +224,7 @@ /* emulate a SS FLEX disk with 72 sectors and 80 tracks */ -#define NUM_DISK 4 /* standard 1797 maximum */ +#define NUM_DISK 4 /* standard 1797 maximum */ #define SECT_SIZE 256 /* standard FLEX sector */ #define NUM_SECT 72 /* sectors/track */ #define TRAK_SIZE (SECT_SIZE * NUM_SECT) /* trk size (bytes) */ @@ -240,10 +240,10 @@ /* 1797 status bits */ -#define BUSY 0x01 -#define DRQ 0x02 -#define WRPROT 0x40 -#define NOTRDY 0x80 +#define BUSY 0x01 +#define DRQ 0x02 +#define WRPROT 0x40 +#define NOTRDY 0x80 /* function prototypes */ @@ -368,7 +368,6 @@ t_stat dsk_reset (DEVICE *dptr) int32 fdcdrv(int32 io, int32 data) { static long pos; - char buf[128]; if (io) { /* write to DC-4 drive register */ if (dsk_dev.dctrl & DEBUG_write) @@ -390,13 +389,13 @@ int32 fdcdrv(int32 io, int32 data) pos = 0x200; /* Read in SIR */ if (dsk_dev.dctrl & DEBUG_read) printf("\nfdcdrv: Read pos = %ld ($%04X)", pos, (unsigned int) pos); - sim_fseek(dsk_unit[cur_dsk].fileref, pos, 0); /* seek to offset */ + sim_fseek(dsk_unit[cur_dsk].fileref, pos, SEEK_SET); /* seek to offset */ sim_fread(dsk_unit[cur_dsk].filebuf, SECSIZ, 1, dsk_unit[cur_dsk].fileref); /* read in buffer */ dsk_unit[cur_dsk].u3 |= BUSY | DRQ; /* set DRQ & BUSY */ dsk_unit[cur_dsk].pos = 0; /* clear counter */ - spt = *(uint8 *)(dsk_unit[cur_dsk].filebuf + MAXSEC) & 0xFF; + spt = *((uint8 *)(dsk_unit[cur_dsk].filebuf) + MAXSEC) & 0xFF; heds = 0; - cpd = *(uint8 *)(dsk_unit[cur_dsk].filebuf + MAXCYL) & 0xFF; + cpd = *((uint8 *)(dsk_unit[cur_dsk].filebuf) + MAXCYL) & 0xFF; trksiz = spt * SECSIZ; dsksiz = trksiz * cpd; if (dsk_dev.dctrl & DEBUG_read) @@ -436,7 +435,7 @@ int32 fdccmd(int32 io, int32 data) pos += SECSIZ * (dsk_unit[cur_dsk].u5 - 1); if (dsk_dev.dctrl & DEBUG_read) printf("\nfdccmd: Read pos = %ld ($%08X)", pos, (unsigned int) pos); - sim_fseek(dsk_unit[cur_dsk].fileref, pos, 0); /* seek to offset */ + sim_fseek(dsk_unit[cur_dsk].fileref, pos, SEEK_SET); /* seek to offset */ sim_fread(dsk_unit[cur_dsk].filebuf, SECSIZ, 1, dsk_unit[cur_dsk].fileref); /* read in buffer */ dsk_unit[cur_dsk].u3 |= BUSY | DRQ; /* set DRQ & BUSY */ dsk_unit[cur_dsk].pos = 0; /* clear counter */ @@ -445,14 +444,14 @@ int32 fdccmd(int32 io, int32 data) if (dsk_dev.dctrl & DEBUG_write) printf("\nfdccmd: Write of disk %d, track %d, sector %d", cur_dsk, dsk_unit[cur_dsk].u4, dsk_unit[cur_dsk].u5); - if (dsk_unit[cur_dsk].u3 & WRPROT) { + if (dsk_unit[cur_dsk].u3 & WRPROT) { printf("\nfdccmd: Drive %d is write-protected", cur_dsk); } else { pos = trksiz * dsk_unit[cur_dsk].u4; /* calculate file offset */ pos += SECSIZ * (dsk_unit[cur_dsk].u5 - 1); if (dsk_dev.dctrl & DEBUG_write) printf("\nfdccmd: Write pos = %ld ($%08X)", pos, (unsigned int) pos); - sim_fseek(dsk_unit[cur_dsk].fileref, pos, 0); /* seek to offset */ + sim_fseek(dsk_unit[cur_dsk].fileref, pos, SEEK_SET); /* seek to offset */ wrt_flag = 1; /* set write flag */ dsk_unit[cur_dsk].u3 |= BUSY | DRQ;/* set DRQ & BUSY */ dsk_unit[cur_dsk].pos = 0; /* clear counter */ @@ -503,8 +502,7 @@ int32 fdctrk(int32 io, int32 data) dsk_unit[cur_dsk].u4 = data & 0xFF; if (dsk_dev.dctrl & DEBUG_read) printf("\nfdctrk: Drive %d track set to %d", cur_dsk, dsk_unit[cur_dsk].u4); - } else - ; + } if (dsk_dev.dctrl & DEBUG_write) printf("\nfdctrk: Drive %d track read as %d", cur_dsk, dsk_unit[cur_dsk].u4); return dsk_unit[cur_dsk].u4; @@ -520,8 +518,7 @@ int32 fdcsec(int32 io, int32 data) dsk_unit[cur_dsk].u5 = 1; if (dsk_dev.dctrl & DEBUG_write) printf("\nfdcsec: Drive %d sector set to %d", cur_dsk, dsk_unit[cur_dsk].u5); - } else - ; + } if (dsk_dev.dctrl & DEBUG_read) printf("\nfdcsec: Drive %d sector read as %d", cur_dsk, dsk_unit[cur_dsk].u5); return dsk_unit[cur_dsk].u5; @@ -538,7 +535,7 @@ int32 fdcdata(int32 io, int32 data) if (dsk_unit[cur_dsk].pos < SECSIZ) { /* copy bytes to buffer */ if (dsk_dev.dctrl & DEBUG_write) printf("\nfdcdata: Writing byte %d of %02X", dsk_unit[cur_dsk].pos, data); - *(uint8 *)(dsk_unit[cur_dsk].filebuf + dsk_unit[cur_dsk].pos) = data; /* byte into buffer */ + *((uint8 *)(dsk_unit[cur_dsk].filebuf) + dsk_unit[cur_dsk].pos) = data; /* byte into buffer */ dsk_unit[cur_dsk].pos++; /* step counter */ if (dsk_unit[cur_dsk].pos == SECSIZ) { dsk_unit[cur_dsk].u3 &= ~(BUSY | DRQ); @@ -552,18 +549,18 @@ int32 fdcdata(int32 io, int32 data) } return 0; } else { /* read byte from fdc */ - if (dsk_unit[cur_dsk].pos < SECSIZ) { /* copy bytes from buffer */ - if (dsk_dev.dctrl & DEBUG_read) - printf("\nfdcdata: Reading byte %d u3=%02X", dsk_unit[cur_dsk].pos, dsk_unit[cur_dsk].u3); - val = *(uint8 *)(dsk_unit[cur_dsk].filebuf + dsk_unit[cur_dsk].pos) & 0xFF; - dsk_unit[cur_dsk].pos++; /* step counter */ - if (dsk_unit[cur_dsk].pos == SECSIZ) { /* done? */ - dsk_unit[cur_dsk].u3 &= ~(BUSY | DRQ); /* clear flags */ - if (dsk_dev.dctrl & DEBUG_write) - printf("\nfdcdata: Sector read complete"); - } - return val; - } else + if (dsk_unit[cur_dsk].pos < SECSIZ) { /* copy bytes from buffer */ + if (dsk_dev.dctrl & DEBUG_read) + printf("\nfdcdata: Reading byte %d u3=%02X", dsk_unit[cur_dsk].pos, dsk_unit[cur_dsk].u3); + val = *((uint8 *)(dsk_unit[cur_dsk].filebuf) + dsk_unit[cur_dsk].pos) & 0xFF; + dsk_unit[cur_dsk].pos++; /* step counter */ + if (dsk_unit[cur_dsk].pos == SECSIZ) { /* done? */ + dsk_unit[cur_dsk].u3 &= ~(BUSY | DRQ); /* clear flags */ + if (dsk_dev.dctrl & DEBUG_write) + printf("\nfdcdata: Sector read complete"); + } + return val; + } else return 0; } } diff --git a/swtp6800/common/i2716.c b/swtp6800/common/i2716.c index 77d4f61e..fe827008 100644 --- a/swtp6800/common/i2716.c +++ b/swtp6800/common/i2716.c @@ -121,7 +121,7 @@ t_stat i2716_attach (UNIT *uptr, char *cptr) printf("\tOpen file\n"); fp = fopen(uptr->filename, "rb"); /* open EPROM file */ if (fp == NULL) { - printf("i2716%d: Unable to open ROM file %s\n", uptr - i2716_dev.units, uptr->filename); + printf("i2716%d: Unable to open ROM file %s\n", (int)(uptr - i2716_dev.units), uptr->filename); printf("\tNo ROM image loaded!!!\n"); return SCPE_OK; } @@ -130,7 +130,7 @@ t_stat i2716_attach (UNIT *uptr, char *cptr) j = 0; /* load EPROM file */ c = fgetc(fp); while (c != EOF) { - *(uint8 *)(uptr->filebuf + j++) = c & 0xFF; + *((uint8 *)(uptr->filebuf) + j++) = c & 0xFF; c = fgetc(fp); if (j > 2048) { printf("\tImage is too large - Load truncated!!!\n"); @@ -150,8 +150,7 @@ t_stat i2716_attach (UNIT *uptr, char *cptr) t_stat i2716_reset (DEVICE *dptr) { - int32 i, j, c, base; - t_stat r; + int32 i, base; UNIT *uptr; if (i2716_dev.dctrl & DEBUG_flow) @@ -207,7 +206,7 @@ int32 i2716_get_mbyte(int32 offset) printf("i2716_get_mbyte: EPROM not configured\n"); return 0xFF; } else { - val = *(uint8 *)(uptr->filebuf + (offset - org)); + val = *((uint8 *)(uptr->filebuf) + (offset - org)); if (i2716_dev.dctrl & DEBUG_read) printf(" val=%04X\n", val); return (val & 0xFF); diff --git a/swtp6800/common/m6800.c b/swtp6800/common/m6800.c index 7ffbe217..31c658e9 100644 --- a/swtp6800/common/m6800.c +++ b/swtp6800/common/m6800.c @@ -88,20 +88,20 @@ /* Macros to handle the flags in the CCR */ #define CCR_ALWAYS_ON (0xC0) /* for 6800 */ #define CCR_MSK (HF|IF|NF|ZF|VF|CF) -#define TOGGLE_FLAG(FLAG) (CCR ^= FLAG) -#define SET_FLAG(FLAG) (CCR |= FLAG) -#define CLR_FLAG(FLAG) (CCR &= ~FLAG) -#define GET_FLAG(FLAG) (CCR & FLAG) +#define TOGGLE_FLAG(FLAG) (CCR ^= (FLAG)) +#define SET_FLAG(FLAG) (CCR |= (FLAG)) +#define CLR_FLAG(FLAG) (CCR &= ~(FLAG)) +#define GET_FLAG(FLAG) (CCR & (FLAG)) #define COND_SET_FLAG(COND,FLAG) \ if (COND) SET_FLAG(FLAG); else CLR_FLAG(FLAG) #define COND_SET_FLAG_N(VAR) \ - if (VAR & 0x80) SET_FLAG(NF); else CLR_FLAG(NF) + if ((VAR) & 0x80) SET_FLAG(NF); else CLR_FLAG(NF) #define COND_SET_FLAG_Z(VAR) \ - if (VAR == 0) SET_FLAG(ZF); else CLR_FLAG(ZF) + if ((VAR) == 0) SET_FLAG(ZF); else CLR_FLAG(ZF) #define COND_SET_FLAG_H(VAR) \ - if (VAR & 0x10) SET_FLAG(HF); else CLR_FLAG(HF) + if ((VAR) & 0x10) SET_FLAG(HF); else CLR_FLAG(HF) #define COND_SET_FLAG_C(VAR) \ - if (VAR & 0x100) SET_FLAG(CF); else CLR_FLAG(CF) + if ((VAR) & 0x100) SET_FLAG(CF); else CLR_FLAG(CF) #define COND_SET_FLAG_V(COND) \ if (COND) SET_FLAG(VF); else CLR_FLAG(VF) @@ -119,9 +119,6 @@ int32 int_req = 0; /* Interrupt request */ int32 mem_fault = 0; /* memory fault flag */ -extern int32 sim_int_char; -extern uint32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ - /* function prototypes */ t_stat m6800_reset (DEVICE *dptr); @@ -151,7 +148,6 @@ extern void CPU_BD_put_mbyte(int32 addr, int32 val); extern void CPU_BD_put_mword(int32 addr, int32 val); extern int32 CPU_BD_get_mbyte(int32 addr); extern int32 CPU_BD_get_mword(int32 addr); -extern int32 sim_switches; /* CPU data structures @@ -303,9 +299,8 @@ int32 oplen[256] = { 3,3,3,0,3,3,3,3,3,3,3,3,0,0,3,3 }; -int32 sim_instr (void) +t_stat sim_instr (void) { - extern int32 sim_interval; int32 IR, OP, DAR, reason, hi, lo, op1; PC = saved_PC & ADDRMASK; /* load local PC */ @@ -316,7 +311,7 @@ int32 sim_instr (void) while (reason == 0) { /* loop until halted */ // dump_regs1(); if (sim_interval <= 0) /* check clock queue */ - if (reason = sim_process_event ()) + if ((reason = sim_process_event ())) break; if (mem_fault) { /* memory fault? */ mem_fault = 0; /* reset fault flag */ @@ -408,7 +403,7 @@ int32 sim_instr (void) DAR += 6; A &= 0xF0; A |= (DAR & 0x0F); - COND_SET_FLAG(DAR & 0x10,CF); + COND_SET_FLAG(DAR & 0x10,CF); } DAR = (A >> 4) & 0x0F; if (DAR > 9 || get_flag(CF)) { @@ -1890,18 +1885,18 @@ int32 get_flag(int32 flg) void condevalVa(int32 op1, int32 op2) { - if (get_flag(CF)) - COND_SET_FLAG_V(((op1 & 0x80) && (op2 & 0x80)) || ( - (op1 & 0x80 == 0) && (op2 & 0x80 == 0))); + if (get_flag(CF)) { + COND_SET_FLAG_V((op1 & op2 & 0x80) || (((op1 | op2) & 0x80) == 0)); + } } /* test and set V for subtraction */ void condevalVs(int32 op1, int32 op2) { - if (get_flag(CF)) - COND_SET_FLAG_V(((op1 & 0x80) && (op2 & 0x80 == 0)) || - ((op1 & 0x80 == 0) && (op2 & 0x80))); + if (get_flag(CF)) { + COND_SET_FLAG_V(op1 & op2 & 0x80); + } } /* calls from the simulator */ @@ -1923,11 +1918,11 @@ t_stat m6800_reset (DEVICE *dptr) /* This is the dumper/loader. This command uses the -h to signify a - hex dump/load vice a binary one. If no address is given to load, it - takes the address from the hex record or the current PC for binary. + hex dump/load vice a binary one. If no address is given to load, it + takes the address from the hex record or the current PC for binary. */ -int32 sim_load (FILE *fileref, char *cptr, char *fnam, int flag) +t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag) { int32 i, addr = 0, cnt = 0; @@ -1955,7 +1950,7 @@ int32 sim_load (FILE *fileref, char *cptr, char *fnam, int flag) for M6800 */ -int32 fprint_sym (FILE *of, int32 addr, uint32 *val, UNIT *uptr, int32 sw) +t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, UNIT *uptr, int32 sw) { int32 i, inst, inst1; @@ -2010,7 +2005,7 @@ int32 fprint_sym (FILE *of, int32 addr, uint32 *val, UNIT *uptr, int32 sw) status = error status */ -int32 parse_sym (char *cptr, int32 addr, UNIT *uptr, uint32 *val, int32 sw) +t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw) { return (-2); } diff --git a/swtp6800/common/m6810.c b/swtp6800/common/m6810.c index 382b6794..3bb5660a 100644 --- a/swtp6800/common/m6810.c +++ b/swtp6800/common/m6810.c @@ -111,12 +111,12 @@ t_stat m6810_reset (DEVICE *dptr) int32 m6810_get_mbyte(int32 offset) { - int32 val, org, len; + int32 val; if (m6810_dev.dctrl & DEBUG_read) printf("m6810_get_mbyte: offset=%04X\n", offset); - if (offset < m6810_unit.capac) { - val = *(uint8 *)(m6810_unit.filebuf + offset) & 0xFF; + if (((t_addr)offset) < m6810_unit.capac) { + val = *((uint8 *)(m6810_unit.filebuf) + offset) & 0xFF; if (m6810_dev.dctrl & DEBUG_read) printf("val=%04X\n", val); return val; @@ -133,8 +133,8 @@ void m6810_put_mbyte(int32 offset, int32 val) { if (m6810_dev.dctrl & DEBUG_write) printf("m6810_put_mbyte: offset=%04X, val=%02X\n", offset, val); - if (offset < m6810_unit.capac) { - *(uint8 *)(m6810_unit.filebuf + offset) = val & 0xFF; + if ((t_addr)offset < m6810_unit.capac) { + *((uint8 *)(m6810_unit.filebuf) + offset) = val & 0xFF; return; } else { if (m6810_dev.dctrl & DEBUG_write) diff --git a/swtp6800/common/mp-8m.c b/swtp6800/common/mp-8m.c index 8b6e9b9a..9126b05a 100644 --- a/swtp6800/common/mp-8m.c +++ b/swtp6800/common/mp-8m.c @@ -120,7 +120,7 @@ t_stat mp_8m_reset (DEVICE *dptr) } for (j=0; j<8192; j++) { /* fill pattern for testing */ val = (0xA0 | i); - *(uint8 *)(uptr->filebuf + j) = val & 0xFF; + *((uint8 *)(uptr->filebuf) + j) = val & 0xFF; } } if (mp_8m_dev.dctrl & DEBUG_flow) @@ -151,7 +151,7 @@ int32 mp_8m_get_mbyte(int32 addr) org = uptr->u3; len = uptr->capac - 1; if ((addr >= org) && (addr <= org + len)) { - val = *(uint8 *)(uptr->filebuf + (addr - org)); + val = *((uint8 *)(uptr->filebuf) + (addr - org)); if (mp_8m_dev.dctrl & DEBUG_read) printf(" val=%04X\n", val); return (val & 0xFF); @@ -177,7 +177,7 @@ int32 mp_8m_get_mword(int32 addr) void mp_8m_put_mbyte(int32 addr, int32 val) { - int32 org, len, type; + int32 org, len; int32 i; UNIT *uptr; @@ -188,7 +188,7 @@ void mp_8m_put_mbyte(int32 addr, int32 val) org = uptr->u3; len = uptr->capac - 1; if ((addr >= org) && (addr < org + len)) { - *(uint8 *)(uptr->filebuf + (addr - org)) = val & 0xFF; + *((uint8 *)(uptr->filebuf) + (addr - org)) = val & 0xFF; if (mp_8m_dev.dctrl & DEBUG_write) printf("\n"); return; diff --git a/swtp6800/common/mp-b2.c b/swtp6800/common/mp-b2.c index 7b93d7d5..bcab28bd 100644 --- a/swtp6800/common/mp-b2.c +++ b/swtp6800/common/mp-b2.c @@ -76,7 +76,7 @@ address is here, 'nulldev' means no device is available */ struct idev { - int32 (*routine)(); + int32 (*routine)(int32, int32); }; struct idev dev_table[32] = { @@ -214,7 +214,10 @@ int32 MB_get_mbyte(int32 addr) } else return 0xFF; case 0x8000: - val = (dev_table[addr - 0x8000].routine(0, 0)) & 0xFF; + if (addr < 0x8020) + val = (dev_table[addr - 0x8000].routine(0, 0)) & 0xFF; + else + val = 0xFF; if (MB_dev.dctrl & DEBUG_read) printf("MB_get_mbyte: I/O addr=%04X val=%02X\n", addr, val); return val; @@ -290,7 +293,8 @@ void MB_put_mbyte(int32 addr, int32 val) return; } case 0x8000: - dev_table[addr - 0x8000].routine(1, val); + if (addr < 0x8020) + dev_table[addr - 0x8000].routine(1, val); return; case 0xA000: case 0xB000: @@ -320,3 +324,4 @@ void MB_put_mword(int32 addr, int32 val) } /* end of mp-b2.c */ + diff --git a/swtp6800/common/mp-s.c b/swtp6800/common/mp-s.c index 6c9c12a3..e3603c7d 100644 --- a/swtp6800/common/mp-s.c +++ b/swtp6800/common/mp-s.c @@ -1,4 +1,4 @@ -/* mp-s.c: SWTP MP-S serial I/O card emulator +/* mp-s.c: SWTP MP-S serial I/O card simulator Copyright (c) 2005-2011, William Beech @@ -43,9 +43,9 @@ +---+---+---+---+---+---+---+---+ RXF - A 1 in this bit position means a character has been received - on the data port and is ready to be read. + on the data port and is ready to be read. TXE - A 1 in this bit means the port is ready to receive a character - on the data port and transmit it out over the serial line. + on the data port and transmit it out over the serial line. A read to the data port gets the buffered character, a write to the data port writes the character to the device. @@ -145,7 +145,7 @@ DEVICE ptp_dev = { /* console input service routine */ -int32 sio_svc (UNIT *uptr) +t_stat sio_svc (UNIT *uptr) { int32 temp; @@ -161,7 +161,7 @@ int32 sio_svc (UNIT *uptr) /* paper tape reader input service routine */ -int32 ptr_svc (UNIT *uptr) +t_stat ptr_svc (UNIT *uptr) { int32 temp; @@ -177,40 +177,41 @@ int32 ptr_svc (UNIT *uptr) /* paper tape punch output service routine */ -int32 ptp_svc (UNIT *uptr) +t_stat ptp_svc (UNIT *uptr) { return SCPE_OK; } /* Reset console */ -int32 sio_reset (DEVICE *dptr) +t_stat sio_reset (DEVICE *dptr) { sio_unit.buf = 0; // Data buffer sio_unit.u3 = 0x02; // Status buffer + sio_unit.wait = 10000; sim_activate (&sio_unit, sio_unit.wait); // activate unit return SCPE_OK; } /* Reset paper tape reader */ -int32 ptr_reset (DEVICE *dptr) +t_stat ptr_reset (DEVICE *dptr) { ptr_unit.buf = 0; ptr_unit.u3 = 0x02; - sim_activate (&ptr_unit, ptr_unit.wait); // activate unit -// sim_cancel (&ptr_unit); // deactivate unit +// sim_activate (&ptr_unit, ptr_unit.wait); // activate unit + sim_cancel (&ptr_unit); // deactivate unit return SCPE_OK; } /* Reset paper tape punch */ -int32 ptp_reset (DEVICE *dptr) +t_stat ptp_reset (DEVICE *dptr) { ptp_unit.buf = 0; ptp_unit.u3 = 0x02; - sim_activate (&ptp_unit, ptp_unit.wait); // activate unit -// sim_cancel (&ptp_unit); // deactivate unit +// sim_activate (&ptp_unit, ptp_unit.wait); // activate unit + sim_cancel (&ptp_unit); // deactivate unit return SCPE_OK; } @@ -265,12 +266,12 @@ int32 sio0d(int32 io, int32 data) } if ((odata = getc(ptr_unit.fileref)) == EOF) { // end of file? // printf("Got EOF\n"); - ptr_unit.u3 &= 0xFE; // clear RXF flag + ptr_unit.u3 &= 0xFE; // clear RXF flag return (odata = 0); // no data } // printf("Returning new %02X\n", odata); ptr_unit.pos++; // step character count - ptr_unit.u3 &= 0xFE; // clear RXF flag + ptr_unit.u3 &= 0xFE; // clear RXF flag return (odata & 0xFF); // return character } else { sio_unit.u3 &= 0xFE; // clear RXF flag @@ -311,10 +312,10 @@ int32 sio0d(int32 io, int32 data) return (odata = 0); } -/* because each port appears at 2 addresses and this fact is used - to determine if it is a MP-C or MP-S repeatedly in the SWTBUG - monitor, this code assures that reads of the high ports return - the same data as was read the last time on the low ports. +/* Because each port appears at 2 addresses and this fact is used + to determine if it is a MP-C or MP-S repeatedly in the SWTBUG + monitor, this code assures that reads of the high ports return + the same data as was read the last time on the low ports. */ int32 sio1s(int32 io, int32 data) @@ -327,4 +328,4 @@ int32 sio1d(int32 io, int32 data) return odata; } -/* end of mp-s.c */ \ No newline at end of file +/* end of mp-s.c */ diff --git a/swtp6800/swtp6800/mp-a_sys.c b/swtp6800/swtp6800/mp-a_sys.c index 4460b781..2bc1afc2 100644 --- a/swtp6800/swtp6800/mp-a_sys.c +++ b/swtp6800/swtp6800/mp-a_sys.c @@ -45,12 +45,12 @@ extern DEVICE dsk_dev; /* SCP data structures - sim_name simulator name string - sim_PC pointer to saved PC register descriptor - sim_emax number of words needed for examine - sim_devices array of pointers to simulated devices - sim_stop_messages array of pointers to stop messages - sim_load binary loader + sim_name simulator name string + sim_PC pointer to saved PC register descriptor + sim_emax number of words needed 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[] = "SWTP 6800, V2, MP-A CPU Board"; diff --git a/swtp6800/swtp6800/swtp_defs.h b/swtp6800/swtp6800/swtp_defs.h index 9a935403..1cbb5232 100644 --- a/swtp6800/swtp6800/swtp_defs.h +++ b/swtp6800/swtp6800/swtp_defs.h @@ -25,14 +25,14 @@ Copyright (c) 2005-2012, William Beech */ #include -#include "../../sim_defs.h" // simulator defs +#include "sim_defs.h" // simulator defs /* Memory */ -#define MAXMEMSIZE 65536 // max memory size -#define MEMSIZE (m6800_unit.capac) // actual memory size -#define ADDRMASK (MAXMEMSIZE - 1) // address mask -#define MEM_ADDR_OK(x) (((uint32) (x)) < MEMSIZE) +#define MAXMEMSIZE 65536 // max memory size +#define MEMSIZE (m6800_unit.capac) // actual memory size +#define ADDRMASK (MAXMEMSIZE - 1) // address mask +#define MEM_ADDR_OK(x) (((uint32) (x)) < MEMSIZE) /* debug definitions */ @@ -47,9 +47,9 @@ Copyright (c) 2005-2012, William Beech /* Simulator stop codes */ -#define STOP_RSRV 1 // must be 1 -#define STOP_HALT 2 // HALT-really WAI -#define STOP_IBKPT 3 // breakpoint -#define STOP_OPCODE 4 // invalid opcode -#define STOP_MEMORY 5 // invalid memory address +#define STOP_RSRV 1 // must be 1 +#define STOP_HALT 2 // HALT-really WAI +#define STOP_IBKPT 3 // breakpoint +#define STOP_OPCODE 4 // invalid opcode +#define STOP_MEMORY 5 // invalid memory address