Casio_asm/old/asm.c

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