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