Implement 386 instruction table, improve 8086/186/286 instruction table
[multi_emu.git] / emu_6800.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 "sim68xx/inc/base/cpu.h"
8 #include "sim68xx/inc/arch/m68xx/instr.h"
9 #include "sim68xx/inc/arch/m68xx/reg.h"
10 #else
11 #include "cpu_6800.h"
12 #endif
13
14 #define REG_TRACE 1
15 #define MEM_TRACE 1
16
17 #define MEM_SIZE 0x10000
18 uint8_t mem[MEM_SIZE];
19
20 void load_s19(char *name) {
21   FILE *fp = fopen(name, "r");
22   if (fp == NULL) {
23     perror(name);
24     exit(EXIT_FAILURE);
25   }
26
27   char line[0x100];
28   while (fgets(line, 0x100, fp)) {
29     for (char *p = line; *p; ++p)
30       if (*p == '\n') {
31         *p = 0;
32         break;
33       }
34
35     // allow comments and concatenation
36     if (line[0] != 'S' || line[1] != '1')
37       continue;
38
39     uint8_t buf[0x7f];
40     int len;
41     for (len = 0; len < 0x7f; ++len) {
42       char *p = line + 2 + len * 2;
43       if (*p == 0)
44         break;
45       if (*p == '\n') {
46         *p = 0;
47         break;
48       }
49       uint8_t c = p[2];
50       p[2] = 0;
51
52       char *q;
53       buf[len] = (uint8_t)strtol(p, &q, 16);
54       p[2] = c;
55       if (q != p + 2) {
56         fprintf(stderr, "not hex byte: %s\n", p);
57         exit(EXIT_FAILURE);
58       }
59     }
60
61     if (len < 4) {
62       fprintf(stderr, "too short: %s\n", line);
63       exit(EXIT_FAILURE);
64     }
65
66     uint8_t checksum = 0;
67     for (int i = 0; i < len; ++i)
68       checksum += buf[i];
69     if (checksum != 0xff) {
70       checksum -= 0xff + buf[len - 1];
71       fprintf(
72         stderr,
73         "checksum %02x, should be %02x\n",
74         checksum,
75         buf[len - 1]
76       );
77       exit(EXIT_FAILURE);
78     }
79
80     if (len != buf[0] + 1) {
81       fprintf(stderr, "incorrect length: %s\n", line);
82       exit(EXIT_FAILURE);
83     }
84     len -= 4;
85
86     int addr = (buf[1] << 8) | buf[2], end_addr;
87     end_addr = addr + len;
88     if (end_addr < addr || end_addr > MEM_SIZE) {
89       fprintf(stderr, "invalid load range: [0x%x, 0x%x)\n", addr, end_addr);
90       exit(EXIT_FAILURE);
91     }
92     memcpy(mem + addr, buf + 3, len);
93   }
94
95   fclose(fp);
96 }
97
98 int read_byte(void *context, int addr) {
99   int data;
100   switch (addr) {
101   case 0xf001:
102     data = getchar();
103     switch (data) {
104     case '\n':
105       data = '\r';
106       break;
107     case 0x7f:
108       data = '\b';
109       break;
110     case EOF:
111       exit(EXIT_SUCCESS);
112       break;
113     }
114     break;
115   default:
116     data = mem[addr];
117     break;
118   }
119 #if MEM_TRACE
120   fprintf(stderr, "addr=%04x rd=%02x\n", addr, data);
121 #endif
122   return data;
123 }
124
125 void write_byte(void *context, int addr, int data) {
126 #if MEM_TRACE
127   fprintf(stderr, "addr=%04x wr=%02x\n", addr, data);
128 #endif
129   switch (addr) {
130   case 0xf000:
131     break;
132   case 0xf001:
133     data &= 0x7f;
134     switch (data) {
135     case '\r':
136       putchar('\n');
137       break;
138     case '\n':
139       break;
140     default:
141       putchar(data);
142       break;
143     }
144     break;
145   default:
146     mem[addr] = data;
147   }
148 }
149
150 #if ALT_BACKEND
151 int nerrors;
152
153 u_char mem_getb(u_int addr) {
154   return read_byte(NULL, addr);
155 }
156
157 u_int mem_getw(u_int addr) {
158   /* Make sure hi byte is accessed first */
159   u_char hi = mem_getb(addr);
160   u_char lo = mem_getb(addr + 1);
161   return (hi << 8) | lo;
162 }
163
164 void mem_putb(u_int addr, u_char value) {
165   write_byte(NULL, addr, value);
166 }
167
168 void mem_putw(u_int addr, u_int value) {
169   mem_putb(addr, value >> 8);           /* hi byte */
170   mem_putb(addr + 1, value & 0xFF);     /* lo byte */
171 }
172 #endif
173
174 int main(int argc, char **argv) {
175   if (argc < 2) {
176     printf("usage: %s image.s19\n", argv[0]);
177     exit(EXIT_FAILURE);
178   }
179   load_s19(argv[1]);
180
181   mem[0xf000] = 3; // bit 0 = rdrf, bit 1 = tdre
182
183 #if ALT_BACKEND
184   cpu_reset();
185
186   while (true) {
187 #if REG_TRACE
188     fprintf(
189       stderr,
190       "pc=%04x a=%02x b=%02x s=%04x x=%04x p=%02x hf=%d if=%d nf=%d zf=%d vf=%d cf=%d\n",
191       regs.pc,
192       regs.accd.a,
193       regs.accd.b,
194       regs.sp,
195       regs.ix,
196       regs.ccr | 0xc0,
197       (regs.ccr >> 5) & 1,
198       (regs.ccr >> 4) & 1,
199       (regs.ccr >> 3) & 1,
200       (regs.ccr >> 2) & 1,
201       (regs.ccr >> 1) & 1,
202       regs.ccr & 1
203     );
204 #endif
205
206     instr_exec();
207   }
208 #else
209   struct cpu_6800 cpu;
210   cpu_6800_init(&cpu, read_byte, NULL, write_byte, NULL);
211   cpu_6800_reset(&cpu);
212
213   while (true) {
214 #if REG_TRACE
215     fprintf(
216       stderr,
217       "pc=%04x a=%02x b=%02x s=%04x x=%04x p=%02x hf=%d if=%d nf=%d zf=%d vf=%d cf=%d\n",
218       cpu.regs.word.pc,
219       cpu.regs.byte.a,
220       cpu.regs.byte.b,
221       cpu.regs.word.s,
222       cpu.regs.word.x,
223       cpu.regs.byte.p,
224       cpu.regs.bit.hf,
225       cpu.regs.bit._if,
226       cpu.regs.bit.nf,
227       cpu.regs.bit.zf,
228       cpu.regs.bit.vf,
229       cpu.regs.bit.cf
230     );
231 #endif
232
233     cpu_6800_execute(&cpu);
234   }
235 #endif
236
237   return 0;
238 }