Initial commit
[jwcc.git] / sim / blargcpu2.c
1 /*
2  * BlargCPU2
3  *
4  * A dummy CPU emulated on a microcode level, suitable for implementation in hardware.
5  *
6  * Copyright (c) 2005 Joshua Wise <joshua@joshuawise.com>.
7  * Copyright (c) 2005 Matthew Maurer <Fallen.Azrael@gmail.com>.
8  *
9  * All rights reserved.
10  */
11
12 /*
13 four registers + flag + pc + stack pointer
14
15 Insns:
16  0000 mov reg, lit16
17  0001 ldr reg, [reg]
18  0010 sto [reg], reg
19  0011 mov reg, reg
20  0100 add reg, reg
21  0101 tst reg, reg
22  0110 and reg, reg
23  0111 not reg
24  1000 push reg, reg
25  1001 pop reg, reg
26  1010 call reg, reg
27  1011 shr reg, reg
28  1100 shl reg, reg
29  
30 Predicates:
31  000 Never
32  001 Not-Equal
33  010 Equal
34  011 Less than
35  100 Greater than
36  111 Always
37
38 Opcode format:
39 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00
40 |--INSN---| |-PRED-|    |TREGISTER| |SREGISTER|
41
42 Vectors:
43   0 - start
44   4 - ISR
45 */
46
47 #include <stdio.h>
48 #include <sys/types.h>
49 #include <sys/stat.h>
50 #include <fcntl.h>
51 #include <unistd.h>
52 #include <stdlib.h>
53 #include <string.h>
54
55 #define STACK_LOC 0x8000
56
57 #define PRED_NV 0x0
58 #define PRED_NE 0x1
59 #define PRED_EQ 0x2
60 #define PRED_LT 0x3
61 #define PRED_GT 0x4
62 #define PRED_AL 0x7
63
64 #define FLAG_LT 0x1
65 #define FLAG_GT 0x2
66 #define FLAG_EQ 0x4
67
68 #define REG_R0 0x0
69 #define REG_R1 0x1
70 #define REG_R2 0x2
71 #define REG_R3 0x3
72 #define REG_FR 0x4
73 #define REG_PC 0x5
74 #define REG_SP 0x6
75
76 #define INSN_MOV_REG_LIT16 0x0
77 #define INSN_LDR_REG_ADR_REG 0x1
78 #define INSN_STO_ADR_REG_REG 0x2
79 #define INSN_MOV_REG_REG 0x3
80 #define INSN_ADD_REG_REG 0x4
81 #define INSN_TST_REG_REG 0x5
82 #define INSN_AND_REG_REG 0x6
83 #define INSN_NOT_REG 0x7
84 #define INSN_PUSH_REG_REG 0x8
85 #define INSN_POP_REG_REG 0x9
86 #define INSN_CALL_REG_REG 0xA
87 #define INSN_SHR_REG_REG 0xB
88 #define INSN_SHL_REG_REG 0xC
89
90 #define INSN(insn, pred, treg, sreg) (((insn) << 12) | ((pred) << 9) | ((treg) << 4) | ((sreg)))
91
92 /*******************************************************************/
93 /*******************************************************************/
94
95 struct peripheral {
96         struct peripheral *next;
97         
98         char *name;
99         unsigned short start;
100         unsigned short length;
101         unsigned short (*read)(struct peripheral*, unsigned short);
102         void (*write)(struct peripheral*, unsigned short, unsigned short);
103         void *priv;
104 };
105
106 struct peripheral *plist = NULL;
107
108 unsigned short null_read(struct peripheral *device, unsigned short address)
109 {
110         printf("%s: read to address %04x disallowed\n", device->name, address);
111         abort();
112 }
113
114 void null_write(struct peripheral *device, unsigned short address, unsigned short data)
115 {
116         printf("%s: write to address %04x disallowed\n", device->name, address);
117         abort();
118 }
119
120 unsigned short nodev_read(struct peripheral *device, unsigned short address)
121 {
122         printf("peripherals: no device to read from at address %04x\n", address);
123         abort();
124 }
125
126 void nodev_write(struct peripheral *device, unsigned short address, unsigned short data)
127 {
128         printf("peripherals: no device to write %04x to at address %04x\n", data, address);
129         abort();
130 }
131
132 struct peripheral noperiph = { NULL, "noperiph", 0x0, 0x0, nodev_read, nodev_write, NULL };
133
134 struct peripheral* peripheral_cache[65536 /* ouch! */];
135
136 /* this could be done in a more optimized manner by stepping through each periph and just setting the bits where it's at, but ... */
137 void peripheral_rehash()
138 {
139         int address;
140         
141         for (address = 0; address < 65536; address++)
142         {
143                 struct peripheral *p;
144                 
145                 peripheral_cache[address] = &noperiph;  /* No'bdy has harmed me!, quoth the Cyclops */
146                 
147                 for (p=plist; p; p = p->next)
148                         if ((p->start <= address) && ((p->start + p->length) > address))
149                         {
150                                 peripheral_cache[address] = p;
151                                 break;
152                         }
153         }
154 }
155
156 #define peripheral_get(address) (peripheral_cache[address])
157
158 void peripheral_add(struct peripheral *device)
159 {
160         device->next = plist;
161         plist = device;
162         if (!device->read)
163                 device->read = null_read;
164         if (!device->write)
165                 device->write = null_write;
166         peripheral_rehash();
167 }
168
169 void peripheral_remove(struct peripheral *device)
170 {
171         struct peripheral *temp, *ptemp;
172         
173         if (plist == device)
174         {
175                 plist = device->next;
176                 return;
177         }
178         
179         ptemp = plist;
180         for (temp = plist; temp; temp->next)
181                 if (temp == device)
182                         ptemp->next = device->next;
183         peripheral_rehash();
184 }
185
186 /*******************************************************************/
187
188 #define ROMSIZE 0x4000
189 unsigned short rom_data[ROMSIZE]= {
190         INSN(INSN_MOV_REG_LIT16,    PRED_AL, REG_R3,0       ), 9,           /*mov r3, 9*/           
191         INSN(INSN_MOV_REG_LIT16,    PRED_AL, REG_R0,0       ), '9',         /*mov r0, '9'*/         
192         INSN(INSN_MOV_REG_LIT16,    PRED_AL, REG_R1,0       ), 0x4000,      /*mov r1, 0x4000*/      
193         INSN(INSN_MOV_REG_LIT16,    PRED_AL, REG_R2,0       ), 0xFFFF,      /*mov r2, 0xFFFF*/
194         INSN(INSN_STO_ADR_REG_REG,  PRED_AL, REG_R1,REG_R0  ),              /* loop 0x0008 *//*mov [r1], r0*/
195         INSN(INSN_ADD_REG_REG,      PRED_AL, REG_R3,REG_R2  ),              /*add r3,r2*/
196         INSN(INSN_ADD_REG_REG,      PRED_AL, REG_R0,REG_R2  ),              /*add r0,r2*/
197         INSN(INSN_TST_REG_REG,      PRED_AL, REG_R3,REG_R2  ),              /* loop 0x0011 *//*test r3, r2*/
198         INSN(INSN_MOV_REG_LIT16,    PRED_NE, REG_PC,0       ), 0x0008,      /*jne 0x0008*/
199         INSN(INSN_MOV_REG_LIT16,    PRED_AL, REG_R0,0       ), '\n',        /*mov r0,0*/
200         INSN(INSN_STO_ADR_REG_REG,  PRED_AL, REG_R1,REG_R0  ),              /*mov [r1], r0*/
201         INSN(INSN_MOV_REG_LIT16,    PRED_AL, REG_PC,0       ), 0x0011,      /*jmp 0x0011*/
202 };
203
204 /*ROM Read*/
205 unsigned short rom_read(struct peripheral *device, unsigned short address)
206 {
207         return ((unsigned short*)device->priv)[address - device->start];
208 }
209
210 unsigned short rom_optread(struct peripheral *device, unsigned short address)
211 {
212         return ((unsigned short*)device->priv)[address];
213 }
214
215 void rom_add()
216 {
217         struct peripheral *p = (struct peripheral*)malloc(sizeof(struct peripheral));
218         p->name = "rom";
219         p->start = 0x0;
220         p->length = ROMSIZE;
221         p->read = (p->start == 0x0) ? &rom_optread : &rom_read;
222         p->write = NULL;
223         p->priv = &rom_data;    
224         peripheral_add(p);
225 }
226
227 /*******************************************************************/
228
229 #define RAMSIZE 32768
230 unsigned short ram_data[RAMSIZE];
231
232 unsigned short ram_read(struct peripheral *device, unsigned short address)
233 {
234         return ((unsigned short*)device->priv)[address - device->start];
235 }
236
237 void ram_write(struct peripheral *device, unsigned short address, unsigned short data)
238 {
239         ((unsigned short*)device->priv)[address - device->start] = data;
240 }
241
242 void ram_add()
243 {
244         struct peripheral *p = (struct peripheral*)malloc(sizeof(struct peripheral));
245         p->name = "ram";
246         p->start = 0x8000;
247         p->length = RAMSIZE;
248         p->read = &ram_read;
249         p->write = &ram_write;
250         p->priv = &ram_data;
251         peripheral_add(p);
252 }
253
254 /*******************************************************************/
255
256 #include "SDL.h"
257
258 struct blargfb {
259   SDL_Surface* screen;
260   SDL_Color palette[256];
261   unsigned short row, col;
262 };
263
264 Uint32 fb_events(Uint32 interval)
265 {
266         SDL_Event event;
267         
268         while (SDL_PollEvent(&event)) {
269                 switch (event.type) {
270                 case SDL_KEYDOWN:
271                         if (event.key.keysym.sym == SDLK_q)
272                                 exit(0);
273                         break;
274                 case SDL_QUIT:
275                         exit(0);
276                 }
277         }
278         return interval;
279 }
280
281 void fb_initsurface(struct blargfb *fb)
282 {
283         if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_NOPARACHUTE) < 0)
284         {
285                 printf("SDL init failed: %s, FB disabled\n", SDL_GetError());
286                 fb->screen = NULL;
287                 return;
288         }
289         atexit(SDL_Quit);
290         
291         fb->screen = SDL_SetVideoMode(320,240,8,SDL_SWSURFACE);
292         if (!fb->screen)
293         {
294                 printf("SDL video init failed: %s, FB disabled\n", SDL_GetError());
295                 return;
296         }
297         
298         SDL_WM_SetCaption("BlargCPU Framebuffer", "BlargFB");
299         
300         fb->palette[0].r = 0;   fb->palette[0].g = 0;   fb->palette[0].b = 0;
301         fb->palette[1].r = 127; fb->palette[1].g = 0;   fb->palette[1].b = 0;
302         fb->palette[2].r = 0;   fb->palette[2].g = 127; fb->palette[2].b = 0;
303         fb->palette[3].r = 0;   fb->palette[3].g = 0;   fb->palette[3].b = 127;
304         fb->palette[4].r = 255; fb->palette[4].g = 0;   fb->palette[4].b = 0;
305         fb->palette[5].r = 0;   fb->palette[5].g = 255; fb->palette[5].b = 0;
306         fb->palette[6].r = 0;   fb->palette[6].g = 0;   fb->palette[6].b = 255;
307         fb->palette[7].r = 255; fb->palette[7].g = 255; fb->palette[7].b = 255;
308         SDL_SetColors(fb->screen, fb->palette, 0, 8);
309         
310         SDL_SetTimer(50, fb_events);
311 }
312   
313 void fb_init(struct peripheral *device)
314 {
315         struct blargfb *priv = (struct blargfb*)device->priv;
316         priv->row = 0;
317         priv->col = 0;
318 }
319
320 unsigned short fb_read(struct peripheral *device, unsigned short address)
321 {
322         struct blargfb *priv = (struct blargfb*)device->priv;
323         unsigned char res;
324         
325         if (!priv->screen) fb_initsurface(priv);
326         
327         switch (address - device->start)
328         {
329         case 0: return priv->row;
330         case 1: return priv->col;
331         case 2: SDL_LockSurface(priv->screen);
332                 res = *((unsigned char*)(priv->screen->pixels + priv->row * priv->screen->pitch + priv->col));
333                 SDL_UnlockSurface(priv->screen);
334                 return res;
335         case 3: return 0;
336         default:printf("%s: read: incorrect offset %d\n", device->name, address - device->start);
337         };
338 }
339
340 void fb_write(struct peripheral *device, unsigned short address, unsigned short data)
341 {
342         struct blargfb *priv = (struct blargfb*)device->priv;
343         
344         if (!priv->screen) fb_initsurface(priv);
345         
346         switch (address - device->start)
347         {
348         case 0: priv->row = data; break;
349         case 1: priv->col = data; break;
350         case 2: SDL_LockSurface(priv->screen);
351                 *((unsigned char*)(priv->screen->pixels + priv->row * priv->screen->pitch + priv->col)) = data;
352                 SDL_UnlockSurface(priv->screen);
353                 break;
354         case 3: SDL_UpdateRect(priv->screen, 0, 0, 0, 0); break;
355         default:printf("%s: write: incorrect offset %d\n", device->name, address - device->start);
356         }
357 }
358
359 void fb_add()
360 {
361         struct peripheral *p = (struct peripheral*)malloc(sizeof(struct peripheral));
362         struct blargfb *fb = (struct blargfb*)malloc(sizeof(struct blargfb));
363         p->name = "fb";
364         p->start = 0x4100;
365         p->length = 0x4;
366         p->read = &fb_read;
367         p->write = &fb_write;
368         p->priv = fb;
369         fb_init(p);
370         peripheral_add(p);
371 }
372
373 /*******************************************************************/
374
375 void console_write(struct peripheral *device, unsigned short address, unsigned short data)
376 {
377 //      write(1, &data, 1);
378         printf("Console write: data: %04x (%d)\n", data, data);
379 }
380
381 void console_add()
382 {
383         struct peripheral *p = (struct peripheral*)malloc(sizeof(struct peripheral));
384         p->name = "console";
385         p->start = 0x4000;
386         p->length = 0x1;
387         p->read = NULL;
388         p->write = &console_write;
389         p->priv = NULL;
390         peripheral_add(p);
391 }
392
393 /*******************************************************************/
394
395 unsigned short fetch(unsigned short address)
396 {
397         struct peripheral* temp = peripheral_get(address);
398         return temp->read(temp, address);
399 }
400
401 void store(unsigned short address, unsigned short data)
402 {
403         struct peripheral* temp = peripheral_get(address);
404         temp->write(temp, address, data);
405 }
406
407 /*******************************************************************/
408 /*******************************************************************/
409
410 #include <readline/readline.h>
411 #include <readline/history.h>
412
413 static int indebugger = 0;
414 static int trace = 0;
415 static int breakpoint = -1;
416
417 unsigned short regs[7];
418
419 char* insntostr(unsigned short opc)
420 {
421         static char insn[] = "inspr rx,rx";
422         switch ((opc >> 12) & 0xF)
423         {
424         case INSN_MOV_REG_LIT16:        memcpy(insn, "mvc", 3); break;
425         case INSN_STO_ADR_REG_REG:      memcpy(insn, "sto", 3); break;
426         case INSN_LDR_REG_ADR_REG:      memcpy(insn, "ldr", 3); break;
427         case INSN_MOV_REG_REG:          memcpy(insn, "mov", 3); break;
428         case INSN_ADD_REG_REG:          memcpy(insn, "add", 3); break;
429         case INSN_TST_REG_REG:          memcpy(insn, "tst", 3); break;
430         case INSN_AND_REG_REG:          memcpy(insn, "and", 3); break;
431         case INSN_NOT_REG:              memcpy(insn, "not", 3); break;
432         case INSN_PUSH_REG_REG:         memcpy(insn, "psh", 3); break;
433         case INSN_POP_REG_REG:          memcpy(insn, "pop", 3); break;
434         case INSN_CALL_REG_REG:         memcpy(insn, "cal", 3); break;
435         default:                        memcpy(insn, "bad", 3); break;
436         }
437         switch ((opc >> 9) & 0x7)
438         {
439         case PRED_NV:   memcpy(insn+3, "nv", 2); break;
440         case PRED_NE:   memcpy(insn+3, "ne", 2); break;
441         case PRED_EQ:   memcpy(insn+3, "eq", 2); break;
442         case PRED_LT:   memcpy(insn+3, "lt", 2); break;
443         case PRED_GT:   memcpy(insn+3, "gt", 2); break;
444         case PRED_AL:   memcpy(insn+3, "  ", 2); break;
445         default:        memcpy(insn+3, "!!", 2); break;
446         }
447         
448         sprintf(insn+6, "r%x,r%x", (opc >> 4) & 0xF, opc & 0xF);
449         return insn;
450 }
451
452 void debugger()
453 {
454   char *line;
455   static char *oldline;
456   int loopmore = 1;
457   unsigned short insn = fetch(regs[5]);
458   
459   if (trace)
460     printf("r0:%04x r1:%04x r2:%04x r3:%04x fr:%04x pc:%04x sp:%04x -- %04x[%s]\n",
461           regs[0], regs[1], regs[2], regs[3], regs[4], regs[5], regs[6],
462           insn, insntostr(insn));
463   
464   if (regs[5] == breakpoint)
465   {
466     printf("Breakpoint reached (pc %04x)\n", breakpoint);
467     indebugger = 1;
468   }
469   
470   if (!indebugger)
471     return;
472   
473   while (loopmore && (line = readline("blargcpu> ")))
474   {
475     if (!*line)
476     {
477       free(line);
478       line = oldline;
479     } else
480       free(oldline);
481     
482     if ((strcmp(line, "exit") == 0) || (strcmp(line, "quit") == 0) || (strcmp(line, "bye") == 0))
483     {
484       printf("Bye.\n");
485       exit(0);
486     } else if ((strcmp(line, "cont") == 0) || (strcmp(line, "continue") == 0)) {
487       loopmore = 0;
488       indebugger = 0;
489     } else if ((strcmp(line, "step") == 0) || (strcmp(line, "stepi") == 0))
490       loopmore = 0;
491     else if (strcmp(line, "trace") == 0) {
492       trace = !trace;
493       printf("Trace is now %s.\n", trace ? "ON" : "OFF");
494     } else if (strcmp(line, "status") == 0) {
495       int i;
496       printf("blargCPU status report\n");
497       printf("Register status:\n");
498       printf("  r0: %04x\n", regs[0]);
499       printf("  r1: %04x\n", regs[1]);
500       printf("  r2: %04x\n", regs[2]);
501       printf("  r3: %04x\n", regs[3]);
502       printf("  FR: %04x\n", regs[4]);
503       printf("  PC: %04x\n", regs[5]);
504       printf("  SP: %04x [%04x]\n", regs[6], fetch(regs[6]));
505       printf("Context:\n");
506       i = regs[5] - 3;
507       for (i=(((regs[5] - 3) < 0) ? 0 : (regs[5] - 3)); i < (regs[5] + 4); i++)
508         printf("  %s[%04x] %04x [%s]\n", (i == regs[5]) ? "==>" : "   ", i, fetch(i), insntostr(fetch(i)));
509     } else if (strncmp(line, "break", 5) == 0) {
510       if (line[5] == ' ') {
511         unsigned short addr;
512         addr = strtol(line+6, NULL, 16);
513         breakpoint = addr;
514         printf("Breakpoint set to %04x.\n", addr);
515       } else {
516         breakpoint = -1;
517         printf("Breakpoint reset.\n");
518       }
519     } else if (strncmp(line, "xa ", 3) == 0) {
520       unsigned short addr, len = 0;
521       int i;
522       char *next;
523       addr = strtol(line+3, &next, 16);
524       if (*next)
525         len = strtol(next+1, NULL, 16);
526       if (len == 0)
527         len = 1;
528       printf("Memory examination of %04x words at %04x:\n", len, addr);
529       for (i=addr; i<(addr+len); i++)
530         printf("  [%04x] %04x\n", i, fetch(i));
531     } else
532       printf("Come again?\n");
533     oldline = line;
534   }
535 }
536
537 void reset()
538 {
539   regs[REG_PC] = 0x0;
540   regs[REG_FR] = 0x0;
541   regs[REG_SP] = STACK_LOC;
542 }
543
544 void cpuloop()
545 {
546     while(1)
547     {
548         unsigned short insn;
549         unsigned char pred_match;
550         unsigned short tmp;
551         
552         debugger();
553         
554         insn = fetch(regs[REG_PC]);
555         switch ((insn >> 9) & 0x7)
556         {
557         case PRED_NV:   pred_match = 0; break;
558         case PRED_NE:   pred_match = regs[REG_FR] & (FLAG_LT | FLAG_GT); break;
559         case PRED_EQ:   pred_match = regs[REG_FR] & FLAG_EQ; break;
560         case PRED_LT:   pred_match = regs[REG_FR] & FLAG_LT; break;
561         case PRED_GT:   pred_match = regs[REG_FR] & FLAG_GT; break;
562         case PRED_AL:   pred_match = 1; break;
563         default:        printf("Invalid predicate %1x, aborting.\n", (insn >> 9) & 0x7);
564                         abort();
565         }
566         
567 #define UCODE_NEXT_INSN         break;
568 #define UCODE_INC_PC            regs[REG_PC]++;
569 #define UCODE_INC_LATCH         tmp++;
570 #define UCODE_DEC_LATCH         tmp--;
571 #define UCODE_LATCH_ADR_PC      tmp = fetch(regs[REG_PC]);
572 #define UCODE_LATCH_PC          tmp = regs[REG_PC];
573
574 #define UCODE_STORE_TREG        regs[(insn >> 4) & 0xF] = tmp;
575 #define UCODE_LATCH_TREG        tmp = regs[(insn >> 4) & 0xF];
576 #define UCODE_LATCH_ADR_TREG    tmp = fetch(regs[(insn >> 4) & 0xF]);
577
578 #define UCODE_STORE_SREG        regs[insn & 0xF] = tmp;
579 #define UCODE_LATCH_SREG        tmp = regs[insn & 0xF];
580 #define UCODE_LATCH_ADR_SREG    tmp = fetch(regs[insn & 0xF]);
581
582 #define UCODE_STORE_ADR_TREG    store(regs[(insn >> 4) & 0xF], tmp);
583 #define UCODE_STORE_PC          regs[REG_PC] = tmp;
584 #define UCODE_ADD_TREG          tmp += regs[(insn >> 4) & 0xF];
585 #define UCODE_ZERO_FR           regs[REG_FR] = 0;
586 #define UCODE_SET_FR_EQ         if (tmp == regs[(insn >> 4) & 0xF]) regs[REG_FR] |= FLAG_EQ;
587 #define UCODE_SET_FR_LT         if (tmp <  regs[(insn >> 4) & 0xF]) regs[REG_FR] |= FLAG_LT;
588 #define UCODE_SET_FR_GT         if (tmp  > regs[(insn >> 4) & 0xF]) regs[REG_FR] |= FLAG_GT;
589 #define UCODE_AND_TREG          tmp &= regs[(insn >> 4) & 0xF];
590 #define UCODE_LATCH_NOT_TREG    tmp = ~regs[(insn >> 4) & 0xF];
591
592 #define UCODE_SHIFT_RIGHT       tmp = tmp >> (regs[(insn >> 4) & 0xF]);
593 #define UCODE_SHIFT_LEFT        tmp = tmp << (regs[(insn << 4) & 0xF]); 
594
595         switch ((insn >> 12) & 0xF)
596         {
597         case INSN_MOV_REG_LIT16:                    UCODE_INC_PC
598                                     if (pred_match) UCODE_LATCH_ADR_PC
599                                                     UCODE_INC_PC
600                                     if (pred_match) UCODE_STORE_TREG
601                                                     UCODE_NEXT_INSN
602                                                     
603         case INSN_STO_ADR_REG_REG:  if (pred_match) UCODE_LATCH_SREG
604                                                     UCODE_INC_PC
605                                     if (pred_match) UCODE_STORE_ADR_TREG
606                                                     UCODE_NEXT_INSN
607                                                     
608         case INSN_LDR_REG_ADR_REG:  if (pred_match) UCODE_LATCH_ADR_SREG
609                                                     UCODE_INC_PC
610                                     if (pred_match) UCODE_STORE_TREG
611                                                     UCODE_NEXT_INSN
612                                                     
613         case INSN_MOV_REG_REG:      if (pred_match) UCODE_LATCH_SREG
614                                                     UCODE_INC_PC
615                                     if (pred_match) UCODE_STORE_TREG
616                                                     UCODE_NEXT_INSN
617                                                     
618         case INSN_ADD_REG_REG:      if (pred_match) UCODE_LATCH_SREG
619                                                     UCODE_INC_PC
620                                     if (pred_match) UCODE_ADD_TREG
621                                     if (pred_match) UCODE_STORE_TREG
622                                                     UCODE_NEXT_INSN
623                                                     
624         case INSN_TST_REG_REG:      if (pred_match) UCODE_LATCH_SREG
625                                                     UCODE_INC_PC
626                                     if (pred_match) UCODE_ZERO_FR
627                                     if (pred_match) UCODE_SET_FR_EQ
628                                     if (pred_match) UCODE_SET_FR_LT
629                                     if (pred_match) UCODE_SET_FR_GT
630                                                     UCODE_NEXT_INSN
631         
632         case INSN_AND_REG_REG:      if (pred_match) UCODE_LATCH_SREG
633                                                     UCODE_INC_PC
634                                     if (pred_match) UCODE_AND_TREG
635                                     if (pred_match) UCODE_STORE_TREG
636                                                     UCODE_NEXT_INSN
637                                                     
638         case INSN_NOT_REG:          if (pred_match) UCODE_LATCH_NOT_TREG
639                                                     UCODE_INC_PC
640                                     if (pred_match) UCODE_STORE_TREG
641                                                     UCODE_NEXT_INSN
642                                                     
643         case INSN_PUSH_REG_REG:     if (pred_match) UCODE_LATCH_SREG
644                                     if (pred_match) UCODE_STORE_ADR_TREG
645                                     if (pred_match) UCODE_LATCH_TREG
646                                     if (pred_match) UCODE_INC_LATCH
647                                     if (pred_match) UCODE_STORE_TREG
648                                                     UCODE_INC_PC
649                                                     UCODE_NEXT_INSN
650                                                             
651         case INSN_POP_REG_REG:                      UCODE_INC_PC
652                                     if (pred_match) UCODE_LATCH_TREG
653                                     if (pred_match) UCODE_DEC_LATCH
654                                     if (pred_match) UCODE_STORE_TREG
655                                     if (pred_match) UCODE_LATCH_ADR_TREG
656                                     if (pred_match) UCODE_STORE_SREG
657                                                     UCODE_NEXT_INSN
658         
659         case INSN_CALL_REG_REG:                     UCODE_INC_PC
660                                     if (pred_match) UCODE_LATCH_PC
661                                     if (pred_match) UCODE_STORE_ADR_TREG
662                                     if (pred_match) UCODE_LATCH_TREG
663                                     if (pred_match) UCODE_INC_LATCH
664                                     if (pred_match) UCODE_STORE_TREG
665                                     if (pred_match) UCODE_LATCH_SREG
666                                     if (pred_match) UCODE_STORE_PC
667                                                     UCODE_NEXT_INSN
668         
669         case INSN_SHR_REG_REG:      if (pred_match) UCODE_LATCH_SREG
670                                                     UCODE_INC_PC
671                                     if (pred_match) UCODE_SHIFT_RIGHT
672                                     if (pred_match) UCODE_STORE_SREG
673                                                     UCODE_NEXT_INSN
674
675         case INSN_SHL_REG_REG:      if (pred_match) UCODE_LATCH_SREG
676                                                     UCODE_INC_PC
677                                     if (pred_match) UCODE_SHIFT_LEFT
678                                     if (pred_match) UCODE_STORE_SREG
679                                                     UCODE_NEXT_INSN
680 /*
681 * Two concerns as of right now about this microcode:
682 * 1.) We latch to some things, but then access the registers directly in others. As far as I can tell, we need a second latch.
683 * 2.) We increment the program counter before storing to tregs and the like sometimes, but don't others. For example, in
684 * call, we increment, then proceed to store to the address in treg. However, at other times, such as in tst, we latch to a
685 * register, first, almost giving the impression that we couldn't afterwards. I'm not sure which way it is, but it should
686 * be one way throughout the entire system.
687 * --Matthew Maurer
688 */ 
689         default:                    printf("Internal emulation error: Out of range opcode\n");
690                                     abort();
691         }
692     }
693 }
694
695 /*******************************************************************/
696 /*******************************************************************/
697
698 #include <signal.h>
699 #include <getopt.h>
700
701 void dbghandler(int sig)
702 {
703   char *str;
704   if (indebugger)
705   {
706     str = "Caught signal in debugger; bailing out!\n";
707     write(2, str, strlen(str));
708     exit(1);
709   }
710   str = "^C hit; breaking into debugger\n";
711   write(2, str, strlen(str));
712   indebugger = 1;
713 }
714
715 struct option longopts[] = {
716   {"rom", required_argument, NULL, 'r'},
717   {"debugger", no_argument, NULL, 'd'},
718   {"help", no_argument, NULL, 'h'},
719   {0,0,0,0} /* sentinel */
720 };
721
722 int main(int argc, char** argv)
723 {
724   int arg;
725   while ((arg = getopt_long(argc, argv, "r:d", longopts, NULL)) != -1)
726   {
727     switch(arg)
728     {
729     case 'r':
730     {
731       int fd;
732       fd = open(optarg, O_RDONLY);
733       if (fd < 0)
734       {
735         perror("open");
736         exit(0);
737       }
738       read(fd, rom_data, ROMSIZE*sizeof(short));
739       close(fd);
740     }
741     case 'd':
742       indebugger = 1;
743       break;
744     case 'h':
745       printf(
746         "blargCPU2\n"
747         "\n"
748         "Usage: %s [OPTION] ...\n"
749         "Simulates a blargCPU.\n"
750         "\n"
751         "Mandatory arguments to long options are mandatory for short options too.\n"
752         "  -r, --rom=ROMFILE            preloads ROM with a boot image\n"
753         "  -d, --debugger               immediately drops into the debugger\n"
754         "      --help                   shows this help\n"
755         "\n"
756         "Written by Joshua Wise <joshua@joshuawise.com> and Matthew Maurer <Fallen.Azrael@gmail.com>.\n"
757         , argv[0]
758         );
759       exit(2);
760     case '?': case ':':
761       printf("Try `%s --help' for more information.\n", argv[0]);
762       exit(2);
763     default:
764       printf("Oh God I am not good with computers how did this get here?\n");
765       exit(127);
766     }
767   }
768   signal(SIGINT, dbghandler);
769   rom_add();
770   ram_add();
771   console_add();
772   fb_add();
773   reset();
774   cpuloop();
775   return 0;
776 }
This page took 0.112291 seconds and 4 git commands to generate.