Do some stuff
This commit is contained in:
306
cpu/core.c
306
cpu/core.c
@@ -9,7 +9,6 @@
|
||||
// Initialize CPU
|
||||
void init_cpu(CPU *cpu) {
|
||||
memset(cpu, 0, sizeof(CPU));
|
||||
cpu->sp = MEM_SIZE - 1; // Stack grows downward
|
||||
}
|
||||
|
||||
// Helper function for setting flags in the CPU (here we assume bit0 is the Zero flag,
|
||||
@@ -17,21 +16,25 @@ void init_cpu(CPU *cpu) {
|
||||
static inline void set_flags(CPU *cpu, int32_t result) {
|
||||
cpu->flags = 0;
|
||||
if (result == 0)
|
||||
cpu->flags |= 0x01; // Zero flag
|
||||
cpu->flags |= CPU_FLAG_ZERO; // Zero flag
|
||||
if (result < 0)
|
||||
cpu->flags |= 0x02; // Negative flag
|
||||
cpu->flags |= CPU_FLAG_NEGATIVE; // Negative flag
|
||||
}
|
||||
|
||||
// Execute a program (a byte array) on the given CPU.
|
||||
// Execute one cycle
|
||||
void step(CPU *cpu) {
|
||||
if (cpu->mode < EverySecond) {
|
||||
if (!(cpu->mode & (CPU_MODE_HALTED | CPU_MODE_PAUSED | CPU_MODE_ERROR))) {
|
||||
return;
|
||||
}
|
||||
if (cpu->pc >= MEM_SIZE) {
|
||||
cpu->mode = Done; //terminate
|
||||
if (cpu->mode | CPU_MODE_LOOP) {
|
||||
cpu->pc = 0;
|
||||
} else {
|
||||
cpu->mode |= CPU_MODE_HALTED;
|
||||
}
|
||||
}
|
||||
uint8_t opcode = read_mem(cpu, cpu->pc++);
|
||||
uint8_t reg1, reg2, imm, temp;
|
||||
uint8_t reg1, reg2, imm, temp, temp2;
|
||||
uint32_t newPC, addrTemp;
|
||||
int32_t cmpResult;
|
||||
|
||||
@@ -42,7 +45,7 @@ void step(CPU *cpu) {
|
||||
|
||||
case BRK:
|
||||
//Pause CPU (for breakpoints)
|
||||
cpu->mode = Paused;
|
||||
cpu->mode |= CPU_MODE_PAUSED;
|
||||
break;
|
||||
|
||||
case INC_RN:
|
||||
@@ -50,11 +53,10 @@ void step(CPU *cpu) {
|
||||
reg1 = read_reg_number(cpu);
|
||||
temp = read_reg(cpu, reg1);
|
||||
write_reg(cpu, reg1, temp + 1);
|
||||
cpu->regs[reg1]++;
|
||||
|
||||
case INC_ADDR:
|
||||
//Increment address
|
||||
addrTemp = read_address(cpu);
|
||||
addrTemp = read_address_argument(cpu);
|
||||
temp = read_mem(cpu, addrTemp);
|
||||
write_mem(cpu, addrTemp, temp + 1);
|
||||
|
||||
@@ -63,11 +65,10 @@ void step(CPU *cpu) {
|
||||
reg1 = read_reg_number(cpu);
|
||||
temp = read_reg(cpu, reg1);
|
||||
write_reg(cpu, reg1, temp - 1);
|
||||
cpu->regs[reg1]++;
|
||||
|
||||
case DEC_ADDR:
|
||||
//Decrement address
|
||||
addrTemp = read_address(cpu);
|
||||
addrTemp = read_address_argument(cpu);
|
||||
temp = read_mem(cpu, addrTemp);
|
||||
write_mem(cpu, addrTemp, temp - 1);
|
||||
|
||||
@@ -88,211 +89,254 @@ void step(CPU *cpu) {
|
||||
case MOV_RN_ADDR:
|
||||
// Store register to memory
|
||||
reg1 = read_reg_number(cpu);
|
||||
addrTemp = read_address(cpu);
|
||||
addrTemp = read_address_argument(cpu);
|
||||
temp = read_reg(cpu, reg1);
|
||||
write_mem(cpu, addrTemp, temp);
|
||||
break;
|
||||
|
||||
case MOV_ADDR_RN:
|
||||
// Load memory to register
|
||||
addrTemp = read_address(cpu);
|
||||
addrTemp = read_address_argument(cpu);
|
||||
reg1 = read_reg_number(cpu);
|
||||
temp = read
|
||||
write_mem(cpu, addrTemp, cpu->regs[reg1]);
|
||||
temp = read_mem(cpu, addrTemp);
|
||||
write_reg(cpu, reg1, temp);
|
||||
break;
|
||||
|
||||
case SWAP: {
|
||||
// Swap contents of two registers.
|
||||
reg1 = read_reg_number(cpu);
|
||||
reg2 = read_reg_number(cpu);
|
||||
temp = cpu->regs[reg1];
|
||||
cpu->regs[reg1] = cpu->regs[reg2];
|
||||
cpu->regs[reg2] = temp;
|
||||
temp = read_reg(cpu, reg1);
|
||||
temp2 = read_reg(cpu, reg2);
|
||||
write_reg(cpu, reg1, temp2);
|
||||
write_reg(cpu, reg2, temp);
|
||||
break;
|
||||
}
|
||||
|
||||
case SWAPN: {
|
||||
// Swap the nibbles of a register.
|
||||
reg1 = read_reg_number(cpu);
|
||||
uint8_t val = (uint8_t) cpu->regs[reg1];
|
||||
cpu->regs[reg1] = ((val & 0x0F) << 4) | ((val & 0xF0) >> 4);
|
||||
temp = read_reg(cpu, reg1);
|
||||
cpu->regs[reg1] = ((temp & 0x0F) << 4) | ((temp & 0xF0) >> 4);
|
||||
write_reg(cpu, reg1, temp);
|
||||
break;
|
||||
}
|
||||
|
||||
case ADD_RN_RM:
|
||||
reg1 = read_reg_number(cpu);
|
||||
reg2 = read_reg_number(cpu);
|
||||
cpu->regs[reg1] += cpu->regs[reg2];
|
||||
set_flags(cpu, cpu->regs[reg1]);
|
||||
temp = read_reg(cpu, reg1);
|
||||
temp += read_reg(cpu, reg2);
|
||||
write_reg(cpu, reg1, temp);
|
||||
set_flags(cpu, temp);
|
||||
break;
|
||||
|
||||
case ADD_RN_IMM:
|
||||
reg1 = read_reg_number(cpu);
|
||||
imm = read_mem(cpu, cpu->pc++);
|
||||
cpu->regs[reg1] += imm;
|
||||
set_flags(cpu, cpu->regs[reg1]);
|
||||
temp = read_reg(cpu, reg1);
|
||||
temp += imm;
|
||||
write_reg(cpu, reg1, temp);
|
||||
set_flags(cpu, temp);
|
||||
break;
|
||||
|
||||
case SUB_RN_RM:
|
||||
reg1 = read_reg_number(cpu);
|
||||
reg2 = read_reg_number(cpu);
|
||||
cpu->regs[reg1] -= cpu->regs[reg2];
|
||||
set_flags(cpu, cpu->regs[reg1]);
|
||||
temp = read_reg(cpu, reg1);
|
||||
temp -= read_reg(cpu, reg2);
|
||||
write_reg(cpu, reg1, temp);
|
||||
set_flags(cpu, temp);
|
||||
break;
|
||||
|
||||
case SUB_RN_IMM:
|
||||
reg1 = read_reg_number(cpu);
|
||||
imm = read_mem(cpu, cpu->pc++);
|
||||
cpu->regs[reg1] -= imm;
|
||||
set_flags(cpu, cpu->regs[reg1]);
|
||||
temp = read_reg(cpu, reg1);
|
||||
temp -= imm;
|
||||
write_reg(cpu, reg1, temp);
|
||||
set_flags(cpu, temp);
|
||||
break;
|
||||
|
||||
case MUL_RN_RM:
|
||||
reg1 = read_reg_number(cpu);
|
||||
reg2 = read_reg_number(cpu);
|
||||
cpu->regs[reg1] *= cpu->regs[reg2];
|
||||
set_flags(cpu, cpu->regs[reg1]);
|
||||
temp = read_reg(cpu, reg1);
|
||||
temp *= read_reg(cpu, reg2);
|
||||
write_reg(cpu, reg1, temp);
|
||||
set_flags(cpu, temp);
|
||||
break;
|
||||
|
||||
case MUL_RN_IMM:
|
||||
reg1 = read_reg_number(cpu);
|
||||
imm = read_mem(cpu, cpu->pc++);
|
||||
cpu->regs[reg1] *= imm;
|
||||
set_flags(cpu, cpu->regs[reg1]);
|
||||
temp = read_reg(cpu, reg1);
|
||||
temp *= imm;
|
||||
write_reg(cpu, reg1, temp);
|
||||
set_flags(cpu, temp);
|
||||
break;
|
||||
|
||||
case DIV_RN_RM:
|
||||
reg1 = read_reg_number(cpu);
|
||||
reg2 = read_reg_number(cpu);
|
||||
if (cpu->regs[reg2] == 0) {
|
||||
temp = read_reg(cpu, reg1);
|
||||
temp2 = read_reg(cpu, reg2);
|
||||
if (temp2 == 0) {
|
||||
printf("Error: Division by zero!\n");
|
||||
cpu->mode = Error;
|
||||
cpu->mode |= CPU_MODE_ERROR;
|
||||
return;
|
||||
}
|
||||
cpu->regs[reg1] /= cpu->regs[reg2];
|
||||
set_flags(cpu, cpu->regs[reg1]);
|
||||
temp /= temp2;
|
||||
write_reg(cpu, reg1, temp);
|
||||
set_flags(cpu, temp);
|
||||
break;
|
||||
|
||||
case DIV_RN_IMM:
|
||||
reg1 = read_reg_number(cpu);
|
||||
temp = read_reg(cpu, reg1);
|
||||
imm = read_mem(cpu, cpu->pc++);
|
||||
if (imm == 0) {
|
||||
printf("Error: Division by zero!\n");
|
||||
cpu->mode = Error;
|
||||
cpu->mode |= CPU_MODE_ERROR;
|
||||
return;
|
||||
}
|
||||
cpu->regs[reg1] /= imm;
|
||||
set_flags(cpu, cpu->regs[reg1]);
|
||||
temp /= imm;
|
||||
write_reg(cpu, reg1, temp);
|
||||
set_flags(cpu, temp);
|
||||
break;
|
||||
|
||||
case MOD_RN_RM:
|
||||
reg1 = read_reg_number(cpu);
|
||||
reg2 = read_reg_number(cpu);
|
||||
if (cpu->regs[reg2] == 0) {
|
||||
temp = read_reg(cpu, reg1);
|
||||
temp2 = read_reg(cpu, reg2);
|
||||
if (temp2 == 0) {
|
||||
printf("Error: Modulo by zero!\n");
|
||||
cpu->mode = Error;
|
||||
cpu->mode |= CPU_MODE_ERROR;
|
||||
return;
|
||||
}
|
||||
cpu->regs[reg1] %= cpu->regs[reg2];
|
||||
set_flags(cpu, cpu->regs[reg1]);
|
||||
temp %= temp2;
|
||||
write_reg(cpu, reg1, temp);
|
||||
set_flags(cpu, temp);
|
||||
break;
|
||||
|
||||
case MOD_RN_IMM:
|
||||
reg1 = read_reg_number(cpu);
|
||||
temp = read_reg(cpu, reg1);
|
||||
imm = read_mem(cpu, cpu->pc++);
|
||||
if (imm == 0) {
|
||||
printf("Error: Modulo by zero!\n");
|
||||
cpu->mode = Error;
|
||||
cpu->mode |= CPU_MODE_ERROR;
|
||||
return;
|
||||
}
|
||||
cpu->regs[reg1] %= imm;
|
||||
set_flags(cpu, cpu->regs[reg1]);
|
||||
temp %= imm;
|
||||
write_reg(cpu, reg1, temp);
|
||||
set_flags(cpu, temp);
|
||||
break;
|
||||
|
||||
case NEG_RN:
|
||||
reg1 = read_reg_number(cpu);
|
||||
cpu->regs[reg1] = -((int32_t) cpu->regs[reg1]);
|
||||
set_flags(cpu, cpu->regs[reg1]);
|
||||
temp = -read_reg(cpu, reg1);
|
||||
write_reg(cpu, reg1, temp);
|
||||
set_flags(cpu, temp);
|
||||
break;
|
||||
|
||||
case AND_RN_RM:
|
||||
reg1 = read_reg_number(cpu);
|
||||
reg2 = read_reg_number(cpu);
|
||||
cpu->regs[reg1] &= cpu->regs[reg2];
|
||||
set_flags(cpu, cpu->regs[reg1]);
|
||||
temp = read_reg(cpu, reg1);
|
||||
temp &= read_reg(cpu, reg2);
|
||||
write_reg(cpu, reg1, temp);
|
||||
set_flags(cpu, temp);
|
||||
break;
|
||||
|
||||
case AND_RN_IMM:
|
||||
reg1 = read_reg_number(cpu);
|
||||
temp = read_reg(cpu, reg1);
|
||||
imm = read_mem(cpu, cpu->pc++);
|
||||
cpu->regs[reg1] &= imm;
|
||||
set_flags(cpu, cpu->regs[reg1]);
|
||||
temp &= imm;
|
||||
write_reg(cpu, reg1, temp);
|
||||
set_flags(cpu, temp);
|
||||
break;
|
||||
|
||||
case OR_RN_RM:
|
||||
reg1 = read_reg_number(cpu);
|
||||
reg2 = read_reg_number(cpu);
|
||||
cpu->regs[reg1] |= cpu->regs[reg2];
|
||||
set_flags(cpu, cpu->regs[reg1]);
|
||||
temp = read_reg(cpu, reg1);
|
||||
temp |= read_reg(cpu, reg2);
|
||||
write_reg(cpu, reg1, temp);
|
||||
set_flags(cpu, temp);
|
||||
break;
|
||||
|
||||
case OR_RN_IMM:
|
||||
reg1 = read_reg_number(cpu);
|
||||
imm = read_mem(cpu, cpu->pc++);
|
||||
cpu->regs[reg1] |= imm;
|
||||
set_flags(cpu, cpu->regs[reg1]);
|
||||
temp = read_reg(cpu, reg1);
|
||||
temp |= imm;
|
||||
write_reg(cpu, reg1, temp);
|
||||
set_flags(cpu, temp);
|
||||
break;
|
||||
|
||||
case XOR_RN_RM:
|
||||
reg1 = read_reg_number(cpu);
|
||||
reg2 = read_reg_number(cpu);
|
||||
cpu->regs[reg1] ^= cpu->regs[reg2];
|
||||
set_flags(cpu, cpu->regs[reg1]);
|
||||
temp = read_reg(cpu, reg1);
|
||||
temp ^= read_reg(cpu, reg2);
|
||||
write_reg(cpu, reg1, temp);
|
||||
set_flags(cpu, temp);
|
||||
break;
|
||||
|
||||
case XOR_RN_IMM:
|
||||
reg1 = read_reg_number(cpu);
|
||||
imm = read_mem(cpu, cpu->pc++);
|
||||
cpu->regs[reg1] ^= imm;
|
||||
set_flags(cpu, cpu->regs[reg1]);
|
||||
temp = read_reg(cpu, reg1);
|
||||
temp ^= imm;
|
||||
write_reg(cpu, reg1, temp);
|
||||
set_flags(cpu, temp);
|
||||
break;
|
||||
|
||||
case NOT_RN:
|
||||
reg1 = read_reg_number(cpu);
|
||||
cpu->regs[reg1] = ~cpu->regs[reg1];
|
||||
set_flags(cpu, cpu->regs[reg1]);
|
||||
temp = ~read_reg(cpu, reg1);
|
||||
write_reg(cpu, reg1, temp);
|
||||
set_flags(cpu, temp);
|
||||
break;
|
||||
|
||||
case SHL_RN_IMM:
|
||||
reg1 = read_reg_number(cpu);
|
||||
imm = read_mem(cpu, cpu->pc++);
|
||||
cpu->regs[reg1] <<= imm;
|
||||
set_flags(cpu, cpu->regs[reg1]);
|
||||
temp = read_reg(cpu, reg1);
|
||||
temp <<= imm;
|
||||
write_reg(cpu, reg1, temp);
|
||||
set_flags(cpu, temp);
|
||||
break;
|
||||
|
||||
case SHR_RN_IMM:
|
||||
reg1 = read_reg_number(cpu);
|
||||
imm = read_mem(cpu, cpu->pc++);
|
||||
cpu->regs[reg1] >>= imm; // Logical right shift (assuming unsigned value)
|
||||
set_flags(cpu, cpu->regs[reg1]);
|
||||
temp = read_reg(cpu, reg1);
|
||||
temp >>= imm; // Logical right shift (assuming unsigned value)
|
||||
write_reg(cpu, reg1, temp);
|
||||
set_flags(cpu, temp);
|
||||
break;
|
||||
|
||||
case SAR_RN_IMM:
|
||||
reg1 = read_reg_number(cpu);
|
||||
imm = read_mem(cpu, cpu->pc++);
|
||||
temp = read_reg(cpu, reg1);
|
||||
// Arithmetic right shift; cast to signed before shifting.
|
||||
cpu->regs[reg1] = ((int32_t) cpu->regs[reg1]) >> imm;
|
||||
set_flags(cpu, cpu->regs[reg1]);
|
||||
temp = ((int32_t) temp) >> imm;
|
||||
write_reg(cpu, reg1, temp);
|
||||
set_flags(cpu, temp);
|
||||
break;
|
||||
|
||||
case JMP:
|
||||
newPC = read_mem32(cpu, cpu->pc);
|
||||
cpu->pc += 4;
|
||||
newPC = read_address_argument(cpu);
|
||||
cpu->pc = newPC;
|
||||
break;
|
||||
|
||||
case JMP_REL:
|
||||
imm = (int32_t) read_mem(cpu, cpu->pc++);
|
||||
imm = read_mem(cpu, cpu->pc++) & 0xFF;
|
||||
cpu->pc += imm;
|
||||
break;
|
||||
|
||||
@@ -300,31 +344,34 @@ void step(CPU *cpu) {
|
||||
// Compare two registers: set flags (Zero, Negative)
|
||||
reg1 = read_reg_number(cpu);
|
||||
reg2 = read_reg_number(cpu);
|
||||
cmpResult = (int32_t) cpu->regs[reg1] - (int32_t) cpu->regs[reg2];
|
||||
temp = read_reg(cpu, reg1);
|
||||
temp2 = read_reg(cpu, reg2);
|
||||
cmpResult = (int32_t) temp - (int32_t) temp2;
|
||||
set_flags(cpu, cmpResult);
|
||||
break;
|
||||
}
|
||||
|
||||
case JE_BIT_RN: {
|
||||
case JMP_BIT_SET_RN: {
|
||||
// Jump if bit in register set
|
||||
reg1 = read_reg_number(cpu);
|
||||
uint8_t bit = read_mem(cpu, cpu->pc++);
|
||||
newPC = read_address_argument(cpu);
|
||||
|
||||
temp = read_reg(cpu, reg1);
|
||||
if (reg1 >= REG_COUNT) {
|
||||
reg1 = REG_COUNT - 1;
|
||||
}
|
||||
uint8_t bit = read_mem(cpu, cpu->pc++);
|
||||
if (bit > 7) {
|
||||
bit = 7;
|
||||
}
|
||||
newPC = read_mem32(cpu, cpu->pc);
|
||||
cpu->pc += 4;
|
||||
if (cpu->regs[reg1] & (1 << bit))
|
||||
if (temp & (1 << bit))
|
||||
cpu->pc = newPC;
|
||||
break;
|
||||
}
|
||||
|
||||
case JE_BIT_ADDR: {
|
||||
case JMP_BIT_SET_ADDR: {
|
||||
// Jump if bit in register set
|
||||
addrTemp = read_mem32(cpu, cpu->pc);
|
||||
addrTemp = read_address_argument(cpu);
|
||||
if (addrTemp >= MEM_SIZE) {
|
||||
addrTemp = MEM_SIZE - 1;
|
||||
}
|
||||
@@ -332,9 +379,8 @@ void step(CPU *cpu) {
|
||||
if (bit > 7) {
|
||||
bit = 7;
|
||||
}
|
||||
newPC = read_mem32(cpu, cpu->pc);
|
||||
cpu->pc += 4;
|
||||
if (cpu->memory[addrTemp] & (1 << bit))
|
||||
newPC = read_address_argument(cpu);
|
||||
if (read_mem(cpu, addrTemp) & (1 << bit))
|
||||
cpu->pc = newPC;
|
||||
break;
|
||||
}
|
||||
@@ -342,134 +388,98 @@ void step(CPU *cpu) {
|
||||
|
||||
case JE: {
|
||||
// Jump if equal (Zero flag set)
|
||||
newPC = read_mem32(cpu, cpu->pc);
|
||||
cpu->pc += 4;
|
||||
if (cpu->flags & 0x01)
|
||||
newPC = read_address_argument(cpu);
|
||||
if (cpu->flags & CPU_FLAG_ZERO)
|
||||
cpu->pc = newPC;
|
||||
break;
|
||||
}
|
||||
|
||||
case JNE_BIT_RN: {
|
||||
case JMP_BIT_CLEAR_RN: {
|
||||
// Jump if bit in register set
|
||||
reg1 = read_reg_number(cpu);
|
||||
if (reg1 >= REG_COUNT) {
|
||||
reg1 = REG_COUNT - 1;
|
||||
}
|
||||
temp = read_reg(cpu, reg1);
|
||||
uint8_t bit = read_mem(cpu, cpu->pc++);
|
||||
if (bit > 7) {
|
||||
bit = 7;
|
||||
}
|
||||
newPC = read_mem32(cpu, cpu->pc);
|
||||
cpu->pc += 4;
|
||||
if (!(cpu->regs[reg1] & (1 << bit)))
|
||||
newPC = read_address_argument(cpu);
|
||||
if (!(temp & (1 << bit)))
|
||||
cpu->pc = newPC;
|
||||
break;
|
||||
}
|
||||
|
||||
case JNE_BIT_ADDR: {
|
||||
case JMP_BIT_CLEAR_ADDR: {
|
||||
// Jump if bit in register set
|
||||
addrTemp = read_mem32(cpu, cpu->pc);
|
||||
if (addrTemp >= MEM_SIZE) {
|
||||
addrTemp = MEM_SIZE - 1;
|
||||
}
|
||||
addrTemp = read_address_argument(cpu);
|
||||
uint8_t bit = read_mem(cpu, cpu->pc++);
|
||||
if (bit > 7) {
|
||||
bit = 7;
|
||||
}
|
||||
newPC = read_mem32(cpu, cpu->pc);
|
||||
cpu->pc += 4;
|
||||
if (!(cpu->memory[addrTemp] & (1 << bit)))
|
||||
newPC = read_address_argument(cpu);
|
||||
if (!(read_mem(cpu, addrTemp) & (1 << bit)))
|
||||
cpu->pc = newPC;
|
||||
break;
|
||||
}
|
||||
|
||||
case JNE: {
|
||||
// Jump if not equal (Zero flag clear)
|
||||
newPC = read_mem32(cpu, cpu->pc);
|
||||
cpu->pc += 4;
|
||||
if (!(cpu->flags & 0x01))
|
||||
newPC = read_address_argument(cpu);
|
||||
if (!(cpu->flags & CPU_FLAG_ZERO)) {
|
||||
cpu->pc = newPC;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case JG: {
|
||||
// Jump if greater: not negative and not zero.
|
||||
newPC = read_mem32(cpu, cpu->pc);
|
||||
cpu->pc += 4;
|
||||
if (((cpu->flags & 0x02) == 0) && ((cpu->flags & 0x01) == 0))
|
||||
newPC = read_address_argument(cpu);
|
||||
if (!(cpu->flags & CPU_FLAG_NEGATIVE) && !(cpu->flags & CPU_FLAG_ZERO)) {
|
||||
cpu->pc = newPC;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case JL: {
|
||||
// Jump if less: Negative flag set.
|
||||
newPC = read_mem32(cpu, cpu->pc);
|
||||
cpu->pc += 4;
|
||||
if (cpu->flags & 0x02)
|
||||
newPC = read_address_argument(cpu);
|
||||
if (cpu->flags & CPU_FLAG_NEGATIVE) {
|
||||
cpu->pc = newPC;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case JGE: {
|
||||
// Jump if greater or equal: Zero flag set or negative clear.
|
||||
newPC = read_mem32(cpu, cpu->pc);
|
||||
cpu->pc += 4;
|
||||
if ((cpu->flags & 0x01) || ((cpu->flags & 0x02) == 0))
|
||||
newPC = read_address_argument(cpu);
|
||||
if ((cpu->flags & CPU_FLAG_ZERO) || !(cpu->flags & CPU_FLAG_NEGATIVE)) {
|
||||
cpu->pc = newPC;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case JLE: {
|
||||
// Jump if less or equal: Negative flag set or Zero flag set.
|
||||
newPC = read_mem32(cpu, cpu->pc);
|
||||
cpu->pc += 4;
|
||||
if ((cpu->flags & 0x02) || (cpu->flags & 0x01))
|
||||
newPC = read_address_argument(cpu);
|
||||
if ((cpu->flags & CPU_FLAG_NEGATIVE) || (cpu->flags & CPU_FLAG_ZERO)) {
|
||||
cpu->pc = newPC;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case CALL: {
|
||||
// Push the current PC onto the stack, then jump to the address.
|
||||
newPC = read_mem32(cpu, cpu->pc);
|
||||
cpu->pc += 4;
|
||||
// Push return address (current PC) onto the stack.
|
||||
write_mem32(cpu, cpu->sp, cpu->pc);
|
||||
cpu->sp -= 4;
|
||||
newPC = read_address_argument(cpu);
|
||||
write_stack(cpu);
|
||||
cpu->pc = newPC;
|
||||
break;
|
||||
}
|
||||
|
||||
case RET:
|
||||
// For RET, assume that the return address was stored on the stack.
|
||||
cpu->pc = read_mem(cpu, ++cpu->sp);
|
||||
break;
|
||||
|
||||
case PUSH: {
|
||||
// Push register value onto the stack.
|
||||
reg1 = read_reg_number(cpu);
|
||||
write_mem(cpu, cpu->sp--, (uint8_t) cpu->regs[reg1]);
|
||||
break;
|
||||
}
|
||||
|
||||
case POP: {
|
||||
// Pop a value from the stack into a register.
|
||||
reg1 = read_reg_number(cpu);
|
||||
cpu->regs[reg1] = read_mem(cpu, ++cpu->sp);
|
||||
break;
|
||||
}
|
||||
|
||||
case PUSHF:
|
||||
// Push the flags register.
|
||||
write_mem(cpu, cpu->sp--, cpu->flags);
|
||||
break;
|
||||
|
||||
case POPF:
|
||||
// Pop into the flags register.
|
||||
cpu->flags = read_mem(cpu, ++cpu->sp);
|
||||
read_stack(cpu);
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("Unknown opcode: %d\n", opcode);
|
||||
cpu->mode = Error;
|
||||
cpu->mode |= CPU_MODE_ERROR;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user