forked from DavidBuchanan314/6502-emu
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy path6502-emu.c
184 lines (163 loc) · 3.8 KB
/
6502-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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <termios.h>
#include <time.h>
#include "6502.h"
#include "6850.h"
struct termios initial_termios;
void step_delay()
{
struct timespec req, rem;
req.tv_sec = 0;
req.tv_nsec = STEP_DURATION;
nanosleep(&req, &rem);
}
void run_cpu(uint64_t cycle_stop, int verbose, int mem_dump, int break_pc, int fast)
{
uint64_t cycles = 0;
uint64_t cycles_per_step = (CPU_FREQ / (ONE_SECOND / STEP_DURATION));
for (;;) {
for (cycles %= cycles_per_step; cycles < cycles_per_step;) {
if (mem_dump) save_memory(NULL);
cycles += step_cpu(verbose);
if ((cycle_stop > 0) && (total_cycles >= cycle_stop)) goto end;
step_uart();
if (break_pc >= 0 && PC == (uint16_t)break_pc) {
fprintf(stderr, "break at %04x\n", break_pc);
save_memory(NULL);
goto end;
}
}
if (!fast) step_delay();
}
end:
return;
}
void restore_stdin()
{
tcsetattr(0, TCSANOW, &initial_termios);
}
void raw_stdin()
{
struct termios new_termios;
tcgetattr(0, &initial_termios);
new_termios = initial_termios;
cfmakeraw(&new_termios);
tcsetattr(0, TCSANOW, &new_termios);
atexit(restore_stdin);
}
int hextoint(char *str) {
int val;
if (*str == '$') str++;
val = strtol(str, NULL, 16);
return val;
}
void usage(char *argv[]) {
fprintf(stderr, "Usage: %s [OPTIONS] FILE\n"
"Simulate a NMOS 6502 processor\n"
"\nOPTIONS:\n"
"\n CPU Initialization (specify all values in hex; $nn, 0xNN, etc.)\n"
" -a HEX set A register (default 0)\n"
" -x HEX set X register (default 0)\n"
" -y HEX set Y register (default 0)\n"
" -s HEX set stack pointer (default $ff)\n"
" -p HEX set processor status register (default 0)\n"
" -r ADDR set initial run address (default: use value at RST_VEC)\n"
"\n Emulator Control\n"
" -v print CPU info at every step\n"
" -i connect stdin/stdout to the emulator\n"
" -b ADDR stop when PC reaches this address, write memory dump, and exit\n"
" -c NUM exit after number of cycles (default: never)\n"
" -f run as fast as possible; no delay loop\n"
"\n Memory Initialization\n"
" -l ADDR load address for ROM file (default $c000)\n"
" FILE binary file to load\n"
, argv[0]);
}
int main(int argc, char *argv[])
{
int a, x, y, sp, sr, pc, load_addr;
int verbose, interactive, mem_dump, break_pc, fast;
uint64_t cycles;
int opt;
verbose = 0;
interactive = 0;
mem_dump = 0;
cycles = 0;
load_addr = 0xC000;
break_pc = -1;
fast = 0;
a = 0;
x = 0;
y = 0;
sp = 0xFF;
sr = 0;
pc = -RST_VEC; // negative implies indirect
while ((opt = getopt(argc, argv, "hvimfa:b:x:y:r:p:s:g:c:l:")) != -1) {
switch (opt) {
case 'v':
verbose = 1;
break;
case 'i':
interactive = 1;
break;
case 'm':
mem_dump = 1;
break;
case 'f':
fast = 1;
break;
case 'b':
break_pc = hextoint(optarg);
break;
case 'a':
a = hextoint(optarg);
break;
case 'x':
x = hextoint(optarg);
break;
case 'y':
y = hextoint(optarg);
break;
case 's':
sp = hextoint(optarg);
break;
case 'p':
sr = hextoint(optarg);
break;
case 'r':
case 'g':
pc = hextoint(optarg);
break;
case 'c':
cycles = atol(optarg);
break;
case 'l':
load_addr = hextoint(optarg);
break;
case 'h':
default: /* '?' */
usage(argv);
exit(EXIT_FAILURE);
}
}
if (optind >= argc) {
fprintf(stderr, "Error: expected binary file to load\n\n");
usage(argv);
exit(EXIT_FAILURE);
}
if (load_rom(argv[optind], load_addr) != 0) {
printf("Error loading \"%s\".\n", argv[optind]);
return EXIT_FAILURE;
}
if (interactive) {
printf("*** Entering interactive mode. CTRL+X to exit ***\n\n");
raw_stdin(); // allow individual keystrokes to be detected
}
//init_tables();
init_uart();
reset_cpu(a, x, y, sp, sr, pc);
run_cpu(cycles, verbose, mem_dump, break_pc, fast);
return EXIT_SUCCESS;
}