Implement 386 instruction table, improve 8086/186/286 instruction table
[multi_emu.git] / emu_6809.c
1 #include <stdbool.h>
2 #include <stdint.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #if ALT_BACKEND
7 #include "VCC/mc6809.h"
8 #include "VCC/tcc1014mmu.h"
9 #else
10 #include "cpu_6809.h"
11 #endif
12
13 #define REG_TRACE 1
14 #define MEM_TRACE 1
15
16 #define MEM_SIZE 0x10000
17 uint8_t mem[MEM_SIZE];
18
19 int load_ihx(char *name) {
20   FILE *fp = fopen(name, "r");
21   if (fp == NULL) {
22     perror(name);
23     exit(EXIT_FAILURE);
24   }
25
26   int base = 0, entry_point = 0;
27   bool had_eof = false;
28   char line[0x100];
29   while (fgets(line, 0x100, fp)) {
30     for (char *p = line; *p; ++p)
31       if (*p == '\n') {
32         *p = 0;
33         break;
34       }
35
36     if (had_eof) {
37       fprintf(stderr, "garbage after EOF record: %s\n", line);
38       exit(EXIT_FAILURE);
39     }
40
41     if (line[0] != ':') {
42       fprintf(stderr, "require colon: %s\n", line);
43       exit(EXIT_FAILURE);
44     }
45
46     uint8_t buf[0x7f];
47     int len;
48     for (len = 0; len < 0x7f; ++len) {
49       char *p = line + 1 + len * 2;
50       if (*p == 0)
51         break;
52       if (*p == '\n') {
53         *p = 0;
54         break;
55       }
56       uint8_t c = p[2];
57       p[2] = 0;
58
59       char *q;
60       buf[len] = (uint8_t)strtol(p, &q, 16);
61       p[2] = c;
62       if (q != p + 2) {
63         fprintf(stderr, "not hex byte: %s\n", p);
64         exit(EXIT_FAILURE);
65       }
66     }
67
68     if (len == 0) {
69       fprintf(stderr, "empty line: %s\n", line);
70       exit(EXIT_FAILURE);
71     }
72
73     uint8_t checksum = 0;
74     for (int i = 0; i < len; ++i)
75       checksum += buf[i];
76     if (checksum) {
77       checksum -= buf[len - 1];
78       fprintf(
79         stderr,
80         "checksum %02x, should be %02x\n",
81         checksum,
82         buf[len - 1]
83       );
84       exit(EXIT_FAILURE);
85     }
86
87     len -= 5;
88     if (len != buf[0]) {
89       fprintf(stderr, "incorrect length: %s\n", line);
90       exit(EXIT_FAILURE);
91     }
92
93     int addr = (buf[1] << 8) | buf[2], end_addr;
94     switch (buf[3]) {
95     case 0:
96       addr += base;
97       end_addr = addr + len;
98       if (end_addr < addr || end_addr > MEM_SIZE) {
99         fprintf(stderr, "invalid load range: [0x%x, 0x%x)\n", addr, end_addr);
100         exit(EXIT_FAILURE);
101       }
102       memcpy(mem + addr, buf + 4, len);
103       break;
104     case 1:
105       had_eof = true;
106       break;
107     case 4:
108       if (len < 2) {
109         fprintf(stderr, "invalid extended linear address record: %s\n", line);
110         exit(EXIT_FAILURE);
111       }
112       base = (buf[4] << 24) | (buf[5] << 16);
113       break;
114     case 5:
115       if (len < 4) {
116         fprintf(stderr, "invalid start linear address record: %s\n", line);
117         exit(EXIT_FAILURE);
118       }
119       entry_point = (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7];
120       break;
121     default:
122       fprintf(stderr, "unknown record type: 0x%x\n", buf[3]);
123       exit(EXIT_FAILURE);
124     }
125   }
126   if (!had_eof) {
127     fprintf(stderr, "no EOF record\n");
128     exit(EXIT_FAILURE);
129   }
130
131   fclose(fp);
132   return entry_point;
133 }
134
135 int read_byte(void *context, int addr) {
136   int data;
137   switch (addr) {
138   case 0xa001:
139     data = getchar();
140     switch (data) {
141     case '\n':
142       data = '\r';
143       break;
144     case 0x7f:
145       data = '\b';
146       break;
147     case EOF:
148       exit(EXIT_SUCCESS);
149       break;
150     }
151     break;
152   default:
153     data = mem[addr];
154     break;
155   }
156 #if MEM_TRACE
157   fprintf(stderr, "addr=%04x rd=%02x\n", addr, data);
158 #endif
159   return data;
160 }
161
162 void write_byte(void *context, int addr, int data) {
163 #if MEM_TRACE
164   fprintf(stderr, "addr=%04x wr=%02x\n", addr, data);
165 #endif
166   switch (addr) {
167   case 0xa000:
168     break;
169   case 0xa001:
170     data &= 0x7f;
171     switch (data) {
172     case '\r':
173       putchar('\n');
174       break;
175     case '\n':
176       break;
177     default:
178       putchar(data);
179       break;
180     }
181     break;
182   default:
183     mem[addr] = data;
184   }
185 }
186
187 #if ALT_BACKEND
188 int JS_Ramp_Clock;
189
190 void SetMapType(unsigned char type) {
191 }
192
193 unsigned char MemRead8(short unsigned int addr) {
194   return read_byte(NULL, addr);
195 }
196
197 unsigned short MemRead16(unsigned short addr) {
198   int result = MemRead8(addr) << 8;
199   return result | MemRead8(addr + 1);
200 }
201
202 void MemWrite8(unsigned char value, unsigned short addr) {
203   write_byte(NULL, addr, value);
204 }
205
206 void MemWrite16(unsigned short data,unsigned short addr) {
207   MemWrite8(data >> 8, addr);
208   MemWrite8(data & 0xFF, addr + 1);
209   return;
210 }
211 #endif
212
213 int main(int argc, char **argv) {
214   if (argc < 2) {
215     printf("usage: %s image.ihx\n", argv[0]);
216     exit(EXIT_FAILURE);
217   }
218   load_ihx(argv[1]);
219
220   mem[0xa000] = 3; // bit 0 = rdrf, bit 1 = tdre
221
222 #if ALT_BACKEND
223   MC6809Init();
224   MC6809Reset();
225
226   while (true) {
227 #if REG_TRACE
228     fprintf(
229       stderr,
230       "pc=%04x d=%04x u=%04x s=%04x x=%04x y=%04x cc=%02x ef=%d ff=%d hf=%d if=%d nf=%d zf=%d vf=%d cf=%d\n",
231       pc.Reg,
232       d.Reg,
233       u.Reg,
234       s.Reg,
235       x.Reg,
236       y.Reg,
237       cc[0] |
238       (cc[1] << 1) |
239       (cc[2] << 2) |
240       (cc[3] << 3) |
241       (cc[4] << 4) |
242       (cc[5] << 5) |
243       (cc[6] << 6) |
244       (cc[7] << 7),
245       cc[7],
246       cc[6],
247       cc[5],
248       cc[4],
249       cc[3],
250       cc[2],
251       cc[1],
252       cc[0]
253     );
254 #endif
255
256     MC6809Exec(1);
257   }
258 #else
259   struct cpu_6809 cpu;
260   cpu_6809_init(&cpu, read_byte, NULL, write_byte, NULL);
261   cpu_6809_reset(&cpu);
262
263   while (true) {
264 #if REG_TRACE
265     fprintf(
266       stderr,
267       "pc=%04x d=%04x u=%04x s=%04x x=%04x y=%04x cc=%02x ef=%d ff=%d hf=%d if=%d nf=%d zf=%d vf=%d cf=%d\n",
268       cpu.regs.word.pc,
269       cpu.regs.word.d,
270       cpu.regs.word.u,
271       cpu.regs.word.s,
272       cpu.regs.word.x,
273       cpu.regs.word.y,
274       cpu.regs.byte.cc,
275       cpu.regs.bit.ef,
276       cpu.regs.bit.ff,
277       cpu.regs.bit.hf,
278       cpu.regs.bit._if,
279       cpu.regs.bit.nf,
280       cpu.regs.bit.zf,
281       cpu.regs.bit.vf,
282       cpu.regs.bit.cf
283     );
284 #endif
285
286     cpu_6809_execute(&cpu);
287   }
288 #endif
289
290   return 0;
291 }