|
|
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 */
}
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.