/* $Id: interpre.c,v 1.3 2000/07/05 15:20:34 jholder Exp $ * -------------------------------------------------------------------- * see doc/License.txt for License Information * -------------------------------------------------------------------- * * File name: $Id: interpre.c,v 1.3 2000/07/05 15:20:34 jholder Exp $ * * Description: * * Modification history: * $Log: interpre.c,v $ * Revision 1.3 2000/07/05 15:20:34 jholder * Updated code to remove warnings. * * 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 * * * -------------------------------------------------------------------- */ /* * interpre.c * * Main interpreter loop * */ #include "ztypes.h" /*#define DEBUG_TERPRE*/ static int halt = FALSE; /* * interpret * * Interpret Z code * */ int interpret( void ) { zbyte_t opcode; zword_t specifier; zword_t operand[8]; int maxoperands; int count; int extend; int i; interpreter_status = 1; /* Loop until HALT instruction executed */ for ( interpreter_state = RUN; interpreter_state == RUN && halt == FALSE; ) { /* Load opcode and set operand count */ opcode = read_code_byte( ); if ( h_type > V4 && opcode == 0xbe ) { opcode = read_code_byte( ); extend = TRUE; } else extend = FALSE; count = 0; /* Multiple operand instructions */ if ( ( opcode < 0x80 || opcode > 0xc0 ) || extend == TRUE ) { /* Two operand class, load both operands */ if ( opcode < 0x80 && extend == FALSE ) { operand[count++] = load_operand( ( opcode & 0x40 ) ? 2 : 1 ); operand[count++] = load_operand( ( opcode & 0x20 ) ? 2 : 1 ); opcode &= 0x1f; } else { /* Variable operand class, load operand specifier */ opcode &= 0x3f; if ( opcode == 0x2c || opcode == 0x3a ) { /* Extended CALL instruction */ specifier = read_code_word( ); maxoperands = 8; } else { specifier = read_code_byte( ); maxoperands = 4; } /* Load operands */ for ( i = ( maxoperands - 1 ) * 2; i >= 0; i -= 2 ) if ( ( ( specifier >> i ) & 0x03 ) != 3 ) operand[count++] = load_operand( ( specifier >> i ) & 0x03 ); else i = 0; } if ( extend == TRUE ) { #ifdef DEBUG_TERPRE fprintf( stderr, "PC = 0x%08lx Op%s = 0x%02x %d, %d, %d\n", pc, "(EX)", opcode, operand[0], operand[1], operand[2] ); #endif switch ( ( char ) opcode ) { /* Extended operand instructions */ case 0x00: z_save( count, operand[0], operand[1], operand[2] ); break; case 0x01: z_restore( count, operand[0], operand[1], operand[2] ); break; case 0x02: z_log_shift( operand[0], operand[1] ); break; case 0x03: z_art_shift( operand[0], operand[1] ); break; case 0x04: z_set_font( operand[0] ); break; case 0x09: z_save_undo( ); break; case 0x0a: z_restore_undo( ); break; default: fatal( "interpret(): Illegal extended operand instruction" ); } } else { #ifdef DEBUG_TERPRE fprintf( stderr, "PC = 0x%08lx Op%s = 0x%02x %d, %d, %d\n", pc, "(2+)", opcode, operand[0], operand[1], operand[2] ); #endif switch ( ( char ) opcode ) { /* Two or multiple operand instructions */ case 0x01: z_je( count, operand ); break; case 0x02: z_jl( operand[0], operand[1] ); break; case 0x03: z_jg( operand[0], operand[1] ); break; case 0x04: z_dec_chk( operand[0], operand[1] ); break; case 0x05: z_inc_chk( operand[0], operand[1] ); break; case 0x06: z_jin( operand[0], operand[1] ); break; case 0x07: z_test( operand[0], operand[1] ); break; case 0x08: z_or( operand[0], operand[1] ); break; case 0x09: z_and( operand[0], operand[1] ); break; case 0x0a: z_test_attr( operand[0], operand[1] ); break; case 0x0b: z_set_attr( operand[0], operand[1] ); break; case 0x0c: z_clear_attr( operand[0], operand[1] ); break; case 0x0d: z_store( operand[0], operand[1] ); break; case 0x0e: z_insert_obj( operand[0], operand[1] ); break; case 0x0f: z_loadw( operand[0], operand[1] ); break; case 0x10: z_loadb( operand[0], operand[1] ); break; case 0x11: z_get_prop( operand[0], operand[1] ); break; case 0x12: z_get_prop_addr( operand[0], operand[1] ); break; case 0x13: z_get_next_prop( operand[0], operand[1] ); break; case 0x14: z_add( operand[0], operand[1] ); break; case 0x15: z_sub( operand[0], operand[1] ); break; case 0x16: z_mul( operand[0], operand[1] ); break; case 0x17: z_div( operand[0], operand[1] ); break; case 0x18: z_mod( operand[0], operand[1] ); break; case 0x19: z_call( count, operand, FUNCTION ); break; case 0x1a: z_call( count, operand, PROCEDURE ); break; case 0x1b: z_set_colour( operand[0], operand[1] ); break; case 0x1c: z_throw( operand[0], operand[1] ); break; /* Multiple operand instructions */ case 0x20: z_call( count, operand, FUNCTION ); break; case 0x21: z_storew( operand[0], operand[1], operand[2] ); break; case 0x22: z_storeb( operand[0], operand[1], operand[2] ); break; case 0x23: z_put_prop( operand[0], operand[1], operand[2] ); break; case 0x24: z_sread_aread( count, operand ); break; case 0x25: z_print_char( operand[0] ); break; case 0x26: z_print_num( operand[0] ); break; case 0x27: z_random( operand[0] ); break; case 0x28: z_push( operand[0] ); break; case 0x29: z_pull( operand[0] ); break; case 0x2a: z_split_window( operand[0] ); break; case 0x2b: z_set_window( operand[0] ); break; case 0x2c: z_call( count, operand, FUNCTION ); break; case 0x2d: z_erase_window( operand[0] ); break; case 0x2e: z_erase_line( operand[0] ); break; case 0x2f: z_set_cursor( operand[0], operand[1] ); break; case 0x31: z_set_text_style( operand[0] ); break; case 0x32: z_buffer_mode( operand[0] ); break; case 0x33: z_output_stream( operand[0], operand[1] ); break; case 0x34: z_input_stream( operand[0] ); break; case 0x35: sound( count, operand ); break; case 0x36: z_read_char( count, operand ); break; case 0x37: z_scan_table( count, operand ); break; case 0x38: z_not( operand[0] ); break; case 0x39: z_call( count, operand, PROCEDURE ); break; case 0x3a: z_call( count, operand, PROCEDURE ); break; case 0x3b: z_tokenise( count, operand ); break; case 0x3c: z_encode( operand[0], operand[1], operand[2], operand[3] ); break; case 0x3d: z_copy_table( operand[0], operand[1], operand[2] ); break; case 0x3e: z_print_table( count, operand ); break; case 0x3f: z_check_arg_count( operand[0] ); break; default: fatal( "interpret(): Illegal 2 or more operand instruction" ); } } } else { /* Single operand class, load operand and execute instruction */ if ( opcode < 0xb0 ) { operand[0] = load_operand( ( opcode >> 4 ) & 0x03 ); #ifdef DEBUG_TERPRE fprintf( stderr, "PC = 0x%08lx Op%s = 0x%02x %d\n", pc, "(1 )", opcode, operand[0] ); #endif switch ( ( char ) opcode & 0x0f ) { case 0x00: z_jz( operand[0] ); break; case 0x01: z_get_sibling( operand[0] ); break; case 0x02: z_get_child( operand[0] ); break; case 0x03: z_get_parent( operand[0] ); break; case 0x04: z_get_prop_len( operand[0] ); break; case 0x05: z_inc( operand[0] ); break; case 0x06: z_dec( operand[0] ); break; case 0x07: z_print_addr( operand[0] ); break; case 0x08: z_call( 1, operand, FUNCTION ); break; case 0x09: z_remove_obj( operand[0] ); break; case 0x0a: z_print_obj( operand[0] ); break; case 0x0b: z_ret( operand[0] ); break; case 0x0c: z_jump( operand[0] ); break; case 0x0d: z_print_paddr( operand[0] ); break; case 0x0e: z_load( operand[0] ); break; case 0x0f: if ( h_type > V4 ) z_call( 1, operand, PROCEDURE ); else z_not( operand[0] ); break; } } else { /* Zero operand class, execute instruction */ #ifdef DEBUG_TERPRE fprintf( stderr, "PC = 0x%08lx Op%s = 0x%02x\n", pc, "(0 )", opcode ); #endif switch ( ( char ) opcode & 0x0f ) { case 0x00: z_ret( TRUE ); break; case 0x01: z_ret( FALSE ); break; case 0x02: z_print( ); break; case 0x03: z_print_ret( ); break; case 0x04: /* z_nop */ break; case 0x05: z_save( 0, 0, 0, 0 ); break; case 0x06: z_restore( 0, 0, 0, 0 ); break; case 0x07: z_restart( ); break; case 0x08: z_ret( stack[sp++] ); break; case 0x09: z_catch( ); break; case 0x0a: halt = TRUE; /* z_quit */ break; case 0x0b: z_new_line( ); break; case 0x0c: z_show_status( ); break; case 0x0d: z_verify( ); break; case 0x0f: z_piracy( TRUE ); break; default: fatal( "interpret(): Illegal zero operand instruction" ); } } } } return ( interpreter_status ); } /* interpret */