/*****************************************************************************
*           Change Log
*  Date     | Change
*-----------+-----------------------------------------------------------------
* 29-Dec-85 | [1.270] Created
* 25-Jan-86 | [1.327] Check for illegal length
* 25-Feb-86 | [1.379] include <> => include ""
* 10-Nov-91 | [1.428] <jmn> converted to Microsoft C 6.0 libraries
* 18-Nov-91 | [1.428] <jmn> memory.h => mem1401.h, avoid ANSI name
*****************************************************************************/

#include "mem1401.h"
#include "btypes.h"
#include "boolean.h"
#include "mach.h"
#include "diag.h"
#include "instr.h"
#include "ifetch.h"

#define MA_fetch_A_units	    single_cycle(i_MA,local_microstate+1)
#define MA_fetch_B_units	    single_cycle(i_MA,local_microstate+2)
#define MA_store_B_units	    single_cycle(i_MA,local_microstate+3)
#define MA_fetch_A_tens		    single_cycle(i_MA,local_microstate+4)
#define MA_fetch_B_tens		    single_cycle(i_MA,local_microstate+5)
#define MA_store_B_tens		    single_cycle(i_MA,local_microstate+6)
#define MA_fetch_A_hundreds	    single_cycle(i_MA,local_microstate+7)
#define MA_fetch_B_hundreds	    single_cycle(i_MA,local_microstate+8)
#define MA_store_B_hundreds	    single_cycle(i_MA,local_microstate+9)
#define MA_fetch_B_units_zones      single_cycle(i_MA,local_microstate+10)
#define MA_store_B_units_zones      single_cycle(i_MA,local_microstate+11)

static int carry;

/*****************************************************************************
				1401 Simulator

			  Modify Address Instruction

			Modify Address (Two Addresses)
			------------------------------

Instruction format

Mnemonic	Op Code	A-address	B-address
--------        ------- ---------       ---------
MA		#	AAA		BBB

Function: This instructioncauses the 3-character field, specified by the
A-address (A-field) to be added to the 3-character field specified by the
B-address (B-field).  The result is stored in the B-field.  The three
numerical portions and the zones of the units and hundreds positions of the
B-field make up the 3-character result.

Word Marks: Word marks are not affected, and are not required to define the A-
or B-fields.  If word marks are present they are ignored and remain unchanged.

Address Registers After Operation:

I-Add		A-Add		B-Add
-----		-----		-----
NSI		A-3		B-1 or B-3

Chaining: This instruction can be chained to the preceding operation (if
that instruction left usable address-register contents) by supplying
only the operation code.


			 Modify Address (One Address)
			 ----------------------------
Instruction format

Mnemonic	Op Code	A-address
--------        ------- ---------
MA		#	AAA		

Function: This format of the Modify Address instruction causes the 3-character
field, specified by the A-address to be added to itself.  The result is stored
in the A-field.

Word Marks:  Word marks are not required to define the A-field.  If they are
present, they are ignored and left undisturbed.

Address Registers After Operation:

I-Add		A-Add		B-Add
-----           -----           -----
NSI		A-3		A-1 or A-3

Chaining: This instruction can be chained to the preceding operation (if
that instruction left usable address-register contents) by supplying
only the operation code.


*****************************************************************************/


/****************************************************************************
*                                    madd
* Result: int
*       result of adding numeric portions of A and B registers
* Effect:
*	carry reflects if there was an overflow
****************************************************************************/

int madd()
    {
     int a;
     int b;

     a = NUMBITS(A);
     if(a==10) a = 0;
     b = NUMBITS(B);
     if(b==10) b = 0;
     b += a + carry;
     if(b>9)
        { /* carry */
	 carry = 1;
	 b -= 10;
	} /* carry */
     else
        { /* no carry */
	 carry = 0;
	} /* no carry */
     if(b==0) b = 10;
     return b;
    }

/****************************************************************************
*                                   inst_MA
* result: boolean
*	true if instruction succeeded
*	false if instruction failed
* Effect: 
*	Executes the Modify-Address instruction
****************************************************************************/

