415 lines
10 KiB
C
415 lines
10 KiB
C
/*
|
|
|
|
ugl_bc.c
|
|
|
|
items can be at three places
|
|
1) map
|
|
2) inventory
|
|
3) hero
|
|
|
|
map --> inventory take
|
|
inventory --> map drop
|
|
inventory --> hero equip
|
|
hero --> inventory unequip
|
|
hero --> map drop
|
|
|
|
|
|
inputs:
|
|
hDir() // direction into which the hero wants to walk, had waked or looks
|
|
iDir() // direction into which the item/creatue/missel wants to go, went or looks
|
|
hX() // hero X position
|
|
hY() // hero Y position
|
|
posByH // set current position to the position of the hero
|
|
posByI // set current position to the position of the current item
|
|
posAppyDir(dir) // change the possition going one step into the specified direction
|
|
|
|
*/
|
|
|
|
#include "ugl_bc.h"
|
|
#include <stdio.h>
|
|
#include <assert.h>
|
|
|
|
#ifndef UGL_TEST
|
|
#include "item.h"
|
|
#include "map.h"
|
|
#endif
|
|
|
|
|
|
|
|
void bc_push_on_arg_stack(bc_t *bc, uint16_t val)
|
|
{
|
|
bc->arg_stack[bc->arg_stack_pointer] = val;
|
|
bc->arg_stack_pointer++;
|
|
}
|
|
|
|
uint16_t bc_pop_from_arg_stack(bc_t *bc)
|
|
{
|
|
assert( bc->arg_stack_pointer > 0 );
|
|
bc->arg_stack_pointer--;
|
|
return bc->arg_stack[bc->arg_stack_pointer] ;
|
|
}
|
|
|
|
void bc_duplicate_arg_stack_top_value(bc_t *bc)
|
|
{
|
|
bc->arg_stack[bc->arg_stack_pointer] = bc->arg_stack[bc->arg_stack_pointer-1];
|
|
bc->arg_stack_pointer++;
|
|
}
|
|
|
|
void bc_push_on_return_stack(bc_t *bc, uint16_t val)
|
|
{
|
|
bc->return_stack[bc->return_stack_pointer] = val;
|
|
bc->return_stack_pointer++;
|
|
}
|
|
|
|
uint16_t bc_pop_from_return_stack(bc_t *bc)
|
|
{
|
|
assert( bc->return_stack_pointer > 0 );
|
|
bc->return_stack_pointer--;
|
|
return bc->return_stack[bc->return_stack_pointer];
|
|
}
|
|
|
|
|
|
uint16_t bc_get_value(uint8_t *code)
|
|
{
|
|
uint16_t val;
|
|
val = *code;
|
|
code++;
|
|
val <<= 8;
|
|
val |= *code;
|
|
code++;
|
|
return val;
|
|
}
|
|
|
|
void bc_init(bc_t *bc)
|
|
{
|
|
bc->arg_stack_pointer = 0;
|
|
bc->return_stack_pointer = 0;
|
|
}
|
|
|
|
#define BC_DBG_OUT_POS(pos) printf("%05d ", (int)(pos))
|
|
#define BC_DBG_OUT_HEX(c) printf("0x%02x ", (int)(c))
|
|
#define BC_DBG_OUT_STR(str) printf("%s ", (str))
|
|
#define BC_DBG_OUT_NUM(n) printf("%d ", (int)(n))
|
|
#define BC_DBG_OUT_NUM3(n) printf("%03d ", (int)(n))
|
|
#define BC_DBG_OUT_CR() printf("\n")
|
|
|
|
void bc_exec(bc_t *bc, uint8_t *code, uint16_t pos)
|
|
{
|
|
uint16_t val;
|
|
uint8_t cmd;
|
|
|
|
bc_init(bc);
|
|
bc->code = code;
|
|
bc->code_pos = pos;
|
|
|
|
for(;;)
|
|
{
|
|
cmd = bc->code[bc->code_pos];
|
|
BC_DBG_OUT_POS(bc->code_pos);
|
|
BC_DBG_OUT_NUM3(bc->arg_stack_pointer);
|
|
BC_DBG_OUT_HEX(cmd);
|
|
bc->code_pos++;
|
|
val = cmd;
|
|
val &=0x0f0; /* put upper four bit as upper 4bit of the 12bit value into val */
|
|
val <<= 4;
|
|
switch(cmd&15)
|
|
{
|
|
case BC_CMD_LOAD_12BIT:
|
|
BC_DBG_OUT_STR("LOAD12");
|
|
val |= bc->code[bc->code_pos];
|
|
BC_DBG_OUT_NUM(val);
|
|
bc->code_pos++;
|
|
bc_push_on_arg_stack(bc, val);
|
|
BC_DBG_OUT_CR();
|
|
break;
|
|
case BC_CMD_CALL_BUILDIN:
|
|
BC_DBG_OUT_STR("CALL BUILDIN");
|
|
val |= bc->code[bc->code_pos];
|
|
BC_DBG_OUT_NUM(val);
|
|
bc->code_pos++;
|
|
BC_DBG_OUT_CR();
|
|
bc_buildin_list[val](bc);
|
|
break;
|
|
case BC_CMD_CALL_BUILDIN_POP_STACK:
|
|
BC_DBG_OUT_STR("CALL BUILDIN POP ARG STACK");
|
|
val |= bc->code[bc->code_pos];
|
|
BC_DBG_OUT_NUM(val);
|
|
bc->code_pos++;
|
|
BC_DBG_OUT_CR();
|
|
bc_buildin_list[val](bc);
|
|
bc_pop_from_arg_stack(bc);
|
|
break;
|
|
case BC_CMD_BRANCH:
|
|
BC_DBG_OUT_STR("BRANCH");
|
|
val |= bc->code[bc->code_pos];
|
|
bc->code_pos++;
|
|
if ( val < 0x0800 )
|
|
{
|
|
bc->code_pos += val;
|
|
}
|
|
else
|
|
{
|
|
val = 0x1000 - val;
|
|
bc->code_pos -= val;
|
|
}
|
|
BC_DBG_OUT_POS(bc->code_pos);
|
|
BC_DBG_OUT_CR();
|
|
case BC_CMD_POP_ARG_STACK:
|
|
cmd >>= 4; /* in this case we need the lower 4 bit */
|
|
BC_DBG_OUT_STR("POP ARG STACK");
|
|
cmd++; /* cmd is reused as a counter for the number of stack pops */
|
|
BC_DBG_OUT_NUM(cmd);
|
|
do
|
|
{
|
|
bc_pop_from_arg_stack(bc);
|
|
cmd--;
|
|
} while( cmd > 0 );
|
|
BC_DBG_OUT_CR();
|
|
break;
|
|
case BC_CMD_PUSH_ARG_STACK:
|
|
cmd >>= 4; /* in this case we need the lower 4 bit */
|
|
BC_DBG_OUT_STR("PUSH ARG STACK");
|
|
cmd++; /* cmd is reused as a counter for the number of stack pops */
|
|
BC_DBG_OUT_NUM(cmd);
|
|
do
|
|
{
|
|
bc_push_on_arg_stack(bc, 0);
|
|
cmd--;
|
|
} while( cmd > 0 );
|
|
BC_DBG_OUT_CR();
|
|
break;
|
|
case BC_CMD_CALL_PROCEDURE:
|
|
BC_DBG_OUT_STR("CALL PROC");
|
|
cmd >>= 4; /* in this case we need the lower 4 bit--> number of args */
|
|
BC_DBG_OUT_NUM(cmd); /* output number of args */
|
|
|
|
val = bc->code[bc->code_pos];
|
|
bc->code_pos++;
|
|
val <<= 8;
|
|
val |= bc->code[bc->code_pos];
|
|
bc->code_pos++;
|
|
|
|
bc_push_on_return_stack(bc, bc->code_pos); /* return position */
|
|
bc_push_on_return_stack(bc, bc->arg_stack_pointer - cmd -1); /* store the start pos of the return value and the args */
|
|
bc->code_pos = val;
|
|
BC_DBG_OUT_NUM(bc->code_pos);
|
|
BC_DBG_OUT_CR();
|
|
|
|
break;
|
|
default: /* assume 0x0f, extended command */
|
|
switch( cmd )
|
|
{
|
|
case BC_CMD_LOAD_0:
|
|
BC_DBG_OUT_STR("LOAD#0");
|
|
bc_push_on_arg_stack(bc, 0);
|
|
BC_DBG_OUT_CR();
|
|
break;
|
|
case BC_CMD_LOAD_1:
|
|
BC_DBG_OUT_STR("LOAD#1");
|
|
bc_push_on_arg_stack(bc, 1);
|
|
BC_DBG_OUT_CR();
|
|
break;
|
|
case BC_CMD_LOAD_16BIT:
|
|
BC_DBG_OUT_STR("LOAD16");
|
|
val = bc->code[bc->code_pos];
|
|
bc->code_pos++;
|
|
val <<= 8;
|
|
val |= bc->code[bc->code_pos];
|
|
bc->code_pos++;
|
|
bc_push_on_arg_stack(bc, val);
|
|
BC_DBG_OUT_NUM(val);
|
|
BC_DBG_OUT_CR();
|
|
break;
|
|
case BC_CMD_RETURN_FROM_PROCEDURE:
|
|
BC_DBG_OUT_STR("RETURN to");
|
|
if ( bc->return_stack_pointer == 0 )
|
|
{
|
|
BC_DBG_OUT_STR("exit");
|
|
BC_DBG_OUT_CR();
|
|
|
|
BC_DBG_OUT_STR("arg stack: ");
|
|
BC_DBG_OUT_NUM(bc->arg_stack_pointer);
|
|
BC_DBG_OUT_CR();
|
|
BC_DBG_OUT_STR("return stack: ");
|
|
BC_DBG_OUT_NUM(bc->return_stack_pointer);
|
|
BC_DBG_OUT_CR();
|
|
return; /* stop execution */
|
|
}
|
|
//bc_push_on_arg_stack(bc, bc_pop_from_return_stack(bc)); /* copy return value on arg stack */
|
|
bc->arg_stack_pointer = bc_pop_from_return_stack(bc) + 1; /* restore the arg stack pointer, leave return value on stack */
|
|
bc->code_pos = bc_pop_from_return_stack(bc);
|
|
BC_DBG_OUT_NUM(bc->code_pos);
|
|
BC_DBG_OUT_CR();
|
|
break;
|
|
case BC_CMD_JUMP_NOT_ZERO:
|
|
BC_DBG_OUT_STR("JUMP NZ");
|
|
val = bc->code[bc->code_pos];
|
|
bc->code_pos++;
|
|
val <<= 8;
|
|
val |= bc->code[bc->code_pos];
|
|
bc->code_pos++;
|
|
|
|
if ( bc_pop_from_arg_stack(bc) != 0 )
|
|
bc->code_pos = val;
|
|
break;
|
|
BC_DBG_OUT_NUM(bc->code_pos);
|
|
BC_DBG_OUT_CR();
|
|
case BC_CMD_JUMP_ZERO:
|
|
BC_DBG_OUT_STR("JUMP Z");
|
|
val = bc->code[bc->code_pos];
|
|
bc->code_pos++;
|
|
val <<= 8;
|
|
val |= bc->code[bc->code_pos];
|
|
bc->code_pos++;
|
|
|
|
if ( bc_pop_from_arg_stack(bc) == 0 )
|
|
bc->code_pos = val;
|
|
BC_DBG_OUT_NUM(bc->code_pos);
|
|
BC_DBG_OUT_CR();
|
|
break;
|
|
case BC_CMD_CALL_PROCEDURE:
|
|
BC_DBG_OUT_STR("CALL PROC");
|
|
val = bc->code[bc->code_pos];
|
|
bc->code_pos++;
|
|
val <<= 8;
|
|
val |= bc->code[bc->code_pos];
|
|
bc->code_pos++;
|
|
|
|
bc_push_on_return_stack(bc, bc->code_pos); /* return position */
|
|
bc_push_on_return_stack(bc, 0); /* return value */
|
|
bc->code_pos = val;
|
|
BC_DBG_OUT_NUM(bc->code_pos);
|
|
BC_DBG_OUT_CR();
|
|
|
|
break;
|
|
/*
|
|
case BC_CMD_POP_ARG_STACK:
|
|
BC_DBG_OUT_STR("POP ARG STACK");
|
|
BC_DBG_OUT_CR();
|
|
bc_pop_from_arg_stack(bc);
|
|
break;
|
|
*/
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
} /* switch() */
|
|
} /* for(;;) */
|
|
|
|
}
|
|
|
|
|
|
/*======================================================*/
|
|
|
|
/* put top of stack into register a, reduce stack */
|
|
//void bc_pop_a(bc_t *bc)
|
|
//{
|
|
// bc->stack_pointer--;
|
|
// bc->a = bc->stack[bc->stack_pointer];
|
|
//}
|
|
|
|
/*======================================================*/
|
|
|
|
/* return a pointer to a variable on the arg stack within the current stack frame */
|
|
/* pos = 0 is the return value of a user function, pos = 1... are the args for that function */
|
|
uint16_t *bc_get_stack_frame_address(bc_t *bc, uint8_t pos)
|
|
{
|
|
return bc->arg_stack + bc->return_stack[bc->return_stack_pointer-1] + pos ;
|
|
}
|
|
|
|
void bc_fn_nop(bc_t *bc)
|
|
{
|
|
bc_push_on_arg_stack(bc, 0);
|
|
}
|
|
|
|
/* description: "return" sets the return value of a procedure. If used inside an expresion, it returns its argument */
|
|
/* assign return value for a user defined function */
|
|
/* identical to arg(0) */
|
|
void bc_fn_return(bc_t *bc)
|
|
{
|
|
bc_duplicate_arg_stack_top_value(bc); /* goal is to leave a value on the stack */
|
|
*bc_get_stack_frame_address(bc, 0) = bc_pop_from_arg_stack(bc);
|
|
|
|
/*
|
|
v = bc_pop_from_arg_stack(bc);
|
|
bc_push_on_arg_stack(bc, v);
|
|
bc_pop_from_return_stack(bc);
|
|
bc_push_on_return_stack(bc, v);
|
|
*/
|
|
}
|
|
|
|
|
|
|
|
void bc_fn_print(bc_t *bc)
|
|
{
|
|
bc_duplicate_arg_stack_top_value(bc); /* goal is to leave a value on the stack */
|
|
printf("%u\n", bc_pop_from_arg_stack(bc));
|
|
}
|
|
|
|
/* return an argument of a user defined procedure */
|
|
void bc_fn_arg1(bc_t *bc)
|
|
{
|
|
bc_push_on_arg_stack(bc, *bc_get_stack_frame_address(bc, bc_pop_from_arg_stack(bc)));
|
|
}
|
|
|
|
/* remove the top element from the stack and return the same */
|
|
void bc_fn_arg2(bc_t *bc)
|
|
{
|
|
uint16_t v = bc_pop_from_arg_stack(bc); /* the value, which should be assigned */
|
|
*bc_get_stack_frame_address(bc, bc_pop_from_arg_stack(bc)) = v;
|
|
bc_push_on_arg_stack(bc, v); /* push the value back on the stack */
|
|
}
|
|
|
|
|
|
|
|
void bc_fn_add(bc_t *bc)
|
|
{
|
|
uint16_t v;
|
|
v = bc_pop_from_arg_stack(bc);
|
|
v += bc_pop_from_arg_stack(bc);
|
|
bc_push_on_arg_stack(bc, v);
|
|
}
|
|
|
|
#ifndef UGL_TEST
|
|
pos_t bc_pos;
|
|
#endif
|
|
|
|
void bc_fn_setPos(bc_t *bc)
|
|
{
|
|
uint8_t x, y;
|
|
y = bc_pop_from_arg_stack(bc);
|
|
x = bc_pop_from_arg_stack(bc);
|
|
#ifndef UGL_TEST
|
|
bc_pos.x = x;
|
|
bc_pos.y = y;
|
|
#endif
|
|
bc_push_on_arg_stack(bc, 0);
|
|
}
|
|
|
|
void bc_fn_setItemPos(bc_t *bc)
|
|
{
|
|
uint8_t i;
|
|
i = bc_pop_from_arg_stack(bc);
|
|
#ifndef UGL_TEST
|
|
pool_GetItem(i)->pos = bc_pos;
|
|
printf("item %d new x=%d y=%d\n", i, bc_pos.x, bc_pos.y);
|
|
#endif
|
|
bc_push_on_arg_stack(bc, i);
|
|
}
|
|
|
|
|
|
/*======================================================*/
|
|
bc_buildin_fn bc_buildin_list[] =
|
|
{
|
|
/* 0 */ bc_fn_nop,
|
|
/* 1 */ bc_fn_return,
|
|
/* 2 */ bc_fn_arg1, /* one argument */
|
|
/* 3 */ bc_fn_arg2, /* two arguments */
|
|
/* 4 */ bc_fn_add,
|
|
/* 5 */ bc_fn_print,
|
|
/* 6 */ bc_fn_setPos, /* two args: x & y*/
|
|
/* 7 */ bc_fn_setItemPos, /* one args: item */
|
|
};
|
|
|
|
|