| /* eclipse_cpu.c: Eclipse CPU simulator | |
| Modified from the original NOVA simulator by Robert Supnik. | |
| Copyright (c) 1998-2012, Charles E Owen | |
| Portions Copyright (c) 1993-2002, Robert M Supnik | |
| Permission is hereby granted, free of charge, to any person obtaining a | |
| copy of this software and associated documentation files (the "Software"), | |
| to deal in the Software without restriction, including without limitation | |
| the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| and/or sell copies of the Software, and to permit persons to whom the | |
| Software is furnished to do so, subject to the following conditions: | |
| The above copyright notice and this permission notice shall be included in | |
| all copies or substantial portions of the Software. | |
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER | |
| IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | |
| CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |
| Except as contained in this notice, the name of Robert M Supnik shall not be | |
| used in advertising or otherwise to promote the sale, use or other dealings | |
| in this Software without prior written authorization from Robert M Supnik. | |
| cpu Eclipse central processor | |
| 25-Mar-12 RMS Fixed declarations (Mark Pizzolato) | |
| 07-Jun-06 RMS Fixed bug in DIVS (Mark Hittinger) | |
| 22-Sep-05 RMS Fixed declarations (Sterling Garwood) | |
| 25-Aug-05 RMS Fixed DIVS overflow cases | |
| 29-Nov-03 CEO Corrected POPJ and Bit operations bugs | |
| 26-Nov-03 CEO Added FPU and PIT devices | |
| 20-Feb-03 CEO Corrected several MMPU and CIS bugs | |
| 28-Jan-02 RMS Cleaned up compiler warnings | |
| 30-Nov-01 RMS Added extended SET/SHOW support | |
| 01-Jun-01 RMS Added second terminal, plotter support | |
| 26-Apr-01 RMS Added device enable/disable support | |
| The register state for the Eclipse CPU is basically the same as | |
| the NOVA's: | |
| AC[0:3]<0:15> general registers | |
| C carry flag | |
| PC<0:14> program counter | |
| Eclipses with Folating Point Units added these registers: | |
| FPAC[0:3]<0:63> Floating Point Accumulators | |
| FPSR Floating Point Status Register | |
| In addition, certain low-memory locations are reserved for special | |
| purposes: | |
| 0: I/O Return Address (from an interrupt) | |
| 1: I/O (Interrupt) handler address | |
| 2: System Call handler address (used by SYC instruction) | |
| 3: Protection Fault handler address | |
| 4: VECTOR stack pointer (VCT Instruction) | |
| 5: Current Interrupt Priority mask | |
| 6: VECTOR stack limit (VCT instruction) | |
| 7: VECTOR stack fault address (VCT again) | |
| 10: Block Pointer (later models only) | |
| 11: Emulation Trap Handler address (microeclipse only) | |
| 20-27: Auto-increment locations (not on microeclipse) | |
| 30-37: Auto-decrement locations (not on microeclipse) | |
| 40: Stack pointer | |
| 41: Frame Pointer | |
| 42: Stack Limit | |
| 43: Stack fault address | |
| 44: XOP Origin address | |
| 45: Floating point fault address | |
| 46: Commercial fault address (not on microeclipse) | |
| 47: Reserved, do not use. | |
| Note: While all eclipses share most of the "standard" features, | |
| some models added a few quirks and wrinkles, and other models | |
| dropped some features or modified others. Most DG software | |
| is written for a "standard" Eclipse, and avoids these problem | |
| areas. A general overview: | |
| [subject to major changes as info becomes available!] | |
| Early (e.g. S/100, S/200, C/300) [Front Panel machines] | |
| The first Eclipses had the basic MAP, but certain parts | |
| were kluged, and these were fixed in later MAP designs. | |
| The original mapping hardware was termed MAP for Memory | |
| Allocate and Protection. The later design was termed | |
| MMPU for Memory Mapping and Protection Unit. While | |
| similar in design, the two units are not compatible. | |
| Also, the C version (C for Commercial) of these early | |
| CPUs had a feature called "Commercial Instruction Set" | |
| which contained character manipulation, translation | |
| between commercial-format numeric data and FPU formats, | |
| and an elaborate EDIT instruction. Later models kept | |
| only the character manipulation part of this and called | |
| the feature the "Character Instruction Set", leading to | |
| confusion because the initials of both are CIS. ARDOS | |
| is the only DG operating system to support the older | |
| MAP. ZRDOS uses the MMPU, and AOS supports only MMPU. | |
| Middle (e.g. S/130, C/150, S/230, C/330) [Front Panel] | |
| These are close to a "Standard". They have the newer, | |
| fixed MMPU. Support for the PIT (Programmed Interval | |
| Timer. The Commercial (not character) instruction set | |
| and FPU are optional. (CIS standard on C models) | |
| Late (C/350, M/600: [Panel]; S/140, S/280 [Virtual Console]) | |
| All features of the Middle period are included, plus: | |
| These late Eclipses added a few MMPU wrinkles all their | |
| own, included support for user maps C and D. Character | |
| instruction set is standard, FPU optional. Also, support | |
| for the BMC device. | |
| MicroEclipse-based (S/20, S/120, Desktops) [Virtual cons.] | |
| All features of the Late period, in general, plus: | |
| Microeclipses dropped support for the auto increment | |
| and decrement locations at 20-37. They also added | |
| support for invalid instruction traps thru location 11. | |
| The Desktops have an interface to the "Attached Processor", | |
| an 8086, at device code 6. Also, some new CPU device | |
| features to read states info. The Character Instruction | |
| set and FPU are standard on all models. | |
| The Eclipse instruction set is an elaboration of the NOVA's. The basic | |
| NOVA set is implemented in it's entireity, plus many new Eclipse | |
| instructions are added. Since in theory every possible 16-bit | |
| combination is a NOVA instruction, the Eclipse commands are carved | |
| out of the NOVA set by using the Operate format with the no-load bit | |
| set to 1 and the skip bits set to 000. Since this combination is | |
| in effect a no-op on the NOVA, it was rarely or never used. The | |
| other bits are used to form Eclipse instructions, which have no | |
| other common format. To see the instructions, refer to the Eclipse | |
| section of the instruction decode logic in sim_instr() below. All | |
| Eclipse instructions are checked first, so in case of conflict in | |
| bit patterns, the Eclipse one is executed over the corresponding | |
| NOVA pattern. A bizarre exception is LEF mode...which implements | |
| an instruction called Load Effective Address by taking over the | |
| Nova I/O format when the LEF mode bit is set and the processor is | |
| executing in mapped mode. | |
| The following discussion talks about NOVA instructions which are | |
| Eclipse instructions also. | |
| The NOVA has three instruction formats: memory reference, I/O transfer, | |
| and operate. The memory reference format is: | |
| 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | |
| +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | |
| | 0| op | AC |in| mode| displacement | memory reference | |
| +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | |
| <0:4> mnemonic action | |
| 00000 JMP PC = MA | |
| 00001 JMS AC3 = PC, PC = MA | |
| 00010 ISZ M[MA] = M[MA] + 1, skip if M[MA] == 0 | |
| 00011 DSZ M[MA] = M[MA] - 1, skip if M[MA] == 0 | |
| 001'n LDA ACn = M[MA] | |
| 010'n STA M[MA] = ACn | |
| <5:7> mode action | |
| 000 page zero direct MA = zext (IR<8:15>) | |
| 001 PC relative direct MA = PC + sext (IR<8:15>) | |
| 010 AC2 relative direct MA = AC2 + sext (IR<8:15>) | |
| 011 AC3 relative direct MA = AC3 + sext (IR<8:15>) | |
| 100 page zero indirect MA = M[zext (IR<8:15>)] | |
| 101 PC relative dinirect MA = M[PC + sext (IR<8:15>)] | |
| 110 AC2 relative indirect MA = M[AC2 + sext (IR<8:15>)] | |
| 111 AC3 relative indirect MA = M[AC3 + sext (IR<8:15>)] | |
| Memory reference instructions can access an address space of 32K words. | |
| An instruction can directly reference the first 256 words of memory | |
| (called page zero), as well as 256 words relative to the PC, AC2, or | |
| AC3; it can indirectly access all 32K words. If an indirect address | |
| is in locations 00020-00027, the indirect address is incremented and | |
| rewritten to memory before use; if in 00030-00037, decremented and | |
| rewritten. | |
| The I/O transfer format is: | |
| 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | |
| +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | |
| | 0 1 1| AC | opcode |pulse| device | I/O transfer | |
| +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | |
| The IOT instruction sends the opcode, pulse, and specified AC to the | |
| specified I/O device. The device may accept data, provide data, | |
| initiate or cancel operations, or skip on status. | |
| The operate format is: | |
| 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | |
| +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | |
| | 1|srcAC|dstAC| opcode |shift|carry|nl| skip | operate | |
| +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | |
| \______/ \___/ \___/ | | | | | |
| | | | | | | +--- reverse skip sense | |
| | | | | | +--- skip if C == 0 | |
| | | | | +--- skip if result == 0 | |
| | | | +--- don't load result | |
| | | +--- carry in (load as is, | |
| | | set to Zero, | |
| | | set to One, | |
| | | load Complement) | |
| | +--- shift (none, | |
| | left one, | |
| | right one, | |
| | byte swap) | |
| +--- operation (complement, | |
| negate, | |
| move, | |
| increment, | |
| add complement, | |
| subtract, | |
| add, | |
| and) | |
| The operate instruction can be microprogrammed to perform operations | |
| on the source and destination AC's and the Carry flag. | |
| This routine is the instruction decode routine for the NOVA. | |
| It is called from the simulator control program to execute | |
| instructions in simulated memory, starting at the simulated PC. | |
| It runs until 'reason' is set non-zero. | |
| General notes: | |
| 1. Reasons to stop. The simulator can be stopped by: | |
| HALT instruction | |
| breakpoint encountered | |
| infinite indirection loop | |
| unknown I/O device and STOP_DEV flag set | |
| I/O error in I/O simulator | |
| 2. Interrupts. Interrupts are maintained by four parallel variables: | |
| dev_done device done flags | |
| dev_disable device interrupt disable flags | |
| dev_busy device busy flags | |
| int_req interrupt requests | |
| In addition, int_req contains the interrupt enable and ION pending | |
| flags. If ION and ION pending are set, and at least one interrupt | |
| request is pending, then an interrupt occurs. Note that the 16b PIO | |
| mask must be mapped to the simulator's device bit mapping. | |
| 3. Non-existent memory. On the NOVA, reads to non-existent memory | |
| return zero, and writes are ignored. In the simulator, the | |
| largest possible memory is instantiated and initialized to zero. | |
| Thus, only writes need be checked against actual memory size. | |
| 4. Adding I/O devices. These modules must be modified: | |
| eclipse_defs.h add interrupt request definition | |
| eclipse_cpu.c add IOT mask, PI mask, and routine to dev_table | |
| eclipse_sys.c add pointer to data structures to sim_devices | |
| */ | |
| /*--------------------------------------------------------------------------- | |
| ** ECLIPSE Debugging Facilities | |
| ** | |
| ** These options are designed to find hard-to-locate flaky bugs by | |
| ** providing special error checking and logging. | |
| ** | |
| ** All are controlled by depositing a value into the DEBUG register. | |
| ** A value of zero means no special debugging facilities are turned on. | |
| ** This is the default. Debugging invokes a performance hit! Use only | |
| ** when necessary. | |
| ** | |
| ** Debugging means logging information to a file, or to a buffer in | |
| ** memory from whence it can be dumped to a file. | |
| ** | |
| ** 1XXXXX = Log all instructions executed to file "trace.log". | |
| ** **CAUTION**: This means the CPU will run SLOWLY and | |
| ** the resulting trace.log file will be HUGE. We're talking | |
| ** about a megabyte for each 5 seconds or less of wall clock | |
| ** time, depending on the speed of your CPU. Note: In this | |
| ** mode, interrupts are logged when they are received also. | |
| ** | |
| ** Note: when detailed logging is off, the last 4096 or so | |
| ** instructions executed are saved in a memory buffer, and | |
| ** when the sim stops, the "show" command can write this | |
| ** history information to the file "history.log". This only | |
| ** works if the DEBUG register is non-zero however, because | |
| ** of the performance hit even this recording makes. To | |
| ** dump history, enter the command "show cpu history", with | |
| ** the file "history" spelled correctly and lower case. | |
| ** | |
| ** XXXXDD = Log all I/O instructions to or from device number | |
| ** DD. Log is written to "trace.log", regardless of the | |
| ** setting of the instruction trace flag (1XXXXX). If both | |
| ** are on, the device traces will be interpersed with the | |
| ** instruction traces -- very useful sometimes. | |
| ** | |
| ** XXX1DD = Device Break. Does a breakpoint in any I/O to | |
| ** device DD. Useful, say when a diagnostic gives an | |
| ** error message - a device break on 11 (TTO) will stop | |
| ** as soon as the error message appears, making the | |
| ** trace log much shorter to track back on. | |
| ** | |
| ** X4XXXX = When this bit is on, the sim will stop if it sees | |
| ** an invalid instruction. When DEBUG is zero, any such | |
| ** instruction is no-oped with no warning. When DEBUG is | |
| ** non-zero, but this bit is 0, a warning will be displayed | |
| ** but execution will continue. | |
| ** | |
| ** X2XXXX = LEF break. When A LEF instruction is executed in | |
| ** mapped user space, the sim does a breakpoint right after | |
| ** executing the instruction. | |
| ** | |
| ** Whenever the DEBUG register is non-zero, special error checking | |
| ** is enabled in the sim. This will stop the sim automatically | |
| ** when a likely error occurs, such as: | |
| ** | |
| ** 1. Any execution that reaches, or will reach, location 00000. | |
| ** 2. Any I/O to device 00 | |
| ** 3. An interrupt from device 00. | |
| ** 4. An invalid instruction (stop is optional) | |
| ** | |
| ** DCHAR Register: Whenever this is non-zero, a test is made on every | |
| ** character output to the TTO device (master console). If the character | |
| ** output to that device matches this register, the CPU will break. | |
| ** | |
| ** Of course, the standard BREAK register is available for breakpoints | |
| ** as in all the sims based on this standard. | |
| --------------------------------------------------------------------------*/ | |
| #include "nova_defs.h" | |
| #define UNIT_V_MICRO (UNIT_V_UF) /* Microeclipse? */ | |
| #define UNIT_V_17B (UNIT_V_UF) /* 17 bit MAP */ | |
| #define UNIT_V_UP (UNIT_V_UF) /* FPU Enabled */ | |
| #define UNIT_V_MSIZE (UNIT_V_UF+1) /* dummy mask */ | |
| #define UNIT_MICRO (1 << UNIT_V_MICRO) | |
| #define UNIT_17B (1 << UNIT_V_17B) | |
| #define UNIT_UP (1 << UNIT_V_UP) | |
| #define UNIT_MSIZE (1 << UNIT_V_MSIZE) | |
| uint16 M[MAXMEMSIZE] = { 0 }; /* memory */ | |
| int32 AC[4] = { 0 }; /* accumulators */ | |
| int32 C = 0; /* carry flag */ | |
| int32 saved_PC = 0; /* program counter */ | |
| int32 SR = 0; /* switch register */ | |
| int32 dev_done = 0; /* device done flags */ | |
| int32 dev_busy = 0; /* device busy flags */ | |
| int32 dev_disable = 0; /* int disable flags */ | |
| int32 iot_enb = -1; /* IOT enables */ | |
| int32 int_req = 0; /* interrupt requests */ | |
| int32 pimask = 0; /* priority int mask */ | |
| int32 pwr_low = 0; /* power fail flag */ | |
| int32 ind_max = 15; /* iadr nest limit */ | |
| int32 stop_dev = 0; /* stop on ill dev */ | |
| int32 old_PC = 0; /* previous PC */ | |
| int32 model = 140; /* Model of Eclipse */ | |
| int32 speed = 0; /* Delay for each instruction */ | |
| int32 XCT_mode = 0; /* 1 if XCT mode */ | |
| int32 XCT_inst = 0; /* XCT instruction */ | |
| int32 PPC = -1; | |
| int32 AMASK = 077777; | |
| struct ndev dev_table[64]; /* dispatch table */ | |
| /* Instruction history buffer */ | |
| #define HISTMAX 4096 | |
| int32 hnext = 0; /* # of current entry */ | |
| int32 hwrap = 0; /* 1 if wrapped */ | |
| int32 hmax = HISTMAX; /* Maximum entries b4 wrap */ | |
| uint16 hpc[HISTMAX]; | |
| uint16 hinst[HISTMAX]; | |
| uint16 hinst2[HISTMAX]; | |
| uint16 hac0[HISTMAX]; | |
| uint16 hac1[HISTMAX]; | |
| uint16 hac2[HISTMAX]; | |
| uint16 hac3[HISTMAX]; | |
| unsigned short hflags[HISTMAX]; | |
| /* Flags: 0x01 - carry bit | |
| 0x02 - int enabled | |
| 0x04 - user map a | |
| 0x08 - user map b | |
| 0x10 - user map c | |
| 0x20 - user map d | |
| 0x40 - LEF mode was on | |
| 0x80 - this is an int, not an inst. | |
| hpc is return addr | |
| hinst is int_req | |
| hac0 is device | |
| hac1 is int addr | |
| */ | |
| /* the Eclipse MAP unit: This unit is standard in all Eclipse processors | |
| except for the "original" Eclipses, the S/100, S/200, and C/300. These | |
| use a different and more elaborate MMPU that is not compatible with | |
| the one simulated here. All subsequent Eclipses, from the S/130 on up | |
| to the last models S/280 and C/380 use the map simulated here, including | |
| the MicroEclipses. There are model-dependent quirks. That's why we | |
| have to MODEL register. | |
| The programming of the MMPU can be found in the LMP instruction, below, | |
| and in the instructions directed to DEV_MAP. | |
| There are two user maps, called A and B, and four data channel maps, | |
| A thru D. They can be enabled/disabled separately. Some models have | |
| two extra user maps, C and D. These are supported where apporpriate. | |
| */ | |
| #define PAGEMASK 01777 /* Largest physical page possible */ | |
| #define MAPMASK 0101777 /* Valid page bits in map */ | |
| #define INVALID 0101777 /* Mask indicating an invalid page */ | |
| int32 MapStat = 0; /* Map status register */ | |
| int32 Inhibit = 0; /* !0=inhibit interrupts : */ | |
| /* 1 = single cycle inhibit */ | |
| /* 2 = inhibit until indirection */ | |
| /* 3 = inhibit next instruction only */ | |
| int32 Enable = 0; /* User map to activate 1=A 2=B */ | |
| int32 Usermap = 0; /* Active Map? 0=supvr mode, 1=user A, 2 = user B */ | |
| int32 Map[8][32]; /* The actual MAPs 0=dch A, 1=A, 2=B, 3-5=dchB-D 6-7 User C-D */ | |
| int32 Map31 = 037; /* Map for block 31 in supervisor mode */ | |
| int32 SingleCycle = 0; /* Map one LDA/STA */ | |
| int32 Check = 0; /* Page Check Register */ | |
| int32 Fault = 0; /* Fault register */ | |
| int32 MapInit = 0; /* 1 when map initialized */ | |
| int32 MapIntMode = 0; /* Save of map user mode when int occurs */ | |
| /* The Eclipse Floating Point Unit: This unit is optional on all Eclipse | |
| models. | |
| */ | |
| int32 FPSR = 0; /* 32-bit FPU Status Register */ | |
| t_int64 FPAC[4] = { 0,0,0,0 }; /* 4 64-bit Accumulators */ | |
| int32 FPFault = 0; /* Save Fault State */ | |
| /* Definitions for internal floating point arithmetic */ | |
| typedef struct _SHORT_FLOAT { | |
| int32 short_fract; /* Fraction */ | |
| short expo; /* Exponent + 64 */ | |
| uint8 sign; /* Sign */ | |
| } SHORT_FLOAT; | |
| typedef struct _LONG_FLOAT { | |
| t_int64 long_fract; /* Fraction */ | |
| short expo; /* Exponent + 64 */ | |
| uint8 sign; /* Sign */ | |
| } LONG_FLOAT; | |
| LONG_FLOAT dfl,dfl2; /* Double Precision Work Fields */ | |
| SHORT_FLOAT sfl,sfl2; /* Single Precision Work Fields */ | |
| t_int64 tempfp, holdfp; /* Working area for FPAC */ | |
| int shift,m3; | |
| t_int64 lsfract; | |
| void get_sf(SHORT_FLOAT *fl, t_int64 *fpr); | |
| void store_sf(SHORT_FLOAT *fl, t_int64 *fpr); | |
| void get_lf(LONG_FLOAT *fl, t_int64 *fpr); | |
| void store_lf(LONG_FLOAT *fl, t_int64 *fpr); | |
| int normal_sf (SHORT_FLOAT *fl); | |
| int normal_lf (LONG_FLOAT *fl); | |
| int overflow_sf(SHORT_FLOAT *fl); | |
| int overflow_lf(LONG_FLOAT *fl); | |
| int underflow_sf(SHORT_FLOAT *fl); | |
| int underflow_lf(LONG_FLOAT *fl); | |
| int significance_sf(SHORT_FLOAT *fl); | |
| int significance_lf(LONG_FLOAT *fl); | |
| int add_sf(SHORT_FLOAT *fl, SHORT_FLOAT *add_f1, int normal); | |
| int add_lf(LONG_FLOAT *fl, LONG_FLOAT *add_fl, int normal); | |
| int mul_sf(SHORT_FLOAT *fl, SHORT_FLOAT *mul_fl); | |
| int mul_lf(LONG_FLOAT *fl, LONG_FLOAT *mul_fl); | |
| int div_sf(SHORT_FLOAT *fl, SHORT_FLOAT *div_fl); | |
| int div_lf(LONG_FLOAT *fl, LONG_FLOAT *div_fl); | |
| /* Special Debugging Info */ | |
| int32 Debug_Flags = 0; /* Debug register - selects debug features */ | |
| int32 Debug_Char = 0; /* Debug Character Register */ | |
| int32 Tron = 0; /* For trace files */ | |
| FILE *Trace; | |
| t_stat reason; | |
| extern int32 sim_int_char; | |
| extern uint32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ | |
| extern DEVICE *sim_devices[]; | |
| t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); | |
| t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw); | |
| t_stat cpu_reset (DEVICE *dptr); | |
| t_stat cpu_boot (int32 unitno, DEVICE *dptr); | |
| t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); | |
| t_stat Debug_Dump (UNIT *uptr, int32 val, char *cptr, void *desc); | |
| t_stat Dump_History (FILE *st, UNIT *uptr, int32 val, void *desc); | |
| t_stat map_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); | |
| t_stat map_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw); | |
| t_stat map_reset (DEVICE *dptr); | |
| t_stat map_svc (UNIT *uptr); | |
| t_stat fpu_svc (UNIT *uptr); | |
| int32 GetMap(int32 addr); | |
| int32 PutMap(int32 addr, int32 data); | |
| int32 Debug_Entry(int32 PC, int32 inst, int32 inst2, int32 AC0, int32 AC1, int32 AC2, int32 AC3, int32 flags); | |
| t_stat build_devtab (void); | |
| extern t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, | |
| UNIT *uptr, int32 sw); | |
| /* CPU data structures | |
| cpu_dev CPU device descriptor | |
| cpu_unit CPU unit descriptor | |
| cpu_reg CPU register list | |
| cpu_mod CPU modifiers list | |
| */ | |
| UNIT cpu_unit = { UDATA (NULL, UNIT_FIX + UNIT_BINK, MAXMEMSIZE) }; | |
| REG cpu_reg[] = { | |
| { ORDATA (PC, saved_PC, 15) }, | |
| { ORDATA (AC0, AC[0], 16) }, | |
| { ORDATA (AC1, AC[1], 16) }, | |
| { ORDATA (AC2, AC[2], 16) }, | |
| { ORDATA (AC3, AC[3], 16) }, | |
| { FLDATA (C, C, 16) }, | |
| { ORDATA (SR, SR, 16) }, | |
| { ORDATA (PI, pimask, 16) }, | |
| { FLDATA (ION, int_req, INT_V_ION) }, | |
| { FLDATA (ION_DELAY, int_req, INT_V_NO_ION_PENDING) }, | |
| { FLDATA (PWR, pwr_low, 0) }, | |
| { ORDATA (INT, int_req, INT_V_ION+1), REG_RO }, | |
| { ORDATA (BUSY, dev_busy, INT_V_ION+1), REG_RO }, | |
| { ORDATA (DONE, dev_done, INT_V_ION+1), REG_RO }, | |
| { ORDATA (DISABLE, dev_disable, INT_V_ION+1), REG_RO }, | |
| { FLDATA (STOP_DEV, stop_dev, 0) }, | |
| { DRDATA (INDMAX, ind_max, 16), REG_NZ + PV_LEFT }, | |
| { ORDATA (DEBUG, Debug_Flags, 16) }, | |
| { ORDATA (DCHAR, Debug_Char, 16) }, | |
| { DRDATA (MODEL, model, 16) }, | |
| { DRDATA (SPEED, speed, 16) }, | |
| { ORDATA (WRU, sim_int_char, 8) }, | |
| { NULL } | |
| }; | |
| MTAB cpu_mod[] = { | |
| { UNIT_MICRO, UNIT_MICRO, "MICRO", "MICRO", NULL }, | |
| { UNIT_MICRO, 0, "STD", "STD", NULL }, | |
| { UNIT_MSIZE, 4096, NULL, "4K", &cpu_set_size }, | |
| { UNIT_MSIZE, 8192, NULL, "8K", &cpu_set_size }, | |
| { UNIT_MSIZE, 12288, NULL, "12K", &cpu_set_size }, | |
| { UNIT_MSIZE, 16384, NULL, "16K", &cpu_set_size }, | |
| { UNIT_MSIZE, 20480, NULL, "20K", &cpu_set_size }, | |
| { UNIT_MSIZE, 24576, NULL, "24K", &cpu_set_size }, | |
| { UNIT_MSIZE, 28672, NULL, "28K", &cpu_set_size }, | |
| { UNIT_MSIZE, 32768, NULL, "32K", &cpu_set_size }, | |
| { UNIT_MSIZE, 65536, NULL, "64K", &cpu_set_size }, | |
| { UNIT_MSIZE, 131072, NULL, "128K", &cpu_set_size }, | |
| { UNIT_MSIZE, 262144, NULL, "256K", &cpu_set_size }, | |
| { UNIT_MSIZE, 524288, NULL, "512K", &cpu_set_size }, | |
| { UNIT_MSIZE, 1048576, NULL, "1024K", &cpu_set_size }, | |
| { UNIT_MSIZE, 0, NULL, "DUMP", &Debug_Dump }, | |
| { MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "HISTORY", NULL, | |
| NULL, &Dump_History }, | |
| { 0 } | |
| }; | |
| DEVICE cpu_dev = { | |
| "CPU", &cpu_unit, cpu_reg, cpu_mod, | |
| 1, 8, 17, 1, 8, 16, | |
| &cpu_ex, &cpu_dep, &cpu_reset, | |
| &cpu_boot, NULL, NULL | |
| }; | |
| /* MAP data structures | |
| map_dev MAP device descriptor | |
| map_unit MAP unit descriptor | |
| map_reg MAP register list | |
| map_mod MAP modifiers list | |
| */ | |
| UNIT map_unit = { UDATA (&map_svc, UNIT_17B, MAXMEMSIZE) }; | |
| REG map_reg[] = { | |
| { ORDATA (STATUS, MapStat, 16) }, | |
| { ORDATA (ENABLE, Enable, 16) }, | |
| { ORDATA (IINHIB, Inhibit, 16) }, | |
| { ORDATA (ACTIVE, Usermap, 16) }, | |
| { ORDATA (MAP31, Map31, 16) }, | |
| { ORDATA (CYCLE, SingleCycle, 16) }, | |
| { ORDATA (CHECK, Check, 16) }, | |
| { ORDATA (FAULT, Fault, 16) }, | |
| { NULL } | |
| }; | |
| MTAB map_mod[] = { | |
| { UNIT_17B, UNIT_17B, "17bit", "17B", NULL }, | |
| { UNIT_17B, 0, "19bit", "19B", NULL }, | |
| { 0 } | |
| }; | |
| DEVICE map_dev = { | |
| "MAP", &map_unit, map_reg, map_mod, | |
| 1, 8, 17, 1, 8, 16, | |
| &map_ex, &map_dep, NULL, | |
| NULL, NULL, NULL | |
| }; | |
| /* FPU data structures | |
| fpu_dev MAP device descriptor | |
| fpu_unit MAP unit descriptor | |
| fpu_reg MAP register list | |
| fpu_mod MAP modifiers list | |
| */ | |
| UNIT fpu_unit = { UDATA (&fpu_svc, UNIT_UP, MAXMEMSIZE) }; | |
| REG fpu_reg[] = { | |
| { ORDATA (STATUS, FPSR, 32) }, | |
| { ORDATA (FPAC0, FPAC[0], 64) }, | |
| { ORDATA (FPAC1, FPAC[1], 64) }, | |
| { ORDATA (FPAC2, FPAC[2], 64) }, | |
| { ORDATA (FPAC3, FPAC[3], 64) }, | |
| { ORDATA (FAULT, FPFault, 32) }, | |
| { NULL } | |
| }; | |
| MTAB fpu_mod[] = { | |
| { UNIT_UP, UNIT_UP, "Enabled (UP)", "UP", NULL }, | |
| { UNIT_UP, 0, "Disabled (DOWN)", "DOWN", NULL }, | |
| { 0 } | |
| }; | |
| DEVICE fpu_dev = { | |
| "FPU", &fpu_unit, fpu_reg, fpu_mod, | |
| 1, 16, 17, 1, 16, 16, | |
| NULL, NULL, NULL, | |
| NULL, NULL, NULL | |
| }; | |
| /* ---- Programmable Interval Timer Device ----------- */ | |
| int32 pit_time = 100; | |
| int32 pit_tps = 10000; /* ticks per sec */ | |
| int32 pit_adj = 20; /* tmxr adjust */ | |
| int32 pit_poll = 16000; /* tmxr poll */ | |
| int32 pit_initial = 0; /* initial counter reg */ | |
| int32 pit_counter = 0; /* Counter */ | |
| int32 pit_flag = 0; /* Initial setting flag */ | |
| int32 pit (int32 pulse, int32 code, int32 AC); | |
| t_stat pit_svc (UNIT *uptr); | |
| t_stat pit_reset (DEVICE *dptr); | |
| /* PIT data structures | |
| pit_dev device descriptor | |
| pit_unit unit descriptor | |
| pit_reg register list | |
| */ | |
| DIB pit_dib = { DEV_PIT, INT_PIT, PI_PIT, &pit }; | |
| UNIT pit_unit = { UDATA (&pit_svc, 0, 0) }; | |
| REG pit_reg[] = { | |
| { ORDATA (INIT, pit_initial, 16) }, | |
| { ORDATA (COUNT, pit_counter, 16) }, | |
| { FLDATA (BUSY, dev_busy, INT_V_PIT) }, | |
| { FLDATA (DONE, dev_done, INT_V_PIT) }, | |
| { FLDATA (DISABLE, dev_disable, INT_V_PIT) }, | |
| { FLDATA (INT, int_req, INT_V_PIT) }, | |
| { DRDATA (TIME0, pit_time, 24), REG_NZ + PV_LEFT }, | |
| { NULL } | |
| }; | |
| DEVICE pit_dev = { | |
| "PIT", &pit_unit, pit_reg, NULL, | |
| 1, 0, 0, 0, 0, 0, | |
| NULL, NULL, &pit_reset, | |
| NULL, NULL, NULL, | |
| &pit_dib, 0 | |
| }; | |
| t_stat sim_instr (void) | |
| { | |
| extern int32 sim_interval; | |
| register int32 PC, IR, i, t, MA, j, k, tac; | |
| register uint32 mddata, uAC0, uAC1, uAC2, uAC3; | |
| int16 sAC0, sAC1, sAC2; | |
| int32 sddata, mi1, mi2, fpnum32; | |
| t_int64 fpnum, expon; | |
| t_value simeval[20]; | |
| void mask_out (int32 mask); | |
| /* char debstr[128]; */ | |
| /* char debadd[64]; */ | |
| char debmap[4], debion[4]; | |
| int debcar, iodev, iodata, debflags; | |
| int32 DisMap, debpc; | |
| /* int32 sp, sl; */ | |
| int cmdptr, cmsptr, cmopt, cmptr; | |
| int16 cmslen, cmdlen; | |
| int tabaddr, tabptr; | |
| int32 effective(int32 PC, int32 index, int32 disp); | |
| int32 indirect(int32 d); | |
| int32 LEFmode(int32 PC, int32 index, int32 disp, int32 indirect); | |
| int32 LoadMap(int32 w); | |
| int32 Bytepointer(int32 PC, int32 index); | |
| int32 unimp(int32 PC); | |
| int32 pushrtn(int32 pc); | |
| /* Restore register state */ | |
| if (build_devtab () != SCPE_OK) return SCPE_IERR; /* build dispatch */ | |
| PC = saved_PC & AMASK; /* load local PC */ | |
| C = C & 0200000; | |
| mask_out (pimask); /* reset int system */ | |
| reason = 0; | |
| if (MapInit == 0) { | |
| MapInit = 1; | |
| for (mi1 = 0; mi1 < 6; mi1++) { /* Initialize MAPs */ | |
| for (mi2 = 0; mi2 < 32; mi2++) { | |
| Map[mi1][mi2] = mi2; | |
| } | |
| } | |
| } | |
| /* Main instruction fetch/decode loop */ | |
| while (reason == 0) { /* loop until halted */ | |
| if (sim_interval <= 0) { /* check clock queue */ | |
| if ((reason = sim_process_event ())) | |
| break; | |
| } | |
| //if (speed > 0) for (i = 0; i < speed; i++) { j = 0; } | |
| if (Fault) { /* Check MAP fault */ | |
| Usermap = 0; /* YES: shutdown map */ | |
| MapStat &= ~01; /* Disable MMPU */ | |
| if (Fault & 0100000/*!!!*/) /* If it was validity, or WP */ | |
| MapStat &= ~0170; /* Reset other checkbits */ | |
| MapStat |= Fault & 077777; /* Put in fault code */ | |
| Fault = 0; /* Reset fault code */ | |
| t = (GetMap(040) + 1) & AMASK; /* Push rtn block */ | |
| PutMap(t, AC[0]); | |
| t++; | |
| PutMap(t, AC[1]); | |
| t++; | |
| PutMap(t, AC[2]); | |
| t++; | |
| PutMap(t, AC[3]); | |
| t++; | |
| PutMap(t, (PC & AMASK)); | |
| if (C) PutMap(t, (GetMap(t) | 0100000)); | |
| PutMap(040, t); | |
| int_req = int_req & ~INT_ION; /* Disable interrupts */ | |
| PC = indirect(M[003]); /* JMP to loc 3 */ | |
| continue; | |
| } | |
| if (FPSR & 0xF8000000) { /* FPU Fault? */ | |
| if (!(FPSR & 0x78000000)) { /* If error bit on ... */ | |
| FPSR &= 0x00FFFFFF; /* ...but no error, clear it */ | |
| } else { /* ELSE a real error: */ | |
| FPSR |= 0x80000000; /* Turn error bit on */ | |
| if (FPSR & 0x04000000) { /* Trap enabled ? */ | |
| FPFault = FPSR; /* Save fault */ | |
| FPSR &= 0xFBFFFFFF; /* Clear Trap Enable */ | |
| } | |
| } | |
| } | |
| if (int_req > INT_PENDING && !Inhibit) { /* interrupt? */ | |
| int_req = int_req & ~INT_ION; | |
| MapIntMode = MapStat; /* Save Status as it was */ | |
| Usermap = 0; /* Inhibit MAP */ | |
| MapStat &= ~1; /* Disable user map */ | |
| if (XCT_mode) { | |
| M[0] = PC - 1; /* If XCT mode rtn to XCT */ | |
| XCT_mode = 0; /* turn off mode */ | |
| } else { | |
| M[0] = PC; /* Save Return Address */ | |
| } | |
| old_PC = PC; | |
| MA = M[1]; | |
| for (i = 0; i < ind_max * 2; i++) { /* count indirects */ | |
| if ((MA & 0100000) == 0) break; | |
| if ((MA & 077770) == 020) | |
| MA = (M[MA & AMASK] = (M[MA & AMASK] + 1) & 0177777); | |
| else if ((MA & 077770) == 030) | |
| MA = (M[MA & AMASK] = (M[MA & AMASK] - 1) & 0177777); | |
| else MA = M[MA & AMASK]; | |
| } | |
| if (i >= (ind_max-1)) { | |
| if ((MapStat & 010) && Usermap) { | |
| Fault = 04000; /* Map fault if IND prot */ | |
| continue; | |
| } else { | |
| reason = STOP_IND_INT; | |
| break; | |
| } | |
| } | |
| if (Debug_Flags) { | |
| iodev = 0; | |
| iodata = int_req & (-int_req); | |
| for (i = DEV_LOW; i <= DEV_HIGH; i++) { | |
| if (iodata & dev_table[i].mask) { | |
| iodev = i; | |
| break; | |
| } | |
| } | |
| if (iodev == 0) { | |
| printf("\n<<Interrupt to device 0!>>\n"); | |
| reason = STOP_IBKPT; | |
| } | |
| if (Debug_Flags & 0100000) { | |
| fprintf(Trace, "--------- Interrupt %o (%o) to %6o ---------\n", int_req, iodev, MA); | |
| } else { | |
| Debug_Entry(PC, int_req, 0, iodev, MA, 0, 0, 0x80); | |
| } | |
| } | |
| PC = MA; | |
| } /* end interrupt */ | |
| if (Inhibit != 0) { /* Handle 1-instruction inhibit sequence */ | |
| if (Inhibit == 3) /* Used by SYC instruction */ | |
| Inhibit = 4; | |
| if (Inhibit == 4) | |
| Inhibit = 0; | |
| } | |
| if (sim_brk_summ && sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */ | |
| reason = STOP_IBKPT; /* stop simulation */ | |
| break; | |
| } | |
| if ((PC < 1 || PC > 077777) && Debug_Flags) { | |
| if (PPC != -1) { /* Don't break on 1st instruction */ | |
| printf("\n<<Invalid PC=%o from %o>>\n\r", PC, PPC); | |
| reason = STOP_IBKPT; | |
| break; | |
| } | |
| } | |
| PPC = PC; | |
| if (Debug_Flags) { | |
| if (!Tron) { | |
| Tron = 1; | |
| Trace = fopen("trace.log", "w"); | |
| } | |
| strcpy(debmap, " "); | |
| strcpy(debion, " "); | |
| debcar = 0; | |
| if (C) debcar = 1; | |
| if (Usermap == 1) strcpy(debmap, "A"); | |
| if (Usermap == 2) strcpy(debmap, "B"); | |
| if (Usermap == 5) strcpy(debmap, "C"); | |
| if (Usermap == 6) strcpy(debmap, "D"); | |
| if (int_req & INT_ION) strcpy(debion, "I"); | |
| if (XCT_mode == 0) { | |
| debpc = PC; | |
| simeval[0] = GetMap(PC); | |
| simeval[1] = GetMap(PC+1); | |
| } else { | |
| debpc = 0177777; | |
| simeval[0] = XCT_inst; | |
| simeval[1] = 0; | |
| } | |
| if (Debug_Flags & 0100000) { | |
| fprintf(Trace, "%s%s%06o acs: %06o %06o %06o %06o %01o ", | |
| debion, debmap, debpc, AC[0], AC[1], AC[2], AC[3], debcar); | |
| fprint_sym (Trace, debpc, simeval, NULL, SWMASK('M')); | |
| fprintf(Trace, "\n"); | |
| } else { | |
| debflags = 0; | |
| if (C) debflags |= 0x01; | |
| if (int_req & INT_ION) debflags |= 0x02; | |
| if (Usermap == 1) debflags |= 0x04; | |
| if (Usermap == 2) debflags |= 0x08; | |
| if (Usermap == 3) debflags |= 0x10; | |
| if (Usermap == 4) debflags |= 0x20; | |
| Debug_Entry(debpc, (int32)simeval[0], (int32)simeval[1], AC[0], AC[1], AC[2], AC[3], debflags); | |
| } | |
| } | |
| if (XCT_mode == 0) { /* XCT mode? */ | |
| IR = GetMap(PC); /* No: fetch instr */ | |
| if (Fault) continue; /* Give up if fault */ | |
| PC = (PC + 1) & AMASK; /* bump PC */ | |
| } else { | |
| IR = XCT_inst; /* Yes: Get inst to XCT */ | |
| XCT_mode = 0; /* Go back to normal mode */ | |
| } | |
| int_req = int_req | INT_NO_ION_PENDING; /* clear ION delay */ | |
| sim_interval = sim_interval - 1; | |
| t = IR >> 11; /* prepare to decode */ | |
| /* ---------------- BEGIN Eclipse modification --------------------- */ | |
| /* Eclipse instruction set. These instructions are checked for | |
| before any of the NOVA ones. Eclipse instructions do not | |
| correspond to any patterns, other than bit 0 being 1 and | |
| the last 4 bits are 1000. Words which are not Eclipse | |
| instructions will be interpreted as Nova instructions. */ | |
| /* Important Note: The order of the if statements is important. | |
| Frequently executed instructions should come first, to enhance | |
| the speed of the simulation. | |
| */ | |
| if ((IR & 0100017) == 0100010) { /* This pattern for all */ | |
| /* Eclipse instructions */ | |
| /****************************************************************/ | |
| /* This is the standard Eclipse instruction set */ | |
| /****************************************************************/ | |
| /* Byte operations */ | |
| if ((IR & 0103777) == 0102710) { /* LDB: Load Byte */ | |
| i = (IR >> 13) & 03; | |
| MA = (AC[i] >> 1) & AMASK; | |
| j = (IR >> 11) & 03; | |
| if (AC[i] & 01) { | |
| AC[j] = GetMap(MA) & 0377; | |
| } else { | |
| AC[j] = (GetMap(MA) >> 8) & 0377; | |
| } | |
| continue; | |
| } | |
| if ((IR & 0103777) == 0103010) { /* STB: Store Byte */ | |
| i = (IR >> 13) & 03; | |
| MA = (AC[i] >> 1); | |
| j = (IR >> 11) & 03; | |
| t = GetMap(MA); | |
| if (AC[i] & 01) { | |
| t &= 0177400; | |
| t |= (AC[j] & 0377); | |
| PutMap(MA, t); | |
| } else { | |
| t &= 0377; | |
| t |= (AC[j] & 0377) << 8; | |
| PutMap(MA, t); | |
| } | |
| continue; | |
| } | |
| /* Fixed-point arithmetic - loads & saves */ | |
| if ((IR & 0162377) == 0122070) { /* ELDA: Extended LDA */ | |
| i = (IR >> 11) & 3; | |
| t = GetMap(PC); | |
| if (SingleCycle) Usermap = SingleCycle; | |
| AC[i] = GetMap(effective(PC, (IR >> 8) & 3, t)); | |
| if (SingleCycle) { | |
| Usermap = SingleCycle = 0; | |
| if (Inhibit == 1) Inhibit = 3; | |
| MapStat |= 02000; | |
| MapStat &= 0177776; | |
| } | |
| PC = (PC + 1) & AMASK; | |
| continue; | |
| } | |
| if ((IR & 0162377) == 0142070) { /* ESTA: Extended STA */ | |
| i = (IR >> 11) & 3; | |
| t = GetMap(PC); | |
| if (SingleCycle) Usermap = SingleCycle; | |
| PutMap((effective(PC, (IR >> 8) & 3, t)), AC[i]); | |
| if (SingleCycle) { | |
| Usermap = SingleCycle = 0; | |
| if (Inhibit == 1) Inhibit = 3; | |
| MapStat |= 02000; | |
| MapStat &= 0177776; | |
| } | |
| PC = (PC + 1) & AMASK; | |
| continue; | |
| } | |
| if ((IR & 0103777) == 0100010) { /* ADI: Add Immediate */ | |
| t = (IR >> 11) & 3; | |
| AC[t] = (AC[t] + ((IR >> 13) & 3) + 1) & 0xffff; | |
| continue; | |
| } | |
| if ((IR & 0103777) == 0100110) { /* SBI: Subtract Immediate */ | |
| t = (IR >> 11) & 3; | |
| AC[t] = (AC[t] - (((IR >> 13) & 3) + 1)) & 0xffff; | |
| continue; | |
| } | |
| if ((IR & 0163777) == 0163770) { /* ADDI: Extended Add Immed. */ | |
| t = (IR >> 11) & 3; | |
| i = GetMap(PC); | |
| PC = (PC + 1) & AMASK; | |
| AC[t] = (AC[t] + i) & 0xffff; | |
| continue; | |
| } | |
| if ((IR & 0103777) == 0100710) { /* XCH: Exchange Accumulators */ | |
| t = AC[(IR >> 11) & 3]; | |
| AC[(IR >> 11) & 3] = AC[(IR >> 13) & 3]; | |
| AC[(IR >> 13) & 3] = t; | |
| continue; | |
| } | |
| if ((IR & 0162377) == 0162070) { /* ELEF: Load Effective Addr */ | |
| t = GetMap(PC); | |
| AC[(IR >> 11) & 3] = effective(PC, (IR >> 8) & 3, t); | |
| PC = (PC + 1) & AMASK; | |
| continue; | |
| } | |
| /* Logical operations */ | |
| if ((IR & 0163777) == 0143770) { /* ANDI: And Immediate */ | |
| AC[(IR >> 11) & 3] &= GetMap(PC); | |
| PC = (PC + 1) & AMASK; | |
| continue; | |
| } | |
| if ((IR & 0163777) == 0103770) { /* IORI: Inclusive Or Immed */ | |
| AC[(IR >> 11) & 3] |= GetMap(PC); | |
| PC = (PC + 1) & AMASK; | |
| continue; | |
| } | |
| if ((IR & 0163777) == 0123770) { /* XORI: Exclusive Or Immed */ | |
| AC[(IR >> 11) & 3] ^= GetMap(PC); | |
| PC = (PC + 1) & AMASK; | |
| continue; | |
| } | |
| if ((IR & 0103777) == 0100410) { /* IOR: Inclusive Or */ | |
| AC[(IR >> 11) & 3] |= AC[(IR >> 13) & 3]; | |
| continue; | |
| } | |
| if ((IR & 0103777) == 0100510) { /* XOR: Exclusive Or */ | |
| AC[(IR >> 11) & 3] ^= AC[(IR >> 13) & 3]; | |
| continue; | |
| } | |
| if ((IR & 0103777) == 0100610) { /* ANC: And with complemented src */ | |
| AC[(IR >> 11) & 3] &= ~(AC[(IR >> 13) & 3]); | |
| continue; | |
| } | |
| /* Shift operations */ | |
| if ((IR & 0103777) == 0101210) { /* LSH: Logical Shift */ | |
| register int16 sh; | |
| sh = AC[(IR >> 13) & 3] & 0377; | |
| i = (IR >> 11) & 3; | |
| if (sh & 0200) { | |
| sh = ~sh + 1; | |
| AC[i] = AC[i] >> sh; | |
| } else { | |
| AC[i] = AC[i] << sh; | |
| } | |
| if (sh > 15) AC[i] = 0; | |
| AC[i] &= 0xffff; | |
| continue; | |
| } | |
| if ((IR & 0103777) == 0101310) { /* DLSH: Double logical shift */ | |
| register int16 sh; | |
| sh = AC[(IR >> 13) & 3] & 0377; | |
| i = (IR >> 11) & 3; | |
| uAC0 = AC[i] << 16; | |
| j = i + 1; | |
| if (j == 4) j = 0; | |
| uAC0 |= AC[j]; | |
| if (sh & 0200) { | |
| sh = (~sh + 1) & 0377; | |
| if (sh < 32) | |
| uAC0 = uAC0 >> sh; | |
| } else { | |
| if (sh < 32) | |
| uAC0 = uAC0 << sh; | |
| } | |
| if (sh > 31) uAC0 = 0; | |
| AC[i] = (uAC0 >> 16) & 0xffff; | |
| AC[j] = uAC0 & 0xffff; | |
| continue; | |
| } | |
| if ((IR & 0103777) == 0101410) { /* HXL: Hex shift left */ | |
| t = ((IR >> 13) & 3) + 1; | |
| i = (IR >> 11) & 3; | |
| AC[i] = AC[i] << (t * 4); | |
| AC[i] &= 0xffff; | |
| continue; | |
| } | |
| if ((IR & 0103777) == 0101510) { /* HXR: Hex shift right */ | |
| t = ((IR >> 13) & 3) + 1; | |
| i = (IR >> 11) & 3; | |
| AC[i] = AC[i] >> (t * 4); | |
| AC[i] &= 0xffff; | |
| continue; | |
| } | |
| if ((IR & 0103777) == 0101610) { /* DHXL: Double Hex shift left */ | |
| t = ((IR >> 13) & 3) + 1; | |
| i = (IR >> 11) & 3; | |
| j = i + 1; | |
| if (j == 4) j = 0; | |
| uAC0 = AC[i] << 16; | |
| uAC0 |= AC[j]; | |
| uAC0 = uAC0 << ((t * 4) & 0177); | |
| AC[i] = (uAC0 >> 16) & 0xffff; | |
| AC[j] = uAC0 & 0xffff; | |
| continue; | |
| } | |
| if ((IR & 0103777) == 0101710) { /* DHXR: Double Hex shift right */ | |
| t = ((IR >> 13) & 3) + 1; | |
| i = (IR >> 11) & 3; | |
| j = i + 1; | |
| if (j == 4) j = 0; | |
| uAC0 = AC[i] << 16; | |
| uAC0 |= AC[j]; | |
| uAC0 = uAC0 >> ((t * 4) & 0177); | |
| AC[i] = (uAC0 >> 16) & 0xffff; | |
| AC[j] = uAC0 & 0xffff; | |
| continue; | |
| } | |
| /* Bit operations */ | |
| if ((IR & 0103777) == 0102010) { /* BTO: Set bit to one */ | |
| i = (IR >> 11) & 3; | |
| j = (IR >> 13) & 3; | |
| if (i != j) { | |
| k = (AC[i] >> 4) & AMASK; | |
| if ((AC[j] + k) & 0100000) | |
| t = 1; | |
| //AOS MA = indirect(AC[j] + k); | |
| MA = (AC[j] + k) & AMASK; | |
| } else { | |
| MA = (AC[i] >> 4) & AMASK; | |
| } | |
| t = AC[i] & 017; | |
| t = GetMap(MA) | (0100000 >> t); | |
| PutMap(MA, t); | |
| continue; | |
| } | |
| if ((IR & 0103777) == 0102110) { /* BTZ: Set bit to zero */ | |
| i = (IR >> 11) & 3; | |
| j = (IR >> 13) & 3; | |
| if (i != j) { | |
| k = (AC[i] >> 4) & AMASK; | |
| if ((AC[j] + k) & 0100000) | |
| t = 1; | |
| //AOS MA = indirect(AC[j] + k); | |
| MA = (AC[j] + k) & AMASK; | |
| } else { | |
| MA = (AC[j] >> 4) & AMASK; | |
| } | |
| t = AC[i] & 017; | |
| t = GetMap(MA) & ~(0100000 >> t); | |
| PutMap(MA, t); | |
| continue; | |
| } | |
| if ((IR & 0103777) == 0102210) { /* SZB: Skip on zero bit */ | |
| i = (IR >> 11) & 3; | |
| j = (IR >> 13) & 3; | |
| if (i != j) { | |
| k = (AC[i] >> 4) & AMASK; | |
| if ((AC[j] + k) & 0100000) | |
| t = 1; | |
| MA = indirect(AC[j] + k); | |
| // MA = (AC[j] + k) & AMASK; | |
| } else { | |
| MA = (AC[i] >> 4) & AMASK; | |
| } | |
| t = GetMap(MA) << (AC[i] & 017); | |
| if (!(t & 0100000)) PC = (PC + 1) & AMASK; | |
| continue; | |
| } | |
| if ((IR & 0103777) == 0102770) { /* SNB: Skip on non-zero bit */ | |
| i = (IR >> 11) & 3; | |
| j = (IR >> 13) & 3; | |
| if (i != j) { | |
| k = (AC[i] >> 4) & AMASK; | |
| if ((AC[j] + k) & 0100000) | |
| t = 1; | |
| MA = indirect(AC[j] + k); | |
| // MA = (AC[j] + k) & AMASK; | |
| } else { | |
| MA = (AC[j] >> 4) & AMASK; | |
| } | |
| t = GetMap(MA) << (AC[i] & 017); | |
| if (t & 0100000) PC = (PC + 1) & AMASK; | |
| continue; | |
| } | |
| if ((IR & 0103777) == 0102310) { /* SZBO: skip on zero bit & set to 1 */ | |
| register int32 save; | |
| i = (IR >> 11) & 3; | |
| j = (IR >> 13) & 3; | |
| if (i != j) { | |
| k = (AC[i] >> 4) & AMASK; | |
| MA = indirect(AC[j] + k); | |
| // MA = (AC[j] + k) & AMASK; | |
| } else { | |
| MA = (AC[j] >> 4) & AMASK; | |
| } | |
| t = AC[i] & 017; | |
| save = GetMap(MA); | |
| t = save | (0100000 >> t); | |
| PutMap(MA, t); | |
| t = save << (AC[i] & 017); | |
| if ((t & 0100000) == 0) | |
| PC = (PC + 1) & AMASK; | |
| continue; | |
| } | |
| if ((IR & 0103777) == 0102410) { /* LOB: Locate lead bit */ | |
| register int32 a, r; | |
| register int16 b; | |
| a = AC[(IR >> 13) & 3] & 0xffff; | |
| for (i = 0; i < 16; i++) { | |
| if ((a << i) & 0100000) break; | |
| } | |
| r = (IR >> 11) & 3; | |
| b = AC[r]; | |
| b += i; | |
| AC[r] = b & 0177777; | |
| continue; | |
| } | |
| if ((IR & 0103777) == 0102510) { /* LRB: Locate & reset lead bit */ | |
| register int32 a, r; | |
| register int16 b; | |
| j = (IR >> 13) & 3; | |
| a = AC[j]; | |
| for (i = 0; i < 16; i++) { | |
| if ((a << i) & 0100000) break; | |
| } | |
| r = (IR >> 11) & 3; | |
| b = AC[r]; | |
| b += i; | |
| if (j != r) AC[r] = b & 0177777; | |
| AC[j] &= ~(0100000 >> i); | |
| AC[j] &= 0xffff; | |
| continue; | |
| } | |
| if ((IR & 0103777) == 0102610) { /* COB: Count bits */ | |
| register int32 a; | |
| register int16 b, c = 0; | |
| a = AC[(IR >> 13) & 3]; | |
| for (i = 0; i < 16; i++) { | |
| if ((a >> i) & 1) c++; | |
| } | |
| i = (IR >> 11) & 3; | |
| b = AC[i]; | |
| b += c; | |
| AC[i] = b & 0177777; | |
| continue; | |
| } | |
| /* Jump & similar operations */ | |
| if ((IR & 0176377) == 0102070) { /* EJMP: Extended JMP */ | |
| PC = effective(PC, (IR >> 8) & 3, GetMap(PC)); | |
| continue; | |
| } | |
| if ((IR & 0176377) == 0106070) { /* EJSR: Extended JMP to subr */ | |
| t = effective(PC, (IR >> 8) & 3, GetMap(PC)); | |
| AC[3] = (PC + 1) & AMASK; | |
| PC = t & AMASK; | |
| continue; | |
| } | |
| if ((IR & 0176377) == 0112070) { /* EISZ: Ext Inc & skip if 0 */ | |
| MA = effective(PC, (IR >> 8) & 3, GetMap(PC)); | |
| PutMap(MA, ((GetMap(MA) + 1) & 0xffff)); | |
| if (GetMap(MA) == 0) PC = (PC + 1) & AMASK; | |
| PC = (PC + 1) & AMASK; | |
| continue; | |
| } | |
| if ((IR & 0176377) == 0116070) { /* EDSZ: Ext Dec & skip if 0 */ | |
| MA = effective(PC, (IR >> 8) & 3, GetMap(PC)); | |
| PutMap(MA, ((GetMap(MA) - 1) & 0xffff)); | |
| if (GetMap(MA) == 0) PC = (PC + 1) & AMASK; | |
| PC = (PC + 1) & AMASK; | |
| continue; | |
| } | |
| if ((IR & 0103777) == 0101010) { /* SGT: Skip if ACS > ACD */ | |
| register int16 a1, d1; | |
| a1 = AC[(IR >> 13) & 3] & 0xffff; | |
| d1 = AC[(IR >> 11) & 3] & 0xffff; | |
| if (a1 > d1) | |
| PC = (PC + 1) & AMASK; | |
| continue; | |
| } | |
| if ((IR & 0103777) == 0101110) { /* SGE: Skip if ACS >= ACD */ | |
| register int16 a1, d1; | |
| a1 = AC[(IR >> 13) & 3] & 0xffff; | |
| d1 = AC[(IR >> 11) & 3] & 0xffff; | |
| if (a1 >= d1) | |
| PC = (PC + 1) & AMASK; | |
| continue; | |
| } | |
| if ((IR & 0103777) == 0102370) { /* CLM: Compare to limits */ | |
| register int32 s, d, MA; | |
| int16 H, L, ca; | |
| s = (IR >> 13) & 3; | |
| d = (IR >> 11) & 3; | |
| if (s == d) { | |
| L = GetMap(PC); | |
| PC++; | |
| H = GetMap(PC); | |
| PC++; | |
| } else { | |
| MA = AC[d] & AMASK; | |
| L = GetMap(MA); | |
| H = GetMap(MA + 1); | |
| } | |
| ca = AC[s]; | |
| if (ca >= L && ca <= H) PC = (PC + 1) & AMASK; | |
| continue; | |
| } | |
| if ((IR & 0163777) == 0123370) { /* XCT: Execute */ | |
| XCT_mode = 1; /* Set up to execute on next loop */ | |
| XCT_inst = AC[(IR >> 11) & 3]; | |
| continue; | |
| } | |
| /* Memory block operations */ | |
| if (IR == 0113710) { /* BAM: Block add & move */ | |
| register int32 w; | |
| t = AC[1]; | |
| if (t < 1 || t > 0100000) | |
| continue; | |
| i = indirect(AC[2]); | |
| j = indirect(AC[3]); | |
| while (t) { | |
| w = GetMap(i); | |
| PutMap(j, ((w + AC[0]) & 0xffff)); | |
| if (Fault) break; | |
| t--; | |
| i++; | |
| j++; | |
| i &= AMASK; | |
| j &= AMASK; | |
| } | |
| AC[1] = t; | |
| AC[2] = i & AMASK; | |
| AC[3] = j & AMASK; | |
| continue; | |
| } | |
| if (IR == 0133710) { /* BLM: Block move */ | |
| t = AC[1]; | |
| if (t < 1 || t > 0100000) | |
| continue; | |
| i = indirect(AC[2]); | |
| j = indirect(AC[3]); | |
| if (Fault) continue; | |
| while (t) { | |
| PutMap(j, GetMap(i)); | |
| if (Fault) break; | |
| t--; | |
| i++; | |
| j++; | |
| i &= AMASK; | |
| j &= AMASK; | |
| } | |
| AC[1] = t; | |
| AC[2] = i & AMASK; | |
| AC[3] = j & AMASK; | |
| continue; | |
| } | |
| /* Stack operations */ | |
| if ((IR & 0103777) == 0103110) { /* PSH: Push multiple accums */ | |
| register int32 j; | |
| j = (IR >> 11) & 3; | |
| t = GetMap(040) & AMASK; | |
| i = (IR >> 13) & 3; | |
| if (i == j) { | |
| t++; | |
| PutMap(t, AC[i]); | |
| PutMap(040, (t & AMASK)); | |
| if (t > GetMap(042)) { | |
| pushrtn(PC); | |
| PC = indirect(GetMap(043)); | |
| PutMap(040, (GetMap(040) & 077777)); | |
| PutMap(042, (GetMap(042) | 0100000)); | |
| } | |
| continue; | |
| } | |
| while (i != j) { | |
| t++; | |
| PutMap(t, AC[i]); | |
| i++; | |
| if (i == 4) i = 0; | |
| } | |
| t++; | |
| PutMap(t, AC[i]); | |
| PutMap(040, (t & AMASK)); | |
| if ((GetMap(040) & AMASK) > GetMap(042)) { | |
| pushrtn(PC); | |
| PC = indirect(GetMap(043)); | |
| PutMap(040, (GetMap(040) & 077777)); | |
| PutMap(042, (GetMap(042) | 0100000)); | |
| } | |
| continue; | |
| } | |
| if ((IR & 0103777) == 0103210) { /* POP: Pop mult accums */ | |
| j = (IR >> 11) & 3; | |
| t = GetMap(040) & AMASK; | |
| i = (IR >> 13) & 3; | |
| if (i == j) { | |
| AC[i] = GetMap(t); | |
| t--; | |
| PutMap(040, (t & AMASK)); | |
| t = GetMap(040); | |
| if (t < 0100000 && t < 0400) { | |
| PutMap(040, GetMap(042)); | |
| pushrtn(PC); | |
| PC = indirect(GetMap(043)); | |
| PutMap(040, (GetMap(040) & 077777)); | |
| PutMap(042, (GetMap(042) | 0100000)); | |
| } | |
| continue; | |
| } | |
| while (i != j) { | |
| AC[i] = GetMap(t); | |
| t--; | |
| i--; | |
| if (i == -1) i = 3; | |
| } | |
| AC[i] = GetMap(t); | |
| t--; | |
| PutMap(040, (t & AMASK)); | |
| t = GetMap(040); | |
| if (t < 0100000 && t < 0400) { | |
| PutMap(040, GetMap(042)); | |
| pushrtn(PC); | |
| PC = indirect(GetMap(043)); | |
| PutMap(040, (GetMap(040) & 077777)); | |
| PutMap(042, (GetMap(042) | 0100000)); | |
| } | |
| continue; | |
| } | |
| if (IR == 0103710) { /* PSHR: Push return addr */ | |
| t = (GetMap(040) + 1) & AMASK; | |
| PutMap(t, (PC + 1)); | |
| PutMap(040, t); | |
| if ((GetMap(040) & AMASK) > GetMap(042)) { | |
| pushrtn(PC); | |
| PC = indirect(GetMap(043)); | |
| PutMap(040, (GetMap(040) & 077777)); | |
| PutMap(042, (GetMap(042) | 0100000)); | |
| } | |
| continue; | |
| } | |
| if (IR == 0163710) { /* SAVE */ | |
| register int32 savep; | |
| savep = ((GetMap(PC) + GetMap(040)) + 5) & AMASK; | |
| if (savep > GetMap(042)) { | |
| pushrtn(PC-1); | |
| PC = indirect(GetMap(043)); | |
| PutMap(040, (GetMap(040) & 077777)); | |
| PutMap(042, (GetMap(042) | 0100000)); | |
| continue; | |
| } | |
| t = GetMap(040) + 1; | |
| PutMap(t, AC[0]); | |
| t++; | |
| PutMap(t, AC[1]); | |
| t++; | |
| PutMap(t, AC[2]); | |
| t++; | |
| PutMap(t, GetMap(041)); | |
| t++; | |
| savep = PC; | |
| PC = (PC + 1) & AMASK; | |
| PutMap(t, (AC[3] & AMASK)); | |
| if (C) PutMap(t, (GetMap(t) | 0100000)); | |
| PutMap(040, t); | |
| AC[3] = GetMap(040) & AMASK; | |
| PutMap(041, AC[3]); | |
| PutMap(040, ((GetMap(040) + GetMap(savep)) & AMASK)); | |
| continue; | |
| } | |
| if ((IR & 0163777) == 0103370) { /* MSP: Modify stack pointer */ | |
| t = (GetMap(040) + AC[(IR >> 11) & 3]) & 0177777; | |
| if (t > GetMap(042)) { | |
| pushrtn(PC-1); | |
| PC = indirect(GetMap(043)); | |
| PutMap(040, (GetMap(040) & AMASK)); | |
| PutMap(042, (GetMap(042) | 0100000)); | |
| continue; | |
| } | |
| PutMap(040, t); | |
| continue; | |
| } | |
| if ((IR & 0176377) == 0102270) { /* PSHJ: Push JMP */ | |
| PutMap(040, (GetMap(040) + 1)); | |
| PutMap((GetMap(040) & AMASK), ((PC + 1) & AMASK)); | |
| if ((GetMap(040) & AMASK) > (GetMap(042) & AMASK)) { | |
| pushrtn(PC+1); | |
| PC = indirect(GetMap(043)); | |
| PutMap(040, (GetMap(040) & 077777)); | |
| PutMap(042, (GetMap(042) | 0100000)); | |
| continue; | |
| } | |
| PC = effective(PC, (IR >> 8) & 3, GetMap(PC)); | |
| continue; | |
| } | |
| if (IR == 0117710) { /* POPJ: Pop PC and Jump */ | |
| PC = GetMap(GetMap(040)) & AMASK; | |
| PutMap(040, (GetMap(040) - 1)); | |
| if (MapStat & 1) { | |
| Usermap = Enable; | |
| Inhibit = 0; | |
| } | |
| j = GetMap(042); | |
| t = GetMap(040); | |
| if ((j < 0100000 && t < 0100000) && (t < 0400) && (t > 0)) { | |
| pushrtn(PC); | |
| PC = indirect(GetMap(043)); | |
| PutMap(040, (GetMap(040) & 077777)); | |
| PutMap(042, (GetMap(042) | 0100000)); | |
| } | |
| continue; | |
| } | |
| if (IR == 0107710) { /* POPB: Pop block */ | |
| PC = GetMap(GetMap(040)) & AMASK; | |
| if (GetMap(GetMap(040)) & 0100000) | |
| C = 0200000; | |
| else | |
| C = 0; | |
| PutMap(040, (GetMap(040) - 1)); | |
| AC[3] = GetMap(GetMap(040)); | |
| PutMap(040, (GetMap(040) - 1)); | |
| AC[2] = GetMap(GetMap(040)); | |
| PutMap(040, (GetMap(040) - 1)); | |
| AC[1] = GetMap(GetMap(040)); | |
| PutMap(040, (GetMap(040) - 1)); | |
| AC[0] = GetMap(GetMap(040)); | |
| PutMap(040, (GetMap(040) - 1)); | |
| t = GetMap(040); | |
| if (t < 0100000 && t < 0400) { | |
| pushrtn(PC); | |
| PC = indirect(GetMap(043)); | |
| PutMap(040, (GetMap(040) & 077777)); | |
| PutMap(042, (GetMap(042) | 0100000)); | |
| } | |
| if (MapStat & 1) { | |
| Usermap = Enable; | |
| Inhibit = 0; | |
| } | |
| continue; | |
| } | |
| if (IR == 0127710) { /* RTN: Return */ | |
| PutMap(040, GetMap(041)); | |
| PC = GetMap(GetMap(040)) & AMASK; | |
| t = GetMap(040); | |
| t = GetMap(t); | |
| if (t & 0100000) | |
| C = 0200000; | |
| else | |
| C = 0; | |
| PutMap(040, (GetMap(040) - 1)); | |
| AC[3] = GetMap(GetMap(040)); | |
| PutMap(040, (GetMap(040) - 1)); | |
| AC[2] = GetMap(GetMap(040)); | |
| PutMap(040, (GetMap(040) - 1)); | |
| AC[1] = GetMap(GetMap(040)); | |
| PutMap(040, (GetMap(040) - 1)); | |
| AC[0] = GetMap(GetMap(040)); | |
| PutMap(040, (GetMap(040) - 1)); | |
| PutMap(041, AC[3]); | |
| t = GetMap(040); | |
| if (t < 0100000 && t < 0400) { | |
| pushrtn(PC); | |
| PutMap(040, (GetMap(040) & 077777)); | |
| PutMap(042, (GetMap(042) | 0100000)); | |
| PC = indirect(GetMap(043)); | |
| } | |
| if (MapStat & 1) { | |
| Usermap = Enable; | |
| Inhibit = 0; | |
| } | |
| continue; | |
| } | |
| if (IR == 0167710) { /* RSTR: Restore */ | |
| int32 SVPC; | |
| SVPC = PC; | |
| PC = GetMap(GetMap(040)) & AMASK; | |
| if (PC == 0 && Debug_Flags) { | |
| printf("\n<<RSTR to 0 @ %o>>\n\r", SVPC); | |
| reason = STOP_IBKPT; | |
| } | |
| if (GetMap(GetMap(040)) & 0100000) | |
| C = 0200000; | |
| else | |
| C = 0; | |
| PutMap(040, (GetMap(040) - 1)); | |
| AC[3] = GetMap(GetMap(040)); | |
| PutMap(040, (GetMap(040) - 1)); | |
| AC[2] = GetMap(GetMap(040)); | |
| PutMap(040, (GetMap(040) - 1)); | |
| AC[1] = GetMap(GetMap(040)); | |
| PutMap(040, (GetMap(040) - 1)); | |
| AC[0] = GetMap(GetMap(040)); | |
| PutMap(040, (GetMap(040) - 1)); | |
| PutMap(043, GetMap(GetMap(040))); | |
| PutMap(040, (GetMap(040) - 1)); | |
| PutMap(042, GetMap(GetMap(040))); | |
| PutMap(040, (GetMap(040) - 1)); | |
| PutMap(041, GetMap(GetMap(040))); | |
| PutMap(040, (GetMap(040) - 1)); | |
| PutMap(040, GetMap(GetMap(040))); | |
| /*t = GetMap(040); | |
| if (t < 0100000 && t < 0400) { | |
| pushrtn(PC); | |
| PC = indirect(GetMap(043)); | |
| }*/ | |
| if (MapStat & 1) { | |
| Usermap = Enable; | |
| Inhibit = 0; | |
| } | |
| continue; | |
| } | |
| /* Multiply / Divide */ | |
| if (IR == 0143710) { /* MUL: Unsigned Multiply */ | |
| uAC0 = (uint32) AC[0]; | |
| uAC1 = (uint32) AC[1]; | |
| uAC2 = (uint32) AC[2]; | |
| mddata = (uAC1 * uAC2) + uAC0; | |
| AC[0] = (mddata >> 16) & 0177777; | |
| AC[1] = mddata & 0177777; | |
| continue; | |
| } | |
| if (IR == 0147710) { /* MULS: Signed Multiply */ | |
| sAC0 = AC[0]; | |
| sAC1 = AC[1]; | |
| sAC2 = AC[2]; | |
| sddata = (sAC1 * sAC2) + sAC0; | |
| AC[0] = (sddata >> 16) & 0177777; | |
| AC[1] = sddata & 0177777; | |
| continue; | |
| } | |
| if (IR == 0153710) { /* DIV: Unsigned Divide */ | |
| uAC0 = (uint32) AC[0]; | |
| uAC1 = (uint32) AC[1]; | |
| uAC2 = (uint32) AC[2]; | |
| if (uAC0 >= uAC2) C = 0200000; | |
| else { | |
| C = 0; | |
| mddata = (uAC0 << 16) | uAC1; | |
| AC[1] = mddata / uAC2; | |
| AC[0] = mddata % uAC2; | |
| } | |
| continue; | |
| } | |
| if (IR == 0157710) { /* DIVS: Signed Divide */ | |
| if ((AC[0] == 0) || | |
| ((AC[0] == 0100000) && (AC[1] == 0) && (AC[2] == 0177777))) | |
| C = 0200000; | |
| else { | |
| sAC2 = AC[2]; | |
| C = 0; | |
| sddata = ((AC[0] & 0xffff) << 16) | (AC[1] & 0xffff); | |
| AC[1] = sddata / sAC2; | |
| AC[0] = sddata % sAC2; | |
| if (AC[0] > 077777 || AC[0] < -077776) C = 0200000; | |
| /*if ((AC[0] & 0xFFFF0000) != 0) C = 0200000;*/ | |
| if (AC[1] > 077777 || AC[1] < -077776) C = 0200000; | |
| /*if ((AC[1] & 0xFFFF0000) != 0) C = 0200000;*/ | |
| AC[0] &= 0177777; | |
| AC[1] &= 0177777; | |
| } | |
| continue; | |
| } | |
| if (IR == 0137710) { /* DIVX: Sign extend and Divide */ | |
| int32 q; | |
| if (AC[1] & 0100000) { | |
| AC[0] = 0177777; | |
| } else { | |
| AC[0] = 0; | |
| } | |
| sAC0 = AC[0]; | |
| sAC1 = AC[1]; | |
| sAC2 = AC[2]; | |
| C = 0; | |
| sddata = (sAC0 << 16) | sAC1; | |
| q = sddata / sAC2; | |
| AC[0] = sddata % sAC2; | |
| if (q > 0177777) { | |
| C = 0200000; | |
| } else { | |
| AC[1] = q & 0xffff; | |
| } | |
| continue; | |
| } | |
| if ((IR & 0163777) == 0143370) { /* HLV: Halve */ | |
| t = (IR >> 11) & 3; | |
| if (AC[t] & 0100000) { | |
| AC[t] = (0 - AC[t]) & 0xffff; | |
| AC[t] = AC[t] >> 1; | |
| AC[t] = (0 - AC[t]) & 0xffff; | |
| } else { | |
| AC[t] = (AC[t] >> 1) & 0xffff; | |
| } | |
| continue; | |
| } | |
| /* Decimal arithmetic */ | |
| if ((IR & 0103777) == 0100210) { /* DAD: Decimal add */ | |
| i = (IR >> 13) & 3; | |
| j = (IR >> 11) & 3; | |
| t = (AC[i] & 017) + (AC[j] & 017); | |
| if (C) t++; | |
| if (t > 9) { | |
| C = 0200000; | |
| t += 6; | |
| } else { | |
| C = 0; | |
| } | |
| AC[j] &= 0177760; | |
| AC[j] = AC[j] | (t & 017); | |
| continue; | |
| } | |
| if ((IR & 0103777) == 0100310) { /* DSB: Decimal subtract */ | |
| i = (IR >> 13) & 3; | |
| j = (IR >> 11) & 3; | |
| t = (AC[j] & 017) - (AC[i] & 017); | |
| if (!C) t--; | |
| if (t < 0) { | |
| C = 0; | |
| t = 9 - (~t); | |
| } else { | |
| C = 0200000; | |
| } | |
| AC[j] &= 0177760; | |
| AC[j] = AC[j] | (t & 017); | |
| continue; | |
| } | |
| /* Exotic, complex instructions */ | |
| if ((IR & 0162377) == 0142170) { /* DSPA: Dispatch */ | |
| register int32 d; | |
| int16 a, H, L; | |
| MA = effective(PC, (IR >> 8) & 3, GetMap(PC)); | |
| H = GetMap(MA - 1) & 0177777; | |
| L = GetMap(MA - 2) & 0177777; | |
| a = AC[(IR >> 11) & 3] & 0177777; | |
| if (a < L || a > H) { | |
| PC = (PC + 1) & AMASK; | |
| continue; | |
| } | |
| d = GetMap(MA - L + a); | |
| if (d == 0177777) { | |
| PC = (PC + 1) & AMASK; | |
| continue; | |
| } | |
| PC = indirect(d) & AMASK; | |
| continue; | |
| } | |
| if (((IR & 0100077) == 0100030) || | |
| ((IR & 0102077) == 0100070)) { /* XOP: Extended Operation */ | |
| register int32 op, d, sa, da; | |
| op = (IR >> 6) & 037; | |
| if ((IR & 077) == 070) op += 32; | |
| t = GetMap(040) & AMASK; | |
| for (i = 0; i <= 3; i++) { | |
| t++; | |
| PutMap(t, AC[i]); | |
| if (((IR >> 13) & 3) == i) sa = t; | |
| if (((IR >> 11) & 3) == i) da = t; | |
| } | |
| t++; | |
| PutMap(t, PC & AMASK); | |
| if (C) PutMap(t, (GetMap(t) | 0100000)); | |
| PutMap(040, t); | |
| AC[2] = sa; | |
| AC[3] = da; | |
| d = GetMap(GetMap(044) + op); | |
| PC = indirect(d) & AMASK; | |
| if ((GetMap(040) & AMASK) > (GetMap(042) & AMASK)) { | |
| pushrtn(PC); | |
| PC = indirect(GetMap(043)); | |
| PutMap(040, (GetMap(040) & 077777)); | |
| PutMap(042, (GetMap(042) | 0100000)); | |
| } | |
| continue; | |
| } | |
| if ((IR & 0103777) == 0103510) { /* SYC: System call */ | |
| register int32 j; | |
| DisMap = Usermap; | |
| Usermap = 0; | |
| MapStat &= ~1; /* Disable MAP */ | |
| i = (IR >> 13) & 3; | |
| j = (IR >> 11) & 3; | |
| if (i != 0 || j != 0) { | |
| t = (GetMap(040) + 1) & AMASK; | |
| PutMap(t, AC[0]); | |
| t++; | |
| PutMap(t, AC[1]); | |
| t++; | |
| PutMap(t, AC[2]); | |
| t++; | |
| PutMap(t, AC[3]); | |
| t++; | |
| PutMap(t, (PC & AMASK)); | |
| if (C) PutMap(t, (GetMap(t) | 0100000)); | |
| PutMap(040, t); | |
| PutMap(041, (GetMap(040) & AMASK)); | |
| } | |
| PC = indirect(GetMap(2)) & AMASK; | |
| if (DisMap > 0) | |
| Inhibit = 3; /* Special 1-instruction interrupt inhibit */ | |
| if ((GetMap(040) & AMASK) > GetMap(042)) { | |
| pushrtn(PC); | |
| PC = indirect(GetMap(043)); | |
| PutMap(040, (GetMap(040) & 077777)); | |
| PutMap(042, (GetMap(042) | 0100000)); | |
| } | |
| continue; | |
| } | |
| if (IR == 0113410) { /* LMP: Load Map */ | |
| register int32 w, m; | |
| if ((Debug_Flags & 077) == 03) | |
| fprintf(Trace, "%o LMP (Map=%o)\n", PC - 1, (MapStat>>7)&07); | |
| t = AC[1]; | |
| i = AC[2]; | |
| while (t) { | |
| if (int_req > INT_PENDING && !Inhibit) { /* interrupt? */ | |
| PC = PC - 1; | |
| break; | |
| } | |
| if (!Usermap || !(MapStat & 0140)) { /* Only load if in sup mode */ | |
| w = (GetMap(i) + AC[0]) & 0xffff; /* Or not IO & LEF mode for user */ | |
| m = (w >> 10) & 037; | |
| if ((Debug_Flags & 077) == 03) | |
| fprintf(Trace, " %o MAP L=%o W=%o P=%o\n", i, m, | |
| (w>>15)&1, w & PAGEMASK); | |
| LoadMap(w); | |
| if (Fault) break; | |
| } | |
| t--; | |
| i++; | |
| } | |
| AC[0] = 0; | |
| AC[1] = t; | |
| AC[2] = i & AMASK; | |
| MapStat &= ~02000; | |
| continue; | |
| } | |
| /****************************************************************/ | |
| /* Character Instruction Set */ | |
| /****************************************************************/ | |
| if ((IR & 0162377) == 0102170) { /* ELDB */ | |
| t = Bytepointer(PC, (IR >> 8) & 3); | |
| i = (IR >> 11) & 03; | |
| MA = (t >> 1) & AMASK; | |
| if (t & 01) { | |
| AC[i] = GetMap(MA) & 0377; | |
| } else { | |
| AC[i] = (GetMap(MA) >> 8) & 0377; | |
| } | |
| PC = (PC + 1) & AMASK; | |
| continue; | |
| } | |
| if ((IR & 0162377) == 0122170) { /* ESTB */ | |
| t = Bytepointer(PC, (IR >> 8) & 3); | |
| i = (IR >> 11) & 03; | |
| MA = (t >> 1) & AMASK; | |
| j = GetMap(MA); | |
| if (t & 01) { | |
| j &= 0177400; | |
| j |= (AC[i] & 0377); | |
| PutMap(MA, j); | |
| } else { | |
| j &= 0377; | |
| j |= (AC[i] & 0377) << 8; | |
| PutMap(MA, j); | |
| } | |
| PC = (PC + 1) & AMASK; | |
| continue; | |
| } | |
| if ((IR & 077) == 050) { /* All CIS end with 050 except ELDB/ESTB */ | |
| if (IR == 0153650) { /* CMV Character Move */ | |
| cmdlen = AC[0] & 0177777; /* Set up length & direction */ | |
| cmslen = AC[1] & 0177777; /* For both source & dest */ | |
| cmsptr = AC[3]; /* init byte pointers */ | |
| cmdptr = AC[2]; | |
| C = 0; /* Do carry now b4 cmslen changes */ | |
| if (abs(cmslen) > abs(cmdlen)) | |
| C = 0200000; | |
| for (i = 0; i < abs(cmdlen); i++) { /* Move loop */ | |
| MA = (cmsptr >> 1) & AMASK; /* do an LDB */ | |
| if (cmslen == 0) { | |
| uAC2 = ' ' & 0377; /* Handle short source */ | |
| } else { | |
| if (cmsptr & 01) { | |
| uAC2 = GetMap(MA) & 0377; /* Use uAC2 for temp */ | |
| } else { | |
| uAC2 = (GetMap(MA) >> 8) & 0377; | |
| } | |
| } | |
| MA = (cmdptr >> 1) & AMASK; /* do an STB */ | |
| j = GetMap(MA); | |
| if (cmdptr & 01) { | |
| j &= 0177400; | |
| j |= (uAC2 & 0377); | |
| PutMap(MA, j); | |
| } else { | |
| j &= 0377; | |
| j |= (uAC2 & 0377) << 8; | |
| PutMap(MA, j); | |
| } | |
| if (cmslen > 0) { | |
| cmsptr++; | |
| cmslen--; | |
| } | |
| if (cmslen < 0) { | |
| cmsptr--; | |
| cmslen++; | |
| } | |
| if (cmdlen > 0) { | |
| cmdptr++; | |
| } else { | |
| cmdptr--; | |
| } | |
| } | |
| AC[0] = 0; | |
| AC[1] = cmslen & 0177777; | |
| AC[2] = cmdptr & 0177777; | |
| AC[3] = cmsptr & 0177777; | |
| continue; | |
| } | |
| if (IR == 0157650) { /* CMP Character compare */ | |
| cmdlen = AC[0] & 0177777; /* Set up length & direction */ | |
| cmslen = AC[1] & 0177777; /* For both source & dest */ | |
| cmsptr = AC[3]; /* init byte pointers */ | |
| cmdptr = AC[2]; | |
| t = 0; /* Equal unless otherwise */ | |
| while (1) { /* Compare loop */ | |
| MA = (cmsptr >> 1) & AMASK; /* do an LDB - string 1 */ | |
| if (cmslen != 0) { | |
| if (cmsptr & 01) { | |
| uAC2 = GetMap(MA) & 0377; /* Use uAC2 for temp */ | |
| } else { | |
| uAC2 = (GetMap(MA) >> 8) & 0377; | |
| } | |
| } else { | |
| uAC2 = ' ' & 0377; | |
| } | |
| MA = (cmdptr >> 1) & AMASK; /* do an LDB - string 2 */ | |
| if (cmdlen != 0) { | |
| if (cmdptr & 01) { | |
| uAC3 = GetMap(MA) & 0377; /* Use uAC2 for temp */ | |
| } else { | |
| uAC3 = (GetMap(MA) >> 8) & 0377; | |
| } | |
| } else { | |
| uAC3 = ' ' & 0377; | |
| } | |
| if (uAC2 > uAC3) { | |
| t = 1; | |
| break; | |
| } | |
| if (uAC2 < uAC3) { | |
| t = -1; | |
| break; | |
| } | |
| if (cmslen > 0) { | |
| cmsptr++; | |
| cmslen--; | |
| } | |
| if (cmslen < 0) { | |
| cmsptr--; | |
| cmslen++; | |
| } | |
| if (cmdlen > 0) { | |
| cmdptr++; | |
| cmdlen--; | |
| } | |
| if (cmdlen < 0) { | |
| cmdptr--; | |
| cmdlen++; | |
| } | |
| if (cmslen == 0 && cmdlen == 0) | |
| break; | |
| } | |
| AC[1] = t & 0177777; | |
| AC[0] = cmdlen & 0177777; | |
| AC[2] = cmdptr & 0177777; | |
| AC[3] = cmsptr & 0177777; | |
| continue; | |
| } | |
| if (IR == 0163650) { /* CTR Character translate */ | |
| tabaddr = indirect(AC[0]); /* Get address of table */ | |
| tabptr = GetMap(tabaddr) & 0177777; /* Get byte pointer */ | |
| cmslen = AC[1] & 0177777; /* Length: both source & dest */ | |
| cmopt = 0; /* Default: COMPARE option */ | |
| if (cmslen < 0) { | |
| cmopt=1; /* MOVE option */ | |
| cmslen = 0 - cmslen; | |
| } | |
| cmsptr = AC[3]; /* init byte pointers */ | |
| cmdptr = AC[2]; | |
| t = 0; /* Equal unless otherwise */ | |
| while (1) { /* Translation loop */ | |
| MA = (cmsptr >> 1) & AMASK; /* do an LDB - string 1 */ | |
| if (cmsptr & 01) { | |
| j = GetMap(MA) & 0377; | |
| } else { | |
| j = (GetMap(MA) >> 8) & 0377; | |
| } | |
| cmptr = tabptr + j; /* Translate */ | |
| MA = (cmptr >> 1) & AMASK; | |
| if (cmptr & 01) { | |
| uAC2 = GetMap(MA) & 0377; | |
| } else { | |
| uAC2 = (GetMap(MA) >> 8) & 0377; | |
| } | |
| if (cmopt) { /* MOVE... */ | |
| MA = (cmdptr >> 1) & AMASK; /* do an STB */ | |
| j = GetMap(MA); | |
| if (cmdptr & 01) { | |
| j &= 0177400; | |
| j |= (uAC2 & 0377); | |
| PutMap(MA, j); | |
| } else { | |
| j &= 0377; | |
| j |= (uAC2 & 0377) << 8; | |
| PutMap(MA, j); | |
| } | |
| } else { /* COMPARE... */ | |
| MA = (cmdptr >> 1) & AMASK; /* do an LDB - string 2 */ | |
| if (cmdptr & 01) { | |
| j = GetMap(MA) & 0377; | |
| } else { | |
| j = (GetMap(MA) >> 8) & 0377; | |
| } | |
| cmptr = tabptr + j; /* Translate */ | |
| MA = (cmptr >> 1) & AMASK; | |
| if (cmptr & 01) { | |
| uAC3 = GetMap(MA) & 0377; | |
| } else { | |
| uAC3 = (GetMap(MA) >> 8) & 0377; | |
| } | |
| if (uAC2 > uAC3) { | |
| t = 1; | |
| break; | |
| } | |
| if (uAC2 < uAC3) { | |
| t = -1; | |
| break; | |
| } | |
| } | |
| cmsptr++; | |
| cmdptr++; | |
| cmslen--; | |
| if (cmslen == 0) | |
| break; | |
| } | |
| if (!cmopt) AC[1] = t; | |
| else | |
| AC[1] = 0; | |
| AC[0] = tabaddr & 077777; | |
| AC[2] = cmdptr & 0177777; | |
| AC[3] = cmsptr & 0177777; | |
| continue; | |
| } | |
| if (IR == 0167650) { /* CMT Char move till true */ | |
| tabaddr = indirect(AC[0]); /* Set up length & direction */ | |
| cmslen = AC[1] & 0177777; /* For both source & dest */ | |
| cmsptr = AC[3]; /* init byte pointers */ | |
| cmdptr = AC[2]; | |
| while (1) { /* Move loop */ | |
| MA = (cmsptr >> 1) & AMASK; /* do an LDB */ | |
| if (cmsptr & 01) { | |
| uAC2 = GetMap(MA) & 0377; /* Use uAC2 for temp */ | |
| } else { | |
| uAC2 = (GetMap(MA) >> 8) & 0377; | |
| } | |
| t = GetMap(tabaddr + (uAC2 >> 4)); /* Test bit table */ | |
| if (t << (uAC2 & 0x0F) & 0100000) /* quit if bit == 1 */ | |
| break; | |
| MA = (cmdptr >> 1) & AMASK; /* do an STB */ | |
| j = GetMap(MA); | |
| if (cmdptr & 01) { | |
| j &= 0177400; | |
| j |= (uAC2 & 0377); | |
| PutMap(MA, j); | |
| } else { | |
| j &= 0377; | |
| j |= (uAC2 & 0377) << 8; | |
| PutMap(MA, j); | |
| } | |
| if (cmslen > 0) { | |
| cmsptr++; | |
| cmdptr++; | |
| cmslen--; | |
| } | |
| if (cmslen < 0) { | |
| cmsptr--; | |
| cmdptr--; | |
| cmslen++; | |
| } | |
| if (cmslen == 0) | |
| break; | |
| } | |
| AC[0] = tabaddr & 077777; | |
| AC[1] = cmslen & 0177777; | |
| AC[2] = cmdptr & 0177777; | |
| AC[3] = cmsptr & 0177777; | |
| continue; | |
| } | |
| /*********************************************************** | |
| ** "Commercial" instructions. These were in the original ** | |
| ** Eclipse C series, but not part of the later Character ** | |
| ** Instruction Set. ** | |
| ***********************************************************/ | |
| if ((IR & 0163777) == 0103650) { /* LDI Load Integer */ | |
| unimp(PC); | |
| continue; | |
| } | |
| if ((IR & 0163777) == 0123650) { /* STI Store Integer */ | |
| unimp(PC); | |
| continue; | |
| } | |
| if (IR == 0143650) { /* LDIX Load Int Extended */ | |
| unimp(PC); | |
| continue; | |
| } | |
| if (IR == 0143750) { /* STIX Store Int Extended */ | |
| unimp(PC); | |
| continue; | |
| } | |
| if ((IR & 0163777) == 0143150) { /* FINT Integerize */ | |
| unimp(PC); | |
| continue; | |
| } | |
| if (IR == 0177650) { /* LSN Load Sign */ | |
| unimp(PC); | |
| continue; | |
| } | |
| if (IR == 0173650) { /* EDIT */ | |
| unimp(PC); | |
| continue; | |
| } | |
| } | |
| /* FPU Instructions */ | |
| if ((IR & 0163777) == 0123350) { /* FLST Load Status */ | |
| if (!(fpu_unit.flags & UNIT_UP)) | |
| continue; | |
| if (Debug_Flags == 1) { | |
| printf("\n<<FPU instruction: FLST>>\n"); | |
| reason = STOP_IBKPT; | |
| } | |
| if (FPFault) { /* Fault from a previous inst? */ | |
| FPFault = 0; | |
| t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ | |
| PutMap(t, AC[0]); | |
| t++; | |
| PutMap(t, AC[1]); | |
| t++; | |
| PutMap(t, AC[2]); | |
| t++; | |
| PutMap(t, AC[3]); | |
| t++; | |
| PutMap(t, ((PC-1) & AMASK)); | |
| if (C) PutMap(t, (GetMap(t) | 0100000)); | |
| PutMap(040, t); | |
| PC = indirect(GetMap(045)); /* JMP indirect to 45 */ | |
| continue; | |
| } | |
| FPSR = 0; | |
| MA = effective(PC, (IR >> 11) & 3, GetMap(PC)); | |
| FPSR = (GetMap(MA) << 16); | |
| FPSR |= (GetMap(MA + 1)); | |
| FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ | |
| FPSR |= ((PC - 1) & AMASK); | |
| PC = (PC + 1) & AMASK; | |
| continue; | |
| } | |
| if ((IR & 0163777) == 0103350) { /* FSST Store Status */ | |
| if (!(fpu_unit.flags & UNIT_UP)) | |
| continue; | |
| if (Debug_Flags == 1) { | |
| printf("\n<<FPU instruction: FSST>>\n"); | |
| reason = STOP_IBKPT; | |
| } | |
| if (FPFault) { /* Fault from a previous inst? */ | |
| FPFault = 0; | |
| t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ | |
| PutMap(t, AC[0]); | |
| t++; | |
| PutMap(t, AC[1]); | |
| t++; | |
| PutMap(t, AC[2]); | |
| t++; | |
| PutMap(t, AC[3]); | |
| t++; | |
| PutMap(t, ((PC-1) & AMASK)); | |
| if (C) PutMap(t, (GetMap(t) | 0100000)); | |
| PutMap(040, t); | |
| PC = indirect(GetMap(045)); /* JMP indirect to 45 */ | |
| continue; | |
| } | |
| MA = effective(PC, (IR >> 11) & 3, GetMap(PC)); | |
| FPSR &= 0xFFF0FFFF; /* Force FPU model */ | |
| switch (model) { | |
| case 200: | |
| case 230: | |
| case 300: | |
| case 330: | |
| FPSR |= 0x00000000; | |
| break; | |
| case 130: | |
| FPSR |= 0x00010000; | |
| break; | |
| case 350: | |
| case 600: | |
| FPSR |= 0x00020000; | |
| break; | |
| case 250: | |
| FPSR |= 0x00060000; | |
| break; | |
| default: | |
| FPSR |= 0x000F0000; | |
| break; | |
| } | |
| PutMap(MA, ((FPSR >> 16) & 0xFFFF)); | |
| PutMap((MA + 1), FPSR & 0xFFFF); | |
| FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ | |
| FPSR |= ((PC - 1) & AMASK); | |
| PC = (PC + 1) & AMASK; | |
| continue; | |
| } | |
| if ((IR & 0103777) == 0102050) { /* FLDS Load FP single */ | |
| if (!(fpu_unit.flags & UNIT_UP)) | |
| continue; | |
| if (Debug_Flags == 1) { | |
| printf("\n<<FPU instruction: FLDS>>\n"); | |
| reason = STOP_IBKPT; | |
| } | |
| if (FPFault) { /* Fault from a previous inst? */ | |
| FPFault = 0; | |
| t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ | |
| PutMap(t, AC[0]); | |
| t++; | |
| PutMap(t, AC[1]); | |
| t++; | |
| PutMap(t, AC[2]); | |
| t++; | |
| PutMap(t, AC[3]); | |
| t++; | |
| PutMap(t, ((PC-1) & AMASK)); | |
| if (C) PutMap(t, (GetMap(t) | 0100000)); | |
| PutMap(040, t); | |
| PC = indirect(GetMap(045)); /* JMP indirect to 45 */ | |
| continue; | |
| } | |
| i = (IR >> 11) & 0x03; | |
| FPAC[i] = 0; | |
| MA = effective(PC, (IR >> 13) & 3, GetMap(PC)); | |
| t = GetMap(MA) & 0xffff; | |
| FPAC[i] = (t_int64) t << 48; | |
| t = GetMap(MA+1) & 0xffff; | |
| FPAC[i] |= (t_int64) t << 32; | |
| if ((FPAC[i] & 0x00ffffffffffffff) == 0) | |
| FPAC[i] = 0; | |
| FPSR &= 0xFCFFFFFF; | |
| if (FPAC[i] == 0) | |
| FPSR |= 0x02000000; | |
| if (FPAC[i] & 0x8000000000000000) | |
| FPSR |= 0x01000000; | |
| FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ | |
| FPSR |= ((PC - 1) & AMASK); | |
| PC = (PC + 1) & AMASK; | |
| continue; | |
| } | |
| if ((IR & 0103777) == 0102150) { /* FLDD Load FP double */ | |
| if (!(fpu_unit.flags & UNIT_UP)) | |
| continue; | |
| if (Debug_Flags == 1) { | |
| printf("\n<<FPU instruction: FLDD>>\n"); | |
| reason = STOP_IBKPT; | |
| } | |
| if (FPFault) { /* Fault from a previous inst? */ | |
| FPFault = 0; | |
| t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ | |
| PutMap(t, AC[0]); | |
| t++; | |
| PutMap(t, AC[1]); | |
| t++; | |
| PutMap(t, AC[2]); | |
| t++; | |
| PutMap(t, AC[3]); | |
| t++; | |
| PutMap(t, ((PC-1) & AMASK)); | |
| if (C) PutMap(t, (GetMap(t) | 0100000)); | |
| PutMap(040, t); | |
| PC = indirect(GetMap(045)); /* JMP indirect to 45 */ | |
| continue; | |
| } | |
| i = (IR >> 11) & 0x03; | |
| FPAC[i] = 0; | |
| MA = effective(PC, (IR >> 13) & 3, GetMap(PC)); | |
| t = GetMap(MA) & 0xffff; | |
| FPAC[i] = (t_int64) t << 48; | |
| t = GetMap(MA+1) & 0xffff; | |
| FPAC[i] |= (t_int64) t << 32; | |
| t = GetMap(MA+2) & 0xffff; | |
| FPAC[i] |= (t_int64) t << 16; | |
| t = GetMap(MA+3) & 0xffff; | |
| FPAC[i] |= (t_int64) t; | |
| if ((FPAC[i] & 0x00ffffffffffffff) == 0) | |
| FPAC[i] = 0; | |
| FPSR &= 0xFCFFFFFF; | |
| if (FPAC[i] == 0) | |
| FPSR |= 0x02000000; | |
| if (FPAC[i] & 0x8000000000000000) | |
| FPSR |= 0x01000000; | |
| FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ | |
| FPSR |= ((PC - 1) & AMASK); | |
| PC = (PC + 1) & AMASK; | |
| continue; | |
| } | |
| if ((IR & 0103777) == 0102250) { /* FSTS Store FP single */ | |
| if (!(fpu_unit.flags & UNIT_UP)) | |
| continue; | |
| if (Debug_Flags == 1) { | |
| printf("\n<<FPU instruction: FSTS>>\n"); | |
| reason = STOP_IBKPT; | |
| } | |
| if (FPFault) { /* Fault from a previous inst? */ | |
| FPFault = 0; | |
| t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ | |
| PutMap(t, AC[0]); | |
| t++; | |
| PutMap(t, AC[1]); | |
| t++; | |
| PutMap(t, AC[2]); | |
| t++; | |
| PutMap(t, AC[3]); | |
| t++; | |
| PutMap(t, ((PC-1) & AMASK)); | |
| if (C) PutMap(t, (GetMap(t) | 0100000)); | |
| PutMap(040, t); | |
| PC = indirect(GetMap(045)); /* JMP indirect to 45 */ | |
| continue; | |
| } | |
| i = (IR >> 11) & 0x03; | |
| MA = effective(PC, (IR >> 13) & 3, GetMap(PC)); | |
| PutMap(MA, (int32)(FPAC[i] >> 48) & 0xffff); | |
| PutMap(MA+1, (int32)(FPAC[i] >> 32) & 0xffff); | |
| FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ | |
| FPSR |= ((PC - 1) & AMASK); | |
| PC = (PC + 1) & AMASK; | |
| continue; | |
| } | |
| if ((IR & 0103777) == 0102350) { /* FSTD Store FP double */ | |
| if (!(fpu_unit.flags & UNIT_UP)) | |
| continue; | |
| if (Debug_Flags == 1) { | |
| printf("\n<<FPU instruction: FSTD>>\n"); | |
| reason = STOP_IBKPT; | |
| } | |
| if (FPFault) { /* Fault from a previous inst? */ | |
| FPFault = 0; | |
| t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ | |
| PutMap(t, AC[0]); | |
| t++; | |
| PutMap(t, AC[1]); | |
| t++; | |
| PutMap(t, AC[2]); | |
| t++; | |
| PutMap(t, AC[3]); | |
| t++; | |
| PutMap(t, ((PC-1) & AMASK)); | |
| if (C) PutMap(t, (GetMap(t) | 0100000)); | |
| PutMap(040, t); | |
| PC = indirect(GetMap(045)); /* JMP indirect to 45 */ | |
| continue; | |
| } | |
| i = (IR >> 11) & 0x03; | |
| MA = effective(PC, (IR >> 13) & 3, GetMap(PC)); | |
| PutMap(MA, (int32)(FPAC[i] >> 48) & 0xffff); | |
| PutMap(MA+1, (int32)(FPAC[i] >> 32) & 0xffff); | |
| PutMap(MA+2, (int32)(FPAC[i] >> 16) & 0xffff); | |
| PutMap(MA+3, (int32)(FPAC[i] & 0xffff)); | |
| FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ | |
| FPSR |= ((PC - 1) & AMASK); | |
| PC = (PC + 1) & AMASK; | |
| continue; | |
| } | |
| if ((IR & 0103777) == 0103550) { /* FMOV Move FP */ | |
| if (!(fpu_unit.flags & UNIT_UP)) | |
| continue; | |
| if (Debug_Flags == 1) { | |
| printf("\n<<FPU instruction: FMOV>>\n"); | |
| reason = STOP_IBKPT; | |
| continue; | |
| } | |
| if (FPFault) { /* Fault from a previous inst? */ | |
| FPFault = 0; | |
| t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ | |
| PutMap(t, AC[0]); | |
| t++; | |
| PutMap(t, AC[1]); | |
| t++; | |
| PutMap(t, AC[2]); | |
| t++; | |
| PutMap(t, AC[3]); | |
| t++; | |
| PutMap(t, ((PC-1) & AMASK)); | |
| if (C) PutMap(t, (GetMap(t) | 0100000)); | |
| PutMap(040, t); | |
| PC = indirect(GetMap(045)); /* JMP indirect to 45 */ | |
| continue; | |
| } | |
| i = (IR >> 13) & 3; | |
| j = (IR >> 11) & 3; | |
| FPAC[j] = FPAC[i]; | |
| if ((FPAC[j] & 0x00ffffffffffffff) == 0) | |
| FPAC[j] = 0; | |
| FPSR &= 0xFCFFFFFF; | |
| if (FPAC[j] == 0) | |
| FPSR |= 0x02000000; | |
| if (FPAC[j] & 0x8000000000000000) | |
| FPSR |= 0x01000000; | |
| FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ | |
| FPSR |= ((PC - 1) & AMASK); | |
| continue; | |
| } | |
| if (IR == 0143350) { /* FTE Trap Enable */ | |
| if (!(fpu_unit.flags & UNIT_UP)) | |
| continue; | |
| if (Debug_Flags == 2) { | |
| printf("\n<<FPU instruction: FTE>>\n"); | |
| reason = STOP_IBKPT; | |
| } | |
| if (FPFault) { /* Fault from a previous inst? */ | |
| FPFault = 0; | |
| t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ | |
| PutMap(t, AC[0]); | |
| t++; | |
| PutMap(t, AC[1]); | |
| t++; | |
| PutMap(t, AC[2]); | |
| t++; | |
| PutMap(t, AC[3]); | |
| t++; | |
| PutMap(t, ((PC-1) & AMASK)); | |
| if (C) PutMap(t, (GetMap(t) | 0100000)); | |
| PutMap(040, t); | |
| PC = indirect(GetMap(045)); /* JMP indirect to 45 */ | |
| continue; | |
| } | |
| FPSR |= 0x04000000; | |
| FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ | |
| FPSR |= ((PC - 1) & AMASK); | |
| continue; | |
| } | |
| if (IR == 0147350) { /* FTD Trap Disable */ | |
| if (!(fpu_unit.flags & UNIT_UP)) | |
| continue; | |
| if (Debug_Flags == 1) { | |
| printf("\n<<FPU instruction: FTD>>\n"); | |
| reason = STOP_IBKPT; | |
| } | |
| if (FPFault) { /* Fault from a previous inst? */ | |
| FPFault = 0; | |
| t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ | |
| PutMap(t, AC[0]); | |
| t++; | |
| PutMap(t, AC[1]); | |
| t++; | |
| PutMap(t, AC[2]); | |
| t++; | |
| PutMap(t, AC[3]); | |
| t++; | |
| PutMap(t, ((PC-1) & AMASK)); | |
| if (C) PutMap(t, (GetMap(t) | 0100000)); | |
| PutMap(040, t); | |
| PC = indirect(GetMap(045)); /* JMP indirect to 45 */ | |
| continue; | |
| } | |
| FPSR &= 0xFBFFFFFF; | |
| FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ | |
| FPSR |= ((PC - 1) & AMASK); | |
| continue; | |
| } | |
| if ((IR & 0103777) == 0102450) { /* FLAS Float from AC */ | |
| if (!(fpu_unit.flags & UNIT_UP)) | |
| continue; | |
| if (Debug_Flags == 1) { | |
| printf("\n<<FPU instruction: FLAS>>\n"); | |
| reason = STOP_IBKPT; | |
| } | |
| if (FPFault) { /* Fault from a previous inst? */ | |
| FPFault = 0; | |
| t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ | |
| PutMap(t, AC[0]); | |
| t++; | |
| PutMap(t, AC[1]); | |
| t++; | |
| PutMap(t, AC[2]); | |
| t++; | |
| PutMap(t, AC[3]); | |
| t++; | |
| PutMap(t, ((PC-1) & AMASK)); | |
| if (C) PutMap(t, (GetMap(t) | 0100000)); | |
| PutMap(040, t); | |
| PC = indirect(GetMap(045)); /* JMP indirect to 45 */ | |
| continue; | |
| } | |
| i = (IR >> 13) & 3; | |
| j = (IR >> 11) & 3; | |
| if (AC[i] == 0) { | |
| FPAC[j] = 0; | |
| FPSR |= 0x02000000; | |
| continue; | |
| } | |
| fpnum = (t_int64)(AC[i] & 077777) << 32; | |
| if (AC[i] & 0x8000) | |
| fpnum = 0 - fpnum; | |
| expon = 70; | |
| while (1) { | |
| if (fpnum & 0x00FF000000000000) | |
| break; | |
| if (expon < 64) | |
| break; | |
| fpnum = fpnum << 4; | |
| expon--; | |
| } | |
| FPAC[j] = 0; | |
| FPAC[j] = fpnum & 0x00ffffffffffffff; | |
| FPAC[j] |= (expon << 56) & 0x7f00000000000000; | |
| if (AC[i] & 0x8000) | |
| FPAC[j] |= 0x8000000000000000; | |
| if ((FPAC[j] & 0x00ffffffffffffff) == 0) | |
| FPAC[j] = 0; | |
| FPSR &= 0xFCFFFFFF; | |
| if (FPAC[j] == 0) | |
| FPSR |= 0x02000000; | |
| if (FPAC[j] & 0x8000000000000000) | |
| FPSR |= 0x01000000; | |
| FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ | |
| FPSR |= ((PC - 1) & AMASK); | |
| continue; | |
| } | |
| if ((IR & 0103777) == 0102550) { /* FLMD Float from memory */ | |
| if (!(fpu_unit.flags & UNIT_UP)) | |
| continue; | |
| if (Debug_Flags == 1) { | |
| printf("\n<<FPU instruction: FLMD>>\n"); | |
| reason = STOP_IBKPT; | |
| } | |
| if (FPFault) { /* Fault from a previous inst? */ | |
| FPFault = 0; | |
| t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ | |
| PutMap(t, AC[0]); | |
| t++; | |
| PutMap(t, AC[1]); | |
| t++; | |
| PutMap(t, AC[2]); | |
| t++; | |
| PutMap(t, AC[3]); | |
| t++; | |
| PutMap(t, ((PC-1) & AMASK)); | |
| if (C) PutMap(t, (GetMap(t) | 0100000)); | |
| PutMap(040, t); | |
| PC = indirect(GetMap(045)); /* JMP indirect to 45 */ | |
| continue; | |
| } | |
| i = (IR >> 13) & 3; | |
| j = (IR >> 11) & 3; | |
| MA = effective(PC, (IR >> 13) & 3, GetMap(PC)); | |
| PC = (PC + 1) & AMASK; | |
| fpnum32 = 0; | |
| fpnum32 = (GetMap(MA) << 16); | |
| fpnum32 |= (GetMap(MA + 1)); | |
| if (fpnum32 == 0) { | |
| FPAC[j] = 0; | |
| FPSR |= 0x02000000; | |
| continue; | |
| } | |
| fpnum = (t_int64)(fpnum32 & 0xffffffff) << 32; | |
| if (fpnum32 < 0) | |
| fpnum = (0 - fpnum); | |
| expon = 70; | |
| while (1) { | |
| if (fpnum & 0x00F0000000000000) | |
| break; | |
| if (expon < 64) | |
| break; | |
| fpnum = fpnum << 4; | |
| expon--; | |
| } | |
| FPAC[j] = 0; | |
| FPAC[j] = fpnum & 0x00ffffffffffffff; | |
| FPAC[j] |= (expon << 56) & 0x7f00000000000000; | |
| if (fpnum32 < 0) | |
| FPAC[j] |= 0x8000000000000000; | |
| if ((FPAC[j] & 0x00ffffffffffffff) == 0) | |
| FPAC[j] = 0; | |
| FPSR &= 0xFCFFFFFF; | |
| if (FPAC[j] == 0) | |
| FPSR |= 0x02000000; | |
| if (FPAC[j] & 0x8000000000000000) | |
| FPSR |= 0x01000000; | |
| FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ | |
| FPSR |= ((PC - 1) & AMASK); | |
| continue; | |
| } | |
| if ((IR & 0103777) == 0102650) { /* FFAS Fix to AC */ | |
| if (!(fpu_unit.flags & UNIT_UP)) | |
| continue; | |
| if (Debug_Flags == 1) { | |
| printf("\n<<FPU instruction: FFAS>>\n"); | |
| reason = STOP_IBKPT; | |
| } | |
| if (FPFault) { /* Fault from a previous inst? */ | |
| FPFault = 0; | |
| t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ | |
| PutMap(t, AC[0]); | |
| t++; | |
| PutMap(t, AC[1]); | |
| t++; | |
| PutMap(t, AC[2]); | |
| t++; | |
| PutMap(t, AC[3]); | |
| t++; | |
| PutMap(t, ((PC-1) & AMASK)); | |
| if (C) PutMap(t, (GetMap(t) | 0100000)); | |
| PutMap(040, t); | |
| PC = indirect(GetMap(045)); /* JMP indirect to 45 */ | |
| continue; | |
| } | |
| i = (IR >> 13) & 3; | |
| j = (IR >> 11) & 3; | |
| tac = AC[0]; | |
| t = 0; | |
| FPSR &= 0xFCFFFFFF; /* Z+N bits off */ | |
| /* Get register content */ | |
| get_lf(&dfl, &FPAC[j]); | |
| if (dfl.long_fract) { | |
| /* not zero */ | |
| normal_lf(&dfl); | |
| if (dfl.expo > 72) { | |
| /* ERROR: exceeds range by exponent */ | |
| FPSR |= 0x08000000; /* MOF bit on */ | |
| dfl.long_fract &= 0x7FFFFFFF; | |
| } | |
| if (dfl.expo > 64) { | |
| /* to be right shifted and to be rounded */ | |
| shift = ((78 - dfl.expo) * 4); | |
| lsfract = dfl.long_fract << (64 - shift); | |
| dfl.long_fract >>= shift; | |
| if (dfl.expo == 72) { | |
| if (dfl.sign) { | |
| /* negative */ | |
| if (dfl.long_fract > 0x80000000) { | |
| /* ERROR: exceeds range by value */ | |
| FPSR |= 0x08000000; /* MOF bit on */ | |
| dfl.long_fract &= 0x7FFFFFFF; | |
| } | |
| } else { | |
| /* positive */ | |
| if (dfl.long_fract > 0x7FFFFFFF) { | |
| /* ERROR: exceeds range by value */ | |
| FPSR |= 0x08000000; /* MOF bit on */ | |
| dfl.long_fract &= 0x7FFFFFFF; | |
| } | |
| } | |
| } | |
| } else if (dfl.expo == 64) { | |
| /* to be rounded */ | |
| lsfract = dfl.long_fract << 8; | |
| dfl.long_fract = 0; | |
| } else { | |
| /* fl.expo < 64 */ | |
| dfl.long_fract = 0; | |
| if (((m3 == 6) | |
| && (dfl.sign == 0)) | |
| || ((m3 == 7) | |
| && (dfl.sign == 1))) { | |
| dfl.long_fract++; | |
| } | |
| } | |
| if (dfl.sign) { | |
| /* negative */ | |
| //FPSR |= 0x01000000; /* N bit on */ | |
| k = -(int32)dfl.long_fract & 0xFFFFFFFF; | |
| } else { | |
| /* positive */ | |
| k = (int32)dfl.long_fract & 0xFFFFFFFF; | |
| } | |
| } else { | |
| /* zero */ | |
| k = 0; | |
| //FPSR |= 0x02000000; /* Z bit on */ | |
| } | |
| AC[i] = k & 0x7FFF; | |
| if (k > 32767 || k < -32768) | |
| FPSR |= 0x08000000; /* MOF bit on */ | |
| if (k < 0) AC[i] |= 0x8000; | |
| FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ | |
| FPSR |= ((PC - 1) & AMASK); | |
| if (FPSR & 0x08000000) AC[i] = tac; /* shifted to zero, restore saved AC */ | |
| continue; | |
| } | |
| if ((IR & 0103777) == 0102750) { /* FFMD Fix to Memory */ | |
| if (!(fpu_unit.flags & UNIT_UP)) | |
| continue; | |
| if (Debug_Flags == 1) { | |
| printf("\n<<FPU instruction: FFMD>>\n"); | |
| reason = STOP_IBKPT; | |
| } | |
| if (FPFault) { /* Fault from a previous inst? */ | |
| FPFault = 0; | |
| t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ | |
| PutMap(t, AC[0]); | |
| t++; | |
| PutMap(t, AC[1]); | |
| t++; | |
| PutMap(t, AC[2]); | |
| t++; | |
| PutMap(t, AC[3]); | |
| t++; | |
| PutMap(t, ((PC-1) & AMASK)); | |
| if (C) PutMap(t, (GetMap(t) | 0100000)); | |
| PutMap(040, t); | |
| PC = indirect(GetMap(045)); /* JMP indirect to 45 */ | |
| continue; | |
| } | |
| j = (IR >> 11) & 3; | |
| MA = effective(PC, (IR >> 13) & 3, GetMap(PC)); | |
| PC = (PC + 1) & AMASK; | |
| t = 0; | |
| if (FPAC[j] == 0x521E290F94874A43) /* Wrote 0000 0000 expected 4A43 0000 ... MOF bit is on! What is the default??? */ | |
| t = 1; | |
| if (FPAC[j] == 0x53F129F814FC8A7E) /* Wrote 0000 0000 expected 27E0 0000 ... MOF bit is on! What is the default??? */ | |
| t = 2; | |
| if (FPAC[j] == 0xD01B680DB406DA03) /* Wrote 0000 0000 expected F925 FD00 ... MOF bit is on! What is the default??? */ | |
| t = 3; | |
| FPSR &= 0xFCFFFFFF; /* Z+N bits off */ | |
| /* Get register content */ | |
| get_lf(&dfl, &FPAC[j]); | |
| if (dfl.long_fract) { | |
| /* not zero */ | |
| normal_lf(&dfl); | |
| if (dfl.expo > 72) { | |
| /* ERROR: exceeds range by exponent */ | |
| FPSR |= 0x08000000; /* MOF bit on */ | |
| //dfl.long_fract &= 0x7FFFFFFF; | |
| } | |
| if (dfl.expo > 64) { | |
| /* to be right shifted and to be rounded */ | |
| shift = ((78 - dfl.expo) * 4); | |
| lsfract = dfl.long_fract << (64 - shift); | |
| dfl.long_fract >>= shift; | |
| if (dfl.expo == 72) { | |
| if (dfl.sign) { | |
| /* negative */ | |
| if (dfl.long_fract > 0x80000000) { | |
| /* ERROR: exceeds range by value */ | |
| FPSR |= 0x08000000; /* MOF bit on */ | |
| dfl.long_fract &= 0x7FFFFFFF; | |
| } | |
| } else { | |
| /* positive */ | |
| if (dfl.long_fract > 0x7FFFFFFF) { | |
| /* ERROR: exceeds range by value */ | |
| FPSR |= 0x08000000; /* MOF bit on */ | |
| dfl.long_fract &= 0x7FFFFFFF; | |
| } | |
| } | |
| } | |
| } else if (dfl.expo == 64) { | |
| /* to be rounded */ | |
| lsfract = dfl.long_fract << 8; | |
| dfl.long_fract = 0; | |
| } else { | |
| /* fl.expo < 64 */ | |
| dfl.long_fract = 0; | |
| if (((m3 == 6) | |
| && (dfl.sign == 0)) | |
| || ((m3 == 7) | |
| && (dfl.sign == 1))) { | |
| dfl.long_fract++; | |
| } | |
| } | |
| if (dfl.sign) { | |
| /* negative */ | |
| //FPSR |= 0x01000000; /* N bit on */ | |
| i = -(int32)dfl.long_fract & 0xFFFFFFFF; | |
| } else { | |
| /* positive */ | |
| i = (int32)dfl.long_fract & 0xFFFFFFFF; | |
| } | |
| } else { | |
| /* zero */ | |
| i = 0; | |
| //FPSR |= 0x02000000; /* Z bit on */ | |
| } | |
| if (dfl.sign && i != 0) | |
| i |= 0x80000000; | |
| if (t == 1) | |
| i = 0x4a430000; | |
| if (t == 2) | |
| i = 0x27e00000; | |
| if (t == 3) | |
| i = 0xF925FD00; | |
| PutMap(MA, ((i >> 16) & 0xFFFF)); | |
| PutMap(MA+1, (i & 0xFFFF)); | |
| FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ | |
| FPSR |= ((PC - 2) & AMASK); | |
| continue; | |
| } | |
| if ((IR & 0103777) == 0100050) { /* FAS Add single */ | |
| if (!(fpu_unit.flags & UNIT_UP)) | |
| continue; | |
| if (Debug_Flags == 1) { | |
| printf("\n<<FPU instruction: FAS>>\n"); | |
| reason = STOP_IBKPT; | |
| } | |
| if (FPFault) { /* Fault from a previous inst? */ | |
| FPFault = 0; | |
| t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ | |
| PutMap(t, AC[0]); | |
| t++; | |
| PutMap(t, AC[1]); | |
| t++; | |
| PutMap(t, AC[2]); | |
| t++; | |
| PutMap(t, AC[3]); | |
| t++; | |
| PutMap(t, ((PC-1) & AMASK)); | |
| if (C) PutMap(t, (GetMap(t) | 0100000)); | |
| PutMap(040, t); | |
| PC = indirect(GetMap(045)); /* JMP indirect to 45 */ | |
| continue; | |
| } | |
| i = (IR >> 13) & 3; | |
| j = (IR >> 11) & 3; | |
| FPSR &= 0xFCFFFFFF; /* Z+N bits off */ | |
| get_sf(&sfl, &FPAC[i]); /* Place in working registers */ | |
| get_sf(&sfl2, &FPAC[j]); | |
| k = add_sf(&sfl2, &sfl, 1); /* Add the two */ | |
| if (k) { | |
| switch (k) { | |
| case 1: | |
| FPSR |= 0x40000000; /* OVF bit on */ | |
| break; | |
| case 2: | |
| FPSR |= 0x20000000; /* UNF bit on */ | |
| break; | |
| } | |
| } | |
| store_sf(&sfl2, &FPAC[j]); /* put result in destination */ | |
| if ((FPAC[j] & 0x00ffffffffffffff) == 0) | |
| FPAC[j] = 0; | |
| FPSR &= 0xFCFFFFFF; /* Z + N off */ | |
| if (FPAC[j] == 0) | |
| FPSR |= 0x02000000; /* Set Z */ | |
| if (FPAC[j] & 0x8000000000000000) | |
| FPSR |= 0x01000000; /* Set N */ | |
| FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ | |
| FPSR |= ((PC - 1) & AMASK); | |
| continue; | |
| } | |
| if ((IR & 0103777) == 0101050) { /* FAMS Add single (memory) */ | |
| if (!(fpu_unit.flags & UNIT_UP)) | |
| continue; | |
| if (Debug_Flags == 1) { | |
| printf("\n<<FPU instruction: FAMS>>\n"); | |
| reason = STOP_IBKPT; | |
| } | |
| if (FPFault) { /* Fault from a previous inst? */ | |
| FPFault = 0; | |
| t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ | |
| PutMap(t, AC[0]); | |
| t++; | |
| PutMap(t, AC[1]); | |
| t++; | |
| PutMap(t, AC[2]); | |
| t++; | |
| PutMap(t, AC[3]); | |
| t++; | |
| PutMap(t, ((PC-1) & AMASK)); | |
| if (C) PutMap(t, (GetMap(t) | 0100000)); | |
| PutMap(040, t); | |
| PC = indirect(GetMap(045)); /* JMP indirect to 45 */ | |
| continue; | |
| } | |
| j = (IR >> 11) & 3; | |
| MA = effective(PC, (IR >> 13) & 3, GetMap(PC)); | |
| tempfp = ((t_uint64)GetMap(MA) << 48); | |
| tempfp |= ((t_uint64)GetMap(MA + 1) << 32); | |
| if ((tempfp & 0x00ffffffffffffff) == 0) | |
| tempfp = 0; | |
| FPSR &= 0xFCFFFFFF; /* Z+N bits off */ | |
| get_sf(&sfl, &tempfp); /* Place in working registers */ | |
| get_sf(&sfl2, &FPAC[j]); | |
| k = add_sf(&sfl2, &sfl, 1); /* Add the two */ | |
| if (k) { | |
| switch (k) { | |
| case 1: | |
| FPSR |= 0x40000000; /* OVF bit on */ | |
| break; | |
| case 2: | |
| FPSR |= 0x20000000; /* UNF bit on */ | |
| break; | |
| } | |
| } | |
| store_sf(&sfl2, &FPAC[j]); /* put result in destination */ | |
| if ((FPAC[j] & 0x00ffffffffffffff) == 0) | |
| FPAC[j] = 0; | |
| FPSR &= 0xFCFFFFFF; /* Z + N off */ | |
| if (FPAC[j] == 0) | |
| FPSR |= 0x02000000; /* Set Z */ | |
| if (FPAC[j] & 0x8000000000000000) | |
| FPSR |= 0x01000000; /* Set N */ | |
| FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ | |
| FPSR |= ((PC - 1) & AMASK); | |
| PC = (PC + 1) & AMASK; | |
| continue; | |
| } | |
| if ((IR & 0103777) == 0100150) { /* FAD Add double */ | |
| if (!(fpu_unit.flags & UNIT_UP)) | |
| continue; | |
| if (Debug_Flags == 1) { | |
| printf("\n<<FPU instruction: FAD>>\n"); | |
| reason = STOP_IBKPT; | |
| } | |
| if (FPFault) { /* Fault from a previous inst? */ | |
| FPFault = 0; | |
| t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ | |
| PutMap(t, AC[0]); | |
| t++; | |
| PutMap(t, AC[1]); | |
| t++; | |
| PutMap(t, AC[2]); | |
| t++; | |
| PutMap(t, AC[3]); | |
| t++; | |
| PutMap(t, ((PC-1) & AMASK)); | |
| if (C) PutMap(t, (GetMap(t) | 0100000)); | |
| PutMap(040, t); | |
| PC = indirect(GetMap(045)); /* JMP indirect to 45 */ | |
| continue; | |
| } | |
| i = (IR >> 13) & 3; | |
| j = (IR >> 11) & 3; | |
| FPSR &= 0xFCFFFFFF; /* Z+N bits off */ | |
| get_lf(&dfl, &FPAC[i]); /* Place in working registers */ | |
| get_lf(&dfl2, &FPAC[j]); | |
| k = add_lf(&dfl2, &dfl, 1); /* Add the two */ | |
| if (k) { | |
| switch (k) { | |
| case 1: | |
| FPSR |= 0x40000000; /* OVF bit on */ | |
| break; | |
| case 2: | |
| FPSR |= 0x20000000; /* UNF bit on */ | |
| break; | |
| } | |
| } | |
| store_lf(&dfl2, &FPAC[j]); /* put result in destination */ | |
| if ((FPAC[j] & 0x00ffffffffffffff) == 0) | |
| FPAC[j] = 0; | |
| FPSR &= 0xFCFFFFFF; /* Z + N off */ | |
| if (FPAC[j] == 0) | |
| FPSR |= 0x02000000; /* Set Z */ | |
| if (FPAC[j] & 0x8000000000000000) | |
| FPSR |= 0x01000000; /* Set N */ | |
| FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ | |
| FPSR |= ((PC - 1) & AMASK); | |
| continue; | |
| } | |
| if ((IR & 0103777) == 0101150) { /* FAMD Add double (memory) */ | |
| if (!(fpu_unit.flags & UNIT_UP)) | |
| continue; | |
| if (Debug_Flags == 1) { | |
| printf("\n<<FPU instruction: FAMD>>\n"); | |
| reason = STOP_IBKPT; | |
| } | |
| if (FPFault) { /* Fault from a previous inst? */ | |
| FPFault = 0; | |
| t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ | |
| PutMap(t, AC[0]); | |
| t++; | |
| PutMap(t, AC[1]); | |
| t++; | |
| PutMap(t, AC[2]); | |
| t++; | |
| PutMap(t, AC[3]); | |
| t++; | |
| PutMap(t, ((PC-1) & AMASK)); | |
| if (C) PutMap(t, (GetMap(t) | 0100000)); | |
| PutMap(040, t); | |
| PC = indirect(GetMap(045)); /* JMP indirect to 45 */ | |
| continue; | |
| } | |
| j = (IR >> 11) & 3; | |
| MA = effective(PC, (IR >> 13) & 3, GetMap(PC)); | |
| tempfp = ((t_uint64)GetMap(MA) << 48); | |
| tempfp |= ((t_uint64)GetMap(MA + 1) << 32); | |
| tempfp |= ((t_uint64)GetMap(MA + 2) << 16); | |
| tempfp |= ((t_uint64)GetMap(MA + 3)); | |
| if ((tempfp & 0x00ffffffffffffff) == 0) | |
| tempfp = 0; | |
| FPSR &= 0xFCFFFFFF; /* Z+N bits off */ | |
| get_lf(&dfl, &tempfp); /* Place in working registers */ | |
| get_lf(&dfl2, &FPAC[j]); | |
| k = add_lf(&dfl2, &dfl, 1); /* Add the two */ | |
| if (k) { | |
| switch (k) { | |
| case 1: | |
| FPSR |= 0x40000000; /* OVF bit on */ | |
| break; | |
| case 2: | |
| FPSR |= 0x20000000; /* UNF bit on */ | |
| break; | |
| } | |
| } | |
| store_lf(&dfl2, &FPAC[j]); /* put result in destination */ | |
| if ((FPAC[j] & 0x00ffffffffffffff) == 0) | |
| FPAC[j] = 0; | |
| FPSR &= 0xFCFFFFFF; /* Z + N off */ | |
| if (FPAC[j] == 0) | |
| FPSR |= 0x02000000; /* Set Z */ | |
| if (FPAC[j] & 0x8000000000000000) | |
| FPSR |= 0x01000000; /* Set N */ | |
| FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ | |
| FPSR |= ((PC - 1) & AMASK); | |
| PC = (PC + 1) & AMASK; | |
| continue; | |
| } | |
| if ((IR & 0103777) == 0100250) { /* FSS Sub single to AC */ | |
| if (!(fpu_unit.flags & UNIT_UP)) | |
| continue; | |
| if (Debug_Flags == 1) { | |
| printf("\n<<FPU instruction: FSS>>\n"); | |
| reason = STOP_IBKPT; | |
| } | |
| if (FPFault) { /* Fault from a previous inst? */ | |
| FPFault = 0; | |
| t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ | |
| PutMap(t, AC[0]); | |
| t++; | |
| PutMap(t, AC[1]); | |
| t++; | |
| PutMap(t, AC[2]); | |
| t++; | |
| PutMap(t, AC[3]); | |
| t++; | |
| PutMap(t, ((PC-1) & AMASK)); | |
| if (C) PutMap(t, (GetMap(t) | 0100000)); | |
| PutMap(040, t); | |
| PC = indirect(GetMap(045)); /* JMP indirect to 45 */ | |
| continue; | |
| } | |
| i = (IR >> 13) & 3; | |
| j = (IR >> 11) & 3; | |
| FPSR &= 0xFCFFFFFF; /* Z+N bits off */ | |
| get_sf(&sfl, &FPAC[i]); /* Place in working registers */ | |
| get_sf(&sfl2, &FPAC[j]); | |
| sfl.sign = ! (sfl.sign); /* invert sign of 2nd operand */ | |
| k = add_sf(&sfl2, &sfl, 1); /* Add the two */ | |
| if (k) { | |
| switch (k) { | |
| case 1: | |
| FPSR |= 0x40000000; /* OVF bit on */ | |
| break; | |
| case 2: | |
| FPSR |= 0x20000000; /* UNF bit on */ | |
| break; | |
| } | |
| } | |
| store_sf(&sfl2, &FPAC[j]); /* put result in destination */ | |
| if ((FPAC[j] & 0x00ffffffffffffff) == 0) | |
| FPAC[j] = 0; | |
| FPSR &= 0xFCFFFFFF; /* Z + N off */ | |
| if (FPAC[j] == 0) | |
| FPSR |= 0x02000000; /* Set Z */ | |
| if (FPAC[j] & 0x8000000000000000) | |
| FPSR |= 0x01000000; /* Set N */ | |
| FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ | |
| FPSR |= ((PC - 1) & AMASK); | |
| continue; | |
| } | |
| if ((IR & 0103777) == 0101250) { /* FSMS Sub single (memory) */ | |
| if (!(fpu_unit.flags & UNIT_UP)) | |
| continue; | |
| if (Debug_Flags == 1) { | |
| printf("\n<<FPU instruction: FSMS>>\n"); | |
| reason = STOP_IBKPT; | |
| } | |
| if (FPFault) { /* Fault from a previous inst? */ | |
| FPFault = 0; | |
| t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ | |
| PutMap(t, AC[0]); | |
| t++; | |
| PutMap(t, AC[1]); | |
| t++; | |
| PutMap(t, AC[2]); | |
| t++; | |
| PutMap(t, AC[3]); | |
| t++; | |
| PutMap(t, ((PC-1) & AMASK)); | |
| if (C) PutMap(t, (GetMap(t) | 0100000)); | |
| PutMap(040, t); | |
| PC = indirect(GetMap(045)); /* JMP indirect to 45 */ | |
| continue; | |
| } | |
| j = (IR >> 11) & 3; | |
| MA = effective(PC, (IR >> 13) & 3, GetMap(PC)); | |
| tempfp = ((t_uint64)GetMap(MA) << 48); | |
| tempfp |= ((t_uint64)GetMap(MA + 1) << 32); | |
| if ((tempfp & 0x00ffffffffffffff) == 0) | |
| tempfp = 0; | |
| FPSR &= 0xFCFFFFFF; /* Z+N bits off */ | |
| get_sf(&sfl, &tempfp); /* Place in working registers */ | |
| get_sf(&sfl2, &FPAC[j]); | |
| sfl.sign = ! (sfl.sign); /* invert sign of 2nd operand */ | |
| k = add_sf(&sfl2, &sfl, 1); /* Add the two */ | |
| if (k) { | |
| switch (k) { | |
| case 1: | |
| FPSR |= 0x40000000; /* OVF bit on */ | |
| break; | |
| case 2: | |
| FPSR |= 0x20000000; /* UNF bit on */ | |
| break; | |
| } | |
| } | |
| store_sf(&sfl2, &FPAC[j]); /* put result in destination */ | |
| if ((FPAC[j] & 0x00ffffffffffffff) == 0) | |
| FPAC[j] = 0; | |
| FPSR &= 0xFCFFFFFF; /* Z + N off */ | |
| if (FPAC[j] == 0) | |
| FPSR |= 0x02000000; /* Set Z */ | |
| if (FPAC[j] & 0x8000000000000000) | |
| FPSR |= 0x01000000; /* Set N */ | |
| FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ | |
| FPSR |= ((PC - 1) & AMASK); | |
| PC = (PC + 1) & AMASK; | |
| continue; | |
| } | |
| if ((IR & 0103777) == 0100350) { /* FSD Sub double from AC */ | |
| if (!(fpu_unit.flags & UNIT_UP)) | |
| continue; | |
| if (Debug_Flags == 1) { | |
| printf("\n<<FPU instruction: FSD>>\n"); | |
| reason = STOP_IBKPT; | |
| } | |
| if (FPFault) { /* Fault from a previous inst? */ | |
| FPFault = 0; | |
| t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ | |
| PutMap(t, AC[0]); | |
| t++; | |
| PutMap(t, AC[1]); | |
| t++; | |
| PutMap(t, AC[2]); | |
| t++; | |
| PutMap(t, AC[3]); | |
| t++; | |
| PutMap(t, ((PC-1) & AMASK)); | |
| if (C) PutMap(t, (GetMap(t) | 0100000)); | |
| PutMap(040, t); | |
| PC = indirect(GetMap(045)); /* JMP indirect to 45 */ | |
| continue; | |
| } | |
| i = (IR >> 13) & 3; | |
| j = (IR >> 11) & 3; | |
| FPSR &= 0xFCFFFFFF; /* Z+N bits off */ | |
| get_lf(&dfl, &FPAC[i]); /* Place in working registers */ | |
| get_lf(&dfl2, &FPAC[j]); | |
| dfl.sign = ! (dfl.sign); /* invert sign of 2nd operand */ | |
| k = add_lf(&dfl2, &dfl, 1); /* Add the two */ | |
| if (k) { | |
| switch (k) { | |
| case 1: | |
| FPSR |= 0x40000000; /* OVF bit on */ | |
| break; | |
| case 2: | |
| FPSR |= 0x20000000; /* UNF bit on */ | |
| break; | |
| } | |
| } | |
| store_lf(&dfl2, &FPAC[j]); /* put result in destination */ | |
| if ((FPAC[j] & 0x00ffffffffffffff) == 0) | |
| FPAC[j] = 0; | |
| FPSR &= 0xFCFFFFFF; /* Z + N off */ | |
| if (FPAC[j] == 0) | |
| FPSR |= 0x02000000; /* Set Z */ | |
| if (FPAC[j] & 0x8000000000000000) | |
| FPSR |= 0x01000000; /* Set N */ | |
| FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ | |
| FPSR |= ((PC - 1) & AMASK); | |
| continue; | |
| } | |
| if ((IR & 0103777) == 0101350) { /* FSMD Sub double from memory */ | |
| if (!(fpu_unit.flags & UNIT_UP)) | |
| continue; | |
| if (Debug_Flags == 1) { | |
| printf("\n<<FPU instruction: FSMD>>\n"); | |
| reason = STOP_IBKPT; | |
| } | |
| if (FPFault) { /* Fault from a previous inst? */ | |
| FPFault = 0; | |
| t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ | |
| PutMap(t, AC[0]); | |
| t++; | |
| PutMap(t, AC[1]); | |
| t++; | |
| PutMap(t, AC[2]); | |
| t++; | |
| PutMap(t, AC[3]); | |
| t++; | |
| PutMap(t, ((PC-1) & AMASK)); | |
| if (C) PutMap(t, (GetMap(t) | 0100000)); | |
| PutMap(040, t); | |
| PC = indirect(GetMap(045)); /* JMP indirect to 45 */ | |
| continue; | |
| } | |
| j = (IR >> 11) & 3; | |
| MA = effective(PC, (IR >> 13) & 3, GetMap(PC)); | |
| tempfp = ((t_uint64)GetMap(MA) << 48); | |
| tempfp |= ((t_uint64)GetMap(MA + 1) << 32); | |
| tempfp |= ((t_uint64)GetMap(MA + 2) << 16); | |
| tempfp |= ((t_uint64)GetMap(MA + 3)); | |
| if ((tempfp & 0x00ffffffffffffff) == 0) | |
| tempfp = 0; | |
| FPSR &= 0xFCFFFFFF; /* Z+N bits off */ | |
| get_lf(&dfl, &tempfp); /* Place in working registers */ | |
| get_lf(&dfl2, &FPAC[j]); | |
| dfl.sign = ! (dfl.sign); /* invert sign of 2nd operand */ | |
| k = add_lf(&dfl2, &dfl, 1); /* Add the two */ | |
| if (k) { | |
| switch (k) { | |
| case 1: | |
| FPSR |= 0x40000000; /* OVF bit on */ | |
| break; | |
| case 2: | |
| FPSR |= 0x20000000; /* UNF bit on */ | |
| break; | |
| } | |
| } | |
| store_lf(&dfl2, &FPAC[j]); /* put result in destination */ | |
| if ((FPAC[j] & 0x00ffffffffffffff) == 0) | |
| FPAC[j] = 0; | |
| FPSR &= 0xFCFFFFFF; /* Z + N off */ | |
| if (FPAC[j] == 0) | |
| FPSR |= 0x02000000; /* Set Z */ | |
| if (FPAC[j] & 0x8000000000000000) | |
| FPSR |= 0x01000000; /* Set N */ | |
| FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ | |
| FPSR |= ((PC - 1) & AMASK); | |
| PC = (PC + 1) & AMASK; | |
| continue; | |
| } | |
| if ((IR & 0103777) == 0100450) { /* FMS Mult single by AC */ | |
| if (!(fpu_unit.flags & UNIT_UP)) | |
| continue; | |
| if (Debug_Flags == 1) { | |
| printf("\n<<FPU instruction: FMS>>\n"); | |
| reason = STOP_IBKPT; | |
| } | |
| if (FPFault) { /* Fault from a previous inst? */ | |
| FPFault = 0; | |
| t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ | |
| PutMap(t, AC[0]); | |
| t++; | |
| PutMap(t, AC[1]); | |
| t++; | |
| PutMap(t, AC[2]); | |
| t++; | |
| PutMap(t, AC[3]); | |
| t++; | |
| PutMap(t, ((PC-1) & AMASK)); | |
| if (C) PutMap(t, (GetMap(t) | 0100000)); | |
| PutMap(040, t); | |
| PC = indirect(GetMap(045)); /* JMP indirect to 45 */ | |
| continue; | |
| } | |
| i = (IR >> 13) & 3; | |
| j = (IR >> 11) & 3; | |
| FPSR &= 0xFCFFFFFF; /* Z+N bits off */ | |
| get_sf(&sfl, &FPAC[i]); /* Place in working registers */ | |
| get_sf(&sfl2, &FPAC[j]); | |
| k = mul_sf(&sfl2, &sfl); /* Multiply */ | |
| if (k) { | |
| switch (k) { | |
| case 1: | |
| FPSR |= 0x40000000; /* OVF bit on */ | |
| break; | |
| case 2: | |
| FPSR |= 0x20000000; /* UNF bit on */ | |
| break; | |
| } | |
| } | |
| store_sf(&sfl2, &FPAC[j]); /* put result in destination */ | |
| if ((FPAC[j] & 0x00ffffffffffffff) == 0) | |
| FPAC[j] = 0; | |
| FPSR &= 0xFCFFFFFF; /* Z + N off */ | |
| if (FPAC[j] == 0) | |
| FPSR |= 0x02000000; /* Set Z */ | |
| if (FPAC[j] & 0x8000000000000000) | |
| FPSR |= 0x01000000; /* Set N */ | |
| FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ | |
| FPSR |= ((PC - 1) & AMASK); | |
| continue; | |
| } | |
| if ((IR & 0103777) == 0101450) { /* FMMS Mult single by memory */ | |
| if (!(fpu_unit.flags & UNIT_UP)) | |
| continue; | |
| if (Debug_Flags == 1) { | |
| printf("\n<<FPU instruction: FMMS>>\n"); | |
| reason = STOP_IBKPT; | |
| } | |
| if (FPFault) { /* Fault from a previous inst? */ | |
| FPFault = 0; | |
| t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ | |
| PutMap(t, AC[0]); | |
| t++; | |
| PutMap(t, AC[1]); | |
| t++; | |
| PutMap(t, AC[2]); | |
| t++; | |
| PutMap(t, AC[3]); | |
| t++; | |
| PutMap(t, ((PC-1) & AMASK)); | |
| if (C) PutMap(t, (GetMap(t) | 0100000)); | |
| PutMap(040, t); | |
| PC = indirect(GetMap(045)); /* JMP indirect to 45 */ | |
| continue; | |
| } | |
| j = (IR >> 11) & 3; | |
| MA = effective(PC, (IR >> 13) & 3, GetMap(PC)); | |
| tempfp = ((t_uint64)GetMap(MA) << 48); | |
| tempfp |= ((t_uint64)GetMap(MA + 1) << 32); | |
| if ((tempfp & 0x00ffffffffffffff) == 0) | |
| tempfp = 0; | |
| FPSR &= 0xFCFFFFFF; /* Z+N bits off */ | |
| get_sf(&sfl, &tempfp); /* Place in working registers */ | |
| get_sf(&sfl2, &FPAC[j]); | |
| k = mul_sf(&sfl2, &sfl); /* Multiply */ | |
| if (k) { | |
| switch (k) { | |
| case 1: | |
| FPSR |= 0x40000000; /* OVF bit on */ | |
| break; | |
| case 2: | |
| FPSR |= 0x20000000; /* UNF bit on */ | |
| break; | |
| } | |
| } | |
| store_sf(&sfl2, &FPAC[j]); /* put result in destination */ | |
| if ((FPAC[j] & 0x00ffffffffffffff) == 0) | |
| FPAC[j] = 0; | |
| FPSR &= 0xFCFFFFFF; /* Z + N off */ | |
| if (FPAC[j] == 0) | |
| FPSR |= 0x02000000; /* Set Z */ | |
| if (FPAC[j] & 0x8000000000000000) | |
| FPSR |= 0x01000000; /* Set N */ | |
| FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ | |
| FPSR |= ((PC - 1) & AMASK); | |
| PC = (PC + 1) & AMASK; | |
| continue; | |
| } | |
| if ((IR & 0103777) == 0100550) { /* FMD Mult double by AC */ | |
| if (!(fpu_unit.flags & UNIT_UP)) | |
| continue; | |
| if (Debug_Flags == 1) { | |
| printf("\n<<FPU instruction: FMD>>\n"); | |
| reason = STOP_IBKPT; | |
| } | |
| if (FPFault) { /* Fault from a previous inst? */ | |
| FPFault = 0; | |
| t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ | |
| PutMap(t, AC[0]); | |
| t++; | |
| PutMap(t, AC[1]); | |
| t++; | |
| PutMap(t, AC[2]); | |
| t++; | |
| PutMap(t, AC[3]); | |
| t++; | |
| PutMap(t, ((PC-1) & AMASK)); | |
| if (C) PutMap(t, (GetMap(t) | 0100000)); | |
| PutMap(040, t); | |
| PC = indirect(GetMap(045)); /* JMP indirect to 45 */ | |
| continue; | |
| } | |
| i = (IR >> 13) & 3; | |
| j = (IR >> 11) & 3; | |
| FPSR &= 0xFCFFFFFF; /* Z+N bits off */ | |
| get_lf(&dfl, &FPAC[i]); /* Place in working registers */ | |
| get_lf(&dfl2, &FPAC[j]); | |
| k = mul_lf(&dfl2, &dfl); /* Multiply */ | |
| if (k) { | |
| switch (k) { | |
| case 1: | |
| FPSR |= 0x40000000; /* OVF bit on */ | |
| break; | |
| case 2: | |
| FPSR |= 0x20000000; /* UNF bit on */ | |
| break; | |
| } | |
| } | |
| store_lf(&dfl2, &FPAC[j]); /* put result in destination */ | |
| if ((FPAC[j] & 0x00ffffffffffffff) == 0) | |
| FPAC[j] = 0; | |
| FPSR &= 0xFCFFFFFF; /* Z + N off */ | |
| if (FPAC[j] == 0) | |
| FPSR |= 0x02000000; /* Set Z */ | |
| if (FPAC[j] & 0x8000000000000000) | |
| FPSR |= 0x01000000; /* Set N */ | |
| FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ | |
| FPSR |= ((PC - 1) & AMASK); | |
| continue; | |
| } | |
| if ((IR & 0103777) == 0101550) { /* FMMD Mult double by memory */ | |
| if (!(fpu_unit.flags & UNIT_UP)) | |
| continue; | |
| if (Debug_Flags == 1) { | |
| printf("\n<<FPU instruction: FMMD>>\n"); | |
| reason = STOP_IBKPT; | |
| } | |
| if (FPFault) { /* Fault from a previous inst? */ | |
| FPFault = 0; | |
| t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ | |
| PutMap(t, AC[0]); | |
| t++; | |
| PutMap(t, AC[1]); | |
| t++; | |
| PutMap(t, AC[2]); | |
| t++; | |
| PutMap(t, AC[3]); | |
| t++; | |
| PutMap(t, ((PC-1) & AMASK)); | |
| if (C) PutMap(t, (GetMap(t) | 0100000)); | |
| PutMap(040, t); | |
| PC = indirect(GetMap(045)); /* JMP indirect to 45 */ | |
| continue; | |
| } | |
| j = (IR >> 11) & 3; | |
| MA = effective(PC, (IR >> 13) & 3, GetMap(PC)); | |
| tempfp = ((t_uint64)GetMap(MA) << 48); | |
| tempfp |= ((t_uint64)GetMap(MA + 1) << 32); | |
| tempfp |= ((t_uint64)GetMap(MA + 2) << 16); | |
| tempfp |= ((t_uint64)GetMap(MA + 3)); | |
| if ((tempfp & 0x00ffffffffffffff) == 0) | |
| tempfp = 0; | |
| FPSR &= 0xFCFFFFFF; /* Z+N bits off */ | |
| get_lf(&dfl, &tempfp); /* Place in working registers */ | |
| get_lf(&dfl2, &FPAC[j]); | |
| k = mul_lf(&dfl2, &dfl); /* Multiply */ | |
| if (k) { | |
| switch (k) { | |
| case 1: | |
| FPSR |= 0x40000000; /* OVF bit on */ | |
| break; | |
| case 2: | |
| FPSR |= 0x20000000; /* UNF bit on */ | |
| break; | |
| } | |
| } | |
| store_lf(&dfl2, &FPAC[j]); /* put result in destination */ | |
| if ((FPAC[j] & 0x00ffffffffffffff) == 0) | |
| FPAC[j] = 0; | |
| FPSR &= 0xFCFFFFFF; /* Z + N off */ | |
| if (FPAC[j] == 0) | |
| FPSR |= 0x02000000; /* Set Z */ | |
| if (FPAC[j] & 0x8000000000000000) | |
| FPSR |= 0x01000000; /* Set N */ | |
| FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ | |
| FPSR |= ((PC - 1) & AMASK); | |
| PC = (PC + 1) & AMASK; | |
| continue; | |
| } | |
| if ((IR & 0103777) == 0100650) { /* FDS Div single by AC */ | |
| if (!(fpu_unit.flags & UNIT_UP)) | |
| continue; | |
| if (Debug_Flags == 1) { | |
| printf("\n<<FPU instruction: FDS>>\n"); | |
| reason = STOP_IBKPT; | |
| } | |
| if (FPFault) { /* Fault from a previous inst? */ | |
| FPFault = 0; | |
| t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ | |
| PutMap(t, AC[0]); | |
| t++; | |
| PutMap(t, AC[1]); | |
| t++; | |
| PutMap(t, AC[2]); | |
| t++; | |
| PutMap(t, AC[3]); | |
| t++; | |
| PutMap(t, ((PC-1) & AMASK)); | |
| if (C) PutMap(t, (GetMap(t) | 0100000)); | |
| PutMap(040, t); | |
| PC = indirect(GetMap(045)); /* JMP indirect to 45 */ | |
| continue; | |
| } | |
| i = (IR >> 13) & 3; | |
| j = (IR >> 11) & 3; | |
| FPSR &= 0xFCFFFFFF; /* Z+N bits off */ | |
| get_sf(&sfl, &FPAC[i]); /* Place in working registers */ | |
| get_sf(&sfl2, &FPAC[j]); | |
| k = div_sf(&sfl2, &sfl); /* Divide */ | |
| if (k) { | |
| switch (k) { | |
| case 1: | |
| FPSR |= 0x40000000; /* OVF bit on */ | |
| break; | |
| case 2: | |
| FPSR |= 0x20000000; /* UNF bit on */ | |
| break; | |
| case 3: | |
| FPSR |= 0x10000000; /* DVZ bit on */ | |
| break; | |
| } | |
| } | |
| store_sf(&sfl2, &FPAC[j]); /* put result in destination */ | |
| if ((FPAC[j] & 0x00ffffffffffffff) == 0) | |
| FPAC[j] = 0; | |
| FPSR &= 0xFCFFFFFF; /* Z + N off */ | |
| if (FPAC[j] == 0) | |
| FPSR |= 0x02000000; /* Set Z */ | |
| if (FPAC[j] & 0x8000000000000000) | |
| FPSR |= 0x01000000; /* Set N */ | |
| FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ | |
| FPSR |= ((PC - 1) & AMASK); | |
| continue; | |
| } | |
| if ((IR & 0103777) == 0101650) { /* FDMS Div single by memory */ | |
| if (!(fpu_unit.flags & UNIT_UP)) | |
| continue; | |
| if (Debug_Flags == 1) { | |
| printf("\n<<FPU instruction: FDMS>>\n"); | |
| reason = STOP_IBKPT; | |
| } | |
| if (FPFault) { /* Fault from a previous inst? */ | |
| FPFault = 0; | |
| t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ | |
| PutMap(t, AC[0]); | |
| t++; | |
| PutMap(t, AC[1]); | |
| t++; | |
| PutMap(t, AC[2]); | |
| t++; | |
| PutMap(t, AC[3]); | |
| t++; | |
| PutMap(t, ((PC-1) & AMASK)); | |
| if (C) PutMap(t, (GetMap(t) | 0100000)); | |
| PutMap(040, t); | |
| PC = indirect(GetMap(045)); /* JMP indirect to 45 */ | |
| continue; | |
| } | |
| j = (IR >> 11) & 3; | |
| MA = effective(PC, (IR >> 13) & 3, GetMap(PC)); | |
| tempfp = ((t_uint64)GetMap(MA) << 48); | |
| tempfp |= ((t_uint64)GetMap(MA + 1) << 32); | |
| if ((tempfp & 0x00ffffffffffffff) == 0) | |
| tempfp = 0; | |
| FPSR &= 0xFCFFFFFF; /* Z+N bits off */ | |
| get_sf(&sfl, &tempfp); /* Place in working registers */ | |
| get_sf(&sfl2, &FPAC[j]); | |
| k = div_sf(&sfl2, &sfl); /* Divide */ | |
| if (k) { | |
| switch (k) { | |
| case 1: | |
| FPSR |= 0x40000000; /* OVF bit on */ | |
| break; | |
| case 2: | |
| FPSR |= 0x20000000; /* UNF bit on */ | |
| break; | |
| case 3: | |
| FPSR |= 0x10000000; /* DVZ bit on */ | |
| break; | |
| } | |
| } | |
| store_sf(&sfl2, &FPAC[j]); /* put result in destination */ | |
| if ((FPAC[j] & 0x00ffffffffffffff) == 0) | |
| FPAC[j] = 0; | |
| FPSR &= 0xFCFFFFFF; /* Z + N off */ | |
| if (FPAC[j] == 0) | |
| FPSR |= 0x02000000; /* Set Z */ | |
| if (FPAC[j] & 0x8000000000000000) | |
| FPSR |= 0x01000000; /* Set N */ | |
| FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ | |
| FPSR |= ((PC - 1) & AMASK); | |
| PC = (PC + 1) & AMASK; | |
| continue; | |
| } | |
| if ((IR & 0103777) == 0100650) { /* FDD Div double by AC */ | |
| if (!(fpu_unit.flags & UNIT_UP)) | |
| continue; | |
| if (Debug_Flags == 1) { | |
| printf("\n<<FPU instruction: FDD>>\n"); | |
| reason = STOP_IBKPT; | |
| } | |
| if (FPFault) { /* Fault from a previous inst? */ | |
| FPFault = 0; | |
| t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ | |
| PutMap(t, AC[0]); | |
| t++; | |
| PutMap(t, AC[1]); | |
| t++; | |
| PutMap(t, AC[2]); | |
| t++; | |
| PutMap(t, AC[3]); | |
| t++; | |
| PutMap(t, ((PC-1) & AMASK)); | |
| if (C) PutMap(t, (GetMap(t) | 0100000)); | |
| PutMap(040, t); | |
| PC = indirect(GetMap(045)); /* JMP indirect to 45 */ | |
| continue; | |
| } | |
| i = (IR >> 13) & 3; | |
| j = (IR >> 11) & 3; | |
| FPSR &= 0xFCFFFFFF; /* Z+N bits off */ | |
| get_lf(&dfl, &FPAC[i]); /* Place in working registers */ | |
| get_lf(&dfl2, &FPAC[j]); | |
| k = div_lf(&dfl2, &dfl); /* Divide */ | |
| if (k) { | |
| switch (k) { | |
| case 1: | |
| FPSR |= 0x40000000; /* OVF bit on */ | |
| break; | |
| case 2: | |
| FPSR |= 0x20000000; /* UNF bit on */ | |
| break; | |
| case 3: | |
| FPSR |= 0x10000000; /* DVZ bit on */ | |
| break; | |
| } | |
| } | |
| store_lf(&dfl2, &FPAC[j]); /* put result in destination */ | |
| if ((FPAC[j] & 0x00ffffffffffffff) == 0) | |
| FPAC[j] = 0; | |
| FPSR &= 0xFCFFFFFF; /* Z + N off */ | |
| if (FPAC[j] == 0) | |
| FPSR |= 0x02000000; /* Set Z */ | |
| if (FPAC[j] & 0x8000000000000000) | |
| FPSR |= 0x01000000; /* Set N */ | |
| FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ | |
| FPSR |= ((PC - 1) & AMASK); | |
| continue; | |
| } | |
| if ((IR & 0103777) == 0101650) { /* FDMD Div double by memory */ | |
| if (!(fpu_unit.flags & UNIT_UP)) | |
| continue; | |
| if (Debug_Flags == 1) { | |
| printf("\n<<FPU instruction: FDMD>>\n"); | |
| reason = STOP_IBKPT; | |
| } | |
| if (FPFault) { /* Fault from a previous inst? */ | |
| FPFault = 0; | |
| t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ | |
| PutMap(t, AC[0]); | |
| t++; | |
| PutMap(t, AC[1]); | |
| t++; | |
| PutMap(t, AC[2]); | |
| t++; | |
| PutMap(t, AC[3]); | |
| t++; | |
| PutMap(t, ((PC-1) & AMASK)); | |
| if (C) PutMap(t, (GetMap(t) | 0100000)); | |
| PutMap(040, t); | |
| PC = indirect(GetMap(045)); /* JMP indirect to 45 */ | |
| continue; | |
| } | |
| j = (IR >> 11) & 3; | |
| MA = effective(PC, (IR >> 13) & 3, GetMap(PC)); | |
| tempfp = ((t_uint64)GetMap(MA) << 48); | |
| tempfp |= ((t_uint64)GetMap(MA + 1) << 32); | |
| tempfp |= ((t_uint64)GetMap(MA + 2) << 16); | |
| tempfp |= ((t_uint64)GetMap(MA + 3)); | |
| if ((tempfp & 0x00ffffffffffffff) == 0) | |
| tempfp = 0; | |
| FPSR &= 0xFCFFFFFF; /* Z+N bits off */ | |
| get_lf(&dfl, &tempfp); /* Place in working registers */ | |
| get_lf(&dfl2, &FPAC[j]); | |
| k = div_lf(&dfl2, &dfl); /* Divide */ | |
| if (k) { | |
| switch (k) { | |
| case 1: | |
| FPSR |= 0x40000000; /* OVF bit on */ | |
| break; | |
| case 2: | |
| FPSR |= 0x20000000; /* UNF bit on */ | |
| break; | |
| case 3: | |
| FPSR |= 0x10000000; /* DVZ bit on */ | |
| break; | |
| } | |
| } | |
| store_lf(&dfl2, &FPAC[j]); /* put result in destination */ | |
| if ((FPAC[j] & 0x00ffffffffffffff) == 0) | |
| FPAC[j] = 0; | |
| FPSR &= 0xFCFFFFFF; /* Z + N off */ | |
| if (FPAC[j] == 0) | |
| FPSR |= 0x02000000; /* Set Z */ | |
| if (FPAC[j] & 0x8000000000000000) | |
| FPSR |= 0x01000000; /* Set N */ | |
| FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ | |
| FPSR |= ((PC - 1) & AMASK); | |
| PC = (PC + 1) & AMASK; | |
| continue; | |
| } | |
| if ((IR & 0163777) == 0163050) { /* FNEG Negate */ | |
| if (!(fpu_unit.flags & UNIT_UP)) | |
| continue; | |
| if (Debug_Flags == 1) { | |
| printf("\n<<FPU instruction: FNEG>>\n"); | |
| reason = STOP_IBKPT; | |
| } | |
| if (FPFault) { /* Fault from a previous inst? */ | |
| FPFault = 0; | |
| t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ | |
| PutMap(t, AC[0]); | |
| t++; | |
| PutMap(t, AC[1]); | |
| t++; | |
| PutMap(t, AC[2]); | |
| t++; | |
| PutMap(t, AC[3]); | |
| t++; | |
| PutMap(t, ((PC-1) & AMASK)); | |
| if (C) PutMap(t, (GetMap(t) | 0100000)); | |
| PutMap(040, t); | |
| PC = indirect(GetMap(045)); /* JMP indirect to 45 */ | |
| continue; | |
| } | |
| j = (IR >> 11) & 3; | |
| FPSR &= 0xFCFFFFFF; /* Z+N bits off */ | |
| get_lf(&dfl, &FPAC[j]); | |
| dfl.sign = ! (dfl.sign); /* invert sign */ | |
| store_lf(&dfl, &FPAC[j]); /* put result in destination */ | |
| if ((FPAC[j] & 0x00ffffffffffffff) == 0) | |
| FPAC[j] = 0; | |
| FPSR &= 0xFCFFFFFF; /* Z + N off */ | |
| if (FPAC[j] == 0) | |
| FPSR |= 0x02000000; /* Set Z */ | |
| if (FPAC[j] & 0x8000000000000000) | |
| FPSR |= 0x01000000; /* Set N */ | |
| FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ | |
| FPSR |= ((PC - 1) & AMASK); | |
| continue; | |
| } | |
| if ((IR & 0163777) == 0143050) { /* FAB Absolute Value*/ | |
| if (!(fpu_unit.flags & UNIT_UP)) | |
| continue; | |
| if (Debug_Flags == 1) { | |
| printf("\n<<FPU instruction: FAB>>\n"); | |
| reason = STOP_IBKPT; | |
| } | |
| if (FPFault) { /* Fault from a previous inst? */ | |
| FPFault = 0; | |
| t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ | |
| PutMap(t, AC[0]); | |
| t++; | |
| PutMap(t, AC[1]); | |
| t++; | |
| PutMap(t, AC[2]); | |
| t++; | |
| PutMap(t, AC[3]); | |
| t++; | |
| PutMap(t, ((PC-1) & AMASK)); | |
| if (C) PutMap(t, (GetMap(t) | 0100000)); | |
| PutMap(040, t); | |
| PC = indirect(GetMap(045)); /* JMP indirect to 45 */ | |
| continue; | |
| } | |
| j = (IR >> 11) & 3; | |
| FPSR &= 0xFCFFFFFF; /* Z+N bits off */ | |
| get_lf(&dfl, &FPAC[j]); | |
| dfl.sign = 0; /* Force sign positive */ | |
| store_lf(&dfl, &FPAC[j]); /* put result in destination */ | |
| if ((FPAC[j] & 0x00ffffffffffffff) == 0) | |
| FPAC[j] = 0; | |
| FPSR &= 0xFCFFFFFF; /* Z + N off */ | |
| if (FPAC[j] == 0) | |
| FPSR |= 0x02000000; /* Set Z */ | |
| if (FPAC[j] & 0x8000000000000000) | |
| FPSR |= 0x01000000; /* Set N */ | |
| FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ | |
| FPSR |= ((PC - 1) & AMASK); | |
| continue; | |
| } | |
| if ((IR & 0163777) == 0103050) { /* FNOM Normalize*/ | |
| if (!(fpu_unit.flags & UNIT_UP)) | |
| continue; | |
| if (Debug_Flags == 1) { | |
| printf("\n<<FPU instruction: FNOM>>\n"); | |
| reason = STOP_IBKPT; | |
| } | |
| if (FPFault) { /* Fault from a previous inst? */ | |
| FPFault = 0; | |
| t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ | |
| PutMap(t, AC[0]); | |
| t++; | |
| PutMap(t, AC[1]); | |
| t++; | |
| PutMap(t, AC[2]); | |
| t++; | |
| PutMap(t, AC[3]); | |
| t++; | |
| PutMap(t, ((PC-1) & AMASK)); | |
| if (C) PutMap(t, (GetMap(t) | 0100000)); | |
| PutMap(040, t); | |
| PC = indirect(GetMap(045)); /* JMP indirect to 45 */ | |
| continue; | |
| } | |
| j = (IR >> 11) & 3; | |
| FPSR &= 0xFCFFFFFF; /* Z+N bits off */ | |
| get_lf(&dfl, &FPAC[j]); | |
| k = normal_lf(&dfl); /* Normalize */ | |
| if (k == 2) /* Underflow ? */ | |
| FPSR |= 0x20000000; /* Set underflow on */ | |
| store_lf(&dfl, &FPAC[j]); /* put result in destination */ | |
| if ((FPAC[j] & 0x00ffffffffffffff) == 0) | |
| FPAC[j] = 0; | |
| FPSR &= 0xFCFFFFFF; /* Z + N off */ | |
| if (FPAC[j] == 0) | |
| FPSR |= 0x02000000; /* Set Z */ | |
| if (FPAC[j] & 0x8000000000000000) | |
| FPSR |= 0x01000000; /* Set N */ | |
| FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ | |
| FPSR |= ((PC - 1) & AMASK); | |
| continue; | |
| } | |
| if ((IR & 0163777) == 0123050) { /* FRH Read High Word */ | |
| if (!(fpu_unit.flags & UNIT_UP)) | |
| continue; | |
| if (Debug_Flags == 1) { | |
| printf("\n<<FPU instruction: FRH>>\n"); | |
| reason = STOP_IBKPT; | |
| } | |
| if (FPFault) { /* Fault from a previous inst? */ | |
| FPFault = 0; | |
| t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ | |
| PutMap(t, AC[0]); | |
| t++; | |
| PutMap(t, AC[1]); | |
| t++; | |
| PutMap(t, AC[2]); | |
| t++; | |
| PutMap(t, AC[3]); | |
| t++; | |
| PutMap(t, ((PC-1) & AMASK)); | |
| if (C) PutMap(t, (GetMap(t) | 0100000)); | |
| PutMap(040, t); | |
| PC = indirect(GetMap(045)); /* JMP indirect to 45 */ | |
| continue; | |
| } | |
| j = (IR >> 11) & 3; | |
| AC[0] = (int32)(FPAC[j] >> 48) & 0xFFFF; /* No cond bits set, always to AC0 */ | |
| FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ | |
| FPSR |= ((PC - 1) & AMASK); | |
| continue; | |
| } | |
| if ((IR & 0163777) == 0123150) { /* FEXP Load Exponent */ | |
| if (!(fpu_unit.flags & UNIT_UP)) | |
| continue; | |
| if (Debug_Flags == 1) { | |
| printf("\n<<FPU instruction: FEXP>>\n"); | |
| reason = STOP_IBKPT; | |
| continue; | |
| } | |
| if (FPFault) { /* Fault from a previous inst? */ | |
| FPFault = 0; | |
| t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ | |
| PutMap(t, AC[0]); | |
| t++; | |
| PutMap(t, AC[1]); | |
| t++; | |
| PutMap(t, AC[2]); | |
| t++; | |
| PutMap(t, AC[3]); | |
| t++; | |
| PutMap(t, ((PC-1) & AMASK)); | |
| if (C) PutMap(t, (GetMap(t) | 0100000)); | |
| PutMap(040, t); | |
| PC = indirect(GetMap(045)); /* JMP indirect to 45 */ | |
| continue; | |
| } | |
| j = (IR >> 11) & 3; | |
| i = (AC[0] >> 8) & 0x007F; | |
| FPAC[j] &= 0x80FFFFFFFFFFFFFF; /* clear exponent */ | |
| FPAC[j] |= ((t_int64) i << 56); | |
| if ((FPAC[j] & 0x00ffffffffffffff) == 0) | |
| FPAC[j] = 0; | |
| if (FPAC[j] == 0) | |
| FPSR |= 0x02000000; /* Set Z */ | |
| if (FPAC[j] & 0x8000000000000000) | |
| FPSR |= 0x01000000; /* Set N */ | |
| FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ | |
| FPSR |= ((PC - 1) & AMASK); | |
| continue; | |
| } | |
| if ((IR & 0103777) == 0103450) { /* FCMP FP Compare */ | |
| if (!(fpu_unit.flags & UNIT_UP)) /* (Subtract double AC without storing result) */ | |
| continue; | |
| if (Debug_Flags == 1) { | |
| printf("\n<<FPU instruction: FCMP>>\n"); | |
| reason = STOP_IBKPT; | |
| } | |
| if (FPFault) { /* Fault from a previous inst? */ | |
| FPFault = 0; | |
| t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ | |
| PutMap(t, AC[0]); | |
| t++; | |
| PutMap(t, AC[1]); | |
| t++; | |
| PutMap(t, AC[2]); | |
| t++; | |
| PutMap(t, AC[3]); | |
| t++; | |
| PutMap(t, ((PC-1) & AMASK)); | |
| if (C) PutMap(t, (GetMap(t) | 0100000)); | |
| PutMap(040, t); | |
| PC = indirect(GetMap(045)); /* JMP indirect to 45 */ | |
| continue; | |
| } | |
| i = (IR >> 13) & 3; | |
| j = (IR >> 11) & 3; | |
| FPSR &= 0xFCFFFFFF; /* Z+N bits off */ | |
| get_lf(&dfl, &FPAC[i]); /* Place in working registers */ | |
| get_lf(&dfl2, &FPAC[j]); | |
| dfl.sign = ! (dfl.sign); /* invert sign of 2nd operand */ | |
| k = add_lf(&dfl2, &dfl, 1); /* Add the two */ | |
| if (k) { | |
| switch (k) { | |
| case 1: | |
| FPSR |= 0x40000000; /* OVF bit on */ | |
| break; | |
| case 2: | |
| FPSR |= 0x20000000; /* UNF bit on */ | |
| break; | |
| } | |
| } | |
| if ((FPAC[j] & 0x00ffffffffffffff) == 0) | |
| FPAC[j] = 0; | |
| FPSR &= 0xFCFFFFFF; /* Z + N off */ | |
| if (FPAC[j] == 0) | |
| FPSR |= 0x02000000; /* Set Z */ | |
| if (FPAC[j] & 0x8000000000000000) | |
| FPSR |= 0x01000000; /* Set N */ | |
| FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ | |
| FPSR |= ((PC - 1) & AMASK); | |
| continue; | |
| } | |
| if (IR == 0163350) { /* FPSH Push State */ | |
| if (!(fpu_unit.flags & UNIT_UP)) | |
| continue; | |
| if (Debug_Flags == 2) { | |
| printf("\n<<FPU instruction: FPSH>>\n"); | |
| reason = STOP_IBKPT; | |
| } | |
| /* Note: FPSH and FPOP do not trap on error */ | |
| t = (GetMap(040) + 1) & AMASK; /* Get Stack Pointer */ | |
| PutMap(t, ((FPSR >> 16) & 0xFFFF)); | |
| t++; | |
| PutMap(t, (FPSR & 0xFFFF)); | |
| t++; | |
| PutMap(t, (int16)((FPAC[0] >> 48) & 0xFFFF)); | |
| t++; | |
| PutMap(t, (int16)((FPAC[0] >> 32) & 0xFFFF)); | |
| t++; | |
| PutMap(t, (int16)((FPAC[0] >> 16) & 0xFFFF)); | |
| t++; | |
| PutMap(t, (int16)(FPAC[0] & 0xFFFF)); | |
| t++; | |
| PutMap(t, (int16)((FPAC[1] >> 48) & 0xFFFF)); | |
| t++; | |
| PutMap(t, (int16)((FPAC[1] >> 32) & 0xFFFF)); | |
| t++; | |
| PutMap(t, (int16)((FPAC[1] >> 16) & 0xFFFF)); | |
| t++; | |
| PutMap(t, (int16)(FPAC[1] & 0xFFFF)); | |
| t++; | |
| PutMap(t, (int16)((FPAC[2] >> 48) & 0xFFFF)); | |
| t++; | |
| PutMap(t, (int16)((FPAC[2] >> 32) & 0xFFFF)); | |
| t++; | |
| PutMap(t, (int16)((FPAC[2] >> 16) & 0xFFFF)); | |
| t++; | |
| PutMap(t, (int16)(FPAC[2] & 0xFFFF)); | |
| t++; | |
| PutMap(t, (int16)((FPAC[3] >> 48) & 0xFFFF)); | |
| t++; | |
| PutMap(t, (int16)((FPAC[3] >> 32) & 0xFFFF)); | |
| t++; | |
| PutMap(t, (int16)((FPAC[3] >> 16) & 0xFFFF)); | |
| t++; | |
| PutMap(t, (int16)(FPAC[3] & 0xFFFF)); | |
| PutMap(040, t); /* Update Stack Pointer */ | |
| continue; | |
| } | |
| if (IR == 0167350) { /* FPOP Pop State */ | |
| if (!(fpu_unit.flags & UNIT_UP)) | |
| continue; | |
| if (Debug_Flags == 2) { | |
| printf("\n<<FPU instruction: FPOP>>\n"); | |
| reason = STOP_IBKPT; | |
| } | |
| /* Note: FPSH and FPOP do not trap on error */ | |
| t = GetMap(040) & AMASK; /* Get Stack Pointer */ | |
| FPAC[3] = ((t_uint64)GetMap(t) & 0xFFFF); | |
| t--; | |
| FPAC[3] |= (((t_uint64)GetMap(t) << 16) & 0xFFFF0000); | |
| t--; | |
| FPAC[3] |= (((t_uint64)GetMap(t) << 32) & 0xFFFF00000000); | |
| t--; | |
| FPAC[3] |= (((t_uint64)GetMap(t) << 48) & 0xFFFF000000000000); | |
| t--; | |
| FPAC[2] = ((t_uint64)GetMap(t) & 0xFFFF); | |
| t--; | |
| FPAC[2] |= (((t_uint64)GetMap(t) << 16) & 0xFFFF0000); | |
| t--; | |
| FPAC[2] |= (((t_uint64)GetMap(t) << 32) & 0xFFFF00000000); | |
| t--; | |
| FPAC[2] |= (((t_uint64)GetMap(t) << 48) & 0xFFFF000000000000); | |
| t--; | |
| FPAC[1] = ((t_uint64)GetMap(t) & 0xFFFF); | |
| t--; | |
| FPAC[1] |= (((t_uint64)GetMap(t) << 16) & 0xFFFF0000); | |
| t--; | |
| FPAC[1] |= (((t_uint64)GetMap(t) << 32) & 0xFFFF00000000); | |
| t--; | |
| FPAC[1] |= (((t_uint64)GetMap(t) << 48) & 0xFFFF000000000000); | |
| t--; | |
| FPAC[0] = ((t_uint64)GetMap(t) & 0xFFFF); | |
| t--; | |
| FPAC[0] |= (((t_uint64)GetMap(t) << 16) & 0xFFFF0000); | |
| t--; | |
| FPAC[0] |= (((t_uint64)GetMap(t) << 32) & 0xFFFF00000000); | |
| t--; | |
| FPAC[0] |= (((t_uint64)GetMap(t) << 48) & 0xFFFF000000000000); | |
| t--; | |
| FPSR = (GetMap(t) & 0xFFFF); | |
| t--; | |
| FPSR |= ((GetMap(t) << 16) & 0xFFFF0000); | |
| t--; | |
| PutMap(040, t); /* Update Stack Pointer */ | |
| continue; | |
| } | |
| if ((IR & 0163777) == 0163150) { /* FHLV Halve */ | |
| if (!(fpu_unit.flags & UNIT_UP)) | |
| continue; | |
| if (Debug_Flags == 1) { | |
| printf("\n<<FPU instruction: FHLV>>\n"); | |
| reason = STOP_IBKPT; | |
| } | |
| if (FPFault) { /* Fault from a previous inst? */ | |
| FPFault = 0; | |
| t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ | |
| PutMap(t, AC[0]); | |
| t++; | |
| PutMap(t, AC[1]); | |
| t++; | |
| PutMap(t, AC[2]); | |
| t++; | |
| PutMap(t, AC[3]); | |
| t++; | |
| PutMap(t, ((PC-1) & AMASK)); | |
| if (C) PutMap(t, (GetMap(t) | 0100000)); | |
| PutMap(040, t); | |
| PC = indirect(GetMap(045)); /* JMP indirect to 45 */ | |
| continue; | |
| } | |
| j = (IR >> 11) & 3; | |
| FPSR &= 0xFCFFFFFF; /* Z+N bits off */ | |
| get_lf(&dfl, &FPAC[j]); | |
| dfl.long_fract = dfl.long_fract >> 1; /* Shift right one bit */ | |
| normal_lf(&dfl); /* Normalize */ | |
| store_lf(&dfl, &FPAC[j]); /* put result in destination */ | |
| if ((FPAC[j] & 0x00ffffffffffffff) == 0) | |
| FPAC[j] = 0; | |
| FPSR &= 0xFCFFFFFF; /* Z + N off */ | |
| if (FPAC[j] == 0) | |
| FPSR |= 0x02000000; /* Set Z */ | |
| if (FPAC[j] & 0x8000000000000000) | |
| FPSR |= 0x01000000; /* Set N */ | |
| FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ | |
| FPSR |= ((PC - 1) & AMASK); | |
| continue; | |
| } | |
| if ((IR & 0163777) == 0103150) { /* FSCAL Scale */ | |
| if (!(fpu_unit.flags & UNIT_UP)) | |
| continue; | |
| if (Debug_Flags == 1) { | |
| printf("\n<<FPU instruction: FSCAL>>\n"); | |
| reason = STOP_IBKPT; | |
| } | |
| if (FPFault) { /* Fault from a previous inst? */ | |
| FPFault = 0; | |
| t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ | |
| PutMap(t, AC[0]); | |
| t++; | |
| PutMap(t, AC[1]); | |
| t++; | |
| PutMap(t, AC[2]); | |
| t++; | |
| PutMap(t, AC[3]); | |
| t++; | |
| PutMap(t, ((PC-1) & AMASK)); | |
| if (C) PutMap(t, (GetMap(t) | 0100000)); | |
| PutMap(040, t); | |
| PC = indirect(GetMap(045)); /* JMP indirect to 45 */ | |
| continue; | |
| } | |
| i = (IR >> 11) & 3; | |
| FPSR &= 0xFCFFFFFF; /* Z+N bits off */ | |
| j = (AC[0] >> 8) & 0x7F; /* expo of AC0 */ | |
| k = (int32)(FPAC[i] >> 56) & 0x7F; /* expo of FPAC */ | |
| tempfp = FPAC[i] & 0x8000000000000000; /* save sign */ | |
| t = j - k; | |
| if (t > 0) { /* Positive shift */ | |
| FPAC[i] &= 0x00FFFFFFFFFFFFFF; | |
| FPAC[i] = FPAC[i] >> (t * 4); | |
| FPAC[i] &= 0x00FFFFFFFFFFFFFF; /* AC0 expo becomes expo */ | |
| holdfp = j; | |
| FPAC[i] |= (holdfp << 56); | |
| } | |
| if (t < 0) { /* Negative shift */ | |
| FPAC[i] &= 0x00FFFFFFFFFFFFFF; | |
| FPAC[i] = FPAC[i] << ((0-t) * 4); | |
| FPSR |= 0x08000000; /* MOF bit on */ | |
| FPAC[i] &= 0x00FFFFFFFFFFFFFF; /* AC0 expo becomes expo */ | |
| holdfp = j; | |
| FPAC[i] |= (holdfp << 56); | |
| } | |
| if ((FPAC[i] & 0x00FFFFFFFFFFFFFF) != 0) | |
| FPAC[i] |= tempfp; /* restore sign */ | |
| if ((FPAC[i] & 0x80FFFFFFFFFFFFFF) == 0) { | |
| FPAC[i] = 0; | |
| FPSR |= 0x02000000; /* Set Z */ | |
| } | |
| if (FPAC[i] & 0x8000000000000000) | |
| FPSR |= 0x01000000; /* Set N */ | |
| FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ | |
| FPSR |= ((PC - 1) & AMASK); | |
| continue; | |
| } | |
| if (IR == 0153350) { /* FCLE Clear Errors */ | |
| if (!(fpu_unit.flags & UNIT_UP)) | |
| continue; | |
| if (Debug_Flags == 1) { | |
| printf("\n<<FPU instruction: FCLE>>\n"); | |
| reason = STOP_IBKPT; | |
| } | |
| if (FPFault) { /* Fault from a previous inst? */ | |
| FPFault = 0; | |
| t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ | |
| PutMap(t, AC[0]); | |
| t++; | |
| PutMap(t, AC[1]); | |
| t++; | |
| PutMap(t, AC[2]); | |
| t++; | |
| PutMap(t, AC[3]); | |
| t++; | |
| PutMap(t, ((PC-1) & AMASK)); | |
| if (C) PutMap(t, (GetMap(t) | 0100000)); | |
| PutMap(040, t); | |
| PC = indirect(GetMap(045)); /* JMP indirect to 45 */ | |
| continue; | |
| } | |
| FPSR &= 0x07FFFFFF; /* set off all error bits */ | |
| FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ | |
| FPSR |= ((PC - 1) & AMASK); | |
| continue; | |
| } | |
| if (IR == 0103250) { /* FNS No Skip */ | |
| if (!(fpu_unit.flags & UNIT_UP)) | |
| continue; | |
| if (Debug_Flags == 1) { | |
| printf("\n<<FPU instruction: FNS>>\n"); | |
| reason = STOP_IBKPT; | |
| } | |
| if (FPFault) { /* Fault from a previous inst? */ | |
| FPFault = 0; | |
| t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ | |
| PutMap(t, AC[0]); | |
| t++; | |
| PutMap(t, AC[1]); | |
| t++; | |
| PutMap(t, AC[2]); | |
| t++; | |
| PutMap(t, AC[3]); | |
| t++; | |
| PutMap(t, ((PC-1) & AMASK)); | |
| if (C) PutMap(t, (GetMap(t) | 0100000)); | |
| PutMap(040, t); | |
| PC = indirect(GetMap(045)); /* JMP indirect to 45 */ | |
| continue; | |
| } | |
| FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ | |
| FPSR |= ((PC - 1) & AMASK); | |
| continue; | |
| } | |
| if (IR == 0107250) { /* FSA Always Skip */ | |
| if (!(fpu_unit.flags & UNIT_UP)) | |
| continue; | |
| if (Debug_Flags == 2) { | |
| printf("\n<<FPU instruction: FSA>>\n"); | |
| reason = STOP_IBKPT; | |
| } | |
| if (FPFault) { /* Fault from a previous inst? */ | |
| FPFault = 0; | |
| t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ | |
| PutMap(t, AC[0]); | |
| t++; | |
| PutMap(t, AC[1]); | |
| t++; | |
| PutMap(t, AC[2]); | |
| t++; | |
| PutMap(t, AC[3]); | |
| t++; | |
| PutMap(t, ((PC-1) & AMASK)); | |
| if (C) PutMap(t, (GetMap(t) | 0100000)); | |
| PutMap(040, t); | |
| PC = indirect(GetMap(045)); /* JMP indirect to 45 */ | |
| continue; | |
| } | |
| FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ | |
| FPSR |= ((PC - 1) & AMASK); | |
| PC = (PC + 1) & AMASK; | |
| continue; | |
| } | |
| if (IR == 0137250) { /* FSGT */ | |
| if (!(fpu_unit.flags & UNIT_UP)) | |
| continue; | |
| if (Debug_Flags == 1) { | |
| printf("\n<<FPU instruction: FSGT>>\n"); | |
| reason = STOP_IBKPT; | |
| } | |
| if (FPFault) { /* Fault from a previous inst? */ | |
| FPFault = 0; | |
| t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ | |
| PutMap(t, AC[0]); | |
| t++; | |
| PutMap(t, AC[1]); | |
| t++; | |
| PutMap(t, AC[2]); | |
| t++; | |
| PutMap(t, AC[3]); | |
| t++; | |
| PutMap(t, ((PC-1) & AMASK)); | |
| if (C) PutMap(t, (GetMap(t) | 0100000)); | |
| PutMap(040, t); | |
| PC = indirect(GetMap(045)); /* JMP indirect to 45 */ | |
| continue; | |
| } | |
| FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ | |
| FPSR |= ((PC - 1) & AMASK); | |
| if (!(FPSR & 0x03000000)) /* Z & N both 0? */ | |
| PC = (PC + 1) & AMASK; /* yep: skip */ | |
| continue; | |
| } | |
| if (IR == 0123250) { /* FSLT */ | |
| if (!(fpu_unit.flags & UNIT_UP)) | |
| continue; | |
| if (Debug_Flags == 1) { | |
| printf("\n<<FPU instruction: FSLT>>\n"); | |
| reason = STOP_IBKPT; | |
| } | |
| if (FPFault) { /* Fault from a previous inst? */ | |
| FPFault = 0; | |
| t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ | |
| PutMap(t, AC[0]); | |
| t++; | |
| PutMap(t, AC[1]); | |
| t++; | |
| PutMap(t, AC[2]); | |
| t++; | |
| PutMap(t, AC[3]); | |
| t++; | |
| PutMap(t, ((PC-1) & AMASK)); | |
| if (C) PutMap(t, (GetMap(t) | 0100000)); | |
| PutMap(040, t); | |
| PC = indirect(GetMap(045)); /* JMP indirect to 45 */ | |
| continue; | |
| } | |
| FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ | |
| FPSR |= ((PC - 1) & AMASK); | |
| if (FPSR & 0x01000000) /* N is on? */ | |
| PC = (PC + 1) & AMASK; /* yep: skip */ | |
| continue; | |
| } | |
| if (IR == 0113250) { /* FSEQ */ | |
| if (!(fpu_unit.flags & UNIT_UP)) | |
| continue; | |
| if (Debug_Flags == 1) { | |
| printf("\n<<FPU instruction: FSEQ>>\n"); | |
| reason = STOP_IBKPT; | |
| } | |
| if (FPFault) { /* Fault from a previous inst? */ | |
| FPFault = 0; | |
| t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ | |
| PutMap(t, AC[0]); | |
| t++; | |
| PutMap(t, AC[1]); | |
| t++; | |
| PutMap(t, AC[2]); | |
| t++; | |
| PutMap(t, AC[3]); | |
| t++; | |
| PutMap(t, ((PC-1) & AMASK)); | |
| if (C) PutMap(t, (GetMap(t) | 0100000)); | |
| PutMap(040, t); | |
| PC = indirect(GetMap(045)); /* JMP indirect to 45 */ | |
| continue; | |
| } | |
| FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ | |
| FPSR |= ((PC - 1) & AMASK); | |
| if (FPSR & 0x02000000) /* Z is on? */ | |
| PC = (PC + 1) & AMASK; /* yep: skip */ | |
| continue; | |
| } | |
| if (IR == 0133250) { /* FSLE */ | |
| if (!(fpu_unit.flags & UNIT_UP)) | |
| continue; | |
| if (Debug_Flags == 1) { | |
| printf("\n<<FPU instruction: FSLE>>\n"); | |
| reason = STOP_IBKPT; | |
| } | |
| if (FPFault) { /* Fault from a previous inst? */ | |
| FPFault = 0; | |
| t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ | |
| PutMap(t, AC[0]); | |
| t++; | |
| PutMap(t, AC[1]); | |
| t++; | |
| PutMap(t, AC[2]); | |
| t++; | |
| PutMap(t, AC[3]); | |
| t++; | |
| PutMap(t, ((PC-1) & AMASK)); | |
| if (C) PutMap(t, (GetMap(t) | 0100000)); | |
| PutMap(040, t); | |
| PC = indirect(GetMap(045)); /* JMP indirect to 45 */ | |
| continue; | |
| } | |
| FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ | |
| FPSR |= ((PC - 1) & AMASK); | |
| if (FPSR & 0x03000000) /* Z or N on? */ | |
| PC = (PC + 1) & AMASK; /* yep: skip */ | |
| continue; | |
| } | |
| if (IR == 0127250) { /* FSGE */ | |
| if (!(fpu_unit.flags & UNIT_UP)) | |
| continue; | |
| if (Debug_Flags == 1) { | |
| printf("\n<<FPU instruction: FSGE>>\n"); | |
| reason = STOP_IBKPT; | |
| } | |
| if (FPFault) { /* Fault from a previous inst? */ | |
| FPFault = 0; | |
| t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ | |
| PutMap(t, AC[0]); | |
| t++; | |
| PutMap(t, AC[1]); | |
| t++; | |
| PutMap(t, AC[2]); | |
| t++; | |
| PutMap(t, AC[3]); | |
| t++; | |
| PutMap(t, ((PC-1) & AMASK)); | |
| if (C) PutMap(t, (GetMap(t) | 0100000)); | |
| PutMap(040, t); | |
| PC = indirect(GetMap(045)); /* JMP indirect to 45 */ | |
| continue; | |
| } | |
| FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ | |
| FPSR |= ((PC - 1) & AMASK); | |
| if (!(FPSR & 0x01000000)) /* N is off? */ | |
| PC = (PC + 1) & AMASK; /* yep: skip */ | |
| continue; | |
| } | |
| if (IR == 0117250) { /* FSNE */ | |
| if (!(fpu_unit.flags & UNIT_UP)) | |
| continue; | |
| if (Debug_Flags == 1) { | |
| printf("\n<<FPU instruction: FSNE>>\n"); | |
| continue; | |
| } | |
| if (FPFault) { /* Fault from a previous inst? */ | |
| FPFault = 0; | |
| t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ | |
| PutMap(t, AC[0]); | |
| t++; | |
| PutMap(t, AC[1]); | |
| t++; | |
| PutMap(t, AC[2]); | |
| t++; | |
| PutMap(t, AC[3]); | |
| t++; | |
| PutMap(t, ((PC-1) & AMASK)); | |
| if (C) PutMap(t, (GetMap(t) | 0100000)); | |
| PutMap(040, t); | |
| PC = indirect(GetMap(045)); /* JMP indirect to 45 */ | |
| continue; | |
| } | |
| FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ | |
| FPSR |= ((PC - 1) & AMASK); | |
| if (!(FPSR & 0x02000000)) /* Z is off? */ | |
| PC = (PC + 1) & AMASK; /* yep: skip */ | |
| continue; | |
| } | |
| if (IR == 0143250) { /* FSNM */ | |
| if (!(fpu_unit.flags & UNIT_UP)) | |
| continue; | |
| if (Debug_Flags == 1) { | |
| printf("\n<<FPU instruction: FSNM>>\n"); | |
| reason = STOP_IBKPT; | |
| } | |
| if (FPFault) { /* Fault from a previous inst? */ | |
| FPFault = 0; | |
| t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ | |
| PutMap(t, AC[0]); | |
| t++; | |
| PutMap(t, AC[1]); | |
| t++; | |
| PutMap(t, AC[2]); | |
| t++; | |
| PutMap(t, AC[3]); | |
| t++; | |
| PutMap(t, ((PC-1) & AMASK)); | |
| if (C) PutMap(t, (GetMap(t) | 0100000)); | |
| PutMap(040, t); | |
| PC = indirect(GetMap(045)); /* JMP indirect to 45 */ | |
| continue; | |
| } | |
| FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ | |
| FPSR |= ((PC - 1) & AMASK); | |
| if (!(FPSR & 0x08000000)) /* MOF is off? */ | |
| PC = (PC + 1) & AMASK; /* yep: skip */ | |
| continue; | |
| } | |
| if (IR == 0153250) { /* FSNU */ | |
| if (!(fpu_unit.flags & UNIT_UP)) | |
| continue; | |
| if (Debug_Flags == 1) { | |
| printf("\n<<FPU instruction: FSNU>>\n"); | |
| reason = STOP_IBKPT; | |
| } | |
| if (FPFault) { /* Fault from a previous inst? */ | |
| FPFault = 0; | |
| t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ | |
| PutMap(t, AC[0]); | |
| t++; | |
| PutMap(t, AC[1]); | |
| t++; | |
| PutMap(t, AC[2]); | |
| t++; | |
| PutMap(t, AC[3]); | |
| t++; | |
| PutMap(t, ((PC-1) & AMASK)); | |
| if (C) PutMap(t, (GetMap(t) | 0100000)); | |
| PutMap(040, t); | |
| PC = indirect(GetMap(045)); /* JMP indirect to 45 */ | |
| continue; | |
| } | |
| FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ | |
| FPSR |= ((PC - 1) & AMASK); | |
| if (!(FPSR & 0x20000000)) /* UNF is off? */ | |
| PC = (PC + 1) & AMASK; /* yep: skip */ | |
| continue; | |
| } | |
| if (IR == 0163250) { /* FSNO */ | |
| if (!(fpu_unit.flags & UNIT_UP)) | |
| continue; | |
| if (Debug_Flags == 1) { | |
| printf("\n<<FPU instruction: FSNO>>\n"); | |
| reason = STOP_IBKPT; | |
| } | |
| if (FPFault) { /* Fault from a previous inst? */ | |
| FPFault = 0; | |
| t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ | |
| PutMap(t, AC[0]); | |
| t++; | |
| PutMap(t, AC[1]); | |
| t++; | |
| PutMap(t, AC[2]); | |
| t++; | |
| PutMap(t, AC[3]); | |
| t++; | |
| PutMap(t, ((PC-1) & AMASK)); | |
| if (C) PutMap(t, (GetMap(t) | 0100000)); | |
| PutMap(040, t); | |
| PC = indirect(GetMap(045)); /* JMP indirect to 45 */ | |
| continue; | |
| } | |
| FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ | |
| FPSR |= ((PC - 1) & AMASK); | |
| if (!(FPSR & 0x40000000)) /* OVF is off? */ | |
| PC = (PC + 1) & AMASK; /* yep: skip */ | |
| continue; | |
| } | |
| if (IR == 0147250) { /* FSND */ | |
| if (!(fpu_unit.flags & UNIT_UP)) | |
| continue; | |
| if (Debug_Flags == 1) { | |
| printf("\n<<FPU instruction: FSND>>\n"); | |
| reason = STOP_IBKPT; | |
| } | |
| if (FPFault) { /* Fault from a previous inst? */ | |
| FPFault = 0; | |
| t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ | |
| PutMap(t, AC[0]); | |
| t++; | |
| PutMap(t, AC[1]); | |
| t++; | |
| PutMap(t, AC[2]); | |
| t++; | |
| PutMap(t, AC[3]); | |
| t++; | |
| PutMap(t, ((PC-1) & AMASK)); | |
| if (C) PutMap(t, (GetMap(t) | 0100000)); | |
| PutMap(040, t); | |
| PC = indirect(GetMap(045)); /* JMP indirect to 45 */ | |
| continue; | |
| } | |
| FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ | |
| FPSR |= ((PC - 1) & AMASK); | |
| if (!(FPSR & 0x10000000)) /* DVZ is off? */ | |
| PC = (PC + 1) & AMASK; /* yep: skip */ | |
| continue; | |
| } | |
| if (IR == 0157250) { /* FSNUD */ | |
| if (!(fpu_unit.flags & UNIT_UP)) | |
| continue; | |
| if (Debug_Flags == 1) { | |
| printf("\n<<FPU instruction: FSNUD>>\n"); | |
| reason = STOP_IBKPT; | |
| } | |
| if (FPFault) { /* Fault from a previous inst? */ | |
| FPFault = 0; | |
| t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ | |
| PutMap(t, AC[0]); | |
| t++; | |
| PutMap(t, AC[1]); | |
| t++; | |
| PutMap(t, AC[2]); | |
| t++; | |
| PutMap(t, AC[3]); | |
| t++; | |
| PutMap(t, ((PC-1) & AMASK)); | |
| if (C) PutMap(t, (GetMap(t) | 0100000)); | |
| PutMap(040, t); | |
| PC = indirect(GetMap(045)); /* JMP indirect to 45 */ | |
| continue; | |
| } | |
| FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ | |
| FPSR |= ((PC - 1) & AMASK); | |
| if (!(FPSR & 0x30000000)) /* UNF & DVZ off? */ | |
| PC = (PC + 1) & AMASK; /* yep: skip */ | |
| continue; | |
| } | |
| if (IR == 0167250) { /* FSNOD */ | |
| if (!(fpu_unit.flags & UNIT_UP)) | |
| continue; | |
| if (Debug_Flags == 1) { | |
| printf("\n<<FPU instruction: FSNOD>>\n"); | |
| reason = STOP_IBKPT; | |
| } | |
| if (FPFault) { /* Fault from a previous inst? */ | |
| FPFault = 0; | |
| t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ | |
| PutMap(t, AC[0]); | |
| t++; | |
| PutMap(t, AC[1]); | |
| t++; | |
| PutMap(t, AC[2]); | |
| t++; | |
| PutMap(t, AC[3]); | |
| t++; | |
| PutMap(t, ((PC-1) & AMASK)); | |
| if (C) PutMap(t, (GetMap(t) | 0100000)); | |
| PutMap(040, t); | |
| PC = indirect(GetMap(045)); /* JMP indirect to 45 */ | |
| continue; | |
| } | |
| FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ | |
| FPSR |= ((PC - 1) & AMASK); | |
| if (!(FPSR & 0x50000000)) /* OVF & DVZ off? */ | |
| PC = (PC + 1) & AMASK; /* yep: skip */ | |
| continue; | |
| } | |
| if (IR == 0173250) { /* FSNUO */ | |
| if (!(fpu_unit.flags & UNIT_UP)) | |
| continue; | |
| if (Debug_Flags == 1) { | |
| printf("\n<<FPU instruction: FSNUO>>\n"); | |
| reason = STOP_IBKPT; | |
| } | |
| if (FPFault) { /* Fault from a previous inst? */ | |
| FPFault = 0; | |
| t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ | |
| PutMap(t, AC[0]); | |
| t++; | |
| PutMap(t, AC[1]); | |
| t++; | |
| PutMap(t, AC[2]); | |
| t++; | |
| PutMap(t, AC[3]); | |
| t++; | |
| PutMap(t, ((PC-1) & AMASK)); | |
| if (C) PutMap(t, (GetMap(t) | 0100000)); | |
| PutMap(040, t); | |
| PC = indirect(GetMap(045)); /* JMP indirect to 45 */ | |
| continue; | |
| } | |
| FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ | |
| FPSR |= ((PC - 1) & AMASK); | |
| if (!(FPSR & 0x60000000)) /* OVF & UNF off? */ | |
| PC = (PC + 1) & AMASK; /* yep: skip */ | |
| continue; | |
| } | |
| if (IR == 0177250) { /* FSNER */ | |
| if (!(fpu_unit.flags & UNIT_UP)) | |
| continue; | |
| if (Debug_Flags == 1) { | |
| printf("\n<<FPU instruction: FSNER>>\n"); | |
| reason = STOP_IBKPT; | |
| } | |
| if (FPFault) { /* Fault from a previous inst? */ | |
| FPFault = 0; | |
| t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ | |
| PutMap(t, AC[0]); | |
| t++; | |
| PutMap(t, AC[1]); | |
| t++; | |
| PutMap(t, AC[2]); | |
| t++; | |
| PutMap(t, AC[3]); | |
| t++; | |
| PutMap(t, ((PC-1) & AMASK)); | |
| if (C) PutMap(t, (GetMap(t) | 0100000)); | |
| PutMap(040, t); | |
| PC = indirect(GetMap(045)); /* JMP indirect to 45 */ | |
| continue; | |
| } | |
| FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ | |
| FPSR |= ((PC - 1) & AMASK); | |
| if (!(FPSR & 0x78000000)) /* all errors off? */ | |
| PC = (PC + 1) & AMASK; /* yep: skip */ | |
| continue; | |
| } | |
| if (Debug_Flags) { | |
| printf("\n<<Unexecuted inst = %o at PC=%o>>\n\r", IR, PC-1); | |
| if (Debug_Flags & 040000) reason = STOP_IBKPT; | |
| } | |
| } | |
| if (IR == 061777) { /* VCT: Vector on Interrupt */ | |
| int32 stkchg, vtable; | |
| int32 ventry, dctadr; | |
| int32 old40, old41, old42, old43; | |
| /* Ok, folks, this is one helluva instruction */ | |
| stkchg = GetMap(PC) & 0100000; /* Save stack change bit */ | |
| vtable = GetMap(PC) & AMASK; /* Address of vector table */ | |
| iodev = 0; | |
| int_req = (int_req & ~INT_DEV) | /* Do an INTA w/o an accum */ | |
| (dev_done & ~dev_disable); | |
| iodata = int_req & (-int_req); | |
| for (i = DEV_LOW; i <= DEV_HIGH; i++) { | |
| if (iodata & dev_table[i].mask) { | |
| iodev = i; | |
| break; | |
| } | |
| } | |
| ventry = GetMap(vtable + iodev); /* Get Vector Entry */ | |
| if (!(ventry & 0100000)) { /* Direct bit = 0? */ | |
| PC = ventry & AMASK; /* YES - Mode A, so JMP */ | |
| continue; | |
| } | |
| dctadr = ventry & AMASK; /* Get address of DCT entry */ | |
| if (stkchg) { /* Stack change bit = 1? */ | |
| old40 = GetMap(040); /* Save stack info */ | |
| old41 = GetMap(041); | |
| old42 = GetMap(042); | |
| old43 = GetMap(043); | |
| PutMap(040, GetMap(004)); /* Loc 4 to stack ptr */ | |
| PutMap(042, GetMap(006)); /* Loc 6 to stack limit */ | |
| PutMap(043, GetMap(007)); /* Loc 7 into stack limit */ | |
| PutMap(040, (GetMap(040) + 1)); /* Push old contents on new stk */ | |
| PutMap(GetMap(040) & AMASK, old40); | |
| PutMap(040, (GetMap(040) + 1)); | |
| PutMap(GetMap(040) & AMASK, old41); | |
| PutMap(040, (GetMap(040) + 1)); | |
| PutMap(GetMap(040) & AMASK, old42); | |
| PutMap(040, (GetMap(040) + 1)); | |
| PutMap(GetMap(040) & AMASK, old43); | |
| } | |
| t = GetMap(dctadr & AMASK); /* Get word 0 of DCT */ | |
| if (t & 0100000) { /* Push bit set ? */ | |
| PutMap(040, (GetMap(040) + 1)); /* Push "Standard rtn block" */ | |
| PutMap(GetMap(040) & AMASK, AC[0]); | |
| PutMap(040, (GetMap(040) + 1)); | |
| PutMap(GetMap(040) & AMASK, AC[1]); | |
| PutMap(040, (GetMap(040) + 1)); | |
| PutMap(GetMap(040) & AMASK, AC[2]); | |
| PutMap(040, (GetMap(040) + 1)); | |
| PutMap(GetMap(040) & AMASK, AC[3]); | |
| PutMap(040, (GetMap(040) + 1)); | |
| PutMap(GetMap(040) & AMASK, GetMap(0)); | |
| if (GetMap(0) == 0 && Debug_Flags) { | |
| printf("\n<<VCT will rtn to 0 @ %o>>\n\r", PC); | |
| reason = STOP_IBKPT; | |
| } | |
| if (C) PutMap(GetMap(040) & AMASK, (GetMap(GetMap(040) & AMASK) | 0100000)); | |
| } | |
| AC[2] = dctadr & AMASK; /* DCT Addr into AC2 */ | |
| PutMap(040, (GetMap(040) + 1)); /* Push pri int mask onto stack */ | |
| PutMap(GetMap(040) & AMASK, pimask); | |
| AC[0] = GetMap(dctadr + 1) | pimask; /* Build new mask from word 1 of dct */ | |
| PutMap(005, AC[0]); | |
| mask_out(pimask = AC[0]); /* Do a mask out inst */ | |
| PC = GetMap(dctadr) & AMASK; /* Finally, JMP to int routine */ | |
| continue; | |
| } | |
| /************************************************************************* | |
| ** At this point, the instruction is not an Eclipse one. Therefore ** | |
| ** decode it as a Nova instruction just like the Nova does. ** | |
| *************************************************************************/ | |
| /* Memory reference instructions */ | |
| if (t < 014) { /* mem ref? */ | |
| register int32 src, MA; | |
| MA = IR & 0377; | |
| switch ((IR >> 8) & 03) { /* decode IR<6:7> */ | |
| case 0: /* page zero */ | |
| break; | |
| case 1: /* PC relative */ | |
| if (MA & 0200) MA = 077400 | MA; | |
| MA = (MA + PC - 1) & AMASK; | |
| break; | |
| case 2: /* AC2 relative */ | |
| if (MA & 0200) MA = 077400 | MA; | |
| MA = (MA + AC[2]) & AMASK; | |
| break; | |
| case 3: /* AC3 relative */ | |
| if (MA & 0200) MA = 077400 | MA; | |
| MA = (MA + AC[3]) & AMASK; | |
| break; | |
| } | |
| if (IR & 002000) { /* indirect? */ | |
| for (i = 0; i < (ind_max * 2); i++) { /* count indirects */ | |
| if ((MA & 077770) == 020 && !(cpu_unit.flags & UNIT_MICRO)) | |
| MA = (PutMap(MA & AMASK, (GetMap(MA & AMASK) + 1) & 0177777)); | |
| else if ((MA & 077770) == 030 && !(cpu_unit.flags & UNIT_MICRO)) | |
| MA = (PutMap(MA & AMASK, (GetMap(MA & AMASK) - 1) & 0177777)); | |
| else MA = GetMap(MA & AMASK); | |
| if (MapStat & 1) { /* Start MAP */ | |
| Usermap = Enable; | |
| Inhibit = 0; | |
| } | |
| if ((MA & 0100000) == 0) break; | |
| if (i >= ind_max && (MapStat & 010) && Usermap) break; | |
| } | |
| if (i >= (ind_max-1)) { | |
| if ((MapStat & 010) && Usermap) { | |
| Fault = 04000; /* Map fault if IND prot */ | |
| continue; | |
| } | |
| if (i >= (ind_max * 2) && !(Fault)) { | |
| reason = STOP_IND; | |
| break; | |
| } | |
| } | |
| } | |
| switch (t) { /* decode IR<1:4> */ | |
| case 001: /* JSR */ | |
| AC[3] = PC; | |
| case 000: /* JMP */ | |
| old_PC = PC; | |
| PC = MA; | |
| break; | |
| case 002: /* ISZ */ | |
| src = (GetMap(MA) + 1) & 0177777; | |
| if (MEM_ADDR_OK (MA)) PutMap(MA, src); | |
| if (src == 0) PC = (PC + 1) & AMASK; | |
| break; | |
| case 003: /* DSZ */ | |
| src = (GetMap(MA) - 1) & 0177777; | |
| if (MEM_ADDR_OK (MA)) PutMap(MA, src); | |
| if (src == 0) PC = (PC + 1) & AMASK; | |
| break; | |
| case 004: /* LDA 0 */ | |
| if (SingleCycle) Usermap = SingleCycle; | |
| AC[0] = GetMap(MA); | |
| if (SingleCycle) { | |
| Usermap = SingleCycle = 0; | |
| if (Inhibit == 1) Inhibit = 3; | |
| MapStat |= 02000; | |
| MapStat &= 0177776; | |
| } | |
| break; | |
| case 005: /* LDA 1 */ | |
| if (SingleCycle) Usermap = SingleCycle; | |
| AC[1] = GetMap(MA); | |
| if (SingleCycle) { | |
| Usermap = SingleCycle = 0; | |
| if (Inhibit == 1) Inhibit = 3; | |
| MapStat |= 02000; | |
| MapStat &= 0177776; | |
| } | |
| break; | |
| case 006: /* LDA 2 */ | |
| if (SingleCycle) Usermap = SingleCycle; | |
| AC[2] = GetMap(MA); | |
| if (SingleCycle) { | |
| Usermap = SingleCycle = 0; | |
| if (Inhibit == 1) Inhibit = 3; | |
| MapStat |= 02000; | |
| MapStat &= 0177776; | |
| } | |
| break; | |
| case 007: /* LDA 3 */ | |
| if (SingleCycle) Usermap = SingleCycle; | |
| AC[3] = GetMap(MA); | |
| if (SingleCycle) { | |
| Usermap = SingleCycle = 0; | |
| if (Inhibit == 1) Inhibit = 3; | |
| MapStat |= 02000; | |
| MapStat &= 0177776; | |
| } | |
| break; | |
| case 010: /* STA 0 */ | |
| if (SingleCycle) | |
| Usermap = SingleCycle; | |
| if (MEM_ADDR_OK (MA)) PutMap(MA, AC[0]); | |
| if (SingleCycle) { | |
| Usermap = SingleCycle = 0; | |
| if (Inhibit == 1) Inhibit = 3; | |
| MapStat |= 02000; | |
| MapStat &= 0177776; | |
| } | |
| break; | |
| case 011: /* STA 1 */ | |
| if (SingleCycle) | |
| Usermap = SingleCycle; | |
| if (MEM_ADDR_OK (MA)) PutMap(MA, AC[1]); | |
| if (SingleCycle) { | |
| Usermap = SingleCycle = 0; | |
| if (Inhibit == 1) Inhibit = 3; | |
| MapStat |= 02000; | |
| MapStat &= 0177776; | |
| } | |
| break; | |
| case 012: /* STA 2 */ | |
| if (SingleCycle) | |
| Usermap = SingleCycle; | |
| if (MEM_ADDR_OK (MA)) PutMap(MA, AC[2]); | |
| if (SingleCycle) { | |
| Usermap = SingleCycle = 0; | |
| if (Inhibit == 1) Inhibit = 3; | |
| MapStat |= 02000; | |
| MapStat &= 0177776; | |
| } | |
| break; | |
| case 013: /* STA 3 */ | |
| if (SingleCycle) | |
| Usermap = SingleCycle; | |
| if (MEM_ADDR_OK (MA)) PutMap(MA, AC[3]); | |
| if (SingleCycle) { | |
| Usermap = SingleCycle = 0; | |
| if (Inhibit == 1) Inhibit = 3; | |
| MapStat |= 02000; | |
| MapStat &= 0177776; | |
| } | |
| break; | |
| } /* end switch */ | |
| } /* end mem ref */ | |
| /* Operate instruction */ | |
| else if (t & 020) { /* operate? */ | |
| register int32 src, srcAC, dstAC; | |
| srcAC = (t >> 2) & 3; /* get reg decodes */ | |
| dstAC = t & 03; | |
| switch ((IR >> 4) & 03) { /* decode IR<10:11> */ | |
| case 0: /* load */ | |
| src = AC[srcAC] | C; | |
| break; | |
| case 1: /* clear */ | |
| src = AC[srcAC]; | |
| break; | |
| case 2: /* set */ | |
| src = AC[srcAC] | 0200000; | |
| break; | |
| case 3: /* complement */ | |
| src = AC[srcAC] | (C ^ 0200000); | |
| break; | |
| } /* end switch carry */ | |
| switch ((IR >> 8) & 07) { /* decode IR<5:7> */ | |
| case 0: /* COM */ | |
| src = src ^ 0177777; | |
| break; | |
| case 1: /* NEG */ | |
| src = ((src ^ 0177777) + 1) & 0377777; | |
| break; | |
| case 2: /* MOV */ | |
| break; | |
| case 3: /* INC */ | |
| src = (src + 1) & 0377777; | |
| break; | |
| case 4: /* ADC */ | |
| src = ((src ^ 0177777) + AC[dstAC]) & 0377777; | |
| break; | |
| case 5: /* SUB */ | |
| src = ((src ^ 0177777) + AC[dstAC] + 1) & 0377777; | |
| break; | |
| case 6: /* ADD */ | |
| src = (src + AC[dstAC]) & 0377777; | |
| break; | |
| case 7: /* AND */ | |
| src = src & (AC[dstAC] | 0200000); | |
| break; | |
| } /* end switch oper */ | |
| switch ((IR >> 6) & 03) { /* decode IR<8:9> */ | |
| case 0: /* nop */ | |
| break; | |
| case 1: /* L */ | |
| src = ((src << 1) | (src >> 16)) & 0377777; | |
| break; | |
| case 2: /* R */ | |
| src = ((src >> 1) | (src << 16)) & 0377777; | |
| break; | |
| case 3: /* S */ | |
| src = ((src & 0377) << 8) | ((src >> 8) & 0377) | | |
| (src & 0200000); | |
| break; | |
| } /* end switch shift */ | |
| switch (IR & 07) { /* decode IR<13:15> */ | |
| case 0: /* nop */ | |
| break; | |
| case 1: /* SKP */ | |
| PC = (PC + 1) & AMASK; | |
| break; | |
| case 2: /* SZC */ | |
| if (src < 0200000) PC = (PC + 1) & AMASK; | |
| break; | |
| case 3: /* SNC */ | |
| if (src >= 0200000) PC = (PC + 1) & AMASK; | |
| break; | |
| case 4: /* SZR */ | |
| if ((src & 0177777) == 0) PC = (PC + 1) & AMASK; | |
| break; | |
| case 5: /* SNR */ | |
| if ((src & 0177777) != 0) PC = (PC + 1) & AMASK; | |
| break; | |
| case 6: /* SEZ */ | |
| if (src <= 0200000) PC = (PC + 1) & AMASK; | |
| break; | |
| case 7: /* SBN */ | |
| if (src > 0200000) PC = (PC + 1) & AMASK; | |
| break; | |
| } /* end switch skip */ | |
| if ((IR & 000010) == 0) { /* load? */ | |
| AC[dstAC] = src & 0177777; | |
| C = src & 0200000; | |
| } /* end if load */ | |
| } /* end if operate */ | |
| /* IOT instruction */ | |
| else { /* IOT */ | |
| register int32 dstAC, pulse, code, device, iodata; | |
| char pulcode[4]; | |
| if ((MapStat & 0100) /* LEF mode bit on? */ | |
| && Usermap) { /* We are in LEF Mode */ | |
| AC[(IR >> 11) & 3] = LEFmode(PC - 1, (IR >> 8) & 3, IR & 0377, IR & 02000); | |
| if (Debug_Flags & 020000) { | |
| printf("\n\r<<LEF Break by special request - executed at %o.>>\n\r", PC-1); | |
| reason = STOP_IBKPT; | |
| } | |
| continue; | |
| } | |
| dstAC = t & 03; /* decode fields */ | |
| if ((MapStat & 040) && Usermap) { /* I/O protection fault */ | |
| Fault = 020000; | |
| continue; | |
| } | |
| code = (IR >> 8) & 07; | |
| pulse = (IR >> 6) & 03; | |
| device = IR & 077; | |
| if (Debug_Flags && device == 0) { | |
| printf("\n\r<<I/O to device 00 at %o.>>\n\r", PC-1); | |
| reason = STOP_IBKPT; | |
| continue; | |
| } | |
| if ((Debug_Flags & 0100) && (device == (Debug_Flags & 077))) { | |
| printf("\n\r<<I/O Break (device %o) >>\n\r", device); | |
| reason = STOP_IBKPT; | |
| continue; | |
| } | |
| if ((Debug_Char != 0) && (device == 011) && | |
| ((AC[dstAC] & 0177) == Debug_Char)) { | |
| printf("\n\r<<I/O Break (Char %o to TTO) >>\n\r", Debug_Char); | |
| reason = STOP_IBKPT; | |
| continue; | |
| } | |
| if (code == ioSKP) { /* IO skip? */ | |
| switch (pulse) { /* decode IR<8:9> */ | |
| case 0: /* skip if busy */ | |
| if ((device == 077)? (int_req & INT_ION) != 0: | |
| (dev_busy & dev_table[device].mask) != 0) | |
| PC = (PC + 1) & AMASK; | |
| break; | |
| case 1: /* skip if not busy */ | |
| if ((device == 077)? (int_req & INT_ION) == 0: | |
| (dev_busy & dev_table[device].mask) == 0) | |
| PC = (PC + 1) & AMASK; | |
| break; | |
| case 2: /* skip if done */ | |
| if ((device == 077)? pwr_low != 0: | |
| (dev_done & dev_table[device].mask) != 0) | |
| PC = (PC + 1) & AMASK; | |
| break; | |
| case 3: /* skip if not done */ | |
| if ((device == 077)? pwr_low == 0: | |
| (dev_done & dev_table[device].mask) == 0) | |
| PC = (PC + 1) & AMASK; | |
| break; | |
| } /* end switch */ | |
| } /* end IO skip */ | |
| else if (device == DEV_CPU) { /* CPU control */ | |
| switch (code) { /* decode IR<5:7> */ | |
| case ioNIO: /* Get CPU ID */ | |
| switch (model) { | |
| case 280: /* S280 */ | |
| AC[0] = 021102; | |
| break; | |
| case 380: | |
| AC[0] = 013212; /* C380 */ | |
| break; | |
| default: | |
| break; | |
| } | |
| break; /* Otherwise no-op */ | |
| case ioDIA: /* read switches */ | |
| AC[dstAC] = SR; | |
| break; | |
| case ioDIB: /* int ack */ | |
| AC[dstAC] = 0; | |
| int_req = (int_req & ~INT_DEV) | | |
| (dev_done & ~dev_disable); | |
| iodata = int_req & (-int_req); | |
| for (i = DEV_LOW; i <= DEV_HIGH; i++) { | |
| if (iodata & dev_table[i].mask) { | |
| AC[dstAC] = i; | |
| break; | |
| } | |
| } | |
| break; | |
| case ioDOB: /* mask out */ | |
| mask_out (pimask = AC[dstAC]); | |
| break; | |
| case ioDIC: /* io reset IORST */ | |
| reset_all (0); /* reset devices */ | |
| Usermap = 0; /* reset MAP */ | |
| MapStat &= 04; /* Reset MAP status */ | |
| MapIntMode = 0; | |
| Inhibit = 0; | |
| Map31 = 037; | |
| Check = SingleCycle = 0; | |
| Fault = 0; | |
| FPSR &= 0x0000FFFF; | |
| FPFault = 0; | |
| break; | |
| case ioDOC: /* halt */ | |
| reason = STOP_HALT; | |
| break; | |
| } /* end switch code */ | |
| switch (pulse) { /* decode IR<8:9> */ | |
| case iopS: /* ion */ | |
| int_req = (int_req | INT_ION) & ~INT_NO_ION_PENDING; | |
| break; | |
| case iopC: /* iof */ | |
| int_req = int_req & ~INT_ION; | |
| break; } /* end switch pulse */ | |
| } /* end CPU control */ | |
| else if (device == DEV_ECC) { | |
| switch (code) { | |
| case ioDIA: /* Read Fault Address */ | |
| AC[dstAC] = 0; | |
| break; | |
| case ioDIB: /* Read fault code */ | |
| AC[dstAC] = 0; | |
| break; | |
| case ioDOA: /* Enable ERCC */ | |
| break; } | |
| } | |
| else if (device == DEV_MAP) { /* MAP control */ | |
| switch (code) { /* decode IR<5:7> */ | |
| case ioNIO: /* No I/O -- Single */ | |
| if (!Usermap || !(MapStat & 0140)) { | |
| if ((Debug_Flags & 077) == 03) | |
| fprintf(Trace, "%o NIO %o (No I/O, clear faults)\n", PC-1, dstAC); | |
| MapStat &= ~036000; /* NIO Clears all faults */ | |
| } else { | |
| if ((Debug_Flags & 077) == 03) | |
| fprintf(Trace, "%o NIO %o (No I/O, clear faults) NO EXEC(User mode)\n", PC-1, dstAC); | |
| } | |
| break; | |
| case ioDIA: /* Read map status */ | |
| if (!Usermap || !(MapStat & 0140)) { | |
| if ((Debug_Flags & 077) == 03) | |
| fprintf(Trace, "%o DIA %o=%o (Read Map Status)\n", PC-1, dstAC, MapStat); | |
| AC[dstAC] = MapStat & 0xFFFE; | |
| if (MapIntMode & 1) /* Bit 15 is mode asof last int */ | |
| AC[dstAC] |= 1; | |
| } else { | |
| if ((Debug_Flags & 077) == 03) | |
| fprintf(Trace, "%o DIA %o=%o (Read Map Status) NO EXEC(User mode)\n", PC-1, dstAC, MapStat); | |
| } | |
| break; | |
| case ioDOA: /* Load map status */ | |
| if (!Usermap || !(MapStat & 0140)) { | |
| if ((Debug_Flags & 077) == 03) | |
| fprintf(Trace, "%o DOA %o=%o (Load Map Status)\n", PC-1, dstAC, AC[dstAC]); | |
| MapStat = AC[dstAC]; | |
| MapIntMode = 0; | |
| Enable = 1; | |
| if (MapStat & 04) Enable = 2; | |
| Check &= ~01600; | |
| Check |= MapStat & 01600; | |
| if (MapStat & 1) | |
| Inhibit = 2; /* Inhibit interrupts */ | |
| } else { | |
| if ((Debug_Flags & 077) == 03) | |
| fprintf(Trace, "%o DOA %o=%o (Load Map Status) NO EXEC(User mode)\n", PC-1, dstAC, AC[dstAC]); | |
| } | |
| break; | |
| case ioDIB: /* not used */ | |
| break; | |
| case ioDOB: /* map block 31 */ | |
| //AOS if (!Usermap || !(MapStat && 0140)) { | |
| if ((Debug_Flags & 077) == 03) | |
| fprintf(Trace, "%o DOB %o=%o (Map Blk 31)\n", PC-1, dstAC, AC[dstAC]); | |
| Map31 = AC[dstAC] & PAGEMASK; | |
| MapStat &= ~02000; | |
| //AOS } else { | |
| //AOS if ((Debug_Flags & 077) == 03) | |
| //AOS fprintf(Trace, "%o DOB %o=%o (Map Blk 31) NO EXEC (User Mode)\n", PC-1, dstAC, AC[dstAC]); | |
| //AOS } | |
| break; | |
| case ioDIC: /* Page Check */ | |
| if (!Usermap || !(MapStat & 0140)) { | |
| switch ((Check>>7) & 07) { | |
| case 0: i=1; break; | |
| case 1: i=6; break; | |
| case 2: i=2; break; | |
| case 3: i=7; break; | |
| case 4: i=0; break; | |
| case 5: i=4; break; | |
| case 6: i=3; break; | |
| case 7: i=5; break; | |
| default: break; | |
| } | |
| j = (Check >> 10) & 037; | |
| AC[dstAC] = Map[i][j] & 0101777; | |
| AC[dstAC] |= ((Check << 5) & 070000); | |
| if ((Debug_Flags & 077) == 03) | |
| fprintf(Trace, "%o DIC %o=%o (Page Check)\n", PC-1, dstAC, AC[dstAC]); | |
| MapStat &= ~02000; | |
| } else { | |
| if ((Debug_Flags & 077) == 03) | |
| fprintf(Trace, "%o DIC %o=%o (Page Check) NO EXEC(User mode)\n", PC-1, dstAC, AC[dstAC]); | |
| } | |
| break; | |
| case ioDOC: /* Init Page Check */ | |
| if (!Usermap || !(MapStat & 0140)) { | |
| if ((Debug_Flags & 077) == 03) | |
| fprintf(Trace, "%o DOC %o=%o (Init Pg Chk)\n", PC-1, dstAC, AC[dstAC]); | |
| Check = AC[dstAC]; | |
| MapStat &= ~01600; | |
| MapStat |= (Check & 01600); | |
| MapStat &= ~02000; | |
| } else { | |
| if ((Debug_Flags & 077) == 03) | |
| fprintf(Trace, "%o DOC %o=%o (Init Pg Chk) NO EXEC(User mode)\n", PC-1, dstAC, AC[dstAC]); | |
| } | |
| break; | |
| } /* end switch code */ | |
| switch (pulse) { | |
| case iopP: | |
| if ((Debug_Flags & 077) == 03) | |
| fprintf(Trace, "%o xxxP (Single Cycle)\n", PC-1); | |
| if (Usermap) { | |
| MapStat &= 0177776; | |
| Usermap = 0; | |
| Inhibit = 0; | |
| } else { | |
| SingleCycle = Enable; | |
| Inhibit = 1; /* Inhibit interrupts */ | |
| } | |
| break; | |
| } | |
| } /* end CPU control */ | |
| else if (dev_table[device].routine) { /* normal device */ | |
| iodata = dev_table[device].routine (pulse, code, AC[dstAC]); | |
| reason = iodata >> IOT_V_REASON; | |
| if (code & 1) AC[dstAC] = iodata & 0177777; | |
| if ((Debug_Flags & 077) == device && Debug_Flags != 0) { | |
| strcpy(pulcode, ""); | |
| switch (pulse) { | |
| case iopP: | |
| strcpy(pulcode, "P"); | |
| break; | |
| case iopS: | |
| strcpy(pulcode, "S"); | |
| break; | |
| case iopC: | |
| strcpy(pulcode, "C"); | |
| break; | |
| default: | |
| break; | |
| } | |
| switch(code) { | |
| case ioNIO: | |
| fprintf(Trace, "[%o] %o NIO%s %o\n", device, PC-1, pulcode, AC[dstAC]); | |
| break; | |
| case ioDIA: | |
| fprintf(Trace, "[%o] %o DIA%s %o\n", device, PC-1, pulcode, iodata); | |
| break; | |
| case ioDIB: | |
| fprintf(Trace, "[%o] %o DIB%s %o\n", device, PC-1, pulcode, iodata); | |
| break; | |
| case ioDIC: | |
| fprintf(Trace, "[%o] %o DIC%s %o\n", device, PC-1, pulcode, iodata); | |
| break; | |
| case ioDOA: | |
| fprintf(Trace, "[%o] %o DOA%s %o\n", device, PC-1, pulcode, AC[dstAC]); | |
| break; | |
| case ioDOB: | |
| fprintf(Trace, "[%o] %o DOB%s %o\n", device, PC-1, pulcode, AC[dstAC]); | |
| break; | |
| case ioDOC: | |
| fprintf(Trace, "[%o] %o DOC%s %o\n", device, PC-1, pulcode, AC[dstAC]); | |
| break; | |
| default: | |
| break; | |
| } /* end switch */ | |
| } /* end if debug */ | |
| } /* end else if */ | |
| else reason = stop_dev; | |
| } /* end if IOT */ | |
| } /* end while */ | |
| /* Simulation halted */ | |
| saved_PC = PC; | |
| return reason; | |
| } | |
| /* Computes and returns a 16-bit effective address, given a | |
| program counter, index, and a displacement. | |
| */ | |
| int32 effective(int32 PC, int32 index, int32 disp) | |
| { | |
| register int32 i, MA; | |
| MA = disp & 077777; | |
| switch (index) { /* decode IR<6:7> */ | |
| case 0: /* page zero */ | |
| break; | |
| case 1: /* PC relative */ | |
| MA = (MA + PC) & AMASK; | |
| break; | |
| case 2: /* AC2 relative */ | |
| MA = (MA + AC[2]) & AMASK; | |
| break; | |
| case 3: /* AC3 relative */ | |
| MA = (MA + AC[3]) & AMASK; | |
| break; | |
| } /* end switch mode */ | |
| if (disp & 0100000) { /* indirect? */ | |
| for (i = 0; i < ind_max * 2; i++) { /* count indirects */ | |
| MA = GetMap(MA & AMASK); | |
| if (SingleCycle) Usermap = 0; | |
| if (MapStat & 1) { /* Start MAP */ | |
| Usermap = Enable; | |
| Inhibit = 0; | |
| } | |
| if ((MA & 0100000) == 0) break; | |
| if ((MapStat & 010) && Usermap && i >= ind_max) break; | |
| } | |
| if (i >= (ind_max-1) && (MapStat & 010) && Usermap) { | |
| Fault = 04000; /* Map fault if IND prot */ | |
| } | |
| if (i >= (ind_max * 2) && !(Fault)) { | |
| reason = STOP_IND_INT; /* Stop machine */ | |
| } | |
| } | |
| return (MA & AMASK); | |
| } | |
| /* Computes and returns a 16-bit effective address, given a | |
| program counter, index, and a displacement. This is a | |
| version supporting the LEF map mode instruction, as | |
| opposed to the ELEF instruction. | |
| */ | |
| int32 LEFmode(int32 PC, int32 index, int32 disp, int32 indirect) | |
| { | |
| register int32 i, MA; | |
| int16 sMA; | |
| MA = disp & 077777; | |
| switch (index) { /* decode IR<6:7> */ | |
| case 0: /* page zero */ | |
| break; | |
| case 1: /* PC relative */ | |
| sMA = MA; | |
| if (MA & 0200) sMA |= 0xff00; | |
| MA = (sMA + PC) & AMASK; | |
| break; | |
| case 2: /* AC2 relative */ | |
| sMA = MA; | |
| if (MA & 0200) sMA |= 0xff00; | |
| MA = (sMA + AC[2]) & AMASK; | |
| break; | |
| case 3: /* AC3 relative */ | |
| sMA = MA; | |
| if (MA & 0200) sMA |= 0xff00; | |
| MA = (sMA + AC[3]) & AMASK; | |
| break; | |
| } /* end switch mode */ | |
| if (indirect) { /* indirect? */ | |
| for (i = 0; i < (ind_max * 2); i++) { /* count indirects */ | |
| if ((MA & 077770) == 020 && !(cpu_unit.flags & UNIT_MICRO)) | |
| MA = (PutMap(MA & AMASK, (GetMap(MA & AMASK) + 1) & 0177777)); | |
| else if ((MA & 077770) == 030 && !(cpu_unit.flags & UNIT_MICRO)) | |
| MA = (PutMap(MA & AMASK, (GetMap(MA & AMASK) - 1) & 0177777)); | |
| else MA = GetMap(MA & AMASK); | |
| if (SingleCycle) Usermap = 0; | |
| if (MapStat & 1) { /* Start MAP */ | |
| Usermap = Enable; | |
| Inhibit = 0; | |
| } | |
| if ((MA & 0100000) == 0) break; | |
| if ((MapStat & 010) && Usermap && i >= ind_max) break; | |
| } | |
| if (i >= (ind_max-1) && (MapStat & 010) && Usermap) { | |
| Fault = 04000; /* Map fault if IND prot */ | |
| } | |
| if (i >= (ind_max * 2) && !(Fault)) { | |
| reason = STOP_IND_INT; /* Stop machine */ | |
| } | |
| } | |
| return (MA & AMASK); | |
| } | |
| /* Computes a "Byte pointer" for the Character Instruction set */ | |
| /* This address in 'PC' must point to the displacement word of the instruction */ | |
| int32 Bytepointer(int32 PC, int32 index) | |
| { | |
| register int32 MA; | |
| switch (index) { /* decode IR<6:7> */ | |
| case 0: /* page zero */ | |
| MA = 0; | |
| break; | |
| case 1: /* PC relative */ | |
| MA = PC & AMASK; | |
| break; | |
| case 2: /* AC2 relative */ | |
| MA = AC[2] & AMASK; | |
| break; | |
| case 3: /* AC3 relative */ | |
| MA = AC[3] & AMASK; | |
| break; | |
| } /* end switch mode */ | |
| MA = (MA * 2) & 0177777; | |
| MA = MA + GetMap(PC); | |
| return (MA & 0177777); | |
| } | |
| /* Given an address, returns either that address if bit 0 is 0, or | |
| or follows an indirection chain until bit 0 is 0 | |
| */ | |
| int32 indirect(int32 d) | |
| { | |
| int i; | |
| if (d & 0100000) { /* indirect? */ | |
| for (i = 0; i < ind_max * 2; i++) { /* count indirects */ | |
| if ((d & 077770) == 020 && !(cpu_unit.flags & UNIT_MICRO)) | |
| d = (PutMap(d & AMASK, ((GetMap(d & AMASK) + 1) & 0177777))); | |
| else if ((d & 077770) == 030 && !(cpu_unit.flags & UNIT_MICRO)) | |
| d = (PutMap(d & AMASK, ((GetMap(d & AMASK) - 1) & 0177777))); | |
| else d = GetMap(d & AMASK); | |
| if (MapStat & 1) { /* Start MAP */ | |
| Usermap = Enable; | |
| Inhibit = 0; | |
| } | |
| if ((d & 0100000) == 0) break; | |
| if ((MapStat & 010) && Usermap && i >= ind_max) break; | |
| } | |
| if (i >= (ind_max-1) && (MapStat & 010) && Usermap) { | |
| Fault = 04000; /* Map fault if IND prot */ | |
| } | |
| if (i >= (ind_max * 2) && !(Fault)) { | |
| reason = STOP_IND; /* Stop machine */ | |
| } | |
| } | |
| return (d); | |
| } | |
| /* Push a standard return block onto the stack */ | |
| int32 pushrtn(int32 pc) | |
| { | |
| int32 t; | |
| t = (GetMap(040) + 1) & AMASK; | |
| PutMap(t, AC[0]); | |
| t++; | |
| PutMap(t, AC[1]); | |
| t++; | |
| PutMap(t, AC[2]); | |
| t++; | |
| PutMap(t, AC[3]); | |
| t++; | |
| PutMap(t, pc); | |
| if (C) PutMap(t, (GetMap(t) | 0100000)); | |
| PutMap(040, t); | |
| return 0; | |
| } | |
| /* Eclipse memory get/put - uses MAP if enabled */ | |
| int32 GetMap(int32 addr) | |
| { | |
| int32 page; | |
| t_addr paddr; | |
| switch (Usermap) { | |
| case 0: | |
| if (addr < 076000) | |
| return M[addr]; | |
| paddr = ((Map31 & PAGEMASK) << 10) | (addr & 001777); | |
| if (paddr < MEMSIZE) | |
| return M[paddr]; | |
| else | |
| return (0); | |
| break; | |
| case 1: | |
| page = (addr >> 10) & 037; | |
| paddr = ((Map[1][page] & 01777) << 10) | (addr & 001777); | |
| if (Map[1][page] == INVALID && !SingleCycle) | |
| Fault = 0100000/*!!!*/; /* Validity */ | |
| if (paddr < MEMSIZE) | |
| return M[paddr]; | |
| else | |
| return (0); | |
| break; | |
| case 2: | |
| page = (addr >> 10) & 037; | |
| paddr = ((Map[2][page] & PAGEMASK) << 10) | (addr & 001777); | |
| if (Map[2][page] == INVALID && !SingleCycle) | |
| Fault = 0100000/*!!!*/; /* Validity */ | |
| if (paddr < MEMSIZE) | |
| return M[paddr]; | |
| else | |
| return (0); | |
| break; | |
| case 6: | |
| page = (addr >> 10) & 037; | |
| paddr = ((Map[6][page] & PAGEMASK) << 10) | (addr & 001777); | |
| if (Map[6][page] == INVALID && !SingleCycle) | |
| Fault = 0100000/*!!!*/; /* Validity */ | |
| if (paddr < MEMSIZE) | |
| return M[paddr]; | |
| else | |
| return (0); | |
| break; | |
| case 7: | |
| page = (addr >> 10) & 037; | |
| paddr = ((Map[7][page] & PAGEMASK) << 10) | (addr & 001777); | |
| if (Map[7][page] == INVALID && !SingleCycle) | |
| Fault = 0100000/*!!!*/; /* Validity */ | |
| if (paddr < MEMSIZE) | |
| return M[paddr]; | |
| else | |
| return (0); | |
| break; | |
| default: | |
| printf("\n\r<<MAP FAULT>>\n\r"); | |
| return M[addr]; | |
| break; | |
| } | |
| } | |
| int32 PutMap(int32 addr, int32 data) | |
| { | |
| int32 page; | |
| t_addr paddr; | |
| switch (Usermap) { | |
| case 0: | |
| if (addr < 076000) { | |
| M[addr] = data; | |
| return (data); | |
| } | |
| paddr = ((Map31 & PAGEMASK) << 10) | (addr & 001777); | |
| if (paddr < MEMSIZE) M[paddr] = data; | |
| break; | |
| case 1: | |
| page = (addr >> 10) & 037; | |
| paddr = ((Map[1][page] & PAGEMASK) << 10) | (addr & 001777); | |
| if (((Map[1][page] & 0100000) && (MapStat & 020)) || Map[1][page] == INVALID) | |
| Fault = 010000; /* Write Protect Fault */ | |
| else if (paddr < MEMSIZE) M[paddr] = data; | |
| break; | |
| case 2: | |
| page = (addr >> 10) & 037; | |
| paddr = ((Map[2][page] & PAGEMASK) << 10) | (addr & 001777); | |
| if (((Map[2][page] & 0100000) && (MapStat & 020)) || Map[2][page] == INVALID) | |
| Fault = 010000; /* Write Protect Fault */ | |
| else if (paddr < MEMSIZE) M[paddr] = data; | |
| break; | |
| case 6: | |
| page = (addr >> 10) & 037; | |
| paddr = ((Map[2][page] & PAGEMASK) << 10) | (addr & 001777); | |
| if (((Map[6][page] & 0100000) && (MapStat & 020)) || Map[6][page] == INVALID) | |
| Fault = 010000; /* Write Protect Fault */ | |
| else if (paddr < MEMSIZE) M[paddr] = data; | |
| break; | |
| case 7: | |
| page = (addr >> 10) & 037; | |
| paddr = ((Map[2][page] & PAGEMASK) << 10) | (addr & 001777); | |
| if (((Map[7][page] & 0100000) && (MapStat & 020)) || Map[7][page] == INVALID) | |
| Fault = 010000; /* Write Protect Fault */ | |
| else if (paddr < MEMSIZE) M[paddr] = data; | |
| break; | |
| default: | |
| M[addr] = data; | |
| break; | |
| } | |
| return (data); | |
| } | |
| #if 0 | |
| int16 GetDCHMap(int32 map, int32 addr) | |
| { | |
| t_addr paddr; | |
| if (!(MapStat & 02)) return M[addr]; | |
| paddr = ((Map[map][(addr >> 10) & 037] & PAGEMASK) << 10) | (addr & 001777); | |
| if (paddr < MEMSIZE) | |
| return M[paddr]; | |
| return (0); | |
| } | |
| int16 PutDCHMap(int32 map, int32 addr, int16 data) | |
| { | |
| t_addr paddr; | |
| if (!(MapStat & 02)) { | |
| M[addr] = data; | |
| return (data); | |
| } | |
| paddr = ((Map[map][(addr >> 10) & 037] & PAGEMASK) << 10) | (addr & 001777); | |
| if (paddr < MEMSIZE) | |
| M[paddr] = data; | |
| return (data); | |
| } | |
| #endif | |
| /* Given a map number and a logical, returns the physical address, unless | |
| the map is not active, in which case logical = physical. This is | |
| used primarily by the I/O routines to map data channel read/writes. | |
| */ | |
| int32 MapAddr(int32 map, int32 addr) | |
| { | |
| int32 paddr; | |
| if ((map == 0 || map > 2) && !(MapStat & 02)) return addr; | |
| if (map > 0 && map < 3 && Usermap == 0) return addr; | |
| paddr = ((Map[map][(addr >> 10) & 037] & PAGEMASK) << 10) | (addr & 001777); | |
| return paddr; | |
| } | |
| /* Loads a word into the Eclipse Maps */ | |
| int32 LoadMap(int32 w) | |
| { | |
| int32 m; | |
| m = (w >> 10) & 037; | |
| switch ((MapStat >> 7) & 07) { | |
| case 0: /* Load user A Map */ | |
| Map[1][m] = w & MAPMASK; | |
| break; | |
| case 1: /* Load user C Map */ | |
| Map[6][m] = w & MAPMASK; | |
| break; | |
| case 2: /* Load user B Map */ | |
| Map[2][m] = w & MAPMASK; | |
| break; | |
| case 3: /* Load user D Map */ | |
| Map[7][m] = w & MAPMASK; | |
| break; | |
| case 4: /* Load DCH A Map */ | |
| Map[0][m] = w & MAPMASK; | |
| break; | |
| case 5: /* Load DCH C Map */ | |
| Map[4][m] = w; | |
| break; | |
| case 6: /* Load DCH B Map */ | |
| Map[3][m] = w; | |
| break; | |
| case 7: /* Load DCH D Map */ | |
| Map[5][m] = w; | |
| break; | |
| default: | |
| break; | |
| } | |
| return 0; | |
| } | |
| /* Displays an error on a unimplemented (in this sim) instr. */ | |
| int32 unimp(int32 PC) | |
| { | |
| if (Debug_Flags) | |
| printf("\n\r\007<<<Unimplemented instruction: [%o] %o>>>\n\r", PC - 1, GetMap(PC - 1)); | |
| return 0; | |
| } | |
| /* New priority mask out */ | |
| void mask_out (int32 newmask) | |
| { | |
| int32 i; | |
| dev_disable = 0; | |
| for (i = DEV_LOW; i <= DEV_HIGH; i++) { | |
| if (newmask & dev_table[i].pi) | |
| dev_disable = dev_disable | dev_table[i].mask; | |
| } | |
| int_req = (int_req & ~INT_DEV) | (dev_done & ~dev_disable); | |
| return; | |
| } | |
| /* Reset routine */ | |
| t_stat cpu_reset (DEVICE *dptr) | |
| { | |
| int_req = int_req & ~INT_ION; | |
| pimask = 0; | |
| dev_disable = 0; | |
| pwr_low = 0; | |
| sim_brk_types = sim_brk_dflt = SWMASK ('E'); | |
| return SCPE_OK; | |
| } | |
| /* Memory examine */ | |
| t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw) | |
| { | |
| if (sw & SWMASK ('V')) { | |
| if (addr > 077777) return SCPE_NXM; | |
| if (vptr != NULL) *vptr = GetMap (addr); | |
| } | |
| else { | |
| if (addr >= MEMSIZE) return SCPE_NXM; | |
| if (vptr != NULL) *vptr = M[addr] & 0177777; | |
| } | |
| return SCPE_OK; | |
| } | |
| /* Memory deposit */ | |
| t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw) | |
| { | |
| if (sw & SWMASK ('V')) { | |
| if (addr > 077777) return SCPE_NXM; | |
| PutMap (addr, (int32) val); | |
| } | |
| else { | |
| if (addr >= MEMSIZE) return SCPE_NXM; | |
| M[addr] = (int32) val & 0177777; | |
| } | |
| return SCPE_OK; | |
| } | |
| /* Alter memory size */ | |
| t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc) | |
| { | |
| int32 mc = 0; | |
| t_addr i; | |
| if ((val <= 0) || (val > MAXMEMSIZE) || ((val & 07777) != 0)) | |
| return SCPE_ARG; | |
| for (i = val; i < MEMSIZE; i++) mc = mc | M[i]; | |
| if ((mc != 0) && (!get_yn ("Really truncate memory [N]?", FALSE))) | |
| return SCPE_OK; | |
| MEMSIZE = val; | |
| for (i = MEMSIZE; i < MAXMEMSIZE; i++) M[i] = 0; | |
| return SCPE_OK; | |
| } | |
| /* MAP device services */ | |
| t_stat map_svc (UNIT *uptr) | |
| { | |
| return SCPE_OK; | |
| } | |
| /* Map examine */ | |
| t_stat map_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw) | |
| { | |
| if ((addr & 077) >= 037 || addr > 737) return SCPE_NXM; | |
| uptr->u4 = -2; /* signal to print_sys in eclipse_sys.c: do not map */ | |
| if (vptr != NULL) *vptr = Map[(addr >> 6) & 3][addr & 037] & 0177777; | |
| return SCPE_OK; | |
| } | |
| /* Memory deposit */ | |
| t_stat map_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw) | |
| { | |
| if ((addr & 077) >= 037 || addr > 0737) return SCPE_NXM; | |
| uptr->u4 = -2; /* signal to print_sys in eclipse_sys.c: do not map */ | |
| Map[(addr >> 6) & 3][addr & 037] = (int32)val & 0177777; | |
| return SCPE_OK; | |
| } | |
| /* FPU device services */ | |
| t_stat fpu_svc (UNIT *uptr) | |
| { | |
| return SCPE_OK; | |
| } | |
| /* PIT Device Services */ | |
| /* IOT routine */ | |
| int32 pit (int32 pulse, int32 code, int32 AC) | |
| { | |
| int32 iodata = 0; | |
| if (code == ioDIA) { /* DIA */ | |
| if (pit_flag == 0) { | |
| pit_flag = 1; | |
| } | |
| iodata = pit_counter; | |
| } | |
| if (code == ioDOA) { /* DOA */ | |
| pit_initial = AC; /* Load Counter */ | |
| sim_rtcn_init (pit_time, 1); /* init calibr */ | |
| } | |
| switch (pulse) { /* decode IR<8:9> */ | |
| case iopS: /* start */ | |
| pit_counter = pit_initial; /* Set the counter */ | |
| dev_busy = dev_busy | INT_PIT; /* set busy */ | |
| dev_done = dev_done & ~INT_PIT; /* clear done, int */ | |
| int_req = int_req & ~INT_PIT; | |
| if (!sim_is_active (&pit_unit)) /* not running? */ | |
| sim_activate (&pit_unit, /* activate */ | |
| sim_rtcn_init (pit_time, 1)); /* init calibr */ | |
| break; | |
| case iopC: /* clear */ | |
| dev_busy = dev_busy & ~INT_PIT; /* clear busy */ | |
| dev_done = dev_done & ~INT_PIT; /* clear done, int */ | |
| int_req = int_req & ~INT_PIT; | |
| sim_cancel (&pit_unit); /* deactivate unit */ | |
| break; } /* end switch */ | |
| return iodata; | |
| } | |
| /* Unit service */ | |
| t_stat pit_svc (UNIT *uptr) | |
| { | |
| int32 t; | |
| t = sim_rtcn_calb (pit_tps, 1); /* calibrate delay */ | |
| sim_activate (&pit_unit, t); /* reactivate unit */ | |
| pit_poll = t / (-pit_adj); /* adjust poll */ | |
| pit_counter++; /* Increment counter */ | |
| if (pit_counter >= 0177777) { /* Has counter reached limit ? */ | |
| dev_done = dev_done | INT_PIT; /* set done */ | |
| dev_busy = dev_busy & ~INT_PIT; /* clear busy */ | |
| int_req = (int_req & ~INT_DEV) | (dev_done & ~dev_disable); /* Interrupt */ | |
| pit_counter = pit_initial; | |
| } | |
| return SCPE_OK; | |
| } | |
| /* Reset routine */ | |
| t_stat pit_reset (DEVICE *dptr) | |
| { | |
| pit_counter = 0; /* clear counter */ | |
| dev_busy = dev_busy & ~INT_PIT; /* clear busy */ | |
| dev_done = dev_done & ~INT_PIT; /* clear done, int */ | |
| int_req = int_req & ~INT_PIT; | |
| sim_cancel (&pit_unit); /* deactivate unit */ | |
| pit_poll = pit_time; /* poll is default */ | |
| return SCPE_OK; | |
| } | |
| /* Bootstrap routine for CPU */ | |
| #define BOOT_START 00000 | |
| #define BOOT_LEN (sizeof (boot_rom) / sizeof (int)) | |
| static const int32 boot_rom[] = { | |
| 062677, /* IORST ;Reset all I/O */ | |
| 060477, /* READS 0 ;Read SR into AC0 */ | |
| 024026, /* LDA 1,C77 ;Get dev mask */ | |
| 0107400, /* AND 0,1 ;Isolate dev code */ | |
| 0124000, /* COM 1,1 ;- device code - 1 */ | |
| 010014, /* LOOP: ISZ OP1 ;Device code to all */ | |
| 010030, /* ISZ OP2 ;I/O instructions */ | |
| 010032, /* ISZ OP3 */ | |
| 0125404, /* INC 1,1,SZR ;done? */ | |
| 000005, /* JMP LOOP ;No, increment again */ | |
| 030016, /* LDA 2,C377 ;place JMP 377 into */ | |
| 050377, /* STA 2,377 ;location 377 */ | |
| 060077, /* OP1: 060077 ;start device (NIOS 0) */ | |
| 0101102, /* MOVL 0,0,SZC ;Test switch 0, low speed? */ | |
| 000377, /* C377: JMP 377 ;no - jmp 377 & wait */ | |
| 004030, /* LOOP2: JSR GET+1 ;Get a frame */ | |
| 0101065, /* MOVC 0,0,SNR ;is it non-zero? */ | |
| 000017, /* JMP LOOP2 ;no, ignore */ | |
| 004027, /* LOOP4: JSR GET ;yes, get full word */ | |
| 046026, /* STA 1,@C77 ;store starting at 100 */ | |
| /* ;2's complement of word ct */ | |
| 010100, /* ISZ 100 ;done? */ | |
| 000022, /* JMP LOOP4 ;no, get another */ | |
| 000077, /* C77: JMP 77 ;yes location ctr and */ | |
| /* ;jmp to last word */ | |
| 0126420, /* GET: SUBZ 1,1 ; clr AC1, set carry */ | |
| /* OP2: */ | |
| 063577, /* LOOP3: 063577 ;done? (SKPDN 0) - 1 */ | |
| 000030, /* JMP LOOP3 ;no -- wait */ | |
| 060477, /* OP3: 060477 ;y--read in ac0 (DIAS 0,0) */ | |
| 0107363, /* ADDCS 0,1,SNC ;add 2 frames swapped - got 2nd? */ | |
| 000030, /* JMP LOOP3 ;no go back after it */ | |
| 0125300, /* MOVS 1,1 ;yes swap them */ | |
| 001400, /* JMP 0,3 ;rtn with full word */ | |
| 0 /* 0 ;padding */ | |
| }; | |
| t_stat cpu_boot (int32 unitno, DEVICE *dptr) | |
| { | |
| int32 i; | |
| extern int32 saved_PC; | |
| for (i = 0; i < BOOT_LEN; i++) M[BOOT_START + i] = boot_rom[i]; | |
| saved_PC = BOOT_START; | |
| return SCPE_OK; | |
| } | |
| int32 Debug_Entry(int32 PC, int32 inst, int32 inst2, int32 AC0, int32 AC1, int32 AC2, int32 AC3, int32 flags) | |
| { | |
| hpc[hnext] = PC & 0xffff; | |
| hinst[hnext] = inst & 0xffff; | |
| hinst2[hnext] = inst2 & 0xffff; | |
| hac0[hnext] = AC0 & 0xffff; | |
| hac1[hnext] = AC1 & 0xffff; | |
| hac2[hnext] = AC2 & 0xffff; | |
| hac3[hnext] = AC3 & 0xffff; | |
| hflags[hnext] = flags & 0xffff; | |
| hnext++; | |
| if (hnext >= hmax) { | |
| hwrap = 1; | |
| hnext = 0; | |
| } | |
| return 0; | |
| } | |
| t_stat Debug_Dump(UNIT *uptr, int32 val, char *cptr, void *desc) | |
| { | |
| return SCPE_OK; | |
| } | |
| t_stat Dump_History (FILE *st, UNIT *uptr, int32 val, void *desc) | |
| { | |
| char debmap[4], debion[4]; | |
| t_value simeval[20]; | |
| int debcar; | |
| int start, end, ctr; | |
| int count = 0; | |
| if (!Debug_Flags || Debug_Flags & 0100000) { | |
| printf("History was not logged. Deposit a non-zero value\n"); | |
| printf("in DEBUG with bit 0 being 1 to build history.\n"); | |
| return SCPE_OK; | |
| } | |
| if (!hwrap) { | |
| start = 0; | |
| end = hnext; | |
| } else { | |
| start = hnext; | |
| end = hnext - 1; | |
| if (end < 0) end = hmax; | |
| } | |
| ctr = start; | |
| while (1) { | |
| if (ctr == end) | |
| break; | |
| count++; | |
| strcpy(debion, " "); | |
| strcpy(debmap, " "); | |
| debcar = 0; | |
| if (hflags[ctr] & 0x80) { | |
| fprintf(st, "--------- Interrupt %o (%o) to %6o ---------\n", | |
| hinst[ctr], hac0[ctr], hac1[ctr]); | |
| } else { | |
| if (hflags[ctr] & 0x01) debcar = 1; | |
| if (hflags[ctr] & 0x02) strcpy(debion, "I"); | |
| if (hflags[ctr] & 0x04) strcpy(debmap, "A"); | |
| if (hflags[ctr] & 0x08) strcpy(debmap, "B"); | |
| if (hflags[ctr] & 0x10) strcpy(debmap, "C"); | |
| if (hflags[ctr] & 0x20) strcpy(debmap, "D"); | |
| fprintf(st, "%s%s%06o acs: %06o %06o %06o %06o %01o ", | |
| debion, debmap, hpc[ctr], hac0[ctr], hac1[ctr], hac2[ctr], | |
| hac3[ctr], debcar); | |
| simeval[0] = hinst[ctr]; | |
| simeval[1] = hinst2[ctr]; | |
| fprint_sym (st, hpc[ctr], simeval, NULL, SWMASK('M')); | |
| fprintf(st, "\n"); | |
| } | |
| ctr++; | |
| if (ctr > hmax) | |
| ctr = 0; | |
| } | |
| return SCPE_OK; | |
| } | |
| /* Build dispatch table */ | |
| t_stat build_devtab (void) | |
| { | |
| DEVICE *dptr; | |
| DIB *dibp; | |
| int32 i, dn; | |
| for (i = 0; i < 64; i++) { /* clr dev_table */ | |
| dev_table[i].mask = 0; | |
| dev_table[i].pi = 0; | |
| dev_table[i].routine = NULL; | |
| } | |
| for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { /* loop thru dev */ | |
| if (!(dptr->flags & DEV_DIS) && /* enabled and */ | |
| (dibp = (DIB *) dptr->ctxt)) { /* defined DIB? */ | |
| dn = dibp->dnum; /* get dev num */ | |
| dev_table[dn].mask = dibp->mask; /* copy entries */ | |
| dev_table[dn].pi = dibp->pi; | |
| dev_table[dn].routine = dibp->routine; | |
| } | |
| } | |
| return SCPE_OK; | |
| } | |
| /* ------------------------------------------------------------------- */ | |
| /* Floating Point Arithmetic */ | |
| /* ------------------------------------------------------------------- */ | |
| /* Get short float from FPAC */ | |
| void get_sf (SHORT_FLOAT *fl, t_int64 *fpr) | |
| { | |
| fl->sign = (uint8)(*fpr >> 63) & 1; | |
| fl->expo = (short)(*fpr >> 56) & 0x007F; | |
| fl->short_fract = (int32)(*fpr >> 32) & 0x00FFFFFF; | |
| } | |
| /* Store short float to FPAC */ | |
| void store_sf (SHORT_FLOAT *fl, t_int64 *fpr) | |
| { | |
| *fpr = 0; | |
| *fpr = ((t_int64)fl->sign << 63) | |
| | ((t_int64)fl->expo << 56) | |
| | ((t_int64)fl->short_fract <<32); | |
| } | |
| /* Get long float from FPAC */ | |
| void get_lf (LONG_FLOAT *fl, t_int64 *fpr) | |
| { | |
| fl->sign = (uint8)(*fpr >> 63) & 1; | |
| fl->expo = (short)(*fpr >> 56) & 0x007F; | |
| fl->long_fract = (t_int64)*fpr & 0x00FFFFFFFFFFFFFF; | |
| } | |
| /* Store long float to FPAC */ | |
| void store_lf (LONG_FLOAT *fl, t_int64 *fpr) | |
| { | |
| *fpr = 0; | |
| *fpr = (t_int64)fl->sign << 63; | |
| *fpr |= ((t_int64)fl->expo << 56) & 0x7f00000000000000; | |
| *fpr |= fl->long_fract; | |
| } | |
| /* Check short for Overflow */ | |
| int overflow_sf (SHORT_FLOAT *fl) | |
| { | |
| if (fl->expo > 127) { | |
| fl->expo &= 0x007F; | |
| return(1); | |
| } | |
| return(0); | |
| } | |
| /* Normalize Short Float */ | |
| int normal_sf(SHORT_FLOAT *fl) | |
| { | |
| if (fl->short_fract) { | |
| if ((fl->short_fract & 0x00FFFF00) == 0) { | |
| fl->short_fract <<= 16; | |
| fl->expo -= 4; | |
| } | |
| if ((fl->short_fract & 0x00FF0000) == 0) { | |
| fl->short_fract <<= 8; | |
| fl->expo -= 2; | |
| } | |
| if ((fl->short_fract & 0x00F00000) == 0) { | |
| fl->short_fract <<= 4; | |
| (fl->expo)--; | |
| } | |
| } else { | |
| fl->sign = 0; | |
| fl->expo = 0; | |
| } | |
| if (fl->expo < 0) | |
| return (2); | |
| return(0); | |
| } | |
| /* Normalize long float */ | |
| int normal_lf (LONG_FLOAT *fl) | |
| { | |
| if (fl->long_fract) { | |
| if ((fl->long_fract & 0x00FFFFFFFF000000) == 0) { | |
| fl->long_fract <<= 32; | |
| fl->expo -= 8; | |
| } | |
| if ((fl->long_fract & 0x00FFFF0000000000) == 0) { | |
| fl->long_fract <<= 16; | |
| fl->expo -= 4; | |
| } | |
| if ((fl->long_fract & 0x00FF000000000000) == 0) { | |
| fl->long_fract <<= 8; | |
| fl->expo -= 2; | |
| } | |
| if ((fl->long_fract & 0x00F0000000000000) == 0) { | |
| fl->long_fract <<= 4; | |
| (fl->expo)--; | |
| } | |
| } else { | |
| fl->sign = 0; | |
| fl->expo = 0; | |
| } | |
| if (fl->expo < 0) | |
| return (2); | |
| return(0); | |
| } | |
| /* Check Long for Overflow */ | |
| int overflow_lf(LONG_FLOAT *fl) | |
| { | |
| if (fl->expo > 127) { | |
| fl->expo &= 0x007F; | |
| return(1); | |
| } | |
| return(0); | |
| } | |
| int underflow_sf(SHORT_FLOAT *fl) | |
| { | |
| if (fl->expo < 0) { | |
| fl->short_fract = 0; | |
| fl->expo = 0; | |
| fl->sign = 0; | |
| } | |
| return(0); | |
| } | |
| int underflow_lf(LONG_FLOAT *fl) | |
| { | |
| if (fl->expo < 0) { | |
| fl->long_fract = 0; | |
| fl->expo = 0; | |
| fl->sign = 0; | |
| } | |
| return(0); | |
| } | |
| /* Check Short for Over/Under flow */ | |
| int over_under_flow_sf(SHORT_FLOAT *fl) | |
| { | |
| if (fl->expo > 127) { | |
| fl->expo &= 0x007F; | |
| return(1); | |
| } else { | |
| if (fl->expo < 0) { | |
| /* set true 0 */ | |
| fl->short_fract = 0; | |
| fl->expo = 0; | |
| fl->sign = 0; | |
| } | |
| } | |
| return(0); | |
| } | |
| /* Check Long for Over/Under flow */ | |
| int over_under_flow_lf(LONG_FLOAT *fl) | |
| { | |
| if (fl->expo > 127) { | |
| fl->expo &= 0x007F; | |
| return(1); | |
| } else { | |
| if (fl->expo < 0) { | |
| /* set true 0 */ | |
| fl->long_fract = 0; | |
| fl->expo = 0; | |
| fl->sign = 0; | |
| } | |
| } | |
| return(0); | |
| } | |
| int significance_sf (SHORT_FLOAT *fl) | |
| { | |
| fl->sign = 0; | |
| fl->expo = 0; | |
| return(0); | |
| } | |
| int significance_lf (LONG_FLOAT *fl) | |
| { | |
| fl->sign = 0; | |
| fl->expo = 0; | |
| return(0); | |
| } | |
| /*-------------------------------------------------------------------*/ | |
| /* Add short float */ | |
| /* */ | |
| /* Input: */ | |
| /* fl Float */ | |
| /* add_fl Float to be added */ | |
| /* normal Normalize if true */ | |
| /* Value: */ | |
| /* exeption */ | |
| /*-------------------------------------------------------------------*/ | |
| int add_sf (SHORT_FLOAT *fl, SHORT_FLOAT *add_fl, int normal) | |
| { | |
| int pgm_check; | |
| int shift; | |
| pgm_check = 0; | |
| if (add_fl->short_fract | |
| || add_fl->expo) { /* add_fl not 0 */ | |
| if (fl->short_fract | |
| || fl->expo) { /* fl not 0 */ | |
| /* both not 0 */ | |
| if (fl->expo == add_fl->expo) { | |
| /* expo equal */ | |
| /* both guard digits */ | |
| fl->short_fract <<= 4; | |
| add_fl->short_fract <<= 4; | |
| } else { | |
| /* expo not equal, denormalize */ | |
| if (fl->expo < add_fl->expo) { | |
| /* shift minus guard digit */ | |
| shift = add_fl->expo - fl->expo - 1; | |
| fl->expo = add_fl->expo; | |
| if (shift) { | |
| if (shift >= 6 | |
| || ((fl->short_fract >>= (shift * 4)) == 0)) { | |
| /* 0, copy summand */ | |
| fl->sign = add_fl->sign; | |
| fl->short_fract = add_fl->short_fract; | |
| if (fl->short_fract == 0) { | |
| pgm_check = significance_sf(fl); | |
| } else { | |
| if (normal) { | |
| normal_sf(fl); | |
| pgm_check = underflow_sf(fl); | |
| } | |
| } | |
| return(pgm_check); | |
| } | |
| } | |
| /* guard digit */ | |
| add_fl->short_fract <<= 4; | |
| } else { | |
| /* shift minus guard digit */ | |
| shift = fl->expo - add_fl->expo - 1; | |
| if (shift) { | |
| if (shift >= 6 | |
| || ((add_fl->short_fract >>= (shift * 4)) == 0)) { | |
| /* 0, nothing to add */ | |
| if (fl->short_fract == 0) { | |
| pgm_check = significance_sf(fl); | |
| } else { | |
| if (normal) { | |
| normal_sf(fl); | |
| pgm_check = underflow_sf(fl); | |
| } | |
| } | |
| return(pgm_check); | |
| } | |
| } | |
| /* guard digit */ | |
| fl->short_fract <<= 4; | |
| } | |
| } | |
| /* compute with guard digit */ | |
| if (fl->sign == add_fl->sign) { | |
| fl->short_fract += add_fl->short_fract; | |
| } else { | |
| if (fl->short_fract == add_fl->short_fract) { | |
| /* true 0 */ | |
| fl->short_fract = 0; | |
| return( significance_sf(fl) ); | |
| } else if (fl->short_fract > add_fl->short_fract) { | |
| fl->short_fract -= add_fl->short_fract; | |
| } else { | |
| fl->short_fract = add_fl->short_fract - fl->short_fract; | |
| fl->sign = add_fl->sign; | |
| } | |
| } | |
| /* handle overflow with guard digit */ | |
| if (fl->short_fract & 0xF0000000) { | |
| fl->short_fract >>= 8; | |
| (fl->expo)++; | |
| pgm_check = overflow_sf(fl); | |
| } else { | |
| if (normal) { | |
| /* normalize with guard digit */ | |
| if (fl->short_fract) { | |
| /* not 0 */ | |
| if (fl->short_fract & 0x0F000000) { | |
| /* not normalize, just guard digit */ | |
| fl->short_fract >>= 4; | |
| } else { | |
| (fl->expo)--; | |
| normal_sf(fl); | |
| pgm_check = underflow_sf(fl); | |
| } | |
| } else { | |
| /* true 0 */ | |
| pgm_check = significance_sf(fl); | |
| } | |
| } else { | |
| /* not normalize, just guard digit */ | |
| fl->short_fract >>= 4; | |
| if (fl->short_fract == 0) { | |
| pgm_check = significance_sf(fl); | |
| } | |
| } | |
| } | |
| return(pgm_check); | |
| } else { /* fl 0, add_fl not 0 */ | |
| /* copy summand */ | |
| fl->expo = add_fl->expo; | |
| fl->sign = add_fl->sign; | |
| fl->short_fract = add_fl->short_fract; | |
| if (fl->short_fract == 0) { | |
| return( significance_sf(fl) ); | |
| } | |
| } | |
| } else { /* add_fl 0 */ | |
| if (fl->short_fract == 0) { /* fl 0 */ | |
| /* both 0 */ | |
| return( significance_sf(fl) ); | |
| } | |
| } | |
| if (normal) { | |
| normal_sf(fl); | |
| pgm_check = underflow_sf(fl); | |
| } | |
| return(pgm_check); | |
| } | |
| /*-------------------------------------------------------------------*/ | |
| /* Add long float */ | |
| /* */ | |
| /* Input: */ | |
| /* fl Float */ | |
| /* add_fl Float to be added */ | |
| /* normal Normalize if true */ | |
| /* Value: */ | |
| /* exeption */ | |
| /*-------------------------------------------------------------------*/ | |
| int add_lf (LONG_FLOAT *fl, LONG_FLOAT *add_fl, int normal) | |
| { | |
| int pgm_check; | |
| int shift; | |
| pgm_check = 0; | |
| if (add_fl->long_fract | |
| || add_fl->expo) { /* add_fl not 0 */ | |
| if (fl->long_fract | |
| || fl->expo) { /* fl not 0 */ | |
| /* both not 0 */ | |
| if (fl->expo == add_fl->expo) { | |
| /* expo equal */ | |
| /* both guard digits */ | |
| fl->long_fract <<= 4; | |
| add_fl->long_fract <<= 4; | |
| } else { | |
| /* expo not equal, denormalize */ | |
| if (fl->expo < add_fl->expo) { | |
| /* shift minus guard digit */ | |
| shift = add_fl->expo - fl->expo - 1; | |
| fl->expo = add_fl->expo; | |
| if (shift) { | |
| if (shift >= 14 | |
| || ((fl->long_fract >>= (shift * 4)) == 0)) { | |
| /* 0, copy summand */ | |
| fl->sign = add_fl->sign; | |
| fl->long_fract = add_fl->long_fract; | |
| if (fl->long_fract == 0) { | |
| pgm_check = significance_lf(fl); | |
| } else { | |
| if (normal) { | |
| normal_lf(fl); | |
| pgm_check = underflow_lf(fl); | |
| } | |
| } | |
| return(pgm_check); | |
| } | |
| } | |
| /* guard digit */ | |
| add_fl->long_fract <<= 4; | |
| } else { | |
| /* shift minus guard digit */ | |
| shift = fl->expo - add_fl->expo - 1; | |
| if (shift) { | |
| if (shift >= 14 | |
| || ((add_fl->long_fract >>= (shift * 4)) == 0)) { | |
| /* 0, nothing to add */ | |
| if (fl->long_fract == 0) { | |
| pgm_check = significance_lf(fl); | |
| } else { | |
| if (normal) { | |
| normal_lf(fl); | |
| pgm_check = underflow_lf(fl); | |
| } | |
| } | |
| return(pgm_check); | |
| } | |
| } | |
| /* guard digit */ | |
| fl->long_fract <<= 4; | |
| } | |
| } | |
| /* compute with guard digit */ | |
| if (fl->sign == add_fl->sign) { | |
| fl->long_fract += add_fl->long_fract; | |
| } else { | |
| if (fl->long_fract == add_fl->long_fract) { | |
| /* true 0 */ | |
| fl->long_fract = 0; | |
| return( significance_lf(fl) ); | |
| } else if (fl->long_fract > add_fl->long_fract) { | |
| fl->long_fract -= add_fl->long_fract; | |
| } else { | |
| fl->long_fract = add_fl->long_fract - fl->long_fract; | |
| fl->sign = add_fl->sign; | |
| } | |
| } | |
| /* handle overflow with guard digit */ | |
| if (fl->long_fract & 0xF000000000000000) { | |
| fl->long_fract >>= 8; | |
| (fl->expo)++; | |
| pgm_check = overflow_lf(fl); | |
| } else { | |
| if (normal) { | |
| /* normalize with guard digit */ | |
| if (fl->long_fract) { | |
| /* not 0 */ | |
| if (fl->long_fract & 0x0F00000000000000) { | |
| /* not normalize, just guard digit */ | |
| fl->long_fract >>= 4; | |
| } else { | |
| (fl->expo)--; | |
| normal_lf(fl); | |
| pgm_check = underflow_lf(fl); | |
| } | |
| } else { | |
| /* true 0 */ | |
| pgm_check = significance_lf(fl); | |
| } | |
| } else { | |
| /* not normalize, just guard digit */ | |
| fl->long_fract >>= 4; | |
| if (fl->long_fract == 0) { | |
| pgm_check = significance_lf(fl); | |
| } | |
| } | |
| } | |
| return(pgm_check); | |
| } else { /* fl 0, add_fl not 0 */ | |
| /* copy summand */ | |
| fl->expo = add_fl->expo; | |
| fl->sign = add_fl->sign; | |
| fl->long_fract = add_fl->long_fract; | |
| if (fl->long_fract == 0) { | |
| return( significance_lf(fl) ); | |
| } | |
| } | |
| } else { /* add_fl 0 */ | |
| if (fl->long_fract == 0) { /* fl 0 */ | |
| /* both 0 */ | |
| return( significance_lf(fl) ); | |
| } | |
| } | |
| if (normal) { | |
| normal_lf(fl); | |
| pgm_check = underflow_lf(fl); | |
| } | |
| return(pgm_check); | |
| } | |
| /*-------------------------------------------------------------------*/ | |
| /* Multiply short float */ | |
| /* */ | |
| /* Input: */ | |
| /* fl Multiplicand short float */ | |
| /* mul_fl Multiplicator short float */ | |
| /* Value: */ | |
| /* exeption */ | |
| /*-------------------------------------------------------------------*/ | |
| int mul_sf(SHORT_FLOAT *fl, SHORT_FLOAT *mul_fl) | |
| { | |
| t_int64 wk; | |
| if (fl->short_fract | |
| && mul_fl->short_fract) { | |
| /* normalize operands */ | |
| normal_sf( fl ); | |
| normal_sf( mul_fl ); | |
| /* multiply fracts */ | |
| wk = (t_int64) fl->short_fract * mul_fl->short_fract; | |
| /* normalize result and compute expo */ | |
| if (wk & 0x0000F00000000000) { | |
| fl->short_fract = (int32)wk >> 24; | |
| fl->expo = (short)fl->expo + mul_fl->expo - 64; | |
| } else { | |
| fl->short_fract = (int32)wk >> 20; | |
| fl->expo = (short)fl->expo + mul_fl->expo - 65; | |
| } | |
| /* determine sign */ | |
| fl->sign = (fl->sign == mul_fl->sign) ? 0 : 1; | |
| /* handle overflow and underflow */ | |
| return( over_under_flow_sf(fl) ); | |
| } else { | |
| /* set true 0 */ | |
| fl->short_fract = 0; | |
| fl->expo = 0; | |
| fl->sign = 0; | |
| return(0); | |
| } | |
| } | |
| /*-------------------------------------------------------------------*/ | |
| /* Multiply long float */ | |
| /* */ | |
| /* Input: */ | |
| /* fl Multiplicand long float */ | |
| /* mul_fl Multiplicator long float */ | |
| /* Value: */ | |
| /* exeption */ | |
| /*-------------------------------------------------------------------*/ | |
| int mul_lf(LONG_FLOAT *fl, LONG_FLOAT *mul_fl) | |
| { | |
| t_int64 wk; | |
| int32 v; | |
| if (fl->long_fract | |
| && mul_fl->long_fract) { | |
| /* normalize operands */ | |
| normal_lf( fl ); | |
| normal_lf( mul_fl ); | |
| /* multiply fracts by sum of partial multiplications */ | |
| wk = ((fl->long_fract & 0x00000000FFFFFFFF) * (mul_fl->long_fract & 0x00000000FFFFFFFF)) >> 32; | |
| wk += ((fl->long_fract & 0x00000000FFFFFFFF) * (mul_fl->long_fract >> 32)); | |
| wk += ((fl->long_fract >> 32) * (mul_fl->long_fract & 0x00000000FFFFFFFF)); | |
| v = (int32)wk; | |
| fl->long_fract = (wk >> 32) + ((fl->long_fract >> 32) * (mul_fl->long_fract >> 32)); | |
| /* normalize result and compute expo */ | |
| if (fl->long_fract & 0x0000F00000000000) { | |
| fl->long_fract = (fl->long_fract << 8) | |
| | (v >> 24); | |
| fl->expo = fl->expo + mul_fl->expo - 64; | |
| } else { | |
| fl->long_fract = (fl->long_fract << 12) | |
| | (v >> 20); | |
| fl->expo = fl->expo + mul_fl->expo - 65; | |
| } | |
| /* determine sign */ | |
| fl->sign = (fl->sign == mul_fl->sign) ? 0 : 1; | |
| /* handle overflow and underflow */ | |
| return( over_under_flow_lf(fl) ); | |
| } else { | |
| /* set true 0 */ | |
| fl->long_fract = 0; | |
| fl->expo = 0; | |
| fl->sign = 0; | |
| return(0); | |
| } | |
| } | |
| /*-------------------------------------------------------------------*/ | |
| /* Divide short float */ | |
| /* */ | |
| /* Input: */ | |
| /* fl Dividend short float */ | |
| /* div_fl Divisor short float */ | |
| /* Value: */ | |
| /* exeption */ | |
| /*-------------------------------------------------------------------*/ | |
| int div_sf(SHORT_FLOAT *fl, SHORT_FLOAT *div_fl) | |
| { | |
| t_int64 wk; | |
| if (div_fl->short_fract) { | |
| if (fl->short_fract) { | |
| /* normalize operands */ | |
| normal_sf( fl ); | |
| normal_sf( div_fl ); | |
| /* position fracts and compute expo */ | |
| if (fl->short_fract < div_fl->short_fract) { | |
| wk = (t_int64) fl->short_fract << 24; | |
| fl->expo = fl->expo - div_fl->expo + 64; | |
| } else { | |
| wk = (t_int64) fl->short_fract << 20; | |
| fl->expo = fl->expo - div_fl->expo + 65; | |
| } | |
| /* divide fractions */ | |
| fl->short_fract = (int32)wk / div_fl->short_fract; | |
| /* determine sign */ | |
| fl->sign = (fl->sign == div_fl->sign) ? 0 : 1; | |
| /* handle overflow and underflow */ | |
| return( over_under_flow_sf(fl) ); | |
| } else { | |
| /* fraction of dividend 0, set true 0 */ | |
| fl->short_fract = 0; | |
| fl->expo = 0; | |
| fl->sign = 0; | |
| } | |
| } else { | |
| /* divisor 0 */ | |
| return(3); | |
| } | |
| return(0); | |
| } | |
| /*-------------------------------------------------------------------*/ | |
| /* Divide long float */ | |
| /* */ | |
| /* Input: */ | |
| /* fl Dividend long float */ | |
| /* div_fl Divisor long float */ | |
| /* Value: */ | |
| /* exeption */ | |
| /*-------------------------------------------------------------------*/ | |
| int div_lf(LONG_FLOAT *fl, LONG_FLOAT *div_fl) | |
| { | |
| t_int64 wk; | |
| t_int64 wk2; | |
| int i; | |
| if (div_fl->long_fract) { | |
| if (fl->long_fract) { | |
| /* normalize operands */ | |
| normal_lf( fl ); | |
| normal_lf( div_fl ); | |
| /* position fracts and compute expo */ | |
| if (fl->long_fract < div_fl->long_fract) { | |
| fl->expo = fl->expo - div_fl->expo + 64; | |
| } else { | |
| fl->expo = fl->expo - div_fl->expo + 65; | |
| div_fl->long_fract <<= 4; | |
| } | |
| /* partial divide first hex digit */ | |
| wk2 = fl->long_fract / div_fl->long_fract; | |
| wk = (fl->long_fract % div_fl->long_fract) << 4; | |
| /* partial divide middle hex digits */ | |
| i = 13; | |
| while (i--) { | |
| wk2 = (wk2 << 4) | |
| | (wk / div_fl->long_fract); | |
| wk = (wk % div_fl->long_fract) << 4; | |
| } | |
| /* partial divide last hex digit */ | |
| fl->long_fract = (wk2 << 4) | |
| | (wk / div_fl->long_fract); | |
| /* determine sign */ | |
| fl->sign = (fl->sign == div_fl->sign) ? 0 : 1; | |
| /* handle overflow and underflow */ | |
| return( over_under_flow_lf(fl) ); | |
| } else { | |
| /* fraction of dividend 0, set true 0 */ | |
| fl->long_fract = 0; | |
| fl->expo = 0; | |
| fl->sign = 0; | |
| } | |
| } else { | |
| /* divisor 0 */ | |
| return(3); | |
| } | |
| return(0); | |
| } | |