/*****************************************************************************
*           Change Log
*  Date     | Change
*-----------+-----------------------------------------------------------------
* 15-Dec-85 | [1.212] Created
* 19-Dec-85 | [1.216] Added debug_ALU mode and check mouse button for abort
* 19-Dec-85 | [1.217] If state is unknown, kill instruction
* 19-Dec-85 | [1.218] Compute sign bits
* 20-Dec-85 | [1.224] Print out address regs in tell_add_state
* 20-Dec-85 | [1.230] Do not add overflow into h/o zones if doing complement
*           | add 
* 24-Dec-85 | [1.236] Add ALU pipe printout
* 26-Dec-85 | [1.237] Use magnitudes instead of carry detect for sign
*           | determination; maintain magnitude computation during add
* 28-Dec-85 | [1.267] Changed state names to more meaningful names.  Fixed
*           | bugs in bogus address detect register cycle setting.  Removed
*           | some dead code
* 28-Dec-85 | [1.268] Compare BtoA data after normalization from BCD
* 28-Dec-85 | [1.269] Initialize debug_ALU false, set_ALU procedure plus
*           | new diagnostic button enables it
* 24-Jan-86 | [1.314] check_left_mouse_button => check_mouse_halt
* 27-Jan-86 | [1.350] Fixed too-many-arguments-to-ALU(...)
* 25-Feb-86 | [1.377] Store proper cycle information so single step display
*           | works properly
* 25-Feb-86 | [1.379] include <> => include ""
* 31-Jul-86 | [1.405] Made all chars unsigned
*  6-Aug-86 | [1.410] Removed 'else' in signbits to defeat stupid compiler
*           | type check
*  6-Aug-86 | [1.410] Added NOTREACHED comments
*  6-Aug-86 | [1.410] Args to faddmode, signbits now unsigned char
* 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
*****************************************************************************/

