/*****************************************************************************
*           Change Log
*  Date     | Change
*-----------+-----------------------------------------------------------------
* 15-Nov-85 | [1.33] Created
* 12-Dec-85 | [1.175] Support fact that OP register does not have WM display.
*           | Requires passing reg value, not XY pair, to all levels
* 20-Dec-85 | [1.221] set_X => show_X for various x; made local procs static
* 27-Jan-86 | [1.350] markscreen with red for error lights
* 22-Feb-86 | [1.362] Treat id as string, not char; use mark_screen_color
*           | to get proper highlighting
* 22-Feb-86 | [1.364] Replace all printf with scdspmsg
* 22-Feb-86 | [1.364] include <> => include ""
* 23-Feb-86 | [1.368] Markscreen now marks characters red
* 23-Feb-86 | [1.368] Updated markscreen calls
* 23-Feb-86 | [1.369] Use new args to mark_screen
* 23-Feb-86 | [1.370] Make active color light red
* 25-Feb-86 | [1.376] Added zap_data to clear color, use color.h to decide
*           | display colors
* 29-Jul-86 | [1.393] Handle lamp test
* 31-Jul-86 | [1.405] Made all chars unsigned
* 18-Aug-86 | [1.414] screen.h -> bscreen.h
* 18-Aug-86 | [1.414] Write characters invisibly in data display
* 20-Aug-86 | [1.426] Special call for turning on address/data check lights
* 10-Nov-91 | [1.428] <jmn> converted to Microsoft C 6.0
*****************************************************************************/

/*****************************************************************************
				 1401 Emulator

			 Data Register Display Module

This module displays the data from the data registers

The encoding of the data is

	M B A 8 4 2 1

The "C" or parity bit is computed as part of this display, and is not actually
stored.

*****************************************************************************/

#include "stdio.h"

#include "btypes.h"
#include "scdspmsg.h"

#include "panel.h"
#include "boolean.h"
#include "disp.h"
#include "hercules.h"
#include "display.h"

#include "data.h"
#include "color.h"

static data_register A = { A_display_X, A_display_Y, "A", '\0', '\0',false,true};
static data_register B = { B_display_X, B_display_Y, "B", '\0', '\0',false,true};
static data_register O = { O_display_X, O_display_Y, "O", '\0', '\0',false,false};

extern void zap_data();
extern void display_data();
extern boolean lamp_test;

/****************************************************************************
*                                draw_data_box
* Inputs:
*       data_register * D;
* Effect: 
*       Draws the data register display on the screen
****************************************************************************/

void draw_data_box(data_register * D)
    {
     attrib fore;
     attrib back;
     char msg[10];

     setcolor(true,&fore,&back,WHITE,BLACK,BLACK,WHITE);

     sprintf(msg,"Ú%s¿",D->id);
     scdspmsg(D->Y,D->X,fore,back,msg);
     scdspmsg((coord)(D->Y+1),D->X,fore,back,"³ ³");
     scdspmsg((coord)(D->Y+1),(coord)(D->X+1),back,back,"C");

     scdspmsg((coord)(D->Y+2),D->X,fore,back,"³ ³");
     scdspmsg((coord)(D->Y+2),(coord)(D->X+1),back,back,"B");

     scdspmsg((coord)(D->Y+3),D->X,fore,back,"³ ³");
     scdspmsg((coord)(D->Y+3),(coord)(D->X+1),back,back,"A");

     scdspmsg((coord)(D->Y+4),D->X,fore,back,"³ ³");
     scdspmsg((coord)(D->Y+4),(coord)(D->X+1),back,back,"8");

     scdspmsg((coord)(D->Y+5),D->X,fore,back,"³ ³");
     scdspmsg((coord)(D->Y+5),(coord)(D->X+1),back,back,"4");

     scdspmsg((coord)(D->Y+6),D->X,fore,back,"³ ³");
     scdspmsg((coord)(D->Y+6),(coord)(D->X+1),back,back,"2");

     scdspmsg((coord)(D->Y+7),D->X,fore,back,"³ ³");
     scdspmsg((coord)(D->Y+7),(coord)(D->X+1),back,back,"1");

     if(D->display_wm)
        { /* wm */
	 scdspmsg((coord)(D->Y+8),D->X,fore,back,"³ ³");
	 scdspmsg((coord)(D->Y+8),(coord)(D->X+1),back,back,"M");
	 scdspmsg((coord)(D->Y+9),D->X,fore,back,"ÀÄÙ");
	} /* wm */
     else
        { /* no wm */
	 scdspmsg((coord)(D->Y+8),D->X,fore,back,"ÀÄÙ");
	} /* no wm */
     zap_data(D);
    }


/****************************************************************************
*                                  zap_data
* Inputs:
*       data_register * D: data register to zap
* Effect: 
*       turns off all the data bits in the box
****************************************************************************/

