File:  [Power 6/32 Unix Tahoe 4.2BSD] / cci / d / fpevent / chk_event.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Sun Jul 28 12:30:17 2019 UTC (7 years ago) by root
Branches: bsd, MAIN
CVS tags: v121, HEAD
Power 6/32 Unix version 1.21

#include "evt_defs.h"

/*
 ********************************************************************
 *
 *	Check the Results of a Floating Point Event
 *
 * This code will verify the following:
 *   - the PSL saved after the event
 *   - the # of operands pushed during the event.
 *   - the PSL pushed on the stack
 *   - the register values
 *   - the final accumulator value
 *
 * If it was an FPP Emulation (FPM) Trap then this code will verify
 *   - the data pushed onto the stack by the trap 
 *   - the PSL saved after the event
 *   - the register values 
 *   - the final accumulator value
 *
 *  17-Jul-85 : added the FPM checks
 *  26-Jul-85 : don't check stack's PSL w/ no-fpp. The no-fpp firmware may
 *              update the PSL before pushing it. 
 ********************************************************************
*/
chk_event()
{
	error = FALSE;
	if( test_event == FPM_CODE ) {	   /* FPP EMULATION TRAP */
	     chk_fpm_trap();			/* check FPM trap data    */
	     if( !error )
		  chk_final_acc();		/* check final Acc value  */
	     if( !error )
		  chk_final_psl();		/* check final PSL value  */
	     if( !error )
		  chk_registers();		/* check final REG values */
	} else {			   /* other event type */
	     chk_final_psl();			/* check final PSL value  */
	     if( !error )
		  chk_push_cnt();		/* check # ops pushed     */
	     if( (!error) && (!no_fpp_wcs) )
		  chk_stack_psl();		/* check PSL on the stack */
	     if( !error )
		  chk_registers();		/* check final REG values */
	     if( !error )
		  chk_final_acc();		/* check final Acc value  */
 	}
 }





/*
 ***************************************************************************
 *
 *	Check the final PSL value
 *
 ***************************************************************************
*/
chk_final_psl()
{
	if( bad_final_psl() ) {
	     error = TRUE;
	     errcnt++;
	     if( prt_error ) {
                  prt_evt_er_msg( bad_psl_msg );
	          writes("final PSL = ");
	          write32h( psl_val );
	          writes(",   expected PSL = ");
	          write32h( exp_psl );
	          writec('\n');
             }
	     if( halt_flg )
		  event_halt( BAD_PSL_HLT );	/* halt on the error */
	     if( loop_on_err )
		  force_loop = TRUE;		/* set loop flag */
	}
}



/*
 ***************************************************************************
 *
 *	Is the final PSL correct?
 *
 *   2-May-85   -stopped looking for 'V' set if the event was enabled.
 *
 ***************************************************************************
*/
bad_final_psl()
{
	exp_psl = psl_val;
	if( (test_event == ARITH_CODE) &&    /* the PSL overflow bit should */
	    (exp_code == INT_OVFL_CODE) &&   /* be set for int. overflow's  */
	    ( evt_disabled ) )		     /* when the event is disabled  */
	     exp_psl |= PSL_V;		/* expect the INTEGER OVERFLOW set  */
	else
	     exp_psl &= ~PSL_V;		/* expect INTEGER OVERFLOW reset    */
	if( psl_val == exp_psl )
	     return( FALSE );
	else 
	     return( TRUE );
}




/*
 ***************************************************************************
 *
 *	Check the # of operands pushed onto the stack
 *
 ***************************************************************************
*/
chk_push_cnt()
{
	 if( bad_push_count() ) {
	     error = TRUE;
	     errcnt++;
	     if( prt_error ) {
	          prt_evt_er_msg( push_cnt_msg );
		  writed( push_cnt );
		  writes(" longwords pushed,   ");
		  writed( exp_push_cnt );
		  writes(" longwords expected\n");
	     }
	     if( halt_flg )
		  event_halt( PUSH_CNT_HLT );	/* halt on the error */
	     if( loop_on_err )
		  force_loop = TRUE;		/* set loop flag */
	}
}



/*
 ***************************************************************************
 *
 *	Were the right number of longwords pushed onto the stack?
 *
 * Get the number of longwords pushed by the change in stack pointer.
 * The only special case is with CMPF2: If the addressing mode is POP
 * and a Reserved Operand fault happens with the 2nd operand then the
 * CMPF2 will pop 2 operands and then the fault will push 2.
 ***************************************************************************
*/
bad_push_count()
{
	push_cnt =  (int) pre_event_sp - (int) post_event_sp;
	push_cnt /= 4;			/* get # longwords pushed */
	if( test_event == ARITH_CODE )
	     exp_push_cnt = 3;	/* ARITHMETIC faults push 3 longwords */
	 else if( test_event == RESOP_CODE ) {
	     if( (op_code == CMPF2_OP_CODE) &&
		 ( (addr_code == 0x8e) || (addr_code == 0x9e) ) &&
		 ( (dbl_value_1.m & 0xff800000) != 0x80000000 ) )
		exp_push_cnt = 0;	/* special case with POPs */
	     else
		exp_push_cnt = 2;	/* reserved ops push 2 longwords */
	} else
	     exp_push_cnt = 2;
	if( push_cnt != exp_push_cnt )
	     return( TRUE );
	else
	     return( FALSE );
}




