583 lines
12 KiB
C
583 lines
12 KiB
C
|
|
/* $Id: property.c,v 1.2 2000/05/25 22:28:56 jholder Exp $
|
|
* --------------------------------------------------------------------
|
|
* see doc/License.txt for License Information
|
|
* --------------------------------------------------------------------
|
|
*
|
|
* File name: $Id: property.c,v 1.2 2000/05/25 22:28:56 jholder Exp $
|
|
*
|
|
* Description:
|
|
*
|
|
* Modification history:
|
|
* $Log: property.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
|
|
*
|
|
*
|
|
* --------------------------------------------------------------------
|
|
*/
|
|
|
|
/*
|
|
* property.c
|
|
*
|
|
* Property manipulation routines
|
|
*
|
|
*/
|
|
|
|
#include "ztypes.h"
|
|
|
|
/*
|
|
* get_property_addr
|
|
*
|
|
* Calculate the address of the start of the property list associated with an
|
|
* object.
|
|
*
|
|
*/
|
|
|
|
static zword_t get_property_addr( zword_t obj )
|
|
{
|
|
zword_t object_addr;
|
|
zword_t prop_addr;
|
|
zbyte_t size;
|
|
|
|
/* Calculate the address of the property pointer in the object */
|
|
|
|
object_addr = get_object_address( obj );
|
|
object_addr += ( h_type <= V3 ) ? O3_PROPERTY_OFFSET : O4_PROPERTY_OFFSET;
|
|
|
|
/* Read the property address */
|
|
prop_addr = get_word( object_addr );
|
|
|
|
/* Skip past object description which is an ASCIC of encoded words */
|
|
size = get_byte( prop_addr );
|
|
|
|
return prop_addr + ( size * 2 ) + 1;
|
|
|
|
} /* get_property_addr */
|
|
|
|
/*
|
|
* get_next_property
|
|
*
|
|
* Calculate the address of the next property in a property list.
|
|
*
|
|
*/
|
|
|
|
static zword_t get_next_property( zword_t prop_addr )
|
|
{
|
|
zbyte_t value;
|
|
|
|
/* Load the current property id */
|
|
value = get_byte( prop_addr );
|
|
prop_addr++;
|
|
|
|
/* Calculate the length of this property */
|
|
|
|
if ( h_type <= V3 )
|
|
value >>= 5;
|
|
else if ( !( value & 0x80 ) )
|
|
value >>= 6;
|
|
else
|
|
{
|
|
value = get_byte( prop_addr );
|
|
value &= property_size_mask;
|
|
|
|
if ( value == 0 )
|
|
value = 64; /* spec 1.0 */
|
|
}
|
|
|
|
/* Address property length to current property pointer */
|
|
return prop_addr + value + 1;
|
|
|
|
} /* get_next_property */
|
|
|
|
/*
|
|
* z_get_prop
|
|
*
|
|
* Load a property from a property list. Properties are held in list sorted by
|
|
* property id, with highest ids first. There is also a concept of a default
|
|
* property for loading only. The default properties are held in a table pointed
|
|
* to be the object pointer, and occupy the space before the first object.
|
|
*
|
|
*/
|
|
|
|
void z_get_prop( zword_t obj, zword_t prop )
|
|
{
|
|
zword_t prop_addr;
|
|
zword_t wprop_val;
|
|
zbyte_t bprop_val;
|
|
zbyte_t value;
|
|
|
|
#ifdef STRICTZ
|
|
if ( obj == 0 )
|
|
{
|
|
report_strictz_error( STRZERR_GET_PROP, "@get_prop called with object 0" );
|
|
store_operand( 0 );
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
/* Load address of first property */
|
|
prop_addr = get_property_addr( obj );
|
|
|
|
/* Scan down the property list */
|
|
for ( ;; )
|
|
{
|
|
value = get_byte( prop_addr );
|
|
if ( ( zbyte_t ) ( value & property_mask ) <= ( zbyte_t ) prop )
|
|
break;
|
|
prop_addr = get_next_property( prop_addr );
|
|
}
|
|
|
|
/* If the property ids match then load the first property */
|
|
|
|
if ( ( zbyte_t ) ( value & property_mask ) == ( zbyte_t ) prop ) /* property found */
|
|
{
|
|
prop_addr++;
|
|
/* Only load first property if it is a byte sized property */
|
|
if ( (h_type <= V3 && !( value & 0xe0 )) || (h_type >= V4 && !( value & 0xc0 )) )
|
|
{
|
|
bprop_val = get_byte( prop_addr );
|
|
wprop_val = bprop_val;
|
|
}
|
|
else
|
|
{
|
|
wprop_val = get_word( prop_addr );
|
|
}
|
|
}
|
|
else /* property not found */
|
|
{
|
|
/* Calculate the address of the default property */
|
|
prop_addr = h_objects_offset + ( ( prop - 1 ) * 2 );
|
|
wprop_val = get_word( prop_addr );
|
|
}
|
|
|
|
/* store the property value */
|
|
|
|
store_operand( wprop_val );
|
|
|
|
} /* z_get_prop */
|
|
|
|
/*
|
|
* z_put_prop
|
|
*
|
|
* Store a property value in a property list. The property must exist in the
|
|
* property list to be replaced.
|
|
*
|
|
*/
|
|
|
|
void z_put_prop( zword_t obj, zword_t prop, zword_t setvalue )
|
|
{
|
|
zword_t prop_addr;
|
|
zword_t value;
|
|
|
|
#ifdef STRICTZ
|
|
if ( obj == 0 )
|
|
{
|
|
report_strictz_error( STRZERR_PUT_PROP, "@put_prop called with object 0" );
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
/* Load address of first property */
|
|
prop_addr = get_property_addr( obj );
|
|
|
|
/* Scan down the property list */
|
|
for ( ;; )
|
|
{
|
|
value = get_byte( prop_addr );
|
|
if ( ( value & property_mask ) <= prop )
|
|
break;
|
|
prop_addr = get_next_property( prop_addr );
|
|
}
|
|
|
|
/* If the property id was found, store a new value, otherwise complain */
|
|
|
|
if ( ( value & property_mask ) != prop )
|
|
{
|
|
fatal( "store_property(): No such property" );
|
|
}
|
|
|
|
/* Determine if this is a byte or word sized property */
|
|
|
|
prop_addr++;
|
|
|
|
if ( (h_type <= V3 && !( value & 0xe0 )) || (h_type >= V4 && !( value & 0xc0 )) )
|
|
{
|
|
set_byte( prop_addr, ( zbyte_t ) setvalue );
|
|
}
|
|
else
|
|
{
|
|
set_word( prop_addr, ( zword_t ) setvalue );
|
|
}
|
|
|
|
} /* z_put_prop */
|
|
|
|
/*
|
|
* z_get_next_prop
|
|
*
|
|
* Load the property after the current property. If the current property is zero
|
|
* then load the first property.
|
|
*
|
|
*/
|
|
|
|
void z_get_next_prop( zword_t obj, zword_t prop )
|
|
{
|
|
zword_t prop_addr;
|
|
zbyte_t value;
|
|
|
|
#ifdef STRICTZ
|
|
if ( obj == 0 )
|
|
{
|
|
report_strictz_error( STRZERR_GET_NEXT_PROP, "@get_next_prop called with object 0" );
|
|
store_operand( 0 );
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
/* Load address of first property */
|
|
prop_addr = get_property_addr( obj );
|
|
|
|
/* If the property id is non zero then find the next property */
|
|
if ( prop != 0 )
|
|
{
|
|
/* Scan down the property list while the target property id is less
|
|
* than the property id in the list */
|
|
do
|
|
{
|
|
value = get_byte( prop_addr );
|
|
prop_addr = get_next_property( prop_addr );
|
|
}
|
|
while ( ( zbyte_t ) ( value & property_mask ) > ( zbyte_t ) prop );
|
|
|
|
/* If the property id wasn't found then complain */
|
|
if ( ( zbyte_t ) ( value & property_mask ) != ( zbyte_t ) prop )
|
|
{
|
|
fatal( "load_next_property(): No such property" );
|
|
}
|
|
}
|
|
|
|
/* Return the next property id */
|
|
value = get_byte( prop_addr );
|
|
store_operand( ( zword_t ) ( value & property_mask ) );
|
|
|
|
} /* z_get_next_prop */
|
|
|
|
/*
|
|
* z_get_prop_addr
|
|
*
|
|
* Load the address address of the data associated with a property.
|
|
*
|
|
*/
|
|
|
|
void z_get_prop_addr( zword_t obj, zword_t prop )
|
|
{
|
|
zword_t prop_addr;
|
|
zbyte_t value;
|
|
|
|
#ifdef STRICTZ
|
|
if ( obj == 0 )
|
|
{
|
|
report_strictz_error( STRZERR_GET_PROP_ADDR, "@get_prop_addr called with object 0" );
|
|
store_operand( 0 );
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
/* Load address of first property */
|
|
prop_addr = get_property_addr( obj );
|
|
|
|
/* Scan down the property list */
|
|
for ( ;; )
|
|
{
|
|
value = get_byte( prop_addr );
|
|
if ( ( zbyte_t ) ( value & property_mask ) <= ( zbyte_t ) prop )
|
|
break;
|
|
prop_addr = get_next_property( prop_addr );
|
|
}
|
|
|
|
/* If the property id was found, calc the prop addr, else return zero */
|
|
|
|
if ( ( zbyte_t ) ( value & property_mask ) == ( zbyte_t ) prop )
|
|
{
|
|
/* Skip past property id, can be a byte or a word */
|
|
|
|
if ( h_type >= V4 && ( value & 0x80 ) )
|
|
{
|
|
prop_addr++;
|
|
}
|
|
store_operand( ( zword_t ) ( prop_addr + 1 ) );
|
|
}
|
|
else
|
|
{
|
|
/* No property found, just return 0 */
|
|
store_operand( 0 );
|
|
}
|
|
|
|
} /* z_get_prop_addr */
|
|
|
|
/*
|
|
* z_get_prop_len
|
|
*
|
|
* Load the length of a property.
|
|
*
|
|
*/
|
|
|
|
void z_get_prop_len( zword_t prop_addr )
|
|
{
|
|
zbyte_t value;
|
|
|
|
/* This is proper according to an email to the Zmachine list by Graham*/
|
|
if ( prop_addr == 0 )
|
|
{
|
|
store_operand( ( zword_t ) 0 );
|
|
return;
|
|
}
|
|
|
|
/* Back up the property pointer to the property id */
|
|
prop_addr--;
|
|
value = get_byte( prop_addr );
|
|
|
|
if ( h_type <= V3 )
|
|
{
|
|
value = ( zbyte_t ) ( ( value >> ( zbyte_t ) 5 ) + ( zbyte_t ) 1 );
|
|
}
|
|
else if ( !( value & 0x80 ) )
|
|
{
|
|
value = ( zbyte_t ) ( ( value >> ( zbyte_t ) 6 ) + ( zbyte_t ) 1 );
|
|
}
|
|
else
|
|
{
|
|
value &= ( zbyte_t ) property_size_mask;
|
|
|
|
if ( value == 0 )
|
|
value = ( zbyte_t ) 64; /* spec 1.0 */
|
|
}
|
|
|
|
store_operand( value );
|
|
|
|
} /* z_get_prop_len */
|
|
|
|
/*
|
|
* z_scan_table
|
|
*
|
|
* Scan an array of bytes or words looking for a target byte or word. The
|
|
* optional 4th parameter can set the address step and also whether to scan a
|
|
* byte array.
|
|
*
|
|
*/
|
|
|
|
void z_scan_table( int argc, zword_t * argv )
|
|
{
|
|
unsigned long address;
|
|
unsigned int i, step;
|
|
|
|
/* Supply default parameters */
|
|
|
|
if ( argc < 4 )
|
|
argv[3] = 0x82;
|
|
|
|
address = argv[1];
|
|
step = argv[3];
|
|
|
|
/* Check size bit (bit 7 of step, 1 = word, 0 = byte) */
|
|
|
|
if ( step & 0x80 )
|
|
{
|
|
|
|
step &= 0x7f;
|
|
|
|
/* Scan down an array for count words looking for a match */
|
|
|
|
for ( i = 0; i < argv[2]; i++ )
|
|
{
|
|
|
|
/* If the word was found store its address and jump */
|
|
|
|
if ( read_data_word( &address ) == argv[0] )
|
|
{
|
|
store_operand( ( zword_t ) ( address - 2 ) );
|
|
conditional_jump( TRUE );
|
|
return;
|
|
}
|
|
|
|
/* Back up address then step by increment */
|
|
|
|
address = ( address - 2 ) + step;
|
|
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
|
|
step &= 0x7f;
|
|
|
|
/* Scan down an array for count bytes looking for a match */
|
|
|
|
for ( i = 0; i < argv[2]; i++ )
|
|
{
|
|
|
|
/* If the byte was found store its address and jump */
|
|
|
|
if ( ( zword_t ) read_data_byte( &address ) == ( zword_t ) argv[0] )
|
|
{
|
|
store_operand( ( zword_t ) ( address - 1 ) );
|
|
conditional_jump( TRUE );
|
|
return;
|
|
}
|
|
|
|
/* Back up address then step by increment */
|
|
|
|
address = ( address - 1 ) + step;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* If the data was not found store zero and jump */
|
|
|
|
store_operand( 0 );
|
|
conditional_jump( FALSE );
|
|
|
|
} /* z_scan_table */
|
|
|
|
/*
|
|
* z_copy_table
|
|
*
|
|
*/
|
|
|
|
void z_copy_table( zword_t src, zword_t dst, zword_t count )
|
|
{
|
|
unsigned long address;
|
|
unsigned int i;
|
|
|
|
/* Catch no-op move case */
|
|
|
|
if ( src == dst || count == 0 )
|
|
return;
|
|
|
|
/* If destination address is zero then fill source with zeros */
|
|
|
|
if ( dst == 0 )
|
|
{
|
|
for ( i = 0; i < count; i++ )
|
|
z_storeb( src++, 0, 0 );
|
|
return;
|
|
}
|
|
|
|
address = src;
|
|
|
|
if ( ( ZINT16 ) count < 0 )
|
|
{
|
|
while ( count++ )
|
|
z_storeb( dst++, 0, read_data_byte( &address ) );
|
|
}
|
|
else
|
|
{
|
|
address += ( unsigned long ) count;
|
|
dst += count;
|
|
while ( count-- )
|
|
{
|
|
address--;
|
|
z_storeb( --dst, 0, read_data_byte( &address ) );
|
|
address--;
|
|
}
|
|
}
|
|
|
|
} /* z_copy_table */
|
|
|
|
/*
|
|
* z_loadw
|
|
*
|
|
* Load a word from an array of words
|
|
*
|
|
*/
|
|
|
|
void z_loadw( zword_t addr, zword_t offset )
|
|
{
|
|
unsigned long address;
|
|
|
|
/* Calculate word array index address */
|
|
|
|
address = addr + ( offset * 2 );
|
|
|
|
/* Store the byte */
|
|
|
|
store_operand( read_data_word( &address ) );
|
|
|
|
} /* z_loadw */
|
|
|
|
/*
|
|
* z_loadb
|
|
*
|
|
* Load a byte from an array of bytes
|
|
*
|
|
*/
|
|
|
|
void z_loadb( zword_t addr, zword_t offset )
|
|
{
|
|
unsigned long address;
|
|
|
|
/* Calculate byte array index address */
|
|
|
|
address = addr + offset;
|
|
|
|
/* Load the byte */
|
|
|
|
store_operand( read_data_byte( &address ) );
|
|
|
|
} /* z_loadb */
|
|
|
|
/*
|
|
* z_storew
|
|
*
|
|
* Store a word in an array of words
|
|
*
|
|
*/
|
|
|
|
void z_storew( zword_t addr, zword_t offset, zword_t value )
|
|
{
|
|
|
|
/* Calculate word array index address */
|
|
|
|
addr += offset * 2;
|
|
|
|
/* Check we are not writing outside of the writeable data area */
|
|
|
|
if ( addr > data_size )
|
|
fatal( "z_storew(): Attempted write outside of data area" );
|
|
|
|
/* Store the word */
|
|
|
|
set_word( addr, value );
|
|
|
|
} /* z_storew */
|
|
|
|
/*
|
|
* z_storeb
|
|
*
|
|
* Store a byte in an array of bytes
|
|
*
|
|
*/
|
|
|
|
void z_storeb( zword_t addr, zword_t offset, zword_t value )
|
|
{
|
|
|
|
/* Calculate byte array index address */
|
|
|
|
addr += offset;
|
|
|
|
/* Check we are not writing outside of the writeable data area */
|
|
|
|
if ( addr > data_size )
|
|
fatal( "z_storeb(): Attempted write outside of data area" );
|
|
|
|
/* Store the byte */
|
|
|
|
set_byte( addr, value );
|
|
|
|
} /* z_storeb */
|