xref: /plan9-contrib/sys/src/cmd/aux/realemu/xec.c (revision ccaec48a6a7d481d90233fb80c88e608b0a02604)
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