/*
 *  Interactive disassembler (IDA).
 *  Zilog Z8 module
 *
 */

#include "z8.hpp"

static char *phrases[] =
{
  "F", "LT", "LE", "ULE", "OV",  "MI", "Z",  "C",
  "T", "GE", "GT", "UGT", "NOV", "PL", "NZ", "NC"
};

//----------------------------------------------------------------------

inline void OutReg( int rgnum ) { out_register( ph.regNames[rgnum] ); }

//--------------------------------------------------------------------------

void header( void )
{
  gen_cmt_line( "Processor:        %s", inf.procName );
  gen_cmt_line( "Target assembler: %s", ash.name );
  gen_cmt_line( "Byte sex        : %s", inf.mf ? "Big endian" : "Little endian");
}

//--------------------------------------------------------------------------

void footer( void )
{
  char buf[MAXSTR];

  MakeNull();

  tag_addstr( buf, buf+sizeof(buf), COLOR_ASMDIR, ash.end );
  MakeLine(buf);

  gen_cmt_line( "end of file" );
}

//--------------------------------------------------------------------------

void segstart( ea_t ea )
{
  segment_t *Sarea = getseg( ea );

  gen_cmt_line( COLSTR("segment %s", SCOLOR_AUTOCMT), get_segm_name(Sarea) );

  ea_t org = ea - get_segm_base( Sarea );
  if( org != 0 )    gen_cmt_line( "%s %s", ash.origin, btoa( org ) );
}

//--------------------------------------------------------------------------

void segend( ea_t ea )
{
  gen_cmt_line( "end of '%s'", get_segm_name( getseg(ea-1) ) );
}

//----------------------------------------------------------------------

void out( void )
{
  char buf[MAXSTR];

  init_output_buffer(buf, sizeof(buf));
  OutMnem();

  out_one_operand( 0 );

  if( cmd.Op2.type != o_void )
  {
    out_symbol( ',' );
    OutChar( ' ' );
    out_one_operand( 1 );
  }

  if( isVoid( cmd.ea, uFlag, 0 ) )    OutImmChar( cmd.Op1 );
  if( isVoid( cmd.ea, uFlag, 1 ) )    OutImmChar( cmd.Op2 );

  term_output_buffer();
  gl_comm = 1;
  MakeLine( buf );
}

//----------------------------------------------------------------------

bool outop( op_t &x )
{
  uval_t v;
  const char *ptr;

  switch( x.type )
  {
    case o_imm:
      out_symbol( '#' );
      OutValue( x, OOF_SIGNED | OOFW_IMM );
      break;

    case o_ind_reg:
      out_symbol( '@' );

    case o_reg:
      OutReg( x.reg );
      break;

    case o_phrase:
//ig: лучше out_keyword, чем простой OutLine()
//    так цвет будет правильный
      out_keyword( phrases[x.phrase] );
      break;

    case o_displ:
      OutValue( x, OOF_ADDR | OOF_SIGNED | OOFW_IMM );  // x.addr
      out_symbol( '(' );
      OutReg( x.reg );
      out_symbol( ')' );
      break;

    case o_ind_mem:
      out_symbol( '@' );

    case o_mem:
    case o_near:
      v = (x.type == o_near) ? toEA( cmd.cs, x.addr ) : intmem + x.addr;
      ptr = get_name_expr( cmd.ea + x.offb, x.n, v, x.addr );
      if( !ptr )
      {
        OutValue( x, OOF_ADDR | OOF_NUMBER | OOFS_NOSIGN | OOFW_16 );
        QueueMark( Q_noName, cmd.ea );
      }
      else
        OutLine( ptr );
      break;

    case o_void:
      return 0;

    default:
      warning( "out: %lx: bad optype %d", cmd.ea, x.type );
  }

  return 1;
}

//--------------------------------------------------------------------------

static void out_equ( char *name, const char *equ, uchar off )
{
  char buf[MAXSTR];
  char *const end = buf + sizeof(buf);

  char *p = tag_addstr(buf, end, COLOR_DNAME, name);
  APPCHAR(p, end, ' ');
  p = tag_addstr(p, end, COLOR_KEYWORD, equ);
  APPCHAR(p, end, ' ');
  tag_addstr(p, end, COLOR_NUMBER, btoa(off));

  MakeLine(buf, 0);
}

//--------------------------------------------------------------------------

void z8_data( ea_t ea )
{
  segment_t *s = getseg(ea);

  if( s != NULL && s->type == SEG_IMEM )
  {
    char nbuf[MAXSTR];
    char *name = get_name( BADADDR, ea, nbuf, sizeof(nbuf) );

    if( name != NULL )
      out_equ( name, ash.a_equ, uchar(ea - get_segm_base(s)) );
  }
  else
    intel_data( ea );
}
