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