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