/*****************************************************************************
*           Change Log
*  Date     | Change
*-----------+-----------------------------------------------------------------
* 15-Dec-85 | [1.199] Created
* 27-Jan-86 | [1.350] declare single_cycle_decode
* 25-Feb-86 | [1.379] include <> => include ""
* 31-Jul-86 | [1.405] Made char vars unsigned
*  6-Aug-86 | [1.410] Added NOTREACHED comment
* 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
*****************************************************************************/
#include "stdio.h"
#include "boolean.h"

#include "mem1401.h"
#include "btypes.h"
#include "mach.h"
#include "diag.h"
#include "instr.h"
#include "alerts.h"
#include "poll.h"
#include "ifetch.h"
#include "alert.h"

#define BWZ_B_f_complete single_cycle(i_BWZ,B_f_complete)

extern char * single_cycle_decode();

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

		    Branch on Word Mark or Zone Instruction


			 Branch on Word Mark or Zone
			 ---------------------------

Instruction format

Mnemonic	Op Code	I-address	B-address	d-char
--------        ------- ---------       ---------	------
BWZ		V	III		BBB		d

Function: This instruction examines the single character at the B-address for
zone or word mark combinations specified by the d-character.  A correct
comparison branches to the specified I-address.  If the program does not
branch to the I-address, it continues sequentially.  The d-character can be
one of:

	1	word mark
	2	No zone
	3	A word mark, or no zone
	B	12-zone (AB)
	C	A word mark, or 12 zone
	K	11-zone (B)
	L	A word mark, or 11-zone
	S	0-zone (A)
	T	A word mark, or 0-zone

Word Marks:  Word marks in the location tested have no effect on the
operation.

Address Registers After Operation:

No Branch:

I-Add		A-Add		B-Add
NSI		BI		B-1

Branch

I-Add		A-Add		B-Add
NSI		BI		NSI

Chaining: The instruction can be chained to the preceding operation by
supplying only the operation code.

*****************************************************************************/

/****************************************************************************
*                                     bwz
* Inputs:
*       unsigned char data: data to test
*	unsigned char d: Condition to test it against
* Result: boolean
*       true if branch should be taken
*	false if not
* Effect: 
*       may set a process alert if the d-char is illegal
****************************************************************************/

boolean bwz(unsigned char data, unsigned char d)
    {
     switch(d)
        { /* d decode */

	 case 1:	/* "1" - word mark */
	 	return (boolean) WM(data);

	 case 2:	/* "2" - no zone */
	 	return (boolean) ZONEBITS(data) == 0;

	 case 3:	/* "3" - wm or no zone */
	 	return WM(data) || (ZONEBITS(data) == 0);

	 case 50:	/* "B" - AB bits */
	 	return ZONEBITS(data) == BA_bits;

	 case 51:	/* "C" - AB bits or wm */
	 	return WM(data) || (ZONEBITS(data) == BA_bits);

	 case 34:	/* "K" - B bit */
	 	return ZONEBITS(data) == B_bits;

	 case 35:	/* "L" - B bit or wm */
	 	return WM(data) || (ZONEBITS(data) == B_bits);

	 case 18:	/* "S" - A bit */
	 	return ZONEBITS(data) == A_bits;

	 case 19:	/* "T" - A bit or wm */
	 	return WM(data) || (ZONEBITS(data) == A_bits);

	 default:	/* Illegal code */
	 	alert(alert_process);
		return false;
	} /* d decode */
     /*NOTREACHED */
     return false;	/* should never get here */
    }

/****************************************************************************
*                                   inst_BWZ
* Result: boolean
*       true if processing should continue
*	false if processing should halt
* Effect: 
*       Executes the branch-on-word-or-zone instruction
****************************************************************************/

boolean inst_BWZ()
    {

     tell_op(op_A|op_B|op_d);

     switch(I_cycle)
         {

/* BWZ */
	  case 1: /* chained */

		if(bad_address(B_addr)) return false;

		switch(single_cycle_state)
		   { /* state decode */
		    case single_cycle_run:
		    	B = memory[B_addr];

			if(bwz(B,d_char))
			   { /* take branch */
			    NI_addr = A_addr;
			    B_addr = I_addr;
			    poll();
			   } /* take branch */
			else
			   { /* don't branch */
			    B_addr--;
			   } /* don't branch */
			single_cycle_state = single_cycle_complete;
			break;
		    case single_cycle_start:
		    	B = memory[B_addr];
			B_addr--;
			cycle = cycle_B;
			single_cycle_state = BWZ_B_f_complete;
			break;
		    case BWZ_B_f_complete:
			if(bwz(B,d_char))
			   { /* take branch */
			    NI_addr = A_addr;
			    B_addr = I_addr;
			    poll();
			   } /* take branch */
		        single_cycle_state = single_cycle_complete;
		    default:
			  sprintf(diag_buffer,"Illegal microstate %s",single_cycle_decode());
			  tell(diag_buffer);
			  single_cycle_state = single_cycle_complete;
		   } /* state decode */
		tell_new_state("BWZ");
		break;

/* Biiibbbd */
	  case 8: /* two-address + d */

		if(bad_address(B_addr)) return false;

		switch(single_cycle_state)
		   { /* state decode */
		    case single_cycle_run:
		    	B = memory[B_addr];

			if(bwz(B,d_char))
			   { /* take branch */
			    NI_addr = A_addr;
			    B_addr = I_addr;
			    poll();
			   } /* take branch */
			else
			   { /* don't branch */
			    B_addr--;
			   } /* don't branch */
			single_cycle_state = single_cycle_complete;
			break;
		    case single_cycle_start:
		    	B = memory[B_addr];
			A = d_char;	/* this may not be right... */
			B_addr--;
			cycle = cycle_B;
			single_cycle_state = BWZ_B_f_complete;
			break;
		    case BWZ_B_f_complete:
			if(bwz(B,d_char))
			   { /* take branch */
			    NI_addr = A_addr;
			    B_addr = I_addr;
			    poll();
			   } /* take branch */
		        single_cycle_state = single_cycle_complete;
		   } /* state decode */

		/* be sure to reset any indicators as described in 'notes' */
		single_cycle_state = single_cycle_complete;
		tell_new_state("BWZ");
		break;
	  default: /* Illegal */
	  	illegal_length();
	  	return false;
	 }

      return true;
    }
