First Commit of my working state
[simh.git] / AltairZ80 / i86_prim_ops.c
1 /*
2 * Dos/PC Emulator
3 * Copyright (C) 1991 Jim Hudgens
4 *
5 *
6 * The file is part of GDE.
7 *
8 * GDE is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 1, or (at your option)
11 * any later version.
12 *
13 * GDE is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with GDE; see the file COPYING. If not, write to
20 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
21 *
22 */
23
24 #include "altairz80_defs.h"
25 #include "i86.h"
26
27 extern uint32 GetBYTEExtended(register uint32 Addr);
28 extern void PutBYTEExtended(register uint32 Addr, const register uint32 Value);
29
30 /* $Log: i86_prim_ops.c,v $
31 * Revision 0.9 2003-01-10 23:33:10 jce
32 * fixed some more warnings under gcc -Wall
33 *
34 * Revision 0.8 1992/04/11 21:58:13 hudgens
35 * fixed some code causing warnings under gcc -Wall
36 *
37 * Revision 0.7 1991/07/30 02:04:34 hudgens
38 * added copyright.
39 *
40 * Revision 0.6 1991/07/21 16:50:37 hudgens
41 * fixed all flags in the bit shift and rotate instructions so that they
42 * finally agree.
43 * Also fixed the flags associated with IMUL and MUL instructions.
44 *
45 * Revision 0.5 1991/07/21 01:28:16 hudgens
46 * added support for aad and aam primitives.
47 *
48 * Revision 0.4 1991/07/20 22:26:25 hudgens
49 * fixed problem with sign extension in subroutine mem_access_word.
50 *
51 * Revision 0.3 1991/07/17 03:48:22 hudgens
52 * fixed bugs having to do with the setting of flags in the
53 * shift and rotate operations. Also, fixed sign extension problem
54 * with push_word and pop_word.
55 *
56 * Revision 0.2 1991/04/01 02:36:00 hudgens
57 * Fixed several nasty bugs dealing with flag setting in the subroutines
58 * sub_byte, sub_word, sbb_byte, sbb_word, and test_word. The results
59 * now agree with the PC on both of the testaopb and testaopw tests.
60 *
61 * Revision 0.1 1991/03/30 21:13:37 hudgens
62 * Initial checkin.
63 *
64 *
65 */
66
67 /* [JCE] Stop gcc -Wall complaining */
68 void i86_intr_raise(PC_ENV *m, uint8 intrnum);
69
70 /* the following table was generated using the following
71 code (running on an IBM AT, Turbo C++ 2.0), for all values of i
72 between 0 and 255. AL is loaded with i's value, and then the
73 operation "and al,al" sets the parity flag. The flags are pushed
74 onto the stack, and then popped back into AX. Then AX is
75 returned. So the value of each table entry represents the
76 parity of its index into the table. This results in a somewhat
77 faster mechanism for parity calculations than the straightforward
78 method.
79 andflags(i,res) int *res; {
80 int flags;
81 _AX = i; asm and al,al; asm pushf; *res = _AX;
82 asm pop ax; flags = _AX; return flags;
83 }
84 */
85
86 char parity_tab[] = {
87 /*0*/ 1, /*1*/ 0, /*2*/ 0, /*3*/ 1,
88 /*4*/ 0, /*5*/ 1, /*6*/ 1, /*7*/ 0,
89 /*8*/ 0, /*9*/ 1, /*a*/ 1, /*b*/ 0,
90 /*c*/ 1, /*d*/ 0, /*e*/ 0, /*f*/ 1,
91 /*10*/ 0, /*11*/ 1, /*12*/ 1, /*13*/ 0,
92 /*14*/ 1, /*15*/ 0, /*16*/ 0, /*17*/ 1,
93 /*18*/ 1, /*19*/ 0, /*1a*/ 0, /*1b*/ 1,
94 /*1c*/ 0, /*1d*/ 1, /*1e*/ 1, /*1f*/ 0,
95 /*20*/ 0, /*21*/ 1, /*22*/ 1, /*23*/ 0,
96 /*24*/ 1, /*25*/ 0, /*26*/ 0, /*27*/ 1,
97 /*28*/ 1, /*29*/ 0, /*2a*/ 0, /*2b*/ 1,
98 /*2c*/ 0, /*2d*/ 1, /*2e*/ 1, /*2f*/ 0,
99 /*30*/ 1, /*31*/ 0, /*32*/ 0, /*33*/ 1,
100 /*34*/ 0, /*35*/ 1, /*36*/ 1, /*37*/ 0,
101 /*38*/ 0, /*39*/ 1, /*3a*/ 1, /*3b*/ 0,
102 /*3c*/ 1, /*3d*/ 0, /*3e*/ 0, /*3f*/ 1,
103 /*40*/ 0, /*41*/ 1, /*42*/ 1, /*43*/ 0,
104 /*44*/ 1, /*45*/ 0, /*46*/ 0, /*47*/ 1,
105 /*48*/ 1, /*49*/ 0, /*4a*/ 0, /*4b*/ 1,
106 /*4c*/ 0, /*4d*/ 1, /*4e*/ 1, /*4f*/ 0,
107 /*50*/ 1, /*51*/ 0, /*52*/ 0, /*53*/ 1,
108 /*54*/ 0, /*55*/ 1, /*56*/ 1, /*57*/ 0,
109 /*58*/ 0, /*59*/ 1, /*5a*/ 1, /*5b*/ 0,
110 /*5c*/ 1, /*5d*/ 0, /*5e*/ 0, /*5f*/ 1,
111 /*60*/ 1, /*61*/ 0, /*62*/ 0, /*63*/ 1,
112 /*64*/ 0, /*65*/ 1, /*66*/ 1, /*67*/ 0,
113 /*68*/ 0, /*69*/ 1, /*6a*/ 1, /*6b*/ 0,
114 /*6c*/ 1, /*6d*/ 0, /*6e*/ 0, /*6f*/ 1,
115 /*70*/ 0, /*71*/ 1, /*72*/ 1, /*73*/ 0,
116 /*74*/ 1, /*75*/ 0, /*76*/ 0, /*77*/ 1,
117 /*78*/ 1, /*79*/ 0, /*7a*/ 0, /*7b*/ 1,
118 /*7c*/ 0, /*7d*/ 1, /*7e*/ 1, /*7f*/ 0,
119 /*80*/ 0, /*81*/ 1, /*82*/ 1, /*83*/ 0,
120 /*84*/ 1, /*85*/ 0, /*86*/ 0, /*87*/ 1,
121 /*88*/ 1, /*89*/ 0, /*8a*/ 0, /*8b*/ 1,
122 /*8c*/ 0, /*8d*/ 1, /*8e*/ 1, /*8f*/ 0,
123 /*90*/ 1, /*91*/ 0, /*92*/ 0, /*93*/ 1,
124 /*94*/ 0, /*95*/ 1, /*96*/ 1, /*97*/ 0,
125 /*98*/ 0, /*99*/ 1, /*9a*/ 1, /*9b*/ 0,
126 /*9c*/ 1, /*9d*/ 0, /*9e*/ 0, /*9f*/ 1,
127 /*a0*/ 1, /*a1*/ 0, /*a2*/ 0, /*a3*/ 1,
128 /*a4*/ 0, /*a5*/ 1, /*a6*/ 1, /*a7*/ 0,
129 /*a8*/ 0, /*a9*/ 1, /*aa*/ 1, /*ab*/ 0,
130 /*ac*/ 1, /*ad*/ 0, /*ae*/ 0, /*af*/ 1,
131 /*b0*/ 0, /*b1*/ 1, /*b2*/ 1, /*b3*/ 0,
132 /*b4*/ 1, /*b5*/ 0, /*b6*/ 0, /*b7*/ 1,
133 /*b8*/ 1, /*b9*/ 0, /*ba*/ 0, /*bb*/ 1,
134 /*bc*/ 0, /*bd*/ 1, /*be*/ 1, /*bf*/ 0,
135 /*c0*/ 1, /*c1*/ 0, /*c2*/ 0, /*c3*/ 1,
136 /*c4*/ 0, /*c5*/ 1, /*c6*/ 1, /*c7*/ 0,
137 /*c8*/ 0, /*c9*/ 1, /*ca*/ 1, /*cb*/ 0,
138 /*cc*/ 1, /*cd*/ 0, /*ce*/ 0, /*cf*/ 1,
139 /*d0*/ 0, /*d1*/ 1, /*d2*/ 1, /*d3*/ 0,
140 /*d4*/ 1, /*d5*/ 0, /*d6*/ 0, /*d7*/ 1,
141 /*d8*/ 1, /*d9*/ 0, /*da*/ 0, /*db*/ 1,
142 /*dc*/ 0, /*dd*/ 1, /*de*/ 1, /*df*/ 0,
143 /*e0*/ 0, /*e1*/ 1, /*e2*/ 1, /*e3*/ 0,
144 /*e4*/ 1, /*e5*/ 0, /*e6*/ 0, /*e7*/ 1,
145 /*e8*/ 1, /*e9*/ 0, /*ea*/ 0, /*eb*/ 1,
146 /*ec*/ 0, /*ed*/ 1, /*ee*/ 1, /*ef*/ 0,
147 /*f0*/ 1, /*f1*/ 0, /*f2*/ 0, /*f3*/ 1,
148 /*f4*/ 0, /*f5*/ 1, /*f6*/ 1, /*f7*/ 0,
149 /*f8*/ 0, /*f9*/ 1, /*fa*/ 1, /*fb*/ 0,
150 /*fc*/ 1, /*fd*/ 0, /*fe*/ 0, /*ff*/ 1,
151 };
152
153 char xor_0x3_tab[] = { 0, 1, 1, 0 };
154
155 /* CARRY CHAIN CALCULATION.
156 This represents a somewhat expensive calculation which is
157 apparently required to emulate the setting of the OF and
158 AF flag. The latter is not so important, but the former is.
159 The overflow flag is the XOR of the top two bits of the
160 carry chain for an addition (similar for subtraction).
161 Since we do not want to simulate the addition in a bitwise
162 manner, we try to calculate the carry chain given the
163 two operands and the result.
164
165 So, given the following table, which represents the
166 addition of two bits, we can derive a formula for
167 the carry chain.
168
169 a b cin r cout
170 0 0 0 0 0
171 0 0 1 1 0
172 0 1 0 1 0
173 0 1 1 0 1
174 1 0 0 1 0
175 1 0 1 0 1
176 1 1 0 0 1
177 1 1 1 1 1
178
179 Construction of table for cout:
180
181 ab
182 r \ 00 01 11 10
183 |------------------
184 0 | 0 1 1 1
185 1 | 0 0 1 0
186
187 By inspection, one gets: cc = ab + r'(a + b)
188
189 That represents alot of operations, but NO CHOICE....
190
191 BORROW CHAIN CALCULATION.
192 The following table represents the
193 subtraction of two bits, from which we can derive a formula for
194 the borrow chain.
195
196 a b bin r bout
197 0 0 0 0 0
198 0 0 1 1 1
199 0 1 0 1 1
200 0 1 1 0 1
201 1 0 0 1 0
202 1 0 1 0 0
203 1 1 0 0 0
204 1 1 1 1 1
205
206 Construction of table for cout:
207
208 ab
209 r \ 00 01 11 10
210 |------------------
211 0 | 0 1 0 0
212 1 | 1 1 1 0
213
214 By inspection, one gets: bc = a'b + r(a' + b)
215
216 */
217
218 uint8 aad_word(PC_ENV *m, uint16 d)
219 {
220 uint16 l;
221 uint8 hb,lb;
222 hb = (d>>8)&0xff;
223 lb = (d&0xff);
224 l = lb + 10 * hb;
225 CONDITIONAL_SET_FLAG(l & 0x80, m, F_SF);
226 CONDITIONAL_SET_FLAG(l == 0, m, F_ZF);
227 CONDITIONAL_SET_FLAG(parity_tab[l & 0xff], m, F_PF);
228 return (uint8) l;
229 }
230
231 uint16 aam_word(PC_ENV *m, uint8 d)
232 {
233 uint16 h,l;
234 h = d / 10;
235 l = d % 10;
236 l |= (h<<8);
237 CONDITIONAL_SET_FLAG(l & 0x80, m, F_SF);
238 CONDITIONAL_SET_FLAG(l == 0, m, F_ZF);
239 CONDITIONAL_SET_FLAG(parity_tab[l & 0xff], m, F_PF);
240 return l;
241 }
242
243 uint8 adc_byte(PC_ENV *m, uint8 d, uint8 s)
244 {
245 register uint16 res; /* all operands in native machine order */
246 register uint16 cc;
247 if (ACCESS_FLAG(m,F_CF) )
248 res = 1 + d + s;
249 else
250 res = d + s;
251 CONDITIONAL_SET_FLAG(res & 0x100, m, F_CF);
252 CONDITIONAL_SET_FLAG((res&0xff)==0, m, F_ZF);
253 CONDITIONAL_SET_FLAG(res & 0x80, m, F_SF);
254 CONDITIONAL_SET_FLAG(parity_tab[res&0xff], m, F_PF);
255 /* calculate the carry chain SEE NOTE AT TOP.*/
256 cc = (s & d) | ((~res) & (s | d));
257 CONDITIONAL_SET_FLAG(xor_0x3_tab[(cc>>6)&0x3], m, F_OF);
258 CONDITIONAL_SET_FLAG(cc&0x8, m, F_AF);
259 return (uint8) res;
260 }
261
262 uint16 adc_word(PC_ENV *m, uint16 d, uint16 s)
263 {
264 register uint32 res; /* all operands in native machine order */
265 register uint32 cc;
266 if (ACCESS_FLAG(m,F_CF) )
267 res = 1 + d + s;
268 else
269 res = d + s;
270 /* set the carry flag to be bit 8 */
271 CONDITIONAL_SET_FLAG(res & 0x10000, m, F_CF);
272 CONDITIONAL_SET_FLAG((res&0xffff)==0, m, F_ZF);
273 CONDITIONAL_SET_FLAG(res & 0x8000, m, F_SF);
274 CONDITIONAL_SET_FLAG(parity_tab[res&0xff], m, F_PF);
275 /* calculate the carry chain SEE NOTE AT TOP.*/
276 cc = (s & d) | ((~res) & (s | d));
277 CONDITIONAL_SET_FLAG(xor_0x3_tab[(cc>>14)&0x3], m, F_OF);
278 CONDITIONAL_SET_FLAG(cc&0x8, m, F_AF);
279 return res;
280 }
281
282 /* Given flags=f, and bytes d (dest) and s (source)
283 perform the add and set the flags and the result back to
284 *d. USE NATIVE MACHINE ORDER...
285 */
286 uint8 add_byte(PC_ENV *m, uint8 d, uint8 s)
287 {
288 register uint16 res; /* all operands in native machine order */
289 register uint16 cc;
290 res = d + s;
291 /* set the carry flag to be bit 8 */
292 CONDITIONAL_SET_FLAG(res & 0x100, m, F_CF);
293 CONDITIONAL_SET_FLAG((res&0xff)==0, m, F_ZF);
294 CONDITIONAL_SET_FLAG(res & 0x80, m, F_SF);
295 CONDITIONAL_SET_FLAG(parity_tab[res&0xff], m, F_PF);
296 /* calculate the carry chain SEE NOTE AT TOP.*/
297 cc = (s & d) | ((~res) & (s | d));
298 CONDITIONAL_SET_FLAG(xor_0x3_tab[(cc>>6)&0x3], m, F_OF);
299 CONDITIONAL_SET_FLAG(cc&0x8, m, F_AF);
300 return (uint8) res;
301 }
302
303 /* Given flags=f, and bytes d (dest) and s (source)
304 perform the add and set the flags and the result back to
305 *d. USE NATIVE MACHINE ORDER...
306 */
307 uint16 add_word(PC_ENV *m, uint16 d, uint16 s)
308 {
309 register uint32 res; /* all operands in native machine order */
310 register uint32 cc;
311 res = d + s;
312 /* set the carry flag to be bit 8 */
313 CONDITIONAL_SET_FLAG(res & 0x10000, m, F_CF);
314 CONDITIONAL_SET_FLAG((res&0xffff)==0, m, F_ZF);
315 CONDITIONAL_SET_FLAG(res & 0x8000, m, F_SF);
316 CONDITIONAL_SET_FLAG(parity_tab[res&0xff], m, F_PF);
317 /* calculate the carry chain SEE NOTE AT TOP.*/
318 cc = (s & d) | ((~res) & (s | d));
319 CONDITIONAL_SET_FLAG(xor_0x3_tab[(cc>>14)&0x3], m, F_OF);
320 CONDITIONAL_SET_FLAG(cc&0x8, m, F_AF);
321 return res;
322 }
323
324 /*
325 Flags m->R_FLG, dest *d, source *s, do a bitwise and of the
326 source and destination, and then store back to the
327 destination. Size=byte.
328 */
329 uint8 and_byte(PC_ENV *m, uint8 d, uint8 s)
330 {
331 register uint8 res; /* all operands in native machine order */
332 res = d & s;
333 /* set the flags */
334 CLEAR_FLAG(m, F_OF);
335 CLEAR_FLAG(m, F_CF);
336 CONDITIONAL_SET_FLAG(res&0x80, m, F_SF);
337 CONDITIONAL_SET_FLAG(res==0, m, F_ZF);
338 CONDITIONAL_SET_FLAG(parity_tab[res], m, F_PF);
339 return res;
340 }
341
342 /*
343 Flags m->R_FLG, dest *d, source *s, do a bitwise and of the
344 source and destination, and then store back to the
345 destination. Size=byte.
346 */
347 uint16 and_word(PC_ENV *m, uint16 d, uint16 s)
348 {
349 register uint16 res; /* all operands in native machine order */
350 res = d & s;
351 /* set the flags */
352 CLEAR_FLAG(m, F_OF);
353 CLEAR_FLAG(m, F_CF);
354 CONDITIONAL_SET_FLAG(res&0x8000, m, F_SF);
355 CONDITIONAL_SET_FLAG(res==0, m, F_ZF);
356 CONDITIONAL_SET_FLAG(parity_tab[res&0xff], m, F_PF);
357 return res;
358 }
359
360 uint8 cmp_byte(PC_ENV *m, uint8 d, uint8 s)
361 {
362 register uint32 res; /* all operands in native machine order */
363 register uint32 bc;
364 res = d - s;
365 CLEAR_FLAG(m, F_CF);
366 CONDITIONAL_SET_FLAG(res&0x80, m, F_SF);
367 CONDITIONAL_SET_FLAG((res&0xff)==0, m, F_ZF);
368 CONDITIONAL_SET_FLAG(parity_tab[res&0xff], m, F_PF);
369 /* calculate the borrow chain. See note at top */
370 bc= (res&(~d|s))|(~d&s);
371 CONDITIONAL_SET_FLAG(bc&0x80,m, F_CF);
372 CONDITIONAL_SET_FLAG(xor_0x3_tab[(bc>>6)&0x3], m, F_OF);
373 CONDITIONAL_SET_FLAG(bc&0x8, m, F_AF);
374 return d; /* long story why this is needed. Look at opcode
375 0x80 in ops.c, for an idea why this is necessary.*/
376 }
377
378 uint16 cmp_word(PC_ENV *m, uint16 d, uint16 s)
379 {
380 register uint32 res; /* all operands in native machine order */
381 register uint32 bc;
382 res = d - s;
383 CONDITIONAL_SET_FLAG(res&0x8000, m, F_SF);
384 CONDITIONAL_SET_FLAG((res&0xffff)==0, m, F_ZF);
385 CONDITIONAL_SET_FLAG(parity_tab[res&0xff], m, F_PF);
386 /* calculate the borrow chain. See note at top */
387 bc= (res&(~d|s))|(~d&s);
388 CONDITIONAL_SET_FLAG(bc&0x8000,m, F_CF);
389 CONDITIONAL_SET_FLAG(xor_0x3_tab[(bc>>14)&0x3], m, F_OF);
390 CONDITIONAL_SET_FLAG(bc&0x8, m, F_AF);
391 return d;
392 }
393
394 uint8 dec_byte(PC_ENV *m, uint8 d)
395 {
396 register uint32 res; /* all operands in native machine order */
397 register uint32 bc;
398 res = d - 1;
399 CONDITIONAL_SET_FLAG(res&0x80, m, F_SF);
400 CONDITIONAL_SET_FLAG((res&0xff)==0, m, F_ZF);
401 CONDITIONAL_SET_FLAG(parity_tab[res&0xff], m, F_PF);
402 /* calculate the borrow chain. See note at top */
403 /* based on sub_byte, uses s==1. */
404 bc= (res&(~d|1))|(~d&1);
405 /* carry flag unchanged */
406 CONDITIONAL_SET_FLAG(xor_0x3_tab[(bc>>6)&0x3], m, F_OF);
407 CONDITIONAL_SET_FLAG(bc&0x8, m, F_AF);
408 return res;
409 }
410
411 uint16 dec_word(PC_ENV *m, uint16 d)
412 {
413 register uint32 res; /* all operands in native machine order */
414 register uint32 bc;
415 res = d - 1;
416 CONDITIONAL_SET_FLAG(res&0x8000, m, F_SF);
417 CONDITIONAL_SET_FLAG((res&0xffff)==0, m, F_ZF);
418 CONDITIONAL_SET_FLAG(parity_tab[res&0xff], m, F_PF);
419 /* calculate the borrow chain. See note at top */
420 /* based on the sub_byte routine, with s==1 */
421 bc= (res&(~d|1))|(~d&1);
422 /* carry flag unchanged */
423 CONDITIONAL_SET_FLAG(xor_0x3_tab[(bc>>14)&0x3], m, F_OF);
424 CONDITIONAL_SET_FLAG(bc&0x8, m, F_AF);
425 return res;
426 }
427
428 /* Given flags=f, and byte d (dest)
429 perform the inc and set the flags and the result back to
430 d. USE NATIVE MACHINE ORDER...
431 */
432 uint8 inc_byte(PC_ENV *m, uint8 d)
433 {
434 register uint32 res; /* all operands in native machine order */
435 register uint32 cc;
436 res = d + 1;
437 CONDITIONAL_SET_FLAG((res&0xff)==0, m, F_ZF);
438 CONDITIONAL_SET_FLAG(res & 0x80, m, F_SF);
439 CONDITIONAL_SET_FLAG(parity_tab[res&0xff], m, F_PF);
440 /* calculate the carry chain SEE NOTE AT TOP.*/
441 cc = ((1 & d) | (~res)) & (1 | d);
442 CONDITIONAL_SET_FLAG(xor_0x3_tab[(cc>>6)&0x3], m, F_OF);
443 CONDITIONAL_SET_FLAG(cc&0x8, m, F_AF);
444 return res;
445 }
446
447 /* Given flags=f, and byte d (dest)
448 perform the inc and set the flags and the result back to
449 *d. USE NATIVE MACHINE ORDER...
450 */
451 uint16 inc_word(PC_ENV *m, uint16 d)
452 {
453 register uint32 res; /* all operands in native machine order */
454 register uint32 cc;
455 res = d + 1;
456 CONDITIONAL_SET_FLAG((res&0xffff)==0, m, F_ZF);
457 CONDITIONAL_SET_FLAG(res & 0x8000, m, F_SF);
458 CONDITIONAL_SET_FLAG(parity_tab[res&0xff], m, F_PF);
459 /* calculate the carry chain SEE NOTE AT TOP.*/
460 cc = (1 & d) | ((~res) & (1 | d));
461 CONDITIONAL_SET_FLAG(xor_0x3_tab[(cc>>14)&0x3], m, F_OF);
462 CONDITIONAL_SET_FLAG(cc&0x8, m, F_AF);
463 return res ;
464 }
465
466 uint8 or_byte(PC_ENV *m, uint8 d, uint8 s)
467 {
468 register uint8 res; /* all operands in native machine order */
469 res = d | s;
470 CLEAR_FLAG(m, F_OF);
471 CLEAR_FLAG(m, F_CF);
472 CONDITIONAL_SET_FLAG(res&0x80, m, F_SF);
473 CONDITIONAL_SET_FLAG(res==0, m, F_ZF);
474 CONDITIONAL_SET_FLAG(parity_tab[res], m, F_PF);
475 return res;
476 }
477
478 uint16 or_word(PC_ENV *m, uint16 d, uint16 s)
479 {
480 register uint16 res; /* all operands in native machine order */
481 res = d | s;
482 /* set the carry flag to be bit 8 */
483 CLEAR_FLAG(m, F_OF);
484 CLEAR_FLAG(m, F_CF);
485 CONDITIONAL_SET_FLAG(res&0x8000, m, F_SF);
486 CONDITIONAL_SET_FLAG(res==0, m, F_ZF);
487 CONDITIONAL_SET_FLAG(parity_tab[res&0xff], m, F_PF);
488 return res;
489 }
490
491 uint8 neg_byte(PC_ENV *m, uint8 s)
492 {
493 register uint8 res;
494 register uint8 bc;
495 CONDITIONAL_SET_FLAG(s!=0, m, F_CF);
496 res = -s;
497 CONDITIONAL_SET_FLAG((res&0xff)==0, m, F_ZF);
498 CONDITIONAL_SET_FLAG(res & 0x80, m, F_SF);
499 CONDITIONAL_SET_FLAG(parity_tab[res], m, F_PF);
500 /* calculate the borrow chain --- modified such that d=0.
501 substitutiing d=0 into bc= res&(~d|s)|(~d&s);
502 (the one used for sub) and simplifying, since ~d=0xff...,
503 ~d|s == 0xffff..., and res&0xfff... == res. Similarly
504 ~d&s == s. So the simplified result is:*/
505 bc= res|s;
506 CONDITIONAL_SET_FLAG(xor_0x3_tab[(bc>>6)&0x3], m, F_OF);
507 CONDITIONAL_SET_FLAG(bc&0x8, m, F_AF);
508 return res;
509 }
510
511 uint16 neg_word(PC_ENV *m, uint16 s)
512 {
513 register uint16 res;
514 register uint16 bc;
515 CONDITIONAL_SET_FLAG(s!=0, m, F_CF);
516 res = -s;
517 CONDITIONAL_SET_FLAG((res&0xffff)==0, m, F_ZF);
518 CONDITIONAL_SET_FLAG(res & 0x8000, m, F_SF);
519 CONDITIONAL_SET_FLAG(parity_tab[res&0xff], m, F_PF);
520 /* calculate the borrow chain --- modified such that d=0.
521 substitutiing d=0 into bc= res&(~d|s)|(~d&s);
522 (the one used for sub) and simplifying, since ~d=0xff...,
523 ~d|s == 0xffff..., and res&0xfff... == res. Similarly
524 ~d&s == s. So the simplified result is:*/
525 bc= res|s;
526 CONDITIONAL_SET_FLAG(xor_0x3_tab[(bc>>6)&0x3], m, F_OF);
527 CONDITIONAL_SET_FLAG(bc&0x8, m, F_AF);
528 return res;
529 }
530
531 uint8 not_byte(PC_ENV *m, uint8 s)
532 {
533 return ~s;
534 }
535
536 uint16 not_word(PC_ENV *m, uint16 s)
537 {
538 return ~s;
539 }
540
541 /* access stuff from absolute location in memory.
542 no segment registers are involved.
543 */
544 uint16 mem_access_word(PC_ENV *m, int addr)
545 {
546 /* Load in two steps. Native byte order independent */
547 return GetBYTEExtended(addr) | (GetBYTEExtended(addr + 1) << 8);
548 }
549
550 /* given the register_set r, and memory descriptor m,
551 and word w, push w onto the stack.
552 w ASSUMED IN NATIVE MACHINE ORDER. Doesn't matter in this case???
553 */
554 void push_word(PC_ENV *m, uint16 w)
555 {
556 m->R_SP --;
557 PutBYTEExtended((m->R_SS << 4) + m->R_SP, w >> 8);
558 m->R_SP --;
559 PutBYTEExtended((m->R_SS << 4) + m->R_SP, w & 0xff);
560 }
561
562 /* given the memory descriptor m,
563 and word w, pop word from the stack.
564 */
565 uint16 pop_word(PC_ENV *m)
566 {
567 register uint16 res;
568 res = GetBYTEExtended((m->R_SS << 4) + m->R_SP);
569 m->R_SP++;
570 res |= GetBYTEExtended((m->R_SS << 4) + m->R_SP) << 8;
571 m->R_SP++;
572 return res;
573 }
574
575 /*****************************************************************
576 BEGIN region consisting of bit shifts and rotates,
577 much of which may be wrong. Large hirsute factor.
578 *****************************************************************/
579 uint8 rcl_byte(PC_ENV *m, uint8 d, uint8 s)
580 {
581 register uint32 res, cnt, mask,cf;
582 /* s is the rotate distance. It varies from 0 - 8. */
583 /* have
584 CF B_7 B_6 B_5 B_4 B_3 B_2 B_1 B_0
585 want to rotate through the carry by "s" bits. We could
586 loop, but that's inefficient. So the width is 9,
587 and we split into three parts:
588 The new carry flag (was B_n)
589 the stuff in B_n-1 .. B_0
590 the stuff in B_7 .. B_n+1
591 The new rotate is done mod 9, and given this,
592 for a rotation of n bits (mod 9) the new carry flag is
593 then located n bits from the MSB. The low part is
594 then shifted up cnt bits, and the high part is or'd
595 in. Using CAPS for new values, and lowercase for the
596 original values, this can be expressed as:
597 IF n > 0
598 1) CF <- b_(8-n)
599 2) B_(7) .. B_(n) <- b_(8-(n+1)) .. b_0
600 3) B_(n-1) <- cf
601 4) B_(n-2) .. B_0 <- b_7 .. b_(8-(n-1))
602 I think this is correct.
603 */
604 res = d;
605 /* [JCE] Extra brackets to stop gcc -Wall moaning */
606 if ((cnt = s % 9)) /* not a typo, do nada if cnt==0 */
607 {
608 /* extract the new CARRY FLAG. */
609 /* CF <- b_(8-n) */
610 cf = (d >> (8-cnt)) & 0x1;
611 /* get the low stuff which rotated
612 into the range B_7 .. B_cnt */
613 /* B_(7) .. B_(n) <- b_(8-(n+1)) .. b_0 */
614 /* note that the right hand side done by the mask */
615 res = (d << cnt) & 0xff;
616 /* now the high stuff which rotated around
617 into the positions B_cnt-2 .. B_0 */
618 /* B_(n-2) .. B_0 <- b_7 .. b_(8-(n-1)) */
619 /* shift it downward, 7-(n-2) = 9-n positions.
620 and mask off the result before or'ing in.
621 */
622 mask = (1<<(cnt-1)) - 1;
623 res |= (d >> (9-cnt)) & mask;
624 /* if the carry flag was set, or it in. */
625 if (ACCESS_FLAG(m,F_CF)) /* carry flag is set */
626 {
627 /* B_(n-1) <- cf */
628 res |= 1 << (cnt-1);
629 }
630 /* set the new carry flag, based on the variable "cf" */
631 CONDITIONAL_SET_FLAG(cf, m, F_CF);
632 /* OVERFLOW is set *IFF* cnt==1, then it is the
633 xor of CF and the most significant bit. Blecck. */
634 /* parenthesized this expression since it appears to
635 be causing OF to be misset */
636 CONDITIONAL_SET_FLAG(cnt==1&&
637 xor_0x3_tab[cf+((res>>6)&0x2)],
638 m, F_OF);
639 }
640 return res & 0xff;
641 }
642
643 uint16 rcl_word(PC_ENV *m, uint16 d, uint16 s)
644 {
645 register uint32 res, cnt, mask,cf;
646 /* see analysis above. */
647 /* width here is 16 bits + carry bit */
648 res = d;
649 /* [JCE] Extra brackets to stop gcc -Wall moaning */
650 if ((cnt = s % 17)) /* not a typo, do nada if cnt==0 */
651 {
652 /* extract the new CARRY FLAG. */
653 /* CF <- b_(16-n) */
654 cf = (d >> (16-cnt)) & 0x1;
655 /* get the low stuff which rotated
656 into the range B_15 .. B_cnt */
657 /* B_(15) .. B_(n) <- b_(16-(n+1)) .. b_0 */
658 /* note that the right hand side done by the mask */
659 res = (d << cnt) & 0xffff;
660 /* now the high stuff which rotated around
661 into the positions B_cnt-2 .. B_0 */
662 /* B_(n-2) .. B_0 <- b_15 .. b_(16-(n-1)) */
663 /* shift it downward, 15-(n-2) = 17-n positions.
664 and mask off the result before or'ing in.
665 */
666 mask = (1<<(cnt-1)) - 1;
667 res |= (d >> (17-cnt)) & mask;
668 /* if the carry flag was set, or it in. */
669 if (ACCESS_FLAG(m, F_CF)) /* carry flag is set */
670 {
671 /* B_(n-1) <- cf */
672 res |= 1 << (cnt-1);
673 }
674 /* set the new carry flag, based on the variable "cf" */
675 CONDITIONAL_SET_FLAG(cf, m, F_CF);
676 /* OVERFLOW is set *IFF* cnt==1, then it is the
677 xor of CF and the most significant bit. Blecck.
678 Note that we're forming a 2 bit word here to index
679 into the table. The expression cf+(res>>14)&0x2
680 represents the two bit word b_15 CF.
681 */
682 /* parenthesized following expression... */
683 CONDITIONAL_SET_FLAG(cnt==1&&xor_0x3_tab[cf+((res>>14)&0x2)],
684 m, F_OF);
685 }
686 return res & 0xffff;
687 }
688
689 uint8 rcr_byte(PC_ENV *m, uint8 d, uint8 s)
690 {
691 uint8 res, cnt;
692 uint8 mask, cf, ocf = 0;
693 /* rotate right through carry */
694 /*
695 s is the rotate distance. It varies from 0 - 8.
696 d is the byte object rotated.
697 have
698 CF B_7 B_6 B_5 B_4 B_3 B_2 B_1 B_0
699 The new rotate is done mod 9, and given this,
700 for a rotation of n bits (mod 9) the new carry flag is
701 then located n bits from the LSB. The low part is
702 then shifted up cnt bits, and the high part is or'd
703 in. Using CAPS for new values, and lowercase for the
704 original values, this can be expressed as:
705 IF n > 0
706 1) CF <- b_(n-1)
707 2) B_(8-(n+1)) .. B_(0) <- b_(7) .. b_(n)
708 3) B_(8-n) <- cf
709 4) B_(7) .. B_(8-(n-1)) <- b_(n-2) .. b_(0)
710 I think this is correct.
711 */
712 res = d;
713 /* [JCE] Extra brackets to stop gcc -Wall moaning */
714 if ((cnt = s % 9)) /* not a typo, do nada if cnt==0 */
715 {
716 /* extract the new CARRY FLAG. */
717 /* CF <- b_(n-1) */
718 if (cnt == 1)
719 {
720 cf = d & 0x1;
721 /* note hackery here. Access_flag(..) evaluates to either
722 0 if flag not set
723 non-zero if flag is set.
724 doing access_flag(..) != 0 casts that into either
725 0..1 in any representation of the flags register
726 (i.e. packed bit array or unpacked.)
727 */
728 ocf = ACCESS_FLAG(m,F_CF) != 0;
729 }
730 else
731 cf = (d >> (cnt-1)) & 0x1;
732 /* B_(8-(n+1)) .. B_(0) <- b_(7) .. b_n */
733 /* note that the right hand side done by the mask
734 This is effectively done by shifting the
735 object to the right. The result must be masked,
736 in case the object came in and was treated
737 as a negative number. Needed???*/
738 mask = (1<<(8-cnt))-1;
739 res = (d >> cnt) & mask;
740 /* now the high stuff which rotated around
741 into the positions B_cnt-2 .. B_0 */
742 /* B_(7) .. B_(8-(n-1)) <- b_(n-2) .. b_(0) */
743 /* shift it downward, 7-(n-2) = 9-n positions.
744 and mask off the result before or'ing in.
745 */
746 res |= (d << (9-cnt));
747 /* if the carry flag was set, or it in. */
748 if (ACCESS_FLAG(m,F_CF)) /* carry flag is set */
749 {
750 /* B_(8-n) <- cf */
751 res |= 1 << (8 - cnt);
752 }
753 /* set the new carry flag, based on the variable "cf" */
754 CONDITIONAL_SET_FLAG(cf, m, F_CF);
755 /* OVERFLOW is set *IFF* cnt==1, then it is the
756 xor of CF and the most significant bit. Blecck. */
757 /* parenthesized... */
758 if (cnt == 1)
759 { /* [JCE] Explicit braces to stop gcc -Wall moaning */
760 CONDITIONAL_SET_FLAG(xor_0x3_tab[ocf+((d>>6)&0x2)],
761 m, F_OF);
762 }
763 }
764 return res;
765 }
766
767 uint16 rcr_word(PC_ENV *m, uint16 d, uint16 s)
768 {
769 uint16 res, cnt;
770 uint16 mask, cf, ocf = 0;
771 /* rotate right through carry */
772 /*
773 s is the rotate distance. It varies from 0 - 8.
774 d is the byte object rotated.
775 have
776 CF B_15 ... B_0
777 The new rotate is done mod 17, and given this,
778 for a rotation of n bits (mod 17) the new carry flag is
779 then located n bits from the LSB. The low part is
780 then shifted up cnt bits, and the high part is or'd
781 in. Using CAPS for new values, and lowercase for the
782 original values, this can be expressed as:
783 IF n > 0
784 1) CF <- b_(n-1)
785 2) B_(16-(n+1)) .. B_(0) <- b_(15) .. b_(n)
786 3) B_(16-n) <- cf
787 4) B_(15) .. B_(16-(n-1)) <- b_(n-2) .. b_(0)
788 I think this is correct.
789 */
790 res = d;
791 /* [JCE] Extra brackets to stop gcc -Wall moaning */
792 if ((cnt = s % 17)) /* not a typo, do nada if cnt==0 */
793 {
794 /* extract the new CARRY FLAG. */
795 /* CF <- b_(n-1) */
796 if (cnt==1)
797 {
798 cf = d & 0x1;
799 /* see note above on teh byte version */
800 ocf = ACCESS_FLAG(m,F_CF) != 0;
801 }
802 else
803 cf = (d >> (cnt-1)) & 0x1;
804 /* B_(16-(n+1)) .. B_(0) <- b_(15) .. b_n */
805 /* note that the right hand side done by the mask
806 This is effectively done by shifting the
807 object to the right. The result must be masked,
808 in case the object came in and was treated
809 as a negative number. Needed???*/
810 mask = (1<<(16-cnt))-1;
811 res = (d >> cnt) & mask;
812 /* now the high stuff which rotated around
813 into the positions B_cnt-2 .. B_0 */
814 /* B_(15) .. B_(16-(n-1)) <- b_(n-2) .. b_(0) */
815 /* shift it downward, 15-(n-2) = 17-n positions.
816 and mask off the result before or'ing in.
817 */
818 res |= (d << (17-cnt));
819 /* if the carry flag was set, or it in. */
820 if (ACCESS_FLAG(m,F_CF)) /* carry flag is set */
821 {
822 /* B_(16-n) <- cf */
823 res |= 1 << (16 - cnt);
824 }
825 /* set the new carry flag, based on the variable "cf" */
826 CONDITIONAL_SET_FLAG(cf, m, F_CF);
827 /* OVERFLOW is set *IFF* cnt==1, then it is the
828 xor of CF and the most significant bit. Blecck. */
829 if (cnt==1)
830 { /* [JCE] Explicit braces to stop gcc -Wall moaning */
831 CONDITIONAL_SET_FLAG(xor_0x3_tab[ocf+((d>>14)&0x2)],
832 m, F_OF);
833 }
834 }
835 return res;
836 }
837
838 uint8 rol_byte(PC_ENV *m, uint8 d, uint8 s)
839 {
840 register uint32 res, cnt, mask;
841 /* rotate left */
842 /*
843 s is the rotate distance. It varies from 0 - 8.
844 d is the byte object rotated.
845 have
846 CF B_7 ... B_0
847 The new rotate is done mod 8.
848 Much simpler than the "rcl" or "rcr" operations.
849 IF n > 0
850 1) B_(7) .. B_(n) <- b_(8-(n+1)) .. b_(0)
851 2) B_(n-1) .. B_(0) <- b_(7) .. b_(8-n)
852 I think this is correct.
853 */
854 res =d;
855 /* [JCE] Extra brackets to stop gcc -Wall moaning */
856 if ((cnt = s % 8)) /* not a typo, do nada if cnt==0 */
857 {
858 /* B_(7) .. B_(n) <- b_(8-(n+1)) .. b_(0) */
859 res = (d << cnt);
860 /* B_(n-1) .. B_(0) <- b_(7) .. b_(8-n) */
861 mask = (1 << cnt) - 1;
862 res |= (d >> (8-cnt)) & mask;
863 /* set the new carry flag, Note that it is the low order
864 bit of the result!!! */
865 CONDITIONAL_SET_FLAG(res&0x1, m, F_CF);
866 /* OVERFLOW is set *IFF* cnt==1, then it is the
867 xor of CF and the most significant bit. Blecck. */
868 CONDITIONAL_SET_FLAG(cnt==1 &&
869 xor_0x3_tab[(res&0x1)+((res>>6)&0x2)],
870 m, F_OF);
871 }
872 return res&0xff;
873 }
874
875 uint16 rol_word(PC_ENV *m, uint16 d, uint16 s)
876 {
877 register uint32 res, cnt, mask;
878 /* rotate left */
879 /*
880 s is the rotate distance. It varies from 0 - 8.
881 d is the byte object rotated.
882 have
883 CF B_15 ... B_0
884 The new rotate is done mod 8.
885 Much simpler than the "rcl" or "rcr" operations.
886 IF n > 0
887 1) B_(15) .. B_(n) <- b_(16-(n+1)) .. b_(0)
888 2) B_(n-1) .. B_(0) <- b_(16) .. b_(16-n)
889 I think this is correct.
890 */
891 res = d;
892 /* [JCE] Extra brackets to stop gcc -Wall moaning */
893 if ((cnt = s % 16)) /* not a typo, do nada if cnt==0 */
894 {
895 /* B_(16) .. B_(n) <- b_(16-(n+1)) .. b_(0) */
896 res = (d << cnt);
897 /* B_(n-1) .. B_(0) <- b_(15) .. b_(16-n) */
898 mask = (1 << cnt) - 1;
899 res |= (d >> (16-cnt)) & mask;
900 /* set the new carry flag, Note that it is the low order
901 bit of the result!!! */
902 CONDITIONAL_SET_FLAG(res&0x1, m, F_CF);
903 /* OVERFLOW is set *IFF* cnt==1, then it is the
904 xor of CF and the most significant bit. Blecck. */
905 CONDITIONAL_SET_FLAG(cnt==1 &&
906 xor_0x3_tab[(res&0x1)+((res>>14)&0x2)],
907 m, F_OF);
908 }
909 return res&0xffff;
910 }
911
912 uint8 ror_byte(PC_ENV *m, uint8 d, uint8 s)
913 {
914 register uint32 res, cnt, mask;
915 /* rotate right */
916 /*
917 s is the rotate distance. It varies from 0 - 8.
918 d is the byte object rotated.
919 have
920 B_7 ... B_0
921 The rotate is done mod 8.
922 IF n > 0
923 1) B_(8-(n+1)) .. B_(0) <- b_(7) .. b_(n)
924 2) B_(7) .. B_(8-n) <- b_(n-1) .. b_(0)
925 */
926 res = d;
927 /* [JCE] Extra brackets to stop gcc -Wall moaning */
928 if ((cnt = s % 8)) /* not a typo, do nada if cnt==0 */
929 {
930 /* B_(7) .. B_(8-n) <- b_(n-1) .. b_(0)*/
931 res = (d << (8-cnt));
932 /* B_(8-(n+1)) .. B_(0) <- b_(7) .. b_(n) */
933 mask = (1 << (8-cnt)) - 1;
934 res |= (d >> (cnt)) & mask;
935 /* set the new carry flag, Note that it is the low order
936 bit of the result!!! */
937 CONDITIONAL_SET_FLAG(res&0x80, m, F_CF);
938 /* OVERFLOW is set *IFF* cnt==1, then it is the
939 xor of the two most significant bits. Blecck. */
940 CONDITIONAL_SET_FLAG(cnt==1 &&
941 xor_0x3_tab[(res>>6)&0x3],
942 m, F_OF);
943 }
944 return res&0xff;
945 }
946
947 uint16 ror_word(PC_ENV *m, uint16 d, uint16 s)
948 {
949 register uint32 res, cnt, mask;
950 /* rotate right */
951 /*
952 s is the rotate distance. It varies from 0 - 8.
953 d is the byte object rotated.
954 have
955 B_15 ... B_0
956 The rotate is done mod 16.
957 IF n > 0
958 1) B_(16-(n+1)) .. B_(0) <- b_(15) .. b_(n)
959 2) B_(15) .. B_(16-n) <- b_(n-1) .. b_(0)
960 I think this is correct.
961 */
962 res =d ;
963 /* [JCE] Extra brackets to stop gcc -Wall moaning */
964 if ((cnt = s % 16)) /* not a typo, do nada if cnt==0 */
965 {
966 /* B_(15) .. B_(16-n) <- b_(n-1) .. b_(0)*/
967 res = (d << (16-cnt));
968 /* B_(16-(n+1)) .. B_(0) <- b_(15) .. b_(n) */
969 mask = (1 << (16-cnt)) - 1;
970 res |= (d >> (cnt)) & mask;
971 /* set the new carry flag, Note that it is the low order
972 bit of the result!!! */
973 CONDITIONAL_SET_FLAG(res&0x8000, m, F_CF);
974 /* OVERFLOW is set *IFF* cnt==1, then it is the
975 xor of CF and the most significant bit. Blecck. */
976 CONDITIONAL_SET_FLAG(cnt==1 &&
977 xor_0x3_tab[(res>>14)&0x3],
978 m, F_OF);
979 }
980 return res & 0xffff;
981 }
982
983 uint8 shl_byte(PC_ENV *m, uint8 d, uint8 s)
984 {
985 uint32 cnt,res,cf;
986 if (s < 8)
987 {
988 cnt = s % 8;
989 /* last bit shifted out goes into carry flag */
990 if (cnt>0)
991 {
992 res = d << cnt;
993 cf = d & (1<<(8-cnt));
994 CONDITIONAL_SET_FLAG(cf, m, F_CF);
995 CONDITIONAL_SET_FLAG((res&0xff)==0, m, F_ZF);
996 CONDITIONAL_SET_FLAG(res & 0x80, m, F_SF);
997 CONDITIONAL_SET_FLAG(parity_tab[res&0xff], m, F_PF);
998 }
999 else
1000 {
1001 res = (uint8)d;
1002 }
1003 if (cnt == 1)
1004 {
1005 /* Needs simplification. */
1006 CONDITIONAL_SET_FLAG(
1007 (((res&0x80)==0x80) ^
1008 (ACCESS_FLAG(m,F_CF) != 0)) ,
1009 /* was (m->R_FLG&F_CF)==F_CF)), */
1010 m, F_OF);
1011 }
1012 else
1013 {
1014 CLEAR_FLAG(m,F_OF);
1015 }
1016 }
1017 else
1018 {
1019 res = 0;
1020 CLEAR_FLAG(m,F_CF);
1021 CLEAR_FLAG(m,F_OF);
1022 CLEAR_FLAG(m,F_SF);
1023 CLEAR_FLAG(m,F_PF);
1024 SET_FLAG(m,F_ZF);
1025 }
1026 return res&0xff;
1027 }
1028
1029 uint16 shl_word(PC_ENV *m, uint16 d, uint16 s)
1030 {
1031 uint32 cnt,res,cf;
1032 if (s < 16)
1033 {
1034 cnt = s % 16;
1035 if (cnt > 0)
1036 {
1037 res = d << cnt;
1038 /* last bit shifted out goes into carry flag */
1039 cf = d & (1<<(16-cnt));
1040 CONDITIONAL_SET_FLAG(cf, m, F_CF);
1041 CONDITIONAL_SET_FLAG((res&0xffff)==0, m, F_ZF);
1042 CONDITIONAL_SET_FLAG(res & 0x8000, m, F_SF);
1043 CONDITIONAL_SET_FLAG(parity_tab[res&0xff], m, F_PF);
1044 }
1045 else
1046 {
1047 res = (uint16)d;
1048 }
1049 if (cnt == 1)
1050 {
1051 /* Needs simplification. */
1052 CONDITIONAL_SET_FLAG(
1053 (((res&0x8000)==0x8000) ^
1054 (ACCESS_FLAG(m,F_CF) != 0)),
1055 /*((m&F_CF)==F_CF)),*/
1056 m, F_OF);
1057 }
1058 else
1059 {
1060 CLEAR_FLAG(m,F_OF);
1061 }
1062 }
1063 else
1064 {
1065 res = 0;
1066 CLEAR_FLAG(m,F_CF);
1067 CLEAR_FLAG(m,F_OF);
1068 SET_FLAG(m,F_ZF);
1069 CLEAR_FLAG(m,F_SF);
1070 CLEAR_FLAG(m,F_PF);
1071 }
1072 return res&0xffff;
1073 }
1074
1075 uint8 shr_byte(PC_ENV *m, uint8 d, uint8 s)
1076 {
1077 uint32 cnt,res,cf,mask;
1078 if (s < 8)
1079 {
1080 cnt = s % 8;
1081 if (cnt > 0)
1082 {
1083 mask = (1<<(8-cnt))-1;
1084 cf = d & (1<<(cnt-1));
1085 res = (d >> cnt) & mask;
1086 CONDITIONAL_SET_FLAG(cf, m, F_CF);
1087 CONDITIONAL_SET_FLAG((res&0xff)==0, m, F_ZF);
1088 CONDITIONAL_SET_FLAG(res & 0x80, m, F_SF);
1089 CONDITIONAL_SET_FLAG(parity_tab[res&0xff], m, F_PF);
1090 }
1091 else
1092 {
1093 res = (uint8) d;
1094 }
1095 if (cnt == 1)
1096 {
1097 CONDITIONAL_SET_FLAG(
1098 xor_0x3_tab[(res>>6)&0x3], m, F_OF);
1099 }
1100 else
1101 {
1102 CLEAR_FLAG(m,F_OF);
1103 }
1104 }
1105 else
1106 {
1107 res = 0;
1108 CLEAR_FLAG(m,F_CF);
1109 CLEAR_FLAG(m,F_OF);
1110 SET_FLAG(m,F_ZF);
1111 CLEAR_FLAG(m,F_SF);
1112 CLEAR_FLAG(m,F_PF);
1113 }
1114 return res&0xff;
1115 }
1116
1117 uint16 shr_word(PC_ENV *m, uint16 d, uint16 s)
1118 {
1119 uint32 cnt,res,cf,mask;
1120 res = d;
1121 if (s < 16)
1122 {
1123 cnt = s % 16;
1124 if (cnt > 0)
1125 {
1126 mask = (1<<(16-cnt))-1;
1127 cf = d & (1<<(cnt-1));
1128 res = (d >> cnt) & mask;
1129 CONDITIONAL_SET_FLAG(cf, m, F_CF);
1130 CONDITIONAL_SET_FLAG((res&0xffff)==0, m, F_ZF);
1131 CONDITIONAL_SET_FLAG(res & 0x8000, m, F_SF);
1132 CONDITIONAL_SET_FLAG(parity_tab[res&0xff], m, F_PF);
1133 }
1134 else
1135 {
1136 res = d;
1137 }
1138 if (cnt == 1)
1139 {
1140 CONDITIONAL_SET_FLAG(
1141 xor_0x3_tab[(res>>14)&0x3], m, F_OF);
1142 }
1143 else
1144 {
1145 CLEAR_FLAG(m,F_OF);
1146 }
1147 }
1148 else
1149 {
1150 res = 0;
1151 CLEAR_FLAG(m,F_CF);
1152 CLEAR_FLAG(m,F_OF);
1153 SET_FLAG(m,F_ZF);
1154 CLEAR_FLAG(m,F_SF);
1155 CLEAR_FLAG(m,F_PF);
1156 }
1157 return res&0xffff;
1158 }
1159
1160 /* XXXX ??? flags may be wrong??? */
1161 uint8 sar_byte(PC_ENV *m, uint8 d, uint8 s)
1162 {
1163 uint32 cnt,res,cf,mask,sf;
1164 res = d;
1165 sf = d & 0x80;
1166 cnt = s % 8;
1167 if(cnt > 0 && cnt < 8)
1168 {
1169 mask = (1<<(8-cnt))-1;
1170 cf = d & (1<<(cnt-1));
1171 res = (d >> cnt) & mask;
1172 CONDITIONAL_SET_FLAG(cf, m, F_CF);
1173 if (sf)
1174 {
1175 res |= ~mask;
1176 }
1177 CONDITIONAL_SET_FLAG((res&0xff)==0, m, F_ZF);
1178 CONDITIONAL_SET_FLAG(parity_tab[res&0xff], m, F_PF);
1179 CONDITIONAL_SET_FLAG(res & 0x80, m, F_SF);
1180 }
1181 else if (cnt >= 8)
1182 {
1183 if (sf)
1184 {
1185 res = 0xff;
1186 SET_FLAG(m,F_CF);
1187 CLEAR_FLAG(m,F_ZF);
1188 SET_FLAG(m, F_SF);
1189 SET_FLAG(m, F_PF);
1190 }
1191 else
1192 {
1193 res = 0;
1194 CLEAR_FLAG(m,F_CF);
1195 SET_FLAG(m,F_ZF);
1196 CLEAR_FLAG(m, F_SF);
1197 CLEAR_FLAG(m, F_PF);
1198 }
1199 }
1200 return res&0xff;
1201 }
1202
1203 uint16 sar_word(PC_ENV *m, uint16 d, uint16 s)
1204 {
1205 uint32 cnt, res, cf, mask, sf;
1206 sf = d & 0x8000;
1207 cnt = s % 16;
1208 res = d;
1209 if (cnt > 0 && cnt < 16)
1210 {
1211 mask = (1<<(16-cnt))-1;
1212 cf = d & (1<<(cnt-1));
1213 res = (d >> cnt) & mask;
1214 CONDITIONAL_SET_FLAG(cf, m, F_CF);
1215 if (sf)
1216 {
1217 res |= ~mask;
1218 }
1219 CONDITIONAL_SET_FLAG((res&0xffff)==0, m, F_ZF);
1220 CONDITIONAL_SET_FLAG(res & 0x8000, m, F_SF);
1221 CONDITIONAL_SET_FLAG(parity_tab[res&0xff], m, F_PF);
1222 }
1223 else if (cnt >= 16)
1224 {
1225 if (sf)
1226 {
1227 res = 0xffff;
1228 SET_FLAG(m,F_CF);
1229 CLEAR_FLAG(m,F_ZF);
1230 SET_FLAG(m, F_SF);
1231 SET_FLAG(m, F_PF);
1232 }
1233 else
1234 {
1235 res = 0;
1236 CLEAR_FLAG(m,F_CF);
1237 SET_FLAG(m,F_ZF);
1238 CLEAR_FLAG(m, F_SF);
1239 CLEAR_FLAG(m, F_PF);
1240 }
1241 }
1242 return res&0xffff;
1243 }
1244
1245 uint8 sbb_byte(PC_ENV *m, uint8 d, uint8 s)
1246 {
1247 register uint32 res; /* all operands in native machine order */
1248 register uint32 bc;
1249 if (ACCESS_FLAG(m,F_CF) )
1250 res = d - s - 1;
1251 else
1252 res = d - s;
1253 CONDITIONAL_SET_FLAG(res&0x80, m, F_SF);
1254 CONDITIONAL_SET_FLAG((res&0xff)==0, m, F_ZF);
1255 CONDITIONAL_SET_FLAG(parity_tab[res&0xff], m, F_PF);
1256 /* calculate the borrow chain. See note at top */
1257 bc= (res&(~d|s))|(~d&s);
1258 CONDITIONAL_SET_FLAG(bc&0x80,m, F_CF);
1259 CONDITIONAL_SET_FLAG(xor_0x3_tab[(bc>>6)&0x3], m, F_OF);
1260 CONDITIONAL_SET_FLAG(bc&0x8, m, F_AF);
1261 return res & 0xff;
1262 }
1263
1264 uint16 sbb_word(PC_ENV *m, uint16 d, uint16 s)
1265 {
1266 register uint32 res; /* all operands in native machine order */
1267 register uint32 bc;
1268 if (ACCESS_FLAG(m,F_CF))
1269 res = d - s - 1;
1270 else
1271 res = d - s;
1272 CONDITIONAL_SET_FLAG(res&0x8000, m, F_SF);
1273 CONDITIONAL_SET_FLAG((res&0xffff)==0, m, F_ZF);
1274 CONDITIONAL_SET_FLAG(parity_tab[res&0xff], m, F_PF);
1275 /* calculate the borrow chain. See note at top */
1276 bc= (res&(~d|s))|(~d&s);
1277 CONDITIONAL_SET_FLAG(bc&0x8000,m, F_CF);
1278 CONDITIONAL_SET_FLAG(xor_0x3_tab[(bc>>14)&0x3], m, F_OF);
1279 CONDITIONAL_SET_FLAG(bc&0x8, m, F_AF);
1280 return res & 0xffff;
1281 }
1282
1283 uint8 sub_byte(PC_ENV *m, uint8 d, uint8 s)
1284 {
1285 register uint32 res; /* all operands in native machine order */
1286 register uint32 bc;
1287 res = d - s;
1288 CONDITIONAL_SET_FLAG(res&0x80, m, F_SF);
1289 CONDITIONAL_SET_FLAG((res&0xff)==0, m, F_ZF);
1290 CONDITIONAL_SET_FLAG(parity_tab[res&0xff], m, F_PF);
1291 /* calculate the borrow chain. See note at top */
1292 bc= (res&(~d|s))|(~d&s);
1293 CONDITIONAL_SET_FLAG(bc&0x80,m, F_CF);
1294 CONDITIONAL_SET_FLAG(xor_0x3_tab[(bc>>6)&0x3], m, F_OF);
1295 CONDITIONAL_SET_FLAG(bc&0x8, m, F_AF);
1296 return res & 0xff;
1297 }
1298
1299 uint16 sub_word(PC_ENV *m, uint16 d, uint16 s)
1300 {
1301 register uint32 res; /* all operands in native machine order */
1302 register uint32 bc;
1303 res = d - s;
1304 CONDITIONAL_SET_FLAG(res&0x8000, m, F_SF);
1305 CONDITIONAL_SET_FLAG((res&0xffff)==0, m, F_ZF);
1306 CONDITIONAL_SET_FLAG(parity_tab[res&0xff], m, F_PF);
1307 /* calculate the borrow chain. See note at top */
1308 bc= (res&(~d|s))|(~d&s);
1309 CONDITIONAL_SET_FLAG(bc&0x8000,m, F_CF);
1310 CONDITIONAL_SET_FLAG(xor_0x3_tab[(bc>>14)&0x3], m, F_OF);
1311 CONDITIONAL_SET_FLAG(bc&0x8, m, F_AF);
1312 return res & 0xffff;
1313 }
1314
1315 void test_byte(PC_ENV *m, uint8 d, uint8 s)
1316 {
1317 register uint32 res; /* all operands in native machine order */
1318 res = d & s;
1319 CLEAR_FLAG(m, F_OF);
1320 CONDITIONAL_SET_FLAG(res&0x80, m, F_SF);
1321 CONDITIONAL_SET_FLAG(res==0, m, F_ZF);
1322 CONDITIONAL_SET_FLAG(parity_tab[res&0xff], m, F_PF);
1323 /* AF == dont care*/
1324 CLEAR_FLAG(m, F_CF);
1325 }
1326
1327 void test_word(PC_ENV *m, uint16 d, uint16 s)
1328 {
1329 register uint32 res; /* all operands in native machine order */
1330 res = d & s;
1331 CLEAR_FLAG(m, F_OF);
1332 CONDITIONAL_SET_FLAG(res&0x8000, m, F_SF);
1333 CONDITIONAL_SET_FLAG(res==0, m, F_ZF);
1334 CONDITIONAL_SET_FLAG(parity_tab[res&0xff], m, F_PF);
1335 /* AF == dont care*/
1336 CLEAR_FLAG(m, F_CF);
1337 }
1338
1339 uint8 xor_byte(PC_ENV *m, uint8 d, uint8 s)
1340 {
1341 register uint8 res; /* all operands in native machine order */
1342 res = d ^ s;
1343 CLEAR_FLAG(m, F_OF);
1344 CONDITIONAL_SET_FLAG(res&0x80, m, F_SF);
1345 CONDITIONAL_SET_FLAG(res==0, m, F_ZF);
1346 CONDITIONAL_SET_FLAG(parity_tab[res], m, F_PF);
1347 CLEAR_FLAG(m, F_CF);
1348 return res;
1349 }
1350
1351 uint16 xor_word(PC_ENV *m, uint16 d, uint16 s)
1352 {
1353 register uint16 res; /* all operands in native machine order */
1354 res = d ^ s;
1355 /* set the carry flag to be bit 8 */
1356 CLEAR_FLAG(m, F_OF);
1357 CONDITIONAL_SET_FLAG(res&0x8000, m, F_SF);
1358 CONDITIONAL_SET_FLAG(res==0, m, F_ZF);
1359 CONDITIONAL_SET_FLAG(parity_tab[res&0xff], m, F_PF);
1360 CLEAR_FLAG(m, F_CF);
1361 return res;
1362 }
1363
1364 void imul_byte(PC_ENV *m, uint8 s)
1365 {
1366 int16 res = (int8)m->R_AL * (int8)s;
1367 m->R_AX = res;
1368 /* Undef --- Can't hurt */
1369 CONDITIONAL_SET_FLAG(res&0x8000,m,F_SF);
1370 CONDITIONAL_SET_FLAG(res==0,m,F_ZF);
1371 if (m->R_AH == 0 || m->R_AH == 0xff)
1372 {
1373 CLEAR_FLAG(m, F_CF);
1374 CLEAR_FLAG(m, F_OF);
1375 }
1376 else
1377 {
1378 SET_FLAG(m, F_CF);
1379 SET_FLAG(m, F_OF);
1380 }
1381 }
1382
1383 void imul_word(PC_ENV *m, uint16 s)
1384 {
1385 int32 res = (int16)m->R_AX * (int16)s;
1386 m->R_AX = res & 0xffff;
1387 m->R_DX = (res >> 16) & 0xffff;
1388 /* Undef --- Can't hurt */
1389 CONDITIONAL_SET_FLAG(res&0x80000000,m,F_SF);
1390 CONDITIONAL_SET_FLAG(res==0,m,F_ZF);
1391 if (m->R_DX == 0 || m->R_DX == 0xffff)
1392 {
1393 CLEAR_FLAG(m, F_CF);
1394 CLEAR_FLAG(m, F_OF);
1395 }
1396 else
1397 {
1398 SET_FLAG(m, F_CF);
1399 SET_FLAG(m, F_OF);
1400 }
1401 }
1402
1403 void mul_byte(PC_ENV *m, uint8 s)
1404 {
1405 uint16 res = m->R_AL * s;
1406 m->R_AX = res;
1407 /* Undef --- Can't hurt */
1408 CLEAR_FLAG(m,F_SF);
1409 CONDITIONAL_SET_FLAG(res==0,m,F_ZF);
1410 if (m->R_AH == 0)
1411 {
1412 CLEAR_FLAG(m, F_CF);
1413 CLEAR_FLAG(m, F_OF);
1414 }
1415 else
1416 {
1417 SET_FLAG(m, F_CF);
1418 SET_FLAG(m, F_OF);
1419 }
1420 }
1421
1422 void mul_word(PC_ENV *m, uint16 s)
1423 {
1424 uint32 res = m->R_AX * s;
1425 /* Undef --- Can't hurt */
1426 CLEAR_FLAG(m,F_SF);
1427 CONDITIONAL_SET_FLAG(res==0,m,F_ZF);
1428 m->R_AX = res & 0xffff;
1429 m->R_DX = (res >> 16) & 0xffff;
1430 if (m->R_DX == 0)
1431 {
1432 CLEAR_FLAG(m, F_CF);
1433 CLEAR_FLAG(m, F_OF);
1434 }
1435 else
1436 {
1437 SET_FLAG(m, F_CF);
1438 SET_FLAG(m, F_OF);
1439 }
1440 }
1441
1442 void idiv_byte(PC_ENV *m, uint8 s)
1443 {
1444 int32 dvd,div,mod;
1445 dvd = (int16)m->R_AX;
1446 if (s == 0)
1447 {
1448 i86_intr_raise(m,0);
1449 return;
1450 }
1451 div = dvd / (int8)s;
1452 mod = dvd % (int8)s;
1453 if (abs(div) > 0x7f)
1454 {
1455 i86_intr_raise(m,0);
1456 return;
1457 }
1458 /* Undef --- Can't hurt */
1459 CONDITIONAL_SET_FLAG(div&0x80,m,F_SF);
1460 CONDITIONAL_SET_FLAG(div==0,m,F_ZF);
1461 m->R_AL = (int8)div;
1462 m->R_AH = (int8)mod;
1463 }
1464
1465 void idiv_word(PC_ENV *m, uint16 s)
1466 {
1467 int32 dvd,dvs,div,mod;
1468 dvd = m->R_DX;
1469 dvd = (dvd << 16) | m->R_AX;
1470 if (s == 0)
1471 {
1472 i86_intr_raise(m,0);
1473 return;
1474 }
1475 dvs = (int16)s;
1476 div = dvd / dvs;
1477 mod = dvd % dvs;
1478 if (abs(div) > 0x7fff)
1479 {
1480 i86_intr_raise(m,0);
1481 return;
1482 }
1483 /* Undef --- Can't hurt */
1484 CONDITIONAL_SET_FLAG(div&0x8000,m,F_SF);
1485 CONDITIONAL_SET_FLAG(div==0,m,F_ZF);
1486 /* debug_printf(m, "\n%d/%d=%d,%d\n",dvd,dvs,div,mod); */
1487 m->R_AX = div;
1488 m->R_DX = mod;
1489 }
1490
1491 void div_byte(PC_ENV *m, uint8 s)
1492 {
1493 uint32 dvd,dvs,div,mod;
1494 dvs = s;
1495 dvd = m->R_AX;
1496 if (s == 0)
1497 {
1498 i86_intr_raise(m,0);
1499 return;
1500 }
1501 div = dvd / dvs;
1502 mod = dvd % dvs;
1503 if (abs(div) > 0xff)
1504 {
1505 i86_intr_raise(m,0);
1506 return;
1507 }
1508 /* Undef --- Can't hurt */
1509 CLEAR_FLAG(m,F_SF);
1510 CONDITIONAL_SET_FLAG(div==0,m,F_ZF);
1511 m->R_AL = (uint8)div;
1512 m->R_AH = (uint8)mod;
1513 }
1514
1515 void div_word(PC_ENV *m, uint16 s)
1516 {
1517 uint32 dvd,dvs,div,mod;
1518 dvd = m->R_DX;
1519 dvd = (dvd << 16) | m->R_AX;
1520 dvs = s;
1521 if (dvs == 0)
1522 {
1523 i86_intr_raise(m,0);
1524 return;
1525 }
1526 div = dvd / dvs;
1527 mod = dvd % dvs;
1528 /* printf("dvd=%x dvs=%x -> div=%x mod=%x\n",dvd, dvs,div, mod);*/
1529 if (abs(div) > 0xffff)
1530 {
1531 i86_intr_raise(m,0);
1532 return;
1533 }
1534 /* Undef --- Can't hurt */
1535 CLEAR_FLAG(m,F_SF);
1536 CONDITIONAL_SET_FLAG(div==0,m,F_ZF);
1537 m->R_AX = div;
1538 m->R_DX = mod;
1539 }