-
Notifications
You must be signed in to change notification settings - Fork 27
/
emu.c
100 lines (81 loc) · 2.85 KB
/
emu.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
#include "emu.h"
#include <stdio.h>
#include "debug.h"
#include "functions.h"
#include "io.h"
#include "opcodes.h"
#define NEXT_BYTE(cpu) ((cpu)->mem[(cpu)->pc + (pc_offset++)])
void main_loop(cpu *m) {
uint8_t opcode;
uint8_t arg1, arg2, t1;
int8_t s1;
uint16_t r1, r2;
// pc_offset is used to read from memory like a stream when processing
// bytecode without modifying the pc. pc_start is the memory address of the
// currently-executing opcode; if pc == pc_start at the end of a simulation
// step, we add pc_offset to get the start of the next instruction. if pc !=
// pc_start, we branched so we don't touch the pc.
uint8_t pc_offset = 0;
uint16_t pc_start;
// branch_offset is an offset that will be added to the program counter
// after we move to the next instruction
int8_t branch_offset = 0;
init_io();
for (;;) {
DUMP_DEBUG(m);
reset_emu_flags(m);
pc_offset = 0;
branch_offset = 0;
pc_start = m->pc;
opcode = NEXT_BYTE(m);
switch (opcode) {
case NOP:
break;
#ifndef DISABLE_EXTENSIONS
case EXT:
goto end;
case DUMP:
dump_cpu(m);
break;
#endif
#include "opcode_handlers/arithmetic.h"
#include "opcode_handlers/branch.h"
#include "opcode_handlers/compare.h"
#include "opcode_handlers/flags.h"
#include "opcode_handlers/incdec.h"
#include "opcode_handlers/interrupts.h"
#include "opcode_handlers/jump.h"
#include "opcode_handlers/load.h"
#include "opcode_handlers/logical.h"
#include "opcode_handlers/shift.h"
#include "opcode_handlers/stack.h"
#include "opcode_handlers/store.h"
#include "opcode_handlers/transfer.h"
default:
printf("ERROR: got unknown opcode %02x\n", opcode);
goto end;
}
if (m->pc == pc_start) {
m->pc += pc_offset;
}
m->pc += branch_offset;
do {
handle_io(m);
// clear dirty memory flag immediately so that subsequent runs don't
// redo whatever I/O operation is associated with the dirty memaddr
m->emu_flags &= ~EMU_FLAG_DIRTY;
} while ((m->emu_flags & EMU_FLAG_WAIT_FOR_INTERRUPT) &&
!m->interrupt_waiting);
if (m->interrupt_waiting && !get_flag(m, FLAG_INTERRUPT)) {
STACK_PUSH(m) = (m->pc & 0xFF00) >> 8;
STACK_PUSH(m) = m->pc & 0xFF;
STACK_PUSH(m) = m->sr;
m->interrupt_waiting = 0x00;
m->pc = mem_abs(m->mem[0xFFFE], m->mem[0xFFFF], 0);
m->sr |= FLAG_INTERRUPT;
}
m->last_opcode = opcode;
}
end:
finish_io();
}