/*****************************************************************************
				 1401 Emulator

			       Arithmetic Module

This module implements the 1401 arithmetic instructions, A, S, ZA, ZS.

Notes: 

1.  Sign control: If a recomplement cycle is taken, the sign of the
    B- (result) field is changed and the result is stored in true form.

2.  Zone bits:  If the fields to be added contain zone bits in other than
    the high-order position of the B-field and the sign positions of
    both fields, only the digits are used in a true-add operation.  B-field
    zone bits are removed except for the units and high-order positions in
    a true-add operation.  If a complement add takes place, zone bits are
    removed from all but the units positions of the B-field.

3.  Overflow indication:  If an overflow occurs during a true-add operation
    the overflow indicator is set ON, and the overflow indications are
    stored over the high-order digit of the B-field.  When the A-field
    exceeds, or is equal to, the B-field length, and the A-field that
    corresponds to the high-order B-field position contains a zone bit,
    this zone bit is added to any zone bits present in the high-order
    B-field position.

    	Condition	Result
	first overflow	A-bit
	second overflow	B-bit
	third overflow	A- and B-bits
	fourth overflow	no A- or B-bits

    For subsequent overflows repeat conditions 1 thru 4.  Overflow 
    indication does not occur for a 1-position field.

Sign indication:

Sign	BCD Zones	Card code
----	---------	---------
Plus	none		no zone
Plus	A-,B-bits	12-zone
Minus	B-bit		11-zone
Plus	A-bit		0-zone


Result sign given input signs, operation, and magnitude relations
ÉÍÍÍÍÍÍÍÍÍÍÑÍÍÍÑÍÍÍÑÍÍÍÑÍÍÍËÍÍÍÑÍÍÍÑÍÍÍÑÍÍÍËÍÍÍÑÍÍÍÑÍÍÍÑÍÍÍËÍÍÍÑÍÍÍÑÍÍÍÑÍÍÍ»
ºA-sign    ³   ³   ³   ³   º A ³ A ³ A ³ A º B ³ B ³ B ³ B º AB³ AB³ AB³ ABº
ºB-sign    ³   ³ A ³ B ³ ABº   ³ A ³ B ³ ABº   ³ A ³ B ³ ABº   ³ A ³ B ³ ABº
ÌÍÍÍÍÍÍÍÍÍÍØÍÍÍØÍÍÍØÍÍÍØÍÍÍÎÍÍÍØÍÍÍØÍÍÍØÍÍÍÎÍÍÍØÍÍÍØÍÍÍØÍÍÍÎÍÍÍØÍÍÍØÍÍÍØÍÍÍ¹
ºA   B<A   ³   ³ A ³ AB³ ABº   ³ A ³ AB³ ABº B ³ B ³ B ³ B º   ³ A ³ AB³ ABº
ºD         ÃÄÄÄÅÄÄÄÅÄÄÄÅÄÄÄ×ÄÄÄÅÄÄÄÅÄÄÄÅÄÄÄ×ÄÄÄÅÄÄÄÅÄÄÄÅÄÄÄ×ÄÄÄÅÄÄÄÅÄÄÄÅÄÄÄ¶
ºD   B>=A  ³   ³ A ³ B ³ ABº   ³ A ³ B ³ ABº AB³ AB³ B ³ ABº   ³ A ³ B ³ ABº
ÌÍÍÍÍÍÍÍÍÍÍØÍÍÍØÍÍÍØÍÍÍØÍÍÍÎÍÍÍØÍÍÍØÍÍÍØÍÍÍÎÍÍÍØÍÍÍØÍÍÍØÍÍÍÎÍÍÍØÍÍÍØÍÍÍØÍÍÍ¹
ºS   B<A   ³ B ³ B ³ B ³ B º B ³ B ³ B ³ B º   ³ A ³ AB³ ABº B ³ B ³ B ³ B º
ºU         ÃÄÄÄÅÄÄÄÅÄÄÄÅÄÄÄ×ÄÄÄÅÄÄÄÅÄÄÄÅÄÄÄ×ÄÄÄÅÄÄÄÅÄÄÄÅÄÄÄ×ÄÄÄÅÄÄÄÅÄÄÄÅÄÄÄ¶
ºB   B>=A  ³ AB³ AB³ B ³ ABº AB³ AB³ B ³ ABº   ³ A ³ B ³ ABº AB³ AB³ B ³ ABº
ÈÍÍÍÍÍÍÍÍÍÍÏÍÍÍÏÍÍÍÏÍÍÍÏÍÍÍÊÍÍÍÏÍÍÍÏÍÍÍÏÍÍÍÊÍÍÍÏÍÍÍÏÍÍÍÏÍÍÍÊÍÍÍÏÍÍÍÏÍÍÍÏÍÍÍ¼


Types of Add Cycles and Sign of Result
ÉÍÍÍÍÍÍÍÍÍÑÍÍÍÍÍÍÍÑÍÍÍÍÍÍÍÑÍÍÍÍÍÍÍÍÍÑÍÍÍÍÍÍÍÍ»
º Type of ³ A-fld ³ B-fld ³ Type of ³ Result º
º Oper.   ³ sign  ³ sign  ³ Add     ³ sign   º
ÌÍÍÍÍÍÍÍÍÍØÍÍÍÍÍÍÍØÍÍÍÍÍÍÍØÍÍÍÍÍÍÍÍÍØÍÍÍÍÍÍÍÍ¹
º         ³       ³   +   ³  true   ³   +    º
º         ³   +   ÃÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄ¶
º         ³       ³   -   ³  compl  ³   M    º
º  Add    ÃÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄ¶
º         ³       ³   +   ³  compl  ³   M    º
º         ³   -   ÃÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄ¶
º         ³       ³   -   ³  true   ³   -    º
ÌÍÍÍÍÍÍÍÍÍØÍÍÍÍÍÍÍØÍÍÍÍÍÍÍØÍÍÍÍÍÍÍÍÍØÍÍÍÍÍÍÍÍ¹
º         ³       ³   +   ³  compl  ³   M    º
º         ³   +   ÃÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄ¶
º         ³       ³   -   ³  true   ³   -    º
º  Sub    ÃÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄ¶
º         ³       ³   +   ³  true   ³   +    º
º         ³   -   ÃÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄ¶
º         ³       ³   -   ³  compl  ³   M    º
ÈÍÍÍÍÍÍÍÍÍÏÍÍÍÍÍÍÍÏÍÍÍÍÍÍÍÏÍÍÍÍÍÍÍÍÍÏÍÍÍÍÍÍÍÍ¼
M = sign of field with larger magnitude

*****************************************************************************/

