/*
 *      Interactive disassembler (IDA).
 *      Version 3.05
 *      Copyright (c) 1990-95 by Ilfak Guilfanov.
 *      ALL RIGHTS RESERVED.
 *                              FIDO:   2:5020/209
 *                              E-mail: ig@estar.msk.su
 *
 */

#include <ctype.h>
#include "78k_0.hpp"
#include <diskio.hpp>
#include <entry.hpp>
#include <fpro.h>
#include <srarea.hpp>

extern  const bool nec_find_ioport_bit(int port, int bit);
//----------------------------------------------------------------------
static char *RegNames[] = {
  "X", "A", "C", "B", "E", "D", "L", "H", "AX", "BC", "DE","HL",
  "PSW", "SP", "s", "cc", "dpr", "CY",
  "cs", "ds"
};

//----------------------------------------------------------------------
static asm_t nec78k0 = {
  AS_COLON | ASH_HEXF0 | ASD_DECF0 | ASO_OCTF0 | ASB_BINF4 | AS_N2CHR | AS_ONEDUP | AS_NOXRF,
  UAS_NOSPA,
  "NEC _78K_0 Assembler",
  0,
  NULL,     //header
  NULL,
  ".org",
  ".end",

  ";",        // comment string
  '"',        // string delimiter
  '\'',       // char delimiter
  "'\"",      // special symbols in char and string constants

  ".db",    // ascii string directive
  ".db",    // byte directive
  ".dw",    // word directive
  NULL,     // no double words
  NULL,     // no qwords
  NULL,     // oword  (16 bytes)
  NULL,     // no float
  NULL,     // no double
  NULL,     // no tbytes
  NULL,     // no packreal
  NULL,     //".db.#s(b,w) #d,#v",   // #h - header(.byte,.word)
                    // #d - size of array
                    // #v - value of array elements
                    // #s - size specifier
  ".rs %s",    // uninited data (reserve space)
  ".equ",
  NULL,         // seg prefix
  NULL,         // preline for checkarg
  NULL,      // checkarg_atomprefix
  NULL,   // checkarg operations
  NULL,   // XlatAsciiOutput
  "*",    // a_curip
  NULL,         // returns function header line
  NULL,         // returns function footer line
  NULL,         // public
  NULL,         // weak
  NULL,         // extrn
  NULL,         // comm
  NULL,         // get_type_name
  NULL,         // align
  '(', ')',     // lbrace, rbrace
  NULL,    // mod
  NULL,    // and
  NULL,    // or
  NULL,    // xor
  NULL,    // not
  NULL,    // shl
  NULL,    // shr
  NULL,    // sizeof
};
//----------------------------------------------------------------------
//----------------------------------------------------------------------
static char *shnames[] = { "78k0",
                           NULL };
static char *lnames[] =  {
                           "NEC 78K/0",
                            NULL };


static asm_t *asms[] =
{
  &nec78k0,
  NULL
};

//--------------------------------------------------------------------------
static uchar retcNEC78K0_0[] = { 0xAF };    //ret
static uchar retcNEC78K0_1[] = { 0x9F };    //retb
static uchar retcNEC78K0_2[] = { 0x8F };    //reti
static uchar retcNEC78K0_3[] = { 0xBF };    //brk


static bytes_t retcodes[] = {
 { sizeof(retcNEC78K0_0), retcNEC78K0_0 },
 { sizeof(retcNEC78K0_1), retcNEC78K0_1 },
 { sizeof(retcNEC78K0_2), retcNEC78K0_2 },
 { sizeof(retcNEC78K0_3), retcNEC78K0_3 },
 { 0, NULL }
};


//----------------------------------------------------------------------
static netnode helper;
char device[MAXSTR] = "";
static size_t numports;
static ioport_t *ports;


#include "../iocommon.cpp"


//------------------------------------------------------------------
const bool nec_find_ioport_bit(int port, int bit)
{

  //поиск бита из регистра в списке портов
  const ioport_bit_t *b = find_ioport_bit(ports, numports, port, bit);
  if ( b != NULL && b->name != NULL )
  {
    //выводим имя бита из регистра
    out_line(b->name, COLOR_IMPNAME);
    return true;
  }
  return false;
}

