Ejemplo n.º 1
0
void vm_op_ifu(vm_t* vm, uint16_t b, uint16_t a)
{
	int16_t val_b, val_a;
	val_a = (int16_t)vm_resolve_value(vm, a, POS_A);
	val_b = (int16_t)vm_resolve_value(vm, b, POS_B);

	VM_BRANCHING_SKIP;
	vm->skip = !(val_b < val_a);
}
Ejemplo n.º 2
0
void vm_op_ifc(vm_t* vm, uint16_t b, uint16_t a)
{
	uint16_t val_b, val_a;
	val_a = vm_resolve_value(vm, a, POS_A);
	val_b = vm_resolve_value(vm, b, POS_B);

	VM_BRANCHING_SKIP;
	vm->skip = !((val_b & val_a) == 0);
}
Ejemplo n.º 3
0
void vm_op_hcf(vm_t* vm, uint16_t a)
{
    uint16_t val_a = vm_resolve_value(vm, a, POS_A);
    (void)val_a;
    OP_NUM_CYCLES(9);
    vm->halted = true;
}
Ejemplo n.º 4
0
void vm_op_mdi(vm_t* vm, uint16_t b, uint16_t a)
{
	uint16_t val_a;
	uint16_t val_b;
	int16_t val_b_signed;
	uint16_t* store_b;
	val_a = vm_resolve_value(vm, a, POS_A);
	val_b = vm_resolve_value_once(vm, b, POS_B);
	store_b = vm_internal_get_store(vm, b, POS_B);
	OP_NUM_CYCLES(3);

	VM_SKIP_RESET;

	// compute 2s complement
	if (val_b > (2 ^ 8))
		val_b_signed = 0 - (0x10000 - val_b);
	else
		val_b_signed = val_b;

	if (val_a != 0)
		*store_b = val_b_signed % val_a;
	else
		*store_b = 0;

	VM_HOOK_FIRE(store_b);
}
Ejemplo n.º 5
0
// Sometimes an instruction will get the value of 'a' for a second
// time (such as in the case of ADD).  We need to make sure that
// if the value of 'a' modified the VM state in vm_internal_get_store
// that we don't modify the state again (for example, not incrementing
// PC for NXT).
uint16_t vm_resolve_value_once(vm_t* vm, uint16_t val, uint8_t pos)
{
	switch (val)
	{
		case NXT:
			return vm->ram[(uint16_t)vm->ram[(uint16_t)(vm->pc - 1)]];

		case PUSH_POP:
			return vm->ram[vm->sp];

		case PICK:
			return vm->ram[(uint16_t)(vm->sp + vm->ram[(uint16_t)(vm->pc - 1)])];

		case NXT_VAL_A:
		case NXT_VAL_B:
		case NXT_VAL_C:
		case NXT_VAL_X:
		case NXT_VAL_Y:
		case NXT_VAL_Z:
		case NXT_VAL_I:
		case NXT_VAL_J:
			return vm->ram[(uint16_t)(vm->registers[val - NXT_VAL_A] + vm->ram[(uint16_t)(vm->pc - 1)])];

		default:
			return vm_resolve_value(vm, val, pos);
	}
}
Ejemplo n.º 6
0
void vm_op_dvi(vm_t* vm, uint16_t b, uint16_t a)
{
	uint16_t val_a;
	int16_t val_b;
	uint16_t* store_b;
	val_a = vm_resolve_value(vm, a, POS_A);
	val_b = (int16_t)vm_resolve_value_once(vm, b, POS_B);
	store_b = vm_internal_get_store(vm, b, POS_B);
	OP_NUM_CYCLES(3);

	VM_SKIP_RESET;

	if (val_a != 0)
	{
		*store_b = val_b / val_a;
		vm->ex = ((val_b << 16) / val_a) & 0xffff;
	}
	else
	{
		*store_b = 0;
		vm->ex = 0;
	}

	VM_HOOK_FIRE(store_b);
}
Ejemplo n.º 7
0
void vm_op_hwq(vm_t* vm, uint16_t a)
{
	hw_t queried_device;
	uint16_t* store_a = vm_internal_get_store(vm, REG_A, POS__);
	uint16_t* store_b = vm_internal_get_store(vm, REG_B, POS__);
	uint16_t* store_c = vm_internal_get_store(vm, REG_C, POS__);
	uint16_t* store_x = vm_internal_get_store(vm, REG_X, POS__);
	uint16_t* store_y = vm_internal_get_store(vm, REG_Y, POS__);

	uint16_t val_a = vm_resolve_value(vm, a, POS_A);
	OP_NUM_CYCLES(4);

	VM_SKIP_RESET;
	if (val_a < vm_hw_count(vm))
	{
		queried_device = vm_hw_get_device(vm, val_a);

		printd(LEVEL_DEBUG, "hwq: index %d %08X\n", val_a, queried_device.id);

		*store_a = (queried_device.id & 0x0000FFFF) >>	0;
		*store_b = (queried_device.id & 0xFFFF0000) >> 16;
		*store_c = queried_device.version;
		*store_x = (queried_device.manufacturer & 0x0000FFFF) >>  0;
		*store_y = (queried_device.manufacturer & 0xFFFF0000) >> 16;

		VM_HOOK_FIRE(store_a);
		VM_HOOK_FIRE(store_b);
		VM_HOOK_FIRE(store_c);
		VM_HOOK_FIRE(store_x);
		VM_HOOK_FIRE(store_y);
	}
Ejemplo n.º 8
0
void vm_op_int(vm_t* vm, uint16_t a)
{
	uint16_t val_a = vm_resolve_value(vm, a, POS_A);
	OP_NUM_CYCLES(4);

	printd(LEVEL_DEBUG, "sending interrupt %u\n", val_a);
	vm_interrupt(vm, val_a);
}
Ejemplo n.º 9
0
void vm_op_jsr(vm_t* vm, uint16_t a)
{
	uint16_t val_a = vm_resolve_value(vm, a, POS_A);
	uint16_t t;
	OP_NUM_CYCLES(3);

	VM_SKIP_RESET;
	t = --vm->sp;
	vm->ram[t] = vm->pc;
	vm->pc = val_a;
}
Ejemplo n.º 10
0
void vm_op_rfi(vm_t* vm, uint16_t a)
{
	uint16_t val_a = vm_resolve_value(vm, a, POS_A);
	OP_NUM_CYCLES(3);
	VM_SKIP_RESET;
	vm->registers[REG_A] = vm->ram[vm->sp++];
	vm->pc = vm->ram[vm->sp++];
	printd(LEVEL_DEBUG, "turning off interrupt queue\n");
	vm->queue_interrupts = false;
	printd(LEVEL_DEBUG, "returning from interrupt.\n");
	VM_HOOK_FIRE(&vm->registers[REG_A]);
}
Ejemplo n.º 11
0
void vm_op_xor(vm_t* vm, uint16_t b, uint16_t a)
{
	uint16_t val_b, val_a;
	uint16_t* store_b;
	val_a = vm_resolve_value(vm, a, POS_A);
	val_b = vm_resolve_value_once(vm, b, POS_B);
	store_b = vm_internal_get_store(vm, b, POS_B);
	OP_NUM_CYCLES(1);

	VM_SKIP_RESET;
	*store_b = val_b ^ val_a;
	VM_HOOK_FIRE(store_b);
}
Ejemplo n.º 12
0
void vm_op_set(vm_t* vm, uint16_t b, uint16_t a)
{
	uint16_t val_a;
	uint16_t* store_b;
	val_a = vm_resolve_value(vm, a, POS_A);
	store_b = vm_internal_get_store(vm, b, POS_B);
	OP_NUM_CYCLES(1);

	VM_SKIP_RESET;
	*store_b = val_a;
	VM_HOOK_FIRE(store_b);
	vm->skip = false;
}
Ejemplo n.º 13
0
void vm_op_sub(vm_t* vm, uint16_t b, uint16_t a)
{
	uint16_t val_b, val_a;
	uint16_t* store_b;
	val_a = vm_resolve_value(vm, a, POS_A);
	val_b = vm_resolve_value_once(vm, b, POS_B);
	store_b = vm_internal_get_store(vm, b, POS_B);
	OP_NUM_CYCLES(2);

	VM_SKIP_RESET;
	*store_b = val_b - val_a;
	VM_CHECK_ARITHMETIC_FLOW(-, val_b, val_a);
	VM_HOOK_FIRE(store_b);
}
Ejemplo n.º 14
0
void vm_op_shl(vm_t* vm, uint16_t b, uint16_t a)
{
	uint16_t val_b, val_a;
	uint16_t* store_b;
	val_a = vm_resolve_value(vm, a, POS_A);
	val_b = vm_resolve_value_once(vm, b, POS_B);
	store_b = vm_internal_get_store(vm, b, POS_B);
	OP_NUM_CYCLES(1);

	VM_SKIP_RESET;
	*store_b = val_b << val_a;
	vm->ex = ((val_b << val_a) >> 16) & 0xffff;
	VM_HOOK_FIRE(store_b);
}
Ejemplo n.º 15
0
void vm_op_std(vm_t* vm, uint16_t b, uint16_t a)
{
	uint16_t val_a;
	uint16_t* store_b;
	val_a = vm_resolve_value(vm, a, POS_A);
	store_b = vm_internal_get_store(vm, b, POS_B);

	VM_SKIP_RESET;
	*store_b = val_a;
	VM_HOOK_FIRE(store_b);
	vm->registers[REG_I]--;
	vm->registers[REG_J]--;
	VM_HOOK_FIRE(&vm->registers[REG_I]);
	VM_HOOK_FIRE(&vm->registers[REG_J]);
}
Ejemplo n.º 16
0
void vm_op_adx(vm_t* vm, uint16_t b, uint16_t a)
{
	uint16_t val_b, val_a, val_ex;
	uint16_t* store_b;
	val_a = vm_resolve_value(vm, a, POS_A);
	val_b = vm_resolve_value_once(vm, b, POS_B);
	store_b = vm_internal_get_store(vm, b, POS_B);
	OP_NUM_CYCLES(3);

	val_ex = vm->ex;
	VM_SKIP_RESET;
	*store_b = val_b + val_a + val_ex;
	VM_CHECK_ARITHMETIC_FLOW_EX(+, val_b, val_a, val_ex);
	VM_HOOK_FIRE(store_b);
}
Ejemplo n.º 17
0
void vm_op_mli(vm_t* vm, uint16_t b, uint16_t a)
{
    int16_t val_a;
    int16_t val_b;
    uint16_t* store_b;
    val_a = vm_resolve_value(vm, a, POS_A);
    store_b = vm_internal_get_store(vm, b, POS_B);
    val_b = *store_b;
    OP_NUM_CYCLES(2);

    VM_SKIP_RESET;
    *store_b = val_b * val_a;
    vm->ex = ((val_b * val_a) >> 16) & 0xffff;
    VM_HOOK_FIRE(store_b);
}
Ejemplo n.º 18
0
void vm_op_mod(vm_t* vm, uint16_t b, uint16_t a)
{
	uint16_t val_b, val_a;
	uint16_t* store_b;
	val_a = vm_resolve_value(vm, a, POS_A);
	val_b = vm_resolve_value_once(vm, b, POS_B);
	store_b = vm_internal_get_store(vm, b, POS_B);
	OP_NUM_CYCLES(3);

	VM_SKIP_RESET;

	if (val_a != 0)
		*store_b = val_b % val_a;
	else
		*store_b = 0;

	VM_HOOK_FIRE(store_b);
}
Ejemplo n.º 19
0
void vm_op_asr(vm_t* vm, uint16_t b, uint16_t a)
{
	// TODO: This may not infact be correct.  C uses
	// arithmetic shifts if the left-hand value is
	// signed, however, we still need to make sure that the
	// excess register is completely compliant.
	int16_t val_b, val_a;
	uint16_t* store_b;
	val_a = (int16_t)vm_resolve_value(vm, a, POS_A);
	val_b = (int16_t)vm_resolve_value_once(vm, b, POS_B);
	store_b = vm_internal_get_store(vm, b, POS_B);
	OP_NUM_CYCLES(1);

	VM_SKIP_RESET;
	*store_b = val_b >> val_a;
	vm->ex = ((val_b << 16) >> val_a) & 0xffff;
	VM_HOOK_FIRE(store_b);
}
Ejemplo n.º 20
0
void vm_op_iaq(vm_t* vm, uint16_t a)
{
    uint16_t val_a = vm_resolve_value(vm, a, POS_A);
    OP_NUM_CYCLES(2);

    VM_SKIP_RESET;

    printd(LEVEL_DEBUG, "IAQ CALLED WITH %u\n", val_a);

    if (val_a == 0)
    {
        printd(LEVEL_DEBUG, "turning off interrupt queue\n");
        vm->queue_interrupts = false;
    }
    else
    {
        printd(LEVEL_DEBUG, "turning on interrupt queue\n");
        vm->queue_interrupts = true;
    }
}
Ejemplo n.º 21
0
///
/// Disassembles a single instruction located at the specified position.
///
/// Disassembles a single instruction without affecting the state of the
/// virtual machine by saving the state of the PC and SP registers before
/// doing value resolution and then restoring them afterwards.
///
/// @param vm The virtual machine.
/// @param pos The position in RAM of the instruction to disassemble.
/// @param pretty Whether the 'pretty' substructure should be filled.  The caller is responsible for destroying the bstrings.
///
struct inst vm_disassemble(vm_t* vm, uint16_t pos, bool pretty)
{
	struct inst result;
	uint16_t pc_store = vm->pc;
	uint16_t sp_store = vm->sp;
	uint8_t debug_store = vm->debug;
	struct instruction_mapping* instmap;
	struct register_mapping* regmap;

	// Set pretty structure to NULL by default.
	result.pretty.op = NULL;
	result.pretty.a = NULL;
	result.pretty.b = NULL;

	// Set correct VM state for a resolving read.
	vm->pc = pos;
	vm->debug = false;

	// Read the basic instruction data.
	result.original.full = vm->ram[vm->pc++];
	result.original.op = INSTRUCTION_GET_OP(result.original.full);
	result.original.a = INSTRUCTION_GET_A(result.original.full);
	result.original.b = INSTRUCTION_GET_B(result.original.full);

	// Resolve values.
	if (result.original.op == OP_NONBASIC)
	{
		result.op = result.original.b;
		result.a = vm_resolve_value(vm, result.original.a, POS_A);
		result.b = 0x0;
	}
	else
	{
		result.op = result.original.op;
		result.a = vm_resolve_value(vm, result.original.a, POS_A);
		result.b = vm_resolve_value(vm, result.original.b, POS_B);
	}
	result.size = vm->pc - pos;
	result.extra[0] = 0x0;
	result.extra[1] = 0x0;
	result.next[0] = 0x0;
	result.next[1] = 0x0;
	result.used[0] = false;
	result.used[1] = false;
	if (result.size - 1 >= 1)
		result.extra[0] = vm->ram[pos + 1];
	if (result.size - 1 >= 2)
		result.extra[1] = vm->ram[pos + 2];
	if (result.size - 1 >= 2)
	{
		result.used[0] = true;
		result.used[1] = true;
		result.next[0] = vm->ram[pos + 1];
		result.next[1] = vm->ram[pos + 2];
	}
	else if (result.size - 1 >= 1 && (result.original.a == NXT || result.original.a == NXT_LIT || result.original.a == PICK || (result.original.a >= NXT_VAL_A && result.original.a <= NXT_VAL_J)))
	{
		result.used[0] = true;
		result.next[0] = vm->ram[pos + 1];
	}
	else if (result.size - 1 >= 1 && (result.original.b == NXT || result.original.b == NXT_LIT || result.original.b == PICK || (result.original.b >= NXT_VAL_A && result.original.b <= NXT_VAL_J)))
	{
		result.used[1] = true;
		result.next[1] = vm->ram[pos + 1];
	}

	// Work out pretty values if required.
	instmap = get_instruction_by_value(result.original.op, result.original.b);
	if (pretty && instmap != NULL)
	{
		// Work out the instruction name.
		result.pretty.op = bfromcstr(instmap->name);

		// Work out the a parameter.
		regmap = get_register_by_value(result.original.a);
		if (result.original.a >= REG_A && result.original.a <= REG_J)
			result.pretty.a = bfromcstr(regmap->name);
		else if (result.original.a >= VAL_A && result.original.a <= VAL_J)
			result.pretty.a = bformat("[%s]", regmap->name);
		else if (result.original.a >= NXT_VAL_A && result.original.a <= NXT_VAL_J)
			result.pretty.a = bformat("[%s+0x%04X]", regmap->name, result.next[0]);
		else if (result.original.a == PUSH_POP)
			result.pretty.a = bfromcstr("POP");
		else if (result.original.a == PEEK)
			result.pretty.a = bfromcstr("[SP]");
		else if (result.original.a == PICK)
			result.pretty.a = bformat("[SP+0x%04X]", result.next[0]);
		else if (result.original.a >= SP && result.original.a <= EX)
			result.pretty.a = bfromcstr(regmap->name);
		else if (result.original.a == NXT)
			result.pretty.a = bformat("[0x%04X]", result.next[0]);
		else if (result.original.a == NXT_LIT)
			result.pretty.a = bformat("0x%04X", result.next[0]);
		else if (result.original.a >= 0x20 && result.original.a <= 0x3F)
			result.pretty.a = bformat("0x%04X", result.original.a - 0x21);
		else
			result.pretty.a = bfromcstr("???");

		// Only fill the b parameter if the opcode was basic.
		if (result.pretty.op != OP_NONBASIC)
		{
			regmap = get_register_by_value(result.original.b);
			if (result.original.b >= REG_A && result.original.b <= REG_J)
				result.pretty.b = bfromcstr(regmap->name);
			else if (result.original.b >= VAL_A && result.original.b <= VAL_J)
				result.pretty.b = bformat("[%s]", regmap->name);
			else if (result.original.b >= NXT_VAL_A && result.original.b <= NXT_VAL_J)
				result.pretty.b = bformat("[%s+0x%04X]", regmap->name, result.next[1]);
			else if (result.original.b == PUSH_POP)
				result.pretty.b = bfromcstr("PUSH");
			else if (result.original.b == PEEK)
				result.pretty.b = bfromcstr("[SP]");
			else if (result.original.b == PICK)
				result.pretty.b = bformat("[SP+0x%04X]", result.next[1]);
			else if (result.original.b >= SP && result.original.b <= EX)
				result.pretty.b = bfromcstr(regmap->name);
			else if (result.original.b == NXT)
				result.pretty.b = bformat("[0x%04X]", result.next[1]);
			else if (result.original.b == NXT_LIT)
				result.pretty.b = bformat("0x%04X", result.next[1]);
			else if (result.original.b >= 0x20 && result.original.b <= 0x3F)
				result.pretty.b = bformat("0x%04X", result.original.b - 0x21);
			else
				result.pretty.b = bfromcstr("???");
		}
	}

	// Restore state.
	vm->pc = pc_store;
	vm->sp = sp_store;
	vm->debug = debug_store;

	// Return instruction.
	return result;
}
Ejemplo n.º 22
0
void vm_op_ias(vm_t* vm, uint16_t a)
{
	uint16_t val_a = vm_resolve_value(vm, a, POS_A);
	VM_SKIP_RESET;
	vm->ia = val_a;
}