// no debug part in here...


/*****************************************************************************/
/*                                                                           */
/*   VECTREX HP3000 Software Emulator              Copyright K.Wilkins 1996  */
/*                                                                           */
/*****************************************************************************/
/*                                                                           */
/*   Title      : 6809 Disassembler Module                                   */
/*                                                                           */
/*   File Name  : dis6809.c                                                  */
/*                                                                           */
/*   Author     : Keith Wilkins                                              */
/*                                                                           */
/*   Version    : 1.00                                                       */
/*                                                                           */
/*   Desciption : This file contains the 6809 dissasembler code              */
/*                                                                           */
/*   Functions  : f6809Disassemble() - Return string of instruction code     */
/*                f6809CycleCount()  - Count 6809 machine cycles per inst    */
/*                                                                           */
/*****************************************************************************/
/*                                                                           */
/*   Revision History:                                                       */
/*                                                                           */
/*   Version    Date    Who  Description of changes                          */
/*   -------    ----    ---  ----------------------                          */
/*                                                                           */
/*    0.01    11/04/95  K.W  Creation                                        */
/*    1.00    05/08/96  K.W  Public release of DVE V1.0                      */
/*                                                                           */
/*****************************************************************************/

/* Include opcode table & local references */
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <standard.h>

#include <parser.h>
#include <error.h>
#include <tools.h>


#include "vectrex.h"
#include "emu6809.h"
#include "tab6809.h"
#include "mon_cmds.h"
#include "dis6809.h"

#define COMMENT_START 60
#define LABEL_LEN 30


T_CHAR dis_mem_map[D_MEM_SIZE];
T_LISTE *info_liste_first=NULL;
T_LISTE *info_liste_last=NULL;
T_INT dis_init_state=T_FALSE;

////////////////////////////////

T_VOID init_dis(T_VOID);
T_VOID debug_parse(T_PCHAR cart_name);

static T_PCHAR dstring=NULL;
static T_INT daddress=0;
static T_INT dstart=0;
static T_INT dend=0;

// all ranges are including start and end addresses!
static PARSER_STRUKT dequ[]=
{
 {PARSER_TYPE_STRING, 1,&dstring},
 {PARSER_TYPE_SINT, 1,&daddress},
 {PARSER_STRUKT_END, 0, NULL}
};
static PARSER_STRUKT dinfo[]=
{
 {PARSER_TYPE_SINT, 1,&daddress},
 {PARSER_TYPE_STRING, 1,&dstring},
 {PARSER_STRUKT_END, 0, NULL}
};
static PARSER_STRUKT dmem[]=
{
 {PARSER_TYPE_SINT, 1,&dstart},
 {PARSER_TYPE_SINT, 1,&dend},
 {PARSER_STRUKT_END, 0, NULL}
};

static PARSER_WORD parse_control[]=
{
 {PARSER_TYPE_STRUKT, "EQU"  ,&dequ,D_EQU},
 {PARSER_TYPE_STRUKT, "LABEL"  ,&dinfo,D_LABEL},
 {PARSER_TYPE_STRUKT, "COMMENT_LINE",&dinfo,D_COMMENT_LINE},
 {PARSER_TYPE_STRUKT, "COMMENT",&dinfo,D_COMMENT},
 {PARSER_TYPE_STRUKT, "CODE",&dmem,D_CODE},
 {PARSER_TYPE_STRUKT, "DATA_BIN",&dmem,D_DATA_BIN},
 {PARSER_TYPE_STRUKT, "DATA_ASCII",&dmem,D_DATA_ASCII},
 {PARSER_TYPE_STRUKT, "RANGE",&dmem,D_RANGE},
 {PARSER_TYPE_END,NULL,NULL}
};

