/* Intermediate 68000 Assembly Language String Functions This file contains the functions necessary to convert the intermediate 68000 assembly language instructions to a text string. The public functions are unsigned CchSzOpcode(piasm, psz, opt) This function writes the opcode indicated by the specified IASM structure to the string pointed at by psz using the specified options. piasm pointer to the IASM structure to be written psz pointer to the destination string for the opcode opt formatting options, one of the following optDEFAULT default formating optUPPER opcode is upper-cased returns the number of characters placed in the string, not including the terminating null character unsigned CchSzOper(poper, psz, opt) This function writes the operand indicated by the specified OPER structure to the string pointed at by psz using the specified options. poper pointer to the OPER structure to be written psz pointer to the destination string for the operand opt formatting options, one of the following optDEFAULT default formating optUPPER operand is upper-cased optALTREGLIST register lists written as "" optRELLABEL labels written as ".+/-displacement" returns the number of characters placed in the string, not including the terminating null character */ #include #include #include "iasm68.h" #ifdef TRAP_NAMES #include "trpd.h" extern TRPD rgtrpd[]; #endif // Internal constants #define iszAREG 0 #define iszDREG 1 #define iszFREG 2 #define iszWORD 3 #define iszLONG 4 #define iszPC 5 #define bitA0 8 #define bitFPcr 24 #define chNULL '\0' #define chDASH '-' #define chSLASH '/' #define chCOMMA ',' #define chLFBRACKET '<' #define chRTBRACKET '>' #define chLFPAREN '(' #define chCOLON ':' // Prototypes for internal functions unsigned CchSzDispLabel(char *, long, char *); unsigned CchSzRegList(char *, long, short); unsigned CchSzRegFromBit(char *, unsigned, short); // Opcode string descriptor structure typedef struct _OPSD { const char *sz; char fmt; } OPSD; #define OPCODE(op, sz, fmt) sz, fmt, const OPSD mpopopsd[] = { #include "iasmop.h" }; unsigned CchSzOpcode( IASM *piasm, char *psz, short opt) { /* This function writes the opcode indicated by the specified IASM structure to the string pointed at by psz using the specified options. The number of characters placed in the string, not including the terminating null character, is returned. */ static const char * const mpsizesz[] = { ".b", ".w", ".l", "" }; static const char * const mpdsizesz[] = { ".s", ".w", ".l", "" }; static const char * const mpfpsizesz[] = { ".b", ".w", ".l", "", ".s", ".d", ".x", ".p" }; /* Write the basic opcode to the string. */ #ifdef TRAP_NAMES if (piasm->op >= opMAX) { strcpy(psz, rgtrpd[piasm->op - opMAX].sztrp); } else #endif { strcpy(psz, mpopopsd[piasm->op].sz); } switch (mpopopsd[piasm->op].fmt) { case fmtSIZE: /* Append a size suffix if necessary. */ strcat(psz, mpsizesz[piasm->size]); break; case fmtDSIZE: /* Append a displacement size suffix if necessary. */ strcat(psz, mpdsizesz[piasm->size]); break; case fmtFPSIZE: /* Append a floating point size suffix if necessary. */ strcat(psz, mpfpsizesz[piasm->size]); break; } /* If the upper case option was specified, then change the opcode to upper case. */ if ((opt & optUPPER) != 0) { _strupr(psz); } /* Return the length of the string. */ return strlen(psz); } unsigned CchSzOper( OPER *poper, char *psz, short opt) { /* This function writes the operand indicated by the specified OPER structure to the string pointed at by psz using the specified options. The number of characters placed in the string, not including the terminating null character, is returned. */ static const char * const rgszLower[] = { "a", "d", "fp", "w", "l", "pc" }; static const char * const rgszUpper[] = { "A", "D", "FP", "W", "L", "PC" }; static const char * const mpsregsz[] = { "sr", "fpiar", "fpsr", "ccr", "fpcr", "usp" }; static const char szUnknown[] = "???"; OPER oper; const char * const *prgsz; unsigned cch; /* Get a pointer to either the array of lower case or upper case constants depending on the options specified. */ prgsz = (opt & optUPPER) != 0 ? &rgszUpper[0] : &rgszLower[0]; switch (poper->ea) { case eaDREG: /* Write a data register string, D0 to D7. */ return sprintf(psz, "%s%d", prgsz[iszDREG], poper->reg); case eaAREG: /* Write an address register string, A0 to A7. */ return sprintf(psz, "%s%d", prgsz[iszAREG], poper->reg); case eaFREG: /* Write a floating point register string, FP0 to FP7. */ return sprintf(psz, "%s%d", prgsz[iszFREG], poper->reg); case eaINDIRECT: /* Write an indirect addressing string, (An). */ return sprintf(psz, "(%s%d)", prgsz[iszAREG], poper->reg); case eaPOSTINC: /* Write a post-increment addressing string, (An)+. */ return sprintf(psz, "(%s%d)+", prgsz[iszAREG], poper->reg); case eaPREDEC: /* Write a pre-decrement addressing string, -(An). */ return sprintf(psz, "-(%s%d)", prgsz[iszAREG], poper->reg); case eaDISP: /* Write a displacement addressing string, d(An). */ cch = CchSzDispLabel(psz, poper->disp, poper->szLabel); return cch + sprintf(psz + cch, "(%s%d)", prgsz[iszAREG], poper->reg); case eaINDEX: /* Write an indexed addressing string, d(An,Rn.X). */ cch = CchSzDispLabel(psz, poper->disp, poper->szLabel); return cch + sprintf(psz + cch, "(%s%d,%s%d.%s)", prgsz[iszAREG], poper->reg, prgsz[poper->fARegIndex ? iszAREG : iszDREG], poper->reg2, prgsz[poper->fLongIndex ? iszLONG : iszWORD]); case eaSHORTADDR: /* Write a short address string, xxx.w. */ return sprintf(psz, "%d.%s", (short)poper->val.w, prgsz[iszWORD]); case eaLONGADDR: /* Write a long address string, xxx.l. */ return sprintf(psz, "%ld.%s", poper->val.l, prgsz[iszLONG]); case eaPCDISP: /* Write a PC-relative displacement addressing string, d(PC). */ cch = CchSzDispLabel(psz, poper->disp, poper->szLabel); if (poper->szLabel == (char *)NULL) { /* This string should look like "d(PC)". */ return cch + sprintf(psz + cch, "(%s)", prgsz[iszPC]); } else { /* This string should look like "label+/d", which has already been written. */ return cch; } case eaPCINDEX: /* Write a PC-relative indexed addressing string, d(PC,Rn.X). */ cch = CchSzDispLabel(psz, poper->disp, poper->szLabel); if (poper->szLabel == (char *)NULL) { /* This string should look like "d(PC,..." */ cch += sprintf(psz + cch, "(%s,", prgsz[iszPC]); } else { /* This string should look like "label+/d(...". */ *(psz + cch++) = chLFPAREN; } /* Write "Rn.X)" to the string. */ return cch + sprintf(psz + cch, "%s%d.%s)", prgsz[poper->fARegIndex ? iszAREG : iszDREG], poper->reg2, prgsz[poper->fLongIndex ? iszLONG : iszWORD]); case eaBYTEIMMED: /* Write a byte of immediate data, #xxx. */ return sprintf(psz, "#%d", (short)poper->val.b); case eaWORDIMMED: /* Write a word of immediate data, #xxx. */ return sprintf(psz, "#%d", poper->val.w); case eaLONGIMMED: /* Write a long of immediate data, #xxx. */ return sprintf(psz, "#%ld", poper->val.l); #if 0 case eaSINGLEIMMED: /* Write a single precision immediate data, #xxx. */ return sprintf(psz, "#%g", poper->val.s); case eaDOUBLEIMMED: /* Write a double precision immediate data, #xxx. */ return sprintf(psz, "#%lg", poper->val.d); case eaEXTENDEDIMMED: /* Write an extended precision immediate data, #xxx. */ return sprintf(psz, "#%Lg", poper->val.x); #endif case eaSYMIMMED: /* Write a symbolic immediate data, #sym. */ cch = sprintf(psz, "#"); return cch + CchSzDispLabel(psz + cch, poper->disp, poper->szLabel); case eaLABEL: /* If there is a label string, then use it. */ if (poper->szLabel != (char *)NULL) { return CchSzDispLabel(psz, poper->disp, poper->szLabel); /* If this is a relative label, write ".+/-displacement". */ } else if ((opt & optRELLABEL) != 0) { return sprintf(psz, ".%+ld", poper->disp); /* Otherwise, simply write the destination. */ } else { return sprintf(psz, "$%lx", poper->val.pc + poper->disp); } break; case eaSREG: /* Write the special register string. */ strcpy(psz, mpsregsz[poper->reg]); /* If the upper case option was specified, then change the special register to upper case. */ if ((opt & optUPPER) != 0) { _strupr(psz); } /* Return the length of the string. */ return strlen(psz); case eaREGLIST: /* Write the register list. */ return CchSzRegList(psz, poper->val.rl, opt); case eaDREGPAIR: /* Write out the register pair, Dn:Dm. */ oper.ea = eaDREG; oper.reg = poper->reg; cch = CchSzOper(&oper, psz, opt); psz[cch++] = chCOLON; oper.reg = poper->reg2; cch += CchSzOper(&oper, psz + cch, opt); return cch; case eaFREGPAIR: /* Write out the register pair, FPn:FPm. */ oper.ea = eaFREG; oper.reg = poper->reg; cch = CchSzOper(&oper, psz, opt); psz[cch++] = chCOLON; oper.reg = poper->reg2; cch += CchSzOper(&oper, psz + cch, opt); return cch; case eaNULL: default: /* Write a string to inidcate that we don't understand this operand. */ strcpy(psz, szUnknown); return sizeof(szUnknown) - 1; } } unsigned CchSzDispLabel( char *psz, long disp, char *szLabel) { /* This function writes a displacement-label string to the string pointed at by psz. Either "label+/-disp", "label", or "disp" is written depending on the values of szLabel and disp. The number of characters placed in the string, not including the terminating null character, is returned. */ unsigned cch; if (szLabel != (char *)NULL) { /* If there is a label string, write it. */ cch = sprintf(psz, "%s", szLabel); if (disp != 0L) { /* Write simply "label+/-disp". */ cch += sprintf(psz + cch, "%+ld", disp); } } else { /* Otherwise, simply write "disp". */ cch = sprintf(psz, "%ld", disp); } return cch; } unsigned CchSzRegList( char *psz, long reglist, short opt) { /* This function writes the register list indicated by the reglist to the string pointed at by psz using the specified options. The register list has the form "An/An-An/Dn/Dn-Dn". The number of characters placed in the string, not including the terminating null character, is returned. */ int bit = 0; int bitFirst; int cch; int cchsz = 0; char chSeparate; /* The alternate register list is given by */ if ((opt & optALTREGLIST) != 0) { *psz++ = chLFBRACKET; cchsz++; chSeparate = chCOMMA; } else { chSeparate = chSLASH; } /* Continue looping while there are registers left in the list. */ while (reglist != 0) { /* Find the first bit set in the register list. */ while ((reglist & 1) == 0) { reglist >>= 1; bit++; } /* Put the name of this register into the string. */ cch = CchSzRegFromBit(psz, bitFirst = bit, opt); cchsz += cch; psz += cch; /* If this is the alternate form then advance to the next register. */ if ((opt & optALTREGLIST) != 0) { reglist >>= 1; bit++; /* We are writing a standard register list. */ } else { /* Find the next bit not set in the register list. */ while ((reglist & 1) != 0) { reglist >>= 1; /* Stop looking if we cross the data register/address register boundary or we are in the midst of the floating point control register. */ if (++bit == bitA0 || bit >= bitFPcr) { break; } } /* If there is more than one consecutive register, then write Rn-Rn. */ if (bit != bitFirst + 1) { *psz++ = chDASH; cch = CchSzRegFromBit(psz, bit - 1, opt); cchsz += cch + 1; psz += cch; } } /* Put out a separator if there is any more registers to list. */ if (reglist != 0) { *psz++ = chSeparate; cchsz++; } } /* Put a closing bracket on the alternate register list. */ if ((opt & optALTREGLIST) != 0) { *psz++ = chRTBRACKET; cchsz++; } /* Put a null on the end of the string. */ *psz = chNULL; return cchsz; } unsigned CchSzRegFromBit( char *psz, unsigned bit, short opt) { /* This function writes the name of the register indicated by bit in the string psz. The bit is pulled from a register list where 0 to 7 correspond to data registers 0 to 7, 8 to 15 correspond to address registers 0 to 7, 16 to 23 correspond to floating point registers 0 to 7, and bits 24, 25, and 26 correspond to FPIAR, FPSR, and FPCR. The number of characters placed in the string, not including the terminating null character, is returned. */ OPER oper; /* Build an OPER structure and call CchSzFromOper. */ if (bit >= bitFPcr) { oper.ea = eaSREG; oper.reg = 1 << (bit - bitFPcr); } else { oper.ea = (bit & 0x10) != 0 ? eaFREG : (bit & 0x08) != 0 ? eaAREG : eaDREG; oper.reg = bit & 0x07; } return CchSzOper(&oper, psz, opt); }