Can now load the entire executable, doesn't run
[userspace_emu.git] / emu_68000.c
1 #include <endian.h>
2 #include <fcntl.h>
3 #include <stdbool.h>
4 #include <stdint.h>
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include <unistd.h>
9 #if ALT_BACKEND
10 #include "Musashi/m68k.h"
11 #else
12 #include "cpu_68000.h"
13 #endif
14 #include "x_exec.h"
15
16 #define PAGE_SIZE 0x1000
17 #define EXCEPTION_TRAP_BASE 0x20
18
19 #define REG_TRACE 1
20 #define MEM_TRACE 1
21
22 #define MEM_SIZE 0x20000
23 #if __BYTE_ORDER == __LITTLE_ENDIAN
24 #define MEM_SIZE_M1 (MEM_SIZE - 1)
25 #define MEM_SIZE_M2 (MEM_SIZE - 2)
26 #define MEM_SIZE_M4 (MEM_SIZE - 4)
27 #else
28 #define MEM_SIZE_M1 0
29 #define MEM_SIZE_M2 0
30 #define MEM_SIZE_M4 0
31 #endif
32 union {
33   uint8_t b[MEM_SIZE];
34   uint16_t w[MEM_SIZE >> 1];
35   uint32_t l[MEM_SIZE >> 2];
36 } mem;
37
38 // used with be_read() and be_write()
39 // when host/target endianness differs, pass pointer to end of buffer,
40 // and then the buffer will be read or written backwards from the end
41 #if __BYTE_ORDER == __LITTLE_ENDIAN
42 #define BE_ARR(name) ((uint8_t *)(name) + sizeof(name))
43 #define BE_PTR(name) ((uint8_t *)&(name) + sizeof(name))
44 #define BE_XOR ((size_t)-1)
45 #else
46 #define BE_ARR(name) ((uint8_t *)(name) + sizeof(name))
47 #define BE_PTR(name) ((uint8_t *)&(name))
48 #define BE_XOR 0
49 #endif
50
51 uint8_t *be_buf;
52 size_t be_buf_size;
53
54 void be_resize(size_t count) {
55   free(be_buf);
56   be_buf = malloc(count);
57   if (be_buf == NULL) {
58     perror("realloc()");
59     exit(EXIT_FAILURE);
60   }
61   be_buf_size = count;
62 }
63
64 ssize_t be_read(int fd, uint8_t *buf, size_t count) {
65   if (count > be_buf_size)
66     be_resize(count);
67
68   ssize_t result = read(fd, be_buf, count);
69   if (result == (ssize_t)-1)
70     return (ssize_t)-1;
71
72   for (size_t i = 0; i < (size_t)result; ++i)
73     buf[i ^ BE_XOR] = be_buf[i];
74
75   return result;
76 }
77
78 ssize_t be_write(int fd, uint8_t *buf, size_t count) {
79   if (count > be_buf_size)
80     be_resize(count);
81
82   for (size_t i = 0; i < count; ++i)
83     be_buf[i] = buf[i ^ BE_XOR];
84
85   return write(fd, be_buf, count);
86 }
87
88 int load_aout(char *name) {
89   int fd = open(name, O_RDONLY);
90   if (fd == -1) {
91     perror(name);
92     exit(EXIT_FAILURE);
93   }
94
95   struct x_exec aout_header;
96   ssize_t result = be_read(fd, BE_PTR(aout_header), sizeof(aout_header));
97   if (result == (ssize_t)-1) {
98     perror("read()");
99     exit(EXIT_FAILURE);
100   }
101   if (result != sizeof(aout_header)) {
102     fprintf(stderr, "short read\n");
103     exit(EXIT_FAILURE);
104   }
105
106   if (aout_header.x_a_magic != x_ZMAGIC) {
107     fprintf(stderr, "unrecognized magic 0%o\n", aout_header.x_a_magic);
108     exit(EXIT_FAILURE);
109   }
110
111   if (aout_header.x_a_mid != x_MID_HP300) {
112     fprintf(stderr, "unrecognized machine ID 0%o\n", aout_header.x_a_mid);
113     exit(EXIT_FAILURE);
114   }
115
116   // text_base == 0
117   size_t data_base = (
118     ((size_t)aout_header.x_a_text + (PAGE_SIZE - 1)) & ~PAGE_SIZE
119   );
120   size_t bss_base = data_base + (
121     ((size_t)aout_header.x_a_data + (PAGE_SIZE - 1)) & ~PAGE_SIZE
122   );
123   size_t end = bss_base + (size_t)aout_header.x_a_bss;
124   if (end > MEM_SIZE) {
125     fprintf(stderr, "too large\n");
126     exit(EXIT_FAILURE);
127   }
128
129   // read text
130   if (lseek(fd, PAGE_SIZE, SEEK_SET) == (off_t)-1) {
131     perror("lseek()");
132     exit(EXIT_FAILURE);
133   }
134
135   /*ssize_t*/ result = be_read(fd, BE_PTR(mem), aout_header.x_a_text);
136   if (result == (ssize_t)-1) {
137     perror("read()");
138     exit(EXIT_FAILURE);
139   }
140   if (result != aout_header.x_a_text) {
141     fprintf(stderr, "short read\n");
142     exit(EXIT_FAILURE);
143   }
144
145   // read data
146   if (lseek(fd, PAGE_SIZE + data_base, SEEK_SET) == (off_t)-1) {
147     perror("lseek()");
148     exit(EXIT_FAILURE);
149   }
150
151   /*ssize_t*/ result = be_read(
152     fd,
153     BE_PTR(mem) + (data_base ^ BE_XOR),
154     aout_header.x_a_data
155   );
156   if (result == (ssize_t)-1) {
157     perror("read()");
158     exit(EXIT_FAILURE);
159   }
160   if (result != aout_header.x_a_data) {
161     fprintf(stderr, "short read\n");
162     exit(EXIT_FAILURE);
163   }
164
165   close(fd);
166
167   return aout_header.x_a_entry;
168 }
169
170 int read_byte(void *context, int addr) {
171   int data;
172   switch (addr) {
173   case 0x10040:
174     return 3; // bit 0 = rdrf, bit 1 = tdre
175   case 0x10042:
176     data = getchar();
177     switch (data) {
178     case '\n':
179       data = '\r';
180       break;
181     case 0x7f:
182       data = '\b';
183       break;
184 #if 0 // just keep sending 0xff at EOF
185     case EOF:
186       exit(EXIT_SUCCESS);
187       break;
188 #endif
189     }
190     break;
191   default:
192     if (addr < 0 || addr >= MEM_SIZE) {
193       fprintf(stderr, "invalid read byte: %06x\n", addr);
194       exit(EXIT_FAILURE);
195     }
196     data = mem.b[addr ^ MEM_SIZE_M1];
197     break;
198   }
199 #if MEM_TRACE
200   fprintf(stderr, "addr=%06x rd=%02x\n", addr, data);
201 #endif
202   return data;
203 }
204
205 int read_word(void *context, int addr) {
206   if (addr < 0 || addr >= MEM_SIZE || (addr & 1)) {
207     fprintf(stderr, "invalid read word: %06x\n", addr);
208     exit(EXIT_FAILURE);
209   }
210   int data = mem.w[(addr ^ MEM_SIZE_M2) >> 1];
211 #if MEM_TRACE
212   fprintf(stderr, "addr=%06x rd=%04x\n", addr, data);
213 #endif
214   return data;
215 }
216
217 int read_long(void *context, int addr) {
218   if (addr < 0 || addr >= MEM_SIZE - 2 || (addr & 1)) {
219     fprintf(stderr, "invalid read long: %06x\n", addr);
220     exit(EXIT_FAILURE);
221   }
222   int data =
223     (mem.w[(addr ^ MEM_SIZE_M2) >> 1] << 16) |
224     mem.w[((addr + 2) ^ MEM_SIZE_M2) >> 1];
225 #if MEM_TRACE
226   fprintf(stderr, "addr=%06x rd=%08x\n", addr, data);
227 #endif
228   return data;
229 }
230
231 void write_byte(void *context, int addr, int data) {
232 #if MEM_TRACE
233   fprintf(stderr, "addr=%06x wr=%02x\n", addr, data);
234 #endif
235   switch (addr) {
236   case 0x10040:
237     break;
238   case 0x10042:
239     data &= 0x7f;
240     switch (data) {
241     case '\r':
242       putchar('\n');
243       break;
244     case '\n':
245       break;
246     default:
247       putchar(data);
248       break;
249     }
250     break;
251   default:
252     if (addr < 0 || addr >= MEM_SIZE) {
253       fprintf(stderr, "invalid write byte: %06x\n", addr);
254       exit(EXIT_FAILURE);
255     }
256     mem.b[addr ^ MEM_SIZE_M1] = data;
257   }
258 }
259
260 void write_word(void *context, int addr, int data) {
261 #if MEM_TRACE
262   fprintf(stderr, "addr=%06x wr=%04x\n", addr, data);
263 #endif
264   if (addr < 0 || addr >= MEM_SIZE || (addr & 1)) {
265     fprintf(stderr, "invalid write word: %06x\n", addr);
266     exit(EXIT_FAILURE);
267   }
268   mem.w[(addr ^ MEM_SIZE_M2) >> 1] = data;
269 }
270
271 void write_long(void *context, int addr, int data) {
272 #if MEM_TRACE
273   fprintf(stderr, "addr=%06x wr=%08x\n", addr, data);
274 #endif
275   if (addr < 0 || addr >= MEM_SIZE - 2 || (addr & 1)) {
276     fprintf(stderr, "invalid write long: %06x\n", addr);
277     exit(EXIT_FAILURE);
278   }
279   mem.w[(addr ^ MEM_SIZE_M2) >> 1] = data >> 16;
280   mem.w[((addr + 2) ^ MEM_SIZE_M2) >> 1] = data;
281 }
282
283 #if ALT_BACKEND
284 unsigned int m68k_read_memory_8(unsigned int address) {
285   return read_byte(NULL, address);
286 }
287
288 unsigned int m68k_read_memory_16(unsigned int address) {
289   return read_word(NULL, address);
290 }
291
292 unsigned int m68k_read_memory_32(unsigned int address) {
293   return read_long(NULL, address);
294 }
295
296 void m68k_write_memory_8(unsigned int address, unsigned int value) {
297   write_byte(NULL, address, value);
298 }
299
300 void m68k_write_memory_16(unsigned int address, unsigned int value) {
301   write_word(NULL, address, value);
302 }
303
304 void m68k_write_memory_32(unsigned int address, unsigned int value) {
305   write_long(NULL, address, value);
306 }
307
308 /* Called when the CPU pulses the RESET line */
309 void cpu_pulse_reset(void)
310 {
311 //      nmi_device_reset();
312 //      output_device_reset();
313 //      input_device_reset();
314 }
315
316 /* Called when the CPU changes the function code pins */
317 void cpu_set_fc(unsigned int fc)
318 {
319 //      g_fc = fc;
320 }
321
322 /* Called when the CPU acknowledges an interrupt */
323 int cpu_irq_ack(int level)
324 {
325 //      switch(level)
326 //      {
327 //              case IRQ_NMI_DEVICE:
328 //                      return nmi_device_ack();
329 //              case IRQ_INPUT_DEVICE:
330 //                      return input_device_ack();
331 //              case IRQ_OUTPUT_DEVICE:
332 //                      return output_device_ack();
333 //      }
334 //      return M68K_INT_ACK_SPURIOUS;
335   return 0;
336 }
337
338 int m68k_service_trap(unsigned int vector) {
339   //fprintf(stderr, "trap %x\n", vector);
340   if (vector == EXCEPTION_TRAP_BASE + 0xe) // TBI68K bye command
341     exit(EXIT_SUCCESS);
342   return 0;
343 }
344 #endif
345
346 int main(int argc, char **argv) {
347   if (argc < 2) {
348     printf("usage: %s executable\n", argv[0]);
349     exit(EXIT_FAILURE);
350   }
351   int entry_point = load_aout(argv[1]);
352   printf("entry_point %08x\n", entry_point);
353
354 #if ALT_BACKEND
355   m68k_init();
356   m68k_set_cpu_type(M68K_CPU_TYPE_68000);
357   m68k_pulse_reset();
358   m68k_set_reg(M68K_REG_PC, entry_point);
359   m68k_set_reg(M68K_REG_SP, MEM_SIZE);
360
361   while (true) {
362 #if REG_TRACE
363     int sr = m68k_get_reg(NULL, M68K_REG_SR);
364     fprintf(
365       stderr,
366       "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",
367       m68k_get_reg(NULL, M68K_REG_PC),
368       m68k_get_reg(NULL, M68K_REG_D0),
369       m68k_get_reg(NULL, M68K_REG_D1),
370       m68k_get_reg(NULL, M68K_REG_D2),
371       m68k_get_reg(NULL, M68K_REG_D3),
372       m68k_get_reg(NULL, M68K_REG_D4),
373       m68k_get_reg(NULL, M68K_REG_D5),
374       m68k_get_reg(NULL, M68K_REG_D6),
375       m68k_get_reg(NULL, M68K_REG_D7),
376       m68k_get_reg(NULL, M68K_REG_A0),
377       m68k_get_reg(NULL, M68K_REG_A1),
378       m68k_get_reg(NULL, M68K_REG_A2),
379       m68k_get_reg(NULL, M68K_REG_A3),
380       m68k_get_reg(NULL, M68K_REG_A4),
381       m68k_get_reg(NULL, M68K_REG_A5),
382       m68k_get_reg(NULL, M68K_REG_A6),
383       m68k_get_reg(NULL, M68K_REG_A7),
384       sr,
385       (sr >> 4) & 1,
386       (sr >> 3) & 1,
387       (sr >> 2) & 1,
388       (sr >> 1) & 1,
389       sr & 1
390     );
391 #endif
392
393     m68k_execute(1);
394   }
395 #else
396   struct cpu_68000 cpu;
397   cpu_68000_init(&cpu, read_byte, NULL, write_byte, NULL);
398   cpu_68000_reset(&cpu);
399
400   while (true) {
401 #if REG_TRACE
402     fprintf(
403       stderr,
404       "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",
405       cpu.regs.word.pc,
406       cpu.regs.byte.a,
407       cpu.regs.byte.b,
408       cpu.regs.word.s,
409       cpu.regs.word.x,
410       cpu.regs.byte.p,
411       cpu.regs.bit.hf,
412       cpu.regs.bit._if,
413       cpu.regs.bit.nf,
414       cpu.regs.bit.zf,
415       cpu.regs.bit.vf,
416       cpu.regs.bit.cf
417     );
418 #endif
419
420     cpu_68000_execute(&cpu);
421   }
422 #endif
423
424   return 0;
425 }