データ構造の名前を変更
[YACASL2.git] / src / exec.c
1 #include <stdio.h>
2 #include <assert.h>
3 #include <time.h>
4
5 #include "exec.h"
6 #include "cerr.h"
7
8 /**
9  * 実行エラーの定義
10  */
11 static CERR cerr_exec[] = {
12     { 201, "Loading - full of COMET II memory" },
13     { 202, "SVC input - out of Input memory" },
14     { 203, "SVC output - out of COMET II memory" },
15     { 204, "Program Register (PR) - out of COMET II memory" },
16     { 205, "Stack Pointer (SP) - cannot allocate stack buffer" },
17     { 206, "Address - out of COMET II memory" },
18     { 207, "Stack Pointer (SP) - out of COMET II memory" },
19     { 209, "not GR in operand x" },
20 };
21
22 /**
23  * 実行モード: trace, logical, dump
24  */
25 EXECMODE execmode = {false, false, false};
26
27 /**
28  * 実行エラーをエラーリストに追加
29  */
30 bool addcerrlist_exec()
31 {
32     return addcerrlist(ARRAYSIZE(cerr_exec), cerr_exec);
33 }
34
35 /**
36  * 指定されたファイルからアセンブル結果を読み込む
37  */
38 bool loadassemble(char *file)
39 {
40     FILE *fp;
41     bool status = true;
42
43     assert(file != NULL);
44     if((fp = fopen(file, "r")) == NULL) {
45         perror(file);
46         return false;
47     }
48     execptr->end = execptr->start +
49         fread(sys->memory, sizeof(WORD), sys->memsize - execptr->start, fp);
50     if(execptr->end == sys->memsize) {
51         setcerr(201, file);    /* Loading - full of COMET II memory */
52         fprintf(stderr, "Load error - %d: %s\n", cerr->num, cerr->msg);
53         status = false;
54     }
55     fclose(fp);
56     return status;
57 }
58
59 /**
60  * 標準入力から文字データを読込(SVC 1)
61  */
62 static void svcin()
63 {
64     int i;
65     char *buffer = malloc_chk(INSIZE + 1, "svcin.buffer");
66
67     if(fgets(buffer, INSIZE, stdin) == NULL) {
68         sys->memory[sys->cpu->gr[1]] = sys->memory[sys->cpu->gr[2]] = 0x0;
69         return;
70     }
71     for(i = 0; i < INSIZE; i++) {
72         if(*(buffer + i) == '\0' || *(buffer + i) == '\n') {
73             --i;
74             break;
75         }
76         if(sys->cpu->gr[1] + i >= sys->memsize - 1) {
77             setcerr(202, NULL);    /* SVC input - out of Input memory */
78             break;
79         }
80         sys->memory[sys->cpu->gr[1]+i] = *(buffer + i);
81     }
82     sys->memory[sys->cpu->gr[2]] = i + 1;
83     free_chk(buffer, "buffer");
84 }
85
86 /**
87  * 標準出力へ文字データを書出(SVC 2)
88  */
89 static void svcout()
90 {
91     int i;
92     WORD w;
93
94     for(i = 0; i < sys->memory[sys->cpu->gr[2]]; i++) {
95         if(sys->cpu->gr[1] + i >= sys->memsize - 1) {
96             setcerr(203, NULL);    /* SVC output - out of Comet II memory */
97             return;
98         }
99         /* 「文字の組」の符号表に記載された文字と、改行(CR)/タブを表示 */
100         /* それ以外の文字は、「.」で表す */
101         if(((w = sys->memory[sys->cpu->gr[1]+i]) >= 0x20 && w <= 0x7E) || w == 0xA || w == '\t') {
102             putchar((char)w);
103         } else {
104             putchar('.');
105         }
106     }
107 }
108
109 /**
110  * ロード/論理積/論理和/排他的論理和のフラグ設定。OFは常に0
111  */
112 static void setfr(WORD val)
113 {
114     sys->cpu->fr = 0x0;
115     /* 第15ビットが1のとき、SFは1 */
116     if((val & 0x8000) == 0x8000) {
117         sys->cpu->fr += SF;
118     }
119     /* 演算結果が0のとき、ZFは1 */
120     if(val == 0x0) {
121         sys->cpu->fr += ZF;
122     }
123 }
124
125 /**
126  * 算術加算。フラグを設定して値を返す
127  */
128 static WORD adda(WORD val0, WORD val1)
129 {
130     WORD res;
131     long tmp;
132
133     sys->cpu->fr = 0x0;
134     /* 引数の値を16ビット符号付整数として加算し、オーバーフローをチェック */
135     assert(sizeof(short)*8 == 16 && (short)0xFFFF == -1);
136     if((tmp = (short)val0 + (short)val1) > 32767 || tmp < -32768) {
137         sys->cpu->fr += OF;
138     }
139     /* 加算した結果を、WORD値に戻す */
140     res = (WORD)(tmp & 0xFFFF);
141     if((res & 0x8000) == 0x8000) {
142         sys->cpu->fr += SF;
143     } else if(res == 0x0) {
144         sys->cpu->fr += ZF;
145     }
146     return res;
147 }
148
149 /**
150  * 算術減算。フラグを設定して値を返す
151  */
152 static WORD suba(WORD val0, WORD val1)
153 {
154     return adda(val0, (~val1 + 1));
155 }
156
157 /**
158  * 論理加算。フラグを設定して値を返す
159  */
160 static WORD addl(WORD val0, WORD val1)
161 {
162     long tmp;
163     WORD res;
164     sys->cpu->fr = 0x0;
165
166     if((tmp = val0 + val1) < 0 || tmp > 65535) {
167         sys->cpu->fr += OF;
168     }
169     if(((res = (WORD)(tmp & 0xFFFF)) & 0x8000) == 0x8000) {
170         sys->cpu->fr += SF;
171     } else if(res == 0x0) {
172         sys->cpu->fr += ZF;
173     }
174     return res;
175 }
176
177 /**
178  * 論理減算。フラグを設定して値を返す
179  */
180 static WORD subl(WORD val0, WORD val1)
181 {
182     return addl(val0, (~val1 + 1));
183 }
184
185 /**
186  * 算術比較のフラグ設定。OFは常に0
187  */
188 static void cpa(WORD val0, WORD val1)
189 {
190     sys->cpu->fr = 0x0;
191     if((short)val0 < (short)val1) {
192         sys->cpu->fr = SF;
193     } else if(val0 == val1) {
194         sys->cpu->fr = ZF;
195     }
196 }
197
198 /**
199  * 論理比較のフラグ設定。OFは常に0
200  */
201 static void cpl(WORD val0, WORD val1)
202 {
203     sys->cpu->fr = 0x0;
204     if(val0 < val1) {
205         sys->cpu->fr = SF;
206     } else if(val0 == val1) {
207         sys->cpu->fr = ZF;
208     }
209 }
210
211 /**
212  * 算術左シフト。フラグを設定して値を返す
213  * 算術演算なので、第15ビットは送り出されない
214  */
215 static WORD sla(WORD val0, WORD val1)
216 {
217     WORD sign, res, last = 0x0;
218     int i;
219
220     sys->cpu->fr = 0x0;
221     sign = val0 & 0x8000;
222     res = val0 & 0x7FFF;
223     for(i = 0; i < val1; i++) {
224         last = res & 0x4000;
225         res <<= 1;
226     }
227     res = sign | (res & 0x7FFF);
228     /* OFに、レジスタから最後に送り出されたビットの値を設定 */
229     if(last > 0x0) {
230         sys->cpu->fr += OF;
231     }
232     /* 符号(第15ビット)が1のとき、SFは1 */
233     if(sign > 0x0) {
234         sys->cpu->fr += SF;
235     }
236     /* 演算結果が0のとき、ZFは1 */
237     if(res == 0x0) {
238         sys->cpu->fr += ZF;
239     }
240     return res;
241 }
242
243 /**
244  * 算術右シフト。フラグを設定して値を返す
245  * 算術演算なので、第15ビットは送り出されない
246  * 空いたビット位置には符号と同じものが入る
247  */
248 static WORD sra(WORD val0, WORD val1)
249 {
250     WORD sign, res, last = 0x0;
251     int i;
252
253     sys->cpu->fr = 0x0;
254     sign = val0 & 0x8000;
255     res = val0 & 0x7FFF;
256     for(i = 0; i < val1; i++) {
257         last = res & 0x1;
258         res >>= 1;
259         if(sign > 0) {
260             res |= 0x4000;
261         }
262     }
263     res = sign | res;
264     /* OFに、レジスタから最後に送り出されたビットの値を設定 */
265     if(last > 0x0) {
266         sys->cpu->fr += OF;
267     }
268     /* 符号(第15ビット)が1のとき、SFは1 */
269     if(sign > 0x0) {
270         sys->cpu->fr += SF;
271     }
272     /* 演算結果が0のとき、ZFは1 */
273     if(res == 0x0) {
274         sys->cpu->fr += ZF;
275     }
276     return res;
277 }
278
279 /**
280  * 論理左シフト。フラグを設定して値を返す
281  */
282 static WORD sll(WORD val0, WORD val1)
283 {
284     WORD res = val0, last = 0x0;
285     int i;
286
287     sys->cpu->fr = 0x0;
288     for(i = 0; i < val1; i++) {
289         last = res & 0x8000;
290         res <<= 1;
291     }
292     /* OFに、レジスタから最後に送り出されたビットの値を設定 */
293     if(last > 0x0) {
294         sys->cpu->fr += OF;
295     }
296     /* 第15ビットが1のとき、SFは1 */
297     if((res & 0x8000) > 0x0) {
298         sys->cpu->fr += SF;
299     }
300     /* 演算結果が0のとき、ZFは1 */
301     if(res == 0x0) {
302         sys->cpu->fr += ZF;
303     }
304     return res;
305 }
306
307 /**
308  * 論理右シフト。フラグを設定して値を返す
309  */
310 static WORD srl(WORD val0, WORD val1)
311 {
312     WORD res = val0, last = 0x0;
313     int i;
314
315     sys->cpu->fr = 0x0;
316     for(i = 0; i < val1; i++) {
317         last = res & 0x0001;
318         res >>= 1;
319     }
320     /* OFに、レジスタから最後に送り出されたビットの値を設定 */
321     if(last > 0x0) {
322         sys->cpu->fr += OF;
323     }
324     /* 第15ビットが1のとき、SFは1 */
325     if((res & 0x8000) > 0x0) {
326         sys->cpu->fr += SF;
327     }
328     /* 演算結果が0のとき、ZFは1 */
329     if(res == 0x0) {
330         sys->cpu->fr += ZF;
331     }
332     return res;
333 }
334
335 /**
336  * 仮想マシンCOMET IIの実行
337  */
338 bool exec()
339 {
340     WORD op, r_r1, x_r2, val;
341     CMDTYPE cmdtype;
342     char *errpr = malloc_chk(CERRSTRSIZE + 1, "exec.errpr");
343     clock_t clock_begin, clock_end;
344
345     if(execmode.trace == true) {
346         fprintf(stdout, "\nExecuting machine codes\n");
347     }
348     /* フラグレジスタの初期値設定 */
349     sys->cpu->fr = 0x0;
350     sys->cpu->sp = sys->memsize;
351     sys->cpu->pr = execptr->start;
352     /* 機械語の実行 */
353     for (; ; ) {
354         clock_begin = clock();
355         /* プログラムレジスタのアドレスが主記憶の範囲外の場合はエラー */
356         if(sys->cpu->pr >= sys->memsize) {
357             sprintf(errpr, "PR:#%04X", sys->cpu->pr);
358             setcerr(204, errpr);    /* Program Register (PR) - out of COMET II memory */
359         }
360         /* スタック領域を確保できない場合はエラー */
361         else if(sys->cpu->sp <= execptr->end) {
362             sprintf(errpr, "PR:#%04X", sys->cpu->pr);
363             setcerr(205, errpr);    /* Stack Pointer (SP) - cannot allocate stack buffer */
364         }
365         /* スタック領域のアドレスが主記憶の範囲外の場合はエラー */
366         else if(sys->cpu->sp > sys->memsize) {
367             sprintf(errpr, "PR:#%04X", sys->cpu->pr);
368             setcerr(207, errpr);    /* Stack Pointer (SP) - out of COMET II memory */
369         }
370         /* エラー発生時は終了 */
371         if(cerr->num > 0) {
372             goto execerr;
373         }
374         /* 命令の取り出し */
375         op = sys->memory[sys->cpu->pr] & 0xFF00;
376         /* 命令の解読 */
377         cmdtype = getcmdtype(op);
378         r_r1 = (sys->memory[sys->cpu->pr] >> 4) & 0xF;
379         x_r2 = sys->memory[sys->cpu->pr] & 0xF;
380         /* traceオプション指定時、レジスタを出力 */
381         if(execmode.trace){
382             fprintf(stdout, "#%04X: Register::::\n", sys->cpu->pr);
383             dspregister();
384         }
385         /* dumpオプション指定時、メモリを出力 */
386         if(execmode.dump){
387             fprintf(stdout, "#%04X: Memory::::\n", sys->cpu->pr);
388             dumpmemory();
389         }
390         /* traceまたはdumpオプション指定時、改行を出力 */
391         if(execmode.dump || execmode.trace) {
392             fprintf(stdout, "\n");
393         }
394         sys->cpu->pr++;
395         /* オペランドの取り出し */
396         if(cmdtype == R1_R2) {
397             /* オペランドの数値が汎用レジスタの範囲外の場合はエラー */
398             if(x_r2 > GRSIZE - 1) {
399                 sprintf(errpr, "PR:#%04X", sys->cpu->pr-1);
400                 setcerr(209, errpr);    /* not GR in operand x */
401                 goto execerr;
402             }
403             val = sys->cpu->gr[x_r2];
404         }
405         else if(cmdtype ==  R_ADR_X || cmdtype == R_ADR_X_ || cmdtype == ADR_X) {
406             /* オペランドの数値が汎用レジスタの範囲外の場合はエラー */
407             if(x_r2 > GRSIZE - 1) {
408                 sprintf(errpr, "PR:#%04X", sys->cpu->pr-1);
409                 setcerr(209, errpr);    /* not GR in operand x */
410                 goto execerr;
411             }
412             /* 実効アドレス(値または値が示す番地)を取得  */
413             val = sys->memory[sys->cpu->pr++];
414             /* 指標アドレスを加算  */
415             if(x_r2 > 0x0) {
416                 val += sys->cpu->gr[x_r2];
417             }
418             /* ロード/算術論理演算命令/比較演算命令では、アドレスに格納されている内容を取得 */
419             if(cmdtype == R_ADR_X_) {
420                 if(val >= sys->memsize) {
421                     sprintf(errpr, "PR:#%04X", sys->cpu->pr-1);
422                     setcerr(206, errpr);    /* Address - out of COMET II memory */
423                     goto execerr;
424                 }
425                 val = sys->memory[val];
426             }
427         }
428         free_chk(errpr, "errpr");
429         /* 主オペランドが1から4の場合、第2ビットを無視 */
430         if(op >= 0x1000 && op <= 0x4FFF) {
431             op &= 0xFB00;
432         }
433         /* 命令の実行 */
434         switch(op)
435         {
436         case 0x0:       /* NOP */
437             break;
438         case 0x1000:    /* LD */
439             setfr(sys->cpu->gr[r_r1] = val);
440             break;
441         case 0x1100:    /* ST */
442             sys->memory[val] = sys->cpu->gr[r_r1];
443             break;
444         case 0x1200:    /* LAD */
445             sys->cpu->gr[r_r1] = val;
446             break;
447         case 0x2000:    /* ADDA */
448             sys->cpu->gr[r_r1] = adda(sys->cpu->gr[r_r1], val);
449             break;
450         case 0x2100:    /* SUBA */
451             sys->cpu->gr[r_r1] = suba(sys->cpu->gr[r_r1], val);
452             break;
453         case 0x2200:    /* ADDL */
454             sys->cpu->gr[r_r1] = addl(sys->cpu->gr[r_r1], val);
455             break;
456         case 0x2300:    /* SUBL */
457             sys->cpu->gr[r_r1] = subl(sys->cpu->gr[r_r1], val);
458             break;
459         case 0x3000:    /* AND */
460             setfr(sys->cpu->gr[r_r1] &= val);
461             break;
462         case 0x3100:    /* OR */
463             setfr(sys->cpu->gr[r_r1] |= val);
464             break;
465         case 0x3200:    /* XOR */
466             setfr(sys->cpu->gr[r_r1] ^= val);
467             break;
468         case 0x4000:    /* CPA */
469             cpa(sys->cpu->gr[r_r1], val);
470             break;
471         case 0x4100:    /* CPL */
472             cpl(sys->cpu->gr[r_r1], val);
473             break;
474         case 0x5000:    /* SLA */
475             sys->cpu->gr[r_r1] = sla(sys->cpu->gr[r_r1], val);
476             break;
477         case 0x5100:    /* SRA */
478             sys->cpu->gr[r_r1] = sra(sys->cpu->gr[r_r1], val);
479             break;
480         case 0x5200:    /* SLL */
481             sys->cpu->gr[r_r1] = sll(sys->cpu->gr[r_r1], val);
482             break;
483         case 0x5300:    /* SRL */
484             sys->cpu->gr[r_r1] = srl(sys->cpu->gr[r_r1], val);
485             break;
486         case 0x6100:    /* JMI */
487             if((sys->cpu->fr & SF) > 0) {
488                 sys->cpu->pr = val;
489             }
490             break;
491         case 0x6200:    /* JNZ */
492             if((sys->cpu->fr & ZF) == 0) {
493                 sys->cpu->pr = val;
494             }
495             break;
496         case 0x6300:    /* JZE */
497             if((sys->cpu->fr & ZF) > 0) {
498                 sys->cpu->pr = val;
499             }
500             break;
501         case 0x6400:    /* JUMP */
502             sys->cpu->pr = val;
503             break;
504         case 0x6500:    /* JPL */
505             if((sys->cpu->fr & (SF | ZF)) == 0) {
506                 sys->cpu->pr = val;
507             }
508             break;
509         case 0x6600:    /* JOV */
510             if((sys->cpu->fr & OF) > 0) {
511                 sys->cpu->pr = val;
512             }
513             break;
514         case 0x7000:    /* PUSH */
515             assert(sys->cpu->sp > execptr->end && sys->cpu->sp <= sys->memsize);
516             sys->memory[--(sys->cpu->sp)] = val;
517             break;
518         case 0x7100:    /* POP */
519             assert(sys->cpu->sp > execptr->end && sys->cpu->sp <= sys->memsize);
520             sys->cpu->gr[r_r1] = sys->memory[(sys->cpu->sp)++];
521             break;
522         case 0x8000:    /* CALL */
523             assert(sys->cpu->sp > execptr->end && sys->cpu->sp <= sys->memsize);
524             sys->memory[--(sys->cpu->sp)] = sys->cpu->pr;
525             sys->cpu->pr = val;
526             break;
527         case 0x8100:    /* RET */
528             assert(sys->cpu->sp > execptr->end && sys->cpu->sp <= sys->memsize);
529             if(sys->cpu->sp == sys->memsize) {
530                 return true;
531             } else {
532                 sys->cpu->pr = sys->memory[(sys->cpu->sp)++];
533                 break;
534             }
535         case 0xF000:    /* SVC */
536             switch(val)
537             {
538             case 0x0: /* EXIT */
539                 return true;
540             case 0x1: /* IN */
541                 svcin();
542                 break;
543             case 0x2: /* OUT */
544                 svcout();
545                 break;
546             }
547         default:
548             break;
549         }
550         /* クロック周波数の設定 */
551         do {
552             clock_end = clock();
553         } while(clock_end - clock_begin < CLOCKS_PER_SEC / sys->clocks);
554     }
555     return true;
556 execerr:
557     fprintf(stderr, "Execute error - %d: %s\n", cerr->num, cerr->msg);
558     cerr->msg = NULL;           /* Ubuntu 10.04 PPCでcerr.msg開放時にSegmentation Faultが発生する現象を回避するため */
559     return false;
560 }