270 lines
7.7 KiB
C
Executable File
270 lines
7.7 KiB
C
Executable File
#include "asm.h"
|
|
|
|
//BEGIN Internal functions prototypes
|
|
void decodeOpcode(asm_t *state, opcode_t *opcode, opcode_data_t *data);
|
|
void execute(asm_t *state, opcode_data_t *instruction, opcode_t *raw);
|
|
//END Internal functions prototypes
|
|
|
|
|
|
int run(asm_t *state, int cycles) {
|
|
int i=0;
|
|
state->status|=ASM_RUNNING;
|
|
for(; i<cycles; i++) {
|
|
if(state->status&ASM_RUNNING) tick(state);
|
|
else break;
|
|
}
|
|
return i;
|
|
}
|
|
|
|
int tick(asm_t *state) {
|
|
opcode_t opcode;
|
|
opcode_data_t data;
|
|
|
|
//read opcode and increment pc
|
|
state->registers[0].i+=readOpcode(state->rom, state->registers[0].i, state->romSize, &opcode);
|
|
|
|
//decode opcode
|
|
decodeOpcode(state, &opcode, &data);
|
|
|
|
//execute instruction
|
|
execute(state, &data, &opcode);
|
|
}
|
|
|
|
void initAsm(asm_t *state) {
|
|
state->stack.top=0;
|
|
for(int i=0; i<256; i++) {
|
|
state->stack.elements[i].i=0;
|
|
state->registers[i].i=0;
|
|
}
|
|
state->status=0;
|
|
}
|
|
|
|
//BEGIN Internal functions
|
|
|
|
//BEGIN opcode reading functions
|
|
void readOpcodeData(asm_t *state, opcode_t *opcode, opcode_data_t *data, int args, int type) {
|
|
if(!args) return;
|
|
|
|
if(opcode->nArgs==0) {
|
|
//no arguments in opcode, pop everything from stack
|
|
popDouble(&state->stack, &(data->arg0.d));
|
|
if(args==2) popDouble(&state->stack, &(data->arg1.d));
|
|
} else if(opcode->nArgs==1) {
|
|
//one argument in opcode, get it from registers
|
|
data->arg0=state->registers[opcode->arg0_1];
|
|
if(args==2) popDouble(&state->stack, &(data->arg1.d));
|
|
} else if(opcode->nArgs==2) {
|
|
//two arguments in opcode, get them from registers
|
|
data->arg0=state->registers[opcode->arg0_2];
|
|
if(args==2) data->arg1=state->registers[opcode->arg1_2];
|
|
} else { //opcode->nArgs==3
|
|
//immediate argument in opcode
|
|
if(!type) {
|
|
//we requested an int, it is directly readable
|
|
data->arg0.i=opcode->immediate;
|
|
} else {
|
|
//we requested a double, it must be decoded
|
|
data->arg0.d=(double) ((opcode->immediate>>4)&0x7ff);
|
|
data->arg0.d*=(2>>((opcode->immediate&0xf)-7));
|
|
if((opcode->immediate)>>15) data->arg0.d*=-1;
|
|
// smmmmmmm mmmmeeee
|
|
// immediate=(-1)^(s+1)*m*2^(e-7)
|
|
}
|
|
if(args==2) popDouble(&state->stack, &(data->arg1.d));
|
|
}
|
|
}
|
|
void decodeOpcode(asm_t *state, opcode_t *opcode, opcode_data_t *data) {
|
|
data->op=opcode->op;
|
|
data->nArgs=opcode->nArgs;
|
|
//read arguments for opcode
|
|
//TODO use a switch instead to handle this
|
|
if((data->op>=OP_add_i && data->op<OP_neg_i)
|
|
|| (data->op>=OP_pow_i && data->op<OP_not)
|
|
|| (data->op>=OP_or_l && data->op<OP_not_l)
|
|
|| (data->op>=OP_jnz_i && data->op<=OP_jind)) {
|
|
//op takes two int arguments
|
|
readOpcodeData(state, opcode, data, 2, 0);
|
|
} else if((data->op>=OP_add_d && data->op<OP_neg_d)
|
|
|| (data->op==OP_pow_d || data->op==OP_rt_d)
|
|
|| (data->op==OP_atan2)) {
|
|
//op takes two double arguments
|
|
readOpcodeData(state, opcode, data, 2, 1);
|
|
} else if((data->op==OP_neg_i)
|
|
|| (data->op==OP_not)
|
|
|| (data->op==OP_not_l)
|
|
|| (data->op==OP_high)
|
|
|| (data->op==OP_push)
|
|
|| (data->op==OP_const)
|
|
|| (data->op==OP_jmp)
|
|
|| (data->op==OP_call)
|
|
|| (data->op==OP_ext)
|
|
|| (data->op==OP_int)) {
|
|
//op takes one int argument
|
|
readOpcodeData(state, opcode, data, 1, 0);
|
|
} else if((data->op==OP_neg_d)
|
|
|| (data->op>=OP_sin && data->op<OP_atan2)
|
|
|| (data->op==OP_dup)) {
|
|
//op takes one double argument
|
|
readOpcodeData(state, opcode, data, 1, 1);
|
|
} else if((data->op>=OP_store && data->op<OP_rea_i)) {
|
|
//store and write instructions
|
|
readOpcodeData(state, opcode, data, 2, 0);
|
|
} else if((data->op==OP_rea_i || data->op==OP_rea_d)) {
|
|
//read instructions
|
|
readOpcodeData(state, opcode, data, 1, 0);
|
|
} else if((data->op==OP_i2d)) {
|
|
//i2d
|
|
readOpcodeData(state, opcode, data, 1, 0);
|
|
} else if((data->op==OP_d2i)) {
|
|
//d2i
|
|
readOpcodeData(state, opcode, data, 1, 1);
|
|
}
|
|
}
|
|
//END opcode reading functions
|
|
|
|
//BEGIN memory access functions
|
|
void readMemoryInt(asm_t *state, int address, int *value) {
|
|
int val;
|
|
if(address<0) return;
|
|
if(address<=0xffff) {
|
|
if(address+4<state->romSize) {
|
|
val=state->rom[address]<<24;
|
|
val|=state->rom[address+1]<<16;
|
|
val|=state->rom[address+2]<<8;
|
|
val|=state->rom[address+3];
|
|
*value=val;
|
|
}
|
|
} else {
|
|
address-=0x10000;
|
|
if(address+4<state->ramSize) {
|
|
val=state->ram[address]<<24;
|
|
val|=state->ram[address+1]<<16;
|
|
val|=state->ram[address+2]<<8;
|
|
val|=state->ram[address+3];
|
|
*value=val;
|
|
}
|
|
}
|
|
}
|
|
void writeMemoryInt(asm_t *state, int address, int value) {
|
|
if(address<=0xffff) return;
|
|
address-=0x10000;
|
|
if(address+4<state->ramSize) {
|
|
state->ram[address]=(char) value>>24;
|
|
state->ram[address+1]=(char) value>>16;
|
|
state->ram[address+2]=(char) value>>8;
|
|
state->ram[address+3]=(char) value;
|
|
}
|
|
}
|
|
//END memory access functions
|
|
|
|
//BEGIN execution functions
|
|
void execute(asm_t *state, opcode_data_t *instruction, opcode_t *raw) {
|
|
stack_element_t temp0, temp1;
|
|
debug("Opcode: 0x%x, nArgs: %d, PC: 0x%x, stack: %d\n", instruction->op, instruction->nArgs, state->registers[0].i, state->stack.top);
|
|
switch(instruction->op) {
|
|
case OP_nop:
|
|
break;
|
|
case OP_halt:
|
|
state->status=0;
|
|
break;
|
|
|
|
//BEGIN arithmetic operations
|
|
case OP_add_i:
|
|
pushInt(&state->stack, instruction->arg0.i+instruction->arg1.i);
|
|
break;
|
|
case OP_sub_i:
|
|
pushInt(&state->stack, instruction->arg0.i-instruction->arg1.i);
|
|
break;
|
|
case OP_mod_i:
|
|
pushInt(&state->stack, instruction->arg0.i%instruction->arg1.i);
|
|
break;
|
|
case OP_mul_i:
|
|
pushInt(&state->stack, instruction->arg0.i*instruction->arg1.i);
|
|
break;
|
|
case OP_div_i:
|
|
pushInt(&state->stack, instruction->arg0.i/instruction->arg1.i);
|
|
break;
|
|
case OP_neg_i:
|
|
pushInt(&state->stack, -instruction->arg0.i);
|
|
break;
|
|
/*case OP_pow_i:
|
|
pushInt(&state->stack, (int) pow((double) instruction->arg0.i, (double) instruction->arg1.i));
|
|
break;*/
|
|
case OP_add_d:
|
|
pushDouble(&state->stack, instruction->arg0.d+instruction->arg1.d);
|
|
break;
|
|
case OP_sub_d:
|
|
pushDouble(&state->stack, instruction->arg0.d-instruction->arg1.d);
|
|
break;
|
|
case OP_mul_d:
|
|
pushDouble(&state->stack, instruction->arg0.d*instruction->arg1.d);
|
|
break;
|
|
case OP_div_d:
|
|
pushDouble(&state->stack, instruction->arg0.d/instruction->arg1.d);
|
|
break;
|
|
case OP_neg_d:
|
|
pushDouble(&state->stack, -instruction->arg0.d);
|
|
break;
|
|
//END arithmetic operations
|
|
|
|
//BEGIN bitwise operations
|
|
case OP_shlt:
|
|
pushInt(&state->stack, instruction->arg0.i<<instruction->arg1.i);
|
|
break;
|
|
case OP_shrt:
|
|
pushInt(&state->stack, instruction->arg0.i>>instruction->arg1.i);
|
|
break;
|
|
//END bitwise operations
|
|
|
|
//BEGIN data manipulation operations
|
|
case OP_store:
|
|
state->registers[raw->arg0_1]=instruction->arg1;
|
|
break;
|
|
case OP_push:
|
|
if(instruction->nArgs==3) {
|
|
pushInt(&state->stack, raw->immediate);
|
|
} else {
|
|
readOpcodeData(state, raw, instruction, 1, 1);
|
|
pushDouble(&state->stack, instruction->arg0.d);
|
|
}
|
|
break;
|
|
case OP_high:
|
|
pushInt(&state->stack, instruction->arg0.i<<16);
|
|
break;
|
|
case OP_swap:
|
|
popDouble(&state->stack, &temp0.d);
|
|
popDouble(&state->stack, &temp1.d);
|
|
pushDouble(&state->stack, temp0.d);
|
|
pushDouble(&state->stack, temp1.d);
|
|
break;
|
|
case OP_dup:
|
|
pushDouble(&state->stack, instruction->arg0.d);
|
|
pushDouble(&state->stack, instruction->arg0.d);
|
|
break;
|
|
case OP_i2d:
|
|
pushDouble(&state->stack, (double) instruction->arg0.i);
|
|
break;
|
|
case OP_d2i:
|
|
pushInt(&state->stack, (int) instruction->arg0.d);
|
|
break;
|
|
//END data manipulation operations
|
|
|
|
//BEGIN flow control operations
|
|
case OP_jmp:
|
|
state->registers[0].i=instruction->arg0.i%65536;
|
|
break;
|
|
case OP_jle_i:
|
|
popInt(&state->stack, &temp0.i);
|
|
if(instruction->arg1.i<=temp0.i) state->registers[0].i=instruction->arg0.i%65536;
|
|
break;
|
|
case OP_jlt_i:
|
|
popInt(&state->stack, &temp0.i);
|
|
if(instruction->arg1.i<temp0.i) state->registers[0].i=instruction->arg0.i%65536;
|
|
break;
|
|
//END flow control operations
|
|
}
|
|
}
|
|
//END execution functions
|
|
|
|
//END Internal functions
|