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 extern int32 AX_S; /* AX register (8086) */
30 extern int32 BX_S; /* BX register (8086) */
31 extern int32 CX_S; /* CX register (8086) */
32 extern int32 DX_S; /* DX register (8086) */
33 extern int32 CS_S; /* CS register (8086) */
34 extern int32 DS_S; /* DS register (8086) */
35 extern int32 ES_S; /* ES register (8086) */
36 extern int32 SS_S; /* SS register (8086) */
37 extern int32 DI_S; /* DI register (8086) */
38 extern int32 SI_S; /* SI register (8086) */
39 extern int32 BP_S; /* BP register (8086) */
40 extern int32 SPX_S; /* SP register (8086) */
41 extern int32 IP_S; /* IP register (8086) */
42 extern int32 FLAGS_S; /* flags register (8086) */
43 extern int32 PCX_S; /* PC register (8086), 20 bit */
44 extern int32 sim_interval;
45 extern uint32 PCX; /* external view of PC */
46 extern uint32 sim_brk_summ;
47 extern UNIT cpu_unit;
48
49 volatile int intr;
50 void i86_intr_raise(PC_ENV *m,uint8 intrnum);
51 void cpu8086reset(void);
52 t_stat sim_instr_8086(void);
53 void cpu8086_intr(uint8 intrnum);
54
55 /* $Log: $
56 * Revision 0.05 1992/04/12 23:16:42 hudgens
57 * Many changes. Added support for the QUICK_FETCH option,
58 * so that memory accesses are faster. Now compiles with gcc -Wall
59 * and gcc -traditional and Sun cc.
60 *
61 * Revision 0.04 1991/07/30 01:59:56 hudgens
62 * added copyright.
63 *
64 * Revision 0.03 1991/06/03 01:02:09 hudgens
65 * fixed minor problems due to unsigned to signed short integer
66 * promotions.
67 *
68 * Revision 0.02 1991/03/31 01:29:39 hudgens
69 * Fixed segment handling (overrides, default segment accessed) in
70 * routines decode_rmXX_address and the {fetch,store}_data_{byte,word}.
71 *
72 * Revision 0.01 1991/03/30 21:59:49 hudgens
73 * Initial checkin.
74 *
75 *
76 */
77
78 /* this file includes subroutines which do:
79 stuff involving decoding instruction formats.
80 stuff involving accessess of immediate data via IP.
81 etc.
82 */
83
i86_intr_handle(PC_ENV * m)84 static void i86_intr_handle(PC_ENV *m)
85 { uint16 tmp;
86 uint8 intno;
87 if (intr & INTR_SYNCH) /* raised by something */
88 {
89 intno = m->intno;
90 {
91 tmp = m->R_FLG;
92 push_word(m, tmp);
93 CLEAR_FLAG(m, F_IF);
94 CLEAR_FLAG(m, F_TF);
95 /* [JCE] If we're interrupting between a segment override (or REP override)
96 * and the following instruction, decrease IP to get back to the prefix */
97 if (m->sysmode & (SYSMODE_SEGMASK | SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE))
98 {
99 --m->R_IP;
100 }
101 /* [JCE] CS and IP were the wrong way round... */
102 push_word(m, m->R_CS);
103 push_word(m, m->R_IP);
104 tmp = mem_access_word(m, intno * 4);
105 m->R_IP = tmp;
106 tmp = mem_access_word(m, intno * 4 + 2);
107 m->R_CS = tmp;
108 }
109 intr &= ~INTR_SYNCH; /* [JCE] Dealt with, reset flag */
110 }
111 /* The interrupt code can't pick up the segment override status. */
112 DECODE_CLEAR_SEGOVR(m);
113 }
114
i86_intr_raise(PC_ENV * m,uint8 intrnum)115 void i86_intr_raise(PC_ENV *m,uint8 intrnum)
116 {
117 m->intno = intrnum;
118 intr |= INTR_SYNCH;
119 }
120
121 static PC_ENV cpu8086;
122
cpu8086_intr(uint8 intrnum)123 void cpu8086_intr(uint8 intrnum)
124 {
125 i86_intr_raise(&cpu8086, intrnum);
126 }
127
setViewRegisters(void)128 static void setViewRegisters(void) {
129 FLAGS_S = cpu8086.R_FLG;
130 AX_S = cpu8086.R_AX;
131 BX_S = cpu8086.R_BX;
132 CX_S = cpu8086.R_CX;
133 DX_S = cpu8086.R_DX;
134 SPX_S = cpu8086.R_SP;
135 BP_S = cpu8086.R_BP;
136 SI_S = cpu8086.R_SI;
137 DI_S = cpu8086.R_DI;
138 ES_S = cpu8086.R_ES;
139 CS_S = cpu8086.R_CS;
140 SS_S = cpu8086.R_SS;
141 DS_S = cpu8086.R_DS;
142 IP_S = cpu8086.R_IP;
143 }
144
setCPURegisters(void)145 static void setCPURegisters(void) {
146 cpu8086.R_FLG = FLAGS_S;
147 cpu8086.R_AX = AX_S;
148 cpu8086.R_BX = BX_S;
149 cpu8086.R_CX = CX_S;
150 cpu8086.R_DX = DX_S;
151 cpu8086.R_SP = SPX_S;
152 cpu8086.R_BP = BP_S;
153 cpu8086.R_SI = SI_S;
154 cpu8086.R_DI = DI_S;
155 cpu8086.R_ES = ES_S;
156 cpu8086.R_CS = CS_S;
157 cpu8086.R_SS = SS_S;
158 cpu8086.R_DS = DS_S;
159 cpu8086.R_IP = IP_S;
160 }
161
cpu8086reset(void)162 void cpu8086reset(void) {
163 cpu8086.R_AX = 0x1961;
164 if ((cpu8086.R_AH != 0x19) || (cpu8086.R_AL != 0x61)) {
165 printf("Fatal endian error - make sure to compile with '#define LOWFIRST %i'\n", 1 - LOWFIRST);
166 exit(1);
167 }
168 /* 16 bit registers */
169 cpu8086.R_AX = 0;
170 cpu8086.R_BX = 0;
171 cpu8086.R_CX = 0;
172 cpu8086.R_DX = 0;
173 /* special registers */
174 cpu8086.R_SP = 0;
175 cpu8086.R_BP = 0;
176 cpu8086.R_SI = 0;
177 cpu8086.R_DI = 0;
178 cpu8086.R_IP = 0;
179 cpu8086.R_FLG = F_ALWAYS_ON;
180 /* segment registers */
181 cpu8086.R_CS = 0;
182 cpu8086.R_DS = 0;
183 cpu8086.R_SS = 0;
184 cpu8086.R_ES = 0;
185 setViewRegisters();
186 }
187
getFullPC(void)188 static uint32 getFullPC(void) {
189 return cpu8086.R_IP + (cpu8086.R_CS << 4);
190 }
191
192 extern int32 switch_cpu_now; /* hharte */
193
sim_instr_8086(void)194 t_stat sim_instr_8086(void) {
195 t_stat reason = SCPE_OK;
196 uint8 op1;
197 int32 newIP;
198 setCPURegisters();
199 intr = 0;
200 newIP = PCX_S - 16 * CS_S;
201 switch_cpu_now = TRUE; /* hharte */
202 if ((0 <= newIP) && (newIP <= 0xffff))
203 cpu8086.R_IP = newIP;
204 else {
205 if (CS_S != ((PCX_S & 0xf0000) >> 4)) {
206 cpu8086.R_CS = (PCX_S & 0xf0000) >> 4;
207 if (cpu_unit.flags & UNIT_CPU_VERBOSE)
208 printf("CPU: " ADDRESS_FORMAT " Segment register CS set to %04x" NLP, PCX, cpu8086.R_CS);
209 }
210 cpu8086.R_IP = PCX_S & 0xffff;
211 }
212 while (switch_cpu_now == TRUE) { /* loop until halted */
213 if (sim_interval <= 0) { /* check clock queue */
214 #if !UNIX_PLATFORM
215 if ((reason = sim_os_poll_kbd()) == SCPE_STOP) /* poll on platforms without reliable signalling */
216 break;
217 #endif
218 if ( (reason = sim_process_event()) )
219 break;
220 }
221 if (sim_brk_summ && sim_brk_test(getFullPC(), SWMASK('E'))) { /* breakpoint? */
222 reason = STOP_IBKPT; /* stop simulation */
223 break;
224 }
225 PCX = getFullPC();
226 op1 = GetBYTEExtended((((uint32)cpu8086.R_CS<<4) + cpu8086.R_IP) & 0xFFFFF);
227 if (sim_brk_summ && sim_brk_test(op1, (1u << SIM_BKPT_V_SPC) | SWMASK('I'))) { /* instruction breakpoint? */
228 reason = STOP_IBKPT; /* stop simulation */
229 break;
230 }
231 sim_interval--;
232 cpu8086.R_IP++;
233 (*(i86_optab[op1]))(&cpu8086);
234 if (intr & INTR_HALTED) {
235 reason = STOP_HALT;
236 intr &= ~INTR_HALTED;
237 break;
238 }
239 if (intr & INTR_ILLEGAL_OPCODE) {
240 intr &= ~INTR_ILLEGAL_OPCODE;
241 if (cpu_unit.flags & UNIT_CPU_OPSTOP) {
242 reason = STOP_OPCODE;
243 break;
244 }
245 }
246 if (((intr & INTR_SYNCH) && (cpu8086.intno == 0 || cpu8086.intno == 2)) ||
247 (ACCESS_FLAG(&cpu8086, F_IF))) {
248 /* [JCE] Reversed the sense of this ACCESS_FLAG; it's set for interrupts
249 enabled, not interrupts blocked i.e. either not blockable (intr 0 or 2)
250 or the IF flag not set so interrupts not blocked */
251 /* hharte: if a segment override exists, then treat that as "atomic" and do not handle
252 * an interrupt until the override is cleared.
253 * Not sure if this is the way an 8086 really works, need to find out for sure.
254 * Also, what about the REPE prefix?
255 */
256 if ((cpu8086.sysmode & SYSMODE_SEGMASK) == 0) {
257 i86_intr_handle(&cpu8086);
258 }
259 }
260 }
261 /* It we stopped processing instructions because of a switch to the other
262 * CPU, then fixup the reason code.
263 */
264 if (switch_cpu_now == FALSE) {
265 reason = SCPE_OK;
266 PCX += 2;
267 PCX_S = PCX;
268 } else {
269 PCX_S = (reason == STOP_HALT) | (reason == STOP_OPCODE) ? PCX : getFullPC();
270 }
271
272 setViewRegisters();
273 return reason;
274 }
275
halt_sys(PC_ENV * m)276 void halt_sys(PC_ENV *m)
277 {
278 intr |= INTR_HALTED;
279 }
280
281 /* once the instruction is fetched, an optional byte follows which
282 has 3 fields encoded in it. This routine fetches the byte
283 and breaks into the three fields.
284 This has been changed, in an attempt to reduce the amount of
285 executed code for this frequently executed subroutine. If this
286 works, then it may pay to somehow inline it.
287 */
288
289 #ifdef NOTDEF
290 /* this code generated the following table */
main()291 main()
292 { int i;
293 printf("\n\nstruct modrm{ uint8 mod,rh,rl;} modrmtab[] = {\n");
294 for (i=0; i<256; i++)
295 {
296 printf("{%d,%d,%d}, ",((i&0xc0)>>6),((i&0x38)>>3),(i&0x07));
297 if (i%4==3)
298 printf("/* %d to %d */\n",i&0xfc,i);
299 }
300 printf("};\n\n");
301 }
302 #endif
303
304 struct modrm { uint16 mod, rh, rl; };
305 static struct modrm modrmtab[] = {
306 {0,0,0}, {0,0,1}, {0,0,2}, {0,0,3}, /* 0 to 3 */
307 {0,0,4}, {0,0,5}, {0,0,6}, {0,0,7}, /* 4 to 7 */
308 {0,1,0}, {0,1,1}, {0,1,2}, {0,1,3}, /* 8 to 11 */
309 {0,1,4}, {0,1,5}, {0,1,6}, {0,1,7}, /* 12 to 15 */
310 {0,2,0}, {0,2,1}, {0,2,2}, {0,2,3}, /* 16 to 19 */
311 {0,2,4}, {0,2,5}, {0,2,6}, {0,2,7}, /* 20 to 23 */
312 {0,3,0}, {0,3,1}, {0,3,2}, {0,3,3}, /* 24 to 27 */
313 {0,3,4}, {0,3,5}, {0,3,6}, {0,3,7}, /* 28 to 31 */
314 {0,4,0}, {0,4,1}, {0,4,2}, {0,4,3}, /* 32 to 35 */
315 {0,4,4}, {0,4,5}, {0,4,6}, {0,4,7}, /* 36 to 39 */
316 {0,5,0}, {0,5,1}, {0,5,2}, {0,5,3}, /* 40 to 43 */
317 {0,5,4}, {0,5,5}, {0,5,6}, {0,5,7}, /* 44 to 47 */
318 {0,6,0}, {0,6,1}, {0,6,2}, {0,6,3}, /* 48 to 51 */
319 {0,6,4}, {0,6,5}, {0,6,6}, {0,6,7}, /* 52 to 55 */
320 {0,7,0}, {0,7,1}, {0,7,2}, {0,7,3}, /* 56 to 59 */
321 {0,7,4}, {0,7,5}, {0,7,6}, {0,7,7}, /* 60 to 63 */
322 {1,0,0}, {1,0,1}, {1,0,2}, {1,0,3}, /* 64 to 67 */
323 {1,0,4}, {1,0,5}, {1,0,6}, {1,0,7}, /* 68 to 71 */
324 {1,1,0}, {1,1,1}, {1,1,2}, {1,1,3}, /* 72 to 75 */
325 {1,1,4}, {1,1,5}, {1,1,6}, {1,1,7}, /* 76 to 79 */
326 {1,2,0}, {1,2,1}, {1,2,2}, {1,2,3}, /* 80 to 83 */
327 {1,2,4}, {1,2,5}, {1,2,6}, {1,2,7}, /* 84 to 87 */
328 {1,3,0}, {1,3,1}, {1,3,2}, {1,3,3}, /* 88 to 91 */
329 {1,3,4}, {1,3,5}, {1,3,6}, {1,3,7}, /* 92 to 95 */
330 {1,4,0}, {1,4,1}, {1,4,2}, {1,4,3}, /* 96 to 99 */
331 {1,4,4}, {1,4,5}, {1,4,6}, {1,4,7}, /* 100 to 103 */
332 {1,5,0}, {1,5,1}, {1,5,2}, {1,5,3}, /* 104 to 107 */
333 {1,5,4}, {1,5,5}, {1,5,6}, {1,5,7}, /* 108 to 111 */
334 {1,6,0}, {1,6,1}, {1,6,2}, {1,6,3}, /* 112 to 115 */
335 {1,6,4}, {1,6,5}, {1,6,6}, {1,6,7}, /* 116 to 119 */
336 {1,7,0}, {1,7,1}, {1,7,2}, {1,7,3}, /* 120 to 123 */
337 {1,7,4}, {1,7,5}, {1,7,6}, {1,7,7}, /* 124 to 127 */
338 {2,0,0}, {2,0,1}, {2,0,2}, {2,0,3}, /* 128 to 131 */
339 {2,0,4}, {2,0,5}, {2,0,6}, {2,0,7}, /* 132 to 135 */
340 {2,1,0}, {2,1,1}, {2,1,2}, {2,1,3}, /* 136 to 139 */
341 {2,1,4}, {2,1,5}, {2,1,6}, {2,1,7}, /* 140 to 143 */
342 {2,2,0}, {2,2,1}, {2,2,2}, {2,2,3}, /* 144 to 147 */
343 {2,2,4}, {2,2,5}, {2,2,6}, {2,2,7}, /* 148 to 151 */
344 {2,3,0}, {2,3,1}, {2,3,2}, {2,3,3}, /* 152 to 155 */
345 {2,3,4}, {2,3,5}, {2,3,6}, {2,3,7}, /* 156 to 159 */
346 {2,4,0}, {2,4,1}, {2,4,2}, {2,4,3}, /* 160 to 163 */
347 {2,4,4}, {2,4,5}, {2,4,6}, {2,4,7}, /* 164 to 167 */
348 {2,5,0}, {2,5,1}, {2,5,2}, {2,5,3}, /* 168 to 171 */
349 {2,5,4}, {2,5,5}, {2,5,6}, {2,5,7}, /* 172 to 175 */
350 {2,6,0}, {2,6,1}, {2,6,2}, {2,6,3}, /* 176 to 179 */
351 {2,6,4}, {2,6,5}, {2,6,6}, {2,6,7}, /* 180 to 183 */
352 {2,7,0}, {2,7,1}, {2,7,2}, {2,7,3}, /* 184 to 187 */
353 {2,7,4}, {2,7,5}, {2,7,6}, {2,7,7}, /* 188 to 191 */
354 {3,0,0}, {3,0,1}, {3,0,2}, {3,0,3}, /* 192 to 195 */
355 {3,0,4}, {3,0,5}, {3,0,6}, {3,0,7}, /* 196 to 199 */
356 {3,1,0}, {3,1,1}, {3,1,2}, {3,1,3}, /* 200 to 203 */
357 {3,1,4}, {3,1,5}, {3,1,6}, {3,1,7}, /* 204 to 207 */
358 {3,2,0}, {3,2,1}, {3,2,2}, {3,2,3}, /* 208 to 211 */
359 {3,2,4}, {3,2,5}, {3,2,6}, {3,2,7}, /* 212 to 215 */
360 {3,3,0}, {3,3,1}, {3,3,2}, {3,3,3}, /* 216 to 219 */
361 {3,3,4}, {3,3,5}, {3,3,6}, {3,3,7}, /* 220 to 223 */
362 {3,4,0}, {3,4,1}, {3,4,2}, {3,4,3}, /* 224 to 227 */
363 {3,4,4}, {3,4,5}, {3,4,6}, {3,4,7}, /* 228 to 231 */
364 {3,5,0}, {3,5,1}, {3,5,2}, {3,5,3}, /* 232 to 235 */
365 {3,5,4}, {3,5,5}, {3,5,6}, {3,5,7}, /* 236 to 239 */
366 {3,6,0}, {3,6,1}, {3,6,2}, {3,6,3}, /* 240 to 243 */
367 {3,6,4}, {3,6,5}, {3,6,6}, {3,6,7}, /* 244 to 247 */
368 {3,7,0}, {3,7,1}, {3,7,2}, {3,7,3}, /* 248 to 251 */
369 {3,7,4}, {3,7,5}, {3,7,6}, {3,7,7}, /* 252 to 255 */
370 };
371
fetch_decode_modrm(PC_ENV * m,uint16 * mod,uint16 * regh,uint16 * regl)372 void fetch_decode_modrm(PC_ENV *m, uint16 *mod, uint16 *regh, uint16 *regl)
373 { uint8 fetched;
374 register struct modrm *p;
375 /* do the fetch in real mode. Shift the CS segment register
376 over by 4 bits, and add in the IP register. Index into
377 the system memory.
378 */
379 /* [JCE] Wrap at 1Mb (the A20 gate) */
380 fetched = GetBYTEExtended(((m->R_CS << 4) + (m->R_IP++)) & 0xFFFFF);
381
382 #ifdef NOTDEF
383 *mod = ((fetched&0xc0)>>6);
384 *regh= ((fetched&0x38)>>3);
385 *regl= (fetched&0x7);
386 #else
387 p = modrmtab + fetched;
388 *mod = p->mod;
389 *regh= p->rh;
390 *regl= p->rl;
391 #endif
392
393 }
394
395 /*
396 return a pointer to the register given by the R/RM field of
397 the modrm byte, for byte operands.
398 Also enables the decoding of instructions.
399 */
decode_rm_byte_register(PC_ENV * m,int reg)400 uint8 *decode_rm_byte_register(PC_ENV *m, int reg)
401 {
402 switch(reg)
403 {
404 case 0:
405 return &m->R_AL;
406 break;
407 case 1:
408 return &m->R_CL;
409 break;
410 case 2:
411 return &m->R_DL;
412 break;
413 case 3:
414 return &m->R_BL;
415 break;
416 case 4:
417 return &m->R_AH;
418 break;
419 case 5:
420 return &m->R_CH;
421 break;
422 case 6:
423 return &m->R_DH;
424 break;
425 case 7:
426 return &m->R_BH;
427 break;
428 }
429 halt_sys(m);
430 return NULL; /* NOT REACHED OR REACHED ON ERROR */
431 }
432
433 /*
434 return a pointer to the register given by the R/RM field of
435 the modrm byte, for word operands.
436 Also enables the decoding of instructions.
437 */
decode_rm_word_register(PC_ENV * m,int reg)438 uint16 *decode_rm_word_register(PC_ENV *m, int reg)
439 {
440 switch(reg)
441 {
442 case 0:
443 return &m->R_AX;
444 break;
445 case 1:
446 return &m->R_CX;
447 break;
448 case 2:
449 return &m->R_DX;
450 break;
451 case 3:
452 return &m->R_BX;
453 break;
454 case 4:
455 return &m->R_SP;
456 break;
457 case 5:
458 return &m->R_BP;
459 break;
460 case 6:
461 return &m->R_SI;
462 break;
463 case 7:
464 return &m->R_DI;
465 break;
466 }
467 halt_sys(m);
468 return NULL; /* NOTREACHED OR REACHED ON ERROR*/
469 }
470
471 /*
472 return a pointer to the register given by the R/RM field of
473 the modrm byte, for word operands, modified from above
474 for the weirdo special case of segreg operands.
475 Also enables the decoding of instructions.
476 */
decode_rm_seg_register(PC_ENV * m,int reg)477 uint16 *decode_rm_seg_register(PC_ENV *m, int reg)
478 {
479 switch(reg)
480 {
481 case 0:
482 return &m->R_ES;
483 break;
484 case 1:
485 return &m->R_CS;
486 break;
487 case 2:
488 return &m->R_SS;
489 break;
490 case 3:
491 return &m->R_DS;
492 break;
493 case 4:
494 case 5:
495 case 6:
496 case 7:
497 break;
498 }
499 halt_sys(m);
500 return NULL; /* NOT REACHED OR REACHED ON ERROR */
501 }
502
503 /* once the instruction is fetched, an optional byte follows which
504 has 3 fields encoded in it. This routine fetches the byte
505 and breaks into the three fields.
506 */
fetch_byte_imm(PC_ENV * m)507 uint8 fetch_byte_imm(PC_ENV *m)
508 {
509 uint8 fetched;
510 /* do the fetch in real mode. Shift the CS segment register
511 over by 4 bits, and add in the IP register. Index into
512 the system memory.
513 */
514 /* [JCE] Wrap at 1Mb (the A20 gate) */
515 fetched = GetBYTEExtended((((uint32)m->R_CS << 4) + (m->R_IP++)) & 0xFFFFF);
516 return fetched;
517 }
518
fetch_word_imm(PC_ENV * m)519 uint16 fetch_word_imm(PC_ENV *m)
520 {
521 uint16 fetched;
522 /* do the fetch in real mode. Shift the CS segment register
523 over by 4 bits, and add in the IP register. Index into
524 the system PC_ENVory.
525 */
526 /* [JCE] Wrap at 1Mb (the A20 gate) */
527 fetched = GetBYTEExtended((((uint32)m->R_CS << 4) + (m->R_IP++)) & 0xFFFFF);
528 fetched |= (GetBYTEExtended((((uint32)m->R_CS << 4) + (m->R_IP++)) & 0xFFFFF) << 8);
529 return fetched;
530 }
531
532 /*
533 return the offset given by mod=00 addressing.
534 Also enables the decoding of instructions.
535 */
decode_rm00_address(PC_ENV * m,int rm)536 uint16 decode_rm00_address(PC_ENV *m, int rm)
537 {
538 uint16 offset;
539 /* note the code which specifies the corresponding segment (ds vs ss)
540 below in the case of [BP+..]. The assumption here is that at the
541 point that this subroutine is called, the bit corresponding to
542 SYSMODE_SEG_DS_SS will be zero. After every instruction
543 except the segment override instructions, this bit (as well
544 as any bits indicating segment overrides) will be clear. So
545 if a SS access is needed, set this bit. Otherwise, DS access
546 occurs (unless any of the segment override bits are set).
547 */
548 switch(rm)
549 {
550 case 0:
551 return (int16)m->R_BX + (int16)m->R_SI;
552 break;
553 case 1:
554 return (int16)m->R_BX + (int16)m->R_DI;
555 break;
556 case 2:
557 m->sysmode |= SYSMODE_SEG_DS_SS;
558 return (int16)m->R_BP + (int16)m->R_SI;
559 break;
560 case 3:
561 m->sysmode |= SYSMODE_SEG_DS_SS;
562 return (int16)m->R_BP + (int16)m->R_DI;
563 break;
564 case 4:
565 return m->R_SI;
566 break;
567 case 5:
568 return m->R_DI;
569 break;
570 case 6:
571 offset = (int16)fetch_word_imm(m);
572 return offset;
573 break;
574 case 7:
575 return m->R_BX;
576 }
577 halt_sys(m);
578 return 0;
579 }
580
581 /*
582 return the offset given by mod=01 addressing.
583 Also enables the decoding of instructions.
584 */
decode_rm01_address(PC_ENV * m,int rm)585 uint16 decode_rm01_address(PC_ENV *m, int rm)
586 {
587 int8 displacement;
588 /* note comment on decode_rm00_address above */
589 displacement = (int8)fetch_byte_imm(m); /* !!!! Check this */
590 switch(rm)
591 {
592 case 0:
593 return (int16)m->R_BX + (int16)m->R_SI + displacement;
594 break;
595 case 1:
596 return (int16)m->R_BX + (int16)m->R_DI + displacement;
597 break;
598 case 2:
599 m->sysmode |= SYSMODE_SEG_DS_SS;
600 return (int16)m->R_BP + (int16)m->R_SI + displacement;
601 break;
602 case 3:
603 m->sysmode |= SYSMODE_SEG_DS_SS;
604 return (int16)m->R_BP + (int16)m->R_DI + displacement;
605 break;
606 case 4:
607 return (int16)m->R_SI + displacement;
608 break;
609 case 5:
610 return (int16)m->R_DI + displacement;
611 break;
612 case 6:
613 m->sysmode |= SYSMODE_SEG_DS_SS;
614 return (int16)m->R_BP + displacement;
615 break;
616 case 7:
617 return (int16)m->R_BX + displacement;
618 break;
619 }
620 halt_sys(m);
621 return 0; /* SHOULD NOT HAPPEN */
622 }
623
624 /*
625 return the offset given by mod=01 addressing.
626 Also enables the decoding of instructions.
627 */
decode_rm10_address(PC_ENV * m,int rm)628 uint16 decode_rm10_address(PC_ENV *m, int rm)
629 {
630 int16 displacement;
631 /* note comment on decode_rm00_address above */
632 displacement = (int16)fetch_word_imm(m);
633 switch(rm)
634 {
635 case 0:
636 return (int16)m->R_BX + (int16)m->R_SI + displacement;
637 break;
638 case 1:
639 return (int16)m->R_BX + (int16)m->R_DI + displacement;
640 break;
641 case 2:
642 m->sysmode |= SYSMODE_SEG_DS_SS;
643 return (int16)m->R_BP + (int16)m->R_SI + displacement;
644 break;
645 case 3:
646 m->sysmode |= SYSMODE_SEG_DS_SS;
647 return (int16)m->R_BP + (int16)m->R_DI + displacement;
648 break;
649 case 4:
650 return (int16)m->R_SI + displacement;
651 break;
652 case 5:
653 return (int16)m->R_DI + displacement;
654 break;
655 case 6:
656 m->sysmode |= SYSMODE_SEG_DS_SS;
657 return (int16)m->R_BP + displacement;
658 break;
659 case 7:
660 return (int16)m->R_BX + displacement;
661 break;
662 }
663 halt_sys(m);
664 return 0;
665 /*NOTREACHED */
666 }
667
668 /* fetch a byte of data, given an offset, the current register set,
669 and a descriptor for memory.
670 */
fetch_data_byte(PC_ENV * m,uint16 offset)671 uint8 fetch_data_byte(PC_ENV *m, uint16 offset)
672 {
673 register uint8 value;
674 /* this code originally completely broken, and never showed
675 up since the DS segments === SS segment in all test cases.
676 It had been originally assumed, that all access to data would
677 involve the DS register unless there was a segment override.
678 Not so. Address modes such as -3[BP] or 10[BP+SI] all
679 refer to addresses relative to the SS. So, at the minimum,
680 all decodings of addressing modes would have to set/clear
681 a bit describing whether the access is relative to DS or SS.
682 That is the function of the cpu-state-varible m->sysmode.
683 There are several potential states:
684 repe prefix seen (handled elsewhere)
685 repne prefix seen (ditto)
686 cs segment override
687 ds segment override
688 es segment override
689 ss segment override
690 ds/ss select (in absense of override)
691 Each of the above 7 items are handled with a bit in the sysmode
692 field.
693 The latter 5 can be implemented as a simple state machine:
694 */
695 switch(m->sysmode & SYSMODE_SEGMASK)
696 {
697 case 0:
698 /* default case: use ds register */
699 value = GetBYTEExtended(((uint32)m->R_DS<<4) + offset);
700 break;
701 case SYSMODE_SEG_DS_SS:
702 /* non-overridden, use ss register */
703 /* [JCE] Wrap at 1Mb (the A20 gate) */
704 value = GetBYTEExtended((((uint32)m->R_SS << 4) + offset) & 0xFFFFF);
705 break;
706 case SYSMODE_SEGOVR_CS:
707 /* ds overridden */
708 case SYSMODE_SEGOVR_CS|SYSMODE_SEG_DS_SS:
709 /* ss overridden, use cs register */
710 /* [JCE] Wrap at 1Mb (the A20 gate) */
711 value = GetBYTEExtended((((uint32)m->R_CS << 4) + offset) & 0xFFFFF);
712 break;
713 case SYSMODE_SEGOVR_DS:
714 /* ds overridden --- shouldn't happen, but hey. */
715 case SYSMODE_SEGOVR_DS|SYSMODE_SEG_DS_SS:
716 /* ss overridden, use ds register */
717 /* [JCE] Wrap at 1Mb (the A20 gate) */
718 value = GetBYTEExtended((((uint32)m->R_DS << 4) + offset) & 0xFFFFF);
719 break;
720 case SYSMODE_SEGOVR_ES:
721 /* ds overridden */
722 case SYSMODE_SEGOVR_ES|SYSMODE_SEG_DS_SS:
723 /* ss overridden, use es register */
724 /* [JCE] Wrap at 1Mb (the A20 gate) */
725 value = GetBYTEExtended((((uint32)m->R_ES << 4) + offset) & 0xFFFFF);
726 break;
727 case SYSMODE_SEGOVR_SS:
728 /* ds overridden */
729 case SYSMODE_SEGOVR_SS|SYSMODE_SEG_DS_SS:
730 /* ss overridden, use ss register === should not happen */
731 /* [JCE] Wrap at 1Mb (the A20 gate) */
732 value = GetBYTEExtended((((uint32)m->R_SS << 4) + offset) & 0xFFFFF);
733 break;
734 default:
735 printf("error: should not happen: multiple overrides. " NLP);
736 value = 0;
737 halt_sys(m);
738 }
739 return value;
740 }
741
742 /* fetch a byte of data, given an offset, the current register set,
743 and a descriptor for memory.
744 */
fetch_data_byte_abs(PC_ENV * m,uint16 segment,uint16 offset)745 uint8 fetch_data_byte_abs(PC_ENV *m, uint16 segment, uint16 offset)
746 {
747 register uint8 value;
748 uint32 addr;
749 /* note, cannot change this, since we do not know the ID of the segment. */
750 /* [JCE] Simulate wrap at top of memory (the A20 gate) */
751 /* addr = (segment << 4) + offset; */
752 addr = ((segment << 4) + offset) & 0xFFFFF;
753 value = GetBYTEExtended(addr);
754 return value;
755 }
756
757 /* fetch a byte of data, given an offset, the current register set,
758 and a descriptor for memory.
759 */
fetch_data_word(PC_ENV * m,uint16 offset)760 uint16 fetch_data_word(PC_ENV *m, uint16 offset)
761 {
762 uint16 value;
763 /* See note above in fetch_data_byte. */
764 switch(m->sysmode & SYSMODE_SEGMASK)
765 {
766 case 0:
767 /* default case: use ds register */
768 /* [JCE] Wrap at 1Mb (the A20 gate) */
769 value = GetBYTEExtended((((uint32)m->R_DS << 4) + offset) & 0xFFFFF)
770 | (GetBYTEExtended((((uint32)m->R_DS << 4) +
771 (uint16)(offset + 1)) & 0xFFFFF) << 8);
772 break;
773 case SYSMODE_SEG_DS_SS:
774 /* non-overridden, use ss register */
775 /* [JCE] Wrap at 1Mb (the A20 gate) */
776 value = GetBYTEExtended((((uint32)m->R_SS << 4) + offset) & 0xFFFFF)
777 | (GetBYTEExtended((((uint32)m->R_SS << 4)
778 + (uint16)(offset + 1)) & 0xFFFFF) << 8);
779 break;
780 case SYSMODE_SEGOVR_CS:
781 /* ds overridden */
782 case SYSMODE_SEGOVR_CS|SYSMODE_SEG_DS_SS:
783 /* ss overridden, use cs register */
784 /* [JCE] Wrap at 1Mb (the A20 gate) */
785 value = GetBYTEExtended((((uint32)m->R_CS << 4) + offset) & 0xFFFFF)
786 | (GetBYTEExtended((((uint32)m->R_CS << 4)
787 + (uint16)(offset + 1)) & 0xFFFFF) << 8);
788 break;
789 case SYSMODE_SEGOVR_DS:
790 /* ds overridden --- shouldn't happen, but hey. */
791 case SYSMODE_SEGOVR_DS|SYSMODE_SEG_DS_SS:
792 /* ss overridden, use ds register */
793 /* [JCE] Wrap at 1Mb (the A20 gate) */
794 value = GetBYTEExtended((((uint32)m->R_DS << 4) + offset) & 0xFFFFF)
795 | (GetBYTEExtended((((uint32)m->R_DS << 4)
796 + (uint16)(offset + 1)) & 0xFFFFF) << 8);
797 break;
798 case SYSMODE_SEGOVR_ES:
799 /* ds overridden */
800 case SYSMODE_SEGOVR_ES|SYSMODE_SEG_DS_SS:
801 /* ss overridden, use es register */
802 value = GetBYTEExtended((((uint32)m->R_ES << 4) + offset) & 0xFFFFF)
803 | (GetBYTEExtended((((uint32)m->R_ES << 4) +
804 (uint16)(offset + 1)) & 0xFFFFF) << 8);
805 break;
806 case SYSMODE_SEGOVR_SS:
807 /* ds overridden */
808 case SYSMODE_SEGOVR_SS|SYSMODE_SEG_DS_SS:
809 /* ss overridden, use ss register === should not happen */
810 value = GetBYTEExtended((((uint32)m->R_SS << 4) + offset) & 0xFFFFF)
811 | (GetBYTEExtended((((uint32)m->R_SS << 4)
812 + (uint16)(offset + 1)) & 0xFFFFF) << 8);
813 break;
814 default:
815 printf("error: should not happen: multiple overrides. " NLP);
816 value = 0;
817 halt_sys(m);
818 }
819 return value;
820 }
821
822 /* fetch a byte of data, given an offset, the current register set,
823 and a descriptor for memory.
824 */
fetch_data_word_abs(PC_ENV * m,uint16 segment,uint16 offset)825 uint16 fetch_data_word_abs(PC_ENV *m, uint16 segment, uint16 offset)
826 {
827 uint16 value;
828 uint32 addr;
829 /* [JCE] Simulate wrap at top of memory (the A20 gate) */
830 /* addr = (segment << 4) + offset; */
831 addr = ((segment << 4) + offset) & 0xFFFFF;
832 value = GetBYTEExtended(addr) | (GetBYTEExtended(addr + 1) << 8);
833 return value;
834 }
835
836 /* Store a byte of data, given an offset, the current register set,
837 and a descriptor for memory.
838 */
store_data_byte(PC_ENV * m,uint16 offset,uint8 val)839 void store_data_byte(PC_ENV *m, uint16 offset, uint8 val)
840 {
841 /* See note above in fetch_data_byte. */
842 uint32 addr;
843 register uint16 segment;
844 switch(m->sysmode & SYSMODE_SEGMASK)
845 {
846 case 0:
847 /* default case: use ds register */
848 segment = m->R_DS;
849 break;
850 case SYSMODE_SEG_DS_SS:
851 /* non-overridden, use ss register */
852 segment = m->R_SS;
853 break;
854 case SYSMODE_SEGOVR_CS:
855 /* ds overridden */
856 case SYSMODE_SEGOVR_CS|SYSMODE_SEG_DS_SS:
857 /* ss overridden, use cs register */
858 segment = m->R_CS;
859 break;
860 case SYSMODE_SEGOVR_DS:
861 /* ds overridden --- shouldn't happen, but hey. */
862 case SYSMODE_SEGOVR_DS|SYSMODE_SEG_DS_SS:
863 /* ss overridden, use ds register */
864 segment = m->R_DS;
865 break;
866 case SYSMODE_SEGOVR_ES:
867 /* ds overridden */
868 case SYSMODE_SEGOVR_ES|SYSMODE_SEG_DS_SS:
869 /* ss overridden, use es register */
870 segment = m->R_ES;
871 break;
872 case SYSMODE_SEGOVR_SS:
873 /* ds overridden */
874 case SYSMODE_SEGOVR_SS|SYSMODE_SEG_DS_SS:
875 /* ss overridden, use ss register === should not happen */
876 segment = m->R_SS;
877 break;
878 default:
879 printf("error: should not happen: multiple overrides. " NLP);
880 segment = 0;
881 halt_sys(m);
882 }
883 /* [JCE] Simulate wrap at top of memory (the A20 gate) */
884 /* addr = (segment << 4) + offset; */
885 addr = (((uint32)segment << 4) + offset) & 0xFFFFF;
886 PutBYTEExtended(addr, val);
887 }
888
store_data_byte_abs(PC_ENV * m,uint16 segment,uint16 offset,uint8 val)889 void store_data_byte_abs(PC_ENV *m, uint16 segment, uint16 offset, uint8 val)
890 {
891 register uint32 addr;
892 /* [JCE] Simulate wrap at top of memory (the A20 gate) */
893 /* addr = (segment << 4) + offset; */
894 addr = (((uint32)segment << 4) + offset) & 0xFFFFF;
895 PutBYTEExtended(addr, val);
896 }
897
898 /* Store a word of data, given an offset, the current register set,
899 and a descriptor for memory.
900 */
store_data_word(PC_ENV * m,uint16 offset,uint16 val)901 void store_data_word(PC_ENV *m, uint16 offset, uint16 val)
902 {
903 register uint32 addr;
904 register uint16 segment;
905 /* See note above in fetch_data_byte. */
906 switch(m->sysmode & SYSMODE_SEGMASK)
907 {
908 case 0:
909 /* default case: use ds register */
910 segment = m->R_DS;
911 break;
912 case SYSMODE_SEG_DS_SS:
913 /* non-overridden, use ss register */
914 segment = m->R_SS;
915 break;
916 case SYSMODE_SEGOVR_CS:
917 /* ds overridden */
918 case SYSMODE_SEGOVR_CS|SYSMODE_SEG_DS_SS:
919 /* ss overridden, use cs register */
920 segment = m->R_CS;
921 break;
922 case SYSMODE_SEGOVR_DS:
923 /* ds overridden --- shouldn't happen, but hey. */
924 case SYSMODE_SEGOVR_DS|SYSMODE_SEG_DS_SS:
925 /* ss overridden, use ds register */
926 segment = m->R_DS;
927 break;
928 case SYSMODE_SEGOVR_ES:
929 /* ds overridden */
930 case SYSMODE_SEGOVR_ES|SYSMODE_SEG_DS_SS:
931 /* ss overridden, use es register */
932 segment = m->R_ES;
933 break;
934 case SYSMODE_SEGOVR_SS:
935 /* ds overridden */
936 case SYSMODE_SEGOVR_SS|SYSMODE_SEG_DS_SS:
937 /* ss overridden, use ss register === should not happen */
938 segment = m->R_SS;
939 break;
940 default:
941 printf("error: should not happen: multiple overrides." NLP);
942 segment = 0;
943 halt_sys(m);
944 }
945 /* [JCE] Simulate wrap at top of memory (the A20 gate) */
946 /* addr = (segment << 4) + offset; */
947 addr = (((uint32)segment << 4) + offset) & 0xFFFFF;
948 PutBYTEExtended(addr, val & 0xff);
949 PutBYTEExtended(addr + 1, val >> 8);
950 }
951
store_data_word_abs(PC_ENV * m,uint16 segment,uint16 offset,uint16 val)952 void store_data_word_abs(PC_ENV *m, uint16 segment, uint16 offset, uint16 val)
953 {
954 register uint32 addr;
955 /* [JCE] Wrap at top of memory */
956 addr = ((segment << 4) + offset) & 0xFFFFF;
957 PutBYTEExtended(addr, val & 0xff);
958 PutBYTEExtended(addr + 1, val >> 8);
959 }
960