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