/*****************************************************************************
		single_cycle_run
        	single_cycle_start
     ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»
     º fetch A          º
     º set a-sign       º
     º set a-done       º
     º Assume A=B       º
     º A-addr--         º
     ÈÍÍÍÍËÍÍÍÍÍÍÍÍÍÍÍÍÍ¼
          º
           A_init_B_fetch
     ÉÍÍÍÍÊÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»
     º fetch B                 º
     º save B_addr for recomp. º
     º set b-sign              º
     º set complement mode     º
     º set carry               º
     ÈÍÍÍÍËÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ¼
          º
            A_init_add
     ÉÍÍÍÍÊÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»
     º add (l/o digits)        º
     º compute A:B             º
     ÈÍÍÍÍÍÍÍÍÍÍÍÍËÍÍÍÍÍÍÍÍÍÍÍÍ¼
                  º 
                  º
                           A_init_store_B
   ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÊÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»
   º     determine last cycle     º
   ÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍËÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ¹
   º last cycle:  º  ~last cycle  º
   º compute sign º  compute sign º
   º store data   º  store data   º
   º B_addr--     º  B_addr--     º
   ÈÍÍÍÍËÍÍÍÍÍÍÍÍÍÊÍÍÍÍÍÍËÍÍÍÍÍÍÍÍ¼
        º                º
        º                º                ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»  
        º                                 A_A_fetch                     º
        º           ÉÍÍÍÍÊÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÊÍÍÍÍÍÍ»                        º
        º           º    is A-field done?        º                        º
        º           ÌÍÍÍÍÍÍÍÍÍÍÍÍÍËÍÍÍÍÍÍÍÍÍÍÍÍÍÍ¹                        º
        º           º a-done      º    ~a-done   º                        º
        º           º fetch '0'   º    fetch A   º                        º
        º           º             º    save zonesº                        º
        º           º             º    a-done?   º                        º
        º           º             º    A_addr--  º                        º
        º           ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÎÍÍÍÍÍÍÍÍÍÍÍÍÍÍ¼                        º
        º                         º                                       º
        º                            A_B_fetch                           º
        º                    ÉÍÍÍÍÊÍÍÍÍÍÍÍ»                               º
        º                    º fetch B    º                               º
        º                    º save zones º                               º
        º                    º b-done?    º                               º
        º                    ÈÍÍÍÍËÍÍÍÍÍÍÍ¼                               º
        º                         º                                       º
        º                          A_add                                 º
        º                     ÉÍÍÍÊÍÍÍ»                                   º
        º                     º  add  º                                   º
        º                     º  A:B  º                                   º
        º                     ÈÍÍÍËÍÍÍ¼                                   º
        º                         º                                       º
        º                         ÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»                      º
        º                                           A_add_cycle_completeº
        º                    ÉÍÍÍÍÊÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÊÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»   º
        º                    º          determinte last cycle         º   º
        º                    ÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍËÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ¹   º
        º                    º last cycle:       º  ~last cycle:      º   º
        º                    º compute h/o zones º                    º   º
        º                    º store data        º  store data        º   º
        º                    º B_addr--          º  B_addr--          º   º
        º                    ÈÍÍÍÍËÍÍÍÍÍÍÍÍÍÍÍÍÍÍÊÍÍÍÍÍÍÍÍËÍÍÍÍÍÍÍÍÍÍÍ¼   º
        º                         º                       º               º
        ÈÍÍÍÍÍÍÍÍÍÍÍËÍÍÍÍÍÍÍÍÍÍÍ¼                       ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ¼
                     º
                        A_B_field_complete
ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÊÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»
º           decide recomplement           º
ÌÍÍÍÍÍÍÍÍÍÍÍÍÍËÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ¹
º  ~recomp    º               recomp      º
º             ÌÍÍÍÍÍÍÍÍÍÍÍÍÍËÍÍÍÍÍÍÍÍÍÍÍÍÍ¹
º             º  carry = 1  º carry = 0   º 
º             ÌÍÍÍÍÍÍÍÍÍÍÍÍÍÎÍÍÍÍÍÍÍÍÍÍÍÍÍ¹
º             º             ºreset B-addr º
º             º  compute &  º             º
º             º  store sign º             º
ÈÍÍÍÍÍÍËÍÍÍÍÍÍÊÍÍÍÍÍÍËÍÍÍÍÍÍÊÍÍËÍÍÍÍÍÍÍÍÍÍ¼
       º             º         º    
       º             º           A_recomp_init_f  
       º             º   ÉÍÍÍÍÍÊÍÍÍÍÍÍÍÍÍÍ»          
       º             º   º  fetch B-data  º          
       º             º   º  complement it º          
       º             º   º  compute sign  º          
       º             º   ÈÍÍÍÍÍËÍÍÍÍÍÍÍÍÍÍ¼          
       º             º         º                      
       º             º           A_recomp_init_s  
       º             º   ÉÍÍÍÍÍÊÍÍÍÍÍÍÍÍÍÍ»          
       º             º   º  store B-data  º          
       º             º   º  B_addr--      º           
       º             º   º  b-done?       º          
       º             º   º  yes     no    º          
       º             º   ÈÍËÍÍÍÍÍÍÍÍËÍÍÍÍÍ¼          
       º             º     º        º                     
       º             º     º        º    ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»
       º             º     º             A_recomp_fetch  º
       º             º     º  ÉÍÍÍÍÍÊÍÍÍÍÊÍÍÍÍÍ»           º
       º             º     º  º  fetch B-data  º           º
       º             º     º  º  complement it º           º
       º             º     º  ÈÍÍÍÍÍËÍÍÍÍÍÍÍÍÍÍ¼           º
       º             º     º        º                      º
       º             º     º           A_recomp_store     º
       º             º     º  ÉÍÍÍÍÍÊÍÍÍÍÍÍÍÍÍÍ»           º
       º             º     º  º  store B-data  º           º
       º             º     º  º  B_addr--      º           º
       º             º     º  ÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ¹           º
       º             º     º  º  b-done?       º           º
       º             º     º  ÌÍÍÍÍÍÍÍÍËÍÍÍÍÍÍÍ¹           º
       º             º     º  º  yes   º  no   º           º
       º             º     º  ÈÍÍÍËÍÍÍÍÊÍÍÍËÍÍÍ¼           º
       º                        º        º               º  
       ÈÍÍÍÍÍÍÍÍÍÍÍÍÊÍÍËÍÊÍÍÍÍÍ¼        ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ¼
                         º
                          single_cycle_complete
                     ÉÍÍÍÊÍÍÍ»           
                     º DONE! º
                     ÈÍÍÍÍÍÍÍ¼ 
*****************************************************************************/