/*****************************************************************************/
/*                                                                           */
/*   Function    : f6809Dissasemble()                                        */
/*                                                                           */
/*   Author      : K.W                                                       */
/*                                                                           */
/*   Description : Dissasemble 6809 code, passed an addres it returns a      */
/*                 string containing one dissasembled instruction and then   */
/*                 returns the addres of the next T_UCHAR.                      */
/*                                                                           */
/*   Accepts     : address & string pointer                                  */
/*                                                                           */
/*   Returns     : new address                                               */
/*                                                                           */
/*****************************************************************************/

T_UWORD f6809Disassemble(T_UWORD wAddress,T_PUCHAR pcOutString)
{
 static volatile T_UCHAR acTmpStr[DISAS_MAX_STRING];
 static volatile T_UWORD wOpCode,wTemp,wLoop;
 static volatile T_UCHAR bTemp,bFirstFlag;
 static volatile T_INT label_done;
 static volatile T_INT entry_Address;
 label_done=T_FALSE;
 entry_Address=wAddress;

 if (dis_init_state==T_FALSE)
 {
  dis_init_state=T_TRUE;
  init_dis();
 }

 /* Read the 1st instruction BYTE */
 wOpCode=(T_UWORD)f6809AddressRead(wAddress++);
 strcpy(pcOutString,as6809Dis[wOpCode].acInstruction);

 /* Sort out 16 bit instructions before we do the real decode */
 switch(as6809Dis[wOpCode].bAddressMode)
 {
  case PAGE2:
   wOpCode=(T_UWORD)f6809AddressRead(wAddress++);
   wOpCode+=256;
   strcpy(pcOutString,as6809Dis[wOpCode].acInstruction);
   break;
  case PAGE3:
   wOpCode=(T_UWORD)f6809AddressRead(wAddress++);
   wOpCode+=512;
   strcpy(pcOutString,as6809Dis[wOpCode].acInstruction);
   break;
  default:
   break;
 }
 strcat(pcOutString," ");

 /* Now we have the correct opcode generate the operand */
 switch(as6809Dis[wOpCode].bAddressMode)
 {
  case ILLEGAL:
   strcpy(pcOutString,"???");
   break;
  case INHERENT:
   break;
  case DIRECT:
   sprintf((T_PCHAR)acTmpStr,"$%02x",f6809AddressRead(wAddress++));
   strcat((T_PCHAR)pcOutString,(const T_PCHAR)acTmpStr);
   break;
  case EXTENDED:
  {
   static volatile T_INT hi;
   static volatile T_INT lo;
   static volatile T_INT address;
   static volatile T_INT label_done;
   static volatile T_LISTE *liste;
   hi=f6809AddressRead(wAddress++);
   lo=f6809AddressRead(wAddress++);
   address=hi*256+lo;
   label_done=T_FALSE;
   liste=info_liste_first;
   while (liste!=NULL)
   {
    static volatile D_ADDRESS_INFO *info;
    info=(D_ADDRESS_INFO *)(liste->objekt);
    if (info->address==address)
    {
     if (info->kind_of_info==D_INFO_LABEL)
     {
      strcat(pcOutString,info->string);
      label_done=T_TRUE;
      break;
     }
    }
    liste=liste->naechstes;
   }
   if (label_done==T_FALSE)
   {
    sprintf((T_PCHAR)acTmpStr,"$%02x%",hi);
    strcat(pcOutString,(const T_PCHAR)acTmpStr);
    sprintf((T_PCHAR)acTmpStr,"%02x",lo);
    strcat(pcOutString,(const T_PCHAR)acTmpStr);
   }
   break;
  }
  case RELATIVE8:
  {
   static volatile T_INT label_done;
   static volatile T_LISTE *liste;
   label_done=T_FALSE;
   liste=info_liste_first;
   wTemp=(T_UWORD)f6809AddressRead(wAddress++);
   if (wTemp>=128)
    wTemp=wTemp|0xff00;
   wTemp=wAddress+wTemp;
   while (liste!=NULL)
   {
    static volatile D_ADDRESS_INFO *info;
    info=(D_ADDRESS_INFO *)(liste->objekt);
    if (info->address==wTemp)
    {
     if (info->kind_of_info==D_INFO_LABEL)
     {
      strcat(pcOutString,info->string);
      label_done=T_TRUE;
      break;
     }
    }
    liste=liste->naechstes;
   }
   if (label_done==T_FALSE)
   {
    sprintf((T_PCHAR)acTmpStr,"$%04x%",wTemp);
    strcat(pcOutString,(const T_PCHAR)acTmpStr);
   }
   break;
  }
  case RELATIVE16:
  {
   static volatile T_INT label_done;
   static volatile T_LISTE *liste;
   label_done=T_FALSE;
   liste=info_liste_first;
   wTemp=(T_UWORD)f6809AddressRead(wAddress++);
   wTemp=wTemp<<8;
   wTemp=wTemp | (T_UWORD)f6809AddressRead(wAddress++);
   wTemp=wAddress+wTemp;
   while (liste!=NULL)
   {
    static volatile D_ADDRESS_INFO *info;
    info=(D_ADDRESS_INFO *)(liste->objekt);
    if (info->address==wTemp)
    {
     if (info->kind_of_info==D_INFO_LABEL)
     {
      strcat(pcOutString,info->string);
      label_done=T_TRUE;
      break;
     }
    }
    liste=liste->naechstes;
   }
   if (label_done==T_FALSE)
   {
    sprintf((T_PCHAR)acTmpStr,"$%04x%",wTemp);
    strcat(pcOutString,(const T_PCHAR)acTmpStr);
   }
   break;
  }
  case IMMEDIATE8:
  {
   static volatile T_INT hi;
   static volatile T_INT address;
   static volatile T_INT equ_done;
   static volatile T_LISTE *liste;
   hi=f6809AddressRead(wAddress++);
   address=hi;
   equ_done=T_FALSE;
   liste=info_liste_first;
   while (liste!=NULL)
   {
    static volatile D_ADDRESS_INFO *info;
    info=(D_ADDRESS_INFO *)(liste->objekt);
    if (info->address==address)
    {
     if (info->kind_of_info==D_INFO_EQU)
     {
      strcat(pcOutString,"#");
      strcat(pcOutString,info->string);
      equ_done=T_TRUE;
      break;
     }
    }
    liste=liste->naechstes;
   }
   if (equ_done==T_FALSE)
   {
    sprintf((T_PCHAR)acTmpStr,"#$%02x",hi);
    strcat(pcOutString,(const T_PCHAR)acTmpStr);
   }
   break;
  }
  case IMMEDIATE16:
  {
   static volatile T_INT hi;
   static volatile T_INT lo;
   static volatile T_INT address;
   static volatile T_INT equ_done;
   static volatile T_LISTE *liste;
   hi=f6809AddressRead(wAddress++);
   lo=f6809AddressRead(wAddress++);
   address=hi*256+lo;
   equ_done=T_FALSE;
   liste=info_liste_first;
   while (liste!=NULL)
   {
    static volatile D_ADDRESS_INFO *info;
    info=(D_ADDRESS_INFO *)(liste->objekt);
    if (info->address==address)
    {
     if (info->kind_of_info==D_INFO_EQU)
     {
      strcat(pcOutString,"#");
      strcat(pcOutString,info->string);
      equ_done=T_TRUE;
      break;
     }
    }
    liste=liste->naechstes;
   }
   if (equ_done==T_FALSE)
   {
    sprintf((T_PCHAR)acTmpStr,"#$%02x",hi);
    strcat(pcOutString,(const T_PCHAR)acTmpStr);
    sprintf((T_PCHAR)acTmpStr,"%02x",lo);
    strcat(pcOutString,(const T_PCHAR)acTmpStr);
   }
   break;
  }
  case REGISTER1:
   bTemp=f6809AddressRead(wAddress++);
   sprintf((T_PCHAR)acTmpStr,"%s,%s",asRegNames1[bTemp>>4],asRegNames1[bTemp&0x0f]);
   strcat(pcOutString,(const T_PCHAR)acTmpStr);
   break;
  case REGISTER2:
   wTemp=(T_UWORD)f6809AddressRead(wAddress++);
   bTemp=0;
   bFirstFlag=T_TRUE;
   for (wLoop=1;wLoop<129;wLoop=wLoop<<1)
   {
    if ((wTemp&wLoop)!=0)
    {
     if (bFirstFlag==T_FALSE)
      strcat(pcOutString,",");
     strcat(pcOutString,asRegNames2[bTemp]);
     bFirstFlag=T_FALSE;
    }
    bTemp++;
   }
   break;
  case INDEXED:
   bTemp=f6809AddressRead(wAddress++);

   /* Now we must decode the index T_UCHAR */
   switch(asIndexDecode[bTemp].wWordSize)
   {
    case 0:
     strcat(pcOutString,asIndexDecode[bTemp].acFormat);
     break;
    case 1:
     sprintf((T_PCHAR)acTmpStr,asIndexDecode[bTemp].acFormat,f6809AddressRead(wAddress++));
     strcat(pcOutString,(const T_PCHAR)acTmpStr);
     break;
    case 2:
     wTemp=(T_UWORD)f6809AddressRead(wAddress++)<<8;
     wTemp+=(T_UWORD)f6809AddressRead(wAddress++);
     sprintf((T_PCHAR)acTmpStr,asIndexDecode[bTemp].acFormat,wTemp);
     strcat(pcOutString,(const T_PCHAR)acTmpStr);
     break;
    default:
     strcat(pcOutString,"Error in Index Table");
     break;
   }
   break;
  case PAGE2:
  case PAGE3:
  default:
   strcat(pcOutString," Bad decode table entry");
   break;
 }
 // now do my control stuff
 label_done=T_FALSE;
 if (dis_mem_map[entry_Address]&D_MEM_HAS_INFO)
 {
  T_LISTE *liste;
  liste=info_liste_first;
  while (liste!=NULL)
  {
   static volatile D_ADDRESS_INFO *info;
   info=(D_ADDRESS_INFO *)(liste->objekt);
   if (info->address==entry_Address)
   {
    if (info->kind_of_info==D_INFO_LABEL)
    {
     T_CHAR help[STRING_LENGTH];
     strcpy((T_PCHAR)help,pcOutString);
     pcOutString[0]=0;
     strcat(pcOutString,info->string);
     strcat(pcOutString," "); // was " "
     while (strlen(pcOutString)<LABEL_LEN)
      strcat(pcOutString," ");
     strcat(pcOutString,(const T_PCHAR)help);
     label_done=T_TRUE;
     break;
    }
    else
    if (info->kind_of_info==D_INFO_COMMENT)
    {
     while (strlen(pcOutString)<COMMENT_START)
      strcat(pcOutString," ");
     strcat(pcOutString,"; ");
     strcat(pcOutString,info->string);
    }
   }
   liste=liste->naechstes;
  }
 }
 if (label_done==T_FALSE)
 {
  T_CHAR help[STRING_LENGTH];
  strcpy((T_PCHAR)help,pcOutString);
  pcOutString[0]=0;
  while (strlen(pcOutString)<LABEL_LEN)
   strcat(pcOutString," ");
  strcat(pcOutString,(const T_PCHAR)help);
  label_done=T_TRUE;
 }
 /* Return the next valid address */
 return (wAddress);
}

