/*****************************************************************************
*           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] <jmn> converted to Microsoft C 6.0
* 18-Nov-91 | [1.428] <jmn> memory.h => mem1401.h, avoid ANSI name
* 23-Dec-91 | [1.524] <jmn> compare: use register vars for speed
* 23-Dec-91 | [1.524] <jmn> 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;

    }
