| 
									
										
										
										
											2011-04-24 01:14:00 +00:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Turbo68K: Motorola 680X0 emulator | 
					
						
							|  |  |  |  * Copyright 2000-2002 Bart Trzynadlowski, see "README.TXT" for terms of use | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Make68K: This program emits Turbo68K. Please see README.TXT for details. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Note: If you get a link error involving pow(), remember to link in the math | 
					
						
							|  |  |  |  *       library. Try using "-lm". | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Note: I am not certain about dummy reads. The manual says they occur with | 
					
						
							|  |  |  |  *       some instructions on the MC68000 and MC68008 only. Does this include | 
					
						
							|  |  |  |  *       the MC68EC000? I'm assuming it does. Also, is a dummy read made for | 
					
						
							|  |  |  |  *       all Scc instructions, or just ST? I'm assuming all of them do it. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Note: Do not use the profiling feature (#define PROFILE.) It will add | 
					
						
							|  |  |  |  *       useless junk to the emulator. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Note: Future plans: I intend on removing as much of the Save/RestoreReg() | 
					
						
							|  |  |  |  *       junk from the API functions as possible. PUSH/POPs should work much | 
					
						
							|  |  |  |  *       better. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Additional developers' notes pertaining to all aspects of Turbo68K can be | 
					
						
							|  |  |  |  * found at the very end of this file. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <math.h>
 | 
					
						
							|  |  |  | #include <stdarg.h>
 | 
					
						
							|  |  |  | #include <stdio.h>
 | 
					
						
							|  |  |  | #include <stdlib.h>
 | 
					
						
							|  |  |  | #include <string.h>
 | 
					
						
							|  |  |  | #include "turbo68k.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define VERSION "0.6"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define SIZEOF_CONTEXT          "(context_end - context_start)"
 | 
					
						
							|  |  |  | #define SIZEOF_FETCHREGION      "12"
 | 
					
						
							|  |  |  | #define SIZEOF_DATAREGION       "16"
 | 
					
						
							|  |  |  | #define OFFSET_DATA_BASE        "0"
 | 
					
						
							|  |  |  | #define OFFSET_DATA_LIMIT       "4"
 | 
					
						
							|  |  |  | #define OFFSET_DATA_PTR         "8"
 | 
					
						
							|  |  |  | #define OFFSET_DATA_HANDLER     "12"
 | 
					
						
							|  |  |  | #define OFFSET_FETCH_BASE       "0"
 | 
					
						
							|  |  |  | #define OFFSET_FETCH_LIMIT      "4"
 | 
					
						
							|  |  |  | #define OFFSET_FETCH_PTR        "8"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define WRITEPCTOMEM(dest)      {                               \
 | 
					
						
							|  |  |  |                                 e("mov  dword ["dest"], esi\n");\ | 
					
						
							|  |  |  |                                 e("sub  dword ["dest"], ebp\n");\ | 
					
						
							|  |  |  |                                 } | 
					
						
							|  |  |  | #define WRITEPCTOREG(dest)      {                               \
 | 
					
						
							|  |  |  |                                 e("mov  "dest", esi\n");        \ | 
					
						
							|  |  |  |                                 e("sub  "dest", ebp\n");        \ | 
					
						
							|  |  |  |                                 } | 
					
						
							|  |  |  | #define EMULATING()             e("or   byte [status], 1\n");
 | 
					
						
							|  |  |  | #define STOP_EMULATING()        e("and  byte [status], 0xfe\n");
 | 
					
						
							|  |  |  | #define STOP_CPU()              e("or   byte [status], 2\n");
 | 
					
						
							|  |  |  | #define UNSTOP_CPU()            e("and  byte [status], 0xfd\n");
 | 
					
						
							|  |  |  | #define INTERRUPT_PROCESSING()  e("or   byte [status], 4\n");
 | 
					
						
							|  |  |  | #define INTERRUPT_DONE()        e("and  byte [status], 0xfb\n");
 | 
					
						
							|  |  |  | #define STOP_RUNNING()          {                               \
 | 
					
						
							|  |  |  |                                 e("mov [remaining], ecx\n");  \ | 
					
						
							|  |  |  |                                 WRITEPCTOMEM("pc");           \ | 
					
						
							|  |  |  |                                 } | 
					
						
							|  |  |  | #define A7                      "[a+7*4]"
 | 
					
						
							|  |  |  | #define SP                      "[__sp]"
 | 
					
						
							|  |  |  | #define SR                      "[sr]"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define UNKNOWN_SIZE            0
 | 
					
						
							|  |  |  | #define BYTE_SIZE               1
 | 
					
						
							|  |  |  | #define WORD_SIZE               2
 | 
					
						
							|  |  |  | #define LONG_SIZE               3
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | unsigned short  decoded[65536];             /* compressed jump table data */ | 
					
						
							|  |  |  | char            id[17] = { '\0' };          /* prepended to identifiers */ | 
					
						
							|  |  |  | FILE            *fp;                        /* output file */ | 
					
						
							|  |  |  | int             mpu = 68000;                /* 68000 by default */ | 
					
						
							|  |  |  | unsigned        addr_bits = 24;             /* 24-bit by default */ | 
					
						
							|  |  |  | unsigned        addr_mask = 0xffffff; | 
					
						
							|  |  |  | int             illegal = 1;                /* illegal instruction traps */ | 
					
						
							|  |  |  | int             dummyread = 1;              /* dummy reads (68000 only) */ | 
					
						
							|  |  |  | int             skip = 0;                   /* CPU (idle loop) skipping */ | 
					
						
							|  |  |  | int             brafetch = 0;               /* branch fetch ptr updating */ | 
					
						
							|  |  |  | int             pcfetch = 0;                /* special PC-relative fetching */ | 
					
						
							|  |  |  | int             multiaddr = 1;              /* supervisor and user spaces */ | 
					
						
							|  |  |  | int             memmap_type = 0;            /* memory map type */ | 
					
						
							|  |  |  | int             call_convention = 0;        /* calling convention */ | 
					
						
							| 
									
										
										
										
											2011-06-27 23:10:51 +00:00
										 |  |  | int             debug = 0;                  /* call debug function at every instruction */ | 
					
						
							| 
									
										
										
										
											2011-04-24 01:14:00 +00:00
										 |  |  | int             mmx = 0;                    /* MMX support -- don't use! */ | 
					
						
							|  |  |  | unsigned        num_handlers = 0;           /* # of inst. handlers emitted */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifdef PROFILE
 | 
					
						
							|  |  |  | char            *prof[512]; | 
					
						
							|  |  |  | int             prof_i = 0; | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*****************************************************************************
 | 
					
						
							|  |  |  | * General Emitters                                                          */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void e(char *input, ...) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     va_list arg; | 
					
						
							|  |  |  |     char    text[256]; | 
					
						
							|  |  |  |     va_start(arg, input); | 
					
						
							|  |  |  |     vsprintf(text, input, arg); | 
					
						
							|  |  |  |     va_end(arg); | 
					
						
							|  |  |  |     fprintf(fp, text); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void EmitLabel(char *label) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     e("%s:\n", label); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void Align(int i) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     e("times ($$-$) & %d nop\n", i - 1); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void CacheAlign() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     Align(32); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void EmitGlobalLabel(char *label) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     e("global %s%s, _%s%s, %s%s_\n", id, label, id, label, id, label); | 
					
						
							|  |  |  |     e("%s%s:\n_%s%s:\n%s%s_:\n", id, label, id, label, id, label); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*****************************************************************************
 | 
					
						
							|  |  |  | * Utility Functions                                                         */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * SizeOfContext(): Returns the size of the context if needed by the emitter. | 
					
						
							|  |  |  |  * This should be used instead of C's sizeof(). | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int SizeOfContext() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     switch (mpu) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |     case 68010: | 
					
						
							|  |  |  |         return sizeof(struct TURBO68K_CONTEXT_68010); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return sizeof(struct TURBO68K_CONTEXT_68000); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * NameOfContext(): Returns the name of the context based on the MPU type, | 
					
						
							|  |  |  |  * but NOT with the identifier in front of it. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static char *NameOfContext() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     static char name[16 + 6 + 1]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     sprintf(name, "turbo68kcontext_%d", mpu); | 
					
						
							|  |  |  |     return name; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * NOTE: Only pass 32-bit or 8-bit (XL, not XH regs) to the SaveReg/SaveRegTo, | 
					
						
							|  |  |  |  * RestoreReg/RestoreRegTo functions. Don't ever pass 16-bit regs! | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * SaveReg/RestoreReg: Save/restore registers to/from a specific save slot | 
					
						
							|  |  |  |  * area. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void SaveReg(char *area, char *reg) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (mmx) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if (!strcmp(area, "memhandler")) | 
					
						
							|  |  |  |         {   /* memhandler always saves full reg */ | 
					
						
							|  |  |  |             if (!strcmp(reg, "eax"))    { e("movd   mm0, eax\n"); return; } | 
					
						
							|  |  |  |             if (!strcmp(reg, "ebx"))    { e("movd   mm1, ebx\n"); return; } | 
					
						
							|  |  |  |             if (!strcmp(reg, "ebp"))    { e("movd   mm2, ebp\n"); return; } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else if (!strcmp(area, "run")) | 
					
						
							|  |  |  |         {   /* we have to check if its a full or byte reg */ | 
					
						
							|  |  |  |             if (!strcmp(reg, "edx") || !strcmp(reg, "dl")) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 e("movd mm3, edx\n"); | 
					
						
							|  |  |  |                 return; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             if (!strcmp(reg, "esi"))    { e("movd   mm4, esi\n"); return; } | 
					
						
							|  |  |  |             if (!strcmp(reg, "edi"))    { e("movd   mm5, edi\n"); return; } | 
					
						
							|  |  |  |         }           | 
					
						
							|  |  |  |     }         | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     e("mov  [%s_", area); | 
					
						
							|  |  |  |     if (reg[1] == 'l')  /* ?l byte reg */ | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         switch (reg[0]) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |         case 'a':   e("eax"); break; | 
					
						
							|  |  |  |         case 'b':   e("ebx"); break; | 
					
						
							|  |  |  |         case 'c':   e("ecx"); break; | 
					
						
							|  |  |  |         case 'd':   e("edx"); break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |         e("%s", reg); | 
					
						
							|  |  |  |     e("], %s\n", reg); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void RestoreReg(char *area, char *reg) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (mmx) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if (!strcmp(area, "memhandler")) | 
					
						
							|  |  |  |         {   /* memhandler always restores full reg */ | 
					
						
							|  |  |  |             if (!strcmp(reg, "eax"))    { e("movd   eax, mm0\n"); return; } | 
					
						
							|  |  |  |             if (!strcmp(reg, "ebx"))    { e("movd   ebx, mm1\n"); return; } | 
					
						
							|  |  |  |             if (!strcmp(reg, "ebp"))    { e("movd   ebp, mm2\n"); return; } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else if (!strcmp(area, "run")) | 
					
						
							|  |  |  |         {   /* we have to check if its a full or byte reg */ | 
					
						
							|  |  |  |             if (!strcmp(reg, "edx") || !strcmp(reg, "dl")) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 e("movd edx, mm3\n"); | 
					
						
							|  |  |  |                 return; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             if (!strcmp(reg, "esi"))    { e("movd   esi, mm4\n"); return; } | 
					
						
							|  |  |  |             if (!strcmp(reg, "edi"))    { e("movd   edi, mm5\n"); return; } | 
					
						
							|  |  |  |         }           | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     e("mov  %s, [%s_", reg, area); | 
					
						
							|  |  |  |     if (reg[1] == 'l')  /* ?l byte reg */ | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         switch (reg[0]) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |         case 'a':   e("eax"); break; | 
					
						
							|  |  |  |         case 'b':   e("ebx"); break; | 
					
						
							|  |  |  |         case 'c':   e("ecx"); break; | 
					
						
							|  |  |  |         case 'd':   e("edx"); break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |         e("%s", reg); | 
					
						
							|  |  |  |     e("]\n"); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * SaveRegTo/RestoreRegTo: Saves/restore a register to a different register | 
					
						
							|  |  |  |  * than indicated by the name of the save slot. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void SaveRegTo(char *area, char *d_reg, char *s_reg) | 
					
						
							|  |  |  | {     | 
					
						
							|  |  |  |     if (mmx) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         /* currently, memhandlers don't need this, only run_ does. */ | 
					
						
							|  |  |  |         if (!strcmp(area, "run")) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             /* test to make sure dest is MMX-able */ | 
					
						
							|  |  |  |             if (!strcmp(d_reg, "edx") || !strcmp(d_reg, "esi") || !strcmp(d_reg, "edi")) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 e("movd "); | 
					
						
							|  |  |  |                 if (!strcmp(d_reg, "edx"))      e("mm3, "); | 
					
						
							|  |  |  |                 else if (!strcmp(d_reg, "esi")) e("mm4, "); | 
					
						
							|  |  |  |                 else if (!strcmp(d_reg, "edi")) e("mm5, "); | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |                 if (s_reg[1] == 'l')    /* ?l byte reg */ | 
					
						
							|  |  |  |                 { | 
					
						
							|  |  |  |                     switch (s_reg[0]) | 
					
						
							|  |  |  |                     { | 
					
						
							|  |  |  |                     case 'a':   e("eax\n"); break; | 
					
						
							|  |  |  |                     case 'b':   e("ebx\n"); break; | 
					
						
							|  |  |  |                     case 'c':   e("ecx\n"); break; | 
					
						
							|  |  |  |                     case 'd':   e("edx\n"); break; | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 else | 
					
						
							|  |  |  |                     e("%s\n", s_reg); | 
					
						
							|  |  |  |                 return; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     e("mov  [%s_%s], %s\n", area, d_reg, s_reg); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void RestoreRegTo(char *area, char *s_reg, char *d_reg) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (mmx) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         /* currently, memhandlers don't need this, only run_ does. */ | 
					
						
							|  |  |  |         if (!strcmp(area, "run")) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             /* test to make sure src is MMX-able */ | 
					
						
							|  |  |  |             if (!strcmp(s_reg, "edx") || !strcmp(s_reg, "esi") || !strcmp(s_reg, "edi")) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 e("movd "); | 
					
						
							|  |  |  |                 if (d_reg[1] == 'l')    /* ?l byte reg */ | 
					
						
							|  |  |  |                 { | 
					
						
							|  |  |  |                     switch (d_reg[0]) | 
					
						
							|  |  |  |                     { | 
					
						
							|  |  |  |                     case 'a':   e("eax, "); break; | 
					
						
							|  |  |  |                     case 'b':   e("ebx, "); break; | 
					
						
							|  |  |  |                     case 'c':   e("ecx, "); break; | 
					
						
							|  |  |  |                     case 'd':   e("edx, "); break; | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 else | 
					
						
							|  |  |  |                     e("%s, ", d_reg); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 if (!strcmp(s_reg, "edx"))      e("mm3\n"); | 
					
						
							|  |  |  |                 else if (!strcmp(s_reg, "esi")) e("mm4\n"); | 
					
						
							|  |  |  |                 else if (!strcmp(s_reg, "edi")) e("mm5\n"); | 
					
						
							|  |  |  |                 return; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     e("mov  %s, [%s_%s]\n", d_reg, area, s_reg); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void AddrClip(char *reg) | 
					
						
							|  |  |  | {   /* if it's 32-bit we don't need this */ | 
					
						
							|  |  |  |     if (addr_mask != 0xffffffff)    e("and  %s, 0x%08X\n", reg, addr_mask); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void RideIntoTheDangerZone()    /* where EBP is modified and must be saved */ | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     e("push ebp\n"); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void RideOutOfTheDangerZone() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     e("pop  ebp\n"); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void GetArg(char *dest_reg, int num_arg, int stack_offs) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     char    *reg[2] = { "eax", "edx" }; /* currently, only 2 args supported */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (num_arg > 1)    /* error! */ | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         fprintf(stderr, "Make68K: Internal Error: GetArg() called with num_arg = %d. Please contact Bart Trzynadlowski!\n", num_arg); | 
					
						
							|  |  |  |         if (call_convention) | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!call_convention) | 
					
						
							|  |  |  |         e("mov  %s, [esp+%d]\n", dest_reg, stack_offs); | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if ((!strcmp(dest_reg, "eax") && !num_arg) || (!strcmp(dest_reg, "edx") && num_arg == 1)) | 
					
						
							|  |  |  |             ;               /* EAX,EAX or EDX,EDX */ | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |             e("mov  %s, %s\n", dest_reg, reg[num_arg]); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void GetArgFromTheDangerZone(char *dest_reg, int num) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     char    *reg[2] = { "eax", "edx" }; /* no more than 2 args usually */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!call_convention)   /* stack-based */ | 
					
						
							|  |  |  |         e("mov  %s, [esp+8+(%d*4)]\n", dest_reg, num); | 
					
						
							|  |  |  |     else                    /* register-based */ | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if ((!strcmp(dest_reg, "eax") && !num) || (!strcmp(dest_reg, "edx") && num == 1)) | 
					
						
							|  |  |  |             ;               /* EAX,EAX or EDX,EDX */ | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |             e("mov  %s, %s\n", dest_reg, reg[num]); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void GetArgNoStringsAttached(char *dest_reg, int num) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     char    *reg[2] = { "eax", "edx" }; /* no more than 2 args usually */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!call_convention) | 
					
						
							|  |  |  |         e("mov  %s, [esp+4+(%d*4)]\n", dest_reg, num); | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if ((!strcmp(dest_reg, "eax") && !num) || (!strcmp(dest_reg, "edx") && num == 1)) | 
					
						
							|  |  |  |             ;               /* EAX,EAX or EDX,EDX */ | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |             e("mov  %s, %s\n", dest_reg, reg[num]); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ReadLong() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (memmap_type == 0 || memmap_type == 1)   e("call ReadLong\n"); | 
					
						
							|  |  |  |     else if (memmap_type == 2)                  e("call dword [read_long]\n"); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ReadByte() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (memmap_type == 0 || memmap_type == 1)   e("call ReadByte\n"); | 
					
						
							|  |  |  |     else if (memmap_type == 2)                  e("call dword [read_byte]\n"); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ReadWord() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (memmap_type == 0 || memmap_type == 1)   e("call ReadWord\n"); | 
					
						
							|  |  |  |     else if (memmap_type == 2)                  e("call dword [read_word]\n"); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void WriteLong() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (memmap_type == 0 || memmap_type == 1)   e("call WriteLong\n"); | 
					
						
							|  |  |  |     else if (memmap_type == 2)                  e("call dword [write_long]\n"); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void WriteByte() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (memmap_type == 0 || memmap_type == 1)   e("call WriteByte\n"); | 
					
						
							|  |  |  |     else if (memmap_type == 2)                  e("call dword [write_byte]\n"); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void WriteWord() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (memmap_type == 0 || memmap_type == 1)   e("call WriteWord\n"); | 
					
						
							|  |  |  |     else if (memmap_type == 2)                  e("call dword [write_word]\n"); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ReadByteSX() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     fprintf(stderr, "Make68K: Internal Error: Sign-extended byte read handler required. Please contact Bart Trzynadlowski!\n"); | 
					
						
							|  |  |  |     exit(1); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ReadWordSX() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (memmap_type == 0 || memmap_type == 1)   e("call ReadWordSX\n"); | 
					
						
							|  |  |  |     else if (memmap_type == 2) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         e("call     dword [read_word]\n"); | 
					
						
							|  |  |  |         e("movsx    edx, dx\n"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * LoadFromEA() and MOVEM() use the ReadXXXPC() functions. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ReadLongPC() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     e("call ReadLongPC\n"); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ReadBytePC() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     e("call ReadBytePC\n"); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ReadWordPC() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     e("call ReadWordPC\n"); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ReadByteSXPC() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     fprintf(stderr, "Make68K: Internal Error: Sign-extended byte read handler required. Please contact Bart Trzynadlowski!\n"); | 
					
						
							|  |  |  |     exit(1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     e("call     ReadBytePC\n"); | 
					
						
							|  |  |  |     e("movsx    edx, dl\n"); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ReadWordSXPC() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     e("call     ReadWordPC\n"); | 
					
						
							|  |  |  |     e("movsx    edx, dx\n"); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void UpdateFetchPtr()   /* scan the fetch area */ | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     int     inst = 0; | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |      * In:  ESI = address | 
					
						
							|  |  |  |      * Out: ESI = PC + ptr | 
					
						
							|  |  |  |      *      EBP = ptr (base) | 
					
						
							|  |  |  |      *      EDX = trashed | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |      * Note: If address bus is NOT 32-bits, the following applies. | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * The unused bits of the PC MUST be preserved. Therefore, those unused | 
					
						
							|  |  |  |      * bits are subtracted from the base pointer so that when we add a PC | 
					
						
							|  |  |  |      * WITH unused bits, it won't go out of range, because it will be far | 
					
						
							|  |  |  |      * below range to begin with. | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * The reasoning here is that if we subtract the unused bits from the base | 
					
						
							|  |  |  |      * pointer, the unused bits in the normalized PC pointer (ESI) will cancel | 
					
						
							|  |  |  |      * out. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     if (addr_mask != 0xffffffff) | 
					
						
							|  |  |  |         SaveReg("fetch", "esi"); | 
					
						
							|  |  |  |     AddrClip("esi"); | 
					
						
							|  |  |  |     e("mov     edx, [fetch]\n"); | 
					
						
							|  |  |  |     e(".find_fetch_loop%d:\n", inst); | 
					
						
							|  |  |  |     e("add     edx, byte "SIZEOF_FETCHREGION"\n"); | 
					
						
							|  |  |  |     e("cmp     dword [edx], byte -1\n");        /* limit=-1? end. */ | 
					
						
							|  |  |  |     e("je      near fetch_error\n"); | 
					
						
							|  |  |  |     e("cmp     esi, [edx]\n");                  /* offset 0: base. above it? */ | 
					
						
							|  |  |  |     e("jb      .find_fetch_loop%d\n", inst);    /* nope, not this region */ | 
					
						
							|  |  |  |     e("cmp     esi, [edx+"OFFSET_FETCH_LIMIT"]\n"); /* limit. below it? */ | 
					
						
							|  |  |  |     e("ja      .find_fetch_loop%d\n", inst);        /* nope, not this region */ | 
					
						
							|  |  |  |     e("mov     ebp, [edx+"OFFSET_FETCH_PTR"]\n");   /* ebp=base ptr */ | 
					
						
							|  |  |  |     if (addr_mask != 0xffffffff)    /* to handle those nasty unused bits! */ | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         e("mov  edx, [fetch_esi]\n"); | 
					
						
							|  |  |  |         e("mov  esi, edx\n");   /* this is the ACTUAL PC we saved earlier */ | 
					
						
							|  |  |  |         e("and  edx, 0x%08X\n", ~addr_mask);/* we only want the unused bits */ | 
					
						
							|  |  |  |         e("sub  ebp, edx\n"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     e("add     esi, ebp\n");                        /* +pc=pc ptr.. */ | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void LoadCCR()  /* CCR->AX ... trashes AX and DX */ | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     e("mov      dh, [sr]\n");       /* DH:***XNZVC  */ | 
					
						
							|  |  |  |     e("mov      ah, dh\n");         /* AH:***XNZVC  */ | 
					
						
							|  |  |  |     e("shl      ah, byte 4\n");     /* AH:NZVC0000  */ | 
					
						
							|  |  |  |     e("test     dh, byte 2\n");     /* V flag?      */ | 
					
						
							|  |  |  |     e("setnz    al\n");             /* AL:0000000V  */ | 
					
						
							|  |  |  |     e("test     dh, 0x10\n");       /* X flag?      */ | 
					
						
							|  |  |  |     e("setnz    byte [x]\n");       /* X:0000000000000000000000000000000X */ | 
					
						
							|  |  |  |     e("and      dh, byte 1\n");     /* DH:0000000C  */ | 
					
						
							|  |  |  |     e("or       ah, dh\n");         /* AH:NZ**000C  */ | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void SaveCCR()  /* AX->CCR... trashes AX and DX */ | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     e("and      eax, 0xc101\n");    /* EAX:0000000000000000NZ00000C0000000V */ | 
					
						
							|  |  |  |     e("mov      dh, ah\n");         /*  DH:NZ00000C */ | 
					
						
							|  |  |  |     e("shr      dh, byte 4\n");     /*  DH:0000NZ00 */ | 
					
						
							|  |  |  |     e("shl      al, byte 1\n");     /*  AL:000000V0 */ | 
					
						
							|  |  |  |     e("or       dh, al\n");         /*  DH:0000NZV0 */ | 
					
						
							|  |  |  |     e("shr      ah, byte 1\n");     /*  CF:C        */ | 
					
						
							|  |  |  |     e("adc      dh, 0\n");          /*  DH:0000NZVC */ | 
					
						
							|  |  |  |     e("mov      ah, [x]\n");        /*  AH:0000000X */ | 
					
						
							|  |  |  |     e("shl      ah, byte 4\n");     /*  AH:000X0000 */ | 
					
						
							|  |  |  |     e("or       dh, ah\n");         /*  DH:000XNZVC */ | 
					
						
							|  |  |  |     e("mov      [sr], dh\n");          | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void InstBegin(unsigned short op, char *mnem, unsigned num) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | #ifdef PROFILE
 | 
					
						
							|  |  |  |     int i; | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Align(4); | 
					
						
							|  |  |  |     if (num == 1) | 
					
						
							|  |  |  |         e("I%04X: ; %s\t\t0x%04X\n", op, mnem, op); | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |         e("I%04X: ; %s\t\t0x%04X-0x%04X\n", op, mnem, op, op+(num-1)); | 
					
						
							| 
									
										
										
										
											2011-06-27 23:10:51 +00:00
										 |  |  | 	if (debug) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		// Debugging code 
 | 
					
						
							|  |  |  | 		char noDebugLabel[16]; | 
					
						
							|  |  |  | 		char noPCChgLabel[16]; | 
					
						
							|  |  |  | 		sprintf(noDebugLabel, ".no_debug%04X", op); | 
					
						
							|  |  |  | 		sprintf(noPCChgLabel, ".no_pcchg%04X", op); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		e("mov  ebx, [Debug]\n");            /* Get debug handler */ | 
					
						
							|  |  |  | 		e("test ebx, ebx\n");                /* If no handler set, skip debugging */ | 
					
						
							|  |  |  | 		e("jz   short %s\n", noDebugLabel); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		e("push eax\n");					 /* Note: __cdecl calling convention used to call handler */ | 
					
						
							|  |  |  | 		e("push edi\n"); | 
					
						
							|  |  |  | 		e("push ebp\n"); | 
					
						
							|  |  |  | 		WRITEPCTOMEM("pc");                  /* Save esi */ | 
					
						
							|  |  |  | 		e("mov  [remaining], ecx\n"); | 
					
						
							|  |  |  | 		e("push edi\n");                     /* Pass instruction opcode to handler */ | 
					
						
							|  |  |  | 		e("sub  esi, ebp\n");                /* Convert PC to base offset */ | 
					
						
							|  |  |  | 		e("sub  esi, byte 2\n");             /* Adjust back to beginning of instruction */ | 
					
						
							|  |  |  | 		e("push esi\n");				     /* Pass result to handler */ | 
					
						
							|  |  |  | 		e("call ebx\n");                     /* Call handler */ | 
					
						
							|  |  |  | 		e("add  esp, byte 8\n"); | 
					
						
							|  |  |  | 		e("mov  esi, [pc]\n");               /* Restore esi (this could have been changed) */ | 
					
						
							|  |  |  | 		e("mov  ecx, [remaining]\n");        /* This could have been changed */ | 
					
						
							|  |  |  | 		e("pop  ebp\n"); | 
					
						
							|  |  |  | 		e("pop  edi\n"); | 
					
						
							|  |  |  | 		e("add  esi, ebp\n");				 /* Convert esi to pointer (base+pc) */ | 
					
						
							|  |  |  | 		e("test eax, eax\n");			     /* Check if debug handler changed PC */ | 
					
						
							|  |  |  | 		e("jz   short %s\n", noPCChgLabel);  | 
					
						
							|  |  |  | 		e("pop  eax\n");                     /* If so, move onto instruction at new PC */ | 
					
						
							|  |  |  | 		e("mov  di, [esi]\n"); | 
					
						
							|  |  |  | 		e("add  esi, byte 2\n");             /* Point to word after next opcode */ | 
					
						
							|  |  |  | 		e("jmp  dword [jmptab+edi*4]\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		EmitLabel(noPCChgLabel); | 
					
						
							|  |  |  | 		e("pop  eax\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		EmitLabel(noDebugLabel); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2011-04-24 01:14:00 +00:00
										 |  |  |     decoded[op] = num; | 
					
						
							|  |  |  |     num_handlers++; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifdef PROFILE
 | 
					
						
							|  |  |  |     for (i = 0; i < strlen(mnem); i++)  /* remove spaces */ | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if (mnem[i] == ' ') | 
					
						
							|  |  |  |             mnem[i] = '_'; | 
					
						
							|  |  |  |     }     | 
					
						
							|  |  |  |     e("inc  dword [prof%s]\n", mnem); | 
					
						
							|  |  |  |     for (i = 0; prof[i] != NULL && i < 512; i++) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if (!strcmp(prof[i], mnem)) /* already have one of these... */ | 
					
						
							|  |  |  |             return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     prof[prof_i] = calloc(strlen(mnem) + 1, 1); | 
					
						
							|  |  |  |     strcpy(prof[prof_i], mnem); | 
					
						
							|  |  |  |     prof_i++; | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void InstEnd() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     e("mov  di, [esi]\n"); | 
					
						
							|  |  |  |     e("add  esi, byte 2\n");        /* point to word after next opcode */ | 
					
						
							|  |  |  |     e("jmp  dword [jmptab+edi*4]\n"); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*****************************************************************************
 | 
					
						
							|  |  |  | * Address Space Management                                                  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Input:   Nothing | 
					
						
							|  |  |  |  * Notes:   Assumes that run_ecx, run_edi, and run_esi are available for use. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void SetSupervisorAddressSpace() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (!multiaddr) return; | 
					
						
							|  |  |  |     e("push ecx\n"); | 
					
						
							|  |  |  |     e("cld\n");                     /* direction: forward */ | 
					
						
							|  |  |  |     e("push esi\n"); | 
					
						
							|  |  |  |     e("push edi\n"); | 
					
						
							|  |  |  |     e("mov  ecx, 8\n");             /* 8 dword-size pointers to copy */ | 
					
						
							|  |  |  |     e("mov  edi, fetch\n"); | 
					
						
							|  |  |  |     e("mov  esi, super_fetch\n"); | 
					
						
							|  |  |  |     e("rep  movsd\n"); | 
					
						
							|  |  |  |     e("pop  edi\n"); | 
					
						
							|  |  |  |     e("pop  esi\n"); | 
					
						
							|  |  |  |     e("pop  ecx\n"); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void SetUserAddressSpace() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (!multiaddr) return; | 
					
						
							|  |  |  |     e("push ecx\n"); | 
					
						
							|  |  |  |     e("cld\n");                     /* direction: forward */ | 
					
						
							|  |  |  |     e("push esi\n"); | 
					
						
							|  |  |  |     e("push edi\n"); | 
					
						
							|  |  |  |     e("mov  ecx, 8\n");             /* 8 dword-size pointers to copy */ | 
					
						
							|  |  |  |     e("mov  edi, fetch\n"); | 
					
						
							|  |  |  |     e("mov  esi, user_fetch\n"); | 
					
						
							|  |  |  |     e("rep  movsd\n"); | 
					
						
							|  |  |  |     e("pop  edi\n"); | 
					
						
							|  |  |  |     e("pop  esi\n"); | 
					
						
							|  |  |  |     e("pop  ecx\n"); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  | /*****************************************************************************
 | 
					
						
							|  |  |  | * Timing                                                                    */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* TimingEA: calculates amount of clocks taken by a given EA mode */ | 
					
						
							|  |  |  | unsigned TimingEA(unsigned ea, int size)  | 
					
						
							|  |  |  | {       /* EA format = MMMRRR (mode/register) */ | 
					
						
							|  |  |  |     switch ((ea >> 3) & 7)  /* mode */ | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |     case 0: case 1: return 0; break; | 
					
						
							|  |  |  |     case 2: case 3: | 
					
						
							|  |  |  |         switch (size) { case BYTE_SIZE: case WORD_SIZE: return 4; break; | 
					
						
							|  |  |  |                         case LONG_SIZE: return 8; break; } break; | 
					
						
							|  |  |  |     case 4: | 
					
						
							|  |  |  |         switch (size) { case BYTE_SIZE: case WORD_SIZE: return 6; break; | 
					
						
							|  |  |  |                         case LONG_SIZE: return 10; break; } break; | 
					
						
							|  |  |  |     case 5: | 
					
						
							|  |  |  |         switch (size) { case BYTE_SIZE: case WORD_SIZE: return 8; break; | 
					
						
							|  |  |  |                         case LONG_SIZE: return 12; break; } break; | 
					
						
							|  |  |  |     case 6: | 
					
						
							|  |  |  |         switch (size) { case BYTE_SIZE: case WORD_SIZE: return 10; break; | 
					
						
							|  |  |  |                         case LONG_SIZE: return 14; break; } break; | 
					
						
							|  |  |  |     case 7: /* misc... */ | 
					
						
							|  |  |  |         switch (ea & 0x7) { case 0: /* (xxx).W */ | 
					
						
							|  |  |  |                                 switch (size) | 
					
						
							|  |  |  |                                 { case BYTE_SIZE: case WORD_SIZE: return 8; break; | 
					
						
							|  |  |  |                                   case LONG_SIZE: return 12; break; } break; | 
					
						
							|  |  |  |                             case 1: /* (xxx).L */ | 
					
						
							|  |  |  |                                 switch (size) | 
					
						
							|  |  |  |                                 { case BYTE_SIZE: case WORD_SIZE: return 12; break; | 
					
						
							|  |  |  |                                   case LONG_SIZE: return 16; break; } break; | 
					
						
							|  |  |  |                             case 4: /* #<data> */ | 
					
						
							|  |  |  |                                 switch (size) | 
					
						
							|  |  |  |                                 { case BYTE_SIZE: case WORD_SIZE: return 4; break; | 
					
						
							|  |  |  |                                   case LONG_SIZE: return 8; break; } break; | 
					
						
							|  |  |  |                             case 2: /* (d16,pc) */ | 
					
						
							|  |  |  |                                 switch (size) | 
					
						
							|  |  |  |                                 { case BYTE_SIZE: case WORD_SIZE: return 8; break; | 
					
						
							|  |  |  |                                   case LONG_SIZE: return 12; break; } break; | 
					
						
							|  |  |  |                             case 3: /* (d8,pc,Xn) */ | 
					
						
							|  |  |  |                             switch (size) | 
					
						
							|  |  |  |                             { case BYTE_SIZE: case WORD_SIZE: return 10; break; | 
					
						
							|  |  |  |                               case LONG_SIZE: return 14; break; } break; | 
					
						
							|  |  |  |                           } | 
					
						
							|  |  |  |     } return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void EmitTiming(unsigned cycles) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (cycles) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if (cycles == 1)            e("dec  ecx\n"); | 
					
						
							|  |  |  |         else if (!(cycles & 0x80))  e("sub  ecx, byte %d\n", cycles); | 
					
						
							|  |  |  |         else                        e("sub  ecx, %d\n", cycles); | 
					
						
							|  |  |  |         e("js   near Turbo68KRun_done\n"); /* below 0, finished */ | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*****************************************************************************
 | 
					
						
							|  |  |  | * Effective Address Code                                                    */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int CheckEA(unsigned ea, char *valid)   /* EA = MMMRRR (mode/reg) */ | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |      * valid[] string is a mask for valid addressing modes as they appear | 
					
						
							|  |  |  |      * in the 68K manual, in order, 1 = okay, 0 = not allowed | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     if (((ea >> 3) & 7) != 7)   /* mode 7 is handled separately */ | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if (valid[(ea >> 3) & 7] != '1')    return 0;   /* not allowed! */ | 
					
						
							|  |  |  |         else                                return 1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else                        /* handle mode 7 here */ | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         /* first check if the register is invalid */ | 
					
						
							|  |  |  |         if ((ea & 7) >= 5)  return 0;                   /* no such thing! */ | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             switch (ea & 7) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |             case 0: | 
					
						
							|  |  |  |             case 1: | 
					
						
							|  |  |  |                 if (valid[7+(ea & 7)] != '1')       return 0; | 
					
						
							|  |  |  |                 else                    return 1;   break; | 
					
						
							|  |  |  |             case 4: | 
					
						
							|  |  |  |                 if (valid[7+2] != '1')  return 0; | 
					
						
							|  |  |  |                 else                    return 1;   break; | 
					
						
							|  |  |  |             case 2: | 
					
						
							|  |  |  |                 if (valid[7+3] != '1')  return 0; | 
					
						
							|  |  |  |                 else                    return 1;   break; | 
					
						
							|  |  |  |             case 3: | 
					
						
							|  |  |  |                 if (valid[7+4] != '1')  return 0; | 
					
						
							|  |  |  |                 else                    return 1;   break; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     }   return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int NumDecodedEA(unsigned ea)   /* how many handlers can this feed? */ | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |      * Turbo68K does not generate an instruction handler for every possible | 
					
						
							|  |  |  |      * opcode, instead, it generates one for every possible EA mode of a given | 
					
						
							|  |  |  |      * instruction. This means if reg==0, it returns the # to pass to InstEnd | 
					
						
							|  |  |  |      * (which indicates how many opcodes this will cover for) Otherwise, this | 
					
						
							|  |  |  |      * function returns 0 and the instruction handler should not be emitted. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (((ea >> 3) & 7) <= 6 && (ea & 7) != 0)      return 0; | 
					
						
							|  |  |  |     else if (((ea >> 3) & 7) <= 6 && (ea & 7) == 0) return 8;   /* 8 regs */ | 
					
						
							|  |  |  |     else if (((ea >> 3) & 7) == 7 && (ea & 7) <= 4) return 1;   /* 1 reg */ | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Effective Address calculations | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Note: When loading words, usually the whole dword is loaded. When storing, | 
					
						
							|  |  |  |  * only the word part is stored | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  |     | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Returns: Data in EDX, address preserved in EBX | 
					
						
							|  |  |  |  * Used:    EBX, EDX, EDI (unless reading from register) | 
					
						
							|  |  |  |  * Notes:   ESI is assumed to point at word after opcode | 
					
						
							|  |  |  |  *          Assumes EDI contains opcode and that it has EA at the very end | 
					
						
							|  |  |  |  *          This function is only to be used when EA mode fields are located | 
					
						
							|  |  |  |  *          at bits 0-5.  | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void LoadFromEA(unsigned ea, int size, int sign_extend) | 
					
						
							|  |  |  | {  | 
					
						
							|  |  |  |     switch ((ea >> 3) & 7) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |     case 0: /* Dn */ | 
					
						
							|  |  |  |     case 1: /* An */ | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         char    r = ((ea >> 3) & 7) ? 'a' : 'd'; | 
					
						
							|  |  |  |         e("and  edi, byte 7\n");    /* get reg number, EDI contains opcode */ | 
					
						
							|  |  |  |         if (size == LONG_SIZE) | 
					
						
							|  |  |  |             e("mov  edx, [%c+edi*4]\n", r); | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             if (size == BYTE_SIZE) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 if (!sign_extend) | 
					
						
							|  |  |  |                     e("mov  dl, [%c+edi*4]\n", r); | 
					
						
							|  |  |  |                 else | 
					
						
							|  |  |  |                     e("movsx    edx, byte [%c+edi*4]\n", r); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             else    /* word size */ | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 if (!sign_extend) | 
					
						
							|  |  |  |                     e("mov  edx, [%c+edi*4]\n", r); | 
					
						
							|  |  |  |                 else | 
					
						
							|  |  |  |                     e("movsx    edx, word [%c+edi*4]\n", r); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         }         | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     break; | 
					
						
							|  |  |  |     case 2: /* (An) */ | 
					
						
							|  |  |  |     case 3: /* (An)+ */ | 
					
						
							|  |  |  |     case 4: /* -(An) */ | 
					
						
							|  |  |  |     case 5: /* (d16,An) */ | 
					
						
							|  |  |  |         e("and  edi, byte 7\n");    /* reg */ | 
					
						
							|  |  |  |         if (((ea >> 3) & 7) == 4)   /* pre-dec */ | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             if (size == BYTE_SIZE) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 e("cmp  edi, byte 7\n");    /* A7 bytes */ | 
					
						
							|  |  |  |                 e("cmc\n");                 /* switch carry */ | 
					
						
							|  |  |  |                 e("sbb  dword [a+edi*4], byte 1\n");                 | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             else if (size == WORD_SIZE) | 
					
						
							|  |  |  |                 e("sub  dword [a+edi*4], byte 2\n"); | 
					
						
							|  |  |  |             else if (size == LONG_SIZE) | 
					
						
							|  |  |  |                 e("sub  dword [a+edi*4], byte 4\n"); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (((ea >> 3) & 7) == 5)   /* (d16,An) */ | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             e("movsx    ebx, word [esi]\n"); | 
					
						
							|  |  |  |             e("add      ebx, [a+edi*4]\n"); | 
					
						
							|  |  |  |             e("add      esi, byte 2\n");    /* past d16, next instruction */ | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |             e("mov  ebx, [a+edi*4]\n"); | 
					
						
							|  |  |  |         if (((ea >> 3) & 7) == 3)   /* post-inc */ | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             if (size == BYTE_SIZE) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 e("cmp  edi, byte 7\n");    /* A7 bytes */ | 
					
						
							|  |  |  |                 e("cmc\n");                 /* switch carry */ | 
					
						
							|  |  |  |                 e("adc  dword [a+edi*4], byte 1\n"); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             else if (size == WORD_SIZE) | 
					
						
							|  |  |  |                 e("add  dword [a+edi*4], byte 2\n"); | 
					
						
							|  |  |  |             else if (size == LONG_SIZE) | 
					
						
							|  |  |  |                 e("add  dword [a+edi*4], byte 4\n"); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         switch (size) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |         case BYTE_SIZE: | 
					
						
							|  |  |  |             if (sign_extend) | 
					
						
							|  |  |  |                 ReadByteSX(); | 
					
						
							|  |  |  |             else | 
					
						
							|  |  |  |                 ReadByte(); | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         case WORD_SIZE: | 
					
						
							|  |  |  |             if (sign_extend) | 
					
						
							|  |  |  |                 ReadWordSX(); | 
					
						
							|  |  |  |             else | 
					
						
							|  |  |  |                 ReadWord(); | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         case LONG_SIZE: | 
					
						
							|  |  |  |             ReadLong(); | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case 6: /* (d8,An,Xn) */ | 
					
						
							|  |  |  |         e("and      edi, byte 7\n");    /* An reg # */ | 
					
						
							|  |  |  |         e("xor      ebx, ebx\n");       /* so the high part is clear */ | 
					
						
							|  |  |  |         e("mov      bx, [esi]\n");      /* fetch extension word */ | 
					
						
							|  |  |  |         e("movsx    edx, bl\n");        /* sign-extended index */ | 
					
						
							|  |  |  |         e("add      esi, byte 2\n");    /* point at next word */ | 
					
						
							|  |  |  |         e("shr      ebx, byte 12\n");   /* regs must be: d, a for this to work */ | 
					
						
							|  |  |  |                                         /* the shr sets CF if Long reg */ | 
					
						
							|  |  |  |         e("mov      ebx, [d+ebx*4]\n"); | 
					
						
							|  |  |  |         e("jc       short .ll\n");      /* CF=1? index reg is LONG */ | 
					
						
							|  |  |  |         e("movsx    ebx, bx\n");        /* otherwise: sign-extended WORD */ | 
					
						
							|  |  |  |         EmitLabel(".ll"); | 
					
						
							|  |  |  |         e("add      ebx, edx\n");       /* disp+index_reg */ | 
					
						
							|  |  |  |         e("add      ebx, [a+edi*4]\n"); | 
					
						
							|  |  |  |         switch (size) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |         case BYTE_SIZE: | 
					
						
							|  |  |  |             if (sign_extend) | 
					
						
							|  |  |  |                 ReadByteSX(); | 
					
						
							|  |  |  |             else | 
					
						
							|  |  |  |                 ReadByte(); | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         case WORD_SIZE: | 
					
						
							|  |  |  |             if (sign_extend) | 
					
						
							|  |  |  |                 ReadWordSX(); | 
					
						
							|  |  |  |             else | 
					
						
							|  |  |  |                 ReadWord(); | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         case LONG_SIZE: | 
					
						
							|  |  |  |             ReadLong(); | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case 0x7: | 
					
						
							|  |  |  |         switch (ea & 7) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |         case 0: /* (xxx).W */ | 
					
						
							|  |  |  |         case 1: /* (xxx).L */ | 
					
						
							|  |  |  |             if ((ea & 7) == 0)  /* word */ | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 e("movsx    ebx, word [esi]\n"); | 
					
						
							|  |  |  |                 e("add      esi, byte 2\n"); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             else                /* long */ | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 e("mov      ebx, [esi]\n");                | 
					
						
							|  |  |  |                 e("ror      ebx, byte 16\n");    /* word-swap */ | 
					
						
							|  |  |  |                 e("add      esi, byte 4\n"); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             switch (size) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |             case BYTE_SIZE: | 
					
						
							|  |  |  |                 if (sign_extend) | 
					
						
							|  |  |  |                     ReadByteSX(); | 
					
						
							|  |  |  |                 else | 
					
						
							|  |  |  |                     ReadByte(); | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             case WORD_SIZE: | 
					
						
							|  |  |  |                 if (sign_extend) | 
					
						
							|  |  |  |                     ReadWordSX(); | 
					
						
							|  |  |  |                 else | 
					
						
							|  |  |  |                     ReadWord(); | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             case LONG_SIZE: | 
					
						
							|  |  |  |                 ReadLong(); | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         case 4: /* #<data> */ | 
					
						
							|  |  |  |             switch (size) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |             case BYTE_SIZE: | 
					
						
							|  |  |  |                 if (!sign_extend) | 
					
						
							|  |  |  |                     e("mov  dl, [esi]\n");  /* get low byte of ext. word */ | 
					
						
							|  |  |  |                 else | 
					
						
							|  |  |  |                     e("movsx    edx, byte [esi]\n"); | 
					
						
							|  |  |  |                 e("add  esi, byte 2\n"); | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             case WORD_SIZE: | 
					
						
							|  |  |  |                 if (!sign_extend) | 
					
						
							|  |  |  |                     e("mov  edx, [esi]\n"); /* bx = word, ebx=????:word */ | 
					
						
							|  |  |  |                 else | 
					
						
							|  |  |  |                     e("movsx    edx, word [esi]\n"); | 
					
						
							|  |  |  |                 e("add  esi, byte 2\n"); | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             case LONG_SIZE: | 
					
						
							|  |  |  |                 e("mov  edx, [esi]\n");     /* get long-word */ | 
					
						
							|  |  |  |                 e("add  esi, byte 4\n"); | 
					
						
							|  |  |  |                 e("ror  edx, byte 16\n");   /* word swap to work... */ | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |         case 2: /* (d16,PC) */             | 
					
						
							|  |  |  |             /*
 | 
					
						
							|  |  |  |              * The PC is assumed to be pointing at the extension word, which | 
					
						
							|  |  |  |              * is exactly how the emulator works | 
					
						
							|  |  |  |              */ | 
					
						
							|  |  |  |             e("movsx    ebx, word [esi]\n"); | 
					
						
							|  |  |  |             e("add      ebx, esi\n"); | 
					
						
							|  |  |  |             e("sub      ebx, ebp\n"); | 
					
						
							|  |  |  |             e("add      esi, byte 2\n"); | 
					
						
							|  |  |  |             switch (size) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |             case BYTE_SIZE: | 
					
						
							|  |  |  |                 if (sign_extend) | 
					
						
							|  |  |  |                     pcfetch ? ReadByteSXPC() : ReadByteSX(); | 
					
						
							|  |  |  |                 else | 
					
						
							|  |  |  |                     pcfetch ? ReadBytePC() : ReadByte(); | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             case WORD_SIZE: | 
					
						
							|  |  |  |                 if (sign_extend) | 
					
						
							|  |  |  |                     pcfetch ? ReadWordSXPC() : ReadWordSX(); | 
					
						
							|  |  |  |                 else | 
					
						
							|  |  |  |                     pcfetch ? ReadWordPC() : ReadWord(); | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             case LONG_SIZE: | 
					
						
							|  |  |  |                 pcfetch ? ReadLongPC() : ReadLong(); | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         case 3: /* (d8,PC,Xn) */ | 
					
						
							|  |  |  |             e("xor      ebx, ebx\n");       /* so the high part is clear */ | 
					
						
							|  |  |  |             e("mov      bx, [esi]\n");      /* fetch extension word */ | 
					
						
							|  |  |  |             e("movsx    edx, bl\n");        /* sign-extended index */ | 
					
						
							|  |  |  |             e("shr      ebx, byte 12\n");   /* regs must be: d, a for this to work */ | 
					
						
							|  |  |  |                                             /* the shr sets CF if Long reg */ | 
					
						
							|  |  |  |             e("mov      ebx, [d+ebx*4]\n"); | 
					
						
							|  |  |  |             e("jc       short .ll\n");      /* CF=1? index reg is LONG */ | 
					
						
							|  |  |  |             e("movsx    ebx, bx\n");        /* otherwise: sign-extended WORD */ | 
					
						
							|  |  |  |             EmitLabel(".ll"); | 
					
						
							|  |  |  |             e("add      ebx, edx\n");       /* disp+index_reg */ | 
					
						
							|  |  |  |             e("add      ebx, esi\n");       /* add the PC */ | 
					
						
							|  |  |  |             e("sub      ebx, ebp\n"); | 
					
						
							|  |  |  |             e("add      esi, byte 2\n");    /* point at next word */ | 
					
						
							|  |  |  |             switch (size) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |             case BYTE_SIZE: | 
					
						
							|  |  |  |                 if (sign_extend) | 
					
						
							|  |  |  |                     pcfetch ? ReadByteSXPC() : ReadByteSX(); | 
					
						
							|  |  |  |                 else | 
					
						
							|  |  |  |                     pcfetch ? ReadBytePC() : ReadByte(); | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             case WORD_SIZE: | 
					
						
							|  |  |  |                 if (sign_extend) | 
					
						
							|  |  |  |                     pcfetch ? ReadWordSXPC() : ReadWordSX(); | 
					
						
							|  |  |  |                 else | 
					
						
							|  |  |  |                     pcfetch ? ReadWordPC() : ReadWord(); | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             case LONG_SIZE: | 
					
						
							|  |  |  |                 pcfetch ? ReadLongPC() : ReadLong(); | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |         printf("Error!\a\n"); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Expects: Data in EDX, address in EBX | 
					
						
							|  |  |  |  * Notes:   Destroys EBX, make sure to preserve the address if you need it. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void StoreToEA(unsigned ea, int size, int same) | 
					
						
							|  |  |  | {   /* the "same" parameter is ignored. it no longer is needed */ | 
					
						
							|  |  |  |     switch ((ea >> 3) & 7) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |     case 0: /* Dn */ | 
					
						
							|  |  |  |     case 1: /* An */ | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         char    r = ((ea >> 3) & 7) ? 'a' : 'd'; | 
					
						
							|  |  |  |         if (size == LONG_SIZE) | 
					
						
							|  |  |  |             e("mov  [%c+%d*4], edx\n", r, ea & 7); | 
					
						
							|  |  |  |         else if (size == BYTE_SIZE) | 
					
						
							|  |  |  |             e("mov  [%c+%d*4], dl\n", r, ea & 7); | 
					
						
							|  |  |  |         else if (size == WORD_SIZE) | 
					
						
							|  |  |  |             e("mov  [%c+%d*4], dx\n", r, ea & 7); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     break; | 
					
						
							|  |  |  |     case 2: /* (An) */ | 
					
						
							|  |  |  |     case 3: /* (An)+ */ | 
					
						
							|  |  |  |     case 4: /* -(An) */ | 
					
						
							|  |  |  |     case 5: /* (d16,An) */ | 
					
						
							|  |  |  |         if (((ea >> 3) & 7) == 4)   /* pre-dec */ | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             if (size == BYTE_SIZE) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 if ((ea & 7) == 7)  /* A7 kept word aligned */ | 
					
						
							|  |  |  |                     e("sub  dword [a+%d*4], byte 2\n", ea & 7); | 
					
						
							|  |  |  |                 else | 
					
						
							|  |  |  |                     e("dec  dword [a+%d*4]\n", ea & 7); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             else if (size == WORD_SIZE) | 
					
						
							|  |  |  |                 e("sub  dword [a+%d*4], byte 2\n", ea & 7); | 
					
						
							|  |  |  |             else if (size == LONG_SIZE) | 
					
						
							|  |  |  |                 e("sub  dword [a+%d*4], byte 4\n", ea & 7); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (((ea >> 3) & 7) == 5)   /* (d16,An) */ | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             e("movsx    ebx, word [esi]\n"); | 
					
						
							|  |  |  |             e("add      ebx, [a+%d*4]\n", ea & 7); | 
					
						
							|  |  |  |             e("add      esi, byte 2\n");    /* past d16, next instruction */ | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |                 e("mov  ebx, [a+%d*4]\n", ea & 7); | 
					
						
							|  |  |  |         if (((ea >> 3) & 7) == 3)   /* post-inc */ | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             if (size == BYTE_SIZE) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 if ((ea & 7) == 7)  /* A7 kept word aligned */ | 
					
						
							|  |  |  |                     e("add  dword [a+%d*4], byte 2\n", ea & 7); | 
					
						
							|  |  |  |                 else | 
					
						
							|  |  |  |                     e("inc  dword [a+%d*4]\n", ea & 7); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             else if (size == WORD_SIZE) | 
					
						
							|  |  |  |                 e("add  dword [a+%d*4], byte 2\n", ea & 7); | 
					
						
							|  |  |  |             else if (size == LONG_SIZE) | 
					
						
							|  |  |  |                 e("add  dword [a+%d*4], byte 4\n", ea & 7); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         switch (size) | 
					
						
							|  |  |  |         {   case BYTE_SIZE: WriteByte(); break; | 
					
						
							|  |  |  |             case WORD_SIZE: WriteWord(); break; | 
					
						
							|  |  |  |             case LONG_SIZE: WriteLong(); break;  } | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case 6: /* (d8,An,Xn) */ | 
					
						
							|  |  |  |         e("xor      ebx, ebx\n");       /* so the high part is clear */ | 
					
						
							|  |  |  |         e("mov      bx, [esi]\n");      /* fetch extension word */ | 
					
						
							|  |  |  |         e("movsx    edi, bl\n");        /* sign-extended index */ | 
					
						
							|  |  |  |         e("add      esi, byte 2\n");    /* point at next word */ | 
					
						
							|  |  |  |         e("shr      ebx, byte 12\n");   /* regs must be: d, a for this to work */ | 
					
						
							|  |  |  |                                         /* the shr sets CF if Long reg */ | 
					
						
							|  |  |  |         e("mov      ebx, [d+ebx*4]\n"); | 
					
						
							|  |  |  |         e("jc       short .ls\n");      /* CF=1? index reg is LONG */ | 
					
						
							|  |  |  |         e("movsx    ebx, bx\n");        /* otherwise: sign-extended WORD */ | 
					
						
							|  |  |  |         EmitLabel(".ls"); | 
					
						
							|  |  |  |         e("add      ebx, edi\n");       /* disp+index_reg */ | 
					
						
							|  |  |  |         e("add      ebx, [a+%d*4]\n", ea & 7); | 
					
						
							|  |  |  |         switch (size)   /* WriteXXX() clears EDI */ | 
					
						
							|  |  |  |         {   case BYTE_SIZE: WriteByte(); break; | 
					
						
							|  |  |  |             case WORD_SIZE: WriteWord(); break; | 
					
						
							|  |  |  |             case LONG_SIZE: WriteLong(); break;  } | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case 0x7: | 
					
						
							|  |  |  |         switch (ea & 7) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |         case 0: /* (xxx).W */ | 
					
						
							|  |  |  |         case 1: /* (xxx).L */ | 
					
						
							|  |  |  |             if ((ea & 7) == 0)  /* word */ | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 e("movsx    ebx, word [esi]\n"); | 
					
						
							|  |  |  |                 e("add      esi, byte 2\n"); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             else                /* long */ | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 e("mov      ebx, [esi]\n");                | 
					
						
							|  |  |  |                 e("ror      ebx, byte 16\n");   /* word-swap */ | 
					
						
							|  |  |  |                 e("add      esi, byte 4\n"); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             switch (size) | 
					
						
							|  |  |  |             {   case BYTE_SIZE: WriteByte(); break; | 
					
						
							|  |  |  |                 case WORD_SIZE: WriteWord(); break; | 
					
						
							|  |  |  |                 case LONG_SIZE: WriteLong(); break;  } | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         case 4: /* #<data> */ | 
					
						
							|  |  |  |             /* can't store to #data! */ | 
					
						
							|  |  |  |             printf("Error!\a\n"); | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         case 2: /* (d16,PC) */             | 
					
						
							|  |  |  |             /*
 | 
					
						
							|  |  |  |              * The PC is assumed to be pointing at the extension word, which | 
					
						
							|  |  |  |              * is exactly how the emulator works | 
					
						
							|  |  |  |              */ | 
					
						
							|  |  |  |             e("movsx    ebx, word [esi]\n"); | 
					
						
							|  |  |  |             e("add      ebx, esi\n"); | 
					
						
							|  |  |  |             e("sub      ebx, ebp\n"); | 
					
						
							|  |  |  |             e("add      esi, byte 2\n"); | 
					
						
							|  |  |  |             switch (size) | 
					
						
							|  |  |  |             {   case BYTE_SIZE: WriteByte(); break; | 
					
						
							|  |  |  |                 case WORD_SIZE: WriteWord(); break; | 
					
						
							|  |  |  |                 case LONG_SIZE: WriteLong(); break;  } | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         case 3: /* (d8,PC,Xn) */ | 
					
						
							|  |  |  |             e("xor      ebx, ebx\n");       /* so the high part is clear */ | 
					
						
							|  |  |  |             e("mov      bx, [esi]\n");      /* fetch extension word */ | 
					
						
							|  |  |  |             e("movsx    edi, bl\n");        /* sign-extended index */ | 
					
						
							|  |  |  |             e("shr      ebx, byte 12\n");   /* regs must be: d, a for this to work */ | 
					
						
							|  |  |  |                                             /* the shr sets CF if Long reg */ | 
					
						
							|  |  |  |             e("mov      ebx, [d+ebx*4]\n"); | 
					
						
							|  |  |  |             e("jc       short .ls\n");      /* CF=1? index reg is LONG */ | 
					
						
							|  |  |  |             e("movsx    ebx, bx\n");        /* otherwise: sign-extended WORD */ | 
					
						
							|  |  |  |             EmitLabel(".ls"); | 
					
						
							|  |  |  |             e("add      ebx, edi\n");       /* disp+index_reg */ | 
					
						
							|  |  |  |             e("add      ebx, esi\n");       /* add the PC */ | 
					
						
							|  |  |  |             e("sub      ebx, ebp\n");        | 
					
						
							|  |  |  |             e("add      esi, byte 2\n");    /* point at next word */ | 
					
						
							|  |  |  |             switch (size)   /* WriteXXX() clears EDI */ | 
					
						
							|  |  |  |             {   case BYTE_SIZE: WriteByte(); break; | 
					
						
							|  |  |  |                 case WORD_SIZE: WriteWord(); break; | 
					
						
							|  |  |  |                 case LONG_SIZE: WriteLong(); break;  }        | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * This is the same as StoreToEA() except that it uses EDI&7 to find the | 
					
						
							|  |  |  |  * register. It is assumed that EA is bits 0-5 of the opcode. This only works | 
					
						
							|  |  |  |  * in special situations like CLR and Scc. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void StoreToEAUsingEDI(unsigned ea, int size, int same) | 
					
						
							|  |  |  | {   /* the "same" parameter is ignored. it no longer is needed */ | 
					
						
							|  |  |  |     switch ((ea >> 3) & 7) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |     case 0: /* Dn */ | 
					
						
							|  |  |  |     case 1: /* An */ | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         char    r = ((ea >> 3) & 7) ? 'a' : 'd'; | 
					
						
							|  |  |  |         e("and  edi, byte 7\n"); | 
					
						
							|  |  |  |         if (size == LONG_SIZE) | 
					
						
							|  |  |  |             e("mov  [%c+edi*4], edx\n", r); | 
					
						
							|  |  |  |         else if (size == BYTE_SIZE) | 
					
						
							|  |  |  |             e("mov  [%c+edi*4], dl\n", r); | 
					
						
							|  |  |  |         else if (size == WORD_SIZE) | 
					
						
							|  |  |  |             e("mov  [%c+edi*4], dx\n", r); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     break; | 
					
						
							|  |  |  |     case 2: /* (An) */ | 
					
						
							|  |  |  |     case 3: /* (An)+ */ | 
					
						
							|  |  |  |     case 4: /* -(An) */ | 
					
						
							|  |  |  |     case 5: /* (d16,An) */ | 
					
						
							|  |  |  |         e("and  edi, byte 7\n"); | 
					
						
							|  |  |  |         if (((ea >> 3) & 7) == 4)   /* pre-dec */ | 
					
						
							|  |  |  |         {           | 
					
						
							|  |  |  |             if (size == BYTE_SIZE) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 e("cmp  edi, byte 7\n");    /* A7 bytes */ | 
					
						
							|  |  |  |                 e("cmc\n");                 /* switch carry */ | 
					
						
							|  |  |  |                 e("sbb  dword [a+edi*4], byte 1\n");                 | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             else if (size == WORD_SIZE) | 
					
						
							|  |  |  |                 e("sub  dword [a+edi*4], byte 2\n"); | 
					
						
							|  |  |  |             else if (size == LONG_SIZE) | 
					
						
							|  |  |  |                 e("sub  dword [a+edi*4], byte 4\n"); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (((ea >> 3) & 7) == 5)   /* (d16,An) */ | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             e("movsx    ebx, word [esi]\n"); | 
					
						
							|  |  |  |             e("add      ebx, [a+edi*4]\n"); | 
					
						
							|  |  |  |             e("add      esi, byte 2\n");    /* past d16, next instruction */ | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |                 e("mov  ebx, [a+edi*4]\n"); | 
					
						
							|  |  |  |         if (((ea >> 3) & 7) == 3)   /* post-inc */ | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             if (size == BYTE_SIZE) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 e("cmp  edi, byte 7\n");    /* A7 bytes */ | 
					
						
							|  |  |  |                 e("cmc\n");                 /* switch carry */ | 
					
						
							|  |  |  |                 e("adc  dword [a+edi*4], byte 1\n"); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             else if (size == WORD_SIZE) | 
					
						
							|  |  |  |                 e("add  dword [a+edi*4], byte 2\n"); | 
					
						
							|  |  |  |             else if (size == LONG_SIZE) | 
					
						
							|  |  |  |                 e("add  dword [a+edi*4], byte 4\n"); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         switch (size) | 
					
						
							|  |  |  |         {   case BYTE_SIZE: WriteByte(); break; | 
					
						
							|  |  |  |             case WORD_SIZE: WriteWord(); break; | 
					
						
							|  |  |  |             case LONG_SIZE: WriteLong(); break;  } | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case 6: /* (d8,An,Xn) */ | 
					
						
							|  |  |  |         e("and      edi, byte 7\n");    /* An reg # */ | 
					
						
							|  |  |  |         SaveReg("memhandler", "edi");   /* no memhandlers using this now... */ | 
					
						
							|  |  |  |         e("xor      ebx, ebx\n");       /* so the high part is clear */ | 
					
						
							|  |  |  |         e("mov      bx, [esi]\n");      /* fetch extension word */ | 
					
						
							|  |  |  |         e("movsx    edi, bl\n");        /* sign-extended index */ | 
					
						
							|  |  |  |         e("add      esi, byte 2\n");    /* point at next word */ | 
					
						
							|  |  |  |         e("shr      ebx, byte 12\n");   /* regs must be: d, a for this to work */ | 
					
						
							|  |  |  |                                         /* the shr sets CF if Long reg */ | 
					
						
							|  |  |  |         e("mov      ebx, [d+ebx*4]\n"); | 
					
						
							|  |  |  |         e("jc       short .ll\n");      /* CF=1? index reg is LONG */ | 
					
						
							|  |  |  |         e("movsx    ebx, bx\n");        /* otherwise: sign-extended WORD */ | 
					
						
							|  |  |  |         EmitLabel(".ll"); | 
					
						
							|  |  |  |         e("add      ebx, edi\n");       /* disp+index_reg */ | 
					
						
							|  |  |  |         RestoreReg("memhandler", "edi"); | 
					
						
							|  |  |  |         e("add      ebx, [a+edi*4]\n"); | 
					
						
							|  |  |  |         switch (size)   /* WriteXXX() clears EDI */ | 
					
						
							|  |  |  |         {   case BYTE_SIZE: WriteByte(); break; | 
					
						
							|  |  |  |             case WORD_SIZE: WriteWord(); break; | 
					
						
							|  |  |  |             case LONG_SIZE: WriteLong(); break;  } | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case 0x7: | 
					
						
							|  |  |  |         switch (ea & 7) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |         case 0: /* (xxx).W */ | 
					
						
							|  |  |  |         case 1: /* (xxx).L */ | 
					
						
							|  |  |  |             if ((ea & 7) == 0)  /* word */ | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 e("movsx    ebx, word [esi]\n"); | 
					
						
							|  |  |  |                 e("add      esi, byte 2\n"); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             else                /* long */ | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 e("mov      ebx, [esi]\n");                | 
					
						
							|  |  |  |                 e("ror      ebx, byte 16\n");   /* word-swap */ | 
					
						
							|  |  |  |                 e("add      esi, byte 4\n"); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             switch (size) | 
					
						
							|  |  |  |             {   case BYTE_SIZE: WriteByte(); break; | 
					
						
							|  |  |  |                 case WORD_SIZE: WriteWord(); break; | 
					
						
							|  |  |  |                 case LONG_SIZE: WriteLong(); break;  } | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         case 4: /* #<data> */ | 
					
						
							|  |  |  |             /* can't store to #data! */ | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         case 2: /* (d16,PC) */             | 
					
						
							|  |  |  |             /*
 | 
					
						
							|  |  |  |              * The PC is assumed to be pointing at the extension word, which | 
					
						
							|  |  |  |              * is exactly how the emulator works | 
					
						
							|  |  |  |              */ | 
					
						
							|  |  |  |             e("movsx    ebx, word [esi]\n"); | 
					
						
							|  |  |  |             e("add      ebx, esi\n"); | 
					
						
							|  |  |  |             e("sub      ebx, ebp\n"); | 
					
						
							|  |  |  |             e("add      esi, byte 2\n"); | 
					
						
							|  |  |  |             switch (size) | 
					
						
							|  |  |  |             {   case BYTE_SIZE: WriteByte(); break; | 
					
						
							|  |  |  |                 case WORD_SIZE: WriteWord(); break; | 
					
						
							|  |  |  |                 case LONG_SIZE: WriteLong(); break;  } | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         case 3: /* (d8,PC,Xn) */ | 
					
						
							|  |  |  |             e("xor      ebx, ebx\n");       /* so the high part is clear */ | 
					
						
							|  |  |  |             e("mov      bx, [esi]\n");      /* fetch extension word */ | 
					
						
							|  |  |  |             e("movsx    edi, bl\n");        /* sign-extended index */ | 
					
						
							|  |  |  |             e("shr      ebx, byte 12\n");   /* regs must be: d, a for this to work */ | 
					
						
							|  |  |  |                                             /* the shr sets CF if Long reg */ | 
					
						
							|  |  |  |             e("mov      ebx, [d+ebx*4]\n"); | 
					
						
							|  |  |  |             e("jc       short .ls\n");      /* CF=1? index reg is LONG */ | 
					
						
							|  |  |  |             e("movsx    ebx, bx\n");        /* otherwise: sign-extended WORD */ | 
					
						
							|  |  |  |             EmitLabel(".ls"); | 
					
						
							|  |  |  |             e("add      ebx, edi\n");       /* disp+index_reg */ | 
					
						
							|  |  |  |             e("add      ebx, esi\n");       /* add the PC */ | 
					
						
							|  |  |  |             e("sub      ebx, ebp\n");        | 
					
						
							|  |  |  |             e("add      esi, byte 2\n");    /* point at next word */ | 
					
						
							|  |  |  |             switch (size)   /* WriteXXX() clears EDI */ | 
					
						
							|  |  |  |             {   case BYTE_SIZE: WriteByte(); break; | 
					
						
							|  |  |  |                 case WORD_SIZE: WriteWord(); break; | 
					
						
							|  |  |  |                 case LONG_SIZE: WriteLong(); break;  }        | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |         printf("Error!\a\n"); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Returns: Address in EBX | 
					
						
							|  |  |  |  * Used:    EBX, EDX | 
					
						
							|  |  |  |  * Notes:   ESI is assumed to point at word after opcode | 
					
						
							|  |  |  |  *          Assumes EDI contains opcode and that it has EA at the very end | 
					
						
							|  |  |  |  *          This function is only to be used when EA mode fields are located | 
					
						
							|  |  |  |  *          at bits 0-5.  | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void LoadControlEA(unsigned ea) | 
					
						
							|  |  |  | {  | 
					
						
							|  |  |  |     switch ((ea >> 3) & 7) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |     case 2: /* (An) */ | 
					
						
							|  |  |  |     case 3: /* (An)+ (just load what's in (An) -- MOVEM needs this) */ | 
					
						
							|  |  |  |     case 4: /* -(An) (just load what's in (An) -- MOVEM needs this) */ | 
					
						
							|  |  |  |     case 5: /* (d16,An) */ | 
					
						
							|  |  |  |         e("and  edi, byte 7\n");    /* reg */ | 
					
						
							|  |  |  |         if (((ea >> 3) & 7) == 5)   /* (d16,An) */ | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             e("movsx    ebx, word [esi]\n"); | 
					
						
							|  |  |  |             e("add      ebx, [a+edi*4]\n"); | 
					
						
							|  |  |  |             e("add      esi, byte 2\n");    /* past d16, next instruction */ | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |             e("mov  ebx, [a+edi*4]\n"); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case 6: /* (d8,An,Xn) */ | 
					
						
							|  |  |  |         e("and      edi, byte 7\n");    /* edi=An # */ | 
					
						
							|  |  |  |         e("xor      ebx, ebx\n");       /* so the high part is clear */ | 
					
						
							|  |  |  |         e("mov      bx, [esi]\n");      /* fetch extension word */ | 
					
						
							|  |  |  |         e("movsx    edx, bl\n");        /* sign-extended index */ | 
					
						
							|  |  |  |         e("add      esi, byte 2\n");    /* point at next word */ | 
					
						
							|  |  |  |         e("shr      ebx, byte 12\n");   /* regs must be: d, a for this to work */ | 
					
						
							|  |  |  |                                         /* the shr sets CF if Long reg */ | 
					
						
							|  |  |  |         e("mov      ebx, [d+ebx*4]\n"); | 
					
						
							|  |  |  |         e("jc       short .ll\n");      /* CF=1? index reg is LONG */ | 
					
						
							|  |  |  |         e("movsx    ebx, bx\n");        /* otherwise: sign-extended WORD */ | 
					
						
							|  |  |  |         EmitLabel(".ll"); | 
					
						
							|  |  |  |         e("add      ebx, edx\n");       /* disp+index_reg */ | 
					
						
							|  |  |  |         e("add      ebx, [a+edi*4]\n"); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case 0x7: | 
					
						
							|  |  |  |         switch (ea & 7) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |         case 0: /* (xxx).W */ | 
					
						
							|  |  |  |         case 1: /* (xxx).L */ | 
					
						
							|  |  |  |             if ((ea & 7) == 0)  /* word */ | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 e("movsx    ebx, word [esi]\n"); | 
					
						
							|  |  |  |                 e("add      esi, byte 2\n"); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             else                /* long */ | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 e("mov      ebx, [esi]\n"); | 
					
						
							|  |  |  |                 e("ror      ebx, byte 16\n");   /* word-swap */ | 
					
						
							|  |  |  |                 e("add      esi, byte 4\n"); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         case 2: /* (d16,PC) */ | 
					
						
							|  |  |  |             /*
 | 
					
						
							|  |  |  |              * The PC is assumed to be pointing at the extension word, which | 
					
						
							|  |  |  |              * is exactly how the emulator works | 
					
						
							|  |  |  |              */ | 
					
						
							|  |  |  |             e("movsx    ebx, word [esi]\n"); | 
					
						
							|  |  |  |             e("add      ebx, esi\n"); | 
					
						
							|  |  |  |             e("sub      ebx, ebp\n"); | 
					
						
							|  |  |  |             e("add      esi, byte 2\n"); | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         case 3: /* (d8,PC,Xn) */ | 
					
						
							|  |  |  |             e("xor      ebx, ebx\n");       /* so the high part is clear */ | 
					
						
							|  |  |  |             e("mov      bx, [esi]\n");      /* fetch extension word */ | 
					
						
							|  |  |  |             e("movsx    edx, bl\n");        /* sign-extended index */ | 
					
						
							|  |  |  |             e("shr      ebx, byte 12\n");   /* regs must be: d, a for this to work */ | 
					
						
							|  |  |  |                                             /* the shr sets CF if Long reg */ | 
					
						
							|  |  |  |             e("mov      ebx, [d+ebx*4]\n"); | 
					
						
							|  |  |  |             e("jc       short .ll\n");      /* CF=1? index reg is LONG */ | 
					
						
							|  |  |  |             e("movsx    ebx, bx\n");        /* otherwise: sign-extended WORD */ | 
					
						
							|  |  |  |             EmitLabel(".ll"); | 
					
						
							|  |  |  |             e("add      ebx, edx\n");       /* disp+index_reg */ | 
					
						
							|  |  |  |             e("add      ebx, esi\n");       /* add the PC */ | 
					
						
							|  |  |  |             e("sub      ebx, ebp\n"); | 
					
						
							|  |  |  |             e("add      esi, byte 2\n");    /* point at next word */ | 
					
						
							|  |  |  |             break;             | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |         printf("Warning: LoadControlEA() defaulted\n"); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*****************************************************************************
 | 
					
						
							|  |  |  | * Instruction Handlers                                                      */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int RTD(unsigned short op, char *mnem, unsigned base_timing) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     InstBegin(op, mnem, 1); | 
					
						
							|  |  |  |     e("mov  ebx, [a+7*4]\n"); | 
					
						
							|  |  |  |     ReadLong(); | 
					
						
							|  |  |  |     e("xor  ebx, ebx\n"); | 
					
						
							|  |  |  |     e("add  dword [a+7*4], byte 4\n"); | 
					
						
							|  |  |  |     e("mov  bx, [esi]\n"); | 
					
						
							|  |  |  |     e("add  dword [a+7*4], ebx\n"); /* SP+4+disp */ | 
					
						
							|  |  |  |     e("mov  esi, edx\n"); | 
					
						
							|  |  |  |     UpdateFetchPtr(); | 
					
						
							|  |  |  |     EmitTiming(base_timing); | 
					
						
							|  |  |  |     InstEnd(); | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  | int MOVEC(unsigned short op, char *mnem, unsigned base_timing) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |      * Timing for an illegal control register is not handled, control is | 
					
						
							|  |  |  |      * simply passed to the illegal instruction exception handler, which uses | 
					
						
							|  |  |  |      * different timing. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     InstBegin(op, mnem, 2); | 
					
						
							|  |  |  |     e("test byte [sr+1], 0x20\n");      /* in supervisor? */ | 
					
						
							|  |  |  |     e("jz   near exception_privilege_violation\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     e("xor  ebx, ebx\n"); | 
					
						
							|  |  |  |     e("xor  edx, edx\n"); | 
					
						
							|  |  |  |     e("mov  dx, [esi]\n");               /* fetch data word */ | 
					
						
							|  |  |  |     e("mov  ebx, edx\n"); | 
					
						
							|  |  |  |     e("shr  ebx, byte 12\n");           /* EBX=general register */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     e("shr  edi, byte 1\n");            /* dr field */ | 
					
						
							|  |  |  |     e("jc   short .to_control\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |      * Test for control register. The control register value is placed in | 
					
						
							|  |  |  |      * EDX. At the end, EDX is moved to [d+ebx*4]. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     e("and  edx, 0xfff\n"); | 
					
						
							|  |  |  |     e("jnz  short .from_dfc\n"); | 
					
						
							|  |  |  |     e("mov  dl, [fc]\n");   /* SFC */ | 
					
						
							|  |  |  |     e("jmp  short .end_from\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     EmitLabel(".from_dfc"); | 
					
						
							|  |  |  |     e("cmp  edx, byte 1\n"); | 
					
						
							|  |  |  |     e("jne  short .from_usp\n"); | 
					
						
							|  |  |  |     e("mov  dl, [fc+1]\n"); /* DFC */ | 
					
						
							|  |  |  |     e("jmp  short .end_from\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     EmitLabel(".from_usp"); | 
					
						
							|  |  |  |     e("cmp  edx, 0x800\n"); | 
					
						
							|  |  |  |     e("jne  short .from_vbr\n"); | 
					
						
							|  |  |  |     e("mov  edx, [__sp]\n");    /* we're in supervisor, USP is in __sp */ | 
					
						
							|  |  |  |     e("jmp  short .end_from\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     EmitLabel(".from_vbr"); | 
					
						
							|  |  |  |     e("cmp  edx, 0x801\n"); | 
					
						
							|  |  |  |     e("jne  near exception_illegal_instruction\n"); /* invalid control reg */ | 
					
						
							|  |  |  |     e("mov  edx, [vbr]\n"); /* VBR */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     EmitLabel(".end_from"); | 
					
						
							|  |  |  |     e("mov  [d+ebx*4], edx\n"); /* move to general reg */ | 
					
						
							|  |  |  |     e("add  esi, byte 2\n");    /* remember, we fetched a word */ | 
					
						
							|  |  |  |     EmitTiming(12); | 
					
						
							|  |  |  |     e("jmp  short .end\n"); | 
					
						
							|  |  |  |                       | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |      * Test for control register. General reg is written to control reg. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     EmitLabel(".to_control"); | 
					
						
							|  |  |  |     e("mov  ebx, [d+ebx*4]\n"); /* general reg */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     e("and  edx, 0xfff\n"); | 
					
						
							|  |  |  |     e("jnz  short .to_dfc\n"); | 
					
						
							|  |  |  |     e("and  bl, 3\n"); | 
					
						
							|  |  |  |     e("mov  [fc], bl\n");   /* SFC */ | 
					
						
							|  |  |  |     e("jmp  short .end_to\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     EmitLabel(".to_dfc"); | 
					
						
							|  |  |  |     e("cmp  edx, byte 1\n"); | 
					
						
							|  |  |  |     e("jne  short .to_usp\n"); | 
					
						
							|  |  |  |     e("and  bl, 3\n"); | 
					
						
							|  |  |  |     e("mov  [fc+1], bl\n"); /* DFC */ | 
					
						
							|  |  |  |     e("jmp  short .end_to\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     EmitLabel(".to_usp"); | 
					
						
							|  |  |  |     e("cmp  edx, 0x800\n"); | 
					
						
							|  |  |  |     e("jne  short .to_vbr\n"); | 
					
						
							|  |  |  |     e("mov  [__sp], ebx\n");    /* we're in supervisor, USP is in __sp */ | 
					
						
							|  |  |  |     e("jmp  short .end_to\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     EmitLabel(".to_vbr"); | 
					
						
							|  |  |  |     e("cmp  edx, 0x801\n"); | 
					
						
							|  |  |  |     e("jne  near exception_illegal_instruction\n"); /* invalid control reg */ | 
					
						
							|  |  |  |     e("mov  [vbr], ebx\n"); /* VBR */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     EmitLabel(".end_to"); | 
					
						
							|  |  |  |     e("add  esi, byte 2\n");    /* remember, we fetched a word */ | 
					
						
							|  |  |  |     EmitTiming(10); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |      * End | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     EmitLabel(".end"); | 
					
						
							|  |  |  |     InstEnd(); | 
					
						
							|  |  |  |     return 2; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int BKPT(unsigned short op, char *mnem, unsigned base_timing) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |      * NOTE: Timing isn't done here, the exception processing code will do it. | 
					
						
							|  |  |  |      * The exception code doesn't use the proper timing for a BKPT, but it's | 
					
						
							|  |  |  |      * good enough ;) | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     InstBegin(op, mnem, 8); | 
					
						
							|  |  |  |     e("and  edi, byte 7\n");    /* vector # */ | 
					
						
							|  |  |  |     e("mov  ebx, [Bkpt]\n");    /* BKPT handler */ | 
					
						
							|  |  |  |     e("test ebx, ebx\n");       /* if no handler, don't do anything */ | 
					
						
							|  |  |  |     e("jz   short .no_handler\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     e("push eax\n"); | 
					
						
							|  |  |  |     e("push edi\n"); | 
					
						
							|  |  |  |     e("push ebp\n"); | 
					
						
							|  |  |  |     WRITEPCTOMEM("pc");                 /* saves esi */ | 
					
						
							|  |  |  |     e("mov     [remaining], ecx\n"); | 
					
						
							|  |  |  |     e("push    edi\n");                 /* vector # */ | 
					
						
							|  |  |  |     e("call    ebx\n"); | 
					
						
							|  |  |  |     e("add     esp, byte 4\n"); | 
					
						
							|  |  |  |     e("mov     esi, [pc]\n"); | 
					
						
							|  |  |  |     e("mov     ecx, [remaining]\n");    /* this could have been changed */ | 
					
						
							|  |  |  |     e("pop  ebp\n"); | 
					
						
							|  |  |  |     e("pop  edi\n"); | 
					
						
							|  |  |  |     e("pop  eax\n"); | 
					
						
							|  |  |  |     e("add     esi, ebp\n");            /* base+pc=pc pointer */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     EmitLabel(".no_handler"); | 
					
						
							|  |  |  |     e("jmp  near exception_illegal_instruction\n"); | 
					
						
							|  |  |  |     return 8; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int MOVEfromCCR(unsigned short op, char *mnem, unsigned base_timing) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     unsigned    ea = op & 0x3f, t = 4; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!CheckEA(ea, "101111111000"))   return 0; | 
					
						
							|  |  |  |     if (!NumDecodedEA(ea))              return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     InstBegin(op, mnem, NumDecodedEA(ea)); | 
					
						
							|  |  |  |     e("xor  edx, edx\n");                       /* CCR->(sign extend)->word */ | 
					
						
							|  |  |  |     e("mov  dl, [sr]\n"); | 
					
						
							|  |  |  |     StoreToEA(ea, WORD_SIZE, 0); | 
					
						
							|  |  |  |     if ((ea >> 3) != 0) t += 4;                 /* mem */ | 
					
						
							|  |  |  |     EmitTiming(t + TimingEA(ea, WORD_SIZE));    /* technically, word sized */ | 
					
						
							|  |  |  |     InstEnd(); | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int TRAPV(unsigned short op, char *mnem, unsigned base_timing) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     InstBegin(op, mnem, 1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     e("test al, al\n"); /* do only if V */ | 
					
						
							|  |  |  |     e("jz   near .no_trap\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     e("mov  edx, 0x2000\n");            /* what the SR will be */ | 
					
						
							|  |  |  |     e("xor  edx, [sr]\n");              /* see if S bit is different */ | 
					
						
							|  |  |  |     e("test edx, 0x2000\n"); | 
					
						
							|  |  |  |     e("jz   .no_sp_magic\n");           /* nope, don't swap SPs */ | 
					
						
							|  |  |  |     e("mov  edx, [__sp]\n"); | 
					
						
							|  |  |  |     e("xchg [a+7*4], edx\n"); | 
					
						
							|  |  |  |     e("mov  [__sp], edx\n"); | 
					
						
							|  |  |  |     SetSupervisorAddressSpace(); | 
					
						
							|  |  |  |     EmitLabel(".no_sp_magic"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     e("mov  ebx, [a+7*4]\n");           /* SP */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |      * If 68010, push format info | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (mpu == 68010) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         e("sub  ebx, byte 2\n");/* SP-2 */ | 
					
						
							|  |  |  |         e("mov  edx, 7*4\n");   /* TRAPV vector | 0x00000000 */ | 
					
						
							|  |  |  |         e("push ebx\n"); | 
					
						
							|  |  |  |         WriteWord(); | 
					
						
							|  |  |  |         e("pop  ebx\n"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     e("mov  edx, esi\n"); | 
					
						
							|  |  |  |     e("sub  edx, ebp\n");               /* PC->EDX */ | 
					
						
							|  |  |  |     e("sub  ebx, byte 4\n");            /* SP-4 */ | 
					
						
							|  |  |  |     e("push ebx\n"); | 
					
						
							|  |  |  |     WriteLong(); | 
					
						
							|  |  |  |     e("pop  ebx\n"); | 
					
						
							|  |  |  |     e("mov  edx, [sr]\n");              /* get SR */ | 
					
						
							|  |  |  |     e("sub  ebx, byte 2\n");            /* SP-2 */ | 
					
						
							|  |  |  |     e("push ebx\n"); | 
					
						
							|  |  |  |     WriteWord();                        /* save SR to stack */ | 
					
						
							|  |  |  |     e("pop  ebx\n"); | 
					
						
							|  |  |  |     e("or   dh, 0x20\n");               /* set supervisor for exception */ | 
					
						
							|  |  |  |     e("and  edx, 0xa71f\n");            /* clear unwanted bits */ | 
					
						
							|  |  |  |     e("xchg [sr], edx\n");              /* set new SR, get old SR->EDX */ | 
					
						
							|  |  |  |     e("mov  [a+7*4], ebx\n");           /* write back SP */ | 
					
						
							|  |  |  |     e("mov  ebx, 7*4\n");               /* TRAPV vector */ | 
					
						
							|  |  |  |     if (mpu == 68010) | 
					
						
							|  |  |  |         e("add  ebx, [vbr]\n"); | 
					
						
							|  |  |  |     ReadLong();                         /* get PC */ | 
					
						
							|  |  |  |     e("mov  esi, edx\n");               /* set new PC */ | 
					
						
							|  |  |  |     UpdateFetchPtr(); | 
					
						
							|  |  |  |     EmitTiming(34+4);                   /* TRAPV=4, exception=34 */ | 
					
						
							|  |  |  |     InstEnd(); | 
					
						
							|  |  |  |     EmitLabel(".no_trap"); | 
					
						
							|  |  |  |     e("xor  edi, edi\n"); | 
					
						
							|  |  |  |     EmitTiming(4);                   | 
					
						
							|  |  |  |     InstEnd(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  | int STOP(unsigned short op, char *mnem, unsigned base_timing) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     InstBegin(op, mnem, 1); | 
					
						
							|  |  |  |     e("test byte [sr+1], 0x20\n");      /* in supervisor? */ | 
					
						
							|  |  |  |     e("jz   near exception_privilege_violation\n"); | 
					
						
							|  |  |  |     e("mov  edx, [esi]\n"); | 
					
						
							|  |  |  |     e("add  esi, byte 2\n"); | 
					
						
							|  |  |  |     e("and  edx, 0xa71f\n");            /* mask out unimplemented bits */ | 
					
						
							|  |  |  |     e("mov  [sr], dx\n"); | 
					
						
							|  |  |  |     LoadCCR(); | 
					
						
							|  |  |  |     STOP_CPU(); | 
					
						
							|  |  |  |     EmitTiming(base_timing); | 
					
						
							|  |  |  |     e("mov  dword [remaining], 0\n");   /* stop executing */ | 
					
						
							|  |  |  |     e("jmp  near Turbo68KRun_done\n"); | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int RESET(unsigned short op, char *mnem, unsigned base_timing) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     InstBegin(op, mnem, 1); | 
					
						
							|  |  |  |     e("test byte [sr+1], 0x20\n");      /* in supervisor? */ | 
					
						
							|  |  |  |     e("jz   near exception_privilege_violation\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     e("mov  ebx, [Reset]\n");   /* Reset handler */ | 
					
						
							|  |  |  |     e("test ebx, ebx\n");       /* if no handler, don't do anything */ | 
					
						
							|  |  |  |     e("jz   short .no_reset\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     e("push eax\n"); | 
					
						
							|  |  |  |     e("push ebp\n"); | 
					
						
							|  |  |  |     WRITEPCTOMEM("pc");                 /* saves esi */ | 
					
						
							|  |  |  |     e("mov     [remaining], ecx\n"); | 
					
						
							|  |  |  |     e("call    ebx\n"); | 
					
						
							|  |  |  |     e("mov     esi, [pc]\n"); | 
					
						
							|  |  |  |     e("mov     ecx, [remaining]\n");    /* this could have been changed */ | 
					
						
							|  |  |  |     e("pop  ebp\n"); | 
					
						
							|  |  |  |     e("pop  eax\n"); | 
					
						
							|  |  |  |     e("add     esi, ebp\n");            /* base+pc=pc pointer */ | 
					
						
							|  |  |  |     e("xor     edi, edi\n");            /* keep clear for fetch */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     EmitLabel(".no_reset"); | 
					
						
							|  |  |  |     EmitTiming(base_timing); | 
					
						
							|  |  |  |     InstEnd(); | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int TAS(unsigned short op, char *mnem, unsigned base_timing) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     unsigned    ea = op & 0x3f; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!CheckEA(ea, "101111111000"))   return 0; | 
					
						
							|  |  |  |     if (!NumDecodedEA(ea))              return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     InstBegin(op, mnem, NumDecodedEA(ea)); | 
					
						
							|  |  |  |     LoadFromEA(ea, BYTE_SIZE, 0); | 
					
						
							|  |  |  |     e("test dl, dl\n");     /* test... */ | 
					
						
							|  |  |  |     e("lahf\n"); | 
					
						
							|  |  |  |     e("xor  al, al\n"); | 
					
						
							|  |  |  |     e("or   dl, 0x80\n");   /* ...and set bit 7 */ | 
					
						
							|  |  |  |     if ((ea >> 3) == 0) | 
					
						
							|  |  |  |     {         | 
					
						
							|  |  |  |         e("mov  [d+edi*4], dl\n"); | 
					
						
							|  |  |  |         EmitTiming(4); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * NOTE: | 
					
						
							|  |  |  |  * ----- | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * You may wish to uncomment the WriteByte() below when emulating the Sega | 
					
						
							|  |  |  |  * Genesis if you wish to get Gargoyles running. The TAS instruction is used | 
					
						
							|  |  |  |  * to synchronize multiple 68Ks by grabbing the bus, but on the Genesis, the | 
					
						
							|  |  |  |  * VDP will not release the bus resulting in data not being written. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         WriteByte(); | 
					
						
							|  |  |  |         EmitTiming(14 + TimingEA(ea, BYTE_SIZE)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     InstEnd(); | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  | }     | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int NBCD(unsigned short op, char *mnem, unsigned base_timing) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     unsigned    ea = op & 0x3f, t; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |      * Notes About Undefined Flags: | 
					
						
							|  |  |  |      * ---------------------------- | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * N flag = Set the same as the MSB of the result | 
					
						
							|  |  |  |      * V flag = If MSB changes from 1 to 0 when result is adjusted for BCD, | 
					
						
							|  |  |  |      *          the V flag is set, otherwise it is cleared. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!CheckEA(ea, "101111111000"))   return 0; | 
					
						
							|  |  |  |     if (!NumDecodedEA(ea))              return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     InstBegin(op, mnem, NumDecodedEA(ea)); | 
					
						
							|  |  |  |     if ((ea >> 3) == 0) /* Dn */ | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         e("and  edi, byte 7\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         e("xor  al, al\n");         /* we use AL so we can use DAS */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         e("shr  byte [x], 1\n");    /* X->CF */ | 
					
						
							|  |  |  |         e("sbb  al, [d+edi*4]\n"); | 
					
						
							|  |  |  |         e("mov  bh, al\n");         /* save unadjusted result in BH */ | 
					
						
							|  |  |  |         e("das\n");                 /* BCD! */ | 
					
						
							|  |  |  |         e("mov  bl, ah\n");         /* store old flags */ | 
					
						
							|  |  |  |         e("lahf\n"); | 
					
						
							|  |  |  |         e("setc byte [x]\n"); | 
					
						
							|  |  |  |         e("jnz  short .clr\n");     /* Z clear */ | 
					
						
							|  |  |  |         e("and  bl, byte 0x40\n");  /* isolate old Z */ | 
					
						
							|  |  |  |         e("and  ah, byte 0x3f\n");  /* kill new Z */ | 
					
						
							|  |  |  |         e("or   ah, bl\n");         /* in w/ old Z */ | 
					
						
							|  |  |  |         EmitLabel(".clr"); | 
					
						
							|  |  |  |         e("test al, al\n");         /* N flag */ | 
					
						
							|  |  |  |         e("sets dh\n"); | 
					
						
							|  |  |  |         e("ror  dh, 1\n");          /* into MSB of DH */ | 
					
						
							|  |  |  |         e("or   ah, dh\n");         /* -> N flag */ | 
					
						
							|  |  |  |         e("mov  [d+edi*4], al\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /*
 | 
					
						
							|  |  |  |          * V flag calculation: Put unadjusted result's MSB into bit 1, and the | 
					
						
							|  |  |  |          * adjusted result's MSB into bit 0. If the result is 2, the V flag | 
					
						
							|  |  |  |          * is set. | 
					
						
							|  |  |  |          */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         e("shr  bh, byte 6\n"); | 
					
						
							|  |  |  |         e("shr  al, byte 7\n"); | 
					
						
							|  |  |  |         e("and  bh, 2\n"); | 
					
						
							|  |  |  |         e("or   bh, al\n"); | 
					
						
							|  |  |  |         e("xor  al, al\n"); | 
					
						
							|  |  |  |         e("cmp  bh, 2\n"); | 
					
						
							|  |  |  |         e("jne  short .no_v\n"); | 
					
						
							|  |  |  |         e("mov  al, 1\n");  /* move 1 into V flag */ | 
					
						
							|  |  |  |         EmitLabel(".no_v"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         t = 6; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else                /* memory */ | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         LoadFromEA(ea, BYTE_SIZE, 0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         e("xor  al, al\n"); | 
					
						
							|  |  |  |         e("shr  byte [x], 1\n");    /* X->CF */ | 
					
						
							|  |  |  |         e("sbb  al, dl\n"); | 
					
						
							|  |  |  |         e("mov  dh, al\n");         /* DH now has unadjusted result */ | 
					
						
							|  |  |  |         e("mov  dl, ah\n"); | 
					
						
							|  |  |  |         e("das\n");                 /* BCD! */ | 
					
						
							|  |  |  |         e("lahf\n");       | 
					
						
							|  |  |  |         e("setc byte [x]\n"); | 
					
						
							|  |  |  |         e("jnz  short .clr\n"); | 
					
						
							|  |  |  |         e("and  dl, byte 0x40\n"); | 
					
						
							|  |  |  |         e("and  ah, byte 0x3f\n"); | 
					
						
							|  |  |  |         e("or   ah, dl\n"); | 
					
						
							|  |  |  |         EmitLabel(".clr"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         e("test al, al\n");         /* N flag */ | 
					
						
							|  |  |  |         e("sets dl\n"); | 
					
						
							|  |  |  |         e("ror  dl, 1\n");          /* into MSB of DL */ | 
					
						
							|  |  |  |         e("or   ah, dl\n");         /* -> N flag */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         e("mov  dl, al\n");         /* move result into DL to write it */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /*
 | 
					
						
							|  |  |  |          * V flag calculation: Put unadjusted result's MSB into bit 1, and the | 
					
						
							|  |  |  |          * adjusted result's MSB into bit 0. If the result is 2, the V flag | 
					
						
							|  |  |  |          * is set. | 
					
						
							|  |  |  |          */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         e("shr  dh, byte 6\n"); | 
					
						
							|  |  |  |         e("shr  al, byte 7\n"); | 
					
						
							|  |  |  |         e("and  dh, 2\n"); | 
					
						
							|  |  |  |         e("or   dh, al\n"); | 
					
						
							|  |  |  |         e("xor  al, al\n"); | 
					
						
							|  |  |  |         e("cmp  dh, 2\n"); | 
					
						
							|  |  |  |         e("jne  short .no_v\n"); | 
					
						
							|  |  |  |         e("mov  al, 1\n");  /* move 1 into V flag */ | 
					
						
							|  |  |  |         EmitLabel(".no_v"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /* WriteXXX will clear EDI for us */ | 
					
						
							|  |  |  |         WriteByte(); | 
					
						
							|  |  |  |         t = 8 + TimingEA(ea, BYTE_SIZE); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     EmitTiming(t); | 
					
						
							|  |  |  |     InstEnd(); | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int CHK(unsigned short op, char *mnem, unsigned base_timing) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     unsigned    reg = (op >> 9) & 7, size, ea = op & 0x3f; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |      * Notes About Undefined Flags: | 
					
						
							|  |  |  |      * ---------------------------- | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * Z flag = Set if register operand is 0 (second operand), cleared | 
					
						
							|  |  |  |      *          otherwise | 
					
						
							|  |  |  |      * V flag = Always cleared (?) | 
					
						
							|  |  |  |      * C flag = Always cleared (?) | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!CheckEA(ea, "101111111111"))   return 0; | 
					
						
							|  |  |  |     if (!NumDecodedEA(ea))              return 0; | 
					
						
							|  |  |  |     switch ((op >> 7) & 3) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |     case 3: size = WORD_SIZE; break; | 
					
						
							|  |  |  |     default:    return 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     InstBegin(op, mnem, NumDecodedEA(ea)); | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |      * We have to emit the EA timing first because it must be accounted for | 
					
						
							|  |  |  |      * whether or not a trap occurs. DIVU and DIVS work like this too. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     if (TimingEA(ea, size)) | 
					
						
							|  |  |  |         e("sub     ecx, byte %d\n", TimingEA(ea, size)); | 
					
						
							|  |  |  |     LoadFromEA(ea, size, 0); | 
					
						
							|  |  |  |     e("xor  al, al\n");                     /* V should be cleared */ | 
					
						
							|  |  |  |     e("test word [d+%d*4], 0xffff\n", reg); /* If Dn == 0 Then Z=1 */ | 
					
						
							|  |  |  |     e("setz ah\n");                         /* this also clears N and C */ | 
					
						
							|  |  |  |     e("shl  ah, 6\n");                      /* put Z in proper position */ | 
					
						
							|  |  |  |     e("test byte [d+%d*4+1], 0x80\n", reg); /* If Dn < 0 Then TRAP */ | 
					
						
							|  |  |  |     e("jnz  near .trap_dn\n"); | 
					
						
							|  |  |  |     e("cmp  [d+%d*4], dx\n", reg);          /* If Dn > Source Then TRAP */ | 
					
						
							|  |  |  |     e("jg   near .trap_ea\n"); | 
					
						
							|  |  |  |     EmitTiming(base_timing); | 
					
						
							|  |  |  |     InstEnd(); | 
					
						
							|  |  |  |     EmitLabel(".trap_dn");  /* set N to 1 because Dn<0 test failed */ | 
					
						
							|  |  |  |     e("or   ah, 0x80\n"); | 
					
						
							|  |  |  |     e("jmp  short .trap\n"); | 
					
						
							|  |  |  |     EmitLabel(".trap_ea");  /* clear N because Dn>Source test failed */ | 
					
						
							|  |  |  |     e("and  ah, 0x7f\n"); | 
					
						
							|  |  |  |     EmitLabel(".trap"); | 
					
						
							|  |  |  |     e("jmp  near exception_chk\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int MOVEP(unsigned short op, char *mnem, unsigned base_timing) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     unsigned    dx = (op >> 9) & 7, opmode = (op >> 6) & 7, t; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (opmode != 4 && opmode != 5 && opmode != 6 && opmode != 7)   return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     InstBegin(op, mnem, 8); | 
					
						
							|  |  |  |     e("and      edi, byte 7\n"); | 
					
						
							|  |  |  |     e("movsx    ebx, word [esi]\n");    /* (d16,An) */ | 
					
						
							|  |  |  |     e("add      ebx, [a+edi*4]\n"); | 
					
						
							|  |  |  |     e("add      esi, byte 2\n"); | 
					
						
							|  |  |  |     switch (opmode & 2) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |     case 2: /* reg->mem */ | 
					
						
							|  |  |  |         if (opmode & 1) /* long */ | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             t = 24; | 
					
						
							|  |  |  |             e("push eax\n");        /* we will be using EAX to save EBX */ | 
					
						
							|  |  |  |             e("mov      edx, [d+%d*4]\n", dx); | 
					
						
							|  |  |  |             e("mov      eax, ebx\n");   /* save EBX */ | 
					
						
							|  |  |  |             e("rol      edx, byte 8\n");/* write high order */ | 
					
						
							|  |  |  |             WriteByte();                 | 
					
						
							|  |  |  |             e("add      eax, byte 2\n"); | 
					
						
							|  |  |  |             e("rol      edx, byte 8\n");/* write mid-upper */ | 
					
						
							|  |  |  |             e("mov      ebx, eax\n"); | 
					
						
							|  |  |  |             WriteByte(); | 
					
						
							|  |  |  |             e("add      eax, byte 2\n"); | 
					
						
							|  |  |  |             e("rol      edx, byte 8\n");/* write mid-lower */ | 
					
						
							|  |  |  |             e("mov      ebx, eax\n"); | 
					
						
							|  |  |  |             WriteByte(); | 
					
						
							|  |  |  |             e("add      eax, byte 2\n"); | 
					
						
							|  |  |  |             e("rol      edx, byte 8\n");/* write lower order */ | 
					
						
							|  |  |  |             e("mov      ebx, eax\n"); | 
					
						
							|  |  |  |             WriteByte(); | 
					
						
							|  |  |  |             e("pop  eax\n"); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else            /* word */ | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             t = 16; | 
					
						
							|  |  |  |             e("push eax\n");    /* we will be using EAX to save EBX */ | 
					
						
							|  |  |  |             e("mov      dx, [d+%d*4]\n", dx); | 
					
						
							|  |  |  |             e("mov      eax, ebx\n");   /* save EBX */ | 
					
						
							|  |  |  |             e("ror      edx, byte 8\n");/* write high order */ | 
					
						
							|  |  |  |             WriteByte();                 | 
					
						
							|  |  |  |             e("add      eax, byte 2\n"); | 
					
						
							|  |  |  |             e("rol      edx, byte 8\n");/* write low order */ | 
					
						
							|  |  |  |             e("mov      ebx, eax\n"); | 
					
						
							|  |  |  |             WriteByte(); | 
					
						
							|  |  |  |             e("pop  eax\n"); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case 0: /* mem->reg */ | 
					
						
							|  |  |  |         if (opmode & 1) /* long */ | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             t = 24; | 
					
						
							|  |  |  |             ReadByte(); /* read high order */ | 
					
						
							|  |  |  |             e("mov  [d+%d*4+3], dl\n", dx);     /* store high order in Dn */ | 
					
						
							|  |  |  |             e("add  ebx, byte 2\n"); | 
					
						
							|  |  |  |             ReadByte(); /* mid-upper order */ | 
					
						
							|  |  |  |             e("mov  [d+%d*4+2], dl\n", dx);     /* store mid-upper order */ | 
					
						
							|  |  |  |             e("add  ebx, byte 2\n"); | 
					
						
							|  |  |  |             ReadByte(); /* mid-lower order */ | 
					
						
							|  |  |  |             e("mov  [d+%d*4+1], dl\n", dx);     /* store mid-lower order */ | 
					
						
							|  |  |  |             e("add  ebx, byte 2\n"); | 
					
						
							|  |  |  |             ReadByte(); /* low order */ | 
					
						
							|  |  |  |             e("mov  [d+%d*4+0], dl\n", dx);     /* store low order */ | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else            /* word */ | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             t = 16; | 
					
						
							|  |  |  |             ReadByte(); /* read high order */ | 
					
						
							|  |  |  |             e("mov  [d+%d*4+1], dl\n", dx);     /* store high order in Dn */ | 
					
						
							|  |  |  |             e("add  ebx, byte 2\n"); | 
					
						
							|  |  |  |             ReadByte(); /* read low order */ | 
					
						
							|  |  |  |             e("mov  [d+%d*4+0], dl\n", dx);     /* store low order */ | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     EmitTiming(t); | 
					
						
							|  |  |  |     InstEnd(); | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int CMPM(unsigned short op, char *mnem, unsigned base_timing) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     unsigned    size, ax = (op >> 9) & 7; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     switch ((op >> 6) & 3) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |     case 0: size = BYTE_SIZE; break; | 
					
						
							|  |  |  |     case 1: size = WORD_SIZE; break; | 
					
						
							|  |  |  |     case 2: size = LONG_SIZE; break; | 
					
						
							|  |  |  |     default:    return 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     InstBegin(op, mnem, 8); | 
					
						
							|  |  |  |     e("and  edi, byte 7\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     e("mov  ebx, [a+edi*4]\n");   /* get Ay */ | 
					
						
							|  |  |  |     if (size == BYTE_SIZE)  /* Ay */ | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         e("cmp  edi, byte 7\n");    /* A7 bytes */ | 
					
						
							|  |  |  |         e("cmc\n");                 /* switch carry */ | 
					
						
							|  |  |  |         e("adc  dword [a+edi*4], byte 1\n"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else if (size == WORD_SIZE) | 
					
						
							|  |  |  |         e("add  dword [a+edi*4], byte 2\n"); | 
					
						
							|  |  |  |     else if (size == LONG_SIZE) | 
					
						
							|  |  |  |         e("add  dword [a+edi*4], byte 4\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     switch (size) | 
					
						
							|  |  |  |     {   case BYTE_SIZE: ReadByte(); break; | 
					
						
							|  |  |  |         case WORD_SIZE: ReadWord(); break; | 
					
						
							|  |  |  |         case LONG_SIZE: ReadLong(); break;  } | 
					
						
							|  |  |  |     SaveReg("run", "edx");      /* save Ay */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     e("mov  ebx, [a+%d*4]\n", ax);/* get Ax */ | 
					
						
							|  |  |  |     if (size == BYTE_SIZE)  /* Ax */ | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if (ax == 7) | 
					
						
							|  |  |  |             e("add  dword [a+7*4], byte 2\n"); | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |             e("inc  dword [a+%d*4]\n", ax); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else if (size == WORD_SIZE) | 
					
						
							|  |  |  |         e("add  dword [a+%d*4], byte 2\n", ax); | 
					
						
							|  |  |  |     else    /* LONG */ | 
					
						
							|  |  |  |         e("add  dword [a+%d*4], byte 4\n", ax); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     switch (size) | 
					
						
							|  |  |  |     {   case BYTE_SIZE: ReadByte(); break; | 
					
						
							|  |  |  |         case WORD_SIZE: ReadWord(); break; | 
					
						
							|  |  |  |         case LONG_SIZE: ReadLong(); break;  } | 
					
						
							|  |  |  |     switch (size)                   /* compare */ | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |     case BYTE_SIZE: | 
					
						
							|  |  |  |         RestoreRegTo("run", "edx", "bl");   /* [run_edx]->bl */ | 
					
						
							|  |  |  |         e("cmp  dl, bl\n"); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case WORD_SIZE: | 
					
						
							|  |  |  |         RestoreRegTo("run", "edx", "ebx");  /* [run_edx]->ebx */ | 
					
						
							|  |  |  |         e("cmp  dx, bx\n"); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case LONG_SIZE: | 
					
						
							|  |  |  |         RestoreRegTo("run", "edx", "ebx");  /* [run_edx]->ebx */ | 
					
						
							|  |  |  |         e("cmp  edx, ebx\n"); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     e("lahf\n"); | 
					
						
							|  |  |  |     e("seto al\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (size != LONG_SIZE)  /* byte, word */ | 
					
						
							|  |  |  |         EmitTiming(12); | 
					
						
							|  |  |  |     else                    /* long */ | 
					
						
							|  |  |  |         EmitTiming(20); | 
					
						
							|  |  |  |     InstEnd(); | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int TRAP(unsigned short op, char *mnem, unsigned base_timing) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     InstBegin(op, mnem, 16); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     e("and  edi, byte 0xf\n");          /* lower 4 bits=vector */ | 
					
						
							|  |  |  |     SaveReg("run", "edi"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     e("mov  edx, 0x2000\n");            /* what the SR will be */ | 
					
						
							|  |  |  |     e("xor  edx, [sr]\n");              /* see if S bit is different */ | 
					
						
							|  |  |  |     e("test edx, 0x2000\n"); | 
					
						
							|  |  |  |     e("jz   .no_sp_magic\n");           /* nope, don't swap SPs */ | 
					
						
							|  |  |  |     e("mov  edx, [__sp]\n"); | 
					
						
							|  |  |  |     e("xchg [a+7*4], edx\n"); | 
					
						
							|  |  |  |     e("mov  [__sp], edx\n"); | 
					
						
							|  |  |  |     SetSupervisorAddressSpace(); | 
					
						
							|  |  |  |     EmitLabel(".no_sp_magic"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     e("mov  ebx, [a+7*4]\n");           /* SP */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |      * If 68010, push format info | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (mpu == 68010) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         e("sub  ebx, byte 2\n");/* SP-2 */ | 
					
						
							|  |  |  |         RestoreReg("run", "edi");   /* vector */ | 
					
						
							|  |  |  |         e("mov  edx, edi\n"); | 
					
						
							|  |  |  |         SaveReg("run", "edi"); | 
					
						
							|  |  |  |         e("add  edx, byte 32\n"); | 
					
						
							|  |  |  |         e("shl  edx, byte 2\n");    /* TRAP vector | 0x00000000 */ | 
					
						
							|  |  |  |         SaveReg("run", "ebx"); | 
					
						
							|  |  |  |         WriteWord(); | 
					
						
							|  |  |  |         RestoreReg("run", "ebx"); | 
					
						
							|  |  |  |     }         | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     e("mov  edx, esi\n"); | 
					
						
							|  |  |  |     e("sub  edx, ebp\n");               /* PC->EDX */ | 
					
						
							|  |  |  |     e("sub  ebx, byte 4\n");            /* SP-4 */ | 
					
						
							|  |  |  |     e("push ebx\n"); | 
					
						
							|  |  |  |     WriteLong(); | 
					
						
							|  |  |  |     e("pop  ebx\n"); | 
					
						
							|  |  |  |     e("mov  edx, [sr]\n");              /* get SR */ | 
					
						
							|  |  |  |     e("sub  ebx, byte 2\n");            /* SP-2 */ | 
					
						
							|  |  |  |     e("push ebx\n"); | 
					
						
							|  |  |  |     SaveReg("run", "ebx"); | 
					
						
							|  |  |  |     WriteWord();                        /* save SR to stack */ | 
					
						
							|  |  |  |     e("pop  ebx\n"); | 
					
						
							|  |  |  |     e("or   dh, 0x20\n");               /* set supervisor for exception */ | 
					
						
							|  |  |  |     e("and  edx, 0xa71f\n");            /* clear unwanted bits */ | 
					
						
							|  |  |  |     e("xchg [sr], edx\n");              /* set new SR, get old SR->EDX */ | 
					
						
							|  |  |  |     e("mov  [a+7*4], ebx\n");           /* write back SP */ | 
					
						
							|  |  |  |     RestoreReg("run", "edi"); | 
					
						
							|  |  |  |     e("mov  ebx, edi\n"); | 
					
						
							|  |  |  |     e("add  ebx, byte 32\n");           /* vector+32=trap vector */ | 
					
						
							|  |  |  |     e("shl  ebx, 2\n"); | 
					
						
							|  |  |  |     if (mpu == 68010) | 
					
						
							|  |  |  |         e("add  ebx, [vbr]\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     ReadLong();                         /* get PC */ | 
					
						
							|  |  |  |     e("mov  esi, edx\n");               /* set new PC */ | 
					
						
							|  |  |  |     UpdateFetchPtr(); | 
					
						
							|  |  |  |     e("xor  edi, edi\n"); | 
					
						
							|  |  |  |     EmitTiming(base_timing); | 
					
						
							|  |  |  |     InstEnd(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int EORItoSR(unsigned short op, char *mnem, unsigned base_timing) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     InstBegin(op, mnem, 1); | 
					
						
							|  |  |  |     e("test byte [sr+1], 0x20\n");      /* in supervisor? */ | 
					
						
							|  |  |  |     e("jz   near exception_privilege_violation\n"); | 
					
						
							|  |  |  |     SaveCCR();  /* save flags to SR */ | 
					
						
							|  |  |  |     e("mov  edx, [esi]\n"); | 
					
						
							|  |  |  |     e("and  edx, 0xa71f\n");            /* mask out unwanted bits */ | 
					
						
							|  |  |  |     e("xor  [sr], dx\n"); | 
					
						
							|  |  |  |     e("add  esi, byte 2\n"); | 
					
						
							|  |  |  |     LoadCCR();  /* get flags back */ | 
					
						
							|  |  |  |     e("test byte [sr+1], 0x20\n");      /* if we changed to User, swap SPs */ | 
					
						
							|  |  |  |     e("jnz  short .in_s\n"); | 
					
						
							|  |  |  |     e("mov  ebx, [a+7*4]\n"); | 
					
						
							|  |  |  |     e("mov  edx, [__sp]\n"); | 
					
						
							|  |  |  |     e("mov  [a+7*4], edx\n"); | 
					
						
							|  |  |  |     e("mov  [__sp], ebx\n"); | 
					
						
							|  |  |  |     SetUserAddressSpace();              /* map in user address space */ | 
					
						
							|  |  |  |     EmitLabel(".in_s");     | 
					
						
							|  |  |  |     EmitTiming(base_timing); | 
					
						
							|  |  |  |     InstEnd(); | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int EORItoCCR(unsigned short op, char *mnem, unsigned base_timing) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     InstBegin(op, mnem, 1); | 
					
						
							|  |  |  |     SaveCCR(); | 
					
						
							|  |  |  |     e("mov  dl, [esi]\n"); | 
					
						
							|  |  |  |     e("and  dl, 0x1f\n"); | 
					
						
							|  |  |  |     e("xor  [sr], dl\n"); | 
					
						
							|  |  |  |     LoadCCR(); | 
					
						
							|  |  |  |     e("add  esi, byte 2\n"); | 
					
						
							|  |  |  |     EmitTiming(base_timing); | 
					
						
							|  |  |  |     InstEnd(); | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int RTR(unsigned short op, char *mnem, unsigned base_timing) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     InstBegin(op, mnem, 1); | 
					
						
							|  |  |  |     e("mov  ebx, [a+7*4]\n");             /* (SP)->CCR */ | 
					
						
							|  |  |  |     ReadWord(); | 
					
						
							|  |  |  |     e("and  dl, 0x1f\n"); | 
					
						
							|  |  |  |     e("mov  [sr], dl\n"); | 
					
						
							|  |  |  |     e("add  dword [a+7*4], byte 2\n");    /* SP+2->SP */ | 
					
						
							|  |  |  |     LoadCCR(); | 
					
						
							|  |  |  |     e("mov  ebx, [a+7*4]\n");             /* (SP)->PC */ | 
					
						
							|  |  |  |     ReadLong(); | 
					
						
							|  |  |  |     e("add  dword [a+7*4], byte 4\n");    /* SP+4->SP */ | 
					
						
							|  |  |  |     e("mov  esi, edx\n"); | 
					
						
							|  |  |  |     UpdateFetchPtr(); | 
					
						
							|  |  |  |     EmitTiming(base_timing); | 
					
						
							|  |  |  |     InstEnd(); | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int SUBX(unsigned short op, char *mnem, unsigned base_timing) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     unsigned    rx = (op >> 9) & 7, rm = (op >> 3) & 1, size; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     switch ((op >> 6) & 3) | 
					
						
							|  |  |  |     {   case 0: size = BYTE_SIZE; break; | 
					
						
							|  |  |  |         case 1: size = WORD_SIZE; break; | 
					
						
							|  |  |  |         case 2: size = LONG_SIZE; break; | 
					
						
							|  |  |  |         default: return 0;  } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     InstBegin(op, mnem, 8); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     e("and  edi, byte 7\n"); | 
					
						
							|  |  |  |     if (!rm)    /* Dy,Dx */ | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if (size == BYTE_SIZE)          /* EBX,BX,BL=destination */ | 
					
						
							|  |  |  |             e("mov  bl, [d+%d*4]\n", rx); | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |             e("mov  ebx, [d+%d*4]\n", rx); | 
					
						
							|  |  |  |         if (size == BYTE_SIZE)          /* EDX,DX,DL=source */ | 
					
						
							|  |  |  |             e("mov  dl, [d+edi*4]\n"); | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |             e("mov  edx, [d+edi*4]\n"); | 
					
						
							|  |  |  |         e("shr  byte [x], 1\n");      /* X->CF */ | 
					
						
							|  |  |  |         switch (size) | 
					
						
							|  |  |  |         {   case BYTE_SIZE: e("sbb  bl, dl\n"); break; | 
					
						
							|  |  |  |             case WORD_SIZE: e("sbb  bx, dx\n"); break; | 
					
						
							|  |  |  |             case LONG_SIZE: e("sbb  ebx, edx\n"); break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         e("mov  dl, ah\n"); /* keep temporary copy of old flags in DL */ | 
					
						
							|  |  |  |         e("lahf\n"); | 
					
						
							|  |  |  |         e("setc byte [x]\n"); | 
					
						
							|  |  |  |         e("seto al\n"); | 
					
						
							|  |  |  |         e("jnz  short .z\n");           /* if non-zero, cleared */ | 
					
						
							|  |  |  |         e("and  dl, 0x40\n");           /* otherwise, unchanged */ | 
					
						
							|  |  |  |         e("and  ah, 0xbf\n");           /* (get rid of new unwanted Z) */ | 
					
						
							|  |  |  |         e("or   ah, dl\n");             /* OR in the old, unchanged Z flag */ | 
					
						
							|  |  |  |         EmitLabel(".z");         | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         switch (size)   /* store results */ | 
					
						
							|  |  |  |         {   case BYTE_SIZE: e("mov  [d+%d*4], bl\n", rx); break; | 
					
						
							|  |  |  |             case WORD_SIZE: e("mov  [d+%d*4], bx\n", rx); break; | 
					
						
							|  |  |  |             case LONG_SIZE: e("mov  [d+%d*4], ebx\n", rx); break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else        /* -(Ay),-(Ax) */ | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if (size == BYTE_SIZE) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             e("cmp  edi, byte 7\n");    /* decrement Ay register (-2 for A7) */ | 
					
						
							|  |  |  |             e("cmc\n"); | 
					
						
							|  |  |  |             e("sbb  dword [a+edi*4], byte 1\n"); | 
					
						
							|  |  |  |             if (rx != 7) | 
					
						
							|  |  |  |                 e("dec  dword [a+%d*4]\n", rx); | 
					
						
							|  |  |  |             else | 
					
						
							|  |  |  |                 e("sub  dword [a+7*4], byte 2\n"); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else if (size == WORD_SIZE) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             e("sub  dword [a+edi*4], byte 2\n"); | 
					
						
							|  |  |  |             e("sub  dword [a+%d*4], byte 2\n", rx); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else if (size == LONG_SIZE) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             e("sub  dword [a+edi*4], byte 4\n"); | 
					
						
							|  |  |  |             e("sub  dword [a+%d*4], byte 4\n", rx); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         e("mov  ebx, [a+edi*4]\n");   /* first, load up -(Ay) */ | 
					
						
							|  |  |  |         switch (size) | 
					
						
							|  |  |  |         {   case BYTE_SIZE: ReadByte(); break; | 
					
						
							|  |  |  |             case WORD_SIZE: ReadWord(); break; | 
					
						
							|  |  |  |             case LONG_SIZE: ReadLong(); break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         SaveReg("run", "edx");          /* save data obtained */ | 
					
						
							|  |  |  |         e("mov  ebx, [a+%d*4]\n", rx);/* next, load up -(Ax) */ | 
					
						
							|  |  |  |         switch (size) | 
					
						
							|  |  |  |         {   case BYTE_SIZE: ReadByte(); break; | 
					
						
							|  |  |  |             case WORD_SIZE: ReadWord(); break; | 
					
						
							|  |  |  |             case LONG_SIZE: ReadLong(); break; | 
					
						
							|  |  |  |         }        | 
					
						
							|  |  |  |         SaveReg("run", "ebx"); | 
					
						
							|  |  |  |         e("mov  ebx, edx\n");       /* EBX,BX,BL=destination */ | 
					
						
							|  |  |  |         RestoreReg("run", "edx");   /* EDX,DX,DL=source */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         e("shr  byte [x], 1\n");      /* X->CF */ | 
					
						
							|  |  |  |         switch (size) | 
					
						
							|  |  |  |         {   case BYTE_SIZE: e("sbb  bl, dl\n"); break; | 
					
						
							|  |  |  |             case WORD_SIZE: e("sbb  bx, dx\n"); break; | 
					
						
							|  |  |  |             case LONG_SIZE: e("sbb  ebx, edx\n"); break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         e("mov  dl, ah\n"); /* keep temporary copy of old flags in DL */ | 
					
						
							|  |  |  |         e("lahf\n"); | 
					
						
							|  |  |  |         e("setc byte [x]\n"); | 
					
						
							|  |  |  |         e("seto al\n"); | 
					
						
							|  |  |  |         e("jnz  short .z\n");           /* if non-zero, cleared */ | 
					
						
							|  |  |  |         e("and  dl, 0x40\n");           /* otherwise, unchanged */ | 
					
						
							|  |  |  |         e("and  ah, 0xbf\n");           /* (get rid of new unwanted Z) */ | 
					
						
							|  |  |  |         e("or   ah, dl\n");             /* OR in the old, unchanged Z flag */ | 
					
						
							|  |  |  |         EmitLabel(".z");        | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         e("mov  edx, ebx\n");   /* store result */ | 
					
						
							|  |  |  |         RestoreReg("run", "ebx"); | 
					
						
							|  |  |  |         switch (size) | 
					
						
							|  |  |  |         {   case BYTE_SIZE: WriteByte(); break; | 
					
						
							|  |  |  |             case WORD_SIZE: WriteWord(); break; | 
					
						
							|  |  |  |             case LONG_SIZE: WriteLong(); break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |     if (!rm) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if (size == LONG_SIZE) | 
					
						
							|  |  |  |             EmitTiming(8); | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |             EmitTiming(4); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if (size == LONG_SIZE) | 
					
						
							|  |  |  |             EmitTiming(30); | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |             EmitTiming(18); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     InstEnd(); | 
					
						
							|  |  |  |     return 1;   | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int ADDX(unsigned short op, char *mnem, unsigned base_timing) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     unsigned    rx = (op >> 9) & 7, rm = (op >> 3) & 1, size; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     switch ((op >> 6) & 3) | 
					
						
							|  |  |  |     {   case 0: size = BYTE_SIZE; break; | 
					
						
							|  |  |  |         case 1: size = WORD_SIZE; break; | 
					
						
							|  |  |  |         case 2: size = LONG_SIZE; break; | 
					
						
							|  |  |  |         default: return 0;  } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     InstBegin(op, mnem, 8); | 
					
						
							|  |  |  |     e("and  edi, byte 7\n"); | 
					
						
							|  |  |  |     if (!rm)    /* Dy,Dx */ | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if (size == BYTE_SIZE)          /* EBX,BX,BL=destination */ | 
					
						
							|  |  |  |             e("mov  bl, [d+%d*4]\n", rx); | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |             e("mov  ebx, [d+%d*4]\n", rx); | 
					
						
							|  |  |  |         if (size == BYTE_SIZE)          /* EDX,DX,DL=source */ | 
					
						
							|  |  |  |             e("mov  dl, [d+edi*4]\n"); | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |             e("mov  edx, [d+edi*4]\n"); | 
					
						
							|  |  |  |         e("shr  byte [x], 1\n");      /* X->CF */ | 
					
						
							|  |  |  |         switch (size) | 
					
						
							|  |  |  |         {   case BYTE_SIZE: e("adc  bl, dl\n"); break; | 
					
						
							|  |  |  |             case WORD_SIZE: e("adc  bx, dx\n"); break; | 
					
						
							|  |  |  |             case LONG_SIZE: e("adc  ebx, edx\n"); break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         e("mov  dl, ah\n"); /* keep temporary copy of old flags in DL */ | 
					
						
							|  |  |  |         e("lahf\n"); | 
					
						
							|  |  |  |         e("setc byte [x]\n"); | 
					
						
							|  |  |  |         e("seto al\n"); | 
					
						
							|  |  |  |         e("jnz  short .z\n");           /* if non-zero, cleared */ | 
					
						
							|  |  |  |         e("and  dl, 0x40\n");           /* otherwise, unchanged */ | 
					
						
							|  |  |  |         e("and  ah, 0xbf\n");           /* (get rid of new unwanted Z) */ | 
					
						
							|  |  |  |         e("or   ah, dl\n");             /* OR in the old, unchanged Z flag */ | 
					
						
							|  |  |  |         EmitLabel(".z");         | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         switch (size)   /* store results */ | 
					
						
							|  |  |  |         {   case BYTE_SIZE: e("mov  [d+%d*4], bl\n", rx); break; | 
					
						
							|  |  |  |             case WORD_SIZE: e("mov  [d+%d*4], bx\n", rx); break; | 
					
						
							|  |  |  |             case LONG_SIZE: e("mov  [d+%d*4], ebx\n", rx); break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else        /* -(Ay),-(Ax) */ | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if (size == BYTE_SIZE) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             e("cmp  edi, byte 7\n");    /* decrement Ay register (-2 for A7) */ | 
					
						
							|  |  |  |             e("cmc\n"); | 
					
						
							|  |  |  |             e("sbb  dword [a+edi*4], byte 1\n"); | 
					
						
							|  |  |  |             if (rx != 7) | 
					
						
							|  |  |  |                 e("dec  dword [a+%d*4]\n", rx); | 
					
						
							|  |  |  |             else | 
					
						
							|  |  |  |                 e("sub  dword [a+7*4], byte 2\n"); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else if (size == WORD_SIZE) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             e("sub  dword [a+edi*4], byte 2\n"); | 
					
						
							|  |  |  |             e("sub  dword [a+%d*4], byte 2\n", rx); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else if (size == LONG_SIZE) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             e("sub  dword [a+edi*4], byte 4\n"); | 
					
						
							|  |  |  |             e("sub  dword [a+%d*4], byte 4\n", rx); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         e("mov  ebx, [a+edi*4]\n");   /* first, load up -(Ay) */ | 
					
						
							|  |  |  |         switch (size) | 
					
						
							|  |  |  |         {   case BYTE_SIZE: ReadByte(); break; | 
					
						
							|  |  |  |             case WORD_SIZE: ReadWord(); break; | 
					
						
							|  |  |  |             case LONG_SIZE: ReadLong(); break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         SaveReg("run", "edx");  /* save data obtained */ | 
					
						
							|  |  |  |         e("mov  ebx, [a+%d*4]\n", rx);/* next, load up -(Ax) */ | 
					
						
							|  |  |  |         switch (size) | 
					
						
							|  |  |  |         {   case BYTE_SIZE: ReadByte(); break; | 
					
						
							|  |  |  |             case WORD_SIZE: ReadWord(); break; | 
					
						
							|  |  |  |             case LONG_SIZE: ReadLong(); break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         SaveReg("run", "ebx"); | 
					
						
							|  |  |  |         e("mov  ebx, edx\n");       /* EBX,BX,BL=destination */ | 
					
						
							|  |  |  |         RestoreReg("run", "edx");   /* EDX,DX,DL=source */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         e("shr  byte [x], 1\n");      /* X->CF */ | 
					
						
							|  |  |  |         switch (size) | 
					
						
							|  |  |  |         {   case BYTE_SIZE: e("adc  bl, dl\n"); break; | 
					
						
							|  |  |  |             case WORD_SIZE: e("adc  bx, dx\n"); break; | 
					
						
							|  |  |  |             case LONG_SIZE: e("adc  ebx, edx\n"); break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         e("mov  dl, ah\n"); /* keep temporary copy of old flags in DL */ | 
					
						
							|  |  |  |         e("lahf\n"); | 
					
						
							|  |  |  |         e("setc byte [x]\n"); | 
					
						
							|  |  |  |         e("seto al\n"); | 
					
						
							|  |  |  |         e("jnz  short .z\n");           /* if non-zero, cleared */ | 
					
						
							|  |  |  |         e("and  dl, 0x40\n");           /* otherwise, unchanged */ | 
					
						
							|  |  |  |         e("and  ah, 0xbf\n");           /* (get rid of new unwanted Z) */ | 
					
						
							|  |  |  |         e("or   ah, dl\n");             /* OR in the old, unchanged Z flag */ | 
					
						
							|  |  |  |         EmitLabel(".z");        | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         e("mov  edx, ebx\n");   /* store result */ | 
					
						
							|  |  |  |         RestoreReg("run", "ebx"); | 
					
						
							|  |  |  |         switch (size) | 
					
						
							|  |  |  |         {   case BYTE_SIZE: WriteByte(); break; | 
					
						
							|  |  |  |             case WORD_SIZE: WriteWord(); break; | 
					
						
							|  |  |  |             case LONG_SIZE: WriteLong(); break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |     if (!rm) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if (size == LONG_SIZE) | 
					
						
							|  |  |  |             EmitTiming(8); | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |             EmitTiming(4); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if (size == LONG_SIZE) | 
					
						
							|  |  |  |             EmitTiming(30); | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |             EmitTiming(18); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     InstEnd(); | 
					
						
							|  |  |  |     return 1;   | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int SBCD(unsigned short op, char *mnem, unsigned base_timing) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |      * Notes About Undefined Flags: | 
					
						
							|  |  |  |      * ---------------------------- | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * N flag = Set the same as the MSB of the result | 
					
						
							|  |  |  |      * V flag = If MSB changes from 1 to 0 when result is adjusted for BCD, | 
					
						
							|  |  |  |      *          the V flag is set, otherwise it is cleared. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     unsigned    rx = (op >> 9) & 7, rm = (op >> 3) & 1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     InstBegin(op, mnem, 8); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     e("and  edi, byte 7\n"); | 
					
						
							|  |  |  |     if (!rm)    /* Dy,Dx */ | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         e("mov  al, [d+%d*4]\n", rx); /* AL=destination */ | 
					
						
							|  |  |  |         e("mov  bl, [d+edi*4]\n");    /* BL=source */ | 
					
						
							|  |  |  |         e("shr  byte [x], 1\n");  /* X->CF */ | 
					
						
							|  |  |  |         e("sbb  al, bl\n"); /* subtract */ | 
					
						
							|  |  |  |         e("mov  bh, al\n"); /* save the unadjusted result in BH */ | 
					
						
							|  |  |  |         e("das\n");         /* adjust the packed BCD result */ | 
					
						
							|  |  |  |         e("setc dl\n"); | 
					
						
							|  |  |  |         e("setc byte [x]\n"); | 
					
						
							|  |  |  |         e("jz   short .unchanged_z\n"); | 
					
						
							|  |  |  |         e("and  ah, 0xbf\n");   /* cleared if nonzero, otherwise unchanged */ | 
					
						
							|  |  |  |         EmitLabel(".unchanged_z"); | 
					
						
							|  |  |  |         e("and  ah, 0x7e\n"); | 
					
						
							|  |  |  |         e("or   ah, dl\n");     /* set C */ | 
					
						
							|  |  |  |         e("test al, al\n");     /* N flag */ | 
					
						
							|  |  |  |         e("sets dl\n"); | 
					
						
							|  |  |  |         e("ror  dl, 1\n");      /* N flag -> MSB of DL */ | 
					
						
							|  |  |  |         e("or   ah, dl\n");     /* into N flag */ | 
					
						
							|  |  |  |         e("mov  [d+%d*4], al\n", rx); /* store result */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /*
 | 
					
						
							|  |  |  |          * V flag calculation: Put unadjusted result's MSB into bit 1, and the | 
					
						
							|  |  |  |          * adjusted result's MSB into bit 0. If the result is 2, the V flag | 
					
						
							|  |  |  |          * is set. | 
					
						
							|  |  |  |          */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         e("shr  bh, byte 6\n"); | 
					
						
							|  |  |  |         e("shr  al, byte 7\n"); | 
					
						
							|  |  |  |         e("and  bh, 2\n"); | 
					
						
							|  |  |  |         e("or   bh, al\n"); | 
					
						
							|  |  |  |         e("cmp  bh, 2\n"); | 
					
						
							|  |  |  |         e("sete al\n");     /* 1 -> V */ | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else        /* -(Ay),-(Ax) */ | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         e("cmp  edi, byte 7\n");    /* decrement Ay register (-2 for A7) */ | 
					
						
							|  |  |  |         e("cmc\n"); | 
					
						
							|  |  |  |         e("sbb  dword [a+edi*4], byte 1\n"); | 
					
						
							|  |  |  |         if (rx != 7) | 
					
						
							|  |  |  |             e("dec  dword [a+%d*4]\n", rx); | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |             e("sub  dword [a+7*4], byte 2\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         e("mov  ebx, [a+edi*4]\n");   /* first, load up -(Ay) */ | 
					
						
							|  |  |  |         ReadByte(); | 
					
						
							|  |  |  |         SaveReg("run", "dl");       /* save byte obtained */ | 
					
						
							|  |  |  |         e("mov  ebx, [a+%d*4]\n", rx);/* next, load up -(Ax) */ | 
					
						
							|  |  |  |         ReadByte(); | 
					
						
							|  |  |  |         e("mov  al, dl\n");         /* AL=destination */ | 
					
						
							|  |  |  |         RestoreReg("run", "dl");    /* DL=source */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         e("shr  byte [x], 1\n");  /* X->CF */ | 
					
						
							|  |  |  |         e("sbb  al, dl\n"); /* subtract */ | 
					
						
							|  |  |  |         e("mov  dh, al\n"); /* save unadjusted result in DH */ | 
					
						
							|  |  |  |         e("das\n");         /* adjust the packed BCD result */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         e("setc dl\n"); | 
					
						
							|  |  |  |         e("setc byte [x]\n"); | 
					
						
							|  |  |  |         e("jz   short .unchanged_z\n"); | 
					
						
							|  |  |  |         e("and  ah, 0xbf\n");   /* cleared if nonzero, otherwise unchanged */ | 
					
						
							|  |  |  |         EmitLabel(".unchanged_z"); | 
					
						
							|  |  |  |         e("and  ah, 0x7e\n"); | 
					
						
							|  |  |  |         e("or   ah, dl\n");     /* set C */ | 
					
						
							|  |  |  |         e("test al, al\n");     /* N flag */ | 
					
						
							|  |  |  |         e("sets dl\n"); | 
					
						
							|  |  |  |         e("ror  dl, 1\n");      /* N flag -> MSB of DL */ | 
					
						
							|  |  |  |         e("or   ah, dl\n");     /* into N flag */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         e("mov  dl, al\n");     /* prepare to write result */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /*
 | 
					
						
							|  |  |  |          * V flag calculation: Put unadjusted result's MSB into bit 1, and the | 
					
						
							|  |  |  |          * adjusted result's MSB into bit 0. If the result is 2, the V flag | 
					
						
							|  |  |  |          * is set. | 
					
						
							|  |  |  |          */ | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |         e("shr  dh, byte 6\n"); | 
					
						
							|  |  |  |         e("shr  al, byte 7\n"); | 
					
						
							|  |  |  |         e("and  dh, 2\n"); | 
					
						
							|  |  |  |         e("or   dh, al\n"); | 
					
						
							|  |  |  |         e("cmp  dh, 2\n"); | 
					
						
							|  |  |  |         e("sete al\n"); /* 1->V */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         WriteByte(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |     if (!rm) | 
					
						
							|  |  |  |         EmitTiming(6); | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |         EmitTiming(18); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     InstEnd(); | 
					
						
							|  |  |  |     return 1;   | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int ABCD(unsigned short op, char *mnem, unsigned base_timing) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     unsigned    rx = (op >> 9) & 7, rm = (op >> 3) & 1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |      * Notes About Undefined Flags: | 
					
						
							|  |  |  |      * ---------------------------- | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * N flag = Set the same as the MSB of the result | 
					
						
							|  |  |  |      * V flag = If MSB changes from 0 to 1 when result is adjusted for BCD, | 
					
						
							|  |  |  |      *          the V flag is set, otherwise it is cleared. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     InstBegin(op, mnem, 8); | 
					
						
							|  |  |  |     e("and  edi, byte 7\n"); | 
					
						
							|  |  |  |     if (!rm)    /* Dy,Dx */ | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         e("mov  al, [d+%d*4]\n", rx); /* AL=destination */ | 
					
						
							|  |  |  |         e("mov  bl, [d+edi*4]\n");    /* BL=source */ | 
					
						
							|  |  |  |         e("shr  byte [x], 1\n");  /* X->CF */ | 
					
						
							|  |  |  |         e("adc  al, bl\n"); /* add with extend */ | 
					
						
							|  |  |  |         e("mov  bh, al\n"); /* save unadjusted result in BH */ | 
					
						
							|  |  |  |         e("daa\n");         /* adjust the packed BCD result */ | 
					
						
							|  |  |  |         e("setc dl\n"); | 
					
						
							|  |  |  |         e("setc byte [x]\n"); | 
					
						
							|  |  |  |         e("jz   short .unchanged_z\n"); | 
					
						
							|  |  |  |         e("and  ah, 0xbf\n");   /* cleared if nonzero, otherwise unchanged */ | 
					
						
							|  |  |  |         EmitLabel(".unchanged_z");         | 
					
						
							|  |  |  |         e("and  ah, 0x7e\n"); | 
					
						
							|  |  |  |         e("or   ah, dl\n");     /* set C */ | 
					
						
							|  |  |  |         e("test al, al\n");     /* N flag */ | 
					
						
							|  |  |  |         e("sets dl\n"); | 
					
						
							|  |  |  |         e("ror  dl, 1\n");      /* N flag -> MSB of DL */ | 
					
						
							|  |  |  |         e("or   ah, dl\n");     /* into N flag */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         e("mov  [d+%d*4], al\n", rx); /* store result */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /*
 | 
					
						
							|  |  |  |          * V flag calculation: Put unadjusted result's MSB into bit 1, and the | 
					
						
							|  |  |  |          * adjusted result's MSB into bit 0. If the result is 01, the V flag | 
					
						
							|  |  |  |          * is set. | 
					
						
							|  |  |  |          */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         e("shr  bh, byte 6\n"); | 
					
						
							|  |  |  |         e("shr  al, byte 7\n"); | 
					
						
							|  |  |  |         e("and  bh, 2\n"); | 
					
						
							|  |  |  |         e("or   bh, al\n"); | 
					
						
							|  |  |  |         e("cmp  bh, 1\n"); | 
					
						
							|  |  |  |         e("sete al\n");     /* move 1 into V flag */ | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else        /* -(Ay),-(Ax) */ | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         e("cmp  edi, byte 7\n");    /* decrement Ay register (-2 for A7) */ | 
					
						
							|  |  |  |         e("cmc\n"); | 
					
						
							|  |  |  |         e("sbb  dword [a+edi*4], byte 1\n"); | 
					
						
							|  |  |  |         if (rx != 7) | 
					
						
							|  |  |  |             e("dec  dword [a+%d*4]\n", rx); | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |             e("sub  dword [a+7*4], byte 2\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         e("mov  ebx, [a+edi*4]\n");   /* first, load up -(Ay) */ | 
					
						
							|  |  |  |         ReadByte(); | 
					
						
							|  |  |  |         SaveReg("run", "dl");       /* save byte obtained */ | 
					
						
							|  |  |  |         e("mov  ebx, [a+%d*4]\n", rx);/* next, load up -(Ax) */ | 
					
						
							|  |  |  |         ReadByte(); | 
					
						
							|  |  |  |         e("mov  al, dl\n");         /* AL=destination */ | 
					
						
							|  |  |  |         RestoreReg("run", "dl");    /* DL=source */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         e("shr  byte [x], 1\n");  /* X->CF */ | 
					
						
							|  |  |  |         e("adc  al, dl\n"); /* add */ | 
					
						
							|  |  |  |         e("mov  dh, al\n"); /* save unadjusted result in DH */ | 
					
						
							|  |  |  |         e("daa\n");         /* adjust the packed BCD result */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         e("setc dl\n"); | 
					
						
							|  |  |  |         e("setc byte [x]\n"); | 
					
						
							|  |  |  |         e("jz   short .unchanged_z\n"); | 
					
						
							|  |  |  |         e("and  ah, 0xbf\n");   /* cleared if nonzero, otherwise unchanged */ | 
					
						
							|  |  |  |         EmitLabel(".unchanged_z"); | 
					
						
							|  |  |  |         e("and  ah, 0x7e\n"); | 
					
						
							|  |  |  |         e("or   ah, dl\n");     /* set C */ | 
					
						
							|  |  |  |         e("test al, al\n");     /* N flag */ | 
					
						
							|  |  |  |         e("sets dl\n"); | 
					
						
							|  |  |  |         e("ror  dl, 1\n");      /* N flag -> MSB of DL */ | 
					
						
							|  |  |  |         e("or   ah, dl\n");     /* into N flag */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         e("mov  dl, al\n"); /* store result */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /*
 | 
					
						
							|  |  |  |          * V flag calculation: Put unadjusted result's MSB into bit 1, and the | 
					
						
							|  |  |  |          * adjusted result's MSB into bit 0. If the result is 1, the V flag | 
					
						
							|  |  |  |          * is set. | 
					
						
							|  |  |  |          */ | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |         e("shr  dh, byte 6\n"); | 
					
						
							|  |  |  |         e("shr  al, byte 7\n"); | 
					
						
							|  |  |  |         e("and  dh, 2\n"); | 
					
						
							|  |  |  |         e("or   dh, al\n"); | 
					
						
							|  |  |  |         e("cmp  dh, 1\n"); | 
					
						
							|  |  |  |         e("sete al\n");     /* 1 -> V */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         WriteByte(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |     if (!rm) | 
					
						
							|  |  |  |         EmitTiming(6); | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |         EmitTiming(18); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     InstEnd(); | 
					
						
							|  |  |  |     return 1;   | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int ORItoCCR(unsigned short op, char *mnem, unsigned base_timing) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     InstBegin(op, mnem, 1); | 
					
						
							|  |  |  |     SaveCCR(); | 
					
						
							|  |  |  |     e("mov  dl, [esi]\n");      /* get data */ | 
					
						
							|  |  |  |     e("and  dl, 0x1f\n");       /* mask out unwanted bits */ | 
					
						
							|  |  |  |     e("or   [sr], dl\n"); | 
					
						
							|  |  |  |     e("add  esi, byte 2\n"); | 
					
						
							|  |  |  |     LoadCCR(); | 
					
						
							|  |  |  |     EmitTiming(base_timing); | 
					
						
							|  |  |  |     InstEnd(); | 
					
						
							|  |  |  |     e("db 66, 65, 82, 84, 33, 1\n"); | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int Scc(unsigned short op, char *mnem_unused, unsigned base_timing) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     unsigned    ea = op & 0x3f, cond = (op >> 8) & 0xf; | 
					
						
							|  |  |  |     char        mnem[4]; | 
					
						
							|  |  |  |     char        *mnem_t[] = { "ST",  "SF",  "SHI", "SLS", | 
					
						
							|  |  |  |                               "SCC", "SCS", "SNE", "SEQ", | 
					
						
							|  |  |  |                               "SVC", "SVS", "SPL", "SMI", | 
					
						
							|  |  |  |                               "SGE", "SLT", "SGT", "SLE" }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!CheckEA(ea, "101111111000"))   return 0; | 
					
						
							|  |  |  |     if (!NumDecodedEA(ea))              return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     strcpy(mnem, mnem_t[cond]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     InstBegin(op, mnem, NumDecodedEA(ea)); | 
					
						
							|  |  |  |     switch (cond) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |     /* EAX:0000000000000000 NZ00 000C 0000 000V */ | 
					
						
							|  |  |  |     case 0:     /* T: Always true */ | 
					
						
							|  |  |  |         if ((ea >> 3) == 0) /* Dn */ | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             e("and  edi, byte 7\n"); | 
					
						
							|  |  |  |             e("mov  byte [d+edi*4], 0xff\n"); | 
					
						
							|  |  |  |             EmitTiming(6);                              /* reg: byte, true */ | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             if (mpu == 68000 && dummyread && (ea >> 3)) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 /*
 | 
					
						
							|  |  |  |                  * If the processor type is 68000, and the EA mode is not | 
					
						
							|  |  |  |                  * register, we can emulate dummy reads! | 
					
						
							|  |  |  |                  */ | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |                 LoadFromEA(ea, BYTE_SIZE, 0); | 
					
						
							|  |  |  |                 e("mov  dl, 0xff\n"); | 
					
						
							|  |  |  |                 WriteByte(); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             else | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 e("mov  dl, 0xff\n"); | 
					
						
							|  |  |  |                 StoreToEAUsingEDI(ea, BYTE_SIZE, 0); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             EmitTiming(8 + TimingEA(ea, BYTE_SIZE));    /* mem: byte, true */ | 
					
						
							|  |  |  |         }     | 
					
						
							|  |  |  |         InstEnd(); | 
					
						
							|  |  |  |         return 1; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case 1:     /* F: Always false */ | 
					
						
							|  |  |  |         if ((ea >> 3) == 0) /* Dn */ | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             e("and  edi, byte 7\n"); | 
					
						
							|  |  |  |             e("mov  byte [d+edi*4], 0\n");    | 
					
						
							|  |  |  |             EmitTiming(4);                              /* reg: byte, false */ | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             if (mpu == 68000 && dummyread && (ea >> 3)) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 /*
 | 
					
						
							|  |  |  |                  * If the processor type is 68000, and the EA mode is not | 
					
						
							|  |  |  |                  * register, we can emulate dummy reads! | 
					
						
							|  |  |  |                  */ | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |                 LoadFromEA(ea, BYTE_SIZE, 0); | 
					
						
							|  |  |  |                 e("xor  dl, dl\n"); | 
					
						
							|  |  |  |                 WriteByte(); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             else | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 e("xor  dl, dl\n"); | 
					
						
							|  |  |  |                 StoreToEAUsingEDI(ea, BYTE_SIZE, 0); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             EmitTiming(8 + TimingEA(ea, BYTE_SIZE));    /* mem: byte, false */ | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         InstEnd(); | 
					
						
							|  |  |  |         return 1; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case 2:     /* HI: !C & !Z */ | 
					
						
							|  |  |  |         e("test ah, byte 0x41\n"); | 
					
						
							|  |  |  |         e("jz   short do%d\n", op); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case 3:     /* LS: C | Z */ | 
					
						
							|  |  |  |         e("test ah, byte 0x41\n"); | 
					
						
							|  |  |  |         e("jnz  short do%d\n", op); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case 4:     /* CC: !C */ | 
					
						
							|  |  |  |         e("test ah, byte 1\n"); | 
					
						
							|  |  |  |         e("jz   short do%d\n", op); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case 5:     /* CS: C */ | 
					
						
							|  |  |  |         e("test ah, byte 1\n"); | 
					
						
							|  |  |  |         e("jnz  short do%d\n", op); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case 6:     /* NE: !Z */ | 
					
						
							|  |  |  |         e("test ah, byte 0x40\n"); | 
					
						
							|  |  |  |         e("jz   short do%d\n", op); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case 7:     /* EQ: Z */ | 
					
						
							|  |  |  |         e("test ah, byte 0x40\n"); | 
					
						
							|  |  |  |         e("jnz  short do%d\n", op); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case 8:     /* VC: !V */ | 
					
						
							|  |  |  |         e("test al, byte 1\n"); | 
					
						
							|  |  |  |         e("jz   short do%d\n", op); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case 9:     /* VS: V */ | 
					
						
							|  |  |  |         e("test al, byte 1\n"); | 
					
						
							|  |  |  |         e("jnz  short do%d\n", op); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case 0xa:   /* PL: !N */ | 
					
						
							|  |  |  |         e("test ah, byte 0x80\n"); | 
					
						
							|  |  |  |         e("jz   short do%d\n", op); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case 0xb:   /* MI: N */ | 
					
						
							|  |  |  |         e("test ah, byte 0x80\n"); | 
					
						
							|  |  |  |         e("jnz  short do%d\n", op); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case 0xc:   /* GE: N & V | !N & !V      (N&V || !N&!V) */ | 
					
						
							|  |  |  |         e("mov  bl, al\n"); | 
					
						
							|  |  |  |         e("mov  bh, ah\n"); | 
					
						
							|  |  |  |         e("and  bh, 0xfe\n"); | 
					
						
							|  |  |  |         e("or   bl, bh\n"); | 
					
						
							|  |  |  |         e("test bl, byte 0x81\n"); | 
					
						
							|  |  |  |         e("jpe  short do%d\n", op);         | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case 0xd:   /* LT: N & !V | !N & V */ | 
					
						
							|  |  |  |         e("mov  bl, al\n"); | 
					
						
							|  |  |  |         e("mov  bh, ah\n"); | 
					
						
							|  |  |  |         e("and  bh, 0xfe\n"); | 
					
						
							|  |  |  |         e("or   bl, bh\n"); | 
					
						
							|  |  |  |         e("test bl, byte 0x81\n"); | 
					
						
							|  |  |  |         e("jpo  short do%d\n", op); | 
					
						
							|  |  |  |         EmitLabel(".dont_do"); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case 0xe:   /* GT: N & V & !Z | !N & !V & !Z */ | 
					
						
							|  |  |  |         /* if Z, then it is GE and we don't take this branch */ | 
					
						
							|  |  |  |         e("test ah, byte 0x40\n"); | 
					
						
							|  |  |  |         e("jnz  short .dont_do\n"); | 
					
						
							|  |  |  |         e("mov  bl, al\n"); | 
					
						
							|  |  |  |         e("mov  bh, ah\n"); | 
					
						
							|  |  |  |         e("and  bh, 0xfe\n"); | 
					
						
							|  |  |  |         e("or   bl, bh\n"); | 
					
						
							|  |  |  |         e("test bl, byte 0x81\n"); | 
					
						
							|  |  |  |         e("jpe  short do%d\n", op);         | 
					
						
							|  |  |  |         EmitLabel(".dont_do"); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case 0xf:   /* LE: Z | N & !V | !N & V */ | 
					
						
							|  |  |  |         e("test ah, 0x40\n"); | 
					
						
							|  |  |  |         e("jnz  short do%d\n", op); | 
					
						
							|  |  |  |         e("mov  bl, al\n"); | 
					
						
							|  |  |  |         e("mov  bh, ah\n"); | 
					
						
							|  |  |  |         e("and  bh, 0xfe\n"); | 
					
						
							|  |  |  |         e("or   bl, bh\n"); | 
					
						
							|  |  |  |         e("test bl, byte 0x81\n"); | 
					
						
							|  |  |  |         e("jpo  short do%d\n", op); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if ((ea >> 3) == 0) /* Dn */ | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         e("and  edi, byte 7\n"); | 
					
						
							|  |  |  |         e("mov  byte [d+edi*4], 0\n");    | 
					
						
							|  |  |  |         EmitTiming(4);                              /* reg: byte, false */ | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         e("false%d:\n", op);    /* this prevents redefinitions of labels in
 | 
					
						
							|  |  |  |                                    the EA code */ | 
					
						
							|  |  |  |         if (mpu == 68000 && dummyread && (ea >> 3)) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             /*
 | 
					
						
							|  |  |  |              * If the processor type is 68000, and the EA mode is not | 
					
						
							|  |  |  |              * register, we can emulate dummy reads! | 
					
						
							|  |  |  |              */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             LoadFromEA(ea, BYTE_SIZE, 0); | 
					
						
							|  |  |  |             e("xor  dl, dl\n"); | 
					
						
							|  |  |  |             WriteByte(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             e("xor  dl, dl\n"); | 
					
						
							|  |  |  |             StoreToEAUsingEDI(ea, BYTE_SIZE, 0); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         EmitTiming(8 + TimingEA(ea, BYTE_SIZE));    /* mem: byte, false */ | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     InstEnd(); | 
					
						
							|  |  |  |     Align(4); | 
					
						
							|  |  |  |     e("do%d:\n", op); | 
					
						
							|  |  |  |     if ((ea >> 3) == 0) /* Dn */ | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         e("and  edi, byte 7\n"); | 
					
						
							|  |  |  |         e("mov  byte [d+edi*4], 0xff\n"); | 
					
						
							|  |  |  |         EmitTiming(6);                              /* reg: byte, true */ | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         e("true%d:\n", op);     /* this prevents redefinitions of labels in
 | 
					
						
							|  |  |  |                                    the EA code */ | 
					
						
							|  |  |  |         if (mpu == 68000 && dummyread && (ea >> 3)) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             /*
 | 
					
						
							|  |  |  |              * If the processor type is 68000, and the EA mode is not | 
					
						
							|  |  |  |              * register, we can emulate dummy reads! | 
					
						
							|  |  |  |              */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             LoadFromEA(ea, BYTE_SIZE, 0); | 
					
						
							|  |  |  |             e("mov  dl, 0xff\n"); | 
					
						
							|  |  |  |             WriteByte(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             e("mov  dl, 0xff\n"); | 
					
						
							|  |  |  |             StoreToEAUsingEDI(ea, BYTE_SIZE, 0); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         EmitTiming(8 + TimingEA(ea, BYTE_SIZE));    /* mem: byte, true */ | 
					
						
							|  |  |  |     }     | 
					
						
							|  |  |  |     InstEnd(); | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int EXG(unsigned short op, char *mnem, unsigned base_timing) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     unsigned    rx = (op >> 9) & 7, opmode = (op >> 3) & 0x1f; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (opmode != 0x8 && opmode != 0x9 && opmode != 0x11)   return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     InstBegin(op, mnem, 8); | 
					
						
							|  |  |  |     e("and  edi, byte 7\n"); | 
					
						
							|  |  |  |     switch (opmode) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |     case 8:     /* Dx,Dy */ | 
					
						
							|  |  |  |         e("mov  ebx, [d+%d*4]\n", rx); | 
					
						
							|  |  |  |         e("mov  edx, [d+edi*4]\n"); | 
					
						
							|  |  |  |         e("mov  [d+%d*4], edx\n", rx); | 
					
						
							|  |  |  |         e("mov  [d+edi*4], ebx\n"); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case 9:     /* Ax,Ay */ | 
					
						
							|  |  |  |         e("mov  ebx, [a+%d*4]\n", rx); | 
					
						
							|  |  |  |         e("mov  edx, [a+edi*4]\n"); | 
					
						
							|  |  |  |         e("mov  [a+%d*4], edx\n", rx); | 
					
						
							|  |  |  |         e("mov  [a+edi*4], ebx\n"); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case 0x11:  /* Dx,Ay */ | 
					
						
							|  |  |  |         e("mov  ebx, [d+%d*4]\n", rx); | 
					
						
							|  |  |  |         e("mov  edx, [a+edi*4]\n"); | 
					
						
							|  |  |  |         e("mov  [d+%d*4], edx\n", rx); | 
					
						
							|  |  |  |         e("mov  [a+edi*4], ebx\n"); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     EmitTiming(base_timing); | 
					
						
							|  |  |  |     InstEnd(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int MULS(unsigned short op, char *mnem, unsigned base_timing) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     unsigned    ea = op & 0x3f, dn = (op >> 9) & 7; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!CheckEA(ea, "101111111111"))   return 0; | 
					
						
							|  |  |  |     if (!NumDecodedEA(ea))              return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     InstBegin(op, mnem, NumDecodedEA(ea)); | 
					
						
							|  |  |  |     LoadFromEA(ea, WORD_SIZE, 0); | 
					
						
							|  |  |  |     e("mov  ax, [d+%d*4]\n", dn); | 
					
						
							|  |  |  |     e("imul dx\n");             /* ax*dx->dx:ax */ | 
					
						
							|  |  |  |     e("shl  edx, byte 16\n");   /* EDX=32-bit result */ | 
					
						
							|  |  |  |     e("mov  dx, ax\n"); | 
					
						
							|  |  |  |     e("mov  [d+%d*4], edx\n", dn); | 
					
						
							|  |  |  |     e("test edx, edx\n");       /* C is always cleared */ | 
					
						
							|  |  |  |     e("lahf\n"); | 
					
						
							|  |  |  |     e("xor  al, al\n");         /* V=1 only occurs on 32*32 (not on 68000) */ | 
					
						
							|  |  |  |     EmitTiming(base_timing + TimingEA(ea, WORD_SIZE)); | 
					
						
							|  |  |  |     InstEnd(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int MULU(unsigned short op, char *mnem, unsigned base_timing) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     unsigned    ea = op & 0x3f, dn = (op >> 9) & 7; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!CheckEA(ea, "101111111111"))   return 0; | 
					
						
							|  |  |  |     if (!NumDecodedEA(ea))              return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     InstBegin(op, mnem, NumDecodedEA(ea)); | 
					
						
							|  |  |  |     LoadFromEA(ea, WORD_SIZE, 0); | 
					
						
							|  |  |  |     e("mov  ax, [d+%d*4]\n", dn); | 
					
						
							|  |  |  |     e("mul  dx\n"); /* ax*dx->dx:ax */ | 
					
						
							|  |  |  |     e("shl  edx, byte 16\n");   /* EDX=32-bit result */ | 
					
						
							|  |  |  |     e("mov  dx, ax\n"); | 
					
						
							|  |  |  |     e("mov  [d+%d*4], edx\n", dn); | 
					
						
							|  |  |  |     e("test edx, edx\n");       /* C is always cleared */ | 
					
						
							|  |  |  |     e("lahf\n"); | 
					
						
							|  |  |  |     e("xor  al, al\n");         /* V=1 only occurs on 32*32 (not on 68000) */ | 
					
						
							|  |  |  |     EmitTiming(base_timing + TimingEA(ea, WORD_SIZE)); | 
					
						
							|  |  |  |     InstEnd(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int DIVS(unsigned short op, char *mnem, unsigned base_timing) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     unsigned    ea = op & 0x3f, dn = (op >> 9) & 7; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!CheckEA(ea, "101111111111"))   return 0; | 
					
						
							|  |  |  |     if (!NumDecodedEA(ea))              return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* See the note in DIVU() for info on how overflow is detected */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     InstBegin(op, mnem, NumDecodedEA(ea)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (TimingEA(ea, WORD_SIZE)) | 
					
						
							|  |  |  |         e("sub     ecx, byte %d\n", TimingEA(ea, WORD_SIZE));   /* do 1st.. */ | 
					
						
							|  |  |  |     LoadFromEA(ea, WORD_SIZE, 0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     e("test dx, dx\n"); | 
					
						
							|  |  |  |     e("jz   .divide_by_zero\n"); | 
					
						
							|  |  |  |     e("movsx    ebx, dx\n");        /* divisor->EBX (sign extend to work) */ | 
					
						
							|  |  |  |     SaveReg("run", "eax"); | 
					
						
							|  |  |  |     e("mov  eax, [d+%d*4]\n", dn);    /* dividend */ | 
					
						
							|  |  |  |     e("cdq\n");                         /* EAX->sign extend->EDX:EAX */ | 
					
						
							|  |  |  |     e("idiv ebx\n"); | 
					
						
							|  |  |  |     e("cmp  eax, -32768\n"); | 
					
						
							|  |  |  |     e("jl   .overflow\n"); | 
					
						
							|  |  |  |     e("cmp  eax, 32767\n"); | 
					
						
							|  |  |  |     e("jg   .overflow\n"); | 
					
						
							|  |  |  |     e("test ax, ax\n");                 /* test for flags */ | 
					
						
							|  |  |  |     e("mov     [d+(%d*4)+2], dx\n", dn);  /* store back to Dn */ | 
					
						
							|  |  |  |     e("mov     [d+(%d*4)+0], ax\n", dn); | 
					
						
							|  |  |  |     e("lahf\n");    /* the mov's did not affect the flags... */ | 
					
						
							|  |  |  |     e("xor     al, al\n"); /* C cleared by TEST */ | 
					
						
							|  |  |  |     EmitTiming(base_timing); | 
					
						
							|  |  |  |     InstEnd(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     EmitLabel(".overflow"); | 
					
						
							|  |  |  |     RestoreReg("run", "eax"); | 
					
						
							|  |  |  |     e("mov  eax, 1\n");             /* clear C and set overflow */ | 
					
						
							|  |  |  |     EmitTiming(base_timing); | 
					
						
							|  |  |  |     InstEnd(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     EmitLabel(".divide_by_zero"); | 
					
						
							|  |  |  |     e("xor  eax, eax\n");           /* clear C */ | 
					
						
							|  |  |  |     e("jmp     near exception_divide_by_zero\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int DIVU(unsigned short op, char *mnem, unsigned base_timing) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |      * Overflow Detection: | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * Overflow detection is actually pretty simple. The 68000 DIVU and DIVS | 
					
						
							|  |  |  |      * instructions divide 32-bit operands by 16-bit operands. What I've done | 
					
						
							|  |  |  |      * is zero extend the operands to 64-bit and 32-bit and then divide. If | 
					
						
							|  |  |  |      * the result is larger than 0xFFFF (16 bits), the overflow condition is | 
					
						
							|  |  |  |      * set. | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * See the end of this function for an alternate method. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     unsigned    ea = op & 0x3f, dn = (op >> 9) & 7; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!CheckEA(ea, "101111111111"))   return 0; | 
					
						
							|  |  |  |     if (!NumDecodedEA(ea))              return 0; | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     InstBegin(op, mnem, NumDecodedEA(ea)); | 
					
						
							|  |  |  |     LoadFromEA(ea, WORD_SIZE, 0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (TimingEA(ea, WORD_SIZE)) | 
					
						
							|  |  |  |         e("sub     ecx, byte %d\n", TimingEA(ea, WORD_SIZE));   /* do 1st.. */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     e("test dx, dx\n"); | 
					
						
							|  |  |  |     e("jz   .divide_by_zero\n"); | 
					
						
							|  |  |  |     e("mov      ebx, edx\n"); | 
					
						
							|  |  |  |     e("and      ebx, 0xffff\n");    /* divisor->EBX */ | 
					
						
							|  |  |  |     SaveReg("run", "eax"); | 
					
						
							|  |  |  |     e("mov  eax, [d+%d*4]\n", dn);  /* dividend */ | 
					
						
							|  |  |  |     e("xor  edx, edx\n");           /* EDX:EAX=dividend */ | 
					
						
							|  |  |  |     e("div  ebx\n"); | 
					
						
							|  |  |  |     e("cmp  eax, 0xffff\n"); | 
					
						
							|  |  |  |     e("jg   .overflow\n"); | 
					
						
							|  |  |  |     e("test ax, ax\n");             /* test for flags */ | 
					
						
							|  |  |  |     e("mov     [d+(%d*4)+2], dx\n", dn);    /* store back to Dn */ | 
					
						
							|  |  |  |     e("mov     [d+(%d*4)+0], ax\n", dn); | 
					
						
							|  |  |  |     e("lahf\n");            /* the mov's did not affect the flags... */ | 
					
						
							|  |  |  |     e("xor     al, al\n");  /* C cleared by TEST */ | 
					
						
							|  |  |  |     EmitTiming(base_timing); | 
					
						
							|  |  |  |     InstEnd(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     EmitLabel(".overflow"); | 
					
						
							|  |  |  |     RestoreReg("run", "eax"); | 
					
						
							|  |  |  |     e("mov  eax, 1\n");             /* clear C and set overflow */ | 
					
						
							|  |  |  |     EmitTiming(base_timing); | 
					
						
							|  |  |  |     InstEnd(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     EmitLabel(".divide_by_zero"); | 
					
						
							|  |  |  |     e("xor  eax, eax\n");           /* clear C */ | 
					
						
							|  |  |  |     e("jmp     near exception_divide_by_zero\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * An alternate method to detecting overflows is shown below. It doesn't | 
					
						
							|  |  |  |      * seem to be as acurrate as the method that is actually used, but perhaps | 
					
						
							|  |  |  |      * I implemented it wrong or misunderstood it. It broke Comix Zone, Hard | 
					
						
							|  |  |  |      * Drivin', and Race Drivin' (well, caused graphical glitches actually.) | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * Kuwanger in #programmers (DALnet, of course) came up with a cool idea | 
					
						
							|  |  |  |      * on how to detect overflow before actually dividing. He used an example | 
					
						
							|  |  |  |      * of AH:AL/BL ... in the emulator, it is DX:AX/BX. The dividend, DX:AX | 
					
						
							|  |  |  |      * is stored entirely in EDX, and it is shifted right by the bit number of | 
					
						
							|  |  |  |      * the highest 1 bit in BX, the divisor. If the high 16-bits of EDX (which | 
					
						
							|  |  |  |      * would be DX in DX:AX) are not clear, then an overflow would occur. | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * Here's Kuwanger's classic lecture: | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * <Kuwanger> Maybe I should use a smaller example. | 
					
						
							|  |  |  |      * <Kuwanger> Lets use, ah:al/bl | 
					
						
							|  |  |  |      * ... | 
					
						
							|  |  |  |      * <Kuwanger> trzy: You could just convert one to a bit value. | 
					
						
							|  |  |  |      * <Kuwanger> trzy: Ie, hb(bl).. | 
					
						
							|  |  |  |      * <Kuwanger> And then shift the other one ah:al | 
					
						
							|  |  |  |      * ... | 
					
						
							|  |  |  |      * <Kuwanger> Though hb(bl) would have to return 0, that time. | 
					
						
							|  |  |  |      * <Kuwanger> then ah:all>>hb(bl) | 
					
						
							|  |  |  |      * <Kuwanger> err, ah:al, rather | 
					
						
							|  |  |  |      * <Kuwanger> Ie, you shift by the most prominent bit. | 
					
						
							|  |  |  |      * <Kuwanger> And if ah is non-zero.. | 
					
						
							|  |  |  |      * <Kuwanger> Well, then the number won't fit. | 
					
						
							|  |  |  |      * ... | 
					
						
							|  |  |  |      * <Kuwanger> Lets try an extreme case. | 
					
						
							|  |  |  |      * <Kuwanger> 65535/255 | 
					
						
							|  |  |  |      * <Kuwanger> 65535>>7 | 
					
						
							|  |  |  |      * ... | 
					
						
							|  |  |  |      * <Kuwanger> That obviously doesn't fit. :) | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * Hip-hip-HURRAY!  | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  | }     | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int NOT(unsigned short op, char *mnem, unsigned base_timing) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     int         size; | 
					
						
							|  |  |  |     unsigned    ea = op & 0x3f, t; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!CheckEA(ea, "101111111000"))   return 0; | 
					
						
							|  |  |  |     if (!NumDecodedEA(ea))              return 0; | 
					
						
							|  |  |  |     switch ((op >> 6) & 3) | 
					
						
							|  |  |  |     {   case 0: size = BYTE_SIZE; break; | 
					
						
							|  |  |  |         case 1: size = WORD_SIZE; break; | 
					
						
							|  |  |  |         case 2: size = LONG_SIZE; break; | 
					
						
							|  |  |  |         default: return 0;  } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     InstBegin(op, mnem, NumDecodedEA(ea)); | 
					
						
							|  |  |  |     if ((ea >> 3) == 0) /* Dn */ | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         e("and  edi, byte 7\n"); | 
					
						
							|  |  |  |         if (size == BYTE_SIZE) | 
					
						
							|  |  |  |             e("mov  dl, [d+edi*4]\n"); | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |             e("mov  edx, [d+edi*4]\n"); | 
					
						
							|  |  |  |         switch (size) | 
					
						
							|  |  |  |         {   case BYTE_SIZE: e("not  dl\n"); e("test dl, dl\n"); break; | 
					
						
							|  |  |  |             case WORD_SIZE: e("not  dx\n"); e("test dx, dx\n"); break; | 
					
						
							|  |  |  |             case LONG_SIZE: e("not  edx\n"); e("test edx, edx\n"); break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         e("lahf\n");        /* C cleared */ | 
					
						
							|  |  |  |         e("xor  al, al\n"); /* V cleared */ | 
					
						
							|  |  |  |         switch (size) | 
					
						
							|  |  |  |         {   case BYTE_SIZE: e("mov  [d+edi*4], dl\n"); break; | 
					
						
							|  |  |  |             case WORD_SIZE: e("mov  [d+edi*4], dx\n"); break; | 
					
						
							|  |  |  |             case LONG_SIZE: e("mov  [d+edi*4], edx\n"); break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         switch (size) | 
					
						
							|  |  |  |         {   case BYTE_SIZE: | 
					
						
							|  |  |  |             case WORD_SIZE: | 
					
						
							|  |  |  |                 t = 4; break; | 
					
						
							|  |  |  |             case LONG_SIZE: | 
					
						
							|  |  |  |                 t = 6; break;   } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else                /* mem */ | 
					
						
							|  |  |  |     {         | 
					
						
							|  |  |  |         LoadFromEA(ea, size, 0); | 
					
						
							|  |  |  |         switch (size) | 
					
						
							|  |  |  |         {   case BYTE_SIZE: e("not  dl\n"); e("test dl, dl\n"); break; | 
					
						
							|  |  |  |             case WORD_SIZE: e("not  dx\n"); e("test dx, dx\n"); break; | 
					
						
							|  |  |  |             case LONG_SIZE: e("not  edx\n"); e("test edx, edx\n"); break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         e("lahf\n");        /* C cleared */ | 
					
						
							|  |  |  |         e("xor  al, al\n"); /* V cleared */ | 
					
						
							|  |  |  |         switch (size) | 
					
						
							|  |  |  |         {   case BYTE_SIZE: WriteByte(); break; | 
					
						
							|  |  |  |             case WORD_SIZE: WriteWord(); break; | 
					
						
							|  |  |  |             case LONG_SIZE: WriteLong(); break; | 
					
						
							|  |  |  |         }     | 
					
						
							|  |  |  |         switch (size) | 
					
						
							|  |  |  |         {   case BYTE_SIZE: | 
					
						
							|  |  |  |             case WORD_SIZE: | 
					
						
							|  |  |  |                 t = 8; break; | 
					
						
							|  |  |  |             case LONG_SIZE: | 
					
						
							|  |  |  |                 t = 12; break;   } | 
					
						
							|  |  |  |         t += TimingEA(ea, size); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     EmitTiming(t); | 
					
						
							|  |  |  |     InstEnd(); | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int RTE(unsigned short op, char *mnem, unsigned base_timing) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     InstBegin(op, mnem, 1); | 
					
						
							|  |  |  |     e("test byte [sr+1], 0x20\n");      /* must be in supervisor mode */ | 
					
						
							|  |  |  |     e("jz   near exception_privilege_violation\n"); | 
					
						
							|  |  |  |     e("mov  ebx, [a+7*4]\n"); | 
					
						
							|  |  |  |     SaveReg("run", "ebx"); | 
					
						
							|  |  |  |     ReadWord();                         /* get SR */ | 
					
						
							|  |  |  |     RestoreReg("run", "ebx"); | 
					
						
							|  |  |  |     e("and  edx, 0xa71f\n"); | 
					
						
							|  |  |  |     e("mov  [sr], edx\n"); | 
					
						
							|  |  |  |     LoadCCR(); | 
					
						
							|  |  |  |     e("add  ebx, byte 2\n"); | 
					
						
							|  |  |  |     SaveReg("run", "ebx"); | 
					
						
							|  |  |  |     ReadLong();                         /* get PC */ | 
					
						
							|  |  |  |     RestoreReg("run", "ebx"); | 
					
						
							|  |  |  |     e("add  ebx, byte 4\n"); | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |      * If 68010, we have to fetch the format word and check it. If invalid, | 
					
						
							|  |  |  |      * we branch to stackframe_error. The PC points at the word AFTER the | 
					
						
							|  |  |  |      * faulty RTE. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     if (mpu == 68010) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         SaveReg("run", "edx");  /* EDX has the PC! */ | 
					
						
							|  |  |  |         SaveReg("run", "ebx"); | 
					
						
							|  |  |  |         ReadWord(); | 
					
						
							|  |  |  |         RestoreReg("run", "ebx"); | 
					
						
							|  |  |  |         e("add  ebx, byte 2\n"); | 
					
						
							|  |  |  |         e("test dh, 0xf0\n");   /* format should only be 0x0000 */ | 
					
						
							|  |  |  |         e("jnz  near stackframe_error\n"); | 
					
						
							|  |  |  |         RestoreReg("run", "edx"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |     e("mov  [a+7*4], ebx\n"); | 
					
						
							|  |  |  |     e("mov  esi, edx\n"); | 
					
						
							|  |  |  |     UpdateFetchPtr(); | 
					
						
							|  |  |  |     e("test byte [sr+1], 0x20\n");      /* if no longer in supervisor,
 | 
					
						
							|  |  |  |                                            SP->SSP, USP->SP */ | 
					
						
							|  |  |  |     e("jnz  short .in_s\n"); | 
					
						
							|  |  |  |     e("mov  ebx, [a+7*4]\n"); | 
					
						
							|  |  |  |     e("mov  edx, [__sp]\n"); | 
					
						
							|  |  |  |     e("mov  [a+7*4], edx\n"); | 
					
						
							|  |  |  |     e("mov  [__sp], ebx\n"); | 
					
						
							|  |  |  |     SetUserAddressSpace();              /* map in user address space */ | 
					
						
							|  |  |  |     EmitLabel(".in_s"); | 
					
						
							|  |  |  |     EmitTiming(base_timing); | 
					
						
							|  |  |  |     InstEnd(); | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int ANDItoCCR(unsigned short op, char *mnem, unsigned base_timing) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     InstBegin(op, mnem, 1); | 
					
						
							|  |  |  |     SaveCCR(); | 
					
						
							|  |  |  |     e("mov  dl, [esi]\n");      /* get data */ | 
					
						
							|  |  |  |     e("and  dl, 0x1f\n");       /* mask out unwanted bits */ | 
					
						
							|  |  |  |     e("and  [sr], dl\n"); | 
					
						
							|  |  |  |     e("add  esi, byte 2\n"); | 
					
						
							|  |  |  |     LoadCCR(); | 
					
						
							|  |  |  |     EmitTiming(base_timing); | 
					
						
							|  |  |  |     InstEnd(); | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int CMPA(unsigned short op, char *mnem, unsigned base_timing) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     unsigned    opmode = (op >> 6) & 7, t; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!CheckEA(op & 0x3f, "111111111111"))    return 0; | 
					
						
							|  |  |  |     if (!NumDecodedEA(op & 0x3f))               return 0; | 
					
						
							|  |  |  |     if (opmode != 3 && opmode != 7)             return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     InstBegin(op, mnem, NumDecodedEA(op & 0x3f)); | 
					
						
							|  |  |  |     if (opmode == 3)    LoadFromEA(op & 0x3f, WORD_SIZE, 1); | 
					
						
							|  |  |  |     else                LoadFromEA(op & 0x3f, LONG_SIZE, 0); | 
					
						
							|  |  |  |     e("cmp  [a+%d*4], edx\n", (op >> 9) & 7); | 
					
						
							|  |  |  |     e("lahf\n"); | 
					
						
							|  |  |  |     e("seto al\n"); | 
					
						
							|  |  |  |     if (opmode == 3)    /* word size */ | 
					
						
							|  |  |  |         t = 6 + TimingEA(op & 0x3f, WORD_SIZE); | 
					
						
							|  |  |  |     else                /* long */ | 
					
						
							|  |  |  |         t = 6 + TimingEA(op & 0x3f, LONG_SIZE); | 
					
						
							|  |  |  |     EmitTiming(t); | 
					
						
							|  |  |  |     InstEnd(); | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int PEA(unsigned short op, char *mnem, unsigned base_timing) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     unsigned    t; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!CheckEA(op & 0x3f, "001001111011"))    return 0; | 
					
						
							|  |  |  |     if (!NumDecodedEA(op & 0x3f))               return 0; | 
					
						
							|  |  |  |     InstBegin(op, mnem, NumDecodedEA(op & 0x3f)); | 
					
						
							|  |  |  |     LoadControlEA(op & 0x3f); | 
					
						
							|  |  |  |     e("sub  dword [a+7*4], byte 4\n");  /* SP-4->SP */ | 
					
						
							|  |  |  |     e("mov  edx, ebx\n"); | 
					
						
							|  |  |  |     e("mov  ebx, [a+7*4]\n"); | 
					
						
							|  |  |  |     WriteLong();                        /* <ea>->(SP) */ | 
					
						
							|  |  |  |     switch ((op >> 3) & 7)      /* timing based on control addressing mode */ | 
					
						
							|  |  |  |     {   case 2: t = 12; break;  /* (An) */ | 
					
						
							|  |  |  |         case 5: t = 16; break;  /* (d16,An) */ | 
					
						
							|  |  |  |         case 6: t = 20; break;  /* (d8,An,Xn) */ | 
					
						
							|  |  |  |         case 7: | 
					
						
							|  |  |  |             switch (op & 7) | 
					
						
							|  |  |  |             {   case 0: t = 16; break;  /* (xxx).W */ | 
					
						
							|  |  |  |                 case 1: t = 20; break;  /* (xxx).L */ | 
					
						
							|  |  |  |                 case 2: t = 16; break;  /* (d16,pc) */ | 
					
						
							|  |  |  |                 case 3: t = 20; break;  /* (d8,pc,Xn) */ | 
					
						
							|  |  |  |             } break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     EmitTiming(t); | 
					
						
							|  |  |  |     InstEnd(); | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int SWAP(unsigned short op, char *mnem, unsigned base_timing) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     InstBegin(op, mnem, 8); | 
					
						
							|  |  |  |     e("and  edi, byte 7\n"); | 
					
						
							|  |  |  |     e("mov  edx, [d+edi*4]\n");  | 
					
						
							|  |  |  |     e("rol  edx, byte 16\n");       /* swap words */ | 
					
						
							|  |  |  |     e("test edx, edx\n");           /* clears CF, will set N and Z */ | 
					
						
							|  |  |  |     e("lahf\n");                     | 
					
						
							|  |  |  |     e("xor  al, al\n");             /* clear V */ | 
					
						
							|  |  |  |     e("mov  [d+edi*4], edx\n"); | 
					
						
							|  |  |  |     EmitTiming(base_timing); | 
					
						
							|  |  |  |     InstEnd(); | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int BSET(unsigned short op, char *mnem, unsigned base_timing) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     unsigned    t; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (((op >> 6) & 7) != 7 && ((op >> 6) & 7) != 3)   return 0; | 
					
						
							|  |  |  |     if (op & 0x100)                 /* dynamic */ | 
					
						
							|  |  |  |     {     | 
					
						
							|  |  |  |         if (!CheckEA(op & 0x3f, "101111111000"))    return 0; | 
					
						
							|  |  |  |         if (!NumDecodedEA(op & 0x3f))               return 0; | 
					
						
							|  |  |  |         InstBegin(op, mnem, NumDecodedEA(op & 0x3f)); | 
					
						
							|  |  |  |         if (((op >> 3) & 7) == 0)   /* Dn is long */ | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             t = 8; | 
					
						
							|  |  |  |             e("and  edi, byte 7\n"); | 
					
						
							|  |  |  |             e("mov  ebx, [d+%d*4]\n", (op >> 9) & 7); /* bit # */ | 
					
						
							|  |  |  |             e("and  ebx, byte 31\n");           /* same as modulo 32 */ | 
					
						
							|  |  |  |             e("bts  dword [d+edi*4], ebx\n"); /* bit->CF, set */ | 
					
						
							|  |  |  |             e("setnc dh\n");        /* zero status of C->DH */ | 
					
						
							|  |  |  |             e("and  ah, 0xbf\n");   /* get rid of old Z */ | 
					
						
							|  |  |  |             e("shl  dh, 6\n");      /* put C in Z position */ | 
					
						
							|  |  |  |             e("or   ah, dh\n");     /* set the new Z */ | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else                        /* mem is byte */ | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             t = 8; | 
					
						
							|  |  |  |             LoadFromEA(op & 0x3f, BYTE_SIZE, 0); | 
					
						
							|  |  |  |             e("mov  edi, [d+%d*4]\n", (op >> 9) & 7); /* bit # */ | 
					
						
							|  |  |  |             e("and  edi, byte 7\n");             /* same as modulo 8 */ | 
					
						
							|  |  |  |             e("bts  edx, edi\n");                /* bit->CF, set */ | 
					
						
							|  |  |  |             e("setnc dh\n");        /* zero status of C->DH */ | 
					
						
							|  |  |  |             e("and  ah, 0xbf\n");   /* get rid of old Z */ | 
					
						
							|  |  |  |             e("shl  dh, 6\n");      /* put C in Z position */ | 
					
						
							|  |  |  |             e("or   ah, dh\n");     /* set the new Z */ | 
					
						
							|  |  |  |             WriteByte();                         /* clears EDI for us */ | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else if (!(op & 0x100))         /* static */ | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if (!CheckEA(op & 0x3f, "101111111000"))    return 0; | 
					
						
							|  |  |  |         if (!NumDecodedEA(op & 0x3f))               return 0; | 
					
						
							|  |  |  |         InstBegin(op, mnem, NumDecodedEA(op & 0x3f)); | 
					
						
							|  |  |  |         if (((op >> 3) & 7) == 0)   /* Dn is long */ | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             t = 12; | 
					
						
							|  |  |  |             e("and  edi, byte 7\n");    /* isolate Dn reg # */ | 
					
						
							|  |  |  |             e("mov  ebx, [esi]\n");     /* get bit # */ | 
					
						
							|  |  |  |             e("and  ebx, byte 31\n");   /* same as modulo 32 */ | 
					
						
							|  |  |  |             e("add  esi, byte 2\n"); | 
					
						
							|  |  |  |             e("bts  dword [d+edi*4], ebx\n"); /* bit->CF, set */ | 
					
						
							|  |  |  |             e("setnc dh\n");        /* zero status of C->DH */ | 
					
						
							|  |  |  |             e("and  ah, 0xbf\n");   /* get rid of old Z */ | 
					
						
							|  |  |  |             e("shl  dh, 6\n");      /* put C in Z position */ | 
					
						
							|  |  |  |             e("or   ah, dh\n");     /* set the new Z */ | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else                        /* mem is byte */ | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             t = 12; | 
					
						
							|  |  |  |             SaveRegTo("run", "edi", "esi"); /* save to EDI spot */ | 
					
						
							|  |  |  |             e("add  esi, byte 2\n"); | 
					
						
							|  |  |  |             LoadFromEA(op & 0x3f, BYTE_SIZE, 0); | 
					
						
							|  |  |  |             RestoreReg("run", "edi"); | 
					
						
							|  |  |  |             e("mov  edi, [edi]\n"); | 
					
						
							|  |  |  |             e("and  edi, byte 7\n");    /* same as modulo 8 */ | 
					
						
							|  |  |  |             e("bts  edx, edi\n");       /* bit->CF, set */ | 
					
						
							|  |  |  |             e("setnc dh\n");        /* zero status of C->DH */ | 
					
						
							|  |  |  |             e("and  ah, 0xbf\n");   /* get rid of old Z */ | 
					
						
							|  |  |  |             e("shl  dh, 6\n");      /* put C in Z position */ | 
					
						
							|  |  |  |             e("or   ah, dh\n");     /* set the new Z */ | 
					
						
							|  |  |  |             WriteByte();            /* write back, EDI is cleared */ | 
					
						
							|  |  |  |         }         | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (((op & 0x3f) & 7) == 0) /* Dn is long */ | 
					
						
							|  |  |  |         EmitTiming(t); | 
					
						
							|  |  |  |     else                        /* mem is byte */ | 
					
						
							|  |  |  |         EmitTiming(t + TimingEA(op & 0x3f, BYTE_SIZE));         | 
					
						
							|  |  |  |     InstEnd(); | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int BCLR(unsigned short op, char *mnem, unsigned base_timing) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     unsigned    t; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (((op >> 6) & 7) != 6 && ((op >> 6) & 7) != 2)   return 0; | 
					
						
							|  |  |  |     if (op & 0x100)                 /* dynamic */ | 
					
						
							|  |  |  |     {     | 
					
						
							|  |  |  |         if (!CheckEA(op & 0x3f, "101111111000"))    return 0; | 
					
						
							|  |  |  |         if (!NumDecodedEA(op & 0x3f))               return 0; | 
					
						
							|  |  |  |         InstBegin(op, mnem, NumDecodedEA(op & 0x3f)); | 
					
						
							|  |  |  |         if (((op >> 3) & 7) == 0)   /* Dn is long */ | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             t = 10; | 
					
						
							|  |  |  |             e("and  edi, byte 7\n"); | 
					
						
							|  |  |  |             e("mov  ebx, [d+%d*4]\n", (op >> 9) & 7); /* bit # */ | 
					
						
							|  |  |  |             e("and  ebx, byte 31\n");           /* same as modulo 32 */ | 
					
						
							|  |  |  |             e("btr  dword [d+edi*4], ebx\n"); /* bit->CF, clear */ | 
					
						
							|  |  |  |             e("setnc dh\n");        /* zero status of C->DH */ | 
					
						
							|  |  |  |             e("and  ah, 0xbf\n");   /* get rid of old Z */ | 
					
						
							|  |  |  |             e("shl  dh, 6\n");      /* put C in Z position */ | 
					
						
							|  |  |  |             e("or   ah, dh\n");     /* set the new Z */ | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else                        /* mem is byte */ | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             t = 8; | 
					
						
							|  |  |  |             LoadFromEA(op & 0x3f, BYTE_SIZE, 0); | 
					
						
							|  |  |  |             e("mov  edi, [d+%d*4]\n", (op >> 9) & 7); /* bit # */ | 
					
						
							|  |  |  |             e("and  edi, byte 7\n");             /* same as modulo 8 */ | 
					
						
							|  |  |  |             e("btr  edx, edi\n");                /* bit->CF, clear */ | 
					
						
							|  |  |  |             e("setnc dh\n");        /* zero status of C->DH */ | 
					
						
							|  |  |  |             e("and  ah, 0xbf\n");   /* get rid of old Z */ | 
					
						
							|  |  |  |             e("shl  dh, 6\n");      /* put C in Z position */ | 
					
						
							|  |  |  |             e("or   ah, dh\n");     /* set the new Z */ | 
					
						
							|  |  |  |             WriteByte();                         /* clears EDI for us */ | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else if (!(op & 0x100))         /* static */ | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if (!CheckEA(op & 0x3f, "101111111000"))    return 0; | 
					
						
							|  |  |  |         if (!NumDecodedEA(op & 0x3f))               return 0; | 
					
						
							|  |  |  |         InstBegin(op, mnem, NumDecodedEA(op & 0x3f)); | 
					
						
							|  |  |  |         if (((op >> 3) & 7) == 0)   /* Dn is long */ | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             t = 14; | 
					
						
							|  |  |  |             e("and  edi, byte 7\n");    /* isolate Dn reg # */ | 
					
						
							|  |  |  |             e("mov  ebx, [esi]\n");     /* get bit # */ | 
					
						
							|  |  |  |             e("and  ebx, byte 31\n");   /* same as modulo 32 */ | 
					
						
							|  |  |  |             e("add  esi, byte 2\n"); | 
					
						
							|  |  |  |             e("btr  dword [d+edi*4], ebx\n"); /* bit->CF, clear */ | 
					
						
							|  |  |  |             e("setnc dh\n");        /* zero status of C->DH */ | 
					
						
							|  |  |  |             e("and  ah, 0xbf\n");   /* get rid of old Z */ | 
					
						
							|  |  |  |             e("shl  dh, 6\n");      /* put C in Z position */ | 
					
						
							|  |  |  |             e("or   ah, dh\n");     /* set the new Z */ | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else                        /* mem is byte */ | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             t = 12; | 
					
						
							|  |  |  |             SaveRegTo("run", "edi", "esi"); /* save to EDI spot */ | 
					
						
							|  |  |  |             e("add  esi, byte 2\n"); | 
					
						
							|  |  |  |             LoadFromEA(op & 0x3f, BYTE_SIZE, 0); | 
					
						
							|  |  |  |             RestoreReg("run", "edi"); | 
					
						
							|  |  |  |             e("mov  edi, [edi]\n"); | 
					
						
							|  |  |  |             e("and  edi, byte 7\n");    /* same as modulo 8 */ | 
					
						
							|  |  |  |             e("btr  edx, edi\n");       /* bit->CF, clear */ | 
					
						
							|  |  |  |             e("setnc dh\n");        /* zero status of C->DH */ | 
					
						
							|  |  |  |             e("and  ah, 0xbf\n");   /* get rid of old Z */ | 
					
						
							|  |  |  |             e("shl  dh, 6\n");      /* put C in Z position */ | 
					
						
							|  |  |  |             e("or   ah, dh\n");     /* set the new Z */ | 
					
						
							|  |  |  |             WriteByte();                /* write back, EDI is cleared */ | 
					
						
							|  |  |  |         }         | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (((op & 0x3f) & 7) == 0) /* Dn is long */ | 
					
						
							|  |  |  |         EmitTiming(t); | 
					
						
							|  |  |  |     else                        /* mem is byte */ | 
					
						
							|  |  |  |         EmitTiming(t + TimingEA(op & 0x3f, BYTE_SIZE));         | 
					
						
							|  |  |  |     InstEnd(); | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int BCHG(unsigned short op, char *mnem, unsigned base_timing) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     unsigned    t; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (((op >> 6) & 7) != 5 && ((op >> 6) & 7) != 1)   return 0; | 
					
						
							|  |  |  |     if (op & 0x100)                 /* dynamic */ | 
					
						
							|  |  |  |     {     | 
					
						
							|  |  |  |         if (!CheckEA(op & 0x3f, "101111111000"))    return 0; | 
					
						
							|  |  |  |         if (!NumDecodedEA(op & 0x3f))               return 0; | 
					
						
							|  |  |  |         InstBegin(op, mnem, NumDecodedEA(op & 0x3f)); | 
					
						
							|  |  |  |         if (((op >> 3) & 7) == 0)   /* Dn is long */ | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             t = 8; | 
					
						
							|  |  |  |             e("and  edi, byte 7\n"); | 
					
						
							|  |  |  |             e("mov  ebx, [d+%d*4]\n", (op >> 9) & 7); /* bit # */ | 
					
						
							|  |  |  |             e("and  ebx, byte 31\n");           /* same as modulo 32 */ | 
					
						
							|  |  |  |             e("btc  dword [d+edi*4], ebx\n"); /* bit->CF, change */ | 
					
						
							|  |  |  |             e("setnc dh\n");        /* zero status of C->DH */ | 
					
						
							|  |  |  |             e("and  ah, 0xbf\n");   /* get rid of old Z */ | 
					
						
							|  |  |  |             e("shl  dh, 6\n");      /* put C in Z position */ | 
					
						
							|  |  |  |             e("or   ah, dh\n");     /* set the new Z */ | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else                        /* mem is byte */ | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             t = 8; | 
					
						
							|  |  |  |             LoadFromEA(op & 0x3f, BYTE_SIZE, 0); | 
					
						
							|  |  |  |             e("mov  edi, [d+%d*4]\n", (op >> 9) & 7); /* bit # */ | 
					
						
							|  |  |  |             e("and  edi, byte 7\n");             /* same as modulo 8 */ | 
					
						
							|  |  |  |             e("btc  edx, edi\n");                /* bit->CF, change */ | 
					
						
							|  |  |  |             e("setnc dh\n");        /* zero status of C->DH */ | 
					
						
							|  |  |  |             e("and  ah, 0xbf\n");   /* get rid of old Z */ | 
					
						
							|  |  |  |             e("shl  dh, 6\n");      /* put C in Z position */ | 
					
						
							|  |  |  |             e("or   ah, dh\n");     /* set the new Z */ | 
					
						
							|  |  |  |             WriteByte();                         /* clears EDI for us */ | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else if (!(op & 0x100))         /* static */ | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if (!CheckEA(op & 0x3f, "101111111000"))    return 0; | 
					
						
							|  |  |  |         if (!NumDecodedEA(op & 0x3f))               return 0; | 
					
						
							|  |  |  |         InstBegin(op, mnem, NumDecodedEA(op & 0x3f)); | 
					
						
							|  |  |  |         if (((op >> 3) & 7) == 0)   /* Dn is long */ | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             t = 12; | 
					
						
							|  |  |  |             e("and  edi, byte 7\n");    /* isolate Dn reg # */ | 
					
						
							|  |  |  |             e("mov  ebx, [esi]\n");     /* get bit # */ | 
					
						
							|  |  |  |             e("and  ebx, byte 31\n");   /* same as modulo 32 */ | 
					
						
							|  |  |  |             e("add  esi, byte 2\n"); | 
					
						
							|  |  |  |             e("btc  dword [d+edi*4], ebx\n"); /* bit->CF, change */ | 
					
						
							|  |  |  |             e("setnc dh\n");        /* zero status of C->DH */ | 
					
						
							|  |  |  |             e("and  ah, 0xbf\n");   /* get rid of old Z */ | 
					
						
							|  |  |  |             e("shl  dh, 6\n");      /* put C in Z position */ | 
					
						
							|  |  |  |             e("or   ah, dh\n");     /* set the new Z */ | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else                        /* mem is byte */ | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             t = 12; | 
					
						
							|  |  |  |             SaveRegTo("run", "edi", "esi"); /* save to EDI spot */ | 
					
						
							|  |  |  |             e("add  esi, byte 2\n"); | 
					
						
							|  |  |  |             LoadFromEA(op & 0x3f, BYTE_SIZE, 0); | 
					
						
							|  |  |  |             RestoreReg("run", "edi"); | 
					
						
							|  |  |  |             e("mov  edi, [edi]\n"); | 
					
						
							|  |  |  |             e("and  edi, byte 7\n");    /* same as modulo 8 */ | 
					
						
							|  |  |  |             e("btc  edx, edi\n");       /* bit->CF, change */ | 
					
						
							|  |  |  |             e("setnc dh\n");        /* zero status of C->DH */ | 
					
						
							|  |  |  |             e("and  ah, 0xbf\n");   /* get rid of old Z */ | 
					
						
							|  |  |  |             e("shl  dh, 6\n");      /* put C in Z position */ | 
					
						
							|  |  |  |             e("or   ah, dh\n");     /* set the new Z */ | 
					
						
							|  |  |  |             WriteByte();                /* write back, EDI is cleared */ | 
					
						
							|  |  |  |         }         | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (((op & 0x3f) & 7) == 0) /* Dn is long */ | 
					
						
							|  |  |  |         EmitTiming(t); | 
					
						
							|  |  |  |     else                        /* mem is byte */ | 
					
						
							|  |  |  |         EmitTiming(t + TimingEA(op & 0x3f, BYTE_SIZE));         | 
					
						
							|  |  |  |     InstEnd(); | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int ANDItoSR(unsigned short op, char *mnem, unsigned base_timing) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     InstBegin(op, mnem, 1); | 
					
						
							|  |  |  |     e("test byte [sr+1], 0x20\n");    /* in supervisor? */ | 
					
						
							|  |  |  |     e("jz   near exception_privilege_violation\n"); | 
					
						
							|  |  |  |     SaveCCR();  /* save flags to SR */ | 
					
						
							|  |  |  |     e("mov  edx, [esi]\n"); | 
					
						
							|  |  |  |     e("and  edx, 0xa71f\n");    /* mask out unwanted bits */ | 
					
						
							|  |  |  |     e("and  [sr], dx\n"); | 
					
						
							|  |  |  |     e("add  esi, byte 2\n"); | 
					
						
							|  |  |  |     LoadCCR();  /* get flags back */ | 
					
						
							|  |  |  |     e("test byte [sr+1], 0x20\n");    /* if we changed to User, swap SPs */ | 
					
						
							|  |  |  |     e("jnz  short .in_s\n"); | 
					
						
							|  |  |  |     e("mov  ebx, [a+7*4]\n"); | 
					
						
							|  |  |  |     e("mov  edx, [__sp]\n"); | 
					
						
							|  |  |  |     e("mov  [a+7*4], edx\n"); | 
					
						
							|  |  |  |     e("mov  [__sp], ebx\n"); | 
					
						
							|  |  |  |     SetUserAddressSpace();              /* map in user address space */ | 
					
						
							|  |  |  |     EmitLabel(".in_s"); | 
					
						
							|  |  |  |     EmitTiming(base_timing); | 
					
						
							|  |  |  |     InstEnd(); | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int UNLK(unsigned short op, char *mnem, unsigned base_timing) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     InstBegin(op, mnem, 8); | 
					
						
							|  |  |  |     e("and  edi, byte 7\n"); | 
					
						
							|  |  |  |     e("mov  ebx, [a+edi*4]\n");   /* An->SP */ | 
					
						
							|  |  |  |     SaveReg("run", "ebx");          /* to avoid addrclip() */ | 
					
						
							|  |  |  |     SaveReg("run", "edi"); | 
					
						
							|  |  |  |     ReadLong();                     /* (SP)->An */ | 
					
						
							|  |  |  |     RestoreReg("run", "edi"); | 
					
						
							|  |  |  |     RestoreReg("run", "ebx"); | 
					
						
							|  |  |  |     e("mov  [a+edi*4], edx\n"); | 
					
						
							|  |  |  |     e("add  ebx, byte 4\n"); | 
					
						
							|  |  |  |     e("mov  [a+7*4], ebx\n");     /* SP+4->SP */ | 
					
						
							|  |  |  |     EmitTiming(base_timing); | 
					
						
							|  |  |  |     InstEnd(); | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int LINK(unsigned short op, char *mnem, unsigned base_timing) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     InstBegin(op, mnem, 8); | 
					
						
							|  |  |  |     e("and  edi, byte 7\n"); | 
					
						
							|  |  |  |     e("mov  ebx, [a+7*4]\n"); /* EBX=SP */ | 
					
						
							|  |  |  |     e("sub  ebx, byte 4\n"); | 
					
						
							|  |  |  |     e("mov  edx, [a+edi*4]\n"); | 
					
						
							|  |  |  |     SaveReg("run", "ebx"); | 
					
						
							|  |  |  |     SaveReg("run", "edi"); | 
					
						
							|  |  |  |     WriteLong();                    /* An->(SP) */ | 
					
						
							|  |  |  |     RestoreReg("run", "edi"); | 
					
						
							|  |  |  |     RestoreReg("run", "ebx"); | 
					
						
							|  |  |  |     e("mov  [a+edi*4], ebx\n");   /* SP->An */ | 
					
						
							|  |  |  |     e("movsx    edx, word [esi]\n"); | 
					
						
							|  |  |  |     e("add      ebx, edx\n");       /* dn + SP->SP */ | 
					
						
							|  |  |  |     e("mov      [a+7*4], ebx\n"); | 
					
						
							|  |  |  |     e("add      esi, byte 2\n"); | 
					
						
							|  |  |  |     EmitTiming(base_timing); | 
					
						
							|  |  |  |     InstEnd(); | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int ROxMem(unsigned short op, char *mnem_unused, unsigned base_timing) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     unsigned    ea = op & 0x3f, dr = (op >> 8) & 1; | 
					
						
							|  |  |  |     char        mnem[4]; | 
					
						
							|  |  |  |     char        *mnem_t[] = { "ROR", "ROL" }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!CheckEA(ea, "001111111000"))   return 0; | 
					
						
							|  |  |  |     if (!NumDecodedEA(ea))              return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     strcpy(mnem, mnem_t[(op >> 8) & 1]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     InstBegin(op, mnem, NumDecodedEA(ea)); | 
					
						
							|  |  |  |     LoadFromEA(ea, WORD_SIZE, 0); | 
					
						
							|  |  |  |     if (dr) /* left */ | 
					
						
							|  |  |  |         e("rol  dx, byte 1\n"); | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |         e("ror  dx, byte 1\n"); | 
					
						
							|  |  |  |     e("setc al\n");     /* AL=CF */ | 
					
						
							|  |  |  |     e("test dx, dx\n"); /* CF is cleared */ | 
					
						
							|  |  |  |     e("lahf\n"); | 
					
						
							|  |  |  |     e("or   ah, al\n"); /* put in CF */ | 
					
						
							|  |  |  |     e("xor  al, al\n"); /* V is always cleared */ | 
					
						
							|  |  |  |     WriteWord();    /* write back to mem */ | 
					
						
							|  |  |  |     EmitTiming(base_timing + TimingEA(ea, WORD_SIZE)); | 
					
						
							|  |  |  |     InstEnd(); | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int ROxReg(unsigned short op, char *mnem_unused, unsigned base_timing) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     unsigned    size, t, opr_i, count; | 
					
						
							|  |  |  |     char        *opr[] =    { "ror", "rol" }; | 
					
						
							|  |  |  |     char        mnem[4]; | 
					
						
							|  |  |  |     char        *mnem_t[] = { "ROR", "ROL" }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     switch ((op >> 6) & 3) | 
					
						
							|  |  |  |     {   case 0:     size = BYTE_SIZE; break; | 
					
						
							|  |  |  |         case 1:     size = WORD_SIZE; break; | 
					
						
							|  |  |  |         case 2:     size = LONG_SIZE; break; | 
					
						
							|  |  |  |         default:    return 0;   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     opr_i = (op >> 8) & 1; | 
					
						
							|  |  |  |     strcpy(mnem, mnem_t[opr_i]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     count = (op >> 9) & 7; | 
					
						
							|  |  |  |     if (!count) count = 8; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     InstBegin(op, mnem, 8); /* 8 regs */ | 
					
						
							|  |  |  |     e("and  edi, byte 7\n"); | 
					
						
							|  |  |  |     if ((op >> 5) & 1)  /* reg contains count */ | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         e("mov  ebx, ecx\n");   /* save ECX */ | 
					
						
							|  |  |  |         e("mov  ecx, [d+%d*4]\n", (op >> 9) & 7); | 
					
						
							|  |  |  |         e("and  ecx, byte 0x3f\n"); /* modulo 64 */ | 
					
						
							|  |  |  |         e("mov  edx, [d+edi*4]\n"); | 
					
						
							|  |  |  |         switch (size) | 
					
						
							|  |  |  |         {   case BYTE_SIZE: e("%s   dl, cl\n", opr[opr_i]); e("setc al\n"); e("test dl, dl\n"); break; | 
					
						
							|  |  |  |             case WORD_SIZE: e("%s   dx, cl\n", opr[opr_i]); e("setc al\n"); e("test dx, dx\n"); break; | 
					
						
							|  |  |  |             case LONG_SIZE: e("%s   edx, cl\n", opr[opr_i]); e("setc al\n"); e("test edx, edx\n"); break; | 
					
						
							|  |  |  |         }         | 
					
						
							|  |  |  |         e("lahf\n"); | 
					
						
							|  |  |  |         e("test cl, cl\n"); /* if shift count of 0, X is unaffected */ | 
					
						
							|  |  |  |         e("jnz  short .not_zero\n"); | 
					
						
							|  |  |  |         e("xor      al, al\n"); /* clear CF, count was 0 */ | 
					
						
							|  |  |  |         EmitLabel(".not_zero"); | 
					
						
							|  |  |  |         e("or   ah, al\n");     /* put CF in with rest of flags */ | 
					
						
							|  |  |  |         e("xor  al, al\n");     /* V always cleared */ | 
					
						
							|  |  |  |         switch (size)   /* write back results */ | 
					
						
							|  |  |  |         {   case BYTE_SIZE: e("mov  [d+edi*4], dl\n", opr[opr_i]); break; | 
					
						
							|  |  |  |             case WORD_SIZE: e("mov  [d+edi*4], dx\n", opr[opr_i]); break; | 
					
						
							|  |  |  |             case LONG_SIZE: e("mov  [d+edi*4], edx\n", opr[opr_i]); break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         /* timing */ | 
					
						
							|  |  |  |         switch (size) | 
					
						
							|  |  |  |         {   case BYTE_SIZE: | 
					
						
							|  |  |  |             case WORD_SIZE: t = 6; break; | 
					
						
							|  |  |  |             case LONG_SIZE: t = 8; break;   } | 
					
						
							|  |  |  |         e("shl  cl, byte 1\n"); /* 2n */ | 
					
						
							|  |  |  |         e("add  cl, byte %d\n", t); | 
					
						
							|  |  |  |         e("neg  ecx\n"); | 
					
						
							|  |  |  |         e("add  ecx, ebx\n"); | 
					
						
							|  |  |  |         e("js   near Turbo68KRun_done\n"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else                /* immediate count */ | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         e("mov  edx, [d+edi*4]\n"); | 
					
						
							|  |  |  |         switch (size) | 
					
						
							|  |  |  |         {   case BYTE_SIZE: e("%s   dl, byte %d\n", opr[opr_i], count); e("setc al\n"); e("test dl, dl\n"); break; | 
					
						
							|  |  |  |             case WORD_SIZE: e("%s   dx, byte %d\n", opr[opr_i], count); e("setc al\n"); e("test dx, dx\n"); break; | 
					
						
							|  |  |  |             case LONG_SIZE: e("%s   edx, byte %d\n", opr[opr_i], count); e("setc al\n"); e("test edx, edx\n"); break; | 
					
						
							|  |  |  |         }         | 
					
						
							|  |  |  |         e("lahf\n"); | 
					
						
							|  |  |  |         e("or       ah, al\n"); /* set CF */ | 
					
						
							|  |  |  |         e("xor  al, al\n"); /* V always cleared */ | 
					
						
							|  |  |  |         switch (size)   /* write back results */ | 
					
						
							|  |  |  |         {   case BYTE_SIZE: e("mov  [d+edi*4], dl\n"); break; | 
					
						
							|  |  |  |             case WORD_SIZE: e("mov  [d+edi*4], dx\n"); break; | 
					
						
							|  |  |  |             case LONG_SIZE: e("mov  [d+edi*4], edx\n"); break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         switch (size) | 
					
						
							|  |  |  |         {   case BYTE_SIZE: | 
					
						
							|  |  |  |             case WORD_SIZE: t = 6; break; | 
					
						
							|  |  |  |             case LONG_SIZE: t = 8; break;   } | 
					
						
							|  |  |  |         EmitTiming(t + count * 2); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     InstEnd(); | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int EXT(unsigned short op, char *mnem, unsigned base_timing) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     unsigned    opmode = (op >> 6) & 7; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (opmode != 2 && opmode != 3) return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     InstBegin(op, mnem, 8); | 
					
						
							|  |  |  |     e("and  edi, byte 7\n"); | 
					
						
							|  |  |  |     e("mov  edx, [d+edi*4]\n"); | 
					
						
							|  |  |  |     if (opmode == 2)    /* byte -> word */ | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         e("movsx    dx, dl\n"); | 
					
						
							|  |  |  |         e("mov      [d+edi*4], dx\n"); | 
					
						
							|  |  |  |         e("test     dx, dx\n"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else if (opmode == 3)   /* word -> long */ | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         e("movsx    edx, dx\n"); | 
					
						
							|  |  |  |         e("mov      [d+edi*4], edx\n"); | 
					
						
							|  |  |  |         e("test     edx, edx\n"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else if (opmode == 7)   /* byte -> long */ | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         /*
 | 
					
						
							|  |  |  |          * Note: This code is never executed. EXTB is present on 68020 and | 
					
						
							|  |  |  |          * higher processors. Turbo68K was only intended to emulate the | 
					
						
							|  |  |  |          * 68000. This code was an accident, but it will be kept here in case | 
					
						
							|  |  |  |          * in the future it is needed. | 
					
						
							|  |  |  |          */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         e("movsx    edx, dl\n"); | 
					
						
							|  |  |  |         e("mov      [d+edi*4], edx\n"); | 
					
						
							|  |  |  |         e("test     edx, edx\n"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     e("lahf\n");    /* CF is already cleared by TEST */ | 
					
						
							|  |  |  |     e("xor  al, al\n"); /* V always cleared */ | 
					
						
							|  |  |  |     EmitTiming(base_timing); | 
					
						
							|  |  |  |     InstEnd(); | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int ROXxMem(unsigned short op, char *mnem_unused, unsigned base_timing) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     unsigned    ea = op & 0x3f, dr = (op >> 8) & 1; | 
					
						
							|  |  |  |     char        mnem[5]; | 
					
						
							|  |  |  |     char        *mnem_t[] = { "ROXR", "ROXL" }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!CheckEA(ea, "001111111000"))   return 0; | 
					
						
							|  |  |  |     if (!NumDecodedEA(ea))              return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     strcpy(mnem, mnem_t[(op >> 8) & 1]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     InstBegin(op, mnem, NumDecodedEA(ea)); | 
					
						
							|  |  |  |     LoadFromEA(ea, WORD_SIZE, 0); | 
					
						
							|  |  |  |     e("shr  byte [x], 1\n"); | 
					
						
							|  |  |  |     if (dr) /* left */ | 
					
						
							|  |  |  |         e("rcl  dx, byte 1\n"); | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |         e("rcr  dx, byte 1\n"); | 
					
						
							|  |  |  |     e("setc al\n");     /* AL=CF */ | 
					
						
							|  |  |  |     e("setc byte [x]\n"); | 
					
						
							|  |  |  |     e("test dx, dx\n"); /* CF is cleared */ | 
					
						
							|  |  |  |     e("lahf\n"); | 
					
						
							|  |  |  |     e("or   ah, al\n"); /* put in CF */ | 
					
						
							|  |  |  |     e("xor  al, al\n"); | 
					
						
							|  |  |  |     WriteWord();    /* write back to mem */ | 
					
						
							|  |  |  |     EmitTiming(base_timing + TimingEA(ea, WORD_SIZE)); | 
					
						
							|  |  |  |     InstEnd(); | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int ROXxReg(unsigned short op, char *mnem_unused, unsigned base_timing) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     unsigned    size, t, opr_i, count; | 
					
						
							|  |  |  |     char        *opr[] =    { "rcr", "rcl" }; | 
					
						
							|  |  |  |     char        mnem[5]; | 
					
						
							|  |  |  |     char        *mnem_t[] = { "ROXR", "ROXL" }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     switch ((op >> 6) & 3) | 
					
						
							|  |  |  |     {   case 0:     size = BYTE_SIZE; break; | 
					
						
							|  |  |  |         case 1:     size = WORD_SIZE; break; | 
					
						
							|  |  |  |         case 2:     size = LONG_SIZE; break; | 
					
						
							|  |  |  |         default:    return 0;   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     opr_i = (op >> 8) & 1; | 
					
						
							|  |  |  |     strcpy(mnem, mnem_t[opr_i]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     count = (op >> 9) & 7; | 
					
						
							|  |  |  |     if (!count) count = 8; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     InstBegin(op, mnem, 8); /* 8 regs */ | 
					
						
							|  |  |  |     e("and  edi, byte 7\n"); | 
					
						
							|  |  |  |     if ((op >> 5) & 1)  /* reg contains count */ | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         e("mov  ebx, ecx\n");   /* save ECX */ | 
					
						
							|  |  |  |         e("mov  ecx, [d+%d*4]\n", (op >> 9) & 7); | 
					
						
							|  |  |  |         e("and  ecx, byte 0x3f\n"); /* modulo 64 */ | 
					
						
							|  |  |  |         e("mov  dl, [x]\n");   | 
					
						
							|  |  |  |         e("shr  dl, byte 1\n");     /* X->CF so we can use RCL/RCR */ | 
					
						
							|  |  |  |         e("mov  edx, [d+edi*4]\n"); | 
					
						
							|  |  |  |         switch (size) | 
					
						
							|  |  |  |         {   case BYTE_SIZE: e("%s   dl, cl\n", opr[opr_i]); e("setc al\n"); e("test dl, dl\n"); break; | 
					
						
							|  |  |  |             case WORD_SIZE: e("%s   dx, cl\n", opr[opr_i]); e("setc al\n"); e("test dx, dx\n"); break; | 
					
						
							|  |  |  |             case LONG_SIZE: e("%s   edx, cl\n", opr[opr_i]); e("setc al\n"); e("test edx, edx\n"); break; | 
					
						
							|  |  |  |         }         | 
					
						
							|  |  |  |         e("lahf\n"); | 
					
						
							|  |  |  |         e("test cl, cl\n"); /* if shift count of 0, X is unaffected */ | 
					
						
							|  |  |  |         e("jz   short .zero_count\n"); | 
					
						
							|  |  |  |         e("or       ah, al\n"); /* set CF */ | 
					
						
							|  |  |  |         e("test     ah, 1\n");  /* CF */ | 
					
						
							|  |  |  |         e("setnz    byte [x]\n"); | 
					
						
							|  |  |  |         e("jmp      short .skip\n"); | 
					
						
							|  |  |  |         EmitLabel(".zero_count"); | 
					
						
							|  |  |  |         e("mov  al, [x]\n");  /* X->C */ | 
					
						
							|  |  |  |         e("and  al, byte 1\n"); | 
					
						
							|  |  |  |         e("and  ah, 0xfe\n");   /* get rid of old C before putting new C in */ | 
					
						
							|  |  |  |         e("or   ah, al\n"); | 
					
						
							|  |  |  |         EmitLabel(".skip"); | 
					
						
							|  |  |  |         e("xor  al, al\n"); /* V always cleared */ | 
					
						
							|  |  |  |         switch (size)   /* write back results */ | 
					
						
							|  |  |  |         {   case BYTE_SIZE: e("mov  [d+edi*4], dl\n", opr[opr_i]); break; | 
					
						
							|  |  |  |             case WORD_SIZE: e("mov  [d+edi*4], dx\n", opr[opr_i]); break; | 
					
						
							|  |  |  |             case LONG_SIZE: e("mov  [d+edi*4], edx\n", opr[opr_i]); break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /* timing */ | 
					
						
							|  |  |  |         switch (size) | 
					
						
							|  |  |  |         {   case BYTE_SIZE: | 
					
						
							|  |  |  |             case WORD_SIZE: t = 6; break; | 
					
						
							|  |  |  |             case LONG_SIZE: t = 8; break;   } | 
					
						
							|  |  |  |         e("shl  cl, byte 1\n"); /* 2n */ | 
					
						
							|  |  |  |         e("add  cl, byte %d\n", t); | 
					
						
							|  |  |  |         e("neg  ecx\n"); | 
					
						
							|  |  |  |         e("add  ecx, ebx\n"); | 
					
						
							|  |  |  |         e("js   near Turbo68KRun_done\n"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else                /* immediate count */ | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         e("mov  dl, [x]\n");   | 
					
						
							|  |  |  |         e("shr  dl, byte 1\n");     /* X->CF so we can use RCL/RCR */     | 
					
						
							|  |  |  |         e("mov  edx, [d+edi*4]\n"); | 
					
						
							|  |  |  |         switch (size) | 
					
						
							|  |  |  |         {   case BYTE_SIZE: e("%s   dl, byte %d\n", opr[opr_i], count); e("setc al\n"); e("test dl, dl\n"); break; | 
					
						
							|  |  |  |             case WORD_SIZE: e("%s   dx, byte %d\n", opr[opr_i], count); e("setc al\n"); e("test dx, dx\n"); break; | 
					
						
							|  |  |  |             case LONG_SIZE: e("%s   edx, byte %d\n", opr[opr_i], count); e("setc al\n"); e("test edx, edx\n"); break; | 
					
						
							|  |  |  |         }         | 
					
						
							|  |  |  |         e("lahf\n"); | 
					
						
							|  |  |  |         e("or       ah, al\n"); /* set CF */ | 
					
						
							|  |  |  |         e("test     ah, 1\n");  /* CF */ | 
					
						
							|  |  |  |         e("setnz    byte [x]\n"); | 
					
						
							|  |  |  |         e("xor  al, al\n"); /* V always cleared */ | 
					
						
							|  |  |  |         switch (size)   /* write back results */ | 
					
						
							|  |  |  |         {   case BYTE_SIZE: e("mov  [d+edi*4], dl\n", opr[opr_i]); break; | 
					
						
							|  |  |  |             case WORD_SIZE: e("mov  [d+edi*4], dx\n", opr[opr_i]); break; | 
					
						
							|  |  |  |             case LONG_SIZE: e("mov  [d+edi*4], edx\n", opr[opr_i]); break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         switch (size) | 
					
						
							|  |  |  |         {   case BYTE_SIZE: | 
					
						
							|  |  |  |             case WORD_SIZE: t = 6; break; | 
					
						
							|  |  |  |             case LONG_SIZE: t = 8; break;   } | 
					
						
							|  |  |  |         EmitTiming(t + count * 2); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     InstEnd(); | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int MOVEtoCCR(unsigned short op, char *mnem, unsigned base_timing) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     unsigned    ea = op & 0x3f; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!CheckEA(ea, "101111111111"))   return 0; | 
					
						
							|  |  |  |     if (!NumDecodedEA(ea))              return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     InstBegin(op, mnem, NumDecodedEA(ea)); | 
					
						
							|  |  |  |     LoadFromEA(ea, WORD_SIZE, 0); | 
					
						
							|  |  |  |     e("mov  [sr], dl\n"); | 
					
						
							|  |  |  |     LoadCCR();  /* update flags */ | 
					
						
							|  |  |  |     EmitTiming(base_timing + TimingEA(ea, WORD_SIZE));  /* technically, word
 | 
					
						
							|  |  |  |                                                            sized */ | 
					
						
							|  |  |  |     InstEnd(); | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int LSxMem(unsigned short op, char *mnem_unused, unsigned base_timing) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     unsigned    ea = op & 0x3f, dr = (op >> 8) & 1; | 
					
						
							|  |  |  |     char        mnem[4]; | 
					
						
							|  |  |  |     char        *mnem_t[] = { "LSR", "LSL" }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!CheckEA(ea, "001111111000"))   return 0; | 
					
						
							|  |  |  |     if (!NumDecodedEA(ea))              return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     strcpy(mnem, mnem_t[(op >> 8) & 1]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     InstBegin(op, mnem, NumDecodedEA(ea)); | 
					
						
							|  |  |  |     LoadFromEA(ea, WORD_SIZE, 0); | 
					
						
							|  |  |  |     if (dr) /* left */ | 
					
						
							|  |  |  |         e("shl  dx, byte 1\n"); | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |         e("shr  dx, byte 1\n"); | 
					
						
							|  |  |  |     e("lahf\n"); | 
					
						
							|  |  |  |     e("setc byte [x]\n"); | 
					
						
							|  |  |  |     e("xor  al, al\n"); | 
					
						
							|  |  |  |     WriteWord();    /* write back to mem */ | 
					
						
							|  |  |  |     EmitTiming(base_timing + TimingEA(ea, WORD_SIZE)); | 
					
						
							|  |  |  |     InstEnd(); | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int LSxReg(unsigned short op, char *mnem_unused, unsigned base_timing) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     unsigned    size, t, opr_i, count; | 
					
						
							|  |  |  |     char        *opr[] =    { "shr", "shl" }; | 
					
						
							|  |  |  |     char        mnem[4]; | 
					
						
							|  |  |  |     char        *mnem_t[] = { "LSR", "LSL" }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     switch ((op >> 6) & 3) | 
					
						
							|  |  |  |     {   case 0:     size = BYTE_SIZE; break; | 
					
						
							|  |  |  |         case 1:     size = WORD_SIZE; break; | 
					
						
							|  |  |  |         case 2:     size = LONG_SIZE; break; | 
					
						
							|  |  |  |         default:    return 0;   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     opr_i = (op >> 8) & 1; | 
					
						
							|  |  |  |     strcpy(mnem, mnem_t[opr_i]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     count = (op >> 9) & 7; | 
					
						
							|  |  |  |     if (!count) count = 8; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     InstBegin(op, mnem, 8); /* 8 regs */ | 
					
						
							|  |  |  |     e("and  edi, byte 7\n"); | 
					
						
							|  |  |  |     if ((op >> 5) & 1)  /* reg contains count */ | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         e("mov  ebx, ecx\n");   /* save ECX */ | 
					
						
							|  |  |  |         e("mov  ecx, [d+%d*4]\n", (op >> 9) & 7); | 
					
						
							|  |  |  |         e("and  ecx, byte 0x3f\n");     /* modulo 64 */ | 
					
						
							|  |  |  |         e("mov  edx, [d+edi*4]\n");   /* get register... */ | 
					
						
							|  |  |  |         switch (size) | 
					
						
							|  |  |  |         {   case BYTE_SIZE: e("%s   dl, cl\n", opr[opr_i]); | 
					
						
							|  |  |  |                             e("setc al\n"); /* CF -> AL */ | 
					
						
							|  |  |  |                             e("test dl, dl\n"); | 
					
						
							|  |  |  |                             e("mov  [d+edi*4], dl\n");    /* MOV does not
 | 
					
						
							|  |  |  |                                                                affect flags */ | 
					
						
							|  |  |  |                             break;   | 
					
						
							|  |  |  |             case WORD_SIZE: e("%s   dx, cl\n", opr[opr_i]); | 
					
						
							|  |  |  |                             e("setc al\n"); | 
					
						
							|  |  |  |                             e("test dx, dx\n"); | 
					
						
							|  |  |  |                             e("mov  [d+edi*4], dx\n"); | 
					
						
							|  |  |  |                             break; | 
					
						
							|  |  |  |             case LONG_SIZE: e("%s   edx, cl\n", opr[opr_i]); | 
					
						
							|  |  |  |                             e("setc al\n"); | 
					
						
							|  |  |  |                             e("test edx, edx\n"); | 
					
						
							|  |  |  |                             e("mov  [d+edi*4], edx\n"); | 
					
						
							|  |  |  |                             break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         e("lahf\n"); | 
					
						
							|  |  |  |         e("test cl, cl\n"); /* if zero count... */ | 
					
						
							|  |  |  |         e("jz   short .zero\n"); | 
					
						
							|  |  |  |         e("or   ah, al\n"); /* new CF... the first test cleared old C */ | 
					
						
							|  |  |  |         e("test al, 1\n");  /* C->X */ | 
					
						
							|  |  |  |         e("setnz    byte [x]\n"); | 
					
						
							|  |  |  |         EmitLabel(".zero"); | 
					
						
							|  |  |  |         e("xor  al, al\n"); /* V cleared */ | 
					
						
							|  |  |  |         /* timing */ | 
					
						
							|  |  |  |         switch (size) | 
					
						
							|  |  |  |         {   case BYTE_SIZE: | 
					
						
							|  |  |  |             case WORD_SIZE: t = 6; break; | 
					
						
							|  |  |  |             case LONG_SIZE: t = 8; break;   } | 
					
						
							|  |  |  |         e("shl  cl, byte 1\n"); /* 2n */ | 
					
						
							|  |  |  |         e("add  cl, byte %d\n", t); | 
					
						
							|  |  |  |         e("neg  ecx\n"); | 
					
						
							|  |  |  |         e("add  ecx, ebx\n"); | 
					
						
							|  |  |  |         e("js   near Turbo68KRun_done\n"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else                /* immediate count */ | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         e("%s   ", opr[opr_i]); | 
					
						
							|  |  |  |         switch (size) | 
					
						
							|  |  |  |         {   case BYTE_SIZE: e("byte "); break; | 
					
						
							|  |  |  |             case WORD_SIZE: e("word "); break; | 
					
						
							|  |  |  |             case LONG_SIZE: e("dword "); break; } | 
					
						
							|  |  |  |         e("[d+edi*4], %d\n", count); | 
					
						
							|  |  |  |         e("lahf\n"); | 
					
						
							|  |  |  |         e("setc byte [x]\n"); | 
					
						
							|  |  |  |         e("xor  al, al\n"); | 
					
						
							|  |  |  |         switch (size) | 
					
						
							|  |  |  |         {   case BYTE_SIZE: | 
					
						
							|  |  |  |             case WORD_SIZE: t = 6; break; | 
					
						
							|  |  |  |             case LONG_SIZE: t = 8; break;   } | 
					
						
							|  |  |  |         EmitTiming(t + count * 2); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     InstEnd(); | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int NOP(unsigned short op, char *mnem, unsigned base_timing) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     InstBegin(op, mnem, 1); | 
					
						
							|  |  |  |     EmitTiming(base_timing); | 
					
						
							|  |  |  |     InstEnd(); | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int CLR(unsigned short op, char *mnem, unsigned base_timing) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     unsigned    ea = op & 0x3f, size, t; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!CheckEA(ea, "101111111000"))   return 0; | 
					
						
							|  |  |  |     if (!NumDecodedEA(ea))              return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     switch ((op >> 6) & 3) | 
					
						
							|  |  |  |     {   case 0:     size = BYTE_SIZE; break; | 
					
						
							|  |  |  |         case 1:     size = WORD_SIZE; break; | 
					
						
							|  |  |  |         case 2:     size = LONG_SIZE; break; | 
					
						
							|  |  |  |         default:    return 0;   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     InstBegin(op, mnem, NumDecodedEA(ea)); | 
					
						
							|  |  |  |     e("mov  eax, 0x4000\n");    /* Z always set, everything else cleared */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (mpu == 68000 && dummyread && (ea >> 3)) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         /*
 | 
					
						
							|  |  |  |          * Emulate the dummy read for memory addressing modes, if necessary. | 
					
						
							|  |  |  |          * We only do it for memory modes, because it really can't make any | 
					
						
							|  |  |  |          * difference if the destination is a register! | 
					
						
							|  |  |  |          */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         LoadFromEA(ea, size, 0);    /* do the dummy read */ | 
					
						
							|  |  |  |         e("xor  edx, edx\n");       /* now, write a 0 */ | 
					
						
							|  |  |  |         switch (size)               /* write */ | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |         case BYTE_SIZE: WriteByte(); break; | 
					
						
							|  |  |  |         case WORD_SIZE: WriteWord(); break; | 
					
						
							|  |  |  |         case LONG_SIZE: WriteLong(); break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         /*
 | 
					
						
							|  |  |  |          * This method is quicker, since dummy reads aren't needed | 
					
						
							|  |  |  |          */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         e("xor  edx, edx\n"); | 
					
						
							|  |  |  |         StoreToEAUsingEDI(ea, size, 0); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     switch (size) | 
					
						
							|  |  |  |     {   case BYTE_SIZE: | 
					
						
							|  |  |  |         case WORD_SIZE: | 
					
						
							|  |  |  |             if ((ea >> 3) == 0) t = 4;  /* reg */ | 
					
						
							|  |  |  |             else                t = 8 + TimingEA(ea, size); /* mem */ | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         case LONG_SIZE: | 
					
						
							|  |  |  |             if ((ea >> 3) == 0) t = 6;  /* reg */ | 
					
						
							|  |  |  |             else                t = 12 + TimingEA(ea, size); /* mem */ | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     EmitTiming(t); | 
					
						
							|  |  |  |     InstEnd(); | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int ORItoSR(unsigned short op, char *mnem, unsigned base_timing) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     InstBegin(op, mnem, 1); | 
					
						
							|  |  |  |     e("test byte [sr+1], 0x20\n");      /* in supervisor? */ | 
					
						
							|  |  |  |     e("jz   near exception_privilege_violation\n"); | 
					
						
							|  |  |  |     SaveCCR();  /* save flags to SR */ | 
					
						
							|  |  |  |     e("mov  edx, [esi]\n"); | 
					
						
							|  |  |  |     e("and  edx, 0xa71f\n");            /* mask out unwanted bits */ | 
					
						
							|  |  |  |     e("or   [sr], dx\n"); | 
					
						
							|  |  |  |     e("add  esi, byte 2\n"); | 
					
						
							|  |  |  |     LoadCCR();  /* get flags back */ | 
					
						
							|  |  |  |     EmitTiming(base_timing); | 
					
						
							|  |  |  |     InstEnd(); | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int MOVEfromSR(unsigned short op, char *mnem, unsigned base_timing) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     unsigned    ea = op & 0x3f; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!CheckEA(ea, "101111111000"))   return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     InstBegin(op, mnem, 1); | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |      * This instruction is not privileged for 68000 and 68008 processors. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     if (mpu == 68010) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         e("test byte [sr+1], 0x20\n");    /* in supervisor? */ | 
					
						
							|  |  |  |         e("jz   near exception_privilege_violation\n"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     SaveCCR();  /* save flags to SR */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (mpu == 68000 && dummyread && (ea >> 3)) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         /*
 | 
					
						
							|  |  |  |          * When dummy reads are enabled, and the EA mode is not register, we | 
					
						
							|  |  |  |          * perform a dummy read | 
					
						
							|  |  |  |          */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         LoadFromEA(ea, WORD_SIZE, 0); | 
					
						
							|  |  |  |         e("mov  edx, [sr]\n"); | 
					
						
							|  |  |  |         WriteWord(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         e("mov  edx, [sr]\n");    /* get SR */ | 
					
						
							|  |  |  |         StoreToEAUsingEDI(ea, WORD_SIZE, 0); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     LoadCCR();  /* get back SR */ | 
					
						
							|  |  |  |     if ((ea >> 3) == 0)         | 
					
						
							|  |  |  |         EmitTiming(6); | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |         EmitTiming(8 + TimingEA(ea, WORD_SIZE)); | 
					
						
							|  |  |  |     InstEnd(); | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int ArithmeticA(unsigned short op, char *mnem, unsigned base_timing) | 
					
						
							|  |  |  | {     | 
					
						
							|  |  |  |     int     size = UNKNOWN_SIZE, t; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!CheckEA(op & 0x3f, "111111111111"))    /* check EA mode */ | 
					
						
							|  |  |  |         return 0; | 
					
						
							|  |  |  |     if (!NumDecodedEA(op & 0x3f))               /* check if decoded this EA */ | 
					
						
							|  |  |  |         return 0; | 
					
						
							|  |  |  |     switch ((op >> 6) & 7)  /* set allowed sizes */ | 
					
						
							|  |  |  |     {   case 3:     size = WORD_SIZE; break; | 
					
						
							|  |  |  |         case 7:     size = LONG_SIZE; break; | 
					
						
							|  |  |  |         default:    return 0; } | 
					
						
							|  |  |  |     if (((op >> 12) & 0xf) != 0xd && ((op >> 12) & 0xf) != 9)   return 0; | 
					
						
							|  |  |  |           | 
					
						
							|  |  |  |     InstBegin(op, mnem, NumDecodedEA(op & 0x3f));     | 
					
						
							|  |  |  |     LoadFromEA(op & 0x3f, size, 1);                 /* load */ | 
					
						
							|  |  |  |     if (((op >> 12) & 0xf) == 0xd)  /* ADDA */ | 
					
						
							|  |  |  |         e("add  [a+%d*4], edx\n", (op >> 9) & 7); /* store */ | 
					
						
							|  |  |  |     else                            /* SUBA */ | 
					
						
							|  |  |  |         e("sub  [a+%d*4], edx\n", (op >> 9) & 7); | 
					
						
							|  |  |  |     switch (size) | 
					
						
							|  |  |  |     {   case WORD_SIZE: t = 8; break; | 
					
						
							|  |  |  |         case LONG_SIZE: t = 6; | 
					
						
							|  |  |  |                         if (((op & 0x3f) >> 3) == 0) t += 2;    /* Dn */ | 
					
						
							|  |  |  |                         else if (((op & 0x3f) >> 3) == 1) t += 2;   /* An */ | 
					
						
							|  |  |  |                         else if (((op & 0x3f) >> 3) == 7 && (op & 7) == 4) | 
					
						
							|  |  |  |                             t += 2;                             /* #<data> */ | 
					
						
							|  |  |  |                         break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     EmitTiming(TimingEA(op & 0x3f, size) + t); | 
					
						
							|  |  |  |     InstEnd(); | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int ASxMem(unsigned short op, char *mnem_unused, unsigned base_timing) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     unsigned    ea = op & 0x3f, dr = (op >> 8) & 1; | 
					
						
							|  |  |  |     char        mnem[4]; | 
					
						
							|  |  |  |     char        *mnem_t[] = { "ASR", "ASL" }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!CheckEA(ea, "001111111000"))   return 0; | 
					
						
							|  |  |  |     if (!NumDecodedEA(ea))              return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     strcpy(mnem, mnem_t[(op >> 8) & 1]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     InstBegin(op, mnem, NumDecodedEA(ea)); | 
					
						
							|  |  |  |     LoadFromEA(ea, WORD_SIZE, 0); | 
					
						
							|  |  |  |     if (dr) /* left */ | 
					
						
							|  |  |  |         e("shl  dx, byte 1\n"); | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |         e("sar  dx, byte 1\n"); | 
					
						
							|  |  |  |     e("lahf\n"); | 
					
						
							|  |  |  |     e("setc byte [x]\n"); | 
					
						
							|  |  |  |     if (dr) /* only for left shifts, right shifts don't change the MSB */ | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         e("sets al\n");         /* AL=current MSB */ | 
					
						
							|  |  |  |         e("adc  al, byte 0\n"); /* CF contains old MSB */ | 
					
						
							|  |  |  |         e("and  al, 1\n");      /* preserve only the flag bit */ | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     WriteWord();    /* write back to mem */ | 
					
						
							|  |  |  |     EmitTiming(base_timing + TimingEA(ea, WORD_SIZE)); | 
					
						
							|  |  |  |     InstEnd(); | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int ASxReg(unsigned short op, char *mnem_unused, unsigned base_timing) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     unsigned    i, size, t = 0, opr_i, count; | 
					
						
							|  |  |  |     char        mnem[4]; | 
					
						
							|  |  |  |     char        *mnem_t[] = { "ASR", "ASL" }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     switch ((op >> 6) & 3) | 
					
						
							|  |  |  |     {   case 0:     size = BYTE_SIZE; break; | 
					
						
							|  |  |  |         case 1:     size = WORD_SIZE; break; | 
					
						
							|  |  |  |         case 2:     size = LONG_SIZE; break; | 
					
						
							|  |  |  |         default:    return 0;   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     opr_i = (op >> 8) & 1; | 
					
						
							|  |  |  |     strcpy(mnem, mnem_t[opr_i]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     count = (op >> 9) & 7; | 
					
						
							|  |  |  |     if (!count) count = 8; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     InstBegin(op, mnem, 8); /* 8 regs */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     e("and  edi, byte 7\n"); | 
					
						
							|  |  |  |     if ((op >> 5) & 1)  /* reg contains count */ | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if (opr_i)  /* ASL */ | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             e("xor  al, al\n"); | 
					
						
							|  |  |  |             SaveReg("run", "edi");      /* save EDI */ | 
					
						
							|  |  |  |             e("mov  edx, [d+edi*4]\n"); /* get reg to shift */ | 
					
						
							|  |  |  |             e("mov  edi, [d+%d*4]\n", (op >> 9) & 7); | 
					
						
							|  |  |  |             e("and  edi, byte 0x3f\n"); /* modulo 64 */ | 
					
						
							|  |  |  |             e("jz   short .zero_shift\n"); | 
					
						
							|  |  |  |             EmitLabel(".loop"); | 
					
						
							|  |  |  |             e("shl  "); | 
					
						
							|  |  |  |             switch (size) | 
					
						
							|  |  |  |             {   case BYTE_SIZE: e("dl, "); break; | 
					
						
							|  |  |  |                 case WORD_SIZE: e("dx, "); break; | 
					
						
							|  |  |  |                 case LONG_SIZE: e("edx, "); break;  } | 
					
						
							|  |  |  |             e("1\n"); | 
					
						
							|  |  |  |             e("setc bl\n");     /* old MSB */ | 
					
						
							|  |  |  |             e("sets bh\n");     /* new MSB */ | 
					
						
							|  |  |  |             e("xor  bh, bl\n"); /* detect change */ | 
					
						
							|  |  |  |             e("or   al, bh\n"); /* reflect change in V */ | 
					
						
							|  |  |  |             e("sub  ecx, byte 2\n");    /* each rotation=2 cycles */ | 
					
						
							|  |  |  |             e("dec  edi\n"); | 
					
						
							|  |  |  |             e("jnz  short .loop\n"); | 
					
						
							|  |  |  |             RestoreReg("run", "edi"); | 
					
						
							|  |  |  |             switch (size)       /* store reg, get flags */ | 
					
						
							|  |  |  |             {   case BYTE_SIZE: e("mov  [d+edi*4], dl\n"); | 
					
						
							|  |  |  |                                 e("test dl, dl\n"); break; | 
					
						
							|  |  |  |                 case WORD_SIZE: e("mov  [d+edi*4], dx\n"); | 
					
						
							|  |  |  |                                 e("test dx, dx\n"); break; | 
					
						
							|  |  |  |                 case LONG_SIZE: e("mov  [d+edi*4], edx\n"); | 
					
						
							|  |  |  |                                 e("test edx, edx\n"); break; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             e("lahf\n"); | 
					
						
							|  |  |  |             e("or   ah, bl\n");     /* CF */ | 
					
						
							|  |  |  |             e("test bl, bl\n"); | 
					
						
							|  |  |  |             e("setnz byte [x]\n");  /* CF==X */ | 
					
						
							|  |  |  |             e("jmp  short .end\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             EmitLabel(".zero_shift"); | 
					
						
							|  |  |  |             switch (size) | 
					
						
							|  |  |  |             {   case BYTE_SIZE: e("test dl, dl\n"); break; | 
					
						
							|  |  |  |                 case WORD_SIZE: e("test dx, dx\n"); break; | 
					
						
							|  |  |  |                 case LONG_SIZE: e("test edx, edx\n"); break; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             e("lahf\n"); | 
					
						
							|  |  |  |             e("xor  al, al\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             EmitLabel(".end");             | 
					
						
							|  |  |  |             switch (size) | 
					
						
							|  |  |  |             {   case BYTE_SIZE: | 
					
						
							|  |  |  |                 case WORD_SIZE: t = 6; break; | 
					
						
							|  |  |  |                 case LONG_SIZE: t = 8; break;   } | 
					
						
							|  |  |  |             EmitTiming(t); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else        /* ASR */ | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             e("mov  ebx, ecx\n");   /* save ECX */ | 
					
						
							|  |  |  |             e("mov  ecx, [d+%d*4]\n", (op >> 9) & 7); | 
					
						
							|  |  |  |             e("and  ecx, byte 0x3f\n"); /* modulo 64 */ | 
					
						
							|  |  |  |             switch (size) | 
					
						
							|  |  |  |             {   case BYTE_SIZE: e("mov  dl, [d+edi*4]\n"); | 
					
						
							|  |  |  |                                 e("sar  dl, cl\n"); | 
					
						
							|  |  |  |                                 e("setc bl\n"); | 
					
						
							|  |  |  |                                 e("test dl, dl\n"); | 
					
						
							|  |  |  |                                 break; | 
					
						
							|  |  |  |                 case WORD_SIZE: e("mov  edx, [d+edi*4]\n"); | 
					
						
							|  |  |  |                                 e("sar  dx, cl\n"); | 
					
						
							|  |  |  |                                 e("setc bl\n"); | 
					
						
							|  |  |  |                                 e("test dx, dx\n"); | 
					
						
							|  |  |  |                                 break; | 
					
						
							|  |  |  |                 case LONG_SIZE: e("mov  edx, [d+edi*4]\n"); | 
					
						
							|  |  |  |                                 e("sar  edx, cl\n"); | 
					
						
							|  |  |  |                                 e("setc bl\n");      /* get CF from SHL/SHR */ | 
					
						
							|  |  |  |                                 e("test edx, edx\n");/* this trashes the CF */ | 
					
						
							|  |  |  |                                 break; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |                  | 
					
						
							|  |  |  |             e("lahf\n"); | 
					
						
							|  |  |  |             e("test cl, cl\n"); /* if shift count of 0, X is unaffected, C=0 */ | 
					
						
							|  |  |  |             e("jz   short .no_x\n"); | 
					
						
							|  |  |  |             e("or   ah, bl\n");     /* CF! */ | 
					
						
							|  |  |  |             e("test     ah, 1\n");  /* CF */ | 
					
						
							|  |  |  |             e("setnz    byte [x]\n"); | 
					
						
							|  |  |  |             EmitLabel(".no_x"); | 
					
						
							|  |  |  |             switch (size)   /* write back and detect MSB change */ | 
					
						
							|  |  |  |             {   case BYTE_SIZE: e("mov  [d+edi*4], dl\n"); | 
					
						
							|  |  |  |                                 break; | 
					
						
							|  |  |  |                 case WORD_SIZE: e("mov  [d+edi*4], dx\n"); | 
					
						
							|  |  |  |                                 break; | 
					
						
							|  |  |  |                 case LONG_SIZE: e("mov  [d+edi*4], edx\n"); | 
					
						
							|  |  |  |                                 break; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             e("xor  al, al\n"); /* V=0 because MSB never changes w/ ASR */ | 
					
						
							|  |  |  |             /* timing */ | 
					
						
							|  |  |  |             switch (size) | 
					
						
							|  |  |  |             {   case BYTE_SIZE: | 
					
						
							|  |  |  |                 case WORD_SIZE: t = 6; break; | 
					
						
							|  |  |  |                 case LONG_SIZE: t = 8; break;   } | 
					
						
							|  |  |  |             e("shl  cl, byte 1\n"); /* 2n */ | 
					
						
							|  |  |  |             e("add  cl, byte %d\n", t); | 
					
						
							|  |  |  |             e("neg  ecx\n"); | 
					
						
							|  |  |  |             e("add  ecx, ebx\n"); | 
					
						
							|  |  |  |             e("js   near Turbo68KRun_done\n"); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else                /* immediate count */ | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if (!opr_i) /* ASR */ | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             e("sar  "); | 
					
						
							|  |  |  |             switch (size) | 
					
						
							|  |  |  |             {   case BYTE_SIZE: e("byte "); break; | 
					
						
							|  |  |  |                 case WORD_SIZE: e("word "); break; | 
					
						
							|  |  |  |                 case LONG_SIZE: e("dword "); break; } | 
					
						
							|  |  |  |             e("[d+edi*4], %d\n", count); | 
					
						
							|  |  |  |             e("lahf\n"); | 
					
						
							|  |  |  |             e("setc byte [x]\n"); | 
					
						
							|  |  |  |             e("xor  al, al\n"); | 
					
						
							|  |  |  |             t = count * 2;  /* 2 cycles per shift */ | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else        /* ASL */ | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             e("xor  al, al\n"); /* clear V */ | 
					
						
							|  |  |  |             switch (size) | 
					
						
							|  |  |  |             {   case BYTE_SIZE: e("mov  dl, [d+edi*4]\n"); break; | 
					
						
							|  |  |  |                 case WORD_SIZE: e("mov  dx, [d+edi*4]\n"); break; | 
					
						
							|  |  |  |                 case LONG_SIZE: e("mov  edx, [d+edi*4]\n"); break;    } | 
					
						
							|  |  |  |             for (i = 1; i <= count; i++) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 e("shl  "); | 
					
						
							|  |  |  |                 switch (size) | 
					
						
							|  |  |  |                 {   case BYTE_SIZE: e("dl, "); break; | 
					
						
							|  |  |  |                     case WORD_SIZE: e("dx, "); break; | 
					
						
							|  |  |  |                     case LONG_SIZE: e("edx, "); break;  } | 
					
						
							|  |  |  |                 e("1\n"); | 
					
						
							|  |  |  |                 if (i == count) | 
					
						
							|  |  |  |                 { | 
					
						
							|  |  |  |                     e("lahf\n"); | 
					
						
							|  |  |  |                     e("setc byte [x]\n"); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 e("setc bl\n");     /* old MSB */ | 
					
						
							|  |  |  |                 e("sets bh\n");     /* new MSB */ | 
					
						
							|  |  |  |                 e("xor  bh, bl\n"); /* detect change */ | 
					
						
							|  |  |  |                 e("or   al, bh\n"); /* reflect change in V */ | 
					
						
							|  |  |  |                 e("sub  ecx, byte 2\n");    /* each rotation=2 cycles */ | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             switch (size)   /* write results back to Dn */ | 
					
						
							|  |  |  |             {   case BYTE_SIZE: e("mov  [d+edi*4], dl\n"); break; | 
					
						
							|  |  |  |                 case WORD_SIZE: e("mov  [d+edi*4], dx\n"); break; | 
					
						
							|  |  |  |                 case LONG_SIZE: e("mov  [d+edi*4], edx\n"); break;    } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         switch (size) | 
					
						
							|  |  |  |         {   case BYTE_SIZE: | 
					
						
							|  |  |  |             case WORD_SIZE: t += 6; break; | 
					
						
							|  |  |  |             case LONG_SIZE: t += 8; break;  } | 
					
						
							|  |  |  |         EmitTiming(t); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     InstEnd(); | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int ArithmeticQ(unsigned short op, char *mnem_unused, unsigned base_timing) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     unsigned    ea = op & 0x3f, size, t, data, opr_i; | 
					
						
							|  |  |  |     char        mnem[5]; | 
					
						
							|  |  |  |     char        *mnem_t[] = { "ADDQ", "SUBQ" }; | 
					
						
							|  |  |  |     char        *opr[] =    { "add", "sub" }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!CheckEA(ea, "111111111000"))   return 0; | 
					
						
							|  |  |  |     t = base_timing; | 
					
						
							|  |  |  |     switch ((op >> 6) & 3) | 
					
						
							|  |  |  |     {   case 0:     size = BYTE_SIZE; break; | 
					
						
							|  |  |  |         case 1:     size = WORD_SIZE; break; | 
					
						
							|  |  |  |         case 2:     size = LONG_SIZE; t += 4; break; | 
					
						
							|  |  |  |         default:    return 0;   } | 
					
						
							|  |  |  |     if ((ea >> 3) != 0 && (ea >> 3) != 1)   t += 4; /* mem */ | 
					
						
							|  |  |  |     if (size == BYTE_SIZE && (ea >> 3) == 1)        /* byte An not allowed */ | 
					
						
							|  |  |  |        return 0; | 
					
						
							|  |  |  |     if (!NumDecodedEA(ea))              return 0; | 
					
						
							|  |  |  |     data = (op >> 9) & 7; | 
					
						
							|  |  |  |     if (!data)  data = 8; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     strcpy(mnem, mnem_t[(op >> 8) & 1]); | 
					
						
							|  |  |  |     opr_i = (op >> 8) & 1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     InstBegin(op, mnem, NumDecodedEA(ea)); | 
					
						
							|  |  |  |     if ((ea >> 3) == 0)         /* Dn */ | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         e("and  edi, byte 7\n"); | 
					
						
							|  |  |  |         switch (size) | 
					
						
							|  |  |  |         {   case BYTE_SIZE: | 
					
						
							|  |  |  |                 e("%s   byte [d+edi*4], %d\n", opr[opr_i], data); | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             case WORD_SIZE: | 
					
						
							|  |  |  |                 e("%s   word [d+edi*4], %d\n", opr[opr_i], data); | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             case LONG_SIZE: | 
					
						
							|  |  |  |                 e("%s   dword [d+edi*4], byte %d\n", opr[opr_i], data); | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         e("lahf\n"); | 
					
						
							|  |  |  |         e("seto al\n"); | 
					
						
							|  |  |  |         e("setc byte [x]\n"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else if ((ea >> 3) == 1)    /* An */ | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         /*
 | 
					
						
							|  |  |  |          * Manual says the entire address register is used despite the size | 
					
						
							|  |  |  |          * of the operation. | 
					
						
							|  |  |  |          */ | 
					
						
							|  |  |  |         e("and  edi, byte 7\n"); | 
					
						
							|  |  |  |         e("%s   dword [a+edi*4], byte %d\n", opr[opr_i], data); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else                        /* memory */ | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         LoadFromEA(ea, size, 0); | 
					
						
							|  |  |  |         switch (size) | 
					
						
							|  |  |  |         {   case BYTE_SIZE: e("%s   dl, byte %d\n", opr[opr_i], data); break; | 
					
						
							|  |  |  |             case WORD_SIZE: e("%s   dx, %d\n", opr[opr_i], data); break; | 
					
						
							|  |  |  |             case LONG_SIZE: e("%s   edx, byte %d\n", opr[opr_i], data); break;  } | 
					
						
							|  |  |  |         e("lahf\n"); | 
					
						
							|  |  |  |         e("seto al\n"); | 
					
						
							|  |  |  |         e("setc byte [x]\n"); | 
					
						
							|  |  |  |         switch (size) | 
					
						
							|  |  |  |         {   case BYTE_SIZE: WriteByte(); break; | 
					
						
							|  |  |  |             case WORD_SIZE: WriteWord(); break; | 
					
						
							|  |  |  |             case LONG_SIZE: WriteLong(); break; } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     EmitTiming(t + TimingEA(ea, size)); | 
					
						
							|  |  |  |     InstEnd(); | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  | }               | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int NEGx(unsigned short op, char *mnem_unused, unsigned base_timing) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     unsigned    ea = op & 0x3f, size, t; | 
					
						
							|  |  |  |     char        mnem[5]; | 
					
						
							|  |  |  |     char        *mnem_t[] = { "NEGX", "NEG" }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!CheckEA(ea, "101111111000"))   return 0; | 
					
						
							|  |  |  |     if (!NumDecodedEA(ea))              return 0; | 
					
						
							|  |  |  |     switch ((op >> 6) & 3) | 
					
						
							|  |  |  |     {   case 0: size = BYTE_SIZE; break; | 
					
						
							|  |  |  |         case 1: size = WORD_SIZE; break; | 
					
						
							|  |  |  |         case 2: size = LONG_SIZE; break; | 
					
						
							|  |  |  |         default: return 0;  } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     strcpy(mnem, mnem_t[(op >> 10) & 1]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     InstBegin(op, mnem, NumDecodedEA(ea)); | 
					
						
							|  |  |  |     if ((ea >> 3) == 0) /* Dn */ | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         e("and  edi, byte 7\n"); | 
					
						
							|  |  |  |         if (!(op & 0x0400)) /* NEGX */ | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             switch (size) | 
					
						
							|  |  |  |             {   case BYTE_SIZE: e("xor  dl, dl\n"); break; | 
					
						
							|  |  |  |                 case WORD_SIZE: case LONG_SIZE: | 
					
						
							|  |  |  |                                 e("xor  edx, edx\n"); break; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             e("shr  byte [x], 1\n");  /* X->CF */ | 
					
						
							|  |  |  |             switch (size) | 
					
						
							|  |  |  |             {   case BYTE_SIZE: e("sbb  dl, [d+edi*4]\n"); | 
					
						
							|  |  |  |                                 e("mov  bl, ah\n"); /* store old flags */ | 
					
						
							|  |  |  |                                 e("lahf\n"); | 
					
						
							|  |  |  |                                 e("seto al\n"); | 
					
						
							|  |  |  |                                 e("setc byte [x]\n"); | 
					
						
							|  |  |  |                                 e("jnz  short .clr\n"); /* Z clear */ | 
					
						
							|  |  |  |                                 e("and  bl, byte 0x40\n"); /* isolate old Z */ | 
					
						
							|  |  |  |                                 e("and  ah, byte 0xbf\n"); /* kill new Z */ | 
					
						
							|  |  |  |                                 e("or   ah, bl\n");        /* in w/ old Z */ | 
					
						
							|  |  |  |                                 EmitLabel(".clr"); | 
					
						
							|  |  |  |                                 e("mov  [d+edi*4], dl\n"); t = 4; break; | 
					
						
							|  |  |  |                 case WORD_SIZE: e("sbb  dx, [d+edi*4]\n"); | 
					
						
							|  |  |  |                                 e("mov  bl, ah\n"); | 
					
						
							|  |  |  |                                 e("lahf\n"); | 
					
						
							|  |  |  |                                 e("seto al\n"); | 
					
						
							|  |  |  |                                 e("setc byte [x]\n"); | 
					
						
							|  |  |  |                                 e("jnz  short .clr\n"); | 
					
						
							|  |  |  |                                 e("and  bl, byte 0x40\n"); | 
					
						
							|  |  |  |                                 e("and  ah, byte 0xbf\n"); | 
					
						
							|  |  |  |                                 e("or   ah, bl\n"); | 
					
						
							|  |  |  |                                 EmitLabel(".clr"); | 
					
						
							|  |  |  |                                 e("mov  [d+edi*4], dx\n"); t = 4; break; | 
					
						
							|  |  |  |                 case LONG_SIZE: e("sbb  edx, [d+edi*4]\n"); | 
					
						
							|  |  |  |                                 e("mov  bl, ah\n"); | 
					
						
							|  |  |  |                                 e("lahf\n"); | 
					
						
							|  |  |  |                                 e("seto al\n"); | 
					
						
							|  |  |  |                                 e("setc byte [x]\n"); | 
					
						
							|  |  |  |                                 e("jnz  short .clr\n"); | 
					
						
							|  |  |  |                                 e("and  bl, byte 0x40\n"); | 
					
						
							|  |  |  |                                 e("and  ah, byte 0xbf\n"); | 
					
						
							|  |  |  |                                 e("or   ah, bl\n"); | 
					
						
							|  |  |  |                                 EmitLabel(".clr"); | 
					
						
							|  |  |  |                                 e("mov  [d+edi*4], edx\n"); t = 6; break; } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else                /* NEG */ | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             switch (size) | 
					
						
							|  |  |  |             {   case BYTE_SIZE: e("neg  byte [d+edi*4]\n"); | 
					
						
							|  |  |  |                                 e("lahf\n"); | 
					
						
							|  |  |  |                                 e("seto al\n"); | 
					
						
							|  |  |  |                                 e("setc byte [x]\n"); | 
					
						
							|  |  |  |                                 t = 4; break; | 
					
						
							|  |  |  |                 case WORD_SIZE: e("neg  word [d+edi*4]\n"); | 
					
						
							|  |  |  |                                 e("lahf\n"); | 
					
						
							|  |  |  |                                 e("seto al\n"); | 
					
						
							|  |  |  |                                 e("setc byte [x]\n"); | 
					
						
							|  |  |  |                                 t = 4; break; | 
					
						
							|  |  |  |                 case LONG_SIZE: e("neg  dword [d+edi*4]\n"); | 
					
						
							|  |  |  |                                 e("lahf\n"); | 
					
						
							|  |  |  |                                 e("seto al\n"); | 
					
						
							|  |  |  |                                 e("setc byte [x]\n"); | 
					
						
							|  |  |  |                                 t = 6; break; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else                /* memory */ | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if (!(op & 0x0400)) /* NEGX */ | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             LoadFromEA(ea, size, 0); | 
					
						
							|  |  |  |             e("mov  edi, ebx\n");   /* save address where data came from */ | 
					
						
							|  |  |  |             switch (size) | 
					
						
							|  |  |  |             {   case BYTE_SIZE: e("xor  bl, bl\n"); break; | 
					
						
							|  |  |  |                 case WORD_SIZE: case LONG_SIZE: | 
					
						
							|  |  |  |                                 e("xor  ebx, ebx\n"); break; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             e("shr  byte [x], 1\n");  /* X->CF */ | 
					
						
							|  |  |  |             switch (size) | 
					
						
							|  |  |  |             {   case BYTE_SIZE: e("sbb  bl, dl\n"); | 
					
						
							|  |  |  |                                 e("mov  dl, ah\n"); | 
					
						
							|  |  |  |                                 e("lahf\n"); | 
					
						
							|  |  |  |                                 e("seto al\n"); | 
					
						
							|  |  |  |                                 e("setc byte [x]\n"); | 
					
						
							|  |  |  |                                 e("jnz  short .clr\n"); | 
					
						
							|  |  |  |                                 e("and  dl, byte 0x40\n"); | 
					
						
							|  |  |  |                                 e("and  ah, byte 0xbf\n"); | 
					
						
							|  |  |  |                                 e("or   ah, dl\n"); | 
					
						
							|  |  |  |                                 EmitLabel(".clr"); | 
					
						
							|  |  |  |                                 break; | 
					
						
							|  |  |  |                 case WORD_SIZE: e("sbb  bx, dx\n"); | 
					
						
							|  |  |  |                                 e("mov  dl, ah\n"); | 
					
						
							|  |  |  |                                 e("lahf\n"); | 
					
						
							|  |  |  |                                 e("seto al\n"); | 
					
						
							|  |  |  |                                 e("setc byte [x]\n"); | 
					
						
							|  |  |  |                                 e("jnz  short .clr\n"); | 
					
						
							|  |  |  |                                 e("and  dl, byte 0x40\n"); | 
					
						
							|  |  |  |                                 e("and  ah, byte 0xbf\n"); | 
					
						
							|  |  |  |                                 e("or   ah, dl\n"); | 
					
						
							|  |  |  |                                 EmitLabel(".clr"); | 
					
						
							|  |  |  |                                 break; | 
					
						
							|  |  |  |                 case LONG_SIZE: e("sbb  ebx, edx\n"); | 
					
						
							|  |  |  |                                 e("mov  dl, ah\n"); | 
					
						
							|  |  |  |                                 e("lahf\n"); | 
					
						
							|  |  |  |                                 e("seto al\n"); | 
					
						
							|  |  |  |                                 e("setc byte [x]\n"); | 
					
						
							|  |  |  |                                 e("jnz  short .clr\n"); | 
					
						
							|  |  |  |                                 e("and  dl, byte 0x40\n"); | 
					
						
							|  |  |  |                                 e("and  ah, byte 0xbf\n"); | 
					
						
							|  |  |  |                                 e("or   ah, dl\n"); | 
					
						
							|  |  |  |                                 EmitLabel(".clr"); | 
					
						
							|  |  |  |                                 break;    } | 
					
						
							|  |  |  |             e("mov  edx, ebx\n"); | 
					
						
							|  |  |  |             e("mov  ebx, edi\n"); | 
					
						
							|  |  |  |             /* WriteXXX will clear EDI for us */ | 
					
						
							|  |  |  |             switch (size) | 
					
						
							|  |  |  |             {   case BYTE_SIZE: WriteByte(); t = 8; break; | 
					
						
							|  |  |  |                 case WORD_SIZE: WriteWord(); t = 8; break; | 
					
						
							|  |  |  |                 case LONG_SIZE: WriteLong(); t = 12; break; } | 
					
						
							|  |  |  |             t += TimingEA(ea, size); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else                /* NEG */ | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             LoadFromEA(ea, size, 0); | 
					
						
							|  |  |  |             switch (size) | 
					
						
							|  |  |  |             {   case BYTE_SIZE: e("neg  dl\n"); | 
					
						
							|  |  |  |                                 e("lahf\n"); | 
					
						
							|  |  |  |                                 e("seto al\n"); | 
					
						
							|  |  |  |                                 e("setc byte [x]\n"); | 
					
						
							|  |  |  |                                 WriteByte(); t = 8; break; | 
					
						
							|  |  |  |                 case WORD_SIZE: e("neg  dx\n"); | 
					
						
							|  |  |  |                                 e("lahf\n"); | 
					
						
							|  |  |  |                                 e("seto al\n"); | 
					
						
							|  |  |  |                                 e("setc byte [x]\n"); | 
					
						
							|  |  |  |                                 WriteWord(); t = 8; break; | 
					
						
							|  |  |  |                 case LONG_SIZE: e("neg  edx\n"); | 
					
						
							|  |  |  |                                 e("lahf\n"); | 
					
						
							|  |  |  |                                 e("seto al\n"); | 
					
						
							|  |  |  |                                 e("setc byte [x]\n"); | 
					
						
							|  |  |  |                                 WriteLong(); t = 12; break; } | 
					
						
							|  |  |  |             t += TimingEA(ea, size); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     EmitTiming(t); | 
					
						
							|  |  |  |     InstEnd(); | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  |     | 
					
						
							|  |  |  | int RTS(unsigned short op, char *mnem, unsigned base_timing) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     InstBegin(op, mnem, 1); | 
					
						
							|  |  |  |     e("mov  ebx, [a+7*4]\n"); | 
					
						
							|  |  |  |     ReadLong(); | 
					
						
							|  |  |  |     e("add  dword [a+7*4], byte 4\n"); | 
					
						
							|  |  |  |     e("mov  esi, edx\n"); | 
					
						
							|  |  |  |     UpdateFetchPtr(); | 
					
						
							|  |  |  |     EmitTiming(base_timing); | 
					
						
							|  |  |  |     InstEnd(); | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int MOVEtoSR(unsigned short op, char *mnem, unsigned base_timing) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     unsigned    ea = op & 0x3f; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!CheckEA(ea, "101111111111"))   return 0; | 
					
						
							|  |  |  |     if (!NumDecodedEA(ea))              return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     InstBegin(op, mnem, NumDecodedEA(ea)); | 
					
						
							|  |  |  |     LoadFromEA(ea, WORD_SIZE, 0); | 
					
						
							|  |  |  |     e("test byte [sr+1], 0x20\n");      /* in supervisor? */ | 
					
						
							|  |  |  |     e("jz   near exception_privilege_violation\n"); | 
					
						
							|  |  |  |     e("test dh, 0x20\n");               /* if still in supervisor... */ | 
					
						
							|  |  |  |     e("jnz  .still_s\n");               /* ...no changes need to be made */ | 
					
						
							|  |  |  |     e("mov  ebx, [__sp]\n");            /* swap SSP and USP */ | 
					
						
							|  |  |  |     e("xchg [a+7*4], ebx\n"); | 
					
						
							|  |  |  |     e("mov  [__sp], ebx\n"); | 
					
						
							|  |  |  |     SetUserAddressSpace();              /* map in user address space */ | 
					
						
							|  |  |  |     EmitLabel(".still_s"); | 
					
						
							|  |  |  |     e("and  edx, 0xa71f\n");            /* mask out unwanted bits */ | 
					
						
							|  |  |  |     e("mov  [sr], edx\n");              /* load new SR */ | 
					
						
							|  |  |  |     LoadCCR();  /* reload flags we changed in CCR */ | 
					
						
							|  |  |  |     EmitTiming(base_timing + TimingEA(ea, WORD_SIZE)); | 
					
						
							|  |  |  |     InstEnd(); | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int DBcc(unsigned short op, char *mnem_unused, unsigned base_timing) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     unsigned    cond = (op >> 8) & 0xf; | 
					
						
							|  |  |  |     char        mnem[5]; | 
					
						
							|  |  |  |     char        *mnem_t[] = {  "DBT",  "DBF",  "DBHI", "DBLS", | 
					
						
							|  |  |  |                                "DBCC", "DBCS", "DBNE", "DBEQ", | 
					
						
							|  |  |  |                                "DBVC", "DBVS", "DBPL", "DBMI", | 
					
						
							|  |  |  |                                "DBGE", "DBLT", "DBGT", "DBLE" }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     strcpy(mnem, mnem_t[cond]);             /* set mnemonic */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     InstBegin(op, mnem, 8); | 
					
						
							|  |  |  |     switch (cond) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |     /* EAX:0000000000000000 NZ00 000C 0000 000V */ | 
					
						
							|  |  |  |     case 0:     /* always true */ | 
					
						
							|  |  |  |         e("add  esi, byte 2\n"); | 
					
						
							|  |  |  |         EmitTiming(10); | 
					
						
							|  |  |  |         InstEnd(); | 
					
						
							|  |  |  |         return 1; | 
					
						
							|  |  |  |     case 1:     /* DBF/DBRA: no condition to test, just loop */ | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case 2:     /* HI: !C & !Z */ | 
					
						
							|  |  |  |         e("test ah, byte 0x41\n"); | 
					
						
							|  |  |  |         e("jz   short .do\n"); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case 3:     /* LS: C | Z */ | 
					
						
							|  |  |  |         e("test ah, byte 0x41\n"); | 
					
						
							|  |  |  |         e("jnz  short .do\n"); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case 4:     /* CC: !C */ | 
					
						
							|  |  |  |         e("test ah, byte 1\n"); | 
					
						
							|  |  |  |         e("jz   short .do\n"); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case 5:     /* CS: C */ | 
					
						
							|  |  |  |         e("test ah, byte 1\n"); | 
					
						
							|  |  |  |         e("jnz  short .do\n"); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case 6:     /* NE: !Z */ | 
					
						
							|  |  |  |         e("test ah, byte 0x40\n"); | 
					
						
							|  |  |  |         e("jz   short .do\n"); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case 7:     /* EQ: Z */ | 
					
						
							|  |  |  |         e("test ah, byte 0x40\n"); | 
					
						
							|  |  |  |         e("jnz  short .do\n"); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case 8:     /* VC: !V */ | 
					
						
							|  |  |  |         e("test al, byte 1\n"); | 
					
						
							|  |  |  |         e("jz   short .do\n"); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case 9:     /* VS: V */ | 
					
						
							|  |  |  |         e("test al, byte 1\n"); | 
					
						
							|  |  |  |         e("jnz  short .do\n"); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case 0xa:   /* PL: !N */ | 
					
						
							|  |  |  |         e("test ah, byte 0x80\n"); | 
					
						
							|  |  |  |         e("jz   short .do\n"); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case 0xb:   /* MI: N */ | 
					
						
							|  |  |  |         e("test ah, byte 0x80\n"); | 
					
						
							|  |  |  |         e("jnz  short .do\n"); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case 0xc:   /* GE: N & V | !N & !V      (N&V || !N&!V) */ | 
					
						
							|  |  |  |         e("mov  bl, al\n"); | 
					
						
							|  |  |  |         e("mov  bh, ah\n"); | 
					
						
							|  |  |  |         e("and  bh, 0xfe\n"); | 
					
						
							|  |  |  |         e("or   bl, bh\n"); | 
					
						
							|  |  |  |         e("test bl, byte 0x81\n"); | 
					
						
							|  |  |  |         e("jpe  short .do\n");         | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case 0xd:   /* LT: N & !V | !N & V */ | 
					
						
							|  |  |  |         e("mov  bl, al\n"); | 
					
						
							|  |  |  |         e("mov  bh, ah\n"); | 
					
						
							|  |  |  |         e("and  bh, 0xfe\n"); | 
					
						
							|  |  |  |         e("or   bl, bh\n"); | 
					
						
							|  |  |  |         e("test bl, byte 0x81\n"); | 
					
						
							|  |  |  |         e("jpo  short .do\n"); | 
					
						
							|  |  |  |         EmitLabel(".dont_do"); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case 0xe:   /* GT: N & V & !Z | !N & !V & !Z */ | 
					
						
							|  |  |  |         /* if Z, then it is GE and we don't take this branch */ | 
					
						
							|  |  |  |         e("test ah, byte 0x40\n"); | 
					
						
							|  |  |  |         e("jnz  short .dont_do\n"); | 
					
						
							|  |  |  |         e("mov  bl, al\n"); | 
					
						
							|  |  |  |         e("mov  bh, ah\n"); | 
					
						
							|  |  |  |         e("and  bh, 0xfe\n"); | 
					
						
							|  |  |  |         e("or   bl, bh\n"); | 
					
						
							|  |  |  |         e("test bl, byte 0x81\n"); | 
					
						
							|  |  |  |         e("jpe  short .do\n");         | 
					
						
							|  |  |  |         EmitLabel(".dont_do"); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case 0xf:   /* LE: Z | N & !V | !N & V */ | 
					
						
							|  |  |  |         e("test ah, 0x40\n"); | 
					
						
							|  |  |  |         e("jnz  short .do\n"); | 
					
						
							|  |  |  |         e("mov  bl, al\n"); | 
					
						
							|  |  |  |         e("mov  bh, ah\n"); | 
					
						
							|  |  |  |         e("and  bh, 0xfe\n"); | 
					
						
							|  |  |  |         e("or   bl, bh\n"); | 
					
						
							|  |  |  |         e("test bl, byte 0x81\n"); | 
					
						
							|  |  |  |         e("jpo  short .do\n"); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     }         | 
					
						
							|  |  |  |     e("and  edi, byte 7\n");/* condition not met, decrement and branch */ | 
					
						
							|  |  |  |     if (cond == 1 && skip)  /* idle loop skipping w/ DBRA */ | 
					
						
							|  |  |  |         e("mov  edx, esi\n"); | 
					
						
							|  |  |  |     e("sub  word [d+edi*4], 1\n"); | 
					
						
							|  |  |  |     e("jc   short .do_loop_expired\n"); /* loop expired... */ | 
					
						
							|  |  |  |     e("movsx    ebx, word [esi]\n"); | 
					
						
							|  |  |  |     e("add      esi, ebx\n"); | 
					
						
							|  |  |  |     if (brafetch) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if (skip)               /* skip uses EDX, we must save it */ | 
					
						
							|  |  |  |             SaveReg("run", "edx"); | 
					
						
							|  |  |  |         e("sub  esi, ebp\n");   /* ESI=denormalized PC */ | 
					
						
							|  |  |  |         UpdateFetchPtr(); | 
					
						
							|  |  |  |         if (skip) | 
					
						
							|  |  |  |             RestoreReg("run", "edx"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (cond == 1 && skip) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         e("sub  edx, byte 2\n");        /* to get address of instruction */ | 
					
						
							|  |  |  |         e("cmp  edx, esi\n"); | 
					
						
							|  |  |  |         e("je   short .skip\n");        /* the same: this is an idle loop */ | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     EmitTiming(10); | 
					
						
							|  |  |  |     InstEnd(); | 
					
						
							|  |  |  |     Align(4); | 
					
						
							|  |  |  |     EmitLabel(".do");   /* condition was met, go on to next instruction */ | 
					
						
							|  |  |  |     e("add  esi, byte 2\n"); | 
					
						
							|  |  |  |     EmitTiming(12); | 
					
						
							|  |  |  |     InstEnd(); | 
					
						
							|  |  |  |     Align(4); | 
					
						
							|  |  |  |     EmitLabel(".do_loop_expired");  /* condition false, but loop expired */ | 
					
						
							|  |  |  |     e("add  esi, byte 2\n"); | 
					
						
							|  |  |  |     EmitTiming(14); | 
					
						
							|  |  |  |     InstEnd(); | 
					
						
							|  |  |  |     if (cond == 1 && skip) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         /*
 | 
					
						
							|  |  |  |          * This code makes it look as if the loop was executed and expired. | 
					
						
							|  |  |  |          */ | 
					
						
							|  |  |  |         EmitLabel(".skip"); | 
					
						
							|  |  |  |         e("add  edx, byte 4\n"); | 
					
						
							|  |  |  |         e("mov  esi, edx\n");       /* EDX contained PC for DBRA */ | 
					
						
							|  |  |  |         e("mov  edx, [d+edi*4]\n"); /* get counter loop */ | 
					
						
							|  |  |  |         e("and  edx, 0xffff\n"); | 
					
						
							|  |  |  |         e("inc  edx\n");            /* we subtracted 1 a little ways above */ | 
					
						
							|  |  |  |         e("mov  word [d+edi*4], 0xffff\n"); | 
					
						
							|  |  |  |         e("mov  ebx, edx\n"); | 
					
						
							|  |  |  |         e("shl  edx, byte 3\n");    /* (i << 3) + (i << 2) = i*10 */ | 
					
						
							|  |  |  |         e("shl  ebx, byte 2\n"); | 
					
						
							|  |  |  |         e("sub  ecx, edx\n"); | 
					
						
							|  |  |  |         e("sub  ecx, ebx\n"); | 
					
						
							|  |  |  |         e("js   near Turbo68KRun_done\n"); | 
					
						
							|  |  |  |         InstEnd(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int MOVEM(unsigned short op, char *mnem, unsigned base_timing) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |      * If a non-post/pre-inc/decrement mode is used, the registers are | 
					
						
							|  |  |  |      * transferred to the address, and that address is inc/decremented but the | 
					
						
							|  |  |  |      * change is NOT reflected in the address register. | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * If the mode is pre-dec or post-inc, it IS reflected. First, load up the | 
					
						
							|  |  |  |      * value of the register, and then write it back and the end, but don't | 
					
						
							|  |  |  |      * modify it while performing the operation, use a temp. X86 register | 
					
						
							|  |  |  |      * instead. | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * NOTE: The reg->mem mode should be fine, I've tested it -- but there | 
					
						
							|  |  |  |      * might be some bugs. | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * NOTE (April 8, 2001): Pete Dabbs just emailed me to report a problem | 
					
						
							|  |  |  |      * with MOVEM mem->reg. Basically, code like this wasn't working properly: | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      *      MOVEM.L (A7)+,A7 | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * What should happen there is the data from (A7) is read. Then, 4 is added | 
					
						
							|  |  |  |      * to A7, and finally, the data is written to A7. What Turbo68K was doing | 
					
						
							|  |  |  |      * wrong was it was writing the data from (A7) to A7 and THEN incrementing | 
					
						
							|  |  |  |      * A7. Not sure if the fix is correct, but I hope it is... I didn't change | 
					
						
							|  |  |  |      * anything in MOVEM reg->mem... | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     int         dr = (op >> 10) & 1, size = UNKNOWN_SIZE; | 
					
						
							|  |  |  |     unsigned    ea = op & 0x3f; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     switch ((op >> 6) & 1) | 
					
						
							|  |  |  |     {   case 0:     size = WORD_SIZE; break; | 
					
						
							|  |  |  |         case 1:     size = LONG_SIZE; break; | 
					
						
							|  |  |  |         default:    return 0;   } | 
					
						
							|  |  |  |     if (!NumDecodedEA(ea))              return 0; | 
					
						
							|  |  |  |     if (!dr)    /* reg->mem */ | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if (!CheckEA(ea, "001011111000"))   return 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else        /* mem->reg */ | 
					
						
							|  |  |  |         if (!CheckEA(ea, "001101111011"))   return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     InstBegin(op, mnem, NumDecodedEA(ea)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!dr)    /* reg->mem */ | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         SaveReg("run", "eax");  /* save flags */ | 
					
						
							|  |  |  |         e("mov  eax, [esi]\n"); /* AX=register list mask */ | 
					
						
							|  |  |  |         e("add  esi, byte 2\n"); | 
					
						
							|  |  |  |         LoadControlEA(ea);      /* EBX=store address */ | 
					
						
							|  |  |  |         SaveReg("run", "esi"); | 
					
						
							|  |  |  |         if ((ea >> 3) == 4)         /* write back if (An)+,-(An) */ | 
					
						
							|  |  |  |             SaveReg("run", "edi");  /* EDI may contain reg # */ | 
					
						
							|  |  |  |         if ((ea >> 3) == 4)         /* -(An) has reg mask reversed */ | 
					
						
							|  |  |  |             e("mov  esi, d+15*4\n");  /* start from top and decrement */ | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |             e("mov  esi, d\n"); | 
					
						
							|  |  |  |         EmitLabel(".loop"); | 
					
						
							|  |  |  |         if (size == WORD_SIZE) | 
					
						
							|  |  |  |             e("sub  ecx, byte 4\n"); | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |             e("sub  ecx, byte 8\n"); | 
					
						
							|  |  |  |         e("shr  eax, byte 1\n");    /* mask bit->CF */ | 
					
						
							|  |  |  |         e("jnc  short .skip\n");    /* not 1? skip this reg */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if ((ea >> 3) == 4) /* -(An) */ | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             if (size == WORD_SIZE)  e("sub  ebx, byte 2\n");    /* predec */ | 
					
						
							|  |  |  |             else                    e("sub  ebx, byte 4\n"); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         e("mov  edx, [esi]\n"); /* get reg to store... */ | 
					
						
							|  |  |  |         SaveReg("run", "ebx"); | 
					
						
							|  |  |  |         if (size == WORD_SIZE)  WriteWord(); else  WriteLong(); /* get mem */ | 
					
						
							|  |  |  |         RestoreReg("run", "ebx"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (!((ea >> 3) == 4))      /* not predec, increment */ | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             if (size == WORD_SIZE)  e("add  ebx, byte 2\n"); | 
					
						
							|  |  |  |             else                    e("add  ebx, byte 4\n"); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         EmitLabel(".skip"); | 
					
						
							|  |  |  |         if ((ea >> 3) == 4)         /* -(An) */ | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             e("sub  esi, byte 4\n");    /* next reg down */ | 
					
						
							|  |  |  |             e("cmp  esi, d-4\n");     /* done? */ | 
					
						
							|  |  |  |             e("jne  short .loop\n");    /* not done, keep looping */        | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             e("add  esi, byte 4\n");    /* next reg up */ | 
					
						
							|  |  |  |             e("cmp  esi, d+16*4\n");  /* done? */ | 
					
						
							|  |  |  |             e("jne  short .loop\n");    /* not done, keep looping */ | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if ((ea >> 3) == 4)   /* write back if -(An) */ | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             RestoreReg("run", "edi");            | 
					
						
							|  |  |  |             e("mov  [a+edi*4], ebx\n"); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         RestoreReg("run", "esi"); | 
					
						
							|  |  |  |         RestoreReg("run", "eax"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         switch (ea >> 3)    /* timing for address mode */ | 
					
						
							|  |  |  |         {   case 2: base_timing = 8; break;     /* (An) */ | 
					
						
							|  |  |  |             case 4: base_timing = 8; break;     /* -(An) */ | 
					
						
							|  |  |  |             case 5: base_timing = 12; break;    /* (d16,An) */ | 
					
						
							|  |  |  |             case 6: base_timing = 14; break;    /* (d8,An,Xn) */ | 
					
						
							|  |  |  |             case 7: | 
					
						
							|  |  |  |                 switch (ea & 7) | 
					
						
							|  |  |  |                 {   case 0: base_timing = 12; break;    /* (xxx).W */ | 
					
						
							|  |  |  |                     case 1: base_timing = 16; break;    /* (xxx).L */ | 
					
						
							|  |  |  |                 } break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else        /* mem->reg */ | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         SaveReg("run", "eax");  /* save flags */ | 
					
						
							|  |  |  |         e("mov  eax, [esi]\n"); /* AX=register list mask */ | 
					
						
							|  |  |  |         e("add  esi, byte 2\n"); | 
					
						
							|  |  |  |         LoadControlEA(ea);      /* EBX=load address */ | 
					
						
							|  |  |  |         SaveReg("run", "esi"); | 
					
						
							|  |  |  |         if ((ea >> 3) == 3)         /* write back if (An)+,-(An) */ | 
					
						
							|  |  |  |             SaveReg("run", "edi");  /* EDI may contain reg # */ | 
					
						
							|  |  |  |         e("mov  esi, d\n");       /* start from bottom and increment */ | 
					
						
							|  |  |  |         EmitLabel(".loop"); | 
					
						
							|  |  |  |         if (size == WORD_SIZE) | 
					
						
							|  |  |  |             e("sub  ecx, byte 4\n"); | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |             e("sub  ecx, byte 8\n"); | 
					
						
							|  |  |  |         e("shr  eax, byte 1\n");    /* mask bit->CF */ | 
					
						
							|  |  |  |         e("jnc  short .skip\n");    /* not 1? skip this reg */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /* if word, sign extend to long */ | 
					
						
							|  |  |  |         if (size == WORD_SIZE) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             if ((ea >> 3) == 7 && ((ea & 7) == 2 || (ea & 7) == 3)) | 
					
						
							|  |  |  |                 pcfetch ? ReadWordSXPC() : ReadWordSX();    /* PC-relative is special */ | 
					
						
							|  |  |  |             else | 
					
						
							|  |  |  |                 ReadWordSX(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             if ((ea >> 3) == 7 && ((ea & 7) == 2 || (ea & 7) == 3)) | 
					
						
							|  |  |  |                 pcfetch ? ReadLongPC() : ReadLong(); | 
					
						
							|  |  |  |             else | 
					
						
							|  |  |  |                 ReadLong(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (size == WORD_SIZE)  e("add  ebx, byte 2\n"); | 
					
						
							|  |  |  |         else                    e("add  ebx, byte 4\n"); | 
					
						
							|  |  |  |         if ((ea >> 3) == 3) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             RestoreReg("run", "edi"); | 
					
						
							|  |  |  |             e("mov  [a+edi*4], ebx\n"); | 
					
						
							|  |  |  |             SaveReg("run", "edi"); | 
					
						
							|  |  |  |         }             | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         e("mov  [esi], edx\n"); /* store to reg */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         EmitLabel(".skip"); | 
					
						
							|  |  |  |         e("add  esi, byte 4\n");    /* next reg up */ | 
					
						
							|  |  |  |         e("cmp  esi, d+16*4\n");  /* done? */ | 
					
						
							|  |  |  |         e("jne  short .loop\n");    /* not done, keep looping */        | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if ((ea >> 3) == 3)   /* just in case SaveReg()/RestoreReg() use stack */ | 
					
						
							|  |  |  |             RestoreReg("run", "edi"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         RestoreReg("run", "esi"); | 
					
						
							|  |  |  |         RestoreReg("run", "eax"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         switch (ea >> 3)    /* timing for address mode */ | 
					
						
							|  |  |  |         {   case 2: base_timing = 12; break;    /* (An) */ | 
					
						
							|  |  |  |             case 3: base_timing = 12; break;    /* (An)+ */ | 
					
						
							|  |  |  |             case 5: base_timing = 16; break;    /* (d16,An) */ | 
					
						
							|  |  |  |             case 6: base_timing = 18; break;    /* (d8,An,Xn) */ | 
					
						
							|  |  |  |             case 7: | 
					
						
							|  |  |  |                 switch (ea & 7) | 
					
						
							|  |  |  |                 {   case 0: base_timing = 16; break;    /* (xxx).W */ | 
					
						
							|  |  |  |                     case 1: base_timing = 20; break;    /* (xxx).L */ | 
					
						
							|  |  |  |                     case 2: base_timing = 16; break;    /* (d16,PC) */ | 
					
						
							|  |  |  |                     case 3: base_timing = 18; break;    /* (d16,PC,Xn */ | 
					
						
							|  |  |  |                 } break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     | 
					
						
							|  |  |  |     EmitTiming(base_timing); | 
					
						
							|  |  |  |     InstEnd(); | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* In case I screwed up MOVEM(), I have a back-up right here ;) */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int OldMOVEM(unsigned short op, char *mnem, unsigned base_timing) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |      * If a non-post/pre-inc/decrement mode is used, the registers are | 
					
						
							|  |  |  |      * transferred to the address, and that address is inc/decremented but the | 
					
						
							|  |  |  |      * change is NOT reflected in the address register. | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * If the mode is pre-dec or post-inc, it IS reflected. First, load up the | 
					
						
							|  |  |  |      * value of the register, and then write it back and the end, but don't | 
					
						
							|  |  |  |      * modify it while performing the operation, use a temp. X86 register | 
					
						
							|  |  |  |      * instead. | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * NOTE: The reg->mem mode should be fine, I've tested it -- but there | 
					
						
							|  |  |  |      * might be some bugs. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     int         dr = (op >> 10) & 1, size = UNKNOWN_SIZE; | 
					
						
							|  |  |  |     unsigned    ea = op & 0x3f; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     switch ((op >> 6) & 1) | 
					
						
							|  |  |  |     {   case 0:     size = WORD_SIZE; break; | 
					
						
							|  |  |  |         case 1:     size = LONG_SIZE; break; | 
					
						
							|  |  |  |         default:    return 0;   } | 
					
						
							|  |  |  |     if (!NumDecodedEA(ea))              return 0; | 
					
						
							|  |  |  |     if (!dr)    /* reg->mem */ | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if (!CheckEA(ea, "001011111000"))   return 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else        /* mem->reg */ | 
					
						
							|  |  |  |         if (!CheckEA(ea, "001101111011"))   return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     InstBegin(op, mnem, NumDecodedEA(ea)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!dr)    /* reg->mem */ | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         SaveReg("run", "eax");  /* save flags */ | 
					
						
							|  |  |  |         e("mov  eax, [esi]\n"); /* AX=register list mask */ | 
					
						
							|  |  |  |         e("add  esi, byte 2\n"); | 
					
						
							|  |  |  |         LoadControlEA(ea);      /* EBX=store address */ | 
					
						
							|  |  |  |         SaveReg("run", "esi"); | 
					
						
							|  |  |  |         if ((ea >> 3) == 4)         /* write back if (An)+,-(An) */ | 
					
						
							|  |  |  |             SaveReg("run", "edi");  /* EDI may contain reg # */ | 
					
						
							|  |  |  |         if ((ea >> 3) == 4)         /* -(An) has reg mask reversed */ | 
					
						
							|  |  |  |             e("mov  esi, d+15*4\n");  /* start from top and decrement */ | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |             e("mov  esi, d\n"); | 
					
						
							|  |  |  |         EmitLabel(".loop"); | 
					
						
							|  |  |  |         if (size == WORD_SIZE) | 
					
						
							|  |  |  |             e("sub  ecx, byte 4\n"); | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |             e("sub  ecx, byte 8\n"); | 
					
						
							|  |  |  |         e("shr  eax, byte 1\n");    /* mask bit->CF */ | 
					
						
							|  |  |  |         e("jnc  short .skip\n");    /* not 1? skip this reg */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if ((ea >> 3) == 4) /* -(An) */ | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             if (size == WORD_SIZE)  e("sub  ebx, byte 2\n");    /* predec */ | 
					
						
							|  |  |  |             else                    e("sub  ebx, byte 4\n"); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         e("mov  edx, [esi]\n"); /* get reg to store... */ | 
					
						
							|  |  |  |         SaveReg("run", "ebx"); | 
					
						
							|  |  |  |         if (size == WORD_SIZE)  WriteWord(); else  WriteLong(); /* get mem */ | 
					
						
							|  |  |  |         RestoreReg("run", "ebx"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (!((ea >> 3) == 4))      /* not predec, increment */ | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             if (size == WORD_SIZE)  e("add  ebx, byte 2\n"); | 
					
						
							|  |  |  |             else                    e("add  ebx, byte 4\n"); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         EmitLabel(".skip"); | 
					
						
							|  |  |  |         if ((ea >> 3) == 4)         /* -(An) */ | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             e("sub  esi, byte 4\n");    /* next reg down */ | 
					
						
							|  |  |  |             e("cmp  esi, d-4\n");     /* done? */ | 
					
						
							|  |  |  |             e("jne  short .loop\n");    /* not done, keep looping */        | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             e("add  esi, byte 4\n");    /* next reg up */ | 
					
						
							|  |  |  |             e("cmp  esi, d+16*4\n");  /* done? */ | 
					
						
							|  |  |  |             e("jne  short .loop\n");    /* not done, keep looping */ | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if ((ea >> 3) == 4)   /* write back if -(An) */ | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             RestoreReg("run", "edi");            | 
					
						
							|  |  |  |             e("mov  [a+edi*4], ebx\n"); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         RestoreReg("run", "esi"); | 
					
						
							|  |  |  |         RestoreReg("run", "eax"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         switch (ea >> 3)    /* timing for address mode */ | 
					
						
							|  |  |  |         {   case 2: base_timing = 8; break;     /* (An) */ | 
					
						
							|  |  |  |             case 4: base_timing = 8; break;     /* -(An) */ | 
					
						
							|  |  |  |             case 5: base_timing = 12; break;    /* (d16,An) */ | 
					
						
							|  |  |  |             case 6: base_timing = 14; break;    /* (d8,An,Xn) */ | 
					
						
							|  |  |  |             case 7: | 
					
						
							|  |  |  |                 switch (ea & 7) | 
					
						
							|  |  |  |                 {   case 0: base_timing = 12; break;    /* (xxx).W */ | 
					
						
							|  |  |  |                     case 1: base_timing = 16; break;    /* (xxx).L */ | 
					
						
							|  |  |  |                 } break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else        /* mem->reg */ | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         SaveReg("run", "eax");  /* save flags */ | 
					
						
							|  |  |  |         e("mov  eax, [esi]\n"); /* AX=register list mask */ | 
					
						
							|  |  |  |         e("add  esi, byte 2\n"); | 
					
						
							|  |  |  |         LoadControlEA(ea);      /* EBX=load address */ | 
					
						
							|  |  |  |         SaveReg("run", "esi"); | 
					
						
							|  |  |  |         if ((ea >> 3) == 3)         /* write back if (An)+,-(An) */ | 
					
						
							|  |  |  |             SaveReg("run", "edi");  /* EDI may contain reg # */ | 
					
						
							|  |  |  |         e("mov  esi, d\n");       /* start from bottom and increment */ | 
					
						
							|  |  |  |         EmitLabel(".loop"); | 
					
						
							|  |  |  |         if (size == WORD_SIZE) | 
					
						
							|  |  |  |             e("sub  ecx, byte 4\n"); | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |             e("sub  ecx, byte 8\n"); | 
					
						
							|  |  |  |         e("shr  eax, byte 1\n");    /* mask bit->CF */ | 
					
						
							|  |  |  |         e("jnc  short .skip\n");    /* not 1? skip this reg */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /* if word, sign extend to long */ | 
					
						
							|  |  |  |         if (size == WORD_SIZE) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             if ((ea >> 3) == 7 && ((ea & 7) == 2 || (ea & 7) == 3)) | 
					
						
							|  |  |  |                 pcfetch ? ReadWordSXPC() : ReadWordSX();    /* PC-relative is special */ | 
					
						
							|  |  |  |             else | 
					
						
							|  |  |  |                 ReadWordSX(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             if ((ea >> 3) == 7 && ((ea & 7) == 2 || (ea & 7) == 3)) | 
					
						
							|  |  |  |                 pcfetch ? ReadLongPC() : ReadLong(); | 
					
						
							|  |  |  |             else | 
					
						
							|  |  |  |                 ReadLong(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         e("mov  [esi], edx\n"); /* store to reg */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (size == WORD_SIZE)  e("add  ebx, byte 2\n"); | 
					
						
							|  |  |  |         else                    e("add  ebx, byte 4\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         EmitLabel(".skip"); | 
					
						
							|  |  |  |         e("add  esi, byte 4\n");    /* next reg up */ | 
					
						
							|  |  |  |         e("cmp  esi, d+16*4\n");  /* done? */ | 
					
						
							|  |  |  |         e("jne  short .loop\n");    /* not done, keep looping */        | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if ((ea >> 3) == 3)   /* write back if (An)+ */ | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             RestoreReg("run", "edi");            | 
					
						
							|  |  |  |             e("mov  [a+edi*4], ebx\n"); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         RestoreReg("run", "esi"); | 
					
						
							|  |  |  |         RestoreReg("run", "eax"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         switch (ea >> 3)    /* timing for address mode */ | 
					
						
							|  |  |  |         {   case 2: base_timing = 12; break;    /* (An) */ | 
					
						
							|  |  |  |             case 3: base_timing = 12; break;    /* (An)+ */ | 
					
						
							|  |  |  |             case 5: base_timing = 16; break;    /* (d16,An) */ | 
					
						
							|  |  |  |             case 6: base_timing = 18; break;    /* (d8,An,Xn) */ | 
					
						
							|  |  |  |             case 7: | 
					
						
							|  |  |  |                 switch (ea & 7) | 
					
						
							|  |  |  |                 {   case 0: base_timing = 16; break;    /* (xxx).W */ | 
					
						
							|  |  |  |                     case 1: base_timing = 20; break;    /* (xxx).L */ | 
					
						
							|  |  |  |                     case 2: base_timing = 16; break;    /* (d16,PC) */ | 
					
						
							|  |  |  |                     case 3: base_timing = 18; break;    /* (d16,PC,Xn */ | 
					
						
							|  |  |  |                 } break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     | 
					
						
							|  |  |  |     EmitTiming(base_timing); | 
					
						
							|  |  |  |     InstEnd(); | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int MOVEUSP(unsigned short op, char *mnem, unsigned base_timing) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     InstBegin(op, mnem, 8); /* handles all 8 possible An regs */ | 
					
						
							|  |  |  |     e("and      edi, byte 7\n"); | 
					
						
							|  |  |  |     e("test     byte [sr+1], 0x20\n"); | 
					
						
							|  |  |  |     e("jz       near exception_privilege_violation\n"); | 
					
						
							|  |  |  |     if (op & 8) /* USP->An */ | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         e("mov  edx, [__sp]\n"); | 
					
						
							|  |  |  |         e("mov  [a+edi*4], edx\n"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else        /* An->USP */ | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         e("mov  edx, [a+edi*4]\n"); | 
					
						
							|  |  |  |         e("mov  [__sp], edx\n"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     EmitTiming(base_timing); | 
					
						
							|  |  |  |     InstEnd(); | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int Jxx(unsigned short op, char *mnem, unsigned base_timing) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     unsigned    t; | 
					
						
							|  |  |  |     if (!CheckEA(op & 0x3f, "001001111011"))    return 0; | 
					
						
							|  |  |  |     if (!NumDecodedEA(op & 0x3f))               return 0; | 
					
						
							|  |  |  |     InstBegin(op, mnem, NumDecodedEA(op & 0x3f)); | 
					
						
							|  |  |  |     LoadControlEA(op & 0x3f); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if ((op & 0xffc0) == 0x4e80)    /* JSR */ | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         e("mov  edx, esi\n");   /* EDX=PC to save to stack */ | 
					
						
							|  |  |  |         e("sub  edx, ebp\n"); | 
					
						
							|  |  |  |         SaveReg("run", "edx"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     e("mov  esi, ebx\n"); | 
					
						
							|  |  |  |     UpdateFetchPtr(); | 
					
						
							|  |  |  |     if ((op & 0xffc0) == 0x4e80)    /* JSR stuff again... */ | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         RestoreReg("run", "edx");   /* remember? EDX contains PC to save */ | 
					
						
							|  |  |  |         e("sub  dword [a+7*4], byte 4\n");    /* SP - 4 -> SP */ | 
					
						
							|  |  |  |         e("mov  ebx, [a+7*4]\n"); | 
					
						
							|  |  |  |         WriteLong();                            /* PC -> (SP) */ | 
					
						
							|  |  |  |     }         | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     switch ((op >> 3) & 7)  /* timing based on control addressing mode */ | 
					
						
							|  |  |  |     {   case 2: t = 8; break;   /* (An) */ | 
					
						
							|  |  |  |         case 5: t = 10; break;  /* (d16,An) */ | 
					
						
							|  |  |  |         case 6: t = 14; break;  /* (d8,An,Xn) */ | 
					
						
							|  |  |  |         case 7: | 
					
						
							|  |  |  |             switch (op & 7) | 
					
						
							|  |  |  |             {   case 0: t = 10; break;  /* (xxx).W */ | 
					
						
							|  |  |  |                 case 1: t = 12; break;  /* (xxx).L */ | 
					
						
							|  |  |  |                 case 2: t = 10; break;  /* (d16,pc) */ | 
					
						
							|  |  |  |                 case 3: t = 14; break;  /* (d8,pc,Xn) */ | 
					
						
							|  |  |  |             } break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if ((op & 0xffc0) == 0x4e80)    t += 8; /* JSR */ | 
					
						
							|  |  |  |     EmitTiming(t); | 
					
						
							|  |  |  |     InstEnd(); | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int LEA(unsigned short op, char *mnem, unsigned base_timing) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     unsigned    t; | 
					
						
							|  |  |  |     if (!CheckEA(op & 0x3f, "001001111011"))    return 0; | 
					
						
							|  |  |  |     if (!NumDecodedEA(op & 0x3f))               return 0; | 
					
						
							|  |  |  |     InstBegin(op, mnem, NumDecodedEA(op & 0x3f)); | 
					
						
							|  |  |  |     LoadControlEA(op & 0x3f); | 
					
						
							|  |  |  |     e("mov  [a+%d*4], ebx\n", (op >> 9) & 7); | 
					
						
							|  |  |  |     switch ((op >> 3) & 7)  /* timing based on control addressing mode */ | 
					
						
							|  |  |  |     {   case 2: t = 4; break;   /* (An) */ | 
					
						
							|  |  |  |         case 5: t = 8; break;   /* (d16,An) */ | 
					
						
							|  |  |  |         case 6: t = 12; break;  /* (d8,An,Xn) */ | 
					
						
							|  |  |  |         case 7: | 
					
						
							|  |  |  |             switch (op & 7) | 
					
						
							|  |  |  |             {   case 0: t = 8; break;   /* (xxx).W */ | 
					
						
							|  |  |  |                 case 1: t = 12; break;  /* (xxx).L */ | 
					
						
							|  |  |  |                 case 2: t = 8; break;   /* (d16,pc) */ | 
					
						
							|  |  |  |                 case 3: t = 12; break;  /* (d8,pc,Xn) */ | 
					
						
							|  |  |  |             } break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     EmitTiming(t); | 
					
						
							|  |  |  |     InstEnd(); | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int BTST(unsigned short op, char *mnem, unsigned base_timing) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     unsigned    t; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (((op >> 6) & 7) != 4 && ((op >> 6) & 7) != 0)   return 0; | 
					
						
							|  |  |  |     if (op & 0x100)                 /* dynamic */ | 
					
						
							|  |  |  |     {     | 
					
						
							|  |  |  |         if (!CheckEA(op & 0x3f, "101111111111"))    return 0; | 
					
						
							|  |  |  |         if (!NumDecodedEA(op & 0x3f))               return 0; | 
					
						
							|  |  |  |         InstBegin(op, mnem, NumDecodedEA(op & 0x3f)); | 
					
						
							|  |  |  |         if (((op >> 3) & 7) == 0)   /* Dn is long */ | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             t = 6; | 
					
						
							|  |  |  |             e("and  edi, byte 7\n"); | 
					
						
							|  |  |  |             e("mov  ebx, [d+%d*4]\n", (op >> 9) & 7); /* bit # */ | 
					
						
							|  |  |  |             e("and  ebx, byte 31\n");           /* same as modulo 32 */ | 
					
						
							|  |  |  |             e("bt   dword [d+edi*4], ebx\n"); /* bit->CF */ | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else                        /* mem is byte */ | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             t = 4; | 
					
						
							|  |  |  |             LoadFromEA(op & 0x3f, BYTE_SIZE, 0); | 
					
						
							|  |  |  |             e("mov  ebx, [d+%d*4]\n", (op >> 9) & 7); /* bit # */ | 
					
						
							|  |  |  |             e("and  ebx, byte 7\n");            /* same as modulo 8 */ | 
					
						
							|  |  |  |             e("bt   edx, ebx\n");               /* bit->CF */ | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else if (!(op & 0x100))         /* static */ | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if (!CheckEA(op & 0x3f, "101111111011"))    return 0; | 
					
						
							|  |  |  |         if (!NumDecodedEA(op & 0x3f))               return 0; | 
					
						
							|  |  |  |         InstBegin(op, mnem, NumDecodedEA(op & 0x3f)); | 
					
						
							|  |  |  |         if (((op >> 3) & 7) == 0)   /* Dn is long */ | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             t = 10; | 
					
						
							|  |  |  |             e("and  edi, byte 7\n");    /* isolate Dn reg # */ | 
					
						
							|  |  |  |             e("mov  ebx, [esi]\n");     /* get bit # */ | 
					
						
							|  |  |  |             e("and  ebx, byte 31\n");   /* same as modulo 32 */ | 
					
						
							|  |  |  |             e("add  esi, byte 2\n"); | 
					
						
							|  |  |  |             e("bt   dword [d+edi*4], ebx\n"); /* bit->CF */ | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else                        /* mem is byte */ | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             t = 8; | 
					
						
							|  |  |  |             e("mov  ebx, [esi]\n");     /* get bit # */ | 
					
						
							|  |  |  |             e("and  ebx, byte 7\n");    /* same as modulo 8 */ | 
					
						
							|  |  |  |             e("add  esi, byte 2\n"); | 
					
						
							|  |  |  |             SaveReg("run", "ebx"); | 
					
						
							|  |  |  |             LoadFromEA(op & 0x3f, BYTE_SIZE, 0); | 
					
						
							|  |  |  |             RestoreReg("run", "ebx"); | 
					
						
							|  |  |  |             e("bt   edx, ebx\n");               /* bit->CF */ | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     e("setnc bl\n");        /* zero status of C->DH */ | 
					
						
							|  |  |  |     e("and  ah, 0xbf\n");   /* get rid of old Z */ | 
					
						
							|  |  |  |     e("shl  bl, 6\n");      /* put C in Z position */ | 
					
						
							|  |  |  |     e("or   ah, bl\n");     /* set the new Z */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (((op & 0x3f) & 7) == 0) /* Dn is long */ | 
					
						
							|  |  |  |         EmitTiming(t); | 
					
						
							|  |  |  |     else                        /* mem is byte */ | 
					
						
							|  |  |  |         EmitTiming(t + TimingEA(op & 0x3f, BYTE_SIZE));         | 
					
						
							|  |  |  |     InstEnd(); | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int TST(unsigned short op, char *mnem, unsigned base_timing) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     int size; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     switch ((op >> 6) & 3)  /* set valid sizes */ | 
					
						
							|  |  |  |     {   case 0:     size = BYTE_SIZE; break; | 
					
						
							|  |  |  |         case 1:     size = WORD_SIZE; break; | 
					
						
							|  |  |  |         case 2:     size = LONG_SIZE; break; | 
					
						
							|  |  |  |         default:    return 0;   } | 
					
						
							|  |  |  |     if (!NumDecodedEA(op & 0x3f))   /* check if decoded this EA */ | 
					
						
							|  |  |  |         return 0; | 
					
						
							|  |  |  |     if (!CheckEA(op & 0x3f, "101111111000")) | 
					
						
							|  |  |  |         return 0;   /* no An,#dat,(d16,pc),(d8,pc,Xn) for 68000 */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     InstBegin(op, mnem, NumDecodedEA(op & 0x3f)); | 
					
						
							|  |  |  |     if (((op & 0x3f) >> 3) == 0)    /* Dn shortcut */ | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         e("and  edi, byte 7\n"); | 
					
						
							|  |  |  |         e("mov  edx, [d+edi*4]\n"); | 
					
						
							|  |  |  |         if (size == BYTE_SIZE) | 
					
						
							|  |  |  |             e("test dl, dl\n"); | 
					
						
							|  |  |  |         else if (size == WORD_SIZE) | 
					
						
							|  |  |  |             e("test dx, dx\n"); | 
					
						
							|  |  |  |         else if (size == LONG_SIZE) | 
					
						
							|  |  |  |             e("test edx, edx\n"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         LoadFromEA(op & 0x3f, size, 0); | 
					
						
							|  |  |  |         if (size == BYTE_SIZE) | 
					
						
							|  |  |  |             e("test dl, dl\n"); | 
					
						
							|  |  |  |         else if (size == WORD_SIZE) | 
					
						
							|  |  |  |             e("test dx, dx\n"); | 
					
						
							|  |  |  |         else if (size == LONG_SIZE) | 
					
						
							|  |  |  |             e("test edx, edx\n"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     e("lahf\n"); | 
					
						
							|  |  |  |     e("xor  al, al\n"); | 
					
						
							|  |  |  |     EmitTiming(base_timing + TimingEA(op & 0x3f, size)); | 
					
						
							|  |  |  |     InstEnd(); | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int Bxx(unsigned short op, char *mnem, unsigned base_timing) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if ((op & 0xff) != 0 && (op & 0xff) != 1) | 
					
						
							|  |  |  |         return 0; | 
					
						
							|  |  |  |     switch (op & 0xff) | 
					
						
							|  |  |  |     {   case 0:     InstBegin(op, mnem, 1); break; | 
					
						
							|  |  |  |         case 1:     InstBegin(op, mnem, 255); break; | 
					
						
							|  |  |  |         break;  } | 
					
						
							|  |  |  |     switch (op & 0xff) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |     case 0:     /* 16-bit displacement */ | 
					
						
							|  |  |  |         if ((op & 0xff00) == 0x6100) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             e("mov  edx, 2\n"); | 
					
						
							|  |  |  |             e("add  edx, esi\n"); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         e("movsx    ebx, word [esi]\n"); | 
					
						
							|  |  |  |         e("add      esi, ebx\n"); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case 1:     /* 8-bit displacement -- XX01-XXFF */ | 
					
						
							|  |  |  |         if ((op & 0xff00) == 0x6100) | 
					
						
							|  |  |  |             e("mov  edx, esi\n"); | 
					
						
							|  |  |  |         e("and      edi, 0xff\n"); | 
					
						
							|  |  |  |         e("mov      ebx, edi\n"); | 
					
						
							|  |  |  |         e("movsx    ebx, bl\n"); | 
					
						
							|  |  |  |         e("add      esi, ebx\n"); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (brafetch) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         e("sub  esi, ebp\n");   /* ESI=denormalized PC */ | 
					
						
							|  |  |  |         if ((op & 0xff00) == 0x6100)    /* if BSR, save EDX */ | 
					
						
							|  |  |  |             SaveReg("run", "edx"); | 
					
						
							|  |  |  |         UpdateFetchPtr(); | 
					
						
							|  |  |  |         if ((op & 0xff00) == 0x6100) | 
					
						
							|  |  |  |             RestoreReg("run", "edx"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if ((op & 0xff00) == 0x6100)    /* BSR */ | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         e("sub  dword [a+7*4], byte 4\n");    /* SP - 4 -> SP */ | 
					
						
							|  |  |  |         e("sub  edx, ebp\n");   /* EDX=PC of next instruction */ | 
					
						
							|  |  |  |         e("mov  ebx, [a+7*4]\n"); | 
					
						
							|  |  |  |         WriteLong();                    /* PC -> (SP) */ | 
					
						
							|  |  |  |     }         | 
					
						
							|  |  |  |     EmitTiming(base_timing); | 
					
						
							|  |  |  |     InstEnd(); | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  | int Bcc(unsigned short op, char *mnem_unused, unsigned base_timing) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     unsigned    cond = (op >> 8) & 0xf; | 
					
						
							|  |  |  |     char        mnem[4]; | 
					
						
							|  |  |  |     char        *mnem_t[] = {  NULL,  NULL, "BHI", "BLS", | 
					
						
							|  |  |  |                               "BCC", "BCS", "BNE", "BEQ", | 
					
						
							|  |  |  |                               "BVC", "BVS", "BPL", "BMI", | 
					
						
							|  |  |  |                               "BGE", "BLT", "BGT", "BLE" }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!cond || cond == 1)     return 0;   /* these not available for Bcc */ | 
					
						
							|  |  |  |     strcpy(mnem, mnem_t[cond]);             /* set mnemonic */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     switch (op & 0xff) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |     case 0:     /* 16-bit displacement */ | 
					
						
							|  |  |  |         InstBegin(op, mnem, 1); break; | 
					
						
							|  |  |  |     case 1:     /* 8-bit displacement -- XX01-XXFE */ | 
					
						
							|  |  |  |         InstBegin(op, mnem, 255); break; | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |         return 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     switch (cond) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |     /* EAX:0000000000000000 NZ00 000C 0000 000V */ | 
					
						
							|  |  |  |     case 2:     /* HI: !C & !Z */ | 
					
						
							|  |  |  |         e("test ah, byte 0x41\n"); | 
					
						
							|  |  |  |         e("jz   short .do\n"); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case 3:     /* LS: C | Z */ | 
					
						
							|  |  |  |         e("test ah, byte 0x41\n"); | 
					
						
							|  |  |  |         e("jnz  short .do\n"); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case 4:     /* CC: !C */ | 
					
						
							|  |  |  |         e("test ah, byte 1\n"); | 
					
						
							|  |  |  |         e("jz   short .do\n"); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case 5:     /* CS: C */ | 
					
						
							|  |  |  |         e("test ah, byte 1\n"); | 
					
						
							|  |  |  |         e("jnz  short .do\n"); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case 6:     /* NE: !Z */ | 
					
						
							|  |  |  |         e("test ah, byte 0x40\n"); | 
					
						
							|  |  |  |         e("jz   short .do\n"); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case 7:     /* EQ: Z */ | 
					
						
							|  |  |  |         e("test ah, byte 0x40\n"); | 
					
						
							|  |  |  |         e("jnz  short .do\n"); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case 8:     /* VC: !V */ | 
					
						
							|  |  |  |         e("test al, byte 1\n"); | 
					
						
							|  |  |  |         e("jz   short .do\n"); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case 9:     /* VS: V */ | 
					
						
							|  |  |  |         e("test al, byte 1\n"); | 
					
						
							|  |  |  |         e("jnz  short .do\n"); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case 0xa:   /* PL: !N */ | 
					
						
							|  |  |  |         e("test ah, byte 0x80\n"); | 
					
						
							|  |  |  |         e("jz   short .do\n"); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case 0xb:   /* MI: N */ | 
					
						
							|  |  |  |         e("test ah, byte 0x80\n"); | 
					
						
							|  |  |  |         e("jnz  short .do\n"); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case 0xc:   /* GE: N & V | !N & !V      (N&V || !N&!V) */ | 
					
						
							|  |  |  |         e("mov  bl, al\n"); | 
					
						
							|  |  |  |         e("mov  bh, ah\n"); | 
					
						
							|  |  |  |         e("and  bh, 0xfe\n"); | 
					
						
							|  |  |  |         e("or   bl, bh\n"); | 
					
						
							|  |  |  |         e("test bl, byte 0x81\n"); | 
					
						
							|  |  |  |         e("jpe  short .do\n");         | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case 0xd:   /* LT: N & !V | !N & V */ | 
					
						
							|  |  |  |         e("mov  bl, al\n"); | 
					
						
							|  |  |  |         e("mov  bh, ah\n"); | 
					
						
							|  |  |  |         e("and  bh, 0xfe\n"); | 
					
						
							|  |  |  |         e("or   bl, bh\n"); | 
					
						
							|  |  |  |         e("test bl, byte 0x81\n"); | 
					
						
							|  |  |  |         e("jpo  short .do\n"); | 
					
						
							|  |  |  |         EmitLabel(".dont_do"); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case 0xe:   /* GT: N & V & !Z | !N & !V & !Z */ | 
					
						
							|  |  |  |         /* if Z, then it is GE and we don't take this branch */ | 
					
						
							|  |  |  |         e("test ah, byte 0x40\n"); | 
					
						
							|  |  |  |         e("jnz  short .dont_do\n"); | 
					
						
							|  |  |  |         e("mov  bl, al\n"); | 
					
						
							|  |  |  |         e("mov  bh, ah\n"); | 
					
						
							|  |  |  |         e("and  bh, 0xfe\n"); | 
					
						
							|  |  |  |         e("or   bl, bh\n"); | 
					
						
							|  |  |  |         e("test bl, byte 0x81\n"); | 
					
						
							|  |  |  |         e("jpe  short .do\n");         | 
					
						
							|  |  |  |         EmitLabel(".dont_do"); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case 0xf:   /* LE: Z | N & !V | !N & V */ | 
					
						
							|  |  |  |         e("test ah, 0x40\n"); | 
					
						
							|  |  |  |         e("jnz  short .do\n"); | 
					
						
							|  |  |  |         e("mov  bl, al\n"); | 
					
						
							|  |  |  |         e("mov  bh, ah\n"); | 
					
						
							|  |  |  |         e("and  bh, 0xfe\n"); | 
					
						
							|  |  |  |         e("or   bl, bh\n"); | 
					
						
							|  |  |  |         e("test bl, byte 0x81\n"); | 
					
						
							|  |  |  |         e("jpo  short .do\n"); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     }         | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* branch not taken */ | 
					
						
							|  |  |  |     switch (op & 0xff)  /* look at this to figure out timing and increment */ | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |     case 0:     /* 16-bit */ | 
					
						
							|  |  |  |         e("add  esi, byte 2\n"); EmitTiming(12); break;        | 
					
						
							|  |  |  |     case 1:     /* 8-bit */ | 
					
						
							|  |  |  |         EmitTiming(8); break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     InstEnd(); | 
					
						
							|  |  |  |     Align(4); | 
					
						
							|  |  |  |     EmitLabel(".do"); | 
					
						
							|  |  |  |     switch (op & 0xff) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |     case 0:     /* 16-bit */ | 
					
						
							|  |  |  |         e("movsx    ebx, word [esi]\n"); | 
					
						
							|  |  |  |         e("add      esi, ebx\n"); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case 1:     /* 8-bit */ | 
					
						
							|  |  |  |         e("and      edi, 0xff\n"); | 
					
						
							|  |  |  |         e("mov      ebx, edi\n"); | 
					
						
							|  |  |  |         e("movsx    ebx, bl\n"); | 
					
						
							|  |  |  |         e("add      esi, ebx\n"); | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (brafetch) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         e("sub  esi, ebp\n");   /* ESI=denormalized PC */ | 
					
						
							|  |  |  |         UpdateFetchPtr(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     EmitTiming(10); | 
					
						
							|  |  |  |     InstEnd(); | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int Arithmetic(unsigned short op, char *mnem_unused, unsigned base_timing) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     unsigned    t, ea = op & 0x3f, opr_code = (op >> 12), | 
					
						
							|  |  |  |                 opmode = (op >> 6) & 7; | 
					
						
							|  |  |  |     int         size = UNKNOWN_SIZE; | 
					
						
							|  |  |  |     char        mnem[4]; | 
					
						
							|  |  |  |     char        opr[4], *size_s[] = { "byte", "word", "dword" }, | 
					
						
							|  |  |  |                 *edx[] = { "dl", "dx", "edx" }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (opmode & 4) /* EA == destination */ | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         switch (opr_code) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |         case 8:                                                     /* OR  */ | 
					
						
							|  |  |  |         case 9:                                                     /* SUB */ | 
					
						
							|  |  |  |         case 0xc:                                                   /* AND */ | 
					
						
							|  |  |  |         case 0xd:   if (!CheckEA(ea, "001111111000"))   return 0;   /* ADD */ | 
					
						
							|  |  |  |                     break; | 
					
						
							|  |  |  |         case 0xb:   if (!CheckEA(ea, "101111111000"))   return 0;   /* EOR */ | 
					
						
							|  |  |  |                     break; | 
					
						
							|  |  |  |         default:    return 0;   } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else            /* EA == source */ | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         switch (opr_code) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |         case 0xd:                                                   /* ADD */ | 
					
						
							|  |  |  |         case 0xb:                                                   /* CMP */ | 
					
						
							|  |  |  |         case 9:     if (!CheckEA(ea, "111111111111"))   return 0;   /* SUB */ | 
					
						
							|  |  |  |                     if ((ea >> 3) == 1 && (opmode & 3) == 0) | 
					
						
							|  |  |  |                         return 0;   /* byte access to An not allowed! */ | 
					
						
							|  |  |  |                     break; | 
					
						
							|  |  |  |         case 8:                                                     /* OR  */ | 
					
						
							|  |  |  |         case 0xc:   if (!CheckEA(ea, "101111111111"))   return 0;   /* AND */ | 
					
						
							|  |  |  |                     break; | 
					
						
							|  |  |  |         default:    return 0;   } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (!NumDecodedEA(ea))  /* check if decoded this EA */ | 
					
						
							|  |  |  |         return 0; | 
					
						
							|  |  |  |     switch (opmode & 3) /* set allowed sizes */ | 
					
						
							|  |  |  |     {   case 0:     size = BYTE_SIZE; break; | 
					
						
							|  |  |  |         case 1:     size = WORD_SIZE; break; | 
					
						
							|  |  |  |         case 2:     size = LONG_SIZE; break; | 
					
						
							|  |  |  |         default:    return 0;   } | 
					
						
							|  |  |  |     switch (opr_code)       /* timing */ | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |     case 0xd:   /* ADD */ | 
					
						
							|  |  |  |     case 9:     /* SUB */ | 
					
						
							|  |  |  |         if (size == BYTE_SIZE || size == WORD_SIZE) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             if ((ea >> 3) == 1)         t = 8; | 
					
						
							|  |  |  |             else if ((ea >> 3) == 0)    t = 4; | 
					
						
							|  |  |  |             else                        t = 8; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             if ((ea >> 3) == 1)         t = 6; | 
					
						
							|  |  |  |             else if ((ea >> 3) == 0)    t = 6; | 
					
						
							|  |  |  |             else                        t = 12; | 
					
						
							|  |  |  |             if ((ea >> 3) == 0 || (ea >> 3) == 1 || ea == 0x3c) | 
					
						
							|  |  |  |                 t += 2; /* if reg direct or immediate, timing of 6 is
 | 
					
						
							|  |  |  |                            increased to 8 */ | 
					
						
							|  |  |  |         } break; | 
					
						
							|  |  |  |     case 0xb: | 
					
						
							|  |  |  |         if (!(opmode & 4))  /* CMP */ | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             if (size == BYTE_SIZE || size == WORD_SIZE) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 if ((ea >> 3) == 1)         t = 6; | 
					
						
							|  |  |  |                 else if ((ea >> 3) == 0)    t = 4; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             else | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 if ((ea >> 3) == 1)         t = 6; | 
					
						
							|  |  |  |                 else if ((ea >> 3) == 0)    t = 6; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else                /* EOR */ | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             if (size == BYTE_SIZE || size == WORD_SIZE) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 if ((ea >> 3) == 0)             t = 4; | 
					
						
							|  |  |  |                 else                            t = 8; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             else | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 if ((ea >> 3) == 0)             t = 8; | 
					
						
							|  |  |  |                 else                            t = 12; | 
					
						
							|  |  |  |             } break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     case 0xc:   /* AND */ | 
					
						
							|  |  |  |         if (size == BYTE_SIZE || size == WORD_SIZE) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             if ((ea >> 3) == 0)             t = 4; | 
					
						
							|  |  |  |             else                            t = 8; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             if ((ea >> 3) == 0)             t = 6; | 
					
						
							|  |  |  |             else                            t = 12; | 
					
						
							|  |  |  |             if ((ea >> 3) == 0 || (ea >> 3) == 1 || ea == 0x3c) | 
					
						
							|  |  |  |                 t += 2; /* if reg direct or immediate, timing of 6 is
 | 
					
						
							|  |  |  |                            increased to 8 */ | 
					
						
							|  |  |  |         } break; | 
					
						
							|  |  |  |     case 0x8:   /* OR */ | 
					
						
							|  |  |  |         if (size == BYTE_SIZE || size == WORD_SIZE) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             if ((ea >> 3) == 0)             t = 4; | 
					
						
							|  |  |  |             else                            t = 8; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             if ((ea >> 3) == 0)             t = 6; | 
					
						
							|  |  |  |             else                            t = 12; | 
					
						
							|  |  |  |             if ((ea >> 3) == 0 || (ea >> 3) == 1 || ea == 0x3c) | 
					
						
							|  |  |  |                 t += 2; /* if reg direct or immediate, timing of 6 is
 | 
					
						
							|  |  |  |                            increased to 8 */ | 
					
						
							|  |  |  |         } break; | 
					
						
							|  |  |  |     }     | 
					
						
							|  |  |  |     /* set mnem and opr */ | 
					
						
							|  |  |  |     switch (opr_code) | 
					
						
							|  |  |  |     {   case 0xd:   strcpy(mnem, "ADD");    strcpy(opr, "add"); break; | 
					
						
							|  |  |  |         case 0xc:   strcpy(mnem, "AND");    strcpy(opr, "and"); break; | 
					
						
							|  |  |  |         case 0xb: | 
					
						
							|  |  |  |                     if (opmode & 4) { strcpy(mnem, "EOR"); strcpy(opr, "xor"); } | 
					
						
							|  |  |  |                     else            { strcpy(mnem, "CMP"); strcpy(opr, "cmp"); } | 
					
						
							|  |  |  |                     break; | 
					
						
							|  |  |  |         case 8:     strcpy(mnem, "OR");     strcpy(opr, "or");  break; | 
					
						
							|  |  |  |         case 9:     strcpy(mnem, "SUB");    strcpy(opr, "sub"); break; | 
					
						
							|  |  |  |         default:    return 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     InstBegin(op, mnem, NumDecodedEA(ea)); | 
					
						
							|  |  |  |     if (opmode & 4) /* op Dn,ea */ | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if ((ea >> 3) == 0 || (ea >> 3) == 1)   /* Dn, An shortcut */ | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             char    r[2] = { 'd', 'a' }; | 
					
						
							|  |  |  |             int     i = ea >> 3; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             e("and  edi, byte 7\n"); | 
					
						
							|  |  |  |             e("mov  edx, [d+(%d*4)]\n", (op >> 9) & 7); | 
					
						
							|  |  |  |             e("%s   %s [%c+(edi*4)], %s\n", opr, size_s[opmode & 3], r[i], | 
					
						
							|  |  |  |                                               edx[opmode & 3]); | 
					
						
							|  |  |  |             e("lahf\n"); | 
					
						
							|  |  |  |             switch ((op >> 12) & 0xf)   /* flags calculations */ | 
					
						
							|  |  |  |             {   case 0xc:   e("xor  al, al\n"); break;      /* AND */ | 
					
						
							|  |  |  |                 case 0xd:   e("setc byte [x]\n"); | 
					
						
							|  |  |  |                             e("seto al\n"); break;          /* ADD */ | 
					
						
							|  |  |  |                 case 0xb: | 
					
						
							|  |  |  |                     if (opmode & 4) e("xor  al, al\n");     /* EOR */ | 
					
						
							|  |  |  |                     else            e("seto al\n");         /* CMP */ | 
					
						
							|  |  |  |                     break; | 
					
						
							|  |  |  |                 case 8:     e("xor  al, al\n"); break;      /* OR  */ | 
					
						
							|  |  |  |                 case 9:     e("setc byte [x]\n"); | 
					
						
							|  |  |  |                             e("seto al\n"); break;          /* SUB */ } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             LoadFromEA(ea, size, 0); | 
					
						
							|  |  |  |             e("%s   %s, [d+(%d*4)]\n", opr, edx[opmode & 3], (op >> 9) & 7); | 
					
						
							|  |  |  |             e("lahf\n"); | 
					
						
							|  |  |  |             switch ((op >> 12) & 0xf)   /* flags calculations */ | 
					
						
							|  |  |  |             {   case 0xc:   e("xor  al, al\n"); break;      /* AND */ | 
					
						
							|  |  |  |                 case 0xd:   e("setc byte [x]\n"); | 
					
						
							|  |  |  |                             e("seto al\n"); break;          /* ADD */ | 
					
						
							|  |  |  |                 case 0xb: | 
					
						
							|  |  |  |                     if (opmode & 4) e("xor  al, al\n");     /* EOR */ | 
					
						
							|  |  |  |                     else            e("seto al\n");         /* CMP */ | 
					
						
							|  |  |  |                     break; | 
					
						
							|  |  |  |                 case 8:     e("xor  al, al\n"); break;      /* OR  */ | 
					
						
							|  |  |  |                 case 9:     e("setc byte [x]\n"); | 
					
						
							|  |  |  |                             e("seto al\n"); break;          /* SUB */ } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if(!(((op >> 12) & 0xf) == 0xb && !(opmode & 4))) // don't write if CMP
 | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 switch (size) | 
					
						
							|  |  |  |                 {   case BYTE_SIZE: WriteByte(); break; | 
					
						
							|  |  |  |                     case WORD_SIZE: WriteWord(); break; | 
					
						
							|  |  |  |                     case LONG_SIZE: WriteLong(); break; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             else | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 e("xor edi, edi\n"); // the write functions normally handle this
 | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else            /* op ea,Dn */ | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         LoadFromEA(ea, size, 0); | 
					
						
							|  |  |  |         e("%s   [d+(%d*4)], %s\n", opr, (op >> 9) & 7, edx[opmode & 3]); | 
					
						
							|  |  |  |         e("lahf\n"); | 
					
						
							|  |  |  |         switch ((op >> 12) & 0xf)   /* flags calculations */ | 
					
						
							|  |  |  |         {   case 0xc:   e("xor  al, al\n"); break;      /* AND */ | 
					
						
							|  |  |  |             case 0xd:   e("setc byte [x]\n"); | 
					
						
							|  |  |  |                         e("seto al\n"); break;          /* ADD */ | 
					
						
							|  |  |  |             case 0xb: | 
					
						
							|  |  |  |                 if (opmode & 4) e("xor  al, al\n");     /* EOR */ | 
					
						
							|  |  |  |                 else            e("seto al\n");         /* CMP */ | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             case 8:     e("xor  al, al\n"); break;      /* OR  */ | 
					
						
							|  |  |  |             case 9:     e("setc byte [x]\n"); | 
					
						
							|  |  |  |                         e("seto al\n"); break;          /* SUB */ }         | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     EmitTiming(t); | 
					
						
							|  |  |  |     InstEnd(); | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int ArithmeticI(unsigned short op, char *mnem_unused, unsigned base_timing) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     unsigned    t = base_timing, ea = op & 0x3f;    /* base_timing = 8 */ | 
					
						
							|  |  |  |     int         size = UNKNOWN_SIZE; | 
					
						
							|  |  |  |     char        mnem[5]; | 
					
						
							|  |  |  |     char        opr[5], *size_s[] = { "byte", "word", "dword" }, | 
					
						
							|  |  |  |                 *edx[] = { "dl", "dx", "edx" }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!CheckEA(ea, "101111111000")) | 
					
						
							|  |  |  |         return 0; | 
					
						
							|  |  |  |     if (!NumDecodedEA(ea))  /* check if decoded this EA */ | 
					
						
							|  |  |  |         return 0; | 
					
						
							|  |  |  |     switch ((op >> 6) & 3)  /* set allowed sizes */ | 
					
						
							|  |  |  |     {   case 0:     size = BYTE_SIZE; break; | 
					
						
							|  |  |  |         case 1:     size = WORD_SIZE; break; | 
					
						
							|  |  |  |         case 2:     size = LONG_SIZE; break; | 
					
						
							|  |  |  |         default:    return 0;   }     | 
					
						
							|  |  |  |     switch ((op >> 8) & 0xf)    /* set operation, mnem */ | 
					
						
							|  |  |  |     {   case 2:     strcpy(mnem, "ANDI"); strcpy(opr, "and"); break; | 
					
						
							|  |  |  |         case 6:     strcpy(mnem, "ADDI"); strcpy(opr, "add"); break; | 
					
						
							|  |  |  |         case 0xc:   strcpy(mnem, "CMPI"); strcpy(opr, "cmp"); break; | 
					
						
							|  |  |  |         case 0xa:   strcpy(mnem, "EORI"); strcpy(opr, "xor"); break; | 
					
						
							|  |  |  |         case 0:     strcpy(mnem, "ORI");  strcpy(opr, "or");  break; | 
					
						
							|  |  |  |         case 4:     strcpy(mnem, "SUBI"); strcpy(opr, "sub"); break; | 
					
						
							|  |  |  |         default:    return 0;  } | 
					
						
							|  |  |  |     /* all but CMPI,ANDI take 8+8 cycles for long sizes */ | 
					
						
							|  |  |  |     if (((op >> 8) & 0xf) != 0xc && ((op >> 8) & 0xf) != 2 && size == LONG_SIZE) | 
					
						
							|  |  |  |         t += 8; | 
					
						
							|  |  |  |     else if (((op >> 8) & 0xf) == 0xc)                  t += 6; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     InstBegin(op, mnem, NumDecodedEA(ea)); | 
					
						
							|  |  |  |     if (((ea >> 3) & 7) == 0)   /* Dn is treated differently */ | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         e("and  edi, byte 7\n");/* get reg # */ | 
					
						
							|  |  |  |         e("mov  edx, [esi]\n"); /* get imm data */ | 
					
						
							|  |  |  |         if (size == LONG_SIZE) | 
					
						
							|  |  |  |             e("ror  edx, byte 16\n");   /* prep. the long-word */ | 
					
						
							|  |  |  |         e("%s   %s [d+edi*4], %s\n", opr, size_s[(op >> 6) & 3], edx[(op >> 6) & 3]); | 
					
						
							|  |  |  |         e("lahf\n"); | 
					
						
							|  |  |  |         switch ((op >> 8) & 0xf)    /* flags calculations */ | 
					
						
							|  |  |  |         {   case 2:     e("xor  al, al\n"); break;      /* ANDI */ | 
					
						
							|  |  |  |             case 6:     e("setc byte [x]\n"); | 
					
						
							|  |  |  |                         e("seto al\n"); break;          /* ADDI */ | 
					
						
							|  |  |  |             case 0xc:   e("seto al\n"); break;          /* CMPI */ | 
					
						
							|  |  |  |             case 0xa:   e("xor  al, al\n"); break;      /* EORI */ | 
					
						
							|  |  |  |             case 0:     e("xor  al, al\n"); break;      /* ORI  */ | 
					
						
							|  |  |  |             case 4:     e("setc byte [x]\n"); | 
					
						
							|  |  |  |                         e("seto al\n"); break;          /* SUBI */ } | 
					
						
							|  |  |  |         if (size != LONG_SIZE) | 
					
						
							|  |  |  |             e("add  esi, byte 2\n"); | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |             e("add  esi, byte 4\n"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         SaveReg("run", "esi");      /* address of immediate data */ | 
					
						
							|  |  |  |         switch (size)   /* make ESI point to EA data */ | 
					
						
							|  |  |  |         {   case BYTE_SIZE: | 
					
						
							|  |  |  |             case WORD_SIZE: e("add  esi, byte 2\n"); break; | 
					
						
							|  |  |  |             case LONG_SIZE: e("add  esi, byte 4\n"); break; | 
					
						
							|  |  |  |         }             | 
					
						
							|  |  |  |         LoadFromEA(ea, size, 0); | 
					
						
							|  |  |  |         RestoreRegTo("run", "esi", "edi"); /* EDI=address of immediate data */ | 
					
						
							|  |  |  |         /* if byte or word, perform operation directly from memory */ | 
					
						
							|  |  |  |         if (size == BYTE_SIZE || size == WORD_SIZE) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             e("%s   %s, [edi]\n", opr, edx[(op >> 6) & 3]); | 
					
						
							|  |  |  |             e("lahf\n"); | 
					
						
							|  |  |  |             switch ((op >> 8) & 0xf)    /* flags calculations */ | 
					
						
							|  |  |  |             {   case 2:     e("xor  al, al\n"); break;      /* ANDI */ | 
					
						
							|  |  |  |                 case 6:     e("setc byte [x]\n"); | 
					
						
							|  |  |  |                             e("seto al\n"); break;          /* ADDI */ | 
					
						
							|  |  |  |                 case 0xc:   e("seto al\n"); break;          /* CMPI */ | 
					
						
							|  |  |  |                 case 0xa:   e("xor  al, al\n"); break;      /* EORI */ | 
					
						
							|  |  |  |                 case 0:     e("xor  al, al\n"); break;      /* ORI  */ | 
					
						
							|  |  |  |                 case 4:     e("setc byte [x]\n"); | 
					
						
							|  |  |  |                             e("seto al\n"); break;          /* SUBI */ } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else    /* long */ | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             e("mov  edi, [edi]\n"); | 
					
						
							|  |  |  |             e("ror  edi, byte 16\n");   /* word-swap long-words... */ | 
					
						
							|  |  |  |             e("%s   %s, edi\n", opr, edx[(op >> 6) & 3]); | 
					
						
							|  |  |  |             e("lahf\n"); | 
					
						
							|  |  |  |             switch ((op >> 8) & 0xf)    /* flags calculations */ | 
					
						
							|  |  |  |             {   case 2:     e("xor  al, al\n"); break;      /* ANDI */ | 
					
						
							|  |  |  |                 case 6:     e("setc byte [x]\n"); | 
					
						
							|  |  |  |                             e("seto al\n"); break;          /* ADDI */ | 
					
						
							|  |  |  |                 case 0xc:   e("seto al\n"); break;          /* CMPI */ | 
					
						
							|  |  |  |                 case 0xa:   e("xor  al, al\n"); break;      /* EORI */ | 
					
						
							|  |  |  |                 case 0:     e("xor  al, al\n"); break;      /* ORI  */ | 
					
						
							|  |  |  |                 case 4:     e("setc byte [x]\n"); | 
					
						
							|  |  |  |                             e("seto al\n"); break;          /* SUBI */ } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if(((op >> 8) & 0x0F) != 0x0C) | 
					
						
							|  |  |  |       { | 
					
						
							|  |  |  |         switch (size)   /* write back to mem */ | 
					
						
							|  |  |  |         {   case BYTE_SIZE: WriteByte(); break; | 
					
						
							|  |  |  |             case WORD_SIZE: WriteWord(); break; | 
					
						
							|  |  |  |             case LONG_SIZE: WriteLong(); break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       else | 
					
						
							|  |  |  |       { | 
					
						
							|  |  |  |         e("xor edi, edi\n"); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     EmitTiming(t + TimingEA(ea, size)); | 
					
						
							|  |  |  |     InstEnd(); | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int MOVE(unsigned short op, char *mnem, unsigned base_timing) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     unsigned    src = op & 0x3f, dest = (op >> 6) & 0x3f; | 
					
						
							|  |  |  |     int         size = UNKNOWN_SIZE; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     dest = ((dest & 0x7) << 3) | ((dest >> 3) & 0x7); | 
					
						
							|  |  |  |     if (!CheckEA(src, "111111111111") || !CheckEA(dest, "101111111000")) | 
					
						
							|  |  |  |         return 0; | 
					
						
							|  |  |  |     if (!NumDecodedEA(src)) /* check if decoded this source EA */ | 
					
						
							|  |  |  |         return 0; | 
					
						
							|  |  |  |     switch ((op >> 12) & 3) /* set allowed sizes */ | 
					
						
							|  |  |  |     {   case 1:     size = BYTE_SIZE; break; | 
					
						
							|  |  |  |         case 3:     size = WORD_SIZE; break; | 
					
						
							|  |  |  |         case 2:     size = LONG_SIZE; break; | 
					
						
							|  |  |  |         default:    return 0; } | 
					
						
							|  |  |  |     if (size == BYTE_SIZE && ((src >> 3) & 7) == 1) | 
					
						
							|  |  |  |         return 0;   /* no An byte accesses allowed */ | 
					
						
							|  |  |  |     InstBegin(op, mnem, NumDecodedEA(op & 0x3f)); | 
					
						
							|  |  |  |     LoadFromEA(src, size, 0); | 
					
						
							|  |  |  |     switch (size) | 
					
						
							|  |  |  |     {   case BYTE_SIZE: e("test dl, dl\n"); break; | 
					
						
							|  |  |  |         case WORD_SIZE: e("test dx, dx\n"); break; | 
					
						
							|  |  |  |         case LONG_SIZE: e("test edx, edx\n"); break;    } | 
					
						
							|  |  |  |     e("lahf\n"); | 
					
						
							|  |  |  |     e("xor  al, al\n"); /* V=always cleared */ | 
					
						
							|  |  |  |     if (src == dest) | 
					
						
							|  |  |  |         StoreToEA(dest, size, 1); | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |         StoreToEA(dest, size, 0); | 
					
						
							|  |  |  |     EmitTiming(base_timing + TimingEA(src, size) + TimingEA(dest, size)); | 
					
						
							|  |  |  |     InstEnd(); | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int MOVEQ(unsigned op, char *mnem, unsigned base_timing) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     InstBegin(op, mnem, 256);   /* 256 possible immediate data combinations */ | 
					
						
							|  |  |  |     e("mov      ebx, edi\n");   /* opcode is in edi */ | 
					
						
							|  |  |  |     e("movsx    ebx, bl\n");    /* sign extend */ | 
					
						
							|  |  |  |     e("mov      [d+%d*4], ebx\n", (op >> 9) & 7); | 
					
						
							|  |  |  |     e("test     bl, bl\n");     /* set N,Z,C appropriately */ | 
					
						
							|  |  |  |     e("lahf\n");                /* get changes */ | 
					
						
							|  |  |  |     e("xor      al, al\n");     /* V is cleared */    | 
					
						
							|  |  |  |     EmitTiming(base_timing); | 
					
						
							|  |  |  |     InstEnd(); | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int MOVEA(unsigned short op, char *mnem, unsigned base_timing) | 
					
						
							|  |  |  | {     | 
					
						
							|  |  |  |     int     size = UNKNOWN_SIZE; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!CheckEA(op & 0x3f, "111111111111"))    /* check EA mode */ | 
					
						
							|  |  |  |         return 0; | 
					
						
							|  |  |  |     if (!NumDecodedEA(op & 0x3f))               /* check if decoded this EA */ | 
					
						
							|  |  |  |         return 0; | 
					
						
							|  |  |  |     switch ((op >> 12) & 3) /* set allowed sizes */ | 
					
						
							|  |  |  |     {   case 3:     size = WORD_SIZE; break; | 
					
						
							|  |  |  |         case 2:     size = LONG_SIZE; break; | 
					
						
							|  |  |  |         default:    return 0; } | 
					
						
							|  |  |  |           | 
					
						
							|  |  |  |     InstBegin(op, mnem, NumDecodedEA(op & 0x3f));     | 
					
						
							|  |  |  |     LoadFromEA(op & 0x3f, size, 1);                 /* load */ | 
					
						
							|  |  |  |     e("mov  [a+%d*4], edx\n", (op >> 9) & 7);     /* store */ | 
					
						
							|  |  |  |     EmitTiming(TimingEA(op & 0x3f, size) + base_timing); | 
					
						
							|  |  |  |     InstEnd(); | 
					
						
							|  |  |  |     return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*****************************************************************************
 | 
					
						
							|  |  |  | * Instruction Emission                                                      */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void EmitInstructions() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     unsigned    i, j, k, l, n; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* TST */ | 
					
						
							|  |  |  |     n = 0; | 
					
						
							|  |  |  |     for (i = 0; i <= 2; i++) | 
					
						
							|  |  |  |         for (j = 0; j <= 0x3f; j++) | 
					
						
							|  |  |  |             n += TST((i << 6) + j + 0x4a00, "TST", 4); | 
					
						
							|  |  |  |     printf("TST:\t\t%d\n", n); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Bcc */ | 
					
						
							|  |  |  |     n = 0; | 
					
						
							|  |  |  |     for (i = 0; i <= 0xf; i++) | 
					
						
							|  |  |  |         for (j = 0; j < 0xff; j++) | 
					
						
							|  |  |  |             n += Bcc((i << 8) + j + 0x6000, "B??", 0); | 
					
						
							|  |  |  |     printf("Bcc:\t\t%d\n", n); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* MOVE */ | 
					
						
							|  |  |  |     n = 0; | 
					
						
							|  |  |  |     for (i = 1; i <= 3; i++)            /* size */ | 
					
						
							|  |  |  |         for (j = 0; j <= 0x3f; j++)     /* dest. EA */ | 
					
						
							|  |  |  |             for (k = 0; k <= 0x3f; k++) /* source EA */ | 
					
						
							|  |  |  |                 n += MOVE((i << 12) + (j << 6) + k + 0x0000, "MOVE", 4); | 
					
						
							|  |  |  |     printf("MOVE:\t\t%d\n", n); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* ADD, AND, CMP, EOR, OR, SUB -- "Arithmetic" */ | 
					
						
							|  |  |  |     n = 0; | 
					
						
							|  |  |  |     for (i = 8; i <= 0xd; i++)              /* operation */ | 
					
						
							|  |  |  |         for (j = 0; j <= 7; j++)            /* Dn */ | 
					
						
							|  |  |  |             for (k = 0; k <= 6; k++)        /* opmode */ | 
					
						
							|  |  |  |                 for (l = 0; l <= 0x3f; l++) /* EA */ | 
					
						
							|  |  |  |                     n += Arithmetic((i << 12) + (j << 9) + (k << 6) + l, "????", 0); | 
					
						
							|  |  |  |     printf("ADD, AND, CMP, EOR, OR, SUB: %d\n", n); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* ADDI, ANDI, CMPI, EORI, ORI, SUBI -- "ArithmeticI" */ | 
					
						
							|  |  |  |     n = 0; | 
					
						
							|  |  |  |     for (i = 0; i <= 0xc; i++)          /* operation */ | 
					
						
							|  |  |  |         for (j = 0; j <= 2; j++)        /* size */ | 
					
						
							|  |  |  |             for (k = 0; k <= 0x3f; k++) /* EA */ | 
					
						
							|  |  |  |                 n += ArithmeticI((i << 8) + (j << 6) + k + 0x0000, "????I", 8); | 
					
						
							|  |  |  |     printf("ADDI, ANDI, CMPI, EORI, ORI, SUBI: %d\n", n); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* DBcc */ | 
					
						
							|  |  |  |     n = 0; | 
					
						
							|  |  |  |     for (i = 0; i <= 0xf; i++)          /* condition */ | 
					
						
							|  |  |  |         n += DBcc((i << 8) + 0x50c8, "DB??", 0); | 
					
						
							|  |  |  |     printf("DBcc:\t\t%d\n", n); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* BTST */ | 
					
						
							|  |  |  |     n = 0; | 
					
						
							|  |  |  |     for (i = 0; i <= 7; i++)            /* register */ | 
					
						
							|  |  |  |         for (j = 0; j <= 0x3f; j++)     /* EA */ | 
					
						
							|  |  |  |             n += BTST((i << 9) + j + 0x0100, "BTST", 0); | 
					
						
							|  |  |  |     for (i = 0; i <= 0x3f; i++)         /* EA */ | 
					
						
							|  |  |  |         n += BTST(i + 0x0800, "BTST", 0); | 
					
						
							|  |  |  |     printf("BTST:\t\t%d\n", n); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* ADDQ, SUBQ -- "ArithmeticQ" */ | 
					
						
							|  |  |  |     n = 0; | 
					
						
							|  |  |  |     for (i = 0; i <= 7; i++)                /* data */ | 
					
						
							|  |  |  |         for (j = 0; j <= 1; j++)            /* ADDQ/SUBQ */ | 
					
						
							|  |  |  |             for (k = 0; k <= 2; k++)        /* size */ | 
					
						
							|  |  |  |                 for (l = 0; l <= 0x3f; l++) /* EA */ | 
					
						
							|  |  |  |                     n += ArithmeticQ((i << 9) + (j << 8) + (k << 6) + l + 0x5000, "???Q", 4); | 
					
						
							|  |  |  |     printf("ADDQ, SUBQ:\t%d\n", n); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* BRA */ | 
					
						
							|  |  |  |     n = 0; | 
					
						
							|  |  |  |     for (i = 0; i <= 0xff; i++) | 
					
						
							|  |  |  |         n += Bxx(i + 0x6000, "BRA", 10); | 
					
						
							|  |  |  |     printf("BRA:\t\t%d\n", n); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* LEA */ | 
					
						
							|  |  |  |     n = 0; | 
					
						
							|  |  |  |     for (i = 0; i <= 7; i++)            /* register */ | 
					
						
							|  |  |  |         for (j = 0; j <= 0x3f; j++)     /* EA */ | 
					
						
							|  |  |  |             n += LEA((i << 9) + 0x41c0 + j, "LEA", 0); | 
					
						
							|  |  |  |     printf("LEA:\t\t%d\n", n); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* RTS */ | 
					
						
							|  |  |  |     RTS(0x4e75, "RTS", 16); | 
					
						
							|  |  |  |     printf("RTS:\t\t1\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* MOVEA */ | 
					
						
							|  |  |  |     n = 0; | 
					
						
							|  |  |  |     for (i = 2; i <= 3; i++)            /* size */ | 
					
						
							|  |  |  |         for (j = 0; j <= 7; j++)        /* dest. reg */ | 
					
						
							|  |  |  |             for (k = 0; k <= 0x3f; k++) /* source EA */ | 
					
						
							|  |  |  |                 n += MOVEA((i << 12) + (j << 9) + k + 0x0040, "MOVEA", 4); | 
					
						
							|  |  |  |     printf("MOVEA:\t\t%d\n", n); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* ADDA */ | 
					
						
							|  |  |  |     n = 0; | 
					
						
							|  |  |  |     for (i = 3; i <= 7; i++)            /* size */ | 
					
						
							|  |  |  |         for (j = 0; j <= 7; j++)        /* dest. reg */ | 
					
						
							|  |  |  |             for (k = 0; k <= 0x3f; k++) /* source EA */ | 
					
						
							|  |  |  |                 n += ArithmeticA((i << 6) + (j << 9) + k + 0xd000, "ADDA", 4); | 
					
						
							|  |  |  |     printf("ADDA:\t\t%d\n", n); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* MOVEQ */ | 
					
						
							|  |  |  |     n = 0; | 
					
						
							|  |  |  |     for (i = 0; i < 8; i++) | 
					
						
							|  |  |  |         n += MOVEQ((i << 9) + 0x7000, "MOVEQ", 4); | 
					
						
							|  |  |  |     printf("MOVEQ:\t\t%d\n", n); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* JSR */ | 
					
						
							|  |  |  |     n = 0; | 
					
						
							|  |  |  |     for (i = 0; i <= 0x3f; i++)         /* register */ | 
					
						
							|  |  |  |         n += Jxx(i + 0x4e80, "JSR", 0); | 
					
						
							|  |  |  |     printf("JSR:\t\t%d\n", n); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* LSL, LSR */ | 
					
						
							|  |  |  |     n = 0; | 
					
						
							|  |  |  |     for (i = 0; i <= 7; i++)                /* count/register */ | 
					
						
							|  |  |  |         for (j = 0; j <= 1; j++)            /* direction */ | 
					
						
							|  |  |  |             for (k = 0; k <= 2; k++)        /* size */ | 
					
						
							|  |  |  |                 for (l = 0; l <= 1; l++)    /* immediate/reg */ | 
					
						
							|  |  |  |                     n += LSxReg((i << 9) + (j << 8) + (k << 6) + (l << 5) + 0xe008, "LS?", 0); | 
					
						
							|  |  |  |     for (i = 0; i <= 1; i++)                /* direction */ | 
					
						
							|  |  |  |         for (j = 0; j <= 0x3f; j++)         /* EA */ | 
					
						
							|  |  |  |             n += LSxMem((i << 8) + j + 0xe2c0, "LS?", 8); | 
					
						
							|  |  |  |     printf("LSL, LSR:\t%d\n", n);     | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* SWAP */ | 
					
						
							|  |  |  |     SWAP(0x4840, "SWAP", 4); | 
					
						
							|  |  |  |     printf("SWAP:\t\t1\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* BSR */ | 
					
						
							|  |  |  |     n = 0; | 
					
						
							|  |  |  |     for (i = 0; i <= 0xff; i++) | 
					
						
							|  |  |  |         n += Bxx(i + 0x6100, "BSR", 18); | 
					
						
							|  |  |  |     printf("BSR:\t\t%d\n", n); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* EXT */ | 
					
						
							|  |  |  |     n = 0; | 
					
						
							|  |  |  |     for (i = 2; i <= 7; i++) | 
					
						
							|  |  |  |         n += EXT((i << 6) + 0x4800, "EXT", 4); | 
					
						
							|  |  |  |     printf("EXT:\t\t%d\n", n); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* CLR */ | 
					
						
							|  |  |  |     n = 0; | 
					
						
							|  |  |  |     for (i = 0; i <= 2; i++)            /* size */ | 
					
						
							|  |  |  |         for (j = 0; j <= 0x3f; j++)     /* EA */ | 
					
						
							|  |  |  |             n += CLR((i << 6) + j + 0x4200, "CLR", 0); | 
					
						
							|  |  |  |     printf("CLR:\t\t%d\n", n); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* MOVEM */ | 
					
						
							|  |  |  |     n = 0; | 
					
						
							|  |  |  |     for (i = 0; i <= 1; i++)            /* direction */ | 
					
						
							|  |  |  |         for (j = 0; j <= 1; j++)        /* size */ | 
					
						
							|  |  |  |             for (k = 0; k <= 0x3f; k++) /* EA */ | 
					
						
							|  |  |  |                 n += MOVEM((i << 10) + (j << 6) + k + 0x4880, "MOVEM", 0); | 
					
						
							|  |  |  |     printf("MOVEM:\t\t%d\n", n); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* MOVE to SR */ | 
					
						
							|  |  |  |     n = 0; | 
					
						
							|  |  |  |     for (i = 0; i <= 0x3f; i++) | 
					
						
							|  |  |  |         n += MOVEtoSR(i + 0x46c0, "MOVE to SR", 12); | 
					
						
							|  |  |  |     printf("MOVE to SR:\t%d\n", n); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* NOP */ | 
					
						
							|  |  |  |     NOP(0x4e71, "NOP", 4); | 
					
						
							|  |  |  |     printf("NOP:\t\t1\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* JMP */ | 
					
						
							|  |  |  |     n = 0; | 
					
						
							|  |  |  |     for (i = 0; i <= 0x3f; i++)         /* register */ | 
					
						
							|  |  |  |         n += Jxx(i + 0x4ec0, "JMP", 0); | 
					
						
							|  |  |  |     printf("JMP:\t\t%d\n", n); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* CMPA */ | 
					
						
							|  |  |  |     n = 0; | 
					
						
							|  |  |  |     for (i = 0; i <= 7; i++)            /* register */ | 
					
						
							|  |  |  |         for (j = 3; j <= 7; j++)        /* opmode */ | 
					
						
							|  |  |  |             for (k = 0; k <= 0x3f; k++) /* EA */ | 
					
						
							|  |  |  |                 n += CMPA((i << 9) + (j << 6) + k + 0xb000, "CMPA", 0); | 
					
						
							|  |  |  |     printf("CMPA:\t\t%d\n", n); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* ASL, ASR */ | 
					
						
							|  |  |  |     n = 0; | 
					
						
							|  |  |  |     for (i = 0; i <= 7; i++)                /* count/reg */ | 
					
						
							|  |  |  |         for (j = 0; j <= 1; j++)            /* direction */ | 
					
						
							|  |  |  |             for (k = 0; k <= 2; k++)        /* size */ | 
					
						
							|  |  |  |                 for (l = 0; l <= 1; l++)    /* immediate/reg */ | 
					
						
							|  |  |  |                     n += ASxReg((i << 9) + (j << 8) + (k << 6) + (l << 5) + 0xe000, "AS?", 0); | 
					
						
							|  |  |  |     for (i = 0; i <= 1; i++)                /* direction */ | 
					
						
							|  |  |  |         for (j = 0; j <= 0x3f; j++)         /* EA */ | 
					
						
							|  |  |  |             n += ASxMem((i << 8) + j + 0xe0c0, "AS?", 8); | 
					
						
							|  |  |  |     printf("ASL, ASR:\t%d\n", n); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* MULS */ | 
					
						
							|  |  |  |     n = 0; | 
					
						
							|  |  |  |     for (i = 0; i <= 7; i++)        /* register */ | 
					
						
							|  |  |  |         for (j = 0; j <= 0x3f; j++) /* EA */ | 
					
						
							|  |  |  |             n += MULS((i << 9) + j + 0xc1c0, "MULS", 70); | 
					
						
							|  |  |  |     printf("MULS:\t\t%d\n", n); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* RTE */ | 
					
						
							|  |  |  |     RTE(0x4e73, "RTE", 20); | 
					
						
							|  |  |  |     printf("RTE:\t\t1\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* NEG, NEGX */ | 
					
						
							|  |  |  |     n = 0; | 
					
						
							|  |  |  |     for (i = 0; i <= 1; i++)            /* NEG/NEGX */ | 
					
						
							|  |  |  |         for (j = 0; j <= 2; j++)        /* size */ | 
					
						
							|  |  |  |             for (k = 0; k <= 0x3f; k++) /* EA */ | 
					
						
							|  |  |  |                 n += NEGx((i << 10) + (j << 6) + k + 0x4000, "NEG?", 0); | 
					
						
							|  |  |  |     printf("NEG, NEGX:\t%d\n", n); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* ROL, ROR */ | 
					
						
							|  |  |  |     n = 0; | 
					
						
							|  |  |  |     for (i = 0; i <= 7; i++)                /* count/register */ | 
					
						
							|  |  |  |         for (j = 0; j <= 1; j++)            /* direction */ | 
					
						
							|  |  |  |             for (k = 0; k <= 2; k++)        /* size */ | 
					
						
							|  |  |  |                 for (l = 0; l <= 1; l++)    /* immediate/reg */ | 
					
						
							|  |  |  |                     n += ROxReg((i << 9) + (j << 8) + (k << 6) + (l << 5) + 0xe018, "RO?", 0); | 
					
						
							|  |  |  |     for (i = 0; i <= 1; i++)                /* direction */ | 
					
						
							|  |  |  |         for (j = 0; j <= 0x3f; j++)         /* EA */ | 
					
						
							|  |  |  |             n += ROxMem((i << 8) + j + 0xe6c0, "RO?", 8); | 
					
						
							|  |  |  |     printf("ROL, ROR:\t%d\n", n); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* BCLR */ | 
					
						
							|  |  |  |     n = 0; | 
					
						
							|  |  |  |     for (i = 0; i <= 7; i++)            /* register */ | 
					
						
							|  |  |  |         for (j = 0; j <= 0x3f; j++)     /* EA */ | 
					
						
							|  |  |  |             n += BCLR((i << 9) + j + 0x0180, "BCLR", 0); | 
					
						
							|  |  |  |     for (i = 0; i <= 0x3f; i++)         /* EA */ | 
					
						
							|  |  |  |         n += BCLR(i + 0x0880, "BCLR", 0); | 
					
						
							|  |  |  |     printf("BCLR:\t\t%d\n", n); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* NOT */ | 
					
						
							|  |  |  |     n = 0; | 
					
						
							|  |  |  |     for (i = 0; i <= 2; i++) | 
					
						
							|  |  |  |         for (j = 0; j <= 0x3f; j++) | 
					
						
							|  |  |  |             n += NOT((i << 6) + j + 0x4600, "NOT", 0); | 
					
						
							|  |  |  |     printf("NOT:\t\t%d\n", n); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* MOVE USP */ | 
					
						
							|  |  |  |     n = 0; | 
					
						
							|  |  |  |     for (i = 0; i <= 1; i++) | 
					
						
							|  |  |  |         n += MOVEUSP((i << 3) + 0x4e60, "MOVE USP", 4); | 
					
						
							|  |  |  |     printf("MOVE USP:\t%d\n", n); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* ROXL, ROXR */ | 
					
						
							|  |  |  |     n = 0; | 
					
						
							|  |  |  |     for (i = 0; i <= 7; i++)                /* count/register */ | 
					
						
							|  |  |  |         for (j = 0; j <= 1; j++)            /* direction */ | 
					
						
							|  |  |  |             for (k = 0; k <= 2; k++)        /* size */ | 
					
						
							|  |  |  |                 for (l = 0; l <= 1; l++)    /* immediate/reg */ | 
					
						
							|  |  |  |                     n += ROXxReg((i << 9) + (j << 8) + (k << 6) + (l << 5) + 0xe010, "ROX?", 0); | 
					
						
							|  |  |  |     for (i = 0; i <= 1; i++)                /* direction */ | 
					
						
							|  |  |  |         for (j = 0; j <= 0x3f; j++)         /* EA */ | 
					
						
							|  |  |  |             n += ROXxMem((i << 8) + j + 0xe4c0, "ROX?", 8); | 
					
						
							|  |  |  |     printf("ROXL, ROXR:\t%d\n", n); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* BSET */ | 
					
						
							|  |  |  |     n = 0; | 
					
						
							|  |  |  |     for (i = 0; i <= 7; i++)            /* register */ | 
					
						
							|  |  |  |         for (j = 0; j <= 0x3f; j++)     /* EA */ | 
					
						
							|  |  |  |             n += BSET((i << 9) + j + 0x01c0, "BSET", 0); | 
					
						
							|  |  |  |     for (i = 0; i <= 0x3f; i++)         /* EA */ | 
					
						
							|  |  |  |         n += BSET(i + 0x08c0, "BSET", 0); | 
					
						
							|  |  |  |     printf("BSET:\t\t%d\n", n); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* MOVE from SR */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |      * The 68000 and 68008 "MOVE from SR" is not privileged. But for the 68010 | 
					
						
							|  |  |  |      * and higher, it is. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     n = 0; | 
					
						
							|  |  |  |     for (i = 0; i <= 0x3f; i++) | 
					
						
							|  |  |  |         n += MOVEfromSR(i + 0x40c0, "MOVE from SR", 0); | 
					
						
							|  |  |  |     printf("MOVE from SR:\t%d\n", n); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* SUBA */ | 
					
						
							|  |  |  |     n = 0; | 
					
						
							|  |  |  |     for (i = 3; i <= 7; i++)            /* size */ | 
					
						
							|  |  |  |         for (j = 0; j <= 7; j++)        /* dest. reg */ | 
					
						
							|  |  |  |             for (k = 0; k <= 0x3f; k++) /* source EA */ | 
					
						
							|  |  |  |                 n += ArithmeticA((i << 6) + (j << 9) + k + 0x9000, "SUBA", 4); | 
					
						
							|  |  |  |     printf("SUBA:\t\t%d\n", n); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* DIVS */ | 
					
						
							|  |  |  |     n = 0; | 
					
						
							|  |  |  |     for (i = 0; i <= 7; i++)            /* register */ | 
					
						
							|  |  |  |         for (j = 0; j <= 0x3f; j++)     /* EA */ | 
					
						
							|  |  |  |             n += DIVS((i << 9) + j + 0x81c0, "DIVS", 158); | 
					
						
							|  |  |  |     printf("DIVS:\t\t%d\n", n); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* MULU */ | 
					
						
							|  |  |  |     n = 0; | 
					
						
							|  |  |  |     for (i = 0; i <= 7; i++)        /* register */ | 
					
						
							|  |  |  |         for (j = 0; j <= 0x3f; j++) /* EA */ | 
					
						
							|  |  |  |             n += MULU((i << 9) + j + 0xc0c0, "MULU", 70); | 
					
						
							|  |  |  |     printf("MULU:\t\t%d\n", n); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* ADDX */ | 
					
						
							|  |  |  |     n = 0; | 
					
						
							|  |  |  |     for (i = 0; i <= 7; i++)                /* Rx */ | 
					
						
							|  |  |  |         for (j = 0; j <= 2; j++)            /* size */ | 
					
						
							|  |  |  |             for (k = 0; k <= 1; k++)        /* R/M */ | 
					
						
							|  |  |  |                 n += ADDX((i << 9) + (j << 6) + (k << 3) + 0xd100, "ADDX", 0); | 
					
						
							|  |  |  |     printf("ADDX:\t\t%d\n", n); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Scc */ | 
					
						
							|  |  |  |     n = 0; | 
					
						
							|  |  |  |     for (i = 0; i <= 0xf; i++)      /* condition */ | 
					
						
							|  |  |  |         for (j = 0; j <= 0x3f; j++) /* EA */ | 
					
						
							|  |  |  |             n += Scc((i << 8) + j + 0x50c0, "S??", 0); | 
					
						
							|  |  |  |     printf("Scc:\t\t%d\n", n); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* ORI to SR */ | 
					
						
							|  |  |  |     ORItoSR(0x007c, "ORI to SR", 20); | 
					
						
							|  |  |  |     printf("ORI to SR:\t1\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* MOVE to CCR */ | 
					
						
							|  |  |  |     n = 0; | 
					
						
							|  |  |  |     for (i = 0; i <= 0x3f; i++) | 
					
						
							|  |  |  |         n += MOVEtoCCR(i + 0x44c0, "MOVE to CCR", 12); | 
					
						
							|  |  |  |     printf("MOVE to CCR:\t%d\n", n); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* EXG */ | 
					
						
							|  |  |  |     n = 0; | 
					
						
							|  |  |  |     for (i = 0; i <= 7; i++)            /* Rx */ | 
					
						
							|  |  |  |         for (j = 0; j <= 0x11; j++)     /* opmode */ | 
					
						
							|  |  |  |             n += EXG((i << 9) + (j << 3) + 0xc100, "EXG", 6); | 
					
						
							|  |  |  |     printf("EXG:\t\t%d\n", n); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* UNLK */ | 
					
						
							|  |  |  |     UNLK(0x4e58, "UNLK", 12); | 
					
						
							|  |  |  |     printf("UNLK:\t\t1\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* LINK */ | 
					
						
							|  |  |  |     LINK(0x4e50, "LINK", 16);   /* word */ | 
					
						
							|  |  |  |     printf("LINK:\t\t1\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* DIVU */ | 
					
						
							|  |  |  |     n = 0; | 
					
						
							|  |  |  |     for (i = 0; i <= 7; i++)            /* register */ | 
					
						
							|  |  |  |         for (j = 0; j <= 0x3f; j++)     /* EA */ | 
					
						
							|  |  |  |             n += DIVU((i << 9) + j + 0x80c0, "DIVU", 144); | 
					
						
							|  |  |  |     printf("DIVU:\t\t%d\n", n); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* ANDI to CCR */ | 
					
						
							|  |  |  |     ANDItoCCR(0x023c, "ANDI to CCR", 20); | 
					
						
							|  |  |  |     printf("ANDI to CCR:\t1\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* PEA */ | 
					
						
							|  |  |  |     n = 0; | 
					
						
							|  |  |  |     for (i = 0; i <= 0x3f; i++) | 
					
						
							|  |  |  |         n += PEA(i + 0x4840, "PEA", 0); | 
					
						
							|  |  |  |     printf("PEA:\t\t%d\n", n); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* ANDI to SR */ | 
					
						
							|  |  |  |     ANDItoSR(0x027c, "ANDI to SR", 20); | 
					
						
							|  |  |  |     printf("ANDI to SR:\t%d\n", n); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* BCHG */ | 
					
						
							|  |  |  |     n = 0; | 
					
						
							|  |  |  |     for (i = 0; i <= 7; i++)            /* register */ | 
					
						
							|  |  |  |         for (j = 0; j <= 0x3f; j++)     /* EA */ | 
					
						
							|  |  |  |             n += BCHG((i << 9) + j + 0x0140, "BCHG", 0); | 
					
						
							|  |  |  |     for (i = 0; i <= 0x3f; i++)         /* EA */ | 
					
						
							|  |  |  |         n += BCHG(i + 0x0840, "BCHG", 0); | 
					
						
							|  |  |  |     printf("BCHG:\t\t%d\n", n); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* ORI to CCR */ | 
					
						
							|  |  |  |     ORItoCCR(0x003c, "ORI to CCR", 20); | 
					
						
							|  |  |  |     printf("ORI to CCR:\t1\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* RTR */ | 
					
						
							|  |  |  |     RTR(0x4e77, "RTR", 20); | 
					
						
							|  |  |  |     printf("RTR:\t\t1\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* TRAP */ | 
					
						
							|  |  |  |     TRAP(0x4e40, "TRAP", 34); | 
					
						
							|  |  |  |     printf("TRAP:\t\t1\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* SBCD */ | 
					
						
							|  |  |  |     n = 0; | 
					
						
							|  |  |  |     for (i = 0; i <= 7; i++)            /* Rx */ | 
					
						
							|  |  |  |         for (j = 0; j <= 1; j++)        /* R/M */ | 
					
						
							|  |  |  |             n += SBCD((i << 9) + (j << 3) + 0x8100, "SBCD", 0); | 
					
						
							|  |  |  |     printf("SBCD:\t\t%d\n", n); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* SUBX */ | 
					
						
							|  |  |  |     n = 0; | 
					
						
							|  |  |  |     for (i = 0; i <= 7; i++)                /* Rx */ | 
					
						
							|  |  |  |         for (j = 0; j <= 2; j++)            /* size */ | 
					
						
							|  |  |  |             for (k = 0; k <= 1; k++)        /* R/M */ | 
					
						
							|  |  |  |                 n += SUBX((i << 9) + (j << 6) + (k << 3) + 0x9100, "SUBX", 0); | 
					
						
							|  |  |  |     printf("SUBX:\t\t%d\n", n); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* ABCD */ | 
					
						
							|  |  |  |     n = 0; | 
					
						
							|  |  |  |     for (i = 0; i <= 7; i++)            /* Rx */ | 
					
						
							|  |  |  |         for (j = 0; j <= 1; j++)        /* R/M */ | 
					
						
							|  |  |  |             n += ABCD((i << 9) + (j << 3) + 0xc100, "ABCD", 0); | 
					
						
							|  |  |  |     printf("ABCD:\t\t%d\n", n); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* CMPM */ | 
					
						
							|  |  |  |     n = 0; | 
					
						
							|  |  |  |     for (i = 0; i <= 7; i++)            /* Ax */ | 
					
						
							|  |  |  |         for (j = 0; j <= 2; j++)        /* size */ | 
					
						
							|  |  |  |             n += CMPM((i << 9) + (j << 6) + 0xb108, "CMPM", 0); | 
					
						
							|  |  |  |     printf("CMPM:\t\t%d\n", n); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* MOVEP */ | 
					
						
							|  |  |  |     n = 0; | 
					
						
							|  |  |  |     for (i = 0; i <= 7; i++)        /* Dx */ | 
					
						
							|  |  |  |         for (j = 0; j <= 7; j++)    /* opmode */ | 
					
						
							|  |  |  |             n += MOVEP((i << 9) + (j << 6) + 0x0008, "MOVEP", 0); | 
					
						
							|  |  |  |     printf("MOVEP:\t\t%d\n", n); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |      * The following have no profile data associated with them, as far as my | 
					
						
							|  |  |  |      * tests have shown. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* BKPT */ | 
					
						
							|  |  |  |     if (mpu == 68010) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         n = BKPT(0x4848, "BKPT", 45); | 
					
						
							|  |  |  |         printf("BKPT:\t\t%d\n", n); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     /* CHK */ | 
					
						
							|  |  |  |     n = 0; | 
					
						
							|  |  |  |     for (i = 0; i <= 7; i++)            /* register */ | 
					
						
							|  |  |  |         for (j = 0; j <= 3; j++)        /* size */ | 
					
						
							|  |  |  |             for (k = 0; k <= 0x3f; k++) /* EA */ | 
					
						
							|  |  |  |                 n += CHK((i << 9) + (j << 7) + k + 0x4000, "CHK", 10); | 
					
						
							|  |  |  |     printf("CHK:\t\t%d\n", n); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* EORI to CCR */ | 
					
						
							|  |  |  |     EORItoCCR(0x0a3c, "EORI to CCR", 20); | 
					
						
							|  |  |  |     printf("EORI to CCR:\t1\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* EORI to SR */ | 
					
						
							|  |  |  |     EORItoSR(0x0a7c, "EORI to SR", 20); | 
					
						
							|  |  |  |     printf("EORI to SR:\t1\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* ILLEGAL */ | 
					
						
							|  |  |  |     InstBegin(0x4afc, "ILLEGAL", 1); | 
					
						
							|  |  |  |     e("jmp  near exception_illegal_instruction\n"); | 
					
						
							|  |  |  |     printf("ILLEGAL:\t1\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* MOVEC */ | 
					
						
							|  |  |  |     if (mpu == 68010) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         n = MOVEC(0x4e7a, "MOVEC", 0); | 
					
						
							|  |  |  |         printf("MOVEC:\t\t%d\n", n); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |                  | 
					
						
							|  |  |  |     /* MOVE from CCR -- 68010, 68020, 68030, 68040, CPU32 */ | 
					
						
							|  |  |  |     if (mpu == 68010) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         n = 0; | 
					
						
							|  |  |  |         for (i = 0; i <= 0x3f; i++) | 
					
						
							|  |  |  |             n += MOVEfromCCR(i + 0x42c0, "MOVE from CCR", 0); | 
					
						
							|  |  |  |         printf("MOVE from CCR:\t%d\n", n); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* NBCD */ | 
					
						
							|  |  |  |     n = 0; | 
					
						
							|  |  |  |     for (i = 0; i <= 0x3f; i++)     /* EA */ | 
					
						
							|  |  |  |         n += NBCD(i + 0x4800, "NBCD", 0); | 
					
						
							|  |  |  |     printf("NBCD:\t\t%d\n", n); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* RESET */ | 
					
						
							|  |  |  |     RESET(0x4e70, "RESET", 132); | 
					
						
							|  |  |  |     printf("RESET:\t\t1\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* RTD */ | 
					
						
							|  |  |  |     if (mpu == 68010) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         RTD(0x4e74, "RTD", 16); | 
					
						
							|  |  |  |         printf("RTD:\t\t1\n"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* STOP */ | 
					
						
							|  |  |  |     STOP(0x4e72, "STOP", 4); | 
					
						
							|  |  |  |     printf("STOP:\t\t1\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* TAS */ | 
					
						
							|  |  |  |     n = 0; | 
					
						
							|  |  |  |     for (i = 0; i <= 0x3f; i++) | 
					
						
							|  |  |  |         n += TAS(i + 0x4ac0, "TAS", 0); | 
					
						
							|  |  |  |     printf("TAS:\t\t%d\n", n); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* TRAPV */ | 
					
						
							|  |  |  |     TRAPV(0x4e76, "TRAPV", 0); | 
					
						
							|  |  |  |     printf("TRAPV:\t\t1\n"); | 
					
						
							|  |  |  |                | 
					
						
							|  |  |  |     if (illegal)    /* emulate Line 1010 and Line 1111 exceptions */ | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         /* Line 1010 */ | 
					
						
							|  |  |  |         InstBegin(0xa000, "Line 1010 Emulator", 4096); | 
					
						
							|  |  |  |         e("jmp  near exception_line_1010_emulator\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /* Line 1111 */ | 
					
						
							|  |  |  |         InstBegin(0xf000, "Line 1111 Emulator", 4096); | 
					
						
							|  |  |  |         e("jmp  near exception_line_1111_emulator\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         num_handlers -= 2;  /* don't count these as instruction handlers */ | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* I_Invalid: Invalid instruction */ | 
					
						
							|  |  |  |     EmitLabel("I_Invalid"); | 
					
						
							|  |  |  |     if (illegal)    /* emulate illegal instruction exceptions */ | 
					
						
							|  |  |  |         e("jmp  near exception_illegal_instruction\n"); | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         e("sub  esi, byte 2\n");        /* back up to the bad instruction */ | 
					
						
							|  |  |  |         e("jmp  invalid_error\n");      /* invalid instruction error */ | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void EmitExceptions() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |      * exception_chk: | 
					
						
							|  |  |  |      * exception_divide_by_zero: | 
					
						
							|  |  |  |      * Assume the PC points to the instruction AFTER the instruction which | 
					
						
							|  |  |  |      * caused the trap. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     Align(4); | 
					
						
							|  |  |  |     EmitLabel("exception_chk"); | 
					
						
							|  |  |  |     e("push dword 6*4\n");  /* CHK exception vector */ | 
					
						
							|  |  |  |     e("jmp  short do_exception\n"); | 
					
						
							|  |  |  |     Align(4); | 
					
						
							|  |  |  |     EmitLabel("exception_divide_by_zero"); | 
					
						
							|  |  |  |     e("push dword 5*4\n");  /* division by zero exception vector */ | 
					
						
							|  |  |  |     e("jmp  short do_exception\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |      * exception_privilege_violation: | 
					
						
							|  |  |  |      * exception_illegal_instruction: | 
					
						
							|  |  |  |      * exception_line_1010_emulator: | 
					
						
							|  |  |  |      * exception_line_1111_emulator: | 
					
						
							|  |  |  |      * Assume the PC points to the word AFTER the instruction which caused the | 
					
						
							|  |  |  |      * trap. The value 2 will be subtracted from the PC in order to make them | 
					
						
							|  |  |  |      * point AT the instruction which caused the trap, as this is how the | 
					
						
							|  |  |  |      * exceptions work. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     Align(4); | 
					
						
							|  |  |  |     EmitLabel("exception_privilege_violation"); | 
					
						
							|  |  |  |     e("push dword 8*4\n");  /* privilege violation exception vector */ | 
					
						
							|  |  |  |     e("jmp  short do_exception_fix_pc\n"); | 
					
						
							|  |  |  |     Align(4); | 
					
						
							|  |  |  |     EmitLabel("exception_illegal_instruction"); | 
					
						
							|  |  |  |     e("push dword 4*4\n");  /* illegal instruction exception vector */ | 
					
						
							|  |  |  |     e("jmp  short do_exception_fix_pc\n"); | 
					
						
							|  |  |  |     Align(4); | 
					
						
							|  |  |  |     EmitLabel("exception_line_1010_emulator"); | 
					
						
							|  |  |  |     e("push dword 10*4\n"); /* Line 1010 emulator exception vector */ | 
					
						
							|  |  |  |     e("jmp  short do_exception_fix_pc\n"); | 
					
						
							|  |  |  |     Align(4); | 
					
						
							|  |  |  |     EmitLabel("exception_line_1111_emulator"); | 
					
						
							|  |  |  |     e("push dword 11*4\n"); /* Line 1111 emulator exception vector */ | 
					
						
							|  |  |  |     e("jmp  short do_exception_fix_pc\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     EmitLabel("do_exception_fix_pc");   /* points PC at trap instruction */ | 
					
						
							|  |  |  |     e("sub  esi, byte 2\n"); | 
					
						
							|  |  |  |     EmitLabel("do_exception"); | 
					
						
							|  |  |  |     e("mov  edx, 0x2000\n");            /* what the SR will be */ | 
					
						
							|  |  |  |     e("xor  edx, [sr]\n");              /* see if S bit is different */ | 
					
						
							|  |  |  |     e("test edx, 0x2000\n"); | 
					
						
							|  |  |  |     e("jz   .no_sp_magic\n");           /* nope, don't swap SPs */ | 
					
						
							|  |  |  |     e("mov  edx, [__sp]\n"); | 
					
						
							|  |  |  |     e("xchg [a+7*4], edx\n"); | 
					
						
							|  |  |  |     e("mov  [__sp], edx\n"); | 
					
						
							|  |  |  |     SetSupervisorAddressSpace();        /* map in supervisor address space */ | 
					
						
							|  |  |  |     EmitLabel(".no_sp_magic"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     e("mov  ebx, [a+7*4]\n");           /* SP */ | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |      * If 68010, we have to push the format word on the stack first. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     if (mpu == 68010) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         e("sub  ebx, byte 2\n");/* SP-2 */ | 
					
						
							|  |  |  |         e("mov  edx, [esp]\n"); /* vector offset | 0x00000000 */ | 
					
						
							|  |  |  |         SaveReg("run", "ebx"); | 
					
						
							|  |  |  |         WriteWord(); | 
					
						
							|  |  |  |         RestoreReg("run", "ebx"); | 
					
						
							|  |  |  |     }         | 
					
						
							|  |  |  |     e("mov  edx, esi\n"); | 
					
						
							|  |  |  |     e("sub  edx, ebp\n");               /* PC->EDX */ | 
					
						
							|  |  |  |     e("sub  ebx, byte 4\n");            /* SP-4 */ | 
					
						
							|  |  |  |     SaveReg("run", "ebx"); | 
					
						
							|  |  |  |     WriteLong(); | 
					
						
							|  |  |  |     RestoreReg("run", "ebx"); | 
					
						
							|  |  |  |     e("mov  edx, [sr]\n");              /* get SR */ | 
					
						
							|  |  |  |     e("sub  ebx, byte 2\n");            /* SP-2 */ | 
					
						
							|  |  |  |     SaveReg("run", "ebx"); | 
					
						
							|  |  |  |     WriteWord();                        /* save SR to stack */ | 
					
						
							|  |  |  |     RestoreReg("run", "ebx"); | 
					
						
							|  |  |  |     e("or   dh, 0x20\n");               /* set supervisor for exception */ | 
					
						
							|  |  |  |     e("and  edx, 0xa71f\n");            /* clear unwanted bits */ | 
					
						
							|  |  |  |     e("mov  [sr], edx\n");              /* set new SR, get old SR->EDX */ | 
					
						
							|  |  |  |     e("mov  [a+7*4], ebx\n");           /* write back SP */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     e("pop  ebx\n");                    /* get exception vector address */ | 
					
						
							|  |  |  |     if (mpu == 68010) | 
					
						
							|  |  |  |         e("add  ebx, [vbr]\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     ReadLong();                         /* get PC */ | 
					
						
							|  |  |  |     e("mov  esi, edx\n");               /* set new PC */ | 
					
						
							|  |  |  |     UpdateFetchPtr(); | 
					
						
							|  |  |  |     e("xor  edi, edi\n"); | 
					
						
							|  |  |  |     e("sub  ecx, byte 40\n");           /* timing... */ | 
					
						
							|  |  |  |     e("mov  di, [esi]\n"); | 
					
						
							|  |  |  |     e("add  esi, byte 2\n"); | 
					
						
							|  |  |  |     e("jmp  [jmptab+edi*4]\n");         /* continue execution */ | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*****************************************************************************
 | 
					
						
							|  |  |  | * Data                                                                      */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void EmitData() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     int     i; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     CacheAlign(); | 
					
						
							|  |  |  |     EmitGlobalLabel(NameOfContext()); | 
					
						
							|  |  |  |     e("context_start:\n"); | 
					
						
							|  |  |  |     e("fetch      dd 0\n");             /* pointer to fetch array */ | 
					
						
							|  |  |  |     e("pcfetch    dd 0\n");             /* PC-relative fetch */ | 
					
						
							|  |  |  |     e("read_byte  dd 0\n");             /* pointer to read_byte array */ | 
					
						
							|  |  |  |     e("read_word  dd 0\n");             /* pointer to read_word array */ | 
					
						
							|  |  |  |     e("read_long  dd 0\n");             /* pointer to read_long array */ | 
					
						
							|  |  |  |     e("write_byte dd 0\n");             /* pointer to write_byte array */ | 
					
						
							|  |  |  |     e("write_word dd 0\n");             /* pointer to write_word array */ | 
					
						
							|  |  |  |     e("write_long dd 0\n");             /* pointer to write_long array */ | 
					
						
							|  |  |  |     e("super_fetch      dd 0\n");       /* supervisor memory map... */ | 
					
						
							|  |  |  |     e("super_pcfetch    dd 0\n"); | 
					
						
							|  |  |  |     e("super_read_byte  dd 0\n"); | 
					
						
							|  |  |  |     e("super_read_word  dd 0\n"); | 
					
						
							|  |  |  |     e("super_read_long  dd 0\n"); | 
					
						
							|  |  |  |     e("super_write_byte dd 0\n"); | 
					
						
							|  |  |  |     e("super_write_word dd 0\n"); | 
					
						
							|  |  |  |     e("super_write_long dd 0\n"); | 
					
						
							|  |  |  |     e("user_fetch       dd 0\n");       /* user memory map... */ | 
					
						
							|  |  |  |     e("user_pcfetch     dd 0\n"); | 
					
						
							|  |  |  |     e("user_read_byte   dd 0\n"); | 
					
						
							|  |  |  |     e("user_read_word   dd 0\n"); | 
					
						
							|  |  |  |     e("user_read_long   dd 0\n"); | 
					
						
							|  |  |  |     e("user_write_byte  dd 0\n"); | 
					
						
							|  |  |  |     e("user_write_word  dd 0\n"); | 
					
						
							|  |  |  |     e("user_write_long  dd 0\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     e("intr       times 8 dd 0\n");     /* intr[0-6]=vectors for interrupt
 | 
					
						
							|  |  |  |                                            levels 1-7 (0=not pending.) | 
					
						
							|  |  |  |                                            intr[7]=# of interrupts pending */ | 
					
						
							|  |  |  |     e("cycles     dd 0\n");             /* cycles total to emulate */ | 
					
						
							|  |  |  |     e("remaining  dd 0\n");             /* cycles remaining */ | 
					
						
							|  |  |  |     e("d          times 8 dd 0\n");     /* D0-D7 */ | 
					
						
							|  |  |  |     e("a          times 8 dd 0\n");     /* A0-A7 */ | 
					
						
							|  |  |  |     e("__sp       dd 0\n");             /* User mode: SSP, Supervisor: USP */ | 
					
						
							|  |  |  |     e("sr         dd 0\n");             /* SR */ | 
					
						
							|  |  |  |     e("pc         dd 0\n");             /* PC */ | 
					
						
							|  |  |  |     if (mpu == 68010) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         e("fc     dd 0\n");             /* FC (DFC, SFC) */ | 
					
						
							|  |  |  |         e("vbr    dd 0\n");             /* VBR */ | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     e("status     dd 0\n");             /* bit 0:1=emulating, 0=not
 | 
					
						
							|  |  |  |                                            bit 1:1=stopped, 0=not | 
					
						
							|  |  |  |                                            bit 2:1=processing ints, 0=not */ | 
					
						
							|  |  |  |     e("InterruptAcknowledge dd 0\n");   /* interrupt acknowledge callback */ | 
					
						
							|  |  |  |     e("Reset      dd 0\n");             /* pointer to RESET handler */ | 
					
						
							| 
									
										
										
										
											2011-06-27 23:10:51 +00:00
										 |  |  | 	if (mpu == 68010) | 
					
						
							| 
									
										
										
										
											2011-04-24 01:14:00 +00:00
										 |  |  |         e("Bkpt   dd 0\n");             /* pointer to BKPT handler */ | 
					
						
							| 
									
										
										
										
											2011-06-27 23:10:51 +00:00
										 |  |  |     e("Debug      dd 0\n");			    /* pointer to debug handler */ | 
					
						
							| 
									
										
										
										
											2011-04-24 01:14:00 +00:00
										 |  |  |     e("context_end:\n"); | 
					
						
							|  |  |  |     e("x          dd 0\n");             /* X flag (maintained internally) */ | 
					
						
							|  |  |  |     for (i = 0; i < 7; i++) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         char    *reg[] = { "eax", "ebx", "ecx", "edx", "esi", "edi", "ebp" }; | 
					
						
							|  |  |  |         e("memhandler_%s    dd 0\n", reg[i]); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     for (i = 0; i < 7; i++) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         char    *reg[] = { "eax", "ebx", "ecx", "edx", "esi", "edi", "ebp" }; | 
					
						
							|  |  |  |         e("run_%s    dd 0\n", reg[i]); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     e("fetch_esi dd 0\n");  /* for UpdateFetchPtr() */ | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*****************************************************************************
 | 
					
						
							|  |  |  | * Code                                                                      */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void EmitCode() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     int     i; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Turbo68KInit() */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |      * Decompresses the jump table. See main() for the compression format | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     EmitGlobalLabel("Turbo68KInit"); | 
					
						
							|  |  |  |     e("push ecx\n"); | 
					
						
							|  |  |  |     e("push edx\n"); | 
					
						
							|  |  |  |     e("push esi\n"); | 
					
						
							|  |  |  |     e("push edi\n"); | 
					
						
							|  |  |  |     e("mov  esi, compressed_jmptab\n"); | 
					
						
							|  |  |  |     e("mov  edi, jmptab\n"); | 
					
						
							|  |  |  |     e("xor  ecx, ecx\n");               /* we only need lower half (CX) */ | 
					
						
							|  |  |  |     EmitLabel(".l"); | 
					
						
							|  |  |  |     e("mov  cx, [esi]\n");              /* get repeat information */ | 
					
						
							|  |  |  |     e("add  esi, byte 2\n");            /* point at data */ | 
					
						
							|  |  |  |     e("mov  edx, ecx\n"); | 
					
						
							|  |  |  |     e("and  edx, 0xc000\n"); | 
					
						
							|  |  |  |     e("cmp  dx, 0xc000\n");             /* #handlers * 1 each? */ | 
					
						
							|  |  |  |     e("je   .r1\n"); | 
					
						
							|  |  |  |     e("cmp  dx, 0x8000\n");             /* #handlers * 8 each? */ | 
					
						
							|  |  |  |     e("je   .r8\n"); | 
					
						
							|  |  |  |     e("mov  eax, [esi]\n"); /* get data and repeat */ | 
					
						
							|  |  |  |     e("add  esi, byte 4\n"); | 
					
						
							|  |  |  |     e("cld\n"); | 
					
						
							|  |  |  |     e("rep  stosd\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     EmitLabel(".c"); | 
					
						
							|  |  |  |     e("cmp  dword [esi], byte -1\n");   /* end of compressed data? */ | 
					
						
							|  |  |  |     e("jne  .l\n"); | 
					
						
							|  |  |  |     e("pop  edi\n"); | 
					
						
							|  |  |  |     e("pop  esi\n"); | 
					
						
							|  |  |  |     e("pop  edx\n"); | 
					
						
							|  |  |  |     e("pop  ecx\n"); | 
					
						
							|  |  |  |     e("xor  eax, eax\n"); | 
					
						
							|  |  |  |     e("ret\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     EmitLabel(".r1"); | 
					
						
							|  |  |  |     e("and  ecx, 0x3ff\n");             /* get rid of 0xc000 marker */ | 
					
						
							|  |  |  |     e("cld\n"); | 
					
						
							|  |  |  |     e("rep  movsd\n");                  /* move address to decomp'd jmptab */ | 
					
						
							|  |  |  |     e("jmp  .c\n");                     /* continue decompression */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     EmitLabel(".r8"); | 
					
						
							|  |  |  |     e("and  ecx, 0x7ff\n");             /* get rid of 0x8000 marker */ | 
					
						
							|  |  |  |     EmitLabel(".r8_l"); | 
					
						
							|  |  |  |     e("mov  edx, ecx\n");               /* save counter temporarily */ | 
					
						
							|  |  |  |     e("mov  ecx, 8\n");                 /* repeat handler 8 times */ | 
					
						
							|  |  |  |     e("mov  eax, [esi]\n");             /* get handler to repeat */ | 
					
						
							|  |  |  |     e("add  esi, byte 4\n");            /* point to next */ | 
					
						
							|  |  |  |     e("cld\n"); | 
					
						
							|  |  |  |     e("rep  stosd\n");                  /* store! */ | 
					
						
							|  |  |  |     e("mov  ecx, edx\n");               /* restore loop counter and loop */ | 
					
						
							|  |  |  |     e("dec  ecx\n"); | 
					
						
							|  |  |  |     e("jnz  .r8_l\n"); | 
					
						
							|  |  |  |     e("jmp  .c\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Turbo68KReset() */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Align(4); | 
					
						
							|  |  |  |     EmitGlobalLabel("Turbo68KReset"); | 
					
						
							|  |  |  |     e("push ebx\n"); | 
					
						
							|  |  |  |     e("push ecx\n"); | 
					
						
							|  |  |  |     e("push edx\n"); | 
					
						
							|  |  |  |     e("push esi\n"); | 
					
						
							|  |  |  |     e("push edi\n"); | 
					
						
							|  |  |  |     e("push ebp\n"); | 
					
						
							|  |  |  |     SetSupervisorAddressSpace(); | 
					
						
							|  |  |  |     EMULATING(); | 
					
						
							|  |  |  |     UNSTOP_CPU();                       /* in case we're STOPped, unstop */ | 
					
						
							|  |  |  |     if (mpu == 68010)                   /* clear 68010 VBR */ | 
					
						
							|  |  |  |         e("mov  dword [vbr], 0\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     e("xor  ecx, ecx\n");   /* no cycles executed in case error */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |      * Read the PC vector from the fetch memory map | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     if (!call_convention)   /* stack calling convention */ | 
					
						
							|  |  |  |         e("push dword 4\n"); | 
					
						
							|  |  |  |     else                    /* register calling convention */ | 
					
						
							|  |  |  |         e("mov  eax, 4\n"); | 
					
						
							|  |  |  |     e("call %sTurbo68KFetchPtr\n", id); | 
					
						
							|  |  |  |     if (!call_convention) | 
					
						
							|  |  |  |         e("add  esp, byte 4\n"); | 
					
						
							|  |  |  |     e("test eax, eax\n"); | 
					
						
							|  |  |  |     e("jz   near fetch_error\n"); | 
					
						
							|  |  |  |     e("mov  eax, [eax]\n"); | 
					
						
							|  |  |  |     e("rol  eax, byte 16\n");   /* memory is byte swapped */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     e("mov  dword "SR", 0x2700\n");     /* in supervisor mode at start */ | 
					
						
							|  |  |  |     e("mov  dword [cycles], 0\n");      /* no cycles executed */ | 
					
						
							|  |  |  |     e("mov  dword [remaining], 0\n");   /* ..ditto.. */ | 
					
						
							|  |  |  |     e("mov  esi, eax\n");   /* from Turbo68KFetchPtr() */ | 
					
						
							|  |  |  |     e("xor  eax, eax\n");   /* clear registers */ | 
					
						
							|  |  |  |     e("mov  edi, d\n"); | 
					
						
							|  |  |  |     e("mov  ecx, 16\n"); | 
					
						
							|  |  |  |     e("cld\n"); | 
					
						
							|  |  |  |     e("rep  stosd\n"); | 
					
						
							|  |  |  |     e("mov  edi, intr\n");  /* clear interrupt queue */ | 
					
						
							|  |  |  |     e("mov  ecx, 8\n"); | 
					
						
							|  |  |  |     e("rep  stosd\n"); | 
					
						
							|  |  |  |     e("xor  ecx, ecx\n");   /* no cycles executed in case error */ | 
					
						
							|  |  |  |     UpdateFetchPtr();       /* this also makes sure it can be fetched */ | 
					
						
							|  |  |  |     WRITEPCTOMEM("pc");         | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |      * Read the SP vector from the fetch memory map | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     if (!call_convention)   /* stack calling convention */ | 
					
						
							|  |  |  |         e("push dword 0\n"); | 
					
						
							|  |  |  |     else                    /* register calling convention */ | 
					
						
							|  |  |  |         e("xor  eax, eax\n"); | 
					
						
							|  |  |  |     e("call %sTurbo68KFetchPtr\n", id); | 
					
						
							|  |  |  |     if (!call_convention) | 
					
						
							|  |  |  |         e("add  esp, byte 4\n"); | 
					
						
							|  |  |  |     e("test eax, eax\n"); | 
					
						
							|  |  |  |     e("jz   near fetch_error\n"); | 
					
						
							|  |  |  |     e("mov  eax, [eax]\n"); | 
					
						
							|  |  |  |     e("rol  eax, byte 16\n");   /* memory is byte swapped */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     e("mov  "A7", eax\n");  /* supervisor */ | 
					
						
							|  |  |  |     e("mov  "SP", eax\n");  /* user */ | 
					
						
							|  |  |  |     STOP_EMULATING();       /* no longer running */ | 
					
						
							|  |  |  |     e("pop  ebp\n"); | 
					
						
							|  |  |  |     e("pop  edi\n"); | 
					
						
							|  |  |  |     e("pop  esi\n"); | 
					
						
							|  |  |  |     e("pop  edx\n"); | 
					
						
							|  |  |  |     e("pop  ecx\n"); | 
					
						
							|  |  |  |     e("pop  ebx\n"); | 
					
						
							|  |  |  |     e("xor  eax, eax\n"); | 
					
						
							|  |  |  |     if (mmx)    e("emms\n"); | 
					
						
							|  |  |  |     e("ret\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     EmitLabel("invalid_error");     /* invalid instruction */ | 
					
						
							|  |  |  |     SaveCCR(); | 
					
						
							|  |  |  |     STOP_EMULATING(); | 
					
						
							|  |  |  |     STOP_RUNNING();                 /* save PC and cycles remaining */ | 
					
						
							|  |  |  |     e("pop  ebp\n"); | 
					
						
							|  |  |  |     e("pop  edi\n"); | 
					
						
							|  |  |  |     e("pop  esi\n"); | 
					
						
							|  |  |  |     e("pop  edx\n"); | 
					
						
							|  |  |  |     e("pop  ecx\n"); | 
					
						
							|  |  |  |     e("pop  ebx\n"); | 
					
						
							|  |  |  |     e("mov  eax, %d\n", TURBO68K_ERROR_INVINST); | 
					
						
							|  |  |  |     e("ret\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |      * NOTE: Only UpdateFetchPtr() and Turbo68KReset() can call this | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     EmitLabel("fetch_error");       /* could not fetch instruction */ | 
					
						
							|  |  |  |     e("mov  [remaining], ecx\n");   /* save cycles remaining */ | 
					
						
							|  |  |  |     STOP_EMULATING(); | 
					
						
							|  |  |  |     e("mov  [pc], esi\n");          /* UpdateFetchPtr() didn't yet change this */  | 
					
						
							|  |  |  |     e("pop  ebp\n"); | 
					
						
							|  |  |  |     e("pop  edi\n"); | 
					
						
							|  |  |  |     e("pop  esi\n"); | 
					
						
							|  |  |  |     e("pop  edx\n"); | 
					
						
							|  |  |  |     e("pop  ecx\n"); | 
					
						
							|  |  |  |     e("pop  ebx\n"); | 
					
						
							|  |  |  |     e("mov  eax, %d\n", TURBO68K_ERROR_FETCH); | 
					
						
							|  |  |  |     e("ret\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Turbo68KReadPC() */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |      * Can be used anywhere, but usage while Turbo68K is emulating may | 
					
						
							|  |  |  |      * result in the value being offset a few bytes into the current | 
					
						
							|  |  |  |      * instruction, but it shouldn't | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Align(4); | 
					
						
							|  |  |  |     EmitGlobalLabel("Turbo68KReadPC"); | 
					
						
							|  |  |  |     e("mov  eax, [pc]\n"); | 
					
						
							|  |  |  |     e("ret\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Turbo68KSetFetch() */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Align(4); | 
					
						
							|  |  |  |     EmitGlobalLabel("Turbo68KSetFetch"); | 
					
						
							|  |  |  |     e("push eax\n"); | 
					
						
							|  |  |  |     e("push edx\n"); | 
					
						
							|  |  |  |     GetArg("eax", 0, 12); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     e("sub  eax, "SIZEOF_FETCHREGION"\n"); | 
					
						
							|  |  |  |     if (multiaddr) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         GetArg("edx", 1, 16); | 
					
						
							|  |  |  |         e("cmp  edx, byte %d\n", TURBO68K_SUPERVISOR); | 
					
						
							|  |  |  |         e("jne  short .user\n"); | 
					
						
							|  |  |  |         e("mov  [super_fetch], eax\n"); | 
					
						
							|  |  |  |         e("test byte [sr+1], 0x20\n");  /* if supervisor, update fetch */ | 
					
						
							|  |  |  |         e("jz   near .not_super\n"); | 
					
						
							|  |  |  |         e("mov  [fetch], eax\n"); | 
					
						
							|  |  |  |         EmitLabel(".not_super"); | 
					
						
							|  |  |  |         e("pop  edx\n"); | 
					
						
							|  |  |  |         e("pop  eax\n"); | 
					
						
							|  |  |  |         e("ret\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         EmitLabel(".user"); | 
					
						
							|  |  |  |         e("mov  [user_fetch], eax\n"); | 
					
						
							|  |  |  |         e("test byte [sr+1], 0x20\n");  /* if user, update fetch */ | 
					
						
							|  |  |  |         e("jnz  near .not_user\n"); | 
					
						
							|  |  |  |         e("mov  [fetch], eax\n"); | 
					
						
							|  |  |  |         EmitLabel(".not_user"); | 
					
						
							|  |  |  |         e("pop  edx\n"); | 
					
						
							|  |  |  |         e("pop  eax\n"); | 
					
						
							|  |  |  |         e("ret\n"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         e("mov  [fetch], eax\n"); | 
					
						
							|  |  |  |         e("pop  edx\n"); | 
					
						
							|  |  |  |         e("pop  eax\n"); | 
					
						
							|  |  |  |         e("ret\n"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Turbo68KGetFetch() */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Align(4); | 
					
						
							|  |  |  |     EmitGlobalLabel("Turbo68KGetFetch"); | 
					
						
							|  |  |  |     e("push edx\n"); | 
					
						
							|  |  |  |     if (multiaddr) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         GetArg("edx", 0, 8); | 
					
						
							|  |  |  |         e("cmp  edx, byte %d\n", TURBO68K_SUPERVISOR); | 
					
						
							|  |  |  |         e("jne  short .user\n"); | 
					
						
							|  |  |  |         e("mov  eax, [super_fetch]\n"); | 
					
						
							|  |  |  |         e("jmp  near .finish\n"); | 
					
						
							|  |  |  |         EmitLabel(".user"); | 
					
						
							|  |  |  |         e("mov  eax, [user_fetch]\n"); | 
					
						
							|  |  |  |         EmitLabel(".finish"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |         e("mov  eax, [fetch]\n"); | 
					
						
							|  |  |  |     e("pop  edx\n"); | 
					
						
							|  |  |  |     e("add  eax, "SIZEOF_FETCHREGION"\n"); | 
					
						
							|  |  |  |     e("ret\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Turbo68KSetPCFetch() */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (pcfetch) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         Align(4); | 
					
						
							|  |  |  |         EmitGlobalLabel("Turbo68KSetPCFetch"); | 
					
						
							|  |  |  |         e("push eax\n"); | 
					
						
							|  |  |  |         e("push edx\n"); | 
					
						
							|  |  |  |         GetArg("eax", 0, 12); | 
					
						
							|  |  |  |         e("sub  eax, "SIZEOF_FETCHREGION"\n"); | 
					
						
							|  |  |  |         if (multiaddr) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             GetArg("edx", 1, 16); | 
					
						
							|  |  |  |             e("cmp  edx, byte %d\n", TURBO68K_SUPERVISOR); | 
					
						
							|  |  |  |             e("jne  short .user\n"); | 
					
						
							|  |  |  |             e("mov  [super_pcfetch], eax\n"); | 
					
						
							|  |  |  |             e("test byte [sr+1], 0x20\n");  /* if supervisor, update fetch */ | 
					
						
							|  |  |  |             e("jz   near .not_super\n"); | 
					
						
							|  |  |  |             e("mov  [pcfetch], eax\n"); | 
					
						
							|  |  |  |             EmitLabel(".not_super"); | 
					
						
							|  |  |  |             e("pop  edx\n"); | 
					
						
							|  |  |  |             e("pop  eax\n"); | 
					
						
							|  |  |  |             e("ret\n"); | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |             EmitLabel(".user"); | 
					
						
							|  |  |  |             e("mov  [user_pcfetch], eax\n"); | 
					
						
							|  |  |  |             e("test byte [sr+1], 0x20\n");  /* if user, update fetch */ | 
					
						
							|  |  |  |             e("jnz  near .not_user\n"); | 
					
						
							|  |  |  |             e("mov  [pcfetch], eax\n"); | 
					
						
							|  |  |  |             EmitLabel(".not_user"); | 
					
						
							|  |  |  |             e("pop  edx\n"); | 
					
						
							|  |  |  |             e("pop  eax\n"); | 
					
						
							|  |  |  |             e("ret\n"); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             e("mov  [pcfetch], eax\n"); | 
					
						
							|  |  |  |             e("pop  edx\n"); | 
					
						
							|  |  |  |             e("pop  eax\n"); | 
					
						
							|  |  |  |             e("ret\n"); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /* Turbo68KGetPCFetch() */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         Align(4); | 
					
						
							|  |  |  |         EmitGlobalLabel("Turbo68KGetPCFetch"); | 
					
						
							|  |  |  |         e("push edx\n"); | 
					
						
							|  |  |  |         if (multiaddr) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             GetArg("edx", 0, 8); | 
					
						
							|  |  |  |             e("cmp  edx, byte %d\n", TURBO68K_SUPERVISOR); | 
					
						
							|  |  |  |             e("jne  short .user\n"); | 
					
						
							|  |  |  |             e("mov  eax, [super_pcfetch]\n"); | 
					
						
							|  |  |  |             e("jmp  near .finish\n"); | 
					
						
							|  |  |  |             EmitLabel(".user"); | 
					
						
							|  |  |  |             e("mov  eax, [user_pcfetch]\n"); | 
					
						
							|  |  |  |             EmitLabel(".finish"); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |             e("mov  eax, [pcfetch]\n"); | 
					
						
							|  |  |  |         e("pop  edx\n"); | 
					
						
							|  |  |  |         e("add  eax, "SIZEOF_FETCHREGION"\n"); | 
					
						
							|  |  |  |         e("ret\n"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |      * If the memory map mode is NOT 0 (defmap), we do not add or subtract | 
					
						
							|  |  |  |      * from the pointers because they aren't arrays, but function pointers. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Turbo68KSetReadByte() */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Align(4); | 
					
						
							|  |  |  |     EmitGlobalLabel("Turbo68KSetReadByte"); | 
					
						
							|  |  |  |     e("push eax\n"); | 
					
						
							|  |  |  |     e("push ebx\n"); | 
					
						
							|  |  |  |     GetArg("eax", 0, 12); | 
					
						
							|  |  |  |     if (memmap_type == 0) | 
					
						
							|  |  |  |         e("sub  eax, "SIZEOF_DATAREGION"\n"); | 
					
						
							|  |  |  |     if (multiaddr) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         GetArg("edx", 1, 16); | 
					
						
							|  |  |  |         e("cmp  edx, byte %d\n", TURBO68K_SUPERVISOR); | 
					
						
							|  |  |  |         e("jne  short .user\n"); | 
					
						
							|  |  |  |         e("mov  [super_read_byte], eax\n"); | 
					
						
							|  |  |  |         e("test byte [sr+1], 0x20\n");  /* if supervisor, update fetch */ | 
					
						
							|  |  |  |         e("jz   near .not_super\n"); | 
					
						
							|  |  |  |         e("mov  [read_byte], eax\n"); | 
					
						
							|  |  |  |         EmitLabel(".not_super"); | 
					
						
							|  |  |  |         e("pop  edx\n"); | 
					
						
							|  |  |  |         e("pop  eax\n"); | 
					
						
							|  |  |  |         e("ret\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         EmitLabel(".user"); | 
					
						
							|  |  |  |         e("mov  [user_read_byte], eax\n"); | 
					
						
							|  |  |  |         e("test byte [sr+1], 0x20\n");  /* if user, update fetch */ | 
					
						
							|  |  |  |         e("jnz  near .not_user\n"); | 
					
						
							|  |  |  |         e("mov  [read_byte], eax\n"); | 
					
						
							|  |  |  |         EmitLabel(".not_user"); | 
					
						
							|  |  |  |         e("pop  edx\n"); | 
					
						
							|  |  |  |         e("pop  eax\n"); | 
					
						
							|  |  |  |         e("ret\n"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         e("mov  [read_byte], eax\n"); | 
					
						
							|  |  |  |         e("pop  edx\n"); | 
					
						
							|  |  |  |         e("pop  eax\n"); | 
					
						
							|  |  |  |         e("ret\n"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Turbo68KGetReadByte() */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Align(4); | 
					
						
							|  |  |  |     EmitGlobalLabel("Turbo68KGetReadByte"); | 
					
						
							|  |  |  |     e("push edx\n"); | 
					
						
							|  |  |  |     if (multiaddr) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         GetArg("edx", 0, 8); | 
					
						
							|  |  |  |         e("cmp  edx, byte %d\n", TURBO68K_SUPERVISOR); | 
					
						
							|  |  |  |         e("jne  short .user\n"); | 
					
						
							|  |  |  |         e("mov  eax, [super_read_byte]\n"); | 
					
						
							|  |  |  |         e("jmp  near .finish\n"); | 
					
						
							|  |  |  |         EmitLabel(".user"); | 
					
						
							|  |  |  |         e("mov  eax, [user_read_byte]\n"); | 
					
						
							|  |  |  |         EmitLabel(".finish"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |         e("mov  eax, [read_byte]\n"); | 
					
						
							|  |  |  |     if (memmap_type == 0) | 
					
						
							|  |  |  |         e("add  eax, "SIZEOF_DATAREGION"\n"); | 
					
						
							|  |  |  |     e("pop  edx\n"); | 
					
						
							|  |  |  |     e("ret\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Turbo68KSetReadWord() */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Align(4); | 
					
						
							|  |  |  |     EmitGlobalLabel("Turbo68KSetReadWord"); | 
					
						
							|  |  |  |     e("push eax\n"); | 
					
						
							|  |  |  |     e("push ebx\n"); | 
					
						
							|  |  |  |     GetArg("eax", 0, 12); | 
					
						
							|  |  |  |     if (memmap_type == 0) | 
					
						
							|  |  |  |         e("sub  eax, "SIZEOF_DATAREGION"\n"); | 
					
						
							|  |  |  |     if (multiaddr) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         GetArg("edx", 1, 16); | 
					
						
							|  |  |  |         e("cmp  edx, byte %d\n", TURBO68K_SUPERVISOR); | 
					
						
							|  |  |  |         e("jne  short .user\n"); | 
					
						
							|  |  |  |         e("mov  [super_read_word], eax\n"); | 
					
						
							|  |  |  |         e("test byte [sr+1], 0x20\n");  /* if supervisor, update fetch */ | 
					
						
							|  |  |  |         e("jz   near .not_super\n"); | 
					
						
							|  |  |  |         e("mov  [read_word], eax\n"); | 
					
						
							|  |  |  |         EmitLabel(".not_super"); | 
					
						
							|  |  |  |         e("pop  edx\n"); | 
					
						
							|  |  |  |         e("pop  eax\n"); | 
					
						
							|  |  |  |         e("ret\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         EmitLabel(".user"); | 
					
						
							|  |  |  |         e("mov  [user_read_word], eax\n"); | 
					
						
							|  |  |  |         e("test byte [sr+1], 0x20\n");  /* if user, update fetch */ | 
					
						
							|  |  |  |         e("jnz  near .not_user\n"); | 
					
						
							|  |  |  |         e("mov  [read_word], eax\n"); | 
					
						
							|  |  |  |         EmitLabel(".not_user"); | 
					
						
							|  |  |  |         e("pop  edx\n"); | 
					
						
							|  |  |  |         e("pop  eax\n"); | 
					
						
							|  |  |  |         e("ret\n"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         e("mov  [read_word], eax\n"); | 
					
						
							|  |  |  |         e("pop  edx\n"); | 
					
						
							|  |  |  |         e("pop  eax\n"); | 
					
						
							|  |  |  |         e("ret\n"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Turbo68KGetReadWord() */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Align(4); | 
					
						
							|  |  |  |     EmitGlobalLabel("Turbo68KGetReadWord"); | 
					
						
							|  |  |  |     e("push edx\n"); | 
					
						
							|  |  |  |     if (multiaddr) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         GetArg("edx", 0, 8); | 
					
						
							|  |  |  |         e("cmp  edx, byte %d\n", TURBO68K_SUPERVISOR); | 
					
						
							|  |  |  |         e("jne  short .user\n"); | 
					
						
							|  |  |  |         e("mov  eax, [super_read_word]\n"); | 
					
						
							|  |  |  |         e("jmp  near .finish\n"); | 
					
						
							|  |  |  |         EmitLabel(".user"); | 
					
						
							|  |  |  |         e("mov  eax, [user_read_word]\n"); | 
					
						
							|  |  |  |         EmitLabel(".finish"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |         e("mov  eax, [read_word]\n"); | 
					
						
							|  |  |  |     if (memmap_type == 0) | 
					
						
							|  |  |  |         e("add  eax, "SIZEOF_DATAREGION"\n"); | 
					
						
							|  |  |  |     e("pop  edx\n"); | 
					
						
							|  |  |  |     e("ret\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Turbo68KSetReadLong() */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Align(4); | 
					
						
							|  |  |  |     EmitGlobalLabel("Turbo68KSetReadLong"); | 
					
						
							|  |  |  |     e("push eax\n"); | 
					
						
							|  |  |  |     e("push ebx\n"); | 
					
						
							|  |  |  |     GetArg("eax", 0, 12); | 
					
						
							|  |  |  |     if (memmap_type == 0) | 
					
						
							|  |  |  |         e("sub  eax, "SIZEOF_DATAREGION"\n"); | 
					
						
							|  |  |  |     if (multiaddr) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         GetArg("edx", 1, 16); | 
					
						
							|  |  |  |         e("cmp  edx, byte %d\n", TURBO68K_SUPERVISOR); | 
					
						
							|  |  |  |         e("jne  short .user\n"); | 
					
						
							|  |  |  |         e("mov  [super_read_long], eax\n"); | 
					
						
							|  |  |  |         e("test byte [sr+1], 0x20\n");  /* if supervisor, update fetch */ | 
					
						
							|  |  |  |         e("jz   near .not_super\n"); | 
					
						
							|  |  |  |         e("mov  [read_long], eax\n"); | 
					
						
							|  |  |  |         EmitLabel(".not_super"); | 
					
						
							|  |  |  |         e("pop  edx\n"); | 
					
						
							|  |  |  |         e("pop  eax\n"); | 
					
						
							|  |  |  |         e("ret\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         EmitLabel(".user"); | 
					
						
							|  |  |  |         e("mov  [user_read_long], eax\n"); | 
					
						
							|  |  |  |         e("test byte [sr+1], 0x20\n");  /* if user, update fetch */ | 
					
						
							|  |  |  |         e("jnz  near .not_user\n"); | 
					
						
							|  |  |  |         e("mov  [read_long], eax\n"); | 
					
						
							|  |  |  |         EmitLabel(".not_user"); | 
					
						
							|  |  |  |         e("pop  edx\n"); | 
					
						
							|  |  |  |         e("pop  eax\n"); | 
					
						
							|  |  |  |         e("ret\n"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         e("mov  [read_long], eax\n"); | 
					
						
							|  |  |  |         e("pop  edx\n"); | 
					
						
							|  |  |  |         e("pop  eax\n"); | 
					
						
							|  |  |  |         e("ret\n"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Turbo68KGetReadLong() */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Align(4); | 
					
						
							|  |  |  |     EmitGlobalLabel("Turbo68KGetReadLong"); | 
					
						
							|  |  |  |     e("push edx\n"); | 
					
						
							|  |  |  |     if (multiaddr) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         GetArg("edx", 0, 8); | 
					
						
							|  |  |  |         e("cmp  edx, byte %d\n", TURBO68K_SUPERVISOR); | 
					
						
							|  |  |  |         e("jne  short .user\n"); | 
					
						
							|  |  |  |         e("mov  eax, [super_read_long]\n"); | 
					
						
							|  |  |  |         e("jmp  near .finish\n"); | 
					
						
							|  |  |  |         EmitLabel(".user"); | 
					
						
							|  |  |  |         e("mov  eax, [user_read_long]\n"); | 
					
						
							|  |  |  |         EmitLabel(".finish"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |         e("mov  eax, [read_long]\n"); | 
					
						
							|  |  |  |     if (memmap_type == 0) | 
					
						
							|  |  |  |         e("add  eax, "SIZEOF_DATAREGION"\n"); | 
					
						
							|  |  |  |     e("pop  edx\n"); | 
					
						
							|  |  |  |     e("ret\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Turbo68KSetWriteByte() */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Align(4); | 
					
						
							|  |  |  |     EmitGlobalLabel("Turbo68KSetWriteByte"); | 
					
						
							|  |  |  |     e("push eax\n"); | 
					
						
							|  |  |  |     e("push edx\n"); | 
					
						
							|  |  |  |     GetArg("eax", 0, 12); | 
					
						
							|  |  |  |     if (memmap_type == 0) | 
					
						
							|  |  |  |         e("sub  eax, "SIZEOF_DATAREGION"\n"); | 
					
						
							|  |  |  |     if (multiaddr) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         GetArg("edx", 1, 16); | 
					
						
							|  |  |  |         e("cmp  edx, byte %d\n", TURBO68K_SUPERVISOR); | 
					
						
							|  |  |  |         e("jne  short .user\n"); | 
					
						
							|  |  |  |         e("mov  [super_write_byte], eax\n"); | 
					
						
							|  |  |  |         e("test byte [sr+1], 0x20\n");  /* if supervisor, update fetch */ | 
					
						
							|  |  |  |         e("jz   near .not_super\n"); | 
					
						
							|  |  |  |         e("mov  [write_byte], eax\n"); | 
					
						
							|  |  |  |         EmitLabel(".not_super"); | 
					
						
							|  |  |  |         e("pop  edx\n"); | 
					
						
							|  |  |  |         e("pop  eax\n"); | 
					
						
							|  |  |  |         e("ret\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         EmitLabel(".user"); | 
					
						
							|  |  |  |         e("mov  [user_write_byte], eax\n"); | 
					
						
							|  |  |  |         e("test byte [sr+1], 0x20\n");  /* if user, update fetch */ | 
					
						
							|  |  |  |         e("jnz  near .not_user\n"); | 
					
						
							|  |  |  |         e("mov  [write_byte], eax\n"); | 
					
						
							|  |  |  |         EmitLabel(".not_user"); | 
					
						
							|  |  |  |         e("pop  edx\n"); | 
					
						
							|  |  |  |         e("pop  eax\n"); | 
					
						
							|  |  |  |         e("ret\n"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         e("mov  [write_byte], eax\n"); | 
					
						
							|  |  |  |         e("pop  edx\n"); | 
					
						
							|  |  |  |         e("pop  eax\n"); | 
					
						
							|  |  |  |         e("ret\n"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Turbo68KGetWriteByte() */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Align(4); | 
					
						
							|  |  |  |     EmitGlobalLabel("Turbo68KGetWriteByte"); | 
					
						
							|  |  |  |     e("push edx\n"); | 
					
						
							|  |  |  |     if (multiaddr) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         GetArg("edx", 0, 8); | 
					
						
							|  |  |  |         e("cmp  edx, byte %d\n", TURBO68K_SUPERVISOR); | 
					
						
							|  |  |  |         e("jne  short .user\n"); | 
					
						
							|  |  |  |         e("mov  eax, [super_write_byte]\n"); | 
					
						
							|  |  |  |         e("jmp  near .finish\n"); | 
					
						
							|  |  |  |         EmitLabel(".user"); | 
					
						
							|  |  |  |         e("mov  eax, [user_write_byte]\n"); | 
					
						
							|  |  |  |         EmitLabel(".finish"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |         e("mov  eax, [write_byte]\n"); | 
					
						
							|  |  |  |     if (memmap_type == 0) | 
					
						
							|  |  |  |         e("add  eax, "SIZEOF_DATAREGION"\n"); | 
					
						
							|  |  |  |     e("pop  edx\n"); | 
					
						
							|  |  |  |     e("ret\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Turbo68KSetWriteWord() */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Align(4); | 
					
						
							|  |  |  |     EmitGlobalLabel("Turbo68KSetWriteWord"); | 
					
						
							|  |  |  |     e("push eax\n"); | 
					
						
							|  |  |  |     e("push edx\n"); | 
					
						
							|  |  |  |     GetArg("eax", 0, 12); | 
					
						
							|  |  |  |     if (memmap_type == 0) | 
					
						
							|  |  |  |         e("sub  eax, "SIZEOF_DATAREGION"\n"); | 
					
						
							|  |  |  |     if (multiaddr) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         GetArg("edx", 1, 16); | 
					
						
							|  |  |  |         e("cmp  edx, byte %d\n", TURBO68K_SUPERVISOR); | 
					
						
							|  |  |  |         e("jne  short .user\n"); | 
					
						
							|  |  |  |         e("mov  [super_write_word], eax\n"); | 
					
						
							|  |  |  |         e("test byte [sr+1], 0x20\n");  /* if supervisor, update fetch */ | 
					
						
							|  |  |  |         e("jz   near .not_super\n"); | 
					
						
							|  |  |  |         e("mov  [write_word], eax\n"); | 
					
						
							|  |  |  |         EmitLabel(".not_super"); | 
					
						
							|  |  |  |         e("pop  edx\n"); | 
					
						
							|  |  |  |         e("pop  eax\n"); | 
					
						
							|  |  |  |         e("ret\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         EmitLabel(".user"); | 
					
						
							|  |  |  |         e("mov  [user_write_word], eax\n"); | 
					
						
							|  |  |  |         e("test byte [sr+1], 0x20\n");  /* if user, update fetch */ | 
					
						
							|  |  |  |         e("jnz  near .not_user\n"); | 
					
						
							|  |  |  |         e("mov  [write_word], eax\n"); | 
					
						
							|  |  |  |         EmitLabel(".not_user"); | 
					
						
							|  |  |  |         e("pop  edx\n"); | 
					
						
							|  |  |  |         e("pop  eax\n"); | 
					
						
							|  |  |  |         e("ret\n"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         e("mov  [write_word], eax\n"); | 
					
						
							|  |  |  |         e("pop  edx\n"); | 
					
						
							|  |  |  |         e("pop  eax\n"); | 
					
						
							|  |  |  |         e("ret\n"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Turbo68KGetWriteWord() */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Align(4); | 
					
						
							|  |  |  |     EmitGlobalLabel("Turbo68KGetWriteWord"); | 
					
						
							|  |  |  |     e("push edx\n"); | 
					
						
							|  |  |  |     if (multiaddr) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         GetArg("edx", 0, 8); | 
					
						
							|  |  |  |         e("cmp  edx, byte %d\n", TURBO68K_SUPERVISOR); | 
					
						
							|  |  |  |         e("jne  short .user\n"); | 
					
						
							|  |  |  |         e("mov  eax, [super_write_word]\n"); | 
					
						
							|  |  |  |         e("jmp  near .finish\n"); | 
					
						
							|  |  |  |         EmitLabel(".user"); | 
					
						
							|  |  |  |         e("mov  eax, [user_write_word]\n"); | 
					
						
							|  |  |  |         EmitLabel(".finish"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |         e("mov  eax, [write_word]\n"); | 
					
						
							|  |  |  |     if (memmap_type == 0) | 
					
						
							|  |  |  |         e("add  eax, "SIZEOF_DATAREGION"\n"); | 
					
						
							|  |  |  |     e("pop  edx\n"); | 
					
						
							|  |  |  |     e("ret\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Turbo68KSetWriteLong() */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Align(4); | 
					
						
							|  |  |  |     EmitGlobalLabel("Turbo68KSetWriteLong"); | 
					
						
							|  |  |  |     e("push eax\n"); | 
					
						
							|  |  |  |     e("push edx\n"); | 
					
						
							|  |  |  |     GetArg("eax", 0, 12); | 
					
						
							|  |  |  |     if (memmap_type == 0) | 
					
						
							|  |  |  |         e("sub  eax, "SIZEOF_DATAREGION"\n"); | 
					
						
							|  |  |  |     if (multiaddr) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         GetArg("edx", 1, 16); | 
					
						
							|  |  |  |         e("cmp  edx, byte %d\n", TURBO68K_SUPERVISOR); | 
					
						
							|  |  |  |         e("jne  short .user\n"); | 
					
						
							|  |  |  |         e("mov  [super_write_long], eax\n"); | 
					
						
							|  |  |  |         e("test byte [sr+1], 0x20\n");  /* if supervisor, update fetch */ | 
					
						
							|  |  |  |         e("jz   near .not_super\n"); | 
					
						
							|  |  |  |         e("mov  [write_long], eax\n"); | 
					
						
							|  |  |  |         EmitLabel(".not_super"); | 
					
						
							|  |  |  |         e("pop  edx\n"); | 
					
						
							|  |  |  |         e("pop  eax\n"); | 
					
						
							|  |  |  |         e("ret\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         EmitLabel(".user"); | 
					
						
							|  |  |  |         e("mov  [user_write_long], eax\n"); | 
					
						
							|  |  |  |         e("test byte [sr+1], 0x20\n");  /* if user, update fetch */ | 
					
						
							|  |  |  |         e("jnz  near .not_user\n"); | 
					
						
							|  |  |  |         e("mov  [write_long], eax\n"); | 
					
						
							|  |  |  |         EmitLabel(".not_user"); | 
					
						
							|  |  |  |         e("pop  edx\n"); | 
					
						
							|  |  |  |         e("pop  eax\n"); | 
					
						
							|  |  |  |         e("ret\n"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         e("mov  [write_long], eax\n"); | 
					
						
							|  |  |  |         e("pop  edx\n"); | 
					
						
							|  |  |  |         e("pop  eax\n"); | 
					
						
							|  |  |  |         e("ret\n"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Turbo68KGetWriteLong() */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Align(4); | 
					
						
							|  |  |  |     EmitGlobalLabel("Turbo68KGetWriteLong"); | 
					
						
							|  |  |  |     e("push edx\n"); | 
					
						
							|  |  |  |     if (multiaddr) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         GetArg("edx", 0, 8); | 
					
						
							|  |  |  |         e("cmp  edx, byte %d\n", TURBO68K_SUPERVISOR); | 
					
						
							|  |  |  |         e("jne  short .user\n"); | 
					
						
							|  |  |  |         e("mov  eax, [super_write_long]\n"); | 
					
						
							|  |  |  |         e("jmp  near .finish\n"); | 
					
						
							|  |  |  |         EmitLabel(".user"); | 
					
						
							|  |  |  |         e("mov  eax, [user_write_long]\n"); | 
					
						
							|  |  |  |         EmitLabel(".finish"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |         e("mov  eax, [write_long]\n"); | 
					
						
							|  |  |  |     if (memmap_type == 0) | 
					
						
							|  |  |  |         e("add  eax, "SIZEOF_DATAREGION"\n"); | 
					
						
							|  |  |  |     e("pop  edx\n"); | 
					
						
							|  |  |  |     e("ret\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Turbo68KFetchPtr() */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Align(4); | 
					
						
							|  |  |  |     EmitGlobalLabel("Turbo68KFetchPtr"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     e("push ebx\n"); | 
					
						
							|  |  |  |     e("push edx\n"); | 
					
						
							|  |  |  |     e("push esi\n"); | 
					
						
							|  |  |  |     e("push ebp\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     GetArg("esi", 0, 20);                   /* address */ | 
					
						
							|  |  |  |     if (multiaddr) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         e("test byte [sr+1], 0x20\n");      /* set proper address space */ | 
					
						
							|  |  |  |         e("jz   short .user\n"); | 
					
						
							|  |  |  |         SetSupervisorAddressSpace(); | 
					
						
							|  |  |  |         e("jmp  short .continue\n"); | 
					
						
							|  |  |  |         EmitLabel(".user"); | 
					
						
							|  |  |  |         SetUserAddressSpace(); | 
					
						
							|  |  |  |         EmitLabel(".continue"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     AddrClip("esi"); | 
					
						
							|  |  |  |     e("mov     edx, [fetch]\n"); | 
					
						
							|  |  |  |     e(".find_fetch_loop:\n"); | 
					
						
							|  |  |  |     e("add     edx, byte "SIZEOF_FETCHREGION"\n"); | 
					
						
							|  |  |  |     e("cmp     dword [edx], byte -1\n");    /* limit=-1? end. */ | 
					
						
							|  |  |  |     e("je      short .not_found\n"); | 
					
						
							|  |  |  |     e("cmp     esi, [edx]\n");              /* offset 0: base. above it? */ | 
					
						
							|  |  |  |     e("jb      short .find_fetch_loop\n");  /* nope, not this region */ | 
					
						
							|  |  |  |     e("cmp     esi, [edx+"OFFSET_FETCH_LIMIT"]\n"); /* limit. below it? */ | 
					
						
							|  |  |  |     e("ja      short .find_fetch_loop\n");  /* nope, not this region */ | 
					
						
							|  |  |  |     e("mov     ebp, [edx+"OFFSET_FETCH_PTR"]\n");   /* ebp=base ptr */ | 
					
						
							|  |  |  |     e("add     esi, ebp\n");                        /* +pc=pc ptr.. */ | 
					
						
							|  |  |  |     e("mov     eax, esi\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     e("pop  ebp\n"); | 
					
						
							|  |  |  |     e("pop  esi\n"); | 
					
						
							|  |  |  |     e("pop  edx\n"); | 
					
						
							|  |  |  |     e("pop  ebx\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     e("ret\n"); | 
					
						
							|  |  |  |     EmitLabel(".not_found"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     e("pop  ebp\n"); | 
					
						
							|  |  |  |     e("pop  esi\n"); | 
					
						
							|  |  |  |     e("pop  edx\n"); | 
					
						
							|  |  |  |     e("pop  ebx\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     e("xor  eax, eax\n"); | 
					
						
							|  |  |  |     e("ret\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Turbo68KReadByte() */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Align(4); | 
					
						
							|  |  |  |     EmitGlobalLabel("Turbo68KReadByte"); | 
					
						
							|  |  |  |     e("push ebx\n"); | 
					
						
							|  |  |  |     e("push ecx\n"); | 
					
						
							|  |  |  |     e("push edx\n"); | 
					
						
							|  |  |  |     e("push esi\n"); | 
					
						
							|  |  |  |     e("push edi\n"); | 
					
						
							|  |  |  |     e("push ebp\n"); | 
					
						
							|  |  |  |     e("xor  ebp, ebp\n");                   /* so PC doesn't get trashed */ | 
					
						
							|  |  |  |     e("mov  esi, [pc]\n"); | 
					
						
							|  |  |  |     if (multiaddr) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         e("test byte [sr+1], 0x20\n");      /* set proper address space */ | 
					
						
							|  |  |  |         e("jz   short .user\n"); | 
					
						
							|  |  |  |         SetSupervisorAddressSpace(); | 
					
						
							|  |  |  |         e("jmp  short .continue\n"); | 
					
						
							|  |  |  |         EmitLabel(".user"); | 
					
						
							|  |  |  |         SetUserAddressSpace(); | 
					
						
							|  |  |  |         EmitLabel(".continue"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     GetArg("ebx", 0, 28); | 
					
						
							|  |  |  |     ReadByte(); | 
					
						
							|  |  |  |     e("mov  eax, edx\n"); | 
					
						
							|  |  |  |     if (mmx)    e("emms\n"); | 
					
						
							|  |  |  |     e("pop  ebp\n"); | 
					
						
							|  |  |  |     e("pop  edi\n"); | 
					
						
							|  |  |  |     e("pop  esi\n"); | 
					
						
							|  |  |  |     e("pop  edx\n"); | 
					
						
							|  |  |  |     e("pop  ecx\n"); | 
					
						
							|  |  |  |     e("pop  ebx\n"); | 
					
						
							|  |  |  |     e("ret\n"); | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     /* Turbo68KReadWord() */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Align(4); | 
					
						
							|  |  |  |     EmitGlobalLabel("Turbo68KReadWord"); | 
					
						
							|  |  |  |     e("push ebx\n"); | 
					
						
							|  |  |  |     e("push ecx\n"); | 
					
						
							|  |  |  |     e("push edx\n"); | 
					
						
							|  |  |  |     e("push esi\n"); | 
					
						
							|  |  |  |     e("push edi\n"); | 
					
						
							|  |  |  |     e("push ebp\n"); | 
					
						
							|  |  |  |     e("xor  ebp, ebp\n");                   /* so PC doesn't get trashed */ | 
					
						
							|  |  |  |     e("mov  esi, [pc]\n"); | 
					
						
							|  |  |  |     if (multiaddr) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         e("test byte [sr+1], 0x20\n");      /* set proper address space */ | 
					
						
							|  |  |  |         e("jz   short .user\n"); | 
					
						
							|  |  |  |         SetSupervisorAddressSpace(); | 
					
						
							|  |  |  |         e("jmp  short .continue\n"); | 
					
						
							|  |  |  |         EmitLabel(".user"); | 
					
						
							|  |  |  |         SetUserAddressSpace(); | 
					
						
							|  |  |  |         EmitLabel(".continue"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     GetArg("ebx", 0, 28); | 
					
						
							|  |  |  |     ReadWord(); | 
					
						
							|  |  |  |     e("mov  eax, edx\n"); | 
					
						
							|  |  |  |     if (mmx)    e("emms\n"); | 
					
						
							|  |  |  |     e("pop  ebp\n"); | 
					
						
							|  |  |  |     e("pop  edi\n"); | 
					
						
							|  |  |  |     e("pop  esi\n"); | 
					
						
							|  |  |  |     e("pop  edx\n"); | 
					
						
							|  |  |  |     e("pop  ecx\n"); | 
					
						
							|  |  |  |     e("pop  ebx\n"); | 
					
						
							|  |  |  |     e("ret\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Turbo68KReadLong() */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Align(4); | 
					
						
							|  |  |  |     EmitGlobalLabel("Turbo68KReadLong"); | 
					
						
							|  |  |  |     e("push ebx\n"); | 
					
						
							|  |  |  |     e("push ecx\n"); | 
					
						
							|  |  |  |     e("push edx\n"); | 
					
						
							|  |  |  |     e("push esi\n"); | 
					
						
							|  |  |  |     e("push edi\n"); | 
					
						
							|  |  |  |     e("push ebp\n"); | 
					
						
							|  |  |  |     e("xor  ebp, ebp\n");                   /* so PC doesn't get trashed */ | 
					
						
							|  |  |  |     e("mov  esi, [pc]\n"); | 
					
						
							|  |  |  |     if (multiaddr) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         e("test byte [sr+1], 0x20\n");      /* set proper address space */ | 
					
						
							|  |  |  |         e("jz   short .user\n"); | 
					
						
							|  |  |  |         SetSupervisorAddressSpace(); | 
					
						
							|  |  |  |         e("jmp  short .continue\n"); | 
					
						
							|  |  |  |         EmitLabel(".user"); | 
					
						
							|  |  |  |         SetUserAddressSpace(); | 
					
						
							|  |  |  |         EmitLabel(".continue"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     GetArg("ebx", 0, 28); | 
					
						
							|  |  |  |     ReadLong(); | 
					
						
							|  |  |  |     e("mov  eax, edx\n"); | 
					
						
							|  |  |  |     if (mmx)    e("emms\n"); | 
					
						
							|  |  |  |     e("pop  ebp\n"); | 
					
						
							|  |  |  |     e("pop  edi\n"); | 
					
						
							|  |  |  |     e("pop  esi\n"); | 
					
						
							|  |  |  |     e("pop  edx\n"); | 
					
						
							|  |  |  |     e("pop  ecx\n"); | 
					
						
							|  |  |  |     e("pop  ebx\n"); | 
					
						
							|  |  |  |     e("ret\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Turbo68KWriteByte() */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Align(4); | 
					
						
							|  |  |  |     EmitGlobalLabel("Turbo68KWriteByte"); | 
					
						
							|  |  |  |     e("pusha\n"); | 
					
						
							|  |  |  |     e("xor  ebp, ebp\n");                   /* so PC doesn't get trashed */ | 
					
						
							|  |  |  |     e("mov  esi, [pc]\n"); | 
					
						
							|  |  |  |     if (multiaddr) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         e("test byte [sr+1], 0x20\n");      /* set proper address space */ | 
					
						
							|  |  |  |         e("jz   short .user\n"); | 
					
						
							|  |  |  |         SetSupervisorAddressSpace(); | 
					
						
							|  |  |  |         e("jmp  short .continue\n"); | 
					
						
							|  |  |  |         EmitLabel(".user"); | 
					
						
							|  |  |  |         SetUserAddressSpace(); | 
					
						
							|  |  |  |         EmitLabel(".continue"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     GetArg("ebx", 0, 36); | 
					
						
							|  |  |  |     GetArg("edx", 1, 40); | 
					
						
							|  |  |  |     WriteByte(); | 
					
						
							|  |  |  |     if (mmx)    e("emms\n"); | 
					
						
							|  |  |  |     e("popa\n"); | 
					
						
							|  |  |  |     e("ret\n"); | 
					
						
							|  |  |  |                     | 
					
						
							|  |  |  |     /* Turbo68KWriteWord() */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Align(4); | 
					
						
							|  |  |  |     EmitGlobalLabel("Turbo68KWriteWord"); | 
					
						
							|  |  |  |     e("pusha\n"); | 
					
						
							|  |  |  |     e("xor  ebp, ebp\n");                   /* so PC doesn't get trashed */ | 
					
						
							|  |  |  |     e("mov  esi, [pc]\n"); | 
					
						
							|  |  |  |     if (multiaddr) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         e("test byte [sr+1], 0x20\n");      /* set proper address space */ | 
					
						
							|  |  |  |         e("jz   short .user\n"); | 
					
						
							|  |  |  |         SetSupervisorAddressSpace(); | 
					
						
							|  |  |  |         e("jmp  short .continue\n"); | 
					
						
							|  |  |  |         EmitLabel(".user"); | 
					
						
							|  |  |  |         SetUserAddressSpace(); | 
					
						
							|  |  |  |         EmitLabel(".continue"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     GetArg("ebx", 0, 36); | 
					
						
							|  |  |  |     GetArg("edx", 1, 40); | 
					
						
							|  |  |  |     WriteWord(); | 
					
						
							|  |  |  |     if (mmx)    e("emms\n"); | 
					
						
							|  |  |  |     e("popa\n"); | 
					
						
							|  |  |  |     e("ret\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Turbo68KWriteLong() */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Align(4); | 
					
						
							|  |  |  |     EmitGlobalLabel("Turbo68KWriteLong"); | 
					
						
							|  |  |  |     e("pusha\n"); | 
					
						
							|  |  |  |     e("xor  ebp, ebp\n");                   /* so PC doesn't get trashed */ | 
					
						
							|  |  |  |     e("mov  esi, [pc]\n"); | 
					
						
							|  |  |  |     if (multiaddr) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         e("test byte [sr+1], 0x20\n");      /* set proper address space */ | 
					
						
							|  |  |  |         e("jz   short .user\n"); | 
					
						
							|  |  |  |         SetSupervisorAddressSpace(); | 
					
						
							|  |  |  |         e("jmp  short .continue\n"); | 
					
						
							|  |  |  |         EmitLabel(".user"); | 
					
						
							|  |  |  |         SetUserAddressSpace(); | 
					
						
							|  |  |  |         EmitLabel(".continue"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     GetArg("ebx", 0, 36); | 
					
						
							|  |  |  |     GetArg("edx", 1, 40); | 
					
						
							|  |  |  |     WriteLong(); | 
					
						
							|  |  |  |     if (mmx)    e("emms\n"); | 
					
						
							|  |  |  |     e("popa\n"); | 
					
						
							|  |  |  |     e("ret\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Turbo68KSet/GetContext() */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |      * Notice the trick here, all of the memory map pointers have 16 | 
					
						
							|  |  |  |      * subtracted from them, this helps optimize the read/write handlers | 
					
						
							|  |  |  |      * since an "add edi, 16" is possible straight off. This was NB's | 
					
						
							|  |  |  |      * idea. The fetch area is also handled this way | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Align(4); | 
					
						
							|  |  |  |     EmitGlobalLabel("Turbo68KSetContext"); | 
					
						
							|  |  |  |     e("push ecx\n"); | 
					
						
							|  |  |  |     e("push esi\n"); | 
					
						
							|  |  |  |     e("push edi\n"); | 
					
						
							|  |  |  |     GetArg("esi", 0, 16); | 
					
						
							|  |  |  |     e("mov  edi, %s%s\n", id, NameOfContext()); | 
					
						
							|  |  |  |     if (mmx && !(SizeOfContext() & 7)) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         e("mov  ecx, " SIZEOF_CONTEXT " / 8\n"); | 
					
						
							|  |  |  |         EmitLabel(".l"); | 
					
						
							|  |  |  |         e("movq mm6, [esi]\n"); | 
					
						
							|  |  |  |         e("movq [edi], mm6\n"); | 
					
						
							|  |  |  |         e("add  esi, byte 8\n"); | 
					
						
							|  |  |  |         e("add  edi, byte 8\n"); | 
					
						
							|  |  |  |         e("dec  ecx\n"); | 
					
						
							|  |  |  |         e("jnz  short .l\n"); | 
					
						
							|  |  |  |         e("emms\n"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         e("mov  ecx, " SIZEOF_CONTEXT " / 4\n"); | 
					
						
							|  |  |  |         e("cld\n"); | 
					
						
							|  |  |  |         e("rep  movsd\n"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     e("sub  dword [fetch], "SIZEOF_FETCHREGION"\n"); | 
					
						
							|  |  |  |     e("sub  dword [pcfetch], "SIZEOF_FETCHREGION"\n"); | 
					
						
							|  |  |  |     e("sub  dword [super_fetch], "SIZEOF_FETCHREGION"\n"); | 
					
						
							|  |  |  |     e("sub  dword [super_pcfetch], "SIZEOF_FETCHREGION"\n"); | 
					
						
							|  |  |  |     e("sub  dword [user_fetch], "SIZEOF_FETCHREGION"\n"); | 
					
						
							|  |  |  |     e("sub  dword [user_pcfetch], "SIZEOF_FETCHREGION"\n"); | 
					
						
							|  |  |  |     if (memmap_type == 0) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         e("sub  dword [read_byte], "SIZEOF_DATAREGION"\n"); | 
					
						
							|  |  |  |         e("sub  dword [read_word], "SIZEOF_DATAREGION"\n"); | 
					
						
							|  |  |  |         e("sub  dword [read_long], "SIZEOF_DATAREGION"\n"); | 
					
						
							|  |  |  |         e("sub  dword [write_byte], "SIZEOF_DATAREGION"\n"); | 
					
						
							|  |  |  |         e("sub  dword [write_word], "SIZEOF_DATAREGION"\n"); | 
					
						
							|  |  |  |         e("sub  dword [write_long], "SIZEOF_DATAREGION"\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         e("sub  dword [super_read_byte], "SIZEOF_DATAREGION"\n"); | 
					
						
							|  |  |  |         e("sub  dword [super_read_word], "SIZEOF_DATAREGION"\n"); | 
					
						
							|  |  |  |         e("sub  dword [super_read_long], "SIZEOF_DATAREGION"\n"); | 
					
						
							|  |  |  |         e("sub  dword [super_write_byte], "SIZEOF_DATAREGION"\n"); | 
					
						
							|  |  |  |         e("sub  dword [super_write_word], "SIZEOF_DATAREGION"\n"); | 
					
						
							|  |  |  |         e("sub  dword [super_write_long], "SIZEOF_DATAREGION"\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         e("sub  dword [user_read_byte], "SIZEOF_DATAREGION"\n"); | 
					
						
							|  |  |  |         e("sub  dword [user_read_word], "SIZEOF_DATAREGION"\n"); | 
					
						
							|  |  |  |         e("sub  dword [user_read_long], "SIZEOF_DATAREGION"\n"); | 
					
						
							|  |  |  |         e("sub  dword [user_write_byte], "SIZEOF_DATAREGION"\n"); | 
					
						
							|  |  |  |         e("sub  dword [user_write_word], "SIZEOF_DATAREGION"\n"); | 
					
						
							|  |  |  |         e("sub  dword [user_write_long], "SIZEOF_DATAREGION"\n"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     e("pop  edi\n"); | 
					
						
							|  |  |  |     e("pop  esi\n"); | 
					
						
							|  |  |  |     e("pop  ecx\n"); | 
					
						
							|  |  |  |     e("ret\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Align(4); | 
					
						
							|  |  |  |     EmitGlobalLabel("Turbo68KGetContext"); | 
					
						
							|  |  |  |     e("push ecx\n"); | 
					
						
							|  |  |  |     e("push esi\n"); | 
					
						
							|  |  |  |     e("push edi\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     e("add  dword [fetch], "SIZEOF_FETCHREGION"\n"); | 
					
						
							|  |  |  |     e("add  dword [pcfetch], "SIZEOF_FETCHREGION"\n"); | 
					
						
							|  |  |  |     e("add  dword [super_fetch], "SIZEOF_FETCHREGION"\n"); | 
					
						
							|  |  |  |     e("add  dword [super_pcfetch], "SIZEOF_FETCHREGION"\n"); | 
					
						
							|  |  |  |     e("add  dword [user_fetch], "SIZEOF_FETCHREGION"\n"); | 
					
						
							|  |  |  |     e("add  dword [user_pcfetch], "SIZEOF_FETCHREGION"\n"); | 
					
						
							|  |  |  |     if (memmap_type == 0) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         e("add  dword [read_byte], "SIZEOF_DATAREGION"\n"); | 
					
						
							|  |  |  |         e("add  dword [read_word], "SIZEOF_DATAREGION"\n"); | 
					
						
							|  |  |  |         e("add  dword [read_long], "SIZEOF_DATAREGION"\n"); | 
					
						
							|  |  |  |         e("add  dword [write_byte], "SIZEOF_DATAREGION"\n"); | 
					
						
							|  |  |  |         e("add  dword [write_word], "SIZEOF_DATAREGION"\n"); | 
					
						
							|  |  |  |         e("add  dword [write_long], "SIZEOF_DATAREGION"\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         e("add  dword [super_read_byte], "SIZEOF_DATAREGION"\n"); | 
					
						
							|  |  |  |         e("add  dword [super_read_word], "SIZEOF_DATAREGION"\n"); | 
					
						
							|  |  |  |         e("add  dword [super_read_long], "SIZEOF_DATAREGION"\n"); | 
					
						
							|  |  |  |         e("add  dword [super_write_byte], "SIZEOF_DATAREGION"\n"); | 
					
						
							|  |  |  |         e("add  dword [super_write_word], "SIZEOF_DATAREGION"\n"); | 
					
						
							|  |  |  |         e("add  dword [super_write_long], "SIZEOF_DATAREGION"\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         e("add  dword [user_read_byte], "SIZEOF_DATAREGION"\n"); | 
					
						
							|  |  |  |         e("add  dword [user_read_word], "SIZEOF_DATAREGION"\n"); | 
					
						
							|  |  |  |         e("add  dword [user_read_long], "SIZEOF_DATAREGION"\n"); | 
					
						
							|  |  |  |         e("add  dword [user_write_byte], "SIZEOF_DATAREGION"\n"); | 
					
						
							|  |  |  |         e("add  dword [user_write_word], "SIZEOF_DATAREGION"\n"); | 
					
						
							|  |  |  |         e("add  dword [user_write_long], "SIZEOF_DATAREGION"\n"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     GetArg("edi", 0, 16); | 
					
						
							|  |  |  |     e("mov  esi, %s%s\n", id, NameOfContext()); | 
					
						
							|  |  |  |     if (mmx && !(SizeOfContext() & 7)) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         e("mov  ecx, " SIZEOF_CONTEXT " / 8\n"); | 
					
						
							|  |  |  |         EmitLabel(".l"); | 
					
						
							|  |  |  |         e("movq mm6, [esi]\n"); | 
					
						
							|  |  |  |         e("movq [edi], mm6\n"); | 
					
						
							|  |  |  |         e("add  esi, byte 8\n"); | 
					
						
							|  |  |  |         e("add  edi, byte 8\n"); | 
					
						
							|  |  |  |         e("dec  ecx\n"); | 
					
						
							|  |  |  |         e("jnz  short .l\n"); | 
					
						
							|  |  |  |         e("emms\n"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         e("mov  ecx, " SIZEOF_CONTEXT " / 4\n"); | 
					
						
							|  |  |  |         e("cld\n"); | 
					
						
							|  |  |  |         e("rep  movsd\n"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     e("sub  dword [fetch], "SIZEOF_FETCHREGION"\n"); | 
					
						
							|  |  |  |     e("sub  dword [pcfetch], "SIZEOF_FETCHREGION"\n"); | 
					
						
							|  |  |  |     e("sub  dword [super_fetch], "SIZEOF_FETCHREGION"\n"); | 
					
						
							|  |  |  |     e("sub  dword [super_pcfetch], "SIZEOF_FETCHREGION"\n"); | 
					
						
							|  |  |  |     e("sub  dword [user_fetch], "SIZEOF_FETCHREGION"\n"); | 
					
						
							|  |  |  |     e("sub  dword [user_pcfetch], "SIZEOF_FETCHREGION"\n"); | 
					
						
							|  |  |  |     if (memmap_type == 0) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         e("sub  dword [read_byte], "SIZEOF_DATAREGION"\n"); | 
					
						
							|  |  |  |         e("sub  dword [read_word], "SIZEOF_DATAREGION"\n"); | 
					
						
							|  |  |  |         e("sub  dword [read_long], "SIZEOF_DATAREGION"\n"); | 
					
						
							|  |  |  |         e("sub  dword [write_byte], "SIZEOF_DATAREGION"\n"); | 
					
						
							|  |  |  |         e("sub  dword [write_word], "SIZEOF_DATAREGION"\n"); | 
					
						
							|  |  |  |         e("sub  dword [write_long], "SIZEOF_DATAREGION"\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         e("sub  dword [super_read_byte], "SIZEOF_DATAREGION"\n"); | 
					
						
							|  |  |  |         e("sub  dword [super_read_word], "SIZEOF_DATAREGION"\n"); | 
					
						
							|  |  |  |         e("sub  dword [super_read_long], "SIZEOF_DATAREGION"\n"); | 
					
						
							|  |  |  |         e("sub  dword [super_write_byte], "SIZEOF_DATAREGION"\n"); | 
					
						
							|  |  |  |         e("sub  dword [super_write_word], "SIZEOF_DATAREGION"\n"); | 
					
						
							|  |  |  |         e("sub  dword [super_write_long], "SIZEOF_DATAREGION"\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         e("sub  dword [user_read_byte], "SIZEOF_DATAREGION"\n"); | 
					
						
							|  |  |  |         e("sub  dword [user_read_word], "SIZEOF_DATAREGION"\n"); | 
					
						
							|  |  |  |         e("sub  dword [user_read_long], "SIZEOF_DATAREGION"\n"); | 
					
						
							|  |  |  |         e("sub  dword [user_write_byte], "SIZEOF_DATAREGION"\n"); | 
					
						
							|  |  |  |         e("sub  dword [user_write_word], "SIZEOF_DATAREGION"\n"); | 
					
						
							|  |  |  |         e("sub  dword [user_write_long], "SIZEOF_DATAREGION"\n"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     e("pop  edi\n"); | 
					
						
							|  |  |  |     e("pop  esi\n"); | 
					
						
							|  |  |  |     e("pop  ecx\n"); | 
					
						
							|  |  |  |     e("ret\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Turbo68KGetContextSize() */ | 
					
						
							|  |  |  |     EmitGlobalLabel("Turbo68KGetContextSize"); | 
					
						
							|  |  |  |     e("mov  eax, "SIZEOF_CONTEXT"\n"); | 
					
						
							|  |  |  |     e("ret\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Turbo68KClearCycles */ | 
					
						
							|  |  |  |     EmitGlobalLabel("Turbo68KClearCycles"); | 
					
						
							|  |  |  |     e("mov  dword [cycles], 0\n"); | 
					
						
							|  |  |  |     e("mov  dword [remaining], 0\n"); | 
					
						
							|  |  |  |     e("ret\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Turbo68KFreeTimeSlice */ | 
					
						
							|  |  |  |     EmitGlobalLabel("Turbo68KFreeTimeSlice"); | 
					
						
							|  |  |  |     e("push eax\n"); | 
					
						
							|  |  |  |     e("mov  eax, [cycles]\n"); | 
					
						
							|  |  |  |     e("sub  eax, [remaining]\n"); | 
					
						
							|  |  |  |     e("mov  [cycles], eax\n"); | 
					
						
							|  |  |  |     e("mov  dword [remaining], 0\n"); | 
					
						
							|  |  |  |     e("pop  eax\n"); | 
					
						
							|  |  |  |     e("ret\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Turbo68KGetElapsedCycles */ | 
					
						
							|  |  |  |     Align(4); | 
					
						
							|  |  |  |     EmitGlobalLabel("Turbo68KGetElapsedCycles"); | 
					
						
							|  |  |  |     e("mov  eax, [cycles]\n"); | 
					
						
							|  |  |  |     e("sub  eax, [remaining]\n"); | 
					
						
							|  |  |  |     e("ret\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Turbo68KProcessInterrupts() */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Align(4); | 
					
						
							|  |  |  |     EmitGlobalLabel("Turbo68KProcessInterrupts"); | 
					
						
							|  |  |  |     e("pusha\n"); | 
					
						
							|  |  |  |     e("test byte [status], 1\n"); | 
					
						
							|  |  |  |     e("jnz  near .end\n");              /* does not work while running */ | 
					
						
							|  |  |  |     e("mov  ecx, [remaining]\n"); | 
					
						
							|  |  |  |     EMULATING();                        /* running=1 */ | 
					
						
							|  |  |  |     e("mov  esi, [pc]\n");              /* fetch PC */ | 
					
						
							|  |  |  |     UpdateFetchPtr(); | 
					
						
							|  |  |  |     e("call ProcessInterrupts\n"); | 
					
						
							|  |  |  |     STOP_RUNNING();                     /* save PC and cycles remaining */ | 
					
						
							|  |  |  |     STOP_EMULATING(); | 
					
						
							|  |  |  |     EmitLabel(".end"); | 
					
						
							|  |  |  |     if (mmx)    e("emms\n"); | 
					
						
							|  |  |  |     e("popa\n"); | 
					
						
							|  |  |  |     e("xor  eax, eax\n"); | 
					
						
							|  |  |  |     e("ret\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Turbo68KInterrupt() */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |      * Note: This function assumes that TURBO68K_AUTOVECTOR == 256, make | 
					
						
							|  |  |  |      * sure the definition in TURBO68K.H reflects this | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * If 68K is halted (STOP instruction), if an interrupt with a priority | 
					
						
							|  |  |  |      * equal to or lower than the SR priority is requested, is the interrupt | 
					
						
							|  |  |  |      * made pending or discarded? (ask) Are there any situations when invalid- | 
					
						
							|  |  |  |      * priority interrupts are discarded completely? | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Align(4); | 
					
						
							|  |  |  |     EmitGlobalLabel("Turbo68KInterrupt"); | 
					
						
							|  |  |  |     e("push\tebx\n"); | 
					
						
							|  |  |  |     e("push\tecx\n"); | 
					
						
							|  |  |  |     e("push\tedx\n"); | 
					
						
							|  |  |  |     e("push\tesi\n"); | 
					
						
							|  |  |  |     e("push\tedi\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     GetArg("eax", 0, 24); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     e("test eax, eax\n");               /* 0 is not a valid level */ | 
					
						
							|  |  |  |     e("jz   short .inv_level\n"); | 
					
						
							|  |  |  |     e("cmp  eax, byte 7\n");            /* if greater than 7, invalid level */ | 
					
						
							|  |  |  |     e("ja   short .inv_level\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     GetArg("ebx", 1, 28);               /* get vector */ | 
					
						
							|  |  |  |     e("cmp  ebx, byte 2\n"); | 
					
						
							|  |  |  |     e("jb   short .inv_vector\n"); | 
					
						
							|  |  |  |     e("cmp  ebx, 256\n"); | 
					
						
							|  |  |  |     e("ja   short .inv_vector\n"); | 
					
						
							|  |  |  |     e("jne  short .not_auto\n"); | 
					
						
							|  |  |  |     e("mov  ebx, eax\n"); | 
					
						
							|  |  |  |     e("add  ebx, byte 24\n"); | 
					
						
							|  |  |  |     EmitLabel(".not_auto"); | 
					
						
							|  |  |  |     e("dec  eax\n");                    /* (level-1)*4=offset into intr[] */ | 
					
						
							|  |  |  |     e("shl  eax, byte 2\n"); | 
					
						
							|  |  |  |     e("cmp  [intr+eax], byte 0\n"); | 
					
						
							|  |  |  |     e("jne  short .pending\n");         /* already pending */ | 
					
						
							|  |  |  |     e("mov  [intr+eax], ebx\n");        /* store vector into intr[] */ | 
					
						
							|  |  |  |     e("inc  dword [intr+7*4]\n");       /* one interrupt added */ | 
					
						
							|  |  |  |     e("pop\tedi\n"); | 
					
						
							|  |  |  |     e("pop\tesi\n"); | 
					
						
							|  |  |  |     e("pop\tedx\n"); | 
					
						
							|  |  |  |     e("pop\tecx\n"); | 
					
						
							|  |  |  |     e("pop\tebx\n"); | 
					
						
							|  |  |  |     e("xor  eax, eax\n"); | 
					
						
							|  |  |  |     e("ret\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     EmitLabel(".inv_level"); | 
					
						
							|  |  |  |     e("mov  eax, %d\n", TURBO68K_ERROR_INTLEVEL); | 
					
						
							|  |  |  |     e("pop\tedi\n"); | 
					
						
							|  |  |  |     e("pop\tesi\n"); | 
					
						
							|  |  |  |     e("pop\tedx\n"); | 
					
						
							|  |  |  |     e("pop\tecx\n"); | 
					
						
							|  |  |  |     e("pop\tebx\n"); | 
					
						
							|  |  |  |     e("ret\n"); | 
					
						
							|  |  |  |     EmitLabel(".inv_vector"); | 
					
						
							|  |  |  |     e("mov  eax, %d\n", TURBO68K_ERROR_INTVECTOR); | 
					
						
							|  |  |  |     e("pop\tedi\n"); | 
					
						
							|  |  |  |     e("pop\tesi\n"); | 
					
						
							|  |  |  |     e("pop\tedx\n"); | 
					
						
							|  |  |  |     e("pop\tecx\n"); | 
					
						
							|  |  |  |     e("pop\tebx\n"); | 
					
						
							|  |  |  |     e("ret\n"); | 
					
						
							|  |  |  |     EmitLabel(".pending"); | 
					
						
							|  |  |  |     e("mov  eax, %d\n", TURBO68K_ERROR_INTPENDING); | 
					
						
							|  |  |  |     e("pop\tedi\n"); | 
					
						
							|  |  |  |     e("pop\tesi\n"); | 
					
						
							|  |  |  |     e("pop\tedx\n"); | 
					
						
							|  |  |  |     e("pop\tecx\n"); | 
					
						
							|  |  |  |     e("pop\tebx\n"); | 
					
						
							|  |  |  |     e("ret\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Turbo68KCancelInterrupt */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     EmitGlobalLabel("Turbo68KCancelInterrupt"); | 
					
						
							|  |  |  |     e("push\tebx\n"); | 
					
						
							|  |  |  |     e("push\tecx\n"); | 
					
						
							|  |  |  |     e("push\tedx\n"); | 
					
						
							|  |  |  |     e("push\tesi\n"); | 
					
						
							|  |  |  |     e("push\tedi\n"); | 
					
						
							|  |  |  |     GetArg("eax", 0, 24); | 
					
						
							|  |  |  |     e("test eax, eax\n");        /* 0 is not a valid level */ | 
					
						
							|  |  |  |     e("jz   short .inv_level\n"); | 
					
						
							|  |  |  |     e("cmp  eax, byte 7\n");            /* if greater than 7, invalid level */ | 
					
						
							|  |  |  |     e("ja   short .inv_level\n"); | 
					
						
							|  |  |  |     e("test byte [status], 0x04\n");    /* processing interrupts? */ | 
					
						
							|  |  |  |     e("jnz  short .busy\n");            /* yep... can't do this */ | 
					
						
							|  |  |  |     e("dec  eax\n");                    /* make index into intr[] */ | 
					
						
							|  |  |  |     e("cmp  dword [intr+eax*4], byte 0\n"); | 
					
						
							|  |  |  |     e("je   .nothing_to_cancel\n"); | 
					
						
							|  |  |  |     e("mov  dword [intr+eax*4], 0\n"); | 
					
						
							|  |  |  |     e("dec  dword [intr+7*4]\n");       /* removed 1 interrupt */ | 
					
						
							|  |  |  |     EmitLabel(".busy"); | 
					
						
							|  |  |  |     EmitLabel(".nothing_to_cancel"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     e("pop\tedi\n"); | 
					
						
							|  |  |  |     e("pop\tesi\n"); | 
					
						
							|  |  |  |     e("pop\tedx\n"); | 
					
						
							|  |  |  |     e("pop\tecx\n"); | 
					
						
							|  |  |  |     e("pop\tebx\n"); | 
					
						
							|  |  |  |     e("xor  eax, eax\n"); | 
					
						
							|  |  |  |     e("ret\n"); | 
					
						
							|  |  |  |     EmitLabel(".inv_level"); | 
					
						
							|  |  |  |     e("pop\tedi\n"); | 
					
						
							|  |  |  |     e("pop\tesi\n"); | 
					
						
							|  |  |  |     e("pop\tedx\n"); | 
					
						
							|  |  |  |     e("pop\tecx\n"); | 
					
						
							|  |  |  |     e("pop\tebx\n"); | 
					
						
							|  |  |  |     e("mov  eax, %d\n", TURBO68K_ERROR_INTLEVEL); | 
					
						
							|  |  |  |     e("ret\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |      * ProcessInterrupts: Processes any pending interrupts if allowed. | 
					
						
							|  |  |  |      * Assumes all registers have been set up as per Turbo68KRun | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Align(4); | 
					
						
							|  |  |  |     EmitLabel("ProcessInterrupts"); | 
					
						
							|  |  |  |     INTERRUPT_PROCESSING(); | 
					
						
							|  |  |  |     e("cmp  dword [intr+7*4], byte 0\n"); | 
					
						
							|  |  |  |     e("je   near .no_int_end\n");       /* no interrupts pending */ | 
					
						
							|  |  |  |     e("push eax\n");                    /* EAX=flags, save it! */ | 
					
						
							|  |  |  |     e("mov  al, [sr+1]\n"); | 
					
						
							|  |  |  |     e("and  eax, byte 7\n");            /* EAX=interrupt priority */ | 
					
						
							|  |  |  |     e("cmp  al, 7\n"); | 
					
						
							|  |  |  |     e("jne  short .no_int7\n"); | 
					
						
							|  |  |  |     e("mov  edi, intr+6*4\n"); | 
					
						
							|  |  |  |     e("jmp  short .l\n"); | 
					
						
							|  |  |  |     EmitLabel(".no_int7"); | 
					
						
							|  |  |  |     e("mov  edi, eax\n"); | 
					
						
							|  |  |  |     e("shl  edi, byte 2\n");            /* *4, index into intr[] */ | 
					
						
							|  |  |  |     e("add  edi, intr\n");              /* EDI=interrupt queue */ | 
					
						
							|  |  |  |     e("inc  al\n");                     /* new SR priority mask */ | 
					
						
							|  |  |  |     EmitLabel(".l"); | 
					
						
							|  |  |  |     e("cmp  dword [edi], byte 0\n"); | 
					
						
							|  |  |  |     e("je   near .skip\n");             /* no interrupt at this level */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     e("test byte [sr+1], 0x20\n");      /* see if in User mode */ | 
					
						
							|  |  |  |     e("jnz  short .no_sp_magic\n");     /* nope, don't need to swap SPs */ | 
					
						
							|  |  |  |     e("mov  edx, [__sp]\n"); | 
					
						
							|  |  |  |     e("xchg [a+7*4], edx\n"); | 
					
						
							|  |  |  |     e("mov  [__sp], edx\n"); | 
					
						
							|  |  |  |     SetSupervisorAddressSpace(); | 
					
						
							|  |  |  |     EmitLabel(".no_sp_magic"); | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     e("mov  ebx, [a+7*4]\n");           /* SP */ | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |      * If 68010, we have to push the format word on the stack. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     if (mpu == 68010) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         e("mov  edx, [edi]\n"); /* vector number */ | 
					
						
							|  |  |  |         e("sub  ebx, byte 2\n");/* SP-2 */ | 
					
						
							|  |  |  |         e("shl  edx, byte 2\n");/* vector*4 for offset */ | 
					
						
							|  |  |  |         e("push ebx\n"); | 
					
						
							|  |  |  |         e("push edi\n"); | 
					
						
							|  |  |  |         WriteWord(); | 
					
						
							|  |  |  |         e("pop  edi\n"); | 
					
						
							|  |  |  |         e("pop  ebx\n"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     e("mov  edx, [pc]\n");              /* get old PC */ | 
					
						
							|  |  |  |     e("sub  ebx, byte 4\n");            /* SP-4 */ | 
					
						
							|  |  |  |     e("push ebx\n"); | 
					
						
							|  |  |  |     e("push edi\n"); | 
					
						
							|  |  |  |     WriteLong(); | 
					
						
							|  |  |  |     e("pop  edi\n"); | 
					
						
							|  |  |  |     e("pop  ebx\n"); | 
					
						
							|  |  |  |     e("mov  edx, [sr]\n");              /* get SR */ | 
					
						
							|  |  |  |     e("sub  ebx, byte 2\n");            /* SP-2 */ | 
					
						
							|  |  |  |     e("push edi\n"); | 
					
						
							|  |  |  |     e("push ebx\n"); | 
					
						
							|  |  |  |     WriteWord();                        /* save SR to stack */ | 
					
						
							|  |  |  |     e("pop  ebx\n"); | 
					
						
							|  |  |  |     e("pop  edi\n"); | 
					
						
							|  |  |  |     e("mov  dh, al\n");                 /* new interrupt priority bits */ | 
					
						
							|  |  |  |     e("or   dh, 0x20\n");               /* set supervisor for exception */ | 
					
						
							|  |  |  |     e("and  edx, 0xa71f\n");            /* clear unwanted bits */ | 
					
						
							|  |  |  |     e("mov  [sr], edx\n");              /* set new SR */ | 
					
						
							|  |  |  |     e("mov  [a+7*4], ebx\n");           /* write back SP */ | 
					
						
							|  |  |  |     e("mov  ebx, [edi]\n");             /* vector of interrupt */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     e("test dword [InterruptAcknowledge], -1\n");   /* interrupt call-back */ | 
					
						
							|  |  |  |     e("jz   short .no_interrupt_ack_handler\n"); | 
					
						
							|  |  |  |     e("pushad\n"); | 
					
						
							|  |  |  |     e("push ebx\n"); | 
					
						
							|  |  |  |     e("call dword [InterruptAcknowledge]\n"); | 
					
						
							|  |  |  |     e("add  esp, byte 4\n"); | 
					
						
							|  |  |  |     e("popad\n"); | 
					
						
							|  |  |  |     e(".no_interrupt_ack_handler:\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     e("shl  ebx, byte 2\n");            /* vector *= 4 */ | 
					
						
							|  |  |  |     if (mpu == 68010) | 
					
						
							|  |  |  |         e("add  ebx, [vbr]\n"); | 
					
						
							|  |  |  |     e("push edi\n"); | 
					
						
							|  |  |  |     ReadLong();                         /* get PC */ | 
					
						
							|  |  |  |     e("pop  edi\n"); | 
					
						
							|  |  |  |     e("mov  [pc], edx\n");              /* set new PC */ | 
					
						
							|  |  |  |     e("mov  dword [edi], 0\n");         /* done w/ this interrupt */ | 
					
						
							|  |  |  |     e("dec  dword [intr+7*4]\n");       /* processed 1 interrupt... */ | 
					
						
							|  |  |  |     e("sub  ecx, byte 44\n");           /* interrupts take 44 clocks */ | 
					
						
							|  |  |  |     UNSTOP_CPU(); | 
					
						
							|  |  |  |     EmitLabel(".skip"); | 
					
						
							|  |  |  |     e("add  edi, byte 4\n"); | 
					
						
							|  |  |  |     e("inc  al\n");                     /* next entry */ | 
					
						
							|  |  |  |     e("cmp  edi, intr+7*4\n"); | 
					
						
							|  |  |  |     e("jne  near .l\n"); | 
					
						
							|  |  |  |     e("mov  esi, [pc]\n"); | 
					
						
							|  |  |  |     e("pop  eax\n");                    /* get flags back */ | 
					
						
							|  |  |  |     UpdateFetchPtr(); | 
					
						
							|  |  |  |     EmitLabel(".no_int_end"); | 
					
						
							|  |  |  |     INTERRUPT_DONE(); | 
					
						
							|  |  |  |     e("ret\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Turbo68KRun() */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Align(4); | 
					
						
							|  |  |  |     EmitGlobalLabel("Turbo68KRun"); | 
					
						
							|  |  |  |     e("pusha\n"); | 
					
						
							|  |  |  |     GetArg("ecx", 0, 36);   /* ECX = cycles */ | 
					
						
							|  |  |  |     e("mov  [cycles], ecx\n"); | 
					
						
							|  |  |  |     e("mov  [remaining], ecx\n"); | 
					
						
							|  |  |  |     e("test byte [sr+1], 0x20\n"); | 
					
						
							|  |  |  |     e("jz   near .set_user_space\n"); | 
					
						
							|  |  |  |     SetSupervisorAddressSpace(); | 
					
						
							|  |  |  |     e("jmp  near .continue\n"); | 
					
						
							|  |  |  |     EmitLabel(".set_user_space"); | 
					
						
							|  |  |  |     SetUserAddressSpace(); | 
					
						
							|  |  |  |     EmitLabel(".continue"); | 
					
						
							|  |  |  |     EMULATING();                        /* running=1 */ | 
					
						
							|  |  |  |     e("mov  esi, [pc]\n");              /* fetch PC */ | 
					
						
							|  |  |  |     UpdateFetchPtr(); | 
					
						
							|  |  |  |     LoadCCR();                          /* get flags */ | 
					
						
							|  |  |  |     e("call ProcessInterrupts\n"); | 
					
						
							|  |  |  |     e("test byte [status], 2\n");       /* stopped? */ | 
					
						
							|  |  |  |     e("jnz  short .stopped\n"); | 
					
						
							|  |  |  |     e("xor  edi, edi\n"); | 
					
						
							|  |  |  |     e("mov  di, [esi]\n");              /* next instruction */ | 
					
						
							|  |  |  |     e("add  esi, byte 2\n");     | 
					
						
							|  |  |  |     e("jmp  dword [jmptab+edi*4]\n");   /* jump... */ | 
					
						
							|  |  |  |     EmitLabel(".stopped"); | 
					
						
							|  |  |  |     e("xor  ecx, ecx\n"); | 
					
						
							|  |  |  |     e("jmp  Turbo68KRun_done\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Align(4); | 
					
						
							|  |  |  |     EmitLabel("Turbo68KRun_done"); | 
					
						
							|  |  |  |     SaveCCR();                          /* save flags */ | 
					
						
							|  |  |  |     STOP_RUNNING();                     /* save PC and cycles */ | 
					
						
							|  |  |  |     STOP_EMULATING(); | 
					
						
							|  |  |  |     if (mmx)    e("emms\n"); | 
					
						
							|  |  |  |     e("popa\n"); | 
					
						
							|  |  |  |     e("xor  eax, eax\n");               /* everything okay... */ | 
					
						
							|  |  |  |     e("ret\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |      * NOTE: Only the 68010 RTE handler can call this. PC is assumed to point | 
					
						
							|  |  |  |      * one word after the faulty RTE. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (mpu == 68010) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         EmitLabel("stackframe_error"); | 
					
						
							|  |  |  |         e("sub  esi, byte 2\n");        /* point at faulty RTE */ | 
					
						
							|  |  |  |         SaveCCR(); | 
					
						
							|  |  |  |         STOP_EMULATING(); | 
					
						
							|  |  |  |         STOP_RUNNING();                 /* save PC and cycles remaining */ | 
					
						
							|  |  |  |         e("popa\n"); | 
					
						
							|  |  |  |         e("mov  eax, %d\n", TURBO68K_ERROR_STACKFRAME); | 
					
						
							|  |  |  |         e("ret\n"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (memmap_type == 2)   /* low level handling? don't generate the rest */ | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |      * ReadXXXXPC: EBX = address | 
					
						
							|  |  |  |      * Out:        EDX = data; DL=byte, EDX=upper 32-bits trashed, DX=word, | 
					
						
							|  |  |  |      *             EDX=long-word | 
					
						
							|  |  |  |      *             EBX=address | 
					
						
							|  |  |  |      * Notes:      EDI is trashed in the process, but cleared at the end. | 
					
						
							|  |  |  |      *             These functions read from the *pcfetch areas. There are no | 
					
						
							|  |  |  |      *             SX functions, this is handled by the emitter. I did this to | 
					
						
							|  |  |  |      *             save space. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     if (pcfetch) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         for (i = 0; i < 3; i++) /* 0=byte, 1=word, 2=dword */ | 
					
						
							|  |  |  |         {           | 
					
						
							|  |  |  |             CacheAlign(); | 
					
						
							|  |  |  |             switch (i) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |             case 0: | 
					
						
							|  |  |  |                 EmitLabel("ReadBytePC"); | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             case 1: | 
					
						
							|  |  |  |                 EmitLabel("ReadWordPC"); | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             case 2: | 
					
						
							|  |  |  |                 EmitLabel("ReadLongPC"); | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             e("mov  edi, [pcfetch]\n"); | 
					
						
							|  |  |  |             SaveReg("memhandler", "ebx");           /* save address */ | 
					
						
							|  |  |  |             AddrClip("ebx"); | 
					
						
							|  |  |  |             EmitLabel(".loop"); | 
					
						
							|  |  |  |             e("add     edi, byte "SIZEOF_FETCHREGION"\n"); | 
					
						
							|  |  |  |             e("cmp     dword [edi], byte -1\n");    /* base=-1? end. */ | 
					
						
							|  |  |  |             e("je      short .not_found\n"); | 
					
						
							|  |  |  |             e("cmp     ebx, [edi]\n");              /* offset 0: base. above it? */ | 
					
						
							|  |  |  |             e("jb      short .loop\n");             /* nope, not this region */ | 
					
						
							|  |  |  |             e("cmp     ebx, [edi+"OFFSET_FETCH_LIMIT"]\n");  /* limit. below it? */ | 
					
						
							|  |  |  |             e("ja      short .loop\n");             /* nope, not this region */ | 
					
						
							|  |  |  |             e("mov     edx, ebx\n"); | 
					
						
							|  |  |  |             if (!i)     /* byte accesses need this because buffer is swapped */ | 
					
						
							|  |  |  |                 e("xor     dl, 1\n"); | 
					
						
							|  |  |  |             e("add     edx, [edi+"OFFSET_FETCH_PTR"]\n");    /* into ptr.. */ | 
					
						
							|  |  |  |             if (!i)         /* byte */ | 
					
						
							|  |  |  |                 e("mov     dl, [edx]\n");           /* fetch */ | 
					
						
							|  |  |  |             else if (i == 1)    /* word */ | 
					
						
							|  |  |  |                 e("mov     edx, [edx]\n"); | 
					
						
							|  |  |  |             else            /* long */ | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 e("mov     edx, [edx]\n"); | 
					
						
							|  |  |  |                 e("rol     edx, byte 16\n");        /* swap words */ | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             e("xor  edi, edi\n"); | 
					
						
							|  |  |  |             RestoreReg("memhandler", "ebx"); | 
					
						
							|  |  |  |             e("ret\n"); | 
					
						
							|  |  |  |             Align(4); | 
					
						
							|  |  |  |             EmitLabel(".not_found"); | 
					
						
							|  |  |  |             e("xor  edi, edi\n"); | 
					
						
							|  |  |  |             e("xor  edx, edx\n"); | 
					
						
							|  |  |  |             e("dec  edx\n");    /* not found, return all 1s */ | 
					
						
							|  |  |  |             RestoreReg("memhandler", "ebx"); | 
					
						
							|  |  |  |             e("ret\n"); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |      * ReadXXXX: EBX = address | 
					
						
							|  |  |  |      * Out:      EDX = data; DL=byte, EDX=upper 32-bits trashed, DX=word, | 
					
						
							|  |  |  |      *           EDX=long-word | 
					
						
							|  |  |  |      *           EBX=address | 
					
						
							|  |  |  |      * Notes:    EDI is trashed in the process, but cleared at the end. | 
					
						
							|  |  |  |      *           This applies to all ReadXXX and WriteXXX handlers, some | 
					
						
							|  |  |  |      *           instructions (NEGX) rely on this behavior. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     if (memmap_type == 0)       /* default memory mapping system */ | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         for (i = 0; i < 3; i++) /* 0=byte, 1=word, 2=dword */ | 
					
						
							|  |  |  |         {           | 
					
						
							|  |  |  |             CacheAlign(); | 
					
						
							|  |  |  |             switch (i) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |             case 0: | 
					
						
							|  |  |  |                 EmitLabel("ReadByte"); | 
					
						
							|  |  |  |                 e("mov  edi, [read_byte]\n"); | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             case 1: | 
					
						
							|  |  |  |                 EmitLabel("ReadWord"); | 
					
						
							|  |  |  |                 e("mov  edi, [read_word]\n"); | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             case 2: | 
					
						
							|  |  |  |                 EmitLabel("ReadLong"); | 
					
						
							|  |  |  |                 e("mov  edi, [read_long]\n"); | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             SaveReg("memhandler", "ebx");           /* save address */ | 
					
						
							|  |  |  |             AddrClip("ebx"); | 
					
						
							|  |  |  |             EmitLabel(".loop"); | 
					
						
							|  |  |  |             e("add     edi, byte "SIZEOF_DATAREGION"\n"); | 
					
						
							|  |  |  |             e("cmp     dword [edi], byte -1\n");    /* base=-1? end. */ | 
					
						
							|  |  |  |             e("je      short .not_found\n"); | 
					
						
							|  |  |  |             e("cmp     ebx, [edi]\n");              /* offset 0: base. above it? */ | 
					
						
							|  |  |  |             e("jb      short .loop\n");             /* nope, not this region */ | 
					
						
							|  |  |  |             e("cmp     ebx, [edi+"OFFSET_DATA_LIMIT"]\n");  /* limit. below it? */ | 
					
						
							|  |  |  |             e("ja      short .loop\n");             /* nope, not this region */ | 
					
						
							|  |  |  |             e("cmp     dword [edi+"OFFSET_DATA_PTR"], byte 0\n"); | 
					
						
							|  |  |  |             e("je      short .read_from_handler\n"); | 
					
						
							|  |  |  |             e("mov     edx, ebx\n"); | 
					
						
							|  |  |  |             if (!i)     /* byte accesses need this because buffer is swapped */ | 
					
						
							|  |  |  |                 e("xor     dl, 1\n"); | 
					
						
							|  |  |  |             e("add     edx, [edi+"OFFSET_DATA_PTR"]\n");    /* into ptr.. */ | 
					
						
							|  |  |  |             if (!i)         /* byte */ | 
					
						
							|  |  |  |                 e("mov     dl, [edx]\n");           /* fetch */ | 
					
						
							|  |  |  |             else if (i == 1)    /* word */ | 
					
						
							|  |  |  |                 e("mov     edx, [edx]\n"); | 
					
						
							|  |  |  |             else            /* long */ | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 e("mov     edx, [edx]\n"); | 
					
						
							|  |  |  |                 e("rol     edx, byte 16\n");        /* swap words */ | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             e("xor  edi, edi\n"); | 
					
						
							|  |  |  |             RestoreReg("memhandler", "ebx"); | 
					
						
							|  |  |  |             e("ret\n"); | 
					
						
							|  |  |  |             Align(4); | 
					
						
							|  |  |  |             EmitLabel(".not_found"); | 
					
						
							|  |  |  |             e("xor  edi, edi\n"); | 
					
						
							|  |  |  |             e("xor  edx, edx\n"); | 
					
						
							|  |  |  |             e("dec  edx\n");    /* not found, return all 1s */ | 
					
						
							|  |  |  |             RestoreReg("memhandler", "ebx"); | 
					
						
							|  |  |  |             e("ret\n"); | 
					
						
							|  |  |  |             Align(4); | 
					
						
							|  |  |  |             EmitLabel(".read_from_handler"); | 
					
						
							|  |  |  |             SaveReg("memhandler", "eax"); | 
					
						
							|  |  |  |             SaveReg("memhandler", "ebp"); | 
					
						
							|  |  |  |             WRITEPCTOMEM("pc");                     /* saves esi */ | 
					
						
							|  |  |  |             e("mov     [remaining], ecx\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             /* address */ | 
					
						
							|  |  |  |             if (!call_convention)                   /* stack-based */ | 
					
						
							|  |  |  |                 e("push ebx\n");  | 
					
						
							|  |  |  |             else                                    /* register-based */ | 
					
						
							|  |  |  |                 e("mov  eax, ebx\n"); | 
					
						
							|  |  |  |              | 
					
						
							|  |  |  |             e("call    dword [edi+"OFFSET_DATA_HANDLER"]\n");       | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (!call_convention) | 
					
						
							|  |  |  |                 e("add     esp, byte 4\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             e("mov     edx, eax\n");                /* get the data */ | 
					
						
							|  |  |  |             e("mov     esi, [pc]\n");       /* handler could have changed PC */ | 
					
						
							|  |  |  |             e("mov     ecx, [remaining]\n");/* this could have been changed */ | 
					
						
							|  |  |  |             RestoreReg("memhandler", "eax"); | 
					
						
							|  |  |  |             RestoreReg("memhandler", "ebp"); | 
					
						
							|  |  |  |             e("add     esi, ebp\n");        /* base+pc=pc pointer */ | 
					
						
							|  |  |  |             e("xor     edi, edi\n");        /* keep clear for fetch */ | 
					
						
							|  |  |  |             RestoreReg("memhandler", "ebx"); | 
					
						
							|  |  |  |             e("ret\n"); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else if (memmap_type == 1)  /* high level handler */ | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         for (i = 0; i < 3; i++) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             CacheAlign(); | 
					
						
							|  |  |  |             switch (i) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |             case 0: EmitLabel("ReadByte"); break; | 
					
						
							|  |  |  |             case 1: EmitLabel("ReadWord"); break; | 
					
						
							|  |  |  |             case 2: EmitLabel("ReadLong"); break; | 
					
						
							|  |  |  |             }             | 
					
						
							|  |  |  |             SaveReg("memhandler", "ebx");           /* save address */ | 
					
						
							|  |  |  |             AddrClip("ebx"); | 
					
						
							|  |  |  |             SaveReg("memhandler", "eax"); | 
					
						
							|  |  |  |             SaveReg("memhandler", "ebp"); | 
					
						
							|  |  |  |             WRITEPCTOMEM("pc");                     /* saves esi */ | 
					
						
							|  |  |  |             e("mov     [remaining], ecx\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             /* address */ | 
					
						
							|  |  |  |             if (!call_convention)                   /* stack-based */ | 
					
						
							|  |  |  |                 e("push ebx\n");  | 
					
						
							|  |  |  |             else                                    /* register-based */ | 
					
						
							|  |  |  |                 e("mov  eax, ebx\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             switch (i) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |             case 0: e("call dword [read_byte]\n"); break; | 
					
						
							|  |  |  |             case 1: e("call dword [read_word]\n"); break; | 
					
						
							|  |  |  |             case 2: e("call dword [read_long]\n"); break; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (!call_convention) | 
					
						
							|  |  |  |                 e("add     esp, byte 4\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             e("mov     edx, eax\n");                /* get the data */ | 
					
						
							|  |  |  |             e("mov     esi, [pc]\n");       /* handler could have changed PC */ | 
					
						
							|  |  |  |             e("mov     ecx, [remaining]\n");/* this could have been changed */ | 
					
						
							|  |  |  |             RestoreReg("memhandler", "eax"); | 
					
						
							|  |  |  |             RestoreReg("memhandler", "ebp"); | 
					
						
							|  |  |  |             e("add     esi, ebp\n");        /* base+pc=pc pointer */ | 
					
						
							|  |  |  |             e("xor     edi, edi\n");        /* keep clear for fetch */ | 
					
						
							|  |  |  |             RestoreReg("memhandler", "ebx"); | 
					
						
							|  |  |  |             e("ret\n"); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (memmap_type == 0) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         /*
 | 
					
						
							|  |  |  |          * ReadWordSX is the same as ReadWord except that it sign extends the | 
					
						
							|  |  |  |          * word to 32 bits. | 
					
						
							|  |  |  |          */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         CacheAlign(); | 
					
						
							|  |  |  |         EmitLabel("ReadWordSX"); | 
					
						
							|  |  |  |         e("mov  edi, [read_word]\n"); | 
					
						
							|  |  |  |         SaveReg("memhandler", "ebx");       /* save address */ | 
					
						
							|  |  |  |         AddrClip("ebx"); | 
					
						
							|  |  |  |         EmitLabel(".loop");         | 
					
						
							|  |  |  |         e("add     edi, byte "SIZEOF_DATAREGION"\n"); | 
					
						
							|  |  |  |         e("cmp     dword [edi], byte -1\n"); | 
					
						
							|  |  |  |         e("je      short .not_found\n"); | 
					
						
							|  |  |  |         e("cmp     ebx, [edi]\n"); | 
					
						
							|  |  |  |         e("jb      short .loop\n"); | 
					
						
							|  |  |  |         e("cmp     ebx, [edi+"OFFSET_DATA_LIMIT"]\n"); | 
					
						
							|  |  |  |         e("ja      short .loop\n"); | 
					
						
							|  |  |  |         e("cmp     dword [edi+"OFFSET_DATA_PTR"], byte 0\n"); | 
					
						
							|  |  |  |         e("je      short .read_from_handler\n"); | 
					
						
							|  |  |  |         e("mov     edx, ebx\n"); | 
					
						
							|  |  |  |         e("add     edx, [edi+"OFFSET_DATA_PTR"]\n"); | 
					
						
							|  |  |  |         e("movsx   edx, word [edx]\n"); /* sign extend! */ | 
					
						
							|  |  |  |         e("xor  edi, edi\n"); | 
					
						
							|  |  |  |         RestoreReg("memhandler", "ebx"); | 
					
						
							|  |  |  |         e("ret\n"); | 
					
						
							|  |  |  |         Align(4); | 
					
						
							|  |  |  |         EmitLabel(".not_found"); | 
					
						
							|  |  |  |         e("xor  edi, edi\n"); | 
					
						
							|  |  |  |         e("xor  edx, edx\n"); | 
					
						
							|  |  |  |         e("dec  edx\n");    /* not found, return all 1s */ | 
					
						
							|  |  |  |         RestoreReg("memhandler", "ebx"); | 
					
						
							|  |  |  |         e("ret\n"); | 
					
						
							|  |  |  |         Align(4); | 
					
						
							|  |  |  |         EmitLabel(".read_from_handler"); | 
					
						
							|  |  |  |         SaveReg("memhandler", "eax"); | 
					
						
							|  |  |  |         SaveReg("memhandler", "ebp"); | 
					
						
							|  |  |  |         WRITEPCTOMEM("pc"); | 
					
						
							|  |  |  |         e("mov     [remaining], ecx\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /* address */ | 
					
						
							|  |  |  |         if (!call_convention)                   /* stack-based */ | 
					
						
							|  |  |  |             e("push ebx\n");  | 
					
						
							|  |  |  |         else                                    /* register-based */ | 
					
						
							|  |  |  |             e("mov  eax, ebx\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         e("call    dword [edi+"OFFSET_DATA_HANDLER"]\n");       | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (!call_convention) | 
					
						
							|  |  |  |             e("add     esp, byte 4\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         e("movsx   edx, ax\n");                 /* sign extend! */ | 
					
						
							|  |  |  |         e("mov     esi, [pc]\n"); | 
					
						
							|  |  |  |         e("mov     ecx, [remaining]\n"); | 
					
						
							|  |  |  |         RestoreReg("memhandler", "eax"); | 
					
						
							|  |  |  |         RestoreReg("memhandler", "ebp"); | 
					
						
							|  |  |  |         e("add     esi, ebp\n"); | 
					
						
							|  |  |  |         e("xor     edi, edi\n"); | 
					
						
							|  |  |  |         RestoreReg("memhandler", "ebx"); | 
					
						
							|  |  |  |         e("ret\n"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else if (memmap_type == 1) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         CacheAlign(); | 
					
						
							|  |  |  |         EmitLabel("ReadWordSX"); | 
					
						
							|  |  |  |         SaveReg("memhandler", "ebx");           /* save address */ | 
					
						
							|  |  |  |         AddrClip("ebx"); | 
					
						
							|  |  |  |         SaveReg("memhandler", "eax"); | 
					
						
							|  |  |  |         SaveReg("memhandler", "ebp"); | 
					
						
							|  |  |  |         WRITEPCTOMEM("pc");                     /* saves esi */ | 
					
						
							|  |  |  |         e("mov     [remaining], ecx\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /* address */ | 
					
						
							|  |  |  |         if (!call_convention)                   /* stack-based */ | 
					
						
							|  |  |  |             e("push ebx\n");  | 
					
						
							|  |  |  |         else                                    /* register-based */ | 
					
						
							|  |  |  |             e("mov  eax, ebx\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         e("call dword [read_word]\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (!call_convention) | 
					
						
							|  |  |  |             e("add     esp, byte 4\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         e("movsx    edx, ax\n");                /* sign extend */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         e("mov     esi, [pc]\n");       /* handler could have changed PC */ | 
					
						
							|  |  |  |         e("mov     ecx, [remaining]\n");/* this could have been changed */ | 
					
						
							|  |  |  |         RestoreReg("memhandler", "eax"); | 
					
						
							|  |  |  |         RestoreReg("memhandler", "ebp"); | 
					
						
							|  |  |  |         e("add     esi, ebp\n");        /* base+pc=pc pointer */ | 
					
						
							|  |  |  |         e("xor     edi, edi\n");        /* keep clear for fetch */ | 
					
						
							|  |  |  |         RestoreReg("memhandler", "ebx"); | 
					
						
							|  |  |  |         e("ret\n"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |      * WriteXXXX: EBX = address | 
					
						
							|  |  |  |      * In:        EDX = data; DL=byte, EDX{DX}=word, | 
					
						
							|  |  |  |      *            EDX=long-word | 
					
						
							|  |  |  |      * Out:       EBX=trashed, EDX=preserved | 
					
						
							|  |  |  |      * Notes:     EDI is trashed in the process, but cleared at the end | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     if (memmap_type == 0) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         for (i = 0; i < 3; i++) /* 0=byte, 1=word, 2=dword */ | 
					
						
							|  |  |  |         {           | 
					
						
							|  |  |  |             CacheAlign(); | 
					
						
							|  |  |  |             switch (i) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |             case 0: | 
					
						
							|  |  |  |                 EmitLabel("WriteByte"); | 
					
						
							|  |  |  |                 e("mov  edi, [write_byte]\n"); | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             case 1: | 
					
						
							|  |  |  |                 EmitLabel("WriteWord"); | 
					
						
							|  |  |  |                 e("mov  edi, [write_word]\n"); | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             case 2: | 
					
						
							|  |  |  |                 EmitLabel("WriteLong"); | 
					
						
							|  |  |  |                 e("mov  edi, [write_long]\n"); | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             AddrClip("ebx"); | 
					
						
							|  |  |  |             EmitLabel(".loop"); | 
					
						
							|  |  |  |             e("add     edi, byte "SIZEOF_DATAREGION"\n"); | 
					
						
							|  |  |  |             e("cmp     dword [edi], byte -1\n");    /* base=-1? end. */ | 
					
						
							|  |  |  |             e("je      short .not_found\n"); | 
					
						
							|  |  |  |             e("cmp     ebx, [edi]\n");              /* offset 0: base. above it? */ | 
					
						
							|  |  |  |             e("jb      short .loop\n");             /* nope, not this region */ | 
					
						
							|  |  |  |             e("cmp     ebx, [edi+"OFFSET_DATA_LIMIT"]\n");  /* limit. below it? */ | 
					
						
							|  |  |  |             e("ja      short .loop\n");             /* nope, not this region */ | 
					
						
							|  |  |  |             e("cmp     dword [edi+"OFFSET_DATA_PTR"], byte 0\n"); | 
					
						
							|  |  |  |             e("je      short .write_with_handler\n"); | 
					
						
							|  |  |  |             if (!i)         /* byte accesses need this because buffer is swapped */ | 
					
						
							|  |  |  |                 e("xor     bl, 1\n"); | 
					
						
							|  |  |  |             e("add     ebx, [edi+"OFFSET_DATA_PTR"]\n");    /* into ptr.. */ | 
					
						
							|  |  |  |             if (!i)         /* byte */ | 
					
						
							|  |  |  |                 e("mov     [ebx], dl\n");           /* write */           | 
					
						
							|  |  |  |             else if (i == 1)    /* word */ | 
					
						
							|  |  |  |                 e("mov     [ebx], dx\n"); | 
					
						
							|  |  |  |             else            /* long */ | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 e("ror     edx, byte 16\n");        /* swap words */ | 
					
						
							|  |  |  |                 e("mov     [ebx], edx\n"); | 
					
						
							|  |  |  |                 e("ror     edx, byte 16\n");        /* reswap back */ | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             EmitLabel(".not_found"); | 
					
						
							|  |  |  |             e("xor  edi, edi\n"); | 
					
						
							|  |  |  |             RestoreReg("memhandler", "ebx"); | 
					
						
							|  |  |  |             e("ret\n"); | 
					
						
							|  |  |  |             Align(4); | 
					
						
							|  |  |  |             EmitLabel(".write_with_handler"); | 
					
						
							|  |  |  |             SaveReg("memhandler", "eax"); | 
					
						
							|  |  |  |             SaveReg("memhandler", "ebp"); | 
					
						
							|  |  |  |             WRITEPCTOMEM("pc");                     /* saves esi */ | 
					
						
							|  |  |  |             e("mov     [remaining], ecx\n"); | 
					
						
							|  |  |  |             SaveReg("memhandler", "edx");           /* save params */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             /* data, address */ | 
					
						
							|  |  |  |             if (!call_convention)                   /* stack-based */ | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 e("push edx\n"); | 
					
						
							|  |  |  |                 e("push ebx\n"); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             else                                    /* register-based */ | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 e("mov  eax, ebx\n"); | 
					
						
							|  |  |  |                 /* don't need: e("mov  edx, edx\n"); */ | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             e("call    dword [edi+"OFFSET_DATA_HANDLER"]\n");       | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (!call_convention) | 
					
						
							|  |  |  |                 e("add     esp, byte 8\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             RestoreReg("memhandler", "edx");        /* restore params */ | 
					
						
							|  |  |  |             e("mov     esi, [pc]\n"); | 
					
						
							|  |  |  |             e("mov     ecx, [remaining]\n");    /* this could have been changed */ | 
					
						
							|  |  |  |             RestoreReg("memhandler", "eax"); | 
					
						
							|  |  |  |             RestoreReg("memhandler", "ebp"); | 
					
						
							|  |  |  |             e("add     esi, ebp\n");            /* base+pc=pc pointer */ | 
					
						
							|  |  |  |             e("xor     edi, edi\n");            /* keep clear for fetch */ | 
					
						
							|  |  |  |             e("ret\n"); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else if (memmap_type == 1) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         for (i = 0; i < 3; i++) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             CacheAlign(); | 
					
						
							|  |  |  |             switch (i) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |             case 0: EmitLabel("WriteByte"); break; | 
					
						
							|  |  |  |             case 1: EmitLabel("WriteWord"); break; | 
					
						
							|  |  |  |             case 2: EmitLabel("WriteLong"); break; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             AddrClip("ebx"); | 
					
						
							|  |  |  |             SaveReg("memhandler", "eax"); | 
					
						
							|  |  |  |             SaveReg("memhandler", "ebp"); | 
					
						
							|  |  |  |             WRITEPCTOMEM("pc");                     /* saves esi */ | 
					
						
							|  |  |  |             e("mov     [remaining], ecx\n"); | 
					
						
							|  |  |  |             SaveReg("memhandler", "edx");           /* save params */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             /* data, address */ | 
					
						
							|  |  |  |             if (!call_convention)                   /* stack-based */ | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 e("push edx\n"); | 
					
						
							|  |  |  |                 e("push ebx\n"); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             else                                    /* register-based */ | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 e("mov  eax, ebx\n"); | 
					
						
							|  |  |  |                 /* don't need: e("mov  edx, edx\n"); */ | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             switch (i) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |             case 0: e("call dword [write_byte]\n"); break; | 
					
						
							|  |  |  |             case 1: e("call dword [write_word]\n"); break; | 
					
						
							|  |  |  |             case 2: e("call dword [write_long]\n"); break; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (!call_convention) | 
					
						
							|  |  |  |                 e("add     esp, byte 8\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             RestoreReg("memhandler", "edx");        /* restore params */ | 
					
						
							|  |  |  |             e("mov     esi, [pc]\n"); | 
					
						
							|  |  |  |             e("mov     ecx, [remaining]\n");    /* this could have been changed */ | 
					
						
							|  |  |  |             RestoreReg("memhandler", "eax"); | 
					
						
							|  |  |  |             RestoreReg("memhandler", "ebp"); | 
					
						
							|  |  |  |             e("add     esi, ebp\n");            /* base+pc=pc pointer */ | 
					
						
							|  |  |  |             e("xor     edi, edi\n");            /* keep clear for fetch */ | 
					
						
							|  |  |  |             e("ret\n"); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*****************************************************************************
 | 
					
						
							|  |  |  | * main() and Friends                                                        */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int FindV(char *option, int p, int h, int u, int argc, char **argv, int m) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     static int  t[128] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | 
					
						
							|  |  |  |                            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | 
					
						
							|  |  |  |                            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | 
					
						
							|  |  |  |                            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | 
					
						
							|  |  |  |                            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | 
					
						
							|  |  |  |                            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | 
					
						
							|  |  |  |                            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | 
					
						
							|  |  |  |                            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 | 
					
						
							|  |  |  |                          }; | 
					
						
							|  |  |  |     int         i; | 
					
						
							|  |  |  |     char        *c; | 
					
						
							|  |  |  |            | 
					
						
							|  |  |  |     if (m)  /* mark as touched */ | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if (m < 128) | 
					
						
							|  |  |  |             t[m] = 1; | 
					
						
							|  |  |  |         return 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (argc > 128) | 
					
						
							|  |  |  |         argc = 128;     /* maximum this function can handle is 128 */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (u)  /* find first untouched element */ | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         for (i = 1; i < argc; i++) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             if (!t[i])      /* 0 indicates untouched */ | 
					
						
							|  |  |  |                 return i; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (p)  /* find option and return integer value following it */ | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         for (i = 1; i < argc; i++) | 
					
						
							|  |  |  |         {         | 
					
						
							|  |  |  |             if (strcmp(argv[i], option) == 0)       /* found */ | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 if (i >= (argc - 1))        /* bounds! */ | 
					
						
							|  |  |  |                     return 0; | 
					
						
							|  |  |  |                 t[i + 1] = t[i] = 1;        /* touched */ | 
					
						
							|  |  |  |                 if (!h) | 
					
						
							|  |  |  |                     return atoi(argv[i + 1]); | 
					
						
							|  |  |  |                 else | 
					
						
							|  |  |  |                     return strtoul(argv[i + 1], &c, 16); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return 0;                       /* no match */ | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else    /* find option and return position  */     | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         for (i = 1; i < argc; i++) | 
					
						
							|  |  |  |         {         | 
					
						
							|  |  |  |             if (strcmp(argv[i], option) == 0) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 t[i] = 1; | 
					
						
							|  |  |  |                 return i;       /* found! return position */ | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         }                               | 
					
						
							|  |  |  |         return 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ShowHelp() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     printf("Make68K Version "VERSION" by Bart Trzynadlowski: Turbo68K Source Emitter\n"); | 
					
						
							|  |  |  |     printf("Usage:      make68k <outfile> [options]\n"); | 
					
						
							|  |  |  |     printf("Options:    -?,-h        Show this help text\n"); | 
					
						
							|  |  |  |     printf("            -mpu <type>  Processor to emulate [Default=68000]\n"); | 
					
						
							|  |  |  |     printf("            -addr <bits> Address bus width [Default=24]\n"); | 
					
						
							|  |  |  |     printf("            -illegal     Emulate illegal instruction exceptions [Default]\n"); | 
					
						
							|  |  |  |     printf("            -noillegal   Treat illegal instructions as errors\n"); | 
					
						
							|  |  |  |     printf("            -dummyread   Emulate 68000 dummy reads [Default]\n"); | 
					
						
							|  |  |  |     printf("            -nodummyread Do not emulate dummy reads\n"); | 
					
						
							|  |  |  |     printf("            -skip        Skip over idle loops\n"); | 
					
						
							|  |  |  |     printf("            -noskip      Do not skip over idle loops [Default]\n"); | 
					
						
							|  |  |  |     printf("            -brafetch    Update fetch pointer on Bcc, BRA, BSR, DBcc\n"); | 
					
						
							|  |  |  |     printf("            -nobrafetch  Do not update fetch pointer for branches [Default]\n"); | 
					
						
							|  |  |  |     printf("            -pcfetch     Special PC-relative read mode\n"); | 
					
						
							|  |  |  |     printf("            -nopcfetch   Use data regions for PC-relative reading [Default]\n"); | 
					
						
							|  |  |  |     printf("            -multiaddr   Address spaces for supervisor and user [Default]\n"); | 
					
						
							|  |  |  |     printf("            -singleaddr  Single address space for supervisor and user\n"); | 
					
						
							|  |  |  |     printf("            -defmap      Definable memory map arrays [Default]\n"); | 
					
						
							|  |  |  |     printf("            -handler     Single handlers for memory access\n"); | 
					
						
							|  |  |  |     printf("            -stackcall   Stack calling conventions [Default]\n"); | 
					
						
							|  |  |  |     printf("            -regcall     Register calling conventions\n"); | 
					
						
							|  |  |  |     printf("            -id <string> Add string to beginning of identifiers\n"); | 
					
						
							|  |  |  |     exit(0); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void SetAddrMask(int num_bits) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     addr_bits = num_bits; | 
					
						
							|  |  |  |     if (!num_bits) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         addr_mask = 0xffffff;   /* 24-bit is default address bus width */ | 
					
						
							|  |  |  |         addr_bits = 24; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |         addr_mask = (unsigned) pow(2, num_bits) - 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int main(int argc, char **argv) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     int     i, j, k, l, f; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifdef PROFILE
 | 
					
						
							|  |  |  |     for (i = 0; i < 512; i++)   prof[i] = NULL; | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (argc <= 1 || FindV("-?", 0, 0, 0, argc, argv, 0) || FindV("-h", 0, 0, 0, argc, argv, 0)) | 
					
						
							|  |  |  |         ShowHelp(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     mpu = FindV("-mpu", 1, 0, 0, argc, argv, 0); | 
					
						
							|  |  |  |     switch (mpu)    /* make sure a valid MPU type was specified */ | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |     case 0: | 
					
						
							|  |  |  |         mpu = 68000; | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     case 68000: | 
					
						
							|  |  |  |     case 68010: | 
					
						
							|  |  |  |         break; | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |         fprintf(stderr, "Make68K: Unknown or unsupported processor type: %d\n", mpu); | 
					
						
							|  |  |  |         exit(1); | 
					
						
							|  |  |  |     }         | 
					
						
							|  |  |  |     SetAddrMask(FindV("-addr", 1, 0, 0, argc, argv, 0)); | 
					
						
							|  |  |  |     if (FindV("-illegal", 0, 0, 0, argc, argv, 0))      illegal = 1; | 
					
						
							|  |  |  |     if (FindV("-noillegal", 0, 0, 0, argc, argv, 0))    illegal = 0; | 
					
						
							|  |  |  |     if (FindV("-dummyread", 0, 0, 0, argc, argv, 0))    dummyread = 1; | 
					
						
							|  |  |  |     if (FindV("-nodummyread", 0, 0, 0, argc, argv, 0))  dummyread = 0; | 
					
						
							|  |  |  |     if (FindV("-skip", 0, 0, 0, argc, argv, 0))         skip = 1; | 
					
						
							|  |  |  |     if (FindV("-noskip", 0, 0, 0, argc, argv, 0))       skip = 0; | 
					
						
							|  |  |  |     if (FindV("-brafetch", 0, 0, 0, argc, argv, 0))     brafetch = 1; | 
					
						
							|  |  |  |     if (FindV("-nobrafetch", 0, 0, 0, argc, argv, 0))   brafetch = 0; | 
					
						
							|  |  |  |     if (FindV("-pcfetch", 0, 0, 0, argc, argv, 0))      pcfetch = 1; | 
					
						
							|  |  |  |     if (FindV("-nopcfetch", 0, 0, 0, argc, argv, 0))    pcfetch = 0; | 
					
						
							|  |  |  |     if (FindV("-multiaddr", 0, 0, 0, argc, argv, 0))    multiaddr = 1; | 
					
						
							|  |  |  |     if (FindV("-singleaddr", 0, 0, 0, argc, argv, 0))   multiaddr = 0; | 
					
						
							|  |  |  |     if (FindV("-defmap", 0, 0, 0, argc, argv, 0))       memmap_type = 0; | 
					
						
							|  |  |  |     if (FindV("-handler", 0, 0, 0, argc, argv, 0))      memmap_type = 1; | 
					
						
							|  |  |  |     if (FindV("-stackcall", 0, 0, 0, argc, argv, 0))    call_convention = 0; | 
					
						
							|  |  |  |     if (FindV("-regcall", 0, 0, 0, argc, argv, 0))      call_convention = 1; | 
					
						
							| 
									
										
										
										
											2011-06-27 23:10:51 +00:00
										 |  |  | 	if (FindV("-debug", 0, 0, 0, argc, argv, 0))        debug = 1; | 
					
						
							| 
									
										
										
										
											2011-04-24 01:14:00 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if ((i = FindV("-id", 0, 0, 0, argc, argv, 0))) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if ((i + 1) < argc) /* make sure we're within argv[] bounds */ | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             if (strlen(argv[i + 1]) > 16) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 fprintf(stderr, "Make68K: Identifier string is too long (maximum is 16 characters)\n"); | 
					
						
							|  |  |  |                 exit(1); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             strncpy(id, argv[i + 1], 16); | 
					
						
							|  |  |  |             FindV(NULL, 0, 0, 0, argc, argv, i + 1); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     }     | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     if (!(f = FindV(NULL, 0, 0, 1, argc, argv, 0))) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         fprintf(stderr, "Make68K: No output file specified\n"); | 
					
						
							|  |  |  |         exit(1); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if ((fp = fopen(argv[f], "w")) == NULL) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         fprintf(stderr, "Make68K: Failed to open file for writing: %s\n", argv[f]); | 
					
						
							|  |  |  |         exit(1); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for (i = 0; i < 65536; i++) decoded[i] = 0; | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |     printf("Make68K Version "VERSION" by Bart Trzynadlowski: Turbo68K Source Emitter\n"); | 
					
						
							|  |  |  |     printf("\n"); | 
					
						
							|  |  |  |     printf("Emitting file: %s\n", argv[f]); | 
					
						
							|  |  |  |     printf("Configuration:\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     e(";\n"); | 
					
						
							|  |  |  |     e("; Turbo68K Version "VERSION": Motorola 680X0 emulator\n"); | 
					
						
							|  |  |  |     e("; Copyright 2000-2002 Bart Trzynadlowski, see \"README.TXT\" for terms of use\n"); | 
					
						
							|  |  |  |     e("; Assemble with NASM (http://www.web-sites.co.uk/nasm) only\n"); | 
					
						
							|  |  |  |     e(";\n"); | 
					
						
							|  |  |  |     e("; Configuration:\n"); | 
					
						
							|  |  |  |     printf("- %d processor\n", mpu); | 
					
						
							|  |  |  |     e("; - %d processor\n", mpu); | 
					
						
							|  |  |  |     printf("- %d-bit addresses\n", addr_bits); | 
					
						
							|  |  |  |     e("; - %d-bit addresses\n", addr_bits); | 
					
						
							|  |  |  |     printf("- %s\n", illegal ? "Illegal instruction, Line 1010, and Line 1111 exceptions" : "Illegal instructions reported as errors"); | 
					
						
							|  |  |  |     e("; - %s\n", illegal ? "Illegal instruction, Line 1010, and Line 1111 exceptions" : "Illegal instructions reported as errors"); | 
					
						
							|  |  |  |     if (mpu == 68000) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         printf("- Dummy reads %s\n", dummyread ? "emulated" : "not emulated"); | 
					
						
							|  |  |  |         e("; - Dummy reads %s\n", dummyread ? "emulated" : "not emulated"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     printf("- Idle loop skipping %s\n", skip ? "enabled" : "disabled"); | 
					
						
							|  |  |  |     e("; - Idle loop skipping %s\n", skip ? "enabled" : "disabled"); | 
					
						
							|  |  |  |     printf("- Fetch pointer%supdated for Bcc, BRA, BSR, and DBcc\n", brafetch ? " " : " not "); | 
					
						
							|  |  |  |     e("; - Fetch pointer%supdated for Bcc, BRA, BSR, and DBcc\n", brafetch ? " " : " not "); | 
					
						
							|  |  |  |     printf("- %s regions used for PC-relative reading\n", pcfetch ? "Special PC fetch" : "Data"); | 
					
						
							|  |  |  |     e("; - %s regions used for PC-relative reading\n", pcfetch ? "Special PC fetch" : "Data"); | 
					
						
							|  |  |  |     printf("- %s for supervisor and user\n", multiaddr ? "Separate address spaces" : "Single address space"); | 
					
						
							|  |  |  |     e("; - %s for supervisor and user\n", multiaddr ? "Separate address spaces" : "Single address space"); | 
					
						
							|  |  |  |     switch (memmap_type) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |     case 0: printf("- Definable memory map arrays\n"); | 
					
						
							|  |  |  |             e("; - Definable memory map arrays\n");             | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |     case 1: printf("- Single memory handlers\n"); | 
					
						
							|  |  |  |             e("; - Single memory handlers\n"); | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |     case 2: printf("- Low-level memory handlers\n"); | 
					
						
							|  |  |  |             e("; - Low-level memory handlers\n"); | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     printf("- %s calling conventions\n", call_convention ? "Register" : "Stack"); | 
					
						
							|  |  |  |     e("; - %s calling conventions\n", call_convention ? "Register" : "Stack"); | 
					
						
							|  |  |  |     if (id[0] != '\0') | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         printf("- Identifers start with: %s\n", id); | 
					
						
							|  |  |  |         e("; - Identifiers start with: %s\n", id); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2011-06-27 23:10:51 +00:00
										 |  |  | 	if (debug) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		printf("- Debug function called at every instruction\n"); | 
					
						
							|  |  |  | 		e("; - Debug function called at every instruction\n"); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2011-04-24 01:14:00 +00:00
										 |  |  |     e(";\n"); | 
					
						
							|  |  |  |     printf("\n"); | 
					
						
							|  |  |  |     e("bits 32\n"); | 
					
						
							|  |  |  |     e("section .data\n"); | 
					
						
							|  |  |  |     EmitData(); | 
					
						
							|  |  |  |     e("section .text\n"); | 
					
						
							|  |  |  |     EmitCode(); | 
					
						
							|  |  |  |     printf("Generating instruction handlers:\n"); | 
					
						
							|  |  |  |     EmitInstructions(); | 
					
						
							|  |  |  |     EmitExceptions(); | 
					
						
							|  |  |  |     e("section .bss\n"); | 
					
						
							|  |  |  |     CacheAlign(); | 
					
						
							|  |  |  |     e("jmptab       resd 65536\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |      * Emit the compressed jump table | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * Format: | 
					
						
							|  |  |  |      * dw 0x8000 + #    ; # of handler addresses follow, each repeated 8 times | 
					
						
							|  |  |  |      * ... dd # ...     ; handler addresses... | 
					
						
							|  |  |  |      * dw 0xc000 + #    ; # of handler addresses follow, each repeated 1 time | 
					
						
							|  |  |  |      * ... dd # ...     ; handler addresses... | 
					
						
							|  |  |  |      * dw 0x0000 + #    ; repeat following address handler # times | 
					
						
							|  |  |  |      * dd #             ; handler address to repeat | 
					
						
							|  |  |  |      * dd -1            ; terminator | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     e("section .data\n"); | 
					
						
							|  |  |  |     Align(4); | 
					
						
							|  |  |  |     e("compressed_jmptab:\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     i = 0; | 
					
						
							|  |  |  |     j = 0; | 
					
						
							|  |  |  |     while (i < 65536) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if (!decoded[i])        /* invalid */ | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             for (i = i; decoded[i] == 0 && i < 65536; i++)  j++; | 
					
						
							|  |  |  |             e("dw 0x0000 + %d\n", j); | 
					
						
							|  |  |  |             e("dd I_Invalid\n"); | 
					
						
							|  |  |  |             j = 0; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             if (decoded[i] == 8)    /* if more handlers*8, make a big block */ | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 k = 0; | 
					
						
							|  |  |  |                 l = i;  /* save opcode # */ | 
					
						
							|  |  |  |                 while (decoded[i] == 8) | 
					
						
							|  |  |  |                 { | 
					
						
							|  |  |  |                     i += decoded[i]; | 
					
						
							|  |  |  |                     k++; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 e("dw 0x8000 + %d\n", k);   /* # of handlers w/ 8 reps */ | 
					
						
							|  |  |  |                 while (k != 0)              /* list handlers */ | 
					
						
							|  |  |  |                 { | 
					
						
							|  |  |  |                     e("dd I%04X\n", l); | 
					
						
							|  |  |  |                     l += decoded[l]; | 
					
						
							|  |  |  |                     k--; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             if (decoded[i] == 1)    /* if more handlers*1, make a big block */ | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 k = 0; | 
					
						
							|  |  |  |                 l = i;  /* save opcode # */ | 
					
						
							|  |  |  |                 while (decoded[i] == 1) | 
					
						
							|  |  |  |                 { | 
					
						
							|  |  |  |                     i += decoded[i]; | 
					
						
							|  |  |  |                     k++; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 e("dw 0xc000 + %d\n", k);   /* # of handlers w/ 1 reps */ | 
					
						
							|  |  |  |                 while (k != 0)              /* list handlers */ | 
					
						
							|  |  |  |                 { | 
					
						
							|  |  |  |                     e("dd I%04X\n", l); | 
					
						
							|  |  |  |                     l += decoded[l]; | 
					
						
							|  |  |  |                     k--; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             }    | 
					
						
							|  |  |  |             else if (decoded[i] == 0)       /* invalid instruction */ | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 e("dw 1\n"); | 
					
						
							|  |  |  |                 e("dd I_Invalid\n"); | 
					
						
							|  |  |  |                 i++; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             else                            /* misc. */ | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 e("dw %d\n", decoded[i]);   /* # of valids */ | 
					
						
							|  |  |  |                 e("dd I%04X\n", i);         /* opcode */ | 
					
						
							|  |  |  |                 i += decoded[i]; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     }             | 
					
						
							|  |  |  |     e("dd -1\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |      * Emit profile data | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * Step 1: Output the names of the instructions. | 
					
						
							|  |  |  |      * Step 2: Output the usage count variables and pointers to the strings. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifdef PROFILE
 | 
					
						
							|  |  |  |     for (i = 0; prof[i] != NULL && i < 512; i++) | 
					
						
							|  |  |  |         e("str%s db \"%s\",0\n", prof[i], prof[i]); | 
					
						
							|  |  |  |     e("global _t68k_prof\n"); | 
					
						
							|  |  |  |     e("_t68k_prof: dd begin_t68k_prof\n"); | 
					
						
							|  |  |  |     e("begin_t68k_prof:\n"); | 
					
						
							|  |  |  |     for (i = 0; prof[i] != NULL && i < 512; i++) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         e("prof%s dd 0, str%s\n", prof[i], prof[i]); | 
					
						
							|  |  |  |         free(prof[i]); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     e("dd -1, -1\n"); | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     fclose(fp); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     printf("Total:\t%d\n", num_handlers); | 
					
						
							|  |  |  |     printf("\nSee \"README.TXT\" for terms of use and documentation!\n"); | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Developers' Notes: A Guide to the Guts of Turbo68K ;) | 
					
						
							|  |  |  |  * ----------------------------------------------------- | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Register Usage: | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * EAX: ****************NZ*****C*******V | 
					
						
							|  |  |  |  *      AH: NZ*****C    AL: *******V | 
					
						
							|  |  |  |  * EBX: Address | 
					
						
							|  |  |  |  * ECX: Cycle counter | 
					
						
							|  |  |  |  * EDX: Data | 
					
						
							|  |  |  |  * ESI: Current fetch (PC) pointer | 
					
						
							|  |  |  |  * EDI: Instruction fetch/decoding (keep upper 16 bits clear!). At the | 
					
						
							|  |  |  |  *      beginning of any instruction handler, contains opcode in lower 16 bits | 
					
						
							|  |  |  |  * EBP: Pointer to base of PC region. May be below the base if the unused PC | 
					
						
							|  |  |  |  *      bits are non-zero | 
					
						
							|  |  |  |  * --- | 
					
						
							|  |  |  |  * MMX optimizations are unsupported -- DO NOT USE THEM! They happen to slow | 
					
						
							|  |  |  |  * things down | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * MMX Register Usage: | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * MM0:     Saved EAX (memhandler_eax) | 
					
						
							|  |  |  |  * MM1:     Saved EBX (memhandler_ebx) | 
					
						
							|  |  |  |  * MM2:     Saved EBP (memhandler_ebp) | 
					
						
							|  |  |  |  * MM3:     Saved EDX (run_edx) | 
					
						
							|  |  |  |  * MM4:     Saved ESI (run_esi) | 
					
						
							|  |  |  |  * MM5:     Saved EDI (run_edi) | 
					
						
							|  |  |  |  * MM6,MM7: Misc. usage | 
					
						
							|  |  |  |  * --- | 
					
						
							|  |  |  |  * Format of context.intr[]: | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * intr[0-6] = Interrupt levels 1-7, elements contain the vector #, if 0 then | 
					
						
							|  |  |  |  *             no interrupt is pending at this level | 
					
						
							|  |  |  |  * intr[7] = Number of interrupts pending (set to 0 at reset) | 
					
						
							|  |  |  |  * --- | 
					
						
							|  |  |  |  * Format of context.status: | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * 0000 0000 0000 0000 0000 0000 0000 0ISR | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * I=Interrupt; 1=interrupts being processed, 0=not | 
					
						
							|  |  |  |  * S=Stop; 1=68K is stopped (STOP instruction), 0=not | 
					
						
							|  |  |  |  * R=Running; 1=68K is running, 0=not | 
					
						
							|  |  |  |  * --- | 
					
						
							|  |  |  |  * Format of decoded[]: | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * [0] = 1: 2 opcode 0 handlers | 
					
						
							|  |  |  |  * [1] = 0: see above.. this is unused | 
					
						
							|  |  |  |  * [2] = next handler... (0 + 2) | 
					
						
							|  |  |  |  * --- | 
					
						
							|  |  |  |  * SR values obtained from instructions are ANDed with 0xa71f to mask out | 
					
						
							|  |  |  |  * unused bits. CCR values are ANDed with 0x1f to mask out the unused bits. | 
					
						
							|  |  |  |  * This is how a real 68K behaves. | 
					
						
							|  |  |  |  * --- | 
					
						
							|  |  |  |  * Memory mapping types: The low-level handler mode code is present, but not | 
					
						
							|  |  |  |  * accessible. I decided to forbid using it because of performance problems. | 
					
						
							|  |  |  |  * --- | 
					
						
							|  |  |  |  * The unused address bits of the PC are preserved. They are only lost if the | 
					
						
							|  |  |  |  * PC goes out of bounds. | 
					
						
							|  |  |  |  */ |