ifengine/interpre.c
2018-09-08 19:51:49 -05:00

483 lines
10 KiB
C

/* $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 */