/*****************************************************************************/
/*                                                                           */
/*   Function    : f6809CycleCount()                                         */
/*                                                                           */
/*   Author      : K.W                                                       */
/*                                                                           */
/*   Description : This function counts the number of cycles taken to exec   */
/*                 the instruction at wAddr.                                 */
/*                                                                           */
/*   Accepts     : Address of instruction operand                            */
/*                                                                           */
/*   Returns     : number of CPU E clock cycles to execute instruction       */
/*                                                                           */
/*****************************************************************************/

T_UCHAR   f6809CycleCount(T_UWORD wAddr)
{
 wAddr=0;
 return(1);
}

T_VOID init_dis(T_VOID)
{
 T_PCHAR current_path=NULL;
 T_CHAR rom_name[STRING_LENGTH];
 T_CHAR cart_name[STRING_LENGTH];
 T_INT i;

// t_printf(0,"\ninit_dis()");
// init global field as not init
 for (i=0;i<D_MEM_SIZE;i++)
  dis_mem_map[i]=D_MEM_NOT_INIT;

 // generate filenames
 strcpy(rom_name,acGblROMImageFileName);
 i = strlen(rom_name);
 while ((i) && ((*(rom_name+i))!='.'))
  i--;
 (*(rom_name+i))=0;
 strcat(rom_name,".cnt");

 strcpy(cart_name,acGblDefaultCartFileName);
 i = strlen(cart_name);
 while ((i) && ((*(cart_name+i))!='.'))
  i--;
 (*(cart_name+i))=0;
 strcat(cart_name,".cnt");

 // read files

 // process ram
 if (strcmp(cart_name,rom_name))
 {
  current_path=get_current_path();
  if (GblDevDir!=NULL)
   change_directory(GblDevDir);
  if (f_file_exist(cart_name)==T_FALSE)
  {
   if (current_path!=NULL)
   {
    change_directory(current_path);
    free(current_path);
    current_path=NULL;
   }
  }
//  t_printf(0,"\ncart_name:\"%s\"",cart_name);
  if (f_file_exist(cart_name)==T_TRUE)
   debug_parse(cart_name);
  if (current_path!=NULL)
  {
   change_directory(current_path);
   free(current_path);
   current_path=NULL;
  }
 } //if (strcmp(cart_name,rom_name))

 // process rom
 current_path=get_current_path();
 if (GblDevDir!=NULL)
  change_directory(GblDevDir);
 if (f_file_exist(rom_name)==T_FALSE)
 {
  if (current_path!=NULL)
  {
   change_directory(current_path);
   free(current_path);
   current_path=NULL;
  }
 }
 if (f_file_exist(rom_name)==T_TRUE)
  debug_parse(rom_name);
 if (current_path!=NULL)
 {
  change_directory(current_path);
  free(current_path);
  current_path=NULL;
 }
 // all done
}
T_VOID deinit_dis(T_VOID)
{
 while (info_liste_first!=NULL)
 {
  D_ADDRESS_INFO *info=(D_ADDRESS_INFO *)(info_liste_first->objekt);
  d_entferne_aus_liste(info,&info_liste_first,&info_liste_last,DL_CLEAN_UP);
  if (info)
  {
   if (info->string)
    free(info->string);
   free(info);
  }
 }
 return;
}

