File:  [Repository ATC2] / ADD_ver_10 / Source Code / Source Files / Desensambladorx86IA16.c
Revision 1.2: download - view: text, annotated - select for diffs
Tue Feb 28 14:54:21 2006 UTC (18 years, 8 months ago) by rico
Branches: MAIN
CVS tags: HEAD
*** empty log message ***

/********************************************************************/
/*  Desensambladorx86IA16.c                                         */
/*                                                                  */
/*                                                                  */
/*  Copyright (c) 1997-2006 Rafael Rico      (rafael.rico@uah.es)   */
/*                                                                  */
/*  Este fichero forma parte de ADD                                 */
/*  (Analizador de Dependencias de Datos)                           */
/*  Version 5.10.                                                   */
/*                                                                  */
/*                                                                  */
/*  ADD es software libre. Puede redistribuirlo y/o modificarlo     */
/*  bajo los términos de la Licencia Pública General de GNU         */
/*  según es publicada por la Free Software Foundation, bien bajo   */
/*  la versión 2 de dicha Licencia o bien (según su elección)       */
/*  bajo cualquier versión posterior.                               */
/*                                                                  */
/*  ADD se distribuye con la esperanza de que sea útil,             */
/*  pero SIN NINGUNA GARANTÍA, incluso sin la garantía MERCANTIL    */
/*  implícita y sin garantizar la CONVENIENCIA PARA UN PROPÓSITO    */
/*  PARTICULAR. Véase la Licencia Pública General de GNU para       */
/*  más detalles.                                                   */
/*                                                                  */
/*  Debería haber recibido una copia de la Licencia Pública General */
/*  junto con ADD. Si no ha sido así, escriba a la Free Software    */
/*  Foundation, Inc., 51 Franklin St, Fifth Floor,                  */
/*  Boston, MA  02110-1301  EEUU.                                   */
/*                                                                  */
/*  -------------------------- Historia --------------------------- */
/*                                                                  */
/*  $Id: Desensambladorx86IA16.c,v 1.2 2006/02/28 14:54:21 rico Exp $                                                            */
/*                                                                  */
/*  Revisión 1.2. 01/2006                                           */
/*  Se añade la licencia GPL y documentación en estilo Javadoc      */
/*                                                                  */
/*  Revisión 1.1. 09/2005                                           */
/*  Versión inicial                                                 */
/*                                                                  */
/********************************************************************/

/******************************************************************************/
/* MÓDULO: DesensambladorX86IA16.c                                            */
/*                                                                            */
/* Este módulo determina el nemónico, los operandos y la longitud del         */
/* formato a partir de una cadena de bytes del código binario del ejecutable. */
/* - El nemónico depende del código de operación y en casos excepcionales     */
/* del 2º byte.                                                               */
/* - Los operandos dependen del modo de direccionamiento (a través del código */
/* de operación) y de los bytes del formato.                                  */
/******************************************************************************/
/* Fecha: 29 de junio de 2005                                                 */
/******************************************************************************/


#include <stdio.h>
#include <string.h>

#include "defines.h"
#include "tipos.h"

/* tipos de formatos y modos de direccionamiento */
#define SINOPERANDOS 0  /* formato de 1 byte sin operandos */
#define PREFIJOS 1      /* formato de 1 byte sin operandos que es un prefijo */
#define REGPALABRA 2    /* formato de 1 byte: 1 operando registro palabra */
#define REGSEGMENTO 3   /* formato de 1 byte: 1 operando reg. segmento */
#define REGMEM 4        /* hasta 4 bytes; 1 operando reg/mem */
#define INMED8 5        /* formato de 2 bytes: 1 operando inm8 */
#define INMED16 6       /* formato de 3 bytes: 1 operando inm16 */
#define SALTO8 7        /* formato de 2 bytes: 1 operando: relativo IP 8bits */
#define SALTO16 8       /* formato de 3 bytes: 1 operando: relativo IP 16bits */
#define BASEOFFSET 9    /* formato de 5 bytes: 1 op: BASE:OFFSET (CALL y JMP) */
#define REGULAR 10      /* hasta 4 bytes; 2 operandos reg/mem -> reg/mem */
#define INMEDTOAX 11    /* hasta 3 bytes; 2 operandos inm -> acc */
#define INMEDTOREGMEM 12   /* hasta 6 bytes; 2 operandos inm -> reg/mem */
#define MOVMEMAX 13     /* formato de 3 bytes; 2 op LOAD/STORE mem-AX */
#define MOVSEGMTO 14    /* hasta 4 bytes; 2 op MOV entre reg/mem y reg. seg. */
#define MOVINMEDTOREG 15   /* hasta 3 bytes; 2 operandos MOV inm -> registro */
#define DESPLAZAMIENTO 16  /* hasta 4 bytes; 2 op reg/mem y contador (1 o CL) */
#define ENTRADA_SALIDA 17  /* hasta 2 bytes: 2 operandos: acc y DX o inm8 */