boolean inst_MA()
    {
     boolean quit;
     boolean result;
     boolean cycling;
     boolean run;
     int sum;
     int zone;

     tell_op(op_A|op_B);

      result = true;
      cycling = true;
      quit = false;

     switch(I_cycle)
         {
	  case 1: /* chained */
	  case 4: /* one-address */
	  case 7: /* two-address */
	  	break;
	  default: /* Illegal length */
	  	illegal_length();
	  	return false;
	 }

      while(cycling)
         { /* add addresses */
	  if(bad_address(A_addr))
	     { /* bogus */
	      cycle = cycle_A;
	      result = false;
	      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:
	      	run = true;
		single_cycle_state = MA_fetch_A_units;
		carry = 0;
		break;
	      case single_cycle_start:
	        run = false;
		single_cycle_state = MA_fetch_A_units;
		carry = 0;
		break;
	      case MA_fetch_A_units:
	        A = B = memory[A_addr];
		A_addr--;
		cycle = cycle_A;
		cycling = run;
		single_cycle_state = MA_fetch_B_units;
		break;
	      case MA_fetch_B_units:
	        B = memory[B_addr];
		cycle = cycle_B;
		cycling = run;
		single_cycle_state = MA_store_B_units;
		break;
	      case MA_store_B_units:
	        sum = madd();
		sum |= (ZONEBITS(A) + ZONEBITS(B)) & BA_bits;
		B = sum | WM(B);
		memory[B_addr] = B;
		B_addr--;
		cycle = cycle_B;
		cycling = run;
		single_cycle_state = MA_fetch_A_tens;
		break;
	      case MA_fetch_A_tens:
	        A = B = memory[A_addr];
		A_addr--;
		cycle = cycle_A;
		cycling = run;
		single_cycle_state = MA_fetch_B_tens;
		break;
	      case MA_fetch_B_tens:
	        B = memory[B_addr];
		cycle = cycle_B;
		cycling = run;
		single_cycle_state = MA_store_B_tens;
		break;
	      case MA_store_B_tens:
	        sum = madd();
		sum |= ZONEBITS(B);
		B = sum | WM(B);
		memory[B_addr] = B;
		B_addr--;
		cycle = cycle_B;
		cycling = run;
		single_cycle_state = MA_fetch_A_hundreds;
		break;
	      case MA_fetch_A_hundreds:
	        A = B = memory[A_addr];
		A_addr--;
		cycle = cycle_A;
		cycling = run;
		single_cycle_state = MA_fetch_B_hundreds;
		break;
	      case MA_fetch_B_hundreds:
	        B = memory[B_addr];
		cycle = cycle_B;
		cycling = run;
		single_cycle_state = MA_store_B_hundreds;
		break;
	      case MA_store_B_hundreds:
	        sum = madd();
		zone = (ZONEBITS(A) + ZONEBITS(B) + (carry==0 ? 0 : A_bits));
		carry = (zone > BA_bits);
		sum |= zone & BA_bits;
		B = sum | WM(B);
		memory[B_addr] = B;
		B_addr--;
		cycle = cycle_B;
		if(carry)
		   { /* must do units zones */
		    single_cycle_state = MA_fetch_B_units_zones;
		    cycling = run;
		   } /* must do units zones */
                else
		   { /* done */
		    single_cycle_state = single_cycle_complete;
		    cycling = false;
		   } /* done */
		break;
	      case MA_fetch_B_units_zones:
	        B_addr += 3;
		B = memory[B_addr];
		single_cycle_state = MA_store_B_units_zones;
		cycling = run;
		cycle = cycle_B;
		break;
	      case MA_store_B_units_zones:
		B = ((ZONEBITS(B) + A_bits) & BA_bits) | NUMBITS(B) | WM(B);
		memory[B_addr] = B;
		B_addr--;
		cycling = false;
		single_cycle_state = single_cycle_complete;
		break;
	     } /* state decode */
	 } /* add addresses */
      return result;
    }