#include "stdio.h"
#include "boolean.h"

#include "btypes.h"

#include "diag.h"
#include "instr.h"
#include "mach.h"
#include "mem1401.h"
#include "logic.h"
#include "bcd.h"
#include "arith.h"
#include "kb.h"
#include "scan.h"

/* State retained across microcycles */

unsigned char a_sign;		/* zone bits of A-field low order position */
unsigned char b_sign;		/* zone bits of B-field low order position */
unsigned char b_ovf;		/* zone bits of B-field high order position */
unsigned char a_ovf;		/* zone bits of A-field high order (presumed) 
				   position (ignored if not b_done) */
boolean complement; 		/* true if complement add required */
int carry;			/* 0 or 1; 0 if no carry, 1 if carry */
int a_done;			/* A-field terminated with WM */
int b_done;			/* B-field terminated with WM */
int init_B_addr; 		/* Initial B-address */
boolean single;	 		/* Are we in single-cycle mode? */
boolean debug_ALU = false;	/* debug mode */
int last_state;			/* last state we were in for debug printout */
int BtoA;			/* comparison of B to A */

#define A_base (local_microstate+1)

#define A_init_B_fetch 		single_cycle(i_A,A_base+1)
#define A_init_add		single_cycle(i_A,A_base+2)
#define A_init_store_B		single_cycle(i_A,A_base+3)
#define A_B_field_complete	single_cycle(i_A,A_base+4)
#define A_recomp_init_f		single_cycle(i_A,A_base+5)
#define A_recomp_init_s		single_cycle(i_A,A_base+6)
#define A_recomp_fetch		single_cycle(i_A,A_base+7)
#define A_recomp_store		single_cycle(i_A,A_base+8)
#define A_A_fetch		single_cycle(i_A,A_base+9)
#define A_B_fetch		single_cycle(i_A,A_base+10)
#define A_add			single_cycle(i_A,A_base+11)
#define A_add_cycle_complete	single_cycle(i_A,A_base+12)