void OperandoRegistro(char w, char codigo, char *registro)
{
    char *registrosL[] = {"AL", "CL", "DL", "BL", "AH", "CH", "DH", "BH"};
    char *registrosX[] = {"AX", "CX", "DX", "BX", "SP", "BP", "SI", "DI"};

    switch(w)
    {
        case 0:
        sprintf(registro, registrosL[codigo]);
        break;

        case 1:
        sprintf(registro, registrosX[codigo]);
        break;
    }
}

void OperandoRegSeg(char codigo, char *registro)
{
    char *regSEG[] = {"ES", "CS", "SS", "DS"};

    sprintf(registro, regSEG[codigo]);
}

void OperandoMemoria(char codigo, char *memoria)
{
    /* char *direfectiva[] = {"[BX][SI]", "[BX][DI]", "[BP][SI]", "[BP][DI]",
                        "[SI]", "[DI]", "[BP]", "[BX]"}; */
    /* cambio los identificadores de las ubicaciones de memoria para simplificar el análisis */
    char *direfectiva[] = {"[BXSI]", "[BXDI]", "[BPSI]", "[BPDI]",
                        "[SI]", "[DI]", "[BP]", "[BX]"};

    sprintf(memoria, direfectiva[codigo]);
}

void OperandoRM(char w, char mod, char r_m, unsigned char byteL, unsigned char byteH, char *registro_memoria, char *l)
{
    char desplazamiento[5];

    switch(mod)
    {
        case 3:        /* el operando es un registro */
        OperandoRegistro(w, r_m, registro_memoria);    *l=0;
        break;

        case 0:
        /* el operando es memoria sin desplazamiento */
        if(r_m!=6) {OperandoMemoria(r_m, registro_memoria);    *l=0;}
        /* el operando es una dirección absoluta de memoria */
        else {sprintf(registro_memoria, "[%02X%02X]", byteH, byteL); *l=2;}
        break;

        case 1:        /* el operando es memoria con desplazamiento 8 */
        OperandoMemoria(r_m, registro_memoria);
        sprintf(desplazamiento, "%02X", byteL);    *l=1;
        strcat(registro_memoria, desplazamiento);
        break;

        case 2:        /* el operando es memoria con desplazamiento 16 */
        OperandoMemoria(r_m, registro_memoria);
        sprintf(desplazamiento, "%02X%02X", byteH, byteL); *l=2;
        strcat(registro_memoria, desplazamiento);
        break;
    }
}