T_VOID debug_parse(T_PCHAR name)
{
 M_FILE *help_file=NULL;
 T_INT read_status=T_OK;
 p_alloc_pointer=T_TRUE;
//t_printf(0,"\ndebug_parse(), %s", name);
 p_parse_init();
 p_open_parse( name, &help_file, parse_control );
 if ((help_file==NULL)||(parse_error!=T_OK))
 {
  show_message("DEBUG nicht verfuegbar! (Name: %s, Parse Error:%i)",name,parse_error);
  return;
 }
 while (read_status!=PARSE_FILE_END)
 {
  T_CHAR last_key[80];
  T_INT key=0;
  read_status =p_parse_next( help_file, last_key, &key );
  switch (key)
  {
   case D_RANGE:
   {
    T_INT i;
//t_printf(0,"\nRANGE start:%i, end:%i",dstart,dend);
    for (i=dstart;i<=dend;i++)
    {
     dis_mem_map[i]|=D_MEM_CODE;
     dis_mem_map[i]&=(255-D_MEM_DATA_BIN-D_MEM_DATA_ASCII-D_MEM_NOT_INIT);
    }
    break;
   }
   case D_DATA_ASCII:
   {
    T_INT i;
//t_printf(0,"\nDATA_ASCII start:%i, end:%i",dstart,dend);
    for (i=dstart;i<=dend;i++)
    {
     dis_mem_map[i]|=D_MEM_DATA_ASCII;
     dis_mem_map[i]&=(255-D_MEM_DATA_BIN-D_MEM_CODE-D_MEM_NOT_INIT);
    }
    break;
   }
   case D_DATA_BIN:
   {
    T_INT i;
//t_printf(0,"\nDATA_BIN start:%i, end:%i",dstart,dend);
    for (i=dstart;i<=dend;i++)
    {
     dis_mem_map[i]|=D_MEM_DATA_BIN;
     dis_mem_map[i]&=(255-D_MEM_DATA_ASCII-D_MEM_CODE-D_MEM_NOT_INIT);
    }
    break;
   }
   case D_CODE:
   {
    T_INT i;
//t_printf(0,"\nCODE start:%i, end:%i",dstart,dend);
    for (i=dstart;i<=dend;i++)
    {
     dis_mem_map[i]|=D_MEM_CODE;
     dis_mem_map[i]&=(255-D_MEM_DATA_ASCII-D_MEM_DATA_BIN-D_MEM_NOT_INIT);
    }
    break;
   }
   case D_COMMENT:
   {
    D_ADDRESS_INFO *info=(D_ADDRESS_INFO *)malloc(sizeof(D_ADDRESS_INFO));
//t_printf(0,"\nCOMMENT address:%i, string:\"%s\"",daddress,dstring);
    if (info==NULL)
    {
     tool_exit(GENERIC_MEMORY_NOT_AVAILABLE);
    }
    info->kind_of_info=D_INFO_COMMENT;
    info->string=dstring;
    info->address=daddress;
    d_fuege_in_liste_ein( info, &info_liste_first, &info_liste_last, DL_HINTEN );
    dis_mem_map[daddress]|=D_MEM_HAS_INFO;
    break;
   }
   case D_LABEL:
   {
    D_ADDRESS_INFO *info=(D_ADDRESS_INFO *)malloc(sizeof(D_ADDRESS_INFO));
//t_printf(0,"\nLABEL address:%i, string:\"%s\"",daddress,dstring);
    if (info==NULL)
    {
     tool_exit(GENERIC_MEMORY_NOT_AVAILABLE);
    }
    info->kind_of_info=D_INFO_LABEL;
    info->string=dstring;
    info->address=daddress;
    d_fuege_in_liste_ein( info, &info_liste_first, &info_liste_last, DL_HINTEN );
    dis_mem_map[daddress]|=D_MEM_HAS_INFO;
    break;
   }
   case D_EQU:
   {
    D_ADDRESS_INFO *info=(D_ADDRESS_INFO *)malloc(sizeof(D_ADDRESS_INFO));
//t_printf(0,"\nEQU define:%s, value:\"%i\"",dstring,daddress);

//    ...
    if (info==NULL)
    {
     tool_exit(GENERIC_MEMORY_NOT_AVAILABLE);
    }
    info->kind_of_info=D_INFO_EQU;
    info->string=dstring;
    info->address=daddress;
    d_fuege_in_liste_ein( info, &info_liste_first, &info_liste_last, DL_HINTEN );
    break;
   }
   case D_COMMENT_LINE:
   {
    D_ADDRESS_INFO *info=(D_ADDRESS_INFO *)malloc(sizeof(D_ADDRESS_INFO));
//t_printf(0,"\nCOMMENT_LINE address:%i, string:\"%s\"",daddress,dstring);
    if (info==NULL)
    {
     tool_exit(GENERIC_MEMORY_NOT_AVAILABLE);
    }
    info->kind_of_info=D_INFO_COMMENT_LINE;
    info->string=dstring;
    info->address=daddress;
    d_fuege_in_liste_ein( info, &info_liste_first, &info_liste_last, DL_HINTEN );
    dis_mem_map[daddress]|=D_MEM_HAS_INFO;
    break;
   }
   default:
   {
    break;
   }
  } // switch (key)
 }
 p_close_parse( &help_file );
}

