/***************************************************************************** * Change Log * Date | Change *-----------+----------------------------------------------------------------- * 16-Nov-85 | [1.80] Created * 23-Nov-85 | [1.91] Check instructions dispatch vector immediately...flag * | illegal operation * 24-Nov-85 | [1.106] CS operation does not require word mark following * 12-Dec-85 | [1.179] Handle case 8 properly; turn on instruction length light * | for long instructions * 13-Dec-85 | [1.183] Move previous A-addr to B-addr during A-cycle of * | SAR instruction * 14-Dec-85 | [1.193] Keep hyp. d_char for length 2 and 5 instructions; if * | instruction terminates on next fetch cycle, store in d_char * 24-Dec-85 | [1.236] Turn off 'op fetch' message; no longer needed and * | interferes with selective trace facility * 27-Dec-85 | [1.255] store d_char properly for length 2 instructions * 30-Dec-85 | [1.276] Detect illegal instructions by also checking for * | inst_illegal in the dispatch table, not just NULL * 30-Dec-85 | [1.279] Added code to support indexing * 24-Jan-86 | [1.314] check_left_mouse_button => check_mouse_halt * 25-Feb-86 | [1.379] include<> => include "" * 31-Jul-86 | [1.405] Made char variables unsigned * 6-Aug-86 | [1.410] Added NOTREACHED comment for Pre-C * 6-Aug-86 | [1.410] Added bcd.h dependency * 18-Nov-91 | [1.428] memory.h => mem1401.h, avoid ANSI name * 22-Dec-94 | [1.600J] JRJ extend array binary to 16 bytes to avoid bad index * 22-Dec-94 | [1.600J] JRJ add code to set up I/O instructions. * 20-Jan-95 | [1.600J] JRJ add code to handle CU I/O instruction units. *****************************************************************************/ /***************************************************************************** 1401 Simulator Instruction Fetch Logic *****************************************************************************/ #include "stdio.h" #include "boolean.h" #include "mem1401.h" #include "btypes.h" #include "instr.h" #include "state.h" #include "mach.h" #include "alerts.h" #include "modes.h" #include "dispatch.h" #include "diag.h" #include "icycle.h" #include "bcd.h" #include "kb.h" #include "scan.h" #include "alert.h" #include "mach.h" #include "length.h" #include "data.h" #include "io.h" static char binary[] = " \1\2\3\4\5\6\7\10\11\0\1\2\3\4\5"; static unsigned char t_char; /* temporary d-modifier */ static int index; static int index_addr; /**************************************************************************** * cvindex * Inputs: * short zones: Zone bits of index field * Result: int * Address of index register units position ****************************************************************************/ short cvindex(short zones) { switch(zones) { /* decode */ case A_bits: return 89; case B_bits: return 94; case BA_bits: return 99; } /* decode */ return 0; } /**************************************************************************** * ifetch * Result: boolean * true if the instruction can be executed * false if there was some error * Effect: * Fetches an instruction. Decodes its operands, if present ****************************************************************************/ boolean ifetch() { /*---------------------------------------------------------------- All information about the actions of the machine are taken from "Systems Operation Reference Manual: IBM 1401 Data Processing System/ IBM 1460 Data Processing System", IBM File Number 1401/1460-01, Form A24-3067-1, Copyright IBM, November 1964. ----------------------------------------------------------------*/ int temp; cycle = cycle_I; while(true) { /* instruction fetch */ if(check_mouse_halt()) return false; if(reset_mandatory) return false; /* We had an error */ switch(I_cycle) { /* fetch */ /* ? */ case Iop: /* opcode fetch */ /* O OF OAAA OIIIF OAAABBB OAAABBBF ^ you are here */ /*-------------------------------------------------------- The operation code enters the B-register and the OP-register. Because this is the first I-cycle, the A-register is left undisturbed --------------------------------------------------------*/ B = memory[I_addr]; OP = B; #if 1 if(diagnostics_on) { /* trace */ sprintf(diag_buffer,"%d: Op fetch %c%d ('%c')", I_addr, (WM(OP) ? '^' : ' '), BA8421(OP), bcd_to_ascii(BA8421(OP))); tell(diag_buffer); } /* trace */ #endif if((B & word_mark) == 0) { /* missing word mark! */ alert(alert_process); light_O(true); I_addr++; break; } /* missing word mark! */ if(instructions[BA8421(OP)] == NULL || instructions[BA8421(OP)] == inst_illegal) { /* no dispatch address */ inst_illegal(); light_O(true); alert(alert_process); return false; } /* no dispatch address */ I_cycle = I1; I_addr++; /* NSI position */ break; /* O? */ case I1: /* First address cycle */ /* O OF OAAA OIIIF OAAABBB OAAABBBF ^ you are here */ /*-------------------------------------------------------- The A-Address register is set to blanks during the first part of this cycle for all instructions. The B-address is reset to blanks during the first part of the cycle for all operations except Move, Load, Store A- and B- Registers operations. During the I-1 cycle, the second instruction character (first character of the A-address) enters the hundreds position of the A- and B- address registers and the A-register by way of the B-register. --------------------------------------------------------*/ B = memory[I_addr]; index = 0; /* Assume no indexing */ if((B & word_mark) != 0) { /* new instruction found */ /* Our operation is of the 'O' variety */ return true; } /* new instruction found */ A = B; /* The A_addr and B_addr are both loaded; It is presumed the first character is the hundreds position, and the BA bits determine the thousands. Remember that 0 is 8-2. */ /* Reset flag that inhibits indexing for I/O instructions. Actual test for "%" deferred into op specific stuff for efficiency. JRJ */ io_index_inhibit = false; temp = ZONEBITS_DOWN(B)*1000 + binary[NUMBITS(B)] * 100; switch(BA8421(OP)) { /* inhibit B-store */ case i_SAR: B_addr = A_addr; /* Save Ap in B */ A_addr = temp; break; case i_SBR: case i_MLCWA: case i_MLC: case i_CU: /* If 1st character of A addr is %, set I/O flag to inhibit indexing. Set address to 0 (A kludge, because this simulator does not keep a real character A address reg). JRJ */ if(io_index_inhibit = (BA8421(B) == ascii_to_bcd('%'))) { temp = 0; } A_addr = temp; break; default: A_addr = B_addr = temp; } /* inhibit B-store */ t_char = B; /* in case we terminate in next cycle */ I_cycle = I2; I_addr++; /* NSI position */ break; /* Ox? */ case I2: /* Case 2: second address cycle */ /* O OF OAAA OIIIF OAAABBB OAAABBBF ^ you are here */ /*-------------------------------------------------------- --------------------------------------------------------*/ B = memory[I_addr]; if((B & word_mark) != 0) { /* new instruction found */ /* Our operation is of the 'OF' variety */ d_char = t_char; return true; } /* new instruction found */ A = B; /* The A and B registers are both loaded. This is the tens position. If it has zone bits, they represent indexing. (Unless, of course, this is an I/O instruction. However, the zone bits get cleared in the A address register anyway. Really! JRJ). */ index = ZONEBITS(B); A_addr += binary[NUMBITS(B)]*10; switch(BA8421(OP)) { /* inhibit B-store */ case i_MLCWA: case i_MLC: case i_CU: if(io_index_inhibit) { index = 0; /* inhibits cycles */ io_device = B; } break; case i_SAR: case i_SBR: break; default: B_addr = A_addr; } /* inhibit B-store */ I_cycle = I3; I_addr++; /* NSI position */ break; /* Oxx? */ case I3: /* Units fetch */ /* O OF OAAA OIIIF OAAABBB OAAABBBF ^ you are here */ /*-------------------------------------------------------- --------------------------------------------------------*/ B = memory[I_addr]; if((B & word_mark) != 0) { /* new instruction found */ /* There is no legal instruction format of this length */ alert(alert_process); break; } /* new instruction found */ A = B; /* We have the units position */ A_addr += ZONEBITS_DOWN(B)*4000 + binary[NUMBITS(B)]; d_char = B; switch(BA8421(OP)) { /* inhibit B-store */ case i_MLCWA: case i_MLC: case i_CU: if(io_index_inhibit) { io_unit = B; } case i_SAR: case i_SBR: break; default: B_addr = A_addr; } /* inhibit B-store */ if(index==0) { /* no indexing */ I_cycle = I4; I_addr++; /* NSI position */ } /* no indexing */ else I_cycle = I3X1; break; /* Oxxx+Xn */ case I3X1: /* Units index cycle */ index_addr = cvindex(index); B = memory[index_addr]; index_addr--; if(ZONEBITS(B)) { /* big number */ switch(ZONEBITS(B)) { /* zone decode */ case A_bits: A_addr += 4000; break; case B_bits: A_addr += 8000; break; case BA_bits: A_addr += 12000; break; } /* zone decode */ } /* big number */ A_addr += binary[NUMBITS(B)]; I_cycle = I3X10; break; case I3X10: /* Fetch tens position of index */ B = memory[index_addr]; index_addr--; A_addr += 10 * binary[NUMBITS(B)]; I_cycle = I3X100; break; case I3X100: B = memory[index_addr]; index_addr--; A_addr += 100 * binary[NUMBITS(B)]; if(ZONEBITS(B)) { /* complex */ switch(ZONEBITS(B)) { /* thousands decode */ case A_bits: A_addr += 1000; break; case B_bits: A_addr += 2000; break; case BA_bits: A_addr += 3000; break; } /* thousands decode */ } /* complex */ A_addr %= 16000; switch(BA8421(OP)) { /* inhibit B-store */ case i_MLCWA: case i_MLC: case i_SAR: case i_SBR: break; default: B_addr = A_addr; } /* inhibit B-store */ I_cycle = I4; I_addr++; /* NSI position */ break; /* Oxxx? */ case I4: /* Start next field */ /* O OF OAAA OIIIF OAAABBB OAAABBBF ^ you are here */ /*-------------------------------------------------------- The B-address register is reset at the beginning of this cycle. The fifth instruction character (first character of the B-address) enters the hundreds position of the B-address register, and the A-register through the B-register. --------------------------------------------------------*/ index = 0; B = memory[I_addr]; if((B & word_mark) != 0) { /* new instruction found */ /* We have an instruction of the form OAAA */ return true; } /* new instruction found */ A = B; /* The B_addr register is loaded; It is presumed the first character is the hundreds position, and the BA bits determine the thousands. Remember that 0 is 8-2. */ B_addr = ZONEBITS_DOWN(B)*1000 + binary[NUMBITS(B)] * 100; t_char = B; /* in case we terminate in next cycle */ I_cycle = I5; I_addr++; /* NSI position */ break; /* OAAAF? */ case I5: /* Fetch tens of B-field */ /* O OF OAAA OIIIF OAAABBB OAAABBBF ^ you are here */ /*-------------------------------------------------------- --------------------------------------------------------*/ B = memory[I_addr]; if((B & word_mark) != 0) { /* new instruction found */ /* We have an instruction of the 'OIIIF' variety */ d_char = t_char; return true; } /* new instruction found */ A = B; /* The B address register is loaded. This is the tens position. If it has zone bits, they represent indexing */ index = ZONEBITS(B); B_addr += binary[NUMBITS(B)]*10; I_cycle = I6; I_addr++; /* NSI position */ break; /* OAAABB? */ case I6: /* Fetch units position of B-field */ /* O OF OAAA OIIIF OAAABBB OAAABBBF ^ you are here */ /*-------------------------------------------------------- --------------------------------------------------------*/ B = memory[I_addr]; if((B & word_mark) != 0) { /* new instruction found */ /* There is no legal instruction of this length */ alert(alert_process); break; } /* new instruction found */ A = B; B_addr += ZONEBITS_DOWN(B)*4000 + binary[NUMBITS(B)]; B_addr %= 16000; if(index==0) { /* no indexing */ I_cycle = I7; I_addr++; /* NSI position */ } /* no indexing */ else I_cycle = I6X1; break; /* Oxxx+Xn */ case I6X1: /* Units index cycle */ index_addr = cvindex(index); B = memory[index_addr]; index_addr--; if(ZONEBITS(B)) { /* big number */ switch(ZONEBITS(B)) { /* zone decode */ case A_bits: B_addr += 4000; break; case B_bits: B_addr += 8000; break; case BA_bits: B_addr += 12000; break; } /* zone decode */ } /* big number */ B_addr += binary[NUMBITS(B)]; I_cycle = I6X10; break; case I6X10: /* Fetch tens position of index */ B = memory[index_addr]; index_addr--; B_addr += 10 * binary[NUMBITS(B)]; I_cycle = I6X100; break; case I6X100: B = memory[index_addr]; index_addr--; B_addr += 100 * binary[NUMBITS(B)]; if(ZONEBITS(B)) { /* complex */ switch(ZONEBITS(B)) { /* thousands decode */ case A_bits: B_addr += 1000; break; case B_bits: B_addr += 2000; break; case BA_bits: B_addr += 3000; break; } /* thousands decode */ } /* complex */ I_cycle = I7; I_addr++; /* NSI position */ break; /* OAAABBB? */ case I7: /* Fetch modifier */ /* O OF OAAA OIIIF OAAABBB OAAABBBF ^ you are here */ /*-------------------------------------------------------- --------------------------------------------------------*/ B = memory[I_addr]; if((B & word_mark) != 0 || BA8421(OP) == i_SW || BA8421(OP) == i_CS) { /* new instruction found, or operation has all fields filled */ /* We have form 'OAAABBB' */ return true; } /* new instruction found */ I_cycle = I8; I_addr++; /* NSI position */ d_char = B; break; case I8: /* About to fetch opcode of next instruction */ B = memory[I_addr]; if((B & word_mark) != 0) { /* valid */ return true; } /* valid */ set_inst_length(); alert(alert_process); break; default: /* We should handle indefinite-length NOP someday */ tell("Instruction too long during fetch"); alert(alert_process); break; } /* fetch */ if(current_mode == mode_sing_cyc || current_mode == mode_adr_stop) { /* step */ #if 0 if(diagnostics_on) { /* report */ switch(I_cycle) { /* display */ case 1: /* op only */ sprintf(diag_buffer,"Fetch: %c: %s", bcd_to_ascii(BA8421(OP)), opcodes[BA8421(OP)]); break; case 2: /* op + d or op+A100 */ sprintf(diag_buffer,"Fetch: %c%c: %s %dxx | %s %c", bcd_to_ascii(BA8421(OP)), bcd_to_ascii(B), opcodes[BA8421(OP)], A_addr/100, opcodes[BA8421(OP)], bcd_to_ascii(d_char)); break; /* unfinished...*/ } /* display */ tell(diag_buffer); } /* report */ #endif return false; } /* step */ } /* instruction fetch */ /*NOTREACHED */ return false; } /**************************************************************************** * illegal_length * Effect: * Writes a diagnostic message if diagnostics enabled; sets appropriate * alert ****************************************************************************/ void illegal_length() { if(diagnostics_on) { /* report */ sprintf(diag_buffer,"%d: %s has illegal length %d", I_addr - I_cycle, opcodes[BA8421(OP)],I_cycle); tell(diag_buffer); } /* report */ alert(alert_process); }