diff --git a/0readme_32.txt b/0readme_32.txt index 38076c30..65b74b53 100644 --- a/0readme_32.txt +++ b/0readme_32.txt @@ -1,103 +1,64 @@ -Notes For V3.2-0 +Notes For V3.2-1 RESTRICTION: The PDP-15 FPP is only partially debugged. Do NOT enable this feature for normal operations. -WARNING: The core simulator files (scp.c, sim_*.c) have been -reorganized. Unzip V3.2-0 to an empty directory before attempting -to compile the source. - -IMPORTANT: If you are compiling for UNIX, please read the notes -for Ethernet very carefully. You may need to download a new -version of the pcap library, or make changes to the makefile, -to get Ethernet support to work. - -1. New Features in 3.2-0 +1. New Features in 3.2-1 1.1 SCP and libraries -- Added SHOW RADIX command. -- Added SHOW MODIFIERS command. -- Added SHOW NAMES command. -- Added SET/SHOW DEBUG command. -- Added sim_vm_parse_addr and sim_vm_fprint_addr optional interfaces. -- Added REG_VMAD flag. -- Split SCP into separate libraries for easier modification. -- Added more room to the device and unit flag fields. -- Changed terminal multiplexor library to support unlimited. - number of async lines. +- Added SET CONSOLE subhierarchy. +- Added SHOW CONSOLE subhierarchy. +- Added limited keyboard mapping capability. -1.2 All DECtapes +1.2 HP2100 (new features from Dave Bryan) -- Added STOP_EOR flag to enable end-of-reel error stop -- Added device debug support. +- Added instruction printout to HALT message. +- Added M and T internal registers. +- Added N, S, and U breakpoints. -1.3 Nova and Eclipse +1.3 PDP-11 and VAX -- Added QTY and ALM multiplexors (Bruce Ray). +- Added DHQ11 support (from John Dundas) -1.4 LGP-30 +2. Bugs Fixed in 3.2-1 -- Added LGP-30/LGP-21 simulator. +2.1 HP2100 (most fixes from Dave Bryan) -1.5 PDP-11 +- 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. +- Revised IBL facility to conform to microcode. +- Added DMA EDT I/O pseudo-opcode. +- Separated DMA SRQ (service request) from FLG. +- Revised peripherals to make SFS x,C and SFC x,C work. +- Revised boot ROMs to use IBL facility. +- Revised IBL treatment of SR to preserve SR<5:3>. +- Fixed LPS, LPT timing. +- Fixed DP boot interpretation of SR<0>. +- Revised DR boot code to use IBL algorithm. +- Fixed TTY input behavior during typeout for RTE-IV. +- Suppressed nulls on TTY output for RTE-IV. +- Added SFS x,C and SFC x,C to print/parse routines. +- Fixed spurious timing error in magtape reads. -- Added format, address increment inhibit, transfer overrun - detection to RK. -- Added device debug support to HK, RP, TM, TQ, TS. -- Added DEUNA/DELUA (XU) support (Dave Hittner). -- Add DZ per-line logging. +2.2 All DEC console devices -1.6 18b PDP's +- Removed SET TTI CTRL-C option. -- Added support for 1-4 (PDP-9)/1-16 (PDP-15) additional - terminals. +2.3 PDP-11/VAX peripherals -1.7 PDP-10 +- Fixed bug in TQ reporting write protect status (reported by Lyle Bickley). +- Fixed TK70 model number and media ID (found by Robert Schaffrath). +- Fixed bug in autoconfigure (found by John Dundas). -- Added DEUNA/DELUA (XU) support (Dave Hittner). - -1.8 VAX - -- Added extended memory to 512MB (Mark Pizzolato). -- Added RXV21 support. - -2. Bugs Fixed in 3.2-0 - -2.1 SCP - -- Fixed double logging of SHOW BREAK (found by Mark Pizzolato). -- Fixed implementation of REG_VMIO. - -2.2 Nova and Eclipse - -- Fixed device enable/disable support (found by Bruce Ray). - -2.3 PDP-1 - -- Fixed bug in LOAD (found by Mark Crispin). - -2.4 PDP-10 - -- Fixed bug in floating point unpack. -- Fixed bug in FIXR (found by Phil Stone, fixed by Chris Smith). - -2.6 PDP-11 - -- Fixed bug in RQ interrupt control (found by Tom Evans). - -2.6 PDP-18B - -- Fixed bug in PDP-15 XVM g_mode implementation. -- Fixed bug in PDP-15 indexed address calculation. -- Fixed bug in PDP-15 autoindexed address calculation. -- Fixed bugs in FPP-15 instruction decode. -- Fixed clock response to CAF. -- Fixed bug in hardware read-in mode bootstrap. -- Fixed PDP-15 XVM instruction decoding errors. - -2.7 VAX - -- Fixed PC read fault in EXTxV. -- Fixed PC write fault in INSV. +2.4 VAX +- Fixed bug in DIVBx and DIVWx (reported by Peter Trimmel). diff --git a/AltairZ80/altairZ80_defs.h b/AltairZ80/altairZ80_defs.h index 793407db..7eecd9b3 100644 --- a/AltairZ80/altairZ80_defs.h +++ b/AltairZ80/altairZ80_defs.h @@ -1,86 +1,86 @@ -/* altairz80_defs.h: MITS Altair simulator definitions - - Copyright (c) 2002-2004, Peter Schorn - - 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 - PETER SCHORN 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 Peter Schorn shall not - be used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from Peter Schorn. - - Based on work by Charles E Owen (c) 1997 -*/ - -#include "sim_defs.h" /* simulator definitions */ - -#define MAXMEMSIZE 65536 /* maximum memory size */ -#define ADDRMASK (MAXMEMSIZE - 1) /* address mask */ -#define bootrom_size 256 /* size of boot rom */ -#define MAXBANKS 8 /* max number of memory banks */ -#define MAXBANKSLOG2 3 /* log2 of MAXBANKS */ -#define BANKMASK (MAXBANKS-1) /* bank mask */ -#define MEMSIZE (cpu_unit.capac) /* actual memory size */ -#define KB 1024 /* kilo byte */ -#define defaultROMLow 0xff00 /* default for lowest addres of ROM */ -#define defaultROMHigh 0xffff /* default for highest addres of ROM */ - -#define NUM_OF_DSK 8 /* NUM_OF_DSK must be power of two */ -#define LDAInstruction 0x3e /* op-code for LD A,<8-bit value> instruction */ -#define unitNoOffset1 0x37 /* LD A, */ -#define unitNoOffset2 0xb4 /* LD a,80h | */ - -#define UNIT_V_OPSTOP (UNIT_V_UF+0) /* stop on nvalid operation */ -#define UNIT_OPSTOP (1 << UNIT_V_OPSTOP) -#define UNIT_V_CHIP (UNIT_V_UF+1) /* 8080 or Z80 CPU */ -#define UNIT_CHIP (1 << UNIT_V_CHIP) -#define UNIT_V_MSIZE (UNIT_V_UF+2) /* memory size */ -#define UNIT_MSIZE (1 << UNIT_V_MSIZE) -#define UNIT_V_BANKED (UNIT_V_UF+3) /* banked memory is used */ -#define UNIT_BANKED (1 << UNIT_V_BANKED) -#define UNIT_V_ROM (UNIT_V_UF+4) /* ROM exists */ -#define UNIT_ROM (1 << UNIT_V_ROM) -#define UNIT_V_ALTAIRROM (UNIT_V_UF+5) /* ALTAIR ROM exists */ -#define UNIT_ALTAIRROM (1 << UNIT_V_ALTAIRROM) -#define UNIT_V_WARNROM (UNIT_V_UF+6) /* warn if ROM is written to */ -#define UNIT_WARNROM (1 << UNIT_V_WARNROM) - -#define AddressFormat "[%04xh]" -#define PCformat "\n" AddressFormat " " -#define message1(p1) \ - sprintf(messageBuffer,PCformat p1,PCX); printMessage() -#define message2(p1,p2) \ - sprintf(messageBuffer,PCformat p1,PCX,p2); printMessage() -#define message3(p1,p2,p3) \ - sprintf(messageBuffer,PCformat p1,PCX,p2,p3); printMessage() -#define message4(p1,p2,p3,p4) \ - sprintf(messageBuffer,PCformat p1,PCX,p2,p3,p4); printMessage() -#define message5(p1,p2,p3,p4,p5) \ - sprintf(messageBuffer,PCformat p1,PCX,p2,p3,p4,p5); printMessage() -#define message6(p1,p2,p3,p4,p5,p6) \ - sprintf(messageBuffer,PCformat p1,PCX,p2,p3,p4,p5,p6); printMessage() - -/* The Default is to use "inline". */ -#if defined(NO_INLINE) -#define INLINE -#else -#if defined(__DECC) && defined(VMS) -#define INLINE __inline -#else -#define INLINE inline -#endif -#endif +/* altairz80_defs.h: MITS Altair simulator definitions + + Copyright (c) 2002-2004, Peter Schorn + + 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 + PETER SCHORN 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 Peter Schorn shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Peter Schorn. + + Based on work by Charles E Owen (c) 1997 +*/ + +#include "sim_defs.h" /* simulator definitions */ + +#define MAXMEMSIZE 65536 /* maximum memory size */ +#define ADDRMASK (MAXMEMSIZE - 1) /* address mask */ +#define bootrom_size 256 /* size of boot rom */ +#define MAXBANKS 8 /* max number of memory banks */ +#define MAXBANKSLOG2 3 /* log2 of MAXBANKS */ +#define BANKMASK (MAXBANKS-1) /* bank mask */ +#define MEMSIZE (cpu_unit.capac) /* actual memory size */ +#define KB 1024 /* kilo byte */ +#define defaultROMLow 0xff00 /* default for lowest addres of ROM */ +#define defaultROMHigh 0xffff /* default for highest addres of ROM */ + +#define NUM_OF_DSK 8 /* NUM_OF_DSK must be power of two */ +#define LDAInstruction 0x3e /* op-code for LD A,<8-bit value> instruction */ +#define unitNoOffset1 0x37 /* LD A, */ +#define unitNoOffset2 0xb4 /* LD a,80h | */ + +#define UNIT_V_OPSTOP (UNIT_V_UF+0) /* stop on nvalid operation */ +#define UNIT_OPSTOP (1 << UNIT_V_OPSTOP) +#define UNIT_V_CHIP (UNIT_V_UF+1) /* 8080 or Z80 CPU */ +#define UNIT_CHIP (1 << UNIT_V_CHIP) +#define UNIT_V_MSIZE (UNIT_V_UF+2) /* memory size */ +#define UNIT_MSIZE (1 << UNIT_V_MSIZE) +#define UNIT_V_BANKED (UNIT_V_UF+3) /* banked memory is used */ +#define UNIT_BANKED (1 << UNIT_V_BANKED) +#define UNIT_V_ROM (UNIT_V_UF+4) /* ROM exists */ +#define UNIT_ROM (1 << UNIT_V_ROM) +#define UNIT_V_ALTAIRROM (UNIT_V_UF+5) /* ALTAIR ROM exists */ +#define UNIT_ALTAIRROM (1 << UNIT_V_ALTAIRROM) +#define UNIT_V_WARNROM (UNIT_V_UF+6) /* warn if ROM is written to */ +#define UNIT_WARNROM (1 << UNIT_V_WARNROM) + +#define AddressFormat "[%04xh]" +#define PCformat "\n" AddressFormat " " +#define message1(p1) \ + sprintf(messageBuffer,PCformat p1,PCX); printMessage() +#define message2(p1,p2) \ + sprintf(messageBuffer,PCformat p1,PCX,p2); printMessage() +#define message3(p1,p2,p3) \ + sprintf(messageBuffer,PCformat p1,PCX,p2,p3); printMessage() +#define message4(p1,p2,p3,p4) \ + sprintf(messageBuffer,PCformat p1,PCX,p2,p3,p4); printMessage() +#define message5(p1,p2,p3,p4,p5) \ + sprintf(messageBuffer,PCformat p1,PCX,p2,p3,p4,p5); printMessage() +#define message6(p1,p2,p3,p4,p5,p6) \ + sprintf(messageBuffer,PCformat p1,PCX,p2,p3,p4,p5,p6); printMessage() + +/* The Default is to use "inline". */ +#if defined(NO_INLINE) +#define INLINE +#else +#if defined(__DECC) && defined(VMS) +#define INLINE __inline +#else +#define INLINE inline +#endif +#endif diff --git a/AltairZ80/altairZ80_sys.c b/AltairZ80/altairZ80_sys.c index 51bdb4b9..0fc65a78 100644 --- a/AltairZ80/altairZ80_sys.c +++ b/AltairZ80/altairZ80_sys.c @@ -1,719 +1,719 @@ -/* altairz80_sys.c: MITS Altair system interface - - Copyright (c) 2002-2004, Peter Schorn - - 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 - PETER SCHORN 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 Peter Schorn shall not - be used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from Peter Schorn. - - Based on work by Charles E Owen (c) 1997 - Disassembler from Marat Fayzullin ((c) 1995, 1996, 1997 - Commercial use prohibited) -*/ - -#include -#include "altairz80_defs.h" - -extern DEVICE cpu_dev; -extern DEVICE dsk_dev; -extern DEVICE hdsk_dev; -extern UNIT cpu_unit; -extern REG cpu_reg[]; -extern DEVICE sio_dev; -extern DEVICE simh_device; -extern DEVICE ptr_dev; -extern DEVICE ptp_dev; -extern int32 saved_PC; - -int32 fprint_sym(FILE *of, int32 addr, uint32 *val, UNIT *uptr, int32 sw); -static int32 checkbase(char ch, const char *numString); -static int32 numok(char ch, const char **numString, const int32 minvalue, - const int32 maxvalue, const int32 requireSign, int32 *result); -static int32 match(const char *pattern, const char *input, char *xyFirst, char *xy, int32 *number, int32 *star, int32 *at, - int32 *hat, int32 *dollar); -static int32 parse_X80(const char *cptr, const int32 addr, uint32 *val, char *const Mnemonics[]); -int32 parse_sym(char *cptr, int32 addr, UNIT *uptr, uint32 *val, int32 sw); -static int32 DAsm(char *S, const uint32 *val, const int32 useZ80Mnemonics, const int32 addr); -static int32 checkXY(const char xy); - -/* 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 -*/ - -char sim_name[] = "Altair 8800 (Z80)"; -REG *sim_PC = &cpu_reg[0]; -int32 sim_emax = 4; -DEVICE *sim_devices[] = { &cpu_dev, &sio_dev, &simh_device, &ptr_dev, &ptp_dev, &dsk_dev, &hdsk_dev, NULL }; - -char memoryAccessMessage[80]; -const char *sim_stop_messages[] = { - "HALT instruction", - "Breakpoint", - memoryAccessMessage, - "Invalid Opcode" }; - -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 */ - "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 */ - "MOV E,B", "MOV E,C", "MOV E,D", "MOV E,E", "MOV E,H", "MOV E,L", "MOV E,M", "MOV E,A", /* 58-5f */ - "MOV H,B", "MOV H,C", "MOV H,D", "MOV H,E", "MOV H,H", "MOV H,L", "MOV H,M", "MOV H,A", /* 60-67 */ - "MOV L,B", "MOV L,C", "MOV L,D", "MOV L,E", "MOV L,H", "MOV L,L", "MOV L,M", "MOV L,A", /* 68-6f */ - "MOV M,B", "MOV M,C", "MOV M,D", "MOV M,E", "MOV M,H", "MOV M,L", "HLT", "MOV M,A", /* 70-77 */ - "MOV A,B", "MOV A,C", "MOV A,D", "MOV A,E", "MOV A,H", "MOV A,L", "MOV A,M", "MOV A,A", /* 78-7f */ - "ADD B", "ADD C", "ADD D", "ADD E", "ADD H", "ADD L", "ADD M", "ADD A", /* 80-87 */ - "ADC B", "ADC C", "ADC D", "ADC E", "ADC H", "ADC L", "ADC M", "ADC A", /* 88-8f */ - "SUB B", "SUB C", "SUB D", "SUB E", "SUB H", "SUB L", "SUB M", "SUB A", /* 90-97 */ - "SBB B", "SBB C", "SBB D", "SBB E", "SBB H", "SBB L", "SBB M", "SBB A", /* 98-9f */ - "ANA B", "ANA C", "ANA D", "ANA E", "ANA H", "ANA L", "ANA M", "ANA A", /* a0-a7 */ - "XRA B", "XRA C", "XRA D", "XRA E", "XRA H", "XRA L", "XRA M", "XRA A", /* a8-af */ - "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 */ - "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 */ - "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 */ - "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 */ - }; - -static char *const MnemonicsZ80[256] = { -/*0/8 1/9 2/A 3/B 4/C 5/D 6/E 7/F */ - "NOP", "LD BC,#h", "LD (BC),A", "INC BC", "INC B", "DEC B", "LD B,*h", "RLCA", /* 00-07 */ - "EX AF,AF'", "ADD HL,BC", "LD A,(BC)", "DEC BC", "INC C", "DEC C", "LD C,*h", "RRCA", /* 08-0f */ - "DJNZ $h", "LD DE,#h", "LD (DE),A", "INC DE", "INC D", "DEC D", "LD D,*h", "RLA", /* 10-17 */ - "JR $h", "ADD HL,DE", "LD A,(DE)", "DEC DE", "INC E", "DEC E", "LD E,*h", "RRA", /* 18-1f */ - "JR NZ,$h", "LD HL,#h", "LD (#h),HL", "INC HL", "INC H", "DEC H", "LD H,*h", "DAA", /* 20-27 */ - "JR Z,$h", "ADD HL,HL", "LD HL,(#h)", "DEC HL", "INC L", "DEC L", "LD L,*h", "CPL", /* 28-2f */ - "JR NC,$h", "LD SP,#h", "LD (#h),A", "INC SP", "INC (HL)", "DEC (HL)", "LD (HL),*h", "SCF", /* 30-37 */ - "JR C,$h", "ADD HL,SP", "LD A,(#h)", "DEC SP", "INC A", "DEC A", "LD A,*h", "CCF", /* 38-3f */ - "LD B,B", "LD B,C", "LD B,D", "LD B,E", "LD B,H", "LD B,L", "LD B,(HL)", "LD B,A", /* 40-47 */ - "LD C,B", "LD C,C", "LD C,D", "LD C,E", "LD C,H", "LD C,L", "LD C,(HL)", "LD C,A", /* 48-4f */ - "LD D,B", "LD D,C", "LD D,D", "LD D,E", "LD D,H", "LD D,L", "LD D,(HL)", "LD D,A", /* 50-57 */ - "LD E,B", "LD E,C", "LD E,D", "LD E,E", "LD E,H", "LD E,L", "LD E,(HL)", "LD E,A", /* 58-5f */ - "LD H,B", "LD H,C", "LD H,D", "LD H,E", "LD H,H", "LD H,L", "LD H,(HL)", "LD H,A", /* 60-67 */ - "LD L,B", "LD L,C", "LD L,D", "LD L,E", "LD L,H", "LD L,L", "LD L,(HL)", "LD L,A", /* 68-6f */ - "LD (HL),B", "LD (HL),C", "LD (HL),D", "LD (HL),E", "LD (HL),H", "LD (HL),L", "HALT", "LD (HL),A", /* 70-77 */ - "LD A,B", "LD A,C", "LD A,D", "LD A,E", "LD A,H", "LD A,L", "LD A,(HL)", "LD A,A", /* 78-7f */ - "ADD A,B", "ADD A,C", "ADD A,D", "ADD A,E", "ADD A,H", "ADD A,L", "ADD A,(HL)", "ADD A,A", /* 80-87 */ - "ADC A,B", "ADC A,C", "ADC A,D", "ADC A,E", "ADC A,H", "ADC A,L", "ADC A,(HL)", "ADC A,A", /* 88-8f */ - "SUB B", "SUB C", "SUB D", "SUB E", "SUB H", "SUB L", "SUB (HL)", "SUB A", /* 90-97 */ - "SBC A,B", "SBC A,C", "SBC A,D", "SBC A,E", "SBC A,H", "SBC A,L", "SBC A,(HL)", "SBC A,A", /* 98-9f */ - "AND B", "AND C", "AND D", "AND E", "AND H", "AND L", "AND (HL)", "AND A", /* a0-a7 */ - "XOR B", "XOR C", "XOR D", "XOR E", "XOR H", "XOR L", "XOR (HL)", "XOR A", /* a8-af */ - "OR B", "OR C", "OR D", "OR E", "OR H", "OR L", "OR (HL)", "OR A", /* b0-b7 */ - "CP B", "CP C", "CP D", "CP E", "CP H", "CP L", "CP (HL)", "CP A", /* b8-bf */ - "RET NZ", "POP BC", "JP NZ,#h", "JP #h", "CALL NZ,#h", "PUSH BC", "ADD A,*h", "RST 00h", /* c0-c7 */ - "RET Z", "RET", "JP Z,#h", "PFX_CB", "CALL Z,#h", "CALL #h", "ADC A,*h", "RST 08h", /* c8-cf */ - "RET NC", "POP DE", "JP NC,#h", "OUT (*h),A", "CALL NC,#h", "PUSH DE", "SUB *h", "RST 10h", /* d0-d7 */ - "RET C", "EXX", "JP C,#h", "IN A,(*h)", "CALL C,#h", "PFX_DD", "SBC A,*h", "RST 18h", /* d8-df */ - "RET PO", "POP HL", "JP PO,#h", "EX (SP),HL", "CALL PO,#h", "PUSH HL", "AND *h", "RST 20h", /* e0-e7 */ - "RET PE", "LD PC,HL", "JP PE,#h", "EX DE,HL", "CALL PE,#h", "PFX_ED", "XOR *h", "RST 28h", /* e8-ef */ - "RET P", "POP AF", "JP P,#h", "DI", "CALL P,#h", "PUSH AF", "OR *h", "RST 30h", /* f0-f7 */ - "RET M", "LD SP,HL", "JP M,#h", "EI", "CALL M,#h", "PFX_FD", "CP *h", "RST 38h" /* f8-ff */ -}; - -static char *const MnemonicsCB[256] = { -/*0/8 1/9 2/A 3/B 4/C 5/D 6/E 7/F */ - "RLC B", "RLC C", "RLC D", "RLC E", "RLC H", "RLC L", "RLC (HL)", "RLC A", /* 00-07 */ - "RRC B", "RRC C", "RRC D", "RRC E", "RRC H", "RRC L", "RRC (HL)", "RRC A", /* 08-0f */ - "RL B", "RL C", "RL D", "RL E", "RL H", "RL L", "RL (HL)", "RL A", /* 10-17 */ - "RR B", "RR C", "RR D", "RR E", "RR H", "RR L", "RR (HL)", "RR A", /* 18-1f */ - "SLA B", "SLA C", "SLA D", "SLA E", "SLA H", "SLA L", "SLA (HL)", "SLA A", /* 20-27 */ - "SRA B", "SRA C", "SRA D", "SRA E", "SRA H", "SRA L", "SRA (HL)", "SRA A", /* 28-2f */ - "SLL B", "SLL C", "SLL D", "SLL E", "SLL H", "SLL L", "SLL (HL)", "SLL A", /* 30-37 */ - "SRL B", "SRL C", "SRL D", "SRL E", "SRL H", "SRL L", "SRL (HL)", "SRL A", /* 38-3f */ - "BIT 0,B", "BIT 0,C", "BIT 0,D", "BIT 0,E", "BIT 0,H", "BIT 0,L", "BIT 0,(HL)", "BIT 0,A", /* 40-47 */ - "BIT 1,B", "BIT 1,C", "BIT 1,D", "BIT 1,E", "BIT 1,H", "BIT 1,L", "BIT 1,(HL)", "BIT 1,A", /* 48-4f */ - "BIT 2,B", "BIT 2,C", "BIT 2,D", "BIT 2,E", "BIT 2,H", "BIT 2,L", "BIT 2,(HL)", "BIT 2,A", /* 50-57 */ - "BIT 3,B", "BIT 3,C", "BIT 3,D", "BIT 3,E", "BIT 3,H", "BIT 3,L", "BIT 3,(HL)", "BIT 3,A", /* 58-5f */ - "BIT 4,B", "BIT 4,C", "BIT 4,D", "BIT 4,E", "BIT 4,H", "BIT 4,L", "BIT 4,(HL)", "BIT 4,A", /* 60-67 */ - "BIT 5,B", "BIT 5,C", "BIT 5,D", "BIT 5,E", "BIT 5,H", "BIT 5,L", "BIT 5,(HL)", "BIT 5,A", /* 68-6f */ - "BIT 6,B", "BIT 6,C", "BIT 6,D", "BIT 6,E", "BIT 6,H", "BIT 6,L", "BIT 6,(HL)", "BIT 6,A", /* 70-77 */ - "BIT 7,B", "BIT 7,C", "BIT 7,D", "BIT 7,E", "BIT 7,H", "BIT 7,L", "BIT 7,(HL)", "BIT 7,A", /* 78-7f */ - "RES 0,B", "RES 0,C", "RES 0,D", "RES 0,E", "RES 0,H", "RES 0,L", "RES 0,(HL)", "RES 0,A", /* 80-87 */ - "RES 1,B", "RES 1,C", "RES 1,D", "RES 1,E", "RES 1,H", "RES 1,L", "RES 1,(HL)", "RES 1,A", /* 88-8f */ - "RES 2,B", "RES 2,C", "RES 2,D", "RES 2,E", "RES 2,H", "RES 2,L", "RES 2,(HL)", "RES 2,A", /* 90-97 */ - "RES 3,B", "RES 3,C", "RES 3,D", "RES 3,E", "RES 3,H", "RES 3,L", "RES 3,(HL)", "RES 3,A", /* 98-9f */ - "RES 4,B", "RES 4,C", "RES 4,D", "RES 4,E", "RES 4,H", "RES 4,L", "RES 4,(HL)", "RES 4,A", /* a0-a7 */ - "RES 5,B", "RES 5,C", "RES 5,D", "RES 5,E", "RES 5,H", "RES 5,L", "RES 5,(HL)", "RES 5,A", /* a8-af */ - "RES 6,B", "RES 6,C", "RES 6,D", "RES 6,E", "RES 6,H", "RES 6,L", "RES 6,(HL)", "RES 6,A", /* b0-b7 */ - "RES 7,B", "RES 7,C", "RES 7,D", "RES 7,E", "RES 7,H", "RES 7,L", "RES 7,(HL)", "RES 7,A", /* b8-bf */ - "SET 0,B", "SET 0,C", "SET 0,D", "SET 0,E", "SET 0,H", "SET 0,L", "SET 0,(HL)", "SET 0,A", /* c0-c7 */ - "SET 1,B", "SET 1,C", "SET 1,D", "SET 1,E", "SET 1,H", "SET 1,L", "SET 1,(HL)", "SET 1,A", /* c8-cf */ - "SET 2,B", "SET 2,C", "SET 2,D", "SET 2,E", "SET 2,H", "SET 2,L", "SET 2,(HL)", "SET 2,A", /* d0-d7 */ - "SET 3,B", "SET 3,C", "SET 3,D", "SET 3,E", "SET 3,H", "SET 3,L", "SET 3,(HL)", "SET 3,A", /* d8-df */ - "SET 4,B", "SET 4,C", "SET 4,D", "SET 4,E", "SET 4,H", "SET 4,L", "SET 4,(HL)", "SET 4,A", /* e0-e7 */ - "SET 5,B", "SET 5,C", "SET 5,D", "SET 5,E", "SET 5,H", "SET 5,L", "SET 5,(HL)", "SET 5,A", /* e8-ef */ - "SET 6,B", "SET 6,C", "SET 6,D", "SET 6,E", "SET 6,H", "SET 6,L", "SET 6,(HL)", "SET 6,A", /* f0-f7 */ - "SET 7,B", "SET 7,C", "SET 7,D", "SET 7,E", "SET 7,H", "SET 7,L", "SET 7,(HL)", "SET 7,A" /* f8-ff */ -}; - -static char *const MnemonicsED[256] = { -/*0/8 1/9 2/A 3/B 4/C 5/D 6/E 7/F */ - "DB EDh,00h", "DB EDh,01h", "DB EDh,02h", "DB EDh,03h", "DB EDh,04h", "DB EDh,05h", "DB EDh,06h", "DB EDh,07h", /* 00-07 */ - "DB EDh,08h", "DB EDh,09h", "DB EDh,0Ah", "DB EDh,0Bh", "DB EDh,0Ch", "DB EDh,0Dh", "DB EDh,0Eh", "DB EDh,0Fh", /* 08-0f */ - "DB EDh,10h", "DB EDh,11h", "DB EDh,12h", "DB EDh,13h", "DB EDh,14h", "DB EDh,15h", "DB EDh,16h", "DB EDh,17h", /* 10-17 */ - "DB EDh,18h", "DB EDh,19h", "DB EDh,1Ah", "DB EDh,1Bh", "DB EDh,1Ch", "DB EDh,1Dh", "DB EDh,1Eh", "DB EDh,1Fh", /* 18-1f */ - "DB EDh,20h", "DB EDh,21h", "DB EDh,22h", "DB EDh,23h", "DB EDh,24h", "DB EDh,25h", "DB EDh,26h", "DB EDh,27h", /* 20-27 */ - "DB EDh,28h", "DB EDh,29h", "DB EDh,2Ah", "DB EDh,2Bh", "DB EDh,2Ch", "DB EDh,2Dh", "DB EDh,2Eh", "DB EDh,2Fh", /* 28-2f */ - "DB EDh,30h", "DB EDh,31h", "DB EDh,32h", "DB EDh,33h", "DB EDh,34h", "DB EDh,35h", "DB EDh,36h", "DB EDh,37h", /* 30-37 */ - "DB EDh,38h", "DB EDh,39h", "DB EDh,3Ah", "DB EDh,3Bh", "DB EDh,3Ch", "DB EDh,3Dh", "DB EDh,3Eh", "DB EDh,3Fh", /* 38-3f */ - "IN B,(C)", "OUT (C),B", "SBC HL,BC", "LD (#h),BC", "NEG", "RETN", "IM 0", "LD I,A", /* 40-47 */ - "IN C,(C)", "OUT (C),C", "ADC HL,BC", "LD BC,(#h)", "DB EDh,4Ch", "RETI", "DB EDh,4Eh", "LD R,A", /* 48-4f */ - "IN D,(C)", "OUT (C),D", "SBC HL,DE", "LD (#h),DE", "DB EDh,54h", "DB EDh,55h", "IM 1", "LD A,I", /* 50-57 */ - "IN E,(C)", "OUT (C),E", "ADC HL,DE", "LD DE,(#h)", "DB EDh,5Ch", "DB EDh,5Dh", "IM 2", "LD A,R", /* 58-5f */ - "IN H,(C)", "OUT (C),H", "SBC HL,HL", "LD (#h),HL", "DB EDh,64h", "DB EDh,65h", "DB EDh,66h", "RRD", /* 60-67 */ - "IN L,(C)", "OUT (C),L", "ADC HL,HL", "LD HL,(#h)", "DB EDh,6Ch", "DB EDh,6Dh", "DB EDh,6Eh", "RLD", /* 68-6f */ - "IN F,(C)", "DB EDh,71h", "SBC HL,SP", "LD (#h),SP", "DB EDh,74h", "DB EDh,75h", "DB EDh,76h", "DB EDh,77h", /* 70-77 */ - "IN A,(C)", "OUT (C),A", "ADC HL,SP", "LD SP,(#h)", "DB EDh,7Ch", "DB EDh,7Dh", "DB EDh,7Eh", "DB EDh,7Fh", /* 78-7f */ - "DB EDh,80h", "DB EDh,81h", "DB EDh,82h", "DB EDh,83h", "DB EDh,84h", "DB EDh,85h", "DB EDh,86h", "DB EDh,87h", /* 80-87 */ - "DB EDh,88h", "DB EDh,89h", "DB EDh,8Ah", "DB EDh,8Bh", "DB EDh,8Ch", "DB EDh,8Dh", "DB EDh,8Eh", "DB EDh,8Fh", /* 88-8f */ - "DB EDh,90h", "DB EDh,91h", "DB EDh,92h", "DB EDh,93h", "DB EDh,94h", "DB EDh,95h", "DB EDh,96h", "DB EDh,97h", /* 90-97 */ - "DB EDh,98h", "DB EDh,99h", "DB EDh,9Ah", "DB EDh,9Bh", "DB EDh,9Ch", "DB EDh,9Dh", "DB EDh,9Eh", "DB EDh,9Fh", /* 98-9f */ - "LDI", "CPI", "INI", "OUTI", "DB EDh,A4h", "DB EDh,A5h", "DB EDh,A6h", "DB EDh,A7h", /* a0-a7 */ - "LDD", "CPD", "IND", "OUTD", "DB EDh,ACh", "DB EDh,ADh", "DB EDh,AEh", "DB EDh,AFh", /* a8-af */ - "LDIR", "CPIR", "INIR", "OTIR", "DB EDh,B4h", "DB EDh,B5h", "DB EDh,B6h", "DB EDh,B7h", /* b0-b7 */ - "LDDR", "CPDR", "INDR", "OTDR", "DB EDh,BCh", "DB EDh,BDh", "DB EDh,BEh", "DB EDh,BFh", /* b8-bf */ - "DB EDh,C0h", "DB EDh,C1h", "DB EDh,C2h", "DB EDh,C3h", "DB EDh,C4h", "DB EDh,C5h", "DB EDh,C6h", "DB EDh,C7h", /* c0-c7 */ - "DB EDh,C8h", "DB EDh,C9h", "DB EDh,CAh", "DB EDh,CBh", "DB EDh,CCh", "DB EDh,CDh", "DB EDh,CEh", "DB EDh,CFh", /* c8-cf */ - "DB EDh,D0h", "DB EDh,D1h", "DB EDh,D2h", "DB EDh,D3h", "DB EDh,D4h", "DB EDh,D5h", "DB EDh,D6h", "DB EDh,D7h", /* d0-d7 */ - "DB EDh,D8h", "DB EDh,D9h", "DB EDh,DAh", "DB EDh,DBh", "DB EDh,DCh", "DB EDh,DDh", "DB EDh,DEh", "DB EDh,DFh", /* d8-df */ - "DB EDh,E0h", "DB EDh,E1h", "DB EDh,E2h", "DB EDh,E3h", "DB EDh,E4h", "DB EDh,E5h", "DB EDh,E6h", "DB EDh,E7h", /* e0-e7 */ - "DB EDh,E8h", "DB EDh,E9h", "DB EDh,EAh", "DB EDh,EBh", "DB EDh,ECh", "DB EDh,EDh", "DB EDh,EEh", "DB EDh,EFh", /* e8-ef */ - "DB EDh,F0h", "DB EDh,F1h", "DB EDh,F2h", "DB EDh,F3h", "DB EDh,F4h", "DB EDh,F5h", "DB EDh,F6h", "DB EDh,F7h", /* f0-f7 */ - "DB EDh,F8h", "DB EDh,F9h", "DB EDh,FAh", "DB EDh,FBh", "DB EDh,FCh", "DB EDh,FDh", "DB EDh,FEh", "DB EDh,FFh" /* f8-ff */ -}; - -static char *const MnemonicsXX[256] = { -/*0/8 1/9 2/A 3/B 4/C 5/D 6/E 7/F */ - "NOP", "LD BC,#h", "LD (BC),A", "INC BC", "INC B", "DEC B", "LD B,*h", "RLCA", /* 00-07 */ - "EX AF,AF'", "ADD I%,BC", "LD A,(BC)", "DEC BC", "INC C", "DEC C", "LD C,*h", "RRCA", /* 08-0f */ - "DJNZ $h", "LD DE,#h", "LD (DE),A", "INC DE", "INC D", "DEC D", "LD D,*h", "RLA", /* 10-17 */ - "JR $h", "ADD I%,DE", "LD A,(DE)", "DEC DE", "INC E", "DEC E", "LD E,*h", "RRA", /* 18-1f */ - "JR NZ,$h", "LD I%,#h", "LD (#h),I%", "INC I%", "INC I%H", "DEC I%H", "LD I%H,*h", "DAA", /* 20-27 */ - "JR Z,$h", "ADD I%,I%", "LD I%,(#h)", "DEC I%", "INC I%L", "DEC I%L", "LD I%L,*h", "CPL", /* 28-2f */ - "JR NC,$h", "LD SP,#h", "LD (#h),A", "INC SP", "INC (I%+^h)", "DEC (I%+^h)", "LD (I%+^h),*h", "SCF", /* 30-37 */ - "JR C,$h", "ADD I%,SP", "LD A,(#h)", "DEC SP", "INC A", "DEC A", "LD A,*h", "CCF", /* 38-3f */ - "LD B,B", "LD B,C", "LD B,D", "LD B,E", "LD B,I%H", "LD B,I%L", "LD B,(I%+^h)", "LD B,A", /* 40-47 */ - "LD C,B", "LD C,C", "LD C,D", "LD C,E", "LD C,I%H", "LD C,I%L", "LD C,(I%+^h)", "LD C,A", /* 48-4f */ - "LD D,B", "LD D,C", "LD D,D", "LD D,E", "LD D,I%H", "LD D,I%L", "LD D,(I%+^h)", "LD D,A", /* 50-57 */ - "LD E,B", "LD E,C", "LD E,D", "LD E,E", "LD E,I%H", "LD E,I%L", "LD E,(I%+^h)", "LD E,A", /* 58-5f */ - "LD I%H,B", "LD I%H,C", "LD I%H,D", "LD I%H,E", "LD I%H,I%H", "LD I%H,I%L", "LD H,(I%+^h)", "LD I%H,A", /* 60-67 */ - "LD I%L,B", "LD I%L,C", "LD I%L,D", "LD I%L,E", "LD I%L,I%H", "LD I%L,I%L", "LD L,(I%+^h)", "LD I%L,A", /* 68-6f */ - "LD (I%+^h),B", "LD (I%+^h),C", "LD (I%+^h),D", "LD (I%+^h),E", "LD (I%+^h),H", "LD (I%+^h),L", "HALT", "LD (I%+^h),A", /* 70-77 */ - "LD A,B", "LD A,C", "LD A,D", "LD A,E", "LD A,I%H", "LD A,I%L", "LD A,(I%+^h)", "LD A,A", /* 78-7f */ - "ADD A,B", "ADD A,C", "ADD A,D", "ADD A,E", "ADD A,I%H", "ADD A,I%L", "ADD A,(I%+^h)", "ADD A,A", /* 80-87 */ - "ADC A,B", "ADC A,C", "ADC A,D", "ADC A,E", "ADC A,I%H", "ADC A,I%L", "ADC A,(I%+^h)", "ADC A,A", /* 88-8f */ - "SUB B", "SUB C", "SUB D", "SUB E", "SUB I%H", "SUB I%L", "SUB (I%+^h)", "SUB A", /* 90-97 */ - "SBC A,B", "SBC A,C", "SBC A,D", "SBC A,E", "SBC A,I%H", "SBC A,I%L", "SBC A,(I%+^h)", "SBC A,A", /* 98-9f */ - "AND B", "AND C", "AND D", "AND E", "AND I%H", "AND I%L", "AND (I%+^h)", "AND A", /* a0-a7 */ - "XOR B", "XOR C", "XOR D", "XOR E", "XOR I%H", "XOR I%L", "XOR (I%+^h)", "XOR A", /* a8-af */ - "OR B", "OR C", "OR D", "OR E", "OR I%H", "OR I%L", "OR (I%+^h)", "OR A", /* b0-b7 */ - "CP B", "CP C", "CP D", "CP E", "CP I%H", "CP I%L", "CP (I%+^h)", "CP A", /* b8-bf */ - "RET NZ", "POP BC", "JP NZ,#h", "JP #h", "CALL NZ,#h", "PUSH BC", "ADD A,*h", "RST 00h", /* c8-cf */ - "RET Z", "RET", "JP Z,#h", "PFX_CB", "CALL Z,#h", "CALL #h", "ADC A,*h", "RST 08h", /* c8-cf */ - "RET NC", "POP DE", "JP NC,#h", "OUT (*h),A", "CALL NC,#h", "PUSH DE", "SUB *h", "RST 10h", /* d0-d7 */ - "RET C", "EXX", "JP C,#h", "IN A,(*h)", "CALL C,#h", "PFX_DD", "SBC A,*h", "RST 18h", /* d8-df */ - "RET PO", "POP I%", "JP PO,#h", "EX (SP),I%", "CALL PO,#h", "PUSH I%", "AND *h", "RST 20h", /* e0-e7 */ - "RET PE", "LD PC,I%", "JP PE,#h", "EX DE,I%", "CALL PE,#h", "PFX_ED", "XOR *h", "RST 28h", /* e8-ef */ - "RET P", "POP AF", "JP P,#h", "DI", "CALL P,#h", "PUSH AF", "OR *h", "RST 30h", /* f0-f7 */ - "RET M", "LD SP,I%", "JP M,#h", "EI", "CALL M,#h", "PFX_FD", "CP *h", "RST 38h" /* f8-ff */ -}; - -static char *const MnemonicsXCB[256] = { -/*0/8 1/9 2/A 3/B 4/C 5/D 6/E 7/F */ - "RLC B", "RLC C", "RLC D", "RLC E", "RLC H", "RLC L", "RLC (I%@h)", "RLC A", /* 00-07 */ - "RRC B", "RRC C", "RRC D", "RRC E", "RRC H", "RRC L", "RRC (I%@h)", "RRC A", /* 08-0f */ - "RL B", "RL C", "RL D", "RL E", "RL H", "RL L", "RL (I%@h)", "RL A", /* 10-17 */ - "RR B", "RR C", "RR D", "RR E", "RR H", "RR L", "RR (I%@h)", "RR A", /* 18-1f */ - "SLA B", "SLA C", "SLA D", "SLA E", "SLA H", "SLA L", "SLA (I%@h)", "SLA A", /* 20-27 */ - "SRA B", "SRA C", "SRA D", "SRA E", "SRA H", "SRA L", "SRA (I%@h)", "SRA A", /* 28-2f */ - "SLL B", "SLL C", "SLL D", "SLL E", "SLL H", "SLL L", "SLL (I%@h)", "SLL A", /* 30-37 */ - "SRL B", "SRL C", "SRL D", "SRL E", "SRL H", "SRL L", "SRL (I%@h)", "SRL A", /* 38-3f */ - "BIT 0,B", "BIT 0,C", "BIT 0,D", "BIT 0,E", "BIT 0,H", "BIT 0,L", "BIT 0,(I%@h)", "BIT 0,A", /* 40-47 */ - "BIT 1,B", "BIT 1,C", "BIT 1,D", "BIT 1,E", "BIT 1,H", "BIT 1,L", "BIT 1,(I%@h)", "BIT 1,A", /* 48-4f */ - "BIT 2,B", "BIT 2,C", "BIT 2,D", "BIT 2,E", "BIT 2,H", "BIT 2,L", "BIT 2,(I%@h)", "BIT 2,A", /* 50-57 */ - "BIT 3,B", "BIT 3,C", "BIT 3,D", "BIT 3,E", "BIT 3,H", "BIT 3,L", "BIT 3,(I%@h)", "BIT 3,A", /* 58-5f */ - "BIT 4,B", "BIT 4,C", "BIT 4,D", "BIT 4,E", "BIT 4,H", "BIT 4,L", "BIT 4,(I%@h)", "BIT 4,A", /* 60-67 */ - "BIT 5,B", "BIT 5,C", "BIT 5,D", "BIT 5,E", "BIT 5,H", "BIT 5,L", "BIT 5,(I%@h)", "BIT 5,A", /* 68-6f */ - "BIT 6,B", "BIT 6,C", "BIT 6,D", "BIT 6,E", "BIT 6,H", "BIT 6,L", "BIT 6,(I%@h)", "BIT 6,A", /* 70-77 */ - "BIT 7,B", "BIT 7,C", "BIT 7,D", "BIT 7,E", "BIT 7,H", "BIT 7,L", "BIT 7,(I%@h)", "BIT 7,A", /* 78-7f */ - "RES 0,B", "RES 0,C", "RES 0,D", "RES 0,E", "RES 0,H", "RES 0,L", "RES 0,(I%@h)", "RES 0,A", /* 80-87 */ - "RES 1,B", "RES 1,C", "RES 1,D", "RES 1,E", "RES 1,H", "RES 1,L", "RES 1,(I%@h)", "RES 1,A", /* 88-8f */ - "RES 2,B", "RES 2,C", "RES 2,D", "RES 2,E", "RES 2,H", "RES 2,L", "RES 2,(I%@h)", "RES 2,A", /* 90-97 */ - "RES 3,B", "RES 3,C", "RES 3,D", "RES 3,E", "RES 3,H", "RES 3,L", "RES 3,(I%@h)", "RES 3,A", /* 98-9f */ - "RES 4,B", "RES 4,C", "RES 4,D", "RES 4,E", "RES 4,H", "RES 4,L", "RES 4,(I%@h)", "RES 4,A", /* a0-a7 */ - "RES 5,B", "RES 5,C", "RES 5,D", "RES 5,E", "RES 5,H", "RES 5,L", "RES 5,(I%@h)", "RES 5,A", /* a8-af */ - "RES 6,B", "RES 6,C", "RES 6,D", "RES 6,E", "RES 6,H", "RES 6,L", "RES 6,(I%@h)", "RES 6,A", /* b0-b7 */ - "RES 7,B", "RES 7,C", "RES 7,D", "RES 7,E", "RES 7,H", "RES 7,L", "RES 7,(I%@h)", "RES 7,A", /* b8-bf */ - "SET 0,B", "SET 0,C", "SET 0,D", "SET 0,E", "SET 0,H", "SET 0,L", "SET 0,(I%@h)", "SET 0,A", /* c0-c7 */ - "SET 1,B", "SET 1,C", "SET 1,D", "SET 1,E", "SET 1,H", "SET 1,L", "SET 1,(I%@h)", "SET 1,A", /* c8-cf */ - "SET 2,B", "SET 2,C", "SET 2,D", "SET 2,E", "SET 2,H", "SET 2,L", "SET 2,(I%@h)", "SET 2,A", /* d0-d7 */ - "SET 3,B", "SET 3,C", "SET 3,D", "SET 3,E", "SET 3,H", "SET 3,L", "SET 3,(I%@h)", "SET 3,A", /* d8-df */ - "SET 4,B", "SET 4,C", "SET 4,D", "SET 4,E", "SET 4,H", "SET 4,L", "SET 4,(I%@h)", "SET 4,A", /* e0-e7 */ - "SET 5,B", "SET 5,C", "SET 5,D", "SET 5,E", "SET 5,H", "SET 5,L", "SET 5,(I%@h)", "SET 5,A", /* e8-ef */ - "SET 6,B", "SET 6,C", "SET 6,D", "SET 6,E", "SET 6,H", "SET 6,L", "SET 6,(I%@h)", "SET 6,A", /* f0-f7 */ - "SET 7,B", "SET 7,C", "SET 7,D", "SET 7,E", "SET 7,H", "SET 7,L", "SET 7,(I%@h)", "SET 7,A" /* f8-ff */ -}; - -/* symbolic disassembler - - Inputs: - *val = instructions to disassemble - useZ80Mnemonics = > 0 iff Z80 mnemonics are to be used - addr = current PC - Outputs: - *S = output text - - DAsm is Copyright (C) Marat Fayzullin 1995,1996,1997 - You are not allowed to distribute this software - commercially. - -*/ - -static int32 DAsm(char *S, const uint32 *val, const int32 useZ80Mnemonics, const int32 addr) { - char R[128], H[10], C = '\0', *T, *P; - uint8 J = 0, Offset = 0; - uint16 B = 0; - - if (useZ80Mnemonics) { - switch(val[B]) { - case 0xcb: - B++; - T = MnemonicsCB[val[B++]]; - break; - case 0xed: - B++; - T = MnemonicsED[val[B++]]; - break; - case 0xdd: - case 0xfd: - C = (val[B++] == 0xdd) ? 'X' : 'Y'; - if (val[B] == 0xcb) { - B++; - Offset = val[B++]; - J = 1; - T = MnemonicsXCB[val[B++]]; - } - else { - T = MnemonicsXX[val[B++]]; - } - break; - default: - T = MnemonicsZ80[val[B++]]; - } - } - else { - T = Mnemonics8080[val[B++]]; - } - - if ( (P = strchr(T, '^')) ) { - strncpy(R, T, P - T); - R[P - T] = '\0'; - sprintf(H, "%02X", val[B++]); - strcat(R, H); - strcat(R, P + 1); - } - else { - strcpy(R, T); - } - if ( (P = strchr(R, '%')) ) { - *P = C; - if ( (P = strchr(P + 1, '%')) ) { - *P = C; - } - } - - if( (P = strchr(R, '*')) ) { - strncpy(S, R, P - R); - S[P - R] = '\0'; - sprintf(H, "%02X", val[B++]); - strcat(S, H); - strcat(S, P + 1); - } - else if ( (P = strchr(R, '@')) ) { - strncpy(S, R, P - R); - S[P - R] = '\0'; - if(!J) { - Offset = val[B++]; - } - strcat(S, Offset & 0x80 ? "-" : "+"); - J = Offset & 0x80 ? 256 - Offset : Offset; - sprintf(H, "%02X", J); - strcat(S, H); - strcat(S, P + 1); - } - else if ( (P = strchr(R, '$')) ) { - strncpy(S, R, P - R); - S[P - R] = '\0'; - Offset = val[B++]; - sprintf(H, "%04X", addr + 2 + (Offset & 0x80 ? (Offset - 256) : Offset)); - strcat(S, H); - strcat(S, P + 1); - } - else if ( (P = strchr(R, '#')) ) { - strncpy(S, R, P - R); - S[P - R] = '\0'; - sprintf(H, "%04X", val[B] + 256 * val[B + 1]); - strcat(S, H); - strcat(S, P + 1); - B += 2; - } - else { - strcpy(S, R); - } - return(B); -} - -/* symbolic output - - Inputs: - *of = output stream - addr = current PC - *val = pointer to values - *uptr = pointer to unit - sw = switches - Outputs: - status = error code -*/ - -int32 fprint_sym(FILE *of, int32 addr, uint32 *val, UNIT *uptr, int32 sw) { - char disasm[128]; - int32 ch = val[0] & 0x7f; - if (sw & (SWMASK('A') | SWMASK('C'))) { - fprintf(of, ((0x20 <= ch) && (ch < 0x7f)) ? "'%c'" : "%02x", ch); - return SCPE_OK; - } - if (!(sw & SWMASK('M'))) { - return SCPE_ARG; - } - ch = DAsm(disasm, val, cpu_unit.flags & UNIT_CHIP, addr); - fprintf(of, "%s", disasm); - return 1 - ch; /* need to return additional bytes */ -} - -/* numString checks determines the base of the number (ch, *numString) - and returns FALSE if the number is bad */ -static int32 checkbase(char ch, const char *numString) { - int32 decimal = (ch <= '9'); - if (toupper(ch) == 'H') { - return FALSE; - } - while (isxdigit(ch = *numString++)) { - if (ch > '9') { - decimal = FALSE; - } - } - return toupper(ch) == 'H' ? 16 : (decimal ? 10 : FALSE); -} - -static int32 numok(char ch, const char **numString, const int32 minvalue, - const int32 maxvalue, const int32 requireSign, int32 *result) { - int32 sign = 1, value = 0, base; - if (requireSign) { - if (ch == '+') { - ch = *(*numString)++; - } - else if (ch == '-') { - sign = -1; - ch = *(*numString)++; - } - else { - return FALSE; - } - } - if (!(base = checkbase(ch, *numString))) { - return FALSE; - } - while (isxdigit(ch)) { - value = base * value + ((ch <= '9') ? (ch - '0') : (toupper(ch) - 'A' + 10)); - ch = *(*numString)++; - } - if (toupper(ch) != 'H') { - (*numString)--; - } - *result = value * sign; - return (minvalue <= value) && (value <= maxvalue); -} - -static int32 match(const char *pattern, const char *input, char *xyFirst, char *xy, int32 *number, int32 *star, - int32 *at, int32 *hat, int32 *dollar) { - char pat = *pattern++; - char inp = *input++; - while ((pat) && (inp)) { - switch(pat) { - case '_': /* patterns containting '_' should never match */ - return FALSE; - case ',': - if (inp == ' ') { - inp = *input++; - continue; - } /* otherwise fall through */ - case ' ': - if (inp != pat) { - return FALSE; - } - pat = *pattern++; - inp = *input++; - while (inp == ' ') { - inp = *input++; - } - continue; - case '%': - inp = toupper(inp); - if ((inp == 'X') || (inp == 'Y')) { - if (*xyFirst) { /* make sure that second '%' corresponds to first */ - if (*xyFirst == inp) { - *xy = inp; - } - else { - return FALSE; - } - } - else { /* take note of first '%' for later */ - *xyFirst = inp; - *xy = inp; - } - } - else { - return FALSE; - } - break; - case '#': - if (numok(inp, &input, 0, 65535, FALSE, number)) { - pattern++; /* skip h */ - } - else { - return FALSE; - } - break; - case '*': - if (numok(inp, &input, 0, 255, FALSE, star)) { - pattern++; /* skip h */ - } - else { - return FALSE; - } - break; - case '@': - if (numok(inp, &input, -128, 65535, TRUE, at)) { - pattern++; /* skip h */ - } - else { - return FALSE; - } - break; - case '$': - if (numok(inp, &input, 0, 65535, FALSE, dollar)) { - pattern++; /* skip h */ - } - else { - return FALSE; - } - break; - case '^': - if (numok(inp, &input, 0, 255, FALSE, hat)) { - pattern++; /* skip h */ - } - else { - return FALSE; - } - break; - default: - if (toupper(pat) != toupper(inp)) { - return FALSE; - } - } - pat = *pattern++; - inp = *input++; - } - while (inp == ' ') { - inp = *input++; - } - return (pat == 0) && (inp == 0); -} - -static INLINE int32 checkXY(const char xy) { - return xy == 'X' ? 0xdd : 0xfd; /* else is 'Y' */ -} - -static int32 parse_X80(const char *cptr, const int32 addr, uint32 *val, char *const Mnemonics[]) { - char xyFirst = 0, xy; - int32 op, number, star, at, hat, dollar; - for (op = 0; op < 256; op++) { - number = star = at = dollar = -129; - if (match(Mnemonics[op], cptr, &xyFirst, &xy, &number, &star, &at, &hat, &dollar)) { - val[0] = op; - if (number >= 0) { - val[1] = (0xff) & number; - val[2] = (0xff) & (number >> 8); - return -2; /* two additional bytes returned */ - } - else if (star >= 0) { - val[1] = (0xff) & star; - return -1; /* one additional byte returned */ - } - else if (at > -129) { - if ((-128 <= at) && (at <= 127)) { - val[1] = (int8)(at); - return -1; /* one additional byte returned */ - } - else { - return SCPE_ARG; - } - } - else if (dollar >= 0) { - dollar -= addr + 2; /* relative translation */ - if ((-128 <= dollar) && (dollar <= 127)) { - val[1] = (int8)(dollar); - return -1; /* one additional byte returned */ - } - else { - return SCPE_ARG; - } - } - else { - return SCPE_OK; - } - } - } - if (Mnemonics == Mnemonics8080) { - return SCPE_ARG; - } - - for (op = 0; op < 256; op++) { - if (match(MnemonicsCB[op], cptr, &xyFirst, &xy, &number, &star, &at, &hat, &dollar)) { - val[0] = 0xcb; - val[1] = op; - return -1; /* one additional byte returned */ - } - } - - for (op = 0; op < 256; op++) { - number = -1; - if (match(MnemonicsED[op], cptr, &xyFirst, &xy, &number, &star, &at, &hat, &dollar)) { - val[0] = 0xed; - val[1] = op; - if (number >= 0) { - val[2] = (0xff) & number; - val[3] = (0xff) & (number >> 8); - return -3; /* three additional bytes returned */ - } - else { - return -1; /* one additional byte returned */ - } - } - } - - for (op = 0; op < 256; op++) { - number = star = hat = -1; - xy = 0; - if (match(MnemonicsXX[op], cptr, &xyFirst, &xy, &number, &star, &at, &hat, &dollar)) { - /* all matches must have contained a '%' character */ - if (!(val[0] = checkXY(xy))) { - return SCPE_ARG; - } - val[1] = op; - if (number >= 0) { - val[2] = (0xff) & number; - val[3] = (0xff) & (number >> 8); - return -3; /* three additional bytes returned */ - } - else if ((star >= 0) && (hat >= 0)) { - val[2] = (0xff) & hat; - val[3] = (0xff) & star; - return -3; /* three additional bytes returned */ - } - else if (star >= 0) { - val[2] = (0xff) & star; - return -2; /* two additional bytes returned */ - } - else if (hat >= 0) { - val[2] = (0xff) & hat; - return -2; /* two additional bytes returned */ - } - else { - return -1; /* one additional byte returned */ - } - } - } - - for (op = 0; op < 256; op++) { - at = -129; - xy = 0; - if (match(MnemonicsXCB[op], cptr, &xyFirst, &xy, &number, &star, &at, &hat, &dollar)) { - /* all matches must have contained a '%' character */ - if (!(val[0] = checkXY(xy))) { - return SCPE_ARG; - } - val[1] = 0xcb; - if (at > -129) { - val[2] = (int8) (at); - } - else { - printf("Offset expected.\n"); - return SCPE_ARG; - } - val[3] = op; - return -3; /* three additional bytes returned */ - } - } - return SCPE_ARG; -} - - -/* 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 -*/ -int32 parse_sym(char *cptr, int32 addr, UNIT *uptr, uint32 *val, int32 sw) { - while (isspace(*cptr)) cptr++; /* absorb spaces */ - if ((sw & (SWMASK('A') | SWMASK('C'))) || ((*cptr == '\'') && cptr++)) { /* ASCII char? */ - if (cptr[0] == 0) { - return SCPE_ARG; /* must have one char */ - } - val[0] = (uint32) cptr[0]; - return SCPE_OK; - } - return parse_X80(cptr, addr, val, cpu_unit.flags & UNIT_CHIP ? MnemonicsZ80 : Mnemonics8080); -} +/* altairz80_sys.c: MITS Altair system interface + + Copyright (c) 2002-2004, Peter Schorn + + 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 + PETER SCHORN 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 Peter Schorn shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Peter Schorn. + + Based on work by Charles E Owen (c) 1997 + Disassembler from Marat Fayzullin ((c) 1995, 1996, 1997 - Commercial use prohibited) +*/ + +#include +#include "altairz80_defs.h" + +extern DEVICE cpu_dev; +extern DEVICE dsk_dev; +extern DEVICE hdsk_dev; +extern UNIT cpu_unit; +extern REG cpu_reg[]; +extern DEVICE sio_dev; +extern DEVICE simh_device; +extern DEVICE ptr_dev; +extern DEVICE ptp_dev; +extern int32 saved_PC; + +int32 fprint_sym(FILE *of, int32 addr, uint32 *val, UNIT *uptr, int32 sw); +static int32 checkbase(char ch, const char *numString); +static int32 numok(char ch, const char **numString, const int32 minvalue, + const int32 maxvalue, const int32 requireSign, int32 *result); +static int32 match(const char *pattern, const char *input, char *xyFirst, char *xy, int32 *number, int32 *star, int32 *at, + int32 *hat, int32 *dollar); +static int32 parse_X80(const char *cptr, const int32 addr, uint32 *val, char *const Mnemonics[]); +int32 parse_sym(char *cptr, int32 addr, UNIT *uptr, uint32 *val, int32 sw); +static int32 DAsm(char *S, const uint32 *val, const int32 useZ80Mnemonics, const int32 addr); +static int32 checkXY(const char xy); + +/* 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 +*/ + +char sim_name[] = "Altair 8800 (Z80)"; +REG *sim_PC = &cpu_reg[0]; +int32 sim_emax = 4; +DEVICE *sim_devices[] = { &cpu_dev, &sio_dev, &simh_device, &ptr_dev, &ptp_dev, &dsk_dev, &hdsk_dev, NULL }; + +char memoryAccessMessage[80]; +const char *sim_stop_messages[] = { + "HALT instruction", + "Breakpoint", + memoryAccessMessage, + "Invalid Opcode" }; + +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 */ + "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 */ + "MOV E,B", "MOV E,C", "MOV E,D", "MOV E,E", "MOV E,H", "MOV E,L", "MOV E,M", "MOV E,A", /* 58-5f */ + "MOV H,B", "MOV H,C", "MOV H,D", "MOV H,E", "MOV H,H", "MOV H,L", "MOV H,M", "MOV H,A", /* 60-67 */ + "MOV L,B", "MOV L,C", "MOV L,D", "MOV L,E", "MOV L,H", "MOV L,L", "MOV L,M", "MOV L,A", /* 68-6f */ + "MOV M,B", "MOV M,C", "MOV M,D", "MOV M,E", "MOV M,H", "MOV M,L", "HLT", "MOV M,A", /* 70-77 */ + "MOV A,B", "MOV A,C", "MOV A,D", "MOV A,E", "MOV A,H", "MOV A,L", "MOV A,M", "MOV A,A", /* 78-7f */ + "ADD B", "ADD C", "ADD D", "ADD E", "ADD H", "ADD L", "ADD M", "ADD A", /* 80-87 */ + "ADC B", "ADC C", "ADC D", "ADC E", "ADC H", "ADC L", "ADC M", "ADC A", /* 88-8f */ + "SUB B", "SUB C", "SUB D", "SUB E", "SUB H", "SUB L", "SUB M", "SUB A", /* 90-97 */ + "SBB B", "SBB C", "SBB D", "SBB E", "SBB H", "SBB L", "SBB M", "SBB A", /* 98-9f */ + "ANA B", "ANA C", "ANA D", "ANA E", "ANA H", "ANA L", "ANA M", "ANA A", /* a0-a7 */ + "XRA B", "XRA C", "XRA D", "XRA E", "XRA H", "XRA L", "XRA M", "XRA A", /* a8-af */ + "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 */ + "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 */ + "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 */ + "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 */ + }; + +static char *const MnemonicsZ80[256] = { +/*0/8 1/9 2/A 3/B 4/C 5/D 6/E 7/F */ + "NOP", "LD BC,#h", "LD (BC),A", "INC BC", "INC B", "DEC B", "LD B,*h", "RLCA", /* 00-07 */ + "EX AF,AF'", "ADD HL,BC", "LD A,(BC)", "DEC BC", "INC C", "DEC C", "LD C,*h", "RRCA", /* 08-0f */ + "DJNZ $h", "LD DE,#h", "LD (DE),A", "INC DE", "INC D", "DEC D", "LD D,*h", "RLA", /* 10-17 */ + "JR $h", "ADD HL,DE", "LD A,(DE)", "DEC DE", "INC E", "DEC E", "LD E,*h", "RRA", /* 18-1f */ + "JR NZ,$h", "LD HL,#h", "LD (#h),HL", "INC HL", "INC H", "DEC H", "LD H,*h", "DAA", /* 20-27 */ + "JR Z,$h", "ADD HL,HL", "LD HL,(#h)", "DEC HL", "INC L", "DEC L", "LD L,*h", "CPL", /* 28-2f */ + "JR NC,$h", "LD SP,#h", "LD (#h),A", "INC SP", "INC (HL)", "DEC (HL)", "LD (HL),*h", "SCF", /* 30-37 */ + "JR C,$h", "ADD HL,SP", "LD A,(#h)", "DEC SP", "INC A", "DEC A", "LD A,*h", "CCF", /* 38-3f */ + "LD B,B", "LD B,C", "LD B,D", "LD B,E", "LD B,H", "LD B,L", "LD B,(HL)", "LD B,A", /* 40-47 */ + "LD C,B", "LD C,C", "LD C,D", "LD C,E", "LD C,H", "LD C,L", "LD C,(HL)", "LD C,A", /* 48-4f */ + "LD D,B", "LD D,C", "LD D,D", "LD D,E", "LD D,H", "LD D,L", "LD D,(HL)", "LD D,A", /* 50-57 */ + "LD E,B", "LD E,C", "LD E,D", "LD E,E", "LD E,H", "LD E,L", "LD E,(HL)", "LD E,A", /* 58-5f */ + "LD H,B", "LD H,C", "LD H,D", "LD H,E", "LD H,H", "LD H,L", "LD H,(HL)", "LD H,A", /* 60-67 */ + "LD L,B", "LD L,C", "LD L,D", "LD L,E", "LD L,H", "LD L,L", "LD L,(HL)", "LD L,A", /* 68-6f */ + "LD (HL),B", "LD (HL),C", "LD (HL),D", "LD (HL),E", "LD (HL),H", "LD (HL),L", "HALT", "LD (HL),A", /* 70-77 */ + "LD A,B", "LD A,C", "LD A,D", "LD A,E", "LD A,H", "LD A,L", "LD A,(HL)", "LD A,A", /* 78-7f */ + "ADD A,B", "ADD A,C", "ADD A,D", "ADD A,E", "ADD A,H", "ADD A,L", "ADD A,(HL)", "ADD A,A", /* 80-87 */ + "ADC A,B", "ADC A,C", "ADC A,D", "ADC A,E", "ADC A,H", "ADC A,L", "ADC A,(HL)", "ADC A,A", /* 88-8f */ + "SUB B", "SUB C", "SUB D", "SUB E", "SUB H", "SUB L", "SUB (HL)", "SUB A", /* 90-97 */ + "SBC A,B", "SBC A,C", "SBC A,D", "SBC A,E", "SBC A,H", "SBC A,L", "SBC A,(HL)", "SBC A,A", /* 98-9f */ + "AND B", "AND C", "AND D", "AND E", "AND H", "AND L", "AND (HL)", "AND A", /* a0-a7 */ + "XOR B", "XOR C", "XOR D", "XOR E", "XOR H", "XOR L", "XOR (HL)", "XOR A", /* a8-af */ + "OR B", "OR C", "OR D", "OR E", "OR H", "OR L", "OR (HL)", "OR A", /* b0-b7 */ + "CP B", "CP C", "CP D", "CP E", "CP H", "CP L", "CP (HL)", "CP A", /* b8-bf */ + "RET NZ", "POP BC", "JP NZ,#h", "JP #h", "CALL NZ,#h", "PUSH BC", "ADD A,*h", "RST 00h", /* c0-c7 */ + "RET Z", "RET", "JP Z,#h", "PFX_CB", "CALL Z,#h", "CALL #h", "ADC A,*h", "RST 08h", /* c8-cf */ + "RET NC", "POP DE", "JP NC,#h", "OUT (*h),A", "CALL NC,#h", "PUSH DE", "SUB *h", "RST 10h", /* d0-d7 */ + "RET C", "EXX", "JP C,#h", "IN A,(*h)", "CALL C,#h", "PFX_DD", "SBC A,*h", "RST 18h", /* d8-df */ + "RET PO", "POP HL", "JP PO,#h", "EX (SP),HL", "CALL PO,#h", "PUSH HL", "AND *h", "RST 20h", /* e0-e7 */ + "RET PE", "LD PC,HL", "JP PE,#h", "EX DE,HL", "CALL PE,#h", "PFX_ED", "XOR *h", "RST 28h", /* e8-ef */ + "RET P", "POP AF", "JP P,#h", "DI", "CALL P,#h", "PUSH AF", "OR *h", "RST 30h", /* f0-f7 */ + "RET M", "LD SP,HL", "JP M,#h", "EI", "CALL M,#h", "PFX_FD", "CP *h", "RST 38h" /* f8-ff */ +}; + +static char *const MnemonicsCB[256] = { +/*0/8 1/9 2/A 3/B 4/C 5/D 6/E 7/F */ + "RLC B", "RLC C", "RLC D", "RLC E", "RLC H", "RLC L", "RLC (HL)", "RLC A", /* 00-07 */ + "RRC B", "RRC C", "RRC D", "RRC E", "RRC H", "RRC L", "RRC (HL)", "RRC A", /* 08-0f */ + "RL B", "RL C", "RL D", "RL E", "RL H", "RL L", "RL (HL)", "RL A", /* 10-17 */ + "RR B", "RR C", "RR D", "RR E", "RR H", "RR L", "RR (HL)", "RR A", /* 18-1f */ + "SLA B", "SLA C", "SLA D", "SLA E", "SLA H", "SLA L", "SLA (HL)", "SLA A", /* 20-27 */ + "SRA B", "SRA C", "SRA D", "SRA E", "SRA H", "SRA L", "SRA (HL)", "SRA A", /* 28-2f */ + "SLL B", "SLL C", "SLL D", "SLL E", "SLL H", "SLL L", "SLL (HL)", "SLL A", /* 30-37 */ + "SRL B", "SRL C", "SRL D", "SRL E", "SRL H", "SRL L", "SRL (HL)", "SRL A", /* 38-3f */ + "BIT 0,B", "BIT 0,C", "BIT 0,D", "BIT 0,E", "BIT 0,H", "BIT 0,L", "BIT 0,(HL)", "BIT 0,A", /* 40-47 */ + "BIT 1,B", "BIT 1,C", "BIT 1,D", "BIT 1,E", "BIT 1,H", "BIT 1,L", "BIT 1,(HL)", "BIT 1,A", /* 48-4f */ + "BIT 2,B", "BIT 2,C", "BIT 2,D", "BIT 2,E", "BIT 2,H", "BIT 2,L", "BIT 2,(HL)", "BIT 2,A", /* 50-57 */ + "BIT 3,B", "BIT 3,C", "BIT 3,D", "BIT 3,E", "BIT 3,H", "BIT 3,L", "BIT 3,(HL)", "BIT 3,A", /* 58-5f */ + "BIT 4,B", "BIT 4,C", "BIT 4,D", "BIT 4,E", "BIT 4,H", "BIT 4,L", "BIT 4,(HL)", "BIT 4,A", /* 60-67 */ + "BIT 5,B", "BIT 5,C", "BIT 5,D", "BIT 5,E", "BIT 5,H", "BIT 5,L", "BIT 5,(HL)", "BIT 5,A", /* 68-6f */ + "BIT 6,B", "BIT 6,C", "BIT 6,D", "BIT 6,E", "BIT 6,H", "BIT 6,L", "BIT 6,(HL)", "BIT 6,A", /* 70-77 */ + "BIT 7,B", "BIT 7,C", "BIT 7,D", "BIT 7,E", "BIT 7,H", "BIT 7,L", "BIT 7,(HL)", "BIT 7,A", /* 78-7f */ + "RES 0,B", "RES 0,C", "RES 0,D", "RES 0,E", "RES 0,H", "RES 0,L", "RES 0,(HL)", "RES 0,A", /* 80-87 */ + "RES 1,B", "RES 1,C", "RES 1,D", "RES 1,E", "RES 1,H", "RES 1,L", "RES 1,(HL)", "RES 1,A", /* 88-8f */ + "RES 2,B", "RES 2,C", "RES 2,D", "RES 2,E", "RES 2,H", "RES 2,L", "RES 2,(HL)", "RES 2,A", /* 90-97 */ + "RES 3,B", "RES 3,C", "RES 3,D", "RES 3,E", "RES 3,H", "RES 3,L", "RES 3,(HL)", "RES 3,A", /* 98-9f */ + "RES 4,B", "RES 4,C", "RES 4,D", "RES 4,E", "RES 4,H", "RES 4,L", "RES 4,(HL)", "RES 4,A", /* a0-a7 */ + "RES 5,B", "RES 5,C", "RES 5,D", "RES 5,E", "RES 5,H", "RES 5,L", "RES 5,(HL)", "RES 5,A", /* a8-af */ + "RES 6,B", "RES 6,C", "RES 6,D", "RES 6,E", "RES 6,H", "RES 6,L", "RES 6,(HL)", "RES 6,A", /* b0-b7 */ + "RES 7,B", "RES 7,C", "RES 7,D", "RES 7,E", "RES 7,H", "RES 7,L", "RES 7,(HL)", "RES 7,A", /* b8-bf */ + "SET 0,B", "SET 0,C", "SET 0,D", "SET 0,E", "SET 0,H", "SET 0,L", "SET 0,(HL)", "SET 0,A", /* c0-c7 */ + "SET 1,B", "SET 1,C", "SET 1,D", "SET 1,E", "SET 1,H", "SET 1,L", "SET 1,(HL)", "SET 1,A", /* c8-cf */ + "SET 2,B", "SET 2,C", "SET 2,D", "SET 2,E", "SET 2,H", "SET 2,L", "SET 2,(HL)", "SET 2,A", /* d0-d7 */ + "SET 3,B", "SET 3,C", "SET 3,D", "SET 3,E", "SET 3,H", "SET 3,L", "SET 3,(HL)", "SET 3,A", /* d8-df */ + "SET 4,B", "SET 4,C", "SET 4,D", "SET 4,E", "SET 4,H", "SET 4,L", "SET 4,(HL)", "SET 4,A", /* e0-e7 */ + "SET 5,B", "SET 5,C", "SET 5,D", "SET 5,E", "SET 5,H", "SET 5,L", "SET 5,(HL)", "SET 5,A", /* e8-ef */ + "SET 6,B", "SET 6,C", "SET 6,D", "SET 6,E", "SET 6,H", "SET 6,L", "SET 6,(HL)", "SET 6,A", /* f0-f7 */ + "SET 7,B", "SET 7,C", "SET 7,D", "SET 7,E", "SET 7,H", "SET 7,L", "SET 7,(HL)", "SET 7,A" /* f8-ff */ +}; + +static char *const MnemonicsED[256] = { +/*0/8 1/9 2/A 3/B 4/C 5/D 6/E 7/F */ + "DB EDh,00h", "DB EDh,01h", "DB EDh,02h", "DB EDh,03h", "DB EDh,04h", "DB EDh,05h", "DB EDh,06h", "DB EDh,07h", /* 00-07 */ + "DB EDh,08h", "DB EDh,09h", "DB EDh,0Ah", "DB EDh,0Bh", "DB EDh,0Ch", "DB EDh,0Dh", "DB EDh,0Eh", "DB EDh,0Fh", /* 08-0f */ + "DB EDh,10h", "DB EDh,11h", "DB EDh,12h", "DB EDh,13h", "DB EDh,14h", "DB EDh,15h", "DB EDh,16h", "DB EDh,17h", /* 10-17 */ + "DB EDh,18h", "DB EDh,19h", "DB EDh,1Ah", "DB EDh,1Bh", "DB EDh,1Ch", "DB EDh,1Dh", "DB EDh,1Eh", "DB EDh,1Fh", /* 18-1f */ + "DB EDh,20h", "DB EDh,21h", "DB EDh,22h", "DB EDh,23h", "DB EDh,24h", "DB EDh,25h", "DB EDh,26h", "DB EDh,27h", /* 20-27 */ + "DB EDh,28h", "DB EDh,29h", "DB EDh,2Ah", "DB EDh,2Bh", "DB EDh,2Ch", "DB EDh,2Dh", "DB EDh,2Eh", "DB EDh,2Fh", /* 28-2f */ + "DB EDh,30h", "DB EDh,31h", "DB EDh,32h", "DB EDh,33h", "DB EDh,34h", "DB EDh,35h", "DB EDh,36h", "DB EDh,37h", /* 30-37 */ + "DB EDh,38h", "DB EDh,39h", "DB EDh,3Ah", "DB EDh,3Bh", "DB EDh,3Ch", "DB EDh,3Dh", "DB EDh,3Eh", "DB EDh,3Fh", /* 38-3f */ + "IN B,(C)", "OUT (C),B", "SBC HL,BC", "LD (#h),BC", "NEG", "RETN", "IM 0", "LD I,A", /* 40-47 */ + "IN C,(C)", "OUT (C),C", "ADC HL,BC", "LD BC,(#h)", "DB EDh,4Ch", "RETI", "DB EDh,4Eh", "LD R,A", /* 48-4f */ + "IN D,(C)", "OUT (C),D", "SBC HL,DE", "LD (#h),DE", "DB EDh,54h", "DB EDh,55h", "IM 1", "LD A,I", /* 50-57 */ + "IN E,(C)", "OUT (C),E", "ADC HL,DE", "LD DE,(#h)", "DB EDh,5Ch", "DB EDh,5Dh", "IM 2", "LD A,R", /* 58-5f */ + "IN H,(C)", "OUT (C),H", "SBC HL,HL", "LD (#h),HL", "DB EDh,64h", "DB EDh,65h", "DB EDh,66h", "RRD", /* 60-67 */ + "IN L,(C)", "OUT (C),L", "ADC HL,HL", "LD HL,(#h)", "DB EDh,6Ch", "DB EDh,6Dh", "DB EDh,6Eh", "RLD", /* 68-6f */ + "IN F,(C)", "DB EDh,71h", "SBC HL,SP", "LD (#h),SP", "DB EDh,74h", "DB EDh,75h", "DB EDh,76h", "DB EDh,77h", /* 70-77 */ + "IN A,(C)", "OUT (C),A", "ADC HL,SP", "LD SP,(#h)", "DB EDh,7Ch", "DB EDh,7Dh", "DB EDh,7Eh", "DB EDh,7Fh", /* 78-7f */ + "DB EDh,80h", "DB EDh,81h", "DB EDh,82h", "DB EDh,83h", "DB EDh,84h", "DB EDh,85h", "DB EDh,86h", "DB EDh,87h", /* 80-87 */ + "DB EDh,88h", "DB EDh,89h", "DB EDh,8Ah", "DB EDh,8Bh", "DB EDh,8Ch", "DB EDh,8Dh", "DB EDh,8Eh", "DB EDh,8Fh", /* 88-8f */ + "DB EDh,90h", "DB EDh,91h", "DB EDh,92h", "DB EDh,93h", "DB EDh,94h", "DB EDh,95h", "DB EDh,96h", "DB EDh,97h", /* 90-97 */ + "DB EDh,98h", "DB EDh,99h", "DB EDh,9Ah", "DB EDh,9Bh", "DB EDh,9Ch", "DB EDh,9Dh", "DB EDh,9Eh", "DB EDh,9Fh", /* 98-9f */ + "LDI", "CPI", "INI", "OUTI", "DB EDh,A4h", "DB EDh,A5h", "DB EDh,A6h", "DB EDh,A7h", /* a0-a7 */ + "LDD", "CPD", "IND", "OUTD", "DB EDh,ACh", "DB EDh,ADh", "DB EDh,AEh", "DB EDh,AFh", /* a8-af */ + "LDIR", "CPIR", "INIR", "OTIR", "DB EDh,B4h", "DB EDh,B5h", "DB EDh,B6h", "DB EDh,B7h", /* b0-b7 */ + "LDDR", "CPDR", "INDR", "OTDR", "DB EDh,BCh", "DB EDh,BDh", "DB EDh,BEh", "DB EDh,BFh", /* b8-bf */ + "DB EDh,C0h", "DB EDh,C1h", "DB EDh,C2h", "DB EDh,C3h", "DB EDh,C4h", "DB EDh,C5h", "DB EDh,C6h", "DB EDh,C7h", /* c0-c7 */ + "DB EDh,C8h", "DB EDh,C9h", "DB EDh,CAh", "DB EDh,CBh", "DB EDh,CCh", "DB EDh,CDh", "DB EDh,CEh", "DB EDh,CFh", /* c8-cf */ + "DB EDh,D0h", "DB EDh,D1h", "DB EDh,D2h", "DB EDh,D3h", "DB EDh,D4h", "DB EDh,D5h", "DB EDh,D6h", "DB EDh,D7h", /* d0-d7 */ + "DB EDh,D8h", "DB EDh,D9h", "DB EDh,DAh", "DB EDh,DBh", "DB EDh,DCh", "DB EDh,DDh", "DB EDh,DEh", "DB EDh,DFh", /* d8-df */ + "DB EDh,E0h", "DB EDh,E1h", "DB EDh,E2h", "DB EDh,E3h", "DB EDh,E4h", "DB EDh,E5h", "DB EDh,E6h", "DB EDh,E7h", /* e0-e7 */ + "DB EDh,E8h", "DB EDh,E9h", "DB EDh,EAh", "DB EDh,EBh", "DB EDh,ECh", "DB EDh,EDh", "DB EDh,EEh", "DB EDh,EFh", /* e8-ef */ + "DB EDh,F0h", "DB EDh,F1h", "DB EDh,F2h", "DB EDh,F3h", "DB EDh,F4h", "DB EDh,F5h", "DB EDh,F6h", "DB EDh,F7h", /* f0-f7 */ + "DB EDh,F8h", "DB EDh,F9h", "DB EDh,FAh", "DB EDh,FBh", "DB EDh,FCh", "DB EDh,FDh", "DB EDh,FEh", "DB EDh,FFh" /* f8-ff */ +}; + +static char *const MnemonicsXX[256] = { +/*0/8 1/9 2/A 3/B 4/C 5/D 6/E 7/F */ + "NOP", "LD BC,#h", "LD (BC),A", "INC BC", "INC B", "DEC B", "LD B,*h", "RLCA", /* 00-07 */ + "EX AF,AF'", "ADD I%,BC", "LD A,(BC)", "DEC BC", "INC C", "DEC C", "LD C,*h", "RRCA", /* 08-0f */ + "DJNZ $h", "LD DE,#h", "LD (DE),A", "INC DE", "INC D", "DEC D", "LD D,*h", "RLA", /* 10-17 */ + "JR $h", "ADD I%,DE", "LD A,(DE)", "DEC DE", "INC E", "DEC E", "LD E,*h", "RRA", /* 18-1f */ + "JR NZ,$h", "LD I%,#h", "LD (#h),I%", "INC I%", "INC I%H", "DEC I%H", "LD I%H,*h", "DAA", /* 20-27 */ + "JR Z,$h", "ADD I%,I%", "LD I%,(#h)", "DEC I%", "INC I%L", "DEC I%L", "LD I%L,*h", "CPL", /* 28-2f */ + "JR NC,$h", "LD SP,#h", "LD (#h),A", "INC SP", "INC (I%+^h)", "DEC (I%+^h)", "LD (I%+^h),*h", "SCF", /* 30-37 */ + "JR C,$h", "ADD I%,SP", "LD A,(#h)", "DEC SP", "INC A", "DEC A", "LD A,*h", "CCF", /* 38-3f */ + "LD B,B", "LD B,C", "LD B,D", "LD B,E", "LD B,I%H", "LD B,I%L", "LD B,(I%+^h)", "LD B,A", /* 40-47 */ + "LD C,B", "LD C,C", "LD C,D", "LD C,E", "LD C,I%H", "LD C,I%L", "LD C,(I%+^h)", "LD C,A", /* 48-4f */ + "LD D,B", "LD D,C", "LD D,D", "LD D,E", "LD D,I%H", "LD D,I%L", "LD D,(I%+^h)", "LD D,A", /* 50-57 */ + "LD E,B", "LD E,C", "LD E,D", "LD E,E", "LD E,I%H", "LD E,I%L", "LD E,(I%+^h)", "LD E,A", /* 58-5f */ + "LD I%H,B", "LD I%H,C", "LD I%H,D", "LD I%H,E", "LD I%H,I%H", "LD I%H,I%L", "LD H,(I%+^h)", "LD I%H,A", /* 60-67 */ + "LD I%L,B", "LD I%L,C", "LD I%L,D", "LD I%L,E", "LD I%L,I%H", "LD I%L,I%L", "LD L,(I%+^h)", "LD I%L,A", /* 68-6f */ + "LD (I%+^h),B", "LD (I%+^h),C", "LD (I%+^h),D", "LD (I%+^h),E", "LD (I%+^h),H", "LD (I%+^h),L", "HALT", "LD (I%+^h),A", /* 70-77 */ + "LD A,B", "LD A,C", "LD A,D", "LD A,E", "LD A,I%H", "LD A,I%L", "LD A,(I%+^h)", "LD A,A", /* 78-7f */ + "ADD A,B", "ADD A,C", "ADD A,D", "ADD A,E", "ADD A,I%H", "ADD A,I%L", "ADD A,(I%+^h)", "ADD A,A", /* 80-87 */ + "ADC A,B", "ADC A,C", "ADC A,D", "ADC A,E", "ADC A,I%H", "ADC A,I%L", "ADC A,(I%+^h)", "ADC A,A", /* 88-8f */ + "SUB B", "SUB C", "SUB D", "SUB E", "SUB I%H", "SUB I%L", "SUB (I%+^h)", "SUB A", /* 90-97 */ + "SBC A,B", "SBC A,C", "SBC A,D", "SBC A,E", "SBC A,I%H", "SBC A,I%L", "SBC A,(I%+^h)", "SBC A,A", /* 98-9f */ + "AND B", "AND C", "AND D", "AND E", "AND I%H", "AND I%L", "AND (I%+^h)", "AND A", /* a0-a7 */ + "XOR B", "XOR C", "XOR D", "XOR E", "XOR I%H", "XOR I%L", "XOR (I%+^h)", "XOR A", /* a8-af */ + "OR B", "OR C", "OR D", "OR E", "OR I%H", "OR I%L", "OR (I%+^h)", "OR A", /* b0-b7 */ + "CP B", "CP C", "CP D", "CP E", "CP I%H", "CP I%L", "CP (I%+^h)", "CP A", /* b8-bf */ + "RET NZ", "POP BC", "JP NZ,#h", "JP #h", "CALL NZ,#h", "PUSH BC", "ADD A,*h", "RST 00h", /* c8-cf */ + "RET Z", "RET", "JP Z,#h", "PFX_CB", "CALL Z,#h", "CALL #h", "ADC A,*h", "RST 08h", /* c8-cf */ + "RET NC", "POP DE", "JP NC,#h", "OUT (*h),A", "CALL NC,#h", "PUSH DE", "SUB *h", "RST 10h", /* d0-d7 */ + "RET C", "EXX", "JP C,#h", "IN A,(*h)", "CALL C,#h", "PFX_DD", "SBC A,*h", "RST 18h", /* d8-df */ + "RET PO", "POP I%", "JP PO,#h", "EX (SP),I%", "CALL PO,#h", "PUSH I%", "AND *h", "RST 20h", /* e0-e7 */ + "RET PE", "LD PC,I%", "JP PE,#h", "EX DE,I%", "CALL PE,#h", "PFX_ED", "XOR *h", "RST 28h", /* e8-ef */ + "RET P", "POP AF", "JP P,#h", "DI", "CALL P,#h", "PUSH AF", "OR *h", "RST 30h", /* f0-f7 */ + "RET M", "LD SP,I%", "JP M,#h", "EI", "CALL M,#h", "PFX_FD", "CP *h", "RST 38h" /* f8-ff */ +}; + +static char *const MnemonicsXCB[256] = { +/*0/8 1/9 2/A 3/B 4/C 5/D 6/E 7/F */ + "RLC B", "RLC C", "RLC D", "RLC E", "RLC H", "RLC L", "RLC (I%@h)", "RLC A", /* 00-07 */ + "RRC B", "RRC C", "RRC D", "RRC E", "RRC H", "RRC L", "RRC (I%@h)", "RRC A", /* 08-0f */ + "RL B", "RL C", "RL D", "RL E", "RL H", "RL L", "RL (I%@h)", "RL A", /* 10-17 */ + "RR B", "RR C", "RR D", "RR E", "RR H", "RR L", "RR (I%@h)", "RR A", /* 18-1f */ + "SLA B", "SLA C", "SLA D", "SLA E", "SLA H", "SLA L", "SLA (I%@h)", "SLA A", /* 20-27 */ + "SRA B", "SRA C", "SRA D", "SRA E", "SRA H", "SRA L", "SRA (I%@h)", "SRA A", /* 28-2f */ + "SLL B", "SLL C", "SLL D", "SLL E", "SLL H", "SLL L", "SLL (I%@h)", "SLL A", /* 30-37 */ + "SRL B", "SRL C", "SRL D", "SRL E", "SRL H", "SRL L", "SRL (I%@h)", "SRL A", /* 38-3f */ + "BIT 0,B", "BIT 0,C", "BIT 0,D", "BIT 0,E", "BIT 0,H", "BIT 0,L", "BIT 0,(I%@h)", "BIT 0,A", /* 40-47 */ + "BIT 1,B", "BIT 1,C", "BIT 1,D", "BIT 1,E", "BIT 1,H", "BIT 1,L", "BIT 1,(I%@h)", "BIT 1,A", /* 48-4f */ + "BIT 2,B", "BIT 2,C", "BIT 2,D", "BIT 2,E", "BIT 2,H", "BIT 2,L", "BIT 2,(I%@h)", "BIT 2,A", /* 50-57 */ + "BIT 3,B", "BIT 3,C", "BIT 3,D", "BIT 3,E", "BIT 3,H", "BIT 3,L", "BIT 3,(I%@h)", "BIT 3,A", /* 58-5f */ + "BIT 4,B", "BIT 4,C", "BIT 4,D", "BIT 4,E", "BIT 4,H", "BIT 4,L", "BIT 4,(I%@h)", "BIT 4,A", /* 60-67 */ + "BIT 5,B", "BIT 5,C", "BIT 5,D", "BIT 5,E", "BIT 5,H", "BIT 5,L", "BIT 5,(I%@h)", "BIT 5,A", /* 68-6f */ + "BIT 6,B", "BIT 6,C", "BIT 6,D", "BIT 6,E", "BIT 6,H", "BIT 6,L", "BIT 6,(I%@h)", "BIT 6,A", /* 70-77 */ + "BIT 7,B", "BIT 7,C", "BIT 7,D", "BIT 7,E", "BIT 7,H", "BIT 7,L", "BIT 7,(I%@h)", "BIT 7,A", /* 78-7f */ + "RES 0,B", "RES 0,C", "RES 0,D", "RES 0,E", "RES 0,H", "RES 0,L", "RES 0,(I%@h)", "RES 0,A", /* 80-87 */ + "RES 1,B", "RES 1,C", "RES 1,D", "RES 1,E", "RES 1,H", "RES 1,L", "RES 1,(I%@h)", "RES 1,A", /* 88-8f */ + "RES 2,B", "RES 2,C", "RES 2,D", "RES 2,E", "RES 2,H", "RES 2,L", "RES 2,(I%@h)", "RES 2,A", /* 90-97 */ + "RES 3,B", "RES 3,C", "RES 3,D", "RES 3,E", "RES 3,H", "RES 3,L", "RES 3,(I%@h)", "RES 3,A", /* 98-9f */ + "RES 4,B", "RES 4,C", "RES 4,D", "RES 4,E", "RES 4,H", "RES 4,L", "RES 4,(I%@h)", "RES 4,A", /* a0-a7 */ + "RES 5,B", "RES 5,C", "RES 5,D", "RES 5,E", "RES 5,H", "RES 5,L", "RES 5,(I%@h)", "RES 5,A", /* a8-af */ + "RES 6,B", "RES 6,C", "RES 6,D", "RES 6,E", "RES 6,H", "RES 6,L", "RES 6,(I%@h)", "RES 6,A", /* b0-b7 */ + "RES 7,B", "RES 7,C", "RES 7,D", "RES 7,E", "RES 7,H", "RES 7,L", "RES 7,(I%@h)", "RES 7,A", /* b8-bf */ + "SET 0,B", "SET 0,C", "SET 0,D", "SET 0,E", "SET 0,H", "SET 0,L", "SET 0,(I%@h)", "SET 0,A", /* c0-c7 */ + "SET 1,B", "SET 1,C", "SET 1,D", "SET 1,E", "SET 1,H", "SET 1,L", "SET 1,(I%@h)", "SET 1,A", /* c8-cf */ + "SET 2,B", "SET 2,C", "SET 2,D", "SET 2,E", "SET 2,H", "SET 2,L", "SET 2,(I%@h)", "SET 2,A", /* d0-d7 */ + "SET 3,B", "SET 3,C", "SET 3,D", "SET 3,E", "SET 3,H", "SET 3,L", "SET 3,(I%@h)", "SET 3,A", /* d8-df */ + "SET 4,B", "SET 4,C", "SET 4,D", "SET 4,E", "SET 4,H", "SET 4,L", "SET 4,(I%@h)", "SET 4,A", /* e0-e7 */ + "SET 5,B", "SET 5,C", "SET 5,D", "SET 5,E", "SET 5,H", "SET 5,L", "SET 5,(I%@h)", "SET 5,A", /* e8-ef */ + "SET 6,B", "SET 6,C", "SET 6,D", "SET 6,E", "SET 6,H", "SET 6,L", "SET 6,(I%@h)", "SET 6,A", /* f0-f7 */ + "SET 7,B", "SET 7,C", "SET 7,D", "SET 7,E", "SET 7,H", "SET 7,L", "SET 7,(I%@h)", "SET 7,A" /* f8-ff */ +}; + +/* symbolic disassembler + + Inputs: + *val = instructions to disassemble + useZ80Mnemonics = > 0 iff Z80 mnemonics are to be used + addr = current PC + Outputs: + *S = output text + + DAsm is Copyright (C) Marat Fayzullin 1995,1996,1997 + You are not allowed to distribute this software + commercially. + +*/ + +static int32 DAsm(char *S, const uint32 *val, const int32 useZ80Mnemonics, const int32 addr) { + char R[128], H[10], C = '\0', *T, *P; + uint8 J = 0, Offset = 0; + uint16 B = 0; + + if (useZ80Mnemonics) { + switch(val[B]) { + case 0xcb: + B++; + T = MnemonicsCB[val[B++]]; + break; + case 0xed: + B++; + T = MnemonicsED[val[B++]]; + break; + case 0xdd: + case 0xfd: + C = (val[B++] == 0xdd) ? 'X' : 'Y'; + if (val[B] == 0xcb) { + B++; + Offset = val[B++]; + J = 1; + T = MnemonicsXCB[val[B++]]; + } + else { + T = MnemonicsXX[val[B++]]; + } + break; + default: + T = MnemonicsZ80[val[B++]]; + } + } + else { + T = Mnemonics8080[val[B++]]; + } + + if ( (P = strchr(T, '^')) ) { + strncpy(R, T, P - T); + R[P - T] = '\0'; + sprintf(H, "%02X", val[B++]); + strcat(R, H); + strcat(R, P + 1); + } + else { + strcpy(R, T); + } + if ( (P = strchr(R, '%')) ) { + *P = C; + if ( (P = strchr(P + 1, '%')) ) { + *P = C; + } + } + + if( (P = strchr(R, '*')) ) { + strncpy(S, R, P - R); + S[P - R] = '\0'; + sprintf(H, "%02X", val[B++]); + strcat(S, H); + strcat(S, P + 1); + } + else if ( (P = strchr(R, '@')) ) { + strncpy(S, R, P - R); + S[P - R] = '\0'; + if(!J) { + Offset = val[B++]; + } + strcat(S, Offset & 0x80 ? "-" : "+"); + J = Offset & 0x80 ? 256 - Offset : Offset; + sprintf(H, "%02X", J); + strcat(S, H); + strcat(S, P + 1); + } + else if ( (P = strchr(R, '$')) ) { + strncpy(S, R, P - R); + S[P - R] = '\0'; + Offset = val[B++]; + sprintf(H, "%04X", addr + 2 + (Offset & 0x80 ? (Offset - 256) : Offset)); + strcat(S, H); + strcat(S, P + 1); + } + else if ( (P = strchr(R, '#')) ) { + strncpy(S, R, P - R); + S[P - R] = '\0'; + sprintf(H, "%04X", val[B] + 256 * val[B + 1]); + strcat(S, H); + strcat(S, P + 1); + B += 2; + } + else { + strcpy(S, R); + } + return(B); +} + +/* symbolic output + + Inputs: + *of = output stream + addr = current PC + *val = pointer to values + *uptr = pointer to unit + sw = switches + Outputs: + status = error code +*/ + +int32 fprint_sym(FILE *of, int32 addr, uint32 *val, UNIT *uptr, int32 sw) { + char disasm[128]; + int32 ch = val[0] & 0x7f; + if (sw & (SWMASK('A') | SWMASK('C'))) { + fprintf(of, ((0x20 <= ch) && (ch < 0x7f)) ? "'%c'" : "%02x", ch); + return SCPE_OK; + } + if (!(sw & SWMASK('M'))) { + return SCPE_ARG; + } + ch = DAsm(disasm, val, cpu_unit.flags & UNIT_CHIP, addr); + fprintf(of, "%s", disasm); + return 1 - ch; /* need to return additional bytes */ +} + +/* numString checks determines the base of the number (ch, *numString) + and returns FALSE if the number is bad */ +static int32 checkbase(char ch, const char *numString) { + int32 decimal = (ch <= '9'); + if (toupper(ch) == 'H') { + return FALSE; + } + while (isxdigit(ch = *numString++)) { + if (ch > '9') { + decimal = FALSE; + } + } + return toupper(ch) == 'H' ? 16 : (decimal ? 10 : FALSE); +} + +static int32 numok(char ch, const char **numString, const int32 minvalue, + const int32 maxvalue, const int32 requireSign, int32 *result) { + int32 sign = 1, value = 0, base; + if (requireSign) { + if (ch == '+') { + ch = *(*numString)++; + } + else if (ch == '-') { + sign = -1; + ch = *(*numString)++; + } + else { + return FALSE; + } + } + if (!(base = checkbase(ch, *numString))) { + return FALSE; + } + while (isxdigit(ch)) { + value = base * value + ((ch <= '9') ? (ch - '0') : (toupper(ch) - 'A' + 10)); + ch = *(*numString)++; + } + if (toupper(ch) != 'H') { + (*numString)--; + } + *result = value * sign; + return (minvalue <= value) && (value <= maxvalue); +} + +static int32 match(const char *pattern, const char *input, char *xyFirst, char *xy, int32 *number, int32 *star, + int32 *at, int32 *hat, int32 *dollar) { + char pat = *pattern++; + char inp = *input++; + while ((pat) && (inp)) { + switch(pat) { + case '_': /* patterns containting '_' should never match */ + return FALSE; + case ',': + if (inp == ' ') { + inp = *input++; + continue; + } /* otherwise fall through */ + case ' ': + if (inp != pat) { + return FALSE; + } + pat = *pattern++; + inp = *input++; + while (inp == ' ') { + inp = *input++; + } + continue; + case '%': + inp = toupper(inp); + if ((inp == 'X') || (inp == 'Y')) { + if (*xyFirst) { /* make sure that second '%' corresponds to first */ + if (*xyFirst == inp) { + *xy = inp; + } + else { + return FALSE; + } + } + else { /* take note of first '%' for later */ + *xyFirst = inp; + *xy = inp; + } + } + else { + return FALSE; + } + break; + case '#': + if (numok(inp, &input, 0, 65535, FALSE, number)) { + pattern++; /* skip h */ + } + else { + return FALSE; + } + break; + case '*': + if (numok(inp, &input, 0, 255, FALSE, star)) { + pattern++; /* skip h */ + } + else { + return FALSE; + } + break; + case '@': + if (numok(inp, &input, -128, 65535, TRUE, at)) { + pattern++; /* skip h */ + } + else { + return FALSE; + } + break; + case '$': + if (numok(inp, &input, 0, 65535, FALSE, dollar)) { + pattern++; /* skip h */ + } + else { + return FALSE; + } + break; + case '^': + if (numok(inp, &input, 0, 255, FALSE, hat)) { + pattern++; /* skip h */ + } + else { + return FALSE; + } + break; + default: + if (toupper(pat) != toupper(inp)) { + return FALSE; + } + } + pat = *pattern++; + inp = *input++; + } + while (inp == ' ') { + inp = *input++; + } + return (pat == 0) && (inp == 0); +} + +static INLINE int32 checkXY(const char xy) { + return xy == 'X' ? 0xdd : 0xfd; /* else is 'Y' */ +} + +static int32 parse_X80(const char *cptr, const int32 addr, uint32 *val, char *const Mnemonics[]) { + char xyFirst = 0, xy; + int32 op, number, star, at, hat, dollar; + for (op = 0; op < 256; op++) { + number = star = at = dollar = -129; + if (match(Mnemonics[op], cptr, &xyFirst, &xy, &number, &star, &at, &hat, &dollar)) { + val[0] = op; + if (number >= 0) { + val[1] = (0xff) & number; + val[2] = (0xff) & (number >> 8); + return -2; /* two additional bytes returned */ + } + else if (star >= 0) { + val[1] = (0xff) & star; + return -1; /* one additional byte returned */ + } + else if (at > -129) { + if ((-128 <= at) && (at <= 127)) { + val[1] = (int8)(at); + return -1; /* one additional byte returned */ + } + else { + return SCPE_ARG; + } + } + else if (dollar >= 0) { + dollar -= addr + 2; /* relative translation */ + if ((-128 <= dollar) && (dollar <= 127)) { + val[1] = (int8)(dollar); + return -1; /* one additional byte returned */ + } + else { + return SCPE_ARG; + } + } + else { + return SCPE_OK; + } + } + } + if (Mnemonics == Mnemonics8080) { + return SCPE_ARG; + } + + for (op = 0; op < 256; op++) { + if (match(MnemonicsCB[op], cptr, &xyFirst, &xy, &number, &star, &at, &hat, &dollar)) { + val[0] = 0xcb; + val[1] = op; + return -1; /* one additional byte returned */ + } + } + + for (op = 0; op < 256; op++) { + number = -1; + if (match(MnemonicsED[op], cptr, &xyFirst, &xy, &number, &star, &at, &hat, &dollar)) { + val[0] = 0xed; + val[1] = op; + if (number >= 0) { + val[2] = (0xff) & number; + val[3] = (0xff) & (number >> 8); + return -3; /* three additional bytes returned */ + } + else { + return -1; /* one additional byte returned */ + } + } + } + + for (op = 0; op < 256; op++) { + number = star = hat = -1; + xy = 0; + if (match(MnemonicsXX[op], cptr, &xyFirst, &xy, &number, &star, &at, &hat, &dollar)) { + /* all matches must have contained a '%' character */ + if (!(val[0] = checkXY(xy))) { + return SCPE_ARG; + } + val[1] = op; + if (number >= 0) { + val[2] = (0xff) & number; + val[3] = (0xff) & (number >> 8); + return -3; /* three additional bytes returned */ + } + else if ((star >= 0) && (hat >= 0)) { + val[2] = (0xff) & hat; + val[3] = (0xff) & star; + return -3; /* three additional bytes returned */ + } + else if (star >= 0) { + val[2] = (0xff) & star; + return -2; /* two additional bytes returned */ + } + else if (hat >= 0) { + val[2] = (0xff) & hat; + return -2; /* two additional bytes returned */ + } + else { + return -1; /* one additional byte returned */ + } + } + } + + for (op = 0; op < 256; op++) { + at = -129; + xy = 0; + if (match(MnemonicsXCB[op], cptr, &xyFirst, &xy, &number, &star, &at, &hat, &dollar)) { + /* all matches must have contained a '%' character */ + if (!(val[0] = checkXY(xy))) { + return SCPE_ARG; + } + val[1] = 0xcb; + if (at > -129) { + val[2] = (int8) (at); + } + else { + printf("Offset expected.\n"); + return SCPE_ARG; + } + val[3] = op; + return -3; /* three additional bytes returned */ + } + } + return SCPE_ARG; +} + + +/* 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 +*/ +int32 parse_sym(char *cptr, int32 addr, UNIT *uptr, uint32 *val, int32 sw) { + while (isspace(*cptr)) cptr++; /* absorb spaces */ + if ((sw & (SWMASK('A') | SWMASK('C'))) || ((*cptr == '\'') && cptr++)) { /* ASCII char? */ + if (cptr[0] == 0) { + return SCPE_ARG; /* must have one char */ + } + val[0] = (uint32) cptr[0]; + return SCPE_OK; + } + return parse_X80(cptr, addr, val, cpu_unit.flags & UNIT_CHIP ? MnemonicsZ80 : Mnemonics8080); +} diff --git a/HP2100/hp2100_cpu.c b/HP2100/hp2100_cpu.c index efadef53..34255f1d 100644 --- a/HP2100/hp2100_cpu.c +++ b/HP2100/hp2100_cpu.c @@ -23,6 +23,23 @@ 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-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 @@ -55,6 +72,8 @@ BR<15:0> B register - addressable as location 1 PC<14:0> P register (program counter) SR<15:0> S register + MR<14:0> M register - memory address + TR<15:0> T register - memory data E extend flag (carry out) O overflow flag @@ -232,12 +251,13 @@ unknown I/O device and stop_dev flag set I/O error in I/O simulator - 2. Interrupts. I/O devices are modelled as four parallel arrays: + 2. Interrupts. I/O devices are modelled as five parallel arrays: device commands as bit array dev_cmd[2][31..0] device flags as bit array dev_flg[2][31..0] device flag buffers as bit array dev_fbf[2][31..0] device controls as bit array dev_ctl[2][31..0] + device service requests as bit array dev_srq[3][31..0] The HP 2100 interrupt structure is based on flag, flag buffer,. and control. If a device flag is set, the flag buffer is set, @@ -251,6 +271,8 @@ tells whether a device is active. It is set by STC and cleared by CLC; it is also cleared when the device flag is set. Simple devices don't need to track command separately from control. + + Service requests are used to trigger the DMA service logic. 3. Non-existent memory. On the HP 2100, reads to non-existent memory return zero, and writes are ignored. In the simulator, the @@ -308,11 +330,15 @@ #define DMAR0 1 #define DMAR1 2 +#define ALL_BKPTS (SWMASK('E')|SWMASK('N')|SWMASK('S')|SWMASK('U')) + uint16 *M = NULL; /* memory */ uint32 saved_AR = 0; /* A register */ uint32 saved_BR = 0; /* B register */ 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 */ @@ -321,6 +347,7 @@ uint32 dev_cmd[2] = { 0 }; /* device command */ uint32 dev_ctl[2] = { 0 }; /* device control */ uint32 dev_flg[2] = { 0 }; /* device flags */ uint32 dev_fbf[2] = { 0 }; /* device flag bufs */ +uint32 dev_srq[2] = { 0 }; /* device svc reqs */ struct DMA dmac[2] = { { 0 }, { 0 } }; /* DMA channels */ uint32 ion = 0; /* interrupt enable */ uint32 ion_defer = 0; /* interrupt defer */ @@ -334,7 +361,7 @@ 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 */ -uint32 dms_map[MAP_NUM * MAP_LNT] = { 0 }; /* dms maps */ +uint16 dms_map[MAP_NUM * MAP_LNT] = { 0 }; /* dms maps */ uint32 iop_sp = 0; /* iop stack */ uint32 ind_max = 16; /* iadr nest limit */ uint32 stop_inst = 1; /* stop on ill inst */ @@ -361,6 +388,7 @@ extern int32 sim_int_char; extern int32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ extern FILE *sim_log; extern DEVICE *sim_devices[]; +extern char halt_msg[]; t_stat Ea (uint32 IR, uint32 *addr, uint32 irq); t_stat Ea1 (uint32 *addr, uint32 irq); @@ -390,6 +418,7 @@ void dma_cycle (uint32 chan, uint32 map); 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 dma0_reset (DEVICE *dptr); t_stat dma1_reset (DEVICE *dptr); t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); @@ -417,18 +446,20 @@ REG cpu_reg[] = { { ORDATA (P, PC, 15) }, { ORDATA (A, saved_AR, 16) }, { ORDATA (B, saved_BR, 16) }, + { ORDATA (M, MR, 15) }, + { ORDATA (T, TR, 16), REG_RO }, { ORDATA (X, XR, 16) }, { ORDATA (Y, YR, 16) }, { ORDATA (S, SR, 16) }, - { ORDATA (F, mp_fence, 15) }, { FLDATA (E, E, 0) }, { FLDATA (O, O, 0) }, { FLDATA (ION, ion, 0) }, { FLDATA (ION_DEFER, ion_defer, 0) }, - { ORDATA (IADDR, intaddr, 6) }, + { ORDATA (CIR, intaddr, 6) }, { FLDATA (MPCTL, dev_ctl[PRO/32], INT_V (PRO)) }, { FLDATA (MPFLG, dev_flg[PRO/32], INT_V (PRO)) }, { FLDATA (MPFBF, dev_fbf[PRO/32], INT_V (PRO)) }, + { ORDATA (MPFR, mp_fence, 15) }, { ORDATA (MPVR, mp_viol, 16) }, { FLDATA (MPMEV, mp_mevff, 0) }, { FLDATA (MPEVR, mp_evrff, 0) }, @@ -436,7 +467,7 @@ REG cpu_reg[] = { { FLDATA (DMSCUR, dms_ump, VA_N_PAG) }, { ORDATA (DMSSR, dms_sr, 16) }, { ORDATA (DMSVR, dms_vr, 16) }, - { BRDATA (DMSMAP, dms_map, 8, PA_N_SIZE, MAP_NUM * MAP_LNT) }, + { 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) }, @@ -452,6 +483,8 @@ REG cpu_reg[] = { { ORDATA (LFLG, dev_flg[1], 32), REG_HRO }, { ORDATA (HFBF, dev_fbf[0], 32), REG_HRO }, { ORDATA (LFBF, dev_fbf[1], 32), REG_HRO }, + { ORDATA (HSRQ, dev_srq[0], 32), REG_HRO }, + { ORDATA (LSRQ, dev_srq[1], 32), REG_HRO }, { NULL } }; MTAB cpu_mod[] = { @@ -499,9 +532,9 @@ MTAB cpu_mod[] = { DEVICE cpu_dev = { "CPU", &cpu_unit, cpu_reg, cpu_mod, - 1, 8, 15, 1, 8, 16, + 1, 8, PA_N_SIZE, 1, 8, 16, &cpu_ex, &cpu_dep, &cpu_reset, - NULL, NULL, NULL }; + &cpu_boot, NULL, NULL }; /* DMA controller data structures @@ -663,6 +696,7 @@ int32 (*dtab[64])() = { t_stat sim_instr (void) { uint32 intrq, dmarq; /* set after setjmp */ +uint32 iotrap = 0; /* set after setjmp */ t_stat reason; /* set after setjmp */ int32 i, dev; /* temp */ DEVICE *dptr; /* temp */ @@ -684,6 +718,7 @@ dev_cmd[0] = dev_cmd[0] & M_FXDEV; /* clear dynamic info */ dev_ctl[0] = dev_ctl[0] & M_FXDEV; dev_flg[0] = dev_flg[0] & M_FXDEV; dev_fbf[0] = dev_fbf[0] & M_FXDEV; +dev_srq[0] = dev_srq[1] = 0; /* init svc requests */ dev_cmd[1] = dev_ctl[1] = dev_flg[1] = dev_fbf[1] = 0; for (i = 0; dptr = sim_devices[i]; i++) { /* loop thru dev */ dibp = (DIB *) dptr->ctxt; /* get DIB */ @@ -694,6 +729,7 @@ for (i = 0; dptr = sim_devices[i]; i++) { /* loop thru dev */ if (dibp->flg) { setFLG (dev); } /* restore flg */ clrFBF (dev); /* also sets fbf */ if (dibp->fbf) { setFBF (dev); } /* restore fbf */ + if (dibp->srq) { setSRQ (dev); } /* restore srq */ dtab[dev] = dibp->iot; } } /* set I/O dispatch */ sim_rtc_init (clk_delay (0)); /* recalibrate clock */ @@ -719,7 +755,7 @@ while (reason == 0) { /* loop until halted */ uint32 IR, MA, M1, absel, v1, v2, t; uint32 fop, eop, etype, eflag; uint32 skip, mapi, mapj, qs, rs; -uint32 awc, sc, wc, hp, tp, iotrap; +uint32 awc, sc, wc, hp, tp; int32 sop1, sop2; if (sim_interval <= 0) { /* check clock queue */ @@ -733,9 +769,21 @@ if (dmarq) { dmarq = calc_dma (); /* recalc DMA reqs */ intrq = calc_int (); } /* recalc interrupts */ +/* (From Dave Bryan) + Unlike most other I/O devices, the MP flag flip-flop is cleared + automatically when the interrupt is acknowledged and not by a programmed + instruction (CLF and STF affect the parity error enable FF instead). + Section 4.4.3 "Memory Protect and I/O Interrupt Generation" of the "HP 1000 + M/E/F-Series Computers Engineering and Reference Documentation" (HP + 92851-90001) says: + + "When IAK occurs and IRQ5 is asserted, the FLAGBFF is cleared, FLAGFF + clocked off at next T2, and IRQ5 will no longer occur." */ + if (intrq && ((intrq <= PRO) || !ion_defer)) { /* interrupt request? */ iotrap = 1; /* I/O trap cell instr */ clrFBF (intrq); /* clear flag buffer */ + if (intrq == PRO) clrFLG (PRO); /* MP flag follows flag buffer */ intaddr = intrq; /* save int addr */ if (dms_enb) dms_sr = dms_sr | MST_ENBI; /* dms enabled? */ else dms_sr = dms_sr & ~MST_ENBI; @@ -752,8 +800,12 @@ if (intrq && ((intrq <= PRO) || !ion_defer)) { /* interrupt request? */ else { iotrap = 0; /* normal instruction */ err_PC = PC; /* save PC for error */ - if (sim_brk_summ && - sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */ + if (sim_brk_summ && /* any breakpoints? */ + sim_brk_test (PC, ALL_BKPTS) && /* at this location? */ + (sim_brk_test (PC, SWMASK ('E')) || /* unconditional? */ + sim_brk_test (PC, dms_enb? /* or right type for DMS? */ + (dms_ump? SWMASK ('U'): SWMASK ('S')): + SWMASK ('N')))) { reason = STOP_IBKPT; /* stop simulation */ break; } if (mp_evrff) mp_viol = PC; /* if ok, upd mp_viol */ @@ -1200,19 +1252,23 @@ case 0203:case 0213: /* MAC1 ext */ break; case 0221: /* IOP PRFIO (I_NO) */ case 0473: /* IOPX PFRIO (I_NO) */ - IR = ReadW (PC); /* get IO instr */ + t = ReadW (PC); /* get IO instr */ PC = (PC + 1) & VAMASK; WriteW (PC, 1); /* set flag */ PC = (PC + 1) & VAMASK; - reason = iogrp (IR, 0); /* execute instr */ + reason = iogrp (t, 0); /* execute instr */ + dmarq = calc_dma (); /* recalc DMA */ + intrq = calc_int (); /* recalc interrupts */ break; case 0222: /* IOP PRFEI (I_NO) */ case 0471: /* IOPX PFREI (I_NO) */ - IR = ReadW (PC); /* get IO instr */ + t = ReadW (PC); /* get IO instr */ PC = (PC + 1) & VAMASK; WriteW (PC, 1); /* set flag */ PC = (PC + 1) & VAMASK; - reason = iogrp (IR, 0); /* execute instr */ + reason = iogrp (t, 0); /* execute instr */ + dmarq = calc_dma (); /* recalc DMA */ + intrq = calc_int (); /* recalc interrupts */ /* fall through */ case 0223: /* IOP PRFEX (I_NO) */ case 0472: /* IOPX PFREX (I_NO) */ @@ -1655,6 +1711,7 @@ case 0203:case 0213: /* MAC1 ext */ break; case 0764: /* SBT (E_NO) */ WriteB (BR, AR); /* store byte */ + BR = (BR + 1) & DMASK; /* incr ptr */ break; IOP_MBYTE: /* IOP MBYTE (I_AZ) */ if (wc & SIGN) break; /* must be positive */ @@ -1763,8 +1820,12 @@ if (reason == STOP_INDINT) { /* indirect intr? */ /* Simulation halted */ +if (iotrap && (reason == STOP_HALT)) MR = intaddr; /* HLT in trap cell? */ +else MR = (PC - 1) & VAMASK; /* no, M = P - 1 */ +TR = ReadIO (MR, dms_ump); /* last word fetched */ saved_AR = AR & DMASK; saved_BR = BR & DMASK; +dms_upd_sr (); /* update dms_sr */ for (i = 0; dptr = sim_devices[i]; i++) { /* loop thru dev */ dibp = (DIB *) dptr->ctxt; /* get DIB */ if (dibp) { /* exist? */ @@ -1772,7 +1833,8 @@ for (i = 0; dptr = sim_devices[i]; i++) { /* loop thru dev */ dibp->cmd = CMD (dev); dibp->ctl = CTL (dev); dibp->flg = FLG (dev); - dibp->fbf = FBF (dev); } } + dibp->fbf = FBF (dev); + dibp->srq = SRQ (dev); } } pcq_r->qptr = pcq_p; /* update pc q ptr */ return reason; } @@ -1865,7 +1927,10 @@ iodata = devdisp (dev, sop, ir, ABREG[ab]); /* process I/O */ ion_defer = defer_tab[sop]; /* set defer */ if ((sop == ioMIX) || (sop == ioLIX)) /* store ret data */ ABREG[ab] = iodata & DMASK; -if (sop == ioHLT) return STOP_HALT; /* halt? */ +if (sop == ioHLT) { /* halt? */ + int32 len = strlen (halt_msg); /* find end msg */ + sprintf (&halt_msg[len - 6], "%06o", ir); /* add the halt */ + return STOP_HALT; } return (iodata >> IOT_V_REASON); /* return status */ } @@ -1883,9 +1948,9 @@ uint32 calc_dma (void) { uint32 r = 0; -if (CMD (DMA0) && FLG (dmac[0].cw1 & I_DEVMASK)) /* check DMA0 cycle */ +if (CMD (DMA0) && SRQ (dmac[0].cw1 & I_DEVMASK)) /* check DMA0 cycle */ r = r | DMAR0; -if (CMD (DMA1) && FLG (dmac[1].cw1 & I_DEVMASK)) /* check DMA1 cycle */ +if (CMD (DMA1) && SRQ (dmac[1].cw1 & I_DEVMASK)) /* check DMA1 cycle */ r = r | DMAR1; return r; } @@ -1994,7 +2059,14 @@ else pa = va; return M[pa]; } -/* Memory protection test for writes */ +/* Memory protection test for writes + + From Dave Bryan: The problem is that memory writes aren't being checked for + an MP violation if DMS is enabled, i.e., if DMS is enabled, and the page is + writable, then whether the target is below the MP fence is not checked. [The + simulator must] do MP check on all writes after DMS translation and violation + checks are done (so, to pass, the page must be writable AND the target must + be above the MP fence). */ #define MP_TEST(x) (CTL (PRO) && ((x) > 1) && ((x) < mp_fence)) @@ -2003,8 +2075,8 @@ void WriteB (uint32 va, uint32 dat) uint32 pa; if (dms_enb) pa = dms (va >> 1, dms_ump, WR); -else { if (MP_TEST (va >> 1)) ABORT (ABORT_PRO); - pa = va >> 1; } +else pa = va >> 1; +if (MP_TEST (va >> 1)) ABORT (ABORT_PRO); if (MEM_ADDR_OK (pa)) { if (va & 1) M[pa] = (M[pa] & 0177400) | (dat & 0377); else M[pa] = (M[pa] & 0377) | ((dat & 0377) << 8); } @@ -2018,8 +2090,8 @@ uint32 pa; if (dms_enb) { dms_viol (va >> 1, MVI_WPR); /* viol if prot */ pa = dms (va >> 1, dms_ump ^ MAP_LNT, WR); } -else { if (MP_TEST (va >> 1)) ABORT (ABORT_PRO); - pa = va >> 1; } +else pa = va >> 1; +if (MP_TEST (va >> 1)) ABORT (ABORT_PRO); if (MEM_ADDR_OK (pa)) { if (va & 1) M[pa] = (M[pa] & 0177400) | (dat & 0377); else M[pa] = (M[pa] & 0377) | ((dat & 0377) << 8); } @@ -2031,8 +2103,8 @@ void WriteW (uint32 va, uint32 dat) uint32 pa; if (dms_enb) pa = dms (va, dms_ump, WR); -else { if (MP_TEST (va)) ABORT (ABORT_PRO); - pa = va; } +else pa = va; +if (MP_TEST (va)) ABORT (ABORT_PRO); if (MEM_ADDR_OK (pa)) M[pa] = dat; return; } @@ -2044,8 +2116,8 @@ int32 pa; if (dms_enb) { dms_viol (va, MVI_WPR); /* viol if prot */ pa = dms (va, dms_ump ^ MAP_LNT, WR); } -else { if (MP_TEST (va)) ABORT (ABORT_PRO); - pa = va; } +else pa = va; +if (MP_TEST (va)) ABORT (ABORT_PRO); if (MEM_ADDR_OK (pa)) M[pa] = dat; return; } @@ -2076,8 +2148,8 @@ if (pgn == 0) { /* base page? */ if (prot == WR) dms_viol (va, MVI_BPG); /* if W, viol */ return va; } } /* no mapping */ mpr = dms_map[map + pgn]; /* get map reg */ -if (mpr & prot) dms_viol (va, prot << (MVI_V_WPR - MAPA_V_WPR)); -return (PA_GETPAG (mpr) | VA_GETOFF (va)); +if (mpr & prot) dms_viol (va, prot); /* prot violation? */ +return (MAP_GETPAG (mpr) | VA_GETOFF (va)); } /* DMS relocation for IO access */ @@ -2095,19 +2167,24 @@ if (pgn == 0) { /* base page? */ (va < dms_fence)) { /* 0B10: < fence */ return va; } } /* no mapping */ mpr = dms_map[map + pgn]; /* get map reg */ -return (PA_GETPAG (mpr) | VA_GETOFF (va)); +return (MAP_GETPAG (mpr) | VA_GETOFF (va)); } /* DMS relocation for console access */ uint32 dms_cons (uint32 va, int32 sw) { -if (sw & SWMASK ("V")) return dms_io (va, dms_ump); -if (sw & SWMASK ("S")) return dms_io (va, SMAP); -if (sw & SWMASK ("U")) return dms_io (va, UMAP); -if (sw & SWMASK ("P")) return dms_io (va, PAMAP); -if (sw & SWMASK ("Q")) return dms_io (va, PBMAP); -return va; +uint32 map_sel; + +if (sw & SWMASK ('V')) map_sel = dms_ump; /* switch? select map */ +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 return va; /* no switch, physical */ +if (va >= VASIZE) return MEMSIZE; /* virtual, must be 15b */ +else if (dms_enb) return dms_io (va, map_sel); /* DMS on? go thru map */ +else return va; /* else return virtual */ } /* Mem protect and DMS validation for jumps */ @@ -2131,19 +2208,14 @@ return; uint16 dms_rmap (uint32 mapi) { -int32 t; - mapi = mapi & MAP_MASK; -t = (((dms_map[mapi] >> VA_N_OFF) & PA_M_PAG) | - ((dms_map[mapi] & (RD | WR)) << (MAPM_V_WPR - MAPA_V_WPR))); -return (uint16) t; +return (dms_map[mapi] & ~MAP_MBZ); } void dms_wmap (uint32 mapi, uint32 dat) { mapi = mapi & MAP_MASK; -dms_map[mapi] = ((dat & PA_M_PAG) << VA_N_OFF) | - ((dat >> (MAPM_V_WPR - MAPA_V_WPR)) & (RD | WR)); +dms_map[mapi] = (uint16) (dat & ~MAP_MBZ); return; } @@ -2172,7 +2244,24 @@ if (CTL (PRO)) dms_sr = dms_sr | MST_PRO; return dms_sr; } -/* Device 0 (CPU) I/O routine */ +/* Device 0 (CPU) I/O routine + + From Dave Bryan: RTE uses the undocumented instruction "SFS 0,C" 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." */ int32 cpuio (int32 inst, int32 IR, int32 dat) { @@ -2184,10 +2273,10 @@ case ioFLG: /* flag */ return dat; case ioSFC: /* skip flag clear */ if (!ion) PC = (PC + 1) & VAMASK; - return dat; + break; case ioSFS: /* skip flag set */ if (ion) PC = (PC + 1) & VAMASK; - return dat; + break; case ioLIX: /* load */ dat = 0; /* returns 0 */ break; @@ -2249,7 +2338,11 @@ default: return dat; } -/* Device 5 (memory protect) I/O routine */ +/* Device 5 (memory protect) I/O routine + + From Dave Bryan: Examination of the schematics for the MP card in the + engineering documentation shows that the SFS and SFC I/O backplane signals + gate the output of the MEVFF onto the SKF line unconditionally. */ int32 proio (int32 inst, int32 IR, int32 dat) { @@ -2257,13 +2350,11 @@ if ((cpu_unit.flags & UNIT_MPR) == 0) /* not installed? */ return nulio (inst, IR, dat); /* non-existent dev */ switch (inst) { /* case on opcode */ case ioSFC: /* skip flag clear */ - if (FLG (PRO) && !mp_mevff) /* skip if mem prot */ - PC = (PC + 1) & VAMASK; - return dat; + if (!mp_mevff) PC = (PC + 1) & VAMASK; /* skip if mem prot */ + break; case ioSFS: /* skip flag set */ - if (FLG (PRO) && mp_mevff) /* skip if DMS */ - PC = (PC + 1) & VAMASK; - return dat; + if (mp_mevff) PC = (PC + 1) & VAMASK; /* skip if DMS */ + break; case ioMIX: /* merge */ dat = dat | mp_viol; break; @@ -2329,10 +2420,10 @@ case ioFLG: /* flag */ break; case ioSFC: /* skip flag clear */ if (FLG (DMA0 + ch) == 0) PC = (PC + 1) & VAMASK; - return dat; + break; case ioSFS: /* skip flag set */ if (FLG (DMA0 + ch) != 0) PC = (PC + 1) & VAMASK; - return dat; + break; case ioMIX: case ioLIX: /* load, merge */ dat = DMASK; break; @@ -2358,9 +2449,10 @@ return dat; - CLC requested: issue CLC Output cases: - neither STC nor CLC requested: issue CLF - - CLC requested but not STC: issue CLC,C - STC requested but not CLC: issue STC,C - - STC and CLC both requested: issue STC,C and CLC,C + - CLC requested but not STC: issue CLC,C + - STC and CLC both requested: issue STC,C and CLC,C, in that order + Either: issue EDT */ void dma_cycle (uint32 ch, uint32 map) @@ -2380,20 +2472,24 @@ dmac[ch].cw3 = (dmac[ch].cw3 + 1) & DMASK; /* incr wcount */ if (dmac[ch].cw3) { /* more to do? */ if (dmac[ch].cw1 & DMA1_STC) /* if STC flag, */ devdisp (dev, ioCTL, I_HC + dev, 0); /* do STC,C dev */ - else devdisp (dev, ioFLG, I_HC + dev, 0); } /* else CLF dev */ + else devdisp (dev, ioFLG, I_HC + dev, 0); /* else CLF dev */ + } else { if (inp) { /* last cycle, input? */ if (dmac[ch].cw1 & DMA1_CLC) /* CLC at end? */ devdisp (dev, ioCTL, I_CTL + dev, 0); /* yes */ } /* end input */ else { /* output */ - devdisp (dev, ioFLG, I_HC + dev, 0); /* clear flag */ + if ((dmac[ch].cw1 & (DMA1_STC | DMA1_CLC)) == 0) + devdisp (dev, ioFLG, I_HC + dev, 0); /* clear flag */ if (dmac[ch].cw1 & DMA1_STC) /* if STC flag, */ - devdisp (dev, ioCTL, dev, 0); /* do STC dev */ + devdisp (dev, ioCTL, I_HC + dev, 0); /* do STC,C dev */ if (dmac[ch].cw1 & DMA1_CLC) /* CLC at end? */ - devdisp (dev, ioCTL, I_CTL + dev, 0); /* yes */ + devdisp (dev, ioCTL, I_HC + I_CTL + dev, 0); /* yes */ } /* end output */ setFLG (DMA0 + ch); /* set DMA flg */ - clrCMD (DMA0 + ch); } /* clr DMA cmd */ + clrCMD (DMA0 + ch); /* clr DMA cmd */ + devdisp (dev, ioEDT, dev, 0); /* do EDT */ + } return; } @@ -2428,6 +2524,7 @@ clrCMD (PRO); clrCTL (PRO); clrFLG (PRO); clrFBF (PRO); +dev_srq[0] = dev_srq[0] & ~M_FXDEV; mp_fence = 0; /* init mprot */ mp_viol = 0; mp_mevff = 0; @@ -2436,7 +2533,8 @@ dms_enb = dms_ump = 0; /* init DMS */ dms_sr = 0; dms_vr = 0; pcq_r = find_reg ("PCQ", NULL, dptr); -sim_brk_types = sim_brk_dflt = SWMASK ('E'); +sim_brk_types = ALL_BKPTS; +sim_brk_dflt = SWMASK ('E'); if (M == NULL) M = calloc (PASIZE, sizeof (unsigned int16)); if (M == NULL) return SCPE_MEM; if (pcq_r) pcq_r->qptr = 0; @@ -2449,6 +2547,7 @@ t_stat dma0_reset (DEVICE *tptr) clrCMD (DMA0); clrCTL (DMA0); setFLG (DMA0); +clrSRQ (DMA0); dmac[0].cw1 = dmac[0].cw2 = dmac[0].cw3 = 0; return SCPE_OK; } @@ -2458,6 +2557,7 @@ t_stat dma1_reset (DEVICE *tptr) clrCMD (DMA1); clrCTL (DMA1); setFLG (DMA1); +clrSRQ (DMA1); dmac[1].cw1 = dmac[1].cw2 = dmac[1].cw3 = 0; return SCPE_OK; } @@ -2468,8 +2568,8 @@ t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw) { int32 d; -if (addr >= MEMSIZE) return SCPE_NXM; addr = dms_cons (addr, sw); +if (addr >= MEMSIZE) return SCPE_NXM; if (addr == 0) d = saved_AR; else if (addr == 1) d = saved_BR; else d = M[addr]; @@ -2481,8 +2581,8 @@ return SCPE_OK; t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw) { -if (addr >= MEMSIZE) return SCPE_NXM; addr = dms_cons (addr, sw); +if (addr >= MEMSIZE) return SCPE_NXM; if (addr == 0) saved_AR = val & DMASK; else if (addr == 1) saved_BR = val & DMASK; else M[addr] = val & DMASK; @@ -2558,7 +2658,7 @@ t_bool dev_conflict (void) { DEVICE *dptr, *cdptr; DIB *dibp, *chkp; -int32 i, j, dno; +uint32 i, j, dno; for (i = 0; cdptr = sim_devices[i]; i++) { chkp = (DIB *) cdptr->ctxt; @@ -2599,4 +2699,59 @@ for (i = 0; opt_val[i].optf != 0; i++) { return SCPE_OK; } } return SCPE_NOFNC; } + +/* IBL routine (CPU boot) */ + +t_stat cpu_boot (int32 unitno, DEVICE *dptr) +{ +extern const uint16 ptr_rom[IBL_LNT], dq_rom[IBL_LNT], ms_rom[IBL_LNT]; +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; +default: + return SCPE_NOFNC; } +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 2's complement of boot base in last location + + Notes: + - SR settings are done by the caller + - Boot ROM's must be assembled with a device code of 10 (10 and 11 for + devices requiring two codes) +*/ + +t_stat ibl_copy (const uint16 pboot[IBL_LNT], int32 dev) +{ +int32 i; +uint16 wd; + +if (dev < 010) return SCPE_ARG; /* valid device? */ +PC = ((MEMSIZE - 1) & ~IBL_MASK) & VAMASK; /* start at mem top */ +for (i = 0; i < IBL_LNT; i++) { /* copy bootstrap */ + wd = pboot[i]; /* get word */ + if (((wd & I_NMRMASK) == I_IO) && /* IO instruction? */ + ((wd & I_DEVMASK) >= 010) && /* dev >= 10? */ + (I_GETIOOP (wd) != ioHLT)) /* not a HALT? */ + M[PC + i] = (wd + (dev - 010)) & DMASK; /* change dev code */ + else M[PC + i] = wd; } /* leave unchanged */ +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; +} diff --git a/HP2100/hp2100_defs.h b/HP2100/hp2100_defs.h index 142da0e0..eacc89c6 100644 --- a/HP2100/hp2100_defs.h +++ b/HP2100/hp2100_defs.h @@ -23,6 +23,8 @@ 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. + 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 @@ -81,7 +83,7 @@ /* Other instructions */ -#define I_NMRMASK 0102000 /* non-mrf opcode */ +#define I_NMRMASK 0172000 /* non-mrf opcode */ #define I_SRG 0000000 /* shift */ #define I_ASKP 0002000 /* alter/skip */ #define I_EXTD 0100000 /* extend */ @@ -98,9 +100,9 @@ #define DMA2_OI 0100000 /* DMA - output/input */ struct DMA { /* DMA channel */ - int32 cw1; /* device select */ - int32 cw2; /* direction, address */ - int32 cw3; /* word count */ + uint32 cw1; /* device select */ + uint32 cw2; /* direction, address */ + uint32 cw3; /* word count */ }; /* Memory management */ @@ -123,18 +125,17 @@ struct DMA { /* DMA channel */ #define PAMAP (UMAP + MAP_LNT) /* port A map */ #define PBMAP (PAMAP + MAP_LNT) /* port B map */ -/* Map entries are left shifted by VA_N_OFF, flags in lower 2b */ +/* DMS map entries */ -#define PA_N_PAG (PA_N_SIZE - VA_N_OFF) /* page width */ -#define PA_V_PAG (VA_N_OFF) -#define PA_M_PAG ((1 << PA_N_PAG) - 1) -#define MAPM_V_RPR 15 /* in mem: read prot */ -#define MAPM_V_WPR 14 /* write prot */ -#define MAPA_V_RPR 1 /* in array: */ -#define MAPA_V_WPR 0 -#define PA_GETPAG(x) ((x) & (PA_M_PAG << VA_V_PAG)) -#define RD (1 << MAPA_V_RPR) -#define WR (1 << MAPA_V_WPR) +#define MAP_V_RPR 15 /* read prot */ +#define MAP_V_WPR 14 /* write prot */ +#define RD (1 << MAP_V_RPR) +#define WR (1 << MAP_V_WPR) +#define MAP_MBZ 0036000 /* must be zero */ +#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) /* Map status register */ @@ -148,8 +149,8 @@ struct DMA { /* DMA channel */ /* Map violation register */ -#define MVI_V_RPR 15 -#define MVI_V_WPR 14 +#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 */ @@ -174,6 +175,7 @@ struct DMA { /* DMA channel */ #define ioLIX 5 /* load into A/B */ #define ioOTX 6 /* output from A/B */ #define ioCTL 7 /* set/clear control */ +#define ioEDT 8 /* DMA: end data transfer */ /* I/O devices - fixed assignments */ @@ -211,31 +213,39 @@ struct DMA { /* DMA channel */ #define MSC 031 /* 13181A control */ #define IPLI 032 /* 12556B link in */ #define IPLO 033 /* 12556B link out */ +#define DS 034 /* 13037 control */ #define MUXL 040 /* 12920A lower data */ #define MUXU 041 /* 12920A upper data */ #define MUXC 042 /* 12920A control */ /* IBL assignments */ +#define IBL_V_SEL 14 /* ROM select */ +#define IBL_M_SEL 03 #define IBL_PTR 0000000 /* PTR */ -#define IBL_DP 0040000 /* DP */ -#define IBL_DQ 0060000 /* DQ */ -#define IBL_MS 0100000 /* MS */ -#define IBL_TBD 0140000 /* tbd */ +#define IBL_DP 0040000 /* disk: DP */ +#define IBL_DQ 0060000 /* disk: DQ */ +#define IBL_MS 0100000 /* option 0: MS */ +#define IBL_DS 0140000 /* option 1: DS */ +#define IBL_MAN 0010000 /* RPL/man boot */ #define IBL_V_DEV 6 /* dev in <11:6> */ -#define IBL_FIX 0000001 /* DP fixed */ +#define IBL_OPT 0000070 /* options in <5:3> */ +#define IBL_DP_REM 0000001 /* DP removable */ #define IBL_LNT 64 /* boot length */ #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 */ /* Dynamic device information table */ struct hp_dib { - int32 devno; /* device number */ - int32 cmd; /* saved command */ - int32 ctl; /* saved control */ - int32 flg; /* saved flag */ - int32 fbf; /* saved flag buf */ - int32 (*iot)(); /* I/O routine */ + uint32 devno; /* device number */ + uint32 cmd; /* saved command */ + uint32 ctl; /* saved control */ + uint32 flg; /* saved flag */ + uint32 fbf; /* saved flag buf */ + uint32 srq; /* saved svc req */ + int32 (*iot)(int32 op, int32 ir, int32 dat); /* I/O routine */ }; typedef struct hp_dib DIB; @@ -254,16 +264,24 @@ typedef struct hp_dib DIB; setFBF(D) #define clrFLG(D) dev_flg[(D)/32] = dev_flg[(D)/32] & ~INT_M (D); \ clrFBF(D) +#define setFSR(D) dev_flg[(D)/32] = dev_flg[(D)/32] | INT_M (D); \ + setFBF(D); setSRQ(D) +#define clrFSR(D) dev_flg[(D)/32] = dev_flg[(D)/32] & ~INT_M (D); \ + clrFBF(D); clrSRQ(D) +#define setSRQ(D) dev_srq[(D)/32] = dev_srq[(D)/32] | INT_M ((D)) +#define clrSRQ(D) dev_srq[(D)/32] = dev_srq[(D)/32] & ~INT_M (D) #define CMD(D) ((dev_cmd[(D)/32] >> INT_V (D)) & 1) #define CTL(D) ((dev_ctl[(D)/32] >> INT_V (D)) & 1) #define FLG(D) ((dev_flg[(D)/32] >> INT_V (D)) & 1) #define FBF(D) ((dev_fbf[(D)/32] >> INT_V (D)) & 1) +#define SRQ(D) ((dev_srq[(D)/32] >> INT_V (D)) & 1) #define IOT_V_REASON 16 #define IORETURN(f,v) ((f)? (v): SCPE_OK) /* stop on error */ /* Function prototypes */ +t_stat ibl_copy (const uint16 pboot[IBL_LNT], int32 dev); t_stat hp_setdev (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat hp_showdev (FILE *st, UNIT *uptr, int32 val, void *desc); void hp_enbdis_pair (DEVICE *ccp, DEVICE *dcp); diff --git a/HP2100/hp2100_diag.txt b/HP2100/hp2100_diag.txt index 263c10f8..84b55d3d 100644 --- a/HP2100/hp2100_diag.txt +++ b/HP2100/hp2100_diag.txt @@ -169,3 +169,12 @@ Peripherals - test 19 uses non-supported read rev 13183 7970E magtape not run in 21MX CE no 12920 multiplexor not run in 21MX CE no + +Bug List (post-release) + +1. SFS x,C and SFC x,C work for all devices, not just device 1. +2. DMS protection does not disable conventional memory protection. +3. Memory protect violation clears automatically when the interrupt is acknowledged. +4. SFS/SFC 5 is not gated by protection enabled. + +3. SBT increments B after the byte store. diff --git a/HP2100/hp2100_doc.txt b/HP2100/hp2100_doc.txt index 4e1c57ee..daceb220 100644 --- a/HP2100/hp2100_doc.txt +++ b/HP2100/hp2100_doc.txt @@ -1,7 +1,7 @@ To: Users From: Bob Supnik Subj: HP2100 Simulator Usage -Date: 15-Feb-2004 +Date: 30-Jun-2004 COPYRIGHT NOTICE @@ -80,7 +80,7 @@ CPU 2116 CPU with 32KW memory 21MX CPU with 1024KW memory, FP or DMS instructions DMA0, DMA1 dual channel DMA controller PTR,PTP 12597A paper tape reader/punch -TTY 12631C buffered terminal controller +TTY 12531C buffered terminal controller LPS 12653A printer controller with 2767 printer 12566B microcircuit interface for diagnostics LPT 12845A printer controller with 2607 printer @@ -99,7 +99,7 @@ IPLO 12556B interprocessor link, output side The HP2100 simulator implements several unique stop conditions: - - decode of an undefined instruction, and STOP_INST is et + - decode of an undefined instruction, and STOP_INST is set - reference to an undefined I/O device, and STOP_DEV is set - more than INDMAX indirect references are detected during memory reference address decoding @@ -149,6 +149,13 @@ These switches are recognized when examining or depositing in CPU memory: -p if DMS enabled, force port A map -q if DMS enabled, force port B map +The CPU implements four different kinds of instruction breakpoints: + + -e break unconditionally + -n break if DMS is disabled + -s break if DMS enabled and system map + -u break if DMS enabled and user map + CPU registers include the visible state of the processor as well as the control registers for the interrupt system. @@ -157,18 +164,20 @@ control registers for the interrupt system. P all 15 program counter A all 16 A register B all 16 B register + M all 15 M (memory address) register + T all 16 T (memory data) register X 21MX 16 X index register Y 21MX 16 Y index register S all 16 switch/display register - F 2100,21MX 15 memory protection fence E all 1 extend flag O all 1 overflow flag ION all 1 interrupt enable flag ION_DEFER all 1 interrupt defer flag - IADDR all 6 most recent interrupting device + CIR all 6 current interrupt register MPCTL 2100,21MX 1 memory protection enable MPFLG 2100,21MX 1 memory protection flag MPFBF 2100,21MX 1 memory protection flag buffer + MPFR 2100,21MX 15 memory protection fence MPVR 2100,21MX 16 memory protection violation reg MPEVR 2100,21MX 1 memory protection freeze flag MPMEV 2100,21MX 1 memory protection DMS error flag @@ -176,7 +185,7 @@ control registers for the interrupt system. DMSCUR 21MX 1 DMS current mode DMSSR 21MX 16 DMS status register DMSVR 21MX 16 DMS violation register - DMSMAP[4][32] 21MX 20 DMS maps + DMSMAP[4][16] 21MX 16 DMS maps STOP_INST all 1 stop on undefined instruction STOP_DEV all 1 stop on undefined device INDMAX all 16 indirect address limit @@ -184,6 +193,24 @@ control registers for the interrupt system. most recent P change first WRU all 8 interrupt character +BOOT CPU implements the 21MX IBL facility. IBL is controlled by the switch +register S. S<15:14> selects the device to boot: + + 00 paper-tape reader (12992K ROM) + 01 7900A/2883 disk (12992A ROM) + 10 7970B/E tape (12992D ROM) + 11 undefined + +For the 7900A/2883 only, S<13:12> specify the type of disk: + + 00 7900A + 10 2883 + +S<11:6> contains the device address. If the device has two addresses, S<11:6> +specifies the lower address. S<5:3> are passed to the bootstrap program. +S<2:0> specify options for the boot loader. IBL will not report an error if +the device address in S<11:6> is incorrect. + 2.2 DMA Controllers The HP2100 includes two DMA channel controllers (DMA0 and DMA1). Each @@ -243,7 +270,13 @@ register specifies the number of the next data item to be read. Thus, by changing POS, the user can backspace or advance the reader. The paper tape reader supports the BOOT command. BOOT PTR copies the -absolute binary loader into memory and starts it running. +IBL into memory and starts it running. The switch register (S) is +set automatically to the value expected by the IBL loader: + + <15:12> = 0000 + <11:6> = device code + <5:3> = unchanged + <2:0> = 000 The paper tape reader implements these registers: @@ -254,6 +287,9 @@ The paper tape reader implements these registers: CTL 1 device/interrupt enable FLG 1 device ready FBF 1 device ready buffer + SRQ 1 device DMA service request + TRLLIM 8 number of trailing nulls to append + after end-of-file is detected POS 32 position in the input file TIME 24 time from I/O initiation to interrupt STOP_IOE 1 stop on I/O error @@ -285,6 +321,7 @@ The paper tape punch implements these registers: CTL 1 device/interrupt enable FLG 1 device ready FBF 1 device ready buffer + SRQ 1 device DMA service request POS 32 position in the output file TIME 24 time from I/O initiation to interrupt STOP_IOE 1 stop on I/O error @@ -298,7 +335,7 @@ Error handling is as follows: OS I/O error x report error and stop -2.4.3 12631C Buffered Terminal (TTY) +2.4.3 12531C Buffered Terminal (TTY) The console terminal has three units: keyboard (unit 0), printer (unit 1), and punch (unit 2). The keyboard reads from the console @@ -307,8 +344,20 @@ punch writes to a disk file. The keyboard and printer units (TTY0, TTY1) can be set to one of three modes: UC, 7B, or 8B. In UC mode, lower case input and output characters are automatically converted to upper case. In 7B mode, input and output characters are masked to 7 -bits. In 8B mode, characters are not modified. Changing the mode -of either unit changes both. The default mode is UC. +bits. In 8B mode, characters are not modified. In UC and 7B mode, +output of null characters is suppressed; in 8B mode, output of null +characters is permitted. Changing the mode of either the keyboard +or the printer changes both. The default mode is UC. + +Some HP software systems expect the console terminal to transmit +line-feed automatically following carriage-return. This feature is +enabled with: + + SET TTY AUTOLF + +and disabled with: + + SET TTY NOAUTOLF The console teleprinter implements these registers: @@ -319,6 +368,7 @@ The console teleprinter implements these registers: CTL 1 device/interrupt enable FLG 1 device ready FBF 1 device ready buffer + SRQ 1 device DMA service request KPOS 32 number of characters input KTIME 24 keyboard polling interval TPOS 32 number of characters printed @@ -363,6 +413,7 @@ The 12653A implements these registers: CTL 1 device/interrupt enable FLG 1 device ready FBF 1 device ready buffer + SRQ 1 device DMA service request POS 32 position in the output file CTIME 24 time between characters PTIME 24 time for a print operation @@ -395,6 +446,7 @@ The line printer implements these registers: CTL 1 device/interrupt enable FLG 1 device ready FBF 1 device ready buffer + SRQ 1 device DMA service request LCNT 7 line count within page POS 32 position in the output file CTIME 24 time between characters @@ -497,6 +549,7 @@ The lines (MUXL) implements these registers: CTL 1 device/interrupt enable FLG 1 device ready FBF 1 device ready buffer + SRQ 1 device DMA service request STA[0:20] 16 line status, lines 0-20 RPAR[0:20] 16 receive parameters, lines 0-20 XPAR[0:15] 16 transmit parameters, lines 0-15 @@ -513,6 +566,7 @@ The modem control (MUXM) implements these registers: CTL 1 device/interrupt enable FLG 1 device ready FBF 1 device ready buffer + SRQ 1 device DMA service request SCAN 1 scan enabled CHAN 4 current line DSO[0:15] 6 C2,C1,ES2,ES1,SS2,SS1, lines 0-15 @@ -574,6 +628,7 @@ Both IPLI and IPLO implement these registers: CTL 1 device/interrupt enable FLG 1 device ready FBF 1 device ready buffer + SRQ 1 device DMA service request TIME 24 polling interval for input STOP_IOE 1 stop on I/O error @@ -596,16 +651,17 @@ a device controller. The data channel includes a 128-word (one sector) buffer for reads and writes. The device controller includes the four disk drives. Disk drives can be set ONLINE or OFFLINE. -The 12557A/13210A supports the BOOT command. BOOT DP loads the IBL -for 7900 class disks into memory and starts it running. BOOT -F DP -boots from the fixed platter (head 2). The switch register (S) is +The 12557A/13210A supports the BOOT command. BOOT DPC copies the IBL +for 7900 class disks into memory and starts it running. BOOT -R DP +boots from the removable platter (head 2). The switch register (S) is set automatically to the value expected by the IBL loader: <15:14> = 01 <13:12> = 00 <11:6> = data channel device code - <5:1> = 00000 - <0> = 1 if booting from the fixed platter + <5:3> = unchanged + <2:1> = 00 + <0> = 1 if booting from the removable platter The data channel implements these registers: @@ -619,6 +675,7 @@ The data channel implements these registers: CTL 1 interrupt enable FLG 1 channel ready FBF 1 channel ready buffer + SRQ 1 channel DMA service request XFER 1 transfer in progress flag WVAL 1 write data valid flag @@ -633,6 +690,7 @@ The device controller implements these registers: CTL 1 interrupt enable FLG 1 controller ready FBF 1 controller ready buffer + SRQ 1 controller DMA service request EOC 1 end of cylinder pending RARC[0:3] 8 record address register cylinder, drives 0-3 RARH[0:3] 2 record address register head, drives 0-3 @@ -660,14 +718,14 @@ a device controller. The data channel includes a 128-word (one sector) buffer for reads and writes. The device controller includes the two disk drives. Disk drives can be set ONLINE or OFFLINE. -The 12565A supports the BOOT command. BOOT DQ loads the IBL for 2883 +The 12565A supports the BOOT command. BOOT DQC copies the IBL for 2883 class disks into memory and starts it running. The switch register (S) is set automatically to the value expected by the IBL loader: - <15:14> = 01 - <13:12> = 10 + <15:12> = 0110 <11:6> = data channel device code - <5:0> = 00000 + <5:3> = unchanged + <2:0> = 000 The data channel implements these registers: @@ -681,6 +739,7 @@ The data channel implements these registers: CTL 1 interrupt enable FLG 1 channel ready FBF 1 channel ready buffer + SRQ 1 channel DMA service request XFER 1 transfer in progress flag WVAL 1 write data valid flag @@ -695,6 +754,7 @@ The device controller implements these registers: CTL 1 interrupt enable FLG 1 controller ready FBF 1 controller ready buffer + SRQ 1 controller DMA service request RARC[0:1] 8 record address register cylinder, drives 0-1 RARH[0:1] 5 record address register head, drives 0-1 RARS[0:1] 5 record address register sector, drives 0-1 @@ -747,6 +807,7 @@ The data channel implements these registers: CTL 1 interrupt enable FLG 1 channel ready FBF 1 channel ready buffer + SRQ 1 channel DMA service request BPTR 6 sector buffer pointer The device controller implements these registers: @@ -759,6 +820,7 @@ The device controller implements these registers: CTL 1 interrupt enable FLG 1 controller ready FBF 1 controller ready buffer + SRQ 1 controller DMA service request TIME 24 interword transfer time STOP_IOE 1 stop on I/O error @@ -793,6 +855,7 @@ The data channel implements these registers: name size comments FLG 1 channel ready + SRQ 1 channel DMA service request DBUF[0:65535] 8 transfer buffer BPTR 16 buffer pointer (reads and writes) BMAX 16 buffer size (writes) @@ -807,6 +870,7 @@ The device controller implements these registers: CTL 1 interrupt enabled FLG 1 controller ready FBF 1 controller ready buffer + SRQ 1 controller DMA service request DTF 1 data transfer flop FSVC 1 first service flop POS 32 magtape position @@ -847,10 +911,10 @@ MS causes the loader to space forward the number of files specified in the A register before starting to load data. The switch register (S) is set automatically to the value expected by the IBL loader: - <15:14> = 10 - <13:12> = 00 + <15:12> = 1000 <11:6> = data channel device code - <5:1> = 00000 + <5:3> = unchanged + <2:0> = 00 <0> = 1 if space forward before loading The data channel implements these registers: @@ -861,6 +925,7 @@ The data channel implements these registers: CTL 1 interrupt enabled FLG 1 channel ready FBF 1 channel ready buffer + SRQ 1 channel DMA service request DBUF[0:65535] 8 transfer buffer BPTR 17 buffer pointer (reads and writes) BMAX 17 buffer size (writes) @@ -876,6 +941,7 @@ The device controller implements these registers: CTL 1 interrupt enabled FLG 1 controller ready FBF 1 controller ready buffer + SRQ 1 controller DMA service request POS[0:3] 32 magtape position CTIME 24 command delay time XTIME 24 interword transfer delay time diff --git a/HP2100/hp2100_dp.c b/HP2100/hp2100_dp.c index 8a1d1424..f33e4615 100644 --- a/HP2100/hp2100_dp.c +++ b/HP2100/hp2100_dp.c @@ -26,6 +26,12 @@ dp 12557A 2871 disk subsystem 13210A 7900 disk subsystem + 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 @@ -122,7 +128,7 @@ extern uint16 *M; extern uint32 PC, SR; -extern uint32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2]; +extern uint32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2], dev_srq[2]; extern int32 sim_switches; extern UNIT cpu_unit; @@ -167,8 +173,8 @@ t_stat dp_showtype (FILE *st, UNIT *uptr, int32 val, void *desc); */ DIB dp_dib[] = { - { DPD, 0, 0, 0, 0, &dpdio }, - { DPC, 0, 0, 0, 0, &dpcio } }; + { DPD, 0, 0, 0, 0, 0, &dpdio }, + { DPC, 0, 0, 0, 0, 0, &dpcio } }; #define dpd_dib dp_dib[0] #define dpc_dib dp_dib[1] @@ -182,6 +188,7 @@ REG dpd_reg[] = { { FLDATA (CTL, dpd_dib.ctl, 0) }, { FLDATA (FLG, dpd_dib.flg, 0) }, { FLDATA (FBF, dpd_dib.fbf, 0) }, + { FLDATA (SRQ, dpd_dib.srq, 0) }, { FLDATA (XFER, dpd_xfer, 0) }, { FLDATA (WVAL, dpd_wval, 0) }, { BRDATA (DBUF, dpxb, 8, 16, DP_NUMWD) }, @@ -227,6 +234,7 @@ REG dpc_reg[] = { { FLDATA (CTL, dpc_dib.ctl, 0) }, { FLDATA (FLG, dpc_dib.flg, 0) }, { FLDATA (FBF, dpc_dib.fbf, 0) }, + { FLDATA (SRQ, dpc_dib.srq, 0) }, { FLDATA (EOC, dpc_eoc, 0) }, { BRDATA (RARC, dpc_rarc, 8, 8, DP_NUMDRV) }, { BRDATA (RARH, dpc_rarh, 8, 2, DP_NUMDRV) }, @@ -275,14 +283,14 @@ int32 devd; devd = IR & I_DEVMASK; /* get device no */ switch (inst) { /* case on opcode */ case ioFLG: /* flag clear/set */ - if ((IR & I_HC) == 0) { setFLG (devd); } /* STF */ + if ((IR & I_HC) == 0) { setFSR (devd); } /* STF */ break; case ioSFC: /* skip flag clear */ if (FLG (devd) == 0) PC = (PC + 1) & VAMASK; - return dat; + break; case ioSFS: /* skip flag set */ if (FLG (devd) != 0) PC = (PC + 1) & VAMASK; - return dat; + break; case ioOTX: /* output */ dpd_obuf = dat; if (!dpc_busy || dpd_xfer) dpd_wval = 1; /* if !overrun, valid */ @@ -306,7 +314,7 @@ case ioCTL: /* control clear/set */ break; default: break; } -if (IR & I_HC) { clrFLG (devd); } /* H/C option */ +if (IR & I_HC) { clrFSR (devd); } /* H/C option */ return dat; } @@ -318,14 +326,14 @@ int32 devd = dpd_dib.devno; devc = IR & I_DEVMASK; /* get device no */ switch (inst) { /* case on opcode */ case ioFLG: /* flag clear/set */ - if ((IR & I_HC) == 0) { setFLG (devc); } /* STF */ + if ((IR & I_HC) == 0) { setFSR (devc); } /* STF */ break; case ioSFC: /* skip flag clear */ if (FLG (devc) == 0) PC = (PC + 1) & VAMASK; - return dat; + break; case ioSFS: /* skip flag set */ if (FLG (devc) != 0) PC = (PC + 1) & VAMASK; - return dat; + break; case ioOTX: /* output */ dpc_obuf = dat; break; @@ -351,7 +359,7 @@ case ioCTL: /* control clear/set */ fnc = CW_GETFNC (dpc_obuf); /* from cmd word */ switch (fnc) { /* case on fnc */ case FNC_STA: /* rd sta */ - if (dp_ctype) { clrFLG (devd); } /* 13210? clr dch flag */ + if (dp_ctype) { clrFSR (devd); } /* 13210? clr dch flag */ case FNC_SEEK: case FNC_CHK: /* seek, check */ case FNC_AR: /* addr rec */ dp_god (fnc, drv, dpc_dtime); /* sched dch xfr */ @@ -365,7 +373,7 @@ case ioCTL: /* control clear/set */ break; default: break; } -if (IR & I_HC) { clrFLG (devc); } /* H/C option */ +if (IR & I_HC) { clrFSR (devc); } /* H/C option */ return dat; } @@ -428,7 +436,7 @@ case FNC_SEEK: /* seek, need cyl */ if (CMD (devd)) { /* dch active? */ dpc_rarc[drv] = DA_GETCYL (dpd_obuf); /* take cyl word */ dpd_wval = 0; /* clr data valid */ - setFLG (devd); /* set dch flg */ + setFSR (devd); /* set dch flg */ clrCMD (devd); /* clr dch cmd */ uptr->FNC = FNC_SEEK1; } /* advance state */ sim_activate (uptr, dpc_xtime); /* no, wait more */ @@ -438,7 +446,7 @@ case FNC_SEEK1: /* seek, need hd/sec */ dpc_rarh[drv] = DA_GETHD (dpd_obuf); /* get head */ dpc_rars[drv] = DA_GETSC (dpd_obuf); /* get sector */ dpd_wval = 0; /* clr data valid */ - setFLG (devd); /* set dch flg */ + setFSR (devd); /* set dch flg */ clrCMD (devd); /* clr dch cmd */ if (sim_is_active (&dpc_unit[drv])) { /* if busy, */ dpc_sta[drv] = dpc_sta[drv] | STA_SKE; @@ -457,7 +465,7 @@ case FNC_AR: /* arec, need cyl */ if (CMD (devd)) { /* dch active? */ dpc_rarc[drv] = DA_GETCYL (dpd_obuf); /* take cyl word */ dpd_wval = 0; /* clr data valid */ - setFLG (devd); /* set dch flg */ + setFSR (devd); /* set dch flg */ clrCMD (devd); /* clr dch cmd */ uptr->FNC = FNC_AR1; } /* advance state */ sim_activate (uptr, dpc_xtime); /* no, wait more */ @@ -467,9 +475,9 @@ case FNC_AR1: /* arec, need hd/sec */ dpc_rarh[drv] = DA_GETHD (dpd_obuf); /* get head */ dpc_rars[drv] = DA_GETSC (dpd_obuf); /* get sector */ dpd_wval = 0; /* clr data valid */ - setFLG (devc); /* set cch flg */ + setFSR (devc); /* set cch flg */ clrCMD (devc); /* clr cch cmd */ - setFLG (devd); /* set dch flg */ + setFSR (devd); /* set dch flg */ clrCMD (devd); } /* clr dch cmd */ else sim_activate (uptr, dpc_xtime); /* no, wait more */ break; @@ -484,7 +492,7 @@ case FNC_STA: /* read status */ else dpd_ibuf = STA_NRDY; /* not ready */ if (dpd_ibuf & STA_ALLERR) /* errors? set flg */ dpd_ibuf = dpd_ibuf | STA_ERR; - setFLG (devd); /* set dch flg */ + setFSR (devd); /* set dch flg */ clrCMD (devd); /* clr dch cmd */ clrCMD (devc); /* clr cch cmd */ dpc_sta[drv] = dpc_sta[drv] & /* clr sta flags */ @@ -498,7 +506,7 @@ case FNC_CHK: /* check, need cnt */ if (CMD (devd)) { /* dch active? */ dpc_cnt = dpd_obuf & DA_CKMASK; /* get count */ dpd_wval = 0; /* clr data valid */ -/* setFLG (devd); /* set dch flg */ +/* setFSR (devd); /* set dch flg */ /* clrCMD (devd); /* clr dch cmd */ dp_goc (FNC_CHK1, drv, dpc_xtime); } /* sched drv */ else sim_activate (uptr, dpc_xtime); /* wait more */ @@ -535,7 +543,7 @@ drv = uptr - dpc_dev.units; /* get drive no */ devc = dpc_dib.devno; /* get cch devno */ devd = dpd_dib.devno; /* get dch devno */ if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */ - setFLG (devc); /* set cch flg */ + setFSR (devc); /* set cch flg */ clrCMD (devc); /* clr cch cmd */ dpc_sta[drv] = 0; /* clr status */ dpc_busy = 0; /* ctlr is free */ @@ -553,7 +561,7 @@ case FNC_SEEK3: /* waiting for flag */ uptr->FNC = FNC_SEEK3; /* next state */ sim_activate (uptr, dpc_xtime); } else { - setFLG (devc); /* set cch flg */ + setFSR (devc); /* set cch flg */ clrCMD (devc); } /* clear cmd */ return SCPE_OK; @@ -589,7 +597,7 @@ case FNC_CHK1: /* check */ if (dpc_cnt == 0) break; } /* stop at zero */ dp_ptr = 0; } /* wrap buf ptr */ if (CMD (devd) && dpd_xfer) { /* dch on, xfer? */ - setFLG (devd); } /* set flag */ + setFSR (devd); } /* set flag */ clrCMD (devd); /* clr dch cmd */ sim_activate (uptr, dpc_xtime); /* sched next word */ return SCPE_OK; @@ -623,7 +631,7 @@ case FNC_WD: /* write */ if (err = ferror (uptr->fileref)) break; /* error? */ dp_ptr = 0; } /* next sector */ if (CMD (devd) && dpd_xfer) { /* dch on, xfer? */ - setFLG (devd); } /* set flag */ + setFSR (devd); } /* set flag */ clrCMD (devd); /* clr dch cmd */ sim_activate (uptr, dpc_xtime); /* sched next word */ return SCPE_OK; @@ -632,7 +640,7 @@ default: return SCPE_IERR; } /* end case fnc */ if (!dp_ctype) dpc_sta[drv] = dpc_sta[drv] | STA_ATN; /* 12559 sets ATN */ -setFLG (devc); /* set cch flg */ +setFSR (devc); /* set cch flg */ clrCMD (devc); /* clr cch cmd */ dpc_busy = 0; /* ctlr is free */ dpd_xfer = dpd_wval = 0; @@ -659,6 +667,7 @@ dpc_dib.cmd = dpd_dib.cmd = 0; /* clear cmd */ dpc_dib.ctl = dpd_dib.ctl = 0; /* clear ctl */ dpc_dib.fbf = dpd_dib.fbf = 1; /* set fbf */ dpc_dib.flg = dpd_dib.flg = 1; /* set flg */ +dpc_dib.srq = dpd_dib.flg = 1; /* srq follows flg */ sim_cancel (&dpd_unit); /* cancel dch */ for (i = 0; i < DP_NUMDRV; i++) { /* loop thru drives */ sim_cancel (&dpc_unit[i]); /* cancel activity */ @@ -711,27 +720,24 @@ return SCPE_OK; /* 7900/7901 bootstrap routine (HP 12992F ROM) */ -#define LDR_BASE 077 -#define CHANGE_DEV (1 << 24) - -static const int32 dboot[IBL_LNT] = { - 0106700+CHANGE_DEV, /*ST CLC DC ; clr dch */ - 0106701+CHANGE_DEV, /* CLC CC ; clr cch */ +const uint16 dp_rom[IBL_LNT] = { + 0106710, /*ST CLC DC ; clr dch */ + 0106711, /* CLC CC ; clr cch */ 0017757, /* JSB STAT ; get status */ 0067746, /*SK LDB SKCMD ; seek cmd */ - 0106600+CHANGE_DEV, /* OTB DC ; cyl # */ - 0103700+CHANGE_DEV, /* STC DC,C ; to dch */ - 0106601+CHANGE_DEV, /* OTB CC ; seek cmd */ - 0103701+CHANGE_DEV, /* STC CC,C ; to cch */ - 0102300+CHANGE_DEV, /* SFS DC ; addr wd ok? */ + 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 = fixed */ - 0106600+CHANGE_DEV, /* OTB DC ; head/sector */ - 0103700+CHANGE_DEV, /* STC DC,C ; to dch */ - 0102301+CHANGE_DEV, /* SFS CC ; seek done? */ + 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 */ @@ -742,11 +748,11 @@ static const int32 dboot[IBL_LNT] = { 0067752, /* LDB CNT ; word count */ 0106602, /* OTB 2 */ 0063745, /* LDB RDCMD ; read cmd */ - 0102601+CHANGE_DEV, /* OTA CC ; to cch */ - 0103700+CHANGE_DEV, /* STC DC,C ; start dch */ - 0103606, /* STC 6,C ; start DMA */ - 0103701+CHANGE_DEV, /* STC CC,C ; start cch */ - 0102301+CHANGE_DEV, /* SFS CC ; done? */ + 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 */ @@ -761,11 +767,11 @@ static const int32 dboot[IBL_LNT] = { 0, 0, 0, 0, /* unused */ 0000000, /*STAT 0 */ 0002400, /* CLA ; status request */ - 0102601+CHANGE_DEV, /* OTC CC ; to cch */ - 0103701+CHANGE_DEV, /* STC CC,C ; start cch */ - 0102300+CHANGE_DEV, /* SFS DC ; done? */ + 0102611, /* OTC CC ; to cch */ + 0103711, /* STC CC,C ; start cch */ + 0102310, /* SFS DC ; done? */ 0027763, /* JMP *-1 */ - 0102500+CHANGE_DEV, /* LIA DC ; get status */ + 0102510, /* LIA DC ; get status */ 0013743, /* AND FSMSK ; mask 15,14,3,0 */ 0002003, /* SZA,RSS ; drive ready? */ 0127757, /* JMP STAT,I ; yes */ @@ -774,23 +780,18 @@ static const int32 dboot[IBL_LNT] = { 0102030, /* HLT 30 ; yes */ 0027700, /* JMP ST ; no, retry */ 0117751, /*XT JSB ADDR2,I ; start program */ - 0120000+CHANGE_DEV, /*DMACW 120000+DC */ + 0120010, /*DMACW 120000+DC */ 0000000 }; /* -ST */ t_stat dpc_boot (int32 unitno, DEVICE *dptr) { -int32 i, dev; +int32 dev; if (unitno != 0) return SCPE_NOFNC; /* only unit 0 */ dev = dpd_dib.devno; /* get data chan dev */ -PC = ((MEMSIZE - 1) & ~IBL_MASK) & VAMASK; /* start at mem top */ -SR = IBL_DP + (dev << IBL_V_DEV); /* set SR */ -if (sim_switches & SWMASK ('F')) SR = SR | IBL_FIX; /* boot from fixed? */ -for (i = 0; i < IBL_LNT; i++) { /* copy bootstrap */ - if (dboot[i] & CHANGE_DEV) /* IO instr? */ - M[PC + i] = (dboot[i] + dev) & DMASK; - else M[PC + i] = dboot[i]; } -M[PC + LDR_BASE] = (~PC + 1) & DMASK; +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; } diff --git a/HP2100/hp2100_dq.c b/HP2100/hp2100_dq.c index f11dab05..18569e8c 100644 --- a/HP2100/hp2100_dq.c +++ b/HP2100/hp2100_dq.c @@ -25,6 +25,11 @@ dq 12565A 2883 disk system + 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 @@ -106,7 +111,7 @@ extern uint16 *M; extern uint32 PC, SR; -extern uint32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2]; +extern uint32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2], dev_srq[2]; extern int32 sim_switches; extern UNIT cpu_unit; @@ -145,8 +150,8 @@ void dq_goc (int32 fnc, int32 drv, int32 time); */ DIB dq_dib[] = { - { DQD, 0, 0, 0, 0, &dqdio }, - { DQC, 0, 0, 0, 0, &dqcio } }; + { DQD, 0, 0, 0, 0, 0, &dqdio }, + { DQC, 0, 0, 0, 0, 0, &dqcio } }; #define dqd_dib dq_dib[0] #define dqc_dib dq_dib[1] @@ -160,6 +165,7 @@ REG dqd_reg[] = { { FLDATA (CTL, dqd_dib.ctl, 0) }, { FLDATA (FLG, dqd_dib.flg, 0) }, { FLDATA (FBF, dqd_dib.fbf, 0) }, + { FLDATA (SRQ, dqd_dib.srq, 0) }, { FLDATA (XFER, dqd_xfer, 0) }, { FLDATA (WVAL, dqd_wval, 0) }, { BRDATA (DBUF, dqxb, 8, 16, DQ_NUMWD) }, @@ -201,6 +207,7 @@ REG dqc_reg[] = { { FLDATA (CTL, dqc_dib.ctl, 0) }, { FLDATA (FLG, dqc_dib.flg, 0) }, { FLDATA (FBF, dqc_dib.fbf, 0) }, + { FLDATA (SRQ, dqc_dib.srq, 0) }, { BRDATA (RARC, dqc_rarc, 8, 8, DQ_NUMDRV) }, { BRDATA (RARH, dqc_rarh, 8, 5, DQ_NUMDRV) }, { BRDATA (RARS, dqc_rars, 8, 5, DQ_NUMDRV) }, @@ -239,14 +246,14 @@ int32 devd; devd = IR & I_DEVMASK; /* get device no */ switch (inst) { /* case on opcode */ case ioFLG: /* flag clear/set */ - if ((IR & I_HC) == 0) { setFLG (devd); } /* STF */ + if ((IR & I_HC) == 0) { setFSR (devd); } /* STF */ break; case ioSFC: /* skip flag clear */ if (FLG (devd) == 0) PC = (PC + 1) & VAMASK; - return dat; + break; case ioSFS: /* skip flag set */ if (FLG (devd) != 0) PC = (PC + 1) & VAMASK; - return dat; + break; case ioOTX: /* output */ dqd_obuf = dat; if (!dqc_busy || dqd_xfer) dqd_wval = 1; /* if !overrun, valid */ @@ -270,7 +277,7 @@ case ioCTL: /* control clear/set */ break; default: break; } -if (IR & I_HC) { clrFLG (devd); } /* H/C option */ +if (IR & I_HC) { clrFSR (devd); } /* H/C option */ return dat; } @@ -281,14 +288,14 @@ int32 devc, fnc, drv; devc = IR & I_DEVMASK; /* get device no */ switch (inst) { /* case on opcode */ case ioFLG: /* flag clear/set */ - if ((IR & I_HC) == 0) { setFLG (devc); } /* STF */ + if ((IR & I_HC) == 0) { setFSR (devc); } /* STF */ break; case ioSFC: /* skip flag clear */ if (FLG (devc) == 0) PC = (PC + 1) & VAMASK; - return dat; + break; case ioSFS: /* skip flag set */ if (FLG (devc) != 0) PC = (PC + 1) & VAMASK; - return dat; + break; case ioOTX: /* output */ dqc_obuf = dat; break; @@ -327,7 +334,7 @@ case ioCTL: /* control clear/set */ break; default: break; } -if (IR & I_HC) { clrFLG (devc); } /* H/C option */ +if (IR & I_HC) { clrFSR (devc); } /* H/C option */ return dat; } @@ -391,7 +398,7 @@ case FNC_SEEK: /* seek, need cyl */ if (CMD (devd)) { /* dch active? */ dqc_rarc[drv] = DA_GETCYL (dqd_obuf); /* take cyl word */ dqd_wval = 0; /* clr data valid */ - setFLG (devd); /* set dch flg */ + setFSR (devd); /* set dch flg */ clrCMD (devd); /* clr dch cmd */ uptr->FNC = FNC_SEEK1; } /* advance state */ sim_activate (uptr, dqc_xtime); /* no, wait more */ @@ -401,7 +408,7 @@ case FNC_SEEK1: /* seek, need hd/sec */ dqc_rarh[drv] = DA_GETHD (dqd_obuf); /* get head */ dqc_rars[drv] = DA_GETSC (dqd_obuf); /* get sector */ dqd_wval = 0; /* clr data valid */ - setFLG (devd); /* set dch flg */ + setFSR (devd); /* set dch flg */ clrCMD (devd); /* clr dch cmd */ if (sim_is_active (&dqc_unit[drv])) break; /* if busy */ st = abs (dqc_rarc[drv] - dqc_unit[drv].CYL) * dqc_stime; @@ -428,7 +435,7 @@ case FNC_LA: /* arec, need cyl */ if (CMD (devd)) { /* dch active? */ dqc_rarc[drv] = DA_GETCYL (dqd_obuf); /* take cyl word */ dqd_wval = 0; /* clr data valid */ - setFLG (devd); /* set dch flg */ + setFSR (devd); /* set dch flg */ clrCMD (devd); /* clr dch cmd */ uptr->FNC = FNC_LA1; } /* advance state */ sim_activate (uptr, dqc_xtime); /* no, wait more */ @@ -438,9 +445,9 @@ case FNC_LA1: /* arec, need hd/sec */ dqc_rarh[drv] = DA_GETHD (dqd_obuf); /* get head */ dqc_rars[drv] = DA_GETSC (dqd_obuf); /* get sector */ dqd_wval = 0; /* clr data valid */ - setFLG (devc); /* set cch flg */ + setFSR (devc); /* set cch flg */ clrCMD (devc); /* clr cch cmd */ - setFLG (devd); /* set dch flg */ + setFSR (devd); /* set dch flg */ clrCMD (devd); } /* clr dch cmd */ else sim_activate (uptr, dqc_xtime); /* no, wait more */ break; @@ -451,7 +458,7 @@ case FNC_STA: /* read status */ dqd_ibuf = dqc_sta[drv] & ~STA_DID; else dqd_ibuf = STA_NRDY; if (drv) dqd_ibuf = dqd_ibuf | STA_DID; - setFLG (devd); /* set dch flg */ + setFSR (devd); /* set dch flg */ clrCMD (devd); /* clr dch cmd */ clrCMD (devc); /* clr cch cmd */ dqc_sta[drv] = dqc_sta[drv] & /* clr sta flags */ @@ -464,7 +471,7 @@ case FNC_CHK: /* check, need cnt */ if (CMD (devd)) { /* dch active? */ dqc_cnt = dqd_obuf & DA_CKMASK; /* get count */ dqd_wval = 0; /* clr data valid */ -/* setFLG (devd); /* set dch flg */ +/* setFSR (devd); /* set dch flg */ /* clrCMD (devd); /* clr dch cmd */ dq_goc (FNC_CHK1, drv, dqc_ctime); } /* sched drv */ else sim_activate (uptr, dqc_xtime); /* wait more */ @@ -504,7 +511,7 @@ drv = uptr - dqc_dev.units; /* get drive no */ devc = dqc_dib.devno; /* get cch devno */ devd = dqd_dib.devno; /* get dch devno */ if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */ - setFLG (devc); /* set cch flg */ + setFSR (devc); /* set cch flg */ clrCMD (devc); /* clr cch cmd */ dqc_sta[drv] = 0; /* clr status */ dqc_busy = 0; /* ctlr is free */ @@ -522,7 +529,7 @@ case FNC_SEEK3: uptr->FNC = FNC_SEEK3; /* next state */ sim_activate (uptr, dqc_xtime); } /* ctrl busy? wait */ else { - setFLG (devc); /* set cch flg */ + setFSR (devc); /* set cch flg */ clrCMD (devc); } /* clr cch cmd */ return SCPE_OK; @@ -537,7 +544,7 @@ case FNC_RA: /* read addr */ dqc_rars[drv] = 0; } else break; dq_ptr = dq_ptr + 1; - setFLG (devd); /* set dch flg */ + setFSR (devd); /* set dch flg */ clrCMD (devd); /* clr dch cmd */ sim_activate (uptr, dqc_xtime); /* sched next word */ return SCPE_OK; @@ -570,7 +577,7 @@ case FNC_CHK1: /* check */ if (dqc_cnt == 0) break; } /* if zero, done */ dq_ptr = 0; } /* wrap buf ptr */ if (CMD (devd) && dqd_xfer) { /* dch on, xfer? */ - setFLG (devd); } /* set flag */ + setFSR (devd); } /* set flag */ clrCMD (devd); /* clr dch cmd */ sim_activate (uptr, dqc_xtime); /* sched next word */ return SCPE_OK; @@ -603,7 +610,7 @@ case FNC_WD: /* write */ if (err = ferror (uptr->fileref)) break; dq_ptr = 0; } if (CMD (devd) && dqd_xfer) { /* dch on, xfer? */ - setFLG (devd); } /* set flag */ + setFSR (devd); } /* set flag */ clrCMD (devd); /* clr dch cmd */ sim_activate (uptr, dqc_xtime); /* sched next word */ return SCPE_OK; @@ -611,7 +618,7 @@ case FNC_WD: /* write */ default: return SCPE_IERR; } /* end case fnc */ -setFLG (devc); /* set cch flg */ +setFSR (devc); /* set cch flg */ clrCMD (devc); /* clr cch cmd */ dqc_busy = 0; /* ctlr is free */ dqd_xfer = dqd_wval = 0; @@ -637,6 +644,7 @@ dqc_dib.cmd = dqd_dib.cmd = 0; /* clear cmd */ dqc_dib.ctl = dqd_dib.ctl = 0; /* clear ctl */ dqc_dib.fbf = dqd_dib.fbf = 1; /* set fbf */ dqc_dib.flg = dqd_dib.flg = 1; /* set flg */ +dqc_dib.srq = dqd_dib.srq = 1; /* srq follows flg */ sim_cancel (&dqd_unit); /* cancel dch */ for (i = 0; i < DQ_NUMDRV; i++) { /* loop thru drives */ sim_cancel (&dqc_unit[i]); /* cancel activity */ @@ -655,66 +663,81 @@ if (uptr->flags & UNIT_ATT) return SCPE_ARG; return SCPE_OK; } -/* 2883/2884 bootstrap routine (subset HP 12992A ROM) */ +/* 7900/7901/2883/2884 bootstrap routine (HP 12992A ROM) */ -#define LDR_BASE 077 -#define CHANGE_DEV (1 << 24) - -static const int32 dboot[IBL_LNT] = { - 0106700+CHANGE_DEV, /*ST CLC DC ; clr dch */ - 0106701+CHANGE_DEV, /* CLC CC ; clr cch */ - 0067771, /* LDA SKCMD ; seek cmd */ - 0106600+CHANGE_DEV, /* OTB DC ; cyl # */ - 0103700+CHANGE_DEV, /* STC DC,C ; to dch */ - 0106601+CHANGE_DEV, /* OTB CC ; seek cmd */ - 0103701+CHANGE_DEV, /* STC CC,C ; to cch */ - 0102300+CHANGE_DEV, /* SFS DC ; addr wd ok? */ - 0027707, /* JMP *-1 ; no, wait */ +const uint16 dq_rom[IBL_LNT] = { + 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 */ - 0106600+CHANGE_DEV, /* OTB DC ; head/sector */ - 0103700+CHANGE_DEV, /* STC DC,C ; to dch */ - 0102301+CHANGE_DEV, /* SFS CC ; seek done? */ - 0027714, /* JMP *-1 ; no, wait */ - 0063770, /* LDA RDCMD ; get read read */ - 0067776, /* LDB DMACW ; DMA control */ + 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 */ - 0067772, /* LDB ADDR1 ; memory addr */ + 0067762, /* LDB ADDR1 ; memory addr */ + 0077741, /* STB RD ; make non re-executable */ 0106602, /* OTB 2 */ 0102702, /* STC 2 ; flip DMA ctrl */ - 0067774, /* LDB CNT ; word count */ + 0067764, /* LDB COUNT ; word count */ 0106602, /* OTB 2 */ - 0102601+CHANGE_DEV, /* OTA CC ; to cch */ - 0103700+CHANGE_DEV, /* STC DC,C ; start dch */ - 0103606, /* STC 6,C ; start DMA */ - 0103701+CHANGE_DEV, /* STC CC,C ; start cch */ - 0102301+CHANGE_DEV, /* SFS CC ; done? */ - 0027732, /* JMP *-1 ; no, wait */ - 0027775, /* JMP XT ; done */ - 0, 0, 0, /* unused */ - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0020000, /*RDCMD 020000 ; read cmd */ - 0030000, /*SKCMD 030000 ; seek cmd */ + 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, /*CNT -6144. */ - 0117773, /*XT JSB ADDR2,I ; start program */ - 0120000+CHANGE_DEV, /*DMACW 120000+DC */ + 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 i, dev; +int32 dev; if (unitno != 0) return SCPE_NOFNC; /* only unit 0 */ dev = dqd_dib.devno; /* get data chan dev */ -PC = ((MEMSIZE - 1) & ~IBL_MASK) & VAMASK; /* start at mem top */ -SR = IBL_DQ + (dev << IBL_V_DEV); /* set SR */ -for (i = 0; i < IBL_LNT; i++) { /* copy bootstrap */ - if (dboot[i] & CHANGE_DEV) /* IO instr? */ - M[PC + i] = (dboot[i] + dev) & DMASK; - else M[PC + i] = dboot[i]; } -M[PC + LDR_BASE] = (~PC + 1) & DMASK; +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; } diff --git a/HP2100/hp2100_dr.c b/HP2100/hp2100_dr.c index 7326fb1a..d41d32d4 100644 --- a/HP2100/hp2100_dr.c +++ b/HP2100/hp2100_dr.c @@ -35,6 +35,9 @@ The drum control channel does not have any of the traditional flip-flops. + 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 @@ -110,7 +113,7 @@ extern UNIT cpu_unit; extern uint16 *M; extern uint32 PC; -extern uint32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2]; +extern uint32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2], dev_srq[2]; int32 drc_cw = 0; /* fnc, addr */ int32 drc_sta = 0; /* status */ @@ -142,8 +145,8 @@ t_stat dr_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); */ DIB dr_dib[] = { - { DRD, 0, 0, 0, 0, &drdio }, - { DRC, 0, 0, 0, 0, &drcio } }; + { DRD, 0, 0, 0, 0, 0, &drdio }, + { DRC, 0, 0, 0, 0, 0, &drcio } }; #define drd_dib dr_dib[0] #define drc_dib dr_dib[1] @@ -157,6 +160,7 @@ REG drd_reg[] = { { FLDATA (CTL, drd_dib.ctl, 0) }, { FLDATA (FLG, drd_dib.flg, 0) }, { FLDATA (FBF, drd_dib.fbf, 0) }, + { FLDATA (SRQ, drd_dib.srq, 0) }, { ORDATA (BPTR, drd_ptr, 6) }, { ORDATA (DEVNO, drd_dib.devno, 6), REG_HRO }, { NULL } }; @@ -192,6 +196,7 @@ REG drc_reg[] = { { FLDATA (CTL, drc_dib.ctl, 0) }, { FLDATA (FLG, drc_dib.flg, 0) }, { FLDATA (FBF, drc_dib.fbf, 0) }, + { FLDATA (SRQ, drc_dib.srq, 0) }, { DRDATA (TIME, dr_time, 24), REG_NZ + PV_LEFT }, { FLDATA (STOP_IOE, dr_stopioe, 0) }, { ORDATA (DEVNO, drc_dib.devno, 6), REG_HRO }, @@ -242,11 +247,11 @@ case ioLIX: /* load */ case ioCTL: /* control clear/set */ if (IR & I_AB) { /* CLC */ clrCMD (devd); /* clr "ctl" */ - clrFLG (devd); /* clr flg */ + clrFSR (devd); /* clr flg */ drc_sta = drc_sta & ~DRS_SAC; } /* clear SAC flag */ else if (!CMD (devd)) { /* STC, not set? */ setCMD (devd); /* set "ctl" */ - if (drc_cw & CW_WR) { setFLG (devd); } /* prime DMA */ + if (drc_cw & CW_WR) { setFSR (devd); } /* prime DMA */ drc_sta = 0; /* clear errors */ drd_ptr = 0; /* clear sec ptr */ sim_cancel (&drc_unit); /* cancel curr op */ @@ -256,7 +261,7 @@ case ioCTL: /* control clear/set */ break; default: break; } -if (IR & I_HC) { clrFLG (devd); } /* H/C option */ +if (IR & I_HC) { clrFSR (devd); } /* H/C option */ return dat; } @@ -267,7 +272,7 @@ int32 st; switch (inst) { /* case on opcode */ case ioSFC: /* skip flag clear */ PC = (PC + 1) & VAMASK; - return dat; + break; case ioOTX: /* output */ drc_cw = dat; break; @@ -310,7 +315,7 @@ if (drc_cw & CW_WR) { /* write? */ uptr->hwmark = da + drd_ptr + 1; } drd_ptr = dr_incda (trk, sec, drd_ptr); /* inc disk addr */ if (CMD (devd)) { /* dch active? */ - setFLG (devd); /* set dch flg */ + setFSR (devd); /* set dch flg */ sim_activate (uptr, dr_time); } /* sched next word */ else if (drd_ptr) { /* done, need to fill? */ for ( ; drd_ptr < DR_NUMWD; drd_ptr++) @@ -321,7 +326,7 @@ else { /* read */ 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); - setFLG (devd); /* set dch flg */ + setFSR (devd); /* set dch flg */ sim_activate (uptr, dr_time); } /* sched next word */ } return SCPE_OK; @@ -354,6 +359,7 @@ drc_dib.cmd = drd_dib.cmd = 0; /* clear cmd */ drc_dib.ctl = drd_dib.ctl = 0; /* clear ctl */ drc_dib.fbf = drd_dib.fbf = 0; /* clear fbf */ drc_dib.flg = drd_dib.flg = 0; /* clear flg */ +drc_dib.srq = drd_dib.srq = 0; /* srq follows flg */ sim_cancel (&drc_unit); return SCPE_OK; } @@ -384,18 +390,17 @@ return SCPE_OK; /* Fixed head disk/drum bootstrap routine (disc subset of disc/paper tape loader) */ -#define CHANGE_DEV (1 << 24) #define BOOT_BASE 056 #define BOOT_START 060 -static const int32 dboot[IBL_LNT - BOOT_BASE] = { - 0020000+CHANGE_DEV, /*DMA 20000+DC */ +static const uint16 dr_rom[IBL_LNT - BOOT_BASE] = { + 0020010, /*DMA 20000+DC */ 0000000, /* 0 */ 0107700, /* CLC 0,C */ 0063756, /* LDA DMA ; DMA ctrl */ 0102606, /* OTA 6 */ 0002700, /* CLA,CCE */ - 0102601+CHANGE_DEV, /* OTA CC ; trk = sec = 0 */ + 0102611, /* OTA CC ; trk = sec = 0 */ 0001500, /* ERA ; A = 100000 */ 0102602, /* OTA 2 ; DMA in, addr */ 0063777, /* LDA M64 */ @@ -404,21 +409,25 @@ static const int32 dboot[IBL_LNT - BOOT_BASE] = { 0103706, /* STC 6,C ; start DMA */ 0067776, /* LDB JSF ; get JMP . */ 0074077, /* STB 77 ; in base page */ - 0102700+CHANGE_DEV, /* STC DC ; start disc */ + 0102710, /* STC DC ; start disc */ 0024077, /*JSF JMP 77 ; go wait */ 0177700 }; /*M64 -100 */ t_stat drc_boot (int32 unitno, DEVICE *dptr) { int32 i, dev, ad; +uint16 wd; if (unitno != 0) return SCPE_NOFNC; /* only unit 0 */ dev = drd_dib.devno; /* get data chan dev */ ad = ((MEMSIZE - 1) & ~IBL_MASK) & VAMASK; /* start at mem top */ -for (i = 0; i < (IBL_LNT - BOOT_BASE); i++) { /* copy bootstrap */ - if (dboot[i] & CHANGE_DEV) /* IO instr? */ - M[ad + BOOT_BASE + i] = (dboot[i] + dev) & DMASK; - else M[ad + BOOT_BASE + i] = dboot[i]; } +for (i = BOOT_BASE; i < IBL_LNT; i++) { /* copy bootstrap */ + wd = dr_rom[i - BOOT_BASE]; /* get word */ + if (((wd & I_NMRMASK) == I_IO) && /* IO instruction? */ + ((wd & I_DEVMASK) >= 010) && /* dev >= 10? */ + (I_GETIOOP (wd) != ioHLT)) /* not a HALT? */ + M[ad + i] = (wd + (dev - 010)) & DMASK; + else M[ad + i] = wd; } PC = ad + BOOT_START; return SCPE_OK; } diff --git a/HP2100/hp2100_ds.c b/HP2100/hp2100_ds.c new file mode 100644 index 00000000..c002bd59 --- /dev/null +++ b/HP2100/hp2100_ds.c @@ -0,0 +1,1398 @@ +/* hp2100_ds.c: HP 2100 13037 disk controller simulator + + Copyright (c) 2004, 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. + + ds 13037 disk controller + + States of the controller: the controller uP runs all the time, but most of + the time it is waiting for an event. The simulator only 'runs' the controller + when there's an event to process: change in CPU interface state, change in + disk state, or timeout. The controller has three states: + + - Idle. No operations other than seek or recalibrate are in progress, and + the CPU interface is disconnected. The controller responds both to new + commands and to drive attention interrupts. + - Wait. No operations other than seek or recalibrate are in progress, but + the CPU interface is connected. The controller responds to new commands + but not to drive attention interrupts. + - Busy. The controller is processing a command. The controller does not + respond to new commands or to drive attention interrupts. + + Omissions: the following features are not implemented: + + - Drive hold. Since this is a single CPU implementation, the drives are + always available to the CPU. + - Spare, defective, protected. The disk files carry only data. + - Formatting. The disk files carry only data. + - ECC. Data errors are always uncorrectable. +*/ + +#include "hp2100_defs.h" +#include + +#define DS_NUMDR 8 /* max drives */ +#define DS_DRMASK (DS_NUMDR - 1) +#define DS_NUMWD 128 /* words/sector */ +#define DS_NUMWDF 138 /* words/full sec */ +#define DS_FSYNC 0 /* full offsets */ +#define DS_FCYL 1 +#define DS_FHS 2 +#define DS_FDATA 3 +#define DS_FIFO_SIZE 16 /* fifo size */ +#define ds_ctrl ds_unit[DS_NUMDR] /* ctrl thread */ +#define ds_timer ds_unit[DS_NUMDR + 1] /* timeout thread */ +#define GET_DA(x,y,z,t) \ + ((((((x) * drv_tab[t].hd) + (y)) * drv_tab[t].sc) + (z)) * DS_NUMWD) +#define GET_CURSEC(x,d) ((int32) fmod (sim_gtime() / ((double) (x)), \ + ((double) (drv_tab[d].sc)))) + +/* Flags in the unit flags word */ + +#define UNIT_V_WLK (UNIT_V_UF + 0) /* write locked */ +#define UNIT_V_FMT (UNIT_V_UF + 1) /* format enabled */ +#define UNIT_V_DTYPE (UNIT_V_UF + 2) /* disk type */ +#define UNIT_M_DTYPE 3 +#define UNIT_V_AUTO (UNIT_V_UF + 4) /* autosize */ +#define UNIT_WLK (1 << UNIT_V_WLK) +#define UNIT_FMT (1 << UNIT_V_FMT) +#define UNIT_DTYPE (UNIT_M_DTYPE << UNIT_V_DTYPE) +#define UNIT_AUTO (1 << UNIT_V_AUTO) +#define GET_DTYPE(x) (((x) >> UNIT_V_DTYPE) & UNIT_M_DTYPE) +#define UNIT_WPR (UNIT_WLK | UNIT_RO) /* write prot */ + +/* Parameters in the unit descriptor */ + +#define FNC u3 /* function */ +#define CYL u4 /* current cylinder */ +#define STA u5 /* status */ + +/* Arguments to subroutines */ + +#define CLR_BUSY 0 /* clear visible busy */ +#define SET_BUSY 1 /* set visible busy */ + +/* Command word - <12:8> are opcode, <7:0> are opcode dependent + + cold load read <7:6> = head + <5:0> = sector + set file mask <7:4> = retry count + <3:0> = file mask (auto-seek options) + commands with units <7> = hold flag + <4:0> = unit number */ + +#define DSC_V_OP 8 /* opcode */ +#define DSC_M_OP 037 +#define DSC_COLD 000 /* cold load read */ +#define DSC_RECAL 001 /* recalibrate */ +#define DSC_SEEK 002 /* seek */ +#define DSC_RSTA 003 /* request status */ +#define DSC_RSA 004 /* request sector addr */ +#define DSC_READ 005 /* read */ +#define DSC_RFULL 006 /* read full */ +#define DSC_VFY 007 /* verify */ +#define DSC_WRITE 010 /* write */ +#define DSC_WFULL 011 /* write full - na */ +#define DSC_CLEAR 012 /* clear */ +#define DSC_INIT 013 /* initialize - na */ +#define DSC_AREC 014 /* address record */ +#define DSC_RSYN 015 /* request syndrome */ +#define DSC_ROFF 016 /* read with offset */ +#define DSC_SFM 017 /* set file mask */ +#define DSC_RNOVFY 022 /* read no verify */ +#define DSC_WTIO 023 /* write TIO */ +#define DSC_RDA 024 /* request disk addr */ +#define DSC_END 025 /* end */ +#define DSC_WAKE 026 /* wakeup */ +#define DSC_ATTN 035 /* pseudo: ATTN */ +#define DSC_BADU 036 /* pseudo: bad unit */ +#define DSC_BADF 037 /* pseudo: bad opcode */ +#define DSC_NEXT 0040 /* state increment */ +#define DSC_2ND 0040 /* subcommand states */ +#define DSC_3RD 0100 +#define DSC_4TH 0140 +#define DSC_V_CHD 6 /* cold load head */ +#define DSC_M_CHD 03 +#define DSC_V_CSC 0 /* cold load sector */ +#define DSC_M_CSC 077 +#define DSC_V_RTY 4 /* retry count */ +#define DSC_M_RTY 017 +#define DSC_V_DECR 3 /* seek decrement */ +#define DSC_V_SPAR 2 /* enable sparing */ +#define DSC_V_CYLM 1 /* cylinder mode */ +#define DSC_V_AUTO 0 /* auto seek */ +#define DSC_V_HOLD 7 /* hold flag */ +#define DSC_V_UNIT 0 /* unit */ +#define DSC_M_UNIT 017 + +#define DSC_HOLD (1u << DSC_V_HOLD) +#define DSC_DECR (1u << DSC_V_DECR) +#define DSC_SPAR (1u << DSC_V_SPAR) +#define DSC_CYLM (1u << DSC_V_CYLM) +#define DSC_AUTO (1u << DSC_V_AUTO) +#define DSC_FMASK ((DSC_M_RTY << DSC_V_RTY)|DSC_DECR|\ + DSC_SPAR|DSC_CYLM|DSC_AUTO) +#define DSC_GETOP(x) (((x) >> DSC_V_OP) & DSC_M_OP) +#define DSC_GETUNIT(x) (((x) >> DSC_V_UNIT) & DSC_M_UNIT) +#define DSC_GETCHD(x) (((x) >> DSC_V_CHD) & DSC_M_CHD) +#define DSC_GETCSC(x) (((x) >> DSC_V_CSC) & DSC_M_CSC) + +/* Command flags */ + +#define CMF_UNDF 001 /* undefined */ +#define CMF_CLREC 002 /* clear eoc flag */ +#define CMF_CLRS 004 /* clear status */ +#define CMF_UNIT 010 /* validate unit */ +#define CMF_UIDLE 020 /* unit must be idle */ + +/* Cylinder words - 16b */ + +/* Head/sector word */ + +#define DSHS_V_HD 8 /* head */ +#define DSHS_M_HD 037 +#define DSHS_V_SC 0 /* sector */ +#define DSHS_M_SC 0377 +#define DSHS_HD (DSHS_M_HD << DSHS_V_HD) +#define DSHS_SC (DSHS_M_SC << DSHS_V_SC) +#define DSHS_GETHD(x) (((x) >> DSHS_V_HD) & DSHS_M_HD) +#define DSHS_GETSC(x) (((x) >> DSHS_V_SC) & DSHS_M_SC) + +/* Status 1 */ + +#define DS1_V_SPAR 15 /* spare - na */ +#define DS1_V_PROT 14 /* protected - na */ +#define DS1_V_DFCT 13 /* defective - na */ +#define DS1_V_STAT 8 /* status */ +#define DS1_OK (000 << DS1_V_STAT) /* normal */ +#define DS1_ILLOP (001 << DS1_V_STAT) /* illegal opcode */ +#define DS1_AVAIL (002 << DS1_V_STAT) /* available */ +#define DS1_CYLCE (007 << DS1_V_STAT) /* cyl compare err */ +#define DS1_UNCOR (010 << DS1_V_STAT) /* uncor data err */ +#define DS1_HSCE (011 << DS1_V_STAT) /* h/s compare err */ +#define DS1_IOPE (012 << DS1_V_STAT) /* IO operation err - na */ +#define DS1_EOCYL (014 << DS1_V_STAT) /* end cylinder */ +#define DS1_OVRUN (016 << DS1_V_STAT) /* overrun */ +#define DS1_CORDE (017 << DS1_V_STAT) /* correctible - na */ +#define DS1_ILLST (020 << DS1_V_STAT) /* illegal spare - na */ +#define DS1_DEFTK (021 << DS1_V_STAT) /* defective trk - na */ +#define DS1_ACCER (022 << DS1_V_STAT) /* access not rdy - na */ +#define DS1_S2ERR (023 << DS1_V_STAT) /* status 2 error */ +#define DS1_TKPER (026 << DS1_V_STAT) /* protected trk - na */ +#define DS1_UNAVL (027 << DS1_V_STAT) /* illegal unit */ +#define DS1_ATTN (037 << DS1_V_STAT) /* attention */ +#define DS1_V_UNIT 0 + +/* Status 2, ^ = kept in unit status, * = dynamic */ + +#define DS2_ERR 0100000 /* *error */ +#define DS2_ATN 0000200 /* ^attention */ +#define DS2_RO 0000100 /* *read only */ +#define DS2_FRM 0000040 /* format - na */ +#define DS2_FLT 0000020 /* fault - na */ +#define DS2_FS 0000010 /* ^first status */ +#define DS2_SC 0000004 /* ^seek error */ +#define DS2_NR 0000002 /* *not ready */ +#define DS2_BS 0000001 /* *busy */ +#define DS2_ALLERR (DS2_FLT|DS2_SC|DS2_NR|DS2_BS) + +/* Drive state */ + +#define DS_IDLE 0 /* idle */ +#define DS_WAIT 1 /* command wait */ +#define DS_BUSY 2 /* busy */ + +/* This controller supports four different disk drive types: + + type #sectors/ #surfaces/ #cylinders/ + surface cylinder drive + + 7905 48 3 411 =15MB + 7906 48 4 411 =20MB + 7920 48 5 823 =50MB + 7925 64 9 823 =120MB + + 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 D7905_DTYPE 0 +#define D7905_SECT 48 +#define D7905_SURF 3 +#define D7905_CYL 411 +#define D7905_ID 2 +#define D7905_SIZE (D7905_SECT * D7905_SURF * D7905_CYL * DS_NUMWD) + +#define D7906_DTYPE 1 +#define D7906_SECT 48 +#define D7906_SURF 4 +#define D7906_CYL 411 +#define D7906_ID 0 +#define D7906_SIZE (D7906_SECT * D7906_SURF * D7906_CYL * DS_NUMWD) + +#define D7920_DTYPE 2 +#define D7920_SECT 48 +#define D7920_SURF 5 +#define D7920_CYL 823 +#define D7920_ID 1 +#define D7920_SIZE (D7920_SECT * D7920_SURF * D7920_CYL * DS_NUMWD) + +#define D7925_DTYPE 3 +#define D7925_SECT 64 +#define D7925_SURF 9 +#define D7925_CYL 823 +#define D7925_ID 3 +#define D7925_SIZE (D7925_SECT * D7925_SURF * D7925_CYL * DS_NUMWD) + +struct drvtyp { + uint32 sc; /* sectors */ + uint32 hd; /* surfaces */ + uint32 cyl; /* cylinders */ + uint32 size; /* #blocks */ + uint32 id; /* device type */ +}; + +static struct drvtyp drv_tab[] = { + { D7905_SECT, D7905_SURF, D7905_CYL, D7905_SIZE, D7905_ID }, + { D7906_SECT, D7906_SURF, D7906_CYL, D7906_SIZE, D7906_ID }, + { D7920_SECT, D7920_SURF, D7920_CYL, D7920_SIZE, D7920_ID }, + { D7925_SECT, D7925_SURF, D7925_CYL, D7925_SIZE, D7925_ID }, + { 0 } }; + +extern uint16 *M; +extern uint32 PC, SR; +extern uint32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2], dev_srq[2]; +extern int32 sim_switches; +extern UNIT cpu_unit; + +uint32 ds_fifo[DS_FIFO_SIZE] = { 0 }; /* fifo */ +uint32 ds_fifo_ip = 0; /* insertion ptr */ +uint32 ds_fifo_rp = 0; /* removal ptr */ +uint32 ds_fifo_cnt = 0; /* count */ +uint32 ds_cmd = 0; /* command word */ +uint32 ds_sr1 = 0; /* status word 1 */ +uint32 ds_u = 0; /* saved unit */ +uint32 ds_busy = 0; /* busy flag */ +uint32 ds_eoc = 0; /* end of cylinder */ +uint32 ds_eod = 0; /* end of data */ +uint32 ds_fmask = 0; /* file mask */ +uint32 ds_cmdf = 0; /* command follows */ +uint32 ds_cmdp = 0; /* command present */ +uint32 ds_cyl = 0; /* disk address: cyl */ +uint32 ds_hs = 0; /* disk address: hs */ +uint32 ds_vctr = 0; /* verify counter */ +uint32 ds_state = 0; /* controller state */ +uint32 ds_lastatn = 0; /* last attn intr */ +int32 ds_stime = 100; /* seek time */ +int32 ds_rtime = 100; /* inter-sector time */ +int32 ds_ctime = 3; /* command time */ +int32 ds_dtime = 1; /* dch time */ +int32 ds_tmo = 1000000; /* timeout */ +uint32 ds_ptr = 0; /* buffer ptr */ +uint16 dsxb[DS_NUMWDF]; /* sector buffer */ + +static const uint32 ds_opflags[32] = { /* flags for ops */ + CMF_CLREC|CMF_CLRS|CMF_UNIT|CMF_UIDLE, /* cold read */ + CMF_CLREC|CMF_CLRS|CMF_UNIT|CMF_UIDLE, /* recalibrate */ + CMF_CLREC|CMF_CLRS|CMF_UNIT|CMF_UIDLE, /* seek */ + 0, /* read status */ + CMF_CLRS, /* read sector */ + CMF_CLRS|CMF_UNIT|CMF_UIDLE, /* read */ + CMF_CLRS|CMF_UNIT|CMF_UIDLE, /* read full */ + CMF_CLRS|CMF_UNIT|CMF_UIDLE, /* verify */ + CMF_CLRS|CMF_UNIT|CMF_UIDLE, /* write */ + CMF_CLRS|CMF_UNIT|CMF_UIDLE, /* write full */ + CMF_CLRS, /* clear */ + CMF_CLRS|CMF_UNIT|CMF_UIDLE, /* init */ + CMF_CLREC|CMF_CLRS, /* addr record */ + 0, /* read syndrome */ + CMF_CLRS|CMF_UNIT|CMF_UIDLE, /* read offset */ + CMF_CLRS, /* set file mask */ + CMF_UNDF|CMF_CLRS, /* undefined */ + CMF_UNDF|CMF_CLRS, /* undefined */ + CMF_CLRS|CMF_UNIT|CMF_UIDLE, /* read no verify */ + CMF_UNDF|CMF_CLRS, /* undefined */ + CMF_UNDF|CMF_CLRS, /* undefined */ + CMF_UNDF|CMF_CLRS, /* undefined */ + CMF_UNDF|CMF_CLRS, /* undefined */ + CMF_UNDF|CMF_CLRS, /* undefined */ + CMF_UNDF|CMF_CLRS, /* undefined */ + CMF_UNDF|CMF_CLRS, /* undefined */ + CMF_UNDF|CMF_CLRS, /* undefined */ + CMF_UNDF|CMF_CLRS, /* undefined */ + CMF_UNDF|CMF_CLRS, /* undefined */ + CMF_UNDF|CMF_CLRS, /* undefined */ + CMF_UNDF|CMF_CLRS }; /* undefined */ + +DEVICE ds_dev; +int32 dsio (int32 inst, int32 IR, int32 dat); +t_stat ds_svc_c (UNIT *uptr); +t_stat ds_svc_u (UNIT *uptr); +t_stat ds_svc_t (UNIT *uptr); +t_stat ds_reset (DEVICE *dptr); +t_stat ds_vlock (UNIT *uptr, int32 val); +t_stat ds_attach (UNIT *uptr, char *cptr); +t_stat ds_detach (UNIT *uptr); +t_stat ds_boot (int32 unitno, DEVICE *dptr); +t_stat ds_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); +void ds_poll (void); +void ds_docmd (uint32 cmd); +uint32 ds_updds2 (UNIT *uptr, uint32 clear); +void ds_cmd_done (t_bool sf, uint32 sr1); +void ds_wait_for_cpu (UNIT *uptr, uint32 newst); +void ds_set_idle (void); +void ds_sched_ctrl_op (uint32 op, uint32 arg, uint32 busy); +void ds_reqad (uint16 *cyl, uint16 *hs); +void ds_start_seek (UNIT *uptr, uint32 cyl, uint32 newst); +t_bool ds_start_rw (UNIT *uptr, int32 tm, t_bool vfy); +void ds_next_sec (UNIT *uptr); +void ds_next_cyl (UNIT *uptr); +t_stat ds_start_rd (UNIT *uptr, uint32 off, t_bool vfy); +void ds_start_wr (UNIT *uptr, t_bool vfy); +void ds_cont_rd (UNIT *uptr, uint32 bsize); +t_stat ds_cont_wr (UNIT *uptr, uint32 off, uint32 bsize); +void ds_end_rw (UNIT *uptr, uint32 newst); +t_stat ds_set_uncorr (UNIT *uptr); +t_stat ds_reset_cmn (DEVICE *dptr); +void ds_sched_attn (UNIT *uptr); +uint32 ds_fifo_read (void); +void ds_fifo_write (uint32 dat); +void ds_fifo_reset (void); + +/* DS data structures + + ds_dev DS device descriptor + ds_unit DS unit list + ds_reg DS register list + ds_mod DS modifier list +*/ + +DIB ds_dib = { DS, 0, 0, 0, 0, 0, &dsio }; + +UNIT ds_unit[] = { + { UDATA (&ds_svc_u, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ + UNIT_ROABLE, D7905_SIZE) }, + { UDATA (&ds_svc_u, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ + UNIT_ROABLE, D7905_SIZE) }, + { UDATA (&ds_svc_u, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ + UNIT_ROABLE, D7905_SIZE) }, + { UDATA (&ds_svc_u, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ + UNIT_ROABLE, D7905_SIZE) }, + { UDATA (&ds_svc_u, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ + UNIT_ROABLE, D7905_SIZE) }, + { UDATA (&ds_svc_u, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ + UNIT_ROABLE, D7905_SIZE) }, + { UDATA (&ds_svc_u, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ + UNIT_ROABLE, D7905_SIZE) }, + { UDATA (&ds_svc_u, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ + UNIT_ROABLE, D7905_SIZE) }, + { UDATA (&ds_svc_c, UNIT_DIS, 0) }, + { UDATA (&ds_svc_t, UNIT_DIS, 0) } }; + +REG ds_reg[] = { + { ORDATA (CMD, ds_cmd, 16) }, + { BRDATA (FIFO, ds_fifo, 8, 16, DS_FIFO_SIZE) }, + { ORDATA (SR1, ds_sr1, 16) }, + { ORDATA (VCTR, ds_vctr, 16) }, + { ORDATA (UNIT, ds_u, 4) }, + { ORDATA (FMASK, ds_fmask, 8) }, + { ORDATA (CYL, ds_cyl, 16) }, + { ORDATA (HS, ds_hs, 12) }, + { ORDATA (STATE, ds_state, 2), REG_RO }, + { ORDATA (LASTA, ds_lastatn, 3) }, + { DRDATA (FIP, ds_fifo_ip, 4) }, + { DRDATA (FRP, ds_fifo_rp, 4) }, + { DRDATA (FCNT, ds_fifo_cnt, 5) }, + { FLDATA (CMD, ds_dib.cmd, 0), REG_HRO }, + { FLDATA (CTL, ds_dib.ctl, 0) }, + { FLDATA (FLG, ds_dib.flg, 0) }, + { FLDATA (FBF, ds_dib.fbf, 0) }, + { FLDATA (SRQ, ds_dib.srq, 0) }, + { FLDATA (BUSY, ds_busy, 0) }, + { FLDATA (CMDF, ds_cmdf, 0) }, + { FLDATA (CMDP, ds_cmdp, 0) }, + { FLDATA (EOC, ds_eoc, 0) }, + { FLDATA (EOD, ds_eod, 0) }, + { BRDATA (DBUF, dsxb, 8, 16, DS_NUMWDF) }, + { FLDATA (DPTR, ds_ptr, 8) }, + { DRDATA (CTIME, ds_ctime, 24), PV_LEFT + REG_NZ }, + { DRDATA (DTIME, ds_dtime, 24), PV_LEFT + REG_NZ }, + { DRDATA (STIME, ds_stime, 24), PV_LEFT + REG_NZ }, + { DRDATA (TTIME, ds_rtime, 24), PV_LEFT + REG_NZ }, + { DRDATA (TIMEOUT, ds_tmo, 31), PV_LEFT + REG_NZ }, + { URDATA (UCYL, ds_unit[0].CYL, 10, 8, 0, + DS_NUMDR + 1, PV_LEFT | REG_HRO) }, + { URDATA (UFNC, ds_unit[0].FNC, 8, 8, 0, + DS_NUMDR + 1, REG_HRO) }, + { URDATA (USTA, ds_unit[0].STA, 8, 16, 0, + DS_NUMDR + 1, REG_HRO) }, + { URDATA (CAPAC, ds_unit[0].capac, 10, T_ADDR_W, 0, + DS_NUMDR, PV_LEFT | REG_HRO) }, + { ORDATA (DEVNO, ds_dib.devno, 6), REG_HRO }, + { NULL } }; + +MTAB ds_mod[] = { + { UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL }, + { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL }, + { UNIT_FMT, 0, "format disabled", "NOFORMAT", NULL }, + { UNIT_FMT, UNIT_FMT, "format enabled", "FORMAT", NULL }, + { (UNIT_DTYPE+UNIT_ATT), (D7905_DTYPE << UNIT_V_DTYPE) + UNIT_ATT, + "7905", NULL, NULL }, + { (UNIT_DTYPE+UNIT_ATT), (D7906_DTYPE << UNIT_V_DTYPE) + UNIT_ATT, + "7906", NULL, NULL }, + { (UNIT_DTYPE+UNIT_ATT), (D7920_DTYPE << UNIT_V_DTYPE) + UNIT_ATT, + "7920", NULL, NULL }, + { (UNIT_DTYPE+UNIT_ATT), (D7925_DTYPE << UNIT_V_DTYPE) + UNIT_ATT, + "7925", NULL, NULL }, + { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (D7905_DTYPE << UNIT_V_DTYPE), + "7905", NULL, NULL }, + { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (D7906_DTYPE << UNIT_V_DTYPE), + "7906", NULL, NULL }, + { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (D7920_DTYPE << UNIT_V_DTYPE), + "7920", NULL, NULL }, + { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (D7925_DTYPE << UNIT_V_DTYPE), + "7925", NULL, NULL }, + { (UNIT_AUTO+UNIT_ATT), UNIT_AUTO, "autosize", NULL, NULL }, + { UNIT_AUTO, UNIT_AUTO, NULL, "AUTOSIZE", NULL }, + { (UNIT_AUTO+UNIT_DTYPE), (D7905_DTYPE << UNIT_V_DTYPE), + NULL, "7905", &ds_set_size }, + { (UNIT_AUTO+UNIT_DTYPE), (D7906_DTYPE << UNIT_V_DTYPE), + NULL, "7906", &ds_set_size }, + { (UNIT_AUTO+UNIT_DTYPE), (D7920_DTYPE << UNIT_V_DTYPE), + NULL, "7920", &ds_set_size }, + { (UNIT_AUTO+UNIT_DTYPE), (D7925_DTYPE << UNIT_V_DTYPE), + NULL, "7925", &ds_set_size }, + { MTAB_XTD | MTAB_VDV, 0, "DEVNO", "DEVNO", + &hp_setdev, &hp_showdev, &ds_dev }, + { 0 } }; + +DEVICE ds_dev = { + "DS", ds_unit, ds_reg, ds_mod, + DS_NUMDR + 2, 8, 27, 1, 8, 16, + NULL, NULL, &ds_reset, + &ds_boot, &ds_attach, &ds_detach, + &ds_dib, DEV_DISABLE }; + +/* IO instructions */ + +int32 dsio (int32 inst, int32 IR, int32 dat) +{ +int32 dev; + +dev = IR & I_DEVMASK; /* get device no */ +switch (inst) { /* case on opcode */ +case ioFLG: /* flag clear/set */ + if ((IR & I_HC) == 0) { setFLG (dev); } /* STF */ + break; +case ioSFS: /* skip flag set */ + if (FLG (dev) != 0) PC = (PC + 1) & VAMASK; + break; +case ioSFC: /* skip flag clear */ + if (ds_busy == 0) PC = (PC + 1) & VAMASK; + break; +case ioOTX: /* output */ + if (ds_cmdf) { /* expecting command? */ + ds_cmd = dat; /* save command */ + ds_cmdf = 0; + ds_cmdp = 1; } /* command present */ + else ds_fifo_write (dat); /* put in fifo */ + break; +case ioMIX: /* merge */ + dat = dat | ds_fifo_read (); + break; +case ioLIX: /* load */ + dat = ds_fifo_read (); + break; +case ioCTL: /* control clear/set */ + if (IR & I_CTL) { /* CLC */ + ds_cmdf = 1; /* expecting command */ + ds_cmdp = 0; /* none pending */ + ds_fifo_reset (); } /* clear fifo */ + else { /* STC */ + setCTL (dev); } /* set ctl */ + break; +case ioEDT: /* end of transfer */ + ds_eod = 1; /* flag end transfer */ + break; +default: + break; } +if (IR & I_HC) { clrFSR (dev); } /* H/C option */ +ds_poll (); /* run the controller */ +return dat; +} + +/* Run the controller polling loop, based on ds_state: + + IDLE commands and ATTN interrupts + WAIT commands only + BUSY nothing +*/ + +void ds_poll (void) +{ +uint32 i; +uint32 dev = ds_dib.devno; + +if (ds_state == DS_BUSY) return; /* ctrl busy? */ +if (ds_cmdp) ds_docmd (ds_cmd); /* cmd pending? */ +if ((ds_state != DS_IDLE) || !CTL (dev)) return; /* waiting for cmd or */ +for (i = 0; i < DS_NUMDR; i++) { /* intr disabled? */ + ds_lastatn = (ds_lastatn + 1) & DS_DRMASK; /* loop through units */ + if (ds_unit[ds_lastatn].STA & DS2_ATN) { /* ATN set? */ + ds_unit[ds_lastatn].STA &= ~DS2_ATN; /* clear ATN */ + setFLG (dev); /* request interrupt */ + ds_sr1 = DS1_ATTN | ds_lastatn; /* set up status 1 */ + ds_state = DS_WAIT; /* block attn intrs */ + return; } } +return; +} + +/* Process a command - ctrl state is either IDLE or WAIT. + + - A drive may be processing a seek or recalibrate + - The controller unit is idle + - If the command can be processed, ds_state is set to BUSY, and + the interface command buffer is cleared + - If the command cannot be processed, ds_state is set to WAIT, + and the command is retained in the interface command buffer */ + +void ds_docmd (uint32 cmd) +{ +uint32 op = DSC_GETOP (cmd); /* operation */ +uint32 f = ds_opflags[op]; /* flags */ +uint32 dtyp; + +if (op == DSC_COLD) ds_u = 0; /* boot force unit 0 */ +else ds_u = DSC_GETUNIT (cmd); /* get unit */ +if ((f & CMF_UIDLE) && (ds_u < DS_NUMDR) && /* idle required */ + sim_is_active (&ds_unit[ds_u])) { /* but unit busy? */ + ds_state = DS_WAIT; /* wait */ + return; } +ds_cmdp = 0; /* flush command */ +ds_state = DS_BUSY; /* ctrl is busy */ +if (f & CMF_CLRS) ds_sr1 = 0; /* clear status */ +if (f & CMF_CLREC) ds_eoc = 0; /* clear end cyl */ +if (f & CMF_UNDF) { /* illegal op? */ + ds_sched_ctrl_op (DSC_BADF, 0, CLR_BUSY); /* sched, not busy */ + return; } +if (f & CMF_UNIT) { /* validate unit? */ + if (f & CMF_CLRS) ds_sr1 = ds_u; /* init status */ + if (ds_u >= DS_NUMDR) { /* invalid unit? */ + ds_sched_ctrl_op (DSC_BADU, ds_u, CLR_BUSY);/* sched, not busy */ + return; } } +switch (op) { + +/* Drive commands */ + +case DSC_COLD: /* cold load read */ + ds_fmask = DSC_SPAR; /* sparing enabled */ + ds_cyl = 0; /* cylinder 0 */ + ds_hs = (DSC_GETCHD (ds_cmd) << DSHS_V_HD) | /* reformat hd/sec */ + (DSC_GETCSC (ds_cmd) << DSHS_V_SC); +case DSC_RECAL: /* recalibrate */ +case DSC_SEEK: /* seek */ +case DSC_READ: /* read */ +case DSC_RFULL: /* read full */ +case DSC_ROFF: /* read offset */ +case DSC_RNOVFY: /* read no verify */ +case DSC_VFY: /* verify */ +case DSC_WRITE: /* write */ +case DSC_WFULL: /* write full */ +case DSC_INIT: /* init */ + ds_unit[ds_u].FNC = op; /* save op */ + ds_unit[ds_u].STA &= ~DS2_ATN; /* clear ATTN */ + sim_activate (&ds_unit[ds_u], ds_ctime); /* schedule unit */ + ds_busy = 1; /* set visible busy */ + break; + +/* Read status commands */ + +case DSC_RSTA: /* read status */ + dsxb[1] = ds_sr1; /* return SR1 */ + if (ds_u >= DS_NUMDR) dsxb[0] = DS2_ERR|DS2_NR|ds_u; /* SR2 */ + else dsxb[0] = ds_updds2 (&ds_unit[ds_u], DS2_FS); + ds_sched_ctrl_op (DSC_RSTA, 2, SET_BUSY); /* sched 2 wds, busy */ + break; +case DSC_RSA: /* read sector address */ + dtyp = GET_DTYPE (ds_unit[ds_u].flags); /* get unit type */ + dsxb[0] = GET_CURSEC (ds_dtime * DS_NUMWD, dtyp); /* rot position */ + ds_sched_ctrl_op (DSC_RSTA, 1, SET_BUSY); /* sched 1 wd, busy */ + break; +case DSC_RDA: /* read disk address */ + ds_reqad (&dsxb[1], &dsxb[0]); /* return disk address */ + ds_sched_ctrl_op (DSC_RSTA, 2, SET_BUSY); /* sched 2 wds, busy */ + break; +case DSC_RSYN: /* read syndrome */ + dsxb[6] = ds_sr1; /* return SR1 */ + ds_reqad (&dsxb[5], &dsxb[4]); /* return disk address */ + dsxb[3] = dsxb[2] = dsxb[1] = dsxb[0] = 0; /* syndrome is 0 */ + ds_sched_ctrl_op (DSC_RSTA, 7, SET_BUSY); /* sched 7 wds, busy */ + break; + +/* Other controller commands */ + +case DSC_SFM: /* set file mask */ +case DSC_CLEAR: /* clear */ +case DSC_AREC: /* address record */ +case DSC_WAKE: /* wakeup */ +case DSC_WTIO: /* write TIO */ + ds_sched_ctrl_op (op, 0, SET_BUSY); /* schedule, busy */ + break; + +case DSC_END: /* end */ + ds_set_idle (); /* idle ctrl */ + break; } +return; +} + +/* Controller service + + The argument for the function, if any, is stored in uptr->CYL */ + +t_stat ds_svc_c (UNIT *uptr) +{ +uint32 op = uptr->FNC; +uint32 dev = ds_dib.devno; + +switch (op) { + +case DSC_AREC: /* address record */ + ds_wait_for_cpu (uptr, DSC_AREC|DSC_2ND); /* set flag, new state */ + break; +case DSC_AREC | DSC_2ND: /* poll done */ + if (!FLG (dev)) { /* OTA x,C? */ + ds_cyl = ds_fifo_read (); /* save cylinder */ + ds_wait_for_cpu (uptr, DSC_AREC|DSC_3RD); }/* set flag, new state */ + else sim_activate (uptr, ds_ctime); /* no, continue poll */ + break; +case DSC_AREC | DSC_3RD: /* poll done */ + if (!FLG (dev)) { /* OTA x,C? */ + ds_hs = ds_fifo_read (); /* save head/sector */ + ds_cmd_done (0, DS1_OK); } /* op done, no flag */ + else sim_activate (uptr, ds_ctime); /* no, continue poll */ + break; + +case DSC_RSTA: /* rd stat (all forms) */ + if (!FLG (dev)) { /* buffer clear? */ + uptr->CYL--; + ds_fifo_write (dsxb[uptr->CYL]); /* store next status */ + ds_wait_for_cpu (uptr, DSC_RSTA | + (uptr->CYL? 0: DSC_2ND)); } /* set flag, new state */ + else sim_activate (uptr, ds_ctime); /* no, continue poll */ + break; +case DSC_RSTA | DSC_2ND: /* poll done */ + if (!FLG (dev)) ds_cmd_done (0, DS1_OK); /* op done? no flag */ + else sim_activate (uptr, ds_ctime); /* no, continue poll */ + break; + +case DSC_CLEAR: /* clear */ + ds_reset_cmn (&ds_dev); /* reset ctrl */ + clrCTL (dev); /* clear CTL, SRQ */ + clrSRQ (dev); + ds_cmd_done (1, DS1_OK); /* op done, set flag */ + break; + +case DSC_SFM: /* set file mask */ + ds_fmask = ds_cmd & DSC_FMASK; + ds_cmd_done (1, DS1_OK); /* op done, set flag */ + break; + +case DSC_WTIO: /* write I/O */ + ds_cmd_done (0, DS1_OK); /* op done, no flag */ + break; + +case DSC_WAKE: /* wakeup */ + ds_cmd_done (1, DS1_AVAIL); /* op done, set flag */ + break; + +case DSC_BADU: /* invalid unit */ + if (uptr->CYL > 10) ds_cmd_done (1, DS1_UNAVL); /* [11,16]? bad unit */ + else ds_cmd_done (1, DS1_S2ERR); /* else unit not ready */ + break; + +case DSC_BADF: /* invalid operation */ + ds_cmd_done (1, DS1_ILLOP); /* op done, set flag */ + break; + +default: + return SCPE_IERR; + } +ds_poll (); /* run the controller */ +return SCPE_OK; +} + +/* Timeout service */ + +t_stat ds_svc_t (UNIT *uptr) +{ +int32 i; + +for (i = 0; i < DS_NUMDR; i++) /* cancel all ops */ + sim_cancel (&ds_unit[i]); +ds_set_idle (); /* idle the controller */ +ds_fmask = 0; /* clear file mask */ +ds_poll (); /* run the controller */ +return SCPE_OK; +} + +/* Unit service */ + +t_stat ds_svc_u (UNIT *uptr) +{ +uint32 op = uptr->FNC; +uint32 dev = ds_dib.devno; +uint32 dtyp = GET_DTYPE (uptr->flags); +t_stat r; + +switch (op) { /* case on function */ + +/* Seek and recalibrate */ + +case DSC_RECAL: /* recalibrate */ + if (uptr->flags & UNIT_ATT) { /* attached? */ + ds_start_seek (uptr, 0, DSC_RECAL|DSC_2ND); /* set up seek */ + ds_set_idle (); } /* ctrl is idle */ + else ds_cmd_done (1, DS1_S2ERR); /* not ready error */ + break; +case DSC_RECAL | DSC_2ND: /* recal complete */ + uptr->STA = uptr->STA | DS2_ATN; /* set attention */ + break; + +case DSC_SEEK: /* seek */ + ds_wait_for_cpu (uptr, DSC_SEEK|DSC_2ND); /* set flag, new state */ + break; +case DSC_SEEK | DSC_2ND: /* waiting for word 1 */ + if (!FLG (dev)) { /* OTA x,C? */ + ds_cyl = ds_fifo_read (); /* save cylinder */ + ds_wait_for_cpu (uptr, DSC_SEEK|DSC_3RD); }/* set flag, new state */ + else sim_activate (uptr, ds_ctime); /* no, continue poll */ + break; +case DSC_SEEK | DSC_3RD: /* waiting for word 2 */ + if (!FLG (dev)) { /* OTA x,C? */ + ds_hs = ds_fifo_read (); /* save head/sector */ + if (uptr->flags & UNIT_ATT) { /* attached? */ + ds_start_seek (uptr, ds_cyl, DSC_SEEK|DSC_4TH); /* set up seek */ + ds_set_idle (); } /* ctrl is idle */ + else ds_cmd_done (1, DS1_S2ERR); } /* else not ready error */ + else sim_activate (uptr, ds_ctime); /* continue poll */ + break; +case DSC_SEEK | DSC_4TH: /* seek complete */ + uptr->STA = uptr->STA | DS2_ATN; /* set attention */ + break; + +/* Read variants */ + +case DSC_ROFF: /* read with offset */ + ds_wait_for_cpu (uptr, DSC_ROFF|DSC_2ND); /* set flag, new state */ + break; +case DSC_ROFF | DSC_2ND: /* poll done */ + if (!FLG (dev)) uptr->FNC = DSC_READ; /* OTA x,C? new state */ + sim_activate (uptr, ds_ctime); /* schedule unit */ + break; + +case DSC_COLD: /* cold load read */ + if (uptr->flags & UNIT_ATT) /* attached? */ + ds_start_seek (uptr, 0, DSC_READ); /* set up seek */ + else ds_cmd_done (1, DS1_S2ERR); /* no, not ready error */ + break; + +case DSC_READ: /* read */ +case DSC_RNOVFY: /* read, no verify */ + if (r = ds_start_rd (uptr, 0, op != DSC_RNOVFY)) /* new sector; error? */ + return r; + break; +case DSC_READ | DSC_2ND: /* word transfer */ + ds_cont_rd (uptr, DS_NUMWD); /* xfr wd, check end */ + break; +case DSC_READ | DSC_3RD: /* end of sector */ + ds_end_rw (uptr, DSC_READ); /* see if more to do */ + break; + +case DSC_RFULL: /* read full */ + if (r = ds_start_rd (uptr, DS_FDATA, 0)) /* new sector; error? */ + return r; + dsxb[DS_FSYNC] = 0100376; /* fill in header */ + dsxb[DS_FCYL] = uptr->CYL; + dsxb[DS_FHS] = ds_hs; + break; +case DSC_RFULL | DSC_2ND: /* word transfer */ + ds_cont_rd (uptr, DS_NUMWDF); /* xfr wd, check end */ + break; +case DSC_RFULL | DSC_3RD: /* end of sector */ + ds_end_rw (uptr, DSC_RFULL); /* see if more to do */ + break; + +case DSC_VFY: /* verify */ + ds_wait_for_cpu (uptr, DSC_VFY|DSC_2ND); /* set flag, new state */ + break; +case DSC_VFY | DSC_2ND: /* poll done */ + if (!FLG (dev)) { /* OTA x,C? */ + ds_vctr = ds_fifo_read (); /* save count */ + uptr->FNC = DSC_VFY | DSC_3RD; /* next state */ + sim_activate (uptr, ds_rtime); } /* delay for transfer */ + else sim_activate (uptr, ds_ctime); /* no, continue poll */ + break; +case DSC_VFY | DSC_3RD: /* start sector */ + if (ds_start_rw (uptr, ds_dtime * DS_NUMWD, 1)) break; + /* new sector; error? */ + ds_next_sec (uptr); /* increment hd, sc */ + break; +case DSC_VFY | DSC_4TH: /* end sector */ + ds_vctr = (ds_vctr - 1) & DMASK; /* decrement count */ + if (ds_vctr) ds_end_rw (uptr, DSC_VFY | DSC_3RD); /* more to do? */ + else ds_cmd_done (1, DS1_OK); /* no, set done */ + break; + +/* Write variants */ + +case DSC_INIT: /* init */ +case DSC_WRITE: /* write */ + ds_start_wr (uptr, op != DSC_INIT); /* new sector */ + break; +case DSC_WRITE | DSC_2ND: + if (r = ds_cont_wr (uptr, 0, DS_NUMWD)) /* write word */ + return r; /* error? */ + break; +case DSC_WRITE | DSC_3RD: /* end sector */ + ds_end_rw (uptr, DSC_WRITE); /* see if more to do */ + break; + +case DSC_WFULL: /* write full */ + ds_start_wr (uptr, 0); /* new sector */ + break; +case DSC_WFULL | DSC_2ND: + if (r = ds_cont_wr (uptr, DS_FDATA, DS_NUMWDF)) + return r; + break; +case DSC_WFULL | DSC_3RD: + ds_end_rw (uptr, DSC_WFULL); /* see if more to do */ + break; + +default: + break; } +ds_poll (); +return SCPE_OK; +} + +/* Schedule timed wait for CPU response + + - Set flag to get CPU attention + - Set specified unit to 'newstate' and schedule + - Schedule timeout */ + +void ds_wait_for_cpu (UNIT *uptr, uint32 newst) +{ +uint32 dev = ds_dib.devno; + +setFLG (dev); /* set flag */ +uptr->FNC = newst; /* new state */ +sim_activate (uptr, ds_ctime); /* activate unit */ +sim_cancel (&ds_timer); /* activate timeout */ +sim_activate (&ds_timer, ds_tmo); +return; +} + +/* Set idle state + + - Controller is set to idle state + - Visible busy is cleared + - Timeout is cancelled */ + +void ds_set_idle (void) +{ +ds_busy = 0; /* busy clear */ +ds_state = DS_IDLE; /* ctrl idle */ +sim_cancel (&ds_timer); /* no timeout */ +return; +} + +/* Set wait state + + - Set flag if required + - Set controller to wait state + - Clear visible busy + - Schedule timeout */ + +void ds_cmd_done (t_bool sf, uint32 sr1) +{ +uint32 dev = ds_dib.devno; + +if (sf) { setFLG (dev); } /* set host flag */ +ds_busy = 0; /* clear visible busy */ +ds_sr1 = ds_sr1 | sr1; /* final status */ +ds_state = DS_WAIT; /* ctrl waiting */ +sim_cancel (&ds_timer); /* activate timeout */ +sim_activate (&ds_timer, ds_tmo); +return; +} + +/* Return drive status (status word 2), clear specified flags */ + +uint32 ds_updds2 (UNIT *uptr, uint32 clear) +{ +uint32 sta; +uint32 dtyp = GET_DTYPE (uptr->flags); + +sta = drv_tab[dtyp].id | /* form status */ + uptr->STA | /* static bits */ + ((uptr->flags & UNIT_WPR)? DS2_RO: 0) | /* dynamic bits */ + ((uptr->flags & UNIT_ATT)? 0: DS2_NR) | + (sim_is_active (uptr)? DS2_BS: 0); +if (sta & DS2_ALLERR) sta = sta | DS2_ERR; /* set error */ +uptr->STA = uptr->STA & ~clear; /* clear static */ +return sta; +} + +/* Schedule controller operation */ + +void ds_sched_ctrl_op (uint32 op, uint32 arg, uint32 busy) +{ +ds_ctrl.FNC = op; /* save op */ +ds_ctrl.CYL = arg; /* save argument */ +ds_busy = busy; /* set visible busy */ +sim_activate (&ds_ctrl, ds_ctime); /* schedule */ +sim_cancel (&ds_timer); /* activate timeout */ +sim_activate (&ds_timer, ds_tmo); +return; +} + +/* Request address - if pending eoc, report cylinder + 1 */ + +void ds_reqad (uint16 *cyl, uint16 *hs) +{ +*cyl = ds_cyl + (ds_eoc? 1: 0); +*hs = ds_hs; +return; +} + +/* Start seek - schedule whether in bounds or out of bounds */ + +void ds_start_seek (UNIT *uptr, uint32 cyl, uint32 newst) +{ +int32 t; +uint32 dtyp = GET_DTYPE (uptr->flags); + +uptr->FNC = newst; /* set new state */ +uptr->STA = uptr->STA & ~DS2_SC; /* clear seek check */ +if (cyl >= drv_tab[dtyp].cyl) { /* out of bounds? */ + uptr->CYL = t = drv_tab[dtyp].cyl; /* put off edge */ + uptr->STA = uptr->STA | DS2_SC; } /* set seek check */ +else { /* seek in range */ + t = abs (uptr->CYL - cyl); /* delta cylinders */ + uptr->CYL = cyl; } /* put on cylinder */ +sim_activate (uptr, ds_stime * (t + 1)); /* schedule */ +return; +} + +/* Start next sector for read or write + + - If error, set command done, return TRUE, nothing is scheduled + - If implicit seek, return TRUE, implicit seek is scheduled, but + state is not changed - we will return here when seek is done + - Otherwise, advance state, set position in file, schedule next state */ + +t_bool ds_start_rw (UNIT *uptr, int32 tm, t_bool vfy) +{ +uint32 da, hd, sc; +uint32 dtyp = GET_DTYPE (uptr->flags); + +if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */ + ds_cmd_done (1, DS1_S2ERR); + return TRUE; } +if (ds_eoc) { /* at end of cylinder? */ + ds_next_cyl (uptr); /* auto seek to next */ + return TRUE; } /* or error */ +if (vfy && ((uint32) uptr->CYL != ds_cyl)) { /* on proper cylinder? */ + ds_cmd_done (1, DS1_CYLCE); /* no, error */ + return TRUE; } +hd = DSHS_GETHD (ds_hs); +sc = DSHS_GETSC (ds_hs); +if ((uint32) uptr->CYL >= drv_tab[dtyp].cyl) { /* valid cylinder? */ + uptr->STA = uptr->STA | DS2_SC; /* set seek check */ + ds_cmd_done (1, DS1_S2ERR); /* error */ + return TRUE; } +if ((hd >= drv_tab[dtyp].hd) || /* valid head, sector? */ + (sc >= drv_tab[dtyp].sc)) { + ds_cmd_done (1, DS1_HSCE); /* no, error */ + return TRUE; } +da = GET_DA (uptr->CYL, hd, sc, dtyp); /* position in file */ +fseek (uptr->fileref, da * sizeof (uint16), SEEK_SET); /* set up I/O oper */ +ds_ptr = 0; /* init buffer ptr */ +uptr->FNC += DSC_NEXT; /* next state */ +sim_activate (uptr, tm); /* activate unit */ +return FALSE; +} + +/* Start next sector for read + + - Do common start for read and write + - If error, return, command has been terminated, nothing scheduled + - If no error, state has been advanced and unit scheduled + - Read sector + - If read error, terminate command and return, nothing scheduled + - If no error, advance head/sector, next state scheduled */ + +t_stat ds_start_rd (UNIT *uptr, uint32 off, t_bool vfy) +{ +uint32 t; + +if (ds_start_rw (uptr, ds_rtime, vfy)) /* new sector; error? */ + return SCPE_OK; /* nothing scheduled */ +t = sim_fread (dsxb + off, sizeof (uint16), DS_NUMWD, uptr->fileref); +for ( ; t < (DS_NUMWDF - off); t++) dsxb[t] = 0; /* fill sector */ +if (ferror (uptr->fileref)) /* error? */ + return ds_set_uncorr (uptr); /* say uncorrectable */ +ds_next_sec (uptr); /* increment hd, sc */ +return SCPE_OK; +} + +/* Start next sector for write + + - Do common start for read and write + - If error, return, command has been terminated, nothing scheduled + - If no error, state has been advanced and unit scheduled + - Clear buffer + - Set service request */ + +void ds_start_wr (UNIT *uptr, t_bool vfy) +{ +uint32 i; +uint32 dev = ds_dib.devno; + +if ((uptr->flags & UNIT_WPR) || /* write protected? */ + (!vfy && ((uptr->flags & UNIT_FMT) == 0))) { /* format, not enbl? */ + ds_cmd_done (1, DS1_S2ERR); /* error */ + return; } +if (ds_start_rw (uptr, ds_rtime, vfy)) return; /* new sector; error? */ +for (i = 0; i < DS_NUMWDF; i++) dsxb[i] = 0; /* clear buffer */ +setSRQ (dev); /* request word */ +return; +} + +/* Advance to next sector (but not next cylinder) */ + +void ds_next_sec (UNIT *uptr) +{ +uint32 dtyp = GET_DTYPE (uptr->flags); +uint32 hd = DSHS_GETHD (ds_hs); +uint32 sc = DSHS_GETSC (ds_hs); + +ds_hs = ds_hs + 1; /* increment sector */ +if (sc < drv_tab[dtyp].sc) return; /* end of track? */ +ds_hs = ds_hs & ~DSHS_SC; /* yes, wrap sector */ +if (ds_fmask & DSC_CYLM) { /* cylinder mode? */ + ds_hs = ds_hs + (1 << DSHS_V_HD); /* increment head */ + if (hd < drv_tab[dtyp].hd) return; /* end of cyl? */ + ds_hs = ds_hs & ~DSHS_HD; } /* 0 head */ +ds_eoc = 1; /* flag end cylinder */ +return; +} + +/* Advance to next cylinder + + - If autoseek enabled, seek to cylinder +/- 1 + - Otherwise, done with end of cylinder error */ + +void ds_next_cyl (UNIT *uptr) +{ +uint32 dtyp = GET_DTYPE (uptr->flags); + +if (ds_fmask & DSC_AUTO) { /* auto seek allowed? */ + if (ds_fmask & DSC_DECR) ds_cyl = (ds_cyl - 1) & DMASK; + else ds_cyl = (ds_cyl + 1) & DMASK; + ds_eoc = 0; /* clear end cylinder */ + ds_start_seek (uptr, ds_cyl, uptr->FNC); } /* seek, same state */ +else ds_cmd_done (1, DS1_EOCYL); /* no, end of cyl err */ +return; +} + +/* Transfer word for read + + - If end of data, terminate command, nothing scheduled + - Otherwise, transfer word, advance state if last word, schedule */ + +void ds_cont_rd (UNIT *uptr, uint32 bsize) +{ +uint32 dev = ds_dib.devno; + +if (ds_eod) ds_cmd_done (1, DS1_OK); /* DMA end? done */ +else { ds_fifo_write (dsxb[ds_ptr++]); /* next word */ + setSRQ (dev); /* request service */ + if (ds_ptr >= bsize) uptr->FNC += DSC_NEXT; /* sec done? next state */ + sim_activate (uptr, ds_dtime); } /* schedule */ +return; +} + +/* Transfer word for write + + - Copy word from fifo to buffer + - If end of data, write buffer, terminate command, nothing scheduled + - If end of sector, write buffer, next state, schedule + - Otherwises, set service request, schedule */ + +t_stat ds_cont_wr (UNIT *uptr, uint32 off, uint32 bsize) +{ +uint32 dev = ds_dib.devno; + +dsxb[ds_ptr++] = ds_fifo_read (); /* next word */ +if (ds_eod || (ds_ptr >= bsize)) { /* xfr or sector done? */ + sim_fwrite (dsxb + off, sizeof (uint16), DS_NUMWD, uptr->fileref); + if (ferror (uptr->fileref)) /* error on write? */ + return ds_set_uncorr (uptr); /* uncorrectable */ + ds_next_sec (uptr); /* increment hd, sc */ + if (ds_eod) { /* end data? */ + ds_cmd_done (1, DS1_OK); /* set done */ + return SCPE_OK; } + else uptr->FNC += DSC_NEXT; } /* no, next state */ +else { setSRQ (dev); } /* request next word */ +sim_activate (uptr, ds_dtime); /* schedule */ +return SCPE_OK; +} + +/* End sector for read or write + + - If end of data, terminate command, nothing scheduled + - If end of cylinder, schedule next cylinder + - Else schedule start of next sector */ + +void ds_end_rw (UNIT *uptr, uint32 newst) +{ +uptr->FNC = newst; /* new state */ +if (ds_eod) ds_cmd_done (1, DS1_OK); /* done? */ +else if (ds_eoc) ds_next_cyl (uptr); /* end cyl? seek if auto */ +else sim_activate (uptr, ds_rtime); /* normal transfer */ +return; +} + +/* Report uncorrectable data error */ + +t_stat ds_set_uncorr (UNIT *uptr) +{ +sim_cancel (uptr); /* cancel any operation */ +ds_cmd_done (1, DS1_UNCOR); /* done with error */ +perror ("DS I/O error"); /* visible error */ +clearerr (uptr->fileref); +ds_poll (); /* force poll */ +return SCPE_IOERR; +} + +/* Fifo read */ + +uint32 ds_fifo_read (void) +{ +uint32 dat; + +if (ds_fifo_cnt == 0) return ds_fifo[ds_fifo_rp]; +dat = ds_fifo[ds_fifo_rp++]; +if (ds_fifo_rp >= DS_FIFO_SIZE) ds_fifo_rp = 0; +ds_fifo_cnt--; +return dat; +} + +void ds_fifo_write (uint32 dat) +{ +ds_fifo[ds_fifo_ip++] = dat; +if (ds_fifo_ip >= DS_FIFO_SIZE) ds_fifo_ip = 0; +if (ds_fifo_cnt < DS_FIFO_SIZE) ds_fifo_cnt++; +return; +} + +void ds_fifo_reset (void) +{ +uint32 i; + +ds_fifo_ip = ds_fifo_rp = ds_fifo_cnt = 0; +for (i = 0; i < DS_FIFO_SIZE; i++) ds_fifo[i] = 0; +return; +} + +/* Reset routine */ + +t_stat ds_reset_cmn (DEVICE *dptr) +{ +int32 i; + +ds_cmd = 0; /* clear command */ +ds_cmdf = ds_cmdp = 0; /* clear commands flops */ +ds_fifo_reset (); /* clear fifo */ +ds_eoc = ds_eod = 0; +ds_busy = 0; +ds_state = DS_IDLE; /* ctrl idle */ +ds_lastatn = 0; +ds_fmask = 0; +ds_ptr = 0; +ds_cyl = ds_hs = 0; +ds_vctr = 0; +for (i = 0; i < DS_NUMDR; i++) { /* loop thru drives */ + sim_cancel (&ds_unit[i]); /* cancel activity */ + ds_unit[i].FNC = 0; /* clear function */ + ds_unit[i].CYL = 0; + ds_unit[i].STA = 0; } +sim_cancel (&ds_ctrl); +sim_cancel (&ds_timer); +return SCPE_OK; +} + +t_stat ds_reset (DEVICE *dptr) +{ +ds_dib.cmd = 0; /* clear cmd */ +ds_dib.ctl = 0; /* clear ctl */ +ds_dib.fbf = 1; /* set fbf */ +ds_dib.flg = 1; /* set flg */ +ds_dib.srq = 0; /* clear srq */ +return ds_reset_cmn (dptr); /* do common reset */ +} + +/* Device attach */ + +t_stat ds_attach (UNIT *uptr, char *cptr) +{ +uint32 i, p; +t_stat r; + +uptr->capac = drv_tab[GET_DTYPE (uptr->flags)].size; +r = attach_unit (uptr, cptr); /* attach unit */ +if (r != SCPE_OK) return r; /* error? */ +uptr->STA = DS2_ATN | DS2_FS; /* update drive status */ +if (ds_dib.ctl) ds_sched_attn (uptr); /* if CTL, sched ATTN */ +if (((p = sim_fsize (uptr->fileref)) == 0) || /* new disk image? */ + ((uptr->flags & UNIT_AUTO) == 0)) return SCPE_OK; /* static size? */ +for (i = 0; drv_tab[i].sc != 0; i++) { /* find best fit */ + if (p <= (drv_tab[i].size * sizeof (uint16))) { + uptr->flags = (uptr->flags & ~UNIT_DTYPE) | (i << UNIT_V_DTYPE); + uptr->capac = drv_tab[i].size; + return SCPE_OK; } } +return SCPE_OK; +} + +/* Device detach */ + +t_stat ds_detach (UNIT *uptr) +{ +uptr->STA = DS2_ATN; /* update drive status */ +if (ds_dib.ctl) ds_sched_attn (uptr); /* if CTL, sched ATTN */ +return detach_unit (uptr); +} + +/* Schedule attention interrupt if controller idle */ + +void ds_sched_attn (UNIT *uptr) +{ +int32 i; + +for (i = 0; i < (DS_NUMDR + 1); i++) { /* check units, ctrl */ + if (sim_is_active (ds_dev.units + i)) return; } +uptr->FNC = DSC_ATTN; /* pseudo operation */ +sim_activate (uptr, 1); /* do immediately */ +return; +} + +/* Set size command validation routine */ + +t_stat ds_set_size (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +if (uptr->flags & UNIT_ATT) return SCPE_ALATT; +uptr->capac = drv_tab[GET_DTYPE (val)].size; +return SCPE_OK; +} + +/* 13037 bootstrap routine (HP 12992B ROM) */ + +const uint16 ds_rom[IBL_LNT] = { + 0017727, /* STRT 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 ; faulty or hard down? */ + 0102030, /* HLT 30B ; HALT 30B */ + 0027700, /* JMP STRT ; try again */ + 0102011, /* ADR1 OCT 102011 */ + 0102055, /* ADR2 OCT 102055 */ + 0164000, /* CNT DEC -6144 */ + 0000007, /* D7 OCT 7 */ + 0001400, /* STCM OCT 1400 */ + 0000020, /* B20 OCT 20 */ + 0017400, /* STMS OCT 17400 */ + 0000000, /* 9 NOP's */ + 0000000, + 0000000, + 0000000, + 0000000, + 0000000, + 0000000, + 0000000, + 0000000, + 0000000, /* STAT NOP ; status check routine */ + 0107710, /* CLC DC,C ; set command mode */ + 0063713, /* LDA STCM ; get status command */ + 0102610, /* OTA DC ; output status command */ + 0102310, /* SFS DC ; wait for stat#1 word */ + 0027733, /* JMP *-1 */ + 0107510, /* LIB DC,C ; B-reg - status#1 word */ + 0102310, /* SFS DC ; wait for stat#2 word */ + 0027736, /* JMP *-1 */ + 0103510, /* LIA DC,C ; A-reg - status#2 word */ + 0127727, /* JMP STAT,I ; return */ + 0067776, /* DMA LDB DMAC ; get DMA control word */ + 0106606, /* OTB 6 ; output DMA ctrl word */ + 0067707, /* LDB ADR1 ; get memory address */ + 0106702, /* CLC 2 ; set memory addr mode */ + 0106602, /* OTB 2 ; output mem addr to DMA */ + 0102702, /* STC 2 ; set word count mode */ + 0067711, /* LDB CNT ; get word count */ + 0106602, /* OTB 2 ; output word cnt to DMA */ + 0106710, /* CLC CLC DC ; set command follows */ + 0102501, /* LIA 1 ; load switches */ + 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, head# = 0? */ + 0001000, /* ALS ; no, head# = 1 --> 2 */ + 0001720, /* ALF,ALS ; form cold load */ + 0001000, /* ALS ; command word */ + 0103706, /* STC 6,C ; activate DMA */ + 0103610, /* OTA DC,C ; output cold load cmd */ + 0102310, /* SFS DC ; is cold load done? */ + 0027766, /* JMP *-1 ; no, wait */ + 0017727, /* JSB STAT ; yes, get status */ + 0060001, /* LDA 1 ; get status word #1 */ + 0013715, /* AND STMS ; isolate status bits */ + 0002002, /* SZA ; is transfer ok? */ + 0027700, /* JMP STRT ; no, try again */ + 0117710, /* JSB ADR2,I ; yes, start program */ + 0000010, /* DMAC ABS DC ; DMA command word */ + 0170100, /* ABS -STRT */ +}; + +t_stat ds_boot (int32 unitno, DEVICE *dptr) +{ +int32 dev; + +if (unitno != 0) return SCPE_NOFNC; /* only unit 0 */ +dev = ds_dib.devno; /* get data chan dev */ +if (ibl_copy (ds_rom, dev)) return SCPE_IERR; /* copy boot to memory */ +SR = (SR & IBL_OPT) | IBL_DS | IBL_MAN | (dev << IBL_V_DEV); /* set SR */ +return SCPE_OK; +} diff --git a/HP2100/hp2100_ipl.c b/HP2100/hp2100_ipl.c index af3086e1..454c78d2 100644 --- a/HP2100/hp2100_ipl.c +++ b/HP2100/hp2100_ipl.c @@ -25,6 +25,8 @@ ipli, iplo 12556B interprocessor link pair + 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) @@ -48,7 +50,7 @@ #define LSOCKET u4 /* listening socket */ extern uint32 PC; -extern uint32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2]; +extern uint32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2], dev_srq[2]; extern FILE *sim_log; int32 ipl_ptime = 31; /* polling interval */ int32 ipl_stopioe = 0; /* stop on error */ @@ -75,8 +77,8 @@ t_bool ipl_check_conn (UNIT *uptr); */ DIB ipl_dib[] = { - { IPLI, 0, 0, 0, 0, &ipliio }, - { IPLO, 0, 0, 0, 0, &iploio } }; + { IPLI, 0, 0, 0, 0, 0, &ipliio }, + { IPLO, 0, 0, 0, 0, 0, &iploio } }; #define ipli_dib ipl_dib[0] #define iplo_dib ipl_dib[1] @@ -95,6 +97,7 @@ REG ipli_reg[] = { { FLDATA (CTL, ipli_dib.ctl, 0) }, { FLDATA (FLG, ipli_dib.flg, 0) }, { FLDATA (FBF, ipli_dib.fbf, 0) }, + { FLDATA (SRQ, ipli_dib.srq, 0) }, { ORDATA (HOLD, ipl_hold[0], 8) }, { DRDATA (TIME, ipl_ptime, 24), PV_LEFT }, { FLDATA (STOP_IOE, ipl_stopioe, 0) }, @@ -131,6 +134,7 @@ REG iplo_reg[] = { { FLDATA (CTL, iplo_dib.ctl, 0) }, { FLDATA (FLG, iplo_dib.flg, 0) }, { FLDATA (FBF, iplo_dib.fbf, 0) }, + { FLDATA (SRQ, iplo_dib.srq, 0) }, { ORDATA (HOLD, ipl_hold[1], 8) }, { DRDATA (TIME, ipl_ptime, 24), PV_LEFT }, { ORDATA (DEVNO, iplo_dib.devno, 6), REG_HRO }, @@ -164,14 +168,14 @@ int8 msg[2]; dev = IR & I_DEVMASK; /* get device no */ switch (inst) { /* case on opcode */ case ioFLG: /* flag clear/set */ - if ((IR & I_HC) == 0) { setFLG (dev); } /* STF */ + if ((IR & I_HC) == 0) { setFSR (dev); } /* STF */ break; case ioSFC: /* skip flag clear */ if (FLG (dev) == 0) PC = (PC + 1) & VAMASK; - return dat; + break; case ioSFS: /* skip flag set */ if (FLG (dev) != 0) PC = (PC + 1) & VAMASK; - return dat; + break; case ioOTX: /* output */ uptr->OBUF = dat; break; @@ -204,12 +208,12 @@ case ioCTL: /* control clear/set */ u = (uptr - ipl_unit) ^ 1; /* find other device */ ipl_unit[u].IBUF = uptr->OBUF; /* output to other */ odev = ipl_dib[u].devno; /* other device no */ - setFLG (odev); } /* set other flag */ + setFSR (odev); } /* set other flag */ else return SCPE_UNATT; } /* lose */ break; default: break; } -if (IR & I_HC) { clrFLG (dev); } /* H/C option */ +if (IR & I_HC) { clrFSR (dev); } /* H/C option */ return dat; } @@ -241,7 +245,7 @@ else uptr->IBUF = ((((int32) msg[0]) & 0377) << 8) | (((int32) msg[1]) & 0377); dev = ipl_dib[u].devno; /* get device number */ clrCMD (dev); /* clr cmd, set flag */ -setFLG (dev); +setFSR (dev); return SCPE_OK; } @@ -268,7 +272,7 @@ UNIT *uptr = dptr->units; hp_enbdis_pair (&ipli_dev, &iplo_dev); /* make pair cons */ dibp->cmd = dibp->ctl = 0; /* clear cmd, ctl */ -dibp->flg = dibp->fbf = 1; /* set flg, fbf */ +dibp->flg = dibp->fbf = dibp->srq = 1; /* set flg, fbf, srq */ uptr->IBUF = uptr->OBUF = 0; /* clr buffers */ if (uptr->flags & UNIT_ATT) sim_activate (uptr, ipl_ptime); else sim_cancel (uptr); /* deactivate unit */ @@ -381,13 +385,13 @@ return SCPE_OK; /* Interprocessor link bootstrap routine (HP Access Manual) */ -#define LDR_BASE 073 +#define MAX_BASE 073 #define IPL_PNTR 074 #define PTR_PNTR 075 #define IPL_DEVA 076 #define PTR_DEVA 077 -static const int32 pboot[IBL_LNT] = { +static const uint32 pboot[IBL_LNT] = { 0163774, /*BBL LDA ICK,I ; IPL sel code */ 0027751, /* JMP CFG ; go configure */ 0107700, /*ST CLC 0,C ; intr off */ @@ -467,7 +471,7 @@ devp = ptr_dib.devno; PC = ((MEMSIZE - 1) & ~IBL_MASK) & VAMASK; /* start at mem top */ SR = (devi << IBL_V_DEV) | devp; /* set SR */ for (i = 0; i < IBL_LNT; i++) M[PC + i] = pboot[i]; /* copy bootstrap */ -M[PC + LDR_BASE] = (~PC + 1) & DMASK; /* fix ups */ +M[PC + MAX_BASE] = (~PC + 1) & DMASK; /* fix ups */ M[PC + IPL_PNTR] = M[PC + IPL_PNTR] | PC; M[PC + PTR_PNTR] = M[PC + PTR_PNTR] | PC; M[PC + IPL_DEVA] = devi; diff --git a/HP2100/hp2100_lps.c b/HP2100/hp2100_lps.c index 005bb19c..18bea87b 100644 --- a/HP2100/hp2100_lps.c +++ b/HP2100/hp2100_lps.c @@ -26,6 +26,9 @@ lps 12653A 2767 line printer (based on 12556B microcircuit interface) + 03-Jun-04 RMS Fixed timing (found by Dave Bryan) + 26-Apr-04 RMS Fixed SFS x,C and SFC x,C + Implemented DMA SRQ (follows FLG) 25-Apr-03 RMS Revised for extended file support 24-Oct-02 RMS Added microcircuit test features 30-May-02 RMS Widened POS to 32b @@ -44,8 +47,9 @@ #define UNIT_DIAG (1 << UNIT_V_DIAG) extern uint32 PC; -extern uint32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2]; -int32 lps_ctime = 1000; /* char time */ +extern uint32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2], dev_srq[2]; +int32 lps_ctime = 4; /* char time */ +int32 lps_ptime = 10000; /* print time */ int32 lps_stopioe = 0; /* stop on error */ int32 lps_sta = 0; @@ -61,10 +65,10 @@ t_stat lps_reset (DEVICE *dptr); lps_reg LPS register list */ -DIB lps_dib = { LPS, 0, 0, 0, 0, &lpsio }; +DIB lps_dib = { LPS, 0, 0, 0, 0, 0, &lpsio }; UNIT lps_unit = { - UDATA (&lps_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT }; + UDATA (&lps_svc, UNIT_SEQ+UNIT_ATTABLE, 0) }; REG lps_reg[] = { { ORDATA (BUF, lps_unit.buf, 16) }, @@ -73,9 +77,10 @@ REG lps_reg[] = { { FLDATA (CTL, lps_dib.ctl, 0) }, { FLDATA (FLG, lps_dib.flg, 0) }, { FLDATA (FBF, lps_dib.fbf, 0) }, + { FLDATA (SRQ, lps_dib.srq, 0) }, { DRDATA (POS, lps_unit.pos, T_ADDR_W), PV_LEFT }, { DRDATA (CTIME, lps_ctime, 31), PV_LEFT }, - { DRDATA (PTIME, lps_unit.wait, 24), PV_LEFT }, + { DRDATA (PTIME, lps_ptime, 24), PV_LEFT }, { FLDATA (STOP_IOE, lps_stopioe, 0) }, { ORDATA (DEVNO, lps_dib.devno, 6), REG_HRO }, { NULL } }; @@ -103,14 +108,14 @@ int32 dev; dev = IR & I_DEVMASK; /* get device no */ switch (inst) { /* case on opcode */ case ioFLG: /* flag clear/set */ - if ((IR & I_HC) == 0) { setFLG (dev); } /* STF */ + if ((IR & I_HC) == 0) { setFSR (dev); } /* STF */ break; case ioSFC: /* skip flag clear */ if (FLG (dev) == 0) PC = (PC + 1) & VAMASK; - return dat; + break; case ioSFS: /* skip flag set */ if (FLG (dev) != 0) PC = (PC + 1) & VAMASK; - return dat; + break; case ioOTX: /* output */ lps_unit.buf = dat; break; @@ -135,11 +140,11 @@ case ioCTL: /* control clear/set */ if (lps_unit.flags & UNIT_DIAG) /* diagnostic? */ sim_activate (&lps_unit, 1); /* loop back */ else sim_activate (&lps_unit, /* real lpt, sched */ - (lps_unit.buf < 040)? lps_unit.wait: lps_ctime); } + (lps_unit.buf < 040)? lps_ptime: lps_ctime); } break; default: break; } -if (IR & I_HC) { clrFLG (dev); } /* H/C option */ +if (IR & I_HC) { clrFSR (dev); } /* H/C option */ return dat; } @@ -150,7 +155,7 @@ int32 c = lps_unit.buf & 0177; dev = lps_dib.devno; /* get dev no */ clrCMD (dev); /* clear cmd */ -setFLG (dev); /* set flag, fbf */ +setFSR (dev); /* set flag, fbf */ if (lps_unit.flags & UNIT_DIAG) { /* diagnostic? */ lps_sta = lps_unit.buf; /* loop back */ return SCPE_OK; } /* done */ @@ -169,7 +174,7 @@ return SCPE_OK; t_stat lps_reset (DEVICE *dptr) { lps_dib.cmd = lps_dib.ctl = 0; /* clear cmd, ctl */ -lps_dib.flg = lps_dib.fbf = 1; /* set flg, fbf */ +lps_dib.flg = lps_dib.fbf = lps_dib.srq = 1; /* set flg, fbf, srq */ lps_sta = lps_unit.buf = 0; sim_cancel (&lps_unit); /* deactivate unit */ return SCPE_OK; diff --git a/HP2100/hp2100_lpt.c b/HP2100/hp2100_lpt.c index 9644f596..3ab56965 100644 --- a/HP2100/hp2100_lpt.c +++ b/HP2100/hp2100_lpt.c @@ -25,6 +25,9 @@ lpt 12845A line printer + 03-Jun-04 RMS Fixed timing (found by Dave Bryan) + 26-Apr-04 RMS Fixed SFS x,C and SFC x,C + Implemented DMA SRQ (follows FLG) 25-Apr-03 RMS Revised for extended file support 24-Oct-02 RMS Cloned from 12653A */ @@ -43,8 +46,10 @@ #define LPT_CHANM 0000007 /* channel mask */ extern uint32 PC; -extern uint32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2]; -int32 lpt_ctime = 1000; /* char time */ +extern uint32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2], dev_srq[2]; + +int32 lpt_ctime = 4; /* char time */ +int32 lpt_ptime = 10000; /* print time */ int32 lpt_stopioe = 0; /* stop on error */ int32 lpt_lcnt = 0; /* line count */ static int32 lpt_cct[8] = { @@ -63,10 +68,10 @@ t_stat lpt_attach (UNIT *uptr, char *cptr); lpt_reg LPT register list */ -DIB lpt_dib = { LPT, 0, 0, 0, 0, &lptio }; +DIB lpt_dib = { LPT, 0, 0, 0, 0, 0, &lptio }; UNIT lpt_unit = { - UDATA (&lpt_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT }; + UDATA (&lpt_svc, UNIT_SEQ+UNIT_ATTABLE, 0) }; REG lpt_reg[] = { { ORDATA (BUF, lpt_unit.buf, 7) }, @@ -74,10 +79,11 @@ REG lpt_reg[] = { { FLDATA (CTL, lpt_dib.ctl, 0) }, { FLDATA (FLG, lpt_dib.flg, 0) }, { FLDATA (FBF, lpt_dib.fbf, 0) }, + { FLDATA (SRQ, lpt_dib.srq, 0) }, { DRDATA (LCNT, lpt_lcnt, 7) }, { DRDATA (POS, lpt_unit.pos, T_ADDR_W), PV_LEFT }, { DRDATA (CTIME, lpt_ctime, 31), PV_LEFT }, - { DRDATA (PTIME, lpt_unit.wait, 24), PV_LEFT }, + { DRDATA (PTIME, lpt_ptime, 24), PV_LEFT }, { FLDATA (STOP_IOE, lpt_stopioe, 0) }, { ORDATA (DEVNO, lpt_dib.devno, 6), REG_HRO }, { NULL } }; @@ -103,14 +109,14 @@ int32 dev; dev = IR & I_DEVMASK; /* get device no */ switch (inst) { /* case on opcode */ case ioFLG: /* flag clear/set */ - if ((IR & I_HC) == 0) { setFLG (dev); } /* STF */ + if ((IR & I_HC) == 0) { setFSR (dev); } /* STF */ break; case ioSFC: /* skip flag clear */ if (FLG (dev) == 0) PC = (PC + 1) & VAMASK; - return dat; + break; case ioSFS: /* skip flag set */ if (FLG (dev) != 0) PC = (PC + 1) & VAMASK; - return dat; + break; case ioOTX: /* output */ lpt_unit.buf = dat & (LPT_CTL | 0177); break; @@ -131,11 +137,11 @@ case ioCTL: /* control clear/set */ setCMD (dev); /* set ctl, cmd */ setCTL (dev); sim_activate (&lpt_unit, /* schedule op */ - (lpt_unit.buf & LPT_CTL)? lpt_unit.wait: lpt_ctime); } + (lpt_unit.buf & LPT_CTL)? lpt_ptime: lpt_ctime); } break; default: break; } -if (IR & I_HC) { clrFLG (dev); } /* H/C option */ +if (IR & I_HC) { clrFSR (dev); } /* H/C option */ return dat; } @@ -147,7 +153,7 @@ dev = lpt_dib.devno; /* get dev no */ clrCMD (dev); /* clear cmd */ if ((uptr->flags & UNIT_ATT) == 0) /* attached? */ return IORETURN (lpt_stopioe, SCPE_UNATT); -setFLG (dev); /* set flag, fbf */ +setFSR (dev); /* set flag, fbf */ if (uptr->buf & LPT_CTL) { /* control word? */ if (uptr->buf & LPT_CHAN) { chan = uptr->buf & LPT_CHANM; @@ -179,7 +185,7 @@ return SCPE_OK; t_stat lpt_reset (DEVICE *dptr) { lpt_dib.cmd = lpt_dib.ctl = 0; /* clear cmd, ctl */ -lpt_dib.flg = lpt_dib.fbf = 1; /* set flg, fbf */ +lpt_dib.flg = lpt_dib.fbf = lpt_dib.srq = 1; /* set flg, fbf, srq */ lpt_unit.buf = 0; sim_cancel (&lpt_unit); /* deactivate unit */ return SCPE_OK; diff --git a/HP2100/hp2100_ms.c b/HP2100/hp2100_ms.c index 825b4dd1..7c849896 100644 --- a/HP2100/hp2100_ms.c +++ b/HP2100/hp2100_ms.c @@ -26,6 +26,11 @@ ms 13181A 7970B 800bpi nine track magnetic tape 13183A 7970E 1600bpi nine track magnetic tape + 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 @@ -110,7 +115,7 @@ extern uint16 *M; extern uint32 PC, SR; -extern uint32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2]; +extern uint32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2], dev_srq[2]; extern int32 sim_switches; extern UNIT cpu_unit; @@ -148,8 +153,8 @@ t_stat ms_showtype (FILE *st, UNIT *uptr, int32 val, void *desc); */ DIB ms_dib[] = { - { MSD, 0, 0, 0, 0, &msdio }, - { MSC, 0, 0, 0, 0, &mscio } }; + { MSD, 0, 0, 0, 0, 0, &msdio }, + { MSC, 0, 0, 0, 0, 0, &mscio } }; #define msd_dib ms_dib[0] #define msc_dib ms_dib[1] @@ -162,6 +167,7 @@ REG msd_reg[] = { { FLDATA (CTL, msd_dib.ctl, 0) }, { FLDATA (FLG, msd_dib.flg, 0) }, { FLDATA (FBF, msd_dib.fbf, 0) }, + { FLDATA (SRQ, msd_dib.srq, 0) }, { BRDATA (DBUF, msxb, 8, 8, DBSIZE) }, { DRDATA (BPTR, ms_ptr, DB_N_SIZE + 1) }, { DRDATA (BMAX, ms_max, DB_N_SIZE + 1) }, @@ -203,6 +209,7 @@ REG msc_reg[] = { { FLDATA (CTL, msc_dib.ctl, 0) }, { FLDATA (FLG, msc_dib.flg, 0) }, { FLDATA (FBF, msc_dib.fbf, 0) }, + { FLDATA (SRQ, msc_dib.srq, 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) }, @@ -246,14 +253,14 @@ int32 devd; devd = IR & I_DEVMASK; /* get device no */ switch (inst) { /* case on opcode */ case ioFLG: /* flag clear/set */ - if ((IR & I_HC) == 0) { setFLG (devd); } /* STF */ + if ((IR & I_HC) == 0) { setFSR (devd); } /* STF */ break; case ioSFC: /* skip flag clear */ if (FLG (devd) == 0) PC = (PC + 1) & VAMASK; - return dat; + break; case ioSFS: /* skip flag set */ if (FLG (devd) != 0) PC = (PC + 1) & VAMASK; - return dat; + break; case ioOTX: /* output */ msd_buf = dat; /* store data */ break; @@ -271,9 +278,12 @@ case ioCTL: /* control clear/set */ setCTL (devd); /* set ctl, cmd */ setCMD (devd); } break; +case ioEDT: /* DMA end */ + clrFSR (devd); /* same as CLF */ + break; default: break; } -if (IR & I_HC) { clrFLG (devd); } /* H/C option */ +if (IR & I_HC) { clrFSR (devd); } /* H/C option */ return dat; } @@ -290,14 +300,14 @@ devc = IR & I_DEVMASK; /* get device no */ devd = devc - 1; switch (inst) { /* case on opcode */ case ioFLG: /* flag clear/set */ - if ((IR & I_HC) == 0) { setFLG (devc); } /* STF */ + if ((IR & I_HC) == 0) { setFSR (devc); } /* STF */ break; case ioSFC: /* skip flag clear */ if (FLG (devc) == 0) PC = (PC + 1) & VAMASK; - return dat; + break; case ioSFS: /* skip flag set */ if (FLG (devc) != 0) PC = (PC + 1) & VAMASK; - return dat; + break; case ioOTX: /* output */ msc_buf = dat; msc_sta = msc_sta & ~STA_REJ; /* clear reject */ @@ -338,9 +348,9 @@ case ioCTL: /* control clear/set */ if ((msc_unit[i].UST & STA_REW) == 0) sim_cancel (&msc_unit[i]); } /* stop if now rew */ clrCTL (devc); /* init device */ - setFLG (devc); + setFSR (devc); clrCTL (devd); - setFLG (devd); + setFSR (devd); msc_sta = msd_buf = msc_buf = msc_1st = 0; return SCPE_OK; } uptr->FNC = msc_buf & 0377; /* save function */ @@ -352,9 +362,12 @@ case ioCTL: /* control clear/set */ msc_1st = 1; setCTL (devc); } /* go */ break; +case ioEDT: /* DMA end */ + clrFSR (devc); /* same as CLF */ + break; default: break; } -if (IR & I_HC) { clrFLG (devc); } /* H/C option */ +if (IR & I_HC) { clrFSR (devc); } /* H/C option */ return dat; } @@ -377,7 +390,7 @@ devd = msd_dib.devno; if ((uptr->flags & UNIT_ATT) == 0) { /* offline? */ msc_sta = (msc_sta | STA_REJ) & ~STA_BUSY; /* reject */ - setFLG (devc); /* set cch flg */ + setFSR (devc); /* set cch flg */ return IORETURN (msc_stopioe, SCPE_UNATT); } switch (uptr->FNC) { /* case on function */ @@ -446,11 +459,11 @@ case FNC_RC: /* read */ return SCPE_OK; } break; } /* err, done */ } - if (ms_ptr < ms_max) { /* more chars? */ + if (CTL (devd) && (ms_ptr < ms_max)) { /* DCH on, more data? */ if (FLG (devd)) msc_sta = msc_sta | STA_TIM | STA_PAR; msd_buf = ((uint16) msxb[ms_ptr] << 8) | msxb[ms_ptr + 1]; ms_ptr = ms_ptr + 2; - setFLG (devd); /* set dch flg */ + setFSR (devd); /* set dch flg */ sim_activate (uptr, msc_xtime); /* re-activate */ return SCPE_OK; } sim_activate (uptr, msc_gtime); /* sched IRG */ @@ -468,7 +481,7 @@ case FNC_WC: /* write */ uptr->UST = 0; } else msc_sta = msc_sta | STA_PAR; } if (CTL (devd)) { /* xfer flop set? */ - setFLG (devd); /* set dch flag */ + setFSR (devd); /* set dch flag */ sim_activate (uptr, msc_xtime); /* re-activate */ return SCPE_OK; } if (ms_ptr) { /* any data? write */ @@ -482,7 +495,7 @@ case FNC_WC: /* write */ default: /* unknown */ break; } -setFLG (devc); /* set cch flg */ +setFSR (devc); /* set cch flg */ msc_sta = msc_sta & ~STA_BUSY; /* update status */ return SCPE_OK; } @@ -535,6 +548,7 @@ msc_dib.cmd = msd_dib.cmd = 0; /* clear cmd */ msc_dib.ctl = msd_dib.ctl = 0; /* clear ctl */ msc_dib.flg = msd_dib.flg = 1; /* set flg */ msc_dib.fbf = msd_dib.fbf = 1; /* set fbf */ +msc_dib.srq = msd_dib.srq = 1; /* srq follows flg */ for (i = 0; i < MS_NUMDR; i++) { uptr = msc_dev.units + i; sim_tape_reset (uptr); @@ -587,9 +601,7 @@ return SCPE_OK; /* 7970B/7970E bootstrap routine (HP 12992D ROM) */ -#define CHANGE_DEV (1 << 24) - -static const int32 mboot[IBL_LNT] = { +const uint16 ms_rom[IBL_LNT] = { 0106501, /*ST LIB 1 ; read sw */ 0006011, /* SLB,RSS ; bit 0 set? */ 0027714, /* JMP RD ; no read */ @@ -597,42 +609,42 @@ static const int32 mboot[IBL_LNT] = { 0073775, /* STA WC ; save */ 0067772, /* LDA SL0RW ; sel 0, rew */ 0017762, /*FF JSB CMD ; do cmd */ - 0102301+CHANGE_DEV, /* SFS CC ; done? */ + 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 */ - 0103700+CHANGE_DEV, /* STC DC,C ; start dch */ - 0102201+CHANGE_DEV, /* SFC CC ; read done? */ + 0103710, /* STC DC,C ; start dch */ + 0102211, /* SFC CC ; read done? */ 0027752, /* JMP STAT ; no, get stat */ - 0102300+CHANGE_DEV, /* SFS DC ; any data? */ + 0102310, /* SFS DC ; any data? */ 0027717, /* JMP *-3 ; wait */ - 0107500+CHANGE_DEV, /* LIB DC,C ; get rec cnt */ + 0107510, /* LIB DC,C ; get rec cnt */ 0005727, /* BLF,BLF ; move to lower */ 0007000, /* CMB ; make neg */ 0077775, /* STA WC ; save */ - 0102201+CHANGE_DEV, /* SFC CC ; read done? */ + 0102211, /* SFC CC ; read done? */ 0027752, /* JMP STAT ; no, get stat */ - 0102300+CHANGE_DEV, /* SFS DC ; any data? */ + 0102310, /* SFS DC ; any data? */ 0027727, /* JMP *-3 ; wait */ - 0107500+CHANGE_DEV, /* LIB DC,C ; get load addr */ + 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 */ - 0102300+CHANGE_DEV, /* SFS DC ; any data? */ + 0102310, /* SFS DC ; any data? */ 0027742, /* JMP *-1 ; wait */ - 0107500+CHANGE_DEV, /* LIB DC,C ; get word */ + 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 */ - 0102501+CHANGE_DEV, /*ST LIA CC ; get status */ + 0102511, /*ST LIA CC ; get status */ 0001727, /* ALF,ALF ; get eof bit */ 0002020, /* SSA ; set? */ 0102077, /* HLT 77 ; done */ @@ -641,12 +653,12 @@ static const int32 mboot[IBL_LNT] = { 0102000, /* HLT 0 ; no */ 0027714, /* JMP RD ; read next */ 0000000, /*CMD 0 */ - 0106601+CHANGE_DEV, /* OTB CC ; output cmd */ - 0102501+CHANGE_DEV, /* LIA CC ; check for reject */ + 0106611, /* OTB CC ; output cmd */ + 0102511, /* LIA CC ; check for reject */ 0001323, /* RAR,RAR */ 0001310, /* RAR,SLA */ 0027763, /* JMP CMD+1 ; try again */ - 0103701+CHANGE_DEV, /* STC CC,C ; start command */ + 0103711, /* STC CC,C ; start command */ 0127762, /* JMP CMD,I ; exit */ 0001501, /*SL0RW 001501 ; select 0, rewind */ 0001423, /*RDCMD 001423 ; read record */ @@ -657,16 +669,12 @@ static const int32 mboot[IBL_LNT] = { t_stat msc_boot (int32 unitno, DEVICE *dptr) { -int32 i, dev; +int32 dev; if (unitno != 0) return SCPE_NOFNC; /* only unit 0 */ dev = msd_dib.devno; /* get data chan dev */ -PC = ((MEMSIZE - 1) & ~IBL_MASK) & VAMASK; /* start at mem top */ -SR = IBL_MS + (dev << IBL_V_DEV); /* set SR */ +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? */ -for (i = 0; i < IBL_LNT; i++) { /* copy bootstrap */ - if (mboot[i] & CHANGE_DEV) /* IO instr? */ - M[PC + i] = (mboot[i] + dev) & DMASK; - else M[PC + i] = mboot[i]; } return SCPE_OK; } diff --git a/HP2100/hp2100_mt.c b/HP2100/hp2100_mt.c index dc9163ff..c89cdb64 100644 --- a/HP2100/hp2100_mt.c +++ b/HP2100/hp2100_mt.c @@ -25,6 +25,9 @@ mt 12559A 3030 nine track magnetic tape + 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 @@ -88,7 +91,8 @@ #define STA_BUSY 0001 /* busy (d) */ extern uint32 PC; -extern uint32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2]; +extern uint32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2], dev_srq[2]; + int32 mtc_fnc = 0; /* function */ int32 mtc_sta = 0; /* status register */ int32 mtc_dtf = 0; /* data xfer flop */ @@ -119,8 +123,8 @@ t_stat mt_map_err (UNIT *uptr, t_stat st); */ DIB mt_dib[] = { - { MTD, 0, 0, 0, 0, &mtdio }, - { MTC, 0, 0, 0, 0, &mtcio } }; + { MTD, 0, 0, 0, 0, 0, &mtdio }, + { MTC, 0, 0, 0, 0, 0, &mtcio } }; #define mtd_dib mt_dib[0] #define mtc_dib mt_dib[1] @@ -131,7 +135,8 @@ REG mtd_reg[] = { { FLDATA (CMD, mtd_dib.cmd, 0), REG_HRO }, { FLDATA (CTL, mtd_dib.ctl, 0), REG_HRO }, { FLDATA (FLG, mtd_dib.flg, 0) }, - { FLDATA (FBF, mtd_dib.fbf, 0), REG_HRO }, + { FLDATA (FBF, mtd_dib.fbf, 0) }, + { FLDATA (SRQ, mtd_dib.srq, 0) }, { BRDATA (DBUF, mtxb, 8, 8, DBSIZE) }, { DRDATA (BPTR, mt_ptr, DB_V_SIZE + 1) }, { DRDATA (BMAX, mt_max, DB_V_SIZE + 1) }, @@ -172,6 +177,7 @@ REG mtc_reg[] = { { FLDATA (CTL, mtc_dib.ctl, 0) }, { FLDATA (FLG, mtc_dib.flg, 0) }, { FLDATA (FBF, mtc_dib.fbf, 0) }, + { FLDATA (SRQ, mtc_dib.srq, 0) }, { FLDATA (DTF, mtc_dtf, 0) }, { FLDATA (FSVC, mtc_1st, 0) }, { DRDATA (POS, mtc_unit.pos, T_ADDR_W), PV_LEFT }, @@ -203,14 +209,14 @@ int32 devd; devd = IR & I_DEVMASK; /* get device no */ switch (inst) { /* case on opcode */ case ioFLG: /* flag clear/set */ - if ((IR & I_HC) == 0) { setFLG (devd); } /* STF */ + if ((IR & I_HC) == 0) { setFSR (devd); } /* STF */ break; case ioSFC: /* skip flag clear */ if (FLG (devd) == 0) PC = (PC + 1) & VAMASK; - return dat; + break; case ioSFS: /* skip flag set */ if (FLG (devd) != 0) PC = (PC + 1) & VAMASK; - return dat; + break; case ioOTX: /* output */ mtc_unit.buf = dat & 0377; /* store data */ break; @@ -225,7 +231,7 @@ case ioCTL: /* control clear/set */ break; default: break; } -if (IR & I_HC) { clrFLG (devd); } /* H/C option */ +if (IR & I_HC) { clrFSR (devd); } /* H/C option */ return dat; } @@ -238,14 +244,14 @@ devc = IR & I_DEVMASK; /* get device no */ devd = devc - 1; switch (inst) { /* case on opcode */ case ioFLG: /* flag clear/set */ - if ((IR & I_HC) == 0) { setFLG (devc); } /* STF */ + if ((IR & I_HC) == 0) { setFSR (devc); } /* STF */ break; case ioSFC: /* skip flag clear */ if (FLG (devc) == 0) PC = (PC + 1) & VAMASK; - return dat; + break; case ioSFS: /* skip flag set */ if (FLG (devc) != 0) PC = (PC + 1) & VAMASK; - return dat; + break; case ioOTX: /* output */ dat = dat & 0377; mtc_sta = mtc_sta & ~STA_REJ; /* clear reject */ @@ -259,9 +265,9 @@ case ioOTX: /* output */ mtc_1st = mtc_dtf = 0; mtc_sta = mtc_sta & STA_BOT; clrCTL (devc); /* init device */ - clrFLG (devc); + clrFSR (devc); clrCTL (devd); - clrFLG (devd); + clrFSR (devd); return SCPE_OK; } for (i = valid = 0; i < sizeof (mtc_cmd); i++) /* is fnc valid? */ if (dat == mtc_cmd[i]) valid = 1; @@ -275,8 +281,8 @@ case ioOTX: /* output */ mtc_fnc = dat; /* save function */ mtc_sta = STA_BUSY; /* unit busy */ mt_ptr = 0; /* init buffer ptr */ - clrFLG (devc); /* clear flags */ - clrFLG (devd); + clrFSR (devc); /* clear flags */ + clrFSR (devd); mtc_1st = 1; /* set 1st flop */ mtc_dtf = 1; } /* set xfer flop */ break; @@ -295,7 +301,7 @@ case ioCTL: /* control clear/set */ break; default: break; } -if (IR & I_HC) { clrFLG (devc); } /* H/C option */ +if (IR & I_HC) { clrFSR (devc); } /* H/C option */ return dat; } @@ -317,7 +323,7 @@ devc = mtc_dib.devno; /* get device nos */ devd = mtd_dib.devno; if ((mtc_unit.flags & UNIT_ATT) == 0) { /* offline? */ mtc_sta = STA_LOCAL | STA_REJ; /* rejected */ - setFLG (devc); /* set cch flg */ + setFSR (devc); /* set cch flg */ return IORETURN (mtc_stopioe, SCPE_UNATT); } switch (mtc_fnc) { /* case on function */ @@ -368,10 +374,10 @@ case FNC_RC: /* read */ mtc_sta = mtc_sta | STA_PAR; /* set flag */ break; } } - if (mt_ptr < mt_max) { /* more chars? */ + if (mtc_dtf && (mt_ptr < mt_max)) { /* more chars? */ if (FLG (devd)) mtc_sta = mtc_sta | STA_TIM; mtc_unit.buf = mtxb[mt_ptr++]; /* fetch next */ - setFLG (devd); /* set dch flg */ + setFSR (devd); /* set dch flg */ sim_activate (uptr, mtc_xtime); /* re-activate */ return SCPE_OK; } sim_activate (uptr, mtc_gtime); /* schedule gap */ @@ -386,7 +392,7 @@ case FNC_WC: /* write */ mtc_sta = mtc_sta & ~STA_BOT; } /* clear BOT */ else mtc_sta = mtc_sta | STA_PAR; } if (mtc_dtf) { /* xfer flop set? */ - setFLG (devd); /* set dch flag */ + setFSR (devd); /* set dch flag */ sim_activate (uptr, mtc_xtime); /* re-activate */ return SCPE_OK; } if (mt_ptr) { /* write buffer */ @@ -400,7 +406,7 @@ case FNC_WC: /* write */ default: /* unknown */ break; } -setFLG (devc); /* set cch flg */ +setFSR (devc); /* set cch flg */ mtc_sta = mtc_sta & ~STA_BUSY; /* not busy */ return SCPE_OK; } @@ -449,6 +455,7 @@ mtc_dib.cmd = mtd_dib.cmd = 0; /* clear cmd */ mtc_dib.ctl = mtd_dib.ctl = 0; /* clear ctl */ mtc_dib.flg = mtd_dib.flg = 0; /* clear flg */ mtc_dib.fbf = mtd_dib.fbf = 0; /* clear fbf */ +mtc_dib.srq = mtd_dib.srq = 0; /* srq follows flg */ sim_cancel (&mtc_unit); /* cancel activity */ sim_tape_reset (&mtc_unit); if (mtc_unit.flags & UNIT_ATT) mtc_sta = diff --git a/HP2100/hp2100_mux.c b/HP2100/hp2100_mux.c index 1c06839e..91d1fd67 100644 --- a/HP2100/hp2100_mux.c +++ b/HP2100/hp2100_mux.c @@ -25,6 +25,8 @@ mux,muxl,muxc 12920A terminal multiplexor + 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 @@ -133,7 +135,7 @@ << LIC_V_I) extern uint32 PC; -extern uint32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2]; +extern uint32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2], dev_srq[2]; uint16 mux_sta[MUX_LINES]; /* line status */ uint16 mux_rpar[MUX_LINES + MUX_ILINES]; /* rcv param */ @@ -191,8 +193,8 @@ static uint8 odd_par[256] = { #define RCV_PAR(x) (odd_par[(x) & 0377]? LIL_PAR: 0) DIB mux_dib[] = { - { MUXL, 0, 0, 0, 0, &muxlio }, - { MUXU, 0, 0, 0, 0, &muxuio } }; + { MUXL, 0, 0, 0, 0, 0, &muxlio }, + { MUXU, 0, 0, 0, 0, 0, &muxuio } }; #define muxl_dib mux_dib[0] #define muxu_dib mux_dib[1] @@ -214,6 +216,7 @@ REG muxu_reg[] = { { FLDATA (CTL, muxu_dib.ctl, 0), REG_HRO }, { FLDATA (FLG, muxu_dib.flg, 0), REG_HRO }, { FLDATA (FBF, muxu_dib.fbf, 0), REG_HRO }, + { FLDATA (SRQ, muxu_dib.srq, 0), REG_HRO }, { ORDATA (DEVNO, muxu_dib.devno, 6), REG_HRO }, { NULL } }; @@ -282,6 +285,7 @@ REG muxl_reg[] = { { FLDATA (CTL, muxl_dib.ctl, 0) }, { FLDATA (FLG, muxl_dib.flg, 0) }, { FLDATA (FBF, muxl_dib.fbf, 0) }, + { FLDATA (SRQ, muxl_dib.srq, 0) }, { BRDATA (STA, mux_sta, 8, 16, MUX_LINES) }, { BRDATA (RPAR, mux_rpar, 8, 16, MUX_LINES + MUX_ILINES) }, { BRDATA (XPAR, mux_xpar, 8, 16, MUX_LINES) }, @@ -309,7 +313,7 @@ DEVICE muxl_dev = { muxc_mod MUXM modifiers list */ -DIB muxc_dib = { MUXC, 0, 0, 0, 0, &muxcio }; +DIB muxc_dib = { MUXC, 0, 0, 0, 0, 0, &muxcio }; UNIT muxc_unit = { UDATA (NULL, 0, 0) }; @@ -318,6 +322,7 @@ REG muxc_reg[] = { { FLDATA (CTL, muxc_dib.ctl, 0) }, { FLDATA (FLG, muxc_dib.flg, 0) }, { FLDATA (FBF, muxc_dib.fbf, 0) }, + { FLDATA (SRQ, muxc_dib.srq, 0) }, { FLDATA (SCAN, muxc_scan, 0) }, { ORDATA (CHAN, muxc_chan, 4) }, { BRDATA (DSO, muxc_ota, 8, 6, MUX_LINES) }, @@ -346,14 +351,14 @@ int32 dev, ln; dev = IR & I_DEVMASK; /* get device no */ switch (inst) { /* case on opcode */ case ioFLG: /* flag clear/set */ - if ((IR & I_HC) == 0) { setFLG (dev); } /* STF */ + if ((IR & I_HC) == 0) { setFSR (dev); } /* STF */ break; case ioSFC: /* skip flag clear */ if (FLG (dev) == 0) PC = (PC + 1) & VAMASK; - return dat; + break; case ioSFS: /* skip flag set */ if (FLG (dev) != 0) PC = (PC + 1) & VAMASK; - return dat; + break; case ioOTX: /* output */ muxl_obuf = dat; /* store data */ break; @@ -385,7 +390,7 @@ case ioCTL: /* control clear/set */ default: break; } if (IR & I_HC) { /* H/C option */ - clrFLG (dev); /* clear flag */ + clrFSR (dev); /* clear flag */ mux_data_int (); } /* look for new int */ return dat; } @@ -416,14 +421,14 @@ int32 dev, ln, t, old; dev = IR & I_DEVMASK; /* get device no */ switch (inst) { /* case on opcode */ case ioFLG: /* flag clear/set */ - if ((IR & I_HC) == 0) { setFLG (dev); } /* STF */ + if ((IR & I_HC) == 0) { setFSR (dev); } /* STF */ break; case ioSFC: /* skip flag clear */ if (FLG (dev) == 0) PC = (PC + 1) & VAMASK; - return dat; + break; case ioSFS: /* skip flag set */ if (FLG (dev) != 0) PC = (PC + 1) & VAMASK; - return dat; + break; case ioOTX: /* output */ if (dat & OTC_SCAN) muxc_scan = 1; /* set scan flag */ else muxc_scan = 0; @@ -460,7 +465,7 @@ case ioCTL: /* ctrl clear/set */ default: break; } if (IR & I_HC) { /* H/C option */ - clrFLG (dev); /* clear flag */ + clrFSR (dev); /* clear flag */ mux_ctrl_int (); } /* look for new int */ return dat; } @@ -558,14 +563,14 @@ for (i = 0; i < MUX_LINES; i++) { /* rcv lines */ muxu_ibuf = PUT_CCH (i) | mux_sta[i]; /* hi buf = stat */ mux_rchp[i] = 0; /* clr char, stat */ mux_sta[i] = 0; - setFLG (muxl_dib.devno); /* interrupt */ + setFSR (muxl_dib.devno); /* interrupt */ return; } } for (i = 0; i < MUX_LINES; i++) { /* xmt lines */ if ((mux_xpar[i] & OTL_ENB) && mux_xdon[i]) { /* enabled, done? */ muxu_ibuf = PUT_CCH (i) | mux_sta[i] | LIU_TR; /* hi buf = stat */ mux_xdon[i] = 0; /* clr done, stat */ mux_sta[i] = 0; - setFLG (muxl_dib.devno); /* interrupt */ + setFSR (muxl_dib.devno); /* 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? */ @@ -574,7 +579,7 @@ for (i = MUX_LINES; i < (MUX_LINES + MUX_ILINES); i++) { /* diag lines */ muxu_ibuf = PUT_CCH (i) | mux_sta[i] | LIU_DG; /* hi buf = stat */ mux_rchp[i] = 0; /* clr char, stat */ mux_sta[i] = 0; - setFLG (muxl_dib.devno); + setFSR (muxl_dib.devno); return; } } return; } @@ -589,7 +594,7 @@ if (muxc_scan == 0) return; for (i = 0; i < MUX_LINES; i++) { muxc_chan = (muxc_chan + 1) & LIC_M_CHAN; /* step channel */ if (LIC_TSTI (muxc_chan)) { /* status change? */ - setFLG (muxc_dib.devno); /* set flag */ + setFSR (muxc_dib.devno); /* set flag */ break; } } return; } @@ -639,11 +644,11 @@ if (muxu_dev.flags & DEV_DIS) { /* enb/dis dev */ else { muxl_dev.flags = muxl_dev.flags & ~DEV_DIS; muxc_dev.flags = muxc_dev.flags & ~DEV_DIS; } muxl_dib.cmd = muxl_dib.ctl = 0; /* init lower */ -muxl_dib.flg = muxl_dib.fbf = 1; +muxl_dib.flg = muxl_dib.fbf = muxl_dib.srq = 1; muxu_dib.cmd = muxu_dib.ctl = 0; /* upper not */ -muxu_dib.flg = muxu_dib.fbf = 0; /* implemented */ +muxu_dib.flg = muxu_dib.fbf = muxu_dib.srq = 0; /* implemented */ muxc_dib.cmd = muxc_dib.ctl = 0; /* init ctrl */ -muxc_dib.flg = muxc_dib.fbf = 1; +muxc_dib.flg = muxc_dib.fbf = muxc_dib.srq = 1; muxc_chan = muxc_scan = 0; /* init modem scan */ if (muxu_unit.flags & UNIT_ATT) { /* master att? */ if (!sim_is_active (&muxu_unit)) { diff --git a/HP2100/hp2100_stddev.c b/HP2100/hp2100_stddev.c index ca8ff209..3578f87a 100644 --- a/HP2100/hp2100_stddev.c +++ b/HP2100/hp2100_stddev.c @@ -28,6 +28,11 @@ tty 12531C buffered teleprinter interface clk 12539C time base generator + 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 @@ -62,12 +67,15 @@ #include "hp2100_defs.h" #include + #define UNIT_V_8B (UNIT_V_UF + 0) /* 8B */ #define UNIT_V_UC (UNIT_V_UF + 1) /* UC only */ #define UNIT_V_DIAG (UNIT_V_UF + 2) /* diag mode */ +#define UNIT_V_AUTOLF (UNIT_V_UF + 3) /* auto linefeed */ #define UNIT_8B (1 << UNIT_V_8B) #define UNIT_UC (1 << UNIT_V_UC) #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 */ @@ -81,12 +89,18 @@ extern uint16 *M; extern uint32 PC, SR; -extern uint32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2]; +extern uint32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2], dev_srq[2]; extern UNIT cpu_unit; -int32 ptr_stopioe = 0, ptp_stopioe = 0; /* stop on error */ +int32 ptr_stopioe = 0; /* stop on error */ +int32 ptr_trlcnt = 0; /* trailer counter */ +int32 ptr_trllim = 40; /* trailer to add */ +int32 ptp_stopioe = 0; int32 ttp_stopioe = 0; -int32 tty_buf = 0, tty_mode = 0; /* tty buffer, mode */ +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 */ int32 clk_select = 0; /* clock time select */ int32 clk_error = 0; /* clock error */ int32 clk_ctr = 0; /* clock counter */ @@ -100,6 +114,7 @@ int32 clk_rpt[8] = /* number of repeats */ DEVICE ptr_dev, ptp_dev, tty_dev, clk_dev; int32 ptrio (int32 inst, int32 IR, int32 dat); 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); int32 ptpio (int32 inst, int32 IR, int32 dat); @@ -109,11 +124,13 @@ int32 ttyio (int32 inst, int32 IR, int32 dat); t_stat tti_svc (UNIT *uptr); t_stat tto_svc (UNIT *uptr); t_stat tty_reset (DEVICE *dptr); -t_stat tty_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat tty_set_opt (UNIT *uptr, int32 val, char *cptr, void *desc); int32 clkio (int32 inst, int32 IR, int32 dat); t_stat clk_svc (UNIT *uptr); t_stat clk_reset (DEVICE *dptr); int32 clk_delay (int32 flg); +t_stat tto_out (int32 c); +t_stat ttp_out (int32 c); /* PTR data structures @@ -123,7 +140,7 @@ int32 clk_delay (int32 flg); ptr_reg PTR register list */ -DIB ptr_dib = { PTR, 0, 0, 0, 0, &ptrio }; +DIB ptr_dib = { PTR, 0, 0, 0, 0, 0, &ptrio }; UNIT ptr_unit = { UDATA (&ptr_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE, 0), @@ -135,6 +152,9 @@ REG ptr_reg[] = { { FLDATA (CTL, ptr_dib.ctl, 0) }, { FLDATA (FLG, ptr_dib.flg, 0) }, { FLDATA (FBF, ptr_dib.fbf, 0) }, + { FLDATA (SRQ, ptr_dib.srq, 0) }, + { DRDATA (TRLCTR, ptr_trlcnt, 8), REG_HRO }, + { DRDATA (TRLLIM, ptr_trllim, 8) }, { DRDATA (POS, ptr_unit.pos, T_ADDR_W), PV_LEFT }, { DRDATA (TIME, ptr_unit.wait, 24), PV_LEFT }, { FLDATA (STOP_IOE, ptr_stopioe, 0) }, @@ -150,7 +170,7 @@ DEVICE ptr_dev = { "PTR", &ptr_unit, ptr_reg, ptr_mod, 1, 10, 31, 1, 8, 8, NULL, NULL, &ptr_reset, - &ptr_boot, NULL, NULL, + &ptr_boot, &ptr_attach, NULL, &ptr_dib, DEV_DISABLE }; /* PTP data structures @@ -161,7 +181,7 @@ DEVICE ptr_dev = { ptp_reg PTP register list */ -DIB ptp_dib = { PTP, 0, 0, 0, 0, &ptpio }; +DIB ptp_dib = { PTP, 0, 0, 0, 0, 0, &ptpio }; UNIT ptp_unit = { UDATA (&ptp_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT }; @@ -172,6 +192,7 @@ REG ptp_reg[] = { { FLDATA (CTL, ptp_dib.ctl, 0) }, { FLDATA (FLG, ptp_dib.flg, 0) }, { FLDATA (FBF, ptp_dib.fbf, 0) }, + { FLDATA (SRQ, ptp_dib.srq, 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) }, @@ -202,7 +223,7 @@ DEVICE ptp_dev = { #define TTO 1 #define TTP 2 -DIB tty_dib = { TTY, 0, 0, 0, 0, &ttyio }; +DIB tty_dib = { TTY, 0, 0, 0, 0, 0, &ttyio }; UNIT tty_unit[] = { { UDATA (&tti_svc, UNIT_UC, 0), KBD_POLL_WAIT }, @@ -212,10 +233,13 @@ UNIT tty_unit[] = { REG tty_reg[] = { { ORDATA (BUF, tty_buf, 8) }, { ORDATA (MODE, tty_mode, 16) }, + { ORDATA (SHIN, tty_shin, 8), REG_HRO }, { FLDATA (CMD, tty_dib.cmd, 0), REG_HRO }, { FLDATA (CTL, tty_dib.ctl, 0) }, { FLDATA (FLG, tty_dib.flg, 0) }, { FLDATA (FBF, tty_dib.fbf, 0) }, + { FLDATA (SRQ, tty_dib.srq, 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 }, @@ -226,9 +250,16 @@ REG tty_reg[] = { { NULL } }; MTAB tty_mod[] = { - { UNIT_UC+UNIT_8B, UNIT_UC, "UC", "UC", &tty_set_mode }, - { UNIT_UC+UNIT_8B, 0 , "7b", "7B", &tty_set_mode }, - { UNIT_UC+UNIT_8B, UNIT_8B, "8b", "8B", &tty_set_mode }, + { UNIT_UC+UNIT_8B, UNIT_UC, "UC", "UC", &tty_set_opt, + NULL, ((void *) (UNIT_UC + UNIT_8B)) }, + { UNIT_UC+UNIT_8B, 0 , "7b", "7B", &tty_set_opt, + NULL, ((void *) (UNIT_UC + UNIT_8B)) }, + { UNIT_UC+UNIT_8B, UNIT_8B, "8b", "8B", &tty_set_opt, + NULL, ((void *) (UNIT_UC + UNIT_8B)) }, + { UNIT_AUTOLF, UNIT_AUTOLF, "autolf", "AUTOLF", &tty_set_opt, + NULL, ((void *) UNIT_AUTOLF) }, + { UNIT_AUTOLF, 0 , NULL, "NOAUTOLF", &tty_set_opt, + NULL, ((void *) UNIT_AUTOLF) }, { MTAB_XTD | MTAB_VDV, 0, "DEVNO", "DEVNO", &hp_setdev, &hp_showdev, &tty_dev }, { 0 } }; @@ -248,7 +279,7 @@ DEVICE tty_dev = { clk_reg CLK register list */ -DIB clk_dib = { CLK, 0, 0, 0, 0, &clkio }; +DIB clk_dib = { CLK, 0, 0, 0, 0, 0, &clkio }; UNIT clk_unit = { UDATA (&clk_svc, 0, 0) }; @@ -260,6 +291,7 @@ REG clk_reg[] = { { FLDATA (CTL, clk_dib.ctl, 0) }, { FLDATA (FLG, clk_dib.flg, 0) }, { FLDATA (FBF, clk_dib.fbf, 0) }, + { FLDATA (SRQ, clk_dib.srq, 0) }, { FLDATA (ERR, clk_error, CLK_V_ERROR) }, { BRDATA (TIME, clk_time, 10, 24, 8) }, { ORDATA (DEVNO, clk_dib.devno, 6), REG_HRO }, @@ -288,14 +320,14 @@ int32 dev; dev = IR & I_DEVMASK; /* get device no */ switch (inst) { /* case on opcode */ case ioFLG: /* flag clear/set */ - if ((IR & I_HC) == 0) { setFLG (dev); } /* STF */ + if ((IR & I_HC) == 0) { setFSR (dev); } /* STF */ break; case ioSFC: /* skip flag clear */ if (FLG (dev) == 0) PC = (PC + 1) & VAMASK; - return dat; + break; case ioSFS: /* skip flag set */ if (FLG (dev) != 0) PC = (PC + 1) & VAMASK; - return dat; + break; case ioMIX: /* merge */ dat = dat | ptr_unit.buf; break; @@ -313,7 +345,7 @@ case ioCTL: /* control clear/set */ break; default: break; } -if (IR & I_HC) { clrFLG (dev); } /* H/C option */ +if (IR & I_HC) { clrFSR (dev); } /* H/C option */ return dat; } @@ -327,25 +359,40 @@ dev = ptr_dib.devno; /* get device no */ clrCMD (dev); /* clear cmd */ if ((ptr_unit.flags & UNIT_ATT) == 0) /* attached? */ return IORETURN (ptr_stopioe, SCPE_UNATT); -if ((temp = getc (ptr_unit.fileref)) == EOF) { /* read byte */ - if (feof (ptr_unit.fileref)) { - if (ptr_stopioe) printf ("PTR end of file\n"); - else return SCPE_OK; } - else perror ("PTR I/O error"); - clearerr (ptr_unit.fileref); - return SCPE_IOERR; } -setFLG (dev); /* set flag */ +if ((temp = getc (ptr_unit.fileref)) == EOF) { /* read byte, error? */ + if (feof (ptr_unit.fileref)) { /* end of file? */ + 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 */ + else { /* no, real error */ + perror ("PTR I/O error"); + clearerr (ptr_unit.fileref); + return SCPE_IOERR; } + } +setFSR (dev); /* set flag */ ptr_unit.buf = temp & 0377; /* put byte in buf */ ptr_unit.pos = ftell (ptr_unit.fileref); 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, flags in DIB's */ t_stat ptr_reset (DEVICE *dptr) { ptr_dib.cmd = ptr_dib.ctl = 0; /* clear cmd, ctl */ -ptr_dib.flg = ptr_dib.fbf = 1; /* set flg, fbf */ +ptr_dib.flg = ptr_dib.fbf = ptr_dib.srq = 1; /* set flg, fbf, srq */ ptr_unit.buf = 0; sim_cancel (&ptr_unit); /* deactivate unit */ return SCPE_OK; @@ -353,10 +400,7 @@ return SCPE_OK; /* Paper tape reader bootstrap routine (HP 12992K ROM) */ -#define LDR_BASE 077 -#define CHANGE_DEV (1 << 24) - -static const int32 pboot[IBL_LNT] = { +const uint16 ptr_rom[IBL_LNT] = { 0107700, /*ST CLC 0,C ; intr off */ 0002401, /* CLA,RSS ; skip in */ 0063756, /*CN LDA M11 ; feed frame */ @@ -393,10 +437,10 @@ static const int32 pboot[IBL_LNT] = { 0027700, /* JMP ST ; next */ 0000000, /*RD 0 */ 0006600, /* CLB,CME ; E reg byte ptr */ - 0103700+CHANGE_DEV, /* STC RDR,C ; start reader */ - 0102300+CHANGE_DEV, /* SFS RDR ; wait */ + 0103710, /* STC RDR,C ; start reader */ + 0102310, /* SFS RDR ; wait */ 0027745, /* JMP *-1 */ - 0106400+CHANGE_DEV, /* MIB RDR ; get byte */ + 0106410, /* MIB RDR ; get byte */ 0002041, /* SEZ,RSS ; E set? */ 0127742, /* JMP RD,I ; no, done */ 0005767, /* BLF,CLE,BLF ; shift byte */ @@ -410,16 +454,11 @@ static const int32 pboot[IBL_LNT] = { t_stat ptr_boot (int32 unitno, DEVICE *dptr) { -int32 i, dev; +int32 dev; dev = ptr_dib.devno; /* get device no */ -PC = ((MEMSIZE - 1) & ~IBL_MASK) & VAMASK; /* start at mem top */ -SR = IBL_PTR + (dev << IBL_V_DEV); /* set SR */ -for (i = 0; i < IBL_LNT; i++) { /* copy bootstrap */ - if (pboot[i] & CHANGE_DEV) /* IO instr? */ - M[PC + i] = (pboot[i] + dev) & DMASK; - else M[PC + i] = pboot[i]; } -M[PC + LDR_BASE] = (~PC + 1) & DMASK; +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; } @@ -432,14 +471,14 @@ int32 dev; dev = IR & I_DEVMASK; /* get device no */ switch (inst) { /* case on opcode */ case ioFLG: /* flag clear/set */ - if ((IR & I_HC) == 0) { setFLG (dev); } /* STF */ + if ((IR & I_HC) == 0) { setFSR (dev); } /* STF */ break; case ioSFC: /* skip flag clear */ if (FLG (dev) == 0) PC = (PC + 1) & VAMASK; - return dat; + break; case ioSFS: /* skip flag set */ if (FLG (dev) != 0) PC = (PC + 1) & VAMASK; - return dat; + break; case ioLIX: /* load */ dat = 0; case ioMIX: /* merge */ @@ -460,7 +499,7 @@ case ioCTL: /* control clear/set */ break; default: break; } -if (IR & I_HC) { clrFLG (dev); } /* H/C option */ +if (IR & I_HC) { clrFSR (dev); } /* H/C option */ return dat; } @@ -472,7 +511,7 @@ int32 dev; dev = ptp_dib.devno; /* get device no */ clrCMD (dev); /* clear cmd */ -setFLG (dev); /* set flag */ +setFSR (dev); /* set flag */ if ((ptp_unit.flags & UNIT_ATT) == 0) /* attached? */ return IORETURN (ptp_stopioe, SCPE_UNATT); if (putc (ptp_unit.buf, ptp_unit.fileref) == EOF) { /* output byte */ @@ -488,7 +527,7 @@ return SCPE_OK; t_stat ptp_reset (DEVICE *dptr) { ptp_dib.cmd = ptp_dib.ctl = 0; /* clear cmd, ctl */ -ptp_dib.flg = ptp_dib.fbf = 1; /* set flg, fbf */ +ptp_dib.flg = ptp_dib.fbf = ptp_dib.srq = 1; /* set flg, fbf, srq */ ptp_unit.buf = 0; sim_cancel (&ptp_unit); /* deactivate unit */ return SCPE_OK; @@ -503,14 +542,14 @@ int32 dev; dev = IR & I_DEVMASK; /* get device no */ switch (inst) { /* case on opcode */ case ioFLG: /* flag clear/set */ - if ((IR & I_HC) == 0) { setFLG (dev); } /* STF */ + if ((IR & I_HC) == 0) { setFSR (dev); } /* STF */ break; case ioSFC: /* skip flag clear */ if (FLG (dev) == 0) PC = (PC + 1) & VAMASK; - return dat; + break; case ioSFS: /* skip flag set */ if (FLG (dev) != 0) PC = (PC + 1) & VAMASK; - return dat; + break; case ioLIX: /* load */ dat = 0; case ioMIX: /* merge */ @@ -531,11 +570,79 @@ case ioCTL: /* control clear/set */ break; default: break; } -if (IR & I_HC) { clrFLG (dev); } /* H/C option */ +if (IR & I_HC) { clrFSR (dev); } /* H/C option */ return dat; } -/* Unit service routines */ +/* Unit service routines. Note from Dave Bryan: + + 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 RTE to output the asterisk and initiate a + terminal read when the current output line is completed. */ + +t_stat tti_svc (UNIT *uptr) +{ +int32 c, dev; + +dev = tty_dib.devno; /* get device no */ +sim_activate (&tty_unit[TTI], tty_unit[TTI].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 if (tty_unit[TTI].flags & UNIT_UC) { /* UC only? */ + c = c & 0177; + if (islower (c)) c = toupper (c); } + else c = c & ((tty_unit[TTI].flags & UNIT_8B)? 0377: 0177); + tty_lf = ((c & 0177) == 015) && (uptr->flags & UNIT_AUTOLF); + } +if (tty_mode & TM_KBD) { /* keyboard enabled? */ + tty_buf = c; /* put char in buf */ + tty_unit[TTI].pos = tty_unit[TTI].pos + 1; + setFSR (dev); /* set flag */ + if (c) { + tto_out (c); /* echo? */ + return ttp_out (c); } } /* punch? */ +else tty_shin = c; /* no, char shifts in */ +return SCPE_OK; +} + +t_stat tto_svc (UNIT *uptr) +{ +int32 c, dev; +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 */ +dev = tty_dib.devno; /* get device no */ +setFSR (dev); /* set done flag */ +return ttp_out (c); /* punch if enabled */ +} t_stat tto_out (int32 c) { @@ -546,8 +653,10 @@ if (tty_mode & TM_PRI) { /* printing? */ c = c & 0177; if (islower (c)) c = toupper (c); } else c = c & ((tty_unit[TTO].flags & UNIT_8B)? 0377: 0177); - if (r = sim_putchar_s (c)) return r; /* output char */ - tty_unit[TTO].pos = tty_unit[TTO].pos + 1; } + if (c || (tty_unit[TTO].flags & UNIT_8B)) { /* !null or 8b? */ + if (r = sim_putchar_s (c)) return r; /* output char */ + tty_unit[TTO].pos = tty_unit[TTO].pos + 1; } + } return SCPE_OK; } @@ -564,63 +673,29 @@ if (tty_mode & TM_PUN) { /* punching? */ return SCPE_OK; } -t_stat tti_svc (UNIT *uptr) -{ -int32 c, dev; - -dev = tty_dib.devno; /* get device no */ -sim_activate (&tty_unit[TTI], tty_unit[TTI].wait); /* continue poll */ -if ((c = sim_poll_kbd ()) < SCPE_KFLAG) return c; /* no char or error? */ -if (c & SCPE_BREAK) c = 0; /* break? */ -else if (tty_unit[TTI].flags & UNIT_UC) { /* UC only? */ - c = c & 0177; - if (islower (c)) c = toupper (c); } -else c = c & ((tty_unit[TTI].flags & UNIT_8B)? 0377: 0177); -if (tty_mode & TM_KBD) { /* keyboard enabled? */ - tty_buf = c; /* put char in buf */ - tty_unit[TTI].pos = tty_unit[TTI].pos + 1; - setFLG (dev); /* set flag */ - if (c) { - tto_out (c); /* echo? */ - return ttp_out (c); } } /* punch? */ -return SCPE_OK; -} - -t_stat tto_svc (UNIT *uptr) -{ -int32 c, dev; -t_stat r; - -c = tty_buf; /* get char */ -tty_buf = 0377; /* defang buf */ -if ((r = tto_out (c)) != SCPE_OK) { /* output; error? */ - sim_activate (uptr, uptr->wait); /* retry */ - return ((r == SCPE_STALL)? SCPE_OK: r); } /* !stall? report */ -dev = tty_dib.devno; /* get device no */ -setFLG (dev); /* set done flag */ -return ttp_out (c); /* punch if enabled */ -} - /* Reset routine */ t_stat tty_reset (DEVICE *dptr) { tty_dib.cmd = tty_dib.ctl = 0; /* clear cmd, ctl */ -tty_dib.flg = tty_dib.fbf = 1; /* set flg, fbf */ +tty_dib.flg = tty_dib.fbf = tty_dib.srq = 1; /* set flg, fbf, srq */ tty_mode = TM_KBD; /* enable input */ tty_buf = 0; +tty_shin = 0377; /* input inactive */ +tty_lf = 0; /* no lf pending */ 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_mode (UNIT *uptr, int32 val, char *cptr, void *desc) +t_stat tty_set_opt (UNIT *uptr, int32 val, char *cptr, void *desc) { int32 u = uptr - tty_dev.units; +int32 mask = (int32) desc; if (u > 1) return SCPE_NOFNC; -tty_unit[TTI].flags = (tty_unit[TTI].flags & ~(UNIT_UC | UNIT_8B)) | val; -tty_unit[TTO].flags = (tty_unit[TTO].flags & ~(UNIT_UC | UNIT_8B)) | val; +tty_unit[TTI].flags = (tty_unit[TTI].flags & ~mask) | val; +tty_unit[TTO].flags = (tty_unit[TTO].flags & ~mask) | val; return SCPE_OK; } @@ -633,14 +708,14 @@ int32 dev; dev = IR & I_DEVMASK; /* get device no */ switch (inst) { /* case on opcode */ case ioFLG: /* flag clear/set */ - if ((IR & I_HC) == 0) { setFLG (dev); } /* STF */ + if ((IR & I_HC) == 0) { setFSR (dev); } /* STF */ break; case ioSFC: /* skip flag clear */ if (FLG (dev) == 0) PC = (PC + 1) & VAMASK; - return dat; + break; case ioSFS: /* skip flag set */ if (FLG (dev) != 0) PC = (PC + 1) & VAMASK; - return dat; + break; case ioMIX: /* merge */ dat = dat | clk_error; break; @@ -666,7 +741,7 @@ case ioCTL: /* control clear/set */ break; default: break; } -if (IR & I_HC) { clrFLG (dev); } /* H/C option */ +if (IR & I_HC) { clrFSR (dev); } /* H/C option */ return dat; } @@ -686,7 +761,7 @@ clk_ctr = clk_ctr - 1; /* decrement counter */ if (clk_ctr <= 0) { /* end of interval? */ tim = FLG (dev); if (FLG (dev)) clk_error = CLK_ERROR; /* overrun? error */ - else { setFLG (dev); } /* else set flag */ + else { setFSR (dev); } /* else set flag */ clk_ctr = clk_delay (1); } /* reset counter */ return SCPE_OK; } @@ -696,7 +771,7 @@ return SCPE_OK; t_stat clk_reset (DEVICE *dptr) { clk_dib.cmd = clk_dib.ctl = 0; /* clear cmd, ctl */ -clk_dib.flg = clk_dib.fbf = 1; /* set flg, fbf */ +clk_dib.flg = clk_dib.fbf = clk_dib.srq = 1; /* set flg, fbf, srq */ clk_error = 0; /* clear error */ clk_select = 0; /* clear select */ clk_ctr = 0; /* clear counter */ diff --git a/HP2100/hp2100_sys.c b/HP2100/hp2100_sys.c index d820eacf..6e0dea5f 100644 --- a/HP2100/hp2100_sys.c +++ b/HP2100/hp2100_sys.c @@ -23,6 +23,8 @@ 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-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 @@ -50,6 +52,7 @@ 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 REG cpu_reg[]; @@ -67,6 +70,8 @@ extern uint16 *M; char sim_name[] = "HP 2100"; +char halt_msg[] = "HALT instruction xxxxxx"; + REG *sim_PC = &cpu_reg[0]; int32 sim_emax = 3; @@ -84,6 +89,7 @@ DEVICE *sim_devices[] = { &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, @@ -94,7 +100,7 @@ const char *sim_stop_messages[] = { "Unknown error", "Unimplemented instruction", "Non-existent I/O device", - "HALT instruction", + halt_msg, "Breakpoint", "Indirect address loop", "Indirect address interrupt (should not happen!)", @@ -231,7 +237,7 @@ static const int32 opc_val[] = { 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_IO2, 0102300+I_IO2, 0102400+I_IO1, 0106400+I_IO1, + 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, diff --git a/Ibm1130/ibm1130.mak b/Ibm1130/ibm1130.mak index fc839dbb..5a0b2c1f 100644 --- a/Ibm1130/ibm1130.mak +++ b/Ibm1130/ibm1130.mak @@ -70,10 +70,12 @@ BSC32_SBRS= \ $(INTDIR)/ibm1130_gui.sbr \ $(INTDIR)/ibm1130_prt.sbr \ $(INTDIR)/scp.sbr \ - $(INTDIR)/scp_tty.sbr \ $(INTDIR)/sim_tmxr.sbr \ $(INTDIR)/sim_sock.sbr \ - $(INTDIR)/ibm1130_fmt.sbr + $(INTDIR)/ibm1130_fmt.sbr \ + $(INTDIR)/sim_console.sbr \ + $(INTDIR)/sim_fio.sbr \ + $(INTDIR)/sim_timer.sbr $(OUTDIR)/ibm1130.bsc : $(OUTDIR) $(BSC32_SBRS) $(BSC32) @<< @@ -98,10 +100,12 @@ LINK32_OBJS= \ $(INTDIR)/ibm1130_gui.obj \ $(INTDIR)/ibm1130_prt.obj \ $(INTDIR)/scp.obj \ - $(INTDIR)/scp_tty.obj \ $(INTDIR)/sim_tmxr.obj \ $(INTDIR)/sim_sock.obj \ - $(INTDIR)/ibm1130_fmt.obj + $(INTDIR)/ibm1130_fmt.obj \ + $(INTDIR)/sim_console.obj \ + $(INTDIR)/sim_fio.obj \ + $(INTDIR)/sim_timer.obj $(OUTDIR)/ibm1130.exe : $(OUTDIR) $(DEF_FILE) $(LINK32_OBJS) $(LINK32) @<< @@ -149,10 +153,12 @@ BSC32_SBRS= \ $(INTDIR)/ibm1130_gui.sbr \ $(INTDIR)/ibm1130_prt.sbr \ $(INTDIR)/scp.sbr \ - $(INTDIR)/scp_tty.sbr \ $(INTDIR)/sim_tmxr.sbr \ $(INTDIR)/sim_sock.sbr \ - $(INTDIR)/ibm1130_fmt.sbr + $(INTDIR)/ibm1130_fmt.sbr \ + $(INTDIR)/sim_console.sbr \ + $(INTDIR)/sim_fio.sbr \ + $(INTDIR)/sim_timer.sbr $(OUTDIR)/ibm1130.bsc : $(OUTDIR) $(BSC32_SBRS) $(BSC32) @<< @@ -178,10 +184,12 @@ LINK32_OBJS= \ $(INTDIR)/ibm1130_gui.obj \ $(INTDIR)/ibm1130_prt.obj \ $(INTDIR)/scp.obj \ - $(INTDIR)/scp_tty.obj \ $(INTDIR)/sim_tmxr.obj \ $(INTDIR)/sim_sock.obj \ - $(INTDIR)/ibm1130_fmt.obj + $(INTDIR)/ibm1130_fmt.obj \ + $(INTDIR)/sim_console.obj \ + $(INTDIR)/sim_fio.obj \ + $(INTDIR)/sim_timer.obj $(OUTDIR)/ibm1130.exe : $(OUTDIR) $(DEF_FILE) $(LINK32_OBJS) $(LINK32) @<< @@ -325,17 +333,6 @@ $(INTDIR)/scp.obj : $(SOURCE) $(DEP_SCP_C) $(INTDIR) ################################################################################ # Begin Source File -SOURCE=..\scp_tty.c -DEP_SCP_T=\ - ..\sim_defs.h - -$(INTDIR)/scp_tty.obj : $(SOURCE) $(DEP_SCP_T) $(INTDIR) - $(CPP) $(CPP_PROJ) $(SOURCE) - -# End Source File -################################################################################ -# Begin Source File - SOURCE=\pdp11\supnik\sim_tmxr.c DEP_SIM_T=\ ..\sim_defs.h\ @@ -367,6 +364,59 @@ SOURCE=.\ibm1130_fmt.c $(INTDIR)/ibm1130_fmt.obj : $(SOURCE) $(INTDIR) +# End Source File +################################################################################ +# Begin Source File + +SOURCE=\pdp11\supnik\sim_console.c +DEP_SIM_C=\ + ..\sim_defs.h\ + \pdp11\supnik\sim_sock.h\ + \pdp11\supnik\sim_tmxr.h\ + \pdp11\supnik\scp.h\ + \pdp11\supnik\sim_console.h\ + \pdp11\supnik\sim_timer.h\ + \pdp11\supnik\sim_fio.h\ + d:\progra~1\micros~1\include\winsock2.h\ + \MSVC20\INCLUDE\sys\TYPES.H\ + d:\progra~1\micros~1\include\qos.h\ + d:\winddk\2600\inc\wxp\guiddef.h + +$(INTDIR)/sim_console.obj : $(SOURCE) $(DEP_SIM_C) $(INTDIR) + $(CPP) $(CPP_PROJ) $(SOURCE) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=\pdp11\supnik\sim_fio.c +DEP_SIM_F=\ + ..\sim_defs.h\ + d:\progra~1\micros~1\include\BASETSD.H\ + \pdp11\supnik\scp.h\ + \pdp11\supnik\sim_console.h\ + \pdp11\supnik\sim_timer.h\ + \pdp11\supnik\sim_fio.h + +$(INTDIR)/sim_fio.obj : $(SOURCE) $(DEP_SIM_F) $(INTDIR) + $(CPP) $(CPP_PROJ) $(SOURCE) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=\pdp11\supnik\sim_timer.c +DEP_SIM_TI=\ + ..\sim_defs.h\ + d:\progra~1\micros~1\include\BASETSD.H\ + \pdp11\supnik\scp.h\ + \pdp11\supnik\sim_console.h\ + \pdp11\supnik\sim_timer.h\ + \pdp11\supnik\sim_fio.h + +$(INTDIR)/sim_timer.obj : $(SOURCE) $(DEP_SIM_TI) $(INTDIR) + $(CPP) $(CPP_PROJ) $(SOURCE) + # End Source File # End Group # End Project diff --git a/Ibm1130/ibm1130.rc b/Ibm1130/ibm1130.rc index 83e141c9..47a56a67 100644 --- a/Ibm1130/ibm1130.rc +++ b/Ibm1130/ibm1130.rc @@ -19,7 +19,7 @@ // TEXTINCLUDE // -1 TEXTINCLUDE DISCARDABLE +1 TEXTINCLUDE DISCARDABLE BEGIN "ibm1130res.h\0" END @@ -45,21 +45,20 @@ END // Bitmap // -IDB_CONSOLE BITMAP "1130consoleblank.bmp" -FULL_1442 BITMAP "1442full.bmp" -EOF_1442 BITMAP "1442eof.bmp" -EMPTY_1442 BITMAP "1442empty.bmp" -MIDDLE_1442 BITMAP "1442middle.bmp" -FULL_1132 BITMAP "1132full.bmp" -EMPTY_1132 BITMAP "1132empty.bmp" - +IDB_CONSOLE BITMAP MOVEABLE PURE "1130consoleblank.bmp" +FULL_1442 BITMAP MOVEABLE PURE "1442full.bmp" +EOF_1442 BITMAP MOVEABLE PURE "1442eof.bmp" +EMPTY_1442 BITMAP MOVEABLE PURE "1442empty.bmp" +MIDDLE_1442 BITMAP MOVEABLE PURE "1442middle.bmp" +FULL_1132 BITMAP MOVEABLE PURE "1132full.bmp" +EMPTY_1132 BITMAP MOVEABLE PURE "1132empty.bmp" ///////////////////////////////////////////////////////////////////////////// // // Cursor // -IDC_HAND CURSOR "HAND.CUR" +IDC_MYHAND CURSOR DISCARDABLE "HAND.CUR" #ifndef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// diff --git a/Ibm1130/ibm1130_cr.c b/Ibm1130/ibm1130_cr.c index ad90ebb6..11ff01c8 100644 --- a/Ibm1130/ibm1130_cr.c +++ b/Ibm1130/ibm1130_cr.c @@ -18,6 +18,9 @@ * This is not a supported product, but I welcome bug reports and fixes. * Mail to simh@ibm1130.org + * Update 2004-04-12: Changed ascii field of CPCODE to unsigned char, caught a couple + other potential problems with signed characters used as subscript indexes. + * Update 2003-11-25: Physical card reader support working, may not be perfect. Changed magic filename for stdin to "(stdin)". @@ -454,7 +457,7 @@ DEVICE cp_dev = { typedef struct { uint16 hollerith; - char ascii; + unsigned char ascii; } CPCODE; static CPCODE cardcode_029[] = @@ -505,7 +508,7 @@ static CPCODE cardcode_029[] = 0x0120, '\'', 0x00A0, '=', 0x0060, '"', - 0x8820, '\xA2', // cent, in MS-DOS encoding (this is in guess_cr_code as well) + 0x8820, (unsigned char) '\xA2', // cent, in MS-DOS encoding (this is in guess_cr_code as well) 0x8420, '.', 0x8220, '<', // ) in 026 Fortran 0x8120, '(', @@ -516,7 +519,7 @@ static CPCODE cardcode_029[] = 0x4220, '*', 0x4120, ')', 0x40A0, ';', - 0x4060, '\xAC', // not, in MS-DOS encoding (this is in guess_cr_code as well) + 0x4060, (unsigned char) '\xAC', // not, in MS-DOS encoding (this is in guess_cr_code as well) 0x2420, ',', 0x2220, '%', // ( in 026 Fortran 0x2120, '_', @@ -947,7 +950,7 @@ char card_to_ascii (uint16 hol) for (i = 0; i < ncardcode; i++) if (cardcode[i].hollerith == hol) - return cardcode[i].ascii; + return (char) cardcode[i].ascii; return '?'; } @@ -960,7 +963,7 @@ char hollerith_to_ascii (uint16 hol) for (i = 0; i < ncardcode; i++) if (cardcode_029[i].hollerith == hol) - return cardcode[i].ascii; + return (char) cardcode[i].ascii; return ' '; } @@ -1074,7 +1077,7 @@ again: /* jump here if we've loaded a new deck after emptying the previous one result = buf; for (i = 0; i < nread; i++) /* convert ascii to punch code */ - readstation[i] = ascii_to_card[result[i]]; + readstation[i] = ascii_to_card[(unsigned char) result[i]]; nread = 80; /* even if line was blank consider it present */ } diff --git a/Ibm1130/ibm1130_defs.h b/Ibm1130/ibm1130_defs.h index 20a8f247..ef2a7a5b 100644 --- a/Ibm1130/ibm1130_defs.h +++ b/Ibm1130/ibm1130_defs.h @@ -13,6 +13,8 @@ */ #include "sim_defs.h" /* main SIMH defns (include path should include .., or make a copy) */ +#include "sim_console.h" /* more SIMH defns (include path should include .., or make a copy) */ + #include #include #include diff --git a/Ibm1130/ibm1130_gui.c b/Ibm1130/ibm1130_gui.c index 9ae67c35..bd972bba 100644 --- a/Ibm1130/ibm1130_gui.c +++ b/Ibm1130/ibm1130_gui.c @@ -11,6 +11,8 @@ * This is not a supported product, but I welcome bug reports and fixes. * Mail to simh@ibm1130.org * + * 09-Apr-04 BLK Changed code to use stock windows cursor IDC_HAND if available + * * 02-Dec-02 BLK Changed display, added printer and card reader icons * Added drag and drop support for scripts and card decks * Added support for physical card reader and printer (hides icons) @@ -768,7 +770,13 @@ static DWORD WINAPI Pump (LPVOID arg) hDkGreyPen = CreatePen(PS_SOLID, 1, RGB(64,64,64)); hcArrow = LoadCursor(NULL, IDC_ARROW); - hcHand = LoadCursor(hInstance, MAKEINTRESOURCE(IDC_HAND)); +#ifdef IDC_HAND + hcHand = LoadCursor(NULL, IDC_HAND); // use stock object provided by Windows + if (hcHand == NULL) + hcHand = LoadCursor(hInstance, MAKEINTRESOURCE(IDC_MYHAND)); +#else + hcHand = LoadCursor(hInstance, MAKEINTRESOURCE(IDC_MYHAND)); +#endif if (hBitmap == NULL) hBitmap = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_CONSOLE)); diff --git a/Ibm1130/ibm1130res.h b/Ibm1130/ibm1130res.h index 6990b89e..d84a46ee 100644 --- a/Ibm1130/ibm1130res.h +++ b/Ibm1130/ibm1130res.h @@ -3,7 +3,7 @@ // Used by ibm1130.rc // #define IDB_CONSOLE 101 -#define IDC_HAND 102 +#define IDC_MYHAND 102 // Next default values for new objects // diff --git a/Ibm1130/makefile b/Ibm1130/makefile new file mode 100644 index 00000000..04779dc5 --- /dev/null +++ b/Ibm1130/makefile @@ -0,0 +1,74 @@ +# (This makefile is for operating systems other than Windows, +# or compilers other than Microsoft's. For MS builds, use the +# .mak files found in this directory and the utils directory). +# +# If you are building the emulator and utilities as part of +# the SIMH package, please: +# +# Be sure that you there are NO copies of scp.c, scp_tty.c, +# sim_sock.c, sim_tmxr.c, sim_rev.h, sim_defs.h, sim_sock.h and +# sim_tmxr.h in the ibm1130 subdirectory. Delete them if there +# are. +# +# Do not use this makefile with "make all" or "make ibm1130". +# Use the SIMH build files instead. +# +# If and when you download updates for this simulator from +# www.ibm1130.org, get ibm1130code.zip and ibm1130software.zip +# separately. +# +# If you have downloaded the emulator independently of SIMH (e.g, from +# www.ibm1130.org), please: +# +# Be sure that you DO have copies of scp.c, scp_tty.c, sim_sock.c, +# sim_tmxr.c, sim_rev.h, sim_defs.h, sim_sock.h and sim_tmxr.h +# in this folder. +# +# Use this file to make the emulator. +# +# If and when you download updates for this simulator from +# www.ibm1130.org, get ibm1130.zip. When you expand it, +# also expand ibm1130sofware.zip, which is inside. +# +# In either case, if you want to build DMS or work with assembly +# language programs outside of DMS, you'll want to make the utilities +# by cd'ing to the utils directory and running make there. + +# CC Command +# +# Note: -O2 is sometimes broken in GCC when setjump/longjump is being +# used. Try -O2 only with released simulators. +# +CC = gcc -O0 -lm -I . +#CC = gcc -O2 -g -lm -I . + + +# +# Common Libraries +# +BIN = +SIM = scp.c sim_console.c sim_fio.c sim_sock.c sim_timer.c sim_tmxr.c scp_tty.c +SIM_INC = scp.h sim_console.h sim_defs.h sim_fio.h sim_rev.h sim_sock.h sim_timer.h sim_tmxr.h + +# +# Emulator source files and compile time options +# + +ibm1130D = ./ +ibm1130 = ${ibm1130D}ibm1130_sys.c ${ibm1130D}ibm1130_cpu.c \ + ${ibm1130D}ibm1130_cr.c ${ibm1130D}ibm1130_disk.c \ + ${ibm1130D}ibm1130_stddev.c ${ibm1130D}ibm1130_gdu.c \ + ${ibm1130D}ibm1130_gui.c ${ibm1130D}ibm1130_prt.c \ + ${ibm1130D}ibm1130_fmt.c + +ibm1130_INC = ibm1130res.h ibm1130_conin.h ibm1130_conout.h \ + ibm1130_defs.h ibm1130_prtwheel.h ibm1130_fmt.h \ + dmsr2v12phases.h dmsr2v12slet.h + +# +# Build the emulator +# + +${BIN}ibm1130 : ${ibm1130} ${SIM} ${ibm1130_INC} ${SIM_INC} + ${CC} ${ibm1130} ${SIM} -o $@ + diff --git a/Ibm1130/utils/asm1130.c b/Ibm1130/utils/asm1130.c new file mode 100644 index 00000000..b5dce215 --- /dev/null +++ b/Ibm1130/utils/asm1130.c @@ -0,0 +1,4503 @@ +/* + * (C) Copyright 2002, Brian Knittel. + * You may freely use this program, but: it offered strictly on an AS-IS, AT YOUR OWN + * RISK basis, there is no warranty of fitness for any purpose, and the rest of the + * usual yada-yada. Please keep this notice and the copyright in any distributions + * or modifications. + * + * This is not a supported product, but I welcome bug reports and fixes. + * Mail to sim@ibm1130.org + */ + +// --------------------------------------------------------------------------------- +// ASM1130 - IBM 1130 Cross Assembler +// +// Version +// 1.10 - 2003Dec08 - Fixed opcode value for XCH instruction, thanks to +// Roger Simpson. +// 1.09 - 2003Aug03 - Added fxwrite so asm will write little-endian files +// on all CPUs. +// 1.08 - 2003Mar18 - Fixed bug that complained about valid MDX displacement of +127 +// 1.07 - 2003Jan05 - Filenames are now left in lower case. SYMBOLS.SYS stays all upper case +// 1.06 - 2002May02 - Fixed bug in ebdic constants (data goes into low byte) +// First stab at adding ISS level # info, this is iffy +// 1.05 - 2002Apr24 - Made negative BSS size a warning not an error, as it +// it's looking like it happens twice in PTMASMBL. +// This version still doesn't do fixed point numbers and +// negative floats may be wrong. +// 1.04 - 2002Apr18 - Added binary (card loader format) output, removed +// interim IPL output formats and moved that to MKBOOT. +// Enhanced relocatable code handling. Added floating +// point constants, but don't know how to make fixed point +// constants yet. Made amenable to syntax variations found +// in the DMS sources. Doesn't properly handle ILS +// modules yet and ISS is probably wrong. +// 1.03 - 2002Apr10 - numerous fixes, began to add relative/absolute support +// 1.02 - 2002Feb26 - replaced "strupr" with "upcase" for compatibility +// 1.01 - 2002Feb25 - minor compiler compatibility changes +// 1.00 - 2002Feb01 - first release. Tested only under Win32. +// --------------------------------------------------------------------------------- +// +// Usage: +// asm1130 [-bvsx] [-o[file]] [-l[file]] [-rN.M] file... +// +// Description: +// -b binary output (.bin, relocatable absolute format) +// -v verbose +// -s print symbol table +// -x print cross references +// -o output file (default is name of first source file + extension .out or .bin) +// -l listing file (default is name of first source file + extension .lst) +// -y preload system symbol table SYMBOLS.SYS (from the current directory) +// -w write the system symbol table SYMBOLS.SYS in the current directory +// -W same as -w but don't prompt to confirm overwriting existing file +// -r set DMS release to release N version M, for sbrk cards +// +// Listing and symbol table output can be turned on by *LIST directives in the source, too +// Listing file default extension is .LST +// +// Input files can use strict IBM 1130 Assembler column format, or loose formatting +// with tabs, or any mix on a line-by-line basis. Input files default extension is .ASM. +// +// Strict specification is: +// +// label columns 1 - 5 +// opcode 7 - 10 +// tag 12 +// index 13 +// arguments 15 - 51 +// +// Loose, indicated by presence of ascii tab character(s): +// +// labelopcodeindex and format indicatorsarguments +// +// In both cases, the IBM convention that the arguments section ends with the +// first nonblank applies. This means that ".DC 1, 2, 3" assembles only the 1! +// +// Output file format is that used by the LOAD command in my 1130 +// simulator. Lines are any of the following. All values are in hex: +// +// @addr load address for subsequent words is addr +// Znwords Zero the next "nwords" and increment load address by nwords. +// =addr set IAR register to address addr (a convenience) +// value load value at load address and increment load address +// +// Output file default extension is .OUT or .BIN for binary assemblies +// +// Note: this version does not handle relative assembly, and so doesn't carry +// absolute/relative indication through expression calculation. +// +// Seems to work. Was able to assemble the resident monitor OK. +// >>> Look for "bug here" though, for things to check out. +// +// Notes: +// org_advanced tells whether * in an expression refers to the address AFTER the +// instruction (1 or 2 words, depending on length). This is the case for opcodes +// but not all directives. +// +// Added special coldstart format directives: +// +// .IPL 1130,XXXXXXXX +// .IPL 1800,XXXXXXXX +// +// (these are not standard IBM) +// +// These directives cause the output file to be written in binary in either 1130 or +// 1800 IPL format. In 1130 format, the index bits are lost and the displacement +// is sign extended. In 1800 format, the data are punched 8 bits at a time into +// two columns per word. If an identifier is not given, data are punched into +// all 80 columns. If an identifier is given, data is punched in columns 0 through +// 72, and the identification XXXXXXXX is punched in columns 73 through 80. (If +// there are multiple output cards the last ident character is incremented). A +// warning is issued if 1130 assembly results in lost bits. These directives +// should be the first in the file as you don't want text and binary mixed in +// the same output file. +// +// Revision History +// 16Apr02 1.03 Added sector break, relocation flag output +// 02Apr02 1.02 Fixed bug in BOSC: it CAN be a short instruction. +// Added directives for 1130 and 1800 IPL output formats +// Added conditional assembly directives +// --------------------------------------------------------------------------------- + +#include +#include +#include +#include +#include +#include +#include +#include "util_io.h" + +// ---------------------------------------------------------------1------------------ +// DEFINITIONS +// --------------------------------------------------------------------------------- + +// I have found some IBM source code where @ and ' seem interchangable. +// Comment out this define to make @ and ' different in symbol names, keep to make equivalent + +#if defined(VMS) + # include /* to pick up 'unlink' */ +#endif + +#define BETWEEN(v,a,b) (((v) >= (a)) && ((v) <= (b))) +#define MIN(a,b) (((a) <= (b)) ? (a) : (b)) +#define MAX(a,b) (((a) >= (b)) ? (a) : (b)) + +#ifndef _WIN32 + int strnicmp (char *a, char *b, int n); + int strcmpi (char *a, char *b); +#endif + +#define FIX_ATS + +#define DMSVERSION "V2M12" /* required 5 characters on sector break card col 67-71 */ + +#define DOLLAREXIT "/38" // hmmm, are these really fixed absolutely in all versions? +#define DOLLARDUMP "/3F" + +#define SYSTEM_TABLE "SYMBOLS.SYS" + +#define BOOL int +#define TRUE 1 +#define FALSE 0 + +#define VERSION "ASM1130 CROSS ASSEMBLER V1.08" + +#define ISTV 0x33 // magic number from DMS R2V12 monitorm symbol @ISTV + +#define MAXLITERALS 300 +#define MAXENTRIES 14 + +#define LINEFORMAT " %4ld | %s" +#define LEFT_MARGIN " |" + // XXXX XXXX XXXX XXXX XXXX XXXX + // org w1 w2 w3 w4 w5 + // XXXX 1111 2222 3333 4444 LLLL | + // 12345678901234567890123456789012 + +typedef enum {ABSOLUTE = 0, RELATIVE = 1, LIBF = 2, CALL = 3} RELOC; + +typedef struct tag_symbol { // symbol table entry: + char *name; // name of symbol + int value; // value (absolute) + int pass; // defined during pass # + int defined; // definition state, see #defines below + RELOC relative; // ABSOLUTE = absolute, RELATIVE = relative + struct tag_symbol *next; // next symbol in list + struct tag_xref *xrefs; // cross references +} SYMBOL, *PSYMBOL; + +#define S_UNDEFINED 0 // values of 'defined' +#define S_PROVISIONAL 1 // usually an expression with forward references +#define S_DEFINED 2 // ordering must be undef < prov < def + +typedef struct tag_xref { // cross reference entry + char *fname; // filename + int lno; // line number + BOOL definition; // true = definition, false = reference + struct tag_xref *next; // next reference +} XREF, *PXREF; + +typedef struct tag_expr { // expression result: absolute or relative + int value; + RELOC relative; +} EXPR; + +typedef enum {PROGTYPE_ABSOLUTE = 1, PROGTYPE_RELOCATABLE = 2, PROGTYPE_LIBF = 3, PROGTYPE_CALL = 4, + PROGTYPE_ISSLIBF = 5, PROGTYPE_ISSCALL = 6, PROGTYPE_ILS = 7} PROGTYPE; + +typedef enum {SUBTYPE_INCORE = 0, SUBTYPE_FORDISK = 1, SUBTYPE_ARITH = 2, + SUBTYPE_FORNONDISK = 3, SUBTYPE_FUNCTION=8} SUBTYPE; + +typedef enum {INTMODE_UNSPECIFIED = 0, INTMODE_MATCHREAL = 0x0080, INTMODE_ONEWORD = 0x0090} INTMODE; +typedef enum {REALMODE_UNSPECIFIED = 0, REALMODE_STANDARD = 0x0001, REALMODE_EXTENDED = 0x0002} REALMODE; + +#define OP_INDEXED 0x0300 // 1130 opcode modifier bits +#define OP_LONG 0x0400 +#define OP_INDIRECT 0x0080 + +typedef enum {OUTMODE_LOAD, OUTMODE_1130, OUTMODE_1800, OUTMODE_BINARY} OUTMODE; + +#ifdef _WIN32 +# define OUTWRITEMODE "wb" // write outfile in binary mode +# define ENDLINE "\r\n" // explictly write CR/LF +#else +# define OUTWRITEMODE "w" // use native mode +# define ENDLINE "\n" +#endif + +// --------------------------------------------------------------------------------- +// GLOBALS +// --------------------------------------------------------------------------------- + +// command line syntax +char *usestr = +"Usage: asm1130 [-bpsvwxy] [-o[file]] [-l[file]] [-rN.M] file...\n\n" +"-b binary (relocatable format) output; default is simulator LOAD format\n" +"-p count passes required; no assembly output is created with this flag" +"-s add symbol table to listing\n" +"-v verbose mode\n" +"-w write system symbol table as SYMBOLS.SYS\n" +"-W same as -w but do not confirm overwriting previous file\n" +"-x add cross reference table to listing\n" +"-y preload system symbol table SYMBOLS.SYS\n" +"-o set output file; default is first input file + .out or .bin\n" +"-l create listing file; default is first input file + .lst\n" +"-r set dms version to VN RM for system SBRK cards"; + +BOOL verbose = FALSE; // verbose mode flag +BOOL tabformat = FALSE; // TRUE if tabs were seen in the file +int pass; // current assembler pass (1 or 2) +char curfn[256]; // current input file name +char progname[8]; // base name of primary input file +char *outfn = NULL; // output file name +int lno; // current input file line number +BOOL preload = FALSE; // preload system symbol table +BOOL savetable = FALSE; // write system symbol table +BOOL saveprompt = TRUE; // prompt before overwriting +int nerrors = 0; // count of errors +int nwarnings = 0; // count of warnings +FILE *fin = NULL; // current input file +FILE *fout = NULL; // output file stream +OUTMODE outmode = OUTMODE_LOAD; // output file mode +int outcols = 0; // columns written in using card output +int maxiplcols = 80; +char cardid[9]; // characters used for IPL card ID +FILE *flist = NULL; // listing file stream +char *listfn = NULL; // listing filename +BOOL do_list = FALSE; // flag: create listing +BOOL passcount = FALSE; // flag: count passes only +BOOL list_on = TRUE; // listing is currently enabled +BOOL do_xref = FALSE; // cross reference listing +BOOL do_syms = FALSE; // symbol table listing +BOOL ended = FALSE; // end of current file +BOOL hasforward = FALSE; // true if there are any forward references +char listline[350]; // output listing line +BOOL line_error; // already saw an error on current line +RELOC relocate = RELATIVE; // relocatable assembly mode +BOOL assembled = FALSE; // true if any output has been generated +int nwout; // number of words written on current line +int org = 0; // output address (origin) +int org_advanced; // if TRUE, * means instruction addr+(value) during evaluation +int pta = -1; // program transfer address +BOOL cexpr = FALSE; // "C" expression syntax +PSYMBOL symbols = NULL; // the symbol table (linear search) +BOOL check_control = TRUE; // check for control cards +PROGTYPE progtype = PROGTYPE_RELOCATABLE; // program type +INTMODE intmode = INTMODE_UNSPECIFIED; // integer mode +REALMODE realmode = REALMODE_UNSPECIFIED; // real mode +int nintlevels = 0; // # of interrupt levels for ISS +int intlevel_primary = 0; // primary level for ISS and level for ILS +int intlevel_secondary = 0; // secondary level for ISS +int iss_number = 0; // ISS number +PSYMBOL entry[MAXENTRIES]; // entries for subroutines +int nentries = 0; +int ndefined_files = 0; + +struct lit { // accumulated literals waiting to be output + int value; // constant value + int tagno; // constant symbol tag number (e.g. _L001) + BOOL hex; // constant was expressed in hex + BOOL even; // constant was operand of a double-width instruction (e.g. AD) +} literal[MAXLITERALS]; + +int n_literals = 0, lit_tag = 0; +BOOL requires_even_address; // target of current instruction +BOOL dmes_saved; // odd character left over from dmes ending in ' +int dmes_savew; +char opfield[256]; // extracted operand field from source line +char dmsversion[12] = DMSVERSION; // version number for SBRK cards +const char whitespace[] = " \t"; // whitespace + +int ascii_to_ebcdic_table[128] = +{ +// + 0x00,0x01,0x02,0x03,0x37,0x2d,0x2e,0x2f, 0x16,0x05,0x25,0x0b,0x0c,0x0d,0x0e,0x0f, +// + 0x10,0x11,0x12,0x13,0x3c,0x3d,0x32,0x26, 0x18,0x19,0x3f,0x27,0x1c,0x1d,0x1e,0x1f, +// spac ! " # $ % & ' ( ) * + , - . / + 0x40,0x5a,0x7f,0x7b,0x5b,0x6c,0x50,0x7d, 0x4d,0x5d,0x5c,0x4e,0x6b,0x60,0x4b,0x61, +// 0 1 2 3 4 5 6 7 8 9 : ; < = > ? + 0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7, 0xf8,0xf9,0x7a,0x5e,0x4c,0x7e,0x6e,0x6f, +// @ A B C D E F G H I J K L M N O + 0x7c,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7, 0xc8,0xc9,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6, +// P Q R S T U V W X Y Z [ \ ] & _ + 0xd7,0xd8,0xd9,0xe2,0xe3,0xe4,0xe5,0xe6, 0xe7,0xe8,0xe9,0xba,0xe0,0xbb,0xb0,0x6d, +// a b c d e f g h i j k l m n o + 0x79,0x81,0x82,0x83,0x84,0x85,0x86,0x87, 0x88,0x89,0x91,0x92,0x93,0x94,0x95,0x96, +// p q r s t u v w x y z { | } ~ + 0x97,0x98,0x99,0xa2,0xa3,0xa4,0xa5,0xa6, 0xa7,0xa8,0xa9,0xc0,0x4f,0xd0,0xa1,0x07, +}; + +int ascii_to_1403_table[128] = +{ /* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f */ + 0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f, 0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f, + 0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f, 0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f, + 0x7f,0x7f,0x7f,0x7f,0x62,0x7f,0x15,0x0b, 0x57,0x2f,0x23,0x6d,0x16,0x61,0x6e,0x4c, + 0x49,0x40,0x01,0x02,0x43,0x04,0x45,0x46, 0x07,0x08,0x7f,0x7f,0x7f,0x4a,0x7f,0x7f, + 0x7f,0x64,0x25,0x26,0x67,0x68,0x29,0x2a, 0x6b,0x2c,0x58,0x19,0x1a,0x5b,0x1c,0x5d, + 0x5e,0x1f,0x20,0x0d,0x0e,0x4f,0x10,0x51, 0x52,0x13,0x54,0x7f,0x7f,0x7f,0x7f,0x7f, + 0x7f,0x64,0x25,0x26,0x67,0x68,0x29,0x2a, 0x6b,0x2c,0x58,0x19,0x1a,0x5b,0x1c,0x5d, + 0x5e,0x1f,0x20,0x0d,0x0e,0x4f,0x10,0x51, 0x52,0x13,0x54,0x7f,0x7f,0x7f,0x7f,0x7f +}; + +#include "../ibm1130_conout.h" /* conout_to_ascii_table */ +#include "../ibm1130_prtwheel.h" /* 1132 printer printwheel data */ + +// --------------------------------------------------------------------------------- +// PROTOTYPES +// --------------------------------------------------------------------------------- + +void bail (char *msg); +void flag (char *arg); +void proc (char *fname); +void startpass (int n); +void errprintf (char *fmt, ...); +void asm_error (char *fmt, ...); +void asm_warning (char *fmt, ...); +char *astring (char *str); +PSYMBOL lookup_symbol (char *name, BOOL define); +void add_xref (PSYMBOL s, BOOL definition); +int get_symbol (char *name); +void set_symbol (char *name, int value, int known, RELOC relative); +char * gtok (char **pc, char *tok); +char *skipbl (char *c); +void sym_list (void); +void xref_list (void); +void listhdr (void); +int getexpr (char *pc, BOOL undefined_ok, EXPR *expr); +void passreport (void); +void listout (BOOL reset); +void output_literals (BOOL eof); +char *upcase (char *str); +void prep_line (char *line); +int ascii_to_hollerith (int ch); +char *detab (char *str); +void preload_symbols (void); +void save_symbols (void); +void bincard_init (void); +void bincard_writecard (char *sbrk_text); +void bincard_writedata (void); +void bincard_flush (void); +void bincard_sbrk (char *line); +void bincard_setorg (int neworg); +void bincard_writew (int word, RELOC relative); +void bincard_endcard (void); +void handle_sbrk (char *line); +void bincard_typecard (void); +void namecode (unsigned short *words, char *tok); + +// --------------------------------------------------------------------------------- +// main routine +// --------------------------------------------------------------------------------- + +int main (int argc, char **argv) +{ + int i, sawfile = FALSE; + + for (i = 1; i < argc; i++) // process command line switches + if (*argv[i] == '-') + flag(argv[i]+1); + + startpass(1); // first pass, process files + + for (i = 1; i < argc; i++) + if (*argv[i] != '-') + proc(argv[i]), sawfile = TRUE; + + if (! sawfile) // should have seen at least one file + bail(usestr); + + if (passcount) { + passreport(); + return 0; + } + + startpass(2); // second pass, process files again + + for (i = 1; i < argc; i++) + if (*argv[i] != '-') + proc(argv[i]); + + if (outmode == OUTMODE_LOAD) { + if (pta >= 0) // write start address to the load file + fprintf(fout, "=%04x" ENDLINE, pta & 0xFFFF); + } + else + bincard_endcard(); + + if (flist) { + if (nerrors || nwarnings) { // summarize (or summarise) + if (nerrors == 0) + fprintf(flist, "There %s ", (nwarnings == 1) ? "was" : "were"); + else + fprintf(flist, "\nThere %s %d error%s %s", + (nerrors == 1) ? "was" : "were", nerrors, (nerrors == 1) ? "" : "s", nwarnings ? "and " : ""); + + if (nwarnings > 0) + fprintf(flist, "%d warning%s ", nwarnings, (nwarnings == 1) ? "" : "s"); + + fprintf(flist, "in this assembly\n"); + } + else + fprintf(flist, "\nThere were no errors in this assembly\n"); + } + + if (flist) { // finish the listing + if (pta >= 0) + fprintf(flist, "\nProgram transfer address = %04x\n", pta); + + if (do_xref) + xref_list(); + else if (do_syms) + sym_list(); + } + + if (savetable) + save_symbols(); + + return 0; // all done +} + +// --------------------------------------------------------------------------------- +// flag - process one command line switch +// --------------------------------------------------------------------------------- + +void flag (char *arg) +{ + int major, minor; + + while (*arg) { + switch (*arg++) { + case 'o': // output (load) file name + if (! *arg) + bail(usestr); + outfn = arg; + return; + + case 'p': + passcount = TRUE; + break; + + case 'v': // mumble while running + verbose = TRUE; + break; + + case 'x': // print cross reference table + do_xref = TRUE; + break; + + case 's': // print symbol table + do_syms = TRUE; + break; + + case 'l': // listing file name + listfn = (* arg) ? arg : NULL; + do_list = TRUE; + return; + + case 'W': + saveprompt = FALSE; + // fall through + case 'w': + savetable = TRUE; + break; + + case 'y': + preload = TRUE; + break; + + case 'b': + outmode = OUTMODE_BINARY; + break; + + case 'r': + if (sscanf(arg, "%d.%d", &major, &minor) != 2) + bail(usestr); + sprintf(dmsversion, "V%01.1dM%02.2d", major, minor); + return; + + default: + bail(usestr); + break; + } + } +} + +// --------------------------------------------------------------------------------- +// bail - print error message on stderr (only) and exit +// --------------------------------------------------------------------------------- + +void bail (char *msg) +{ + fprintf(stderr, "%s\n", msg); + exit(1); +} + +// --------------------------------------------------------------------------------- +// errprintf - print error message to stderr +// --------------------------------------------------------------------------------- + +void errprintf (char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); // get pointer to argument list + + vfprintf(stderr, fmt, args); // write errors to terminal (stderr) + + va_end(args); +} + +// --------------------------------------------------------------------------------- +// asm_error - report an error to listing file and to user's console +// --------------------------------------------------------------------------------- + +void asm_error (char *fmt, ...) +{ + va_list args; + + if (pass == 1) // only print on pass 2 + return; + + va_start(args, fmt); // get pointer to argument list + + fprintf(stderr, "E: %s (%d): ", curfn, lno); + vfprintf(stderr, fmt, args); // write errors to terminal (stderr) + putc('\n', stderr); + + if (flist != NULL && list_on) { + listout(FALSE); + line_error = TRUE; + + fprintf(flist, "**** Error: "); + vfprintf(flist, fmt, args); // write errors to listing file + putc('\n', flist); + } + + nerrors++; + va_end(args); +} + +// --------------------------------------------------------------------------------- +// asm_warning - same but warnings are not counted +// --------------------------------------------------------------------------------- + +void asm_warning (char *fmt, ...) +{ + va_list args; + + if (pass == 1) // only print on pass 2 + return; + + va_start(args, fmt); // get pointer to argument list + + fprintf(stderr, "W: %s (%d): ", curfn, lno); + vfprintf(stderr, fmt, args); // write errors to terminal (stderr) + putc('\n', stderr); + + if (flist != NULL && list_on) { + listout(FALSE); + line_error = TRUE; + + fprintf(flist, "**** Warning: "); + vfprintf(flist, fmt, args); // write errors to listing file + putc('\n', flist); + } + + nwarnings++; +} + +// --------------------------------------------------------------------------------- +// sym_list - print the symbol table +// --------------------------------------------------------------------------------- + +void sym_list (void) +{ + PSYMBOL s; + int n = 5; + + if (symbols == NULL || flist == NULL) + return; + + fprintf(flist, "\n=== SYMBOL TABLE ==============================================================\n"); + + for (s = symbols, n = 0; s != NULL; s = s->next) { + if (n >= 5) { + putc('\n', flist); + n = 0; + } + else if (n > 0) + fprintf(flist, " "); + + fprintf(flist, "%-6s ", s->name); + if (s->defined == S_DEFINED) + fprintf(flist, "%04x%s", s->value & 0xFFFF, s->relative ? "R" : " "); + else + fprintf(flist, "UUUU "); + + n++; + } + fprintf(flist, "\n"); +} + +// --------------------------------------------------------------------------------- +// passreport - report # of passes required for assembly on the 1130 +// --------------------------------------------------------------------------------- + +void passreport (void) +{ + PSYMBOL s; + + for (s = symbols; s != NULL; s = s->next) { + if (s->defined == S_UNDEFINED || s->defined == S_PROVISIONAL) { + printf("There are undefined symbols. Cannot determine pass requirement.\n"); + return; + } + } + + if (hasforward) + printf("There are forward references. Two passes are required.\n"); + else + printf("There are no forward references. Only one pass is required.\n"); +} + +// --------------------------------------------------------------------------------- +// xref_list - print the cross-reference table +// --------------------------------------------------------------------------------- + +void xref_list (void) +{ + int n = 0; + PXREF x; + PSYMBOL s; + + if (flist == NULL || symbols == NULL) + return; + + fprintf(flist, "\n=== CROSS REFERENCES ==========================================================\n"); + + if (symbols == NULL || flist == NULL) + return; + + fprintf(flist, "Name Val Defd Referenced\n"); + + for (s = symbols; s != NULL; s = s->next) { + fprintf(flist, "%-5s %04x%s", s->name, s->value & 0xFFFF, s->relative ? "R" : " "); + + for (x = s->xrefs; x != NULL; x = x->next) + if (x->definition) + break; + + if (x == NULL) + fprintf(flist, "----"); + else + fprintf(flist, " %4d", x->lno); + + for (n = 0, x = s->xrefs; x != NULL; x = x->next) { + if (x->definition) + continue; + + if (n >= 12) { + n = 0; + fprintf(flist, "\n "); + } + fprintf(flist, " %4d", x->lno); + n++; + } + putc('\n', flist); + } +} + +// --------------------------------------------------------------------------------- +// listhdr - print a banner header in the listing file. Since it's not paginated +// at this time, this is not used often. +// --------------------------------------------------------------------------------- + +void listhdr (void) +{ + time_t t; + + time(&t); + fprintf(flist, "%s -- %s -- %s\n", VERSION, dmsversion, ctime(&t)); +} + +// --------------------------------------------------------------------------------- +// astring - allocate a copy of a string +// --------------------------------------------------------------------------------- + +char *astring (char *str) +{ + static char *s = NULL; + + if (s != NULL) + if (strcmp(s, str) == 0) // if same as immediately previous allocation + return s; // return same pointer (why did I do this?) + + if ((s = malloc(strlen(str)+1)) == NULL) + bail("out of memory"); + + strcpy(s, str); + return s; +} + +// --------------------------------------------------------------------------------- +// lookup_symbol - get pointer to a symbol. +// If define is TRUE, creates and marks 'undefined' if not previously defined. +// --------------------------------------------------------------------------------- + +PSYMBOL lookup_symbol (char *name, BOOL define) +{ + PSYMBOL s, n, prv = NULL; + int c; + char *at; + + if (strlen(name) > 5) { // (sigh) + asm_error("Symbol '%s' is longer than 5 letters", name); + name[5] = '\0'; + } + +#ifdef FIX_ATS + while ((at = strchr(name, '@')) != NULL) + *at = '\''; +#endif + // search sorted list of symbols + for (s = symbols; s != NULL; prv = s, s = s->next) { + c = strcmpi(s->name, name); + if (c == 0) + return s; + if (c > 0) + break; + } + + if (! define) + return NULL; // not found + + if ((n = malloc(sizeof(SYMBOL))) == NULL) + bail("out of memory"); + + n->name = astring(name); // symbol was undefined -- add it now + n->value = 0; + n->defined = FALSE; + n->xrefs = NULL; + n->defined = FALSE; + + n->next = s; // link in alpha order + + if (prv == NULL) // we stopped before first item in list + symbols = n; + else + prv->next = n; // insert after item before place we stopped + + return n; +} + +// --------------------------------------------------------------------------------- +// add_xref - add a cross reference entry to a symbol +// --------------------------------------------------------------------------------- + +void add_xref (PSYMBOL s, BOOL definition) +{ + PXREF x, prv = NULL, n; + + if (pass == 1 || ! do_xref) // define only during 2nd pass and only if listing was requested + return; + + for (x = s->xrefs; x != NULL; prv = x, x = x->next) + if (strcmpi(x->fname, curfn) == 0 && x->lno == lno) + return; // ignore multiple refs on same line + + if ((n = malloc(sizeof(XREF))) == NULL) + bail("out of memory"); + + n->fname = astring(curfn); + n->lno = lno; + n->definition = definition; + + n->next = x; // link at end of existing list + + if (prv == NULL) + s->xrefs = n; + else + prv->next = n; +} + +// --------------------------------------------------------------------------------- +// get_symbol - get a symbol value, defining if necessary +// --------------------------------------------------------------------------------- + +int get_symbol (char *name) +{ + PSYMBOL s; + + s = lookup_symbol(name, TRUE); // lookup, define if necessary + + if (pass == 2) // should be defined by now + if (! s->defined) + asm_error("Symbol '%s' is undefined", name); + + add_xref(s, FALSE); // note the reference + + return s->value; +} + +// --------------------------------------------------------------------------------- +// set_symbol - set a symbol value. Known = TRUE means we really know the value; +// FALSE means we're calculating it with forward referenced values or something like +// that. +// --------------------------------------------------------------------------------- + +void set_symbol (char *name, int value, int known, RELOC relative) +{ + PSYMBOL s; + char *at; + + if (strlen(name) > 5) { + asm_error("Symbol '%s' is longer than 5 letters", name); + name[5] = '\0'; + } + +#ifdef FIX_ATS + while ((at = strchr(name, '@')) != NULL) + *at = '\''; +#endif + + s = lookup_symbol(name, TRUE); + + if (s->defined == S_DEFINED) // once defined, it should not change + if (s->value != value) + asm_error("Symbol '%s' %s", name, (s->pass == pass) ? "is multiply defined" : "changed between passes"); + + s->value = value; + s->relative = relative; + s->defined = known ? S_DEFINED : S_PROVISIONAL; + s->pass = pass; + + if (! known) + hasforward = TRUE; + + add_xref(s, TRUE); // record the place of definition +} + +// --------------------------------------------------------------------------------- +// skipbl - return pointer to first nonblank character in string s +// --------------------------------------------------------------------------------- + +char *skipbl (char *s) +{ + while (*s && *s <= ' ') + s++; + + return s; +} + +// --------------------------------------------------------------------------------- +// gtok - extracts a whitespace-delimited token from the string pointed to by *pc; +// stores the token into the buffer tok and returns pointer to same. Returns NULL +// when there are no tokens. Best to call repeatedly with a pointer to the source +// buffer, e.g. +// char *pbuf = buf; +// while (gtok(&pbuf, token) != NULL) ... +// --------------------------------------------------------------------------------- + +char * gtok (char **pc, char *tok) +{ + char *s = *pc, *otok = tok; + + while (*s && *s <= ' ') // skip blanks + s++; + + if (! *s) { // no tokens to be found + *tok = '\0'; + *pc = s; + return NULL; + } + + while (*s > ' ') // save nonblanks into 'tok' + *tok++ = *s++; + + *tok = '\0'; // terminate + *pc = s; // adjust caller's pointer + + return otok; // return pointer to token +} + +// listing format: +// +// ADDR CODE SOURCE +// 0000 0000 0000 0000 0000 | XXXXXXXXXXXXXXXXX + +// --------------------------------------------------------------------------------- +// trim - remove trailing whitespace from string s +// --------------------------------------------------------------------------------- + +char *trim (char *s) +{ + char *os = s, *nb; + + for (nb = s-1; *s; s++) + if (*s > ' ') + nb = s; + + nb[1] = '\0'; + return os; +} + +// --------------------------------------------------------------------------------- +// listout - emit current constructed output listing line held in "listline" and +// if "reset" is true, prepare listline for second and subsequent listing lines +// for a given input statement. +// --------------------------------------------------------------------------------- + +void listout (BOOL reset) +{ + if (flist && list_on && ! line_error) { + trim(listline); + fputs(listline, flist); + putc('\n', flist); + if (reset) + sprintf(listline, LEFT_MARGIN, org); + } +} + +// --------------------------------------------------------------------------------- +// storew - store a word in the output medium (hex or binary file). Most of the time +// writew is used. Advances the origin! +// --------------------------------------------------------------------------------- + +void storew (int word, RELOC relative) +{ + if (pass == 2) { // save in output (load) file. + switch (outmode) { + case OUTMODE_BINARY: + bincard_writew(word, relative); + break; + + case OUTMODE_LOAD: + fprintf(fout, " %04x%s" ENDLINE, word & 0xFFFF, + (relative == ABSOLUTE) ? "" : (relative == RELATIVE) ? "R" : + (relative == LIBF) ? "L" : (relative == CALL) ? "$" : "?"); + break; + + default: + bail("in storew, can't happen"); + } + } + + if (relative != LIBF) + org++; + + assembled = TRUE; // remember that we wrote something +} + +// --------------------------------------------------------------------------------- +// setw - store a word value in the current listing output line in position 'pos'. +// --------------------------------------------------------------------------------- + +void setw (int pos, int word, RELOC relative) +{ + char tok[10], *p; + int i; + + if (flist == NULL || ! list_on) + return; + + sprintf(tok, "%04x", word & 0xFFFF); + + for (i = 0, p = listline + 5*pos; i < 4; i++) + p[i] = tok[i]; + + if (relative == RELATIVE) + p[i] = 'R'; + else if (relative != ABSOLUTE) + p[i] = '*'; +} + +// --------------------------------------------------------------------------------- +// writew - emit an assembled word value. Words are also displayed in the listing file. +// if relative is true, a relocation entry should be recorded. +// --------------------------------------------------------------------------------- + +void writew (int word, RELOC relative) +{ // first, the listing stuff... + if (nwout == 0) { // on first output word, display address in column 0 + setw(0, org, FALSE); + } + else if (nwout >= 4) { // if 4 words have already been written, start new line + listout(TRUE); + nwout = 0; + } + + nwout++; + setw(nwout, word, relative); // display word in the listing line + + storew(word, relative); // write it to the output medium +} + +// --------------------------------------------------------------------------------- +// setorg - take note of new load address +// --------------------------------------------------------------------------------- + +void setorg (int neworg) +{ + if (pass == 2) { + setw(0, neworg, FALSE); // display in listing file in column 0 + + if (outmode == OUTMODE_LOAD) { // write new load address to the output file + fprintf(fout, "@%04x%s" ENDLINE, neworg & 0xFFFF, relocate ? "R" : ""); + } + else { + bincard_setorg(neworg); + } + } + + org = neworg; +} + +// --------------------------------------------------------------------------------- +// org_even - force load address to an even address +// --------------------------------------------------------------------------------- + +void org_even (void) +{ + if (org & 1) + setorg(org+1); +} + +// --------------------------------------------------------------------------------- +// tabtok - get the token in tab-delimited column number i, from source string c, +// saving in string 'tok'. If save is nonnull, we copy the entire remainder of +// the input string in buffer 'save' (in contrast to 'tok' which gets only the +// first whitespace delimited token). +// --------------------------------------------------------------------------------- + +void tabtok (char *c, char *tok, int i, char *save) +{ + *tok = '\0'; + + while (--i >= 0) { // skip to i'th tab-delimited field + if ((c = strchr(c, '\t')) == NULL) { + if (save) // was none + *save = '\0'; + return; + } + c++; + } + + while (*c == ' ') // skip leading blanks + c++; + + if (save != NULL) // save copy of entire remainder + strcpy(save, c); + + while (*c > ' ') { // take up to any whitespace + if (*c == '(') { // if we start with a paren, take all up to closing paren including spaces + while (*c && *c != ')') + *tok++ = *c++; + } + else if (*c == '.') { // period means literal character following + *tok++ = *c++; + if (*c) + *tok++ = *c++; + } + else + *tok++ = *c++; + } + + *tok = '\0'; +} + +// --------------------------------------------------------------------------------- +// coltok - extract a token from string c, saving to buffer tok, by examining +// columns ifrom through ito only. If save is nonnull, the entire remainder +// of the input from ifrom to the end is saved there. In this routine +// if condense is true, we save all nonwhite characters in the column range; +// not the usual thing. This helps us coalesce the format, tag, & index things +// nto one string for the simple minded parser. If condense is FALSE, we terminate +// on the first nonblank, except that if we start with a (, we take up to ) and +// then terminate on a space. +// +// ifrom and ito on entry are column numbers, not indices; we change that right away +// --------------------------------------------------------------------------------- + +void coltok (char *c, char *tok, int ifrom, int ito, BOOL condense, char *save) +{ + char *otok = tok; + int i; + + ifrom--; + ito--; + + for (i = 0; i < ifrom; i++) { + if (c[i] == '\0') { // line ended before this column + *tok = '\0'; + if (save) + *save = '\0'; + return; + } + } + + if (save) // save from ifrom on + strcpy(save, c+i); + + if (condense) { + for (; i <= ito; i++) { // save only nonwhite characters + if (c[i] > ' ') + *tok++ = c[i]; + } + } + else { + if (c[i] == ' ' && save != NULL)// if it starts with a space, it's empty + *save = '\0'; + + while (i <= ito) { // take up to any whitespace + if (c[i] <= ' ') + break; + else if (c[i] == '(') { // starts with paren? take to close paren + while (i <= ito && c[i]) { + if ((*tok++ = c[i++]) == ')') + break; + } + } + else if (c[i] == '.') { // period means literal character following + *tok++ = c[i++]; + if (i <= ito && c[i]) + *tok++ = c[i++]; + } + else + *tok++ = c[i++]; + } + } + + *tok = '\0'; + trim(otok); +} + +// --------------------------------------------------------------------------------- +// opcode table +// --------------------------------------------------------------------------------- + +// modifiers for the opcode definition table: + +#define L "L" // long +#define X "X" // absolute displacement +#define I "I" // indirect +#define IDX "0123" // indexed (some LDX commands in the DMS source say LDX L0, so accept 0 +#define E "E" // even address +#define NONE "" +#define ALL L X I IDX // hope non-Microsoft C accepts and concatenates strings like this +#define ANY "\xFF" +#define NUMS "0123456789" + +#define IS_DBL 0x0001 // double word operand implies even address +#define IS_ABS 0x0002 // always uses absolute addressing mode (implied X) +#define NO_IDX 0x0004 // even with 1 or 2 modifier, this is not really indexed (for STX/LDX) +#define NO_ARGS 0x0008 // statement takes no arguments +#define TRAP 0x1000 // debug this instruction + +struct tag_op { // OPCODE TABLE + char *mnem; + int opcode; + void (*handler)(struct tag_op *op, char *label, char *mods, char *arg); + char *mods_allowed; + char *mods_implied; + int flags; +}; + // special opcode handlers +void std_op (struct tag_op *op, char *label, char *mods, char *arg); +void b_op (struct tag_op *op, char *label, char *mods, char *arg); +void bsc_op (struct tag_op *op, char *label, char *mods, char *arg); +void bsi_op (struct tag_op *op, char *label, char *mods, char *arg); +void mdx_op (struct tag_op *op, char *label, char *mods, char *arg); +void shf_op (struct tag_op *op, char *label, char *mods, char *arg); + +void x_aif (struct tag_op *op, char *label, char *mods, char *arg); +void x_aifb (struct tag_op *op, char *label, char *mods, char *arg); +void x_ago (struct tag_op *op, char *label, char *mods, char *arg); +void x_agob (struct tag_op *op, char *label, char *mods, char *arg); +void x_anop (struct tag_op *op, char *label, char *mods, char *arg); +void x_abs (struct tag_op *op, char *label, char *mods, char *arg); +void x_call (struct tag_op *op, char *label, char *mods, char *arg); +void x_dsa (struct tag_op *op, char *label, char *mods, char *arg); +void x_file (struct tag_op *op, char *label, char *mods, char *arg); +void x_link (struct tag_op *op, char *label, char *mods, char *arg); +void x_libf (struct tag_op *op, char *label, char *mods, char *arg); +void x_org (struct tag_op *op, char *label, char *mods, char *arg); +void x_opt (struct tag_op *op, char *label, char *mods, char *arg); +void x_ces (struct tag_op *op, char *label, char *mods, char *arg); +void x_bes (struct tag_op *op, char *label, char *mods, char *arg); +void x_bss (struct tag_op *op, char *label, char *mods, char *arg); +void x_dc (struct tag_op *op, char *label, char *mods, char *arg); +void x_dec (struct tag_op *op, char *label, char *mods, char *arg); +void x_ebc (struct tag_op *op, char *label, char *mods, char *arg); +void x_end (struct tag_op *op, char *label, char *mods, char *arg); +void x_ent (struct tag_op *op, char *label, char *mods, char *arg); +void x_epr (struct tag_op *op, char *label, char *mods, char *arg); +void x_equ (struct tag_op *op, char *label, char *mods, char *arg); +void x_exit (struct tag_op *op, char *label, char *mods, char *arg); +void x_ils (struct tag_op *op, char *label, char *mods, char *arg); +void x_iss (struct tag_op *op, char *label, char *mods, char *arg); +void x_libr (struct tag_op *op, char *label, char *mods, char *arg); +void x_lorg (struct tag_op *op, char *label, char *mods, char *arg); +void x_dmes (struct tag_op *op, char *label, char *mods, char *arg); +void x_dn (struct tag_op *op, char *label, char *mods, char *arg); +void x_dump (struct tag_op *op, char *label, char *mods, char *arg); +void x_pdmp (struct tag_op *op, char *label, char *mods, char *arg); +void x_hdng (struct tag_op *op, char *label, char *mods, char *arg); +void x_list (struct tag_op *op, char *label, char *mods, char *arg); +void x_spac (struct tag_op *op, char *label, char *mods, char *arg); +void x_spr (struct tag_op *op, char *label, char *mods, char *arg); +void x_ejct (struct tag_op *op, char *label, char *mods, char *arg); +void x_trap (struct tag_op *op, char *label, char *mods, char *arg); +void x_xflc (struct tag_op *op, char *label, char *mods, char *arg); + +struct tag_op ops[] = { + ".OPT", 0, x_opt, NONE, NONE, 0, // non-IBM extensions + "TRAP", 0, x_trap, NONE, NONE, 0, // assembler breakpoint trap + ".CES", 0, x_ces, NONE, NONE, 0, // lets us specify simulated console entry switch values for startup + + "ABS", 0, x_abs, NONE, NONE, 0, + "BES", 0, x_bes, E, NONE, 0, // standard pseudo-ops + "BSS", 0, x_bss, E, NONE, 0, + "DC", 0, x_dc, NONE, NONE, 0, + "DEC", 0, x_dec, E, E, IS_DBL, + "DMES", 0, x_dmes, ANY, NONE, 0, + "DN", 0, x_dn, NONE, NONE, 0, + "DSA", 0, x_dsa, NONE, NONE, 0, + "DUMP", 0, x_dump, NONE, NONE, 0, + "EBC", 0, x_ebc, NONE, NONE, 0, + "EJCT", 0, x_ejct, NONE, NONE, 0, + "END", 0, x_end, NONE, NONE, 0, + "ENT", 0, x_ent, NONE, NONE, 0, + "EPR", 0, x_epr, NONE, NONE, 0, + "EQU", 0, x_equ, NONE, NONE, 0, + "EXIT", 0, x_exit, NONE, NONE, 0, // alias for call $exit since we don't have macros yet + "FILE", 0, x_file, NONE, NONE, 0, + "HDNG", 0, x_hdng, ANY, NONE, 0, + "ILS", 0, x_ils, NUMS, NONE, 0, + "ISS", 0, x_iss, NUMS, NONE, 0, + "LIBF", 0, x_libf, NONE, NONE, 0, + "LIBR", 0, x_libr, NONE, NONE, 0, + "LINK", 0, x_link, NONE, NONE, 0, + "LIST", 0, x_list, NONE, NONE, 0, + "LORG", 0, x_lorg, NONE, NONE, 0, + "ORG", 0, x_org, NONE, NONE, 0, + "PDMP", 0, x_pdmp, NONE, NONE, 0, + "SPAC", 0, x_spac, NONE, NONE, 0, + "SPR", 0, x_spr, NONE, NONE, 0, + "XFLC", 0, x_xflc, NONE, NONE, 0, + + "A", 0x8000, std_op, ALL, NONE, 0, // standard addressing ops + "AD", 0x8800, std_op, ALL, NONE, IS_DBL, + "AND", 0xE000, std_op, ALL, NONE, 0, + "BSI", 0x4000, bsi_op, ALL, NONE, 0, + "CALL", 0x4000, x_call, ALL, L, 0, // alias for BSI L, or external call + "D" , 0xA800, std_op, ALL, NONE, 0, + "EOR", 0xF000, std_op, ALL, NONE, 0, + "LD", 0xC000, std_op, ALL, NONE, 0, + "LDD", 0xC800, std_op, ALL, NONE, IS_DBL, + "LDS", 0x2000, std_op, NONE, NONE, IS_ABS, + "LDX", 0x6000, std_op, ALL, NONE, IS_ABS|NO_IDX, + "M", 0xA000, std_op, ALL, NONE, 0, + "MDX", 0x7000, mdx_op, ALL, NONE, 0, + "MDM", 0x7000, mdx_op, L, L, 0, // like MDX L + "NOP", 0x1000, std_op, NONE, NONE, NO_ARGS, + "OR", 0xE800, std_op, ALL, NONE, 0, + "S", 0x9000, std_op, ALL, NONE, 0, + "SD", 0x9800, std_op, ALL, NONE, IS_DBL, + "STD", 0xD800, std_op, ALL, NONE, IS_DBL, + "STO", 0xD000, std_op, ALL, NONE, 0, + "STS", 0x2800, std_op, ALL, NONE, 0, + "STX", 0x6800, std_op, ALL, NONE, NO_IDX, + "WAIT", 0x3000, std_op, NONE, NONE, NO_ARGS, + "XCH", 0x18D0, std_op, NONE, NONE, 0, // same as RTE 16, 18C0 + 10 + "XIO", 0x0800, std_op, ALL, NONE, IS_DBL, + + "BSC", 0x4800, bsc_op, ALL, NONE, 0, // branch family + "BOSC", 0x4840, bsc_op, ALL, NONE, 0, // is BOSC always long form? No. + "SKP", 0x4800, bsc_op, NONE, NONE, 0, // alias for BSC one word version + + "B", 0x4800, b_op, ALL, NONE, 0, // alias for MDX or BSC L + "BC", 0x4802, std_op, ALL, L, 0, // alias for BSC L + "BN", 0x4828, std_op, ALL, L, 0, // alias for BSC L + "BNN", 0x4810, std_op, ALL, L, 0, // alias for BSC L + "BNP", 0x4808, std_op, ALL, L, 0, // alias for BSC L + "BNZ", 0x4820, std_op, ALL, L, 0, // alias for BSC L + "BO", 0x4801, std_op, ALL, L, 0, // alias for BSC L + "BOD", 0x4840, std_op, ALL, L, 0, // alias for BSC L + "BP", 0x4830, std_op, ALL, L, 0, // alias for BSC L + "BZ", 0x4818, std_op, ALL, L, 0, // alias for BSC L + + "RTE", 0x18C0, shf_op, IDX X, X, 0, // shift family + "SLA", 0x1000, shf_op, IDX X, X, 0, + "SLC", 0x10C0, shf_op, IDX X, X, 0, + "SLCA", 0x1040, shf_op, IDX X, X, 0, + "SLT", 0x1080, shf_op, IDX X, X, 0, + "SRA", 0x1800, shf_op, IDX X, X, 0, + "SRT", 0x1880, shf_op, IDX X, X, 0, + + "AIF", 0, x_aif, NONE, NONE, 0, // assemble if + "AIFB", 0, x_aifb, NONE, NONE, 0, // assemble if + "AGO", 0, x_ago, NONE, NONE, 0, // assemble goto + "AGOB", 0, x_agob, NONE, NONE, 0, // assemble goto + "ANOP", 0, x_anop, NONE, NONE, 0, // assemble target + + NULL // end of table +}; + +// --------------------------------------------------------------------------------- +// addextn - apply file extension 'extn' to filename 'fname' and put result in 'outbuf' +// if outbuf is NULL, we allocate a buffer +// --------------------------------------------------------------------------------- + +char *addextn (char *fname, char *extn, char *outbuf) +{ + char *buf, line[500], *c; + + buf = (outbuf == NULL) ? line : outbuf; + + strcpy(buf, fname); // create listfn from first source filename (e.g. xxx.lst); + if ((c = strrchr(buf, '\\')) == NULL) + if ((c = strrchr(buf, '/')) == NULL) + if ((c = strrchr(buf, ':')) == NULL) + c = buf; + + if ((c = strrchr(c, '.')) == NULL) + strcat(buf, extn); + else + strcpy(c, extn); + + return (outbuf == NULL) ? astring(line) : outbuf; +} + +// --------------------------------------------------------------------------------- +// controlcard - examine an assembler control card (* in column 1) +// --------------------------------------------------------------------------------- + +BOOL controlcard (char *line) +{ + if (strnicmp(line, "*LIST", 5) == 0) { // turn on listing file even if not specified on command line + do_list = list_on = TRUE; + return TRUE; + } + + if (strnicmp(line, "*XREF", 5) == 0) { + do_xref = TRUE; + return TRUE; + } + + if (strnicmp(line, "*PRINT SYMBOL TABLE", 19) == 0) { + do_syms = TRUE; + return TRUE; + } + + if (strnicmp(line, "*SAVE SYMBOL TABLE", 18) == 0) { + savetable = TRUE; + return TRUE; + } + + if (strnicmp(line, "*SYSTEM SYMBOL TABLE", 20) == 0) { + preload = TRUE; + preload_symbols(); + return TRUE; + } + + return FALSE; +} + +// --------------------------------------------------------------------------------- +// stuff - insert characters into a line +// --------------------------------------------------------------------------------- + +void stuff (char *buf, char *tok, int maxchars) +{ + while (*tok) { + *buf++ = *tok++; + + if (maxchars) + if (--maxchars <= 0) + break; + } +} + +// --------------------------------------------------------------------------------- +// format_line - construct a source code input line from components +// --------------------------------------------------------------------------------- + +void format_line (char *buf, char *label, char *op, char *mods, char *args, char *remarks) +{ + int i; + + if (tabformat) { + sprintf(buf, "%s\t%s\t%s\t%s\t%s", label, op, mods, args, remarks); + } + else { + for (i = 0; i < 72; i++) + buf[i] = ' '; + buf[i] = '\0'; + + stuff(buf+20, label, 5); + stuff(buf+26, op, 4); + stuff(buf+31, mods, 2); + stuff(buf+34, args, 72-34); + } +} + +// --------------------------------------------------------------------------------- +// lookup_op - find an opcode +// --------------------------------------------------------------------------------- + +struct tag_op * lookup_op (char *mnem) +{ + struct tag_op *op; + int i; + + for (op = ops; op->mnem != NULL; op++) { + if ((i = strcmp(op->mnem, mnem)) == 0) + return op; + + if (i > 0) + break; + } + return NULL; +} + +// --------------------------------------------------------------------------------- +// bincard - routines to write IBM 1130 Card object format +// --------------------------------------------------------------------------------- + +unsigned short bincard[54]; // the 54 data words that can fit on a binary format card +char binflag[45]; // the relocation flags of the 45 buffered object words (0, 1, 2, 3) +int bincard_n = 0; // number of object words stored in bincard (0-45) +int bincard_seq = 0; // card output sequence number +int bincard_org = 0; // origin of current card-full +int bincard_maxaddr = 0; +BOOL bincard_first = TRUE; // TRUE when we're to write the program type card + +// bincard_init - prepare a new object data output card + +void bincard_init (void) +{ + memset(bincard, 0, sizeof(bincard)); // clear card data + memset(binflag, 0, sizeof(binflag)); // clear relocation data + bincard_n = 0; // no data + bincard[0] = bincard_org; // store load address + bincard_maxaddr = MAX(bincard_maxaddr, bincard_org-1); // save highest address written-to (this may be a BSS) +} + +// binard_writecard - emit a card. sbrk_text = NULL for normal data cards, points to comment text for sbrk card +// note: sbrk_text if not NULL MUST be a writeable buffer of at LEAST 71 characters + +void bincard_writecard (char *sbrk_text) +{ + unsigned short binout[80]; + char ident[12]; + int i, j; + + if (sbrk_text != NULL) { // sbrk card has 4 binary words followed by comment text + for (j = 66; j < 71; j++) // be sure input columns 67..71 are nonblank (have version number) + if (sbrk_text[j] <= ' ') + break; + + if (j < 71) // sbrk card didn't have the info, stuff in current release + for (j = 0; j < 5; j++) + sbrk_text[66+j] = dmsversion[j]; + + binout[0] = 0; + binout[1] = 0; + binout[2] = 0; + binout[3] = 0x1000; + + sbrk_text += 5; // start at the real column 6 (after *SBRK + for (j = 5; j < 72; j++) + binout[j] = (*sbrk_text) ? ascii_to_hollerith(*sbrk_text++) : 0; + + } + else { // binary card format packs 54 words into 72 columns + for (i = j = 0; i < 54; i += 3, j += 4) { + binout[j ] = ( bincard[i] & 0xFFF0); + binout[j+1] = ((bincard[i] << 12) & 0xF000) | ((bincard[i+1] >> 4) & 0x0FF0); + binout[j+2] = ((bincard[i+1] << 8) & 0xFF00) | ((bincard[i+2] >> 8) & 0x00F0); + binout[j+3] = ((bincard[i+2] << 4) & 0xFFF0); + } + } + + sprintf(ident, "%08ld", ++bincard_seq); // append sequence text + memmove(ident, progname, MIN(strlen(progname), 4)); + + for (i = 0; i < 8; i++) + binout[j++] = ascii_to_hollerith(ident[i]); + + fxwrite(binout, sizeof(binout[0]), 80, fout); // write card image +} + +// binard_writedata - emit an object data card + +void bincard_writedata (void) +{ + unsigned short rflag = 0; + int i, j, nflag = 0; + + bincard[1] = 0; // checksum + bincard[2] = 0x0A00 | bincard_n; // data card type + word count + + for (i = 0, j = 3; i < bincard_n; i++) { // construct relocation indicator bitmap + if (nflag == 8) { + bincard[j++] = rflag; + rflag = 0; + nflag = 0; + } + rflag = (rflag << 2) | (binflag[i] & 3); + nflag++; + } + + if (nflag > 0) + bincard[j] = rflag << (16 - 2*nflag); + + bincard_writecard(FALSE); // emit the card +} + +// bincard_flush - flush any pending binary data + +void bincard_flush (void) +{ + if (bincard_n > 0) + bincard_writedata(); + + bincard_init(); +} + +// bincard_sbrk - emit an SBRK card + +void bincard_sbrk (char *line) +{ + if (bincard_first) + bincard_typecard(); + else + bincard_flush(); + + bincard_writecard(line); +} + +// bincard_setorg - set the origin + +void bincard_setorg (int neworg) +{ + bincard_org = neworg; // set origin for next card + bincard_flush(); // flush any current data & store origin +} + +// bincard_endcard - write end of program card + +void bincard_endcard (void) +{ + bincard_flush(); + + bincard[0] = (bincard_maxaddr + 2) & ~1; // effective length: add 1 to max origin, then 1 more to round up + bincard[1] = 0; + bincard[2] = 0x0F00; + bincard[3] = pta & 0xFFFF; + + bincard_writecard(NULL); +} + +// bincard_typecard - write the program type + +void bincard_typecard (void) +{ + int i; + + if (! bincard_first) + return; + + bincard_first = FALSE; + + memset(bincard, 0, sizeof(bincard)); + + bincard[2] = (unsigned short) ((progtype << 8) | intmode | realmode); + +// all indices not listed are documented as 'reserved' + + switch (progtype) { + case PROGTYPE_ABSOLUTE: + case PROGTYPE_RELOCATABLE: +// bincard[ 4] = 0; // length of common (fortran only) + bincard[ 5] = 0x0003; +// bincard[ 6] = 0; // length of work area (fortran only) + bincard[ 8] = ndefined_files; + namecode(&bincard[9], progname); + bincard[11] = (pta < 0) ? 0 : pta; + break; + + case PROGTYPE_LIBF: + case PROGTYPE_CALL: + bincard[ 5] = 3*nentries; + for (i = 0; i < nentries; i++) { + namecode(&bincard[9+3*i], entry[i]->name); + bincard[11+3*i] = entry[i]->value; + } + break; + + case PROGTYPE_ISSLIBF: + case PROGTYPE_ISSCALL: + bincard[ 5] = 6+nintlevels; + namecode(&bincard[9], entry[0]->name); + bincard[11] = entry[0]->value; + bincard[12] = iss_number + ISTV; // magic number ISTV is 0x33 in DMS R2V12 + bincard[13] = iss_number; + bincard[14] = nintlevels; + bincard[15] = intlevel_primary; + bincard[16] = intlevel_secondary; + bincard[29] = 1; + break; + + case PROGTYPE_ILS: + bincard[ 2] = (unsigned short) (progtype << 8); + bincard[ 5] = 4; + bincard[12] = intlevel_primary; + break; + + default: + bail("in bincard_typecard, can't happen"); + } + + bincard[1] = 0; // checksum + + bincard_writecard(NULL); + + bincard_init(); +} + +// bincard_writew - write a word to the current output card. + +void bincard_writew (int word, RELOC relative) +{ + if (pass != 2) + return; + + if (bincard_first) + bincard_typecard(); + else if (bincard_n >= 45) // flush full card buffer + bincard_flush(); + + binflag[bincard_n] = relative & 3; // store relocation bits and data word + bincard[9+bincard_n++] = word; + + if (relative != LIBF) { + bincard_maxaddr = MAX(bincard_maxaddr, bincard_org); + bincard_org++; + } +} + +// writetwo - notification that we are about to write two words which must stay together + +void writetwo (void) +{ + if (pass == 2 && outmode == OUTMODE_BINARY && bincard_n >= 44) + bincard_flush(); +} + +// handle_sbrk - handle an SBRK directive. +// This was not part of the 1130 assembler; they assembled DMS on a 360 + +void handle_sbrk (char *line) +{ + char rline[90]; + + if (pass != 2) + return; + + strncpy(rline, line, 81); // get a copy and pad it if necessary to 80 characters + rline[80] = '\0'; + while (strlen(rline) < 80) + strcat(rline, " "); + + switch (outmode) { + case OUTMODE_LOAD: + fprintf(fout, "#SBRK%s\n", trim(rline+5)); + + case OUTMODE_BINARY: + bincard_sbrk(rline); + break; + + default: + bail("in handle_sbrk, can't happen"); + } +} + +// --------------------------------------------------------------------------------- +// namecode - turn a string into a two-word packed name +// --------------------------------------------------------------------------------- + +void namecode (unsigned short *words, char *tok) +{ + long val = 0; + int i, ch; + + for (i = 0; i < 5; i++) { // pick up bits + if (*tok) + ch = *tok++; + else + ch = ' '; + + val = (val << 6) | (ascii_to_ebcdic_table[ch] & 0x3F); + } + + words[0] = (unsigned short) (val >> 16); + words[1] = (unsigned short) val; +} + +// --------------------------------------------------------------------------------- +// parse_line - parse one input line. +// --------------------------------------------------------------------------------- + +void parse_line (char *line) +{ + char label[100], mnem[100], arg[200], mods[20], *c; + struct tag_op *op; + + if (line[0] == '/' && line[1] == '/') // job control card? probably best to ignore it + return; + + if (line[0] == '*') { // control card comment or comment in tab-format file + if (check_control) // pay attention to control cards only at top of file + if (! controlcard(line)) + check_control = FALSE; // first non-control card shuts off sensitivity to them + + if (strnicmp(line+1, "SBRK", 4) == 0) + handle_sbrk(line); + + return; + } + + check_control = FALSE; // non-control card, consider them no more + + label[0] = '\0'; // prepare to extract fields + mods[0] = '\0'; + mnem[0] = '\0'; + arg[0] = '\0'; + + if (tabformat || strchr(line, '\t') != NULL) { // if input line has tabs, parse loosely + tabformat = TRUE; // this is a tab-formatted file + + for (c = line; *c && *c <= ' '; c++) // find first nonblank + ; + + if (*c == '*' || ! *c) // ignore as a comment + return; + + tabtok(line, label, 0, NULL); + tabtok(line, mnem, 1, NULL); + tabtok(line, mods, 2, NULL); + tabtok(line, arg, 3, opfield); + } + else { // if no tabs, use strict card-column format + if (line[20] == '*') // comment + return; + + line[72] = '\0'; // clip off sequence + + coltok(line, label, 21, 25, TRUE, NULL); + coltok(line, mnem, 27, 30, TRUE, NULL); + coltok(line, mods, 32, 33, TRUE, NULL); + coltok(line, arg, 35, 72, FALSE, opfield); + } + +// I don't know where I got this idea, but it's wrong... +// if (strchr(mods, '1') || strchr(mods, '2') || strchr(mods, '3')) { // index + X means ignore X +// if ((c = strchr(mods, 'X')) != NULL) +// strcpy(c, c+1); // remove the X +// } + + if (*label) // display org in any line with a label + setw(0, org, FALSE); + + if (! *mnem) { // label w/o mnemonic, just define the symbol + if (*label) + set_symbol(label, org, TRUE, relocate); + return; + } + + if ((op = lookup_op(mnem)) == NULL) { // look up mnemonic + if (*label) + set_symbol(label, org, TRUE, relocate);// at least define the label + + asm_error("Unknown opcode '%s'", mnem); + return; + } + + if (op->flags & TRAP) // assembler debugging breakpoint + x_trap(op, label, mods, arg); + + if (*op->mods_allowed != '\xFF') { // validate modifiers against list of allowed characters + for (c = mods; *c; ) { + if (strchr(op->mods_allowed, *c) == NULL) { + asm_warning("Modifier '%c' not permitted", *c); + strcpy(c, c+1); // remove it and keep parsing + } + else + c++; + } + } + + strcat(mods, op->mods_implied); // tack on implied modifiers + + if (strchr(mods, 'I')) // indirect implies long + strcat(mods, "L"); + + requires_even_address = op->flags & IS_DBL; + + org_advanced = strchr(mods, 'L') ? 2 : 1; // by default, * means address + 1 or 2. Sometimes it doesn't + (op->handler)(op, label, mods, arg); +} + +// --------------------------------------------------------------------------------- +// get one input line from current file or macro +// --------------------------------------------------------------------------------- + +BOOL get_line (char *buf, int nbuf, BOOL onelevel) +{ + char *retval; + + if (ended) // we hit the END command + return FALSE; + + // if macro active, return line from macro buffer, otherwise read from file + // do not pop end-of-macro if onelevel is TRUE + + if ((retval = fgets(buf, nbuf, fin)) == NULL) + return FALSE; + + lno++; // count the line + return TRUE; +} + +// --------------------------------------------------------------------------------- +// proc - process one pass of one source file +// --------------------------------------------------------------------------------- + +void proc (char *fname) +{ + char line[256], *c; + int i; + + if (strchr(fname, '.') == NULL) // if input file has no extension, + addextn(fname, ".asm", curfn); // set appropriate file extension + else + strcpy(curfn, fname); // otherwise use extension specified + +// let's leave filename case alone even if it doesn't matter +//#if (defined(_WIN32) || defined(VMS)) +// upcase(curfn); // only force uppercase of name on Windows and VMS +//#endif + + if (progname[0] == '\0') { // pick up primary filename + if ((c = strrchr(curfn, '\\')) == NULL) + if ((c = strrchr(curfn, '/')) == NULL) + if ((c = strrchr(curfn, ':')) == NULL) + c = curfn; + + strncpy(progname, c, sizeof(progname)); // take name after path + progname[sizeof(progname)-1] = '\0'; + if ((c = strchr(progname, '.')) != NULL)// remove extension + *c = '\0'; + } + + lno = 0; // reset global input line number + ended = FALSE; // have not seen END statement + + if (listfn == NULL) // if list file name is undefined, + listfn = addextn(fname, ".lst", NULL); // create from first filename + + if (verbose) + fprintf(stderr, "--- Starting file %s pass %d\n", curfn, pass); + + if ((fin = fopen(curfn, "r")) == NULL) { + perror(curfn); // oops + exit(1); + } + + if (flist) { // put banner in listing file + strcpy(listline,"=== FILE ======================================================================"); + for (i = 9, c = curfn; *c;) + listline[i++] = *c++; + listline[i] = ' '; + fputs(listline, flist); + putc('\n', flist); + list_on = TRUE; + } + // read all lines till EOF or END statement + while (get_line(line, sizeof(line), FALSE)) { + prep_line(line); // preform standard line prep + parse_line(line); // parse + listout(FALSE); // complete the listing + } + + fclose(fin); + + if (n_literals > 0) { // force out any pending literal constants at end of file + output_literals(TRUE); + listout(FALSE); + } +} + +// --------------------------------------------------------------------------------- +// prep_line - prepare input line for parsing +// --------------------------------------------------------------------------------- + +void prep_line (char *line) +{ + char *c; + + upcase(line); // uppercase it + nwout = 0; // number of words output so far + line_error = FALSE; // no errors on this line so far + + for (c = line; *c; c++) { // truncate at newline + if (*c == '\r' || *c == '\n') { + *c = '\0'; + break; + } + } + + if (flist && list_on) { // construct beginning of listing line + if (tabformat) + sprintf(listline, LINEFORMAT, lno, detab(line)); + else { + if (strlen(line) > 20) // get the part where the commands start + c = line+20; + else + c = ""; + + sprintf(listline, LINEFORMAT, lno, c); + stuff(listline, line, 20); // stuff the left margin in to the left side + } + } +} + +// --------------------------------------------------------------------------------- +// opcmp - operand name comparison routine for qsort +// --------------------------------------------------------------------------------- + +int opcmp (const void *a, const void *b) +{ + return strcmp(((struct tag_op *) a)->mnem, ((struct tag_op *) b)->mnem); +} + +// --------------------------------------------------------------------------------- +// preload_symbols - load a saved symbol table +// --------------------------------------------------------------------------------- + +void preload_symbols (void) +{ + FILE *fd; + char str[200], sym[20]; + int v; + static BOOL preloaded_already = FALSE; + + if (pass > 1 || preloaded_already) + return; + + preloaded_already = TRUE; + + if ((fd = fopen(SYSTEM_TABLE, "r")) == NULL) // read the system symbol tabl + perror(SYSTEM_TABLE); + else { + while (fgets(str, sizeof(str), fd) != NULL) { + if (sscanf(str, "%s %x", sym, &v) == 2) + set_symbol(sym, v, TRUE, FALSE); + } + fclose(fd); + } +} + +// --------------------------------------------------------------------------------- +// save_symbols - save a symbol table +// --------------------------------------------------------------------------------- + +void save_symbols (void) +{ + FILE *fd; + char str[20]; + PSYMBOL s; + + if (relocate) { + fprintf(stderr, "Can't save symbol table unless ABS assembly\n"); + return; + } + + if ((fd = fopen(SYSTEM_TABLE, "r")) != NULL) { + fclose(fd); + if (saveprompt) { + printf("Overwrite system symbol table %s? ", SYSTEM_TABLE); + fgets(str, sizeof(str), stdin); + if (str[0] != 'y' && str[0] != 'Y') + return; + } + unlink(SYSTEM_TABLE); + } + + if ((fd = fopen(SYSTEM_TABLE, "w")) == NULL) { + perror(SYSTEM_TABLE); + return; + } + + for (s = symbols; s != NULL; s = s->next) + fprintf(fd, "%-5s %04x\n", s->name, s->value); + + fclose(fd); +} + +// --------------------------------------------------------------------------------- +// startpass - initialize data structures, prepare to start a pass +// --------------------------------------------------------------------------------- + +void startpass (int n) +{ + int nops; + struct tag_op *p; + + pass = n; // reset globals: pass number + nerrors = 0; // error count + org = 0; // load address (origin) + lno = 0; // input line number + relocate = TRUE; // relocatable assembly mode + assembled = FALSE; // true if any output has been generated + list_on = do_list; // listing enable + dmes_saved = FALSE; // partial character strings output + + n_literals = 0; // literal values pending output + lit_tag = 0; + + if (pass == 1) { // first pass only + for (nops = 0, p = ops; p->mnem != NULL; p++, nops++) // count opcodes + ; + + qsort(ops, nops, sizeof(*p), opcmp); // sort the opcode table + + if (preload) + preload_symbols(); + } + else { // second pass only + if (outfn == NULL) + outfn = addextn(curfn, (outmode == OUTMODE_LOAD) ? ".out" : ".bin" , NULL); + + if ((fout = fopen(outfn, OUTWRITEMODE)) == NULL) { // open output file + perror(outfn); + exit(1); + } + + if (do_list) { // open listing file + if ((flist = fopen(listfn, "w")) == NULL) { + perror(listfn); + exit(1); + } + listhdr(); // print banner + } + } +} + +// --------------------------------------------------------------------------------- +// x_dc - DC define constant directive +// --------------------------------------------------------------------------------- + +void x_dc (struct tag_op *op, char *label, char *mods, char *arg) +{ + EXPR expr; +// char *tok; + + org_advanced = 1; // assume * means this address+1 +// doesn't make sense, but I think I found DMS listings to support it + + if (strchr(mods, 'E') != NULL) // force even address + org_even(); + + setw(0, org, FALSE); // display org in listing line + + if (*label) // define label + set_symbol(label, org, TRUE, relocate); + +// just one!? + getexpr(arg, FALSE, &expr); + writew(expr.value, expr.relative); // store value + + // pick up values, comma delimited +// for (tok = strtok(arg, ","); tok != NULL; tok = strtok(NULL, ",")) { +// getexpr(tok, FALSE, &expr); +// writew(expr.value, expr.relative); // store value +// } +} + +// --------------------------------------------------------------------------------- +// x_dec - DEC define double word constant directive. +// --------------------------------------------------------------------------------- + +// wd[0]: 8 unused bits | characteristic (= exponent+128) +// wd[1]: sign + 15 msb of mantissa in 2's complement +// wd[2]: 16 lsb of mantissa + +// NOTE: these are wrong with Fixed point numbers + +void convert_double_to_extended (double d, unsigned short *wd) +{ + int neg, exp; + unsigned long mantissa; + unsigned char *byte = (unsigned char *) &d; + + if (d == 0.) { + wd[0] = wd[1] = wd[2] = 0; + return; + } + // 7 6 5 4 0 + // d = ansi real*8 SXXX XXXX XXXX MMMM MMMM MMMM MMMM MMMM ... MMMM MMMM + + neg = byte[7] & 0x80; + exp = ((byte[7] & 0x7F) << 4) | ((byte[6] & 0xF0) >> 4); // extract exponent + exp -= 1023; // remove bias + + exp++; // shift to account for implied 1 we added + + // get 32 bits worth of mantissa. add the implied point + mantissa = 0x80000000L | ((byte[6] & 0x0F) << 27) | (byte[5] << 19) | (byte[4] << 11) | (byte[3] << 3) | ((byte[2] & 0xE0) >> 5); + + if (mantissa & (0x80000000L >> 31)) // keep 31 bits, round if necessary + mantissa += (0x80000000L >> 31); + + mantissa >>= (32-31); // get into low 31 bits + + // now turn into IBM 1130 extended precision + + exp += 128; + + if (neg) + mantissa = (unsigned long) (- (long) mantissa); // two's complement + + wd[0] = (unsigned short) (exp & 0xFF); + wd[1] = (unsigned short) ((neg ? 0x8000 : 0) | ((mantissa >> (31-15)) & 0x7FFF)); + wd[2] = (unsigned short) (mantissa & 0xFFFF); +} + +void convert_double_to_standard (double d, unsigned short *wd) +{ + int neg, exp; + unsigned long mantissa; + unsigned char *byte = (unsigned char *) &d; + + if (d == 0.) { + wd[0] = wd[1] = 0; + return; + } + // 7 6 5 4 0 + // d = ansi real*8 SXXX XXXX XXXX MMMM MMMM MMMM MMMM MMMM ... MMMM MMMM + + neg = byte[7] & 0x80; + exp = ((byte[7] & 0x7F) << 4) | ((byte[6] & 0xF0) >> 4); // extract exponent + exp -= 1023; // remove bias + + exp++; // shift to account for implied 1 we added + + // get 32 bits worth of mantissa. add the implied point + mantissa = 0x80000000L | ((byte[6] & 0x0F) << 27) | (byte[5] << 19) | (byte[4] << 11) | (byte[3] << 3) | ((byte[2] & 0xE0) >> 5); + +// if (mantissa & (0x80000000L >> 23)) // keep 23 bits, round if necessary +// mantissa += (0x80000000L >> 23); + +// DEBUG +// printf("%8.4lf: %08lx %d\n", d, mantissa, exp); + + mantissa >>= (32-23); // get into low 23 bits + + // now turn into IBM 1130 standard precision + + exp += 128; + + if (neg) + mantissa = (unsigned long) (- (long) mantissa); // two's complement + + wd[0] = (unsigned short) ((neg ? 0x8000 : 0) | ((mantissa >> (23-15)) & 0x7FFF)); + wd[1] = (unsigned short) ((mantissa & 0x00FF) << 8) | (exp & 0xFF); + +// DEBUG +// printf(" D %04x%04x\n", wd[0], wd[1]); +} + +void convert_double_to_fixed (double d, unsigned short *wd, int bexp) +{ + int neg, exp, rshift; + unsigned long mantissa; + unsigned char *byte = (unsigned char *) &d; + + if (d == 0.) { + wd[0] = wd[1] = 0; + return; + } + // 7 6 5 4 0 + // d = ansi real*8 SXXX XXXX XXXX MMMM MMMM MMMM MMMM MMMM ... MMMM MMMM + + neg = byte[7] & 0x80; + exp = ((byte[7] & 0x7F) << 4) | ((byte[6] & 0xF0) >> 4); // extract exponent + exp -= 1023; // remove bias + + exp++; // shift to account for implied 1 we added + + // get 32 bits worth of mantissa. add the implied point + mantissa = 0x80000000L | ((byte[6] & 0x0F) << 27) | (byte[5] << 19) | (byte[4] << 11) | (byte[3] << 3) | ((byte[2] & 0xE0) >> 5); + + mantissa >>= 1; // shift it out of the sign bit + +// DEBUG +// printf("%8.4lf: %08lx %d\n", d, mantissa, exp); + + rshift = bexp - exp; + + if (rshift > 0) { + mantissa >>= rshift; + } + else if (rshift < 0) { + mantissa >>= (-rshift); + asm_warning("Fixed point overflow"); + } + + if (neg) + mantissa = (unsigned long) (- (long) mantissa); // two's complement + +// DEBUG +// printf(" B %08lx\n", mantissa); + + wd[0] = (unsigned short) ((mantissa >> 16) & 0xFFFF); // return all of the bits; no exponent here + wd[1] = (unsigned short) (mantissa & 0xFFFF); +} + +void getDconstant (char *tok, unsigned short *wd) +{ + unsigned long l; + char *b, *fmt; + double d; + int bexp, fixed; + + wd[0] = 0; + wd[1] = 0; + + if (strchr(tok, '.') == NULL && strchr(tok, 'B') == NULL && strchr(tok, 'E') == NULL) { + fmt = "%ld"; + if (*tok == '/') { // I don't see that this is legal but can't hurt to allow it + fmt = "%lx"; + tok++; + } + if (sscanf(tok, fmt, &l) != 1) { // no decimal means it's an integer? + asm_error("Syntax error in constant"); + } + else { + wd[0] = (unsigned short) ((l >> 16) & 0xFFFF); // high word + wd[1] = (unsigned short) (l & 0xFFFF); // low word + } + return; + } + + fixed = 0; + if ((b = strchr(tok, 'B')) != NULL) { + fixed = 1; + bexp = atoi(b+1); + *b = '\0'; // truncate at the b + } + if (sscanf(tok, "%lg", &d) != 1) { + asm_error("Syntax error in constant"); + return; + } + + if (fixed) + convert_double_to_fixed(d, wd, bexp); + else + convert_double_to_standard(d, wd); +} + +// If the input value is an integer with no decimal point and no B or E, +// DEC generates a double INTEGER value. +// IBM documentation ranges from ambiguous to wrong on this point, but +// examination of the DMS microfiche supports this. + +void x_dec (struct tag_op *op, char *label, char *mods, char *arg) +{ +// char *tok; + unsigned short wd[2]; + + org_advanced = 2; // assume * means address after this location, since it's +1 for dc? + + org_even(); // even address is implied + setw(0, org, FALSE); // display the origin + + if (*label) // define label + set_symbol(label, org, TRUE, relocate); + +// just one!? + getDconstant(arg, wd); + writew(wd[0], FALSE); // write hiword, then loword + writew(wd[1], FALSE); + + // pick up values, comma delimited +// for (tok = strtok(arg, ","); tok != NULL; tok = strtok(NULL, ",")) { +// getDconstant(tok, wd); +// +// writew(wd[0], FALSE); // write hiword, then loword +// writew(wd[1], FALSE); +} + +void x_xflc (struct tag_op *op, char *label, char *mods, char *arg) +{ + char *tok, *b; + double d; + int bexp, fixed; + unsigned short wd[3]; + + org_advanced = 2; // who knows? + + setw(0, org, FALSE); // display the origin + + if (*label) // define label + set_symbol(label, org, TRUE, relocate); + // pick up values, comma delimited + for (tok = strtok(arg, ","); tok != NULL; tok = strtok(NULL, ",")) { + bexp = 0; + if ((b = strchr(tok, 'B')) != NULL) { + bexp = atoi(b+1); + fixed = TRUE; + *b = '\0'; // truncate at the b + asm_warning("Fixed point extended floating constant?"); + } + + if (sscanf(tok, "%lg", &d) != 1) { + asm_error("Syntax error in constant"); + d = 0.; + } + + convert_double_to_extended(d, wd); + + writew(wd[0], ABSOLUTE); + writew(wd[1], ABSOLUTE); + writew(wd[2], ABSOLUTE); + } +} + +// --------------------------------------------------------------------------------- +// x_equ - EQU directive +// --------------------------------------------------------------------------------- + +void x_equ (struct tag_op *op, char *label, char *mods, char *arg) +{ + EXPR expr; + + org_advanced = FALSE; // * means this address, not incremented + + getexpr(arg, FALSE, &expr); + + setw(0, expr.value, expr.relative); // show this as address + + if (*label) // EQU is all about defining labels, better have one + set_symbol(label, expr.value, TRUE, expr.relative); +// else // IBM assembler doesn't complain about this +// asm_error("EQU without label?"); +} + +// --------------------------------------------------------------------------------- +// x_lorg - LORG directive -- output queued literal values +// --------------------------------------------------------------------------------- + +void x_lorg (struct tag_op *op, char *label, char *mods, char *arg) +{ + org_advanced = FALSE; // * means this address (not used, though) + output_literals(FALSE); // generate .DC's for queued literal values +} + +// --------------------------------------------------------------------------------- +// x_abs - ABS directive +// --------------------------------------------------------------------------------- + +void x_abs (struct tag_op *op, char *label, char *mods, char *arg) +{ + if (assembled) + asm_error("ABS must be first statement"); + + relocate = ABSOLUTE; + + switch (progtype) { + case PROGTYPE_ABSOLUTE: + case PROGTYPE_RELOCATABLE: + progtype = PROGTYPE_ABSOLUTE; // change program type, still assumed to be mainline + break; + + case PROGTYPE_LIBF: + case PROGTYPE_CALL: + case PROGTYPE_ISSLIBF: + case PROGTYPE_ISSCALL: + case PROGTYPE_ILS: + asm_error("ABS not allowed with LIBF, ENT, ILS or ISS"); + break; + + default: + bail("in x_libr, can't happen"); + } +} + +// --------------------------------------------------------------------------------- +// x_call - ORG pseudo-op +// --------------------------------------------------------------------------------- + +void x_call (struct tag_op *op, char *label, char *mods, char *arg) +{ + unsigned short words[2]; + static struct tag_op *bsi = NULL; + + if (*label) // define label + set_symbol(label, org, TRUE, relocate); + + if (! *arg) { + asm_error("CALL missing argument"); + return; + } + + if (pass == 1) { // it will take two words in any case + org += 2; + return; + } + + setw(0, org, FALSE); // display origin + + if (lookup_symbol(arg, FALSE) != NULL) { // it's a defined symbol? + if (bsi == NULL) + if ((bsi = lookup_op("BSI")) == NULL) + bail("Can't find BSI op"); + + (bsi->handler)(bsi, "", "L", arg); + } + else { + namecode(words, arg); // emit namecode for loader + + writetwo(); + writew(words[0], CALL); + writew(words[1], ABSOLUTE); + } +} + +// --------------------------------------------------------------------------------- +// x_org - ORG directive +// --------------------------------------------------------------------------------- + +void x_org (struct tag_op *op, char *label, char *mods, char *arg) +{ + EXPR expr; + + org_advanced = FALSE; // * means this address + + if (*label) // label is defined BEFORE the new origin is set!!! + set_symbol(label, org, TRUE, relocate); + + if (getexpr(arg, FALSE, &expr) != S_DEFINED) + return; + + setorg(expr.value); // set origin to this value +} + +// --------------------------------------------------------------------------------- +// x_end - END directive +// --------------------------------------------------------------------------------- + +void x_end (struct tag_op *op, char *label, char *mods, char *arg) +{ + EXPR expr; + + org_advanced = FALSE; // * means this address + + if (*arg) { // they're specifing the program start address + if (getexpr(arg, FALSE, &expr) == S_DEFINED) + pta = expr.value; + } + + if (*label) // define label + set_symbol(label, org, TRUE, relocate); + + setw(0, org, FALSE); // display origin + + ended = TRUE; // assembly is done, stop reading file +} + +// --------------------------------------------------------------------------------- +// x_ent - ENT op +// --------------------------------------------------------------------------------- + +void x_ent (struct tag_op *op, char *label, char *mods, char *arg) +{ + PSYMBOL s; + + org_advanced = FALSE; // * means this address + + if (pass < 2) + return; + +// if (*label) // define label +// set_symbol(label, org, TRUE, relocate); +// +// setw(0, org, FALSE); // display origin + + if (! *arg) + asm_error("No entry label specified"); + + else if ((s = lookup_symbol(arg, FALSE)) == NULL) + asm_error("Entry symbol %s not defined", arg); + + else if (nentries >= MAXENTRIES) + asm_error("Too many entries, limit is %d", MAXENTRIES); + + else + entry[nentries++] = s; // save symbol pointer + + switch (progtype) { + case PROGTYPE_ABSOLUTE: + asm_error("ENT not allowed with ABS"); + break; + case PROGTYPE_RELOCATABLE: + progtype = PROGTYPE_CALL; + break; + case PROGTYPE_LIBF: + case PROGTYPE_CALL: + case PROGTYPE_ISSLIBF: + case PROGTYPE_ISSCALL: + break; + case PROGTYPE_ILS: + asm_error("Can't mix ENT and ILS, can you?"); + break; + default: + bail("in x_libr, can't happen"); + } +} + +// --------------------------------------------------------------------------------- +// declare a libf-type subprogram +// --------------------------------------------------------------------------------- + +void x_libr (struct tag_op *op, char *label, char *mods, char *arg) +{ + switch (progtype) { + case PROGTYPE_ABSOLUTE: + asm_error("LIBR not allowed with ABS"); + break; + case PROGTYPE_RELOCATABLE: + case PROGTYPE_LIBF: + case PROGTYPE_CALL: + progtype = PROGTYPE_LIBF; + break; + case PROGTYPE_ISSLIBF: + case PROGTYPE_ISSCALL: + progtype = PROGTYPE_ISSLIBF; + break; + case PROGTYPE_ILS: + asm_error("Can't use LIBR in an ILS"); + break; + default: + bail("in x_libr, can't happen"); + } +} + +// --------------------------------------------------------------------------------- +// x_ils - ILS directive +// --------------------------------------------------------------------------------- + +void x_ils (struct tag_op *op, char *label, char *mods, char *arg) +{ + switch (progtype) { + case PROGTYPE_ABSOLUTE: + asm_error("ILS not allowed with ABS"); + break; + case PROGTYPE_RELOCATABLE: + case PROGTYPE_ILS: + progtype = PROGTYPE_ILS; + break; + case PROGTYPE_LIBF: + case PROGTYPE_CALL: + asm_error("Invalid placement of ILS"); + break; + case PROGTYPE_ISSLIBF: + case PROGTYPE_ISSCALL: + break; + default: + bail("in x_libr, can't happen"); + } + + intlevel_primary = atoi(mods); +} + +// --------------------------------------------------------------------------------- +// x_iss - ISS directive +// --------------------------------------------------------------------------------- + +void x_iss (struct tag_op *op, char *label, char *mods, char *arg) +{ + char *tok; + + switch (progtype) { + case PROGTYPE_ABSOLUTE: + asm_error("ISS not allowed with ABS"); + break; + case PROGTYPE_RELOCATABLE: + case PROGTYPE_CALL: + case PROGTYPE_ISSCALL: + progtype = PROGTYPE_ISSCALL; + break; + case PROGTYPE_LIBF: + case PROGTYPE_ISSLIBF: + progtype = PROGTYPE_ISSLIBF; + break; + case PROGTYPE_ILS: + asm_error("Can't mix ISS and ILS"); + default: + bail("in x_libr, can't happen"); + } + + iss_number = atoi(mods); // get ISS number + + opfield[16] = '\0'; // be sure not to look too far into this + + nintlevels = 0; // # of interrupt levels for ISS + intlevel_primary = 0; // primary level for ISS and level for ILS + intlevel_secondary = 0; // secondary level for ISS + + if ((tok = strtok(opfield, " ")) == NULL) + asm_error("ISS missing entry label"); + else + x_ent(NULL, label, "", arg); // process as an ENT + + if ((tok = strtok(NULL, " ")) != NULL) { // get associated levels + nintlevels++; + intlevel_primary = atoi(tok); + } + + if ((tok = strtok(NULL, " ")) != NULL) { + nintlevels++; + intlevel_secondary = atoi(tok); + } +} + +void x_spr (struct tag_op *op, char *label, char *mods, char *arg) +{ + realmode = REALMODE_STANDARD; +} + +void x_epr (struct tag_op *op, char *label, char *mods, char *arg) +{ + realmode = REALMODE_EXTENDED; +} + +void x_dsa (struct tag_op *op, char *label, char *mods, char *arg) +{ + unsigned short words[2]; + + setw(0, org, FALSE); // display origin + + if (*label) // define label + set_symbol(label, org, TRUE, relocate); + + if (! *arg) { + asm_error("DSA missing filename"); + } + else { + namecode(words, arg); + writetwo(); + writew(words[0], CALL); // special relocation bits here 3 and 1 + writew(words[1], RELATIVE); + } +} + +void x_link (struct tag_op *op, char *label, char *mods, char *arg) +{ + unsigned short words[2]; + char nline[128]; + + setw(0, org, FALSE); // display origin + + if (*label) // define label + set_symbol(label, org, TRUE, relocate); + + if (! *arg) { + asm_error("LINK missing program name"); + } + else { + format_line(nline, label, "CALL", "", "$LINK", ""); + parse_line(nline); + + namecode(words, arg); + writew(words[0], ABSOLUTE); // special relocation bits here 3 and 1 + writew(words[1], ABSOLUTE); + } +} + +void x_libf (struct tag_op *op, char *label, char *mods, char *arg) +{ + unsigned short words[2]; + + if (*label) // define label + set_symbol(label, org, TRUE, relocate); + + if (! *arg) { + asm_error("LIBF missing argument"); + return; + } + + if (pass == 1) { // it will take one words in any case + org++; + return; + } + + setw(0, org, FALSE); // display origin + + namecode(words, arg); // emit namecode for loader + + writetwo(); + writew(words[0], LIBF); // this one does NOT advance org! + writew(words[1], ABSOLUTE); +} + +void x_file (struct tag_op *op, char *label, char *mods, char *arg) +{ + int i, n, r; + EXPR vals[5]; + char *tok; + + for (i = 0; i < 5; i++) { + if ((tok = strtok(arg, ",")) == NULL) { + asm_error("FILE has insufficient arguments"); + return; + } + arg = NULL; // for next strtok call + + if (i == 3) { + if (strcmpi(tok, "U") != 0) + asm_error("Argument 4 must be the letter U"); + } + else if (getexpr(tok, FALSE, &vals[i]) == S_DEFINED) { + if (i <= 3 && vals[i].relative) + asm_error("Argument %d must be absolute", i+1); + else if (pass == 2 && vals[i].value == 0) + asm_error("Argument %d must be nonzero", i+1); + } + } + + writew(vals[0].value, ABSOLUTE); + writew(vals[1].value, ABSOLUTE); + writew(vals[2].value, ABSOLUTE); + writew(vals[4].value, vals[i].relative); + writew(0, ABSOLUTE); + n = MAX(1, vals[2].value); + r = 320/n; + writew(r, ABSOLUTE); + r = MAX(1, r); + writew((16*vals[1].value)/r, ABSOLUTE); + + if (pass == 2) + ndefined_files++; +} + +// --------------------------------------------------------------------------------- +// x_trap - place to set a breakpoint +// --------------------------------------------------------------------------------- + +void x_trap (struct tag_op *op, char *label, char *mods, char *arg) +{ + // debugging breakpoint +} + +// --------------------------------------------------------------------------------- +// x_ces - .CES directive (nonstandard). Specify a value for the console entry +// switches. When this program is loaded into the simulator, the switches will +// be set accordingly. Handy for bootstraps and other programs that read +// the switches. +// --------------------------------------------------------------------------------- + +void x_ces (struct tag_op *op, char *label, char *mods, char *arg) +{ + EXPR expr; + + if (outmode != OUTMODE_LOAD) // this works only in our loader format + return; + + if (getexpr(arg, FALSE, &expr) != S_DEFINED) + return; + + if (pass == 2) + fprintf(fout, "S%04x" ENDLINE, expr.value & 0xFFFF); +} + +// --------------------------------------------------------------------------------- +// x_bss - BSS directive - reserve space in core +// --------------------------------------------------------------------------------- + +void x_bss (struct tag_op *op, char *label, char *mods, char *arg) +{ + EXPR expr; + + org_advanced = FALSE; // * means this address + + if (! *arg) { + expr.value = 0; + expr.relative = ABSOLUTE; + } + else if (getexpr(arg, FALSE, &expr) != S_DEFINED) + return; + + if (strchr(mods, 'E') != NULL) // force even address + org_even(); + + if (expr.relative) + asm_error("BSS size must be an absolute value"); + + setw(0, org, FALSE); // display origin + + if (*label) // define label + set_symbol(label, org, TRUE, relocate); + + if (expr.value < 0) + asm_warning("Negative BSS size"); + + else if (expr.value > 0) { + if (outmode == OUTMODE_LOAD) { + org += expr.value; // advance the origin by appropriate number of words + if (pass == 2) // emit new load address in output file + fprintf(fout, "@%04x%s" ENDLINE, org & 0xFFFF, relocate ? "R" : ""); + } + else { + org += expr.value; // advance the origin by appropriate number of words + if (pass == 2) + bincard_setorg(org); + } + } +} + +// --------------------------------------------------------------------------------- +// x_bes - Block Ended by Symbol directive. Like BSS but label gets address AFTER the space, instead of first address +// --------------------------------------------------------------------------------- + +void x_bes (struct tag_op *op, char *label, char *mods, char *arg) +{ + EXPR expr; + + org_advanced = FALSE; // * means this address + + if (! *arg) { // arg field = space + expr.value = 0; + expr.relative = ABSOLUTE; + } + else if (getexpr(arg, FALSE, &expr) != S_DEFINED) + return; + + if (strchr(mods, 'E') != NULL && (org & 1) != 0) + org_even(); // force even address + + if (expr.relative) + asm_error("BES size must be an absolute value"); + + if (expr.value < 0) + asm_warning("Negative BES size"); + + else if (expr.value > 0) { + setw(0, org+expr.value, FALSE); // display NEW origin + + if (outmode == OUTMODE_LOAD) { + org += expr.value; // advance the origin + if (pass == 2) // emit new load address in output file + fprintf(fout, "@%04x%s" ENDLINE, org & 0xFFFF, relocate ? "R" : ""); + } + else { + org += expr.value; // advance the origin + bincard_setorg(org); + } + } + + if (*label) // NOW define the label + set_symbol(label, org, TRUE, relocate); +} + +// --------------------------------------------------------------------------------- +// x_dmes - DMES define message directive. Various encodings, none pretty. +// --------------------------------------------------------------------------------- + +int dmes_wd; +int dmes_nc; +enum {CODESET_CONSOLE, CODESET_1403, CODESET_1132, CODESET_EBCDIC} dmes_cs; +void stuff_dmes (int ch, int rpt); + +void x_dmes (struct tag_op *op, char *label, char *mods, char *arg) +{ + int rpt; + char *c = opfield; + BOOL cont = FALSE; + + if (dmes_saved) { // previous DMES had an odd character saved + dmes_wd = dmes_savew; + dmes_nc = 1; // stick it into the outbut buffer + } + else + dmes_nc = dmes_wd = 0; // clear output buffer + + trim(opfield); // remove trailing blanks from rest of input line (use whole thing) + setw(0, org, FALSE); // display origin + + if (*label) // define label + set_symbol(label, org, TRUE, relocate); + + if (strchr(mods, '1') != NULL) // determine the encoding scheme + dmes_cs = CODESET_1403; + else if (strchr(mods, '2') != NULL) + dmes_cs = CODESET_1132; + else if (strchr(mods, '0') != NULL || ! *mods) + dmes_cs = CODESET_CONSOLE; + else { + asm_error("Invalid printer code in tag field"); + dmes_cs = CODESET_EBCDIC; + } + + while (*c) { // pick up characters + if (*c == '\'') { // quote (') is the escape character + c++; + + rpt = 0; // get repeat count + while (BETWEEN(*c, '0', '9')) { + rpt = rpt*10 + *c++ - '0'; + } + if (rpt <= 0) // no count = insert one copy + rpt = 1; + + switch (*c) { // handle escape codes + case '\'': + stuff_dmes(*c, 1); + break; + + case 'E': + *c = '\0'; // end + break; + + case 'X': + case 'S': + stuff_dmes(' ', rpt); + break; + + case 'F': + stuff_dmes(*++c, rpt); // repeat character + break; + + case ' ': + case '\0': + cont = TRUE; + *c = '\0'; // end + break; + + case 'T': + if (dmes_cs != CODESET_CONSOLE) { +badcode: asm_error("Invalid ' escape for selected printer"); + break; + } + stuff_dmes(0x41, -rpt); // tab + break; + + case 'D': + if (dmes_cs != CODESET_CONSOLE) goto badcode; + stuff_dmes(0x11, -rpt); // backspace + break; + + case 'B': + if (dmes_cs != CODESET_CONSOLE) goto badcode; + stuff_dmes(0x05, -rpt); // black + break; + + case 'A': + if (dmes_cs != CODESET_CONSOLE) goto badcode; + stuff_dmes(0x09, -rpt); // red + break; + + case 'R': + if (dmes_cs != CODESET_CONSOLE) goto badcode; + stuff_dmes(0x81, -rpt); // return + break; + + case 'L': + if (dmes_cs != CODESET_CONSOLE) goto badcode; + stuff_dmes(0x03, -rpt); // line feed + break; + + default: + asm_error("Invalid ' escape in DMES"); + *c = '\0'; + break; + } + } + else // just copy literal character + stuff_dmes(*c, 1); + + if (*c) + c++; + } + + dmes_saved = FALSE; + + if (dmes_nc) { // odd number of characters + if (cont) { + dmes_saved = TRUE; + dmes_savew = dmes_wd; // save for next time + } + else + stuff_dmes(' ', 1); // pad with a space to force out even # of characters + } +} + +// --------------------------------------------------------------------------------- +// stuff_dmes - insert 'rpt' copies of character 'ch' into output words +// --------------------------------------------------------------------------------- + +void stuff_dmes (int ch, int rpt) +{ + int nch, i; // nch is translated output value + + if (rpt < 0) { // negative repeat means no translation needed + rpt = -rpt; + nch = ch; + } + else { + switch (dmes_cs) { + case CODESET_CONSOLE: + nch = 0x21; + for (i = 0; i < 256; i++) { + if (conout_to_ascii[i] == ch) { + nch = i; + break; + } + } + break; + + case CODESET_EBCDIC: + nch = ascii_to_ebcdic_table[ch & 0x7F]; + if (nch == 0) + nch = 0x7F; + break; + + case CODESET_1403: + nch = ascii_to_1403_table[ch & 0x7F]; + if (nch == 0) + nch = 0x7F; + break; + + case CODESET_1132: + nch = 0x40; + for (i = 0; i < WHEELCHARS_1132; i++) { + if (codewheel1132[i].ascii == ch) { + nch = codewheel1132[i].ebcdic; + break; + } + } + break; + + default: + bail("bad cs in x_dmes, can't happen"); + break; + } + } + + while (--rpt >= 0) { // pack them into words, output when we have two + if (dmes_nc == 0) { + dmes_wd = (nch & 0xFF) << 8; + dmes_nc = 1; + } + else { + dmes_wd |= (nch & 0xFF); + writew(dmes_wd, FALSE); + dmes_nc = 0; + } + } +} + +// --------------------------------------------------------------------------------- +// x_ebc - handle EBCDIC string definition (delimited with periods) +// --------------------------------------------------------------------------------- + +void x_ebc (struct tag_op *op, char *label, char *mods, char *arg) +{ + char *p; + +// setw(0, org, FALSE); + if (*label) + set_symbol(label, org, TRUE, relocate); + + p = trim(opfield); // remove trailing blanks from rest of input line (use whole thing) + + if (*p != '.') { + asm_error("EBC data must start with ."); + return; + } + p++; // skip leading period + + dmes_nc = dmes_wd = 0; // clear output buffer (we're borrowing the DMES packer) + dmes_cs = CODESET_EBCDIC; + + while (*p && *p != '.') // store packed ebcdic + stuff_dmes(*p++, 1); + + if (dmes_nc) // odd number of characters + stuff_dmes(' ', 1); // pad with a space to force out even # of characters + + if (*p != '.') + asm_error("EBC missing closing ."); +} + +// --------------------------------------------------------------------------------- +// x_dn - define name DN directive. Pack 5 characters into two words. This by the +// way is the reason the language Forth is not Fourth. +// --------------------------------------------------------------------------------- + +void x_dn (struct tag_op *op, char *label, char *mods, char *arg) +{ + unsigned short words[2]; + + setw(0, org, FALSE); // display origin + + if (*label) // define label + set_symbol(label, org, TRUE, relocate); + + namecode(words, arg); + + writew(words[0], ABSOLUTE); + writew(words[1], ABSOLUTE); +} + +// --------------------------------------------------------------------------------- +// x_dump - DUMP directive - pretend we saw "call $dump, call $exit" +// --------------------------------------------------------------------------------- + +void x_dump (struct tag_op *op, char *label, char *mods, char *arg) +{ + x_pdmp(op, label, mods, arg); + x_exit(NULL, "", "", ""); // compile "call $exit" +} + +// --------------------------------------------------------------------------------- +// x_pdmp - PDMP directive - like DUMP but without the call $exit +// --------------------------------------------------------------------------------- + +void x_pdmp (struct tag_op *op, char *label, char *mods, char *arg) +{ + char nline[200], *tok; + EXPR addr[3]; + int i; + + for (i = 0, tok = strtok(arg, ","); i < 3 && tok != NULL; i++, tok = strtok(NULL, ",")) { + if (getexpr(tok, FALSE, addr+i) != S_DEFINED) { + addr[i].value = (i == 1) ? 0x3FFF : 0; + addr[i].relative = ABSOLUTE; + } + } + + org_advanced = FALSE; // * means this address+1 + + format_line(nline, label, "BSI", "L", DOLLARDUMP, ""); + parse_line(nline); // compile "call $dump" + + writew(addr[2].value, ABSOLUTE); // append arguments (0, start, end address) + writew(addr[0].value, addr[0].relative); + writew(addr[1].value, addr[1].relative); +} + +// --------------------------------------------------------------------------------- +// x_hdng - HDNG directive +// --------------------------------------------------------------------------------- + +void x_hdng (struct tag_op *op, char *label, char *mods, char *arg) +{ + char *c; + + // label is not entered into the symbol table + + if (flist == NULL || ! list_on) { + line_error = TRUE; // inhibit listing: don't print the HDNG statement + return; + } + + line_error = TRUE; // don't print the statement + + c = skipbl(opfield); + trim(c); + fprintf(flist, "\f%s\n\n", c); // print page header +} + +// --------------------------------------------------------------------------------- +// x_list - LIST directive. enable or disable listing +// --------------------------------------------------------------------------------- + +void x_list (struct tag_op *op, char *label, char *mods, char *arg) +{ + BOOL on; + + // label is not entered into the symbol table + + line_error = TRUE; // don't print the LIST statement + + if (flist == NULL || ! list_on) { + return; + } + + if (strcmpi(arg, "ON") == 0) + on = TRUE; + else if (strcmpi(arg, "OFF") == 0) + on = FALSE; + else + on = do_list; + + list_on = on; +} + +// --------------------------------------------------------------------------------- +// x_spac - SPAC directive. Put blank lines in listing +// --------------------------------------------------------------------------------- + +void x_spac (struct tag_op *op, char *label, char *mods, char *arg) +{ + EXPR expr; + + // label is not entered into the symbol table + + if (flist == NULL || ! list_on) { + line_error = TRUE; // don't print the SPAC statement + return; + } + + if (getexpr(arg, FALSE, &expr) != S_DEFINED) + return; + + line_error = TRUE; // don't print the statement + + while (--expr.value >= 0) + putc('\n', flist); +} + +// --------------------------------------------------------------------------------- +// x_ejct - EJCT directive - put formfeed in listing +// --------------------------------------------------------------------------------- + +void x_ejct (struct tag_op *op, char *label, char *mods, char *arg) +{ + // label is not entered into the symbol table + + if (flist == NULL || ! list_on) { + line_error = TRUE; // don't print the EJCT statement + return; + } + + line_error = TRUE; // don't print the statement + + putc('\f', flist); +} + +// --------------------------------------------------------------------------------- +// basic_opcode - construct a standard opcode value from op table entry and modifier chars +// --------------------------------------------------------------------------------- + +int basic_opcode (struct tag_op *op, char *mods) +{ + int opcode = op->opcode; // basic code value + + if (strchr(mods, '1') != 0) // indexing + opcode |= 0x0100; + else if (strchr(mods, '2') != 0) + opcode |= 0x0200; + else if (strchr(mods, '3') != 0) + opcode |= 0x0300; + + if (strchr(mods, 'L')) { // two-word format + opcode |= OP_LONG; + if (strchr(mods, 'I') != 0) // and indirect to boot + opcode |= OP_INDIRECT; + } + + return opcode; +} + +// --------------------------------------------------------------------------------- +// std_op - assemble a vanilla opcode +// --------------------------------------------------------------------------------- + +void std_op (struct tag_op *op, char *label, char *mods, char *arg) +{ + EXPR expr; + int opcode = basic_opcode(op, mods); + BOOL val_ok = FALSE; + + if (*label) // define label + set_symbol(label, org, TRUE, relocate); + + if (*arg && ! (op->flags & NO_ARGS)) { // get value argument + if (getexpr(arg, FALSE, &expr) == S_DEFINED) + val_ok = TRUE; + } + else { + expr.value = 0; + expr.relative = FALSE; + } + + if (opcode & OP_LONG) { // two-word format, just write code and value + writew(opcode, FALSE); + writew(expr.value, expr.relative); + } + else { // one-word format + if (strchr(mods, 'I') != 0) + asm_error("Indirect mode not permitted on one-word instructions"); + + if (val_ok && ! (strchr(mods, 'X') || (op->flags & IS_ABS) || ((opcode & OP_INDEXED) && ! (op->flags & NO_IDX)))) + expr.value -= (org+1); // compute displacement + + if (expr.value < -128 || expr.value > 127) {// check range + asm_error("Offset of %d is too large", expr.value); + expr.value = 0; + } + + writew(opcode | (expr.value & 0x00FF), FALSE);// that's the code + } +} + +// --------------------------------------------------------------------------------- +// mdx_op - assemble a MDX family instruction +// --------------------------------------------------------------------------------- + +void mdx_op (struct tag_op *op, char *label, char *mods, char *arg) +{ + EXPR dest, incr = {0, FALSE}; + int opcode = basic_opcode(op, mods); + char *tok; + + if (*label) // define label + set_symbol(label, org, TRUE, relocate); + + if ((tok = strtok(arg, ",")) == NULL) { // argument format is dest[,increment] +// asm_error("Destination not specified"); // seems not to be an error, IBM omits it sometimes + dest.value = 0; + dest.relative = ABSOLUTE; + } + else + getexpr(tok, FALSE, &dest); // parse the address + + tok = strtok(NULL, ","); // look for second argument + + if (opcode & OP_LONG) { // two word format + if (opcode & OP_INDEXED) { // format: MDX 2 dest + if (tok != NULL) + asm_error("This format takes only one argument"); + } + else { // format: MDX dest,increment + if (opcode & OP_INDIRECT) + asm_error("Indirect can't be used without indexing"); + + if (tok == NULL) { +// asm_error("This format takes two arguments"); + incr.value = 0; + incr.relative = ABSOLUTE; + } + else + getexpr(tok, FALSE, &incr); + + if (incr.value < -128 || incr.value > 127) // displacement style (fixed in ver 1.08) + asm_error("Invalid increment value (8 bits signed)"); + + opcode |= (incr.value & 0xFF); + } + + writew(opcode, ABSOLUTE); + writew(dest.value, dest.relative); + } + else { // one word format MDX val + if (tok != NULL) + asm_error("This format takes only one argument"); + + if (! (strchr(mods, 'X') || (opcode & OP_INDEXED))) + dest.value -= (org+1); // compute displacement + + if (dest.value < -128 || dest.value > 127) + asm_error("Offset/Increment of %d is too large", dest.value); + + writew(opcode | (dest.value & 0xFF), FALSE); + } +} + +// --------------------------------------------------------------------------------- +// bsi_op - BSI long instruction is like a BSC L, short is standard +// --------------------------------------------------------------------------------- + +void bsi_op (struct tag_op *op, char *label, char *mods, char *arg) +{ + if (strchr(mods, 'L') || strchr(mods, 'I')) + bsc_op(op, label, mods, arg); + else + std_op(op, label, mods, arg); +} + +// --------------------------------------------------------------------------------- +// b_op - branch; use short or long version +// -------------------------------------------------------------------------------- + +void b_op (struct tag_op *op, char *label, char *mods, char *arg) +{ + static struct tag_op *mdx = NULL; + + if (strchr(mods, 'L') || strchr(mods, 'I')) { + bsi_op(op, label, mods, arg); + return; + } + + if (mdx == NULL) + if ((mdx = lookup_op("MDX")) == NULL) + bail("Can't find MDX op"); + + (mdx->handler)(mdx, label, mods, arg); +} + +// --------------------------------------------------------------------------------- +// bsc_op - compute a BSC family instruction +// --------------------------------------------------------------------------------- + +void bsc_op (struct tag_op *op, char *label, char *mods, char *arg) +{ + EXPR dest; + int opcode = basic_opcode(op, mods); + char *tok, *tests; + + if (*label) // define label + set_symbol(label, org, TRUE, relocate); + + if (opcode & OP_LONG) { // two word format + if ((tok = strtok(arg, ",")) == NULL) { // format is BSC dest[,tests] + asm_error("Destination not specified"); + dest.value = 0; + dest.relative = ABSOLUTE; + } + else + getexpr(tok, FALSE, &dest); + + tests = strtok(NULL, ","); // get test characters + } + else + tests = arg; // short format is BSC tests + + if (tests != NULL) { // stick in the testing bits + for (; *tests; tests++) { + switch (*tests) { + // bit 0x40 is the BOSC bit + case 'Z': opcode |= 0x20; break; + case '-': opcode |= 0x10; break; + case '+': + case '&': opcode |= 0x08; break; + case 'E': opcode |= 0x04; break; + case 'C': opcode |= 0x02; break; + case 'O': opcode |= 0x01; break; + default: + asm_error("Invalid test flag: '%c'", *tests); + } + } + } + + writew(opcode, ABSOLUTE); // emit code + if (opcode & OP_LONG) + writew(dest.value, dest.relative); +} + +// --------------------------------------------------------------------------------- +// shf_op - assemble a shift instruction +// --------------------------------------------------------------------------------- + +void shf_op (struct tag_op *op, char *label, char *mods, char *arg) +{ + EXPR expr; + int opcode = basic_opcode(op, mods); + + if (*label) // define label + set_symbol(label, org, TRUE, relocate); + + if (opcode & OP_INDEXED) { // shift value comes from index register + expr.value = 0; + expr.relative = ABSOLUTE; + } + else + getexpr(arg, FALSE, &expr); + + if (expr.relative) { + asm_error("Shift value is a relative address"); + expr.relative = ABSOLUTE; + } + + if (expr.value < 0 || expr.value > 32) { // check range + asm_error("Shift count of %d is invalid", expr.value); + expr.value = 0; + } + + writew(opcode | (expr.value & 0x3F), FALSE); // put shift count into displacement field +} + +// --------------------------------------------------------------------------------- +// x_mdm - MDM instruction +// --------------------------------------------------------------------------------- + +void x_mdm (struct tag_op *op, char *label, char *mods, char *arg) +{ + int opcode = basic_opcode(op, mods); + + if (*label) // define label + set_symbol(label, org, TRUE, relocate); + // oh dear: bug here + asm_error("'%s' is not yet supported", op->mnem); +} + +// --------------------------------------------------------------------------------- +// x_exit - EXIT directive. Assembler manual says it treats like CALL $EXIT, but +// object code reveals the truth: jump to $EXIT, which is a small value, so we can use LDX. +// --------------------------------------------------------------------------------- + +void x_exit (struct tag_op *op, char *label, char *mods, char *arg) +{ + char nline[120]; + + format_line(nline, label, "LDX", "X", DOLLAREXIT, ""); + parse_line(nline); +} + +// --------------------------------------------------------------------------------- +// x_opt - .OPT directive. Nonstandard. Possible values: +// +// .OPT CEXPR - use C precedence in evaluating expressions rather than strict left-right +// --------------------------------------------------------------------------------- + +void x_opt (struct tag_op *op, char *label, char *mods, char *arg) +{ + char *tok; + + org_advanced = FALSE; // * means this address + + if (*label) { + asm_error("Label not permitted on .OPT statement"); + return; + } + // look for OPT arguments + for (tok = strtok(arg, ","); tok != NULL; tok = strtok(NULL, ",")) { + if (strcmp(tok, "CEXPR") == 0) { + cexpr = TRUE; // use C expression precedence (untested) + } + else + asm_error("Unknown .OPT: '%s'", tok); + } +} + +// --------------------------------------------------------------------------------- +// askip - skip input lines until a line with the target label appears +// --------------------------------------------------------------------------------- + +void askip (char *target) +{ + char nline[200], cur_label[20], *c; + + while (get_line(nline, sizeof(nline), TRUE)) { // read next line (but don't exit a macro) + listout(FALSE); // end listing of previous input line + + prep_line(nline); // preform standard line prep + + strncpy(cur_label, nline, 6); // get first 5 characters + cur_label[5] = '\0'; + + for (c = cur_label; *c > ' '; c++) // truncate at first whitespace + ; + *c = '\0'; + // stop if there's a match + if ((target == NULL) ? (cur_label[0] == '\0') : strcmp(target, cur_label) == 0) { + parse_line(nline); // process this line + return; + } + } + + if (target != NULL) + asm_error("Label %s not found", target); +} + +// --------------------------------------------------------------------------------- +// x_aif - process conditional assembly jump +// --------------------------------------------------------------------------------- + +void x_aif (struct tag_op *op, char *label, char *mods, char *arg) +{ + char *target, *tok; + EXPR expr1, expr2; + BOOL istrue; + enum {OP_EQ, OP_LT, OP_GT, OP_NE, OP_LE, OP_GE} cmp_op; + + // label is not entered into the symbol table + + arg = skipbl(arg); + if (*arg != '(') { + asm_error("AIF operand must start with ("); + return; + } + + arg++; // skip the paren + + // normally whitespace is never found in the arg string (see tabtok and coltok). + // However, spaces inside parens are permitted. + + if ((tok = strtok(arg, whitespace)) == NULL) { + asm_error("AIF missing first expression"); + return; + } + + getexpr(tok, FALSE, &expr1); + + if ((tok = strtok(NULL, whitespace)) == NULL) { + asm_error("AIF missing conditional operator"); + return; + } + + if (strcmp(tok, "EQ") == 0) + cmp_op = OP_EQ; + else if (strcmp(tok, "LT") == 0) + cmp_op = OP_LT; + else if (strcmp(tok, "GT") == 0) + cmp_op = OP_GT; + else if (strcmp(tok, "NE") == 0) + cmp_op = OP_NE; + else if (strcmp(tok, "LE") == 0) + cmp_op = OP_LE; + else if (strcmp(tok, "GE") == 0) + cmp_op = OP_GE; + else { + asm_error("AIF: %s is not a valid conditional operator", tok); + return; + } + + if ((tok = strtok(NULL, ")")) == NULL) { + asm_error("AIF missing second expression"); + return; + } + + getexpr(tok, FALSE, &expr2); + + switch (cmp_op) { // test the condition + case OP_EQ: istrue = expr1.value == expr2.value; break; + case OP_LT: istrue = expr1.value < expr2.value; break; + case OP_GT: istrue = expr1.value > expr2.value; break; + case OP_NE: istrue = expr1.value != expr2.value; break; + case OP_LE: istrue = expr1.value <= expr2.value; break; + case OP_GE: istrue = expr1.value >= expr2.value; break; + default: bail("in aif, can't happen"); + } + + // After the closing paren coltok and tabtok guarantee we will have no whitespace + + if ((target = strtok(arg, ",")) == NULL) // get target label + asm_warning("Missing target label"); + + if (istrue) + askip(target); // skip to the target +} + +// --------------------------------------------------------------------------------- +// x_aifb - conditional assembly jump back (macro only) +// --------------------------------------------------------------------------------- + +void x_aifb (struct tag_op *op, char *label, char *mods, char *arg) +{ + asm_error("aifb valid in macros only and not implemented in any case"); +} + +// --------------------------------------------------------------------------------- +// x_ago +// --------------------------------------------------------------------------------- + +void x_ago (struct tag_op *op, char *label, char *mods, char *arg) +{ + char *target; + + // label is not entered into the symbol table + + // handle differently in a macro + + if ((target = strtok(arg, ",")) == NULL) // get target label + asm_warning("Missing target label"); + + askip(target); // skip to the target +} + +// --------------------------------------------------------------------------------- +// --------------------------------------------------------------------------------- + +void x_agob (struct tag_op *op, char *label, char *mods, char *arg) +{ + asm_error("agob valid in macros only and not implemented in any case"); +} + +// --------------------------------------------------------------------------------- +// --------------------------------------------------------------------------------- + +void x_anop (struct tag_op *op, char *label, char *mods, char *arg) +{ + // label is not entered into the symbol table + // do nothing else +} + +// --------------------------------------------------------------------------------- +// expression parser, borrowed from older code, no comments, sorry +// --------------------------------------------------------------------------------- + +char *exprptr, *oexprptr; + +#define GETNEXT (*exprptr++) +#define UNGET --exprptr + +#define LETTER 0 /* character types */ +#define DIGIT 1 +#define ETC 2 +#define ILL 3 +#define SPACE 4 +#define MULOP 5 +#define ADDOP 6 +#define EXPOP 7 + +int getnb (void); +void c_expr (EXPR *ap); +void c_expr_m (EXPR *ap); +void c_expr_e (EXPR *ap); +void c_expr_u (EXPR *ap); +void c_term (EXPR *ap); +int c_number (int c, int r, int nchar); +int digit (int c, int r); +int c_esc (int c); +void exprerr (int n); +void a1130_expr (EXPR *ap); +void a1130_term (EXPR *ap); + +char ctype[128] = { // character types +/*^0ABCDEFG */ ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL, +/*^HIJKLMNO */ ILL, SPACE, SPACE, ILL, SPACE, SPACE, ILL, ILL, +/*^PQRSTUVW */ ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL, +/*^XYZ */ ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL, +/* !"#$%&' */ SPACE, ETC, ETC, LETTER, LETTER, MULOP, MULOP, LETTER, /* $ # @ and ' are letters here */ +/* ()*+,-./ */ ETC, ETC, MULOP, ADDOP, ETC, ADDOP, ETC, MULOP, +/* 01234567 */ DIGIT, DIGIT, DIGIT, DIGIT, DIGIT, DIGIT, DIGIT, DIGIT, +/* 89:;<=>? */ DIGIT, DIGIT, ETC, ETC, MULOP, ETC, MULOP, ETC, +/* @ABCDEFG */ LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, +/* HIJKLMNO */ LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, +/* PQRSTUVW */ LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, +/* XYZ[\]^_ */ LETTER, LETTER, LETTER, ETC, ETC, ETC, EXPOP, LETTER, +/* `abcdefg */ ETC, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, +/* hijklmno */ LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, +/* pqrstuvw */ LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, +/* xyz{|}~ */ LETTER, LETTER, LETTER, ETC, ADDOP, ETC, ETC, ETC +}; + +char *errstr[] = { + "Missing exponent", // 0 + "Undefined symbol", // 1 + "Division by zero", // 2 + "Illegal operator", // 3 + ") expected", // 4 + "Char expected after '", // 5 + "Char expected after .", // 6 + "Number expected after =", // 7 + "Syntax error", // 8 + "Number syntax", // 9 + "Char expected after \\", // 10 + "Relocation error" // 11 +}; + +int getnb () { + int c; + + if (cexpr) { // in C mode, handle normally + while (ctype[(c = GETNEXT)] == SPACE) + ; + } // in 1130 mode, a space terminates the expression. Here, eat the rest + else if ((c = GETNEXT) == ' ') { + while ((c = GETNEXT) != '\0') + ; + } + + return c; +} + +int symbest, exprerrno; +jmp_buf exprjmp; + +// --------------------------------------------------------------------------------- +// getexpr +// --------------------------------------------------------------------------------- + +int getexpr (char *pc, BOOL undefined_ok, EXPR *pval) +{ + symbest = S_DEFINED; // assume no questionable symbols + + pval->value = 0; + pval->relative = ABSOLUTE; + + if (! *pc) // blank expression is same as zero, ok? + return S_DEFINED; + + if (setjmp(exprjmp) != 0) { // encountered a syntax error & bailed + pval->value = 0; + pval->relative = ABSOLUTE; + return S_UNDEFINED; + } + + exprptr = oexprptr = pc; // make global the buffer pointer + + c_expr(pval); + + if (GETNEXT) // expression should have been entirely eaten + exprerr(8); // if characters are left, it's an error + + if (pval->relative < 0 || pval->relative > 1) + exprerr(11); // has to work out to an absolute or a single relative term + + if (symbest == S_DEFINED) // tell how it came out + return S_DEFINED; + + pval->value = 0; + pval->relative = ABSOLUTE; + return (pass == 1 && undefined_ok) ? S_PROVISIONAL : S_UNDEFINED; +} + +// --------------------------------------------------------------------------------- +// output_literals - construct .DC assembler lines to assemble pending literal +// constant values that have accumulated. +// --------------------------------------------------------------------------------- + +void output_literals (BOOL eof) +{ + char line[120], label[12], num[20]; + int i; + + for (i = 0; i < n_literals; i++) { // generate DC statements for any pending literal constants + if (literal[i].even && literal[i].hex) // create the value string + sprintf(num, "/%08lx", literal[i].value); + else if (literal[i].even) + sprintf(num, "%ld", literal[i].value); + else if (literal[i].hex) + sprintf(num, "/%04x", literal[i].value & 0xFFFF); + else + sprintf(num, "%d", literal[i].value); + + sprintf(label, "_L%03d", literal[i].tagno); + format_line(line, label, literal[i].even ? "DEC" : "DC", "", num, "GENERATED LITERAL CONSTANT"); + + if (eof) { + eof = FALSE; // at end of file, for first literal, only prepare blank line + sprintf(listline, LEFT_MARGIN, org); + } + else + listout(TRUE); // push out any pending line(s) + + if (flist && list_on) // this makes stuff appear in the listing + sprintf(listline, LEFT_MARGIN " %s", detab(line)); + + nwout = 0; + + parse_line(line); // assemble the constant definition + } + + n_literals = 0; // clear list +} + +// --------------------------------------------------------------------------------- +// a1130_term - extract one term of an expression +// --------------------------------------------------------------------------------- + +void a1130_term (EXPR *ap) +{ + PSYMBOL s; + char token[80], *t; + int c; + + if (cexpr) { // use C syntax + c_term(ap); + return; + } + + c = GETNEXT; + + if (ctype[c] == DIGIT) { /* number */ + ap->value = c_number(c,10,-1); + ap->relative = ABSOLUTE; + } + else if (c == '+') { /* unary + */ + a1130_term(ap); + } + else if (c == '-') { /* unary - */ + a1130_term(ap); + ap->value = - ap->value; + } + else if (c == '/') { /* / starts a hex constant */ + ap->value = c_number(c,16,-1); + ap->relative = ABSOLUTE; + } + else if (c == '*') { /* asterisk alone = org */ + ap->value = org + org_advanced; // here is where that offset matters! + ap->relative = relocate; + } + else if (c == '.') { /* EBCDIC constant */ + c = GETNEXT; + if (c == '\0') { + UNGET; + c = ' '; + } + c = ascii_to_ebcdic_table[c]; + ap->value = c; // VALUE IS IN LOW BYTE!!! + ap->relative = ABSOLUTE; + } + else if (ctype[c] == LETTER) { /* symbol */ + t = token; + do { + *t++ = c; + c = GETNEXT; + } while (ctype[c] == LETTER || ctype[c] == DIGIT); + UNGET; + *t++ = '\0'; + + s = lookup_symbol(token, TRUE); + add_xref(s, FALSE); + ap->value = s->value; + ap->relative = s->relative; + + symbest = MIN(symbest, s->defined); // this goes to lowest value (undefined < provisional < defined) + if (pass == 2 && s->defined != S_DEFINED) + exprerr(1); + } + else + exprerr(8); +} + +// --------------------------------------------------------------------------------- +// c_expr - evalate an expression +// --------------------------------------------------------------------------------- + +void c_expr (EXPR *ap) +{ + int c; + EXPR rop; + + c_expr_m(ap); // get combined multiplicative terms + for (;;) { // handle +/- precedence operators + if (ctype[c=getnb()] != ADDOP) { + UNGET; + break; + } + c_expr_m(&rop); // right hand operand + switch (c) { + case '+': + ap->value += rop.value; + ap->relative += rop.relative; + break; + + case '-': + ap->value -= rop.value; + ap->relative -= rop.relative; + break; + + case '|': + if (ap->relative || rop.relative) + exprerr(11); + ap->value = ((long) (ap->value)) | ((long) rop.value); + break; + + default: + printf("In expr, can't happen\n"); + } + } +} + +// --------------------------------------------------------------------------------- +// c_expr_m - get multiplicative precedence terms. Again, this is not usually used +// --------------------------------------------------------------------------------- + +void c_expr_m (EXPR *ap) +{ + int c; + EXPR rop; + + c_expr_e(ap); // get exponential precedence term + for (;;) { // get operator + c = getnb(); + if ((c=='<') || (c=='>')) + if (c != getnb()) // << or >> + exprerr(3); + if (ctype[c] != MULOP) { + UNGET; + break; + } + c_expr_e(&rop); // right hand operand + + switch(c) { + case '*': + if (ap->relative && rop.relative) + exprerr(11); + + ap->value *= rop.value; + ap->relative = (ap->relative || rop.relative) ? RELATIVE : ABSOLUTE; + break; + + case '/': + if (rop.value == 0) + exprerr(2); + if (ap->relative || rop.relative) + exprerr(11); + + ap->value /= rop.value; + break; + + case '%': + if (rop.value == 0) + exprerr(2); + if (ap->relative || rop.relative) + exprerr(11); + + ap->value = ((long) (ap->value)) % ((long) rop.value); + break; + + case '&': + if (ap->relative || rop.relative) + exprerr(11); + + ap->value = ((long) (ap->value)) & ((long) rop.value); + break; + + case '>': + if (ap->relative || rop.relative) + exprerr(11); + + ap->value = ((long) (ap->value)) >> ((long) rop.value); + break; + + case '<': + if (ap->relative || rop.relative) + exprerr(11); + + ap->value = ((long) (ap->value)) << ((long) rop.value); + break; + + default: + printf("In expr_m, can't happen\n"); + } + } +} + +// --------------------------------------------------------------------------------- +// c_expr_e - get exponential precedence terms. Again, this is not usually used +// --------------------------------------------------------------------------------- + +void c_expr_e (EXPR *ap) +{ + int c, i, v; + EXPR rop; + + c_expr_u(ap); + for (;;) { + c = getnb(); + if (ctype[c] != EXPOP) { + UNGET; + break; + } + c_expr_u(&rop); + + switch(c) { + case '^': + if (ap->relative || rop.relative) + exprerr(11); + + v = ap->value; + ap->value = 1; + for (i = 0; i < rop.value; i++) + ap->value *= v; + break; + + default: + printf("In expr_e, can't happen\n"); + } + } +} + +// --------------------------------------------------------------------------------- +// c_expr_u - get unary precedence terms. Again, this is not usually used +// --------------------------------------------------------------------------------- + +void c_expr_u (EXPR *ap) +{ + int c; + + if ((c = getnb()) == '!') { + a1130_term(ap); + ap->value = ~ ((long)(ap->value)); + if (ap->relative) + exprerr(11); + } + else if (c == '-') { + a1130_term(ap); + ap->value = - ap->value; + if (ap->relative) + exprerr(11); + } + else { + UNGET; + a1130_term(ap); + } +} + +// --------------------------------------------------------------------------------- +// c_term - get basic operand or parenthesized expression. Again, this is not usually used +// --------------------------------------------------------------------------------- + +void c_term (EXPR *ap) +{ + int c, cc; + PSYMBOL s; + char token[80], *t; + + ap->relative = ABSOLUTE; /* assume absolute */ + + if ((c = getnb()) == '(') { /* parenthesized expr */ + c_expr(ap); /* start over at the top! */ + if ((cc = getnb()) != ')') + exprerr(4); + } + else if (c == '\'') { /* single quote: char */ + if ((c = GETNEXT) == '\0') + c = ' '; + ap->value = c_esc(c); + } + else if (ctype[c] == DIGIT) { /* number */ + ap->value = c_number(c,10,-1); + } + else if (c == '0') { /* 0 starts a hex or octal constant */ + if ((c = GETNEXT) == 'x') { + c = GETNEXT; + ap->value = c_number(c,16,-1); + } + else { + ap->value = c_number(c,8,-1); + } + } + else if (c == '*') { /* asterisk alone = org */ + ap->value = org + org_advanced; + ap->relative = relocate; + } + else if (ctype[c] == LETTER) { /* symbol */ + t = token; + do { + *t++ = c; + c = GETNEXT; + } while (ctype[c] == LETTER || ctype[c] == DIGIT); + UNGET; + *t++ = '\0'; + + s = lookup_symbol(token, TRUE); + ap->value = s->value; + ap->relative = s->relative; + add_xref(s, FALSE); + symbest = MIN(symbest, s->defined); // this goes to lowest value (undefined < provisional < defined) + + if (pass == 2 && s->defined != S_DEFINED) + exprerr(1); + } + else + exprerr(8); +} + +// --------------------------------------------------------------------------------- +// c_number - get a C format constant value. Again, this is not usually used +// --------------------------------------------------------------------------------- + +int c_number (int c, int r, int nchar) +{ + int v, n; + + nchar--; + + if (c == '/' && ! cexpr) { /* special radix stuff */ + r = 16; + c = GETNEXT; + } + else if (r == 10 && c == '0' && cexpr) { /* accept C style 0x## also */ + c = GETNEXT; + if (c == 'x') { + r = 16; + c = GETNEXT; + } + else { + r = 8; + UNGET; + c = '0'; + } + } + + n = 0; /* decode number */ + while ((nchar-- != 0) && (v = digit(c, r)) >= 0) { + if (v >= r) /* out of range! */ + exprerr(9); + + n = r*n + v; + + c = GETNEXT; + if (c == '.') { // maybe make it decimal? + c = GETNEXT; + break; + } + } + + UNGET; + return (n); +} + +// --------------------------------------------------------------------------------- +// digit - get digit value of character c in radix r +// --------------------------------------------------------------------------------- + +int digit (int c, int r) +{ + if (r == 16) { + if (c >= 'A' && c <= 'F') + return (c - 'A' + 10); + } + + if (c >= '0' && c <= '9') + return (c - '0'); + + return (-1); +} + +// --------------------------------------------------------------------------------- +// c_esc - handle C character escape +// --------------------------------------------------------------------------------- + +int c_esc (int c) +{ + if (c != '\\') /* not escaped */ + return(c); + + if ((c = GETNEXT) == '\0') /* must be followed by something */ + exprerr(10); + if ((c >= 'A') && (c <= 'Z')) /* handle upper case */ + c += 'a'-'A'; + if (ctype[c] == LETTER) /* control character abbrevs */ + switch (c) { + case 'b': c = '\b'; break; /* backspace */ + case 'e': c = 27 ; break; /* escape */ + case 'f': c = '\f'; break; /* formfeed */ + case 'n': c = '\n'; break; /* newline */ + case 'r': c = '\r'; break; /* return */ + case 't': c = '\t'; break; /* horiz. tab */ + } + else if (ctype[c] == DIGIT) { /* get character by the numbers */ + c = c_number(c,8,3); /* force octal */ + } + + return c; +} + +// --------------------------------------------------------------------------------- +// exprerr - note an expression syntax error. Longjumps back to caller with failure code +// --------------------------------------------------------------------------------- + +void exprerr (int n) +{ + char msg[256]; + int nex = exprptr-oexprptr; + + strncpy(msg, oexprptr, nex); // show where the problem was + msg[nex] = '\0'; + strcat(msg, " << "); + strcat(msg, errstr[n]); + + asm_error(msg); + + exprerrno = n; + longjmp(exprjmp, 1); +} + +/* ------------------------------------------------------------------------ + * upcase - force a string to uppercase (ASCII) + * ------------------------------------------------------------------------ */ + +char *upcase (char *str) +{ + char *s; + + for (s = str; *s; s++) { + if (*s >= 'a' && *s <= 'z') + *s -= 32; + } + + return str; +} + +/* ------------------------------------------------------------------------ + * hollerith table for IPL card ident field + * ------------------------------------------------------------------------ */ + +typedef struct { + int hollerith; + char ascii; +} CPCODE; + +static CPCODE cardcode_029[] = +{ + 0x0000, ' ', + 0x8000, '&', // + in 026 Fortran + 0x4000, '-', + 0x2000, '0', + 0x1000, '1', + 0x0800, '2', + 0x0400, '3', + 0x0200, '4', + 0x0100, '5', + 0x0080, '6', + 0x0040, '7', + 0x0020, '8', + 0x0010, '9', + 0x9000, 'A', + 0x8800, 'B', + 0x8400, 'C', + 0x8200, 'D', + 0x8100, 'E', + 0x8080, 'F', + 0x8040, 'G', + 0x8020, 'H', + 0x8010, 'I', + 0x5000, 'J', + 0x4800, 'K', + 0x4400, 'L', + 0x4200, 'M', + 0x4100, 'N', + 0x4080, 'O', + 0x4040, 'P', + 0x4020, 'Q', + 0x4010, 'R', + 0x3000, '/', + 0x2800, 'S', + 0x2400, 'T', + 0x2200, 'U', + 0x2100, 'V', + 0x2080, 'W', + 0x2040, 'X', + 0x2020, 'Y', + 0x2010, 'Z', + 0x0820, ':', + 0x0420, '#', // = in 026 Fortran + 0x0220, '@', // ' in 026 Fortran + 0x0120, '\'', + 0x00A0, '=', + 0x0060, '"', + 0x8820, 'c', // cent + 0x8420, '.', + 0x8220, '<', // ) in 026 Fortran + 0x8120, '(', + 0x80A0, '+', + 0x8060, '|', + 0x4820, '!', + 0x4420, '$', + 0x4220, '*', + 0x4120, ')', + 0x40A0, ';', + 0x4060, 'n', // not + 0x2820, 'x', // what? + 0x2420, ',', + 0x2220, '%', // ( in 026 Fortran + 0x2120, '_', + 0x20A0, '>', + 0x2060, '>', +}; + +int ascii_to_hollerith (int ch) +{ + int i; + + for (i = 0; i < sizeof(cardcode_029) / sizeof(CPCODE); i++) + if (cardcode_029[i].ascii == ch) + return cardcode_029[i].hollerith; + + return 0; +} + +/* ------------------------------------------------------------------------ + * detab - replace tabs with spaces for listing files + * ------------------------------------------------------------------------ */ + +char *detab (char *instr) +{ + static char outstr[256]; + char *out = outstr; + int col = 0; + + while (*instr) { + if (*instr == '\t') { + do { + *out++ = ' '; + col++; + } + while (col & 7); + } + else { + *out++ = *instr; + col++; + } + + instr++; + } + + *out = '\0'; + + return outstr; +} + +#ifndef _WIN32 + +int strnicmp (char *a, char *b, int n) +{ + int ca, cb; + + for (;;) { + if (--n < 0) // still equal after n characters? quit now + return 0; + + if ((ca = *a) == 0) // get character, stop on null terminator + return *b ? -1 : 0; + + if (ca >= 'a' && ca <= 'z') // fold lowercase to uppercase + ca -= 32; + + cb = *b; + if (cb >= 'a' && cb <= 'z') + cb -= 32; + + if ((ca -= cb) != 0) // if different, return comparison + return ca; + + a++, b++; + } +} + +int strcmpi (char *a, char *b) +{ + int ca, cb; + + for (;;) { + if ((ca = *a) == 0) // get character, stop on null terminator + return *b ? -1 : 0; + + if (ca >= 'a' && ca <= 'z') // fold lowercase to uppercase + ca -= 32; + + cb = *b; + if (cb >= 'a' && cb <= 'z') + cb -= 32; + + if ((ca -= cb) != 0) // if different, return comparison + return ca; + + a++, b++; + } +} + +#endif diff --git a/Ibm1130/utils/asm1130.mak b/Ibm1130/utils/asm1130.mak new file mode 100644 index 00000000..f95ef130 --- /dev/null +++ b/Ibm1130/utils/asm1130.mak @@ -0,0 +1,175 @@ +# Microsoft Visual C++ Generated NMAKE File, Format Version 2.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +!IF "$(CFG)" == "" +CFG=Win32 Debug +!MESSAGE No configuration specified. Defaulting to Win32 Debug. +!ENDIF + +!IF "$(CFG)" != "Win32 Release" && "$(CFG)" != "Win32 Debug" +!MESSAGE Invalid configuration "$(CFG)" specified. +!MESSAGE You can specify a configuration when running NMAKE on this makefile +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "asm1130.mak" CFG="Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE +!ERROR An invalid configuration is specified. +!ENDIF + +################################################################################ +# Begin Project +# PROP Target_Last_Scanned "Win32 Debug" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "WinRel" +# PROP BASE Intermediate_Dir "WinRel" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "WinRel" +# PROP Intermediate_Dir "WinRel" +OUTDIR=.\WinRel +INTDIR=.\WinRel + +ALL : $(OUTDIR)/asm1130.exe $(OUTDIR)/asm1130.bsc + +$(OUTDIR) : + if not exist $(OUTDIR)/nul mkdir $(OUTDIR) + +# ADD BASE CPP /nologo /W3 /GX /YX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /FR /c +# ADD CPP /nologo /W3 /GX /YX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /FR /c +CPP_PROJ=/nologo /W3 /GX /YX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE"\ + /FR$(INTDIR)/ /Fp$(OUTDIR)/"asm1130.pch" /Fo$(INTDIR)/ /c +CPP_OBJS=.\WinRel/ +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +BSC32_FLAGS=/nologo /o$(OUTDIR)/"asm1130.bsc" +BSC32_SBRS= \ + $(INTDIR)/asm1130.sbr \ + $(INTDIR)/util_io.sbr + +$(OUTDIR)/asm1130.bsc : $(OUTDIR) $(BSC32_SBRS) + $(BSC32) @<< + $(BSC32_FLAGS) $(BSC32_SBRS) +<< + +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /NOLOGO /SUBSYSTEM:console /MACHINE:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib /NOLOGO /SUBSYSTEM:console /MACHINE:I386 +LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib /NOLOGO /SUBSYSTEM:console\ + /INCREMENTAL:no /PDB:$(OUTDIR)/"asm1130.pdb" /MACHINE:I386\ + /OUT:$(OUTDIR)/"asm1130.exe" +DEF_FILE= +LINK32_OBJS= \ + $(INTDIR)/asm1130.obj \ + $(INTDIR)/util_io.obj + +$(OUTDIR)/asm1130.exe : $(OUTDIR) $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ELSEIF "$(CFG)" == "Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "WinDebug" +# PROP BASE Intermediate_Dir "WinDebug" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "WinDebug" +# PROP Intermediate_Dir "WinDebug" +OUTDIR=.\WinDebug +INTDIR=.\WinDebug + +ALL : $(OUTDIR)/asm1130.exe $(OUTDIR)/asm1130.bsc + +$(OUTDIR) : + if not exist $(OUTDIR)/nul mkdir $(OUTDIR) + +# ADD BASE CPP /nologo /W3 /GX /Zi /YX /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /FR /c +# ADD CPP /nologo /W3 /GX /Zi /YX /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /FR /c +CPP_PROJ=/nologo /W3 /GX /Zi /YX /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE"\ + /FR$(INTDIR)/ /Fp$(OUTDIR)/"asm1130.pch" /Fo$(INTDIR)/\ + /Fd$(OUTDIR)/"asm1130.pdb" /c +CPP_OBJS=.\WinDebug/ +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +BSC32_FLAGS=/nologo /o$(OUTDIR)/"asm1130.bsc" +BSC32_SBRS= \ + $(INTDIR)/asm1130.sbr \ + $(INTDIR)/util_io.sbr + +$(OUTDIR)/asm1130.bsc : $(OUTDIR) $(BSC32_SBRS) + $(BSC32) @<< + $(BSC32_FLAGS) $(BSC32_SBRS) +<< + +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /NOLOGO /SUBSYSTEM:console /DEBUG /MACHINE:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib /NOLOGO /SUBSYSTEM:console /DEBUG /MACHINE:I386 +LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib /NOLOGO /SUBSYSTEM:console\ + /INCREMENTAL:yes /PDB:$(OUTDIR)/"asm1130.pdb" /DEBUG /MACHINE:I386\ + /OUT:$(OUTDIR)/"asm1130.exe" +DEF_FILE= +LINK32_OBJS= \ + $(INTDIR)/asm1130.obj \ + $(INTDIR)/util_io.obj + +$(OUTDIR)/asm1130.exe : $(OUTDIR) $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ENDIF + +.c{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.cpp{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.cxx{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +################################################################################ +# Begin Group "Source Files" + +################################################################################ +# Begin Source File + +SOURCE=.\asm1130.c + +$(INTDIR)/asm1130.obj : $(SOURCE) $(INTDIR) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\util_io.c +DEP_UTIL_=\ + .\util_io.h + +$(INTDIR)/util_io.obj : $(SOURCE) $(DEP_UTIL_) $(INTDIR) + +# End Source File +# End Group +# End Project +################################################################################ diff --git a/Ibm1130/utils/bindump.c b/Ibm1130/utils/bindump.c new file mode 100644 index 00000000..a5f8ea64 --- /dev/null +++ b/Ibm1130/utils/bindump.c @@ -0,0 +1,755 @@ +/* + * (C) Copyright 2002, Brian Knittel. + * You may freely use this program, but: it offered strictly on an AS-IS, AT YOUR OWN + * RISK basis, there is no warranty of fitness for any purpose, and the rest of the + * usual yada-yada. Please keep this notice and the copyright in any distributions + * or modifications. + * + * This is not a supported product, but I welcome bug reports and fixes. + * Mail to sim@ibm1130.org + */ + +// --------------------------------------------------------------------------------- +// BINDUMP - dumps card deck files in assembler object format +// +// Usage: +/// bindump deckfile lists object header info & sector break cards +// bindump -v deckfile lists object data records as well +// bindump -p deckfile for system program, lists phase IDs in the deck +// bindump -s deckfile >outfile for system program, sorts the phases & writes to stdout + +#include +#include +#ifdef _WIN32 +# include +# include +# include +#endif + +#include "util_io.h" + +#ifndef TRUE + #define BOOL int + #define TRUE 1 + #define FALSE 0 +#endif + +typedef enum {R_ABSOLUTE = 0, R_RELATIVE = 1, R_LIBF = 2, R_CALL = 3} RELOC; + +BOOL verbose = FALSE; +BOOL phid = FALSE; +BOOL sort = FALSE; +unsigned short card[80], buf[54], cardtype; + +// bindump - dump a binary (card format) deck to verify sbrks, etc + +void bail (char *msg); +void dump (char *fname); +void dump_data (char *fname); +void dump_phids (char *fname); +char *getname (unsigned short *ptr); +char *getseq (void); +int hollerith_to_ascii (unsigned short h); +void process (char *fname); +void show_raw (char *name); +void show_data (void); +void show_core (void); +void show_endc (void); +void show_81 (void); +void show_main (void); +void show_sub (void); +void show_ils (void); +void show_iss (void); +void show_end (void); +void sort_phases (char *fname); +void trim (char *s); +void unpack (unsigned short *card, unsigned short *buf); +void verify_checksum(unsigned short *buf); + +int main (int argc, char **argv) +{ + char *arg; + static char usestr[] = "Usage: bindump [-psv] filename..."; + int i; + + for (i = 1; i < argc; i++) { + arg = argv[i]; + if (*arg == '-') { + arg++; + while (*arg) { + switch (*arg++) { + case 'v': + verbose = TRUE; + break; + case 'p': + phid = TRUE; // print only phase ID's + break; + case 's': + sort = TRUE; // sort deck by phases, writing to stdout + break; + default: + bail(usestr); + } + } + } + } + + for (i = 1; i < argc; i++) { + arg = argv[i]; + if (*arg != '-') + process(arg); + } + return 0; +} + +void process (char *nm) +{ +#ifdef _WIN32 + WIN32_FIND_DATA fd; + HANDLE hFind; + char *c, buf[256]; + + if (strchr(nm, '*') == NULL && strchr(nm, '?') == NULL) + dump(nm); + + else if ((hFind = FindFirstFile(nm, &fd)) == INVALID_HANDLE_VALUE) + fprintf(stderr, "No files matching '%s'\n", nm); + + else { + if ((c = strrchr(nm, '\\')) == NULL) + c = strrchr(nm, ':'); + + do { + if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + continue; + + if (c == NULL) + dump(fd.cFileName); + else { + strcpy(buf, nm); + strcpy(buf + (c-nm+1), fd.cFileName); + dump(buf); + } + + } while (FindNextFile(hFind, &fd)); + + FindClose(hFind); + } +#else + dump(nm); // on unices, sh globs for us +#endif +} + +void dump (char *fname) +{ + if (sort) + sort_phases(fname); + else if (phid) + dump_phids(fname); + else + dump_data(fname); +} + +struct tag_card { + int phid, seq; + unsigned short card[80]; +}; + +int cardcomp (const void *a, const void *b) +{ + short diff; + + diff = ((struct tag_card *) a)->phid - ((struct tag_card *) b)->phid; + + return diff ? diff : (((struct tag_card *) a)->seq - ((struct tag_card *) b)->seq); +} + +void sort_phases (char *fname) +{ + int i, ncards, cardtype, len, seq = 0, phid; + struct tag_card *deck; + FILE *fd; + BOOL saw_sbrk = TRUE; + + if ((fd = fopen(fname, "rb")) == NULL) { + perror(fname); + return; + } + + fseek(fd, 0, SEEK_END); + len = ftell(fd); // get length of file + fseek(fd, 0, SEEK_SET); + + if (len <= 0 || (len % 160) != 0) { + fprintf(stderr, "%s is not a binard deck image\n"); + fclose(fd); + return; + } + + ncards = len / 160; + + if ((deck = (struct tag_card *) malloc(ncards*sizeof(struct tag_card))) == NULL) { + fprintf(stderr, "%s: can't sort, insufficient memory\n"); + fclose(fd); + return; + } + + phid = 0; + for (i = 0; i < ncards; i++) { + if (fxread(deck[i].card, sizeof(card[0]), 80, fd) != 80) { + free(deck); + fprintf(stderr, "%s: error reading deck\n"); + fclose(fd); + return; + } + + unpack(deck[i].card, buf); + deck[i].seq = seq++; + deck[i].phid = phid; + + verify_checksum(buf); + + cardtype = (buf[2] >> 8) & 0xFF; + + if (cardtype == 1 || cardtype == 2) { // start of deck is same as sector break + saw_sbrk = TRUE; + } + else if (cardtype == 0) { + fprintf(stderr, "%s is a core image deck\n"); + free(deck); + fclose(fd); + return; + } + else if (cardtype == 0x0A && saw_sbrk) { + phid = (int) (signed short) buf[10]; + if (phid < 0) + phid = -phid; + + deck[i].phid = phid; // this belongs to the new phase + deck[i-1].phid = phid; // as does previous card + saw_sbrk = FALSE; + } + } + fclose(fd); + + qsort(deck, ncards, sizeof(struct tag_card), cardcomp); // sort the deck + +#ifdef _WIN32 + _setmode(_fileno(stdout), _O_BINARY); // set standard output to binary mode +#endif + + for (i = 0; i < ncards; i++) // write to stdout + fxwrite(deck[i].card, sizeof(card[0]), 80, stdout); + + free(deck); +} + +void dump_phids (char *fname) +{ + FILE *fp; + BOOL first = TRUE; + BOOL saw_sbrk = TRUE, neg; + short id; + + if ((fp = fopen(fname, "rb")) == NULL) { + perror(fname); + return; + } + + printf("\n%s:\n", fname); + + while (fxread(card, sizeof(card[0]), 80, fp) > 0) { + unpack(card, buf); + verify_checksum(buf); + + cardtype = (buf[2] >> 8) & 0xFF; + + if (cardtype == 1 && ! first) { // sector break + saw_sbrk = TRUE; + continue; + } + else { + switch (cardtype) { + case 0x00: + printf(" This is a core image deck\n"); + goto done; + break; + case 0x01: + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + case 0x07: + case 0x0F: + break; + + case 0x0A: + if (saw_sbrk) { + id = buf[10]; + if (id < 0) + id = -id, neg = TRUE; + else + neg = FALSE; + printf(" : %3d / %02x%s\n", id, id, neg ? " (neg)" : ""); + saw_sbrk = FALSE; + } + break; + + default: + show_raw("??? "); + } + } +done: + first = FALSE; + } + + fclose(fp); +} + +void dump_data (char *fname) +{ + FILE *fp; + BOOL first = TRUE; + char str[80]; + int i; + + if ((fp = fopen(fname, "rb")) == NULL) { + perror(fname); + return; + } + + printf("\n%s:\n", fname); + + while (fxread(card, sizeof(card[0]), 80, fp) > 0) { + unpack(card, buf); + verify_checksum(buf); + + cardtype = (buf[2] >> 8) & 0xFF; + + if (cardtype == 1 && ! first) { // sector break + for (i = 4; i < 72; i++) + str[i] = hollerith_to_ascii(card[i]); + + str[i] = '\0'; + trim(str+4); + printf("*SBRK %s\n", str+4); + continue; + } + else { + switch (cardtype) { + case 0x00: + if (first) + show_raw("CORE"); + if (verbose) + show_core(); + break; + + case 0x01: + show_raw("ABS "); + show_main(); + break; + case 0x02: + show_raw("REL "); + show_main(); + break; + case 0x03: + show_raw("LIB "); + show_sub(); + break; + case 0x04: + show_raw("SUB "); + show_sub(); + break; + case 0x05: + show_raw("ISSL"); + show_iss(); + break; + case 0x06: + show_raw("ISSC"); + show_iss(); + break; + case 0x07: + show_raw("ILS "); + show_ils(); + break; + case 0x0F: + show_raw("END "); + show_end(); + break; + case 0x80: + show_raw("ENDC"); + show_endc(); + break; + case 0x81: + show_raw("81 "); + show_81(); + break; + case 0x0A: + if (verbose) + show_data(); + break; + default: + show_raw("??? "); + } + } + + first = FALSE; + } + + fclose(fp); +} + +void show_data (void) +{ + int i, n, jrel, rflag, nout, ch, reloc; + BOOL first = TRUE; + + n = buf[2] & 0x00FF; + + printf("%04x: ", buf[0]); + + jrel = 3; + nout = 0; + rflag = buf[jrel++]; + for (i = 0; i < n; i++) { + if (nout >= 8) { + rflag = buf[jrel++]; + if (first) { + printf(" %s", getseq()); + first = FALSE; + } + printf("\n "); + nout = 0; + } + reloc = (rflag >> 14) & 0x03; + ch = (reloc == R_ABSOLUTE) ? ' ' : + (reloc == R_RELATIVE) ? 'R' : + (reloc == R_LIBF) ? 'L' : '@'; + + printf("%04x%c ", buf[9+i], ch); + rflag <<= 2; + nout++; + } + putchar('\n'); +} + +void show_core (void) +{ + int i, n, nout; + BOOL first = TRUE; + + n = buf[2] & 0x00FF; + + printf("%04x: ", buf[0]); + + nout = 0; + for (i = 0; i < n; i++) { + if (nout >= 8) { + if (first) { + printf(" %s", getseq()); + first = FALSE; + } + printf("\n "); + nout = 0; + } + printf("%04x ", buf[9+i]); + nout++; + } + putchar('\n'); +} + +void info (int i, char *nm, char type) +{ + if (nm) + printf("%s ", nm); + + switch (type) { + case 'd': + printf("%d ", buf[i]); + break; + + case 'x': + printf("%04x ", buf[i]); + break; + + case 'b': + printf("%02x ", buf[i] & 0xFF); + break; + + case 'n': + printf("%s ", getname(buf+i)); + break; + + default: + bail("BAD TYPE"); + } +} + +void show_main (void) +{ + printf(" "); + info(2, "prec", 'b'); + info(4, "common", 'd'); + info(6, "work", 'd'); + info(8, "files", 'd'); + info(9, "name", 'n'); + info(11, "pta", 'x'); + putchar('\n'); +} + +void show_sub (void) +{ + int i, n; + + printf(" "); + info( 2, "prec", 'b'); + + n = buf[5] / 3; + for (i = 0; i < n; i++) { + info( 9+3*i, "ent", 'n'); + info(11+3*i, NULL, 'x'); + } + + putchar('\n'); +} + +void show_iss (void) +{ + printf(" "); + info(12, "level", 'd'); + putchar('\n'); +} + +void show_ils (void) +{ + printf(" "); + info( 2, "prec", 'b'); + info( 5, "nint6", 'd'); + info( 9, "ent", 'n'); + info(11, NULL, 'x'); + info(14, "nint", 'd'); + info(15, "il1", 'd'); + info(16, "il2", 'd'); + putchar('\n'); +} + +void show_end (void) +{ + printf(" "); + info(0, "size", 'd'); + info(3, "pta", 'x'); + putchar('\n'); +} + +void show_endc(void) +{ + printf(" "); + info(52, "IX3", 'x'); + info(53, "pta", 'x'); + putchar('\n'); +} + +void show_81(void) +{ +} + +void show_raw (char *name) +{ + int i; + printf("*%s", name); + + for (i = 0; i < 12; i++) + printf(" %04x", buf[i]); + + printf(" %s\n", getseq()); +} + +char * getseq (void) +{ + static char seq[10]; + int i; + + for (i = 0; i < 8; i++) + seq[i] = hollerith_to_ascii(card[72+i]); + + seq[i] = '\0'; + return seq; +} + + +void bail (char *msg) +{ + fprintf(stderr, "%s\n", msg); + exit(1); +} + +void unpack (unsigned short *icard, unsigned short *obuf) +{ + int i, j; + unsigned short wd1, wd2, wd3, wd4; + + for (i = j = 0; i < 54; i += 3, j += 4) { + wd1 = icard[j]; + wd2 = icard[j+1]; + wd3 = icard[j+2]; + wd4 = icard[j+3]; + + obuf[i ] = (wd1 & 0xFFF0) | ((wd2 >> 12) & 0x000F); + obuf[i+1] = ((wd2 << 4) & 0xFF00) | ((wd3 >> 8) & 0x00FF); + obuf[i+2] = ((wd3 << 8) & 0xF000) | ((wd4 >> 4) & 0x0FFF); + } +} + +void verify_checksum (unsigned short *obuf) +{ +// unsigned short sum; + + if (obuf[1] == 0) // no checksum + return; + +// if (sum != card[1]) +// printf("Checksum %04x doesn't match card %04x\n", sum, card[1]); +} + +typedef struct { + unsigned short hollerith; + char ascii; +} CPCODE; + +static CPCODE cardcode_029[] = +{ + 0x0000, ' ', + 0x8000, '&', // + in 026 Fortran + 0x4000, '-', + 0x2000, '0', + 0x1000, '1', + 0x0800, '2', + 0x0400, '3', + 0x0200, '4', + 0x0100, '5', + 0x0080, '6', + 0x0040, '7', + 0x0020, '8', + 0x0010, '9', + 0x9000, 'A', + 0x8800, 'B', + 0x8400, 'C', + 0x8200, 'D', + 0x8100, 'E', + 0x8080, 'F', + 0x8040, 'G', + 0x8020, 'H', + 0x8010, 'I', + 0x5000, 'J', + 0x4800, 'K', + 0x4400, 'L', + 0x4200, 'M', + 0x4100, 'N', + 0x4080, 'O', + 0x4040, 'P', + 0x4020, 'Q', + 0x4010, 'R', + 0x3000, '/', + 0x2800, 'S', + 0x2400, 'T', + 0x2200, 'U', + 0x2100, 'V', + 0x2080, 'W', + 0x2040, 'X', + 0x2020, 'Y', + 0x2010, 'Z', + 0x0820, ':', + 0x0420, '#', // = in 026 Fortran + 0x0220, '@', // ' in 026 Fortran + 0x0120, '\'', + 0x00A0, '=', + 0x0060, '"', + 0x8820, 'c', // cent + 0x8420, '.', + 0x8220, '<', // ) in 026 Fortran + 0x8120, '(', + 0x80A0, '+', + 0x8060, '|', + 0x4820, '!', + 0x4420, '$', + 0x4220, '*', + 0x4120, ')', + 0x40A0, ';', + 0x4060, 'n', // not + 0x2820, 'x', // what? + 0x2420, ',', + 0x2220, '%', // ( in 026 Fortran + 0x2120, '_', + 0x20A0, '>', + 0x2060, '>', +}; + +int hollerith_to_ascii (unsigned short h) +{ + int i; + + h &= 0xFFF0; + + for (i = 0; i < sizeof(cardcode_029) / sizeof(CPCODE); i++) + if (cardcode_029[i].hollerith == h) + return cardcode_029[i].ascii; + + return '?'; +} + +// --------------------------------------------------------------------------------- +// trim - remove trailing whitespace from string s +// --------------------------------------------------------------------------------- + +void trim (char *s) +{ + char *nb; + + for (nb = s-1; *s; s++) + if (*s > ' ') + nb = s; + + nb[1] = '\0'; +} + +int ascii_to_ebcdic_table[128] = +{ + 0x00,0x01,0x02,0x03,0x37,0x2d,0x2e,0x2f, 0x16,0x05,0x25,0x0b,0x0c,0x0d,0x0e,0x0f, + 0x10,0x11,0x12,0x13,0x3c,0x3d,0x32,0x26, 0x18,0x19,0x3f,0x27,0x1c,0x1d,0x1e,0x1f, + 0x40,0x5a,0x7f,0x7b,0x5b,0x6c,0x50,0x7d, 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, 0xc8,0xc9,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6, + 0xd7,0xd8,0xd9,0xe2,0xe3,0xe4,0xe5,0xe6, 0xe7,0xe8,0xe9,0xba,0xe0,0xbb,0xb0,0x6d, + 0x79,0x81,0x82,0x83,0x84,0x85,0x86,0x87, 0x88,0x89,0x91,0x92,0x93,0x94,0x95,0x96, + 0x97,0x98,0x99,0xa2,0xa3,0xa4,0xa5,0xa6, 0xa7,0xa8,0xa9,0xc0,0x4f,0xd0,0xa1,0x07, +}; + +char *getname (unsigned short *ptr) +{ + static char str[6]; + int i, j, ch; + long v; + + v = (ptr[0] << 16L) | ptr[1]; + + for (i = 0; i < 5; i++) { + ch = ((v >> 24) & 0x3F) | 0xC0; // recover those lost two bits + v <<= 6; + + str[i] = ' '; + + for (j = 0; j < (sizeof(ascii_to_ebcdic_table)/sizeof(ascii_to_ebcdic_table[0])); j++) { + if (ascii_to_ebcdic_table[j] == ch) { + str[i] = j; + break; + } + } + } + + str[5] = '\0'; + return str; +} + + diff --git a/Ibm1130/utils/bindump.mak b/Ibm1130/utils/bindump.mak new file mode 100644 index 00000000..c2cbab2e --- /dev/null +++ b/Ibm1130/utils/bindump.mak @@ -0,0 +1,175 @@ +# Microsoft Visual C++ Generated NMAKE File, Format Version 2.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +!IF "$(CFG)" == "" +CFG=Win32 Debug +!MESSAGE No configuration specified. Defaulting to Win32 Debug. +!ENDIF + +!IF "$(CFG)" != "Win32 Release" && "$(CFG)" != "Win32 Debug" +!MESSAGE Invalid configuration "$(CFG)" specified. +!MESSAGE You can specify a configuration when running NMAKE on this makefile +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "bindump.mak" CFG="Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE +!ERROR An invalid configuration is specified. +!ENDIF + +################################################################################ +# Begin Project +# PROP Target_Last_Scanned "Win32 Debug" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "WinRel" +# PROP BASE Intermediate_Dir "WinRel" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "WinRel" +# PROP Intermediate_Dir "WinRel" +OUTDIR=.\WinRel +INTDIR=.\WinRel + +ALL : $(OUTDIR)/bindump.exe $(OUTDIR)/bindump.bsc + +$(OUTDIR) : + if not exist $(OUTDIR)/nul mkdir $(OUTDIR) + +# ADD BASE CPP /nologo /W3 /GX /YX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /FR /c +# ADD CPP /nologo /W3 /GX /YX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /FR /c +CPP_PROJ=/nologo /W3 /GX /YX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE"\ + /FR$(INTDIR)/ /Fp$(OUTDIR)/"bindump.pch" /Fo$(INTDIR)/ /c +CPP_OBJS=.\WinRel/ +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +BSC32_FLAGS=/nologo /o$(OUTDIR)/"bindump.bsc" +BSC32_SBRS= \ + $(INTDIR)/bindump.sbr \ + $(INTDIR)/util_io.sbr + +$(OUTDIR)/bindump.bsc : $(OUTDIR) $(BSC32_SBRS) + $(BSC32) @<< + $(BSC32_FLAGS) $(BSC32_SBRS) +<< + +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /NOLOGO /SUBSYSTEM:console /MACHINE:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib /NOLOGO /SUBSYSTEM:console /MACHINE:I386 +LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\ + /NOLOGO /SUBSYSTEM:console /INCREMENTAL:no /PDB:$(OUTDIR)/"bindump.pdb"\ + /MACHINE:I386 /OUT:$(OUTDIR)/"bindump.exe" +DEF_FILE= +LINK32_OBJS= \ + $(INTDIR)/bindump.obj \ + $(INTDIR)/util_io.obj + +$(OUTDIR)/bindump.exe : $(OUTDIR) $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ELSEIF "$(CFG)" == "Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "WinDebug" +# PROP BASE Intermediate_Dir "WinDebug" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "WinDebug" +# PROP Intermediate_Dir "WinDebug" +OUTDIR=.\WinDebug +INTDIR=.\WinDebug + +ALL : $(OUTDIR)/bindump.exe $(OUTDIR)/bindump.bsc + +$(OUTDIR) : + if not exist $(OUTDIR)/nul mkdir $(OUTDIR) + +# ADD BASE CPP /nologo /W3 /GX /Zi /YX /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /FR /c +# ADD CPP /nologo /W3 /GX /Zi /YX /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /FR /c +CPP_PROJ=/nologo /W3 /GX /Zi /YX /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE"\ + /FR$(INTDIR)/ /Fp$(OUTDIR)/"bindump.pch" /Fo$(INTDIR)/\ + /Fd$(OUTDIR)/"bindump.pdb" /c +CPP_OBJS=.\WinDebug/ +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +BSC32_FLAGS=/nologo /o$(OUTDIR)/"bindump.bsc" +BSC32_SBRS= \ + $(INTDIR)/bindump.sbr \ + $(INTDIR)/util_io.sbr + +$(OUTDIR)/bindump.bsc : $(OUTDIR) $(BSC32_SBRS) + $(BSC32) @<< + $(BSC32_FLAGS) $(BSC32_SBRS) +<< + +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /NOLOGO /SUBSYSTEM:console /DEBUG /MACHINE:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib /NOLOGO /SUBSYSTEM:console /DEBUG /MACHINE:I386 +LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\ + /NOLOGO /SUBSYSTEM:console /INCREMENTAL:yes /PDB:$(OUTDIR)/"bindump.pdb" /DEBUG\ + /MACHINE:I386 /OUT:$(OUTDIR)/"bindump.exe" +DEF_FILE= +LINK32_OBJS= \ + $(INTDIR)/bindump.obj \ + $(INTDIR)/util_io.obj + +$(OUTDIR)/bindump.exe : $(OUTDIR) $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ENDIF + +.c{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.cpp{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.cxx{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +################################################################################ +# Begin Group "Source Files" + +################################################################################ +# Begin Source File + +SOURCE=.\bindump.c + +$(INTDIR)/bindump.obj : $(SOURCE) $(INTDIR) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\util_io.c +DEP_UTIL_=\ + .\util_io.h + +$(INTDIR)/util_io.obj : $(SOURCE) $(DEP_UTIL_) $(INTDIR) + +# End Source File +# End Group +# End Project +################################################################################ diff --git a/Ibm1130/utils/checkdisk.c b/Ibm1130/utils/checkdisk.c new file mode 100644 index 00000000..bf775d00 --- /dev/null +++ b/Ibm1130/utils/checkdisk.c @@ -0,0 +1,262 @@ +/* + * (C) Copyright 2002, Brian Knittel. + * You may freely use this program, but: it offered strictly on an AS-IS, AT YOUR OWN + * RISK basis, there is no warranty of fitness for any purpose, and the rest of the + * usual yada-yada. Please keep this notice and the copyright in any distributions + * or modifications. + * + * This is not a supported product, but I welcome bug reports and fixes. + * Mail to sim@ibm1130.org + */ + +// checkdisk - validates and optionally dumps an IBM1130 DMS2 disk image file +// +// Usage: +// checkdisk [-f] [-d cyl.sec|abssec] [-n count] filename +// +// Examples: +// checkdisk file.dsk +// report any misnumbered sectors in file.dsk +// +// checkdisk -f file.dsk +// report and fix any misnumbered sectors +// +// checkdisk -d 198.0 file.dsk +// dump cylinder 198 sector 0 +// +// checkdisk -d 0 file.dsk +// dump absolute sector 0 +// +// checkdisk -d 198.0 -n 4 file.dsk +// dump 4 sectors starting at m.n +// ----------------------------------------------------------------------------------------- +#include +#include +#include +#include "util_io.h" + +#ifdef _WIN32 +# include +#else + long filelength (int fno); +# include +# include +#endif + +#ifndef TRUE +# define BOOL int +# define TRUE 1 +# define FALSE 0 +#endif + +#define DSK_NUMWD 321 /* words/sector */ +#define DSK_NUMSC 4 /* sectors/surface */ +#define DSK_NUMSF 2 /* surfaces/cylinder */ +#define DSK_NUMCY 203 /* cylinders/drive */ +#define DSK_NUMDR 5 /* drives/controller */ +#define DSK_SIZE (DSK_NUMCY * DSK_NUMSF * DSK_NUMSC * DSK_NUMWD) /* words/drive */ + +char *usestr = "Usage: checkdisk [-f] [-d cyl.sec|abssec] [-n count] diskfile"; +char *baddisk = "Cannot fix this"; + +void bail (char *msg); +char *lowcase (char *str); + +int main (int argc, char **argv) +{ + FILE *fp; + char *fname = NULL, *arg, *argval; + int i, j, cyl, sec, pos, asec, retry, nbad = 0, nfixed = 0, nline; + BOOL fixit = FALSE, dump = FALSE; + int dsec, nsec = 1; + unsigned short wd, buf[DSK_NUMWD]; + + for (i = 1; i < argc;) { + arg = argv[i++]; + if (*arg == '-') { + arg++; + lowcase(arg); + while (*arg) { + switch (*arg++) { + case 'f': + fixit = TRUE; + break; + + case 'd': + dump = TRUE; + + if (i >= argc) + bail(usestr); + + argval = argv[i++]; + if (strchr(argval, '.') != NULL) { + if (sscanf(argval, "%d.%d", &cyl, &sec) != 2) + bail(usestr); + + dsec = cyl*(DSK_NUMSF*DSK_NUMSC) + sec; + } + else if (sscanf(argval, "%d", &dsec) != 1) + bail(usestr); + + if (dsec < 0 || dsec >= (DSK_NUMCY*DSK_NUMSF*DSK_NUMSC)) + bail("No such sector"); + + break; + + case 'n': + if (i >= argc) + bail(usestr); + + argval = argv[i++]; + if (sscanf(argval, "%d", &nsec) != 1) + bail(usestr); + + if (nsec <= 0) + bail(usestr); + + break; + + default: + bail(usestr); + } + } + } + else if (fname == NULL) + fname = arg; + else + bail(usestr); + } + + if (fname == NULL) + bail(usestr); + + if ((fp = fopen(fname, "rb+")) == NULL) { + perror(fname); + return 1; + } + + if (filelength(fileno(fp)) != 2*DSK_SIZE) { + fprintf(stderr, "File is wrong length, expected %d\n", DSK_SIZE); + bail(baddisk); + } + + for (cyl = 0; cyl < DSK_NUMCY; cyl++) { + for (sec = 0; sec < (DSK_NUMSF*DSK_NUMSC); sec++) { + retry = 1; +again: + asec = cyl*(DSK_NUMSF*DSK_NUMSC) + sec; + pos = asec*2*DSK_NUMWD; + + if (fseek(fp, pos, SEEK_SET) != 0) { + fprintf(stderr, "Error seeking to pos %x\n", pos); + bail(baddisk); + } + + if (fxread(&wd, sizeof(wd), 1, fp) != 1) { + fprintf(stderr, "Error reading word at abs sec %x, cyl %x, sec %x at offset %x\n", asec, cyl, sec, pos); + bail(baddisk); + } + + if (wd != asec) { + fprintf(stderr, "Bad sector #%x at abs sec %x, cyl %x, sec %x at offset %x\n", wd, asec, cyl, sec, pos); + nbad++; + + if (fixit) { + if (fseek(fp, pos, SEEK_SET) != 0) { + fprintf(stderr, "Error seeking to pos %x\n", pos); + bail(baddisk); + } + + if (fxwrite(&asec, sizeof(wd), 1, fp) != 1) { + fprintf(stderr, "Error writing sector # to abs sec %x, cyl %x, sec %x at offset %x\n", asec, cyl, sec, pos); + bail(baddisk); + } + + if (retry) { + retry = 0; + nfixed++; + goto again; + } + + fprintf(stderr, "Failed after retry\n"); + bail(baddisk); + } + } + } + } + + if (nbad) + printf("%d bad sector mark%s %s\n", nbad, (nbad == 1) ? "" : "s", fixit ? "fixed" : "found"); + else if (! dump) + printf("All sector marks OK\n"); + + if (! dump) + return 0; + + pos = dsec*2*DSK_NUMWD; + if (fseek(fp, pos, SEEK_SET) != 0) { + fprintf(stderr, "Error seeking to pos %x\n", pos); + bail(baddisk); + } + + for (i = 0; i < nsec; i++) { + cyl = dsec / (DSK_NUMSF*DSK_NUMSC); + sec = dsec - cyl*(DSK_NUMSF*DSK_NUMSC); + + if (fxread(&buf, sizeof(buf[0]), DSK_NUMWD, fp) != DSK_NUMWD) { + fprintf(stderr, "Error reading abs sec %x, cyl %x, sec %x at offset %x\n", dsec, cyl, sec, pos); + bail(baddisk); + } + + printf("\nSector %d.%d - %d - /%04x label %04x\n", cyl, sec, dsec, dsec, buf[0]); + for (nline = 0, j = 1; j < DSK_NUMWD; j++) { + printf("%04x", buf[j]); + if (++nline == 16) { + putchar('\n'); + nline = 0; + } + else + putchar(' '); + } + + dsec++; + } + + return 0; +} + +void bail (char *msg) +{ + fprintf(stderr, "%s\n", msg); + exit(1); +} + +/* ------------------------------------------------------------------------ + * lowcase - force a string to lower case (ASCII) + * ------------------------------------------------------------------------ */ + +char *lowcase (char *str) +{ + char *s; + + for (s = str; *s; s++) { + if (*s >= 'A' && *s <= 'Z') + *s += 32; + } + + return str; +} + +#ifndef _WIN32 + +long filelength (int fno) +{ + struct stat sb; + + if (fstat(fno, &sb) != 0) + return 0; + + return (long) sb.st_size; +} +#endif + diff --git a/Ibm1130/utils/checkdisk.mak b/Ibm1130/utils/checkdisk.mak new file mode 100644 index 00000000..e03d955b --- /dev/null +++ b/Ibm1130/utils/checkdisk.mak @@ -0,0 +1,177 @@ +# Microsoft Visual C++ Generated NMAKE File, Format Version 2.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +!IF "$(CFG)" == "" +CFG=Win32 Debug +!MESSAGE No configuration specified. Defaulting to Win32 Debug. +!ENDIF + +!IF "$(CFG)" != "Win32 Release" && "$(CFG)" != "Win32 Debug" +!MESSAGE Invalid configuration "$(CFG)" specified. +!MESSAGE You can specify a configuration when running NMAKE on this makefile +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "checkdisk.mak" CFG="Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE +!ERROR An invalid configuration is specified. +!ENDIF + +################################################################################ +# Begin Project +# PROP Target_Last_Scanned "Win32 Release" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "WinRel" +# PROP BASE Intermediate_Dir "WinRel" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "WinRel" +# PROP Intermediate_Dir "WinRel" +OUTDIR=.\WinRel +INTDIR=.\WinRel + +ALL : $(OUTDIR)/checkdisk.exe $(OUTDIR)/checkdisk.bsc + +$(OUTDIR) : + if not exist $(OUTDIR)/nul mkdir $(OUTDIR) + +# ADD BASE CPP /nologo /W3 /GX /YX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /FR /c +# ADD CPP /nologo /W3 /GX /YX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /FR /c +CPP_PROJ=/nologo /W3 /GX /YX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE"\ + /FR$(INTDIR)/ /Fp$(OUTDIR)/"checkdisk.pch" /Fo$(INTDIR)/ /c +CPP_OBJS=.\WinRel/ +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +BSC32_FLAGS=/nologo /o$(OUTDIR)/"checkdisk.bsc" +BSC32_SBRS= \ + $(INTDIR)/checkdisk.sbr \ + $(INTDIR)/util_io.sbr + +$(OUTDIR)/checkdisk.bsc : $(OUTDIR) $(BSC32_SBRS) + $(BSC32) @<< + $(BSC32_FLAGS) $(BSC32_SBRS) +<< + +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /NOLOGO /SUBSYSTEM:console /MACHINE:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib /NOLOGO /SUBSYSTEM:console /MACHINE:I386 +LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib /NOLOGO\ + /SUBSYSTEM:console /INCREMENTAL:no /PDB:$(OUTDIR)/"checkdisk.pdb" /MACHINE:I386\ + /OUT:$(OUTDIR)/"checkdisk.exe" +DEF_FILE= +LINK32_OBJS= \ + $(INTDIR)/checkdisk.obj \ + $(INTDIR)/util_io.obj + +$(OUTDIR)/checkdisk.exe : $(OUTDIR) $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ELSEIF "$(CFG)" == "Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "WinDebug" +# PROP BASE Intermediate_Dir "WinDebug" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "WinDebug" +# PROP Intermediate_Dir "WinDebug" +OUTDIR=.\WinDebug +INTDIR=.\WinDebug + +ALL : $(OUTDIR)/checkdisk.exe $(OUTDIR)/checkdisk.bsc + +$(OUTDIR) : + if not exist $(OUTDIR)/nul mkdir $(OUTDIR) + +# ADD BASE CPP /nologo /W3 /GX /Zi /YX /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /FR /c +# ADD CPP /nologo /W3 /GX /Zi /YX /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /FR /c +CPP_PROJ=/nologo /W3 /GX /Zi /YX /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE"\ + /FR$(INTDIR)/ /Fp$(OUTDIR)/"checkdisk.pch" /Fo$(INTDIR)/\ + /Fd$(OUTDIR)/"checkdisk.pdb" /c +CPP_OBJS=.\WinDebug/ +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +BSC32_FLAGS=/nologo /o$(OUTDIR)/"checkdisk.bsc" +BSC32_SBRS= \ + $(INTDIR)/checkdisk.sbr \ + $(INTDIR)/util_io.sbr + +$(OUTDIR)/checkdisk.bsc : $(OUTDIR) $(BSC32_SBRS) + $(BSC32) @<< + $(BSC32_FLAGS) $(BSC32_SBRS) +<< + +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /NOLOGO /SUBSYSTEM:console /DEBUG /MACHINE:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib /NOLOGO /SUBSYSTEM:console /DEBUG /MACHINE:I386 +LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib /NOLOGO\ + /SUBSYSTEM:console /INCREMENTAL:yes /PDB:$(OUTDIR)/"checkdisk.pdb" /DEBUG\ + /MACHINE:I386 /OUT:$(OUTDIR)/"checkdisk.exe" +DEF_FILE= +LINK32_OBJS= \ + $(INTDIR)/checkdisk.obj \ + $(INTDIR)/util_io.obj + +$(OUTDIR)/checkdisk.exe : $(OUTDIR) $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ENDIF + +.c{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.cpp{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.cxx{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +################################################################################ +# Begin Group "Source Files" + +################################################################################ +# Begin Source File + +SOURCE=.\checkdisk.c +DEP_CHECK=\ + .\util_io.h\ + \MSVC20\INCLUDE\sys\types.h\ + \MSVC20\INCLUDE\sys\stat.h + +$(INTDIR)/checkdisk.obj : $(SOURCE) $(DEP_CHECK) $(INTDIR) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\util_io.c + +$(INTDIR)/util_io.obj : $(SOURCE) $(INTDIR) + +# End Source File +# End Group +# End Project +################################################################################ diff --git a/Ibm1130/utils/diskview.c b/Ibm1130/utils/diskview.c new file mode 100644 index 00000000..42fa37d2 --- /dev/null +++ b/Ibm1130/utils/diskview.c @@ -0,0 +1,612 @@ +/* + * (C) Copyright 2002, Brian Knittel. + * You may freely use this program, but: it offered strictly on an AS-IS, AT YOUR OWN + * RISK basis, there is no warranty of fitness for any purpose, and the rest of the + * usual yada-yada. Please keep this notice and the copyright in any distributions + * or modifications. + * + * This is not a supported product, but I welcome bug reports and fixes. + * Mail to sim@ibm1130.org + */ + +// DISKVIEW - lists contents of an 1130 system disk image file. Not finished yet. +// needs LET/SLET listing routine. +// +// usage: +// diskview -v diskfile + +#include +#include +#include +#include +#include "util_io.h" + +#define BETWEEN(v,a,b) (((v) >= (a)) && ((v) <= (b))) +#define MIN(a,b) (((a) <= (b)) ? (a) : (b)) +#define MAX(a,b) (((a) >= (b)) ? (a) : (b)) + +#ifndef TRUE +# define TRUE 1 +# define FALSE 0 +# define BOOL int +#endif + +#define NOT_DEF 0x0658 // defective cylinder table entry means no defect + +#define DSK_NUMWD 321 /* words/sector */ +#define DSK_NUMCY 203 /* cylinders/drive */ +#define DSK_SECCYL 8 /* sectors per cylinder */ +#define SECLEN 320 /* data words per sector */ +#define SLETLEN ((3*SECLEN)/4) /* length of slet in records */ + +typedef unsigned short WORD; + +FILE *fp; +WORD buf[DSK_NUMWD]; +WORD dcom[DSK_NUMWD]; + +#pragma pack(2) +struct tag_slet { + WORD phid; + WORD addr; + WORD nwords; + WORD sector; +} slet[SLETLEN]; + +#pragma pack() + +WORD dcyl[3]; +BOOL verbose = FALSE; + +void checksectors (void); +void dump_id (void); +void dump_dcom (void); +void dump_resmon (void); +void dump_slet (void); +void dump_hdng (void); +void dump_scra (void); +void dump_let (void); +void dump_flet (void); +void dump_cib (void); +void getsector (int sec, WORD *sbuf); +void getdcyl (void); +char *lowcase (char *str); + +void bail(char *fmt, ...); +char *trim (char *s); + +int main (int argc, char **argv) +{ + char *fname = NULL, *arg; + static char usestr[] = "Usage: diskview [-v] filename"; + int i; + + for (i = 1; i < argc;) { + arg = argv[i++]; + if (*arg == '-') { + arg++; + lowcase(arg); + while (*arg) { + switch (*arg++) { + case 'v': + verbose = TRUE; + break; + + default: + bail(usestr); + } + } + } + else if (fname == NULL) + fname = arg; + else + bail(usestr); + } + + if (fname == NULL) + bail(usestr); + + if ((fp = fopen(fname, "rb")) == NULL) { + perror(fname); + return 2; + } + + printf("%s:\n", fname); + + checksectors(); + getdcyl(); + + dump_id(); // ID & coldstart + dump_dcom(); // DCOM + dump_resmon(); // resident image + dump_slet(); // SLET + dump_hdng(); // heading sector + dump_scra(); + dump_flet(); + dump_cib(); + dump_let(); + + fclose(fp); + return 0; +} + +// checksectors - verify that all sectors are properly numbered + +void checksectors () +{ + WORD sec = 0; + + fseek(fp, 0, SEEK_SET); + + for (sec = 0; sec < DSK_NUMCY*DSK_SECCYL; sec++) { + if (fxread(buf, sizeof(WORD), DSK_NUMWD, fp) != DSK_NUMWD) + bail("File read error or not a disk image file"); + + if (buf[0] != sec) + bail("Sector /%x is misnumbered, run checkdisk [-f]", sec); + } +} + +// get defective cylinder list + +void getdcyl (void) +{ + fseek(fp, sizeof(WORD), SEEK_SET); // skip sector count + if (fxread(dcyl, sizeof(WORD), 3, fp) != 3) + bail("Unable to read defective cylinder table"); +} + +// getsector - read specified absolute sector + +void getsector (int sec, WORD *sbuf) +{ + int i, cyl, ssec; + + sec &= 0x7FF; // mask of drive bits, if any + + cyl = sec / DSK_SECCYL; // get cylinder + ssec = sec & ~(DSK_SECCYL-1); // mask to get starting sector of cylinder + for (i = 0; i < 3; i++) { // map through defective cylinder table + if (dcyl[i] == ssec) { + sec &= (DSK_SECCYL-1); // mask to get base sector + cyl = DSK_NUMCY-3+i; // replacements are last three on disk + sec += cyl*DSK_SECCYL; // add new cylinder offset + break; + } + } + // read the sector + if (fseek(fp, (sec*DSK_NUMWD+1)*sizeof(WORD), SEEK_SET) != 0) + bail("File seek failed"); + + if (fxread(sbuf, sizeof(WORD), DSK_NUMWD, fp) != DSK_NUMWD) + bail("File read error or not a disk image file"); +} + +void dump (int nwords) +{ + int i, nline = 0; + + for (i = 0; i < nwords; i++) { + if (nline == 16) { + putchar('\n'); + nline = 0; + } + + printf("%04x", buf[i]); + nline++; + } + putchar('\n'); +} + +void showmajor (char *label) +{ + int i; + + printf("\n--- %s ", label); + + for (i = strlen(label); i < 40; i++) + putchar('-'); + + putchar('\n'); + putchar('\n'); +} + +void name (char *label) +{ + printf("%-32.32s ", label); +} + +void pbf (char *label, WORD *buf, int nwords) +{ + int i, nout; + + name(label); + + for (i = nout = 0; i < nwords; i++, nout++) { + if (nout == 8) { + putchar('\n'); + name(""); + nout = 0; + } + printf(" %04x", buf[i]); + } + + putchar('\n'); +} + +void prt (char *label, char *fmt, ...) +{ + va_list args; + + name(label); + + putchar(' '); + va_start(args, fmt); + vprintf(fmt, args); + va_end(args); + + putchar('\n'); +} + +void dump_id (void) +{ + showmajor("Sector 0 - ID & coldstart"); + getsector(0, buf); + + pbf("DCYL def cyl table", buf+ 0, 3); + pbf("CIDN cart id", buf+ 3, 1); + pbf(" copy code", buf+ 4, 1); + pbf("DTYP disk type", buf+ 7, 1); + pbf(" diskz copy", buf+ 30, 8); + pbf(" cold start pgm",buf+270, 8); +} + +// EQUIVALENCES FOR DCOM PARAMETERS +#define NAME 4 // NAME OF PROGRAM/CORE LOAD +#define DBCT 6 // BLOCK CT OF PROGRAM/CORE LOAD +#define FCNT 7 // FILES SWITCH +#define SYSC 8 // SYSTEM/NON-SYSTEM CARTRIDGE INDR +#define JBSW 9 // JOBT SWITCH +#define CBSW 10 // CLB-RETURN SWITCH +#define LCNT 11 // NO. OF LOCALS +#define MPSW 12 // CORE MAP SWITCH +#define MDF1 13 // NO. DUP CTRL RECORDS (MODIF) +#define MDF2 14 // ADDR OF MODIF BUFFER +#define NCNT 15 // NO. OF NOCALS +#define ENTY 16 // RLTV ENTRY ADDR OF PROGRAM +#define RP67 17 // 1442-5 SWITCH +#define TODR 18 // OBJECT WORK STORAGE DRIVE CODE +#define FHOL 20 // ADDR LARGEST HOLE IN FIXED AREA +#define FSZE 21 // BLK CNT LARGEST HOLE IN FXA +#define UHOL 22 // ADDR LAST HOLE IN USER AREA 2-10 +#define USZE 23 // BLK CNT LAST HOLE IN UA 2-10 +#define DCSW 24 // DUP CALL SWITCH +#define PIOD 25 // PRINCIPAL I/O DEVICE INDICATOR +#define PPTR 26 // PRINCIPAL PRINT DEVICE INDICATOR +#define CIAD 27 // RLTV ADDR IN @STRT OF CIL ADDR +#define ACIN 28 // AVAILABLE CARTRIDGE INDICATOR +#define GRPH 29 // 2250 INDICATOR 2G2 +#define GCNT 30 // NO. G2250 RECORDS 2G2 +#define LOSW 31 // LOCAL-CALLS-LOCAL SWITCH 2-2 +#define X3SW 32 // SPECIAL ILS SWITCH 2-2 +#define ECNT 33 // NO. OF *EQUAT RCDS 2-4 +#define ANDU 35 // 1+BLK ADDR END OF UA (ADJUSTED) +#define BNDU 40 // 1+BLK ADDR END OF UA (BASE) +#define FPAD 45 // FILE PROTECT ADDR +#define PCID 50 // CARTRIDGE ID, PHYSICAL DRIVE +#define CIDN 55 // CARTRIDGE ID, LOGICAL DRIVE +#define CIBA 60 // SCTR ADDR OF CIB +#define SCRA 65 // SCTR ADDR OF SCRA +#define FMAT 70 // FORMAT OF PROG IN WORKING STG +#define FLET 75 // SCTR ADDR 1ST SCTR OF FLET +#define ULET 80 // SCTR ADDR 1ST SCTR OF LET +#define WSCT 85 // BLK CNT OF PROG IN WORKING STG +#define CSHN 90 // NO. SCTRS IN CUSHION AREA + +struct tag_dcominfo { + char *nm; + int offset; + char *descr; +} dcominfo[] = { + "NAME", 4, "NAME OF PROGRAM/CORE LOAD", + "DBCT", 6, "BLOCK CT OF PROGRAM/CORE LOAD", + "FCNT", 7, "FILES SWITCH", + "SYSC", 8, "SYSTEM/NON-SYSTEM CARTRIDGE INDR", + "JBSW", 9, "JOBT SWITCH", + "CBSW", 10, "CLB-RETURN SWITCH", + "LCNT", 11, "NO. OF LOCALS", + "MPSW", 12, "CORE MAP SWITCH", + "MDF1", 13, "NO. DUP CTRL RECORDS (MODIF)", + "MDF2", 14, "ADDR OF MODIF BUFFER", + "NCNT", 15, "NO. OF NOCALS", + "ENTY", 16, "RLTV ENTRY ADDR OF PROGRAM", + "RP67", 17, "1442-5 SWITCH", + "TODR", 18, "OBJECT WORK STORAGE DRIVE CODE", + "FHOL", 20, "ADDR LARGEST HOLE IN FIXED AREA", + "FSZE", 21, "BLK CNT LARGEST HOLE IN FXA", + "UHOL", 22, "ADDR LAST HOLE IN USER AREA", + "USZE", 23, "BLK CNT LAST HOLE IN UA", + "DCSW", 24, "DUP CALL SWITCH", + "PIOD", 25, "PRINCIPAL I/O DEVICE INDICATOR", + "PPTR", 26, "PRINCIPAL PRINT DEVICE INDICATOR", + "CIAD", 27, "RLTV ADDR IN @STRT OF CIL ADDR", + "ACIN", 28, "AVAILABLE CARTRIDGE INDICATOR", + "GRPH", 29, "2250 INDICATOR", + "GCNT", 30, "NO. G2250 RECORDS", + "LOSW", 31, "LOCAL-CALLS-LOCAL SWITCH", + "X3SW", 32, "SPECIAL ILS SWITCH", + "ECNT", 33, "NO. OF *EQUAT RCDS", + "ANDU", 35, "1+BLK ADDR END OF UA (ADJUSTED)", + "BNDU", 40, "1+BLK ADDR END OF UA (BASE)", + "FPAD", 45, "FILE PROTECT ADDR", + "PCID", 50, "CARTRIDGE ID, PHYSICAL DRIVE", + "CIDN", 55, "CARTRIDGE ID, LOGICAL DRIVE", + "CIBA", 60, "SCTR ADDR OF CIB", + "SCRA", 65, "SCTR ADDR OF SCRA", + "FMAT", 70, "FORMAT OF PROG IN WORKING STG", + "FLET", 75, "SCTR ADDR 1ST SCTR OF FLET", + "ULET", 80, "SCTR ADDR 1ST SCTR OF LET", + "WSCT", 85, "BLK CNT OF PROG IN WORKING STG", + "CSHN", 90, "NO. SCTRS IN CUSHION AREA", + NULL +}; + +void dump_dcom (void) +{ + struct tag_dcominfo *d; + char txt[50]; + + showmajor("Sector 1 - DCOM"); + getsector(1, dcom); + + for (d = dcominfo; d->nm != NULL; d++) { + sprintf(txt, "%-4.4s %s", d->nm, d->descr); + pbf(txt, dcom+d->offset, 1); + } +} + +void dump_resmon (void) +{ + showmajor("Sector 2 - Resident Image"); + getsector(2, buf); + dump(verbose ? SECLEN : 32); +} + +struct { + int pfrom, pto; + int printed; + char *name; +} sletinfo[] = { + 0x01, 0x12, FALSE, "DUP", + 0x1F, 0x39, FALSE, "Fortran", + 0x51, 0x5C, FALSE, "Cobol", + 0x6E, 0x74, FALSE, "Supervisor", + 0x78, 0x84, FALSE, "Core Load Builder", + 0x8C, 0x8C, FALSE, "Sys 1403 prt", + 0x8D, 0x8D, FALSE, "Sys 1132 prt", + 0x8E, 0x8E, FALSE, "Sys console prt", + 0x8F, 0x8F, FALSE, "Sys 2501 rdr", + 0x90, 0x90, FALSE, "Sys 1442 rdr/pun", + 0x91, 0x91, FALSE, "Sys 1134 paper tape", + 0x92, 0x92, FALSE, "Sys kbd", + 0x93, 0x93, FALSE, "Sys 2501/1442 conv", + 0x94, 0x94, FALSE, "Sys 1134 conv", + 0x95, 0x95, FALSE, "Sys kbd conv", + 0x96, 0x96, FALSE, "Sys diskz", + 0x97, 0x97, FALSE, "Sys disk1", + 0x98, 0x98, FALSE, "Sys diskn", + 0x99, 0x99, FALSE, "(primary print)", + 0x9A, 0x9A, FALSE, "(primary input)", + 0x9B, 0x9B, FALSE, "(primary input excl kbd)", + 0x9C, 0x9C, FALSE, "(primary sys conv)", + 0x9D, 0x9D, FALSE, "(primary conv excl kbd)", + 0xA0, 0xA1, FALSE, "Core Image Loader", + 0xB0, 0xCC, FALSE, "RPG", + 0xCD, 0xCE, FALSE, "Dup Part 2", + 0xCF, 0xF6, FALSE, "Macro Assembler", + 0 +}; + +void dump_slet (void) +{ + int i, j, iphase, nsecs, sec, max_sec = 0; + char sstr[16], *smark; + + showmajor("Sectors 3-5 - SLET"); + for (i = 0; i < 3; i++) { + getsector(3+i, buf); + memmove(((WORD *) slet)+SECLEN*i, buf, SECLEN*sizeof(WORD)); + } + + printf("# PHID Addr Len Sector Secs\n"); + printf("------------------------------------------\n"); + for (i = 0; i < SLETLEN; i++) { + if (slet[i].phid == 0) + break; + + sec = slet[i].sector; + iphase = (int) (signed short) slet[i].phid; + nsecs = (slet[i].nwords + SECLEN-1)/SECLEN; + + if (sec & 0xF800) { + smark = "*"; + sec &= 0x7FF; + } + else + smark = " "; + + for (j = 0; sletinfo[j].pfrom != 0; j++) + if (sletinfo[j].pfrom <= iphase && sletinfo[j].pto >= iphase) + break; + + sprintf(sstr, "(%d.%d)", sec / DSK_SECCYL, slet[i].sector % DSK_SECCYL); + + printf("%3d %04x %4d %04x %04x %04x %s %-7s %3x", + i, slet[i].phid, iphase, slet[i].addr, slet[i].nwords, slet[i].sector, smark, sstr, nsecs); + + if (iphase < 0) + iphase = -iphase; + + if (sletinfo[j].pfrom == 0) + printf(" ???"); + else if (! sletinfo[j].printed) { + printf(" %s", sletinfo[j].name); + sletinfo[j].printed = TRUE; + } + + for (j = 0; j < i; j++) { + if (sec == (slet[j].sector & 0x7FF)) { + printf(" (same as %04x)", slet[j].phid); + break; + } + } + + max_sec = MAX(max_sec, sec+nsecs-1); // find last sector used + + putchar('\n'); + + if (i >= 15 && ! verbose) { + printf("...\n"); + break; + } + } +} + +int ascii_to_ebcdic_table[128] = +{ + 0x00,0x01,0x02,0x03,0x37,0x2d,0x2e,0x2f, 0x16,0x05,0x25,0x0b,0x0c,0x0d,0x0e,0x0f, + 0x10,0x11,0x12,0x13,0x3c,0x3d,0x32,0x26, 0x18,0x19,0x3f,0x27,0x1c,0x1d,0x1e,0x1f, + 0x40,0x5a,0x7f,0x7b,0x5b,0x6c,0x50,0x7d, 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, 0xc8,0xc9,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6, + 0xd7,0xd8,0xd9,0xe2,0xe3,0xe4,0xe5,0xe6, 0xe7,0xe8,0xe9,0xba,0xe0,0xbb,0xb0,0x6d, + 0x79,0x81,0x82,0x83,0x84,0x85,0x86,0x87, 0x88,0x89,0x91,0x92,0x93,0x94,0x95,0x96, + 0x97,0x98,0x99,0xa2,0xa3,0xa4,0xa5,0xa6, 0xa7,0xa8,0xa9,0xc0,0x4f,0xd0,0xa1,0x07, +}; + +int ebcdic_to_ascii (int ch) +{ + int j; + + for (j = 32; j < 128; j++) + if (ascii_to_ebcdic_table[j] == ch) + return j; + + return '?'; +} + +#define HDR_LEN 120 + +void dump_hdng(void) +{ + int i; + char str[HDR_LEN+1], *p = str; + + showmajor("Sector 7 - Heading"); + getsector(7, buf); + + for (i = 0; i < (HDR_LEN/2); i++) { + *p++ = ebcdic_to_ascii((buf[i] >> 8) & 0xFF); + *p++ = ebcdic_to_ascii( buf[i] & 0xFF); + } + + *p = '\0'; + trim(str); + printf("%s\n", str); +} + +BOOL mget (int offset, char *name) +{ + char title[80]; + + if (dcom[offset] == 0) + return FALSE; + + getsector(dcom[offset], buf); + sprintf(title, "Sector %x - %s", dcom[offset], name); + showmajor(title); + return TRUE; +} + +void dump_scra (void) +{ + if (! mget(SCRA, "SCRA")) + return; + + dump(verbose ? SECLEN : 32); +} + +void dump_let (void) +{ + if (! mget(ULET, "LET")) + return; +} + +void dump_flet (void) +{ + if (! mget(FLET, "FLET")) + return; +} + +void dump_cib (void) +{ + if (! mget(CIBA, "CIB")) + return; + + dump(verbose ? SECLEN : 32); +} + +#define LFHD 5 // WORD COUNT OF LET/FLET HEADER PMN09970 +#define LFEN 3 // NO OF WDS PER LET/FLET ENTRY PMN09980 +#define SCTN 0 // RLTY ADDR OF LET/FLET SCTR NO. PMN09990 +#define UAFX 1 // RLTV ADDR OF SCTR ADDR OF UA/FXA PMN10000 +#define WDSA 3 // RLTV ADDR OF WDS AVAIL IN SCTR PMN10010 +#define NEXT 4 // RLTV ADDR OF ADDR NEXT SCTR PMN10020 +#define LFNM 0 // RLTV ADDR OF LET/FLET ENTRY NAME PMN10030 +#define BLCT 2 // RLTV ADDR OF LET/FLET ENTRY DBCT PMN10040 + +void bail (char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + fprintf(stderr, fmt, args); + va_end(args); + putchar('\n'); + + exit(1); +} + +// --------------------------------------------------------------------------------- +// trim - remove trailing whitespace from string s +// --------------------------------------------------------------------------------- + +char *trim (char *s) +{ + char *os = s, *nb; + + for (nb = s-1; *s; s++) + if (*s > ' ') + nb = s; + + nb[1] = '\0'; + return os; +} + +/* ------------------------------------------------------------------------ + * lowcase - force a string to lowercase (ASCII) + * ------------------------------------------------------------------------ */ + +char *lowcase (char *str) +{ + char *s; + + for (s = str; *s; s++) { + if (*s >= 'A' && *s <= 'Z') + *s += 32; + } + + return str; +} + diff --git a/Ibm1130/utils/diskview.mak b/Ibm1130/utils/diskview.mak new file mode 100644 index 00000000..ef9a8cf3 --- /dev/null +++ b/Ibm1130/utils/diskview.mak @@ -0,0 +1,175 @@ +# Microsoft Visual C++ Generated NMAKE File, Format Version 2.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +!IF "$(CFG)" == "" +CFG=Win32 Debug +!MESSAGE No configuration specified. Defaulting to Win32 Debug. +!ENDIF + +!IF "$(CFG)" != "Win32 Release" && "$(CFG)" != "Win32 Debug" +!MESSAGE Invalid configuration "$(CFG)" specified. +!MESSAGE You can specify a configuration when running NMAKE on this makefile +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "diskview.mak" CFG="Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE +!ERROR An invalid configuration is specified. +!ENDIF + +################################################################################ +# Begin Project +# PROP Target_Last_Scanned "Win32 Debug" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "WinRel" +# PROP BASE Intermediate_Dir "WinRel" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "WinRel" +# PROP Intermediate_Dir "WinRel" +OUTDIR=.\WinRel +INTDIR=.\WinRel + +ALL : $(OUTDIR)/diskview.exe $(OUTDIR)/diskview.bsc + +$(OUTDIR) : + if not exist $(OUTDIR)/nul mkdir $(OUTDIR) + +# ADD BASE CPP /nologo /W3 /GX /YX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /FR /c +# ADD CPP /nologo /W3 /GX /YX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /FR /c +CPP_PROJ=/nologo /W3 /GX /YX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE"\ + /FR$(INTDIR)/ /Fp$(OUTDIR)/"diskview.pch" /Fo$(INTDIR)/ /c +CPP_OBJS=.\WinRel/ +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +BSC32_FLAGS=/nologo /o$(OUTDIR)/"diskview.bsc" +BSC32_SBRS= \ + $(INTDIR)/diskview.sbr \ + $(INTDIR)/util_io.sbr + +$(OUTDIR)/diskview.bsc : $(OUTDIR) $(BSC32_SBRS) + $(BSC32) @<< + $(BSC32_FLAGS) $(BSC32_SBRS) +<< + +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /NOLOGO /SUBSYSTEM:console /MACHINE:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib /NOLOGO /SUBSYSTEM:console /MACHINE:I386 +LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib /NOLOGO /SUBSYSTEM:console\ + /INCREMENTAL:no /PDB:$(OUTDIR)/"diskview.pdb" /MACHINE:I386\ + /OUT:$(OUTDIR)/"diskview.exe" +DEF_FILE= +LINK32_OBJS= \ + $(INTDIR)/diskview.obj \ + $(INTDIR)/util_io.obj + +$(OUTDIR)/diskview.exe : $(OUTDIR) $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ELSEIF "$(CFG)" == "Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "WinDebug" +# PROP BASE Intermediate_Dir "WinDebug" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "WinDebug" +# PROP Intermediate_Dir "WinDebug" +OUTDIR=.\WinDebug +INTDIR=.\WinDebug + +ALL : $(OUTDIR)/diskview.exe $(OUTDIR)/diskview.bsc + +$(OUTDIR) : + if not exist $(OUTDIR)/nul mkdir $(OUTDIR) + +# ADD BASE CPP /nologo /W3 /GX /Zi /YX /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /FR /c +# ADD CPP /nologo /W3 /GX /Zi /YX /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /FR /c +CPP_PROJ=/nologo /W3 /GX /Zi /YX /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE"\ + /FR$(INTDIR)/ /Fp$(OUTDIR)/"diskview.pch" /Fo$(INTDIR)/\ + /Fd$(OUTDIR)/"diskview.pdb" /c +CPP_OBJS=.\WinDebug/ +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +BSC32_FLAGS=/nologo /o$(OUTDIR)/"diskview.bsc" +BSC32_SBRS= \ + $(INTDIR)/diskview.sbr \ + $(INTDIR)/util_io.sbr + +$(OUTDIR)/diskview.bsc : $(OUTDIR) $(BSC32_SBRS) + $(BSC32) @<< + $(BSC32_FLAGS) $(BSC32_SBRS) +<< + +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /NOLOGO /SUBSYSTEM:console /DEBUG /MACHINE:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib /NOLOGO /SUBSYSTEM:console /DEBUG /MACHINE:I386 +LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib /NOLOGO /SUBSYSTEM:console\ + /INCREMENTAL:yes /PDB:$(OUTDIR)/"diskview.pdb" /DEBUG /MACHINE:I386\ + /OUT:$(OUTDIR)/"diskview.exe" +DEF_FILE= +LINK32_OBJS= \ + $(INTDIR)/diskview.obj \ + $(INTDIR)/util_io.obj + +$(OUTDIR)/diskview.exe : $(OUTDIR) $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ENDIF + +.c{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.cpp{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.cxx{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +################################################################################ +# Begin Group "Source Files" + +################################################################################ +# Begin Source File + +SOURCE=.\diskview.c + +$(INTDIR)/diskview.obj : $(SOURCE) $(INTDIR) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\util_io.c +DEP_UTIL_=\ + .\util_io.h + +$(INTDIR)/util_io.obj : $(SOURCE) $(DEP_UTIL_) $(INTDIR) + +# End Source File +# End Group +# End Project +################################################################################ diff --git a/Ibm1130/utils/makefile b/Ibm1130/utils/makefile new file mode 100644 index 00000000..612b3c67 --- /dev/null +++ b/Ibm1130/utils/makefile @@ -0,0 +1,47 @@ +# (This makefile is for operating systems other than Windows, +# or compilers other than Microsoft's. For MS builds, use the +# .mak files). +# +# CC Command +# +# Note: -O2 is sometimes broken in GCC when setjump/longjump is being +# used. Try -O2 only with released simulators. +# + +CC = gcc -O0 -lm -I . +#CC = gcc -O2 -g -lm -I . + +BIN = + +IOLIB_DEP = util_io.c util_io.h +IOLIB_SRC = util_io.c + +# +# Build everything +# + +all : ${BIN}asm1130 ${BIN}bindump ${BIN}checkdisk \ + ${BIN}diskview ${BIN}mkboot ${BIN}viewdeck + +# +# Individual builds +# + +${BIN}asm1130 : asm1130.c ${IOLIB_DEP} + ${CC} asm1130.c ${IOLIB_SRC} -o $@ + +${BIN}bindump : bindump.c ${IOLIB_DEP} + ${CC} bindump.c ${IOLIB_SRC} -o $@ + +${BIN}checkdisk : checkdisk.c ${IOLIB_DEP} + ${CC} checkdisk.c ${IOLIB_SRC} -o $@ + +${BIN}diskview : diskview.c ${IOLIB_DEP} + ${CC} diskview.c ${IOLIB_SRC} -o $@ + +${BIN}mkboot : mkboot.c ${IOLIB_DEP} + ${CC} mkboot.c ${IOLIB_SRC} -o $@ + +${BIN}viewdeck : viewdeck.c ${IOLIB_DEP} + ${CC} viewdeck.c ${IOLIB_SRC} -o $@ + diff --git a/Ibm1130/utils/mkboot.c b/Ibm1130/utils/mkboot.c new file mode 100644 index 00000000..6d1d9750 --- /dev/null +++ b/Ibm1130/utils/mkboot.c @@ -0,0 +1,706 @@ +/* + * (C) Copyright 2002, Brian Knittel. + * You may freely use this program, but: it offered strictly on an AS-IS, AT YOUR OWN + * RISK basis, there is no warranty of fitness for any purpose, and the rest of the + * usual yada-yada. Please keep this notice and the copyright in any distributions + * or modifications. + * + * This is not a supported product, but I welcome bug reports and fixes. + * Mail to sim@ibm1130.org + */ + +// --------------------------------------------------------------------------------- +// MKBOOT - reads card loader format cards and produces an absolute core image that +// can then be dumped out in 1130 IPL, 1800 IPL or Core Image loader formats. +// +// Usage: mkboot [-v] binfile outfile [1130|1800|core [loaddr [hiaddr [ident]]]]" +// +// Arguments: +// binfile - name of assembler output file (card loader format, absolute output) +// outfile - name of output file to create +// mode - output mode, default is 1130 IPL format +// loaddr - low address to dump. Default is lowest address loaded from binfile +// hiaddr - high address to dump. Defult is highest address loaded from binfile +// ident - ident string to write in last 8 columns. Omit when when writing an +// 1130 IPL card that requires all 80 columns of data. +// +// Examples: +// mkboot somefile.bin somefile.ipl 1130 +// +// loads somefile.bin, writes object in 1130 IPL format to somefile.ipl +// Up to 80 columns will be written depending on what the object actually uses +// +// mkboot somefile.bin somefile.ipl 1130 0 48 SOMEF +// +// loads somefile.bin. Writes 72 columns (hex 48), with ident columns 73-80 = SOMEF001 +// +// mkboot somefile.bin somefile.dat core 0 0 SOMEF001 +// +// loads somefile.bin and writes a core image format deck with ident SOMEF001, SOMEF002, etc +// +// For other examples of usage, see MKDMS.BAT +// +// 1.00 - 2002Apr18 - first release. Tested only under Win32. The core image +// loader format is almost certainly wrong. Cannot handle +// relocatable input decks, but it works well enough to +// load DSYSLDR1 which is what we are after here. +// --------------------------------------------------------------------------------- + +#include +#include +#include +#include +#include "util_io.h" + +#ifndef TRUE + #define BOOL int + #define TRUE 1 + #define FALSE 0 +#endif + +#ifndef _WIN32 + int strnicmp (char *a, char *b, int n); + int strcmpi (char *a, char *b); +#endif + +#define BETWEEN(v,a,b) (((v) >= (a)) && ((v) <= (b))) +#define MIN(a,b) (((a) <= (b)) ? (a) : (b)) +#define MAX(a,b) (((a) >= (b)) ? (a) : (b)) + +#define MAXADDR 4096 + +typedef enum {R_ABSOLUTE = 0, R_RELATIVE = 1, R_LIBF = 2, R_CALL = 3} RELOC; + +typedef enum {B_1130, B_1800, B_CORE} BOOTMODE; + +BOOL verbose = FALSE; +char *infile = NULL, *outfile = NULL; +BOOTMODE mode = B_1130; +int addr_from = 0, addr_to = 79; +int outcols = 0; // columns written in using card output +int maxiplcols = 80; +char cardid[9]; // characters used for IPL card ID +int pta = 0; +int load_low = 0x7FFFFFF; +int load_high = 0; +unsigned short mem[MAXADDR]; // small core! + +// mkboot - load a binary object deck into core and dump requested bytes as a boot card + +void bail (char *msg); +void verify_checksum(unsigned short *card); +char *upcase (char *str); +void unpack (unsigned short *card, unsigned short *buf); +void dump (char *fname); +void loaddata (char *fname); +void write_1130 (void); +void write_1800 (void); +void write_core (void); +void flushcard(void); +int ascii_to_hollerith (int ch); +void corecard_init (void); +void corecard_writecard (char *sbrk_text); +void corecard_writedata (void); +void corecard_flush (void); +void corecard_setorg (int neworg); +void corecard_writew (int word, RELOC relative); +void corecard_endcard (void); + +char *fname = NULL; +FILE *fout; + +int main (int argc, char **argv) +{ + char *arg; + static char usestr[] = "Usage: mkboot [-v] binfile outfile [1130|1800|core [loaddr [hiaddr [ident]]]]"; + int i, ano = 0, ok; + + for (i = 1; i < argc; i++) { + arg = argv[i]; + if (*arg == '-') { + arg++; + while (*arg) { + switch (*arg++) { + case 'v': + verbose = TRUE; + break; + default: + bail(usestr); + } + } + } + else { + switch (ano++) { + case 0: + infile = arg; + break; + + case 1: + outfile = arg; + break; + + case 2: + if (strcmp(arg, "1130") == 0) mode = B_1130; + else if (strcmp(arg, "1800") == 0) mode = B_1800; + else if (strcmpi(arg, "core") == 0) mode = B_CORE; + else bail(usestr); + break; + + case 3: + if (strnicmp(arg, "0x", 2) == 0) ok = sscanf(arg+2, "%x", &addr_from); + else if (arg[0] == '/') ok = sscanf(arg+1, "%x", &addr_from); + else ok = sscanf(arg, "%d", &addr_from); + if (ok != 1) bail(usestr); + break; + + case 4: + if (strnicmp(arg, "0x", 2) == 0) ok = sscanf(arg+2, "%x", &addr_to); + else if (arg[0] == '/') ok = sscanf(arg+1, "%x", &addr_to); + else ok = sscanf(arg, "%d", &addr_to); + if (ok != 1) bail(usestr); + break; + + case 5: + strncpy(cardid, arg, 9); + cardid[8] = '\0'; + upcase(cardid); + break; + + default: + bail(usestr); + } + } + } + + if (*cardid == '\0') + maxiplcols = (mode == B_1130) ? 80 : 72; + else { + while (strlen(cardid) < 8) + strcat(cardid, "0"); + maxiplcols = 72; + } + + loaddata(infile); + + if (mode == B_1800) + write_1800(); + else if (mode == B_CORE) + write_core(); + else + write_1130(); + + return 0; +} + +void write_1130 (void) +{ + int addr; + unsigned short word; + + if ((fout = fopen(outfile, "wb")) == NULL) { + perror(outfile); + exit(1); + } + + for (addr = addr_from; addr <= addr_to; addr++) { + if (outcols >= maxiplcols) + flushcard(); + + word = mem[addr]; + + // if F or L bits are set, or if high 2 bits of displacement are unequal, it's bad + if ((word & 0x0700) || ! (((word & 0x00C0) == 0) || ((word & 0x00C0) == 0x00C0))) + printf("Warning: word %04x @ %04x may not IPL properly\n", word & 0xFFFF, addr); + + word = ((word & 0xF800) >> 4) | (word & 0x7F); // convert to 1130 IPL format + + putc((word & 0x000F) << 4, fout); // write the 12 bits in little-endian binary AABBCC00 as CC00 AABB + putc((word & 0x0FF0) >> 4, fout); + outcols++; + } + flushcard(); + fclose(fout); +} + +void write_1800 (void) +{ + int addr; + unsigned short word; + + if ((fout = fopen(outfile, "wb")) == NULL) { + perror(outfile); + exit(1); + } + + for (addr = addr_from; addr <= addr_to; addr++) { + word = mem[addr]; + + if (outcols >= maxiplcols) + flushcard(); + + putc(0, fout); + putc(word & 0xFF, fout); // write the low 8 bits in little-endian binary + outcols++; + + putc(0, fout); + putc((word >> 8) & 0xFF, fout); // write the high 8 bits in little-endian binary + outcols++; + } + flushcard(); + fclose(fout); +} + +void write_core (void) +{ + int addr; + + if ((fout = fopen(outfile, "wb")) == NULL) { + perror(outfile); + exit(1); + } + + addr_from = load_low; + addr_to = load_high; + + maxiplcols = 72; + corecard_init(); + corecard_setorg(addr_from); + + for (addr = addr_from; addr <= addr_to; addr++) { + corecard_writew(mem[addr], 0); + } + + corecard_flush(); + corecard_endcard(); + fclose(fout); +} + +void flushcard (void) +{ + int i, hol, ndig; + char fmt[20], newdig[20]; + + if (outcols <= 0) + return; // nothing to flush + + while (outcols < maxiplcols) { // pad to required number of columns with blanks (no punches) + putc(0, fout); + putc(0, fout); + outcols++; + } + + if (*cardid) { // add label + for (i = 0; i < 8; i++) { // write label as specified + hol = ascii_to_hollerith(cardid[i] & 0x7F); + putc(hol & 0xFF, fout); + putc((hol >> 8) & 0xFF, fout); + } + + ndig = 0; // count trailing digits in the label + for (i = 8; --i >= 0; ndig++) + if (! isdigit(cardid[i])) + break; + + i++; // index of first digit in trailing sequence + + if (ndig > 0) { // if any, increment them + sprintf(fmt, "%%0%dd", ndig); // make, e.g. %03d + sprintf(newdig, fmt, atoi(cardid+i)+1); + newdig[ndig] = '\0'; // clip if necessary + strcpy(cardid+i, newdig); // replace for next card's sequence number + } + } + + outcols = 0; +} + +void show_data (unsigned short *buf) +{ + int i, n, jrel, rflag, nout, ch, reloc; + + n = buf[2] & 0x00FF; + + printf("%04x: ", buf[0]); + + jrel = 3; + nout = 0; + rflag = buf[jrel++]; + for (i = 0; i < n; i++) { + if (nout >= 8) { + rflag = buf[jrel++]; + putchar('\n'); + printf(" "); + nout = 0; + } + reloc = (rflag >> 14) & 0x03; + ch = (reloc == R_ABSOLUTE) ? ' ' : + (reloc == R_RELATIVE) ? 'R' : + (reloc == R_LIBF) ? 'L' : '@'; + + printf("%04x%c ", buf[9+i], ch); + rflag <<= 2; + nout++; + } + putchar('\n'); +} + +void loadcard (unsigned short *buf) +{ + int addr, n, i; + + addr = buf[0]; + n = buf[2] & 0x00FF; + + for (i = 0; i < n; i++) { + if (addr >= MAXADDR) + bail("Program doesn't fit into 4K"); + mem[addr] = buf[9+i]; + + load_low = MIN(addr, load_low); + load_high = MAX(addr, load_high); + addr++; + } +} + +void loaddata (char *fname) +{ + FILE *fp; + BOOL first = TRUE; + unsigned short card[80], buf[54], cardtype; + + if ((fp = fopen(fname, "rb")) == NULL) { + perror(fname); + exit(1); + } + + if (verbose) + printf("\n%s:\n", fname); + + while (fxread(card, sizeof(card[0]), 80, fp) > 0) { + unpack(card, buf); + verify_checksum(card); + + cardtype = (buf[2] >> 8) & 0xFF; + + if (cardtype == 1 && ! first) { // sector break + if (verbose) + printf("*SBRK\n"); + continue; + } + else { + switch (cardtype) { + case 0x01: + if (verbose) + printf("*ABS\n"); + break; + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + case 0x07: + bail("Data must be in absolute format"); + break; + + case 0x0F: + pta = buf[3]; // save program transfer address + if (verbose) + printf("*END\n"); + break; + + case 0x0A: + if (verbose) + show_data(buf); + loadcard(buf); + break; + default: + bail("Unexpected card type"); + } + } + first = FALSE; + } + + fclose(fp); +} + +void bail (char *msg) +{ + fprintf(stderr, "%s\n", msg); + exit(1); +} + +void unpack (unsigned short *card, unsigned short *buf) +{ + int i, j; + unsigned short wd1, wd2, wd3, wd4; + + for (i = j = 0; i < 54; i += 3, j += 4) { + wd1 = card[j]; + wd2 = card[j+1]; + wd3 = card[j+2]; + wd4 = card[j+3]; + + buf[i ] = (wd1 & 0xFFF0) | ((wd2 >> 12) & 0x000F); + buf[i+1] = ((wd2 << 4) & 0xFF00) | ((wd3 >> 8) & 0x00FF); + buf[i+2] = ((wd3 << 8) & 0xF000) | ((wd4 >> 4) & 0x0FFF); + } +} + +void verify_checksum (unsigned short *card) +{ +// unsigned short sum; + + if (card[1] == 0) // no checksum + return; + +// if (sum != card[1]) +// printf("Checksum %04x doesn't match card %04x\n", sum, card[1]); +} + +typedef struct { + int hollerith; + char ascii; +} CPCODE; + +static CPCODE cardcode_029[] = +{ + 0x0000, ' ', + 0x8000, '&', // + in 026 Fortran + 0x4000, '-', + 0x2000, '0', + 0x1000, '1', + 0x0800, '2', + 0x0400, '3', + 0x0200, '4', + 0x0100, '5', + 0x0080, '6', + 0x0040, '7', + 0x0020, '8', + 0x0010, '9', + 0x9000, 'A', + 0x8800, 'B', + 0x8400, 'C', + 0x8200, 'D', + 0x8100, 'E', + 0x8080, 'F', + 0x8040, 'G', + 0x8020, 'H', + 0x8010, 'I', + 0x5000, 'J', + 0x4800, 'K', + 0x4400, 'L', + 0x4200, 'M', + 0x4100, 'N', + 0x4080, 'O', + 0x4040, 'P', + 0x4020, 'Q', + 0x4010, 'R', + 0x3000, '/', + 0x2800, 'S', + 0x2400, 'T', + 0x2200, 'U', + 0x2100, 'V', + 0x2080, 'W', + 0x2040, 'X', + 0x2020, 'Y', + 0x2010, 'Z', + 0x0820, ':', + 0x0420, '#', // = in 026 Fortran + 0x0220, '@', // ' in 026 Fortran + 0x0120, '\'', + 0x00A0, '=', + 0x0060, '"', + 0x8820, 'c', // cent + 0x8420, '.', + 0x8220, '<', // ) in 026 Fortran + 0x8120, '(', + 0x80A0, '+', + 0x8060, '|', + 0x4820, '!', + 0x4420, '$', + 0x4220, '*', + 0x4120, ')', + 0x40A0, ';', + 0x4060, 'n', // not + 0x2820, 'x', // what? + 0x2420, ',', + 0x2220, '%', // ( in 026 Fortran + 0x2120, '_', + 0x20A0, '>', + 0x2060, '>', +}; + +int ascii_to_hollerith (int ch) +{ + int i; + + for (i = 0; i < sizeof(cardcode_029) / sizeof(CPCODE); i++) + if (cardcode_029[i].ascii == ch) + return cardcode_029[i].hollerith; + + return 0; +} + +// --------------------------------------------------------------------------------- +// corecard - routines to write IBM 1130 Card object format +// --------------------------------------------------------------------------------- + +unsigned short corecard[54]; // the 54 data words that can fit on a binary format card +int corecard_n = 0; // number of object words stored in corecard (0-45) +int corecard_seq = 1; // card output sequence number +int corecard_org = 0; // origin of current card-full +int corecard_maxaddr = 0; +BOOL corecard_first = TRUE; // TRUE when we're to write the program type card + +// corecard_init - prepare a new object data output card + +void corecard_init (void) +{ + memset(corecard, 0, sizeof(corecard)); // clear card data + corecard_n = 0; // no data + corecard[0] = corecard_org; // store load address + corecard_maxaddr = MAX(corecard_maxaddr, corecard_org-1); // save highest address written-to (this may be a BSS) +} + +// binard_writecard - emit a card. sbrk_text = NULL for normal data cards, points to comment text for sbrk card + +void corecard_writecard (char *sbrk_text) +{ + unsigned short binout[80]; + int i, j; + + for (i = j = 0; i < 54; i += 3, j += 4) { + binout[j ] = ( corecard[i] & 0xFFF0); + binout[j+1] = ((corecard[i] << 12) & 0xF000) | ((corecard[i+1] >> 4) & 0x0FF0); + binout[j+2] = ((corecard[i+1] << 8) & 0xFF00) | ((corecard[i+2] >> 8) & 0x00F0); + binout[j+3] = ((corecard[i+2] << 4) & 0xFFF0); + } + + for (i = 0; i < 72; i++) { + putc(binout[i] & 0xFF, fout); + putc((binout[i] >> 8) & 0xFF, fout); + } + + outcols = 72; // add the ident + flushcard(); +} + +// binard_writedata - emit an object data card + +void corecard_writedata (void) +{ + corecard[1] = 0; // checksum + corecard[2] = 0x0000 | corecard_n; // data card type + word count + corecard_writecard(FALSE); // emit the card +} + +// corecard_flush - flush any pending binary data + +void corecard_flush (void) +{ + if (corecard_n > 0) + corecard_writedata(); + + corecard_init(); +} + +// corecard_setorg - set the origin + +void corecard_setorg (int neworg) +{ + corecard_org = neworg; // set origin for next card + corecard_flush(); // flush any current data & store origin +} + +// corecard_writew - write a word to the current output card. + +void corecard_writew (int word, RELOC relative) +{ + if (corecard_n >= 50) // flush full card buffer (must be even) + corecard_flush(); + + corecard[3+corecard_n++] = word; + corecard_org++; +} + +// corecard_endcard - write end of program card + +void corecard_endcard (void) +{ + corecard_flush(); + + corecard[0] = 0; // effective length: add 1 to max origin, then 1 more to round up + corecard[1] = 0; + corecard[2] = 0x8000; // they look for negative bit but all else must be zero + corecard[52] = 0xabcd; // index register 3 value, this is for fun + corecard[53] = pta; // hmmm + + corecard_writecard(NULL); +} + +/* ------------------------------------------------------------------------ + * upcase - force a string to uppercase (ASCII) + * ------------------------------------------------------------------------ */ + +char *upcase (char *str) +{ + char *s; + + for (s = str; *s; s++) { + if (*s >= 'a' && *s <= 'z') + *s -= 32; + } + + return str; +} + +#ifndef _WIN32 + +int strnicmp (char *a, char *b, int n) +{ + int ca, cb; + + for (;;) { + if (--n < 0) // still equal after n characters? quit now + return 0; + + if ((ca = *a) == 0) // get character, stop on null terminator + return *b ? -1 : 0; + + if (ca >= 'a' && ca <= 'z') // fold lowercase to uppercase + ca -= 32; + + cb = *b; + if (cb >= 'a' && cb <= 'z') + cb -= 32; + + if ((ca -= cb) != 0) // if different, return comparison + return ca; + + a++, b++; + } +} + +int strcmpi (char *a, char *b) +{ + int ca, cb; + + for (;;) { + if ((ca = *a) == 0) // get character, stop on null terminator + return *b ? -1 : 0; + + if (ca >= 'a' && ca <= 'z') // fold lowercase to uppercase + ca -= 32; + + cb = *b; + if (cb >= 'a' && cb <= 'z') + cb -= 32; + + if ((ca -= cb) != 0) // if different, return comparison + return ca; + + a++, b++; + } +} + +#endif diff --git a/Ibm1130/utils/mkboot.mak b/Ibm1130/utils/mkboot.mak new file mode 100644 index 00000000..15715362 --- /dev/null +++ b/Ibm1130/utils/mkboot.mak @@ -0,0 +1,175 @@ +# Microsoft Visual C++ Generated NMAKE File, Format Version 2.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +!IF "$(CFG)" == "" +CFG=Win32 Debug +!MESSAGE No configuration specified. Defaulting to Win32 Debug. +!ENDIF + +!IF "$(CFG)" != "Win32 Release" && "$(CFG)" != "Win32 Debug" +!MESSAGE Invalid configuration "$(CFG)" specified. +!MESSAGE You can specify a configuration when running NMAKE on this makefile +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "mkboot.mak" CFG="Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE +!ERROR An invalid configuration is specified. +!ENDIF + +################################################################################ +# Begin Project +# PROP Target_Last_Scanned "Win32 Debug" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "WinRel" +# PROP BASE Intermediate_Dir "WinRel" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "WinRel" +# PROP Intermediate_Dir "WinRel" +OUTDIR=.\WinRel +INTDIR=.\WinRel + +ALL : $(OUTDIR)/mkboot.exe $(OUTDIR)/mkboot.bsc + +$(OUTDIR) : + if not exist $(OUTDIR)/nul mkdir $(OUTDIR) + +# ADD BASE CPP /nologo /W3 /GX /YX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /FR /c +# ADD CPP /nologo /W3 /GX /YX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /FR /c +CPP_PROJ=/nologo /W3 /GX /YX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE"\ + /FR$(INTDIR)/ /Fp$(OUTDIR)/"mkboot.pch" /Fo$(INTDIR)/ /c +CPP_OBJS=.\WinRel/ +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +BSC32_FLAGS=/nologo /o$(OUTDIR)/"mkboot.bsc" +BSC32_SBRS= \ + $(INTDIR)/mkboot.sbr \ + $(INTDIR)/util_io.sbr + +$(OUTDIR)/mkboot.bsc : $(OUTDIR) $(BSC32_SBRS) + $(BSC32) @<< + $(BSC32_FLAGS) $(BSC32_SBRS) +<< + +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /NOLOGO /SUBSYSTEM:console /MACHINE:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib /NOLOGO /SUBSYSTEM:console /MACHINE:I386 +LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib /NOLOGO /SUBSYSTEM:console\ + /INCREMENTAL:no /PDB:$(OUTDIR)/"mkboot.pdb" /MACHINE:I386\ + /OUT:$(OUTDIR)/"mkboot.exe" +DEF_FILE= +LINK32_OBJS= \ + $(INTDIR)/mkboot.obj \ + $(INTDIR)/util_io.obj + +$(OUTDIR)/mkboot.exe : $(OUTDIR) $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ELSEIF "$(CFG)" == "Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "WinDebug" +# PROP BASE Intermediate_Dir "WinDebug" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "WinDebug" +# PROP Intermediate_Dir "WinDebug" +OUTDIR=.\WinDebug +INTDIR=.\WinDebug + +ALL : $(OUTDIR)/mkboot.exe $(OUTDIR)/mkboot.bsc + +$(OUTDIR) : + if not exist $(OUTDIR)/nul mkdir $(OUTDIR) + +# ADD BASE CPP /nologo /W3 /GX /Zi /YX /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /FR /c +# ADD CPP /nologo /W3 /GX /Zi /YX /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /FR /c +CPP_PROJ=/nologo /W3 /GX /Zi /YX /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE"\ + /FR$(INTDIR)/ /Fp$(OUTDIR)/"mkboot.pch" /Fo$(INTDIR)/ /Fd$(OUTDIR)/"mkboot.pdb"\ + /c +CPP_OBJS=.\WinDebug/ +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +BSC32_FLAGS=/nologo /o$(OUTDIR)/"mkboot.bsc" +BSC32_SBRS= \ + $(INTDIR)/mkboot.sbr \ + $(INTDIR)/util_io.sbr + +$(OUTDIR)/mkboot.bsc : $(OUTDIR) $(BSC32_SBRS) + $(BSC32) @<< + $(BSC32_FLAGS) $(BSC32_SBRS) +<< + +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /NOLOGO /SUBSYSTEM:console /DEBUG /MACHINE:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib /NOLOGO /SUBSYSTEM:console /DEBUG /MACHINE:I386 +LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib /NOLOGO /SUBSYSTEM:console\ + /INCREMENTAL:yes /PDB:$(OUTDIR)/"mkboot.pdb" /DEBUG /MACHINE:I386\ + /OUT:$(OUTDIR)/"mkboot.exe" +DEF_FILE= +LINK32_OBJS= \ + $(INTDIR)/mkboot.obj \ + $(INTDIR)/util_io.obj + +$(OUTDIR)/mkboot.exe : $(OUTDIR) $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ENDIF + +.c{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.cpp{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.cxx{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +################################################################################ +# Begin Group "Source Files" + +################################################################################ +# Begin Source File + +SOURCE=.\mkboot.c + +$(INTDIR)/mkboot.obj : $(SOURCE) $(INTDIR) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\util_io.c +DEP_UTIL_=\ + .\util_io.h + +$(INTDIR)/util_io.obj : $(SOURCE) $(DEP_UTIL_) $(INTDIR) + +# End Source File +# End Group +# End Project +################################################################################ diff --git a/Ibm1130/utils/viewdeck.c b/Ibm1130/utils/viewdeck.c new file mode 100644 index 00000000..894d7aea --- /dev/null +++ b/Ibm1130/utils/viewdeck.c @@ -0,0 +1,243 @@ +/* Simple program to display a binary card-image file in ASCII. + * We assume the deck was written with one card per 16-bit word, left-justified, + * and written in PC little-endian order + * + * (C) Copyright 2002, Brian Knittel. + * You may freely use this program, but: it offered strictly on an AS-IS, AT YOUR OWN + * RISK basis, there is no warranty of fitness for any purpose, and the rest of the + * usual yada-yada. Please keep this notice and the copyright in any distributions + * or modifications. + * + * This is not a supported product, but I welcome bug reports and fixes. + * Mail to sim@ibm1130.org + */ + +#include +#include +#include "util_io.h" + +#define TRUE 1 +#define FALSE 0 +typedef int BOOL; + +int hollerith_to_ascii (unsigned short h); +void bail (char *msg); +void format_coldstart (unsigned short *buf); + +int main (int argc, char **argv) +{ + FILE *fd; + char *fname = NULL, line[82], *arg; + BOOL coldstart = FALSE; + unsigned short buf[80]; + int i, lastnb; + static char usestr[] = + "Usage: viewdeck [-c] deckfile\n" + "\n" + "-c: convert cold start card to 16-bit format as a C array initializer\n"; + + for (i = 1; i < argc; i++) { // process command line arguments + arg = argv[i]; + + if (*arg == '-') { + arg++; + while (*arg) { + switch (*arg++) { + case 'c': + coldstart = TRUE; + break; + default: + bail(usestr); + } + } + } + else if (fname == NULL) // first non-switch arg is file name + fname = arg; + else + bail(usestr); // there can be only one name + } + + if (fname == NULL) // there must be a name + bail(usestr); + + if ((fd = fopen(fname, "rb")) == NULL) { + perror(fname); + return 1; + } + + while (fxread(buf, sizeof(short), 80, fd) == 80) { + if (coldstart) { + format_coldstart(buf); + break; + } + + lastnb = -1; + for (i = 0; i < 80; i++) { + line[i] = hollerith_to_ascii(buf[i]); + if (line[i] > ' ') + lastnb = i; + } + line[++lastnb] = '\n'; + line[++lastnb] = '\0'; + fputs(line, stdout); + } + + if (coldstart) { + if (fxread(buf, sizeof(short), 1, fd) == 1) + bail("Coldstart deck has more than one card"); + } + + fclose(fd); + + return 0; +} + +void format_coldstart (unsigned short *buf) +{ + int i, nout = 0; + unsigned short word; + + for (i = 0; i < 80; i++) { + word = buf[i]; // expand 12-bit card data to 16-bit instruction + word = (word & 0xF800) | ((word & 0x0400) ? 0x00C0 : 0x0000) | ((word & 0x03F0) >> 4); + + if (nout >= 8) { + fputs(",\n", stdout); + nout = 0; + } + else if (i > 0) + fputs(", ", stdout); + + printf("0x%04x", word); + nout++; + } + + putchar('\n'); +} + +typedef struct { + unsigned short hollerith; + char ascii; +} CPCODE; + +static CPCODE cardcode_029[] = +{ + 0x0000, ' ', + 0x8000, '&', // + in 026 Fortran + 0x4000, '-', + 0x2000, '0', + 0x1000, '1', + 0x0800, '2', + 0x0400, '3', + 0x0200, '4', + 0x0100, '5', + 0x0080, '6', + 0x0040, '7', + 0x0020, '8', + 0x0010, '9', + 0x9000, 'A', + 0x8800, 'B', + 0x8400, 'C', + 0x8200, 'D', + 0x8100, 'E', + 0x8080, 'F', + 0x8040, 'G', + 0x8020, 'H', + 0x8010, 'I', + 0x5000, 'J', + 0x4800, 'K', + 0x4400, 'L', + 0x4200, 'M', + 0x4100, 'N', + 0x4080, 'O', + 0x4040, 'P', + 0x4020, 'Q', + 0x4010, 'R', + 0x3000, '/', + 0x2800, 'S', + 0x2400, 'T', + 0x2200, 'U', + 0x2100, 'V', + 0x2080, 'W', + 0x2040, 'X', + 0x2020, 'Y', + 0x2010, 'Z', + 0x0820, ':', + 0x0420, '#', // = in 026 Fortran + 0x0220, '@', // ' in 026 Fortran + 0x0120, '\'', + 0x00A0, '=', + 0x0060, '"', + 0x8820, '\xA2', // cent, in MS-DOS encoding + 0x8420, '.', + 0x8220, '<', // ) in 026 Fortran + 0x8120, '(', + 0x80A0, '+', + 0x8060, '|', + 0x4820, '!', + 0x4420, '$', + 0x4220, '*', + 0x4120, ')', + 0x40A0, ';', + 0x4060, '\xAC', // not, in MS-DOS encoding + 0x2420, ',', + 0x2220, '%', // ( in 026 Fortran + 0x2120, '_', + 0x20A0, '>', + 0xB000, 'a', + 0xA800, 'b', + 0xA400, 'c', + 0xA200, 'd', + 0xA100, 'e', + 0xA080, 'f', + 0xA040, 'g', + 0xA020, 'h', + 0xA010, 'i', + 0xD000, 'j', + 0xC800, 'k', + 0xC400, 'l', + 0xC200, 'm', + 0xC100, 'n', + 0xC080, 'o', + 0xC040, 'p', + 0xC020, 'q', + 0xC010, 'r', + 0x6800, 's', + 0x6400, 't', + 0x6200, 'u', + 0x6100, 'v', + 0x6080, 'w', + 0x6040, 'x', + 0x6020, 'y', + 0x6010, 'z', // these odd punch codes are used by APL: + 0x1010, '\001', // no corresponding ASCII using ^A + 0x0810, '\002', // SYN using ^B + 0x0410, '\003', // no corresponding ASCII using ^C + 0x0210, '\004', // PUNCH ON using ^D + 0x0110, '\005', // READER STOP using ^E + 0x0090, '\006', // UPPER CASE using ^F + 0x0050, '\013', // EOT using ^K + 0x0030, '\016', // no corresponding ASCII using ^N + 0x1030, '\017', // no corresponding ASCII using ^O + 0x0830, '\020', // no corresponding ASCII using ^P +}; + +int hollerith_to_ascii (unsigned short h) +{ + int i; + + h &= 0xFFF0; + + for (i = 0; i < sizeof(cardcode_029) / sizeof(CPCODE); i++) + if (cardcode_029[i].hollerith == h) + return cardcode_029[i].ascii; + + return '?'; +} + +void bail (char *msg) +{ + fprintf(stderr, "%s\n", msg); + exit(1); +} + diff --git a/Ibm1130/utils/viewdeck.mak b/Ibm1130/utils/viewdeck.mak new file mode 100644 index 00000000..3ee6f6aa --- /dev/null +++ b/Ibm1130/utils/viewdeck.mak @@ -0,0 +1,176 @@ +# Microsoft Visual C++ Generated NMAKE File, Format Version 2.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +!IF "$(CFG)" == "" +CFG=Win32 Debug +!MESSAGE No configuration specified. Defaulting to Win32 Debug. +!ENDIF + +!IF "$(CFG)" != "Win32 Release" && "$(CFG)" != "Win32 Debug" +!MESSAGE Invalid configuration "$(CFG)" specified. +!MESSAGE You can specify a configuration when running NMAKE on this makefile +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "viewdeck.mak" CFG="Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE +!ERROR An invalid configuration is specified. +!ENDIF + +################################################################################ +# Begin Project +# PROP Target_Last_Scanned "Win32 Debug" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "WinRel" +# PROP BASE Intermediate_Dir "WinRel" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "WinRel" +# PROP Intermediate_Dir "WinRel" +OUTDIR=.\WinRel +INTDIR=.\WinRel + +ALL : $(OUTDIR)/viewdeck.exe $(OUTDIR)/viewdeck.bsc + +$(OUTDIR) : + if not exist $(OUTDIR)/nul mkdir $(OUTDIR) + +# ADD BASE CPP /nologo /W3 /GX /YX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /FR /c +# ADD CPP /nologo /W3 /GX /YX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /FR /c +CPP_PROJ=/nologo /W3 /GX /YX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE"\ + /FR$(INTDIR)/ /Fp$(OUTDIR)/"viewdeck.pch" /Fo$(INTDIR)/ /c +CPP_OBJS=.\WinRel/ +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +BSC32_FLAGS=/nologo /o$(OUTDIR)/"viewdeck.bsc" +BSC32_SBRS= \ + $(INTDIR)/viewdeck.sbr \ + $(INTDIR)/util_io.sbr + +$(OUTDIR)/viewdeck.bsc : $(OUTDIR) $(BSC32_SBRS) + $(BSC32) @<< + $(BSC32_FLAGS) $(BSC32_SBRS) +<< + +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /NOLOGO /SUBSYSTEM:console /MACHINE:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib /NOLOGO /SUBSYSTEM:console /MACHINE:I386 +LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\ + advapi32.lib /NOLOGO /SUBSYSTEM:console /INCREMENTAL:no\ + /PDB:$(OUTDIR)/"viewdeck.pdb" /MACHINE:I386 /OUT:$(OUTDIR)/"viewdeck.exe" +DEF_FILE= +LINK32_OBJS= \ + $(INTDIR)/viewdeck.obj \ + $(INTDIR)/util_io.obj + +$(OUTDIR)/viewdeck.exe : $(OUTDIR) $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ELSEIF "$(CFG)" == "Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "WinDebug" +# PROP BASE Intermediate_Dir "WinDebug" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "WinDebug" +# PROP Intermediate_Dir "WinDebug" +OUTDIR=.\WinDebug +INTDIR=.\WinDebug + +ALL : $(OUTDIR)/viewdeck.exe $(OUTDIR)/viewdeck.bsc + +$(OUTDIR) : + if not exist $(OUTDIR)/nul mkdir $(OUTDIR) + +# ADD BASE CPP /nologo /W3 /GX /Zi /YX /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /FR /c +# ADD CPP /nologo /W3 /GX /Zi /YX /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /FR /c +CPP_PROJ=/nologo /W3 /GX /Zi /YX /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE"\ + /FR$(INTDIR)/ /Fp$(OUTDIR)/"viewdeck.pch" /Fo$(INTDIR)/\ + /Fd$(OUTDIR)/"viewdeck.pdb" /c +CPP_OBJS=.\WinDebug/ +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +BSC32_FLAGS=/nologo /o$(OUTDIR)/"viewdeck.bsc" +BSC32_SBRS= \ + $(INTDIR)/viewdeck.sbr \ + $(INTDIR)/util_io.sbr + +$(OUTDIR)/viewdeck.bsc : $(OUTDIR) $(BSC32_SBRS) + $(BSC32) @<< + $(BSC32_FLAGS) $(BSC32_SBRS) +<< + +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /NOLOGO /SUBSYSTEM:console /DEBUG /MACHINE:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib /NOLOGO /SUBSYSTEM:console /DEBUG /MACHINE:I386 +LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\ + advapi32.lib /NOLOGO /SUBSYSTEM:console /INCREMENTAL:yes\ + /PDB:$(OUTDIR)/"viewdeck.pdb" /DEBUG /MACHINE:I386\ + /OUT:$(OUTDIR)/"viewdeck.exe" +DEF_FILE= +LINK32_OBJS= \ + $(INTDIR)/viewdeck.obj \ + $(INTDIR)/util_io.obj + +$(OUTDIR)/viewdeck.exe : $(OUTDIR) $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ENDIF + +.c{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.cpp{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.cxx{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +################################################################################ +# Begin Group "Source Files" + +################################################################################ +# Begin Source File + +SOURCE=.\viewdeck.c + +$(INTDIR)/viewdeck.obj : $(SOURCE) $(INTDIR) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\util_io.c +DEP_UTIL_=\ + .\util_io.h + +$(INTDIR)/util_io.obj : $(SOURCE) $(DEP_UTIL_) $(INTDIR) + +# End Source File +# End Group +# End Project +################################################################################ diff --git a/Interdata/id32_sys.c b/Interdata/id32_sys.c index f1a04fec..a36afc1a 100644 --- a/Interdata/id32_sys.c +++ b/Interdata/id32_sys.c @@ -23,6 +23,7 @@ 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-Jul-04 RMS Fixed missing type in declaration 15-Jul-03 RMS Fixed signed/unsigned bug in get_imm 27-Feb-03 RMS Added relative addressing support 23-Dec-01 RMS Cloned from ID4 sources @@ -50,7 +51,7 @@ extern uint32 *M; t_stat fprint_sym_m (FILE *of, t_addr addr, t_value *val, t_bool cf); t_stat parse_sym_m (char *cptr, t_addr addr, t_value *val, t_bool cf); extern t_stat lp_load (FILE *fileref, char *cptr, char *fnam); -extern pt_dump (FILE *of, char *cptr, char *fnam); +extern t_stat pt_dump (FILE *of, char *cptr, char *fnam); /* SCP data structures and interface routines diff --git a/PDP10/pdp10_diag.txt b/PDP10/pdp10_diag.txt index 3f9a18a6..f5a01b87 100644 --- a/PDP10/pdp10_diag.txt +++ b/PDP10/pdp10_diag.txt @@ -23,3 +23,4 @@ Bugs Found 15. UBA initialization reset the UBA itself 16. RHCS1: writing IE cannot trigger an interrupt 17. Tape bootstrap was set to 800bpi instead of 1600bpi +18. FIXR off by 1 in testing for lower limit to process diff --git a/PDP10/pdp10_doc.txt b/PDP10/pdp10_doc.txt index 1f776c88..0990a586 100644 --- a/PDP10/pdp10_doc.txt +++ b/PDP10/pdp10_doc.txt @@ -1,7 +1,7 @@ To: Users From: Bob Supnik Subj: PDP-10 Simulator Usage -Date: 04-Apr-2004 +Date: 15-Jun-2004 COPYRIGHT NOTICE @@ -208,10 +208,9 @@ The Unibus adapter has the following registers: 2.4 Front End (FE) The front end is the system console. The keyboard input is unit 0, -the console output is unit 1. It supports two options: +the console output is unit 1. It supports one option: SET FE STOP halts the PDP-10 operating system - SET FE CTLC simulates typing ^C The front end has the following registers: diff --git a/PDP10/pdp10_fe.c b/PDP10/pdp10_fe.c index 0bc74579..c3c5066f 100644 --- a/PDP10/pdp10_fe.c +++ b/PDP10/pdp10_fe.c @@ -25,6 +25,7 @@ fe KS10 console front end + 28-May-04 RMS Removed SET FE CTRL-C 29-Dec-03 RMS Added console backpressure support 25-Apr-03 RMS Revised for extended file support 22-Dec-02 RMS Added break support @@ -43,7 +44,6 @@ t_stat fei_svc (UNIT *uptr); t_stat feo_svc (UNIT *uptr); t_stat fe_reset (DEVICE *dptr); t_stat fe_stop_os (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat fe_ctrl_c (UNIT *uptr, int32 val, char *cptr, void *desc); /* FE data structures @@ -70,7 +70,6 @@ REG fe_reg[] = { MTAB fe_mod[] = { { UNIT_DUMMY, 0, NULL, "STOP", &fe_stop_os }, - { UNIT_DUMMY, 0, NULL, "CTRL-C", &fe_ctrl_c }, { 0 } }; DEVICE fe_dev = { @@ -161,13 +160,3 @@ t_stat fe_stop_os (UNIT *uptr, int32 val, char *cptr, void *desc) M[FE_SWITCH] = IOBA_RP; /* tell OS to stop */ return SCPE_OK; } - -/* Enter control-C for Windoze */ - -t_stat fe_ctrl_c (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -fei_unit.buf = 003; /* control-C */ -M[FE_CTYIN] = fei_unit.buf | FE_CVALID; /* put char in mem */ -apr_flg = apr_flg | APRF_CON; /* interrupt KS10 */ -return SCPE_OK; -} diff --git a/PDP11/pdp11_defs.h b/PDP11/pdp11_defs.h index 28e21a2c..fdfd7255 100644 --- a/PDP11/pdp11_defs.h +++ b/PDP11/pdp11_defs.h @@ -26,6 +26,7 @@ The author gratefully acknowledges the help of Max Burnet, Megan Gentry, and John Wilson in resolving questions about the PDP-11 + 28-May-04 RMS Added DHQ support 25-Jan-04 RMS Removed local debug logging support 22-Dec-03 RMS Added second DEUNA/DELUA support 18-Oct-03 RMS Added DECtape off reel message @@ -74,6 +75,8 @@ #define UNIMEMSIZE 001000000 /* 2**18 */ #define UNIMASK (UNIMEMSIZE - 1) /* 2**18 - 1 */ #define IOPAGEBASE 017760000 /* 2**22 - 2**13 */ +#define IOPAGESIZE 000020000 /* 2**13 */ +#define IOPAGEMASK (IOPAGESIZE - 1) /* 2**13 - 1 */ #define MAXMEMSIZE 020000000 /* 2**22 */ #define PAMASK (MAXMEMSIZE - 1) /* 2**22 - 1 */ #define MEMSIZE (cpu_unit.capac) @@ -308,8 +311,9 @@ typedef struct fpac fpac_t; /* IO parameters */ -#define DZ_MUXES 4 /* max # of muxes */ -#define DZ_LINES 8 /* lines per mux */ +#define DZ_MUXES 4 /* max # of DZ muxes */ +#define DZ_LINES 8 /* lines per DZ mux */ +#define VH_MUXES 4 /* max # of VH muxes */ #define MT_MAXFR (1 << 16) /* magtape max rec */ #define AUTO_LNT 34 /* autoconfig ranks */ #define DIB_MAX 100 /* max DIBs */ @@ -359,6 +363,8 @@ typedef struct pdp_dib DIB; #define IOLN_RQC 004 #define IOBA_RQD (IOPAGEBASE + IOBA_RQC + IOLN_RQC) #define IOLN_RQD 004 +#define IOBA_VH (IOPAGEBASE + 000440) /* DHQ11 */ +#define IOLN_VH 020 #define IOBA_UBM (IOPAGEBASE + 010200) /* Unibus map */ #define IOLN_UBM (UBM_LNT_LW * sizeof (int32)) #define IOBA_RQ (IOPAGEBASE + 012150) /* RQDX3 */ @@ -446,7 +452,9 @@ typedef struct pdp_dib DIB; #define INT_V_PTR 2 #define INT_V_PTP 3 #define INT_V_LPT 4 -#define INT_V_PIR4 5 +#define INT_V_VHRX 5 +#define INT_V_VHTX 6 +#define INT_V_PIR4 7 #define INT_V_PIR3 0 /* BR3 */ #define INT_V_PIR2 0 /* BR2 */ @@ -477,6 +485,8 @@ typedef struct pdp_dib DIB; #define INT_TTI (1u << INT_V_TTI) #define INT_TTO (1u << INT_V_TTO) #define INT_LPT (1u << INT_V_LPT) +#define INT_VHRX (1u << INT_V_VHRX) +#define INT_VHTX (1u << INT_V_VHTX) #define INT_PIR4 (1u << INT_V_PIR4) #define INT_PIR3 (1u << INT_V_PIR3) #define INT_PIR2 (1u << INT_V_PIR2) @@ -504,6 +514,8 @@ typedef struct pdp_dib DIB; #define IPL_TTI 4 #define IPL_TTO 4 #define IPL_LPT 4 +#define IPL_VHRX 4 +#define IPL_VHTX 4 #define IPL_PIR7 7 #define IPL_PIR6 6 @@ -539,6 +551,8 @@ typedef struct pdp_dib DIB; #define VEC_RY 0264 #define VEC_DZRX 0300 #define VEC_DZTX 0304 +#define VEC_VHRX 0310 +#define VEC_VHTX 0314 /* Autoconfigure ranks */ @@ -548,6 +562,7 @@ typedef struct pdp_dib DIB; #define RANK_XU 25 #define RANK_RQ 26 #define RANK_TQ 30 +#define RANK_VH 32 /* Interrupt macros */ diff --git a/PDP11/pdp11_doc.txt b/PDP11/pdp11_doc.txt index 22864ee1..2b7a73d1 100644 --- a/PDP11/pdp11_doc.txt +++ b/PDP11/pdp11_doc.txt @@ -1,7 +1,7 @@ To: Users From: Bob Supnik Subj: PDP-11 Simulator Usage -Date: 04-Apr-2004 +Date: 15-Jun-2004 COPYRIGHT NOTICE @@ -84,6 +84,7 @@ sim/pdp11/ pdp11_defs.h pdp11_tc.c pdp11_tm.c pdp11_ts.c + pdp11_vh.c pdp11_xq.c pdp11_xu.c @@ -103,6 +104,7 @@ LPT LP11 line printer CLK line frequency clock PCLK KW11P programmable clock DZ DZ11 8-line terminal multiplexor (up to 4) +VH DHQ11 8-line terminal multiplexor (up to 4) RK RK11/RK05 cartridge disk controller with eight drives HK RK611/RK06(7) cartridge disk controller with eight drives RL RLV12/RL01(2) cartridge disk controller with four drives @@ -144,12 +146,12 @@ The CPU options include CPU mapping configuration (18b Unibus, 22b Unibus with RH70-style controllers, 22b Unibus with RH11 style controllers, and 22b Qbus), the CIS instruction set, and the size of main memory. - SET CPU 18B 18b addressing, no I/O map - SET CPU URH11 22b addresssing, Unibus I/O map, + SET CPU U18 Unibus, no I/O map, 18b addressing + SET CPU URH11 Unibus, I/O map with 22b addressing, 18b mapped RH11 controller - SET CPU URH70 22b addressing, Unibus I/O map, + SET CPU URH70 Unibus, I/O map with 22b addressing, 22b unmapped RH70 controller - SET CPU 22B 22b addressing, no I/O map (Qbus) + SET CPU Q22 Qbus, no I/O map, 22b addressing SET CPU NOCIS disable CIS instructions (default) SET CPU CIS enable CIS instructions SET CPU 16K set memory size = 16KB @@ -395,12 +397,6 @@ implements these registers: POS 32 number of characters input TIME 24 keyboard polling interval -If the simulator is compiled under Windows Visual C++, typing ^C to the -terminal input causes a fatal run-time error. Use the following command -to simulate typing ^C: - - SET TTI CTRL-C - 2.3.4 DL11 Terminal Output (TTO) The terminal output (TTO) writes to the simulator console window. It @@ -499,81 +495,6 @@ up or down so that the clock tracks actual elapsed time. Operation at the highest clock rate (100Khz) is not recommended. The programmable clock is disabled by default. -2.3.8 DZ11 Terminal Multiplexor (DZ) - -The DZ11 is an 8-line terminal multiplexor. Up to 4 DZ11's (32 lines) -are supported. The number of lines can be changed with the command - - SET DZ LINES=n set line count to n - -The line count must be a multiple of 8, with a maximum of 32. - -The DZ11 supports 8-bit input and output of characters. 8-bit output -may be incompatible with certain operating systems. The command - - SET DZ 7B - -forces output characters (only) to be masked to 7 bits. - -The DZ11 supports logging on a per-line basis. The command - - SET DZ LOG=line=filename - -enables logging for the specified line to the indicated file. The -command - - SET DZ NOLOG=line - -disables logging for the specified line and closes any open log file. -Finally, the command - - SHOW DZ LOG - -displays logging information for all DZ lines. - -The terminal lines perform input and output through Telnet sessions -connected to a user-specified port. The ATTACH command specifies -the port to be used: - - ATTACH {-am} DZ set up listening port - -where port is a decimal number between 1 and 65535 that is not being used -for other TCP/IP activities. The optional switch -m turns on the DZ11's -modem controls; the optional switch -a turns on active disconnects -(disconnect session if computer clears Data Terminal Ready). Without -modem control, the DZ behaves as though terminals were directly connected; -disconnecting the Telnet session does not cause any operating system- -visible change in line status. - -Once the DZ is attached and the simulator is running, the DZ will listen -for connections on the specified port. It assumes that the incoming -connections are Telnet connections. The connection remains open until -disconnected by the simulated program, the Telnet client, a SET DZ -DISCONNECT command, or a DETACH DZ command. - -The SHOW DZ CONNECTIONS command displays the current connections to the DZ. -The SHOW DZ STATISTICS command displays statistics for active connections. -The SET DZ DISCONNECT=linenumber disconnects the specified line. - -The DZ11 implements these registers: - - name size comments - - CSR[0:3] 16 control/status register, boards 0..3 - RBUF[0:3] 16 receive buffer, boards 0..3 - LPR[0:3] 16 line parameter register, boards 0..3 - TCR[0:3] 16 transmission control register, boards 0..3 - MSR[0:3] 16 modem status register, boards 0..3 - TDR[0:3] 16 transmit data register, boards 0..3 - SAENB[0:3] 1 silo alarm enabled, boards 0..3 - RXINT 4 receive interrupts, boards 3..0 - TXINT 4 transmit interrupts, boards 3..0 - MDMTCL 1 modem control enabled - AUTODS 1 autodisconnect enabled - -The DZ11 does not support save and restore. All open connections are -lost when the simulator shuts down or the DZ is detached. - 2.4 Floppy Disk Drives 2.4.1 RX11/RX01 Floppy Disk (RX) @@ -1217,7 +1138,166 @@ Error handling is as follows: OS I/O error fatal tape error -2.10 DELQA/DEQNA Qbus Ethernet Controllers (XQ, XQB) +2.10 Communications Devices + +2.10.1 DZ11 Terminal Multiplexor (DZ) + +The DZ11 is an 8-line terminal multiplexor. Up to 4 DZ11's (32 lines) +are supported. The number of lines can be changed with the command + + SET DZ LINES=n set line count to n + +The line count must be a multiple of 8, with a maximum of 32. + +The DZ11 supports 8-bit input and output of characters. 8-bit output +may be incompatible with certain operating systems. The command + + SET DZ 7B + +forces output characters (only) to be masked to 7 bits. + +The DZ11 supports logging on a per-line basis. The command + + SET DZ LOG=line=filename + +enables logging for the specified line to the indicated file. The +command + + SET DZ NOLOG=line + +disables logging for the specified line and closes any open log file. +Finally, the command + + SHOW DZ LOG + +displays logging information for all DZ lines. + +The terminal lines perform input and output through Telnet sessions +connected to a user-specified port. The ATTACH command specifies +the port to be used: + + ATTACH {-am} DZ set up listening port + +where port is a decimal number between 1 and 65535 that is not being used +for other TCP/IP activities. The optional switch -m turns on the DZ11's +modem controls; the optional switch -a turns on active disconnects +(disconnect session if computer clears Data Terminal Ready). Without +modem control, the DZ behaves as though terminals were directly connected; +disconnecting the Telnet session does not cause any operating system- +visible change in line status. + +Once the DZ is attached and the simulator is running, the DZ will listen +for connections on the specified port. It assumes that the incoming +connections are Telnet connections. The connection remains open until +disconnected by the simulated program, the Telnet client, a SET DZ +DISCONNECT command, or a DETACH DZ command. + +The SHOW DZ CONNECTIONS command displays the current connections to the DZ. +The SHOW DZ STATISTICS command displays statistics for active connections. +The SET DZ DISCONNECT=linenumber disconnects the specified line. + +The DZ11 implements these registers: + + name size comments + + CSR[0:3] 16 control/status register, boards 0..3 + RBUF[0:3] 16 receive buffer, boards 0..3 + LPR[0:3] 16 line parameter register, boards 0..3 + TCR[0:3] 16 transmission control register, boards 0..3 + MSR[0:3] 16 modem status register, boards 0..3 + TDR[0:3] 16 transmit data register, boards 0..3 + SAENB[0:3] 1 silo alarm enabled, boards 0..3 + RXINT 4 receive interrupts, boards 3..0 + TXINT 4 transmit interrupts, boards 3..0 + MDMTCL 1 modem control enabled + AUTODS 1 autodisconnect enabled + +The DZ11 does not support save and restore. All open connections are +lost when the simulator shuts down or the DZ is detached. + +2.10.2 DHQ11 Terminal Multiplexor (VH) + +The DHQ11 is an 8-line terminal multiplexor for Qbus systems. Up +to 4 DHQ11's are supported. + +The DHQ11 is a programmable asynchronous terminal multiplexor. It +has two programming modes: DHV11 and DHU11. The register sets are +compatible with these devices. For transmission, the DHQ11 can be +used in either DMA or programmed I/O mode. For reception, there +is a 256-entry FIFO for received characters, dataset status changes, +and diagnostic information, and a programmable input interrupt +timer (in DHU mode). The device supports 16-, 18-, and 22-bit +addressing. The DHQ11 can be programmed to filter and/or handle +XON/XOFF characters independently of the processor. The DHQ11 +supports programmable bit width (between 5 and 8) for the input +and output of characters. + +The DHQ11 has a rocker switch for determining the programming mode. +By default, the DHV11 mode is selected, though DHU11 mode is +recommended for applications that can support it. The VH controller +may be adjusted on a per controller basis as follows: + + SET VHn DHU use the DHU programming mode and registers + SET VHn DHV use the DHV programming mode and registers + +DMA output is supported. In a real DHQ11, DMA is not initiated +immediately upon receipt of TX.DMA.START but is dependent upon some +internal processes. The VH controller mimics this behavior by default. +It may be desirable to alter this and start immediately, though +this may not be compatible with all operating systems and diagnostics. +You can change the behavior of the VH controller as follows: + + SET VHn NORMAL use normal DMA procedures + SET VHn FASTDMA set DMA to initiate immediately + +The terminal lines perform input and output through Telnet sessions +connected to a user-specified port. The ATTACH command specifies +the port to be used: + + ATTACH VH set up listening port + DETACH VH + +where port is a decimal number between 1 and 65535 that is not +being used for other TCP/IP activities. This port is the point of +entry for al lines on all VH controllers. + +Modem and auto-disconnect support may be set on an individual +controller basis. The SET MODEM command directs the controller to +report modem status changes to the computer. The SET HANGUP command +turns on active disconnects (disconnect session if computer clears +Data Terminal Ready). + + SET VHn [NO]MODEM disable/enable modem control + SET VHn [NO]HANGUP disable/enable disconnect on DTR drop + +Once the VH is attached and the simulator is running, the VH will +listen for connections on the specified port. It assumes that the +incoming connections are Telnet connections. The connection remains +open until disconnected by the simulated program, the Telnet client, +a SET VH DISCONNECT command, or a DETACH VH command. + +The SHOW VH CONNECTIONS command displays the current connections to the VH. +The SHOW VH STATISTICS command displays statistics for active connections. +The SET VH DISCONNECT=linenumber disconnects the specified line. + +The DHQ11 implements these registers, though not all can be examined +from SCP: + + name size comments + + CSR[0:3] 16 control/status register, boards 0..3 + RBUF[0:3] 16 receive buffer, boards 0..3 + LPR[0:3] 16 line parameter register, boards 0..3 + RXINT 4 receive interrupts, boards 3..0 + TXINT 4 transmit interrupts, boards 3..0 +[more to be described...] + +The DHQ11 does not support save and restore. All open connections +are lost when the simulator shuts down or the VH is detached. + +2.11 Ethernet Controllers + +2.11.1 DELQA/DEQNA Qbus Ethernet Controllers (XQ, XQB) The simulator implements two DELQA/DEQNA Qbus Ethernet controllers (XQ, XQB). Initially, XQ is enabled, and XQB is disabled. Options allow @@ -1301,10 +1381,10 @@ not limited to the ~1.5Mbit/sec of the real DEQNA/DELQA controllers, nor the 10Mbit/sec of a standard Ethernet. Attach it to a Fast Ethernet (100 Mbit/sec) card, and "Feel the Power!" :-) -2.11 DEUNA/DELUA Unibus Ethernet Controller (XU) +2.11.2 DEUNA/DELUA Unibus Ethernet Controller (XU) -XU simulates the DEUNA/DELUA Unibus Ethernet controller. THe current -implementation is a stub and is permanently disabled. +XU simulates the DEUNA/DELUA Unibus Ethernet controller. Its operation +is analagous to the DELQA/DEQNA controller. 2.12 Symbolic Display and Input diff --git a/PDP11/pdp11_io.c b/PDP11/pdp11_io.c index e9f5ca3d..70ca54e5 100644 --- a/PDP11/pdp11_io.c +++ b/PDP11/pdp11_io.c @@ -23,6 +23,7 @@ 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-May-04 RMS Revised I/O dispatching (from John Dundas) 25-Jan-04 RMS Removed local debug logging support 21-Dec-03 RMS Fixed bug in autoconfigure vector assignment; added controls 21-Nov-03 RMS Added check for interrupt slot conflict (found by Dave Hittner) @@ -42,13 +43,13 @@ extern uint16 *M; extern int32 int_req[IPL_HLVL]; extern int32 ub_map[UBM_LNT_LW]; -extern UNIT cpu_unit; extern int32 cpu_bme, cpu_18b, cpu_ubm; extern int32 trap_req, ipl; extern int32 cpu_log; extern int32 autcon_enb; extern FILE *sim_log; -extern DEVICE *sim_devices[]; +extern DEVICE *sim_devices[], cpu_dev; +extern UNIT cpu_unit; int32 calc_ints (int32 nipl, int32 trq); @@ -57,7 +58,9 @@ extern DIB cpu3_dib, cpu4_dib, ubm_dib; /* I/O data structures */ -DIB *dib_tab[DIB_MAX]; /* run time DIBs */ +static t_stat (*iodispR[IOPAGESIZE >> 1])(int32 *dat, int32 ad, int32 md); +static t_stat (*iodispW[IOPAGESIZE >> 1])(int32 dat, int32 ad, int32 md); +static DIB *iodibp[IOPAGESIZE >> 1]; int32 int_vec[IPL_HLVL][32]; /* int req to vector */ @@ -71,9 +74,9 @@ static DIB *std_dib[] = { /* standard DIBs */ &cpu4_dib, NULL }; -static int32 pirq_vloc[7] = { - IVCL (PIR7), IVCL (PIR6), IVCL (PIR5), IVCL (PIR4), - IVCL (PIR3), IVCL (PIR2), IVCL (PIR1) }; +static const int32 pirq_bit[7] = { + INT_V_PIR1, INT_V_PIR2, INT_V_PIR3, INT_V_PIR4, + INT_V_PIR5, INT_V_PIR6, INT_V_PIR7 }; /* I/O page lookup and linkage routines @@ -88,31 +91,27 @@ static int32 pirq_vloc[7] = { t_stat iopageR (int32 *data, uint32 pa, int32 access) { -int32 i; -DIB *dibp; +int32 idx; t_stat stat; -for (i = 0; dibp = dib_tab[i]; i++ ) { - if ((pa >= dibp->ba) && - (pa < (dibp->ba + dibp->lnt))) { - stat = dibp->rd (data, pa, access); - trap_req = calc_ints (ipl, trap_req); - return stat; } } +idx = (pa & IOPAGEMASK) >> 1; +if (iodispR[idx]) { + stat = iodispR[idx] (data, pa, access); + trap_req = calc_ints (ipl, trap_req); + return stat; } return SCPE_NXM; } t_stat iopageW (int32 data, uint32 pa, int32 access) { -int32 i; -DIB *dibp; +int32 idx; t_stat stat; -for (i = 0; dibp = dib_tab[i]; i++ ) { - if ((pa >= dibp->ba) && - (pa < (dibp->ba + dibp->lnt))) { - stat = dibp->wr (data, pa, access); - trap_req = calc_ints (ipl, trap_req); - return stat; } } +idx = (pa & IOPAGEMASK) >> 1; +if (iodispW[idx]) { + stat = iodispW[idx] (data, pa, access); + trap_req = calc_ints (ipl, trap_req); + return stat; } return SCPE_NXM; } @@ -422,123 +421,126 @@ else { fprintf (st, "vector=%o", vec); return SCPE_OK; } -/* Test for conflict in device addresses */ +/* Build dispatch tables */ -t_bool dev_conflict (DIB *curr) +t_stat build_dsp_tab (DEVICE *dptr, DIB *dibp) { -uint32 i, end; -DEVICE *dptr; -DIB *dibp; +uint32 i, idx; -end = curr->ba + curr->lnt - 1; /* get end */ -for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { /* loop thru dev */ - dibp = (DIB *) dptr->ctxt; /* get DIB */ - if ((dibp == NULL) || (dibp == curr) || - (dptr->flags & DEV_DIS)) continue; - if (((curr->ba >= dibp->ba) && /* overlap start? */ - (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_dname (dptr), dibp->ba); - return TRUE; } } -return FALSE; +if ((dptr == NULL) || (dibp == NULL)) return SCPE_IERR; /* validate args */ +for (i = 0; i < dibp->lnt; i = i + 2) { /* create entries */ + idx = ((dibp->ba + i) & IOPAGEMASK) >> 1; /* index into disp */ + if ((iodispR[idx] && dibp->rd && /* conflict? */ + (iodispR[idx] != dibp->rd)) || + (iodispW[idx] && dibp->wr && + (iodispW[idx] != dibp->wr))) { + 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_dname (dptr), dibp->ba); + return SCPE_STOP; + } + if (dibp->rd) iodispR[idx] = dibp->rd; /* set rd dispatch */ + if (dibp->wr) iodispW[idx] = dibp->wr; /* set wr dispatch */ + iodibp[idx] = dibp; /* remember DIB */ + } +return SCPE_OK; } /* Build interrupt tables */ -t_bool build_int_vec (int32 vloc, int32 ivec, int32 (*iack)(void) ) +t_stat build_int_vec (DEVICE *dptr, DIB *dibp) { -int32 ilvl = vloc / 32; -int32 ibit = vloc % 32; +int32 i, idx, vec, ilvl, ibit; -if (iack != NULL) { - if (int_ack[ilvl][ibit] && - (int_ack[ilvl][ibit] != iack)) return TRUE; - int_ack[ilvl][ibit] = iack; } -else if (ivec != 0) { - if (int_vec[ilvl][ibit] && - (int_vec[ilvl][ibit] != ivec)) return TRUE; - int_vec[ilvl][ibit] = ivec; } -return FALSE; -} - -/* Build dib_tab from device list */ - -t_stat build_dib_tab (int32 ubm) -{ -int32 i, j, k; -DEVICE *dptr; -DIB *dibp; - -for (i = 0; i < IPL_HLVL; i++) { /* clear int tables */ - for (j = 0; j < 32; j++) { - int_vec[i][j] = 0; - int_ack[i][j] = 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? */ - if (dibp->vnum > VEC_DEVMAX) return SCPE_IERR; - for (k = 0; k < dibp->vnum; k++) { /* loop thru vec */ - if (build_int_vec (dibp->vloc + k, /* add vector */ - dibp->vec + (k * 4), dibp->ack[k])) { - printf ("Device %s interrupt slot conflict at %d\n", - sim_dname (dptr), dibp->vloc + k); - if (sim_log) fprintf (sim_log, - "Device %s interrupt slot conflict at %d\n", - sim_dname (dptr), dibp->vloc + k); - return SCPE_IERR; } } - if (dibp->lnt != 0) { /* I/O addresses? */ - dib_tab[j++] = dibp; /* add DIB to dib_tab */ - if (j >= DIB_MAX) return SCPE_IERR; } /* too many? */ - } /* end if enabled */ - } /* end for */ -for (i = 0; (dibp = std_dib[i]) != NULL; i++) { /* loop thru std */ - dib_tab[j++] = dibp; /* add to dib_tab */ - if (j >= DIB_MAX) return SCPE_IERR; } /* too many? */ -if (ubm) { /* Unibus map? */ - dib_tab[j++] = &ubm_dib; /* add to dib_tab */ - if (j >= DIB_MAX) return SCPE_IERR; } /* too many? */ -dib_tab[j] = NULL; /* end with NULL */ -for (i = 0; i < 7; i++) /* add PIRQ intr */ - build_int_vec (pirq_vloc[i], VEC_PIRQ, NULL); -for (i = 0; (dibp = dib_tab[i]) != NULL; i++) { /* test built dib_tab */ - if (dev_conflict (dibp)) { - return SCPE_STOP; } } /* for conflicts */ +if ((dptr == NULL) || (dibp == NULL)) return SCPE_IERR; /* validate args */ +if (dibp->vnum > VEC_DEVMAX) return SCPE_IERR; +for (i = 0; i < dibp->vnum; i++) { /* loop thru vec */ + idx = dibp->vloc + i; /* vector index */ + vec = dibp->vec? (dibp->vec + (i * 4)): 0; /* vector addr */ + ilvl = idx / 32; + ibit = idx % 32; + if ((int_ack[ilvl][ibit] && dibp->ack[i] && /* conflict? */ + (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); + return SCPE_STOP; + } + if (dibp->ack[i]) int_ack[ilvl][ibit] = dibp->ack[i]; + else if (vec) int_vec[ilvl][ibit] = vec; + } return SCPE_OK; } -/* Show dib_tab */ +/* Build tables from device list */ + +t_stat build_dib_tab (int32 ubm) +{ +int32 i, j; +DEVICE *dptr; +DIB *dibp; +t_stat r; + +for (i = 0; i < IPL_HLVL; i++) { /* clear intr tab */ + for (j = 0; j < 32; j++) { + int_vec[i][j] = 0; + int_ack[i][j] = NULL; } } +for (i = 0; i < (IOPAGESIZE >> 1); i++) { /* clear dispatch tab */ + iodispR[i] = NULL; + iodispW[i] = NULL; + iodibp[i] = NULL; } +for (i = 0; i < 7; i++) /* seed PIRQ intr */ + int_vec[i + 1][pirq_bit[i]] = VEC_PIRQ; +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_int_vec (dptr, dibp)) /* add to intr tab */ + return r; + if (r = build_dsp_tab (dptr, dibp)) /* add to dispatch tab */ + return r; + } /* end if enabled */ + } /* end for */ +for (i = 0; std_dib[i] != NULL; i++) { /* loop thru std */ + if (r = build_dsp_tab (&cpu_dev, std_dib[i])) /* add to dispatch tab */ + return r; + } +if (ubm) { /* Unibus map? */ + if (r = build_dsp_tab (&cpu_dev, &ubm_dib)) /* add to dispatch tab */ + return r; + } +return SCPE_OK; +} + +/* Show IO space */ t_stat show_iospace (FILE *st, UNIT *uptr, int32 val, void *desc) { -int32 i, j, done = 0; +uint32 i, j; DEVICE *dptr; -DIB *dibt; +DIB *dibp; -build_dib_tab (cpu_ubm); /* build table */ -while (done == 0) { /* sort ascending */ - done = 1; /* assume done */ - for (i = 0; dib_tab[i + 1] != NULL; i++) { /* check table */ - if (dib_tab[i]->ba > dib_tab[i + 1]->ba) { /* out of order? */ - dibt = dib_tab[i]; /* interchange */ - dib_tab[i] = dib_tab[i + 1]; - dib_tab[i + 1] = dibt; - done = 0; } } /* not done */ - } /* end while */ -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]) { - dptr = sim_devices[j]; - break; } } - fprintf (st, "%08o - %08o%c\t%s\n", dib_tab[i]->ba, - dib_tab[i]->ba + dib_tab[i]->lnt - 1, +if (build_dib_tab (cpu_ubm)) return SCPE_OK; /* build IO page */ +for (i = 0, dibp = NULL; i < (IOPAGESIZE >> 1); i++) { /* loop thru entries */ + if (iodibp[i] && (iodibp[i] != dibp)) { /* new block? */ + dibp = iodibp[i]; /* DIB for block */ + for (j = 0, dptr = NULL; sim_devices[j] != NULL; j++) { + if (((DIB*) sim_devices[j]->ctxt) == dibp) { + dptr = sim_devices[j]; /* locate device */ + break; + } /* end if */ + } /* end for j */ + fprintf (st, "%08o - %08o%c\t%s\n", /* print block entry */ + dibp->ba, dibp->ba + dibp->lnt - 1, (dptr && (dptr->flags & DEV_FLTA))? '*': ' ', dptr? sim_dname (dptr): "CPU"); - } + } /* end if */ + } /* end for i */ return SCPE_OK; } @@ -593,7 +595,7 @@ struct auto_con auto_tab[AUTO_LNT + 1] = { { 0xf, 0x3 }, /* VS100 */ { 0x3, 0x3, AUTO_DYN|AUTO_VEC, 0, IOBA_TQ, { "TQ", "TQB" } }, { 0xf, 0x7 }, /* KMV11 */ - { 0xf, 0x7 }, /* DHU11/DHQ11 */ + { 0x1f, 0x7, AUTO_VEC, VH_MUXES, 0, { "VH" } }, /* DHU11/DHQ11 */ { 0x1f, 0x7 }, /* DMZ32 */ { 0x1f, 0x7 }, /* CP132 */ diff --git a/PDP11/pdp11_stddev.c b/PDP11/pdp11_stddev.c index c5d11569..05fe8078 100644 --- a/PDP11/pdp11_stddev.c +++ b/PDP11/pdp11_stddev.c @@ -26,6 +26,7 @@ tti,tto DL11 terminal input/output clk KW11L line frequency clock + 28-May-04 RMS Removed SET TTI CTRL-C 29-Dec-03 RMS Added console backpressure support 25-Apr-03 RMS Revised for extended file support 01-Mar-03 RMS Added SET/SHOW CLOCK FREQ, SET TTI CTRL-C @@ -80,7 +81,6 @@ t_stat tto_rd (int32 *data, int32 PA, int32 access); t_stat tto_wr (int32 data, int32 PA, int32 access); t_stat tto_svc (UNIT *uptr); t_stat tto_reset (DEVICE *dptr); -t_stat tti_set_ctrlc (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat tty_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat clk_rd (int32 *data, int32 PA, int32 access); t_stat clk_wr (int32 data, int32 PA, int32 access); @@ -115,8 +115,6 @@ REG tti_reg[] = { MTAB tti_mod[] = { { UNIT_8B, 0 , "7b" , "7B" , &tty_set_mode }, { UNIT_8B, UNIT_8B , "8b" , "8B" , &tty_set_mode }, - { MTAB_XTD|MTAB_VDV|MTAB_VUN, 0, NULL, "CTRL-C", - &tti_set_ctrlc, NULL, NULL }, { MTAB_XTD|MTAB_VDV, 0, "ADDRESS", NULL, NULL, &show_addr, NULL }, { MTAB_XTD|MTAB_VDV, 0, "VECTOR", NULL, @@ -267,18 +265,6 @@ CLR_INT (TTI); sim_activate (&tti_unit, tti_unit.wait); /* activate unit */ return SCPE_OK; } - -/* Set control-C */ - -t_stat tti_set_ctrlc (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -if (cptr) return SCPE_ARG; -uptr->buf = 003; -uptr->pos = uptr->pos + 1; -tti_csr = tti_csr | CSR_DONE; -if (tti_csr & CSR_IE) SET_INT (TTI); -return SCPE_OK; -} /* Terminal output address routines */ diff --git a/PDP11/pdp11_sys.c b/PDP11/pdp11_sys.c index 55b4d416..3bd48bf3 100644 --- a/PDP11/pdp11_sys.c +++ b/PDP11/pdp11_sys.c @@ -57,6 +57,7 @@ extern DEVICE tti_dev, tto_dev; extern DEVICE lpt_dev; extern DEVICE clk_dev, pclk_dev; extern DEVICE dz_dev; +extern DEVICE vh_dev; extern DEVICE rk_dev, rl_dev; extern DEVICE hk_dev; extern DEVICE rx_dev, ry_dev; @@ -98,6 +99,7 @@ DEVICE *sim_devices[] = { &clk_dev, &pclk_dev, &dz_dev, + &vh_dev, &rk_dev, &rl_dev, &hk_dev, diff --git a/PDP11/pdp11_tq.c b/PDP11/pdp11_tq.c index 2dd4256b..b93b880b 100644 --- a/PDP11/pdp11_tq.c +++ b/PDP11/pdp11_tq.c @@ -25,6 +25,8 @@ tq TQK50 tape controller + 12-Jun-04 RMS Fixed bug in reporting write protect (reported by Lyle Bickley) + 18-Apr-04 RMS Fixed TQK70 media ID and model byte (found by Robert Schaffrath) 26-Mar-04 RMS Fixed warnings with -std=c99 25-Jan-04 RMS Revised for device debug support 19-May-03 RMS Revised for new conditional compilation scheme @@ -87,7 +89,7 @@ extern int32 cpu_18b, cpu_ubm; #define pktq u4 /* packet queue */ #define uf buf /* settable unit flags */ #define objp wait /* object position */ -#define TQ_WPH(u) (sim_tape_wrp (u)) +#define TQ_WPH(u) ((sim_tape_wrp (u))? UF_WPH: 0) #define CST_S1 0 /* init stage 1 */ #define CST_S1_WR 1 /* stage 1 wrap */ @@ -144,8 +146,8 @@ struct tqpkt { #define TQ7_TYPE 1 /* TK70 */ #define TQ7_UQPM 14 /* UQ port ID */ #define TQ7_CMOD 14 /* ctrl ID */ -#define TQ7_UMOD 11 /* unit ID */ -#define TQ7_MED 0x6A68B046 /* media ID */ +#define TQ7_UMOD 14 /* unit ID */ +#define TQ7_MED 0x6D68B046 /* media ID */ #define TQ7_CREV ((1 << 8) | 5) /* ctrl revs */ #define TQ7_FREV 0 /* formatter revs */ #define TQ7_UREV 0 /* unit revs */ diff --git a/PDP11/pdp11_vh.c b/PDP11/pdp11_vh.c new file mode 100644 index 00000000..17663929 --- /dev/null +++ b/PDP11/pdp11_vh.c @@ -0,0 +1,1367 @@ +/* pdp11_vh.c: DHQ11 asynchronous terminal multiplexor simulator + + Copyright (c) 2004, John A. Dundas III + Portions derived from work by 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 + 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. + + vh DHQ11 asynch multiplexor for SIMH + + 12-Jun-04 RMS Repair MS2SIMH macro to avoid possible divide by + 0 bug. + 8-Jun-04 JAD Repair vh_dev initialization; remove unused + variables, cast to avoid conversion confusion. + 7-Jun-04 JAD Complete function prototypes of forward declarations. + Repair broken prototypes of vh_rd() and vh_wr(). + Explicitly size integer declarations. + 4-Jun-04 JAD Preliminary code: If operating in a PDP-11 Unibus + environment, force DHU mode. + 29-May-04 JAD Make certain RX.TIMER is within allowable range. + 25-May-04 JAD All time-based operations are scaled by tmxr_poll + units. + 23-May-04 JAD Change to fifo_get() and dq_tx_report() to avoid + gratuitous stack manipulation. + 20-May-04 JAD Made modem control and auto-hangup unit flags + 19-May-04 JAD Fix problem with modem status where the line number + was not being included + 12-May-04 JAD Revised for updated tmxr interfaces + 28-Jan-04 JAD Original creation and testing + +I/O Page Registers + +CSR 17 760 440 (float) + +Vector: 300 (float) + +Priority: BR4 + +Rank: 32 + +*/ + /* MANY constants needed! */ + +#if defined (VM_VAX) +#include "vax_defs.h" +extern int32 int_req[IPL_HLVL]; +extern int32 int_vec[IPL_HLVL][32]; +#endif + +#if defined (VM_PDP11) +#include "pdp11_defs.h" +extern int32 int_req[IPL_HLVL]; +extern int32 int_vec[IPL_HLVL][32]; +#endif + +#include "sim_sock.h" +#include "sim_tmxr.h" + +/* imports from pdp11_stddev.c: */ +extern int32 tmxr_poll, clk_tps; +/* convert ms to SIMH time units based on tmxr_poll polls per second */ +#define MS2SIMH(ms) (((ms) * clk_tps) / 1000) +extern FILE *sim_log; + +#ifndef VH_MUXES +#define VH_MUXES (4) +#endif +#define VH_MNOMASK (VH_MUXES - 1) + +#define VH_LINES (8) + +#define UNIT_V_MODEDHU (UNIT_V_UF + 0) +#define UNIT_V_FASTDMA (UNIT_V_UF + 1) +#define UNIT_V_MODEM (UNIT_V_UF + 2) +#define UNIT_V_HANGUP (UNIT_V_UF + 3) +#define UNIT_MODEDHU (1 << UNIT_V_MODEDHU) +#define UNIT_FASTDMA (1 << UNIT_V_FASTDMA) +#define UNIT_MODEM (1 << UNIT_V_MODEM) +#define UNIT_HANGUP (1 << UNIT_V_HANGUP) + +/* VHCSR - 160440 - Control and Status Register */ + +#define CSR_M_IND_ADDR (017) +#define CSR_SKIP (1 << 4) +#define CSR_MASTER_RESET (1 << 5) +#define CSR_RXIE (1 << 6) +#define CSR_RX_DATA_AVAIL (1 << 7) +#define CSR_M_TX_LINE (017) +#define CSR_V_TX_LINE (8) +#define CSR_TX_DMA_ERR (1 << 12) +#define CSR_DIAG_FAIL (1 << 13) +#define CSR_TXIE (1 << 14) +#define CSR_TX_ACTION (1 << 15) +#define CSR_GETCHAN(x) ((x) & CSR_M_IND_ADDR) +#define CSR_RW \ + (CSR_TXIE|CSR_RXIE|CSR_SKIP|CSR_M_IND_ADDR|CSR_MASTER_RESET) +#define RESET_ABORT (052525) + +/* Receive Buffer (RBUF) */ + +#define FIFO_SIZE (256) +#define FIFO_ALARM (191) +#define FIFO_HALF (FIFO_SIZE / 2) +#define RBUF_M_RX_CHAR (0377) +#define RBUF_M_RX_LINE (07) +#define RBUF_V_RX_LINE (8) +#define RBUF_PARITY_ERR (1 << 12) +#define RBUF_FRAME_ERR (1 << 13) +#define RBUF_OVERRUN_ERR (1 << 14) +#define RBUF_DATA_VALID (1 << 15) +#define RBUF_GETLINE(x) (((x) >> RBUF_V_RX_LINE) & RBUF_M_RX_LINE) +#define RBUF_PUTLINE(x) ((x) << RBUF_V_RX_LINE) +#define RBUF_DIAG \ + (RBUF_PARITY_ERR|RBUF_FRAME_ERR|RBUF_OVERRUN_ERR) +#define XON (021) +#define XOFF (023) + +/* Transmit Character Register (TXCHAR) */ + +#define TXCHAR_M_CHAR (0377) +#define TXCHAR_TX_DATA_VALID (1 << 15) + +/* Receive Timer Register (RXTIMER) */ + +#define RXTIMER_M_RX_TIMER (0377) + +/* Line-Parameter Register (LPR) */ + +#define LPR_DISAB_XRPT (1 << 0) /* not impl. in real DHU */ +#define LPR_V_DIAG (1) +#define LPR_M_DIAG (03) +#define LPR_V_CHAR_LGTH (3) +#define LPR_M_CHAR_LGTH (03) +#define LPR_PARITY_ENAB (1 << 5) +#define LPR_EVEN_PARITY (1 << 6) +#define LPR_STOP_CODE (1 << 7) +#define LPR_V_RX_SPEED (8) +#define LPR_M_RX_SPEED (017) +#define LPR_V_TX_SPEED (12) +#define LPR_M_TX_SPEED (017) + +#define RATE_50 (0) +#define RATE_75 (1) +#define RATE_110 (2) +#define RATE_134 (3) +#define RATE_150 (4) +#define RATE_300 (5) +#define RATE_600 (6) +#define RATE_1200 (7) +#define RATE_1800 (8) +#define RATE_2000 (9) +#define RATE_2400 (10) +#define RATE_4800 (11) +#define RATE_7200 (12) +#define RATE_9600 (13) +#define RATE_19200 (14) +#define RATE_38400 (15) + +/* Line-Status Register (STAT) */ + +#define STAT_DHUID (1 << 8) /* mode: 0=DHV, 1=DHU */ +#define STAT_MDL (1 << 9) /* always 0, has modem support */ +#define STAT_CTS (1 << 11) /* CTS from modem */ +#define STAT_DCD (1 << 12) /* DCD from modem */ +#define STAT_RI (1 << 13) /* RI from modem */ +#define STAT_DSR (1 << 15) /* DSR from modem */ + +/* FIFO Size Register (FIFOSIZE) */ + +#define FIFOSIZE_M_SIZE (0377) + +/* FIFO Data Register (FIFODATA) */ + +#define FIFODATA_W0 (0377) +#define FIFODATA_V_W1 (8) +#define FIFODATA_M_W1 (0377) + +/* Line-Control Register (LNCTRL) */ + +#define LNCTRL_TX_ABORT (1 << 0) +#define LNCTRL_IAUTO (1 << 1) +#define LNCTRL_RX_ENA (1 << 2) +#define LNCTRL_BREAK (1 << 3) +#define LNCTRL_OAUTO (1 << 4) +#define LNCTRL_FORCE_XOFF (1 << 5) +#define LNCTRL_V_MAINT (6) +#define LNCTRL_M_MAINT (03) +#define LNCTRL_LINK_TYPE (1 << 8) /* 0=data leads only, 1=modem */ +#define LNCTRL_DTR (1 << 9) /* DTR to modem */ +#define LNCTRL_RTS (1 << 12) /* RTS to modem */ + +/* Transmit Buffer Address Register Number 1 (TBUFFAD1) */ + +/* Transmit Buffer Address Register Number 2 (TBUFFAD2) */ + +#define TB2_M_TBUFFAD (077) +#define TB2_TX_DMA_START (1 << 7) +#define TB2_TX_ENA (1 << 15) + +/* Transmit DMA Buffer Counter (TBUFFCT) */ + +/* Self-Test Error Codes */ + +#define SELF_NULL (0201) +#define SELF_SKIP (0203) +#define SELF_OCT (0211) +#define SELF_RAM (0225) +#define SELF_RCD (0231) +#define SELF_DRD (0235) + +#define BMP_OK (0305) +#define BMP_BAD (0307) + +/* Loopback types */ + +#define LOOP_NONE (0) +#define LOOP_H325 (1) +#define LOOP_H3101 (2) /* p.2-13 DHQ manual */ + /* Local storage */ + +static uint16 vh_csr[VH_MUXES] = { 0 }; /* CSRs */ +static uint16 vh_timer[VH_MUXES] = { 1 }; /* controller timeout */ +static uint16 vh_mcount[VH_MUXES] = { 0 }; +static uint32 vh_timeo[VH_MUXES] = { 0 }; +static uint32 vh_ovrrun[VH_MUXES] = { 0 }; /* line overrun bits */ +/* XOFF'd channels, one bit/channel */ +static uint32 vh_stall[VH_MUXES] = { 0 }; +static uint16 vh_loop[VH_MUXES] = { 0 }; /* loopback status */ + +/* One bit per controller: */ +static uint32 vh_rxi = 0; /* rcv interrupts */ +static uint32 vh_txi = 0; /* xmt interrupts */ +static uint32 vh_crit = 0; /* FIFO.CRIT */ + +static const int32 bitmask[4] = { 037, 077, 0177, 0377 }; + +/* RX FIFO state */ + +static int32 rbuf_idx[VH_MUXES] = { 0 };/* index into vh_rbuf */ +static uint32 vh_rbuf[VH_MUXES][FIFO_SIZE] = { 0 }; + +/* TXQ state */ + +#define TXQ_SIZE (16) +static int32 txq_idx[VH_MUXES] = { 0 }; +static uint32 vh_txq[VH_MUXES][TXQ_SIZE] = { 0 }; + +/* Need to extend the TMLN structure */ + +typedef struct { + TMLN *tmln; + uint16 lpr; /* line parameters */ + uint16 lnctrl; /* line control */ + uint16 lstat; /* line modem status */ + uint16 tbuffct; /* remaining character count */ + uint16 tbuf1; + uint16 tbuf2; + uint16 txchar; /* single character I/O */ +} TMLX; + +static TMLN vh_ldsc[VH_MUXES * VH_LINES] = { 0 }; +static TMXR vh_desc = { VH_MUXES * VH_LINES, 0, 0, vh_ldsc }; +static TMLX vh_parm[VH_MUXES * VH_LINES] = { 0 }; + + /* Forward references */ +static t_stat vh_rd (int32 *data, int32 PA, int32 access); +static t_stat vh_wr (int32 data, int32 PA, int32 access); +static t_stat vh_svc (UNIT *uptr); +static int32 vh_rxinta (void); +static int32 vh_txinta (void); +static t_stat vh_clear (int32 vh, t_bool flag); +static t_stat vh_reset (DEVICE *dptr); +static t_stat vh_attach (UNIT *uptr, char *cptr); +static t_stat vh_detach (UNIT *uptr); +static t_stat vh_show_vec (FILE *st, UNIT *uptr, int32 val, void *desc); +static t_stat vh_show (FILE *st, UNIT *uptr, int32 val, void *desc); +static t_stat vh_show_debug (FILE *st, UNIT *uptr, int32 val, void *desc); +static t_stat vh_show_rbuf (FILE *st, UNIT *uptr, int32 val, void *desc); +static t_stat vh_show_txq (FILE *st, UNIT *uptr, int32 val, void *desc); +static t_stat vh_putc (int32 vh, TMLX *lp, int32 chan, int32 data); +static void doDMA (int32 vh, int32 chan); +static t_stat vh_summ (FILE *st, UNIT *uptr, int32 val, void *desc); + +int32 tmxr_send_buffered_data (TMLN *lp); + + /* SIMH I/O Structures */ + +static DIB vh_dib = { + IOBA_VH, + IOLN_VH * VH_MUXES, + &vh_rd, /* read */ + &vh_wr, /* write */ + 2, /* # of vectors */ + IVCL (VHRX), + VEC_VHRX, + { &vh_rxinta, &vh_txinta } /* int. ack. routines */ +}; + +static UNIT vh_unit[VH_MUXES] = { + { UDATA (&vh_svc, UNIT_ATTABLE, 0) }, + { UDATA (&vh_svc, UNIT_ATTABLE, 0) }, + { UDATA (&vh_svc, UNIT_ATTABLE, 0) }, + { UDATA (&vh_svc, UNIT_ATTABLE, 0) }, +}; + +static const REG vh_nlreg = { DRDATA (NLINES, vh_desc.lines, 6), PV_LEFT }; + +static const REG vh_reg[] = { + { BRDATA (CSR, vh_csr, DEV_RDX, 16, VH_MUXES) }, + { GRDATA (DEVADDR, vh_dib.ba, DEV_RDX, 32, 0), REG_HRO }, + { GRDATA (DEVVEC, vh_dib.vec, DEV_RDX, 16, 0), REG_HRO }, + { NULL } +}; + +static const MTAB vh_mod[] = { + { UNIT_MODEDHU, 0, "DHV mode", "DHV", NULL }, + { UNIT_MODEDHU, UNIT_MODEDHU, "DHU mode", "DHU", NULL }, + { UNIT_FASTDMA, 0, NULL, "NORMAL", NULL }, + { UNIT_FASTDMA, UNIT_FASTDMA, "fast DMA", "FASTDMA", NULL }, + { UNIT_MODEM, 0, NULL, "NOMODEM", NULL }, + { UNIT_MODEM, UNIT_MODEM, "modem", "MODEM", NULL }, + { UNIT_HANGUP, 0, NULL, "NOHANGUP", NULL }, + { UNIT_HANGUP, UNIT_HANGUP, "hangup", "HANGUP", NULL }, + { MTAB_XTD|MTAB_VDV, 020, "ADDRESS", "ADDRESS", + &set_addr, &show_addr, NULL }, + { MTAB_XTD|MTAB_VDV, 0, "VECTOR", "VECTOR", + &set_vec, &vh_show_vec, NULL }, + { MTAB_XTD|MTAB_VDV, 0, NULL, "AUTOCONFIGURE", + &set_addr_flt, NULL, NULL }, + /* this one is dangerous, don't use yet */ + { MTAB_XTD|MTAB_VDV|MTAB_VAL, 0, "lines", "LINES", + NULL, NULL, (REG *)&vh_nlreg }, + { UNIT_ATT, UNIT_ATT, "connections", NULL, NULL, &vh_summ }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "CONNECTIONS", NULL, + NULL, &vh_show, NULL }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "STATISTICS", NULL, + NULL, &vh_show, NULL }, + { MTAB_XTD | MTAB_VDV, 1, NULL, "DISCONNECT", + &tmxr_dscln, NULL, &vh_desc }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "DEBUG", NULL, + NULL, &vh_show_debug, NULL }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "RBUF", NULL, + NULL, &vh_show_rbuf, NULL }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "TXQ", NULL, + NULL, &vh_show_txq, NULL }, + { 0 } +}; + +DEVICE vh_dev = { + "VH", /* name */ + vh_unit, /* units */ + (REG *)vh_reg, /* registers */ + (MTAB *)vh_mod, /* modifiers */ + VH_MUXES, /* # units */ + DEV_RDX, /* address radix */ + 8, /* address width */ + 1, /* address increment */ + DEV_RDX, /* data radix */ + 8, /* data width */ + NULL, /* examine routine */ + NULL, /* deposit routine */ + &vh_reset, /* reset routine */ + NULL, /* boot routine */ + &vh_attach, /* attach routine */ + &vh_detach, /* detach routine */ + (void *)&vh_dib, /* context */ + DEV_FLTA | DEV_DISABLE | DEV_NET | DEV_QBUS | DEV_UBUS, /* flags */ +}; + + /* Interrupt routines */ + +static void vh_clr_rxint ( int32 vh ) +{ + vh_rxi &= ~(1 << vh); + if (vh_rxi == 0) + CLR_INT (VHRX); + else + SET_INT (VHRX); +} + +static void vh_set_rxint ( int32 vh ) +{ + vh_rxi |= (1 << vh); + SET_INT (VHRX); +} + +/* RX interrupt ack. (bus cycle) */ + +static int32 vh_rxinta (void) +{ + int32 vh; + + for (vh = 0; vh < VH_MUXES; vh++) { + if (vh_rxi & (1 << vh)) { + vh_clr_rxint (vh); + return (vh_dib.vec + (vh * 010)); + } + } + return (0); +} + +static void vh_clr_txint ( int32 vh ) +{ + vh_txi &= ~(1 << vh); + if (vh_txi == 0) + CLR_INT (VHTX); + else + SET_INT (VHTX); +} + +static void vh_set_txint ( int32 vh ) +{ + vh_txi |= (1 << vh); + SET_INT (VHTX); +} + +/* TX interrupt ack. (bus cycle) */ + +static int32 vh_txinta (void) +{ + int32 vh; + + for (vh = 0; vh < VH_MUXES; vh++) { + if (vh_txi & (1 << vh)) { + vh_clr_txint (vh); + return (vh_dib.vec + 4 + (vh * 010)); + } + } + return (0); +} + /* RX FIFO get/put routines */ + +/* return 0 on success, -1 on FIFO overflow */ + +static int32 fifo_put ( int32 vh, + TMLX *lp, + int32 data ) +{ + int32 status = 0; + + if (lp == NULL) + goto override; + /* this might have to move to vh_getc() */ + if ((lp->lnctrl & LNCTRL_OAUTO) && ((data & RBUF_DIAG) == 0)) { + TMLX *l0p; + /* implement transmitted data flow control */ + switch (data & 0377) { + case XON: + lp->tbuf2 |= TB2_TX_ENA; + goto common; + case XOFF: + lp->tbuf2 &= ~TB2_TX_ENA; + common: + /* find line 0 for this controller */ + l0p = &vh_parm[vh * VH_LINES]; + if (l0p->lpr & LPR_DISAB_XRPT) + return (0); + break; + default: + break; + } + } +/* BUG: which of the following 2 is correct? */ + /* if ((data & RBUF_DIAG) == RBUF_DIAG) */ + if (data & RBUF_DIAG) + goto override; + if (((lp->lnctrl >> LNCTRL_V_MAINT) & LNCTRL_M_MAINT) == 2) + goto override; + if (!(lp->lnctrl & LNCTRL_RX_ENA)) + return (0); +override: + vh_csr[vh] |= CSR_RX_DATA_AVAIL; + if (rbuf_idx[vh] < FIFO_SIZE) { + vh_rbuf[vh][rbuf_idx[vh]] = data; + rbuf_idx[vh] += 1; + } else { + vh_ovrrun[vh] |= (1 << RBUF_GETLINE (data)); + status = -1; + } + if (vh_csr[vh] & CSR_RXIE) { + if (vh_unit[vh].flags & UNIT_MODEDHU) { + /* was it a modem status change? */ + if ((data & RBUF_DIAG) == RBUF_DIAG) + vh_set_rxint (vh); + /* look for FIFO alarm @ 3/4 full */ + else if (rbuf_idx[vh] == FIFO_ALARM) + vh_set_rxint (vh); + else if (vh_timer[vh] == 0) + ; /* nothing, infinite timeout */ + else if (vh_timer[vh] == 1) + vh_set_rxint (vh); + else if (vh_timeo[vh] == 0) + vh_timeo[vh] = MS2SIMH (vh_timer[vh]) + 1; + } else { + /* Interrupt on transition _from_ an empty FIFO */ + if (rbuf_idx[vh] == 1) + vh_set_rxint (vh); + } + } + if (rbuf_idx[vh] > FIFO_ALARM) + vh_crit |= (1 << vh); + /* Implement RX FIFO-level flow control */ + if (lp != NULL) { + if ((lp->lnctrl & LNCTRL_FORCE_XOFF) || + ((vh_crit & (1 << vh)) && (lp->lnctrl & LNCTRL_IAUTO))) { + int32 chan = RBUF_GETLINE(data); + vh_stall[vh] ^= (1 << chan); + /* send XOFF every other character received */ + if (vh_stall[vh] & (1 << chan)) + vh_putc (vh, lp, chan, XOFF); + } + } + return (status); +} + +static int32 fifo_get ( int32 vh ) +{ + int32 data, i; + + if (rbuf_idx[vh] == 0) { + vh_csr[vh] &= ~CSR_RX_DATA_AVAIL; + return (0); + } + /* pick off the first character, mark valid */ + data = vh_rbuf[vh][0] | RBUF_DATA_VALID; + /* move the remainder up */ + rbuf_idx[vh] -= 1; + for (i = 0; i < rbuf_idx[vh]; i++) + vh_rbuf[vh][i] = vh_rbuf[vh][i + 1]; + /* rbuf_idx[vh] -= 1; */ + /* look for any previous overruns */ + if (vh_ovrrun[vh]) { + for (i = 0; i < VH_LINES; i++) { + if (vh_ovrrun[vh] & (1 << i)) { + fifo_put (vh, NULL, RBUF_OVERRUN_ERR | + RBUF_PUTLINE (i)); + vh_ovrrun[vh] &= ~(1 << i); + break; + } + } + } + /* recompute FIFO alarm condition */ + if ((rbuf_idx[vh] < FIFO_HALF) && (vh_crit & (1 << vh))) { + vh_crit &= ~(1 << vh); + /* send XON to all XOFF'd channels on this controller */ + for (i = 0; i < VH_LINES; i++) { + TMLX *lp = &vh_parm[(vh * VH_LINES) + i]; + if (lp->lnctrl & LNCTRL_FORCE_XOFF) + continue; + if (vh_stall[vh] & (1 << i)) { + vh_putc (vh, NULL, i, XON); + vh_stall[vh] &= ~(1 << i); + } + } + } + return (data & 0177777); +} + /* TX Q manipulation */ + +static int32 dq_tx_report ( int32 vh ) +{ + int32 data, i; + + if (txq_idx[vh] == 0) + return (0); + data = vh_txq[vh][0]; + txq_idx[vh] -= 1; + for (i = 0; i < txq_idx[vh]; i++) + vh_txq[vh][i] = vh_txq[vh][i + 1]; + /* txq_idx[vh] -= 1; */ + return (data & 0177777); +} + +static void q_tx_report ( int32 vh, + int32 data ) +{ + if (vh_csr[vh] & CSR_TXIE) + vh_set_txint (vh); + if (txq_idx[vh] >= TXQ_SIZE) { +/* BUG: which of the following 2 is correct? */ + dq_tx_report (vh); + /* return; */ + } + vh_txq[vh][txq_idx[vh]] = CSR_TX_ACTION | data; + txq_idx[vh] += 1; +} + /* Channel get/put routines */ + +static void HangupModem ( int32 vh, + TMLX *lp, + int32 chan ) +{ + if (vh_unit[vh].flags & UNIT_MODEM) + lp->lstat &= ~(STAT_DCD|STAT_DSR|STAT_CTS|STAT_RI); + if (lp->lnctrl & LNCTRL_LINK_TYPE) + /* RBUF<0> = 0 for modem status */ + fifo_put (vh, lp, RBUF_DIAG | + RBUF_PUTLINE (chan) | + ((lp->lstat >> 8) & 0376)); + /* BUG: check for overflow above */ +} + +/* TX a character on a line, regardless of the TX enable state */ + +static t_stat vh_putc ( int32 vh, + TMLX *lp, + int32 chan, + int32 data ) +{ + int32 val; + t_stat status = SCPE_OK; + + /* truncate to desired character length */ + data &= bitmask[(lp->lpr >> LPR_V_CHAR_LGTH) & LPR_M_CHAR_LGTH]; + switch ((lp->lnctrl >> LNCTRL_V_MAINT) & LNCTRL_M_MAINT) { + case 0: /* normal */ +#if 0 + /* check for (external) loopback setting */ + switch (vh_loop[vh]) { + default: + case LOOP_NONE: + break; + } +#endif + status = tmxr_putc_ln (lp->tmln, data); + if (status == SCPE_LOST) { + tmxr_reset_ln (lp->tmln); + HangupModem (vh, lp, chan); + } else if (status == SCPE_STALL) { + /* let's flush and try again */ + tmxr_send_buffered_data (lp->tmln); + status = tmxr_putc_ln (lp->tmln, data); + } + break; + case 1: /* auto echo */ + break; + case 2: /* local loopback */ + if (lp->lnctrl & LNCTRL_BREAK) + val = fifo_put (vh, lp, + RBUF_FRAME_ERR | RBUF_PUTLINE (chan)); + else + val = fifo_put (vh, lp, + RBUF_PUTLINE (chan) | data); + status = (val < 0) ? SCPE_TTMO : SCPE_OK; + break; + default: /* remote loopback */ + break; + } + return (status); +} + +/* Retrieve all stored input from TMXR and place in RX FIFO */ + +static void vh_getc ( int32 vh ) +{ + uint32 i, c; + TMLX *lp; + + for (i = 0; i < VH_LINES; i++) { + lp = &vh_parm[(vh * VH_LINES) + i]; + while (c = tmxr_getc_ln (lp->tmln)) { + if (c & SCPE_BREAK) { + fifo_put (vh, lp, + RBUF_FRAME_ERR | RBUF_PUTLINE (i)); + /* BUG: check for overflow above */ + } else { + c &= bitmask[(lp->lpr >> LPR_V_CHAR_LGTH) & + LPR_M_CHAR_LGTH]; + fifo_put (vh, lp, RBUF_PUTLINE (i) | c); + /* BUG: check for overflow above */ + } + } + } +} + + /* I/O dispatch routines */ + +static t_stat vh_rd ( int32 *data, + int32 PA, + int32 access ) +{ + int32 vh = ((PA - vh_dib.ba) >> 4) & VH_MNOMASK, line; + TMLX *lp; + + switch ((PA >> 1) & 7) { + case 0: /* CSR */ + *data = vh_csr[vh] | dq_tx_report (vh); + vh_csr[vh] &= ~0117400; /* clear the read-once bits */ + break; + case 1: /* RBUF */ + *data = fifo_get (vh); + break; + case 2: /* LPR */ + if (CSR_GETCHAN (vh_csr[vh]) >= VH_LINES) { + *data = 0; + break; + } + line = (vh * VH_LINES) + CSR_GETCHAN (vh_csr[vh]); + lp = &vh_parm[line]; + *data = lp->lpr; + break; + case 3: /* STAT/FIFOSIZE */ + if (CSR_GETCHAN (vh_csr[vh]) >= VH_LINES) { + *data = 0; + break; + } + line = (vh * VH_LINES) + CSR_GETCHAN (vh_csr[vh]); + lp = &vh_parm[line]; + *data = (lp->lstat & ~0377) | /* modem status */ +#if 0 + (64 - tmxr_tqln (lp->tmln)); +fprintf (stderr, "\rtqln %d\n", 64 - tmxr_tqln (lp->tmln)); +#else + 64; +#endif + break; + case 4: /* LNCTRL */ + if (CSR_GETCHAN (vh_csr[vh]) >= VH_LINES) { + *data = 0; + break; + } + line = (vh * VH_LINES) + CSR_GETCHAN (vh_csr[vh]); + lp = &vh_parm[line]; + *data = lp->lnctrl; + break; + case 5: /* TBUFFAD1 */ + if (CSR_GETCHAN (vh_csr[vh]) >= VH_LINES) { + *data = 0; + break; + } + line = (vh * VH_LINES) + CSR_GETCHAN (vh_csr[vh]); + lp = &vh_parm[line]; + *data = lp->tbuf1; + break; + case 6: /* TBUFFAD2 */ + if (CSR_GETCHAN (vh_csr[vh]) >= VH_LINES) { + *data = 0; + break; + } + line = (vh * VH_LINES) + CSR_GETCHAN (vh_csr[vh]); + lp = &vh_parm[line]; + *data = lp->tbuf2; + break; + case 7: /* TBUFFCT */ + if (CSR_GETCHAN (vh_csr[vh]) >= VH_LINES) { + *data = 0; + break; + } + line = (vh * VH_LINES) + CSR_GETCHAN (vh_csr[vh]); + lp = &vh_parm[line]; + *data = lp->tbuffct; + break; + default: + /* can't happen */ + break; + } + return (SCPE_OK); +} + +static t_stat vh_wr ( int32 data, + int32 PA, + int32 access ) +{ + int32 vh = ((PA - vh_dib.ba) >> 4) & VH_MNOMASK, line; + TMLX *lp; + + switch ((PA >> 1) & 7) { + case 0: /* CSR, but no read-modify-write */ + if (access == WRITEB) + data = (PA & 1) ? + (vh_csr[vh] & 0377) | (data << 8) : + (vh_csr[vh] & ~0377) | data & 0377; + if (data & CSR_MASTER_RESET) { + if ((vh_unit[vh].flags & UNIT_MODEDHU) && (data & CSR_SKIP)) + data &= ~CSR_MASTER_RESET; + sim_activate (&vh_unit[vh], tmxr_poll); + /* vh_mcount[vh] = 72; */ /* 1.2 seconds */ + vh_mcount[vh] = MS2SIMH (1200); /* 1.2 seconds */ + } + if ((data & CSR_RXIE) == 0) + vh_clr_rxint (vh); + /* catch the RXIE transition if the FIFO is not empty */ + else if (((vh_csr[vh] & CSR_RXIE) == 0) && + (rbuf_idx[vh] != 0)) { + if (vh_unit[vh].flags & UNIT_MODEDHU) { + if (rbuf_idx[vh] > FIFO_ALARM) + vh_set_rxint (vh); + else if (vh_timer[vh] == 0) + ; + else if (vh_timer[vh] == 1) + vh_set_rxint (vh); + else if (vh_timeo[vh] == 0) + vh_timeo[vh] = MS2SIMH (vh_timer[vh]) + 1; + } else { + vh_set_rxint (vh); + } + } + if ((data & CSR_TXIE) == 0) + vh_clr_txint (vh); + else if (((vh_csr[vh] & CSR_TXIE) == 0) && + (txq_idx[vh] != 0)) + vh_set_txint (vh); + vh_csr[vh] = (vh_csr[vh] & ~((uint16) CSR_RW)) | (data & (uint16) CSR_RW); + break; + case 1: /* TXCHAR/RXTIMER */ + if (CSR_GETCHAN (vh_csr[vh]) >= VH_LINES) + break; + if ((data == RESET_ABORT) && (vh_csr[vh] & CSR_MASTER_RESET)) { + vh_mcount[vh] = 1; + break; + } + if (vh_unit[vh].flags & UNIT_MODEDHU) { + if (CSR_GETCHAN (vh_csr[vh]) != 0) + break; + if (access == WRITEB) + data = (PA & 1) ? + (vh_timer[vh] & 0377) | (data << 8) : + (vh_timer[vh] & ~0377) | (data & 0377); + vh_timer[vh] = data & 0377; +#if 0 + if (vh_csr[vh] & CSR_RXIE) { + if (rbuf_idx[vh] > FIFO_ALARM) + vh_set_rxint (vh); + else if (vh_timer[vh] == 0) + ; + else if (vh_timer[vh] == 1) + vh_set_rxint (vh); + else if (vh_timeo[vh] == 0) + vh_timeo[vh] = MS2SIMH (vh_timer[vh]) + 1; + } +#endif + } else { + line = (vh * VH_LINES) + CSR_GETCHAN (vh_csr[vh]); + lp = &vh_parm[line]; + if (access == WRITEB) + data = (PA & 1) ? + (lp->txchar & 0377) | (data << 8) : + (lp->txchar & ~0377) | (data & 0377); + lp->txchar = data; /* TXCHAR */ + if (lp->txchar & TXCHAR_TX_DATA_VALID) { + if (lp->tbuf2 & TB2_TX_ENA) + vh_putc (vh, lp, + CSR_GETCHAN (vh_csr[vh]), + lp->txchar); + q_tx_report (vh, + CSR_GETCHAN (vh_csr[vh]) << CSR_V_TX_LINE); + lp->txchar &= ~TXCHAR_TX_DATA_VALID; + } + } + break; + case 2: /* LPR */ + if ((data == RESET_ABORT) && (vh_csr[vh] & CSR_MASTER_RESET)) { + vh_mcount[vh] = 1; + break; + } + if (CSR_GETCHAN (vh_csr[vh]) >= VH_LINES) + break; + line = (vh * VH_LINES) + CSR_GETCHAN (vh_csr[vh]); + lp = &vh_parm[line]; + if (access == WRITEB) + data = (PA & 1) ? + (lp->lpr & 0377) | (data << 8) : + (lp->lpr & ~0377) | data & 0377; + /* Modify only if CSR<3:0> == 0 */ + if (CSR_GETCHAN (vh_csr[vh]) != 0) + data &= ~LPR_DISAB_XRPT; + lp->lpr = data; + if (((lp->lpr >> LPR_V_DIAG) & LPR_M_DIAG) == 1) { + fifo_put (vh, lp, + RBUF_DIAG | + RBUF_PUTLINE (CSR_GETCHAN (vh_csr[vh])) | + BMP_OK); + /* BUG: check for overflow above */ + lp->lpr &= ~(LPR_M_DIAG << LPR_V_DIAG); + } + break; + case 3: /* STAT/FIFODATA */ + if ((data == RESET_ABORT) && (vh_csr[vh] & CSR_MASTER_RESET)) { + vh_mcount[vh] = 1; + break; + } + if (CSR_GETCHAN (vh_csr[vh]) >= VH_LINES) + break; + line = (vh * VH_LINES) + CSR_GETCHAN (vh_csr[vh]); + lp = &vh_parm[line]; + if (vh_unit[vh].flags & UNIT_MODEDHU) { + /* high byte writes not allowed */ + if (PA & 1) + break; + /* transmit 1 or 2 characters */ + if (!(lp->tbuf2 & TB2_TX_ENA)) + break; + vh_putc (vh, lp, CSR_GETCHAN (vh_csr[vh]), data); + q_tx_report (vh, CSR_GETCHAN (vh_csr[vh]) << CSR_V_TX_LINE); + if (access != WRITEB) + vh_putc (vh, lp, CSR_GETCHAN (vh_csr[vh]), + data >> 8); + } + break; + case 4: /* LNCTRL */ + if ((data == RESET_ABORT) && (vh_csr[vh] & CSR_MASTER_RESET)) { + vh_mcount[vh] = 1; + break; + } + if (CSR_GETCHAN (vh_csr[vh]) >= VH_LINES) + break; + line = (vh * VH_LINES) + CSR_GETCHAN (vh_csr[vh]); + lp = &vh_parm[line]; + if (access == WRITEB) + data = (PA & 1) ? + (lp->lnctrl & 0377) | (data << 8) : + (lp->lnctrl & ~0377) | data & 0377; + /* catch the abort TX transition */ + if (!(lp->lnctrl & LNCTRL_TX_ABORT) && + (data & LNCTRL_TX_ABORT)) { + if ((lp->tbuf2 & TB2_TX_ENA) && + (lp->tbuf2 & TB2_TX_DMA_START)) { + lp->tbuf2 &= ~TB2_TX_DMA_START; + q_tx_report (vh, CSR_GETCHAN (vh_csr[vh]) << CSR_V_TX_LINE); + } + } + /* Implement program-initiated flow control */ + if ( (data & LNCTRL_FORCE_XOFF) && + !(lp->lnctrl & LNCTRL_FORCE_XOFF) ) { + if (!(lp->lnctrl & LNCTRL_IAUTO)) + vh_putc (vh, lp, CSR_GETCHAN (vh_csr[vh]), XOFF); + } else if ( !(data & LNCTRL_FORCE_XOFF) && + (lp->lnctrl & LNCTRL_FORCE_XOFF) ) { + if (!(lp->lnctrl & LNCTRL_IAUTO)) + vh_putc (vh, lp, CSR_GETCHAN (vh_csr[vh]), XON); + else if (!(vh_crit & (1 << vh)) && + (vh_stall[vh] & (1 << CSR_GETCHAN (vh_csr[vh])))) + vh_putc (vh, lp, CSR_GETCHAN (vh_csr[vh]), XON); + } + if ( (data & LNCTRL_IAUTO) && /* IAUTO 0->1 */ + !(lp->lnctrl & LNCTRL_IAUTO) ) { + if (!(lp->lnctrl & LNCTRL_FORCE_XOFF)) { + if (vh_crit & (1 << vh)) { + vh_putc (vh, lp, + CSR_GETCHAN (vh_csr[vh]), XOFF); + vh_stall[vh] |= (1 << CSR_GETCHAN (vh_csr[vh])); + } + } else { + /* vh_stall[vh] |= (1 << CSR_GETCHAN (vh_csr[vh])) */; + } + } else if ( !(data & LNCTRL_IAUTO) && + (lp->lnctrl & LNCTRL_IAUTO) ) { + if (!(lp->lnctrl & LNCTRL_FORCE_XOFF)) + vh_putc (vh, lp, CSR_GETCHAN (vh_csr[vh]), XON); + } + /* check modem control bits */ + if ( !(data & LNCTRL_DTR) && /* DTR 1->0 */ + (lp->lnctrl & LNCTRL_DTR)) { + if ((lp->tmln->conn) && (vh_unit[vh].flags & UNIT_HANGUP)) { + tmxr_linemsg (lp->tmln, "\r\nLine hangup\r\n"); + tmxr_reset_ln (lp->tmln); + } + HangupModem (vh, lp, CSR_GETCHAN (vh_csr[vh])); + } + lp->lnctrl = data; + lp->tmln->rcve = (data & LNCTRL_RX_ENA) ? 1 : 0; + tmxr_poll_rx (&vh_desc); + vh_getc (vh); + if (lp->lnctrl & LNCTRL_BREAK) + vh_putc (vh, lp, CSR_GETCHAN (vh_csr[vh]), 0); + break; + case 5: /* TBUFFAD1 */ + if ((data == RESET_ABORT) && (vh_csr[vh] & CSR_MASTER_RESET)) { + vh_mcount[vh] = 1; + break; + } + if (CSR_GETCHAN (vh_csr[vh]) >= VH_LINES) + break; + line = (vh * VH_LINES) + CSR_GETCHAN (vh_csr[vh]); + lp = &vh_parm[line]; + if (access == WRITEB) + data = (PA & 1) ? + (lp->tbuf1 & 0377) | (data << 8) : + (lp->tbuf1 & ~0377) | data & 0377; + lp->tbuf1 = data; + break; + case 6: /* TBUFFAD2 */ + if ((data == RESET_ABORT) && (vh_csr[vh] & CSR_MASTER_RESET)) { + vh_mcount[vh] = 1; + break; + } + if (CSR_GETCHAN (vh_csr[vh]) >= VH_LINES) + break; + line = (vh * VH_LINES) + CSR_GETCHAN (vh_csr[vh]); + lp = &vh_parm[line]; + if (access == WRITEB) + data = (PA & 1) ? + (lp->tbuf2 & 0377) | (data << 8) : + (lp->tbuf2 & ~0377) | data & 0377; + lp->tbuf2 = data; + /* if starting a DMA, clear DMA_ERR */ + if (vh_unit[vh].flags & UNIT_FASTDMA) { + doDMA (vh, CSR_GETCHAN (vh_csr[vh])); + tmxr_send_buffered_data (lp->tmln); + } + break; + case 7: /* TBUFFCT */ + if ((data == RESET_ABORT) && (vh_csr[vh] & CSR_MASTER_RESET)) { + vh_mcount[vh] = 1; + break; + } + if (CSR_GETCHAN (vh_csr[vh]) >= VH_LINES) + break; + line = (vh * VH_LINES) + CSR_GETCHAN (vh_csr[vh]); + lp = &vh_parm[line]; + if (access == WRITEB) + data = (PA & 1) ? + (lp->tbuffct & 0377) | (data << 8) : + (lp->tbuffct & ~0377) | data & 0377; + lp->tbuffct = data; + break; + default: + /* can't happen */ + break; + } + return (SCPE_OK); +} + +static void doDMA ( int32 vh, + int32 chan ) +{ + int32 line, status; + uint32 pa; + TMLX *lp; + + line = (vh * VH_LINES) + chan; + lp = &vh_parm[line]; + if ((lp->tbuf2 & TB2_TX_ENA) && (lp->tbuf2 & TB2_TX_DMA_START)) { +/* BUG: should compare against available xmit buffer space */ + pa = lp->tbuf1; + pa |= (lp->tbuf2 & TB2_M_TBUFFAD) << 16; + status = chan << CSR_V_TX_LINE; + while (lp->tbuffct) { + char buf; + if (Map_ReadB (pa, 1, &buf, MAP)) { + status |= CSR_TX_DMA_ERR; + lp->tbuffct = 0; + break; + } + if (vh_putc (vh, lp, chan, buf) != SCPE_OK) + break; + /* pa = (pa + 1) & PAMASK; */ + pa = (pa + 1) & ((1 << 22) - 1); + lp->tbuffct--; + } + lp->tbuf1 = pa & 0177777; + lp->tbuf2 = (lp->tbuf2 & ~TB2_M_TBUFFAD) | + ((pa >> 16) & TB2_M_TBUFFAD); + if (lp->tbuffct == 0) { + lp->tbuf2 &= ~TB2_TX_DMA_START; + q_tx_report (vh, status); + } + } +} + +/* Perform many of the functions of PROC2 */ + +static t_stat vh_svc ( UNIT *uptr ) +{ + int32 vh, newln, i; + + /* scan all muxes for countdown reset */ + for (vh = 0; vh < VH_MUXES; vh++) { + if (vh_csr[vh] & CSR_MASTER_RESET) { + if (vh_mcount[vh] != 0) + vh_mcount[vh] -= 1; + else + vh_clear (vh, FALSE); + } + } + /* sample every 10ms for modem changes (new connections) */ + newln = tmxr_poll_conn (&vh_desc); + if (newln >= 0) { + TMLX *lp; + int32 line; + vh = newln / VH_LINES; /* determine which mux */ + line = newln - (vh * VH_LINES); + lp = &vh_parm[newln]; + lp->lstat |= STAT_DSR | STAT_DCD | STAT_CTS; + if (!(lp->lnctrl & LNCTRL_DTR)) + lp->lstat |= STAT_RI; + if (lp->lnctrl & LNCTRL_LINK_TYPE) + fifo_put (vh, lp, RBUF_DIAG | + RBUF_PUTLINE (line) | + ((lp->lstat >> 8) & 0376)); + /* BUG: should check for overflow above */ + } + /* scan all muxes, lines for DMA to complete; start every 3.12ms */ + for (vh = 0; vh < VH_MUXES; vh++) { + for (i = 0; i < VH_LINES; i++) + doDMA (vh, i); + } + /* interrupt driven in a real DHQ */ + tmxr_poll_rx (&vh_desc); + for (vh = 0; vh < VH_MUXES; vh++) + vh_getc (vh); + tmxr_poll_tx (&vh_desc); + /* scan all DHU-mode muxes for RX FIFO timeout */ + for (vh = 0; vh < VH_MUXES; vh++) { + if (vh_unit[vh].flags & UNIT_MODEDHU) { + if (vh_timeo[vh] && (vh_csr[vh] & CSR_RXIE)) { + vh_timeo[vh] -= 1; + if ((vh_timeo[vh] == 0) && rbuf_idx[vh]) + vh_set_rxint (vh); + } + } + } + sim_activate (uptr, tmxr_poll); /* requeue ourselves */ + return (SCPE_OK); +} + + /* init a channel on a controller */ + +/* set for: +send/receive 9600 +8 data bits +1 stop bit +no parity +parity odd +auto-flow off +RX disabled +TX enabled +no break on line +no loopback +link type set to data-leads only +DTR & RTS off +DMA character counter 0 +DMA start address registers 0 +TX_DMA_START 0 +TX_ABORT 0 +auto-flow reports enabled +FIFO size set to 64 +*/ + +static void vh_init_chan ( int32 vh, + int32 chan ) +{ + int32 line; + TMLX *lp; + + line = (vh * VH_LINES) + chan; + lp = &vh_parm[line]; + lp->lpr = (RATE_9600 << LPR_V_TX_SPEED) | + (RATE_9600 << LPR_V_RX_SPEED) | + (03 << LPR_V_CHAR_LGTH); + lp->lnctrl = 0; + lp->lstat &= ~(STAT_MDL | STAT_DHUID | STAT_RI); + if (vh_unit[vh].flags & UNIT_MODEDHU) + lp->lstat |= STAT_DHUID | 64; + if (!(vh_unit[vh].flags & UNIT_MODEM)) + lp->lstat |= STAT_DSR | STAT_DCD | STAT_CTS; + lp->tmln->xmte = 1; + lp->tmln->rcve = 0; + lp->tbuffct = 0; + lp->tbuf1 = 0; + lp->tbuf2 = TB2_TX_ENA; + lp->txchar = 0; +} + +/* init a controller; flag true if BINIT, false if master.reset */ + +static t_stat vh_clear ( int32 vh, + t_bool flag ) +{ + int32 i; + + txq_idx[vh] = 0; + rbuf_idx[vh] = 0; + /* put 8 diag bytes in FIFO: 6 SELF_x, 2 circuit revision codes */ + if (vh_csr[vh] & CSR_SKIP) { + fifo_put (vh, NULL, RBUF_DIAG | RBUF_PUTLINE(0) | SELF_SKIP); + fifo_put (vh, NULL, RBUF_DIAG | RBUF_PUTLINE(1) | SELF_SKIP); + fifo_put (vh, NULL, RBUF_DIAG | RBUF_PUTLINE(2) | SELF_SKIP); + fifo_put (vh, NULL, RBUF_DIAG | RBUF_PUTLINE(3) | SELF_SKIP); + fifo_put (vh, NULL, RBUF_DIAG | RBUF_PUTLINE(4) | SELF_SKIP); + fifo_put (vh, NULL, RBUF_DIAG | RBUF_PUTLINE(5) | SELF_SKIP); + fifo_put (vh, NULL, RBUF_DIAG | RBUF_PUTLINE(6) | 0107); + fifo_put (vh, NULL, RBUF_DIAG | RBUF_PUTLINE(7) | 0105); + } else { + fifo_put (vh, NULL, RBUF_DIAG | RBUF_PUTLINE(0) | SELF_NULL); + fifo_put (vh, NULL, RBUF_DIAG | RBUF_PUTLINE(1) | SELF_NULL); + fifo_put (vh, NULL, RBUF_DIAG | RBUF_PUTLINE(2) | SELF_NULL); + fifo_put (vh, NULL, RBUF_DIAG | RBUF_PUTLINE(3) | SELF_NULL); + fifo_put (vh, NULL, RBUF_DIAG | RBUF_PUTLINE(4) | SELF_NULL); + fifo_put (vh, NULL, RBUF_DIAG | RBUF_PUTLINE(5) | SELF_NULL); + /* PROC2 ver. 1 */ + fifo_put (vh, NULL, RBUF_DIAG | RBUF_PUTLINE(6) | 0107); + /* PROC1 ver. 1 */ + fifo_put (vh, NULL, RBUF_DIAG | RBUF_PUTLINE(7) | 0105); + } + vh_csr[vh] &= ~(CSR_TX_ACTION|CSR_DIAG_FAIL|CSR_MASTER_RESET); + if (flag) + vh_csr[vh] &= ~(CSR_TXIE|CSR_RXIE|CSR_SKIP); + vh_csr[vh] |= CSR_TX_DMA_ERR | (CSR_M_TX_LINE << CSR_V_TX_LINE); + vh_clr_rxint (vh); + vh_clr_txint (vh); + vh_timer[vh] = 1; + vh_timeo[vh] = 0; + vh_ovrrun[vh] = 0; + for (i = 0; i < VH_LINES; i++) + vh_init_chan (vh, i); + vh_crit &= ~(1 << vh); + vh_stall[vh] = 0; + vh_loop[vh] = LOOP_NONE; + return (SCPE_OK); +} + +/* Reset all controllers. Used by BINIT and RESET. */ + +static t_stat vh_reset ( DEVICE *dptr ) +{ + int32 i; +#if defined (VM_PDP11) + /* import from pdp11_cpu.c: */ + extern int32 cpu_18b, cpu_ubm; +#endif + + for (i = 0; i < (VH_MUXES * VH_LINES); i++) + vh_parm[i].tmln = &vh_ldsc[i]; + for (i = 0; i < VH_MUXES; i++) { +#if defined (VM_PDP11) + /* if Unibus, force DHU mode */ + if (UNIBUS) + vh_unit[i].flags |= UNIT_MODEDHU; +#endif + vh_clear (i, TRUE); + } + vh_rxi = vh_txi = 0; + CLR_INT (VHRX); + CLR_INT (VHTX); + for (i = 0; i < VH_MUXES; i++) + sim_cancel (&vh_unit[i]); + return (auto_config (RANK_VH, (dptr->flags & DEV_DIS) ? 0 : VH_MUXES)); +} + + +static t_stat vh_attach ( UNIT *uptr, + char *cptr ) +{ + if (uptr == &vh_unit[0]) + return (tmxr_attach (&vh_desc, uptr, cptr)); + return (SCPE_NOATT); +} + +static t_stat vh_detach ( UNIT *uptr ) +{ + return (tmxr_detach (&vh_desc, uptr)); +} + +static t_stat vh_summ ( FILE *st, + UNIT *uptr, + int32 val, + void *desc ) +{ +int32 i, t; + +for (i = t = 0; i < vh_desc.lines; i++) { /* get num conn */ + if (vh_ldsc[i].conn) t = t + 1; } +fprintf (st, "%d %s", t, (t == 1) ? "connection" : "connections"); +return SCPE_OK; +} + +static t_stat vh_show (FILE *st, UNIT *uptr, int32 val, void *desc) +{ +int32 i, t; + +for (i = t = 0; i < vh_desc.lines; i++) { /* loop thru conn */ + if (vh_ldsc[i].conn) { + t = 1; + if (val) tmxr_fconns (st, &vh_ldsc[i], i); + else tmxr_fstats (st, &vh_ldsc[i], i); } } +if (t == 0) fprintf (st, "all disconnected\n"); +return SCPE_OK; +} + +static t_stat vh_show_vec ( FILE *st, + UNIT *uptr, + int32 val, + void *desc ) +{ + return (show_vec (st, uptr, val, desc)); +} + +static void debug_line ( FILE *st, + int32 vh, + int32 chan ) +{ + int32 line; + TMLX *lp; + + line = (vh * VH_LINES) + chan; + lp = &vh_parm[line]; + fprintf (st, "\tline %d\tlpr %06o, lnctrl %06o, lstat %06o\n", + chan, lp->lpr, lp->lnctrl, lp->lstat); + fprintf (st, "\t\ttbuffct %06o, tbuf1 %06o, tbuf2 %06o, txchar %06o\n", + lp->tbuffct, lp->tbuf1, lp->tbuf2, lp->txchar); + fprintf (st, "\t\ttmln rcve %d xmte %d\n", + lp->tmln->rcve, lp->tmln->xmte); +} + +static t_stat vh_show_debug ( FILE *st, + UNIT *uptr, + int32 val, + void *desc ) +{ + int32 i, j; + + fprintf (st, "VH:\trxi %d, txi %d\n", vh_rxi, vh_txi); + for (i = 0; i < VH_MUXES; i++) { + fprintf (st, "VH%d:\tmode %s, crit %d\n", i, + vh_unit[i].flags & UNIT_MODEDHU ? "DHU" : "DHV", + vh_crit & (1 << i)); + fprintf (st, "\tCSR %06o, mcount %d, rbuf_idx %d, txq_idx %d\n", + vh_csr[i], vh_mcount[i], rbuf_idx[i], txq_idx[i]); + for (j = 0; j < VH_LINES; j++) + debug_line (st, i, j); + } + return (SCPE_OK); +} + +static t_stat vh_show_rbuf ( FILE *st, + UNIT *uptr, + int32 val, + void *desc ) +{ + int32 i; + + for (i = 0; i < rbuf_idx[0]; i++) + fprintf (st, "%03d: %06o\n", i, vh_rbuf[0][i]); + return (SCPE_OK); +} + +static t_stat vh_show_txq ( FILE *st, + UNIT *uptr, + int32 val, + void *desc ) +{ + int32 i; + + for (i = 0; i < txq_idx[0]; i++) + fprintf (st, "%02d: %06o\n\r", i, vh_txq[0][i]); + return (SCPE_OK); +} + diff --git a/PDP18B/pdp18b_doc.txt b/PDP18B/pdp18b_doc.txt index f17536ee..90053cd8 100644 --- a/PDP18B/pdp18b_doc.txt +++ b/PDP18B/pdp18b_doc.txt @@ -1,7 +1,7 @@ To: Users From: Bob Supnik Subj: 18b PDP Simulator Usage -Date: 4-Apr-2004 +Date: 15-Jun-2004 COPYRIGHT NOTICE @@ -416,12 +416,6 @@ implements these registers: POS 32 number of characters input TIME 24 keyboard polling interval -If the simulator is debugged under Windows Visual C++, typing ^C to the -terminal input causes a fatal run-time error. Use the following command -to simulate typing ^C: - - SET TTI CTRL-C - 2.3.4 Terminal Output (TTO) The terminal output (TTO) writes to the simulator console window. It diff --git a/PDP18B/pdp18b_fpp.c b/PDP18B/pdp18b_fpp.c index 5d27437c..259b090f 100644 --- a/PDP18B/pdp18b_fpp.c +++ b/PDP18B/pdp18b_fpp.c @@ -24,6 +24,8 @@ in this Software without prior written authorization from Robert M Supnik. fpp PDP-15 floating point processor + + 10-Apr-04 RMS JEA is 15b not 18b The FP15 instruction format is: @@ -168,7 +170,6 @@ void dp_swap (UFP *a, UFP *b); extern t_stat Read (int32 ma, int32 *dat, int32 cyc); extern t_stat Write (int32 ma, int32 dat, int32 cyc); -extern t_stat Ia (int32 ma, int32 *ea, t_bool jmp); extern int32 Incr_addr (int32 addr); extern int32 Jms_word (int32 t); @@ -195,7 +196,7 @@ REG fpp_reg[] = { { FLDATA (FGUARD, fguard, 0) }, { ORDATA (FMQH, fmq.hi, 17) }, { ORDATA (FMQL, fmq.lo, 18) }, - { ORDATA (JEA, jea, 18) }, + { ORDATA (JEA, jea, 15) }, { FLDATA (STOP_FPP, stop_fpp, 0) }, { NULL } }; @@ -314,7 +315,7 @@ case FOP_JEA: /* JEA */ else { /* no, load */ if (sta = Read (ar, &dat, RD)) break; fguard = (dat >> JEA_V_GUARD) & 1; - jea = dat; } + jea = dat & JEA_EAMASK; } break; case FOP_ADD: /* add */ diff --git a/PDP18B/pdp18b_stddev.c b/PDP18B/pdp18b_stddev.c index 8d391714..02b4e941 100644 --- a/PDP18B/pdp18b_stddev.c +++ b/PDP18B/pdp18b_stddev.c @@ -29,6 +29,7 @@ tto teleprinter clk clock + 28-May-04 RMS Removed SET TTI CTRL-C 16-Feb-04 RMS Fixed bug in hardware read-in mode bootstrap 14-Jan-04 RMS Revised IO device call interface CAF does not turn off the clock @@ -37,7 +38,7 @@ Added hardware read-in mode support for PDP-7/9/15 25-Apr-03 RMS Revised for extended file support 14-Mar-03 RMS Clean up flags on detach - 01-Mar-03 RMS Added SET/SHOW CLK FREQ support, SET TTI CTRL-C support + 01-Mar-03 RMS Added SET/SHOW CLK freq, SET TTI CTRL-C 22-Dec-02 RMS Added break support 01-Nov-02 RMS Added 7B/8B support to terminal 05-Oct-02 RMS Added DIBs, device number support, IORS call @@ -106,7 +107,6 @@ t_stat ptr_detach (UNIT *uptr); t_stat ptp_detach (UNIT *uptr); t_stat ptr_boot (int32 unitno, DEVICE *dptr); t_stat tty_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat tti_set_ctrlc (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat clk_set_freq (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat clk_show_freq (FILE *st, UNIT *uptr, int32 val, void *desc); @@ -292,7 +292,6 @@ MTAB tti_mod[] = { { UNIT_KSR+UNIT_8B, UNIT_8B , "8b" , "8B" , &tty_set_mode }, { UNIT_HDX, 0 , "full duplex", "FDX", NULL }, { UNIT_HDX, UNIT_HDX, "half duplex", "HDX", NULL }, - { MTAB_XTD|MTAB_VDV|MTAB_VUN, 0, NULL, "CTRL-C", &tti_set_ctrlc, NULL, NULL }, #endif { MTAB_XTD|MTAB_VDV, 0, "DEVNO", NULL, NULL, &show_devno, NULL }, { 0 } }; diff --git a/PDP8/pdp8_doc.txt b/PDP8/pdp8_doc.txt index 3ea13e4c..50e014d0 100644 --- a/PDP8/pdp8_doc.txt +++ b/PDP8/pdp8_doc.txt @@ -1,7 +1,7 @@ To: Users From: Bob Supnik Subj: PDP-8 Simulator Usage -Date: 15-Feb-2004 +Date: 15-Jun-2004 COPYRIGHT NOTICE @@ -305,12 +305,6 @@ implements these registers: POS 32 number of characters input TIME 24 keyboard polling interval -If the simulator is compiled under Windows Visual C++, typing ^C to the -terminal input causes a fatal run-time error. Use the following command -to simulate typing ^C: - - SET TTI CTRL-C - 2.3.4 KL8E Terminal Output (TTO) The terminal output (TTO) writes to the simulator console window. It diff --git a/PDP8/pdp8_tt.c b/PDP8/pdp8_tt.c index eb6a595d..295c1466 100644 --- a/PDP8/pdp8_tt.c +++ b/PDP8/pdp8_tt.c @@ -25,6 +25,7 @@ tti,tto KL8E terminal input/output + 28-May-04 RMS Removed SET TTI CTRL-C 29-Dec-03 RMS Added console output backpressure support 25-Apr-03 RMS Revised for extended file support 02-Mar-02 RMS Added SET TTI CTRL-C @@ -51,7 +52,6 @@ t_stat tti_svc (UNIT *uptr); t_stat tto_svc (UNIT *uptr); t_stat tti_reset (DEVICE *dptr); t_stat tto_reset (DEVICE *dptr); -t_stat tti_set_ctrlc (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat tty_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc); /* TTI data structures @@ -80,7 +80,6 @@ MTAB tti_mod[] = { { UNIT_KSR+UNIT_8B, UNIT_KSR, "KSR", "KSR", &tty_set_mode }, { UNIT_KSR+UNIT_8B, 0 , "7b" , "7B" , &tty_set_mode }, { UNIT_KSR+UNIT_8B, UNIT_8B , "8b" , "8B" , &tty_set_mode }, - { MTAB_XTD|MTAB_VDV|MTAB_VUN, 0, NULL, "CTRL-C", &tti_set_ctrlc, NULL, NULL }, { MTAB_XTD|MTAB_VDV, 0, "DEVNO", NULL, NULL, &show_dev, NULL }, { 0 } }; @@ -186,18 +185,6 @@ int_enable = int_enable | INT_TTI; /* set enable */ sim_activate (&tti_unit, tti_unit.wait); /* activate unit */ return SCPE_OK; } - -/* Set control-C */ - -t_stat tti_set_ctrlc (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -if (cptr) return SCPE_ARG; -uptr->buf = (uptr->flags & UNIT_KSR)? 0203: 0003; -uptr->pos = uptr->pos + 1; -dev_done = dev_done | INT_TTI; /* set done */ -int_req = INT_UPDATE; /* update interrupts */ -return SCPE_OK; -} /* Terminal output: IOT routine */ diff --git a/VAX/vax_cpu.c b/VAX/vax_cpu.c index df579873..999341bb 100644 --- a/VAX/vax_cpu.c +++ b/VAX/vax_cpu.c @@ -25,6 +25,8 @@ cpu CVAX central processor + 28-Jun-04 RMS Fixed bug in DIVBx, DIVWx (reported by Peter Trimmel) + 18-Apr-04 RMS Added octaword macros 25-Jan-04 RMS Removed local debug logging support RMS,MP Added extended physical memory support 31-Dec-03 RMS Fixed bug in set_cpu_hist @@ -155,7 +157,7 @@ #define UNIT_MSIZE (1u << UNIT_V_MSIZE) #define GET_CUR acc = ACC_MASK (PSL_GETCUR (PSL)) -#define OPND_SIZE 10 +#define OPND_SIZE 20 #define op0 opnd[0] #define op1 opnd[1] #define op2 opnd[2] @@ -167,6 +169,7 @@ #define op8 opnd[8] #define CHECK_FOR_PC if (rn == nPC) RSVD_ADDR_FAULT #define CHECK_FOR_SP if (rn >= nSP) RSVD_ADDR_FAULT +#define CHECK_FOR_AP if (rn >= nAP) RSVD_ADDR_FAULT #define RECW(l) ((l) << 4) | rn #define WRITE_B(r) if (spec > (GRN | nPC)) Write (va, r, L_BYTE, WA); \ else R[rn] = (R[rn] & ~BMASK) | ((r) & BMASK) @@ -174,11 +177,24 @@ else R[rn] = (R[rn] & ~WMASK) | ((r) & WMASK) #define WRITE_L(r) if (spec > (GRN | nPC)) Write (va, r, L_LONG, WA); \ else R[rn] = (r) -#define WRITE_Q(rl,rh) if (spec > (GRN | nPC)) { \ - if (Test (va + 7, WA, &mstat) >= 0) \ - Write (va, rl, L_LONG, WA); \ - Write (va + 4, rh, L_LONG, WA); } \ - else { R[rn] = rl; R[rnplus1] = rh; } +#define WRITE_Q(rl,rh) if (spec > (GRN | nPC)) { \ + if (Test (va + 7, WA, &mstat) >= 0) \ + Write (va, rl, L_LONG, WA); \ + Write (va + 4, rh, L_LONG, WA); } \ + else { \ + R[rn] = rl; \ + R[rnplus1] = rh; } +#define WRITE_O(rl,rm2,rm1,rh) if (spec > (GRN | nPC)) { \ + if (Test (va + 15, WA, &mstat) >= 0) \ + Write (va, rl, L_LONG, WA); \ + Write (va + 4, rm2, L_LONG, WA); \ + Write (va + 8, rm1, L_LONG, WA); \ + Write (va + 12, rh, L_LONG, WA); } \ + else { \ + R[rn] = rl; \ + R[(rn + 1) & 0xF] = rm2; \ + R[(rn + 2) & 0xF] = rm1; \ + R[(rn + 3) & 0xF] = rh; } #define HIST_MIN 128 #define HIST_MAX 65536 @@ -1343,6 +1359,7 @@ case DIVB2: case DIVB3: else { r = SXTB (op1) / SXTB (op0); /* ok, divide */ temp = 0; } + r = r & BMASK; /* mask to result */ WRITE_B (r); /* write result */ CC_IIZZ_B (r); /* set cc's */ cc = cc | temp; /* error? set V */ @@ -1359,6 +1376,7 @@ case DIVW2: case DIVW3: else { r = SXTW (op1) / SXTW (op0); /* ok, divide */ temp = 0; } + r = r & WMASK; /* mask to result */ WRITE_W (r); /* write result */ CC_IIZZ_W (r); /* set cc's */ cc = cc | temp; /* error? set V */ @@ -1375,6 +1393,7 @@ case DIVL2: case DIVL3: else { r = op1 / op0; /* ok, divide */ temp = 0; } + r = r & LMASK; /* mask to result */ WRITE_L (r); /* write result */ CC_IIZZ_L (r); /* set cc's */ cc = cc | temp; /* error? set V */ @@ -1460,7 +1479,7 @@ case ROTL: case ASHL: if (op0 & BSIGN) { /* right shift? */ temp = 0x100 - op0; /* get |shift| */ - if (temp > 31) r = (op1 & LSIGN)? -1: 0; /* sc > 31? */ + if (temp > 31) r = (op1 & LSIGN)? LMASK: 0; /* sc > 31? */ else r = op1 >> temp; /* shift */ WRITE_L (r); /* store result */ CC_IIZZ_L (r); /* set cc's */ @@ -1468,7 +1487,7 @@ case ASHL: else { if (op0 > 31) r = temp = 0; /* sc > 31? */ else { - r = ((uint32) op1) << op0; /* shift */ + r = (((uint32) op1) << op0) & LMASK; /* shift */ temp = r >> op0; } /* shift back */ WRITE_L (r); /* store result */ CC_IIZZ_L (r); /* set cc's */ diff --git a/VAX/vax_cpu1.c b/VAX/vax_cpu1.c index 53585471..507931d9 100644 --- a/VAX/vax_cpu1.c +++ b/VAX/vax_cpu1.c @@ -730,15 +730,6 @@ return 0; /* q can't be empty */ #define MVC_FILL 3 /* must be 3 */ #define MVC_M_STATE 3 #define MVC_V_CC 2 -#define STR_V_DPC 24 -#define STR_M_DPC 0xFF -#define STR_V_CHR 16 -#define STR_M_CHR 0xFF -#define STR_LNMASK 0xFFFF -#define STR_GETDPC(x) (((x) >> STR_V_DPC) & STR_M_DPC) -#define STR_GETCHR(x) (((x) >> STR_V_CHR) & STR_M_CHR) -#define STR_PACK(m,x) ((((PC - fault_PC) & STR_M_DPC) << STR_V_DPC) | \ - (((m) & STR_M_CHR) << STR_V_CHR) | ((x) & STR_LNMASK)) /* MOVC3, MOVC5 diff --git a/VAX/vax_defs.h b/VAX/vax_defs.h index dfed24ff..b8d69a32 100644 --- a/VAX/vax_defs.h +++ b/VAX/vax_defs.h @@ -26,6 +26,7 @@ The author gratefully acknowledges the help of Stephen Shirron, Antonio Carlini, and Kevin Peterson in providing specifications for the Qbus VAX's + 18-Apr-04 RMS Added octa, fp, string definitions 19-May-03 RMS Revised for new conditional compilation scheme 14-Jul-02 RMS Added infinite loop message 30-Apr-02 RMS Added CLR_TRAPS macro @@ -96,6 +97,32 @@ #define NUM_INST 512 /* one byte+two byte */ #define MAX_SPEC 6 /* max spec/instr */ +/* Floating point formats */ + +#define FD_V_EXP 7 /* f/d exponent */ +#define FD_M_EXP 0xFF +#define FD_BIAS 0x80 /* f/d bias */ +#define FD_EXP (FD_M_EXP << FD_V_EXP) +#define FD_HB (1 << FD_V_EXP) /* f/d hidden bit */ +#define FD_GUARD (15 - FD_V_EXP) /* # guard bits */ +#define FD_GETEXP(x) (((x) >> FD_V_EXP) & FD_M_EXP) + +#define G_V_EXP 4 /* g exponent */ +#define G_M_EXP 0x7FF +#define G_BIAS 0x400 /* g bias */ +#define G_EXP (G_M_EXP << G_V_EXP) +#define G_HB (1 << G_V_EXP) /* g hidden bit */ +#define G_GUARD (15 - G_V_EXP) /* # guard bits */ +#define G_GETEXP(x) (((x) >> G_V_EXP) & G_M_EXP) + +#define H_V_EXP 0 /* h exponent */ +#define H_M_EXP 0x7FFF +#define H_BIAS 0x4000 /* h bias */ +#define H_EXP (H_M_EXP << H_V_EXP) +#define H_HB (1 << H_V_EXP) /* h hidden bit */ +#define H_GUARD (15 - H_V_EXP) /* # guard bits */ +#define H_GETEXP(x) (((x) >> H_V_EXP) & H_M_EXP) + /* Memory management modes */ #define KERN 0 @@ -458,6 +485,18 @@ enum opcodes { #define SETPC(d) PC = (d), FLUSH_ISTR #define FLUSH_ISTR ibcnt = 0, ppc = -1 +/* Character string instructions */ + +#define STR_V_DPC 24 /* delta PC */ +#define STR_M_DPC 0xFF +#define STR_V_CHR 16 /* char argument */ +#define STR_M_CHR 0xFF +#define STR_LNMASK 0xFFFF /* string length */ +#define STR_GETDPC(x) (((x) >> STR_V_DPC) & STR_M_DPC) +#define STR_GETCHR(x) (((x) >> STR_V_CHR) & STR_M_CHR) +#define STR_PACK(m,x) ((((PC - fault_PC) & STR_M_DPC) << STR_V_DPC) | \ + (((m) & STR_M_CHR) << STR_V_CHR) | ((x) & STR_LNMASK)) + /* Read and write */ #define RA (acc) @@ -488,6 +527,10 @@ enum opcodes { if ((rh) & LSIGN) cc = CC_N; \ else if (((rl) | (rh)) == 0) cc = CC_Z; \ else cc = 0 +#define CC_IIZZ_O(rl,rm2,rm1,rh) \ + if ((rh) & LSIGN) cc = CC_N; \ + else if (((rl) | (rm2) | (rm1) | (rh)) == 0) cc = CC_Z; \ + else cc = 0 #define CC_IIZZ_FP CC_IIZZ_W #define CC_IIZP_B(r) \ @@ -506,6 +549,10 @@ enum opcodes { if ((rh) & LSIGN) cc = CC_N | (cc & CC_C); \ else if (((rl) | (rh)) == 0) cc = CC_Z | (cc & CC_C); \ else cc = cc & CC_C +#define CC_IIZP_O(rl,rm2,rm1,rh) \ + if ((rh) & LSIGN) cc = CC_N | (cc & CC_C); \ + else if (((rl) | (rm2) | (rm1) | (rh)) == 0) cc = CC_Z | (cc & CC_C); \ + else cc = cc & CC_C #define CC_IIZP_FP CC_IIZP_W #define V_ADD_B(r,s1,s2) \ diff --git a/VAX/vax_doc.txt b/VAX/vax_doc.txt index 2033a6b2..05bc356d 100644 --- a/VAX/vax_doc.txt +++ b/VAX/vax_doc.txt @@ -1,7 +1,7 @@ To: Users From: Bob Supnik Subj: VAX Simulator Usage -Date: 04-Apr-2004 +Date: 15-Jun-2004 COPYRIGHT NOTICE @@ -82,7 +82,8 @@ sim/pdp11/ pdp11_mscp.h pdp11_rq.c pdp11_tq.c pdp11_ts.c - pdp11_xp.c + pdp11_vh.c + pdp11_xq.c Additional files are: @@ -108,6 +109,7 @@ TTI,TTO console terminal LPT LPV11 line printer CLK real-time clock DZ DZV11 4-line terminal multiplexor (up to 4) +VH DHQ11 8-line terminal multiplexor (up to 4) RL RLV12/RL01(2) cartridge disk controller with four drives RQ RQDX3 MSCP controller with four drives RQB second RQDX3 MSCP controller with four drives @@ -476,12 +478,6 @@ implements these registers: POS 32 number of characters input TIME 24 keyboard polling interval -If the simulator is compiled under Windows Visual C++, typing ^C to the -terminal input causes a fatal run-time error. Use the following command -to simulate typing ^C: - - SET TTI CTRL-C - 2.3.4 Terminal Output (TTO) The terminal output (TTO) writes to the simulator console window. It @@ -544,81 +540,6 @@ The clock (CLK) implements these registers: The real-time clock autocalibrates; the clock interval is adjusted up or down so that the clock tracks actual elapsed time. -2.3.7 DZV11 Terminal Multiplexor (DZ) - -The DZV11 is an 4-line terminal multiplexor. Up to 4 DZ11's (16 lines) -are supported. The number of lines can be changed with the command - - SET DZ LINES=n set line count to n - -The line count must be a multiple of 4, with a maximum of 16. - -The DZV11 supports 8-bit input and output of characters. 8-bit output -may be incompatible with certain operating systems. The command - - SET DZ 7B - -forces output characters to be masked to 7 bits. - -The DZ11 supports logging on a per-line basis. The command - - SET DZ LOG=line=filename - -enables logging for the specified line to the indicated file. The -command - - SET DZ NOLOG=line - -disables logging for the specified line and closes any open log file. -Finally, the command - - SHOW DZ LOG - -displays logging information for all DZ lines. - -The terminal lines perform input and output through Telnet sessions -connected to a user-specified port. The ATTACH command specifies -the port to be used: - - ATTACH {-am} DZ set up listening port - -where port is a decimal number between 1 and 65535 that is not being used -for other TCP/IP activities. The optional switch -m turns on the DZV11's -modem controls; the optional switch -a turns on active disconnects -(disconnect session if computer clears Data Terminal Ready). Without -modem control, the DZ behaves as though terminals were directly connected; -disconnecting the Telnet session does not cause any operating system- -visible change in line status. - -Once the DZ is attached and the simulator is running, the DZ will listen -for connections on the specified port. It assumes that the incoming -connections are Telnet connections. The connection remains open until -disconnected by the simulated program, the Telnet client, a SET DZ -DISCONNECT command, or a DETACH DZ command. - -The SHOW DZ CONNECTIONS command displays the current connections to the DZ. -The SHOW DZ STATISTICS command displays statistics for active connections. -The SET DZ DISCONNECT=linenumber disconnects the specified line. - -The DZV11 implements these registers: - - name size comments - - CSR[0:3] 16 control/status register, boards 0-3 - RBUF[0:3] 16 receive buffer, boards 0-3 - LPR[0:3] 16 line parameter register, boards 0-3 - TCR[0:3] 16 transmission control register, boards 0-3 - MSR[0:3] 16 modem status register, boards 0-3 - TDR[0:3] 16 transmit data register, boards 0-3 - SAENB[0:3] 1 silo alarm enabled, boards 0-3 - RXINT 4 receive interrupts, boards 3..0 - TXINT 4 transmit interrupts, boards 3..0 - MDMTCL 1 modem control enabled - AUTODS 1 autodisconnect enabled - -The DZV11 does not support save and restore. All open connections are -lost when the simulator shuts down or the DZ is detached. - 2.4 RLV12/RL01,RL02 Cartridge Disk (RL) RLV12 options include the ability to set units write enabled or write locked, @@ -685,13 +606,12 @@ of many disk types: SET RQn RA72 set type to RA72 SET RQn RA90 set type to RA90 SET RQn RA92 set type to RA92 - SET RQn RAUSER{=n} set type to RA81 with n LBN's + SET RQn RAUSER{=n} set type to RA81 with n MB's The type options can be used only when a unit is not attached to a file. RAUSER is a "user specified" disk; the user can specify the size of the -disk in logical block numbers (LBN's, 512 bytes each). The minimum size -is 50MB. The maximum size is 2GB if the simulator is compiled without -64b addressing, 1000GB with 64b addressing. +disk in megabytes. The minimum size is 50MB. The maximum size is 2GB if +the simulator is compiled without 64b addressing, 1000GB with 64b addressing. Units can also be set ONLINE or OFFLINE. @@ -912,6 +832,163 @@ Error handling is as follows: OS I/O error report error and stop +2.8 Communications Devices + +2.8.1 DZV11 Terminal Multiplexor (DZ) + +The DZV11 is an 4-line terminal multiplexor. Up to 4 DZ11's (16 lines) +are supported. The number of lines can be changed with the command + + SET DZ LINES=n set line count to n + +The line count must be a multiple of 4, with a maximum of 16. + +The DZV11 supports 8-bit input and output of characters. 8-bit output +may be incompatible with certain operating systems. The command + + SET DZ 7B + +forces output characters to be masked to 7 bits. + +The DZ11 supports logging on a per-line basis. The command + + SET DZ LOG=line=filename + +enables logging for the specified line to the indicated file. The +command + + SET DZ NOLOG=line + +disables logging for the specified line and closes any open log file. +Finally, the command + + SHOW DZ LOG + +displays logging information for all DZ lines. + +The terminal lines perform input and output through Telnet sessions +connected to a user-specified port. The ATTACH command specifies +the port to be used: + + ATTACH {-am} DZ set up listening port + +where port is a decimal number between 1 and 65535 that is not being used +for other TCP/IP activities. The optional switch -m turns on the DZV11's +modem controls; the optional switch -a turns on active disconnects +(disconnect session if computer clears Data Terminal Ready). Without +modem control, the DZ behaves as though terminals were directly connected; +disconnecting the Telnet session does not cause any operating system- +visible change in line status. + +Once the DZ is attached and the simulator is running, the DZ will listen +for connections on the specified port. It assumes that the incoming +connections are Telnet connections. The connection remains open until +disconnected by the simulated program, the Telnet client, a SET DZ +DISCONNECT command, or a DETACH DZ command. + +The SHOW DZ CONNECTIONS command displays the current connections to the DZ. +The SHOW DZ STATISTICS command displays statistics for active connections. +The SET DZ DISCONNECT=linenumber disconnects the specified line. + +The DZV11 implements these registers: + + name size comments + + CSR[0:3] 16 control/status register, boards 0-3 + RBUF[0:3] 16 receive buffer, boards 0-3 + LPR[0:3] 16 line parameter register, boards 0-3 + TCR[0:3] 16 transmission control register, boards 0-3 + MSR[0:3] 16 modem status register, boards 0-3 + TDR[0:3] 16 transmit data register, boards 0-3 + SAENB[0:3] 1 silo alarm enabled, boards 0-3 + RXINT 4 receive interrupts, boards 3..0 + TXINT 4 transmit interrupts, boards 3..0 + MDMTCL 1 modem control enabled + AUTODS 1 autodisconnect enabled + +The DZV11 does not support save and restore. All open connections are +lost when the simulator shuts down or the DZ is detached. + +2.8.2 DHQ11 Terminal Multiplexor (VH) + +The DHQ11 is an 8-line terminal multiplexor for Qbus systems. Up +to 4 DHQ11's are supported. + +The DHQ11 is a programmable asynchronous terminal multiplexor. It +has two programming modes: DHV11 and DHU11. The register sets are +compatible with these devices. For transmission, the DHQ11 can be +used in either DMA or programmed I/O mode. For reception, there +is a 256-entry FIFO for received characters, dataset status changes, +and diagnostic information, and a programmable input interrupt +timer (in DHU mode). The device supports 16-, 18-, and 22-bit +addressing. The DHQ11 can be programmed to filter and/or handle +XON/XOFF characters independently of the processor. The DHQ11 +supports programmable bit width (between 5 and 8) for the input +and output of characters. + +The DHQ11 has a rocker switch for determining the programming mode. +By default, the DHV11 mode is selected, though DHU11 mode is +recommended for applications that can support it. The VH controller +may be adjusted on a per controller basis as follows: + + SET VHn DHU use the DHU programming mode and registers + SET VHn DHV use the DHV programming mode and registers + +DMA output is supported. In a real DHQ11, DMA is not initiated +immediately upon receipt of TX.DMA.START but is dependent upon some +internal processes. The VH controller mimics this behavior by default. +It may be desirable to alter this and start immediately, though +this may not be compatible with all operating systems and diagnostics. +You can change the behavior of the VH controller as follows: + + SET VHn NORMAL use normal DMA procedures + SET VHn FASTDMA set DMA to initiate immediately + +The terminal lines perform input and output through Telnet sessions +connected to a user-specified port. The ATTACH command specifies +the port to be used: + + ATTACH VH set up listening port + DETACH VH + +where port is a decimal number between 1 and 65535 that is not +being used for other TCP/IP activities. This port is the point of +entry for al lines on all VH controllers. + +Modem and auto-disconnect support may be set on an individual +controller basis. The SET MODEM command directs the controller to +report modem status changes to the computer. The SET HANGUP command +turns on active disconnects (disconnect session if computer clears +Data Terminal Ready). + + SET VHn [NO]MODEM disable/enable modem control + SET VHn [NO]HANGUP disable/enable disconnect on DTR drop + +Once the VH is attached and the simulator is running, the VH will +listen for connections on the specified port. It assumes that the +incoming connections are Telnet connections. The connection remains +open until disconnected by the simulated program, the Telnet client, +a SET VH DISCONNECT command, or a DETACH VH command. + +The SHOW VH CONNECTIONS command displays the current connections to the VH. +The SHOW VH STATISTICS command displays statistics for active connections. +The SET VH DISCONNECT=linenumber disconnects the specified line. + +The DHQ11 implements these registers, though not all can be examined +from SCP: + + name size comments + + CSR[0:3] 16 control/status register, boards 0..3 + RBUF[0:3] 16 receive buffer, boards 0..3 + LPR[0:3] 16 line parameter register, boards 0..3 + RXINT 4 receive interrupts, boards 3..0 + TXINT 4 transmit interrupts, boards 3..0 +[more to be described...] + +The DHQ11 does not support save and restore. All open connections +are lost when the simulator shuts down or the VH is detached. + 2.9 DELQA/DEQNA Qbus Ethernet Controllers (XQ, XQB) The simulator implements two DELQA/DEQNA Qbus Ethernet controllers (XQ, diff --git a/VAX/vax_fpa.c b/VAX/vax_fpa.c index 94980a8d..e8ff0e2c 100644 --- a/VAX/vax_fpa.c +++ b/VAX/vax_fpa.c @@ -23,6 +23,7 @@ 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. + 18-Apr-04 RMS Moved format definitions to vax_defs.h 19-Jun-03 RMS Simplified add algorithm 16-May-03 RMS Fixed bug in floating to integer convert overflow Fixed multiple bugs in EMODx @@ -43,22 +44,6 @@ #define M32 0xFFFFFFFF /* 32b */ #define M16 0x0000FFFF -#define FD_V_EXP 7 /* f/d exponent */ -#define FD_M_EXP 0xFF -#define FD_BIAS 0x80 /* f/d bias */ -#define FD_EXP (FD_M_EXP << FD_V_EXP) -#define FD_HB (1 << FD_V_EXP) /* f/d hidden bit */ -#define FD_GUARD (15 - FD_V_EXP) /* # guard bits */ -#define FD_GETEXP(x) (((x) >> FD_V_EXP) & FD_M_EXP) - -#define G_V_EXP 4 /* g exponent */ -#define G_M_EXP 0x7FF -#define G_BIAS 0x400 /* g bias */ -#define G_EXP (G_M_EXP << G_V_EXP) -#define G_HB (1 << G_V_EXP) /* g hidden bit */ -#define G_GUARD (15 - G_V_EXP) /* # guard bits */ -#define G_GETEXP(x) (((x) >> G_V_EXP) & G_M_EXP) - extern int32 R[16]; extern int32 PSL; extern int32 p1; diff --git a/VAX/vax_io.c b/VAX/vax_io.c index 13d64b69..cf0643a7 100644 --- a/VAX/vax_io.c +++ b/VAX/vax_io.c @@ -25,6 +25,7 @@ qba Qbus adapter + 28-May-04 RMS Revised I/O dispatching (from John Dundas) 21-Mar-04 RMS Added RXV21 support 21-Dec-03 RMS Fixed bug in autoconfigure vector assignment; added controls 21-Nov-03 RMS Added check for interrupt slot conflict (found by Dave Hittner) @@ -154,9 +155,11 @@ DEVICE qba_dev = { NULL, NULL, NULL, &qba_dib, DEV_QBUS }; -/* IO page addresses */ +/* IO page dispatches */ -DIB *dib_tab[DIB_MAX]; /* DIB table */ +static t_stat (*iodispR[IOPAGESIZE >> 1])(int32 *dat, int32 ad, int32 md); +static t_stat (*iodispW[IOPAGESIZE >> 1])(int32 dat, int32 ad, int32 md); +static DIB *iodibp[IOPAGESIZE >> 1]; /* Interrupt request to interrupt action map */ @@ -174,14 +177,12 @@ int32 int_vec[IPL_HLVL][32]; /* int req to vector */ int32 ReadQb (uint32 pa) { -int32 i, val; -DIB *dibp; +int32 idx, val; -for (i = 0; dibp = dib_tab[i]; i++ ) { - if ((pa >= dibp->ba) && - (pa < (dibp->ba + dibp->lnt))) { - dibp->rd (&val, pa, READ); - return val; } } +idx = (pa & IOPAGEMASK) >> 1; +if (iodispR[idx]) { + iodispR[idx] (&val, pa, READ); + return val; } cq_merr (pa); MACH_CHECK (MCHK_READ); return 0; @@ -189,14 +190,12 @@ return 0; void WriteQb (uint32 pa, int32 val, int32 mode) { -int32 i; -DIB *dibp; +int32 idx; -for (i = 0; dibp = dib_tab[i]; i++ ) { - if ((pa >= dibp->ba) && - (pa < (dibp->ba + dibp->lnt))) { - dibp->wr (val, pa, mode); - return; } } +idx = (pa & IOPAGEMASK) >> 1; +if (iodispW[idx]) { + iodispW[idx] (val, pa, mode); + return; } cq_merr (pa); mem_err = 1; return; @@ -781,114 +780,117 @@ else { fprintf (st, "vector=%X", vec); return SCPE_OK; } -/* Test for conflict in device addresses */ +/* Build dispatch tables */ -t_bool dev_conflict (DIB *curr) +t_stat build_dsp_tab (DEVICE *dptr, DIB *dibp) { -uint32 i, end; -DEVICE *dptr; -DIB *dibp; +uint32 i, idx; -end = curr->ba + curr->lnt - 1; /* get end */ -for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { /* loop thru dev */ - dibp = (DIB *) dptr->ctxt; /* get DIB */ - if ((dibp == NULL) || (dibp == curr) || - (dptr->flags & DEV_DIS)) continue; - if (((curr->ba >= dibp->ba) && /* overlap start? */ - (curr->ba < (dibp->ba + dibp->lnt))) || - ((end >= dibp->ba) && /* overlap end? */ - (end < (dibp->ba + dibp->lnt)))) { - printf ("Device %s address conflict at %08X\n", - sim_dname (dptr), dibp->ba); - if (sim_log) fprintf (sim_log, - "Device %s address conflict at %08X\n", - sim_dname (dptr), dibp->ba); - return TRUE; } } -return FALSE; +if ((dptr == NULL) || (dibp == NULL)) return SCPE_IERR; /* validate args */ +for (i = 0; i < dibp->lnt; i = i + 2) { /* create entries */ + idx = ((dibp->ba + i) & IOPAGEMASK) >> 1; /* index into disp */ + if ((iodispR[idx] && dibp->rd && /* conflict? */ + (iodispR[idx] != dibp->rd)) || + (iodispW[idx] && dibp->wr && + (iodispW[idx] != dibp->wr))) { + 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_dname (dptr), dibp->ba); + return SCPE_STOP; + } + if (dibp->rd) iodispR[idx] = dibp->rd; /* set rd dispatch */ + if (dibp->wr) iodispW[idx] = dibp->wr; /* set wr dispatch */ + iodibp[idx] = dibp; /* remember DIB */ + } +return SCPE_OK; } + /* Build interrupt tables */ -t_bool build_int_vec (int32 vloc, int32 ivec, int32 (*iack)(void) ) +t_stat build_int_vec (DEVICE *dptr, DIB *dibp) { -int32 ilvl = vloc / 32; -int32 ibit = vloc % 32; +int32 i, idx, vec, ilvl, ibit; -if (iack != NULL) { - if (int_ack[ilvl][ibit] && - (int_ack[ilvl][ibit] != iack)) return TRUE; - int_ack[ilvl][ibit] = iack; } -else if (ivec != 0) { - if (int_vec[ilvl][ibit] && - (int_vec[ilvl][ibit] != ivec)) return TRUE; - int_vec[ilvl][ibit] = ivec; } -return FALSE; +if ((dptr == NULL) || (dibp == NULL)) return SCPE_IERR; /* validate args */ +if (dibp->vnum > VEC_DEVMAX) return SCPE_IERR; +for (i = 0; i < dibp->vnum; i++) { /* loop thru vec */ + idx = dibp->vloc + i; /* vector index */ + vec = dibp->vec? (dibp->vec + (i * 4)): 0; /* vector addr */ + ilvl = idx / 32; + ibit = idx % 32; + if ((int_ack[ilvl][ibit] && dibp->ack[i] && /* conflict? */ + (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); + return SCPE_STOP; + } + if (dibp->ack[i]) int_ack[ilvl][ibit] = dibp->ack[i]; + else if (vec) int_vec[ilvl][ibit] = vec; + } +return SCPE_OK; } /* Build dib_tab from device list */ t_stat build_dib_tab (void) { -int32 i, j, k; +int32 i, j; DEVICE *dptr; DIB *dibp; +t_stat r; for (i = 0; i < IPL_HLVL; i++) { /* clear int tables */ for (j = 0; j < 32; j++) { int_vec[i][j] = 0; int_ack[i][j] = NULL; } } -for (i = j = 0; (dptr = sim_devices[i]) != NULL; i++) { /* loop thru dev */ +for (i = 0; i < (IOPAGESIZE >> 1); i++) { /* clear dispatch tab */ + iodispR[i] = NULL; + iodispW[i] = NULL; + iodibp[i] = NULL; } +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 (dibp->vnum > VEC_DEVMAX) return SCPE_IERR; - for (k = 0; k < dibp->vnum; k++) { /* loop thru vec */ - if (build_int_vec (dibp->vloc + k, /* add vector */ - dibp->vec + (k * 4), dibp->ack[k])) { - printf ("Device %s interrupt slot conflict at %d\n", - sim_dname (dptr), dibp->vloc + k); - if (sim_log) fprintf (sim_log, - "Device %s interrupt slot conflict at %d\n", - sim_dname (dptr), dibp->vloc + k); - return SCPE_IERR; } } - if (dibp->lnt != 0) { /* I/O addresses? */ - dib_tab[j++] = dibp; /* add DIB to dib_tab */ - if (j >= DIB_MAX) return SCPE_IERR; } /* too many? */ + if (r = build_int_vec (dptr, dibp)) /* add to intr tab */ + return r; + if (r = build_dsp_tab (dptr, dibp)) /* add to dispatch tab */ + return r; } /* end if enabled */ } /* end for */ -dib_tab[j] = NULL; /* end with NULL */ -for (i = 0; (dibp = dib_tab[i]) != NULL; i++) { /* test built dib_tab */ - if (dev_conflict (dibp)) return SCPE_STOP; } /* for conflicts */ -return FALSE; +return SCPE_OK; } -/* Show dib_tab */ +/* Show IO space */ t_stat show_iospace (FILE *st, UNIT *uptr, int32 val, void *desc) { -int32 i, j, done = 0; +uint32 i, j; DEVICE *dptr; -DIB *dibt; +DIB *dibp; -build_dib_tab (); /* build table */ -while (done == 0) { /* sort ascending */ - done = 1; /* assume done */ - for (i = 0; dib_tab[i + 1] != NULL; i++) { /* check table */ - if (dib_tab[i]->ba > dib_tab[i + 1]->ba) { /* out of order? */ - dibt = dib_tab[i]; /* interchange */ - dib_tab[i] = dib_tab[i + 1]; - dib_tab[i + 1] = dibt; - done = 0; } } /* not done */ - } /* end while */ -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]) { - dptr = sim_devices[j]; - break; } } - fprintf (st, "%08X - %08X%c\t%s\n", dib_tab[i]->ba, - dib_tab[i]->ba + dib_tab[i]->lnt - 1, +if (build_dib_tab ()) return SCPE_OK; /* build IO page */ +for (i = 0, dibp = NULL; i < (IOPAGESIZE >> 1); i++) { /* loop thru entries */ + if (iodibp[i] && (iodibp[i] != dibp)) { /* new block? */ + dibp = iodibp[i]; /* DIB for block */ + for (j = 0, dptr = NULL; sim_devices[j] != NULL; j++) { + if (((DIB*) sim_devices[j]->ctxt) == dibp) { + dptr = sim_devices[j]; /* locate device */ + break; + } /* end if */ + } /* end for j */ + fprintf (st, "%08X - %08X%c\t%s\n", dibp->ba, + dibp->ba + dibp->lnt - 1, (dptr && (dptr->flags & DEV_FLTA))? '*': ' ', dptr? sim_dname (dptr): "CPU"); - } + } /* end if */ + } /* end for i */ return SCPE_OK; } @@ -943,7 +945,7 @@ struct auto_con auto_tab[AUTO_LNT + 1] = { { 0xf, 0x3 }, /* VS100 */ { 0x3, 0x3, AUTO_DYN|AUTO_VEC, 0, IOBA_TQ, { "TQ", "TQB" } }, { 0xf, 0x7 }, /* KMV11 */ - { 0xf, 0x7 }, /* DHU11/DHQ11 */ + { 0x1f, 0x7, AUTO_VEC, VH_MUXES, 0, { "VH" } }, /* DHU11/DHQ11 */ { 0x1f, 0x7 }, /* DMZ32 */ { 0x1f, 0x7 }, /* CP132 */ diff --git a/VAX/vax_mmu.c b/VAX/vax_mmu.c index 4841019f..22c165a5 100644 --- a/VAX/vax_mmu.c +++ b/VAX/vax_mmu.c @@ -194,7 +194,7 @@ if (lnt >= L_LONG) { /* lw unaligned? */ sc = bo << 3; wl = ReadL (pa); /* read both lw */ wh = ReadL (pa1); /* extract */ - return (((wl >> sc) & align[bo]) | (wh << (32 - sc))); } + return ((((wl >> sc) & align[bo]) | (wh << (32 - sc))) & LMASK); } else if (bo == 1) return ((ReadL (pa) >> 8) & WMASK); else { wl = ReadL (pa); /* word cross lw */ wh = ReadL (pa1); /* read, extract */ @@ -248,7 +248,7 @@ wl = ReadL (pa); if (lnt >= L_LONG) { sc = bo << 3; wh = ReadL (pa1); - wl = (wl & insert[bo]) | (val << sc); + wl = (wl & insert[bo]) | ((val << sc) & LMASK); wh = (wh & ~insert[bo]) | ((val >> (32 - sc)) & insert[bo]); WriteL (pa, wl); WriteL (pa1, wh); } @@ -256,7 +256,7 @@ else if (bo == 1) { wl = (wl & 0xFF0000FF) | (val << 8); WriteL (pa, wl); } else { wh = ReadL (pa1); - wl = (wl & 0x00FFFFFF) | (val << 24); + wl = (wl & 0x00FFFFFF) | ((val & 0xFF) << 24); wh = (wh & 0xFFFFFF00) | ((val >> 8) & 0xFF); WriteL (pa, wl); WriteL (pa1, wh); } diff --git a/VAX/vax_stddev.c b/VAX/vax_stddev.c index a1878d5f..3acc322f 100644 --- a/VAX/vax_stddev.c +++ b/VAX/vax_stddev.c @@ -27,6 +27,7 @@ tto terminal output clk 100Hz and TODR clock + 28-May-04 RMS Removed SET TTI CTRL-C 29-Dec-03 RMS Added console backpressure support 25-Apr-03 RMS Revised for extended file support 02-Mar-02 RMS Added SET TTI CTRL-C @@ -74,7 +75,6 @@ t_stat clk_svc (UNIT *uptr); t_stat tti_reset (DEVICE *dptr); t_stat tto_reset (DEVICE *dptr); t_stat clk_reset (DEVICE *dptr); -t_stat tti_set_ctrlc (UNIT *uptr, int32 val, char *cptr, void *desc); extern int32 sysd_hlt_enb (void); @@ -102,8 +102,6 @@ REG tti_reg[] = { MTAB tti_mod[] = { { UNIT_8B, UNIT_8B, "8b", "8B", NULL }, { UNIT_8B, 0 , "7b", "7B", NULL }, - { MTAB_XTD|MTAB_VDV|MTAB_VUN, 0, NULL, "CTRL-C", - &tti_set_ctrlc, NULL, NULL }, { MTAB_XTD|MTAB_VDV, 0, "VECTOR", NULL, NULL, &show_vec, NULL }, { 0 } }; @@ -292,18 +290,6 @@ CLR_INT (TTI); sim_activate (&tti_unit, tti_unit.wait); /* activate unit */ return SCPE_OK; } - -/* Set control-C */ - -t_stat tti_set_ctrlc (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -if (cptr) return SCPE_ARG; -uptr->buf = 003; -uptr->pos = uptr->pos + 1; -tti_csr = tti_csr | CSR_DONE; -if (tti_csr & CSR_IE) SET_INT (TTI); -return SCPE_OK; -} /* Terminal output routines diff --git a/VAX/vax_sys.c b/VAX/vax_sys.c index 961440ba..d4fd4873 100644 --- a/VAX/vax_sys.c +++ b/VAX/vax_sys.c @@ -23,6 +23,7 @@ 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. + 16-Jun-04 RMS Added DHQ11 support 21-Mar-04 RMS Added RXV21 support 06-May-03 RMS Added support for second DELQA 12-Oct-02 RMS Added multiple RQ controller support @@ -52,6 +53,7 @@ extern DEVICE ry_dev; extern DEVICE ts_dev; extern DEVICE tq_dev; extern DEVICE dz_dev; +extern DEVICE vh_dev; extern DEVICE xq_dev, xqb_dev; extern UNIT cpu_unit; extern REG cpu_reg[]; @@ -104,6 +106,7 @@ DEVICE *sim_devices[] = { &ptp_dev, &lpt_dev, &dz_dev, + &vh_dev, &rl_dev, &rq_dev, &rqb_dev, diff --git a/VAX/vaxmod_defs.h b/VAX/vaxmod_defs.h index 749feb71..9a4bd04b 100644 --- a/VAX/vaxmod_defs.h +++ b/VAX/vaxmod_defs.h @@ -23,6 +23,7 @@ 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. + 16-Jun-04 RMS Added DHQ11 support 21-Mar-04 RMS Added RXV21 support 25-Jan-04 RMS Removed local debug logging support RMS,MP Added "KA655X" support @@ -204,8 +205,9 @@ /* I/O system definitions */ -#define DZ_MUXES 4 /* max # of muxes */ -#define DZ_LINES 4 /* (DZV) lines per mux */ +#define DZ_MUXES 4 /* max # of DZV muxes */ +#define DZ_LINES 4 /* lines per DZV mux */ +#define VH_MUXES 4 /* max # of DHQ muxes */ #define MT_MAXFR (1 << 16) /* magtape max rec */ #define AUTO_LNT 34 /* autoconfig ranks */ #define DIB_MAX 100 /* max DIBs */ @@ -250,6 +252,8 @@ typedef struct pdp_dib DIB; #define IOLN_RQC 004 #define IOBA_RQD (IOPAGEBASE + IOBA_RQC + IOLN_RQC) #define IOLN_RQD 004 +#define IOBA_VH (IOPAGEBASE + 000440) /* DHQ11 */ +#define IOLN_VH 020 #define IOBA_RQ (IOPAGEBASE + 012150) /* RQDX3 */ #define IOLN_RQ 004 #define IOBA_TS (IOPAGEBASE + 012520) /* TS11 */ @@ -297,6 +301,7 @@ typedef struct pdp_dib DIB; #define INT_V_TS 5 /* TS11/TSV05 */ #define INT_V_TQ 6 /* TMSCP */ #define INT_V_XQ 7 /* DEQNA/DELQA */ +#define INT_V_RY 8 /* RXV21 */ /* IPL 14 */ @@ -309,7 +314,8 @@ typedef struct pdp_dib DIB; #define INT_V_CSO 6 #define INT_V_TMR0 7 /* SSC timers */ #define INT_V_TMR1 8 -#define INT_V_RY 9 /* RXV21 */ +#define INT_V_VHRX 9 /* DHQ11 */ +#define INT_V_VHTX 10 #define INT_CLK (1u << INT_V_CLK) #define INT_RQ (1u << INT_V_RQ) @@ -320,6 +326,7 @@ typedef struct pdp_dib DIB; #define INT_TS (1u << INT_V_TS) #define INT_TQ (1u << INT_V_TQ) #define INT_XQ (1u << INT_V_XQ) +#define INT_RY (1u << INT_V_RY) #define INT_TTI (1u << INT_V_TTI) #define INT_TTO (1u << INT_V_TTO) #define INT_PTR (1u << INT_V_PTR) @@ -329,7 +336,8 @@ typedef struct pdp_dib DIB; #define INT_CSO (1u << INT_V_CSO) #define INT_TMR0 (1u << INT_V_TMR0) #define INT_TMR1 (1u << INT_V_TMR1) -#define INT_RY (1u << INT_V_RY) +#define INT_VHRX (1u << INT_V_VHRX) +#define INT_VHTX (1u << INT_V_VHTX) #define IPL_CLK (0x16 - IPL_HMIN) /* relative IPL */ #define IPL_RQ (0x15 - IPL_HMIN) @@ -350,6 +358,8 @@ typedef struct pdp_dib DIB; #define IPL_CSO (0x14 - IPL_HMIN) #define IPL_TMR0 (0x14 - IPL_HMIN) #define IPL_TMR1 (0x14 - IPL_HMIN) +#define IPL_VHRX (0x14 - IPL_HMIN) +#define IPL_VHTX (0x14 - IPL_HMIN) #define IPL_HMAX 0x17 /* highest hwre level */ #define IPL_HMIN 0x14 /* lowest hwre level */ @@ -371,6 +381,8 @@ typedef struct pdp_dib DIB; #define VEC_RY (VEC_Q + 0264) #define VEC_DZRX (VEC_Q + 0300) #define VEC_DZTX (VEC_Q + 0304) +#define VEC_VHRX (VEC_Q + 0310) +#define VEC_VHTX (VEC_Q + 0314) /* Autoconfigure ranks */ @@ -379,6 +391,7 @@ typedef struct pdp_dib DIB; #define RANK_RX 18 #define RANK_RQ 26 #define RANK_TQ 30 +#define RANK_VH 32 /* Interrupt macros */ diff --git a/descrip.mms b/descrip.mms index 3d032ced..96305d8a 100644 --- a/descrip.mms +++ b/descrip.mms @@ -362,7 +362,8 @@ PDP11_SOURCE1 = $(PDP11_DIR)PDP11_FP.C,$(PDP11_DIR)PDP11_CPU.C,\ $(PDP11_DIR)PDP11_LP.C,$(PDP11_DIR)PDP11_RK.C,\ $(PDP11_DIR)PDP11_RL.C,$(PDP11_DIR)PDP11_RP.C,\ $(PDP11_DIR)PDP11_RX.C,$(PDP11_DIR)PDP11_STDDEV.C,\ - $(PDP11_DIR)PDP11_SYS.C,$(PDP11_DIR)PDP11_TC.C + $(PDP11_DIR)PDP11_SYS.C,$(PDP11_DIR)PDP11_TC.C, \ + $(PDP11_DIR)PDP11_VH.C PDP11_LIB2 = $(LIB_DIR)PDP11L2-$(ARCH).OLB PDP11_SOURCE2 = $(PDP11_DIR)PDP11_TM.C,$(PDP11_DIR)PDP11_TS.C,\ $(PDP11_DIR)PDP11_IO.C,$(PDP11_DIR)PDP11_RQ.C,\ @@ -422,7 +423,7 @@ VAX_SOURCE = $(VAX_DIR)VAX_CPU1.C,$(VAX_DIR)VAX_CPU.C,\ $(PDP11_DIR)PDP11_TS.C,$(PDP11_DIR)PDP11_DZ.C,\ $(PDP11_DIR)PDP11_LP.C,$(PDP11_DIR)PDP11_TQ.C,\ $(PDP11_DIR)PDP11_PT.C,$(PDP11_DIR)PDP11_XQ.C,\ - $(PDP11_DIR)PDP11_RY.C + $(PDP11_DIR)PDP11_RY.C,$(PDP11_DIR)PDP11_VH.C VAX_OPTIONS = /INCLUDE=($(SIMH_DIR),$(VAX_DIR),$(PDP11_DIR)$(PCAP_INC))\ /DEFINE=($(CC_DEFS),"VM_VAX=1"$(PCAP_DEFS)) diff --git a/makefile b/makefile index 9be1acdf..7089748f 100644 --- a/makefile +++ b/makefile @@ -81,7 +81,7 @@ PDP11 = ${PDP11D}pdp11_fp.c ${PDP11D}pdp11_cpu.c ${PDP11D}pdp11_dz.c \ ${PDP11D}pdp11_tm.c ${PDP11D}pdp11_ts.c ${PDP11D}pdp11_io.c \ ${PDP11D}pdp11_rq.c ${PDP11D}pdp11_tq.c ${PDP11D}pdp11_pclk.c \ ${PDP11D}pdp11_ry.c ${PDP11D}pdp11_pt.c ${PDP11D}pdp11_hk.c \ - ${PDP11D}pdp11_xq.c ${PDP11D}pdp11_xu.c + ${PDP11D}pdp11_xq.c ${PDP11D}pdp11_xu.c ${PDP11D}pdp11_vh.c PDP11_OPT = -DVM_PDP11 -I ${PDP11D} ${NETWORK_OPT} @@ -92,7 +92,8 @@ VAX = ${VAXD}vax_cpu1.c ${VAXD}vax_cpu.c ${VAXD}vax_fpa.c ${VAXD}vax_io.c \ ${VAXD}vax_sysdev.c \ ${PDP11D}pdp11_rl.c ${PDP11D}pdp11_rq.c ${PDP11D}pdp11_ts.c \ ${PDP11D}pdp11_dz.c ${PDP11D}pdp11_lp.c ${PDP11D}pdp11_tq.c \ - ${PDP11D}pdp11_pt.c ${PDP11D}pdp11_xq.c ${PDP11D}pdp11_ry.c + ${PDP11D}pdp11_pt.c ${PDP11D}pdp11_xq.c ${PDP11D}pdp11_ry.c \ + ${PDP11D}pdp11_vh.c VAX_OPT = -DVM_VAX -DUSE_INT64 -I ${VAXD} -I ${PDP11D} ${NETWORK_OPT} @@ -131,7 +132,7 @@ HP2100 = ${HP2100D}hp2100_stddev.c ${HP2100D}hp2100_dp.c ${HP2100D}hp2100_dq.c \ ${HP2100D}hp2100_dr.c ${HP2100D}hp2100_lps.c ${HP2100D}hp2100_ms.c \ ${HP2100D}hp2100_mt.c ${HP2100D}hp2100_mux.c ${HP2100D}hp2100_cpu.c \ ${HP2100D}hp2100_fp.c ${HP2100D}hp2100_sys.c ${HP2100D}hp2100_lpt.c \ - ${HP2100D}hp2100_ipl.c + ${HP2100D}hp2100_ipl.c ${HP2100D}hp2100_ds.c HP2100_OPT = -I ${HP2100D} diff --git a/scp.c b/scp.c index 0ae71abd..a58f8f28 100644 --- a/scp.c +++ b/scp.c @@ -23,6 +23,7 @@ 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-May-04 RMS Added SET/SHOW CONSOLE 14-Feb-04 RMS Updated SAVE/RESTORE (V3.2) RMS Added debug print routines (from Dave Hittner) RMS Added sim_vm_parse_addr and sim_vm_fprint_addr @@ -247,8 +248,6 @@ t_stat spawn_cmd (int32 flag, char *ptr); /* Set and show command processors */ -t_stat set_logon (int32 flag, char *cptr); -t_stat set_logoff (int32 flag, char *cptr); t_stat set_debon (int32 flag, char *cptr); t_stat set_deboff (int32 flag, char *cptr); t_stat set_dev_radix (DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr); @@ -261,7 +260,6 @@ t_stat show_queue (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr); t_stat show_time (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr); t_stat show_mod_names (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr); t_stat show_log_names (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr); -t_stat show_log (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr); t_stat show_debug (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr); t_stat show_dev_radix (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr); t_stat show_dev_debug (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr); @@ -305,10 +303,7 @@ void fprint_help (FILE *st); void fprint_stopped (FILE *st, t_stat r); void fprint_capac (FILE *st, DEVICE *dptr, UNIT *uptr); char *read_line (char *ptr, int32 size, FILE *stream); -CTAB *find_ctab (CTAB *tab, char *gbuf); -C1TAB *find_c1tab (C1TAB *tab, char *gbuf); CTAB *find_cmd (char *gbuf); -SHTAB *find_shtab (SHTAB *tab, char *gbuf); DEVICE *find_dev (char *ptr); DEVICE *find_unit (char *ptr, UNIT **uptr); REG *find_reg_glob (char *ptr, char **optr, DEVICE **gdptr); @@ -492,10 +487,7 @@ static CTAB cmd_table[] = { { "QUIT", &exit_cmd, 0, NULL }, { "BYE", &exit_cmd, 0, NULL }, { "SET", &set_cmd, 0, - "set log enable logging to file\n" - "set nolog disable logging\n" - "set telnet enable Telnet port for console\n" - "set notelnet disable Telnet for console\n" + "set console arg{,arg...} set console options\n" "set debug enable debug output to file\n" "set nodebug disable debug output\n" "set OCT|DEC|HEX set device display radix\n" @@ -510,14 +502,13 @@ static CTAB cmd_table[] = { }, { "SHOW", &show_cmd, 0, "sh{ow} br{eak} show breakpoints on address list\n" - "sh{ow} c{onfiguration} show configuration\n" + "sh{ow} con{figuration} show configuration\n" + "sh{ow} cons{ole} {arg} show console options\n" "sh{ow} deb{ug} show debugging output\n" "sh{ow} dev{ices} show devices\n" - "sh{ow} l{og} show log\n" "sh{ow} m{odifiers} show modifiers\n" "sh{ow} n{ames} show logical names\n" "sh{ow} q{ueue} show event queue\n" - "sh{ow} te{lnet} show console Telnet status\n" "sh{ow} ti{me} show simulated time\n" "sh{ow} ve{rsion} show simulator version\n" "sh{ow} RADIX show device display radix\n" @@ -634,8 +625,8 @@ while (stat != SCPE_EXIT) { /* in case exit */ } /* end while */ detach_all (0, TRUE); /* close files */ -set_logoff (0, NULL); /* close log */ set_deboff (0, NULL); /* close debug */ +sim_set_logoff (0, NULL); /* close log */ sim_set_notelnet (0, NULL); /* close Telnet */ sim_ttclose (); /* close console */ return 0; @@ -802,10 +793,11 @@ CTAB *gcmdp; C1TAB *ctbr, *glbr; static CTAB set_glob_tab[] = { - { "TELNET", &sim_set_telnet, 0 }, - { "NOTELNET", &sim_set_notelnet, 0 }, - { "LOG", &set_logon, 0 }, - { "NOLOG", &set_logoff, 0 }, + { "CONSOLE", &sim_set_console, 0 }, + { "TELNET", &sim_set_telnet, 0 }, /* deprecated */ + { "NOTELNET", &sim_set_notelnet, 0 }, /* deprecated */ + { "LOG", &sim_set_logon, 0 }, /* deprecated */ + { "NOLOG", &sim_set_logoff, 0 }, /* deprecated */ { "BREAK", &brk_cmd, SSH_ST }, { "DEBUG", &set_debon, 0 }, { "NODEBUG", &set_deboff, 0 }, @@ -905,36 +897,6 @@ for (; tab->name != NULL; tab++) { return NULL; } -/* Log on routine */ - -t_stat set_logon (int32 flag, char *cptr) -{ -char gbuf[CBUFSIZE]; - -if (*cptr == 0) return SCPE_2FARG; /* need arg */ -cptr = get_glyph_nc (cptr, gbuf, 0); /* get file name */ -if (*cptr != 0) return SCPE_2MARG; /* now eol? */ -set_logoff (0, NULL); /* close cur log */ -sim_log = sim_fopen (gbuf, "a"); /* open log */ -if (sim_log == NULL) return SCPE_OPENERR; /* error? */ -if (!sim_quiet) printf ("Logging to file \"%s\"\n", gbuf); -fprintf (sim_log, "Logging to file \"%s\"\n", gbuf); /* start of log */ -return SCPE_OK; -} - -/* Log off routine */ - -t_stat set_logoff (int32 flag, char *cptr) -{ -if (cptr && (*cptr != 0)) return SCPE_2MARG; /* now eol? */ -if (sim_log == NULL) return SCPE_OK; /* no log? */ -if (!sim_quiet) printf ("Log file closed\n"); -fprintf (sim_log, "Log file closed\n"); /* close log */ -fclose (sim_log); -sim_log = NULL; -return SCPE_OK; -} - /* Set device data radix routine */ t_stat set_dev_radix (DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr) @@ -1064,8 +1026,9 @@ static SHTAB show_glob_tab[] = { { "MODIFIERS", &show_mod_names, 0 }, { "NAMES", &show_log_names, 0 }, { "VERSION", &show_version, 0 }, - { "LOG", &show_log, 0 }, - { "TELNET", &sim_show_telnet, 0 }, + { "CONSOLE", &sim_show_console, 0 }, + { "LOG", &sim_show_log, 0 }, /* deprecated */ + { "TELNET", &sim_show_telnet, 0 }, /* deprecated */ { "BREAK", &show_break, 0 }, { "DEBUG", &show_debug, 0 }, { NULL, NULL, 0 } }; @@ -1283,14 +1246,6 @@ fprintf (st, "Time: %.0f\n", sim_time); return SCPE_OK; } -t_stat show_log (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr) -{ -if (cptr && (*cptr != 0)) return SCPE_2MARG; -if (sim_log) fputs ("Logging enabled\n", st); -else fputs ("Logging disabled\n", st); -return SCPE_OK; -} - t_stat show_break (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr) { t_stat r; diff --git a/scp.h b/scp.h index 2154e7cd..119616d9 100644 --- a/scp.h +++ b/scp.h @@ -1,4 +1,4 @@ -/* sim_timer.h: simulator timer library headers +/* scp.h: simulator control program headers Copyright (c) 1993-2004, Robert M Supnik @@ -52,6 +52,9 @@ t_value strtotv (char *cptr, char **endptr, uint32 radix); t_stat fprint_val (FILE *stream, t_value val, uint32 rdx, uint32 wid, uint32 fmt); DEVICE *find_dev_from_unit (UNIT *uptr); REG *find_reg (char *ptr, char **optr, DEVICE *dptr); +CTAB *find_ctab (CTAB *tab, char *gbuf); +C1TAB *find_c1tab (C1TAB *tab, char *gbuf); +SHTAB *find_shtab (SHTAB *tab, char *gbuf); BRKTAB *sim_brk_fnd (t_addr loc); t_bool sim_brk_test (t_addr bloc, int32 btyp); char *match_ext (char *fnam, char *ext); diff --git a/sim_console.c b/sim_console.c index f0e6771a..6327a168 100644 --- a/sim_console.c +++ b/sim_console.c @@ -23,6 +23,8 @@ 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-May-04 RMS Added SET/SHOW CONSOLE + RMS Added break, delete character maps 02-Jan-04 RMS Removed timer routines, added Telnet console routines RMS Moved console logging to OS-independent code 25-Apr-03 RMS Added long seek support from Mark Pizzolato @@ -50,9 +52,8 @@ sim_poll_kbd - poll for keyboard input sim_putchar - output character to console sim_putchar_s - output character to console, stall if congested - sim_set_telnet - set console to Telnet port - sim_set_notelnet - close console Telnet port - sim_show_telnet - show console status + sim_set_console - set console parameters + sim_show_console - show console parameters sim_ttinit - called once to get initial terminal state sim_ttrun - called to put terminal into run state @@ -62,18 +63,63 @@ sim_os_putchar - output character to console The first group is OS-independent; the second group is OS-dependent. + + The following routines are exposed but deprecated: + + sim_set_telnet - set console to Telnet port + sim_set_notelnet - close console Telnet port + sim_show_telnet - show console status */ #include "sim_defs.h" #include "sim_sock.h" #include "sim_tmxr.h" +#define KMAP_WRU 0 +#define KMAP_BRK 1 +#define KMAP_DEL 2 +#define KMAP_MASK 0377 +#define KMAP_NZ 0400 + int32 sim_int_char = 005; /* interrupt character */ +int32 sim_brk_char = 000; /* break character */ +#if defined (_WIN32) || defined (__OS2__) || (defined (__MWERKS__) && defined (macintosh)) +int32 sim_del_char = '\b'; /* delete character */ +#else +int32 sim_del_char = 0177; +#endif 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; extern FILE *sim_log; +extern DEVICE *sim_devices[]; + +/* Set/show data structures */ + +static CTAB set_con_tab[] = { + { "WRU", &sim_set_kmap, KMAP_WRU | KMAP_NZ }, + { "BRK", &sim_set_kmap, KMAP_BRK }, + { "DEL", &sim_set_kmap, KMAP_DEL |KMAP_NZ }, + { "TELNET", &sim_set_telnet, 0 }, + { "NOTELNET", &sim_set_notelnet, 0 }, + { "LOG", &sim_set_logon, 0 }, + { "NOLOG", &sim_set_logoff, 0 }, + { NULL, NULL, 0 } }; + +static SHTAB show_con_tab[] = { + { "WRU", &sim_show_kmap, KMAP_WRU }, + { "BRK", &sim_show_kmap, KMAP_BRK }, + { "DEL", &sim_show_kmap, KMAP_DEL }, + { "LOG", &sim_show_log, 0 }, + { "TELNET", &sim_show_telnet, 0 }, + { NULL, NULL, 0 } }; + +static int32 *cons_kmap[] = { + &sim_int_char, + &sim_brk_char, + &sim_del_char }; /* Console I/O package. @@ -83,11 +129,126 @@ extern FILE *sim_log; sim_con_tmxr and internal terminal line description sim_con_ldsc. */ +/* SET CONSOLE command */ + +t_stat sim_set_console (int32 flag, char *cptr) +{ +char *cvptr, gbuf[CBUFSIZE]; +CTAB *ctptr; +t_stat r; + +if ((cptr == NULL) || (*cptr == 0)) return SCPE_2FARG; +while (*cptr != 0) { /* do all mods */ + cptr = get_glyph_nc (cptr, gbuf, 0); /* get modifier */ + if (cvptr = strchr (gbuf, '=')) *cvptr++ = 0; /* = value? */ + get_glyph (gbuf, gbuf, 0); /* modifier to UC */ + if (ctptr = find_ctab (set_con_tab, gbuf)) { /* match? */ + r = ctptr->action (ctptr->arg, cvptr); /* do the rest */ + if (r != SCPE_OK) return r; } + else return SCPE_NOPARAM; + } +return SCPE_OK; +} + +/* SHOW CONSOLE command */ + +t_stat sim_show_console (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr) +{ +char gbuf[CBUFSIZE]; +SHTAB *shptr; +int32 i; + +if (*cptr == 0) { /* show all */ + for (i = 0; show_con_tab[i].name; i++) + show_con_tab[i].action (st, dptr, uptr, show_con_tab[i].arg, cptr); + return SCPE_OK; + } +while (*cptr != 0) { + cptr = get_glyph (cptr, gbuf, ','); /* get modifier */ + if (shptr = find_shtab (show_con_tab, gbuf)) + shptr->action (st, dptr, uptr, shptr->arg, cptr); + else return SCPE_NOPARAM; + } +return SCPE_OK; +} + +/* Set keyboard map */ + +t_stat sim_set_kmap (int32 flag, char *cptr) +{ +DEVICE *dptr = sim_devices[0]; +int32 val, rdx; +t_stat r; + +if ((cptr == NULL) || (*cptr == 0)) return SCPE_2FARG; +if (dptr->dradix == 16) rdx = 16; +else rdx = 8; +val = (int32) get_uint (cptr, rdx, 0177, &r); +if ((r != SCPE_OK) || + ((val == 0) && (flag & KMAP_NZ))) return SCPE_ARG; +*(cons_kmap[flag & KMAP_MASK]) = val; +return SCPE_OK; +} + +/* Show keyboard map */ + +t_stat sim_show_kmap (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr) +{ +int32 rdx = 8; + +dptr = sim_devices[0]; +if (dptr->dradix == 16) rdx = 16; +fprintf (st, "%s = ", show_con_tab[flag].name); +fprint_val (st, *(cons_kmap[flag & KMAP_MASK]), rdx, 7, 0); +fprintf (st, "\n"); +return SCPE_OK; +} + +/* Set log routine */ + +t_stat sim_set_logon (int32 flag, char *cptr) +{ +char gbuf[CBUFSIZE]; + +if ((cptr == NULL) || (*cptr == 0)) return SCPE_2FARG; /* need arg */ +cptr = get_glyph_nc (cptr, gbuf, 0); /* get file name */ +if (*cptr != 0) return SCPE_2MARG; /* now eol? */ +sim_set_logoff (0, NULL); /* close cur log */ +sim_log = sim_fopen (gbuf, "a"); /* open log */ +if (sim_log == NULL) return SCPE_OPENERR; /* error? */ +if (!sim_quiet) printf ("Logging to file \"%s\"\n", gbuf); +fprintf (sim_log, "Logging to file \"%s\"\n", gbuf); /* start of log */ +return SCPE_OK; +} + +/* Set nolog routine */ + +t_stat sim_set_logoff (int32 flag, char *cptr) +{ +if (cptr && (*cptr != 0)) return SCPE_2MARG; /* now eol? */ +if (sim_log == NULL) return SCPE_OK; /* no log? */ +if (!sim_quiet) printf ("Log file closed\n"); +fprintf (sim_log, "Log file closed\n"); /* close log */ +fclose (sim_log); +sim_log = NULL; +return SCPE_OK; +} + +/* Show log status */ + +t_stat sim_show_log (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr) +{ +if (cptr && (*cptr != 0)) return SCPE_2MARG; +if (sim_log) fputs ("Logging enabled\n", st); +else fputs ("Logging disabled\n", st); +return SCPE_OK; +} + /* Set console to Telnet port */ t_stat sim_set_telnet (int32 flg, char *cptr) { -if (*cptr == 0) return SCPE_2FARG; /* too few arguments? */ +if ((cptr == NULL) || (*cptr == 0)) return SCPE_2FARG; /* too few arguments? */ if (sim_con_tmxr.master) return SCPE_ALATT; /* already open? */ return tmxr_open_master (&sim_con_tmxr, cptr); /* open master socket */ } @@ -284,6 +445,7 @@ status = sys$qiow (EFN, tty_chan, &iosb, 0, 0, buf, 1, 0, term, 0, 0); if ((status != SS$_NORMAL) || (iosb.status != SS$_NORMAL)) return SCPE_OK; if (buf[0] == sim_int_char) return SCPE_STOP; +if (sim_brk_char && (buf[0] == sim_brk_char)) return SCPE_BREAK; return (buf[0] | SCPE_KFLAG); } @@ -349,8 +511,9 @@ if (sim_win_ctlc) { return 003 | SCPE_KFLAG; } if (!_kbhit ()) return SCPE_OK; c = _getch (); -if ((c & 0177) == '\b') c = 0177; +if ((c & 0177) == sim_del_char) c = 0177; if ((c & 0177) == sim_int_char) return SCPE_STOP; +if (sim_brk_char && ((c & 0177) == sim_brk_char)) return SCPE_BREAK; return c | SCPE_KFLAG; } @@ -392,8 +555,9 @@ int c; if (!kbhit ()) return SCPE_OK; c = getch(); -if ((c & 0177) == '\b') c = 0177; +if ((c & 0177) == sim_del_char) c = 0177; if ((c & 0177) == sim_int_char) return SCPE_STOP; +if (sim_brk_char && ((c & 0177) == sim_brk_char)) return SCPE_BREAK; return c | SCPE_KFLAG; } @@ -561,8 +725,9 @@ int c; if (!ps_kbhit ()) return SCPE_OK; c = ps_getch(); -if ((c & 0177) == '\b') c = 0177; +if ((c & 0177) == sim_del_char) c = 0177; if ((c & 0177) == sim_int_char) return SCPE_STOP; +if (sim_brk_char && ((c & 0177) == sim_brk_char)) return SCPE_BREAK; return c | SCPE_KFLAG; } @@ -644,6 +809,7 @@ unsigned char buf[1]; status = read (0, buf, 1); if (status != 1) return SCPE_OK; +if (sim_brk_char && (buf[0] == sim_brk_char)) return SCPE_BREAK; else return (buf[0] | SCPE_KFLAG); } @@ -741,6 +907,7 @@ unsigned char buf[1]; status = read (0, buf, 1); if (status != 1) return SCPE_OK; +if (sim_brk_char && (buf[0] == sim_brk_char)) return SCPE_BREAK; else return (buf[0] | SCPE_KFLAG); } diff --git a/sim_console.h b/sim_console.h index c81905ce..e73f7db4 100644 --- a/sim_console.h +++ b/sim_console.h @@ -23,15 +23,23 @@ 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-May-04 RMS Added SET/SHOW CONSOLE 02-Jan-04 RMS Removed timer routines, added Telnet console routines */ #ifndef _SIM_CONSOLE_H_ #define _SIM_CONSOLE_H_ 0 -t_stat sim_set_telnet (int32 flg, char *cptr); +t_stat sim_set_console (int32 flag, char *cptr); +t_stat sim_set_kmap (int32 flag, char *cptr); +t_stat sim_set_telnet (int32 flag, char *cptr); t_stat sim_set_notelnet (int32 flag, char *cptr); +t_stat sim_set_logon (int32 flag, char *cptr); +t_stat sim_set_logoff (int32 flag, char *cptr); +t_stat sim_show_console (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr); +t_stat sim_show_kmap (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr); t_stat sim_show_telnet (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr); +t_stat sim_show_log (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr); t_stat sim_check_console (int32 sec); t_stat sim_poll_kbd (void); t_stat sim_putchar (int32 c); diff --git a/sim_fio.c b/sim_fio.c index 58f422a5..afc92410 100644 --- a/sim_fio.c +++ b/sim_fio.c @@ -23,6 +23,7 @@ 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. + 26-May-04 RMS Optimized sim_fread (suggested by John Dundas) 02-Jan-04 RMS Split out from SCP This library includes: @@ -57,8 +58,8 @@ int32 sim_end = 1; /* 1 = little */ These routines are analogs of the standard C runtime routines fread and fwrite. If the host is little endian, or the data items are size char, then the calls are passed directly to fread or - fwrite. Otherwise, these routines perform the necessary byte swaps - using an intermediate buffer. + fwrite. Otherwise, these routines perform the necessary byte swaps. + Sim_fread swaps in place, sim_fwrite uses an intermediate buffer. */ int32 sim_finit (void) @@ -72,28 +73,21 @@ return sim_end; size_t sim_fread (void *bptr, size_t size, size_t count, FILE *fptr) { -size_t c, j, nelem, nbuf, lcnt, total; -int32 i, k; -unsigned char *sptr, *dptr; +size_t c, j; +int32 k; +unsigned char by, *sptr, *dptr; -if (sim_end || (size == sizeof (char))) - return fread (bptr, size, count, fptr); -if ((size == 0) || (count == 0)) return 0; -nelem = FLIP_SIZE / size; /* elements in buffer */ -nbuf = count / nelem; /* number buffers */ -lcnt = count % nelem; /* count in last buf */ -if (lcnt) nbuf = nbuf + 1; -else lcnt = nelem; -total = 0; -dptr = bptr; /* init output ptr */ -for (i = nbuf; i > 0; i--) { - c = fread (sim_flip, size, (i == 1? lcnt: nelem), fptr); - if (c == 0) return total; - total = total + c; - for (j = 0, sptr = sim_flip; j < c; j++) { - for (k = size - 1; k >= 0; k--) *(dptr + k) = *sptr++; - dptr = dptr + size; } } -return total; +if ((size == 0) || (count == 0)) return 0; /* check arguments */ +c = fread (bptr, size, count, fptr); /* read buffer */ +if (sim_end || (size == sizeof (char)) || (c == 0)) /* le, byte, or err? */ + return c; /* done */ +for (j = 0, dptr = sptr = bptr; j < c; j++) { /* loop on items */ + for (k = size - 1; k >= 0; k--) { /* loop on bytes/item */ + by = *sptr; /* swap end-for-end */ + *sptr++ = *(dptr + k); + *(dptr + k) = by; } + dptr = dptr + size; } /* next item */ +return c; } size_t sim_fwrite (void *bptr, size_t size, size_t count, FILE *fptr) @@ -102,9 +96,9 @@ size_t c, j, nelem, nbuf, lcnt, total; int32 i, k; unsigned char *sptr, *dptr; -if (sim_end || (size == sizeof (char))) - return fwrite (bptr, size, count, fptr); -if ((size == 0) || (count == 0)) return 0; +if ((size == 0) || (count == 0)) return 0; /* check arguments */ +if (sim_end || (size == sizeof (char))) /* le or byte? */ + return fwrite (bptr, size, count, fptr); /* done */ nelem = FLIP_SIZE / size; /* elements in buffer */ nbuf = count / nelem; /* number buffers */ lcnt = count % nelem; /* count in last buf */ @@ -112,9 +106,9 @@ if (lcnt) nbuf = nbuf + 1; else lcnt = nelem; total = 0; sptr = bptr; /* init input ptr */ -for (i = nbuf; i > 0; i--) { +for (i = nbuf; i > 0; i--) { /* loop on buffers */ c = (i == 1)? lcnt: nelem; - for (j = 0, dptr = sim_flip; j < c; j++) { + for (j = 0, dptr = sim_flip; j < c; j++) { /* loop on items */ for (k = size - 1; k >= 0; k--) *(dptr + k) = *sptr++; dptr = dptr + size; } c = fwrite (sim_flip, size, c, fptr); @@ -146,6 +140,8 @@ FILE *sim_fopen (char *file, 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) +return fopen64 (file, mode); #else return fopen (file, mode); #endif @@ -250,6 +246,18 @@ return fsetpos (st, &fileaddr); #endif /* end Windows */ +/* Linux */ + +#if defined (linux) +#define _SIM_IO_FSEEK_EXT_ 1 + +int sim_fseek (FILE *st, t_addr xpos, int origin) +{ +return fseeko64 (st, xpos, origin); +} + +#endif /* end Linux with LFS */ + #endif /* end 64b seek defs */ /* Default: no OS-specific routine has been defined */ diff --git a/sim_rev.h b/sim_rev.h index 44aa4459..2237fbd3 100644 --- a/sim_rev.h +++ b/sim_rev.h @@ -29,38 +29,96 @@ #define SIM_MAJOR 3 #define SIM_MINOR 2 -#define SIM_PATCH 0 +#define SIM_PATCH 1 /* V3.2 revision history patch date module(s) and fix(es) - 0 tbd scp.c: - -- added sim_vm_parse_addr and sim_vm_fprint_addr - -- added REG_VMAD - -- moved console logging to SCP - -- changed sim_fsize to use descriptor rather than name - -- added global device/unit show modifiers - -- added device debug support (Dave Hittner) - -- moved device and unit flags, updated save format + 1 10-Jul-04 scp.c: added SET/SHOW CONSOLE subhierarchy + + hp2100_cpu.c: 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 + + all HP2100 peripherals: + - revised to make SFS x,C and SFC x,C work + - revised to separate SRQ from FLG + + all HP2100 IBL bootable peripherals: + - revised boot ROMs to use IBL facility + - revised SR values to preserve SR<5:3> + + hp2100_lps.c, hp2100_lpt.c: fixed timing + + hp2100_dp.c: fixed interpretation of SR<0> + + hp2100_dr.c: revised boot code to use IBL algorithm + + hp2100_mt.c, hp2100_ms.c: fixed spurious timing error after CLC + (found by Dave Bryan) + + hp2100_stddev.c: + - fixed input behavior during typeout for RTE-IV + - suppressed nulls on TTY output for RTE-IV + + hp2100_sys.c: added SFS x,C and SFC x,C to print/parse routines + + pdp10_fe.c, pdp11_stddev.c, pdp18b_stddev.c, pdp8_tt.c, vax_stddev.c: + - removed SET TTI CTRL-C option + + pdp11_tq.c: + - fixed bug in reporting write protect (reported by Lyle Bickley) + - fixed TK70 model number and media ID (found by Robert Schaffrath) + + pdp11_vh.c: added DHQ11 support (from John Dundas) + + pdp11_io.c, vax_io.c: fixed DHQ11 autoconfigure (from John Dundas) + + pdp11_sys.c, vax_sys.c: added DHQ11 support (from John Dundas) + + vax_cpu.c: fixed bug in DIVBx, DIVWx (reported by Peter Trimmel) + + 0 04-Apr-04 scp.c: + - added sim_vm_parse_addr and sim_vm_fprint_addr + - added REG_VMAD + - moved console logging to SCP + - changed sim_fsize to use descriptor rather than name + - added global device/unit show modifiers + - added device debug support (Dave Hittner) + - moved device and unit flags, updated save format sim_ether.c: - -- further generalizations (Dave Hittner, Mark Pizzolato) + - further generalizations (Dave Hittner, Mark Pizzolato) sim_tmxr.h, sim_tmxr.c: - -- added tmxr_linemsg - -- changed TMXR definition to support variable number of lines + - added tmxr_linemsg + - changed TMXR definition to support variable number of lines sim_libraries: - -- new console library (sim_console.h, sim_console.c) - -- new file I/O library (sim_fio.h, sim_fio.c) - -- new timer library (sim_timer.h, sim_timer.c) + - new console library (sim_console.h, sim_console.c) + - new file I/O library (sim_fio.h, sim_fio.c) + - new timer library (sim_timer.h, sim_timer.c) all terminal multiplexors: revised for tmxr library changes all DECtapes: - -- added STOP_EOR to enable end-of-reel stop - -- revised for device debug support + - added STOP_EOR to enable end-of-reel stop + - revised for device debug support all variable-sized devices: revised for sim_fsize change @@ -68,7 +126,7 @@ patch date module(s) and fix(es) (found by Bruce Ray) nova_defs.h, nova_sys.c, nova_qty.c: - -- added QTY and ALM support (Bruce Ray) + - added QTY and ALM support (Bruce Ray) id32_cpu.c, id_dp.c: revised for device debug support @@ -77,15 +135,15 @@ patch date module(s) and fix(es) pdp1_sys.c: fixed bug in LOAD (found by Mark Crispin) pdp10_mdfp.c: - -- fixed bug in floating unpack - -- fixed bug in FIXR (found by Philip Stone, fixed by Chris Smith) + - fixed bug in floating unpack + - fixed bug in FIXR (found by Philip Stone, fixed by Chris Smith) pdp11_dz.c: added per-line logging pdp11_rk.c: - -- added formatting support - -- added address increment inhibit support - -- added transfer overrun detection + - added formatting support + - added address increment inhibit support + - added transfer overrun detection pdp11_hk.c, pdp11_rp.c: revised for device debug support @@ -98,27 +156,27 @@ patch date module(s) and fix(es) pdp11_xu.c: replaced stub with real implementation (Dave Hittner) pdp18b_cpu.c: - -- fixed bug in XVM g_mode implementation - -- fixed bug in PDP-15 indexed address calculation - -- fixed bug in PDP-15 autoindexed address calculation + - fixed bug in XVM g_mode implementation + - fixed bug in PDP-15 indexed address calculation + - fixed bug in PDP-15 autoindexed address calculation pdp18b_fpp.c: fixed bugs in instruction decode pdp18b_stddev.c: - -- fixed clock response to CAF - -- fixed bug in hardware read-in mode bootstrap + - fixed clock response to CAF + - fixed bug in hardware read-in mode bootstrap pdp18b_sys.c: fixed XVM instruction decoding errors pdp18b_tt1.c: added support for 1-16 additional terminals vax_moddef.h, vax_cpu.c, vax_sysdev.c: - -- added extended physical memory support (Mark Pizzolato) - -- added RXV21 support + - added extended physical memory support (Mark Pizzolato) + - added RXV21 support vax_cpu1.c: - -- added PC read fault in EXTxV - -- fixed PC write fault in INSV + - added PC read fault in EXTxV + - fixed PC write fault in INSV /* V3.1 revision history @@ -127,29 +185,29 @@ patch date module(s) and fix(es) all console emulators: added output stall support sim_ether.c (Dave Hittner, Mark Pizzolato, Anders Ahgren): - -- added Alpha/VMS support - -- added FreeBSD, Mac OS/X support - -- added TUN/TAP support - -- added DECnet duplicate address detection + - added Alpha/VMS support + - added FreeBSD, Mac OS/X support + - added TUN/TAP support + - added DECnet duplicate address detection all memory buffered devices (fixed head disks, floppy disks): - -- cleaned up buffer copy code + - cleaned up buffer copy code all DECtapes: - -- fixed reverse checksum in read all - -- added DECtape off reel message - -- simplified timing + - fixed reverse checksum in read all + - added DECtape off reel message + - simplified timing eclipse_cpu.c (Charles Owen): - -- added floating point support - -- added programmable interval timer support - -- bug fixes + - added floating point support + - added programmable interval timer support + - bug fixes h316_cpu.c: - -- added instruction history - -- added DMA/DMC support - -- added device ENABLE/DISABLE support - -- change default to HSA option included + - added instruction history + - added DMA/DMC support + - added device ENABLE/DISABLE support + - change default to HSA option included h316_dp.c: added moving head disk support @@ -160,115 +218,115 @@ patch date module(s) and fix(es) h316_sys.c: added new device support nova_dkp.c (Charles Owen): - -- fixed bug in flag clear sequence - -- added diagnostic mode support for disk sizing + - fixed bug in flag clear sequence + - added diagnostic mode support for disk sizing ` nova_mt.c (Charles Owen): - -- fixed bug, space operations return record count - -- fixed bug, reset doesn't cancel rewind + - fixed bug, space operations return record count + - fixed bug, reset doesn't cancel rewind nova_sys.c: added floating point, timer support (from Charles Owen) i1620_cpu.c: fixed bug in branch digit (found by Dave Babcock) pdp1_drm.c: - -- added parallel drum support - -- fixed bug in serial drum instructin decoding + - added parallel drum support + - fixed bug in serial drum instructin decoding pdp1_sys.c: added parallel drum support, mnemonics pdp11_cpu.c: - -- added autoconfiguration controls - -- added support for 18b-only Qbus devices - -- cleaned up addressing/bus definitions + - added autoconfiguration controls + - added support for 18b-only Qbus devices + - cleaned up addressing/bus definitions pdp11_rk.c, pdp11_ry.c, pdp11_tm.c, pdp11_hk.c: - -- added Q18 attribute + - added Q18 attribute pdp11_io.c: - -- added autoconfiguration controls - -- fixed bug in I/O configuration (found by Dave Hittner) + - added autoconfiguration controls + - fixed bug in I/O configuration (found by Dave Hittner) pdp11_rq.c: - -- revised MB->LBN conversion for greater accuracy - -- fixed bug with multiple RAUSER drives + - revised MB->LBN conversion for greater accuracy + - fixed bug with multiple RAUSER drives pdp11_tc.c: changed to be off by default (base config is Qbus) pdp11_xq.c (Dave Hittner, Mark Pizzolato): - -- fixed second controller interrupts - -- fixed bugs in multicast and promiscuous setup + - fixed second controller interrupts + - fixed bugs in multicast and promiscuous setup pdp18b_cpu.c: - -- added instruction history - -- fixed PDP-4,-7,-9 autoincrement bug - -- change PDP-7,-9 default to API option included + - added instruction history + - fixed PDP-4,-7,-9 autoincrement bug + - change PDP-7,-9 default to API option included pdp8_defs.h, pdp8_sys.c: - -- added DECtape off reel message - -- added support for TSC8-75 (ETOS) option - -- added support for TD8E controller + - added DECtape off reel message + - added support for TSC8-75 (ETOS) option + - added support for TD8E controller pdp8_cpu.c: added instruction history pdp8_rx.c: - -- fixed bug in RX28 read status (found by Charles Dickman) - -- fixed double density write + - fixed bug in RX28 read status (found by Charles Dickman) + - fixed double density write pdp8_td.c: added TD8E controller pdp8_tsc.c: added TSC8-75 option vax_cpu.c: - -- revised instruction history for dynamic sizing - -- added autoconfiguration controls + - revised instruction history for dynamic sizing + - added autoconfiguration controls vax_io.c: - -- added autoconfiguration controls - -- fixed bug in I/O configuration (found by Dave Hittner) + - added autoconfiguration controls + - fixed bug in I/O configuration (found by Dave Hittner) id16_cpu.c: revised instruction decoding id32_cpu.c: - -- revised instruction decoding - -- added instruction history + - revised instruction decoding + - added instruction history /* V3.0 revision history 2 15-Sep-03 scp.c: - -- fixed end-of-file problem in dep, idep - -- fixed error on trailing spaces in dep, idep + - fixed end-of-file problem in dep, idep + - fixed error on trailing spaces in dep, idep pdp1_stddev.c - -- fixed system hang if continue after PTR error - -- added PTR start/stop functionality - -- added address switch functionality to PTR BOOT + - fixed system hang if continue after PTR error + - added PTR start/stop functionality + - added address switch functionality to PTR BOOT pdp1_sys.c: added multibank capability to LOAD pdp18b_cpu.c: - -- fixed priorities in PDP-15 API (PI between 3 and 4) - -- fixed sign handling in PDP-15 unsigned mul/div - -- fixed bug in CAF, must clear API subsystem + - fixed priorities in PDP-15 API (PI between 3 and 4) + - fixed sign handling in PDP-15 unsigned mul/div + - fixed bug in CAF, must clear API subsystem i1401_mt.c: - -- fixed tape read end-of-record handling based on real 1401 - -- added diagnostic read (space forward) + - fixed tape read end-of-record handling based on real 1401 + - added diagnostic read (space forward) i1620_cpu.c - -- fixed bug in immediate index add (found by Michael Short) + - fixed bug in immediate index add (found by Michael Short) 1 27-Jul-03 pdp1_cpu.c: updated to detect indefinite I/O wait pdp1_drm.c: fixed incorrect logical, missing activate, break pdp1_lp.c: - -- fixed bugs in instruction decoding, overprinting - -- updated to detect indefinite I/O wait + - fixed bugs in instruction decoding, overprinting + - updated to detect indefinite I/O wait pdp1_stddev.c: - -- changed RIM loader to be "hardware" - -- updated to detect indefinite I/O wait + - changed RIM loader to be "hardware" + - updated to detect indefinite I/O wait pdp1_sys.c: added block loader format support to LOAD @@ -277,12 +335,12 @@ patch date module(s) and fix(es) pdp11_rq: fixed bug in user disk size (found by Chaskiel M Grundman) pdp18b_cpu.c: - -- added FP15 support - -- added XVM support - -- added EAE support to the PDP-4 - -- added PDP-15 "re-entrancy ECO" - -- fixed memory protect/skip interaction - -- fixed CAF to only reset peripherals + - added FP15 support + - added XVM support + - added EAE support to the PDP-4 + - added PDP-15 "re-entrancy ECO" + - fixed memory protect/skip interaction + - fixed CAF to only reset peripherals pdp18b_fpp.c: added FP15 @@ -291,16 +349,16 @@ patch date module(s) and fix(es) pdp18b_rf.c: fixed bug in set size routine pdp18b_stddev.c: - -- increased PTP TIME for PDP-15 operating systems - -- added hardware RIM loader for PDP-7, PDP-9, PDP-15 + - increased PTP TIME for PDP-15 operating systems + - added hardware RIM loader for PDP-7, PDP-9, PDP-15 pdp18b_sys.c: added FP15, KT15, XVM instructions pdp8b_df.c, pdp8_rf.c: fixed bug in set size routine hp2100_dr.c: - -- fixed drum sizes - -- fixed variable capacity interaction with SAVE/RESTORE + - fixed drum sizes + - fixed variable capacity interaction with SAVE/RESTORE i1401_cpu.c: revised fetch to model hardware more closely @@ -311,33 +369,33 @@ patch date module(s) and fix(es) altairz80: fixed bug in real-time clock on Windows host 0 15-Jun-03 scp.c: - -- added ASSIGN/DEASSIGN - -- changed RESTORE to detach files - -- added u5, u6 unit fields - -- added USE_ADDR64 support - -- changed some structure fields to unsigned + - added ASSIGN/DEASSIGN + - changed RESTORE to detach files + - added u5, u6 unit fields + - added USE_ADDR64 support + - changed some structure fields to unsigned scp_tty.c: added extended file seek sim_sock.c: fixed calling sequence in stubs sim_tape.c: - -- added E11 and TPC format support - -- added extended file support + - added E11 and TPC format support + - added extended file support sim_tmxr.c: fixed bug in SHOW CONNECTIONS all magtapes: - -- added multiformat support - -- added extended file support + - added multiformat support + - added extended file support i1401_cpu.c: - -- fixed mnemonic, instruction lengths, and reverse + - fixed mnemonic, instruction lengths, and reverse scan length check bug for MCS - -- fixed MCE bug, BS off by 1 if zero suppress - -- fixed chaining bug, D lost if return to SCP - -- fixed H branch, branch occurs after continue - -- added check for invalid 8 character MCW, LCA + - fixed MCE bug, BS off by 1 if zero suppress + - fixed chaining bug, D lost if return to SCP + - fixed H branch, branch occurs after continue + - added check for invalid 8 character MCW, LCA i1401_mt.c: fixed load-mode end of record response @@ -348,8 +406,8 @@ patch date module(s) and fix(es) pdp10_rp.c: fixed ordering bug in attach pdp11_cpu.c: - -- fixed bug in MMR1 update (found by Tim Stark) - -- fixed bug in memory size table + - fixed bug in MMR1 update (found by Tim Stark) + - fixed bug in memory size table pdp11_lp.c, pdp11_rq.c: added extended file support @@ -358,23 +416,23 @@ patch date module(s) and fix(es) pdp11_tc.c: fixed variable size interaction with restore pdp11_xq.c: - -- corrected interrupts on IE state transition (code by Tom Evans) - -- added interrupt clear on soft reset (first noted by Bob Supnik) - -- removed interrupt when setting XL or RL (multiple people) - -- added SET/SHOW XQ STATS - -- added SHOW XQ FILTERS - -- added ability to split received packet into multiple buffers - -- added explicit runt & giant packet processing + - corrected interrupts on IE state transition (code by Tom Evans) + - added interrupt clear on soft reset (first noted by Bob Supnik) + - removed interrupt when setting XL or RL (multiple people) + - added SET/SHOW XQ STATS + - added SHOW XQ FILTERS + - added ability to split received packet into multiple buffers + - added explicit runt & giant packet processing vax_fpa.c: - -- fixed integer overflow bug in CVTfi - -- fixed multiple bugs in EMODf + - fixed integer overflow bug in CVTfi + - fixed multiple bugs in EMODf vax_io.c: optimized byte and word DMA routines vax_sysdev.c: - -- added calibrated delay to ROM reads (from Mark Pizzolato) - -- fixed calibration problems in interval timer (from Mark Pizzolato) + - added calibrated delay to ROM reads (from Mark Pizzolato) + - fixed calibration problems in interval timer (from Mark Pizzolato) pdp1_dt.c: fixed variable size interaction with restore @@ -392,8 +450,8 @@ patch date module(s) and fix(es) pdp8_mt.c: fixed bug in SKTR hp2100_dp.c,hp2100_dq.c: - -- fixed bug in read status (13210A controller) - -- fixed bug in seek completion + - fixed bug in read status (13210A controller) + - fixed bug in seek completion id_pt.c: fixed type declaration (found by Mark Pizzolato) @@ -402,10 +460,10 @@ patch date module(s) and fix(es) /* V2.10 revision history 4 03-Mar-03 scp.c - -- added .ini startup file capability - -- added multiple breakpoint actions - -- added multiple switch evaluation points - -- fixed bug in multiword deposits to file + - added .ini startup file capability + - added multiple breakpoint actions + - added multiple switch evaluation points + - fixed bug in multiword deposits to file sim_tape.c: magtape simulation library @@ -418,14 +476,14 @@ patch date module(s) and fix(es) id_dp.c, id_idc.c: fixed cylinder overflow on writes id_mt.c: - -- fixed error handling to stop selector channel - -- revised to use magtape library + - fixed error handling to stop selector channel + - revised to use magtape library id16_sys.c, id32_sys.c: added relative addressing support id_uvc.c: - -- added set frequency command to line frequency clock - -- improved calibration algorithm for precision clock + - added set frequency command to line frequency clock + - improved calibration algorithm for precision clock nova_clk.c: added set line frequency command @@ -438,38 +496,38 @@ patch date module(s) and fix(es) pdp11_cpu.c: fixed bug in MMR1 update (found by Tim Stark) pdp11_stddev.c - -- added set line frequency command - -- added set ctrl-c command + - added set line frequency command + - added set ctrl-c command pdp11_rq.c: - -- fixed ordering problem in queue process - -- fixed bug in vector calculation for VAXen - -- added user defined drive support + - fixed ordering problem in queue process + - fixed bug in vector calculation for VAXen + - added user defined drive support pdp11_ry.c: fixed autosizing algorithm pdp11_tm.c, pdp11_ts.c: revised to use magtape library pdp11_tq.c: - -- fixed ordering problem in queue process - -- fixed overly restrictive test for bad modifiers - -- fixed bug in vector calculation for VAXen - -- added variable controller, user defined drive support - -- revised to use magtape library + - fixed ordering problem in queue process + - fixed overly restrictive test for bad modifiers + - fixed bug in vector calculation for VAXen + - added variable controller, user defined drive support + - revised to use magtape library pdp18b_cpu.c: fixed three EAE bugs (found by Hans Pufal) pdp18b_mt.c: - -- fixed bugs in BOT error handling, interrupt handling - -- revised to use magtape library + - fixed bugs in BOT error handling, interrupt handling + - revised to use magtape library pdp18b_rf.c: - -- removed 22nd bit from disk address - -- fixed autosizing algorithm + - removed 22nd bit from disk address + - fixed autosizing algorithm pdp18b_stddev.c: - -- added set line frequency command - -- added set ctrl-c command + - added set line frequency command + - added set ctrl-c command pdp18b_sys.c: fixed FMTASC printouts (found by Hans Pufal) @@ -478,8 +536,8 @@ patch date module(s) and fix(es) pdp8_df.c, pdp8_rf.c, pdp8_rx.c: fixed autosizing algorithm pdp8_mt.c: - -- fixed bug in BOT error handling - -- revised to use magtape library + - fixed bug in BOT error handling + - revised to use magtape library pdp8_tt.c: added set ctrl-c command @@ -490,8 +548,8 @@ patch date module(s) and fix(es) vax_stddev.c: added set ctrl-c command 3 06-Feb-03 scp.c: - -- added dynamic extension of the breakpoint table - -- added breakpoint actions + - added dynamic extension of the breakpoint table + - added breakpoint actions hp2100_cpu.c: fixed last cycle bug in DMA output (found by Mike Gemeny) @@ -505,13 +563,13 @@ patch date module(s) and fix(es) LP09 printer pdp18b_rf.c: - -- fixed IOT decoding (found by Hans Pufal) - -- fixed address overrun logic - -- added variable number of platters and autosizing + - fixed IOT decoding (found by Hans Pufal) + - fixed address overrun logic + - added variable number of platters and autosizing pdp18b_rf.c: - -- fixed IOT decoding - -- fixed bug in command initiation + - fixed IOT decoding + - fixed bug in command initiation pdp18b_rb.c: new RB09 fixed head disk @@ -526,19 +584,19 @@ patch date module(s) and fix(es) id16_cpu.c: fixed bug in SETM, SETMR (found by Mark Pizzolato) 2 15-Jan-03 scp.c: - -- added dynamic memory size flag and RESTORE support - -- added EValuate command - -- added get_ipaddr routine - -- added ! (OS command) feature (from Mark Pizzolato) - -- added BREAK support to sim_poll_kbd (from Mark Pizzolato) + - added dynamic memory size flag and RESTORE support + - added EValuate command + - added get_ipaddr routine + - added ! (OS command) feature (from Mark Pizzolato) + - added BREAK support to sim_poll_kbd (from Mark Pizzolato) sim_tmxr.c: - -- fixed bugs in IAC+IAC handling (from Mark Pizzolato) - -- added IAC+BRK handling (from Mark Pizzolato) + - fixed bugs in IAC+IAC handling (from Mark Pizzolato) + - added IAC+BRK handling (from Mark Pizzolato) sim_sock.c: - -- added use count for Windows start/stop - -- added sim_connect_sock + - added use count for Windows start/stop + - added sim_connect_sock pdp1_defs.h, pdp1_cpu.c, pdp1_sys.c, pdp1_drm.c: added Type 24 serial drum @@ -552,10 +610,10 @@ patch date module(s) and fix(es) pdp11_tq.c: fixed bug in transfer end packet length pdp11_xq.c: - -- added VMScluster support (thanks to Mark Pizzolato) - -- added major performance enhancements (thanks to Mark Pizzolato) - -- added local packet processing - -- added system id broadcast + - added VMScluster support (thanks to Mark Pizzolato) + - added major performance enhancements (thanks to Mark Pizzolato) + - added local packet processing + - added system id broadcast pdp11_stddev.c: changed default to 7b (for early UNIX) @@ -568,132 +626,132 @@ patch date module(s) and fix(es) (found by Derek Peschel) pdp10_tu.c: - -- fixed bug in bootstrap (reported by Michael Thompson) - -- fixed bug in read (reported by Harris Newman) + - fixed bug in bootstrap (reported by Michael Thompson) + - fixed bug in read (reported by Harris Newman) 0 15-Nov-02 SCP and libraries scp.c: - -- added Telnet console support - -- removed VT emulation support - -- added support for statically buffered devices - -- added HELP - -- fixed bugs in set_logon, ssh_break (found by David Hittner) - -- added VMS file optimization (from Robert Alan Byer) - -- added quiet mode, DO with parameters, GUI interface, + - added Telnet console support + - removed VT emulation support + - added support for statically buffered devices + - added HELP + - fixed bugs in set_logon, ssh_break (found by David Hittner) + - added VMS file optimization (from Robert Alan Byer) + - added quiet mode, DO with parameters, GUI interface, extensible commands (from Brian Knittel) - -- added DEVICE context and flags - -- added central device enable/disable support - -- modified SAVE/GET to save and restore flags - -- modified boot routine calling sequence + - added DEVICE context and flags + - added central device enable/disable support + - modified SAVE/GET to save and restore flags + - modified boot routine calling sequence scp_tty.c: - -- removed VT emulation support - -- added sim_os_sleep, renamed sim_poll_kbd, sim_putchar + - removed VT emulation support + - added sim_os_sleep, renamed sim_poll_kbd, sim_putchar sim_tmxr.c: - -- modified for Telnet console support - -- fixed bug in binary (8b) support + - modified for Telnet console support + - fixed bug in binary (8b) support sim_sock.c: modified for Telnet console support sim_ether.c: new library for Ethernet (from David Hittner) all magtapes: - -- added support for end of medium - -- cleaned up BOT handling + - added support for end of medium + - cleaned up BOT handling all DECtapes: added support for RT11 image file format most terminals and multiplexors: - -- added support for 7b vs 8b character processing + - added support for 7b vs 8b character processing PDP-1 pdp1_cpu.c, pdp1_sys.c, pdp1_dt.c: added PDP-1 DECtape support PDP-8 pdp8_cpu.c, all peripherals: - -- added variable device number support - -- added new device enabled/disable support + - added variable device number support + - added new device enabled/disable support pdp8_rx.c: added RX28/RX02 support PDP-11 pdp11_defs.h, pdp11_io.c, pdp11_sys.c, all peripherals: - -- added variable vector support - -- added new device enable/disable support - -- added autoconfiguration support + - added variable vector support + - added new device enable/disable support + - added autoconfiguration support all bootstraps: modified to support variable addresses dec_mscp.h, pdp11_tq.c: added TK50 support pdp11_rq.c: - -- added multicontroller support - -- fixed bug in HBE error log packet - -- fixed bug in ATP processing + - added multicontroller support + - fixed bug in HBE error log packet + - fixed bug in ATP processing pdp11_ry.c: added RX211/RX02 support pdp11_hk.c: added RK611/RK06/RK07 support pdp11_tq.c: added TMSCP support pdp11_xq.c: added DEQNA/DELQA support (from David Hittner) pdp11_pclk.c: added KW11P support pdp11_ts.c: - -- fixed bug in CTL decoding - -- fixed bug in extended status XS0_MOT + - fixed bug in CTL decoding + - fixed bug in extended status XS0_MOT pdp11_stddev.c: removed paper tape to its own module PDP-18b pdp18b_cpu.c, all peripherals: - -- added variable device number support - -- added new device enabled/disabled support + - added variable device number support + - added new device enabled/disabled support VAX dec_dz.h: fixed bug in number of boards calculation vax_moddefs.h, vax_io.c, vax_sys.c, all peripherals: - -- added variable vector support - -- added new device enable/disable support - -- added autoconfiguration support + - added variable vector support + - added new device enable/disable support + - added autoconfiguration support vax_sys.c: - -- generalized examine/deposit - -- added TMSCP, multiple RQDX3, DEQNA/DELQA support + - generalized examine/deposit + - added TMSCP, multiple RQDX3, DEQNA/DELQA support vax_stddev.c: removed paper tape, now uses PDP-11 version vax_sysdev.c: - -- allowed NVR to be attached to file - -- removed unused variables (found by David Hittner) + - allowed NVR to be attached to file + - removed unused variables (found by David Hittner) PDP-10 pdp10_defs.h, pdp10_ksio.c, all peripherals: - -- added variable vector support - -- added new device enable/disable support + - added variable vector support + - added new device enable/disable support pdp10_defs.h, pdp10_ksio.c: added support for standard PDP-11 peripherals, added RX211 support pdp10_pt.c: rewritten to reference common implementation Nova, Eclipse: nova_cpu.c, eclipse_cpu.c, all peripherals: - -- added new device enable/disable support + - added new device enable/disable support HP2100 hp2100_cpu: - -- fixed bugs in the EAU, 21MX, DMS, and IOP instructions - -- fixed bugs in the memory protect and DMS functions - -- created new options to enable/disable EAU, MPR, DMS - -- added new device enable/disable support + - fixed bugs in the EAU, 21MX, DMS, and IOP instructions + - fixed bugs in the memory protect and DMS functions + - created new options to enable/disable EAU, MPR, DMS + - added new device enable/disable support hp2100_fp.c: - -- recoded to conform to 21MX microcode algorithms + - recoded to conform to 21MX microcode algorithms hp2100_stddev.c: - -- fixed bugs in TTY reset, OTA, time base generator - -- revised BOOT support to conform to RBL loader - -- added clock calibration + - fixed bugs in TTY reset, OTA, time base generator + - revised BOOT support to conform to RBL loader + - added clock calibration hp2100_dp.c: - -- changed default to 13210A - -- added BOOT support + - changed default to 13210A + - added BOOT support hp2100_dq.c: - -- finished incomplete functions, fixed head switching - -- added BOOT support + - finished incomplete functions, fixed head switching + - added BOOT support hp2100_ms.c: - -- fixed bugs found by diagnostics - -- added 13183 support - -- added BOOT support + - fixed bugs found by diagnostics + - added 13183 support + - added BOOT support hp2100_mt.c: - -- fixed bugs found by diagnostics - -- disabled by default + - fixed bugs found by diagnostics + - disabled by default hp2100_lpt.c: implemented 12845A controller hp2100_lps.c: - -- renamed 12653A controller - -- added diagnostic mode for MPR, DCPC diagnostics - -- disabled by default + - renamed 12653A controller + - added diagnostic mode for MPR, DCPC diagnostics + - disabled by default IBM 1620: first release @@ -732,13 +790,13 @@ patch date module(s) and fix(es) sim_sock.c: added OS/2 support (from Holger Veit) pdp11_cpu.c: fixed bugs (from John Dundas) - -- added special case for PS<15:12> = 1111 to MFPI - -- removed special case from MTPI - -- added masking of relocation adds + - added special case for PS<15:12> = 1111 to MFPI + - removed special case from MTPI + - added masking of relocation adds i1401_cpu.c: - -- added multiply/divide - -- fixed bugs (found by Van Snyder) + - added multiply/divide + - fixed bugs (found by Van Snyder) o 5 and 7 character H, 7 character doesn't branch o 8 character NOP o 1401-like memory dump @@ -748,16 +806,16 @@ patch date module(s) and fix(es) 9 04-May-02 pdp11_rq: fixed bug in polling routine 8 03-May-02 scp.c: - -- changed LOG/NOLOG to SET LOG/NOLOG - -- added SHOW LOG - -- added SET VT/NOVT and SHOW VT for VT emulation + - changed LOG/NOLOG to SET LOG/NOLOG + - added SHOW LOG + - added SET VT/NOVT and SHOW VT for VT emulation sim_sock.h: changed VMS stropt.h include to ioctl.h vax_cpu.c - -- added TODR powerup routine to set date, time on boot - -- fixed exception flows to clear trap request - -- fixed register logging in autoincrement indexed + - added TODR powerup routine to set date, time on boot + - fixed exception flows to clear trap request + - fixed register logging in autoincrement indexed vax_stddev.c: added TODR powerup routine @@ -768,25 +826,25 @@ patch date module(s) and fix(es) pdp11_cpu.c: fixed bugs, added features (from John Dundas and Wolfgang Helbig) - -- added HTRAP and BPOK to maintenance register - -- added trap on kernel HALT if MAINT set - -- fixed red zone trap, clear odd address and nxm traps - -- fixed RTS SP, don't increment restored SP - -- fixed TSTSET, write dst | 1 rather than prev R0 | 1 - -- fixed DIV, set N=0,Z=1 on div by zero (J11, 11/70) - -- fixed DIV, set set N=Z=0 on overfow (J11, 11/70) - -- fixed ASH, ASHC, count = -32 used implementation- + - added HTRAP and BPOK to maintenance register + - added trap on kernel HALT if MAINT set + - fixed red zone trap, clear odd address and nxm traps + - fixed RTS SP, don't increment restored SP + - fixed TSTSET, write dst | 1 rather than prev R0 | 1 + - fixed DIV, set N=0,Z=1 on div by zero (J11, 11/70) + - fixed DIV, set set N=Z=0 on overfow (J11, 11/70) + - fixed ASH, ASHC, count = -32 used implementation- dependent 32 bit right shift - -- fixed illegal instruction test to detect 000010 - -- fixed write-only page test + - fixed illegal instruction test to detect 000010 + - fixed write-only page test pdp11_rp.c: fixed SHOW ADDRESS command vaxmod_defs.h: fixed DZ vector base and number of lines dec_dz.h: - -- fixed interrupt acknowledge routines - -- fixed SHOW ADDRESS command + - fixed interrupt acknowledge routines + - fixed SHOW ADDRESS command all magtape routines: added test for badly formed record length (suggested by Jonathan Engdahl) @@ -798,8 +856,8 @@ patch date module(s) and fix(es) vax_fpu.c: fixed EDIV overflow test for 0 quotient 5 14-Apr-02 vax_cpu1.c: - -- fixed interrupt, prv_mode set to 0 (found by Tim Stark) - -- fixed PROBEx to mask mode to 2b (found by Kevin Handy) + - fixed interrupt, prv_mode set to 0 (found by Tim Stark) + - fixed PROBEx to mask mode to 2b (found by Kevin Handy) 4 1-Apr-02 pdp11_rq.c: fixed bug, reset cleared write protect status @@ -816,8 +874,8 @@ patch date module(s) and fix(es) revised to allocate memory dynamically 2 01-Mar-02 pdp11_cpu.c: - -- fixed bugs in CPU registers - -- fixed double operand evaluation order for M+ + - fixed bugs in CPU registers + - fixed double operand evaluation order for M+ pdp11_rq.c: added delays to initialization for RSX11M+ prior to V4.5 @@ -833,8 +891,8 @@ patch date module(s) and fix(es) PDP-7 DECtape support hp2100_cpu.c: - -- added floating point and DMS - -- fixed bugs in DIV, ASL, ASR, LBT, SBT, CBT, CMW + - added floating point and DMS + - fixed bugs in DIV, ASL, ASR, LBT, SBT, CBT, CMW hp2100_sys.c: added floating point, DMS @@ -843,24 +901,24 @@ patch date module(s) and fix(es) ibm1130: added Brian Knittel's IBM 1130 simulator 0 30-Jan-02 scp.c: - -- generalized timer package for multiple timers - -- added circular register arrays - -- fixed bugs, line spacing in modifier display - -- added -e switch to attach - -- moved device enable/disable to simulators + - generalized timer package for multiple timers + - added circular register arrays + - fixed bugs, line spacing in modifier display + - added -e switch to attach + - moved device enable/disable to simulators scp_tty.c: VAX specific fix (from Robert Alan Byer) sim_tmxr.c, sim_tmxr.h: - -- added tmxr_fstats, tmxr_dscln - -- renamed tmxr_fstatus to tmxr_fconns + - added tmxr_fstats, tmxr_dscln + - renamed tmxr_fstatus to tmxr_fconns sim_sock.c, sim_sock.h: added VMS support (from Robert Alan Byer) pdp_dz.h, pdp18b_tt1.c, nova_tt1.c: - -- added SET DISCONNECT - -- added SHOW STATISTICS + - added SET DISCONNECT + - added SHOW STATISTICS pdp8_defs.h: fixed bug in interrupt enable initialization @@ -876,9 +934,9 @@ patch date module(s) and fix(es) exit (found by Doug Carman) hp2100_cpu.c: - -- fixed DMA register tables (found by Bill McDermith) - -- fixed SZx,SLx,RSS bug (found by Bill McDermith) - -- fixed flop restore logic (found by Bill McDermith) + - fixed DMA register tables (found by Bill McDermith) + - fixed SZx,SLx,RSS bug (found by Bill McDermith) + - fixed flop restore logic (found by Bill McDermith) hp2100_mt.c: fixed bug on write of last character @@ -892,17 +950,17 @@ patch date module(s) and fix(es) word mark (found by Van Snyder) most CPUs: - -- replaced OLDPC with PC queue - -- implemented device enable/disable locally + - replaced OLDPC with PC queue + - implemented device enable/disable locally V2.8 revision history 5 25-Dec-01 scp.c: fixed bug in DO command (found by John Dundas) pdp10_cpu.c: - -- moved trap-in-progress to separate variable - -- cleaned up declarations - -- cleaned up volatile state for GNU C longjmp + - moved trap-in-progress to separate variable + - cleaned up declarations + - cleaned up volatile state for GNU C longjmp pdp11_cpu.c: cleaned up declarations @@ -911,9 +969,9 @@ patch date module(s) and fix(es) 4 17-Dec-01 pdp11_rq.c: added delayed processing of packets 3 16-Dec-01 pdp8_cpu.c: - -- mode A EAE instructions didn't clear GTF - -- ASR shift count > 24 mis-set GTF - -- effective shift count == 32 didn't work + - mode A EAE instructions didn't clear GTF + - ASR shift count > 24 mis-set GTF + - effective shift count == 32 didn't work 2 07-Dec-01 scp.c: added breakpoint package @@ -992,9 +1050,9 @@ patch date module(s) and fix(es) interrupting only if DON = 1 as well 4 27-Sep-01 pdp11_ts.c: - -- NXM errors should return TC4 or TC5; were returning TC3 - -- extended features is part of XS2; was returned in XS3 - -- extended characteristics (fifth) word needed for RSTS/E + - NXM errors should return TC4 or TC5; were returning TC3 + - extended features is part of XS2; was returned in XS3 + - extended characteristics (fifth) word needed for RSTS/E pdp11_tc.c: stop, stop all do cause an interrupt @@ -1002,8 +1060,8 @@ patch date module(s) and fix(es) if there are no connections; needed for RSTS/E autoconfigure scp.c: - -- added routine sim_qcount for 1130 - -- added "simulator exit" detach routine for 1130 + - added routine sim_qcount for 1130 + - added "simulator exit" detach routine for 1130 sim_defs.h: added header for sim_qcount diff --git a/simh_doc.txt b/simh_doc.txt index 9669ec87..7a4fa0cf 100644 --- a/simh_doc.txt +++ b/simh_doc.txt @@ -1,7 +1,7 @@ To: Users From: Bob Supnik -Subj: Simulator Usage, V3.2 -Date: 4-Apr-2004 +Subj: Simulator Usage, V3.2-1 +Date: 15-Jun-2004 COPYRIGHT NOTICE @@ -527,8 +527,8 @@ These simulator-detected conditions stop simulation: 3.7.2 User Specified Stop Conditions Typing the interrupt character stops simulation. The interrupt character -is defined by the WRU (where are you) register and is initially set to -005 (^E). +is defined by the WRU (where are you) console option and is initially set +to 005 (^E). 3.7.3 Breakpoints @@ -632,16 +632,6 @@ Most multi-unit devices allow units to be placed online or offline: When a unit is offline, it will not be displayed by SHOW DEVICE. -The console terminal normally runs in the controlling window. -Optionally, the console terminal can be connected to a Telnet port. -This allows systems to emulate a VT100 using the built-in terminal -emulation of the Telnet client. - - sim> SET TELNET -- listen for console - Telnet connection on port - sim> SET NOTELNET -- disable console Telnet - sim> SHOW TELNET -- show console Telnet status - The standard device names can be supplemented with logical names. Logical names must be unique within a simulator (that is, they cannot be the same as an existing device name). To assign a logical name @@ -661,18 +651,43 @@ To show all logical names: sim> SHOW NAMES -3.11 Logging Console Output +3.11 Console Options -Output to the console can be logged simultaneously to a file. Logging -is enabled by the LOG command: +Console options are controlled by the SET CONSOLE command. - sim> SET LOG -- log console output to file +The console terminal normally runs in the controlling window. +Optionally, the console terminal can be connected to a Telnet port. +This allows systems to emulate a VT100 using the built-in terminal +emulation of the Telnet client. -Logging is disabled by the NOLOG command: + sim> SET CONSOLE TELNET= -- connect console terminal + to Telnet session on port + sim> SET CONSOLE NOTELNET -- disable console Telnet - sim> SET NOLOG -- disable logging +Output to the console can be logged simultaneously to a file: -SHOW LOG displays whether logging is enabled or disabled. + sim> SET CONSOLE LOG= -- log console output to file + sim> SET CONSOLE NOLOG -- disable logging + +The console provides a limited key remapping capability: + + sim> SET CONSOLE WRU= -- interpret ASCII code + value as WRU + sim> SET CONSOLE BRK= -- interpret ASCII code + value as BREAK (0 disables) + sim> SET CONSOLE DEL= -- interpret ASCII code + value as DELETE + +Values are hexadecimal on hex CPU's, octal on all others. + +The SHOW CONSOLE command displays the current state of console options: + + sim> SHOW CONSOLE -- show all console options + sim> SHOW CONSOLE TELNET -- show console Telnet state + sim> SHOW CONSOLE LOG -- show console logging state + sim> SHOW CONSOLE WRU -- show value assigned to WRU + sim> SHOW CONSOLE BRK -- show value assigned to BREAK + sim> SHOW CONSOLE DEL -- show value assigned to DELETE 3.12 Executing Command Files @@ -859,9 +874,9 @@ line printer y y y h y clock - y y h y extra terminal - y y - y hard disk h y y - y -fixed disk - n - h - +fixed disk - h - h - floppy disk - - h - - -drum - n - - - +drum - h - - - DECtape - - - - - mag tape y y y h y diff --git a/simh_swre.txt b/simh_swre.txt index eba0731a..6677bed2 100644 --- a/simh_swre.txt +++ b/simh_swre.txt @@ -1,7 +1,7 @@ To: Users From: Bob Supnik Subj: Sample Software Packages -Date: 15-Jan-2004 +Date: 06-Apr-2004 This memorandum documents the sample software packages available to run with the SIMH simulators. Many of these packages are available under @@ -176,7 +176,7 @@ the license. UNIX V5 is contained on a single RK05 disk image. To boot UNIX: - sim> set cpu 18b + sim> set cpu u18 sim> att rk0 unix_v5_rk.dsk sim> boot rk @unix @@ -187,7 +187,7 @@ UNIX V5 is contained on a single RK05 disk image. To boot UNIX: UNIX V6 is contained on four RK05 disk images. To boot UNIX: - sim> set cpu 18b + sim> set cpu u18 sim> att rk0 unix0_v6_rk.dsk sim> att rk1 unix1_v6_rk.dsk sim> att rk2 unix2_v6_rk.dsk @@ -201,7 +201,7 @@ UNIX V6 is contained on four RK05 disk images. To boot UNIX: UNIX V7 is contained on a single RL02 disk image. To boot UNIX: - sim> set cpu 18b + sim> set cpu u18 sim> set rl0 RL02 sim> att rl0 unix_v7_rl.dsk sim> boot rl0 @@ -212,7 +212,7 @@ UNIX V7 is contained on a single RL02 disk image. To boot UNIX: A smaller image is contained on a single RK05 disk image. To boot UNIX: - sim> set cpu 18b + sim> set cpu u18 sim> att rk0 unix_v7_rk.dsk sim> boot rk0 @boot