void DecodificarInstruccion086(unsigned char formato[6], struct desensamblado *instruccion)
{
    char *saltos_cc[] = {"JO", "JNO", "JB/JNAE", "JNB/JAE", "JE/JZ",
                 "JNE/JNZ", "JBE/JNA", "JNBE/JA", "JS", "JNS",
                 "JP/JPE", "JNP/JPO", "JL/JNGE", "JNL/JGE",
                 "JLE/JNG", "JNLE/JG"};
    char *tablainmediatos[] = {"ADD", "OR", "ADC", "SBB", "AND",
                         "SUB", "XOR", "CMP"};
    char *tabladesplazamientos[] = {"ROL", "ROR", "RCL", "RCR",
                             "SHL/SAL", "SHR", "(086)?", "SAR"};
    char *tablagrupo1[] = {"TEST", "(086)?", "NOT", "NEG", "MUL",
                         "IMUL", "DIV", "IDIV"};
    char *tablagrupo2[] = {"INC", "DEC", "CALL", "CALL", "JMP",
                         "JMP", "PUSH", "(086)?"};

    char nemonico[20] = {""};
    char op1[20] = {""};
    char op2[20] = {""};
    char modo = SINOPERANDOS;
    char longitud = 0;
    char bytesadicionales = 0;


    union{
        struct{
            unsigned short int valor;
        }byte;
        struct{
            unsigned int L:4;
            unsigned int H:4;
        }nibble;
        struct{
            unsigned int w:1;    
            unsigned int d:1;
            unsigned int opcode:6;
        }campo;
    }byte1;

    union{
        struct{
            unsigned short int valor;
        }byte;
        struct{
            unsigned int r_m:3;
            unsigned int reg:3;
            unsigned int mod:2;
        }campo;
    }byte2;

    byte1.byte.valor = formato[0];    /* primer byte del formato */
    byte2.byte.valor = formato[1];    /* segundo byte del formato */

    longitud = 1;        /* al menos leo el primer byte del formato */
    
    switch(byte1.nibble.H)
    {
        case 0x0:
        switch(byte1.nibble.L)
        {
            case 0x0:
            case 0x1:
            case 0x2:
            case 0x3:
            sprintf(nemonico, "ADD"); modo = REGULAR; break;

            case 0x4:
            case 0x5:
            sprintf(nemonico, "ADD"); modo = INMEDTOAX; break;

            case 0x6:
            sprintf(nemonico, "PUSH"); modo = REGSEGMENTO; break;

            case 0x7:
            sprintf(nemonico, "POP"); modo = REGSEGMENTO; break;

            case 0x8:
            case 0x9:
            case 0xA:
            case 0xB:
            sprintf(nemonico, "OR"); modo = REGULAR; break;

            case 0xC:
            case 0xD:
            sprintf(nemonico, "OR"); modo = INMEDTOAX; break;

            case 0xE:
            sprintf(nemonico, "PUSH"); modo = REGSEGMENTO; break;

            case 0xF:        /* esta instrucción no existe realmente */
            sprintf(nemonico, "POP"); modo = REGSEGMENTO; break;
        }
        break;

        case 0x1:
        switch(byte1.nibble.L)
        {
            case 0x0:
            case 0x1:
            case 0x2:
            case 0x3:
            sprintf(nemonico, "ADC"); modo = REGULAR; break;

            case 0x4:
            case 0x5:
            sprintf(nemonico, "ADC"); modo = INMEDTOAX; break;

            case 0x6:
            sprintf(nemonico, "PUSH"); modo = REGPALABRA; break;

            case 0x7:
            sprintf(nemonico, "POP"); modo = REGPALABRA; break;

            case 0x8:
            case 0x9:
            case 0xA:
            case 0xB:
            sprintf(nemonico, "SBB"); modo = REGULAR; break;

            case 0xC:
            case 0xD:
            sprintf(nemonico, "SBB"); modo = INMEDTOAX; break;

            case 0xE:
            sprintf(nemonico, "PUSH"); modo = REGPALABRA; break;

            case 0xF:
            sprintf(nemonico, "POP"); modo = REGPALABRA; break;
        }
        break;

        case 0x2:
        switch(byte1.nibble.L)
        {
            case 0x0:
            case 0x1:
            case 0x2:
            case 0x3:
            sprintf(nemonico, "AND"); modo = REGULAR; break;

            case 0x4:
            case 0x5:
            sprintf(nemonico, "AND"); modo = INMEDTOAX; break;

            case 0x6:
            sprintf(nemonico, "ES"); modo = PREFIJOS; break;

            case 0x7:
            sprintf(nemonico, "DAA"); modo = SINOPERANDOS; break;

            case 0x8:
            case 0x9:
            case 0xA:
            case 0xB:
            sprintf(nemonico, "SUB"); modo = REGULAR; break;

            case 0xC:
            case 0xD:
            sprintf(nemonico, "SUB"); modo = INMEDTOAX; break;

            case 0xE:
            sprintf(nemonico, "CS"); modo = PREFIJOS; break;

            case 0xF:
            sprintf(nemonico, "DAS"); modo = SINOPERANDOS; break;
        }
        break;

        case 0x3:
        switch(byte1.nibble.L)
        {
            case 0x0:
            case 0x1:
            case 0x2:
            case 0x3:
            sprintf(nemonico, "XOR"); modo = REGULAR; break;

            case 0x4:
            case 0x5:
            sprintf(nemonico, "XOR"); modo = INMEDTOAX; break;

            case 0x6:
            sprintf(nemonico, "SS"); modo = PREFIJOS; break;

            case 0x7:
            sprintf(nemonico, "AAA"); modo = SINOPERANDOS; break;

            case 0x8:
            case 0x9:
            case 0xA:
            case 0xB:
            sprintf(nemonico, "CMP"); modo = REGULAR; break;

            case 0xC:
            case 0xD:
            sprintf(nemonico, "CMP"); modo = INMEDTOAX; break;

            case 0xE:
            sprintf(nemonico, "DS"); modo = PREFIJOS; break;

            case 0xF:
            sprintf(nemonico, "AAS"); modo = SINOPERANDOS; break;
        }
        break;

        case 0x4:
        if(byte1.nibble.L < 8)
        sprintf(nemonico, "INC");
        else
        sprintf(nemonico, "DEC");
        modo = REGPALABRA;
        break;


        case 0x5:
        if(byte1.nibble.L < 8) sprintf(nemonico, "PUSH");
        else sprintf(nemonico, "POP");
        modo = REGPALABRA;
        break;

        case 0x6:
        sprintf(nemonico, "(086)?");
        modo = SINOPERANDOS;
        break;

        case 0x7:
        sprintf(nemonico, saltos_cc[byte1.nibble.L]);
        modo = SALTO8;
        break;

        case 0x8:
        switch(byte1.nibble.L)
        {
            case 0x0:        /* requiere 2º byte */
            case 0x1:
            case 0x2:
            case 0x3:        /* binario 1000 00 XX; grupo inmediatos */
            /* aunque necesito el 2º byte del formato no lo cuanto ahora */
            /* lo contaré después cuando obtenga el operando del 2º byte */
            sprintf(nemonico, tablainmediatos[byte2.campo.reg]);
            modo = INMEDTOREGMEM;
            break;

            case 0x4:
            case 0x5:
            sprintf(nemonico, "TEST"); modo = REGULAR; break;

            case 0x6:
            case 0x7:
            sprintf(nemonico, "XCHG"); modo = REGULAR; break;

            case 0x8:
            case 0x9:
            case 0xA:
            case 0xB:
            sprintf(nemonico, "MOV"); modo = REGULAR; break;

            case 0xC:
            case 0xE:
            sprintf(nemonico, "MOV"); modo = MOVSEGMTO; break;

            case 0xD:
            sprintf(nemonico, "LEA");
            modo = REGULAR; /* CON */ byte1.campo.d = 1; byte1.campo.w = 1;
            break;

            case 0xF:
            sprintf(nemonico, "POP"); modo = REGMEM; break;
        }
        break;

        case 0x9:
        switch(byte1.nibble.L)
        {
            case 0x0:
            sprintf(nemonico, "NOP"); modo = SINOPERANDOS; break;

            case 0x8:
            sprintf(nemonico, "CBW"); modo = SINOPERANDOS; break;

            case 0x9:
            sprintf(nemonico, "CWD"); modo = SINOPERANDOS; break;

            case 0xA:
            sprintf(nemonico, "CALL"); modo = BASEOFFSET; break;

            case 0xB:
            sprintf(nemonico, "WAIT"); modo = SINOPERANDOS; break;

            case 0xC:
            sprintf(nemonico, "PUSHF"); modo = SINOPERANDOS; break;

            case 0xD:
            sprintf(nemonico, "POPF"); modo = SINOPERANDOS; break;

            case 0xE:
            sprintf(nemonico, "SAHF"); modo = SINOPERANDOS; break;

            case 0xF:
            sprintf(nemonico, "LAHF"); modo = SINOPERANDOS; break;

            default:
            sprintf(nemonico, "XCHG"); modo = REGPALABRA;
        }
        break;

        case 0xA:
        switch(byte1.nibble.L)
        {
            case 0x0:
            case 0x1:
            case 0x2:
            case 0x3:
            sprintf(nemonico, "MOV"); modo = MOVMEMAX; break;

            case 0x4:
            case 0x5:
            sprintf(nemonico, "MOVS"); modo = SINOPERANDOS; break;

            case 0x6:
            case 0x7:
            sprintf(nemonico, "CMPS"); modo = SINOPERANDOS; break;

            case 0x8:
            case 0x9:
            sprintf(nemonico, "TEST"); modo = INMEDTOAX; break;

            case 0xA:
            case 0xB:
            sprintf(nemonico, "STOS"); modo = SINOPERANDOS; break;

            case 0xC:
            case 0xD:
            sprintf(nemonico, "LODS"); modo = SINOPERANDOS; break;

            case 0xE:
            case 0xF:
            sprintf(nemonico, "SCAS"); modo = SINOPERANDOS; break;
        }
        break;

        case 0xB:
        sprintf(nemonico, "MOV"); modo = MOVINMEDTOREG; break;

        case 0xC:
        switch(byte1.nibble.L)
        {
            case 0x0:
            case 0x1:
            case 0x8:
            case 0x9:
            sprintf(nemonico, "(086)?"); modo = SINOPERANDOS; break;

            case 0x2:
            sprintf(nemonico, "RET"); modo = INMED16; break;

            case 0x3:
            sprintf(nemonico, "RET"); modo = SINOPERANDOS; break;

            case 0xA:
            sprintf(nemonico, "RETF"); modo = INMED16; break;

            case 0xB:
            sprintf(nemonico, "RETF"); modo = SINOPERANDOS; break;
            break;

            case 0x4:
            sprintf(nemonico, "LES");
            modo = REGULAR; /* CON */ byte1.campo.d = 1; byte1.campo.w = 1;
            break;

            case 0x5:
            sprintf(nemonico, "LDS");
            modo = REGULAR; /* CON */ byte1.campo.d = 1; byte1.campo.w = 1;
            break;

            case 0x6:
            case 0x7:
            sprintf(nemonico, "MOV"); modo = INMEDTOREGMEM; break;

            case 0xC:
            sprintf(nemonico, "INT 3"); modo = SINOPERANDOS; break;

            case 0xD:
            sprintf(nemonico, "INT"); modo = INMED8; break;

            case 0xE:
            sprintf(nemonico, "INTO"); modo = SINOPERANDOS; break;

            case 0xF:
            sprintf(nemonico, "IRET"); modo = SINOPERANDOS; break;
        }
        break;

        case 0xD:
        switch(byte1.nibble.L)
        {
            case 0x00:        /* requiere 2º byte */
            case 0x01:
            case 0x02:
            case 0x03:        /* binario 1101 00 XX; grupo desplazamientos */
            /* aunque necesito el 2º byte del formato lo contaré cuando lea el operando */
              sprintf(nemonico, tabladesplazamientos[byte2.campo.reg]);
            modo = DESPLAZAMIENTO;
            break;

            case 0x04:
            sprintf(nemonico, "AAM"); modo = INMED8; break;

            case 0x05:
            sprintf(nemonico, "AAD"); modo = INMED8; break;

            case 0x06:
            sprintf(nemonico, "(086)?"); modo = SINOPERANDOS; break;

            case 0x07:
            sprintf(nemonico, "XLAT"); modo = SINOPERANDOS; break;

            default:
            sprintf(nemonico, "ESC"); modo = REGMEM;
        }
        break;

        case 0xE:
        switch(byte1.nibble.L)
        {
            case 0x0:
            sprintf(nemonico, "LOOPNZ/LOOPNE"); modo = SALTO8; break;

            case 0x1:
            sprintf(nemonico, "LOOPZ/LOOPE"); modo = SALTO8; break;

            case 0x2:
            sprintf(nemonico, "LOOP"); modo = SALTO8; break;

            case 0x3:
            sprintf(nemonico, "JCXZ"); modo = SALTO8; break;

            case 0x4:
            case 0x5:
            case 0xC:
            case 0xD:
            sprintf(nemonico, "IN"); modo = ENTRADA_SALIDA; break;

            case 0x6:
            case 0x7:
            case 0xE:
            case 0xF:
            sprintf(nemonico, "OUT"); modo = ENTRADA_SALIDA; break;

            case 0x8:
            sprintf(nemonico, "CALL"); modo = SALTO16; break;

            case 0x9:
            sprintf(nemonico, "JMP"); modo = SALTO16; break;


            case 0xA:
            sprintf(nemonico, "JMP"); modo = BASEOFFSET; break;

            case 0xB:
            sprintf(nemonico, "JMP"); modo = SALTO8; break;
        }
        break;

        case 0xF:
        switch(byte1.nibble.L)
        {
            case 0x0:
            sprintf(nemonico, "LOCK"); modo = SINOPERANDOS; break;

            case 0x1:
            sprintf(nemonico, "(086)?"); modo = SINOPERANDOS; break;

            case 0x2:     /* este nemónico es equivalente a "REPZ/REPE" */
            sprintf(nemonico, "REP"); modo = PREFIJOS; break;

            case 0x3:
            sprintf(nemonico, "REPNZ/REPNE"); modo = PREFIJOS; break;

            case 0x4:
            sprintf(nemonico, "HLT"); modo = SINOPERANDOS; break;

            case 0x5:
            sprintf(nemonico, "CMC"); modo = SINOPERANDOS; break;

            case 0x6:        /* requiere 2º byte */
            case 0x7:        /* binario 1111 01 1X; grupo 1 */
            /* aunque necesito el 2º byte del formato no lo cuento ahora */
            /* lo contaré cuando leo el operando del 2º byte */
            sprintf(nemonico, tablagrupo1[byte2.campo.reg]);
            switch(byte2.campo.reg)
            {
                case 0:     /* instrucción TEST */
                modo = INMEDTOREGMEM;
                break;

                case 1:     /* no definida (086)? */
                modo = SINOPERANDOS;
                break;

                case 2:     /* instrucción NOT */
                case 3:     /* instrucción NEG */
                case 4:     /* instrucción MUL */
                case 5:     /* instrucción IMUL */
                case 6:     /* instrucción DIV */
                case 7:     /* instrucción IDIV */
                modo = REGMEM;
                break;
            }
            break;

            case 0x8:
            sprintf(nemonico, "CLC"); modo = SINOPERANDOS; break;

            case 0x9:
            sprintf(nemonico, "STC"); modo = SINOPERANDOS; break;

            case 0xA:
            sprintf(nemonico, "CLI"); modo = SINOPERANDOS; break;

            case 0xB:
            sprintf(nemonico, "STI"); modo = SINOPERANDOS; break;

            case 0xC:
            sprintf(nemonico, "CLD"); modo = SINOPERANDOS; break;

            case 0xD:
            sprintf(nemonico, "STD"); modo = SINOPERANDOS; break;

            case 0xE:        /* requiere 2º byte */
            case 0xF:        /* binario 1111 11 1X; grupo 2 */
            /* aunque necesito el 2º byte del formato lo contaré cuando saque el operando */
            sprintf(nemonico, tablagrupo2[byte2.campo.reg]);
            switch(byte2.campo.reg)
            {
                case 0:     /* instrucción INC */
                case 1:     /* instrucción DEC */
                case 2:
                case 3:     /* instrucciones CALL */
                case 4:
                case 5:     /* instrucciones JMP */
                case 6:     /* instrucción PUSH */
                modo = REGMEM;
                break;

                case 7:
                modo = SINOPERANDOS;    /* no definida (086)? */
                break;
            }
            break;
        }
        break;
    }

    /* ahora añado los operandos (si los hay) al nemónico */
    /* quizá sea interesante dar un formato que permita distinguir con más facilidad */
    /* el tipo de operando (registro, memoria, inmediato, etc.) con el fin de    */
    /* facilitar el análisis posterior por funciones de los operandos */
    /* cuando hay un único operando siempre se considera op1 (destino en la notación INTEL) */

    switch (modo)
    {
        case SINOPERANDOS:    /* sin operandos */
        case PREFIJOS:
        break;

        case REGPALABRA:    /* 1 operando: registro tamaño palabra */
        OperandoRegistro(1, byte1.nibble.L & 0x7, op1);
        break;

        case REGSEGMENTO:    /* 1 operando registro segmento */
        OperandoRegSeg((byte1.campo.opcode >> 1) & 0x03, op1);
        break;

        case REGMEM:        /* 1 operando registro o memoria */
        longitud += 1;        /* necesito el 2º byte */
        OperandoRM(byte1.campo.w, byte2.campo.mod, byte2.campo.r_m, formato[longitud], formato[longitud+1], op1, &bytesadicionales);
        longitud += bytesadicionales;    /* sumo los posibles bytes del formato utilizados */
        break;

        case INMED8:        /* 1 operando inmediato de 8 bits */
        longitud += 1;        /* necesito otro byte más */
        if(!strcmp(nemonico, "INT")) sprintf(op1, "%02X", formato[longitud-1]);
        /* en los casos de AAM y AAD el 2º byte es 0x0A y sólo hay que contarlo */
        break;

        case INMED16:        /* 1 operando inmediato de 16 bits */
        longitud += 2;        /* necesito otros 2 bytes más */
        sprintf(op1, "%02X%02X", formato[longitud-1], formato[longitud-2]);
        break;
    
        case SALTO8:        /* 1 operando: byte */
        longitud += 1;        /* necesito otro byte más */
        /* sprintf(destino, "IP+%02X", formato[longitud-1]); */
        /* no hace falta dar IP ya que es un implícito indicado en la base de datos */
        sprintf(op1, "%02X", formato[longitud-1]);
        break;

        case SALTO16:        /* 1 operando: 2 bytes */
        longitud += 2;        /* necesito otros 2 bytes más */
        /* sprintf(destino, "IP+%02X%02X", formato[longitud-1], formato[longitud-2]); */
        /* no hace falta dar IP ya que es un implícito indicado en la base de datos */
        sprintf(op1, "%02X%02X", formato[longitud-1], formato[longitud-2]);
        break;

        case BASEOFFSET:    /* 1 operando: base:offset */
        longitud += 4;        /* necesito otros 4 bytes más */
        sprintf(op1, "%02X%02X:%02X%02X", formato[longitud-1], formato[longitud-2], formato[longitud-3], formato[longitud-4]);
        break;

        case REGULAR:        /* 2 operandos: 1 registro y 1 reg/mem */
        longitud += 1;    /* necesito el 2º byte */
        switch(byte1.campo.d)
        {
            case 0:        /* reg es el operando 2 (fuente) */
            OperandoRegistro(byte1.campo.w, byte2.campo.reg, op2);
            OperandoRM(byte1.campo.w, byte2.campo.mod, byte2.campo.r_m, formato[longitud], formato[longitud+1], op1, &bytesadicionales);
            break;

            case 1:        /* reg es el operando 1 (destino) */
            OperandoRegistro(byte1.campo.w, byte2.campo.reg, op1);
            OperandoRM(byte1.campo.w, byte2.campo.mod, byte2.campo.r_m, formato[longitud], formato[longitud+1], op2, &bytesadicionales);
            break;
        }
        longitud += bytesadicionales;    /* sumo los posibles bytes del formato utilizados */
        break;

        case INMEDTOAX:        /* 2 operandos: inmediato -> acumulador */
        switch(byte1.campo.w)
        {
            case 0:
            longitud += 1;        /* necesito otro byte más */
            sprintf(op2, "%02X", formato[longitud-1]);
            sprintf(op1, "AL");    /* este op1 está asociado a la operación (es implícito) */
                                    /* sin embargo no lo considero tal ya que el programador */
                                    /* lo explicita voluntariamente cuando escribe la instrucción */
                                    /* el formato lo hace implícito para ahorrar espacio */
            break;

            case 1:
            longitud += 2;        /* necesito otros 2 bytes más */
            sprintf(op2, "%02X%02X", formato[longitud-1], formato[longitud-2]);
            sprintf(op1, "AX");
            break;
        }
        break;

        case INMEDTOREGMEM:    /* 2 operandos: inmediato -> registro o memoria */
        longitud += 1;    /* necesito el 2º byte */
        OperandoRM(byte1.campo.w, byte2.campo.mod, byte2.campo.r_m, formato[longitud], formato[longitud+1], op1, &bytesadicionales);
        longitud += bytesadicionales;    /* sumo los posibles bytes del formato utilizados */
        switch(byte1.campo.w)
        {
            case 0:
            longitud += 1;        /* necesito otro byte más */
            sprintf(op2, "%02X", formato[longitud-1]);
            break;

            case 1:
            longitud += 2;        /* necesito otros 2 bytes más */
            sprintf(op2, "%02X%02X", formato[longitud-1], formato[longitud-2]);
            break;
        }
        break;

        case MOVMEMAX:        /* 2 operandos: load/store entre memoria y acc */
        longitud += 2;        /* necesito otros 2 bytes más */
        switch(byte1.campo.d)
        {
            case 0:        /* memoria es el operando 2 */
            sprintf(op2, "[%02X%02X]", formato[longitud-1], formato[longitud-2]);
            OperandoRegistro(byte1.campo.w, 0, op1);    /* es el acumulador */            
            break;

            case 1:        /* memoria es el operando 1 */
            sprintf(op1, "[%02X%02X]", formato[longitud-1], formato[longitud-2]);
            OperandoRegistro(byte1.campo.w, 0, op2);        /* es el acumulador */    
                            /* este op1 está asociado a la operación (es implícito) */
                            /* sin embargo no lo considero tal ya que el programador */
                            /* lo explicita voluntariamente cuando escribe la instrucción */
                            /* el formato lo hace implícito para ahorrar espacio */
            break;
        }
        break;

        case MOVSEGMTO:        /* 2 operandos: 1 reg. de segmento y 1 reg/mem */
        longitud += 1;    /* necesito el 2º byte */
        switch(byte1.campo.d)
        {
            case 0:        /* reg. de segmento es el operando 2 */
            OperandoRegSeg(byte2.campo.reg & 0x3, op2);
            OperandoRM(1, byte2.campo.mod, byte2.campo.r_m, formato[longitud], formato[longitud+1], op1, &bytesadicionales);
            /* hay que forzar w = 1 ya que del formato viene a 0 */
            break;

            case 1:        /* reg. de segmento es el operando 1 */
            OperandoRegSeg(byte2.campo.reg & 0x3, op1);
            OperandoRM(1, byte2.campo.mod, byte2.campo.r_m, formato[longitud], formato[longitud+1], op2, &bytesadicionales);
            /* hay que forzar w = 1 ya que del formato viene a 0 */
            break;
        }
        longitud += bytesadicionales;    /* sumo los posibles bytes del formato utilizados */
        break;

        case MOVINMEDTOREG:        /* 2 operandos: inm -> registro */
        switch((byte1.nibble.L & 0x8) >> 3)
        {
            case 0:
            longitud += 1;        /* necesito otro byte más */
            sprintf(op2, "%02X", formato[longitud-1]);
            OperandoRegistro(0, byte1.nibble.L & 0x7, op1);
            break;

            case 1:
            longitud += 2;        /* necesito otros 2 bytes más */
            sprintf(op2, "%02X%02X", formato[longitud-1], formato[longitud-2]);
            OperandoRegistro(1, byte1.nibble.L & 0x7, op1);
            break;
        }
        break;

        case DESPLAZAMIENTO:    /* 2 operandos: reg/mem y contador */
        longitud += 1;            /* necesito el 2º byte */
        OperandoRM(byte1.campo.w, byte2.campo.mod, byte2.campo.r_m, formato[longitud], formato[longitud+1], op1, &bytesadicionales);
        longitud += bytesadicionales;    /* sumo los posibles bytes del formato utilizados */
        switch(byte1.campo.d)    /* ahora se llama 'v' en lugar de 'd' pero es el mismo */
        {
            case 0:
            sprintf(op2, "01");        /* todos los inmediatos deben tener 2 dígitos hex por byte */
            break;

            case 1:
            sprintf(op2, "CL");
            break;
        }    
        break;

        case ENTRADA_SALIDA:    /* 2 operandos: acc y DX o inm8 */
        switch(byte1.campo.d)
        {
            case 0:        /* reg es el operando 2 */
            if(byte1.campo.opcode == 57)    /* 111 001 */
            {
                longitud += 1;        /* necesito otro byte más */
                sprintf(op2, "%02X", formato[longitud-1]);
            }
            else sprintf(op2, "DX");
            OperandoRegistro(byte1.campo.w, 0, op1);    /* es el acumulador */    
            break;

            case 1:        /* reg es el operando 1 */
            OperandoRegistro(byte1.campo.w, 0, op2);        /* es el acumulador */    
            if(byte1.campo.opcode == 57)    /* 111 011 */
            {
                longitud += 1;        /* necesito otro byte más */
                sprintf(op1, "%02X", formato[longitud-1]);
            }
            else sprintf(op1, "DX");
            break;
        }
        break;
    }

    /* (*p).miembro es equivalente a p->miembro */
    
    strcpy((*instruccion).nemonico, nemonico);
    strcpy(instruccion->op2, op2);
    strcpy(instruccion->op1, op1);
    instruccion->longitud = longitud;
}

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>