char * arith_state_decode(short state);
static void tell_add_state(boolean op);

/****************************************************************************
*                                  signbits
* Inputs:
*       unsigned char asign: A-sign bit configuration
*	unsigned char bsign: B-sign bit configuration
*	boolean op: true for add, false for subtract
*	int BtoA: Comparison of B to A, gives relative magnitude:
*			logic_BEQA
*			logic_BGTA
*			logic_BLTA
* Result: int
*       Sign bits of result, based on tables as specified in 1401 manual
* Notes:
*	The determination of the relative magnitudes also determines the
*	need to recomplement the result; thus during the recomplement cycle
*	we call for the sign bit given the magnitude considerations.
****************************************************************************/

int addsign[4][4][2] = {
  /* Bsign      0                A                B              AB
       +----------------+----------------+----------------+-----------------+
A-sign |  B<A  | B>=A   |  B<A  | B>=A   |  B<A   | B>=A  |  B<A   | B>=A   |
   0 */{{0     ,0      },{A_bits,A_bits} ,{BA_bits,B_bits},{BA_bits,BA_bits}},
/* A */{{0     ,0      },{A_bits,A_bits} ,{BA_bits,B_bits},{BA_bits,BA_bits}},
/* B */{{B_bits,BA_bits},{B_bits,BA_bits},{B_bits, B_bits},{B_bits ,BA_bits}},
/* AB*/{{0     ,0      },{A_bits,A_bits} ,{BA_bits,B_bits},{BA_bits,BA_bits}}
		       };
	
int subsign[4][4][2] = {
  /* Bsign      0                A                B              AB
        +---------------+----------------+----------------+------------------+
A-sign  | B<A  | B>=A   |  B<A  | B>=A   |  B<A   | B>=A  |  B<A   |  B>=A   |
   0 */{{B_bits,BA_bits},{B_bits,BA_bits},{B_bits ,B_bits},{B_bits ,BA_bits}},
/* A */{{B_bits,BA_bits},{B_bits,BA_bits},{B_bits ,B_bits},{B_bits ,BA_bits}},
/* B */{{0     ,0      },{A_bits,A_bits} ,{BA_bits,B_bits},{BA_bits,BA_bits}},
/* AB*/{{B_bits,BA_bits},{B_bits,BA_bits},{B_bits ,B_bits},{B_bits ,BA_bits}}
		       };

short signbits(unsigned char asign, unsigned char bsign, boolean op, short BtoA)
    {
     if(op)
     	return addsign[ZONEBITS_DOWN(asign)][ZONEBITS_DOWN(bsign)][(BtoA == logic_BLTA ? 0 : 1)];
     
     return subsign[ZONEBITS_DOWN(asign)][ZONEBITS_DOWN(bsign)][(BtoA == logic_BLTA ? 0 : 1)];    
    }

/****************************************************************************
*                                     ALU
* Inputs:
*       unsigned char a: A_data
*	unsigned char b: B_data
* Result: unsigned char 
*       Result of adding a to b, with all zone bits stripped
****************************************************************************/