/*
 ***************************************************************************
 *
 *	Check the PSL pushed onto the stack
 *
 *  22-Jul-85 : don't worry about the N or Z bits in the PSL. The interrupt
 *              handler can store a Zero and update the status.
 *  23-Jul-85 : don't expect the DBL bit set after a CVDF instruction.
 ***************************************************************************
*/
chk_stack_psl()
{
int mask;
	 if( op_code == CVDF_OP_CODE )
	     mask = 0xffffff73;			/* don't look at the DBL bit */
	 else
	     mask = 0xfffffff3;			/* look at the DBL bit */
	 if( (event_psl & mask) != (init_psl & mask) ) { 
	     error = TRUE;
	     errcnt++;
	     if( prt_error ) {
	          prt_evt_er_msg( psl_pushed_msg );
		  writes("PSL on stack = ");
		  write32h( event_psl );
		  writes(",  expected = ");
		  write32h( init_psl );
		  writec('\n');
	     }
	     if( halt_flg )
		  event_halt( PUSH_PSL_HLT );	/* halt on the error */
	     if( loop_on_err )
		  force_loop = TRUE;		/* set loop flag */
	}
}



/*
 ***************************************************************************
 *
 *	Check the final register values
 *
 *  23-Jul-85 : If we are running MULL2 or MULL3 with register addressing 
 *              then don't check the final operand's register. 
 ***************************************************************************
*/
chk_registers()
{
	 if( (op_code == MULL2_OP_CODE) && (addr_mode == ADR_REG) ) {
	      reg_no = addr_code2 & 0xf;	/* get operand 2's reg # */
	      exp_regs[reg_no] = store_regs[reg_no];
	 }
	 if( (op_code == MULL3_OP_CODE) && (addr_mode == ADR_REG) ) {
	      reg_no = addr_code3 & 0xf;	/* get operand 3's reg # */
	      exp_regs[reg_no] = store_regs[reg_no];
	 }
	 reg_no = 0;			/* check regs 0 - 12 */
	 regs_ok = TRUE;
	 while( (reg_no < 13) && (regs_ok) )  
	      if( store_regs[reg_no] == exp_regs[reg_no] )
		   reg_no++;
	      else
		   regs_ok = FALSE;
	 if( !regs_ok ) {
	      error = TRUE;
	      errcnt++;
	      if( prt_error ) {
		   prt_evt_er_msg( reg_modified_msg );
		   writes("Register ");
		   writeh( reg_no );
		   writes(" = ");
		   write32h( store_regs[reg_no] );
		   writes(",  expected = ");
		   write32h( exp_regs[reg_no] );
		   writec('\n');
	      }
	      if( halt_flg )
		   event_halt( BAD_REG_HLT );	/* halt on the error */
	      if( loop_on_err )
		   force_loop = TRUE;		/* set loop flag */
	}
}




/*
 ***************************************************************************
 *
 *	Check the final Accumulator value
 *
 ***************************************************************************
*/
chk_final_acc()
{
	if( acc_trashed() ) {
	     error = TRUE;
	     errcnt++;
	     if( prt_error ) {
	          prt_evt_er_msg( bad_acc_msg );
		  writes("    expected = ");
		  write32h( dbl_expected.m );
		  if( precision == DBL ) {
		       writec(' ');
		       write32h( dbl_expected.l );
		  }
	          writec('\n');
	     }
	     if( halt_flg ) {
		  if( test_event == FPM_CODE )
		       fpm_halt( BAD_ACC_HLT );		/* use the FPM halt */
		  else
		       event_halt( BAD_ACC_HLT );	/* use normal halt */
	     } 
	     if( loop_on_err )
		  force_loop = TRUE;			/* set loop flag */
	} 
}



