5dc4eb101ae845ce927e08fab6e2ca3320fc8db6
[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 adr)
154 {
155
156 }
157
158 /**
159  * LD命令
160  */
161 void ld(const WORD r, const WORD adr)
162 {
163     setfr(sys->cpu->gr[r] = adr);
164 }
165
166 /**
167  * ST命令
168  */
169 void st(const WORD r, const WORD adr)
170 {
171     sys->memory[adr] = sys->cpu->gr[r];
172 }
173
174 /**
175  * LAD命令
176  */
177 void lad(const WORD r, const WORD adr)
178 {
179     sys->cpu->gr[r] = adr;
180 }
181
182 /**
183  * ADDA命令
184  */
185 void adda(const WORD r, const WORD adr)
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)adr) > 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 adr)
208 {
209     adda(r, (~adr + 1));
210 }
211
212 /**
213  * ADDL命令
214  */
215 void addl(const WORD r, const WORD adr)
216 {
217     long tmp;
218     sys->cpu->fr = 0x0;
219
220     if((tmp = sys->cpu->gr[r] + adr) < 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 adr)
234 {
235     addl(r, (~adr + 1));
236 }
237
238 /**
239  * AND命令
240  */
241 void and(const WORD r, const WORD adr)
242 {
243     setfr(sys->cpu->gr[r] &= adr);
244 }
245
246 /**
247  * OR命令
248  */
249 void or(const WORD r, const WORD adr)
250 {
251     setfr(sys->cpu->gr[r] |= adr);
252 }
253
254 /**
255  * XOR命令
256  */
257 void xor(const WORD r, const WORD adr)
258 {
259     setfr(sys->cpu->gr[r] ^= adr);
260 }
261
262 /**
263  * CPA命令
264  */
265 void cpa(const WORD r, const WORD adr)
266 {
267     sys->cpu->fr = 0x0;
268     if((short)sys->cpu->gr[r] < (short)adr) {
269         sys->cpu->fr = SF;
270     } else if(sys->cpu->gr[r] == adr) {
271         sys->cpu->fr = ZF;
272     }
273 }
274
275 /**
276  * CPL命令
277  */
278 void cpl(const WORD r, const WORD adr)
279 {
280     sys->cpu->fr = 0x0;
281     if(sys->cpu->gr[r] < adr) {
282         sys->cpu->fr = SF;
283     } else if(sys->cpu->gr[r] == adr) {
284         sys->cpu->fr = ZF;
285     }
286 }
287
288
289 /**
290  * SLA命令。算術演算なので、第15ビットは送り出されない
291  */
292 void sla(const WORD r, const WORD adr)
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 < adr; 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 adr)
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 < adr; 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 adr)
358 {
359     WORD last = 0x0;
360     int i;
361
362     sys->cpu->fr = 0x0;
363     for(i = 0; i < adr; 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 adr)
385 {
386     WORD last = 0x0;
387     int i;
388
389     sys->cpu->fr = 0x0;
390     for(i = 0; i < adr; 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 adr)
412 {
413     if((sys->cpu->fr & SF) > 0) {
414         sys->cpu->pr = adr;
415     }
416 }
417
418 /**
419  * JNZ命令
420  */
421 void jnz(const WORD r, const WORD adr)
422 {
423     if((sys->cpu->fr & ZF) == 0) {
424         sys->cpu->pr = adr;
425     }
426 }
427
428 /**
429  * JZE命令
430  */
431 void jze(const WORD r, const WORD adr)
432 {
433     if((sys->cpu->fr & ZF) > 0) {
434         sys->cpu->pr = adr;
435     }
436 }
437
438 /**
439  * JUMP命令
440  */
441 void jump(const WORD r, const WORD adr)
442 {
443     sys->cpu->pr = adr;
444 }
445
446 /**
447  * JPL命令
448  */
449 void jpl(const WORD r, const WORD adr)
450 {
451     if((sys->cpu->fr & (SF | ZF)) == 0) {
452         sys->cpu->pr = adr;
453     }
454 }
455
456 /**
457  * JOV命令
458  */
459 void jov(const WORD r, const WORD adr)
460 {
461     if((sys->cpu->fr & OF) > 0) {
462         sys->cpu->pr = adr;
463     }
464 }
465
466 /**
467  * PUSH命令
468  */
469 void push(const WORD r, const WORD adr)
470 {
471     assert(sys->cpu->sp > execptr->end && sys->cpu->sp <= sys->memsize);
472     sys->memory[--(sys->cpu->sp)] = adr;
473 }
474
475 /**
476  * POP命令
477  */
478 void pop(const WORD r, const WORD adr)
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 adr)
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 = adr;
492 }
493
494 /**
495  * RET命令
496  */
497 void ret(const WORD r, const WORD adr)
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 adr)
511 {
512     switch(adr)
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     CMD *cmd;
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         /* traceまたはdumpオプション指定時、改行を出力 */
549         if(execmode.dump || execmode.trace) {
550             /* traceオプション指定時、レジスタを出力 */
551             if(execmode.trace){
552                 fprintf(stdout, "#%04X: Register::::\n", sys->cpu->pr);
553                 dspregister();
554             }
555             /* dumpオプション指定時、メモリを出力 */
556             if(execmode.dump){
557                 fprintf(stdout, "#%04X: Memory::::\n", sys->cpu->pr);
558                 dumpmemory();
559             }
560             fprintf(stdout, "\n");
561         }
562         /* プログラムレジスタとスタックポインタをチェック */
563         if(sys->cpu->pr >= sys->memsize || sys->cpu->sp <= execptr->end || sys->cpu->sp > sys->memsize) {
564             if(sys->cpu->pr >= sys->memsize) {
565                 setcerr(204, pr2str(sys->cpu->pr));    /* Program Register (PR) - out of COMET II memory */
566             } else if(sys->cpu->sp <= execptr->end) {
567                 setcerr(205, pr2str(sys->cpu->pr));    /* Stack Pointer (SP) - cannot allocate stack buffer */
568             } else if(sys->cpu->sp > sys->memsize) {
569                 setcerr(207, pr2str(sys->cpu->pr));    /* Stack Pointer (SP) - out of COMET II memory */
570             }
571             goto execerr;
572         }
573         /* 命令の取り出し */
574         op = sys->memory[sys->cpu->pr] & 0xFF00;
575         /* 命令の解読 */
576         /* 命令がCOMET II命令ではない場合はエラー終了 */
577         if((cmd = getcmd(op)) == NULL) {
578             setcerr(210, pr2str(sys->cpu->pr));          /* not command code of COMET II */
579             goto execerr;
580         }
581         cmdptr = cmd->ptr;
582         r_r1 = (sys->memory[sys->cpu->pr] >> 4) & 0xF;
583         x_r2 = sys->memory[sys->cpu->pr] & 0xF;
584         sys->cpu->pr++;
585         /* オペランドの取り出し */
586         if(cmd->type == R1_R2) {
587             /* オペランドの数値が汎用レジスタの範囲外の場合はエラー */
588             if(x_r2 > GRSIZE - 1) {
589                 setcerr(209, pr2str(sys->cpu->pr-1));    /* not GR in operand x */
590                 goto execerr;
591             }
592             val = sys->cpu->gr[x_r2];
593         }
594         else if(cmd->type ==  R_ADR_X || cmd->type == R_ADR_X_ || cmd->type == ADR_X) {
595             /* オペランドの数値が汎用レジスタの範囲外の場合はエラー */
596             if(x_r2 > GRSIZE - 1) {
597                 setcerr(209, pr2str(sys->cpu->pr-1));    /* not GR in operand x */
598                 goto execerr;
599             }
600             /* 実効アドレス(値または値が示す番地)を取得  */
601             val = sys->memory[sys->cpu->pr++];
602             /* 指標アドレスを加算  */
603             if(x_r2 > 0x0) {
604                 val += sys->cpu->gr[x_r2];
605             }
606             /* ロード/算術論理演算命令/比較演算命令では、アドレスに格納されている内容を取得 */
607             if(cmd->type == R_ADR_X_) {
608                 if(val >= sys->memsize) {
609                     setcerr(206, pr2str(sys->cpu->pr-1));    /* Address - out of COMET II memory */
610                     goto execerr;
611                 }
612                 val = sys->memory[val];
613             }
614         }
615         /* 主オペランドが1から4の場合、第2ビットを無視 */
616         if(op >= 0x1000 && op <= 0x4FFF) {
617             op &= 0xFB00;
618         }
619         /* 命令の実行 */
620         (*cmdptr)(r_r1, val);
621         /* エラー発生時はエラー終了 */
622         if(cerr->num > 0) {
623             goto execerr;
624         }
625         /* 終了フラグがtrueの場合は、正常終了 */
626         if(execptr->stop == true) {
627             break;
628         }
629         /* クロック周波数の設定 */
630         do {
631             clock_end = clock();
632         } while(clock_end - clock_begin < CLOCKS_PER_SEC / sys->clocks);
633     }
634     return true;
635 execerr:
636     fprintf(stderr, "Execute error - %d: %s\n", cerr->num, cerr->msg);
637     return false;
638 }