unsigned char ALU(unsigned char a, unsigned char b)
    {
     int a_data;
     int b_data;
     int result;

     a_data = NUMBITS(a);
     b_data = NUMBITS(b);

     if(a_data == 10) a_data = 0;
     if(b_data == 10) b_data = 0;

     if(b_data > a_data) BtoA = logic_BGTA;
     else
     if(b_data < a_data) BtoA = logic_BLTA;

     if(diagnostics_on && debug_ALU)
        { /* trace ALU */
	 sprintf(diag_buffer,"ALU stage 1: a_data=%d, b_data=%d",a_data,
	 			b_data);
         tell(diag_buffer);
	} /* trace ALU */

     if(complement) 
        { /* 9s complement */
	 
	 a_data = 9 - a_data;

	 if(diagnostics_on & debug_ALU)
	    { /* trace ALU */
	     sprintf(diag_buffer,
	     	       "ALU stage 2 [post complement]: a_data=%d, b_data=%d",
	     			a_data,
	 			b_data);
             tell(diag_buffer);
	    } /* trace ALU */
	} /* 9s complement */

     result = a_data + b_data + carry;

     if(diagnostics_on && debug_ALU)
        { /* trace ALU */
	 sprintf(diag_buffer,"ALU stage 3 [sum]: %d = %d + %d + %d",
	 			result, a_data, b_data, carry);
         tell(diag_buffer);
	} /* trace ALU */

     if(result > 9) 
        { /* carry */
	 carry = 1; 
	 result -= 10;
	} /* carry */
     else carry = 0;

     if(diagnostics_on && debug_ALU)
	{ /* trace ALU */
	 sprintf(diag_buffer,"ALU stage 4 [carry detect]: %d, carry %d",
			    result,carry);
	 tell(diag_buffer);
	} /* trace ALU */

     if(result == 0) result = 10;

     return (unsigned char) result;

    }

/****************************************************************************
*                                    faddmode
* Inputs:
*       unsigned char a_sign: Zone bits of A-field, in normal position
*	unsigned char b_sign: Zone bits of B-field, in normal position
*	boolean add: True if add, false if subtract
* Result: boolean
*       true if true add to be used
*	false if complement add to be used
****************************************************************************/

#define T true
#define C false

boolean faddmode_table[4][4][2] = 
            {
               /*      B=none     B ='A'     B='B'      B='AB'  */       
               /*      add,sub    add,sub    add,sub    add,sub */
/* A-sign none */ {   {  T,C  }, {  T,C  }, {  C,T  }, {  T,C } },
/* A-sign 'A'  */ {   {  T,C  }, {  T,C  }, {  C,T  }, {  T,C } },
/* A-sign 'B'  */ {   {  C,T  }, {  C,T  }, {  T,C  }, {  C,T } },
/* A-sign 'AB' */ {   {  T,C  }, {  T,C  }, {  C,T  }, {  T,C } }
	    };
	    

boolean faddmode(unsigned char a_sign, unsigned char b_sign, boolean add)
    {
     return faddmode_table[ZONEBITS_DOWN(a_sign)][ZONEBITS_DOWN(b_sign)]
     				[(add ? 0 : 1)];
    }

/****************************************************************************
*                                    arith
* Inputs:
*	boolean op: true is add, false is subtract
* Result: boolean
*	true if OK
*	false if error
* Effect: 
*       Algebraically adds or substracts the A-field from the B-field
*	according to the rules given in the introduction above
****************************************************************************/