void zap_data(data_register * D)
    {
     int i;
     coord row;

     row = D->Y + 7;

     for(i=0;i<6;i++)  /* BA8421 */
         {
	  markscreen(row,(coord)(D->X+1),false,digit_on,BLACK,digit_off,BLACK);
	  row--;
	 }

      if(D->display_wm)
	  markscreen((coord)(D->Y+8),(coord)(D->X+1),false,digit_on,BLACK,digit_off,BLACK);
	  
      markscreen((coord)(D->Y+1),(coord)(D->X+1),true,digit_on,BLACK,digit_off,BLACK);
    }

/****************************************************************************
*                               draw_data_boxes
* Effect: 
*       Draws the data display register boxes on the screen
****************************************************************************/

void draw_data_boxes()
    {
     draw_data_box(&A);
     draw_data_box(&B);
     draw_data_box(&O);
     display_data(&A);
     display_data(&B);
     display_data(&O);
    }


/****************************************************************************
*                                  mark_data
* Inputs:
*	data_register * D: Data register
*       unsigned char value: Value to mark in position
*	boolean set: true to highlight, false to unhighlight
* Effect: 
*       Turns lights on and off in data display
****************************************************************************/

static void mark_data(data_register * D, unsigned char value, boolean set)
    {
     coord row;
     int i;
     int parity;

     row = D->Y + 7;
     parity = 0;

     for(i=0;i<6;i++)  /* BA8421 */
         {
	  if(value == 0 && !lamp_test) 
	     break;
	  if((value & 1) != 0 || lamp_test)
	     { /* do it */
	      markscreen(row,(coord)(D->X+1),(boolean)(lamp_test || set),digit_on,BLACK,digit_off,BLACK);

	      parity++;
	     } /* do it */
	  row--;
	  value >>= 1;
	 }

      if(D->display_wm)
        if((value & 1) != 0 || lamp_test)
         { /* word mark */
	  markscreen((coord)(D->Y+8),(coord)(D->X+1),(boolean)(lamp_test || set),digit_on,BLACK,digit_off,BLACK);
	  parity++;
	 } /* word mark */
	  
      if((parity & 1) == 0 || lamp_test)
         { /* force odd parity */
	  markscreen((coord)(D->Y+1),(coord)(D->X+1),(boolean)(lamp_test || set),
	  				digit_on,BLACK,digit_off,BLACK);
	 } /* force odd parity */
	  
    }

/****************************************************************************
*                                  set_data
* Inputs:
*	data_register * D: Data register to manipulate
*	unsigned char data: Data to set
* Effect: 
*       Marks the data positions on the display
****************************************************************************/

static void set_data(data_register * D, unsigned char data)
    {
     mark_data(D,data,true);
    }

/****************************************************************************
*                                  clear_data
* Inputs:
*	data_register * D: Data register to manipulate
*	unsigned char data: Data to clear
* Effect: 
*       Unmarks the data positions on the display
****************************************************************************/

static void clear_data(data_register * D, unsigned char data)
    {
     mark_data(D,data,false);
    }

/****************************************************************************
*                                display_data
* Inputs:
*	data_register * D: Data register to display
* Effect: 
*       Displays the data in the register
****************************************************************************/

void display_data( data_register * D )
    {
     clear_data(D,D->old_data);
     set_data(D,D->data);
     D->old_data = D->data;
     light_data(D,D->lit);
    }


/****************************************************************************
*                                 light_data
* Inputs:
*       data_register * D: Data register whose code is to be lit
*	boolean set: true to light it, false to unlight it
* Effect: 
*       Lights the register code.  Normally this indicates parity error,
*	but for illegal opcodes, the op light gets lit
****************************************************************************/

void light_data(data_register * D, boolean set)
    {
     D->lit = set;

     if(!showing_console()) 
	return;

     if(ismono())
	mark_screen_color((coord)(D->X+1),D->Y,D->id,(boolean)(lamp_test || set),
				BLACK,WHITE,WHITE,BLACK);
     else
	mark_screen_color((coord)(D->X+1),D->Y,D->id,(boolean)(lamp_test || set),
				LTRED,BLACK,WHITE,BLACK);
    }

/****************************************************************************
*                                   light_O
* Inputs:
*       boolean set: Mode to light O-register, true on, false off
* Effect: 
*       Lights or unlights the opcode light
****************************************************************************/

void light_O(boolean set)
    {
     light_data(&O,set);
    }

/****************************************************************************
*                                    show_A
* Inputs:
*       unsigned char data: Data to set in register
* Effect: 
*       Updates the A-register
****************************************************************************/

void show_A(unsigned char data)
    {
     A.data = data;
     display_data(&A);
    }

/****************************************************************************
*                                    show_B
* Inputs:
*       unsigned char data: Data to set in register
* Effect: 
*       Updates the B-register
****************************************************************************/

void show_B( unsigned char data )
    {
     B.data = data;
     display_data(&B);
    }

/****************************************************************************
*                                    show_O
* Inputs:
*       unsigned char data: Data to set in register
* Effect: 
*       Updates the O-register
****************************************************************************/

void show_O( unsigned char data)
    {
     O.data = data;
     display_data(&O);
    }
