/*****************************************************************************
*           Change Log
*  Date     | Change
*-----------+-----------------------------------------------------------------
* 25-Nov-85 | [1.131] Created
*  8-Dec-85 | [1.157] Set single_cycle_complete at end of run decode
* 25-Jan-86 | [1.327] Check for bad length; note we do not check for 8-char
*           | device moves
* 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
* 05-Jan-95 | [1.600J] JRJ Implemenent Tape I/O
*****************************************************************************/

#include "stdio.h"
#include "btypes.h"
#include "mem1401.h"
#include "boolean.h"
#include "mach.h"
#include "machmem.h"
#include "diag.h"
#include "instr.h"
#include "ifetch.h"
#include "io.h"
#include "alert.h"
#include "alerts.h"
#include "button.h"
#include "tape.h"

/* Machine State:    */

#define MLCWA_A_complete single_cycle(i_MLCWA,A_complete)
#define MLCWA_B_complete single_cycle(i_MLCWA,B_complete)

extern char * single_cycle_decode();

/*****************************************************************************
				1401 Simulator

			       Load Instruction
		 (Move Left Characters to Wordmark in A-field)


			     Load (Device Address)
			     ---------------------

Instruction Format:

Mnemonic	Op Code	A-address	B-address     d-char
--------        ------- ---------       ---------     ------
LU		L	%Dn		BBB              d

Function: Device-specific.  Cannot be chained.


			     Load (Two Addresses)
			     --------------------

Instruction format

Mnemonic	Op Code	A-address	B-address
--------        ------- ---------       ---------
MLCWA		L	AAA		BBB

Function: The instruction is commonly used to load data into designated
printer or punch output areas of storage, and also to transfer data or
instructions from a designated read-in area to another storage area.
The data and word mark from the A-field are transferred to the B-field, and
all other word marks in the B-field are cleared.

Word Marks: The A-field must have a defining word mark, because the A-field
word mark stops the operation.  Note: If the B-field is larger than the
A-field, the B-field word mark is not cleared.

Address Registers After Operation:

I-Add		A-Add		B-Add
-----		-----		-----
NSI		A-La		B-La

Chaining: This instruction can be chained to the preceding operation (if
that instruction left usable address-register contents) by supplying
only the operation code.


			 Load Characters (One Address)
			 -----------------------------
Instruction format

Mnemonic	Op Code	A-address
--------        ------- ---------
MLCWA		L	AAA

Function: This format can be used when several A-fields (not necessarily
in sequence) are to be loaded sequentially to the B-field.  This instruction
causes the A-field data and word mark to be moved to the B-field.  B-field
word marks are cleared, up to the A-field word mark.

Word Marks:  The A-field word mark stops the operation.  Therefore, B-field
word marks beyond the left limit of the A-field are not cleared.

Address Registers After Operation:

I-Add		A-Add		B-Add
-----           -----           -----
NSI		A-La		Bp-La

Chaining: This instruction can be chained to the preceding operation (if
that instruction left usable address-register contents) by supplying
only the operation code.


*****************************************************************************/


/****************************************************************************
*                                   inst_MLCWA
* result: boolean
*	true if instruction succeeded
*	false if instruction failed
* Effect:
*	Executes load-characters-to-A-field-word-mark instruction
****************************************************************************/

boolean inst_MLCWA()
    {
     boolean quit;
     boolean result;
     boolean cycling;

     tell_op(op_A|op_B);

      result = true;
      cycling = true;
      quit = false;

      /*
	If this is an I/O instruction, then the length must be 8.
	Otherwise, it is a regular move instruction, which can be
	chained.
      */

      if(io_index_inhibit) {
	if(I_cycle != 8) {
		illegal_length();
		return false;
	}
      }
      else {
	switch(I_cycle)
	{
	   case 1: /* chained */
	   case 4: /* one-address */
	   case 7: /* two-address */
		break;
	   default: /* Illegal length */
		illegal_length();
		return false;
	}
      }

      if(io_index_inhibit) {
	switch(io_device) {
	case BCD_U:
		switch(d_char) {
		case BCD_R:
			return(tape_io_read(true));
			break;
		case BCD_W:
			return(tape_io_write(true));
			break;
		default:
			tell("Invalid Tape I/O d character.\n");
			alert(alert_process);
			return(false);
		}
	default:
		tell("Invalid I/O Device.\n");
		alert(alert_ramac);
		break;
	}
      }


     switch(I_cycle)
	 {
	  case 1: /* chained */
	  case 4: /* one-address */
	  case 7: /* two-address */
		break;
	  default: /* Illegal length */
		illegal_length();
		return 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:
	      		A = B = memory[B_addr] = memory[A_addr];
			quit = WM(B);
			A_addr--;
			B_addr--;
			break;
	      case MLCWA_B_complete:
	      case single_cycle_start:
	      		B = memory[A_addr];
			A_addr--;
			cycle = cycle_A;
			single_cycle_state = MLCWA_A_complete;
			cycling = false;
			break;
	      case MLCWA_A_complete:
	      		A = B;
			memory[B_addr] = A;
			B_addr--;
			cycle = cycle_B;
			single_cycle_state = MLCWA_B_complete;
			quit = WM(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;
		}
 	  
	 } /* move chars */
	  
      tell_new_state("MLCWA");
      return result;	
    }