boolean arith(boolean op)
    {
     boolean cycling;
     boolean result = true;
     boolean report;

     if(single_cycle_state == single_cycle_start) single = true;
     else
     if(single_cycle_state == single_cycle_run) single = false;
     cycling = true;

     while(cycling)
        { /* add fields */
	 last_state = single_cycle_state;
	 switch(single_cycle_state)
	    { /* state decode */
	     case single_cycle_start:
	     case single_cycle_run:
			    /* Set up initial conditions */
			    if(bad_address(A_addr))
			       { /* bogus */
				cycle = cycle_A;
				result = false;
				cycling = false;
				break;
			       } /* bogus */
			    B = memory[A_addr];
			    a_sign = ZONEBITS(B);
			    a_done = WM(B);
			    b_done = false;
			    BtoA = logic_BEQA;
			    A_addr--;
			    single_cycle_state = A_init_B_fetch;
			    cycle = cycle_A;
			    break;
		 case A_init_B_fetch:
			    if(bad_address(B_addr))
			       { /* bogus */
				cycle = cycle_B;
				result = false;
				cycling = false;
				break;
			       } /* bogus */
			    A = B;
			    B = memory[B_addr];
			    init_B_addr = B_addr;
			    b_sign = ZONEBITS(B);
			    b_done = WM(B);
			    b_ovf = 0;
			    complement = !faddmode(a_sign,b_sign,op);
			    if(complement) carry = 1; else carry = 0;
			    single_cycle_state = A_init_add;
			    cycle = cycle_B;
			    break;
		 case A_init_add:
			    L = ALU(A,B);
			    /* Compute sign bits */
			    L |= signbits(a_sign,b_sign,op,BtoA);
			    single_cycle_state = A_init_store_B;
			    break;
		 case A_A_fetch:
			    if(a_done)
			       { /* short A-field */
			        B = 10;	/* BCD '0' */
				a_ovf = 0;
			       } /* short A-field */
			    else
			       { /* still fetching A */
				if(bad_address(A_addr))
				   { /* bogus */
				    cycle = cycle_A;
				    result = false;
				    cycling = false;
				    break;
				   } /* bogus */
				B = memory[A_addr];
				a_ovf = ZONEBITS(B);
				a_done = WM(B);
				A_addr--;
			       } /* still fetching A */
			    single_cycle_state = A_B_fetch;
			    cycle = cycle_A;
			    break;
		 case A_B_fetch:
			    if(bad_address(B_addr))
			       { /* bogus */
				cycle = cycle_B;
				result = false;
				cycling = false;
				break;
			       } /* bogus */
			    A = B;
			    B = memory[B_addr];
			    b_ovf = ZONEBITS(B);
			    b_done = WM(B);
			    cycle = cycle_B;
			    single_cycle_state = A_add;
			    break;
                 case A_add:
			    L = ALU(A,B);
			    /* Compute sign bits */
			    single_cycle_state = A_add_cycle_complete;
			    break;
                 case A_add_cycle_complete:
			    if(b_done)
			       { /* compute overflow bits */
				b_ovf = ZONEBITS(b_ovf + a_ovf);
				if(!complement && carry) 
					b_ovf = ZONEBITS(b_ovf+A_bits);
			       } /* compute overflow bits */
			    else
			       { /* no overflow bits */
			        b_ovf = 0;
			       } /* no overflow bits */
			    memory[B_addr] = L | b_done | b_ovf;
			    single_cycle_state = (b_done ? A_B_field_complete
						    : A_A_fetch);
			    B_addr--;
			    cycle = cycle_B;
			    break;
		 case A_init_store_B:
			    memory[B_addr] = L | b_done;
			    single_cycle_state = (b_done ? A_B_field_complete
						    : A_A_fetch);
			    B_addr--;
			    cycle = cycle_B;
			    break;
		 case A_B_field_complete: /* recomplement? */
		 	    if(complement)
			       { /* need recomplement? */
				 /* If there was a carry, no recomplement is
				    necessary; if there was no carry, we need
				    to recomplement the result
				    1401 Sys Ref Man pp B-2..B-3, figs
				    B-3, B4, B-5
				 */
				if(carry == 1)
				   { /* done */
				    int t;
				   single_cycle_state = single_cycle_complete;
				    /* compute the result sign */
				    t = memory[init_B_addr];
				    t = NUMBITS(t) | WM(t);
				    t |= signbits(a_sign,b_sign,op,BtoA);
				    memory[init_B_addr] = t;
				    break;
				   } /* done */
				else
				   { /* need recomplement */
				    single_cycle_state = A_recomp_init_f;
				    B_addr = init_B_addr;
				   } /* need recomplement */
			       } /* need recomplement? */
			    else
			       { /* set overflow flag */

				single_cycle_state = single_cycle_complete;

				if(carry != 0)
					overflow = true;
			       } /* set overflow flag */
			    cycle = cycle_B;
			    break;
		     case A_recomp_init_f:
		     	    /* We don't need to check address because we
			       would have failed earlier on bad address
			    */
			    B = memory[B_addr];
			    carry = 1;	/* force carry */
			    L = ALU(B,(unsigned char) 0);
			    L = L | signbits(a_sign,b_sign,op,BtoA);
			    single_cycle_state = A_recomp_init_s;
			    cycle = cycle_B;
			    break;
		     case A_recomp_init_s:
			    b_done = WM(memory[B_addr]);
			    memory[B_addr] = L | b_done;
			    single_cycle_state = (b_done ? single_cycle_complete
						    : A_recomp_fetch);
			    B_addr--;
			    if(single_cycle_state == single_cycle_complete)
			    	cycling = false;
			    cycle = cycle_B;
			    break;
		     case A_recomp_fetch:
			    B = memory[B_addr];
			    carry = 0;	/* force carry off */
			    L = ALU(B,(unsigned char) 0);
			    b_done = WM(B);
			    single_cycle_state = A_recomp_store;
			    cycle = cycle_B;
			    break;
		    case A_recomp_store:
		    	    memory[B_addr] = L | b_done;
			    if(b_done)
			        single_cycle_state = single_cycle_complete;
			    else
			    	single_cycle_state = A_recomp_fetch;
			    B_addr--;
			    cycle = cycle_B;
			    break;
			    
		    default:	/* bogus */
		    	tell("Bad add state");
			cycling = false;
			result = false;
			break;
	    } /* state decode */

         if(single_cycle_state==single_cycle_complete) cycling = false;

	 report = diagnostics_on && (single || 
     			   single_cycle_state == single_cycle_complete);

	 if(diagnostics_on && !report && debug_ALU)
	    { /* debugging */
	     tell_add_state(op);
	     if(check_mouse_halt()) 
	     	break;
	    } /* debugging */

	 if(single) break;
	} /* add fields */
     if(report)
     		tell_add_state(op);
     return result;
    }

