1 #include <u.h>
2 #include <libc.h>
3 #include "dat.h"
4 #include "fns.h"
5
6 #define sign(s) (1UL<<((s)-1))
7 #define mask(s) (sign(s)|(sign(s)-1))
8
9 static void
push(Iarg * sp,Iarg * a)10 push(Iarg *sp, Iarg *a)
11 {
12 Iarg *p;
13
14 p = amem(sp->cpu, a->len, RSS, ar(sp));
15 p->off -= a->len;
16 p->off &= mask(sp->len*8);
17 aw(p, ar(a));
18 aw(sp, p->off);
19 }
20
21 static void
pop(Iarg * sp,Iarg * a)22 pop(Iarg *sp, Iarg *a)
23 {
24 Iarg *p;
25
26 p = amem(sp->cpu, a->len, RSS, ar(sp));
27 aw(a, ar(p));
28 aw(sp, p->off + a->len);
29 }
30
31 static void
jump(Iarg * to)32 jump(Iarg *to)
33 {
34 Cpu *cpu;
35
36 cpu = to->cpu;
37 switch(to->atype){
38 default:
39 abort();
40 case AMp:
41 to = afar(to, 1, to->len);
42 case AAp:
43 cpu->reg[RCS] = to->seg;
44 case AJb:
45 case AJv:
46 cpu->reg[RIP] = to->off;
47 break;
48 case AEv:
49 cpu->reg[RIP] = ar(to);
50 break;
51 }
52 }
53
54 static void
opcall(Cpu * cpu,Inst * i)55 opcall(Cpu *cpu, Inst *i)
56 {
57 Iarg *sp;
58
59 sp = areg(cpu, cpu->slen, RSP);
60 switch(i->a1->atype){
61 default:
62 abort();
63 case AAp:
64 case AMp:
65 push(sp, areg(cpu, i->olen, RCS));
66 case AJv:
67 case AEv:
68 push(sp, areg(cpu, i->olen, RIP));
69 break;
70 }
71 jump(i->a1);
72 }
73
74 static void
opint(Cpu * cpu,Inst * i)75 opint(Cpu *cpu, Inst *i)
76 {
77 cpu->trap = ar(i->a1);
78 longjmp(cpu->jmp, 1);
79 }
80
81 static void
opiret(Cpu * cpu,Inst * i)82 opiret(Cpu *cpu, Inst *i)
83 {
84 Iarg *sp;
85
86 if(i->olen != 2)
87 trap(cpu, EBADOP);
88 sp = areg(cpu, cpu->slen, RSP);
89 pop(sp, areg(cpu, 2, RIP));
90 pop(sp, areg(cpu, 2, RCS));
91 pop(sp, areg(cpu, 2, RFL));
92 }
93
94 static void
opret(Cpu * cpu,Inst * i)95 opret(Cpu *cpu, Inst *i)
96 {
97 Iarg *sp;
98 ulong c;
99
100 sp = areg(cpu, cpu->slen, RSP);
101 pop(sp, areg(cpu, i->olen, RIP));
102 if(c = ar(i->a1))
103 aw(sp, ar(sp) + c);
104 }
105
106 static void
opretf(Cpu * cpu,Inst * i)107 opretf(Cpu *cpu, Inst *i)
108 {
109 Iarg *sp;
110 ulong c;
111
112 sp = areg(cpu, cpu->slen, RSP);
113 pop(sp, areg(cpu, i->olen, RIP));
114 pop(sp, areg(cpu, i->olen, RCS));
115 if(c = ar(i->a1))
116 aw(sp, ar(sp) + c);
117 }
118
119 static void
openter(Cpu * cpu,Inst * i)120 openter(Cpu *cpu, Inst *i)
121 {
122 Iarg *sp, *bp;
123 ulong oframe, nframe;
124 int j, n;
125
126 sp = areg(cpu, cpu->slen, RSP);
127 bp = areg(cpu, cpu->slen, RBP);
128 push(sp, bp);
129 oframe = ar(bp);
130 nframe = ar(sp);
131 n = ar(i->a2) % 32;
132 if(n > 0){
133 for(j=1; j<n; j++){
134 aw(bp, oframe - i->olen*j);
135 push(sp, bp);
136 }
137 push(sp, acon(cpu, i->olen, nframe));
138 }
139 aw(bp, nframe);
140 aw(sp, nframe - ar(i->a1));
141 }
142
143 static void
opleave(Cpu * cpu,Inst * i)144 opleave(Cpu *cpu, Inst *i)
145 {
146 Iarg *sp;
147
148 sp = areg(cpu, cpu->slen, RSP);
149 aw(sp, ar(areg(cpu, cpu->slen, RBP)));
150 pop(sp, areg(cpu, i->olen, RBP));
151 }
152
153 static void
oppush(Cpu * cpu,Inst * i)154 oppush(Cpu *cpu, Inst *i)
155 {
156 Iarg *sp;
157
158 sp = areg(cpu, cpu->slen, RSP);
159 if(i->a1->len == 1) /* 0x6A push imm8 */
160 push(sp, acon(cpu, i->olen, ar(i->a1)));
161 else
162 push(sp, i->a1);
163 }
164
165 static void
oppop(Cpu * cpu,Inst * i)166 oppop(Cpu *cpu, Inst *i)
167 {
168 pop(areg(cpu, cpu->slen, RSP), i->a1);
169 }
170
171 static void
oppusha(Cpu * cpu,Inst * i)172 oppusha(Cpu *cpu, Inst *i)
173 {
174 Iarg *sp, *osp;
175
176 sp = areg(cpu, cpu->slen, RSP);
177 osp = acon(cpu, i->olen, ar(sp));
178 push(sp, areg(cpu, i->olen, RAX));
179 push(sp, areg(cpu, i->olen, RCX));
180 push(sp, areg(cpu, i->olen, RDX));
181 push(sp, areg(cpu, i->olen, RBX));
182 push(sp, osp);
183 push(sp, areg(cpu, i->olen, RBP));
184 push(sp, areg(cpu, i->olen, RSI));
185 push(sp, areg(cpu, i->olen, RDI));
186 }
187
188 static void
oppopa(Cpu * cpu,Inst * i)189 oppopa(Cpu *cpu, Inst *i)
190 {
191 Iarg *sp;
192
193 sp = areg(cpu, cpu->slen, RSP);
194 pop(sp, areg(cpu, i->olen, RDI));
195 pop(sp, areg(cpu, i->olen, RSI));
196 pop(sp, areg(cpu, i->olen, RBP));
197 pop(sp, areg(cpu, i->olen, RBX)); // RSP
198 pop(sp, areg(cpu, i->olen, RBX));
199 pop(sp, areg(cpu, i->olen, RDX));
200 pop(sp, areg(cpu, i->olen, RCX));
201 pop(sp, areg(cpu, i->olen, RAX));
202 }
203
204 static void
oppushf(Cpu * cpu,Inst * i)205 oppushf(Cpu *cpu, Inst *i)
206 {
207 push(areg(cpu, cpu->slen, RSP), areg(cpu, i->olen, RFL));
208 }
209
210 static void
oppopf(Cpu * cpu,Inst * i)211 oppopf(Cpu *cpu, Inst *i)
212 {
213 ulong *f, o;
214
215 f = cpu->reg + RFL;
216 o = *f;
217 pop(areg(cpu, cpu->slen, RSP), areg(cpu, i->olen, RFL));
218 *f &= ~(VM|RF);
219 *f |= (o & (VM|RF));
220 }
221
222 static void
oplahf(Cpu * cpu,Inst * i)223 oplahf(Cpu *cpu, Inst *i)
224 {
225 aw(i->a1, cpu->reg[RFL]);
226 }
227
228 static void
opsahf(Cpu * cpu,Inst * i)229 opsahf(Cpu *cpu, Inst *i)
230 {
231 enum { MASK = SF|ZF|AF|PF|CF };
232 ulong *f;
233
234 f = cpu->reg + RFL;
235 *f &= ~MASK;
236 *f |= (ar(i->a1) & MASK);
237 }
238
239 static void
opcli(Cpu * cpu,Inst *)240 opcli(Cpu *cpu, Inst *)
241 {
242 cpu->reg[RFL] &= ~IF;
243 }
244
245 static void
opsti(Cpu * cpu,Inst *)246 opsti(Cpu *cpu, Inst *)
247 {
248 cpu->reg[RFL] |= IF;
249 }
250
251 static void
opcld(Cpu * cpu,Inst *)252 opcld(Cpu *cpu, Inst *)
253 {
254 cpu->reg[RFL] &= ~DF;
255 }
256
257 static void
opstd(Cpu * cpu,Inst *)258 opstd(Cpu *cpu, Inst *)
259 {
260 cpu->reg[RFL] |= DF;
261 }
262
263 static void
opclc(Cpu * cpu,Inst *)264 opclc(Cpu *cpu, Inst *)
265 {
266 cpu->reg[RFL] &= ~CF;
267 }
268
269 static void
opstc(Cpu * cpu,Inst *)270 opstc(Cpu *cpu, Inst *)
271 {
272 cpu->reg[RFL] |= CF;
273 }
274
275 static void
opcmc(Cpu * cpu,Inst *)276 opcmc(Cpu *cpu, Inst *)
277 {
278 cpu->reg[RFL] ^= CF;
279 }
280
281 static void
parity(ulong * f,ulong r)282 parity(ulong *f, ulong r)
283 {
284 static ulong tab[8] = {
285 0x96696996,
286 0x69969669,
287 0x69969669,
288 0x96696996,
289 0x69969669,
290 0x96696996,
291 0x96696996,
292 0x69969669,
293 };
294 r &= 0xFF;
295 if((tab[r/32] >> (r%32)) & 1)
296 *f &= ~PF;
297 else
298 *f |= PF;
299 }
300
301 static ulong
test(ulong * f,long r,int s)302 test(ulong *f, long r, int s)
303 {
304 *f &= ~(CF|SF|ZF|OF|PF);
305 r &= mask(s);
306 if(r == 0)
307 *f |= ZF;
308 if(r & sign(s))
309 *f |= SF;
310 parity(f, r);
311 return r;
312 }
313
314 static void
opshl(Cpu * cpu,Inst * i)315 opshl(Cpu *cpu, Inst *i)
316 {
317 ulong *f, r, a, h;
318 int s, n;
319
320 if((n = ar(i->a2) & 31) == 0)
321 return;
322 s = i->a1->len*8;
323 a = ar(i->a1);
324 f = cpu->reg + RFL;
325 r = test(f, a<<n, s);
326 h = sign(s);
327 aw(i->a1, r);
328 if((a<<(n-1)) & h)
329 *f |= CF;
330 if(n == 1 && ((a^r) & h))
331 *f |= OF;
332 }
333
334 static void
opshr(Cpu * cpu,Inst * i)335 opshr(Cpu *cpu, Inst *i)
336 {
337 ulong *f, a;
338 int s, n;
339
340 if((n = ar(i->a2) & 31) == 0)
341 return;
342 s = i->a1->len*8;
343 a = ar(i->a1);
344 f = cpu->reg + RFL;
345 aw(i->a1, test(f, a>>n, s));
346 if(a & sign(n))
347 *f |= CF;
348 if(n == 1 && (a & sign(s)))
349 *f |= OF;
350 }
351
352 static void
opsar(Cpu * cpu,Inst * i)353 opsar(Cpu *cpu, Inst *i)
354 {
355 ulong *f;
356 long a;
357 int n;
358
359 if((n = ar(i->a2) & 31) == 0)
360 return;
361 a = ars(i->a1);
362 f = cpu->reg + RFL;
363 aw(i->a1, test(f, a>>n, i->a1->len*8));
364 if(a & sign(n))
365 *f |= CF;
366 }
367
368 static void
opshld(Cpu * cpu,Inst * i)369 opshld(Cpu *cpu, Inst *i)
370 {
371 ulong *f, a;
372 int s, n;
373
374 if((n = ar(i->a3) & 31) == 0)
375 return;
376 s = i->a1->len*8;
377 a = ar(i->a1);
378 f = cpu->reg + RFL;
379 aw(i->a1, test(f, (a<<n)|(ar(i->a2)>>(s-n)), s));
380 if((a<<(n-1)) & sign(s))
381 *f |= CF;
382 }
383
384 static void
opshrd(Cpu * cpu,Inst * i)385 opshrd(Cpu *cpu, Inst *i)
386 {
387 ulong *f, a;
388 int s, n;
389
390 if((n = ar(i->a3) & 31) == 0)
391 return;
392 s = i->a1->len*8;
393 a = ar(i->a1);
394 f = cpu->reg + RFL;
395 aw(i->a1, test(f, (a>>n)|(ar(i->a2)<<(s-n)), s));
396 if(a & sign(n))
397 *f |= CF;
398 }
399
400
401 static void
oprcl(Cpu * cpu,Inst * i)402 oprcl(Cpu *cpu, Inst *i)
403 {
404 ulong *f, a, r;
405 int s, n;
406
407 s = i->a1->len*8;
408 n = ar(i->a2) % (s+1);
409 a = ar(i->a1);
410 r = (a<<n) | ((a>>(s-n))>>1);
411 f = cpu->reg + RFL;
412 if(*f & CF)
413 r |= sign(n);
414 aw(i->a1, r);
415 *f &= ~(CF|OF);
416 if((a>>(s-n)) & 1)
417 *f |= CF;
418 if((a ^ r) & sign(s))
419 *f |= OF;
420 parity(f, r);
421 }
422
423 static void
oprcr(Cpu * cpu,Inst * i)424 oprcr(Cpu *cpu, Inst *i)
425 {
426 ulong *f, a, r, h;
427 int s, n;
428
429 s = i->a1->len*8;
430 n = ar(i->a2) % (s+1);
431 a = ar(i->a1);
432 h = a<<(s-n);
433 r = (a>>n) | (h<<1);
434 f = cpu->reg + RFL;
435 if(*f & CF)
436 r |= 1<<(s-n);
437 aw(i->a1, r);
438 *f &= ~(CF|OF);
439 if(h & sign(s))
440 *f |= CF;
441 if((a ^ r) & sign(s))
442 *f |= OF;
443 parity(f, r);
444 }
445
446 static void
oprol(Cpu * cpu,Inst * i)447 oprol(Cpu *cpu, Inst *i)
448 {
449 ulong *f, a, r;
450 int s, n;
451
452 s = i->a1->len*8;
453 n = ar(i->a2) & (s-1);
454 a = ar(i->a1);
455 r = (a<<n) | (a>>(s-n));
456 f = cpu->reg + RFL;
457 aw(i->a1, r);
458 *f &= ~(CF|OF);
459 if(r & 1)
460 *f |= CF;
461 if((a ^ r) & sign(s))
462 *f |= OF;
463 parity(f, r);
464 }
465
466 static void
opror(Cpu * cpu,Inst * i)467 opror(Cpu *cpu, Inst *i)
468 {
469 ulong *f, a, r;
470 int s, n;
471
472 s = i->a1->len*8;
473 n = ar(i->a2) & (s-1);
474 a = ar(i->a1);
475 r = (a>>n) | (a<<(s-n));
476 aw(i->a1, r);
477 f = cpu->reg + RFL;
478 *f &= ~(CF|OF);
479 if(r & sign(s))
480 *f |= CF;
481 if((a ^ r) & sign(s))
482 *f |= OF;
483 parity(f, r);
484 }
485
486 static void
opbittest(Cpu * cpu,Inst * i)487 opbittest(Cpu *cpu, Inst *i)
488 {
489 ulong a, m;
490 int n, s;
491 Iarg *x;
492
493 n = ar(i->a2);
494 x = i->a1;
495 s = x->len*8;
496 if(x->tag == TMEM){
497 x = adup(x);
498 x->off += (n / s) * x->len;
499 x->off &= mask(i->alen*8);
500 }
501 a = ar(x);
502 n &= s-1;
503 m = 1<<n;
504 if(a & m)
505 cpu->reg[RFL] |= CF;
506 else
507 cpu->reg[RFL] &= ~CF;
508 switch(i->op){
509 case OBT:
510 break;
511 case OBTS:
512 aw(x, a | m);
513 break;
514 case OBTR:
515 aw(x, a & ~m);
516 break;
517 case OBTC:
518 aw(x, a ^ m);
519 break;
520 }
521 }
522
523 static void
opbitscan(Cpu * cpu,Inst * i)524 opbitscan(Cpu *cpu, Inst *i)
525 {
526 ulong a;
527
528 if((a = ar(i->a2)) == 0)
529 cpu->reg[RFL] |= ZF;
530 else {
531 int j;
532
533 if(i->op == OBSF){
534 for(j = 0; (a & (1<<j)) == 0; j++)
535 ;
536 } else {
537 for(j = i->a2->len*8-1; (a & (1<<j)) == 0; j--)
538 ;
539 }
540 aw(i->a1, j);
541 cpu->reg[RFL] &= ~ZF;
542 }
543 }
544
545 static void
opand(Cpu * cpu,Inst * i)546 opand(Cpu *cpu, Inst *i)
547 {
548 aw(i->a1, test(cpu->reg + RFL, ars(i->a1) & ars(i->a2), i->a1->len*8));
549 }
550
551 static void
opor(Cpu * cpu,Inst * i)552 opor(Cpu *cpu, Inst *i)
553 {
554 aw(i->a1, test(cpu->reg + RFL, ars(i->a1) | ars(i->a2), i->a1->len*8));
555 }
556
557 static void
opxor(Cpu * cpu,Inst * i)558 opxor(Cpu *cpu, Inst *i)
559 {
560 aw(i->a1, test(cpu->reg + RFL, ars(i->a1) ^ ars(i->a2), i->a1->len*8));
561 }
562
563 static void
opnot(Cpu *,Inst * i)564 opnot(Cpu *, Inst *i)
565 {
566 aw(i->a1, ~ar(i->a1));
567 }
568
569 static void
optest(Cpu * cpu,Inst * i)570 optest(Cpu *cpu, Inst *i)
571 {
572 test(cpu->reg + RFL, ars(i->a1) & ars(i->a2), i->a1->len*8);
573 }
574
575 static ulong
add(ulong * f,long a,long b,int c,int s)576 add(ulong *f, long a, long b, int c, int s)
577 {
578 ulong r, cc, m, n;
579
580 *f &= ~(AF|CF|SF|ZF|OF|PF);
581
582 n = sign(s);
583 m = mask(s);
584 r = a + b + c;
585 r &= m;
586 if(r == 0)
587 *f |= ZF;
588 if(r & n)
589 *f |= SF;
590 cc = (a & b) | (~r & (a | b));
591 if(cc & n)
592 *f |= CF;
593 if((cc ^ (cc >> 1)) & (n>>1))
594 *f |= OF;
595 parity(f, r);
596 return r;
597 }
598
599 static ulong
sub(ulong * f,long a,long b,int c,int s)600 sub(ulong *f, long a, long b, int c, int s)
601 {
602 ulong r, bc, n;
603
604 *f &= ~(AF|CF|SF|ZF|OF|PF);
605
606 r = a - b - c;
607 n = sign(s);
608 r &= mask(s);
609 if(r == 0)
610 *f |= ZF;
611 if(r & n)
612 *f |= SF;
613 a = ~a;
614 bc = (a & b) | (r & (a | b));
615 if(bc & n)
616 *f |= CF;
617 if((bc ^ (bc >> 1)) & (n>>1))
618 *f |= OF;
619 parity(f, r);
620 return r;
621 }
622
623 static void
opadd(Cpu * cpu,Inst * i)624 opadd(Cpu *cpu, Inst *i)
625 {
626 aw(i->a1, add(cpu->reg + RFL, ars(i->a1), ars(i->a2), 0, i->a1->len*8));
627 }
628
629 static void
opadc(Cpu * cpu,Inst * i)630 opadc(Cpu *cpu, Inst *i)
631 {
632 ulong *f = cpu->reg + RFL;
633
634 aw(i->a1, add(f, ars(i->a1), ars(i->a2), (*f & CF) != 0, i->a1->len*8));
635 }
636
637 static void
opsub(Cpu * cpu,Inst * i)638 opsub(Cpu *cpu, Inst *i)
639 {
640 aw(i->a1, sub(cpu->reg + RFL, ars(i->a1), ars(i->a2), 0, i->a1->len*8));
641 }
642
643 static void
opsbb(Cpu * cpu,Inst * i)644 opsbb(Cpu *cpu, Inst *i)
645 {
646 ulong *f = cpu->reg + RFL;
647
648 aw(i->a1, sub(f, ars(i->a1), ars(i->a2), (*f & CF) != 0, i->a1->len*8));
649 }
650
651 static void
opneg(Cpu * cpu,Inst * i)652 opneg(Cpu *cpu, Inst *i)
653 {
654 aw(i->a1, sub(cpu->reg + RFL, 0, ars(i->a1), 0, i->a1->len*8));
655 }
656
657 static void
opcmp(Cpu * cpu,Inst * i)658 opcmp(Cpu *cpu, Inst *i)
659 {
660 sub(cpu->reg + RFL, ars(i->a1), ars(i->a2), 0, i->a1->len*8);
661 }
662
663 static void
opinc(Cpu * cpu,Inst * i)664 opinc(Cpu *cpu, Inst *i)
665 {
666 ulong *f, o;
667
668 f = cpu->reg + RFL;
669 o = *f;
670 aw(i->a1, add(f, ars(i->a1), 1, 0, i->a1->len*8));
671 *f = (*f & ~CF) | (o & CF);
672 }
673
674 static void
opdec(Cpu * cpu,Inst * i)675 opdec(Cpu *cpu, Inst *i)
676 {
677 ulong *f, o;
678
679 f = cpu->reg + RFL;
680 o = *f;
681 aw(i->a1, sub(f, ars(i->a1), 1, 0, i->a1->len*8));
682 *f = (*f & ~CF) | (o & CF);
683 }
684
685 static void
opmul(Cpu * cpu,Inst * i)686 opmul(Cpu *cpu, Inst *i)
687 {
688 Iarg *la, *ha;
689 ulong l, h, m;
690 uvlong r;
691 int s;
692
693 s = i->a2->len*8;
694 m = mask(s);
695 r = ar(i->a2) * ar(i->a3);
696 l = r & m;
697 h = (r >> s) & m;
698 if(i->a1->atype != AAX)
699 abort();
700 la = areg(cpu, i->a2->len, RAX);
701 if(s == 8){
702 ha = adup(la);
703 ha->tag |= TH;
704 } else
705 ha = areg(cpu, i->a2->len, RDX);
706 aw(la, l);
707 aw(ha, h);
708 if(h)
709 cpu->reg[RFL] |= (CF|OF);
710 else
711 cpu->reg[RFL] &= ~(CF|OF);
712 }
713
714 static void
opimul(Cpu * cpu,Inst * i)715 opimul(Cpu *cpu, Inst *i)
716 {
717 ulong l, h, m, n;
718 vlong r;
719 int s;
720
721 s = i->a2->len*8;
722 m = mask(s);
723 n = sign(s);
724 r = ars(i->a2) * ars(i->a3);
725 h = (r >> s) & m;
726 l = r & m;
727 if(i->a1->atype == AAX){
728 Iarg *la, *ha;
729
730 la = areg(cpu, i->a2->len, RAX);
731 if(s == 8){
732 ha = adup(la);
733 ha->tag |= TH;
734 }else
735 ha = areg(cpu, i->a2->len, RDX);
736 aw(la, l);
737 aw(ha, h);
738 } else
739 aw(i->a1, l);
740 if((r > (vlong)n-1) || (r < -(vlong)n))
741 cpu->reg[RFL] |= (CF|OF);
742 else
743 cpu->reg[RFL] &= ~(CF|OF);
744 }
745
746 static void
opdiv(Cpu * cpu,Inst * i)747 opdiv(Cpu *cpu, Inst *i)
748 {
749 Iarg *qa, *ra;
750 uvlong n, q;
751 ulong m, r, d;
752 int s;
753
754 s = i->a1->len*8;
755 m = mask(s);
756 d = ar(i->a1);
757 if(d == 0)
758 trap(cpu, EDIV0);
759 if(s == 8){
760 qa = areg(cpu, 1, RAX);
761 ra = adup(qa);
762 ra->tag |= TH;
763 } else {
764 qa = areg(cpu, i->olen, RAX);
765 ra = areg(cpu, i->olen, RDX);
766 }
767 n = (uvlong)ar(ra)<<s | (uvlong)ar(qa);
768 q = n/d;
769 if(q > m)
770 trap(cpu, EDIV0);
771 r = n%d;
772 aw(ra, r);
773 aw(qa, q);
774 }
775
776 static void
opidiv(Cpu * cpu,Inst * i)777 opidiv(Cpu *cpu, Inst *i)
778 {
779 Iarg *qa, *ra;
780 vlong n, q, min, max;
781 long r, d;
782 int s;
783
784 s = i->a1->len*8;
785 d = ars(i->a1);
786 if(d == 0)
787 trap(cpu, EDIV0);
788 if(s == 8){
789 qa = areg(cpu, 1, RAX);
790 ra = adup(qa);
791 ra->tag |= TH;
792 } else {
793 qa = areg(cpu, i->olen, RAX);
794 ra = areg(cpu, i->olen, RDX);
795 }
796 n = (vlong)ars(ra)<<s | (uvlong)ars(qa);
797 q = n/d;
798 r = n%d;
799
800 max = sign(s)-1;
801 min = ~max;
802
803 if(q > max || q < min)
804 trap(cpu, EDIV0);
805
806 aw(ra, r);
807 aw(qa, q);
808 }
809
810 static int
cctrue(Cpu * cpu,Inst * i)811 cctrue(Cpu *cpu, Inst *i)
812 {
813 enum { SO = 1<<16, /* pseudo-flag SF != OF */ };
814 static ulong test[] = {
815 OF, /* JO, JNO */
816 CF, /* JC, JNC */
817 ZF, /* JZ, JNZ */
818 CF|ZF, /* JBE,JA */
819 SF, /* JS, JNS */
820 PF, /* JP, JNP */
821 SO, /* JL, JGE */
822 SO|ZF, /* JLE,JG */
823 };
824 ulong f, t;
825 uchar c;
826
827 c = i->code;
828 switch(c){
829 case 0xE3: /* JCXZ */
830 return ar(areg(cpu, i->alen, RCX)) == 0;
831 case 0xEB: /* JMP */
832 case 0xE9:
833 case 0xEA:
834 case 0xFF:
835 return 1;
836 default:
837 f = cpu->reg[RFL];
838 if(((f&SF)!=0) ^ ((f&OF)!=0))
839 f |= SO;
840 t = test[(c>>1)&7];
841 return ((t&f) != 0) ^ (c&1);
842 }
843 }
844
845 static void
opjump(Cpu * cpu,Inst * i)846 opjump(Cpu *cpu, Inst *i)
847 {
848 if(cctrue(cpu, i))
849 jump(i->a1);
850 }
851
852 static void
opset(Cpu * cpu,Inst * i)853 opset(Cpu *cpu, Inst *i)
854 {
855 aw(i->a1, cctrue(cpu, i));
856 }
857
858 static void
oploop(Cpu * cpu,Inst * i)859 oploop(Cpu *cpu, Inst *i)
860 {
861 Iarg *cx;
862 ulong c;
863
864 switch(i->op){
865 default:
866 abort();
867 case OLOOPNZ:
868 if(cpu->reg[RFL] & ZF)
869 return;
870 break;
871 case OLOOPZ:
872 if((cpu->reg[RFL] & ZF) == 0)
873 return;
874 break;
875 case OLOOP:
876 break;
877 }
878 cx = areg(cpu, i->alen, RCX);
879 c = ar(cx) - 1;
880 aw(cx, c);
881 if(c)
882 jump(i->a1);
883 }
884
885 static void
oplea(Cpu *,Inst * i)886 oplea(Cpu *, Inst *i)
887 {
888 aw(i->a1, i->a2->off);
889 }
890
891 static void
opmov(Cpu *,Inst * i)892 opmov(Cpu *, Inst *i)
893 {
894 aw(i->a1, ar(i->a2));
895 }
896
897 static void
opcbw(Cpu * cpu,Inst * i)898 opcbw(Cpu *cpu, Inst *i)
899 {
900 aw(areg(cpu, i->olen, RAX), ars(areg(cpu, i->olen>>1, RAX)));
901 }
902
903 static void
opcwd(Cpu * cpu,Inst * i)904 opcwd(Cpu *cpu, Inst *i)
905 {
906 aw(areg(cpu, i->olen, RDX), ars(areg(cpu, i->olen, RAX))>>(i->olen*8-1));
907 }
908
909 static void
opmovsx(Cpu *,Inst * i)910 opmovsx(Cpu *, Inst *i)
911 {
912 aw(i->a1, ars(i->a2));
913 }
914
915 static void
opxchg(Cpu *,Inst * i)916 opxchg(Cpu *, Inst *i)
917 {
918 ulong x;
919
920 x = ar(i->a1);
921 aw(i->a1, ar(i->a2));
922 aw(i->a2, x);
923 }
924
925 static void
oplfp(Cpu *,Inst * i)926 oplfp(Cpu *, Inst *i)
927 {
928 Iarg *p;
929
930 p = afar(i->a3, i->olen, i->olen);
931 aw(i->a1, p->seg);
932 aw(i->a2, p->off);
933 }
934
935 static void
opbound(Cpu * cpu,Inst * i)936 opbound(Cpu *cpu, Inst *i)
937 {
938 ulong p, s, e;
939
940 p = ar(i->a1);
941 s = ar(i->a2);
942 e = ar(i->a3);
943 if((p < s) || (p >= e))
944 trap(cpu, EBOUND);
945 }
946
947 static void
opxlat(Cpu * cpu,Inst * i)948 opxlat(Cpu *cpu, Inst *i)
949 {
950 aw(i->a1, ar(amem(cpu, i->a1->len, i->sreg, ar(areg(cpu, i->alen, i->a2->reg)) + ar(i->a1))));
951 }
952
953 static void
opcpuid(Cpu * cpu,Inst *)954 opcpuid(Cpu *cpu, Inst *)
955 {
956 static struct {
957 ulong level;
958
959 ulong ax;
960 ulong bx;
961 ulong cx;
962 ulong dx;
963 } tab[] = {
964 0,
965 5,
966 0x756e6547, /* Genu */
967 0x6c65746e, /* ntel */
968 0x49656e69, /* ineI */
969 1,
970 4<<8,
971 0x00000000,
972 0x00000000,
973 0x00000000,
974 2,
975 0x00000000,
976 0x00000000,
977 0x00000000,
978 0x00000000,
979 3,
980 0x00000000,
981 0x00000000,
982 0x00000000,
983 0x00000000,
984 };
985
986 int i;
987
988 for(i=0; i<nelem(tab); i++){
989 if(tab[i].level == cpu->reg[RAX]){
990 cpu->reg[RAX] = tab[i].ax;
991 cpu->reg[RBX] = tab[i].bx;
992 cpu->reg[RCX] = tab[i].cx;
993 cpu->reg[RDX] = tab[i].dx;
994 return;
995 }
996 }
997 trap(cpu, EBADOP);
998 }
999
1000 static void
opmovs(Cpu * cpu,Inst * i)1001 opmovs(Cpu *cpu, Inst *i)
1002 {
1003 Iarg *cx, *d, *s;
1004 ulong c, m;
1005 int n;
1006
1007 m = mask(i->alen*8);
1008 d = adup(i->a1);
1009 s = adup(i->a2);
1010 n = s->len;
1011 if(cpu->reg[RFL] & DF)
1012 n = -n;
1013 if(i->rep){
1014 cx = areg(cpu, i->alen, RCX);
1015 c = ar(cx);
1016 } else {
1017 cx = nil;
1018 c = 1;
1019 }
1020 while(c){
1021 aw(d, ar(s));
1022 d->off += n;
1023 d->off &= m;
1024 s->off += n;
1025 s->off &= m;
1026 c--;
1027 }
1028 aw(areg(cpu, i->alen, RDI), d->off);
1029 aw(areg(cpu, i->alen, RSI), s->off);
1030 if(cx)
1031 aw(cx, 0);
1032 }
1033
1034 static void
oplods(Cpu * cpu,Inst * i)1035 oplods(Cpu *cpu, Inst *i)
1036 {
1037 Iarg *cx, *s;
1038 ulong c, m;
1039 int n;
1040
1041 m = mask(i->alen*8);
1042 s = adup(i->a2);
1043 n = s->len;
1044 if(cpu->reg[RFL] & DF)
1045 n = -n;
1046 if(i->rep){
1047 cx = areg(cpu, i->alen, RCX);
1048 c = ar(cx);
1049 } else {
1050 cx = nil;
1051 c = 1;
1052 }
1053 if(c){
1054 s->off += n*(c-1);
1055 s->off &= m;
1056 aw(i->a1, ar(s));
1057 s->off += n;
1058 s->off &= m;
1059 }
1060 aw(areg(cpu, i->alen, RSI), s->off);
1061 if(cx)
1062 aw(cx, 0);
1063 }
1064
1065 static void
opstos(Cpu * cpu,Inst * i)1066 opstos(Cpu *cpu, Inst *i)
1067 {
1068 Iarg *cx, *d;
1069 ulong c, a, m;
1070 int n;
1071
1072 m = mask(i->alen*8);
1073 d = adup(i->a1);
1074 n = d->len;
1075 if(cpu->reg[RFL] & DF)
1076 n = -n;
1077 if(i->rep){
1078 cx = areg(cpu, i->alen, RCX);
1079 c = ar(cx);
1080 } else {
1081 cx = nil;
1082 c = 1;
1083 }
1084 a = ar(i->a2);
1085 while(c){
1086 aw(d, a);
1087 d->off += n;
1088 d->off &= m;
1089 c--;
1090 }
1091 aw(areg(cpu, i->alen, RDI), d->off);
1092 if(cx)
1093 aw(cx, c);
1094 }
1095
1096 static int
repcond(ulong * f,int rep)1097 repcond(ulong *f, int rep)
1098 {
1099 if(rep == OREPNE)
1100 return (*f & ZF) == 0;
1101 return (*f & ZF) != 0;
1102 }
1103
1104 static void
opscas(Cpu * cpu,Inst * i)1105 opscas(Cpu *cpu, Inst *i)
1106 {
1107 Iarg *cx, *d;
1108 ulong *f, c, m;
1109 long a;
1110 int n, z;
1111
1112 m = mask(i->alen*8);
1113 d = adup(i->a1);
1114 n = d->len;
1115 z = n*8;
1116 f = cpu->reg + RFL;
1117 if(*f & DF)
1118 n = -n;
1119 if(i->rep){
1120 cx = areg(cpu, i->alen, RCX);
1121 c = ar(cx);
1122 } else {
1123 cx = nil;
1124 c = 1;
1125 }
1126 a = ars(i->a2);
1127 while(c){
1128 sub(f, a, ars(d), 0, z);
1129 d->off += n;
1130 d->off &= m;
1131 c--;
1132 if(!repcond(f, i->rep))
1133 break;
1134 }
1135 aw(areg(cpu, i->alen, RDI), d->off);
1136 if(cx)
1137 aw(cx, c);
1138 }
1139
1140 static void
opcmps(Cpu * cpu,Inst * i)1141 opcmps(Cpu *cpu, Inst *i)
1142 {
1143 Iarg *cx, *s, *d;
1144 ulong *f, c, m;
1145 int n, z;
1146
1147 m = mask(i->alen*8);
1148 d = adup(i->a1);
1149 s = adup(i->a2);
1150 n = s->len;
1151 z = n*8;
1152 f = cpu->reg + RFL;
1153 if(*f & DF)
1154 n = -n;
1155 if(i->rep){
1156 cx = areg(cpu, i->alen, RCX);
1157 c = ar(cx);
1158 } else {
1159 cx = nil;
1160 c = 1;
1161 }
1162 while(c){
1163 sub(f, ars(s), ars(d), 0, z);
1164 s->off += n;
1165 s->off &= m;
1166 d->off += n;
1167 d->off &= m;
1168 c--;
1169 if(!repcond(f, i->rep))
1170 break;
1171 }
1172 aw(areg(cpu, i->alen, RDI), d->off);
1173 aw(areg(cpu, i->alen, RSI), s->off);
1174 if(cx)
1175 aw(cx, c);
1176 }
1177
1178 static void
opin(Cpu * cpu,Inst * i)1179 opin(Cpu *cpu, Inst *i)
1180 {
1181 Bus *io;
1182
1183 io = cpu->port;
1184 aw(i->a1, io->r(io->aux, ar(i->a2) & 0xFFFF, i->a1->len));
1185 }
1186
1187 static void
opout(Cpu * cpu,Inst * i)1188 opout(Cpu *cpu, Inst *i)
1189 {
1190 Bus *io;
1191
1192 io = cpu->port;
1193 io->w(io->aux, ar(i->a1) & 0xFFFF, ar(i->a2), i->a2->len);
1194 }
1195
1196 static void
opnop(Cpu *,Inst *)1197 opnop(Cpu *, Inst *)
1198 {
1199 }
1200
1201 static void
ophlt(Cpu * cpu,Inst *)1202 ophlt(Cpu *cpu, Inst *)
1203 {
1204 trap(cpu, EHALT);
1205 }
1206
1207 static void (*exctab[NUMOP])(Cpu *cpu, Inst*) = {
1208 [OINT] = opint,
1209 [OIRET] = opiret,
1210
1211 [OCALL] = opcall,
1212 [OJUMP] = opjump,
1213 [OSET] = opset,
1214
1215 [OLOOP] = oploop,
1216 [OLOOPZ] = oploop,
1217 [OLOOPNZ] = oploop,
1218
1219 [ORET] = opret,
1220 [ORETF] = opretf,
1221
1222 [OENTER] = openter,
1223 [OLEAVE] = opleave,
1224
1225 [OPUSH] = oppush,
1226 [OPOP] = oppop,
1227
1228 [OPUSHF] = oppushf,
1229 [OPOPF] = oppopf,
1230 [OLAHF] = oplahf,
1231 [OSAHF] = opsahf,
1232
1233 [OPUSHA] = oppusha,
1234 [OPOPA] = oppopa,
1235
1236 [OCLI] = opcli,
1237 [OSTI] = opsti,
1238 [OCLC] = opclc,
1239 [OSTC] = opstc,
1240 [OCMC] = opcmc,
1241 [OCLD] = opcld,
1242 [OSTD] = opstd,
1243
1244 [OSHL] = opshl,
1245 [OSHR] = opshr,
1246 [OSAR] = opsar,
1247
1248 [OSHLD] = opshld,
1249 [OSHRD] = opshrd,
1250
1251 [ORCL] = oprcl,
1252 [ORCR] = oprcr,
1253 [OROL] = oprol,
1254 [OROR] = opror,
1255
1256 [OBT] = opbittest,
1257 [OBTS] = opbittest,
1258 [OBTR] = opbittest,
1259 [OBTC] = opbittest,
1260
1261 [OBSF] = opbitscan,
1262 [OBSR] = opbitscan,
1263
1264 [OAND] = opand,
1265 [OOR] = opor,
1266 [OXOR] = opxor,
1267 [ONOT] = opnot,
1268 [OTEST] = optest,
1269
1270 [OADD] = opadd,
1271 [OADC] = opadc,
1272 [OSUB] = opsub,
1273 [OSBB] = opsbb,
1274 [ONEG] = opneg,
1275 [OCMP] = opcmp,
1276
1277 [OINC] = opinc,
1278 [ODEC] = opdec,
1279
1280 [OMUL] = opmul,
1281 [OIMUL] = opimul,
1282 [ODIV] = opdiv,
1283 [OIDIV] = opidiv,
1284
1285 [OLEA] = oplea,
1286 [OMOV] = opmov,
1287 [OCBW] = opcbw,
1288 [OCWD] = opcwd,
1289 [OMOVZX] = opmov,
1290 [OMOVSX] = opmovsx,
1291 [OXCHG] = opxchg,
1292 [OLFP] = oplfp,
1293 [OBOUND] = opbound,
1294 [OXLAT] = opxlat,
1295
1296 [OCPUID] = opcpuid,
1297
1298 [OMOVS] = opmovs,
1299 [OLODS] = oplods,
1300 [OSTOS] = opstos,
1301 [OSCAS] = opscas,
1302 [OCMPS] = opcmps,
1303
1304 [OIN] = opin,
1305 [OOUT] = opout,
1306
1307 [ONOP] = opnop,
1308 [OHLT] = ophlt,
1309 };
1310
1311 void
trap(Cpu * cpu,int e)1312 trap(Cpu *cpu, int e)
1313 {
1314 cpu->reg[RIP] = cpu->oldip;
1315 cpu->trap = e;
1316 longjmp(cpu->jmp, 1);
1317 }
1318
1319 int
intr(Cpu * cpu,int v)1320 intr(Cpu *cpu, int v)
1321 {
1322 Iarg *sp, *ip, *cs, *iv;
1323
1324 if(v < 0 || v > 0xff || cpu->olen != 2)
1325 return -1;
1326
1327 sp = areg(cpu, cpu->slen, RSP);
1328 cs = areg(cpu, 2, RCS);
1329 ip = areg(cpu, 2, RIP);
1330
1331 iv = amem(cpu, 2, R0S, v * 4);
1332
1333 push(sp, areg(cpu, 2, RFL));
1334 push(sp, cs);
1335 push(sp, ip);
1336
1337 cpu->reg[RIP] = ar(iv);
1338 iv->off += 2;
1339 cpu->reg[RCS] = ar(iv);
1340 return 0;
1341 }
1342
1343 int
xec(Cpu * cpu,int n)1344 xec(Cpu *cpu, int n)
1345 {
1346 if(setjmp(cpu->jmp))
1347 return cpu->trap;
1348 while(n--){
1349 void (*f)(Cpu *, Inst *);
1350 Iarg *ip;
1351 Inst i;
1352
1353 cpu->ic++;
1354
1355 ip = amem(cpu, 1, RCS, cpu->oldip = cpu->reg[RIP]);
1356 decode(ip, &i);
1357 cpu->reg[RIP] = ip->off;
1358 if((f = exctab[i.op]) == nil)
1359 trap(cpu, EBADOP);
1360 f(cpu, &i);
1361 }
1362 return n;
1363 }
1364