/***************************************************************************** * Change Log * Date | Change *-----------+----------------------------------------------------------------- * 15-Dec-85 | [1.201] Created * 25-Jan-86 | [1.327] Check for illegal length * 27-Jan-86 | [1.350] declare single_cycle_decode * 25-Feb-86 | [1.379] include <> => include "" * 29-Jul-86 | [1.385] Moved len check outside case * 31-Jul-86 | [1.405] Made char args unsigned * 10-Nov-91 | [1.428] converted to Microsoft C 6.0 * 18-Nov-91 | [1.428] memory.h => mem1401.h, avoid ANSI name * 23-Dec-91 | [1.524] compare: use register vars for speed * 23-Dec-91 | [1.524] more optimizations, pragmas *****************************************************************************/ #include "stdio.h" #include "boolean.h" #include "btypes.h" #include "mem1401.h" #include "mach.h" #include "diag.h" #include "instr.h" #include "alerts.h" #include "logic.h" #include "ifetch.h" #define C_A_complete single_cycle(i_C,A_complete) #define C_B_complete single_cycle(i_C,B_complete) /* Last compare state used for chaining */ int last_compare_state = logic_BEQA; extern char * single_cycle_decode(); /***************************************************************************** 1401 Simulator Compare Instruction Compare ------- Instruction format Mnemonic Op Code A-address B-address -------- ------- --------- --------- C C AAA BBB Function: The characters in the B-field are compared to an equal number of characters in the A-field. The comparison turns on an indicator that can be tested by a subsequent Branch If Indicator On instruction. The indicator is reset by either the next Compare instruction or the next disk-storage operation. The same indicators set by the compare instruction are also affected by a disk operation (seek, read, write and write-check). The disk-storeage drive performs an address-compare operation automatically on the address in core storage, with the address on the disk record, but using the compare circuits and by setting the appropriate indicator (equal, high or low). Therefore, careful consideration must be made in the use of a compare instruction and subsequent Branch If Indicator On instruction for testing the results of the compare instruction when disk operations are to be performed. Word Marks: The first word mark encoutnered stops the operation. If the A-field is longer than the B-field, extra A-field positions at the left of the B-field word mark are not compared. If the B-field is longer than the A-field, an unequal-compare results. In this case, the high-compare indicator is set ON. Address Registers After Operation: I-Add A-Add B-Add NSI A-Lw B-Lw Chaining: The instruction can be chained to the preceding operation by supplying only the operation code. When compare operations are chained, the compare-result indicators are set by the first unequal condition encountered in the composite field. *****************************************************************************/ /* Collating sequence is *NOT* bit value sequence; here, arranged by bcd value, is a table of integers showing the actual sorting value This information is from the System Operation Reference Manual IBM 1440 Data Processing System, File number 1440-01, Form A24-3116-2, Major revision of March 1965, page I-1. This table is an expansion of, but consistent with, the note found on page B-10 of the System Operation Reference Manual, IBM 1401 Data Processing System/IBM 1460 Data Processing System, File number 1401/1460-01, Form A24-3067-1, Revision of November, 1964; the 1401 description includes only the characters found on the A-character set printer chains and not those found on the 64-character chain, so many characters were omitted. */ unsigned char collation[64] = { 0, /* 0 - space */ 55, /* 1 1 - 1 */ 56, /* 2 2 - 2 */ 57, /* 3 21 - 3 */ 58, /* 4 4 - 4 */ 59, /* 5 4 1 - 5 */ 60, /* 6 42 - 6 */ 61, /* 7 421 - 7 */ 62, /* 8 8 - 8 */ 63, /* 9 8 1 - 9 */ 54, /* 10 8 2 - 0 */ 20, /* 11 8 21 - number sign (#) or equal*/ 21, /* 12 84 - at sign @ or quote */ 22, /* 13 84 1 - colon */ 23, /* 14 842 - greater than */ 24, /* 15 8421 - radical */ 19, /* 16 A - substitute blank */ 13, /* 17 A 1 - slash */ 46, /* 18 A 2 - S */ 47, /* 19 A 21 - T */ 48, /* 20 A 4 - U */ 49, /* 21 A 4 1 - V */ 50, /* 22 A 42 - W */ 51, /* 23 A 421 - X */ 52, /* 24 A8 - Y */ 53, /* 25 A8 1 - Z */ 45, /* 26 A8 2 - record mark */ 14, /* 27 A8 21 - comma */ 15, /* 28 A84 - percent % or paren */ 16, /* 29 A84 1 - word separator */ 17, /* 30 A842 - left oblique */ 18, /* 31 A8421 - segment mark */ 12, /* 32 B - hyphen */ 36, /* 33 B 1 - J */ 37, /* 34 B 2 - K */ 38, /* 35 B 21 - L */ 39, /* 36 B 4 - M */ 40, /* 37 B 4 1 - N */ 41, /* 38 B 42 - O */ 42, /* 39 B 421 - P */ 43, /* 40 B 8 - Q */ 44, /* 41 B 8 1 - R */ 35, /* 42 B 8 2 - exclamation (-0) */ 7, /* 43 B 8 21 - dollar sign */ 8, /* 44 B 84 - asterisk */ 9, /* 45 B 84 1 - right bracket */ 10, /* 46 B 842 - semicolon */ 11, /* 47 B 8421 - delta */ 6, /* 48 BA - ampersand or plus */ 26, /* 49 BA 1 - A */ 27, /* 50 BA 2 - B */ 28, /* 51 BA 21 - C */ 29, /* 52 BA 4 - D */ 30, /* 53 BA 4 1 - E */ 31, /* 54 BA 42 - F */ 32, /* 55 BA 421 - G */ 33, /* 56 BA8 - H */ 34, /* 57 BA8 1 - I */ 25, /* 58 BA8 2 - question mark */ 1, /* 59 BA8 21 - period */ 2, /* 60 BA84 - lozenge or paren */ 3, /* 61 BA84 1 - left bracket */ 4, /* 62 BA842 - less than */ 5 /* 63 BA8421 - group mark */ }; /**************************************************************************** * compare * Inputs: * unsigned char A_data: A-field character to compare * unsigned char B_data: B-field character to compare * Effect: * Sets the last_compare_state indicator ****************************************************************************/ #pragma check_stack(off) void compare(unsigned char A_data, unsigned char B_data) { register unsigned char a = BA8421(A_data); register unsigned char b = BA8421(B_data); if(a == b) return; /* don't change */ /* Not the same, set indicator */ if(collation[b] > collation[a]) last_compare_state = logic_BGTA; else last_compare_state = logic_BLTA; } #pragma check_stack(on) /**************************************************************************** * inst_C * Result: boolean * true if processing should continue * false if processing should halt * Effect: * Executes the Compare instruction and sets the logic indicators ****************************************************************************/ #pragma optimize("te",on) boolean inst_C() { boolean cycling; boolean quit; boolean result; cycling = true; quit = false; result = true; switch(I_cycle) { case 1: /* chained */ case 4: /* one-address */ case 7: /* two-address */ break; default: /* Illegal length */ illegal_length(); return false; } tell_op(op_A|op_B); /* Initialize the last-compare state unless we are chained */ switch(single_cycle_state) { /* init */ case single_cycle_run: case single_cycle_start: switch(I_cycle) { case 1: /* chained */ break; case 7: /* full */ last_compare_state = logic_BEQA; break; default: /* Illegal */ illegal_length(); return false; } } /* init */ while(cycling) { /* compare characters */ if(bad_address(A_addr)) { /* bogus */ cycle = cycle_A; break; } /* bogus */ if(bad_address(B_addr)) { /* bogus */ cycle = cycle_B; result = false; break; } /* bogus */ switch(single_cycle_state) { /* state decode */ case single_cycle_run: B = memory[B_addr]; A = memory[A_addr]; B_addr--; A_addr--; quit = WM(A) || WM(B); if(WM(A) && !WM(B)) { /* A-short */ /* Set unequal, high state */ last_compare_state = logic_BGTA; break; } /* A-short */ /* Now compare the two bytes */ compare(A,B); break; case C_B_complete: case single_cycle_start: B = memory[A_addr]; if(WM(B)) single_cycle_state = C_A_complete; A_addr--; cycle = cycle_A; cycling = false; break; case C_A_complete: A = B; B = memory[B_addr]; if(WM(A) && !WM(B)) { /* A-short */ quit = true; last_compare_state = logic_BGTA; break; } /* A-short */ else { /* continue */ compare(A,B); single_cycle_state = C_B_complete; } /* continue */ B_addr--; cycle = cycle_B; cycling = false; break; default: sprintf(diag_buffer,"Illegal microstate %s",single_cycle_decode()); tell(diag_buffer); result = false; cycling = false; break; } /* state decode */ if(quit) { single_cycle_state = single_cycle_complete; break; } } /* compare characters */ set_compare(last_compare_state); return result; }