実行時二はラーが発生した場合のPR取得方法を変更
[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  * プログラムレジスタ(PR)を表す文字列を返す
337  **/
338 static char *pr2str(WORD pr) {
339     char *str = malloc_chk(CERRSTRSIZE + 1, "pr2str.pr");
340
341     sprintf(str, "PR:#%04X", pr);
342     return str;
343 }
344
345 /**
346  * 仮想マシンCOMET IIの実行
347  */
348 bool exec()
349 {
350     WORD op, r_r1, x_r2, val;
351     CMDTYPE cmdtype;
352     clock_t clock_begin, clock_end;
353
354     if(execmode.trace == true) {
355         fprintf(stdout, "\nExecuting machine codes\n");
356     }
357     /* フラグレジスタの初期値設定 */
358     sys->cpu->fr = 0x0;
359     sys->cpu->sp = sys->memsize;
360     sys->cpu->pr = execptr->start;
361     /* 機械語の実行 */
362     for (; ; ) {
363         clock_begin = clock();
364         /* プログラムレジスタのアドレスが主記憶の範囲外の場合はエラー */
365         if(sys->cpu->pr >= sys->memsize) {
366             setcerr(204, pr2str(sys->cpu->pr));    /* Program Register (PR) - out of COMET II memory */
367         }
368         /* スタック領域を確保できない場合はエラー */
369         else if(sys->cpu->sp <= execptr->end) {
370             setcerr(205, pr2str(sys->cpu->pr));    /* Stack Pointer (SP) - cannot allocate stack buffer */
371         }
372         /* スタック領域のアドレスが主記憶の範囲外の場合はエラー */
373         else if(sys->cpu->sp > sys->memsize) {
374             setcerr(207, pr2str(sys->cpu->pr));    /* Stack Pointer (SP) - out of COMET II memory */
375         }
376         /* エラー発生時は終了 */
377         if(cerr->num > 0) {
378             goto execerr;
379         }
380         /* 命令の取り出し */
381         op = sys->memory[sys->cpu->pr] & 0xFF00;
382         /* 命令の解読 */
383         cmdtype = getcmdtype(op);
384         r_r1 = (sys->memory[sys->cpu->pr] >> 4) & 0xF;
385         x_r2 = sys->memory[sys->cpu->pr] & 0xF;
386         /* traceオプション指定時、レジスタを出力 */
387         if(execmode.trace){
388             fprintf(stdout, "#%04X: Register::::\n", sys->cpu->pr);
389             dspregister();
390         }
391         /* dumpオプション指定時、メモリを出力 */
392         if(execmode.dump){
393             fprintf(stdout, "#%04X: Memory::::\n", sys->cpu->pr);
394             dumpmemory();
395         }
396         /* traceまたはdumpオプション指定時、改行を出力 */
397         if(execmode.dump || execmode.trace) {
398             fprintf(stdout, "\n");
399         }
400         sys->cpu->pr++;
401         /* オペランドの取り出し */
402         if(cmdtype == R1_R2) {
403             /* オペランドの数値が汎用レジスタの範囲外の場合はエラー */
404             if(x_r2 > GRSIZE - 1) {
405                 setcerr(209, pr2str(sys->cpu->pr-1));    /* not GR in operand x */
406                 goto execerr;
407             }
408             val = sys->cpu->gr[x_r2];
409         }
410         else if(cmdtype ==  R_ADR_X || cmdtype == R_ADR_X_ || cmdtype == ADR_X) {
411             /* オペランドの数値が汎用レジスタの範囲外の場合はエラー */
412             if(x_r2 > GRSIZE - 1) {
413                 setcerr(209, pr2str(sys->cpu->pr-1));    /* not GR in operand x */
414                 goto execerr;
415             }
416             /* 実効アドレス(値または値が示す番地)を取得  */
417             val = sys->memory[sys->cpu->pr++];
418             /* 指標アドレスを加算  */
419             if(x_r2 > 0x0) {
420                 val += sys->cpu->gr[x_r2];
421             }
422             /* ロード/算術論理演算命令/比較演算命令では、アドレスに格納されている内容を取得 */
423             if(cmdtype == R_ADR_X_) {
424                 if(val >= sys->memsize) {
425                     setcerr(206, pr2str(sys->cpu->pr-1));    /* Address - out of COMET II memory */
426                     goto execerr;
427                 }
428                 val = sys->memory[val];
429             }
430         }
431         /* 主オペランドが1から4の場合、第2ビットを無視 */
432         if(op >= 0x1000 && op <= 0x4FFF) {
433             op &= 0xFB00;
434         }
435         /* 命令の実行 */
436         switch(op)
437         {
438         case 0x0:       /* NOP */
439             break;
440         case 0x1000:    /* LD */
441             setfr(sys->cpu->gr[r_r1] = val);
442             break;
443         case 0x1100:    /* ST */
444             sys->memory[val] = sys->cpu->gr[r_r1];
445             break;
446         case 0x1200:    /* LAD */
447             sys->cpu->gr[r_r1] = val;
448             break;
449         case 0x2000:    /* ADDA */
450             sys->cpu->gr[r_r1] = adda(sys->cpu->gr[r_r1], val);
451             break;
452         case 0x2100:    /* SUBA */
453             sys->cpu->gr[r_r1] = suba(sys->cpu->gr[r_r1], val);
454             break;
455         case 0x2200:    /* ADDL */
456             sys->cpu->gr[r_r1] = addl(sys->cpu->gr[r_r1], val);
457             break;
458         case 0x2300:    /* SUBL */
459             sys->cpu->gr[r_r1] = subl(sys->cpu->gr[r_r1], val);
460             break;
461         case 0x3000:    /* AND */
462             setfr(sys->cpu->gr[r_r1] &= val);
463             break;
464         case 0x3100:    /* OR */
465             setfr(sys->cpu->gr[r_r1] |= val);
466             break;
467         case 0x3200:    /* XOR */
468             setfr(sys->cpu->gr[r_r1] ^= val);
469             break;
470         case 0x4000:    /* CPA */
471             cpa(sys->cpu->gr[r_r1], val);
472             break;
473         case 0x4100:    /* CPL */
474             cpl(sys->cpu->gr[r_r1], val);
475             break;
476         case 0x5000:    /* SLA */
477             sys->cpu->gr[r_r1] = sla(sys->cpu->gr[r_r1], val);
478             break;
479         case 0x5100:    /* SRA */
480             sys->cpu->gr[r_r1] = sra(sys->cpu->gr[r_r1], val);
481             break;
482         case 0x5200:    /* SLL */
483             sys->cpu->gr[r_r1] = sll(sys->cpu->gr[r_r1], val);
484             break;
485         case 0x5300:    /* SRL */
486             sys->cpu->gr[r_r1] = srl(sys->cpu->gr[r_r1], val);
487             break;
488         case 0x6100:    /* JMI */
489             if((sys->cpu->fr & SF) > 0) {
490                 sys->cpu->pr = val;
491             }
492             break;
493         case 0x6200:    /* JNZ */
494             if((sys->cpu->fr & ZF) == 0) {
495                 sys->cpu->pr = val;
496             }
497             break;
498         case 0x6300:    /* JZE */
499             if((sys->cpu->fr & ZF) > 0) {
500                 sys->cpu->pr = val;
501             }
502             break;
503         case 0x6400:    /* JUMP */
504             sys->cpu->pr = val;
505             break;
506         case 0x6500:    /* JPL */
507             if((sys->cpu->fr & (SF | ZF)) == 0) {
508                 sys->cpu->pr = val;
509             }
510             break;
511         case 0x6600:    /* JOV */
512             if((sys->cpu->fr & OF) > 0) {
513                 sys->cpu->pr = val;
514             }
515             break;
516         case 0x7000:    /* PUSH */
517             assert(sys->cpu->sp > execptr->end && sys->cpu->sp <= sys->memsize);
518             sys->memory[--(sys->cpu->sp)] = val;
519             break;
520         case 0x7100:    /* POP */
521             assert(sys->cpu->sp > execptr->end && sys->cpu->sp <= sys->memsize);
522             sys->cpu->gr[r_r1] = sys->memory[(sys->cpu->sp)++];
523             break;
524         case 0x8000:    /* CALL */
525             assert(sys->cpu->sp > execptr->end && sys->cpu->sp <= sys->memsize);
526             sys->memory[--(sys->cpu->sp)] = sys->cpu->pr;
527             sys->cpu->pr = val;
528             break;
529         case 0x8100:    /* RET */
530             assert(sys->cpu->sp > execptr->end && sys->cpu->sp <= sys->memsize);
531             if(sys->cpu->sp == sys->memsize) {
532                 return true;
533             } else {
534                 sys->cpu->pr = sys->memory[(sys->cpu->sp)++];
535                 break;
536             }
537         case 0xF000:    /* SVC */
538             switch(val)
539             {
540             case 0x0: /* EXIT */
541                 return true;
542             case 0x1: /* IN */
543                 svcin();
544                 break;
545             case 0x2: /* OUT */
546                 svcout();
547                 break;
548             }
549         default:
550             break;
551         }
552         /* クロック周波数の設定 */
553         do {
554             clock_end = clock();
555         } while(clock_end - clock_begin < CLOCKS_PER_SEC / sys->clocks);
556     }
557     return true;
558 execerr:
559     fprintf(stderr, "Execute error - %d: %s\n", cerr->num, cerr->msg);
560     return false;
561 }