234 lines
5 KiB
C
234 lines
5 KiB
C
|
|
/* $Id: operand.c,v 1.2 2000/05/25 22:28:56 jholder Exp $
|
|
* --------------------------------------------------------------------
|
|
* see doc/License.txt for License Information
|
|
* --------------------------------------------------------------------
|
|
*
|
|
* File name: $Id: operand.c,v 1.2 2000/05/25 22:28:56 jholder Exp $
|
|
*
|
|
* Description:
|
|
*
|
|
* Modification history:
|
|
* $Log: operand.c,v $
|
|
* Revision 1.2 2000/05/25 22:28:56 jholder
|
|
* changes routine names to reflect zmachine opcode names per spec 1.0
|
|
*
|
|
* Revision 1.1.1.1 2000/05/10 14:21:34 jholder
|
|
*
|
|
* imported
|
|
*
|
|
*
|
|
* --------------------------------------------------------------------
|
|
*/
|
|
|
|
/*
|
|
* operand.c
|
|
*
|
|
* Operand manipulation routines
|
|
*
|
|
*/
|
|
|
|
#include "ztypes.h"
|
|
|
|
/*
|
|
* load_operand
|
|
*
|
|
* Load an operand, either: a variable, popped from the stack or a literal.
|
|
*
|
|
*/
|
|
|
|
zword_t load_operand( int type )
|
|
{
|
|
zword_t operand;
|
|
|
|
if ( type )
|
|
{
|
|
|
|
/* Type 1: byte literal, or type 2: operand specifier */
|
|
|
|
operand = ( zword_t ) read_code_byte( );
|
|
if ( type == 2 )
|
|
{
|
|
|
|
/* If operand specifier non-zero then it's a variable, otherwise
|
|
* it's the top of the stack */
|
|
|
|
if ( operand )
|
|
{
|
|
return load_variable( operand );
|
|
}
|
|
else
|
|
{
|
|
return stack[sp++];
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Type 0: word literal */
|
|
return read_code_word( );
|
|
}
|
|
return ( operand );
|
|
|
|
} /* load_operand */
|
|
|
|
/*
|
|
* store_operand
|
|
*
|
|
* Store an operand, either as a variable pushed on the stack.
|
|
*
|
|
*/
|
|
|
|
void store_operand( zword_t operand )
|
|
{
|
|
zbyte_t specifier;
|
|
|
|
/* Read operand specifier byte */
|
|
|
|
specifier = read_code_byte( );
|
|
|
|
/* If operand specifier non-zero then it's a variable, otherwise it's the
|
|
* pushed on the stack */
|
|
|
|
if ( specifier )
|
|
z_store( specifier, operand );
|
|
else
|
|
stack[--sp] = operand;
|
|
|
|
} /* store_operand */
|
|
|
|
/*
|
|
* load_variable
|
|
*
|
|
* Load a variable, either: a stack local variable, a global variable or
|
|
* the top of the stack.
|
|
*
|
|
*/
|
|
|
|
zword_t load_variable( int number )
|
|
{
|
|
if ( number )
|
|
{
|
|
if ( number < 16 )
|
|
{
|
|
/* number in range 1 - 15, it's a stack local variable */
|
|
return stack[fp - ( number - 1 )];
|
|
}
|
|
else
|
|
{
|
|
/* number > 15, it's a global variable */
|
|
return get_word( h_globals_offset + ( ( number - 16 ) * 2 ) );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* number = 0, get from top of stack */
|
|
return stack[sp];
|
|
}
|
|
|
|
} /* load_variable */
|
|
|
|
/*
|
|
* z_store
|
|
*
|
|
* Store a variable, either: a stack local variable, a global variable or the
|
|
* top of the stack.
|
|
*
|
|
*/
|
|
|
|
void z_store( int number, zword_t variable )
|
|
{
|
|
|
|
if ( number )
|
|
{
|
|
if ( number < 16 )
|
|
|
|
/* number in range 1 - 15, it's a stack local variable */
|
|
|
|
stack[fp - ( number - 1 )] = variable;
|
|
else
|
|
/* number > 15, it's a global variable */
|
|
|
|
set_word( h_globals_offset + ( ( number - 16 ) * 2 ), variable );
|
|
}
|
|
else
|
|
/* number = 0, get from top of stack */
|
|
|
|
stack[sp] = variable;
|
|
|
|
} /* z_store */
|
|
|
|
/*
|
|
* z_piracy
|
|
*
|
|
* Supposed to jump if the game thinks that it is pirated.
|
|
*/
|
|
void z_piracy( int flag )
|
|
{
|
|
conditional_jump( flag );
|
|
}
|
|
|
|
/*
|
|
* conditional_jump
|
|
*
|
|
* Take a jump after an instruction based on the flag, either true or false. The
|
|
* jump can be modified by the change logic flag. Normally jumps are taken
|
|
* when the flag is true. When the change logic flag is set then the jump is
|
|
* taken when flag is false. A PC relative jump can also be taken. This jump can
|
|
* either be a positive or negative byte or word range jump. An additional
|
|
* feature is the return option. If the jump offset is zero or one then that
|
|
* literal value is passed to the return instruction, instead of a jump being
|
|
* taken. Complicated or what!
|
|
*
|
|
*/
|
|
|
|
void conditional_jump( int flag )
|
|
{
|
|
zbyte_t specifier;
|
|
zword_t offset;
|
|
|
|
/* Read the specifier byte */
|
|
|
|
specifier = read_code_byte( );
|
|
|
|
/* If the reverse logic flag is set then reverse the flag */
|
|
|
|
if ( specifier & 0x80 )
|
|
flag = ( flag ) ? 0 : 1;
|
|
|
|
/* Jump offset is in bottom 6 bits */
|
|
|
|
offset = ( zword_t ) specifier & 0x3f;
|
|
|
|
/* If the byte range jump flag is not set then load another offset byte */
|
|
|
|
if ( ( specifier & 0x40 ) == 0 )
|
|
{
|
|
|
|
/* Add extra offset byte to existing shifted offset */
|
|
|
|
offset = ( offset << 8 ) + read_code_byte( );
|
|
|
|
/* If top bit of offset is set then propogate the sign bit */
|
|
|
|
if ( offset & 0x2000 )
|
|
offset |= 0xc000;
|
|
}
|
|
|
|
/* If the flag is false then do the jump */
|
|
|
|
if ( flag == 0 )
|
|
{
|
|
|
|
/* If offset equals 0 or 1 return that value instead */
|
|
|
|
if ( offset == 0 || offset == 1 )
|
|
{
|
|
z_ret( offset );
|
|
}
|
|
else
|
|
{ /* Add offset to PC */
|
|
pc = ( unsigned long ) ( pc + ( ZINT16 ) offset - 2 );
|
|
}
|
|
}
|
|
} /* conditional_jump */
|