The paradigm of using a "weak" linker reference to find what was previously the vm_init_routine() doesn't work reliably on all compile environments supported by the simulators. This has been reported in #794 and it came up again in #862. This change assures that it will not come up again AND it reliably solves the problem with Visual Studio compilers (and linker) that randomly chooses whether to have the desired effect or not. Of the 82 simulators which are currently part of simh, only these three used the sim_vm_init() interface, so removing it had relatively minor impact.
376 lines
18 KiB
C
376 lines
18 KiB
C
/* i650_defs.h: IBM 650 simulator definitions
|
|
|
|
Copyright (c) 2018, Roberto Sancho
|
|
|
|
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
|
|
ROBERTO SANCHO BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
*/
|
|
|
|
#include "sim_defs.h" /* simulator defns */
|
|
|
|
/* Simulator stop codes */
|
|
|
|
#define STOP_HALT 1 /* HALT */
|
|
#define STOP_IBKPT 2 /* breakpoint */
|
|
#define STOP_UUO 3 /* invalid opcode */
|
|
#define STOP_IO 4 /* Stop on IO:
|
|
card reader/punch error:
|
|
no card in hopper, read/punch failure, no cards, stop pressed on cdr/cdp
|
|
only simulated no card in hopper situation when all cards from attached file has been read
|
|
tape:
|
|
executed tape opcode and got non handled by indicator error
|
|
disk:
|
|
selected arm or unit out of range
|
|
*/
|
|
#define STOP_PROG 5 /* Programmed stop */
|
|
#define STOP_OV 6 /* Overflow stop */
|
|
#define STOP_ERRO 7 /* Error in opcode execution: BRD in witch position tested not 8 or 9, TLU failure */
|
|
#define STOP_ADDR 8 /* Address stop: Store attempt on addr 800X, address out of drum mem */
|
|
|
|
|
|
/* Memory */
|
|
#define MAXDRUMSIZE (4000)
|
|
#define DRUMSIZE ((int)(cpu_unit.capac % 10) * 1000) /* actual drum memory size */
|
|
|
|
extern t_int64 DRUM[MAXDRUMSIZE];
|
|
extern int DRUM_NegativeZeroFlag[MAXDRUMSIZE];
|
|
extern char DRUM_Symbolic_Buffer[MAXDRUMSIZE * 80];
|
|
extern char IAS_Symbolic_Buffer[60 * 80];
|
|
|
|
extern t_int64 IOSync[10];
|
|
extern int IOSync_NegativeZeroFlag[10];
|
|
|
|
#define STOR ((uint32)cpu_unit.flags & OPTION_STOR) // return non zero if set cpu storage option set
|
|
#define CNTRL ((uint32)cpu_unit.flags & OPTION_CNTRL) // return non zero if set cpu cntrl option set
|
|
#define FAST ((uint32)(cpu_unit.flags & OPTION_FAST) ? 1:0) // return non zero if set cpu fast option set
|
|
#define DRUM4K ((uint32)cpu_unit.flags & MEMAMOUNT(2)) // return 0 if drum size < 4k, non zero if = 4k
|
|
|
|
extern t_int64 IAS[60];
|
|
extern int IAS_NegativeZeroFlag[60];
|
|
extern int IAS_TimingRing;
|
|
extern int InterLockCount[8];
|
|
|
|
extern int WriteAddr(int AR, t_int64 d, int NegZero);
|
|
extern int ReadAddr(int AR, t_int64 * d, int * NegZero);
|
|
extern CONST char * DecodeOpcode(t_int64 d, int * opcode, int * DA, int * IA);
|
|
|
|
|
|
/* digits contants */
|
|
#define D10 (10000000000LL) // ten digits (10 zeroes)
|
|
#define D8 (100000000L) // eight digits (8 zeroes)
|
|
#define D4 (10000L) // four digits (4 zeroes)
|
|
|
|
// increment umber of word counts elapsed from starting of simulator -> this is the global time measurement
|
|
extern t_int64 GlobalWordTimeCount;
|
|
|
|
/* Device information block */
|
|
struct dib {
|
|
uint8 upc; // Number of Units in device
|
|
uint32 (*cmd)(UNIT *up, uint16 cmd, uint16 dev);/* Issue command. */
|
|
void (*ini)(UNIT *up, t_bool f);
|
|
};
|
|
|
|
typedef struct dib DIB;
|
|
|
|
/* Debuging controls */
|
|
#define DEBUG_CMD 0x0000010 /* Show device commands */
|
|
#define DEBUG_DETAIL 0x0000020 /* Show details */
|
|
#define DEBUG_EXP 0x0000040 /* Show error conditions */
|
|
#define DEBUG_DATA 0x0000080 /* Show data details */
|
|
|
|
extern DEBTAB dev_debug[];
|
|
extern DEBTAB crd_debug[];
|
|
|
|
/* Returns from device commands */
|
|
#define SCPE_BUSY (1) // Device is active
|
|
#define SCPE_NOCARDS (2) // No cards to read or to write
|
|
#define SCPE_OK_INPROGRESS (3) // Operation in progress
|
|
|
|
/* Global device definitions */
|
|
#ifdef CPANEL
|
|
extern DEVICE cp_dev;
|
|
#endif
|
|
|
|
#define MAX_CARDS_IN_DECK 10000 // max number of cards in deck for carddeck internal command
|
|
#define MAX_CARDS_IN_READ_STAKER_HOPPER 10 // max number of cards in card reader take
|
|
// staker that can be viewev with carddeck echolast
|
|
|
|
extern DIB cdr_dib;
|
|
extern DEVICE cdr_dev;
|
|
extern uint32 cdr_cmd(UNIT *, uint16, uint16);
|
|
extern UNIT cdr_unit[4];
|
|
extern uint16 ReadStaker[3 * MAX_CARDS_IN_READ_STAKER_HOPPER * 80];
|
|
extern int ReadStakerLast[3];
|
|
|
|
extern DIB cdp_dib;
|
|
extern DEVICE cdp_dev;
|
|
extern uint32 cdp_cmd(UNIT *, uint16, uint16);
|
|
extern UNIT cdp_unit[4];
|
|
|
|
/* Card read-punch device status information stored in u5 */
|
|
#define URCSTA_ERR 0002 /* Error reading record */
|
|
#define URCSTA_BUSY 0010 /* Device unit is busy */
|
|
#define URCSTA_LOAD 01000 /* Load flag for 533 card reader */
|
|
#define URCSTA_SOAPSYMB 02000 /* Get soap symbolic info when reading the card */
|
|
|
|
extern DIB mt_dib;
|
|
extern DEVICE mt_dev;
|
|
extern uint32 mt_cmd(UNIT *, uint16, uint16);
|
|
extern UNIT mt_unit[6];
|
|
extern int LastTapeSelected;
|
|
extern int LastTapeIndicator;
|
|
extern const char * TapeIndicatorStr[11];
|
|
extern int mt_ready(int n);
|
|
extern void mt_ini(UNIT * uptr, t_bool f);
|
|
|
|
/* Tape Indicator status */
|
|
#define MT_IND_WRT_PROT 1 // attempting to write to a write protected tape
|
|
#define MT_IND_IOCHECK 2 // host os i/o error on tape file
|
|
#define MT_IND_EOF 3 // found Tape Mark in current record while reading
|
|
#define MT_IND_EOT 4 // found End of Tape Mark while reading/writing
|
|
#define MT_IND_LONG_REC 5 // record begin read from tape does not fit in record defined at IAS storage
|
|
#define MT_IND_SHORT_REC 6 // record begin read from tape does not fill record defined at IAS storage
|
|
#define MT_IND_DIS 7 // no tape has this address (tape unit is disabled)
|
|
#define MT_IND_NOATT 8 // no reel load on tape (no tape file attached)
|
|
#define MT_IND_NOTRDY 9 // tape not ready
|
|
#define MT_IND_BADCHAR 10 // tape not ready
|
|
|
|
extern DIB dsk_dib;
|
|
extern DEVICE dsk_dev;
|
|
extern uint32 dsk_cmd(int, int32, uint16);
|
|
extern UNIT dsk_unit[4];
|
|
extern int dsk_ready(int n, int arm);
|
|
extern void dsk_ini(UNIT * uptr, t_bool f);
|
|
|
|
/* Disk Indicator status */
|
|
#define DSK_IND_BADADDR 1 // invalid unit/arm/disk plate/track accessed
|
|
#define DSK_IND_IOCHECK 2 // host os i/o error on disk file
|
|
#define DSK_IND_DIS 7 // no disk has this address (disk unit is disabled)
|
|
#define DIS_IND_NOATT 8 // no disk file attached
|
|
#define DIS_IND_NOTRDY 9 // disk arm not ready
|
|
|
|
extern struct card_wirings {
|
|
uint32 mode;
|
|
const char *name;
|
|
} wirings[];
|
|
|
|
extern char digits_ascii[31];
|
|
extern char mem_to_ascii[101];
|
|
extern int ascii_to_NN(int ch);
|
|
extern uint16 sim_ascii_to_hol(char c);
|
|
extern char sim_hol_to_ascii(uint16 hol);
|
|
|
|
/* Generic devices common to all */
|
|
extern DEVICE cpu_dev;
|
|
extern UNIT cpu_unit;
|
|
extern REG cpu_reg[];
|
|
|
|
extern const char *cpu_description(DEVICE *dptr);
|
|
|
|
/* Opcodes */
|
|
// Instructions on Basic machine
|
|
#define OP_AABL 17 // Add absolute to lower accumulator
|
|
#define OP_AL 15 // Add to lower accumulator
|
|
#define OP_AU 10 // Add to upper accumulator
|
|
#define OP_BRNZ 45 // Branch on accumulator non-zero
|
|
#define OP_BRMIN 46 // Branch on minus accumulator
|
|
#define OP_BRNZU 44 // Branch on non-zero in upper accumulator
|
|
#define OP_BROV 47 // Branch on overflow
|
|
#define OP_BRD1 91 // Branch on 8 in distributor positions 1-10
|
|
#define OP_BRD2 92
|
|
#define OP_BRD3 93
|
|
#define OP_BRD4 94
|
|
#define OP_BRD5 95
|
|
#define OP_BRD6 96
|
|
#define OP_BRD7 97
|
|
#define OP_BRD8 98
|
|
#define OP_BRD9 99
|
|
#define OP_BRD10 90
|
|
#define OP_DIV 14 // Divide
|
|
#define OP_DIVRU 64 // Divide and reset upper accumulator
|
|
#define OP_LD 69 // Load distributor
|
|
#define OP_MULT 19 // Multiply
|
|
#define OP_NOOP 00 // No operation
|
|
#define OP_PCH 71 // Punch a card
|
|
#define OP_RD 70 // Read a card
|
|
#define OP_RAABL 67 // Reset accumulator and add absolute to lower accumulator
|
|
#define OP_RAL 65 // Reset accumulator and add to lower accumulator
|
|
#define OP_RAU 60 // Reset accumulator and add to upper accumulator
|
|
#define OP_RSABL 68 // Reset accumulator and subtract absolute from lower accumulator
|
|
#define OP_RSL 66 // Reset accumulator and subtract from lower accumulator
|
|
#define OP_RSU 61 // Reset accumulator and subtract from upper accumulator
|
|
#define OP_SLT 35 // Shift accumulator left
|
|
#define OP_SCT 36 // Shift accumulator left and count
|
|
#define OP_SRT 30 // Shift accumulator right
|
|
#define OP_SRD 31 // Shift accumulator right and round accumulator
|
|
#define OP_STOP 01 // Stop if console switch is set to stop, otherwise continue as a NO-OP
|
|
#define OP_STD 24 // Store distributor into memory
|
|
#define OP_STDA 22 // Store lower accumulator data address into distributor, then store distributor into memory
|
|
#define OP_STIA 23 // Store lower accumulator instruction address into distributor, then store distributor into memory
|
|
#define OP_STL 20 // Store lower accumulator into memory
|
|
#define OP_STU 21 // Store upper accumulator into memory
|
|
#define OP_SABL 18 // Subtract absolute from lower accumulator
|
|
#define OP_SL 16 // Subtract from lower accumulator
|
|
#define OP_SU 11 // Subtract from upper accumulator
|
|
#define OP_TLU 84 // Table lookup
|
|
#define OP_TLE 63 // Table lookup on equal
|
|
// Instructions on Storage Unit
|
|
// opcodes for indexing
|
|
#define OP_AXA 50 // Add to index register A
|
|
#define OP_SXA 51 // Substract from index A
|
|
#define OP_RAA 80 // Reset Add Index A
|
|
#define OP_RSA 81 // Reset Substract Index A
|
|
#define OP_NZA 40 // Branch Non Zero Index A
|
|
#define OP_BMA 41 // Branch Minus Index A
|
|
#define OP_AXB 52 // Add to index register B
|
|
#define OP_SXB 53 // Substract from index B
|
|
#define OP_RAB 82 // Reset Add Index B
|
|
#define OP_RSB 83 // Reset Substract Index B
|
|
#define OP_NZB 42 // Branch Non Zero Index B
|
|
#define OP_BMB 43 // Branch Minus Index B
|
|
#define OP_AXC 58 // Add to index register C
|
|
#define OP_SXC 59 // Substract from index C
|
|
#define OP_RAC 88 // Reset Add Index C
|
|
#define OP_RSC 89 // Reset Substract Index C
|
|
#define OP_NZC 48 // Branch Non Zero Index C
|
|
#define OP_BMC 49 // Branch Minus Index C
|
|
// io for synchronizers 2 & 3
|
|
#define OP_RC1 72 // Read Conditional sync 1
|
|
#define OP_RD2 73 // Read Sync 2
|
|
#define OP_WR2 74 // Write Sync 2
|
|
#define OP_RC2 75 // Read Conditional Sync 2
|
|
#define OP_RD3 76 // Read Sync 3
|
|
#define OP_WR3 77 // Write Sync 3
|
|
#define OP_RC3 78 // Read Conditional Sync 3
|
|
// immediate access storage (ias)
|
|
#define OP_LIB 8 // Load IAS block
|
|
#define OP_LDI 9 // Load IAS
|
|
#define OP_SIB 28 // Store IAS Block
|
|
#define OP_STI 29 // Store IAS
|
|
#define OP_SET 27 // Set IAS Timing Ring
|
|
// floating point
|
|
#define OP_FAD 32 // Floating Add
|
|
#define OP_FSB 33 // Floating Subtract
|
|
#define OP_FMP 39 // Floating Multiply
|
|
#define OP_FDV 34 // Floating Divide
|
|
#define OP_UFA 02 // Unnormalized Floating Add
|
|
#define OP_FAM 37 // Floating Add Absolute (Magnitude)
|
|
#define OP_FSM 38 // Floating Subtract Absolute (Magnitude)
|
|
// Instructions on Control Unit
|
|
// tape
|
|
#define OP_RTN 04 // Read Tape Numeric
|
|
#define OP_RTA 05 // Read Tape Alphameric
|
|
#define OP_WTN 06 // Write Tape Numeric
|
|
#define OP_WTA 07 // Write Tape Alphameric
|
|
#define OP_RTC 03 // Read Tape for Checking
|
|
#define OP_NTS 25 // Branch no Tape Signal
|
|
#define OP_NEF 54 // Branch no End of File
|
|
#define OP_RWD 55 // Rewind Tape
|
|
#define OP_WTM 56 // Write Tape Mark
|
|
#define OP_BST 57 // Backspace Tape
|
|
// ramac disk
|
|
#define OP_SDS 85 // Seek Disk Storage
|
|
#define OP_RDS 86 // Read Disk Storage
|
|
#define OP_WDS 87 // Write Disk Storage
|
|
// inquiry stations
|
|
#define OP_BIN 26 // Branch on Inquiry
|
|
#define OP_RPY 79 // Reply on Inquiry
|
|
|
|
// Valid Data Address (DA)
|
|
#define vda_D 1 // 0000-1999 Drum
|
|
#define vda_A 2 // 8000-8003 Arithmetic unit registers (ACC Low & Hi), Distributor, Console Switches register
|
|
#define vda_I 4 // 8005-8007 Index Registers (IR)
|
|
#define vda_T 8 // 8010-8015 Tape address
|
|
#define vda_S 16 // 9000-9059 Immediate Access Storage (IAS)
|
|
#define vda_9000 32 // 9000 Only addr 9000 valid
|
|
|
|
#define vda_DAITS (vda_D | vda_A | vda_I | vda_T | vda_S )
|
|
#define vda_DAIS (vda_D | vda_A | vda_I | vda_S )
|
|
#define vda_DAS (vda_D | vda_A | vda_S )
|
|
#define vda_DS (vda_D | vda_S )
|
|
|
|
#define opReadDA 1 // opcode fetchs data from DA address
|
|
#define opWriteDA 2 // opcode write data to DA
|
|
|
|
#define opStorUnit 1 // opcode available if IBM 653 Storage Unit is present
|
|
#define opCntrlUnit 2 // opcode available if IBM 652 Control Unit is present
|
|
#define opTLE 3 // opcode available if Table Lookup on equal feature installed
|
|
|
|
#define IL_RD1 1 // interlock on drum area 01-10/51-60 used in reading with RD1
|
|
#define IL_WR1 2 // interlock on drum area 27-36/77-86 used in writing for WR1
|
|
#define IL_RD23 3 // interlock on drum area 39-48/89-98 used in reading with RD2/RD3
|
|
#define IL_WR23 4 // interlock on drum area 13-22/63-72 used in writing for WR2/WR3
|
|
#define IL_IAS 5 // interlock on ias access
|
|
#define IL_Tape 6 // interlock on tape control circuits
|
|
#define IL_RamacUnit 7 // interlock on ramac unit control circuits
|
|
|
|
#define IL_Tape_and_Unit_and_IAS 100 // interlock IAS + Tape control + Tape Unit
|
|
#define IL_Tape_and_Unit 101 // interlock Tape control + Tape Unit
|
|
#define IL_RamacUnit_and_Arm_and_IAS 102 // interlock IAS + Ramac unit control + Unit Access Arm
|
|
#define IL_RamacUnit_and_Arm 103 // interlock + Ramac unit control + Unit Access Arm
|
|
|
|
#define msec_to_wordtime(n) ((int)(n / 0.096)) // convert time in msec to number of word times
|
|
#define msec_elapsed(n) ((int)((GlobalWordTimeCount - (n)) * 0.096)) // return msec elapsed from a give wordtime stamp
|
|
|
|
|
|
/* Symbol tables */
|
|
typedef struct
|
|
{
|
|
uint16 opbase; // opcode number
|
|
const char *name1; // opcode name as in operation manual
|
|
const char *name2; // opcode name as in soap
|
|
uint8 opRW; // =wDA, rDA or zero
|
|
int option; // =0 -> opcode in basic machine, =1 -> Opcode because Storage Unit, =2 -> Opcode because Control Unit
|
|
int validDA; // valid data address for this instruction
|
|
int opInterLock; // Interlock required by opcode
|
|
}
|
|
t_opcode;
|
|
|
|
extern t_opcode base_ops[100];
|
|
|
|
|
|
#define NEGZERO_value 0x7fffFFFFffffFFFF
|
|
#define AccNegative (((AccNegativeZeroFlag) || (ACC[1]<0) || (ACC[0]<0)) ? 1:0)
|
|
#define AbsWord(d) ((d < 0) ? -d:d)
|
|
#define printfw(d,negzero) (int32) AbsWord(d/D4), (int32) AbsWord(d%D4), ((d<0) || (negzero)) ? '-':'+'
|
|
#define printfd printfw(DIST, DistNegativeZeroFlag)
|
|
#define printfa (int32) AbsWord(ACC[1]/D4),(int32) AbsWord(ACC[1]%D4), printfw(AbsWord(ACC[0]), AccNegative)
|
|
|
|
/* Standard control panel wiring for card read/punch/print */
|
|
|
|
#define UNIT_CARD_WIRING ( 0xF00 << UNIT_V_CARD_MODE)
|
|
#define WIRING_8WORD ( 0x000 << UNIT_V_CARD_MODE)
|
|
#define WIRING_SOAP ( 0x100 << UNIT_V_CARD_MODE)
|
|
#define WIRING_SOAPA ( 0x200 << UNIT_V_CARD_MODE)
|
|
#define WIRING_IS ( 0x300 << UNIT_V_CARD_MODE)
|
|
#define WIRING_IT ( 0x400 << UNIT_V_CARD_MODE)
|
|
#define WIRING_FORTRANSIT ( 0x500 << UNIT_V_CARD_MODE)
|
|
#define WIRING_RA ( 0x600 << UNIT_V_CARD_MODE)
|
|
#define WIRING_FDS ( 0x700 << UNIT_V_CARD_MODE)
|
|
#define WIRING_SUPERSOAP ( 0x800 << UNIT_V_CARD_MODE)
|
|
#define UNIT_CARD_ECHO ( 0x1000 << UNIT_V_CARD_MODE)
|
|
#define UNIT_CARD_PRINT ( 0x2000 << UNIT_V_CARD_MODE)
|
|
|
|
/* Decimal helper functions */
|
|
extern int Get_HiDigit(t_int64 d);
|
|
extern int Shift_Digits(t_int64 * d, int nDigits);
|
|
extern char * word_to_ascii(char * buf, int CharStart, int CharLen, t_int64 d);
|
|
|
|
extern void vm_init(void); /* One time initialization activities now called in cpu_reset() */
|
|
|
|
|