/****************************************************************************
*                               tell_add_state
* Inputs:
*	boolean op: true for add, false for subtract
* Effect: 
*       Tells state of ALU to diagnostic file
****************************************************************************/

static void tell_add_state(boolean op)
    {
     char * p = diag_buffer;
     p += sprintf(p,"%s [%s]=>%s",
     				(op ? "ADD" : "SUB"),
     				arith_state_decode(last_state),
     				arith_state_decode(single_cycle_state));
     p += sprintf(p,", A=%c, B=%c, L=%c",
     			bcd_to_ascii(A),
     			bcd_to_ascii(B),
     			bcd_to_ascii(L));
     p += sprintf(p,", A_addr=%d, B_addr=%d", A_addr, B_addr);
     if(a_done)
     	p += sprintf(p,", A done");
     if(b_done)
        p += sprintf(p,", B done");
     p += sprintf(p,", Asign=%c, Bsign=%c, Aovf=%c, Bovf=%c",
     			bcd_to_ascii(a_sign),
     			bcd_to_ascii(b_sign),
     			bcd_to_ascii(a_ovf),
     			bcd_to_ascii(b_ovf));
     if(complement)
        p += sprintf(p,", comp");
     if(carry != 0)
        p += sprintf(p,", carry");
     	
     p += sprintf(p, ", %s",logic_state(BtoA));
     tell(diag_buffer);
    }

/****************************************************************************
*                             arith_state_decode
* Inputs:
*	int state: State to decode
* Result: char *
*       printable state string
****************************************************************************/

char * arith_state_decode(short state)
    {
     switch(state)
        { /* decode */
	 case single_cycle_run: return "run";
	 case single_cycle_start: return "start";
	 case single_cycle_complete: return "complete";
	 case A_init_B_fetch: return "init_B_fetch";
	 case A_init_add: return "init_add";
	 case A_init_store_B: return "init_store_B";
	 case A_B_field_complete: return "B_field_complete";
	 case A_recomp_init_f: return "recomp_init_f";
	 case A_recomp_init_s: return "recomp_init_s";
	 case A_recomp_fetch: return "recomp_fetch";
	 case A_A_fetch: return "A_fetch";
	 case A_B_fetch: return "B_fetch";
	 case A_add: return "add";
	 case A_add_cycle_complete: return "add_cycle_complete";
	 default: return "?";
	} /* decode */
     /*NOTREACHED */
     return NULL;
    }

/****************************************************************************
*                                set_ALU_trace
* Inputs:
*       boolean set: Value to set trace to
* Effect: 
*       Sets the debug_ALU flag
****************************************************************************/

void set_ALU_trace(boolean set)
    {
     debug_ALU = set;
    }