//------------------------------------------------------------------
const char *set_idp_options(const char *keyword,int /*value_type*/,const void * /*value*/)
{
  if ( keyword != NULL ) return IDPOPT_BADKEY;

  //функция выбирает все процессора из указанного файла cfg
  //3 параметр это callbak функция, которая вызывается при обнпружении процессора

  char cfgfile[QMAXFILE];
  get_cfg_filename(cfgfile, sizeof(cfgfile));
  if ( choose_ioport_device(cfgfile, device, sizeof(device), parse_area_line0) )
    //передаем имя выбранного процесора
    set_device_name(device, IORESP_PORT|IORESP_INT);

  return IDPOPT_OK;
}
//----------------------------------------------------------------------

void set_dopolnit_info()
{

   for(int NumBanck = 0; NumBanck < 4; NumBanck++)
     for(int Regs = 0; Regs < 8; Regs++)
     {
      char temp[100];
      qsnprintf(temp, sizeof(temp), "Bank%d_%s", NumBanck, RegNames[Regs]);

      //Вычисляем адресс
      ushort Addr = 0xFEE0+((NumBanck*8)+Regs);

      //Устанавливаем имя порта
      set_name(Addr, temp);

      //Устанавливаем коментарий
      qsnprintf(temp, sizeof(temp), "Internal high-speed RAM (Bank %d registr %s)", NumBanck, RegNames[Regs]);
      set_cmt(Addr, temp, true);
     }

}

//----------------------------------------------------------------------
static int notify(processor_t::idp_notify msgid, ...)
{
  va_list va;
  va_start(va, msgid);

// A well behaving processor module should call invoke_callbacks()
// in his notify() function. If this function returns 0, then
// the processor module should process the notification itself
// Otherwise the code should be returned to the caller:

  int code = invoke_callbacks(HT_IDP, msgid, va);
  if ( code ) return code;

  switch(msgid)
  {
    case ph.init:
      inf.mf = 1;
      inf.s_genflags |= INFFL_LZERO;
      helper.create("$ 78k0");
      break;

    case ph.newfile:
      //Выводит длг. окно процессоров, и позволяет выбрать нужный, считывает для выбраного
      //процессора информацию из cfg. По считаной информации подписывает порты и регстры
      {
        char cfgfile[QMAXFILE];
        get_cfg_filename(cfgfile, sizeof(cfgfile));
        if ( choose_ioport_device(cfgfile, device, sizeof(device), parse_area_line0) )
          set_device_name(device, IORESP_ALL);

        set_dopolnit_info();
      }
      break;

    case ph.newprc:
        set_device_name(helper.supval(-1), IORESP_PORT);
        break;

    case ph.newseg:    // new segment
        {
         segment_t *s = va_arg(va, segment_t *);
         // Set default value of DS register for all segments
         set_default_dataseg(s->sel);
        }
      break;

  }
  va_end(va);

  return(1);
}

//-----------------------------------------------------------------------
//      Processor Definition
//-----------------------------------------------------------------------
processor_t LPH =
{
  IDP_INTERFACE_VERSION,
  PLFM_NEC_78K0,            // id
  PRN_HEX|PR_SEGTRANS,
  8,                    // 8 bits in a byte for code segments
  8,                    // 8 bits in a byte for other segments

  shnames,
  lnames,

  asms,

  notify,

  header,
  footer,

  segstart,
  std_gen_segm_footer,

  NULL,

  ana,
  emu,

  out,
  outop,
  intel_data,
  NULL,         //  cmp_opnd,  // 0 if not cmp 1 if eq
  NULL,         //  can_have_type,  //&op    // 1 -yes 0-no    //reg

  qnumber(RegNames),            // Number of registers
  RegNames,                     // Regsiter names
  NULL,                         // get abstract register

  0,                            // Number of register files
  NULL,                         // Register file names
  NULL,                         // Register descriptions
  NULL,                         // Pointer to CPU registers

  Rcs,Rds,
  0,                            // size of a segment register
  Rcs,Rds,

  NULL,                         // No known code start sequences
  retcodes,

  0,
  NEC_78K_0_last,
  Instructions
};
