/*****************************************************************************
*           Change Log
*  Date     | Change
*-----------+-----------------------------------------------------------------
* 27-Dec-85 | [1.241] Created
* 27-Jan-86 | [1.350] declare single_cycle_decode
* 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 "stdio.h"
#include "btypes.h"
#include "mem1401.h"
#include "boolean.h"
#include "mach.h"
#include "diag.h"
#include "instr.h"
#include "ifetch.h"

/* Machine State:    */

#define MCS_A_complete single_cycle(i_MCS,A_complete)
#define MCS_B_complete single_cycle(i_MCS,B_complete)
#define MCS_B_f_complete single_cycle(i_MCS,B_f_complete)
#define MCS_B_s_complete single_cycle(i_MCS,B_s_complete)

#define MCS_move   single_cycle(i_MCS,local_microstate+1)
#define MCS_suppress_f_complete single_cycle(i_MCS,local_microstate+2)
#define MCS_suppress_s_complete single_cycle(i_MCS,local_microstate+3)
#define MCS_suppress_init single_cycle(i_MCS,local_microstate+4)
#define MCS_skip_f_complete     single_cycle(i_MCS,local_microstate+5)
#define MCS_skip_s_complete     single_cycle(i_MCS,local_microstate+6)
	
extern char * single_cycle_decode();

/*****************************************************************************
				1401 Simulator

		      Move Characters and Suppress Zeroes

		   Move and Suppress Zeroes (Two Addresses)
		   ----------------------------------------

Instruction format

Mnemonic	Op Code	A-address	B-address
--------        ------- ---------       ---------
MCS		Z	AAA		BBB

Function: The data in the A-field is moved to the B-field.  AFter the
move, high-order zeros and commas are replaced by blanks in the B-field.
Any character that is not a comma, hyphen, blank, significant digit,
or zero causes zero suppression to begin again.  The sign is removed
from the units position of the data field.

Word Marks: The A-field word mark stops transmission of data.  B-field
word marks, encountered during the move operation, are erased.

Note: This description of the instruction assumes a 1401 without the
expanded print-edit special feature.  If the feature is installed,
a decimal point does not start zero suppression.

Simulator note: We implement expanded print-edit.

Address Registers After Operation:

I-Add		A-Add		B-Add
-----		-----		-----
NSI		A-La		B+1

Chaining: This instruction can be chained to the preceding operation (if
that instruction left usable address-register contents) by supplying
only the operation code.

*****************************************************************************/

static int init_B_addr;

/****************************************************************************
*                                   inst_MCS
* result: boolean
*	true if instruction succeeded
*	false if instruction failed
* Effect: 
*	Executes move and suppress zeroes instruction
****************************************************************************/

