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