/* * 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 */ /* * load_property * * 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 load_property (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 ); }/* load_property */ /* * store_property * * Store a property value in a property list. The property must exist in the * property list to be replaced. * */ void store_property (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 ); } }/* store_property */ /* * load_next_property * * Load the property after the current property. If the current property is zero * then load the first property. * */ void load_next_property (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) ); }/* load_next_property */ /* * load_property_address * * Load the address address of the data associated with a property. * */ void load_property_address (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 ); } }/* load_property_address */ /* * load_property_length * * Load the length of a property. * */ void load_property_length (zword_t prop_addr) { zbyte_t value; 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 ); }/* load_property_length */ /* * scan_data * * 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 scan_data (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); }/* scan_data */ /* * move_data * */ void move_data (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++) store_byte (src++, 0, 0); return; } address = src; if ((ZINT16) count < 0) { while (count++) store_byte (dst++, 0, read_data_byte (&address)); } else { address += (unsigned long) count; dst += count; while (count--) { address--; store_byte (--dst, 0, read_data_byte (&address)); address--; } } }/* move_data */ /* * load_word * * Load a word from an array of words * */ void load_word (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)); }/* load_word */ /* * load_byte * * Load a byte from an array of bytes * */ void load_byte (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)); }/* load_byte */ /* * store_word * * Store a word in an array of words * */ void store_word (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 ("store_word(): Attempted write outside of data area"); /* Store the word */ set_word (addr, value); }/* store_word */ /* * store_byte * * Store a byte in an array of bytes * */ void store_byte (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 ("store_byte(): Attempted write outside of data area"); /* Store the byte */ set_byte (addr, value); }/* store_byte */