/*
 ***************************************************************************
 *
 *	Check to see if the accumulator has the correct value in it
 *
 * The final accumulator should either be the original value loaded or '0'.
 *
 * Bad 0's are numbers with a exponent of zero and a non-zero fraction. These
 * are any hex number between 00000001 and 007fffff. Bad 0's are changed to
 * good 0's by the store instruction unless we are using the "no-fpp" WCS
 * and the most significant longword of a double precision accumulator isn't
 * all 0's. If the most significant longword of the accumulator is '0' then 
 * the least significant longword will get cleared anyway. (I didn't write 
 * the micro-code folks - I just test it).
 *
 * The accumulator will be cleared to '0' by the firmware if there is
 * a floating Underflow fault, if there is a floating Overflow fault, or 
 * if there is a floating Reserved Operand fault (except for the compare
 * instructions -CMPF, CMPF2, CMPD, CMPD2). If we are using the "no-fpp" WCS 
 * then the accumulator will not be changed for any Reserved Operands.
 *
 * The accumulator should not be changed by either the Integer Overflow or
 * the Divide By Zero faults.
 *
 * SUMMARY: the final accumulator will be zero if:
 *   A: the most significant accumulator longword is '0'.
 *   B: the accumulator's exponent was zero AND either:
 *      b1: the accumulator is single precision OR 
 *      b2: we're using the FPP WCS
 *   C: We are using the fpp-hardware wcs  AND either:
 *	c1: the event was either floating Overflow or floating Underflow  OR
 *	c2: the event was Reserved Operand and the instruction was not 
 *          one of the 'compare' instructions.
 *
 ***************************************************************************
*/
acc_trashed()
{
int clear_acc;
	clear_acc = FALSE;			/* initialize the clear flag */
	if( !dbl_ld_acc.m )				/* case A: */
	     clear_acc = TRUE;	
	else
	 if( (!(dbl_ld_acc.m & 0x7f800000)) && 		/* case B: */
	     ( (precision == SGL) || (!no_fpp_wcs)) )	/* case b1, b2 */
	     clear_acc = TRUE;	
	else
	 if( (!no_fpp_wcs) &&				/* case C: */
	     ( ( (test_event == ARITH_CODE) && 		/* case c1 */
	 	 ( (exp_code == FLT_OVFL_CODE) ||
 	           (exp_code == FLT_UNDFL_CODE) ) ) ||
	       ( (test_event == RESOP_CODE) &&		/* case c2 */
		 ( (op_code != CMPF_OP_CODE)  &&	
	           (op_code != CMPF2_OP_CODE) &&
	           (op_code != CMPD_OP_CODE)  &&
	           (op_code != CMPD2_OP_CODE) ) ) ) )
	     clear_acc = TRUE;	
	if( clear_acc ) {
	     dbl_expected.m = 0;		/* the Acc. s/b cleared */
	     dbl_expected.l = 0;
	} else {
	     dbl_expected.m = dbl_ld_acc.m;	/* the Acc. s/b unchanged */
	     dbl_expected.l = dbl_ld_acc.l;
	}
	if( (dbl_expected.m != dbl_st_acc.m) || 
	    ( (precision == DBL) && (dbl_expected.l != dbl_st_acc.l) ) )
	     return( TRUE );
	else
	     return( FALSE );	
}



/*
 ***************************************************************************
 *
 *	Check the results of an FPP Emulation Trap.
 *
 *  Check the stack data, the final accumulator, and the registers. The data
 *  was saved by the FPM trap handler.
 *  The stack data is:
 *   - the PSL
 *   - the PC of the next instruction
 *   - the op-code
 *   - the operand's LS longword  { for double precision instructions }
 *   - the operand's MS longword
 *
 ***************************************************************************
*/
chk_fpm_trap()
{
	exp_pc = code_addr + inst_size;		/* expected PC on stack */
/*
 * check the FPM variables pushed onto the stack
*/
	if( !no_ops )				/* if no operands then    */
	    dbl_value_1.m = fpm_ms_op;		/*   expect whatever was  */
	    dbl_value_1.l = fpm_ls_op;		/*     put on the stack   */
	if( precision != DBL )			/* if single operand then */
	    dbl_value_1.l = fpm_ls_op;		/*   no LS op. errors     */
	if((fpm_ms_op != dbl_value_1.m) ||	/* check stack's MS op   */
	   (fpm_ls_op != dbl_value_1.l) ||	/* check stack's LS op   */
	   (fpm_op_code != op_code) ||		/* check stack's op-code */
	   (fpm_pc != exp_pc) ||		/* check stack's PC      */
	   (fpm_psl != init_psl) ) {		/* check stack's PSL     */
	     error = TRUE;
	     errcnt++;
	     if( prt_error ) {
                  prt_evt_er_msg( bad_fpm_stack_msg );
		  writes("  data on the stack       expected\n");
		  writes("  MS operand = ");
		  write32h( fpm_ms_op );		/* MS operand */
		  writes(",  ");
		  write32h( dbl_value_1.m );
		  writes("\n  LS operand = ");
		  write32h( fpm_ls_op );		/* LS operand */
		  writes(",  ");
		  write32h( dbl_value_1.l );
		  writes("\n     op-code = ");
		  write32h( fpm_op_code );		/* op-code */
		  writes(",  ");
		  write32h( op_code );
		  writes("\n         PC  = ");
		  write32h( fpm_pc );			/* PC */
		  writes(",  ");
		  write32h( exp_pc );
		  writes("\n         PSL = ");
		  write32h( fpm_psl );			/* PSL */
		  writes(",  ");
		  write32h( init_psl );
		  writec('\n');
             }
	     if( halt_flg ) 
		  fpm_halt( BAD_FPM_STK_HLT );	/* halt on the error */
	     if( loop_on_err )
		  force_loop = TRUE;		/* set loop flag */
	}
}

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.