Implement 386 instruction table, improve 8086/186/286 instruction table
[multi_emu.git] / emu_68000.c
1 #include <endian.h>
2 #include <stdbool.h>
3 #include <stdint.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #if ALT_BACKEND
8 #include "Musashi/m68k.h"
9 #else
10 #include "cpu_68000.h"
11 #endif
12
13 #define EXCEPTION_TRAP_BASE 0x20
14
15 #define REG_TRACE 0
16 #define MEM_TRACE 0
17
18 #define MEM_SIZE 0x8000
19 #if __BYTE_ORDER == __LITTLE_ENDIAN
20 #define MEM_SIZE_M1 (MEM_SIZE - 1)
21 #define MEM_SIZE_M2 (MEM_SIZE - 2)
22 #define MEM_SIZE_M4 (MEM_SIZE - 4)
23 #else
24 #define MEM_SIZE_M1 0
25 #define MEM_SIZE_M2 0
26 #define MEM_SIZE_M4 0
27 #endif
28 union {
29   uint8_t b[MEM_SIZE];
30   uint16_t w[MEM_SIZE >> 1];
31   uint32_t l[MEM_SIZE >> 2];
32 } mem;
33
34 void load_s19(char *name) {
35   FILE *fp = fopen(name, "r");
36   if (fp == NULL) {
37     perror(name);
38     exit(EXIT_FAILURE);
39   }
40
41   char line[0x100];
42   while (fgets(line, 0x100, fp)) {
43     for (char *p = line; *p; ++p)
44       if (*p == '\n') {
45         *p = 0;
46         break;
47       }
48
49     // allow comments and concatenation
50     if (line[0] != 'S' || line[1] != '1')
51       continue;
52
53     uint8_t buf[0x7f];
54     int len;
55     for (len = 0; len < 0x7f; ++len) {
56       char *p = line + 2 + len * 2;
57       if (*p == 0)
58         break;
59       if (*p == '\n') {
60         *p = 0;
61         break;
62       }
63       uint8_t c = p[2];
64       p[2] = 0;
65
66       char *q;
67       buf[len] = (uint8_t)strtol(p, &q, 16);
68       p[2] = c;
69       if (q != p + 2) {
70         fprintf(stderr, "not hex byte: %s\n", p);
71         exit(EXIT_FAILURE);
72       }
73     }
74
75     if (len < 4) {
76       fprintf(stderr, "too short: %s\n", line);
77       exit(EXIT_FAILURE);
78     }
79
80     uint8_t checksum = 0;
81     for (int i = 0; i < len; ++i)
82       checksum += buf[i];
83     if (checksum != 0xff) {
84       checksum -= 0xff + buf[len - 1];
85       fprintf(
86         stderr,
87         "checksum %02x, should be %02x\n",
88         checksum,
89         buf[len - 1]
90       );
91       exit(EXIT_FAILURE);
92     }
93
94     if (len != buf[0] + 1) {
95       fprintf(stderr, "incorrect length: %s\n", line);
96       exit(EXIT_FAILURE);
97     }
98     len -= 4;
99
100     int addr = (buf[1] << 8) | buf[2], end_addr;
101     end_addr = addr + len;
102     if (end_addr < addr || end_addr > MEM_SIZE) {
103       fprintf(stderr, "invalid load range: [0x%x, 0x%x)\n", addr, end_addr);
104       exit(EXIT_FAILURE);
105     }
106     for (int i = 0; i < len; ++i)
107       mem.b[(addr + i) ^ MEM_SIZE_M1] = buf[3 + i];
108   }
109
110   fclose(fp);
111 }
112
113 int read_byte(void *context, int addr) {
114   int data;
115   switch (addr) {
116   case 0x10040:
117     data = 3; // bit 0 = rdrf, bit 1 = tdre
118     break;
119   case 0x10042:
120     data = getchar();
121     switch (data) {
122     case '\n':
123       data = '\r';
124       break;
125     case 0x7f:
126       data = '\b';
127       break;
128 #if 0 // just keep sending 0xff at EOF
129     case EOF:
130       exit(EXIT_SUCCESS);
131       break;
132 #endif
133     }
134     break;
135   default:
136     if (addr < 0 || addr >= MEM_SIZE) {
137       fprintf(stderr, "invalid read byte: %06x\n", addr);
138       exit(EXIT_FAILURE);
139     }
140     data = mem.b[addr ^ MEM_SIZE_M1];
141     break;
142   }
143 #if MEM_TRACE
144   fprintf(stderr, "addr=%06x rd=%02x\n", addr, data);
145 #endif
146   return data;
147 }
148
149 int read_word(void *context, int addr) {
150   if (addr < 0 || addr >= MEM_SIZE || (addr & 1)) {
151     fprintf(stderr, "invalid read word: %06x\n", addr);
152     exit(EXIT_FAILURE);
153   }
154   int data = mem.w[(addr ^ MEM_SIZE_M2) >> 1];
155 #if MEM_TRACE
156   fprintf(stderr, "addr=%06x rd=%04x\n", addr, data);
157 #endif
158   return data;
159 }
160
161 int read_long(void *context, int addr) {
162   if (addr < 0 || addr >= MEM_SIZE - 2 || (addr & 1)) {
163     fprintf(stderr, "invalid read long: %06x\n", addr);
164     exit(EXIT_FAILURE);
165   }
166   int data =
167     (mem.w[(addr ^ MEM_SIZE_M2) >> 1] << 16) |
168     mem.w[((addr + 2) ^ MEM_SIZE_M2) >> 1];
169 #if MEM_TRACE
170   fprintf(stderr, "addr=%06x rd=%08x\n", addr, data);
171 #endif
172   return data;
173 }
174
175 void write_byte(void *context, int addr, int data) {
176 #if MEM_TRACE
177   fprintf(stderr, "addr=%06x wr=%02x\n", addr, data);
178 #endif
179   switch (addr) {
180   case 0x10040:
181     break;
182   case 0x10042:
183     data &= 0x7f;
184     switch (data) {
185     case '\r':
186       putchar('\n');
187       break;
188     case '\n':
189       break;
190     default:
191       putchar(data);
192       break;
193     }
194     break;
195   default:
196     if (addr < 0 || addr >= MEM_SIZE) {
197       fprintf(stderr, "invalid write byte: %06x\n", addr);
198       exit(EXIT_FAILURE);
199     }
200     mem.b[addr ^ MEM_SIZE_M1] = data;
201   }
202 }
203
204 void write_word(void *context, int addr, int data) {
205 #if MEM_TRACE
206   fprintf(stderr, "addr=%06x wr=%04x\n", addr, data);
207 #endif
208   if (addr < 0 || addr >= MEM_SIZE || (addr & 1)) {
209     fprintf(stderr, "invalid write word: %06x\n", addr);
210     exit(EXIT_FAILURE);
211   }
212   mem.w[(addr ^ MEM_SIZE_M2) >> 1] = data;
213 }
214
215 void write_long(void *context, int addr, int data) {
216 #if MEM_TRACE
217   fprintf(stderr, "addr=%06x wr=%08x\n", addr, data);
218 #endif
219   if (addr < 0 || addr >= MEM_SIZE - 2 || (addr & 1)) {
220     fprintf(stderr, "invalid write long: %06x\n", addr);
221     exit(EXIT_FAILURE);
222   }
223   mem.w[(addr ^ MEM_SIZE_M2) >> 1] = data >> 16;
224   mem.w[((addr + 2) ^ MEM_SIZE_M2) >> 1] = data;
225 }
226
227 #if ALT_BACKEND
228 unsigned int m68k_read_memory_8(unsigned int address) {
229   return read_byte(NULL, address);
230 }
231
232 unsigned int m68k_read_memory_16(unsigned int address) {
233   return read_word(NULL, address);
234 }
235
236 unsigned int m68k_read_memory_32(unsigned int address) {
237   return read_long(NULL, address);
238 }
239
240 void m68k_write_memory_8(unsigned int address, unsigned int value) {
241   write_byte(NULL, address, value);
242 }
243
244 void m68k_write_memory_16(unsigned int address, unsigned int value) {
245   write_word(NULL, address, value);
246 }
247
248 void m68k_write_memory_32(unsigned int address, unsigned int value) {
249   write_long(NULL, address, value);
250 }
251
252 /* Called when the CPU pulses the RESET line */
253 void cpu_pulse_reset(void)
254 {
255 //      nmi_device_reset();
256 //      output_device_reset();
257 //      input_device_reset();
258 }
259
260 /* Called when the CPU changes the function code pins */
261 void cpu_set_fc(unsigned int fc)
262 {
263 //      g_fc = fc;
264 }
265
266 /* Called when the CPU acknowledges an interrupt */
267 int cpu_irq_ack(int level)
268 {
269 //      switch(level)
270 //      {
271 //              case IRQ_NMI_DEVICE:
272 //                      return nmi_device_ack();
273 //              case IRQ_INPUT_DEVICE:
274 //                      return input_device_ack();
275 //              case IRQ_OUTPUT_DEVICE:
276 //                      return output_device_ack();
277 //      }
278 //      return M68K_INT_ACK_SPURIOUS;
279   return 0;
280 }
281
282 int m68k_service_trap(unsigned int vector) {
283   //fprintf(stderr, "trap %x\n", vector);
284   if (vector == EXCEPTION_TRAP_BASE + 0xe) // TBI68K bye command
285     exit(EXIT_SUCCESS);
286   return 0;
287 }
288 #endif
289
290 int main(int argc, char **argv) {
291   if (argc < 2) {
292     printf("usage: %s image.s19\n", argv[0]);
293     exit(EXIT_FAILURE);
294   }
295   load_s19(argv[1]);
296
297   // emulate Tutor firmware for TBI68K
298   mem.l[(0 ^ MEM_SIZE_M4) >> 2] = 0x8000; // initial SP
299   mem.l[(4 ^ MEM_SIZE_M4) >> 2] = 0x900; // initial PC
300
301 #if ALT_BACKEND
302   m68k_init();
303   m68k_set_cpu_type(M68K_CPU_TYPE_68000);
304   m68k_pulse_reset();
305
306   while (true) {
307 #if REG_TRACE
308     int sr = m68k_get_reg(NULL, M68K_REG_SR);
309     fprintf(
310       stderr,
311       "pc=%08x d0=%08x d1=%08x d2=%08x d3=%08x d4=%08x d5=%08x d6=%08x d7=%08x a0=%08x a1=%08x a2=%08x a3=%08x a4=%08x a5=%08x a6=%08x a7=%08x sr=%04x xf=%d nf=%d zf=%d vf=%d cf=%d\n",
312       m68k_get_reg(NULL, M68K_REG_PC),
313       m68k_get_reg(NULL, M68K_REG_D0),
314       m68k_get_reg(NULL, M68K_REG_D1),
315       m68k_get_reg(NULL, M68K_REG_D2),
316       m68k_get_reg(NULL, M68K_REG_D3),
317       m68k_get_reg(NULL, M68K_REG_D4),
318       m68k_get_reg(NULL, M68K_REG_D5),
319       m68k_get_reg(NULL, M68K_REG_D6),
320       m68k_get_reg(NULL, M68K_REG_D7),
321       m68k_get_reg(NULL, M68K_REG_A0),
322       m68k_get_reg(NULL, M68K_REG_A1),
323       m68k_get_reg(NULL, M68K_REG_A2),
324       m68k_get_reg(NULL, M68K_REG_A3),
325       m68k_get_reg(NULL, M68K_REG_A4),
326       m68k_get_reg(NULL, M68K_REG_A5),
327       m68k_get_reg(NULL, M68K_REG_A6),
328       m68k_get_reg(NULL, M68K_REG_A7),
329       sr,
330       (sr >> 4) & 1,
331       (sr >> 3) & 1,
332       (sr >> 2) & 1,
333       (sr >> 1) & 1,
334       sr & 1
335     );
336 #endif
337
338     m68k_execute(1);
339   }
340 #else
341   struct cpu_68000 cpu;
342   cpu_68000_init(&cpu, read_byte, NULL, write_byte, NULL);
343   cpu_68000_reset(&cpu);
344
345   while (true) {
346 #if REG_TRACE
347     fprintf(
348       stderr,
349       "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",
350       cpu.regs.word.pc,
351       cpu.regs.byte.a,
352       cpu.regs.byte.b,
353       cpu.regs.word.s,
354       cpu.regs.word.x,
355       cpu.regs.byte.p,
356       cpu.regs.bit.hf,
357       cpu.regs.bit._if,
358       cpu.regs.bit.nf,
359       cpu.regs.bit.zf,
360       cpu.regs.bit.vf,
361       cpu.regs.bit.cf
362     );
363 #endif
364
365     cpu_68000_execute(&cpu);
366   }
367 #endif
368
369   return 0;
370 }