boolean inst_MCS()
    {
     boolean quit;
     boolean result;
     boolean cycling;
     boolean run;

     switch(I_cycle)
        { /* length dispatch */
	 case 1: /* chained */
	 	break;
         case 7: /* normal */
	 	break;
	 default: /* illegal length */
	 	illegal_length();
		return false;
	} /* length dispatch */

     tell_op(op_A|op_B);

      result = true;
      cycling = true;
      quit = false;

      while(cycling)
         { /* move chars */
	  if(bad_address(A_addr))
	     { /* bogus */
	      cycle = cycle_A;
	      result = false;
	      quit = true;
	      cycling = false;
	      break;
	     } /* bogus */

	  if(bad_address(B_addr))
	     { /* bogus */
	      cycle = cycle_B;
	      result = false;
	      quit = true;
	      cycling = false;
	      break;
	     } /* bogus */
	      
	  switch(single_cycle_state)
	     { /* state decode */
	      case single_cycle_run:
	      		init_B_addr = B_addr;
			run = true;
			single_cycle_state = MCS_move;
			break;
	      case MCS_move:
	      		B = memory[A_addr];
	      		memory[B_addr] = BA8421(B);
			if(WM(B)) single_cycle_state = MCS_suppress_init;
			A_addr--;
			B_addr--;
			break;
	      case single_cycle_start:
	      		run = false;
	      		init_B_addr = B_addr;
			/* FALLS THRU TO MCS_B_COMPLETE! */
	      case MCS_B_complete:
	      		B = memory[A_addr];
			A_addr--;
			cycle = cycle_A;
			single_cycle_state = MCS_A_complete;
			cycling = run;
			break;
	      case MCS_A_complete:
	      		A = B;
			memory[B_addr] = BA8421(A);
			B_addr--;
			cycle = cycle_B;
			if(WM(B)) single_cycle_state = MCS_suppress_init;
				else
				single_cycle_state = MCS_B_complete;
			cycling = run;
			break;
	      case MCS_suppress_init:
			/* FALLS THRU TO MCS_suppress */
	      case MCS_suppress_s_complete:
	      		B_addr++;
			if(B_addr > init_B_addr)
			   { /* done */
			    quit = true;
			    cycling = false;
			    break;
			   } /* done */
			B = memory[B_addr];
			cycle = cycle_B;
			single_cycle_state = MCS_suppress_f_complete;
			cycling = run;
			break;
		case MCS_suppress_f_complete:
			/* We are in suppress mode.  if the character is
			   '0' or ',', make it a space and set the state
			   to MCS_suppress_s_complete
                        */
			switch(BA8421(B))
			   { /* decode */
			    case 10:	/* BCD '0' */
			    case 27:	/* BCD ',' */
			    		B = 0;		/* BCD space */
					memory[B_addr] = B;
					single_cycle_state = MCS_suppress_s_complete;
					break;
			    case 1:	/* BCD '1' */
			    case 2:	/* BCD '2' */
			    case 3:	/* BCD '3' */
			    case 4:	/* BCD '4' */
			    case 5:	/* BCD '5' */
			    case 6:	/* BCD '6' */
			    case 7:	/* BCD '7' */
			    case 8:	/* BCD '8' */
			    case 9:	/* BCD '9' */
			    	single_cycle_state = MCS_skip_f_complete;
				break;
			    default:	/* skip it but don't change suppress */
			        single_cycle_state = MCS_suppress_s_complete;
				break;

			   } /* decode */
			cycle = cycle_B;
			cycling = run;
			break;
	      case MCS_skip_s_complete:
	      		B_addr++;
			if(B_addr > init_B_addr)
			   { /* done */
			    quit = true;
			    cycling = false;
			    break;
			   } /* done */
			B = memory[B_addr];
			single_cycle_state = MCS_skip_f_complete;
			cycle = cycle_B;
			cycling = run;
			break;
	      case MCS_skip_f_complete:
	      		switch(BA8421(B))
			   { /* check char */
			    case 1:	/* BCD '1' */
			    case 2:	/* BCD '2' */
			    case 3:	/* BCD '3' */
			    case 4:	/* BCD '4' */
			    case 5:	/* BCD '5' */
			    case 6:	/* BCD '6' */
			    case 7:	/* BCD '7' */
			    case 8:	/* BCD '8' */
			    case 9:	/* BCD '9' */
			    case 10:	/* BCD '0' */
			    case 32:	/* BCD '-' */
			    case 27:	/* BCD ',' */
			    case 59:	/* BCD '.' (EXPANDED PRINT EDIT) */
			    case 0:	/* BCD space */
			    	/* retain skip mode */
			    	single_cycle_state = MCS_skip_s_complete;
				break;
			    default:
			        /* It isn't any of the above, restart
				   suppress mode 
				*/   
				single_cycle_state = MCS_suppress_s_complete;
				break;
			   } /* check char */
			cycle = cycle_B;
			cycling = run;
			break;
	      default:
	      		sprintf(diag_buffer,"Illegal microstate %s",single_cycle_decode());
			tell(diag_buffer);
			result = false;
			cycling = run;
			break;
	     } /* state decode */

	      if(quit) 
	      	{
		 single_cycle_state = single_cycle_complete;
		 break;
		}
 	  
	  if(diagnostics_on && run)
	  	tell_new_state("MCS");
	 } /* move chars */
	  
      tell_new_state("MCS");
      return result;	
    }
